Compare commits

..
Author SHA1 Message Date
Flarkinater c9da67aa05 First attempt to add stadium camera test block (temporarily using display case assets) 2024-05-22 23:29:25 -04:00
Apion 5e6091c782 Merge branch 'tmetcalfe89/revive-event' into 'main'
added fossil revived event

See merge request cable-mc/cobblemon!1029
2024-05-22 07:26:52 +00:00
Timothy MetcalfeandApion 5a2e5479e0 added fossil revived event 2024-05-22 07:26:52 +00:00
Hiroku 4e1b82917b Merge branch 'Roaming-Gholdengo-Request' into 'main'
Lets Gholdengo maintain its roaming aspect

See merge request cable-mc/cobblemon!1025
2024-05-20 00:11:17 +00:00
Frank The FarmerandHiroku 3b1d257241 Lets Gholdengo maintain its roaming aspect 2024-05-20 00:11:16 +00:00
Hiroku 0b8f916648 Merge branch 'dimension-condition-uses-id-not-effects' into 'main'
Change dimension spawn condition to check with IDs not effects

See merge request cable-mc/cobblemon!1026
2024-05-20 00:11:02 +00:00
David Sadler 5ad7d5406a Change dimension spawn condition to check with IDs not effects 2024-05-19 18:45:34 +01:00
Paul 6ec008ee83 Merge remote-tracking branch 'origin/main' into 1.5-fixy
# Conflicts:
#	CHANGELOG.md
2024-05-19 11:19:13 +10:00
Hiroku f4d2226ec2 Merge branch '1.5.1' into 'main'
Moar 🐛🔫

Closes #847 and #799

See merge request cable-mc/cobblemon!1023
2024-05-18 01:50:12 +00:00
apion 0fc5d5e9d7 Fixed bad null handling 2024-05-17 21:41:58 -04:00
Hiroku 972c0f6430 Merge branch 'dubwool-dye' into 'main'
Make wooloos dyable

Closes #824

See merge request cable-mc/cobblemon!1021
2024-05-18 01:40:13 +00:00
ApionandHiroku 86db95a7dc Make wooloos dyable 2024-05-18 01:40:13 +00:00
apion be95b79e4d Removed unnecessary override 2024-05-17 21:20:20 -04:00
apion 5753443ab2 Optimized a player lookup 2024-05-17 20:39:27 -04:00
apion c6b7186032 Merge branch 'refs/heads/main' into 1.5.1
# Conflicts:
#	CHANGELOG.md
2024-05-17 20:35:50 -04:00
apion 32f3be2687 Changelog 2024-05-17 20:33:24 -04:00
apion 9012d78806 Apparently Kotlin uses .equals when using ==, === is Java == behavior 2024-05-17 20:30:18 -04:00
apion fffdfb7654 Fixes bug with InvMove, closes #847 2024-05-17 20:28:57 -04:00
Hiroku b314733f0b Merge branch 'Frank's-Bug-Fixing-Farm' into 'main'
Frank's bug fixing farm

See merge request cable-mc/cobblemon!1019
2024-05-17 10:44:01 +00:00
Frank The FarmerandHiroku d5aa07fe91 Frank's bug fixing farm 2024-05-17 10:44:00 +00:00
apion 27bedc2d2c Closes #799 2024-05-16 21:59:36 -04:00
Hiroku 86744c23a5 Merge branch '1.5.1' into 'main'
Fix recoil evo bug

Closes #844

See merge request cable-mc/cobblemon!1022
2024-05-17 01:41:41 +00:00
apion 8d1a64136f Fix recoil evo bug 2024-05-16 20:33:19 -04:00
Paul bc550dd32c Fixed unlocked evolutions getting re-checked and eating held items, fixes #843 2024-05-17 10:04:54 +10:00
Paul 3009af8c42 Fixed missing cant.nopp lang key, fixes #842 2024-05-17 08:52:23 +10:00
Hiroku bfd34eb621 Merge branch '1.5.1' into 'main'
Fixes a few issues

Closes #827, #828, #826, and #832

See merge request cable-mc/cobblemon!1012
2024-05-16 22:46:10 +00:00
Hiroku 2dc2c96176 Update CHANGELOG.md [skip-ci] 2024-05-16 22:44:00 +00:00
Hiroku df4db17cfd Removed println 2024-05-16 22:40:56 +00:00
apion 45bec488f1 Fixed bug with pasture block 2024-05-15 20:41:32 -04:00
apion 9287374504 Merge branch 'refs/heads/main' into 1.5.1 2024-05-15 18:24:56 -04:00
apion 90c5180712 Revert "update Forge to current RB, update Fabric deps to latest"
This reverts commit 7139d4708b.
2024-05-15 18:17:29 -04:00
apion f2a36cd74a Merge branch 'refs/heads/main' into 1.5.1
# Conflicts:
#	CHANGELOG.md
2024-05-15 14:51:45 -04:00
Nick 158aa05f24 Merge branch 'fix/downgrade-loom' into 'main'
fix: resolve mapping issues by downgrading loom

See merge request cable-mc/cobblemon!1015
2024-05-15 15:38:09 +00:00
Apion 8924d0fe0f Merge branch 'navneetset-main-patch-27693' into 'main'
Fix PC store downsizing not working with .resize()

See merge request cable-mc/cobblemon!1016
2024-05-15 12:12:04 +00:00
PebblesandApion d510eaa462 Fix PC store downsizing not working with .resize() 2024-05-15 12:12:04 +00:00
Hiroku 8b63057d9d Merge branch 'we-ballin' into 'main'
Cherish, Dream, Beast, and Ancient Origin Send Out Particles

See merge request cable-mc/cobblemon!1018
2024-05-15 10:26:08 +00:00
Hiroku d572b3c505 Missed a bit [skip-ci] 2024-05-15 10:25:21 +00:00
Hiroku 8edc60224a Merge branch 'main' into 'we-ballin'
# Conflicts:
#   CHANGELOG.md
2024-05-15 10:24:54 +00:00
Hiroku a634c4f046 Merge branch 'update-libs' into 'main'
Update libs

See merge request cable-mc/cobblemon!1017
2024-05-15 10:23:14 +00:00
MoeBoy76 7139d4708b update Forge to current RB, update Fabric deps to latest 2024-05-15 11:11:02 +10:00
dhi_holo 50e99736a3 Partial Fix
Origin Ball now plays correctly in resource pack, but not in the mod itself, updated jsons to match, so all that's left is working out why the mod refuses to read the new jsons even though the new jsons are read in the files, in intellij, and in github desktop.
2024-05-15 10:43:09 +10:00
MoeBoy76 68c4acf0eb Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon 2024-05-15 09:21:22 +10:00
broccoli 5b5e7109f5 fix: resolve mapping issues by downgrading loom
fixes regression in fd7b82dbe3
2024-05-14 23:17:16 +01:00
Hiroku 37596523db Merge branch 'tmetcalfe89/abstract-stat-ratio-requirement' into 'main'
abstracted stat ratio requirement

See merge request cable-mc/cobblemon!1011
2024-05-14 20:15:13 +00:00
tmetcalfe89 eb80c20dbf updated readme 2024-05-14 09:11:16 -07:00
apion 7ab3951613 Fix gilded chest item drops 2024-05-14 11:16:33 -04:00
apion e6d51c4d56 A little more fossil machine clean up 2024-05-14 10:26:25 -04:00
Apion 3813ec3c92 Merge branch 'sound' into 'main'
Renamed Relic Coin Sack sound assets. Added new sounds for Relic Coin Pouches.

See merge request cable-mc/cobblemon!1013
2024-05-14 14:12:24 +00:00
apion b9364304ca Changelog teehee 2024-05-14 09:47:35 -04:00
Sterrezo 9be212d2b8 Renamed Relic Coin Sack sound assets. Added new sounds for Relic Coin Pouches.
Renamed all sounds called "coin_pouch..." to "relic_coin_sack..." Added new sounds for breaking and placing Relic Coin Pouches with a new sound group for them.
2024-05-14 13:27:11 +02:00
tmetcalfe89 2559257b3a added licenses 2024-05-14 01:16:30 -07:00
apion 8236c6fb11 Merge branch 'refs/heads/main' into 1.5.1 2024-05-14 04:13:40 -04:00
apion 2041d43db4 Hopefully fixed some other bugs 2024-05-14 03:53:35 -04:00
Apion a1687e8304 Merge branch 'tmetcalfe89/ensure-defeat-count' into 'main'
Ensure update total defeat count on battle win

See merge request cable-mc/cobblemon!1010
2024-05-14 07:25:09 +00:00
JazzMcNade 94d92b6fc0 Fixes #827
Jade can now view the contents of the analyzer block
2024-05-14 01:53:56 -05:00
tmetcalfe89 3aa95b9339 abstracted stat ratio requirement 2024-05-13 23:39:01 -07:00
tmetcalfe89 4e97f70801 Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into tmetcalfe89/ensure-defeat-count 2024-05-13 22:39:56 -07:00
dhi_holo 404ca565f5 4 balls maybe working
Send out particles for Cherish, Dream, Beast, and Ancient Origin balls

Needs testing on one issue before MR
2024-05-14 15:35:32 +10:00
MoeBoy76 93db0e1cda Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon 2024-05-14 08:57:15 +10:00
apion 4a4d292228 Fixes #828 2024-05-13 17:01:38 -04:00
apion 0fef9eec3d Fixes #826 2024-05-13 17:01:27 -04:00
apion 5f3dc395ec Fixes #832 2024-05-13 12:17:47 -04:00
Hiroku 1bf9d36dbd Merge branch 'wheres-the-tag-drake' into 'main'
Updated fossils.json Item Tag

Closes #834

See merge request cable-mc/cobblemon!1009
2024-05-13 09:45:38 +00:00
dhi_holo b19c5ed125 Updated fossils.json Item Tag
Sorted the fossils tag to match the order on Bulbapedia (just to make sure all other fossils were there, and because it looks a little nicer), and added Fossilized Drake to the tag
2024-05-13 17:51:19 +10:00
Paul e3cca0d9cf SpawnAction#complete returns R instead of Boolean 2024-05-13 15:08:55 +10:00
tmetcalfe89 1aa55f8199 replaced entity ref with originalPokemon 2024-05-12 21:49:58 -07:00
Paul 4c16b2ce2e Track friendship on client entities, tweaks to dataTracker initializing, MoLang in pose & quirk conditions 2024-05-13 12:47:53 +10:00
MoeBoy76 a0b263e392 Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon 2024-05-03 10:45:11 +10:00
224 changed files with 1733 additions and 1743 deletions
+1
View File
@@ -36,6 +36,7 @@ common/src/main/resources/assets/cobblemon/showdown
*/generated/resources/*
/fabric/src/generated/resources/cobblemon-common.accesswidener
/.ignored/
common/.fabric
# MacOS
.DS_Store
+38 -3
View File
@@ -2,10 +2,45 @@
## [1.5.1](#1-5-1)
### Fixes
-Fixed a bug in which adding organic material to the fossil tank via right click was adding the full count of the stack currently in hand
### Additions
- Added unique send out particles for Cherish, Dream, Beast, and Ancient Origin balls.
- Made Wooloo and Dubwool dye-able like sheep
## [1.5.0 - The Ruins and Revival Update (May Xth, 2024)](#1-5-0)
### Changes
- Sounds for Relic Coin Sacks have been correctly renamed. Relic Coin Pouches received new sounds for breaking and placing.
- Readjusted Petilil portraits
- Changed "dimensions" spawn condition to check with dimension IDs instead of effects, so custom dimension IDs can be used.
### Fixes
- Fixed a bug in which adding organic material to the fossil tank via right click was adding the full count of the stack currently in hand
- Fixed a niche issue where some properties of entities were not initialized correctly, causing Pokémon that appeared to be level 1 until you battle them.
- Fixed Fossilized Drake being missing from the Fossils item tag.
- Fixed Gilded Chest block entity not being cleared on block break
- Fixed sherd brokenness on Forge/Supplementaries incompat
- Fixed Fossil Compartment crash with Jade / WAILA forks
- Fixed PCStore#resize not allowing PC boxes size reduction.
- Fixed pasture block PC lookups when the player is offline.
- Fixed an untranslated battle message that occurs when using a move that just ran out of PP (e.g. Fire Blast that just got spited mid-turn).
- Fixed held items being eaten even when the held item evolutions are already unlocked.
- Fixed Hisuian Decidueye not being Grass/Fighting
- Fixed both Decidueye forms learning both Triple Arrows and Spirit Shackle
- Fixed Pineco being unable to evolve into Shulker Forretress
- Fixed Kabutops T-posing when underwater. It still does not have proper swimming animations yet though.
- Fixed Pidgey's missing walk animation.
- Fixed recoil evo condition.
- Fixed issue where poser debug tools didnt work on JSON posers
- Fixed issue where gilded chests dont close when going far away
### Developer
- Changed SpawnAction#complete to return a nullable generic R (the spawn action result) instead of a boolean. More information this way.
- Added an event when a fossil is revived, with or without a player.
### Data Pack & Resource Pack Creators
- Added support for MoLang conditions for quirks and poses.
- Changed the AttackDefenceRatio requirement to StatCompare and StatEqual.
## [1.5.0 - The Ruins and Revival Update (May 12th, 2024)](#1-5-0)
#### "You're telling me that Mojang has added archaeology to the game? Hmm... that gives me an idea."
### Additions
-1
View File
@@ -43,7 +43,6 @@ dependencies {
modCompileOnly(libs.bundles.fabric.integrations.compileOnly) {
isTransitive = false
}
modImplementation(libs.sbl.fabric)
// Flywheel has no common dep so just pick one and don't use any platform specific code in common
// modCompileOnly(libs.flywheelFabric)
@@ -1,25 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import net.minecraft.entity.ai.brain.Brain;
import net.minecraft.entity.ai.brain.MemoryModuleType;
import net.minecraft.entity.ai.brain.sensor.Sensor;
import net.minecraft.entity.ai.brain.sensor.SensorType;
import java.util.Collection;
public class GenericsCheatClass {
// For some reason, doing this in the PokemonEntity class in Kotlin gives confusing generic errors I could not resolve.
public static Brain.Profile<PokemonEntity> createPokemonBrain(Collection<MemoryModuleType<?>> memories, Collection<SensorType<? extends Sensor<? super PokemonEntity>>> sensors) {
return Brain.createProfile(memories, sensors);
}
}
@@ -102,7 +102,6 @@ import com.cobblemon.mod.common.pokemon.properties.HiddenAbilityPropertyType
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
import com.cobblemon.mod.common.pokemon.properties.tags.PokemonFlagProperty
import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
import com.cobblemon.mod.common.sherds.CobblemonSherds
import com.cobblemon.mod.common.starter.CobblemonStarterHandler
import com.cobblemon.mod.common.trade.TradeManager
import com.cobblemon.mod.common.util.DataKeys
@@ -235,7 +234,7 @@ object Cobblemon {
val player = event.player
val block = player.world.getBlockState(event.pos).block
player.party().forEach { pokemon ->
pokemon.evolutions
pokemon.lockedEvolutions
.filterIsInstance<BlockClickEvolution>()
.forEach { evolution ->
evolution.attemptEvolution(pokemon, BlockClickEvolution.BlockInteractionContext(block, player.world))
@@ -416,7 +415,6 @@ object Cobblemon {
).ifSuccessful { it.mute = true }
}
CobblemonSherds.registerSherds()
}
fun getLevel(dimension: RegistryKey<World>): World? {
@@ -12,9 +12,7 @@ import net.minecraft.entity.ai.brain.Activity
object CobblemonActivities {
val activities = mutableListOf<Activity>()
val BATTLING_ACTIVITY = Activity("pokemon_battle")
val POKEMON_SLEEPING_ACTIVITY = Activity("pokemon_sleeping")
val POKEMON_COMBAT_ACTIVITY = Activity("pokemon_combat")
val BATTLING_ACTIVITY = Activity("pokemon_battling")
fun register(activity: Activity): Activity {
activities.add(activity)
@@ -8,16 +8,8 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.block.entity.BerryBlockEntity
import com.cobblemon.mod.common.block.entity.HealingMachineBlockEntity
import com.cobblemon.mod.common.block.entity.PCBlockEntity
import com.cobblemon.mod.common.block.entity.PokemonPastureBlockEntity
import com.cobblemon.mod.common.block.entity.FossilAnalyzerBlockEntity
import com.cobblemon.mod.common.block.entity.FossilMultiblockEntity
import com.cobblemon.mod.common.block.entity.RestorationTankBlockEntity
import com.cobblemon.mod.common.block.multiblock.FossilMultiblockBuilder
import com.cobblemon.mod.common.block.entity.*
import com.cobblemon.mod.common.block.entity.DisplayCaseBlockEntity
import com.cobblemon.mod.common.block.multiblock.FossilMultiblockBuilder
import com.cobblemon.mod.common.platform.PlatformRegistry
import net.minecraft.block.entity.BlockEntityType
import net.minecraft.registry.Registries
@@ -36,6 +28,9 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
@JvmField
val PC: BlockEntityType<PCBlockEntity> = this.create("pc", BlockEntityType.Builder.create(::PCBlockEntity, CobblemonBlocks.PC).build(null))
@JvmField
val STADIUM: BlockEntityType<StadiumBlockEntity> = this.create("stadium_terminal", BlockEntityType.Builder.create(::StadiumBlockEntity, CobblemonBlocks.STADIUM).build(null))
@JvmField
val BERRY = this.create("berry", BlockEntityType.Builder.create(::BerryBlockEntity, *CobblemonBlocks.berries().values.toTypedArray()).build(null))
@@ -11,22 +11,14 @@ package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.apricorn.Apricorn
import com.cobblemon.mod.common.block.*
import com.cobblemon.mod.common.block.MintBlock.MintType
import com.cobblemon.mod.common.block.FossilAnalyzerBlock
import com.cobblemon.mod.common.block.MonitorBlock
import com.cobblemon.mod.common.block.RestorationTankBlock
import com.cobblemon.mod.common.mixin.invoker.DoorBlockInvoker
import com.cobblemon.mod.common.mixin.invoker.PressurePlateBlockInvoker
import com.cobblemon.mod.common.mixin.invoker.StairsBlockInvoker
import com.cobblemon.mod.common.mixin.invoker.TrapdoorBlockInvoker
import com.cobblemon.mod.common.mixin.invoker.*
import com.cobblemon.mod.common.platform.PlatformRegistry
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.block.BerryBlock
import com.cobblemon.mod.common.block.chest.GildedChestBlock
import com.cobblemon.mod.common.block.sign.CobblemonHangingSignBlock
import com.cobblemon.mod.common.block.sign.CobblemonSignBlock
import com.cobblemon.mod.common.block.sign.CobblemonWallHangingSignBlock
import com.cobblemon.mod.common.block.sign.CobblemonWallSignBlock
import com.cobblemon.mod.common.mixin.invoker.*
import com.cobblemon.mod.common.platform.PlatformRegistry
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.block.*
import net.minecraft.block.enums.Instrument
import net.minecraft.block.piston.PistonBehavior
@@ -234,7 +226,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
"relic_coin_pouch",
CoinPouchBlock(
AbstractBlock.Settings.create()
.sounds(CobblemonSounds.COIN_POUCH_SOUNDS)
.sounds(CobblemonSounds.RELIC_COIN_POUCH_SOUNDS)
.pistonBehavior(PistonBehavior.DESTROY)
.strength(0.4f)
.nonOpaque(), true
@@ -245,7 +237,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
"relic_coin_sack",
CoinPouchBlock(
AbstractBlock.Settings.create()
.sounds(CobblemonSounds.COIN_POUCH_SOUNDS)
.sounds(CobblemonSounds.RELIC_COIN_SACK_SOUNDS)
.pistonBehavior(PistonBehavior.DESTROY)
.strength(0.4f), false
))
@@ -388,6 +380,19 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
)
)
@JvmField
val STADIUM = create(
"stadium_terminal",
StadiumBlock(
AbstractBlock.Settings.create()
.mapColor(MapColor.IRON_GRAY)
.sounds(BlockSoundGroup.METAL)
.pistonBehavior(PistonBehavior.BLOCK)
.strength(2F)
.nonOpaque()
)
)
@JvmField
val DISPLAY_CASE = create(
"display_case",
@@ -23,12 +23,7 @@ import com.cobblemon.mod.common.item.armor.CobblemonArmorTrims
import com.cobblemon.mod.common.item.battle.DireHitItem
import com.cobblemon.mod.common.item.battle.GuardSpecItem
import com.cobblemon.mod.common.item.battle.XStatItem
import com.cobblemon.mod.common.item.berry.FriendshipRaisingBerryItem
import com.cobblemon.mod.common.item.berry.HealingBerryItem
import com.cobblemon.mod.common.item.berry.PPRestoringBerryItem
import com.cobblemon.mod.common.item.berry.PortionHealingBerryItem
import com.cobblemon.mod.common.item.berry.StatusCuringBerryItem
import com.cobblemon.mod.common.item.berry.VolatileCuringBerryItem
import com.cobblemon.mod.common.item.berry.*
import com.cobblemon.mod.common.item.interactive.*
import com.cobblemon.mod.common.item.interactive.PotionItem
import com.cobblemon.mod.common.item.interactive.ability.AbilityChangeItem
@@ -253,6 +248,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
@JvmField
val PC = blockItem("pc", CobblemonBlocks.PC)
@JvmField
val STADIUM = blockItem("stadium_terminal", CobblemonBlocks.STADIUM)
@JvmField
val PASTURE = blockItem("pasture", CobblemonBlocks.PASTURE)
@JvmField
val DISPLAY_CASE = blockItem("display_case", CobblemonBlocks.DISPLAY_CASE)
@@ -1,38 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.PrimitiveCodec
import java.util.Optional
import java.util.UUID
import net.minecraft.entity.ai.brain.MemoryModuleType
import net.minecraft.util.Uuids
object CobblemonMemories {
val memories = mutableMapOf<String, MemoryModuleType<*>>()
val POKEMON_FLYING = register("pokemon_flying", PrimitiveCodec.BOOL)
val POKEMON_DROWSY = register("pokemon_drowsy", PrimitiveCodec.BOOL)
val POKEMON_BATTLE = register<UUID>("pokemon_battle") // No codec because it shouldn't survive relogs
val REST_PATH_COOLDOWN = register("rest_path_cooldown", PrimitiveCodec.BOOL)
val TARGETED_BATTLE_POKEMON = register<UUID>("targeted_battle_pokemon")
fun <U> register(id: String, codec: Codec<U>): MemoryModuleType<U> {
val memoryModule = MemoryModuleType(Optional.of(codec))
memories[id] = memoryModule
return memoryModule
}
fun <U> register(id: String): MemoryModuleType<U> {
val memoryModule = MemoryModuleType<U>(Optional.empty())
memories[id] = memoryModule
return memoryModule
}
}
@@ -1,28 +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
import com.cobblemon.mod.common.entity.pokemon.ai.sensors.DrowsySensor
import java.util.function.Supplier
import net.minecraft.entity.Entity
import net.minecraft.entity.ai.brain.sensor.Sensor
import net.minecraft.entity.ai.brain.sensor.SensorType
object CobblemonSensors {
val sensors = mutableMapOf<String, SensorType<*>>()
// val NPC_BATTLING = register("npc_battling", ::NPCBattlingSensor)
val POKEMON_DROWSY = register("pokemon_drowsy", ::DrowsySensor)
fun <E : Entity, U : Sensor<E>> register(id: String, supplier: Supplier<U>): SensorType<U> {
val sensor = SensorType(supplier)
sensors[id] = sensor
return sensor
}
}
@@ -122,13 +122,18 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
val FOSSIL_MACHINE_UNPROTECTED = this.create("fossil_machine.unprotected")
@JvmField
val COIN_POUCH_BREAK = this.create("coin_pouch.break")
val RELIC_COIN_SACK_BREAK = this.create("relic_coin_sack.break")
@JvmField
val COIN_POUCH_HIT = this.create("coin_pouch.hit")
val RELIC_COIN_SACK_HIT = this.create("relic_coin_sack.hit")
@JvmField
val COIN_POUCH_STEP = this.create("coin_pouch.step")
val RELIC_COIN_SACK_STEP = this.create("relic_coin_sack.step")
@JvmField
val COIN_POUCH_PLACE = this.create("coin_pouch.place")
val RELIC_COIN_SACK_PLACE = this.create("relic_coin_sack.place")
@JvmField
val RELIC_COIN_POUCH_BREAK = this.create("relic_coin_pouch.break")
@JvmField
val RELIC_COIN_POUCH_PLACE = this.create("relic_coin_pouch.place")
@JvmField
val TUMBLESTONE_BREAK = this.create("tumblestone.break")
@JvmField
@@ -189,13 +194,22 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
val GILDED_CHEST_PLACE = this.create("gilded_chest.place")
@JvmField
val COIN_POUCH_SOUNDS = BlockSoundGroup(1f, 1f,
COIN_POUCH_BREAK,
COIN_POUCH_STEP,
COIN_POUCH_PLACE,
COIN_POUCH_HIT,
COIN_POUCH_STEP
val RELIC_COIN_SACK_SOUNDS = BlockSoundGroup(1f, 1f,
RELIC_COIN_SACK_BREAK,
RELIC_COIN_SACK_STEP,
RELIC_COIN_SACK_PLACE,
RELIC_COIN_SACK_HIT,
RELIC_COIN_SACK_STEP
)
@JvmField
val RELIC_COIN_POUCH_SOUNDS = BlockSoundGroup(1f, 1f,
RELIC_COIN_POUCH_BREAK,
RELIC_COIN_SACK_STEP,
RELIC_COIN_POUCH_PLACE,
RELIC_COIN_SACK_HIT,
RELIC_COIN_SACK_STEP
)
@JvmField
val IMPACT_NORMAL = this.create("impact.normal")
@JvmField
@@ -226,7 +226,7 @@ open class PokemonBattle(
val facedFainted = opponentPokemon.facedOpponents.contains(faintedPokemon)
val pokemon = opponentPokemon.effectedPokemon
if (facedFainted) {
pokemon.evolutions.forEach { evolution ->
pokemon.lockedEvolutions.forEach { evolution ->
evolution.requirements.filterIsInstance<DefeatRequirement>().forEach { defeatRequirement ->
if (defeatRequirement.target.matches(faintedPokemon.effectedPokemon)) {
val progress = pokemon.evolutionProxy.current().progressFirstOrCreate({ it is DefeatEvolutionProgress && it.currentProgress().target == defeatRequirement.target }) { DefeatEvolutionProgress() }
@@ -78,6 +78,8 @@ object CobblemonEvents {
val POKE_BALL_CAPTURE_CALCULATED = EventObservable<PokeBallCaptureCalculatedEvent>()
@JvmField
val POKEMON_CAPTURED = EventObservable<PokemonCapturedEvent>()
@JvmField
val FOSSIL_REVIVED = EventObservable<FossilRevivedEvent>()
// @JvmField
// val EGG_HATCH = EventObservable<HatchEggEvent>()
@JvmField
@@ -0,0 +1,17 @@
/*
* 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.events.pokemon
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.server.network.ServerPlayerEntity
data class FossilRevivedEvent (
val pokemon: Pokemon,
val player: ServerPlayerEntity?
)
@@ -52,21 +52,24 @@ abstract class MultiblockBlock(properties: Settings) : BlockWithEntity(propertie
if(hand == Hand.OFF_HAND) {
return ActionResult.SUCCESS
}
val entity = world.getBlockEntity(pos) as MultiblockEntity?
if (entity?.multiblockStructure != null) {
return entity.multiblockStructure!!.onUse(state, world, pos, player, hand, hit)
if (!world.isClient) {
val entity = world.getBlockEntity(pos) as MultiblockEntity?
if (entity?.multiblockStructure != null) {
return entity.multiblockStructure!!.onUse(state, world, pos, player, hand, hit)
}
}
return super.onUse(state, world, pos, player, hand, hit)
}
override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity?) {
super.onBreak(world, pos, state, player)
if (!world.isClient) {
val entity = world.getBlockEntity(pos)
if (entity is MultiblockEntity && entity.multiblockStructure != null) {
entity.multiblockStructure!!.onBreak(world, pos, state, player)
}
entity?.markRemoved()
}
super.onBreak(world, pos, state, player)
}
override fun createBlockEntity(pos: BlockPos, state: BlockState): BlockEntity? {
@@ -78,6 +81,7 @@ abstract class MultiblockBlock(properties: Settings) : BlockWithEntity(propertie
return BlockRenderType.MODEL
}
//This is done so a block picked with NBT doesnt absolutely DESTROY multiblocks
override fun getPickStack(world: BlockView, pos: BlockPos, state: BlockState): ItemStack {
val blockEntity = world.getBlockEntity(pos) as? MultiblockEntity ?: return ItemStack.EMPTY
return if (blockEntity.multiblockStructure == null) super.getPickStack(world, pos, state) else ItemStack.EMPTY
@@ -153,7 +153,7 @@ interface Evolution : EvolutionLike {
pokemon.getOwnerPlayer()?.sendMessage(lang("experience.learned_move", pokemon.getDisplayName(), move.displayName))
}
// we want to instantly tick for example you might only evolve your Bulbasaur at level 34 so Venusaur should be immediately available
pokemon.evolutions.filterIsInstance<PassiveEvolution>().forEach { evolution -> evolution.attemptEvolution(pokemon) }
pokemon.lockedEvolutions.filterIsInstance<PassiveEvolution>().forEach { evolution -> evolution.attemptEvolution(pokemon) }
pokemon.getOwnerPlayer()?.playSound(CobblemonSounds.EVOLVING, SoundCategory.NEUTRAL, 1F, 1F)
CobblemonEvents.EVOLUTION_COMPLETE.post(EvolutionCompleteEvent(pokemon, this))
}
@@ -78,7 +78,7 @@ abstract class SpawningCondition<T : SpawningContext> {
return false
} else if (ctx.position.z < minZ.orMin() || ctx.position.z > maxZ.orMax()) {
return false
} else if (dimensions != null && dimensions!!.isNotEmpty() && ctx.world.dimension.effects !in dimensions!!) {
} else if (dimensions != null && dimensions!!.isNotEmpty() && ctx.world.dimensionKey.value !in dimensions!!) {
return false
} else if (moonPhase != null && ctx.moonPhase !in moonPhase!!) {
return false
@@ -34,15 +34,19 @@ abstract class SpawnAction<R>(
/**
* Runs the spawn action and processes any non-null result.
*/
open fun complete(): Boolean {
open fun complete(): R? {
if (future.isDone) {
return null
}
ctx.influences.forEach { it.affectAction(this) }
val result = run()
return if (result != null) {
if (result != null) {
future.complete(result)
true
} else {
future.completeExceptionally(Exception("Nothing was spawned."))
false
}
return result
}
}
@@ -124,7 +124,7 @@ open class PlayerPartyStore(
}
// Passive evolutions
pokemon.evolutions.filterIsInstance<PassiveEvolution>().forEach { it.attemptEvolution(pokemon) }
pokemon.lockedEvolutions.filterIsInstance<PassiveEvolution>().forEach { it.attemptEvolution(pokemon) }
val removeList = mutableListOf<Evolution>()
pokemon.evolutionProxy.server().forEach {
if (!it.test(pokemon) && it is LevelUpEvolution && !it.permanent)
@@ -99,7 +99,7 @@ open class PCStore(
this.lockedSize = lockNewSize
if (boxes.size > newSize) {
// reduce
val slicedBoxes = boxes.slice(boxes.size until newSize)
val slicedBoxes = boxes.slice(newSize until boxes.size)
boxes.removeAll(slicedBoxes)
slicedBoxes.flatMap { it.asIterable() }.forEach(overflowHandler)
} else {
@@ -15,21 +15,5 @@ package com.cobblemon.mod.common.battles.dispatch
* @since July 31st, 2022
*/
class UntilDispatch(val condition: () -> Boolean) : DispatchResult {
var afterAction: (() -> Unit) = {}
override fun canProceed(): Boolean {
val shouldContinue = condition()
if (shouldContinue) {
afterAction()
}
return shouldContinue
}
fun andThen(action: () -> Unit): UntilDispatch {
val old = afterAction
afterAction = {
old()
action()
}
return this
}
override fun canProceed() = condition()
}
@@ -54,8 +54,8 @@ class DamageInstruction(
if (recoiling) {
battlePokemon.effectedPokemon.let { pokemon ->
if (RecoilEvolutionProgress.supports(pokemon)) {
val newPercentage = privateMessage.argumentAt(1)?.split("/")?.getOrNull(0)?.toIntOrNull() ?: 0
val newHealth = (pokemon.hp * (newPercentage / 100.0)).roundToInt()
val healthStr = privateMessage.argumentAt(1) ?: throw UnsupportedOperationException("Cant get recoil string")
val newHealth = "([0-9]+).*".toRegex().find(healthStr)?.groups?.get(1)?.value?.toIntOrNull() ?: throw UnsupportedOperationException("Cant get recoil string")
val difference = pokemon.currentHealth - newHealth
if (difference > 0) {
val progress = pokemon.evolutionProxy.current().progressFirstOrCreate({ it is RecoilEvolutionProgress }) { RecoilEvolutionProgress() }
@@ -10,10 +10,10 @@ package com.cobblemon.mod.common.battles.interpreter.instructions
import com.bedrockk.molang.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
import com.cobblemon.mod.common.api.battles.interpreter.Effect
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunction
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
import com.cobblemon.mod.common.api.moves.Moves
@@ -66,11 +66,6 @@ class MoveInstruction(
val pokemonName = userPokemon.getName()
ShowdownInterpreter.lastCauser[battle.battleId] = message
val targetPokemonEntity = targetPokemon?.entity
if (targetPokemonEntity != null) {
userPokemon.entity?.brain?.remember(CobblemonMemories.TARGETED_BATTLE_POKEMON, targetPokemonEntity.uuid)
}
userPokemon.effectedPokemon.let { pokemon ->
if (UseMoveEvolutionProgress.supports(pokemon, move)) {
val progress = pokemon.evolutionProxy.current().progressFirstOrCreate({ it is UseMoveEvolutionProgress && it.currentProgress().move == move }) { UseMoveEvolutionProgress() }
@@ -130,11 +125,7 @@ class MoveInstruction(
this.future = actionEffect.run(context)
holds = context.holds // Reference so future things can check on this action effect's holds
future.thenApply { holds.clear() }
return@dispatch UntilDispatch { "effects" !in holds }.andThen {
val userPokemonId = userPokemon.entity?.uuid ?: return@andThen
val targets = hurtTargets.mapNotNull { it.entity }
userPokemonId.let { id -> targets.forEach { it.brain.remember(CobblemonMemories.TARGETED_BATTLE_POKEMON, id) } }
}
return@dispatch UntilDispatch { "effects" !in holds }
}
}
}
@@ -38,6 +38,7 @@ import net.minecraft.util.shape.VoxelShapes
import net.minecraft.world.BlockView
import net.minecraft.world.World
import net.minecraft.world.WorldAccess
import net.minecraft.world.WorldEvents
import net.minecraft.world.WorldView
@@ -72,10 +73,12 @@ class RestorationTankBlock(properties: Settings) : MultiblockBlock(properties),
override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity?) {
super.onBreak(world, pos, state, player)
val otherPart = world.getBlockState(getPositionOfOtherPart(state, pos))
if (otherPart.block is RestorationTankBlock) {
world.setBlockState(getPositionOfOtherPart(state, pos), Blocks.AIR.defaultState, 35)
world.syncWorldEvent(player, 2001, getPositionOfOtherPart(state, pos), getRawIdFromState(otherPart))
if (!world.isClient) {
val otherPart = world.getBlockState(getPositionOfOtherPart(state, pos))
if (otherPart.block is RestorationTankBlock) {
world.setBlockState(getPositionOfOtherPart(state, pos), Blocks.AIR.defaultState, Block.NOTIFY_ALL)
world.syncWorldEvent(player, WorldEvents.BLOCK_BROKEN, getPositionOfOtherPart(state, pos), getRawIdFromState(otherPart))
}
}
}
@@ -87,9 +90,9 @@ class RestorationTankBlock(properties: Settings) : MultiblockBlock(properties),
itemStack: ItemStack?
) {
//Place the full block before we call to super to validate the multiblock
world.setBlockState(pos.up(), state.with(PART, TankPart.TOP) as BlockState, 3)
world.setBlockState(pos.up(), state.with(PART, TankPart.TOP) as BlockState, Block.NOTIFY_ALL)
world.updateNeighbors(pos, Blocks.AIR)
state.updateNeighbors(world, pos, 3)
state.updateNeighbors(world, pos, Block.NOTIFY_ALL)
super.onPlaced(world, pos, state, placer, itemStack)
}
@@ -100,7 +103,7 @@ class RestorationTankBlock(properties: Settings) : MultiblockBlock(properties),
val tankBottomPos = pos.down()
val tankBottomState = world.getBlockState(tankBottomPos)
if(tankBottomState.block.equals(CobblemonBlocks.RESTORATION_TANK.asBlock()) && tankBottomState.get(PART) == TankPart.BOTTOM) {
return super.onUse(tankBottomState, world, tankBottomPos, player, hand, hit)
return onUse(tankBottomState, world, tankBottomPos, player, hand, hit)
}
}
return super.onUse(state, world, pos, player, hand, hit)
@@ -0,0 +1,51 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.block
import com.cobblemon.mod.common.api.text.red
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.block.entity.StadiumBlockEntity
import net.minecraft.block.BlockState
import net.minecraft.block.BlockWithEntity
import net.minecraft.block.entity.BlockEntity
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.ActionResult
import net.minecraft.util.Hand
import net.minecraft.util.hit.BlockHitResult
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
class StadiumBlock(properties: Settings): BlockWithEntity(properties) {
override fun createBlockEntity(blockPos: BlockPos?, blockState: BlockState?): BlockEntity = StadiumBlockEntity(blockPos, blockState)
@Deprecated("Deprecated in Java")
override fun onUse(
blockState: BlockState,
world: World,
blockPos: BlockPos,
player: PlayerEntity,
interactionHand: Hand,
blockHitResult: BlockHitResult
): ActionResult {
if (player !is ServerPlayerEntity) return ActionResult.SUCCESS
val blockEntity = world.getBlockEntity(blockPos)
if (blockEntity !is StadiumBlockEntity) return ActionResult.SUCCESS
val message = "Stadium Pos: " + blockEntity.pos +
"\nPlayer 1 Pos: " + blockEntity.getPlayer1Pos() +
"\nPoke 1 Pos: " + blockEntity.getPoke1Pos() +
"\nPlayer 2 Pos: " + blockEntity.getPlayer2Pos() +
"\nPoke 2 Pos: " + blockEntity.getPoke2Pos()
player.sendMessage(text(message).red())
return ActionResult.SUCCESS
}
}
@@ -27,6 +27,7 @@ import net.minecraft.item.ItemPlacementContext
import net.minecraft.item.ItemStack
import net.minecraft.screen.ScreenHandler
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.server.world.ServerWorld
import net.minecraft.sound.SoundCategory
import net.minecraft.state.StateManager
import net.minecraft.state.property.BooleanProperty
@@ -37,6 +38,7 @@ import net.minecraft.util.*
import net.minecraft.util.hit.BlockHitResult
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction
import net.minecraft.util.math.random.Random
import net.minecraft.util.shape.VoxelShape
import net.minecraft.util.shape.VoxelShapes
import net.minecraft.world.BlockView
@@ -125,11 +127,13 @@ class GildedChestBlock(settings: Settings, val type: Type = Type.RED) : BlockWit
fun isFake() = (type == Type.FAKE)
override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity) {
if (isFake()) {
if (player is ServerPlayerEntity) {
if (!world.isClient) {
if (isFake() && (player is ServerPlayerEntity)) {
spawnPokemon(world, pos, state, player)
}
world.setBlockState(pos, if (state.fluidState.isOf(Fluids.WATER)) Blocks.WATER.defaultState else Blocks.AIR.defaultState)
val bEntity = world.getBlockEntity(pos) as? GildedChestBlockEntity
bEntity?.markRemoved()
} else super.onBreak(world, pos, state, player)
}
@@ -197,9 +201,11 @@ class GildedChestBlock(settings: Settings, val type: Type = Type.RED) : BlockWit
newState: BlockState,
moved: Boolean
) {
if (!state.isOf(newState.block)) {
val chest = world.getBlockEntity(pos) as GildedChestBlockEntity
ItemScatterer.spawn(world, pos, chest.inventoryContents)
if (!state.isOf(newState.block) && !world.isClient) {
val chest = world.getBlockEntity(pos) as? GildedChestBlockEntity
chest?.let {
ItemScatterer.spawn(world, pos, chest.inventoryContents)
}
}
}
@@ -261,4 +267,14 @@ class GildedChestBlock(settings: Settings, val type: Type = Type.RED) : BlockWit
}
}
override fun scheduledTick(
state: BlockState?,
world: ServerWorld?,
pos: BlockPos?,
random: Random?
) {
val blockEntity = world?.getBlockEntity(pos) as? GildedChestBlockEntity ?: return
blockEntity.onScheduledTick()
}
}
@@ -29,11 +29,17 @@ class FossilAnalyzerBlockEntity(
class FossilAnalyzerInventory(val analyzerEntity: FossilAnalyzerBlockEntity) : SidedInventory {
override fun clear() {
TODO("Not yet implemented")
if(analyzerEntity.multiblockStructure != null && analyzerEntity.multiblockStructure is FossilMultiblockStructure) {
val fossilMultiblockStructure = analyzerEntity.multiblockStructure as FossilMultiblockStructure
fossilMultiblockStructure.fossilInventory.clear()
}
}
override fun size(): Int {
TODO("Not yet implemented")
if (analyzerEntity.multiblockStructure != null) {
return 3
}
return 0
}
override fun isEmpty(): Boolean {
@@ -41,19 +47,34 @@ class FossilAnalyzerBlockEntity(
}
override fun getStack(slot: Int): ItemStack {
if (analyzerEntity.multiblockStructure != null && analyzerEntity.multiblockStructure is FossilMultiblockStructure) {
val fossilMultiblockStructure = analyzerEntity.multiblockStructure as FossilMultiblockStructure
if (fossilMultiblockStructure.fossilInventory.size > slot) {
return fossilMultiblockStructure.fossilInventory[slot]
}
}
return ItemStack.EMPTY
}
//Unimplemented since no extract
override fun removeStack(slot: Int, amount: Int): ItemStack {
return ItemStack.EMPTY
return removeStack(slot)
}
override fun removeStack(slot: Int): ItemStack {
// if(analyzerEntity.multiblockStructure is FossilMultiblockStructure) {
// val fossilMultiblockStructure = analyzerEntity.multiblockStructure as FossilMultiblockStructure
// if (fossilMultiblockStructure.fossilInventory.size > slot) {
// val itemStack = fossilMultiblockStructure.fossilInventory.removeAt(slot)
// markDirty()
// return itemStack
// }
// }
return ItemStack.EMPTY
}
override fun setStack(slot: Int, stack: ItemStack) {
if (analyzerEntity.multiblockStructure != null) {
if (analyzerEntity.multiblockStructure != null && analyzerEntity.multiblockStructure is FossilMultiblockStructure) {
val struct = analyzerEntity.multiblockStructure as FossilMultiblockStructure
analyzerEntity.world?.let {
struct.insertFossil(stack, it)
@@ -72,7 +93,10 @@ class FossilAnalyzerBlockEntity(
}
override fun getAvailableSlots(side: Direction?): IntArray {
return IntArray(1)
if(analyzerEntity.multiblockStructure != null && analyzerEntity.multiblockStructure is FossilMultiblockStructure) {
return intArrayOf(0,1,2)
}
return IntArray(0)
}
override fun canInsert(slot: Int, stack: ItemStack?, dir: Direction?): Boolean {
@@ -87,8 +111,8 @@ class FossilAnalyzerBlockEntity(
}
override fun canExtract(slot: Int, stack: ItemStack?, dir: Direction?): Boolean {
// return analyzerEntity.multiblockStructure != null && analyzerEntity.multiblockStructure is FossilMultiblockStructure && dir == Direction.DOWN
return false
}
}
}
@@ -20,6 +20,7 @@ import net.minecraft.entity.player.PlayerEntity
import net.minecraft.entity.player.PlayerInventory
import net.minecraft.inventory.DoubleInventory
import net.minecraft.inventory.Inventories
import net.minecraft.inventory.Inventory
import net.minecraft.inventory.SidedInventory
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NbtCompound
@@ -58,9 +59,7 @@ class GildedChestBlockEntity(pos: BlockPos, state: BlockState, val type: Type =
override fun isPlayerViewing(player: PlayerEntity): Boolean {
if (player.currentScreenHandler is GenericContainerScreenHandler) {
val inventory = (player.currentScreenHandler as GenericContainerScreenHandler).inventory
return inventory === this@GildedChestBlockEntity || inventory is DoubleInventory && inventory.isPart(
this@GildedChestBlockEntity
)
return inventory === this@GildedChestBlockEntity
}
return false
}
@@ -99,8 +98,6 @@ class GildedChestBlockEntity(pos: BlockPos, state: BlockState, val type: Type =
return dir == Direction.DOWN
}
override fun canPlayerUse(player: PlayerEntity) = !player.isSpectator
override fun getInvStackList(): DefaultedList<ItemStack> = inventoryContents
override fun setInvStackList(list: DefaultedList<ItemStack>) {
@@ -164,4 +161,10 @@ class GildedChestBlockEntity(pos: BlockPos, state: BlockState, val type: Type =
Inventories.readNbt(nbt, inventoryContents)
}
}
fun onScheduledTick() {
if (!this.removed) {
stateManager.updateViewerCount(this.getWorld(), this.getPos(), this.cachedState)
}
}
}
@@ -0,0 +1,25 @@
package com.cobblemon.mod.common.block.entity
import com.cobblemon.mod.common.CobblemonBlockEntities
import net.minecraft.block.BlockState
import net.minecraft.block.entity.BlockEntity
import net.minecraft.util.math.BlockPos
class StadiumBlockEntity(blockPos: BlockPos?, blockState: BlockState?): BlockEntity(CobblemonBlockEntities.STADIUM, blockPos, blockState) {
fun getPlayer1Pos(): BlockPos? {
return pos.add(5, 0, 10)
}
fun getPlayer2Pos(): BlockPos? {
return pos.add(5, 0, -10)
}
fun getPoke1Pos(): BlockPos? {
return pos.add(5, 0, 5)
}
fun getPoke2Pos(): BlockPos? {
return pos.add(5, 0, -5)
}
}
@@ -11,6 +11,8 @@ package com.cobblemon.mod.common.block.multiblock
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.advancement.CobblemonCriteria
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.pokemon.FossilRevivedEvent
import com.cobblemon.mod.common.api.fossil.Fossil
import com.cobblemon.mod.common.api.fossil.Fossils
import com.cobblemon.mod.common.api.fossil.NaturalMaterials
@@ -113,8 +115,6 @@ class FossilMultiblockStructure (
return ActionResult.FAIL
}
val ballType = (stack.item as PokeBallItem).pokeBall
if (!player.isCreative) {
stack?.decrement(1)
@@ -125,6 +125,7 @@ class FossilMultiblockStructure (
this.fossilState.growthState = "Taken"
player.playSound(CobblemonSounds.FOSSIL_MACHINE_RETRIEVE_POKEMON, SoundCategory.BLOCKS, 1.0F, 1.0F)
CobblemonCriteria.RESURRECT_POKEMON.trigger(player, createdPokemon!!)
CobblemonEvents.FOSSIL_REVIVED.post(FossilRevivedEvent(createdPokemon!!, player))
// Turn the monitor off
val monitorState = world.getBlockState(monitorPos)
@@ -220,6 +221,7 @@ class FossilMultiblockStructure (
entity.setPosition(fixedPosition.toCenterPos().subtract(0.0, 0.5, 0.0))
// TODO: Find a correct way to set the new entity's Yaw rotation. (Face away from the machine)
if (world.spawnEntity(entity)) {
CobblemonEvents.FOSSIL_REVIVED.post(FossilRevivedEvent(pokemon, null))
return true
} else {
Cobblemon.LOGGER.warn("Couldn't spawn resurrected Pokémon for some reason")
@@ -14,6 +14,7 @@ import com.bedrockk.molang.runtime.value.MoValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunctions
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import net.minecraft.client.MinecraftClient
import net.minecraft.client.sound.PositionedSoundInstance
@@ -31,6 +32,13 @@ object ClientMoLangFunctions {
MinecraftClient.getInstance().soundManager.play(PositionedSoundInstance.master(soundEvent, pitch))
}
},
"is_time" to java.util.function.Function { params ->
val time = (MinecraftClient.getInstance().world?.timeOfDay ?: 0) % 24000
val min = params.getInt(0)
val max = params.getInt(1)
time in min..max
},
"say" to java.util.function.Function { params -> MinecraftClient.getInstance().player?.sendMessage(params.getString(0).text()) ?: Unit },
)
fun MoLangRuntime.setupClient(): MoLangRuntime {
@@ -8,25 +8,15 @@
package com.cobblemon.mod.common.client
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.*
import com.cobblemon.mod.common.Cobblemon.LOGGER
import com.cobblemon.mod.common.api.berry.Berries
import com.cobblemon.mod.common.CobblemonBlockEntities
import com.cobblemon.mod.common.CobblemonBlocks
import com.cobblemon.mod.common.CobblemonClientImplementation
import com.cobblemon.mod.common.CobblemonEntities
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.scheduling.ClientTaskTracker
import com.cobblemon.mod.common.api.text.gray
import com.cobblemon.mod.common.client.battle.ClientBattle
import com.cobblemon.mod.common.client.gui.PartyOverlay
import com.cobblemon.mod.common.client.gui.battle.BattleOverlay
import com.cobblemon.mod.common.client.particle.BedrockParticleEffectRepository
import com.cobblemon.mod.common.client.render.block.BerryBlockRenderer
import com.cobblemon.mod.common.client.render.block.FossilAnalyzerRenderer
import com.cobblemon.mod.common.client.render.block.RestorationTankRenderer
import com.cobblemon.mod.common.client.render.block.GildedChestBlockRenderer
import com.cobblemon.mod.common.client.render.block.HealingMachineRenderer
import com.cobblemon.mod.common.client.render.block.*
import com.cobblemon.mod.common.client.render.boat.CobblemonBoatRenderer
import com.cobblemon.mod.common.client.render.generic.GenericBedrockRenderer
@@ -34,10 +24,7 @@ import com.cobblemon.mod.common.client.render.item.CobblemonBuiltinItemRendererR
import com.cobblemon.mod.common.client.render.item.PokemonItemRenderer
import com.cobblemon.mod.common.client.render.layer.PokemonOnShoulderRenderer
import com.cobblemon.mod.common.client.render.models.blockbench.bedrock.animation.BedrockAnimationRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.BerryModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.BlockEntityModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokeBallModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokemonModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.*
import com.cobblemon.mod.common.client.render.pokeball.PokeBallRenderer
import com.cobblemon.mod.common.client.render.pokemon.PokemonRenderer
import com.cobblemon.mod.common.client.sound.battle.BattleMusicController
@@ -47,9 +34,6 @@ import com.cobblemon.mod.common.client.trade.ClientTrade
import com.cobblemon.mod.common.data.CobblemonDataProvider
import com.cobblemon.mod.common.entity.boat.CobblemonBoatType
import com.cobblemon.mod.common.item.PokeBallItem
import com.cobblemon.mod.common.client.render.models.blockbench.repository.FossilModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.GenericBedrockEntityModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.MiscModelRepository
import com.cobblemon.mod.common.platform.events.PlatformEvents
import com.cobblemon.mod.common.util.DataKeys
import com.cobblemon.mod.common.util.asTranslated
@@ -221,7 +205,8 @@ object CobblemonClient {
CobblemonBlocks.LARGE_BUDDING_SKY_TUMBLESTONE,
CobblemonBlocks.SKY_TUMBLESTONE_CLUSTER,
CobblemonBlocks.GIMMIGHOUL_CHEST,
CobblemonBlocks.DISPLAY_CASE
CobblemonBlocks.DISPLAY_CASE,
CobblemonBlocks.STADIUM
)
this.createBoatModelLayers()
@@ -272,6 +272,9 @@ class PokemonClientDelegate : PoseableEntityState<PokemonEntity>(), PokemonSideD
},
"weight" to java.util.function.Function {
return@Function DoubleValue(currentEntity.pokemon.species.weight.toDouble())
},
"friendship" to java.util.function.Function {
return@Function DoubleValue(currentEntity.pokemon.friendship.toDouble())
}
))
}
@@ -20,7 +20,10 @@ import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFram
import com.cobblemon.mod.common.client.render.models.blockbench.quirk.SimpleQuirk
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.normalizeToArray
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.resolveObject
import com.cobblemon.mod.common.util.singularToPluralList
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import com.google.gson.JsonPrimitive
@@ -34,6 +37,8 @@ class JsonPose<T : Entity>(model: PoseableEntityModel<T>, json: JsonObject) {
it.environment.getQueryStruct().addFunctions(model.functions.functions)
}
val condition: ExpressionLike = json.singularToPluralList("condition").get("condition")?.normalizeToArray()?.map { it.asString }?.asExpressionLike() ?: "true".asExpressionLike()
val poseName = json.get("poseName")?.asString ?: "pose"
val poseTypes = (json.get("poseTypes")?.asJsonArray?.map { name ->
PoseType.values().find { it.name.lowercase() == name.asString.lowercase() }
@@ -81,8 +86,9 @@ class JsonPose<T : Entity>(model: PoseableEntityModel<T>, json: JsonObject) {
}
json as JsonObject
json.singularToPluralList("animation")
val animations: (state: PoseableEntityState<T>) -> List<StatefulAnimation<T, *>> = { _ ->
(json.get("animations")?.asJsonArray ?: JsonArray()).map { animJson ->
(json.get("animations")?.normalizeToArray()?.asJsonArray ?: JsonArray()).map { animJson ->
try {
val expr = animJson.asString.asExpressionLike()
runtime.resolveObject(expr).obj as StatefulAnimation<T, *>
@@ -97,10 +103,11 @@ class JsonPose<T : Entity>(model: PoseableEntityModel<T>, json: JsonObject) {
val loopTimes = json.get("loopTimes")?.asInt ?: 1
val minSeconds = json.get("minSecondsBetweenOccurrences")?.asFloat ?: 8F
val maxSeconds = json.get("maxSecondsBetweenOccurrences")?.asFloat ?: 30F
val condition = json.get("condition")?.asString?.asExpressionLike() ?: "true".asExpressionLike()
model.quirkMultiple(
secondsBetweenOccurrences = minSeconds to maxSeconds,
condition = { true },
condition = { it.runtime.resolveBoolean(condition) },
loopTimes = 1..loopTimes,
animations = animations
)
@@ -46,6 +46,7 @@ import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.getDoubleOrNull
import com.cobblemon.mod.common.util.getStringOrNull
import com.cobblemon.mod.common.util.plus
import com.cobblemon.mod.common.util.resolveBoolean
import net.minecraft.client.model.ModelPart
import net.minecraft.client.render.OverlayTexture
import net.minecraft.client.render.RenderLayer
@@ -878,6 +879,18 @@ abstract class PoseableEntityModel<T : Entity>(
animations = { listOf(animation(it)) }
)
fun quirkMoLangCondition(
secondsBetweenOccurrences: Pair<Float, Float> = 8F to 30F,
loopTimes: IntRange = 1..1,
conditionExpression: ExpressionLike = "true".asExpressionLike(),
animation: (state: PoseableEntityState<T>) -> StatefulAnimation<T, *>
) = SimpleQuirk<T>(
secondsBetweenOccurrences = secondsBetweenOccurrences,
loopTimes = loopTimes,
condition = { it.runtime.resolveBoolean(conditionExpression) },
animations = { listOf(animation(it)) }
)
fun quirkMultiple(
secondsBetweenOccurrences: Pair<Float, Float> = 8F to 30F,
loopTimes: IntRange = 1..1,
@@ -78,7 +78,7 @@ abstract class PoseableEntityState<T : Entity> : Schedulable {
"anim_time" to java.util.function.Function { return@Function reusableAnimTime.also { it.value = animationSeconds.toDouble() } },
"pose_type" to java.util.function.Function { return@Function StringValue((getEntity() as Poseable).getCurrentPoseType().name) },
"pose" to java.util.function.Function { _ -> return@Function StringValue(currentPose ?: "") },
"say" to java.util.function.Function { params -> MinecraftClient.getInstance().player?.sendMessage(params.getString(0).text()) ?: Unit },
"has_entity" to java.util.function.Function { _ -> return@Function DoubleValue(getEntity() != null) },
"sound" to java.util.function.Function { params ->
val entity = getEntity() ?: return@Function Unit
if (params.get<MoValue>(0) !is StringValue) {
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
import com.cobblemon.mod.common.client.render.models.blockbench.JsonPose
import com.cobblemon.mod.common.client.render.models.blockbench.JsonPoseableEntityModel
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityState
@@ -24,6 +25,7 @@ import com.cobblemon.mod.common.util.isDusk
import com.cobblemon.mod.common.util.isStandingOnRedSand
import com.cobblemon.mod.common.util.isStandingOnSand
import com.cobblemon.mod.common.util.isStandingOnSandOrRedSand
import com.cobblemon.mod.common.util.resolveBoolean
import com.google.gson.ExclusionStrategy
import com.google.gson.FieldAttributes
import com.google.gson.GsonBuilder
@@ -84,30 +86,12 @@ class JsonPokemonPoseableModel(override val rootPart: Bone) : PokemonPoseableMod
override val head: Bone by lazy { headJoint?.let { getPart(it) } ?: rootPart }
@SerializedName("portraitScale")
private val _portraitScale: Float? = null
@SerializedName("portraitTranslation")
private val _portraitTranslation: Vec3d? = null
@SerializedName("profileScale")
private val _profileScale: Float? = null
@SerializedName("profileTranslation")
private val _profileTranslation: Vec3d? = null
//Some weirdness going on here, vars have to be initialized, gson doesn't like multiple fields with the same name
@Transient
//Idk, works fine with Blastoise
override var portraitScale = 1F
get() = _portraitScale ?: 1F
@Transient
override var portraitTranslation = Vec3d.ZERO
get() = _portraitTranslation ?: Vec3d(0.0, 0.0, 0.0)
@Transient
override var profileScale = 1F
get() = _profileScale ?: 1F
@Transient
override var profileTranslation = Vec3d.ZERO
get() = _profileTranslation ?: Vec3d(0.0, 0.0, 0.0)
val faint: Supplier<StatefulAnimation<PokemonEntity, ModelFrame>>? = null
@@ -192,6 +176,8 @@ class JsonPokemonPoseableModel(override val rootPart: Bone) : PokemonPoseableMod
conditionsList.add { mustBeDusk == it.isDusk() }
}
conditionsList.add { (it.delegate as PokemonClientDelegate).runtime.resolveBoolean(pose.condition) }
val poseCondition: ((PokemonEntity) -> Boolean)? = if (conditionsList.isEmpty()) null else conditionsList.reduce { acc, function -> { acc(it) && function(it) } }
return Pose(
@@ -8,13 +8,14 @@
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
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.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
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.ModelPart
import net.minecraft.util.math.Vec3d
@@ -56,7 +57,7 @@ class KabutopsModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Bipe
standing = registerPose(
poseName = "standing",
poseTypes = UI_POSES + PoseType.STAND,
poseTypes = UI_POSES + STATIONARY_POSES,
condition = { !it.isBattling },
quirks = arrayOf(blink),
idleAnimations = arrayOf(
@@ -67,7 +68,7 @@ class KabutopsModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Bipe
walk = registerPose(
poseName = "walk",
poseType = PoseType.WALK,
poseTypes = MOVING_POSES,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
singleBoneLook(),
@@ -8,21 +8,14 @@
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
import com.cobblemon.mod.common.client.render.models.blockbench.animation.WingFlapIdleAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.createTransformation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BiWingedFrame
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.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.ModelPartTransformation
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.parabolaFunction
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.sineFunction
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.PoseType.Companion.SHOULDER_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
import com.cobblemon.mod.common.util.math.geometry.toRadians
import net.minecraft.client.model.ModelPart
import net.minecraft.util.math.Vec3d
@@ -66,7 +59,7 @@ class PidgeyModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
stand = registerPose(
poseName = "standing",
poseTypes = SHOULDER_POSES + UI_POSES + PoseType.STANDING_POSES,
poseTypes = SHOULDER_POSES + UI_POSES + PoseType.STATIONARY_POSES - PoseType.HOVER,
transformTicks = 10,
transformedParts = arrayOf(
wingClosedLeft.createTransformation().withVisibility(visibility = true),
@@ -25,8 +25,8 @@ class PetililHisuiBiasModel (root: ModelPart) : PokemonPoseableModel(), HeadedFr
val leaf_left = getPart("leaf_left_rotation")
val leaf_right = getPart("leaf_right_rotation")
override var portraitScale = 1.75F
override var portraitTranslation = Vec3d(0.01, -0.39, 0.0)
override var portraitScale = 1.52F
override var portraitTranslation = Vec3d(0.1, -0.25, 0.0)
override var profileScale = 0.8F
override var profileTranslation = Vec3d(0.0, 0.5, 0.0)
@@ -22,8 +22,8 @@ class PetililModel (root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
override val rootPart = root.registerChildWithAllChildren("petilil")
override val head = getPart("head")
override var portraitScale = 2.0F
override var portraitTranslation = Vec3d(-0.3, -1.2, 0.0)
override var portraitScale = 1.52F
override var portraitTranslation = Vec3d(0.1, -0.25, 0.0)
override var profileScale = 0.8F
override var profileTranslation = Vec3d(0.0, 0.5, 0.0)
@@ -28,8 +28,8 @@ class DubwoolModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Quadr
override val foreRightLeg = getPart("leg_front_right")
override val hindLeftLeg = getPart("leg_back_left")
override val hindRightLeg = getPart("leg_back_right")
val wool = getPart("wool")
val neckWool = getPart("neck_wool")
val wool = getPart("wool_shearable")
val neckWool = getPart("neck_wool_shearable")
override var portraitScale = 3.1F
override var portraitTranslation = Vec3d(-1.2, -0.7, 0.0)
@@ -28,7 +28,7 @@ class WoolooModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Quadru
override val foreRightLeg = getPart("leg_front_right")
override val hindLeftLeg = getPart("leg_back_left")
override val hindRightLeg = getPart("leg_back_right")
val wool = getPart("wool")
val wool = getPart("wool_shearable")
override var portraitScale = 3.1F
override var portraitTranslation = Vec3d(-0.85, -1.8, 0.0)
@@ -1,35 +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.entity.ai
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.ai.brain.MemoryModuleType
import net.minecraft.entity.ai.brain.task.SingleTickTask
import net.minecraft.entity.ai.brain.task.TaskRunnable
import net.minecraft.entity.ai.brain.task.TaskTriggerer
object AttackAngryAtTask {
fun create(): SingleTickTask<LivingEntity> = TaskTriggerer.task {
it.group(
it.queryMemoryValue(MemoryModuleType.ANGRY_AT),
it.queryMemoryAbsent(MemoryModuleType.ATTACK_TARGET)
).apply(it) { angryAt, attackTarget ->
TaskRunnable { world, entity, _ ->
val angryAt = it.getValue(angryAt)
val livingEntity = world.getEntity(angryAt) as? LivingEntity
if (livingEntity != null) {
entity.brain.remember(MemoryModuleType.ATTACK_TARGET, livingEntity)
} else {
entity.brain.forget(MemoryModuleType.ANGRY_AT)
}
return@TaskRunnable true
}
}
}
}
@@ -1,37 +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.entity.ai
import net.minecraft.entity.ai.FuzzyTargeting
import net.minecraft.entity.ai.brain.BlockPosLookTarget
import net.minecraft.entity.ai.brain.MemoryModuleType
import net.minecraft.entity.ai.brain.WalkTarget
import net.minecraft.entity.ai.brain.task.SingleTickTask
import net.minecraft.entity.ai.brain.task.TaskRunnable
import net.minecraft.entity.ai.brain.task.TaskTriggerer
import net.minecraft.entity.mob.PathAwareEntity
object ChooseLandWanderTargetTask {
fun create(chance: Int, horizontalRange: Int, verticalRange: Int, walkSpeed: Float, completionRange: Int): SingleTickTask<PathAwareEntity> {
return TaskTriggerer.task {
it.group(
it.queryMemoryAbsent(MemoryModuleType.WALK_TARGET),
it.queryMemoryOptional(MemoryModuleType.LOOK_TARGET)
).apply(it) { walkTarget, lookTarget ->
TaskRunnable { world, entity, time ->
if (world.random.nextInt(chance) != 0) return@TaskRunnable false
val targetVec = FuzzyTargeting.find(entity, horizontalRange, verticalRange) ?: return@TaskRunnable false
walkTarget.remember(WalkTarget(targetVec, walkSpeed, completionRange))
lookTarget.remember(BlockPosLookTarget(targetVec.add(0.0, 1.5, 0.0)))
return@TaskRunnable true
}
}
}
}
}
@@ -1,155 +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.entity.ai
import net.minecraft.entity.ai.NoPenaltyTargeting
import net.minecraft.entity.ai.brain.EntityLookTarget
import net.minecraft.entity.ai.brain.MemoryModuleState
import net.minecraft.entity.ai.brain.MemoryModuleType
import net.minecraft.entity.ai.brain.WalkTarget
import net.minecraft.entity.ai.brain.task.MultiTickTask
import net.minecraft.entity.ai.pathing.Path
import net.minecraft.entity.mob.PathAwareEntity
import net.minecraft.server.world.ServerWorld
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Vec3d
class FollowWalkTargetTask(
minRunTime: Int = 150,
maxRunTime: Int = 250
) : MultiTickTask<PathAwareEntity>(
mapOf(
MemoryModuleType.WALK_TARGET to MemoryModuleState.VALUE_PRESENT,
MemoryModuleType.PATH to MemoryModuleState.VALUE_ABSENT,
MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE to MemoryModuleState.REGISTERED
), minRunTime, maxRunTime
) {
private var pathUpdateCountdownTicks = 0
private var path: Path? = null
private var lookTargetPos: BlockPos? = null
private var speed = 0f
override fun shouldRun(arg: ServerWorld, arg2: PathAwareEntity): Boolean {
if (this.pathUpdateCountdownTicks > 0) {
--this.pathUpdateCountdownTicks
return false
} else {
val brain = arg2.brain
val walkTarget = brain.getOptionalRegisteredMemory(MemoryModuleType.WALK_TARGET).get()
val hasReached = this.hasReached(arg2, walkTarget)
if (!hasReached && this.hasFinishedPath(arg2, walkTarget, arg.time)) {
this.lookTargetPos = walkTarget.lookTarget.blockPos
return true
} else {
brain.forget(MemoryModuleType.WALK_TARGET)
if (hasReached) {
brain.forget(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE)
}
return false
}
}
}
override fun shouldKeepRunning(arg: ServerWorld, arg2: PathAwareEntity, l: Long): Boolean {
if (this.path != null && this.lookTargetPos != null) {
val optional = arg2.brain.getOptionalRegisteredMemory(MemoryModuleType.WALK_TARGET)
val isTargetSpectator = optional.map(::isTargetSpectator).orElse(false)
val entityNavigation = arg2.navigation
return !entityNavigation.isIdle && optional.isPresent && !this.hasReached(arg2, optional.get()) && !isTargetSpectator
} else {
return false
}
}
override fun finishRunning(world: ServerWorld, entity: PathAwareEntity, l: Long) {
val walkTarget = entity.brain.getOptionalRegisteredMemory(MemoryModuleType.WALK_TARGET).orElse(null)
if (walkTarget != null && !this.hasReached(entity, walkTarget) && entity.navigation.isNearPathStartPos) {
this.pathUpdateCountdownTicks = world.getRandom().nextInt(40)
}
entity.navigation.stop()
entity.brain.forget(MemoryModuleType.WALK_TARGET)
entity.brain.forget(MemoryModuleType.PATH)
this.path = null
}
override fun run(arg: ServerWorld, entity: PathAwareEntity, time: Long) {
entity.brain.remember(MemoryModuleType.PATH, this.path)
entity.navigation.startMovingAlong(this.path, speed.toDouble())
}
override fun keepRunning(world: ServerWorld, entity: PathAwareEntity, l: Long) {
val path = entity.navigation.currentPath
val brain = entity.brain
if (this.path !== path) {
this.path = path
brain.remember(MemoryModuleType.PATH, path)
}
if (path != null && lookTargetPos != null) {
val walkTarget = brain.getOptionalRegisteredMemory(MemoryModuleType.WALK_TARGET).get()
if (walkTarget.lookTarget.blockPos.getSquaredDistance(lookTargetPos) > 4.0 && hasFinishedPath(entity, walkTarget, world.time)) {
lookTargetPos = walkTarget.lookTarget.blockPos
run(world, entity, l)
}
}
}
private fun hasFinishedPath(entity: PathAwareEntity, walkTarget: WalkTarget, time: Long): Boolean {
val blockPos = walkTarget.lookTarget.blockPos
this.path = entity.navigation.findPathTo(blockPos, 0)
this.speed = walkTarget.speed
val brain = entity.brain
if (hasReached(entity, walkTarget)) {
brain.forget(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE)
} else {
val bl = this.path != null && path!!.reachesTarget()
if (bl) {
brain.forget(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE)
} else if (!brain.hasMemoryModule(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE)) {
brain.remember(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, time)
}
if (this.path != null) {
return true
}
val vec3d = NoPenaltyTargeting.findTo(
entity,
10,
7,
Vec3d.ofBottomCenter(blockPos),
1.5707963705062866
)
if (vec3d != null) {
this.path = entity.navigation.findPathTo(vec3d.x, vec3d.y, vec3d.z, 0)
return this.path != null
}
}
return false
}
private fun hasReached(entity: PathAwareEntity, walkTarget: WalkTarget): Boolean {
return walkTarget.lookTarget.blockPos.getManhattanDistance(entity.blockPos) <= walkTarget.completionRange
}
companion object {
private fun isTargetSpectator(target: WalkTarget): Boolean {
val lookTarget = target.lookTarget
return if (lookTarget is EntityLookTarget) {
lookTarget.entity.isSpectator
} else {
false
}
}
}
}
@@ -1,43 +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.entity.ai
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.toDF
import com.mojang.datafixers.util.Pair
import net.minecraft.entity.ai.brain.MemoryModuleState
import net.minecraft.entity.ai.brain.MemoryModuleType
import net.tslat.smartbrainlib.api.core.behaviour.ExtendedBehaviour
import net.tslat.smartbrainlib.util.BrainUtils
//todo: make sure it's the same behaviour
class GetAngryAtAttackerTask : ExtendedBehaviour<PokemonEntity>() {
init {
whenStarting { entity ->
val hurtByEntity = requireNotNull(
BrainUtils.getMemory(entity, MemoryModuleType.HURT_BY_ENTITY)
)
val angryAt = BrainUtils.getMemory(entity, MemoryModuleType.ANGRY_AT)
if (angryAt != null && angryAt == hurtByEntity.uuid) {
return@whenStarting
}
entity.brain.remember(MemoryModuleType.ANGRY_AT, hurtByEntity.uuid)
}
}
override fun getMemoryRequirements(): List<Pair<MemoryModuleType<*>, MemoryModuleState>> {
//todo: not sure what state these should be
return listOf(
MemoryModuleType.HURT_BY_ENTITY toDF MemoryModuleState.REGISTERED,
MemoryModuleType.ANGRY_AT toDF MemoryModuleState.REGISTERED,
)
}
}
@@ -1,37 +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.entity.ai
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.ai.brain.MemoryModuleType
import net.minecraft.entity.ai.brain.WalkTarget
import net.minecraft.entity.ai.brain.task.SingleTickTask
import net.minecraft.entity.ai.brain.task.TaskRunnable
import net.minecraft.entity.ai.brain.task.TaskTriggerer
object MoveToAttackTargetTask {
fun create(): SingleTickTask<LivingEntity> = TaskTriggerer.task {
it.group(
it.queryMemoryValue(MemoryModuleType.ATTACK_TARGET),
it.queryMemoryOptional(MemoryModuleType.WALK_TARGET)
).apply(it) { attackTarget, walkTarget ->
TaskRunnable { world, entity, _ ->
val attackTarget = it.getValue(attackTarget)
val position = attackTarget.pos
val walkTarget = it.getOptionalValue(walkTarget).orElse(null)
if (walkTarget == null || walkTarget.lookTarget.pos.squaredDistanceTo(position) > 2.0) {
entity.brain.remember(MemoryModuleType.WALK_TARGET, WalkTarget(attackTarget, 0.5F, 1))
true
} else {
false
}
}
}
}
}
@@ -1,30 +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.entity.ai
import net.minecraft.entity.ai.brain.task.MultiTickTask
import net.minecraft.entity.mob.PathAwareEntity
import net.minecraft.registry.tag.FluidTags
import net.minecraft.server.world.ServerWorld
class StayAfloatTask(private val chance: Float = 0F) : MultiTickTask<PathAwareEntity>(emptyMap()) {
override fun shouldRun(world: ServerWorld, entity: PathAwareEntity): Boolean {
return entity.isTouchingWater && entity.getFluidHeight(FluidTags.WATER) > entity.swimHeight || entity.isInLava
}
override fun shouldKeepRunning(world: ServerWorld, entity: PathAwareEntity, l: Long): Boolean {
return this.shouldRun(world, entity)
}
override fun keepRunning(world: ServerWorld, entity: PathAwareEntity, l: Long) {
if (entity.random.nextFloat() < this.chance) {
entity.jumpControl.setActive()
}
}
}
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common.entity.pokemon
import com.cobblemon.mod.common.*
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.api.drop.DropTable
import com.cobblemon.mod.common.api.entity.Despawner
import com.cobblemon.mod.common.api.events.CobblemonEvents
@@ -21,7 +20,11 @@ import com.cobblemon.mod.common.api.events.pokemon.ShoulderMountEvent
import com.cobblemon.mod.common.api.interaction.PokemonEntityInteraction
import com.cobblemon.mod.common.api.net.serializers.PoseTypeDataSerializer
import com.cobblemon.mod.common.api.net.serializers.StringSetDataSerializer
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.pokemon.feature.ChoiceSpeciesFeatureProvider
import com.cobblemon.mod.common.api.pokemon.feature.FlagSpeciesFeature
import com.cobblemon.mod.common.api.pokemon.feature.StringSpeciesFeature
import com.cobblemon.mod.common.api.pokemon.status.Statuses
import com.cobblemon.mod.common.api.reactive.ObservableSubscription
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.api.scheduling.Schedulable
@@ -35,14 +38,11 @@ import com.cobblemon.mod.common.block.entity.PokemonPastureBlockEntity
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.Poseable
import com.cobblemon.mod.common.entity.ai.*
import com.cobblemon.mod.common.entity.generic.GenericBedrockEntity
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
import com.cobblemon.mod.common.entity.pokemon.ai.PokemonMoveControl
import com.cobblemon.mod.common.entity.pokemon.ai.PokemonNavigation
import com.cobblemon.mod.common.entity.pokemon.ai.goals.*
import com.cobblemon.mod.common.entity.pokemon.ai.sensors.DrowsySensor
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.*
import com.cobblemon.mod.common.entity.pokemon.effects.EffectTracker
import com.cobblemon.mod.common.entity.pokemon.effects.IllusionEffect
import com.cobblemon.mod.common.net.messages.client.animation.PlayPoseableAnimationPacket
@@ -61,22 +61,14 @@ import com.cobblemon.mod.common.pokemon.evolution.variants.ItemInteractionEvolut
import com.cobblemon.mod.common.pokemon.misc.GimmighoulStashHandler
import com.cobblemon.mod.common.util.*
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
import com.google.common.collect.ImmutableList
import com.mojang.serialization.Dynamic
import java.util.EnumSet
import java.util.Optional
import java.util.UUID
import java.util.concurrent.CompletableFuture
import net.minecraft.entity.*
import net.minecraft.entity.ai.brain.Activity
import net.minecraft.entity.ai.brain.Brain
import net.minecraft.entity.ai.brain.MemoryModuleType
import net.minecraft.entity.ai.brain.sensor.NearestLivingEntitiesSensor
import net.minecraft.entity.ai.brain.sensor.NearestPlayersSensor
import net.minecraft.entity.ai.brain.sensor.Sensor
import net.minecraft.entity.ai.brain.sensor.SensorType
import net.minecraft.entity.ai.brain.task.ForgetAngryAtTargetTask
import net.minecraft.entity.ai.brain.task.LookAroundTask
import net.minecraft.entity.ai.brain.task.LookAtMobTask
import net.minecraft.entity.ai.brain.task.MultiTickTask
import net.minecraft.entity.ai.brain.task.Task
import net.minecraft.entity.ai.control.MoveControl
import net.minecraft.entity.ai.goal.EatGrassGoal
import net.minecraft.entity.ai.goal.Goal
import net.minecraft.entity.ai.pathing.PathNodeType
import net.minecraft.entity.attribute.DefaultAttributeContainer
import net.minecraft.entity.attribute.EntityAttributes
@@ -91,6 +83,7 @@ import net.minecraft.entity.passive.PassiveEntity
import net.minecraft.entity.passive.TameableShoulderEntity
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.fluid.FluidState
import net.minecraft.item.DyeItem
import net.minecraft.item.ItemStack
import net.minecraft.item.ItemUsage
import net.minecraft.item.Items
@@ -111,33 +104,25 @@ import net.minecraft.sound.SoundEvents
import net.minecraft.text.Text
import net.minecraft.text.TextContent
import net.minecraft.util.ActionResult
import net.minecraft.util.Colors
import net.minecraft.util.DyeColor
import net.minecraft.util.Hand
import net.minecraft.util.Identifier
import net.minecraft.util.Util
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Box
import net.minecraft.util.math.Vec3d
import net.minecraft.world.EntityView
import net.minecraft.world.LightType
import net.minecraft.world.World
import net.minecraft.world.event.GameEvent
import net.tslat.smartbrainlib.api.SmartBrainOwner
import net.tslat.smartbrainlib.api.core.BrainActivityGroup
import net.tslat.smartbrainlib.api.core.SmartBrainProvider
import net.tslat.smartbrainlib.api.core.sensor.ExtendedSensor
import net.tslat.smartbrainlib.api.core.sensor.vanilla.HurtBySensor
import net.tslat.smartbrainlib.api.core.sensor.vanilla.NearbyLivingEntitySensor
import net.tslat.smartbrainlib.api.core.sensor.vanilla.NearbyPlayersSensor
import java.util.*
import java.util.concurrent.CompletableFuture
import kotlin.math.ceil
@Suppress("unused")
open class PokemonEntity(
world: World,
pokemon: Pokemon = Pokemon(),
type: EntityType<out PokemonEntity> = CobblemonEntities.POKEMON,
) : TameableShoulderEntity(type, world), Poseable, Shearable, Schedulable, SmartBrainOwner<PokemonEntity> {
) : TameableShoulderEntity(type, world), Poseable, Shearable, Schedulable {
companion object {
@JvmStatic val SPECIES = DataTracker.registerData(PokemonEntity::class.java, TrackedDataHandlerRegistry.STRING)
@JvmStatic val NICKNAME = DataTracker.registerData(PokemonEntity::class.java, TrackedDataHandlerRegistry.TEXT_COMPONENT)
@@ -156,45 +141,13 @@ open class PokemonEntity(
@JvmStatic val UNBATTLEABLE = DataTracker.registerData(PokemonEntity::class.java, TrackedDataHandlerRegistry.BOOLEAN)
@JvmStatic val COUNTS_TOWARDS_SPAWN_CAP = DataTracker.registerData(PokemonEntity::class.java, TrackedDataHandlerRegistry.BOOLEAN)
@JvmStatic val SPAWN_DIRECTION = DataTracker.registerData(PokemonEntity::class.java, TrackedDataHandlerRegistry.FLOAT)
@JvmStatic val FRIENDSHIP = DataTracker.registerData(PokemonEntity::class.java, TrackedDataHandlerRegistry.INTEGER)
const val BATTLE_LOCK = "battle"
fun createAttributes(): DefaultAttributeContainer.Builder = LivingEntity.createLivingAttributes()
.add(EntityAttributes.GENERIC_FOLLOW_RANGE)
.add(EntityAttributes.GENERIC_ATTACK_KNOCKBACK)
val SENSORS: Collection<SensorType<out Sensor<in PokemonEntity>>> = listOf(
SensorType.NEAREST_LIVING_ENTITIES,
SensorType.HURT_BY,
SensorType.NEAREST_PLAYERS,
CobblemonSensors.POKEMON_DROWSY
// CobblemonSensors.BATTLING_POKEMON,
// CobblemonSensors.NPC_BATTLING
)
val MEMORY_MODULES: List<MemoryModuleType<*>> = ImmutableList.of(
MemoryModuleType.LOOK_TARGET,
MemoryModuleType.WALK_TARGET,
MemoryModuleType.ATTACK_TARGET,
MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE,
MemoryModuleType.PATH,
MemoryModuleType.IS_PANICKING,
MemoryModuleType.VISIBLE_MOBS,
CobblemonMemories.POKEMON_FLYING,
// CobblemonMemories.NPC_BATTLING,
// CobblemonMemories.BATTLING_POKEMON,
MemoryModuleType.HURT_BY,
MemoryModuleType.HURT_BY_ENTITY,
MemoryModuleType.NEAREST_VISIBLE_PLAYER,
MemoryModuleType.ANGRY_AT,
MemoryModuleType.ATTACK_COOLING_DOWN,
CobblemonMemories.POKEMON_DROWSY,
CobblemonMemories.POKEMON_BATTLE,
MemoryModuleType.HOME,
CobblemonMemories.REST_PATH_COOLDOWN,
CobblemonMemories.TARGETED_BATTLE_POKEMON
)
}
val removalObservable = SimpleObservable<RemovalReason?>()
/** A list of observable subscriptions related to this entity that need to be cleaned up when the entity is removed. */
@@ -214,7 +167,6 @@ open class PokemonEntity(
stepHeight = behaviour.moving.stepHeight
// We need to update this value every time the Pokémon changes, other eye height related things will be dynamic.
this.updateEyeHeight()
setupTasks()
}
var despawner: Despawner<PokemonEntity> = Cobblemon.bestSpawner.defaultPokemonDespawner
@@ -233,10 +185,10 @@ open class PokemonEntity(
var battleId: UUID?
get() = dataTracker.get(BATTLE_ID).orElse(null)
set(value) = dataTracker.set(BATTLE_ID, Optional.ofNullable(value))
val battle: PokemonBattle?
get() = battleId?.let { BattleRegistry.getBattle(it) }
val isBattling: Boolean
get() = dataTracker.get(BATTLE_ID).isPresent
val friendship: Int
get() = dataTracker.get(FRIENDSHIP)
var drops: DropTable? = null
@@ -283,7 +235,6 @@ open class PokemonEntity(
delegate.initialize(this)
delegate.changePokemon(pokemon)
calculateDimensions()
setupTasks()
}
override fun initDataTracker() {
@@ -303,7 +254,9 @@ open class PokemonEntity(
dataTracker.startTracking(LABEL_LEVEL, 1)
dataTracker.startTracking(HIDE_LABEL, false)
dataTracker.startTracking(UNBATTLEABLE, false)
dataTracker.startTracking(COUNTS_TOWARDS_SPAWN_CAP, true)
dataTracker.startTracking(SPAWN_DIRECTION, world.random.nextFloat() * 360F)
dataTracker.startTracking(FRIENDSHIP, 0)
}
override fun onTrackedDataSet(data: TrackedData<*>) {
@@ -327,10 +280,8 @@ open class PokemonEntity(
if (battleId != null) {
busyLocks.remove(BATTLE_LOCK) // Remove in case it's hopped across to another battle, don't want extra battle locks
busyLocks.add(BATTLE_LOCK)
brain.remember(CobblemonMemories.POKEMON_BATTLE, battleId)
} else {
busyLocks.remove(BATTLE_LOCK)
brain.forget(CobblemonMemories.POKEMON_BATTLE)
}
}
}
@@ -385,15 +336,25 @@ open class PokemonEntity(
this.tethering = null
this.pokemon.recall()
}
//This is so that pokemon in the pasture block are ALWAYS in sync with the pokemon box
//Before, pokemon entities in pastures would hold an old ref to a pokemon obj and changes to that would not appear to the underlying file
if (this.tethering != null) {
//Only for online players
if (world.getPlayerByUuid(ownerUuid) != null){
this.ownerUuid?.let {
val actualPokemon = Cobblemon.storage.getPC(it)[this.pokemon.uuid]
actualPokemon?.let {
if (it !== pokemon) {
pokemon = it
}
}
}
}
}
schedulingTracker.update(1/20F)
}
override fun mobTick() {
super.mobTick()
tickBrain(this)
}
fun setMoveControl(moveControl: MoveControl) {
this.moveControl = moveControl
}
@@ -591,131 +552,46 @@ open class PokemonEntity(
override fun getNavigation() = navigation as PokemonNavigation
override fun createNavigation(world: World) = PokemonNavigation(world, this)
@Suppress("KotlinConstantConditions")
// Brain.Profile is final and Kotlin error's, but this cast is safe.
override fun createBrainProfile() = SmartBrainProvider(this) as Brain.Profile<*>
override fun getSensors(): List<ExtendedSensor<PokemonEntity>> {
return listOf(
NearbyLivingEntitySensor(),
HurtBySensor(),
NearbyPlayersSensor(),
DrowsySensor()
)
}
override fun initGoals() {
super.initGoals()
@Suppress("SENSELESS_COMPARISON")
public override fun initGoals() {
// DO NOT REMOVE
// LivingEntity#getActiveEyeHeight is called in the constructor of Entity
// Pokémon param is not available yet
if (this.pokemon == null) {
return
}
moveControl = PokemonMoveControl(this)
}
override fun onFinishPathfinding() {
super.onFinishPathfinding()
(moveControl as PokemonMoveControl).stop()
}
override fun getCoreTasks(): BrainActivityGroup<PokemonEntity> {
val tasks: MutableList<MultiTickTask<in PokemonEntity>> = mutableListOf()
if (!pokemon.form.behaviour.moving.swim.canBreatheUnderwater) {
tasks.add(StayAfloatTask(0.8F))
}
tasks.add(GetAngryAtAttackerTask())
tasks.add(ForgetAngryAtTargetTask.create())
tasks.add(HandleBattleActivityGoal.create())
tasks.add(FollowWalkTargetTask())
return BrainActivityGroup.coreTasks(
tasks
)
}
fun getIdleTasks(): List<com.mojang.datafixers.util.Pair<Int, Task<in PokemonEntity>>> {
val tasks: MutableList<com.mojang.datafixers.util.Pair<Int, Task<in PokemonEntity>>> = mutableListOf()
if (pokemon.form.behaviour.moving.canLook) {
if (pokemon.form.behaviour.moving.looksAtEntities) {
tasks.add(0 toDF LookAtMobTask.create(15F))
goalSelector.clear { true }
goalSelector.add(0, PokemonInBattleMovementGoal(this, 10))
goalSelector.add(0, object : Goal() {
override fun canStart() = this@PokemonEntity.dataTracker.get(PHASING_TARGET_ID) != -1 || pokemon.status?.status == Statuses.SLEEP || dataTracker.get(DYING_EFFECTS_STARTED) || evolutionEntity != null
override fun shouldContinue(): Boolean {
if (pokemon.status?.status == Statuses.SLEEP && !canSleep() && !isBusy) {
return false
} else if (pokemon.status?.status == Statuses.SLEEP || isBusy) {
return true
}
return false
}
tasks.add(0 toDF LookAroundTask(45, 90))
override fun getControls() = EnumSet.allOf(Control::class.java)
})
goalSelector.add(1, PokemonBreatheAirGoal(this))
goalSelector.add(2, PokemonFloatToSurfaceGoal(this))
goalSelector.add(3, PokemonFollowOwnerGoal(this, 1.0, 8F, 2F, false))
goalSelector.add(4, PokemonMoveIntoFluidGoal(this))
goalSelector.add(5, SleepOnTrainerGoal(this))
goalSelector.add(5, WildRestGoal(this))
if (pokemon.getFeature<FlagSpeciesFeature>(DataKeys.HAS_BEEN_SHEARED) != null) {
goalSelector.add(5, EatGrassGoal(this))
}
tasks.add(0 toDF ChooseLandWanderTargetTask.create(pokemon.form.behaviour.moving.wanderChance, horizontalRange = 10, verticalRange = 5, walkSpeed = 0.33F, completionRange = 1))
tasks.add(0 toDF GoToSleepTask.create())
tasks.add(0 toDF FindRestingPlaceTask.create(16, 8))
tasks.add(0 toDF EatGrassTask())
tasks.add(0 toDF AttackAngryAtTask.create())
tasks.add(0 toDF MoveToAttackTargetTask.create())
tasks.add(0 toDF MoveToOwnerTask.create(completionRange = 4, maxDistance = 14F, teleportDistance = 24F))
return tasks
goalSelector.add(6, PokemonWanderAroundGoal(this))
goalSelector.add(7, PokemonLookAtEntityGoal(this, ServerPlayerEntity::class.java, 5F))
goalSelector.add(8, PokemonPointAtSpawnGoal(this))
}
fun getBattlingTasks(): List<com.mojang.datafixers.util.Pair<Int, Task<in PokemonEntity>>> {
val tasks: MutableList<com.mojang.datafixers.util.Pair<Int, Task<in PokemonEntity>>> = mutableListOf()
tasks.add(0 toDF LookAtTargetedBattlePokemonTask.create())
tasks.add(0 toDF LookAroundTask(Int.MAX_VALUE - 1, Int.MAX_VALUE - 1))
return tasks
}
fun getSleepingTasks(): List<com.mojang.datafixers.util.Pair<Int, Task<in PokemonEntity>>> {
val tasks: MutableList<com.mojang.datafixers.util.Pair<Int, Task<in PokemonEntity>>> = mutableListOf()
tasks.add(1 toDF WakeUpTask.create())
return tasks
}
fun setupTasks() {
val brain = this.getBrain()
brain.setTaskList(Activity.CORE, ImmutableList.copyOf(getCoreTasks()))
brain.setTaskList(Activity.IDLE, ImmutableList.copyOf(getIdleTasks()))
brain.setTaskList(CobblemonActivities.BATTLING_ACTIVITY, ImmutableList.copyOf(getBattlingTasks()))
brain.setTaskList(CobblemonActivities.POKEMON_SLEEPING_ACTIVITY, ImmutableList.copyOf(getSleepingTasks()))
brain.setCoreActivities(setOf(Activity.CORE))
brain.setDefaultActivity(Activity.IDLE)
brain.resetPossibleActivities()
}
//
// @Suppress("SENSELESS_COMPARISON")
// public override fun initGoals() {
// // DO NOT REMOVE
// // LivingEntity#getActiveEyeHeight is called in the constructor of Entity
// // Pokémon param is not available yet
// if (this.pokemon == null) {
// return
// }
// moveControl = PokemonMoveControl(this)
// goalSelector.clear { true }
// goalSelector.add(0, PokemonInBattleMovementGoal(this, 10))
// goalSelector.add(0, object : Goal() {
// override fun canStart() = this@PokemonEntity.dataTracker.get(PHASING_TARGET_ID) != -1 || pokemon.status?.status == Statuses.SLEEP || dataTracker.get(DYING_EFFECTS_STARTED) || evolutionEntity != null
// override fun shouldContinue(): Boolean {
// if (pokemon.status?.status == Statuses.SLEEP && !canSleep() && !isBusy) {
// return false
// } else if (pokemon.status?.status == Statuses.SLEEP || isBusy) {
// return true
// }
// return false
// }
// override fun getControls() = EnumSet.allOf(Control::class.java)
// })
//
// goalSelector.add(1, PokemonBreatheAirGoal(this))
// goalSelector.add(2, PokemonFloatToSurfaceGoal(this))
// goalSelector.add(3, PokemonFollowOwnerGoal(this, 1.0, 8F, 2F, false))
// goalSelector.add(4, PokemonMoveIntoFluidGoal(this))
// goalSelector.add(5, SleepOnTrainerGoal(this))
// goalSelector.add(5, WildRestGoal(this))
//
// if (pokemon.getFeature<FlagSpeciesFeature>(DataKeys.HAS_BEEN_SHEARED) != null) {
// goalSelector.add(5, EatGrassGoal(this))
// }
//
// goalSelector.add(6, PokemonWanderAroundGoal(this))
// goalSelector.add(7, PokemonLookAtEntityGoal(this, ServerPlayerEntity::class.java, 5F))
// goalSelector.add(8, PokemonPointAtSpawnGoal(this))
// }
fun canSleep(): Boolean {
val rest = behaviour.resting
val worldTime = (world.timeOfDay % 24000).toInt()
@@ -731,25 +607,6 @@ open class PokemonEntity(
(rest.biomes.isEmpty() || rest.biomes.any { it.fits(biome, this.world.registryManager.get(RegistryKeys.BIOME)) })
}
fun canSleepAt(pos: BlockPos): Boolean {
val rest = behaviour.resting
val light = world.getLightLevel(pos)
val blockState = world.getBlockState(pos)
val block = blockState.block
val biome = world.getBiome(pos).value()
val seesSky = world.isSkyVisible(pos.up())
val fits = true
val canStayAt = world.canEntityStayAt(pos, ceil(width).toInt(), ceil(height).toInt(), PositionType.LAND)
return light in rest.light &&
(rest.skyLight == null || world.lightingProvider.get(LightType.SKY).getLightLevel(pos) in rest.skyLight) &&
(rest.blocks.isEmpty() || rest.blocks.any { it.fits(block, this.world.registryManager.get(RegistryKeys.BLOCK)) }) &&
(rest.biomes.isEmpty() || rest.biomes.any { it.fits(biome, this.world.registryManager.get(RegistryKeys.BIOME)) }) &&
(rest.canSeeSky == null || rest.canSeeSky == seesSky) &&
fits &&
canStayAt
}
override fun createChild(level: ServerWorld, partner: PassiveEntity) = null
override fun isReadyToSitOnPlayer(): Boolean {
@@ -758,6 +615,7 @@ open class PokemonEntity(
override fun interactMob(player: PlayerEntity, hand: Hand) : ActionResult {
val itemStack = player.getStackInHand(hand)
val colorFeature = pokemon.getFeature<StringSpeciesFeature>(DataKeys.CAN_BE_COLORED)
if (itemStack.isOf(Items.SHEARS) && this.isShearable) {
this.sheared(SoundCategory.PLAYERS)
@@ -801,10 +659,7 @@ open class PokemonEntity(
} else if (pokemon.lastFlowerFed.isOf(Items.POPPY) || pokemon.lastFlowerFed.isOf(Items.TORCHFLOWER)) {
effect = StatusEffect.byRawId(16) // Night Vision
duration = 100 // 5 seconds
} else if (pokemon.lastFlowerFed.isOf(Items.PINK_TULIP) || pokemon.lastFlowerFed.isOf(Items.RED_TULIP) || pokemon.lastFlowerFed.isOf(
Items.WHITE_TULIP
) || pokemon.lastFlowerFed.isOf(Items.ORANGE_TULIP)
) {
} else if (pokemon.lastFlowerFed.isOf(Items.PINK_TULIP) || pokemon.lastFlowerFed.isOf(Items.RED_TULIP) || pokemon.lastFlowerFed.isOf(Items.WHITE_TULIP) || pokemon.lastFlowerFed.isOf(Items.ORANGE_TULIP)) {
effect = StatusEffect.byRawId(18) // Weakness
duration = 180 // 9 seconds
} else if (pokemon.lastFlowerFed.isOf(Items.WITHER_ROSE)) {
@@ -825,7 +680,8 @@ open class PokemonEntity(
// reset the flower fed state
pokemon.lastFlowerFed = ItemStack.EMPTY
return ActionResult.success(world.isClient)
} else {
}
else {
val mushroomStew = ItemUsage.exchangeStack(itemStack, player, Items.MUSHROOM_STEW.defaultStack)
player.setStackInHand(hand, mushroomStew)
return ActionResult.success(world.isClient)
@@ -865,6 +721,22 @@ open class PokemonEntity(
return ActionResult.SUCCESS
}
}
else if (itemStack.item is DyeItem && colorFeature != null) {
val item = itemStack.item as DyeItem
if (item.color.name.lowercase() != colorFeature.value.lowercase()) {
itemStack.decrement(1)
colorFeature.value = item.color.name.lowercase()
this.pokemon.markFeatureDirty(colorFeature)
this.pokemon.updateAspects()
}
}
else if (itemStack.item.equals(Items.WATER_BUCKET) && colorFeature != null) {
itemStack.decrement(1)
player.giveOrDropItemStack(Items.BUCKET.defaultStack)
colorFeature.value = ""
this.pokemon.markFeatureDirty(colorFeature)
this.pokemon.updateAspects()
}
if (hand == Hand.MAIN_HAND && player is ServerPlayerEntity && pokemon.getOwnerPlayer() == player) {
@@ -993,7 +865,7 @@ open class PokemonEntity(
// Check evolution item interaction
if (pokemon.getOwnerPlayer() == player) {
val context = ItemInteractionEvolution.ItemInteractionContext(stack, player.world)
pokemon.evolutions
pokemon.lockedEvolutions
.filterIsInstance<ItemInteractionEvolution>()
.forEach { evolution ->
if (evolution.attemptEvolution(pokemon, context)) {
@@ -1291,8 +1163,26 @@ open class PokemonEntity(
this.pokemon.markFeatureDirty(feature)
this.pokemon.updateAspects()
val i = this.random.nextInt(3) + 1
for (j in 0 until i) {
val itemEntity = this.dropItem(Items.WHITE_WOOL, 1) ?: return
for (j in 0 .. i) {
val color = this.pokemon.getFeature<StringSpeciesFeature>(DataKeys.CAN_BE_COLORED)?.value ?: "white"
val woolItem = when (color) {
"black" -> Items.BLACK_WOOL
"blue" -> Items.BLUE_WOOL
"brown" -> Items.BROWN_WOOL
"cyan" -> Items.CYAN_WOOL
"gray" -> Items.GRAY_WOOL
"green" -> Items.GREEN_WOOL
"light-blue" -> Items.LIGHT_BLUE_WOOL
"light-gray" -> Items.LIGHT_GRAY_WOOL
"lime" -> Items.LIME_WOOL
"magenta" -> Items.MAGENTA_WOOL
"orange" -> Items.ORANGE_WOOL
"purple" -> Items.PURPLE_WOOL
"red" -> Items.RED_WOOL
"yellow" -> Items.YELLOW_WOOL
else -> Items.WHITE_WOOL
}
val itemEntity = this.dropItem(woolItem, 1) ?: return
itemEntity.velocity = itemEntity.velocity.add(
((this.random.nextFloat() - this.random.nextFloat()) * 0.1f).toDouble(),
(this.random.nextFloat() * 0.05f).toDouble(),
@@ -1306,6 +1196,8 @@ open class PokemonEntity(
return !this.isBusy && !this.pokemon.isFainted() && !feature.enabled
}
override fun canUsePortals() = false
override fun setAir(air: Int) {
@@ -43,7 +43,7 @@ class PokemonServerDelegate : PokemonSideDelegate {
override fun changePokemon(pokemon: Pokemon) {
updatePathfindingPenalties(pokemon)
// entity.initGoals()
entity.initGoals()
updateMaxHealth()
}
@@ -92,10 +92,28 @@ class PokemonServerDelegate : PokemonSideDelegate {
speed = 0.1F
entity.despawner.beginTracking(this)
}
updateTrackedValues()
}
fun getBattle() = entity.battleId?.let(BattleRegistry::getBattle)
fun updateTrackedValues() {
val trackedSpecies = mock?.species ?: entity.pokemon.species.resourceIdentifier.toString()
val trackedNickname = mock?.nickname ?: entity.pokemon.nickname ?: Text.empty()
val trackedAspects = mock?.aspects ?: entity.pokemon.aspects
entity.dataTracker.set(PokemonEntity.SPECIES, trackedSpecies)
if (entity.dataTracker.get(PokemonEntity.NICKNAME) != trackedNickname) {
entity.dataTracker.set(PokemonEntity.NICKNAME, trackedNickname)
}
entity.dataTracker.set(PokemonEntity.ASPECTS, trackedAspects)
entity.dataTracker.set(PokemonEntity.LABEL_LEVEL, entity.pokemon.level)
entity.dataTracker.set(PokemonEntity.MOVING, entity.velocity.multiply(1.0, if (entity.isOnGround) 0.0 else 1.0, 1.0).length() > 0.005F)
entity.dataTracker.set(PokemonEntity.FRIENDSHIP, entity.pokemon.friendship)
updatePoseType()
}
override fun onTrackedDataSet(data: TrackedData<*>) {
super.onTrackedDataSet(data)
if (this::entity.isInitialized) {
@@ -162,19 +180,7 @@ class PokemonServerDelegate : PokemonSideDelegate {
entity.remove(Entity.RemovalReason.DISCARDED)
}
val trackedSpecies = mock?.species ?: entity.pokemon.species.resourceIdentifier.toString()
val trackedNickname = mock?.nickname ?: entity.pokemon.nickname ?: Text.empty()
val trackedAspects = mock?.aspects ?: entity.pokemon.aspects
entity.dataTracker.set(PokemonEntity.SPECIES, trackedSpecies)
if (entity.dataTracker.get(PokemonEntity.NICKNAME) != trackedNickname) {
entity.dataTracker.set(PokemonEntity.NICKNAME, trackedNickname)
}
entity.dataTracker.set(PokemonEntity.ASPECTS, trackedAspects)
entity.dataTracker.set(PokemonEntity.LABEL_LEVEL, entity.pokemon.level)
entity.dataTracker.set(PokemonEntity.MOVING, entity.velocity.multiply(1.0, if (entity.isOnGround) 0.0 else 1.0, 1.0).length() > 0.005F)
updatePoseType()
updateTrackedValues()
}
fun updatePoseType() {
@@ -34,7 +34,7 @@ class PokemonMoveControl(val pokemonEntity: PokemonEntity) : MoveControl(pokemon
}
override fun tick() {
if (pokemonEntity.isDead) {
if (pokemonEntity.pokemon.status?.status == Statuses.SLEEP || pokemonEntity.isDead) {
pokemonEntity.movementSpeed = 0F
pokemonEntity.upwardSpeed = 0F
return
@@ -47,7 +47,7 @@ class PokemonMoveControl(val pokemonEntity: PokemonEntity) : MoveControl(pokemon
behaviour.moving.swim.swimSpeed
} else {
behaviour.moving.walk.walkSpeed
} * 2.5F
}
val baseSpeed = entity.getAttributeValue(EntityAttributes.GENERIC_MOVEMENT_SPEED).toFloat() * this.speed.toFloat()
val adjustedSpeed = baseSpeed * mediumSpeed
@@ -203,10 +203,4 @@ class PokemonMoveControl(val pokemonEntity: PokemonEntity) : MoveControl(pokemon
}
return true
}
fun stop() {
state = State.WAIT
forwardMovement = 0.0f
sidewaysMovement = 0.0f
}
}
@@ -1,46 +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.entity.pokemon.ai.sensors
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.CobblemonSensors
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import net.minecraft.entity.ai.brain.MemoryModuleType
import net.minecraft.entity.ai.brain.sensor.SensorType
import net.minecraft.server.world.ServerWorld
import net.tslat.smartbrainlib.api.core.sensor.ExtendedSensor
/**
* Senses when the Pokémon is in a situation that would make it ready to sleep.
*
* @author Hiroku
* @since March 23rd, 2024
*/
class DrowsySensor : ExtendedSensor<PokemonEntity>() {
override fun memoriesUsed(): List<MemoryModuleType<*>> {
return listOf(
CobblemonMemories.POKEMON_DROWSY
)
}
override fun type(): SensorType<out ExtendedSensor<*>> {
return CobblemonSensors.POKEMON_DROWSY
}
override fun sense(world: ServerWorld, entity: PokemonEntity) {
val rest = entity.behaviour.resting
val isDrowsy = entity.brain.getOptionalRegisteredMemory(CobblemonMemories.POKEMON_DROWSY).orElse(false)
val shouldBeDrowsy = rest.canSleep && world.timeOfDay.toInt() in rest.times
if (!isDrowsy && shouldBeDrowsy) {
entity.brain.remember(CobblemonMemories.POKEMON_DROWSY, true)
} else if (isDrowsy && !shouldBeDrowsy) {
entity.brain.forget(CobblemonMemories.POKEMON_DROWSY)
}
}
}
@@ -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.entity.pokemon.ai.tasks
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.pokemon.feature.FlagSpeciesFeature
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.DataKeys
import com.google.common.collect.ImmutableMap
import net.minecraft.block.Block
import net.minecraft.block.Blocks
import net.minecraft.entity.ai.brain.MemoryModuleState
import net.minecraft.entity.ai.brain.MemoryModuleType
import net.minecraft.entity.ai.brain.task.MultiTickTask
import net.minecraft.predicate.block.BlockStatePredicate
import net.minecraft.server.world.ServerWorld
import net.minecraft.world.GameRules
/**
* The baa's eat the graa's
*
* @author Hiroku
* @since April 6th, 2024
*/
class EatGrassTask : MultiTickTask<PokemonEntity>(
ImmutableMap.of(
MemoryModuleType.ANGRY_AT, MemoryModuleState.VALUE_ABSENT,
MemoryModuleType.ATTACK_TARGET, MemoryModuleState.VALUE_ABSENT,
MemoryModuleType.WALK_TARGET, MemoryModuleState.VALUE_ABSENT,
CobblemonMemories.POKEMON_BATTLE, MemoryModuleState.VALUE_ABSENT
)
) {
val grassPredicate = BlockStatePredicate.forBlock(Blocks.GRASS)
var timer = -1
override fun shouldRun(world: ServerWorld, entity: PokemonEntity): Boolean {
if (entity.random.nextInt(500) != 0) {
return false
} else {
entity.pokemon.getFeature<FlagSpeciesFeature>(DataKeys.HAS_BEEN_SHEARED)?.enabled?.takeIf { it } ?: run {
return false
}
val blockPos = entity.blockPos
if (grassPredicate.test(world.getBlockState(blockPos)) ) {
return true
} else if (world.getBlockState(blockPos.down()).isOf(Blocks.GRASS_BLOCK)) {
return true
}
return false
}
}
override fun run(world: ServerWorld, entity: PokemonEntity, time: Long) {
timer = 40
world.sendEntityStatus(entity, 10.toByte())
}
override fun shouldKeepRunning(world: ServerWorld, entity: PokemonEntity, time: Long): Boolean {
timer--
if (timer < 0) {
val blockPos = entity.blockPos
if (grassPredicate.test(world.getBlockState(blockPos)) ) {
if (world.gameRules.getBoolean(GameRules.DO_MOB_GRIEFING)) {
world.breakBlock(blockPos, false)
}
entity.onEatingGrass()
} else if (world.getBlockState(blockPos.down()).isOf(Blocks.GRASS_BLOCK)) {
val blockPos2 = blockPos.down()
if (world.getBlockState(blockPos2).isOf(Blocks.GRASS_BLOCK)) {
if (world.gameRules.getBoolean(GameRules.DO_MOB_GRIEFING)) {
world.syncWorldEvent(2001, blockPos2, Block.getRawIdFromState(Blocks.GRASS_BLOCK.defaultState))
world.setBlockState(blockPos2, Blocks.DIRT.defaultState, 2)
}
entity.onEatingGrass()
}
}
return false
}
return true
}
}
@@ -1,53 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.entity.pokemon.ai.tasks
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.pokemon.status.Statuses
import com.cobblemon.mod.common.api.storage.party.PartyStore
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.getBlockPositions
import net.minecraft.entity.ai.brain.MemoryModuleType
import net.minecraft.entity.ai.brain.WalkTarget
import net.minecraft.entity.ai.brain.task.SingleTickTask
import net.minecraft.entity.ai.brain.task.TaskRunnable
import net.minecraft.entity.ai.brain.task.TaskTriggerer
import net.minecraft.util.math.Box
object FindRestingPlaceTask {
fun create(horizontalSearchDistance: Int, verticalSearchDistance: Int): SingleTickTask<PokemonEntity> {
return TaskTriggerer.task {
it.group(
it.queryMemoryAbsent(MemoryModuleType.ANGRY_AT),
it.queryMemoryAbsent(MemoryModuleType.ATTACK_TARGET),
it.queryMemoryAbsent(MemoryModuleType.WALK_TARGET),
it.queryMemoryAbsent(CobblemonMemories.POKEMON_BATTLE),
it.queryMemoryValue(CobblemonMemories.POKEMON_DROWSY),
it.queryMemoryAbsent(CobblemonMemories.REST_PATH_COOLDOWN)
).apply(it) { _, _, walkTarget, _, pokemonDrowsy, restPathCooldown ->
TaskRunnable { world, entity, _ ->
return@TaskRunnable if (it.getValue(pokemonDrowsy) && entity.pokemon.status?.status != Statuses.SLEEP && entity.pokemon.storeCoordinates.get()?.store !is PartyStore) {
entity.brain.remember(CobblemonMemories.REST_PATH_COOLDOWN, true, 40)
val position = entity.world
.getBlockPositions(Box.of(entity.pos, horizontalSearchDistance.toDouble(), verticalSearchDistance.toDouble(), horizontalSearchDistance.toDouble()))
.filter(entity::canSleepAt)
// .randomOrNull()
.minByOrNull { it.getSquaredDistance(entity.pos) }
if (position != null) {
walkTarget.remember(WalkTarget(position.down(), 0.3F, 1))
}
true
} else {
false
}
}
}
}
}
}
@@ -1,47 +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.entity.pokemon.ai.tasks
import com.cobblemon.mod.common.CobblemonActivities
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.pokemon.status.Statuses
import com.cobblemon.mod.common.api.storage.party.PartyStore
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.status.PersistentStatusContainer
import net.minecraft.entity.ai.brain.MemoryModuleType
import net.minecraft.entity.ai.brain.task.SingleTickTask
import net.minecraft.entity.ai.brain.task.TaskRunnable
import net.minecraft.entity.ai.brain.task.TaskTriggerer
object GoToSleepTask {
fun create(): SingleTickTask<PokemonEntity> {
return TaskTriggerer.task {
it.group(
it.queryMemoryAbsent(MemoryModuleType.ANGRY_AT),
it.queryMemoryAbsent(MemoryModuleType.ATTACK_TARGET),
it.queryMemoryAbsent(MemoryModuleType.WALK_TARGET),
it.queryMemoryAbsent(CobblemonMemories.POKEMON_BATTLE),
it.queryMemoryOptional(CobblemonMemories.POKEMON_DROWSY)
).apply(it) { _, _, _, _, pokemonDrowsy ->
TaskRunnable { world, entity, _ ->
val hasSleepStatus = entity.pokemon.status?.status === Statuses.SLEEP
if (entity.behaviour.resting.canSleep && ((it.getOptionalValue(pokemonDrowsy).orElse(false) && entity.canSleepAt(entity.blockPos.down())) || hasSleepStatus) && entity.pokemon.storeCoordinates.get()?.store !is PartyStore) {
if (!hasSleepStatus) {
entity.pokemon.status = PersistentStatusContainer(Statuses.SLEEP)
}
entity.brain.resetPossibleActivities(listOf(CobblemonActivities.POKEMON_SLEEPING_ACTIVITY))
return@TaskRunnable true
} else {
return@TaskRunnable false
}
}
}
}
}
}
@@ -1,53 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.entity.pokemon.ai.tasks
import com.cobblemon.mod.common.CobblemonActivities
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import net.minecraft.entity.ai.brain.Activity
import net.minecraft.entity.ai.brain.MemoryModuleType
import net.minecraft.entity.ai.brain.task.SingleTickTask
import net.minecraft.entity.ai.brain.task.TaskRunnable
import net.minecraft.entity.ai.brain.task.TaskTriggerer
/**
* Moves Pokémon in and out of the battling activity.
*
* @author Hiroku
* @since April 8th, 2024
*/
object HandleBattleActivityGoal {
fun create(): SingleTickTask<PokemonEntity> {
return TaskTriggerer.task {
it.group(
it.queryMemoryOptional(CobblemonMemories.POKEMON_BATTLE),
it.queryMemoryOptional(MemoryModuleType.WALK_TARGET),
it.queryMemoryOptional(MemoryModuleType.LOOK_TARGET),
).apply(it) { battle, walkTarget, lookTarget ->
TaskRunnable { world, entity, _ ->
val battleUUID = it.getOptionalValue(battle).orElse(null)
if (battleUUID != null && !entity.brain.hasActivity(CobblemonActivities.BATTLING_ACTIVITY)) {
entity.brain.resetPossibleActivities(listOf(CobblemonActivities.BATTLING_ACTIVITY))
entity.brain.forget(MemoryModuleType.WALK_TARGET)
entity.brain.forget(MemoryModuleType.LOOK_TARGET)
entity.navigation.stop()
return@TaskRunnable true
} else if (battleUUID == null && entity.brain.hasActivity(CobblemonActivities.BATTLING_ACTIVITY)) {
entity.brain.resetPossibleActivities(listOf(Activity.IDLE))
entity.brain.forget(MemoryModuleType.WALK_TARGET)
entity.brain.forget(MemoryModuleType.LOOK_TARGET)
return@TaskRunnable true
}
return@TaskRunnable false
}
}
}
}
}
@@ -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.entity.pokemon.ai.tasks
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import net.minecraft.entity.ai.brain.EntityLookTarget
import net.minecraft.entity.ai.brain.MemoryModuleType
import net.minecraft.entity.ai.brain.task.SingleTickTask
import net.minecraft.entity.ai.brain.task.TaskRunnable
import net.minecraft.entity.ai.brain.task.TaskTriggerer
/**
* Manages the look target of a Pokémon in battle.
*
* @author Hiroku
* @since April 8th, 2024
*/
object LookAtTargetedBattlePokemonTask {
fun create(): SingleTickTask<PokemonEntity> {
return TaskTriggerer.task {
it.group(
it.queryMemoryValue(CobblemonMemories.POKEMON_BATTLE),
it.queryMemoryOptional(CobblemonMemories.TARGETED_BATTLE_POKEMON),
it.queryMemoryOptional(MemoryModuleType.LOOK_TARGET),
).apply(it) { _, targetedBattlePokemon, lookTarget ->
TaskRunnable { world, entity, _ ->
val targeted = it.getOptionalValue(targetedBattlePokemon).orElse(null)
val targetedEntity = targeted?.let { world.getEntity(it) as? PokemonEntity }
val look = it.getOptionalValue(lookTarget).orElse(null) as? EntityLookTarget
if (targeted != null && targetedEntity == null) {
entity.brain.forget(CobblemonMemories.TARGETED_BATTLE_POKEMON)
return@TaskRunnable false
} else if (targetedEntity != null && look?.entity != targetedEntity) {
entity.brain.remember(MemoryModuleType.LOOK_TARGET, EntityLookTarget(targetedEntity, true))
return@TaskRunnable true
} else if (targetedEntity == null) {
val battle = entity.battle ?: return@TaskRunnable false
val nearestOpposingPokemon = battle.sides
.find { entity in it.actors.flatMap { it.pokemonList.map { it.entity } } }
?.getOppositeSide()?.actors
?.flatMap { it.pokemonList.mapNotNull { it.entity } }
?.minByOrNull { it.distanceTo(entity) }
if (nearestOpposingPokemon != null) {
entity.brain.remember(MemoryModuleType.LOOK_TARGET, EntityLookTarget(nearestOpposingPokemon, true))
return@TaskRunnable true
}
}
return@TaskRunnable false
}
}
}
}
}
@@ -1,96 +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.entity.pokemon.ai.tasks
import com.cobblemon.mod.common.api.storage.party.PartyStore
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import kotlin.math.abs
import net.minecraft.entity.Entity
import net.minecraft.entity.ai.brain.EntityLookTarget
import net.minecraft.entity.ai.brain.MemoryModuleType
import net.minecraft.entity.ai.brain.WalkTarget
import net.minecraft.entity.ai.brain.task.SingleTickTask
import net.minecraft.entity.ai.brain.task.TaskRunnable
import net.minecraft.entity.ai.brain.task.TaskTriggerer
import net.minecraft.entity.ai.pathing.LandPathNodeMaker
import net.minecraft.entity.ai.pathing.PathNodeType
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.random.Random
object MoveToOwnerTask {
fun create(completionRange: Int, maxDistance: Float, teleportDistance: Float): SingleTickTask<PokemonEntity> = TaskTriggerer.task {
it.group(
it.queryMemoryOptional(MemoryModuleType.WALK_TARGET),
it.queryMemoryAbsent(MemoryModuleType.ANGRY_AT)
).apply(it) { walkTarget, _ ->
TaskRunnable { _, entity, _ ->
val owner = entity.owner ?: return@TaskRunnable false
if (entity.pokemon.storeCoordinates.get()?.store !is PartyStore) {
return@TaskRunnable false
}
if (entity.distanceTo(owner) > teleportDistance) {
if (tryTeleport(entity, owner)) {
entity.brain.forget(MemoryModuleType.LOOK_TARGET)
entity.brain.forget(MemoryModuleType.WALK_TARGET)
}
return@TaskRunnable true
} else if (entity.distanceTo(owner) > maxDistance && it.getOptionalValue(walkTarget).isEmpty) {
entity.brain.remember(MemoryModuleType.LOOK_TARGET, EntityLookTarget(owner, true))
entity.brain.remember(MemoryModuleType.WALK_TARGET, WalkTarget(owner, 0.4F, completionRange))
return@TaskRunnable true
}
return@TaskRunnable false
}
}
}
private fun tryTeleport(entity: PokemonEntity, owner: Entity): Boolean {
val blockPos = owner.blockPos
for (i in 0..9) {
val j = this.getRandomInt(entity.random, -3, 3)
val k = this.getRandomInt(entity.random, -1, 1)
val l = this.getRandomInt(entity.random, -3, 3)
val succeeded = this.tryTeleportTo(entity, owner, blockPos.x + j, blockPos.y + k, blockPos.z + l)
if (succeeded) {
return true
}
}
return false
}
private fun tryTeleportTo(entity: PokemonEntity, owner: Entity, x: Int, y: Int, z: Int): Boolean {
if (abs(x.toDouble() - owner.x) < 2.0 && abs(z - owner.z) < 2.0) {
return false
} else if (!this.canTeleportTo(entity, BlockPos(x, y, z))) {
return false
} else {
entity.refreshPositionAndAngles(
x.toDouble() + 0.5, y.toDouble(), z.toDouble() + 0.5,
entity.yaw,
entity.pitch
)
entity.navigation.stop()
return true
}
}
private fun canTeleportTo(entity: PokemonEntity, pos: BlockPos): Boolean {
val pathNodeType = LandPathNodeMaker.getLandNodeType(entity.world, pos.mutableCopy())
if (pathNodeType != PathNodeType.WALKABLE) {
return false
} else {
val blockPos = pos.subtract(entity.blockPos)
return entity.world.isSpaceEmpty(entity, entity.boundingBox.offset(blockPos))
}
}
private fun getRandomInt(random: Random, min: Int, max: Int): Int {
return random.nextInt(max - min + 1) + min
}
}
@@ -1,38 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.entity.pokemon.ai.tasks
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.pokemon.status.Statuses
import com.cobblemon.mod.common.api.storage.party.PartyStore
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import net.minecraft.entity.ai.brain.task.SingleTickTask
import net.minecraft.entity.ai.brain.task.TaskRunnable
import net.minecraft.entity.ai.brain.task.TaskTriggerer
object WakeUpTask {
fun create(): SingleTickTask<PokemonEntity> {
return TaskTriggerer.task {
it.group(
it.queryMemoryAbsent(CobblemonMemories.POKEMON_BATTLE),
it.queryMemoryAbsent(CobblemonMemories.POKEMON_DROWSY)
).apply(it) { _, _ ->
TaskRunnable { world, entity, _ ->
if (entity.pokemon.status?.status == Statuses.SLEEP && entity.pokemon.storeCoordinates.get()?.store !is PartyStore) {
entity.pokemon.status = null
entity.brain.resetPossibleActivities()
return@TaskRunnable true
} else {
return@TaskRunnable false
}
}
}
}
}
}
@@ -87,9 +87,7 @@ object AdvancementHandler {
event.battle.actors.forEach { battleActor ->
if (!event.winners.contains(battleActor) && battleActor.type == ActorType.WILD) {
battleActor.pokemonList.forEach { battlePokemon ->
battlePokemon.entity?.pokemon?.let {
advancementData.updateTotalDefeatedCount(it)
}
advancementData.updateTotalDefeatedCount(battlePokemon.originalPokemon)
}
}
}
@@ -218,6 +218,7 @@ object CobblemonItemGroups {
entries.add(CobblemonItems.MONITOR)
entries.add(CobblemonItems.PC)
entries.add(CobblemonItems.HEALING_MACHINE)
entries.add(CobblemonItems.STADIUM)
entries.add(CobblemonItems.PASTURE)
entries.add(CobblemonItems.GILDED_CHEST)
@@ -19,7 +19,7 @@ class LinkCableItem : CobblemonItem(Settings()), PokemonEntityInteraction {
override val accepted = setOf(PokemonEntityInteraction.Ownership.OWNER)
override fun processInteraction(player: ServerPlayerEntity, entity: PokemonEntity, stack: ItemStack): Boolean {
val pokemon = entity.pokemon
pokemon.evolutions.filterIsInstance<TradeEvolution>().forEach { evolution ->
pokemon.lockedEvolutions.filterIsInstance<TradeEvolution>().forEach { evolution ->
// If an evolution is possible non-optional or has been successfully queued we will consume the item and stop
// validate requirements to respect required held items and such.
if (evolution.requirements.all { it.check(pokemon) } && evolution.evolve(pokemon)) {
@@ -39,6 +39,7 @@ class SpawnPokemonPacket(
private val hideLabel: Boolean,
private val caughtBall: Identifier,
private val spawnYaw: Float,
private val friendship: Int,
vanillaSpawnPacket: EntitySpawnS2CPacket
) : SpawnExtraDataEntityPacket<SpawnPokemonPacket, PokemonEntity>(vanillaSpawnPacket) {
@@ -60,6 +61,7 @@ class SpawnPokemonPacket(
entity.dataTracker.get(PokemonEntity.HIDE_LABEL),
entity.pokemon.caughtBall.name,
entity.dataTracker.get(PokemonEntity.SPAWN_DIRECTION),
entity.dataTracker.get(PokemonEntity.FRIENDSHIP),
vanillaSpawnPacket
)
@@ -79,6 +81,7 @@ class SpawnPokemonPacket(
buffer.writeBoolean(this.hideLabel)
buffer.writeIdentifier(this.caughtBall)
buffer.writeFloat(this.spawnYaw)
buffer.writeInt(this.friendship)
}
override fun applyData(entity: PokemonEntity) {
@@ -101,6 +104,7 @@ class SpawnPokemonPacket(
entity.dataTracker.set(PokemonEntity.UNBATTLEABLE, unbattlable)
entity.dataTracker.set(PokemonEntity.HIDE_LABEL, hideLabel)
entity.dataTracker.set(PokemonEntity.SPAWN_DIRECTION, spawnYaw)
entity.dataTracker.set(PokemonEntity.FRIENDSHIP, friendship)
}
override fun checkType(entity: Entity): Boolean = entity is PokemonEntity
@@ -124,9 +128,10 @@ class SpawnPokemonPacket(
val hideLabel = buffer.readBoolean()
val caughtBall = buffer.readIdentifier()
val spawnAngle = buffer.readFloat()
val friendship = buffer.readInt()
val vanillaPacket = decodeVanillaPacket(buffer)
return SpawnPokemonPacket(ownerId, scaleModifier, species, form, aspects, battleId, phasingTargetId, beamModeEmitter, nickname, labelLevel, poseType, unbattlable, hideLabel, caughtBall, spawnAngle, vanillaPacket)
return SpawnPokemonPacket(ownerId, scaleModifier, species, form, aspects, battleId, phasingTargetId, beamModeEmitter, nickname, labelLevel, poseType, unbattlable, hideLabel, caughtBall, spawnAngle, friendship, vanillaPacket)
}
}
@@ -426,6 +426,8 @@ open class Pokemon : ShowdownIdentifiable {
// We want non-optional evolutions to trigger first to avoid unnecessary packets and any cost associate with an optional one that would just be lost
val evolutions: Iterable<Evolution> get() = this.form.evolutions.sortedBy { evolution -> evolution.optional }
val lockedEvolutions: Iterable<Evolution>
get() = evolutions.filter { it !in evolutionProxy.current() }
val preEvolution: PreEvolution? get() = this.form.preEvolution
@@ -28,8 +28,6 @@ class RestBehaviour {
val biomes = mutableListOf<RegistryLikeCondition<Biome>>()
val light = IntRange(0, 15)
val depth = SleepDepth.normal
val canSeeSky: Boolean? = null
val skyLight: IntRange? = null
val willSleepOnBed = false
}
@@ -43,7 +43,8 @@ object CobblemonRequirementAdapter : RequirementAdapter {
this.registerType(TimeRangeRequirement.ADAPTER_VARIANT, TimeRangeRequirement::class)
this.registerType(LevelRequirement.ADAPTER_VARIANT, LevelRequirement::class)
this.registerType(WeatherRequirement.ADAPTER_VARIANT, WeatherRequirement::class)
this.registerType(AttackDefenceRatioRequirement.ADAPTER_VARIANT, AttackDefenceRatioRequirement::class)
this.registerType(StatCompareRequirement.ADAPTER_VARIANT, StatCompareRequirement::class)
this.registerType(StatEqualRequirement.ADAPTER_VARIANT, StatEqualRequirement::class)
this.registerType(BattleCriticalHitsRequirement.ADAPTER_VARIANT, BattleCriticalHitsRequirement::class)
this.registerType(DamageTakenRequirement.ADAPTER_VARIANT, DamageTakenRequirement::class)
this.registerType(UseMoveRequirement.ADAPTER_VARIANT, UseMoveRequirement::class)
@@ -9,24 +9,18 @@
package com.cobblemon.mod.common.pokemon.evolution.requirements
import com.cobblemon.mod.common.api.pokemon.evolution.requirement.EvolutionRequirement
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.pokemon.Pokemon
class AttackDefenceRatioRequirement : EvolutionRequirement {
class StatCompareRequirement : EvolutionRequirement {
companion object {
const val ADAPTER_VARIANT = "attack_defence_ratio"
}
enum class AttackDefenceRatio {
ATTACK_HIGHER,
DEFENCE_HIGHER,
EQUAL
const val ADAPTER_VARIANT = "stat_compare"
}
val ratio = AttackDefenceRatio.ATTACK_HIGHER
val highStat = Stats.ATTACK.name
val lowStat = Stats.DEFENCE.name
override fun check(pokemon: Pokemon): Boolean {
return when (ratio) {
AttackDefenceRatio.ATTACK_HIGHER -> pokemon.attack > pokemon.defence
AttackDefenceRatio.DEFENCE_HIGHER -> pokemon.defence > pokemon.attack
AttackDefenceRatio.EQUAL -> pokemon.attack == pokemon.defence
}
return pokemon.getStat(Stats.getStat(highStat)) > pokemon.getStat(Stats.getStat(lowStat))
}
}
@@ -0,0 +1,26 @@
/*
* 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.pokemon.evolution.requirements
import com.cobblemon.mod.common.api.pokemon.evolution.requirement.EvolutionRequirement
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.pokemon.Pokemon
class StatEqualRequirement : EvolutionRequirement {
companion object {
const val ADAPTER_VARIANT = "stat_equal"
}
val statOne = Stats.ATTACK.name
val statTwo = Stats.DEFENCE.name
override fun check(pokemon: Pokemon): Boolean {
return pokemon.getStat(Stats.getStat(statOne)) == pokemon.getStat(Stats.getStat(statTwo))
}
}
@@ -98,11 +98,11 @@ object TradeManager {
party2.add(pokemon1)
party1.add(pokemon2)
pokemon1.evolutions.filterIsInstance<TradeEvolution>().firstOrNull {
pokemon1.lockedEvolutions.filterIsInstance<TradeEvolution>().firstOrNull {
it.attemptEvolution(pokemon1, pokemon2)
}
pokemon2.evolutions.filterIsInstance<TradeEvolution>().firstOrNull {
pokemon2.lockedEvolutions.filterIsInstance<TradeEvolution>().firstOrNull {
it.attemptEvolution(pokemon2, pokemon1)
}
CobblemonEvents.TRADE_COMPLETED.post(TradeCompletedEvent(player1, pokemon2, player2, pokemon1))
@@ -134,6 +134,7 @@ object DataKeys {
// Features
const val CAN_BE_MILKED = "milkable"
const val HAS_BEEN_SHEARED = "sheared"
const val CAN_BE_COLORED = "color"
// Variants
const val IS_MOOSHTANK = "mooshtank"
@@ -24,7 +24,7 @@ inline fun <reified T> Gson.fromJson(string: String) = fromJson(string, T::class
* the list value identified by the plural name. During runtime only the plural exists, but when
* configuring the JSON the user can use the singular form for a cleaner document.
*/
fun JsonObject.singularToPluralList(rootName: String, pluralName: String = "${rootName}s") {
fun JsonObject.singularToPluralList(rootName: String, pluralName: String = "${rootName}s"): JsonObject {
if (has(rootName)) {
if (!has(pluralName)) {
add(pluralName, JsonArray())
@@ -32,6 +32,7 @@ fun JsonObject.singularToPluralList(rootName: String, pluralName: String = "${ro
get(pluralName).asJsonArray.add(get(rootName))
remove(rootName)
}
return this
}
fun JsonElement.normalizeToArray(): JsonArray {
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common.util
import net.minecraft.block.BlockState
import net.minecraft.entity.Entity
import net.minecraft.entity.ai.pathing.NavigationType
import net.minecraft.item.Item
import net.minecraft.particle.ParticleEffect
import net.minecraft.registry.Registry
@@ -98,19 +97,6 @@ fun BlockView.getBlockStatesWithPos(box: Box): Iterable<Pair<BlockState, BlockPo
return states
}
fun BlockView.getBlockPositions(box: Box): Iterable<BlockPos> {
val positions = mutableListOf<BlockPos>()
val (xRange, yRange, zRange) = box.getRanges()
for (x in xRange) {
for (y in yRange) {
for (z in zRange) {
positions.add(BlockPos(x, y, z))
}
}
}
return positions
}
fun BlockView.getWaterAndLavaIn(box: Box): Pair<Boolean, Boolean> {
var hasWater = false
var hasLava = false
@@ -134,63 +120,6 @@ fun Entity.canFit(vec: Vec3d): Boolean {
return world.isSpaceEmpty(box)
}
enum class PositionType {
LAND,
WATER,
SEAFLOOR,
LAVAFLOOR
}
fun World.canEntityStayAt(position: BlockPos, width: Int = 1, height: Int = 1, positionType: PositionType): Boolean {
val minX = kotlin.math.floor(position.x + 0.5 - (width - 1) / 2F).toInt()
val maxX = kotlin.math.ceil(position.x + 0.5 + (width - 1) / 2F).toInt()
val maxY = position.y + height
val minZ = kotlin.math.floor(position.z + 0.5 - (width - 1) / 2F).toInt()
val maxZ = kotlin.math.ceil(position.z + 0.5 + (width - 1) / 2F).toInt()
val mutable = BlockPos.Mutable()
for (x in minX until maxX) {
for (y in position.y..maxY) {
for (z in minZ until maxZ) {
val state = getBlockState(mutable.set(x, y, z))
// If it's a floor check, we likely need to do something different than surrounding blocks
if (y == position.y) {
if (positionType == PositionType.LAND) {
// Land entities need to be standing on solid ground
if (state.canPathfindThrough(this, mutable, NavigationType.LAND)) {
return false
}
}
} else {
when (positionType) {
PositionType.LAND -> {
if (!state.canPathfindThrough(this, mutable, NavigationType.LAND)) {
return false
}
}
PositionType.WATER, PositionType.SEAFLOOR -> {
if (!state.fluidState.isIn(FluidTags.WATER)) {
return false
}
}
PositionType.LAVAFLOOR -> {
if (!state.fluidState.isIn(FluidTags.LAVA)) {
return false
}
}
}
}
}
}
}
return true
}
val World.itemRegistry: Registry<Item>
get() = registryManager.get(RegistryKeys.ITEM)
val World.biomeRegistry: Registry<Biome>
@@ -5,30 +5,32 @@
"identifier": "cobblemon:ancientoriginball/ballsparkle",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/balls/pokeball/ballsparkle"
"texture": "textures/particles/balls/originball/originballsparkle"
}
},
"components": {
"minecraft:emitter_rate_steady": {
"spawn_rate": 16,
"max_particles": 16
"spawn_rate": 22,
"max_particles": 24
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.5
},
"minecraft:emitter_shape_sphere": {
"offset": [0, 1.5, 0],
"offset": [0, 2, 0],
"radius": "math.random(0.5,1.5)*1.5",
"surface_only": true,
"direction": [0, 1, 0]
"direction": ["math.random(-9,9)", "math.random(4,7)", "math.random(-9,9)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1
},
"minecraft:particle_initial_speed": 0.75,
"minecraft:particle_motion_dynamic": {},
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, 2, 0]
},
"minecraft:particle_appearance_billboard": {
"size": [0.2, 0.2],
"size": [0.175, 0.175],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 36,
@@ -5,25 +5,30 @@
"identifier": "cobblemon:ancientoriginball/battle/ballsendsparkle",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/balls/pokeball/ballsendsparkle"
"texture": "textures/particles/balls/originball/originballsendsparkle"
}
},
"components": {
"minecraft:emitter_rate_instant": {
"num_particles": 8
"minecraft:emitter_initialization": {
"per_update_expression": "variable.radius = 0.6;"
},
"minecraft:emitter_rate_steady": {
"spawn_rate": 100,
"max_particles": 16
},
"minecraft:emitter_lifetime_once": {
"active_time": 1
},
"minecraft:emitter_shape_sphere": {
"direction": ["math.random(-10,10)", "math.random(-0.05,4)*4+0.5", "math.random(-10,10)"]
"radius": "variable.radius*math.cos(variable.emitter_age*2080)",
"direction": ["math.random(-5,5)*1.75", "math.random(-0.05,6)*3+0.5", "math.random(-5,5)*1.75"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1
},
"minecraft:particle_initial_speed": "math.random(4,7)*3",
"minecraft:particle_initial_speed": "math.random(3,7)*4",
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, -5, 0],
"linear_acceleration": [0, "-math.random(5,8)", 0],
"linear_drag_coefficient": 4
},
"minecraft:particle_appearance_billboard": {
@@ -5,38 +5,52 @@
"identifier": "cobblemon:ancientoriginball/battle/ballsparks",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/balls/pokeball/ballsparks"
"texture": "textures/particles/balls/originball/originballsparks"
}
},
"curves": {
"variable.sizefunny": {
"type": "linear",
"input": "v.particle_age",
"horizontal_range": "v.particle_lifetime",
"nodes": [1, 1, 1, 0.98, 0.93, 0.83, 0.58, -0.01, 0, 0]
}
},
"components": {
"minecraft:emitter_rate_instant": {
"num_particles": 10
"num_particles": 20
},
"minecraft:emitter_lifetime_once": {
"active_time": 1
"active_time": 0.5
},
"minecraft:emitter_shape_sphere": {
"direction": ["math.random(-10,10)", "math.random(-0.1,4)*3+0.5", "math.random(-10,10)"]
"direction": ["math.random(-10,10)", "math.random(-0.1,4)*3+0.25", "math.random(-10,10)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1
},
"minecraft:particle_initial_speed": "math.random(4,7)*3.5",
"minecraft:particle_initial_speed": "math.random(3.1,4.8)*3.5",
"minecraft:particle_motion_dynamic": {
"linear_drag_coefficient": 4.5
"linear_acceleration": ["math.random(-3.5,3.5)*10", "math.random(-2.5,2.5)*10", "math.random(-3.5,3.5)*10"],
"linear_drag_coefficient": 3.5
},
"minecraft:particle_appearance_billboard": {
"size": [0.15, 0.15],
"size": ["(0.225-(variable.particle_random_3*0.1))*v.sizefunny", "(0.225-(variable.particle_random_3*0.1))*v.sizefunny"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 80,
"texture_height": 8,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [8, 8],
"step_UV": [8, 0],
"frames_per_second": 18,
"max_frame": 10
"texture_width": 90,
"texture_height": 9,
"uv": ["math.floor(v.particle_random_3*10)*9", 0],
"uv_size": [9, 9]
}
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.particle_age / v.particle_lifetime",
"gradient": {
"0.14": "#ffffffff",
"0.43": "#FFFF0000",
"0.71": "#FF7B0000"
}
}
}
@@ -5,7 +5,7 @@
"identifier": "cobblemon:ancientoriginball/battle/sendflash",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/balls/pokeball/battle/sendflash"
"texture": "textures/particles/balls/originball/battle/originsendflash"
}
},
"components": {
@@ -27,14 +27,14 @@
"size": [2.25, 2.25],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 1024,
"texture_width": 1088,
"texture_height": 64,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [64, 64],
"step_UV": [64, 0],
"frames_per_second": 24,
"max_frame": 16
"max_frame": 17
}
}
}
@@ -5,12 +5,12 @@
"identifier": "cobblemon:ancientoriginball/casual/ballsendsparkle",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/balls/pokeball/ballsendsparkle"
"texture": "textures/particles/balls/originball/originballsendsparkle"
}
},
"components": {
"minecraft:emitter_rate_instant": {
"num_particles": 4
"num_particles": 6
},
"minecraft:emitter_lifetime_once": {
"active_time": 1
@@ -21,7 +21,7 @@
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1
},
"minecraft:particle_initial_speed": "math.random(4,6)*2.5",
"minecraft:particle_initial_speed": "math.random(3,6)*3",
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, -6, 0],
"linear_drag_coefficient": 4
@@ -5,38 +5,52 @@
"identifier": "cobblemon:ancientoriginball/casual/ballsparks",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/balls/pokeball/ballsparks"
"texture": "textures/particles/balls/originball/originballsparks"
}
},
"curves": {
"variable.sizefunny": {
"type": "linear",
"input": "v.particle_age",
"horizontal_range": "v.particle_lifetime",
"nodes": [1, 1, 1, 0.98, 0.93, 0.83, 0.58, -0.01, 0, 0, 0]
}
},
"components": {
"minecraft:emitter_rate_instant": {
"num_particles": 5
"num_particles": 10
},
"minecraft:emitter_lifetime_once": {
"active_time": 1
"active_time": 0.5
},
"minecraft:emitter_shape_sphere": {
"direction": ["math.random(-10,10)", "math.random(-0.1,4)*3+0.5", "math.random(-10,10)"]
"direction": ["math.random(-10,10)", "math.random(-0.1,4)*3+0.25", "math.random(-10,10)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1
},
"minecraft:particle_initial_speed": "math.random(4,7)*2.1",
"minecraft:particle_initial_speed": "math.random(3.1,4.8)*2.5",
"minecraft:particle_motion_dynamic": {
"linear_acceleration": ["math.random(-3.5,3.5)*10", "math.random(-2.5,2.5)*10", "math.random(-3.5,3.5)*10"],
"linear_drag_coefficient": 3.5
},
"minecraft:particle_appearance_billboard": {
"size": [0.1, 0.1],
"size": ["(0.225-(variable.particle_random_3*0.1))*v.sizefunny", "(0.225-(variable.particle_random_3*0.1))*v.sizefunny"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 80,
"texture_height": 8,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [8, 8],
"step_UV": [8, 0],
"frames_per_second": 18,
"max_frame": 10
"texture_width": 90,
"texture_height": 9,
"uv": ["math.floor(v.particle_random_3*10)*9", 0],
"uv_size": [9, 9]
}
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.particle_age / v.particle_lifetime",
"gradient": {
"0.14": "#ffffffff",
"0.33": "#FFFF0000",
"0.61": "#FF7B0000"
}
}
}
@@ -5,7 +5,7 @@
"identifier": "cobblemon:ancientoriginball/casual/sendflash",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/balls/pokeball/casual/sendcasual"
"texture": "textures/particles/balls/originball/casual/originsendcasual"
}
},
"components": {
@@ -27,14 +27,14 @@
"size": [1.25, 1.25],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 384,
"texture_width": 416,
"texture_height": 32,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [32, 32],
"step_UV": [32, 0],
"frames_per_second": 24,
"max_frame": 12
"max_frame": 13
}
}
}
@@ -5,30 +5,32 @@
"identifier": "cobblemon:beastball/ballsparkle",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/balls/pokeball/ballsparkle"
"texture": "textures/particles/balls/beastball/beastballsparkle"
}
},
"components": {
"minecraft:emitter_rate_steady": {
"spawn_rate": 16,
"max_particles": 16
"spawn_rate": 24,
"max_particles": 18
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.5
},
"minecraft:emitter_shape_sphere": {
"offset": [0, 1.5, 0],
"radius": "math.random(0.5,1.5)*1.5",
"offset": [0, 1.75, 0],
"radius": 1.25,
"surface_only": true,
"direction": [0, 1, 0]
"direction": ["math.random(-9,9)", "math.random(4,7)", "math.random(-9,9)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1
},
"minecraft:particle_initial_speed": 0.75,
"minecraft:particle_motion_dynamic": {},
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, 2, 0]
},
"minecraft:particle_appearance_billboard": {
"size": [0.2, 0.2],
"size": [0.15, 0.15],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 36,
@@ -5,12 +5,12 @@
"identifier": "cobblemon:beastball/battle/ballsendsparkle",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/balls/pokeball/ballsendsparkle"
"texture": "textures/particles/balls/beastball/beastballsendsparkle"
}
},
"components": {
"minecraft:emitter_rate_instant": {
"num_particles": 8
"num_particles": 14
},
"minecraft:emitter_lifetime_once": {
"active_time": 1
@@ -21,13 +21,13 @@
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1
},
"minecraft:particle_initial_speed": "math.random(4,7)*3",
"minecraft:particle_initial_speed": "math.random(4,7)*4.5",
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, -5, 0],
"linear_drag_coefficient": 4
"linear_acceleration": [0, -6, 0],
"linear_drag_coefficient": 5
},
"minecraft:particle_appearance_billboard": {
"size": [0.15, 0.15],
"size": [0.125, 0.125],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 99,
@@ -5,28 +5,32 @@
"identifier": "cobblemon:beastball/battle/ballsparks",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/balls/pokeball/ballsparks"
"texture": "textures/particles/balls/beastball/beastballsparks"
}
},
"components": {
"minecraft:emitter_rate_instant": {
"num_particles": 10
"num_particles": 20
},
"minecraft:emitter_lifetime_once": {
"active_time": 1
},
"minecraft:emitter_shape_sphere": {
"direction": ["math.random(-10,10)", "math.random(-0.1,4)*3+0.5", "math.random(-10,10)"]
"direction": ["math.random(-10,10)", "math.random(-0.5,5)*5+0.5", "math.random(-10,10)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1
},
"minecraft:particle_initial_speed": "math.random(4,7)*3.5",
"minecraft:particle_initial_spin": {
"rotation": "math.random_integer(0,3)*90"
},
"minecraft:particle_initial_speed": "math.random(3,6)*3",
"minecraft:particle_motion_dynamic": {
"linear_drag_coefficient": 4.5
"linear_acceleration": [0, -20, 0],
"linear_drag_coefficient": 2
},
"minecraft:particle_appearance_billboard": {
"size": [0.15, 0.15],
"size": ["0.075+0.075*v.particle_random_2", "0.075+0.075*v.particle_random_2"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 80,
@@ -5,7 +5,7 @@
"identifier": "cobblemon:beastball/battle/sendflash",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/balls/pokeball/battle/sendflash"
"texture": "textures/particles/balls/beastball/battle/beastsendflash"
}
},
"components": {
@@ -27,14 +27,14 @@
"size": [2.25, 2.25],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 1024,
"texture_width": 1088,
"texture_height": 64,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [64, 64],
"step_UV": [64, 0],
"frames_per_second": 24,
"max_frame": 16
"max_frame": 17
}
}
}
@@ -5,12 +5,12 @@
"identifier": "cobblemon:beastball/casual/ballsendsparkle",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/balls/pokeball/ballsendsparkle"
"texture": "textures/particles/balls/beastball/beastballsendsparkle"
}
},
"components": {
"minecraft:emitter_rate_instant": {
"num_particles": 4
"num_particles": 6
},
"minecraft:emitter_lifetime_once": {
"active_time": 1
@@ -21,7 +21,7 @@
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1
},
"minecraft:particle_initial_speed": "math.random(4,6)*2.5",
"minecraft:particle_initial_speed": "math.random(3,6)*3",
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, -6, 0],
"linear_drag_coefficient": 4
@@ -5,28 +5,32 @@
"identifier": "cobblemon:beastball/casual/ballsparks",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/balls/pokeball/ballsparks"
"texture": "textures/particles/balls/beastball/beastballsparks"
}
},
"components": {
"minecraft:emitter_rate_instant": {
"num_particles": 5
"num_particles": 12
},
"minecraft:emitter_lifetime_once": {
"active_time": 1
},
"minecraft:emitter_shape_sphere": {
"direction": ["math.random(-10,10)", "math.random(-0.1,4)*3+0.5", "math.random(-10,10)"]
"direction": ["math.random(-10,10)", "math.random(-0.5,5)*5+0.5", "math.random(-10,10)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1
},
"minecraft:particle_initial_speed": "math.random(4,7)*2.1",
"minecraft:particle_initial_spin": {
"rotation": "math.random_integer(0,3)*90"
},
"minecraft:particle_initial_speed": "math.random(3,7)*2",
"minecraft:particle_motion_dynamic": {
"linear_drag_coefficient": 3.5
"linear_acceleration": [0, -15, 0],
"linear_drag_coefficient": 2
},
"minecraft:particle_appearance_billboard": {
"size": [0.1, 0.1],
"size": ["0.05+0.075*v.particle_random_2", "0.05+0.075*v.particle_random_2"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 80,
@@ -5,7 +5,7 @@
"identifier": "cobblemon:beastball/casual/sendflash",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/balls/pokeball/casual/sendcasual"
"texture": "textures/particles/balls/beastball/casual/beastsendcasual"
}
},
"components": {
@@ -5,30 +5,32 @@
"identifier": "cobblemon:cherishball/ballsparkle",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/balls/pokeball/ballsparkle"
"texture": "textures/particles/balls/cherishball/cherishballsparkle"
}
},
"components": {
"minecraft:emitter_rate_steady": {
"spawn_rate": 16,
"max_particles": 16
"spawn_rate": 24,
"max_particles": 18
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.5
},
"minecraft:emitter_shape_sphere": {
"offset": [0, 1.5, 0],
"radius": "math.random(0.5,1.5)*1.5",
"offset": [0, 1.75, 0],
"radius": 1.25,
"surface_only": true,
"direction": [0, 1, 0]
"direction": ["math.random(-9,9)", "math.random(4,7)", "math.random(-9,9)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1
},
"minecraft:particle_initial_speed": 0.75,
"minecraft:particle_motion_dynamic": {},
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, 2, 0]
},
"minecraft:particle_appearance_billboard": {
"size": [0.2, 0.2],
"size": [0.15, 0.15],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 36,
@@ -41,6 +43,15 @@
"max_frame": 4
}
}
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.particle_age / v.particle_lifetime",
"gradient": {
"0.0": "#FFFFFFFF",
"0.19": "#FFFF8845"
}
}
}
}
}
@@ -5,12 +5,12 @@
"identifier": "cobblemon:cherishball/battle/ballsendsparkle",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/balls/pokeball/ballsendsparkle"
"texture": "textures/particles/balls/cherishball/cherishballsendsparkle"
}
},
"components": {
"minecraft:emitter_rate_instant": {
"num_particles": 8
"num_particles": 14
},
"minecraft:emitter_lifetime_once": {
"active_time": 1
@@ -21,13 +21,13 @@
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1
},
"minecraft:particle_initial_speed": "math.random(4,7)*3",
"minecraft:particle_initial_speed": "math.random(4,7)*4.5",
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, -5, 0],
"linear_drag_coefficient": 4
"linear_acceleration": [0, -6, 0],
"linear_drag_coefficient": 5
},
"minecraft:particle_appearance_billboard": {
"size": [0.15, 0.15],
"size": [0.125, 0.125],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 99,
@@ -40,6 +40,17 @@
"max_frame": 11
}
}
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.particle_age / v.particle_lifetime",
"gradient": {
"0.0": "#FF8DFFC6",
"0.2": "#ffffffff",
"0.35": "#ffffffff",
"0.53": "#FFFF8845"
}
}
}
}
}
@@ -5,12 +5,12 @@
"identifier": "cobblemon:cherishball/battle/ballsparks",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/balls/pokeball/ballsparks"
"texture": "textures/particles/balls/cherishball/cherishballsparks"
}
},
"components": {
"minecraft:emitter_rate_instant": {
"num_particles": 10
"num_particles": 8
},
"minecraft:emitter_lifetime_once": {
"active_time": 1
@@ -21,9 +21,9 @@
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1
},
"minecraft:particle_initial_speed": "math.random(4,7)*3.5",
"minecraft:particle_initial_speed": "math.random(3,6)*3.75",
"minecraft:particle_motion_dynamic": {
"linear_drag_coefficient": 4.5
"linear_drag_coefficient": 5
},
"minecraft:particle_appearance_billboard": {
"size": [0.15, 0.15],
@@ -39,6 +39,17 @@
"max_frame": 10
}
}
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.particle_age / v.particle_lifetime",
"gradient": {
"0.0": "#FF8DFFC6",
"0.2": "#ffffffff",
"0.35": "#ffffffff",
"0.53": "#FFFF8845"
}
}
}
}
}
@@ -5,7 +5,7 @@
"identifier": "cobblemon:cherishball/battle/sendflash",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/balls/pokeball/battle/sendflash"
"texture": "textures/particles/balls/cherishball/battle/cherishsendflash"
}
},
"components": {
@@ -27,14 +27,25 @@
"size": [2.25, 2.25],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 1024,
"texture_width": 1088,
"texture_height": 64,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [64, 64],
"step_UV": [64, 0],
"frames_per_second": 24,
"max_frame": 16
"max_frame": 17
}
}
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.particle_age / v.particle_lifetime",
"gradient": {
"0.0": "#FF8DFFC6",
"0.2": "#ffffffff",
"0.35": "#ffffffff",
"0.53": "#FFFF8845"
}
}
}
@@ -5,12 +5,12 @@
"identifier": "cobblemon:cherishball/casual/ballsendsparkle",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/balls/pokeball/ballsendsparkle"
"texture": "textures/particles/balls/cherishball/cherishballsendsparkle"
}
},
"components": {
"minecraft:emitter_rate_instant": {
"num_particles": 4
"num_particles": 6
},
"minecraft:emitter_lifetime_once": {
"active_time": 1
@@ -21,7 +21,7 @@
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1
},
"minecraft:particle_initial_speed": "math.random(4,6)*2.5",
"minecraft:particle_initial_speed": "math.random(3,6)*3",
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, -6, 0],
"linear_drag_coefficient": 4
@@ -40,6 +40,17 @@
"max_frame": 11
}
}
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.particle_age / v.particle_lifetime",
"gradient": {
"0.0": "#FF8DFFC6",
"0.2": "#ffffffff",
"0.35": "#ffffffff",
"0.53": "#FFFF8845"
}
}
}
}
}
@@ -5,7 +5,7 @@
"identifier": "cobblemon:cherishball/casual/ballsparks",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/balls/pokeball/ballsparks"
"texture": "textures/particles/balls/cherishball/cherishballsparks"
}
},
"components": {
@@ -21,9 +21,9 @@
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1
},
"minecraft:particle_initial_speed": "math.random(4,7)*2.1",
"minecraft:particle_initial_speed": "math.random(3,7)*2",
"minecraft:particle_motion_dynamic": {
"linear_drag_coefficient": 3.5
"linear_drag_coefficient": 3
},
"minecraft:particle_appearance_billboard": {
"size": [0.1, 0.1],
@@ -39,6 +39,17 @@
"max_frame": 10
}
}
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.particle_age / v.particle_lifetime",
"gradient": {
"0.0": "#FF8DFFC6",
"0.2": "#ffffffff",
"0.35": "#ffffffff",
"0.53": "#FFFF8845"
}
}
}
}
}
@@ -5,7 +5,7 @@
"identifier": "cobblemon:cherishball/casual/sendflash",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/balls/pokeball/casual/sendcasual"
"texture": "textures/particles/balls/cherishball/casual/cherishsendcasual"
}
},
"components": {
@@ -27,14 +27,25 @@
"size": [1.25, 1.25],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 384,
"texture_width": 416,
"texture_height": 32,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [32, 32],
"step_UV": [32, 0],
"frames_per_second": 24,
"max_frame": 12
"max_frame": 13
}
}
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.particle_age / v.particle_lifetime",
"gradient": {
"0.0": "#FF8DFFC6",
"0.2": "#ffffffff",
"0.35": "#ffffffff",
"0.53": "#FFFF8845"
}
}
}
@@ -5,22 +5,22 @@
"identifier": "cobblemon:dreamball/ballsparkle",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/balls/pokeball/ballsparkle"
"texture": "textures/particles/balls/dreamball/dreamballsparkle"
}
},
"components": {
"minecraft:emitter_rate_steady": {
"spawn_rate": 16,
"max_particles": 16
"spawn_rate": 20,
"max_particles": 14
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.5
},
"minecraft:emitter_shape_sphere": {
"offset": [0, 1.5, 0],
"radius": "math.random(0.5,1.5)*1.5",
"offset": [0, 1.25, 0],
"radius": "1.25",
"surface_only": true,
"direction": [0, 1, 0]
"direction": "outwards"
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1
@@ -5,12 +5,12 @@
"identifier": "cobblemon:dreamball/battle/ballsendsparkle",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/balls/pokeball/ballsendsparkle"
"texture": "textures/particles/balls/dreamball/dreamballsendsparkle"
}
},
"components": {
"minecraft:emitter_rate_instant": {
"num_particles": 8
"num_particles": 14
},
"minecraft:emitter_lifetime_once": {
"active_time": 1
@@ -21,13 +21,13 @@
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1
},
"minecraft:particle_initial_speed": "math.random(4,7)*3",
"minecraft:particle_initial_speed": "math.random(4,7)*4.5",
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, -5, 0],
"linear_drag_coefficient": 4
"linear_acceleration": [0, -6, 0],
"linear_drag_coefficient": 5
},
"minecraft:particle_appearance_billboard": {
"size": [0.15, 0.15],
"size": [0.125, 0.125],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 99,
@@ -5,12 +5,12 @@
"identifier": "cobblemon:dreamball/battle/ballsparks",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/balls/pokeball/ballsparks"
"texture": "textures/particles/balls/dreamball/dreamballsparks"
}
},
"components": {
"minecraft:emitter_rate_instant": {
"num_particles": 10
"num_particles": 8
},
"minecraft:emitter_lifetime_once": {
"active_time": 1
@@ -21,9 +21,9 @@
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1
},
"minecraft:particle_initial_speed": "math.random(4,7)*3.5",
"minecraft:particle_initial_speed": "math.random(3,6)*3.75",
"minecraft:particle_motion_dynamic": {
"linear_drag_coefficient": 4.5
"linear_drag_coefficient": 5
},
"minecraft:particle_appearance_billboard": {
"size": [0.15, 0.15],
@@ -5,7 +5,7 @@
"identifier": "cobblemon:dreamball/battle/sendflash",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/balls/pokeball/battle/sendflash"
"texture": "textures/particles/balls/dreamball/battle/dreamsendflash"
}
},
"components": {
@@ -27,14 +27,14 @@
"size": [2.25, 2.25],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 1024,
"texture_width": 1088,
"texture_height": 64,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [64, 64],
"step_UV": [64, 0],
"frames_per_second": 24,
"max_frame": 16
"max_frame": 17
}
}
}
@@ -5,12 +5,12 @@
"identifier": "cobblemon:dreamball/casual/ballsendsparkle",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/balls/pokeball/ballsendsparkle"
"texture": "textures/particles/balls/dreamball/dreamballsendsparkle"
}
},
"components": {
"minecraft:emitter_rate_instant": {
"num_particles": 4
"num_particles": 6
},
"minecraft:emitter_lifetime_once": {
"active_time": 1
@@ -21,7 +21,7 @@
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1
},
"minecraft:particle_initial_speed": "math.random(4,6)*2.5",
"minecraft:particle_initial_speed": "math.random(3,6)*3",
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, -6, 0],
"linear_drag_coefficient": 4

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