Compare commits

..
Author SHA1 Message Date
Landon Wills c74f01bd6d Fix sounds on consumable candies 2025-11-28 20:23:33 -05:00
Landon Wills 199a8ba675 Make experience candies consumable, grant player experience when eaten 2025-11-28 20:04:33 -05:00
Landon Wills 556f92e4b0 Make players gain experience from Pokemon methods when wearing an experience share 2025-11-28 20:03:36 -05:00
Landon Wills 4f395ca47f Let pokemon gain exp for killing Minecraft mobs 2025-11-27 12:04:07 -05:00
Polymeta 2a5a292386 fix saccharine hanging signs sometimes dropping oak wood signs
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-11-27 11:27:58 +00:00
Polymeta e8a09f5c48 Merge branch 'json-fixing' into 'main'
JSON Fixes

Closes #1819

See merge request cable-mc/cobblemon!2048
2025-11-27 10:42:07 +00:00
dhi_holo e82193cdfd Update interact_with_pokemon.json
Removed accidental flag
2025-11-27 19:56:33 +10:00
dhi_holo 87e7cdebf6 Fabric Tags that aren't true c tags are the bane of my existence
Fixed the concrete tags to behave properly, changelog
2025-11-27 15:25:53 +10:00
dhi_holo 9ca84d852f Update interact_with_pokemon.json
Should close #1819
2025-11-27 14:22:06 +10:00
Polymeta 635f29e1ac fix glass bottle not being returned when using honey on saccharine leaves
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-11-26 22:08:12 +00:00
Polymeta db2001b60a Merge branch 'attempted-jvm-fix' into 'main'
Fixed JVM crash from campfire pot

Closes #1795

See merge request cable-mc/cobblemon!2040
2025-11-26 21:40:30 +00:00
HirokuandPolymeta b5098a2ad0 Fixed JVM crash from campfire pot 2025-11-26 21:40:29 +00:00
Polymeta 8c939ee276 Merge branch 'lets-wind-down' into 'main'
Fixes wind charges recalling pastured pokémon

Closes #1805

See merge request cable-mc/cobblemon!2042
2025-11-26 13:27:12 +00:00
NeovitalismandPolymeta 645b8993c8 Fixes wind charges recalling pastured pokémon 2025-11-26 13:27:12 +00:00
Polymeta d96799cac7 Merge branch 'feature/neoforge-recipe-book' into 'main'
split recipebooktype and category across fabric and neoforge so we can leverage neoforge APIs

Closes #1789 and #1787

See merge request cable-mc/cobblemon!2044
2025-11-26 12:44:06 +00:00
Polymeta b822b626c4 split recipebooktype and category across fabric and neoforge so we can leverage neoforge APIs 2025-11-26 12:44:05 +00:00
Polymeta 4d9b182fb3 fix hearty grains crashing if a block is in the way
Closes #1818

Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-11-26 11:59:25 +00:00
Polymeta 88d155eaf4 [skip-ci] more changelog
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-11-26 11:33:57 +00:00
Paul af96469b7a changelog [skip-ci] 2025-11-26 21:17:15 +10:00
Paul 65f1e7a3be Merge remote-tracking branch 'weblate/lang-updates' 2025-11-26 21:14:31 +10:00
阿鱼andWeblate 16cd2de02f Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.4% (8973 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-11-26 10:03:51 +00:00
Polymeta 22a44bd7e9 Merge branch 'ImprovedPastureBees' into 'main'
Improved Pasture Combees and More

See merge request cable-mc/cobblemon!2043
2025-11-26 09:36:28 +00:00
Polymeta d37bd4ef03 Merge branch 'OmnipathNavigationCrashFix' into 'main'
OmnipathNavigationCrashFix

See merge request cable-mc/cobblemon!2045
2025-11-26 09:34:03 +00:00
Hiroku a3d9a10f2e Merge branch 'wallpaper' into 'main'
Remove auto generated screen glow due to rendering issues

See merge request cable-mc/cobblemon!2047
2025-11-26 08:48:00 +00:00
Test 7801e3feee changelog clarification [skip-ci] 2025-11-26 04:56:10 +00:00
Test 4a54cb4674 remove auto generated screen glow 2025-11-26 04:38:14 +00:00
JazzMcNade 24fe1c125c changelog 2025-11-25 21:47:45 -06:00
JazzMcNade 023160f87a Removed a really silly cast 2025-11-25 21:32:17 -06:00
Polymeta 17fbf7c6f0 defensive pokemon casts as NPCs use this too
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-11-25 16:53:26 +00:00
Polymeta ec86b7d4bf fix tag reference
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-11-25 15:18:09 +00:00
阿鱼andWeblate 7561eb116f Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.3% (8960 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-11-25 14:20:09 +00:00
Polymeta 6467b97a23 Merge branch 'implement_pokemon' into 'main'
marked furfrou as implemented

See merge request cable-mc/cobblemon!2041
2025-11-25 12:16:02 +00:00
JazzMcNade 6d5909a1e3 Added rain clause, do not attempt to enter a full hive, changelog 2025-11-25 02:17:28 -06:00
JazzMcNade 2bb0d43ca8 Fix wandering for pastured bees, fix hoverpos not being cleared 2025-11-25 00:51:04 -06:00
Watuneni iteiteandWeblate 1fb3f0ebdc Translated using Weblate (Japanese)
Currently translated at 99.2% (8954 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-11-25 06:46:07 +00:00
violet fb2154e2c3 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-24 22:06:34 -05:00
violet 3b14d19fdb marked furfrou as implemented 2025-11-24 22:06:22 -05:00
Carmendar 6840c2fdef Merge branch 'main' into implement_pokemon 2025-11-24 17:28:35 -06:00
阿鱼andWeblate 8fc2031806 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.2% (8954 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-11-24 21:23:59 +00:00
Alexis SalgueiroandWeblate 4795e2e1bc Translated using Weblate (French)
Currently translated at 99.6% (8984 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-11-24 11:22:45 +00:00
Carmendar c563627b05 Shiny female Combee is now actually shiny. 2025-11-24 02:31:25 -06:00
violet 73ebf7a789 tiny typo fix 2025-11-24 03:18:38 -05:00
Landon a1b3d3d2ca Merge branch 'lets-be-friends-again' into 'main'
Move friendship logic to spawn action

See merge request cable-mc/cobblemon!2037
2025-11-24 06:50:24 +00:00
lionandLandon 8baacbcf90 Move friendship logic to spawn action 2025-11-24 06:50:23 +00:00
Hiroku f2e357b749 Merge branch 'pc-crash-fix' into 'main'
Fix PC crash with VulkanMod

Closes #1793

See merge request cable-mc/cobblemon!2038
2025-11-24 04:28:32 +00:00
Test b95900b29a Fix PC crash with VulkanMod 2025-11-23 22:39:28 -05:00
Hiroku 03585fafb0 Merge branch 'HoneyIForgotTheNectar' into 'main'
Don't Forget the Nectar

See merge request cable-mc/cobblemon!2031
2025-11-24 01:38:14 +00:00
washashu0905andWeblate e3d0252d75 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 94.4% (8519 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2025-11-24 00:10:57 +00:00
阿鱼andWeblate dbe8e57341 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.2% (8950 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-11-24 00:10:56 +00:00
Zack the GhastandWeblate 6f37fd69cd Translated using Weblate (Portuguese (Brazil))
Currently translated at 97.4% (8791 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_BR/
2025-11-24 00:10:55 +00:00
JazzMcNade b191f4e9fb Check hivecooldown memory registration 2025-11-23 15:42:56 -06:00
Hiroku a5a7cc20ba Merge branch 'eating-cough-drops' into 'main'
Throat Spray Recipe

See merge request cable-mc/cobblemon!2036
2025-11-23 11:48:00 +00:00
Polymeta 02b6c46082 [skip-ci] 1.7 tag doc files
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-11-23 11:39:39 +00:00
dhi_holo 881a30cca4 Merge branch 'main' into eating-cough-drops 2025-11-23 20:33:20 +10:00
dhi_holo d01011f4d0 Throat Spray Recipe
This either was lost at some point or never existed in the mod, I'm not sure which. It's here now!
2025-11-23 20:32:21 +10:00
Landon 309ed379c7 Merge branch 'AAAAAAAAAAAAAAAAAAAAA' into 'main'
unfudge camera maybe please

See merge request cable-mc/cobblemon!2030
2025-11-23 10:30:50 +00:00
Landon Wills edbf667f45 Add changelog 2025-11-23 04:44:02 -05:00
Landon Wills b6bc766adf Merge branch 'main' into AAAAAAAAAAAAAAAAAAAAA 2025-11-23 04:42:52 -05:00
Test 1ecf556cf2 Merge branch 'nom' into 'main'
Small Fixes

See merge request cable-mc/cobblemon!2035
2025-11-23 03:46:33 +00:00
dhi_holo 6d32073604 Small Fixes
- Ponigiri can no longer be eaten at full hunger
- Medicinal Brew's Campfire Pot recipe now correctly displays that it can be made using an empty glass bottle or a filled bottle
- Added trades for Saccharine Saplings, Hearty Grains, Chipped Pot, and Masterpiece Teacup to the Wandering Trader
- Reduced cost of the Vivichoke Seed trade with the Wandering Trader
2025-11-23 12:45:18 +10:00
Hiroku aa0f5d8a05 Merge branch 'vanilla-ride-fix-and-misc-ride-fixes' into 'main'
Fix vanilla rides suffocating players and misc cobble riding fixes

See merge request cable-mc/cobblemon!2033
2025-11-22 23:50:31 +00:00
jackowes 6202c14215 - changelog update 2025-11-22 16:42:20 -06:00
Hiroku b0790341c7 Merge branch 'some-fixes' into 'main'
Some fixes

See merge request cable-mc/cobblemon!2032
2025-11-22 22:36:17 +00:00
jackowes 4f0fa6af4a - Fix horse player suffocation on vanilla mounts
- stop passengers from hearing the shiny noise of a ridden shiny pokemon.
- Convert the riding freelook button to a configurable keybinding

(cherry picked from commit 6432db9f7d)
2025-11-22 16:24:25 -06:00
JazzMcNade 4e24e09924 Safer memory reading in hive occupant mixins 2025-11-22 16:19:30 -06:00
jackowes 48676067b7 Revert "- Fix horse player suffocation on vanilla mounts"
This reverts commit 6432db9f7d.
2025-11-22 16:16:17 -06:00
jackowes 6432db9f7d - Fix horse player suffocation on vanilla mounts
- stop passengers from hearing the shiny noise of a ridden shiny pokemon.
- Convert the riding freelook button to a configurable keybinding
2025-11-22 16:13:47 -06:00
Test 2cb28fb384 rm unused imports 2025-11-22 12:57:59 -05:00
JazzMcNade 3b59148151 changelog again 2025-11-22 11:43:44 -06:00
JazzMcNade d6198631ba New Changelog 2025-11-22 11:40:03 -06:00
geumuandWeblate 47daea6195 Translated using Weblate (Korean)
Currently translated at 75.6% (6826 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-22 17:37:36 +00:00
Watuneni iteiteandWeblate aca66a4bb0 Translated using Weblate (Japanese)
Currently translated at 99.2% (8954 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-11-22 17:37:35 +00:00
Test e9fe1774c0 fix poke snack sound issue, prevent ride controls from showing to passengers 2025-11-22 12:36:31 -05:00
JazzMcNade bb8b8a77c9 Fixed bees forgetting that they had nectar upon entering a hive 2025-11-22 11:07:37 -06:00
Paul c692b6b5c1 Reset changelog [skip-ci] 2025-11-22 23:09:37 +10:00
geumuandWeblate 68c6d5d9b2 Translated using Weblate (Korean)
Currently translated at 75.6% (6825 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-22 07:33:14 +00:00
Landon Wills 221547aabf unfuck camera maybe please 2025-11-21 22:39:19 -05:00
Watuneni iteiteandWeblate f6b3591d80 Translated using Weblate (Japanese)
Currently translated at 99.2% (8954 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-11-22 03:06:51 +00:00
geumuandWeblate f9878d6137 Translated using Weblate (Korean)
Currently translated at 75.2% (6740 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-22 01:45:14 +00:00
Watuneni iteiteandWeblate 94da3b8d21 Translated using Weblate (Japanese)
Currently translated at 100.0% (8962 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-11-22 01:45:14 +00:00
86 changed files with 9586 additions and 1634 deletions
+41 -995
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -17,6 +17,7 @@ import net.minecraft.nbt.CompoundTag;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.ai.memory.MemoryStatus;
import net.minecraft.world.item.component.CustomData;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.BeehiveBlock;
@@ -52,7 +53,9 @@ public abstract class BeeOccupantMixin {
var facing = state.getValue(HorizontalDirectionalBlock.FACING);
newPos = pos.relative(facing).getCenter();
newYaw = facing.toYRot();
brain.setMemory(CobblemonMemories.HIVE_LOCATION, pos); // This needs to be set in the case that the hive was picked up and moved.
if (brain.checkMemory(CobblemonMemories.HIVE_LOCATION, MemoryStatus.REGISTERED)) {
brain.setMemory(CobblemonMemories.HIVE_LOCATION, pos); // This needs to be set in the case that the hive was picked up and moved.
}
} else {
// Block has likely been destroyed
var center = pos.getCenter();
@@ -62,25 +65,31 @@ public abstract class BeeOccupantMixin {
center.z + level.random.nextFloat() * 0.6 - 0.3
);
newYaw = level.random.nextFloat() * 360F;
brain.eraseMemory(CobblemonMemories.HIVE_LOCATION);
if (brain.checkMemory(CobblemonMemories.HIVE_LOCATION, MemoryStatus.REGISTERED)) {
brain.eraseMemory(CobblemonMemories.HIVE_LOCATION);
}
}
entity.yRotO = newYaw;
entity.setPos(newPos);
// Do honey logic
var hasNectar = brain.getMemory(CobblemonMemories.HAS_NECTAR).orElse(false);
if (hasNectar) {
// Remove nectar and reset got to hive cooldown
brain.eraseMemory(CobblemonMemories.HAS_NECTAR);
brain.setMemoryWithExpiry(CobblemonMemories.HIVE_COOLDOWN, true, PathToBeeHiveTaskConfig.STAY_OUT_OF_HIVE_COOLDOWN);
// Increment honey level of the hive
if (state.is(BlockTags.BEEHIVES, (blockStateBase) -> blockStateBase.hasProperty(BeehiveBlock.HONEY_LEVEL))) {
int i = state.getValue(BeehiveBlock.HONEY_LEVEL);
if (i < 5) {
int j = level.random.nextInt(100) == 0 ? 2 : 1;
if (i + j > 5) {
--j;
if (brain.checkMemory(CobblemonMemories.HAS_NECTAR, MemoryStatus.REGISTERED)) {
var hasNectar = brain.getMemory(CobblemonMemories.HAS_NECTAR).orElse(false);
if (hasNectar) {
// Remove nectar and reset got to hive cooldown
brain.eraseMemory(CobblemonMemories.HAS_NECTAR);
if (brain.checkMemory(CobblemonMemories.HIVE_LOCATION, MemoryStatus.REGISTERED)) {
brain.setMemoryWithExpiry(CobblemonMemories.HIVE_COOLDOWN, true, PathToBeeHiveTaskConfig.STAY_OUT_OF_HIVE_COOLDOWN);
}
// Increment honey level of the hive
if (state.is(BlockTags.BEEHIVES, (blockStateBase) -> blockStateBase.hasProperty(BeehiveBlock.HONEY_LEVEL))) {
int i = state.getValue(BeehiveBlock.HONEY_LEVEL);
if (i < 5) {
int j = level.random.nextInt(100) == 0 ? 2 : 1;
if (i + j > 5) {
--j;
}
level.setBlockAndUpdate(pos, state.setValue(BeehiveBlock.HONEY_LEVEL, i + j));
}
level.setBlockAndUpdate(pos, state.setValue(BeehiveBlock.HONEY_LEVEL, i + j));
}
}
}
@@ -92,12 +101,13 @@ public abstract class BeeOccupantMixin {
@Inject(method = "of", at = @At("HEAD"), cancellable = true)
private static void cobblemon$of(Entity entity, CallbackInfoReturnable<BeehiveBlockEntity.Occupant> cir) {
if (entity instanceof PokemonEntity pokemonEntity) {
List<String> IGNORED_BEE_TAGS = Arrays.asList("Air", "ArmorDropChances", "ArmorItems", "Brain", "CanPickUpLoot", "DeathTime", "FallDistance", "FallFlying", "Fire", "HandDropChances", "HandItems", "HurtByTimestamp", "HurtTime", "LeftHanded", "Motion", "NoGravity", "OnGround", "PortalCooldown", "Pos", "Rotation", "Passengers", "leash", "UUID");
List<String> IGNORED_BEE_TAGS = Arrays.asList("Air", "ArmorDropChances", "ArmorItems", "CanPickUpLoot", "DeathTime", "FallDistance", "FallFlying", "Fire", "HandDropChances", "HandItems", "HurtByTimestamp", "HurtTime", "LeftHanded", "Motion", "NoGravity", "OnGround", "PortalCooldown", "Pos", "Rotation", "Passengers", "leash", "UUID");
CompoundTag compoundTag = new CompoundTag();
entity.save(compoundTag);
Objects.requireNonNull(compoundTag);
IGNORED_BEE_TAGS.forEach(compoundTag::remove);
Boolean hasNectar = pokemonEntity.getBrain().getMemory(CobblemonMemories.HAS_NECTAR).orElse(false);
boolean hasNectar = pokemonEntity.getBrain().checkMemory(CobblemonMemories.HAS_NECTAR, MemoryStatus.REGISTERED)
&& pokemonEntity.getBrain().getMemory(CobblemonMemories.HAS_NECTAR).orElse(false);
cir.setReturnValue(new BeehiveBlockEntity.Occupant(CustomData.of(compoundTag), 0, hasNectar ? 2400 : 600));
cir.cancel();
}
@@ -1,38 +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.mixin;
import com.cobblemon.mod.common.block.PreEmptsExplosion;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Explosion;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(value = Explosion.class)
public class ExplosionMixin {
@Redirect(
method = "finalizeExplosion",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/level/Level;getBlockState(Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/level/block/state/BlockState;",
ordinal = 0
)
)
public BlockState cobblemon$whenExploded(Level world, BlockPos pos) {
BlockState blockState = world.getBlockState(pos);
if(blockState.getBlock() instanceof PreEmptsExplosion preExplosionBlock) {
preExplosionBlock.whenExploded(world, blockState, pos);
}
return blockState;
}
}
@@ -1,32 +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.mixin;
import net.minecraft.stats.RecipeBookSettings;
import net.minecraft.world.inventory.RecipeBookType;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Map;
@Mixin(RecipeBookSettings.class)
public class RecipeBookSettingsMixin {
@Shadow @Final public Map<RecipeBookType, RecipeBookSettings.TypeSettings> states;
@Inject(method = "<init>", at = @At("TAIL"))
private void cobblemon$init(CallbackInfo ci) {
states.put(RecipeBookType.valueOf("COOKING_POT"), new RecipeBookSettings.TypeSettings(true, true));
}
}
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.OrientationControllable;
import com.cobblemon.mod.common.api.orientation.OrientationController;
import com.cobblemon.mod.common.client.CobblemonClient;
import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding;
import com.cobblemon.mod.common.client.keybind.keybinds.RidingFreelookBinding;
import com.cobblemon.mod.common.duck.RidePassenger;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.pokedex.scanner.PokedexUsageContext;
@@ -156,7 +157,7 @@ public abstract class MouseHandlerMixin {
}
var vehicleController = controllableVehicle.getOrientationController();
var lookaroundButtonPressed = Minecraft.getInstance().mouseHandler.isMiddlePressed();
var freeLooking = RidingFreelookBinding.INSTANCE.isDown();
Pair<Boolean, Boolean> mouseShouldModifyDriver = ((PokemonEntity) vehicle).ifRidingAvailableSupply(new Pair(false, false), (behaviour, settings, state) -> {
return behaviour.mouseModifiesDriverRotation(
settings,
@@ -170,7 +171,7 @@ public abstract class MouseHandlerMixin {
// affect the vehicle orientation when looking around.
// If the client is a passenger it will modify these rotations and return
//-------------------------------------------------------------------------
if (lookaroundButtonPressed || player.getControlledVehicle() == null) {
if (freeLooking || player.getControlledVehicle() == null) {
// Modify driver rotations
cobblemon$setDriverRotations(player, cursorDeltaX, cursorDeltaY);
@@ -192,10 +193,10 @@ public abstract class MouseHandlerMixin {
// Smoothly return driver rotations to zero when needed
//-------------------------------------------------------------------------
var playerRotater = (RidePassenger)player;
if( !lookaroundButtonPressed && !mouseShouldModifyDriver.getFirst()){
if( !freeLooking && !mouseShouldModifyDriver.getFirst()){
playerRotater.cobblemon$setRideYRot(lerp(min(5.0f * (float)movementTime, 1.0f), Mth.wrapDegrees(playerRotater.cobblemon$getRideYRot()), 0.0f));
}
if( !lookaroundButtonPressed && !mouseShouldModifyDriver.getSecond()) {
if( !freeLooking && !mouseShouldModifyDriver.getSecond()) {
playerRotater.cobblemon$setRideXRot(lerp(min(5.0f * (float)movementTime, 1.0f), Mth.wrapDegrees(playerRotater.cobblemon$getRideXRot()), 0.0f));
}
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.mixin.entity;
import com.cobblemon.mod.common.OrientationControllable;
import com.cobblemon.mod.common.duck.RidePassenger;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.pokemon.Pokemon;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import net.minecraft.client.player.LocalPlayer;
@@ -23,6 +24,7 @@ import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@@ -68,18 +70,7 @@ public abstract class EntityMixin {
cancellable = true
)
private void cobblemon$modifyEyePosition_partial(float partialTicks, CallbackInfoReturnable<Vec3> cir) {
var entity = (Entity)(Object)this;
if (entity.level().isClientSide) return;
if (!(entity instanceof Player player)) return;
if (!(player instanceof RidePassenger ridePassenger)) return;
if (!(player.getVehicle() instanceof OrientationControllable vehicle)) return;
var vehicleController = vehicle.getOrientationController();
if (vehicleController == null) return;
// TODO: Determine if it needs partialtick involved.
Vec3 customEyePos = ridePassenger.cobblemon$getRideEyePos();
cir.setReturnValue(customEyePos);
cobblemon$getCustomEyePos(cir);
}
@Inject(
@@ -88,15 +79,20 @@ public abstract class EntityMixin {
cancellable = true
)
private void cobblemon$modifyEyePosition_noPartial(CallbackInfoReturnable<Vec3> cir) {
cobblemon$getCustomEyePos(cir);
}
@Unique
private void cobblemon$getCustomEyePos(CallbackInfoReturnable<Vec3> cir) {
var entity = (Entity)(Object)this;
if (entity.level().isClientSide) return;
if (!(entity instanceof Player player)) return;
if (!(player instanceof RidePassenger ridePassenger)) return;
if (!(player.getVehicle() instanceof OrientationControllable vehicle)) return;
if (!(vehicle instanceof PokemonEntity)) return;
var vehicleController = vehicle.getOrientationController();
if (vehicleController == null) return;
// TODO: Determine if it needs partialtick involved.
Vec3 customEyePos = ridePassenger.cobblemon$getRideEyePos();
cir.setReturnValue(customEyePos);
}
@@ -215,7 +215,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
@JvmField
val SACCHARINE_WALL_SIGN = this.create("saccharine_wall_sign", CobblemonWallSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_SIGN), SACCHARINE_WOOD_TYPE))
@JvmField
val SACCHARINE_HANGING_SIGN = this.create("saccharine_hanging_sign", CobblemonHangingSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_WALL_HANGING_SIGN), SACCHARINE_WOOD_TYPE))
val SACCHARINE_HANGING_SIGN = this.create("saccharine_hanging_sign", CobblemonHangingSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_HANGING_SIGN), SACCHARINE_WOOD_TYPE))
@JvmField
val SACCHARINE_WALL_HANGING_SIGN = this.create("saccharine_wall_hanging_sign", CobblemonWallHangingSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_HANGING_SIGN), SACCHARINE_WOOD_TYPE))
@JvmField
@@ -23,6 +23,7 @@ import com.cobblemon.mod.common.block.MintBlock
import com.cobblemon.mod.common.block.MintBlock.MintType
import com.cobblemon.mod.common.client.pokedex.PokedexType
import com.cobblemon.mod.common.block.campfirepot.CampfirePotColor
import com.cobblemon.mod.common.config.CobblemonConfig
import com.cobblemon.mod.common.entity.boat.CobblemonBoatType
import com.cobblemon.mod.common.item.*
import com.cobblemon.mod.common.item.armor.CobblemonArmorTrims
@@ -42,6 +43,7 @@ import com.cobblemon.mod.common.item.interactive.ability.AbilityChangeItem
import com.cobblemon.mod.common.platform.PlatformRegistry
import com.cobblemon.mod.common.pokeball.PokeBall
import com.cobblemon.mod.common.pokemon.IVs
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.core.Registry
@@ -50,6 +52,7 @@ import net.minecraft.core.registries.Registries
import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceKey
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.effect.MobEffectInstance
import net.minecraft.world.effect.MobEffects
import net.minecraft.world.entity.LivingEntity
@@ -66,6 +69,7 @@ import net.minecraft.world.item.SignItem
import net.minecraft.world.item.SmithingTemplateItem
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block
import kotlin.math.ceil
@Suppress("unused", "SameParameterValue")
object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<Item>>, Item>() {
@@ -614,7 +618,11 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
// Medicine
@JvmField
val RARE_CANDY = candyItem("rare_candy", Rarity.RARE) { _, pokemon -> pokemon.getExperienceToNextLevel() }
val RARE_CANDY = candyItem("rare_candy", Rarity.RARE) { player, pokemon ->
if (pokemon != null) return@candyItem pokemon.getExperienceToNextLevel()
return@candyItem -1
}
@JvmField
val EXPERIENCE_CANDY_XS = candyItem("exp_candy_xs") { _, _ -> CandyItem.DEFAULT_XS_CANDY_YIELD }
@JvmField
@@ -1476,7 +1484,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
return item
}
private fun candyItem(name: String, rarity: Rarity = Rarity.COMMON, calculator: CandyItem.Calculator): CandyItem = this.create(name, CandyItem(rarity, calculator))
private fun candyItem(name: String, rarity: Rarity = Rarity.COMMON, calculator: (ServerPlayer, Pokemon?) -> Int): CandyItem = this.create(name, CandyItem(rarity, calculator))
private fun pokerodItem(pokeRodId: ResourceLocation, rarity: Rarity = Rarity.COMMON): PokerodItem {
val settings = Item.Properties().stacksTo(1).durability(256).rarity(rarity)
@@ -9,14 +9,15 @@
package com.cobblemon.mod.common
import net.minecraft.client.RecipeBookCategories
import net.minecraft.world.inventory.RecipeBookType
enum class CobblemonRecipeCategories {
COOKING_POT_SEARCH("COOKING_POT_SEARCH"),
COOKING_POT_FOODS("COOKING_POT_FOODS"),
COOKING_POT_MEDICINES("COOKING_POT_MEDICINES"),
COOKING_POT_COMPLEX_DISHES("COOKING_POT_COMPLEX_DISHES"),
COOKING_POT_MISC("COOKING_POT_MISC");
COOKING_POT_SEARCH("COBBLEMON_COOKING_POT_SEARCH"),
COOKING_POT_FOODS("COBBLEMON_COOKING_POT_FOODS"),
COOKING_POT_MEDICINES("COBBLEMON_COOKING_POT_MEDICINES"),
COOKING_POT_COMPLEX_DISHES("COBBLEMON_COOKING_POT_COMPLEX_DISHES"),
COOKING_POT_MISC("COBBLEMON_COOKING_POT_MISC");
companion object {
val customAggregateCategories: Map<RecipeBookCategories, List<RecipeBookCategories>> = mapOf(
@@ -35,6 +36,9 @@ enum class CobblemonRecipeCategories {
fun toVanillaCategory(): RecipeBookCategories {
return RecipeBookCategories.valueOf(this.id)
}
}
object CobblemonRecipeBookTypes {
const val COOKING_POT_NAME = "COBBLEMON_COOKING_POT"
val COOKING_POT: RecipeBookType = RecipeBookType.valueOf(COOKING_POT_NAME)
}
@@ -89,7 +89,14 @@ object CobblemonTradeOffers {
* @return The resulting list.
*/
fun resolveWanderingTradeOffers(): List<WandererTradeOffer> = listOf(
WandererTradeOffer(false, listOf(VillagerTrades.ItemsForEmeralds(CobblemonItems.VIVICHOKE_SEEDS, 24, 1, 1, 6)))
WandererTradeOffer(false, listOf(
VillagerTrades.ItemsForEmeralds(CobblemonItems.VIVICHOKE_SEEDS, 6, 1, 1, 6),
VillagerTrades.ItemsForEmeralds(CobblemonItems.SACCHARINE_SAPLING, 5, 1, 4, 1),
VillagerTrades.ItemsForEmeralds(CobblemonItems.HEARTY_GRAINS, 1, 1, 12, 1),
VillagerTrades.ItemsForEmeralds(CobblemonItems.CHIPPED_POT, 5, 1, 1, 2),
VillagerTrades.ItemsForEmeralds(CobblemonItems.MASTERPIECE_TEACUP, 5, 1, 1, 2)
))
)
/**
@@ -109,7 +109,7 @@ class PollinateFlowerTaskConfig : SingleTaskConfig {
}
override fun stop(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
hoverPos = null
if (successfulPollinationTicks > REQUIRED_SUCCESSFUL_POLLINATION_TICKS) {
entity.brain.setMemory(CobblemonMemories.HAS_NECTAR, true)
}
@@ -9,13 +9,8 @@
package com.cobblemon.mod.common.api.cooking
import com.cobblemon.mod.common.api.riding.stats.RidingStat
import com.cobblemon.mod.common.util.math.geometry.toDegrees
import com.cobblemon.mod.common.util.math.geometry.toRadians
import net.minecraft.util.FastColor
import net.minecraft.world.item.ItemStack
import kotlin.math.atan2
import kotlin.math.cos
import kotlin.math.sin
private val colourMap = mapOf(
Flavour.SPICY to 0xFEB37D,
@@ -34,27 +29,30 @@ private val bubbleColourMap = mapOf(
)
fun getColourMixFromSeasonings(seasonings: List<ItemStack>, forBubbles: Boolean = false): Int? {
val flavors = seasonings
.mapNotNull { Seasonings.getFlavoursFromItemStack(it) }
.flatMap { it.entries }
.groupingBy { it.key }
.fold(0) { acc, entry -> acc + entry.value }
val flavourValues = mutableMapOf<Flavour, Int>()
for (seasoning in seasonings) {
val flavours = Seasonings.getFlavoursFromItemStack(seasoning) ?: continue
for ((flavour, value) in flavours.entries) {
flavourValues[flavour] = (flavourValues[flavour] ?: 0) + value
}
}
if (flavors.isEmpty()) return null
if (flavourValues.isEmpty()) {
return null
}
val maxFlavorValue = flavors.values.maxOrNull()
val dominantFlavors = flavors.filter { it.value == maxFlavorValue }.map { it.key }
val maxFlavorValue = flavourValues.values.maxOrNull()
val dominantFlavours = flavourValues.filter { it.value == maxFlavorValue }.map { it.key }
return getColourMixFromFlavours(dominantFlavors, forBubbles)
return getColourMixFromFlavours(dominantFlavours, forBubbles)
}
fun getColourMixFromFlavours(dominantFlavours: List<Flavour>, forBubbles: Boolean = false): Int? {
val colors =
dominantFlavours.mapNotNull { if (forBubbles) bubbleColourMap[it] else colourMap[it] }
dominantFlavours
.mapNotNull { if (forBubbles) bubbleColourMap[it] else colourMap[it] }
.map { FastColor.ARGB32.opaque(it) }
if (colors.isEmpty()) return null
return getColourMixFromColors(colors)
}
@@ -62,104 +60,33 @@ fun getColourMixFromRideStatBoosts(dominantBoosts: Iterable<RidingStat>, forBubb
return getColourMixFromFlavours(dominantBoosts.map { it.flavour }, forBubbles)
}
// Mixing RGB colors directly often gives poor results
// Converting them to HSL and averaging hues circularly produces more natural blends
fun getColourMixFromColors(colors: List<Int>): Int? {
if (colors.isEmpty()) return null
if (colors.size == 1) return colors[0]
val hslColors = colors.map {
val red = FastColor.ARGB32.red(it)
val green = FastColor.ARGB32.green(it)
val blue = FastColor.ARGB32.blue(it)
val firstWeight = 0.7f
val otherWeightTotal = 1f - firstWeight
val otherWeight = otherWeightTotal / (colors.size - 1)
rgbToHsl(red, green, blue)
var alphaSum = 0f
var redSum = 0f
var greenSum = 0f
var blueSum = 0f
for (i in colors.indices) {
val weight = if (i == 0) firstWeight else otherWeight
val color = colors[i]
alphaSum += FastColor.ARGB32.alpha(color) * weight
redSum += FastColor.ARGB32.red(color) * weight
greenSum += FastColor.ARGB32.green(color) * weight
blueSum += FastColor.ARGB32.blue(color) * weight
}
val hues = hslColors.map { it.h.toDouble() }
val huesAverage = hueAverage(hues).toFloat()
val saturations = hslColors.map { it.s }
val saturationsAverage = average(saturations)
val lightness = hslColors.map { it.l }
val lightnessAverage = average(lightness)
val rgbColor = hslToRgb(huesAverage, saturationsAverage, lightnessAverage)
return FastColor.ARGB32.color(rgbColor.r, rgbColor.g, rgbColor.b)
}
// Based on https://iter.ca/post/hue-avg
fun hueAverage(hues: List<Double>): Float {
val points = hues.map { hue ->
val rad = hue.toRadians()
Pair(cos(rad), sin(rad))
}
val avgX = points.sumOf { it.first.toDouble() } / points.size
val avgY = points.sumOf { it.second.toDouble() } / points.size
var degrees = atan2(avgY, avgX).toDegrees()
if (degrees < 0) {
degrees += 360f
} else if (degrees > 360) {
degrees -= 360f
}
return degrees
}
fun average(values: List<Float>): Float {
if (values.isEmpty()) return 0f
return values.sum() / values.size
}
data class HSL(val h: Float, val s: Float, val l: Float)
fun rgbToHsl(r: Int, g: Int, b: Int): HSL {
val rf = r / 255f
val gf = g / 255f
val bf = b / 255f
val max = maxOf(rf, gf, bf)
val min = minOf(rf, gf, bf)
val delta = max - min
var h = 0f
val l = (max + min) / 2f
val s = if (delta == 0f) 0f else delta / (1f - kotlin.math.abs(2f * l - 1f))
if (delta != 0f) {
h = when (max) {
rf -> ((gf - bf) / delta) % 6f
gf -> ((bf - rf) / delta) + 2f
else -> ((rf - gf) / delta) + 4f
}
h *= 60f
if (h < 0) h += 360f
}
return HSL(h, s, l)
}
data class RGB(val r: Int, val g: Int, val b: Int)
fun hslToRgb(h: Float, s: Float, l: Float): RGB {
val c = (1f - kotlin.math.abs(2f * l - 1f)) * s
val x = c * (1f - kotlin.math.abs((h / 60f) % 2f - 1f))
val m = l - c / 2f
val (rf, gf, bf) = when {
h < 60f -> Triple(c, x, 0f)
h < 120f -> Triple(x, c, 0f)
h < 180f -> Triple(0f, c, x)
h < 240f -> Triple(0f, x, c)
h < 300f -> Triple(x, 0f, c)
else -> Triple(c, 0f, x)
}
return RGB(
((rf + m) * 255).toInt().coerceIn(0, 255),
((gf + m) * 255).toInt().coerceIn(0, 255),
((bf + m) * 255).toInt().coerceIn(0, 255)
return FastColor.ARGB32.color(
alphaSum.toInt(),
redSum.toInt(),
greenSum.toInt(),
blueSum.toInt()
)
}
@@ -37,8 +37,6 @@ import net.minecraft.resources.ResourceLocation
import net.minecraft.util.FormattedCharSequence
import org.joml.Matrix4f
import org.joml.Vector3f
import org.lwjgl.opengl.GL30
import java.nio.ByteBuffer
@JvmOverloads
fun blitk(
@@ -357,10 +355,10 @@ fun renderSprite(matrixStack: PoseStack, sprite: ResourceLocation) {
val matrix: PoseStack.Pose = matrixStack.last()
matrix.pose().translate(-1f, 0f, 0f)
RenderSystem.setShaderTexture(0, sprite);
RenderSystem.setShaderTexture(0, sprite)
RenderSystem.setShader(GameRenderer::getPositionTexShader)
var buffer = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX)
val buffer = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX)
buffer.addVertex(matrix, 2f, 0f, 0.0f).setUv(1f, 0f)
buffer.addVertex(matrix, 0f, 0f, 0.0f).setUv(0f, 0f)
@@ -369,25 +367,3 @@ fun renderSprite(matrixStack: PoseStack, sprite: ResourceLocation) {
BufferUploader.drawWithShader(buffer.buildOrThrow())
}
fun getPixelRGB(x: Int, y: Int): Triple<Int, Int, Int> {
val window = Minecraft.getInstance().window
val scale = window.guiScale
val buffer = ByteBuffer.allocateDirect(4)
RenderSystem.readPixels(
(x * scale).toInt(),
(window.height - y * scale - scale).toInt(),
1,
1,
GL30.GL_RGBA,
GL30.GL_UNSIGNED_BYTE,
buffer
)
return Triple(
buffer[0].toInt() and 0xFF,
buffer[1].toInt() and 0xFF,
buffer[2].toInt() and 0xFF
)
}
@@ -409,13 +409,7 @@ open class PokemonProperties {
shiny?.let { pokemon.shiny = it }
gender?.let { pokemon.gender = it }
level?.let { pokemon.level = it }
friendship.also {
if (it != null) {
pokemon.setFriendship(it)
} else {
pokemon.setFriendship(pokemon.form.baseFriendship)
}
}
friendship?.also { pokemon.setFriendship(it) }
fullness?.let { pokemon.currentFullness = it }
pokeball?.let { PokeBalls.getPokeBall(it.asIdentifierDefaultingNamespace())?.let { pokeball -> pokemon.caughtBall = pokeball } }
nature?.let { Natures.getNature(it.asIdentifierDefaultingNamespace())?.let { nature -> pokemon.nature = nature } }
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import net.minecraft.commands.CommandSourceStack
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.item.ItemStack
/**
@@ -25,8 +26,13 @@ interface ExperienceSource {
fun isInteraction() = this is CandyExperienceSource
fun isCommand() = this is CommandExperienceSource
fun isSidemod() = this is SidemodExperienceSource
fun isMob() = this is MobExperienceSource
}
open class MobExperienceSource(
mob: LivingEntity,
) : ExperienceSource
open class SidemodExperienceSource(
val sidemodId: String
) : ExperienceSource
@@ -40,9 +40,12 @@ class PokemonSpawnAction(
override fun createEntity(): PokemonEntity {
val props = props.copy()
props.level = levelRange.random()
val sourcePlayer = spawnablePosition.cause.entity as? ServerPlayer
val entity = props.createEntity(spawnablePosition.world, sourcePlayer)
entity.spawnCause = spawnablePosition.cause
entity.pokemon.setFriendship(entity.pokemon.form.baseFriendship)
SeasonFeatureHandler.updateSeason(entity.pokemon, Cobblemon.seasonResolver(spawnablePosition.world, spawnablePosition.position))
val heldItem = heldItem
if (heldItem != ItemStack.EMPTY && heldItem != null) {
@@ -19,7 +19,6 @@ import net.minecraft.server.level.ServerLevel
import net.minecraft.tags.FluidTags
import net.minecraft.util.Mth
import net.minecraft.util.RandomSource
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.context.BlockPlaceContext
import net.minecraft.world.level.*
import net.minecraft.world.level.block.Block
@@ -175,7 +174,7 @@ class HeartyGrainsBlock(settings: Properties) : CropBlock(settings), SimpleWater
UPDATE_CLIENTS
)
}
else if (stateAbove.getValue(HALF) == DoubleBlockHalf.UPPER) {
else if (stateAbove.hasProperty(HALF) && stateAbove.getValue(HALF) == DoubleBlockHalf.UPPER) {
world.setBlock(
abovePos,
stateAbove.setValue(AGE, newAge),
@@ -34,6 +34,7 @@ import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.context.BlockPlaceContext
import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.Explosion
import net.minecraft.world.level.Level
import net.minecraft.world.level.LevelAccessor
import net.minecraft.world.level.LevelReader
@@ -55,9 +56,10 @@ import net.minecraft.world.phys.shapes.VoxelShape
import java.util.*
import net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED
import net.minecraft.world.level.gameevent.GameEvent
import java.util.function.BiConsumer
@Suppress("OVERRIDE_DEPRECATION", "DEPRECATION")
class PastureBlock(settings: Properties): BaseEntityBlock(settings), SimpleWaterloggedBlock, PreEmptsExplosion {
class PastureBlock(settings: Properties): BaseEntityBlock(settings), SimpleWaterloggedBlock {
companion object {
val CODEC = simpleCodec(::PastureBlock)
@@ -213,9 +215,19 @@ class PastureBlock(settings: Properties): BaseEntityBlock(settings), SimpleWater
return super.playerWillDestroy(world, pos, state, player)
}
override fun whenExploded(world: Level, state: BlockState, pos: BlockPos) {
val blockEntity = world.getBlockEntity(pos) as? PokemonPastureBlockEntity ?: return
blockEntity.onBroken()
override fun onExplosionHit(
state: BlockState,
level: Level,
pos: BlockPos,
explosion: Explosion,
dropConsumer: BiConsumer<ItemStack?, BlockPos?>
) {
val interaction = explosion.blockInteraction
if (interaction == Explosion.BlockInteraction.DESTROY || interaction == Explosion.BlockInteraction.DESTROY_WITH_DECAY) {
val blockEntity = level.getBlockEntity(pos) as? PokemonPastureBlockEntity ?: return
blockEntity.onBroken()
}
super.onExplosionHit(state, level, pos, explosion, dropConsumer)
}
override fun <T : BlockEntity?> getTicker(world: Level, state: BlockState, type: BlockEntityType<T>): BlockEntityTicker<T>? {
@@ -1,17 +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.block
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.core.BlockPos
import net.minecraft.world.level.Level
interface PreEmptsExplosion {
fun whenExploded(world: Level, state: BlockState, pos: BlockPos)
}
@@ -271,15 +271,16 @@ class SaccharineLeafBlock(settings: Properties) : LeavesBlock(settings) {
player.addItem(Items.HONEY_BOTTLE.defaultInstance)
level.playSound(null, pos, SoundEvents.BOTTLE_FILL, SoundSource.BLOCKS)
level.setBlock(pos, state.setValue(AGE, 0), 2)
level.setBlock(pos, state.setValue(AGE, 0), UPDATE_CLIENTS)
level.gameEvent(null, GameEvent.BLOCK_CHANGE, pos)
return ItemInteractionResult.SUCCESS
} else if (isHoneyBottle && !isAtMaxAge(state)) {
// Decrement stack if not in creative mode
itemStack.consume(1, player)
player.addItem(Items.GLASS_BOTTLE.defaultInstance)
level.playSound(null, pos, SoundEvents.HONEY_BLOCK_PLACE, SoundSource.BLOCKS)
level.setBlock(pos, state.setValue(AGE, 2), 2)
level.setBlock(pos, state.setValue(AGE, 2), UPDATE_CLIENTS)
level.gameEvent(null, GameEvent.BLOCK_CHANGE, pos)
return ItemInteractionResult.SUCCESS
}
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.block.campfirepot
import com.cobblemon.mod.common.CobblemonMenuType
import com.cobblemon.mod.common.CobblemonRecipeBookTypes.COOKING_POT
import com.cobblemon.mod.common.CobblemonRecipeTypes
import com.cobblemon.mod.common.api.cooking.Seasonings
import com.cobblemon.mod.common.block.entity.CampfireBlockEntity
@@ -211,7 +212,7 @@ class CookingPotMenu : RecipeBookMenu<CraftingInput, CookingPotRecipeBase>, Cont
}
override fun getRecipeBookType(): RecipeBookType {
return RecipeBookType.valueOf("COOKING_POT")
return COOKING_POT
}
override fun shouldMoveToInventory(slotIndex: Int): Boolean {
@@ -111,13 +111,18 @@ class CampfireBlockEntity(pos: BlockPos, state: BlockState) : BaseContainerBlock
BlockEntitySoundTracker.stop(pos, campfireBlockEntity.ambientSound.location)
}
campfireBlockEntity.brothColor =
getColourMixFromSeasonings(campfireBlockEntity.getSeasonings())
?: BASE_BROTH_COLOR
val seasonings = campfireBlockEntity.getSeasonings()
if (seasonings.size != campfireBlockEntity.lastSeasoningStacks.size || seasonings.any { it !in campfireBlockEntity.lastSeasoningStacks }) {
campfireBlockEntity.lastSeasoningStacks = seasonings
campfireBlockEntity.bubbleColor =
getColourMixFromSeasonings(campfireBlockEntity.getSeasonings(), true)
?: BASE_BROTH_BUBBLE_COLOR
campfireBlockEntity.brothColor =
getColourMixFromSeasonings(seasonings)
?: BASE_BROTH_COLOR
campfireBlockEntity.bubbleColor =
getColourMixFromSeasonings(seasonings, true)
?: BASE_BROTH_BUBBLE_COLOR
}
if (campfireBlockEntity.particleCooldown > 0) {
campfireBlockEntity.particleCooldown--
@@ -241,6 +246,9 @@ class CampfireBlockEntity(pos: BlockPos, state: BlockState) : BaseContainerBlock
var bubbleColor: Int = BASE_BROTH_BUBBLE_COLOR
var time: Int = 0
/** Used to know if we should be changing the colour of the broth or if we can go with the previous colour. */
var lastSeasoningStacks = listOf<ItemStack>()
var dataAccess: ContainerData = object : ContainerData {
override fun get(index: Int): Int {
return when (index) {
@@ -49,7 +49,6 @@ import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.block.state.BlockState
import java.util.*
open class PokeSnackBlockEntity(pos: BlockPos, state: BlockState) :
TintBlockEntity(CobblemonBlockEntities.POKE_SNACK, pos, state),
@@ -120,7 +119,7 @@ open class PokeSnackBlockEntity(pos: BlockPos, state: BlockState) :
level.dimension(),
)
block.eat(level, blockPos, blockState, action.spawnablePosition.cause.entity as? Player)
block.eat(level, blockPos, blockState, null)
}
}
@@ -186,7 +186,7 @@ object CobblemonClient {
) { it is PokemonEntity }
nearbyPokemon?.forEach { entity ->
if (entity is PokemonEntity && !entity.isSilent) {
if (entity is PokemonEntity && !entity.isSilent && !entity.passengers.contains(player)) {
if (player.isLookingAt(entity) && !player.isSpectator && entity.pokemon.shiny) entity.delegate.spawnShinyParticle(player)
entity.delegate.spawnAspectParticle()
}
@@ -38,7 +38,7 @@ import kotlin.math.max
class RideControlsOverlay : Gui(Minecraft.getInstance()) {
companion object {
private const val FADE_FRAMES = 20F
private const val CONTROLS_FADE_FRAMES = 20F
private const val BASELINE_FPS = 60F
private const val HALF_SCALE = 0.5F
@@ -63,9 +63,9 @@ class RideControlsOverlay : Gui(Minecraft.getInstance()) {
private val screenExemptions: List<Class<out Screen>> = listOf(ChatScreen::class.java)
private var maxDurationFrames = Cobblemon.config.displayControlSeconds * BASELINE_FPS
private var durationFrames = maxDurationFrames
private var fadeFrames = FADE_FRAMES
private var controlsMaxDurationFrames = Cobblemon.config.displayControlSeconds * BASELINE_FPS
private var controlsDurationFrames = controlsMaxDurationFrames
private var controlsFadeFrames = CONTROLS_FADE_FRAMES
private var lastMouseX = 0
private var lastMouseY = 0
@@ -88,123 +88,132 @@ class RideControlsOverlay : Gui(Minecraft.getInstance()) {
if (minecraft.options.hideGui || minecraft.debugOverlay.showDebugScreen()) return
val riddenEntity = minecraft.player?.vehicle
if (riddenEntity != null && riddenEntity is PokemonEntity) {
// Update max duration if user has changed config
val configDuration = Cobblemon.config.displayControlSeconds * BASELINE_FPS
if (maxDurationFrames != configDuration) {
maxDurationFrames = configDuration
resetOverlayState()
}
// Don't render if duration config set to 0 or less
if (maxDurationFrames <= 0F) return
val rideBehaviourSettings = riddenEntity.ridingController?.context?.settings ?: return
val ridingBehaviourState = riddenEntity.ridingController?.context?.state ?: return
val rideBehaviourKey = rideBehaviourSettings.key
// Update current ride behaviour if changed
// If composite, get active behaviour instead
if (rideBehaviourKey == CompositeBehaviour.KEY) {
val activeBehaviour = (ridingBehaviourState as CompositeState).activeBehaviour.get()
if (currentBehaviourKey != activeBehaviour) {
currentBehaviourKey = activeBehaviour
resetOverlayState()
minecraft.player?.let { player ->
val riddenEntity = player.vehicle
if (riddenEntity != null && riddenEntity is PokemonEntity) {
// Only show controls to driver
if (riddenEntity === player.controlledVehicle) {
renderControls(minecraft, context, tickCounter, riddenEntity)
}
} else if (currentBehaviourKey != rideBehaviourKey) {
currentBehaviourKey = rideBehaviourKey
resetOverlayState()
} else {
resetControlsOverlayState()
}
// Render elements if entity has ride behaviour and if display duration has not ended yet
if (rideBehaviourSettings != null && fadeFrames > 0) {
val tickDelta = tickCounter.realtimeDeltaTicks.takeIf { !minecraft.isPaused } ?: 0F
val updateInterval = (tickDelta / 20F) * BASELINE_FPS
durationFrames = max(durationFrames - updateInterval, 0F)
if (durationFrames == 0F && fadeFrames > 0) fadeFrames = max(fadeFrames - updateInterval, 0F)
var showVerticalMouse = true // Show moving mouse up and down with arrows
var showHorizontalMouse = true // Show moving mouse left and right with arrows
var showSneakKey = true
var showJumpKey = true
var showMovementKeys = true
var disableHorizontalMovementKeys = false // Disable left and right movement keys
// Configure what controls to show for each behaviour
when (currentBehaviourKey) {
BirdBehaviour.KEY -> {}
BoatBehaviour.KEY -> {
showVerticalMouse = false
showHorizontalMouse = false
showSneakKey = false
}
BurstBehaviour.KEY -> {}
DolphinBehaviour.KEY -> {
disableHorizontalMovementKeys = true
showSneakKey = false
showJumpKey = false
}
GliderBehaviour.KEY -> {}
HelicopterBehaviour.KEY -> {}
HorseBehaviour.KEY -> {
showVerticalMouse = false
disableHorizontalMovementKeys = true
showSneakKey = false
}
HoverBehaviour.KEY -> {
showVerticalMouse = false
}
JetBehaviour.KEY -> {
showSneakKey = false
showJumpKey = false
}
MinekartBehaviour.KEY -> {
showVerticalMouse = false
showHorizontalMouse = false
showSneakKey = false
}
RocketBehaviour.KEY -> {
showVerticalMouse = false
showHorizontalMouse = false
}
VehicleBehaviour.KEY -> {}
}
val centerX = minecraft.window.guiScaledWidth / 2
val centerY = minecraft.window.guiScaledHeight / 2
renderMouseControls(
context,
!showMovementKeys && !showJumpKey && !showSneakKey,
showHorizontalMouse,
showVerticalMouse,
centerX,
centerY / 2,
fadeFrames / FADE_FRAMES
)
renderKeyControls(
context,
!showHorizontalMouse && !showVerticalMouse,
showMovementKeys,
disableHorizontalMovementKeys,
showJumpKey,
showSneakKey,
minecraft.player?.input,
centerX,
centerY / 2,
fadeFrames / FADE_FRAMES
)
}
} else {
resetOverlayState()
}
}
private fun resetOverlayState() {
if (durationFrames != maxDurationFrames) durationFrames = maxDurationFrames
if (fadeFrames != FADE_FRAMES) fadeFrames = FADE_FRAMES
private fun renderControls(minecraft: Minecraft, context: GuiGraphics, tickCounter: DeltaTracker, riddenEntity: PokemonEntity) {
// Update max duration if user has changed config
val configDuration = Cobblemon.config.displayControlSeconds * BASELINE_FPS
if (controlsMaxDurationFrames != configDuration) {
controlsMaxDurationFrames = configDuration
resetControlsOverlayState()
}
// Don't render if duration config set to 0 or less
if (controlsMaxDurationFrames <= 0F) return
val rideBehaviourSettings = riddenEntity.ridingController?.context?.settings ?: return
val ridingBehaviourState = riddenEntity.ridingController?.context?.state ?: return
val rideBehaviourKey = rideBehaviourSettings.key
// Update current ride behaviour if changed
// If composite, get active behaviour instead
if (rideBehaviourKey == CompositeBehaviour.KEY) {
val activeBehaviour = (ridingBehaviourState as CompositeState).activeBehaviour.get()
if (currentBehaviourKey != activeBehaviour) {
currentBehaviourKey = activeBehaviour
resetControlsOverlayState()
}
} else if (currentBehaviourKey != rideBehaviourKey) {
currentBehaviourKey = rideBehaviourKey
resetControlsOverlayState()
}
// Render elements if entity has ride behaviour and if display duration has not ended yet
if (rideBehaviourSettings != null && controlsFadeFrames > 0) {
val tickDelta = tickCounter.realtimeDeltaTicks.takeIf { !minecraft.isPaused } ?: 0F
val updateInterval = (tickDelta / 20F) * BASELINE_FPS
controlsDurationFrames = max(controlsDurationFrames - updateInterval, 0F)
if (controlsDurationFrames == 0F && controlsFadeFrames > 0) controlsFadeFrames = max(controlsFadeFrames - updateInterval, 0F)
var showVerticalMouse = true // Show moving mouse up and down with arrows
var showHorizontalMouse = true // Show moving mouse left and right with arrows
var showSneakKey = true
var showJumpKey = true
var showMovementKeys = true
var disableHorizontalMovementKeys = false // Disable left and right movement keys
// Configure what controls to show for each behaviour
when (currentBehaviourKey) {
BirdBehaviour.KEY -> {}
BoatBehaviour.KEY -> {
showVerticalMouse = false
showHorizontalMouse = false
showSneakKey = false
}
BurstBehaviour.KEY -> {}
DolphinBehaviour.KEY -> {
disableHorizontalMovementKeys = true
showSneakKey = false
showJumpKey = false
}
GliderBehaviour.KEY -> {}
HelicopterBehaviour.KEY -> {}
HorseBehaviour.KEY -> {
showVerticalMouse = false
disableHorizontalMovementKeys = true
showSneakKey = false
}
HoverBehaviour.KEY -> {
showVerticalMouse = false
}
JetBehaviour.KEY -> {
showSneakKey = false
showJumpKey = false
}
MinekartBehaviour.KEY -> {
showVerticalMouse = false
showHorizontalMouse = false
showSneakKey = false
}
RocketBehaviour.KEY -> {
showVerticalMouse = false
showHorizontalMouse = false
}
VehicleBehaviour.KEY -> {}
}
val centerX = minecraft.window.guiScaledWidth / 2
val centerY = minecraft.window.guiScaledHeight / 2
renderMouseControls(
context,
!showMovementKeys && !showJumpKey && !showSneakKey,
showHorizontalMouse,
showVerticalMouse,
centerX,
centerY / 2,
controlsFadeFrames / CONTROLS_FADE_FRAMES
)
renderKeyControls(
context,
!showHorizontalMouse && !showVerticalMouse,
showMovementKeys,
disableHorizontalMovementKeys,
showJumpKey,
showSneakKey,
minecraft.player?.input,
centerX,
centerY / 2,
controlsFadeFrames / CONTROLS_FADE_FRAMES
)
}
}
private fun resetControlsOverlayState() {
if (controlsDurationFrames != controlsMaxDurationFrames) controlsDurationFrames = controlsMaxDurationFrames
if (controlsFadeFrames != CONTROLS_FADE_FRAMES) controlsFadeFrames = CONTROLS_FADE_FRAMES
if (mouseMovedUp != null) {
mouseMovedUp = null
lastMouseY = 0
@@ -413,7 +422,7 @@ class RideControlsOverlay : Gui(Minecraft.getInstance()) {
if (showJump || showSneak) {
val offsetY = if (showMovement) 0 else -14
var label: MutableComponent? = null
var label: MutableComponent?
if (showJump && showSneak) {
label = "key.sneak".asTranslated().append("/").append("key.jump".asTranslated())
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.client.gui.pc
import com.cobblemon.mod.common.CobblemonNetwork
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.gui.getPixelRGB
import com.cobblemon.mod.common.api.storage.StorePosition
import com.cobblemon.mod.common.api.storage.party.PartyPosition
import com.cobblemon.mod.common.api.storage.pc.PCPosition
@@ -284,20 +283,6 @@ class StorageWidget(
height = 189,
alpha = if (screenLoaded) 1F else ((pcGui.ticksElapsed).toFloat() / 10F).coerceIn(0F, 1F)
)
} else {
val rgb = getPixelRGB(x + (SCREEN_WIDTH / 2), y + (SCREEN_HEIGHT / 2))
blitk(
matrixStack = matrices,
texture = screenGlowResource,
x = x - 17,
y = y - 17,
width = 208,
height = 189,
red = rgb.first / 255F,
green = rgb.second / 255F,
blue = rgb.third / 255F,
alpha = if (screenLoaded) 1F else ((pcGui.ticksElapsed).toFloat() / 10F).coerceIn(0F, 1F)
)
}
blitk(
@@ -38,6 +38,7 @@ object CobblemonKeyBinds {
val PARTY_OVERLAY_DOWN = this.queue(DownShiftPartyBinding)
val PARTY_OVERLAY_UP = this.queue(UpShiftPartyBinding)
val SEND_OUT_POKEMON = this.queue(PartySendBinding)
val RIDING_FREELOOK = this.queue(RidingFreelookBinding)
fun register(registrar: (KeyMapping) -> Unit) {
this.keyBinds.forEach(registrar::invoke)
@@ -0,0 +1,29 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.keybind.keybinds
import com.cobblemon.mod.common.client.keybind.CobblemonBlockingKeyBinding
import com.cobblemon.mod.common.client.keybind.KeybindCategories
import com.mojang.blaze3d.platform.InputConstants
object RidingFreelookBinding : CobblemonBlockingKeyBinding(
"key.cobblemon.ridingfreelook",
InputConstants.Type.MOUSE,
InputConstants.MOUSE_BUTTON_MIDDLE,
KeybindCategories.COBBLEMON_CATEGORY
) {
override fun onTick() {
}
override fun onRelease() {
}
override fun onPress() {
}
}
@@ -23,7 +23,6 @@ import com.cobblemon.mod.common.duck.CameraDuck
import com.cobblemon.mod.common.duck.RidePassenger
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.math.geometry.toRadians
import com.cobblemon.mod.common.util.toVec3d
import com.mojang.blaze3d.Blaze3D
import net.minecraft.client.Camera
import net.minecraft.client.CameraType
@@ -35,6 +34,7 @@ import net.minecraft.world.phys.HitResult
import net.minecraft.world.phys.Vec3
import org.joml.Matrix3f
import org.joml.Quaternionf
import org.joml.Vector3d
import org.joml.Vector3f
import kotlin.math.min
import kotlin.math.sign
@@ -81,7 +81,6 @@ object MountedCameraRenderer {
val currEyeHeight: Double = Mth.lerp(instance.partialTickTime.toDouble(), eyeHeight, eyeHeightOld)
var offset = Vec3(0.0, currEyeHeight - (driver.bbHeight / 2), 0.0)
var eyeOffset = Vec3(0.0, currEyeHeight - (driver.bbHeight / 2), 0.0)
val locatorOffset = Vec3(locator.matrix.getTranslation(Vector3f()))
val shouldFlip = !(vehicleController.active && vehicleController.orientation != null) // Do not flip the offset for 3rd person reverse unless we are using normal mc camera rotation.
val isFirstPerson = Minecraft.getInstance().options.cameraType == CameraType.FIRST_PERSON
@@ -103,15 +102,17 @@ object MountedCameraRenderer {
else Quaternionf()
.rotateY((Math.PI.toFloat() - Mth.lerp(instance.partialTickTime, vehicle.yRotO, vehicle.yRot).toRadians()))
offset = rotation.transform(offset.toVector3f()).toVec3d()
eyeOffset = rotation.transform(eyeOffset.toVector3f()).toVec3d()
offset = rotation.transform(Vector3d(offset.x, offset.y, offset.z)).let { Vec3(it.x, it.y, it.z) }
eyeOffset = rotation.transform(Vector3d(eyeOffset.x, eyeOffset.y, eyeOffset.z)).let { Vec3(it.x, it.y, it.z) }
val eyePos = locatorOffset.add(entityPos)
val eyeLocatorOffset = Vec3(locator.matrix.getTranslation(Vector3f()))
val eyePos = eyeLocatorOffset.add(entityPos)
// Get the camera position before offsets are applied (which are done with maxZoom to account for clipping). If 3rd person viewbobbing is enabled or the player is
// in first person then base the camera position off the seat locator offset
val pos = /* if (isFirstPerson || Cobblemon.config.thirdPersonViewBobbing) { */
locatorOffset.add(entityPos)
Vec3(locator.matrix.getTranslation(Vector3f()))
.add(entityPos)
/* } else {
val pokemonCenter = Vector3f(0f, driver.bbHeight/2, 0f)
@@ -326,7 +327,7 @@ object MountedCameraRenderer {
locatorName: String,
shouldFlip: Boolean = true
): Vec3 {
var offset = if (thirdPersonReverse && cameraOffsets.containsKey(locatorName + "_reverse")) {
val offset = if (thirdPersonReverse && cameraOffsets.containsKey(locatorName + "_reverse")) {
cameraOffsets[locatorName + "_reverse"]!!
} else if (cameraOffsets.containsKey(locatorName)) {
cameraOffsets[locatorName]!!
@@ -336,8 +337,7 @@ object MountedCameraRenderer {
// Don't need to account for this since orientation is derived from camera rotation and that z is already flipped.
// Flip only when not on a rollable.
if (thirdPersonReverse && shouldFlip) offset = offset.multiply(1.0, 1.0, -1.0)
return offset
return if (thirdPersonReverse && shouldFlip) offset.multiply(1.0, 1.0, -1.0) else offset
}
private fun getFirstPersonOffset(model: PosableModel, locatorName: String): Vec3 {
@@ -344,6 +344,9 @@ class CobblemonConfig {
@CobblemonConfigField(Category.Spawning, lang = "despawner_max_age_ticks", SERVER)
var despawnerMaxAgeTicks = 3600
@CobblemonConfigField(Category.World, lang = "mob_experience_conversion_rate", SERVER)
var mobExperienceConversionRate = 50.0
fun clone(): CobblemonConfig {
val newConfig = CobblemonConfig()
CobblemonConfig::class.memberProperties.forEach { property ->
@@ -186,7 +186,7 @@ class OmniPathNavigation(val world: Level, val entity: Mob) : GroundPathNavigati
val blockState = this.world.getBlockState(target)
val path = if (!blockState.isSolid
|| (blockState.`is`(BlockTags.LEAVES) && blockState.block == CobblemonBlocks.SACCHARINE_LEAVES && (this.entity as PokemonEntity).canPathThroughSaccLeaves())) {
|| (blockState.`is`(BlockTags.LEAVES) && blockState.block == CobblemonBlocks.SACCHARINE_LEAVES && pather.canPathThroughSaccLeaves())) {
findPath(target, distance)
} else {
blockPos = target.above()
@@ -269,7 +269,7 @@ class OmniPathNavigation(val world: Level, val entity: Mob) : GroundPathNavigati
// If we can fly and we're airborne, return the current Y position
return vec.y
}
if (world.getBlockState(blockPos).block == CobblemonBlocks.SACCHARINE_LEAVES && (this.entity as PokemonEntity).canPathThroughSaccLeaves()) {
if (world.getBlockState(blockPos).block == CobblemonBlocks.SACCHARINE_LEAVES && pather.canPathThroughSaccLeaves()) {
return vec.y + 0.5
}
return if ((canFloat()) && blockGetter.getFluidState(blockPos).`is`(FluidTags.WATER)) vec.y + 0.5 else super.getGroundY(vec)
@@ -38,6 +38,7 @@ import com.cobblemon.mod.common.api.net.serializers.PoseTypeDataSerializer
import com.cobblemon.mod.common.api.net.serializers.RideBoostsDataSerializer
import com.cobblemon.mod.common.api.net.serializers.StringSetDataSerializer
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.api.pokemon.experience.MobExperienceSource
import com.cobblemon.mod.common.api.pokemon.feature.ChoiceSpeciesFeatureProvider
import com.cobblemon.mod.common.api.pokemon.feature.FlagSpeciesFeature
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
@@ -1259,7 +1260,18 @@ open class PokemonEntity(
override fun doHurtTarget(target: Entity): Boolean {
if (beamMode != 0) return false
return super.doHurtTarget(target)
val result = super.doHurtTarget(target)
if (result && !target.isAlive && target is LivingEntity && !level().isClientSide) {
val experience = target.getExperienceReward(level() as ServerLevel, this)
val source = MobExperienceSource(mob = target)
if (this.owner is ServerPlayer) {
pokemon.addExperienceWithPlayer(this.owner as ServerPlayer, source, (experience * Cobblemon.config.mobExperienceConversionRate).toInt())
}
else {
pokemon.addExperience(source, (experience * Cobblemon.config.mobExperienceConversionRate).toInt())
}
}
return result
}
override fun hurt(source: DamageSource, amount: Float): Boolean {
@@ -52,8 +52,9 @@ object PlaceHoneyInHiveTask {
if (blockEntity.isFull) {
// Erase Hive memory and give the bee a moment to locate a new hive
entity.brain.eraseMemory(CobblemonMemories.HIVE_LOCATION)
} else {
blockEntity.addOccupant(entity)
}
blockEntity.addOccupant(entity)
}
return@Trigger true
@@ -8,17 +8,24 @@
package com.cobblemon.mod.common.item.interactive
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.pokemon.interaction.ExperienceCandyUseEvent
import com.cobblemon.mod.common.api.item.PokemonSelectingItem
import com.cobblemon.mod.common.api.pokemon.experience.CandyExperienceSource
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.item.CobblemonItem
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.server.level.ServerPlayer
import net.minecraft.sounds.SoundEvents
import net.minecraft.world.InteractionHand
import net.minecraft.world.InteractionResult
import net.minecraft.world.InteractionResultHolder
import net.minecraft.world.entity.ExperienceOrb
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.food.FoodProperties
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Rarity
import net.minecraft.world.level.Level
@@ -34,22 +41,59 @@ import net.minecraft.world.level.Level
*/
class CandyItem(
val item_rarity: Rarity,
val calculator: Calculator
val expYield: (ServerPlayer, Pokemon?) -> Int
) : CobblemonItem(Properties().apply {
rarity(item_rarity)
}), PokemonSelectingItem {
food(FoodProperties.Builder()
.alwaysEdible()
.nutrition(0)
.saturationModifier(0.0f)
.build())
}) {
override val bagItem = null
override fun finishUsingItem(stack: ItemStack, level: Level, livingEntity: LivingEntity): ItemStack? {
if (livingEntity !is Player) return super.finishUsingItem(stack, level, livingEntity)
override fun use(world: Level, user: Player, hand: InteractionHand): InteractionResultHolder<ItemStack> {
if (user is ServerPlayer) {
return use(user, user.getItemInHand(hand))
/* Didn't find a good way to determine the XP needed until the beginning of the next level.
* This works but is a little jank. Feel free to investigate a better solution.
*/
if (level.isClientSide && this == CobblemonItems.RARE_CANDY) {
val volume = if (livingEntity.experienceLevel > 30) 1.0f else livingEntity.experienceLevel.toFloat() / 30.0f
livingEntity.playSound(SoundEvents.PLAYER_LEVELUP, volume * 0.75f, 1.0f)
}
return InteractionResultHolder.success(user.getItemInHand(hand))
if (livingEntity !is ServerPlayer) return super.finishUsingItem(stack, level, livingEntity)
if (this == CobblemonItems.RARE_CANDY) {
livingEntity.setExperienceLevels(livingEntity.experienceLevel + 1)
livingEntity.setExperiencePoints(0)
}
else {
val expYield = expYield(livingEntity, null)
val playerExperience = (expYield / Cobblemon.config.mobExperienceConversionRate).toInt().coerceAtLeast(1)
ExperienceOrb.award(livingEntity.serverLevel(), livingEntity.position(), playerExperience)
}
return super.finishUsingItem(stack, level, livingEntity)
}
override fun applyToPokemon(player: ServerPlayer, stack: ItemStack, pokemon: Pokemon): InteractionResultHolder<ItemStack>? {
val experience = this.calculator.calculate(player, pokemon)
override fun interactLivingEntity(
stack: ItemStack,
player: Player,
interactionTarget: LivingEntity,
usedHand: InteractionHand
): InteractionResult {
if (player.level().isClientSide) return InteractionResult.FAIL
if (player.isCrouching) return InteractionResult.FAIL
if (interactionTarget !is PokemonEntity) return InteractionResult.PASS
if (interactionTarget.pokemon.getOwnerPlayer() != player) return InteractionResult.PASS
return applyToPokemon(player as ServerPlayer, stack, interactionTarget.pokemon)?.result ?: InteractionResult.FAIL
}
fun applyToPokemon(player: ServerPlayer, stack: ItemStack, pokemon: Pokemon): InteractionResultHolder<ItemStack>? {
if (!pokemon.canLevelUpFurther()) {
return InteractionResultHolder.fail(stack)
}
val experience = expYield(player, pokemon)
CobblemonEvents.EXPERIENCE_CANDY_USE_PRE.postThen(
event = ExperienceCandyUseEvent.Pre(player, pokemon, this, experience, experience),
ifSucceeded = { preEvent ->
@@ -74,29 +118,6 @@ class CandyItem(
return InteractionResultHolder.fail(stack)
}
override fun canUseOnPokemon(stack: ItemStack, pokemon: Pokemon): Boolean {
return pokemon.isPlayerOwned()
}
/**
* Functional interface responsible for resolving the experience a candy will yield.
*
* @author Licious
* @since March 5th, 2022
*/
fun interface Calculator {
/**
* Resolves the experience the [CandyItem] will give.
*
* @param player The [ServerPlayer] using the candy.
* @param pokemon The [Pokemon] receiving experience.
* @return The experience that will be received
*/
fun calculate(player: ServerPlayer, pokemon: Pokemon): Int
}
companion object {
const val DEFAULT_XS_CANDY_YIELD = 100
const val DEFAULT_S_CANDY_YIELD = 800
@@ -23,7 +23,6 @@ import net.minecraft.world.level.Level
class PonigiriItem : Item(
Properties().stacksTo(64)
.food(FoodProperties.Builder()
.alwaysEdible()
.nutrition(2)
.saturationModifier(0.55f)
.build())
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.pokemon
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.CobblemonNetwork.sendPacketToPlayers
import com.cobblemon.mod.common.CobblemonSounds
@@ -148,6 +149,7 @@ import net.minecraft.util.Mth.ceil
import net.minecraft.util.Mth.clamp
import net.minecraft.util.StringRepresentable
import net.minecraft.world.InteractionHand
import net.minecraft.world.entity.ExperienceOrb
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.MobSpawnType
import net.minecraft.world.entity.player.Player
@@ -2016,6 +2018,12 @@ open class Pokemon : ShowdownIdentifiable {
}
)
val player = getOwnerPlayer()
if (player != null && player.inventory.getArmor(3).item == CobblemonItems.EXP_SHARE) {
val playerExperience = (appliedXP / Cobblemon.config.mobExperienceConversionRate * Cobblemon.config.experienceShareMultiplier).toInt().coerceAtLeast(1)
ExperienceOrb.award(player.serverLevel(), player.position(), playerExperience)
}
experience += appliedXP
// Bound is needed here as we can still be allowed to level up but go over the current cap
var newLevel = experienceGroup.getLevel(experience).coerceAtMost(Cobblemon.config.maxPokemonLevel)
@@ -5,6 +5,10 @@
{
"aspects": ["female"],
"model": "cobblemon:combee_female.geo"
},
{
"aspects": ["shiny", "female"],
"texture": "cobblemon:textures/pokemon/0415_combee/combee_shiny.png"
}
]
}
@@ -2041,6 +2041,7 @@
"key.cobblemon.pokenavigator": "Open PokéNav",
"key.cobblemon.summary": "Open Summary",
"key.cobblemon.pokedex": "Open Pokédex",
"key.cobblemon.ridingfreelook": "Riding Freelook",
"key.cobblemon.categories.cobblemon": "Cobblemon",
"key.cobblemon.scaleportraitup": "Scale Portrait Up",
@@ -2620,6 +2621,8 @@
"cobblemon.config.ui.infinite_ride_stamina.tooltip": "Whether rideable Pokémon have infinite stamina.",
"cobblemon.config.ui.remember_riding_camera": "Remember Riding Camera",
"cobblemon.config.ui.remember_riding_camera.tooltip": "Whether the camera mode will automatically switch to the last used camera mode when mounting a rideable Pokémon.",
"cobblemon.config.ui.mob_experience_conversion_rate": "Mob Experience Conversion Rate",
"cobblemon.config.ui.mob_experience_conversion_rate.tooltip": "The conversion rate for mob experience to pokemon experience when a Pokemon kills a mob.",
"cobblemon.config.ui.allow_starter_on_join": "Allow Starter on Join",
"cobblemon.config.ui.prompt_starter_once_only": "Prompt Starter Once Only",
@@ -3589,7 +3592,8 @@
"tag.item.cobblemon.small_flowers": "Small Flowers",
"tag.item.cobblemon.held.blacklisted_items_to_hold": "Blacklisted Held Items",
"tag.item.cobblemon.held.whitelisted_items_to_hold": "Whitelisted Held Items",
"tag.item.cobblemon.recipe_filters.poke_puff_seasoner": "Poké Puff Berries",
"tag.item.cobblemon.recipe_filters.poke_puff_seasoning": "Poké Puff Seasoning Items",
"tag.item.cobblemon.recipe_filters.tea_seasoning": "Tea Seasoning Items",
"tag.item.cobblemon.recipe_filters.bait_seasoning": "Baits",
"tag.item.cobblemon.recipe_filters.effect_seasoning": "Effect Seasoning Items",
"tag.item.cobblemon.recipe_filters.nutrition_seasoning": "Nutrition Seasoning Items",
@@ -6165,7 +6165,7 @@
"cobblemon.command.freezepokemon.non_pokemon": "Vous ne pointez pas un Pokémon.",
"advancements.cobblemon.craft_rod": "Équipé pour pécho !",
"advancements.cobblemon.use_bait.description": "Utiliser une baie avec la Poké Rod",
"advancements.cobblemon.craft_master_rod": "Dévouement magistral",
"advancements.cobblemon.craft_master_rod": "Cela affectera la population de Barbicha",
"cobblemon.battle.resisted_spread": "Ça n'est pas très efficace sur %1$s.",
"cobblemon.battle.superEffective_spread": "C'est super efficace sur %1$s !",
"cobblemon.battle.crit_spread": "Coup critique infligé à %1$s !",
@@ -8773,7 +8773,7 @@
"cobblemon.config.ui.despawner_max_age_ticks": "Âge maximum (Ticks)",
"cobblemon.config.ui.despawner_max_age_ticks.tooltip": "L'âge (en ticks de jeu) qu'un Pokémon doit atteindre avant de pouvoir disparaître à petite distance.",
"advancements.cobblemon.resurrect_galar_fossil": "N'arrêtez jamais d'apprendre",
"advancements.cobblemon.resurrect_galar_fossil.description": "Ressuscitez un Pokémon fossile créé à partir d'un Fossile Oiseau ou Fossile Poisson et d'un Fossile Dragon ou Fossile Aileron",
"advancements.cobblemon.resurrect_galar_fossil.description": "Ressuscitez un Pokémon fossile créé à partir d’un Fossile Oiseau ou Poisson et d’un Fossile Dragon ou Aileron",
"advancements.cobblemon.ride_pokemon": "Monteur de Pokémon !",
"advancements.cobblemon.ride_pokemon.description": "Montez sur un Pokémon pour la première fois",
"cobblemon.battle.sidestart.ally.auroraveil": "Voile Aurore augmente la résistance des Pokémon de l'équipe aux capacités physiques et spéciales !",
@@ -9088,7 +9088,7 @@
"cobblemon.config.ui.summary_profile_animations.animate_selected.tooltip": "Animer le Pokémon sélectionné à moins d'être K.O.",
"tag.item.cobblemon.berries.status_recovery": "Baies de récupération de statut",
"cobblemon.behaviour.configurable_resource_identifier.desc": "Permet de modifier l'identifiant de ressource qui contrôle l'apparence du PNJ.",
"item.cobblemon.moomoo_milk.tooltip": "Efface tous les changements de stats du Pokémon cible lorsqu'il est utilisé au combat.",
"item.cobblemon.moomoo_milk.tooltip": "Efface tous les changements de stats du Pokémon cible lorsqu'il est utilisé au combat",
"cobblemon.config.ui.poke_snack_pokemon_per_chunk": "Poké Snack Pokémon par tronçon",
"cobblemon.config.ui.animate_battle_tiles": "Animer les tuiles de combat",
"cobblemon.config.ui.pc_profile_animations.never_animate": "Ne jamais animer",
@@ -9104,5 +9104,35 @@
"cobblemon.entity.variable.display_name_tag.name": "Afficher l'étiquette",
"cobblemon.entity.variable.display_name_tag.desc": "Permet d'afficher ou masquer l'étiquette de l'entité.",
"cobblemon.behaviour.dialogue_selection.name": "Sélection du dialogue",
"cobblemon.behaviour.dialogue_selection.desc": "Permet de configurer l'interaction avec le PNJ afin d'ouvrir un dialogue spécifique."
"cobblemon.behaviour.dialogue_selection.desc": "Permet de configurer l'interaction avec le PNJ afin d'ouvrir un dialogue spécifique.",
"cobblemon.fishing_bait_effects.drops_reroll.tooltip": "%1$s%% - %3$s× Relance Des Butins",
"cobblemon.requires_debug_keys": "Les touches de débogage doivent être activées sur le serveur pour utiliser cette fonctionnalité.",
"cobblemon.requires_permission": "Vous n’avez pas l’autorisation requise pour effectuer cette action.",
"cobblemon.ui.stats.blocks_traveled": "Pas",
"item.cobblemon.eggant_berry.tooltip": "Le porteur est soigné s’il est amoureux",
"cobblemon.config.ui.default_key_items.tooltip": "Les objets rares que les joueurs obtiennent par défaut au début.",
"cobblemon.config.ui.default_key_items": "Objets Rares Par Défaut",
"advancements.cobblemon.cook_all_regional_delicacies": "Paul Bocuse",
"advancements.cobblemon.cook_all_regional_delicacies.description": "Cuisinez chaque Spécialité Régionale",
"advancements.cobblemon.cook_all_ev_mochi": "Mochi Mochi !",
"advancements.cobblemon.cook_all_ev_mochi.description": "Cuisinez chaque parfum de mochi, une délicieuse friandise capable de modifier les Points d’Effort d’un Pokémon",
"advancements.cobblemon.cook_snack": "Sentez-Moi Ça !",
"advancements.cobblemon.cook_snack.description": "Préparez un Poké Snack, un délicieux gâteau capable d’attirer certains Pokémon selon les Baies utilisées",
"advancements.cobblemon.use_poke_bait": "Souvenirs D'Enfance",
"advancements.cobblemon.use_poke_bait.description": "Préparez un Poké Appât personnalisé dans une Marmite de Feu de Camp et utilisez-le pour ferrer un Pokémon",
"advancements.cobblemon.max_ride_stats": "Poké-Athlète, Médaille D'Or",
"advancements.cobblemon.max_ride_stats.description": "Maximisez les cinq statistiques de monture d’un Pokémon en lui donnant du Jus d’Abriko aromatisé\nDifférents profils de saveurs augmentent différentes statistiques",
"advancements.cobblemon.interact_with_pokemon": "Le Bonheur À Portée De Main",
"advancements.cobblemon.interact_with_pokemon.description": "Utilisez l’un de vos nombreux outils pour obtenir des ressources de votre Pokémon",
"advancements.cobblemon.slather_saccharine": "Juste Une Lichette",
"advancements.cobblemon.slather_saccharine.description": "Étalez un pot de miel sur le tronc d’un arbre Saccharine pour attirer l’apparition de certains Pokémon",
"gamerule.healersHealPC": "Soigne les Pokémon du PC lors de l’utilisation d’une Machine de Soin",
"tag.item.cobblemon.berries.colour.white": "Baies Blanches",
"tag.item.cobblemon.berries.colour.brown": "Baies Marrons",
"tag.item.cobblemon.berries.colour.red": "Baies Rouges",
"tag.item.cobblemon.berries.colour.orange": "Baies Oranges",
"tag.item.cobblemon.berries.colour.yellow": "Baies Jaunes",
"tag.item.cobblemon.berries.colour.lime": "Baies Vert Clair",
"tag.item.cobblemon.berries.colour.green": "Baies Vertes",
"tag.item.cobblemon.berries.colour.cyan": "Baies Cyan"
}
@@ -6270,7 +6270,7 @@
"cobblemon.ui.pc.search": "検索",
"cobblemon.ui.wallpapers": "壁紙",
"cobblemon.ui.interact.ride": "騎乗",
"cobblemon.ui.interact.give.cosmetic_item": "コスメティックアイテムの変更",
"cobblemon.ui.interact.give.cosmetic_item": "衣装アイテムの変更",
"item.cobblemon.syrupy_apple.tooltip": "とにかく 蜜入りの 不思議なりんご。カジッチュに使うと カミッチュに進化する。",
"cobblemon.fishing.no_bite": "釣れないなぁ……",
"cobblemon.ui.interact.request_already_expired": "そのリクエストはすでに期限切れです!",
@@ -7778,7 +7778,7 @@
"cobblemon.move.gmaxtartness.desc": "キョダイマックスした アップリューが 繰りだす くさタイプの 攻撃。 相手の 回避率を 下げる。",
"cobblemon.species.basculin-white.desc": "極寒の 海で 群れを 作り エサを 分け合って 暮らす。 時が 来ると 生まれた 川に 帰る。",
"cobblemon.species.landorus-therian.desc": "霊獣の姿にて 天翔けしとき 大地に 豊穣もたらす。 衆人 これを 敬う。 一刻あれば ヒスイの地を 縦断す。",
"cobblemon.ui.pokedex.info.form.greninja-bond": " ",
"cobblemon.ui.pokedex.info.form.greninja-bond": "きずなへんげ",
"cobblemon.species.vivillon-polar.desc": "生まれた 土地の 気候や 風土の 影響により 模様が 変わる。 降雪の 多い 土地の 姿。",
"cobblemon.species.vivillon-archipelago.desc": "生まれた 土地の 気候や 風土の 影響により 模様が 変わる。 島が 群れ成す 土地の 姿。",
"cobblemon.species.furfrou-diamond.desc": "ボサボサの 体毛を 刈りこむと 姿が 美しくなる だけでなく 身体の キレが 良くなるのだ。",
@@ -7921,7 +7921,7 @@
"cobblemon.species.arceus-ice.desc": "アルセウスの持つ つららのプレートには 文字が 刻まれている。 「そのもの じかん くうかんの 2ひき ぶんしんとして よに はなつ」",
"cobblemon.ui.pokedex.info.form.arceus-dragon": "アルセウスのすがた",
"cobblemon.ui.pokedex.info.form.arceus-dark": "アルセウスのすがた",
"cobblemon.species.arceus-dark.desc": "アルセウスの持つ りゅうのプレートには 文字が 刻まれている。 「そのもの じかん くうかんを つなぐ 3びきの ポケモンをも うみだす」",
"cobblemon.species.arceus-dark.desc": "アルセウスの持つ こわもてプレートには 文字が 刻まれている。 「2ひきに もの 3びきに こころ いのり うませ せかい かたちづくる」",
"cobblemon.ui.pokedex.info.form.arceus-fairy": "アルセウスのすがた",
"cobblemon.ui.pokedex.info.form.oshawott": " ",
"cobblemon.ui.pokedex.info.form.dewott": " ",
@@ -8068,8 +8068,8 @@
"cobblemon.ui.pokedex.info.form.zygarde": "50%フォルム",
"cobblemon.ui.pokedex.info.form.zygarde-10": "10%フォルム",
"cobblemon.species.zygarde-10.desc": "鋭い キバで 敵を 仕留める。 ずっと この身体を 維持 できず 一定時間で バラバラになる。",
"cobblemon.ui.pokedex.info.form.zygarde-10c": "10%フォルム",
"cobblemon.ui.pokedex.info.form.zygarde-50c": "50%フォルム",
"cobblemon.ui.pokedex.info.form.zygarde-10c": "10%(スワームチェンジ)",
"cobblemon.ui.pokedex.info.form.zygarde-50c": "50%(スワームチェンジ)",
"cobblemon.species.zygarde-50c.desc": "生態系を 脅かす ものと 戦うとき 更に 強力な 姿に 変化すると いわれる。",
"cobblemon.ui.pokedex.info.form.zygarde-complete": "パーフェクトフォルム",
"cobblemon.species.zygarde-complete.desc": "生態系を 脅かす者を 圧倒的な 力を 以て 制圧する ジガルデの 姿。",
@@ -8084,7 +8084,7 @@
"cobblemon.species.oricorio-pau.desc": "うすもものミツを 吸った オドリドリ。 踊っている ときは トレーナーの 指示が 聞こえないほど マイペース。",
"cobblemon.ui.pokedex.info.form.oricorio-sensu": "まいまいスタイル",
"cobblemon.ui.pokedex.info.form.rockruff": " ",
"cobblemon.ui.pokedex.info.form.rockruff-dusk": " ",
"cobblemon.ui.pokedex.info.form.rockruff-dusk": "マイペース",
"cobblemon.ui.pokedex.info.form.lycanroc": "まひるのすがた",
"cobblemon.ui.pokedex.info.form.lycanroc-midnight": "まよなかのすがた",
"cobblemon.species.lycanroc-midnight.desc": "気に入らない 命令は 平気で 無視。 相手を 仕留めるためなら 傷つくことも まるで 気にしない。",
@@ -8959,5 +8959,74 @@
"entity.cobblemon.chest_boat": "チェスト付きのボート",
"entity.cobblemon.npc": "NPC",
"entity.cobblemon.empty_pokeball": "空のモンスターボール",
"cobblemon.battle.activate.insomnia": "このポケモンは ふみんのため 眠ることができない!"
"cobblemon.battle.activate.insomnia": "このポケモンは ふみんのため 眠ることができない!",
"cobblemon.battle.sideend.ally.auroraveil": "味方の オーロラベールが なくなった!",
"cobblemon.battle.sideend.ally.toxicspikes": "味方の足元から どくびしが 消えた!",
"cobblemon.battle.sideend.opponent.auroraveil": "相手の オーロラベールが なくなった!",
"cobblemon.battle.sideend.opponent.lightscreen": "相手の ひかりのかべが なくなった!",
"cobblemon.battle.sideend.opponent.mist": "相手の しろいきりが なくなった!",
"cobblemon.battle.sideend.opponent.reflect": "相手の リフレクターが なくなった!",
"cobblemon.battle.block.aromaveil": "%1$sは アロマベールで 守られている!",
"cobblemon.battle.error.incorrect_actor_count": "現在の参加者は %1$s人だが %2%s人の参加者が 必要な ようだ",
"cobblemon.battle.error.no_party": "%1$sは バトルに出すための 手持ちのポケモンを 持っていないようだ",
"cobblemon.battle.enditem.focusband": "%1$sは きあいのハチマキで 持ちこたえた!",
"cobblemon.battle.enditem.focussash": "%1$sは きあいのタスキで 持ちこたえた!",
"cobblemon.battle.enditem.ejectpack": "%1$sは だっしゅつパックで 戻っていく!",
"cobblemon.battle.enditem.occaberry": "%1$sへの ダメージを オッカのみが 弱めた!",
"cobblemon.battle.enditem.passhoberry": "%1$sへの ダメージを イトケのみが 弱めた!",
"cobblemon.battle.enditem.chopleberry": "%1$sへの ダメージを ヨプのみが 弱めた!",
"cobblemon.battle.enditem.kebiaberry": "%1$sへの ダメージを ビアーのみが 弱めた!",
"cobblemon.battle.enditem.shucaberry": "%1$sへの ダメージを シュカのみが 弱めた!",
"cobblemon.battle.enditem.cobaberry": "%1$sへの ダメージを バコウのみが 弱めた!",
"cobblemon.battle.enditem.payapaberry": "%1$sへの ダメージを ウタンのみが 弱めた!",
"cobblemon.battle.enditem.chartiberry": "%1$sへの ダメージを ヨロギのみが 弱めた!",
"cobblemon.battle.enditem.kasibberry": "%1$sへの ダメージを カシブのみが 弱めた!",
"cobblemon.battle.enditem.habanberry": "%1$sへの ダメージを ハバンのみが 弱めた!",
"cobblemon.battle.enditem.babiriberry": "%1$sへの ダメージを リリバのみが 弱めた!",
"cobblemon.battle.enditem.chilanberry": "%1$sへの ダメージを ホズのみが 弱めた!",
"cobblemon.battle.formechange.default.temporary.ended": "%1$sは 元の姿に 戻った!",
"cobblemon.battle.formechange.mega": "%1$sが キーストーンに 共鳴した!",
"cobblemon.battle.formechange.ash": "%1$sは サトシゲッコウガに きずなへんげした!",
"cobblemon.battle.formechange.school": "%1$sは むれたすがたに なった!",
"cobblemon.battle.withdraw.other": "%1$sは %2$sを 引っ込めた!",
"cobblemon.battle.sideend.ally.lightscreen": "味方の ひかりのかべが なくなった!",
"cobblemon.battle.sideend.ally.reflect": "味方の リフレクターが なくなった!",
"cobblemon.battle.sideend.ally.spikes": "味方の足元から まきびしが 消えた!",
"cobblemon.battle.sideend.ally.safeguard": "味方の 神秘のベールが なくなった!",
"cobblemon.battle.sideend.opponent.stickyweb": "相手の足元から ねばねばネットが なくなった!",
"cobblemon.battle.enditem.wacanberry": "%1$sへの ダメージを ソクノのみが 弱めた!",
"cobblemon.battle.enditem.rindoberry": "%1$sへの ダメージを リンドのみが 弱めた!",
"cobblemon.battle.enditem.yacheberry": "%1$sへの ダメージを ヤチェのみが 弱めた!",
"cobblemon.battle.heal.bagitemrevive": "%1$sは ひんしから 回復した!",
"cobblemon.battle.heal.bagitemfullrestore": "%1$sの 体力が 回復した!",
"cobblemon.battle.formechange.minior": "%1$sの リミットシールド 発動!",
"cobblemon.battle.switch.other": "%1$s は %2$sを 繰り出した!",
"cobblemon.battle.enditem.tangaberry": "%1$sへの ダメージを タンガのみが 弱めた!",
"cobblemon.battle.withdraw.self": "%1$s、戻れ!",
"cobblemon.battle.sideend.opponent.luckychant": "相手の おまじないが 切れた!",
"cobblemon.battle.block.sweetveil": "%1$sは スイートベールで 眠れない!",
"cobblemon.battle.enditem.colburberry": "%1$sへの ダメージを ナモのみが 弱めた!",
"cobblemon.battle.enditem.roseliberry": "%1$sへの ダメージを ロゼルのみが 弱めた!",
"cobblemon.battle.formechange.wishiwashi": "%1$sの群れは どこかに行ってしまった...",
"cobblemon.battle.switch.other.nickname": "%1$s は %2$s (%3$s)を 繰り出した!",
"cobblemon.battle.sideend.ally.tailwind": "味方の おいかぜが 切れた!",
"cobblemon.battle.sideend.opponent.safeguard": "相手の 神秘のベールが なくなった!",
"cobblemon.battle.sideend.ally.stealthrock": "味方の足元から とがった岩が 消えた!",
"cobblemon.battle.sideend.ally.stickyweb": "味方の足元から ねばねばネットが なくなった!",
"cobblemon.battle.sideend.ally.luckychant": "味方の おまじないが 切れた!",
"cobblemon.battle.sideend.ally.mist": "味方の しろいきりが なくなった!",
"cobblemon.battle.sideend.opponent.tailwind": "相手の おいかぜが 切れた!",
"cobblemon.battle.sideend.opponent.spikes": "相手の足元から まきびしが なくなった!",
"cobblemon.battle.sideend.opponent.toxicspikes": "相手の足元から どくびしが なくなった!",
"cobblemon.battle.cant.nopp": "%1$sは %2$sを使うための PPが 足りない!",
"cobblemon.battle.end.neutralizinggas": "かがくへんかガスが なくなった!",
"cobblemon.battle.ability.replace": "%1$sは 特性が %2$sに変わった!",
"cobblemon.battle.formechange.default.temporary": "%1$s は %2$sフォルムに なった!",
"cobblemon.battle.formechange.default.permanent": "%1$s は %2$sに フォルムチェンジした!",
"cobblemon.battle.formechange.meteor": "%1$sの リミットシールド 解除!",
"cobblemon.battle.switch.self": "いけ! %1$s!",
"cobblemon.fishing_bait_effects.drops_reroll.tooltip": "%1$s%% - %3$s× ドロップ品リロール",
"cobblemon.requires_debug_keys": "この機能を使用するには、サーバーでデバッグキーを有効にする必要があります。",
"cobblemon.requires_permission": "この操作を行うには必要な権限がありません。",
"cobblemon.ui.stats.blocks_traveled": "ステップ"
}
File diff suppressed because it is too large Load Diff
@@ -511,7 +511,7 @@
"cobblemon.ui.starter.hasalreadychosen": "%1$s já escolheu um iniciante.",
"cobblemon.ui.starter.skippedchoosing": "Você ainda não escolheu um iniciante, mas já recebeu um Pokémon. Para selecionar seu inciante, coloque todos seus Pokémon em um PC e pressione \"%1$s\".",
"cobblemon.ui.starter.choose_starter_title": "Escolha o seu inicial!",
"cobblemon.ui.starter.choose_starter_description": "Pressiona a tecla \"%1$s\"",
"cobblemon.ui.starter.choose_starter_description": "Pressione a tecla \"%1$s\"",
"cobblemon.ui.starter.chooseyourstarter": "Pressione %1$s para escolher seu Pokémon e começar sua jornada!",
"cobblemon.ui.moves": "Ataques",
"cobblemon.ui.moves.switch": "Trocar Ataque",
@@ -5906,7 +5906,7 @@
"advancements.cobblemon.craft_rod.description": "使用宝可梦钓竿锻造模版制作一个宝可梦钓竿",
"advancements.cobblemon.use_bait": "非常好树果,使我线轮旋转",
"advancements.cobblemon.craft_master_rod.description": "使用大师球制作一个宝可梦钓竿",
"advancements.cobblemon.craft_master_rod": "慷慨带不来好运",
"advancements.cobblemon.craft_master_rod": "这将影响鲶鱼王的数量",
"advancements.cobblemon.craft_rod": "器渔轩昂",
"advancements.cobblemon.use_bait.description": "让你的宝可梦钓竿挂上一个树果诱饵",
"cobblemon.battle.center": "自动居中!",
@@ -8607,7 +8607,7 @@
"item.cobblemon.swift_mochi.tooltip": "提升宝可梦的速度基础点数4点",
"item.cobblemon.fresh_start_mochi": "净空粘糕",
"item.cobblemon.fresh_start_mochi.tooltip": "将宝可梦的全部基础点数清空",
"item.cobblemon.poke_bait": "宝可梦诱饵",
"item.cobblemon.poke_bait": "宝诱饵",
"item.cobblemon.aprijuice_blue": "蓝球果汁",
"item.cobblemon.aprijuice_green": "绿球果汁",
"item.cobblemon.aprijuice_pink": "粉球果汁",
@@ -8751,7 +8751,7 @@
"cobblemon.config.ui.maximum_spawning_zone_distance_from_player.tooltip": "宝可梦生成时,距玩家所需的最大方块数。",
"cobblemon.config.ui.maximum_spawns_per_pass": "单次生成最大数量",
"cobblemon.config.ui.despawner_far_distance.tooltip": "以玩家为中心的最大距离范围。在此范围之外,且存在时间超过最小活动时间的宝可梦会被系统移除。",
"advancements.cobblemon.resurrect_galar_fossil.description": "复活一只由化石鸟或化石鱼以及化石海兽或化石龙组成的宝可梦",
"advancements.cobblemon.resurrect_galar_fossil.description": "复活一只由化石鸟或化石鱼和化石海兽或化石龙组成的宝可梦",
"cobblemon.battle.sidestart.ally.auroraveil": "极光幕使我方的物理和特殊抗性提高了!",
"cobblemon.battle.sidestart.ally.safeguard": "我方被神秘之幕包围了!",
"cobblemon.battle.sidestart.opponent.auroraveil": "极光幕使对手的物理和特殊抗性提高了!",
@@ -9050,7 +9050,7 @@
"cobblemon.snapshots.warning.dont_show_again": "不再显示",
"cobblemon.snapshots.warning.dont_show_again_tip": "在较新的 方块宝可梦 快照中(例如 1.7.0 与 1.8.0),此设置可能会被忽略",
"key.cobblemon.toggleridingstatsgui": "切换骑乘能力界面",
"item.cobblemon.moomoo_milk.tooltip": "在战斗中使用时,会清除目标的能力变化。",
"item.cobblemon.moomoo_milk.tooltip": "在战斗中使用时,会清除目标的能力变化",
"cobblemon.config.ui.poke_snack_pokemon_per_chunk": "每个区块的宝点心宝可梦数量",
"cobblemon.config.ui.poke_snack_pokemon_per_chunk.tooltip": "通过宝点心生成时,区块中允许的宝可梦数量。",
"cobblemon.config.ui.summary_profile_animations.animate_selected.tooltip": "选中的宝可梦播放动画,除非已昏厥",
@@ -9105,5 +9105,25 @@
"cobblemon.seasoning_ride_boosts_info_header": "骑乘属性提升:",
"item.cobblemon.eggant_berry": "子茄果",
"cobblemon.entity.variable.look_at_entity_types.desc": "该实体将看向的实体类型。",
"cobblemon.entity.variable.look_at_entity_types.name": "看向实体类型"
"cobblemon.entity.variable.look_at_entity_types.name": "看向实体类型",
"cobblemon.fishing_bait_effects.drops_reroll.tooltip": "%1$s%% - %3$s× 额外掉落",
"cobblemon.requires_debug_keys": "必须在服务器上启用调试键才能使用此功能。",
"cobblemon.ui.stats.blocks_traveled": "步数",
"cobblemon.requires_permission": "你没有执行此操作的权限。",
"cobblemon.config.ui.default_key_items": "默认关键道具",
"cobblemon.config.ui.default_key_items.tooltip": "玩家默认拥有的关键道具。",
"advancements.cobblemon.cook_all_regional_delicacies": "世界美食之旅",
"item.cobblemon.eggant_berry.tooltip": "解除着迷状态",
"advancements.cobblemon.cook_all_regional_delicacies.description": "烹饪每种地区美食",
"advancements.cobblemon.cook_all_ev_mochi": "咭呗咭呗!",
"advancements.cobblemon.use_poke_bait.description": "在营火锅中准备一个自制的宝可梦诱饵,并使用它钓到一只宝可梦",
"advancements.cobblemon.max_ride_stats": "明星宝可竞技选手",
"advancements.cobblemon.max_ride_stats.description": "通过喂食不同风味的球果汁,将宝可梦宝可梦的五项坐骑能力提升至最高\n不同风味的球果汁会提升不同的能力",
"advancements.cobblemon.slather_saccharine": "只是一小口",
"advancements.cobblemon.cook_all_ev_mochi.description": "制作每一种口味的粘糕,这种美味点心可以影响宝可梦的基础点数",
"advancements.cobblemon.cook_snack": "诱人的香味",
"advancements.cobblemon.cook_snack.description": "烘焙一个宝点心,一种美味的蛋糕,可以根据使用的树果吸引特定的宝可梦",
"advancements.cobblemon.use_poke_bait": "那是诱饵",
"advancements.cobblemon.interact_with_pokemon": "牧场上的家",
"advancements.cobblemon.interact_with_pokemon.description": "使用你众多工具的一个,从你的宝可梦那里获取资源"
}
@@ -6433,7 +6433,7 @@
"item.cobblemon.smooth_rock.tooltip": "攜帶後,刮起沙暴的話,沙暴的時間就會比平常更長",
"item.cobblemon.icy_rock.tooltip": "攜帶後,將天氣變為下雪的話,下雪的時間就會比平常更長",
"item.cobblemon.energy_root.tooltip": "使一隻寶可夢回復80HP,同時降低它的親密度",
"item.cobblemon.revival_herb.tooltip": "使一隻昏厥的寶可夢回復全部HP,同時降低它的親密度",
"item.cobblemon.revival_herb.tooltip": "使一隻昏厥的寶可夢回復最大HP的25%,同時降低它的親密度",
"item.cobblemon.remedy.tooltip": "使一隻寶可夢回復20HP,同時小幅降低它的親密度",
"item.cobblemon.fine_remedy.tooltip": "使一隻寶可夢回復60HP,同時小幅降低它的親密度",
"item.cobblemon.superb_remedy.tooltip": "使一隻寶可夢回復120HP,同時小幅降低它的親密度",
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

@@ -1,20 +1,25 @@
{
"display": {
"icon": {
"id": "minecraft:shears"
},
"icon": {
"id": "minecraft:shears"
},
"title": {
"translate": "advancements.cobblemon.interact_with_pokemon"
},
"description": {
"translate": "advancements.cobblemon.interact_with_pokemon.description"
},
"hidden": false
"hidden": false
},
"parent": "cobblemon:use_pasture",
"criteria": {
"bucket_interactable_pokemon": {
"conditions": {
"player": {
"flags": {
"is_sneaking": false
}
},
"entity": [
{
"condition": "minecraft:entity_properties",
@@ -32,6 +37,11 @@
},
"shear_interactable_pokemon": {
"conditions": {
"player": {
"flags": {
"is_sneaking": false
}
},
"entity": [
{
"condition": "minecraft:entity_properties",
@@ -49,6 +59,11 @@
},
"bottle_interactable_pokemon": {
"conditions": {
"player": {
"flags": {
"is_sneaking": false
}
},
"entity": [
{
"condition": "minecraft:entity_properties",
@@ -66,6 +81,11 @@
},
"brush_interactable_pokemon": {
"conditions": {
"player": {
"flags": {
"is_sneaking": false
}
},
"entity": [
{
"condition": "minecraft:entity_properties",
@@ -83,6 +103,11 @@
},
"bonemeal_interactable_pokemon": {
"conditions": {
"player": {
"flags": {
"is_sneaking": false
}
},
"entity": [
{
"condition": "minecraft:entity_properties",
@@ -100,6 +125,11 @@
},
"bowl_interactable_pokemon": {
"conditions": {
"player": {
"flags": {
"is_sneaking": false
}
},
"entity": [
{
"condition": "minecraft:entity_properties",
@@ -116,6 +146,15 @@
"trigger": "minecraft:player_interacted_with_entity"
}
},
"requirements": [[ "bucket_interactable_pokemon", "shear_interactable_pokemon", "bottle_interactable_pokemon", "brush_interactable_pokemon", "bonemeal_interactable_pokemon", "bowl_interactable_pokemon" ]],
"requirements": [
[
"bucket_interactable_pokemon",
"shear_interactable_pokemon",
"bottle_interactable_pokemon",
"brush_interactable_pokemon",
"bonemeal_interactable_pokemon",
"bowl_interactable_pokemon"
]
],
"sends_telemetry_event": false
}
@@ -27,7 +27,7 @@
{
"type": "cobblemon:activity_change",
"activity": "minecraft:idle",
"condition": "q.entity.lacks_memory_value('cobblemon:has_nectar', 'cobblemon:nearby_flower') || (q.entity.has_memory_value('cobblemon:has_nectar') && (q.entity.lacks_memory_value('cobblemon:nearby_sacc_leaves', 'cobblemon:hive_location'))) || q.entity.has_memory_value('cobblemon:hive_cooldown')"
"condition": "q.entity.lacks_memory_value('cobblemon:has_nectar', 'cobblemon:nearby_flower') || (q.entity.has_memory_value('cobblemon:has_nectar') && (q.entity.lacks_memory_value('cobblemon:nearby_sacc_leaves', 'cobblemon:hive_location'))) || q.entity.has_memory_value('cobblemon:hive_cooldown') || ((q.entity.biome.is_in('#minecraft:is_overworld') && ((q.entity.world.time_of_day >= 13000 && q.entity.world.time_of_day <= 23000) || q.entity.world.is_raining)) && (q.entity.lacks_memory_value('cobblemon:hive_location')))"
},
{
"type": "cobblemon:activity_change",
@@ -62,7 +62,7 @@
{
"type": "cobblemon:activity_change",
"activity": "cobblemon:pokemon_pollination",
"condition": "(q.entity.has_memory_value('cobblemon:nearby_sacc_leaves') || q.entity.has_memory_value('cobblemon:hive_location')) && !q.entity.has_memory_value('cobblemon:hive_cooldown')"
"condition": "((q.entity.has_memory_value('cobblemon:nearby_sacc_leaves') || q.entity.has_memory_value('cobblemon:hive_location')) && !q.entity.has_memory_value('cobblemon:hive_cooldown'))"
}
],
"1": [
@@ -1,5 +1,5 @@
{
"pokemon": ["braixien", "delphox"],
"pokemon": ["braixen", "delphox"],
"cosmeticItems": [
{
"consumedItem": "cobblemon:silk_scarf",
@@ -5,7 +5,7 @@ q.entity.has_memory_value('cobblemon:hive_location') ? {
t.wander_control.set_path_cooldown_ticks(50);
};
q.entity.lacks_memory_value('cobblemon:hive_location') && q.entity.has_memory_value('cobblemon:nearby_sacc_leaves') ? {
t.position = q.entity.get_position_memory('cobblemon:hive_location');
t.position = q.entity.get_position_memory('cobblemon:nearby_sacc_leaves');
t.wander_control = q.entity.get_wander_control_memory();
t.wander_control.set_center(t.position.x, t.position.y, t.position.z, 2, 32);
t.wander_control.set_path_cooldown_ticks(50);
@@ -0,0 +1,12 @@
{
"type": "cobblemon:brewing_stand",
"input": {
"item": "cobblemon:petaya_berry"
},
"bottle": {
"item": "cobblemon:potion"
},
"result": {
"id": "cobblemon:throat_spray"
}
}
@@ -2,9 +2,14 @@
"type": "cobblemon:cooking_pot_shapeless",
"category": "medicines",
"ingredients": [
{
[
{
"item": "minecraft:glass_bottle"
},
{
"item": "minecraft:potion"
},
}
],
{
"item": "cobblemon:medicinal_leek"
}
@@ -1,17 +0,0 @@
{
"type": "cobblemon:cooking_pot_shapeless",
"category": "medicines",
"ingredients": [
{
"item": "minecraft:glass_bottle"
},
{
"item": "cobblemon:medicinal_leek"
}
],
"result": {
"id": "cobblemon:medicinal_brew"
},
"seasoningTag": "cobblemon:empty",
"seasoningProcessors": []
}
@@ -10,7 +10,7 @@
"item": "cobblemon:green_mint_leaf"
},
"C": {
"tag": "c:concrete"
"tag": "c:concretes"
},
"D": {
"tag": "c:gems/diamond"
@@ -10,7 +10,7 @@
"item": "cobblemon:pink_mint_leaf"
},
"C": {
"tag": "c:concrete"
"tag": "c:concretes"
},
"D": {
"tag": "c:gems/diamond"
@@ -10,7 +10,7 @@
"item": "cobblemon:blue_mint_leaf"
},
"C": {
"tag": "c:concrete"
"tag": "c:concretes"
},
"D": {
"tag": "c:gems/diamond"
@@ -10,7 +10,7 @@
"item": "cobblemon:red_mint_leaf"
},
"C": {
"tag": "c:concrete"
"tag": "c:concretes"
},
"D": {
"tag": "c:gems/diamond"
@@ -10,7 +10,7 @@
"item": "cobblemon:cyan_mint_leaf"
},
"C": {
"tag": "c:concrete"
"tag": "c:concretes"
},
"D": {
"tag": "c:gems/diamond"
@@ -10,7 +10,7 @@
"item": "cobblemon:white_mint_leaf"
},
"C": {
"tag": "c:concrete"
"tag": "c:concretes"
},
"D": {
"tag": "c:gems/diamond"
@@ -1,4 +1,5 @@
{
"implemented": true,
"nationalPokedexNumber": 676,
"name": "Furfrou",
"primaryType": "normal",
@@ -5,6 +5,6 @@
"#cobblemon:recipe_filters/effect_seasoning",
"#cobblemon:recipe_filters/flavour_seasoning",
"#cobblemon:recipe_filters/nutrition_seasoning",
"#cobblemon:recipe_filters/poke_puff_seasoner"
"#cobblemon:recipe_filters/poke_puff_seasoning"
]
}
@@ -35,7 +35,6 @@
"client.MouseHandlerMixin",
"client.OptionsMixin",
"client.PlayerRendererMixin",
"client.RecipeBookCategoriesMixin",
"client.RecipeBookComponentMixin",
"client.RecipeBookTabButtonMixin",
"client.RecipeCollectionMixin",
@@ -60,7 +59,6 @@
"EntitySkeletonMixin",
"EntityStorageMixin",
"EntityVillagerMixin",
"ExplosionMixin",
"ItemStackComponentizationFixMixin",
"LecternBlockMixin",
"LightningBoltMixin",
@@ -74,8 +72,6 @@
"PlayerMixin",
"PointedDripstoneBlockMixin",
"PowderSnowBlockMixin",
"RecipeBookSettingsMixin",
"RecipeBookTypeMixin",
"ServerEntityMixin",
"ServerLevelMixin",
"ServerPlayerMixin",
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,21 @@
# Entity Types Tags
This file contains tags related to different types of entities in cobblemon.
## Tags:
<details>
<summary><b>Tag:</b> #cobblemon:boats</summary>
- cobblemon:boat
- cobblemon:chest_boat
</details>
<details>
<summary><b>Tag:</b> #cobblemon:cannot_have_name_tag</summary>
- cobblemon:empty_pokeball
- cobblemon:pokemon
</details>
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,180 @@
# Spawn Presets
This file contains all current spawn presets of cobblemon.
[[_TOC_]]
# Spawn Preset List
## ancient_city
| Key | Conditions | Anticonditions |
| --- | ---------- | -------------- |
| **maxY** | `62` | |
| **neededNearbyBlocks** | `#cobblemon:ancient_city_blocks` | |
| **structures** | `minecraft:ancient_city` | |
## derelict
| Key | Conditions | Anticonditions |
| --- | ---------- | -------------- |
| **canSeeSky** | `False` | |
| **maxLight** | `0` | |
| **neededBaseBlocks** | | `#cobblemon:natural` |
## desert_pyramid
| Key | Conditions | Anticonditions |
| --- | ---------- | -------------- |
| **minY** | `62` | |
| **neededBaseBlocks** | | `minecraft:blue_terracotta`; `minecraft:orange_terracotta` |
| **neededNearbyBlocks** | `#cobblemon:desert_pyramid_blocks` | |
| **structures** | `minecraft:desert_pyramid` | |
## end_city
| Key | Conditions | Anticonditions |
| --- | ---------- | -------------- |
| **neededBaseBlocks** | `minecraft:end_stone_bricks`; `minecraft:purpur_block`; `minecraft:purpur_pillar` | |
| **neededNearbyBlocks** | `#cobblemon:end_city_blocks` | |
| **structures** | `minecraft:end_city` | |
## foliage
| Key | Conditions | Anticonditions |
| --- | ---------- | -------------- |
| **neededNearbyBlocks** | `#minecraft:leaves`; `#c:leaves` | |
## illager_structures
| Key | Conditions | Anticonditions |
| --- | ---------- | -------------- |
| **minY** | `62` | |
| **structures** | `minecraft:pillager_outpost`; `minecraft:swamp_hut`; `minecraft:mansion` | |
## jungle_pyramid
| Key | Conditions | Anticonditions |
| --- | ---------- | -------------- |
| **minY** | `62` | |
| **neededBaseBlocks** | `minecraft:cobblestone`; `#minecraft:mossy_cobblestone` | |
| **neededNearbyBlocks** | `#cobblemon:jungle_pyramid_blocks` | |
| **structures** | `minecraft:jungle_pyramid` | |
## lava
| Key | Conditions | Anticonditions |
| --- | ---------- | -------------- |
| **fluid** | `#minecraft:lava` | |
## mansion
| Key | Conditions | Anticonditions |
| --- | ---------- | -------------- |
| **minY** | `62` | |
| **neededBaseBlocks** | `minecraft:birch_planks`; `minecraft:double_smooth_stone_slab`; `minecraft:oak_planks`; `minecraft:polished_andesite`; `#minecraft:wool`; `#minecraft:wool_carpets` | |
| **neededNearbyBlocks** | `#cobblemon:mansion_blocks` | |
| **structures** | `minecraft:mansion` | |
## mansion_dining
| Key | Conditions | Anticonditions |
| --- | ---------- | -------------- |
| **minY** | `62` | |
| **neededBaseBlocks** | `minecraft:birch_planks`; `minecraft:double_smooth_stone_slab`; `minecraft:oak_planks`; `minecraft:polished_andesite`; `#minecraft:wool`; `#minecraft:wool_carpets` | |
| **neededNearbyBlocks** | `minecraft:light_grey_carpet`; `minecraft:magenta_carpet`; `minecraft:white_carpet` | |
| **structures** | `minecraft:woodland_mansion/1x1_b2`; `minecraft:woodland_mansion/1x2_c1`; `minecraft:woodland_mansion/2x2_b1`; `minecraft:woodland_mansion/2x2_b2` | |
## natural
| Key | Conditions | Anticonditions |
| --- | ---------- | -------------- |
| **neededBaseBlocks** | `#cobblemon:natural` | `minecraft:farmland` |
## nether_fossil
| Key | Conditions | Anticonditions |
| --- | ---------- | -------------- |
| **neededNearbyBlocks** | `minecraft:bone_block` | |
| **structures** | `minecraft:nether_fossil` | |
## nether_structures
| Key | Conditions | Anticonditions |
| --- | ---------- | -------------- |
| **neededBaseBlocks** | `minecraft:chiseled_polished_blackstone`; `minecraft:cracked_polished_blackstone_bricks`; `minecraft:gilded_blackstone`; `minecraft:nether_bricks`; `minecraft:polished_basalt`; `minecraft:polished_blackstone_bricks` | |
| **neededNearbyBlocks** | `#cobblemon:nether_structure_blocks` | |
| **structures** | `minecraft:bastion_remnant`; `minecraft:fortress` | |
## ocean_monument
| Key | Conditions | Anticonditions |
| --- | ---------- | -------------- |
| **maxY** | `62` | |
| **structures** | `minecraft:monument` | |
## ocean_ruins
| Key | Conditions | Anticonditions |
| --- | ---------- | -------------- |
| **maxY** | `62` | |
| **neededNearbyBlocks** | `#cobblemon:ocean_ruin_blocks` | |
| **structures** | `#minecraft:ocean_ruin` | |
## pillager_outpost
| Key | Conditions | Anticonditions |
| --- | ---------- | -------------- |
| **minY** | `62` | |
| **neededNearbyBlocks** | `#cobblemon:pillager_outpost_blocks` | |
| **structures** | `minecraft:pillager_outpost` | |
## redstone
| Key | Conditions | Anticonditions |
| --- | ---------- | -------------- |
| **neededBaseBlocks** | | `#cobblemon:redstone_blocks` |
| **neededNearbyBlocks** | `#minecraft:redstone_ores`; `#cobblemon:redstone_blocks`; `#c:redstone_ores` | |
## ruined_portal
| Key | Conditions | Anticonditions |
| --- | ---------- | -------------- |
| **neededNearbyBlocks** | `ruined_portal_blocks` | |
| **structures** | `#minecraft:ruined_portal` | |
## saccharine_tree
| Key | Conditions | Anticonditions |
| --- | ---------- | -------------- |
| **neededNearbyBlocks** | `cobblemon:saccharine_leaves`; `cobblemon:saccharine_log`; `cobblemon:saccharine_wood`; `cobblemon:stripped_saccharine_log`; `cobblemon:stripped_saccharine_wood` | |
## salt
| Key | Conditions | Anticonditions |
| --- | ---------- | -------------- |
| **biomes** | `biomesoplenty:hot_springs`; `biomesoplenty:wasteland`; `biomesoplenty:wasteland_steppe`; `terralith:amethyst_canyon`; `terralith:amethyst_rainforest`; `terralith:skylands_winter`; `terralith:yellowstone`; `wythers:calcite_caverns`; `wythers:calcite_coast`; `wythers:mediterranean_island_thermal_spring`; `wythers:salt_lakes_pink`; `wythers:salt_lakes_turquoise`; `wythers:salt_lakes_white`; `wythers:thermal_taiga` | |
## stronghold
| Key | Conditions | Anticonditions |
| --- | ---------- | -------------- |
| **maxY** | `62` | |
| **neededBaseBlocks** | `#minecraft:stone_bricks` | |
| **neededNearbyBlocks** | `minecraft:cracked_stone_bricks`; `minecraft:mossy_stone_bricks` | |
| **structures** | `minecraft:stronghold` | |
## trail_ruins
| Key | Conditions | Anticonditions |
| --- | ---------- | -------------- |
| **minY** | `32` | |
| **neededBaseBlocks** | `#minecraft:convertable_to_mud`; `#minecraft:sand`; `#minecraft:trail_ruins_replaceable`; `#cobblemon:trail_ruins_blocks`; `minecraft:cobblestone`; `minecraft:stone`; `minecraft:stone_bricks` | |
| **neededNearbyBlocks** | `#cobblemon:trail_ruins_blocks` | |
| **structures** | `minecraft:trail_ruins` | |
## treetop
| Key | Conditions | Anticonditions |
| --- | ---------- | -------------- |
| **neededBaseBlocks** | `#cobblemon:trees` | |
## urban
| Key | Conditions | Anticonditions |
| --- | ---------- | -------------- |
| **neededNearbyBlocks** | `#cobblemon:concrete_blocks` | |
| **structures** | | `#minecraft:village`; `minecraft:trail_ruins` |
## water
| Key | Conditions | Anticonditions |
| --- | ---------- | -------------- |
| **fluid** | `#minecraft:water` | |
## webs
| Key | Conditions | Anticonditions |
| --- | ---------- | -------------- |
| **biomes** | `biomesoplenty:spider_nest`; `terralith:cave/infested_caves`; `wythers:forbidden_forest`; `wythers:phantasmal_forest`; `wythers:phantasmal_swamp` | |
## wild
| Key | Conditions | Anticonditions |
| --- | ---------- | -------------- |
| **neededNearbyBlocks** | | `#cobblemon:concrete_blocks` |
| **structures** | | `#minecraft:village` |
+1 -2
View File
@@ -6,8 +6,7 @@ PC box wallpapers have two sides, one on client and an optional one on server.
This involves adding the texture PNG file to the `assets/cobblemon/textures/gui/pc/wallpaper/` directory. The mod will trawl
this directory on asset load and form a base list. The client will send this list to the server to validate
the list, with the server returning a list of valid wallpapers. The client will then display the wallpapers in the GUI.
The emissive screen glow will be automatically generated using colour of the center pixel of the provided wallpaper.
For a custom screen glow, place the file in the `assets/cobblemon/textures/gui/pc/wallpaper/*/glow` directory with the same file name as the wallpaper.
The emissive screen glow is an optional asset. To add one, place the file in the `assets/cobblemon/textures/gui/pc/wallpaper/*/glow` directory with the same file name as the wallpaper.
An optional, alternate wallpaper can also be provided. This should be similar to the main wallpaper as it will share the custom glow if one is provided. This alternate wallpaper will be shown, replacing the main wallpaper, when holding the Shift key while the wallpaper selection list is open in the PC interface. To add an alternate wallpaper, place the file in the `assets/cobblemon/textures/gui/pc/wallpaper/*/alt` directory with the same file name as the main wallpaper.
@@ -6,10 +6,11 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.client;
package com.cobblemon.mod.fabric.mixin;
import com.cobblemon.mod.common.CobblemonItems;
import com.cobblemon.mod.common.CobblemonRecipeBookTypes;
import com.cobblemon.mod.common.CobblemonRecipeCategories;
import com.google.common.collect.ImmutableList;
import net.minecraft.client.RecipeBookCategories;
@@ -49,17 +50,19 @@ public class RecipeBookCategoriesMixin {
)
private static void cobblemon$addRecipeBookType(CallbackInfo ci) {
ArrayList<RecipeBookCategories> types = new ArrayList<>(List.of($VALUES));
types.add(cobblemon$createCategory("COOKING_POT_SEARCH", $VALUES.length, new ItemStack(Items.COMPASS)));
types.add(cobblemon$createCategory("COOKING_POT_FOODS", $VALUES.length + 1, new ItemStack(CobblemonItems.LEEK_AND_POTATO_STEW)));
types.add(cobblemon$createCategory("COOKING_POT_MEDICINES", $VALUES.length + 2, new ItemStack(CobblemonItems.POTION)));
types.add(cobblemon$createCategory("COOKING_POT_COMPLEX_DISHES", $VALUES.length + 3, new ItemStack(CobblemonItems.APRIJUICE_RED)));
types.add(cobblemon$createCategory("COOKING_POT_MISC", $VALUES.length + 4, new ItemStack(CobblemonItems.PROTEIN)));
// if you change or add any of these, neoforge uses a separate mechanism
// check enumextensions.json and `CobblemonEnumExtensions`
types.add(cobblemon$createCategory("COBBLEMON_COOKING_POT_SEARCH", $VALUES.length, new ItemStack(Items.COMPASS)));
types.add(cobblemon$createCategory("COBBLEMON_COOKING_POT_FOODS", $VALUES.length + 1, new ItemStack(CobblemonItems.LEEK_AND_POTATO_STEW)));
types.add(cobblemon$createCategory("COBBLEMON_COOKING_POT_MEDICINES", $VALUES.length + 2, new ItemStack(CobblemonItems.POTION)));
types.add(cobblemon$createCategory("COBBLEMON_COOKING_POT_COMPLEX_DISHES", $VALUES.length + 3, new ItemStack(CobblemonItems.APRIJUICE_RED)));
types.add(cobblemon$createCategory("COBBLEMON_COOKING_POT_MISC", $VALUES.length + 4, new ItemStack(CobblemonItems.PROTEIN)));
$VALUES = types.toArray(RecipeBookCategories[]::new);
}
@Inject(method = "getCategories", at = @At("HEAD"), cancellable = true)
private static void modifyCategories(RecipeBookType recipeBookType, CallbackInfoReturnable<List<RecipeBookCategories>> cir) {
if (recipeBookType == RecipeBookType.valueOf("COOKING_POT")) {
if (recipeBookType == CobblemonRecipeBookTypes.INSTANCE.getCOOKING_POT()) {
List var10000 = ImmutableList.of(
CobblemonRecipeCategories.COOKING_POT_SEARCH.toVanillaCategory(),
CobblemonRecipeCategories.COOKING_POT_FOODS.toVanillaCategory(),
@@ -8,25 +8,42 @@
package com.cobblemon.mod.fabric.mixin;
import com.cobblemon.mod.common.CobblemonRecipeBookTypes;
import net.minecraft.stats.RecipeBookSettings;
import net.minecraft.world.inventory.RecipeBookType;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Arrays;
import java.util.Map;
@Mixin(RecipeBookSettings.class)
public class RecipeBookSettingsMixin {
@Shadow
@Final
public Map<RecipeBookType, RecipeBookSettings.TypeSettings> states;
@Inject(method = "<init>(Ljava/util/Map;)V", at = @At("TAIL"))
private void cobblemon$init(CallbackInfo ci) {
// if you change or add any of these, neoforge uses a separate mechanism
// check enumextensions.json and `CobblemonEnumExtensions`
states.put(CobblemonRecipeBookTypes.INSTANCE.getCOOKING_POT(), new RecipeBookSettings.TypeSettings(true, true));
}
// this fixes a disconnect issue with vanilla servers where the network sync relies on the enum we modify in a common mixin to be the same on both sides
@Redirect( method = "read(Lnet/minecraft/network/FriendlyByteBuf;)Lnet/minecraft/stats/RecipeBookSettings;", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/inventory/RecipeBookType;values()[Lnet/minecraft/world/inventory/RecipeBookType;"))
private static RecipeBookType[] cobblemon$valuesReadRedirect() {
return Arrays.stream(RecipeBookType.values()).filter( recipeBookType -> !RecipeBookType.valueOf("COOKING_POT").equals(recipeBookType) ).toArray(RecipeBookType[]::new);
return Arrays.stream(RecipeBookType.values()).filter( recipeBookType -> !CobblemonRecipeBookTypes.INSTANCE.getCOOKING_POT().equals(recipeBookType) ).toArray(RecipeBookType[]::new);
}
@Redirect( method = "write(Lnet/minecraft/network/FriendlyByteBuf;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/inventory/RecipeBookType;values()[Lnet/minecraft/world/inventory/RecipeBookType;"))
private RecipeBookType[] cobblemon$valuesWriteRedirect() {
return Arrays.stream(RecipeBookType.values()).filter( recipeBookType -> !RecipeBookType.valueOf("COOKING_POT").equals(recipeBookType) ).toArray(RecipeBookType[]::new);
return Arrays.stream(RecipeBookType.values()).filter( recipeBookType -> !CobblemonRecipeBookTypes.INSTANCE.getCOOKING_POT().equals(recipeBookType) ).toArray(RecipeBookType[]::new);
}
}
@@ -6,8 +6,9 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
package com.cobblemon.mod.fabric.mixin;
import com.cobblemon.mod.common.CobblemonRecipeBookTypes;
import net.minecraft.world.inventory.RecipeBookType;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
@@ -40,7 +41,9 @@ public class RecipeBookTypeMixin {
)
private static void cobblemon$addRecipeBookType(CallbackInfo ci) {
ArrayList<RecipeBookType> types = new ArrayList<>(List.of($VALUES));
types.add(cobblemon$createBookType("COOKING_POT", $VALUES.length));
// if you change or add any of these, neoforge uses a separate mechanism
// check enumextensions.json and `CobblemonEnumExtensions`
types.add(cobblemon$createBookType(CobblemonRecipeBookTypes.COOKING_POT_NAME, $VALUES.length));
$VALUES = types.toArray(RecipeBookType[]::new);
}
}
@@ -8,6 +8,7 @@
"FabricCameraMixin",
"GameRendererMixin",
"GuiMixin",
"RecipeBookCategoriesMixin",
"pokeball.ModelLoaderMixin"
],
"mixins": [
@@ -15,6 +16,7 @@
"FabricBrewingStandMenuMixin",
"FabricSoundEngineMixin",
"PlayerMixin",
"RecipeBookSettingsMixin"
"RecipeBookSettingsMixin",
"RecipeBookTypeMixin"
]
}
@@ -0,0 +1,38 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.neoforge
import com.cobblemon.mod.common.CobblemonItems
import net.minecraft.client.RecipeBookCategories
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.neoforged.fml.common.asm.enumextension.EnumProxy
import java.util.List
import java.util.function.Supplier
// to learn more about this, read https://docs.neoforged.net/docs/1.21.1/advanced/extensibleenums/#iextensibleenum
// this is the preferred way instead of mixining in ourselves, as it preserves mod compatibility
object CobblemonEnumExtensions {
@JvmField
val COOKING_POT_SEARCH = EnumProxy(RecipeBookCategories::class.java,
Supplier<List<ItemStack>> { listOf(ItemStack(Items.COMPASS)) as List<ItemStack> })
@JvmField
val COOKING_POT_FOODS = EnumProxy(RecipeBookCategories::class.java,
Supplier<List<ItemStack>> { listOf(ItemStack(CobblemonItems.LEEK_AND_POTATO_STEW)) as List<ItemStack> })
@JvmField
val COOKING_POT_MEDICINES = EnumProxy(RecipeBookCategories::class.java,
Supplier<List<ItemStack>> { listOf(ItemStack(CobblemonItems.POTION)) as List<ItemStack> })
@JvmField
val COOKING_POT_COMPLEX_DISHES = EnumProxy(RecipeBookCategories::class.java,
Supplier<List<ItemStack>> { listOf(ItemStack(CobblemonItems.APRIJUICE_RED)) as List<ItemStack> })
@JvmField
val COOKING_POT_MISC = EnumProxy(RecipeBookCategories::class.java,
Supplier<List<ItemStack>> { listOf(ItemStack(CobblemonItems.PROTEIN)) as List<ItemStack> })
}
@@ -9,6 +9,11 @@
package com.cobblemon.mod.neoforge
import com.cobblemon.mod.common.*
import com.cobblemon.mod.common.CobblemonRecipeCategories.COOKING_POT_COMPLEX_DISHES
import com.cobblemon.mod.common.CobblemonRecipeCategories.COOKING_POT_FOODS
import com.cobblemon.mod.common.CobblemonRecipeCategories.COOKING_POT_MEDICINES
import com.cobblemon.mod.common.CobblemonRecipeCategories.COOKING_POT_MISC
import com.cobblemon.mod.common.CobblemonRecipeCategories.COOKING_POT_SEARCH
import com.cobblemon.mod.common.advancement.CobblemonCriteria
import com.cobblemon.mod.common.advancement.predicate.CobblemonEntitySubPredicates
import com.cobblemon.mod.common.api.net.serializers.IdentifierDataSerializer
@@ -74,6 +79,7 @@ import net.neoforged.fml.ModList
import net.neoforged.fml.common.Mod
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent
import net.neoforged.fml.loading.FMLEnvironment
import net.neoforged.neoforge.client.event.RegisterRecipeBookCategoriesEvent
import net.neoforged.neoforge.common.ItemAbilities
import net.neoforged.neoforge.common.NeoForge
import net.neoforged.neoforge.common.NeoForgeMod
@@ -118,6 +124,7 @@ class CobblemonNeoForge : CobblemonImplementation {
addListener(networkManager::registerMessages)
addListener(EventPriority.HIGH, ::onBuildContents)
addListener(::onAddPackFindersEvent)
addListener(::loadRecipeCategory)
}
with(NeoForge.EVENT_BUS) {
addListener(::onDataPackSync)
@@ -479,6 +486,19 @@ class CobblemonNeoForge : CobblemonImplementation {
}
}
private fun loadRecipeCategory(e: RegisterRecipeBookCategoriesEvent) {
e.registerBookCategories(CobblemonRecipeBookTypes.COOKING_POT, listOf(
COOKING_POT_SEARCH.toVanillaCategory(),
COOKING_POT_FOODS.toVanillaCategory(),
COOKING_POT_MISC.toVanillaCategory(),
COOKING_POT_MEDICINES.toVanillaCategory(),
COOKING_POT_COMPLEX_DISHES.toVanillaCategory()
))
CobblemonRecipeCategories.customAggregateCategories.forEach { bookType ->
e.registerAggregateCategory(bookType.key, bookType.value)
}
}
private fun onLootTableLoad(e: LootTableLoadEvent) {
LootInjector.attemptInjection(e.name) { builder -> e.table.addPool(builder.build()) }
}
@@ -0,0 +1,55 @@
{
"entries": [
{
"enum": "net/minecraft/world/inventory/RecipeBookType",
"name": "COBBLEMON_COOKING_POT",
"constructor": "()V",
"parameters": []
},
{
"enum": "net/minecraft/client/RecipeBookCategories",
"name": "COBBLEMON_COOKING_POT_SEARCH",
"constructor": "(Ljava/util/function/Supplier;)V",
"parameters": {
"class": "com/cobblemon/mod/neoforge/CobblemonEnumExtensions",
"field": "COOKING_POT_SEARCH"
}
},
{
"enum": "net/minecraft/client/RecipeBookCategories",
"name": "COBBLEMON_COOKING_POT_FOODS",
"constructor": "(Ljava/util/function/Supplier;)V",
"parameters": {
"class": "com/cobblemon/mod/neoforge/CobblemonEnumExtensions",
"field": "COOKING_POT_FOODS"
}
},
{
"enum": "net/minecraft/client/RecipeBookCategories",
"name": "COBBLEMON_COOKING_POT_MEDICINES",
"constructor": "(Ljava/util/function/Supplier;)V",
"parameters": {
"class": "com/cobblemon/mod/neoforge/CobblemonEnumExtensions",
"field": "COOKING_POT_MEDICINES"
}
},
{
"enum": "net/minecraft/client/RecipeBookCategories",
"name": "COBBLEMON_COOKING_POT_COMPLEX_DISHES",
"constructor": "(Ljava/util/function/Supplier;)V",
"parameters": {
"class": "com/cobblemon/mod/neoforge/CobblemonEnumExtensions",
"field": "COOKING_POT_COMPLEX_DISHES"
}
},
{
"enum": "net/minecraft/client/RecipeBookCategories",
"name": "COBBLEMON_COOKING_POT_MISC",
"constructor": "(Ljava/util/function/Supplier;)V",
"parameters": {
"class": "com/cobblemon/mod/neoforge/CobblemonEnumExtensions",
"field": "COOKING_POT_MISC"
}
}
]
}
@@ -14,7 +14,7 @@ authors="The Cobblemon Team"
description='''
Adds Pokémon to the world, letting you find, battle, capture, and evolve them.
'''
enumExtensions="META-INF/enumextensions.json"
# A URL for the "homepage" for this mod, displayed in the mod UI
#displayURL="https://change.me.to.your.mods.homepage.example.invalid/" #optional
# A URL to query for updates for this mod. See the JSON update specification https://mcforge.readthedocs.io/en/latest/gettingstarted/autoupdate/