mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-27 04:26:27 -04:00
Merge branch 'smarterer-pokemons' into 1.21.1-breeding-pokemingle.com
This commit is contained in:
+108
-65
@@ -1,33 +1,17 @@
|
||||
# Changelog
|
||||
## [1.6.1 (Release TBD)](#1-6-1)
|
||||
## [1.6.1 (January 26th, 2025)](#1-6-1)
|
||||
|
||||
### Additions
|
||||
- Added config setting `maxPokedexScanningDetectionRange` to control from what distance the player can scan Pokémon using the Pokédex.
|
||||
- Added the `is_standing_on_blocks(depth, blocks...)` MoLang function, which returns whether the specified entity is standing on a specific block or set of blocks. Example usage: `q.is_standing_on_blocks(2, minecraft:sand)`
|
||||
- Added config setting `hideUnimplementedPokemonInThePokedex` which hides unimplemented Pokémon from the Pokédex when set to true.
|
||||
- Added molang particle queries for getting distance to targeted entities.
|
||||
- Added debug renderer for poseable entity locators.
|
||||
- Added `baseScale` property to NPCs.
|
||||
- Added cry for Spinda.
|
||||
- Added the player to `PokerodReelEvent`.
|
||||
- Pokédex and Dialogue API screens now close when the inventory keybind is pressed.
|
||||
- Added Galarica Nuts, used for crafting Galarica Cuffs and Wreaths. Dropped from certain Pokémon.
|
||||
- Added specific compatibility with Repurposed Structures. (Thank you, TelepathicGrunt!)
|
||||
- Added an evolution method for Karrablast to evolve into Escavalier in single-player mode.
|
||||
- Added crossover paintings from Close Combat: Premonition, Altar, Slumber, and Nomad.
|
||||
- Added Galarica Nuts, used for crafting Galarica Cuffs and Wreaths. Dropped from certain Pokémon. Take a wild guess which.
|
||||
- Added compatibility with Repurposed Structures. (Thank you, TelepathicGrunt!)
|
||||
- Added an evolution method for Karrablast to evolve into Escavalier in singleplayer.
|
||||
- Pokédexes can now be placed in Chiseled Bookshelves.
|
||||
- Added crossover paintings from Close Combat, Premonition, Altar, Slumber, and Nomad.
|
||||
|
||||
### Changes
|
||||
- Pokémon will now be dynamically revealed to the Pokédex as they're seen instead of revealing entire parties at the end of battle regardless.
|
||||
- Unseen wild Pokémon will update their name from '???' to their real name as soon as a battle starts to reflect the battle UI showing the actual species name.
|
||||
- Pokémon under the illusion effect will reveal their disguise to the Pokédex first and then the base Pokémon once the disguise is broken.
|
||||
- Added more support for a variety of Fabric/NeoForge Convention tags.
|
||||
- Reformatted some tags to be more consistent.
|
||||
- Edited some recipes to utilize tags instead of direct item ids, for greater mod compatibility.
|
||||
- Berries will drop if broken at age 0
|
||||
- Improved Fortune drops on Mint Seeds
|
||||
- New Slowpoke shiny texture.
|
||||
- Updated drops for many Pokémon.
|
||||
- Added optional box argument to the /pc command.
|
||||
- Pokédex and Dialogue screens now close when the inventory keybind is pressed.
|
||||
- Added config setting `maxPokedexScanningDetectionRange` to control from what distance the player can scan Pokémon using the Pokédex.
|
||||
- Added config setting `hideUnimplementedPokemonInThePokedex` which hides unimplemented Pokémon from the Pokédex when set to true.
|
||||
- Added debug renderer for posable entity locators.
|
||||
|
||||
### Pokémon Added
|
||||
|
||||
@@ -40,10 +24,19 @@
|
||||
- Escavalier
|
||||
- Rufflet
|
||||
- Braviary
|
||||
- Foongus
|
||||
- Amoonguss
|
||||
|
||||
#### Gen 6
|
||||
- Binacle
|
||||
- Barbaracle
|
||||
|
||||
#### Gen 7
|
||||
- Dewpider
|
||||
- Araquanid
|
||||
- Alolan Geodude
|
||||
- Alolan Graveler
|
||||
- Alolan Golem
|
||||
|
||||
#### Gen 8
|
||||
- Galarian Slowpoke
|
||||
@@ -51,11 +44,18 @@
|
||||
- Galarian Slowking
|
||||
|
||||
#### Gen 9
|
||||
- Paldean Tauros's
|
||||
- Paldean Tauros
|
||||
|
||||
### Added cries to the following Pokémon
|
||||
- All Nidorans
|
||||
- Shellder, Cloyster
|
||||
- Pinsir
|
||||
- Tyrogue, Hitmontop
|
||||
- Spinda
|
||||
|
||||
### Animation updates for the following Pokémon
|
||||
- Primeape
|
||||
- Munchlax
|
||||
- Munchlax
|
||||
- Snorlax
|
||||
- Poliwrath
|
||||
- Goldeen
|
||||
@@ -77,46 +77,60 @@
|
||||
- Slowbro
|
||||
- Slowking
|
||||
- Eiscue
|
||||
- Binacle
|
||||
- Barbaracle
|
||||
- Tauros
|
||||
- Goldeen
|
||||
- Seaking
|
||||
- Charcadet
|
||||
- Armarouge
|
||||
- Ceruledge
|
||||
- Pinsir
|
||||
- Geodude
|
||||
- Graveler
|
||||
- Golem
|
||||
|
||||
### Cry updates for the following Pokémon
|
||||
- Sceptile
|
||||
|
||||
### Changes
|
||||
- Completely re-synced Pokémon move and stat data based on later games. Learnsets have changed considerably to maximise available moves.
|
||||
- Pokémon will now be dynamically revealed to the Pokédex as they're seen in battle instead of revealing entire parties at the end of battle.
|
||||
- Unseen wild Pokémon will update their name from '???' to their real name as soon as a battle starts to match how the battle UI shows the actual species name.
|
||||
- Pokémon under the illusion effect will reveal their disguise to the Pokédex first and then the base Pokémon once the disguise is broken.
|
||||
- Berries will now drop from berry trees if broken at age 0 so you aren't punished for mistaken planting.
|
||||
- Increased Fortune drops on Mint Seeds.
|
||||
- Updated Slowpoke's shiny texture.
|
||||
- Updated drops for many Pokémon.
|
||||
- Adjusted the evolution sound to match the timing of the particle effect.
|
||||
- Made berry trees shear-able by dispenser blocks. I'm sure nobody will make unholy contraptions with this.
|
||||
- Edited some recipes to utilize tags instead of direct item IDs, for better mod compatibility.
|
||||
- Added more support for a variety of Fabric/NeoForge conventional tags.
|
||||
- Reformatted some tags to be more consistent.
|
||||
|
||||
### Fixes
|
||||
- Fixed Pokédex sometimes crashing when switching forms.
|
||||
- Fixed Pokédex interface not transitioning out when closed.
|
||||
- Fixed texture dimensions for the interact interface.
|
||||
- Fixed crash related to Tom's Simple Storage mod and Fossil Machine.
|
||||
- Fixed texture dimensions for the player and Pokémon interact interface.
|
||||
- Fixed crash related to Tom's Simple Storage mod and the Fossil Machine.
|
||||
- Fixed not being able to retrieve a fossil from the Fossil Machine with an empty hand.
|
||||
- Fixed Pokémon being collidable while being captured by a Poké Ball.
|
||||
- Fixed Pokémon being collidable (collidible? collissionable? kaleidoscopable?) while being captured by a Poké Ball.
|
||||
- Fixed `full_party`, `own_zangoose_seviper`, `use_revive` and `use_candy` Advancement triggers.
|
||||
- Fixed `healing_machine` Advancement by using the correct 1.21 trigger.
|
||||
- Fix Display Cases not dropping items if destroyed through explosions.
|
||||
- Fixed an issue where the first Pokémon in the pastured Pokémon list clipped into the interface.
|
||||
- Fixed all Pokémon facing South on spawn.
|
||||
- Parametric particle motion now works.
|
||||
- Event spawned particles now work.
|
||||
- Particles can now have independent coordinate spaces.
|
||||
- Fixed bait being consumed when not reeling in any Pokémon.
|
||||
- Fixed bait being consumed even when not reeling in any Pokémon.
|
||||
- Fixed Miltank milk magically disappearing out of your bucket.
|
||||
- Fixed Pokémon nicknames migrating from 1.5.2 not being displayed properly.
|
||||
- Fixed capitalization in one of our config fields, but allowing typo'd version to still be valid.
|
||||
- Fixed Poké Rods not working if lure or luck of the sea enchantments get removed by other mods.
|
||||
- Fixed crashes related to Pokémon when they are ready to evolve while holding an enchanted item.
|
||||
- Fixed crashes that sometimes occur when evolving Nincada.
|
||||
- Fixed plants not being compostible on NeoForge.
|
||||
- Fixed capitalization in one of our config options. It was a very important fix. Very important. Old configs are fine.
|
||||
- Fixed Poké Rods not working if Lure or Luck of the Sea enchantments get removed by other mods.
|
||||
- Fixed crashes related to Pokémon when they are ready to evolve while holding an enchanted item. Very specific.
|
||||
- Fixed a crash that sometimes occurred when evolving Nincada.
|
||||
- Fixed Cobblemon plants not being compostable on NeoForge.
|
||||
- Fixed hide UI (F1 key) not hiding the party overlay.
|
||||
- Fixed NPC MoLang command `player_lose_command` not working.
|
||||
- Corrected misaligned tooltips with editboxes in the NPC editor screen.
|
||||
- Fixed misaligned tooltips with edit boxes in the NPC editor screen.
|
||||
- Fixed Pokémon riding two boats when attempting to deploy a platform on water.
|
||||
- Made berry trees be shearable by dispenser blocks.
|
||||
- Fixed the summary screen showing there's experience to reach the next level when at level cap.
|
||||
- Fixed the summary screen showing there's experience to reach the next level when they are at the level cap.
|
||||
- Fixed Pokémon forgetting moves when evolving on specific cases.
|
||||
- Fixed Adorn compatibility, including improvements when using JEI/REI (Apricorn items now show up under the collapsed entries rather than standalone).
|
||||
- Fixed error message appearing on battle log when using Solar Beam with Sunny Day.
|
||||
@@ -124,38 +138,68 @@
|
||||
- Fixed `/pokedex grant all` command not giving male/female/shininess completion for some Pokémon.
|
||||
- Fixed `/pokedex grant only` and `/pokedex remove only` not respecting the form parameter passed.
|
||||
- Fixed variant forms appearing incorrectly in the Pokédex when the normal form had not been unlocked.
|
||||
- Fixed Pokémon occasionally being shot into the sky during battle.
|
||||
- Fixed Pokémon occasionally being shot into the sky during battle. No Pokémon were harmed by this bug, probably.
|
||||
- Fixed NPC editing GUI not updating aspects until a game restart.
|
||||
- Fix some users being unable to open their PC if a Pokémon in said PC had a lot of pp raises beyond normal bounds
|
||||
- Fix some color variants (dubwool, conkeldurr and undyed wooloo) missing in the Pokédex
|
||||
- Fix invalid species or held_items causing Players to not be able to load into their world anymore (commonly happening after removing addons/mods)
|
||||
- Fixed some users being unable to open their PC if a Pokémon in it had a lot of PP raises beyond normal bounds. How did you get those, anyway? Tell me or the Bellossom gets it.
|
||||
- Fixed some color variants (Dubwool, Conkeldurr and Undyed wooloo) being missing in the Pokédex.
|
||||
- Fixed invalid species or held items causing Players to not be able to load into their world anymore (commonly happening after removing addons/mods).
|
||||
- Fixed Wooloo variants not being automatically registered in the owner's Pokédex when dyed.
|
||||
- Fixed Vivichoke Dip and Leek and Potato Stew not returning a bowl upon consumption.
|
||||
- Fixed Fossil Restoration Machine not accepting Hay Bales.
|
||||
- Fixed Potion items so that they no longer apply over double their intended healing value.
|
||||
- Fixed Fast Ball capture rate applying to all Pokémon.
|
||||
- Fix "learned new move" messages appearing for already known moves on Pokémon evolutions.
|
||||
- Fix Pokémon Item Models breaking shadows nearby when being placed in Display Cases or Item Frames.
|
||||
- Fixed Vivichoke Dip and Leek & Potato Stew not returning a bowl upon consumption.
|
||||
- Fixed Fossil Restoration Tank not accepting Hay Bales as organic material.
|
||||
- Fixed Potion items applying double their intended healing value.
|
||||
- Fixed Fast Ball capture bonuses applying to all Pokémon, making it the Best Ball instead of the Mediocre Edge-Case Ball.
|
||||
- Fixed "learned new move" messages appearing for already-known moves on Pokémon evolutions.
|
||||
- Fixed Pokémon Item Models breaking shadows nearby when being placed in Display Cases or Item Frames.
|
||||
- Fixed berries not giving bonus yields when planted in their preferred biomes. I'm sure we've fixed that 5 times now.
|
||||
- Fixed the NeoForge version not supporting "SodiumDynamicLights".
|
||||
- Fixed players disconnecting from servers if they made changes to certain config options.
|
||||
- Fixed players with shouldered Pokémon not being able to rejoin their 1.5.2 worlds using 1.6.
|
||||
- Fixed `PokemonProperties` utilizing `ability=<some ability>` being treated as a forced ability even when it is a legal ability for the Pokémon.
|
||||
- Fixed type formatting in Pokédex scanner mode when dual types require two lines.
|
||||
- Fixed trading sometimes crashing the game or server.
|
||||
- Fixed Wild shiny sounds not respecting the `shinyNoticeParticlesDistance` config setting.
|
||||
- Fixed Pokémon being able to evolve mid-battle.
|
||||
- Fixed NPC held items being able to be stolen by players. Don't be a thief!
|
||||
- Fixed evolutions that require a held item consuming it as soon as meeting requirements when it should only be consumed upon evolution.
|
||||
- Fixed Pokémon showing only the default form when selecting them as a target in battle.
|
||||
- Fixed a possible error coming out of reeling fishing rods in specific situations.
|
||||
- Fixed incorrect weights being used when Poké Fishing with Luck of the Sea.
|
||||
- Parametric particle motion now works.
|
||||
- Event-spawned particles now work.
|
||||
- Particles can now have independent coordinate spaces.
|
||||
|
||||
### Molang & Datapacks
|
||||
### Developer
|
||||
- Updated the Pokédex data updated events to always include a `Pokemon` instance, and optionally a `DisguiseData` instance.
|
||||
- Updated fields in `SpawnNPCPacket` and `SpawnPokemonPacket` to be visible and mutable.
|
||||
- Updated `UnvalidatedPlaySoundS2CPacket` to be public instead of internal and made its fields mutable.
|
||||
- Added `hideNameTag` field and `HideNPCNameTag` nbt tag to `NPCEntity` to allow hiding the name tag of the NPC.
|
||||
- Added the player to `PokerodReelEvent` so you know who is doing the reeling.
|
||||
|
||||
### MoLang & Datapacks
|
||||
- Added flows for:
|
||||
- `forme_change`: Triggered when a Pokémon changes form in battle.
|
||||
- `mega_evolution`: Triggered when a Pokémon mega evolves in battle. (Note: Third party mods are required for this feature currently)
|
||||
- `zpower_used`: Triggered when a Pokémon uses a Z-Power move in battle. (Note: Third party mods are required for this feature currently)
|
||||
- `terastallization`: Triggered when a Pokémon terastallizes in battle. (Note: Third party mods are required for this feature currently)
|
||||
- `mega_evolution`: Triggered when a Pokémon mega evolves in battle. (Note: Third-party mods are required for this feature currently)
|
||||
- `zpower_used`: Triggered when a Pokémon uses a Z-Power move in battle. (Note: Third-party mods are required for this feature currently)
|
||||
- `terastallization`: Triggered when a Pokémon terastallizes in battle. (Note: Third-party mods are required for this feature currently)
|
||||
- `battle_fainted`: Triggered when a Pokémon faints in battle.
|
||||
- `battle_fled`: Triggered when a Player flees from battle.
|
||||
- `battle_fled`: Triggered when a player flees from battle.
|
||||
- `battle_started_pre`: Triggered when a battle starts. Cancelable!
|
||||
- `battle_started_post`: Triggered when a battle starts.
|
||||
- `apricorn_harvested`: Triggered when an apricorn is harvested.
|
||||
- `apricorn_harvested`: Triggered when an Apricorn is harvested.
|
||||
- `thrown_pokeball_hit`: Triggered when a thrown Pokéball hits a Pokémon.
|
||||
- `level_up`: Triggered when a Pokémon levels up.
|
||||
- `pokemon_fainted`: Triggered when a Pokémon faints.
|
||||
- `pokemon_gained`: Triggered when a Player gains a Pokémon.
|
||||
- Added molang functions:
|
||||
- `pokemon_gained`: Triggered when a player gains a Pokémon.
|
||||
- Added MoLang functions:
|
||||
- For Pokémon:
|
||||
- `pokemon.apply(PokemonProperties)`: Applies the given properties to the Pokémon.
|
||||
- `pokemon.owner`: Returns the owner of the Pokémon or 0.0 if there is no owner or they are not online.
|
||||
- For all entities:
|
||||
- `entity.is_standing_on_blocks(depth, blocks...)`: Returns whether the specified entity is standing on a specific block or set of blocks. Example usage: `q.is_standing_on_blocks(2, minecraft:sand)`
|
||||
- Added NPC field:
|
||||
- `hideNameTag`: Hides the name tag of the NPC.
|
||||
- Added `baseScale` property to NPCs.
|
||||
- Added MoLang particle queries for getting distance to targeted entities.
|
||||
|
||||
## [1.6.0 - The Record Catch Update (December 25th, 2024)](#1-6-0)
|
||||
#### "Now that there's a fishing mechanic, the mod is actually good!"
|
||||
@@ -2058,5 +2102,4 @@ Thank you so much to all of our community translators that bring the mod to the
|
||||
- Added species, ability, and move translations for `ko_ko`, `jp_jp`, `fr_fr`, `es_es`, `it_it`, and `zh_cn`.
|
||||
|
||||
## [1.0.0 (November 12th, 2022)](#1-0-0)
|
||||
- Initial release.
|
||||
|
||||
- Initial release.
|
||||
@@ -14,6 +14,7 @@ import com.cobblemon.mod.common.api.events.CobblemonEvents;
|
||||
import com.cobblemon.mod.common.api.events.item.LeftoversCreatedEvent;
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies;
|
||||
import com.cobblemon.mod.common.api.storage.party.PartyStore;
|
||||
import com.cobblemon.mod.common.api.storage.party.PlayerPartyStore;
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags;
|
||||
import com.cobblemon.mod.common.pokedex.scanner.PokedexEntityData;
|
||||
import com.cobblemon.mod.common.pokedex.scanner.ScannableEntity;
|
||||
@@ -178,10 +179,10 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
|
||||
@Override @Nullable
|
||||
public PokedexEntityData resolvePokemonScan() {
|
||||
if(CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityRight())){
|
||||
if (CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityRight())){
|
||||
return getDataFromShoulderPokemon(this.getShoulderEntityRight());
|
||||
}
|
||||
if(CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityLeft())){
|
||||
if (CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityLeft())){
|
||||
return getDataFromShoulderPokemon(this.getShoulderEntityLeft());
|
||||
}
|
||||
return null;
|
||||
@@ -190,30 +191,34 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
@Nullable @Unique
|
||||
private PokedexEntityData getDataFromShoulderPokemon(CompoundTag shoulderTag) {
|
||||
CompoundTag pokemonTag = shoulderTag.getCompound(DataKeys.POKEMON);
|
||||
if(pokemonTag.isEmpty()) return null;
|
||||
if (pokemonTag.isEmpty()) return null;
|
||||
Species species = PokemonSpecies.INSTANCE.getByIdentifier(ResourceLocation.parse(pokemonTag.getString(DataKeys.POKEMON_SPECIES_IDENTIFIER)));
|
||||
if(species == null) return null;
|
||||
if (species == null) return null;
|
||||
String formId = pokemonTag.getString(DataKeys.POKEMON_FORM_ID);
|
||||
FormData form = species.getStandardForm();
|
||||
List<FormData> formList = species.getForms().stream().filter(it -> it.formOnlyShowdownId().equals(formId)).toList();
|
||||
if(!formList.isEmpty()) form = formList.getFirst();
|
||||
if(form == null) return null;
|
||||
if (!formList.isEmpty()) form = formList.getFirst();
|
||||
if (form == null) return null;
|
||||
String genderString = pokemonTag.getString(DataKeys.POKEMON_GENDER);
|
||||
if(genderString.isEmpty()) return null;
|
||||
if (genderString.isEmpty()) return null;
|
||||
Gender gender = Gender.valueOf(genderString);
|
||||
boolean shiny = pokemonTag.getBoolean(DataKeys.POKEMON_SHINY);
|
||||
int level = pokemonTag.getInt(DataKeys.POKEMON_LEVEL);
|
||||
Set<String> aspects = shoulderTag.getList(DataKeys.SHOULDER_ASPECTS, Tag.TAG_STRING).stream().map(Tag::getAsString).collect(Collectors.toSet());
|
||||
|
||||
return new PokedexEntityData(
|
||||
species,
|
||||
form,
|
||||
gender,
|
||||
aspects,
|
||||
shiny,
|
||||
level,
|
||||
this.getUUID()
|
||||
);
|
||||
Pokemon pokemon = new Pokemon();
|
||||
if (level().isClientSide) {
|
||||
pokemon.setSpecies(species);
|
||||
pokemon.setForm(form);
|
||||
pokemon.setGender(gender);
|
||||
pokemon.setShiny(shiny);
|
||||
pokemon.setLevel(level);
|
||||
pokemon.setForcedAspects(aspects);
|
||||
} else {
|
||||
PlayerPartyStore party = Cobblemon.INSTANCE.getStorage().getParty(this.getUUID(), this.registryAccess());
|
||||
pokemon = party.get(shoulderTag.getUUID(DataKeys.SHOULDER_UUID));
|
||||
}
|
||||
return new PokedexEntityData(pokemon, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -221,7 +221,7 @@ object Cobblemon {
|
||||
storage.onPlayerDataSync(it)
|
||||
playerDataManager.syncAllToPlayer(it)
|
||||
starterHandler.handleJoin(it)
|
||||
ServerSettingsPacket(this.config.preventCompletePartyDeposit, this.config.displayEntityLevelLabel, this.config.displayEntityNameLabel, this.config.maxPokemonLevel).sendToPlayer(it)
|
||||
ServerSettingsPacket(this.config.preventCompletePartyDeposit, this.config.displayEntityLevelLabel, this.config.displayEntityNameLabel, this.config.maxPokemonLevel, this.config.maxPokemonFriendship, this.config.maxDynamaxLevel).sendToPlayer(it)
|
||||
}
|
||||
PlatformEvents.SERVER_PLAYER_LOGOUT.subscribe {
|
||||
PCLinkManager.removeLink(it.player.uuid)
|
||||
@@ -259,6 +259,8 @@ object Cobblemon {
|
||||
// Lowest priority because this applies after luxury ball bonus as of gen 4
|
||||
CobblemonEvents.FRIENDSHIP_UPDATED.subscribe(Priority.LOWEST) { event ->
|
||||
var increment = (event.newFriendship - event.pokemon.friendship).toFloat()
|
||||
if (increment <= 0) //these affects are only meant to affect positive gains
|
||||
return@subscribe
|
||||
// Our Luxury ball spec is diff from official, but we will still assume these stack
|
||||
if (event.pokemon.heldItemNoCopy().`is`(CobblemonItemTags.IS_FRIENDSHIP_BOOSTER)) {
|
||||
increment += increment * 0.5F
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.ai
|
||||
|
||||
/**
|
||||
* The medium that an entity might be in which motivates what type of wandering it should do.
|
||||
*
|
||||
* If you've discovered this in main and it's not being used outside of that unused extension function, delete me
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since January 25th, 2025
|
||||
*/
|
||||
enum class PathfindingMedium {
|
||||
LAND,
|
||||
WATER,
|
||||
LAVA,
|
||||
AIR
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.config.task.WanderTaskConfig.Companion.WANDER
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.entity.ai.util.AirAndWaterRandomPos
|
||||
|
||||
class AirWanderTaskConfig : SingleTaskConfig {
|
||||
val condition = booleanVariable(WANDER, "air_wanders", true).asExpressible()
|
||||
val wanderChance = numberVariable(WANDER, "air_wander_chance", 1/(20 * 1F)).asExpressible()
|
||||
val horizontalRange = numberVariable(WANDER, "horizontal_wander_range", 20).asExpressible()
|
||||
val verticalRange = numberVariable(WANDER, "vertical_wander_range", 5).asExpressible()
|
||||
val speedMultiplier = numberVariable(SharedEntityVariables.MOVEMENT_CATEGORY, SharedEntityVariables.WALK_SPEED, 0.35).asExpressible()
|
||||
|
||||
|
||||
override fun getVariables(entity: LivingEntity): List<MoLangConfigVariable> {
|
||||
return listOf(condition, wanderChance, horizontalRange, verticalRange, speedMultiplier).asVariables()
|
||||
}
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.absent(MemoryModuleType.WALK_TARGET),
|
||||
it.registered(MemoryModuleType.LOOK_TARGET)
|
||||
).apply(it) { walkTarget, lookTarget ->
|
||||
Trigger { world, entity, time ->
|
||||
if (entity !is PathfinderMob || entity.isInWater) {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
val wanderChance = wanderChance.resolveFloat()
|
||||
if (wanderChance <= 0 || world.random.nextFloat() > wanderChance) return@Trigger false
|
||||
|
||||
val target = AirAndWaterRandomPos.getPos(entity, horizontalRange.resolveInt(), verticalRange.resolveInt(), 2, entity.lookAngle.x, entity.lookAngle.z, 2 * Math.PI)
|
||||
if (target != null) {
|
||||
walkTarget.set(WalkTarget(target, speedMultiplier.resolveFloat(), 3))
|
||||
lookTarget.set(BlockPosTracker(target))
|
||||
return@Trigger true
|
||||
}
|
||||
return@Trigger false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,8 @@ interface TaskConfig {
|
||||
val types = mutableMapOf<String, Class<out TaskConfig>>(
|
||||
"one_of" to OneOfTaskConfig::class.java,
|
||||
"wander" to WanderTaskConfig::class.java,
|
||||
"water_wander" to WaterWanderTaskConfig::class.java,
|
||||
"air_wander" to AirWanderTaskConfig::class.java,
|
||||
"look_at_target" to LookAtTargetTaskConfig::class.java,
|
||||
"follow_walk_target" to FollowWalkTargetTaskConfig::class.java,
|
||||
"random" to RandomTaskConfig::class.java,
|
||||
|
||||
+1
-1
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.api.ai.config.task
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
@@ -64,7 +65,6 @@ class WanderTaskConfig : SingleTaskConfig {
|
||||
val wanderChance = wanderChance.resolveFloat()
|
||||
if (wanderChance <= 0 || world.random.nextFloat() > wanderChance) return@Trigger false
|
||||
|
||||
// RandomStroll.stroll(speedMultiplier.resolveFloat(), horizontalRange.resolveInt(), verticalRange.resolveInt())
|
||||
val targetVec = LandRandomPos.getPos(entity, horizontalRange.resolveInt(), verticalRange.resolveInt(), { 0.0 }) ?: return@Trigger false
|
||||
walkTarget.set(WalkTarget(targetVec, speedMultiplier.resolveFloat(), 1))
|
||||
lookTarget.set(BlockPosTracker(targetVec.add(0.0, entity.eyeHeight.toDouble(), 0.0)))
|
||||
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.config.task.WanderTaskConfig.Companion.WANDER
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
|
||||
import net.minecraft.world.entity.ai.behavior.RandomStroll
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
|
||||
class WaterWanderTaskConfig : SingleTaskConfig {
|
||||
val condition = booleanVariable(WANDER, "water_wanders", true).asExpressible()
|
||||
val wanderChance = numberVariable(WANDER, "water_wander_chance", 1/(20 * 3F)).asExpressible()
|
||||
val speedMultiplier = numberVariable(SharedEntityVariables.MOVEMENT_CATEGORY, SharedEntityVariables.WALK_SPEED, 0.35).asExpressible()
|
||||
|
||||
|
||||
override fun getVariables(entity: LivingEntity): List<MoLangConfigVariable> {
|
||||
return listOf(condition, wanderChance, speedMultiplier).asVariables()
|
||||
}
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.absent(MemoryModuleType.WALK_TARGET),
|
||||
it.registered(MemoryModuleType.LOOK_TARGET)
|
||||
).apply(it) { walkTarget, lookTarget ->
|
||||
Trigger { world, entity, time ->
|
||||
if (entity !is PathfinderMob || !entity.isUnderWater) {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
val wanderChance = wanderChance.resolveFloat()
|
||||
if (wanderChance <= 0 || world.random.nextFloat() > wanderChance) return@Trigger false
|
||||
|
||||
val target = RandomStroll.getTargetSwimPos(entity)
|
||||
if (target != null) {
|
||||
walkTarget.set(WalkTarget(target, speedMultiplier.resolveFloat(), 1))
|
||||
lookTarget.set(BlockPosTracker(target))
|
||||
return@Trigger true
|
||||
}
|
||||
return@Trigger false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -95,8 +95,6 @@ class DropTable {
|
||||
pokemon: Pokemon? = null,
|
||||
) {
|
||||
val drops = getDrops(amount, pokemon).toMutableList()
|
||||
val heldItem = (entity as PokemonEntity?)?.pokemon?.heldItemNoCopy() ?: ItemStack.EMPTY
|
||||
if (!heldItem.isEmpty) entity?.spawnAtLocation(heldItem.item)
|
||||
LOOT_DROPPED.postThen(
|
||||
event = LootDroppedEvent(this, player, entity, drops),
|
||||
ifSucceeded = { it.drops.forEach { it.drop(entity, world, pos, player) } }
|
||||
|
||||
+4
-6
@@ -18,19 +18,17 @@ import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
data class PokemonScannedEvent(val player: ServerPlayer, val scannedPokemonEntityData: PokedexEntityData, val scannedEntity: ScannableEntity) {
|
||||
val pokedexEntityData: PokedexEntityData
|
||||
get() = scannedPokemonEntityData
|
||||
|
||||
val isOwned: Boolean
|
||||
get() = scannedPokemonEntityData.ownerUUID == player.uuid
|
||||
get() = scannedPokemonEntityData.pokemon.getOwnerUUID() == player.uuid
|
||||
|
||||
val context = mutableMapOf(
|
||||
"player" to player.asMoLangValue(),
|
||||
"pokemon" to scannedPokemonEntityData.struct,
|
||||
"pokemon" to scannedPokemonEntityData.pokemon.struct,
|
||||
"disguise" to (scannedPokemonEntityData.disguise?.struct ?: DoubleValue.ZERO),
|
||||
"entity" to {
|
||||
when (scannedEntity) {
|
||||
is LivingEntity -> scannedEntity.asMostSpecificMoLangValue()
|
||||
else -> DoubleValue(0.0)
|
||||
else -> DoubleValue.ZERO
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
+9
-2
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.events.pokemon
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
|
||||
/**
|
||||
@@ -18,5 +19,11 @@ import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
*/
|
||||
data class FriendshipUpdatedEvent(
|
||||
val pokemon: Pokemon,
|
||||
var newFriendship: Int
|
||||
)
|
||||
val newFriendshipInitial: Int
|
||||
)
|
||||
{
|
||||
var newFriendship: Int = newFriendshipInitial
|
||||
set(value) {
|
||||
field = value.coerceIn(0, Cobblemon.config.maxPokemonFriendship)
|
||||
}
|
||||
}
|
||||
+5
-7
@@ -17,16 +17,14 @@ import com.cobblemon.mod.common.api.pokedex.AbstractPokedexManager
|
||||
import com.cobblemon.mod.common.api.pokedex.FormDexRecord
|
||||
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
|
||||
import com.cobblemon.mod.common.pokedex.scanner.PokedexEntityData
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.getPlayer
|
||||
import com.mojang.datafixers.util.Either
|
||||
import java.util.UUID
|
||||
|
||||
/**
|
||||
* Event that fires when a Pokémon's information is gained or updated in the Pokédex.
|
||||
*/
|
||||
sealed interface PokedexDataChangedEvent {
|
||||
val dataSource: Either<PokedexEntityData, Pokemon>
|
||||
val dataSource: PokedexEntityData
|
||||
val knowledge: PokedexEntryProgress
|
||||
val playerUUID: UUID
|
||||
val record: FormDexRecord
|
||||
@@ -37,22 +35,22 @@ sealed interface PokedexDataChangedEvent {
|
||||
fun getContext(): MutableMap<String, MoValue> {
|
||||
return mutableMapOf(
|
||||
"player" to (playerUUID.getPlayer()?.asMoLangValue() ?: DoubleValue.ZERO),
|
||||
"pokemon" to dataSource.map({ DoubleValue.ZERO }, { it.struct }),
|
||||
"data" to dataSource.map({ it.struct }, { DoubleValue.ZERO }),
|
||||
"pokemon" to dataSource.pokemon.struct,
|
||||
"disguise" to (dataSource.disguise?.struct ?: DoubleValue.ZERO),
|
||||
"knowledge" to StringValue(knowledge.name.lowercase()),
|
||||
"pokedex" to pokedexManager.struct
|
||||
)
|
||||
}
|
||||
|
||||
class Pre(
|
||||
override val dataSource: Either<PokedexEntityData, Pokemon>,
|
||||
override val dataSource: PokedexEntityData,
|
||||
override val knowledge: PokedexEntryProgress,
|
||||
override val playerUUID: UUID,
|
||||
override val record: FormDexRecord
|
||||
) : PokedexDataChangedEvent, Cancelable()
|
||||
|
||||
class Post(
|
||||
override val dataSource: Either<PokedexEntityData, Pokemon>,
|
||||
override val dataSource: PokedexEntityData,
|
||||
override val knowledge: PokedexEntryProgress,
|
||||
override val playerUUID: UUID,
|
||||
override val record: FormDexRecord
|
||||
|
||||
@@ -732,6 +732,8 @@ object MoLangFunctions {
|
||||
map.put("max_hp") { DoubleValue(pokemon.maxHealth.toDouble()) }
|
||||
map.put("current_hp") { DoubleValue(pokemon.currentHealth.toDouble()) }
|
||||
map.put("friendship") { DoubleValue(pokemon.friendship.toDouble()) }
|
||||
map.put("behaviour") { pokemon.form.behaviour.struct }
|
||||
map.put("behavior") { pokemon.form.behaviour.struct } // Inferior
|
||||
map.put("evs") {
|
||||
val struct = QueryStruct(hashMapOf())
|
||||
for (stat in Stats.PERMANENT) {
|
||||
|
||||
@@ -57,6 +57,7 @@ class NPCClass {
|
||||
var isInvulnerable = false
|
||||
var isLeashable = true
|
||||
var allowProjectileHits = true
|
||||
var hideNameTag = false
|
||||
|
||||
// If you're adding stuff here, add it to NPCPreset and NPCClassAdapter too
|
||||
|
||||
@@ -98,6 +99,7 @@ class NPCClass {
|
||||
buffer.writeBoolean(isInvulnerable)
|
||||
buffer.writeBoolean(isLeashable)
|
||||
buffer.writeBoolean(allowProjectileHits)
|
||||
buffer.writeBoolean(hideNameTag)
|
||||
}
|
||||
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
@@ -150,5 +152,6 @@ class NPCClass {
|
||||
isInvulnerable = buffer.readBoolean()
|
||||
isLeashable = buffer.readBoolean()
|
||||
allowProjectileHits = buffer.readBoolean()
|
||||
hideNameTag = buffer.readBoolean()
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,7 @@ class NPCPreset {
|
||||
var isInvulnerable: Boolean? = null
|
||||
var isLeashable: Boolean? = null
|
||||
var allowProjectileHits: Boolean? = null
|
||||
var hideNameTag: Boolean? = null
|
||||
|
||||
fun applyTo(npcClass: NPCClass) {
|
||||
resourceIdentifier?.let { npcClass.resourceIdentifier = it }
|
||||
@@ -63,5 +64,6 @@ class NPCPreset {
|
||||
isInvulnerable?.let { npcClass.isInvulnerable = it }
|
||||
isLeashable?.let { npcClass.isLeashable = it }
|
||||
allowProjectileHits?.let { npcClass.allowProjectileHits = it }
|
||||
hideNameTag?.let { npcClass.hideNameTag = it }
|
||||
}
|
||||
}
|
||||
@@ -78,6 +78,7 @@ any number of presets and the properties of those presets will be merged into th
|
||||
"skill": 5,
|
||||
"autoHealParty": true,
|
||||
"randomizePartyOrder": true,
|
||||
"hideNameTag": false,
|
||||
"party": {
|
||||
"type": "simple",
|
||||
"pokemon": [
|
||||
@@ -411,4 +412,7 @@ Pokémon in the party.
|
||||
|
||||
### ai
|
||||
The AI property is an array of brain configurations. This is used to configure the behaviours of the NPC. See
|
||||
the documentation for brain configurations at [AI Configuration](../ai/config/README.md).
|
||||
the documentation for brain configurations at [AI Configuration](../ai/config/README.md).
|
||||
|
||||
### hideNameTag
|
||||
Whether the NPC's nametag should be hidden or not. Defaults to false.
|
||||
@@ -202,6 +202,8 @@ object PokeBalls : JsonDataRegistry<PokeBall> {
|
||||
// Luxury ball effect, low priority as it must be triggered before soothe bell as of gen 4
|
||||
CobblemonEvents.FRIENDSHIP_UPDATED.subscribe(priority = Priority.LOW) { event ->
|
||||
var increment = (event.newFriendship - event.pokemon.friendship).toFloat()
|
||||
if (increment <= 0) //these affects are only meant to affect positive gains
|
||||
return@subscribe
|
||||
if (increment <= 1F) {
|
||||
event.pokemon.caughtBall.effects.filterIsInstance<FriendshipEarningBoostEffect>()
|
||||
.forEach { increment *= it.multiplier }
|
||||
|
||||
+9
-3
@@ -96,15 +96,21 @@ abstract class AbstractPokedexManager {
|
||||
}
|
||||
|
||||
fun getNewInformation(pokedexEntityData: PokedexEntityData): PokedexLearnedInformation {
|
||||
val speciesRecord = getSpeciesRecord(pokedexEntityData.species.resourceIdentifier)
|
||||
val speciesRecord = getSpeciesRecord(pokedexEntityData.getApparentSpecies().resourceIdentifier)
|
||||
if (speciesRecord == null || speciesRecord.getKnowledge() == PokedexEntryProgress.NONE) {
|
||||
return PokedexLearnedInformation.SPECIES
|
||||
}
|
||||
val formRecord = speciesRecord.getFormRecord(pokedexEntityData.form.name)
|
||||
val formRecord = speciesRecord.getFormRecord(pokedexEntityData.getApparentForm().name)
|
||||
if (formRecord == null || formRecord.knowledge == PokedexEntryProgress.NONE) {
|
||||
return PokedexLearnedInformation.FORM
|
||||
}
|
||||
if (pokedexEntityData.aspects.any{ !speciesRecord.hasAspect(it) } || pokedexEntityData.gender !in formRecord.getGenders() || !formRecord.hasSeenShinyState(pokedexEntityData.shiny)) {
|
||||
|
||||
// Can't update aspects on a disguise
|
||||
if (pokedexEntityData.disguise != null) {
|
||||
return PokedexLearnedInformation.NONE
|
||||
}
|
||||
|
||||
if (pokedexEntityData.pokemon.aspects.any { !speciesRecord.hasAspect(it) } || pokedexEntityData.pokemon.gender !in formRecord.getGenders() || !formRecord.hasSeenShinyState(pokedexEntityData.pokemon.shiny)) {
|
||||
return PokedexLearnedInformation.VARIATION
|
||||
}
|
||||
return PokedexLearnedInformation.NONE
|
||||
|
||||
@@ -89,21 +89,15 @@ class FormDexRecord {
|
||||
it.knowledge = knowledge
|
||||
}
|
||||
|
||||
fun encountered(pokemon: Pokemon) {
|
||||
if (wouldBeDifferent(pokemon, PokedexEntryProgress.ENCOUNTERED)) {
|
||||
addInformation(pokemon, PokedexEntryProgress.ENCOUNTERED)
|
||||
}
|
||||
}
|
||||
|
||||
fun encountered(pokedexEntityData: PokedexEntityData) {
|
||||
if (wouldBeDifferent(pokedexEntityData, PokedexEntryProgress.ENCOUNTERED)) {
|
||||
addInformation(pokedexEntityData, PokedexEntryProgress.ENCOUNTERED)
|
||||
}
|
||||
}
|
||||
|
||||
fun caught(pokemon: Pokemon) {
|
||||
if (wouldBeDifferent(pokemon, PokedexEntryProgress.CAUGHT)) {
|
||||
addInformation(pokemon, PokedexEntryProgress.CAUGHT)
|
||||
fun caught(pokedexEntityData: PokedexEntityData) {
|
||||
if (wouldBeDifferent(pokedexEntityData, PokedexEntryProgress.CAUGHT)) {
|
||||
addInformation(pokedexEntityData, PokedexEntryProgress.CAUGHT)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,47 +119,18 @@ class FormDexRecord {
|
||||
speciesDexRecord.onFormRecordUpdated(this)
|
||||
}
|
||||
|
||||
private fun addInformation(pokemon: Pokemon, knowledge: PokedexEntryProgress) {
|
||||
(speciesDexRecord.pokedexManager as? PokedexManager)?.let { pokedexManager ->
|
||||
CobblemonEvents.POKEDEX_DATA_CHANGED_PRE.postThen(
|
||||
PokedexDataChangedEvent.Pre(
|
||||
Either.right(pokemon),
|
||||
knowledge,
|
||||
pokedexManager.uuid,
|
||||
this
|
||||
),
|
||||
ifSucceeded = {
|
||||
genders.add(pokemon.gender)
|
||||
seenShinyStates.add(if (pokemon.shiny) "shiny" else "normal")
|
||||
if (knowledge.ordinal > this.knowledge.ordinal) {
|
||||
this.knowledge = knowledge
|
||||
}
|
||||
speciesDexRecord.addInformation(pokemon, knowledge)
|
||||
speciesDexRecord.onFormRecordUpdated(this)
|
||||
CobblemonEvents.POKEDEX_DATA_CHANGED_POST.post(
|
||||
PokedexDataChangedEvent.Post(
|
||||
Either.right(pokemon),
|
||||
knowledge,
|
||||
pokedexManager.uuid,
|
||||
this
|
||||
)
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun addInformation(pokedexEntityData: PokedexEntityData, knowledge: PokedexEntryProgress) {
|
||||
(speciesDexRecord.pokedexManager as? PokedexManager)?.let { pokedexManager ->
|
||||
CobblemonEvents.POKEDEX_DATA_CHANGED_PRE.postThen(
|
||||
PokedexDataChangedEvent.Pre(
|
||||
Either.left(pokedexEntityData),
|
||||
knowledge,
|
||||
pokedexManager.uuid,
|
||||
this
|
||||
pokedexEntityData,
|
||||
knowledge,
|
||||
pokedexManager.uuid,
|
||||
this
|
||||
),
|
||||
ifSucceeded = {
|
||||
genders.add(pokedexEntityData.gender)
|
||||
seenShinyStates.add(if (pokedexEntityData.shiny) "shiny" else "normal")
|
||||
genders.add(pokedexEntityData.pokemon.gender)
|
||||
seenShinyStates.add(if (pokedexEntityData.pokemon.shiny) "shiny" else "normal")
|
||||
if (knowledge.ordinal > this.knowledge.ordinal) {
|
||||
this.knowledge = knowledge
|
||||
}
|
||||
@@ -173,10 +138,10 @@ class FormDexRecord {
|
||||
speciesDexRecord.onFormRecordUpdated(this)
|
||||
CobblemonEvents.POKEDEX_DATA_CHANGED_POST.post(
|
||||
PokedexDataChangedEvent.Post(
|
||||
Either.left(pokedexEntityData),
|
||||
knowledge,
|
||||
pokedexManager.uuid,
|
||||
this
|
||||
pokedexEntityData,
|
||||
knowledge,
|
||||
pokedexManager.uuid,
|
||||
this
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -184,19 +149,10 @@ class FormDexRecord {
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns whether the given [Pokemon] and [knowledge] would add new information to the Pokédex.*/
|
||||
fun wouldBeDifferent(pokemon: Pokemon, knowledge: PokedexEntryProgress): Boolean {
|
||||
return pokemon.gender !in genders
|
||||
|| (pokemon.shiny && "shiny" !in seenShinyStates)
|
||||
|| (!pokemon.shiny && "normal" !in seenShinyStates)
|
||||
|| knowledge.ordinal > this.knowledge.ordinal
|
||||
|| speciesDexRecord.wouldBeDifferent(pokemon)
|
||||
}
|
||||
|
||||
fun wouldBeDifferent(pokedexEntityData: PokedexEntityData, knowledge: PokedexEntryProgress): Boolean {
|
||||
return pokedexEntityData.gender !in genders
|
||||
|| (pokedexEntityData.shiny && "shiny" !in seenShinyStates)
|
||||
|| (!pokedexEntityData.shiny && "normal" !in seenShinyStates)
|
||||
return pokedexEntityData.pokemon.gender !in genders
|
||||
|| (pokedexEntityData.pokemon.shiny && "shiny" !in seenShinyStates)
|
||||
|| (!pokedexEntityData.pokemon.shiny && "normal" !in seenShinyStates)
|
||||
|| knowledge.ordinal > this.knowledge.ordinal
|
||||
|| speciesDexRecord.wouldBeDifferent(pokedexEntityData)
|
||||
}
|
||||
|
||||
@@ -30,19 +30,19 @@ class PokedexManager(
|
||||
fun encounter(pokemon: Pokemon) {
|
||||
val speciesId = pokemon.species.resourceIdentifier
|
||||
val formName = pokemon.form.name
|
||||
getOrCreateSpeciesRecord(speciesId).getOrCreateFormRecord(formName).encountered(pokemon)
|
||||
getOrCreateSpeciesRecord(speciesId).getOrCreateFormRecord(formName).encountered(PokedexEntityData(pokemon = pokemon, disguise = null))
|
||||
}
|
||||
|
||||
fun encounter(pokedexEntityData: PokedexEntityData) {
|
||||
val speciesId = pokedexEntityData.species.resourceIdentifier
|
||||
val formName = pokedexEntityData.form.name
|
||||
val speciesId = pokedexEntityData.getApparentSpecies().resourceIdentifier
|
||||
val formName = pokedexEntityData.getApparentForm().name
|
||||
getOrCreateSpeciesRecord(speciesId).getOrCreateFormRecord(formName).encountered(pokedexEntityData)
|
||||
}
|
||||
|
||||
fun catch(pokemon: Pokemon) {
|
||||
val speciesId = pokemon.species.resourceIdentifier
|
||||
val formName = pokemon.form.name
|
||||
getOrCreateSpeciesRecord(speciesId).getOrCreateFormRecord(formName).caught(pokemon)
|
||||
getOrCreateSpeciesRecord(speciesId).getOrCreateFormRecord(formName).caught(PokedexEntityData(pokemon = pokemon, disguise = null))
|
||||
}
|
||||
|
||||
override fun markDirty() {
|
||||
|
||||
@@ -97,7 +97,7 @@ class SpeciesDexRecord {
|
||||
}
|
||||
|
||||
fun addInformation(pokedexEntityData: PokedexEntityData, knowledge: PokedexEntryProgress) {
|
||||
aspects.addAll(pokedexEntityData.aspects)
|
||||
aspects.addAll(pokedexEntityData.pokemon.aspects)
|
||||
}
|
||||
|
||||
fun addAspects(addedAspects: Set<String>) {
|
||||
@@ -107,7 +107,7 @@ class SpeciesDexRecord {
|
||||
/** Returns true if the given Pokémon contains new information. Internal because it's only to be called from [FormDexRecord.wouldBeDifferent]. */
|
||||
internal fun wouldBeDifferent(pokemon: Pokemon) = pokemon.aspects.any { it !in aspects }
|
||||
|
||||
internal fun wouldBeDifferent(pokedexEntityData: PokedexEntityData) = pokedexEntityData.aspects.any { it !in aspects }
|
||||
internal fun wouldBeDifferent(pokedexEntityData: PokedexEntityData) = pokedexEntityData.pokemon.aspects.any { it !in aspects }
|
||||
|
||||
fun getOrCreateFormRecord(formName: String): FormDexRecord {
|
||||
return formRecords.getOrPut(formName.lowercase()) {
|
||||
|
||||
@@ -809,7 +809,7 @@ open class PokemonProperties {
|
||||
private fun createAbility(id: String, form: FormData): Ability? {
|
||||
val ability = Abilities.get(id) ?: return null
|
||||
val potentialAbility = form.abilities.firstOrNull { potential -> potential.template == ability } ?: return ability.create(true)
|
||||
return potentialAbility.template.create(false)
|
||||
return potentialAbility.template.create(false, potentialAbility.priority)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -105,9 +105,6 @@ interface Evolution : EvolutionLike {
|
||||
* @param pokemon The [Pokemon] being evolved.
|
||||
*/
|
||||
fun evolve(pokemon: Pokemon): Boolean {
|
||||
if (this.consumeHeldItem) {
|
||||
pokemon.swapHeldItem(ItemStack.EMPTY)
|
||||
}
|
||||
if (this.optional) {
|
||||
// All the networking is handled under the hood, see EvolutionController.
|
||||
return pokemon.evolutionProxy.server().add(this)
|
||||
@@ -223,6 +220,10 @@ interface Evolution : EvolutionLike {
|
||||
|
||||
this.shed(pokemon)
|
||||
|
||||
if (this.consumeHeldItem) {
|
||||
pokemon.swapHeldItem(ItemStack.EMPTY)
|
||||
}
|
||||
|
||||
val ownerPlayer = pokemon.getOwnerPlayer()
|
||||
if (ownerPlayer != null && ownerPlayer.level().gameRules.getBoolean(CobblemonGameRules.DO_POKEMON_LOOT)) {
|
||||
drops.drop(
|
||||
|
||||
@@ -53,7 +53,7 @@ enum class Stats(override val identifier: ResourceLocation, override val display
|
||||
fun getStat(statKey: String) = when(statKey.lowercase()) {
|
||||
"hp" -> HP
|
||||
"atk", "attack" -> ATTACK // Hyper Cutter states the full stat name "Attack"
|
||||
"def", "defense" -> DEFENCE // Big Pecks states the full stat name "Defense"
|
||||
"def", "defense", "defence" -> DEFENCE // Big Pecks states the full stat name "Defense"
|
||||
"spa" -> SPECIAL_ATTACK
|
||||
"spd" -> SPECIAL_DEFENCE
|
||||
"spe", "speed" -> SPEED
|
||||
|
||||
+2
-6
@@ -10,15 +10,12 @@ package com.cobblemon.mod.common.api.spawning.fishing
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.api.Priority
|
||||
import com.cobblemon.mod.common.api.abilities.Abilities
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.fishing.BobberSpawnPokemonEvent
|
||||
import com.cobblemon.mod.common.api.fishing.FishingBait
|
||||
import com.cobblemon.mod.common.api.pokemon.Natures
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.api.pokemon.egg.EggGroup
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stat
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnCause
|
||||
@@ -27,7 +24,6 @@ import com.cobblemon.mod.common.api.spawning.detail.PokemonSpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.cobblemon.mod.common.api.types.tera.TeraTypes
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.item.interactive.PokerodItem
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
@@ -129,8 +125,8 @@ class FishingSpawnCause(
|
||||
}
|
||||
|
||||
fun alterFriendshipAttempt(pokemonEntity: PokemonEntity, effect: FishingBait.Effect) {
|
||||
if (pokemonEntity.pokemon.friendship + effect.value > 255)
|
||||
pokemonEntity.pokemon.setFriendship(255)
|
||||
if (pokemonEntity.pokemon.friendship + effect.value > Cobblemon.config.maxPokemonFriendship)
|
||||
pokemonEntity.pokemon.setFriendship(Cobblemon.config.maxPokemonFriendship)
|
||||
else
|
||||
pokemonEntity.pokemon.setFriendship(pokemonEntity.pokemon.friendship + effect.value.toInt())
|
||||
}
|
||||
|
||||
+14
-14
@@ -27,15 +27,15 @@ import net.minecraft.world.entity.player.Player
|
||||
* @since February 21, 2024
|
||||
*/
|
||||
|
||||
class PlayerInstancedDataStoreManager {
|
||||
open class PlayerInstancedDataStoreManager {
|
||||
val factories = mutableMapOf<PlayerInstancedDataStoreType, PlayerInstancedDataFactory<*>>()
|
||||
val saveTasks = mutableMapOf<PlayerInstancedDataStoreType, ScheduledTask>()
|
||||
fun setFactory(factory: PlayerInstancedDataFactory<*>, dataType: PlayerInstancedDataStoreType) {
|
||||
open fun setFactory(factory: PlayerInstancedDataFactory<*>, dataType: PlayerInstancedDataStoreType) {
|
||||
factories[dataType] = factory
|
||||
}
|
||||
|
||||
|
||||
fun setup(server: MinecraftServer) {
|
||||
open fun setup(server: MinecraftServer) {
|
||||
factories.values.forEach {
|
||||
it.setup(server)
|
||||
}
|
||||
@@ -57,62 +57,62 @@ class PlayerInstancedDataStoreManager {
|
||||
.build()
|
||||
}
|
||||
|
||||
fun get(playerId: UUID, dataType: PlayerInstancedDataStoreType): InstancedPlayerData {
|
||||
open fun get(playerId: UUID, dataType: PlayerInstancedDataStoreType): InstancedPlayerData {
|
||||
if (!factories.contains(dataType)) {
|
||||
throw UnsupportedOperationException("No factory registered for $dataType")
|
||||
}
|
||||
return factories[dataType]!!.getForPlayer(playerId)
|
||||
}
|
||||
|
||||
fun get(player: Player, dataType: PlayerInstancedDataStoreType): InstancedPlayerData {
|
||||
open fun get(player: Player, dataType: PlayerInstancedDataStoreType): InstancedPlayerData {
|
||||
return get(player.uuid, dataType)
|
||||
}
|
||||
|
||||
fun saveAllOfOneType(dataType: PlayerInstancedDataStoreType) {
|
||||
open fun saveAllOfOneType(dataType: PlayerInstancedDataStoreType) {
|
||||
if (!factories.contains(dataType)) {
|
||||
throw UnsupportedOperationException("No factory registered for $dataType")
|
||||
}
|
||||
return factories[dataType]!!.saveAll()
|
||||
}
|
||||
|
||||
fun saveSingle(playerData: InstancedPlayerData, dataType: PlayerInstancedDataStoreType) {
|
||||
open fun saveSingle(playerData: InstancedPlayerData, dataType: PlayerInstancedDataStoreType) {
|
||||
if (!factories.contains(dataType)) {
|
||||
throw UnsupportedOperationException("No factory registered for $dataType")
|
||||
}
|
||||
return factories[dataType]!!.saveSingle(playerData.uuid)
|
||||
}
|
||||
|
||||
fun onPlayerDisconnect(player: ServerPlayer) {
|
||||
open fun onPlayerDisconnect(player: ServerPlayer) {
|
||||
factories.values.forEach {
|
||||
it.onPlayerDisconnect(player)
|
||||
}
|
||||
}
|
||||
|
||||
fun syncAllToPlayer(player: ServerPlayer) {
|
||||
open fun syncAllToPlayer(player: ServerPlayer) {
|
||||
factories.values.forEach {
|
||||
it.sendToPlayer(player)
|
||||
}
|
||||
}
|
||||
|
||||
fun saveAllStores() {
|
||||
open fun saveAllStores() {
|
||||
factories.values.forEach {
|
||||
it.saveAll()
|
||||
}
|
||||
}
|
||||
|
||||
fun getGenericData(player: ServerPlayer): GeneralPlayerData {
|
||||
open fun getGenericData(player: ServerPlayer): GeneralPlayerData {
|
||||
return getGenericData(player.uuid)
|
||||
}
|
||||
|
||||
fun getGenericData(playerId: UUID): GeneralPlayerData {
|
||||
open fun getGenericData(playerId: UUID): GeneralPlayerData {
|
||||
return get(playerId, PlayerInstancedDataStoreTypes.GENERAL) as GeneralPlayerData
|
||||
}
|
||||
|
||||
fun getPokedexData(player: ServerPlayer): PokedexManager {
|
||||
open fun getPokedexData(player: ServerPlayer): PokedexManager {
|
||||
return getPokedexData(player.uuid)
|
||||
}
|
||||
|
||||
fun getPokedexData(playerId: UUID): PokedexManager {
|
||||
open fun getPokedexData(playerId: UUID): PokedexManager {
|
||||
return get(playerId, PlayerInstancedDataStoreTypes.POKEDEX) as PokedexManager
|
||||
}
|
||||
}
|
||||
+13
-13
@@ -372,24 +372,24 @@ class PokemonClientDelegate : PosableState(), PokemonSideDelegate {
|
||||
|
||||
override fun tick(entity: PokemonEntity) {
|
||||
incrementAge(entity)
|
||||
if(currentEntity.ownerUUID == null && currentEntity.pokemon.shiny && secondsSinceLastShinyParticle > SHINY_PARTICLE_COOLDOWN && !currentEntity.isBattling) {
|
||||
//wild shiny not looked at
|
||||
playShinyEffect("cobblemon:shiny_sparkle_ambient_wild")
|
||||
lastShinyParticle = System.currentTimeMillis()
|
||||
}
|
||||
getClientShinyPokemon()
|
||||
playWildShinySounds()
|
||||
}
|
||||
|
||||
fun getClientShinyPokemon() {
|
||||
fun playWildShinySounds() {
|
||||
val player = Minecraft.getInstance().player ?: return
|
||||
val isWithinRange = player.position().distanceTo(currentEntity.position()) <= Cobblemon.config.shinyNoticeParticlesDistance
|
||||
|
||||
if (currentEntity.pokemon.shiny && currentEntity.ownerUUID == null && !player.isSpectator ) {
|
||||
if (isWithinRange && !shined) {
|
||||
playShinyEffect("cobblemon:wild_shiny_ring")
|
||||
shined = true
|
||||
lastShinyParticle = System.currentTimeMillis()
|
||||
} else if (!isWithinRange) {
|
||||
if (currentEntity.pokemon.shiny && currentEntity.ownerUUID == null) {
|
||||
if (isWithinRange) {
|
||||
if (secondsSinceLastShinyParticle > SHINY_PARTICLE_COOLDOWN && !currentEntity.isBattling) {
|
||||
playShinyEffect("cobblemon:shiny_sparkle_ambient_wild")
|
||||
lastShinyParticle = System.currentTimeMillis()
|
||||
}
|
||||
if (!shined && !player.isSpectator) {
|
||||
playShinyEffect("cobblemon:wild_shiny_ring")
|
||||
shined = true
|
||||
}
|
||||
} else {
|
||||
shined = false
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -191,6 +191,8 @@ class BattleTargetSelection(
|
||||
matrices.pushPose()
|
||||
matrices.translate(x + TARGET_WIDTH - (25 / 2.0) - 2, y + 5.0, 0.0)
|
||||
matrices.scale(2.5F, 2.5F, 1F)
|
||||
// Grab aspects for right variant
|
||||
state.currentAspects = battlePokemon.state.currentAspects
|
||||
drawProfilePokemon(
|
||||
species = battlePokemon.species.resourceIdentifier,
|
||||
matrixStack = matrices,
|
||||
|
||||
@@ -18,7 +18,7 @@ class GrabbedStorageSlot(
|
||||
) : StorageSlot(x, y, parent, {}) {
|
||||
|
||||
init {
|
||||
isSelected = true
|
||||
isSlotSelected = true
|
||||
}
|
||||
|
||||
override fun renderWidget(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
|
||||
@@ -40,7 +40,8 @@ import net.minecraft.sounds.SoundEvent
|
||||
class PCGUI(
|
||||
val pc: ClientPC,
|
||||
val party: ClientParty,
|
||||
val configuration: PCGUIConfiguration
|
||||
val configuration: PCGUIConfiguration,
|
||||
val openOnBox: Int = 0
|
||||
) : Screen(Component.translatable("cobblemon.ui.pc.title")), CobblemonRenderable {
|
||||
|
||||
companion object {
|
||||
@@ -110,6 +111,7 @@ class PCGUI(
|
||||
pc = pc,
|
||||
party = party
|
||||
)
|
||||
this.storageWidget.box = openOnBox
|
||||
|
||||
this.setPreviewPokemon(null)
|
||||
this.addRenderableWidget(storageWidget)
|
||||
|
||||
@@ -46,7 +46,7 @@ open class StorageSlot(
|
||||
private val slotOverlayMoveIconResource = cobblemonResource("textures/gui/pasture/pc_slot_icon_move.png")
|
||||
}
|
||||
|
||||
protected var isSelected = false;
|
||||
protected var isSlotSelected = false;
|
||||
|
||||
override fun playDownSound(soundManager: SoundManager) {
|
||||
}
|
||||
@@ -84,7 +84,7 @@ open class StorageSlot(
|
||||
|
||||
context.disableScissor()
|
||||
|
||||
if (!isSelected) {
|
||||
if (!isSlotSelected) {
|
||||
// Ensure elements are not hidden behind Pokémon render
|
||||
matrices.pushPose()
|
||||
matrices.translate(0.0, 0.0, 100.0)
|
||||
@@ -129,7 +129,7 @@ open class StorageSlot(
|
||||
matrices.translate(0.0, 0.0, 500.0)
|
||||
|
||||
val config = parent.pcGui.configuration
|
||||
if (pokemon.tetheringId != null && !isSelected) {
|
||||
if (pokemon.tetheringId != null && !isSlotSelected) {
|
||||
if (isStationary()) {
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
|
||||
@@ -163,8 +163,8 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
},
|
||||
text = lang("ui.evolve"),
|
||||
resource = evolveButtonResource,
|
||||
renderRequirement = { selectedPokemon.evolutionProxy.client().isNotEmpty() },
|
||||
clickRequirement = { selectedPokemon.evolutionProxy.client().isNotEmpty() }
|
||||
renderRequirement = { selectedPokemon.evolutionProxy.client().isNotEmpty() && CobblemonClient.battle == null },
|
||||
clickRequirement = { selectedPokemon.evolutionProxy.client().isNotEmpty() && CobblemonClient.battle == null }
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
+2
@@ -19,6 +19,8 @@ object ServerSettingsPacketHandler : ClientNetworkPacketHandler<ServerSettingsPa
|
||||
ServerSettings.displayEntityLevelLabel = packet.displayEntityLevelLabel
|
||||
ServerSettings.displayEntityNameLabel = packet.displayEntityNameLabel
|
||||
ServerSettings.maxPokemonLevel = packet.maxPokemonLevel
|
||||
ServerSettings.maxPokemonFriendship = packet.maxPokemonFriendship
|
||||
ServerSettings.maxDynamaxLevel = packet.maxDynamaxLevel
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -18,6 +18,6 @@ import net.minecraft.client.Minecraft
|
||||
object OpenPCHandler : ClientNetworkPacketHandler<OpenPCPacket> {
|
||||
override fun handle(packet: OpenPCPacket, client: Minecraft) {
|
||||
val pc = CobblemonClient.storage.pcStores[packet.storeID] ?: return
|
||||
Minecraft.getInstance().setScreen(PCGUI(pc, CobblemonClient.storage.myParty, PCGUIConfiguration()))
|
||||
Minecraft.getInstance().setScreen(PCGUI(pc, CobblemonClient.storage.myParty, PCGUIConfiguration(), packet.box))
|
||||
}
|
||||
}
|
||||
+8
-7
@@ -116,7 +116,7 @@ class PokedexScannerRenderer {
|
||||
drawScaledText(
|
||||
context = graphics,
|
||||
font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = lang("ui.lv.number", pokedexEntityData.level).bold(),
|
||||
text = lang("ui.lv.number", pokedexEntityData.pokemon.level).bold(),
|
||||
x = centerX + xOffset + xOffsetText,
|
||||
y = centerY + yOffset + yOffsetText,
|
||||
shadow = true,
|
||||
@@ -126,7 +126,7 @@ class PokedexScannerRenderer {
|
||||
|
||||
if (infoDisplayedCounter == 2) {
|
||||
val hasTrainer = (usageContext.scannableEntityInFocus?.resolveEntityScan() as? PokemonEntity)?.ownerUUID !== null
|
||||
val speciesName = pokedexEntityData.species.translatedName.bold()
|
||||
val speciesName = pokedexEntityData.getApparentSpecies().translatedName.bold()
|
||||
var yOffsetName = if (hasTrainer) 2 else 0
|
||||
if (hasTrainer) {
|
||||
drawScaledText(
|
||||
@@ -149,7 +149,7 @@ class PokedexScannerRenderer {
|
||||
centered = true
|
||||
)
|
||||
|
||||
val gender = pokedexEntityData.gender
|
||||
val gender = pokedexEntityData.pokemon.gender
|
||||
val speciesNameWidth = Minecraft.getInstance().font.width(speciesName.font(CobblemonResources.DEFAULT_LARGE))
|
||||
if (gender != Gender.GENDERLESS) {
|
||||
val isMale = gender == Gender.MALE
|
||||
@@ -179,14 +179,15 @@ class PokedexScannerRenderer {
|
||||
}
|
||||
|
||||
if (infoDisplayedCounter == 3) {
|
||||
val typeText = lang("type.suffix", pokedexEntityData.form.types.map { it.displayName.copy() }.reduce { acc, next -> acc.plus("/").plus(next) }).bold()
|
||||
val typeText = lang("type.suffix", pokedexEntityData.getApparentForm().types.map { it.displayName.copy() }.reduce { acc, next -> acc.plus("/").plus(next) }).bold()
|
||||
val typeWidth = Minecraft.getInstance().font.width(typeText.font(CobblemonResources.DEFAULT_LARGE))
|
||||
// Split into 2 lines if text width is too long
|
||||
if (typeWidth > (OUTER_INFO_FRAME_WIDTH - 8) && pokedexEntityData.form.secondaryType !== null) {
|
||||
if (typeWidth > (OUTER_INFO_FRAME_WIDTH - 8) && pokedexEntityData.getApparentForm().secondaryType !== null) {
|
||||
val splitLines = typeText.string.split("/")
|
||||
drawScaledText(
|
||||
context = graphics,
|
||||
font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = lang("type.suffix", pokedexEntityData.form.primaryType.displayName).bold(),
|
||||
text = text(splitLines[0], "/").bold(),
|
||||
x = centerX + xOffset + xOffsetText,
|
||||
y = centerY + yOffset + yOffsetText - 4,
|
||||
shadow = true,
|
||||
@@ -196,7 +197,7 @@ class PokedexScannerRenderer {
|
||||
drawScaledText(
|
||||
context = graphics,
|
||||
font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = lang("type.suffix", pokedexEntityData.form.secondaryType!!.displayName).bold(),
|
||||
text = text(splitLines[1]).bold(),
|
||||
x = centerX + xOffset + xOffsetText,
|
||||
y = centerY + yOffset + yOffsetText + 3,
|
||||
shadow = true,
|
||||
|
||||
@@ -204,8 +204,8 @@ class SnowstormParticle(
|
||||
val spriteURange = sprite.u1 - sprite.u0
|
||||
val spriteVRange = sprite.v1 - sprite.v0
|
||||
|
||||
val minU = uvs.startU * spriteURange + sprite.u0
|
||||
val maxU = uvs.endU * spriteURange + sprite.u0
|
||||
val maxU = uvs.startU * spriteURange + sprite.u0
|
||||
val minU = uvs.endU * spriteURange + sprite.u0
|
||||
val minV = uvs.startV * spriteVRange + sprite.v0
|
||||
val maxV = uvs.endV * spriteVRange + sprite.v0
|
||||
|
||||
|
||||
-106
@@ -1,106 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.SingleBoneLookAnimation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
|
||||
import com.cobblemon.mod.common.util.isBattling
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class ExeggutorAlolanModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("exeggutor")
|
||||
override val head = getPart("head")
|
||||
|
||||
override val leftLeg = getPart("leg_left")
|
||||
override val rightLeg = getPart("leg_right")
|
||||
|
||||
val head2 = object : HeadedFrame {
|
||||
override val rootPart = this@ExeggutorAlolanModel.rootPart
|
||||
override val head: ModelPart = getPart("head2")
|
||||
}
|
||||
val head3 = object : HeadedFrame {
|
||||
override val rootPart = this@ExeggutorAlolanModel.rootPart
|
||||
override val head: ModelPart = getPart("head3")
|
||||
}
|
||||
|
||||
override var portraitScale = 1.0F
|
||||
override var portraitTranslation = Vec3(-1.4, 16.55, 0.0)
|
||||
|
||||
override var profileScale = 0.45F
|
||||
override var profileTranslation = Vec3(0.0, 1.0, -30.0)
|
||||
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
lateinit var sleep: Pose
|
||||
lateinit var battleidle: Pose
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink1 = quirk { bedrockStateful("exeggutor_alolan", "blink") }
|
||||
val blink2 = quirk { bedrockStateful("exeggutor_alolan", "blink2") }
|
||||
val blink3 = quirk { bedrockStateful("exeggutor_alolan", "blink3") }
|
||||
val blink4 = quirk { bedrockStateful("exeggutor_alolan", "blink4") }
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
animations = arrayOf(bedrock("exeggutor_alolan", "sleep"))
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = STATIONARY_POSES + UI_POSES,
|
||||
quirks = arrayOf(blink1, blink2, blink3, blink4),
|
||||
condition = { !it.isBattling },
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
SingleBoneLookAnimation(head2, false, false, disableX = false, disableY = false),
|
||||
SingleBoneLookAnimation(head3, false, false, disableX = false, disableY = false),
|
||||
bedrock("exeggutor_alolan", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = MOVING_POSES,
|
||||
quirks = arrayOf(blink1, blink2, blink3, blink4),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
SingleBoneLookAnimation(head2, false, false, disableX = false, disableY = false),
|
||||
SingleBoneLookAnimation(head3, false, false, disableX = false, disableY = false),
|
||||
bedrock("exeggutor_alolan", "ground_walk")
|
||||
)
|
||||
)
|
||||
|
||||
battleidle = registerPose(
|
||||
poseName = "battle_idle",
|
||||
poseTypes = PoseType.STATIONARY_POSES,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink1, blink2, blink3, blink4),
|
||||
condition = { it.isBattling },
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
SingleBoneLookAnimation(head2, false, false, disableX = false, disableY = false),
|
||||
SingleBoneLookAnimation(head3, false, false, disableX = false, disableY = false),
|
||||
bedrock("exeggutor_alolan", "battle_idle")
|
||||
)
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
// override fun getFaintAnimation(
|
||||
// pokemonEntity: PokemonEntity,
|
||||
// state: PosableState<PokemonEntity>
|
||||
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("exeggutor_alolan", "faint") else null
|
||||
}
|
||||
+3
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.client.render.models.blockbench.animation.BipedW
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
@@ -40,6 +41,8 @@ class NidokingModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame, B
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("nidoking", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("nidoking", "blink")}
|
||||
standing = registerPose(
|
||||
|
||||
+3
@@ -14,6 +14,7 @@ import com.cobblemon.mod.common.client.render.models.blockbench.animation.BipedW
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
|
||||
@@ -40,6 +41,8 @@ class NidoqueenModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame,
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("nidoqueen", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("nidoqueen", "blink")}
|
||||
val spg = quirk(secondsBetweenOccurrences = 600F to 900F) { bedrockStateful("nidoqueen", "spgs_happy_place") }
|
||||
|
||||
+3
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.QuadrupedWalkAnimation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.QuadrupedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.CobblemonPose
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
|
||||
@@ -37,6 +38,8 @@ class NidoranfModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame, Q
|
||||
lateinit var standing: CobblemonPose
|
||||
lateinit var walk: CobblemonPose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("nidoranf", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("nidoranf", "blink") }
|
||||
standing = registerPose(
|
||||
|
||||
+3
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.QuadrupedWalkAnimation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.QuadrupedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
|
||||
@@ -37,6 +38,8 @@ class NidoranmModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame, Q
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("nidoranm", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("nidoranm", "blink") }
|
||||
standing = registerPose(
|
||||
|
||||
+3
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.QuadrupedWalkAnimation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.QuadrupedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
@@ -40,6 +41,8 @@ class NidorinaModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame, Q
|
||||
lateinit var walk: Pose
|
||||
lateinit var battleidle: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("nidorina", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("nidorina", "blink")}
|
||||
standing = registerPose(
|
||||
|
||||
+3
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonP
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.QuadrupedWalkAnimation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.QuadrupedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
|
||||
@@ -36,6 +37,8 @@ class NidorinoModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame, Q
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("nidorino", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("nidorino", "blink")}
|
||||
standing = registerPose(
|
||||
|
||||
+3
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.CobblemonPose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
@@ -32,6 +33,8 @@ class PinsirModel(root: ModelPart) : PokemonPosableModel(root) {
|
||||
lateinit var battleidle: CobblemonPose
|
||||
lateinit var sleep: CobblemonPose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("pinsir", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("pinsir", "blink")}
|
||||
sleep = registerPose(
|
||||
|
||||
+2
-1
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen2
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
@@ -32,7 +33,7 @@ class HitmontopModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
|
||||
lateinit var walk: Pose
|
||||
lateinit var battleidle: Pose
|
||||
|
||||
// override val cryAnimation = CryProvider { bedrockStateful("hitmontop", "cry") }
|
||||
override val cryAnimation = CryProvider { bedrockStateful("hitmontop", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("hitmontop", "blink") }
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ class ArctozoltModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame
|
||||
override var portraitTranslation = Vec3(-0.45, 2.15, 0.0)
|
||||
override var portraitScale = 0.85F
|
||||
|
||||
override var profileTranslation = Vec3(0.02, 0.95, 0.0)
|
||||
override var profileTranslation = Vec3(0.02, 1.14, 0.0)
|
||||
override var profileScale = 0.33F
|
||||
|
||||
lateinit var sleep: CobblemonPose
|
||||
|
||||
+4
-1
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen8
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
@@ -24,12 +25,14 @@ class EiscueModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
|
||||
override var portraitTranslation = Vec3(-0.1, 0.31, 0.0)
|
||||
|
||||
override var profileScale = 0.8F
|
||||
override var profileTranslation = Vec3(0.0, 0.3, 0.0)
|
||||
override var profileTranslation = Vec3(0.0, 0.55, 0.0)
|
||||
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
lateinit var sleep: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("eiscue_ice", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("eiscue_ice", "blink")}
|
||||
sleep = registerPose(
|
||||
|
||||
+15
-5
@@ -51,7 +51,9 @@ class CharcadetModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame,
|
||||
val blink = quirk { bedrockStateful("charcadet", "blink") }
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
animations = arrayOf(bedrock("charcadet", "sleep"))
|
||||
animations = arrayOf(bedrock("charcadet", "sleep"),
|
||||
bedrock("charcadet", "eye_flame_overlay"),
|
||||
bedrock("charcadet", "head_flame_overlay"))
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
@@ -61,7 +63,9 @@ class CharcadetModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("charcadet", "ground_idle")
|
||||
bedrock("charcadet", "ground_idle"),
|
||||
bedrock("charcadet", "eye_flame_overlay"),
|
||||
bedrock("charcadet", "head_flame_overlay")
|
||||
)
|
||||
)
|
||||
|
||||
@@ -72,7 +76,9 @@ class CharcadetModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("charcadet", "ground_walk")
|
||||
bedrock("charcadet", "ground_walk"),
|
||||
bedrock("charcadet", "eye_flame_overlay"),
|
||||
bedrock("charcadet", "head_flame_overlay")
|
||||
)
|
||||
)
|
||||
|
||||
@@ -81,7 +87,9 @@ class CharcadetModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("charcadet", "shoulder_left")
|
||||
bedrock("charcadet", "shoulder_left"),
|
||||
bedrock("charcadet", "eye_flame_overlay"),
|
||||
bedrock("charcadet", "head_flame_overlay")
|
||||
),
|
||||
transformedParts = arrayOf(
|
||||
rootPart.createTransformation().addPosition(ModelPartTransformation.Y_AXIS, -0.1),
|
||||
@@ -94,7 +102,9 @@ class CharcadetModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("charcadet", "shoulder_right")
|
||||
bedrock("charcadet", "shoulder_right"),
|
||||
bedrock("charcadet", "eye_flame_overlay"),
|
||||
bedrock("charcadet", "head_flame_overlay")
|
||||
),
|
||||
transformedParts = arrayOf(
|
||||
rootPart.createTransformation().addPosition(ModelPartTransformation.Y_AXIS, -0.1),
|
||||
|
||||
-1
@@ -90,7 +90,6 @@ object PokemonModelRepository : VaryingModelRepository<PokemonPosableModel>() {
|
||||
inbuilt("electabuzz", ::ElectabuzzModel)
|
||||
inbuilt("exeggcute", ::ExeggcuteModel)
|
||||
inbuilt("exeggutor", ::ExeggutorModel)
|
||||
inbuilt("exeggutor_alolan", ::ExeggutorAlolanModel)
|
||||
inbuilt("farfetchd", ::FarfetchdModel)
|
||||
inbuilt("farfetchd_galarian", ::FarfetchdGalarianModel)
|
||||
inbuilt("fearow", ::FearowModel)
|
||||
|
||||
@@ -60,4 +60,11 @@ class NPCRenderer(context: Context) : LivingEntityRenderer<NPCEntity, PosableEnt
|
||||
// this.renderLabelIfPresent(entity, entity.displayName, poseMatrix, buffer, packedLight)
|
||||
// }
|
||||
}
|
||||
|
||||
override fun shouldShowName(entity: NPCEntity): Boolean {
|
||||
if (entity.hideNameTag) {
|
||||
return false
|
||||
}
|
||||
return super.shouldShowName(entity)
|
||||
}
|
||||
}
|
||||
@@ -25,5 +25,7 @@ object ServerSettings {
|
||||
var displayEntityLevelLabel = Cobblemon.config.displayEntityLevelLabel
|
||||
var displayEntityNameLabel = Cobblemon.config.displayEntityNameLabel
|
||||
var maxPokemonLevel = Cobblemon.config.maxPokemonLevel
|
||||
var maxPokemonFriendship = Cobblemon.config.maxPokemonFriendship
|
||||
var maxDynamaxLevel = Cobblemon.config.maxDynamaxLevel
|
||||
|
||||
}
|
||||
@@ -11,7 +11,7 @@ package com.cobblemon.mod.common.command
|
||||
import com.cobblemon.mod.common.api.permission.CobblemonPermissions
|
||||
import com.cobblemon.mod.common.command.argument.SpeciesArgumentType
|
||||
import com.cobblemon.mod.common.pokemon.FormData
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.permission
|
||||
import com.mojang.brigadier.Command
|
||||
import com.mojang.brigadier.CommandDispatcher
|
||||
@@ -40,7 +40,7 @@ object ChangeWalkSpeed {
|
||||
val pkm = SpeciesArgumentType.getPokemon(context, "pokemon")
|
||||
val walkSpeed = FloatArgumentType.getFloat(context, "walkSpeed")
|
||||
|
||||
pkm.behaviour.moving.walk.walkSpeed = walkSpeed.toString().asExpressionLike()
|
||||
pkm.behaviour.moving.walk.walkSpeed = walkSpeed.toString().asExpression()
|
||||
pkm.forms.clear()
|
||||
pkm.forms.add(FormData().also { it.initialize(pkm)})
|
||||
return Command.SINGLE_SUCCESS
|
||||
|
||||
@@ -45,8 +45,8 @@ object CobblemonInfoCommand {
|
||||
.append(this.INDENT)
|
||||
.append(Component.literal("Is Snapshot:").withStyle { it.withColor(ChatFormatting.GRAY) })
|
||||
.append(this.SPACE)
|
||||
.append(Component.literal(if(CobblemonBuildDetails.SNAPSHOT) "Yes" else "No").withStyle {
|
||||
it.withColor(if(CobblemonBuildDetails.SNAPSHOT) this.GREEN else this.RED)
|
||||
.append(Component.literal(if (CobblemonBuildDetails.SNAPSHOT) "Yes" else "No").withStyle {
|
||||
it.withColor(if (CobblemonBuildDetails.SNAPSHOT) this.GREEN else this.RED)
|
||||
})
|
||||
|
||||
message.append(this.NEW_LINE)
|
||||
|
||||
@@ -17,10 +17,12 @@ import com.cobblemon.mod.common.net.messages.client.storage.pc.OpenPCPacket
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.mojang.brigadier.Command
|
||||
import com.mojang.brigadier.CommandDispatcher
|
||||
import com.mojang.brigadier.arguments.IntegerArgumentType
|
||||
import com.mojang.brigadier.context.CommandContext
|
||||
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType
|
||||
import net.minecraft.commands.CommandSourceStack
|
||||
import net.minecraft.commands.Commands.literal
|
||||
import net.minecraft.commands.Commands.argument
|
||||
|
||||
object PcCommand {
|
||||
|
||||
@@ -30,25 +32,36 @@ object PcCommand {
|
||||
fun register(dispatcher : CommandDispatcher<CommandSourceStack>) {
|
||||
dispatcher.register(literal(NAME)
|
||||
.permission(CobblemonPermissions.PC)
|
||||
.then(argument("box", IntegerArgumentType.integer(1))
|
||||
.executes(this::execute)
|
||||
)
|
||||
.executes(this::execute)
|
||||
)
|
||||
}
|
||||
|
||||
private fun execute(context: CommandContext<CommandSourceStack>): Int {
|
||||
val player = context.source.playerOrException
|
||||
val box = try {
|
||||
IntegerArgumentType.getInteger(context, "box")
|
||||
} catch (e: IllegalArgumentException) {
|
||||
1
|
||||
}
|
||||
val pc = player.pc()
|
||||
if (player.isInBattle()) {
|
||||
throw IN_BATTLE_EXCEPTION.create()
|
||||
}
|
||||
if (pc.boxes.size < box) {
|
||||
throw SimpleCommandExceptionType(lang("command.pc.invalid-box", box, pc.boxes.size).red()).create()
|
||||
}
|
||||
PCLinkManager.addLink(PermissiblePcLink(pc, player, CobblemonPermissions.PC))
|
||||
OpenPCPacket(pc.uuid).sendToPlayer(player)
|
||||
OpenPCPacket(pc.uuid, box - 1).sendToPlayer(player)
|
||||
context.source.level.playSoundServer(
|
||||
position = context.source.player!!.position(),
|
||||
sound = CobblemonSounds.PC_ON,
|
||||
volume = 0.5F,
|
||||
pitch = 1F
|
||||
position = context.source.player!!.position(),
|
||||
sound = CobblemonSounds.PC_ON,
|
||||
volume = 0.5F,
|
||||
pitch = 1F
|
||||
)
|
||||
return Command.SINGLE_SUCCESS
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -29,14 +29,14 @@ class FeatureFix(output: Schema) : PokemonFix(output) {
|
||||
if (features.result().isPresent) {
|
||||
return dynamic //already has Features nbt format... no work needed
|
||||
}
|
||||
var featureTag = emptyList<CompoundTag>()
|
||||
var featureTag = mutableListOf<CompoundTag>()
|
||||
if (dynamic.value is CompoundTag) {
|
||||
var rootTag = dynamic.value as CompoundTag
|
||||
var species = PokemonSpecies.getByIdentifier(rootTag.getString(DataKeys.POKEMON_SPECIES_IDENTIFIER).asResource())
|
||||
if (species == null) {
|
||||
return dynamic
|
||||
}
|
||||
SpeciesFeatures.getFeaturesFor(species!!).forEach {
|
||||
SpeciesFeatures.getFeaturesFor(species).forEach {
|
||||
val feature = it(rootTag) ?: return@forEach
|
||||
var tag = CompoundTag()
|
||||
tag.putString(FEATURE_ID, feature.name)
|
||||
@@ -51,7 +51,10 @@ class FeatureFix(output: Schema) : PokemonFix(output) {
|
||||
} else if (dynamic.value is JsonElement) {
|
||||
var rootTag = (dynamic.value as JsonElement).asJsonObject
|
||||
var species = PokemonSpecies.getByIdentifier(rootTag.get(DataKeys.POKEMON_SPECIES_IDENTIFIER).asString.asResource())
|
||||
SpeciesFeatures.getFeaturesFor(species!!).forEach {
|
||||
if (species == null) {
|
||||
return dynamic
|
||||
}
|
||||
SpeciesFeatures.getFeaturesFor(species).forEach {
|
||||
val feature = it(rootTag) ?: return@forEach
|
||||
var tag = CompoundTag()
|
||||
tag.putString(FEATURE_ID, feature.name)
|
||||
|
||||
+5
-3
@@ -8,18 +8,20 @@
|
||||
|
||||
package com.cobblemon.mod.common.datafixer.fix
|
||||
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import com.mojang.datafixers.schemas.Schema
|
||||
import com.mojang.serialization.Dynamic
|
||||
|
||||
class ShoulderStateJsonFix(output: Schema) : PokemonFix(output) {
|
||||
override fun fixPokemonData(dynamic: Dynamic<*>): Dynamic<*> {
|
||||
val moveSetJson = dynamic.get("State").result()
|
||||
val stateJson = dynamic.get("State").result()
|
||||
//State not here
|
||||
if (moveSetJson.isEmpty) {
|
||||
if (stateJson.isEmpty) {
|
||||
return dynamic
|
||||
}
|
||||
|
||||
if (moveSetJson.get().mapValues.getOrThrow().size == 0) {
|
||||
if (stateJson.get().mapValues.getOrThrow().isEmpty() ||
|
||||
!stateJson.get().mapValues.getOrThrow().containsKey(dynamic.createString(DataKeys.POKEMON_STATE_TYPE))) {
|
||||
return dynamic.remove("State")
|
||||
}
|
||||
|
||||
|
||||
+15
-29
@@ -35,6 +35,7 @@ import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.cobblemon.mod.common.util.toBlockPos
|
||||
import com.cobblemon.mod.common.util.weightedSelection
|
||||
import net.minecraft.advancements.CriteriaTriggers
|
||||
import net.minecraft.client.resources.sounds.EntityBoundSoundInstance
|
||||
import net.minecraft.core.BlockPos
|
||||
@@ -183,33 +184,19 @@ class PokeRodFishingBobberEntity(type: EntityType<out PokeRodFishingBobberEntity
|
||||
}
|
||||
|
||||
fun chooseAdjustedSpawnBucket(buckets: List<SpawnBucket>, luckOfTheSeaLevel: Int): SpawnBucket {
|
||||
val baseIncreases = listOf(2.5F, 0.5F, 0.2F) // Base increases for the first three buckets beyond the first
|
||||
val baseValues = listOf(94.3F, 5.0F, 0.5F, 0.2F)
|
||||
val adjustments = listOf(-4.1F, 2.5F, 1.0F, 0.6F)
|
||||
|
||||
val adjustedWeights = buckets.mapIndexed { index, bucket ->
|
||||
if (index == 0) {
|
||||
// Placeholder, will be recalculated
|
||||
0.0F
|
||||
} else {
|
||||
val increase = if (index < baseIncreases.size) baseIncreases[index] else baseIncreases.last() + (index - baseIncreases.size + 1) * 0.15F
|
||||
bucket.weight + increase * luckOfTheSeaLevel
|
||||
if (index >= baseValues.size) {
|
||||
return@mapIndexed bucket to bucket.weight
|
||||
}
|
||||
}.toMutableList()
|
||||
val base = baseValues[index]
|
||||
val adjustment = adjustments[index]
|
||||
bucket to (base + adjustment * luckOfTheSeaLevel)
|
||||
}.toMap()
|
||||
|
||||
// Recalculate the first bucket's weight to ensure the total is 100%
|
||||
val totalAdjustedWeight = adjustedWeights.sum() - adjustedWeights[0] // Corrected to ensure the list contains Floats
|
||||
adjustedWeights[0] = 100.0F - totalAdjustedWeight + buckets[0].weight
|
||||
|
||||
// Random selection based on adjusted weights
|
||||
val weightSum = adjustedWeights.sum()
|
||||
val chosenSum = kotlin.random.Random.nextDouble(weightSum.toDouble()).toFloat() // Ensure usage of Random from kotlin.random package
|
||||
var sum = 0.0F
|
||||
adjustedWeights.forEachIndexed { index, weight ->
|
||||
sum += weight
|
||||
if (sum >= chosenSum) {
|
||||
return buckets[index]
|
||||
}
|
||||
}
|
||||
|
||||
return buckets.first() // Fallback
|
||||
return buckets.weightedSelection { adjustedWeights[it]!! }!!
|
||||
}
|
||||
|
||||
fun isOpenOrWaterAround(pos: BlockPos): Boolean {
|
||||
@@ -335,7 +322,7 @@ class PokeRodFishingBobberEntity(type: EntityType<out PokeRodFishingBobberEntity
|
||||
|
||||
val buckets = Cobblemon.bestSpawner.config.buckets
|
||||
|
||||
// choose a spawn bucket according to weights no matter how many there are
|
||||
// choose a spawn bucket according to weights and luck of the sea
|
||||
chosenBucket = chooseAdjustedSpawnBucket(buckets, luckOfTheSeaLevel)
|
||||
CobblemonEvents.BOBBER_BUCKET_CHOSEN.post(BobberBucketChosenEvent(chosenBucket, buckets, luckOfTheSeaLevel)) { event ->
|
||||
chosenBucket = event.chosenBucket
|
||||
@@ -698,10 +685,9 @@ class PokeRodFishingBobberEntity(type: EntityType<out PokeRodFishingBobberEntity
|
||||
)
|
||||
|
||||
// This has a chance to fail, if the position has no suitability for a fishing context
|
||||
// it could also just be a miss which
|
||||
// means two attempts to spawn in the same location can have differing results (which is expected for
|
||||
// randomness).
|
||||
if (result == null) {
|
||||
// it could also just be a miss which means two attempts to spawn in the same location
|
||||
// can have differing results (which is expected for randomness).
|
||||
if (result == null || result.isCompletedExceptionally) {
|
||||
player.sendSystemMessage(lang("fishing.no_bite").red())
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -110,6 +110,12 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
|
||||
val level: Int
|
||||
get() = entityData.get(LEVEL)
|
||||
|
||||
var hideNameTag: Boolean
|
||||
get() = entityData.get(HIDE_NAME_TAG)
|
||||
set(value) {
|
||||
entityData.set(HIDE_NAME_TAG, value)
|
||||
}
|
||||
|
||||
var skill: Int? = null // range from 0 - 5
|
||||
|
||||
var baseScale: Float? = null
|
||||
@@ -208,7 +214,7 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
|
||||
val BATTLE_IDS = SynchedEntityData.defineId(NPCEntity::class.java, UUIDSetDataSerializer)
|
||||
val NPC_PLAYER_TEXTURE = SynchedEntityData.defineId(NPCEntity::class.java, NPCPlayerTextureSerializer)
|
||||
val LEVEL = SynchedEntityData.defineId(NPCEntity::class.java, EntityDataSerializers.INT)
|
||||
|
||||
val HIDE_NAME_TAG = SynchedEntityData.defineId(NPCEntity::class.java, EntityDataSerializers.BOOLEAN)
|
||||
|
||||
// val BATTLING = Activity.register("npc_battling")
|
||||
|
||||
@@ -259,6 +265,7 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
|
||||
builder.define(BATTLE_IDS, setOf())
|
||||
builder.define(NPC_PLAYER_TEXTURE, NPCPlayerTexture(ByteArray(1), NPCPlayerModelType.NONE))
|
||||
builder.define(LEVEL, 1)
|
||||
builder.define(HIDE_NAME_TAG, false)
|
||||
}
|
||||
|
||||
override fun getAddEntityPacket(serverEntity: ServerEntity) = ClientboundCustomPayloadPacket(
|
||||
@@ -332,6 +339,7 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
|
||||
super.saveWithoutId(nbt)
|
||||
saveScriptingToNBT(nbt)
|
||||
nbt.put(DataKeys.NPC_LEVEL, IntTag.valueOf(level))
|
||||
nbt.putBoolean(DataKeys.NPC_HIDE_NAME_TAG, hideNameTag)
|
||||
nbt.putString(DataKeys.NPC_CLASS, npc.id.toString())
|
||||
nbt.put(DataKeys.NPC_ASPECTS, ListTag().also { list -> appliedAspects.forEach { list.add(StringTag.valueOf(it)) } })
|
||||
nbt.put(DataKeys.NPC_VARIATION_ASPECTS, ListTag().also { list -> variationAspects.forEach { list.add(StringTag.valueOf(it)) } })
|
||||
@@ -397,6 +405,7 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
|
||||
override fun load(nbt: CompoundTag) {
|
||||
npc = NPCClasses.getByIdentifier(ResourceLocation.parse(nbt.getString(DataKeys.NPC_CLASS))) ?: NPCClasses.classes.first()
|
||||
entityData.set(LEVEL, nbt.getInt(DataKeys.NPC_LEVEL).takeIf { it != 0 } ?: 1)
|
||||
entityData.set(HIDE_NAME_TAG, nbt.getBoolean(DataKeys.NPC_HIDE_NAME_TAG))
|
||||
super.load(nbt)
|
||||
loadScriptingFromNBT(nbt)
|
||||
appliedAspects.addAll(nbt.getList(DataKeys.NPC_ASPECTS, Tag.TAG_STRING.toInt()).map { it.asString })
|
||||
@@ -503,6 +512,7 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
|
||||
|
||||
fun initialize(level: Int) {
|
||||
variationAspects.clear()
|
||||
entityData.set(HIDE_NAME_TAG, npc.hideNameTag)
|
||||
entityData.set(LEVEL, level)
|
||||
remakeBrain()
|
||||
npc.variations.values.forEach { this.variationAspects.addAll(it.provideAspects(this)) }
|
||||
|
||||
@@ -1696,17 +1696,15 @@ open class PokemonEntity(
|
||||
private fun sidedCodec(): Codec<Pokemon> = if (this.level().isClientSide) Pokemon.CLIENT_CODEC else Pokemon.CODEC
|
||||
|
||||
override fun resolvePokemonScan(): PokedexEntityData? {
|
||||
return PokemonSpecies.getByIdentifier(this.exposedSpecies.resourceIdentifier)?.let { species ->
|
||||
PokedexEntityData(
|
||||
species = species,
|
||||
form = this.form,
|
||||
gender = this.pokemon.gender,
|
||||
aspects = this.aspects,
|
||||
shiny = this.pokemon.shiny,
|
||||
level = this.labelLevel(),
|
||||
ownerUUID = this.ownerUUID
|
||||
)
|
||||
}
|
||||
return PokedexEntityData(
|
||||
pokemon = pokemon,
|
||||
disguise = this.effects.mockEffect?.let {
|
||||
PokedexEntityData.DisguiseData(
|
||||
species = it.exposedSpecies ?: pokemon.species,
|
||||
form = it.exposedForm ?: pokemon.form,
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun resolveEntityScan(): LivingEntity {
|
||||
|
||||
+3
@@ -34,6 +34,7 @@ import net.minecraft.network.chat.Component
|
||||
import net.minecraft.network.syncher.EntityDataAccessor
|
||||
import net.minecraft.world.damagesource.DamageSource
|
||||
import net.minecraft.world.entity.ai.attributes.Attributes
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.level.pathfinder.PathType
|
||||
|
||||
/** Handles purely server logic for a Pokémon */
|
||||
@@ -260,6 +261,8 @@ class PokemonServerDelegate : PokemonSideDelegate {
|
||||
if (entity.ownerUUID == null && entity.owner == null) {
|
||||
entity.level().broadcastEntityEvent(entity, 60.toByte()) // Sends smoke effect
|
||||
if(entity.level().gameRules.getBoolean(CobblemonGameRules.DO_POKEMON_LOOT)) {
|
||||
val heldItem = (entity as PokemonEntity?)?.pokemon?.heldItemNoCopy() ?: ItemStack.EMPTY
|
||||
if (!heldItem.isEmpty) entity.spawnAtLocation(heldItem.item)
|
||||
(entity.drops ?: entity.pokemon.form.drops).drop(entity, entity.level() as ServerLevel, entity.position(), entity.killer)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -80,7 +80,7 @@ class PokemonNavigation(val world: Level, val pokemonEntity: PokemonEntity) : Gr
|
||||
(isTouchingLava && moving.swim.canSwimInLava) ||
|
||||
this.mob.isPassenger
|
||||
if (pokemonEntity.behaviour.moving.swim.canSwimInWater) {
|
||||
return isInLiquid || super.canUpdatePath()
|
||||
return isInLiquid || ((this.mob.onGround() || this.pokemonEntity.isFlying()) || this.mob.isInLiquid() || this.mob.isPassenger())
|
||||
} else {
|
||||
return isAtValidPosition
|
||||
}
|
||||
|
||||
-56
@@ -1,56 +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.entity.pokemon.ai.goals
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.status.PersistentStatusContainer
|
||||
import net.minecraft.world.entity.ai.goal.Goal
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* AI goal for sleeping in the wild.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since July 18th, 2022
|
||||
*/
|
||||
class WildRestGoal(private val pokemonEntity: PokemonEntity) : Goal() {
|
||||
override fun getFlags(): EnumSet<Flag> = EnumSet.allOf(Flag::class.java)
|
||||
|
||||
override fun canUse(): Boolean {
|
||||
val rest = pokemonEntity.behaviour.resting
|
||||
if (!pokemonEntity.pokemon.isWild() || pokemonEntity.random.nextFloat() < 1 - rest.sleepChance || !pokemonEntity.canSleep() || pokemonEntity.isBusy || !rest.depth.canSleep(pokemonEntity)) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun isInterruptable(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun canContinueToUse(): Boolean {
|
||||
return if (pokemonEntity.canSleep() && !pokemonEntity.behaviour.resting.depth.shouldWake(pokemonEntity)) {
|
||||
true
|
||||
} else {
|
||||
wake()
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
override fun start() {
|
||||
pokemonEntity.pokemon.status = PersistentStatusContainer(Statuses.SLEEP)
|
||||
}
|
||||
|
||||
fun wake() {
|
||||
if (pokemonEntity.battleId == null) {
|
||||
pokemonEntity.pokemon.status = null
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-2
@@ -23,7 +23,9 @@ class ServerSettingsPacket internal constructor(
|
||||
val preventCompletePartyDeposit: Boolean,
|
||||
val displayEntityLevelLabel: Boolean,
|
||||
val displayEntityNameLabel: Boolean,
|
||||
val maxPokemonLevel: Int
|
||||
val maxPokemonLevel: Int,
|
||||
val maxPokemonFriendship: Int,
|
||||
val maxDynamaxLevel: Int
|
||||
) : NetworkPacket<ServerSettingsPacket> {
|
||||
override val id = ID
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
@@ -31,9 +33,11 @@ class ServerSettingsPacket internal constructor(
|
||||
buffer.writeBoolean(Cobblemon.config.displayEntityLevelLabel)
|
||||
buffer.writeBoolean(Cobblemon.config.displayEntityNameLabel)
|
||||
buffer.writeInt(Cobblemon.config.maxPokemonLevel)
|
||||
buffer.writeInt(Cobblemon.config.maxPokemonFriendship)
|
||||
buffer.writeInt(Cobblemon.config.maxDynamaxLevel)
|
||||
}
|
||||
companion object {
|
||||
val ID = cobblemonResource("server_settings")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) = ServerSettingsPacket(buffer.readBoolean(), buffer.readBoolean(), buffer.readBoolean(), buffer.readInt())
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) = ServerSettingsPacket(buffer.readBoolean(), buffer.readBoolean(), buffer.readBoolean(), buffer.readInt(), buffer.readInt(), buffer.readInt())
|
||||
}
|
||||
}
|
||||
+8
-8
@@ -25,14 +25,14 @@ import net.minecraft.resources.ResourceLocation
|
||||
* @author Licious
|
||||
* @since December 29th, 2022
|
||||
*/
|
||||
internal class UnvalidatedPlaySoundS2CPacket(
|
||||
val sound: ResourceLocation,
|
||||
val category: SoundSource,
|
||||
val x: Double,
|
||||
val y: Double,
|
||||
val z: Double,
|
||||
val volume: Float,
|
||||
val pitch: Float
|
||||
class UnvalidatedPlaySoundS2CPacket(
|
||||
var sound: ResourceLocation,
|
||||
var category: SoundSource,
|
||||
var x: Double,
|
||||
var y: Double,
|
||||
var z: Double,
|
||||
var volume: Float,
|
||||
var pitch: Float
|
||||
) : NetworkPacket<UnvalidatedPlaySoundS2CPacket> {
|
||||
|
||||
override val id = ID
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ import net.minecraft.network.protocol.PacketUtils
|
||||
import net.minecraft.network.protocol.game.ClientboundAddEntityPacket
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
abstract class SpawnExtraDataEntityPacket<T: NetworkPacket<T>, E : Entity>(private val vanillaSpawnPacket: ClientboundAddEntityPacket) : NetworkPacket<T> {
|
||||
abstract class SpawnExtraDataEntityPacket<T: NetworkPacket<T>, E : Entity>(var vanillaSpawnPacket: ClientboundAddEntityPacket) : NetworkPacket<T> {
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
this.encodeEntityData(buffer)
|
||||
this.vanillaSpawnPacket.write(buffer)
|
||||
|
||||
+13
-8
@@ -30,13 +30,14 @@ import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.entity.Entity
|
||||
|
||||
class SpawnNPCPacket(
|
||||
private val npcClass: ResourceLocation,
|
||||
private val aspects: Set<String>,
|
||||
private val level: Int,
|
||||
private val battleIds: Set<UUID>,
|
||||
private val name: Component,
|
||||
private val poseType: PoseType,
|
||||
private val texture: NPCPlayerTexture,
|
||||
var npcClass: ResourceLocation,
|
||||
var aspects: Set<String>,
|
||||
var level: Int,
|
||||
var battleIds: Set<UUID>,
|
||||
var name: Component,
|
||||
var poseType: PoseType,
|
||||
var texture: NPCPlayerTexture,
|
||||
var hideNameTag: Boolean,
|
||||
vanillaSpawnPacket: ClientboundAddEntityPacket
|
||||
) : SpawnExtraDataEntityPacket<SpawnNPCPacket, NPCEntity>(vanillaSpawnPacket) {
|
||||
|
||||
@@ -50,6 +51,7 @@ class SpawnNPCPacket(
|
||||
entity.name,
|
||||
entity.entityData.get(NPCEntity.POSE_TYPE),
|
||||
entity.entityData.get(NPCEntity.NPC_PLAYER_TEXTURE),
|
||||
entity.hideNameTag,
|
||||
vanillaSpawnPacket
|
||||
)
|
||||
|
||||
@@ -64,6 +66,7 @@ class SpawnNPCPacket(
|
||||
if (this.texture.model != NPCPlayerModelType.NONE) {
|
||||
buffer.writeByteArray(this.texture.texture)
|
||||
}
|
||||
buffer.writeBoolean(this.hideNameTag)
|
||||
}
|
||||
|
||||
override fun applyData(entity: NPCEntity) {
|
||||
@@ -74,6 +77,7 @@ class SpawnNPCPacket(
|
||||
entity.entityData.set(NPCEntity.ASPECTS, aspects)
|
||||
entity.entityData.set(NPCEntity.POSE_TYPE, poseType)
|
||||
entity.entityData.set(NPCEntity.NPC_PLAYER_TEXTURE, texture)
|
||||
entity.entityData.set(NPCEntity.HIDE_NAME_TAG, this.hideNameTag)
|
||||
}
|
||||
|
||||
override fun checkType(entity: Entity): Boolean = entity is NPCEntity
|
||||
@@ -93,9 +97,10 @@ class SpawnNPCPacket(
|
||||
} else {
|
||||
NPCPlayerTexture(byteArrayOf(), model)
|
||||
}
|
||||
val hideNameTag = buffer.readBoolean()
|
||||
val vanillaPacket = decodeVanillaPacket(buffer)
|
||||
|
||||
return SpawnNPCPacket(npc, aspects, level, battleIds, name, poseType, texture, vanillaPacket)
|
||||
return SpawnNPCPacket(npc, aspects, level, battleIds, name, poseType, texture, hideNameTag, vanillaPacket)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+20
-20
@@ -24,26 +24,26 @@ import net.minecraft.network.protocol.game.ClientboundAddEntityPacket
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
class SpawnPokemonPacket(
|
||||
private val ownerId: UUID?,
|
||||
private val scaleModifier: Float,
|
||||
private val speciesId: ResourceLocation,
|
||||
private val gender: Gender,
|
||||
private val shiny: Boolean,
|
||||
private val formName: String,
|
||||
private val aspects: Set<String>,
|
||||
private val battleId: UUID?,
|
||||
private val phasingTargetId: Int,
|
||||
private val beamMode: Byte,
|
||||
private val platform: PlatformType,
|
||||
private val nickname: MutableComponent?,
|
||||
private val labelLevel: Int,
|
||||
private val poseType: PoseType,
|
||||
private val unbattlable: Boolean,
|
||||
private val hideLabel: Boolean,
|
||||
private val caughtBall: ResourceLocation,
|
||||
private val spawnYaw: Float,
|
||||
private val friendship: Int,
|
||||
private val freezeFrame: Float,
|
||||
var ownerId: UUID?,
|
||||
var scaleModifier: Float,
|
||||
var speciesId: ResourceLocation,
|
||||
var gender: Gender,
|
||||
var shiny: Boolean,
|
||||
var formName: String,
|
||||
var aspects: Set<String>,
|
||||
var battleId: UUID?,
|
||||
var phasingTargetId: Int,
|
||||
var beamMode: Byte,
|
||||
var platform: PlatformType,
|
||||
var nickname: MutableComponent?,
|
||||
var labelLevel: Int,
|
||||
var poseType: PoseType,
|
||||
var unbattlable: Boolean,
|
||||
var hideLabel: Boolean,
|
||||
var caughtBall: ResourceLocation,
|
||||
var spawnYaw: Float,
|
||||
var friendship: Int,
|
||||
var freezeFrame: Float,
|
||||
vanillaSpawnPacket: ClientboundAddEntityPacket
|
||||
) : SpawnExtraDataEntityPacket<SpawnPokemonPacket, PokemonEntity>(vanillaSpawnPacket) {
|
||||
|
||||
|
||||
+3
-2
@@ -26,16 +26,17 @@ import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
* @author Hiroku
|
||||
* @since June 20th, 2022
|
||||
*/
|
||||
class OpenPCPacket(val storeID: UUID) : NetworkPacket<OpenPCPacket> {
|
||||
class OpenPCPacket(val storeID: UUID, val box: Int = 1) : NetworkPacket<OpenPCPacket> {
|
||||
|
||||
override val id = ID
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeUUID(storeID)
|
||||
buffer.writeInt(box)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("open_pc")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) = OpenPCPacket(buffer.readUUID())
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) = OpenPCPacket(buffer.readUUID(), buffer.readInt())
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.net.serverhandling.evolution
|
||||
|
||||
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.evolution.AcceptEvolutionPacket
|
||||
import com.cobblemon.mod.common.util.isInBattle
|
||||
import com.cobblemon.mod.common.util.party
|
||||
import net.minecraft.server.MinecraftServer
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
@@ -17,7 +18,7 @@ import net.minecraft.server.level.ServerPlayer
|
||||
object AcceptEvolutionHandler : ServerNetworkPacketHandler<AcceptEvolutionPacket> {
|
||||
override fun handle(packet: AcceptEvolutionPacket, server: MinecraftServer, player: ServerPlayer) {
|
||||
val pokemon = player.party()[packet.pokemonUUID] ?: return
|
||||
if (pokemon.entity?.isBusy == true) return
|
||||
if (player.isInBattle() || pokemon.entity?.isBusy == true) return
|
||||
val evolution = pokemon.evolutionProxy.server().firstOrNull { evolution -> evolution.id.equals(packet.evolutionId, true) } ?: return
|
||||
pokemon.evolutionProxy.server().start(evolution)
|
||||
}
|
||||
|
||||
+2
-2
@@ -43,7 +43,7 @@ object FinishScanningHandler : ServerNetworkPacketHandler<FinishScanningPacket>
|
||||
val scannableEntity = targetEntity as? ScannableEntity ?: return
|
||||
val dex = Cobblemon.playerDataManager.getPokedexData(player)
|
||||
val pokedexEntityData = scannableEntity.resolvePokemonScan()
|
||||
if(pokedexEntityData != null){
|
||||
if (pokedexEntityData != null){
|
||||
val newInformation = dex.getNewInformation(pokedexEntityData)
|
||||
if ((scannableEntity as? PokemonEntity)?.owner === player) {
|
||||
dex.catch(scannableEntity.pokemon)
|
||||
@@ -52,7 +52,7 @@ object FinishScanningHandler : ServerNetworkPacketHandler<FinishScanningPacket>
|
||||
}
|
||||
|
||||
POKEMON_SCANNED.post(PokemonScannedEvent(player, pokedexEntityData, scannableEntity))
|
||||
ServerConfirmedRegisterPacket(pokedexEntityData.species.resourceIdentifier, newInformation).sendToPlayer(player)
|
||||
ServerConfirmedRegisterPacket((pokedexEntityData.getApparentSpecies()).resourceIdentifier, newInformation).sendToPlayer(player)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+14
-18
@@ -9,32 +9,28 @@
|
||||
package com.cobblemon.mod.common.pokedex.scanner
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.pokemon.FormData
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.cobblemon.mod.common.util.asArrayValue
|
||||
import java.util.UUID
|
||||
|
||||
// Hiro note: I honestly want to move to not using this at all. There is always a Pokemon behind the data,
|
||||
// it's just that sometimes it's harder to reach or there's a Zoroark or Ditto throwing a curveball. It makes
|
||||
// in shittier in events to have to cater to two distinct classes of data that can be scanned.
|
||||
|
||||
data class PokedexEntityData(
|
||||
val species: Species,
|
||||
val form: FormData,
|
||||
val gender: Gender,
|
||||
val aspects: Set<String>,
|
||||
val shiny: Boolean,
|
||||
val level: Int,
|
||||
val ownerUUID: UUID?
|
||||
val pokemon: Pokemon,
|
||||
val disguise: DisguiseData?
|
||||
) {
|
||||
val struct = QueryStruct(hashMapOf())
|
||||
.addFunction("species") { species.struct }
|
||||
.addFunction("gender") { StringValue(gender.name.lowercase()) }
|
||||
.addFunction("aspects") { aspects.asArrayValue(::StringValue) }
|
||||
.addFunction("shiny") { DoubleValue(shiny) }
|
||||
.addFunction("level") { DoubleValue(level.toDouble()) }
|
||||
.addFunction("has_owner") { DoubleValue(ownerUUID != null) }
|
||||
class DisguiseData(
|
||||
val species: Species,
|
||||
val form: FormData,
|
||||
) {
|
||||
val struct = QueryStruct(hashMapOf())
|
||||
.addFunction("species") { species.struct }
|
||||
.addFunction("form") { StringValue(form.name) }
|
||||
}
|
||||
|
||||
fun getApparentSpecies() = disguise?.species ?: pokemon.species
|
||||
fun getApparentForm() = disguise?.form ?: pokemon.form
|
||||
}
|
||||
+6
-6
@@ -18,6 +18,9 @@ import com.cobblemon.mod.common.client.pokedex.PokedexType
|
||||
import com.cobblemon.mod.common.net.messages.client.pokedex.ServerConfirmedRegisterPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokedex.scanner.FinishScanningPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokedex.scanner.StartScanningPacket
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.random.Random
|
||||
import net.minecraft.client.DeltaTracker
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
@@ -26,9 +29,6 @@ import net.minecraft.client.resources.sounds.SimpleSoundInstance
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.sounds.SoundEvent
|
||||
import net.minecraft.util.Mth.clamp
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.random.Random
|
||||
|
||||
class PokedexUsageContext {
|
||||
companion object {
|
||||
@@ -85,7 +85,7 @@ class PokedexUsageContext {
|
||||
if (transitionIntervals == TRANSITION_INTERVALS) playSound(CobblemonSounds.POKEDEX_SCAN_CLOSE)
|
||||
transitionIntervals = max(transitionIntervals - updateInterval, 0F)
|
||||
if (transitionIntervals <= 0) {
|
||||
if (viewInfoTicks >= VIEW_INFO_BUFFER_TICKS) openPokedexGUI(type, scannableEntityInFocus!!.resolvePokemonScan()?.species?.resourceIdentifier)
|
||||
if (viewInfoTicks >= VIEW_INFO_BUFFER_TICKS) openPokedexGUI(type, scannableEntityInFocus!!.resolvePokemonScan()?.getApparentSpecies()?.resourceIdentifier)
|
||||
resetState()
|
||||
}
|
||||
}
|
||||
@@ -155,7 +155,7 @@ class PokedexUsageContext {
|
||||
}
|
||||
|
||||
// Check if Pokémon in focus is owned
|
||||
isPokemonInFocusOwned = CobblemonClient.clientPokedexData.getHighestKnowledgeForSpecies(resolvedPokemon.species.resourceIdentifier) == PokedexEntryProgress.CAUGHT
|
||||
isPokemonInFocusOwned = CobblemonClient.clientPokedexData.getHighestKnowledgeForSpecies(resolvedPokemon.getApparentSpecies().resourceIdentifier) == PokedexEntryProgress.CAUGHT
|
||||
|
||||
// Randomize info frames for render
|
||||
if (focusIntervals == 0F) {
|
||||
@@ -170,7 +170,7 @@ class PokedexUsageContext {
|
||||
// Check if Pokémon in focus is new or has new data
|
||||
newPokemonInfo = CobblemonClient.clientPokedexData.getNewInformation(resolvedPokemon)
|
||||
if (newPokemonInfo == PokedexLearnedInformation.NONE) playSound(CobblemonSounds.POKEDEX_SCAN_DETAIL)
|
||||
else scannedSpecies = resolvedPokemon.species.resourceIdentifier
|
||||
else scannedSpecies = resolvedPokemon.getApparentSpecies().resourceIdentifier
|
||||
}
|
||||
} else {
|
||||
resetFocusedPokemonState()
|
||||
|
||||
@@ -314,7 +314,6 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
*/
|
||||
var friendship = this.form.baseFriendship
|
||||
private set(value) {
|
||||
// Don't check on client, that way we don't need to actually sync the config value it doesn't affect anything
|
||||
if (!this.isPossibleFriendship(value)) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -129,10 +129,21 @@ class Species : ClientDataSynchronizer<Species>, ShowdownIdentifiable {
|
||||
},
|
||||
ApplyPresets().apply {
|
||||
condition = Either.left("!q.entity.is_in_party".asExpression())
|
||||
presets.add(cobblemonResource("wanders"))
|
||||
presets.add(cobblemonResource("pokemon_sleeps"))
|
||||
presets.add(cobblemonResource("pokemon_breeding"))
|
||||
},
|
||||
ApplyPresets().apply {
|
||||
condition = Either.left("q.entity.behaviour.moving.walk.can_walk && !q.entity.behaviour.moving.walk.avoids_land".asExpression())
|
||||
presets.add(cobblemonResource("wanders"))
|
||||
},
|
||||
ApplyPresets().apply {
|
||||
condition = Either.left("q.entity.behaviour.moving.fly.can_fly && q.entity.behaviour.moving.walk.avoids_land".asExpression())
|
||||
presets.add(cobblemonResource("wanders_air"))
|
||||
},
|
||||
ApplyPresets().apply {
|
||||
condition = Either.left("q.entity.behaviour.moving.walk.avoids_land && q.entity.behaviour.moving.swim.can_swim_in_water && !q.entity.behaviour.moving.swim.avoids_water".asExpression())
|
||||
presets.add(cobblemonResource("wanders_water"))
|
||||
},
|
||||
ApplyPresets().apply {
|
||||
condition = Either.left("q.entity.is_wild".asExpression())
|
||||
// presets like aggression to players
|
||||
|
||||
@@ -8,7 +8,16 @@
|
||||
|
||||
package com.cobblemon.mod.common.pokemon.ai
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
|
||||
class CombatBehaviour {
|
||||
var willDefendSelf = false
|
||||
var willDefendOwner = true
|
||||
|
||||
@Transient
|
||||
val struct = ObjectValue(this).also {
|
||||
it.addFunction("will_defend_self") { DoubleValue(willDefendSelf) }
|
||||
it.addFunction("will_defend_owner") { DoubleValue(willDefendOwner) }
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
package com.cobblemon.mod.common.pokemon.ai
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.cobblemon.mod.common.pokemon.activestate.ShoulderedState
|
||||
import com.cobblemon.mod.common.util.party
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
@@ -21,13 +23,20 @@ class EntityBehaviour {
|
||||
// val avoidedByPhantom = false
|
||||
val avoidedBySkeleton = false
|
||||
|
||||
@Transient
|
||||
val struct = ObjectValue(this).also {
|
||||
it.addFunction("avoided_by_creeper") { DoubleValue(avoidedByCreeper) }
|
||||
// it.addFunction("avoided_by_phantom") { DoubleValue(avoidedByPhantom) }
|
||||
it.addFunction("avoided_by_skeleton") { DoubleValue(avoidedBySkeleton) }
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun hasCreeperFearedShoulderMount(player: ServerPlayer) : Boolean {
|
||||
return player.party().any { pokemon -> pokemon.state is ShoulderedState && pokemon.species.behaviour.entityInteract.avoidedByCreeper }
|
||||
return player.party().any { pokemon -> pokemon.state is ShoulderedState && pokemon.form.behaviour.entityInteract.avoidedByCreeper }
|
||||
}
|
||||
|
||||
fun hasSkeletonFearedShoulderMount(player: ServerPlayer) : Boolean {
|
||||
return player.party().any { pokemon -> pokemon.state is ShoulderedState && pokemon.species.behaviour.entityInteract.avoidedBySkeleton }
|
||||
return player.party().any { pokemon -> pokemon.state is ShoulderedState && pokemon.form.behaviour.entityInteract.avoidedBySkeleton }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,19 @@
|
||||
|
||||
package com.cobblemon.mod.common.pokemon.ai
|
||||
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.createDuplicateRuntime
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
|
||||
class FlyBehaviour {
|
||||
val canFly = false
|
||||
val flySpeedHorizontal = "0.3".asExpressionLike()
|
||||
val flySpeedHorizontal = "0.3".asExpression()
|
||||
|
||||
@Transient
|
||||
val struct = ObjectValue(this).also {
|
||||
it.addFunction("can_fly") { DoubleValue(canFly) }
|
||||
it.addFunction("fly_speed_horizontal") { it.environment.createDuplicateRuntime().resolveFloat(flySpeedHorizontal) }
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.pokemon.ai
|
||||
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
/**
|
||||
@@ -50,4 +51,13 @@ class FormPokemonBehaviour {
|
||||
|
||||
val combat: CombatBehaviour
|
||||
get() = _combat ?: parent.combat
|
||||
|
||||
@Transient
|
||||
val struct = ObjectValue(this).also {
|
||||
it.addFunction("resting") { resting.struct }
|
||||
it.addFunction("moving") { moving.struct }
|
||||
it.addFunction("idle") { idle.struct }
|
||||
it.addFunction("entity_interact") { entityInteract.struct }
|
||||
it.addFunction("combat") { combat.struct }
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,13 @@
|
||||
|
||||
package com.cobblemon.mod.common.pokemon.ai
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
|
||||
class IdleBehaviour {
|
||||
val pointsAtSpawn = false
|
||||
|
||||
@Transient
|
||||
val struct = ObjectValue(this)
|
||||
.addFunction("points_at_spawn") { DoubleValue(pointsAtSpawn) }
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
|
||||
package com.cobblemon.mod.common.pokemon.ai
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
|
||||
/**
|
||||
* Behavioural properties relating to a Pokémon's ability to look and move.
|
||||
*
|
||||
@@ -23,4 +26,16 @@ class MoveBehaviour {
|
||||
val wanderSpeed = 1.0
|
||||
val canLook = true
|
||||
val looksAtEntities = true
|
||||
|
||||
@Transient
|
||||
val struct = ObjectValue<MoveBehaviour>(this).also {
|
||||
it.addFunction("walk") { walk.struct }
|
||||
it.addFunction("swim") { swim.struct }
|
||||
it.addFunction("fly") { fly.struct }
|
||||
it.addFunction("step_height") { DoubleValue(stepHeight) }
|
||||
it.addFunction("wander_chance") { DoubleValue(wanderChance) }
|
||||
it.addFunction("wander_speed") { DoubleValue(wanderSpeed) }
|
||||
it.addFunction("can_look") { DoubleValue(canLook) }
|
||||
it.addFunction("looks_at_entities") { DoubleValue(looksAtEntities) }
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
package com.cobblemon.mod.common.pokemon.ai
|
||||
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
|
||||
/**
|
||||
* Collection of all AI properties definable at the species level of a Pokémon.
|
||||
*
|
||||
@@ -20,4 +22,13 @@ open class PokemonBehaviour {
|
||||
val idle = IdleBehaviour()
|
||||
val entityInteract = EntityBehaviour()
|
||||
val combat = CombatBehaviour()
|
||||
|
||||
@Transient
|
||||
val struct = ObjectValue<PokemonBehaviour>(this).also {
|
||||
it.addFunction("resting") { resting.struct }
|
||||
it.addFunction("moving") { moving.struct }
|
||||
it.addFunction("idle") { idle.struct }
|
||||
it.addFunction("entity_interact") { entityInteract.struct }
|
||||
it.addFunction("combat") { combat.struct }
|
||||
}
|
||||
}
|
||||
@@ -8,11 +8,13 @@
|
||||
|
||||
package com.cobblemon.mod.common.pokemon.ai
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.api.ai.SleepDepth
|
||||
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.cobblemon.mod.common.api.spawning.TimeRange
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.biome.Biome
|
||||
import net.minecraft.world.level.block.Block
|
||||
|
||||
/**
|
||||
* Behavioural properties relating to a Pokémon sleeping. This can be wild sleeping or sleeping on the player or both.
|
||||
@@ -23,7 +25,6 @@ import net.minecraft.world.level.biome.Biome
|
||||
class RestBehaviour {
|
||||
val canSleep = false
|
||||
val times = TimeRange.timeRanges["night"]!!
|
||||
val sleepChance = 1 / 600F
|
||||
val blocks = mutableListOf<RegistryLikeCondition<Block>>()
|
||||
val biomes = mutableListOf<RegistryLikeCondition<Biome>>()
|
||||
val light = IntRange(0, 15)
|
||||
@@ -32,4 +33,12 @@ class RestBehaviour {
|
||||
val skyLight: IntRange? = null
|
||||
|
||||
val willSleepOnBed = false
|
||||
|
||||
@Transient
|
||||
val struct = ObjectValue<RestBehaviour>(this).also {
|
||||
it.addFunction("can_sleep") { DoubleValue(canSleep) }
|
||||
it.addFunction("min_light") { DoubleValue(light.first) }
|
||||
it.addFunction("max_light") { DoubleValue(light.last) }
|
||||
it.addFunction("will_sleep_on_bed") { DoubleValue(willSleepOnBed) }
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,11 @@
|
||||
|
||||
package com.cobblemon.mod.common.pokemon.ai
|
||||
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.createDuplicateRuntime
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
import net.minecraft.tags.FluidTags
|
||||
import net.minecraft.tags.TagKey
|
||||
import net.minecraft.world.level.material.Fluid
|
||||
@@ -18,7 +22,7 @@ class SwimBehaviour {
|
||||
val hurtByLava = true
|
||||
val canSwimInWater = true
|
||||
val canSwimInLava = true
|
||||
val swimSpeed = "0.3".asExpressionLike()
|
||||
val swimSpeed = "0.3".asExpression()
|
||||
val canBreatheUnderwater = false
|
||||
val canBreatheUnderlava = false
|
||||
val canWalkOnWater = false
|
||||
@@ -27,4 +31,17 @@ class SwimBehaviour {
|
||||
fun canWalkOnFluid(tag: TagKey<Fluid>) = if (tag == FluidTags.WATER) canWalkOnWater else if (tag == FluidTags.LAVA) canWalkOnLava else false
|
||||
fun canBreatheUnderFluid(tag: TagKey<Fluid>) = if (tag == FluidTags.WATER) canBreatheUnderwater else if (tag == FluidTags.LAVA) canBreatheUnderlava else false
|
||||
fun canSwimInFluid(tag: TagKey<Fluid>) = if (tag == FluidTags.WATER) canSwimInWater else if (tag == FluidTags.LAVA) canSwimInLava else false
|
||||
|
||||
@Transient
|
||||
val struct = ObjectValue(this).also {
|
||||
it.addFunction("avoids_water") { DoubleValue(avoidsWater) }
|
||||
it.addFunction("hurt_by_lava") { DoubleValue(hurtByLava) }
|
||||
it.addFunction("can_swim_in_water") { DoubleValue(canSwimInWater) }
|
||||
it.addFunction("can_swim_in_lava") { DoubleValue(canSwimInLava) }
|
||||
it.addFunction("swim_speed") { it.environment.createDuplicateRuntime().resolveFloat(swimSpeed) }
|
||||
it.addFunction("can_breathe_underwater") { DoubleValue(canBreatheUnderwater) }
|
||||
it.addFunction("can_breathe_underlava") { DoubleValue(canBreatheUnderlava) }
|
||||
it.addFunction("can_walk_on_water") { DoubleValue(canWalkOnWater) }
|
||||
it.addFunction("can_walk_on_lava") { DoubleValue(canWalkOnLava) }
|
||||
}
|
||||
}
|
||||
@@ -8,11 +8,22 @@
|
||||
|
||||
package com.cobblemon.mod.common.pokemon.ai
|
||||
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.createDuplicateRuntime
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
|
||||
class WalkBehaviour {
|
||||
val canWalk = true
|
||||
val avoidsLand = false
|
||||
var walkSpeed: ExpressionLike = "0.35".asExpressionLike()
|
||||
var walkSpeed: Expression = "0.35".asExpression()
|
||||
|
||||
@Transient
|
||||
val struct = ObjectValue(this).also {
|
||||
it.addFunction("can_walk") { DoubleValue(canWalk) }
|
||||
it.addFunction("avoids_land") { DoubleValue(avoidsLand) }
|
||||
it.addFunction("walk_speed") { it.environment.createDuplicateRuntime().resolveFloat(walkSpeed) }
|
||||
}
|
||||
}
|
||||
+4
@@ -124,6 +124,10 @@ object CobblemonHeldItemManager : BaseCobblemonHeldItemManager() {
|
||||
if (battle.isPvP && !consumeHeldItems) {
|
||||
return
|
||||
}
|
||||
// Block stealing from NPCs
|
||||
if (battle.isPvN) {
|
||||
return
|
||||
}
|
||||
// if items aren't consumed, then we don't want to give them to wild pokemon (dupe)
|
||||
if (this.giveItemEffect.contains(effectId) && (pokemon.actor is PlayerBattleActor || consumeHeldItems)) {
|
||||
this.give(pokemon, itemID)
|
||||
|
||||
+1
@@ -147,6 +147,7 @@ internal object PropertiesCompletionProvider : DataRegistry {
|
||||
this.inject(setOf("originaltrainer", "ot"), setOf(""))
|
||||
this.inject(setOf("originaltrainertype", "ottype"), setOf("None", "Player", "NPC"))
|
||||
this.inject(setOf("nickname", "nick"), setOf(""))
|
||||
this.inject(setOf("helditem", "held_item"), setOf("cobblemon:exp_share"))
|
||||
|
||||
Stats.PERMANENT.forEach{ stat ->
|
||||
val statName = stat.toString().lowercase()
|
||||
|
||||
@@ -233,6 +233,7 @@ object DataKeys {
|
||||
const val NPC_HITBOX_WIDTH = "Width"
|
||||
const val NPC_HITBOX_HEIGHT = "Height"
|
||||
const val NPC_HITBOX_FIXED = "Fixed"
|
||||
const val NPC_HIDE_NAME_TAG = "HideNPCNameTag"
|
||||
|
||||
const val SCRIPTED_BRAIN_IS_CUSTOM = "BehavioursAreCustom"
|
||||
const val SCRIPTED_BRAIN_PRESETS = "BrainPresets"
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.util
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.PathfindingMedium
|
||||
import com.google.common.collect.ImmutableMap
|
||||
import com.mojang.serialization.Dynamic
|
||||
import net.minecraft.core.BlockPos
|
||||
@@ -17,8 +18,10 @@ import net.minecraft.nbt.Tag
|
||||
import net.minecraft.network.syncher.EntityDataAccessor
|
||||
import net.minecraft.network.syncher.SynchedEntityData
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.pathfinder.PathType.WALKABLE
|
||||
import net.minecraft.world.phys.AABB
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.BooleanOp
|
||||
@@ -197,6 +200,15 @@ fun Entity.isStandingOnSand(): Boolean {
|
||||
return isStandingOn(setOf(Blocks.SAND))
|
||||
}
|
||||
|
||||
fun PathfinderMob.getPathfindingMedium(): PathfindingMedium {
|
||||
return when {
|
||||
this.isUnderWater -> PathfindingMedium.WATER
|
||||
this.isInLava -> PathfindingMedium.LAVA
|
||||
navigation.nodeEvaluator.getPathType(this, blockPosition()) == WALKABLE -> PathfindingMedium.LAND
|
||||
else -> PathfindingMedium.AIR
|
||||
}
|
||||
}
|
||||
|
||||
fun Entity.isStandingOnRedSand(): Boolean {
|
||||
return isStandingOn(setOf(Blocks.RED_SAND))
|
||||
}
|
||||
|
||||
@@ -223,4 +223,10 @@ fun Iterable<MoValue>.asArrayValue(): ArrayStruct {
|
||||
val array = ArrayStruct()
|
||||
forEachIndexed { index, value -> array.setDirectly("$index", value) }
|
||||
return array
|
||||
}
|
||||
|
||||
fun MoLangEnvironment.createDuplicateRuntime(): MoLangRuntime {
|
||||
val runtime = MoLangRuntime()
|
||||
runtime.environment.cloneFrom(this)
|
||||
return runtime
|
||||
}
|
||||
@@ -36,6 +36,7 @@ import net.minecraft.util.Mth
|
||||
import net.minecraft.world.InteractionHand
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.item.ItemEntity
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.ItemStack
|
||||
@@ -46,7 +47,10 @@ import net.minecraft.world.phys.BlockHitResult
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.HitResult
|
||||
import java.util.*
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.min
|
||||
import kotlin.math.sin
|
||||
|
||||
// Stuff like getting their party
|
||||
fun ServerPlayer.party() = Cobblemon.storage.getParty(this)
|
||||
@@ -414,7 +418,7 @@ fun Player.giveOrDropItemStack(stack: ItemStack, playSound: Boolean = true) {
|
||||
val inserted = this.inventory.add(stack)
|
||||
if (inserted && stack.isEmpty) {
|
||||
stack.count = 1
|
||||
this.drop(stack, false)?.makeFakeItem()
|
||||
this.dropFakeItem(stack)
|
||||
if (playSound) {
|
||||
this.level().playSound(null, this.x, this.y, this.z, SoundEvents.ITEM_PICKUP, SoundSource.PLAYERS, 0.2f, ((this.random.nextFloat() - this.random.nextFloat()) * 0.7f + 1.0f) * 2.0f)
|
||||
}
|
||||
@@ -428,6 +432,31 @@ fun Player.giveOrDropItemStack(stack: ItemStack, playSound: Boolean = true) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function to mimic the [Player.drop] method but as a fake item entity.
|
||||
* Avoids cases where other mods listen to that drop method and expect a real item to be dropped.
|
||||
*/
|
||||
fun Player.dropFakeItem(stack: ItemStack): ItemEntity {
|
||||
val d = this.eyeY - 0.3
|
||||
val itemEntity = ItemEntity(this.level(), this.x, d, this.z, stack)
|
||||
|
||||
val f = 0.3F
|
||||
val g = sin(this.xRot * (PI / 180.0)).toFloat()
|
||||
val h = cos(this.xRot * (PI / 180.0)).toFloat()
|
||||
val i = sin(this.yRot * (PI / 180.0)).toFloat()
|
||||
val j = cos(this.yRot * (PI / 180.0)).toFloat()
|
||||
val k = this.random.nextFloat() * (PI * 2)
|
||||
val l = 0.02F * this.random.nextFloat()
|
||||
itemEntity.deltaMovement = Vec3(
|
||||
(-i * h * f).toDouble() + cos(k) * l.toDouble(),
|
||||
(-g * f + 0.1f + (this.random.nextFloat() - this.random.nextFloat()) * 0.1f).toDouble(),
|
||||
(j * h * f).toDouble() + sin(k) * l.toDouble()
|
||||
)
|
||||
|
||||
itemEntity.makeFakeItem()
|
||||
return itemEntity
|
||||
}
|
||||
|
||||
/** Retrieves the battle theme associated with this player, or the default PVP theme if null. */
|
||||
fun ServerPlayer.getBattleTheme() = Cobblemon.playerDataManager.getGenericData(this).battleTheme?.let { BuiltInRegistries.SOUND_EVENT.get(it) } ?: CobblemonSounds.PVP_BATTLE
|
||||
|
||||
@@ -441,4 +470,4 @@ fun Player.isPartyBusy() =
|
||||
|
||||
fun Player.isUsingPokedex() = isUsingItem &&
|
||||
((mainHandItem.item is PokedexItem && usedItemHand == InteractionHand.MAIN_HAND) ||
|
||||
(offhandItem.item is PokedexItem && usedItemHand == InteractionHand.OFF_HAND))
|
||||
(offhandItem.item is PokedexItem && usedItemHand == InteractionHand.OFF_HAND))
|
||||
@@ -83,6 +83,7 @@ object NPCClassAdapter : JsonDeserializer<NPCClass> {
|
||||
obj.get("isInvulnerable")?.let { npcClass.isInvulnerable = it.asBoolean }
|
||||
obj.get("isLeashable")?.let { npcClass.isLeashable = it.asBoolean }
|
||||
obj.get("allowProjectileHits")?.let { npcClass.allowProjectileHits = it.asBoolean }
|
||||
obj.get("hideNameTag")?.let { npcClass.hideNameTag = it.asBoolean }
|
||||
|
||||
return npcClass
|
||||
}
|
||||
|
||||
+6
-2
@@ -15,6 +15,7 @@ import com.cobblemon.mod.common.api.moves.MoveSet
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.SynchronizedSpeciesFeature
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.SynchronizedSpeciesFeatureProvider
|
||||
import com.cobblemon.mod.common.client.settings.ServerSettings
|
||||
import com.cobblemon.mod.common.pokemon.*
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import com.cobblemon.mod.common.util.codec.CodecUtils
|
||||
@@ -99,15 +100,18 @@ internal class ClientPokemonP1(
|
||||
const val FEATURES = "Features"
|
||||
const val FEATURE_ID = "${Cobblemon.MODID}:feature_id"
|
||||
|
||||
/**
|
||||
* do not use cobblemon.config in here, as this is used by the client whose config is different to server, always use [ServerSettings]
|
||||
*/
|
||||
internal val CODEC: MapCodec<ClientPokemonP1> = RecordCodecBuilder.mapCodec { instance ->
|
||||
instance.group(
|
||||
UUIDUtil.LENIENT_CODEC.fieldOf(DataKeys.POKEMON_UUID).forGetter(ClientPokemonP1::uuid),
|
||||
Species.BY_IDENTIFIER_CODEC.fieldOf(DataKeys.POKEMON_SPECIES_IDENTIFIER).forGetter(ClientPokemonP1::species),
|
||||
Codec.STRING.fieldOf(DataKeys.POKEMON_FORM_ID).forGetter { pokemon -> pokemon.form.formOnlyShowdownId() },
|
||||
ComponentSerialization.CODEC.optionalFieldOf(DataKeys.POKEMON_NICKNAME).forGetter(ClientPokemonP1::nickname),
|
||||
CodecUtils.dynamicIntRange(1) { Cobblemon.config.maxPokemonLevel }.fieldOf(DataKeys.POKEMON_LEVEL).forGetter(ClientPokemonP1::level),
|
||||
CodecUtils.dynamicIntRange(1) { ServerSettings.maxPokemonLevel }.fieldOf(DataKeys.POKEMON_LEVEL).forGetter(ClientPokemonP1::level),
|
||||
Codec.intRange(0, Int.MAX_VALUE).fieldOf(DataKeys.POKEMON_EXPERIENCE).forGetter(ClientPokemonP1::experience),
|
||||
CodecUtils.dynamicIntRange(0) { Cobblemon.config.maxPokemonFriendship }.fieldOf(DataKeys.POKEMON_FRIENDSHIP).forGetter(ClientPokemonP1::friendship),
|
||||
CodecUtils.dynamicIntRange(0) { ServerSettings.maxPokemonFriendship }.fieldOf(DataKeys.POKEMON_FRIENDSHIP).forGetter(ClientPokemonP1::friendship),
|
||||
Codec.intRange(0, Int.MAX_VALUE).fieldOf(DataKeys.POKEMON_HEALTH).forGetter(ClientPokemonP1::currentHealth),
|
||||
Gender.CODEC.fieldOf(DataKeys.POKEMON_GENDER).forGetter(ClientPokemonP1::gender),
|
||||
IVs.CODEC.fieldOf(DataKeys.POKEMON_IVS).forGetter(ClientPokemonP1::ivs),
|
||||
|
||||
+5
-1
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.util.codec.internal
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.types.tera.TeraType
|
||||
import com.cobblemon.mod.common.client.settings.ServerSettings
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.AddEvolutionPacket.Companion.convertToDisplay
|
||||
import com.cobblemon.mod.common.pokeball.PokeBall
|
||||
import com.cobblemon.mod.common.pokemon.*
|
||||
@@ -71,6 +72,9 @@ internal data class ClientPokemonP2(
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* do not use cobblemon.config in here, as this is used by the client whose config is different to server, always use [ServerSettings]
|
||||
*/
|
||||
internal val CODEC: MapCodec<ClientPokemonP2> = RecordCodecBuilder.mapCodec { instance ->
|
||||
instance.group(
|
||||
ShoulderedState.CODEC.optionalFieldOf(DataKeys.POKEMON_STATE).forGetter(ClientPokemonP2::state),
|
||||
@@ -86,7 +90,7 @@ internal data class ClientPokemonP2(
|
||||
CompoundTag.CODEC.fieldOf(DataKeys.POKEMON_PERSISTENT_DATA).forGetter(ClientPokemonP2::persistentData),
|
||||
UUIDUtil.LENIENT_CODEC.optionalFieldOf(DataKeys.TETHERING_ID).forGetter(ClientPokemonP2::tetheringId),
|
||||
TeraType.BY_IDENTIFIER_CODEC.fieldOf(DataKeys.POKEMON_TERA_TYPE).forGetter(ClientPokemonP2::teraType),
|
||||
CodecUtils.dynamicIntRange(0) { Cobblemon.config.maxDynamaxLevel }.fieldOf(DataKeys.POKEMON_DMAX_LEVEL).forGetter(ClientPokemonP2::dmaxLevel),
|
||||
CodecUtils.dynamicIntRange(0) { ServerSettings.maxDynamaxLevel }.fieldOf(DataKeys.POKEMON_DMAX_LEVEL).forGetter(ClientPokemonP2::dmaxLevel),
|
||||
Codec.BOOL.fieldOf(DataKeys.POKEMON_GMAX_FACTOR).forGetter(ClientPokemonP2::gmaxFactor),
|
||||
Codec.BOOL.fieldOf(DataKeys.POKEMON_TRADEABLE).forGetter(ClientPokemonP2::tradeable)
|
||||
).apply(instance, ::ClientPokemonP2)
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.util.codec.internal
|
||||
|
||||
import com.cobblemon.mod.common.client.settings.ServerSettings
|
||||
import com.cobblemon.mod.common.pokemon.OriginalTrainerType
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
@@ -32,6 +33,9 @@ internal data class ClientPokemonP3(
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* do not use cobblemon.config in here, as this is used by the client whose config is different to server, always use [ServerSettings]
|
||||
*/
|
||||
internal val CODEC: MapCodec<ClientPokemonP3> = RecordCodecBuilder.mapCodec { instance ->
|
||||
instance.group(
|
||||
OriginalTrainerType.CODEC.optionalFieldOf(DataKeys.POKEMON_ORIGINAL_TRAINER_TYPE, OriginalTrainerType.NONE).forGetter(ClientPokemonP3::originalTrainerType),
|
||||
|
||||
+8
@@ -43,6 +43,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.nidoranf.cry": {
|
||||
"animation_length": 1.2,
|
||||
"sound_effects": {
|
||||
"0.04": {
|
||||
"effect": "pokemon.nidoranf.cry"
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.nidoranf.blink": {
|
||||
"animation_length": 0.16667,
|
||||
"bones": {
|
||||
|
||||
+1
-1
@@ -354,7 +354,7 @@
|
||||
}
|
||||
},
|
||||
"sound_effects": {
|
||||
"0.0": {
|
||||
"0.04": {
|
||||
"effect": "pokemon.nidorina.cry"
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -105,8 +105,8 @@
|
||||
}
|
||||
},
|
||||
"sound_effects": {
|
||||
"0.0": {
|
||||
"effect": "nidoqueen_ambient"
|
||||
"0.04": {
|
||||
"effect": "pokemon.nidoqueen.cry"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
+8
@@ -47,6 +47,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.nidoranm.cry": {
|
||||
"animation_length": 1.2,
|
||||
"sound_effects": {
|
||||
"0.04": {
|
||||
"effect": "pokemon.nidoranm.cry"
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.nidoranm.blink": {
|
||||
"animation_length": 0.16667,
|
||||
"bones": {
|
||||
|
||||
+8
@@ -46,6 +46,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.nidorino.cry": {
|
||||
"animation_length": 1.2,
|
||||
"sound_effects": {
|
||||
"0.04": {
|
||||
"effect": "pokemon.nidorino.cry"
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.nidorino.blink": {
|
||||
"animation_length": 1,
|
||||
"bones": {
|
||||
|
||||
+1
-1
@@ -132,7 +132,7 @@
|
||||
},
|
||||
"sound_effects": {
|
||||
"0.0": {
|
||||
"effect": "nidoking_ambient"
|
||||
"effect": "pokemon.nidoking.cry"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user