Compare commits

...
Author SHA1 Message Date
Tyzillion a077e74bf2 When you wish upon a star
Makes no difference who you are
Anything your heart desires
Will come to you
If your heart is in your dream
No request is too extreme
When you wish upon a star
As dreamers do
Fate is kind
She brings to those who love
The sweet fulfillment of
Their secret longing
Like a bolt out of the blue
Fate steps in and sees you through
When you wish upon a star
Your dreams come true
2024-02-18 14:25:47 -05:00
Lily 763f1de793 forgot to push this mb 2024-02-16 22:34:31 -05:00
Lily 62a95b93c5 begin implementing falling stars 2024-02-16 14:48:20 -05:00
Lily 7991f70c09 Merge remote-tracking branch 'origin/dynamax' into dynamax 2024-02-16 14:48:07 -05:00
Lily 70d393a899 begin implementing falling stars 2024-02-16 14:47:58 -05:00
Lily 5bace46aa6 begin implementing falling stars 2024-02-13 21:51:28 -05:00
Lily c5fb411636 Merge branch 'sega_bass_pro_fishing_2' into dynamax
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonEntities.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonItems.kt
#	fabric/src/main/kotlin/com/cobblemon/mod/fabric/client/CobblemonFabricClient.kt
#	forge/src/main/kotlin/com/cobblemon/mod/forge/client/CobblemonForgeClient.kt
2024-02-13 20:59:18 -05:00
Lily 9a8159ee30 start on dynamax 2024-02-13 20:07:29 -05:00
Plastered_Crab acc6f119e1 - Magikarps getting reeled in now land in front of the player instead of behind the player (for battle reasons) 2024-02-13 16:45:22 -08:00
Plastered_Crab 932a2c375c - Begin different reel-in trajectories for fishing up Magikarps 2024-02-13 14:46:42 -08:00
Nick 142eebe9e6 Apply model predicates, starting with Pokerod 2024-02-09 22:07:43 -08:00
jeffw773 36f19c9180 - Xp is rewarded to player for fishing up Pokemon 2024-02-09 21:15:10 -08:00
jeffw773 beb8fed6bd - Pokeball Bobber now renders correctly when cast out with Pokerod
- Luck of the Sea and Lure get read correctly from the rod and factor into the spawn bucket chosen
2024-02-09 14:17:13 -08:00
jeffw773 142284a17c - Pokemon rarity is altered by Luck of the Sea 2024-02-08 21:18:41 -08:00
jeffw773 f1ea86362a - Fixed fishing spawns being able to check if sky is actually visible.
- added isOcean to biomes to Magikarp
2024-02-07 18:28:42 -08:00
Paul ec3361ad91 Added basic fishing spawn detail for Magikarp and use the world pool for fishing because ehhh 2024-02-03 12:16:53 +10:00
Paul ca7c36ce15 Added trigger spawning with a fishing implementation 2024-02-03 12:13:38 +10:00
jeffw773 f7c73728d7 - Added some newer spawning stuff and added battle initiation after fished up mon 2024-02-02 16:38:15 -08:00
jeffw773 1992a23edc Merge branch 'main' into sega_bass_pro_fishing_2 2024-02-02 13:39:02 -08:00
jeffw773 dad28135cc - Brief changes to particle count based on rarity reeled in 2024-01-18 14:32:43 -08:00
jeffw773 e41d13dd53 - Pokerod now uses config values for rarity buckets and access biome spawn pools 2024-01-14 23:02:33 -08:00
jeffw773 64cae53d82 - Pokerod foundation laid out for having chance to spawn Pokemon instead of getting item as well as rarity chance started 2024-01-14 00:11:12 -08:00
dhi_holo c9bf0bd8d7 Merge branch 'sega_bass_pro_fishing_2' of https://gitlab.com/cable-mc/cobblemon into sega_bass_pro_fishing_2 2024-01-14 13:36:53 +10:00
dhi_holo 97d2047aee It's a Tool, It's a Rod
makes pokerod be held correctly, and adds second model file for the cast variation, when that is implemented.
2024-01-14 13:36:04 +10:00
jeffw773 811f8abed7 - Added override for model of pokerod when cast 2024-01-13 19:27:22 -08:00
jeffw773 ab02a54f28 - Finally the Pokerod is starting to work! (it is backwards tho) 2024-01-13 19:08:36 -08:00
jeffw773 6e0c1aefcc - More testing fishing code for pokerod 2024-01-13 13:55:02 -08:00
jeffw773 e887b6c43c - Some code for fishing testing again 2024-01-13 12:16:38 -08:00
jeffw773 25172c2bc9 - Some code for fishing testing 2024-01-13 11:23:38 -08:00
jeffw773 929b90173a - Some code for fishing testing 2024-01-12 11:58:02 -08:00
jeffw773 70a65f6ffe - Testing code 2024-01-12 07:39:21 -08:00
jeffw773 db7d3f01d8 - Starting implementation on fishing 2024-01-12 07:39:20 -08:00
52 changed files with 2168 additions and 25 deletions
@@ -46,8 +46,13 @@ import com.cobblemon.mod.common.api.scheduling.ServerRealTimeTaskTracker
import com.cobblemon.mod.common.api.scheduling.ServerTaskTracker
import com.cobblemon.mod.common.api.spawning.BestSpawner
import com.cobblemon.mod.common.api.spawning.CobblemonSpawningProspector
import com.cobblemon.mod.common.api.spawning.WorldSlice
import com.cobblemon.mod.common.api.spawning.context.AreaContextResolver
import com.cobblemon.mod.common.api.spawning.context.AreaSpawningContext
import com.cobblemon.mod.common.api.spawning.context.calculators.AreaSpawningContextCalculator
import com.cobblemon.mod.common.api.spawning.context.calculators.AreaSpawningInput
import com.cobblemon.mod.common.api.spawning.prospecting.SpawningProspector
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
import com.cobblemon.mod.common.api.starter.StarterHandler
import com.cobblemon.mod.common.api.storage.PokemonStoreManager
import com.cobblemon.mod.common.api.storage.adapter.conversions.ReforgedConversion
@@ -101,13 +106,7 @@ 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
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.ifDedicatedServer
import com.cobblemon.mod.common.util.isLaterVersion
import com.cobblemon.mod.common.util.party
import com.cobblemon.mod.common.util.removeAmountIf
import com.cobblemon.mod.common.util.server
import com.cobblemon.mod.common.util.*
import com.cobblemon.mod.common.world.feature.CobblemonPlacedFeatures
import com.cobblemon.mod.common.world.feature.ore.CobblemonOrePlacedFeatures
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
@@ -131,6 +130,7 @@ import net.minecraft.item.Items
import net.minecraft.item.NameTagItem
import net.minecraft.registry.RegistryKey
import net.minecraft.util.WorldSavePath
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
import org.apache.logging.log4j.LogManager
@@ -65,4 +65,10 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
CobblemonBlocks.FOSSIL_ANALYZER
).build(null)
)
@JvmField
val DYNITE_ORE: BlockEntityType<DyniteOreBlockEntity> = this.create("dynite_ore",
BlockEntityType.Builder.create(::DyniteOreBlockEntity, CobblemonBlocks.DYNITE_ORE)
.build(null)
)
}
@@ -96,6 +96,15 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
@JvmField
val DEEPSLATE_WATER_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_water_stone_ore")
@JvmField
val DYNITE_ORE = this.create("dynite_ore", DyniteOreBlock(
AbstractBlock.Settings.create()
.mapColor(MapColor.BRIGHT_RED)
.strength(4.5f, 3f)
.requiresTool()
.sounds(BlockSoundGroup.METAL)
))
// Apricorns
@JvmField
val APRICORN_LOG = log("apricorn_log", arg2 = MapColor.BROWN)
@@ -11,7 +11,9 @@ package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.pokeball.PokeBalls
import com.cobblemon.mod.common.entity.boat.CobblemonBoatEntity
import com.cobblemon.mod.common.entity.boat.CobblemonChestBoatEntity
import com.cobblemon.mod.common.entity.fallingstar.FallingStarEntity
import com.cobblemon.mod.common.entity.generic.GenericBedrockEntity
import com.cobblemon.mod.common.entity.fishing.PokeRodFishingBobberEntity
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.platform.PlatformRegistry
@@ -75,6 +77,24 @@ object CobblemonEntities : PlatformRegistry<Registry<EntityType<*>>, RegistryKey
.build(GENERIC_BEDROCK_ENTITY_KEY.toString())
)
@JvmField
val FALLING_STAR_ENTITY_KEY = cobblemonResource("falling_star")
@JvmField
val FALLING_STAR_ENTITY: EntityType<FallingStarEntity> = this.create(
FALLING_STAR_ENTITY_KEY.path,
EntityType.Builder.create({ _, world -> FallingStarEntity(world) }, SpawnGroup.MISC)
.build(FALLING_STAR_ENTITY_KEY.toString())
)
@JvmField
val POKE_BOBBER_KEY = cobblemonResource("poke_bobber")
@JvmField
val POKE_BOBBER: EntityType<PokeRodFishingBobberEntity> = this.create(
POKE_BOBBER_KEY.path,
EntityType.Builder.create(::PokeRodFishingBobberEntity, SpawnGroup.MISC).setDimensions(0.5F, 0.5F).maxTrackingRange(10)
.build(POKE_BOBBER_KEY.toString())
)
fun registerAttributes(consumer: (EntityType<out LivingEntity>, DefaultAttributeContainer.Builder) -> Unit) {
consumer(POKEMON, PokemonEntity.createAttributes())
}
@@ -29,6 +29,7 @@ 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.interactive.*
import com.cobblemon.mod.common.item.interactive.PotionItem
import com.cobblemon.mod.common.platform.PlatformRegistry
import com.cobblemon.mod.common.pokeball.PokeBall
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
@@ -37,6 +38,7 @@ import net.minecraft.block.Block
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.effect.StatusEffectInstance
import net.minecraft.entity.effect.StatusEffects
import net.minecraft.item.*
import net.minecraft.item.BlockItem
import net.minecraft.item.FoodComponent
import net.minecraft.item.HangingSignItem
@@ -578,6 +580,9 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
@JvmField
val NETHER_FIRE_STONE_ORE = blockItem("nether_fire_stone_ore", CobblemonBlocks.NETHER_FIRE_STONE_ORE)
@JvmField
val DYNITE_ORE = blockItem("dynite_ore", CobblemonBlocks.DYNITE_ORE)
@JvmField
val DAWN_STONE = noSettingsItem("dawn_stone")
@JvmField
@@ -821,6 +826,9 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
SmithingTemplateItem.of(CobblemonArmorTrims.AUTOMATON)
)
@JvmField
val POKEROD = pokerodItem("pokerod")
// Misc
@JvmField
val POKEMON_MODEL = this.create("pokemon_model", PokemonItem())
@@ -842,6 +850,12 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
private fun candyItem(name: String, calculator: CandyItem.Calculator): CandyItem = this.create(name, CandyItem(calculator))
private fun pokerodItem(name: String): PokerodItem {
var settings = Item.Settings()
val item = create(name, PokerodItem(settings))
return item
}
private fun heldItem(name: String, remappedName: String? = null): CobblemonItem = create(
name,
CobblemonItem(Item.Settings()).also {
@@ -10,19 +10,8 @@ package com.cobblemon.mod.common.api.spawning
import com.cobblemon.mod.common.Cobblemon.LOGGER
import com.cobblemon.mod.common.api.entity.Despawner
import com.cobblemon.mod.common.api.spawning.condition.AreaSpawningCondition
import com.cobblemon.mod.common.api.spawning.condition.BasicSpawningCondition
import com.cobblemon.mod.common.api.spawning.condition.GroundedSpawningCondition
import com.cobblemon.mod.common.api.spawning.condition.SpawningCondition
import com.cobblemon.mod.common.api.spawning.condition.SubmergedSpawningCondition
import com.cobblemon.mod.common.api.spawning.condition.SurfaceSpawningCondition
import com.cobblemon.mod.common.api.spawning.context.AreaContextResolver
import com.cobblemon.mod.common.api.spawning.context.GroundedSpawningContext
import com.cobblemon.mod.common.api.spawning.context.LavafloorSpawningContext
import com.cobblemon.mod.common.api.spawning.context.SeafloorSpawningContext
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
import com.cobblemon.mod.common.api.spawning.context.SubmergedSpawningContext
import com.cobblemon.mod.common.api.spawning.context.SurfaceSpawningContext
import com.cobblemon.mod.common.api.spawning.condition.*
import com.cobblemon.mod.common.api.spawning.context.*
import com.cobblemon.mod.common.api.spawning.context.calculators.GroundedSpawningContextCalculator
import com.cobblemon.mod.common.api.spawning.context.calculators.LavafloorSpawningContextCalculator
import com.cobblemon.mod.common.api.spawning.context.calculators.SeafloorSpawningContextCalculator
@@ -32,6 +21,8 @@ import com.cobblemon.mod.common.api.spawning.context.calculators.SurfaceSpawning
import com.cobblemon.mod.common.api.spawning.detail.PokemonSpawnDetail
import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
import com.cobblemon.mod.common.api.spawning.fallingstar.FallingStarSpawner
import com.cobblemon.mod.common.api.spawning.fishing.FishingSpawner
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
import com.cobblemon.mod.common.api.spawning.preset.BasicSpawnDetailPreset
import com.cobblemon.mod.common.api.spawning.preset.BestSpawnerConfig
@@ -83,6 +74,8 @@ object BestSpawner {
var config = BestSpawnerConfig()
val spawnerManagers = mutableListOf<SpawnerManager>(CobblemonWorldSpawnerManager)
var defaultPokemonDespawner: Despawner<PokemonEntity> = CobblemonAgingDespawner(getAgeTicks = { it.ticksLived })
lateinit var fishingSpawner: FishingSpawner
lateinit var starSpawner: FallingStarSpawner
fun loadConfig() {
LOGGER.info("Starting the Best Spawner...")
@@ -91,6 +84,8 @@ object BestSpawner {
SpawningCondition.register(SubmergedSpawningCondition.NAME, SubmergedSpawningCondition::class.java)
SpawningCondition.register(GroundedSpawningCondition.NAME, GroundedSpawningCondition::class.java)
SpawningCondition.register(SurfaceSpawningCondition.NAME, SurfaceSpawningCondition::class.java)
SpawningCondition.register(FishingSpawningCondition.NAME, FishingSpawningCondition::class.java)
SpawningCondition.register(FallingStarSpawningCondition.NAME, FallingStarSpawningCondition::class.java)
LOGGER.info("Loaded ${SpawningCondition.conditionTypes.size} spawning condition types.")
SpawningContextCalculator.register(GroundedSpawningContextCalculator)
@@ -104,6 +99,8 @@ object BestSpawner {
SpawningContext.register(name = "lavafloor", clazz = LavafloorSpawningContext::class.java, defaultCondition = GroundedSpawningCondition.NAME)
SpawningContext.register(name = "submerged", clazz = SubmergedSpawningContext::class.java, defaultCondition = SubmergedSpawningCondition.NAME)
SpawningContext.register(name = "surface", clazz = SurfaceSpawningContext::class.java, defaultCondition = SurfaceSpawningCondition.NAME)
SpawningContext.register(name = "fishing", clazz = FishingSpawningContext::class.java, defaultCondition = FishingSpawningCondition.NAME)
SpawningContext.register(name = "fallingstar", clazz = FallingStarSpawningContext::class.java, defaultCondition = FallingStarSpawningCondition.NAME)
LOGGER.info("Loaded ${SpawningContext.contexts.size} spawning context types.")
@@ -118,5 +115,7 @@ object BestSpawner {
fun onServerStarted() {
spawnerManagers.forEach(SpawnerManager::onServerStarted)
fishingSpawner = FishingSpawner()
starSpawner = FallingStarSpawner()
}
}
@@ -0,0 +1,23 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.spawning.condition
import com.cobblemon.mod.common.api.spawning.context.FallingStarSpawningContext
class FallingStarSpawningCondition: SpawningCondition<FallingStarSpawningContext>() {
override fun contextClass() = FallingStarSpawningContext::class.java
override fun fits(ctx: FallingStarSpawningContext): Boolean {
return true
}
companion object {
const val NAME = "fallingstar"
}
}
@@ -0,0 +1,44 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.spawning.condition
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
import com.cobblemon.mod.common.api.spawning.context.FishingSpawningContext
import com.cobblemon.mod.common.util.itemRegistry
import net.minecraft.block.Block
import net.minecraft.item.Item
/**
* A spawning condition that applies to [FishingSpawningContext]s.
*
* @author Hiroku
* @since February 3rd, 2024
*/
class FishingSpawningCondition: SpawningCondition<FishingSpawningContext>() {
override fun contextClass() = FishingSpawningContext::class.java
var rod: RegistryLikeCondition<Item>? = null
var neededNearbyBlocks: MutableList<RegistryLikeCondition<Block>>? = null
override fun fits(ctx: FishingSpawningContext): Boolean {
if (!super.fits(ctx)) {
return false
} else if (rod != null && !rod!!.fits(ctx.rodItem ?: return false, ctx.world.itemRegistry)) {
return false
} else if (neededNearbyBlocks != null && neededNearbyBlocks!!.none { cond -> ctx.nearbyBlockTypes.any { cond.fits(it, ctx.blockRegistry) } }) {
return false
} else {
return true
}
}
companion object {
const val NAME = "fishing"
}
}
@@ -76,4 +76,51 @@ interface AreaContextResolver {
return contexts
}
// fun resolveFishing(
// spawner: Spawner,
// contextCalculators: List<AreaSpawningContextCalculator<*>>,
// slice: WorldSlice
// ): List<AreaSpawningContext> {
// var pos = BlockPos.Mutable(1, 2, 3)
// val input = AreaSpawningInput(spawner, pos, slice)
// val contexts = mutableListOf<AreaSpawningContext>()
//
// var x = slice.baseX
// var y = slice.baseY
// var z = slice.baseZ
//
// while (x < slice.baseX + slice.length) {
// while (y < slice.baseY + slice.height) {
// while (z < slice.baseZ + slice.width) {
// pos.set(x, y, z)
// val vec = pos.toVec3d()
// if (slice.nearbyEntityPositions.none { it.isInRange(vec, 50.0) && it != slice.cause.entity }) {
// val fittedContextCalculator = contextCalculators
// .firstOrNull { calc -> calc.fits(input) && input.spawner.influences.none { !it.isAllowedPosition(input.world, input.position, calc) } }
// if (fittedContextCalculator != null) {
// val context = fittedContextCalculator.calculate(input)
// if (context != null) {
// contexts.add(context)
// // The position BlockPos has been used in a context, editing the same one
// // will cause entities to spawn at the wrong location (buried in walls, usually)
// // I made it so that our context calculators specifically take a copy of the
// // BlockPos but it'd still be exposed in custom contexts so fixing it here too.
// pos = BlockPos.Mutable(1, 2, 3)
// input.position = pos
// }
// }
// }
// z++
// }
// y++
// z = slice.baseZ
// }
// x++
// y = slice.baseY
// z = slice.baseZ
// }
//
// return contexts
// }
}
@@ -0,0 +1,31 @@
/*
* 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.spawning.context
import com.cobblemon.mod.common.api.spawning.fallingstar.FallingStarSpawnCause
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
import net.minecraft.server.world.ServerWorld
import net.minecraft.util.math.BlockPos
class FallingStarSpawningContext(
cause: FallingStarSpawnCause,
world: ServerWorld,
pos: BlockPos,
influences: MutableList<SpawningInfluence>
) : TriggerSpawningContext(
cause = cause,
world = world,
position = pos,
light = world.getLightLevel(pos),
skyLight = world.getLightLevel(pos.up()),
canSeeSky = world.isSkyVisibleAllowingSea(pos),
influences = influences
) {
}
@@ -0,0 +1,44 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.spawning.context
import com.cobblemon.mod.common.api.spawning.fishing.FishingSpawnCause
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
import com.cobblemon.mod.common.util.getBlockStates
import com.cobblemon.mod.common.util.toVec3d
import net.minecraft.block.Block
import net.minecraft.server.world.ServerWorld
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Box
/**
* A spawning context that was generated for a fishing action.
*
* @author Hiroku
* @since February 3rd, 2024
*/
class FishingSpawningContext(
cause: FishingSpawnCause,
world: ServerWorld,
pos: BlockPos,
influences: MutableList<SpawningInfluence>
) : TriggerSpawningContext(
cause = cause,
world = world,
position = pos,
light = world.getLightLevel(pos),
skyLight = world.getLightLevel(pos.up()),
canSeeSky = world.isSkyVisibleAllowingSea(pos),
influences = influences
) {
val nearbyBlocks = world.getBlockStates(Box.of(pos.toVec3d(), 10.0, 10.0, 10.0))
val nearbyBlockTypes: List<Block> by lazy { nearbyBlocks.mapNotNull { it.block }.distinct() }
val rodStack = cause.rodStack
val rodItem = cause.rodItem
}
@@ -0,0 +1,34 @@
/*
* 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.spawning.context
import com.cobblemon.mod.common.api.spawning.SpawnCause
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
import net.minecraft.server.world.ServerWorld
import net.minecraft.util.math.BlockPos
/**
* A spawning context relating to triggered spawning. Uses a single-point structure cache which is
* the only contribution of this implementation.
*
* @author Hiroku
* @since February 3rd, 2024
*/
open class TriggerSpawningContext(
override val cause: SpawnCause,
override val world: ServerWorld,
override val position: BlockPos,
override val light: Int,
override val skyLight: Int,
override val canSeeSky: Boolean,
override val influences: MutableList<SpawningInfluence>
) : SpawningContext() {
val triggerStructureCache = StructureChunkCache()
override fun getStructureCache(pos: BlockPos) = triggerStructureCache
}
@@ -0,0 +1,20 @@
/*
* 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.spawning.fallingstar
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.SpawnCause
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
import net.minecraft.entity.Entity
class FallingStarSpawnCause(
spawner: Spawner,
bucket: SpawnBucket,
entity: Entity?
) : SpawnCause(spawner, bucket, entity)
@@ -0,0 +1,25 @@
/*
* 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.spawning.fallingstar
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnPools
import com.cobblemon.mod.common.api.spawning.context.FallingStarSpawningContext
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
import com.cobblemon.mod.common.api.spawning.spawner.TriggerSpawner
import net.minecraft.server.world.ServerWorld
import net.minecraft.util.math.BlockPos
open class FallingStarSpawner(
override val name: String = "fallingstar",
pool: SpawnPool = CobblemonSpawnPools.WORLD_SPAWN_POOL
) : TriggerSpawner<FallingStarSpawnCause>(name, pool) {
override fun parseContext(cause: FallingStarSpawnCause, world: ServerWorld, pos: BlockPos): FallingStarSpawningContext? {
return FallingStarSpawningContext(cause, world, pos, influences)
}
}
@@ -0,0 +1,32 @@
/*
* 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.spawning.fishing
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.SpawnCause
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
import net.minecraft.entity.Entity
import net.minecraft.item.FishingRodItem
import net.minecraft.item.ItemStack
/**
* A spawning cause that is embellished with fishing information. Could probably also
* have the bobber entity or something.
*
* @author Hiroku
* @since February 3rd, 2024
*/
class FishingSpawnCause(
spawner: Spawner,
bucket: SpawnBucket,
entity: Entity?,
val rodStack: ItemStack
) : SpawnCause(spawner, bucket, entity) {
val rodItem = rodStack.item as? FishingRodItem
}
@@ -0,0 +1,38 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.spawning.fishing
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnPools
import com.cobblemon.mod.common.api.spawning.context.FishingSpawningContext
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
import com.cobblemon.mod.common.api.spawning.spawner.TriggerSpawner
import net.minecraft.server.world.ServerWorld
import net.minecraft.util.math.BlockPos
/**
* A spawner that takes in a [FishingSpawnCause] and spawns things.
*
* @author Hiroku
* @since February 3rd, 2024
*/
open class FishingSpawner(
override val name: String = "fishing",
pool: SpawnPool = CobblemonSpawnPools.WORLD_SPAWN_POOL
) : TriggerSpawner<FishingSpawnCause>(name, pool) {
override fun parseContext(cause: FishingSpawnCause, world: ServerWorld, pos: BlockPos): FishingSpawningContext? {
// Maybe confirm that it's water we're fishing in?
val ctx = FishingSpawningContext(
cause = cause,
world = world,
pos = pos,
influences = influences
)
return ctx
}
}
@@ -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.api.spawning.spawner
import com.cobblemon.mod.common.api.spawning.SpawnCause
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
import com.cobblemon.mod.common.api.spawning.selection.FlatContextWeightedSelector
import com.cobblemon.mod.common.api.spawning.selection.SpawningSelector
import java.util.concurrent.CompletableFuture
import net.minecraft.server.world.ServerWorld
import net.minecraft.util.math.BlockPos
/**
* A type of spawner that occurs at a single point and provides its own means of generating a
* context from a particular cause and position. The trigger spawner must be directly called to
* spawn things (almost as if it was being triggered) as opposed to being scheduled on a ticker.
*
* @author Hiroku
* @since February 3rd, 2024
*/
abstract class TriggerSpawner<T : SpawnCause>(override val name: String, var spawns: SpawnPool) : Spawner {
private var selector: SpawningSelector = FlatContextWeightedSelector()
override val influences = mutableListOf<SpawningInfluence>()
open fun run(cause: T, world: ServerWorld, pos: BlockPos): CompletableFuture<*>? {
val context = parseContext(cause, world, pos) ?: return null
selector.select(this, listOf(context))?.let { (_, spawn) ->
val action = spawn.doSpawn(context)
action.complete()
return action.future
}
return null
}
/** Parses a context, if possible, from the given cause and position. */
abstract fun parseContext(cause: T, world: ServerWorld, pos: BlockPos): SpawningContext?
override fun canSpawn() = true
override fun getSpawningSelector() = selector
override fun setSpawningSelector(selector: SpawningSelector) { this.selector = selector }
override fun getSpawnPool() = spawns
override fun setSpawnPool(spawnPool: SpawnPool) { spawns = spawnPool }
}
@@ -0,0 +1,36 @@
/*
* 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.CobblemonBlockEntities
import com.cobblemon.mod.common.block.entity.DyniteOreBlockEntity
import net.minecraft.block.BlockRenderType
import net.minecraft.block.BlockState
import net.minecraft.block.BlockWithEntity
import net.minecraft.block.entity.BlockEntity
import net.minecraft.block.entity.BlockEntityTicker
import net.minecraft.block.entity.BlockEntityType
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
class DyniteOreBlock(settings: Settings) : BlockWithEntity(settings) {
override fun createBlockEntity(pos: BlockPos, state: BlockState): BlockEntity {
return DyniteOreBlockEntity(pos, state)
}
override fun getRenderType(state: BlockState?) = BlockRenderType.MODEL
override fun <T : BlockEntity> getTicker(
world: World,
state: BlockState,
type: BlockEntityType<T>
): BlockEntityTicker<T>? {
return checkType(type, CobblemonBlockEntities.DYNITE_ORE, DyniteOreBlockEntity.TICKER::tick)
}
}
@@ -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.block.entity
import com.cobblemon.mod.common.CobblemonBlockEntities
import net.minecraft.block.BlockState
import net.minecraft.block.entity.BlockEntity
import net.minecraft.block.entity.BlockEntityTicker
import net.minecraft.util.math.BlockPos
class DyniteOreBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(CobblemonBlockEntities.DYNITE_ORE, pos, state) {
companion object {
internal val TICKER = BlockEntityTicker<DyniteOreBlockEntity> { world, pos, state, blockEntity ->
if (world.isClient) return@BlockEntityTicker
// idk if i'll actually need this but i already made it
}
}
}
@@ -27,6 +27,8 @@ 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.HealingMachineRenderer
import com.cobblemon.mod.common.client.render.boat.CobblemonBoatRenderer
import com.cobblemon.mod.common.client.render.entity.PokeBobberEntityRenderer
import com.cobblemon.mod.common.client.render.entity.FallingStarRenderer
import com.cobblemon.mod.common.client.render.item.CobblemonBuiltinItemRendererRegistry
import com.cobblemon.mod.common.client.render.item.PokemonItemRenderer
import com.cobblemon.mod.common.client.render.layer.PokemonOnShoulderRenderer
@@ -255,6 +257,10 @@ object CobblemonClient {
this.implementation.registerEntityRenderer(CobblemonEntities.BOAT) { ctx -> CobblemonBoatRenderer(ctx, false) }
LOGGER.info("Registering Boat with Chest renderer")
this.implementation.registerEntityRenderer(CobblemonEntities.CHEST_BOAT) { ctx -> CobblemonBoatRenderer(ctx, true) }
LOGGER.info("Registering Falling Star renderer")
this.implementation.registerEntityRenderer(CobblemonEntities.FALLING_STAR_ENTITY) { ctx -> FallingStarRenderer(ctx) }
LOGGER.info("Registering PokeRod Bobber renderer")
this.implementation.registerEntityRenderer(CobblemonEntities.POKE_BOBBER) { ctx -> PokeBobberEntityRenderer(ctx) }
}
fun reloadCodedAssets(resourceManager: ResourceManager) {
@@ -0,0 +1,21 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.entity
import com.cobblemon.mod.common.entity.fallingstar.FallingStarEntity
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.render.entity.EntityRenderer
import net.minecraft.client.render.entity.EntityRendererFactory
import net.minecraft.util.Identifier
class FallingStarRenderer(ctx: EntityRendererFactory.Context?) : EntityRenderer<FallingStarEntity>(ctx) {
override fun getTexture(entity: FallingStarEntity): Identifier {
return cobblemonResource("textures/red")
}
}
@@ -0,0 +1,136 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.entity
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.util.cobblemonResource
import net.fabricmc.api.EnvType
import net.fabricmc.api.Environment
import net.minecraft.client.MinecraftClient
import net.minecraft.client.render.OverlayTexture
import net.minecraft.client.render.RenderLayer
import net.minecraft.client.render.VertexConsumer
import net.minecraft.client.render.VertexConsumerProvider
import net.minecraft.client.render.entity.EntityRenderer
import net.minecraft.client.render.entity.EntityRendererFactory
import net.minecraft.client.render.entity.FishingBobberEntityRenderer
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.entity.projectile.FishingBobberEntity
import net.minecraft.item.Items
import net.minecraft.util.Arm
import net.minecraft.util.Identifier
import net.minecraft.util.math.MathHelper
import net.minecraft.util.math.RotationAxis
import org.joml.Matrix3f
import org.joml.Matrix4f
/*
* Decompiled with CFR 0.2.0 (FabricMC d28b102d).
*/
@Environment(value = EnvType.CLIENT)
class PokeBobberEntityRenderer(context: EntityRendererFactory.Context?) : EntityRenderer<FishingBobberEntity>(context) {
override fun render(fishingBobberEntity: FishingBobberEntity, f: Float, g: Float, matrixStack: MatrixStack, vertexConsumerProvider: VertexConsumerProvider, i: Int) {
var s: Double
val r: Float
val q: Double
val p: Double
val o: Double
val playerEntity = fishingBobberEntity.playerOwner ?: return
matrixStack.push()
matrixStack.push()
matrixStack.scale(0.5f, 0.5f, 0.5f)
matrixStack.multiply(dispatcher.rotation)
matrixStack.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180.0f))
val entry = matrixStack.peek()
val matrix4f = entry.positionMatrix
val matrix3f = entry.normalMatrix
val vertexConsumer = vertexConsumerProvider.getBuffer(PokeBobberEntityRenderer.Companion.LAYER)
PokeBobberEntityRenderer.Companion.vertex(vertexConsumer, matrix4f, matrix3f, i, 0.0f, 0, 0, 1)
PokeBobberEntityRenderer.Companion.vertex(vertexConsumer, matrix4f, matrix3f, i, 1.0f, 0, 1, 1)
PokeBobberEntityRenderer.Companion.vertex(vertexConsumer, matrix4f, matrix3f, i, 1.0f, 1, 1, 0)
PokeBobberEntityRenderer.Companion.vertex(vertexConsumer, matrix4f, matrix3f, i, 0.0f, 1, 0, 0)
matrixStack.pop()
var j = if (playerEntity.mainArm == Arm.RIGHT) 1 else -1
val itemStack = playerEntity.mainHandStack
if (!itemStack.isOf(CobblemonItems.POKEROD)) {
j = -j
}
val h = playerEntity.getHandSwingProgress(g)
val k = MathHelper.sin(MathHelper.sqrt(h) * Math.PI.toFloat())
val l = MathHelper.lerp(g, playerEntity.prevBodyYaw, playerEntity.bodyYaw) * (Math.PI.toFloat() / 180)
val d = MathHelper.sin(l).toDouble()
val e = MathHelper.cos(l).toDouble()
val m = j.toDouble() * 0.35
val n = 0.8
if (dispatcher.gameOptions != null && !dispatcher.gameOptions.perspective.isFirstPerson || playerEntity !== MinecraftClient.getInstance().player) {
o = MathHelper.lerp(g.toDouble(), playerEntity.prevX, playerEntity.x) - e * m - d * 0.8
p = playerEntity.prevY + playerEntity.standingEyeHeight.toDouble() + (playerEntity.y - playerEntity.prevY) * g.toDouble() - 0.45
q = MathHelper.lerp(g.toDouble(), playerEntity.prevZ, playerEntity.z) - d * m + e * 0.8
r = if (playerEntity.isInSneakingPose) -0.1875f else 0.0f
} else {
s = 960.0 / dispatcher.gameOptions.fov.value.toDouble()
var vec3d = dispatcher.camera.projection.getPosition(j.toFloat() * 0.525f, -0.1f)
vec3d = vec3d.multiply(s)
vec3d = vec3d.rotateY(k * 0.5f)
vec3d = vec3d.rotateX(-k * 0.7f)
o = MathHelper.lerp(g.toDouble(), playerEntity.prevX, playerEntity.getX()) + vec3d.x
p = MathHelper.lerp(g.toDouble(), playerEntity.prevY, playerEntity.getY()) + vec3d.y
q = MathHelper.lerp(g.toDouble(), playerEntity.prevZ, playerEntity.getZ()) + vec3d.z
r = playerEntity.getStandingEyeHeight()
}
s = MathHelper.lerp(g.toDouble(), fishingBobberEntity.prevX, fishingBobberEntity.x)
val t = MathHelper.lerp(g.toDouble(), fishingBobberEntity.prevY, fishingBobberEntity.y) + 0.25
val u = MathHelper.lerp(g.toDouble(), fishingBobberEntity.prevZ, fishingBobberEntity.z)
val v = (o - s).toFloat()
val w = (p - t).toFloat() + r
val x = (q - u).toFloat()
val vertexConsumer2 = vertexConsumerProvider.getBuffer(RenderLayer.getLineStrip())
val entry2 = matrixStack.peek()
val y = 16
for (z in 0..16) {
renderFishingLine(v, w, x, vertexConsumer2, entry2, percentage(z, 16), percentage(z + 1, 16))
}
matrixStack.pop()
super.render(fishingBobberEntity, f, g, matrixStack, vertexConsumerProvider, i)
}
override fun getTexture(fishingBobberEntity: FishingBobberEntity): Identifier {
return TEXTURE
}
companion object {
private val TEXTURE = cobblemonResource("textures/item/fishing/pokeball_bobber.png")
private val LAYER = RenderLayer.getEntityCutout(TEXTURE)
private const val field_33632 = 960.0
@JvmStatic
private fun percentage(value: Int, max: Int): Float {
return value.toFloat() / max.toFloat()
}
private fun vertex(buffer: VertexConsumer, matrix: Matrix4f, normalMatrix: Matrix3f, light: Int, x: Float, y: Int, u: Int, v: Int) {
buffer.vertex(matrix, x - 0.5f, y.toFloat() - 0.5f, 0.0f).color(255, 255, 255, 255).texture(u.toFloat(), v.toFloat()).overlay(OverlayTexture.DEFAULT_UV).light(light).normal(normalMatrix, 0.0f, 1.0f, 0.0f).next()
}
@JvmStatic
private fun renderFishingLine(x: Float, y: Float, z: Float, buffer: VertexConsumer, matrices: MatrixStack.Entry, segmentStart: Float, segmentEnd: Float) {
val f = x * segmentStart
val g = y * (segmentStart * segmentStart + segmentStart) * 0.5f + 0.25f
val h = z * segmentStart
var i = x * segmentEnd - f
var j = y * (segmentEnd * segmentEnd + segmentEnd) * 0.5f + 0.25f - g
var k = z * segmentEnd - h
val l = MathHelper.sqrt(i * i + j * j + k * k)
i /= l
j /= l
k /= l
buffer.vertex(matrices.positionMatrix, f, g, h).color(0, 0, 0, 255).normal(matrices.normalMatrix, i, j, k).next()
}
}
}
@@ -0,0 +1,40 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.item
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.item.PokerodItem
import net.minecraft.client.item.ClampedModelPredicateProvider
import net.minecraft.client.item.ModelPredicateProvider
import net.minecraft.client.item.ModelPredicateProviderRegistry
import net.minecraft.client.world.ClientWorld
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.util.Identifier
object CobblemonModelPredicateRegistry {
fun registerPredicates() {
ModelPredicateProviderRegistry.register(CobblemonItems.POKEROD, Identifier("cast"), ClampedModelPredicateProvider { stack: ItemStack, world: ClientWorld?, entity: LivingEntity?, seed: Int ->
if (entity == null) {
return@ClampedModelPredicateProvider 0.0f
} else {
val bl = entity.mainHandStack == stack
var bl2 = entity.offHandStack == stack
if (entity.mainHandStack.item is PokerodItem) {
bl2 = false
}
return@ClampedModelPredicateProvider if ((bl || bl2) && entity is PlayerEntity && (entity.fishHook != null)) 1.0f else 0.0f
}
})
}
}
@@ -6,7 +6,6 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.sound
import net.minecraft.client.MinecraftClient
@@ -13,21 +13,21 @@ import com.cobblemon.mod.common.CobblemonEntities
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.api.scheduling.ServerTaskTracker
import com.cobblemon.mod.common.api.scheduling.taskBuilder
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.battles.BattleFormat
import com.cobblemon.mod.common.battles.BattleRegistry
import com.cobblemon.mod.common.battles.BattleSide
import com.cobblemon.mod.common.battles.actor.PlayerBattleActor
import com.cobblemon.mod.common.battles.actor.PokemonBattleActor
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.entity.fallingstar.FallingStarEntity
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticlePacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeStartedPacket
import com.cobblemon.mod.common.particle.SnowstormParticleReader
import com.cobblemon.mod.common.trade.ActiveTrade
import com.cobblemon.mod.common.trade.DummyTradeParticipant
import com.cobblemon.mod.common.trade.PlayerTradeParticipant
import com.cobblemon.mod.common.util.fromJson
import com.cobblemon.mod.common.util.party
import com.cobblemon.mod.common.util.toPokemon
import com.cobblemon.mod.common.util.*
import com.google.gson.GsonBuilder
import com.google.gson.JsonObject
import com.mojang.brigadier.Command
@@ -57,6 +57,9 @@ object TestCommand {
return Command.SINGLE_SUCCESS
}
val player = context.source.player as ServerPlayerEntity
player.sendMessageToClient("There are ".text().append(player.world.getChunk(player.pos.toBlockPos()).getDyniteOre().toString().text().append(" blocks of Dynite Ore in this chunk".text())), false)
try {
// readBerryDataFromCSV()
@@ -0,0 +1,162 @@
/*
* 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.fallingstar
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonEntities
import com.cobblemon.mod.common.api.spawning.BestSpawner
import com.cobblemon.mod.common.api.spawning.fallingstar.FallingStarSpawnCause
import com.cobblemon.mod.common.loot.CobblemonLootTables
import com.cobblemon.mod.common.util.math.DoubleRange
import com.cobblemon.mod.common.util.nextBetween
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticlePacket
import net.minecraft.entity.Entity
import net.minecraft.entity.ItemEntity
import net.minecraft.entity.MovementType
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.loot.context.LootContextParameterSet
import net.minecraft.loot.context.LootContextParameters
import net.minecraft.loot.context.LootContextTypes
import net.minecraft.nbt.NbtCompound
import net.minecraft.server.world.ServerWorld
import net.minecraft.sound.SoundCategory
import net.minecraft.sound.SoundEvents
import net.minecraft.util.Identifier
import net.minecraft.util.math.Vec3d
import net.minecraft.world.World
import net.minecraft.world.explosion.Explosion
import java.time.Instant
import kotlin.random.Random
class FallingStarEntity(world: World) : Entity(CobblemonEntities.FALLING_STAR_ENTITY, world) {
private var particleOne = Identifier("cobblemon:null")
private var particleTwo = Identifier("cobblemon:null")
private var particleThree = Identifier("cobblemon:null")
private var particleAmbient = Identifier("cobblemon:null")
private var particleImpact = Identifier("cobblemon:null")
private var particleTimer: Instant = Instant.now().plusMillis(50)
private var particleAmbientTimer: Instant = Instant.now().plusMillis(1000)
private var hasFallen = false
override fun initDataTracker() {
}
override fun readCustomDataFromNbt(nbt: NbtCompound?) {
}
override fun writeCustomDataToNbt(nbt: NbtCompound?) {
}
override fun tick() {
particleOne = Identifier("cobblemon:meteor_glitter")
particleTwo = Identifier("cobblemon:meteor_trail")
particleThree = Identifier("cobblemon:meteor_falling")
if (velocity.y == 0.0) {
velocity = Vec3d(Random.nextBetween(VELOCITY_RANGE.start, VELOCITY_RANGE.endInclusive), -1.0, Random.nextBetween(VELOCITY_RANGE.start, VELOCITY_RANGE.endInclusive))
particleOne = Identifier("cobblemon:null")
particleTwo = Identifier("cobblemon:null")
particleThree = Identifier("cobblemon:null")
if (Instant.now().isAfter(particleAmbientTimer)) {
particleAmbient = Identifier("cobblemon:meteor_ambient")
particleHandler(particleAmbient, this.pos)
particleAmbientTimer = Instant.now().plusMillis(1000)
}
}
if (!world.getBlockState(blockPos.down()).isAir) {
velocity = Vec3d(0.0, -1.0, 0.0)
if (!world.isClient && !hasFallen) {
particleImpact = Identifier("cobblemon:meteor_impact")
particleHandler(particleImpact, this.pos)
(world as ServerWorld).createExplosion(
this,
x, y, z, // the position of the explosion
0.0f, // the power of the explosion
World.ExplosionSourceType.MOB
)
hasFallen = true
}
}
move(MovementType.SELF, velocity)
val player = closestPlayer
if (player != null) {
reveal(player)
kill()
}
if(Instant.now().isAfter(particleTimer)) {
particleHandler(particleTwo, this.pos)
particleHandler(particleThree, this.pos)
particleTimer = Instant.now().plusMillis(50)
}
particleHandler(particleOne, this.pos)
super.tick()
}
private fun reveal(playerEntity: PlayerEntity) {
world.playSound(null, blockPos, SoundEvents.ENTITY_PLAYER_LEVELUP, SoundCategory.AMBIENT)
val random = random.nextBetween(0, 100)
if (random <= 50) {
spawnPokemon(playerEntity)
} else {
spawnItem()
}
}
private fun spawnItem() {
if (world.isClient) return
val lootTable = world.server?.lootManager?.getLootTable(CobblemonLootTables.FALLING_STAR) ?: return
val stacks = lootTable.generateLoot(LootContextParameterSet.Builder(world as ServerWorld)
.add(LootContextParameters.THIS_ENTITY, this)
.build(LootContextTypes.BARTER))
stacks.forEach { world.spawnEntity(ItemEntity(world, pos.x, pos.y, pos.z, it)) }
particleOne = Identifier("cobblemon:masterball/ballsparkle")
particleHandler(particleOne, this.pos)
}
private fun spawnPokemon(playerEntity: PlayerEntity) {
if (world.isClient) return
val spawner = BestSpawner.starSpawner
val spawnCause = FallingStarSpawnCause(
spawner = spawner,
bucket = Cobblemon.bestSpawner.config.buckets[0],
entity = playerEntity
)
particleOne = Identifier("cobblemon:confetti")
particleHandler(particleOne, this.pos)
val result = spawner.run(spawnCause, world as ServerWorld, blockPos) ?: return
}
private fun particleHandler(id: Identifier, pos: Vec3d) {
val spawnSnowstormParticlePacket = SpawnSnowstormParticlePacket(id, pos)
spawnSnowstormParticlePacket.sendToPlayersAround(pos.x, pos.y, pos.z, 128.0, world.registryKey)
}
override fun shouldRender(distance: Double): Boolean {
return false
}
private val closestPlayer: PlayerEntity?
get() = world.players.firstOrNull { it.pos.distanceTo(pos) < 6.0 }
companion object {
val VELOCITY_RANGE = DoubleRange(-0.25, 0.25)
}
}
@@ -0,0 +1,647 @@
/*
* 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.fishing
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonEntities
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.spawning.*
import com.cobblemon.mod.common.api.spawning.context.AreaContextResolver
import com.cobblemon.mod.common.api.spawning.detail.EntitySpawnResult
import com.cobblemon.mod.common.api.spawning.detail.PokemonSpawnAction
import com.cobblemon.mod.common.api.spawning.detail.SingleEntitySpawnAction
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
import com.cobblemon.mod.common.api.spawning.fishing.FishingSpawnCause
import com.cobblemon.mod.common.api.spawning.influence.PlayerLevelRangeInfluence
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
import com.cobblemon.mod.common.api.spawning.rules.SpawnRule
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawner
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawnerFactory
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
import com.cobblemon.mod.common.api.spawning.spawner.SpawningArea
import com.cobblemon.mod.common.api.text.green
import com.cobblemon.mod.common.api.text.red
import com.cobblemon.mod.common.battles.BattleBuilder
import com.cobblemon.mod.common.command.SpawnPokemonFromPool
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.net.messages.client.spawn.SpawnPokemonPacket
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.commandLang
import com.cobblemon.mod.common.util.isServerSide
import com.cobblemon.mod.common.util.party
import com.cobblemon.mod.common.util.toBlockPos
import com.mongodb.internal.connection.Server
import net.minecraft.advancement.criterion.Criteria
import net.minecraft.block.Blocks
import net.minecraft.enchantment.Enchantment
import net.minecraft.enchantment.Enchantments
import net.minecraft.entity.*
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.entity.projectile.FishingBobberEntity
import net.minecraft.entity.projectile.ProjectileUtil
import net.minecraft.item.ItemStack
import net.minecraft.loot.LootTables
import net.minecraft.loot.context.LootContextParameterSet
import net.minecraft.loot.context.LootContextParameters
import net.minecraft.loot.context.LootContextTypes
import net.minecraft.nbt.NbtCompound
import net.minecraft.nbt.NbtList
import net.minecraft.nbt.NbtType
import net.minecraft.particle.ParticleTypes
import net.minecraft.registry.Registries
import net.minecraft.registry.tag.FluidTags
import net.minecraft.registry.tag.ItemTags
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.server.world.ServerWorld
import net.minecraft.sound.SoundEvents
import net.minecraft.stat.Stats
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.MathHelper
import net.minecraft.util.math.Vec3d
import net.minecraft.util.math.random.Random
import kotlin.random.*
import net.minecraft.world.World
import java.util.*
class PokeRodFishingBobberEntity(type: EntityType<out PokeRodFishingBobberEntity>, world: World) : FishingBobberEntity(type, world) {
private val velocityRandom = Random.create()
private val caughtFish = false
private var outOfOpenWaterTicks = 0
private val field_30665 = 10
// todo is this needed?
//val HOOK_ENTITY_ID = DataTracker.registerData(PokeRodFishingBobberEntity::class.java, TrackedDataHandlerRegistry.INTEGER)
//private val CAUGHT_FISH = DataTracker.registerData(PokeRodFishingBobberEntity::class.java, TrackedDataHandlerRegistry.BOOLEAN)
// todo if so replace these later
var HOOK_ENTITY_ID = 0
var CAUGHT_FISH = false
private var removalTimer = 0
private var hookCountdown = 0
private var waitCountdown = 0
private var fishTravelCountdown = 0
private var fishAngle = 0f
private var inOpenWater = true
private var hookedEntity: Entity? = null
private var state = State.FLYING
private var luckOfTheSeaLevel = 0
private var lureLevel = 0
private var typeCaught= "ITEM"
private var chosenBucket = Cobblemon.bestSpawner.config.buckets[0] // default to first rarity bucket
private var rarityCaught = "COMMON"
private val pokemonSpawnChance = 70 // chance a Pokemon will be fished up % out of 100
constructor(thrower: PlayerEntity, world: World, luckOfTheSea: Int, lure: Int) : this(CobblemonEntities.POKE_BOBBER, world) {
// Copy pasta a LOT
//this(CobblemonEntities.POKE_BOBBER, world, luckOfTheSeaLevel, lureLevel)
owner = thrower
luckOfTheSeaLevel = luckOfTheSea
lureLevel = lure
val f = thrower.pitch
val g = thrower.yaw
val h = MathHelper.cos(-g * 0.017453292f - 3.1415927f)
val i = MathHelper.sin(-g * 0.017453292f - 3.1415927f)
val j = -MathHelper.cos(-f * 0.017453292f)
val k = MathHelper.sin(-f * 0.017453292f)
val d = thrower.x - i.toDouble() * 0.3
val e = thrower.eyeY
val l = thrower.z - h.toDouble() * 0.3
this.refreshPositionAndAngles(d, e, l, g, f)
var vec3d = Vec3d((-i).toDouble(), MathHelper.clamp(-(k / j), -5.0f, 5.0f).toDouble(), (-h).toDouble())
val m = vec3d.length()
vec3d = vec3d.multiply(0.6 / m + random.nextTriangular(0.5, 0.0103365), 0.6 / m + random.nextTriangular(0.5, 0.0103365), 0.6 / m + random.nextTriangular(0.5, 0.0103365))
velocity = vec3d
yaw = (MathHelper.atan2(vec3d.x, vec3d.z) * 57.2957763671875).toFloat()
pitch = (MathHelper.atan2(vec3d.y, vec3d.horizontalLength()) * 57.2957763671875).toFloat()
prevYaw = yaw
prevPitch = pitch
}
fun calculateMinMaxCountdown(weight: Float): Pair<Int, Int> {
// Constants for the target min and max values at weight extremes
val minAtMaxWeight = 20
val maxAtMaxWeight = 40
val minAtMinWeight = 15
val maxAtMinWeight = 20
// Calculate factors for min and max based on the weight
val minFactor = ((minAtMaxWeight - minAtMinWeight) / 100f) * weight + minAtMinWeight
val maxFactor = ((maxAtMaxWeight - maxAtMinWeight) / 100f) * weight + maxAtMinWeight
// Ensure min and max are within the needed bounds
val min = minFactor.toInt().coerceIn(minAtMinWeight, minAtMaxWeight)
val max = maxFactor.toInt().coerceIn(maxAtMinWeight, maxAtMaxWeight)
return Pair(min, max)
}
fun chooseAdjustedSpawnBucket(buckets: List<SpawnBucket>, luckOfTheSeaLevel: Int): SpawnBucket {
val baseIncreases = listOf(5.0F, 1.0F, 0.2F) // Base increases for the first three buckets beyond the first
val adjustedWeights = buckets.mapIndexed { index, bucket ->
if (index == 0) {
// Placeholder, will be recalculated
0.0F
} else {
val increase = if (index < baseIncreases.size) baseIncreases[index] else baseIncreases.last() + (index - baseIncreases.size + 1) * 0.15F
bucket.weight + increase * luckOfTheSeaLevel
}
}.toMutableList()
// Recalculate the first bucket's weight to ensure the total is 100%
val totalAdjustedWeight = adjustedWeights.sum() - adjustedWeights[0] // Corrected to ensure the list contains Floats
adjustedWeights[0] = 100.0F - totalAdjustedWeight + buckets[0].weight
// Random selection based on adjusted weights
val weightSum = adjustedWeights.sum()
val chosenSum = kotlin.random.Random.nextDouble(weightSum.toDouble()).toFloat() // Ensure usage of Random from kotlin.random package
var sum = 0.0F
adjustedWeights.forEachIndexed { index, weight ->
sum += weight
if (sum >= chosenSum) {
return buckets[index]
}
}
return buckets.first() // Fallback
}
/*// make more generic version for other enchants. Pass in id of enchant
fun getEnchantLevel(enchantment: Enchantment): Int {
var pokerodEnchantments: NbtList? = null
if (owner?.isPlayer == true) {
pokerodEnchantments = (owner as PlayerEntity).mainHandStack?.enchantments
}
val luckOfTheSeaEnchantment = pokerodEnchantments?.filter {
if (it is NbtCompound)
if (it.getString("id") == Registries.ENCHANTMENT.getEntry(enchantment).key.toString())
return@filter true
return@filter false
}?.first()
return (luckOfTheSeaEnchantment as? NbtCompound)?.getShort("lvl")?.toInt() ?: 0
}*/
fun isOpenOrWaterAround(pos: BlockPos): Boolean {
var positionType = PositionType.INVALID
for (i in -1..2) {
val positionType2 = this.getPositionType(pos.add(-2, i, -2), pos.add(2, i, 2))
when (positionType2) {
PositionType.INVALID -> return false
PositionType.ABOVE_WATER -> if (positionType == PositionType.INVALID) {
return false
}
PositionType.INSIDE_WATER -> if (positionType == PositionType.ABOVE_WATER) {
return false
}
else -> return false
}
positionType = positionType2
}
return true
}
/*private fun getPositionType(start: BlockPos, end: BlockPos): PokeRodFishingBobberEntity.PositionType? {
return BlockPos.stream(start, end).map { pos: BlockPos? -> this.getPositionType(pos!!) }.reduce { positionType: PokeRodFishingBobberEntity.PositionType, positionType2: PokeRodFishingBobberEntity.PositionType -> if (positionType == positionType2) positionType else PokeRodFishingBobberEntity.PositionType.INVALID } as ((PositionType?, PositionType?) -> PositionType?)?.orElse(PokeRodFishingBobberEntity.PositionType.INVALID) as PokeRodFishingBobberEntity.PositionType
}*/
private fun getPositionType(start: BlockPos, end: BlockPos): PositionType? {
return BlockPos.stream(start, end)
.map { pos -> this.getPositionType(pos) }
.reduce { positionType, positionType2 ->
if (positionType == positionType2) positionType else PositionType.INVALID
}.orElse(PositionType.INVALID)
}
private fun getPositionType(pos: BlockPos): PositionType {
val blockState = world.getBlockState(pos)
return if (!blockState.isAir && !blockState.isOf(Blocks.LILY_PAD)) {
val fluidState = blockState.fluidState
if (fluidState.isIn(FluidTags.WATER) && fluidState.isStill && blockState.getCollisionShape(world, pos).isEmpty) PositionType.INSIDE_WATER else PositionType.INVALID
} else {
PositionType.ABOVE_WATER
}
}
enum class PositionType {
ABOVE_WATER,
INSIDE_WATER,
INVALID
}
private fun setPlayerFishHook(fishingBobber: FishingBobberEntity?) {
val playerEntity = this.playerOwner
if (playerEntity != null) {
playerEntity.fishHook = fishingBobber
}
}
internal enum class State {
FLYING,
HOOKED_IN_ENTITY,
BOBBING
}
// todo custom behavior for fishing logic
private fun tickFishingLogic(pos: BlockPos) {
val serverWorld = world as ServerWorld
var i = 1
val blockPos = pos.up()
if (random.nextFloat() < 0.25f && world.hasRain(blockPos)) {
++i
}
if (random.nextFloat() < 0.5f && !world.isSkyVisible(blockPos)) {
--i
}
if (this.hookCountdown > 0) {
--this.hookCountdown
if (this.hookCountdown <= 0) {
this.waitCountdown = 0
this.fishTravelCountdown = 0
this.CAUGHT_FISH = false
//getDataTracker().set(CAUGHT_FISH, false)
}
} else if (this.fishTravelCountdown > 0) {
this.fishTravelCountdown -= i
if (this.fishTravelCountdown > 0) {
var j: Double
var e: Double
this.fishAngle += random.nextTriangular(0.0, 9.188).toFloat()
val f = this.fishAngle * (Math.PI.toFloat() / 180)
val g = MathHelper.sin(f)
val h = MathHelper.cos(f)
val d = this.x + (g * this.fishTravelCountdown.toFloat() * 0.1f).toDouble()
val blockState = serverWorld.getBlockState(BlockPos.ofFloored(d, (MathHelper.floor(this.y).toFloat() + 1.0f).toDouble().also { e = it } - 1.0, this.z + (h * this.fishTravelCountdown.toFloat() * 0.1f).toDouble().also { j = it }))
if (blockState.isOf(Blocks.WATER)) {
if (random.nextFloat() < 0.15f) {
serverWorld.spawnParticles(ParticleTypes.BUBBLE, d, e - 0.1, j, 1, g.toDouble(), 0.1, h.toDouble(), 0.0)
}
val k = g * 0.04f
val l = h * 0.04f
serverWorld.spawnParticles(ParticleTypes.FISHING, d, e, j, 0, l.toDouble(), 0.01, -k.toDouble(), 1.0)
serverWorld.spawnParticles(ParticleTypes.FISHING, d, e, j, 0, -l.toDouble(), 0.01, k.toDouble(), 1.0)
}
} else {
playSound(SoundEvents.ENTITY_FISHING_BOBBER_SPLASH, 0.25f, 1.0f + (random.nextFloat() - random.nextFloat()) * 0.4f)
val m = this.y + 0.5
serverWorld.spawnParticles(ParticleTypes.BUBBLE, this.x, m, this.z, (1.0f + this.width * 20.0f).toInt(), this.width.toDouble(), 0.0, this.width.toDouble(), 0.2)
serverWorld.spawnParticles(ParticleTypes.FISHING, this.x, m, this.z, (1.0f + this.width * 20.0f).toInt(), this.width.toDouble(), 0.0, this.width.toDouble(), 0.2)
// TODO find a way to make luck of the sea environment increase odds of getting better rarity rates
if (MathHelper.nextInt(random, 0, 100) < this.pokemonSpawnChance) {
// todo do another chance check for rarity and then set typeCaught
this.typeCaught = "POKEMON"
val buckets = Cobblemon.bestSpawner.config.buckets
// choose a spawn bucket according to weights no matter how many there are
chosenBucket = chooseAdjustedSpawnBucket(buckets, luckOfTheSeaLevel)
val reactionMinMax = calculateMinMaxCountdown(chosenBucket.weight)
// set the hook reaction time to be based off the rarity of the bucket chosen
this.hookCountdown = MathHelper.nextInt(random, reactionMinMax.first, reactionMinMax.second)
System.out.println("Player hooked a Pokemon from the bucket: " + chosenBucket.name);
/*if (MathHelper.nextDouble(random, 0.0, 100.0) < this.commonSpawnChance) {
// todo set common spawn
this.hookCountdown = MathHelper.nextInt(random, 20, 40)
this.rarityCaught = "COMMON"
System.out.println("Player hooked a Common Pokemon");
}
else {
if (MathHelper.nextDouble(random, 0.0, 100.0 - this.commonSpawnChance) < this.uncommonSpawnChance) {
// todo set uncommon spawn
this.hookCountdown = MathHelper.nextInt(random, 20, 35)
this.rarityCaught = "UNCOMMON"
System.out.println("Player hooked a Uncommon Pokemon");
}
else {
if (MathHelper.nextDouble(random, 0.0, 100.0 - this.commonSpawnChance - this.uncommonSpawnChance) < this.rareSpawnChance) {
// todo set rare spawn
this.hookCountdown = MathHelper.nextInt(random, 20, 30)
this.rarityCaught = "RARE"
System.out.println("Player hooked a Rare Pokemon");
}
else {
// todo set ultra-rare spawn chance
this.hookCountdown = MathHelper.nextInt(random, 20, 25)
this.rarityCaught = "ULTRA-RARE"
System.out.println("Player hooked an Ultra-Rare Pokemon");
}
}
}*/
}
else {
// todo caught item
this.typeCaught = "ITEM"
this.hookCountdown = MathHelper.nextInt(random, 20, 40)
}
//this.hookCountdown = MathHelper.nextInt(random, 20, 40)
//getDataTracker().set(CAUGHT_FISH, true)
this.CAUGHT_FISH = true
}
} else if (this.waitCountdown > 0) {
this.waitCountdown -= i
var f = 0.15f
if (this.waitCountdown < 20) {
f += (20 - this.waitCountdown).toFloat() * 0.05f
} else if (this.waitCountdown < 40) {
f += (40 - this.waitCountdown).toFloat() * 0.02f
} else if (this.waitCountdown < 60) {
f += (60 - this.waitCountdown).toFloat() * 0.01f
}
if (random.nextFloat() < f) {
var j: Double
var e: Double
val g = MathHelper.nextFloat(random, 0.0f, 360.0f) * (Math.PI.toFloat() / 180)
val h = MathHelper.nextFloat(random, 25.0f, 60.0f)
val d = this.x + (MathHelper.sin(g) * h).toDouble() * 0.1
val blockState = serverWorld.getBlockState(BlockPos.ofFloored(d, (MathHelper.floor(this.y).toFloat() + 1.0f).toDouble().also { e = it } - 1.0, this.z + (MathHelper.cos(g) * h).toDouble() * 0.1.also { j = it }))
if (blockState.isOf(Blocks.WATER)) {
serverWorld.spawnParticles(ParticleTypes.SPLASH, d, e, j, 2 + random.nextInt(2), 0.1, 0.0, 0.1, 0.0)
}
}
if (this.waitCountdown <= 0) {
this.fishAngle = MathHelper.nextFloat(random, 0.0f, 360.0f)
this.fishTravelCountdown = MathHelper.nextInt(random, 20, 80)
}
} else {
this.waitCountdown = MathHelper.nextInt(random, 100, 600)
this.waitCountdown -= this.lureLevel * 20 * 5
}
}
private fun removeIfInvalid(player: PlayerEntity): Boolean {
val itemStack = player.mainHandStack
val itemStack2 = player.offHandStack
val bl = itemStack.isOf(CobblemonItems.POKEROD)
val bl2 = itemStack2.isOf(CobblemonItems.POKEROD)
if (player.isRemoved || !player.isAlive || !bl && !bl2 || this.squaredDistanceTo(player) > 1024.0) {
discard()
return true
}
return false
}
private fun checkForCollision() {
val hitResult = ProjectileUtil.getCollision(this) { entity: Entity? -> this.canHit(entity) }
onCollision(hitResult)
}
private fun updateHookedEntityId(entity: Entity?) {
this.hookedEntity = entity
//getDataTracker().set(HOOK_ENTITY_ID, if (entity == null) 0 else entity.id + 1)
this.HOOK_ENTITY_ID = if (entity == null) 0 else entity.id + 1
}
override fun tick() {
velocityRandom.setSeed(getUuid().leastSignificantBits xor world.time)
//super.tick()
val playerEntity = this.playerOwner
if (playerEntity == null) {
discard()
} else if (world.isClient || !removeIfInvalid(playerEntity)) {
if (this.isOnGround) {
++removalTimer
if (removalTimer >= 1200) {
discard()
return
}
} else {
removalTimer = 0
}
var f = 0.0f
val blockPos = blockPos
val fluidState = world.getFluidState(blockPos)
if (fluidState.isIn(FluidTags.WATER)) {
f = fluidState.getHeight(world, blockPos)
}
val bl = f > 0.0f
if (state == State.FLYING) {
if (hookedEntity != null) {
velocity = Vec3d.ZERO
state = State.HOOKED_IN_ENTITY
return
}
if (bl) {
velocity = velocity.multiply(0.3, 0.2, 0.3)
state = State.BOBBING
return
}
checkForCollision()
} else {
if (state == State.HOOKED_IN_ENTITY) {
if (hookedEntity != null) {
if (!hookedEntity!!.isRemoved && hookedEntity!!.world.registryKey === world.registryKey) {
this.setPosition(hookedEntity!!.x, hookedEntity!!.getBodyY(0.8), hookedEntity!!.z)
} else {
updateHookedEntityId(null as Entity?)
state = State.FLYING
}
}
return
}
if (state == State.BOBBING) {
val vec3d = velocity
var d = this.y + vec3d.y - blockPos.y.toDouble() - f.toDouble()
if (Math.abs(d) < 0.01) {
d += Math.signum(d) * 0.1
}
this.setVelocity(vec3d.x * 0.9, vec3d.y - d * random.nextFloat().toDouble() * 0.2, vec3d.z * 0.9)
if (hookCountdown <= 0 && fishTravelCountdown <= 0) {
inOpenWater = true
} else {
inOpenWater = inOpenWater && outOfOpenWaterTicks < 10 && isOpenOrWaterAround(blockPos)
}
if (bl) {
outOfOpenWaterTicks = Math.max(0, outOfOpenWaterTicks - 1)
if (caughtFish) {
velocity = velocity.add(0.0, -0.1 * velocityRandom.nextFloat().toDouble() * velocityRandom.nextFloat().toDouble(), 0.0)
}
if (!world.isClient) {
tickFishingLogic(blockPos)
}
} else {
outOfOpenWaterTicks = Math.min(10, outOfOpenWaterTicks + 1)
}
}
}
if (!fluidState.isIn(FluidTags.WATER)) {
velocity = velocity.add(0.0, -0.03, 0.0)
}
move(MovementType.SELF, velocity)
this.updateRotation()
if (state == State.FLYING && (this.isOnGround || horizontalCollision)) {
velocity = Vec3d.ZERO
}
val e = 0.92 // air friction??
velocity = velocity.multiply(0.92)
refreshPosition()
}
}
override fun use(usedItem: ItemStack): Int {
val playerEntity = this.playerOwner
return if (!world.isClient && playerEntity != null && !removeIfInvalid(playerEntity)) {
var i = 0
if (this.hookedEntity != null) {
pullHookedEntity(this.hookedEntity)
Criteria.FISHING_ROD_HOOKED.trigger(playerEntity as ServerPlayerEntity?, usedItem, this, emptyList())
world.sendEntityStatus(this, 31.toByte())
i = if (this.hookedEntity is ItemEntity) 3 else 5
} else if (this.hookCountdown > 0) {
// check if thing caught was an item
if (this.typeCaught == "ITEM") {
val lootContextParameterSet = LootContextParameterSet.Builder(world as ServerWorld).add(LootContextParameters.ORIGIN, pos).add(LootContextParameters.TOOL, usedItem).add(LootContextParameters.THIS_ENTITY, this).luck(this.luckOfTheSeaLevel.toFloat() + playerEntity.luck).build(LootContextTypes.FISHING)
val lootTable = world.server!!.lootManager.getLootTable(LootTables.FISHING_GAMEPLAY)
val list: List<ItemStack> = lootTable.generateLoot(lootContextParameterSet)
Criteria.FISHING_ROD_HOOKED.trigger(playerEntity as ServerPlayerEntity?, usedItem, this, list)
val var7: Iterator<*> = list.iterator()
while (var7.hasNext()) {
val itemStack = var7.next() as ItemStack
val itemEntity = ItemEntity(world, this.x, this.y, this.z, itemStack)
val d = playerEntity.getX() - this.x
val e = playerEntity.getY() - this.y
val f = playerEntity.getZ() - this.z
val g = 0.1
itemEntity.setVelocity(d * 0.1, e * 0.1 + Math.sqrt(Math.sqrt(d * d + e * e + f * f)) * 0.08, f * 0.1)
world.spawnEntity(itemEntity)
playerEntity.getWorld().spawnEntity(ExperienceOrbEntity(playerEntity.getWorld(), playerEntity.getX(), playerEntity.getY() + 0.5, playerEntity.getZ() + 0.5, random.nextInt(6) + 1))
if (itemStack.isIn(ItemTags.FISHES)) {
playerEntity.increaseStat(Stats.FISH_CAUGHT, 1)
}
}
i = 1
}
else { // logic for spawning Pokemon using rarity
System.out.println("Player reeled in a Pokemon from the bucket: " + chosenBucket.name)
val bobberOwner = playerOwner as ServerPlayerEntity
// spawn the pokemon from the chosen bucket at the bobber's location
spawnPokemonFromFishing(bobberOwner, this, chosenBucket)
val serverWorld = world as ServerWorld
val g = MathHelper.nextFloat(random, 0.0f, 360.0f) * (Math.PI.toFloat() / 180)
val h = MathHelper.nextFloat(random, 25.0f, 60.0f)
val partX = this.x + (MathHelper.sin(g) * h).toDouble() * 0.1
serverWorld.spawnParticles(ParticleTypes.SPLASH, partX, this.y, this.z, 4 + random.nextInt(4), 0.1, 0.0, 0.1, 0.0)
playerEntity.getWorld().spawnEntity(ExperienceOrbEntity(playerEntity.getWorld(), playerEntity.getX(), playerEntity.getY() + 0.5, playerEntity.getZ() + 0.5, random.nextInt(6) + 1))
val bobberBiome = world.getBiome(this.blockPos) // biome of the bobber. But idk if we need this. Probably not anymore
}
}
if (this.isOnGround) {
i = 2
}
discard()
i
} else {
0
}
}
fun spawnPokemonFromFishing(player: PlayerEntity, bobber: PokeRodFishingBobberEntity, chosenBucket: SpawnBucket) {
var hookedEntityID: Int? = null
var hookedEntity: Entity? = null
val spawner = BestSpawner.fishingSpawner
// stealing a ton of stuff from the SpawnFromPool Command
//val spawnCause = SpawnCause(spawner = spawner, bucket = spawner.chooseBucket(), entity = spawner.getCauseEntity())
val spawnCause = FishingSpawnCause(
spawner = spawner,
bucket = chosenBucket,
entity = player,
rodStack = player.mainHandStack // Crab, you should probably parse in the rod item connected to the bobber so we can check enchants in spawn conditions
)
val result = spawner.run(spawnCause, world as ServerWorld, pos.toBlockPos())
if (result == null) {
// This has a chance to fail, if the position has no suitability for a fishing context
// it could also just be a miss which
// means two attempts to spawn in the same location can have differing results (which is expected for
// randomness).
player.sendMessage("Not even a nibble".red())
}
var spawnedPokemon: PokemonEntity? = null
val resultingSpawn = result?.get()
if (resultingSpawn is EntitySpawnResult) {
for (entity in resultingSpawn.entities) {
player.sendMessage(commandLang("spawnpokemonfrompool.success", entity.displayName).green())
//pokemon.uuid = it.uuid
hookedEntityID = entity.id
spawnedPokemon = (entity as PokemonEntity)
// if spawned pokemon is a magikarp then lift it up into the air and over the player
if (spawnedPokemon.pokemon.species.name.equals("magikarp", ignoreCase = true)) {
// Direction and position calculations as before
val rad = Math.toRadians(player.yaw.toDouble() + 180)
val behindDirection = Vec3d(-Math.sin(rad), 0.0, Math.cos(rad))
val targetPos = player.pos.add(behindDirection.multiply(2.0))
val diff = targetPos.subtract(entity.pos)
val distance = diff.horizontalLength()
// Simple empirical mapping of distance to launch angle and initial velocity
val angle = when {
distance < 5 -> 60 // Closer targets, higher arc
distance < 10 -> 45 // Moderate distance, moderate arc
else -> 30 // Farther targets, lower arc
}
// Adjust velocity based on distance and angle
// These are placeholder values; you'll need to adjust based on testing
val velocityMultiplier = when {
distance < 5 -> 0.3
distance < 10 -> 0.5
distance < 20 -> .8
else -> 1.2
}
val velocityX = diff.x / distance * velocityMultiplier
val velocityZ = diff.z / distance * velocityMultiplier
// Calculate Y velocity component based on chosen angle, simplified
val velocityY = when {
distance < 5 -> 0.4
distance < 10 -> 0.5
distance < 20 -> 0.8
else -> 0.9
}
val tossVelocity = Vec3d(velocityX, velocityY, velocityZ)
entity.setVelocity(tossVelocity)
}
}
}
// What if it isn't an entity though
hookedEntity = world.getEntityById(hookedEntityID!!)
//val spawnedPokemon = spawnAction.entity
if (spawnedPokemon != null) {
BattleBuilder.pve((player as ServerPlayerEntity), spawnedPokemon).ifErrored { it.sendTo(player) { it.red() } }
}
}
}
@@ -231,6 +231,7 @@ object CobblemonItemGroups {
entries.add(CobblemonItems.DEEPSLATE_THUNDER_STONE_ORE)
entries.add(CobblemonItems.WATER_STONE_ORE)
entries.add(CobblemonItems.DEEPSLATE_WATER_STONE_ORE)
entries.add(CobblemonItems.DYNITE_ORE)
}
private fun consumableEntries(displayContext: DisplayContext, entries: Entries) {
@@ -428,6 +429,7 @@ object CobblemonItemGroups {
private fun pokeballentries(displayContext: DisplayContext, entries: Entries) {
CobblemonItems.pokeBalls.forEach(entries::add)
entries.add(CobblemonItems.POKEROD)
}
private fun foodInjections(injector: Injector) {
@@ -0,0 +1,112 @@
/*
* 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/.
*/
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.cobblemon.mod.common.item
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.entity.fishing.PokeRodFishingBobberEntity
import com.cobblemon.mod.common.item.CobblemonItem
import net.minecraft.enchantment.EnchantmentHelper
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.item.FishingRodItem
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.item.Item.Settings
import net.minecraft.entity.projectile.FishingBobberEntity
import net.minecraft.item.Items
import net.minecraft.sound.SoundCategory
import net.minecraft.sound.SoundEvents
import net.minecraft.stat.Stats
import net.minecraft.util.Hand
import net.minecraft.util.TypedActionResult
import net.minecraft.world.World
import net.minecraft.world.event.GameEvent
class PokerodItem(settings: Settings?) : FishingRodItem(settings) {
override fun use(world: World, user: PlayerEntity, hand: Hand): TypedActionResult<ItemStack> {
val itemStack = user.getStackInHand(hand)
val i: Int
if (user.fishHook != null) { // if the bobber is out yet
if (!world.isClient) {
i = user.fishHook!!.use(itemStack)
itemStack.damage(i, user) { p: PlayerEntity -> p.sendToolBreakStatus(hand) }
}
world.playSound(null as PlayerEntity?, user.x, user.y, user.z, SoundEvents.ENTITY_FISHING_BOBBER_RETRIEVE, SoundCategory.NEUTRAL, 1.0f, 0.4f / (world.getRandom().nextFloat() * 0.4f + 0.8f))
user.emitGameEvent(GameEvent.ITEM_INTERACT_FINISH)
} else { // if the bobber is not out yet
world.playSound(null as PlayerEntity?, user.x, user.y, user.z, SoundEvents.ENTITY_FISHING_BOBBER_THROW, SoundCategory.NEUTRAL, 0.5f, 0.4f / (world.getRandom().nextFloat() * 0.4f + 0.8f))
if (!world.isClient) {
i = EnchantmentHelper.getLure(itemStack)
val j = EnchantmentHelper.getLuckOfTheSea(itemStack)
world.spawnEntity(PokeRodFishingBobberEntity(user, world, j, i))
}
user.incrementStat(Stats.USED.getOrCreateStat(this))
user.emitGameEvent(GameEvent.ITEM_INTERACT_START)
}
return TypedActionResult.success(itemStack, world.isClient())
}
// todo Round 2
/*override fun use(world: World, user: PlayerEntity, hand: Hand): TypedActionResult<ItemStack> {
val itemStack = user.getStackInHand(hand)
// Play the throw sound
world.playSound(null as PlayerEntity?, user.x, user.y, user.z, SoundEvents.ENTITY_FISHING_BOBBER_THROW, SoundCategory.NEUTRAL, 0.5f, 0.4f / (world.getRandom().nextFloat() * 0.4f + 0.8f))
// Spawn the FishingBobberEntity directly without checking for an existing one
if (!world.isClient) {
val i = EnchantmentHelper.getLure(itemStack)
val j = EnchantmentHelper.getLuckOfTheSea(itemStack)
world.spawnEntity(PokeBobberEntity(user, world, j, i))
}
// Record the usage of the item
user.incrementStat(Stats.USED.getOrCreateStat(this))
user.emitGameEvent(GameEvent.ITEM_INTERACT_START)
return TypedActionResult.success(itemStack, world.isClient())
}*/
// todo Round 3 Best so far
/*override fun use(world: World, player: PlayerEntity, hand: Hand): TypedActionResult<ItemStack> {
if (!world.isClient) {
val itemStack = player.getStackInHand(hand)
// Calculate initial position and velocity for PokeBobberEntity
val currentPose = player.pose
val eyeHeight = player.getEyeHeight(currentPose)
val spawnPos = player.pos.add(0.0, eyeHeight.toDouble(), 0.0)
val direction = player.getRotationVec(1.0f)
val velocity = direction.multiply(1.5)
System.out.println("Spawn Position: " + spawnPos);
System.out.println("Velocity: " + velocity);
// Create and spawn PokeBobberEntity
val pokeBobber = PokeRodFishingBobberEntity(player, world, 0, 0)
pokeBobber.setPos(spawnPos.x, spawnPos.y, spawnPos.z)
pokeBobber.setVelocity(velocity.x, velocity.y, velocity.z)
//pokeBobber.use(ItemStack(CobblemonItems.POKEROD))
world.spawnEntity(pokeBobber)
//pokeBobber.use(ItemStack(Items.FISHING_ROD))
pokeBobber.use(itemStack)
}
return TypedActionResult.success(player.getStackInHand(hand))
}*/
override fun getEnchantability(): Int {
return 1
}
}
@@ -0,0 +1,9 @@
package com.cobblemon.mod.common.loot
import com.cobblemon.mod.common.util.cobblemonResource
object CobblemonLootTables {
val FALLING_STAR = cobblemonResource("entities/fallingstar")
}
@@ -8,6 +8,9 @@
package com.cobblemon.mod.common.util
import com.cobblemon.mod.common.CobblemonBlockEntities
import com.cobblemon.mod.common.CobblemonBlocks
import com.cobblemon.mod.common.block.entity.DyniteOreBlockEntity
import net.minecraft.block.BlockState
import net.minecraft.entity.Entity
import net.minecraft.item.Item
@@ -24,6 +27,7 @@ import net.minecraft.util.math.MathHelper.floor
import net.minecraft.world.BlockView
import net.minecraft.world.World
import net.minecraft.world.biome.Biome
import net.minecraft.world.chunk.Chunk
fun World.playSoundServer(
position: Vec3d,
@@ -124,3 +128,15 @@ val World.itemRegistry: Registry<Item>
get() = registryManager.get(RegistryKeys.ITEM)
val World.biomeRegistry: Registry<Biome>
get() = registryManager.get(RegistryKeys.BIOME)
/**
* @return The amount of Dynite Ore in this chunk
* @author whatsy
*/
fun Chunk.getDyniteOre(): Int {
var count = 0
this.blockEntityPositions.forEach {
if (getBlockEntity(it) is DyniteOreBlockEntity) count++
}
return count
}
@@ -0,0 +1,60 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:meteor_ambient",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/shiny"
}
},
"curves": {
"variable.size": {
"type": "linear",
"input": "v.particle_age * 2",
"horizontal_range": "v.particle_lifetime",
"nodes": [0.5, 1, 0]
}
},
"components": {
"minecraft:emitter_rate_instant": {
"num_particles": 1
},
"minecraft:emitter_lifetime_looping": {
"active_time": 1
},
"minecraft:emitter_shape_sphere": {
"offset": [0, 0.3, 0],
"radius": 0.3,
"direction": "outwards"
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1
},
"minecraft:particle_initial_speed": 0,
"minecraft:particle_motion_dynamic": {},
"minecraft:particle_appearance_billboard": {
"size": ["math.clamp(variable.particle_random_3,0.05,0.1) * variable.size", "math.clamp(variable.particle_random_3,0.05,0.1) * variable.size"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 8,
"texture_height": 16,
"uv": [0, 0],
"uv_size": [8, 8]
}
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "variable.particle_random_3 * 1.2",
"gradient": {
"0.0": "#FFFFF9D3",
"0.25": "#FFDFFFCA",
"0.5": "#FFBCFCFF",
"0.74": "#FFFFB7B7",
"1.0": "#FFD7BDFF"
}
}
}
}
}
}
@@ -0,0 +1,57 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:meteor_fallen",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/bigsparkle"
}
},
"components": {
"minecraft:emitter_rate_instant": {
"num_particles": 1
},
"minecraft:emitter_lifetime_once": {
"active_time": 1
},
"minecraft:emitter_shape_point": {},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1
},
"minecraft:particle_initial_spin": {
"rotation": 13
},
"minecraft:particle_initial_speed": 0,
"minecraft:particle_motion_dynamic": {},
"minecraft:particle_appearance_billboard": {
"size": [0.8, 0.8],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 16,
"texture_height": 96,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [16, 16],
"step_UV": [0, 16],
"frames_per_second": 6,
"max_frame": 6,
"loop": true
}
}
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "(v.particle_age / v.particle_lifetime) * variable.particle_random_3",
"gradient": {
"0.0": "#FFFFEBB8",
"0.27": "#FFC3FFC1",
"0.5": "#FFA2F3FF",
"0.77": "#FFB2A9FF",
"1.0": "#FFFF9A9A"
}
}
}
}
}
}
@@ -0,0 +1,51 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:meteor_falling",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/bigsparkle"
}
},
"components": {
"minecraft:emitter_rate_instant": {
"num_particles": 1
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.13
},
"minecraft:emitter_shape_point": {},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 0.13
},
"minecraft:particle_initial_spin": {
"rotation": 13
},
"minecraft:particle_initial_speed": 0,
"minecraft:particle_motion_dynamic": {},
"minecraft:particle_appearance_billboard": {
"size": [0.8, 0.8],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 16,
"texture_height": 96,
"uv": [0, 48],
"uv_size": [16, 16]
}
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "(v.particle_age / v.particle_lifetime) * variable.particle_random_3",
"gradient": {
"0.0": "#FFFFEBB8",
"0.27": "#FFC3FFC1",
"0.5": "#FFA2F3FF",
"0.77": "#FFB2A9FF",
"1.0": "#FFFF9A9A"
}
}
}
}
}
}
@@ -0,0 +1,77 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:meteor_glitter",
"basic_render_parameters": {
"material": "particles_opaque",
"texture": "textures/particles/pokeball_sparkle_yellow"
}
},
"curves": {
"variable.size": {
"type": "linear",
"input": "v.particle_age",
"horizontal_range": "v.particle_lifetime",
"nodes": [1, 1]
},
"variable.radius": {
"type": "linear",
"input": "v.particle_age",
"horizontal_range": "v.particle_lifetime",
"nodes": [1, 4]
}
},
"components": {
"minecraft:emitter_rate_steady": {
"spawn_rate": 20,
"max_particles": 100
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.5
},
"minecraft:emitter_shape_sphere": {
"radius": "0.8 * variable.radius",
"direction": "outwards"
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 0.5
},
"minecraft:particle_initial_spin": {
"rotation": "math.random(-360,360)"
},
"minecraft:particle_initial_speed": 2,
"minecraft:particle_motion_dynamic": {
"linear_drag_coefficient": 1.8
},
"minecraft:particle_appearance_billboard": {
"size": ["0.5*variable.size", "0.5*variable.size"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 8,
"texture_height": 32,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [8, 8],
"step_UV": [0, 8],
"frames_per_second": 12,
"max_frame": 5,
"stretch_to_lifetime": true
}
}
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.particle_age / v.particle_lifetime",
"gradient": {
"0.0": "#FF98F1FD",
"0.26": "#FFFFFDAE",
"0.5": "#FFFFB1FB",
"0.74": "#FF8EFFA7",
"1.0": "#ffffffff"
}
}
}
}
}
}
@@ -0,0 +1,71 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:meteor_impact",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/star"
}
},
"curves": {
"variable.size": {
"type": "linear",
"input": "v.particle_age * 1.2",
"horizontal_range": "v.particle_lifetime",
"nodes": [0, 1, 0]
}
},
"components": {
"minecraft:emitter_rate_instant": {
"num_particles": 5
},
"minecraft:emitter_lifetime_once": {
"active_time": 1
},
"minecraft:emitter_shape_point": {
"offset": [0, 0.1, 0],
"direction": ["math.random(-2,2)", 3, "math.random(-2,2)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 2
},
"minecraft:particle_initial_spin": {
"rotation": "math.random(0,360)",
"rotation_rate": "variable.particle_random_3 * 360"
},
"minecraft:particle_initial_speed": 7,
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, -8, 0],
"linear_drag_coefficient": 2
},
"minecraft:particle_appearance_billboard": {
"size": ["math.clamp(variable.particle_random_3,0.2,0.3) * variable.size", "math.clamp(variable.particle_random_3,0.2,0.3) * variable.size"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 16,
"texture_height": 32,
"uv": [0, 0],
"uv_size": [16, 16]
}
},
"minecraft:particle_motion_collision": {
"collision_drag": 0.1,
"coefficient_of_restitution": 0.7,
"collision_radius": 0.1
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "variable.particle_random_2",
"gradient": {
"0.0": "#FFFFFBD3",
"0.19": "#FFFFCDCD",
"0.5": "#FFBCFFC1",
"0.71": "#FFBECAFF",
"1.0": "#FFDFBCFF"
}
}
}
}
}
}
@@ -0,0 +1,71 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:meteor_trail",
"basic_render_parameters": {
"material": "particles_opaque",
"texture": "textures/particles/impact-fairy"
}
},
"curves": {
"variable.size": {
"type": "linear",
"input": "v.particle_age",
"horizontal_range": "v.particle_lifetime",
"nodes": [1, 1, 1]
}
},
"components": {
"minecraft:emitter_rate_steady": {
"spawn_rate": 30,
"max_particles": 100
},
"minecraft:emitter_lifetime_once": {
"active_time": 1
},
"minecraft:emitter_shape_sphere": {
"radius": 0.3,
"direction": "outwards"
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 0.5
},
"minecraft:particle_initial_spin": {
"rotation": "math.random(-360,360)"
},
"minecraft:particle_initial_speed": 1,
"minecraft:particle_motion_dynamic": {
"linear_drag_coefficient": 1.7
},
"minecraft:particle_appearance_billboard": {
"size": ["0.2 * variable.size", "0.2 * variable.size"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 8,
"texture_height": 56,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [8, 8],
"step_UV": [0, 8],
"frames_per_second": 12,
"max_frame": 7,
"stretch_to_lifetime": true
}
}
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "variable.particle_random_2",
"gradient": {
"0.0": "#FFFA9999",
"0.23": "#FFFFF5BA",
"0.5": "#FFBCFF9A",
"0.74": "#FF5FE1FF",
"1.0": "#FFFFFFFF"
}
}
}
}
}
}
@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "cobblemon:block/dynite_ore"
}
}
}
@@ -48,6 +48,8 @@
"item.cobblemon.ancient_jet_ball": "Ancient Jet Ball",
"item.cobblemon.ancient_origin_ball": "Ancient Origin Ball",
"item.cobblemon.pokerod": "Pokérod",
"item.cobblemon.black_apricorn_seed": "Black Apricorn Sprout",
"item.cobblemon.blue_apricorn_seed": "Blue Apricorn Sprout",
"item.cobblemon.green_apricorn_seed": "Green Apricorn Sprout",
@@ -1415,6 +1417,7 @@
"block.cobblemon.deepslate_water_stone_ore": "Deepslate Water Stone Ore",
"block.cobblemon.dripstone_moon_stone_ore": "Dripstone Moon Stone Ore",
"block.cobblemon.nether_fire_stone_ore": "Nether Fire Stone Ore",
"block.cobblemon.dynite_ore": "Dynite Ore",
"block.cobblemon.pasture": "Pasture Block",
"gamerule.doPokemonSpawning": "Spawn Pokémon",
@@ -3306,6 +3309,7 @@
"cobblemon.entity.pokemon": "Pokémon",
"entity.cobblemon.empty_pokeball": "Empty Poké Ball",
"entity.cobblemon.falling_star": "Falling Star",
"cobblemon.species.bulbasaur.name": "Bulbasaur",
"cobblemon.species.bulbasaur.desc": "While it is young, it uses the nutrients that are stored in the seed on its back in order to grow.",
@@ -0,0 +1,7 @@
{
"parent": "minecraft:block/cube_all",
"textures": {
"all": "cobblemon:block/dynite_ore"
}
}
@@ -0,0 +1,14 @@
{
"parent": "item/handheld_rod",
"textures": {
"layer0": "cobblemon:item/fishing/pokerod"
},
"overrides": [
{
"predicate": {
"cast": 1
},
"model": "cobblemon:item/pokerod_cast"
}
]
}
@@ -0,0 +1,6 @@
{
"parent": "cobblemon:item/pokerod",
"textures": {
"layer0": "cobblemon:item/fishing/pokerod_cast"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 B

@@ -96,6 +96,8 @@ transitive-accessible field net/minecraft/client/model/ModelPart$Cuboid sides [L
transitive-accessible class net/minecraft/client/model/ModelPart$Quad
transitive-accessible method net/minecraft/entity/ai/brain/Activity <init> (Ljava/lang/String;)V
#accessible method net/minecraft/client/render/RenderLayer$MultiPhase (Ljava/lang/String;Lnet/minecraft/client/render/VertexFormat;Lnet/minecraft/client/render/VertexFormat$DrawMode;IZZLnet/minecraft/client/render/RenderLayer$MultiPhaseParameters;)Lnet/minecraft/client/render/RenderLayer$MultiPhase;
accessible method net/minecraft/client/item/ModelPredicateProviderRegistry register (Lnet/minecraft/util/Identifier;Lnet/minecraft/client/item/ClampedModelPredicateProvider;)V
accessible method net/minecraft/client/item/ModelPredicateProviderRegistry register (Lnet/minecraft/item/Item;Lnet/minecraft/util/Identifier;Lnet/minecraft/client/item/ClampedModelPredicateProvider;)V
#accessible method net/minecraft/client/render/RenderLayer$MultiPhase (Ljava/lang/String;Lnet/minecraft/client/render/VertexFormat;Lnet/minecraft/client/render/VertexFormat$DrawMode;IZZLnet/minecraft/client/render/RenderLayer$MultiPhaseParameters;)Lnet/minecraft/client/render/RenderLayer$MultiPhase;
#String name, VertexFormat vertexFormat, VertexFormat.DrawMode drawMode, int expectedBufferSize, boolean hasCrumbling, boolean translucent, MultiPhaseParameters phases
@@ -0,0 +1,14 @@
{
"type": "minecraft:generic",
"pools": [
{
"rolls": 1,
"entries": [
{
"type": "minecraft:item",
"name": "cobblemon:poke_ball"
}
]
}
]
}
@@ -0,0 +1,18 @@
{
"type": "minecraft:crafting_shaped",
"key": {
"#": {
"item": "minecraft:fishing_rod"
},
"X": {
"item": "cobblemon:poke_ball"
}
},
"pattern": [
"# ",
" X"
],
"result": {
"item": "cobblemon:pokerod"
}
}
@@ -70,6 +70,15 @@
"#cobblemon:is_ocean"
]
}
},
{
"id": "magikarp-fishing-1",
"pokemon": "magikarp",
"type": "pokemon",
"context": "fishing",
"bucket": "common",
"level": "1-20",
"weight": 1.98
}
]
}
@@ -0,0 +1,16 @@
{
"enabled": true,
"neededInstalledMods": [],
"neededUninstalledMods": [],
"spawns": [
{
"id": "minior-fallingstar-1",
"pokemon": "minior",
"type": "pokemon",
"context": "fallingstar",
"bucket": "common",
"level": "1-20",
"weight": 1.98
}
]
}
@@ -13,6 +13,8 @@ import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.CobblemonClient.reloadCodedAssets
import com.cobblemon.mod.common.client.keybind.CobblemonKeyBinds
import com.cobblemon.mod.common.client.render.atlas.CobblemonAtlases
import com.cobblemon.mod.common.client.render.item.CobblemonModelPredicateRegistry
import com.cobblemon.mod.common.client.render.models.blockbench.repository.BerryModelRepository
import com.cobblemon.mod.common.particle.CobblemonParticles
import com.cobblemon.mod.common.particle.SnowstormParticleType
import com.cobblemon.mod.common.platform.events.ClientPlayerEvent
@@ -41,6 +43,7 @@ import net.minecraft.block.entity.BlockEntity
import net.minecraft.block.entity.BlockEntityType
import net.minecraft.client.color.block.BlockColorProvider
import net.minecraft.client.color.item.ItemColorProvider
import net.minecraft.client.item.ModelPredicateProviderRegistry
import net.minecraft.client.model.TexturedModelData
import net.minecraft.client.particle.ParticleFactory
import net.minecraft.client.particle.SpriteProvider
@@ -96,6 +99,8 @@ class CobblemonFabricClient: ClientModInitializer, CobblemonClientImplementation
ClientPlayConnectionEvents.JOIN.register { _, _, client -> client.player?.let { PlatformEvents.CLIENT_PLAYER_LOGIN.post(ClientPlayerEvent.Login(it)) } }
ClientPlayConnectionEvents.DISCONNECT.register { _, client -> client.player?.let { PlatformEvents.CLIENT_PLAYER_LOGOUT.post(ClientPlayerEvent.Logout(it)) } }
ItemTooltipCallback.EVENT.register { stack, context, lines -> PlatformEvents.CLIENT_ITEM_TOOLTIP.post(ItemTooltipEvent(stack, context, lines)) }
CobblemonModelPredicateRegistry.registerPredicates()
}
override fun registerLayer(modelLayer: EntityModelLayer, supplier: Supplier<TexturedModelData>) {
@@ -17,6 +17,7 @@ import com.cobblemon.mod.common.client.CobblemonClient.reloadCodedAssets
import com.cobblemon.mod.common.client.keybind.CobblemonKeyBinds
import com.cobblemon.mod.common.compat.LambDynamicLightsCompat
import com.cobblemon.mod.common.client.render.shader.CobblemonShaders
import com.cobblemon.mod.common.client.render.item.CobblemonModelPredicateRegistry
import com.cobblemon.mod.common.item.group.CobblemonItemGroups
import com.cobblemon.mod.common.particle.CobblemonParticles
import com.cobblemon.mod.common.particle.SnowstormParticleType
@@ -84,6 +85,7 @@ object CobblemonForgeClient : CobblemonClientImplementation {
private fun onClientSetup(event: FMLClientSetupEvent) {
event.enqueueWork {
CobblemonClient.initialize(this)
CobblemonModelPredicateRegistry.registerPredicates()
this.attemptModCompat()
}
ForgeClientPlatformEventHandler.register()