mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-21 14:46:25 -04:00
Compare commits
60
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e01bc2eeab | ||
|
|
f6f3070b8e | ||
|
|
0f2301e668 | ||
|
|
e077a5d453 | ||
|
|
e7208ed396 | ||
|
|
27f8bbf029 | ||
|
|
2f97a69b8c | ||
|
|
79d67389ba | ||
|
|
61f2150f2e | ||
|
|
5d63c8fe06 | ||
|
|
0d109a64fd | ||
|
|
5daef700e7 | ||
|
|
21bd1550f0 | ||
|
|
0d4f63ba01 | ||
|
|
946cff21fb | ||
|
|
8a2291cd6e | ||
|
|
304ac0e07a | ||
|
|
3cac1138fb | ||
|
|
b19a11f8ab | ||
|
|
cad64ae24b | ||
|
|
9036909968 | ||
|
|
53b98e8008 | ||
|
|
574fd92827 | ||
|
|
e6d7513c20 | ||
|
|
e36252318a | ||
|
|
5d5dbb9e79 | ||
|
|
4036592c9a | ||
|
|
c0ddbad4f5 | ||
|
|
fa1f485cd2 | ||
|
|
b5aeb0e5f7 | ||
|
|
9c2680783a | ||
|
|
b7ed72241b | ||
|
|
689f9eabc0 | ||
|
|
4fd24be1d3 | ||
|
|
7579203527 | ||
|
|
9e3dd9373c | ||
|
|
c9b9ac7d07 | ||
|
|
dddae893cd | ||
|
|
86508801d3 | ||
|
|
de44411ad2 | ||
|
|
e59aa01345 | ||
|
|
3f3e8b5747 | ||
|
|
bb769fa165 | ||
|
|
163218c0a8 | ||
|
|
e61eadb834 | ||
|
|
29c8bbe9e9 | ||
|
|
7c42390515 | ||
|
|
ff84ca69cd | ||
|
|
dda3c4e981 | ||
|
|
1570bbf42b | ||
|
|
41cfe79b0e | ||
|
|
dc4e3dc39c | ||
|
|
d100537d41 | ||
|
|
fe218399e2 | ||
|
|
8f4a4a7e45 | ||
|
|
de04379297 | ||
|
|
10bf9d1abd | ||
|
|
54cd0ba700 | ||
|
|
46b4bfa7ea | ||
|
|
f5a308e579 |
+76
-72
@@ -1,37 +1,36 @@
|
||||
# Changelog
|
||||
## [1.?.?]()
|
||||
### Developer
|
||||
- Various breaking changes have been made to ElementalTypes, Moves and other registries, Cobblemon has migrated to make use of proper Minecraft registries.
|
||||
- DamageCategory is now an Enum.
|
||||
- Gender has been moved to an API package.
|
||||
|
||||
### Datapack & Resourcepack Creators
|
||||
- Pokémon types can now be created via datapacks. Data path is ``your_mod_namespace/cobblemon/elemental_types/path_to_your_file``.
|
||||
- Custom moves are now possible via datapacks, these require JavaScript/TypeScript programming knowledge. Data path is ``your_mod_namespace/cobblemon/moves/path_to_your_file``.
|
||||
- Pokémon species data path has been changed to ``your_mod_namespace/cobblemon/species/path_to_your_file``.
|
||||
|
||||
## [1.4.0](#1-4-0)
|
||||
## [1.4.0 - The Friends and Farms Update (October 13th, 2023)](#1-4-0)
|
||||
### Additions
|
||||
- Added nicknaming.
|
||||
- Added mints, found on mountains.
|
||||
- Added revival herbs, with pep-up flowers if fully grown, growing in lush caves.
|
||||
- Added medicinal leeks, growing on the surface of rivers and ponds. It is a potion ingredient!
|
||||
- Added big roots, generating from cave ceiling dirt and sometimes spreading into energy roots.
|
||||
- Added trading between players. Press R while looking at another player, you'll figure it out.
|
||||
- Added pasture blocks, used to let your PC Pokémon roam around your base.
|
||||
- Added 69 berry trees. Some are found in village farms, some from planting different berries close to each other.
|
||||
- Added pasture blocks, used to let your PC Pokémon roam around an area.
|
||||
- Added nicknaming from the summary menu of a Pokémon (click their name).
|
||||
- Added trading between players. Press R while looking at another player and you'll figure the rest out.
|
||||
- Added mints for changing Pokémon stats. These are most commonly found at high altitudes.
|
||||
- Added [Revival Herbs](https://wiki.cobblemon.com/index.php/Revival_Herb), with pep-up flowers when fully grown, growing in lush caves.
|
||||
- Added [Medicinal Leeks](https://wiki.cobblemon.com/index.php/Medicinal_Leek), growing on the surface of rivers and ponds. It is a potion ingredient and can be cooked as food!.
|
||||
- Added [Big Roots](https://wiki.cobblemon.com/index.php/Big_Root), generating from cave ceiling dirt which sometimes spread as energy roots.
|
||||
- Added [69 Berry Trees](https://wiki.cobblemon.com/index.php/Berry_Tree) and [Berries](https://wiki.cobblemon.com/index.php/Berry). Some are found in village farms, some from planting different berries close to each other.
|
||||
- Added mulches: Mulch Base, Growth Mulch, Surprise Mulch, Coarse Mulch, Humid Mulch, Rich Mulch, Loamy Mulch, Peat Mulch, and Sandy Mulch
|
||||
- Added [Vivichokes](https://wiki.cobblemon.com/index.php/Vivichoke), obtainable from wandering villager trades and some loot chests.
|
||||
- Added medicine brewing using medicinal leeks and berries in brewing stands.
|
||||
- Added Pokémon cries when in battles and being sent out.
|
||||
- Added support for scale in animations.
|
||||
- Added support for jump keyframes (i.e. pre and post keyframes)
|
||||
- Added AI for Nosepass to point towards world spawn when idle.
|
||||
- Added structure spawn conditions
|
||||
- Added recipes for Berry Juice, Heal Powder, Remedy, Fine Remedy, Superb Remedy, Revive, Max Revive, HP Up, Protein, Iron, Calcium, Zinc, Carbos, PP Up, PP Max, Pasture, Medicinal Leek to Magenta Dye, Roasted Leek, Leek and Potato Stew, Braised Vivichoke, Vivichoke Dip, Mulch Base, Growth Mulch, Surprise Mulch, Coarse Mulch, Humid Mulch, Rich Mulch, Loamy Mulch, Peat Mulch, Sandy Mulch, X Attack, X Defense, X Special Attack, X Special Defense, X Speed, X Accuracy, Dire Hit, Guard Spec, Power Anklet, Power Band, Power Belt, Power Bracelet, Power Lens, Power Weight, Bright Powder, Destiny Knot
|
||||
- Added a shoulder mount for Mimikyu
|
||||
- Added Advancement trigger for defeating Pokémon and collecting varieties of Pokémon.
|
||||
- Added sleep animations to Arcanine, Jigglypuff, Wigglytuff, Vulpix and Ninetales.
|
||||
- Added medicinal items: Berry Juice, Heal Powder, Remedy, Fine Remedy, Superb Remedy, Revive, Max Revive, Potion, Super Potion, Hyper Potion, Max Potion, Full Restore, Full Heal, Antidote, Awakening, Burn Heal, Ice Heal, and Paralyze Heal.
|
||||
- Added battle items: X Attack, X Defence, X Sp.Atk, X Sp.Def, X Speed, Dire Hit, and Guard Spec.
|
||||
- Added EV items: Power Anklet, Power Band, Power Belt, Power Bracelet, Power Lens, Power Weight.
|
||||
- Added food items: Roasted Leek, Leek and Potato Stew, Braised Vivichoke, and Vivichoke Dip
|
||||
- Added evolution items: Auspicious Armor and Malicious Armor, which can be used to evolve Charcadet into Armarouge or Ceruledge respectively.
|
||||
- Added (mostly brewing) recipes for HP Up, Protein, Iron, Calcium, Zinc, Carbos, PP Up, PP Max, and Medicinal Leek to Magenta Dye.
|
||||
- Added held items: Bright Powder, Destiny Knot
|
||||
- Added AI for Nosepass to point towards world spawn when idle. We just think it's neat.
|
||||
- Added shoulder mounting for Mimikyu.
|
||||
- Added flying placeholder animations to Pidgey, Pidgeotto, Pidgeot, Golbat, Crobat, Scyther, Scizor, Zapdos, Moltres, Articuno, Dragonite, Rowlet, Dartrix, and Decidueye.
|
||||
- Added loot to various vanilla chest loot tables (Link Cable in Ancient Cities, Woodland Mansions, End Cities, and Igloos, Vivichoke Seeds in Jungle Temples, Dungeons, and Plains, Savanna, Snowy, and Taiga Villages, and all 7 Apricorn Sprouts in Desert, Plains, Savanna, Snowy, and Taiga Villages, as well as the Bonus Chest, which can also have 5 of the basic Poké Ball types)
|
||||
- Added a `doShinyStarters` gamerule to make it quick and easy to be offered shiny starters.
|
||||
- Added a `doPokemonLoot` gamerule to toggle Pokémon dropping items/exp on death.
|
||||
- Added ability activation announcement when in battle.
|
||||
- Added animations for Wailord and made it BIGGER.
|
||||
- Added Cherry Torterra variant.
|
||||
- Added 2 new face spots for Spinda. The number of unique Spindas increases...
|
||||
- Added Forretress Shulker variant.
|
||||
- Added the `/teststore <player> <store> <properties>` command allowing command block/mcfunction users to query a party, PC or both for Pokémon matching specific properties and returning the match count, this will be a cheat command in the Minecraft permission system or use the permission `cobblemon.command.teststore` if a permission mod is present.
|
||||
- Added the `/querylearnset <player> <slot> <move>` command allowing command block/mcfunction users to query a party slot and check if the Pokémon can learn a specific move returning a 1 if yes otherwise 0, this will be a cheat command in the Minecraft permission system or use the permission `cobblemon.command.querylearnset` if a permission mod is present.
|
||||
- Added the `/testpcslot <player> <slot> <properties>` command allowing command block/mcfunction users to query a pc slot and check if the Pokémon matches specific properties returning a 1 if yes otherwise 0, this will be a cheat command in the Minecraft permission system or use the permission `cobblemon.command.testpcslot` if a permission mod is present.
|
||||
@@ -39,18 +38,6 @@
|
||||
- Added the `/clearparty <player>` command for emptying a player's party.
|
||||
- Added the `/clearpc <player>` command for emptying a player's PC.
|
||||
- Added the `/pokemonrestart <reset_starters>` and the `/pokemonrestartother <player> <reset_starters>` command allowing command block/mcfunction users to reset a players Pokémon data.
|
||||
- Added support for "isBattle" and "isTouchingWater" properties on resource pack Pokémon poses. This allows your custom Pokémon to be posed differently when in battle.
|
||||
- Added support for "isVisible" on a transformed part on resource pack Pokémon poses. This allows your custom Pokémon to have bones disappear in specific poses, such as hiding Greninja's throwing star when not in a battle pose.
|
||||
- Added a "doShinyStarters" gamerule
|
||||
- Added the `doPokemonLoot` gamerule to toggle Pokémon dropping items/exp on death.
|
||||
- Added support for battle music. Sounds can be added to the ``battle.pvp.default`` and ``battle.pvw.default`` sound events.
|
||||
- Added ability activation announcement when in battle.
|
||||
- Added Auspicious Armor and Malicious Armor, which can be used to evolve Charcadet into Armarouge or Ceruledge respectively.
|
||||
- Added animations for Wailord.
|
||||
- Added Cherry Torterra variant.
|
||||
- Added 2 new face spots for Spinda.
|
||||
- Added Forretress Shulker variant.
|
||||
- Added 'enabled' optional property on model layers, allowing later variations to disable previously-defined layers. See [this issue](https://gitlab.com/cable-mc/cobblemon/-/issues/335) for how this looks.
|
||||
|
||||
### Pokémon Added
|
||||
#### Gen 2
|
||||
@@ -268,39 +255,36 @@
|
||||
- Clodsire
|
||||
|
||||
### Changes
|
||||
- Updated model and textures of Spiritomb, Koffing, Weezing, Kadabra, Alakazam, Emolga, Oshawott, Doduo, Dodrio, Dratini, Dragonair, Dragonite, Sneasel, Weavile, Gyarados, Hitmonlee, Hitmonchan, Chesnaught, Spinda, Mamoswine, Steelix, Midreavus, Mismagius, Buneary, Lopunny, Golduck, Meowth, Persian, Fennekin, Braixen, Delphox, Snivy, Servine, Serperior, Ratatta, Raticate, Nidorina, Nidoqueen, NidoranM, Nidoking, Riolu, Lucario, Haunter, Mankey, Primeape, Mew, Mewtwo, Arcanine, Magnemite, Magneton, Magnezone, Exeggcute, Exeggutor, Elekid, Electabuzz, Electivire, Pichu, Pikachu, Raichu, Gengar, Wooper, Drowzee, Hypno, Aerodactyl, Spearow, Fearow, Lickitung, Pidgey, Pidgeotto, Pidgeot, Scyther, Scizor, Kleavor, Popplio, Brionne, Primarina, Torchic, Combusken, Blaziken, Aerodacyl, Scyther, Scizor, Kleavor, Lickitung, Lickilicky, Happiny, Chansey and Blissey.
|
||||
- Updated animations for Steelix, Turtwig, Grotle, Torterra, Ponyta, Rapidash, Piplup, Prinplup, Empoleon, Drowzee, Hypno, Farfetch'd, Exeggcute, Exeggutor, Bidoof, Chimecho, Lickytung, Lickilicky, Popplio, Brionne, Luvdisc, Chimchar, Monferno, Infernape, Sobble, Drizzile, Inteleon, Greninja, Heatmor, Aerodactyl, Ditto, Lotad, Lombre, Ludicolo, Pumpkaboo, Gourgeist.
|
||||
- Removed the existing shoulder effects from Pokémon until we have more balanced versions of them (they're too powerful!)
|
||||
- Updated models and textures of Weedle, Dwebble and Crustle, Spiritomb, Koffing and Weezing, Kadabra and Alakazam, Emolga, Oshawott, Doduo and Dodrio, Dratini and Dragonair and Dragonite, Sneasel and Weavile, Gyarados, Hitmonlee and Hitmonchan, Chesnaught, Spinda, Mamoswine, Steelix, Misdreavus and Mismagius, Buneary and Lopunny, Golduck, Meowth and Persian, Fennekin and Braixen and Delphox, Snivy and Servine and Serperior, Ratatta and Raticate, Nidorina and Nidoqueen, Nidoran Male and Nidoking, Riolu and Lucario, Haunter and Gengar, Mankey and Primeape, Mew and Mewtwo, Arcanine, Magnemite and Magneton and Magnezone, Exeggcute and Exeggutor, Elekid and Electabuzz and Electivire, Pichu and Pikachu and Raichu, Wooper, Drowzee and Hypno, Aerodactyl, Spearow and Fearow, Lickitung and Lickilicky, Pidgey and Pidgeotto and Pidgeot, Scyther and Scizor and Kleavor, Popplio and Brionne and Primarina, Torchic and Combusken and Blaziken, Happiny and Chansey and Blissey.
|
||||
- Updated animations for Steelix, Turtwig and Grotle and Torterra, Ponyta and Rapidash, Piplup and Prinplup and Empoleon, Drowzee and Hypno, Farfetch'd, Exeggcute and Exeggutor, Bidoof, Chimecho, Lickitung and Lickilicky, Popplio and Brionne, Luvdisc, Chimchar and Monferno and Infernape, Sobble and Drizzile and Inteleon, Greninja, Heatmor, Aerodactyl, Ditto, Lotad and Lombre and Ludicolo, Pumpkaboo and Gourgeist.
|
||||
- Updated sprites for EV medicines, the rare candy, and the apricorn door item.
|
||||
- Updated textures for apricorn doors and all the evolution stone ores.
|
||||
- Ponyta and Rapidash now have animated textures; they look insane.
|
||||
- Updated Apricorn Leaves color.
|
||||
- Wild Pokémon now heal if you are defeated by them or flee from them.
|
||||
- Doubled the default time between ambient Pokémon cries (they have cries if you're using a resource pack to add them)
|
||||
- Moved spawn attempts per tick to a config option (ticksBetweenSpawnAttempts)
|
||||
- PCs can now be waterlogged
|
||||
- Starter selection prompt now appears as a tutorial-esque toast instead of plain text
|
||||
- Cobblemon items can now all have their own tooltips via resourcepacks, to add a tooltip simply add a lang entry like "item.cobblemon.{item_id}.tooltip", if you want to add multiple tooltip lines you can do so with "item.cobblemon.{item_id}.tooltip_1" and upwards.
|
||||
- Updated texture of Weedle.
|
||||
- Updated shiny texture of Dwebble and Crustle.
|
||||
- Reorganised the advancements recipes folder
|
||||
- Pokéedit command now supports IVs and EVs.
|
||||
- Reorganised creative categories
|
||||
- Pokémon can now wander into non-solid blocks such as foliage
|
||||
- Pokéballs now despawn after 30 seconds
|
||||
- Thrown Poké Balls now despawn after 30 seconds so that they don't fly forever.
|
||||
- Dive Balls will now have the same motion speed underwater as if they were thrown in the air.
|
||||
- Hardcoded potion shoulder effects have been removed, you can now use any potion vanilla or otherwise with the parameters you'd like, for more information see the [Datapack & Resourcepack Creators](#datapack-&-resourcepack-creators) section.
|
||||
- Clicking categories of the Stat sub-section or the party reorder button in the Summary screen will now produce a click sound.
|
||||
- Hardcoded potion shoulder effects have been removed. You can now use any potion vanilla or otherwise with the parameters you'd like, for more information see the [Datapack & Resourcepack Creators](#datapack-&-resourcepack-creators) section.
|
||||
- Clicking categories of the Stat subsection or the party reorder button in the Summary screen will now produce a click sound.
|
||||
- Updated PC Recipe.
|
||||
- Improved Pokémon AI and movement.
|
||||
- Friendship will slowly increase when Pokémon are shoulder-mounted.
|
||||
- Master balls are now unable to be burned when dropped into fire/lava.
|
||||
- Master Balls are now unable to be burned when dropped into fire/lava. They're made from stronger stuff.
|
||||
- Pokémon will appear red when hurt, like regular entities, except when they're fainting.
|
||||
- Ponyta and Rapidash now have animated textures.
|
||||
- Pokémon's air meter no longer depletes while battling underwater.
|
||||
- Sleeping partially restores PP of Pokémon
|
||||
- Item interaction evolutions and held item requirements now support NBT by creating an object JSON containing the key ``item`` for what used to be the existing condition support and a ``nbt`` key for the NBT format, this is the string [format](https://minecraft.fandom.com/wiki/NBT_format) expected in commands. Existing data does not need to be updated.
|
||||
- Shoulder mounts now match the shoulder position a bit more accurately when sneaking.
|
||||
- Poison Heal will now cause poisoned Pokémon to heal outside of battle.
|
||||
- Updated Pokéball, PC, UI, evolution and Healing Machine sounds.
|
||||
- Updated Poké Ball, PC, UI, evolution and Healing Machine sounds.
|
||||
|
||||
### Added cries to the following Pokémon:
|
||||
- All starters and their evolutions
|
||||
@@ -370,48 +354,48 @@
|
||||
- Tatsugiri
|
||||
|
||||
### Fixes
|
||||
- Fixed spawning moon phase dependent Pokémon only when the moon phase is wrong
|
||||
- Fixed spawning moon phase dependent Pokémon only when the moon phase is wrong (that's a funny woopsy)
|
||||
- Fixed large Pokémon spawning partially inside walls where they suffocate.
|
||||
- Fixed custom Pokémon in your party or PC not being removed when the addon is removed, causing major issues.
|
||||
- Fixed messages for entry hazards, screens, weather, damage, healing, Tailwind, Perish Song, Destiny Bond, Shed Skin, Uproar, Forewarn, Disguise, Arena Trap, Yawn, Curse, Clamp, Whirlpool, Liquid Ooze, Miracle Eye, Safeguard, Magic Bounce, Lock On, Focus Energy, Confusion, and more.
|
||||
- Fixed Porygon not evolving with an Upgrade.
|
||||
- Fixed super sized Pumpkaboo not having any moves.
|
||||
- Fixed Infernape look animation.
|
||||
- Fixed Garchomp t-posing while swimming.
|
||||
- Fixed a bug that caused sleeping Pokémon to stay asleep.
|
||||
- Fixed a bug that would freeze a battle when a Pokémon gets trapped due to an ability.
|
||||
- Fixed Garchomp T-posing while swimming which was very funny.
|
||||
- Fixed a bug that caused sleeping Pokémon to stay asleep. Forever. The years passing them by as they dream of a world without hate...
|
||||
- Fixed a bug that would freeze a battle when a Pokémon gets trapped by an ability, making the trap abilities even scarier and trap-like than they were before.
|
||||
- Fixed the Poké Ball close animation canceling whenever colliding with a block.
|
||||
- Fixed faint animations not working properly in add-ons.
|
||||
- Fixed lighting and Pokémon label issues when a Pokémon item frame is nearby.
|
||||
- Fixed Pokémon being able to spawn outside the world border as a tease.
|
||||
- Fixed deepslate water stone ore items looking like deepslate fire stone ores.
|
||||
- Fixed a bunch of client-side logging errors when Pokémon are shoulder mounted.
|
||||
- Fixed deepslate water stone ore items looking like deepslate fire stone ores. Huh?
|
||||
- Fixed a bunch of client-side logging errors when Pokémon are shoulder mounted. You didn't notice? Good.
|
||||
- Fixed a crash when wild Pokémon have to struggle under specific circumstances.
|
||||
- Fixed uncolored pixels on Yanma's shiny texture.
|
||||
- Fixed apricorn tree leaves looking gross on Fast graphics mode.
|
||||
- Fixed apricorn tree leaves looking gross on the Fast graphics mode.
|
||||
- Fixed hoes not breaking apricorn tree leaves any faster.
|
||||
- Fixed Shiftry's PC model position.
|
||||
- Fixed the /pc command not playing the opening sound.
|
||||
- Fixed Shedinja not being able to recover naturally.
|
||||
- Fixed different forms of Pokémon not being able to appear as different sizes.
|
||||
- Fixed the Healing Machine soft locking you from using others when removed by non-players.
|
||||
- Fixed animations being sped up when using the Replay Mod.
|
||||
- Fixed particle animations not running when a Pokémon is off-screen.
|
||||
- Fixed Pokémon variants and layers not rendering correctly when shouldered and playing on a dedicated server, existing shoulders affected will need to be retrieved and shouldered again.
|
||||
- Shoulder effects will now stay applied through situations that remove potion effects such as drinking milk.
|
||||
- Fixed Shedinja evolving to use the consumed PokéBall and removed the held item.
|
||||
- Fixed non-existent species in spawn pool file causing random species to spawn.
|
||||
- Fixed shearing Pokémon dropping 0-2 wool instead of 1-3.
|
||||
- Fixed some alignment issues in the stat hexagon of the summary menu.
|
||||
- Fixed capture calculations not applying ball bonuses entirely correctly.
|
||||
- Fixed shoulder effects not staying applied through situations that remove potion effects such as drinking milk.
|
||||
- Fixed Shedinja not being able to recover naturally.
|
||||
- Fixed Shedinja evolving to use the consumed Poké Ball and removed the held item to prevent dupes.
|
||||
- Fixed Shedinja healing above 1 HP.
|
||||
- Fixed Shedinja, basically.
|
||||
- Fixed shearing Pokémon dropping 0-2 wool instead of 1-3.
|
||||
- Fixed some alignment issues in the stat hexagon of the summary menu. OCD people rejoice.
|
||||
- Fixed capture calculations not applying ball bonuses entirely correctly.
|
||||
- Fixed battles soft-locking when consecutive Pokémon faint on switch-in.
|
||||
- Fixed timing and color of battle window messages.
|
||||
- Fixed players being able to trade, battle and let out their Pokémon while in spectator mode.
|
||||
- Fixed Galarian Yamask not being able to evolve and by proxy the ``damage_taken`` evolution requirement.
|
||||
- Fixed Bisharp not being able to evolve and by proxy the ``defeat`` evolution requirement.
|
||||
- Fixed White-Striped Basculin not being able to evolve and by proxy the ``recoil`` evolution requirement.
|
||||
- Fixed Primeape, Qwilfish and Stantler not being able to evolve and by proxy the ``use_move`` evolution requirement.
|
||||
- Fixed Bramblin, Pawmo, and Rellor not being able to evolve and by proxy the ``blocks_traveled`` evolution requirement.
|
||||
- Fixed White-Striped Basculin not being able to evolve because of a broken ``recoil`` evolution requirement.
|
||||
- Fixed Primeape, Qwilfish and Stantler not being able to evolve because of a broken ``use_move`` evolution requirement.
|
||||
- Fixed Bramblin, Pawmo, and Rellor not being able to evolve because of a broken ``blocks_traveled`` evolution requirement.
|
||||
- Fixed displayName property in spawn files not doing what it's meant to do.
|
||||
- Fixed Pokémon not sleeping in the wild like we wanted them to.
|
||||
|
||||
@@ -424,9 +408,12 @@
|
||||
- The various hardcoded potion shoulder effects have been removed, make use of PotionBaseEffect.
|
||||
- Added ContextManager for tracking causes and contexts of conditions created during a battle. See BattleContext for types of conditions that are tracked.
|
||||
- Added MongoDB support for storing Pokémon and Player data. Must be enabled in config, requires MongoDB core and sync drivers (4.10.0+).
|
||||
- CobblemonShowdown updated to version 10.
|
||||
- Generation of a battle can be set in BattleFormat.
|
||||
- Pokémon now have ``teraType``, ``dmaxLevel``, and ``gmaxFactor`` properties. Gimmicks can be used during battle by adding the respective identifiers to ``keyItems`` in PlayerData: ``key_stone``, ``z_ring``, ``dynamax_band``, and ``tera_orb``. Dynamax is only supported in Gen 8 battles. Mega Evolution and Z-Power require custom held items to be added (e.g. an item with the path ``gengarite`` will allow Gengar to Mega Evolve). Currently custom Z-Crystals and Mega Stones are not supported.
|
||||
|
||||
### Datapack & Resourcepack Creators
|
||||
- All potion related shoulder effects have had their IDs changed, they now all share the same type being `potion_effect` and use the vanilla Potion data [parameters](https://minecraft.fandom.com/wiki/Potion#Item_data), take for example the default Pidgey asset:
|
||||
- All potion related shoulder effects have had their IDs changed. They now all share the same type being `potion_effect` and use the vanilla Potion data [parameters](https://minecraft.fandom.com/wiki/Potion#Item_data). For example, here is the converted Pidgey asset:
|
||||
- ```json
|
||||
{
|
||||
"type": "potion_effect",
|
||||
@@ -438,6 +425,22 @@
|
||||
}
|
||||
```
|
||||
- Renamed the ``walked_steps`` evolution requirement to ``blocks_traveled``.
|
||||
- Added support for scale in animations.
|
||||
- Added support for jump keyframes (i.e. pre and post keyframes)
|
||||
- Added structure spawning conditions
|
||||
- Added Advancement trigger for defeating Pokémon and collecting varieties of Pokémon.
|
||||
- Added support for "isBattle" and "isTouchingWater" properties on resource pack Pokémon poses. This allows your custom Pokémon to be posed differently when in battle.
|
||||
- Added support for "isVisible" on a transformed part on resource pack Pokémon poses. This allows your custom Pokémon to have bones disappear in specific poses, such as hiding Greninja's throwing star when not in a battle pose.
|
||||
- Added support for battle music. Sounds can be added to the ``battle.pvp.default`` and ``battle.pvw.default`` sound events.
|
||||
- Added 'enabled' optional property on model layers, allowing later variations to disable previously-defined layers. See [this issue](https://gitlab.com/cable-mc/cobblemon/-/issues/335) for how this looks.
|
||||
- Cobblemon items can now all have their own tooltips via resourcepacks. To add a tooltip, add a lang entry like "item.cobblemon.{item_id}.tooltip". If you want to add multiple tooltip lines you can do so with "item.cobblemon.{item_id}.tooltip_1" and upwards.
|
||||
- Item interaction evolutions and held item requirements now support NBT by creating an object JSON containing the key ``item`` for what used to be the existing condition support and a ``nbt`` key for the NBT format, this is the string [format](https://minecraft.fandom.com/wiki/NBT_format) expected in commands. Existing data does not need to be updated.
|
||||
- Fixed faint animations not working properly in add-ons.
|
||||
- Fixed non-existent species in spawn pool files causing random species to spawn.
|
||||
|
||||
### Localization
|
||||
- Added partial translations for Dutch, Polish, Swedish, Hungarian, Czech, Cyprus Greek, and even Esperanto.
|
||||
- Updated translation for French and Canadian French, Simplified Chinese, Japanese, Korean, Spanish and Mexican Spanish, Pirate English, German, Thai, Turkish, Portuguese and Brazilian Portuguese, Ukrainian, and Russian.
|
||||
|
||||
## [1.3.1 (March 31st, 2023)](#1-3-1)
|
||||
|
||||
@@ -451,7 +454,7 @@
|
||||
- Add lava surface spawn preset.
|
||||
- Added an ``any`` evolution requirement allowing you to define ``possibilities`` of other evolution requirements, for example, this allows you to create an evolution that requires the Pokémon to be shiny or a female.
|
||||
- Added the `/spawnpokemonfrompool [amount]` or `/forcespawn [amount]` command to spawn Pokémon(s) in the surrounding area using the natural spawn rates/pool of that area, this will be a cheat command in the Minecraft permission system or use the permission `cobblemon.command.spawnpokemon` if a permission mod is present. On a successful execution of the command, the amount of Pokémon spawned will be the output.
|
||||
- Added the `/pokebox` and `/pokeboxall` commands to move Pokemon(s) to the PC from a Player's party, this will be a cheat command in the Minecraft permission system or use the permission `cobblemon.command.pokebox` if a permission mod is present. On a successful execution of the command the output will be the number of pokemon moved to the Player's PC.
|
||||
- Added the `/pokebox` and `/pokeboxall` commands to move Pokémon(s) to the PC from a Player's party, this will be a cheat command in the Minecraft permission system or use the permission `cobblemon.command.pokebox` if a permission mod is present. On a successful execution of the command the output will be the number of pokemon moved to the Player's PC.
|
||||
- Added the `/pc` command which opens up the PC UI the same way interacting with the block would, this will be a cheat command in the Minecraft permission system or use the permission `cobblemon.command.pc` if a permission mod is present.
|
||||
|
||||
### Changes
|
||||
@@ -794,6 +797,7 @@
|
||||
- Fixed Magnitude battle messages.
|
||||
- Moves that are disabled or out of PP now show transparently in the battle GUI instead of being hidden completely.
|
||||
- Statuses like sleep and frozen no longer last forever if it was carried over from a previous battle.
|
||||
- Fixed a formatting error that affected Pokemon nicknames when the storage type is JSON.
|
||||
|
||||
### Localization
|
||||
- Added species, ability, and move translations for `ko_ko`, `jp_jp`, `fr_fr`, `es_es`, `it_it`, and `zh_cn`.
|
||||
|
||||
@@ -28,7 +28,7 @@ dependencies {
|
||||
|
||||
modImplementation(libs.fabricLoader)
|
||||
//Flywheel has no common dep so just pick one and don't use any platform specific code in common
|
||||
modCompileOnly(libs.flywheelFabric)
|
||||
// modCompileOnly(libs.flywheelFabric)
|
||||
modApi(libs.molang)
|
||||
compileOnlyApi(libs.jeiApi)
|
||||
|
||||
|
||||
@@ -6,11 +6,10 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
@file:Suppress("unused")
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.cobblemon.mod.common.advancement.CobblemonCriteria
|
||||
import com.cobblemon.mod.common.advancement.criterion.EvolvePokemonContext
|
||||
import com.cobblemon.mod.common.api.Priority
|
||||
import com.cobblemon.mod.common.api.SeasonResolver
|
||||
import com.cobblemon.mod.common.api.data.DataProvider
|
||||
@@ -31,7 +30,6 @@ import com.cobblemon.mod.common.api.pokeball.catching.calculators.CaptureCalcula
|
||||
import com.cobblemon.mod.common.api.pokeball.catching.calculators.CaptureCalculators
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.api.pokemon.effect.ShoulderEffectRegistry
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.adapters.EvolutionRegistry
|
||||
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceCalculator
|
||||
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceGroups
|
||||
import com.cobblemon.mod.common.api.pokemon.experience.StandardExperienceCalculator
|
||||
@@ -43,7 +41,6 @@ import com.cobblemon.mod.common.api.pokemon.stats.EvCalculator
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Generation8EvCalculator
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.StatProvider
|
||||
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistryKeys
|
||||
import com.cobblemon.mod.common.api.scheduling.ScheduledTaskTracker
|
||||
import com.cobblemon.mod.common.api.spawning.BestSpawner
|
||||
import com.cobblemon.mod.common.api.spawning.CobblemonSpawningProspector
|
||||
@@ -63,7 +60,6 @@ import com.cobblemon.mod.common.api.storage.player.PlayerDataStoreManager
|
||||
import com.cobblemon.mod.common.api.storage.player.factory.JsonPlayerDataStoreFactory
|
||||
import com.cobblemon.mod.common.api.storage.player.factory.MongoPlayerDataStoreFactory
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonEntityTypeTags
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.battles.BagItems
|
||||
import com.cobblemon.mod.common.battles.BattleFormat
|
||||
import com.cobblemon.mod.common.battles.BattleRegistry
|
||||
@@ -166,7 +162,6 @@ object Cobblemon {
|
||||
|
||||
fun preInitialize(implementation: CobblemonImplementation) {
|
||||
this.implementation = implementation
|
||||
this.queueRegistryCreation()
|
||||
implementation.registerPermissionValidator()
|
||||
implementation.registerSoundEvents()
|
||||
implementation.registerBlocks()
|
||||
@@ -194,8 +189,6 @@ object Cobblemon {
|
||||
|
||||
ShoulderEffectRegistry.register()
|
||||
|
||||
EvolutionRegistry.init()
|
||||
|
||||
DATA_SYNCHRONIZED.subscribe {
|
||||
storage.onPlayerDataSync(it)
|
||||
playerData.get(it).sendToPlayer(it)
|
||||
@@ -344,7 +337,7 @@ object Cobblemon {
|
||||
// Ensure the config option is enabled and that the result was a ninjask and that shedinja exists
|
||||
if (this.config.ninjaskCreatesShedinja && pokemon.species.resourceIdentifier == ninjaskIdentifier && PokemonSpecies.getByIdentifier(Pokemon.SHEDINJA) != null) {
|
||||
val player = pokemon.getOwnerPlayer() ?: return@subscribe
|
||||
if (player.inventory.containsAny { it.item is PokeBallItem }) {
|
||||
if (player.isCreative || player.inventory.containsAny { it.item is PokeBallItem }) {
|
||||
var pokeball = Items.AIR
|
||||
player.inventory.combinedInventory.forEach {
|
||||
it.forEach {
|
||||
@@ -353,7 +346,12 @@ object Cobblemon {
|
||||
}
|
||||
}
|
||||
}
|
||||
player.inventory.removeAmountIf(1) { it.item is PokeBallItem }
|
||||
if (!player.isCreative) {
|
||||
player.inventory.removeAmountIf(1) { it.item is PokeBallItem }
|
||||
}
|
||||
if (pokeball == Items.AIR) {
|
||||
pokeball = CobblemonItems.POKE_BALL
|
||||
}
|
||||
val properties = event.evolution.result.copy()
|
||||
properties.species = Pokemon.SHEDINJA.toString()
|
||||
val product = pokemon.clone()
|
||||
@@ -361,6 +359,7 @@ object Cobblemon {
|
||||
properties.apply(product)
|
||||
product.caughtBall = (pokeball as PokeBallItem).pokeBall
|
||||
pokemon.storeCoordinates.get()?.store?.add(product)
|
||||
CobblemonCriteria.EVOLVE_POKEMON.trigger(player, EvolvePokemonContext(event.pokemon.preEvolution!!.species.resourceIdentifier, product.species.resourceIdentifier, playerData.get(player).advancementData.totalEvolvedCount))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -480,8 +479,4 @@ object Cobblemon {
|
||||
this.implementation.registerCommandArgument(cobblemonResource("pokemon_store"), PokemonStoreArgumentType::class, ConstantArgumentSerializer.of(PokemonStoreArgumentType::pokemonStore))
|
||||
}
|
||||
|
||||
private fun queueRegistryCreation() {
|
||||
this.implementation.createRegistry(CobblemonRegistryKeys.ELEMENTAL_TYPE, ElementalType.CODEC, ElementalType.NETWORK_CODEC)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,14 +13,12 @@ import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
|
||||
import com.mojang.brigadier.arguments.ArgumentType
|
||||
import com.mojang.serialization.Codec
|
||||
import kotlin.reflect.KClass
|
||||
import net.minecraft.advancement.criterion.Criterion
|
||||
import net.minecraft.command.argument.serialize.ArgumentSerializer
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.network.listener.ClientPlayPacketListener
|
||||
import net.minecraft.network.packet.Packet
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.registry.RegistryKey
|
||||
import net.minecraft.registry.tag.TagKey
|
||||
import net.minecraft.resource.ResourceManager
|
||||
@@ -33,7 +31,6 @@ import net.minecraft.world.GameRules
|
||||
import net.minecraft.world.biome.Biome
|
||||
import net.minecraft.world.gen.GenerationStep
|
||||
import net.minecraft.world.gen.feature.PlacedFeature
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
interface CobblemonImplementation {
|
||||
val modAPI: ModAPI
|
||||
@@ -172,34 +169,6 @@ interface CobblemonImplementation {
|
||||
* @param manager The [ResourceManager] to reload from.
|
||||
*/
|
||||
fun <T> reloadJsonRegistry(registry: JsonDataRegistry<T>, manager: ResourceManager): HashMap<Identifier, T>
|
||||
/**
|
||||
* Queue the creation of a registry in the implementation.
|
||||
* This registry will not be immediately available for access.
|
||||
*
|
||||
* @param T The type of the registry entries.
|
||||
* @param registryKey The [RegistryKey] of this registry.
|
||||
* @param codec The [Codec] used for this registry entries to be parsed on the server.
|
||||
* @param networkCodec The [Codec] used when the client is synchronizing this registry from the server. If this is null the client will not require the registry aka not load any data.
|
||||
*
|
||||
* @see getRegistry
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
fun <T> createRegistry(registryKey: RegistryKey<Registry<T>>, codec: Codec<T>, networkCodec: Codec<T>? = null)
|
||||
|
||||
/**
|
||||
* Fetches a registry.
|
||||
* This is intended for Cobblemon registries but can be used for any.
|
||||
*
|
||||
* @param T The type of the registry.
|
||||
* @param registryKey The [RegistryKey] of the registry being fetched.
|
||||
* @return The registry if present.
|
||||
*
|
||||
* @throws Exception If the registry doesn't exist or isn't loaded yet.
|
||||
* @see createRegistry
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
fun <T> getRegistry(registryKey: RegistryKey<Registry<T>>): Registry<T>
|
||||
|
||||
}
|
||||
|
||||
enum class ModAPI {
|
||||
|
||||
@@ -55,8 +55,11 @@ import com.cobblemon.mod.common.net.messages.client.battle.*
|
||||
import com.cobblemon.mod.common.net.messages.client.callback.OpenMoveCallbackPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyCallbackPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyMoveCallbackPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.*
|
||||
import com.cobblemon.mod.common.net.messages.client.data.AbilityRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.BerryRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.MovesRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.PropertiesCompletionRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.SpeciesRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.UnlockReloadPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticlePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.ClosePasturePacket
|
||||
|
||||
+1
-6
@@ -8,7 +8,6 @@
|
||||
|
||||
package com.cobblemon.mod.common.advancement.criterion
|
||||
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.google.gson.JsonObject
|
||||
import net.minecraft.predicate.entity.LootContextPredicate
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
@@ -31,11 +30,7 @@ class CaughtPokemonCriterionCondition(id: Identifier, predicate: LootContextPred
|
||||
|
||||
override fun fromJson(json: JsonObject) {
|
||||
super.fromJson(json)
|
||||
var stored = json.get("type")?.asString
|
||||
if (stored != null && stored != "any") {
|
||||
stored = stored.asIdentifierDefaultingNamespace().toString()
|
||||
}
|
||||
type = stored ?: "any"
|
||||
type = json.get("type")?.asString ?: "any"
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayerEntity, context: CountablePokemonTypeContext): Boolean {
|
||||
|
||||
@@ -12,8 +12,6 @@ import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.api.PrioritizedList
|
||||
import com.cobblemon.mod.common.api.Priority
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.DataResult
|
||||
|
||||
/**
|
||||
* A pool of potential abilities, as a [PrioritizedList]. The added logic of this subclass
|
||||
@@ -37,22 +35,4 @@ open class AbilityPool : PrioritizedList<PotentialAbility>() {
|
||||
Exception().printStackTrace()
|
||||
return Abilities.first().create() to Priority.LOWEST
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmField
|
||||
val CODEC: Codec<AbilityPool> = Codec.list(Codec.STRING)
|
||||
.comapFlatMap(
|
||||
{ raw ->
|
||||
val pool = AbilityPool()
|
||||
if (raw.isEmpty()) {
|
||||
return@comapFlatMap DataResult.error { "Cannot create ability pool from an empty list" }
|
||||
}
|
||||
raw.forEach { }
|
||||
DataResult.success(pool)
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,12 +10,9 @@ package com.cobblemon.mod.common.api.abilities
|
||||
|
||||
import com.cobblemon.mod.common.api.Priority
|
||||
import com.google.gson.JsonElement
|
||||
import com.mojang.serialization.Codec
|
||||
|
||||
interface PotentialAbilityType<T : PotentialAbility> {
|
||||
fun parseFromJSON(element: JsonElement): T?
|
||||
|
||||
fun codec(): Codec<out PotentialAbilityType<*>>
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,10 +45,6 @@ object CommonAbilityType : PotentialAbilityType<CommonAbility> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun codec(): Codec<out PotentialAbilityType<*>> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
|
||||
open class CommonAbility(override val template: AbilityTemplate) : PotentialAbility {
|
||||
|
||||
@@ -10,8 +10,6 @@ package com.cobblemon.mod.common.api.ai
|
||||
|
||||
import com.cobblemon.mod.common.api.serialization.StringIdentifiedObjectAdapter
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.DataResult
|
||||
import net.minecraft.entity.ai.TargetPredicate
|
||||
import net.minecraft.util.math.Box
|
||||
|
||||
@@ -46,11 +44,6 @@ interface SleepDepth {
|
||||
"normal" to normal
|
||||
)
|
||||
val adapter = StringIdentifiedObjectAdapter { depths[it] ?: throw IllegalArgumentException("Unknown sleep depth: $it") }
|
||||
|
||||
val CODEC: Codec<SleepDepth> = Codec.STRING.flatXmap(
|
||||
{ string -> depths[string]?.let { DataResult.success(it) } ?: DataResult.error { "Cannot find a SleepDepth with the ID $string" } },
|
||||
{ depth -> depths.entries.firstOrNull { it.value == depth }?.let { DataResult.success(it.key) } ?: DataResult.error { "Cannot resolve a ID for the SleepDepth $depth" } }
|
||||
)
|
||||
}
|
||||
|
||||
fun canSleep(pokemonEntity: PokemonEntity): Boolean
|
||||
|
||||
-20
@@ -1,20 +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.conditional
|
||||
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
class RegistryElementCondition<T>(val element: T, private val source: Identifier) : RegistryLikeCondition<T> {
|
||||
|
||||
override fun fits(value: T, registry: Registry<T>): Boolean = value == this.element
|
||||
|
||||
override fun pretty(): String = this.source.toString()
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.conditional
|
||||
|
||||
import com.google.gson.JsonDeserializationContext
|
||||
import com.google.gson.JsonDeserializer
|
||||
import com.google.gson.JsonElement
|
||||
import java.lang.reflect.Type
|
||||
|
||||
/**
|
||||
* Adapter for [RegistryLikeCondition]s. Its logic is that the implementation of this adapter must
|
||||
* provide a list of resolvers, and the deserializer will find the first resolver that returns a non-null
|
||||
* value for the [JsonElement].
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since July 17th, 2022
|
||||
*/
|
||||
interface RegistryLikeAdapter<B> : JsonDeserializer<RegistryLikeCondition<B>> {
|
||||
val registryLikeConditions: MutableList<(JsonElement) -> RegistryLikeCondition<B>?>
|
||||
|
||||
override fun deserialize(json: JsonElement, type: Type, ctx: JsonDeserializationContext): RegistryLikeCondition<B> {
|
||||
return registryLikeConditions.firstNotNullOfOrNull { it(json) }
|
||||
?: throw IllegalArgumentException("Unable to deserialize $json")
|
||||
}
|
||||
}
|
||||
+2
-43
@@ -8,11 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.conditional
|
||||
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.DataResult
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.registry.tag.TagKey
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* A condition which applies to an entry in some [Registry].
|
||||
@@ -20,43 +16,6 @@ import net.minecraft.util.Identifier
|
||||
* @author Hiroku
|
||||
* @since July 16th, 2022
|
||||
*/
|
||||
sealed interface RegistryLikeCondition<T> {
|
||||
|
||||
/**
|
||||
* Checks if a given [value] matches this condition.
|
||||
*
|
||||
* @param value The value being matched against this condition.
|
||||
* @param registry The [Registry] of type [T] being queried.
|
||||
* @return If the condition is fulfilled.
|
||||
*/
|
||||
fun fits(value: T, registry: Registry<T>): Boolean
|
||||
|
||||
/**
|
||||
* Generates a string like human-friendly representation used by the Codec when serializing.
|
||||
*
|
||||
* @return The string like human-friendly representation.
|
||||
*/
|
||||
fun pretty(): String
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
fun <T> createCodec(registryAccessor: () -> Registry<T>): Codec<RegistryLikeCondition<T>> = Codec.STRING.comapFlatMap(
|
||||
{ string ->
|
||||
val registry = registryAccessor.invoke()
|
||||
val isTag = string.startsWith("#")
|
||||
val rawIdentifier = if (isTag) string.substringAfter("#") else string
|
||||
val identifier = Identifier.tryParse(rawIdentifier) ?: return@comapFlatMap DataResult.error { "Cannot resolve identifier/tag from the string $string" }
|
||||
if (isTag) {
|
||||
val tag = TagKey.of(registry.key, identifier)
|
||||
return@comapFlatMap DataResult.success(RegistryTagCondition(tag))
|
||||
}
|
||||
val element = registry.get(identifier) ?: return@comapFlatMap DataResult.error { "Cannot find an element in registry ${registry.key.value} with the ID $identifier" }
|
||||
return@comapFlatMap DataResult.success(RegistryElementCondition(element, identifier))
|
||||
},
|
||||
{ it.pretty() }
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
interface RegistryLikeCondition<T> {
|
||||
fun fits(t: T, registry: Registry<T>): Boolean
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.conditional
|
||||
|
||||
import com.google.gson.JsonElement
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* A condition for some registry type which asserts that the entry must have the given [Identifier].
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since July 16th, 2022
|
||||
*/
|
||||
open class RegistryLikeIdentifierCondition<T>(val identifier: Identifier) : RegistryLikeCondition<T> {
|
||||
companion object {
|
||||
fun <T> resolver(
|
||||
constructor: (Identifier) -> RegistryLikeIdentifierCondition<T>
|
||||
): (JsonElement) -> RegistryLikeIdentifierCondition<T>? = { constructor(Identifier(it.asString)) }
|
||||
}
|
||||
override fun fits(t: T, registry: Registry<T>) = registry.getId(t) == identifier
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.conditional
|
||||
|
||||
import com.google.gson.JsonElement
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.registry.RegistryKey
|
||||
import net.minecraft.registry.tag.TagKey
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* A condition for some registry type that asserts that the entry must be inside the given [TagKey]. This is presented
|
||||
* in JSONs as an identifier prefixed with a hash.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since July 16th, 2022
|
||||
*/
|
||||
open class RegistryLikeTagCondition<T>(val tag: TagKey<T>) : RegistryLikeCondition<T> {
|
||||
|
||||
companion object {
|
||||
const val PREFIX = "#"
|
||||
fun <T> resolver(
|
||||
registryKey: RegistryKey<Registry<T>>,
|
||||
constructor: (TagKey<T>) -> RegistryLikeTagCondition<T>
|
||||
): (JsonElement) -> RegistryLikeTagCondition<T>? = {
|
||||
val firstSymbol = it.asString.substring(0, 1)
|
||||
if (firstSymbol == PREFIX) {
|
||||
val identifier = Identifier(it.asString.substring(1))
|
||||
constructor(TagKey.of(registryKey, identifier))
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun fits(t: T, registry: Registry<T>): Boolean {
|
||||
// val registryHasTag = registry.containsTag(tag)
|
||||
// if (!registryHasTag) {
|
||||
//// LOGGER.warn("No tag in registry: ${tag.id}")
|
||||
// return false
|
||||
// }
|
||||
|
||||
return registry.getKey(t)
|
||||
.flatMap(registry::getEntry)
|
||||
.map { entry -> entry.isIn(tag) }
|
||||
.orElse(false)
|
||||
}
|
||||
}
|
||||
-20
@@ -1,20 +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.conditional
|
||||
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.registry.tag.TagKey
|
||||
|
||||
class RegistryTagCondition<T>(val tag: TagKey<T>) : RegistryLikeCondition<T> {
|
||||
|
||||
override fun fits(value: T, registry: Registry<T>): Boolean = registry.getEntry(value).isIn(this.tag)
|
||||
|
||||
override fun pretty(): String = "#${this.tag.id}"
|
||||
|
||||
}
|
||||
@@ -10,11 +10,11 @@ package com.cobblemon.mod.common.api.drop
|
||||
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents.LOOT_DROPPED
|
||||
import com.cobblemon.mod.common.api.events.drops.LootDroppedEvent
|
||||
import kotlin.random.Random
|
||||
import net.minecraft.entity.LivingEntity
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.util.math.Vec3d
|
||||
import kotlin.random.Random
|
||||
|
||||
/**
|
||||
* A table of drops that can produce a list of [DropEntry]. You can produce a drop list from [getDrops] to
|
||||
|
||||
@@ -8,7 +8,11 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.events
|
||||
|
||||
import com.cobblemon.mod.common.api.events.battles.*
|
||||
import com.cobblemon.mod.common.api.events.battles.BattleFaintedEvent
|
||||
import com.cobblemon.mod.common.api.events.battles.BattleFledEvent
|
||||
import com.cobblemon.mod.common.api.events.battles.BattleStartedPostEvent
|
||||
import com.cobblemon.mod.common.api.events.battles.BattleStartedPreEvent
|
||||
import com.cobblemon.mod.common.api.events.battles.BattleVictoryEvent
|
||||
import com.cobblemon.mod.common.api.events.berry.BerryHarvestEvent
|
||||
import com.cobblemon.mod.common.api.events.berry.BerryMutationOfferEvent
|
||||
import com.cobblemon.mod.common.api.events.berry.BerryMutationResultEvent
|
||||
@@ -39,7 +43,6 @@ import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
|
||||
@Suppress("unused")
|
||||
object CobblemonEvents {
|
||||
|
||||
@JvmField
|
||||
@@ -102,7 +105,6 @@ object CobblemonEvents {
|
||||
@JvmField
|
||||
val ENTITY_SPAWN = CancelableObservable<SpawnEvent<*>>()
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@JvmField
|
||||
val POKEMON_ENTITY_SPAWN = ENTITY_SPAWN
|
||||
.pipe(
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.moves
|
||||
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.mojang.serialization.Codec
|
||||
import net.minecraft.text.MutableText
|
||||
import net.minecraft.util.StringIdentifiable
|
||||
|
||||
/**
|
||||
* Represents the damage category of a [MoveTemplate]/[Move].
|
||||
*
|
||||
* @see MoveTemplate
|
||||
* @see Move
|
||||
*/
|
||||
enum class DamageCategory : StringIdentifiable {
|
||||
|
||||
PHYSICAL,
|
||||
SPECIAL,
|
||||
STATUS;
|
||||
|
||||
override fun asString(): String = this.name
|
||||
|
||||
/**
|
||||
* Resolves the display name of this damage category.
|
||||
*
|
||||
* @return The generated text.
|
||||
*/
|
||||
fun displayName(): MutableText = lang("move.category.${this.name.lowercase()}")
|
||||
|
||||
companion object {
|
||||
|
||||
val CODEC: Codec<DamageCategory> = StringIdentifiable.createCodec(DamageCategory::values)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.moves
|
||||
|
||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategory
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.net.IntSize
|
||||
|
||||
@@ -8,15 +8,14 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.moves
|
||||
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistries
|
||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategories
|
||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategory
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.cobblemon.mod.common.battles.MoveTarget
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.text.MutableText
|
||||
import net.minecraft.util.math.random.Random
|
||||
|
||||
/**
|
||||
* This class represents the base of a Move.
|
||||
@@ -49,27 +48,6 @@ open class MoveTemplate(
|
||||
val effectChances: Array<Double>
|
||||
) {
|
||||
|
||||
companion object {
|
||||
fun dummy(name: String) = Dummy(name)
|
||||
|
||||
val CODEC: Codec<MoveTemplate> = RecordCodecBuilder.create { builder ->
|
||||
builder.group(
|
||||
Codec.STRING.fieldOf("name").forGetter(MoveTemplate::name),
|
||||
Codec.INT.fieldOf("num").forGetter(MoveTemplate::num),
|
||||
CobblemonRegistries.ELEMENTAL_TYPE.codec.fieldOf("type").forGetter(MoveTemplate::elementalType),
|
||||
DamageCategory.CODEC.fieldOf("damageCategory").forGetter(MoveTemplate::damageCategory),
|
||||
Codec.DOUBLE.fieldOf("power").forGetter(MoveTemplate::power),
|
||||
MoveTarget.CODEC.fieldOf("target").forGetter(MoveTemplate::target),
|
||||
Codec.DOUBLE.fieldOf("accuracy").forGetter(MoveTemplate::accuracy),
|
||||
Codec.INT.fieldOf("pp").forGetter(MoveTemplate::pp),
|
||||
Codec.INT.fieldOf("priority").forGetter(MoveTemplate::priority),
|
||||
Codec.DOUBLE.fieldOf("critRatio").forGetter(MoveTemplate::critRatio),
|
||||
Codec.list(Codec.DOUBLE).fieldOf("effectChances").xmap({ e -> e.toTypedArray() }, { e -> e.toList() }).forGetter(MoveTemplate::effectChances)
|
||||
).apply(builder, ::MoveTemplate)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
val displayName: MutableText
|
||||
get() = lang("move.$name")
|
||||
val description: MutableText
|
||||
@@ -79,8 +57,8 @@ open class MoveTemplate(
|
||||
class Dummy(name: String) : MoveTemplate(
|
||||
name = name,
|
||||
num = -1,
|
||||
elementalType = CobblemonRegistries.ELEMENTAL_TYPE.getRandom(Random.create()).orElseThrow().value(),
|
||||
damageCategory = DamageCategory.STATUS,
|
||||
elementalType = ElementalTypes.NORMAL,
|
||||
damageCategory = DamageCategories.STATUS,
|
||||
power = 0.0,
|
||||
target = MoveTarget.all,
|
||||
accuracy = 100.0,
|
||||
@@ -90,6 +68,10 @@ open class MoveTemplate(
|
||||
effectChances = emptyArray()
|
||||
)
|
||||
|
||||
companion object {
|
||||
fun dummy(name: String) = Dummy(name)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the Move with full PP
|
||||
*/
|
||||
@@ -110,5 +92,4 @@ open class MoveTemplate(
|
||||
template = this
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,8 +10,9 @@ package com.cobblemon.mod.common.api.moves
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.data.DataRegistry
|
||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategories
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistries
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.cobblemon.mod.common.battles.MoveTarget
|
||||
import com.cobblemon.mod.common.battles.runner.ShowdownService
|
||||
import com.cobblemon.mod.common.net.messages.client.data.MovesRegistrySyncPacket
|
||||
@@ -43,8 +44,8 @@ object Moves : DataRegistry {
|
||||
val id = jsMove.get("id").asString
|
||||
try {
|
||||
val num = jsMove.get("num").asInt
|
||||
val elementalType = CobblemonRegistries.ELEMENTAL_TYPE.first { it.showdownId() == jsMove.get("type").asString }
|
||||
val damageCategory = DamageCategory.valueOf(jsMove.get("category").asString.uppercase())
|
||||
val elementalType = ElementalTypes.getOrException(jsMove.get("type").asString)
|
||||
val damageCategory = DamageCategories.getOrException(jsMove.get("category").asString)
|
||||
val power = jsMove.get("basePower").asDouble
|
||||
val target = MoveTarget.fromShowdownId(jsMove.get("target").asString)
|
||||
// If not a double it's always true
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.moves.adapters
|
||||
|
||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategories
|
||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategory
|
||||
import com.google.gson.JsonDeserializationContext
|
||||
import com.google.gson.JsonDeserializer
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonPrimitive
|
||||
import com.google.gson.JsonSerializationContext
|
||||
import com.google.gson.JsonSerializer
|
||||
import java.lang.reflect.Type
|
||||
|
||||
object DamageCategoryAdapter: JsonSerializer<DamageCategory>, JsonDeserializer<DamageCategory> {
|
||||
|
||||
override fun serialize(src: DamageCategory, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
|
||||
return JsonPrimitive(src.name)
|
||||
}
|
||||
|
||||
override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): DamageCategory {
|
||||
return DamageCategories.getOrException(json.asString)
|
||||
}
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.categories
|
||||
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
object DamageCategories {
|
||||
private val allCategories = mutableListOf<DamageCategory>()
|
||||
|
||||
val PHYSICAL = register(
|
||||
name = "physical",
|
||||
displayName = Text.translatable("cobblemon.move.category.physical"),
|
||||
textureXMultiplier = 0
|
||||
)
|
||||
val SPECIAL = register(
|
||||
name = "special",
|
||||
displayName = Text.translatable("cobblemon.move.category.special"),
|
||||
textureXMultiplier = 1
|
||||
)
|
||||
val STATUS = register(
|
||||
name = "status",
|
||||
displayName = Text.translatable("cobblemon.move.category.status"),
|
||||
textureXMultiplier = 2
|
||||
)
|
||||
|
||||
fun register(
|
||||
name: String,
|
||||
displayName: Text,
|
||||
resourceLocation: Identifier = cobblemonResource("textures/gui/categories.png"),
|
||||
textureXMultiplier: Int
|
||||
): DamageCategory {
|
||||
return DamageCategory(
|
||||
name = name,
|
||||
displayName = displayName,
|
||||
textureXMultiplier = textureXMultiplier,
|
||||
resourceLocation = resourceLocation
|
||||
).also {
|
||||
allCategories.add(it)
|
||||
}
|
||||
}
|
||||
|
||||
fun register(damageCategory: DamageCategory): DamageCategory {
|
||||
allCategories.add(damageCategory)
|
||||
return damageCategory
|
||||
}
|
||||
|
||||
fun get(name: String): DamageCategory? {
|
||||
return allCategories.firstOrNull { cat -> cat.name.equals(name, ignoreCase = true) }
|
||||
}
|
||||
|
||||
fun getOrException(name: String): DamageCategory {
|
||||
return allCategories.first { cat -> cat.name.equals(name, ignoreCase = true) }
|
||||
}
|
||||
|
||||
fun count() = allCategories.size
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.categories
|
||||
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* Representing a DamageCategory from the Pokemon Game
|
||||
*
|
||||
* @param name: The English name used to load / find it (spaces -> _)
|
||||
* @param displayName: A Component used to display the name, normally a TranslatableText
|
||||
* @param resourceLocation: The location of the resource used in the GUI
|
||||
*/
|
||||
class DamageCategory(
|
||||
val name: String,
|
||||
val displayName: Text,
|
||||
val textureXMultiplier: Int,
|
||||
val resourceLocation: Identifier = cobblemonResource("textures/gui/categories.png")
|
||||
) {
|
||||
}
|
||||
@@ -24,7 +24,7 @@ import com.cobblemon.mod.common.api.pokemon.labels.CobblemonPokemonLabels
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.api.types.CobblemonElementalTypeTags
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.cobblemon.mod.common.pokeball.PokeBall
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.Gson
|
||||
@@ -136,13 +136,13 @@ object PokeBalls : JsonDataRegistry<PokeBall> {
|
||||
createDefault("fast_ball", BaseStatModifier(Stats.SPEED, { it >= 100 }, 4F))
|
||||
createDefault("level_ball", CatchRateModifiers.LEVEL)
|
||||
// ToDo we will need fishing context here once fishing is implemented for a multiplier
|
||||
createDefault("lure_ball", CatchRateModifiers.typeBoosting(2F, CobblemonElementalTypeTags.LURE_BALL_BOOSTING))
|
||||
createDefault("lure_ball", CatchRateModifiers.typeBoosting(2F, ElementalTypes.WATER))
|
||||
createDefault("heavy_ball", CatchRateModifiers.WEIGHT_BASED)
|
||||
createDefault("love_ball", CatchRateModifiers.LOVE)
|
||||
createDefault("friend_ball", effects = listOf(CaptureEffects.friendshipSetter(150)))
|
||||
createDefault("moon_ball", CatchRateModifiers.MOON_PHASES)
|
||||
createDefault("sport_ball", MultiplierModifier(1.5F))
|
||||
createDefault("net_ball", CatchRateModifiers.typeBoosting(3F, CobblemonElementalTypeTags.NET_BALL_BOOSTING))
|
||||
createDefault("net_ball", CatchRateModifiers.typeBoosting(3F, ElementalTypes.BUG, ElementalTypes.WATER))
|
||||
createDefault("dive_ball", CatchRateModifiers.SUBMERGED_IN_WATER, waterDragValue = 0.99F)
|
||||
createDefault("nest_ball", CatchRateModifiers.NEST)
|
||||
// ToDo implement effect once pokedex is implemented, we have a custom multiplier of 2.5 instead of the official pokeball
|
||||
|
||||
+4
-5
@@ -14,8 +14,7 @@ import com.cobblemon.mod.common.api.pokemon.status.Status
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonBiomeTags
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.battles.BattleRegistry
|
||||
import com.cobblemon.mod.common.api.pokemon.gender.Gender
|
||||
import net.minecraft.registry.tag.TagKey
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
|
||||
/**
|
||||
* A collection of some default usages of [CatchRateModifier]s.
|
||||
@@ -140,11 +139,11 @@ object CatchRateModifiers {
|
||||
* Used by [PokeBalls.NET_BALL].
|
||||
* Boosts the catch rate if the target is of the given types.
|
||||
*
|
||||
* @param multiplier The multiplier to be applied if the target has any of the accepted [typeTag].
|
||||
* @param typeTag The [ElementalType] [TagKey] that will trigger the multiplier.
|
||||
* @param multiplier The multiplier to be applied if the target has any of the accepted [types].
|
||||
* @param types The [ElementalType]s that will trigger the multiplier.
|
||||
* @return The multiplier modifier.
|
||||
*/
|
||||
fun typeBoosting(multiplier: Float, typeTag: TagKey<ElementalType>): CatchRateModifier = MultiplierModifier(multiplier) { _, pokemon -> pokemon.types.any { type -> type.isIn(typeTag) } }
|
||||
fun typeBoosting(multiplier: Float, vararg types: ElementalType): CatchRateModifier = MultiplierModifier(multiplier) { _, pokemon -> pokemon.types.any { type -> types.contains(type) } }
|
||||
|
||||
/**
|
||||
* Used by [PokeBalls.DREAM_BALL].
|
||||
|
||||
@@ -12,14 +12,13 @@ import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.abilities.Abilities
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.api.pokemon.aspect.AspectProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.gender.Gender
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistries
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.EVs
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.pokemon.IVs
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.RenderablePokemon
|
||||
@@ -31,12 +30,10 @@ import com.cobblemon.mod.common.util.splitMap
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import kotlin.random.Random
|
||||
import com.mojang.serialization.Codec
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.nbt.NbtElement
|
||||
import net.minecraft.nbt.NbtList
|
||||
import net.minecraft.nbt.NbtString
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.text.MutableText
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
@@ -94,7 +91,7 @@ open class PokemonProperties {
|
||||
props.ability = parseStringOfRegistry(keyPairs, listOf("ability")) { Abilities.get(it)?.name }
|
||||
props.status = parseStringOfRegistry(keyPairs, listOf("status")) { (Statuses.getStatus(it) ?: Statuses.getStatus(it.asIdentifierDefaultingNamespace()))?.showdownName }
|
||||
props.nickname = parseText(keyPairs, listOf("nickname", "nick"))
|
||||
props.teraType = parseRegistryValue(CobblemonRegistries.ELEMENTAL_TYPE, keyPairs, "tera_type", "tera")
|
||||
props.teraType = parseStringOfRegistry(keyPairs, listOf("tera_type", "tera")) { ElementalTypes.get(it)?.name }
|
||||
props.dmaxLevel = parseIntProperty(keyPairs, listOf("dmax_level", "dmax"))?.coerceIn(0, Cobblemon.config.maxDynamaxLevel)
|
||||
props.gmaxFactor = parseBooleanProperty(keyPairs, listOf("gmax_factor", "gmax"))
|
||||
props.tradeable = parseBooleanProperty(keyPairs, listOf("tradeable", "tradable"))
|
||||
@@ -159,7 +156,7 @@ open class PokemonProperties {
|
||||
}
|
||||
|
||||
private fun parseSpeciesIdentifier(keyPairs: MutableList<Pair<String, String?>>): String? {
|
||||
fun cleanSpeciesName(string: String) = string.lowercase().replace("[^a-z0-9:]".toRegex(), "")
|
||||
fun cleanSpeciesName(string: String) = string.lowercase().replace("[^a-z0-9_:]".toRegex(), "")
|
||||
val matched = getMatchedKeyPair(keyPairs, listOf("species"))
|
||||
if (matched != null) {
|
||||
val value = matched.second?.let(::cleanSpeciesName) ?: return null
|
||||
@@ -199,17 +196,6 @@ open class PokemonProperties {
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> parseRegistryValue(registry: Registry<T>, keyPairs: MutableList<Pair<String, String?>>, vararg labels: String): T? {
|
||||
val matchingKeyPair = getMatchedKeyPair(keyPairs, labels.asIterable()) ?: return null
|
||||
val rawId = matchingKeyPair.second ?: return null
|
||||
return try {
|
||||
val id = Identifier(rawId)
|
||||
registry.get(id)
|
||||
} catch (_: InvalidIdentifierException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseForm(keyPairs: MutableList<Pair<String, String?>>): String? {
|
||||
val matchingKeyPair = getMatchedKeyPair(keyPairs, listOf("form")) ?: return null
|
||||
keyPairs.remove(matchingKeyPair)
|
||||
@@ -254,9 +240,6 @@ open class PokemonProperties {
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
val CODEC: Codec<PokemonProperties> = Codec.STRING.xmap(PokemonProperties::parse, PokemonProperties::asString)
|
||||
|
||||
}
|
||||
|
||||
var originalString: String = ""
|
||||
@@ -273,7 +256,7 @@ open class PokemonProperties {
|
||||
var ability: String? = null
|
||||
var aspects: Set<String> = emptySet()
|
||||
var status: String? = null
|
||||
var teraType: ElementalType? = null
|
||||
var teraType: String? = null
|
||||
var dmaxLevel: Int? = null
|
||||
var gmaxFactor: Boolean? = null
|
||||
var tradeable: Boolean? = null
|
||||
@@ -326,7 +309,7 @@ open class PokemonProperties {
|
||||
pokemon.setEV(stat.key, stat.value)
|
||||
}
|
||||
}
|
||||
teraType?.let { type -> pokemon.teraType = type }
|
||||
teraType?.let { ElementalTypes.get(it)?.let { type -> pokemon.teraType = type } }
|
||||
dmaxLevel?.let { pokemon.dmaxLevel = it }
|
||||
gmaxFactor?.let { pokemon.gmaxFactor = it }
|
||||
tradeable?.let { pokemon.tradeable = it }
|
||||
@@ -366,7 +349,7 @@ open class PokemonProperties {
|
||||
pokemonEntity.pokemon.setEV(stat.key, stat.value)
|
||||
}
|
||||
}
|
||||
teraType?.let { type -> pokemonEntity.pokemon.teraType = type }
|
||||
teraType?.let { ElementalTypes.get(it)?.let { type -> pokemonEntity.pokemon.teraType = type } }
|
||||
dmaxLevel?.let { pokemonEntity.pokemon.dmaxLevel = it }
|
||||
gmaxFactor?.let { pokemonEntity.pokemon.gmaxFactor = it }
|
||||
tradeable?.let { pokemonEntity.pokemon.tradeable = it }
|
||||
@@ -404,7 +387,7 @@ open class PokemonProperties {
|
||||
evs?.forEach{ stat ->
|
||||
if (stat.value != pokemon.evs[stat.key]) { return false }
|
||||
}
|
||||
teraType?.takeIf { it != pokemon.teraType }?.let { return false }
|
||||
teraType?.takeIf { it != pokemon.teraType.name }?.let { return false }
|
||||
dmaxLevel?.takeIf { it != pokemon.dmaxLevel }?.let { return false }
|
||||
gmaxFactor?.takeIf { it != pokemon.gmaxFactor }?.let { return false }
|
||||
tradeable?.takeIf { it != pokemon.tradeable }?.let { return false }
|
||||
@@ -425,7 +408,7 @@ open class PokemonProperties {
|
||||
if (pokemonEntity.pokemon.species != species) {
|
||||
return false
|
||||
}
|
||||
} catch (_: InvalidIdentifierException) {}
|
||||
} catch (e: InvalidIdentifierException) {}
|
||||
}
|
||||
nickname?.takeIf { it != pokemonEntity.pokemon.nickname }?.let { return false }
|
||||
form?.takeIf { !it.equals(pokemonEntity.pokemon.form.name, true) }?.let { return false }
|
||||
@@ -440,7 +423,7 @@ open class PokemonProperties {
|
||||
evs?.forEach{ stat ->
|
||||
if (stat.value != pokemonEntity.pokemon.evs[stat.key]) { return false }
|
||||
}
|
||||
teraType?.takeIf { it != pokemonEntity.pokemon.teraType }?.let { return false }
|
||||
teraType?.takeIf { it != pokemonEntity.pokemon.teraType.name }?.let { return false }
|
||||
dmaxLevel?.takeIf { it != pokemonEntity.pokemon.dmaxLevel }?.let { return false }
|
||||
gmaxFactor?.takeIf { it != pokemonEntity.pokemon.gmaxFactor }?.let { return false }
|
||||
tradeable?.takeIf { it != pokemonEntity.pokemon.tradeable }?.let { return false }
|
||||
@@ -461,7 +444,7 @@ open class PokemonProperties {
|
||||
if (properties.species != species.toString()) {
|
||||
return false
|
||||
}
|
||||
} catch (_: InvalidIdentifierException) {}
|
||||
} catch (e: InvalidIdentifierException) {}
|
||||
}
|
||||
nickname?.takeIf { it != properties.nickname }?.let { return false }
|
||||
form?.takeIf { !it.equals(properties.form, true) }?.let { return false }
|
||||
@@ -503,9 +486,8 @@ open class PokemonProperties {
|
||||
fun roll(pokemon: Pokemon) {
|
||||
val baseTypes = pokemon.species.types.toList()
|
||||
if (this.shiny == null) pokemon.shiny = Cobblemon.config.shinyRate.checkRate()
|
||||
if (this.gmaxFactor == null) pokemon.gmaxFactor = Cobblemon.config.gigantamaxFactorRate.checkRate()
|
||||
if (this.teraType == null) pokemon.teraType =
|
||||
if (Cobblemon.config.teraTypeRate.checkRate()) CobblemonRegistries.ELEMENTAL_TYPE.filter { !baseTypes.contains(it) }.random()
|
||||
if (Cobblemon.config.teraTypeRate.checkRate()) ElementalTypes.all().filter { !baseTypes.contains(it) }.random()
|
||||
else baseTypes.random()
|
||||
}
|
||||
|
||||
@@ -532,7 +514,7 @@ open class PokemonProperties {
|
||||
status?.let { nbt.putString(DataKeys.POKEMON_STATUS_NAME, it) }
|
||||
ivs?.let { nbt.put(DataKeys.POKEMON_IVS, it.saveToNBT(NbtCompound())) }
|
||||
evs?.let { nbt.put(DataKeys.POKEMON_EVS, it.saveToNBT(NbtCompound())) }
|
||||
teraType?.let { nbt.putString(DataKeys.POKEMON_TERA_TYPE, it.id().toString()) }
|
||||
teraType?.let { nbt.putString(DataKeys.POKEMON_TERA_TYPE, it) }
|
||||
dmaxLevel?.let { nbt.putInt(DataKeys.POKEMON_DMAX_LEVEL, it) }
|
||||
gmaxFactor?.let { nbt.putBoolean(DataKeys.POKEMON_GMAX_FACTOR, it) }
|
||||
tradeable?.let { nbt.putBoolean(DataKeys.POKEMON_TRADEABLE, it) }
|
||||
@@ -557,7 +539,7 @@ open class PokemonProperties {
|
||||
status = if (tag.contains(DataKeys.POKEMON_STATUS_NAME)) tag.getString(DataKeys.POKEMON_STATUS_NAME) else null
|
||||
ivs = if (tag.contains(DataKeys.POKEMON_IVS)) ivs?.loadFromNBT(tag.getCompound(DataKeys.POKEMON_IVS)) as IVs? else null
|
||||
evs = if (tag.contains(DataKeys.POKEMON_EVS)) evs?.loadFromNBT(tag.getCompound(DataKeys.POKEMON_EVS)) as EVs? else null
|
||||
teraType = if (tag.contains(DataKeys.POKEMON_TERA_TYPE)) CobblemonRegistries.ELEMENTAL_TYPE.get(Identifier(tag.getString(DataKeys.POKEMON_TERA_TYPE))) else null
|
||||
teraType = if (tag.contains(DataKeys.POKEMON_TERA_TYPE)) tag.getString(DataKeys.POKEMON_TERA_TYPE) else null
|
||||
dmaxLevel = if (tag.contains(DataKeys.POKEMON_DMAX_LEVEL)) tag.getInt(DataKeys.POKEMON_DMAX_LEVEL) else null
|
||||
gmaxFactor = if (tag.contains(DataKeys.POKEMON_GMAX_FACTOR)) tag.getBoolean(DataKeys.POKEMON_GMAX_FACTOR) else null
|
||||
tradeable = if (tag.contains(DataKeys.POKEMON_TRADEABLE)) tag.getBoolean(DataKeys.POKEMON_TRADEABLE) else null
|
||||
@@ -584,7 +566,7 @@ open class PokemonProperties {
|
||||
status?.let { json.addProperty(DataKeys.POKEMON_STATUS_NAME, it) }
|
||||
ivs?.let { json.add(DataKeys.POKEMON_IVS, it.saveToJSON(JsonObject())) }
|
||||
evs?.let { json.add(DataKeys.POKEMON_EVS, it.saveToJSON(JsonObject())) }
|
||||
teraType?.let { json.addProperty(DataKeys.POKEMON_TERA_TYPE, it.id().toString()) }
|
||||
teraType?.let { json.addProperty(DataKeys.POKEMON_TERA_TYPE, it) }
|
||||
dmaxLevel?.let { json.addProperty(DataKeys.POKEMON_DMAX_LEVEL, it) }
|
||||
gmaxFactor?.let { json.addProperty(DataKeys.POKEMON_GMAX_FACTOR, it) }
|
||||
tradeable?.let { json.addProperty(DataKeys.POKEMON_TRADEABLE, it) }
|
||||
@@ -610,9 +592,7 @@ open class PokemonProperties {
|
||||
status = json.get(DataKeys.POKEMON_STATUS_NAME)?.asString
|
||||
ivs?.loadFromJSON(json.getAsJsonObject(DataKeys.POKEMON_IVS))
|
||||
evs?.loadFromJSON(json.getAsJsonObject(DataKeys.POKEMON_EVS))
|
||||
teraType = json.get(DataKeys.POKEMON_TERA_TYPE)?.asString?.let { CobblemonRegistries.ELEMENTAL_TYPE.get(
|
||||
Identifier(it)
|
||||
) }
|
||||
teraType = json.get(DataKeys.POKEMON_TERA_TYPE)?.asString
|
||||
dmaxLevel = json.get(DataKeys.POKEMON_DMAX_LEVEL)?.asInt
|
||||
gmaxFactor = json.get(DataKeys.POKEMON_GMAX_FACTOR)?.asBoolean
|
||||
tradeable = json.get(DataKeys.POKEMON_TRADEABLE)?.asBoolean
|
||||
@@ -642,7 +622,7 @@ open class PokemonProperties {
|
||||
evs?.forEach{ stat ->
|
||||
pieces.add("${stat.key}_ev=${stat.value}")
|
||||
}
|
||||
teraType?.let { pieces.add("tera_type=${it.id()}") }
|
||||
teraType?.let { pieces.add("tera_type=$it") }
|
||||
dmaxLevel?.let { pieces.add("dmax_level=$it") }
|
||||
gmaxFactor?.let { pieces.add("gmax_factor=$it") }
|
||||
tradeable?.let { pieces.add("tradeable=$it") }
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.cobblemon.mod.common.api.pokemon.effect.ShoulderEffect
|
||||
import com.cobblemon.mod.common.api.pokemon.effect.adapter.ShoulderEffectAdapter
|
||||
import com.cobblemon.mod.common.api.pokemon.egg.EggGroup
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.PreEvolution
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.requirement.EvolutionRequirement
|
||||
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceGroup
|
||||
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceGroupAdapter
|
||||
@@ -37,14 +38,14 @@ import com.cobblemon.mod.common.net.messages.client.data.SpeciesRegistrySyncPack
|
||||
import com.cobblemon.mod.common.pokemon.FormData
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.cobblemon.mod.common.pokemon.SpeciesAdditions
|
||||
import com.cobblemon.mod.common.pokemon.evolution.adapters.CobblemonEvolutionAdapter
|
||||
import com.cobblemon.mod.common.pokemon.evolution.adapters.CobblemonPreEvolutionAdapter
|
||||
import com.cobblemon.mod.common.pokemon.evolution.adapters.CobblemonRequirementAdapter
|
||||
import com.cobblemon.mod.common.pokemon.evolution.adapters.NbtItemPredicateAdapter
|
||||
import com.cobblemon.mod.common.pokemon.evolution.predicate.NbtItemPredicate
|
||||
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
|
||||
import com.cobblemon.mod.common.util.adapters.*
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.codec.toTypeAdapter
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import com.google.common.collect.HashBasedTable
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
@@ -55,7 +56,6 @@ import net.minecraft.entity.effect.StatusEffect
|
||||
import net.minecraft.item.Item
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.registry.Registries
|
||||
import net.minecraft.registry.RegistryKeys
|
||||
import net.minecraft.resource.ResourceType
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
@@ -76,8 +76,11 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
.registerTypeAdapter(ExperienceGroup::class.java, ExperienceGroupAdapter)
|
||||
.registerTypeAdapter(EntityDimensions::class.java, EntityDimensionsAdapter)
|
||||
.registerTypeAdapter(Learnset::class.java, LearnsetAdapter)
|
||||
.registerTypeAdapter(Evolution::class.java, CobblemonEvolutionAdapter)
|
||||
.registerTypeAdapter(Box::class.java, BoxAdapter)
|
||||
.registerTypeAdapter(AbilityPool::class.java, AbilityPoolAdapter)
|
||||
.registerTypeAdapter(EvolutionRequirement::class.java, CobblemonRequirementAdapter)
|
||||
.registerTypeAdapter(PreEvolution::class.java, CobblemonPreEvolutionAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(Set::class.java, Evolution::class.java).type, LazySetAdapter(Evolution::class))
|
||||
.registerTypeAdapter(IntRange::class.java, IntRangeAdapter)
|
||||
.registerTypeAdapter(PokemonProperties::class.java, pokemonPropertiesShortAdapter)
|
||||
@@ -87,9 +90,9 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
.registerTypeAdapter(SleepDepth::class.java, SleepDepth.adapter)
|
||||
.registerTypeAdapter(DropEntry::class.java, DropEntryAdapter)
|
||||
.registerTypeAdapter(NbtCompound::class.java, NbtCompoundAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Biome::class.java).type, RegistryLikeCondition.createCodec { server()!!.registryManager.get(RegistryKeys.BIOME) }.toTypeAdapter())
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Block::class.java).type, RegistryLikeCondition.createCodec { Registries.BLOCK }.toTypeAdapter())
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Item::class.java).type, RegistryLikeCondition.createCodec { Registries.ITEM }.toTypeAdapter())
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Biome::class.java).type, BiomeLikeConditionAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Block::class.java).type, BlockLikeConditionAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Item::class.java).type, ItemLikeConditionAdapter)
|
||||
.registerTypeAdapter(EggGroup::class.java, EggGroupAdapter)
|
||||
.registerTypeAdapter(StatusEffect::class.java, RegistryElementAdapter<StatusEffect> { Registries.STATUS_EFFECT })
|
||||
.registerTypeAdapter(NbtItemPredicate::class.java, NbtItemPredicateAdapter)
|
||||
@@ -208,7 +211,7 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
"H" to "No Ability",
|
||||
"S" to "No Ability"
|
||||
)
|
||||
val types = (form?.types ?: species.types).map { it.showdownId() }
|
||||
val types = (form?.types ?: species.types).map { it.name.replaceFirstChar(Char::uppercase) }
|
||||
val preevo: String? = (form?.preEvolution ?: species.preEvolution)?.let { if (it.form == it.species.standardForm) createShowdownName(it.species) else "${createShowdownName(it.species)}-${it.form.name}" }
|
||||
// For the context of battles the content here doesn't matter whatsoever and due to how PokemonProperties work we can't guarantee an actual specific species is defined.
|
||||
val evos = if ((form?.evolutions ?: species.evolutions).isEmpty()) emptyList() else arrayListOf("")
|
||||
|
||||
@@ -8,9 +8,6 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.egg
|
||||
|
||||
import com.mojang.serialization.Codec
|
||||
import net.minecraft.util.StringIdentifiable
|
||||
|
||||
/**
|
||||
* These represent categories which determine which Pokémon are able to interbreed.
|
||||
*
|
||||
@@ -18,7 +15,7 @@ import net.minecraft.util.StringIdentifiable
|
||||
*
|
||||
* @property showdownID used for data synchronization with Showdown data format.
|
||||
*/
|
||||
enum class EggGroup(internal val showdownID: String) : StringIdentifiable {
|
||||
enum class EggGroup(internal val showdownID: String) {
|
||||
|
||||
MONSTER("Monster"),
|
||||
WATER_1("Water 1"),
|
||||
@@ -34,15 +31,6 @@ enum class EggGroup(internal val showdownID: String) : StringIdentifiable {
|
||||
WATER_2("Water 2"),
|
||||
DITTO("Ditto"),
|
||||
DRAGON("Dragon"),
|
||||
UNDISCOVERED("Undiscovered");
|
||||
|
||||
override fun asString(): String = this.name
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmField
|
||||
val CODEC: Codec<EggGroup> = StringIdentifiable.createCodec(EggGroup::values)
|
||||
|
||||
}
|
||||
UNDISCOVERED("Undiscovered")
|
||||
|
||||
}
|
||||
@@ -9,12 +9,12 @@
|
||||
package com.cobblemon.mod.common.api.pokemon.evolution
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.abilities.AbilityPool
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionCompleteEvent
|
||||
import com.cobblemon.mod.common.api.moves.BenchedMove
|
||||
import com.cobblemon.mod.common.api.moves.MoveTemplate
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.adapters.Variant
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.requirement.EvolutionRequirement
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.activestate.ShoulderedState
|
||||
@@ -22,7 +22,6 @@ import com.cobblemon.mod.common.pokemon.evolution.variants.ItemInteractionEvolut
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.LevelUpEvolution
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.TradeEvolution
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.mojang.serialization.Codec
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.sound.SoundCategory
|
||||
|
||||
@@ -62,11 +61,6 @@ interface Evolution : EvolutionLike {
|
||||
*/
|
||||
val learnableMoves: MutableSet<MoveTemplate>
|
||||
|
||||
/**
|
||||
* The [Variant] of this [Evolution].
|
||||
*/
|
||||
val variant: Variant<Evolution>
|
||||
|
||||
/**
|
||||
* Checks if the given [Pokemon] passes all the conditions and is ready to evolve.
|
||||
*
|
||||
@@ -126,12 +120,4 @@ interface Evolution : EvolutionLike {
|
||||
fun applyTo(pokemon: Pokemon) {
|
||||
result.apply(pokemon)
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
fun codec(): Codec<out Evolution> = this.variant.codec
|
||||
|
||||
}
|
||||
+8
-8
@@ -8,10 +8,9 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.evolution
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.species.Species
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistries
|
||||
import com.mojang.serialization.Codec
|
||||
import net.minecraft.util.Identifier
|
||||
import com.cobblemon.mod.common.pokemon.FormData
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.cobblemon.mod.common.pokemon.evolution.StandardPreEvolution
|
||||
|
||||
/**
|
||||
* Represents the previous stage in the evolutionary line of a given Pokémon.
|
||||
@@ -20,14 +19,15 @@ import net.minecraft.util.Identifier
|
||||
* @author Licious
|
||||
* @since March 22nd, 2022
|
||||
*/
|
||||
class PreEvolution internal constructor(private val speciesKey: Identifier){
|
||||
interface PreEvolution {
|
||||
|
||||
val species: Species by lazy { CobblemonRegistries.SPECIES.get(this.speciesKey)!! }
|
||||
val species: Species
|
||||
|
||||
val form: FormData
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmField
|
||||
val CODEC: Codec<PreEvolution> = Identifier.CODEC.xmap(::PreEvolution, PreEvolution::speciesKey)
|
||||
fun of(species: Species, form: FormData = species.standardForm): PreEvolution = StandardPreEvolution(species, form)
|
||||
|
||||
}
|
||||
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.evolution.adapters
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.pokemon.evolution.adapters.CobblemonEvolutionAdapter
|
||||
import com.google.gson.JsonDeserializer
|
||||
import com.google.gson.JsonSerializer
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* Saves and loads [Evolution]s with JSON.
|
||||
* For the default implementation see [CobblemonEvolutionAdapter].
|
||||
*
|
||||
* @author Licious
|
||||
* @since March 20th, 2022
|
||||
*/
|
||||
interface EvolutionAdapter : JsonDeserializer<Evolution>, JsonSerializer<Evolution> {
|
||||
|
||||
/**
|
||||
* Registers the given type of [Evolution] to it's associated ID for deserialization.
|
||||
*
|
||||
* @param T The type of [Evolution].
|
||||
* @param id The id of the evolution event.
|
||||
* @param type The [KClass] of the type.
|
||||
*/
|
||||
fun <T : Evolution> registerType(id: String, type: KClass<T>)
|
||||
|
||||
}
|
||||
-112
@@ -1,112 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.evolution.adapters
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.requirement.EvolutionRequirement
|
||||
import com.cobblemon.mod.common.pokemon.evolution.requirements.*
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.BlockClickEvolution
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.ItemInteractionEvolution
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.LevelUpEvolution
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.TradeEvolution
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.Lifecycle
|
||||
import net.minecraft.registry.RegistryKey
|
||||
import net.minecraft.registry.SimpleRegistry
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
object EvolutionRegistry {
|
||||
|
||||
private val EVOLUTION_REGISTRY = SimpleRegistry<Variant<Evolution>>(RegistryKey.ofRegistry(cobblemonResource("evolution_variants")), Lifecycle.stable())
|
||||
private val REQUIREMENT_REGISTRY = SimpleRegistry<Variant<EvolutionRequirement>>(RegistryKey.ofRegistry(cobblemonResource("evolution_requirements")), Lifecycle.stable())
|
||||
|
||||
/**
|
||||
* A [Codec] for [Evolution].
|
||||
* If you wish to register more variants see [registerEvolutionVariant].
|
||||
*/
|
||||
@JvmField
|
||||
val EVOLUTION_CODEC: Codec<Evolution> = EVOLUTION_REGISTRY.codec.dispatch("variant", Evolution::variant) { variant -> variant.codec }
|
||||
|
||||
/**
|
||||
* A [Codec] for [EvolutionRequirement].
|
||||
* If you wish to register more variants see [registerRequirementVariant].
|
||||
*/
|
||||
@JvmField
|
||||
val REQUIREMENT_CODEC: Codec<EvolutionRequirement> = REQUIREMENT_REGISTRY.codec.dispatch("variant", EvolutionRequirement::variant) { variant -> variant.codec }
|
||||
|
||||
/**
|
||||
* Registers an [Evolution] type.
|
||||
*
|
||||
* @param variant The [Variant] of an [Evolution] being registered.
|
||||
*
|
||||
* @throws IllegalStateException If the backing registry already contains an entry with the [Variant.identifier].
|
||||
* @throws AssertionError If the registry is missing an intrusive holder.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun registerEvolutionVariant(variant: Variant<Evolution>) {
|
||||
EVOLUTION_REGISTRY.add(RegistryKey.of(EVOLUTION_REGISTRY.key, variant.identifier), variant, Lifecycle.stable())
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an [EvolutionRequirement] type.
|
||||
*
|
||||
* @param variant The [Variant] of an [EvolutionRequirement] being registered.
|
||||
*
|
||||
* @throws IllegalStateException If the backing registry already contains an entry with the [Variant.identifier].
|
||||
* @throws AssertionError If the registry is missing an intrusive holder.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun registerRequirementVariant(variant: Variant<EvolutionRequirement>) {
|
||||
REQUIREMENT_REGISTRY.add(RegistryKey.of(REQUIREMENT_REGISTRY.key, variant.identifier), variant, Lifecycle.stable())
|
||||
}
|
||||
|
||||
internal fun init() {
|
||||
this.registerDefaultEvolutions()
|
||||
this.registerDefaultRequirements()
|
||||
}
|
||||
|
||||
private fun registerDefaultEvolutions() {
|
||||
this.registerEvolutionVariant(BlockClickEvolution.VARIANT)
|
||||
this.registerEvolutionVariant(ItemInteractionEvolution.VARIANT)
|
||||
this.registerEvolutionVariant(LevelUpEvolution.MAIN_VARIANT)
|
||||
this.registerEvolutionVariant(LevelUpEvolution.ALTERNATIVE_VARIANT)
|
||||
this.registerEvolutionVariant(TradeEvolution.VARIANT)
|
||||
}
|
||||
|
||||
private fun registerDefaultRequirements() {
|
||||
this.registerRequirementVariant(AllOfRequirement.VARIANT)
|
||||
this.registerRequirementVariant(AnyOfRequirement.VARIANT)
|
||||
this.registerRequirementVariant(AreaRequirement.VARIANT)
|
||||
this.registerRequirementVariant(AttackDefenceRatioRequirement.VARIANT)
|
||||
this.registerRequirementVariant(BattleCriticalHitsRequirement.VARIANT)
|
||||
this.registerRequirementVariant(BiomeRequirement.VARIANT)
|
||||
this.registerRequirementVariant(BlocksTraveledRequirement.VARIANT)
|
||||
this.registerRequirementVariant(DamageTakenRequirement.VARIANT)
|
||||
this.registerRequirementVariant(DefeatRequirement.VARIANT)
|
||||
this.registerRequirementVariant(FriendshipRequirement.VARIANT)
|
||||
this.registerRequirementVariant(HeldItemRequirement.VARIANT)
|
||||
this.registerRequirementVariant(LevelRequirement.VARIANT)
|
||||
this.registerRequirementVariant(MoonPhaseRequirement.VARIANT)
|
||||
this.registerRequirementVariant(MoveSetRequirement.VARIANT)
|
||||
this.registerRequirementVariant(MoveTypeRequirement.VARIANT)
|
||||
this.registerRequirementVariant(NoneOfRequirement.VARIANT)
|
||||
this.registerRequirementVariant(NotRequirement.VARIANT)
|
||||
this.registerRequirementVariant(PartyMemberRequirement.VARIANT)
|
||||
this.registerRequirementVariant(PokemonPropertiesRequirement.VARIANT)
|
||||
this.registerRequirementVariant(RecoilRequirement.VARIANT)
|
||||
this.registerRequirementVariant(TimeRangeRequirement.VARIANT)
|
||||
this.registerRequirementVariant(UseMoveRequirement.VARIANT)
|
||||
this.registerRequirementVariant(WeatherRequirement.VARIANT)
|
||||
this.registerRequirementVariant(WorldRequirement.VARIANT)
|
||||
}
|
||||
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.evolution.adapters
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.requirement.EvolutionRequirement
|
||||
import com.cobblemon.mod.common.pokemon.evolution.adapters.CobblemonRequirementAdapter
|
||||
import com.google.gson.JsonDeserializer
|
||||
import com.google.gson.JsonSerializer
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* Saves and loads [EvolutionRequirement]s with JSON.
|
||||
* For the default implementation see [CobblemonRequirementAdapter].
|
||||
*
|
||||
* @author Licious
|
||||
* @since March 21st, 2022
|
||||
*/
|
||||
interface RequirementAdapter : JsonDeserializer<EvolutionRequirement>, JsonSerializer<EvolutionRequirement> {
|
||||
|
||||
/**
|
||||
* Registers the given type of [EvolutionRequirement] to it's associated ID for deserialization.
|
||||
*
|
||||
* @param T The type of [EvolutionRequirement].
|
||||
* @param id The id of the evolution event.
|
||||
* @param type The [KClass] of the type.
|
||||
*/
|
||||
fun <T : EvolutionRequirement> registerType(id: String, type: KClass<T>)
|
||||
|
||||
}
|
||||
+1
-22
@@ -10,10 +10,7 @@ package com.cobblemon.mod.common.api.pokemon.evolution.requirement
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.ContextEvolution
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.adapters.EvolutionRegistry
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.adapters.Variant
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.mojang.serialization.Codec
|
||||
|
||||
/**
|
||||
* Represents a requirement for an evolution.
|
||||
@@ -25,12 +22,7 @@ import com.mojang.serialization.Codec
|
||||
* @author Licious
|
||||
* @since March 19th, 2022
|
||||
*/
|
||||
interface EvolutionRequirement {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
val variant: Variant<EvolutionRequirement>
|
||||
fun interface EvolutionRequirement {
|
||||
|
||||
/**
|
||||
* Checks if the given [Pokemon] satisfies the requirement.
|
||||
@@ -40,17 +32,4 @@ interface EvolutionRequirement {
|
||||
*/
|
||||
fun check(pokemon: Pokemon): Boolean
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
fun codec(): Codec<out EvolutionRequirement> = this.variant.codec
|
||||
|
||||
companion object {
|
||||
|
||||
val CODEC: Codec<EvolutionRequirement> = EvolutionRegistry.REQUIREMENT_CODEC
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
-5
@@ -18,7 +18,6 @@ import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonPrimitive
|
||||
import com.google.gson.JsonSerializationContext
|
||||
import com.google.gson.JsonSerializer
|
||||
import com.mojang.serialization.Codec
|
||||
import java.lang.reflect.Type
|
||||
import kotlin.math.max
|
||||
import net.minecraft.text.MutableText
|
||||
@@ -75,10 +74,6 @@ interface ExperienceGroup : LevelCurve {
|
||||
override fun getExperience(level: Int) = 0
|
||||
override fun getLevel(experience: Int) = 1
|
||||
}
|
||||
|
||||
@JvmField
|
||||
val CODEC: Codec<ExperienceGroup> = Codec.STRING.xmap(ExperienceGroups::findByName, ExperienceGroup::name)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.gender
|
||||
|
||||
import com.cobblemon.mod.common.api.data.ShowdownIdentifiable
|
||||
import com.cobblemon.mod.common.api.pokemon.species.Species
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Represents the [Gender] of a [Pokemon].
|
||||
* This is taken into account by [Species] when generating the [Pokemon].
|
||||
*
|
||||
* @property showdownId The ID of the [Gender] in Showdown.
|
||||
*
|
||||
* @see Species.genderSelector
|
||||
* @see Pokemon.gender
|
||||
* @see GenderSelector
|
||||
*/
|
||||
enum class Gender(private val showdownId: String) : ShowdownIdentifiable {
|
||||
|
||||
MALE("M"),
|
||||
FEMALE("F"),
|
||||
GENDERLESS("N");
|
||||
|
||||
override fun showdownId(): String = this.showdownId
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* The [Gender]s when a ratio is attached to a [GenderSelector].
|
||||
*
|
||||
* @see GenderSelector.maleRatio
|
||||
*/
|
||||
@JvmField
|
||||
val RATIO_BASED_GENDERS: Set<Gender> = EnumSet.of(MALE, FEMALE)
|
||||
|
||||
/**
|
||||
* The [Gender]s when no ratio is attached to a [GenderSelector].
|
||||
*
|
||||
* @see GenderSelector.maleRatio
|
||||
*/
|
||||
@JvmField
|
||||
val NO_RATIO_GENDERS: Set<Gender> = EnumSet.of(GENDERLESS)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.gender
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.species.Species
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.mojang.serialization.Codec
|
||||
import kotlin.random.Random
|
||||
|
||||
/**
|
||||
* Class responsible for querying possible [Gender]s of [Species] and assigning them randomly to generated [Pokemon].
|
||||
*
|
||||
* @property maleRatio The raw ratio for the [Gender.MALE] despite the naming this is able to cover all possible genders.
|
||||
*
|
||||
* @see Species.genderSelector
|
||||
*
|
||||
* @throws IllegalArgumentException If male ratio is greater than 1.
|
||||
*/
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
class GenderSelector internal constructor(private val maleRatio: Float) {
|
||||
|
||||
init {
|
||||
if (this.maleRatio < 1F) {
|
||||
throw IllegalArgumentException("Male ratio cannot be greater than 1.0")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects all the possible [Gender]s from [generate].
|
||||
*
|
||||
* @return The possible [Gender]s.
|
||||
*/
|
||||
fun possibleGenders(): Set<Gender> = if (this.maleRatio < 0F) Gender.NO_RATIO_GENDERS else Gender.RATIO_BASED_GENDERS
|
||||
|
||||
/**
|
||||
* Randomly picks a [Gender] using the [maleRatio].
|
||||
*
|
||||
* @return The generated [Gender].
|
||||
*/
|
||||
fun generate(): Gender = when {
|
||||
this.maleRatio < 0F -> Gender.GENDERLESS
|
||||
this.maleRatio == 1F || Random.nextFloat() < this.maleRatio -> Gender.MALE
|
||||
else -> Gender.FEMALE
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given [gender] is a possible selection of [generate].
|
||||
*
|
||||
* @param gender The [Gender] being checked.
|
||||
* @return If the [gender] is possible with the context in this [GenderSelector].
|
||||
*/
|
||||
fun isValid(gender: Gender): Boolean = this.possibleGenders().contains(gender)
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* A [Codec] for [GenderSelector].
|
||||
* This will (de)serialize from a primitive float.
|
||||
* It will error if the value is not between [Float.MIN_VALUE] and 1F.
|
||||
*/
|
||||
@JvmField
|
||||
val CODEC: Codec<GenderSelector> = Codec.floatRange(Float.MIN_VALUE, 1F).xmap(::GenderSelector, GenderSelector::maleRatio)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.species
|
||||
|
||||
import com.cobblemon.mod.common.api.data.ShowdownIdentifiable
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistries
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* Additional data only present in species that are a variation of an existing species.
|
||||
* This is commonly referred to as a Pokémon form.
|
||||
* In the context of Cobblemon aspects are used when a form is purely cosmetic.
|
||||
* This is only present if a [Species] has actual stat related differences from the "base".
|
||||
*
|
||||
* @see <a href="https://bulbapedia.bulbagarden.net/wiki/Variant_Pok%C3%A9mon">Bulbapedias entry on variant Pokémon</a>
|
||||
*/
|
||||
class FormData internal constructor(
|
||||
private var baseSpeciesIdentifier: Identifier,
|
||||
private var battleOnly: Boolean
|
||||
) {
|
||||
|
||||
/**
|
||||
* Resolves the base species of this form.
|
||||
*
|
||||
* @return The [Species] that is the base of this form.
|
||||
*/
|
||||
fun baseSpecies(): Species = CobblemonRegistries.SPECIES.get(this.baseSpeciesIdentifier)!!
|
||||
|
||||
/**
|
||||
* Checks if this [FormData] can only exist in battles.
|
||||
*
|
||||
* @return True if this [FormData] can only exist in battles.
|
||||
*/
|
||||
fun isBattleOnly(): Boolean = this.battleOnly
|
||||
|
||||
companion object {
|
||||
|
||||
val CODEC: Codec<FormData> = RecordCodecBuilder.create { builder ->
|
||||
builder.group(
|
||||
Identifier.CODEC.fieldOf("baseSpecies").forGetter(FormData::baseSpeciesIdentifier),
|
||||
Codec.BOOL.fieldOf("battleOnly").forGetter(FormData::battleOnly)
|
||||
).apply(builder, ::FormData)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,198 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.species
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.abilities.AbilityPool
|
||||
import com.cobblemon.mod.common.api.data.ShowdownIdentifiable
|
||||
import com.cobblemon.mod.common.api.pokemon.egg.EggGroup
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.PreEvolution
|
||||
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceGroup
|
||||
import com.cobblemon.mod.common.api.pokemon.gender.Gender
|
||||
import com.cobblemon.mod.common.api.pokemon.gender.GenderSelector
|
||||
import com.cobblemon.mod.common.api.pokemon.moves.Learnset
|
||||
import com.cobblemon.mod.common.api.pokemon.species.internal.*
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.StatMap
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistryElement
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistryKeys
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.ai.PokemonBehaviour
|
||||
import com.cobblemon.mod.common.util.codec.ExtraCodecs
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.entity.EntityDimensions
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.registry.entry.RegistryEntry
|
||||
import net.minecraft.text.MutableText
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
import java.util.*
|
||||
|
||||
@Suppress("unused")
|
||||
class Species internal constructor(
|
||||
nationalPokedexNumber: Int,
|
||||
types: Pair<ElementalType, Optional<ElementalType>>,
|
||||
abilities: AbilityPool,
|
||||
baseStats: StatMap,
|
||||
catchRate: Int,
|
||||
genderSelector: GenderSelector,
|
||||
private val experienceData: ExperienceData,
|
||||
private val eggData: EggData,
|
||||
learnset: Learnset,
|
||||
private val behaviourData: BehaviourData,
|
||||
private val evolutionData: EvolutionData,
|
||||
baseFriendship: Int,
|
||||
evYield: StatMap,
|
||||
private val cosmeticData: CosmeticData,
|
||||
formData: Optional<FormData>
|
||||
): CobblemonRegistryElement<Species>, ShowdownIdentifiable {
|
||||
|
||||
companion object {
|
||||
|
||||
private val TYPES_CODEC = ExtraCodecs.ENTITY_DIMENSIONS
|
||||
|
||||
val codec = RecordCodecBuilder.create { builder ->
|
||||
builder.group(
|
||||
Codec.INT.fieldOf("nationalPokedexNumber").forGetter(Species::nationalPokedexNumber),
|
||||
ExtraCodecs.DUAL_TYPE_CODEC.fieldOf("types").forGetter(Species::types),
|
||||
// ToDo: abilities
|
||||
StatMap.BASE_STATS_CODEC.fieldOf("baseStats").forGetter(Species::baseStats),
|
||||
Codec.INT.fieldOf("catchRate").forGetter(Species::catchRate),
|
||||
GenderSelector.CODEC.fieldOf("genderSelector").forGetter(Species::genderSelector),
|
||||
ExperienceData.MAP_CODEC.forGetter(Species::experienceData),
|
||||
EggData.MAP_CODEC.fieldOf("eggData").forGetter(Species::eggData),
|
||||
// ToDo: learnset
|
||||
BehaviourData.MAP_CODEC.forGetter(Species::behaviourData),
|
||||
EvolutionData.MAP_CODEC.forGetter(Species::evolutionData),
|
||||
Codec.INT.fieldOf("baseFriendship").forGetter(Species::baseFriendship),
|
||||
StatMap.BASE_STATS_CODEC.fieldOf("evYield").forGetter(Species::evYield),
|
||||
CosmeticData.MAP_CODEC.forGetter(Species::cosmeticData),
|
||||
FormData.CODEC.optionalFieldOf("formData").forGetter(Species::formData)
|
||||
).apply(builder, ::Species)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
val displayName: MutableText by lazy { Text.translatable("${this.id().namespace}.species.${this.id().path.replace("/", ".")}.name") }
|
||||
|
||||
var nationalPokedexNumber: Int = nationalPokedexNumber
|
||||
private set
|
||||
|
||||
var types: Pair<ElementalType, Optional<ElementalType>> = types
|
||||
private set
|
||||
|
||||
val primaryType: ElementalType get() = this.types.first
|
||||
|
||||
val secondaryType: Optional<ElementalType> get() = this.types.second
|
||||
|
||||
var abilities: AbilityPool = abilities
|
||||
private set
|
||||
|
||||
var baseStats: StatMap = baseStats
|
||||
private set
|
||||
|
||||
var catchRate: Int = catchRate
|
||||
private set
|
||||
|
||||
/**
|
||||
* Responsible for picking a [Gender] for this [Species] on [create].
|
||||
*/
|
||||
var genderSelector: GenderSelector = genderSelector
|
||||
private set
|
||||
|
||||
val shoulderMountable: Boolean get() = this.behaviourData.shoulderMountable
|
||||
|
||||
val baseExperienceYield: Int get() = this.experienceData.baseExperienceYield
|
||||
|
||||
val experienceGroup: ExperienceGroup get() = this.experienceData.experienceGroup
|
||||
|
||||
val eggCycles: Int get() = this.eggData.eggCycles
|
||||
|
||||
val eggGroups: Set<EggGroup> get() = this.eggData.eggGroups
|
||||
|
||||
var learnset: Learnset = learnset
|
||||
private set
|
||||
|
||||
val behaviour: PokemonBehaviour get() = this.behaviourData.pokemonBehaviour
|
||||
|
||||
val evolutions: Set<Evolution> get() = this.evolutionData.evolutions
|
||||
|
||||
val preEvolution: Optional<PreEvolution> get() = this.evolutionData.preEvolution
|
||||
|
||||
val baseScale: Float get() = this.cosmeticData.baseScale
|
||||
|
||||
val hitbox: EntityDimensions get() = this.cosmeticData.hitbox
|
||||
|
||||
var baseFriendship: Int = baseFriendship
|
||||
private set
|
||||
|
||||
var evYield: StatMap = evYield
|
||||
private set
|
||||
|
||||
val weight: Float get() = this.cosmeticData.weight
|
||||
|
||||
val height: Float get() = this.cosmeticData.height
|
||||
|
||||
val aspects: Set<String> get() = this.cosmeticData.aspects
|
||||
|
||||
val features: Set<String> get() = this.behaviourData.features
|
||||
|
||||
val standingEyeHeight: Float get() = this.cosmeticData.standingEyeHeight
|
||||
|
||||
val swimmingEyeHeight: Float get() = this.cosmeticData.swimmingEyeHeight
|
||||
|
||||
val flyingEyeHeight: Float get() = this.cosmeticData.flyingEyeHeight
|
||||
|
||||
var formData: Optional<FormData> = formData
|
||||
private set
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*
|
||||
* @param level
|
||||
* @return
|
||||
*/
|
||||
fun create(level: Int): Pokemon {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
/**
|
||||
* Picks a randomly generated [Gender] using the [genderSelector].
|
||||
*
|
||||
* @return The picked [Gender].
|
||||
*/
|
||||
fun pickGender(): Gender = this.genderSelector.generate()
|
||||
|
||||
/**
|
||||
* Checks if this [Species] can be of the given [gender].
|
||||
* This is checked against the [genderSelector].
|
||||
*
|
||||
* @param gender The [Gender] being checked.
|
||||
* @return If the given [gender] is possible for this [Species].
|
||||
*/
|
||||
fun canBeOfGender(gender: Gender): Boolean = this.genderSelector.isValid(gender)
|
||||
|
||||
override fun showdownId(): String {
|
||||
val id = this.id()
|
||||
val showdownId = ShowdownIdentifiable.REGEX.replace(id.path, "")
|
||||
if (id.namespace == Cobblemon.MODID) {
|
||||
return showdownId
|
||||
}
|
||||
return id.namespace + showdownId
|
||||
}
|
||||
|
||||
override fun id(): Identifier = this.registry().getId(this)!!
|
||||
|
||||
override fun registryEntry(): RegistryEntry<Species> = this.registry().getEntry(this)
|
||||
|
||||
override fun registry(): Registry<Species> = Cobblemon.implementation.getRegistry(CobblemonRegistryKeys.SPECIES)
|
||||
|
||||
}
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.species.internal
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.species.Species
|
||||
import com.cobblemon.mod.common.pokemon.ai.PokemonBehaviour
|
||||
import com.cobblemon.mod.common.util.codec.setCodec
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.MapCodec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
|
||||
/**
|
||||
* Intermediate for [Species] data.
|
||||
*/
|
||||
internal data class BehaviourData(
|
||||
var pokemonBehaviour: PokemonBehaviour,
|
||||
var shoulderMountable: Boolean,
|
||||
var features: Set<String>,
|
||||
var dynamaxBlocked: Boolean,
|
||||
) {
|
||||
|
||||
companion object {
|
||||
|
||||
val MAP_CODEC: MapCodec<BehaviourData> = RecordCodecBuilder.mapCodec { builder ->
|
||||
builder.group(
|
||||
PokemonBehaviour.CODEC.fieldOf("pokemonBehaviour").forGetter(BehaviourData::pokemonBehaviour),
|
||||
Codec.BOOL.fieldOf("shoulderMountable").forGetter(BehaviourData::shoulderMountable),
|
||||
setCodec(Codec.STRING).fieldOf("features").forGetter(BehaviourData::features),
|
||||
Codec.BOOL.optionalFieldOf("dynamaxBlocked", false).forGetter(BehaviourData::dynamaxBlocked)
|
||||
).apply(builder, ::BehaviourData)
|
||||
}
|
||||
|
||||
val CODEC: Codec<BehaviourData> = MAP_CODEC.codec()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
-54
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.species.internal
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.species.Species
|
||||
import com.cobblemon.mod.common.util.codec.ExtraCodecs
|
||||
import com.cobblemon.mod.common.util.codec.setCodec
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.MapCodec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.entity.EntityDimensions
|
||||
|
||||
/**
|
||||
* Intermediate for [Species] data.
|
||||
*/
|
||||
internal data class CosmeticData(
|
||||
var baseScale: Float,
|
||||
var hitbox: EntityDimensions,
|
||||
var weight: Float,
|
||||
var height: Float,
|
||||
var aspects: Set<String>,
|
||||
var standingEyeHeight: Float,
|
||||
var swimmingEyeHeight: Float,
|
||||
var flyingEyeHeight: Float,
|
||||
) {
|
||||
|
||||
companion object {
|
||||
|
||||
val MAP_CODEC: MapCodec<CosmeticData> = RecordCodecBuilder.mapCodec { builder ->
|
||||
builder.group(
|
||||
Codec.FLOAT.fieldOf("baseScale").forGetter(CosmeticData::baseScale),
|
||||
ExtraCodecs.ENTITY_DIMENSIONS.fieldOf("hitbox").forGetter(CosmeticData::hitbox),
|
||||
Codec.FLOAT.fieldOf("weight").forGetter(CosmeticData::weight),
|
||||
Codec.FLOAT.fieldOf("height").forGetter(CosmeticData::height),
|
||||
setCodec(Codec.STRING).fieldOf("aspects").forGetter(CosmeticData::aspects),
|
||||
Codec.FLOAT.optionalFieldOf("standingEyeHeight", VANILLA_DEFAULT_EYE_HEIGHT).forGetter(CosmeticData::standingEyeHeight),
|
||||
Codec.FLOAT.optionalFieldOf("swimmingEyeHeight", VANILLA_DEFAULT_EYE_HEIGHT).forGetter(CosmeticData::swimmingEyeHeight),
|
||||
Codec.FLOAT.optionalFieldOf("flyingEyeHeight", VANILLA_DEFAULT_EYE_HEIGHT).forGetter(CosmeticData::flyingEyeHeight),
|
||||
).apply(builder, ::CosmeticData)
|
||||
}
|
||||
|
||||
val CODEC: Codec<CosmeticData> = MAP_CODEC.codec()
|
||||
|
||||
private const val VANILLA_DEFAULT_EYE_HEIGHT = 0.85F
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
-40
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.species.internal
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.egg.EggGroup
|
||||
import com.cobblemon.mod.common.api.pokemon.species.Species
|
||||
import com.cobblemon.mod.common.util.codec.setCodec
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.MapCodec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import java.util.EnumSet
|
||||
|
||||
/**
|
||||
* Intermediate for [Species] data.
|
||||
*/
|
||||
internal data class EggData(
|
||||
var eggCycles: Int,
|
||||
var eggGroups: EnumSet<EggGroup>,
|
||||
) {
|
||||
|
||||
companion object {
|
||||
|
||||
val MAP_CODEC: MapCodec<EggData> = RecordCodecBuilder.mapCodec { builder ->
|
||||
builder.group(
|
||||
Codec.INT.fieldOf("eggCycles").forGetter(EggData::eggCycles),
|
||||
setCodec(EggGroup.CODEC).fieldOf("eggGroups").xmap({ set -> EnumSet.copyOf(set) }, { enumSet -> enumSet }).forGetter { eggData -> eggData.eggGroups }
|
||||
).apply(builder, ::EggData)
|
||||
}
|
||||
|
||||
val CODEC: Codec<EggData> = MAP_CODEC.codec()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.species.internal
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.PreEvolution
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.adapters.EvolutionRegistry
|
||||
import com.cobblemon.mod.common.api.pokemon.species.Species
|
||||
import com.cobblemon.mod.common.util.codec.setCodec
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.MapCodec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Intermediate for [Species] data.
|
||||
*/
|
||||
internal data class EvolutionData(
|
||||
var evolutions: Set<Evolution>,
|
||||
var preEvolution: Optional<PreEvolution>,
|
||||
) {
|
||||
|
||||
companion object {
|
||||
|
||||
val MAP_CODEC: MapCodec<EvolutionData> = RecordCodecBuilder.mapCodec { builder ->
|
||||
builder.group(
|
||||
setCodec(EvolutionRegistry.EVOLUTION_CODEC).optionalFieldOf("evolutions", emptySet()).forGetter(EvolutionData::evolutions),
|
||||
PreEvolution.CODEC.optionalFieldOf("preEvolution").forGetter(EvolutionData::preEvolution)
|
||||
).apply(builder, ::EvolutionData)
|
||||
}
|
||||
|
||||
val CODEC: Codec<EvolutionData> = MAP_CODEC.codec()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
-36
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.species.internal
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceGroup
|
||||
import com.cobblemon.mod.common.api.pokemon.species.Species
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.MapCodec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
|
||||
/**
|
||||
* Intermediate for [Species] data.
|
||||
*/
|
||||
internal data class ExperienceData(
|
||||
var baseExperienceYield: Int,
|
||||
var experienceGroup: ExperienceGroup
|
||||
) {
|
||||
|
||||
companion object {
|
||||
|
||||
val MAP_CODEC: MapCodec<ExperienceData> = RecordCodecBuilder.mapCodec { builder ->
|
||||
builder.group(
|
||||
Codec.INT.fieldOf("baseExperienceYield").forGetter(ExperienceData::baseExperienceYield),
|
||||
ExperienceGroup.CODEC.fieldOf("experienceGroup").forGetter(ExperienceData::experienceGroup),
|
||||
).apply(builder, ::ExperienceData)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.stats
|
||||
|
||||
import com.mojang.serialization.Codec
|
||||
import kotlin.math.absoluteValue
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
* An implementation of [StatMap] aimed solely at the EV data structure.
|
||||
* This exists due to a few extra constraints present in EVs regarding the total value of the structure.
|
||||
*
|
||||
* @see <a href="https://bulbapedia.bulbagarden.net/wiki/Effort_values">Effort values Bulbapedia entry</a>
|
||||
*/
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
class EvMap internal constructor(stats: HashMap<Stat, Int>) : StatMap(Variant.EV, stats) {
|
||||
|
||||
init {
|
||||
if (this.values.sum() > MAX_TOTAL) {
|
||||
throw IllegalArgumentException("Cannot instance ${this::class.simpleName} with values total exceeding $MAX_TOTAL")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherits the logic of [StatMap.validateValue].
|
||||
* This has the added constraint of the maximum possible total value being [MAX_TOTAL].
|
||||
*
|
||||
* @see StatMap.validateValue
|
||||
*/
|
||||
override fun validateValue(key: Stat, value: Int) {
|
||||
super.validateValue(key, value)
|
||||
val existing = this[key]
|
||||
val current = this.values.sum() - existing
|
||||
if (current + value > MAX_TOTAL) {
|
||||
throw IllegalArgumentException("The total of the values of an ${this::class.simpleName} cannot exceed $MAX_TOTAL")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds to the given [stat].
|
||||
*
|
||||
* @param stat The [Stat] being added to.
|
||||
* @param amount The amount being added. This value will be sanitized with [Int.absoluteValue].
|
||||
* @param coerceSafe Should the value be coerced to be safe to add?
|
||||
* @return The new resulting value of [stat].
|
||||
*
|
||||
* @throws IllegalArgumentException if [validateValue] fails.
|
||||
*
|
||||
* @see subtract
|
||||
* @see mutate
|
||||
*/
|
||||
fun add(stat: Stat, amount: Int, coerceSafe: Boolean): Int = this.mutate(stat, amount.absoluteValue, coerceSafe)
|
||||
|
||||
/**
|
||||
* Subtracts from the given [stat].
|
||||
*
|
||||
* @param stat The [Stat] being subtracted from.
|
||||
* @param amount The amount being subtracted. This value will be sanitized with [Int.absoluteValue].
|
||||
* @param coerceSafe Should the value be coerced to be safe to subtract?
|
||||
* @return The new resulting value of [stat].
|
||||
*
|
||||
* @throws IllegalArgumentException if [validateValue] fails.
|
||||
*
|
||||
* @see add
|
||||
* @see mutate
|
||||
*/
|
||||
fun subtract(stat: Stat, amount: Int, coerceSafe: Boolean): Int = this.mutate(stat, amount.absoluteValue, coerceSafe)
|
||||
|
||||
/**
|
||||
* Mutates the given [stat].
|
||||
*
|
||||
* @param stat The [Stat] being mutated.
|
||||
* @param amount The amount being used in the mutation operation.
|
||||
* @param coerceSafe Should the value be coerced to be safe to operate with?
|
||||
* @return The new resulting value of [stat].
|
||||
*
|
||||
* @throws IllegalArgumentException if [validateValue] fails.
|
||||
*
|
||||
* @see add
|
||||
* @see subtract
|
||||
*/
|
||||
fun mutate(stat: Stat, amount: Int, coerceSafe: Boolean): Int {
|
||||
var result = this[stat] + amount
|
||||
if (coerceSafe) {
|
||||
result = result.coerceIn(this.variant.minValue, min(this.variant.maxValue, this.remaining()))
|
||||
}
|
||||
this.put(stat, result)
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves how many EVs can still be allocated to this structure.
|
||||
*
|
||||
* @return How many EVs can still be allocated.
|
||||
*/
|
||||
fun remaining(): Int = MAX_TOTAL - this.values.sum()
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* A [Codec] for a [EvMap].
|
||||
*/
|
||||
@JvmField
|
||||
val EV_STATS_CODEC: Codec<EvMap> = Codec.unboundedMap(Stat.CODEC, Codec.intRange(Variant.EV.minValue, Variant.EV.maxValue))
|
||||
.xmap({ map -> EvMap(HashMap(map)) }, { evMap -> evMap })
|
||||
|
||||
/**
|
||||
* The maximum total EV values.
|
||||
*/
|
||||
const val MAX_TOTAL = 510
|
||||
|
||||
/**
|
||||
* Creates a [EvMap] with the given params.
|
||||
*
|
||||
* @param map The base map to take values from.
|
||||
* @return The generated [EvMap].
|
||||
*
|
||||
* @throws IllegalArgumentException If the constraints seen in [StatMap.create] are not fulfilled or if the total of the values exceeds [MAX_TOTAL].
|
||||
*/
|
||||
fun create(map: Map<Stat, Int>): EvMap = EvMap(HashMap(map))
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,8 +8,6 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.stats
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.mojang.serialization.Codec
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
@@ -63,10 +61,4 @@ interface Stat {
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val CODEC: Codec<Stat> = Identifier.CODEC.xmap(Cobblemon.statProvider::fromIdentifierOrThrow, Stat::identifier)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,287 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.stats
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.serialization.BufferSerializer
|
||||
import com.cobblemon.mod.common.api.serialization.DataSerializer
|
||||
import com.cobblemon.mod.common.pokemon.EVs
|
||||
import com.cobblemon.mod.common.pokemon.IVs
|
||||
import com.google.gson.JsonObject
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.JsonOps
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.nbt.NbtOps
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import kotlin.jvm.optionals.getOrDefault
|
||||
|
||||
/**
|
||||
* Represents a map-like structure that is used solely for the purpose of various stat-like Pokémon data structures.
|
||||
*
|
||||
* @property variant The [Variant] of this map.
|
||||
* @property stats The base map used for this map.
|
||||
*
|
||||
* @see <a href="https://bulbapedia.bulbagarden.net/wiki/Base_stats">Base stats Bulbapedia entry</a>
|
||||
* @see <a href="https://bulbapedia.bulbagarden.net/wiki/Effort_values">Effort values Bulbapedia entry</a>
|
||||
* @see <a href="https://bulbapedia.bulbagarden.net/wiki/Individual_values">Individual values Bulbapedia entry</a>
|
||||
*
|
||||
*/
|
||||
@Suppress("unused", "MemberVisibilityCanBePrivate")
|
||||
open class StatMap internal constructor(
|
||||
val variant: Variant,
|
||||
protected val stats: HashMap<Stat, Int>
|
||||
) : Map<Stat, Int>, DataSerializer<NbtCompound, JsonObject>, BufferSerializer {
|
||||
|
||||
init {
|
||||
if (!Cobblemon.statProvider.ofType(Stat.Type.PERMANENT).all(this.stats::containsKey)) {
|
||||
throw IllegalArgumentException("Cannot instance ${this::class.simpleName} without all ${Stat.Type.PERMANENT.name} ${Stat::class.simpleName}")
|
||||
}
|
||||
if (!this.stats.values.any { value -> this.variant.fits(value) }) {
|
||||
throw IllegalArgumentException("Cannot instance ${this::class.simpleName} with values not in range [${this.variant.minValue}-${this.variant.maxValue}]")
|
||||
}
|
||||
}
|
||||
|
||||
override val entries: Set<Map.Entry<Stat, Int>>
|
||||
get() = this.stats.entries
|
||||
override val keys: Set<Stat>
|
||||
get() = this.stats.keys
|
||||
override val size: Int
|
||||
get() = this.stats.size
|
||||
override val values: Collection<Int>
|
||||
get() = this.stats.values
|
||||
|
||||
/**
|
||||
* A constraint of implementing [Map].
|
||||
* This is impossible to be false.
|
||||
*
|
||||
* @return Always true.
|
||||
*/
|
||||
override fun isEmpty(): Boolean = false
|
||||
|
||||
/**
|
||||
* Returns the value corresponding to the given [key].
|
||||
* Due to implementation details unlike a typical [Map.get] this will never return null.
|
||||
*
|
||||
* @param key The [Stat] being checked.
|
||||
* @return The value attached to the [key].
|
||||
*/
|
||||
override fun get(key: Stat): Int = this.stats[key]!!
|
||||
|
||||
override fun containsValue(value: Int): Boolean = this.stats.containsValue(value)
|
||||
|
||||
override fun containsKey(key: Stat): Boolean = this.stats.containsKey(key)
|
||||
|
||||
override fun loadFromNBT(nbt: NbtCompound) {
|
||||
this.codec().decode(NbtOps.INSTANCE, nbt)
|
||||
.result()
|
||||
.ifPresent { pair -> this.putAll(pair.first) }
|
||||
}
|
||||
|
||||
override fun saveToNBT(): NbtCompound {
|
||||
val result = this.codec().encodeStart(NbtOps.INSTANCE, this)
|
||||
.result()
|
||||
.getOrDefault(NbtCompound())
|
||||
// It's safe to cast it will always result in a NbtCompound
|
||||
return result as NbtCompound
|
||||
}
|
||||
|
||||
override fun loadFromJson(json: JsonObject) {
|
||||
this.codec().decode(JsonOps.INSTANCE, json)
|
||||
.result()
|
||||
.ifPresent { pair -> this.putAll(pair.first) }
|
||||
}
|
||||
|
||||
override fun saveToJson(): JsonObject {
|
||||
val result = this.codec().encodeStart(JsonOps.INSTANCE, this)
|
||||
.result()
|
||||
.getOrDefault(JsonObject())
|
||||
// It's safe to cast it will always result in a JsonObject
|
||||
return result as JsonObject
|
||||
}
|
||||
|
||||
override fun saveToBuffer(buffer: PacketByteBuf, toClient: Boolean) {
|
||||
buffer.writeMap(this.stats, { pb, stat -> pb.writeIdentifier(stat.identifier) }, PacketByteBuf::writeInt)
|
||||
}
|
||||
|
||||
override fun loadFromBuffer(buffer: PacketByteBuf) {
|
||||
// This is safe to do as the server will have sanitized the values.
|
||||
this.stats.clear()
|
||||
this.stats.putAll(buffer.readMap({ pb -> Cobblemon.statProvider.decode(pb) }, PacketByteBuf::readInt))
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the value for the given [key] to the [Variant.minValue] of [variant].
|
||||
*
|
||||
* @param key The [Stat] being reset.
|
||||
* @return The previous attached value.
|
||||
*
|
||||
* @throws IllegalArgumentException If the [key] fails [validateKey].
|
||||
*/
|
||||
fun reset(key: Stat): Int {
|
||||
this.validateKey(key)
|
||||
val existing = this.stats[key]!!
|
||||
this.stats[key] = this.variant.minValue
|
||||
return existing
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets all values of this map to the [Variant.minValue] of [variant].
|
||||
*/
|
||||
fun reset() {
|
||||
Cobblemon.statProvider.ofType(Stat.Type.PERMANENT).forEach(this::reset)
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges key-value pairs from a map into this [StatMap].
|
||||
*
|
||||
* @param from The map being merged.
|
||||
*
|
||||
* @throws IllegalArgumentException If any value of [from] fails [validateValue].
|
||||
*/
|
||||
fun putAll(from: Map<out Stat, Int>) {
|
||||
from.forEach(this::put)
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the given [value] on the given [key] [Stat] of this [StatMap].
|
||||
*
|
||||
* @param key The [Stat] being set.
|
||||
* @param value The value being set to the [key].
|
||||
* @return The previously attached value.
|
||||
*
|
||||
* @throws IllegalArgumentException If the [value] fails [validateValue].
|
||||
*/
|
||||
fun put(key: Stat, value: Int): Int {
|
||||
this.validateValue(key, value)
|
||||
val existing = this.stats[key]!!
|
||||
this.stats[key] = value
|
||||
return existing
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the [Codec] for this instance.
|
||||
* This is done based on the [variant].
|
||||
*
|
||||
* @return The [Codec] for this specific [StatMap] setup.
|
||||
*
|
||||
* @see StatMap.BASE_STATS_CODEC
|
||||
* @see StatMap.EV_STATS_CODEC
|
||||
* @see StatMap.IV_STATS_CODEC
|
||||
*/
|
||||
fun codec(): Codec<StatMap> = when (this.variant) {
|
||||
Variant.BASE_STATS -> BASE_STATS_CODEC
|
||||
Variant.IV -> IV_STATS_CODEC
|
||||
Variant.EV -> EV_STATS_CODEC
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a [Stat.Type] is [Stat.Type.PERMANENT].
|
||||
*
|
||||
* @param stat The [Stat] being checked.
|
||||
*
|
||||
* @throws IllegalArgumentException If the [Stat.Type] is not [Stat.Type.PERMANENT].
|
||||
*/
|
||||
protected open fun validateKey(stat: Stat) {
|
||||
if (stat.type != Stat.Type.PERMANENT) {
|
||||
throw IllegalArgumentException("Unsupported stat type of ${stat.type.name} for ${stat.identifier}")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a value is possible for this map.
|
||||
*
|
||||
* @param key The key having the [value] assigned.
|
||||
* @param value The value being assigned.
|
||||
*
|
||||
* @throws IllegalArgumentException If the [value] doesn't fulfill [Variant.fits] of the [variant].
|
||||
*/
|
||||
protected open fun validateValue(key: Stat, value: Int) {
|
||||
if (!this.variant.fits(value)) {
|
||||
throw IllegalArgumentException("Cannot accept $value, a value must be in range [${this.variant.minValue}-${this.variant.maxValue}]")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a type of data collected inside [StatMap].
|
||||
*
|
||||
* @property minValue The minimum possible value for a value of a [StatMap].
|
||||
* @property maxValue The maximum possible value for a value of a [StatMap].
|
||||
*/
|
||||
enum class Variant(val minValue: Int, val maxValue: Int) {
|
||||
|
||||
/**
|
||||
* Used to represent [base stats](https://bulbapedia.bulbagarden.net/wiki/Base_stats).
|
||||
*/
|
||||
BASE_STATS(1, Int.MAX_VALUE),
|
||||
|
||||
/**
|
||||
* Used to represent [effort values](https://bulbapedia.bulbagarden.net/wiki/Effort_values).
|
||||
*/
|
||||
EV(0, EVs.MAX_STAT_VALUE),
|
||||
|
||||
/**
|
||||
* Used to represent [individual values](https://bulbapedia.bulbagarden.net/wiki/Individual_values).
|
||||
*/
|
||||
IV(0, IVs.MAX_VALUE);
|
||||
|
||||
/**
|
||||
* Checks if the given [value] fits within the range created by [minValue] & [maxValue].
|
||||
*
|
||||
* @param value The value being checked.
|
||||
* @return If the value can fit in this variant.
|
||||
*/
|
||||
fun fits(value: Int): Boolean = value >= this.minValue && value <= this.maxValue
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* A [Codec] for a [StatMap] of the [Variant.BASE_STATS] variant.
|
||||
*/
|
||||
@JvmField
|
||||
val BASE_STATS_CODEC: Codec<StatMap> = this.createCodec(Variant.BASE_STATS)
|
||||
|
||||
/**
|
||||
* A [Codec] for a [StatMap] of the [Variant.EV] variant.
|
||||
* For the [EvMap] typed Codec see [EvMap.EV_STATS_CODEC].
|
||||
* The result as far as instance types go is the same this is just a constraint of [Codec].
|
||||
*
|
||||
* @see EvMap.EV_STATS_CODEC
|
||||
*/
|
||||
@JvmField
|
||||
val EV_STATS_CODEC: Codec<StatMap> = EvMap.EV_STATS_CODEC.xmap({ evMap -> this.create(Variant.EV, evMap) }, EvMap::create)
|
||||
|
||||
/**
|
||||
* A [Codec] for a [StatMap] of the [Variant.IV] variant.
|
||||
*/
|
||||
@JvmField
|
||||
val IV_STATS_CODEC: Codec<StatMap> = this.createCodec(Variant.IV)
|
||||
|
||||
/**
|
||||
* Creates a [StatMap] with the given params.
|
||||
*
|
||||
* @param variant The [StatMap] [Variant].
|
||||
* @param map The base map to take values from.
|
||||
* @return The generated [StatMap].
|
||||
*
|
||||
* @throws IllegalArgumentException If map doesn't contain every possible key with type [Stat.Type.PERMANENT] or if any value doesn't respect [Variant.fits] for the given [variant].
|
||||
*/
|
||||
fun create(variant: Variant, map: Map<Stat, Int>): StatMap = when (variant) {
|
||||
Variant.BASE_STATS -> StatMap(variant, HashMap(map))
|
||||
Variant.EV -> EvMap(HashMap(map))
|
||||
Variant.IV -> StatMap(variant, HashMap(map))
|
||||
}
|
||||
|
||||
private fun createCodec(variant: Variant): Codec<StatMap> = Codec.unboundedMap(Stat.CODEC, Codec.intRange(variant.minValue, variant.maxValue))
|
||||
.xmap({ map -> StatMap(variant, HashMap(map)) }, { statMap -> statMap })
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,7 +9,11 @@
|
||||
package com.cobblemon.mod.common.api.pokemon.stats
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.pokemon.*
|
||||
import com.cobblemon.mod.common.pokemon.EVs
|
||||
import com.cobblemon.mod.common.pokemon.FormData
|
||||
import com.cobblemon.mod.common.pokemon.IVs
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
@@ -1,25 +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.registry
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.pokemon.species.Species
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.registry.RegistryKey
|
||||
|
||||
object CobblemonRegistries {
|
||||
|
||||
val ELEMENTAL_TYPE: Registry<ElementalType> get() = this.get(CobblemonRegistryKeys.ELEMENTAL_TYPE)
|
||||
|
||||
val SPECIES: Registry<Species> get() = this.get(CobblemonRegistryKeys.SPECIES)
|
||||
|
||||
private fun <T> get(key: RegistryKey<Registry<T>>): Registry<T> = Cobblemon.implementation.getRegistry(key)
|
||||
|
||||
}
|
||||
-26
@@ -1,26 +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.registry
|
||||
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.registry.entry.RegistryEntry
|
||||
import net.minecraft.registry.tag.TagKey
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
interface CobblemonRegistryElement<T : CobblemonRegistryElement<T>> {
|
||||
|
||||
fun isIn(tag: TagKey<T>): Boolean = this.registryEntry().isIn(tag)
|
||||
|
||||
fun id(): Identifier
|
||||
|
||||
fun registryEntry(): RegistryEntry<T>
|
||||
|
||||
fun registry(): Registry<T>
|
||||
|
||||
}
|
||||
@@ -1,29 +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.registry
|
||||
|
||||
import com.cobblemon.mod.common.api.moves.MoveTemplate
|
||||
import com.cobblemon.mod.common.api.pokemon.species.Species
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.registry.RegistryKey
|
||||
|
||||
/**
|
||||
* Contains the various [RegistryKey]s for Cobblemon.
|
||||
*/
|
||||
object CobblemonRegistryKeys {
|
||||
|
||||
val ELEMENTAL_TYPE: RegistryKey<Registry<ElementalType>> = this.create("elemental_types")
|
||||
|
||||
val SPECIES: RegistryKey<Registry<Species>> = this.create("species")
|
||||
|
||||
private fun <T> create(key: String): RegistryKey<Registry<T>> = RegistryKey.ofRegistry(cobblemonResource(key))
|
||||
|
||||
}
|
||||
@@ -19,15 +19,12 @@ import com.cobblemon.mod.common.api.spawning.detail.PossibleHeldItem
|
||||
import com.cobblemon.mod.common.api.spawning.preset.SpawnDetailPreset
|
||||
import com.cobblemon.mod.common.util.adapters.*
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.codec.toTypeAdapter
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.fluid.Fluid
|
||||
import net.minecraft.registry.Registries
|
||||
import net.minecraft.registry.RegistryKeys
|
||||
import net.minecraft.registry.tag.TagKey
|
||||
import net.minecraft.resource.ResourceType
|
||||
@@ -51,9 +48,9 @@ object SpawnDetailPresets : JsonDataRegistry<SpawnDetailPreset> {
|
||||
.disableHtmlEscaping()
|
||||
.registerTypeAdapter(SpawnBucket::class.java, SpawnBucketAdapter)
|
||||
.registerTypeAdapter(RegisteredSpawningContext::class.java, RegisteredSpawningContextAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Biome::class.java).type, RegistryLikeCondition.createCodec { server()!!.registryManager.get(RegistryKeys.BIOME) }.toTypeAdapter())
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Block::class.java).type, RegistryLikeCondition.createCodec { Registries.BLOCK }.toTypeAdapter())
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Fluid::class.java).type, RegistryLikeCondition.createCodec { Registries.FLUID }.toTypeAdapter())
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Biome::class.java).type, BiomeLikeConditionAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Block::class.java).type, BlockLikeConditionAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Fluid::class.java).type, FluidLikeConditionAdapter)
|
||||
.registerTypeAdapter(
|
||||
TypeToken.getParameterized(
|
||||
Either::class.java,
|
||||
|
||||
@@ -17,15 +17,12 @@ import com.cobblemon.mod.common.api.spawning.context.RegisteredSpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.detail.PossibleHeldItem
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.util.adapters.*
|
||||
import com.cobblemon.mod.common.util.codec.toTypeAdapter
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.fluid.Fluid
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.registry.Registries
|
||||
import net.minecraft.registry.RegistryKeys
|
||||
import net.minecraft.registry.tag.TagKey
|
||||
import net.minecraft.util.Identifier
|
||||
@@ -44,9 +41,9 @@ object SpawnLoader {
|
||||
.setPrettyPrinting()
|
||||
.disableHtmlEscaping()
|
||||
.setLenient()
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Biome::class.java).type, RegistryLikeCondition.createCodec { server()!!.registryManager.get(RegistryKeys.BIOME) }.toTypeAdapter())
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Block::class.java).type, RegistryLikeCondition.createCodec { Registries.BLOCK }.toTypeAdapter())
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Fluid::class.java).type, RegistryLikeCondition.createCodec { Registries.FLUID }.toTypeAdapter())
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Biome::class.java).type, BiomeLikeConditionAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Block::class.java).type, BlockLikeConditionAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Fluid::class.java).type, FluidLikeConditionAdapter)
|
||||
.registerTypeAdapter(
|
||||
TypeToken.getParameterized(
|
||||
Either::class.java,
|
||||
|
||||
@@ -10,8 +10,6 @@ package com.cobblemon.mod.common.api.spawning
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.TimeRange.Companion.timeRanges
|
||||
import com.cobblemon.mod.common.api.spawning.condition.SpawningCondition
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.DataResult
|
||||
|
||||
/**
|
||||
* A range of time ticks for a world mainly to be used in [SpawningCondition]s. A time range
|
||||
@@ -43,12 +41,6 @@ class TimeRange : IntRanges {
|
||||
"morning" to TimeRange(0..4999),
|
||||
"afternoon" to TimeRange(7000..12039)
|
||||
)
|
||||
|
||||
val CODEC: Codec<TimeRange> = Codec.STRING.flatXmap(
|
||||
{ string -> timeRanges[string]?.let { DataResult.success(it) } ?: DataResult.error { "Can't find a time range with ID $string" } },
|
||||
{ timeRange -> timeRanges.entries.firstOrNull { (_, range) -> range == timeRange }?.let { DataResult.success(it.key) } ?: DataResult.error { "Couldn't resolve a time range ID for $timeRange" } }
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
constructor() : super()
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.condition
|
||||
|
||||
import net.minecraft.util.StringIdentifiable
|
||||
import net.minecraft.world.World
|
||||
|
||||
/**
|
||||
@@ -18,7 +17,7 @@ import net.minecraft.world.World
|
||||
* @author Licious
|
||||
* @since January 25th, 2023
|
||||
*/
|
||||
enum class MoonPhase : StringIdentifiable {
|
||||
enum class MoonPhase {
|
||||
|
||||
FULL_MOON,
|
||||
WANING_GIBBOUS,
|
||||
@@ -29,8 +28,6 @@ enum class MoonPhase : StringIdentifiable {
|
||||
FIRST_QUARTER,
|
||||
WAXING_GIBBOUS;
|
||||
|
||||
override fun asString(): String = this.name
|
||||
|
||||
companion object {
|
||||
private val VALUES = values()
|
||||
|
||||
|
||||
+2
-2
@@ -74,8 +74,8 @@ class PokemonSpawnDetail : SpawnDetail() {
|
||||
val species = PokemonSpecies.getByIdentifier(pokemon.species!!.asIdentifierDefaultingNamespace())
|
||||
if (species != null) {
|
||||
labels.addAll(
|
||||
species.secondaryType?.let { listOf(species.primaryType.id().toString(), it.id().toString()) }
|
||||
?: listOf(species.primaryType.id().toString())
|
||||
species.secondaryType?.let { listOf(species.primaryType.name.lowercase(), it.name.lowercase()) }
|
||||
?: listOf(species.primaryType.name.lowercase())
|
||||
)
|
||||
|
||||
if (height == -1) {
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ import com.cobblemon.mod.common.api.storage.StorePosition
|
||||
import com.cobblemon.mod.common.api.storage.party.PlayerPartyStore
|
||||
import com.cobblemon.mod.common.api.storage.pc.PCStore
|
||||
import com.cobblemon.mod.common.pokemon.EVs
|
||||
import com.cobblemon.mod.common.api.pokemon.gender.Gender
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.pokemon.IVs
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import java.nio.file.Path
|
||||
|
||||
+7
-8
@@ -14,7 +14,6 @@ import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
@Suppress("unused")
|
||||
class PlayerAdvancementData {
|
||||
|
||||
var totalCaptureCount: Int = 0
|
||||
@@ -36,7 +35,7 @@ class PlayerAdvancementData {
|
||||
var totalTradedCount: Int = 0
|
||||
private set
|
||||
|
||||
private var totalTypeCaptureCounts = mutableMapOf<Identifier, Int>()
|
||||
private var totalTypeCaptureCounts = mutableMapOf<String, Int>()
|
||||
private var totalDefeatedCounts = mutableMapOf<Identifier, Int>()
|
||||
var aspectsCollected = mutableMapOf<Identifier, MutableSet<String>>()
|
||||
private set
|
||||
@@ -78,18 +77,18 @@ class PlayerAdvancementData {
|
||||
}
|
||||
|
||||
fun getTotalTypeCaptureCount(type: ElementalType): Int {
|
||||
if (!totalTypeCaptureCounts.containsKey(type.id())) {
|
||||
totalTypeCaptureCounts[type.id()] = 0
|
||||
if (!totalTypeCaptureCounts.containsKey(key = type.name)) {
|
||||
totalTypeCaptureCounts[type.name] = 0
|
||||
}
|
||||
return totalTypeCaptureCounts[type.id()] ?: 0
|
||||
return totalTypeCaptureCounts.get(key = type.name) ?: 0
|
||||
}
|
||||
|
||||
fun updateTotalTypeCaptureCount(type: ElementalType) {
|
||||
val count = totalTypeCaptureCounts[type.id()] ?: 0
|
||||
val count = totalTypeCaptureCounts[type.name] ?: 0
|
||||
if (count == 0) {
|
||||
totalTypeCaptureCounts[type.id()] = 1
|
||||
totalTypeCaptureCounts[type.name] = 1
|
||||
} else {
|
||||
totalTypeCaptureCounts.replace(type.id(), count + 1)
|
||||
totalTypeCaptureCounts.replace(type.name, count + 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-28
@@ -1,28 +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.types
|
||||
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistryKeys
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.registry.tag.TagKey
|
||||
|
||||
/**
|
||||
* Contains all the Cobblemon default elemental type related tags.
|
||||
*/
|
||||
object CobblemonElementalTypeTags {
|
||||
|
||||
val FIRE_IMMUNE: TagKey<ElementalType> = TagKey.of(CobblemonRegistryKeys.ELEMENTAL_TYPE, cobblemonResource("fire_immune"))
|
||||
|
||||
val FALL_DAMAGE_IMMUNE: TagKey<ElementalType> = TagKey.of(CobblemonRegistryKeys.ELEMENTAL_TYPE, cobblemonResource("fall_damage_immune"))
|
||||
|
||||
val LURE_BALL_BOOSTING: TagKey<ElementalType> = TagKey.of(CobblemonRegistryKeys.ELEMENTAL_TYPE, cobblemonResource("lure_ball_boosting"))
|
||||
|
||||
val NET_BALL_BOOSTING: TagKey<ElementalType> = TagKey.of(CobblemonRegistryKeys.ELEMENTAL_TYPE, cobblemonResource("net_ball_boosting"))
|
||||
|
||||
}
|
||||
@@ -1,78 +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.types
|
||||
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistries
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.util.Identifier
|
||||
import java.util.Optional
|
||||
|
||||
/**
|
||||
* The official [ElementalType]s and the ones the Cobblemon mod ships with.
|
||||
* These are not guaranteed to be present in a game instance as we can't control what datapacks may remove them.
|
||||
* It's also not safe to assume they function the exact same as they would in the official games, please check the various properties of [ElementalType].
|
||||
*/
|
||||
@Suppress("MemberVisibilityCanBePrivate", "unused")
|
||||
object CobblemonElementalTypes {
|
||||
|
||||
val BUG_KEY: Identifier = cobblemonResource("bug")
|
||||
val BUG: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(BUG_KEY))
|
||||
|
||||
val DARK_KEY: Identifier = cobblemonResource("dark")
|
||||
val DARK: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(DARK_KEY))
|
||||
|
||||
val DRAGON_KEY: Identifier = cobblemonResource("dragon")
|
||||
val DRAGON: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(DRAGON_KEY))
|
||||
|
||||
val ELECTRIC_KEY: Identifier = cobblemonResource("electric")
|
||||
val ELECTRIC: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(ELECTRIC_KEY))
|
||||
|
||||
val FAIRY_KEY: Identifier = cobblemonResource("fairy")
|
||||
val FAIRY: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(FAIRY_KEY))
|
||||
|
||||
val FIGHTING_KEY: Identifier = cobblemonResource("fighting")
|
||||
val FIGHTING: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(FIGHTING_KEY))
|
||||
|
||||
val FIRE_KEY: Identifier = cobblemonResource("fire")
|
||||
val FIRE: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(FIRE_KEY))
|
||||
|
||||
val FLYING_KEY: Identifier = cobblemonResource("flying")
|
||||
val FLYING: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(FLYING_KEY))
|
||||
|
||||
val GHOST_KEY: Identifier = cobblemonResource("ghost")
|
||||
val GHOST: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(GHOST_KEY))
|
||||
|
||||
val GRASS_KEY: Identifier = cobblemonResource("grass")
|
||||
val GRASS: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(GRASS_KEY))
|
||||
|
||||
val GROUND_KEY: Identifier = cobblemonResource("ground")
|
||||
val GROUND: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(GROUND_KEY))
|
||||
|
||||
val ICE_KEY: Identifier = cobblemonResource("ice")
|
||||
val ICE: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(ICE_KEY))
|
||||
|
||||
val NORMAL_KEY: Identifier = cobblemonResource("normal")
|
||||
val NORMAL: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(NORMAL_KEY))
|
||||
|
||||
val POISON_KEY: Identifier = cobblemonResource("poison")
|
||||
val POISON: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(POISON_KEY))
|
||||
|
||||
val PSYCHIC_KEY: Identifier = cobblemonResource("psychic")
|
||||
val PSYCHIC: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(PSYCHIC_KEY))
|
||||
|
||||
val ROCK_KEY: Identifier = cobblemonResource("rock")
|
||||
val ROCK: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(ROCK_KEY))
|
||||
|
||||
val STEEL_KEY: Identifier = cobblemonResource("steel")
|
||||
val STEEL: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(STEEL_KEY))
|
||||
|
||||
val WATER_KEY: Identifier = cobblemonResource("water")
|
||||
val WATER: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(WATER_KEY))
|
||||
|
||||
}
|
||||
@@ -9,119 +9,21 @@
|
||||
package com.cobblemon.mod.common.api.types
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.data.ShowdownIdentifiable
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistries
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistryElement
|
||||
import com.cobblemon.mod.common.api.types.client.ClientData
|
||||
import com.cobblemon.mod.common.api.types.hiddenpower.HiddenPowerRequirement
|
||||
import com.cobblemon.mod.common.api.types.resistance.*
|
||||
import com.cobblemon.mod.common.util.codec.setCodec
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.registry.entry.RegistryEntry
|
||||
import net.minecraft.text.MutableText
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
import java.util.Optional
|
||||
|
||||
/**
|
||||
* Class representing the elemental type of Pokémon or Move.
|
||||
* Class representing a type of a Pokemon or Move
|
||||
*
|
||||
* @param damageTaken The [RawResistanceInformation] that will be converted into [ResistanceInformation] for this type.
|
||||
* @param hiddenPowerRequirement The [HiddenPowerRequirement] for this elemental type. If not present that means the type doesn't support hidden power.
|
||||
* @param clientData The [ClientData] of this type.
|
||||
* @param name: The English name used to load / find it (spaces -> _)
|
||||
* @param displayName: A Component used to display the name, normally a TranslatableText
|
||||
* @param textureXMultiplier: The multiplier by which the TypeWidget shall move the display
|
||||
* @param resourceLocation: The location of the resource used in the TypeWidget
|
||||
*/
|
||||
@Suppress("MemberVisibilityCanBePrivate", "unused")
|
||||
class ElementalType(
|
||||
private val damageTaken: Set<RawResistanceInformation>,
|
||||
val hiddenPowerRequirement: Optional<HiddenPowerRequirement>,
|
||||
val clientData: ClientData
|
||||
): CobblemonRegistryElement<ElementalType>, ShowdownIdentifiable {
|
||||
|
||||
/**
|
||||
* The translatable component responsible for showing this
|
||||
*/
|
||||
val displayName: MutableText by lazy { Text.translatable("${this.id().namespace}.type.${this.id().path.replace("/", ".")}") }
|
||||
|
||||
/**
|
||||
* The resolved [ResistanceInformation]s.
|
||||
* This is done by lazily invoking [RawResistanceInformation.toImplementation].
|
||||
*/
|
||||
private val resistanceInformation: HashSet<ResistanceInformation> by lazy {
|
||||
val resulting = this.damageTaken.map(RawResistanceInformation::toImplementation).toHashSet()
|
||||
this.populateMissingTypes(resulting)
|
||||
return@lazy resulting
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
fun resistanceInformation(): Set<ResistanceInformation> = this.resistanceInformation
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
fun resistanceAgainst(other: ElementalType): Resistance {
|
||||
return this.resistanceInformation().firstOrNull { it is ElementalTypeResistanceInformation && it.elementalType == other }?.resistance
|
||||
?: throw IllegalArgumentException("Cannot find type resistance for ${other.id()} this should be impossible.")
|
||||
}
|
||||
|
||||
override fun registryEntry(): RegistryEntry<ElementalType> = this.registry().getEntry(this)
|
||||
|
||||
override fun id(): Identifier = this.registry().getId(this)!!
|
||||
|
||||
override fun registry(): Registry<ElementalType> = CobblemonRegistries.ELEMENTAL_TYPE
|
||||
|
||||
override fun showdownId(): String {
|
||||
val showdownId = ShowdownIdentifiable.REGEX.replace(this.id().path.lowercase(), "")
|
||||
if (this.id().namespace == Cobblemon.MODID) {
|
||||
return showdownId
|
||||
}
|
||||
return this.id().namespace + showdownId
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean = other is ElementalType && other.id() == this.id()
|
||||
|
||||
override fun hashCode(): Int = this.id().hashCode()
|
||||
|
||||
/**
|
||||
* Adds in any missing [ResistanceInformation] for other loaded [ElementalType]s.
|
||||
*
|
||||
* @param current The currently loaded [ResistanceInformation].
|
||||
*/
|
||||
private fun populateMissingTypes(current: HashSet<ResistanceInformation>) {
|
||||
CobblemonRegistries.ELEMENTAL_TYPE.forEach { type ->
|
||||
if (current.none { it is ElementalTypeResistanceInformation && it.elementalType == type }) {
|
||||
val information = ElementalTypeResistanceInformation(type, Resistance.NEUTRAL)
|
||||
current.add(information)
|
||||
Cobblemon.LOGGER.info("{} elemental type was missing resistance information against {}, defaulting to neutral, it is recommended to validate if this is intended or if you should add additional data for the missing type", this.id(), type.id())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val CODEC: Codec<ElementalType> = RecordCodecBuilder.create { builder ->
|
||||
builder.group(
|
||||
setCodec(RawResistanceInformation.CODEC).fieldOf("damageTaken").forGetter(ElementalType::damageTaken),
|
||||
HiddenPowerRequirement.CODEC.optionalFieldOf("hiddenPowerRequirement").forGetter(ElementalType::hiddenPowerRequirement),
|
||||
ClientData.CODEC.fieldOf("clientData").forGetter(ElementalType::clientData)
|
||||
).apply(builder, ::ElementalType)
|
||||
}
|
||||
|
||||
val NETWORK_CODEC: Codec<ElementalType> = RecordCodecBuilder.create { builder ->
|
||||
builder.group(
|
||||
setCodec(RawResistanceInformation.CODEC).fieldOf("damageTaken").forGetter(ElementalType::damageTaken),
|
||||
ClientData.CODEC.fieldOf("clientData").forGetter(ElementalType::clientData)
|
||||
).apply(builder) { damageTaken, clientData -> ElementalType(damageTaken, Optional.empty(), clientData) }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
val name: String,
|
||||
val displayName: MutableText,
|
||||
val hue: Int,
|
||||
val textureXMultiplier: Int,
|
||||
val resourceLocation: Identifier = Identifier(Cobblemon.MODID, "ui/types.png")
|
||||
)
|
||||
@@ -6,3 +6,169 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.types
|
||||
|
||||
import net.minecraft.text.MutableText
|
||||
import net.minecraft.text.Text
|
||||
|
||||
/**
|
||||
* Registry for all known ElementalTypes
|
||||
*/
|
||||
object ElementalTypes {
|
||||
|
||||
private val allTypes = mutableListOf<ElementalType>()
|
||||
|
||||
val NORMAL = register(
|
||||
name = "normal",
|
||||
displayName = Text.translatable("cobblemon.type.normal"),
|
||||
hue = 0xDDDDCF,
|
||||
textureXMultiplier = 0
|
||||
)
|
||||
|
||||
val FIRE = register(
|
||||
name = "fire",
|
||||
displayName = Text.translatable("cobblemon.type.fire"),
|
||||
hue = 0xE55C32,
|
||||
textureXMultiplier = 1
|
||||
)
|
||||
|
||||
val WATER = register(
|
||||
name = "water",
|
||||
displayName = Text.translatable("cobblemon.type.water"),
|
||||
hue = 0x4A9BE8,
|
||||
textureXMultiplier = 2
|
||||
)
|
||||
|
||||
val GRASS = register(
|
||||
name = "grass",
|
||||
displayName = Text.translatable("cobblemon.type.grass"),
|
||||
hue = 0x4DBC3C,
|
||||
textureXMultiplier = 3
|
||||
)
|
||||
|
||||
val ELECTRIC = register(
|
||||
name = "electric",
|
||||
displayName = Text.translatable("cobblemon.type.electric"),
|
||||
hue = 0xEFD128,
|
||||
textureXMultiplier = 4
|
||||
)
|
||||
|
||||
val ICE = register(
|
||||
name = "ice",
|
||||
displayName = Text.translatable("cobblemon.type.ice"),
|
||||
hue = 0x6BC3EF,
|
||||
textureXMultiplier = 5
|
||||
)
|
||||
|
||||
val FIGHTING = register(
|
||||
name = "fighting",
|
||||
displayName = Text.translatable("cobblemon.type.fighting"),
|
||||
hue = 0xC44C5C,
|
||||
textureXMultiplier = 6
|
||||
)
|
||||
|
||||
val POISON = register(
|
||||
name = "poison",
|
||||
displayName = Text.translatable("cobblemon.type.poison"),
|
||||
hue = 0xA24BD8,
|
||||
textureXMultiplier = 7
|
||||
)
|
||||
|
||||
val GROUND = register(
|
||||
name = "ground",
|
||||
displayName = Text.translatable("cobblemon.type.ground"),
|
||||
hue = 0xD89950,
|
||||
textureXMultiplier = 8
|
||||
)
|
||||
|
||||
val FLYING = register(
|
||||
name = "flying",
|
||||
displayName = Text.translatable("cobblemon.type.flying"),
|
||||
hue = 0xBCC1FF,
|
||||
textureXMultiplier = 9
|
||||
)
|
||||
|
||||
val PSYCHIC = register(
|
||||
name = "psychic",
|
||||
displayName = Text.translatable("cobblemon.type.psychic"),
|
||||
hue = 0xD86AD6,
|
||||
textureXMultiplier = 10
|
||||
)
|
||||
|
||||
val BUG = register(
|
||||
name = "bug",
|
||||
displayName = Text.translatable("cobblemon.type.bug"),
|
||||
hue = 0xA2C831,
|
||||
textureXMultiplier = 11
|
||||
)
|
||||
|
||||
val ROCK = register(
|
||||
name = "rock",
|
||||
displayName = Text.translatable("cobblemon.type.rock"),
|
||||
hue = 0xAA9666,
|
||||
textureXMultiplier = 12
|
||||
)
|
||||
|
||||
val GHOST = register(
|
||||
name = "ghost",
|
||||
displayName = Text.translatable("cobblemon.type.ghost"),
|
||||
hue = 0x9572E5,
|
||||
textureXMultiplier = 13
|
||||
)
|
||||
|
||||
val DRAGON = register(
|
||||
name = "dragon",
|
||||
displayName = Text.translatable("cobblemon.type.dragon"),
|
||||
hue = 0x535DE8,
|
||||
textureXMultiplier = 14
|
||||
)
|
||||
|
||||
val DARK = register(
|
||||
name = "dark",
|
||||
displayName = Text.translatable("cobblemon.type.dark"),
|
||||
hue = 0x5C6CB2,
|
||||
textureXMultiplier = 15
|
||||
)
|
||||
|
||||
val STEEL = register(
|
||||
name = "steel",
|
||||
displayName = Text.translatable("cobblemon.type.steel"),
|
||||
hue = 0xC3CCE0,
|
||||
textureXMultiplier = 16
|
||||
)
|
||||
|
||||
val FAIRY = register(
|
||||
name = "fairy",
|
||||
displayName = Text.translatable("cobblemon.type.fairy"),
|
||||
hue = 0xEA727E,
|
||||
textureXMultiplier = 17
|
||||
)
|
||||
|
||||
fun register(name: String, displayName: MutableText, hue: Int, textureXMultiplier: Int): ElementalType {
|
||||
return ElementalType(
|
||||
name = name,
|
||||
displayName = displayName,
|
||||
hue = hue,
|
||||
textureXMultiplier = textureXMultiplier
|
||||
).also {
|
||||
allTypes.add(it)
|
||||
}
|
||||
}
|
||||
|
||||
fun register(elementalType: ElementalType): ElementalType {
|
||||
allTypes.add(elementalType)
|
||||
return elementalType
|
||||
}
|
||||
|
||||
fun get(name: String): ElementalType? {
|
||||
return allTypes.firstOrNull { type -> type.name.equals(name, ignoreCase = true) }
|
||||
}
|
||||
|
||||
fun getOrException(name: String): ElementalType {
|
||||
return allTypes.first { type -> type.name.equals(name, ignoreCase = true) }
|
||||
}
|
||||
|
||||
fun count() = allTypes.size
|
||||
|
||||
fun all() = this.allTypes.toList()
|
||||
}
|
||||
|
||||
+9
-8
@@ -8,21 +8,22 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.types.adapters
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistries
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.google.gson.*
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.google.gson.JsonDeserializationContext
|
||||
import com.google.gson.JsonDeserializer
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonPrimitive
|
||||
import com.google.gson.JsonSerializationContext
|
||||
import com.google.gson.JsonSerializer
|
||||
import java.lang.reflect.Type
|
||||
|
||||
object ElementalTypeAdapter: JsonSerializer<ElementalType>, JsonDeserializer<ElementalType> {
|
||||
|
||||
override fun serialize(src: ElementalType, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
|
||||
return JsonPrimitive(if (src.id().namespace == Cobblemon.MODID) src.id().path else src.id().toString())
|
||||
return JsonPrimitive(src.name)
|
||||
}
|
||||
|
||||
override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): ElementalType {
|
||||
return CobblemonRegistries.ELEMENTAL_TYPE.get(json.asString.asIdentifierDefaultingNamespace())!!
|
||||
return ElementalTypes.getOrException(json.asString)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,50 +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.types.client
|
||||
|
||||
import com.cobblemon.mod.common.util.math.toRGB
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* Represents various properties used in UIs.
|
||||
* This data is present on the server and synchronized to clients.
|
||||
*
|
||||
* @property hue The RGB tint applied in a few UIs.
|
||||
* @property primaryTexture The primary texture for the type icon.
|
||||
* @property secondaryTexture The secondary texture used when a miniature icon is wanted.
|
||||
* @property uOffset The uOffset on the blitk.
|
||||
* @property vOffset The vOffset on the blitk.
|
||||
*/
|
||||
data class ClientData(
|
||||
val hue: Int,
|
||||
val primaryTexture: Identifier,
|
||||
val secondaryTexture: Identifier,
|
||||
val uOffset: Float,
|
||||
val vOffset: Float
|
||||
) {
|
||||
|
||||
val something = 0xA2C831
|
||||
|
||||
companion object {
|
||||
|
||||
val CODEC: Codec<ClientData> = RecordCodecBuilder.create { builder ->
|
||||
builder.group(
|
||||
Codec.STRING.xmap(Integer::decode, Integer::toHexString).fieldOf("hue").forGetter(ClientData::hue),
|
||||
Identifier.CODEC.fieldOf("primaryTexture").forGetter(ClientData::primaryTexture),
|
||||
Identifier.CODEC.fieldOf("secondaryTexture").forGetter(ClientData::secondaryTexture),
|
||||
Codec.FLOAT.optionalFieldOf("uOffset", 0F).forGetter(ClientData::uOffset),
|
||||
Codec.FLOAT.optionalFieldOf("vOffset", 0F).forGetter(ClientData::vOffset)
|
||||
).apply(builder, ::ClientData)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
-49
@@ -1,49 +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.types.hiddenpower
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Environment
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stat
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.mojang.serialization.Codec
|
||||
|
||||
/**
|
||||
* Responsible for determining if a [Pokemon] can use the hidden power of a given type.
|
||||
* This will be attached to a [ElementalType.hiddenPowerRequirement].
|
||||
*
|
||||
* @property statMap The stat map that checks [IvCondition]s for each IV value of a [Pokemon].
|
||||
*
|
||||
* @throws IllegalArgumentException if not every stat of type [Stat.Type.PERMANENT] is present.
|
||||
*/
|
||||
class HiddenPowerRequirement(internal val statMap: Map<Stat, IvCondition>) {
|
||||
|
||||
init {
|
||||
if (Cobblemon.implementation.environment() == Environment.SERVER && !this.statMap.keys.containsAll(Cobblemon.statProvider.ofType(Stat.Type.PERMANENT))) {
|
||||
throw IllegalArgumentException("Cannot create a ${this::class.simpleName} when missing permanent stats")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given [Pokemon] passes this requirement.
|
||||
*
|
||||
* @param pokemon The [Pokemon] being checked.
|
||||
* @return If this requirement is passed against the [pokemon].
|
||||
*/
|
||||
fun isValid(pokemon: Pokemon): Boolean = pokemon.ivs.all { (stat, value) -> this.statMap[stat]!!.fits(value) }
|
||||
|
||||
companion object {
|
||||
|
||||
val CODEC: Codec<HiddenPowerRequirement> = Codec.unboundedMap(Stat.CODEC, IvCondition.CODEC)
|
||||
.xmap(::HiddenPowerRequirement, HiddenPowerRequirement::statMap)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,41 +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.types.hiddenpower
|
||||
|
||||
import com.mojang.serialization.Codec
|
||||
import net.minecraft.util.StringIdentifiable
|
||||
|
||||
/**
|
||||
* Represents the odd or even IV value requirement for hidden power.
|
||||
*/
|
||||
enum class IvCondition : StringIdentifiable {
|
||||
|
||||
EVEN,
|
||||
ODD;
|
||||
|
||||
override fun asString(): String = this.name
|
||||
|
||||
/**
|
||||
* Checks if the given IV value respects the condition.
|
||||
*
|
||||
* @param ivValue The value being checked.
|
||||
* @return true if the value respects the condition.
|
||||
*/
|
||||
fun fits(ivValue: Int): Boolean = when (this) {
|
||||
EVEN -> ivValue % 2 == 0
|
||||
ODD -> ivValue % 2 != 0
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val CODEC: Codec<IvCondition> = StringIdentifiable.createCodec(IvCondition::values)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
-23
@@ -1,23 +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.types.resistance
|
||||
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
|
||||
/**
|
||||
* An implementation of [ResistanceInformation] for [ElementalType]s.
|
||||
*
|
||||
* @property elementalType The [ElementalType] that would be attacking the type containing this object.
|
||||
*/
|
||||
class ElementalTypeResistanceInformation(val elementalType: ElementalType, override val resistance: Resistance) : ResistanceInformation {
|
||||
|
||||
override fun showdownId(): String = this.elementalType.showdownId()
|
||||
|
||||
override fun toRaw(): RawResistanceInformation = RawResistanceInformation(this.elementalType.id().toString(), this.resistance, ResistanceVariant.ELEMENTAL_TYPE)
|
||||
}
|
||||
-49
@@ -1,49 +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.types.resistance
|
||||
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
|
||||
/**
|
||||
* The raw representation of [ResistanceInformation].
|
||||
* This is used for (de)serialization purposes as certain implementations expect elements that depend on these to be loaded.
|
||||
*
|
||||
* @property value The raw string value used in the [ResistanceVariant.toImplementation].
|
||||
* @property resistance The [Resistance] value used in the [ResistanceVariant.toImplementation].
|
||||
* @property variant The [ResistanceVariant] that will decide the final [ResistanceInformation] implementation.
|
||||
*/
|
||||
data class RawResistanceInformation(
|
||||
val value: String,
|
||||
val resistance: Resistance,
|
||||
val variant: ResistanceVariant
|
||||
) {
|
||||
|
||||
/**
|
||||
* Converts this raw data to a [ResistanceInformation].
|
||||
*
|
||||
* @return The resulting [ResistanceInformation].
|
||||
*
|
||||
* @throws Exception An exception can be thrown by the [ResistanceVariant.toImplementation].
|
||||
*/
|
||||
fun toImplementation(): ResistanceInformation = this.variant.toImplementation(this)
|
||||
|
||||
companion object {
|
||||
|
||||
val CODEC: Codec<RawResistanceInformation> = RecordCodecBuilder.create { builder ->
|
||||
builder.group(
|
||||
Codec.STRING.fieldOf("value").forGetter(RawResistanceInformation::value),
|
||||
Resistance.CODEC.fieldOf("resistance").forGetter(RawResistanceInformation::resistance),
|
||||
ResistanceVariant.CODEC.fieldOf("variant").forGetter(RawResistanceInformation::variant)
|
||||
).apply(builder, ::RawResistanceInformation)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,37 +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.types.resistance
|
||||
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.mojang.serialization.Codec
|
||||
import net.minecraft.util.StringIdentifiable
|
||||
|
||||
/**
|
||||
* Represents the resistance of an [ElementalType] or a Showdown effect.
|
||||
*
|
||||
* @property showdownValue The showdown numerical value used in its data format for type resistances.
|
||||
*
|
||||
* @see [ResistanceInformation]
|
||||
*/
|
||||
enum class Resistance(val showdownValue: Int) : StringIdentifiable {
|
||||
|
||||
NEUTRAL(0),
|
||||
WEAK(1),
|
||||
RESIST(2),
|
||||
IMMUNE(3);
|
||||
|
||||
override fun asString(): String = this.name
|
||||
|
||||
companion object {
|
||||
|
||||
val CODEC: Codec<Resistance> = StringIdentifiable.createCodec(Resistance::values)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.types.resistance
|
||||
|
||||
import com.cobblemon.mod.common.api.data.ShowdownIdentifiable
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
|
||||
/**
|
||||
* Represents a resistance of an [ElementalType].
|
||||
* This can be to another [ElementalType] or some Showdown effect.
|
||||
* @see [ElementalTypeResistanceInformation]
|
||||
* @see [ShowdownEffectResistanceInformation]
|
||||
*/
|
||||
sealed interface ResistanceInformation : ShowdownIdentifiable {
|
||||
|
||||
/**
|
||||
* The [Resistance] value.
|
||||
*/
|
||||
val resistance: Resistance
|
||||
|
||||
/**
|
||||
* The raw form of this instance.
|
||||
* This is used for (de)serialization as certain elements like elemental types might not be fully loaded when utilizing this.
|
||||
*
|
||||
* @return The resulting [RawResistanceInformation].
|
||||
*/
|
||||
fun toRaw(): RawResistanceInformation
|
||||
|
||||
}
|
||||
-49
@@ -1,49 +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.types.resistance
|
||||
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistries
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.mojang.serialization.Codec
|
||||
import net.minecraft.util.StringIdentifiable
|
||||
|
||||
/**
|
||||
* Utility type to help with (de)serializing [ResistanceInformation].
|
||||
*
|
||||
* @see [RawResistanceInformation]
|
||||
* @see [RawResistanceInformation.CODEC]
|
||||
*/
|
||||
enum class ResistanceVariant : StringIdentifiable {
|
||||
|
||||
ELEMENTAL_TYPE,
|
||||
EFFECT_ID;
|
||||
|
||||
override fun asString(): String = this.name
|
||||
|
||||
/**
|
||||
* Converts a [RawResistanceInformation] to a [ResistanceInformation].
|
||||
*
|
||||
* @param raw The base [RawResistanceInformation].
|
||||
* @return The resulting [ResistanceInformation].
|
||||
*
|
||||
* @throws NullPointerException If this is a [ELEMENTAL_TYPE] and the [RawResistanceInformation.value] is not a possible [ElementalType].
|
||||
*/
|
||||
fun toImplementation(raw: RawResistanceInformation): ResistanceInformation = when (this) {
|
||||
ELEMENTAL_TYPE -> ElementalTypeResistanceInformation(CobblemonRegistries.ELEMENTAL_TYPE.get(raw.value.asIdentifierDefaultingNamespace())!!, raw.resistance)
|
||||
EFFECT_ID -> ShowdownEffectResistanceInformation(raw.value, raw.resistance)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val CODEC: Codec<ResistanceVariant> = StringIdentifiable.createCodec(ResistanceVariant::values)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
-23
@@ -1,23 +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.types.resistance
|
||||
|
||||
/**
|
||||
* An implementation of [ResistanceInformation] for Showdown effects.
|
||||
*
|
||||
* @property showdownEffectId The Showdown ID of the effect being checked.
|
||||
*/
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
class ShowdownEffectResistanceInformation(val showdownEffectId: String, override val resistance: Resistance) : ResistanceInformation {
|
||||
|
||||
override fun showdownId(): String = this.showdownEffectId
|
||||
|
||||
override fun toRaw(): RawResistanceInformation = RawResistanceInformation(this.showdownEffectId, this.resistance, ResistanceVariant.EFFECT_ID)
|
||||
|
||||
}
|
||||
@@ -114,7 +114,7 @@ object BattleRegistry {
|
||||
val evsInOrder = Stats.PERMANENT.map { pk.evs.getOrDefault(it) }.joinToString(separator = ",")
|
||||
packedTeamBuilder.append("$evsInOrder|")
|
||||
// Gender
|
||||
packedTeamBuilder.append("${pk.gender.showdownId()}|")
|
||||
packedTeamBuilder.append("${pk.gender.showdownName}|")
|
||||
// IVs
|
||||
val ivsInOrder = Stats.PERMANENT.map { pk.ivs.getOrDefault(it) }.joinToString(separator = ",")
|
||||
packedTeamBuilder.append("$ivsInOrder|")
|
||||
@@ -138,7 +138,7 @@ object BattleRegistry {
|
||||
// 0 - 9, empty == 10
|
||||
packedTeamBuilder.append("${if (pk.dmaxLevel < 10) pk.dmaxLevel else ""},")
|
||||
// Teratype
|
||||
packedTeamBuilder.append("${pokemon.effectedPokemon.teraType.showdownId()},")
|
||||
packedTeamBuilder.append("${pokemon.effectedPokemon.teraType.name},")
|
||||
|
||||
team.add(packedTeamBuilder.toString())
|
||||
}
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
|
||||
package com.cobblemon.mod.common.battles
|
||||
|
||||
import com.mojang.serialization.Codec
|
||||
import net.minecraft.util.StringIdentifiable
|
||||
import kotlin.math.abs
|
||||
|
||||
|
||||
@@ -83,7 +81,7 @@ interface Targetable {
|
||||
}
|
||||
}
|
||||
|
||||
enum class MoveTarget(val targetList: (Targetable) -> List<Targetable>? = { null }) : StringIdentifiable {
|
||||
enum class MoveTarget(val targetList: (Targetable) -> List<Targetable>? = { null }) {
|
||||
any({ pokemon -> pokemon.getAllActivePokemon().filter { it != pokemon } }),
|
||||
all,
|
||||
allAdjacent,
|
||||
@@ -100,14 +98,11 @@ enum class MoveTarget(val targetList: (Targetable) -> List<Targetable>? = { null
|
||||
foeSide,
|
||||
scripted;
|
||||
|
||||
override fun asString(): String = this.name
|
||||
|
||||
companion object {
|
||||
|
||||
private val VALUES = values()
|
||||
|
||||
val CODEC: Codec<MoveTarget> = StringIdentifiable.createCodec(::VALUES)
|
||||
|
||||
/**
|
||||
* Attempts to parse a [MoveTarget] from the given [showdownId].
|
||||
*
|
||||
|
||||
@@ -21,9 +21,9 @@ import com.cobblemon.mod.common.api.events.battles.BattleVictoryEvent
|
||||
import com.cobblemon.mod.common.api.moves.Moves
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistries
|
||||
import com.cobblemon.mod.common.api.scheduling.after
|
||||
import com.cobblemon.mod.common.api.text.*
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.cobblemon.mod.common.battles.dispatch.BattleDispatch
|
||||
import com.cobblemon.mod.common.battles.dispatch.DispatchResult
|
||||
import com.cobblemon.mod.common.battles.dispatch.GO
|
||||
@@ -1704,7 +1704,7 @@ object ShowdownInterpreter {
|
||||
private fun handleTerastallizeInstructions(battle: PokemonBattle, message: BattleMessage, remainingLines: MutableList<String>) {
|
||||
val battlePokemon = message.getBattlePokemon(0, battle) ?: return
|
||||
val pokemonName = battlePokemon.getName()
|
||||
val type = message.effectAt(1)?.let { CobblemonRegistries.ELEMENTAL_TYPE.firstOrNull { type -> type.showdownId() == it.id } } ?: return
|
||||
val type = message.effectAt(1)?.let { ElementalTypes.get(it.id) } ?: return
|
||||
battle.dispatchWaiting {
|
||||
battle.broadcastChatMessage(battleLang("terastallize", pokemonName, type.displayName).yellow())
|
||||
battle.minorBattleActions[battlePokemon.uuid] = message
|
||||
|
||||
@@ -32,7 +32,6 @@ interface ShowdownService {
|
||||
fun getItemIds(): JsonArray
|
||||
fun registerSpecies()
|
||||
fun registerBagItems()
|
||||
fun registerTypes()
|
||||
fun indicateSpeciesInitialized() {}
|
||||
|
||||
|
||||
|
||||
-33
@@ -11,14 +11,11 @@ package com.cobblemon.mod.common.battles.runner.graal
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistries
|
||||
import com.cobblemon.mod.common.api.types.hiddenpower.IvCondition
|
||||
import com.cobblemon.mod.common.battles.BagItems
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.runner.ShowdownService
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.net.URI
|
||||
@@ -46,7 +43,6 @@ import org.graalvm.polyglot.io.FileSystem
|
||||
* @since February 27, 2023
|
||||
* @author Hiroku, landonjw
|
||||
*/
|
||||
@Suppress("unused")
|
||||
class GraalShowdownService : ShowdownService {
|
||||
|
||||
@Transient
|
||||
@@ -171,35 +167,6 @@ class GraalShowdownService : ShowdownService {
|
||||
receiveSpeciesDataFn.execute(jsArray)
|
||||
}
|
||||
|
||||
override fun registerTypes() {
|
||||
val receiveTypesDataFn = this.context.getBindings("js").getMember("receiveTypeData")
|
||||
val jsArray = this.context.eval("js", "new Array();")
|
||||
var index = 0L
|
||||
CobblemonRegistries.ELEMENTAL_TYPE.forEach { type ->
|
||||
val jObject = JsonObject().apply {
|
||||
val showdownId = type.showdownId()
|
||||
addProperty("name", showdownId.replaceFirstChar(Char::uppercase))
|
||||
addProperty("id", showdownId)
|
||||
val damageTaken = JsonObject()
|
||||
type.resistanceInformation().forEach { information ->
|
||||
damageTaken.addProperty(information.showdownId(), information.resistance.showdownValue)
|
||||
}
|
||||
add("damageTaken", damageTaken)
|
||||
type.hiddenPowerRequirement.ifPresent {
|
||||
val hpIvs = JsonObject()
|
||||
it.statMap.forEach { (stat, requirement) ->
|
||||
if (requirement == IvCondition.EVEN) {
|
||||
hpIvs.addProperty(stat.showdownId, 30)
|
||||
}
|
||||
}
|
||||
add("HPivs", hpIvs)
|
||||
}
|
||||
}
|
||||
jsArray.setArrayElement(index++, jObject)
|
||||
}
|
||||
receiveTypesDataFn.execute(jsArray)
|
||||
}
|
||||
|
||||
override fun indicateSpeciesInitialized() {
|
||||
val afterCobbledSpeciesInitFn = this.context.getBindings("js").getMember("afterCobbledSpeciesInit")
|
||||
afterCobbledSpeciesInitFn.execute()
|
||||
|
||||
+1
-39
@@ -11,9 +11,6 @@ package com.cobblemon.mod.common.battles.runner.socket
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistries
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.api.types.hiddenpower.IvCondition
|
||||
import com.cobblemon.mod.common.battles.BagItems
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.runner.ShowdownService
|
||||
@@ -21,14 +18,13 @@ import com.cobblemon.mod.common.pokemon.FormData
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import java.io.BufferedReader
|
||||
import java.io.InputStreamReader
|
||||
import java.io.OutputStreamWriter
|
||||
import java.net.InetAddress
|
||||
import java.net.Socket
|
||||
import java.nio.charset.Charset
|
||||
import java.util.*
|
||||
import java.util.UUID
|
||||
|
||||
/**
|
||||
* Mediator service for communicating between the Cobblemon Minecraft mod and Cobblemon showdown service via
|
||||
@@ -46,7 +42,6 @@ import java.util.*
|
||||
* @since February 27, 2023
|
||||
* @author landonjw
|
||||
*/
|
||||
@Suppress("unused")
|
||||
class SocketShowdownService(val host: String = "localhost", val port: Int = 18468, val localPort: Int = 0) : ShowdownService {
|
||||
|
||||
private lateinit var socket: Socket
|
||||
@@ -151,14 +146,6 @@ class SocketShowdownService(val host: String = "localhost", val port: Int = 1846
|
||||
}
|
||||
}
|
||||
|
||||
override fun registerTypes() {
|
||||
writer.write(">resetTypeData\n")
|
||||
acknowledge()
|
||||
CobblemonRegistries.ELEMENTAL_TYPE.forEach { type ->
|
||||
this.sendType(type)
|
||||
}
|
||||
}
|
||||
|
||||
fun acknowledge(ifFails: () -> Unit = {}) {
|
||||
writer.flush()
|
||||
val ack = CharArray(3)
|
||||
@@ -179,29 +166,4 @@ class SocketShowdownService(val host: String = "localhost", val port: Int = 1846
|
||||
acknowledge()
|
||||
}
|
||||
|
||||
private fun sendType(type: ElementalType) {
|
||||
// See TypeInfo in Showdown
|
||||
val jObject = JsonObject().apply {
|
||||
val showdownId = type.showdownId()
|
||||
addProperty("name", showdownId.replaceFirstChar(Char::uppercase))
|
||||
addProperty("id", showdownId)
|
||||
val damageTaken = JsonObject()
|
||||
type.resistanceInformation().forEach { information ->
|
||||
damageTaken.addProperty(information.showdownId(), information.resistance.showdownValue)
|
||||
}
|
||||
add("damageTaken", damageTaken)
|
||||
type.hiddenPowerRequirement.ifPresent {
|
||||
val hpIvs = JsonObject()
|
||||
it.statMap.forEach { (stat, requirement) ->
|
||||
if (requirement == IvCondition.EVEN) {
|
||||
hpIvs.addProperty(stat.showdownId, 30)
|
||||
}
|
||||
}
|
||||
add("HPivs", hpIvs)
|
||||
}
|
||||
}
|
||||
writer.write(">receiveTypeData ${this.gson.toJson(jObject)}\n")
|
||||
acknowledge()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,11 +9,16 @@
|
||||
package com.cobblemon.mod.common.berry
|
||||
|
||||
import com.cobblemon.mod.common.api.berry.GrowthFactor
|
||||
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
|
||||
import com.cobblemon.mod.common.block.BerryBlock
|
||||
import com.cobblemon.mod.common.registry.BiomeIdentifierCondition
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.registry.RegistryKeys
|
||||
import net.minecraft.registry.tag.TagKey
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.world.WorldView
|
||||
import net.minecraft.world.biome.Biome
|
||||
|
||||
class PreferredBiomeGrowthFactor(
|
||||
val bonusYield: IntRange
|
||||
|
||||
@@ -67,6 +67,14 @@ class BerryBlock(private val berryIdentifier: Identifier, settings: Settings) :
|
||||
*/
|
||||
fun berry(): Berry? = Berries.getByIdentifier(this.berryIdentifier)
|
||||
|
||||
override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity) {
|
||||
if (!player.isCreative && state.get(AGE) == FRUIT_AGE) {
|
||||
val treeEntity = world.getBlockEntity(pos) as BerryBlockEntity
|
||||
treeEntity.harvest(world, state, pos, player).forEach { drop -> Block.dropStack(world, pos, drop) }
|
||||
}
|
||||
super.onBreak(world, pos, state, player)
|
||||
}
|
||||
|
||||
override fun createBlockEntity(pos: BlockPos, state: BlockState) = BerryBlockEntity(pos, state, berryIdentifier)
|
||||
|
||||
override fun isFertilizable(world: WorldView, pos: BlockPos, state: BlockState, isClient: Boolean) = !this.isMaxAge(state)
|
||||
|
||||
@@ -17,7 +17,6 @@ import com.cobblemon.mod.common.client.gui.PartyOverlay
|
||||
import com.cobblemon.mod.common.client.gui.battle.BattleOverlay
|
||||
import com.cobblemon.mod.common.client.particle.BedrockParticleEffectRepository
|
||||
import com.cobblemon.mod.common.client.render.block.BerryBlockRenderer
|
||||
import com.cobblemon.mod.common.client.render.block.BerryEntityInstance
|
||||
import com.cobblemon.mod.common.client.render.block.HealingMachineRenderer
|
||||
import com.cobblemon.mod.common.client.render.item.CobblemonBuiltinItemRendererRegistry
|
||||
import com.cobblemon.mod.common.client.render.item.PokemonItemRenderer
|
||||
@@ -36,9 +35,6 @@ import com.cobblemon.mod.common.client.render.models.blockbench.repository.Berry
|
||||
import com.cobblemon.mod.common.platform.events.PlatformEvents
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
import com.jozufozu.flywheel.backend.instancing.InstancedRenderRegistry
|
||||
import net.minecraft.client.color.block.BlockColorProvider
|
||||
import net.minecraft.client.color.item.ItemColorProvider
|
||||
import net.minecraft.client.gui.DrawContext
|
||||
import net.minecraft.client.render.RenderLayer
|
||||
import net.minecraft.client.render.entity.EntityRenderer
|
||||
@@ -121,11 +117,11 @@ object CobblemonClient {
|
||||
}
|
||||
|
||||
fun registerFlywheelRenderers() {
|
||||
InstancedRenderRegistry
|
||||
.configure(CobblemonBlockEntities.BERRY)
|
||||
.alwaysSkipRender()
|
||||
.factory(::BerryEntityInstance)
|
||||
.apply()
|
||||
// InstancedRenderRegistry
|
||||
// .configure(CobblemonBlockEntities.BERRY)
|
||||
// .alwaysSkipRender()
|
||||
// .factory(::BerryEntityInstance)
|
||||
// .apply()
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stat
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonFloatingState
|
||||
import com.cobblemon.mod.common.api.pokemon.gender.Gender
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
|
||||
@@ -9,9 +9,10 @@
|
||||
package com.cobblemon.mod.common.client.gui
|
||||
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.moves.DamageCategory
|
||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategory
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.client.gui.DrawContext
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
|
||||
class MoveCategoryIcon(
|
||||
val x: Number,
|
||||
@@ -35,7 +36,7 @@ class MoveCategoryIcon(
|
||||
y = y.toFloat() / SCALE,
|
||||
width = WIDTH,
|
||||
height = HEIGHT,
|
||||
vOffset = HEIGHT * category.ordinal,
|
||||
vOffset = HEIGHT * category.textureXMultiplier,
|
||||
textureHeight = HEIGHT * 3,
|
||||
alpha = opacity,
|
||||
scale = SCALE
|
||||
|
||||
@@ -24,7 +24,7 @@ import com.cobblemon.mod.common.client.keybind.keybinds.SummaryBinding
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.render.getDepletableRedGreen
|
||||
import com.cobblemon.mod.common.client.render.renderScaledGuiItemIcon
|
||||
import com.cobblemon.mod.common.api.pokemon.gender.Gender
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import net.minecraft.client.MinecraftClient
|
||||
|
||||
@@ -10,7 +10,9 @@ package com.cobblemon.mod.common.client.gui
|
||||
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.client.gui.DrawContext
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
|
||||
class TypeIcon(
|
||||
val x: Number,
|
||||
@@ -26,22 +28,24 @@ class TypeIcon(
|
||||
companion object {
|
||||
private const val TYPE_ICON_DIAMETER = 36
|
||||
private const val SCALE = 0.5F
|
||||
|
||||
private val typesResource = cobblemonResource("textures/gui/types.png")
|
||||
private val smallTypesResource = cobblemonResource("textures/gui/types_small.png")
|
||||
}
|
||||
|
||||
fun render(context: DrawContext) {
|
||||
val diameter = if (small) (TYPE_ICON_DIAMETER / 2) else TYPE_ICON_DIAMETER
|
||||
val offsetX = if (centeredX) (((diameter / 2) * SCALE) + (if (secondaryType != null) (doubleCenteredOffset) else 0F)) else 0F
|
||||
val offsetX = if (centeredX) (((diameter / 2) * SCALE) + (if (secondaryType != null) (doubleCenteredOffset) else 0F)) else 0F;
|
||||
|
||||
if (secondaryType != null) {
|
||||
blitk(
|
||||
matrixStack = context.matrices,
|
||||
texture = if (small) secondaryType.clientData.secondaryTexture else secondaryType.clientData.primaryTexture,
|
||||
texture = if (small) smallTypesResource else typesResource,
|
||||
x = (x.toFloat() + secondaryOffset - offsetX) / SCALE,
|
||||
y = y.toFloat() / SCALE,
|
||||
height = diameter,
|
||||
width = diameter,
|
||||
uOffset = diameter * secondaryType.clientData.uOffset + 0.1,
|
||||
vOffset = diameter * secondaryType.clientData.vOffset + 0.1,
|
||||
uOffset = diameter * secondaryType!!.textureXMultiplier.toFloat() + 0.1,
|
||||
textureWidth = diameter * 18,
|
||||
alpha = opacity,
|
||||
scale = SCALE
|
||||
@@ -50,13 +54,12 @@ class TypeIcon(
|
||||
|
||||
blitk(
|
||||
matrixStack = context.matrices,
|
||||
texture = if (small) type.clientData.secondaryTexture else type.clientData.primaryTexture,
|
||||
texture = if (small) smallTypesResource else typesResource,
|
||||
x = (x.toFloat() - offsetX) / SCALE,
|
||||
y = y.toFloat() / SCALE,
|
||||
height = diameter,
|
||||
width = diameter,
|
||||
uOffset = diameter * type.clientData.uOffset + 0.1,
|
||||
vOffset = diameter * type.clientData.vOffset + 0.1,
|
||||
uOffset = diameter * type.textureXMultiplier.toFloat() + 0.1,
|
||||
textureWidth = diameter * 18,
|
||||
alpha = opacity,
|
||||
scale = SCALE
|
||||
|
||||
@@ -27,7 +27,7 @@ import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.sin
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.api.pokemon.gender.Gender
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
+1
-1
@@ -105,7 +105,7 @@ abstract class BattleGimmickButton(gimmick: ShowdownMoveset.Gimmick, val x: Floa
|
||||
init {
|
||||
gimmickMoveTemplate?.let {
|
||||
moveTemplate = it
|
||||
rgb = it.elementalType.clientData.hue.toRGB()
|
||||
rgb = it.elementalType.hue.toRGB()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -83,7 +83,7 @@ class BattleMoveSelection(
|
||||
val y: Float,
|
||||
) {
|
||||
var moveTemplate = Moves.getByNameOrDummy(move.id)
|
||||
var rgb = moveTemplate.elementalType.clientData.hue.toRGB()
|
||||
var rgb = moveTemplate.elementalType.hue.toRGB()
|
||||
|
||||
open val targetList: List<Targetable>? get() = move.target.targetList(moveSelection.request.activePokemon)
|
||||
open val response: MoveActionResponse get() = MoveActionResponse(move.id, targetPnx)
|
||||
@@ -97,7 +97,7 @@ class BattleMoveSelection(
|
||||
}
|
||||
}
|
||||
|
||||
fun render(context: DrawContext, mouseX: Int, mouseY: Int) {
|
||||
fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
|
||||
val selectConditionOpacity = moveSelection.opacity * if (!selectable) 0.5F else 1F
|
||||
|
||||
@@ -184,7 +184,7 @@ class BattleMoveSelection(
|
||||
|
||||
override fun renderButton(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
moveTiles.forEach {
|
||||
it.render(context, mouseX, mouseY)
|
||||
it.render(context, mouseX, mouseY, delta)
|
||||
}
|
||||
backButton.render(context.matrices, mouseX, mouseY, delta)
|
||||
gimmickButtons.forEach {
|
||||
|
||||
+2
-1
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.client.gui.interact.moveselect
|
||||
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.moves.Move
|
||||
import com.cobblemon.mod.common.api.moves.MoveTemplate
|
||||
import com.cobblemon.mod.common.api.moves.Moves
|
||||
import com.cobblemon.mod.common.api.text.bold
|
||||
@@ -48,7 +49,7 @@ class MoveSlotButton(
|
||||
hovered = pMouseX >= x && pMouseY >= y && pMouseX < x + width && pMouseY < y + height && enabled
|
||||
|
||||
val moveTemplate = Moves.getByNameOrDummy(move.name)
|
||||
val rgb = moveTemplate.elementalType.clientData.hue.toRGB()
|
||||
val rgb = moveTemplate.elementalType.hue.toRGB()
|
||||
|
||||
val alpha = if (enabled) 1.0 else 0.5
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.storage.ClientPC
|
||||
import com.cobblemon.mod.common.client.storage.ClientParty
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.pc.UnlinkPlayerFromPCPacket
|
||||
import com.cobblemon.mod.common.api.pokemon.gender.Gender
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
@@ -31,6 +31,7 @@ import net.minecraft.client.gui.DrawContext
|
||||
import net.minecraft.client.gui.screen.Screen
|
||||
import net.minecraft.client.sound.PositionedSoundInstance
|
||||
import net.minecraft.client.util.InputUtil
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.sound.SoundEvent
|
||||
import net.minecraft.text.Text
|
||||
|
||||
@@ -453,7 +454,7 @@ class PCGUI(
|
||||
ticksElapsed++
|
||||
|
||||
// Calculate select pointer offset
|
||||
val delayFactor = 3
|
||||
var delayFactor = 3
|
||||
if (ticksElapsed % (2 * delayFactor) == 0) selectPointerOffsetIncrement = !selectPointerOffsetIncrement
|
||||
if (ticksElapsed % delayFactor == 0) selectPointerOffsetY += if (selectPointerOffsetIncrement) 1 else -1
|
||||
}
|
||||
@@ -479,8 +480,8 @@ class PCGUI(
|
||||
offsetY = -10.0
|
||||
)
|
||||
} else {
|
||||
previewPokemon = null
|
||||
modelWidget = null
|
||||
previewPokemon = null;
|
||||
modelWidget = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import com.cobblemon.mod.common.client.gui.drawProfilePokemon
|
||||
import com.cobblemon.mod.common.client.gui.pasture.PasturePCGUIConfiguration
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.render.renderScaledGuiItemIcon
|
||||
import com.cobblemon.mod.common.api.pokemon.gender.Gender
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
|
||||
+2
-1
@@ -37,6 +37,7 @@ import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.gui.DrawContext
|
||||
import net.minecraft.client.gui.screen.Screen
|
||||
import net.minecraft.client.sound.PositionedSoundInstance
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.text.Text
|
||||
|
||||
/**
|
||||
@@ -209,7 +210,7 @@ class StarterSelectionScreen private constructor(): Screen("cobblemon.ui.starter
|
||||
width = BASE_WIDTH, height = BASE_HEIGHT
|
||||
)
|
||||
// Render Frame
|
||||
val (r, g, b) = currentPokemon.form.primaryType.clientData.hue.toRGB()
|
||||
val (r, g, b) = currentPokemon.form.primaryType.hue.toRGB()
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = baseFrame,
|
||||
|
||||
@@ -34,7 +34,7 @@ import com.cobblemon.mod.common.client.gui.summary.widgets.screens.stats.StatWid
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.party.MovePartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.party.SwapPartyPokemonPacket
|
||||
import com.cobblemon.mod.common.api.pokemon.gender.Gender
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
@@ -306,7 +306,7 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
*/
|
||||
private fun displayMainScreen(screen: Int) {
|
||||
// Get stat tab index if currently displaying stat screen
|
||||
val subIndex = if (mainScreenIndex == STATS && mainScreen is StatWidget) (mainScreen as StatWidget).statTabIndex else 0
|
||||
var subIndex = if (mainScreenIndex == STATS && mainScreen is StatWidget) (mainScreen as StatWidget).statTabIndex else 0
|
||||
|
||||
mainScreenIndex = screen
|
||||
if (::mainScreen.isInitialized) remove(mainScreen)
|
||||
|
||||
+9
-7
@@ -10,26 +10,28 @@ package com.cobblemon.mod.common.client.gui.summary.widgets
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
|
||||
import com.cobblemon.mod.common.client.gui.summary.Summary
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.render.getDepletableRedGreen
|
||||
import com.cobblemon.mod.common.client.render.renderScaledGuiItemIcon
|
||||
import com.cobblemon.mod.common.api.pokemon.gender.Gender
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.cobblemon.mod.common.util.math.fromEulerXYZDegrees
|
||||
import net.minecraft.client.gui.DrawContext
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
import org.joml.Quaternionf
|
||||
import org.joml.Vector3f
|
||||
|
||||
class PartySlotWidget(
|
||||
pX: Number,
|
||||
pY: Number,
|
||||
private val pX: Number,
|
||||
private val pY: Number,
|
||||
private val partyWidget: PartyWidget,
|
||||
private val summary: Summary,
|
||||
private val pokemon: Pokemon?,
|
||||
@@ -69,7 +71,7 @@ class PartySlotWidget(
|
||||
}
|
||||
|
||||
override fun renderButton(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
hovered = mouseX >= x && mouseY >= y && mouseX < x + width && mouseY < y + height
|
||||
hovered = mouseX >= x && mouseY >= y && mouseX < x + width && mouseY < y + height;
|
||||
val matrices = context.matrices
|
||||
val isDraggedSlot = partyWidget.swapEnabled && partyWidget.swapSource == index
|
||||
val slotPokemon = if (isDraggedSlot) null else pokemon
|
||||
@@ -206,8 +208,8 @@ class PartySlotWidget(
|
||||
}
|
||||
}
|
||||
|
||||
override fun mouseClicked(pMouseX: Double, pMouseY: Double, pButton: Int): Boolean {
|
||||
if (isValidClick(pMouseX, pMouseY, pButton)) {
|
||||
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
|
||||
if (isValidClick(mouseX, mouseY, button)) {
|
||||
if (partyWidget.swapEnabled) {
|
||||
toggleDrag(true)
|
||||
} else {
|
||||
@@ -218,7 +220,7 @@ class PartySlotWidget(
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.mouseClicked(pMouseX, pMouseY, pButton)
|
||||
return super.mouseClicked(mouseX, mouseY, button)
|
||||
}
|
||||
|
||||
override fun mouseReleased(pMouseX: Double, pMouseY: Double, pButton: Int): Boolean {
|
||||
|
||||
+3
-3
@@ -70,7 +70,7 @@ class MoveSlotWidget(
|
||||
hovered = pMouseX >= x && pMouseY >= y && pMouseX < x + width && pMouseY < y + height
|
||||
|
||||
val moveTemplate = Moves.getByNameOrDummy(move.name)
|
||||
val rgb = moveTemplate.elementalType.clientData.hue.toRGB()
|
||||
val rgb = moveTemplate.elementalType.hue.toRGB()
|
||||
|
||||
if (movesWidget.selectedMove == move) {
|
||||
blitk(
|
||||
@@ -153,10 +153,10 @@ class MoveSlotWidget(
|
||||
switchMoveButton.render(context, pMouseX, pMouseY, pPartialTicks)
|
||||
}
|
||||
|
||||
override fun mouseClicked(pMouseX: Double, pMouseY: Double, pButton: Int): Boolean {
|
||||
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
|
||||
if (isHovered) {
|
||||
movesWidget.selectMove(move)
|
||||
}
|
||||
return super.mouseClicked(pMouseX, pMouseY, pButton)
|
||||
return super.mouseClicked(mouseX, mouseY, button)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ class MoveSwapScreen(
|
||||
) {
|
||||
val matrices = context.matrices
|
||||
val tweakedRowTop = rowTop - (SLOT_SPACING / 2) + 1
|
||||
val rgb = move.elementalType.clientData.hue.toRGB()
|
||||
val rgb = move.elementalType.hue.toRGB()
|
||||
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ class SingleTypeWidget(
|
||||
pWidth: Int, pHeight: Int,
|
||||
private val type: ElementalType,
|
||||
private val renderText: Boolean = true
|
||||
) : TypeWidget(pX, pY, pWidth, pHeight, Text.literal("SingleTypeWidget - ").append(type.displayName)) {
|
||||
) : TypeWidget(pX, pY, pWidth, pHeight, Text.literal("SingleTypeWidget - ${type.name}")) {
|
||||
|
||||
override fun renderButton(context: DrawContext, pMouseX: Int, pMouseY: Int, pPartialTicks: Float) {
|
||||
val matrices = context.matrices
|
||||
|
||||
+1
-2
@@ -32,8 +32,7 @@ abstract class TypeWidget(
|
||||
texture = typeResource,
|
||||
x = pX + OFFSET, y = pY,
|
||||
width = width, height = height,
|
||||
uOffset = width * type.clientData.uOffset + 0.1,
|
||||
vOffset = width * type.clientData.vOffset + 0.1,
|
||||
uOffset = width * type.textureXMultiplier.toFloat() + 0.1,
|
||||
textureWidth = width * 18
|
||||
)
|
||||
}
|
||||
|
||||
@@ -13,13 +13,14 @@ import com.cobblemon.mod.common.client.gui.drawProfilePokemon
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.render.renderScaledGuiItemIcon
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeStartedPacket
|
||||
import com.cobblemon.mod.common.api.pokemon.gender.Gender
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.cobblemon.mod.common.util.math.fromEulerXYZDegrees
|
||||
import net.minecraft.client.gui.DrawContext
|
||||
import net.minecraft.client.gui.widget.ButtonWidget
|
||||
import net.minecraft.client.sound.SoundManager
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.text.Text
|
||||
import org.joml.Quaternionf
|
||||
import org.joml.Vector3f
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user