Compare commits

...
Author SHA1 Message Date
Nadja Reitzenstein d85fb7e160 Hack in a stupid simple "capture fail == battle" mechanic 2025-09-23 14:36:02 +02:00
Nadja Reitzenstein c56f8b098f Merge branch 'main' into fickle-behaviour
* main: (359 commits)
  Stop using Architectury Runtime Transfomers implicitly
  Re-enabled aprijuice and made creative menu aprijuice 10 in all flavours because w/e
  Release the held pokemon before sorting, closes #1663
  Fixed persistence issues for pokemon item pickup behaviours
  Fixed pokemon having the NPC dialogues memory
  Fixed pokemon in the party following and looking around while asleep, closes #1668
  Fixed crash when adding stationary Behaviour without a movement providing behaviour. Closes #1678
  Fixed terralith:shrubland not counting as plains for pokemon spawning, closes #1685
  tweak default stat ranges for some flying behaviours
  Added math.sign and math.copy_sigh molang dep update
  Grain Improvements
  update fabric-permissions-api to 0.3.1
  Behaviour tweaks
  Update mochis.json
  IV Drip
  Ride settings editor
  Fix in air dismount
  Fix riding waterwalk
  swap out textures
  Remove unnecessary check on resource
  ...

# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/api/molang/MoLangFunctions.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/pokemon/ai/FormPokemonBehaviour.kt
#	common/src/main/resources/assets/cobblemon/lang/en_us.json
#	common/src/main/resources/data/cobblemon/behaviours/looks_around.json
#	common/src/main/resources/data/cobblemon/behaviours/pokemon/auto/pokemon_core.json
#	common/src/main/resources/data/cobblemon/behaviours/pokemon/auto/pokemon_non_party.json
2025-09-21 18:53:26 +02:00
Hiroku 1b525ca3a5 Merge branch 'the-curse-of-gradle-island' into 'main'
Stop using Architectury Runtime Transfomers implicitly

See merge request cable-mc/cobblemon!1867
2025-09-20 10:27:52 +00:00
Nadja Reitzenstein 78ec9d3723 Stop using Architectury Runtime Transfomers implicitly
We don't use the Architectury Runtime Transformers in any of our direct code, so there is no downside for setting compile_only and entirely dropping them.
This necessitates the other implemented changes to our build system though as the transformers also inject code and resources from the :common project into the platform-specific ones in dev-env runs. Production jars use compile-time transformed and remapped jar shadowing for the same purpose so they are wholly unaffected by this removal.
Removing ART has several upsides: For one their dev-env injections have proven very unreliable so with this change a lot of caching issues have been fundamentally removed. They also inject deep into different parts of the JVM, making hot code reloads almost impossible to function so with this change reloads should be able to apply more often.
2025-09-20 11:42:14 +02:00
Paul afa5d22c8e Re-enabled aprijuice and made creative menu aprijuice 10 in all flavours because w/e 2025-09-20 18:50:02 +10:00
Paul 18a8aa12d1 Release the held pokemon before sorting, closes #1663 2025-09-20 14:16:21 +10:00
Paul 308ca6369d Fixed persistence issues for pokemon item pickup behaviours 2025-09-20 12:44:17 +10:00
Paul 79fd9f4e04 Fixed pokemon having the NPC dialogues memory 2025-09-20 12:28:06 +10:00
Paul 38219bbca2 Fixed pokemon in the party following and looking around while asleep, closes #1668 2025-09-20 12:27:48 +10:00
Paul 87de288777 Fixed crash when adding stationary Behaviour without a movement providing behaviour. Closes #1678 2025-09-20 11:25:04 +10:00
Paul b6f1d6c62e Fixed terralith:shrubland not counting as plains for pokemon spawning, closes #1685 2025-09-20 10:44:36 +10:00
Polymeta 43310d3a3b tweak default stat ranges for some flying behaviours
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-09-19 10:29:34 +01:00
Paul 6ae375cf4e Added math.sign and math.copy_sigh molang dep update 2025-09-19 10:34:19 +10:00
Polymeta 29c65c18ff Merge branch 'what-a-grain' into 'main'
Grain Improvements

Closes #1702

See merge request cable-mc/cobblemon!1863
2025-09-18 17:10:08 +00:00
dhi_holoandPolymeta b90384fe08 Grain Improvements 2025-09-18 17:10:08 +00:00
Test 5ad881235f update fabric-permissions-api to 0.3.1 2025-09-18 04:53:02 +00:00
Landon 05796998e8 Merge branch 'riding-behaviour-tweaks-02' into 'main'
Behaviour tweaks

See merge request cable-mc/cobblemon!1862
2025-09-17 18:36:53 +00:00
Jackson BowesandLandon aaf1aad9a4 Behaviour tweaks 2025-09-17 18:36:53 +00:00
Polymeta b315fdcadc Merge branch 'sand-witches' into 'main'
Small Data Changes

See merge request cable-mc/cobblemon!1861
2025-09-17 18:23:42 +00:00
dhi_holo 5b95f0a1c7 Update mochis.json
Added missing and reorganised
2025-09-18 00:01:56 +10:00
dhi_holo 7641a839c2 Merge branch 'main' into sand-witches 2025-09-17 23:33:08 +10:00
dhi_holo 6ed6ca6937 IV Drip
Added new candy tags for IV Candies (additive, subtractive, general, and general candy that includes Exp Candies)
Added Vivichoke, Cobblemon Apples, and Beetroots to Sandwich Vegetable tag
Added advancement for using IV candy
2025-09-17 23:28:18 +10:00
Landon be106a465e Merge branch 'riding-debug-ui-tweaks-02' into 'main'
Ride settings editor

See merge request cable-mc/cobblemon!1858
2025-09-17 12:53:24 +00:00
Jackson BowesandLandon e7c0374c83 Ride settings editor 2025-09-17 12:53:24 +00:00
Polymeta 7fd1a443ac Merge branch 'riding-fix-air-dismount' into 'main'
Fix in air dismount

See merge request cable-mc/cobblemon!1831
2025-09-17 06:22:21 +00:00
Jackson BowesandPolymeta 31359077ed Fix in air dismount 2025-09-17 06:22:20 +00:00
Polymeta 7f683bd618 Merge branch 'riding-fix-waterwalk' into 'main'
Fix riding waterwalk

See merge request cable-mc/cobblemon!1838
2025-09-17 06:21:36 +00:00
Jackson BowesandPolymeta 012f15878e Fix riding waterwalk 2025-09-17 06:21:36 +00:00
Polymeta f406b9695d Merge branch 'main' into 'main'
Skip battle check if the mobTargetInBattle game rule is set to false

See merge request cable-mc/cobblemon!1857
2025-09-16 08:17:01 +00:00
Polymeta f6dbe40246 Merge branch 'implement_pokemon' into 'main'
lots o' implementing, animating and fixing.

See merge request cable-mc/cobblemon!1846
2025-09-16 08:15:52 +00:00
Polymeta a1f6e47f42 Merge branch 'fix-cooking-pot-button-color' into 'main'
Fix Campfire Pot Lid Button Sprite

See merge request cable-mc/cobblemon!1859
2025-09-16 08:15:13 +00:00
Polymeta 04f5dbfca0 swap out textures
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-09-16 09:11:38 +01:00
martin fd940b5549 Remove unnecessary check on resource 2025-09-15 16:12:36 +08:00
Hiroku 3e37c1af32 Merge branch 'animation-scale-shenanigan' into 'main'
Removed Animators/Engineer Frame Ghost Scale Jumpscare

See merge request cable-mc/cobblemon!1855
2025-09-15 01:15:16 +00:00
Paul 8b6b9ffede Changelog [skip-ci] 2025-09-15 10:07:03 +10:00
Hiroku 329a13867c Merge branch 'implemented-patch' into 'main'
Fixes PokemonSpecies.implemented not containing pokémon marked implemented via species additions.

See merge request cable-mc/cobblemon!1835
2025-09-15 00:02:47 +00:00
Carmendar 5c6632c3fb Forgor camera offsets for extra seats 2025-09-14 03:20:07 -05:00
Carmendar ebde125895 Bronzong ready to scrape. 2025-09-14 03:18:17 -05:00
martin c45c74c508 Fix double lid on campfire pot open sprites 2025-09-14 14:31:13 +08:00
martin cd6bc23825 Rename CookingPotColor to CampfirePotColor 2025-09-14 06:16:57 +00:00
martin 3df95df1f9 Add color property in CampfirePotItem
To make it really easy to get it in the future
2025-09-14 06:16:57 +00:00
martin ad3ee75c22 Sync cooking pot button color with open / closed state 2025-09-14 06:16:57 +00:00
martin ce3935950a Add cooking pot open sprites 2025-09-14 06:16:57 +00:00
Paul e1380df7d1 Fixed herd counts exceeding the max, smooth the following timing so it's less robotic 2025-09-14 14:03:13 +10:00
Carmendar cf8cfb8dad Nickel no longer defies gravity when sleeping & corrected underwater behaviors on wiglett line. 2025-09-13 18:52:42 -05:00
Instrafe 3729728124 Implemented locators for Omanyte & Omastar 2025-09-13 17:16:41 -04:00
MemencioPerez 3092abfdd0 Inline mobTargetInBattle game rule check in TargetingConditions mixin 2025-09-12 15:07:30 -04:00
Carmendar 3150f33e9e underwater walkers now walk underwater, and some swimmers now avoid land. (Crabrawler line avoids water entirely.) 2025-09-12 01:27:34 -05:00
Carmendar 40d7e7bccb Merge branch 'main' into implement_pokemon 2025-09-12 01:27:10 -05:00
MemencioPerez cdbe61843f Skip battle check if the mobTargetInBattle game rule is set to false 2025-09-11 23:00:53 -04:00
Paul b13c168347 Increased default PC box count from 30 to 40 2025-09-12 12:12:39 +10:00
Carmendar f77fa82e4f Implemented finalized Mochi sprites. 2025-09-11 19:02:26 -05:00
Konoha 2e2b10311d Implement Unown ! and ? lang 2025-09-11 17:36:42 -04:00
Gertimoshka 2af5de8ce4 Fixed issue where Animation Transition has a frame non zero scale render on a part that is scale 0 for both animations 2025-09-12 00:02:56 +03:00
Jerzykv 66eea576f3 comma 2025-09-11 10:45:55 +02:00
Carmendar 53a516266f Annihilape anims and particle! -- jump anims for Garchomp and Ursaring + jump fixes for a few other mons. 2025-09-11 02:43:41 -05:00
Carmendar f732442133 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-09-11 02:41:16 -05:00
GenotypeXD-Dev 34cad13f57 Pachirisu scale fix 2025-09-11 02:19:23 -05:00
GenotypeXD-Dev e879a755a4 Implemented Mew and Pachirisu Remodels, Updated gengars uv/textures 2025-09-11 02:16:58 -05:00
Carmendar 2ac9c827d4 Merge branch 'refs/heads/main' into implement_pokemon 2025-09-10 23:02:07 -05:00
Test a0ef46a18c Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon 2025-09-10 21:09:09 -04:00
Test 9dc15c9096 fix pasture scroll crash 2025-09-10 21:08:49 -04:00
Landon 346e2cd094 Merge branch 'horse-stepup-tweak' into 'main'
Vanilla-Like Horse Ride Style Stepup

See merge request cable-mc/cobblemon!1854
2025-09-10 20:08:24 +00:00
Konoha f7794d50dd Import for cleanliness 2025-09-10 15:24:04 -04:00
Konoha 3b8d67ce64 Tweak the Horse Ride-style "StepUp" to check for the ground similar to vanilla horses. 2025-09-10 14:52:57 -04:00
Test 105d3a7d90 Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon 2025-09-09 20:15:56 -04:00
Tyzillion 8a685cefc0 Poodle trimmin tweaks. 2025-09-09 13:35:09 -04:00
Tyzillion 3ff536dc02 Updated Changelog. 2025-09-09 11:16:56 -04:00
Tyzillion 638ec03244 The trimming particles no longer glow. 2025-09-09 11:14:00 -04:00
Tyzillion 37438c9fdd CYAN AND LIGHT BLUE ARE NOT THE SAME. WAAAAAAAAAH 2025-09-09 09:58:30 -04:00
Tyzillion cbc4b52193 Finishing touches on Furfrou. 2025-09-09 09:48:18 -04:00
Tyzillion 9a760d8eae Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-09-09 08:36:17 -04:00
Tyzillion b7d26d99cd Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon
# Conflicts:
#	common/src/main/resources/data/cobblemon/cosmetic_items/dyes.json
2025-09-09 08:33:02 -04:00
Tyzillion 04c8b1e95b Let me pet dat dawg! Can I pet dat dawg? 2025-09-09 08:32:21 -04:00
Tyzillion e4149b2a5e Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into implement_pokemon 2025-09-09 08:29:44 -04:00
Carmendar 3cdaa513f8 Lickilicky ready for scrape with placeholder controller, and various other small fixes and tweaks. 2025-09-09 03:09:19 -05:00
GenotypeXD-Dev ca43fcf3a2 Implemented New cosmetics [Watermelon Electrodes, Pokemopolis alakazam, gengar, and jigglypuff, Dots Tinkatink, Tinkatuff, and Tinkaton, Golden Sudowoodo] 2025-09-09 01:39:33 -05:00
Tyzillion 5b56a5758a Drednaw, more like, DredMAH THERE'S A WEIRD MF CAT OUTSIDE. 2025-09-08 21:54:46 -04:00
Tyzillion 424889e820 You know what, screw you. *Downgrades your Chewtle* 2025-09-08 21:24:10 -04:00
Tyzillion 6d3f00cd58 Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into implement_pokemon 2025-09-08 21:07:08 -04:00
Carmendar 1d375bdffa Last Bouffalant fix I swear... also Garchomp head fix in sand. 2025-09-08 19:23:24 -05:00
Carmendar e563bbee49 bouff blink fix 2025-09-08 18:05:22 -05:00
Sterrezo 8fe2dc8304 Restored Golurk's ride sounds 2025-09-08 22:27:49 +02:00
Lennie e3502ec320 Added wing flap sounds to updated noivern & volcarona animations, adjusted noivern's portrait 2025-09-08 10:20:00 +02:00
Carmendar d8d0ade350 luigi and netherite hoe controller updates. 2025-09-08 02:34:31 -05:00
GenotypeXD-Dev e2ac4449b3 Implemented Seedot line Remodels 2025-09-07 22:15:30 -05:00
GenotypeXD-Dev ecec7ccee3 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-09-07 21:16:30 -05:00
GenotypeXD-Dev 228282f083 Added regional caps for raichu and pichu, added ukulele pichu, and fixes for pikachu cap cosmetics 2025-09-07 21:15:25 -05:00
Carmendar 3bc7d39800 Forgor changelog 2025-09-07 21:06:30 -05:00
Carmendar 3dc5873642 Nickel line remodels, Garchomp anims, fixed Bouffalant battle_idle, fixed Noivern clipping, updated Volcarona anim file, implemented Chewtle line cries and Axew cry, removed reference to clobbopus cry anim (it doesn't have one), and fixed third person camera offset for some mons. 2025-09-07 21:03:52 -05:00
Lennie 8d6291c4c2 Fixed a crash due to a poser issue 2025-09-07 13:36:37 +02:00
Jerzykv 2b77d030e8 You can drive now! (Implemented Varoom & Revavroom remodels + placeholder ride data) 2025-09-07 11:45:27 +02:00
Carmendar 029927af6a Merge branch 'main' into implement_pokemon 2025-09-07 04:12:19 -05:00
Carmendar bf791dc4d1 Bouffalant can eepy. 2025-09-07 04:08:13 -05:00
Neovitalism 2a62b49eab Update PokemonSpecies.kt 2025-09-04 21:10:49 -05:00
Test 43dbfc772e Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon 2025-08-30 22:06:27 -04:00
Tyzillion eee3296120 Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into implement_pokemon 2025-08-27 09:54:51 -04:00
Paul e7197a7d3a Outlining some behaviours for responsiveness to triggers 2025-08-23 16:25:18 +10:00
Paul d2febef6cf Merge remote-tracking branch 'origin/main' into fickle-behaviour 2025-08-22 17:23:24 +10:00
Paul d98145617f Fixes from merge 2025-08-16 10:31:32 +10:00
Paul c7b7fd3236 Merge remote-tracking branch 'origin/LionsFoxesAndWolvesOhMy' into fickle-behaviour
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/api/molang/MoLangFunctions.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/entity/npc/ai/MeleeAttackTask.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/pokemon/ai/FormPokemonBehaviour.kt
2025-08-16 10:19:34 +10:00
Paul 0a18c67e34 Merge remote-tracking branch 'origin/main' into fickle-behaviour 2025-08-16 10:16:44 +10:00
Paul 6341ca417f More entity callbacks incl damage and entity visibility (untested), working on avoid target data impl for panicking and move away 2025-08-16 10:14:19 +10:00
Paul fe6841cac4 Merge remote-tracking branch 'origin/main' into fickle-behaviour
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/api/molang/MoLangFunctions.kt
2025-08-09 16:44:48 +10:00
Paul 0536c98b6a Some more molang for memories 2025-08-06 18:54:03 +10:00
Paul fc73384ea2 Respect attack target data disengaging in melee combat 2025-08-02 10:28:30 +10:00
457 changed files with 64073 additions and 13182 deletions
+1
View File
@@ -22,6 +22,7 @@
### Changes
- Slots in pastures will now have darker backgrounds and italicised Pokémon names if the Pokémon is not owned by the player.
- The pasture slot will show the name of the Pokémon owner when hovered if the Pokémon is not owned.
- Increased the default PC box count from 30 to 40 to accommodate the fact that we have way more Pokémon now. If you've changed this config option then you'll need to edit it again after starting up with 1.7!
### Developer
- Added `RenamePCBoxEvent.Pre` and `RenamePCBoxEvent.Post` events to prevent players from renaming a box or changing their input.
+1
View File
@@ -4,6 +4,7 @@
### Fixes
- Fixed the "enabled" property in spawn files not actually being respected. Where do they find these devs?
- Fixed Terralith's shrubland not counting as plains for spawning purposes the way it was intended to.
### Developer
- Spawning Influences now have the context of what the other buckets are when adjusting bucket weights. This will break existing influences that do bucket weight adjustment.
+11
View File
@@ -143,6 +143,8 @@
- Dedenne
- Noibat
- Noivern
- Furfrou
- You can change Furfrou's form by using shears on it while it holds a certain dye in its cosmetic slot.
#### Gen 7
- Yungoos
@@ -277,6 +279,10 @@
- Parasect
- Bastiodon
- Amaura
- Varoom
- Revavroom
- Bouffalant
- Lickilicky
### Model updates for the following Pokémon
- Cleffa
@@ -383,6 +389,10 @@
- Starly
- Staravia
- Staraptor
- Varoom
- Revavroom
- Nickit
- Thievul
### Changes
- Changed pokemon caught and seen count to update based on the current pokedex being looked
@@ -528,6 +538,7 @@
- Fixed Pokémon with alternate forms being created with an incorrect 'forced' tag on their ability.
- Fixed busted abilities and moves in Pokémon data due to removed datapacks etc. causing storage corruption. It now just rerolls their ability / uses Tackle.
- Fixed singular Pokémon corruption causing entire storage corruption. Storages will now skip corrupted Pokémon and print an error to console.
- Fixed species additions not being able to properly mark a species as implemented.
### Developer
- A finished battle now has winners and losers set inside of `PokemonBattle` instead of them always being empty.
+1 -1
View File
@@ -94,4 +94,4 @@ sourceSets {
}
}
}
}
}
@@ -25,9 +25,9 @@ public class TargetingConditionsMixin {
@Inject(method = "test", at = @At("HEAD"), cancellable = true)
public void test(@Nullable LivingEntity baseEntity, LivingEntity targetEntity, CallbackInfoReturnable<Boolean> ci) {
if (targetEntity instanceof ServerPlayer player) {
boolean canTargetInBattle = player.level().getGameRules().getBoolean(CobblemonGameRules.MOB_TARGET_IN_BATTLE);
if (player.level().getGameRules().getBoolean(CobblemonGameRules.MOB_TARGET_IN_BATTLE)) return;
boolean targetInBattle = Cobblemon.INSTANCE.getBattleRegistry().getBattleByParticipatingPlayer(player) != null;
if (!canTargetInBattle && targetInBattle) ci.setReturnValue(false);
if (targetInBattle) ci.setReturnValue(false);
}
}
}
@@ -11,7 +11,10 @@ package com.cobblemon.mod.common.mixin.entity;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -39,10 +42,17 @@ public abstract class EntityMixin {
target = "Lnet/minecraft/world/entity/Entity;onGround()Z"
)
)
public boolean cobblemon$forceOnGroundForStepUp(Entity entity, Operation<Boolean> original)
{
public boolean cobblemon$forceOnGroundForStepUp(Entity entity, Operation<Boolean> original) {
if (entity instanceof PokemonEntity && entity.hasControllingPassenger()) {
return true;
BlockPos below = entity.blockPosition().below();
Level level = entity.level();
var blockStateBelow = level.getBlockState(below);
boolean isAirOrLiquid = blockStateBelow.isAir() || !blockStateBelow.getFluidState().isEmpty();
boolean canSupportEntity = blockStateBelow.isFaceSturdy(level, below, Direction.UP);
boolean standingOnSolid = canSupportEntity && !isAirOrLiquid;
if (standingOnSolid) {
return true;
}
}
return original.call(entity);
}
@@ -22,6 +22,7 @@ import com.cobblemon.mod.common.block.BerryBlock
import com.cobblemon.mod.common.block.MintBlock
import com.cobblemon.mod.common.block.MintBlock.MintType
import com.cobblemon.mod.common.client.pokedex.PokedexType
import com.cobblemon.mod.common.block.campfirepot.CampfirePotColor
import com.cobblemon.mod.common.entity.boat.CobblemonBoatType
import com.cobblemon.mod.common.item.*
import com.cobblemon.mod.common.item.armor.CobblemonArmorTrims
@@ -192,19 +193,19 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
val campfire_pots = mutableListOf<CampfirePotItem>()
@JvmField
val CAMPFIRE_POT_RED = campfirePotItem(CobblemonBlocks.RED_CAMPFIRE_POT, "red")
val CAMPFIRE_POT_RED = campfirePotItem(CobblemonBlocks.RED_CAMPFIRE_POT, CampfirePotColor.RED)
@JvmField
val CAMPFIRE_POT_YELLOW = campfirePotItem(CobblemonBlocks.YELLOW_CAMPFIRE_POT, "yellow")
val CAMPFIRE_POT_YELLOW = campfirePotItem(CobblemonBlocks.YELLOW_CAMPFIRE_POT, CampfirePotColor.YELLOW)
@JvmField
val CAMPFIRE_POT_GREEN = campfirePotItem(CobblemonBlocks.GREEN_CAMPFIRE_POT, "green")
val CAMPFIRE_POT_GREEN = campfirePotItem(CobblemonBlocks.GREEN_CAMPFIRE_POT, CampfirePotColor.GREEN)
@JvmField
val CAMPFIRE_POT_BLUE = campfirePotItem(CobblemonBlocks.BLUE_CAMPFIRE_POT, "blue")
val CAMPFIRE_POT_BLUE = campfirePotItem(CobblemonBlocks.BLUE_CAMPFIRE_POT, CampfirePotColor.BLUE)
@JvmField
val CAMPFIRE_POT_PINK = campfirePotItem(CobblemonBlocks.PINK_CAMPFIRE_POT, "pink")
val CAMPFIRE_POT_PINK = campfirePotItem(CobblemonBlocks.PINK_CAMPFIRE_POT, CampfirePotColor.PINK)
@JvmField
val CAMPFIRE_POT_BLACK = campfirePotItem(CobblemonBlocks.BLACK_CAMPFIRE_POT, "black")
val CAMPFIRE_POT_BLACK = campfirePotItem(CobblemonBlocks.BLACK_CAMPFIRE_POT, CampfirePotColor.BLACK)
@JvmField
val CAMPFIRE_POT_WHITE = campfirePotItem(CobblemonBlocks.WHITE_CAMPFIRE_POT, "white")
val CAMPFIRE_POT_WHITE = campfirePotItem(CobblemonBlocks.WHITE_CAMPFIRE_POT, CampfirePotColor.WHITE)
@JvmField
val HEARTY_GRAINS = compostableItem("hearty_grains", ItemNameBlockItem(CobblemonBlocks.HEARTY_GRAINS, Properties().rarity(Rarity.COMMON)))
@@ -1500,8 +1501,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
}
)
private fun campfirePotItem(block: Block, type: String): CampfirePotItem {
val item = create("campfire_pot_${type}", CampfirePotItem(block))
private fun campfirePotItem(block: Block, color: CampfirePotColor): CampfirePotItem {
val item = create("campfire_pot_${color.suffix}", CampfirePotItem(block, color))
campfire_pots.add(item)
return item
}
@@ -1648,4 +1649,4 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
private fun foodItem(nutrition: Int, saturationModifier: Float): Item {
return CobblemonItem(Item.Properties().food(FoodProperties.Builder().nutrition(nutrition).saturationModifier(saturationModifier).build()))
}
}
}
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.ai.CobblemonAttackTargetData
import com.cobblemon.mod.common.api.ai.CobblemonAvoidTargetData
import com.cobblemon.mod.common.api.ai.CobblemonWanderControl
import com.cobblemon.mod.common.api.dialogue.ActiveDialogue
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
@@ -57,9 +58,11 @@ object CobblemonMemories {
/** how many are following me rn? */
val HERD_SIZE = register<Int>("herd_size") // Don't bother saving it, we'll try to keep count roughly.
val ATTACK_TARGET_DATA = register<CobblemonAttackTargetData>("attack_target_data") // This is used to store additional information about the attack target, such as when to give up pursuit.
val AVOID_TARGET_DATA = register<CobblemonAvoidTargetData>("avoid_target_data") // This is used to store additional information about the avoid target, such as how fast to move.
val WANDER_CONTROL = register<CobblemonWanderControl>("wander_control")
val DISABLE_WALK_TO_WANTED_ITEM = register<Boolean>("disable_walk_to_wanted_item")
val TIME_TRYING_TO_REACH_WANTED_ITEM = register<Int>("time_trying_to_wanted_item")
val RECENT_CATCH_ATTEMPT = register<UUID>("recent_catch_attempt")
fun <U> register(id: String, codec: Codec<U>): MemoryModuleType<U> {
val memoryModule = MemoryModuleType(Optional.of(codec))
@@ -157,6 +157,7 @@ import com.cobblemon.mod.common.net.messages.server.callback.party.PartyPokemonS
import com.cobblemon.mod.common.net.messages.server.callback.party.PartySelectCancelledPacket
import com.cobblemon.mod.common.net.messages.server.callback.partymove.PartyMoveSelectCancelledPacket
import com.cobblemon.mod.common.net.messages.server.callback.partymove.PartyPokemonMoveSelectedPacket
import com.cobblemon.mod.common.net.messages.server.debug.ServerboundUpdateRidingSettingsPacket
import com.cobblemon.mod.common.net.messages.server.debug.ServerboundUpdateRidingStatRangePacket
import com.cobblemon.mod.common.net.messages.server.debug.ServerboundUpdateRidingStatsPacket
import com.cobblemon.mod.common.net.messages.server.dialogue.EscapeDialoguePacket
@@ -208,6 +209,7 @@ import com.cobblemon.mod.common.net.serverhandling.callback.party.PartyPokemonSe
import com.cobblemon.mod.common.net.serverhandling.callback.party.PartySelectCancelledHandler
import com.cobblemon.mod.common.net.serverhandling.callback.partymove.PartyMoveSelectCancelledHandler
import com.cobblemon.mod.common.net.serverhandling.callback.partymove.PartyPokemonMoveSelectedHandler
import com.cobblemon.mod.common.net.serverhandling.debug.ServerboundUpdateRidingSettingsHandler
import com.cobblemon.mod.common.net.serverhandling.debug.ServerboundUpdateRidingStatRangeHandler
import com.cobblemon.mod.common.net.serverhandling.debug.ServerboundUpdateRidingStatsHandler
import com.cobblemon.mod.common.net.serverhandling.dialogue.EscapeDialogueHandler
@@ -578,6 +580,7 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatePacket.ID, ServerboundUpdateRidingStatePacket::decode, ServerboundUpdateRidingStateHandler))
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatsPacket.ID, ServerboundUpdateRidingStatsPacket::decode, ServerboundUpdateRidingStatsHandler))
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatRangePacket.ID, ServerboundUpdateRidingStatRangePacket::decode, ServerboundUpdateRidingStatRangeHandler))
list.add(PacketRegisterInfo(ServerboundUpdateRidingSettingsPacket.ID, ServerboundUpdateRidingSettingsPacket::decode, ServerboundUpdateRidingSettingsHandler))
list.add(PacketRegisterInfo(DismountPokemonPacket.ID, DismountPokemonPacket::decode, DismountPokemonPacketHandler))
list.add(PacketRegisterInfo(ServerboundUpdateDriverInputPacket.ID, ServerboundUpdateDriverInputPacket::decode, DriverInputPacketHandler))
@@ -20,6 +20,8 @@ import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.cobblemon.mod.common.util.resolve
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.memory.MemoryModuleType
/**
* This is used in the AI system to store optional additional information about the attack target,
@@ -41,15 +43,21 @@ import net.minecraft.world.entity.Entity
class CobblemonAttackTargetData(
/** An expression that returns false when the target is no longer worth attacking. */
var shouldContinue: Expression = "true".asExpression(),
var hitsUntilDisengage: Int = -1, // -1 means no limit
var disengageAction: (entity: Entity) -> Unit = {}
var dealtHitsUntilDisengage: Int = -1, // -1 means no limit
var disengageAction: (entity: LivingEntity) -> Unit = ::defaultDisengage
) {
companion object {
fun defaultDisengage(entity: LivingEntity) {
entity.brain.eraseMemory(MemoryModuleType.ATTACK_TARGET)
entity.brain.updateActivityFromSchedule(entity.level().dayTime, entity.level().gameTime)
}
}
val struct = ObjectValue<CobblemonAttackTargetData>(this).also {
it.addFunction("hits_until_disengage") { DoubleValue(hitsUntilDisengage.toDouble()) }
it.addFunction("set_hits_until_disengage") { params ->
it.addFunction("dealt_hits_until_disengage") { DoubleValue(dealtHitsUntilDisengage.toDouble()) }
it.addFunction("set_dealt_hits_until_disengage") { params ->
val value = params.getDouble(0)
hitsUntilDisengage = value.toInt()
DoubleValue(hitsUntilDisengage.toDouble())
dealtHitsUntilDisengage = value.toInt()
DoubleValue(dealtHitsUntilDisengage.toDouble())
}
it.addFunction("set_disengage_action") { params ->
val script = params.getString(0).asIdentifierDefaultingNamespace()
@@ -64,8 +72,15 @@ class CobblemonAttackTargetData(
}
DoubleValue.ONE
}
it.addFunction("reset") {
shouldContinue = "true".asExpression()
dealtHitsUntilDisengage = -1
disengageAction = ::defaultDisengage
DoubleValue.ONE
}
it.addFunction("unset_disengage_action") { params ->
disengageAction = {}
disengageAction = ::defaultDisengage
}
}
}
@@ -0,0 +1,23 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.ai
import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.api.molang.ObjectValue
import com.cobblemon.mod.common.util.getDoubleOrNull
class CobblemonAvoidTargetData {
var walkSpeed: Float? = null
@Transient
val struct = ObjectValue<CobblemonAvoidTargetData>(this).also {
it.addFunction("walk_speed") { DoubleValue(walkSpeed) }
it.addFunction("set_walk_speed") { walkSpeed = it.getDoubleOrNull(0)?.toFloat() }
}
}
@@ -13,7 +13,6 @@ import com.cobblemon.mod.common.util.getBooleanOrNull
import com.cobblemon.mod.common.util.getDoubleOrNull
import kotlin.math.sqrt
import net.minecraft.core.BlockPos
import net.minecraft.world.entity.PathfinderMob
/**
* Used to maintain some settings around how the entity should wander this tick. The idea is you
@@ -30,7 +29,8 @@ class CobblemonWanderControl(
var allowWater: Boolean = false,
var allowAir: Boolean = false,
var pathCooldownTicks: Int = 20 * 5, // Used to mitigate the cost of pathfinding.
var wanderSpeed: Float = 0.35F,
var speedMultiplier: Float = 1F,
var wanderChance: Float? = null
) {
class WanderCenter(val x: Number, val y: Number, val z: Number, val minRange: Float, val maxRange: Float)
@@ -46,7 +46,7 @@ class CobblemonWanderControl(
.addFunction("allow_water") { if (allowWater) 1.0 else 0.0 }
.addFunction("allow_air") { if (allowAir) 1.0 else 0.0 }
.addFunction("path_cooldown_ticks") { pathCooldownTicks.toDouble() }
.addFunction("wander_speed") { wanderSpeed }
.addFunction("speed_multiplier") { speedMultiplier }
.addFunction("set_center") { params ->
if (params.params.size < 3) {
throw IllegalArgumentException("set_center requires at least 3 parameters: x, y, z")
@@ -69,15 +69,19 @@ class CobblemonWanderControl(
.addFunction("set_allow_water") { params -> allowWater = params.getBooleanOrNull(0) ?: false }
.addFunction("set_allow_air") { params -> allowAir = params.getBooleanOrNull(0) ?: false }
.addFunction("set_path_cooldown_ticks") { params -> pathCooldownTicks = params.getDoubleOrNull(0)?.toInt() ?: (20 * 5) }
.addFunction("set_wander_speed") { params -> wanderSpeed = params.getDoubleOrNull(0)?.toFloat() ?: 0.35F }
.addFunction("set_speed_multiplier") { params -> speedMultiplier = params.getDoubleOrNull(0)?.toFloat() ?: 0.35F }
.addFunction("set_wander_chance") { params ->
wanderChance = params.getDoubleOrNull(0)?.toFloat()
}
.addFunction("reset") {
center = null
allowLand = false
allowWater = false
allowAir = false
pathCooldownTicks = 20 * 5
wanderSpeed = 0.35F
speedMultiplier = 1F
maxAttempts = 4
wanderChance = null
}
fun isSuitable(position: BlockPos): Boolean {
@@ -12,11 +12,9 @@ import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
import kotlin.jvm.optionals.getOrNull
import net.minecraft.world.entity.LivingEntity
@@ -27,7 +25,9 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.sensing.SensorType
/**
* Checks nearby entities and counts how many have nominated this entity as their leader.
* Checks nearby entities and counts how many have nominated this entity as their leader. We normally update this
* as people join and leave the herd, but this is a fallback to make sure we don't get stuck with an incorrect value
* like if the entities die or whatever.
*
* @author Hiroku
* @since June 17th, 2025
@@ -8,17 +8,16 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.api.storage.party.PartyStore
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.ai.ToleratedHerdLeader
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
@@ -57,21 +56,21 @@ class FindHerdLeaderTaskConfig : SingleTaskConfig {
!it.brain.hasMemoryValue(CobblemonMemories.POKEMON_DROWSY)
}.forEach { possibleLeader ->
possibleLeader as PokemonEntity
val matchingHerdLeader = entity.behaviour.herd.bestMatchLeader(entity, possibleLeader) ?: return@forEach
val alreadyIsALeader = possibleLeader.brain.hasMemoryValue(CobblemonMemories.HERD_SIZE)
val nestedHerdTier = currentLeaderEntity?.getHerdTier() ?: 0
if (nestedHerdTier >= matchingHerdLeader.tier) {
val bestMatchingHerdLeader = entity.behaviour.herd.bestMatchLeader(entity, possibleLeader) ?: return@forEach
val possibleLeaderIsAlreadyALeader = possibleLeader.brain.hasMemoryValue(CobblemonMemories.HERD_SIZE)
val currentLeaderHerdTier = currentLeaderEntity?.getHerdTier() ?: entity.getHerdTier()
if (currentLeaderHerdTier >= bestMatchingHerdLeader.tier) {
return@forEach // This leader is following a leader of a higher tier, we can't replace them
}
val distance = entity.distanceTo(possibleLeader)
if (matchingHerdLeader.tier < bestTier) {
if (bestMatchingHerdLeader.tier < bestTier) {
return@forEach // No need to check further if this leader is worse than the best found so far
} else if ((distance > bestDistance && !alreadyIsALeader) && matchingHerdLeader.tier == bestTier) {
} else if ((distance > bestDistance && !possibleLeaderIsAlreadyALeader) && bestMatchingHerdLeader.tier == bestTier) {
return@forEach // No need to check further if this leader is farther than the best found so far, unless they are already a leader - I'd prefer to join a pack
} else {
bestLeader = possibleLeader
bestDistance = distance
bestTier = matchingHerdLeader.tier
bestTier = bestMatchingHerdLeader.tier
}
}
return bestLeader ?: currentLeaderEntity
@@ -119,6 +118,7 @@ class FindHerdLeaderTaskConfig : SingleTaskConfig {
herdLeader.set(bestLeader.uuid.toString())
bestLeader.brain.eraseMemory(CobblemonMemories.HERD_LEADER)
bestLeader.adjustHerdSize(1)
return@Trigger true
}
}
@@ -14,15 +14,19 @@ import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.FindRestingPlaceTask
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolveBoolean
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class FindRestingPlaceTaskConfig : SingleTaskConfig {
val condition: ExpressionLike = "true".asExpressionLike()
val horizontalSearchDistance: ExpressionOrEntityVariable = Either.left("16".asExpression())
val verticalSearchDistance: ExpressionOrEntityVariable = Either.left("5".asExpression())
@@ -31,6 +35,13 @@ class FindRestingPlaceTaskConfig : SingleTaskConfig {
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity>? {
if (entity !is PokemonEntity) {
return null
}
if (!behaviourConfigurationContext.runtime.resolveBoolean(condition)) {
return null
}
behaviourConfigurationContext.addMemories(
CobblemonMemories.PATH_COOLDOWN,
CobblemonMemories.POKEMON_DROWSY,
@@ -11,15 +11,20 @@ package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.CobblemonSensors
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.GoToSleepTask
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.resolveBoolean
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class GoToSleepTaskConfig : SingleTaskConfig {
var onlyFromStatus: ExpressionOrEntityVariable = Either.left("false".asExpression())
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = emptyList<MoLangConfigVariable>()
override fun createTask(
entity: LivingEntity,
@@ -34,6 +39,6 @@ class GoToSleepTaskConfig : SingleTaskConfig {
CobblemonMemories.POKEMON_SLEEPING
)
behaviourConfigurationContext.addSensors(CobblemonSensors.POKEMON_DROWSY)
return WrapperLivingEntityTask(GoToSleepTask.create(), PokemonEntity::class.java)
return WrapperLivingEntityTask(GoToSleepTask.create(onlyFromStatus.resolveBoolean(behaviourConfigurationContext.runtime)), PokemonEntity::class.java)
}
}
@@ -10,17 +10,28 @@ package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.npc.ai.LookAtSpeakerTask
import com.cobblemon.mod.common.util.asExpression
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class LookAtSpeakerTaskConfig : SingleTaskConfig {
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = emptyList<MoLangConfigVariable>()
override fun createTask(
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
) = LookAtSpeakerTask.create().also {
behaviourConfigurationContext.addMemories(MemoryModuleType.LOOK_TARGET, CobblemonMemories.DIALOGUES)
): BehaviorControl<in LivingEntity>? {
if (!condition.resolveBoolean(behaviourConfigurationContext.runtime)) {
return null
}
return LookAtSpeakerTask.create().also {
behaviourConfigurationContext.addMemories(MemoryModuleType.LOOK_TARGET, CobblemonMemories.DIALOGUES)
}
}
}
@@ -8,15 +8,14 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
import java.util.UUID
import net.minecraft.world.entity.LivingEntity
@@ -82,6 +81,8 @@ class MaintainHerdLeaderTaskConfig : SingleTaskConfig {
if (bestLeader != null && bestLeader != leader) {
bestLeader.brain.eraseMemory(CobblemonMemories.HERD_LEADER)
entity.brain.setMemory(CobblemonMemories.HERD_LEADER, bestLeader.uuid.toString())
bestLeader.adjustHerdSize(1)
leader.adjustHerdSize(-1)
}
}
return@Trigger true
@@ -0,0 +1,87 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.entity.EntityCallbacks
import com.cobblemon.mod.common.entity.MoLangScriptingEntity
import com.cobblemon.mod.common.util.asExpression
import com.mojang.datafixers.util.Either
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.Behavior
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.memory.MemoryStatus
import net.minecraft.world.entity.ai.sensing.SensorType
/**
* Frequently checks a diff on the visibility of entities around the given entity so EntityCallbacks can be triggered.
*
* @author Hiroku
* @since August 7th, 2025
*/
class NotifyAboutEntityVisibilityTaskConfig : SingleTaskConfig {
val ticksBetweenChecks: ExpressionOrEntityVariable = Either.left("20".asExpression())
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = listOf(ticksBetweenChecks).asVariables()
override fun createTask(
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity>? {
if (entity !is MoLangScriptingEntity) {
return null
}
val ticksBetweenChecks = ticksBetweenChecks.resolveInt(behaviourConfigurationContext.runtime)
behaviourConfigurationContext.addMemories(MemoryModuleType.NEAREST_LIVING_ENTITIES)
behaviourConfigurationContext.addSensors(SensorType.NEAREST_LIVING_ENTITIES)
return object : Behavior<LivingEntity>(mapOf(MemoryModuleType.NEAREST_LIVING_ENTITIES to MemoryStatus.VALUE_PRESENT), Int.MAX_VALUE) {
override fun canStillUse(level: ServerLevel, entity: LivingEntity, gameTime: Long) = true
override fun checkExtraStartConditions(level: ServerLevel, owner: LivingEntity) = true
// Buffer of known entities
val knownEntities = mutableListOf<LivingEntity>()
override fun tick(level: ServerLevel, owner: LivingEntity, gameTime: Long) {
if (gameTime % ticksBetweenChecks != 0L) {
return
}
val visibleEntities = owner.getBrain().getMemory(MemoryModuleType.NEAREST_LIVING_ENTITIES)
.orElse(emptyList<LivingEntity>())
.filter { it.isAlive }
val newEntities = visibleEntities.filterNot { it in knownEntities }
val removedEntities = knownEntities.filterNot { it in visibleEntities }
newEntities.forEach {
entity.callbacks.process(
type = EntityCallbacks.SAW_ENTITY,
functions = mapOf("other_entity" to { _ -> it.asMostSpecificMoLangValue() })
)
}
removedEntities.forEach {
entity.callbacks.process(
type = EntityCallbacks.LOST_ENTITY,
functions = mapOf("other_entity" to { _ -> it.asMostSpecificMoLangValue() })
)
}
knownEntities.clear()
knownEntities.addAll(visibleEntities)
}
}
}
}
@@ -79,7 +79,6 @@ interface TaskConfig {
cobblemonResource("switch_to_panic_when_hostiles_nearby") to SwitchToPanicWhenHostilesNearbyTaskConfig::class.java,
cobblemonResource("calm_down") to CalmDownTaskConfig::class.java,
cobblemonResource("walk_away_from_avoid_target") to WalkAwayFromAvoidTargetTaskConfig::class.java,
cobblemonResource("flee_nearest_hostile") to FleeNearestHostileTaskConfig::class.java,
cobblemonResource("flee_attacker") to FleeAttackerTaskConfig::class.java,
cobblemonResource("fly_in_circles") to FlyInCirclesTaskConfig::class.java,
cobblemonResource("run_script") to RunScript::class.java,
@@ -120,6 +119,7 @@ interface TaskConfig {
cobblemonResource("target_entity") to TargetEntityTaskConfig::class.java,
cobblemonResource("memory_aspect") to MemoryAspectTaskConfig::class.java,
cobblemonResource("activity_change") to ActivityChangeTaskConfig::class.java,
cobblemonResource("notify_about_entity_visibility") to NotifyAboutEntityVisibilityTaskConfig::class.java,
)
}
@@ -133,7 +133,7 @@ class WanderTaskConfig : SingleTaskConfig {
val wanderControl = it.tryGet(wanderControl).orElse(null) ?: CobblemonWanderControl()
mainThreadRuntime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
val avoidsTargetingAir = avoidTargetingAir.resolveBoolean(mainThreadRuntime)
val wanderChance = mainThreadRuntime.resolveFloat(wanderChanceExpression)
val wanderChance = wanderControl.wanderChance ?: mainThreadRuntime.resolveFloat(wanderChanceExpression)
if (wanderChance <= 0 || world.random.nextFloat() > wanderChance || !wanderControl.allowLand) {
return@Trigger false
}
@@ -180,7 +180,7 @@ class WanderTaskConfig : SingleTaskConfig {
walkTarget.set(
CobblemonWalkTarget(
pos = pos,
speedModifier = speedMultiplier.resolveFloat(mainThreadRuntime),
speedModifier = speedMultiplier.resolveFloat(mainThreadRuntime) * wanderControl.speedMultiplier,
completionRange = 0,
nodeTypeFilter = { nodeType -> nodeType !in listOf(PathType.WATER, PathType.WATER_BORDER) },
destinationNodeTypeFilter = { nodeType -> !avoidsTargetingAir || nodeType !in listOf(PathType.OPEN) }
@@ -78,7 +78,7 @@ class WaterWanderTaskConfig : SingleTaskConfig {
}
mainThreadRuntime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
val wanderChance = mainThreadRuntime.resolveFloat(wanderChanceExpression)
val wanderChance = wanderControl.wanderChance ?: mainThreadRuntime.resolveFloat(wanderChanceExpression)
if (wanderChance <= 0 || world.random.nextFloat() > wanderChance) {
return@Trigger false
}
@@ -104,7 +104,7 @@ class WaterWanderTaskConfig : SingleTaskConfig {
CobblemonWalkTarget(
pos = pos,
nodeTypeFilter = { it == PathType.WATER || it == PathType.WATER_BORDER },
speedModifier = speedMultiplier.resolveFloat(mainThreadRuntime),
speedModifier = speedMultiplier.resolveFloat(mainThreadRuntime) * wanderControl.speedMultiplier,
completionRange = 0
)
)
@@ -12,7 +12,6 @@ import com.bedrockk.molang.runtime.MoLangEnvironment
import com.bedrockk.molang.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.MoParams
import com.bedrockk.molang.runtime.struct.ArrayStruct
import com.bedrockk.molang.runtime.struct.MoStruct
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.bedrockk.molang.runtime.struct.VariableStruct
import com.bedrockk.molang.runtime.value.DoubleValue
@@ -25,6 +24,8 @@ import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.CobblemonUnlockableWallpapers
import com.cobblemon.mod.common.Environment
import com.cobblemon.mod.common.api.ai.CobblemonBlockPosTracker
import com.cobblemon.mod.common.api.ai.CobblemonAttackTargetData
import com.cobblemon.mod.common.api.ai.CobblemonAvoidTargetData
import com.cobblemon.mod.common.api.ai.CobblemonWanderControl
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
@@ -348,10 +349,7 @@ object MoLangFunctions {
val b = format.parse(dateB)
DoubleValue(a.after(b))
},
"create_simple_party_provider" to java.util.function.Function { params ->
val partyProvider = SimplePartyProvider()
return@Function partyProvider.struct
},
"create_simple_party_provider" to java.util.function.Function { SimplePartyProvider().struct },
"create_pickup_item" to java.util.function.Function { params ->
val item = params.getOrNull<MoValue>(0)?.asString()?.let(ObtainableItemCondition::parseFromString)
val pickupPriority = params.getIntOrNull(1) ?: 0
@@ -364,6 +362,7 @@ object MoLangFunctions {
{ worldHolder ->
val world = worldHolder.value()
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
map.put("id") { StringValue(world.dimension().location().toString()) }
map.put("is_time_of_day") { params ->
val timeOfDay = TimeRange.timeRanges[params.getString(0).lowercase()]
?: return@put DoubleValue.ZERO
@@ -807,6 +806,13 @@ object MoLangFunctions {
val source = DamageSource(entity.level().registryAccess().registryOrThrow(Registries.DAMAGE_TYPE).getHolder(DamageTypes.GENERIC).get())
entity.hurt(source, amount.toFloat())
}
map.put("damage_source") { params ->
val registry = entity.level().registryAccess().registryOrThrow(Registries.DAMAGE_TYPE)
val type = params.getStringOrNull(0)?.asIdentifierDefaultingNamespace()?.let(registry::getHolder)
?: registry.getHolder(DamageTypes.GENERIC)
val damageSource = DamageSource(type.get(), entity)
return@put damageSource.asMoLangValue()
}
map.put("distance_to_owner") {
if (entity !is TamableAnimal) {
return@put DoubleValue.ZERO
@@ -930,6 +936,10 @@ object MoLangFunctions {
map.put("is_on_fire") { _ -> DoubleValue(entity.isOnFire) }
map.put("is_invisible") { _ -> DoubleValue(entity.isInvisible) }
map.put("is_riding") { _ -> DoubleValue(entity.isPassenger) }
map.put("distance_to_entity") { params ->
val otherEntity = params.get<MoValue>(0) as? ObjectValue<Entity> ?: return@put DoubleValue.ZERO
return@put DoubleValue(entity.distanceTo(otherEntity.obj))
}
map.put("distance_to_pos") { params ->
val x = params.getDouble(0)
val y = params.getDouble(1)
@@ -1063,7 +1073,19 @@ object MoLangFunctions {
}
)
val livingEntityFunctions: MutableList<(LivingEntity) -> HashMap<String, java.util.function.Function<MoParams, Any>>> = mutableListOf<(LivingEntity) -> HashMap<String, java.util.function.Function<MoParams, Any>>>(
val damageSourceFunctions: MutableList<(DamageSource) -> java.util.HashMap<String, java.util.function.Function<MoParams, Any>>> = mutableListOf(
{ source ->
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
map.put("direct_entity") { source.directEntity?.asMostSpecificMoLangValue() ?: DoubleValue.ZERO }
map.put("entity") { source.entity?.asMostSpecificMoLangValue() ?: DoubleValue.ZERO }
map.put("is_food_exhaustion") { DoubleValue(source.foodExhaustion) }
map.put("is_direct") { DoubleValue(source.isDirect) }
map.put("type") { StringValue(source.typeHolder().unwrapKey().get().location().toString()) }
return@mutableListOf map
}
)
val livingEntityFunctions: MutableList<(LivingEntity) -> HashMap<String, java.util.function.Function<MoParams, Any>>> = mutableListOf(
{ entity ->
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
map.put("is_player") { _ -> DoubleValue(entity is Player) }
@@ -1105,6 +1127,23 @@ object MoLangFunctions {
val amount = params.getDouble(0)
entity.heal(amount.toFloat())
}
map.put("reset_activity") { _ ->
entity.brain.updateActivityFromSchedule(entity.level().dayTime, entity.level().gameTime)
DoubleValue.ONE
}
map.put("activity") { _ ->
return@put entity.brain.activeNonCoreActivity.map { StringValue(it.name) }.orElse(null) ?: DoubleValue.ZERO
}
map.put("set_activity") { params ->
val activityId = params.getString(0).asIdentifierDefaultingNamespace()
val activity = BuiltInRegistries.ACTIVITY.get(activityId)
if (activity != null) {
entity.brain.setActiveActivityIfPossible(activity)
return@put DoubleValue.ONE
} else {
return@put DoubleValue.ZERO
}
}
map.put("is_looking_at") { params ->
val targetEntity = params.get<MoValue>(0)
val maxDistance = params.getDoubleOrNull(1)?.toFloat() ?: 2.0F
@@ -1131,6 +1170,26 @@ object MoLangFunctions {
val brain = entity.brain
brain.setMemoryWithExpiry(MemoryModuleType.LOOK_TARGET, CobblemonBlockPosTracker(Vec3(x, y, z), flags.toSet()), duration.toLong())
}
map.put("is_doing_activity") { params ->
val identifiers = params.params.map { it.asString().asIdentifierDefaultingNamespace(namespace = "minecraft") }
val activities = identifiers.mapNotNull(BuiltInRegistries.ACTIVITY::get)
if (activities.isNotEmpty()) {
return@put DoubleValue(activities.any(entity.brain::isActive))
} else {
return@put DoubleValue.ZERO
}
}
map.put("get_attack_target_data_memory") {
val value = entity.brain.getMemorySafely(CobblemonMemories.ATTACK_TARGET_DATA).orElse(null)
?: CobblemonAttackTargetData()
if (
!entity.brain.checkMemory(CobblemonMemories.ATTACK_TARGET_DATA, MemoryStatus.VALUE_PRESENT)
&& entity.brain.checkMemory(CobblemonMemories.ATTACK_TARGET_DATA, MemoryStatus.REGISTERED)
) {
entity.brain.setMemory(CobblemonMemories.ATTACK_TARGET_DATA, value)
}
return@put value.struct
}
map.put("get_wander_control_memory") {
val value = entity.brain.getMemorySafely(CobblemonMemories.WANDER_CONTROL).orElse(null)
?: CobblemonWanderControl()
@@ -1142,6 +1201,17 @@ object MoLangFunctions {
}
return@put value.struct
}
map.put("get_avoid_target_data_memory") {
val value = entity.brain.getMemorySafely(CobblemonMemories.AVOID_TARGET_DATA).orElse(null)
?: CobblemonAvoidTargetData()
if (
!entity.brain.checkMemory(CobblemonMemories.AVOID_TARGET_DATA, MemoryStatus.VALUE_PRESENT)
&& entity.brain.checkMemory(CobblemonMemories.AVOID_TARGET_DATA, MemoryStatus.REGISTERED)
) {
entity.brain.setMemory(CobblemonMemories.AVOID_TARGET_DATA, value)
}
return@put value.struct
}
map.put("get_position_memory") { params ->
val id = params.getString(0).asIdentifierDefaultingNamespace()
val memoryType = BuiltInRegistries.MEMORY_MODULE_TYPE.get(id)
@@ -1168,6 +1238,30 @@ object MoLangFunctions {
return@put DoubleValue.ZERO
}
}
map.put("get_entity_memory") { params ->
val id = params.getString(0).asIdentifierDefaultingNamespace()
val memoryType = BuiltInRegistries.MEMORY_MODULE_TYPE.get(id)
if (entity.brain.checkMemory(memoryType, MemoryStatus.VALUE_PRESENT)) {
val memory = entity.brain.getMemory(memoryType).get()
return@put when (memory) {
is Entity -> memory.asMostSpecificMoLangValue()
else -> DoubleValue.ZERO
}
} else {
return@put DoubleValue.ZERO
}
}
map.put("set_entity_memory") { params ->
val memory = params.getString(0).asIdentifierDefaultingNamespace().let(BuiltInRegistries.MEMORY_MODULE_TYPE::get) as MemoryModuleType<LivingEntity>
val entityValue = (params.get<MoValue>(1) as? ObjectValue<*>)?.obj as? LivingEntity ?: return@put DoubleValue.ZERO
val expiry = params.getIntOrNull(2) ?: -1
if (expiry != -1) {
entity.brain.setMemoryWithExpiry(memory, entityValue, expiry.toLong())
} else {
entity.brain.setMemory(memory, entityValue)
}
return@put DoubleValue.ONE
}
map.put("set_uuid_memory") { params ->
val memory = params.getString(0).asIdentifierDefaultingNamespace().let(BuiltInRegistries.MEMORY_MODULE_TYPE::get) as MemoryModuleType<UUID>
val uuid = params.getString(1).asUUID ?: return@put DoubleValue.ZERO
@@ -1214,6 +1308,18 @@ object MoLangFunctions {
return@put DoubleValue.ZERO
}
}
map.put("is_visible_entity") { params ->
val otherEntity = params.get<ObjectValue<*>>(0)?.obj as? LivingEntity ?: return@put DoubleValue.ZERO
val visibleMobs = entity.brain.getMemorySafely(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES).orElse(null)
?: return@put DoubleValue.ZERO
return@put DoubleValue(visibleMobs.contains(otherEntity))
}
map.put("is_nearby_entity") { params ->
val otherEntity = params.get<ObjectValue<*>>(0)?.obj as? LivingEntity ?: return@put DoubleValue.ZERO
val nearbyMobs = entity.brain.getMemorySafely(MemoryModuleType.NEAREST_LIVING_ENTITIES).orElse(null)
?: return@put DoubleValue.ZERO
return@put DoubleValue(nearbyMobs.contains(otherEntity))
}
if (entity is PathfinderMob) {
map.put("walk_to") { params ->
val x = params.getDouble(0)
@@ -1236,7 +1342,7 @@ object MoLangFunctions {
}
}
map.put("has_walk_target") { _ ->
DoubleValue(entity.brain.getMemory(MemoryModuleType.WALK_TARGET).isPresent || entity.isPathFinding)
DoubleValue(entity.brain.getMemorySafely(MemoryModuleType.WALK_TARGET).isPresent || entity.isPathFinding)
}
}
map
@@ -1252,15 +1358,6 @@ object MoLangFunctions {
map.put("in_battle") { DoubleValue(npc.isInBattle()) }
map.put("battles") { ArrayStruct(npc.battleIds.mapNotNull { BattleRegistry.getBattle(it)?.struct }.mapIndexed { index, value -> "$index" to value }.toMap()) }
map.put("stop_battles") { _ -> npc.battleIds.forEach { BattleRegistry.getBattle(it)?.stop() } }
map.put("is_doing_activity") { params ->
val identifiers = params.params.map { it.asString().asIdentifierDefaultingNamespace(namespace = "minecraft") }
val activities = identifiers.mapNotNull { identifier -> BuiltInRegistries.ACTIVITY.get(identifier) }
if (activities.isNotEmpty()) {
return@put DoubleValue(activities.any { activity -> npc.brain.isActive(activity) })
} else {
return@put DoubleValue.ZERO
}
}
map.put("run_script_on_client") { params ->
val world = npc.level()
if (world is ServerLevel) {
@@ -2471,6 +2568,15 @@ object MoLangFunctions {
return value
}
fun DamageSource.asMoLangValue(): ObjectValue<DamageSource> {
val value = ObjectValue(
obj = this,
stringify = { it.toString() }
)
value.addFunctions(damageSourceFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
return value
}
/**
* Different functions exist depending on the entity type, this tries to make the struct that's most specific to the type.
*/
@@ -160,7 +160,7 @@ object PokeBalls : JsonDataRegistry<PokeBall> {
createDefault("great_ball", MultiplierModifier(1.5F))
createDefault("ultra_ball", MultiplierModifier(2F))
createDefault("master_ball", GuaranteedModifier())
createDefault("safari_ball", CatchRateModifiers.SAFARI)
createDefault("safari_ball", CatchRateModifiers.SAFARI, stealthFactor = 0.75f)
createDefault("fast_ball", BaseStatModifier(Stats.SPEED, { it >= 100 }, 4F))
createDefault("level_ball", CatchRateModifiers.LEVEL)
createDefault("lure_ball", CatchRateModifiers.LURE)
@@ -237,11 +237,12 @@ object PokeBalls : JsonDataRegistry<PokeBall> {
model2d: ResourceLocation = cobblemonResource(name),
model3d: ResourceLocation = cobblemonResource("item/${name}_model"),
throwPower: Float = 1.25f,
ancient: Boolean = false
ancient: Boolean = false,
stealthFactor: Float = 0.0f,
): PokeBall {
val identifier = cobblemonResource(name)
//val finalModifiers = if (appendUltraBeastPenalty) modifiers + listOf(LabelModifier(0.1F, true, CobblemonPokemonLabels.ULTRA_BEAST)) else modifiers
val pokeball = PokeBall(identifier, modifier, effects, waterDragValue, model2d, model3d, throwPower, ancient)
val pokeball = PokeBall(identifier, modifier, effects, waterDragValue, model2d, model3d, throwPower, ancient, stealthFactor)
this.defaults[identifier] = pokeball
return pokeball
}
@@ -43,7 +43,6 @@ import com.cobblemon.mod.common.api.riding.stats.RidingStatDefinition
import com.cobblemon.mod.common.api.spawning.TimeRange
import com.cobblemon.mod.common.api.types.ElementalType
import com.cobblemon.mod.common.api.types.adapters.ElementalTypeAdapter
import com.cobblemon.mod.common.battles.runner.ShowdownService
import com.cobblemon.mod.common.net.messages.client.data.SpeciesRegistrySyncPacket
import com.cobblemon.mod.common.pokemon.FormData
import com.cobblemon.mod.common.pokemon.Species
@@ -57,7 +56,6 @@ import com.cobblemon.mod.common.pokemon.evolution.adapters.LegacyItemConditionWr
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
import com.cobblemon.mod.common.util.adapters.*
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.ifClient
import com.google.common.collect.HashBasedTable
import com.google.gson.Gson
import com.google.gson.GsonBuilder
@@ -65,13 +63,11 @@ import com.google.gson.reflect.TypeToken
import com.mojang.datafixers.util.Either
import net.minecraft.advancements.critereon.ItemPredicate
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.core.registries.Registries
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.server.packs.PackType
import net.minecraft.tags.TagKey
import net.minecraft.world.effect.MobEffect
import net.minecraft.world.entity.EntityDimensions
import net.minecraft.world.entity.ai.memory.MemoryModuleType
@@ -151,17 +147,12 @@ object PokemonSpecies : JsonDataRegistry<Species> {
val species: Collection<Species>
get() = this.speciesByIdentifier.values
val implemented = mutableListOf<Species>()
val implemented: List<Species>
get() = this.species.filter { it.implemented }
init {
SpeciesAdditions.observable.subscribe {
implemented.clear()
this.species.forEach(Species::initialize)
this.species.forEach {
if (it.implemented) {
this.implemented.add(it)
}
}
this.species.forEach(Species::resolveEvolutionMoves)
Cobblemon.showdownThread.queue {
it.resetRegistryData("species")
@@ -233,7 +224,6 @@ object PokemonSpecies : JsonDataRegistry<Species> {
override fun reload(data: Map<ResourceLocation, Species>) {
this.speciesByIdentifier.clear()
this.implemented.clear()
this.speciesByDex.clear()
data.forEach { (identifier, species) ->
species.resourceIdentifier = identifier
@@ -241,11 +231,6 @@ object PokemonSpecies : JsonDataRegistry<Species> {
this.speciesByDex.remove(old.resourceIdentifier.namespace, old.nationalPokedexNumber)
}
this.speciesByDex.put(species.resourceIdentifier.namespace, species.nationalPokedexNumber, species)
ifClient {
if (species.implemented) {
this.implemented.add(species)
}
}
}
}
@@ -21,6 +21,7 @@ import com.cobblemon.mod.common.api.riding.sound.RideSoundSettingsList
import com.cobblemon.mod.common.api.riding.stats.RidingStat
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.*
import com.cobblemon.mod.common.util.math.geometry.toRadians
import net.minecraft.client.Minecraft
@@ -74,6 +75,21 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
) {
if(vehicle.level().isClientSide) {
tickStamina(settings, state, vehicle, driver)
checkUpsideDown(state, vehicle, driver)
}
}
private fun checkUpsideDown(
state: BirdState,
vehicle: PokemonEntity,
driver: Player,
) {
val controller = (driver as OrientationControllable).orientationController
if (cos(controller.roll.toRadians()) < 0.0) {
val upsideDownRate = 1.0 / (2.0 * 20.0) // 2 seconds to max out upsideDown force
state.currUpsideDownForce.set( min(1.0, state.currUpsideDownForce.get() + upsideDownRate * abs(cos(controller.roll.toRadians()))))
} else { // Its right side up so reset it
state.currUpsideDownForce.set(0.0)
}
}
@@ -92,7 +108,8 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
val stamDrainRate = (1.0f / totalStam).toFloat()
val newStam = if (driver.zza > 0.0) max(0.0f,stam - stamDrainRate)
else min(1.0f,stam + stamDrainRate)
else if (!state.gliding.get()) max(0.0f,stam - stamDrainRate * 0.5f) // if hovering half the stam drain
else min(1.0f,stam + stamDrainRate * 0.2f)
state.stamina.set(newStam)
}
@@ -113,8 +130,6 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
driver: Player,
input: Vec3
): Vec3 {
var yVel = 0.0
var leftForce = 0.0
var upForce = 0.0
var forwardForce = 0.0
@@ -133,7 +148,11 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
forwardForce += sin(Math.toRadians(controller.pitch.toDouble())) * state.rideVelocity.get().y
}
val velocity = Vec3(state.rideVelocity.get().x , upForce, forwardForce)
// The downward force used to encourage players to stop flying upside down.
val extraDownwardForce = if(state.stamina.get() == 0.0f) -0.3
else state.currUpsideDownForce.get().pow(2) * -0.3 // 6 blocks a second downward
val velocity = Vec3(state.rideVelocity.get().x , upForce + extraDownwardForce, forwardForce)
return velocity
}
@@ -228,7 +247,7 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
//Check if the ride should be gliding
if (driver.isLocalPlayer) {
if (activeInput && state.stamina.get() > 0.0) {
if ((activeInput && state.stamina.get() > 0.0) || state.rideVelocity.get().z < 0.2) {
state.gliding.set(false)
} else {
state.gliding.set(true)
@@ -454,11 +473,12 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
val xInput = mouseXSmoother.getNewDeltaValue(mouseXc * 0.1, deltaTime * smoothingSpeed);
val yInput = mouseYSmoother.getNewDeltaValue(mouseYc * 0.1, deltaTime * smoothingSpeed);
val currSpeed = state.rideVelocity.get().length()
val currHorzSpeed = state.rideVelocity.get().horizontalDistance()
val hoverSpeed = 0.1
// Yaw locally when at or below hoverSpeed
val yawDampen = abs(cos(controller.pitch.toRadians())).pow(2) * abs(cos(controller.roll.toRadians())).pow(2)
val localYaw = if (currSpeed < hoverSpeed) xInput * (1 - sqrt(RidingBehaviour.scaleToRange(currSpeed, hoverSpeed, topSpeed))).coerceIn(0.0, 1.0)
val localYaw = if (currHorzSpeed < hoverSpeed) xInput * (1 - sqrt(RidingBehaviour.scaleToRange(currHorzSpeed, hoverSpeed, topSpeed))).coerceIn(0.0, 1.0)
else xInput * 0.4 * cos(controller.roll.toRadians()).coerceIn(0.0f, 1.0f) * yawDampen
// Pitch locally up or down depending upon a number of factors:
@@ -467,14 +487,14 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
// - pitch faster at higher speeds
val p = 1.0 - vehicle.runtime.resolveDouble(settings.horizontalPitchExpr)
var localPitch = yInput * (1 - abs(sin(controller.roll.toRadians())).pow(2) * p * hypot(controller.forwardVector.x.toDouble(), controller.forwardVector.z.toDouble()).toFloat())
localPitch *= if (currSpeed > hoverSpeed) RidingBehaviour.scaleToRange(currSpeed, hoverSpeed, topSpeed)
localPitch *= if (currHorzSpeed > hoverSpeed) RidingBehaviour.scaleToRange(currHorzSpeed, hoverSpeed, topSpeed)
else 0.0
// Roll less when slow and not at all when at hoverSpeed or lower.
// Apply a roll righting force when trying to pitch hard while rolled sideways. This nudges the player towards
// pitching globally
val pitchInfluencedRollCorrection = 0.0 // if ( currSpeed > hoverSpeed * 2) 0.4*(abs(yInput - localPitch) * controller.roll.sign * -1.0) else 0.0
val rollForce = if (currSpeed > hoverSpeed) xInput * sqrt(abs(RidingBehaviour.scaleToRange(currSpeed, hoverSpeed, topSpeed)).coerceIn(0.0,1.0)) + pitchInfluencedRollCorrection
val pitchInfluencedRollCorrection = 0.0
val rollForce = if (currHorzSpeed > hoverSpeed) xInput * sqrt(abs(RidingBehaviour.scaleToRange(currHorzSpeed, hoverSpeed, topSpeed)).coerceIn(0.0,1.0)) + pitchInfluencedRollCorrection
else 0.0
//yaw, pitch, roll
@@ -588,6 +608,17 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
return false
}
override fun damageOnCollision(
settings: BirdSettings,
state: BirdState,
vehicle: PokemonEntity,
impactVec: Vec3
): Boolean {
if (!state.gliding.get()) return false
val impactSpeed = impactVec.horizontalDistance().toFloat() * 10f
return vehicle.causeFallDamage(impactSpeed, 1f, vehicle.damageSources().flyIntoWall())
}
override fun getRideSounds(
settings: BirdSettings,
state: BirdState,
@@ -612,15 +643,15 @@ class BirdSettings : RidingBehaviourSettings {
var timeToRollCorrect: Expression = "0.5".asExpression()
private set
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 90.0, 45.0)".asExpression()
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 45.0, 10.0)".asExpression()
var horizontalPitchExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 0.2, 0.1)".asExpression()
var mouseInputMult: Expression = "q.get_ride_stats('SKILL', 'AIR', 1.2, 0.8)".asExpression()
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 14.0, 8.0)".asExpression()
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 20.0, 4.0)".asExpression()
// Seconds from stationary to top speed
var accelerationExpr: Expression = "q.get_ride_stats('ACCELERATION', 'AIR', 2.0, 5.0)".asExpression()
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'AIR', 22.0, 12.0)".asExpression()
var accelerationExpr: Expression = "q.get_ride_stats('ACCELERATION', 'AIR', 2.0, 8.0)".asExpression()
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'AIR', 15.0, 2.0)".asExpression()
var glidespeedExpr: Expression = "q.get_ride_stats('JUMP', 'AIR', 2.2, 1.5)".asExpression()
var glidespeedExpr: Expression = "q.get_ride_stats('JUMP', 'AIR', 2.0, 1.0)".asExpression()
private set
var rideSounds: RideSoundSettingsList = RideSoundSettingsList()
@@ -663,10 +694,10 @@ class BirdState : RidingBehaviourState() {
var currRollCorrectionForce = ridingState(0.0, Side.CLIENT)
var currPitchCorrectionForce = ridingState(0.0, Side.CLIENT)
var noInputTime = ridingState(0.0, Side.CLIENT)
var currUpsideDownForce = ridingState(0.0, Side.CLIENT)
override fun encode(buffer: FriendlyByteBuf) {
super.encode(buffer)
buffer.writeFloat(stamina.get())
buffer.writeBoolean(gliding.get())
}
@@ -97,7 +97,31 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
driver: Player,
input: Vec3
) {
tickStamina(settings, state, vehicle)
if(vehicle.level().isClientSide) {
tickStamina(settings, state, vehicle)
checkTooHigh(settings, state, vehicle)
}
}
fun checkTooHigh(
settings: HoverSettings,
state: HoverState,
vehicle: PokemonEntity,
) {
val heightLimit = vehicle.runtime.resolveDouble(settings.jumpExpr)
val pos = vehicle.position()
val level = Minecraft.getInstance().player?.level() ?: return
val hit = level.clip(
ClipContext(
pos,
pos.subtract(0.0, heightLimit, 0.0),
ClipContext.Block.COLLIDER,
ClipContext.Fluid.NONE,
vehicle
)
)
state.tooHigh.set(hit.type == HitResult.Type.MISS)
}
fun tickStamina(
@@ -108,7 +132,7 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
val stam = state.stamina.get()
val stamDrainRate = (1.0f / vehicle.runtime.resolveDouble(settings.staminaExpr)).toFloat() / 20.0f
val newStam = min(1.0f,stam + stamDrainRate)
val newStam = if (state.tooHigh.get()) max(0.0f, stam - stamDrainRate) else min(1.0f,stam + stamDrainRate)
state.stamina.set(newStam)
}
@@ -206,6 +230,7 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
// Vertical movement based on driver input.
val vertInput = when {
state.stamina.get() == 0.0f -> -1.0
driver.jumping -> 1.0
driver.isShiftKeyDown -> -1.0
else -> 0.0
@@ -219,28 +244,6 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
driver.zza.sign.toDouble()
).normalize()
/******************************************************
* Boosting Logic
*****************************************************/
if (driver.level().isClientSide) {
if(Minecraft.getInstance().options.keySprint.isDown() && state.stamina.get() == 1.0f && !state.isBoosting.get()) {
state.isBoosting.set(true)
val localBoostVel = if (inputVel.horizontalDistance() == 0.0) Vec3(0.0, 0.0, 1.0) else Vec3(inputVel.x, 0.0, inputVel.z)
state.boostVec.set(localBoostVel)
state.boostTicks.set(0)
state.stamina.set(0.0f)
}
}
val maxBoostTicks = 20
val boostPower = (topSpeed * 20) * 0.1 * vehicle.runtime.resolveDouble(settings.jumpExpr)
if (state.isBoosting.get() && state.boostTicks.get() < maxBoostTicks) {
newVelocity = newVelocity.add(state.boostVec.get().scale(boostPower / maxBoostTicks))
state.boostTicks.set(state.boostTicks.get() + 1)
} else if (state.isBoosting.get()) {
state.isBoosting.set(false)
}
// Air Friction/Resistance
// When the dot between friction and input is -1 we want to apply none of it.
// In short we want to avoid applying friction that opposes our input force.
@@ -431,24 +434,24 @@ class HoverSettings : RidingBehaviourSettings {
private set
// Speed in block per second
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 13.0, 6.0)".asExpression()
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 7.0, 1.0)".asExpression()
private set
// Acceleration in number of seconds to top speed
var accelerationExpr: Expression =
"q.get_ride_stats('ACCELERATION', 'AIR', 2.0, 5.0)".asExpression()
"q.get_ride_stats('ACCELERATION', 'AIR', 2.0, 8.0)".asExpression()
private set
// Amount of seconds between boosts
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'AIR', 1, 4)".asExpression()
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'AIR', 30.0, 2.0)".asExpression()
private set
// Power of boost as a fraction of top speed
var jumpExpr: Expression = "q.get_ride_stats('JUMP', 'AIR', 1.2, 0.2)".asExpression()
// Blocks before stamina drain
var jumpExpr: Expression = "q.get_ride_stats('JUMP', 'AIR', 16.0, 2.0)".asExpression()
private set
// Turn rate in degrees per second when stationary
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 360.0, 90)".asExpression()
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 270.0, 45.0)".asExpression()
private set
var rideSounds: RideSoundSettingsList = RideSoundSettingsList()
@@ -481,17 +484,20 @@ class HoverState : RidingBehaviourState() {
var isBoosting = ridingState(false, Side.BOTH)
var boostVec = ridingState(Vec3.ZERO, Side.CLIENT)
var boostTicks = ridingState(0, Side.CLIENT)
var tooHigh = ridingState(false, Side.CLIENT)
override fun encode(buffer: FriendlyByteBuf) {
super.encode(buffer)
buffer.writeDouble(speed.get())
buffer.writeBoolean(isBoosting.get())
buffer.writeBoolean(tooHigh.get())
}
override fun decode(buffer: FriendlyByteBuf) {
super.decode(buffer)
speed.set(buffer.readDouble(), forced = true)
isBoosting.set(buffer.readBoolean(), forced = true)
tooHigh.set(buffer.readBoolean(), forced = true)
}
override fun reset() {
@@ -500,6 +506,7 @@ class HoverState : RidingBehaviourState() {
isBoosting.set(false, forced = true)
boostVec.set(Vec3.ZERO, forced = true)
boostTicks.set(0, forced = true)
tooHigh.set(false, forced = true)
}
override fun copy() = HoverState().also {
@@ -508,6 +515,7 @@ class HoverState : RidingBehaviourState() {
it.isBoosting.set(this.isBoosting.get(), forced = true)
it.boostVec.set(this.boostVec.get(), forced = true)
it.boostTicks.set(this.boostTicks.get(), forced = true)
it.tooHigh.set(this.tooHigh.get(), forced = true)
}
override fun shouldSync(previous: RidingBehaviourState): Boolean {
@@ -114,10 +114,10 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
val stamDrainRate = (1.0f / vehicle.runtime.resolveDouble(settings.staminaExpr)).toFloat() / 20.0f
if (state.boosting.get()) {
newStam = max(0.0f,stam - stamDrainRate)
newStam = max(0.0f,stam - stamDrainRate * 1.5f)
} else {
newStam = min(1.0f,stam + stamDrainRate * 0.25f)
newStam = max(0.0f,stam - stamDrainRate)
}
state.stamina.set(newStam)
@@ -149,11 +149,15 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
//Translate ride space velocity to world space velocity.
if (controller != null) {
upForce = -1.0 * sin(Math.toRadians(controller.pitch.toDouble())) * state.rideVelocity.get().z
upForce = if(state.stamina.get() != 0.0f) -1.0 * sin(Math.toRadians(controller.pitch.toDouble())) * state.rideVelocity.get().z
else min(0.0, -1.0 * sin(Math.toRadians(controller.pitch.toDouble())) * state.rideVelocity.get().z)
forwardForce = cos(Math.toRadians(controller.pitch.toDouble())) * state.rideVelocity.get().z
}
val velocity = Vec3(0.0, upForce, forwardForce)
// The downward force used to encourage players to stop flying upside down.
val extraDownwardForce = if(state.stamina.get() == 0.0f) -0.3 else 0.0 // 6 blocks a second downward
val velocity = Vec3(0.0, upForce + extraDownwardForce, forwardForce)
return velocity
}
@@ -177,7 +181,17 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
val boostAccel = accel * boostMult
//speed up and slow down based on input
if (state.boosting.get() && speed < boostTopSpeed) {
if (state.stamina.get() == 0.0f) {
// Decelerate currently always a constant half of max acceleration.
state.rideVelocity.set(
Vec3(
state.rideVelocity.get().x,
state.rideVelocity.get().y,
max(state.rideVelocity.get().z - ((accel) / 2), minSpeed * 0.5)
)
)
}
else if (state.boosting.get() && speed < boostTopSpeed) {
state.rideVelocity.set(
Vec3(
state.rideVelocity.get().x,
@@ -305,7 +319,8 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
state.currMouseYForce.set((state.currMouseYForce.get() + (0.0015 * mouseY)).coerceIn(-1.0, 1.0))
//Get handling in degrees per second
var handling = vehicle.runtime.resolveDouble(settings.handlingExpr)
val handlingDebuff = if(state.stamina.get() == 0.0f) 0.5 else 1.0
var handling = vehicle.runtime.resolveDouble(settings.handlingExpr) * handlingDebuff
//convert it to delta time
handling *= (cappedDeltaTime)
@@ -358,7 +373,8 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
state.currMouseYForce.set((state.currMouseYForce.get() + (0.0015 * mouseY)).coerceIn(-1.0, 1.0))
//Get handling in degrees per second
var handling = vehicle.runtime.resolveDouble(settings.handlingExpr)
val handlingDebuff = if(state.stamina.get() == 0.0f) 0.5 else 1.0
var handling = vehicle.runtime.resolveDouble(settings.handlingExpr) * handlingDebuff
//convert it to delta time
handling *= (cappedDeltaTime)
@@ -521,21 +537,21 @@ class JetSettings : RidingBehaviourSettings {
private set
// Boost power. Mult for top speed and accel while boosting
var jumpExpr: Expression = "q.get_ride_stats('JUMP', 'AIR', 1.7, 1.2)".asExpression()
var jumpExpr: Expression = "q.get_ride_stats('JUMP', 'AIR', 2.0, 1.0)".asExpression()
private set
// Turn rate in degrees per second
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 120.0, 60.0)".asExpression()
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 60.0, 20.0)".asExpression()
private set
// Top Speed in blocks per second
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 36.0, 20.0)".asExpression()
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 24.0, 4.0)".asExpression()
private set
// Acceleration in blocks per s^2
var accelerationExpr: Expression =
"q.get_ride_stats('ACCELERATION', 'AIR', 5.0, 2.5)".asExpression()
"q.get_ride_stats('ACCELERATION', 'AIR', 4.0, 1.0)".asExpression()
private set
// Time in seconds to drain full bar of stamina when boosting
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'AIR', 8.0, 4.0)".asExpression()
// Time in seconds to drain full bar of stamina flying
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'AIR', 60.0, 4.0)".asExpression()
private set
var rideSounds: RideSoundSettingsList = RideSoundSettingsList()
@@ -86,7 +86,7 @@ class RocketBehaviour : RidingBehaviour<RocketSettings, RocketState> {
// Use this as a "tick" function and check to see if the driver is "boosting"
if(vehicle.level().isClientSide) {
handleBoosting(settings, state, vehicle, driver)
tickStamina(settings, state, vehicle)
tickStamina(settings, state, vehicle, driver)
}
return state.rideVelocity.get().length().toFloat()
@@ -101,7 +101,6 @@ class RocketBehaviour : RidingBehaviour<RocketSettings, RocketState> {
//If the forward key is not held then it cannot be boosting
if(Minecraft.getInstance().options.keyUp.isDown() && state.stamina.get() != 0.0f) {
val boostKeyPressed = Minecraft.getInstance().options.keySprint.isDown()
if (state.stamina.get() >= 0.25f) {
//If on the previous tick the boost key was held then don't change if the ride is boosting
if(state.boostIsToggleable.get() && boostKeyPressed) {
//flip the boosting state if boost key is pressed
@@ -109,7 +108,6 @@ class RocketBehaviour : RidingBehaviour<RocketSettings, RocketState> {
}
//If the boost key is not held then next tick boosting is toggleable
state.boostIsToggleable.set(!boostKeyPressed)
}
} else {
//Turn off boost and reset boost params
state.boostIsToggleable.set(true)
@@ -121,7 +119,8 @@ class RocketBehaviour : RidingBehaviour<RocketSettings, RocketState> {
fun tickStamina(
settings: RocketSettings,
state: RocketState,
vehicle: PokemonEntity
vehicle: PokemonEntity,
driver: Player
) {
val stam = state.stamina.get()
@@ -131,8 +130,7 @@ class RocketBehaviour : RidingBehaviour<RocketSettings, RocketState> {
val boostTime = vehicle.runtime.resolveDouble(settings.staminaExpr) * 20.0f
val stamDrainRate = (1.0f / boostTime).toFloat()
val newStam = if (state.boosting.get()) max(0.0f,stam - stamDrainRate)
else min(1.0f,stam + stamDrainRate)
val newStam = if(state.boosting.get() || driver.jumping) max(0.0f,stam - stamDrainRate) else stam
state.stamina.set(newStam)
}
@@ -266,7 +264,7 @@ class RocketBehaviour : RidingBehaviour<RocketSettings, RocketState> {
if(state.canSpeedBurst.get()) {
burst = 0.5f
state.stamina.set(max(0.0f,state.stamina.get() - 0.1f))
state.stamina.set(max(0.0f,state.stamina.get() - 0.05f))
state.canSpeedBurst.set(false)
}
@@ -301,7 +299,7 @@ class RocketBehaviour : RidingBehaviour<RocketSettings, RocketState> {
} else {
if (driver.jumping && !(vehicle.deltaMovement.y > maxVertSpeed && (newVelocity.y.sign.toFloat() > 0.0))) {
// More force if traveling downwards to allow for quicker fall stops
vertInput = if (newVelocity.y < 0) jump * 3 else jump
vertInput = (if (state.stamina.get() == 0.0f) -1.0f else if(newVelocity.y < 0) jump.toFloat() * 3.0f else jump.toFloat()).toDouble()
// Reset falldistance if upward motion is detected
vehicle.resetFallDistance()
newVelocity = Vec3(
@@ -474,6 +472,18 @@ class RocketBehaviour : RidingBehaviour<RocketSettings, RocketState> {
return false
}
override fun damageOnCollision(
settings: RocketSettings,
state: RocketState,
vehicle: PokemonEntity,
impactVec: Vec3
): Boolean {
if (!state.boosting.get()) return false
val impactSpeed = impactVec.horizontalDistance().toFloat() * 10f
return vehicle.causeFallDamage(impactSpeed, 1f, vehicle.damageSources().flyIntoWall())
}
override fun getRideSounds(
settings: RocketSettings,
state: RocketState,
@@ -509,8 +519,8 @@ class RocketSettings : RidingBehaviourSettings {
"q.get_ride_stats('ACCELERATION', 'AIR', (1.0 / (20.0 * 1.5)), (1.0 / (20.0 * 3.0))) * 0.5".asExpression()
private set
// Boost time in seconds
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'AIR', 7.5, 2.5)".asExpression()
// air time in seconds
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'AIR', 20.0, 10.0)".asExpression()
private set
var jumpExpr: Expression = "q.get_ride_stats('JUMP', 'AIR', 2.0, 1.0)".asExpression()
@@ -520,7 +520,7 @@ class HorseSettings : RidingBehaviourSettings {
private set
//Between a one block jump and a six block jump
var jumpExpr: Expression = "q.get_ride_stats('JUMP', 'LAND', 1.2, 0.45)".asExpression()
var jumpExpr: Expression = "q.get_ride_stats('JUMP', 'LAND', 1.0, 0.38)".asExpression()
private set
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'LAND', 180.0, 40.0)".asExpression()
@@ -29,9 +29,11 @@ object BattleRegistry {
.registerTypeAdapter(ShowdownMoveset::class.java, ShowdownMovesetAdapter)
.create()
private val battleMap = ConcurrentHashMap<UUID, PokemonBattle>()
private val battleLock = ConcurrentHashMap<UUID, Boolean>()
fun onServerStarted() {
battleMap.clear()
battleLock.clear()
}
fun onPlayerDisconnect(player: ServerPlayer) {
@@ -205,12 +207,18 @@ object BattleRegistry {
startShowdown(battle)
}
if (!canPreempt) start().also { return SuccessfulBattleStart(battle) }
if (!canPreempt) start().also {
side1.actors.forEach { actor -> battleLock.remove(actor.uuid) }
side2.actors.forEach { actor -> battleLock.remove(actor.uuid) }
return SuccessfulBattleStart(battle)
}
val preBattleEvent = BattleStartedEvent.Pre(battle)
CobblemonEvents.BATTLE_STARTED_PRE.postThen(preBattleEvent) {
start()
CobblemonEvents.BATTLE_STARTED_POST.post(BattleStartedEvent.Post(battle))
side1.actors.forEach { actor -> battleLock.remove(actor.uuid) }
side2.actors.forEach { actor -> battleLock.remove(actor.uuid) }
return SuccessfulBattleStart(battle)
}
return ErroredBattleStart(mutableSetOf(BattleStartError.canceledByEvent(preBattleEvent.reason)))
@@ -229,6 +237,19 @@ object BattleRegistry {
return battleMap.values.find { it.getActor(serverPlayer) != null }
}
fun checkBattleLock(serverPlayer: ServerPlayer, ancientIsOkay: Boolean): Boolean =
if (ancientIsOkay)
battleLock.get(serverPlayer.uuid) == false
else
battleLock.containsKey(serverPlayer.uuid)
fun lockPlayer(serverPlayer: ServerPlayer, ancient: Boolean) {
battleLock.put(serverPlayer.uuid, ancient)
}
fun unlockPlayer(serverPlayer: ServerPlayer) {
battleLock.remove(serverPlayer.uuid)
}
fun getBattleByParticipatingPlayerId(playerId: UUID): PokemonBattle? {
return battleMap.values.find { playerId in it.playerUUIDs }
}
@@ -249,7 +249,7 @@ class ForcePassActionResponse : ShowdownActionResponse(ShowdownActionResponseTyp
return false
}
return activeBattlePokemon.actor.expectingPassActions.size > 0
return activeBattlePokemon.actor.expectingPassActions.isNotEmpty()
}
override fun toShowdownString(activeBattlePokemon: ActiveBattlePokemon, showdownMoveSet: ShowdownMoveset?) = "pass"
@@ -100,7 +100,7 @@ class HeartyGrainsBlock(settings: Properties) : CropBlock(settings), SimpleWater
override fun randomTick(state: BlockState, world: ServerLevel, pos: BlockPos, random: RandomSource) {
if (state.getValue(HALF) == DoubleBlockHalf.UPPER || !canGrow(world, pos, state)) return
if (hasSufficientLight(world, pos) && random.nextInt(7) == 0) {
if (hasSufficientLight(world, pos) && random.nextInt(16) == 0) {
grow(world, pos, state, 1)
}
}
@@ -0,0 +1,19 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.block.campfirepot
enum class CampfirePotColor(val suffix: String) {
RED("red"),
BLUE("blue"),
GREEN("green"),
PINK("pink"),
WHITE("white"),
YELLOW("yellow"),
BLACK("black");
}
@@ -56,7 +56,7 @@ class CookingPotMenu : RecipeBookMenu<CraftingInput, CookingPotRecipeBase>, Cont
CampfireBlockEntity.Companion.CRAFTING_GRID_WIDTH
)
this.resultContainer = ResultContainer()
this.containerData = SimpleContainerData(3)
this.containerData = SimpleContainerData(4)
this.addDataSlots(containerData)
this.player = playerInventory.player
this.level = playerInventory.player.level()
@@ -280,4 +280,4 @@ class CookingPotMenu : RecipeBookMenu<CraftingInput, CookingPotRecipeBase>, Cont
value: Int
) {
}
}
}
@@ -57,8 +57,8 @@ import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.gameevent.GameEvent
import net.minecraft.world.phys.Vec3
import org.joml.Vector4f
import com.cobblemon.mod.common.item.CampfirePotItem
import java.util.*
import kotlin.math.sign
class CampfireBlockEntity(pos: BlockPos, state: BlockState) : BaseContainerBlockEntity(
CobblemonBlockEntities.CAMPFIRE,
@@ -84,6 +84,7 @@ class CampfireBlockEntity(pos: BlockPos, state: BlockState) : BaseContainerBlock
const val COOKING_PROGRESS_INDEX = 0
const val COOKING_PROGRESS_TOTAL_TIME_INDEX = 1
const val IS_LID_OPEN_INDEX = 2
const val COOKING_POT_COLOR_INDEX = 3
const val BASE_BROTH_COLOR = 0xFDFACF
const val BASE_BROTH_BUBBLE_COLOR = 0xFFFEFDE4.toInt()
@@ -242,6 +243,7 @@ class CampfireBlockEntity(pos: BlockPos, state: BlockState) : BaseContainerBlock
COOKING_PROGRESS_INDEX -> this@CampfireBlockEntity.cookingProgress
COOKING_PROGRESS_TOTAL_TIME_INDEX -> this@CampfireBlockEntity.cookingTotalTime
IS_LID_OPEN_INDEX -> if (this@CampfireBlockEntity.blockState.getValue(CampfireBlock.LID)) 0 else 1
COOKING_POT_COLOR_INDEX -> (this@CampfireBlockEntity.getPotItem()?.item as? CampfirePotItem)?.color?.ordinal ?: 0
else -> 0
}
}
@@ -251,11 +253,12 @@ class CampfireBlockEntity(pos: BlockPos, state: BlockState) : BaseContainerBlock
COOKING_PROGRESS_INDEX -> this@CampfireBlockEntity.cookingProgress = value
COOKING_PROGRESS_TOTAL_TIME_INDEX -> this@CampfireBlockEntity.cookingTotalTime = value
IS_LID_OPEN_INDEX -> this@CampfireBlockEntity.toggleLid(value == 1)
COOKING_POT_COLOR_INDEX -> {}
}
}
override fun getCount(): Int {
return 3
return 4
}
}
@@ -481,4 +484,4 @@ class CampfireBlockEntity(pos: BlockPos, state: BlockState) : BaseContainerBlock
}
}
}
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.client.gui.cookingpot
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.block.campfirepot.CampfirePotColor
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.components.Button
@@ -21,6 +22,7 @@ import net.minecraft.sounds.SoundEvents
class CookButton(
pX: Int, pY: Int,
var selected: Boolean = false,
var color: CampfirePotColor,
onPress: OnPress
): Button(pX, pY, SIZE.toInt(), SIZE.toInt(), Component.literal("Cook"), onPress, DEFAULT_NARRATION) {
@@ -28,11 +30,11 @@ class CookButton(
private const val SIZE = 20F
private val buttonResource = cobblemonResource("textures/gui/campfirepot/button.png")
private val buttonIconResource = cobblemonResource("textures/item/campfire_pots/campfire_pot_red.png")
private val buttonIconOpenResource = cobblemonResource("textures/item/campfire_pots/campfire_pot_red_open.png")
}
override fun renderWidget(context: GuiGraphics, pMouseX: Int, pMouseY: Int, pPartialTicks: Float) {
val closedIcon = cobblemonResource("textures/item/campfire_pots/campfire_pot_${color.suffix}.png")
val openIcon = cobblemonResource("textures/item/campfire_pots/campfire_pot_${color.suffix}_open.png")
blitk(
matrixStack = context.pose(),
texture = buttonResource,
@@ -46,7 +48,7 @@ class CookButton(
blitk(
matrixStack = context.pose(),
texture = if (selected) buttonIconResource else buttonIconOpenResource,
texture = if (selected) closedIcon else openIcon,
x = x + 2,
y = y + 2,
width = 16,
@@ -11,8 +11,10 @@ package com.cobblemon.mod.common.client.gui.cookingpot
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonNetwork.sendToServer
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.block.campfirepot.CampfirePotColor
import com.cobblemon.mod.common.block.campfirepot.CookingPotMenu
import com.cobblemon.mod.common.block.campfirepot.SeasoningSlot
import com.cobblemon.mod.common.block.entity.CampfireBlockEntity.Companion.COOKING_POT_COLOR_INDEX
import com.cobblemon.mod.common.block.entity.CampfireBlockEntity.Companion.IS_LID_OPEN_INDEX
import com.cobblemon.mod.common.integration.jei.CobblemonJeiPlugin
import com.cobblemon.mod.common.integration.jei.cooking.CampfirePotRecipeCategory
@@ -118,7 +120,8 @@ class CookingPotScreen(
this.titleLabelY = 6
if (::cookButton.isInitialized) removeWidget(cookButton)
cookButton = CookButton(this.leftPos + 97, topPos + 56, menu.containerData.get(IS_LID_OPEN_INDEX) == 0) {
val color = CampfirePotColor.entries[menu.containerData.get(COOKING_POT_COLOR_INDEX).coerceIn(0, CampfirePotColor.entries.lastIndex)]
cookButton = CookButton(this.leftPos + 97, topPos + 56, menu.containerData.get(IS_LID_OPEN_INDEX) == 0, color) {
val isLidClosed = menu.containerData.get(IS_LID_OPEN_INDEX) == 0
sendToServer(ToggleCookingPotLidPacket(isLidClosed))
}
@@ -161,6 +164,7 @@ class CookingPotScreen(
mouseY: Int,
partialTicks: Float
) {
cookButton.color = CampfirePotColor.entries[menu.containerData.get(COOKING_POT_COLOR_INDEX).coerceIn(0, CampfirePotColor.entries.lastIndex)]
cookButton.selected = menu.containerData.get(IS_LID_OPEN_INDEX) == 0
cookButton.setPosition(this.leftPos + 97, topPos + 56)
@@ -0,0 +1,179 @@
/*
* 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.gui.debug.riding
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.CobblemonNetwork
import com.cobblemon.mod.common.api.riding.RidingStyle
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.net.messages.server.debug.ServerboundUpdateRidingSettingsPacket
import com.cobblemon.mod.common.net.messages.server.debug.ServerboundUpdateRidingStatsPacket
import com.cobblemon.mod.common.net.serverhandling.debug.ServerboundUpdateRidingSettingsHandler
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.getString
import com.cobblemon.mod.common.util.lang
import com.cobblemon.mod.common.util.resolve
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.components.Button
import net.minecraft.client.gui.components.EditBox
import net.minecraft.client.gui.screens.Screen
import java.awt.Color
/**
* Ride Settings Editor to change the underlying expressions and
* stat mins and maxes of your ride on the fly (pun intended)
*
* Description
*
* @author Jackson
* @since September 13, 2025
*/
class RideSettingsEditorGUI(val parentScreen: Screen, val vehicle: PokemonEntity, val rideStyle: RidingStyle, val rideSettings: RidingBehaviourSettings) : Screen(lang("ui.debug.riding_settings")), CobblemonRenderable {
private val settingWidgets = mutableListOf<Pair<String, EditBox>>()
private val originalValues = mutableMapOf<String, String>() // Used to keep track of saved state of editboxes
override fun init() {
super.init()
clearWidgets()
// Take note of the current saved values in the settings
if (originalValues.isEmpty()) {
val expressionVariables = getExpressionVariables(rideSettings)
for ((name, value) in expressionVariables) {
originalValues[name] = value
}
}
addRenderableWidget(
Button.builder("Back".text()) {
this.minecraft?.setScreen(parentScreen)
}.bounds(10, 10, 40, 20).build()
)
addRenderableWidget(
Button.builder("Save".text()) { button ->
saveRideSettings()
}.bounds(300 + 110, 10, 40, 20).build()
)
createExpressionEditBoxes()
}
override fun render(guiGraphics: GuiGraphics, mouseX: Int, mouseY: Int, partialTick: Float) {
// Make the background blank and transparent?
guiGraphics.fill(0, 0, width, height, Color(0, 0, 0, 100).rgb)
super.render(guiGraphics, mouseX, mouseY, partialTick)
for ((name, editBox) in settingWidgets) {
// Position the text next to the EditBox
guiGraphics.drawString(font, name, editBox.x - 105, editBox.y + 5, 0xFFFFFF)
}
}
private fun createExpressionEditBoxes() {
val expressionVariables = getExpressionVariables(rideSettings)
var currentY = 40
for (variable in expressionVariables) {
val (name, value) = variable
val editBox = EditBox(this.minecraft!!.font, 110, currentY, 300, 20, name.text())
editBox.setMaxLength(256)
editBox.value = value
// Dry run expression changes and if valid then turn white and if
// invalid then turn red. If it remains the same it is green
editBox.setResponder { newExpression ->
when {
!validateExpression(newExpression) -> editBox.setTextColor(0xFF5555)
newExpression == originalValues[name] -> editBox.setTextColor(0x55FF55)
else -> editBox.setTextColor(0xFFFFFF)
}
}
// Set all Boxes to green as they are currently saved
editBox.setTextColor(0x55FF55)
// Add widget
addRenderableWidget(editBox)
// Add widget to list
settingWidgets.add(name to editBox)
currentY += 25
}
}
private fun saveRideSettings() {
for ((name, editBox) in settingWidgets) {
// If expression is valid then save and turn green
if (validateExpression(editBox.value)) {
ServerboundUpdateRidingSettingsHandler.modifyRideSettingsExpression(
vehicle,
rideStyle,
name,
editBox.value
)
// Update the running list of last saved values too
originalValues[name] = editBox.value
// Update server with
CobblemonNetwork.sendToServer(
ServerboundUpdateRidingSettingsPacket(
vehicle.id,
rideStyle,
name,
editBox.value
)
)
editBox.setTextColor(0x55FF55)
}
}
}
private fun validateExpression(expression: String): Boolean {
return try {
// Attempt to parse as expression
val parsedExpression = expression.asExpression()
// Dry run to ensure its not borked.
vehicle.runtime.resolve(parsedExpression)
true
} catch (e: Exception) {
false
}
}
private fun getExpressionVariables(settings: RidingBehaviourSettings): List<Pair<String, String>> {
val clazz = settings.javaClass
val fields = clazz.declaredFields
// Iterate through all expression fields and return the list of those that
// aer expressions
return fields.mapNotNull { field ->
if (field.type == Expression::class.java) {
field.isAccessible = true // Make private fields accessible
val name = field.name
// Get the value, cast it, and call .getString() on it
val value = (field.get(settings) as Expression).getString()
// Create the pair and return it for the list
name to value
} else {
// If it's not an Expression (they all honestly should be if being used by the
// behaviour in question) then ignore
null
}
}
}
}
@@ -33,26 +33,28 @@ class RidingStatsDebugGUI(val vehicle: PokemonEntity) : Screen(lang("ui.debug.ri
var ridingStyle: RidingStyle = RidingStyle.LAND
val changeRidingStyle: Button
private lateinit var changeRidingStyle: Button
val speedSlider: SettingsSlider
val accelerationSlider: SettingsSlider
val skillSlider: SettingsSlider
val jumpSlider: SettingsSlider
val staminaSlider: SettingsSlider
private lateinit var speedSlider: SettingsSlider
private lateinit var accelerationSlider: SettingsSlider
private lateinit var skillSlider: SettingsSlider
private lateinit var jumpSlider: SettingsSlider
private lateinit var staminaSlider: SettingsSlider
val minSpeedInput: RidingStatInputWidget
val maxSpeedInput: RidingStatInputWidget
val minAccelerationInput: RidingStatInputWidget
val maxAccelerationInput: RidingStatInputWidget
val minSkillInput: RidingStatInputWidget
val maxSkillInput: RidingStatInputWidget
val minJumpInput: RidingStatInputWidget
val maxJumpInput: RidingStatInputWidget
val minStaminaInput: RidingStatInputWidget
val maxStaminaInput: RidingStatInputWidget
private lateinit var minSpeedInput: RidingStatInputWidget
private lateinit var maxSpeedInput: RidingStatInputWidget
private lateinit var minAccelerationInput: RidingStatInputWidget
private lateinit var maxAccelerationInput: RidingStatInputWidget
private lateinit var minSkillInput: RidingStatInputWidget
private lateinit var maxSkillInput: RidingStatInputWidget
private lateinit var minJumpInput: RidingStatInputWidget
private lateinit var maxJumpInput: RidingStatInputWidget
private lateinit var minStaminaInput: RidingStatInputWidget
private lateinit var maxStaminaInput: RidingStatInputWidget
init {
public override fun init() {
super.init()
clearWidgets()
ridingStyle = vehicle.ifRidingAvailableSupply(RidingStyle.LAND) { behaviour, settings, state ->
behaviour.getRidingStyle(settings, state)
}
@@ -94,6 +96,15 @@ class RidingStatsDebugGUI(val vehicle: PokemonEntity) : Screen(lang("ui.debug.ri
}.bounds(getScaledWidth() - 210, 220, 200, 20).build()
)
addRenderableWidget(
Button.builder("Edit Ride Settings".text()) { button ->
// Grab the ride settings for the currently being configured style
val rideSettings = vehicle.ridingController?.behaviours?.get(ridingStyle) ?: return@builder
// Open up GUI for editing the given settings
this.minecraft?.setScreen(RideSettingsEditorGUI(this, vehicle, ridingStyle, rideSettings))
}.bounds(10, 240, 200, 20).build()
)
refresh()
}
@@ -266,6 +266,7 @@ class PCGUI(
tooltipKey = "ui.sort.${typeName}",
label = "sort_${typeName}"
) {
storageWidget.resetSelected()
SortPCBoxPacket(pc.uuid, storageWidget.box, sortType, hasShiftDown()).sendToServer()
}.also {
it.visible = displayOptions
@@ -719,7 +720,7 @@ class PCGUI(
if (pasture.pastureScrollList.isHovered) pasture.pastureScrollList.mouseScrolled(mouseX, mouseY, amount, verticalAmount)
}
if (storageWidget.isHovered && mouseX < (storageWidget.x + StorageWidget.SCREEN_WIDTH)) this.storageWidget.box -= verticalAmount.toInt()
if (wallpaperWidget.isHovered) wallpaperWidget.mouseScrolled(mouseX, mouseY, amount, verticalAmount)
if (::wallpaperWidget.isInitialized && wallpaperWidget.isHovered) wallpaperWidget.mouseScrolled(mouseX, mouseY, amount, verticalAmount)
val infoBoxX = ((width - BASE_WIDTH) / 2) + 9
val infoBoxY = ((height - BASE_HEIGHT) / 2) + 128
@@ -492,7 +492,7 @@ class StorageWidget(
}
}
private fun resetSelected() {
fun resetSelected() {
selectedPosition = null
grabbedSlot = null
pcGui.setPreviewPokemon(null)
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.client.keybind.keybinds
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonNetwork.sendToServer
import com.cobblemon.mod.common.api.riding.RidingStyle
import com.cobblemon.mod.common.battles.BattleFormat
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.battle.ClientBattle
@@ -84,7 +85,7 @@ object PartySendBinding : CobblemonBlockingKeyBinding(
if (isRidingPokemon(player) && canAttemptDismount(player, selectedPartyPokemon)) {
sendToServer(DismountPokemonPacket())
}
else {
else if (!isRidingSelectedPokemon(player, selectedPartyPokemon)){
checkForTargetInteractions(player, selectedPartyPokemon)
}
}
@@ -145,6 +146,11 @@ object PartySendBinding : CobblemonBlockingKeyBinding(
if (player != vehicle.controllingPassenger) {
return true
}
val isAirRide = vehicle.ridingController?.context?.style == RidingStyle.AIR
val hasLandRide = vehicle.rideProp.behaviours?.get(RidingStyle.LAND) != null
if (isAirRide && hasLandRide) {
return false
}
else {
return vehicle.pokemon.uuid == selectedPartyPokemon.uuid
}
@@ -157,6 +163,14 @@ object PartySendBinding : CobblemonBlockingKeyBinding(
return true
}
private fun isRidingSelectedPokemon(player: LocalPlayer, selectedPartyPokemon: Pokemon, ignoreControlling: Boolean = false): Boolean {
if (!player.isPassenger) return false
if (player.vehicle !is PokemonEntity) return false
val vehicle = player.vehicle as PokemonEntity
if (ignoreControlling && player.vehicle!!.controllingPassenger == player) return false
return vehicle.pokemon.uuid == selectedPartyPokemon.uuid
}
override fun onPress() {
}
}
@@ -231,8 +231,8 @@ data class BedrockAnimation(
if (!timeline.scale.isEmpty()) {
var scale = timeline.scale.resolve(animationSeconds.toDouble(), runtime)
// If the goal is to make the invisible then kick that into gear after 0.5. Maybe could work better somehow else.
if (scale == Vec3.ZERO && intensity > 0.5) {
// If the goal is to make the invisible then kick that into gear after or on 0.5. Maybe could work better somehow else.
if (scale == Vec3.ZERO && intensity >= 0.5) {
part.xScale *= scale.x.toFloat()
part.yScale *= scale.y.toFloat()
part.zScale *= scale.z.toFloat()
@@ -1,88 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
import com.cobblemon.mod.common.client.render.models.blockbench.createTransformation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.ModelPartTransformation
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class MewModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
override val rootPart = root.registerChildWithAllChildren("mew")
override val head = getPart("head")
override var portraitScale = 2.3F
override var portraitTranslation = Vec3(-0.15, 0.4, 0.0)
override var profileScale = 0.7F
override var profileTranslation = Vec3(0.0, 0.65, 0.0)
lateinit var standing: Pose
lateinit var walk: Pose
lateinit var shoulderLeft: Pose
lateinit var shoulderRight: Pose
val shoulderOffset = 1.5
override fun registerPoses() {
standing = registerPose(
poseName = "standing",
poseTypes = STATIONARY_POSES + UI_POSES,
animations = arrayOf(
singleBoneLook(),
bedrock("mew", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = MOVING_POSES,
animations = arrayOf(
singleBoneLook(),
bedrock("mew", "ground_walk")
)
)
shoulderLeft = registerPose(
poseType = PoseType.SHOULDER_LEFT,
//quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("mew", "ground_idle")
),
transformedParts = arrayOf(
rootPart.createTransformation().addPosition(ModelPartTransformation.X_AXIS, shoulderOffset)
)
)
shoulderRight = registerPose(
poseType = PoseType.SHOULDER_RIGHT,
//quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("mew", "ground_idle")
),
transformedParts = arrayOf(
rootPart.createTransformation().addPosition(ModelPartTransformation.X_AXIS, -shoulderOffset)
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PosableState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("mew", "faint") else null
}
@@ -1,65 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen3
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BimanualSwingAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BipedWalkAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.entity.PoseType
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class NuzleafModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame, BimanualFrame {
override val rootPart = root.registerChildWithAllChildren("nuzleaf")
override val head = getPart("head")
override val leftArm = getPart("arm_left")
override val rightArm = getPart("arm_right")
override val leftLeg = getPart("leg_left")
override val rightLeg = getPart("leg_right")
override var portraitScale = 2.6F
override var portraitTranslation = Vec3(-0.15, -0.65, 0.0)
override var profileScale = 0.9F
override var profileTranslation = Vec3(0.0, 0.44, 0.0)
lateinit var standing: Pose
lateinit var walk: Pose
override fun registerPoses() {
val blink = quirk { bedrockStateful("nuzleaf", "blink") }
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("nuzleaf", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("nuzleaf", "ground_idle"),
BipedWalkAnimation(this, periodMultiplier = 0.6F, amplitudeMultiplier = 0.9F),
BimanualSwingAnimation(this, swingPeriodMultiplier = 0.6F, amplitudeMultiplier = 0.9F)
//bedrock("nuzleaf", "ground_walk")
)
)
}
}
@@ -1,55 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen3
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BipedWalkAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.entity.PoseType
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class SeedotModel (root: ModelPart) : PokemonPosableModel(root), BipedFrame {
override val rootPart = root.registerChildWithAllChildren("seedot")
override val leftLeg = getPart("foot_left")
override val rightLeg = getPart("foot_right")
override var portraitScale = 2.8F
override var portraitTranslation = Vec3(-0.1, -2.5, 0.0)
override var profileScale = 1.0F
override var profileTranslation = Vec3(0.0, 0.3, 0.0)
lateinit var standing: Pose
lateinit var walk: Pose
override fun registerPoses() {
val blink = quirk { bedrockStateful("seedot", "blink") }
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
quirks = arrayOf(blink),
animations = arrayOf(
bedrock("seedot", "idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES,
quirks = arrayOf(blink),
animations = arrayOf(
BipedWalkAnimation(this, amplitudeMultiplier = 0.9F, periodMultiplier = 1F),
bedrock("seedot", "idle")
)
)
}
}
@@ -1,65 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen3
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BimanualSwingAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BipedWalkAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.entity.PoseType
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class ShiftryModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame, BimanualFrame {
override val rootPart = root.registerChildWithAllChildren("shiftry")
override val head = getPart("head")
override val leftArm = getPart("arm_left")
override val rightArm = getPart("arm_right")
override val leftLeg = getPart("leg_left")
override val rightLeg = getPart("leg_right")
override var portraitScale = 2.0F
override var portraitTranslation = Vec3(-0.15, 0.5, 0.0)
override var profileScale = 0.74F
override var profileTranslation = Vec3(0.0, 0.7, 0.0)
lateinit var standing: Pose
lateinit var walk: Pose
override fun registerPoses() {
val blink = quirk { bedrockStateful("shiftry", "blink") }
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("shiftry", "idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("shiftry", "idle"),
BipedWalkAnimation(this, periodMultiplier = 0.6F, amplitudeMultiplier = 0.9F),
BimanualSwingAnimation(this, swingPeriodMultiplier = 0.6F, amplitudeMultiplier = 0.9F)
//bedrock("shiftry", "ground_walk")
)
)
}
}
@@ -1,90 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen4
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
import com.cobblemon.mod.common.util.isBattling
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class LickilickyModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame, BimanualFrame {
override val rootPart = root.registerChildWithAllChildren("lickilicky")
override val head = getPart("head")
override val leftLeg = getPart("left_leg")
override val rightLeg = getPart("right_leg")
override val leftArm = getPart("left_upper_arm")
override val rightArm = getPart("right_upper_arm")
override var portraitScale = 1.4F
override var portraitTranslation = Vec3(-0.2, 1.8, 0.0)
override var profileScale = 0.5F
override var profileTranslation = Vec3(0.0, 1.0, 0.0)
lateinit var standing: Pose
lateinit var walk: Pose
lateinit var battleidle: Pose
lateinit var sleep: Pose
override fun registerPoses() {
val blink = quirk { bedrockStateful("lickilicky", "blink") }
sleep = registerPose(
poseType = PoseType.SLEEP,
animations = arrayOf(bedrock("lickilicky", "sleep"))
)
standing = registerPose(
poseName = "standing",
poseTypes = STATIONARY_POSES + UI_POSES,
quirks = arrayOf(blink),
condition = { !it.isBattling },
animations = arrayOf(
singleBoneLook(),
bedrock("lickilicky", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = MOVING_POSES,
condition = { !it.isBattling },
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("lickilicky", "ground_walk")
)
)
battleidle = registerPose(
poseName = "battle_idle",
poseTypes = PoseType.STATIONARY_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
condition = { it.isBattling },
animations = arrayOf(
singleBoneLook(),
bedrock("lickilicky", "battle_idle")
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PosableState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk, battleidle, sleep)) bedrockStateful("lickilicky", "faint") else null
}
@@ -1,100 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen4
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BipedWalkAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.createTransformation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pose.ModelPartTransformation
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class PachirisuModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame {
override val rootPart = root.registerChildWithAllChildren("pachirisu")
override val head = getPart("head")
override val leftLeg = getPart("leftfoot")
override val rightLeg = getPart("rightfoot")
override var portraitScale = 2.3F
override var portraitTranslation = Vec3(-0.2, -1.1, 0.0)
override var profileScale = 0.8F
override var profileTranslation = Vec3(0.0, 0.55, 0.0)
lateinit var standing: Pose
lateinit var walk: Pose
lateinit var shoulderLeft: Pose
lateinit var shoulderRight: Pose
val shoulderOffset = 5
val shoulderZOffset = 4.8
override fun registerPoses() {
val blink = quirk { bedrockStateful("pachirisu", "blink") }
standing = registerPose(
poseName = "standing",
poseTypes = STATIONARY_POSES + UI_POSES,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("pachirisu", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = MOVING_POSES,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
BipedWalkAnimation(this, periodMultiplier = 0.8F, amplitudeMultiplier = 0.7F),
bedrock("pachirisu", "ground_idle")
)
)
shoulderLeft = registerPose(
poseType = PoseType.SHOULDER_LEFT,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("pachirisu", "ground_idle")
),
transformedParts = arrayOf(
rootPart.createTransformation().addPosition(ModelPartTransformation.X_AXIS, shoulderOffset),
rootPart.createTransformation().addPosition(ModelPartTransformation.Z_AXIS, shoulderZOffset)
)
)
shoulderRight = registerPose(
poseType = PoseType.SHOULDER_RIGHT,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("pachirisu", "ground_idle")
),
transformedParts = arrayOf(
rootPart.createTransformation().addPosition(ModelPartTransformation.X_AXIS, -shoulderOffset),
rootPart.createTransformation().addPosition(ModelPartTransformation.Z_AXIS, shoulderZOffset)
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PosableState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("pachirisu", "faint") else null
}
@@ -1,93 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen8
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.QuadrupedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.util.isBattling
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class NickitModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, QuadrupedFrame {
override val rootPart = root.registerChildWithAllChildren("nickit")
override val head = getPart("head")
override val foreLeftLeg = getPart("leg_front_left")
override val foreRightLeg = getPart("leg_front_right")
override val hindLeftLeg = getPart("leg_back_left")
override val hindRightLeg = getPart("leg_back_right")
override var portraitScale = 1.8F
override var portraitTranslation = Vec3(-0.3, -0.1, 0.0)
override var profileScale = 0.75F
override var profileTranslation = Vec3(0.0, 0.65, 0.0)
lateinit var standing: Pose
lateinit var walk: Pose
lateinit var sleep: Pose
lateinit var battleidle: Pose
override val cryAnimation = CryProvider { bedrockStateful("nickit", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("nickit", "blink")}
val glanceleft = quirk { bedrockStateful("nickit", "quirk_shiftyglance_left")}
val glanceright = quirk { bedrockStateful("nickit", "quirk_shiftyglance_right")}
val eartwitchleft = quirk { bedrockStateful("nickit", "quirk_eartwitch_left")}
val eartwitchright = quirk { bedrockStateful("nickit", "quirk_eartwitch_right")}
sleep = registerPose(
poseType = PoseType.SLEEP,
animations = arrayOf(bedrock("nickit", "sleep"))
)
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
transformTicks = 10,
quirks = arrayOf(blink, glanceleft, glanceright, eartwitchleft, eartwitchright),
condition = { !it.isBattling },
animations = arrayOf(
singleBoneLook(),
bedrock("nickit", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES,
transformTicks = 10,
quirks = arrayOf(blink, eartwitchleft, eartwitchright),
animations = arrayOf(
singleBoneLook(),
bedrock("nickit", "ground_walk")
)
)
battleidle = registerPose(
poseName = "battle_idle",
poseTypes = PoseType.STATIONARY_POSES,
transformTicks = 10,
quirks = arrayOf(blink, glanceleft, glanceright, eartwitchleft, eartwitchright),
condition = { it.isBattling },
animations = arrayOf(
singleBoneLook(),
bedrock("nickit", "battle_idle")
)
)
}
override fun getFaintAnimation(state: PosableState) = if (state.isPosedIn(standing, walk, sleep, battleidle)) bedrockStateful("nickit", "faint") else null
}
@@ -1,93 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen8
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.QuadrupedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.util.isBattling
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class ThievulModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, QuadrupedFrame {
override val rootPart = root.registerChildWithAllChildren("thievul")
override val head = getPart("head")
override val foreLeftLeg = getPart("leg_front_left")
override val foreRightLeg = getPart("leg_front_right")
override val hindLeftLeg = getPart("leg_back_left")
override val hindRightLeg = getPart("leg_back_right")
override var portraitScale = 2.0F
override var portraitTranslation = Vec3(-0.7, 1.11, 0.0)
override var profileScale = 0.65F
override var profileTranslation = Vec3(0.0, 0.7, 0.0)
lateinit var standing: Pose
lateinit var walk: Pose
lateinit var sleep: Pose
lateinit var battleidle: Pose
override val cryAnimation = CryProvider { bedrockStateful("thievul", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("thievul", "blink")}
val sleepquirk = quirk { bedrockStateful("thievul", "quirk_sleep")}
sleep = registerPose(
poseType = PoseType.SLEEP,
quirks = arrayOf(sleepquirk),
animations = arrayOf(bedrock("thievul", "sleep"))
)
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
condition = { !it.isBattling },
animations = arrayOf(
singleBoneLook(),
bedrock("thievul", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("thievul", "ground_walk")
)
)
battleidle = registerPose(
poseName = "battle_idle",
poseTypes = PoseType.STATIONARY_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
condition = { it.isBattling },
animations = arrayOf(
singleBoneLook(),
bedrock("thievul", "battle_idle")
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PosableState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk, sleep, battleidle)) bedrockStateful("thievul", "faint") else null
}
@@ -1,89 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen9
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.util.isBattling
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class AnnihilapeModel (root: ModelPart) : PokemonPosableModel(root), BipedFrame, BimanualFrame {
override val rootPart = root.registerChildWithAllChildren("annihilape")
override val leftArm = getPart("arm_left")
override val rightArm = getPart("arm_right")
override val leftLeg = getPart("leg_left")
override val rightLeg = getPart("leg_right")
override var portraitScale = 1.4F
override var portraitTranslation = Vec3(0.0, 0.1, 0.0)
override var profileScale = 0.85F
override var profileTranslation = Vec3(0.0, 0.45, 0.0)
lateinit var standing: Pose
lateinit var walking: Pose
lateinit var sleep: Pose
lateinit var battleidle: Pose
override val cryAnimation = CryProvider { bedrockStateful("annihilape", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("annihilape", "blink") }
sleep = registerPose(
poseType = PoseType.SLEEP,
animations = arrayOf(
bedrock("annihilape", "sleep"),
bedrock("annihilape", "hair_overlay")
)
)
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
transformTicks = 10,
condition = { !it.isBattling },
quirks = arrayOf(blink),
animations = arrayOf(
bedrock("annihilape", "ground_idle"),
bedrock("annihilape", "hair_overlay")
)
)
walking = registerPose(
poseName = "walking",
poseTypes = PoseType.MOVING_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
animations = arrayOf(
bedrock("annihilape", "ground_walk"),
bedrock("annihilape", "hair_overlay")
)
)
battleidle = registerPose(
poseName = "battle_idle",
poseTypes = PoseType.STATIONARY_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
condition = { it.isBattling },
animations = arrayOf(
bedrock("annihilape", "battle_idle"),
bedrock("annihilape", "hair_overlay")
)
)
}
override fun getFaintAnimation(state: PosableState) = if (state.isPosedIn(standing, walking, battleidle, sleep)) bedrockStateful("annihilape", "faint") else null
}
@@ -1,60 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen9
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.entity.PoseType
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class RevavroomModel (root: ModelPart) : PokemonPosableModel(root) {
override val rootPart = root.registerChildWithAllChildren("revavroom")
override var portraitScale = 3.1F
override var portraitTranslation = Vec3(-1.4, -1.7, 1.1)
override var profileScale = 0.9F
override var profileTranslation = Vec3(-0.2, 0.3, 1.1)
lateinit var standing: Pose
lateinit var walk: Pose
lateinit var sleep: Pose
override val cryAnimation = CryProvider { bedrockStateful("revavroom", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("revavroom", "blink") }
sleep = registerPose(
poseType = PoseType.SLEEP,
animations = arrayOf(bedrock("revavroom", "sleep"))
)
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
animations = arrayOf(
bedrock("revavroom", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
animations = arrayOf(
bedrock("revavroom", "ground_walk")
)
)
}
}
@@ -1,60 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen9
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.entity.PoseType
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class VaroomModel (root: ModelPart) : PokemonPosableModel(root) {
override val rootPart = root.registerChildWithAllChildren("varoom")
override var portraitScale = 3.0F
override var portraitTranslation = Vec3(0.5, -2.5, 0.0)
override var profileScale = 1.1F
override var profileTranslation = Vec3(0.0, 0.0, 0.0)
lateinit var standing: Pose
lateinit var walk: Pose
lateinit var sleep: Pose
override val cryAnimation = CryProvider { bedrockStateful("varoom", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("varoom", "blink") }
sleep = registerPose(
poseType = PoseType.SLEEP,
animations = arrayOf(bedrock("varoom", "sleep"))
)
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
transformTicks = 0,
quirks = arrayOf(blink),
animations = arrayOf(
bedrock("varoom", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES,
transformTicks = 0,
quirks = arrayOf(blink),
animations = arrayOf(
bedrock("varoom", "ground_walk")
)
)
}
}
@@ -278,7 +278,6 @@ object VaryingModelRepository {
inbuilt("lickitung", ::LickitungModel)
inbuilt("marowak", ::MarowakModel)
inbuilt("meowth", ::MeowthModel)
inbuilt("mew", ::MewModel)
inbuilt("nidoqueen", ::NidoqueenModel)
inbuilt("nidoranf", ::NidoranfModel)
inbuilt("nidoranm", ::NidoranmModel)
@@ -306,7 +305,6 @@ object VaryingModelRepository {
inbuilt("smoochum", ::SmoochumModel)
inbuilt("hitmontop", ::HitmontopModel)
inbuilt("electivire", ::ElectivireModel)
inbuilt("lickilicky", ::LickilickyModel)
inbuilt("tangrowth", ::TangrowthModel)
inbuilt("blissey", ::BlisseyModel)
inbuilt("piloswine", ::PiloswineModel)
@@ -321,7 +319,6 @@ object VaryingModelRepository {
inbuilt("buneary", ::BunearyModel)
inbuilt("lopunny", ::LopunnyModel)
inbuilt("mamoswine", ::MamoswineModel)
inbuilt("pachirisu", ::PachirisuModel)
inbuilt("piplup", ::PiplupModel)
inbuilt("yanmega", ::YanmegaModel)
inbuilt("basculin", ::BasculinModel)
@@ -390,9 +387,6 @@ object VaryingModelRepository {
inbuilt("chimchar", :: ChimcharModel)
inbuilt("monferno", :: MonfernoModel)
inbuilt("infernape", :: InfernapeModel)
inbuilt("seedot", ::SeedotModel)
inbuilt("nuzleaf", ::NuzleafModel)
inbuilt("shiftry", ::ShiftryModel)
inbuilt("kricketot", ::KricketotModel)
inbuilt("kricketune", ::KricketuneModel)
inbuilt("durant", ::DurantModel)
@@ -427,8 +421,6 @@ object VaryingModelRepository {
inbuilt("tandemaus", ::TandemausModel)
inbuilt("maushold", ::MausholdModel)
inbuilt("mausholdfour", ::MausholdfourModel)
inbuilt("varoom", ::VaroomModel)
inbuilt("revavroom", ::RevavroomModel)
inbuilt("lanturn", ::LanturnModel)
inbuilt("chingling", ::ChinglingModel)
inbuilt("chimecho", ::ChimechoModel)
@@ -464,8 +456,6 @@ object VaryingModelRepository {
inbuilt("sirfetchd", ::SirfetchdModel)
inbuilt("duskull", ::DuskullModel)
inbuilt("dusclops", ::DusclopsModel)
inbuilt("nickit", ::NickitModel)
inbuilt("thievul", ::ThievulModel)
inbuilt("glimmet", ::GlimmetModel)
inbuilt("glimmora", ::GlimmoraModel)
inbuilt("bonsly", ::BonslyModel)
@@ -500,7 +490,6 @@ object VaryingModelRepository {
inbuilt("shroodle", ::ShroodleModel)
inbuilt("grafaiai", ::GrafaiaiModel)
inbuilt("squawkabilly", ::SquawkabillyModel)
inbuilt("annihilape", ::AnnihilapeModel)
inbuilt("ponyta_galarian", ::PonytaGalarianModel)
inbuilt("rapidash_galarian", ::RapidashGalarianModel)
inbuilt("volbeat", ::VolbeatModel)
@@ -55,7 +55,8 @@ class CobblemonConfig {
@CobblemonConfigField(Category.Storage, lang = "default_box_count")
@IntConstraint(min = 1, max = 1000)
var defaultBoxCount = 30
@LastChangedVersion("1.7.0")
var defaultBoxCount = 40
@CobblemonConfigField(Category.Storage, lang = "pokemon_save_interval_seconds")
@IntConstraint(min = 1, max = 120)
var pokemonSaveIntervalSeconds = 30
@@ -38,6 +38,7 @@ class EntityCallbacks(val entity: Entity) : HashMap<ResourceLocation, MutableLis
companion object {
val HIT_BY_POKEBALL = cobblemonResource("hit_by_pokeball")
val SAW_ENTITY = cobblemonResource("saw_entity")
val LOST_ENTITY = cobblemonResource("lost_sight_of_entity")
val HURT = cobblemonResource("hurt")
val DIED = cobblemonResource("died")
}
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.ai.PokemonMoveControl
import com.google.common.collect.ImmutableMap
import java.util.UUID
import kotlin.math.pow
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.entity.ai.behavior.Behavior
import net.minecraft.world.entity.ai.memory.MemoryModuleType
@@ -30,6 +31,8 @@ class FollowHerdLeaderTask : Behavior<PokemonEntity>(
var leader: PokemonEntity? = null
var tooFar = 8F
var closeEnough = 4F
/** Chance per tick of following the herd leader. */
val chance = 1 / 20F
override fun checkExtraStartConditions(level: ServerLevel, owner: PokemonEntity): Boolean {
leader = level.getEntity(owner.brain.getMemory(CobblemonMemories.HERD_LEADER).map(UUID::fromString).orElse(null) ?: return false) as? PokemonEntity
@@ -74,7 +77,7 @@ class FollowHerdLeaderTask : Behavior<PokemonEntity>(
CobblemonWalkTarget(
pos = leader.blockPosition(),
speedModifier = 0.4F,
completionRange = 0
completionRange = 1
)
)
} else {
@@ -87,8 +90,17 @@ class FollowHerdLeaderTask : Behavior<PokemonEntity>(
)
}
} else if (leader.brain.hasMemoryValue(MemoryModuleType.WALK_TARGET)) {
if (entity.random.nextFloat() > chance) {
return // Not this tick
}
// Go to the leader's walk target, roughly.
val walkTarget = leader.brain.getMemory(MemoryModuleType.WALK_TARGET).orElse(null) ?: return
if (entity.distanceToSqr(walkTarget.target.currentPosition()) < leader.distanceToSqr(walkTarget.target.currentPosition())) {
return // We're already closer to the walk target than the leader is, so no need to move, if anything we should get out of the way
}
entity.brain.setMemory(
MemoryModuleType.WALK_TARGET,
CobblemonWalkTarget(
@@ -644,6 +644,20 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
return InteractionResult.SUCCESS
}
override fun hurt(source: DamageSource, amount: Float): Boolean {
if (super.hurt(source, amount)) {
callbacks.process(
type = EntityCallbacks.HURT,
functions = mapOf(
"source" to { source.asMoLangValue() },
"amount" to { DoubleValue(amount.toDouble()) },
)
)
return true
}
return false
}
override fun recalling(pokemonEntity: PokemonEntity): CompletableFuture<Unit> {
playAnimation(RECALL_ANIMATION, pokemonExpressions(pokemonEntity.pokemon))
return delayedFuture(seconds = 1.6F)
@@ -9,7 +9,9 @@
package com.cobblemon.mod.common.entity.npc.ai
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.util.getMemorySafely
import com.cobblemon.mod.common.util.mainThreadRuntime
import com.cobblemon.mod.common.util.resolveFloat
import com.cobblemon.mod.common.util.resolveInt
@@ -24,9 +26,11 @@ object MeleeAttackTask {
fun create(range: Expression, cooldownTicks: Expression): OneShot<LivingEntity> = BehaviorBuilder.create {
it.group(
it.present(MemoryModuleType.ATTACK_TARGET),
it.absent(MemoryModuleType.ATTACK_COOLING_DOWN)
it.absent(MemoryModuleType.ATTACK_COOLING_DOWN),
).apply(it) { attackTarget, cooldown ->
Trigger { world, entity, _ ->
val attackTargetData = entity.brain.getMemorySafely(CobblemonMemories.ATTACK_TARGET_DATA).orElse(null)
mainThreadRuntime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
val range = mainThreadRuntime.resolveFloat(range)
val cooldownTicks = mainThreadRuntime.resolveInt(cooldownTicks)
@@ -35,6 +39,14 @@ object MeleeAttackTask {
if (entity.distanceTo(attackTarget) <= range) {
entity.doHurtTarget(attackTarget)
cooldown.setWithExpiry(true, cooldownTicks.toLong())
if (attackTargetData != null) {
if (attackTargetData.dealtHitsUntilDisengage == 1) {
attackTargetData.dealtHitsUntilDisengage = 0
attackTargetData.disengageAction(entity)
} else if (attackTargetData.dealtHitsUntilDisengage > 0){
attackTargetData.dealtHitsUntilDisengage--
}
}
true
} else {
false
@@ -13,7 +13,9 @@ import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonEntities.EMPTY_POKEBALL
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.pokeball.PokeBallCaptureCalculatedEvent
import com.cobblemon.mod.common.api.events.pokeball.ThrownPokeballHitEvent
@@ -28,8 +30,10 @@ import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.api.scheduling.Schedulable
import com.cobblemon.mod.common.api.scheduling.ScheduledTask
import com.cobblemon.mod.common.api.scheduling.SchedulingTracker
import com.cobblemon.mod.common.api.text.green
import com.cobblemon.mod.common.api.text.red
import com.cobblemon.mod.common.api.text.yellow
import com.cobblemon.mod.common.battles.BattleBuilder
import com.cobblemon.mod.common.battles.BattleCaptureAction
import com.cobblemon.mod.common.battles.BattleRegistry
import com.cobblemon.mod.common.battles.BattleTypes
@@ -72,7 +76,6 @@ import net.minecraft.world.item.Item
import net.minecraft.world.level.Level
import net.minecraft.world.phys.BlockHitResult
import net.minecraft.world.phys.EntityHitResult
import net.minecraft.world.phys.HitResult
import net.minecraft.world.phys.Vec3
import java.util.concurrent.CompletableFuture
@@ -104,7 +107,8 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
override val schedulingTracker = SchedulingTracker()
var capturingPokemon: PokemonEntity? = null
val captureFuture = CompletableFuture<Boolean>()
var captureFuture = CompletableFuture<Boolean>()
var capturePostAction: (Boolean) -> Unit = {}
var captureState: CaptureState
get() = CaptureState.entries[entityData.get(CAPTURE_STATE).toInt()]
set(value) { entityData.set(CAPTURE_STATE, value.ordinal.toByte()) }
@@ -179,20 +183,28 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
var pokeBall: PokeBall = PokeBalls.POKE_BALL
override fun onHitBlock(hitResult: BlockHitResult) {
if (captureState == CaptureState.NOT) {
if (level().isServerSide()) {
super.onHitBlock(hitResult)
level().sendParticlesServer(ParticleTypes.CLOUD, hitResult.location, 2, hitResult.location.subtract(position()).normalize().scale(-0.1), 0.0)
level().playSoundServer(position(), SoundEvents.WOOD_PLACE, pitch = 2.5F)
discard()
val player = this.owner as? ServerPlayer
if (player?.isCreative == false) {
spawnAtLocation(defaultItem)
when (captureState) {
CaptureState.FALL -> {
if (level().isServerSide()) {
beginCapture()
}
}
} else {
setNoGravity(false)
deltaMovement = Vec3.ZERO
CaptureState.NOT -> {
if (level().isServerSide()) {
super.onHitBlock(hitResult)
level().sendParticlesServer(ParticleTypes.CLOUD, hitResult.location, 2, hitResult.location.subtract(position()).normalize().scale(-0.1), 0.0)
level().playSoundServer(position(), SoundEvents.WOOD_PLACE, pitch = 2.5F)
discard()
val player = this.owner as? ServerPlayer
if (player?.isCreative == false) {
spawnAtLocation(defaultItem)
}
}
}
else -> {
isNoGravity = false
deltaMovement = Vec3.ZERO
}
}
}
@@ -255,7 +267,13 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
owner?.sendSystemMessage(lang("capture.busy", pokemonEntity.exposedSpecies.translatedName).red())
return drop()
} else if (owner is ServerPlayer && BattleRegistry.getBattleByParticipatingPlayer(owner) != null) {
owner.sendSystemMessage(lang("you_in_battle").red())
owner.sendSystemMessage(lang("capture.you_in_battle").red())
return drop()
} else if (owner is ServerPlayer && BattleRegistry.checkBattleLock(owner, pokeBall.ancient)) {
owner.sendSystemMessage(lang("capture.you_already_capturing").red())
return drop()
} else if (pokemonEntity.brain.hasMemoryValue(CobblemonMemories.RECENT_CATCH_ATTEMPT)) {
owner?.sendSystemMessage(lang("capture.enraged", pokemonEntity.exposedSpecies.translatedName).red())
return drop()
}
@@ -279,6 +297,29 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
super.onHitEntity(hitResult)
}
private fun inBattleCatchAction(battle: PokemonBattle, thrower: LivingEntity, pokemonEntity: PokemonEntity) {
val throwerActor = battle.getActor(thrower.uuid)
val hitActor = battle.actors.find { it.isForPokemon(pokemonEntity) }
val hitBattlePokemon = hitActor?.activePokemon?.find { it.battlePokemon?.effectedPokemon?.entity == pokemonEntity }
if (throwerActor == null || hitActor == null || hitBattlePokemon == null) {
return // Weird, shouldn't be possible
}
val pokemonName = hitBattlePokemon.battlePokemon?.getName() ?: "error".red()
battle.broadcastChatMessage(
lang(
"capture.attempted_capture",
throwerActor.getName(),
pokeBall.item().description,
pokemonName
).yellow()
)
battle.dispatchWaiting(2F) { battle.broadcastChatMessage(lang("capture.broke_free", pokemonName).red()) }
battle.dispatchGo { throwerActor.forceChoose(ForcePassActionResponse()) }
}
private fun drop() {
val owner = owner
discard()
@@ -352,6 +393,11 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
if (pokemon.pokemon.isWild() && pokemon.isAlive && !captureFuture.isDone) {
pokemon.discard()
discard()
capturePostAction(true)
val owner = owner
if (owner != null && owner is ServerPlayer) {
BattleRegistry.unlockPlayer(owner)
}
captureFuture.complete(true)
val party = player.party()
pokemon.pokemon.caughtBall = pokeBall
@@ -419,6 +465,11 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
after(seconds = 0.1F) {
pokemon.beamMode = 0
pokemon.busyLocks.remove(this)
capturePostAction(false)
val owner = owner
if (owner != null && owner is ServerPlayer) {
BattleRegistry.unlockPlayer(owner)
}
captureFuture.complete(false)
val ballType =
this.pokeBall.name.path.lowercase().replace("_", "")
@@ -442,6 +493,10 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
private fun attemptCatch(pokemonEntity: PokemonEntity) {
pokemonEntity.busyLocks.add(this)
val owner = owner
if (owner != null && owner is ServerPlayer) {
BattleRegistry.lockPlayer(owner, pokeBall.ancient)
}
val displace = deltaMovement
captureState = CaptureState.HIT
val mul = if (random.nextBoolean()) 1 else -1
@@ -456,7 +511,7 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
after(seconds = 0.7F) {
// Start beaming them up.
deltaMovement = Vec3.ZERO
setNoGravity(true)
isNoGravity = true
level().playSoundServer(position(), CobblemonSounds.POKE_BALL_RECALL, volume = 0.6F)
pokemonEntity.beamMode = 3
}
@@ -471,7 +526,7 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
// If it was still falling after a second and a half, just assume it's landed because we can't wait all day.
if (captureState == CaptureState.FALL) {
deltaMovement = Vec3.ZERO
setNoGravity(true)
isNoGravity = true
setOnGround(true)
beginCapture()
}
@@ -479,25 +534,40 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
}
}
override fun onHit(hitResult: HitResult) {
super.onHit(hitResult)
if (captureState == CaptureState.FALL && hitResult.type == HitResult.Type.BLOCK) {
if (level().isServerSide()) {
beginCapture()
}
}
}
// We have hit the ground, time to stop falling and start shaking! Calculate capture.
fun beginCapture() {
// We have hit the ground, time to stop falling and start shaking! Calculate capture.
capturingPokemon?.setPositionSafely(position())
val capturingPokemon = this.capturingPokemon ?: return
capturingPokemon.setPositionSafely(position())
val thrower = owner as LivingEntity
val captureResult = Cobblemon.config.captureCalculator.processCapture(thrower, this, capturingPokemon!!).let {
val event = PokeBallCaptureCalculatedEvent(thrower = thrower, pokemonEntity = capturingPokemon!!, pokeBallEntity = this, captureResult = it)
val captureResult = Cobblemon.config.captureCalculator.processCapture(thrower, this, capturingPokemon).let {
val event = PokeBallCaptureCalculatedEvent(thrower = thrower, pokemonEntity = capturingPokemon, pokeBallEntity = this, captureResult = it)
CobblemonEvents.POKE_BALL_CAPTURE_CALCULATED.post(event)
event.captureResult
}
if (thrower is ServerPlayer) {
val battle = (capturingPokemon.delegate as PokemonServerDelegate).getBattle()
if (battle == null && !pokeBall.ancient) {
capturingPokemon.brain.setMemoryWithExpiry(CobblemonMemories.RECENT_CATCH_ATTEMPT, thrower.uuid, 30 * 20)
this.capturePostAction = {
if (!it) {
if (this.pokeBall.stealthFactor > 0.0f && this.random.nextFloat() < this.pokeBall.stealthFactor) {
thrower.sendSystemMessage(lang("capture.didnt_notice", capturingPokemon.exposedSpecies.translatedName).green())
} else {
thrower.sendSystemMessage(lang("capture.got_enraged", capturingPokemon.exposedSpecies.translatedName).red())
val lead = thrower.party().firstOrNull {it.entity != null}?.uuid
if (lead != null) {
BattleBuilder.pve(thrower, capturingPokemon, lead).ifSuccessful { battle ->
inBattleCatchAction(battle, thrower, capturingPokemon)
}
}
}
}
}
}
}
var rollsRemaining = captureResult.numberOfShakes
if (rollsRemaining == 4) {
rollsRemaining--
@@ -530,11 +600,12 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
}
.build()
}
override fun getCurrentPoseType(): PoseType {
return PoseType.NONE
}
override fun canUsePortal(allowVehicles: Boolean) = false
override fun canUsePortal(allowVehicles: Boolean) = captureState == CaptureState.NOT
override fun getAddEntityPacket(entityTrackerEntry: ServerEntity): Packet<ClientGamePacketListener> =
ClientboundCustomPayloadPacket(
@@ -26,8 +26,8 @@ import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.entity.PokemonEntityLoadEvent
import com.cobblemon.mod.common.api.events.entity.PokemonEntitySaveEvent
import com.cobblemon.mod.common.api.events.entity.PokemonEntitySaveToWorldEvent
import com.cobblemon.mod.common.api.events.pokemon.ShoulderMountEvent
import com.cobblemon.mod.common.api.events.pokemon.RidePokemonEvent
import com.cobblemon.mod.common.api.events.pokemon.ShoulderMountEvent
import com.cobblemon.mod.common.api.interaction.PokemonEntityInteraction
import com.cobblemon.mod.common.api.interaction.PokemonInteractions
import com.cobblemon.mod.common.api.mark.Marks
@@ -36,6 +36,7 @@ import com.cobblemon.mod.common.api.molang.MoLangFunctions.addLivingEntityFuncti
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addPokemonEntityFunctions
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addPokemonFunctions
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.molang.ObjectValue
import com.cobblemon.mod.common.api.net.serializers.PlatformTypeDataSerializer
@@ -56,7 +57,6 @@ import com.cobblemon.mod.common.api.riding.Seat
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviour
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourState
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviours
import com.cobblemon.mod.common.api.riding.behaviour.RidingController
import com.cobblemon.mod.common.api.riding.events.SelectDriverEvent
import com.cobblemon.mod.common.api.riding.sound.RideSoundManager
@@ -147,7 +147,6 @@ import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerEntity
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
import net.minecraft.sounds.SoundEvent
import net.minecraft.sounds.SoundEvents
import net.minecraft.sounds.SoundSource
import net.minecraft.tags.FluidTags
@@ -499,9 +498,10 @@ open class PokemonEntity(
}
override fun canStandOnFluid(state: FluidState): Boolean {
// val node = navigation.currentPath?.currentNode
// val targetPos = node?.blockPos
// if (targetPos == null || world.getBlockState(targetPos.up()).isAir) {
// If the pokemon is currently ridden then return false to prevent mounts that can transition
// from the air to the water from getting stuck on the water surface.
if (this.passengers.filterIsInstance<LivingEntity>().isNotEmpty() && this.controllingPassenger != null) return false
return if (state.`is`(FluidTags.WATER) && !isEyeInFluid(FluidTags.WATER)) {
exposedForm.behaviour.moving.swim.canWalkOnWater || platform != PlatformType.NONE
} else if (state.`is`(FluidTags.LAVA) && !isEyeInFluid(FluidTags.LAVA)) {
@@ -509,9 +509,6 @@ open class PokemonEntity(
} else {
super.canStandOnFluid(state)
}
// }
//
// return super.canWalkOnFluid(state)
}
override fun canSprint() = true
@@ -1224,6 +1221,14 @@ open class PokemonEntity(
// Only touch battle HP for non-wild Pokémon so that quick ball et. al. aren't owerpowered.
pokemon.currentHealth = (pokemon.maxHealth * (this.health / this.maxHealth)).toInt()
}
callbacks.process(
type = EntityCallbacks.HURT,
functions = mapOf(
"source" to { source.asMoLangValue() },
"amount" to { DoubleValue(amount.toDouble()) },
)
)
true
} else false
}
@@ -1717,15 +1722,13 @@ open class PokemonEntity(
val velocity = ifRidingAvailableSupply(fallback = Vec3.ZERO) { behaviour, settings, state ->
behaviour.velocity(settings, state, this, this.controllingPassenger as Player, deltaMovement)
}
//Handle ridden pokemon differently to allow vector lerp instead of simple addition.
// Handle ridden pokemon differently to allow vector lerp instead of simple addition.
val v = getInputVector(velocity, 1.0f, this.yRot)
//changing this will give the ride more or less inertia/handling/drift
// Changing this will give the ride more or less inertia/handling/drift
val inertia = ifRidingAvailableSupply(fallback = 0.5) { behaviour, settings, state ->
behaviour.inertia(settings, state,this)
}
// TODO: jackowes look over this so I don't accidentally break anything
// TODO: Talk to landon about why this was needed
this.deltaMovement = this.deltaMovement.lerp(v, inertia)
var pos = this.deltaMovement.scale(this.speed.toDouble())
if (super.onGround() && this.deltaMovement.y == 0.0) {
@@ -1797,6 +1800,12 @@ open class PokemonEntity(
val delta = triedMovement.subtract(this.deltaMovement)
if (behaviour.damageOnCollision(settings, state, this, delta)) {
DamageOnCollisionPacket(delta).sendToServer()
for (passenger in this.passengers) {
passenger.deltaMovement = this.deltaMovement
}
this.ejectPassengers()
// Reset ride velocity
state.rideVelocity.set(state.rideVelocity.get().multiply(0.0, 1.0, 0.0))
}
@@ -2423,6 +2432,17 @@ open class PokemonEntity(
}
}
internal fun adjustHerdSize(difference: Int): Int {
val currentSize = brain.getMemorySafely(CobblemonMemories.HERD_SIZE).orElse(0)
val newSize = (currentSize + difference).coerceAtLeast(0)
if (newSize == 0) {
brain.eraseMemory(CobblemonMemories.HERD_SIZE)
} else {
brain.setMemory(CobblemonMemories.HERD_SIZE, newSize)
}
return newSize
}
/**
* Figures out what the strongest tier applied to this herd is from the perspective of this entity. This can be a
* bit confusing so bear with me.
@@ -20,7 +20,9 @@ import net.minecraft.world.entity.ai.behavior.declarative.Trigger
import net.minecraft.world.entity.ai.memory.MemoryModuleType
object GoToSleepTask {
fun create(): OneShot<PokemonEntity> {
fun create(
onlyFromStatus: Boolean
): OneShot<PokemonEntity> {
return BehaviorBuilder.create {
it.group(
it.absent(MemoryModuleType.WALK_TARGET),
@@ -28,8 +30,11 @@ object GoToSleepTask {
).apply(it) { _, pokemonDrowsy ->
Trigger { _, entity, _ ->
val hasSleepStatus = entity.pokemon.status?.status === Statuses.SLEEP
if (entity.behaviour.resting.canSleep && ((it.tryGet(pokemonDrowsy).orElse(false) && entity.canSleepAt(entity.blockPosition().below())) || hasSleepStatus) && entity.pokemon.storeCoordinates.get()?.store !is PartyStore) {
if (entity.behaviour.resting.canSleep && ((it.tryGet(pokemonDrowsy).orElse(false) && entity.canSleepAt(entity.blockPosition().below())) || hasSleepStatus)) {
if (!hasSleepStatus) {
if (onlyFromStatus) {
return@Trigger false
}
entity.pokemon.status = PersistentStatusContainer(Statuses.SLEEP)
}
entity.brain.eraseMemory(MemoryModuleType.WALK_TARGET)
@@ -15,7 +15,6 @@ import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import net.minecraft.world.entity.ai.behavior.OneShot
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
import net.minecraft.world.entity.ai.memory.MemoryModuleType
object WakeUpTask {
fun create(): OneShot<PokemonEntity> {
@@ -23,15 +22,17 @@ object WakeUpTask {
it.group(
it.absent(CobblemonMemories.POKEMON_DROWSY)
).apply(it) { _ ->
Trigger { world, entity, _ ->
if (entity.pokemon.status?.status == Statuses.SLEEP && entity.pokemon.storeCoordinates.get()?.store !is PartyStore) {
entity.pokemon.status = null
entity.brain.eraseMemory(CobblemonMemories.POKEMON_SLEEPING)
entity.brain.useDefaultActivity()
return@Trigger true
} else {
return@Trigger false
Trigger { _, entity, _ ->
val hasSleepStatus = entity.pokemon.status?.status == Statuses.SLEEP
if (hasSleepStatus && entity.pokemon.storeCoordinates.get()?.store is PartyStore) {
return@Trigger false // You can't wake up if you're in the party with the sleep status.
}
if (hasSleepStatus) {
entity.pokemon.status = null
}
entity.brain.eraseMemory(CobblemonMemories.POKEMON_SLEEPING)
entity.brain.useDefaultActivity()
return@Trigger true
}
}
}
@@ -81,7 +81,7 @@ class AprijuiceItem(val type: Apricorn): CobblemonItem(Properties().stacksTo(16)
override fun canUseOnPokemon(stack: ItemStack, pokemon: Pokemon): Boolean {
val boosts = getBoosts(stack, pokemon)
return boosts.isNotEmpty() && boosts.any { pokemon.canAddRideBoost(it.key, it.value) } && super.canUseOnPokemon(stack, pokemon)
return boosts.isNotEmpty() && boosts.any { pokemon.canAddRideBoost(it.key) } && super.canUseOnPokemon(stack, pokemon)
}
fun getBoosts(stack: ItemStack, pokemon: Pokemon): Map<RidingStat, Float> {
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.item
import com.cobblemon.mod.common.CobblemonBlocks
import com.cobblemon.mod.common.block.campfirepot.CampfirePotColor
import com.cobblemon.mod.common.CobblemonSounds
import net.minecraft.core.Direction
import net.minecraft.sounds.SoundSource
@@ -22,7 +23,7 @@ import net.minecraft.world.level.block.CampfireBlock
import net.minecraft.world.level.block.HorizontalDirectionalBlock
import net.minecraft.world.level.block.entity.CampfireBlockEntity
class CampfirePotItem(block: Block): BlockItem(block, Properties()) {
class CampfirePotItem(block: Block, val color: CampfirePotColor): BlockItem(block, Properties()) {
override fun useOn(context: UseOnContext): InteractionResult {
val world = context.level
@@ -9,7 +9,11 @@
package com.cobblemon.mod.common.item.group
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonItemComponents
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.cooking.Flavour
import com.cobblemon.mod.common.item.AprijuiceItem
import com.cobblemon.mod.common.item.components.FlavourComponent
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.world.level.ItemLike
@@ -527,14 +531,27 @@ object CobblemonItemGroups {
entries.accept(CobblemonItems.POKE_CAKE)
entries.accept(CobblemonItems.POKE_PUFF)
//entries.accept(CobblemonItems.APRIJUICE_RED) // TODO uncomment for 1.7.X
//entries.accept(CobblemonItems.APRIJUICE_YELLOW)
//entries.accept(CobblemonItems.APRIJUICE_GREEN)
//entries.accept(CobblemonItems.APRIJUICE_BLUE)
//entries.accept(CobblemonItems.APRIJUICE_PINK)
//entries.accept(CobblemonItems.APRIJUICE_BLACK)
//entries.accept(CobblemonItems.APRIJUICE_WHITE)
entries.accept(defaultAprijuice(CobblemonItems.APRIJUICE_RED))
entries.accept(defaultAprijuice(CobblemonItems.APRIJUICE_YELLOW))
entries.accept(defaultAprijuice(CobblemonItems.APRIJUICE_GREEN))
entries.accept(defaultAprijuice(CobblemonItems.APRIJUICE_BLUE))
entries.accept(defaultAprijuice(CobblemonItems.APRIJUICE_PINK))
entries.accept(defaultAprijuice(CobblemonItems.APRIJUICE_BLACK))
entries.accept(defaultAprijuice(CobblemonItems.APRIJUICE_WHITE))
}
private fun defaultAprijuice(item: AprijuiceItem): ItemStack {
return ItemStack(item).apply {
this.set(CobblemonItemComponents.FLAVOUR, FlavourComponent(
mapOf(
Flavour.SPICY to 10,
Flavour.DRY to 10,
Flavour.SWEET to 10,
Flavour.BITTER to 10,
Flavour.SOUR to 10,
)
))
}
}
private fun evolutionItemEntries(displayContext: ItemDisplayParameters, entries: Output) {
@@ -787,6 +804,8 @@ object CobblemonItemGroups {
injector.putAfter(CobblemonItems.POKE_CAKE, Items.CAKE)
injector.putAfter(CobblemonItems.SINISTER_TEA, Items.MILK_BUCKET)
}
private fun toolsAndUtilitiesInjections(injector: Injector) {
@@ -0,0 +1,44 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.net.messages.server.debug
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.api.riding.RidingStyle
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.readString
import com.cobblemon.mod.common.util.writeString
import net.minecraft.network.RegistryFriendlyByteBuf
class ServerboundUpdateRidingSettingsPacket(
val entity: Int,
val ridingStyle: RidingStyle,
val variable: String,
val expression: String
) : NetworkPacket<ServerboundUpdateRidingSettingsPacket> {
override val id = ID
override fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeInt(entity)
buffer.writeEnum(ridingStyle)
buffer.writeString(variable)
buffer.writeString(expression)
}
companion object {
val ID = cobblemonResource("c2s_update_ride_settings")
fun decode(buffer: RegistryFriendlyByteBuf): ServerboundUpdateRidingSettingsPacket {
return ServerboundUpdateRidingSettingsPacket(
entity = buffer.readInt(),
ridingStyle = buffer.readEnum(RidingStyle::class.java),
variable = buffer.readString(),
expression = buffer.readString()
)
}
}
}
@@ -0,0 +1,41 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.net.serverhandling.debug
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
import com.cobblemon.mod.common.api.riding.RidingStyle
import com.cobblemon.mod.common.api.riding.stats.RidingStat
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.net.messages.server.debug.ServerboundUpdateRidingSettingsPacket
import com.cobblemon.mod.common.net.messages.server.debug.ServerboundUpdateRidingStatsPacket
import com.cobblemon.mod.common.util.asExpression
import net.minecraft.server.MinecraftServer
import net.minecraft.server.level.ServerPlayer
object ServerboundUpdateRidingSettingsHandler : ServerNetworkPacketHandler<ServerboundUpdateRidingSettingsPacket> {
override fun handle(packet: ServerboundUpdateRidingSettingsPacket, server: MinecraftServer, player: ServerPlayer) {
if (!Cobblemon.config.enableDebugKeys) return
val entity = player.level().getEntity(packet.entity) ?: return
if (entity !is PokemonEntity) return
if (entity.controllingPassenger != player) return
this.modifyRideSettingsExpression(entity, packet.ridingStyle, packet.variable, packet.expression)
}
internal fun modifyRideSettingsExpression(vehicle: PokemonEntity, ridingStyle: RidingStyle, variable: String, expression: String) {
val rideSettings = vehicle.ridingController?.behaviours?.get(ridingStyle) ?: return
val clazz = rideSettings.javaClass
val field = clazz.declaredFields.firstOrNull { it.name == variable } ?: return
field.isAccessible = true
field.set(rideSettings, expression.asExpression())
}
}
@@ -40,13 +40,15 @@ open class PokeBall(
val model2d: ResourceLocation,
val model3d: ResourceLocation,
val throwPower: Float,
val ancient: Boolean
val ancient: Boolean,
val stealthFactor: Float,
) {
val struct = QueryStruct(hashMapOf())
.addFunction("name") { StringValue(name.toString()) }
.addFunction("water_drag_value") { DoubleValue(waterDragValue) }
.addFunction("throw_power") { DoubleValue(throwPower) }
.addFunction("is_ancient") { DoubleValue(ancient) }
.addFunction("stealth_factor") { DoubleValue(stealthFactor) }
// .addFunction("item") { } // requires a registry which is hard
// This gets attached during item registry
@@ -1833,14 +1833,14 @@ open class Pokemon : ShowdownIdentifiable {
return rideBoosts.toMap()
}
fun canAddRideBoost(stat: RidingStat, boost: Float): Boolean {
fun canAddRideBoost(stat: RidingStat): Boolean {
val max = getMaxRideBoost(stat)
val current = rideBoosts[stat] ?: 0F
return current + boost <= max
return current < max
}
fun addRideBoost(stat: RidingStat, boost: Float): Boolean {
if (!canAddRideBoost(stat, boost)) {
if (!canAddRideBoost(stat)) {
return false
}
val max = getMaxRideBoost(stat)
@@ -67,12 +67,12 @@ class FormPokemonBehaviour {
val entityInteract: EntityBehaviour
get() = _entityInteract ?: parent.entityInteract
val dampensVibrations: Boolean
get() = _dampensVibrations ?: parent.dampensVibrations
val blockInteract: BlockBehavior
get() = _blockInteract ?: parent.blockInteract
val dampensVibrations: Boolean
get() = _dampensVibrations ?: parent.dampensVibrations
val combat: CombatBehaviour
get() = _combat ?: parent.combat
@@ -35,5 +35,6 @@ class MoveBehaviour {
it.addFunction("wander_chance") { DoubleValue(wanderChance) }
it.addFunction("wander_speed") { DoubleValue(wanderSpeed) }
it.addFunction("can_look") { DoubleValue(canLook) }
it.addFunction("can_move") { DoubleValue(walk.canWalk || swim.canSwimInLava || swim.canSwimInWater || fly.canFly) }
}
}
@@ -242,7 +242,7 @@ object PokemonBrain {
}
add(0 toDF ChooseLandWanderTargetTask.create(pokemon.form.behaviour.moving.wanderChance, horizontalRange = 10, verticalRange = 5, walkSpeed = 0.33F, completionRange = 1))
add(0 toDF GoToSleepTask.create())
add(0 toDF GoToSleepTask.create(onlyFromStatus = false))
add(0 toDF FindRestingPlaceTask.create(16, 8))
// add(0 toDF EatGrassTask())
add(0 toDF AttackAngryAtTask.create())
@@ -296,9 +296,7 @@ object PokemonBrain {
fun onCaptureFailed(pokemonEntity: PokemonEntity, capturer: Entity) {
if (pokemonEntity.pokemon.isWild() && pokemonEntity.battleId == null && capturer is LivingEntity) {
pokemonEntity.brain.eraseMemory(MemoryModuleType.ATTACK_TARGET)
pokemonEntity.getBrain().eraseMemory(MemoryModuleType.WALK_TARGET)
pokemonEntity.getBrain().setMemoryWithExpiry(MemoryModuleType.AVOID_TARGET, capturer, AVOID_MEMORY_DURATION.sample(pokemonEntity.random).toLong())
}
}
}
@@ -0,0 +1,56 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:annihilapeglare",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/generic/sparkle/bigsparkle"
}
},
"components": {
"minecraft:emitter_local_space": {
"position": true,
"rotation": false
},
"minecraft:emitter_rate_instant": {
"num_particles": 1
},
"minecraft:emitter_lifetime_once": {
"active_time": 1
},
"minecraft:emitter_shape_point": {},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 0.3
},
"minecraft:particle_initial_speed": 0,
"minecraft:particle_motion_dynamic": {},
"minecraft:particle_appearance_billboard": {
"size": [0.2, 0.2],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 16,
"texture_height": 96,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [16, 16],
"step_UV": [0, 16],
"frames_per_second": 6,
"max_frame": 6,
"stretch_to_lifetime": true
}
}
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.particle_age / v.particle_lifetime",
"gradient": {
"0.0": "#ffffffff",
"0.68": "#FFFF0000",
"1.0": "#FF1F0505"
}
}
}
}
}
}
@@ -0,0 +1,82 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:poodle_hair_black",
"basic_render_parameters": {
"material": "particles_blend",
"texture": "textures/particles/generic/cotton"
}
},
"events": {
"event_sound": {
"expression": "q.sound('minecraft:entity.sheep.shear', 1, math.random(0.9,1.1))",
"particle_effect": {
"effect": "cobblemon:poodle_hair_particles",
"type": "particle"
}
}
},
"components": {
"minecraft:emitter_rate_steady": {
"spawn_rate": 64,
"max_particles": 64
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.8
},
"minecraft:emitter_lifetime_events": {
"timeline": {
"0.10": "event_sound",
"0.30": "event_sound"
}
},
"minecraft:emitter_shape_point": {
"offset": [0, "math.random(-0.3,0.8)", 0],
"direction": ["math.random(-3,3)", "math.random(0,2)", "math.random(-3,3)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 0.7
},
"minecraft:particle_initial_spin": {
"rotation": "math.random_integer(1,4) * 90"
},
"minecraft:particle_initial_speed": 7,
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, -5, 0],
"linear_drag_coefficient": 5
},
"minecraft:particle_appearance_billboard": {
"size": [0.4, 0.4],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 48,
"texture_height": 256,
"flipbook": {
"base_UV": ["math.floor(v.particle_random_2*3)*16", 0],
"size_UV": [16, 16],
"step_UV": [0, 16],
"frames_per_second": 24,
"max_frame": 16
}
}
},
"minecraft:particle_motion_collision": {
"collision_drag": 5,
"collision_radius": 0.1
},
"minecraft:particle_appearance_lighting": {},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.emitter_age",
"gradient": {
"0.0": "#FFFFFFFF",
"0.6": "#ffffffff",
"0.72": "#FF2F2C3B",
"1.0": "#FF2F2C3B"
}
}
}
}
}
}
@@ -0,0 +1,82 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:poodle_hair_blue",
"basic_render_parameters": {
"material": "particles_blend",
"texture": "textures/particles/generic/cotton"
}
},
"events": {
"event_sound": {
"expression": "q.sound('minecraft:entity.sheep.shear', 1, math.random(0.9,1.1))",
"particle_effect": {
"effect": "cobblemon:poodle_hair_particles",
"type": "particle"
}
}
},
"components": {
"minecraft:emitter_rate_steady": {
"spawn_rate": 64,
"max_particles": 64
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.8
},
"minecraft:emitter_lifetime_events": {
"timeline": {
"0.10": "event_sound",
"0.30": "event_sound"
}
},
"minecraft:emitter_shape_point": {
"offset": [0, "math.random(-0.3,0.8)", 0],
"direction": ["math.random(-3,3)", "math.random(0,2)", "math.random(-3,3)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 0.7
},
"minecraft:particle_initial_spin": {
"rotation": "math.random_integer(1,4) * 90"
},
"minecraft:particle_initial_speed": 7,
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, -5, 0],
"linear_drag_coefficient": 5
},
"minecraft:particle_appearance_billboard": {
"size": [0.4, 0.4],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 48,
"texture_height": 256,
"flipbook": {
"base_UV": ["math.floor(v.particle_random_2*3)*16", 0],
"size_UV": [16, 16],
"step_UV": [0, 16],
"frames_per_second": 24,
"max_frame": 16
}
}
},
"minecraft:particle_motion_collision": {
"collision_drag": 5,
"collision_radius": 0.1
},
"minecraft:particle_appearance_lighting": {},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.emitter_age",
"gradient": {
"0.0": "#FFFFFFFF",
"0.6": "#ffffffff",
"0.72": "#FF5B83DE",
"1.0": "#FF5B83DE"
}
}
}
}
}
}
@@ -0,0 +1,82 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:poodle_hair_brown",
"basic_render_parameters": {
"material": "particles_blend",
"texture": "textures/particles/generic/cotton"
}
},
"events": {
"event_sound": {
"expression": "q.sound('minecraft:entity.sheep.shear', 1, math.random(0.9,1.1))",
"particle_effect": {
"effect": "cobblemon:poodle_hair_particles",
"type": "particle"
}
}
},
"components": {
"minecraft:emitter_rate_steady": {
"spawn_rate": 64,
"max_particles": 64
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.8
},
"minecraft:emitter_lifetime_events": {
"timeline": {
"0.10": "event_sound",
"0.30": "event_sound"
}
},
"minecraft:emitter_shape_point": {
"offset": [0, "math.random(-0.3,0.8)", 0],
"direction": ["math.random(-3,3)", "math.random(0,2)", "math.random(-3,3)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 0.7
},
"minecraft:particle_initial_spin": {
"rotation": "math.random_integer(1,4) * 90"
},
"minecraft:particle_initial_speed": 7,
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, -5, 0],
"linear_drag_coefficient": 5
},
"minecraft:particle_appearance_billboard": {
"size": [0.4, 0.4],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 48,
"texture_height": 256,
"flipbook": {
"base_UV": ["math.floor(v.particle_random_2*3)*16", 0],
"size_UV": [16, 16],
"step_UV": [0, 16],
"frames_per_second": 24,
"max_frame": 16
}
}
},
"minecraft:particle_motion_collision": {
"collision_drag": 5,
"collision_radius": 0.1
},
"minecraft:particle_appearance_lighting": {},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.emitter_age",
"gradient": {
"0.0": "#FFFFFFFF",
"0.6": "#ffffffff",
"0.72": "#FF8E5F45",
"1.0": "#FF8E5F45"
}
}
}
}
}
}
@@ -0,0 +1,82 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:poodle_hair_cyan",
"basic_render_parameters": {
"material": "particles_blend",
"texture": "textures/particles/generic/cotton"
}
},
"events": {
"event_sound": {
"expression": "q.sound('minecraft:entity.sheep.shear', 1, math.random(0.9,1.1))",
"particle_effect": {
"effect": "cobblemon:poodle_hair_particles",
"type": "particle"
}
}
},
"components": {
"minecraft:emitter_rate_steady": {
"spawn_rate": 64,
"max_particles": 64
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.8
},
"minecraft:emitter_lifetime_events": {
"timeline": {
"0.10": "event_sound",
"0.30": "event_sound"
}
},
"minecraft:emitter_shape_point": {
"offset": [0, "math.random(-0.3,0.8)", 0],
"direction": ["math.random(-3,3)", "math.random(0,2)", "math.random(-3,3)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 0.7
},
"minecraft:particle_initial_spin": {
"rotation": "math.random_integer(1,4) * 90"
},
"minecraft:particle_initial_speed": 7,
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, -5, 0],
"linear_drag_coefficient": 5
},
"minecraft:particle_appearance_billboard": {
"size": [0.4, 0.4],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 48,
"texture_height": 256,
"flipbook": {
"base_UV": ["math.floor(v.particle_random_2*3)*16", 0],
"size_UV": [16, 16],
"step_UV": [0, 16],
"frames_per_second": 24,
"max_frame": 16
}
}
},
"minecraft:particle_motion_collision": {
"collision_drag": 5,
"collision_radius": 0.1
},
"minecraft:particle_appearance_lighting": {},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.emitter_age",
"gradient": {
"0.0": "#FFFFFFFF",
"0.6": "#ffffffff",
"0.72": "#FF37A5B3",
"1.0": "#FF37A5B3"
}
}
}
}
}
}
@@ -0,0 +1,82 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:poodle_hair_gray",
"basic_render_parameters": {
"material": "particles_blend",
"texture": "textures/particles/generic/cotton"
}
},
"events": {
"event_sound": {
"expression": "q.sound('minecraft:entity.sheep.shear', 1, math.random(0.9,1.1))",
"particle_effect": {
"effect": "cobblemon:poodle_hair_particles",
"type": "particle"
}
}
},
"components": {
"minecraft:emitter_rate_steady": {
"spawn_rate": 64,
"max_particles": 64
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.8
},
"minecraft:emitter_lifetime_events": {
"timeline": {
"0.10": "event_sound",
"0.30": "event_sound"
}
},
"minecraft:emitter_shape_point": {
"offset": [0, "math.random(-0.3,0.8)", 0],
"direction": ["math.random(-3,3)", "math.random(0,2)", "math.random(-3,3)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 0.7
},
"minecraft:particle_initial_spin": {
"rotation": "math.random_integer(1,4) * 90"
},
"minecraft:particle_initial_speed": 7,
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, -5, 0],
"linear_drag_coefficient": 5
},
"minecraft:particle_appearance_billboard": {
"size": [0.4, 0.4],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 48,
"texture_height": 256,
"flipbook": {
"base_UV": ["math.floor(v.particle_random_2*3)*16", 0],
"size_UV": [16, 16],
"step_UV": [0, 16],
"frames_per_second": 24,
"max_frame": 16
}
}
},
"minecraft:particle_motion_collision": {
"collision_drag": 5,
"collision_radius": 0.1
},
"minecraft:particle_appearance_lighting": {},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.emitter_age",
"gradient": {
"0.0": "#FFFFFFFF",
"0.6": "#ffffffff",
"0.72": "#FF5C646D",
"1.0": "#FF5C646D"
}
}
}
}
}
}
@@ -0,0 +1,82 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:poodle_hair_green",
"basic_render_parameters": {
"material": "particles_blend",
"texture": "textures/particles/generic/cotton"
}
},
"events": {
"event_sound": {
"expression": "q.sound('minecraft:entity.sheep.shear', 1, math.random(0.9,1.1))",
"particle_effect": {
"effect": "cobblemon:poodle_hair_particles",
"type": "particle"
}
}
},
"components": {
"minecraft:emitter_rate_steady": {
"spawn_rate": 64,
"max_particles": 64
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.8
},
"minecraft:emitter_lifetime_events": {
"timeline": {
"0.10": "event_sound",
"0.30": "event_sound"
}
},
"minecraft:emitter_shape_point": {
"offset": [0, "math.random(-0.3,0.8)", 0],
"direction": ["math.random(-3,3)", "math.random(0,2)", "math.random(-3,3)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 0.7
},
"minecraft:particle_initial_spin": {
"rotation": "math.random_integer(1,4) * 90"
},
"minecraft:particle_initial_speed": 7,
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, -5, 0],
"linear_drag_coefficient": 5
},
"minecraft:particle_appearance_billboard": {
"size": [0.4, 0.4],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 48,
"texture_height": 256,
"flipbook": {
"base_UV": ["math.floor(v.particle_random_2*3)*16", 0],
"size_UV": [16, 16],
"step_UV": [0, 16],
"frames_per_second": 24,
"max_frame": 16
}
}
},
"minecraft:particle_motion_collision": {
"collision_drag": 5,
"collision_radius": 0.1
},
"minecraft:particle_appearance_lighting": {},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.emitter_age",
"gradient": {
"0.0": "#FFFFFFFF",
"0.6": "#ffffffff",
"0.72": "#FF366623",
"1.0": "#FF366623"
}
}
}
}
}
}
@@ -0,0 +1,82 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:poodle_hair_light_blue",
"basic_render_parameters": {
"material": "particles_blend",
"texture": "textures/particles/generic/cotton"
}
},
"events": {
"event_sound": {
"expression": "q.sound('minecraft:entity.sheep.shear', 1, math.random(0.9,1.1))",
"particle_effect": {
"effect": "cobblemon:poodle_hair_particles",
"type": "particle"
}
}
},
"components": {
"minecraft:emitter_rate_steady": {
"spawn_rate": 64,
"max_particles": 64
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.8
},
"minecraft:emitter_lifetime_events": {
"timeline": {
"0.10": "event_sound",
"0.30": "event_sound"
}
},
"minecraft:emitter_shape_point": {
"offset": [0, "math.random(-0.3,0.8)", 0],
"direction": ["math.random(-3,3)", "math.random(0,2)", "math.random(-3,3)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 0.7
},
"minecraft:particle_initial_spin": {
"rotation": "math.random_integer(1,4) * 90"
},
"minecraft:particle_initial_speed": 7,
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, -5, 0],
"linear_drag_coefficient": 5
},
"minecraft:particle_appearance_billboard": {
"size": [0.4, 0.4],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 48,
"texture_height": 256,
"flipbook": {
"base_UV": ["math.floor(v.particle_random_2*3)*16", 0],
"size_UV": [16, 16],
"step_UV": [0, 16],
"frames_per_second": 24,
"max_frame": 16
}
}
},
"minecraft:particle_motion_collision": {
"collision_drag": 5,
"collision_radius": 0.1
},
"minecraft:particle_appearance_lighting": {},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.emitter_age",
"gradient": {
"0.0": "#FFFFFFFF",
"0.6": "#ffffffff",
"0.72": "#FF95B8EC",
"1.0": "#FF95B8EC"
}
}
}
}
}
}
@@ -0,0 +1,82 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:poodle_hair_light_gray",
"basic_render_parameters": {
"material": "particles_blend",
"texture": "textures/particles/generic/cotton"
}
},
"events": {
"event_sound": {
"expression": "q.sound('minecraft:entity.sheep.shear', 1, math.random(0.9,1.1))",
"particle_effect": {
"effect": "cobblemon:poodle_hair_particles",
"type": "particle"
}
}
},
"components": {
"minecraft:emitter_rate_steady": {
"spawn_rate": 64,
"max_particles": 64
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.8
},
"minecraft:emitter_lifetime_events": {
"timeline": {
"0.10": "event_sound",
"0.30": "event_sound"
}
},
"minecraft:emitter_shape_point": {
"offset": [0, "math.random(-0.3,0.8)", 0],
"direction": ["math.random(-3,3)", "math.random(0,2)", "math.random(-3,3)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 0.7
},
"minecraft:particle_initial_spin": {
"rotation": "math.random_integer(1,4) * 90"
},
"minecraft:particle_initial_speed": 7,
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, -5, 0],
"linear_drag_coefficient": 5
},
"minecraft:particle_appearance_billboard": {
"size": [0.4, 0.4],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 48,
"texture_height": 256,
"flipbook": {
"base_UV": ["math.floor(v.particle_random_2*3)*16", 0],
"size_UV": [16, 16],
"step_UV": [0, 16],
"frames_per_second": 24,
"max_frame": 16
}
}
},
"minecraft:particle_motion_collision": {
"collision_drag": 5,
"collision_radius": 0.1
},
"minecraft:particle_appearance_lighting": {},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.emitter_age",
"gradient": {
"0.0": "#FFFFFFFF",
"0.6": "#ffffffff",
"0.72": "#FFB1B1BE",
"1.0": "#FFB1B1BE"
}
}
}
}
}
}
@@ -0,0 +1,82 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:poodle_hair_lime",
"basic_render_parameters": {
"material": "particles_blend",
"texture": "textures/particles/generic/cotton"
}
},
"events": {
"event_sound": {
"expression": "q.sound('minecraft:entity.sheep.shear', 1, math.random(0.9,1.1))",
"particle_effect": {
"effect": "cobblemon:poodle_hair_particles",
"type": "particle"
}
}
},
"components": {
"minecraft:emitter_rate_steady": {
"spawn_rate": 64,
"max_particles": 64
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.8
},
"minecraft:emitter_lifetime_events": {
"timeline": {
"0.10": "event_sound",
"0.30": "event_sound"
}
},
"minecraft:emitter_shape_point": {
"offset": [0, "math.random(-0.3,0.8)", 0],
"direction": ["math.random(-3,3)", "math.random(0,2)", "math.random(-3,3)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 0.7
},
"minecraft:particle_initial_spin": {
"rotation": "math.random_integer(1,4) * 90"
},
"minecraft:particle_initial_speed": 7,
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, -5, 0],
"linear_drag_coefficient": 5
},
"minecraft:particle_appearance_billboard": {
"size": [0.4, 0.4],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 48,
"texture_height": 256,
"flipbook": {
"base_UV": ["math.floor(v.particle_random_2*3)*16", 0],
"size_UV": [16, 16],
"step_UV": [0, 16],
"frames_per_second": 24,
"max_frame": 16
}
}
},
"minecraft:particle_motion_collision": {
"collision_drag": 5,
"collision_radius": 0.1
},
"minecraft:particle_appearance_lighting": {},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.emitter_age",
"gradient": {
"0.0": "#FFFFFFFF",
"0.6": "#ffffffff",
"0.72": "#FFB7FF42",
"1.0": "#FFB7FF42"
}
}
}
}
}
}
@@ -0,0 +1,82 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:poodle_hair_magenta",
"basic_render_parameters": {
"material": "particles_blend",
"texture": "textures/particles/generic/cotton"
}
},
"events": {
"event_sound": {
"expression": "q.sound('minecraft:entity.sheep.shear', 1, math.random(0.9,1.1))",
"particle_effect": {
"effect": "cobblemon:poodle_hair_particles",
"type": "particle"
}
}
},
"components": {
"minecraft:emitter_rate_steady": {
"spawn_rate": 64,
"max_particles": 64
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.8
},
"minecraft:emitter_lifetime_events": {
"timeline": {
"0.10": "event_sound",
"0.30": "event_sound"
}
},
"minecraft:emitter_shape_point": {
"offset": [0, "math.random(-0.3,0.8)", 0],
"direction": ["math.random(-3,3)", "math.random(0,2)", "math.random(-3,3)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 0.7
},
"minecraft:particle_initial_spin": {
"rotation": "math.random_integer(1,4) * 90"
},
"minecraft:particle_initial_speed": 7,
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, -5, 0],
"linear_drag_coefficient": 5
},
"minecraft:particle_appearance_billboard": {
"size": [0.4, 0.4],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 48,
"texture_height": 256,
"flipbook": {
"base_UV": ["math.floor(v.particle_random_2*3)*16", 0],
"size_UV": [16, 16],
"step_UV": [0, 16],
"frames_per_second": 24,
"max_frame": 16
}
}
},
"minecraft:particle_motion_collision": {
"collision_drag": 5,
"collision_radius": 0.1
},
"minecraft:particle_appearance_lighting": {},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.emitter_age",
"gradient": {
"0.0": "#FFFFFFFF",
"0.6": "#ffffffff",
"0.72": "#FFFDA6D5",
"1.0": "#FFFDA6D5"
}
}
}
}
}
}
@@ -0,0 +1,82 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:poodle_hair_orange",
"basic_render_parameters": {
"material": "particles_blend",
"texture": "textures/particles/generic/cotton"
}
},
"events": {
"event_sound": {
"expression": "q.sound('minecraft:entity.sheep.shear', 1, math.random(0.9,1.1))",
"particle_effect": {
"effect": "cobblemon:poodle_hair_particles",
"type": "particle"
}
}
},
"components": {
"minecraft:emitter_rate_steady": {
"spawn_rate": 64,
"max_particles": 64
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.8
},
"minecraft:emitter_lifetime_events": {
"timeline": {
"0.10": "event_sound",
"0.30": "event_sound"
}
},
"minecraft:emitter_shape_point": {
"offset": [0, "math.random(-0.3,0.8)", 0],
"direction": ["math.random(-3,3)", "math.random(0,2)", "math.random(-3,3)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 0.7
},
"minecraft:particle_initial_spin": {
"rotation": "math.random_integer(1,4) * 90"
},
"minecraft:particle_initial_speed": 7,
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, -5, 0],
"linear_drag_coefficient": 5
},
"minecraft:particle_appearance_billboard": {
"size": [0.4, 0.4],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 48,
"texture_height": 256,
"flipbook": {
"base_UV": ["math.floor(v.particle_random_2*3)*16", 0],
"size_UV": [16, 16],
"step_UV": [0, 16],
"frames_per_second": 24,
"max_frame": 16
}
}
},
"minecraft:particle_motion_collision": {
"collision_drag": 5,
"collision_radius": 0.1
},
"minecraft:particle_appearance_lighting": {},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.emitter_age",
"gradient": {
"0.0": "#FFFFFFFF",
"0.6": "#ffffffff",
"0.72": "#FFF6AE46",
"1.0": "#FFF6AE46"
}
}
}
}
}
}
@@ -0,0 +1,47 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:poodle_hair_particles",
"basic_render_parameters": {
"material": "particles_blend",
"texture": "textures/particles/generic/confetti"
}
},
"components": {
"minecraft:emitter_rate_steady": {
"spawn_rate": 12,
"max_particles": 100
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.5
},
"minecraft:emitter_shape_sphere": {
"radius": 0.4,
"direction": ["math.random(-3,3)", "math.random(0,3)", "math.random(-3,3)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1
},
"minecraft:particle_initial_speed": 9,
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, -12, 0],
"linear_drag_coefficient": 4
},
"minecraft:particle_appearance_billboard": {
"size": [0.05, 0.05],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 16,
"texture_height": 16,
"uv": [0, 0],
"uv_size": [16, 16]
}
},
"minecraft:particle_motion_collision": {
"collision_drag": 5,
"collision_radius": 0.01
}
}
}
}
@@ -0,0 +1,82 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:poodle_hair_pink",
"basic_render_parameters": {
"material": "particles_blend",
"texture": "textures/particles/generic/cotton"
}
},
"events": {
"event_sound": {
"expression": "q.sound('minecraft:entity.sheep.shear', 1, math.random(0.9,1.1))",
"particle_effect": {
"effect": "cobblemon:poodle_hair_particles",
"type": "particle"
}
}
},
"components": {
"minecraft:emitter_rate_steady": {
"spawn_rate": 64,
"max_particles": 64
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.8
},
"minecraft:emitter_lifetime_events": {
"timeline": {
"0.10": "event_sound",
"0.30": "event_sound"
}
},
"minecraft:emitter_shape_point": {
"offset": [0, "math.random(-0.3,0.8)", 0],
"direction": ["math.random(-3,3)", "math.random(0,2)", "math.random(-3,3)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 0.7
},
"minecraft:particle_initial_spin": {
"rotation": "math.random_integer(1,4) * 90"
},
"minecraft:particle_initial_speed": 7,
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, -5, 0],
"linear_drag_coefficient": 5
},
"minecraft:particle_appearance_billboard": {
"size": [0.4, 0.4],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 48,
"texture_height": 256,
"flipbook": {
"base_UV": ["math.floor(v.particle_random_2*3)*16", 0],
"size_UV": [16, 16],
"step_UV": [0, 16],
"frames_per_second": 24,
"max_frame": 16
}
}
},
"minecraft:particle_motion_collision": {
"collision_drag": 5,
"collision_radius": 0.1
},
"minecraft:particle_appearance_lighting": {},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.emitter_age",
"gradient": {
"0.0": "#FFFFFFFF",
"0.6": "#ffffffff",
"0.72": "#FFCE69CC",
"1.0": "#FFCE69CC"
}
}
}
}
}
}
@@ -0,0 +1,82 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:poodle_hair_purple",
"basic_render_parameters": {
"material": "particles_blend",
"texture": "textures/particles/generic/cotton"
}
},
"events": {
"event_sound": {
"expression": "q.sound('minecraft:entity.sheep.shear', 1, math.random(0.9,1.1))",
"particle_effect": {
"effect": "cobblemon:poodle_hair_particles",
"type": "particle"
}
}
},
"components": {
"minecraft:emitter_rate_steady": {
"spawn_rate": 64,
"max_particles": 64
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.8
},
"minecraft:emitter_lifetime_events": {
"timeline": {
"0.10": "event_sound",
"0.30": "event_sound"
}
},
"minecraft:emitter_shape_point": {
"offset": [0, "math.random(-0.3,0.8)", 0],
"direction": ["math.random(-3,3)", "math.random(0,2)", "math.random(-3,3)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 0.7
},
"minecraft:particle_initial_spin": {
"rotation": "math.random_integer(1,4) * 90"
},
"minecraft:particle_initial_speed": 7,
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, -5, 0],
"linear_drag_coefficient": 5
},
"minecraft:particle_appearance_billboard": {
"size": [0.4, 0.4],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 48,
"texture_height": 256,
"flipbook": {
"base_UV": ["math.floor(v.particle_random_2*3)*16", 0],
"size_UV": [16, 16],
"step_UV": [0, 16],
"frames_per_second": 24,
"max_frame": 16
}
}
},
"minecraft:particle_motion_collision": {
"collision_drag": 5,
"collision_radius": 0.1
},
"minecraft:particle_appearance_lighting": {},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.emitter_age",
"gradient": {
"0.0": "#FFFFFFFF",
"0.6": "#ffffffff",
"0.72": "#FF925AC4",
"1.0": "#FF925AC4"
}
}
}
}
}
}
@@ -0,0 +1,82 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:poodle_hair_red",
"basic_render_parameters": {
"material": "particles_blend",
"texture": "textures/particles/generic/cotton"
}
},
"events": {
"event_sound": {
"expression": "q.sound('minecraft:entity.sheep.shear', 1, math.random(0.9,1.1))",
"particle_effect": {
"effect": "cobblemon:poodle_hair_particles",
"type": "particle"
}
}
},
"components": {
"minecraft:emitter_rate_steady": {
"spawn_rate": 64,
"max_particles": 64
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.8
},
"minecraft:emitter_lifetime_events": {
"timeline": {
"0.10": "event_sound",
"0.30": "event_sound"
}
},
"minecraft:emitter_shape_point": {
"offset": [0, "math.random(-0.3,0.8)", 0],
"direction": ["math.random(-3,3)", "math.random(0,2)", "math.random(-3,3)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 0.7
},
"minecraft:particle_initial_spin": {
"rotation": "math.random_integer(1,4) * 90"
},
"minecraft:particle_initial_speed": 7,
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, -5, 0],
"linear_drag_coefficient": 5
},
"minecraft:particle_appearance_billboard": {
"size": [0.4, 0.4],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 48,
"texture_height": 256,
"flipbook": {
"base_UV": ["math.floor(v.particle_random_2*3)*16", 0],
"size_UV": [16, 16],
"step_UV": [0, 16],
"frames_per_second": 24,
"max_frame": 16
}
}
},
"minecraft:particle_motion_collision": {
"collision_drag": 5,
"collision_radius": 0.1
},
"minecraft:particle_appearance_lighting": {},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.emitter_age",
"gradient": {
"0.0": "#FFFFFFFF",
"0.6": "#ffffffff",
"0.72": "#FFDB4C4C",
"1.0": "#FFDB4C4C"
}
}
}
}
}
}
@@ -0,0 +1,70 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:poodle_hair_white",
"basic_render_parameters": {
"material": "particles_blend",
"texture": "textures/particles/generic/cotton"
}
},
"events": {
"event_sound": {
"expression": "q.sound('minecraft:entity.sheep.shear', 1, math.random(0.9,1.1))",
"particle_effect": {
"effect": "cobblemon:poodle_hair_particles",
"type": "particle"
}
}
},
"components": {
"minecraft:emitter_rate_steady": {
"spawn_rate": 64,
"max_particles": 64
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.8
},
"minecraft:emitter_lifetime_events": {
"timeline": {
"0.10": "event_sound",
"0.30": "event_sound"
}
},
"minecraft:emitter_shape_point": {
"offset": [0, "math.random(-0.3,0.8)", 0],
"direction": ["math.random(-3,3)", "math.random(0,2)", "math.random(-3,3)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 0.7
},
"minecraft:particle_initial_spin": {
"rotation": "math.random_integer(1,4) * 90"
},
"minecraft:particle_initial_speed": 7,
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, -5, 0],
"linear_drag_coefficient": 5
},
"minecraft:particle_appearance_billboard": {
"size": [0.4, 0.4],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 48,
"texture_height": 256,
"flipbook": {
"base_UV": ["math.floor(v.particle_random_2*3)*16", 0],
"size_UV": [16, 16],
"step_UV": [0, 16],
"frames_per_second": 24,
"max_frame": 16
}
}
},
"minecraft:particle_motion_collision": {
"collision_drag": 5,
"collision_radius": 0.1
}
}
}
}
@@ -0,0 +1,82 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:poodle_hair_yellow",
"basic_render_parameters": {
"material": "particles_blend",
"texture": "textures/particles/generic/cotton"
}
},
"events": {
"event_sound": {
"expression": "q.sound('minecraft:entity.sheep.shear', 1, math.random(0.9,1.1))",
"particle_effect": {
"effect": "cobblemon:poodle_hair_particles",
"type": "particle"
}
}
},
"components": {
"minecraft:emitter_rate_steady": {
"spawn_rate": 64,
"max_particles": 64
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.8
},
"minecraft:emitter_lifetime_events": {
"timeline": {
"0.10": "event_sound",
"0.30": "event_sound"
}
},
"minecraft:emitter_shape_point": {
"offset": [0, "math.random(-0.3,0.8)", 0],
"direction": ["math.random(-3,3)", "math.random(0,2)", "math.random(-3,3)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 0.7
},
"minecraft:particle_initial_spin": {
"rotation": "math.random_integer(1,4) * 90"
},
"minecraft:particle_initial_speed": 7,
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, -5, 0],
"linear_drag_coefficient": 5
},
"minecraft:particle_appearance_billboard": {
"size": [0.4, 0.4],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 48,
"texture_height": 256,
"flipbook": {
"base_UV": ["math.floor(v.particle_random_2*3)*16", 0],
"size_UV": [16, 16],
"step_UV": [0, 16],
"frames_per_second": 24,
"max_frame": 16
}
}
},
"minecraft:particle_motion_collision": {
"collision_drag": 5,
"collision_radius": 0.1
},
"minecraft:particle_appearance_lighting": {},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.emitter_age",
"gradient": {
"0.0": "#FFFFFFFF",
"0.6": "#ffffffff",
"0.72": "#FFE7DB4D",
"1.0": "#FFE7DB4D"
}
}
}
}
}
}
@@ -12,31 +12,22 @@
"rotation": [15, 15, 30]
},
"tail2": {
"rotation": [45, 0, 0]
"rotation": [35, 0, 0]
},
"tail3": {
"rotation": [45, 0, 0]
"rotation": [30, 0, 0]
},
"tail4": {
"rotation": [-55, 0, 0]
},
"leg_left": {
"rotation": [15, 0, 0]
},
"foot_left": {
"rotation": [15, 0, 0]
"rotation": [25, 0, 0]
},
"tail": {
"rotation": [17.5, 0, 0]
"rotation": [15, 0, 0]
},
"tail5": {
"rotation": [-52.5, 0, 0]
"rotation": [-35, 0, 0]
},
"tail6": {
"rotation": [-60, 0, 0]
},
"tail7": {
"rotation": [-37.5, 0, 0]
"rotation": [-35, 0, 0]
},
"leg_right": {
"rotation": [15, 0, 0]
@@ -49,6 +40,30 @@
},
"arm_right": {
"rotation": [15, -15, -30]
},
"tail7": {
"rotation": [-35, 0, 0]
},
"tail8": {
"rotation": [-35, 0, 0]
},
"tail9": {
"rotation": [-40, 0, 0]
},
"tail10": {
"rotation": [-30, 0, 0]
},
"tail11": {
"rotation": [10, 0, 0]
},
"leg_left": {
"rotation": [15, 0, 0]
},
"foot_left": {
"rotation": [15, 0, 0]
},
"locator_item": {
"position": [0, "math.sin(q.anim_time*90*0.5)*0.2", 0]
}
}
},
@@ -74,21 +89,12 @@
"tail4": {
"rotation": [-10, 0, 0]
},
"leg_left": {
"rotation": [15, 0, 0]
},
"foot_left": {
"rotation": [30, 0, 0]
},
"tail5": {
"rotation": [-20, 0, 0]
},
"tail6": {
"rotation": [-17.5, 0, 0]
},
"tail7": {
"rotation": [-15, 0, 0]
},
"leg_right": {
"rotation": [15, 0, 0]
},
@@ -100,25 +106,227 @@
},
"arm_right": {
"rotation": [15, 0, -30]
},
"tail7": {
"rotation": [-15, 0, 0]
},
"leg_left": {
"rotation": [15, 0, 0]
},
"foot_left": {
"rotation": [30, 0, 0]
},
"tail8": {
"rotation": [10, 0, 0]
},
"tail9": {
"rotation": [15, 0, 0]
},
"tail10": {
"rotation": [5, 0, 0]
},
"tail11": {
"rotation": [10, 0, 0]
},
"locator_item": {
"position": [0, "math.sin(q.anim_time*90*0.5)*0.2", 0]
}
}
},
"animation.mew.blink": {
"animation_length": 0.16667,
"animation_length": 0.1667,
"bones": {
"eyelid_left": {
"position": {
"0.0": [0.1, 0, -0.1],
"0.125": [0.1, 0, -0.1],
"0.1667": [0, 0, 0]
"0.1667": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]}
}
},
"eyelid_right": {
"position": {
"0.0": [-0.1, 0, -0.1],
"0.125": [-0.1, 0, -0.1],
"0.1667": [0, 0, 0]
"0.1667": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]}
}
},
"eye_left": {
"position": {
"0.0": [-0.1, 0, 0.1],
"0.1667": {"pre": [-0.1, 0, 0.1], "post": [0, 0, 0]}
}
},
"eye_right": {
"position": {
"0.0": [0.1, 0, 0.1],
"0.1667": {"pre": [0.1, 0, 0.1], "post": [0, 0, 0]}
}
}
}
},
"animation.mew.pose": {
"loop": true,
"bones": {
"body": {
"rotation": [15, -35, 0],
"position": [0, 5, 0]
},
"arm_left": {
"rotation": [-8.6, 39.5, 33.5]
},
"tail2": {
"rotation": [18.5, -22, -4]
},
"tail3": {
"rotation": [32, -19.5, -11.5]
},
"tail4": {
"rotation": [45.5, -12.5, -6.5]
},
"tail": {
"rotation": [-65.5, -7, 10.5]
},
"tail5": {
"rotation": [35.5, 7, 7]
},
"tail6": {
"rotation": [20.5, 8, 6]
},
"tail11": {
"rotation": [27.5, 17.5, 0]
},
"leg_right": {
"rotation": [35.2, 24.5, 27.75]
},
"foot_right": {
"rotation": [7.5, 1.5, -9.5]
},
"head": {
"rotation": [-55, 66.7, -57]
},
"torso": {
"rotation": [25, 0, 0]
},
"torso2": {
"rotation": [-17.5, 0.85, 4.95]
},
"arm_left2": {
"rotation": [0, 0, 15]
},
"arm_right": {
"rotation": [-25.5, -31.8, -27.6]
},
"arm_right2": {
"rotation": [0, 0, -17.5]
},
"torso3": {
"rotation": [-15, -1.3, -7.4]
},
"foot_right2": {
"rotation": [10, 0, 0]
},
"leg_right2": {
"rotation": [14.6, 12.5, 9.25]
},
"leg_left": {
"rotation": [24.5, -18.5, -32.5]
},
"leg_left2": {
"rotation": [25.75, 10.25, 11.7]
},
"foot_left": {
"rotation": [15, 2.5, 0.65]
},
"foot_left2": {
"rotation": [7.5, 0, 0]
},
"tail9": {
"rotation": [35.5, 8.5, 9.5]
},
"tail8": {
"rotation": [35.5, 7.5, 7]
},
"tail7": {
"rotation": [30, 3.5, 3.5]
},
"tail10": {
"rotation": [31.5, 11.5, 13]
}
}
},
"animation.mew.angry": {
"loop": true,
"bones": {
"eyelid_angry_left": {
"position": [0, 0, -0.1]
},
"eyelid_angry_right": {
"position": [0, 0, -0.1]
},
"mouth_open": {
"position": [0, -0.1, 0]
}
}
},
"animation.mew.annoyed": {
"loop": true,
"bones": {
"eyelid_annoyed_left": {
"position": [0.1, 0, -0.1]
},
"eyelid_annoyed_right": {
"position": [-0.1, 0, -0.1]
}
}
},
"animation.mew.sad": {
"loop": true,
"bones": {
"eyelid_sad_left": {
"position": [0.1, 0, -0.1]
},
"eyelid_sad_right": {
"position": [-0.1, 0, -0.1]
},
"eyeshine_left": {
"position": [-0.25, 0, 0],
"scale": 1.1
},
"eyeshine_right": {
"position": [0.25, 0, 0],
"scale": 1.1
}
}
},
"animation.mew.happy": {
"loop": true,
"bones": {
"eyelid_happy_left": {
"position": [0.1, 0, -0.1]
},
"eyelid_happy_right": {
"position": [-0.1, 0, -0.1]
},
"eye_left": {
"position": [-0.1, 0, 0.1]
},
"eye_right": {
"position": [0.1, 0, 0.1]
}
}
},
"animation.mew.hurt": {
"loop": true,
"bones": {
"eye_left": {
"position": [-0.1, 0, 0.1]
},
"eyelid_hurt_left": {
"position": [0.1, 0, -0.1]
},
"eye_right": {
"position": [0.1, 0, 0.1]
},
"eyelid_hurt_right": {
"position": [-0.1, 0, -0.1]
}
}
}
@@ -630,6 +630,27 @@
},
"shoulder_tuft_right5": {
"rotation": [0, "math.sin(q.anim_time*90*8/3-90)*12", 0]
},
"locator_seat_1": {
"rotation": [-20, 0, 0],
"position": [0, -1.75, 0]
}
}
},
"animation.ursaring.ride_ground_walk": {
"loop": true,
"bones": {
"torso": {
"rotation": [0, "q.r.yaw_change(0)*10", 0]
},
"waist": {
"rotation": [0, "q.r.yaw_change(0)*10", 0]
},
"chest": {
"rotation": [0, "q.r.yaw_change(0)*10", 0]
},
"head": {
"rotation": [0, "q.r.yaw_change(0)*20", 0]
}
}
},
@@ -1108,6 +1129,152 @@
"lerp_mode": "catmullrom"
}
}
},
"locator_seat_1": {
"rotation": [-45, 0, 0],
"position": [0, -3, 0]
}
}
},
"animation.ursaring.ride_ground_run": {
"loop": true,
"bones": {
"torso": {
"rotation": [0, "q.r.yaw_change(0)*10", 0]
},
"waist": {
"rotation": [0, "q.r.yaw_change(0)*10", 0]
},
"chest": {
"rotation": [0, "q.r.yaw_change(0)*10", 0]
},
"head": {
"rotation": [0, "q.r.yaw_change(0)*10", "q.r.yaw_change(0)*-10"]
}
}
},
"animation.ursaring.ride_jump": {
"loop": true,
"bones": {
"torso": {
"rotation": ["q.r.velocity_y(0)*10+math.sin(q.anim_time*90*12-90)*-1", 0, 0]
},
"waist": {
"rotation": ["q.r.velocity_y(0)*-10", 0, 0]
},
"chest": {
"rotation": ["q.r.velocity_y(0)*-10+math.sin(q.anim_time*90*12-90)*2", 0, 0]
},
"head": {
"rotation": ["q.r.velocity_y(0)*-10", 0, 0]
},
"ear_right": {
"rotation": [-20, 0, "-(math.sin(q.anim_time*90*20))"]
},
"ear_left": {
"rotation": [-20, 0, "math.sin(q.anim_time*90*20)"]
},
"shoulder_tufts_left": {
"rotation": [0, 0, "q.r.velocity_y(0)*20"]
},
"shoulder_tuft_left1": {
"rotation": [0, 0, "math.sin(q.anim_time*90*20-90)"]
},
"shoulder_tuft_left2": {
"rotation": [0, 0, "math.sin(q.anim_time*90*20-120)"]
},
"shoulder_tuft_left3": {
"rotation": [0, 0, "math.sin(q.anim_time*90*20-150)"]
},
"shoulder_tuft_left4": {
"rotation": [0, 0, "math.sin(q.anim_time*90*20-180)"]
},
"shoulder_tuft_left5": {
"rotation": [0, 0, "math.sin(q.anim_time*90*20-210)"]
},
"shoulder_left": {
"rotation": [0, "q.r.velocity_y(0)*-20", "20+q.r.velocity_y(0)*30+math.sin(q.anim_time*90*20)"]
},
"arm_left2": {
"rotation": [0, "32.5+math.sin(q.anim_time*90*20-90)*1.5", 0]
},
"hand_left": {
"rotation": [0, 0, 12.5]
},
"thumb_left": {
"rotation": [37.5, 0, 0]
},
"finger_left1": {
"rotation": [0, 0, 20]
},
"finger_left2": {
"rotation": [0, 0, 12.5]
},
"finger_left3": {
"rotation": [0, 0, 7.5]
},
"shoulder_tufts_right": {
"rotation": [0, 0, "-(q.r.velocity_y(0)*20)"]
},
"shoulder_tuft_right1": {
"rotation": [0, 0, "-(math.sin(q.anim_time*90*20-90))"]
},
"shoulder_tuft_right2": {
"rotation": [0, 0, "-(math.sin(q.anim_time*90*20-120))"]
},
"shoulder_tuft_right3": {
"rotation": [0, 0, "-(math.sin(q.anim_time*90*20-150))"]
},
"shoulder_tuft_right4": {
"rotation": [0, 0, "-(math.sin(q.anim_time*90*20-180))"]
},
"shoulder_tuft_right5": {
"rotation": [0, 0, "-(math.sin(q.anim_time*90*20-210))"]
},
"shoulder_right": {
"rotation": [0, "q.r.velocity_y(0)*20", "-20+q.r.velocity_y(0)*-30-math.sin(q.anim_time*90*20)"]
},
"arm_right2": {
"rotation": [0, "-32.5-math.sin(q.anim_time*90*20-90)*1.5", 0]
},
"hand_right": {
"rotation": [0, 0, -12.5]
},
"thumb_right": {
"rotation": [37.5, 0, 0]
},
"finger_right1": {
"rotation": [0, 0, -20]
},
"finger_right2": {
"rotation": [0, 0, -12.5]
},
"finger_right3": {
"rotation": [0, 0, -7.5]
},
"tail": {
"rotation": ["q.r.velocity_y(0)*-20+math.sin(q.anim_time*90*20)*2", 0, 0]
},
"leg_left": {
"rotation": ["-10+q.r.velocity_y(0)*20+math.sin(q.anim_time*90*20)", -17.5, 0]
},
"knee_left": {
"rotation": ["math.clamp((q.r.velocity_y(0)*32.5),0,32.5)+math.sin(q.anim_time*90*20-90)", 0, 0]
},
"foot_left": {
"rotation": [12.5, 0, 0]
},
"leg_right": {
"rotation": ["-42.5+q.r.velocity_y(0)*20+math.sin(q.anim_time*90*20)", 12.5, 0]
},
"knee_right": {
"rotation": ["math.clamp((q.r.velocity_y(0)*32.5),0,32.5)+math.sin(q.anim_time*90*20-90)", 0, 0]
},
"foot_right": {
"rotation": [12.5, 0, 0]
},
"body": {
"position": [0, "0+math.sin(q.anim_time*90*12)*0.2", 0]
}
}
},
@@ -1,29 +1,78 @@
{
"format_version": "1.8.0",
"animations": {
"animation.seedot.idle": {
"loop": true
"animation.seedot.ground_idle": {
"loop": true,
"bones": {
"foot_left": {
"rotation": [0, -10, 0]
},
"foot_right": {
"rotation": [0, 10, 0]
}
}
},
"animation.seedot.sleep": {
"loop": true,
"bones": {
"torso": {
"rotation": [15, 0, 0],
"position": [0, -0.5, 0]
},
"pupil_right": {
"position": [0, 0, 0.1]
},
"pupil_left": {
"position": [0, 0, 0.1]
},
"eyelid_right": {
"position": [-0.1, 0, -0.1]
},
"eyelid_left": {
"position": [0.1, 0, -0.1]
},
"foot_left": {
"rotation": [0, -22.5, 0]
},
"foot_right": {
"rotation": [0, 22.5, 0]
}
}
},
"animation.seedot.blink": {
"animation_length": 0.16667,
"animation_length": 0.1667,
"bones": {
"eyelid_right": {
"pupil_right": {
"position": {
"0.0": [0, 0, -0.1],
"0.125": [0, 0, -0.1],
"0.1667": [0, 0, 0]
"0.0": [0, 0, 0.1],
"0.125": {"pre": [0, 0, 0.1], "post": [0, 0, 0.1]},
"0.1667": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"pupil_left": {
"position": {
"0.0": [0, 0, 0.1],
"0.125": {"pre": [0, 0, 0.1], "post": [0, 0, 0.1]},
"0.1667": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"eyelid_left": {
"position": {
"0.0": [0, 0, -0.1],
"0.125": [0, 0, -0.1],
"0.1667": [0, 0, 0]
"0.0": [0.1, 0, -0.1],
"0.125": {"pre": [0.1, 0, -0.1], "post": [0.1, 0, -0.1]},
"0.1667": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]}
}
},
"eyelid_right": {
"position": {
"0.0": [-0.1, 0, -0.1],
"0.125": {"pre": [-0.1, 0, -0.1], "post": [-0.1, 0, -0.1]},
"0.1667": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]}
}
}
}
},
"animation.seedot.call": {
"animation.seedot.cry": {
"animation_length": 1.5,
"bones": {
"torso": {
@@ -35,6 +84,98 @@
}
}
}
},
"animation.seedot.happy": {
"loop": true,
"bones": {
"pupil_right": {
"position": [0, -0.4, 0],
"scale": [2.2, 1.2, 1]
},
"pupil_left": {
"position": [0, -0.4, 0],
"scale": [2.2, 1.2, 1]
}
}
},
"animation.seedot.hurt": {
"loop": true,
"bones": {
"pupil_right": {
"position": [0, 0, 0.1]
},
"pupil_left": {
"position": [0, 0, 0.1]
},
"eyelid_left": {
"position": [0.1, 0, -0.1]
},
"eyelid_emote_middle_left": {
"position": [0, 0.5, 0]
},
"eyelid_emote_outer_left": {
"position": [0, 0.5, 0]
},
"eyelid_right": {
"position": [-0.1, 0, -0.1]
},
"eyelid_emote_middle_right": {
"position": [0, 0.5, 0]
},
"eyelid_emote_outer_right": {
"position": [0, 0.5, 0]
}
}
},
"animation.seedot.judgy": {
"loop": true,
"bones": {
"eyelid_emote_inner_left": {
"position": [0.1, 1.7, -0.1]
},
"eyelid_emote_middle_left": {
"position": [0.1, 1.7, -0.1]
},
"eyelid_emote_outer_left": {
"position": [0.1, 1.7, -0.1]
},
"eyelid_emote_inner_right": {
"position": [-0.1, 1.7, -0.1]
},
"eyelid_emote_middle_right": {
"position": [-0.1, 1.7, -0.1]
},
"eyelid_emote_outer_right": {
"position": [-0.1, 1.7, -0.1]
}
}
},
"animation.seedot.new": {
"loop": true,
"bones": {
"torso": {
"rotation": [15, 0, 0],
"position": [0, -0.5, 0]
},
"pupil_right": {
"position": [0, 0, 0.1]
},
"pupil_left": {
"position": [0, 0, 0.1]
},
"eyelid_right": {
"position": [-0.1, 0, -0.1]
},
"eyelid_left": {
"position": [0.1, 0, -0.1]
},
"foot_left": {
"rotation": [0, -22.5, 0]
},
"foot_right": {
"rotation": [0, 22.5, 0]
}
}
}
}
}
@@ -1,60 +1,326 @@
{
"format_version": "1.8.0",
"animations": {
"animation.shiftry.idle": {
"animation.shiftry.ground_idle": {
"loop": true,
"bones": {
"arm_left": {
"rotation": [0, 0, 40]
"hair3": {
"rotation": [10, 0, 0]
},
"hair4": {
"rotation": [5, 0, 0]
},
"hair5": {
"rotation": [70, 0, 0]
},
"hair6": {
"rotation": [5, 0, 0]
},
"arm_right": {
"rotation": [0, 0, -40]
"rotation": [5, 0, -15]
},
"leg_left": {
"rotation": [0, -15, 0]
"arm_left": {
"rotation": [5, 0, 15]
},
"leg_right": {
"rotation": [0, 15, 0]
"rotation": [0, 10, 0]
},
"leg_left": {
"rotation": [0, -10, 0]
}
}
},
"animation.shiftry.sleep": {
"loop": true,
"bones": {
"hair3": {
"rotation": [10, 0, 0]
},
"hair4": {
"rotation": [-7.5, 0, 0]
},
"hair5": {
"rotation": [67.5, 0, 0]
},
"hair6": {
"rotation": [5, 0, 0]
},
"arm_right": {
"rotation": [0, -12.5, -20]
},
"arm_left": {
"rotation": [0, 12.5, 20]
},
"torso": {
"rotation": [10, 0, 0]
},
"iris_right": {
"position": [0, 0, 0.1]
},
"eyelid_right": {
"position": [0, 0, -0.1]
},
"iris_left": {
"position": [0, 0, 0.1]
},
"eyelid_left": {
"position": [0, 0, -0.1]
}
}
},
"animation.shiftry.mouth_open_example": {
"animation_length": 1,
"bones": {
"mouth_closed": {
"scale": {
"0.0": [1, 1, 1],
"0.1667": [1, 1, 1],
"0.2083": [0, 0, 0],
"0.7917": [0, 0, 0],
"0.8333": [1, 1, 1],
"1.0": [1, 1, 1]
}
}
}
},
"animation.shiftry.happy": {
"loop": true,
"bones": {
"mouth_closed": {
"scale": 0
},
"iris_right": {
"position": [0, 0, 0.1]
},
"eyelid_right": {
"position": [0, 0.2, -0.1]
},
"eyelid_inner_right": {
"position": [0, -0.2, 0]
},
"eyelid_middle_right": {
"position": [0, 0.5, 0]
},
"eyelid_outer_right": {
"position": [0, -0.2, 0]
},
"iris_left": {
"position": [0, 0, 0.1]
},
"eyelid_left": {
"position": [0, 0.2, -0.1]
},
"eyelid_inner_left": {
"position": [0, -0.2, 0]
},
"eyelid_middle_left": {
"position": [0, 0.5, 0]
},
"eyelid_outer_left": {
"position": [0, -0.2, 0]
},
"iris_cover": {
"position": [0, 0, 0.1]
},
"eye_emote_left": {
"position": [0.3, 0, 0],
"scale": [0.8, 1, 1]
},
"eye_emote_right": {
"position": [-0.3, 0, 0],
"scale": [0.8, 1, 1]
}
}
},
"animation.shiftry.sad": {
"loop": true,
"bones": {
"iris_emote_left": {
"position": [0, 0, 0.1]
},
"iris_emote_right": {
"position": [0, 0, 0.1]
},
"eye_emote_right": {
"position": [-0.625, 0, 0],
"scale": [0.58, 1, 1]
},
"eye_emote_left": {
"position": [0.625, 0, 0],
"scale": [0.58, 1, 1]
}
}
},
"animation.shiftry.hurt": {
"loop": true,
"bones": {
"iris_right": {
"position": [0, 0, 0.1]
},
"eyelid_right": {
"position": [0, 0, -0.1]
},
"eyelid_middle_right": {
"position": [0, 0.5, 0]
},
"eyelid_outer_right": {
"position": [0, 0.5, 0]
},
"iris_left": {
"position": [0, 0, 0.1]
},
"eyelid_left": {
"position": [0, 0, -0.1]
},
"eyelid_middle_left": {
"position": [0, 0.5, 0]
},
"eyelid_outer_left": {
"position": [0, 0.5, 0]
},
"iris_cover": {
"position": [0, 0, 0]
}
}
},
"animation.shiftry.surprised": {
"loop": true,
"bones": {
"mouth_closed": {
"scale": 0
},
"eye_right": {
"scale": [1, 1.2, 1]
},
"iris_right": {
"position": [0.2, 0, 0],
"scale": [0.8, 1, 1]
},
"pupil_right": {
"position": [-0.1, 0, 0],
"scale": [0.8, 0.5, 1]
},
"eye_left": {
"scale": [1, 1.2, 1]
},
"iris_left": {
"position": [-0.2, 0, 0],
"scale": [0.8, 1, 1]
},
"pupil_left": {
"position": [0.1, 0, 0],
"scale": [0.8, 0.5, 1]
},
"iris_cover": {
"position": [0, 0, 0.1]
},
"eye_emote_right": {
"position": [-0.25, 0, 0],
"scale": [0.83, 1, 1]
},
"eye_emote_left": {
"position": [0.25, 0, 0],
"scale": [0.83, 1, 1]
},
"iris_emote_right": {
"position": [-0.3, 0, 0],
"scale": [0.7, 1, 1]
},
"iris_emote_left": {
"position": [0.3, 0, 0],
"scale": [0.7, 1, 1]
}
}
},
"animation.shiftry.angry": {
"loop": true,
"bones": {
"eye_emote_right": {
"position": [-1, 0, 0],
"scale": [0.35, 2, 1]
},
"iris_emote_right": {
"position": [-0.7, 0, 0],
"scale": [0.3, 1, 1]
},
"eye_emote_left": {
"position": [1, 0, 0],
"scale": [0.35, 2, 1]
},
"iris_emote_left": {
"position": [0.7, 0, 0],
"scale": [0.3, 1, 1]
}
}
},
"animation.shiftry.disintrested": {
"loop": true,
"bones": {
"eye_emote_right": {
"position": [0, -0.5, 0]
},
"iris_emote_right": {
"position": [-0.4, -0.5, 0],
"scale": [0.6, 1, 1]
},
"eye_emote_left": {
"position": [0, -0.5, 0]
},
"iris_emote_left": {
"position": [0.4, -0.5, 0],
"scale": [0.6, 1, 1]
}
}
},
"animation.shiftry.blink": {
"animation_length": 0.16667,
"animation_length": 0.1667,
"bones": {
"eyelid_left": {
"iris_right": {
"position": {
"0.0": [0.1, 0, -0.1],
"0.125": [0.1, 0, -0.1],
"0.1667": [0, 0, 0]
"0.0": [0, 0, 0.1],
"0.125": {"pre": [0, 0, 0.1], "post": [0, 0, 0.1]},
"0.1667": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"eyelid_right": {
"position": {
"0.0": [-0.1, 0, -0.1],
"0.125": [-0.1, 0, -0.1],
"0.1667": [0, 0, 0]
"0.0": [0, 0, -0.1],
"0.125": {"pre": [0, 0, -0.1], "post": [0, 0, -0.1]},
"0.1667": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
},
"iris_left": {
"position": {
"0.0": [0, 0, 0.1],
"0.125": {"pre": [0, 0, 0.1], "post": [0, 0, 0.1]},
"0.1667": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"eyelid_left": {
"position": {
"0.0": [0, 0, -0.1],
"0.125": {"pre": [0, 0, -0.1], "post": [0, 0, -0.1]},
"0.1667": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
}
}
},
"animation.shiftry.call": {
"animation_length": 1.5,
"animation.shiftry.side_eye": {
"loop": true,
"bones": {
"head": {
"rotation": {
"0.0": [0, 0, 0],
"0.25": [0, 0, 0],
"1.25": [0, 0, 0],
"1.5": [0, 0, 0]
}
"iris_right": {
"position": [-0.1, 0, 0],
"scale": [1.3, 1, 1]
},
"teeth2": {
"position": {
"0.0": [0, 0, 0],
"0.25": [0, -1, 0],
"1.25": [0, -1, 0],
"1.5": [0, 0, 0]
}
"pupil_right": {
"position": [-0.6, 0, 0],
"scale": [0.75, 1, 1]
},
"iris_left": {
"position": [-0.1, 0, 0]
},
"pupil_left": {
"position": [-0.1, 0, 0]
}
}
}
@@ -1,39 +1,111 @@
{
"format_version": "1.8.0",
"animations": {
"animation.pachirisu.ground_idle": {
"animation.pachirisu.render": {
"loop": true,
"bones": {
"lefthand": {
"rotation": [30, 15, 0]
"body": {
"rotation": [0, 27.5, 0],
"position": [0, 0.75, 0]
},
"righthand": {
"rotation": [30, -15, 0]
"waist": {
"rotation": [7.5, 0, 0]
},
"leftfoot": {
"rotation": [0, 5, 0]
"torso": {
"rotation": [-7.5, -2.5, -5]
},
"rightfoot": {
"rotation": [0, -5, 0]
"head": {
"rotation": [-4.99917, -2.27268, 7.70829]
},
"arm_left": {
"rotation": [15, 0, 0]
},
"hand_left": {
"rotation": [0, 60, 0]
},
"tail": {
"rotation": [10.34721, 12.06754, 3.28396]
},
"tail2": {
"rotation": [17.5, 0, 0]
},
"tail3": {
"rotation": [22.5, 0, 0]
},
"tail4": {
"rotation": [15, 0, 0]
},
"foot_left": {
"rotation": [22.51606, -32.78202, 3.82048]
},
"foot_left2": {
"rotation": [-12.5, 0, 0]
},
"foot_right": {
"rotation": [28.1141, 35.62807, -3.0733]
},
"foot_right2": {
"rotation": [-20, 0, 0]
},
"arm_right": {
"rotation": [20, 0, 0],
"position": [0, 0.5, 0]
},
"hand_right": {
"rotation": [0, -60, 0]
},
"mouth_open": {
"position": [0, 0, -0.1]
}
}
},
"animation.pachirisu.blink": {
"animation_length": 0.16667,
"animation.pachirisu.ground_idle": {
"loop": true,
"bones": {
"eyelid_right": {
"position": {
"0.0": [0, 0, -0.1],
"0.125": [0, 0, -0.1],
"0.1667": [0, 0, 0]
}
"body": {
"position": [0, 0.5, 0]
},
"eyelid_left": {
"position": {
"0.0": [0, 0, -0.1],
"0.125": [0, 0, -0.1],
"0.1667": [0, 0, 0]
}
"waist": {
"rotation": [7.5, 0, 0]
},
"torso": {
"rotation": [-7.5, 0, 0]
},
"arm_left": {
"rotation": [15, 0, 0]
},
"hand_left": {
"rotation": [0, 60, 0]
},
"tail": {
"rotation": [15, 0, 0]
},
"tail2": {
"rotation": [17.5, 0, 0]
},
"tail3": {
"rotation": [22.5, 0, 0]
},
"tail4": {
"rotation": [15, 0, 0]
},
"foot_left": {
"rotation": [30, -22.5, 0]
},
"foot_left2": {
"rotation": [-17.5, 0, 0]
},
"foot_right": {
"rotation": [30, 22.5, 0]
},
"foot_right2": {
"rotation": [-17.5, 0, 0]
},
"arm_right": {
"rotation": [15, 0, 0]
},
"hand_right": {
"rotation": [0, -60, 0]
}
}
}

Some files were not shown because too many files have changed in this diff Show More