Compare commits

..
Author SHA1 Message Date
whatsy b6beed0963 cleanup 2026-11-03 10:27:13 -05:00
Ronak Chavva 2a882e137a fix(*): temp feature individualism 2026-11-02 13:34:52 -06:00
whatsy 9be710ff32 this floette is gonna drive me insane 2026-11-02 10:57:44 -05:00
whatsy 7a9393b39f more pokedex compat and other stuff 2026-11-01 15:12:12 -05:00
whatsy 087a167bfa ...and then make that PlatformRegistry actually work 2026-10-30 15:18:54 -04:00
whatsy 461d21a87d Convert CobblemonLootItemConditions into a PlatformRegistry 2026-10-30 14:48:30 -04:00
whatsy 78953357a8 Pokedex compat 2026-10-30 14:39:38 -04:00
whatsy bdfabb3724 Update CHANGELOG.md + resolve merge conflicts 2026-10-27 23:54:56 -04:00
whatsy 3adb6144a3 Merge branch 'refs/heads/main' into drop-system-update
# Conflicts:
#	common/src/main/resources/data/cobblemon/species/generation1/exeggutor.json
#	common/src/main/resources/data/cobblemon/species/generation4/rotom.json
#	common/src/main/resources/data/cobblemon/species/generation4/wormadam.json
#	common/src/main/resources/data/cobblemon/species/generation5/kyurem.json
#	common/src/main/resources/data/cobblemon/species/generation6/avalugg.json
#	common/src/main/resources/data/cobblemon/species/generation6/flabebe.json
#	common/src/main/resources/data/cobblemon/species/generation6/floette.json
#	common/src/main/resources/data/cobblemon/species/generation6/florges.json
#	common/src/main/resources/data/cobblemon/species/generation6/goodra.json
#	common/src/main/resources/data/cobblemon/species/generation6/greninja.json
#	common/src/main/resources/data/cobblemon/species/generation6/sliggoo.json
#	common/src/main/resources/data/cobblemon/species/generation7/decidueye.json
#	common/src/main/resources/data/cobblemon/species/generation8/toxtricity.json
2026-10-27 23:48:49 -04:00
whatsy 65bcd118a3 finalizing 2026-10-21 13:25:46 -04:00
whatsy bf6f97e740 auto fire aspect support 2026-10-21 12:25:24 -04:00
whatsy 4e48e2ff9b scraper updates 2026-10-20 18:43:01 -04:00
whatsy faa488b153 ported all pokemon over to loot tables 2026-10-19 17:09:20 -04:00
whatsy 93dbc015fb loot table drop entry type implementation 2026-10-19 13:49:34 -04:00
whatsy 7edf6669d8 Vanilla loot tables for pokemon drops: wip, pushing for review 2026-10-19 11:52:44 -04:00
2372 changed files with 97408 additions and 18013 deletions

No files matched your search

+17 -5
View File
@@ -1,15 +1,27 @@
# Changelog
## [1.8.x (MONTH xth, 2026)](#1-8-x)
## [1.8.5 (MONTH xth, 2026)](#1-8-5)
### Additions
### Particles
### Cries added/updated for the following Pokémon
### Model updates for the following Pokémon
### Animation updates for the following Pokémon
### Changes
### Fixes
### Developer
### Molang & Datapacks
- Added a `loot_table` drop entry type.
- Accepts an `id` field, pointing to a vanilla loot table.
- All base mod Pokémon have been moved to this new system.
- Added the `cobblemon:requirement` loot item condition.
- Accepts a `requirement` field, containing a Requirement, using the existing Cobblemon requirement system.
### Particles
### Localization
- Updated translations for:
### Localization
@@ -15,9 +15,7 @@ import com.cobblemon.mod.common.ModAPI;
import com.cobblemon.mod.common.item.PokeBallItem;
import com.cobblemon.mod.common.item.PokedexItem;
import com.cobblemon.mod.common.item.WearableItem;
import com.cobblemon.mod.common.item.components.PokeBallComponent;
import com.cobblemon.mod.common.item.components.TMMoveComponent;
import com.cobblemon.mod.common.pokeball.PokeBall;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.ItemModelShaper;
@@ -59,32 +57,12 @@ public abstract class ItemRendererMixin {
cancellable = true
)
private void cobblemon$overrideItemModel(ItemStack stack, ItemDisplayContext renderMode, boolean leftHanded, PoseStack matrices, MultiBufferSource multiBufferSource, int light, int overlay, BakedModel model, CallbackInfo ci) {
boolean shouldBe2d =
renderMode == ItemDisplayContext.GUI
|| renderMode == ItemDisplayContext.FIXED
|| stack.getItem() == CobblemonItems.TECHNICAL_MACHINE;
boolean shouldBe3d =
renderMode == ItemDisplayContext.FIRST_PERSON_LEFT_HAND
|| renderMode == ItemDisplayContext.FIRST_PERSON_RIGHT_HAND
|| renderMode == ItemDisplayContext.THIRD_PERSON_LEFT_HAND
|| renderMode == ItemDisplayContext.THIRD_PERSON_RIGHT_HAND
|| renderMode == ItemDisplayContext.GROUND
|| renderMode == ItemDisplayContext.HEAD;
boolean shouldBe2d = renderMode == ItemDisplayContext.GUI || renderMode == ItemDisplayContext.FIXED || stack.getItem() == CobblemonItems.TECHNICAL_MACHINE;
ResourceLocation resourceLocation = null;
if (stack.getItem() instanceof PokeBallItem) {
if (shouldBe2d || renderMode == ItemDisplayContext.NONE) {
resourceLocation = PokeBallComponent.getPokeBall(stack).getModel2d();
}
if (shouldBe3d) {
resourceLocation = PokeBallComponent.getPokeBall(stack).getModel3d();
}
}
if (shouldBe2d) {
if (stack.getItem() instanceof PokedexItem pokedexItem) resourceLocation = pokedexItem.getType().getItemSpritePath();
if (stack.getItem() == CobblemonItems.TECHNICAL_MACHINE) {
if (stack.getItem() instanceof PokeBallItem pokeBallItem) resourceLocation = pokeBallItem.getPokeBall().getModel2d();
else if (stack.getItem() instanceof PokedexItem pokedexItem) resourceLocation = pokedexItem.getType().getItemSpritePath();
else if (stack.getItem() == CobblemonItems.TECHNICAL_MACHINE) {
TMMoveComponent component = stack.get(CobblemonItemComponents.TM_MOVE);
if (component != null) {
resourceLocation = new ResourceLocation(Cobblemon.MODID, "tm/" + component.getMove().getElementalType().showdownId() + "_tm");
@@ -96,9 +74,6 @@ public abstract class ItemRendererMixin {
if (resourceLocation != null) {
BakedModel replacementModel = this.itemModelShaper.getModelManager().getModel(new ModelResourceLocation(resourceLocation, "inventory"));
if (!cobblemon$isSameModel(model, replacementModel)) {
if (stack.getItem() instanceof PokeBallItem) {
ci.cancel();
}
ci.cancel();
render(stack, renderMode, leftHanded, matrices, multiBufferSource, light, overlay, replacementModel);
}
@@ -108,21 +83,16 @@ public abstract class ItemRendererMixin {
@Inject(method = "getModel", at = @At("HEAD"), cancellable = true)
private void cobblemon$getItemModel(ItemStack stack, Level world, LivingEntity entity, int seed, CallbackInfoReturnable<BakedModel> cir) {
ResourceLocation resourceLocation = null;
switch (stack.getItem()) {
case PokeBallItem ignored -> resourceLocation = PokeBallComponent.getPokeBall(stack).getModel3d();
case PokedexItem pokedexItem -> {
boolean isScanModel = entity instanceof Player && entity.getUseItem() == stack && entity.isUsingItem();
boolean canOpenScreen = entity != null && ((entity.getOffhandItem() == stack && !(entity.getMainHandItem().getItem() instanceof PokedexItem)) || entity.getMainHandItem() == stack);
resourceLocation = pokedexItem.getType().getItemModelPath(isScanModel ? "scanning" : (canOpenScreen ? null : "off"));
}
case WearableItem wearableItem -> resourceLocation = wearableItem.getModel3d();
default -> {
}
if (stack.getItem() instanceof PokeBallItem pokeBallItem) resourceLocation = pokeBallItem.getPokeBall().getModel3d();
else if (stack.getItem() instanceof PokedexItem pokedexItem) {
boolean isScanModel = entity instanceof Player && entity.getUseItem() == stack && entity.isUsingItem();
boolean canOpenScreen = entity != null && ((entity.getOffhandItem() == stack && !(entity.getMainHandItem().getItem() instanceof PokedexItem)) || entity.getMainHandItem() == stack);
resourceLocation = pokedexItem.getType().getItemModelPath(isScanModel ? "scanning" : (canOpenScreen ? null : "off"));
}
else if (stack.getItem() instanceof WearableItem wearableItem) resourceLocation = wearableItem.getModel3d();
if (resourceLocation != null) {
String modelPath = (stack.getItem() instanceof PokeBallItem && stack.has(CobblemonItemComponents.POKE_BALL)) ? "inventory" : MODEL_PATH;
BakedModel model = this.itemModelShaper.getModelManager().getModel(new ModelResourceLocation(resourceLocation, modelPath));
BakedModel model = this.itemModelShaper.getModelManager().getModel(new ModelResourceLocation(resourceLocation, MODEL_PATH));
ClientLevel clientWorld = world instanceof ClientLevel ? (ClientLevel) world : null;
BakedModel overriddenModel = model.getOverrides().resolve(model, stack, clientWorld, entity, seed);
cir.setReturnValue(overriddenModel == null ? this.itemModelShaper.getModelManager().getMissingModel() : overriddenModel);
@@ -133,11 +103,10 @@ public abstract class ItemRendererMixin {
// this falls back to comparing the model contents (e.g. location of the texture, width and height)
@Unique
private static boolean cobblemon$isSameModel(BakedModel original, BakedModel replacement) {
return original.equals(replacement) || (
original.getParticleIcon().contents().name().equals(replacement.getParticleIcon().contents().name())
&& original.getParticleIcon().contents().width() == replacement.getParticleIcon().contents().width()
&& original.getParticleIcon().contents().height() == replacement.getParticleIcon().contents().height()
);
return original.equals(replacement) ||
(original.getParticleIcon().contents().name().equals(replacement.getParticleIcon().contents().name()) &&
original.getParticleIcon().contents().width() == replacement.getParticleIcon().contents().width() &&
original.getParticleIcon().contents().height() == replacement.getParticleIcon().contents().height());
}
}
@@ -9,7 +9,6 @@
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.client.CobblemonBakingOverrides;
import com.cobblemon.mod.common.client.CobblemonClient;
import net.minecraft.client.Minecraft;
import net.minecraft.client.color.block.BlockColors;
import net.minecraft.client.renderer.block.model.BlockModel;
@@ -20,7 +19,6 @@ import net.minecraft.client.resources.model.UnbakedModel;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.Resource;
import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.world.item.ItemDisplayContext;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
@@ -31,7 +29,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@Mixin(ModelBakery.class)
public abstract class ModelLoaderMixin {
@@ -41,18 +38,15 @@ public abstract class ModelLoaderMixin {
@Shadow protected abstract void loadItemModelAndDependencies(ResourceLocation resourceLocation);
@Shadow protected abstract void loadSpecialItemModelAndDependencies(ModelResourceLocation modelResourceLocation);
@Unique
List<String> dynamicFolders = Arrays.asList("egg", "tm", "poke_ball");
List<String> dynamicFolders = Arrays.asList("egg", "tm");
@Inject(
method = "<init>",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/util/profiling/ProfilerFiller;popPush(Ljava/lang/String;)V",
ordinal = 1,
shift = At.Shift.AFTER
ordinal = 1
)
)
public void loadCustomItemModels(BlockColors blockColors,
@@ -73,24 +67,13 @@ public abstract class ModelLoaderMixin {
* hacky at the init stage and hacky at the render stage. Pretty cool in the gameplay stage though.
*
* - Hiro
*
* We also want to load different contexts (first/third person etc.) for poke ball models, so additional check was added for them.
* - Gito
*/
dynamicFolders.forEach(folder -> {
Map<ResourceLocation, Resource> map = Minecraft.getInstance().getResourceManager().listResources("models/item/" + folder, (t) -> true);
map.forEach((key, value) -> {
ResourceLocation resourceLocation = new ResourceLocation(key.getNamespace(), key.getPath().replace("models/item/", "").replace(".json", ""));
this.loadItemModelAndDependencies(resourceLocation);
if (folder.equals("poke_ball")) {
// also load variants for different display ctx
Arrays.stream(ItemDisplayContext.values())
.forEach(item -> {
ModelResourceLocation model = new ModelResourceLocation(resourceLocation, item.getSerializedName());
this.loadSpecialItemModelAndDependencies(model);
});
}
});
});
}
@@ -16,6 +16,7 @@ import com.cobblemon.mod.common.api.drop.CommandDropEntry
import com.cobblemon.mod.common.api.drop.DropEntry
import com.cobblemon.mod.common.api.drop.EvolutionItemDropEntry
import com.cobblemon.mod.common.api.drop.ItemDropEntry
import com.cobblemon.mod.common.api.drop.LootTableDropEntry
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.CobblemonEvents.DATA_SYNCHRONIZED
import com.cobblemon.mod.common.api.habitats.HabitatPools
@@ -90,6 +91,7 @@ import com.cobblemon.mod.common.events.EntityCallbackHandler
import com.cobblemon.mod.common.events.PokedexHandler
import com.cobblemon.mod.common.events.ServerTickHandler
import com.cobblemon.mod.common.events.StatHandler
import com.cobblemon.mod.common.loot.CobblemonLootItemConditions
import com.cobblemon.mod.common.net.messages.client.settings.ServerSettingsPacket
import com.cobblemon.mod.common.permission.LaxPermissionValidator
import com.cobblemon.mod.common.platform.events.PlatformEvents
@@ -223,12 +225,15 @@ object Cobblemon {
implementation.registerEntityDataSerializers()
implementation.registerCriteria()
implementation.registerEntitySubPredicates()
implementation.registerLootItemConditions()
implementation.registerMobEffects()
DispenserBehaviorRegistry.registerDispenserBehaviors()
CobblemonLootItemConditions.touch()
DropEntry.register("command", CommandDropEntry::class.java)
DropEntry.register("item", ItemDropEntry::class.java, isDefault = true)
DropEntry.register("evolution", EvolutionItemDropEntry::class.java)
DropEntry.register("loot_table", LootTableDropEntry::class.java)
ExperienceGroups.registerDefaults()
CaptureCalculators.registerDefaults()
@@ -47,7 +47,7 @@ object CobblemonEntities : PlatformRegistry<Registry<EntityType<*>>, ResourceKey
@JvmField
val EMPTY_POKEBALL: EntityType<EmptyPokeBallEntity> = this.create(
EMPTY_POKEBALL_KEY.path,
EntityType.Builder.of({ _, world -> EmptyPokeBallEntity(PokeBalls.STRANGE_BALL, world) }, MobCategory.MISC)
EntityType.Builder.of({ _, world -> EmptyPokeBallEntity(PokeBalls.POKE_BALL, world) }, MobCategory.MISC)
.build(EMPTY_POKEBALL_KEY.toString())
)
@@ -99,4 +99,4 @@ object CobblemonEntities : PlatformRegistry<Registry<EntityType<*>>, ResourceKey
consumer(POKEMON, PokemonEntity.createAttributes())
consumer(NPC, NPCEntity.createAttributes())
}
}
}
@@ -118,6 +118,7 @@ interface CobblemonImplementation {
fun registerMenu()
fun registerEntitySubPredicates()
fun registerLootItemConditions()
/**
* TODO
@@ -99,12 +99,6 @@ object CobblemonItemComponents : PlatformRegistry<Registry<DataComponentType<*>>
.networkSynchronized(ByteBufCodecs.BOOL)
.build())
@JvmField
val POKE_BALL: DataComponentType<PokeBallComponent> = create("poke_ball", DataComponentType.builder<PokeBallComponent>()
.persistent(PokeBallComponent.CODEC)
.networkSynchronized(PokeBallComponent.PACKET_CODEC)
.build())
fun register() {
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:pokemon_item"), POKEMON_ITEM)
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:bait"), BAIT)
@@ -118,10 +112,9 @@ object CobblemonItemComponents : PlatformRegistry<Registry<DataComponentType<*>>
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:food"), FOOD)
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:mob_effects"), MOB_EFFECTS)
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:held_item_effect"), HELD_ITEM_EFFECT)
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:poke_ball"), POKE_BALL)
}
override val registry = BuiltInRegistries.DATA_COMPONENT_TYPE
override val resourceKey = Registries.DATA_COMPONENT_TYPE
}
}
@@ -75,105 +75,103 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
val NPC_EDITOR = create("npc_editor", CobblemonItem(Item.Properties().stacksTo(1)))
@JvmField
val pokeBalls = mutableMapOf< ResourceLocation, PokeBallItem>()
val pokeBalls = mutableListOf<PokeBallItem>()
@JvmField
val STRANGE_BALL = pokeBallItem("strange_ball")
val POKE_BALL = pokeBallItem(PokeBalls.POKE_BALL)
@JvmField
val POKE_BALL = pokeBallItem("poke_ball")
val CITRINE_BALL = pokeBallItem(PokeBalls.CITRINE_BALL)
@JvmField
val CITRINE_BALL = pokeBallItem("citrine_ball")
val VERDANT_BALL = pokeBallItem(PokeBalls.VERDANT_BALL)
@JvmField
val VERDANT_BALL = pokeBallItem("verdant_ball")
val AZURE_BALL = pokeBallItem(PokeBalls.AZURE_BALL)
@JvmField
val AZURE_BALL = pokeBallItem("azure_ball")
val ROSEATE_BALL = pokeBallItem(PokeBalls.ROSEATE_BALL)
@JvmField
val ROSEATE_BALL = pokeBallItem("roseate_ball")
val SLATE_BALL = pokeBallItem(PokeBalls.SLATE_BALL)
@JvmField
val SLATE_BALL = pokeBallItem("slate_ball")
val PREMIER_BALL = pokeBallItem(PokeBalls.PREMIER_BALL)
@JvmField
val PREMIER_BALL = pokeBallItem("premier_ball")
val GREAT_BALL = pokeBallItem(PokeBalls.GREAT_BALL)
@JvmField
val GREAT_BALL = pokeBallItem("great_ball")
val ULTRA_BALL = pokeBallItem(PokeBalls.ULTRA_BALL)
@JvmField
val ULTRA_BALL = pokeBallItem("ultra_ball")
val SAFARI_BALL = pokeBallItem(PokeBalls.SAFARI_BALL)
@JvmField
val SAFARI_BALL = pokeBallItem("safari_ball")
val FAST_BALL = pokeBallItem(PokeBalls.FAST_BALL)
@JvmField
val FAST_BALL = pokeBallItem("fast_ball")
val LEVEL_BALL = pokeBallItem(PokeBalls.LEVEL_BALL)
@JvmField
val LEVEL_BALL = pokeBallItem("level_ball")
val LURE_BALL = pokeBallItem(PokeBalls.LURE_BALL)
@JvmField
val LURE_BALL = pokeBallItem("lure_ball")
val HEAVY_BALL = pokeBallItem(PokeBalls.HEAVY_BALL)
@JvmField
val HEAVY_BALL = pokeBallItem("heavy_ball")
val LOVE_BALL = pokeBallItem(PokeBalls.LOVE_BALL)
@JvmField
val LOVE_BALL = pokeBallItem("love_ball")
val FRIEND_BALL = pokeBallItem(PokeBalls.FRIEND_BALL)
@JvmField
val FRIEND_BALL = pokeBallItem("friend_ball")
val MOON_BALL = pokeBallItem(PokeBalls.MOON_BALL)
@JvmField
val MOON_BALL = pokeBallItem("moon_ball")
val SPORT_BALL = pokeBallItem(PokeBalls.SPORT_BALL)
@JvmField
val SPORT_BALL = pokeBallItem("sport_ball")
val PARK_BALL = pokeBallItem(PokeBalls.PARK_BALL)
@JvmField
val PARK_BALL = pokeBallItem("park_ball")
val NET_BALL = pokeBallItem(PokeBalls.NET_BALL)
@JvmField
val NET_BALL = pokeBallItem("net_ball")
val DIVE_BALL = pokeBallItem(PokeBalls.DIVE_BALL)
@JvmField
val DIVE_BALL = pokeBallItem("dive_ball")
val NEST_BALL = pokeBallItem(PokeBalls.NEST_BALL)
@JvmField
val NEST_BALL = pokeBallItem("nest_ball")
val REPEAT_BALL = pokeBallItem(PokeBalls.REPEAT_BALL)
@JvmField
val REPEAT_BALL = pokeBallItem("repeat_ball")
val TIMER_BALL = pokeBallItem(PokeBalls.TIMER_BALL)
@JvmField
val TIMER_BALL = pokeBallItem("timer_ball")
val LUXURY_BALL = pokeBallItem(PokeBalls.LUXURY_BALL)
@JvmField
val LUXURY_BALL = pokeBallItem("luxury_ball")
val DUSK_BALL = pokeBallItem(PokeBalls.DUSK_BALL)
@JvmField
val DUSK_BALL = pokeBallItem("dusk_ball")
val HEAL_BALL = pokeBallItem(PokeBalls.HEAL_BALL)
@JvmField
val HEAL_BALL = pokeBallItem("heal_ball")
val QUICK_BALL = pokeBallItem(PokeBalls.QUICK_BALL)
@JvmField
val QUICK_BALL = pokeBallItem("quick_ball")
val DREAM_BALL = pokeBallItem(PokeBalls.DREAM_BALL)
@JvmField
val DREAM_BALL = pokeBallItem("dream_ball")
val BEAST_BALL = pokeBallItem(PokeBalls.BEAST_BALL)
@JvmField
val BEAST_BALL = pokeBallItem("beast_ball")
val MASTER_BALL = pokeBallItem(PokeBalls.MASTER_BALL)
@JvmField
val MASTER_BALL = pokeBallItem("master_ball")
val CHERISH_BALL = pokeBallItem(PokeBalls.CHERISH_BALL)
@JvmField
val CHERISH_BALL = pokeBallItem("cherish_ball")
val ANCIENT_POKE_BALL = pokeBallItem(PokeBalls.ANCIENT_POKE_BALL)
@JvmField
val ANCIENT_POKE_BALL = pokeBallItem("ancient_poke_ball")
val ANCIENT_CITRINE_BALL = pokeBallItem(PokeBalls.ANCIENT_CITRINE_BALL)
@JvmField
val ANCIENT_CITRINE_BALL = pokeBallItem("ancient_citrine_ball")
val ANCIENT_VERDANT_BALL = pokeBallItem(PokeBalls.ANCIENT_VERDANT_BALL)
@JvmField
val ANCIENT_VERDANT_BALL = pokeBallItem("ancient_verdant_ball")
val ANCIENT_AZURE_BALL = pokeBallItem(PokeBalls.ANCIENT_AZURE_BALL)
@JvmField
val ANCIENT_AZURE_BALL = pokeBallItem("ancient_azure_ball")
val ANCIENT_ROSEATE_BALL = pokeBallItem(PokeBalls.ANCIENT_ROSEATE_BALL)
@JvmField
val ANCIENT_ROSEATE_BALL = pokeBallItem("ancient_roseate_ball")
val ANCIENT_SLATE_BALL = pokeBallItem(PokeBalls.ANCIENT_SLATE_BALL)
@JvmField
val ANCIENT_SLATE_BALL = pokeBallItem("ancient_slate_ball")
val ANCIENT_IVORY_BALL = pokeBallItem(PokeBalls.ANCIENT_IVORY_BALL)
@JvmField
val ANCIENT_IVORY_BALL = pokeBallItem("ancient_ivory_ball")
val ANCIENT_GREAT_BALL = pokeBallItem(PokeBalls.ANCIENT_GREAT_BALL)
@JvmField
val ANCIENT_GREAT_BALL = pokeBallItem("ancient_great_ball")
val ANCIENT_ULTRA_BALL = pokeBallItem(PokeBalls.ANCIENT_ULTRA_BALL)
@JvmField
val ANCIENT_ULTRA_BALL = pokeBallItem("ancient_ultra_ball")
val ANCIENT_FEATHER_BALL = pokeBallItem(PokeBalls.ANCIENT_FEATHER_BALL)
@JvmField
val ANCIENT_FEATHER_BALL = pokeBallItem("ancient_feather_ball")
val ANCIENT_WING_BALL = pokeBallItem(PokeBalls.ANCIENT_WING_BALL)
@JvmField
val ANCIENT_WING_BALL = pokeBallItem("ancient_wing_ball")
val ANCIENT_JET_BALL = pokeBallItem(PokeBalls.ANCIENT_JET_BALL)
@JvmField
val ANCIENT_JET_BALL = pokeBallItem("ancient_jet_ball")
val ANCIENT_HEAVY_BALL = pokeBallItem(PokeBalls.ANCIENT_HEAVY_BALL)
@JvmField
val ANCIENT_HEAVY_BALL = pokeBallItem("ancient_heavy_ball")
val ANCIENT_LEADEN_BALL = pokeBallItem(PokeBalls.ANCIENT_LEADEN_BALL)
@JvmField
val ANCIENT_LEADEN_BALL = pokeBallItem("ancient_leaden_ball")
val ANCIENT_GIGATON_BALL = pokeBallItem(PokeBalls.ANCIENT_GIGATON_BALL)
@JvmField
val ANCIENT_GIGATON_BALL = pokeBallItem("ancient_gigaton_ball")
@JvmField
val ANCIENT_ORIGIN_BALL = pokeBallItem("ancient_origin_ball")
val ANCIENT_ORIGIN_BALL = pokeBallItem(PokeBalls.ANCIENT_ORIGIN_BALL)
val pokedexes = mutableListOf<PokedexItem>()
@JvmField
@@ -1408,102 +1406,102 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
)
val pokeRods = mutableListOf<PokerodItem>()
// @JvmField
// val POKE_ROD = pokerodItem(cobblemonResource("poke_rod"))
// @JvmField
// val CITRINE_ROD = pokerodItem(cobblemonResource("citrine_rod"))
// @JvmField
// val VERDANT_ROD = pokerodItem(cobblemonResource("verdant_rod"))
// @JvmField
// val AZURE_ROD = pokerodItem(cobblemonResource("azure_rod"))
// @JvmField
// val ROSEATE_ROD = pokerodItem(cobblemonResource("roseate_rod"))
// @JvmField
// val SLATE_ROD = pokerodItem(cobblemonResource("slate_rod"))
// @JvmField
// val PREMIER_ROD = pokerodItem(cobblemonResource("premier_rod"))
// @JvmField
// val GREAT_ROD = pokerodItem(cobblemonResource("great_rod"))
// @JvmField
// val ULTRA_ROD = pokerodItem(cobblemonResource("ultra_rod"))
// @JvmField
// val SAFARI_ROD = pokerodItem(cobblemonResource("safari_rod"))
// @JvmField
// val FAST_ROD = pokerodItem(cobblemonResource("fast_rod"))
// @JvmField
// val LEVEL_ROD = pokerodItem(cobblemonResource("level_rod"))
// @JvmField
// val LURE_ROD = pokerodItem(cobblemonResource("lure_rod"))
// @JvmField
// val HEAVY_ROD = pokerodItem(cobblemonResource("heavy_rod"))
// @JvmField
// val LOVE_ROD = pokerodItem(cobblemonResource("love_rod"))
// @JvmField
// val FRIEND_ROD = pokerodItem(cobblemonResource("friend_rod"))
// @JvmField
// val MOON_ROD = pokerodItem(cobblemonResource("moon_rod"))
// @JvmField
// val SPORT_ROD = pokerodItem(cobblemonResource("sport_rod"))
// @JvmField
// val PARK_ROD = pokerodItem(cobblemonResource("park_rod"))
// @JvmField
// val NET_ROD = pokerodItem(cobblemonResource("net_rod"))
// @JvmField
// val DIVE_ROD = pokerodItem(cobblemonResource("dive_rod"))
// @JvmField
// val NEST_ROD = pokerodItem(cobblemonResource("nest_rod"))
// @JvmField
// val REPEAT_ROD = pokerodItem(cobblemonResource("repeat_rod"))
// @JvmField
// val TIMER_ROD = pokerodItem(cobblemonResource("timer_rod"))
// @JvmField
// val LUXURY_ROD = pokerodItem(cobblemonResource("luxury_rod"))
// @JvmField
// val DUSK_ROD = pokerodItem(cobblemonResource("dusk_rod"))
// @JvmField
// val HEAL_ROD = pokerodItem(cobblemonResource("heal_rod"))
// @JvmField
// val QUICK_ROD = pokerodItem(cobblemonResource("quick_rod"))
// @JvmField
// val DREAM_ROD = pokerodItem(cobblemonResource("dream_rod"))
// @JvmField
// val BEAST_ROD = pokerodItem(cobblemonResource("beast_rod"), Rarity.RARE)
// @JvmField
// val MASTER_ROD = pokerodItem(cobblemonResource("master_rod"), Rarity.EPIC)
// @JvmField
// val CHERISH_ROD = pokerodItem(cobblemonResource("cherish_rod"), Rarity.EPIC)
// @JvmField
// val ANCIENT_POKE_ROD = pokerodItem(cobblemonResource("ancient_poke_rod"))
// @JvmField
// val ANCIENT_CITRINE_ROD = pokerodItem(cobblemonResource("ancient_citrine_rod"))
// @JvmField
// val ANCIENT_VERDANT_ROD = pokerodItem(cobblemonResource("ancient_verdant_rod"))
// @JvmField
// val ANCIENT_AZURE_ROD = pokerodItem(cobblemonResource("ancient_azure_rod"))
// @JvmField
// val ANCIENT_ROSEATE_ROD = pokerodItem(cobblemonResource("ancient_roseate_rod"))
// @JvmField
// val ANCIENT_SLATE_ROD = pokerodItem(cobblemonResource("ancient_slate_rod"))
// @JvmField
// val ANCIENT_IVORY_ROD = pokerodItem(cobblemonResource("ancient_ivory_rod"))
// @JvmField
// val ANCIENT_GREAT_ROD = pokerodItem(cobblemonResource("ancient_great_rod"))
// @JvmField
// val ANCIENT_ULTRA_ROD = pokerodItem(cobblemonResource("ancient_ultra_rod"))
// @JvmField
// val ANCIENT_FEATHER_ROD = pokerodItem(cobblemonResource("ancient_feather_rod"))
// @JvmField
// val ANCIENT_WING_ROD = pokerodItem(cobblemonResource("ancient_wing_rod"))
// @JvmField
// val ANCIENT_JET_ROD = pokerodItem(cobblemonResource("ancient_jet_rod"))
// @JvmField
// val ANCIENT_HEAVY_ROD = pokerodItem(cobblemonResource("ancient_heavy_rod"))
// @JvmField
// val ANCIENT_LEADEN_ROD = pokerodItem(cobblemonResource("ancient_leaden_rod"))
// @JvmField
// val ANCIENT_GIGATON_ROD = pokerodItem(cobblemonResource("ancient_gigaton_rod"))
// @JvmField
// val ANCIENT_ORIGIN_ROD = pokerodItem(cobblemonResource("ancient_origin_rod"), Rarity.EPIC)
@JvmField
val POKE_ROD = pokerodItem(cobblemonResource("poke_rod"))
@JvmField
val CITRINE_ROD = pokerodItem(cobblemonResource("citrine_rod"))
@JvmField
val VERDANT_ROD = pokerodItem(cobblemonResource("verdant_rod"))
@JvmField
val AZURE_ROD = pokerodItem(cobblemonResource("azure_rod"))
@JvmField
val ROSEATE_ROD = pokerodItem(cobblemonResource("roseate_rod"))
@JvmField
val SLATE_ROD = pokerodItem(cobblemonResource("slate_rod"))
@JvmField
val PREMIER_ROD = pokerodItem(cobblemonResource("premier_rod"))
@JvmField
val GREAT_ROD = pokerodItem(cobblemonResource("great_rod"))
@JvmField
val ULTRA_ROD = pokerodItem(cobblemonResource("ultra_rod"))
@JvmField
val SAFARI_ROD = pokerodItem(cobblemonResource("safari_rod"))
@JvmField
val FAST_ROD = pokerodItem(cobblemonResource("fast_rod"))
@JvmField
val LEVEL_ROD = pokerodItem(cobblemonResource("level_rod"))
@JvmField
val LURE_ROD = pokerodItem(cobblemonResource("lure_rod"))
@JvmField
val HEAVY_ROD = pokerodItem(cobblemonResource("heavy_rod"))
@JvmField
val LOVE_ROD = pokerodItem(cobblemonResource("love_rod"))
@JvmField
val FRIEND_ROD = pokerodItem(cobblemonResource("friend_rod"))
@JvmField
val MOON_ROD = pokerodItem(cobblemonResource("moon_rod"))
@JvmField
val SPORT_ROD = pokerodItem(cobblemonResource("sport_rod"))
@JvmField
val PARK_ROD = pokerodItem(cobblemonResource("park_rod"))
@JvmField
val NET_ROD = pokerodItem(cobblemonResource("net_rod"))
@JvmField
val DIVE_ROD = pokerodItem(cobblemonResource("dive_rod"))
@JvmField
val NEST_ROD = pokerodItem(cobblemonResource("nest_rod"))
@JvmField
val REPEAT_ROD = pokerodItem(cobblemonResource("repeat_rod"))
@JvmField
val TIMER_ROD = pokerodItem(cobblemonResource("timer_rod"))
@JvmField
val LUXURY_ROD = pokerodItem(cobblemonResource("luxury_rod"))
@JvmField
val DUSK_ROD = pokerodItem(cobblemonResource("dusk_rod"))
@JvmField
val HEAL_ROD = pokerodItem(cobblemonResource("heal_rod"))
@JvmField
val QUICK_ROD = pokerodItem(cobblemonResource("quick_rod"))
@JvmField
val DREAM_ROD = pokerodItem(cobblemonResource("dream_rod"))
@JvmField
val BEAST_ROD = pokerodItem(cobblemonResource("beast_rod"), Rarity.RARE)
@JvmField
val MASTER_ROD = pokerodItem(cobblemonResource("master_rod"), Rarity.EPIC)
@JvmField
val CHERISH_ROD = pokerodItem(cobblemonResource("cherish_rod"), Rarity.EPIC)
@JvmField
val ANCIENT_POKE_ROD = pokerodItem(cobblemonResource("ancient_poke_rod"))
@JvmField
val ANCIENT_CITRINE_ROD = pokerodItem(cobblemonResource("ancient_citrine_rod"))
@JvmField
val ANCIENT_VERDANT_ROD = pokerodItem(cobblemonResource("ancient_verdant_rod"))
@JvmField
val ANCIENT_AZURE_ROD = pokerodItem(cobblemonResource("ancient_azure_rod"))
@JvmField
val ANCIENT_ROSEATE_ROD = pokerodItem(cobblemonResource("ancient_roseate_rod"))
@JvmField
val ANCIENT_SLATE_ROD = pokerodItem(cobblemonResource("ancient_slate_rod"))
@JvmField
val ANCIENT_IVORY_ROD = pokerodItem(cobblemonResource("ancient_ivory_rod"))
@JvmField
val ANCIENT_GREAT_ROD = pokerodItem(cobblemonResource("ancient_great_rod"))
@JvmField
val ANCIENT_ULTRA_ROD = pokerodItem(cobblemonResource("ancient_ultra_rod"))
@JvmField
val ANCIENT_FEATHER_ROD = pokerodItem(cobblemonResource("ancient_feather_rod"))
@JvmField
val ANCIENT_WING_ROD = pokerodItem(cobblemonResource("ancient_wing_rod"))
@JvmField
val ANCIENT_JET_ROD = pokerodItem(cobblemonResource("ancient_jet_rod"))
@JvmField
val ANCIENT_HEAVY_ROD = pokerodItem(cobblemonResource("ancient_heavy_rod"))
@JvmField
val ANCIENT_LEADEN_ROD = pokerodItem(cobblemonResource("ancient_leaden_rod"))
@JvmField
val ANCIENT_GIGATON_ROD = pokerodItem(cobblemonResource("ancient_gigaton_rod"))
@JvmField
val ANCIENT_ORIGIN_ROD = pokerodItem(cobblemonResource("ancient_origin_rod"), Rarity.EPIC)
// Misc
@JvmField
@@ -1586,19 +1584,15 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
private fun noSettingsItem(name: String): CobblemonItem = this.create(name, CobblemonItem(Item.Properties()))
private fun itemWithRarity(name: String, rarity: Rarity): CobblemonItem = this.create(name, CobblemonItem(Item.Properties().rarity(rarity)))
fun berries() = this.berries.toMap()
private fun mulchItem(name: String, mulchVariant: MulchVariant): MulchItem = this.create(name, MulchItem(mulchVariant))
private fun pokeBallItem(name: String): PokeBallItem {
// we attach strange ball by default to let registry load
// actual ball configurations will be attached on datapack loading stage
// see PokeBalls.reload
val ball = PokeBalls.STRANGE_BALL
val item = create(name, PokeBallItem(ball))
ball.stack = item.defaultInstance
pokeBalls.put(cobblemonResource(name), item)
private fun pokeBallItem(pokeBall: PokeBall): PokeBallItem {
val item = create(pokeBall.name.path, PokeBallItem(pokeBall))
pokeBall.item = item
pokeBalls.add(item)
return item
}
@@ -101,7 +101,6 @@ import com.cobblemon.mod.common.net.messages.client.pasture.OpenPasturePacket
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonPasturedPacket
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonUnpasturedPacket
import com.cobblemon.mod.common.net.messages.client.pasture.UpdatePastureConflictFlagPacket
import com.cobblemon.mod.common.net.messages.client.pokeballs.PokeBallsRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.pokedex.ServerConfirmedRegisterPacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.*
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.AddEvolutionPacket
@@ -446,7 +445,6 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(MarkRegistrySyncPacket.ID, MarkRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(RideSettingsSyncPacket.ID, RideSettingsSyncPacket::decode, RideSettingsSyncHandler))
list.add(PacketRegisterInfo(TechnicalMachineRegistrySyncPacket.ID, TechnicalMachineRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(PokeBallsRegistrySyncPacket.ID, PokeBallsRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
// Effects
list.add(PacketRegisterInfo(SpawnSnowstormParticlePacket.ID, SpawnSnowstormParticlePacket::decode, SpawnSnowstormParticleHandler))
@@ -659,4 +657,4 @@ object CobblemonNetwork {
fun sendPacketToPlayer(player: ServerPlayer, packet: NetworkPacket<*>) {
Cobblemon.implementation.networkManager.sendPacketToPlayer(player, packet)
}
}
}
@@ -10,9 +10,14 @@ package com.cobblemon.mod.common.api.drop
import com.cobblemon.mod.common.api.events.CobblemonEvents.LOOT_DROPPED
import com.cobblemon.mod.common.api.events.drops.LootDroppedEvent
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.core.registries.Registries
import kotlin.random.Random
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceKey
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.LivingEntity
@@ -105,7 +110,11 @@ class DropTable {
) {
LOOT_DROPPED.postThen(
event = LootDroppedEvent(this, player, entity, drops),
ifSucceeded = { it.drops.forEach { it.drop(entity, world, pos, player) } }
ifSucceeded = {
val pokemon = (entity as? PokemonEntity)?.pokemon?.species?.resourceIdentifier ?: return@postThen
it.drops.forEach { it.drop(entity, world, pos, player) }
// val lootKey = ResourceKey.create(Registries.LOOT_TABLE, cobblemonResource("pokemon/${pokemon}"))
}
)
}
@@ -0,0 +1,64 @@
package com.cobblemon.mod.common.api.drop
import net.minecraft.core.registries.Registries
import net.minecraft.resources.ResourceKey
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.item.ItemEntity
import net.minecraft.world.level.storage.loot.LootParams
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets
import net.minecraft.world.level.storage.loot.parameters.LootContextParams
import net.minecraft.world.phys.Vec3
/**
* A drop entry that points to a vanilla loot table.
*/
class LootTableDropEntry(
override var percentage: Float,
override var quantity: Int,
override var maxSelectableTimes: Int,
val id: ResourceLocation
) : DropEntry {
override fun drop(
entity: LivingEntity?,
world: ServerLevel,
pos: Vec3,
player: ServerPlayer?
) {
val key = ResourceKey.create(Registries.LOOT_TABLE, id)
val playerEntity = player as? LivingEntity
if (entity == null) return
if (playerEntity != null) {
val params = LootParams.Builder(world)
.withParameter(LootContextParams.ATTACKING_ENTITY, playerEntity)
.withParameter(LootContextParams.DAMAGE_SOURCE, playerEntity.damageSources().genericKill())
.withParameter(LootContextParams.ORIGIN, pos)
.withParameter(LootContextParams.THIS_ENTITY, entity)
.create(LootContextParamSets.ENTITY)
val drops = world.server.reloadableRegistries().getLootTable(key)
.getRandomItems(params)
for (stack in drops) {
if (stack.isEmpty) continue
val itemEntity = ItemEntity(world, pos.x, pos.y, pos.z, stack)
itemEntity.setDefaultPickUpDelay()
world.addFreshEntity(itemEntity)
}
} else {
val params = LootParams.Builder(world)
.create(LootContextParamSets.EMPTY)
val drops = world.server.reloadableRegistries().getLootTable(key)
.getRandomItems(params)
for (stack in drops) {
if (stack.isEmpty) continue
val itemEntity = ItemEntity(world, pos.x, pos.y, pos.z, stack)
itemEntity.setDefaultPickUpDelay()
world.addFreshEntity(itemEntity)
}
}
}
}
@@ -25,7 +25,6 @@ data class PokemonCapturedEvent (
"pokemon" to pokemon.struct,
"player" to player.asMoLangValue(),
"poke_ball" to pokeBallEntity.struct,
"item" to player.level().itemRegistry.wrapAsHolder(pokeBallEntity.pokeBall.item()).asMoLangValue(Registries.ITEM),
"stack" to pokeBallEntity.pokeBall.stack.asMoLangValue(player.level().registryAccess())
"item" to player.level().itemRegistry.wrapAsHolder(pokeBallEntity.pokeBall.item).asMoLangValue(Registries.ITEM)
)
}
}
@@ -37,7 +37,6 @@ import com.cobblemon.mod.common.api.molang.function.NPCMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.PCMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.PartyMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.PlayerMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.PokeBallMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.PokedexMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.PokemonEntityMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.PokemonMoLangFunctions
@@ -57,7 +56,6 @@ import com.cobblemon.mod.common.api.storage.party.PartyStore
import com.cobblemon.mod.common.api.storage.pc.PCStore
import com.cobblemon.mod.common.entity.npc.NPCEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokeball.PokeBall
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.Species
import com.cobblemon.mod.common.util.effectiveName
@@ -264,18 +262,6 @@ object MoLangFunctions {
return value
}
fun PokeBall.asMoLangValue(): ObjectValue<PokeBall> {
val value =
ObjectValue(
obj = this,
stringify = { it.name.toString() }
)
value.addFunctions(PokeBallMoLangFunctions.attach(this))
return value
}
fun Vec3.asMoLangValue(): ObjectValue<Vec3> {
val value =
ObjectValue(
@@ -403,12 +389,6 @@ object MoLangFunctions {
return this
}
fun QueryStruct.addPokeBallFunctions(ball: PokeBall): QueryStruct {
val addedFunctions = PokeBallMoLangFunctions.attach(ball)
addFunctions(addedFunctions)
return this
}
fun <T : QueryStruct> T.addFunctions(functions: Map<String, Function<MoParams, Any>>): T {
this.functions.putAll(functions)
return this
@@ -23,7 +23,6 @@ import com.cobblemon.mod.common.api.scheduling.Schedulable
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.entity.MoLangScriptingEntity
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
import com.cobblemon.mod.common.net.messages.client.animation.PlayPosableAnimationPacket
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
import com.cobblemon.mod.common.util.asArrayValue
@@ -308,15 +307,6 @@ object EntityMoLangFunctions : AbstractMoLangFunctionHolder<Entity>() {
functions["face"] = { params ->
ObjectValue(ReferenceDialogueFaceProvider(entity.id, params.getBooleanOrNull(0) != false))
}
// EmptyPokeBallEntity is a subclass of PosableEntity
// meaning we need to add a condition here to attach our func
// only to instance of EmptyPokeBallEntity
if (entity is EmptyPokeBallEntity) {
functions["capture_state"] = {
StringValue(entity.captureState.toString())
}
}
}
is Schedulable -> {
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common.api.molang.function
import com.bedrockk.molang.runtime.MoParams
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.MoValue
import com.cobblemon.mod.common.api.molang.ObjectValue
import com.cobblemon.mod.common.api.storage.party.PartyStore
import com.cobblemon.mod.common.pokemon.Pokemon
@@ -31,12 +30,6 @@ object PartyMoLangFunctions : AbstractMoLangFunctionHolder<PartyStore>() {
party.set(index, pokemon)
DoubleValue.ONE
}
functions["max_level"] = {
MoValue.of(party.maxOf { it.level })
}
functions["avg_level"] = {
MoValue.of(party.sumOf { it.level }.div(party.occupied()))
}
return functions
}
@@ -32,7 +32,6 @@ import com.cobblemon.mod.common.net.messages.client.sound.UnvalidatedPlaySoundS2
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.activeDialogue
import com.cobblemon.mod.common.util.asBlockPos
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.cobblemon.mod.common.util.asResource
import com.cobblemon.mod.common.util.asUUID
import com.cobblemon.mod.common.util.getBattleState
@@ -48,18 +47,15 @@ import com.cobblemon.mod.common.util.pc
import com.cobblemon.mod.common.util.pokedex
import com.cobblemon.mod.common.util.server
import com.cobblemon.mod.common.util.tmList
import net.minecraft.advancements.critereon.ItemPredicate
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.core.registries.Registries
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.sounds.SoundSource
import net.minecraft.stats.Stats
import net.minecraft.tags.TagKey
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.GameType
import kotlin.jvm.optionals.getOrNull
object PlayerMoLangFunctions : AbstractMoLangFunctionHolder<Player>() {
override fun Player.moLangFunctions(): MutableMap<String, (MoParams) -> Any> {
@@ -436,32 +432,6 @@ object PlayerMoLangFunctions : AbstractMoLangFunctionHolder<Player>() {
functions["has_chosen_starter"] = {
DoubleValue(Cobblemon.playerDataManager.getGenericData(player).starterSelected)
}
functions["has_item"] = hasItem@{ params ->
val check = params.getString(0)
if (check.isNullOrBlank()) return@hasItem DoubleValue.ZERO
when (check.startsWith("#")) {
true -> {
val tag = TagKey.create(
Registries.ITEM,
check.replace("#", "").asIdentifierDefaultingNamespace(),
)
DoubleValue(player.inventory.contains(tag))
}
false -> {
val identifier = check.asIdentifierDefaultingNamespace();
val holder = registryAccess()
.registryOrThrow(Registries.ITEM)
.getHolder(identifier)
.getOrNull() ?: return@hasItem DoubleValue.ZERO
DoubleValue(player.inventory.contains { itemStack -> itemStack.`is`(holder) })
}
}
}
}
}
@@ -1,25 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.molang.function
import com.bedrockk.molang.runtime.MoParams
import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
import com.cobblemon.mod.common.pokeball.PokeBall
import com.cobblemon.mod.common.util.getStringOrNull
object PokeBallMoLangFunctions : AbstractMoLangFunctionHolder<PokeBall>() {
override fun PokeBall.moLangFunctions(): MutableMap<String, (MoParams) -> Any> {
val ball = this
val functions = hashMapOf<String, (MoParams) -> Any>()
return functions
}
}
@@ -47,10 +47,6 @@ object PokemonMoLangFunctions : AbstractMoLangFunctionHolder<Pokemon>() {
functions["max_hp"] = { DoubleValue(pokemon.maxHealth.toDouble()) }
functions["current_hp"] = { DoubleValue(pokemon.currentHealth.toDouble()) }
functions["friendship"] = { DoubleValue(pokemon.friendship.toDouble()) }
functions["set_friendship"] = { params ->
val amount = params.getDouble(0)
pokemon.setFriendship(amount.toInt())
}
functions["max_fullness"] = { DoubleValue(pokemon.getMaxFullness().toDouble()) }
functions["fullness"] = { DoubleValue(pokemon.currentFullness.toDouble()) }
functions["lose_fullness"] = { params ->
@@ -456,7 +452,6 @@ object PokemonMoLangFunctions : AbstractMoLangFunctionHolder<Pokemon>() {
functions["entity"] = { pokemon.entity?.asMoLangValue() ?: DoubleValue.ZERO }
functions["is_alpha"] = { DoubleValue(pokemon.isAlpha) }
functions["size_category"] = { StringValue(pokemon.getSizeCategory().name) }
functions["full_heal"] = { pokemon.heal() }
return functions
}
@@ -8,344 +8,293 @@
package com.cobblemon.mod.common.api.pokeball
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.Priority
import com.cobblemon.mod.common.api.data.ServerJsonDataRegistry
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.pokeball.catching.CaptureEffect
import com.cobblemon.mod.common.api.pokeball.catching.CatchRateModifier
import com.cobblemon.mod.common.api.pokeball.catching.effects.CaptureEffects
import com.cobblemon.mod.common.api.pokeball.catching.effects.FriendshipEarningBoostEffect
import com.cobblemon.mod.common.api.pokeball.catching.modifiers.BaseStatModifier
import com.cobblemon.mod.common.api.pokeball.catching.modifiers.CatchRateModifiers
import com.cobblemon.mod.common.api.pokeball.catching.modifiers.DynamicMultiplierModifier
import com.cobblemon.mod.common.api.pokeball.catching.modifiers.ExpressionModifier
import com.cobblemon.mod.common.api.pokeball.catching.modifiers.*
import com.cobblemon.mod.common.api.pokemon.labels.CobblemonPokemonLabels
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.api.pokemon.status.Statuses
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.item.components.PokeBallComponent
import com.cobblemon.mod.common.net.messages.client.pokeballs.PokeBallsRegistrySyncPacket
import com.cobblemon.mod.common.pokeball.PokeBall
import com.cobblemon.mod.common.util.adapters.*
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.removeIf
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import net.minecraft.advancements.critereon.MinMaxBounds
import net.minecraft.core.HolderLookup
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.server.packs.PackType
import net.minecraft.util.LowerCaseEnumTypeAdapterFactory
import java.awt.Color
import kotlin.math.roundToInt
/**
* The data registry for [PokeBall]s.
* All the pokeball fields are guaranteed to exist
*/
object PokeBalls : ServerJsonDataRegistry<PokeBall> {
// <editor-fold desc="Registry definitions">
override val type = PackType.SERVER_DATA
override val resourcePath = "pokeballs"
override val id = cobblemonResource(resourcePath)
override val observable = SimpleObservable<PokeBalls>()
override val typeToken: TypeToken<PokeBall> = TypeToken.get(PokeBall::class.java)
object PokeBalls : JsonDataRegistry<PokeBall> {
override fun setupParser(registry: HolderLookup.Provider): Gson = GsonBuilder()
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
.registerTypeAdapter(IntRange::class.java, IntRangeAdapter)
.registerTypeAdapter(MinMaxBounds.Doubles::class.java, FloatNumberRangeAdapter)
.registerTypeAdapter(CatchRateModifier::class.java, CobblemonCatchRateModifierAdapter)
.registerTypeAdapter(CaptureEffect::class.java, CobblemonCaptureEffectAdapter)
.registerTypeAdapter(Color::class.java, LiteralHexColorAdapter)
.registerTypeAdapter(PokeBall::class.java, PokeBallAdapter)
.registerTypeAdapterFactory(OptionalTypeAdapterFactory())
.registerTypeAdapterFactory(LowerCaseEnumTypeAdapterFactory())
override val id = cobblemonResource("pokeballs")
override val type = PackType.SERVER_DATA
override val observable = SimpleObservable<PokeBalls>()
// ToDo once datapack pokeball is implemented add required adapters here
override val gson: Gson = GsonBuilder()
.disableHtmlEscaping()
.setPrettyPrinting()
.create()
override val typeToken: TypeToken<PokeBall> = TypeToken.get(PokeBall::class.java)
override val resourcePath = "pokeballs"
private val entries = hashMapOf<ResourceLocation, PokeBall>()
// </editor-fold>
private val defaults = hashMapOf<ResourceLocation, PokeBall>()
// ToDo datapack pokeball type here instead
private val custom = hashMapOf<ResourceLocation, PokeBall>()
// <editor-fold desc="Default balls">
@JvmStatic
@get:JvmName("getPokeBall")
val POKE_BALL
get() = getPokeBall("poke_ball")
get() = this.byName("poke_ball")
@JvmStatic
@get:JvmName("getSlateBall")
val SLATE_BALL
get() = getPokeBall("slate_ball")
get() = this.byName("slate_ball")
@JvmStatic
@get:JvmName("getAzureBall")
val AZURE_BALL
get() = getPokeBall("azure_ball")
get() = this.byName("azure_ball")
@JvmStatic
@get:JvmName("getVerdantBall")
val VERDANT_BALL
get() = getPokeBall("verdant_ball")
get() = this.byName("verdant_ball")
@JvmStatic
@get:JvmName("getRoseateBall")
val ROSEATE_BALL
get() = getPokeBall("roseate_ball")
get() = this.byName("roseate_ball")
@JvmStatic
@get:JvmName("getCitrineBall")
val CITRINE_BALL
get() = getPokeBall("citrine_ball")
get() = this.byName("citrine_ball")
@JvmStatic
@get:JvmName("getGreatBall")
val GREAT_BALL
get() = getPokeBall("great_ball")
get() = this.byName("great_ball")
@JvmStatic
@get:JvmName("getUltraBall")
val ULTRA_BALL
get() = getPokeBall("ultra_ball")
get() = this.byName("ultra_ball")
@JvmStatic
@get:JvmName("getMasterBall")
val MASTER_BALL
get() = getPokeBall("master_ball")
get() = this.byName("master_ball")
@JvmStatic
@get:JvmName("getSafariBall")
val SAFARI_BALL
get() = getPokeBall("safari_ball")
get() = this.byName("safari_ball")
@JvmStatic
@get:JvmName("getFastBall")
val FAST_BALL
get() = getPokeBall("fast_ball")
get() = this.byName("fast_ball")
@JvmStatic
@get:JvmName("getLevelBall")
val LEVEL_BALL
get() = getPokeBall("level_ball")
get() = this.byName("level_ball")
@JvmStatic
@get:JvmName("getLureBall")
val LURE_BALL
get() = getPokeBall("lure_ball")
get() = this.byName("lure_ball")
@JvmStatic
@get:JvmName("getHeavyBall")
val HEAVY_BALL
get() = getPokeBall("heavy_ball")
get() = this.byName("heavy_ball")
@JvmStatic
@get:JvmName("getLoveBall")
val LOVE_BALL
get() = getPokeBall("love_ball")
get() = this.byName("love_ball")
@JvmStatic
@get:JvmName("getFriendBall")
val FRIEND_BALL
get() = getPokeBall("friend_ball")
get() = this.byName("friend_ball")
@JvmStatic
@get:JvmName("getMoonBall")
val MOON_BALL
get() = getPokeBall("moon_ball")
get() = this.byName("moon_ball")
@JvmStatic
@get:JvmName("getSportBall")
val SPORT_BALL
get() = getPokeBall("sport_ball")
get() = this.byName("sport_ball")
@JvmStatic
@get:JvmName("getNetBall")
val NET_BALL
get() = getPokeBall("net_ball")
get() = this.byName("net_ball")
@JvmStatic
@get:JvmName("getDiveBall")
val DIVE_BALL
get() = getPokeBall("dive_ball")
get() = this.byName("dive_ball")
@JvmStatic
@get:JvmName("getNestBall")
val NEST_BALL
get() = getPokeBall("nest_ball")
get() = this.byName("nest_ball")
@JvmStatic
@get:JvmName("getRepeatBall")
val REPEAT_BALL
get() = getPokeBall("repeat_ball")
get() = this.byName("repeat_ball")
@JvmStatic
@get:JvmName("getTimerBall")
val TIMER_BALL
get() = getPokeBall("timer_ball")
get() = this.byName("timer_ball")
@JvmStatic
@get:JvmName("getLuxuryBall")
val LUXURY_BALL
get() = getPokeBall("luxury_ball")
get() = this.byName("luxury_ball")
@JvmStatic
@get:JvmName("getPremierBall")
val PREMIER_BALL
get() = getPokeBall("premier_ball")
get() = this.byName("premier_ball")
@JvmStatic
@get:JvmName("getDuskBall")
val DUSK_BALL
get() = getPokeBall("dusk_ball")
get() = this.byName("dusk_ball")
@JvmStatic
@get:JvmName("getHealBall")
val HEAL_BALL
get() = getPokeBall("heal_ball")
get() = this.byName("heal_ball")
@JvmStatic
@get:JvmName("getQuickBall")
val QUICK_BALL
get() = getPokeBall("quick_ball")
get() = this.byName("quick_ball")
@JvmStatic
@get:JvmName("getCherishBall")
val CHERISH_BALL
get() = getPokeBall("cherish_ball")
get() = this.byName("cherish_ball")
@JvmStatic
@get:JvmName("getParkBall")
val PARK_BALL
get() = getPokeBall("park_ball")
get() = this.byName("park_ball")
@JvmStatic
@get:JvmName("getDreamBall")
val DREAM_BALL
get() = getPokeBall("dream_ball")
get() = this.byName("dream_ball")
@JvmStatic
@get:JvmName("getBeastBall")
val BEAST_BALL
get() = getPokeBall("beast_ball")
get() = this.byName("beast_ball")
@JvmStatic
@get:JvmName("getAncientPokeBall")
val ANCIENT_POKE_BALL
get() = getPokeBall("ancient_poke_ball")
get() = this.byName("ancient_poke_ball")
@JvmStatic
@get:JvmName("getAncientCitrineBall")
val ANCIENT_CITRINE_BALL
get() = getPokeBall("ancient_citrine_ball")
get() = this.byName("ancient_citrine_ball")
@JvmStatic
@get:JvmName("getAncientVerdantBall")
val ANCIENT_VERDANT_BALL
get() = getPokeBall("ancient_verdant_ball")
get() = this.byName("ancient_verdant_ball")
@JvmStatic
@get:JvmName("getAncientAzureBall")
val ANCIENT_AZURE_BALL
get() = getPokeBall("ancient_azure_ball")
get() = this.byName("ancient_azure_ball")
@JvmStatic
@get:JvmName("getAncientRoseateBall")
val ANCIENT_ROSEATE_BALL
get() = getPokeBall("ancient_roseate_ball")
get() = this.byName("ancient_roseate_ball")
@JvmStatic
@get:JvmName("getAncientSlateBall")
val ANCIENT_SLATE_BALL
get() = getPokeBall("ancient_slate_ball")
get() = this.byName("ancient_slate_ball")
@JvmStatic
@get:JvmName("getAncientIvoryBall")
val ANCIENT_IVORY_BALL
get() = getPokeBall("ancient_ivory_ball")
get() = this.byName("ancient_ivory_ball")
@JvmStatic
@get:JvmName("getAncientGreatBall")
val ANCIENT_GREAT_BALL
get() = getPokeBall("ancient_great_ball")
get() = this.byName("ancient_great_ball")
@JvmStatic
@get:JvmName("getAncientUltraBall")
val ANCIENT_ULTRA_BALL
get() = getPokeBall("ancient_ultra_ball")
get() = this.byName("ancient_ultra_ball")
@JvmStatic
@get:JvmName("getAncientHeavyBall")
val ANCIENT_HEAVY_BALL
get() = getPokeBall("ancient_heavy_ball")
get() = this.byName("ancient_heavy_ball")
@JvmStatic
@get:JvmName("getAncientLeadenBall")
val ANCIENT_LEADEN_BALL
get() = getPokeBall("ancient_leaden_ball")
get() = this.byName("ancient_leaden_ball")
@JvmStatic
@get:JvmName("getAncientGigatonBall")
val ANCIENT_GIGATON_BALL
get() = getPokeBall("ancient_gigaton_ball")
get() = this.byName("ancient_gigaton_ball")
@JvmStatic
@get:JvmName("getAncientFeatherBall")
val ANCIENT_FEATHER_BALL
get() = getPokeBall("ancient_feather_ball")
get() = this.byName("ancient_feather_ball")
@JvmStatic
@get:JvmName("getAncientWingBall")
val ANCIENT_WING_BALL
get() = getPokeBall("ancient_wing_ball")
get() = this.byName("ancient_wing_ball")
@JvmStatic
@get:JvmName("getAncientJetBall")
val ANCIENT_JET_BALL
get() = getPokeBall("ancient_jet_ball")
get() = this.byName("ancient_jet_ball")
@JvmStatic
@get:JvmName("getAncientOriginBall")
val ANCIENT_ORIGIN_BALL
get() = getPokeBall("ancient_origin_ball")
@JvmStatic
@get:JvmName("getStrangeBall")
val STRANGE_BALL = create("strange_ball")
// </editor-fold>
get() = this.byName("ancient_origin_ball")
init {
// we need at least one default ball in case of shenanigans
create("strange_ball")
create("heavy_ball", CatchRateModifiers.WEIGHT_BASED)
create("love_ball", CatchRateModifiers.LOVE)
create("friend_ball", effects = listOf("q.pokemon.set_friendship(150.0)".asExpressionLike()))
create("moon_ball", CatchRateModifiers.MOON_PHASES)
create("net_ball", CatchRateModifiers.typeBoosting(3F, ElementalTypes.BUG, ElementalTypes.WATER))
create("dive_ball", CatchRateModifiers.SUBMERGED_IN_WATER, waterDragValue = 0.99F)
create("nest_ball", CatchRateModifiers.NEST)
create("repeat_ball", CatchRateModifiers.REPEAT)
create("timer_ball", CatchRateModifiers.turnBased { turn -> (1F + turn * (1229F / 4096F)).coerceAtMost(4F) })
create("luxury_ball" /*effects = listOf(FriendshipEarningBoostEffect(2F))*/)
create("dusk_ball", CatchRateModifiers.LIGHT_LEVEL)
create("heal_ball", effects = listOf("q.pokemon.heal()".asExpressionLike()))
create("quick_ball", CatchRateModifiers.turnBased { turn -> if (turn == 1) 5F else 1F })
create("park_ball", CatchRateModifiers.PARK)
create("dream_ball", CatchRateModifiers.statusBoosting(4F, Statuses.SLEEP))
create(
"beast_ball",
DynamicMultiplierModifier({ _, pokemon -> if (pokemon.hasLabels(CobblemonPokemonLabels.ULTRA_BEAST)) 5F else 0.1F }) { _, _ -> true })
createDefault("poke_ball")
createDefault("slate_ball")
createDefault("azure_ball")
createDefault("verdant_ball")
createDefault("roseate_ball")
createDefault("citrine_ball")
createDefault("great_ball", MultiplierModifier(1.5F))
createDefault("ultra_ball", MultiplierModifier(2F))
createDefault("master_ball", GuaranteedModifier())
createDefault("safari_ball", CatchRateModifiers.SAFARI)
createDefault("fast_ball", BaseStatModifier(Stats.SPEED, { it >= 100 }, 4F))
createDefault("level_ball", CatchRateModifiers.LEVEL)
createDefault("lure_ball", CatchRateModifiers.LURE)
createDefault("heavy_ball", CatchRateModifiers.WEIGHT_BASED)
createDefault("love_ball", CatchRateModifiers.LOVE)
createDefault("friend_ball", effects = listOf(CaptureEffects.friendshipSetter(150)))
createDefault("moon_ball", CatchRateModifiers.MOON_PHASES)
createDefault("sport_ball", MultiplierModifier(1.5F))
createDefault("net_ball", CatchRateModifiers.typeBoosting(3F, ElementalTypes.BUG, ElementalTypes.WATER))
createDefault("dive_ball", CatchRateModifiers.SUBMERGED_IN_WATER, waterDragValue = 0.99F)
createDefault("nest_ball", CatchRateModifiers.NEST)
createDefault("repeat_ball", CatchRateModifiers.REPEAT)
createDefault("timer_ball", CatchRateModifiers.turnBased { turn -> (1F + turn * (1229F / 4096F)).coerceAtMost(4F) })
createDefault("luxury_ball", effects = listOf(FriendshipEarningBoostEffect(2F)))
createDefault("premier_ball")
createDefault("dusk_ball", CatchRateModifiers.LIGHT_LEVEL)
createDefault("heal_ball", effects = listOf(CaptureEffects.FULL_RESTORE))
createDefault("quick_ball", CatchRateModifiers.turnBased { turn -> if (turn == 1) 5F else 1F })
createDefault("cherish_ball")
createDefault("park_ball", CatchRateModifiers.PARK)
createDefault("dream_ball", CatchRateModifiers.statusBoosting(4F, Statuses.SLEEP))
createDefault("beast_ball", DynamicMultiplierModifier({ _, pokemon -> if (pokemon.hasLabels(CobblemonPokemonLabels.ULTRA_BEAST)) 5F else 0.1F }) { _, _ -> true })
createDefault("ancient_poke_ball", ancient = true)
createDefault("ancient_citrine_ball", ancient = true)
createDefault("ancient_verdant_ball", ancient = true)
createDefault("ancient_azure_ball", ancient = true)
createDefault("ancient_roseate_ball", ancient = true)
createDefault("ancient_slate_ball", ancient = true)
createDefault("ancient_ivory_ball", ancient = true)
createDefault("ancient_great_ball", MultiplierModifier(1.5F), ancient = true)
createDefault("ancient_ultra_ball", MultiplierModifier(2F), ancient = true)
createDefault("ancient_heavy_ball", throwPower = 0.75f, ancient = true)
createDefault("ancient_leaden_ball", MultiplierModifier(1.5F), throwPower = 0.75f, ancient = true)
createDefault("ancient_gigaton_ball", MultiplierModifier(2F), throwPower = 0.75f, ancient = true)
createDefault("ancient_feather_ball", throwPower = 2.5f, ancient = true)
createDefault("ancient_wing_ball", MultiplierModifier(1.5F), throwPower = 2.5f, ancient = true)
createDefault("ancient_jet_ball", MultiplierModifier(2F), throwPower = 2.5f, ancient = true)
createDefault("ancient_origin_ball", GuaranteedModifier(), ancient = true)
// 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 ->
if (!event.earned) {
@@ -361,73 +310,235 @@ object PokeBalls : ServerJsonDataRegistry<PokeBall> {
}
}
override fun reload(
data: Map<ResourceLocation, PokeBall>,
registry: HolderLookup.Provider
) {
this.entries.removeIf { it.key != cobblemonResource("strange_ball") }
data.entries.forEach {
val (key, ball) = it
ball.name = key
when(CobblemonItems.pokeBalls.containsKey(key)) {
true -> {
val item = CobblemonItems.pokeBalls.get(key)!!
item.pokeBall = ball
ball.stack = item.defaultInstance
}
false -> {
ball.stack = PokeBallComponent.createStack(ball)
}
}
this.entries[key] = ball
}
Cobblemon.LOGGER.info("Loaded ${data.size} poke balls.")
override fun reload(data: Map<ResourceLocation, PokeBall>) {
this.custom.clear()
// ToDo once datapack pokeball is implemented load them here, we will want datapacks to be able to override our default pokeballs too, however they will never be able to disable them
}
override fun sync(player: ServerPlayer) {
PokeBallsRegistrySyncPacket(this.entries).sendToPlayer(player)
// ToDo once datapack pokeball is implemented sync them here
}
/**
* Gets a Pokeball from registry name.
* @return the pokeball object if found otherwise strange ball.
* @return the pokeball object if found otherwise null.
*/
@JvmStatic
fun getPokeBall(name: ResourceLocation): PokeBall = this.entries[name] ?: STRANGE_BALL
fun getPokeBall(name : ResourceLocation): PokeBall? = this.custom[name] ?: this.defaults[name]
@JvmStatic
fun getPokeBall(name: String): PokeBall = getPokeBall(cobblemonResource(name))
fun all() = this.defaults.filterKeys { !this.custom.containsKey(it) }.values + this.custom.values
@JvmStatic
fun all() = this.entries.values
fun create(
private fun createDefault(
name: String,
modifier: CatchRateModifier = ExpressionModifier(),
effects: List<ExpressionLike> = emptyList(),
modifier: CatchRateModifier = MultiplierModifier(1F) { _, _ -> true },
effects: List<CaptureEffect> = emptyList(),
waterDragValue: Float = 0.8F,
model2d: ResourceLocation = cobblemonResource(name),
model3d: ResourceLocation = cobblemonResource("item/${name}_model"),
throwPower: Float = 1.25f,
ancient: Boolean = false,
color: Color = Color.RED
): PokeBall = PokeBall(
cobblemonResource(name),
modifier,
effects,
PokeBall.PokeBallProperties(),
waterDragValue,
model2d,
model3d,
throwPower,
ancient,
color
).also {
this.entries[it.name] = it
return it
ancient: Boolean = false
): PokeBall {
val identifier = cobblemonResource(name)
val pokeball = PokeBall(identifier, modifier, effects, waterDragValue, model2d, model3d, throwPower, ancient)
this.defaults[identifier] = pokeball
return pokeball
}
}
private fun byName(name: String): PokeBall {
val identifier = cobblemonResource(name)
return this.custom[identifier] ?: this.defaults[identifier]!!
}
/**
* Backwards compatibility getters
*/
@JvmName("getPOKE_BALL")
@Deprecated("Use PokeBalls.getPokeBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getPOKE_BALL() = POKE_BALL
@JvmName("getSLATE_BALL")
@Deprecated("Use PokeBalls.getSlateBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getSLATE_BALL() = SLATE_BALL
@JvmName("getAZURE_BALL")
@Deprecated("Use PokeBalls.getAzureBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getAZURE_BALL() = AZURE_BALL
@JvmName("getVERDANT_BALL")
@Deprecated("Use PokeBalls.getVerdantBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getVERDANT_BALL() = VERDANT_BALL
@JvmName("getROSEATE_BALL")
@Deprecated("Use PokeBalls.getRoseateBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getROSEATE_BALL() = ROSEATE_BALL
@JvmName("getCITRINE_BALL")
@Deprecated("Use PokeBalls.getCitrineBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getCITRINE_BALL() = CITRINE_BALL
@JvmName("getGREAT_BALL")
@Deprecated("Use PokeBalls.getGreatBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getGREAT_BALL() = GREAT_BALL
@JvmName("getULTRA_BALL")
@Deprecated("Use PokeBalls.getUltraBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getULTRA_BALL() = ULTRA_BALL
@JvmName("getMASTER_BALL")
@Deprecated("Use PokeBalls.getMasterBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getMASTER_BALL() = MASTER_BALL
@JvmName("getSAFARI_BALL")
@Deprecated("Use PokeBalls.getSafariBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getSAFARI_BALL() = SAFARI_BALL
@JvmName("getFAST_BALL")
@Deprecated("Use PokeBalls.getFastBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getFAST_BALL() = FAST_BALL
@JvmName("getLEVEL_BALL")
@Deprecated("Use PokeBalls.getLevelBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getLEVEL_BALL() = LEVEL_BALL
@JvmName("getLURE_BALL")
@Deprecated("Use PokeBalls.getLureBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getLURE_BALL() = LURE_BALL
@JvmName("getHEAVY_BALL")
@Deprecated("Use PokeBalls.getHeavyBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getHEAVY_BALL() = HEAVY_BALL
@JvmName("getLOVE_BALL")
@Deprecated("Use PokeBalls.getLoveBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getLOVE_BALL() = LOVE_BALL
@JvmName("getFRIEND_BALL")
@Deprecated("Use PokeBalls.getFriendBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getFRIEND_BALL() = FRIEND_BALL
@JvmName("getMOON_BALL")
@Deprecated("Use PokeBalls.getMoonBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getMOON_BALL() = MOON_BALL
@JvmName("getSPORT_BALL")
@Deprecated("Use PokeBalls.getSportBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getSPORT_BALL() = SPORT_BALL
@JvmName("getNET_BALL")
@Deprecated("Use PokeBalls.getNetBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getNET_BALL() = NET_BALL
@JvmName("getNEST_BALL")
@Deprecated("Use PokeBalls.getNestBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getNEST_BALL() = NEST_BALL
@JvmName("getREPEAT_BALL")
@Deprecated("Use PokeBalls.getRepeatBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getREPEAT_BALL() = REPEAT_BALL
@JvmName("getTIMER_BALL")
@Deprecated("Use PokeBalls.getTimerBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getTIMER_BALL() = TIMER_BALL
@JvmName("getLUXURY_BALL")
@Deprecated("Use PokeBalls.getLuxuryBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getLUXURY_BALL() = LUXURY_BALL
@JvmName("getPREMIER_BALL")
@Deprecated("Use PokeBalls.getPremierBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getPREMIER_BALL() = PREMIER_BALL
@JvmName("getDUSK_BALL")
@Deprecated("Use PokeBalls.getDuskBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getDUSK_BALL() = DUSK_BALL
@JvmName("getHEAL_BALL")
@Deprecated("Use PokeBalls.getHealBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getHEAL_BALL() = HEAL_BALL
@JvmName("getQUICK_BALL")
@Deprecated("Use PokeBalls.getQuickBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getQUICK_BALL() = QUICK_BALL
@JvmName("getCHERISH_BALL")
@Deprecated("Use PokeBalls.getCherishBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getCHERISH_BALL() = CHERISH_BALL
@JvmName("getPARK_BALL")
@Deprecated("Use PokeBalls.getParkBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getPARK_BALL() = PARK_BALL
@JvmName("getDREAM_BALL")
@Deprecated("Use PokeBalls.getDreamBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getDREAM_BALL() = DREAM_BALL
@JvmName("getBEAST_BALL")
@Deprecated("Use PokeBalls.getBeastBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getBEAST_BALL() = BEAST_BALL
@JvmName("getANCIENT_POKE_BALL")
@Deprecated("Use PokeBalls.getAncientPokeBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_POKE_BALL() = ANCIENT_POKE_BALL
@JvmName("getANCIENT_CITRINE_BALL")
@Deprecated("Use PokeBalls.getAncientCitrineBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_CITRINE_BALL() = ANCIENT_CITRINE_BALL
@JvmName("getANCIENT_VERDANT_BALL")
@Deprecated("Use PokeBalls.getAncientVerdantBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_VERDANT_BALL() = ANCIENT_VERDANT_BALL
@JvmName("getANCIENT_AZURE_BALL")
@Deprecated("Use PokeBalls.getAncientAzureBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_AZURE_BALL() = ANCIENT_AZURE_BALL
@JvmName("getANCIENT_ROSEATE_BALL")
@Deprecated("Use PokeBalls.getAncientRoseateBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_ROSEATE_BALL() = ANCIENT_ROSEATE_BALL
@JvmName("getANCIENT_SLATE_BALL")
@Deprecated("Use PokeBalls.getAncientSlateBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_SLATE_BALL() = ANCIENT_SLATE_BALL
@JvmName("getANCIENT_IVORY_BALL")
@Deprecated("Use PokeBalls.getAncientIvoryBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_IVORY_BALL() = ANCIENT_IVORY_BALL
@JvmName("getANCIENT_GREAT_BALL")
@Deprecated("Use PokeBalls.getAncientGreatBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_GREAT_BALL() = ANCIENT_GREAT_BALL
@JvmName("getANCIENT_ULTRA_BALL")
@Deprecated("Use PokeBalls.getAncientUltraBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_ULTRA_BALL() = ANCIENT_ULTRA_BALL
@JvmName("getANCIENT_HEAVY_BALL")
@Deprecated("Use PokeBalls.getAncientHeavyBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_HEAVY_BALL() = ANCIENT_HEAVY_BALL
@JvmName("getANCIENT_LEADEN_BALL")
@Deprecated("Use PokeBalls.getAncientLeadenBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_LEADEN_BALL() = ANCIENT_LEADEN_BALL
@JvmName("getANCIENT_GIGATON_BALL")
@Deprecated("Use PokeBalls.getAncientGigatonBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_GIGATON_BALL() = ANCIENT_GIGATON_BALL
@JvmName("getANCIENT_FEATHER_BALL")
@Deprecated("Use PokeBalls.getAncientFeatherBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_FEATHER_BALL() = ANCIENT_FEATHER_BALL
@JvmName("getANCIENT_WING_BALL")
@Deprecated("Use PokeBalls.getAncientWingBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_WING_BALL() = ANCIENT_WING_BALL
@JvmName("getANCIENT_JET_BALL")
@Deprecated("Use PokeBalls.getAncientJetBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_JET_BALL() = ANCIENT_JET_BALL
@JvmName("getANCIENT_ORIGIN_BALL")
@Deprecated("Use PokeBalls.getAncientOriginBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_ORIGIN_BALL() = ANCIENT_ORIGIN_BALL
}
@@ -18,10 +18,6 @@ import net.minecraft.world.entity.LivingEntity
*
* @property multiplier The multiplier for friendship gains
*/
data class FriendshipEarningBoostEffect(val multiplier: Float) : CaptureEffect {
companion object {
const val VARIANT = "friendship_boost"
}
class FriendshipEarningBoostEffect(val multiplier: Float) : CaptureEffect {
override fun apply(thrower: LivingEntity, pokemon: Pokemon) {}
}
}
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.api.pokeball.catching.modifiers
import com.cobblemon.mod.common.api.pokeball.catching.CatchRateModifier
import com.cobblemon.mod.common.api.pokemon.stats.Stat
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.util.StringRepresentable
import net.minecraft.world.entity.LivingEntity
/**
@@ -27,13 +26,9 @@ import net.minecraft.world.entity.LivingEntity
*/
class BaseStatModifier(
val stat: Stat,
val value: Int,
val comparator: Comparator,
val multiplier: Float,
val comparator: (value: Int) -> Boolean,
val multiplier: Float
) : CatchRateModifier {
companion object {
const val VARIANT = "bst"
}
init {
if (stat.type != Stat.Type.PERMANENT) {
@@ -49,36 +44,9 @@ class BaseStatModifier(
override fun isValid(thrower: LivingEntity, pokemon: Pokemon): Boolean {
val valStat = pokemon.form.baseStats[this.stat] ?: return false
return when (comparator) {
Comparator.GT -> value > valStat
Comparator.LT -> value < valStat
Comparator.GTE -> value >= valStat
Comparator.LTE -> value <= valStat
Comparator.EQ -> value == valStat
Comparator.NOT -> value != valStat
}
return comparator(valStat)
}
override fun modifyCatchRate(
currentCatchRate: Float,
thrower: LivingEntity,
pokemon: Pokemon,
): Float = this.behavior(thrower, pokemon).mutator(currentCatchRate, this.value(thrower, pokemon))
override fun modifyCatchRate(currentCatchRate: Float, thrower: LivingEntity, pokemon: Pokemon): Float = this.behavior(thrower, pokemon).mutator(currentCatchRate, this.value(thrower, pokemon))
enum class Comparator : StringRepresentable {
@JvmField
GT,
@JvmField
LT,
@JvmField
GTE,
@JvmField
LTE,
@JvmField
EQ,
@JvmField
NOT,
;
override fun getSerializedName(): String = this.name.lowercase()
}
}
@@ -26,6 +26,20 @@ import com.cobblemon.mod.common.pokemon.Gender
* @since May 7th, 2022
*/
object CatchRateModifiers {
/**
* Used by [PokeBalls.LEVEL_BALL].
*/
val LEVEL = BattleModifier { _, playerPokemon, pokemon ->
val highestLevel = playerPokemon.maxOf { bp -> bp.battlePokemon?.originalPokemon?.level ?: 1 }
when {
highestLevel > (pokemon.level * 4) -> 4F
highestLevel > (pokemon.level * 2) -> 3F
highestLevel > pokemon.level -> 2F
else -> 1F
}
}
/**
* Used by [PokeBalls.DIVE_BALL].
* This is the Minecraft interpretation of the generation 3 mechanic.
@@ -90,6 +104,12 @@ object CatchRateModifiers {
}
}
/**
* Used by [PokeBalls.SAFARI_BALL].
* Checks if the target is not battling, if true boost by *1.5
*/
val SAFARI = MultiplierModifier(1.5f) { _, poke -> !poke.entity?.isBattling!! }
/**
* Used by [PokeBalls.PARK_BALL].
* Checks if the entity is in a biome valid for the tag [CobblemonBiomeTags.IS_TEMPERATE].
@@ -1,53 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.pokeball.catching.modifiers
import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.pokeball.catching.CatchRateModifier
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.asExpressionLike
import net.minecraft.world.entity.LivingEntity
class ExpressionModifier(
val query: ExpressionLike = "1.0".asExpressionLike(),
) : CatchRateModifier, MoLangModifier {
companion object {
const val VARIANT = "expression"
val runtime = MoLangRuntime().setup()
}
override fun isGuaranteed(): Boolean = false
override fun value(
thrower: LivingEntity,
pokemon: Pokemon
): Float {
if (query.getString().trim() == "1.0") return 1.0f
return query.resolveFloat(runtime(thrower, pokemon))
}
override fun behavior(
thrower: LivingEntity,
pokemon: Pokemon
): CatchRateModifier.Behavior = CatchRateModifier.Behavior.MULTIPLY
override fun isValid(
thrower: LivingEntity,
pokemon: Pokemon
): Boolean = true
override fun modifyCatchRate(
currentCatchRate: Float,
thrower: LivingEntity,
pokemon: Pokemon
): Float = this.behavior(thrower, pokemon).mutator(currentCatchRate, this.value(thrower, pokemon))
}
@@ -19,13 +19,11 @@ import net.minecraft.world.entity.LivingEntity
* @since August 9th, 2022
*/
class GuaranteedModifier : CatchRateModifier {
companion object {
const val VARIANT = "guaranteed"
}
override fun isGuaranteed() = true
override fun value(thrower: LivingEntity, pokemon: Pokemon): Float = 255F
override fun behavior(thrower: LivingEntity, pokemon: Pokemon): CatchRateModifier.Behavior = CatchRateModifier.Behavior.MULTIPLY
override fun isValid(thrower: LivingEntity, pokemon: Pokemon): Boolean = true
override fun modifyCatchRate(currentCatchRate: Float, thrower: LivingEntity, pokemon: Pokemon): Float = this.behavior(thrower, pokemon).mutator(currentCatchRate, this.value(thrower, pokemon))
}
}
@@ -22,22 +22,20 @@ import net.minecraft.world.entity.LivingEntity
* @property matching Will this multiplier should be applied if the labels match?
* @property labels The literal labels being queried.
*/
data class LabelModifier(val multiplier: Float, val matching: Boolean, val labels: List<String>) : CatchRateModifier {
companion object {
const val VARIANT = "labels"
}
class LabelModifier(
val multiplier: Float,
val matching: Boolean,
vararg val labels: String
) : CatchRateModifier {
override fun isGuaranteed(): Boolean = false
override fun value(thrower: LivingEntity, pokemon: Pokemon): Float = this.multiplier
override fun behavior(thrower: LivingEntity, pokemon: Pokemon): CatchRateModifier.Behavior =
CatchRateModifier.Behavior.MULTIPLY
override fun behavior(thrower: LivingEntity, pokemon: Pokemon): CatchRateModifier.Behavior = CatchRateModifier.Behavior.MULTIPLY
override fun isValid(thrower: LivingEntity, pokemon: Pokemon): Boolean =
if (this.matching) pokemon.hasLabels(*this.labels.toSet().toTypedArray()) else !pokemon.hasLabels(*this.labels.toSet().toTypedArray())
override fun isValid(thrower: LivingEntity, pokemon: Pokemon): Boolean = if (this.matching) pokemon.hasLabels(*this.labels) else !pokemon.hasLabels(*this.labels)
override fun modifyCatchRate(currentCatchRate: Float, thrower: LivingEntity, pokemon: Pokemon): Float =
this.behavior(thrower, pokemon).mutator(currentCatchRate, this.value(thrower, pokemon))
override fun modifyCatchRate(currentCatchRate: Float, thrower: LivingEntity, pokemon: Pokemon): Float = this.behavior(thrower, pokemon).mutator(currentCatchRate, this.value(thrower, pokemon))
}
}
@@ -1,42 +0,0 @@
package com.cobblemon.mod.common.api.pokeball.catching.modifiers
import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asBiomeMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asStruct
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asWorldMoLangValue
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.toBlockPos
import com.cobblemon.mod.common.util.withPlayerValue
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.core.registries.Registries
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.LivingEntity
interface MoLangModifier {
fun runtime(thrower: LivingEntity, pokemon: Pokemon): MoLangRuntime {
val biomeValue = thrower.level().getBiome(thrower.position().toBlockPos()).asBiomeMoLangValue()
val worldValue = thrower
.level()
.registryAccess()
.registryOrThrow(Registries.DIMENSION)
.wrapAsHolder(thrower.level())
.asWorldMoLangValue()
return ExpressionModifier.runtime
.withQueryValue("world", worldValue)
.withQueryValue("biome", biomeValue)
.withQueryValue("pokemon", pokemon.asStruct())
.withQueryValue("thrower", thrower.asMostSpecificMoLangValue())
.let {
if (pokemon.entity?.battle != null) {
return@let it.withQueryValue("battle", pokemon.entity!!.battle!!.asMoLangValue())
}
it
}
}
}
@@ -13,21 +13,19 @@ import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.world.entity.LivingEntity
data class PropertyBasedModifier(val property: PokemonProperties, val multiplier: Float) : CatchRateModifier {
companion object {
const val VARIANT = "property"
}
class PropertyBasedModifier(
val property: PokemonProperties,
val multiplier: Float
) : CatchRateModifier {
override fun isGuaranteed(): Boolean = false
override fun value(thrower: LivingEntity, pokemon: Pokemon): Float = this.multiplier
override fun behavior(thrower: LivingEntity, pokemon: Pokemon): CatchRateModifier.Behavior =
CatchRateModifier.Behavior.MULTIPLY
override fun behavior(thrower: LivingEntity, pokemon: Pokemon): CatchRateModifier.Behavior = CatchRateModifier.Behavior.MULTIPLY
override fun isValid(thrower: LivingEntity, pokemon: Pokemon): Boolean = this.property.matches(pokemon)
override fun modifyCatchRate(currentCatchRate: Float, thrower: LivingEntity, pokemon: Pokemon): Float =
this.behavior(thrower, pokemon).mutator(currentCatchRate, this.value(thrower, pokemon))
override fun modifyCatchRate(currentCatchRate: Float, thrower: LivingEntity, pokemon: Pokemon): Float = this.behavior(thrower, pokemon).mutator(currentCatchRate, this.value(thrower, pokemon))
}
@@ -1,34 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.pokeball.catching.modifiers
import com.cobblemon.mod.common.api.pokeball.catching.CatchRateModifier
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.world.entity.LivingEntity
data class SimpleModifier(val value: Float) : CatchRateModifier {
companion object {
const val VARIANT = "simple"
}
override fun isGuaranteed(): Boolean = false
override fun value(thrower: LivingEntity, pokemon: Pokemon): Float = this.value
override fun behavior(thrower: LivingEntity, pokemon: Pokemon): CatchRateModifier.Behavior =
CatchRateModifier.Behavior.MULTIPLY
override fun isValid(thrower: LivingEntity, pokemon: Pokemon): Boolean = true
override fun modifyCatchRate(
currentCatchRate: Float,
thrower: LivingEntity,
pokemon: Pokemon,
): Float = behavior(thrower, pokemon).mutator(currentCatchRate, value(thrower, pokemon))
}
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.api.pokedex.filter
import com.cobblemon.mod.common.api.drop.ItemDropEntry
import com.cobblemon.mod.common.api.drop.LootTableDropEntry
import com.cobblemon.mod.common.api.moves.MoveTemplate
import com.cobblemon.mod.common.api.pokedex.AbstractPokedexManager
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
@@ -17,14 +18,22 @@ import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.api.tms.TechnicalMachines
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.gui.pokedex.widgets.DropsScrollingWidget.DropWidgetEntry
import com.cobblemon.mod.common.pokemon.abilities.HiddenAbility
import com.cobblemon.mod.common.pokemon.FormData
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.cobblemon.mod.common.util.asTranslated
import com.cobblemon.mod.common.util.itemRegistry
import com.cobblemon.mod.common.util.server
import com.google.gson.JsonArray
import com.google.gson.JsonParser
import net.minecraft.client.Minecraft
import net.minecraft.core.registries.Registries
import net.minecraft.resources.ResourceLocation
import net.minecraft.tags.TagKey
import net.minecraft.world.item.ItemStack
import java.util.Locale
import java.util.Locale.getDefault
/**
* A Pokedex [EntryFilter] that filters out entries that do not contain the current search.
@@ -75,11 +84,59 @@ class SearchFilter(val pokedexManager: AbstractPokedexManager, val searchString:
if (pokedexManager.getHighestKnowledgeFor(entry) == PokedexEntryProgress.UNREGISTERED) return false
val dropsList = mutableListOf<String>()
val formsList = if (species.forms.isEmpty()) mutableListOf(species.standardForm) else species.forms
formsList.forEach {
it.drops.entries.forEach {
if (it is ItemDropEntry) {
val itemStack = Minecraft.getInstance().player?.level()?.itemRegistry?.get(it.item)?.defaultInstance ?: ItemStack.EMPTY
formsList.forEach { formData ->
formData.drops.entries.forEach { dropEntry ->
if (dropEntry is ItemDropEntry) {
val itemStack = Minecraft.getInstance().player?.level()?.itemRegistry?.get(dropEntry.item)?.defaultInstance ?: ItemStack.EMPTY
if (!itemStack.isEmpty) dropsList.add(itemStack.displayName.string.lowercase())
} else if (dropEntry is LootTableDropEntry) {
val server = server() ?: return@forEach
val lootTableResource = ResourceLocation.fromNamespaceAndPath(
dropEntry.id.namespace,
"loot_table/${dropEntry.id.path}.json"
)
val resource = server.resourceManager
.getResource(lootTableResource)
.orElse(null)
?: return@forEach
val json = resource.openAsReader().use { reader ->
JsonParser.parseReader(reader).asJsonObject
}
json.getAsJsonArray("pools")?.forEach { poolElement ->
val pool = poolElement.asJsonObject
val entries = pool.getAsJsonArray("entries") ?: return@forEach
for (entry in entries.map { it.asJsonObject }) {
val items = mutableSetOf<String>()
if (entry["type"].asString == "minecraft:tag") {
val itemRegistry = Minecraft.getInstance()
.level!!
.registryAccess()
.lookupOrThrow(Registries.ITEM)
val tagKey = TagKey.create(Registries.ITEM, ResourceLocation.parse(entry["name"].asString))
val tagItems = itemRegistry.getOrThrow(tagKey)
.stream()
.map { holder ->
holder.unwrapKey().map {
val itemStack = Minecraft.getInstance().player?.level()?.itemRegistry?.get(it.location())?.defaultInstance ?: ItemStack.EMPTY
itemStack.displayName.string.lowercase()
}.orElse(null)
}.toList().filterNotNull()
items.addAll(tagItems)
} else if (entry["type"].asString == "minecraft:item") {
val itemStack = Minecraft.getInstance().player?.level()?.itemRegistry?.get(ResourceLocation.parse(entry["name"].asString))?.defaultInstance ?: ItemStack.EMPTY
items.add(itemStack.displayName.string.lowercase())
}
dropsList.addAll(items.map { it })
}
}
}
}
}
@@ -25,9 +25,7 @@ import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.item.PokeBallItem
import com.cobblemon.mod.common.item.components.PokeBallComponent
import com.cobblemon.mod.common.net.messages.client.animation.PlayPosableAnimationPacket
import com.cobblemon.mod.common.pokeball.PokeBall
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.activestate.ShoulderedState
import com.cobblemon.mod.common.pokemon.evolution.variants.ItemInteractionEvolution
@@ -140,7 +138,7 @@ interface Evolution : EvolutionLike {
val shedPokemon = pokemon.clone(registryAccess = owner.registryAccess())
shedPokemon.removeHeldItem()
innerShedder.apply(shedPokemon)
shedPokemon.caughtBall = pokeballStack?.let { PokeBallComponent.getPokeBall(it) } ?: CobblemonItems.STRANGE_BALL.pokeBall
shedPokemon.caughtBall = ((pokeballStack?.item ?: CobblemonItems.POKE_BALL) as PokeBallItem).pokeBall
pokemon.storeCoordinates.get()?.store?.add(shedPokemon)
CobblemonCriteria.EVOLVE_POKEMON.trigger(owner, EvolvePokemonContext(pokemon.preEvolution!!.species.resourceIdentifier, shedPokemon.species.resourceIdentifier, playerDataManager.getGenericData(owner).advancementData.totalEvolvedCount))
// Consume one of the balls (if the player isn't creative)
@@ -8,9 +8,14 @@
package com.cobblemon.mod.common.api.pokemon.requirement
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.pokemon.evolution.ContextEvolution
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.pokemon.Pokemon
import com.mojang.serialization.Codec
import com.mojang.serialization.DataResult
import com.mojang.serialization.Dynamic
import com.mojang.serialization.JsonOps
import net.minecraft.resources.ResourceLocation
import java.util.WeakHashMap
@@ -40,5 +45,26 @@ fun interface Requirement {
companion object {
val pokedexIconOverrides = WeakHashMap<Requirement, ResourceLocation>()
val pokedexTooltipOverrides = WeakHashMap<Requirement, String>()
val CODEC: Codec<Requirement> = Codec.PASSTHROUGH.comapFlatMap(
{ dynamic ->
try {
val json = dynamic.convert(JsonOps.INSTANCE).value
DataResult.success(
PokemonSpecies.gson.fromJson(json, Requirement::class.java)
)
} catch (e: Exception) {
DataResult.error {
"Failed to decode Requirement: ${e.message}"
}
}
},
{ requirement ->
Dynamic(
JsonOps.INSTANCE,
PokemonSpecies.gson.toJsonTree(requirement, Requirement::class.java)
)
}
)
}
}
@@ -145,7 +145,7 @@ class ReforgedConversion(val base: Path) : CobblemonConverter<CompoundTag> {
// result.nickname = this.find(nbt, "Nickname", NbtCompound::getString)
val ball = this.find(nbt, "CaughtBall", CompoundTag::getString)
result.caughtBall = if(ball != null) PokeBalls.getPokeBall(ResourceLocation.parse(ball)) else PokeBalls.STRANGE_BALL
result.caughtBall = if(ball != null) PokeBalls.getPokeBall(ResourceLocation.parse(ball)) ?: PokeBalls.POKE_BALL else PokeBalls.POKE_BALL
return result
}
@@ -190,4 +190,4 @@ class ReforgedConversion(val base: Path) : CobblemonConverter<CompoundTag> {
CAREFUL,
}
}
}
@@ -22,6 +22,7 @@ import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerLevel
import net.minecraft.util.RandomSource
import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.Level
import net.minecraft.world.level.LevelAccessor
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.Blocks
@@ -140,6 +141,19 @@ class TypeGemCoreBlock(properties: Properties) : Block(properties) {
return clusters
}
override fun onRemove(
state: BlockState,
level: Level,
pos: BlockPos,
newState: BlockState,
movedByPiston: Boolean
) {
getConnectedClusters(level, pos).forEach { // Stop growth of connected gems when core is removed
level.setBlockAndUpdate(it.second, it.first.setValue(GROWTH_TYPE, GrowthType.DECORATION))
}
super.onRemove(state, level, pos, newState, movedByPiston)
}
override fun randomTick(state: BlockState, level: ServerLevel, pos: BlockPos, random: RandomSource) {
// should we tick at all?
if (random.nextFloat() >= Cobblemon.config.typeGemTickChance) {
@@ -16,9 +16,7 @@ import com.cobblemon.mod.common.client.render.pokeball.PokeBallPosableState
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity.CaptureState
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity.CaptureState.NOT
import com.cobblemon.mod.common.util.toRGBA
import net.minecraft.network.syncher.EntityDataAccessor
import org.joml.Vector4f
class EmptyPokeBallClientDelegate : PokeBallPosableState(), EntitySideDelegate<EmptyPokeBallEntity> {
override val stateEmitter: SettableObservable<CaptureState> = SettableObservable(NOT)
@@ -54,8 +52,4 @@ class EmptyPokeBallClientDelegate : PokeBallPosableState(), EntitySideDelegate<E
EmptyPokeBallEntity.ASPECTS -> currentAspects = currentEntity.aspects
}
}
fun getBeamColor(): Vector4f {
return currentEntity.pokeBall.beamColor.rgb.toRGBA()
}
}
}
@@ -748,6 +748,8 @@ class PokedexGUI private constructor(
}
TAB_DROPS -> {
(tabInfoElement as DropsScrollingWidget).dropTable = form.drops
(tabInfoElement as DropsScrollingWidget).form = form
(tabInfoElement as DropsScrollingWidget).aspects = aspects.toSet()
(tabInfoElement as DropsScrollingWidget).setEntries()
}
TAB_MOVES -> {
@@ -10,6 +10,9 @@ package com.cobblemon.mod.common.client.gui.pokedex.widgets
import com.cobblemon.mod.common.api.drop.DropTable
import com.cobblemon.mod.common.api.drop.ItemDropEntry
import com.cobblemon.mod.common.api.drop.LootTableDropEntry
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.ScrollingWidget
@@ -17,17 +20,27 @@ import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.client.render.drawScaledTextJustifiedRight
import com.cobblemon.mod.common.client.render.renderScaledGuiItemIcon
import com.cobblemon.mod.common.pokemon.FormData
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.itemRegistry
import com.cobblemon.mod.common.util.lang
import java.text.DecimalFormat
import com.cobblemon.mod.common.util.server
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import com.google.gson.JsonParser
import net.minecraft.ChatFormatting
import net.minecraft.Util
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.core.registries.Registries
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.MutableComponent
import net.minecraft.resources.ResourceLocation
import net.minecraft.tags.TagKey
import net.minecraft.util.FastColor
import net.minecraft.util.Mth
import net.minecraft.world.item.ItemStack
import java.text.DecimalFormat
class DropsScrollingWidget(val pX: Int, val pY: Int): ScrollingWidget<DropsScrollingWidget.DropWidgetEntry>(
width = PokedexGUIConstants.HALF_OVERLAY_WIDTH - 2,
@@ -38,6 +51,8 @@ class DropsScrollingWidget(val pX: Int, val pY: Int): ScrollingWidget<DropsScrol
) {
var dropTable: DropTable = DropTable()
var aspects: Set<String> = emptySet()
var form: FormData = FormData()
companion object {
val df = DecimalFormat("#.##")
@@ -50,9 +65,157 @@ class DropsScrollingWidget(val pX: Int, val pY: Int): ScrollingWidget<DropsScrol
override fun getX() = pX
override fun getY() = pY
private fun getFormAspects(): Set<String> {
val formAspects = form.species.forms
.flatMapTo(mutableSetOf()) { it.aspects }
.apply { addAll(form.species.standardForm.aspects) }
val selectedFormAspectPrefixes = form.aspects
.mapNotNull { it.substringBeforeLast('-', "").takeIf(String::isNotEmpty) }
.toSet()
return formAspects + aspects.filter { aspect ->
val prefix = aspect.substringBeforeLast('-', "")
prefix.isNotEmpty() && prefix in selectedFormAspectPrefixes
}
}
private fun checkPokemonConditions(condition: JsonObject): Boolean {
val conditionType = condition["condition"].asString
if (conditionType == "cobblemon:requirement") {
val requirementJson = condition["requirement"].asJsonObject
val selectedAspects = (aspects - getFormAspects()) + form.aspects
val requirement = PokemonSpecies.gson.fromJson(requirementJson, Requirement::class.java)
val tempPokemon = Pokemon().apply { species = form.species }
tempPokemon.form = form
tempPokemon.forcedAspects = selectedAspects
tempPokemon.shiny = "shiny" in selectedAspects
tempPokemon.updateAspects()
return requirement.check(tempPokemon)
}
if (conditionType == "minecraft:all_of") {
val terms = condition["terms"]?.asJsonArray ?: return true
return terms.all {
checkPokemonConditions(it.asJsonObject)
}
}
if (conditionType == "minecraft:any_of") {
val terms = condition["terms"]?.asJsonArray ?: return true
return terms.any {
checkPokemonConditions(it.asJsonObject)
}
}
if (conditionType == "minecraft:inverted") {
val term = condition["term"]?.asJsonObject ?: return true
return !checkPokemonConditions(term)
}
return true
}
fun setEntries() {
dropTable.entries.forEach {
if (it is ItemDropEntry) addEntry(DropWidgetEntry(it))
clearEntries()
dropTable.entries.forEach { it ->
if (it is ItemDropEntry) {
addEntry(DropWidgetEntry(it, mutableSetOf(it.item)))
} else if (it is LootTableDropEntry) { // LootTable doesn't expose pools, so we gotta do all this bullshit
val server = server() ?: return
val lootTableResource = ResourceLocation.fromNamespaceAndPath(
it.id.namespace,
"loot_table/${it.id.path}.json"
)
val resource = server.resourceManager
.getResource(lootTableResource)
.orElse(null)
?: return@forEach
val json = resource.openAsReader().use { reader ->
JsonParser.parseReader(reader).asJsonObject
}
json.getAsJsonArray("pools")?.forEach { poolElement ->
val pool = poolElement.asJsonObject
val entries = pool.getAsJsonArray("entries") ?: return@forEach
val validEntries = entries
.map { entryElement -> entryElement.asJsonObject }
.filter { entry ->
val conditions = entry["conditions"]?.asJsonArray ?: JsonArray()
conditions.all { condition ->
val conditionJson = condition.asJsonObject
checkPokemonConditions(conditionJson)
}
}
val totalWeight = validEntries.sumOf { entry ->
entry["weight"]?.asInt ?: 1
}
for (entry in validEntries) {
val dropEntry = ItemDropEntry()
val conditions = entry["conditions"]?.asJsonArray ?: JsonArray()
val functions = entry["functions"]?.asJsonArray ?: JsonArray()
val items = mutableSetOf<ResourceLocation>()
var tag: ResourceLocation? = null
if (validEntries.size > 1 && totalWeight > 0) {
val weight = entry["weight"]?.asInt ?: 1
dropEntry.percentage = weight.toFloat() / totalWeight.toFloat() * 100F
}
conditions.forEach { condition ->
val conditionJson = condition.asJsonObject
val conditionType = conditionJson["condition"].asString
if (conditionType == "minecraft:random_chance") {
val chance = conditionJson["chance"].asFloat * 100F
if (validEntries.size > 1) {
dropEntry.percentage *= chance / 100F
} else {
dropEntry.percentage = chance
}
}
}
functions.forEach { function ->
val functionObj = function.asJsonObject
if (functionObj["function"].asString == "set_count") {
val count = functionObj["count"].asJsonObject
val min = count["min"].asInt
val max = count["max"].asInt
dropEntry.quantityRange = IntRange(min, max)
}
}
if (entry["type"].asString == "minecraft:tag") {
val itemRegistry = Minecraft.getInstance()
.level!!
.registryAccess()
.lookupOrThrow(Registries.ITEM)
val tagKey = TagKey.create(Registries.ITEM, ResourceLocation.parse(entry["name"].asString))
tag = tagKey.location
val tagItems = itemRegistry.getOrThrow(tagKey)
.stream()
.map { holder ->
holder.unwrapKey().map {
it.location()
}.orElse(null)
}.toList().filterNotNull()
items.addAll(tagItems)
} else if (entry["type"].asString == "minecraft:item") {
items.add(ResourceLocation.parse(entry["name"].asString))
}
addEntry(DropWidgetEntry(dropEntry, items, tag))
}
}
}
}
}
@@ -90,7 +253,7 @@ class DropsScrollingWidget(val pX: Int, val pY: Int): ScrollingWidget<DropsScrol
shadow = true
)
if (dropTable.entries.size == 0) {
if (dropTable.entries.isEmpty()) {
drawScaledText(
context = context,
text = lang("ui.pokedex.info.drops_empty"),
@@ -128,7 +291,7 @@ class DropsScrollingWidget(val pX: Int, val pY: Int): ScrollingWidget<DropsScrol
return children()[index] as DropWidgetEntry
}
class DropWidgetEntry(val entry: ItemDropEntry): Slot<DropWidgetEntry>() {
class DropWidgetEntry(val entry: ItemDropEntry, val items: MutableSet<ResourceLocation>, val tag: ResourceLocation? = null): Slot<DropWidgetEntry>() {
override fun render(
context: GuiGraphics,
index: Int,
@@ -141,9 +304,14 @@ class DropsScrollingWidget(val pX: Int, val pY: Int): ScrollingWidget<DropsScrol
hovered: Boolean,
tickDelta: Float
) {
if (items.isEmpty()) return
context.pose().pushPose()
context.pose().translate(0f, 0f, 100f)
val itemStack = Minecraft.getInstance().player?.level()?.itemRegistry?.get(entry.item)?.defaultInstance ?: ItemStack.EMPTY
val index = ((Util.getMillis() / 1000L) % items.size).toInt()
val itemLocation = items.elementAt(index)
val itemStack = Minecraft.getInstance().player?.level()?.itemRegistry?.get(itemLocation)?.defaultInstance ?: ItemStack.EMPTY
renderScaledGuiItemIcon(
itemStack = itemStack,
x = x.toDouble(),
@@ -151,28 +319,32 @@ class DropsScrollingWidget(val pX: Int, val pY: Int): ScrollingWidget<DropsScrol
matrixStack = context.pose(),
scale = PokedexGUIConstants.SCALE.toDouble()
)
context.pose().pushPose()
val min = entry.quantityRange?.min() ?: entry.quantity
val max = entry.quantityRange?.max() ?: entry.quantity
if (min == max) {
entry.quantity = min
entry.quantityRange = null
}
// var itemName: String = Component.translatable(itemStack.hoverName).string
// itemName = if (itemName.length > 24) {
// itemName.substring(0, 24 - 3) + "..."
// } else {
// itemName
// }
val displayName = if (tag == null) {
itemStack.hoverName.copy().withStyle(ChatFormatting.BOLD)
} else {
Component.translatable("tag.item.${tag.namespace}.${tag.path.replace('/', '.')}").withStyle(ChatFormatting.BOLD)
}
val displayText: MutableComponent = if (entry.quantityRange != null) {
lang(
"ui.pokedex.info.drops_display",
itemStack.hoverName.copy().withStyle(ChatFormatting.BOLD),
displayName,
lang("ui.pokedex.info.drops_range", min, max)
)
} else {
lang(
"ui.pokedex.info.drops_display",
itemStack.hoverName.copy().withStyle(ChatFormatting.BOLD),
displayName,
lang("ui.pokedex.info.drops_amount", entry.quantity)
)
}
@@ -20,7 +20,7 @@ object BattleCaptureStartHandler : ClientNetworkPacketHandler<BattleCaptureStart
val battle = CobblemonClient.battle ?: return
val targetPokemon = battle.getPokemonFromPNX(packet.targetPNX)
val tile = targetPokemon.second
val pokeBall = PokeBalls.getPokeBall(packet.pokeBallType)
val pokeBall = PokeBalls.getPokeBall(packet.pokeBallType) ?: PokeBalls.POKE_BALL
tile.ballCapturing = ClientBallDisplay(pokeBall, packet.aspects).also { it.start() }
}
}
}
@@ -133,11 +133,11 @@ class PokeBobberEntityRenderer(context: EntityRendererProvider.Context?) : Entit
val pokeBobberBaitItemStack = fishingBobberEntity.entityData.get(PokeRodFishingBobberEntity.POKEBOBBER_BAIT)
val pokeRodId = ResourceLocation.tryParse(pokeRodIdStr)
val pokeRod = PokeRods.getPokeRod(pokeRodId!!)
val ballItem = PokeBalls.getPokeBall(pokeRod?.pokeBallId!!)!!.stack
val ballItem = PokeBalls.getPokeBall(pokeRod?.pokeBallId!!)!!.item
// render the pokebobber
Minecraft.getInstance().itemRenderer.renderStatic(
ballItem,
ballItem.defaultInstance,
ItemDisplayContext.GROUND,
light,
OverlayTexture.NO_OVERLAY,
@@ -25,55 +25,55 @@ object CobblemonModelPredicateRegistry {
fun registerPredicates() {
val rods = listOf<PokerodItem>(
// CobblemonItems.AZURE_ROD,
// CobblemonItems.BEAST_ROD,
// CobblemonItems.CHERISH_ROD,
// CobblemonItems.CITRINE_ROD,
// CobblemonItems.DIVE_ROD,
// CobblemonItems.DREAM_ROD,
// CobblemonItems.DUSK_ROD,
// CobblemonItems.FAST_ROD,
// CobblemonItems.FRIEND_ROD,
// CobblemonItems.GREAT_ROD,
// CobblemonItems.HEAL_ROD,
// CobblemonItems.HEAVY_ROD,
// CobblemonItems.LEVEL_ROD,
// CobblemonItems.LOVE_ROD,
// CobblemonItems.LURE_ROD,
// CobblemonItems.LUXURY_ROD,
// CobblemonItems.MASTER_ROD,
// CobblemonItems.MOON_ROD,
// CobblemonItems.NEST_ROD,
// CobblemonItems.NET_ROD,
// CobblemonItems.PARK_ROD,
// CobblemonItems.POKE_ROD,
// CobblemonItems.PREMIER_ROD,
// CobblemonItems.QUICK_ROD,
// CobblemonItems.REPEAT_ROD,
// CobblemonItems.ROSEATE_ROD,
// CobblemonItems.SAFARI_ROD,
// CobblemonItems.SLATE_ROD,
// CobblemonItems.SPORT_ROD,
// CobblemonItems.TIMER_ROD,
// CobblemonItems.ULTRA_ROD,
// CobblemonItems.VERDANT_ROD,
// CobblemonItems.ANCIENT_AZURE_ROD,
// CobblemonItems.ANCIENT_CITRINE_ROD,
// CobblemonItems.ANCIENT_FEATHER_ROD,
// CobblemonItems.ANCIENT_GIGATON_ROD,
// CobblemonItems.ANCIENT_GREAT_ROD,
// CobblemonItems.ANCIENT_HEAVY_ROD,
// CobblemonItems.ANCIENT_IVORY_ROD,
// CobblemonItems.ANCIENT_JET_ROD,
// CobblemonItems.ANCIENT_LEADEN_ROD,
// CobblemonItems.ANCIENT_ORIGIN_ROD,
// CobblemonItems.ANCIENT_POKE_ROD,
// CobblemonItems.ANCIENT_ROSEATE_ROD,
// CobblemonItems.ANCIENT_SLATE_ROD,
// CobblemonItems.ANCIENT_ULTRA_ROD,
// CobblemonItems.ANCIENT_VERDANT_ROD,
// CobblemonItems.ANCIENT_WING_ROD
val rods = listOf(
CobblemonItems.AZURE_ROD,
CobblemonItems.BEAST_ROD,
CobblemonItems.CHERISH_ROD,
CobblemonItems.CITRINE_ROD,
CobblemonItems.DIVE_ROD,
CobblemonItems.DREAM_ROD,
CobblemonItems.DUSK_ROD,
CobblemonItems.FAST_ROD,
CobblemonItems.FRIEND_ROD,
CobblemonItems.GREAT_ROD,
CobblemonItems.HEAL_ROD,
CobblemonItems.HEAVY_ROD,
CobblemonItems.LEVEL_ROD,
CobblemonItems.LOVE_ROD,
CobblemonItems.LURE_ROD,
CobblemonItems.LUXURY_ROD,
CobblemonItems.MASTER_ROD,
CobblemonItems.MOON_ROD,
CobblemonItems.NEST_ROD,
CobblemonItems.NET_ROD,
CobblemonItems.PARK_ROD,
CobblemonItems.POKE_ROD,
CobblemonItems.PREMIER_ROD,
CobblemonItems.QUICK_ROD,
CobblemonItems.REPEAT_ROD,
CobblemonItems.ROSEATE_ROD,
CobblemonItems.SAFARI_ROD,
CobblemonItems.SLATE_ROD,
CobblemonItems.SPORT_ROD,
CobblemonItems.TIMER_ROD,
CobblemonItems.ULTRA_ROD,
CobblemonItems.VERDANT_ROD,
CobblemonItems.ANCIENT_AZURE_ROD,
CobblemonItems.ANCIENT_CITRINE_ROD,
CobblemonItems.ANCIENT_FEATHER_ROD,
CobblemonItems.ANCIENT_GIGATON_ROD,
CobblemonItems.ANCIENT_GREAT_ROD,
CobblemonItems.ANCIENT_HEAVY_ROD,
CobblemonItems.ANCIENT_IVORY_ROD,
CobblemonItems.ANCIENT_JET_ROD,
CobblemonItems.ANCIENT_LEADEN_ROD,
CobblemonItems.ANCIENT_ORIGIN_ROD,
CobblemonItems.ANCIENT_POKE_ROD,
CobblemonItems.ANCIENT_ROSEATE_ROD,
CobblemonItems.ANCIENT_SLATE_ROD,
CobblemonItems.ANCIENT_ULTRA_ROD,
CobblemonItems.ANCIENT_VERDANT_ROD,
CobblemonItems.ANCIENT_WING_ROD
)
rods.forEach { rod ->
@@ -186,4 +186,4 @@ object CobblemonModelPredicateRegistry {
}
*/
}
}
}
@@ -1,25 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokeball
import com.cobblemon.mod.common.client.render.models.blockbench.PosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.frame.ModelFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Bone
import net.minecraft.client.model.geom.ModelPart
open class PokeBallPosableModel(root: Bone) : PosableModel(root), ModelFrame {
@Transient
override val rootPart =
(root as ModelPart)
.children.entries
.first()
.let { root.registerChildWithAllChildren(it.key) }
val rootBone: String = (root as ModelPart).children.entries.first().key
}
@@ -13,11 +13,11 @@ import com.cobblemon.mod.common.client.render.models.blockbench.repository.Rende
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
import net.minecraft.world.entity.Entity
class PosablePokeBallEntityModel : PosableEntityModel<EmptyPokeBallEntity>() {
class PosablePokeBallModel : PosableEntityModel<EmptyPokeBallEntity>() {
override fun setupEntityTypeContext(entity: Entity?) {
super.setupEntityTypeContext(entity)
if (entity is EmptyPokeBallEntity) {
context.put(RenderContext.ASPECTS, entity.aspects)
}
}
}
}
@@ -20,7 +20,9 @@ import com.cobblemon.mod.common.client.render.models.blockbench.*
import com.cobblemon.mod.common.client.render.models.blockbench.bedrock.animation.BedrockAnimationRepository
import com.cobblemon.mod.common.client.render.models.blockbench.blockentity.BlockEntityModel
import com.cobblemon.mod.common.client.render.models.blockbench.fossil.FossilModel
import com.cobblemon.mod.common.client.render.models.blockbench.pokeball.PokeBallPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pokeball.AncientPokeBallModel
import com.cobblemon.mod.common.client.render.models.blockbench.pokeball.BeastBallModel
import com.cobblemon.mod.common.client.render.models.blockbench.pokeball.PokeBallModel
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1.*
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen2.*
@@ -86,7 +88,7 @@ object VaryingModelRepository {
"bedrock/fossils/posers" to FossilModel::class.java,
"bedrock/block_entities/posers" to BlockEntityModel::class.java,
"bedrock/npcs/posers" to PosableModel::class.java,
"bedrock/poke_balls/posers" to PokeBallPosableModel::class.java,
"bedrock/poke_balls/posers" to PosableModel::class.java,
"bedrock/generic/posers" to PosableModel::class.java,
)
@@ -114,7 +116,6 @@ object VaryingModelRepository {
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
.registerTypeAdapter(PosableModel::class.java, JsonModelAdapter(::PosableModel))
.registerTypeAdapter(PokemonPosableModel::class.java, JsonModelAdapter(::PokemonPosableModel))
.registerTypeAdapter(PokeBallPosableModel::class.java, JsonModelAdapter(::PokeBallPosableModel))
.registerTypeAdapter(FossilModel::class.java, JsonModelAdapter(::FossilModel))
.registerTypeAdapter(BlockEntityModel::class.java, JsonModelAdapter(::BlockEntityModel))
.registerTypeAdapter(Pose::class.java, PoseAdapter { JsonModelAdapter.model!! })
@@ -154,8 +155,8 @@ object VaryingModelRepository {
return {
var boneName = jsonObject.getAsJsonPrimitive("rootBone")
JsonModelAdapter.modelPart = if (boneName != null && it.children[boneName.asString] != null) it.children[boneName.asString] else it.children[fileName] ?: it.children.entries.filter { LocatorAccess.PREFIX !in it.key }.first().value
gson.fromJson(jsonObject, poserClass).also { model ->
model.poses.forEach { (poseName, pose) -> pose.poseName = poseName }
gson.fromJson(jsonObject, poserClass).also {
it.poses.forEach { (poseName, pose) -> pose.poseName = poseName }
}
}
}
@@ -168,6 +169,55 @@ object VaryingModelRepository {
}
fun registerInBuiltPosers() {
inbuilt("azure_ball", ::PokeBallModel)
inbuilt("beast_ball", ::BeastBallModel)
inbuilt("cherish_ball", ::PokeBallModel)
inbuilt("citrine_ball", ::PokeBallModel)
inbuilt("dive_ball", ::PokeBallModel)
inbuilt("dream_ball", ::PokeBallModel)
inbuilt("dusk_ball", ::PokeBallModel)
inbuilt("fast_ball", ::PokeBallModel)
inbuilt("friend_ball", ::PokeBallModel)
inbuilt("great_ball", ::PokeBallModel)
inbuilt("heal_ball", ::PokeBallModel)
inbuilt("heavy_ball", ::PokeBallModel)
inbuilt("level_ball", ::PokeBallModel)
inbuilt("love_ball", ::PokeBallModel)
inbuilt("lure_ball", ::PokeBallModel)
inbuilt("luxury_ball", ::PokeBallModel)
inbuilt("master_ball", ::PokeBallModel)
inbuilt("moon_ball", ::PokeBallModel)
inbuilt("nest_ball", ::PokeBallModel)
inbuilt("net_ball", ::PokeBallModel)
inbuilt("park_ball", ::PokeBallModel)
inbuilt("poke_ball", ::PokeBallModel)
inbuilt("premier_ball", ::PokeBallModel)
inbuilt("quick_ball", ::PokeBallModel)
inbuilt("repeat_ball", ::PokeBallModel)
inbuilt("roseate_ball", ::PokeBallModel)
inbuilt("safari_ball", ::PokeBallModel)
inbuilt("slate_ball", ::PokeBallModel)
inbuilt("sport_ball", ::PokeBallModel)
inbuilt("strange_ball", ::PokeBallModel)
inbuilt("timer_ball", ::PokeBallModel)
inbuilt("ultra_ball", ::PokeBallModel)
inbuilt("verdant_ball", ::PokeBallModel)
inbuilt("ancient_poke_ball", ::AncientPokeBallModel)
inbuilt("ancient_citrine_ball", ::AncientPokeBallModel)
inbuilt("ancient_verdant_ball", ::AncientPokeBallModel)
inbuilt("ancient_azure_ball", ::AncientPokeBallModel)
inbuilt("ancient_roseate_ball", ::AncientPokeBallModel)
inbuilt("ancient_slate_ball", ::AncientPokeBallModel)
inbuilt("ancient_ivory_ball", ::AncientPokeBallModel)
inbuilt("ancient_great_ball", ::AncientPokeBallModel)
inbuilt("ancient_ultra_ball", ::AncientPokeBallModel)
inbuilt("ancient_feather_ball", ::AncientPokeBallModel)
inbuilt("ancient_wing_ball", ::AncientPokeBallModel)
inbuilt("ancient_jet_ball", ::AncientPokeBallModel)
inbuilt("ancient_heavy_ball", ::AncientPokeBallModel)
inbuilt("ancient_leaden_ball", ::AncientPokeBallModel)
inbuilt("ancient_gigaton_ball", ::AncientPokeBallModel)
inbuilt("squirtle", ::SquirtleModel)
inbuilt("wartortle", ::WartortleModel)
inbuilt("metapod", ::MetapodModel)
@@ -616,4 +666,4 @@ object VaryingModelRepository {
}
}
}
}
}
@@ -12,7 +12,8 @@ import com.cobblemon.mod.common.api.reactive.Observable
import com.cobblemon.mod.common.api.reactive.SettableObservable
import com.cobblemon.mod.common.api.scheduling.Schedulable
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
import com.cobblemon.mod.common.client.render.models.blockbench.pokeball.PokeBallPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pokeball.AncientPokeBallModel
import com.cobblemon.mod.common.client.render.models.blockbench.pokeball.PokeBallModel
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
import kotlin.random.Random
@@ -20,21 +21,18 @@ import kotlin.random.Random
abstract class PokeBallPosableState : PosableState(), Schedulable {
abstract val stateEmitter: SettableObservable<EmptyPokeBallEntity.CaptureState>
abstract val shakeEmitter: Observable<Unit>
protected open val group: String
get() = if (this.currentModel is AncientPokeBallModel) "ancient_poke_ball" else "poke_ball"
protected open var lastKnownState: EmptyPokeBallEntity.CaptureState? = null
open fun initSubscriptions() {
stateEmitter.subscribe { state ->
// if we fail to cast, provide default bone name.
val group = (currentModel as? PokeBallPosableModel)?.rootBone ?: "poke_ball"
when (state) {
EmptyPokeBallEntity.CaptureState.HIT -> {
doLater {
val model = this.currentModel!!
after(seconds = 0.2F) {
if (model is PokeBallPosableModel && stateEmitter.get() == EmptyPokeBallEntity.CaptureState.HIT) {
if (model is PokeBallModel && stateEmitter.get() == EmptyPokeBallEntity.CaptureState.HIT) {
doLater latest@{
model.moveToPose(this, model.poses["open"]!!)
after(seconds = 1.75F) {
@@ -62,7 +60,7 @@ abstract class PokeBallPosableState : PosableState(), Schedulable {
shakeEmitter
.pipe(Observable.emitWhile { stateEmitter.get() == EmptyPokeBallEntity.CaptureState.SHAKE })
.subscribe {
val bob = "bob${Random.nextInt(6) + 1}"
val bob = "bob${Random.Default.nextInt(6) + 1}"
doLater { setActiveAnimations(currentModel!!.bedrockStateful(group, bob)) }
}
}
@@ -81,4 +79,4 @@ abstract class PokeBallPosableState : PosableState(), Schedulable {
this.lastKnownState = state
}
}
}
}
@@ -9,7 +9,7 @@
package com.cobblemon.mod.common.client.render.pokeball
import com.cobblemon.mod.common.client.entity.EmptyPokeBallClientDelegate
import com.cobblemon.mod.common.client.render.models.blockbench.pokeball.PosablePokeBallEntityModel
import com.cobblemon.mod.common.client.render.models.blockbench.pokeball.PosablePokeBallModel
import com.cobblemon.mod.common.client.render.models.blockbench.repository.RenderContext
import com.cobblemon.mod.common.client.render.models.blockbench.repository.VaryingModelRepository
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
@@ -24,7 +24,7 @@ import net.minecraft.client.renderer.texture.OverlayTexture
import net.minecraft.resources.ResourceLocation
class PokeBallRenderer(context: EntityRendererProvider.Context) : EntityRenderer<EmptyPokeBallEntity>(context) {
val model = PosablePokeBallEntityModel()
val model = PosablePokeBallModel()
override fun getTextureLocation(pEntity: EmptyPokeBallEntity): ResourceLocation {
return VaryingModelRepository.getTexture(pEntity.pokeBall.name, pEntity.delegate as EmptyPokeBallClientDelegate)
@@ -58,4 +58,4 @@ class PokeBallRenderer(context: EntityRendererProvider.Context) : EntityRenderer
poseStack.popPose()
super.render(entity, yaw, partialTicks, poseStack, buffer, packedLight)
}
}
}
@@ -13,7 +13,6 @@ import com.cobblemon.mod.common.OrientationControllable
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.battle.ClientBallDisplay
import com.cobblemon.mod.common.client.entity.EmptyPokeBallClientDelegate
import com.cobblemon.mod.common.client.entity.NPCClientDelegate
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate.Companion.BEAM_EXTEND_TIME
@@ -44,7 +43,6 @@ import com.cobblemon.mod.common.util.lang
import com.cobblemon.mod.common.util.math.DoubleRange
import com.cobblemon.mod.common.util.math.geometry.toRadians
import com.cobblemon.mod.common.util.math.remap
import com.cobblemon.mod.common.util.toRGBA
import com.mojang.blaze3d.vertex.PoseStack
import com.mojang.math.Axis
import net.minecraft.ChatFormatting
@@ -322,11 +320,6 @@ class PokemonRenderer(
val pokemonPosition = entity.position().add(0.0, entity.bbHeight / 2.0 * clientDelegate.activeSendoutScale.toDouble(), 0.0)
val recallBallOrigin = (beamTarget as? Player)?.let { RecallArmAnimationTracker.get(it.uuid)?.beamOrigin }
val beamColorVec4f = when(beamTarget) {
is EmptyPokeBallEntity -> (beamTarget.delegate as EmptyPokeBallClientDelegate).getBeamColor()
else -> entity.pokemon.caughtBall.beamColor.rgb.toRGBA()
}
val beamSourcePosition = when {
// cover the recall ball origin presence
recallBallOrigin != null -> recallBallOrigin
@@ -392,10 +385,10 @@ class PokemonRenderer(
partialTicks = partialTicks,
totalLevelTime = entity.level().gameTime,
height = pokemonPosition.distanceTo(beamSourcePosition.add(offset)).toFloat() * ratio,
red = beamColorVec4f.x,
green = beamColorVec4f.y,
blue = beamColorVec4f.z,
alpha = beamColorVec4f.w,
red = recallBeamColour.x,
green = recallBeamColour.y,
blue = recallBeamColour.z,
alpha = recallBeamColour.w,
beamRadius = 0.03F,
glowRadius = 0.07F,
glowAlpha = 0.4F
@@ -30,7 +30,7 @@ object FishingRodTooltipGenerator : TooltipGenerator() {
val baitComponent = stack.get(CobblemonItemComponents.BAIT)
// Add the description of the Poke Ball used in the rod
ball.stack.item.description.let {
ball.item.description.let {
val bobberDescription = Component.translatable(
"cobblemon.pokerod.bobber",
it.copy().gray()
@@ -40,7 +40,7 @@ object FishingRodTooltipGenerator : TooltipGenerator() {
val client = Minecraft.getInstance()
val itemRegistry = client.level?.registryAccess()?.registryOrThrow(Registries.ITEM)
itemRegistry?.let {
itemRegistry?.let { registry ->
baitComponent?.stack?.item?.description
?.let { // maybe this can be simplified to not use the FishingBaits to get the stack and just use PokerodItem to get the stack since we have it already
val baitDescription = "cobblemon.pokerod.bait".asTranslated(it.copy().gray(), PokerodItem.getBaitStackOnRod(stack).count)
@@ -77,4 +77,4 @@ object FishingRodTooltipGenerator : TooltipGenerator() {
return resultLines
}
}
}
@@ -8,7 +8,6 @@
package com.cobblemon.mod.common.entity.pokeball
import com.bedrockk.molang.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.StringValue
@@ -19,9 +18,7 @@ import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.pokeball.PokeBallCaptureCalculatedEvent
import com.cobblemon.mod.common.api.events.pokeball.ThrownPokeballHitEvent
import com.cobblemon.mod.common.api.events.pokemon.PokemonCapturedEvent
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.net.serializers.StringSetDataSerializer
import com.cobblemon.mod.common.api.net.serializers.Vec3DataSerializer
import com.cobblemon.mod.common.api.pokeball.PokeBalls
@@ -52,16 +49,7 @@ import com.cobblemon.mod.common.net.messages.client.spawn.SpawnPokeballPacket
import com.cobblemon.mod.common.pokeball.PokeBall
import com.cobblemon.mod.common.pokemon.ai.PokemonBrain
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
import com.cobblemon.mod.common.util.asArrayValue
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.isServerSide
import com.cobblemon.mod.common.util.lang
import com.cobblemon.mod.common.util.party
import com.cobblemon.mod.common.util.playSoundServer
import com.cobblemon.mod.common.util.sendParticlesServer
import com.cobblemon.mod.common.util.setPositionSafely
import com.cobblemon.mod.common.util.update
import com.cobblemon.mod.common.util.withQueryValue
import com.cobblemon.mod.common.util.*
import com.mojang.blaze3d.vertex.PoseStack
import net.minecraft.client.Minecraft
import net.minecraft.core.particles.ParticleTypes
@@ -77,10 +65,7 @@ import net.minecraft.server.level.ServerPlayer
import net.minecraft.sounds.SoundEvents
import net.minecraft.util.Mth
import net.minecraft.util.Mth.PI
import net.minecraft.world.entity.EntityDimensions
import net.minecraft.world.entity.EntityType
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.Pose
import net.minecraft.world.entity.*
import net.minecraft.world.entity.decoration.LeashFenceKnotEntity
import net.minecraft.world.entity.projectile.ThrowableItemProjectile
import net.minecraft.world.item.Item
@@ -112,9 +97,7 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
const val SECONDS_BETWEEN_SHAKES = 1.25F
const val SECONDS_BEFORE_SHAKE = 1F
val DIMENSIONS: EntityDimensions = EntityDimensions.fixed(0.4F, 0.4F)
val runtime = MoLangRuntime().setup()
val DIMENSIONS = EntityDimensions.fixed(0.4F, 0.4F)
}
val dataTrackerEmitter = SimpleObservable<EntityDataAccessor<*>>()
@@ -142,7 +125,7 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
.addFunction("thrower") { owner?.asMostSpecificMoLangValue() ?: DoubleValue.ZERO }
override fun defineSynchedData(builder: SynchedEntityData.Builder) {
pokeBall = PokeBalls.STRANGE_BALL
pokeBall = PokeBalls.POKE_BALL
super.defineSynchedData(builder)
builder.define(CAPTURE_STATE, CaptureState.NOT.ordinal.toByte())
builder.define(ASPECTS, emptySet())
@@ -175,7 +158,7 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
addPosableFunctions(struct)
}
constructor(world: Level) : this(pokeBall = PokeBalls.STRANGE_BALL, world = world)
constructor(world: Level) : this(pokeBall = PokeBalls.POKE_BALL, world = world)
constructor(
pokeBall: PokeBall,
world: Level,
@@ -193,7 +176,7 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
this.pokeBall = pokeBall
}
var pokeBall: PokeBall = PokeBalls.STRANGE_BALL
var pokeBall: PokeBall = PokeBalls.POKE_BALL
override fun onHitBlock(hitResult: BlockHitResult) {
if (captureState == CaptureState.NOT) {
@@ -204,7 +187,7 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
discard()
val player = this.owner as? ServerPlayer
if (player?.isCreative == false) {
spawnAtLocation(pokeBall.stack())
spawnAtLocation(defaultItem)
}
}
} else {
@@ -262,7 +245,7 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
lang(
"capture.attempted_capture",
throwerActor.getName(),
pokeBall.item().getDescriptionId(pokeBall.stack),
pokeBall.item().description,
pokemonEntity.exposedSpecies.translatedName
).yellow()
)
@@ -301,7 +284,7 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
val owner = owner
discard()
val player = owner?.takeIf { it is ServerPlayer } as? ServerPlayer
if (player?.isCreative != true) spawnAtLocation(pokeBall.stack())
if (player?.isCreative != true) spawnAtLocation(defaultItem)
return
}
@@ -313,7 +296,7 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
delegate.tick(this)
if (level().isServerSide()) {
if (this.tickCount > 600 && this.capturingPokemon == null) {
this.remove(RemovalReason.DISCARDED)
@@ -363,8 +346,7 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
// Do a capture
val pokemon = capturingPokemon ?: return
val player = this.owner as? ServerPlayer ?: return
val captureTime = if (pokeBall.ancient) 1.8F else 1F
val captureTime = if (pokeBall.ancient == true) 1.8F else 1F
after(seconds = captureTime) {
// Dupes occurred by double-adding Pokémon, this hopefully prevents it triple-condom style
// wtf did I just read above me
@@ -373,13 +355,8 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
discard()
captureFuture.complete(true)
val party = player.party()
val effectsRuntime = runtime
.withQueryValue("pokeball", struct)
.withQueryValue("pokemon", pokemon.asMoLangValue())
pokemon.pokemon.caughtBall = pokeBall
pokeBall.effects.forEach { effect -> effect.resolve(effectsRuntime) }
pokeBall.effects.forEach { effect -> effect.apply(player, pokemon.pokemon) }
party.add(pokemon.pokemon)
val leashHolder = pokemon.leashHolder
@@ -403,7 +380,7 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
}
// Emits a shake by changing the value to the opposite of what it currently is. Sends an update to the client basically.
// We could replace this with a packet, but it feels awfully excessive when we already have 5 bajillion packets.
if (pokeBall.ancient) {
if (this.pokeBall.ancient) {
when (captureResult.numberOfShakes) {
1 -> ancientBallShake(setOf("q.bedrock_stateful('ancient_poke_ball', 'weirdhop')"))
2 -> ancientBallShake(setOf("q.bedrock_stateful('ancient_poke_ball', 'bighop')"))
@@ -418,7 +395,7 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
private fun breakFree() {
val pokemon = capturingPokemon ?: return
pokemon.setPositionSafely(position())
pokemon.beamMode = 2
pokemon.isInvisible = false
pokemon.isSilent = false
@@ -448,7 +425,8 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
after(seconds = 0.1F) {
captureFuture.complete(false)
val ballType = pokeBall.name.path.lowercase().replace("_", "")
val ballType =
this.pokeBall.name.path.lowercase().replace("_", "")
val mode = "casual"
val sendflash =
BedrockParticleOptionsRepository.getEffect(cobblemonResource("${ballType}/${mode}/sendflash"))
@@ -465,7 +443,7 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
override fun getDefaultItem(): Item = pokeBall.item()
override fun getDimensions(pPose: Pose): EntityDimensions = DIMENSIONS
override fun getDimensions(pPose: Pose) = DIMENSIONS
private fun attemptCatch(pokemonEntity: PokemonEntity) {
pokemonEntity.busyLocks.add(this)
@@ -573,4 +551,4 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
override fun waterDrag(): Float = this.pokeBall.waterDragValue
}
}
@@ -117,6 +117,7 @@ import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.core.component.DataComponents
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.core.registries.Registries
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.NbtOps
import net.minecraft.nbt.NbtUtils
@@ -132,6 +133,7 @@ import net.minecraft.network.protocol.game.DebugPackets
import net.minecraft.network.syncher.EntityDataAccessor
import net.minecraft.network.syncher.EntityDataSerializers
import net.minecraft.network.syncher.SynchedEntityData
import net.minecraft.resources.ResourceKey
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerEntity
import net.minecraft.server.level.ServerLevel
@@ -173,6 +175,7 @@ import net.minecraft.world.level.gameevent.GameEvent
import net.minecraft.world.level.material.EmptyFluid
import net.minecraft.world.level.material.FluidState
import net.minecraft.world.level.pathfinder.PathType
import net.minecraft.world.level.storage.loot.LootTable
import net.minecraft.world.phys.AABB
import net.minecraft.world.phys.Vec3
import java.util.*
@@ -242,6 +245,12 @@ open class PokemonEntity(
override val schedulingTracker = SchedulingTracker()
override fun getDefaultLootTable(): ResourceKey<LootTable?>? {
println(cobblemonResource("pokemon/${this.pokemon.species.resourceIdentifier.path}"))
// return ResourceKey.create(Registries.LOOT_TABLE, )
return super.getDefaultLootTable()
}
val form: FormData
get() = pokemon.form
val behaviour: FormPokemonBehaviour
@@ -8,31 +8,42 @@
package com.cobblemon.mod.common.item
import com.cobblemon.mod.common.api.pokeball.PokeBalls
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
import com.cobblemon.mod.common.item.components.PokeBallComponent
import com.cobblemon.mod.common.pokeball.PokeBall
import com.cobblemon.mod.common.util.isServerSide
import com.cobblemon.mod.common.util.math.geometry.toRadians
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.InteractionHand
import net.minecraft.world.InteractionResultHolder
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Rarity
import net.minecraft.world.level.Level
import kotlin.math.cos
class PokeBallItem(var pokeBall: PokeBall) : CobblemonItem(pokeBall.itemProperties()) {
class PokeBallItem(
val pokeBall: PokeBall
) : CobblemonItem(Properties().apply {
when (pokeBall.name) {
// Master balls are a netherite product and should be fire immune
PokeBalls.MASTER_BALL.name -> fireResistant().rarity(Rarity.EPIC)
PokeBalls.CHERISH_BALL.name -> rarity(Rarity.EPIC)
PokeBalls.ANCIENT_ORIGIN_BALL.name -> rarity(Rarity.EPIC)
PokeBalls.BEAST_BALL.name -> rarity(Rarity.RARE)
}
}) {
override fun use(world: Level, player: Player, usedHand: InteractionHand): InteractionResultHolder<ItemStack> {
val itemStack = player.getItemInHand(usedHand)
if (world.isServerSide()) {
throwPokeBall(world, player as ServerPlayer, PokeBallComponent.getPokeBall(itemStack))
throwPokeBall(world, player as ServerPlayer)
}
itemStack.consume(1, player)
return InteractionResultHolder.sidedSuccess(itemStack, world.isClientSide)
}
private fun throwPokeBall(world: Level, player: ServerPlayer, pokeBall: PokeBall) {
private fun throwPokeBall(world: Level, player: ServerPlayer) {
val pokeBallEntity = EmptyPokeBallEntity(pokeBall, player.level(), player).apply {
val overhandFactor: Float = if (player.xRot < 0) {
5f * cos(player.xRot.toRadians())
@@ -46,7 +57,4 @@ class PokeBallItem(var pokeBall: PokeBall) : CobblemonItem(pokeBall.itemProperti
}
world.addFreshEntity(pokeBallEntity)
}
override fun getDescriptionId(itemStack: ItemStack): String =
PokeBallComponent.getPokeBall(itemStack).name.toLanguageKey("item")
}
}
@@ -1,64 +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.item.components
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonItemComponents
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.pokeball.PokeBalls
import com.cobblemon.mod.common.item.PokeBallItem
import com.cobblemon.mod.common.pokeball.PokeBall
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import io.netty.buffer.ByteBuf
import net.minecraft.network.codec.ByteBufCodecs
import net.minecraft.network.codec.StreamCodec
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.ItemStack
data class PokeBallComponent(val name: ResourceLocation) {
companion object {
val CODEC: Codec<PokeBallComponent> = RecordCodecBuilder.create {
it
.group(ResourceLocation.CODEC.fieldOf("type").forGetter(PokeBallComponent::name))
.apply(it, ::PokeBallComponent)
}
val PACKET_CODEC: StreamCodec<ByteBuf, PokeBallComponent> = ByteBufCodecs.fromCodec(CODEC)
@JvmStatic
fun getPokeBall(stack: ItemStack): PokeBall {
return stack.get(CobblemonItemComponents.POKE_BALL)?.name?.let(PokeBalls::getPokeBall)
?: (stack.item as? PokeBallItem)?.pokeBall
?: PokeBalls.STRANGE_BALL
}
@JvmStatic
fun setPokeBall(stack: ItemStack, ball: PokeBall): ItemStack {
stack.set(CobblemonItemComponents.POKE_BALL, PokeBallComponent(ball.name))
return stack
}
@JvmStatic
fun createStack(ball: PokeBall?): ItemStack {
var result = PokeBalls.STRANGE_BALL
if (ball == null) {
Cobblemon.LOGGER.error("Attempted to create poke ball stack with null config, falling to strange ball.")
} else {
result = ball
}
val stack = ItemStack(CobblemonItems.STRANGE_BALL)
return setPokeBall(stack, result)
}
}
val ball: PokeBall
get() = PokeBalls.getPokeBall(name)
}
@@ -11,12 +11,10 @@ package com.cobblemon.mod.common.item.group
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonItemComponents
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.pokeball.PokeBalls
import com.cobblemon.mod.common.api.riding.stats.RidingStat
import com.cobblemon.mod.common.api.tms.TechnicalMachines
import com.cobblemon.mod.common.block.TypeGemClusterBlock
import com.cobblemon.mod.common.item.AprijuiceItem
import com.cobblemon.mod.common.item.components.PokeBallComponent
import com.cobblemon.mod.common.item.components.RideBoostsComponent
import com.cobblemon.mod.common.item.components.TMMoveComponent
import com.cobblemon.mod.common.util.cobblemonResource
@@ -944,12 +942,7 @@ object CobblemonItemGroups {
}
private fun utilityItemEntries(displayContext: ItemDisplayParameters, entries: Output) {
CobblemonItems.pokeBalls.values.forEach(entries::accept)
PokeBalls.all()
.filter { ball -> CobblemonItems.pokeBalls.keys.none { it == ball.name } }
.forEach { entries.accept(PokeBallComponent.createStack(it)) }
CobblemonItems.pokeBalls.forEach(entries::accept)
CobblemonItems.pokeRods.forEach(entries::accept)
CobblemonItems.pokedexes.forEach(entries::accept)
}
@@ -0,0 +1,28 @@
package com.cobblemon.mod.common.loot
import com.cobblemon.mod.common.loot.conditions.RequirementLootItemCondition
import com.cobblemon.mod.common.platform.PlatformRegistry
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.core.Registry
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.core.registries.Registries
import net.minecraft.resources.ResourceKey
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType
object CobblemonLootItemConditions :
PlatformRegistry<Registry<LootItemConditionType>, ResourceKey<Registry<LootItemConditionType>>, LootItemConditionType>() {
@JvmField
val REQUIREMENT_CONDITION = create(
cobblemonResource("requirement"),
LootItemConditionType(RequirementLootItemCondition.CODEC)
)
fun touch() = Unit
override val registry: Registry<LootItemConditionType>
get() = BuiltInRegistries.LOOT_CONDITION_TYPE
override val resourceKey: ResourceKey<Registry<LootItemConditionType>>
get() = Registries.LOOT_CONDITION_TYPE
}
@@ -0,0 +1,37 @@
package com.cobblemon.mod.common.loot.conditions
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.loot.CobblemonLootItemConditions
import com.mojang.serialization.MapCodec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.world.level.storage.loot.LootContext
import net.minecraft.world.level.storage.loot.parameters.LootContextParams
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType
/**
* Allows for use of a [Requirement] as a [LootItemConditionType]
*/
class RequirementLootItemCondition(
val requirement: Requirement
) : LootItemCondition {
override fun getType(): LootItemConditionType {
return CobblemonLootItemConditions.REQUIREMENT_CONDITION
}
override fun test(t: LootContext): Boolean {
val entity = t.getParamOrNull(LootContextParams.THIS_ENTITY) as? PokemonEntity ?: return false
return requirement.check(entity.pokemon)
}
companion object {
val CODEC: MapCodec<RequirementLootItemCondition> = RecordCodecBuilder.mapCodec { instance ->
instance.group(
Requirement.CODEC.fieldOf("requirement")
.forGetter(RequirementLootItemCondition::requirement)
).apply(instance, ::RequirementLootItemCondition)
}
}
}
@@ -1,70 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.net.messages.client.pokeballs
import com.cobblemon.mod.common.api.pokeball.PokeBalls
import com.cobblemon.mod.common.net.messages.client.data.DataRegistrySyncPacket
import com.cobblemon.mod.common.pokeball.PokeBall
import com.cobblemon.mod.common.util.adapters.CobblemonCatchRateModifierAdapter
import com.cobblemon.mod.common.util.adapters.RegistryAccessResolver
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import java.awt.Color
class PokeBallsRegistrySyncPacket(balls: Map<ResourceLocation, PokeBall>) : DataRegistrySyncPacket<PokeBall, PokeBallsRegistrySyncPacket>(balls.values) {
companion object {
val ID = cobblemonResource("poke_balls")
fun decode(buffer: RegistryFriendlyByteBuf): PokeBallsRegistrySyncPacket {
return PokeBallsRegistrySyncPacket(emptyMap()).apply { decodeBuffer(buffer) }
}
}
override val id = ID
override fun encodeEntry(buffer: RegistryFriendlyByteBuf, entry: PokeBall) {
buffer.writeResourceLocation(entry.name)
buffer.writeResourceLocation(entry.model2d)
buffer.writeResourceLocation(entry.model3d)
buffer.writeFloat(entry.throwPower)
buffer.writeFloat(entry.waterDragValue)
buffer.writeBoolean(entry.ancient)
buffer.writeInt(entry.beamColor.rgb)
CobblemonCatchRateModifierAdapter.encode(entry.catchRateModifier, buffer)
}
override fun decodeEntry(buffer: RegistryFriendlyByteBuf): PokeBall {
val name = buffer.readResourceLocation()
val model2d = buffer.readResourceLocation()
val model3d = buffer.readResourceLocation()
val throwPower = buffer.readFloat()
val waterDrag = buffer.readFloat()
val ancient = buffer.readBoolean()
val color = Color(buffer.readInt())
val catchRateModifier = CobblemonCatchRateModifierAdapter.decode(buffer)
return PokeBall(
name = name,
model2d = model2d,
model3d = model3d,
throwPower = throwPower,
waterDragValue = waterDrag,
ancient = ancient,
beamColor = color,
catchRateModifier = catchRateModifier,
effects = listOf(),
)
}
override fun synchronizeDecoded(entries: Collection<PokeBall>) {
PokeBalls.reload(entries.associateBy { it.name }, RegistryAccessResolver.getAccess())
}
}
@@ -30,8 +30,8 @@ class CaughtBallUpdatePacket(pokemon: () -> Pokemon?, value: PokeBall): SingleUp
val ID = cobblemonResource("caught_ball_update")
fun decode(buffer: RegistryFriendlyByteBuf): CaughtBallUpdatePacket {
val pokemon = decodePokemon(buffer)
val pokeBall = PokeBalls.getPokeBall(buffer.readIdentifier())
val pokeBall = PokeBalls.getPokeBall(buffer.readIdentifier()) ?: PokeBalls.POKE_BALL
return CaughtBallUpdatePacket(pokemon, pokeBall)
}
}
}
}
@@ -9,25 +9,17 @@
package com.cobblemon.mod.common.pokeball
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addPokeBallFunctions
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.molang.ObjectValue
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.api.pokeball.PokeBalls
import com.cobblemon.mod.common.api.pokeball.catching.CaptureEffect
import com.cobblemon.mod.common.api.pokeball.catching.CatchRateModifier
import com.cobblemon.mod.common.item.PokeBallItem
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.adapters.RegistryAccessResolver
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.codec.CodecUtils
import com.google.gson.annotations.SerializedName
import com.mojang.serialization.Codec
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Rarity
import java.awt.Color
import net.minecraft.resources.ResourceLocation
/**
* Base poke ball object
@@ -39,50 +31,37 @@ import java.awt.Color
* @property waterDragValue The value of the water drag modifier when the entity travels, default is 0.8.
* @property model2d The identifier for the resource this Pokéball will use for the 2d model.
* @property model3d The identifier for the resource this Pokéball will use for the 3d model.
* @property ancient Marks this Pokéball as ancient, which makes it play different animations on catch hops
* @property beamColor Defines the beam color of pokeball
*/
class PokeBall @JvmOverloads constructor(
@Transient // Assigns in PokeBalls.reload
var name: ResourceLocation = cobblemonResource("strange_ball"),
@SerializedName("modifier")
open class PokeBall(
val name: ResourceLocation,
val catchRateModifier: CatchRateModifier = CatchRateModifier.DUMMY,
val effects: List<ExpressionLike> = listOf(),
@SerializedName("item_properties")
val itemProperties: PokeBallProperties = PokeBallProperties(),
@SerializedName("water_drag")
val effects: List<CaptureEffect> = listOf(),
val waterDragValue: Float,
@SerializedName("model_2d")
val model2d: ResourceLocation,
@SerializedName("model_3d")
val model3d: ResourceLocation,
@SerializedName("throw_power")
val throwPower: Float,
val ancient: Boolean = false,
@SerializedName("beam_color")
val beamColor: Color = Color.RED,
val ancient: Boolean
) {
@delegate:Transient
val struct: QueryStruct by lazy {
ObjectValue(this)
.addPokeBallFunctions(this)
.addFunction("stack") { this.stack().asMoLangValue(RegistryAccessResolver.getAccess()) }
}
val struct = QueryStruct(hashMapOf())
.addFunction("name") { StringValue(name.toString()) }
.addFunction("water_drag_value") { DoubleValue(waterDragValue) }
.addFunction("throw_power") { DoubleValue(throwPower) }
.addFunction("is_ancient") { DoubleValue(ancient) }
// .addFunction("item") { } // requires a registry which is hard
// This gets attached during item registry
@Transient
internal lateinit var stack: ItemStack
internal lateinit var item: PokeBallItem
fun item(): PokeBallItem = this.stack.item as PokeBallItem
fun item(): PokeBallItem = this.item
fun stack(count: Int = 1): ItemStack =
ItemStack(this.item(), count)
fun itemProperties(): Item.Properties = Item.Properties()
.rarity(this.itemProperties.rarity)
.let { if (itemProperties.fireResistant) it.fireResistant() else it }
@Deprecated("This is a temporary solution for the safari ball dilemma", ReplaceWith("target.currentHealth"))
internal fun hpForCalculation(target: Pokemon): Int = if (this.name == PokeBalls.SAFARI_BALL.name) target.maxHealth else target.currentHealth
companion object {
@JvmStatic
val BY_IDENTIFIER_CODEC: Codec<PokeBall> = CodecUtils.createByIdentifierCodec(
PokeBalls::getPokeBall,
@@ -91,8 +70,4 @@ class PokeBall @JvmOverloads constructor(
}
data class PokeBallProperties(
val fireResistant: Boolean = false,
val rarity: Rarity = Rarity.COMMON
)
}
}
@@ -46,7 +46,7 @@ object Gen1CaptureCalculator : CaptureCalculator {
}
// This value can be reused when calculating the shakes in case of breakout.
val nBound = when (pokeBall) {
PokeBalls.POKE_BALL, PokeBalls.STRANGE_BALL -> 255
PokeBalls.POKE_BALL -> 255
PokeBalls.GREAT_BALL -> 200
else -> 150
}
@@ -97,4 +97,4 @@ object Gen1CaptureCalculator : CaptureCalculator {
}
}
}
}
@@ -642,16 +642,7 @@ open class Pokemon : ShowdownIdentifiable {
scaleModifier = 1F + (roundedPercent / 100F)
}
var caughtBall: PokeBall = PokeBalls.STRANGE_BALL
get() {
return try {
field
} catch (_: Exception) {
// account for possibility of ball removal (datapack disable/removal)
CaughtBallUpdatePacket({ this }, PokeBalls.STRANGE_BALL)
PokeBalls.STRANGE_BALL
}
}
var caughtBall: PokeBall = PokeBalls.POKE_BALL
set(value) {
field = value
onChange(CaughtBallUpdatePacket({ this }, field))
@@ -71,6 +71,7 @@ object CobblemonRequirementAdapter : RequirementAdapter {
this.registerType(OwnerHoldsItemRequirement.ADAPTER_VARIANT, OwnerHoldsItemRequirement::class)
this.registerType(ChanceRequirement.ADAPTER_VARIANT, ChanceRequirement::class)
this.registerType(NegateRequirement.ADAPTER_VARIANT, NegateRequirement::class)
this.registerType(AspectRequirement.ADAPTER_VARIANT, AspectRequirement::class)
}
val gson: Gson by lazy {
@@ -0,0 +1,20 @@
package com.cobblemon.mod.common.pokemon.requirements
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.pokemon.Pokemon
/**
* A [Requirement] that checks if a [Pokemon] has a certain aspect.
*
* @property aspect The aspect to check for.
* @author whatsy
*/
class AspectRequirement(val target: String) : Requirement {
override fun check(pokemon: Pokemon): Boolean {
return target in pokemon.aspects
}
companion object {
val ADAPTER_VARIANT = "aspect"
}
}
@@ -19,8 +19,6 @@ import java.nio.file.SimpleFileVisitor
import java.nio.file.attribute.BasicFileAttributes
import kotlin.io.path.toPath
import net.minecraft.resources.ResourceLocation
import kotlin.io.path.name
import kotlin.text.endsWith
/**
* Basic functions for dealing with assets inside the mod, using the standard file visitor
@@ -31,9 +29,7 @@ import kotlin.text.endsWith
*/
object AssetLoading {
fun ResourceLocation.toPath() = toURL()?.toPath()
fun ResourceLocation.toURL() =
Cobblemon::class.java.getResource(String.format("/assets/%s/%s", namespace, path))?.toURI()
fun ResourceLocation.toURL() = Cobblemon::class.java.getResource(String.format("/assets/%s/%s", namespace, path))?.toURI()
fun fileSearch(dir: Path, filter: (Path) -> Boolean, recursive: Boolean): List<Path> {
val files = mutableListOf<Path>()
Files.walkFileTree(dir, object : SimpleFileVisitor<Path>() {
@@ -62,14 +58,4 @@ object AssetLoading {
}
}
}
/**
* very "clever" way to get all files in asset folder in loaded minecraft client env
*
*/
fun allAtPath(dir: Path, recursive: Boolean = false, suffix: String = ".json", take: Int = 2) = fileSearch(
dir = dir,
recursive = recursive,
filter = { path -> path.name.endsWith(suffix) },
).map { it.toString().removeSuffix(suffix).split("/").takeLast(take).joinToString("/") }
}
}
@@ -1,87 +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.util.adapters
import com.cobblemon.mod.common.api.pokeball.catching.CaptureEffect
import com.cobblemon.mod.common.util.readString
import com.cobblemon.mod.common.util.writeString
import com.google.common.collect.HashBiMap
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import com.google.gson.JsonSerializationContext
import com.google.gson.JsonSerializer
import net.minecraft.network.FriendlyByteBuf
import java.lang.reflect.Type
import kotlin.reflect.KClass
object CobblemonCaptureEffectAdapter : JsonDeserializer<CaptureEffect>, JsonSerializer<CaptureEffect> {
private const val VARIANT = "variant"
private val types = HashBiMap.create<String, KClass<out CaptureEffect>>()
val gson: Gson by lazy {
GsonBuilder()
.registerTypeAdapter(CaptureEffect::class.java, CobblemonCaptureEffectAdapter)
.setPrettyPrinting()
.create()
}
fun <T : CaptureEffect> registerType(id: String, type: KClass<T>) {
this.types[id.lowercase()] = type
}
override fun deserialize(
json: JsonElement,
typeOfT: Type,
context: JsonDeserializationContext,
): CaptureEffect {
val variant =
json.asJsonObject
.get(VARIANT)
.asString
.lowercase()
val type = getModifierType(variant)
return context.deserialize(json, type.java)
}
override fun serialize(
effect: CaptureEffect,
typeOfSrc: Type,
context: JsonSerializationContext,
): JsonElement {
val json = context.serialize(effect, effect::class.java).asJsonObject
val variant = getVariant(effect)
json.addProperty(VARIANT, variant)
return json
}
fun encode(effect: CaptureEffect, buffer: FriendlyByteBuf) {
buffer.writeString(gson.toJson(effect, CaptureEffect::class.java))
}
fun decode(buffer: FriendlyByteBuf): CaptureEffect = gson.fromJson(buffer.readString(), CaptureEffect::class.java)
private fun getVariant(effect: CaptureEffect): String {
val variant =
this.types.inverse()[effect::class]
?: throw IllegalArgumentException("Cannot resolve pokeball capture effect for type ${effect::class.qualifiedName}")
return variant
}
private fun getModifierType(variant: String): KClass<out CaptureEffect> {
val effectType =
this.types[variant] ?: throw IllegalArgumentException("Cannot resolve pokeball capture effect type for variant $variant")
return effectType
}
}
@@ -1,101 +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.util.adapters
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.pokeball.catching.CatchRateModifier
import com.cobblemon.mod.common.api.pokeball.catching.modifiers.*
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.util.readString
import com.cobblemon.mod.common.util.writeString
import com.google.common.collect.HashBiMap
import com.google.gson.*
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import java.lang.reflect.Type
import kotlin.reflect.KClass
object CobblemonCatchRateModifierAdapter : CatchRateModifierAdapter {
private const val VARIANT = "variant"
private val types = HashBiMap.create<String, KClass<out CatchRateModifier>>()
init {
this.registerType(SimpleModifier.VARIANT, SimpleModifier::class)
this.registerType(BaseStatModifier.VARIANT, BaseStatModifier::class)
this.registerType(GuaranteedModifier.VARIANT, GuaranteedModifier::class)
this.registerType(PropertyBasedModifier.VARIANT, PropertyBasedModifier::class)
this.registerType(LabelModifier.VARIANT, LabelModifier::class)
this.registerType(ExpressionModifier.VARIANT, ExpressionModifier::class)
}
val gson: Gson by lazy {
GsonBuilder()
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
.registerTypeAdapter(PokemonProperties::class.java, pokemonPropertiesShortAdapter)
.registerTypeAdapter(CatchRateModifier::class.java, CobblemonCatchRateModifierAdapter)
.setPrettyPrinting()
.create()
}
override fun <T : CatchRateModifier> registerType(id: String, type: KClass<T>) {
this.types[id.lowercase()] = type
}
override fun deserialize(
json: JsonElement,
typeOfT: Type,
context: JsonDeserializationContext,
): CatchRateModifier {
val variant =
json.asJsonObject
.get(VARIANT)
.asString
.lowercase()
val type = getModifierType(variant)
return context.deserialize(json, type.java)
}
override fun serialize(
modifier: CatchRateModifier,
typeOfSrc: Type,
context: JsonSerializationContext,
): JsonElement {
val json = context.serialize(modifier, modifier::class.java).asJsonObject
val variant = getVariant(modifier)
json.addProperty(VARIANT, variant)
return json
}
fun encode(modifier: CatchRateModifier, buffer: FriendlyByteBuf) {
buffer.writeString(gson.toJson(modifier, CatchRateModifier::class.java))
}
fun decode(buffer: FriendlyByteBuf): CatchRateModifier =
gson.fromJson(buffer.readString(), CatchRateModifier::class.java)
private fun getVariant(modifier: CatchRateModifier): String {
val variant =
this.types.inverse()[modifier::class]
?: throw IllegalArgumentException("Cannot resolve pokeball catchrate modifier for type ${modifier::class.qualifiedName}")
return variant
}
private fun getModifierType(variant: String): KClass<out CatchRateModifier> {
val requirementType =
this.types[variant]
?: throw IllegalArgumentException("Cannot resolve pokeball catchrate modifier type for variant $variant")
return requirementType
}
}
@@ -1,64 +0,0 @@
/*
* Copyright (c) 2026. gitoido-mc
* This Source Code Form is subject to the terms of the GNU General Public License v3.0.
* If a copy of the GNU General Public License v3.0 was not distributed with this file,
* you can obtain one at https://github.com/gitoido-mc/conditional-riding/blob/main/LICENSE.
*/
package com.cobblemon.mod.common.util.adapters
import com.google.gson.Gson
import com.google.gson.TypeAdapter
import com.google.gson.TypeAdapterFactory
import com.google.gson.reflect.TypeToken
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter
import java.io.IOException
import java.lang.reflect.ParameterizedType
import java.util.*
class OptionalTypeAdapterFactory : TypeAdapterFactory {
class OptionalTypeAdapter<T>(
private val typeAdapter: TypeAdapter<T>,
) : TypeAdapter<Optional<T>>() {
@Throws(IOException::class)
override fun write(
out: JsonWriter,
value: Optional<T>,
) {
when (value.isPresent) {
true -> typeAdapter.write(out, value.get())
false -> out.nullValue()
}
}
@Throws(IOException::class)
override fun read(`in`: JsonReader): Optional<T> =
when (`in`.peek() != JsonToken.NULL) {
true -> {
Optional.ofNullable(typeAdapter.read(`in`))
}
false -> {
`in`.nextNull()
Optional.empty()
}
} as Optional<T>
}
override fun <T> create(
gson: Gson,
typeToken: TypeToken<T>,
): TypeAdapter<T>? {
if (!Optional::class.java.isAssignableFrom(typeToken.rawType)) return null
val optionalType = typeToken.type
val parametrizedType = optionalType as ParameterizedType
val typeArgs = parametrizedType.actualTypeArguments
val inner = TypeToken.get(typeArgs.first())
val innerAdapter = gson.getAdapter(inner)
return OptionalTypeAdapter(innerAdapter) as TypeAdapter<T>?
}
}
@@ -1,63 +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.util.adapters
import com.cobblemon.mod.common.api.pokeball.catching.CatchRateModifier
import com.cobblemon.mod.common.api.spawning.detail.PossibleHeldItem
import com.cobblemon.mod.common.pokeball.PokeBall
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import com.mojang.serialization.Codec
import com.mojang.serialization.JsonOps
import net.minecraft.client.renderer.item.ItemProperties
import net.minecraft.core.component.DataComponentMap
import net.minecraft.resources.ResourceLocation
import java.awt.Color
import java.lang.reflect.Type
import kotlin.jvm.optionals.getOrNull
/**
* A JSON deserializer for [PokeBall].
*
* @author Gito
* @since October 28th, 2026
*/
object PokeBallAdapter : JsonDeserializer<PokeBall> {
override fun deserialize(json: JsonElement, tp: Type, ctx: JsonDeserializationContext): PokeBall {
json as JsonObject
val beamColor: Color = when(json.has("beam_color")) {
true -> Color.decode(json.get("beam_color").asString)
false -> Color.RED
}
val properties: PokeBall.PokeBallProperties = when(json.has("item_properties")) {
true -> ctx.deserialize(json.get("item_properties"), PokeBall.PokeBallProperties::class.java)
false -> PokeBall.PokeBallProperties()
}
return PokeBall(
catchRateModifier = ctx.deserialize(json.get("modifier"), CatchRateModifier::class.java),
effects = listOf(),
itemProperties = properties,
waterDragValue = tryParse(json.get("water_drag"), Codec.FLOAT),
model2d = tryParse(json.get("model_2d"), ResourceLocation.CODEC),
model3d = tryParse(json.get("model_3d"), ResourceLocation.CODEC),
throwPower = tryParse(json.get("throw_power"), Codec.FLOAT),
ancient = if (json.has("ancient")) json.get("ancient").asBoolean else false,
beamColor = beamColor,
)
}
private fun <T> tryParse(json: JsonElement, codec: Codec<T>): T {
return runCatching { JsonOps.INSTANCE.withDecoder(codec).apply(json).result().getOrNull()!!.first }.getOrThrow()
}
}
@@ -1,33 +0,0 @@
{
"portraitScale": 1,
"portraitTranslation": [0, 0, 0],
"profileScale": 1,
"profileTranslation": [0, 0, 0],
"rootBone": "ancient_ball",
"poses": {
"flying": {
"poseTypes": ["NONE"],
"condition": "q.capture_state() == 'NOT'",
"animations": ["q.bedrock('ancient_ball', 'throw')"],
"transitions": {
"open": "q.bedrock_stateful('ancient_ball', 'open')"
}
},
"open": {
"poseTypes": ["NONE", "PORTRAIT"],
"animations": ["q.bedrock('ancient_ball', 'open_idle')"],
"transitions": {
"shut": "q.bedrock_stateful('ancient_ball', 'shut')"
}
},
"shut": {
"poseTypes": ["NONE", "PORTRAIT"],
"animations": [
"q.bedrock('ancient_ball', 'shut_idle')"
],
"transitions": {
"open": "q.bedrock_stateful('ancient_ball', 'open')"
}
}
}
}
@@ -1,33 +0,0 @@
{
"portraitScale": 1,
"portraitTranslation": [0, 0, 0],
"profileScale": 1,
"profileTranslation": [0, 0, 0],
"rootBone": "poke_ball",
"poses": {
"flying": {
"poseTypes": ["NONE"],
"condition": "q.capture_state() == 'NOT'",
"animations": ["q.bedrock('poke_ball', 'throw')"],
"transitions": {
"open": "q.bedrock_stateful('poke_ball', 'open')"
}
},
"open": {
"poseTypes": ["NONE", "PORTRAIT"],
"animations": ["q.bedrock('poke_ball', 'open_idle')"],
"transitions": {
"shut": "q.bedrock_stateful('poke_ball', 'shut')"
}
},
"shut": {
"poseTypes": ["NONE", "PORTRAIT"],
"animations": [
"q.bedrock('poke_ball', 'shut_idle')"
],
"transitions": {
"open": "q.bedrock_stateful('poke_ball', 'open')"
}
}
}
}
@@ -31,7 +31,6 @@
"item.cobblemon.park_ball": "Park Ball",
"item.cobblemon.dream_ball": "Dream Ball",
"item.cobblemon.beast_ball": "Beast Ball",
"item.cobblemon.strange_ball": "Strange Ball",
"item.cobblemon.ancient_poke_ball": "Ancient Poké Ball",
"item.cobblemon.ancient_citrine_ball": "Ancient Citrine Ball",
"item.cobblemon.ancient_verdant_ball": "Ancient Verdant Ball",
@@ -3672,6 +3671,12 @@
"tag.item.cobblemon.terrain_plants": "Terrain Plants",
"tag.item.cobblemon.tall_flowers": "Tall Flowers",
"tag.item.cobblemon.small_flowers": "Small Flowers",
"tag.item.cobblemon.drops.coral": "Any Coral",
"tag.item.cobblemon.drops.dead_coral": "Any Dead Coral",
"tag.item.cobblemon.drops.dyes": "Any Dye",
"tag.item.cobblemon.drops.ink_sacs": "Any Ink Sac",
"tag.item.cobblemon.drops.flowers": "Any Flower",
"tag.item.cobblemon.drops.apricorn_sprouts": "Any Apricorn Sprout",
"tag.worldgen.biome.cobblemon.evolution.regional.bergmite_hisuibiome": "Hisuian",
"tag.worldgen.biome.cobblemon.evolution.regional.bergmite_kalosbiome": "Kalosian",
@@ -1,6 +1,6 @@
{
"parent": "cobblemon:item/poke_ball/ancient_poke_ball_model",
"parent": "cobblemon:item/ancient_poke_ball_model",
"textures": {
"layer0": "cobblemon:item/poke_balls/models/ancient_azure_ball"
}
}
}
@@ -1,6 +1,6 @@
{
"parent": "cobblemon:item/poke_ball/ancient_poke_ball_model",
"parent": "cobblemon:item/ancient_poke_ball_model",
"textures": {
"layer0": "cobblemon:item/poke_balls/models/ancient_citrine_ball"
}
}
}
@@ -1,6 +1,6 @@
{
"parent": "cobblemon:item/poke_ball/ancient_poke_ball_model",
"parent": "cobblemon:item/ancient_poke_ball_model",
"textures": {
"layer0": "cobblemon:item/poke_balls/models/ancient_feather_ball"
}
}
}
@@ -1,6 +1,6 @@
{
"parent": "cobblemon:item/poke_ball/ancient_poke_ball_model",
"parent": "cobblemon:item/ancient_poke_ball_model",
"textures": {
"layer0": "cobblemon:item/poke_balls/models/ancient_gigaton_ball"
}
}
}
@@ -1,6 +1,6 @@
{
"parent": "cobblemon:item/poke_ball/ancient_poke_ball_model",
"parent": "cobblemon:item/ancient_poke_ball_model",
"textures": {
"layer0": "cobblemon:item/poke_balls/models/ancient_great_ball"
}
}
}
@@ -1,6 +1,6 @@
{
"parent": "cobblemon:item/poke_ball/ancient_poke_ball_model",
"parent": "cobblemon:item/ancient_poke_ball_model",
"textures": {
"layer0": "cobblemon:item/poke_balls/models/ancient_heavy_ball"
}
}
}
@@ -1,6 +1,6 @@
{
"parent": "cobblemon:item/poke_ball/ancient_poke_ball_model",
"parent": "cobblemon:item/ancient_poke_ball_model",
"textures": {
"layer0": "cobblemon:item/poke_balls/models/ancient_ivory_ball"
}
}
}
@@ -1,6 +1,6 @@
{
"parent": "cobblemon:item/poke_ball/ancient_poke_ball_model",
"parent": "cobblemon:item/ancient_poke_ball_model",
"textures": {
"layer0": "cobblemon:item/poke_balls/models/ancient_jet_ball"
}
}
}
@@ -1,6 +1,6 @@
{
"parent": "cobblemon:item/poke_ball/ancient_poke_ball_model",
"parent": "cobblemon:item/ancient_poke_ball_model",
"textures": {
"layer0": "cobblemon:item/poke_balls/models/ancient_leaden_ball"
}
}
}
@@ -1,6 +1,6 @@
{
"parent": "cobblemon:item/poke_ball/ancient_poke_ball_model",
"parent": "cobblemon:item/ancient_poke_ball_model",
"textures": {
"layer0": "cobblemon:item/poke_balls/models/ancient_origin_ball"
}
}
}
@@ -1,6 +1,6 @@
{
"parent": "cobblemon:item/poke_ball/ancient_poke_ball_model",
"parent": "cobblemon:item/ancient_poke_ball_model",
"textures": {
"layer0": "cobblemon:item/poke_balls/models/ancient_roseate_ball"
}
}
}
@@ -1,6 +1,6 @@
{
"parent": "cobblemon:item/poke_ball/ancient_poke_ball_model",
"parent": "cobblemon:item/ancient_poke_ball_model",
"textures": {
"layer0": "cobblemon:item/poke_balls/models/ancient_slate_ball"
}
}
}
@@ -1,6 +1,6 @@
{
"parent": "cobblemon:item/poke_ball/ancient_poke_ball_model",
"parent": "cobblemon:item/ancient_poke_ball_model",
"textures": {
"layer0": "cobblemon:item/poke_balls/models/ancient_ultra_ball"
}
}
}
@@ -1,6 +1,6 @@
{
"parent": "cobblemon:item/poke_ball/ancient_poke_ball_model",
"parent": "cobblemon:item/ancient_poke_ball_model",
"textures": {
"layer0": "cobblemon:item/poke_balls/models/ancient_verdant_ball"
}
}
}
@@ -1,6 +1,6 @@
{
"parent": "cobblemon:item/poke_ball/ancient_poke_ball_model",
"parent": "cobblemon:item/ancient_poke_ball_model",
"textures": {
"layer0": "cobblemon:item/poke_balls/models/ancient_wing_ball"
}
}
}
Loaded 100 of 2372 files, more files were not shown because too many files have changed in this diff. Show more