Compare commits
69
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
376a420474 | ||
|
|
a8e2db25f8 | ||
|
|
2bb85718d7 | ||
|
|
ee187d7b89 | ||
|
|
3532cac278 | ||
|
|
1447ab25b4 | ||
|
|
9a06ca78c6 | ||
|
|
f6ba70634b | ||
|
|
148fd04a93 | ||
|
|
17f60623ee | ||
|
|
c5ece27c11 | ||
|
|
296ccd1a76 | ||
|
|
08b58e2f78 | ||
|
|
62d2b8db2d | ||
|
|
3869f7ed93 | ||
|
|
c9c44872d6 | ||
|
|
cae53efedc | ||
|
|
5fac24cee8 | ||
|
|
1954dfec80 | ||
|
|
2eea2b64c2 | ||
|
|
a127a93be8 | ||
|
|
9b32f85817 | ||
|
|
ec139d2677 | ||
|
|
4327be0cf9 | ||
|
|
c25c832b31 | ||
|
|
eabaabc535 | ||
|
|
9acf97f5a0 | ||
|
|
24fc212c76 | ||
|
|
04f88bdd63 | ||
|
|
a4eb58aa57 | ||
|
|
6704d4e5ee | ||
|
|
c88087de29 | ||
|
|
86bb802140 | ||
|
|
6b644b384d | ||
|
|
c370af8914 | ||
|
|
1cd6d2bfc7 | ||
|
|
1edeae2a60 | ||
|
|
409f1056b9 | ||
|
|
d8c470db3d | ||
|
|
c642c4b84b | ||
|
|
0b80f7e547 | ||
|
|
d543f45607 | ||
|
|
2b4fdfd219 | ||
|
|
1a3b655d3f | ||
|
|
1f5f278970 | ||
|
|
0b4eb5239a | ||
|
|
118e8f6205 | ||
|
|
cf126c5906 | ||
|
|
645cf61911 | ||
|
|
87d5ede3dd | ||
|
|
203e5d89cd | ||
|
|
ce611cc61c | ||
|
|
f6ad7ff865 | ||
|
|
d69627a9c8 | ||
|
|
54e8763470 | ||
|
|
db34687df0 | ||
|
|
7f008d85ff | ||
|
|
9dac604a93 | ||
|
|
8540a73885 | ||
|
|
25ce784a60 | ||
|
|
5358cccb62 | ||
|
|
698fa9dff9 | ||
|
|
a8949cf1f9 | ||
|
|
61db6334f9 | ||
|
|
46d278ca55 | ||
|
|
339038956d | ||
|
|
116a93d8cc | ||
|
|
acebc35d3f | ||
|
|
aee89f1c92 |
No files matched your search
+23
-3
@@ -6,7 +6,6 @@
|
||||
- Added the Partner Mark, which party Pokémon have a very small chance to earn as the player walks, provided they have enough friendship.
|
||||
- Added trades for Saccharine Saplings, Hearty Grains, Chipped Pot, and Masterpiece Teacup to the Wandering Trader.
|
||||
- Added brewing recipe for Throat Spray.
|
||||
- Added official Controlify Support
|
||||
- Added new effects
|
||||
- Mental Restoration: Reduces "Time Since Last Rest" statistic, which controls Insomnia, by half a minute per second per effect level
|
||||
- Negative Effect Cleanse: Removes all negative effects
|
||||
@@ -16,17 +15,26 @@
|
||||
- White Herb - Negative Effect Cleanse
|
||||
- Milk - Effect Cleanse
|
||||
- Moomoo Milk - Effect Cleanse
|
||||
- Added `label` as an alternate key to the `tag` property.
|
||||
- Added Saccharine wood furniture for Adorn.
|
||||
|
||||
### Changes
|
||||
- Ride sounds have been separated into stereo for passengers and mono for other players. Riding will now sound more spacious.
|
||||
- Added a new config option, `Enable In-Flight Dismounting` (default: off), which lets you dismount while riding a Pokémon in the air.
|
||||
- Battle AI now uses a smarter threshold for switching, reducing unnecessary switches.
|
||||
- AI will always use the most damaging move when at low HP and when it is not switching, improving endgame decision-making.
|
||||
- Added support for optional message variants in battle activate instructions for more context-specific battle text.
|
||||
- Example: `this.add('-activate', pokemon, 'ability: example', '[msg]message1');` will parse to lang key `cobblemon.battle.activate.example.message1`
|
||||
|
||||
### Fixes
|
||||
- Fixed an issue in the OmniPathNodeMaker/Navigation that prevented Combees from pathing into and out of Saccharine leaves.
|
||||
- Fixed orientation not getting reset after crashing while flying and getting back on the Pokémon.
|
||||
- Fixed Furfrou not being trimmable on NeoForge.
|
||||
- Fixed shiny Pokémon not respecting the silent flag on spawn.
|
||||
- Fixed honey from Saccharine Leaves being harvestable at less than the max age.
|
||||
- Items given from interacting with Saccharine Leaves are placed in the active hotbar slot if possible.
|
||||
- Fix all Pokémon being saved to chunks and never despawning.
|
||||
- Fixed possible error on world generation when Combees are placed in naturally generated bee nests.
|
||||
- Fixed PokeSnacks crashing if there was no available spawn.
|
||||
- Fixed Pokémon spawn influences not being specific to regional forms
|
||||
- Fixed crashing when viewing another player in spectator mode
|
||||
@@ -37,15 +45,27 @@
|
||||
- Fixed Soothe Bell not being properly tagged as a held item.
|
||||
- Fixed Mint Leaves not being usable for filling the Resurrection Machine.
|
||||
- Added Saccharine Boats and Saccharine Boat with Chests to relevant boat tags.
|
||||
- Fixed the `run_script` Molang function to not fail if the environment's context is null.
|
||||
- Fixed the movesets of certain Pokémon being incorrectly sanitized upon reload.
|
||||
- Fixed the ordering of Aprijuice's riding stat boosts to always have the same order.
|
||||
- Fixed the Molang functions `date_local_time`, `date_of`, `date_is_after` to use the correct date format.
|
||||
- Fixed the bottom half of pasture blocks having an incorrect hit-box when facing north or south.
|
||||
|
||||
- Fixed Galarian Mr. Mime incorrectly being rideable.
|
||||
- Fixed gimmicks not being usable in double / triple battles
|
||||
- Fixed gimmick buttons showing when already used in the same turn in double / triple battles
|
||||
- Fixed Apricorn block model rotation for counters/sinks/cupboards/drawers to match that of most recent version of Adorn.
|
||||
- Fixed Scraggy & Scrafty being able to spawn on non-natural blocks in badlands
|
||||
|
||||
### Developer
|
||||
- Changed the `owner` parameter in the `OwnerQueryRequirement` interface from `ServerPlayer` to `Player`. This method is now also called on the client to verify whether a Pokémon interaction succeeded, so make sure to update your implementations to handle both server and client contexts.
|
||||
- Changed the `owner` parameter in the `OwnerQueryRequirement` interface from `ServerPlayer` to `Player`. This method is now also called on the client to verify whether a Pokémon interaction succeeded, so make sure to update your implementations to handle both server and client contexts.
|
||||
|
||||
### Molang & Datapacks
|
||||
- Ride sounds can now be set as exclusive to passengers
|
||||
- Ride sounds no longer play when submerged unless specified with a new setting
|
||||
- Exception handling has been added to `run_molang`, resolving some crashes caused by malformed MoLang expressions.
|
||||
|
||||
### Particles
|
||||
|
||||
### Localization
|
||||
- Updated translations for:
|
||||
- Updated translations for:
|
||||
@@ -32,10 +32,6 @@ repositories {
|
||||
maven(url = "https://api.modrinth.com/maven")
|
||||
maven(url = "https://maven.neoforged.net/releases")
|
||||
maven(url = "https://maven.gegy.dev")
|
||||
exclusiveContent {
|
||||
forRepository { maven(url = "https://maven.isxander.dev/releases") }
|
||||
filter { includeGroup("dev.isxander") }
|
||||
}
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
@@ -66,11 +62,6 @@ dependencies {
|
||||
|
||||
// Unit Testing
|
||||
testImplementation(libs.bundles.unitTesting)
|
||||
|
||||
// Controlify Compat, same as flywheel so we pick one and only use the api
|
||||
modCompileOnlyApi("dev.isxander:controlify:2.4.3+1.21.1-fabric") {
|
||||
isTransitive = false
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<Test> {
|
||||
|
||||
@@ -11,7 +11,9 @@ package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories;
|
||||
import com.cobblemon.mod.common.api.ai.config.task.PathToBeeHiveTaskConfig;
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.world.feature.SaccharineTreeFeature;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
@@ -42,7 +44,21 @@ public abstract class BeeOccupantMixin {
|
||||
if (cir.getReturnValue() == null) {
|
||||
final BeehiveBlockEntity.Occupant occupant = (BeehiveBlockEntity.Occupant) (Object) this;
|
||||
CompoundTag compoundTag = occupant.entityData().copyTag();
|
||||
Entity entity = EntityType.loadEntityRecursive(compoundTag, level, (entityx) -> entityx);
|
||||
String id = compoundTag.getString("id");
|
||||
Entity entity = null;
|
||||
if (id.equals(SaccharineTreeFeature.Companion.getPOKEMON_PLACEHOLD_ID())) {
|
||||
// Special case for Pokemon stuffed into a beenest upon world gen.
|
||||
// For technical reasons we cannot create them as full entities during world gen.
|
||||
// So we look for this special id tag and complete the entity when it attempts to exit a hive.
|
||||
if (compoundTag.contains("pokemonProperties")) {
|
||||
String properties = compoundTag.getString("pokemonProperties");
|
||||
PokemonProperties pokemon = PokemonProperties.Companion.parse(properties);
|
||||
entity = pokemon.createEntity(level);
|
||||
}
|
||||
} else {
|
||||
entity = EntityType.loadEntityRecursive(compoundTag, level, (entityx) -> entityx);
|
||||
}
|
||||
|
||||
if (entity instanceof PokemonEntity pokemonEntity) {
|
||||
var state = level.getBlockState(pos);
|
||||
var newPos = Vec3.ZERO;
|
||||
|
||||
@@ -21,14 +21,12 @@ import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import com.mojang.blaze3d.Blaze3D;
|
||||
import kotlin.Pair;
|
||||
import kotlin.jvm.functions.Function4;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.MouseHandler;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.util.SmoothDouble;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.joml.Vector2d;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
@@ -148,12 +146,6 @@ public abstract class MouseHandlerMixin {
|
||||
pokeVehicle.clampPassengerRotation(player);
|
||||
}
|
||||
|
||||
for(Function4<LocalPlayer, Double, Double, Double, Vector2d> rideFun : CobblemonClient.INSTANCE.getRidingTurnInputHandler().values()) {
|
||||
Vector2d vec = rideFun.invoke(player, cursorDeltaX, cursorDeltaY, d);
|
||||
cursorDeltaX = vec.x;
|
||||
cursorDeltaY = vec.y;
|
||||
}
|
||||
|
||||
// If the ride is not orientation controllable then return and perform the normal turnPlayer logic
|
||||
if (!(vehicle instanceof OrientationControllable controllableVehicle) || !controllableVehicle.getOrientationController().isActive()) {
|
||||
xMouseSmoother.reset();
|
||||
|
||||
@@ -91,7 +91,7 @@ import com.cobblemon.mod.common.pokemon.feature.SlowpokeTailRegrowthSpeciesFeatu
|
||||
import com.cobblemon.mod.common.pokemon.feature.TagSeasonResolver
|
||||
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
|
||||
import com.cobblemon.mod.common.pokemon.properties.*
|
||||
import com.cobblemon.mod.common.pokemon.properties.tags.PokemonFlagProperty
|
||||
import com.cobblemon.mod.common.pokemon.properties.LabelProperty
|
||||
import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
|
||||
import com.cobblemon.mod.common.starter.CobblemonStarterHandler
|
||||
import com.cobblemon.mod.common.util.*
|
||||
@@ -315,7 +315,7 @@ object Cobblemon {
|
||||
|
||||
CustomPokemonProperty.register(UncatchableProperty)
|
||||
CustomPokemonProperty.register(BattleCloneProperty)
|
||||
CustomPokemonProperty.register(PokemonFlagProperty)
|
||||
CustomPokemonProperty.register(LabelProperty)
|
||||
CustomPokemonProperty.register(HiddenAbilityPropertyType)
|
||||
CustomPokemonProperty.register(AspectPropertyType)
|
||||
CustomPokemonProperty.register(UnaspectPropertyType)
|
||||
|
||||
@@ -311,7 +311,7 @@ object MoLangFunctions {
|
||||
runtime.environment.variable = params.environment.variable
|
||||
val args = params.params.subList(1, params.params.size)
|
||||
runtime.environment.context = ContextStruct(
|
||||
params.environment.context.map + args.mapIndexed { index, value -> "arg_${index + 1}" to value }.toMap()
|
||||
(params.environment.context?.map ?: emptyMap()) + args.mapIndexed { index, value -> "arg_${index + 1}" to value }.toMap()
|
||||
)
|
||||
val script = params.getString(0).asIdentifierDefaultingNamespace()
|
||||
// store the args in the
|
||||
@@ -324,13 +324,24 @@ object MoLangFunctions {
|
||||
runtime.environment.context = params.environment.context
|
||||
val expression = params.getString(0).asExpressionLike()
|
||||
val delayInSeconds = params.getDoubleOrNull(1)?.toFloat() ?: 0.0f
|
||||
|
||||
fun evaluate(): MoValue {
|
||||
return try {
|
||||
runtime.resolve(expression)
|
||||
} catch (ex: Exception) {
|
||||
Cobblemon.LOGGER.warn("Failed to evaluate MoLang expression${if (delayInSeconds > 0.0f) " (delayed)" else ""}: $expression", ex)
|
||||
DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
|
||||
if (delayInSeconds > 0.0f) {
|
||||
val tracker = if (Cobblemon.implementation.environment() == Environment.SERVER) ServerTaskTracker else ClientTaskTracker
|
||||
tracker.after(delayInSeconds) {
|
||||
runtime.resolve(expression)
|
||||
evaluate()
|
||||
}
|
||||
DoubleValue.ONE
|
||||
} else {
|
||||
runtime.resolve(expression)
|
||||
evaluate()
|
||||
}
|
||||
},
|
||||
"system_time_millis" to java.util.function.Function { _ ->
|
||||
@@ -340,19 +351,19 @@ object MoLangFunctions {
|
||||
"date_local_time" to java.util.function.Function { _ ->
|
||||
val time = System.currentTimeMillis()
|
||||
val date = java.util.Date(time)
|
||||
val formatted = java.text.SimpleDateFormat("DD/MM/YYYY").format(date)
|
||||
val formatted = java.text.SimpleDateFormat("dd/MM/yyyy").format(date)
|
||||
StringValue(formatted)
|
||||
},
|
||||
"date_of" to java.util.function.Function { params ->
|
||||
val time = params.getDouble(0).toLong()
|
||||
val date = java.util.Date(time)
|
||||
val formatted = java.text.SimpleDateFormat("DD/MM/YYYY").format(date)
|
||||
val formatted = java.text.SimpleDateFormat("dd/MM/yyyy").format(date)
|
||||
StringValue(formatted)
|
||||
},
|
||||
"date_is_after" to java.util.function.Function { params ->
|
||||
val dateA = params.getString(0)
|
||||
val dateB = params.getString(1)
|
||||
val format = java.text.SimpleDateFormat("DD/MM/YYYY")
|
||||
val format = java.text.SimpleDateFormat("dd/MM/yyyy")
|
||||
val a = format.parse(dateA)
|
||||
val b = format.parse(dateB)
|
||||
DoubleValue(a.after(b))
|
||||
|
||||
+10
-8
@@ -80,7 +80,9 @@ open class ChoiceSpeciesFeatureProvider(
|
||||
|
||||
internal constructor(): this(emptyList())
|
||||
|
||||
override fun get(pokemon: Pokemon) = pokemon.getFeature<StringSpeciesFeature>(keys.first())
|
||||
override fun get(pokemon: Pokemon): StringSpeciesFeature? {
|
||||
return pokemon.features.filterIsInstance<StringSpeciesFeature>().find { it.name in keys }
|
||||
}
|
||||
|
||||
override fun invoke(pokemon: Pokemon): StringSpeciesFeature? {
|
||||
val existing = get(pokemon)
|
||||
@@ -101,15 +103,15 @@ open class ChoiceSpeciesFeatureProvider(
|
||||
}
|
||||
|
||||
override fun invoke(nbt: CompoundTag): StringSpeciesFeature? {
|
||||
return if (nbt.contains(keys.first())) {
|
||||
StringSpeciesFeature(keys.first(), "").also { it.loadFromNBT(nbt) }
|
||||
} else null
|
||||
val key = keys.find { nbt.contains(it) }
|
||||
if (key == null) return null
|
||||
return StringSpeciesFeature(key, "").also { it.loadFromNBT(nbt) }
|
||||
}
|
||||
|
||||
override fun invoke(json: JsonObject): StringSpeciesFeature? {
|
||||
return if (json.has(keys.first())) {
|
||||
StringSpeciesFeature(keys.first(), "").also { it.loadFromJSON(json) }
|
||||
} else null
|
||||
val key = keys.find { json.has(it) }
|
||||
if (key == null) return null
|
||||
return StringSpeciesFeature(key, "").also { it.loadFromJSON(json) }
|
||||
}
|
||||
|
||||
override fun fromString(value: String?): StringSpeciesFeature? {
|
||||
@@ -131,7 +133,7 @@ open class ChoiceSpeciesFeatureProvider(
|
||||
|
||||
override fun provide(properties: PokemonProperties): Set<String> {
|
||||
return if (isAspect) {
|
||||
val feature = properties.customProperties.filterIsInstance<StringSpeciesFeature>().find { it.name == keys.first() }
|
||||
val feature = properties.customProperties.filterIsInstance<StringSpeciesFeature>().find { it.name in keys }
|
||||
if (feature != null) {
|
||||
setOf(getAspect(feature))
|
||||
} else {
|
||||
|
||||
+23
-11
@@ -132,7 +132,9 @@ class FlagSpeciesFeatureProvider : SynchronizedSpeciesFeatureProvider<FlagSpecie
|
||||
|
||||
constructor(vararg keys: String) : this(keys.toList())
|
||||
|
||||
override fun get(pokemon: Pokemon) = pokemon.getFeature<FlagSpeciesFeature>(keys.first())
|
||||
override fun get(pokemon: Pokemon): FlagSpeciesFeature? {
|
||||
return pokemon.features.filterIsInstance<FlagSpeciesFeature>().find { it.name in keys }
|
||||
}
|
||||
|
||||
override fun invoke(pokemon: Pokemon): FlagSpeciesFeature? {
|
||||
return get(pokemon)
|
||||
@@ -144,15 +146,15 @@ class FlagSpeciesFeatureProvider : SynchronizedSpeciesFeatureProvider<FlagSpecie
|
||||
}
|
||||
|
||||
override fun invoke(nbt: CompoundTag): FlagSpeciesFeature? {
|
||||
return if (nbt.contains(keys.first())) {
|
||||
FlagSpeciesFeature(keys.first(), false).also { it.loadFromNBT(nbt) }
|
||||
} else null
|
||||
val key = keys.find { nbt.contains(it) }
|
||||
if (key == null) return null
|
||||
return FlagSpeciesFeature(key, false).also { it.loadFromNBT(nbt) }
|
||||
}
|
||||
|
||||
override fun invoke(json: JsonObject): FlagSpeciesFeature? {
|
||||
return if (json.has(keys.first())) {
|
||||
FlagSpeciesFeature(keys.first(), false).also { it.loadFromJSON(json) }
|
||||
} else null
|
||||
val key = keys.find { json.has(it) }
|
||||
if (key == null) return null
|
||||
return FlagSpeciesFeature(key, false).also { it.loadFromJSON(json) }
|
||||
}
|
||||
|
||||
override fun fromString(value: String?): FlagSpeciesFeature? {
|
||||
@@ -170,16 +172,26 @@ class FlagSpeciesFeatureProvider : SynchronizedSpeciesFeatureProvider<FlagSpecie
|
||||
}
|
||||
|
||||
override fun provide(pokemon: Pokemon): Set<String> {
|
||||
return if (isAspect && pokemon.getFeature<FlagSpeciesFeature>(keys.first())?.enabled == true) {
|
||||
setOf(keys.first())
|
||||
return if (isAspect) {
|
||||
val feature = pokemon.features.filterIsInstance<FlagSpeciesFeature>().find { it.name in keys }
|
||||
if (feature != null && feature.enabled) {
|
||||
setOf(keys.first())
|
||||
} else {
|
||||
emptySet()
|
||||
}
|
||||
} else {
|
||||
emptySet()
|
||||
}
|
||||
}
|
||||
|
||||
override fun provide(properties: PokemonProperties): Set<String> {
|
||||
return if (isAspect && properties.customProperties.filterIsInstance<FlagSpeciesFeature>().find { it.name == keys.first() }?.enabled == true) {
|
||||
setOf(keys.first())
|
||||
return if (isAspect) {
|
||||
val feature = properties.customProperties.filterIsInstance<FlagSpeciesFeature>().find { it.name in keys }
|
||||
if (feature != null && feature.enabled) {
|
||||
setOf(keys.first())
|
||||
} else {
|
||||
emptySet()
|
||||
}
|
||||
} else {
|
||||
emptySet()
|
||||
}
|
||||
|
||||
+6
-10
@@ -142,19 +142,15 @@ class IntSpeciesFeatureProvider : SynchronizedSpeciesFeatureProvider<IntSpeciesF
|
||||
}
|
||||
|
||||
override fun invoke(nbt: CompoundTag): IntSpeciesFeature? {
|
||||
return if (nbt.contains(keys.first())) {
|
||||
IntSpeciesFeature(keys.first(), nbt.getInt(keys.first()))
|
||||
} else {
|
||||
null
|
||||
}
|
||||
val key = keys.find { nbt.contains(it) }
|
||||
if (key == null) return null
|
||||
return IntSpeciesFeature(keys.first(), nbt.getInt(key));
|
||||
}
|
||||
|
||||
override fun invoke(json: JsonObject): IntSpeciesFeature? {
|
||||
return if (json.has(keys.first())) {
|
||||
IntSpeciesFeature(keys.first(), json.get(keys.first()).asInt)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
val key = keys.find { json.has(it) }
|
||||
if (key == null) return null
|
||||
return IntSpeciesFeature(keys.first(), json.get(key).asInt)
|
||||
}
|
||||
|
||||
override fun get(pokemon: Pokemon) = pokemon.features.filterIsInstance<IntSpeciesFeature>().find { it.name in keys }
|
||||
|
||||
+6
-8
@@ -22,7 +22,6 @@ import com.cobblemon.mod.common.api.riding.posing.PoseOption
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.api.riding.sound.RideSoundSettingsList
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.client.CobblemonClient
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.blockPositionsAsListRounded
|
||||
@@ -145,12 +144,11 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
|
||||
) {
|
||||
val sprintTimerTickLength = 7 // Emulate vanillas tick timer length
|
||||
var hasDoubleTapped = false
|
||||
val forward = Minecraft.getInstance().player?.input?.up == true
|
||||
|
||||
// If you are not sprinting and you just pressed down and theres no
|
||||
if (!state.forwardHeldLastTick.get() && forward && !state.sprinting.get() && state.sprintTickTimer.get() == 0) {
|
||||
if (!state.forwardHeldLastTick.get() && Minecraft.getInstance().options.keyUp.isDown() && !state.sprinting.get() && state.sprintTickTimer.get() == 0) {
|
||||
state.sprintTickTimer.set(sprintTimerTickLength)
|
||||
} else if (!state.forwardHeldLastTick.get() && forward && state.sprintTickTimer.get() != 0) { // If has double tapped
|
||||
} else if (!state.forwardHeldLastTick.get() && Minecraft.getInstance().options.keyUp.isDown() && state.sprintTickTimer.get() != 0) { // If has double tapped
|
||||
hasDoubleTapped = true
|
||||
}else if(!state.sprinting.get() && state.sprintTickTimer.get() > 0) {
|
||||
state.sprintTickTimer.set(state.sprintTickTimer.get() - 1)
|
||||
@@ -158,9 +156,9 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
|
||||
state.sprintTickTimer.set(0)
|
||||
}
|
||||
|
||||
val tryingToSprint = hasDoubleTapped || CobblemonClient.ridingSprintHandler.any { it.value.invoke() }
|
||||
val tryingToSprint = (Minecraft.getInstance().options.keySprint.isDown() && Minecraft.getInstance().options.keyUp.isDown()) || hasDoubleTapped
|
||||
|
||||
if (state.stamina.get() <= 0.0f || !forward) {
|
||||
if (state.stamina.get() <= 0.0f || !Minecraft.getInstance().options.keyUp.isDown()) {
|
||||
// If stamina runs out or the player is not holding forward then stop sprinting
|
||||
state.sprinting.set(false)
|
||||
if (state.stamina.get() <= 0.0f) {
|
||||
@@ -174,8 +172,8 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
|
||||
state.sprinting.set(true)
|
||||
}
|
||||
|
||||
// Take note of whether forward was held last tick
|
||||
state.forwardHeldLastTick.set(forward)
|
||||
// Take not of whether forward was held last tick
|
||||
state.forwardHeldLastTick.set(Minecraft.getInstance().options.keyUp.isDown())
|
||||
}
|
||||
|
||||
fun tickStamina(
|
||||
|
||||
@@ -105,12 +105,18 @@ data class BattleFormat(
|
||||
}
|
||||
|
||||
fun toFormatJSON(): String {
|
||||
/*
|
||||
Bag clause does not exist in showdown as a rule because showdown simply has no concept of a 'bag'.
|
||||
If we try sending it, the battle will error. So this simply omits that from ever getting sent.
|
||||
If we ever find a case where we are doing this for more than just bag clause, we should make a proper abstraction.
|
||||
*/
|
||||
val rulesToSendToShowdown = ruleSet.filter { it != BattleRules.BAG_CLAUSE }
|
||||
return """
|
||||
{
|
||||
"mod": "$mod",
|
||||
"gameType": "${battleType.name}",
|
||||
"gen": $gen,
|
||||
"ruleset": [${ruleSet.joinToString { "\"$it\"" }}],
|
||||
"ruleset": [${rulesToSendToShowdown.joinToString { "\"$it\"" }}],
|
||||
"effectType": "Format"
|
||||
}
|
||||
""".trimIndent().replace("\n", "")
|
||||
|
||||
@@ -12,6 +12,7 @@ object BattleRules {
|
||||
const val OBTAINABLE = "Obtainable"
|
||||
const val PAST = "+Past"
|
||||
const val UNOBTAINABLE = "+Unobtainable"
|
||||
const val BAG_CLAUSE = "Bag Clause"
|
||||
const val TEAM_PREVIEW = "Team Preview"
|
||||
const val ENDLESS_BATTLE_CLAUSE = "Endless Battle Clause"
|
||||
const val CANCEL_MOD = "Cancel Mod"
|
||||
|
||||
@@ -289,6 +289,8 @@ class ShowdownMoveset {
|
||||
var canDynamax = false
|
||||
var maxMoves: List<InBattleGimmickMove?>? = null
|
||||
var canTerastallize: String? = null
|
||||
/** This stores a list of gimmicks that have already been used this turn by a previous Pokemon, but the full turn has not been processed (ie. double battles). */
|
||||
val pendingGimmickUsedThisTurn = mutableListOf<Gimmick>()
|
||||
|
||||
fun saveToBuffer(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeSizedInt(IntSize.U_BYTE, moves.size)
|
||||
|
||||
@@ -31,6 +31,7 @@ import kotlin.collections.associateWith
|
||||
import kotlin.collections.partition
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
|
||||
/**
|
||||
* AI that tries to choose the best move for the given situations. Based off of the Pokemon Trainer Tournament Simulator Github
|
||||
* https://github.com/cRz-Shadows/Pokemon_Trainer_Tournament_Simulator/blob/main/pokemon-showdown/sim/examples/Simulation-test-1.ts#L330
|
||||
@@ -271,6 +272,11 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
}
|
||||
activeTrackerPokemon.firstTurn = false
|
||||
|
||||
// If HP is below 30% and not switching out, always use the most damaging move
|
||||
if (activeTrackerPokemon.currentHpPercent < 0.3 && !shouldSwitchOut(aiSide, battle, activeBattlePokemon, moveset)) {
|
||||
findAndUseMostDamagingMove(activeBattlePokemon, activeTrackerPokemon, opponents, availableMoves, moveset, battle, aiSide)?.let { return it }
|
||||
}
|
||||
|
||||
// Decision-making based on move availability and switch-out condition
|
||||
if (!shouldSwitchOut(aiSide, battle, activeBattlePokemon, moveset)) {
|
||||
val nRemainingMons = activeTracker.alliedSide.actors.sumOf { actor -> actor.party.filter { it.currentHpPercent > 0 }.size }
|
||||
@@ -521,6 +527,19 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
|
||||
val opponentActiveTracker = activeTracker.opponentSide.activePokemon
|
||||
val opponentSpeedEstimations = opponentActiveTracker.map { statEstimationActive(it, Stats.SPEED) }
|
||||
|
||||
|
||||
// Only switch if a switch-in is significantly better than the current Pokémon
|
||||
val currentScore = estimateMatchup(activeBattlePokemon, side, battle)
|
||||
val bestSwitchScore = availableSwitches.maxOfOrNull { estimateMatchup(activeBattlePokemon, side, battle, it) } ?: currentScore
|
||||
val improvementThreshold = currentScore.absoluteValue * 0.25 + 2
|
||||
if (bestSwitchScore <= currentScore + improvementThreshold) {
|
||||
return false
|
||||
}
|
||||
|
||||
if(bestSwitchScore < 1) {
|
||||
return false
|
||||
}
|
||||
// todo add some way to keep track of the player's boosting to see if it needs to switch out to something that can stop it
|
||||
|
||||
// if slower speed stat than the opposing pokemon and HP is less than 20% don't switch out
|
||||
@@ -548,6 +567,8 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
if (availableSwitches.isEmpty() || availableSwitches.none { estimateMatchup(activeBattlePokemon, side, battle, it) > 0 })
|
||||
return false
|
||||
|
||||
|
||||
|
||||
// ...and a 'good' reason to switch out
|
||||
if (opponentActiveTracker.any { it.boosts.getOrDefault(Stats.ACCURACY, 0) <= accuracySwitchThreshold } ||
|
||||
opponentActiveTracker.any { it.boosts.getOrDefault(Stats.DEFENCE, 0) <= -3 } ||
|
||||
|
||||
+8
-1
@@ -114,7 +114,14 @@ class ActivateInstruction(val instructionSet: InstructionSet, val message: Battl
|
||||
}
|
||||
"maxguard", "protect" -> battleLang("activate.protect", pokemonName)
|
||||
"shadowforce", "hyperspacefury", "hyperspacehole" -> battleLang("activate.phantomforce", pokemonName)
|
||||
else -> battleLang("activate.${effect.id}", pokemonName, sourceName, extraEffect)
|
||||
else -> {
|
||||
val msgVariant = message.optionalArgument("msg")
|
||||
if (msgVariant != null) {
|
||||
battleLang("activate.${effect.id}.$msgVariant", pokemonName, sourceName, extraEffect)
|
||||
} else {
|
||||
battleLang("activate.${effect.id}", pokemonName, sourceName, extraEffect)
|
||||
}
|
||||
}
|
||||
}
|
||||
battle.broadcastChatMessage(lang)
|
||||
//We check holds here so the chat msg + particle effect happen more concurrently, instead of sequentially
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.cobblemon.mod.common.util.isInBattle
|
||||
import com.cobblemon.mod.common.util.playSoundServer
|
||||
import com.cobblemon.mod.common.util.toVec3d
|
||||
import com.cobblemon.mod.common.util.voxelShape
|
||||
import com.cobblemon.mod.common.util.rotateShape
|
||||
import com.mojang.serialization.MapCodec
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
@@ -71,10 +72,10 @@ class PastureBlock(settings: Properties): BaseEntityBlock(settings), SimpleWater
|
||||
private val WEST_AABB_TOP = buildCollider(top = true, Direction.WEST)
|
||||
private val EAST_AABB_TOP = buildCollider(top = true, Direction.EAST)
|
||||
|
||||
private val SOUTH_AABB_BOTTOM = buildCollider(top = false, Direction.SOUTH)
|
||||
private val NORTH_AABB_BOTTOM = buildCollider(top = false, Direction.NORTH)
|
||||
private val WEST_AABB_BOTTOM = buildCollider(top = false, Direction.WEST)
|
||||
private val EAST_AABB_BOTTOM = buildCollider(top = false, Direction.EAST)
|
||||
private val SOUTH_AABB_BOTTOM = rotateShape(Direction.EAST, Direction.SOUTH, EAST_AABB_BOTTOM)
|
||||
private val NORTH_AABB_BOTTOM = rotateShape(Direction.EAST, Direction.NORTH, EAST_AABB_BOTTOM)
|
||||
private val WEST_AABB_BOTTOM = rotateShape(Direction.EAST, Direction.WEST, EAST_AABB_BOTTOM)
|
||||
|
||||
private fun buildCollider(top: Boolean, direction: Direction): VoxelShape {
|
||||
if (top) {
|
||||
|
||||
@@ -74,7 +74,6 @@ import com.cobblemon.mod.common.entity.boat.CobblemonBoatType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.platform.events.PlatformEvents
|
||||
import com.cobblemon.mod.common.pokedex.scanner.PokedexUsageContext
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.isLookingAt
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.color.block.BlockColor
|
||||
@@ -84,19 +83,16 @@ import net.minecraft.client.gui.screens.Screen
|
||||
import net.minecraft.client.model.BoatModel
|
||||
import net.minecraft.client.model.ChestBoatModel
|
||||
import net.minecraft.client.model.PlayerModel
|
||||
import net.minecraft.client.player.LocalPlayer
|
||||
import net.minecraft.client.renderer.RenderType
|
||||
import net.minecraft.client.renderer.blockentity.HangingSignRenderer
|
||||
import net.minecraft.client.renderer.blockentity.SignRenderer
|
||||
import net.minecraft.client.renderer.entity.EntityRenderer
|
||||
import net.minecraft.client.renderer.entity.LivingEntityRenderer
|
||||
import net.minecraft.client.resources.PlayerSkin
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.packs.resources.ResourceManager
|
||||
import net.minecraft.world.InteractionHand
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.phys.AABB
|
||||
import org.joml.Vector2d
|
||||
|
||||
object CobblemonClient {
|
||||
|
||||
@@ -116,8 +112,6 @@ object CobblemonClient {
|
||||
val battleOverlay: BattleOverlay by lazy { BattleOverlay() }
|
||||
val pokedexUsageContext: PokedexUsageContext by lazy { PokedexUsageContext() }
|
||||
val rideControlsOverlay: RideControlsOverlay by lazy { RideControlsOverlay() }
|
||||
val ridingTurnInputHandler: MutableMap<ResourceLocation, (LocalPlayer, Double, Double, Double) -> Vector2d> = mutableMapOf()
|
||||
val ridingSprintHandler: MutableMap<ResourceLocation, () -> Boolean> = mutableMapOf()
|
||||
|
||||
fun onLogin() {
|
||||
clientPlayerData = ClientGeneralPlayerData()
|
||||
@@ -201,8 +195,6 @@ object CobblemonClient {
|
||||
ClientPlayerIcon.onTick()
|
||||
PartyOverlayDataControl.tick(event.client.isPaused)
|
||||
}
|
||||
|
||||
ridingSprintHandler.put(cobblemonResource("normal")) { Minecraft.getInstance().options.keySprint.isDown }
|
||||
}
|
||||
|
||||
private fun registerTooltipManagers() {
|
||||
|
||||
@@ -11,10 +11,11 @@ package com.cobblemon.mod.common.client.battle
|
||||
import com.cobblemon.mod.common.CobblemonNetwork
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
|
||||
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.battles.BattleFormat
|
||||
import com.cobblemon.mod.common.battles.ForcePassActionResponse
|
||||
import com.cobblemon.mod.common.battles.MoveActionResponse
|
||||
import com.cobblemon.mod.common.battles.PassActionResponse
|
||||
import com.cobblemon.mod.common.battles.ShowdownMoveset
|
||||
import com.cobblemon.mod.common.client.CobblemonClient
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.BattleSelectActionsPacket
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
@@ -61,8 +62,15 @@ class ClientBattle(
|
||||
if (index != -1) {
|
||||
while(index < pendingActionRequests.size) {
|
||||
val request = pendingActionRequests[index]
|
||||
if (request.response != PassActionResponse && request.response !is ForcePassActionResponse)
|
||||
if (request.response != PassActionResponse && request.response !is ForcePassActionResponse) {
|
||||
val response = request.response
|
||||
// If we're cancelling a turn that used a gimmick, we re-enable the ability for that gimmick to be used.
|
||||
if (response is MoveActionResponse && response.gimmickID != null) {
|
||||
val gimmick = ShowdownMoveset.Gimmick.entries.find { it.id == response.gimmickID }
|
||||
pendingActionRequests.forEach { it.moveSet?.pendingGimmickUsedThisTurn?.remove(gimmick) }
|
||||
}
|
||||
request.response = null
|
||||
}
|
||||
index++
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -68,7 +68,7 @@ class BattleMoveSelection(
|
||||
var moveTiles = baseTiles
|
||||
|
||||
val backButton = BattleBackButton(x - 11F, Minecraft.getInstance().window.guiScaledHeight - 22F)
|
||||
val gimmickButtons = moveSet.getGimmicks().mapIndexed { index, gimmick ->
|
||||
val gimmickButtons = moveSet.getGimmicks().filter { it !in moveSet.pendingGimmickUsedThisTurn }.mapIndexed { index, gimmick ->
|
||||
val initOff = BattleBackButton.WIDTH * 0.65F
|
||||
val xOff = initOff + BattleGimmickButton.SPACING * index
|
||||
BattleGimmickButton.create(gimmick, this, backButton.x + xOff, backButton.y)
|
||||
|
||||
+9
-1
@@ -17,6 +17,7 @@ import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.battles.InBattleGimmickMove
|
||||
import com.cobblemon.mod.common.battles.InBattleMove
|
||||
import com.cobblemon.mod.common.battles.MoveActionResponse
|
||||
import com.cobblemon.mod.common.battles.ShowdownMoveset
|
||||
import com.cobblemon.mod.common.client.CobblemonClient
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.battle.ActiveClientBattlePokemon
|
||||
@@ -127,7 +128,7 @@ class BattleTargetSelection(
|
||||
private val isMultiTarget = multiTargetList?.firstOrNull { it.getPNX() == target.getPNX() } != null
|
||||
private val isCurrentPokemon = request.activePokemon.battlePokemon?.uuid == target.battlePokemon!!.uuid
|
||||
|
||||
open val response: MoveActionResponse get() = MoveActionResponse(targetSelection.move.id, responseTarget)
|
||||
open val response: MoveActionResponse get() = MoveActionResponse(targetSelection.move.id, responseTarget, gimmickID)
|
||||
val state = FloatingState()
|
||||
|
||||
open val selectable: Boolean get() = isMultiTarget || (responseTarget != null)
|
||||
@@ -311,6 +312,13 @@ class BattleTargetSelection(
|
||||
fun onClick() {
|
||||
if (!selectable) return
|
||||
targetSelection.playDownSound(Minecraft.getInstance().soundManager)
|
||||
// If a gimmick is used, remove the ability to use it on any pending action requests ahead of it
|
||||
if (response.gimmickID != null) {
|
||||
val gimmick = ShowdownMoveset.Gimmick.entries.first { it.id == response.gimmickID }
|
||||
CobblemonClient.battle?.pendingActionRequests?.forEach {
|
||||
it.moveSet?.pendingGimmickUsedThisTurn?.add(gimmick)
|
||||
}
|
||||
}
|
||||
targetSelection.battleGUI.selectAction(targetSelection.request, response)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -74,12 +74,12 @@ class InteractWheelButton(
|
||||
y = y,
|
||||
width = width,
|
||||
height = height,
|
||||
vOffset = if ((isHovered(mouseX.toFloat(), mouseY.toFloat()) || isFocused) && isEnabled) height else 0,
|
||||
vOffset = if (isHovered(mouseX.toFloat(), mouseY.toFloat()) && isEnabled) height else 0,
|
||||
textureHeight = height * 2,
|
||||
alpha = if (isEnabled) 1f else 0.4F
|
||||
)
|
||||
|
||||
if(isEnabled && (isHovered(mouseX.toFloat(), mouseY.toFloat()) || isFocused)){
|
||||
if(isEnabled && isHovered(mouseX.toFloat(), mouseY.toFloat())){
|
||||
tooltipText?.let {
|
||||
context.renderTooltip(Minecraft.getInstance().font, Component.translatable(it), mouseX, mouseY)
|
||||
}
|
||||
|
||||
+4
-4
@@ -23,9 +23,9 @@ class InteractWheelGUI(private val options: Multimap<Orientation, InteractWheelO
|
||||
private val backgroundResource = cobblemonResource("textures/gui/interact/interact_wheel_base.png")
|
||||
}
|
||||
|
||||
val buttons = mutableListOf<InteractWheelButton>()
|
||||
var maxPage = 1
|
||||
var currentPage = 0
|
||||
private val buttons = mutableListOf<InteractWheelButton>()
|
||||
private var maxPage = 1
|
||||
private var currentPage = 0
|
||||
override fun renderBlurredBackground(delta: Float) { }
|
||||
override fun renderMenuBackground(context: GuiGraphics) {}
|
||||
|
||||
@@ -77,7 +77,7 @@ class InteractWheelGUI(private val options: Multimap<Orientation, InteractWheelO
|
||||
currentPage = page
|
||||
buttons.forEach { removeWidget(it) }
|
||||
buttons.clear()
|
||||
val orientations = Orientation.entries.toTypedArray()
|
||||
val orientations = Orientation.values()
|
||||
orientations.forEach { orientation ->
|
||||
val option = options[orientation].toList().getOrNull(page)
|
||||
addButton(orientation, option)
|
||||
|
||||
-319
@@ -1,319 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.integration.controlify
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonItems
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.client.CobblemonClient
|
||||
import com.cobblemon.mod.common.client.CobblemonClient.ridingTurnInputHandler
|
||||
import com.cobblemon.mod.common.client.gui.battle.BattleGUI
|
||||
import com.cobblemon.mod.common.client.gui.behaviour.BehaviourEditorScreen
|
||||
import com.cobblemon.mod.common.client.gui.config.CobblemonConfigScreen
|
||||
import com.cobblemon.mod.common.client.gui.cookingpot.CookingPotScreen
|
||||
import com.cobblemon.mod.common.client.gui.debug.riding.RidingStatsDebugGUI
|
||||
import com.cobblemon.mod.common.client.gui.dialogue.DialogueScreen
|
||||
import com.cobblemon.mod.common.client.gui.interact.battleRequest.BattleConfigureGUI
|
||||
import com.cobblemon.mod.common.client.gui.interact.moveselect.MoveSelectGUI
|
||||
import com.cobblemon.mod.common.client.gui.interact.partyselect.PartySelectGUI
|
||||
import com.cobblemon.mod.common.client.gui.interact.wheel.InteractWheelGUI
|
||||
import com.cobblemon.mod.common.client.gui.npc.NPCEditorScreen
|
||||
import com.cobblemon.mod.common.client.gui.pc.PCGUI
|
||||
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUI
|
||||
import com.cobblemon.mod.common.client.gui.pokenav.PokeNav
|
||||
import com.cobblemon.mod.common.client.gui.snapshots.SnapshotWarningScreen
|
||||
import com.cobblemon.mod.common.client.gui.startselection.StarterSelectionScreen
|
||||
import com.cobblemon.mod.common.client.gui.summary.Summary
|
||||
import com.cobblemon.mod.common.client.gui.trade.TradeGUI
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.CobblemonGUIProcessor
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.InteractWheelProcessor
|
||||
import com.cobblemon.mod.common.client.keybind.CobblemonKeyBinds
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import dev.isxander.controlify.api.ControlifyApi
|
||||
import dev.isxander.controlify.api.bind.ControlifyBindApi
|
||||
import dev.isxander.controlify.api.bind.InputBindingBuilder
|
||||
import dev.isxander.controlify.api.bind.InputBindingSupplier
|
||||
import dev.isxander.controlify.api.entrypoint.ControlifyEntrypoint
|
||||
import dev.isxander.controlify.api.entrypoint.InitContext
|
||||
import dev.isxander.controlify.api.entrypoint.PreInitContext
|
||||
import dev.isxander.controlify.bindings.BindContext
|
||||
import dev.isxander.controlify.bindings.ControlifyBindings
|
||||
import dev.isxander.controlify.bindings.RadialIcons
|
||||
import dev.isxander.controlify.screenop.ScreenProcessorFactory
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.screens.Screen
|
||||
import net.minecraft.client.player.LocalPlayer
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.item.Items
|
||||
import org.joml.Vector2d
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.full.primaryConstructor
|
||||
|
||||
class CobblemonControlifyEntrypoint : ControlifyEntrypoint {
|
||||
override fun onControlifyInit(initContext: InitContext) {
|
||||
ridingTurnInputHandler.put(
|
||||
cobblemonResource("compat.controlify"),
|
||||
({ localPlayer: LocalPlayer, xDelta: Double, yDelta: Double, deltaTime: Double ->
|
||||
val vec = Vector2d(xDelta, yDelta)
|
||||
val controller = initContext.controlify().currentController.getOrNull()
|
||||
val vehicle = localPlayer.vehicle
|
||||
if (vehicle is OrientationControllable && vehicle.orientationController.isActive() && initContext.controlify().currentInputMode().isController && controller != null){
|
||||
val multiplier = deltaTime * 1500
|
||||
val config = controller.input().getOrNull()?.config()?.config()
|
||||
val vSensitivity = config?.vLookSensitivity ?: 0.9f
|
||||
val hSensitivity = config?.hLookSensitivity ?: 1f
|
||||
|
||||
// Should never be null once bindings are set
|
||||
var vAxis = (RIDING_DOWN!!.on(controller).analogueNow() - RIDING_UP!!.on(controller).analogueNow()).toDouble()
|
||||
var hAxis = (RIDING_RIGHT!!.on(controller).analogueNow() - RIDING_LEFT!!.on(controller).analogueNow()).toDouble()
|
||||
|
||||
vAxis *= multiplier * vSensitivity
|
||||
hAxis *= multiplier * hSensitivity
|
||||
vec.x = hAxis
|
||||
vec.y = vAxis
|
||||
}
|
||||
vec
|
||||
})
|
||||
)
|
||||
|
||||
CobblemonClient.ridingSprintHandler.put(
|
||||
cobblemonResource("compat.controlify")
|
||||
) {
|
||||
initContext.controlify().currentController.getOrNull()?.let { ControlifyBindings.SPRINT.on(it).digitalNow() } == true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onControlifyPreInit(initContext: PreInitContext) {
|
||||
val bindings = ControlifyBindApi.get()
|
||||
bindings.registerBindContext(ORIENTATION_CONTROLLER_ACTIVE)
|
||||
|
||||
RIDING_UP =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("riding_up"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("controlify.bind.cobblemon.riding_up"))
|
||||
.allowedContexts(ORIENTATION_CONTROLLER_ACTIVE, BindContext.IN_GAME)
|
||||
}
|
||||
|
||||
RIDING_DOWN =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("riding_down"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("controlify.bind.cobblemon.riding_down"))
|
||||
.allowedContexts(ORIENTATION_CONTROLLER_ACTIVE, BindContext.IN_GAME)
|
||||
}
|
||||
|
||||
RIDING_LEFT =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("riding_left"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("controlify.bind.cobblemon.riding_left"))
|
||||
.allowedContexts(ORIENTATION_CONTROLLER_ACTIVE, BindContext.IN_GAME)
|
||||
}
|
||||
|
||||
RIDING_RIGHT =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("riding_right"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("controlify.bind.cobblemon.riding_right"))
|
||||
.allowedContexts(ORIENTATION_CONTROLLER_ACTIVE, BindContext.IN_GAME)
|
||||
}
|
||||
|
||||
HIDE_PARTY =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("hide_party"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("key.cobblemon.hideparty"))
|
||||
.allowedContexts(BindContext.IN_GAME)
|
||||
.radialCandidate(RadialIcons.getItem(Items.BARRIER))
|
||||
.addKeyCorrelation(CobblemonKeyBinds.HIDE_PARTY)
|
||||
.keyEmulation(CobblemonKeyBinds.HIDE_PARTY)
|
||||
}
|
||||
|
||||
SUMMARY =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("summary"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("key.cobblemon.summary"))
|
||||
.allowedContexts(BindContext.IN_GAME)
|
||||
.radialCandidate(RadialIcons.getItem(CobblemonItems.GREAT_BALL))
|
||||
.addKeyCorrelation(CobblemonKeyBinds.SUMMARY)
|
||||
.keyEmulation(CobblemonKeyBinds.SUMMARY)
|
||||
}
|
||||
|
||||
PARTY_OVERLAY_DOWN =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("party_overlay_down"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("key.cobblemon.downshiftparty"))
|
||||
.allowedContexts(HAS_POKEMON, BindContext.IN_GAME)
|
||||
.radialCandidate(RadialIcons.EMPTY)
|
||||
.addKeyCorrelation(CobblemonKeyBinds.PARTY_OVERLAY_DOWN)
|
||||
.keyEmulation(CobblemonKeyBinds.PARTY_OVERLAY_DOWN)
|
||||
}
|
||||
|
||||
PARTY_OVERLAY_UP =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("party_overlay_up"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("key.cobblemon.upshiftparty"))
|
||||
.allowedContexts(HAS_POKEMON, BindContext.IN_GAME)
|
||||
.radialCandidate(RadialIcons.EMPTY)
|
||||
.addKeyCorrelation(CobblemonKeyBinds.PARTY_OVERLAY_UP)
|
||||
.keyEmulation(CobblemonKeyBinds.PARTY_OVERLAY_DOWN)
|
||||
}
|
||||
|
||||
SEND_OUT_POKEMON =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("send_out_pokemon"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("key.cobblemon.throwpartypokemon"))
|
||||
.allowedContexts(HAS_POKEMON, BindContext.IN_GAME)
|
||||
.radialCandidate(RadialIcons.getItem(CobblemonItems.POKE_BALL))
|
||||
.addKeyCorrelation(CobblemonKeyBinds.SEND_OUT_POKEMON)
|
||||
.keyEmulation(CobblemonKeyBinds.SEND_OUT_POKEMON)
|
||||
}
|
||||
|
||||
|
||||
RIDING_FREELOOK =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("riding_freelook"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("key.cobblemon.ridingfreelook"))
|
||||
.allowedContexts(RIDING_POKEMON, BindContext.IN_GAME)
|
||||
.radialCandidate(RadialIcons.EMPTY)
|
||||
.addKeyCorrelation(CobblemonKeyBinds.RIDING_FREELOOK)
|
||||
.keyEmulation(CobblemonKeyBinds.RIDING_FREELOOK)
|
||||
}
|
||||
|
||||
INTERACT_WHEEL_UP_AXIS =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("interact_wheel_up"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("controlify.bind.cobblemon.interact_wheel_up"))
|
||||
.allowedContexts(INTERACT_WHEEL_SCREEN, BindContext.IN_GAME)
|
||||
}
|
||||
|
||||
INTERACT_WHEEL_DOWN_AXIS =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("interact_wheel_down"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("controlify.bind.cobblemon.interact_wheel_down"))
|
||||
.allowedContexts(INTERACT_WHEEL_SCREEN, BindContext.IN_GAME)
|
||||
}
|
||||
|
||||
INTERACT_WHEEL_RIGHT_AXIS =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("interact_wheel_right"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("controlify.bind.cobblemon.interact_wheel_right"))
|
||||
.allowedContexts(INTERACT_WHEEL_SCREEN, BindContext.IN_GAME)
|
||||
}
|
||||
|
||||
INTERACT_WHEEL_LEFT_AXIS =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("interact_wheel_left"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("controlify.bind.cobblemon.interact_wheel_left"))
|
||||
.allowedContexts(INTERACT_WHEEL_SCREEN, BindContext.IN_GAME)
|
||||
}
|
||||
|
||||
|
||||
addProcessor(InteractWheelGUI::class, InteractWheelProcessor::class)
|
||||
// This is the lazy way to do all of these (just using the vmouse), if someone with more time and dedication did this that would be better
|
||||
addProcessor(BattleGUI::class, CobblemonGUIProcessor::class)
|
||||
addProcessor(BehaviourEditorScreen::class, CobblemonGUIProcessor::class)
|
||||
addProcessor(CobblemonConfigScreen::class, CobblemonGUIProcessor::class)
|
||||
addProcessor(CookingPotScreen::class, CobblemonGUIProcessor::class)
|
||||
addProcessor(RidingStatsDebugGUI::class, CobblemonGUIProcessor::class)
|
||||
addProcessor(DialogueScreen::class, CobblemonGUIProcessor::class)
|
||||
addProcessor(BattleConfigureGUI::class, CobblemonGUIProcessor::class)
|
||||
addProcessor(MoveSelectGUI::class, CobblemonGUIProcessor::class)
|
||||
addProcessor(PartySelectGUI::class, CobblemonGUIProcessor::class)
|
||||
addProcessor(NPCEditorScreen::class, CobblemonGUIProcessor::class)
|
||||
addProcessor(PCGUI::class, CobblemonGUIProcessor::class)
|
||||
addProcessor(PokedexGUI::class, CobblemonGUIProcessor::class)
|
||||
addProcessor(PokeNav::class, CobblemonGUIProcessor::class)
|
||||
addProcessor(SnapshotWarningScreen::class, CobblemonGUIProcessor::class)
|
||||
addProcessor(StarterSelectionScreen::class, CobblemonGUIProcessor::class)
|
||||
addProcessor(Summary::class, CobblemonGUIProcessor::class)
|
||||
addProcessor(TradeGUI::class, CobblemonGUIProcessor::class)
|
||||
}
|
||||
|
||||
override fun onControllersDiscovered(controlifyApi: ControlifyApi) {
|
||||
}
|
||||
|
||||
// This is jank, but I did it after I got my wisdom teeth extracted so tbh I think I did good enough, but I won't be offended if someone changes it to something sane.
|
||||
fun addProcessor(t: KClass<out Screen>, processorClazz: KClass<out CobblemonGUIProcessor>) {
|
||||
ScreenProcessorFactory.registerProvider(t.java) {
|
||||
processorClazz.primaryConstructor?.call(it)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
var RIDING_UP: InputBindingSupplier? = null
|
||||
var RIDING_DOWN: InputBindingSupplier? = null
|
||||
var RIDING_RIGHT: InputBindingSupplier? = null
|
||||
var RIDING_LEFT: InputBindingSupplier? = null
|
||||
var HIDE_PARTY: InputBindingSupplier? = null
|
||||
var SUMMARY: InputBindingSupplier? = null
|
||||
var PARTY_OVERLAY_DOWN: InputBindingSupplier? = null
|
||||
var PARTY_OVERLAY_UP: InputBindingSupplier? = null
|
||||
var SEND_OUT_POKEMON: InputBindingSupplier? = null
|
||||
var RIDING_FREELOOK: InputBindingSupplier? = null
|
||||
var INTERACT_WHEEL_UP_AXIS: InputBindingSupplier? = null
|
||||
var INTERACT_WHEEL_DOWN_AXIS: InputBindingSupplier? = null
|
||||
var INTERACT_WHEEL_LEFT_AXIS: InputBindingSupplier? = null
|
||||
var INTERACT_WHEEL_RIGHT_AXIS: InputBindingSupplier? = null
|
||||
|
||||
val RIDING_POKEMON: BindContext = BindContext(
|
||||
cobblemonResource("riding"),
|
||||
{ mc: Minecraft ->
|
||||
mc.player?.vehicle is PokemonEntity
|
||||
}
|
||||
)
|
||||
|
||||
val ORIENTATION_CONTROLLER_ACTIVE: BindContext = BindContext(
|
||||
cobblemonResource("orientation_controller_active"),
|
||||
{ mc: Minecraft ->
|
||||
val localPlayer = mc.player
|
||||
if (localPlayer == null) return@BindContext false
|
||||
val vehicle = localPlayer.vehicle
|
||||
vehicle is OrientationControllable && vehicle.getOrientationController().isActive()
|
||||
}
|
||||
)
|
||||
|
||||
val HAS_POKEMON: BindContext = BindContext(
|
||||
cobblemonResource("has_pokemon"),
|
||||
{mc: Minecraft ->
|
||||
!CobblemonClient.storage.party.isEmpty()
|
||||
}
|
||||
)
|
||||
|
||||
val INTERACT_WHEEL_SCREEN: BindContext = BindContext(
|
||||
cobblemonResource("wheel_screen"),
|
||||
{ it.screen is InteractWheelGUI}
|
||||
)
|
||||
}
|
||||
}
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.integration.controlify.gui
|
||||
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponentManager
|
||||
import dev.isxander.controlify.screenop.ScreenProcessor
|
||||
import dev.isxander.controlify.virtualmouse.VirtualMouseBehaviour
|
||||
import net.minecraft.client.gui.screens.Screen
|
||||
|
||||
open class CobblemonGUIProcessor(open val screen: Screen) : ScreenProcessor<Screen>(screen) {
|
||||
val controllerComponentManager = ControllerComponentManager(screen)
|
||||
|
||||
override fun virtualMouseBehaviour(): VirtualMouseBehaviour {
|
||||
return VirtualMouseBehaviour.DISABLED
|
||||
}
|
||||
}
|
||||
-70
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.integration.controlify.gui
|
||||
|
||||
import com.cobblemon.mod.common.client.gui.interact.wheel.InteractWheelGUI
|
||||
import com.cobblemon.mod.common.client.integration.controlify.CobblemonControlifyEntrypoint
|
||||
import dev.isxander.controlify.controller.ControllerEntity
|
||||
import dev.isxander.controlify.controller.haptic.HapticEffects
|
||||
import dev.isxander.controlify.screenop.ScreenControllerEventListener
|
||||
import net.minecraft.util.Mth
|
||||
import kotlin.math.abs
|
||||
|
||||
|
||||
// Lots of this is taken from the RadialMenu in Controlify to make this screen feel consistent with it
|
||||
class InteractWheelProcessor(override val screen: InteractWheelGUI) : CobblemonGUIProcessor(screen), ScreenControllerEventListener {
|
||||
private var selectedButton = -1
|
||||
private var idleTicks: Int = 0
|
||||
private var idleTicksTimeout: Int? = null
|
||||
|
||||
init {
|
||||
addEventListener(this)
|
||||
}
|
||||
|
||||
override fun onControllerInput(controller: ControllerEntity) {
|
||||
if (idleTicksTimeout == null) {
|
||||
idleTicksTimeout = controller.input().orElseThrow().confObj().radialButtonFocusTimeoutTicks
|
||||
}
|
||||
|
||||
// If not created from entrypoint then something is very wrong
|
||||
val x = CobblemonControlifyEntrypoint.INTERACT_WHEEL_RIGHT_AXIS!!.on(controller).analogueNow()
|
||||
- CobblemonControlifyEntrypoint.INTERACT_WHEEL_LEFT_AXIS!!.on(controller).analogueNow()
|
||||
val y = CobblemonControlifyEntrypoint.INTERACT_WHEEL_DOWN_AXIS!!.on(controller).analogueNow()
|
||||
- CobblemonControlifyEntrypoint.INTERACT_WHEEL_UP_AXIS!!.on(controller).analogueNow()
|
||||
val threshold = controller.input().orElseThrow().config().config().buttonActivationThreshold
|
||||
|
||||
if (abs(x) >= threshold || abs(y) >= threshold) {
|
||||
val angle = Mth.wrapDegrees(Mth.RAD_TO_DEG * Mth.atan2(y.toDouble(), x.toDouble()) - 90f) + 180f
|
||||
val buttonCount = screen.buttons.size
|
||||
val each = 360f / buttonCount
|
||||
|
||||
val newSelected = Mth.floor((angle + each / 2f) / each) % buttonCount
|
||||
if (newSelected != selectedButton) {
|
||||
selectedButton = newSelected
|
||||
controller.hdHaptics().ifPresent { haptics -> haptics.playHaptic(HapticEffects.NAVIGATE) }
|
||||
}
|
||||
|
||||
for (button in 0..<buttonCount) {
|
||||
val selected = button == selectedButton
|
||||
screen.buttons[button].isFocused = selected
|
||||
}
|
||||
|
||||
idleTicks = 0
|
||||
} else {
|
||||
idleTicks = idleTicks+ 1
|
||||
if (idleTicks>= idleTicksTimeout!! && selectedButton != -1) {
|
||||
selectedButton = -1
|
||||
for (button in screen.buttons) {
|
||||
button.isFocused = false
|
||||
}
|
||||
controller.hdHaptics().ifPresent { haptics -> haptics.playHaptic(HapticEffects.NAVIGATE) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
package com.cobblemon.mod.common.client.integration.controlify.gui.component
|
||||
|
||||
import net.minecraft.client.gui.components.events.GuiEventListener
|
||||
import net.minecraft.client.gui.screens.Screen
|
||||
|
||||
class ControllerComponent<T : Screen> {
|
||||
var left: (T) -> ControllerComponent<T>? = { null }
|
||||
var right: (T) -> ControllerComponent<T>? = { null }
|
||||
var up: (T) -> ControllerComponent<T>? = { null }
|
||||
var down: (T) -> ControllerComponent<T>? = { null }
|
||||
|
||||
var associatedGUIElement: GuiEventListener? = null
|
||||
|
||||
fun pairLeft(leftComponent: ControllerComponent<T>) {
|
||||
left = { leftComponent }
|
||||
leftComponent.right = { this }
|
||||
}
|
||||
|
||||
fun pairRight(rightComponent: ControllerComponent<T>) {
|
||||
right = { rightComponent }
|
||||
rightComponent.left = { this }
|
||||
}
|
||||
|
||||
fun pairUp(upComponent: ControllerComponent<T>) {
|
||||
up = { upComponent }
|
||||
upComponent.down = { this }
|
||||
}
|
||||
|
||||
fun pairDown(downComponent: ControllerComponent<T>) {
|
||||
down = { downComponent }
|
||||
downComponent.up = { this }
|
||||
}
|
||||
}
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
package com.cobblemon.mod.common.client.integration.controlify.gui.component
|
||||
|
||||
import net.minecraft.client.gui.screens.Screen
|
||||
|
||||
class ControllerComponentManager<T : Screen>(val screen: T) {
|
||||
var focused: ControllerComponent<T>?
|
||||
get() = focused
|
||||
set(value) {
|
||||
focused = value
|
||||
focused?.associatedGUIElement?.let { screen.focused = it }
|
||||
}
|
||||
|
||||
fun left() = focused?.left?.invoke(screen)?.let { focused = it }
|
||||
fun right() = focused?.right?.invoke(screen)?.let { focused = it }
|
||||
fun up() = focused?.up?.invoke(screen)?.let { focused = it }
|
||||
fun down() = focused?.down?.invoke(screen)?.let { focused = it }
|
||||
}
|
||||
+9
-9
@@ -143,18 +143,18 @@ object PartySendBinding : CobblemonBlockingKeyBinding(
|
||||
}
|
||||
|
||||
private fun canAttemptDismount(player: LocalPlayer, selectedPartyPokemon: Pokemon?): Boolean {
|
||||
if (player.vehicle !is PokemonEntity) return false
|
||||
val vehicle = player.vehicle as PokemonEntity
|
||||
if (player != vehicle.controllingPassenger) {
|
||||
return true
|
||||
}
|
||||
val vehicle = player.vehicle as? PokemonEntity ?: return false
|
||||
|
||||
if (player != vehicle.controllingPassenger) return true
|
||||
|
||||
val isAirRide = vehicle.ridingController?.context?.style == RidingStyle.AIR
|
||||
val hasLandRide = vehicle.rideProp.behaviours?.get(RidingStyle.LAND) != null
|
||||
return if (isAirRide && hasLandRide) {
|
||||
false
|
||||
} else {
|
||||
vehicle.pokemon.uuid == selectedPartyPokemon?.uuid
|
||||
|
||||
if (!Cobblemon.config.enableInFlightDismounting && isAirRide && hasLandRide) {
|
||||
return false
|
||||
}
|
||||
|
||||
return vehicle.pokemon.uuid == selectedPartyPokemon?.uuid
|
||||
}
|
||||
|
||||
private fun isRidingPokemon(player: LocalPlayer, ignoreControlling: Boolean = false): Boolean {
|
||||
|
||||
+1
-1
@@ -206,7 +206,7 @@ fun generateAdditionalRideBoostsTooltip(stack: ItemStack): MutableList<Component
|
||||
val resultLines = mutableListOf<Component>()
|
||||
resultLines.add(rideBoostSeasoningHeader)
|
||||
|
||||
for ((stat, value) in boosts) {
|
||||
for ((stat, value) in boosts.toSortedMap()) {
|
||||
val statName = stat.displayName.also { it.style = it.style.withColor(stat.flavour.colour) }
|
||||
val valueText = if (value < 0) {
|
||||
Component.literal("$value").red()
|
||||
|
||||
@@ -329,6 +329,9 @@ class CobblemonConfig {
|
||||
@CobblemonConfigField(Category.Riding, lang = "remember_riding_camera", CLIENT)
|
||||
var rememberRidingCamera = false
|
||||
|
||||
@CobblemonConfigField(Category.Riding, lang = "enable_in_flight_dismounting", CLIENT)
|
||||
var enableInFlightDismounting = false
|
||||
|
||||
@CobblemonConfigField(Category.Debug, lang = "enable_debug_keys", CLIENT)
|
||||
var enableDebugKeys = false
|
||||
|
||||
|
||||
@@ -269,9 +269,6 @@ 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 && pather.canPathThroughSaccLeaves()) {
|
||||
return vec.y + 0.5
|
||||
}
|
||||
return if ((canFloat()) && blockGetter.getFluidState(blockPos).`is`(FluidTags.WATER)) vec.y + 0.5 else super.getGroundY(vec)
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import juuxel.adorn.block.variant.CompatBlockVariantSet
|
||||
|
||||
class AdornCompatibility : CompatBlockVariantSet() {
|
||||
override fun getWoodVariants(): List<BlockVariant?>? {
|
||||
return this.createVariants({ BlockVariant.Wood(it) }, "apricorn")
|
||||
return this.createVariants({ BlockVariant.Wood(it) }, "apricorn", "saccharine")
|
||||
}
|
||||
|
||||
override fun getModId(): String? {
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.advancement.criterion.PokemonInteractContext
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.battles.BagItemActionResponse
|
||||
import com.cobblemon.mod.common.battles.BagItems
|
||||
import com.cobblemon.mod.common.battles.BattleRules
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
@@ -41,7 +42,7 @@ interface BagItemLike {
|
||||
fun handleInteraction(player: ServerPlayer, battlePokemon: BattlePokemon, stack: ItemStack): Boolean {
|
||||
val battle = battlePokemon.actor.battle
|
||||
val bagItem = getBagItem(stack) ?: return false
|
||||
if (!battlePokemon.actor.canFitForcedAction()) {
|
||||
if (!battlePokemon.actor.canFitForcedAction() || battle.format.ruleSet.contains(BattleRules.BAG_CLAUSE)) {
|
||||
player.sendSystemMessage(battleLang("bagitem.cannot").red())
|
||||
return false
|
||||
}
|
||||
|
||||
+7
-2
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.net.serverhandling.riding
|
||||
|
||||
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.DismountPokemonPacket
|
||||
import net.minecraft.server.MinecraftServer
|
||||
@@ -25,12 +26,16 @@ object DismountPokemonPacketHandler : ServerNetworkPacketHandler<DismountPokemon
|
||||
|
||||
val pokemon = player.vehicle as PokemonEntity
|
||||
if (!canPlayerStopRidingPokemon(pokemon, player)) return
|
||||
|
||||
val isRidingInAir = pokemon.ridingController?.context?.style == RidingStyle.AIR
|
||||
|
||||
if (pokemon.controllingPassenger == player) {
|
||||
pokemon.passengers.forEach { it.stopRiding() }
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
player.stopRiding()
|
||||
}
|
||||
|
||||
if (isRidingInAir) pokemon.setFlying(true)
|
||||
}
|
||||
|
||||
private fun canPlayerStopRidingPokemon(pokemon: PokemonEntity, player: ServerPlayer): Boolean {
|
||||
|
||||
@@ -199,6 +199,9 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
|
||||
var form = species.standardForm
|
||||
set(value) {
|
||||
// If nothing actually changed, avoid running heavy logic (e.g. updateMovesOnFormChange when the form hasn't really "changed")
|
||||
if (field == value) return
|
||||
|
||||
// Species updates already update HP but just a form change may require it
|
||||
// Moved to before the field was set else it won't actually do the hp calc proper <3
|
||||
val quotient = clamp(currentHealth / maxHealth.toFloat(), 0F, 1F)
|
||||
@@ -2144,16 +2147,26 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
*/
|
||||
open fun self(): Pokemon = this
|
||||
|
||||
|
||||
/**
|
||||
* Function that sanitizes specific form-related moves when the form of this Pokémon changes.
|
||||
* We only want to sanitize `form_change` moves here so that intended illegalities from the user are preserved.
|
||||
*
|
||||
* E.g, Removing Overheat from Rotom when it is no longer Rotom-Heat and the target form is not compatible with Overheat.
|
||||
*/
|
||||
private fun updateMovesOnFormChange(newForm: FormData) {
|
||||
if (this.isClient) {
|
||||
return
|
||||
}
|
||||
if (this.isClient) return
|
||||
|
||||
val oldFormChangeMoves = this.form.moves.formChangeMoves.toSet()
|
||||
|
||||
// Only remove moves that were provided by the old form's form-change moves AND are not learnable by the new form
|
||||
for (i in 0 until MoveSet.MOVE_COUNT) {
|
||||
val move = this.moveSet[i]
|
||||
if (move != null && !LearnsetQuery.ANY.canLearn(move.template, newForm.moves)) {
|
||||
if (move != null && move.template in oldFormChangeMoves) {
|
||||
this.moveSet.setMove(i, null)
|
||||
}
|
||||
}
|
||||
|
||||
val benchedIterator = this.benchedMoves.iterator()
|
||||
while (benchedIterator.hasNext()) {
|
||||
val benchedMove = benchedIterator.next()
|
||||
@@ -2161,11 +2174,18 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
benchedIterator.remove()
|
||||
}
|
||||
}
|
||||
// Add form change moves
|
||||
|
||||
// Add new form's form-change moves
|
||||
newForm.moves.formChangeMoves.forEach { move ->
|
||||
// Under the hood these check if the moves already exist
|
||||
this.benchedMoves.add(BenchedMove(move, 0))
|
||||
if (this.moveSet.filterNotNull().none { it.template == move }) {
|
||||
if (this.moveSet.hasSpace()) {
|
||||
this.moveSet.add(move.create())
|
||||
} else {
|
||||
this.benchedMoves.add(BenchedMove(move, 0))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If moveset is empty try to find one valid move to fill it
|
||||
if (this.moveSet.filterNotNull().isEmpty()) {
|
||||
val benchedMove = this.benchedMoves.firstOrNull()
|
||||
|
||||
@@ -562,8 +562,8 @@ class OmniPathNodeMaker : NodeEvaluator() {
|
||||
//// PathType.WALKABLE
|
||||
//// } else if (blockState.canPathfindThrough(world, pos, NavigationType.AIR) && !blockStateBelow.isSideSolid(world, below, Direction.UP, SideShapeType.FULL)) {
|
||||
//// PathType.OPEN
|
||||
// } else if (blockState.`is`(BlockTags.LEAVES) && blockState.block == CobblemonBlocks.SACCHARINE_LEAVES && canPathThroughLeaves()) {
|
||||
// return PathType.OPEN
|
||||
if (canPathThroughLeaves() && blockState.block == CobblemonBlocks.SACCHARINE_LEAVES)
|
||||
return PathType.OPEN
|
||||
// } else PathType.BLOCKED
|
||||
|
||||
// This is the 1.6.1 logic but with some optimizations
|
||||
@@ -633,9 +633,6 @@ class OmniPathNodeMaker : NodeEvaluator() {
|
||||
pfContext, x, y, z, sizeX, sizeY, sizeZ, canOpenDoors, canPassDoors, set, PathType.BLOCKED, BlockPos(x, y, z), returnedEarlyPathType
|
||||
)
|
||||
|
||||
if (PathType.LEAVES in set) {
|
||||
return PathType.OPEN
|
||||
}
|
||||
|
||||
if (PathType.FENCE in set) {
|
||||
return PathType.FENCE
|
||||
@@ -755,7 +752,7 @@ class OmniPathNodeMaker : NodeEvaluator() {
|
||||
} else if (type == PathType.RAIL && block !is BaseRailBlock && pfContext.getCachedBlockState(pos.below()).block !is BaseRailBlock) {
|
||||
PathType.UNPASSABLE_RAIL
|
||||
} else if (type == PathType.LEAVES) {
|
||||
if (blockState.block === CobblemonBlocks.SACCHARINE_LEAVES && canPathThroughLeaves()) {
|
||||
if (canPathThroughLeaves() && blockState.block === CobblemonBlocks.SACCHARINE_LEAVES) {
|
||||
PathType.OPEN
|
||||
} else {
|
||||
PathType.BLOCKED
|
||||
|
||||
+4
-8
@@ -6,19 +6,15 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.pokemon.properties.tags
|
||||
package com.cobblemon.mod.common.pokemon.properties
|
||||
|
||||
import com.cobblemon.mod.common.api.properties.CustomPokemonPropertyType
|
||||
import com.cobblemon.mod.common.pokemon.properties.StringProperty
|
||||
|
||||
object PokemonFlagProperty : CustomPokemonPropertyType<StringProperty> {
|
||||
|
||||
private const val KEY = "tag"
|
||||
|
||||
override val keys = setOf(KEY)
|
||||
object LabelProperty : CustomPokemonPropertyType<StringProperty> {
|
||||
override val keys = setOf("label", "tag")
|
||||
override val needsKey = true
|
||||
|
||||
override fun fromString(value: String?) = if (value == null) null else StringProperty(KEY, value, { _, _ -> }, { pokemon, underlyingValue -> pokemon.hasLabels(underlyingValue) })
|
||||
override fun fromString(value: String?) = if (value == null) null else StringProperty(keys.first(), value, { _, _ -> }, { pokemon, underlyingValue -> pokemon.hasLabels(underlyingValue) })
|
||||
|
||||
override fun examples() = emptySet<String>()
|
||||
}
|
||||
+15
-5
@@ -10,13 +10,14 @@ package com.cobblemon.mod.common.world.feature
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonBlocks
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonBiomeTags
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.core.Direction.UP
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.tags.BlockTags
|
||||
import net.minecraft.util.RandomSource
|
||||
import net.minecraft.world.item.component.CustomData
|
||||
import net.minecraft.world.level.WorldGenLevel
|
||||
import net.minecraft.world.level.block.Block.UPDATE_ALL
|
||||
import net.minecraft.world.level.block.Block.UPDATE_CLIENTS
|
||||
@@ -227,12 +228,20 @@ class SaccharineTreeFeature : Feature<BlockStateConfiguration>(BlockStateConfigu
|
||||
val i: Int = 2 + randomSource.nextInt(2)
|
||||
for (j in 0..<i) {
|
||||
if (isCombee > 0) {
|
||||
beehiveBlockEntity!!.storeBee(BeehiveBlockEntity.Occupant.create(randomSource.nextInt(599)))
|
||||
beehiveBlockEntity?.storeBee(BeehiveBlockEntity.Occupant.create(randomSource.nextInt(599)))
|
||||
} else {
|
||||
// We want to create a Pokemon entity here and turn it into a compound tag to store in the hive.
|
||||
// But creating a Pokemon entity during world generation can cause issues.
|
||||
// So instead we create custom compound tag that is a placeholder for an incomplete Pokemon.
|
||||
// This is caught and handled by BeeOccupantMixin.java, which turns it into a complete entity.
|
||||
val properties = "${POKEMON_ARGS} lvl=${LEVEL_RANGE.random()}"
|
||||
val pokemon = PokemonProperties.parse(properties)
|
||||
val entity = pokemon.createEntity(worldGenLevel.level)
|
||||
beehiveBlockEntity!!.addOccupant(entity)
|
||||
val compoundTag = CompoundTag()
|
||||
compoundTag.putString("id", POKEMON_PLACEHOLD_ID)
|
||||
compoundTag.putString("pokemonProperties", properties)
|
||||
val occupant = BeehiveBlockEntity.Occupant(
|
||||
CustomData.of(compoundTag), randomSource.nextInt(599), 600
|
||||
)
|
||||
beehiveBlockEntity?.storeBee(occupant)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -351,5 +360,6 @@ class SaccharineTreeFeature : Feature<BlockStateConfiguration>(BlockStateConfigu
|
||||
companion object {
|
||||
val POKEMON_ARGS = "combee"
|
||||
val LEVEL_RANGE = 5..15
|
||||
val POKEMON_PLACEHOLD_ID = "cobblemon_pokemon_entity_placeholder"
|
||||
}
|
||||
}
|
||||
@@ -2629,6 +2629,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.enable_in_flight_dismounting": "Enable In-Flight Dismounting",
|
||||
"cobblemon.config.ui.enable_in_flight_dismounting.tooltip": "Allows players to dismount while riding a Pokémon in the air. When disabled, dismounting is only possible while on the ground.",
|
||||
|
||||
"cobblemon.config.ui.allow_starter_on_join": "Allow Starter on Join",
|
||||
"cobblemon.config.ui.prompt_starter_once_only": "Prompt Starter Once Only",
|
||||
@@ -9457,11 +9459,5 @@
|
||||
"stat.cobblemon.reel_ins": "PokéRod Catches",
|
||||
"stat.cobblemon.riding_land": "Distance by Pokémon on Land",
|
||||
"stat.cobblemon.riding_air": "Distance by Pokémon in Air",
|
||||
"stat.cobblemon.riding_liquid": "Distance by Pokémon in Liquid",
|
||||
|
||||
"controlify.category.cobblemon.cobblemon": "Cobblemon",
|
||||
"controlify.bind.cobblemon.riding_up": "Look Up",
|
||||
"controlify.bind.cobblemon.riding_down": "Look Down",
|
||||
"controlify.bind.cobblemon.riding_left": "Look Left",
|
||||
"controlify.bind.cobblemon.riding_right": "Look Right"
|
||||
"stat.cobblemon.riding_liquid": "Distance by Pokémon in Liquid"
|
||||
}
|
||||
@@ -1,4 +1,7 @@
|
||||
{
|
||||
"parent": "minecraft:builtin/entity",
|
||||
"gui_light": "side"
|
||||
"gui_light": "side",
|
||||
"textures": {
|
||||
"particle": "cobblemon:item/poke_balls/cherish_ball"
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
{
|
||||
"defaults": {
|
||||
"cobblemon:riding_up": {
|
||||
"axis": "controlify:axis/right_stick_up"
|
||||
},
|
||||
"cobblemon:riding_down": {
|
||||
"axis": "controlify:axis/right_stick_down"
|
||||
},
|
||||
"cobblemon:riding_left": {
|
||||
"axis": "controlify:axis/right_stick_left"
|
||||
},
|
||||
"cobblemon:riding_right": {
|
||||
"axis": "controlify:axis/right_stick_right"
|
||||
},
|
||||
"cobblemon:interact_wheel_up": {
|
||||
"axis": "controlify:axis/right_stick_up"
|
||||
},
|
||||
"cobblemon:interact_wheel_down": {
|
||||
"axis": "controlify:axis/right_stick_down"
|
||||
},
|
||||
"cobblemon:interact_wheel_left": {
|
||||
"axis": "controlify:axis/right_stick_left"
|
||||
},
|
||||
"cobblemon:interact_wheel_right": {
|
||||
"axis": "controlify:axis/right_stick_right"
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"parent":"minecraft:recipes/root","rewards":{"recipes":["adorn:cobblemon/saccharine_bench"]},"criteria":{"has_slab":{"trigger":"minecraft:inventory_changed","conditions":{"items":[{"items":["cobblemon:saccharine_slab"]}]}},"has_the_recipe":{"trigger":"minecraft:recipe_unlocked","conditions":{"recipe":"adorn:cobblemon/saccharine_bench"}}},"requirements":[["has_slab","has_the_recipe"]],"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"parent":"minecraft:recipes/root","rewards":{"recipes":["adorn:cobblemon/saccharine_chair"]},"criteria":{"has_slab":{"trigger":"minecraft:inventory_changed","conditions":{"items":[{"items":["cobblemon:saccharine_slab"]}]}},"has_the_recipe":{"trigger":"minecraft:recipe_unlocked","conditions":{"recipe":"adorn:cobblemon/saccharine_chair"}}},"requirements":[["has_slab","has_the_recipe"]],"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"parent":"minecraft:recipes/root","rewards":{"recipes":["adorn:cobblemon/saccharine_coffee_table"]},"criteria":{"has_slab":{"trigger":"minecraft:inventory_changed","conditions":{"items":[{"items":["cobblemon:saccharine_slab"]}]}},"has_the_recipe":{"trigger":"minecraft:recipe_unlocked","conditions":{"recipe":"adorn:cobblemon/saccharine_coffee_table"}}},"requirements":[["has_slab","has_the_recipe"]],"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"parent":"minecraft:recipes/root","rewards":{"recipes":["adorn:cobblemon/saccharine_drawer"]},"criteria":{"has_slab":{"trigger":"minecraft:inventory_changed","conditions":{"items":[{"items":["cobblemon:saccharine_slab"]}]}},"has_the_recipe":{"trigger":"minecraft:recipe_unlocked","conditions":{"recipe":"adorn:cobblemon/saccharine_drawer"}}},"requirements":[["has_slab","has_the_recipe"]],"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"parent":"minecraft:recipes/root","rewards":{"recipes":["adorn:cobblemon/saccharine_kitchen_counter"]},"criteria":{"has_planks":{"trigger":"minecraft:inventory_changed","conditions":{"items":[{"items":["cobblemon:saccharine_planks"]}]}},"has_the_recipe":{"trigger":"minecraft:recipe_unlocked","conditions":{"recipe":"adorn:cobblemon/saccharine_kitchen_counter"}}},"requirements":[["has_planks","has_the_recipe"]],"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"parent":"minecraft:recipes/root","rewards":{"recipes":["adorn:cobblemon/saccharine_kitchen_cupboard"]},"criteria":{"has_planks":{"trigger":"minecraft:inventory_changed","conditions":{"items":[{"items":["cobblemon:saccharine_planks"]}]}},"has_kitchen_counter":{"trigger":"minecraft:inventory_changed","conditions":{"items":[{"items":["adorn:cobblemon/saccharine_kitchen_counter"]}]}},"has_the_recipe":{"trigger":"minecraft:recipe_unlocked","conditions":{"recipe":"adorn:cobblemon/saccharine_kitchen_cupboard"}}},"requirements":[["has_planks","has_kitchen_counter","has_the_recipe"]],"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"parent":"minecraft:recipes/root","rewards":{"recipes":["adorn:cobblemon/saccharine_kitchen_sink"]},"criteria":{"has_planks":{"trigger":"minecraft:inventory_changed","conditions":{"items":[{"items":["cobblemon:saccharine_planks"]}]}},"has_the_recipe":{"trigger":"minecraft:recipe_unlocked","conditions":{"recipe":"adorn:cobblemon/saccharine_kitchen_sink"}}},"requirements":[["has_planks","has_the_recipe"]],"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"parent":"minecraft:recipes/root","rewards":{"recipes":["adorn:cobblemon/saccharine_platform"]},"criteria":{"has_slab":{"trigger":"minecraft:inventory_changed","conditions":{"items":[{"items":["cobblemon:saccharine_slab"]}]}},"has_the_recipe":{"trigger":"minecraft:recipe_unlocked","conditions":{"recipe":"adorn:cobblemon/saccharine_platform"}}},"requirements":[["has_slab","has_the_recipe"]],"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"parent":"minecraft:recipes/root","rewards":{"recipes":["adorn:cobblemon/saccharine_post"]},"criteria":{"has_saccharine_planks":{"trigger":"minecraft:inventory_changed","conditions":{"items":[{"items":["cobblemon:saccharine_planks"]}]}},"has_the_recipe":{"trigger":"minecraft:recipe_unlocked","conditions":{"recipe":"adorn:cobblemon/saccharine_post"}}},"requirements":[["has_saccharine_planks","has_the_recipe"]],"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"parent":"minecraft:recipes/root","rewards":{"recipes":["adorn:cobblemon/saccharine_shelf"]},"criteria":{"has_slab":{"trigger":"minecraft:inventory_changed","conditions":{"items":[{"items":["cobblemon:saccharine_slab"]}]}},"has_the_recipe":{"trigger":"minecraft:recipe_unlocked","conditions":{"recipe":"adorn:cobblemon/saccharine_shelf"}}},"requirements":[["has_slab","has_the_recipe"]],"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"parent":"minecraft:recipes/root","rewards":{"recipes":["adorn:cobblemon/saccharine_step"]},"criteria":{"has_slab":{"trigger":"minecraft:inventory_changed","conditions":{"items":[{"items":["cobblemon:saccharine_slab"]}]}},"has_the_recipe":{"trigger":"minecraft:recipe_unlocked","conditions":{"recipe":"adorn:cobblemon/saccharine_step"}}},"requirements":[["has_slab","has_the_recipe"]],"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"parent":"minecraft:recipes/root","rewards":{"recipes":["adorn:cobblemon/saccharine_table"]},"criteria":{"has_slab":{"trigger":"minecraft:inventory_changed","conditions":{"items":[{"items":["cobblemon:saccharine_slab"]}]}},"has_the_recipe":{"trigger":"minecraft:recipe_unlocked","conditions":{"recipe":"adorn:cobblemon/saccharine_table"}}},"requirements":[["has_slab","has_the_recipe"]],"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"type":"minecraft:block","pools":[{"rolls":1,"entries":[{"type":"minecraft:item","name":"adorn:cobblemon/saccharine_bench"}],"conditions":[{"condition":"minecraft:survives_explosion"}]}],"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"type":"minecraft:block","pools":[{"rolls":1,"entries":[{"type":"minecraft:item","name":"adorn:cobblemon/saccharine_chair","conditions":[{"block":"adorn:cobblemon/saccharine_chair","properties":{"half":"lower"},"condition":"minecraft:block_state_property"}]}],"conditions":[{"condition":"minecraft:survives_explosion"}]}],"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"type":"minecraft:block","pools":[{"rolls":1,"entries":[{"type":"minecraft:item","name":"adorn:cobblemon/saccharine_coffee_table"}],"conditions":[{"condition":"minecraft:survives_explosion"}]}],"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"type":"minecraft:block","pools":[{"rolls":1,"entries":[{"type":"minecraft:item","name":"adorn:cobblemon/saccharine_drawer","functions":[{"function":"minecraft:copy_name","source":"block_entity"}]}],"conditions":[{"condition":"minecraft:survives_explosion"}]}],"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"type":"minecraft:block","pools":[{"rolls":1,"entries":[{"type":"minecraft:item","name":"adorn:cobblemon/saccharine_kitchen_counter"}],"conditions":[{"condition":"minecraft:survives_explosion"}]}],"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"type":"minecraft:block","pools":[{"rolls":1,"entries":[{"type":"minecraft:item","name":"adorn:cobblemon/saccharine_kitchen_cupboard","functions":[{"function":"minecraft:copy_name","source":"block_entity"}]}],"conditions":[{"condition":"minecraft:survives_explosion"}]}],"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"type":"minecraft:block","pools":[{"rolls":1,"entries":[{"type":"minecraft:item","name":"adorn:cobblemon/saccharine_kitchen_sink"}],"conditions":[{"condition":"minecraft:survives_explosion"}]}],"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"type":"minecraft:block","pools":[{"rolls":1,"entries":[{"type":"minecraft:item","name":"adorn:cobblemon/saccharine_platform"}],"conditions":[{"condition":"minecraft:survives_explosion"}]}],"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"type":"minecraft:block","pools":[{"rolls":1,"entries":[{"type":"minecraft:item","name":"adorn:cobblemon/saccharine_post"}],"conditions":[{"condition":"minecraft:survives_explosion"}]}],"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"type":"minecraft:block","pools":[{"rolls":1,"entries":[{"type":"minecraft:item","name":"adorn:cobblemon/saccharine_shelf"}],"conditions":[{"condition":"minecraft:survives_explosion"}]}],"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"type":"minecraft:block","pools":[{"rolls":1,"entries":[{"type":"minecraft:item","name":"adorn:cobblemon/saccharine_step"}],"conditions":[{"condition":"minecraft:survives_explosion"}]}],"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"type":"minecraft:block","pools":[{"rolls":1,"entries":[{"type":"minecraft:item","name":"adorn:cobblemon/saccharine_table"}],"conditions":[{"condition":"minecraft:survives_explosion"}]}],"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"type":"crafting_shaped","group":"adorn:bench","pattern":["SSS","S S"],"key":{"S":{"item":"cobblemon:saccharine_slab"}},"result":{"id":"adorn:cobblemon/saccharine_bench","count":2},"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"type":"crafting_shaped","group":"adorn:chair","pattern":[" S","SS","##"],"key":{"S":{"item":"cobblemon:saccharine_slab"},"#":{"tag":"c:rods/wooden"}},"result":{"id":"adorn:cobblemon/saccharine_chair","count":2},"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"type":"crafting_shaped","group":"adorn:coffee_table","pattern":["S-S","# #"],"key":{"S":{"item":"cobblemon:saccharine_slab"},"#":{"tag":"c:rods/wooden"},"-":{"tag":"c:glass_panes"}},"result":{"id":"adorn:cobblemon/saccharine_coffee_table","count":2},"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"type":"crafting_shaped","group":"adorn:drawer","pattern":["S","C","S"],"key":{"C":{"tag":"c:chests/wooden"},"S":{"item":"cobblemon:saccharine_slab"}},"result":{"id":"adorn:cobblemon/saccharine_drawer","count":2},"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"type":"crafting_shaped","group":"adorn:kitchen_counter","pattern":["SS","PP"],"key":{"S":{"item":"minecraft:polished_andesite_slab"},"P":{"item":"cobblemon:saccharine_planks"}},"result":{"id":"adorn:cobblemon/saccharine_kitchen_counter","count":3},"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"type":"crafting_shapeless","group":"adorn:kitchen_cupboard","ingredients":[{"tag":"c:chests/wooden"},{"item":"adorn:cobblemon/saccharine_kitchen_counter"},{"item":"adorn:cobblemon/saccharine_kitchen_counter"}],"result":{"id":"adorn:cobblemon/saccharine_kitchen_cupboard","count":2},"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"type":"crafting_shapeless","group":"adorn:kitchen_sink","ingredients":[{"item":"adorn:cobblemon/saccharine_kitchen_counter"},{"tag":"c:buckets/empty"}],"result":{"id":"adorn:cobblemon/saccharine_kitchen_sink","count":1},"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"type":"crafting_shaped","group":"adorn:platform","pattern":["S","P"],"key":{"S":{"item":"cobblemon:saccharine_slab"},"P":{"item":"adorn:cobblemon/saccharine_post"}},"result":{"id":"adorn:cobblemon/saccharine_platform","count":2},"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"type":"crafting_shaped","group":"adorn:post","pattern":["/","/","#"],"key":{"#":{"item":"cobblemon:saccharine_planks"},"/":{"tag":"c:rods/wooden"}},"result":{"id":"adorn:cobblemon/saccharine_post","count":4},"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"type":"crafting_shaped","group":"adorn:shelf","pattern":["---","/ /"],"key":{"-":{"item":"cobblemon:saccharine_slab"},"/":{"tag":"c:rods/wooden"}},"result":{"id":"adorn:cobblemon/saccharine_shelf","count":3},"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"type":"crafting_shaped","group":"adorn:step","pattern":["S","#"],"key":{"S":{"item":"cobblemon:saccharine_slab"},"#":{"tag":"c:rods/wooden"}},"result":{"id":"adorn:cobblemon/saccharine_step","count":1},"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"type":"crafting_shaped","group":"adorn:table","pattern":["SSS","# #","# #"],"key":{"S":{"item":"cobblemon:saccharine_slab"},"#":{"tag":"c:rods/wooden"}},"result":{"id":"adorn:cobblemon/saccharine_table","count":3},"fabric:load_conditions":[{"condition":"fabric:all_mods_loaded","values":["adorn"]}],"neoforge:conditions":[{"type":"neoforge:mod_loaded","modid":"adorn"}]}
|
||||
@@ -1,6 +1 @@
|
||||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
{ "id": "adorn:cobblemon/apricorn_bench", "required": false }
|
||||
]
|
||||
}
|
||||
{"replace":false,"values":[{"id":"adorn:cobblemon/apricorn_bench","required":false}, {"id":"adorn:cobblemon/saccharine_bench","required":false}]}
|
||||
@@ -1,6 +1 @@
|
||||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
{ "id": "adorn:cobblemon/apricorn_chair", "required": false }
|
||||
]
|
||||
}
|
||||
{"replace":false,"values":[{"id":"adorn:cobblemon/apricorn_chair","required":false}, {"id":"adorn:cobblemon/saccharine_chair","required":false}]}
|
||||
@@ -1,6 +1 @@
|
||||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
{ "id": "adorn:cobblemon/apricorn_coffee_table", "required": false }
|
||||
]
|
||||
}
|
||||
{"replace":false,"values":[{"id":"adorn:cobblemon/apricorn_coffee_table","required":false}, {"id":"adorn:cobblemon/saccharine_coffee_table","required":false}]}
|
||||
@@ -1,6 +1 @@
|
||||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
{ "id": "adorn:cobblemon/apricorn_drawer", "required": false }
|
||||
]
|
||||
}
|
||||
{"replace":false,"values":[{"id":"adorn:cobblemon/apricorn_drawer","required":false}, {"id":"adorn:cobblemon/saccharine_drawer","required":false}]}
|
||||
@@ -1,6 +1 @@
|
||||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
{ "id": "adorn:cobblemon/apricorn_kitchen_counter", "required": false }
|
||||
]
|
||||
}
|
||||
{"replace":false,"values":[{"id":"adorn:cobblemon/apricorn_kitchen_counter","required":false}, {"id":"adorn:cobblemon/saccharine_kitchen_counter","required":false}]}
|
||||
@@ -1,6 +1 @@
|
||||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
{ "id": "adorn:cobblemon/apricorn_kitchen_cupboard", "required": false }
|
||||
]
|
||||
}
|
||||
{"replace":false,"values":[{"id":"adorn:cobblemon/apricorn_kitchen_cupboard","required":false}, {"id":"adorn:cobblemon/saccharine_kitchen_cupboard","required":false}]}
|
||||
@@ -1,6 +1 @@
|
||||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
{ "id": "adorn:cobblemon/apricorn_kitchen_sink", "required": false }
|
||||
]
|
||||
}
|
||||
{"replace":false,"values":[{"id":"adorn:cobblemon/apricorn_kitchen_sink","required":false}, {"id":"adorn:cobblemon/saccharine_kitchen_sink","required":false}]}
|
||||
@@ -1,6 +1 @@
|
||||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
{ "id": "adorn:cobblemon/apricorn_table", "required": false }
|
||||
]
|
||||
}
|
||||
{"replace":false,"values":[{"id":"adorn:cobblemon/apricorn_table","required":false}, {"id":"adorn:cobblemon/saccharine_table","required":false}]}
|
||||
@@ -1,6 +1 @@
|
||||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
{ "id": "adorn:cobblemon/apricorn_platform", "required": false }
|
||||
]
|
||||
}
|
||||
{"replace":false,"values":[{"id":"adorn:cobblemon/apricorn_platform","required":false}, {"id":"adorn:cobblemon/saccharine_platform","required":false}]}
|
||||
@@ -1,6 +1 @@
|
||||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
{ "id": "adorn:cobblemon/apricorn_post", "required": false }
|
||||
]
|
||||
}
|
||||
{"replace":false,"values":[{"id":"adorn:cobblemon/apricorn_post","required":false}, {"id":"adorn:cobblemon/saccharine_post","required":false}]}
|
||||
@@ -1,6 +1 @@
|
||||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
{ "id": "adorn:cobblemon/apricorn_shelf", "required": false }
|
||||
]
|
||||
}
|
||||
{"replace":false,"values":[{"id":"adorn:cobblemon/apricorn_shelf","required":false}, {"id":"adorn:cobblemon/saccharine_shelf","required":false}]}
|
||||
@@ -1,6 +1 @@
|
||||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
{ "id": "adorn:cobblemon/apricorn_step", "required": false }
|
||||
]
|
||||
}
|
||||
{"replace":false,"values":[{"id":"adorn:cobblemon/apricorn_step","required":false}, {"id":"adorn:cobblemon/saccharine_step","required":false}]}
|
||||
@@ -1,6 +1 @@
|
||||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
{ "id": "adorn:cobblemon/apricorn_bench", "required": false }
|
||||
]
|
||||
}
|
||||
{"replace":false,"values":[{"id":"adorn:cobblemon/apricorn_bench","required":false}, {"id":"adorn:cobblemon/saccharine_bench","required":false}]}
|
||||
@@ -1,6 +1 @@
|
||||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
{ "id": "adorn:cobblemon/apricorn_chair", "required": false }
|
||||
]
|
||||
}
|
||||
{"replace":false,"values":[{"id":"adorn:cobblemon/apricorn_chair","required":false}, {"id":"adorn:cobblemon/saccharine_chair","required":false}]}
|
||||
@@ -1,6 +1 @@
|
||||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
{ "id": "adorn:cobblemon/apricorn_coffee_table", "required": false }
|
||||
]
|
||||
}
|
||||
{"replace":false,"values":[{"id":"adorn:cobblemon/apricorn_coffee_table","required":false}, {"id":"adorn:cobblemon/saccharine_coffee_table","required":false}]}
|
||||
@@ -1,6 +1 @@
|
||||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
{ "id": "adorn:cobblemon/apricorn_drawer", "required": false }
|
||||
]
|
||||
}
|
||||
{"replace":false,"values":[{"id":"adorn:cobblemon/apricorn_drawer","required":false}, {"id":"adorn:cobblemon/saccharine_drawer","required":false}]}
|
||||
@@ -1,6 +1 @@
|
||||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
{ "id": "adorn:cobblemon/apricorn_kitchen_counter", "required": false }
|
||||
]
|
||||
}
|
||||
{"replace":false,"values":[{"id":"adorn:cobblemon/apricorn_kitchen_counter","required":false}, {"id":"adorn:cobblemon/saccharine_kitchen_counter","required":false}]}
|
||||
@@ -1,6 +1 @@
|
||||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
{ "id": "adorn:cobblemon/apricorn_kitchen_cupboard", "required": false }
|
||||
]
|
||||
}
|
||||
{"replace":false,"values":[{"id":"adorn:cobblemon/apricorn_kitchen_cupboard","required":false}, {"id":"adorn:cobblemon/saccharine_kitchen_cupboard","required":false}]}
|
||||
@@ -1,6 +1 @@
|
||||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
{ "id": "adorn:cobblemon/apricorn_kitchen_sink", "required": false }
|
||||
]
|
||||
}
|
||||
{"replace":false,"values":[{"id":"adorn:cobblemon/apricorn_kitchen_sink","required":false}, {"id":"adorn:cobblemon/saccharine_kitchen_sink","required":false}]}
|
||||
@@ -1,6 +1 @@
|
||||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
{ "id": "adorn:cobblemon/apricorn_table", "required": false }
|
||||
]
|
||||
}
|
||||
{"replace":false,"values":[{"id":"adorn:cobblemon/apricorn_table","required":false}, {"id":"adorn:cobblemon/saccharine_table","required":false}]}
|
||||
@@ -1,6 +1 @@
|
||||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
{ "id": "adorn:cobblemon/apricorn_platform", "required": false }
|
||||
]
|
||||
}
|
||||
{"replace":false,"values":[{"id":"adorn:cobblemon/apricorn_platform","required":false}, {"id":"adorn:cobblemon/saccharine_platform","required":false}]}
|
||||
@@ -1,6 +1 @@
|
||||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
{ "id": "adorn:cobblemon/apricorn_post", "required": false }
|
||||
]
|
||||
}
|
||||
{"replace":false,"values":[{"id":"adorn:cobblemon/apricorn_post","required":false}, {"id":"adorn:cobblemon/saccharine_post","required":false}]}
|
||||
@@ -1,6 +1 @@
|
||||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
{ "id": "adorn:cobblemon/apricorn_shelf", "required": false }
|
||||
]
|
||||
}
|
||||
{"replace":false,"values":[{"id":"adorn:cobblemon/apricorn_shelf","required":false}, {"id":"adorn:cobblemon/saccharine_shelf","required":false}]}
|
||||
Loaded 100 of 155 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user