diff --git a/PALAMOD_CDC.md b/PALAMOD_CDC.md index 5c07d6d..f8651d3 100644 --- a/PALAMOD_CDC.md +++ b/PALAMOD_CDC.md @@ -706,6 +706,10 @@ avant M4 (TODO:crafts-machines). absente (table vanilla/enclume//enchant). TODO:M-enchants partiel (bottler, overwhelmed, unclaim, anti-chute infaisable serveur, fake-water sans degats). VERIFIE : build SUCCESSFUL, boot Done (datapack accepte), 0 erreur. UNVERIFIED en jeu. +- M-enchants-2 LIVRE 2026-10-19 ~06:55 : Experience Bottler (datapack + redirection XP + minage vers fiole CUSTOM_DATA 1000 max + lore contenu + clic droit = recuperation). + ECART : mineur uniquement, outils de minage uniquement (pas armure/arme). + VERIFIE : build SUCCESSFUL, boot Done, 0 erreur. UNVERIFIED en jeu. - M-palaforge LIVRE 2026-10-19 ~03:55 : bloc + BE partagee (3e mode) + gate mineur 14 + table fonte wiki §3.2 (31 items, ratio floor usure) + fuels bois (+buche/planches/baton, lave exclue : seau non rendu) + craft (1 findium + 4 furnaces + 4 briques, positions diff --git a/mods/pala/src/main/java/fr/surviepote/pala/core/PalaJobs.java b/mods/pala/src/main/java/fr/surviepote/pala/core/PalaJobs.java index f9fb267..49ba5cd 100644 --- a/mods/pala/src/main/java/fr/surviepote/pala/core/PalaJobs.java +++ b/mods/pala/src/main/java/fr/surviepote/pala/core/PalaJobs.java @@ -60,10 +60,98 @@ public final class PalaJobs { Double xp = PalaConfig.get().minerXp.get(id.toString()); if (xp != null && levelOf(player, "mineur") >= PalaConfig.get().minerLevels .getOrDefault(id.toString(), 0)) { + // M-enchants-2 (wiki Experience Bottler) : outil enchante + fiole vide en + // hotbar (contenu < 1000) => l'XP part dans la fiole au lieu du joueur. + // ECART : mineur uniquement (seul gain "casse-bloc" porte). + if (enchantLevel(level, player.getMainHandItem(), "experience_bottler") >= 1 + && bottleXp(player, "mineur", xp)) { + return; + } addXp(player, "mineur", xp); } } + /** Niveau d'un enchant pala sur un item (0 si absent). */ + public static int enchantLevel(ServerLevel level, net.minecraft.world.item.ItemStack stack, + String path) { + if (stack.isEmpty()) { + return 0; + } + net.minecraft.core.Holder holder = + level.registryAccess() + .lookupOrThrow(net.minecraft.core.registries.Registries.ENCHANTMENT) + .getOrThrow(net.minecraft.resources.ResourceKey.create( + net.minecraft.core.registries.Registries.ENCHANTMENT, + net.minecraft.resources.Identifier.fromNamespaceAndPath( + "pala", path))); + return net.minecraft.world.item.enchantment.EnchantmentHelper + .getItemEnchantmentLevel(holder, stack); + } + + // M-enchants-2 : verse de l'XP metier dans la premiere fiole admissible de la hotbar + // (slots 0-8, contenu < 1000). Vrai si verse (appelant : ne pas donner au joueur). + private static boolean bottleXp(ServerPlayer player, String job, double xp) { + net.minecraft.world.entity.player.Inventory inv = player.getInventory(); + for (int i = 0; i < 9; i++) { + net.minecraft.world.item.ItemStack stack = inv.getItem(i); + if (stack.isEmpty() + || !stack.is(fr.surviepote.pala.PalaItems.FLASK)) { + continue; + } + double stored = stack.getOrDefault( + net.minecraft.core.component.DataComponents.CUSTOM_DATA, + net.minecraft.world.item.component.CustomData.EMPTY).copyTag() + .getDoubleOr("bottler_xp", 0.0); + if (stored >= 1000.0) { + continue; + } + double put = Math.min(xp, 1000.0 - stored); + final double total = stored + put; + net.minecraft.world.item.component.CustomData.update( + net.minecraft.core.component.DataComponents.CUSTOM_DATA, stack, + tag -> { + tag.putDouble("bottler_xp", total); + tag.putString("bottler_job", job); + }); + stack.set(net.minecraft.core.component.DataComponents.LORE, + new net.minecraft.world.item.component.ItemLore(java.util.List.of( + net.minecraft.network.chat.Component.literal( + "§7" + job + " : " + (int) total + " / 1000 XP")))); + return true; + } + return false; + } + + /** Boire une fiole : recupere l'XP stockee dans son metier (M-enchants-2). */ + public static boolean drinkFlask(ServerPlayer player, + net.minecraft.world.item.ItemStack stack) { + double stored = stack.getOrDefault( + net.minecraft.core.component.DataComponents.CUSTOM_DATA, + net.minecraft.world.item.component.CustomData.EMPTY).copyTag() + .getDoubleOr("bottler_xp", 0.0); + if (stored <= 0.0) { + return false; + } + String job = stack.getOrDefault( + net.minecraft.core.component.DataComponents.CUSTOM_DATA, + net.minecraft.world.item.component.CustomData.EMPTY).copyTag() + .getStringOr("bottler_job", "mineur"); + if (!JOBS.contains(job)) { + job = "mineur"; + } + addXp(player, job, stored); + net.minecraft.world.item.component.CustomData.update( + net.minecraft.core.component.DataComponents.CUSTOM_DATA, stack, + tag -> { + tag.putDouble("bottler_xp", 0.0); + tag.putString("bottler_job", "mineur"); + }); + stack.set(net.minecraft.core.component.DataComponents.LORE, + new net.minecraft.world.item.component.ItemLore(java.util.List.of( + net.minecraft.network.chat.Component.literal("§7Fiole vide")))); + return true; + } + /** Hook prise fourneau : cuisson mineur (table wiki "Cuire") + viandes chasseur. */ public static void onSmeltTake(ServerPlayer player, net.minecraft.world.item.ItemStack stack) { if (stack.isEmpty()) { diff --git a/mods/pala/src/main/java/fr/surviepote/pala/events/PalaItemUseEvents.java b/mods/pala/src/main/java/fr/surviepote/pala/events/PalaItemUseEvents.java index efea90c..fc6be6f 100644 --- a/mods/pala/src/main/java/fr/surviepote/pala/events/PalaItemUseEvents.java +++ b/mods/pala/src/main/java/fr/surviepote/pala/events/PalaItemUseEvents.java @@ -150,6 +150,13 @@ public final class PalaItemUseEvents { + (n > 1 ? "s" : "") + ".")); return InteractionResult.SUCCESS; } + // M-enchants-2 : boire une fiole pleine = recuperer l'XP stockee. + if (item == PalaItems.FLASK) { + if (fr.surviepote.pala.core.PalaJobs.drinkFlask(sp, stack)) { + return InteractionResult.SUCCESS; + } + return InteractionResult.PASS; + } // M-gadget-2 (wiki items lucky) : grappin — clic droit air, raycast 32 blocs, // tirage instantane vers le point d'impact (ECART : pas de crochet visible). if (item == PalaItems.GRAPPIN) { diff --git a/mods/pala/src/main/resources/assets/pala/lang/en_us.json b/mods/pala/src/main/resources/assets/pala/lang/en_us.json index 8595163..9d98944 100644 --- a/mods/pala/src/main/resources/assets/pala/lang/en_us.json +++ b/mods/pala/src/main/resources/assets/pala/lang/en_us.json @@ -4,6 +4,7 @@ "item.pala.amethyst_mixed_coal": "Amethyst Mixed Coal", "item.pala.amethyst_stick": "Amethyst Stick", "item.pala.compressed_amethyst": "Compressed Amethyst", + "enchantment.pala.experience_bottler": "Experience Bottler", "enchantment.pala.xp_stealer": "Voleur d'XP", "block.pala.mystical_bookshelf": "Bibliotheque mystique", "block.pala.cauldron_block": "Bloc du chaudron", diff --git a/mods/pala/src/main/resources/data/pala/enchantment/experience_bottler.json b/mods/pala/src/main/resources/data/pala/enchantment/experience_bottler.json new file mode 100644 index 0000000..b533061 --- /dev/null +++ b/mods/pala/src/main/resources/data/pala/enchantment/experience_bottler.json @@ -0,0 +1,23 @@ +{ + "anvil_cost": 4, + "description": { + "translate": "enchantment.pala.experience_bottler" + }, + "effects": { + }, + "max_cost": { + "base": 40, + "per_level_above_first": 10 + }, + "max_level": 1, + "min_cost": { + "base": 20, + "per_level_above_first": 10 + }, + "primary_items": "#minecraft:enchantable/mining", + "slots": [ + "mainhand" + ], + "supported_items": "#minecraft:enchantable/mining", + "weight": 2 +} \ No newline at end of file diff --git a/server/mods/pala-0.2.1.jar b/server/mods/pala-0.2.1.jar index 32d9fc1..79de21b 100644 Binary files a/server/mods/pala-0.2.1.jar and b/server/mods/pala-0.2.1.jar differ