mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-31 06:18:54 -04:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6aaca2b302 | ||
|
|
0dcb9c5802 | ||
|
|
5a3d47bf2e | ||
|
|
1c4934fa53 |
No files matched your search
+27
-254
@@ -1,282 +1,55 @@
|
||||
# Changelog
|
||||
## [1.8.x (MONTH xth, 2026)](#1-8-x)
|
||||
## [1.8.3 (MONTH xth, 2026)](#1-8-3)
|
||||
|
||||
### Additions
|
||||
- Added riding statistics: `Distance by Pokémon on Land`, `Distance by Pokémon in Air` and `Distance by Pokémon in Liquid`.
|
||||
- Added the Partner Mark, which party Pokémon have a very small chance to earn as the player walks, provided they have enough friendship.
|
||||
- Added trades for Saccharine Saplings, Hearty Grains, Chipped Pot, and Masterpiece Teacup to the Wandering Trader.
|
||||
- Added brewing recipe for Throat Spray.
|
||||
- Added mood particles! Pokémon now visually react to certain actions:
|
||||
- Angry particles when attacking a mob.
|
||||
- Annoyed particles when a player tries to feed them while they’re already full.
|
||||
- Sweat droplets when they run out of stamina while being ridden.
|
||||
- Added config options to award experience to fainted Pokémon for opponents they helped defeat (`awardExperienceToFaintedPokemon`) and to still award experience for defeated enemies even after battle loss/forfeit (`awardExperienceOnBattleLoss`)
|
||||
- Party Overlay Exp Gained Animation will now display the amount of EXP the Pokémon gained
|
||||
- Added a toast to notify players of how they can scroll through their party. Did you know you can hold R and scroll instead of using arrow keys??!
|
||||
- Added a new layer property that makes a layer scroll in a direction. "scrolling": {"speedU": 0.1, "speedV": 0.1}
|
||||
- Added missing crops to Botany Pots integration
|
||||
- Added a way to obtain Porygon by inserting the Upgrade or Dubious Disc into a data monitor
|
||||
- Added a new `cobblemon:structure`, which is a feature without any restrictions allowing the Builders to place certain structures in much more specific manner.
|
||||
- Added Configs for Infinite Use TMs and Unlocking all TMs
|
||||
- Added Type Gem blocks
|
||||
- Added Type Gem Clusters
|
||||
- Added TMs
|
||||
- Added TM Machine
|
||||
- Added Deepslate Core Block
|
||||
- Added /givetm Command
|
||||
- Added advancement triggers for learning TMs: `cobblemon:has_learn_specific_tm` (per-TM), `cobblemon:has_learn_all_tm` (all TMs learned), and `cobblemon:tms_learned` (count-based), backed by a new `totalTMLearnedCount` on player advancement data.
|
||||
- Added `cobblemon:catch_alpha_pokemon` advancement trigger and `totalAlphaCaptureCount` tracking for capturing Alpha Pokémon.
|
||||
- Added Move Dex to Pokédex
|
||||
- Added the Habitat Block, a spawner block for servers and adventure maps that controls spawning in an area.
|
||||
- Added Disk Rack for storing disks and being an audio sequencer for Noteblocks
|
||||
- Added intrinsic scaling to all Pokémon (+-5%). Some rendering cases, such as shoulder mounting, revert to 1.0 scaling to preserve animation accuracy.
|
||||
- Added scaling to "baby" Pokémon (smaller (-20%) at level 1 → normally sized at level 10)
|
||||
- Added conditional seats for riding. Seats can be gated by molang such as "is_alpha".
|
||||
- Added Alpha Pokémon
|
||||
- Added alpha scaling (alphas are larger than their normal counterparts)
|
||||
- Alphas will always lead herds and will spawn in herds
|
||||
- Alphas spawn with two random TM moves from their learnset
|
||||
- Alpha Pokémon will always defend themselves from players that attack them
|
||||
- Added alpha level matching and stat boost (based on level)
|
||||
- Added pitch-down and reverb to alpha cries
|
||||
- Added alpha Pokémon bait effect
|
||||
- Added alpha eye rendering including eye overlay, bloom, eye trail, and particles.
|
||||
- Added cobweb block slowness immunity for spider Pokémon
|
||||
- Added 49 new habitat structures. 34 as typical Minecraft structures and 15 as structures that get placed as biome features to allow for more natural placement in generation. Structures placed as biome features will not be able to be located with the `/locate structure` command.
|
||||
- Vanilla village house template pools have been adjusted to account for the new abandoned village structure habitat. Weights have changed within the JSON file for every piece to ensure too many habitats don't generate in a single village.
|
||||
- Added 10 new ruin structures.
|
||||
- rooted_arch_ruins & crumbling_arch_ruins have been transferred over to biome features, allowing for better placement in generation.
|
||||
- All ruin structures that did not generate with a gimmighoul/gilded chest before will now generate with one.
|
||||
- All ruin structures gilded chest loot tables have been updated to include a guaranteed TM not learned naturally by any Pokémon through their level-up moveset. Each ruin gets its own specific TM, so you can now go hunting ruins to complete your move dex!
|
||||
- All fossil structures have been transferred over to biome features, allowing for better placement in generation.
|
||||
- The prehistoric_underwater_fissure & prehistoric_submerged_impact fossil structures now use the biome tag `#cobblemon:is_temperate_ocean`.
|
||||
- Gimmighoul towers now generate at ground level rather than sinking one block into the ground.
|
||||
- A new shipwreck cove structure called the "magma_shipwreck_cove" has been added.
|
||||
- Shipwreck coves now generate slightly more frequently.
|
||||
- Added equipment loot tables for shipwreck cove enemies.
|
||||
- Maps from abandoned fishing boats leading to shipwreck coves now will skip explored chunks, allowing the player to find more shipwreck coves easier.
|
||||
- The lush shipwreck cove's phantom mob spawner has been replaced with breezes.
|
||||
- The lush shipwreck cove structure itself has been slightly cleaned up to be less noisy with the blocks it is built out of.
|
||||
- All shipwreck coves' spawners have been adjusted to give compatible mobs enchanted iron or diamond armour and weapons while in its ominous state. The armour given to the mobs will also use the automaton trim. We upped the difficulty because it was too easy now that your Pokémon can fight for you.
|
||||
- One TM of the elemental hyper beams has been added as guaranteed loot to the main treasure chest in every shipwreck cove. (Magma cove gets blast burn, lush cove gets frenzy plant, and submerged cove gets hydro cannon)
|
||||
- Added 7 new advancements
|
||||
- Pressing the inventory key now closes the Pokémon interact wheel GUI
|
||||
- Pokémon cries now play when clicking Pokémon in the summary screen.
|
||||
- Pressing the Summary key while either the starter selection or summary screen are open now closes those screens
|
||||
- Ice type Pokémon are now immune to Packed Snow
|
||||
- Held item visibility can now be controlled by the held_item_visible command argument.
|
||||
|
||||
### New rideable Pokémon
|
||||
- Crobat
|
||||
- Skarmory
|
||||
- Milotic
|
||||
- Archeops
|
||||
- Goodra
|
||||
- Goodra (Hisuian Form)
|
||||
- Drampa
|
||||
- Duraludon
|
||||
- Archaludon
|
||||
|
||||
### Pokémon Added
|
||||
#### Generation 3
|
||||
- Wurmple
|
||||
- Silcoon
|
||||
- Beautifly
|
||||
- Cascoon
|
||||
- Dustox
|
||||
- Skitty
|
||||
- Delcatty
|
||||
- Seviper
|
||||
- Zangoose
|
||||
|
||||
#### Generation 4
|
||||
- Cherubi
|
||||
- Cherrim
|
||||
- Stunky
|
||||
- Skuntank
|
||||
|
||||
#### Generation 5
|
||||
- Audino
|
||||
- Pawniard
|
||||
- Bisharp
|
||||
|
||||
#### Generation 6
|
||||
- Pancham (+ Cosmetic with Black Glasses)
|
||||
- Pangoro (+ Cosmetic with Black Glasses)
|
||||
|
||||
#### Generation 7
|
||||
- Rockruff
|
||||
- Lycanroc
|
||||
|
||||
#### Generation 8
|
||||
- Rolycoly
|
||||
- Carkol
|
||||
- Coalossal
|
||||
- Runerigus
|
||||
- Snom
|
||||
- Frosmoth
|
||||
- Indeedee
|
||||
- Duraludon
|
||||
- Applin
|
||||
- Flapple
|
||||
- Appletun
|
||||
|
||||
#### Generation 9
|
||||
|
||||
- Nymble
|
||||
- Lokix
|
||||
- Kingambit
|
||||
- Dipplin
|
||||
- Archaludon
|
||||
- Hydrapple
|
||||
|
||||
#### Regional Forms
|
||||
- Sandshrew (Alolan Form)
|
||||
- Sandslash (Alolan Form)
|
||||
- Yamask (Galarian Form)
|
||||
- Avalugg (Hisuian Form)
|
||||
|
||||
### Model updates for the following Pokémon
|
||||
|
||||
- Sandshrew
|
||||
- Sandslash
|
||||
- Nidoking
|
||||
- Zubat
|
||||
- Golbat
|
||||
- Crobat
|
||||
- Ditto
|
||||
- Porygon
|
||||
- Porygon2
|
||||
- Porygon-Z
|
||||
- Skarmory
|
||||
- Smoochum
|
||||
- Jynx
|
||||
- Popplio
|
||||
- Brionne
|
||||
- Primarina
|
||||
- Fletchling
|
||||
- Fletchinder
|
||||
- Talonflame
|
||||
- Sableye
|
||||
- Mawile
|
||||
- Goomy
|
||||
- Sliggoo
|
||||
- Goodra
|
||||
- Nacli
|
||||
- Naclstack
|
||||
- Garganacl
|
||||
- Bidoof
|
||||
- Cranidos
|
||||
- Chatot
|
||||
- Yamask
|
||||
- Cofagrigus
|
||||
- Tyranitar
|
||||
- Turtonator
|
||||
- Golett
|
||||
- Corsola
|
||||
- Arbok (New Patterns: Angry, Cartoon, Clown, Comedic, Crow, Grin, Ink, Modern, Rain, Scribble, Silence, Sloth, Suspicious, Will)
|
||||
- ... and Substitute
|
||||
|
||||
#### Model changes to the regional bias resource pack:
|
||||
|
||||
- Added Mime Jr. (Galar Bias)
|
||||
- Added Bergmite (Hisui Bias)
|
||||
- Changed models for every existing regional bias
|
||||
|
||||
### Animation updates for the following Pokémon
|
||||
|
||||
- Kakuna
|
||||
- Grimer
|
||||
- Nidoran♀ (+ New shoulder mount)
|
||||
- Nidorina
|
||||
- Nidoran♂ (+ New shoulder mount)
|
||||
- Sandshrew
|
||||
- Diglett
|
||||
- Dugtrio
|
||||
- Graveler
|
||||
- Happiny
|
||||
- Chansey
|
||||
- Blissey
|
||||
- Poliwhirl
|
||||
- Poliwrath
|
||||
- Zubat
|
||||
- Vulpix
|
||||
- Drowzee
|
||||
- Hypno
|
||||
- Noctowl
|
||||
- Skarmory
|
||||
- Skitty
|
||||
- Flygon
|
||||
- Shellos
|
||||
- Riolu
|
||||
- Lucario
|
||||
- Purrloin
|
||||
- Liepard
|
||||
- Joltik
|
||||
- Galvantula
|
||||
- Nidoking
|
||||
- Fletchling
|
||||
- Fletchinder
|
||||
- Talonflame
|
||||
- Archeops
|
||||
- Drampa
|
||||
- Sewaddle
|
||||
- Swadloon
|
||||
- Leavanny
|
||||
- Goomy
|
||||
- Sliggoo
|
||||
- Goodra
|
||||
- Shedinja
|
||||
- Skwovet
|
||||
- Greedent
|
||||
- Bidoof
|
||||
- Cranidos
|
||||
- Chatot
|
||||
- Yamask
|
||||
- Cofagrigus
|
||||
- Luvdisc
|
||||
- Staryu
|
||||
- Starmie
|
||||
- Togetic
|
||||
- Rellor
|
||||
- Rabsca
|
||||
- Yungoos
|
||||
- Gumshoos
|
||||
- Cottonee
|
||||
- Whimsicott
|
||||
- Corsola
|
||||
|
||||
#### Added sounds to the following moves
|
||||
|
||||
- Absorb
|
||||
- Aurora Beam
|
||||
- Double Team
|
||||
- Draco Meteor
|
||||
- Fire Punch
|
||||
- Fire Spin
|
||||
- Flame Charge
|
||||
- Flame Wheel
|
||||
- Giga Drain
|
||||
- Ice Punch
|
||||
- Leech Life
|
||||
- Magical Leaf
|
||||
- Mega Drain
|
||||
- Minimize
|
||||
- Poison Gas
|
||||
- Rock Throw
|
||||
- Scary Face
|
||||
- Seed bomb
|
||||
- Smokescreen
|
||||
- String Shot
|
||||
- Tail Whip
|
||||
|
||||
### Changes
|
||||
- Changed the Misc icon in the Campfire Pot Recipe Book to Health Candy
|
||||
- Moved EXP Candies from the Medicine recipe book category to the Misc category
|
||||
|
||||
### Fixes
|
||||
- Fixed datapacks with item interaction evolutions that don't specify an item crashing the world on load.
|
||||
- Fixed the Pokédex evolution tree crashing when a datapack's dex entry is missing an evolution's form.
|
||||
- Fixed the Pokédex evolution tree crashing with a stack overflow on evolutions that loop back on themselves.
|
||||
- Fixed the Pokédex evolution tree crashing when looking at a dex that is not part of the "National Dex" aggregate.
|
||||
- Fixed evolution trees not building properly when a pokemon has several pokedex entries for different regions.
|
||||
- Fixed form-changing evolutions sometimes resolving to the source form in the Pokédex evolution tree.
|
||||
- Broken datapack evolutions are now logged and skipped in the Pokédex evolution tree instead of crashing.
|
||||
- Fixed friendship booster items not being recognised as such
|
||||
- Fixed conflicts with other mods that would make use of recipe books in certain ways (Farmer's Delight Cooking Pot)
|
||||
- Fixed Pokémon battles stalling when a sidemod cancels the `THROWN_POKEBALL_HIT` hit event
|
||||
- Fixed choice feature tab completion in `spawnpokemon/pokegive/pokeedit` commands
|
||||
- Fixed MoLang that's targeting players intermittedly failing when they have died, needing them to relog
|
||||
- Fixed all pots of mod on NeoForge
|
||||
- Fixed party overlay not hiding when player opens the pokedex scanner
|
||||
- Added compat for AppleSkin
|
||||
|
||||
### Developer
|
||||
- Bumped NeoForge to `21.1.195` to get access to MixinExtras `0.5` and the expressions annotation
|
||||
- New Platform Event `PLAYER_RESPAWN` which is fired when a player respawns (either through death or returning from the end)
|
||||
- Platform Events `SERVER_PLAYER_TICK_PRE` and `SERVER_PLAYER_TICK_POST` no longer fire when the player is dead
|
||||
- it is now tied much closer to the actual entity rather than the player (or their connection)
|
||||
|
||||
### Molang & Datapacks
|
||||
|
||||
### Particles
|
||||
- Fixed `q.pokemon.nature` returning class instance instead of proper string value (`cobblemon:adamant`)
|
||||
- Fixed `q.entity.is_looking_at` result being always `1` for whatever entity passed as target
|
||||
|
||||
### Localization
|
||||
- Updated translations for:
|
||||
- Updated translations for:
|
||||
@@ -1,107 +0,0 @@
|
||||
# Changelog
|
||||
## [1.8.3 (October 25th, 2026)](#1-8-3)
|
||||
|
||||
### Additions
|
||||
- Added compatability with AppleSkin.
|
||||
|
||||
### New Rideable Pokémon
|
||||
- Vikavolt
|
||||
- Fearow
|
||||
|
||||
### Particles
|
||||
## New Move Animations
|
||||
- Water Shuriken
|
||||
|
||||
### Cries added/updated for the following Pokémon
|
||||
- Hoppip
|
||||
- Skiploom
|
||||
- Jumpluff
|
||||
- Houndour
|
||||
- Houndoom
|
||||
- Wurmple
|
||||
- Silcoon
|
||||
- Beautifly
|
||||
- Cascoon
|
||||
- Dustox
|
||||
- Surskit
|
||||
- Masquerain
|
||||
- Torkoal
|
||||
- Starly
|
||||
- Staravia
|
||||
- Staraptor
|
||||
- Combee
|
||||
- Vespiquen
|
||||
- Dusknoir
|
||||
- Helioptile
|
||||
- Heliolisk
|
||||
- Grubbin
|
||||
- Charjabug
|
||||
- Vikavolt
|
||||
- Applin (updated)
|
||||
- Flapple (updated)
|
||||
- Appletun
|
||||
- Runerigus
|
||||
- Dipplin
|
||||
|
||||
### Animation updates for the following Pokémon
|
||||
- Vikavolt
|
||||
- Magby
|
||||
- Magmar
|
||||
- Ninetales (+ Alolan)
|
||||
- Spearow
|
||||
- Fearow
|
||||
- Squawkabilly
|
||||
- Mudkip
|
||||
- Marshtomp
|
||||
- Swampert
|
||||
|
||||
### Changes
|
||||
- Changed the Misc icon in the Campfire Pot Recipe Book to Health Candy.
|
||||
- Moved EXP Candies from the Medicine recipe book category to the Misc category.
|
||||
- Removed Dynamic Lights data from the Magmarizer item for consistency with the block.
|
||||
- Added `doPokemonPredation` game rule, which controls aggressiveness of Pokémon with the `hate_entity` brain task defined.
|
||||
- Added `predation_chance` server config value, which controls the possibility of attacking the hated entity found in `hate_entity` brain tasks.
|
||||
- Prehistoric Eroded Pillar generates slightly more frequently.
|
||||
- Togekiss was changed from a jet-style mount to bird-style.
|
||||
|
||||
### Fixes
|
||||
- Fixed datapacks with item interaction evolutions that don't specify an item crashing the world on load.
|
||||
- Fixed the Pokédex evolution tree crashing when a datapack's dex entry is missing an evolution's form.
|
||||
- Fixed the Pokédex evolution tree crashing with a stack overflow on evolutions that loop back on themselves.
|
||||
- Fixed the Pokédex evolution tree crashing when looking at a dex that is not part of the "National Dex" aggregate.
|
||||
- Fixed some display names in the Pokédex evolution tree having unintended font colours.
|
||||
- Fixed evolution trees not building properly when a Pokémon has several Pokédex entries for different regions.
|
||||
- Fixed form-changing evolutions sometimes resolving to the source form in the Pokédex evolution tree.
|
||||
- Broken datapack evolutions are now logged and skipped in the Pokédex evolution tree instead of crashing.
|
||||
- Fixed the `alpha` property having no tab completion in commands such as `/pokespawn`, `/pokegive` and `/pokeedit`, and added the missing `dmax_level`, `gmax_factor` and `tradable` aliases to tab completion.
|
||||
- Fixed friendship booster items not being recognised as such.
|
||||
- Fixed conflicts with other mods that would make use of recipe books in certain ways (Farmer's Delight Cooking Pot).
|
||||
- Fixed Pokémon battles stalling when a sidemod cancels the `THROWN_POKEBALL_HIT` hit event.
|
||||
- Fixed choice feature tab completion in `spawnpokemon/pokegive/pokeedit` commands.
|
||||
- Fixed MoLang that's targeting players intermittedly failing when they have died, requiring them to relog.
|
||||
- Fixed a NeoForge bug where none of the Cobblemon plants/berries could be placed into pots.
|
||||
- Fixed party overlay not hiding when the player opens the Pokédex scanner.
|
||||
- Fixed `hate_entity` task focusing on its own entity, therefore enabling deadly warfare between Zangoose and Seviper.
|
||||
- Prehistoric Frozen Pond, Prehistoric Frozen Spike, and Prehistoric Lush Den now actually generate (oops).
|
||||
- Fixed Frogadier floating in its `battle_idle` animation.
|
||||
- Fixed absence or incorrect mergers in spawning conditions, causing the max height/depth of conditions to use the min value instead.
|
||||
- Added stricter riding checks on server side to prevent possible packet forgery when a player tries to ride Pokémon.
|
||||
- Fixed Pokémon cries and animation sounds played from GUIs, such as the starter selection screen and the Pokédex, being tied to the Master volume slider instead of Friendly Creatures.
|
||||
- Fixed Archeops T-posing during its `air_cry` animation.
|
||||
|
||||
### Developer
|
||||
- Bumped NeoForge to `21.1.195` to get access to MixinExtras `0.5` and the expressions annotation.
|
||||
- New Platform Event `PLAYER_RESPAWN` which is fired when a player respawns (either through death or returning from the end).
|
||||
- Platform Events `SERVER_PLAYER_TICK_PRE` and `SERVER_PLAYER_TICK_POST` no longer fire when the player is dead.
|
||||
- It is now tied much closer to the actual entity rather than the player or their connection.
|
||||
|
||||
### Molang & Datapacks
|
||||
- Fixed `q.pokemon.nature` returning class instance instead of proper string value (`cobblemon:adamant`).
|
||||
- Fixed `q.entity.is_looking_at` result being always `1` for whatever entity passed as the target parameter.
|
||||
- Added hate chance optional parameter to `hate_entity` task. `1.0` will make an entity always attack the target.
|
||||
|
||||
### Localization
|
||||
- Updated translations for:
|
||||
- Russian
|
||||
- Japanese
|
||||
- Brazilian Portuguese
|
||||
@@ -1,25 +0,0 @@
|
||||
# Changelog
|
||||
## [1.8.4 (October 27th, 2026)](#1-8-4)
|
||||
|
||||
### Changes
|
||||
- The Froakie line now blinks. The world will never be the same.
|
||||
|
||||
### Fixes
|
||||
- Fixed heaps of spawns not working. This was caused by us missing something before release. RIP.
|
||||
- Fixed a crash caused by Fearow blinking while you're riding one. Makes sense to me.
|
||||
- Fixed Minior's "Shields Down" ability being very broken.
|
||||
- Fixed Dusclops using Squirtle's cry sound (lol).
|
||||
- Fixed blank Cooking Pot recipe book entries and missing tabs on Fabric.
|
||||
- Fixed a hitbox issue with placeable Orb held items attached to a ceiling.
|
||||
- Fixed something sneaky. I'll tell you about it later.
|
||||
|
||||
### Molang & Datapacks
|
||||
- Added `q.target_fainted` function to move action effects that checks if any opponents fainted from the move.
|
||||
|
||||
### Particles
|
||||
- Updated Water Shuriken effect to be timed better when the opponent faints.
|
||||
|
||||
### Localization
|
||||
- Updated translations for:
|
||||
- Korean
|
||||
- Simplified Chinese
|
||||
+1
-1
@@ -69,7 +69,7 @@ public abstract class ClientRecipeBookMixin {
|
||||
value = "INVOKE",
|
||||
target = "Lcom/google/common/collect/ImmutableMap;copyOf(Ljava/util/Map;)Lcom/google/common/collect/ImmutableMap;"
|
||||
))
|
||||
private void addCustomAggregateCategories(Iterable<RecipeHolder<?>> recipes, RegistryAccess registryAccess, CallbackInfo ci, @Local(ordinal = 1) Map<RecipeBookCategories, List<RecipeCollection>> map2) {
|
||||
private void addCustomAggregateCategories(Iterable<RecipeHolder<?>> recipes, RegistryAccess registryAccess, CallbackInfo ci, @Local(name = "map2") Map<RecipeBookCategories, List<RecipeCollection>> map2) {
|
||||
CobblemonRecipeCategories.Companion.getCustomAggregateCategories().forEach((recipeBookCategories, list) -> map2.put(recipeBookCategories, (List) list.stream().flatMap((recipeBookCategoriesx) -> ((List) map2.getOrDefault(recipeBookCategoriesx, ImmutableList.of())).stream()).collect(ImmutableList.toImmutableList())));
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -20,14 +20,14 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
|
||||
@Mixin(RecipeBookComponent.class)
|
||||
public class RecipeBookComponentMixin {
|
||||
@Definition(id = "recipeBookCategories", local = @Local(type = RecipeBookCategories.class))
|
||||
@Definition(id = "recipeBookCategories", local = @Local(name = "recipeBookCategories"))
|
||||
@Definition(id = "FURNACE_SEARCH", field = "Lnet/minecraft/client/RecipeBookCategories;FURNACE_SEARCH:Lnet/minecraft/client/RecipeBookCategories;")
|
||||
@Expression("recipeBookCategories != FURNACE_SEARCH")
|
||||
@ModifyExpressionValue(
|
||||
method = "updateTabs",
|
||||
at = @At(value = "MIXINEXTRAS:EXPRESSION")
|
||||
)
|
||||
private boolean notCookingPotSearch(boolean original, @Local RecipeBookCategories recipeBookCategories) {
|
||||
private boolean notCookingPotSearch(boolean original, @Local(name = "recipeBookCategories") RecipeBookCategories recipeBookCategories) {
|
||||
return original && recipeBookCategories != CobblemonRecipeCategories.COOKING_POT_SEARCH.toVanillaCategory();
|
||||
}
|
||||
}
|
||||
@@ -60,6 +60,8 @@ import com.cobblemon.mod.common.api.storage.pc.PCStore
|
||||
import com.cobblemon.mod.common.api.storage.pc.link.PCLinkManager
|
||||
import com.cobblemon.mod.common.api.storage.player.PlayerInstancedDataStoreManager
|
||||
import com.cobblemon.mod.common.api.storage.player.PlayerInstancedDataStoreTypes
|
||||
import com.cobblemon.mod.common.api.storage.player.adapter.BadgeMongoBackend
|
||||
import com.cobblemon.mod.common.api.storage.player.adapter.BadgeNbtBackend
|
||||
import com.cobblemon.mod.common.api.storage.player.adapter.DexDataMongoBackend
|
||||
import com.cobblemon.mod.common.api.storage.player.adapter.DexDataNbtBackend
|
||||
import com.cobblemon.mod.common.api.storage.player.adapter.PlayerDataJsonBackend
|
||||
@@ -391,10 +393,13 @@ object Cobblemon {
|
||||
|
||||
val tmMoveFactory = CachedPlayerDataStoreFactory(TMMoveNbtBackend())
|
||||
tmMoveFactory.setup(server)
|
||||
val badgeFactory = CachedPlayerDataStoreFactory(BadgeNbtBackend())
|
||||
badgeFactory.setup(server)
|
||||
|
||||
playerDataManager.setFactory(generalJsonFactory, PlayerInstancedDataStoreTypes.GENERAL)
|
||||
playerDataManager.setFactory(pokedexNbtFactory, PlayerInstancedDataStoreTypes.POKEDEX)
|
||||
playerDataManager.setFactory(tmMoveFactory, PlayerInstancedDataStoreTypes.TM_MOVES)
|
||||
playerDataManager.setFactory(badgeFactory, PlayerInstancedDataStoreTypes.BADGES)
|
||||
|
||||
if (config.storageFormat == "nbt") {
|
||||
NBTStoreAdapter(pokemonStoreRoot.absolutePath, useNestedFolders = true, folderPerClass = true)
|
||||
@@ -425,10 +430,15 @@ object Cobblemon {
|
||||
TMMoveMongoBackend(mongoClient, config.mongoDBDatabaseName, "TMMovesCollection")
|
||||
)
|
||||
tmMovesMongoFactory.setup(server)
|
||||
val badgesMongoFactory = CachedPlayerDataStoreFactory(
|
||||
BadgeMongoBackend(mongoClient, config.mongoDBDatabaseName, "BadgesCollection")
|
||||
)
|
||||
badgesMongoFactory.setup(server)
|
||||
|
||||
playerDataManager.setFactory(generalMongoFactory, PlayerInstancedDataStoreTypes.GENERAL)
|
||||
playerDataManager.setFactory(pokedexMongoFactory, PlayerInstancedDataStoreTypes.POKEDEX)
|
||||
playerDataManager.setFactory(tmMovesMongoFactory, PlayerInstancedDataStoreTypes.TM_MOVES)
|
||||
playerDataManager.setFactory(badgesMongoFactory, PlayerInstancedDataStoreTypes.BADGES)
|
||||
MongoDBStoreAdapter(mongoClient, config.mongoDBDatabaseName)
|
||||
} catch (e: ClassNotFoundException) {
|
||||
LOGGER.error("MongoDB driver not found.")
|
||||
@@ -613,6 +623,7 @@ object Cobblemon {
|
||||
this.implementation.registerCommandArgument(cobblemonResource("transform_type"), TransformTypeArgumentType::class, SingletonArgumentInfo.contextFree(TransformTypeArgumentType::transformType))
|
||||
this.implementation.registerCommandArgument(cobblemonResource("model_part"), ModelPartArgumentType::class, SingletonArgumentInfo.contextFree(ModelPartArgumentType::modelPart))
|
||||
this.implementation.registerCommandArgument(cobblemonResource("tm"), TmArgumentType::class, SingletonArgumentInfo.contextFree(TmArgumentType::tm))
|
||||
this.implementation.registerCommandArgument(cobblemonResource("badge"), BadgeArgumentType::class, SingletonArgumentInfo.contextFree(BadgeArgumentType::badge))
|
||||
}
|
||||
|
||||
}
|
||||
@@ -73,6 +73,7 @@ object CobblemonCommands {
|
||||
PcTakeCommand.register(dispatcher)
|
||||
GiveTmCommand.register(dispatcher)
|
||||
TmCommand.register(dispatcher)
|
||||
BadgeCommand.register(dispatcher)
|
||||
|
||||
// Possibly lock down registration if and only if under dev environment or running in an environment
|
||||
// with a certain system environment variable set
|
||||
|
||||
@@ -432,6 +432,7 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(SpeciesFeatureAssignmentSyncPacket.ID, SpeciesFeatureAssignmentSyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(NaturalMaterialRegistrySyncPacket.ID, NaturalMaterialRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(FossilRegistrySyncPacket.ID, FossilRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(BadgeRegistrySyncPacket.ID, BadgeRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(NPCRegistrySyncPacket.ID, NPCRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(PokeRodRegistrySyncPacket.ID, PokeRodRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(ScriptRegistrySyncPacket.ID, ScriptRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
|
||||
+7
-31
@@ -9,7 +9,6 @@
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
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
|
||||
@@ -18,7 +17,6 @@ import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.mainThreadRuntime
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
@@ -36,8 +34,6 @@ import net.minecraft.world.entity.ai.sensing.SensorType
|
||||
class HateEntityTaskConfig : SingleTaskConfig {
|
||||
val entityCondition: Expression = "true".asExpression()
|
||||
val range: ExpressionOrEntityVariable = Either.left("24".asExpression())
|
||||
val chance: Float = Cobblemon.config.predationChance
|
||||
private val coercedChance = chance.coerceIn(0f, 1f)
|
||||
|
||||
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = emptyList<MoLangConfigVariable>()
|
||||
override fun createTask(
|
||||
@@ -47,44 +43,24 @@ class HateEntityTaskConfig : SingleTaskConfig {
|
||||
val range = range.resolveFloat(behaviourConfigurationContext.runtime)
|
||||
behaviourConfigurationContext.addMemories(
|
||||
MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES,
|
||||
MemoryModuleType.ANGRY_AT,
|
||||
MemoryModuleType.ATTACK_TARGET
|
||||
MemoryModuleType.ANGRY_AT
|
||||
)
|
||||
behaviourConfigurationContext.addSensors(SensorType.NEAREST_LIVING_ENTITIES)
|
||||
return BehaviorBuilder.create { instance ->
|
||||
instance.group(
|
||||
instance.present(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES),
|
||||
instance.registered(MemoryModuleType.ANGRY_AT),
|
||||
instance.registered(MemoryModuleType.ATTACK_TARGET),
|
||||
).apply(instance) { entities, angryAt, attackTarget ->
|
||||
instance.registered(MemoryModuleType.ANGRY_AT)
|
||||
).apply(instance) { entities, angryAt ->
|
||||
Trigger { world, entity, _ ->
|
||||
// bail if gamerule is disabled
|
||||
if (!world.gameRules.getBoolean(CobblemonGameRules.DO_POKEMON_PREDATION)) return@Trigger false
|
||||
val target = instance.get(entities).findClosest { hated ->
|
||||
mainThreadRuntime.withQueryValue("entity", hated.asMostSpecificMoLangValue())
|
||||
val target = instance.get(entities).findClosest {
|
||||
mainThreadRuntime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
return@findClosest mainThreadRuntime.resolveBoolean(entityCondition)
|
||||
}.orElse(null)
|
||||
|
||||
var shouldTrigger = false
|
||||
if (target != null && target.distanceTo(entity) <= range) {
|
||||
shouldTrigger = when {
|
||||
// set always attacking if activity chance is equal to 1.0
|
||||
coercedChance == 1f -> {
|
||||
angryAt.set(target.uuid)
|
||||
attackTarget.set(target)
|
||||
true
|
||||
}
|
||||
// roll the dice in other way
|
||||
coercedChance != 1f && world.random.nextFloat() < coercedChance -> {
|
||||
angryAt.set(target.uuid)
|
||||
attackTarget.set(target)
|
||||
true
|
||||
}
|
||||
// fallback to peaceful behavior in unattended cases
|
||||
else -> false
|
||||
}
|
||||
angryAt.set(target.uuid)
|
||||
}
|
||||
return@Trigger shouldTrigger
|
||||
return@Trigger true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.cobblemon.mod.common.api.badges
|
||||
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.StringRepresentable
|
||||
|
||||
class Badge(
|
||||
identifier: ResourceLocation,
|
||||
val name: String,
|
||||
val texture: ResourceLocation,
|
||||
val order: Int
|
||||
): StringRepresentable {
|
||||
|
||||
@Transient
|
||||
var identifier: ResourceLocation = identifier
|
||||
internal set
|
||||
|
||||
override fun getSerializedName(): String {
|
||||
return identifier.toString()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.cobblemon.mod.common.api.badges
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.api.storage.player.InstancedPlayerData
|
||||
import com.cobblemon.mod.common.api.storage.player.PlayerInstancedDataStoreTypes
|
||||
import com.cobblemon.mod.common.api.storage.player.client.ClientBadgeManager
|
||||
import com.cobblemon.mod.common.net.messages.client.SetClientPlayerDataPacket
|
||||
import com.cobblemon.mod.common.util.getPlayer
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import java.util.UUID
|
||||
|
||||
class BadgeManager(
|
||||
override val uuid: UUID,
|
||||
val obtainedBadges: MutableSet<ResourceLocation> = mutableSetOf()
|
||||
) : InstancedPlayerData {
|
||||
|
||||
val storeType = PlayerInstancedDataStoreTypes.BADGES
|
||||
|
||||
override fun toClientData() = ClientBadgeManager(obtainedBadges.toMutableSet())
|
||||
|
||||
fun give(badge: Badge): Boolean {
|
||||
if (!obtainedBadges.add(badge.identifier)) return false
|
||||
syncAndSave()
|
||||
return true
|
||||
}
|
||||
|
||||
fun remove(badge: Badge): Boolean {
|
||||
if (!obtainedBadges.remove(badge.identifier)) return false
|
||||
syncAndSave()
|
||||
return true
|
||||
}
|
||||
|
||||
private fun syncAndSave() {
|
||||
uuid.getPlayer()?.sendPacket(SetClientPlayerDataPacket(storeType, toClientData()))
|
||||
Cobblemon.playerDataManager.saveSingle(this, storeType)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val CODEC: Codec<BadgeManager> = RecordCodecBuilder.create { instance ->
|
||||
instance.group(
|
||||
Codec.STRING.xmap(UUID::fromString, UUID::toString)
|
||||
.fieldOf("uuid")
|
||||
.forGetter { it.uuid },
|
||||
Codec.list(ResourceLocation.CODEC)
|
||||
.xmap({ it.toMutableSet() }, { it.toList() })
|
||||
.fieldOf("obtainedBadges")
|
||||
.forGetter { it.obtainedBadges }
|
||||
).apply(instance, ::BadgeManager)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.cobblemon.mod.common.api.badges
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.net.messages.client.data.BadgeRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.server.packs.PackType
|
||||
|
||||
object Badges : JsonDataRegistry<Badge> {
|
||||
|
||||
override val id: ResourceLocation = cobblemonResource("badges")
|
||||
override val type: PackType = PackType.SERVER_DATA
|
||||
override val observable = SimpleObservable<Badges>()
|
||||
|
||||
override val gson: Gson = GsonBuilder()
|
||||
.disableHtmlEscaping()
|
||||
.setPrettyPrinting()
|
||||
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
|
||||
.create()
|
||||
|
||||
override val typeToken: TypeToken<Badge> = TypeToken.get(Badge::class.java)
|
||||
override val resourcePath: String = "badges"
|
||||
|
||||
private val badges = hashMapOf<ResourceLocation, Badge>()
|
||||
|
||||
override fun reload(data: Map<ResourceLocation, Badge>) {
|
||||
this.badges.clear()
|
||||
data.forEach { (id, badge) ->
|
||||
try {
|
||||
badge.identifier = id
|
||||
this.badges[id] = badge
|
||||
} catch (e: Exception) {
|
||||
Cobblemon.LOGGER.error("Skipped loading the {} badge", id, e)
|
||||
}
|
||||
}
|
||||
Cobblemon.LOGGER.info("Loaded {} badges", this.badges.size)
|
||||
this.observable.emit(this)
|
||||
}
|
||||
|
||||
override fun sync(player: ServerPlayer) {
|
||||
BadgeRegistrySyncPacket(this.all()).sendToPlayer(player)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all loaded [Badge]s.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun all() = this.badges.values.toList()
|
||||
|
||||
/**
|
||||
* Gets a [Badge] by its [ResourceLocation].
|
||||
* @param identifier The identifier of the badge.
|
||||
* @return The [Badge], if loaded, otherwise null.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getByIdentifier(identifier: ResourceLocation): Badge? = this.badges[identifier]
|
||||
}
|
||||
@@ -239,10 +239,6 @@ open class PokemonBattle(
|
||||
}
|
||||
|
||||
fun writeShowdownAction(vararg messages: String) {
|
||||
if (messages.any { it.contains("\n") || it.contains("\r") }) {
|
||||
LOGGER.warn("Refusing to forward Showdown action with an embedded line break for battle {}: {}", battleId, messages.joinToString(" | "))
|
||||
return
|
||||
}
|
||||
log(messages.joinToString("\n"))
|
||||
ShowdownService.service.send(battleId, messages.toList().toTypedArray())
|
||||
}
|
||||
|
||||
+3
-7
@@ -92,17 +92,13 @@ interface PokemonAndMoveSelectingItem {
|
||||
}
|
||||
|
||||
fun canUseOnPokemon(stack: ItemStack, pokemon: Pokemon): Boolean {
|
||||
if (pokemon.entity == null && stack.`is`(CobblemonItemTags.POKE_FOOD) && pokemon.isFull()) {
|
||||
return false
|
||||
if (stack.`is`(CobblemonItemTags.POKE_FOOD)) {
|
||||
return !pokemon.isFull()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun canUseOnBattlePokemon(stack: ItemStack, battlePokemon: BattlePokemon): Boolean {
|
||||
return bagItem!!.canUse(stack, battlePokemon.actor.battle, battlePokemon)
|
||||
}
|
||||
|
||||
fun canUseOnBattlePokemon(stack: ItemStack, battlePokemon: BattlePokemon): Boolean = bagItem!!.canUse(stack, battlePokemon.actor.battle, battlePokemon)
|
||||
fun canUseOnMove(stack: ItemStack, pokemon: Pokemon, move: Move): Boolean = canUseOnMove(stack, move)
|
||||
fun canUseOnMove(stack: ItemStack, move: Move): Boolean
|
||||
|
||||
|
||||
@@ -107,16 +107,13 @@ interface PokemonSelectingItem {
|
||||
}
|
||||
|
||||
fun canUseOnPokemon(stack: ItemStack, pokemon: Pokemon): Boolean {
|
||||
if (pokemon.entity == null && stack.`is`(CobblemonItemTags.POKE_FOOD) && pokemon.isFull()) {
|
||||
return false
|
||||
if (stack.`is`(CobblemonItemTags.POKE_FOOD)) {
|
||||
return !pokemon.isFull()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun canUseOnBattlePokemon(stack: ItemStack, battlePokemon: BattlePokemon): Boolean {
|
||||
return bagItem!!.canUse(stack, battlePokemon.actor.battle, battlePokemon)
|
||||
}
|
||||
fun canUseOnBattlePokemon(stack: ItemStack, battlePokemon: BattlePokemon): Boolean = bagItem!!.canUse(stack, battlePokemon.actor.battle, battlePokemon)
|
||||
|
||||
fun interactWithSpecificBattle(player: ServerPlayer, stack: ItemStack, battlePokemon: BattlePokemon): InteractionResultHolder<ItemStack> {
|
||||
return if (canUseOnBattlePokemon(stack, battlePokemon)) {
|
||||
|
||||
+2
-3
@@ -55,9 +55,8 @@ object PokemonMoLangFunctions : AbstractMoLangFunctionHolder<Pokemon>() {
|
||||
}
|
||||
functions["feed_pokemon"] = { params ->
|
||||
val amount = params.getDouble(0)
|
||||
val playSound = params.getBooleanOrNull(1) != false
|
||||
val playMoodParticles = params.getBooleanOrNull(2) != false
|
||||
DoubleValue(pokemon.feedPokemon(amount.toInt(), playSound, playMoodParticles))
|
||||
val playSound = params.getBooleanOrNull(1) ?: true
|
||||
pokemon.feedPokemon(amount.toInt(), playSound)
|
||||
}
|
||||
functions["behaviour"] = { pokemon.form.behaviour.struct }
|
||||
functions["behavior"] = { pokemon.form.behaviour.struct } // Inferior
|
||||
|
||||
@@ -44,7 +44,6 @@ object ActionEffects : JsonDataRegistry<ActionEffectTimeline> {
|
||||
ActionEffectKeyframe.register<EntityMoLangActionEffectKeyframe>("entity_molang")
|
||||
ActionEffectKeyframe.register<MoLangActionEffectKeyframe>("molang")
|
||||
ActionEffectKeyframe.register<ParallelActionEffectKeyframe>("parallel")
|
||||
ActionEffectKeyframe.register<LoopActionEffectKeyframe>("loop")
|
||||
ActionEffectKeyframe.register<CanInterruptActionEffectKeyframe>("can_interrupt")
|
||||
ActionEffectKeyframe.register<CannotInterruptActionEffectKeyframe>("cannot_interrupt")
|
||||
ActionEffectKeyframe.register<RemoveHoldsActionEffectKeyframe>("remove_holds")
|
||||
|
||||
-39
@@ -1,39 +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.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
class LoopActionEffectKeyframe(
|
||||
val keyframe: ActionEffectKeyframe = PauseActionEffectKeyframe()
|
||||
) : ConditionalActionEffectKeyframe() {
|
||||
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
val future = CompletableFuture<Unit>()
|
||||
runIteration(context, future)
|
||||
return future
|
||||
}
|
||||
|
||||
private fun runIteration(context: ActionEffectContext, future: CompletableFuture<Unit>) {
|
||||
context.currentKeyframes.add(keyframe)
|
||||
keyframe.play(context)
|
||||
.thenRun { context.currentKeyframes.remove(keyframe) }
|
||||
.thenAccept {
|
||||
if (condition.resolveBoolean(context.runtime)) {
|
||||
runIteration(context, future)
|
||||
} else {
|
||||
future.complete(Unit)
|
||||
}
|
||||
}
|
||||
.exceptionally {
|
||||
future.completeExceptionally(it)
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -145,6 +145,8 @@ object CobblemonPermissions {
|
||||
val SPECTATE_BATTLE = this.create("${COMMAND_PREFIX}spectatebattle", PermissionLevel.ALL_COMMANDS)
|
||||
@JvmStatic
|
||||
val TECHNICAL_MACHINE = this.create("${COMMAND_PREFIX}technicalmachine", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
@JvmStatic
|
||||
val BADGE = this.create("${COMMAND_PREFIX}badge", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
|
||||
@JvmStatic
|
||||
val SEE_HIDDEN_NPCS = this.create("seehiddennpcs", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
|
||||
+6
-6
@@ -88,7 +88,7 @@ fun getToolTipHeaderIcon(tradeEvolution: TradeEvolution): CobblemonDexEvolutionR
|
||||
lang("ui.pokedex.evolution.trade.tooltip.with_any_species")
|
||||
} else {
|
||||
PokemonSpecies.getByIdentifier(species.asIdentifierDefaultingNamespace())
|
||||
?.let { lang("ui.pokedex.evolution.trade.tooltip.with_species", it.translatedName.plainCopy().green()) }
|
||||
?.let { lang("ui.pokedex.evolution.trade.tooltip.with_species", it.translatedName.green()) }
|
||||
?: lang("ui.pokedex.evolution.trade.tooltip.with_any_species")
|
||||
}
|
||||
return CobblemonDexEvolutionRequirementDisplay(CobblemonItems.LINK_CABLE, tooltip)
|
||||
@@ -282,7 +282,7 @@ fun buildLevelRequirement(levelRequirement: LevelRequirement): DexEvolutionRequi
|
||||
|
||||
fun buildMoonPhaseRequirement(moonPhaseRequirement: MoonPhaseRequirement): DexEvolutionRequirementDisplay {
|
||||
val icon = Items.CLOCK
|
||||
val moonPhaseComponent = moonPhaseRequirement.moonPhase.displayName().plainCopy().green()
|
||||
val moonPhaseComponent = moonPhaseRequirement.moonPhase.displayName().green()
|
||||
val tooltip = lang("ui.pokedex.requirement.moon_phase.tooltip", moonPhaseComponent)
|
||||
|
||||
return CobblemonDexEvolutionRequirementDisplay(icon, tooltip)
|
||||
@@ -290,7 +290,7 @@ fun buildMoonPhaseRequirement(moonPhaseRequirement: MoonPhaseRequirement): DexEv
|
||||
|
||||
fun buildMoveSetRequirement(moveSetRequirement: MoveSetRequirement): DexEvolutionRequirementDisplay {
|
||||
val icon = CobblemonItems.TECHNICAL_MACHINE
|
||||
val tooltip = lang("ui.pokedex.requirement.has_move.tooltip", moveSetRequirement.move.displayName.plainCopy().green())
|
||||
val tooltip = lang("ui.pokedex.requirement.has_move.tooltip", moveSetRequirement.move.displayName.green())
|
||||
|
||||
return CobblemonDexEvolutionRequirementDisplay(icon, tooltip)
|
||||
}
|
||||
@@ -319,7 +319,7 @@ fun buildMoveTypeRequirement(moveTypeRequirement: MoveTypeRequirement): DexEvolu
|
||||
else -> CobblemonItems.NORMAL_GEM
|
||||
}
|
||||
|
||||
val tooltip = lang("ui.pokedex.requirement.has_move_type.tooltip", moveTypeRequirement.type.displayName.plainCopy().green())
|
||||
val tooltip = lang("ui.pokedex.requirement.has_move_type.tooltip", moveTypeRequirement.type.displayName.green())
|
||||
|
||||
return CobblemonDexEvolutionRequirementDisplay(icon, tooltip)
|
||||
}
|
||||
@@ -437,7 +437,7 @@ fun buildStructureRequirement(structureRequirement: StructureRequirement, negate
|
||||
|
||||
fun buildTimeRangeRequirement(timeRangeRequirement: TimeRangeRequirement): DexEvolutionRequirementDisplay? {
|
||||
val icon = Items.CLOCK
|
||||
val timeRangeComponent = timeRangeRequirement.range.displayName()?.plainCopy() ?: return null
|
||||
val timeRangeComponent = timeRangeRequirement.range.displayName() ?: return null
|
||||
val tooltip = lang("ui.pokedex.requirement.time_range.tooltip", timeRangeComponent.green())
|
||||
|
||||
return CobblemonDexEvolutionRequirementDisplay(icon, tooltip)
|
||||
@@ -445,7 +445,7 @@ fun buildTimeRangeRequirement(timeRangeRequirement: TimeRangeRequirement): DexEv
|
||||
|
||||
fun buildUseMoveRequirement(useMoveRequirement: UseMoveRequirement): DexEvolutionRequirementDisplay {
|
||||
val icon = CobblemonItems.CHOICE_BAND
|
||||
val tooltip = lang("ui.pokedex.requirement.use_move.tooltip", useMoveRequirement.move.displayName.plainCopy().green())
|
||||
val tooltip = lang("ui.pokedex.requirement.use_move.tooltip", useMoveRequirement.move.displayName.green())
|
||||
|
||||
return CobblemonDexEvolutionRequirementDisplay(icon, tooltip)
|
||||
}
|
||||
|
||||
+2
-2
@@ -42,8 +42,8 @@ abstract class AreaTypeSpawningCondition<T : AreaSpawnablePosition> : SpawningCo
|
||||
override fun copyFrom(other: SpawningCondition<*>, merger: Merger) {
|
||||
super.copyFrom(other, merger)
|
||||
if (other is AreaTypeSpawningCondition) {
|
||||
minHeight = merger.mergeSingle(minHeight, other.minHeight)
|
||||
maxHeight = merger.mergeSingle(maxHeight, other.maxHeight)
|
||||
merger.mergeSingle(minHeight, other.minHeight)
|
||||
merger.mergeSingle(maxHeight, other.maxHeight)
|
||||
neededNearbyBlocks = merger.merge(neededNearbyBlocks, other.neededNearbyBlocks)?.toMutableList()
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ abstract class SubmergedTypeSpawningCondition<T : SubmergedSpawnablePosition> :
|
||||
super.copyFrom(other, merger)
|
||||
if (other is SubmergedTypeSpawningCondition) {
|
||||
minDepth = merger.mergeSingle(minDepth, other.minDepth)
|
||||
maxDepth = merger.mergeSingle(maxDepth, other.maxDepth)
|
||||
maxDepth = merger.mergeSingle(minDepth, other.minDepth)
|
||||
fluidIsSource = merger.mergeSingle(fluidIsSource, other.fluidIsSource)
|
||||
fluid = merger.mergeSingle(fluid, other.fluid)
|
||||
}
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ abstract class SurfaceTypeSpawningCondition<T : SurfaceSpawnablePosition> : Area
|
||||
super.copyFrom(other, merger)
|
||||
if (other is SurfaceTypeSpawningCondition) {
|
||||
minDepth = merger.mergeSingle(minDepth, other.minDepth)
|
||||
maxDepth = merger.mergeSingle(maxDepth, other.maxDepth)
|
||||
maxDepth = merger.mergeSingle(minDepth, other.minDepth)
|
||||
fluid = merger.mergeSingle(fluid, other.fluid)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,17 +198,7 @@ interface Spawner {
|
||||
val mid = chunk.getBlockState(startPos)
|
||||
val above = chunk.getBlockState(abovePos)
|
||||
|
||||
// Above must be non-solid
|
||||
if (!above.isPathfindable(PathComputationType.AIR)) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Position must be non-air
|
||||
if (mid.isAir) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
return above.isPathfindable(PathComputationType.AIR) && mid.isAir
|
||||
}
|
||||
|
||||
fun constrainArea(area: SpawningZoneInput): SpawningZoneInput? {
|
||||
|
||||
@@ -29,8 +29,12 @@ object CobblemonStats {
|
||||
@JvmField
|
||||
val BATTLES_WON: CobblemonStat = CobblemonStat("battles_won")
|
||||
@JvmField
|
||||
val PVP_BATTLES_WON: CobblemonStat = CobblemonStat("pvp_battles_won")
|
||||
@JvmField
|
||||
val BATTLES_LOST: CobblemonStat = CobblemonStat("battles_lost")
|
||||
@JvmField
|
||||
val PVP_BATTLES_LOST: CobblemonStat = CobblemonStat("pvp_battles_lost")
|
||||
@JvmField
|
||||
val BATTLES_FLED: CobblemonStat = CobblemonStat("battles_fled")
|
||||
@JvmField
|
||||
val BATTLES_TOTAL: CobblemonStat = CobblemonStat("battles_total")
|
||||
@@ -68,7 +72,9 @@ object CobblemonStats {
|
||||
stats["evolved"] = EVOLVED
|
||||
stats["level_up"] = LEVEL_UP
|
||||
stats["battles_won"] = BATTLES_WON
|
||||
stats["pvp_battles_won"] = PVP_BATTLES_WON
|
||||
stats["battles_lost"] = BATTLES_LOST
|
||||
stats["pvp_battles_lost"] = PVP_BATTLES_LOST
|
||||
stats["battles_fled"] = BATTLES_FLED
|
||||
stats["battles_total"] = BATTLES_TOTAL
|
||||
stats["dex_entries"] = DEX_ENTRIES
|
||||
|
||||
+14
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.api.storage.player
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Cobblemon.MODID
|
||||
import com.cobblemon.mod.common.api.badges.BadgeManager
|
||||
import com.cobblemon.mod.common.api.pokedex.PokedexManager
|
||||
import com.cobblemon.mod.common.api.scheduling.ScheduledTask
|
||||
import com.cobblemon.mod.common.api.scheduling.ServerTaskTracker
|
||||
@@ -76,6 +77,14 @@ open class PlayerInstancedDataStoreManager {
|
||||
.infiniteIterations()
|
||||
.tracker(ServerTaskTracker)
|
||||
.build()
|
||||
|
||||
saveTasks[PlayerInstancedDataStoreTypes.BADGES] = ScheduledTask.Builder()
|
||||
.execute { saveAllOfOneType(PlayerInstancedDataStoreTypes.BADGES) }
|
||||
.delay(30F)
|
||||
.interval(120F)
|
||||
.infiniteIterations()
|
||||
.tracker(ServerTaskTracker)
|
||||
.build()
|
||||
}
|
||||
|
||||
open fun get(playerId: UUID, dataType: PlayerInstancedDataStoreType): InstancedPlayerData {
|
||||
@@ -148,4 +157,9 @@ open class PlayerInstancedDataStoreManager {
|
||||
}
|
||||
return data as TMMoveManager
|
||||
}
|
||||
|
||||
fun getBadgeData(player: ServerPlayer): BadgeManager = getBadgeData(player.uuid)
|
||||
|
||||
fun getBadgeData(playerId: UUID): BadgeManager =
|
||||
get(playerId, PlayerInstancedDataStoreTypes.BADGES) as BadgeManager
|
||||
}
|
||||
+7
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.api.storage.player
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.storage.player.client.ClientBadgeManager
|
||||
import com.cobblemon.mod.common.api.storage.player.client.ClientPokedexManager
|
||||
import com.cobblemon.mod.common.api.storage.player.client.ClientGeneralPlayerData
|
||||
import com.cobblemon.mod.common.api.storage.player.client.ClientTMMoveManager
|
||||
@@ -35,6 +36,12 @@ object PlayerInstancedDataStoreTypes {
|
||||
ClientTMMoveManager::runAction,
|
||||
ClientTMMoveManager::runIncremental
|
||||
))
|
||||
val BADGES = register(PlayerInstancedDataStoreType(
|
||||
cobblemonResource("badge_collection"),
|
||||
ClientBadgeManager::decode,
|
||||
ClientBadgeManager::runAction,
|
||||
ClientBadgeManager::runIncremental
|
||||
))
|
||||
|
||||
fun register(type: PlayerInstancedDataStoreType): PlayerInstancedDataStoreType {
|
||||
Cobblemon.LOGGER.debug("Registering PlayerInstancedDataStoreType: {}", type.id)
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.storage.player.adapter
|
||||
|
||||
import com.cobblemon.mod.common.api.badges.BadgeManager
|
||||
import com.cobblemon.mod.common.api.storage.player.PlayerInstancedDataStoreTypes
|
||||
import com.cobblemon.mod.common.util.adapters.CodecBackedAdapter
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.mongodb.client.MongoClient
|
||||
import java.util.UUID
|
||||
|
||||
class BadgeMongoBackend(
|
||||
mongoClient: MongoClient,
|
||||
databaseName: String,
|
||||
collectionName: String
|
||||
) : MongoBackedPlayerDataStoreBackend<BadgeManager>(
|
||||
mongoClient,
|
||||
databaseName,
|
||||
collectionName,
|
||||
PlayerInstancedDataStoreTypes.BADGES
|
||||
) {
|
||||
override val gson = GsonBuilder()
|
||||
.registerTypeAdapter(BadgeManager::class.java, CodecBackedAdapter(BadgeManager.CODEC))
|
||||
.create()
|
||||
override val classToken = TypeToken.get(BadgeManager::class.java)
|
||||
override val defaultData = defaultDataFunc
|
||||
|
||||
companion object {
|
||||
val defaultDataFunc = { uuid: UUID -> BadgeManager(uuid) }
|
||||
}
|
||||
}
|
||||
+22
@@ -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.storage.player.adapter
|
||||
|
||||
import com.cobblemon.mod.common.api.badges.BadgeManager
|
||||
import com.cobblemon.mod.common.api.storage.player.PlayerInstancedDataStoreTypes
|
||||
import java.util.UUID
|
||||
|
||||
class BadgeNbtBackend : NbtBackedPlayerData<BadgeManager>("badges", PlayerInstancedDataStoreTypes.BADGES) {
|
||||
override val codec = BadgeManager.CODEC
|
||||
override val defaultData = defaultDataFunc
|
||||
|
||||
companion object {
|
||||
val defaultDataFunc = { uuid: UUID -> BadgeManager(uuid) }
|
||||
}
|
||||
}
|
||||
+6
-4
@@ -52,7 +52,7 @@ abstract class FileBasedPlayerDataStoreBackend<T : InstancedPlayerData>(
|
||||
val playerFile = filePath(uuid)
|
||||
val playerFileOld = filePath(uuid, OLD_FILE_EXTENSION)
|
||||
playerFile.parentFile.mkdirs()
|
||||
val loadFallback: () -> T = {
|
||||
val loadFallback: (Boolean) -> T = { primaryFileCorrupt ->
|
||||
playerFile.delete()
|
||||
if (playerFileOld.exists() && playerFileOld.length() > 0L) {
|
||||
try {
|
||||
@@ -68,7 +68,9 @@ abstract class FileBasedPlayerDataStoreBackend<T : InstancedPlayerData>(
|
||||
}
|
||||
}
|
||||
else {
|
||||
Cobblemon.LOGGER.error(".old File $subfolder for $uuid is corrupt or missing. Data is lost")
|
||||
if (primaryFileCorrupt) {
|
||||
Cobblemon.LOGGER.error(".old File $subfolder for $uuid is corrupt or missing. Data is lost")
|
||||
}
|
||||
playerFileOld.delete()
|
||||
defaultData.invoke(uuid).also(::save)
|
||||
}
|
||||
@@ -80,10 +82,10 @@ abstract class FileBasedPlayerDataStoreBackend<T : InstancedPlayerData>(
|
||||
catch (e: Exception) {
|
||||
Cobblemon.LOGGER.warn("Failed to load $subfolder for $uuid due to ${e.message}")
|
||||
Cobblemon.LOGGER.warn(e)
|
||||
loadFallback()
|
||||
loadFallback(true)
|
||||
}
|
||||
} else {
|
||||
loadFallback()
|
||||
loadFallback(false)
|
||||
}.also { it.initialize() }
|
||||
}
|
||||
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package com.cobblemon.mod.common.api.storage.player.client
|
||||
|
||||
import com.cobblemon.mod.common.api.storage.player.PlayerInstancedDataStoreTypes
|
||||
import com.cobblemon.mod.common.client.CobblemonClient
|
||||
import com.cobblemon.mod.common.net.messages.client.SetClientPlayerDataPacket
|
||||
import com.cobblemon.mod.common.util.readString
|
||||
import com.cobblemon.mod.common.util.writeString
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
class ClientBadgeManager(
|
||||
val obtainedBadges: MutableSet<ResourceLocation>
|
||||
) : ClientInstancedPlayerData {
|
||||
|
||||
override fun encode(buf: RegistryFriendlyByteBuf) {
|
||||
buf.writeCollection(obtainedBadges) { _, id, -> buf.writeString(id.toString()) }
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun decode(buf: RegistryFriendlyByteBuf): SetClientPlayerDataPacket {
|
||||
val badges = buf.readCollection(
|
||||
{ mutableSetOf<ResourceLocation>() },
|
||||
{ buf.readString().let(ResourceLocation::tryParse) ?: ResourceLocation("minecraft", "empty") }
|
||||
)
|
||||
return SetClientPlayerDataPacket(
|
||||
PlayerInstancedDataStoreTypes.BADGES,
|
||||
ClientBadgeManager(badges)
|
||||
)
|
||||
}
|
||||
|
||||
fun runAction(data: ClientInstancedPlayerData) {
|
||||
if (data !is ClientBadgeManager) return
|
||||
CobblemonClient.clientBadgeData = data
|
||||
}
|
||||
|
||||
fun runIncremental(data: ClientInstancedPlayerData) {
|
||||
if (data !is ClientBadgeManager) return
|
||||
CobblemonClient.clientBadgeData.obtainedBadges.addAll(data.obtainedBadges)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -117,9 +117,6 @@ abstract class ShowdownActionResponse(val type: ShowdownActionResponseType) {
|
||||
|
||||
data class MoveActionResponse(var moveName: String, var targetPnx: String? = null, var gimmickID: String? = null): ShowdownActionResponse(ShowdownActionResponseType.MOVE) {
|
||||
override fun isValid(activeBattlePokemon: ActiveBattlePokemon, showdownMoveSet: ShowdownMoveset?, forceSwitch: Boolean): Boolean {
|
||||
// Ensure that the gimmick ID the player is sending is valid
|
||||
gimmickID?.let { if (it !in VALID_GIMMICK_IDS) return false }
|
||||
|
||||
if (forceSwitch || showdownMoveSet == null) {
|
||||
return false
|
||||
}
|
||||
@@ -171,10 +168,6 @@ data class MoveActionResponse(var moveName: String, var targetPnx: String? = nul
|
||||
gimmickID = buffer.readNullable { buffer.readString() }
|
||||
return this
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val VALID_GIMMICK_IDS = ShowdownMoveset.Gimmick.entries.map { it.id }.toSet()
|
||||
}
|
||||
}
|
||||
|
||||
data class HealItemActionResponse(var item: String) : ShowdownActionResponse(ShowdownActionResponseType.FORCE_PASS) {
|
||||
@@ -190,8 +183,7 @@ data class HealItemActionResponse(var item: String) : ShowdownActionResponse(Sho
|
||||
}
|
||||
|
||||
override fun isValid(activeBattlePokemon: ActiveBattlePokemon, showdownMoveSet: ShowdownMoveset?, forceSwitch: Boolean): Boolean {
|
||||
// Previously checked for !forceSwitch, excepts in the case of a forceSwitch, this couldn't legally be sent anyway.
|
||||
return false
|
||||
return !forceSwitch
|
||||
}
|
||||
|
||||
override fun toShowdownString(activeBattlePokemon: ActiveBattlePokemon, showdownMoveSet: ShowdownMoveset?): String {
|
||||
|
||||
+2
-11
@@ -37,6 +37,7 @@ import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
/**
|
||||
* Format: |move|POKEMON|MOVE|TARGET
|
||||
@@ -76,7 +77,7 @@ class MoveInstruction(
|
||||
val pokemonName = userPokemon.getName()
|
||||
ShowdownInterpreter.lastCauser[battle.battleId] = message
|
||||
// For Spread targets the message data only gives the pnx strings. So we can't know what pokemon are actually targeted until the previous messages have been interpreted
|
||||
val spreadTargetPokemon = spreadTargets.map { battle.activePokemon.firstOrNull { poke -> poke.getPNX() == it }?.battlePokemon }
|
||||
val spreadTargetPokemon = spreadTargets.map { battle.activePokemon.firstOrNull() { poke -> poke.getPNX() == it }?.battlePokemon }
|
||||
|
||||
val targetPokemonEntity = targetPokemon?.entity
|
||||
if (targetPokemonEntity != null) {
|
||||
@@ -136,20 +137,10 @@ class MoveInstruction(
|
||||
|
||||
val subsequentInstructions = instructionSet.findInstructionsCausedBy(this)
|
||||
val missedTargets = subsequentInstructions.filterIsInstance<MissInstruction>().mapNotNull { it.target }
|
||||
val faintedTargets = subsequentInstructions.filterIsInstance<FaintInstruction>().map { it.faintingPokemon }
|
||||
val failed = subsequentInstructions.any { it is FailInstruction }
|
||||
val failedTargets = subsequentInstructions.filterIsInstance<FailInstruction>().mapNotNull { it.target }
|
||||
val hitCountInstruction = subsequentInstructions.filterIsInstance<HitCountInstruction>().firstOrNull()
|
||||
|
||||
runtime.environment.query.addFunction("target_fainted") { params ->
|
||||
if (params.params.size == 0) {
|
||||
return@addFunction DoubleValue(faintedTargets.isNotEmpty())
|
||||
} else {
|
||||
val entityUUID = params.getString(0)
|
||||
return@addFunction DoubleValue(faintedTargets.any { it.entity?.stringUUID == entityUUID })
|
||||
}
|
||||
}
|
||||
|
||||
runtime.environment.query.addFunction("missed") { params ->
|
||||
if (params.params.size == 0) {
|
||||
return@addFunction DoubleValue(missedTargets.isNotEmpty())
|
||||
|
||||
@@ -30,7 +30,7 @@ class OrbBlock(properties: Properties) : SixFaceRotationalBlock(properties) {
|
||||
|
||||
val FLOOR_NORTH = Shapes.box(0.3125, 0.0, 0.3125, 0.6875, 0.375, 0.6875)
|
||||
val WALL_NORTH = Shapes.box(0.3125, 0.3125, 0.625, 0.6875, 0.6875, 1.0)
|
||||
val CEILING_NORTH = Shapes.box(0.3125, 0.625, 0.3125, 0.6875, 1.0, 0.6875)
|
||||
val CEILING_NORTH = Shapes.box(0.3125, 0.625, 0.375, 0.6875, 1.0, 0.6875)
|
||||
}
|
||||
|
||||
init {
|
||||
|
||||
@@ -17,12 +17,12 @@ import com.cobblemon.mod.common.CobblemonItems
|
||||
import com.cobblemon.mod.common.CobblemonMenuType
|
||||
import com.cobblemon.mod.common.api.berry.Berries
|
||||
import com.cobblemon.mod.common.api.scheduling.ClientTaskTracker
|
||||
import com.cobblemon.mod.common.api.storage.player.client.ClientBadgeManager
|
||||
import com.cobblemon.mod.common.api.storage.player.client.ClientGeneralPlayerData
|
||||
import com.cobblemon.mod.common.api.storage.player.client.ClientPokedexManager
|
||||
import com.cobblemon.mod.common.api.storage.player.client.ClientTMMoveManager
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||
import com.cobblemon.mod.common.block.entity.TintBlockEntity
|
||||
import com.cobblemon.mod.common.block.sign.CobblemonSignBlock
|
||||
import com.cobblemon.mod.common.client.battle.ClientBattle
|
||||
import com.cobblemon.mod.common.client.gui.PartyOverlay
|
||||
import com.cobblemon.mod.common.client.gui.PartyOverlayDataControl
|
||||
@@ -101,6 +101,7 @@ object CobblemonClient {
|
||||
var clientPlayerData = ClientGeneralPlayerData()
|
||||
var clientPokedexData = ClientPokedexManager(mutableMapOf())
|
||||
var clientTMMoveData = ClientTMMoveManager(mutableSetOf())
|
||||
var clientBadgeData = ClientBadgeManager(mutableSetOf())
|
||||
|
||||
/** If true then we won't bother them anymore about choosing a starter even if it's a thing they can do. */
|
||||
var checkedStarterScreen = false
|
||||
@@ -118,6 +119,7 @@ object CobblemonClient {
|
||||
teamData = ClientPlayerTeamData()
|
||||
clientPokedexData = ClientPokedexManager(mutableMapOf())
|
||||
clientTMMoveData = ClientTMMoveManager(mutableSetOf())
|
||||
clientBadgeData = ClientBadgeManager(mutableSetOf())
|
||||
storage.onLogin()
|
||||
// CobblemonDataProvider.canReload = false
|
||||
}
|
||||
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
package com.cobblemon.mod.common.client.gui.trainercard
|
||||
|
||||
import com.cobblemon.mod.common.api.badges.Badge
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.client.CobblemonClient
|
||||
import com.cobblemon.mod.common.client.gui.ScrollingWidget
|
||||
import com.cobblemon.mod.common.client.gui.pokedex.renderTooltip
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
import net.minecraft.util.FastColor
|
||||
import net.minecraft.util.Mth
|
||||
|
||||
class BadgesScrollingWidget(
|
||||
x: Int,
|
||||
y: Int,
|
||||
width: Int,
|
||||
height: Int,
|
||||
private val columns: Int
|
||||
) : ScrollingWidget<BadgesScrollingWidget.BadgeRow>(
|
||||
width = width,
|
||||
height = height,
|
||||
left = x,
|
||||
top = y - height,
|
||||
slotHeight = SLOT_SIZE + SLOT_SPACING
|
||||
) {
|
||||
|
||||
private var tooltip: MutableComponent? = null
|
||||
private var tooltipX = 0
|
||||
private var tooltipY = 0
|
||||
|
||||
companion object {
|
||||
const val SLOT_SIZE = 16
|
||||
const val SLOT_SPACING = 3
|
||||
const val MAX_VISIBLE_ROWS = 2
|
||||
}
|
||||
|
||||
fun createEntries(badges: List<Badge>) {
|
||||
|
||||
val obtainedBadgeList = badges.filter { CobblemonClient.clientBadgeData.obtainedBadges.contains(it.identifier) }
|
||||
.sortedBy { it.order }
|
||||
val unobtainedBadgesList = badges.filter { !obtainedBadgeList.contains(it) }
|
||||
.sortedBy { it.order }
|
||||
val sortedBadgeList = obtainedBadgeList.plus(unobtainedBadgesList)
|
||||
|
||||
sortedBadgeList.chunked(columns).forEach { listChunk ->
|
||||
addEntry(BadgeRow(this, listChunk))
|
||||
}
|
||||
}
|
||||
|
||||
private val visibleRows: Int
|
||||
get() = (height / itemHeight).coerceAtLeast(1)
|
||||
|
||||
private fun hasScrollbar(): Boolean = children().size > visibleRows
|
||||
|
||||
override fun getRowLeft(): Int = if (hasScrollbar()) left + 1 else left
|
||||
override fun getScrollbarPosition(): Int = rowLeft + width - 3
|
||||
|
||||
override fun renderWidget(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
tooltip = null
|
||||
super.renderWidget(context, mouseX, mouseY, delta)
|
||||
tooltip?.let { renderTooltip(context, it, tooltipX, tooltipY, delta) }
|
||||
}
|
||||
|
||||
fun setTooltip(text: MutableComponent, mouseX: Int, mouseY: Int) {
|
||||
if (mouseX in left until left + width && mouseY in this.y until bottom) {
|
||||
tooltip = text
|
||||
tooltipX = mouseX + 20
|
||||
tooltipY = mouseY - 10
|
||||
}
|
||||
}
|
||||
|
||||
override fun renderScrollbar(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
if (hasScrollbar()) {
|
||||
val xLeft = this.scrollbarPosition
|
||||
val xRight = xLeft + 3
|
||||
|
||||
val barHeight = this.bottom - this.y
|
||||
|
||||
var yBottom = ((barHeight * barHeight).toFloat() / this.maxPosition.toFloat()).toInt()
|
||||
yBottom = Mth.clamp(yBottom, minOf(32, barHeight), maxOf(minOf(32, barHeight), barHeight - 8))
|
||||
var yTop = scrollAmount.toInt() * (barHeight - yBottom) / this.maxScroll + this.y
|
||||
if (yTop < this.y) {
|
||||
yTop = this.y
|
||||
}
|
||||
|
||||
context.fill(xLeft, this.y, xRight, this.bottom, FastColor.ARGB32.color(255, 75, 75, 75))
|
||||
context.fill(xLeft, yTop, xRight, yTop + yBottom, FastColor.ARGB32.color(255, 141, 141, 141))
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderEntry(context: GuiGraphics, mouseX: Int, mouseY: Int, index: Int, x: Int, y: Int) {
|
||||
getEntry(index).renderRow(context, y, x, mouseX, mouseY)
|
||||
}
|
||||
|
||||
override fun renderListItems(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
val rowX = rowLeft
|
||||
|
||||
for (index in 0 until this.itemCount) {
|
||||
val rowY = this.getRowTop(index)
|
||||
val o = this.getRowBottom(index)
|
||||
if (o >= this.y && rowY <= this.bottom) {
|
||||
this.renderEntry(context, mouseX, mouseY, index, rowX, rowY)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun mouseDragged(mouseX: Double, mouseY: Double, button: Int, dragX: Double, dragY: Double): Boolean =
|
||||
if (hasScrollbar()) super.mouseDragged(mouseX, mouseY, button, dragX, dragY) else true
|
||||
|
||||
override fun mouseScrolled(mouseX: Double, mouseY: Double, scrollX: Double, scrollY: Double): Boolean =
|
||||
if (hasScrollbar()) super.mouseScrolled(mouseX, mouseY, scrollX, scrollY) else true
|
||||
|
||||
class BadgeRow(
|
||||
val parent: BadgesScrollingWidget,
|
||||
val badgeList: List<Badge?>
|
||||
) : Slot<BadgeRow>() {
|
||||
|
||||
fun renderRow(context: GuiGraphics, y: Int, x: Int, mouseX: Int, mouseY: Int) {
|
||||
badgeList.forEachIndexed { index, badge ->
|
||||
val startPosX = x + ((SLOT_SPACING + SLOT_SIZE) * index)
|
||||
val startPosY = y + SLOT_SPACING
|
||||
|
||||
if (badge != null) {
|
||||
val obtained = CobblemonClient.clientBadgeData.obtainedBadges.contains(badge.identifier)
|
||||
blitk(
|
||||
matrixStack = context.pose(),
|
||||
texture = badge.texture,
|
||||
x = startPosX,
|
||||
y = startPosY,
|
||||
width = SLOT_SIZE,
|
||||
height = SLOT_SIZE,
|
||||
red = if (obtained) 1 else 0,
|
||||
green = if (obtained) 1 else 0,
|
||||
blue = if (obtained) 1 else 0
|
||||
)
|
||||
if (mouseX in startPosX until startPosX + SLOT_SIZE &&
|
||||
mouseY in startPosY until startPosY + SLOT_SIZE
|
||||
) {
|
||||
parent.setTooltip(
|
||||
if (obtained) Component.translatable(badge.name) else lang("badge.unobtained"),
|
||||
mouseX, mouseY
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getNarration(): Component? {
|
||||
return badgeList.firstOrNull()?.let { Component.translatable(it.name) }
|
||||
}
|
||||
|
||||
override fun render(
|
||||
guiGraphics: GuiGraphics,
|
||||
index: Int,
|
||||
top: Int,
|
||||
left: Int,
|
||||
width: Int,
|
||||
height: Int,
|
||||
mouseX: Int,
|
||||
mouseY: Int,
|
||||
hovering: Boolean,
|
||||
partialTick: Float
|
||||
) {}
|
||||
}
|
||||
}
|
||||
+221
@@ -0,0 +1,221 @@
|
||||
package com.cobblemon.mod.common.client.gui.trainercard
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.badges.Badges
|
||||
import com.cobblemon.mod.common.api.pokedex.CaughtCount
|
||||
import com.cobblemon.mod.common.api.stats.CobblemonStats.getStat
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.client.CobblemonClient
|
||||
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.client.gui.components.Button
|
||||
import net.minecraft.client.gui.screens.Screen
|
||||
import net.minecraft.client.gui.screens.inventory.InventoryScreen
|
||||
import net.minecraft.client.sounds.SoundManager
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.network.protocol.game.ServerboundClientCommandPacket
|
||||
import net.minecraft.stats.Stats
|
||||
import net.minecraft.util.CommonColors
|
||||
import kotlin.math.ceil
|
||||
|
||||
class TrainerCardMenu : Screen(
|
||||
Component.translatable("cobblemon.ui.trainercard.title")
|
||||
), CobblemonRenderable {
|
||||
|
||||
private var elapsedTicks = 0
|
||||
private var lastSyncedTimePlayed = 0
|
||||
private var panelLeft = 0
|
||||
private var panelTop = 0
|
||||
private lateinit var badgeScrollList: BadgesScrollingWidget
|
||||
private lateinit var leftPageArrow: TrainerCardPageArrow
|
||||
private lateinit var rightPageArrow: TrainerCardPageArrow
|
||||
private var currentPage = 0
|
||||
private val maxPages = 3
|
||||
|
||||
override fun isPauseScreen(): Boolean = false
|
||||
|
||||
override fun init() {
|
||||
super.init()
|
||||
elapsedTicks = 0
|
||||
lastSyncedTimePlayed = getTimePlayed()
|
||||
// stats need to update when we open the menu, otherwise time played only updates when stats menu is opened
|
||||
Minecraft.getInstance().connection?.send(
|
||||
ServerboundClientCommandPacket(ServerboundClientCommandPacket.Action.REQUEST_STATS)
|
||||
)
|
||||
|
||||
val badges = Badges.all().sortedBy { it.order }
|
||||
val panelWidth = minOf(220, (width - 16).coerceAtLeast(1))
|
||||
panelLeft = (width - panelWidth) / 2
|
||||
val leftColumnWidth = panelWidth / 2
|
||||
val badgeAreaWidth = panelWidth - leftColumnWidth - 8
|
||||
val columns = ((badgeAreaWidth + BadgesScrollingWidget.SLOT_SPACING) /
|
||||
(BadgesScrollingWidget.SLOT_SIZE + BadgesScrollingWidget.SLOT_SPACING)).coerceIn(1, 4)
|
||||
val badgeWidth = columns * BadgesScrollingWidget.SLOT_SIZE +
|
||||
(columns - 1) * BadgesScrollingWidget.SLOT_SPACING + 4
|
||||
val rowCount = ceil(badges.size.toDouble() / columns).toInt().coerceAtLeast(1)
|
||||
val rowHeight = BadgesScrollingWidget.SLOT_SIZE + BadgesScrollingWidget.SLOT_SPACING
|
||||
val badgeHeight = minOf(rowCount, BadgesScrollingWidget.MAX_VISIBLE_ROWS) * rowHeight
|
||||
val panelHeight = maxOf(92, badgeHeight + 20)
|
||||
panelTop = ((height - panelHeight) / 2).coerceAtLeast(8)
|
||||
|
||||
badgeScrollList = BadgesScrollingWidget(
|
||||
x = panelLeft + panelWidth - badgeWidth,
|
||||
y = panelTop + 10,
|
||||
width = badgeWidth,
|
||||
height = badgeHeight,
|
||||
columns = columns
|
||||
)
|
||||
badgeScrollList.createEntries(badges)
|
||||
addRenderableWidget(badgeScrollList)
|
||||
|
||||
leftPageArrow = TrainerCardPageArrow(
|
||||
buttonX = panelLeft - 10,
|
||||
buttonY = panelTop,
|
||||
width = 16,
|
||||
height = 16,
|
||||
onPress = {},
|
||||
parent = this,
|
||||
isRight = false
|
||||
)
|
||||
rightPageArrow = TrainerCardPageArrow(
|
||||
buttonX = panelLeft + panelWidth + 10,
|
||||
buttonY = panelTop,
|
||||
width = 16,
|
||||
height = 16,
|
||||
onPress = {},
|
||||
parent = this,
|
||||
isRight = true
|
||||
)
|
||||
|
||||
addRenderableWidget(leftPageArrow)
|
||||
addRenderableWidget(rightPageArrow)
|
||||
}
|
||||
|
||||
override fun tick() {
|
||||
super.tick()
|
||||
// make our own live playtime update, otherwise we have to send a packet a second to retrieve the playtime stat
|
||||
val timePlayed = getTimePlayed()
|
||||
if (timePlayed != lastSyncedTimePlayed) {
|
||||
lastSyncedTimePlayed = timePlayed
|
||||
elapsedTicks = 0
|
||||
} else { elapsedTicks++ }
|
||||
}
|
||||
|
||||
override fun render(context: GuiGraphics, mouseX: Int, mouseY: Int, partialTick: Float) {
|
||||
when(currentPage) {
|
||||
0 -> {
|
||||
val portraitX = panelLeft
|
||||
val portraitY = minOf(panelTop + 48, (height - 32).coerceAtLeast(0))
|
||||
val portraitSize = 30
|
||||
val statsTextWidth = (badgeScrollList.x - panelLeft - 8).coerceAtLeast(1)
|
||||
|
||||
val player = Minecraft.getInstance().player ?: return // unsure of why this would ever not return a player but if you're here maybe it's because it did
|
||||
val entity = Minecraft.getInstance().level?.getPlayerByUUID(player.uuid) ?: return
|
||||
|
||||
context.enableScissor(portraitX, portraitY, portraitX + portraitSize, portraitY + portraitSize)
|
||||
InventoryScreen.renderEntityInInventoryFollowsMouse(context,
|
||||
portraitX, portraitY, portraitX + portraitSize, portraitY + portraitSize, 28, 0.5f, mouseX.toFloat(), mouseY.toFloat(),
|
||||
entity
|
||||
)
|
||||
|
||||
context.disableScissor()
|
||||
|
||||
val totalSeconds = (getTimePlayed() + elapsedTicks) / 20
|
||||
val timePlayed = "%d:%02d:%02d:%02d".format(
|
||||
totalSeconds / 86_400, // days
|
||||
totalSeconds % 86_400 / 3_600, // hours
|
||||
totalSeconds % 3_600 / 60, // minutes
|
||||
totalSeconds % 60 // seconds
|
||||
)
|
||||
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = lang("ui.trainermenu.timeplayed", timePlayed),
|
||||
x = panelLeft,
|
||||
y = panelTop + 4,
|
||||
maxCharacterWidth = statsTextWidth
|
||||
)
|
||||
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = lang("ui.trainermenu.pokemon_registered",
|
||||
CobblemonClient.clientPokedexData.getDexCalculatedValue(cobblemonResource("national"), CaughtCount)),
|
||||
x = panelLeft,
|
||||
y = panelTop + 14,
|
||||
maxCharacterWidth = statsTextWidth
|
||||
)
|
||||
|
||||
val playerBattlesWon = player.stats.getValue(Stats.CUSTOM.get(getStat(Cobblemon.statistics.PVP_BATTLES_WON)))
|
||||
val playerBattlesLost = player.stats.getValue(Stats.CUSTOM.get(getStat(Cobblemon.statistics.PVP_BATTLES_LOST)))
|
||||
|
||||
if (playerBattlesWon > 0 || playerBattlesLost > 0) {
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = lang("ui.trainermenu.battle_stats",
|
||||
playerBattlesWon,
|
||||
playerBattlesLost
|
||||
),
|
||||
x = panelLeft,
|
||||
y = panelTop + 24,
|
||||
maxCharacterWidth = statsTextWidth
|
||||
)
|
||||
}
|
||||
|
||||
badgeScrollList.render(context, mouseX, mouseY, partialTick)
|
||||
}
|
||||
}
|
||||
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = Component.literal("$currentPage"),
|
||||
x = panelLeft - 30,
|
||||
y = panelTop
|
||||
)
|
||||
|
||||
if (leftPageArrow.shouldExist()) {
|
||||
leftPageArrow.render(context, mouseX, mouseY, partialTick)
|
||||
}
|
||||
|
||||
if (rightPageArrow.shouldExist()) {
|
||||
rightPageArrow.render(context, mouseX, mouseY, partialTick)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class TrainerCardPageArrow(
|
||||
buttonX: Int,
|
||||
buttonY: Int, width: Int, height: Int, onPress: OnPress,
|
||||
val parent: TrainerCardMenu,
|
||||
val isRight: Boolean
|
||||
): Button(
|
||||
buttonX, buttonY, width, height, "".text(), onPress, DEFAULT_NARRATION
|
||||
) {
|
||||
|
||||
fun shouldExist(): Boolean {
|
||||
if (isRight && parent.currentPage == parent.maxPages - 1) return false
|
||||
if (!isRight && parent.currentPage == 0) return false
|
||||
return true
|
||||
}
|
||||
|
||||
override fun renderWidget(context: GuiGraphics, mouseX: Int, mouseY: Int, partialTick: Float) {
|
||||
context.fill(x, y, x + width, y + height, CommonColors.WHITE)
|
||||
}
|
||||
|
||||
override fun playDownSound(handler: SoundManager) {
|
||||
if (shouldExist()) super.playDownSound(handler)
|
||||
}
|
||||
|
||||
override fun onClick(mouseX: Double, mouseY: Double) {
|
||||
if (!shouldExist()) return
|
||||
parent.currentPage += if (isRight) 1 else -1
|
||||
}
|
||||
}
|
||||
|
||||
private fun getTimePlayed(): Int =
|
||||
Minecraft.getInstance().player?.stats?.getValue(Stats.CUSTOM.get(Stats.PLAY_TIME)) ?: 0
|
||||
|
||||
}
|
||||
@@ -39,6 +39,7 @@ object CobblemonKeyBinds {
|
||||
val PARTY_OVERLAY_UP = this.queue(UpShiftPartyBinding)
|
||||
val SEND_OUT_POKEMON = this.queue(PartySendBinding)
|
||||
val RIDING_FREELOOK = this.queue(RidingFreelookBinding)
|
||||
val TRAINER_MENU = this.queue(TrainerMenuBinding)
|
||||
|
||||
fun register(registrar: (KeyMapping) -> Unit) {
|
||||
this.keyBinds.forEach(registrar::invoke)
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.keybind.keybinds
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.client.CobblemonClient
|
||||
import com.cobblemon.mod.common.client.gui.summary.Summary
|
||||
import com.cobblemon.mod.common.client.gui.trainercard.TrainerCardMenu
|
||||
import com.cobblemon.mod.common.client.keybind.CobblemonPartyLockedKeyBinding
|
||||
import com.cobblemon.mod.common.client.keybind.KeybindCategories
|
||||
import com.mojang.blaze3d.platform.InputConstants
|
||||
import net.minecraft.client.Minecraft
|
||||
|
||||
object TrainerMenuBinding : CobblemonPartyLockedKeyBinding(
|
||||
"key.cobblemon.trainermenu",
|
||||
InputConstants.Type.KEYSYM,
|
||||
InputConstants.KEY_N,
|
||||
KeybindCategories.COBBLEMON_CATEGORY
|
||||
) {
|
||||
override fun onPress() {
|
||||
Minecraft.getInstance().setScreen(TrainerCardMenu())
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -34,7 +34,6 @@ import com.cobblemon.mod.common.client.render.models.blockbench.bedrock.animatio
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.quirk.ModelQuirk
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.quirk.QuirkData
|
||||
import com.cobblemon.mod.common.client.sound.instances.UIEntitySoundInstance
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
@@ -45,6 +44,7 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.multiplayer.ClientLevel
|
||||
import net.minecraft.client.resources.sounds.SimpleSoundInstance
|
||||
import net.minecraft.commands.arguments.item.ItemParser
|
||||
import net.minecraft.sounds.SoundEvent
|
||||
import net.minecraft.world.entity.Entity
|
||||
@@ -289,7 +289,7 @@ abstract class PosableState : Schedulable {
|
||||
entity.level().playLocalSound(entity, soundEvent, entity.soundSource, volume, pitch)
|
||||
}
|
||||
} else {
|
||||
Minecraft.getInstance().soundManager.play(UIEntitySoundInstance(soundEvent, volume, pitch))
|
||||
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(soundEvent, volume, pitch))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -19,7 +19,6 @@ import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Bone
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.RenderContext
|
||||
import com.cobblemon.mod.common.client.sound.instances.AlphaCrySoundInstance
|
||||
import com.cobblemon.mod.common.client.sound.instances.UIEntitySoundInstance
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.effectiveName
|
||||
import com.cobblemon.mod.common.util.genericRuntime
|
||||
@@ -32,6 +31,7 @@ import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.client.multiplayer.ClientLevel
|
||||
import net.minecraft.client.resources.sounds.EntityBoundSoundInstance
|
||||
import net.minecraft.client.resources.sounds.SimpleSoundInstance
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.sounds.SoundEvent
|
||||
import net.minecraft.world.entity.Entity
|
||||
@@ -121,7 +121,7 @@ class BedrockSoundKeyframe(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Minecraft.getInstance().soundManager.play(UIEntitySoundInstance(soundEvent))
|
||||
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(soundEvent, 1F, 1F))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -29,8 +29,8 @@ class FarfetchdGalarianModel(root: ModelPart) : PokemonPosableModel(root), Heade
|
||||
override var portraitScale = 2.6F
|
||||
override var portraitTranslation = Vec3(-0.2, -1.0, 0.0)
|
||||
|
||||
override var profileScale = 0.93F
|
||||
override var profileTranslation = Vec3(-0.1, 0.36, 0.0)
|
||||
override var profileScale = 1.1F
|
||||
override var profileTranslation = Vec3(-0.1, 0.1, 0.0)
|
||||
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
|
||||
+2
-2
@@ -28,8 +28,8 @@ class FarfetchdModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame,
|
||||
override var portraitScale = 2.6F
|
||||
override var portraitTranslation = Vec3(-0.2, -1.0, 0.0)
|
||||
|
||||
override var profileScale = 0.93F
|
||||
override var profileTranslation = Vec3(-0.1, 0.36, 0.0)
|
||||
override var profileScale = 1.1F
|
||||
override var profileTranslation = Vec3(-0.1, 0.1, 0.0)
|
||||
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
|
||||
+2
-2
@@ -23,8 +23,8 @@ class KabutoModel(root: ModelPart) : PokemonPosableModel(root) {
|
||||
override var portraitScale = 3.3F
|
||||
override var portraitTranslation = Vec3(0.0, -3.3, 0.0)
|
||||
|
||||
override var profileScale = 1.25F
|
||||
override var profileTranslation = Vec3(0.0, -0.17, 0.0)
|
||||
override var profileScale = 1.6F
|
||||
override var profileTranslation = Vec3(0.0, -0.6, 0.0)
|
||||
|
||||
lateinit var standing: CobblemonPose
|
||||
lateinit var walk: CobblemonPose
|
||||
|
||||
+2
-2
@@ -21,8 +21,8 @@ class HoothootModel (root: ModelPart) : PokemonPosableModel(root) {
|
||||
|
||||
override var portraitScale = 2.2F
|
||||
override var portraitTranslation = Vec3(-0.25, -0.9, 0.0)
|
||||
override var profileScale = 0.82F
|
||||
override var profileTranslation = Vec3(0.0, 0.53, 0.0)
|
||||
override var profileScale = 1.0F
|
||||
override var profileTranslation = Vec3(0.0, 0.3, 0.0)
|
||||
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
|
||||
+2
-2
@@ -29,8 +29,8 @@ class WooperModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
|
||||
override var portraitScale = 2.0F
|
||||
override var portraitTranslation = Vec3(-0.15, -0.65, 0.0)
|
||||
|
||||
override var profileScale = 0.75F
|
||||
override var profileTranslation = Vec3(0.0, 0.6, 0.0)
|
||||
override var profileScale = 0.9F
|
||||
override var profileTranslation = Vec3(0.0, 0.4, 0.0)
|
||||
|
||||
lateinit var shoulderLeft: Pose
|
||||
lateinit var shoulderRight: Pose
|
||||
|
||||
+2
-2
@@ -29,8 +29,8 @@ class WooperPaldeanModel(root: ModelPart) : PokemonPosableModel(root), HeadedFra
|
||||
override var portraitScale = 2.0F
|
||||
override var portraitTranslation = Vec3(-0.15, -0.65, 0.0)
|
||||
|
||||
override var profileScale = 0.75F
|
||||
override var profileTranslation = Vec3(0.0, 0.6, 0.0)
|
||||
override var profileScale = 0.9F
|
||||
override var profileTranslation = Vec3(0.0, 0.4, 0.0)
|
||||
|
||||
lateinit var shoulderLeft: Pose
|
||||
lateinit var shoulderRight: Pose
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ class DusclopsModel (root: ModelPart) : PokemonPosableModel(root) {
|
||||
lateinit var battleidle: Pose
|
||||
|
||||
override fun registerPoses() {
|
||||
animations["cry"] = "q.bedrock_stateful('dusclops', 'cry')".asExpressionLike()
|
||||
animations["cry"] = "q.bedrock_stateful('squirtle', 'cry')".asExpressionLike()
|
||||
|
||||
val blink = quirk { bedrockStateful("dusclops", "blink") }
|
||||
|
||||
|
||||
-3
@@ -12,7 +12,6 @@ import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonP
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
@@ -29,8 +28,6 @@ class MasquerainModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame
|
||||
lateinit var walk: Pose
|
||||
lateinit var standing: Pose
|
||||
override fun registerPoses() {
|
||||
animations["cry"] = "q.bedrock_stateful('masquerain', 'cry')".asExpressionLike()
|
||||
|
||||
val blink = quirk { bedrockStateful("masquerain", "blink") }
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
|
||||
-3
@@ -14,7 +14,6 @@ import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonP
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.ModelPartTransformation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.isInWater
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
@@ -37,8 +36,6 @@ class SurskitModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
|
||||
val wateroffset = -8
|
||||
|
||||
override fun registerPoses() {
|
||||
animations["cry"] = "q.bedrock_stateful('surskit', 'cry')".asExpressionLike()
|
||||
|
||||
val blink = quirk { bedrockStateful("surskit", "blink") }
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
|
||||
-3
@@ -14,7 +14,6 @@ import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonP
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.ModelPartTransformation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
@@ -37,8 +36,6 @@ class CombeeModel (root: ModelPart) : PokemonPosableModel(root) {
|
||||
val shoulderZOffset = 8
|
||||
|
||||
override fun registerPoses() {
|
||||
animations["cry"] = "q.bedrock_stateful('combee', 'cry')".asExpressionLike()
|
||||
|
||||
val blink1 = quirk { bedrockStateful("combee", "blink_right") }
|
||||
val blink2 = quirk { bedrockStateful("combee", "blink_gender") }
|
||||
val blink3 = quirk { bedrockStateful("combee", "blink_left") }
|
||||
|
||||
-3
@@ -12,7 +12,6 @@ import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonP
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
@@ -31,8 +30,6 @@ class VespiquenModel (root: ModelPart) : PokemonPosableModel(root) {
|
||||
lateinit var standing: Pose
|
||||
|
||||
override fun registerPoses() {
|
||||
animations["cry"] = "q.bedrock_stateful('vespiquen', 'cry')".asExpressionLike()
|
||||
|
||||
val blink1 = quirk { bedrockStateful("vespiquen", "blink") }
|
||||
val wingsleep = quirk { bedrockStateful("vespiquen", "sleep_flap") }
|
||||
|
||||
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen5
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class SerperiorModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("serperior")
|
||||
override val head = getPart("head_ai")
|
||||
|
||||
override var portraitScale = 2.5F
|
||||
override var portraitTranslation = Vec3(-0.3, 1.25, 0.0)
|
||||
|
||||
override var profileScale = 0.6F
|
||||
override var profileTranslation = Vec3(0.0, 0.8, 0.0)
|
||||
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
lateinit var sleep: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("serperior", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("serperior", "blink") }
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
animations = arrayOf(bedrock("serperior", "sleep"))
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("serperior", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = PoseType.MOVING_POSES,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("serperior", "ground_walk")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen5
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class ServineModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame, BimanualFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("servine")
|
||||
override val head = getPart("head_ai")
|
||||
override val rightArm = getPart("arm_right")
|
||||
override val leftArm = getPart("arm_left")
|
||||
override val rightLeg = getPart("leg_right")
|
||||
override val leftLeg = getPart("leg_left")
|
||||
|
||||
override var portraitScale = 2.6F
|
||||
override var portraitTranslation = Vec3(-0.15, 0.75, 0.0)
|
||||
override var profileScale = 0.8F
|
||||
override var profileTranslation = Vec3(0.0, 0.55, 0.0)
|
||||
|
||||
lateinit var sleep: Pose
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("servine", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("servine", "blink") }
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
transformTicks = 10,
|
||||
animations = arrayOf(bedrock("servine", "sleep"))
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("servine", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walking",
|
||||
poseTypes = PoseType.MOVING_POSES,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("servine", "ground_walk")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen5
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class SnivyModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame, BimanualFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("snivy")
|
||||
override val head = getPart("head_ai")
|
||||
override val rightArm = getPart("arm_right")
|
||||
override val leftArm = getPart("arm_left")
|
||||
override val rightLeg = getPart("leg_right")
|
||||
override val leftLeg = getPart("leg_left")
|
||||
|
||||
override var portraitScale = 2.0F
|
||||
override var portraitTranslation = Vec3(-0.15, 0.32, 0.0)
|
||||
override var profileScale = 0.8F
|
||||
override var profileTranslation = Vec3(0.0, 0.55, 0.0)
|
||||
|
||||
lateinit var sleep: Pose
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("snivy", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("snivy", "blink") }
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
transformTicks = 10,
|
||||
animations = arrayOf(bedrock("snivy", "sleep"))
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("snivy", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walking",
|
||||
poseTypes = PoseType.MOVING_POSES,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("snivy", "ground_walk")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -23,7 +23,7 @@ class CarbinkModel (root: ModelPart) : PokemonPosableModel(root) {
|
||||
override var portraitScale = 1.8F
|
||||
override var portraitTranslation = Vec3(0.0, 0.2, 0.0)
|
||||
|
||||
override var profileScale = 0.68F
|
||||
override var profileScale = 0.85F
|
||||
override var profileTranslation = Vec3(0.0, 0.7, 0.0)
|
||||
|
||||
lateinit var standing: CobblemonPose
|
||||
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen6
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class GourgeistModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("gourgeist")
|
||||
override val head = getPart("head")
|
||||
|
||||
override var portraitScale = 4.0F
|
||||
override var portraitTranslation = Vec3(-0.1, 0.6, 0.0)
|
||||
|
||||
override var profileScale = 0.8F
|
||||
override var profileTranslation = Vec3(0.0, 0.55, 0.0)
|
||||
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
lateinit var hovering: Pose
|
||||
lateinit var fly: Pose
|
||||
lateinit var sleep: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("gourgeist", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("gourgeist", "blink") }
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = PoseType.UI_POSES + PoseType.STAND,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("gourgeist", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseType = PoseType.WALK,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("gourgeist", "ground_walk")
|
||||
)
|
||||
)
|
||||
|
||||
hovering = registerPose(
|
||||
poseName = "hovering",
|
||||
poseType = PoseType.HOVER,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("gourgeist", "air_idle")
|
||||
)
|
||||
)
|
||||
|
||||
fly = registerPose(
|
||||
poseName = "fly",
|
||||
poseType = PoseType.FLY,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("gourgeist", "air_fly")
|
||||
)
|
||||
)
|
||||
|
||||
sleep = registerPose(
|
||||
poseName = "sleep",
|
||||
poseType = PoseType.SLEEP,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("gourgeist", "sleep")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen6
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.CobblemonPose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class PumpkabooModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("pumpkaboo")
|
||||
override val head = getPart("head")
|
||||
|
||||
override var portraitScale = 3.5F
|
||||
override var portraitTranslation = Vec3(0.0, -1.5, 0.0)
|
||||
|
||||
override var profileScale = 1.0F
|
||||
override var profileTranslation = Vec3(0.0, 0.25, 0.0)
|
||||
|
||||
lateinit var standing: CobblemonPose
|
||||
lateinit var walk: CobblemonPose
|
||||
lateinit var battleidle: CobblemonPose
|
||||
lateinit var sleep: CobblemonPose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("pumpkaboo", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("pumpkaboo", "blink") }
|
||||
val quirk = quirk { bedrockStateful("pumpkaboo", "quirk_idle") }
|
||||
|
||||
sleep = registerPose(
|
||||
poseName = "sleep",
|
||||
poseType = PoseType.SLEEP,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("pumpkaboo", "sleep")
|
||||
)
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
|
||||
quirks = arrayOf(blink, quirk),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("pumpkaboo", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = PoseType.MOVING_POSES,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("pumpkaboo", "ground_walk")
|
||||
)
|
||||
)
|
||||
|
||||
battleidle = registerPose(
|
||||
poseName = "battleidle",
|
||||
poseTypes = PoseType.STATIONARY_POSES,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("pumpkaboo", "battle_idle")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -26,8 +26,8 @@ class ScatterbugModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame
|
||||
override var portraitScale = 2.6F
|
||||
override var portraitTranslation = Vec3(-0.2, -1.9, 0.0)
|
||||
|
||||
override var profileScale = 0.98F
|
||||
override var profileTranslation = Vec3(0.0, 0.28, 0.0)
|
||||
override var profileScale = 1.2F
|
||||
override var profileTranslation = Vec3(0.0, 0.05, 0.0)
|
||||
|
||||
lateinit var standing: CobblemonPose
|
||||
lateinit var walk: CobblemonPose
|
||||
|
||||
+2
-2
@@ -36,8 +36,8 @@ class CharcadetModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame,
|
||||
override var portraitScale = 1.7F
|
||||
override var portraitTranslation = Vec3(-0.15, 0.08, 0.0)
|
||||
|
||||
override var profileScale = 0.58F
|
||||
override var profileTranslation = Vec3(0.0, 0.91, 0.0)
|
||||
override var profileScale = 0.8F
|
||||
override var profileTranslation = Vec3(0.0, 0.6, 0.0)
|
||||
|
||||
lateinit var standing: CobblemonPose
|
||||
lateinit var walking: CobblemonPose
|
||||
|
||||
+2
-2
@@ -35,8 +35,8 @@ class QuaquavalModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame,
|
||||
override var portraitScale = 2.3F
|
||||
override var portraitTranslation = Vec3(-0.42, 3.7, 0.0)
|
||||
|
||||
override var profileScale = 0.36F
|
||||
override var profileTranslation = Vec3(0.0, 1.19, 0.0)
|
||||
override var profileScale = 0.32F
|
||||
override var profileTranslation = Vec3(0.0, 1.24, 0.0)
|
||||
|
||||
lateinit var standing: CobblemonPose
|
||||
lateinit var standing2: CobblemonPose
|
||||
|
||||
+208
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen9
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.WingFlapIdleAnimation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.createTransformation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BiWingedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.ModelPartTransformation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.parabolaFunction
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.sineFunction
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class SquawkabillyModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame, BiWingedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("squawkabilly")
|
||||
override val head = getPart("head")
|
||||
override val leftWing = getPart("wing_left")
|
||||
override val rightWing = getPart("wing_right")
|
||||
override val leftLeg = getPart("leg_left")
|
||||
override val rightLeg = getPart("leg_right")
|
||||
private val tail = getPart("tail")
|
||||
|
||||
override var portraitScale = 2.0F
|
||||
override var portraitTranslation = Vec3(-0.2, -0.2, 0.0)
|
||||
|
||||
override var profileScale = 0.85F
|
||||
override var profileTranslation = Vec3(0.0, 0.51, 0.0)
|
||||
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
lateinit var hovering: Pose
|
||||
lateinit var flying: Pose
|
||||
lateinit var shoulderLeft: Pose
|
||||
lateinit var shoulderRight: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("squawkabilly", "cry") }
|
||||
|
||||
val shoulderOffsetX = -1.0
|
||||
val shoulderOffsetY = 0
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("squawkabilly", "blink") }
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
quirks = arrayOf(blink),
|
||||
poseTypes = PoseType.UI_POSES + PoseType.STAND,
|
||||
transformTicks = 10,
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("squawkabilly", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
quirks = arrayOf(blink),
|
||||
poseType = PoseType.WALK,
|
||||
transformTicks = 10,
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("squawkabilly", "ground_idle"),
|
||||
rootPart.translation(
|
||||
function = parabolaFunction(
|
||||
peak = -4F,
|
||||
period = 0.4F
|
||||
),
|
||||
timeVariable = { state, _, _ -> state.animationSeconds },
|
||||
axis = ModelPartTransformation.Y_AXIS
|
||||
),
|
||||
head.translation(
|
||||
function = sineFunction(
|
||||
amplitude = (-20F).toRadians(),
|
||||
period = 1F,
|
||||
verticalShift = (-10F).toRadians()
|
||||
),
|
||||
axis = ModelPartTransformation.X_AXIS,
|
||||
timeVariable = { state, _, _ -> state.animationSeconds }
|
||||
),
|
||||
leftLeg.rotation(
|
||||
function = parabolaFunction(
|
||||
tightness = -20F,
|
||||
phaseShift = 0F,
|
||||
verticalShift = (30F).toRadians()
|
||||
),
|
||||
axis = ModelPartTransformation.X_AXIS,
|
||||
timeVariable = { _, _, ageInTicks -> ageInTicks / 20 },
|
||||
),
|
||||
rightLeg.rotation(
|
||||
function = parabolaFunction(
|
||||
tightness = -20F,
|
||||
phaseShift = 0F,
|
||||
verticalShift = (30F).toRadians()
|
||||
),
|
||||
axis = ModelPartTransformation.X_AXIS,
|
||||
timeVariable = { _, _, ageInTicks -> ageInTicks / 20 },
|
||||
),
|
||||
tail.rotation(
|
||||
function = sineFunction(
|
||||
amplitude = (-5F).toRadians(),
|
||||
period = 1F
|
||||
),
|
||||
axis = ModelPartTransformation.X_AXIS,
|
||||
timeVariable = { _, _, ageInTicks -> ageInTicks / 20 },
|
||||
),
|
||||
wingFlap(
|
||||
flapFunction = sineFunction(
|
||||
amplitude = (-5F).toRadians(),
|
||||
period = 0.4F,
|
||||
phaseShift = 0.00F,
|
||||
verticalShift = (-20F).toRadians()
|
||||
),
|
||||
timeVariable = { state, _, _ -> state.animationSeconds },
|
||||
axis = ModelPartTransformation.Z_AXIS
|
||||
),
|
||||
rightWing.translation(
|
||||
function = parabolaFunction(
|
||||
tightness = -10F,
|
||||
phaseShift = 30F,
|
||||
verticalShift = (25F).toRadians()
|
||||
),
|
||||
axis = ModelPartTransformation.Y_AXIS,
|
||||
timeVariable = { _, _, ageInTicks -> ageInTicks / 20 },
|
||||
),
|
||||
leftWing.translation(
|
||||
function = parabolaFunction(
|
||||
tightness = -10F,
|
||||
phaseShift = 30F,
|
||||
verticalShift = (25F).toRadians()
|
||||
),
|
||||
axis = ModelPartTransformation.Y_AXIS,
|
||||
timeVariable = { _, _, ageInTicks -> ageInTicks / 20 },
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
hovering = registerPose(
|
||||
poseName = "hovering",
|
||||
quirks = arrayOf(blink),
|
||||
poseTypes = setOf(PoseType.FLOAT, PoseType.HOVER),
|
||||
transformTicks = 10,
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
WingFlapIdleAnimation(this,
|
||||
flapFunction = sineFunction(verticalShift = -10F.toRadians(), period = 0.9F, amplitude = 0.9F),
|
||||
timeVariable = { state, _, _ -> state.animationSeconds },
|
||||
axis = ModelPartTransformation.Z_AXIS
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
flying = registerPose(
|
||||
poseName = "flying",
|
||||
quirks = arrayOf(blink),
|
||||
poseTypes = setOf(PoseType.FLY, PoseType.SWIM),
|
||||
transformTicks = 10,
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
WingFlapIdleAnimation(this,
|
||||
flapFunction = sineFunction(verticalShift = -14F.toRadians(), period = 0.9F, amplitude = 0.9F),
|
||||
timeVariable = { state, _, _ -> state.animationSeconds },
|
||||
axis = ModelPartTransformation.Z_AXIS
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
shoulderLeft = registerPose(
|
||||
poseType = PoseType.SHOULDER_LEFT,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("squawkabilly", "ground_idle")
|
||||
),
|
||||
transformedParts = arrayOf(
|
||||
rootPart.createTransformation().addPosition(shoulderOffsetX, shoulderOffsetY, 0.0)
|
||||
)
|
||||
)
|
||||
|
||||
shoulderRight = registerPose(
|
||||
poseType = PoseType.SHOULDER_RIGHT,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("squawkabilly", "ground_idle")
|
||||
),
|
||||
transformedParts = arrayOf(
|
||||
rootPart.createTransformation().addPosition(-shoulderOffsetX, shoulderOffsetY, 0.0)
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
// override fun getFaintAnimation(
|
||||
// pokemonEntity: PokemonEntity,
|
||||
// state: PosableState<PokemonEntity>
|
||||
// ) = if (state.isNotPosedIn(sleep)) bedrockStateful("squawkabilly", "faint") else null
|
||||
}
|
||||
+6
@@ -322,6 +322,8 @@ object VaryingModelRepository {
|
||||
inbuilt("loudred", :: LoudredModel)
|
||||
inbuilt("exploud", :: ExploudModel)
|
||||
inbuilt("cryogonal", :: CryogonalModel)
|
||||
inbuilt("pumpkaboo", :: PumpkabooModel)
|
||||
inbuilt("gourgeist", :: GourgeistModel)
|
||||
inbuilt("eiscue", :: EiscueModel)
|
||||
inbuilt("wooloo", :: WoolooModel)
|
||||
inbuilt("dubwool", :: DubwoolModel)
|
||||
@@ -338,6 +340,9 @@ object VaryingModelRepository {
|
||||
inbuilt("thwackey", ::ThwackeyModel)
|
||||
inbuilt("rillaboom", ::RillaboomModel)
|
||||
inbuilt("samurott", ::SamurottModel)
|
||||
inbuilt("snivy", ::SnivyModel)
|
||||
inbuilt("servine", ::ServineModel)
|
||||
inbuilt("serperior", ::SerperiorModel)
|
||||
inbuilt("slugma", ::SlugmaModel)
|
||||
inbuilt("magcargo", ::MagcargoModel)
|
||||
inbuilt("slugma_shiny", ::SlugmaShinyModel)
|
||||
@@ -397,6 +402,7 @@ object VaryingModelRepository {
|
||||
inbuilt("bunnelby", ::BunnelbyModel)
|
||||
inbuilt("arrokuda", ::ArrokudaModel)
|
||||
inbuilt("barraskewda", ::BarraskewdaModel)
|
||||
inbuilt("squawkabilly", ::SquawkabillyModel)
|
||||
inbuilt("ponyta_galarian", ::PonytaGalarianModel)
|
||||
inbuilt("rapidash_galarian", ::RapidashGalarianModel)
|
||||
inbuilt("volbeat", ::VolbeatModel)
|
||||
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.sound.instances
|
||||
|
||||
import net.minecraft.client.resources.sounds.SimpleSoundInstance
|
||||
import net.minecraft.client.resources.sounds.SoundInstance
|
||||
import net.minecraft.sounds.SoundEvent
|
||||
import net.minecraft.sounds.SoundSource
|
||||
|
||||
/**
|
||||
* Plays a sound for a Pokémon rendered in a GUI, where there is no entity to take the sound source from.
|
||||
* Unlike [SimpleSoundInstance.forUI] this uses [SoundSource.NEUTRAL] so the Friendly Creatures slider applies.
|
||||
*/
|
||||
class UIEntitySoundInstance(sound: SoundEvent, volume: Float = 1F, pitch: Float = 1F) :
|
||||
SimpleSoundInstance(sound.location, SoundSource.NEUTRAL, volume, pitch, SoundInstance.createUnseededRandom(),
|
||||
false, 0, SoundInstance.Attenuation.NONE, 0.0, 0.0, 0.0, true)
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.cobblemon.mod.common.command
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.permission.CobblemonPermissions
|
||||
import com.cobblemon.mod.common.command.argument.BadgeArgumentType
|
||||
import com.cobblemon.mod.common.util.permission
|
||||
import com.mojang.brigadier.Command
|
||||
import com.mojang.brigadier.CommandDispatcher
|
||||
import com.mojang.brigadier.context.CommandContext
|
||||
import net.minecraft.commands.CommandSourceStack
|
||||
import net.minecraft.commands.Commands
|
||||
import net.minecraft.commands.arguments.EntityArgument
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
object BadgeCommand {
|
||||
|
||||
private const val NAME = "badge"
|
||||
private const val GIVE = "give"
|
||||
private const val REMOVE = "remove"
|
||||
private const val PLAYER = "player"
|
||||
|
||||
fun register(dispatcher: CommandDispatcher<CommandSourceStack>) {
|
||||
val command =
|
||||
Commands.literal(NAME)
|
||||
.permission(CobblemonPermissions.BADGE)
|
||||
.then(Commands.literal(GIVE)
|
||||
.then(Commands.argument(PLAYER, EntityArgument.player())
|
||||
.then(Commands.argument(BADGE, BadgeArgumentType.badge())
|
||||
.executes { executeGive(it, EntityArgument.getPlayer(it, PLAYER)) }
|
||||
)
|
||||
)
|
||||
)
|
||||
.then(Commands.literal(REMOVE)
|
||||
.then(Commands.argument(PLAYER, EntityArgument.player())
|
||||
.then(Commands.argument(BADGE, BadgeArgumentType.badge())
|
||||
.executes { executeRemove(it, EntityArgument.getPlayer(it, PLAYER)) }
|
||||
)
|
||||
)
|
||||
)
|
||||
dispatcher.register(command)
|
||||
}
|
||||
|
||||
private fun executeGive(context: CommandContext<CommandSourceStack>, player: ServerPlayer): Int {
|
||||
val badge = BadgeArgumentType.getBadge(context, BADGE)
|
||||
val changed = Cobblemon.playerDataManager.getBadgeData(player).give(badge)
|
||||
val message = if (changed) {
|
||||
"Gave ${badge.name} to ${player.name.string}."
|
||||
} else {
|
||||
"${player.name.string} already has ${badge.name}."
|
||||
}
|
||||
context.source.sendSuccess({ Component.literal(message) }, true)
|
||||
return Command.SINGLE_SUCCESS
|
||||
}
|
||||
|
||||
private fun executeRemove(context: CommandContext<CommandSourceStack>, player: ServerPlayer): Int {
|
||||
val badge = BadgeArgumentType.getBadge(context, BADGE)
|
||||
val changed = Cobblemon.playerDataManager.getBadgeData(player).remove(badge)
|
||||
val message = if (changed) {
|
||||
"Removed ${badge} from ${player.name.string}." // TODO move this to lang
|
||||
} else {
|
||||
"${player.name.string} does not have ${badge.name}."
|
||||
}
|
||||
context.source.sendSuccess({ Component.literal(message) }, true)
|
||||
return Command.SINGLE_SUCCESS
|
||||
}
|
||||
|
||||
private const val BADGE = "badge"
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.command.argument
|
||||
|
||||
import com.cobblemon.mod.common.api.badges.Badge
|
||||
import com.cobblemon.mod.common.api.badges.Badges
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.mojang.brigadier.StringReader
|
||||
import com.mojang.brigadier.arguments.ArgumentType
|
||||
import com.mojang.brigadier.context.CommandContext
|
||||
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType
|
||||
import com.mojang.brigadier.suggestion.Suggestions
|
||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder
|
||||
import net.minecraft.commands.SharedSuggestionProvider
|
||||
import net.minecraft.network.chat.Component
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
class BadgeArgumentType : ArgumentType<Badge> {
|
||||
|
||||
override fun parse(reader: StringReader): Badge {
|
||||
val identifier = try {
|
||||
reader.asIdentifierDefaultingNamespace()
|
||||
} catch (exception: Exception) {
|
||||
throw SimpleCommandExceptionType(INVALID_BADGE).createWithContext(reader)
|
||||
}
|
||||
return Badges.getByIdentifier(identifier)
|
||||
?: throw SimpleCommandExceptionType(INVALID_BADGE).createWithContext(reader)
|
||||
}
|
||||
|
||||
override fun <S : Any> listSuggestions(
|
||||
context: CommandContext<S>,
|
||||
builder: SuggestionsBuilder
|
||||
): CompletableFuture<Suggestions> {
|
||||
return SharedSuggestionProvider.suggest(Badges.all().map { it.identifier.toString() }, builder)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val INVALID_BADGE = Component.translatable("cobblemon.command.badge.invalid")
|
||||
|
||||
fun badge() = BadgeArgumentType()
|
||||
|
||||
fun <S> getBadge(context: CommandContext<S>, name: String): Badge =
|
||||
context.getArgument(name, Badge::class.java)
|
||||
}
|
||||
}
|
||||
@@ -164,9 +164,6 @@ class CobblemonConfig {
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "experience_multiplier", SERVER)
|
||||
var experienceMultiplier = 2F
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "predation_chance", SERVER)
|
||||
var predationChance = 0.05F
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "pokemon_per_chunk", SERVER)
|
||||
var pokemonPerChunk = 1F
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.data
|
||||
import com.cobblemon.mod.common.*
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.api.abilities.Abilities
|
||||
import com.cobblemon.mod.common.api.badges.Badges
|
||||
import com.cobblemon.mod.common.api.berry.Berries
|
||||
import com.cobblemon.mod.common.api.cooking.Seasonings
|
||||
import com.cobblemon.mod.common.api.data.DataProvider
|
||||
@@ -120,6 +121,7 @@ object CobblemonDataProvider : DataProvider {
|
||||
this.register(SpawnBaitEffects, reloadable = false)
|
||||
this.register(CobblemonRideSettings, reloadable = true)
|
||||
this.register(TechnicalMachines, reloadable = false)
|
||||
this.register(Badges, reloadable = true)
|
||||
SpawnBait.Effects.setupEffects()
|
||||
|
||||
PlatformEvents.SERVER_PLAYER_LOGOUT.subscribe {
|
||||
|
||||
@@ -9,10 +9,7 @@
|
||||
package com.cobblemon.mod.common.entity.ai
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.getMemorySafely
|
||||
import com.cobblemon.mod.common.util.mainThreadRuntime
|
||||
import com.cobblemon.mod.common.util.resolveInt
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
@@ -32,23 +29,12 @@ object FleeFromAttackerTask {
|
||||
Trigger { _, entity, _ ->
|
||||
val hurtByEntity = it.get(hurtByEntity)
|
||||
val avoidTarget = it.tryGet(avoidTarget).orElse(null)
|
||||
|
||||
if (avoidTarget != null && avoidTarget == hurtByEntity) {
|
||||
if (avoidTarget != null && avoidTarget == hurtByEntity.uuid) {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
mainThreadRuntime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
val avoidDurationTicks = mainThreadRuntime.resolveInt(avoidDurationTicks)
|
||||
|
||||
val pokemonEntity = entity as? PokemonEntity
|
||||
pokemonEntity?.let {
|
||||
it.after(1.0f) {
|
||||
it.playMoodParticle("mood_stress")
|
||||
}
|
||||
}
|
||||
|
||||
entity.brain.setMemoryWithExpiry(MemoryModuleType.AVOID_TARGET, hurtByEntity, avoidDurationTicks.toLong())
|
||||
|
||||
return@Trigger true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
package com.cobblemon.mod.common.entity.ai
|
||||
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.OneShot
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
|
||||
@@ -25,16 +24,10 @@ object GetAngryAtAttackerTask {
|
||||
Trigger { _, entity, _ ->
|
||||
val hurtByEntity = it.get(hurtByEntity)
|
||||
val angryAt = it.tryGet(angryAt).orElse(null)
|
||||
|
||||
if (angryAt != null && angryAt == hurtByEntity.uuid) {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
val becomingAngry = angryAt == null
|
||||
entity.brain.setMemory(MemoryModuleType.ANGRY_AT, hurtByEntity.uuid)
|
||||
if (becomingAngry) {
|
||||
(entity as PokemonEntity?)?.playMoodParticle("mood_anger_steam")
|
||||
}
|
||||
return@Trigger true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,9 +34,6 @@ import com.cobblemon.mod.common.api.molang.MoLangFunctions.addPokemonFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
|
||||
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||
import com.cobblemon.mod.common.api.net.serializers.PlatformTypeDataSerializer
|
||||
import com.cobblemon.mod.common.api.net.serializers.PoseTypeDataSerializer
|
||||
import com.cobblemon.mod.common.api.net.serializers.RideBoostsDataSerializer
|
||||
@@ -428,9 +425,6 @@ open class PokemonEntity(
|
||||
|
||||
var occupiedSeats = mutableMapOf<Seat, Entity>()
|
||||
|
||||
var moodParticleLock = false
|
||||
var playedZeroStaminaParticle = false
|
||||
|
||||
init {
|
||||
delegate.initialize(this)
|
||||
delegate.changePokemon(pokemon)
|
||||
@@ -910,27 +904,6 @@ open class PokemonEntity(
|
||||
return future
|
||||
}
|
||||
|
||||
fun playMoodParticle(particleName: String) {
|
||||
if (moodParticleLock) return
|
||||
|
||||
val actionEffect = ActionEffects.actionEffects[cobblemonResource(particleName)] ?: return
|
||||
|
||||
cry()
|
||||
|
||||
val context = ActionEffectContext(
|
||||
actionEffect = actionEffect,
|
||||
providers = mutableListOf(UsersProvider(this)),
|
||||
runtime = runtime,
|
||||
level = level()
|
||||
)
|
||||
actionEffect.run(context)
|
||||
|
||||
moodParticleLock = true
|
||||
after(5.0f) {
|
||||
moodParticleLock = false
|
||||
}
|
||||
}
|
||||
|
||||
override fun saveWithoutId(nbt: CompoundTag): CompoundTag {
|
||||
val tethering = this.tethering
|
||||
if (tethering != null) {
|
||||
@@ -1321,7 +1294,16 @@ open class PokemonEntity(
|
||||
}
|
||||
|
||||
private fun showInteractionWheel(player: ServerPlayer, itemStack: ItemStack) {
|
||||
val canRide = isRideableFor(player)
|
||||
val canRide = ifRidingAvailableSupply(false) { behaviour, settings, state ->
|
||||
if (platform != PlatformType.NONE) return@ifRidingAvailableSupply false
|
||||
if (tethering != null) return@ifRidingAvailableSupply false;
|
||||
if (seats.isEmpty()) return@ifRidingAvailableSupply false;
|
||||
if ((owner as? ServerPlayer)?.isInBattle() == true) return@ifRidingAvailableSupply false;
|
||||
if (this.owner != player && this.passengers.isEmpty()) return@ifRidingAvailableSupply false;
|
||||
if(pokemon.effectiveScale < Cobblemon.config.minimumRidingScale) return@ifRidingAvailableSupply false;
|
||||
if(beamMode == 3) return@ifRidingAvailableSupply false;
|
||||
return@ifRidingAvailableSupply behaviour.isActive(settings, state, this);
|
||||
}
|
||||
if (pokemon.getOwnerPlayer() == player) {
|
||||
val cosmeticItemDefinition = CobblemonCosmeticItems.findValidCosmeticForPokemonAndItem(
|
||||
player.level().registryAccess(),
|
||||
@@ -1343,18 +1325,6 @@ open class PokemonEntity(
|
||||
}
|
||||
}
|
||||
|
||||
fun isRideableFor(player: ServerPlayer): Boolean = ifRidingAvailableSupply(false) canRide@{ behaviour, settings, state ->
|
||||
if (!player.canInteractWithEntity(this, player.entityInteractionRange())) return@canRide false
|
||||
if (platform != PlatformType.NONE) return@canRide false
|
||||
if (tethering != null) return@canRide false
|
||||
if (seats.isEmpty()) return@canRide false
|
||||
if ((owner as? ServerPlayer)?.isInBattle() == true) return@canRide false
|
||||
if (this.owner != player && this.passengers.isEmpty()) return@canRide false
|
||||
if (pokemon.effectiveScale < Cobblemon.config.minimumRidingScale) return@canRide false
|
||||
if (beamMode == 3) return@canRide false
|
||||
return@canRide behaviour.isActive(settings, state, this)
|
||||
}
|
||||
|
||||
override fun getDimensions(pose: Pose): EntityDimensions {
|
||||
val scale = effects.mockEffect?.scale ?: (form.baseScale * pokemon.effectiveScale)
|
||||
var result = this.exposedForm.hitbox.scale(scale)
|
||||
@@ -1636,8 +1606,9 @@ open class PokemonEntity(
|
||||
|| stack.`is`(CobblemonItemTags.WHITELISTED_ITEMS_TO_HOLD)
|
||||
|
||||
fun tryRidingPokemon(player: ServerPlayer): Boolean {
|
||||
if (!isRideableFor(player)) return false
|
||||
|
||||
if (pokemon.effectiveScale < Cobblemon.config.minimumRidingScale) {
|
||||
return false
|
||||
}
|
||||
val event = RidePokemonEvent.Pre(player, this)
|
||||
CobblemonEvents.RIDE_EVENT_PRE.post(event)
|
||||
if (!event.isCanceled) {
|
||||
@@ -2342,8 +2313,6 @@ open class PokemonEntity(
|
||||
ifRidingAvailable { _, _, state ->
|
||||
state.stamina.set(entityData.get(RIDE_STAMINA))
|
||||
}
|
||||
|
||||
playedZeroStaminaParticle = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2372,26 +2341,12 @@ open class PokemonEntity(
|
||||
|
||||
override fun tickRidden(driver: Player, movementInput: Vec3) {
|
||||
super.tickRidden(driver, movementInput)
|
||||
|
||||
ifRidingAvailable { behaviour, settings, state ->
|
||||
behaviour.tick(settings, state, this, driver, movementInput)
|
||||
if (entityData.get(RIDE_STAMINA) == -1F) {
|
||||
state.stamina.set(1F, forced = true)
|
||||
}
|
||||
|
||||
if (!level().isClientSide) {
|
||||
val stamina = state.stamina.get()
|
||||
|
||||
if (stamina <= 0f) {
|
||||
if (!playedZeroStaminaParticle) {
|
||||
playMoodParticle("mood_stress")
|
||||
playedZeroStaminaParticle = true
|
||||
}
|
||||
} else {
|
||||
playedZeroStaminaParticle = false
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.level().isClientSide) {
|
||||
val pose = behaviour.pose(settings, state, this)
|
||||
if (pose != this.entityData.get(POSE_TYPE)) {
|
||||
|
||||
-5
@@ -44,11 +44,6 @@ class DefendOwnerSensor : Sensor<PokemonEntity>(10) {
|
||||
return@findClosest false
|
||||
}.map { mob -> mob as LivingEntity }
|
||||
|
||||
val previousAttacker = entity.brain.getMemorySafely(CobblemonMemories.NEAREST_VISIBLE_ATTACKER)
|
||||
val isNewAttacker = nearestAttacker.isPresent && previousAttacker.isEmpty
|
||||
entity.brain.setMemory(CobblemonMemories.NEAREST_VISIBLE_ATTACKER, nearestAttacker)
|
||||
if (isNewAttacker) {
|
||||
entity.playMoodParticle("mood_anger_steam")
|
||||
}
|
||||
}
|
||||
}
|
||||
-6
@@ -9,7 +9,6 @@
|
||||
package com.cobblemon.mod.common.entity.pokemon.ai.tasks
|
||||
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.getMemorySafely
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.Mob
|
||||
import net.minecraft.world.entity.ai.behavior.OneShot
|
||||
@@ -61,12 +60,7 @@ object AttackHostileMobsTask {
|
||||
}
|
||||
|
||||
if (hostile != null) {
|
||||
val isNewTarget = currentTarget == null
|
||||
entity.brain.setMemory(MemoryModuleType.ATTACK_TARGET, hostile)
|
||||
if (isNewTarget) {
|
||||
(entity as? PokemonEntity)?.playMoodParticle("mood_anger_steam")
|
||||
}
|
||||
|
||||
true
|
||||
} else {
|
||||
false
|
||||
|
||||
+1
-1
@@ -91,7 +91,7 @@ class EatHeldItemTask(entity: PokemonEntity) : Behavior<PokemonEntity>(
|
||||
}
|
||||
this.timelastEaten = time
|
||||
if (itemConfig != null && itemConfig.fullnessValue > 0) {
|
||||
entity.pokemon.feedPokemon(itemConfig.fullnessValue, false, false)
|
||||
entity.pokemon.feedPokemon(itemConfig.fullnessValue, false)
|
||||
}
|
||||
// Check if the result item is something that should be dropped
|
||||
resultItemStack = entity.pokemon.heldItem()
|
||||
|
||||
@@ -78,10 +78,21 @@ object StatHandler : EventHandler {
|
||||
|
||||
fun onWinBattle(event : BattleVictoryEvent) {
|
||||
if (!event.wasWildCapture) {
|
||||
if(event.battle.isPvP) {
|
||||
event.winners
|
||||
.flatMap { it.getPlayerUUIDs().mapNotNull(UUID::getPlayer) }
|
||||
.forEach { player -> player.awardStat(getStat(Cobblemon.statistics.PVP_BATTLES_WON)) }
|
||||
event.losers
|
||||
.flatMap { it.getPlayerUUIDs().mapNotNull(UUID::getPlayer) }
|
||||
.forEach { player -> player.awardStat(getStat(Cobblemon.statistics.PVP_BATTLES_LOST)) }
|
||||
}
|
||||
if (event.battle.isPvW) {
|
||||
event.winners
|
||||
.flatMap { it.getPlayerUUIDs().mapNotNull(UUID::getPlayer) }
|
||||
.forEach { player -> player.awardStat(getStat(Cobblemon.statistics.BATTLES_WON)) }
|
||||
event.losers
|
||||
.flatMap { it.getPlayerUUIDs().mapNotNull(UUID::getPlayer) }
|
||||
.forEach { player -> player.awardStat(getStat(Cobblemon.statistics.BATTLES_LOST)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,7 @@ import com.cobblemon.mod.common.api.apricorn.Apricorn
|
||||
import com.cobblemon.mod.common.api.item.PokemonSelectingItem
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.client.pot.CookingQuality
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
@@ -94,9 +92,7 @@ class AprijuiceItem(val type: Apricorn): CobblemonItem(Properties().stacksTo(16)
|
||||
return InteractionResultHolder.fail(stack)
|
||||
}
|
||||
|
||||
if (!pokemon.feedPokemon(1)) {
|
||||
return InteractionResultHolder.fail(stack)
|
||||
}
|
||||
pokemon.feedPokemon(1)
|
||||
|
||||
val boosts = getBoosts(stack)
|
||||
pokemon.addRideBoosts(boosts.mapValues { it.value.toFloat() })
|
||||
|
||||
@@ -96,9 +96,8 @@ class PokePuffItem : Item(Properties().stacksTo(64)), PokemonSelectingItem {
|
||||
return InteractionResultHolder.fail(stack)
|
||||
}
|
||||
|
||||
if (!pokemon.feedPokemon(4)) {
|
||||
return InteractionResultHolder.fail(stack)
|
||||
}
|
||||
// Feed the Pokémon 4 fullness points
|
||||
pokemon.feedPokemon(4)
|
||||
|
||||
val friendshipChange = PokePuffUtils.calculateFriendshipChange(stack, pokemon.nature)
|
||||
|
||||
|
||||
+6
-8
@@ -54,16 +54,14 @@ class FriendshipRaisingBerryItem(block: BerryBlock, val stat: Stat) : BerryItem(
|
||||
val evLowerAmount = max(genericRuntime.resolveInt(CobblemonMechanics.berries.evLowerAmount), 0)
|
||||
val decreasedEVs = pokemon.evs.add(stat, -evLowerAmount, ItemEvSource(player, stack, pokemon)) != 0
|
||||
|
||||
if (!increasedFriendship && !decreasedEVs) {
|
||||
return InteractionResultHolder.pass(stack)
|
||||
}
|
||||
return if (increasedFriendship || decreasedEVs) {
|
||||
pokemon.feedPokemon(1)
|
||||
|
||||
if (!pokemon.feedPokemon(1)) {
|
||||
return InteractionResultHolder.fail(stack)
|
||||
stack.consume(1, player)
|
||||
InteractionResultHolder.success(stack)
|
||||
} else {
|
||||
InteractionResultHolder.pass(stack)
|
||||
}
|
||||
|
||||
stack.consume(1, player)
|
||||
return InteractionResultHolder.success(stack)
|
||||
}
|
||||
|
||||
override fun use(world: Level, user: Player, hand: InteractionHand): InteractionResultHolder<ItemStack> {
|
||||
|
||||
@@ -54,10 +54,7 @@ class HealingBerryItem(block: BerryBlock, val amount: () -> ExpressionLike): Ber
|
||||
return InteractionResultHolder.fail(stack)
|
||||
}
|
||||
|
||||
if (!pokemon.feedPokemon(1)) {
|
||||
return InteractionResultHolder.fail(stack)
|
||||
}
|
||||
|
||||
pokemon.feedPokemon(1)
|
||||
pokemon.currentHealth = Integer.min(pokemon.currentHealth + genericRuntime.resolveInt(amount(), pokemon), pokemon.maxHealth)
|
||||
stack.consume(1, player)
|
||||
return InteractionResultHolder.success(stack)
|
||||
@@ -65,7 +62,7 @@ class HealingBerryItem(block: BerryBlock, val amount: () -> ExpressionLike): Ber
|
||||
|
||||
override fun applyToBattlePokemon(player: ServerPlayer, stack: ItemStack, battlePokemon: BattlePokemon) {
|
||||
super.applyToBattlePokemon(player, stack, battlePokemon)
|
||||
battlePokemon.originalPokemon.feedPokemon(1, playMoodParticle = false)
|
||||
battlePokemon.originalPokemon.feedPokemon(1)
|
||||
}
|
||||
|
||||
override fun use(world: Level, user: Player, hand: InteractionHand): InteractionResultHolder<ItemStack> {
|
||||
|
||||
@@ -48,26 +48,21 @@ class PPRestoringBerryItem(block: BerryBlock, val amount: () -> ExpressionLike):
|
||||
&& super.canUseOnPokemon(stack, pokemon)
|
||||
|
||||
override fun applyToPokemon(player: ServerPlayer, stack: ItemStack, pokemon: Pokemon, move: Move) {
|
||||
if (!canUseOnPokemon(stack, pokemon) && canUseOnMove(stack, move)) {
|
||||
return
|
||||
}
|
||||
if (canUseOnPokemon(stack, pokemon) && canUseOnMove(stack, move)) {
|
||||
pokemon.feedPokemon(1)
|
||||
val moveToRecover = pokemon.moveSet.find { it.template == move.template }
|
||||
if (moveToRecover != null && moveToRecover.currentPp < moveToRecover.maxPp) {
|
||||
moveToRecover.currentPp =
|
||||
min(moveToRecover.maxPp, moveToRecover.currentPp + genericRuntime.resolveInt(amount(), pokemon))
|
||||
|
||||
if (!pokemon.feedPokemon(1)) {
|
||||
return
|
||||
}
|
||||
|
||||
val moveToRecover = pokemon.moveSet.find { it.template == move.template }
|
||||
if (moveToRecover != null && moveToRecover.currentPp < moveToRecover.maxPp) {
|
||||
moveToRecover.currentPp =
|
||||
min(moveToRecover.maxPp, moveToRecover.currentPp + genericRuntime.resolveInt(amount(), pokemon))
|
||||
|
||||
stack.consume(1, player)
|
||||
stack.consume(1, player)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun applyToBattlePokemon(player: ServerPlayer, stack: ItemStack, battlePokemon: BattlePokemon, move: Move) {
|
||||
super.applyToBattlePokemon(player, stack, battlePokemon, move)
|
||||
battlePokemon.originalPokemon.feedPokemon(1, playMoodParticle = false)
|
||||
battlePokemon.originalPokemon.feedPokemon(1)
|
||||
}
|
||||
|
||||
override fun use(world: Level, user: Player, hand: InteractionHand): InteractionResultHolder<ItemStack> {
|
||||
|
||||
+2
-4
@@ -59,9 +59,7 @@ class PortionHealingBerryItem(block: BerryBlock, val canCauseConfusion: Boolean,
|
||||
}
|
||||
|
||||
// count these berries as multiple feedings due to the amount they heal
|
||||
if (!pokemon.feedPokemon(5)) {
|
||||
return InteractionResultHolder.fail(stack)
|
||||
}
|
||||
pokemon.feedPokemon(5)
|
||||
|
||||
var amount = Integer.min(pokemon.currentHealth + (genericRuntime.resolveFloat(portion(), pokemon) * pokemon.maxHealth).toInt(), pokemon.maxHealth)
|
||||
CobblemonEvents.POKEMON_HEALED.postThen(PokemonHealedEvent(pokemon, amount, this), { cancelledEvent -> return InteractionResultHolder.fail(stack)}) { event ->
|
||||
@@ -75,7 +73,7 @@ class PortionHealingBerryItem(block: BerryBlock, val canCauseConfusion: Boolean,
|
||||
|
||||
override fun applyToBattlePokemon(player: ServerPlayer, stack: ItemStack, battlePokemon: BattlePokemon) {
|
||||
super.applyToBattlePokemon(player, stack, battlePokemon)
|
||||
battlePokemon.originalPokemon.feedPokemon(5, playMoodParticle = false)
|
||||
battlePokemon.originalPokemon.feedPokemon(5)
|
||||
}
|
||||
|
||||
override fun use(world: Level, user: Player, hand: InteractionHand): InteractionResultHolder<ItemStack> {
|
||||
|
||||
+8
-12
@@ -58,23 +58,19 @@ class StatusCuringBerryItem(block: BerryBlock, vararg val status: Status): Berry
|
||||
stack: ItemStack,
|
||||
pokemon: Pokemon
|
||||
): InteractionResultHolder<ItemStack>? {
|
||||
if (!canUseOnPokemon(stack, pokemon)) {
|
||||
return InteractionResultHolder.fail(stack)
|
||||
return if (canUseOnPokemon(stack, pokemon)) {
|
||||
pokemon.feedPokemon(1)
|
||||
pokemon.status = null
|
||||
stack.consume(1, player)
|
||||
InteractionResultHolder.success(stack)
|
||||
} else {
|
||||
InteractionResultHolder.fail(stack)
|
||||
}
|
||||
|
||||
if (!pokemon.feedPokemon(1)) {
|
||||
return InteractionResultHolder.fail(stack)
|
||||
}
|
||||
|
||||
pokemon.status = null
|
||||
stack.consume(1, player)
|
||||
|
||||
return InteractionResultHolder.success(stack)
|
||||
}
|
||||
|
||||
override fun applyToBattlePokemon(player: ServerPlayer, stack: ItemStack, battlePokemon: BattlePokemon) {
|
||||
super.applyToBattlePokemon(player, stack, battlePokemon)
|
||||
battlePokemon.originalPokemon.feedPokemon(1, playMoodParticle = false)
|
||||
battlePokemon.originalPokemon.feedPokemon(1)
|
||||
}
|
||||
|
||||
override fun use(world: Level, user: Player, hand: InteractionHand): InteractionResultHolder<ItemStack> {
|
||||
|
||||
@@ -53,10 +53,7 @@ class BerryJuiceItem : CobblemonItem(Properties()), PokemonSelectingItem, Healin
|
||||
if (!canUseOnPokemon(stack, pokemon)) {
|
||||
return InteractionResultHolder.fail(stack)
|
||||
}
|
||||
|
||||
if (!pokemon.feedPokemon(1)) {
|
||||
return InteractionResultHolder.fail(stack)
|
||||
}
|
||||
pokemon.feedPokemon(1)
|
||||
|
||||
var amount = Integer.min(pokemon.currentHealth + 20, pokemon.maxHealth)
|
||||
CobblemonEvents.POKEMON_HEALED.postThen(PokemonHealedEvent(pokemon, amount, this), { cancelledEvent -> return InteractionResultHolder.fail(stack)}) { event ->
|
||||
@@ -77,9 +74,7 @@ class BerryJuiceItem : CobblemonItem(Properties()), PokemonSelectingItem, Healin
|
||||
|
||||
override fun applyToBattlePokemon(player: ServerPlayer, stack: ItemStack, battlePokemon: BattlePokemon) {
|
||||
super.applyToBattlePokemon(player, stack, battlePokemon)
|
||||
|
||||
battlePokemon.originalPokemon.feedPokemon(1, playMoodParticle = false)
|
||||
|
||||
battlePokemon.originalPokemon.feedPokemon(1)
|
||||
if (!player.hasInfiniteMaterials()) {
|
||||
val woodenBowlItemStack = ItemStack(Items.BOWL)
|
||||
if (!player.inventory.add(woodenBowlItemStack)) {
|
||||
|
||||
+1
-3
@@ -33,9 +33,7 @@ class FreshStartMochiItem : CobblemonItem(Properties()), PokemonSelectingItem {
|
||||
return InteractionResultHolder.fail(stack)
|
||||
}
|
||||
|
||||
if (!pokemon.feedPokemon(1)) {
|
||||
return InteractionResultHolder.fail(stack)
|
||||
}
|
||||
pokemon.feedPokemon(1)
|
||||
|
||||
pokemon.evs.forEach {
|
||||
pokemon.setEV(it.key, 0)
|
||||
|
||||
@@ -27,9 +27,7 @@ class MochiItem(override val stat: Stat): CobblemonItem(Properties()), EVIncreas
|
||||
return InteractionResultHolder.fail(stack)
|
||||
}
|
||||
|
||||
if (!pokemon.feedPokemon(1)) {
|
||||
return InteractionResultHolder.fail(stack)
|
||||
}
|
||||
pokemon.feedPokemon(1)
|
||||
|
||||
return super.applyToPokemon(player, stack, pokemon)
|
||||
}
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.net.messages.client.data
|
||||
|
||||
import com.cobblemon.mod.common.api.badges.Badge
|
||||
import com.cobblemon.mod.common.api.badges.Badges
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.readIdentifier
|
||||
import com.cobblemon.mod.common.util.readString
|
||||
import com.cobblemon.mod.common.util.writeIdentifier
|
||||
import com.cobblemon.mod.common.util.writeString
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
|
||||
class BadgeRegistrySyncPacket(badges: List<Badge>) : DataRegistrySyncPacket<Badge, BadgeRegistrySyncPacket>(badges) {
|
||||
companion object {
|
||||
val ID = cobblemonResource("badges")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) = BadgeRegistrySyncPacket(emptyList()).apply { decodeBuffer(buffer) }
|
||||
}
|
||||
|
||||
|
||||
override val id = ID
|
||||
override fun encodeEntry(buffer: RegistryFriendlyByteBuf, entry: Badge) {
|
||||
buffer.writeIdentifier(entry.identifier)
|
||||
buffer.writeString(entry.name)
|
||||
buffer.writeResourceLocation(entry.texture)
|
||||
buffer.writeInt(entry.order)
|
||||
}
|
||||
|
||||
override fun decodeEntry(buffer: RegistryFriendlyByteBuf): Badge {
|
||||
return Badge(
|
||||
order = buffer.readInt(),
|
||||
texture = buffer.readResourceLocation(),
|
||||
name = buffer.readString(),
|
||||
identifier = buffer.readIdentifier()
|
||||
)
|
||||
}
|
||||
|
||||
override fun synchronizeDecoded(entries: Collection<Badge>) {
|
||||
Badges.reload(entries.associateBy { it.identifier })
|
||||
}
|
||||
}
|
||||
-24
@@ -8,12 +8,9 @@
|
||||
|
||||
package com.cobblemon.mod.common.net.serverhandling.battle
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.battles.BattleRegistry
|
||||
import com.cobblemon.mod.common.battles.HealItemActionResponse
|
||||
import com.cobblemon.mod.common.battles.MoveActionResponse
|
||||
import com.cobblemon.mod.common.exception.IllegalActionChoiceException
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleMakeChoicePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleQueueRequestPacket
|
||||
@@ -28,27 +25,6 @@ object BattleSelectActionsHandler : ServerNetworkPacketHandler<BattleSelectActio
|
||||
if (!actor.mustChoose) {
|
||||
return
|
||||
}
|
||||
|
||||
// Battle command injection attempt detection
|
||||
packet.showdownActionResponses.asSequence()
|
||||
.flatMap {
|
||||
when (it) {
|
||||
is MoveActionResponse -> sequenceOf(it.moveName, it.targetPnx, it.gimmickID)
|
||||
is HealItemActionResponse -> sequenceOf(it.item)
|
||||
else -> emptySequence()
|
||||
}
|
||||
}
|
||||
.filterNotNull()
|
||||
.firstOrNull { field -> field.any(Char::isISOControl) }
|
||||
?.let {
|
||||
// Escapes control chars as \uXXXX to prevent forging logs.
|
||||
val printable = it.replace(Regex("\\p{Cc}")) { "\\u%04x".format(it.value[0].code) }
|
||||
Cobblemon.LOGGER.warn("Blocked battle command injection from ${player.name.string}: $printable")
|
||||
actor.sendUpdate(BattleQueueRequestPacket(actor.request!!))
|
||||
actor.sendUpdate(BattleMakeChoicePacket())
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
actor.setActionResponses(packet.showdownActionResponses)
|
||||
} catch (e: IllegalActionChoiceException) {
|
||||
|
||||
@@ -991,10 +991,6 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
this.recall()
|
||||
}
|
||||
|
||||
fun playMoodParticle(particleName: String) {
|
||||
entity?.playMoodParticle(particleName)
|
||||
}
|
||||
|
||||
fun heal() {
|
||||
CobblemonEvents.POKEMON_HEALED.postThen(PokemonHealedEvent(this)) { event ->
|
||||
this.currentHealth = maxHealth
|
||||
@@ -1066,13 +1062,23 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
else -> 0 // For weights less than 0.1
|
||||
}
|
||||
|
||||
fun feedPokemon(feedCount: Int, playSound: Boolean = true, playMoodParticle: Boolean = true): Boolean {
|
||||
playFullnessEffects(playSound, playMoodParticle)
|
||||
fun feedPokemon(feedCount: Int, playSound: Boolean = true) {
|
||||
// play sounds from the entity first (itemstack is consumed outside of this function)
|
||||
if (this.entity != null && playSound) {
|
||||
val fullnessPercent = ((this.currentFullness).toFloat() / (this.getMaxFullness()).toFloat()) * (.5f)
|
||||
|
||||
if (this.currentFullness >= this.getMaxFullness()) {
|
||||
this.entity?.playSound(CobblemonSounds.BERRY_EAT_FULL, 1F, 1F)
|
||||
}
|
||||
else {
|
||||
this.entity?.playSound(CobblemonSounds.BERRY_EAT, 1F, 1F + fullnessPercent)
|
||||
}
|
||||
}
|
||||
|
||||
// if it is already full we don't need to do anything
|
||||
// TODO this can happen when feeding in battle since we are temporarily ignoring fullness checks for pp/hp/status berries
|
||||
if (isFull()) {
|
||||
return false
|
||||
return
|
||||
}
|
||||
|
||||
this.currentFullness = (this.currentFullness + feedCount).coerceIn(0, this.getMaxFullness())
|
||||
@@ -1081,31 +1087,6 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
if (this.currentFullness == 1) {
|
||||
this.resetMetabolismCycle()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun playFullnessEffects(playSound: Boolean = true, playMoodParticle: Boolean = true) {
|
||||
if (!playSound && !playMoodParticle) return
|
||||
|
||||
val pokemonEntity = entity ?: return
|
||||
val fullnessPercent = ((this.currentFullness).toFloat() / (this.getMaxFullness()).toFloat()) * (.5f)
|
||||
|
||||
if (!isFull()) {
|
||||
if (playSound) {
|
||||
pokemonEntity.playSound(CobblemonSounds.BERRY_EAT, 1F, 1F + fullnessPercent)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (playSound) {
|
||||
pokemonEntity.playSound(CobblemonSounds.BERRY_EAT_FULL, 1F, 1F)
|
||||
|
||||
if (playMoodParticle) {
|
||||
pokemonEntity.playMoodParticle("mood_annoyed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// decrease a pokemon's Fullness value by a certain amount
|
||||
|
||||
+3
-4
@@ -135,18 +135,17 @@ internal object PropertiesCompletionProvider : DataRegistry {
|
||||
private fun addDefaults() {
|
||||
this.inject(setOf("level", "lvl", "l"), setOf("1", "${Cobblemon.config.maxPokemonLevel}") )
|
||||
this.inject(setOf("shiny", "s"), setOf("yes", "no"))
|
||||
this.inject(setOf("alpha", "is_alpha"), setOf("yes", "no"))
|
||||
this.inject(setOf("gender"), Gender.entries.map { it.name.lowercase() })
|
||||
this.inject(setOf("friendship"), setOf("0", Cobblemon.config.maxPokemonFriendship.toString()))
|
||||
this.inject(setOf("fullness"), setOf("0", "255"))
|
||||
this.inject(setOf("pokeball"), PokeBalls.all().map { it.name.simplify() })
|
||||
this.inject(setOf("nature"), Natures.all().map { it.name.simplify() })
|
||||
this.inject(setOf("ability"), Abilities.all().map { if (it.name.asIdentifierDefaultingNamespace().namespace == Cobblemon.MODID) it.name.asIdentifierDefaultingNamespace().path else it.name })
|
||||
this.inject(setOf("dmax_level", "dmax"), setOf("0", Cobblemon.config.maxDynamaxLevel.toString()))
|
||||
this.inject(setOf("gmax_factor", "gmax"), setOf("yes", "no"))
|
||||
this.inject(setOf("dmax"), setOf("0", Cobblemon.config.maxDynamaxLevel.toString()))
|
||||
this.inject(setOf("gmax"), setOf("yes", "no"))
|
||||
this.inject(setOf("type", "elemental_type"), ElementalTypes.all().map { it.name })
|
||||
this.inject(setOf("tera_type", "tera"), TeraTypes.map { it.id.simplify() })
|
||||
this.inject(setOf("tradeable", "tradable"), setOf("yes", "no"))
|
||||
this.inject(setOf("tradeable"), setOf("yes", "no"))
|
||||
this.inject(setOf("originaltrainer", "ot"), setOf(""))
|
||||
this.inject(setOf("originaltrainertype", "ottype"), setOf("None", "Player", "NPC"))
|
||||
this.inject(setOf("nickname", "nick"), setOf(""))
|
||||
|
||||
+1
-2
@@ -26,6 +26,5 @@ object CobblemonGameRules {
|
||||
val SHINY_STARTERS: GameRules.Key<GameRules.BooleanValue> = Cobblemon.implementation.registerGameRule("doShinyStarters", GameRules.Category.MISC, BooleanRuleInvoker.`cobblemon$create`(false))
|
||||
@JvmField
|
||||
val HEALERS_HEAL_PC: GameRules.Key<GameRules.BooleanValue> = Cobblemon.implementation.registerGameRule("healersHealPC", GameRules.Category.MISC, BooleanRuleInvoker.`cobblemon$create`(false))
|
||||
@JvmField
|
||||
val DO_POKEMON_PREDATION: GameRules.Key<GameRules.BooleanValue> = Cobblemon.implementation.registerGameRule("doPokemonPredation", GameRules.Category.MOBS, BooleanRuleInvoker.`cobblemon$create`(true))
|
||||
|
||||
}
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
{
|
||||
"format_version": "1.10.0",
|
||||
"particle_effect": {
|
||||
"description": {
|
||||
"identifier": "cobblemon:mood_anger_steam",
|
||||
"basic_render_parameters": {
|
||||
"material": "particles_alpha",
|
||||
"texture": "textures/particles/mood/steam_center_double"
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"minecraft:emitter_rate_instant": {
|
||||
"num_particles": 1
|
||||
},
|
||||
"minecraft:emitter_lifetime_once": {
|
||||
"active_time": 1
|
||||
},
|
||||
"minecraft:emitter_shape_point": {
|
||||
"offset": [0, "math.clamp((v.entity_radius*1.2),0.48,0.96)*0.75", 0]
|
||||
},
|
||||
"minecraft:particle_lifetime_expression": {
|
||||
"max_lifetime": 1
|
||||
},
|
||||
"minecraft:particle_initial_speed": 0,
|
||||
"minecraft:particle_motion_dynamic": {},
|
||||
"minecraft:particle_appearance_billboard": {
|
||||
"size": ["math.clamp((v.entity_radius*1.5),0.9,2.4)", "math.clamp((v.entity_radius*0.5),0.3,0.8)"],
|
||||
"facing_camera_mode": "rotate_xyz",
|
||||
"uv": {
|
||||
"texture_width": 48,
|
||||
"texture_height": 176,
|
||||
"flipbook": {
|
||||
"base_UV": [0, 0],
|
||||
"size_UV": [48, 16],
|
||||
"step_UV": [0, 16],
|
||||
"max_frame": 11,
|
||||
"stretch_to_lifetime": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-64
@@ -1,64 +0,0 @@
|
||||
{
|
||||
"format_version": "1.10.0",
|
||||
"particle_effect": {
|
||||
"description": {
|
||||
"identifier": "cobblemon:mood_anger_veins",
|
||||
"basic_render_parameters": {
|
||||
"material": "particles_alpha",
|
||||
"texture": "textures/particles/mood/vein_red"
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"minecraft:emitter_initialization": {
|
||||
"creation_expression": "v.particle_size = math.clamp((v.entity_radius*0.75),0.15,0.4);"
|
||||
},
|
||||
"minecraft:emitter_rate_instant": {
|
||||
"num_particles": 1
|
||||
},
|
||||
"minecraft:emitter_lifetime_once": {
|
||||
"active_time": 1
|
||||
},
|
||||
"minecraft:emitter_shape_point": {
|
||||
"direction": ["math.random(-1,1)", 1.5, "math.random(-1,1)"]
|
||||
},
|
||||
"minecraft:particle_lifetime_expression": {
|
||||
"max_lifetime": 1.25
|
||||
},
|
||||
"minecraft:particle_initial_spin": {
|
||||
"rotation": "math.random_integer(-1,2)*90"
|
||||
},
|
||||
"minecraft:particle_initial_speed": "v.particle_size*13",
|
||||
"minecraft:particle_motion_dynamic": {
|
||||
"linear_acceleration": [0, 0.75, 0],
|
||||
"linear_drag_coefficient": "v.particle_size*15"
|
||||
},
|
||||
"minecraft:particle_appearance_billboard": {
|
||||
"size": ["math.clamp((v.entity_radius*0.75),0.15,0.3)", "math.clamp((v.entity_radius*0.75),0.15,0.3)"],
|
||||
"facing_camera_mode": "rotate_xyz",
|
||||
"uv": {
|
||||
"texture_width": 22,
|
||||
"texture_height": 11,
|
||||
"flipbook": {
|
||||
"base_UV": [0, 0],
|
||||
"size_UV": [11, 11],
|
||||
"step_UV": [11, 0],
|
||||
"frames_per_second": 6,
|
||||
"max_frame": 2,
|
||||
"loop": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"minecraft:particle_motion_collision": {},
|
||||
"minecraft:particle_appearance_lighting": {},
|
||||
"minecraft:particle_appearance_tinting": {
|
||||
"color": {
|
||||
"interpolant": "v.particle_age/v.particle_lifetime",
|
||||
"gradient": {
|
||||
"0.86": "#ffffffff",
|
||||
"1.0": "#FF000000"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
{
|
||||
"format_version": "1.10.0",
|
||||
"particle_effect": {
|
||||
"description": {
|
||||
"identifier": "cobblemon:mood_annoyed",
|
||||
"basic_render_parameters": {
|
||||
"material": "particles_alpha",
|
||||
"texture": "textures/particles/mood/scribble_purple"
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"minecraft:emitter_initialization": {
|
||||
"creation_expression": "v.particle_size = math.clamp((v.entity_radius*0.75),0.2,0.5);"
|
||||
},
|
||||
"minecraft:emitter_rate_instant": {
|
||||
"num_particles": 1
|
||||
},
|
||||
"minecraft:emitter_lifetime_once": {
|
||||
"active_time": 2
|
||||
},
|
||||
"minecraft:emitter_shape_point": {
|
||||
"direction": [0, 1, 0]
|
||||
},
|
||||
"minecraft:particle_lifetime_expression": {
|
||||
"max_lifetime": 1
|
||||
},
|
||||
"minecraft:particle_initial_speed": "v.particle_size*10",
|
||||
"minecraft:particle_motion_dynamic": {
|
||||
"linear_drag_coefficient": 3
|
||||
},
|
||||
"minecraft:particle_appearance_billboard": {
|
||||
"size": ["math.clamp((v.entity_radius*0.75),0.2,0.5)", "math.clamp((v.entity_radius*0.75),0.2,0.5)"],
|
||||
"facing_camera_mode": "rotate_xyz",
|
||||
"uv": {
|
||||
"texture_width": 168,
|
||||
"texture_height": 14,
|
||||
"flipbook": {
|
||||
"base_UV": [0, 0],
|
||||
"size_UV": [14, 14],
|
||||
"step_UV": [14, 0],
|
||||
"frames_per_second": 10,
|
||||
"max_frame": 12
|
||||
}
|
||||
}
|
||||
},
|
||||
"minecraft:particle_appearance_lighting": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
-47
@@ -1,47 +0,0 @@
|
||||
{
|
||||
"format_version": "1.10.0",
|
||||
"particle_effect": {
|
||||
"description": {
|
||||
"identifier": "cobblemon:mood_stress",
|
||||
"basic_render_parameters": {
|
||||
"material": "particles_alpha",
|
||||
"texture": "textures/particles/mood/sweat_blue"
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"minecraft:emitter_initialization": {
|
||||
"creation_expression": "v.particle_height = math.clamp((v.entity_radius*1.2),0.48,0.96);"
|
||||
},
|
||||
"minecraft:emitter_rate_instant": {
|
||||
"num_particles": 1
|
||||
},
|
||||
"minecraft:emitter_lifetime_looping": {
|
||||
"active_time": 1
|
||||
},
|
||||
"minecraft:emitter_shape_point": {
|
||||
"offset": [0, "math.clamp((v.entity_radius*1.2),0.48,0.96)*0.75", 0]
|
||||
},
|
||||
"minecraft:particle_lifetime_expression": {
|
||||
"max_lifetime": 0.45
|
||||
},
|
||||
"minecraft:particle_initial_speed": 0,
|
||||
"minecraft:particle_motion_dynamic": {},
|
||||
"minecraft:particle_appearance_billboard": {
|
||||
"size": ["math.clamp((v.entity_radius*1.2),0.48,0.96)", "math.clamp((v.entity_radius*0.65),0.26,0.52)"],
|
||||
"facing_camera_mode": "rotate_xyz",
|
||||
"uv": {
|
||||
"texture_width": 216,
|
||||
"texture_height": 13,
|
||||
"flipbook": {
|
||||
"base_UV": [0, 0],
|
||||
"size_UV": [24, 13],
|
||||
"step_UV": [24, 0],
|
||||
"max_frame": 9,
|
||||
"stretch_to_lifetime": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"minecraft:particle_appearance_lighting": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
-90
@@ -1,90 +0,0 @@
|
||||
{
|
||||
"format_version": "1.10.0",
|
||||
"particle_effect": {
|
||||
"description": {
|
||||
"identifier": "cobblemon:watershuriken_actor",
|
||||
"basic_render_parameters": {
|
||||
"material": "particles_blend",
|
||||
"texture": "textures/particles/moves/watershuriken"
|
||||
}
|
||||
},
|
||||
"curves": {
|
||||
"variable.rsize": {
|
||||
"type": "linear",
|
||||
"input": "v.particle_age",
|
||||
"horizontal_range": "v.particle_lifetime",
|
||||
"nodes": [0, 1, 1, 1, 1, 1, 1, 1]
|
||||
}
|
||||
},
|
||||
"events": {
|
||||
"trail": {
|
||||
"particle_effect": {
|
||||
"effect": "cobblemon:watershuriken_actortrail",
|
||||
"type": "particle"
|
||||
}
|
||||
},
|
||||
"hit": {
|
||||
"particle_effect": {
|
||||
"effect": "cobblemon:watershuriken_target",
|
||||
"type": "particle"
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"minecraft:emitter_initialization": {
|
||||
"creation_expression": "v.target_deltaz=5;"
|
||||
},
|
||||
"minecraft:emitter_rate_instant": {
|
||||
"num_particles": 1
|
||||
},
|
||||
"minecraft:emitter_lifetime_once": {
|
||||
"active_time": 0.25
|
||||
},
|
||||
"minecraft:emitter_shape_disc": {
|
||||
"offset": [0, 0.02, 0.1],
|
||||
"radius": 0.5,
|
||||
"direction": "outwards"
|
||||
},
|
||||
"minecraft:particle_lifetime_expression": {
|
||||
"max_lifetime": 0.35
|
||||
},
|
||||
"minecraft:particle_lifetime_events": {
|
||||
"timeline": {
|
||||
"0.00": "trail",
|
||||
"0.06": "trail",
|
||||
"0.12": "trail",
|
||||
"0.18": "trail",
|
||||
"0.24": "trail",
|
||||
"0.30": "trail",
|
||||
"0.34": "hit"
|
||||
}
|
||||
},
|
||||
"minecraft:particle_initial_spin": {
|
||||
"rotation": "math.random_integer(0,3)*90"
|
||||
},
|
||||
"minecraft:particle_motion_parametric": {
|
||||
"relative_position": ["-v.target_deltax*(v.particle_age / v.particle_lifetime)", "(v.target_deltay*(v.particle_age / v.particle_lifetime))", "-v.target_deltaz*(v.particle_age / v.particle_lifetime)"]
|
||||
},
|
||||
"minecraft:particle_appearance_billboard": {
|
||||
"size": ["0.4*v.rsize", "0.4*v.rsize"],
|
||||
"facing_camera_mode": "lookat_direction",
|
||||
"direction": {
|
||||
"mode": "custom",
|
||||
"custom_direction": [0, 0, -1]
|
||||
},
|
||||
"uv": {
|
||||
"texture_width": 60,
|
||||
"texture_height": 15,
|
||||
"flipbook": {
|
||||
"base_UV": [0, 0],
|
||||
"size_UV": [15, 15],
|
||||
"step_UV": [15, 0],
|
||||
"frames_per_second": 24,
|
||||
"max_frame": 4,
|
||||
"loop": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-91
@@ -1,91 +0,0 @@
|
||||
{
|
||||
"format_version": "1.10.0",
|
||||
"particle_effect": {
|
||||
"description": {
|
||||
"identifier": "cobblemon:watershuriken_actoralt",
|
||||
"basic_render_parameters": {
|
||||
"material": "particles_blend",
|
||||
"texture": "textures/particles/moves/watershuriken"
|
||||
}
|
||||
},
|
||||
"curves": {
|
||||
"variable.rsize": {
|
||||
"type": "linear",
|
||||
"input": "v.particle_age",
|
||||
"horizontal_range": "v.particle_lifetime",
|
||||
"nodes": [0, 1, 1, 1, 1, 1, 1, 1]
|
||||
}
|
||||
},
|
||||
"events": {
|
||||
"trail": {
|
||||
"particle_effect": {
|
||||
"effect": "cobblemon:watershuriken_actortrail",
|
||||
"type": "particle"
|
||||
}
|
||||
},
|
||||
"hit": {
|
||||
"particle_effect": {
|
||||
"effect": "cobblemon:watershuriken_target",
|
||||
"type": "particle"
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"minecraft:emitter_initialization": {
|
||||
"creation_expression": "v.target_deltaz=5;"
|
||||
},
|
||||
"minecraft:emitter_rate_steady": {
|
||||
"spawn_rate": 7,
|
||||
"max_particles": 3
|
||||
},
|
||||
"minecraft:emitter_lifetime_once": {
|
||||
"active_time": 0.4
|
||||
},
|
||||
"minecraft:emitter_shape_disc": {
|
||||
"offset": [0, 0.02, 0.1],
|
||||
"radius": 0.5,
|
||||
"direction": "outwards"
|
||||
},
|
||||
"minecraft:particle_lifetime_expression": {
|
||||
"max_lifetime": 0.35
|
||||
},
|
||||
"minecraft:particle_lifetime_events": {
|
||||
"timeline": {
|
||||
"0.00": "trail",
|
||||
"0.06": "trail",
|
||||
"0.12": "trail",
|
||||
"0.18": "trail",
|
||||
"0.24": "trail",
|
||||
"0.30": "trail",
|
||||
"0.34": "hit"
|
||||
}
|
||||
},
|
||||
"minecraft:particle_initial_spin": {
|
||||
"rotation": "math.random_integer(0,3)*90"
|
||||
},
|
||||
"minecraft:particle_motion_parametric": {
|
||||
"relative_position": ["-(v.target_deltax+((v.particle_random_1-0.5)*1.33))*(v.particle_age / v.particle_lifetime)", "(v.target_deltay+((v.particle_random_2-0.5)*1.33))*(v.particle_age / v.particle_lifetime)", "-v.target_deltaz*(v.particle_age / v.particle_lifetime)"]
|
||||
},
|
||||
"minecraft:particle_appearance_billboard": {
|
||||
"size": ["0.4*v.rsize", "0.4*v.rsize"],
|
||||
"facing_camera_mode": "lookat_direction",
|
||||
"direction": {
|
||||
"mode": "custom",
|
||||
"custom_direction": [0, 0, -1]
|
||||
},
|
||||
"uv": {
|
||||
"texture_width": 60,
|
||||
"texture_height": 15,
|
||||
"flipbook": {
|
||||
"base_UV": [0, 0],
|
||||
"size_UV": [15, 15],
|
||||
"step_UV": [15, 0],
|
||||
"frames_per_second": 24,
|
||||
"max_frame": 4,
|
||||
"loop": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-86
@@ -1,86 +0,0 @@
|
||||
{
|
||||
"format_version": "1.10.0",
|
||||
"particle_effect": {
|
||||
"description": {
|
||||
"identifier": "cobblemon:watershuriken_actorhor",
|
||||
"basic_render_parameters": {
|
||||
"material": "particles_blend",
|
||||
"texture": "textures/particles/moves/watershuriken"
|
||||
}
|
||||
},
|
||||
"curves": {
|
||||
"variable.rsize": {
|
||||
"type": "linear",
|
||||
"input": "v.particle_age",
|
||||
"horizontal_range": "v.particle_lifetime",
|
||||
"nodes": [0, 1, 1, 1, 1, 1, 1, 1]
|
||||
}
|
||||
},
|
||||
"events": {
|
||||
"trail": {
|
||||
"particle_effect": {
|
||||
"effect": "cobblemon:watershuriken_actortrail",
|
||||
"type": "particle"
|
||||
}
|
||||
},
|
||||
"hit": {
|
||||
"particle_effect": {
|
||||
"effect": "cobblemon:watershuriken_target",
|
||||
"type": "particle"
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"minecraft:emitter_initialization": {
|
||||
"creation_expression": "v.target_deltaz=5;"
|
||||
},
|
||||
"minecraft:emitter_rate_instant": {
|
||||
"num_particles": 1
|
||||
},
|
||||
"minecraft:emitter_lifetime_once": {
|
||||
"active_time": 0.25
|
||||
},
|
||||
"minecraft:emitter_shape_disc": {
|
||||
"offset": [0, 0.02, 0.1],
|
||||
"radius": 0.5,
|
||||
"direction": "outwards"
|
||||
},
|
||||
"minecraft:particle_lifetime_expression": {
|
||||
"max_lifetime": 0.35
|
||||
},
|
||||
"minecraft:particle_lifetime_events": {
|
||||
"timeline": {
|
||||
"0.00": "trail",
|
||||
"0.06": "trail",
|
||||
"0.12": "trail",
|
||||
"0.18": "trail",
|
||||
"0.24": "trail",
|
||||
"0.30": "trail",
|
||||
"0.34": "hit"
|
||||
}
|
||||
},
|
||||
"minecraft:particle_initial_spin": {
|
||||
"rotation": "math.random_integer(0,3)*90"
|
||||
},
|
||||
"minecraft:particle_motion_parametric": {
|
||||
"relative_position": ["-v.target_deltax*(v.particle_age / v.particle_lifetime)", "(v.target_deltay*(v.particle_age / v.particle_lifetime))", "-v.target_deltaz*(v.particle_age / v.particle_lifetime)"]
|
||||
},
|
||||
"minecraft:particle_appearance_billboard": {
|
||||
"size": ["0.4*v.rsize", "0.4*v.rsize"],
|
||||
"facing_camera_mode": "emitter_transform_xz",
|
||||
"uv": {
|
||||
"texture_width": 60,
|
||||
"texture_height": 15,
|
||||
"flipbook": {
|
||||
"base_UV": [0, 0],
|
||||
"size_UV": [15, 15],
|
||||
"step_UV": [15, 0],
|
||||
"frames_per_second": 24,
|
||||
"max_frame": 4,
|
||||
"loop": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-63
@@ -1,63 +0,0 @@
|
||||
{
|
||||
"format_version": "1.10.0",
|
||||
"particle_effect": {
|
||||
"description": {
|
||||
"identifier": "cobblemon:watershuriken_actortrail",
|
||||
"basic_render_parameters": {
|
||||
"material": "particles_alpha",
|
||||
"texture": "textures/particles/generic/impact/impact_water"
|
||||
}
|
||||
},
|
||||
"curves": {
|
||||
"variable.scale": {
|
||||
"type": "linear",
|
||||
"input": "v.particle_age",
|
||||
"horizontal_range": "v.particle_lifetime",
|
||||
"nodes": [1, 0]
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"minecraft:emitter_rate_instant": {
|
||||
"num_particles": 1
|
||||
},
|
||||
"minecraft:emitter_lifetime_once": {
|
||||
"active_time": 1
|
||||
},
|
||||
"minecraft:emitter_shape_point": {
|
||||
"direction": ["v.particle_random_1-0.5", "v.particle_random_2-0.25", -3]
|
||||
},
|
||||
"minecraft:particle_lifetime_expression": {
|
||||
"max_lifetime": "math.random(0.3, 0.6)"
|
||||
},
|
||||
"minecraft:particle_initial_spin": {
|
||||
"rotation": "math.round(v.particle_random_4*3)*90"
|
||||
},
|
||||
"minecraft:particle_initial_speed": 8,
|
||||
"minecraft:particle_motion_dynamic": {
|
||||
"linear_acceleration": [0, -5, 0],
|
||||
"linear_drag_coefficient": 8
|
||||
},
|
||||
"minecraft:particle_appearance_billboard": {
|
||||
"size": ["0.22 * variable.scale", "0.22 * variable.scale"],
|
||||
"facing_camera_mode": "rotate_xyz",
|
||||
"uv": {
|
||||
"texture_width": 8,
|
||||
"texture_height": 56,
|
||||
"flipbook": {
|
||||
"base_UV": [0, 24],
|
||||
"size_UV": [8, 8],
|
||||
"step_UV": [0, 8],
|
||||
"frames_per_second": 16,
|
||||
"max_frame": 4
|
||||
}
|
||||
}
|
||||
},
|
||||
"minecraft:particle_motion_collision": {
|
||||
"collision_radius": 0.02
|
||||
},
|
||||
"minecraft:particle_appearance_tinting": {
|
||||
"color": [0.61176, 0.87451, 1, 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-86
@@ -1,86 +0,0 @@
|
||||
{
|
||||
"format_version": "1.10.0",
|
||||
"particle_effect": {
|
||||
"description": {
|
||||
"identifier": "cobblemon:watershuriken_actorvert",
|
||||
"basic_render_parameters": {
|
||||
"material": "particles_blend",
|
||||
"texture": "textures/particles/moves/watershuriken"
|
||||
}
|
||||
},
|
||||
"curves": {
|
||||
"variable.rsize": {
|
||||
"type": "linear",
|
||||
"input": "v.particle_age",
|
||||
"horizontal_range": "v.particle_lifetime",
|
||||
"nodes": [0, 1, 1, 1, 1, 1, 1, 1]
|
||||
}
|
||||
},
|
||||
"events": {
|
||||
"trail": {
|
||||
"particle_effect": {
|
||||
"effect": "cobblemon:watershuriken_actortrail",
|
||||
"type": "particle"
|
||||
}
|
||||
},
|
||||
"hit": {
|
||||
"particle_effect": {
|
||||
"effect": "cobblemon:watershuriken_target",
|
||||
"type": "particle"
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"minecraft:emitter_initialization": {
|
||||
"creation_expression": "v.target_deltaz=5;"
|
||||
},
|
||||
"minecraft:emitter_rate_instant": {
|
||||
"num_particles": 1
|
||||
},
|
||||
"minecraft:emitter_lifetime_once": {
|
||||
"active_time": 0.25
|
||||
},
|
||||
"minecraft:emitter_shape_disc": {
|
||||
"offset": [0, 0.02, 0.1],
|
||||
"radius": 0.5,
|
||||
"direction": "outwards"
|
||||
},
|
||||
"minecraft:particle_lifetime_expression": {
|
||||
"max_lifetime": 0.35
|
||||
},
|
||||
"minecraft:particle_lifetime_events": {
|
||||
"timeline": {
|
||||
"0.00": "trail",
|
||||
"0.06": "trail",
|
||||
"0.12": "trail",
|
||||
"0.18": "trail",
|
||||
"0.24": "trail",
|
||||
"0.30": "trail",
|
||||
"0.34": "hit"
|
||||
}
|
||||
},
|
||||
"minecraft:particle_initial_spin": {
|
||||
"rotation": "math.random_integer(0,3)*90"
|
||||
},
|
||||
"minecraft:particle_motion_parametric": {
|
||||
"relative_position": ["-v.target_deltax*(v.particle_age / v.particle_lifetime)", "(v.target_deltay*(v.particle_age / v.particle_lifetime))", "-v.target_deltaz*(v.particle_age / v.particle_lifetime)"]
|
||||
},
|
||||
"minecraft:particle_appearance_billboard": {
|
||||
"size": ["0.4*v.rsize", "0.4*v.rsize"],
|
||||
"facing_camera_mode": "emitter_transform_yz",
|
||||
"uv": {
|
||||
"texture_width": 60,
|
||||
"texture_height": 15,
|
||||
"flipbook": {
|
||||
"base_UV": [0, 0],
|
||||
"size_UV": [15, 15],
|
||||
"step_UV": [15, 0],
|
||||
"frames_per_second": 24,
|
||||
"max_frame": 4,
|
||||
"loop": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-69
@@ -1,69 +0,0 @@
|
||||
{
|
||||
"format_version": "1.10.0",
|
||||
"particle_effect": {
|
||||
"description": {
|
||||
"identifier": "cobblemon:watershuriken_target",
|
||||
"basic_render_parameters": {
|
||||
"material": "particles_alpha",
|
||||
"texture": "textures/particles/generic/impact/impact_water"
|
||||
}
|
||||
},
|
||||
"curves": {
|
||||
"variable.scale": {
|
||||
"type": "linear",
|
||||
"input": "v.particle_age",
|
||||
"horizontal_range": "v.particle_lifetime",
|
||||
"nodes": [1, 0]
|
||||
}
|
||||
},
|
||||
"events": {
|
||||
"event": {
|
||||
"particle_effect": {
|
||||
"effect": "cobblemon:watershuriken_targetspark",
|
||||
"type": "particle"
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"minecraft:emitter_rate_steady": {
|
||||
"spawn_rate": 240,
|
||||
"max_particles": 14
|
||||
},
|
||||
"minecraft:emitter_lifetime_once": {
|
||||
"active_time": 0.1
|
||||
},
|
||||
"minecraft:emitter_lifetime_events": {
|
||||
"creation_event": "event"
|
||||
},
|
||||
"minecraft:emitter_shape_point": {},
|
||||
"minecraft:particle_lifetime_expression": {
|
||||
"max_lifetime": "math.random(0.3, 0.6)"
|
||||
},
|
||||
"minecraft:particle_initial_spin": {
|
||||
"rotation": "math.round(v.particle_random_4*3)*90"
|
||||
},
|
||||
"minecraft:particle_initial_speed": "math.random(9,17)",
|
||||
"minecraft:particle_motion_dynamic": {
|
||||
"linear_drag_coefficient": 5
|
||||
},
|
||||
"minecraft:particle_appearance_billboard": {
|
||||
"size": ["0.3 * variable.scale", "0.3 * variable.scale"],
|
||||
"facing_camera_mode": "rotate_xyz",
|
||||
"uv": {
|
||||
"texture_width": 8,
|
||||
"texture_height": 56,
|
||||
"flipbook": {
|
||||
"base_UV": [0, 16],
|
||||
"size_UV": [8, 8],
|
||||
"step_UV": [0, 8],
|
||||
"frames_per_second": 16,
|
||||
"max_frame": 5
|
||||
}
|
||||
}
|
||||
},
|
||||
"minecraft:particle_appearance_tinting": {
|
||||
"color": [0.61176, 0.87451, 1, 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loaded 100 of 716 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user