forked from mirrors/cobblemon
Compare commits
144
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8621315fc9 | ||
|
|
5a37693101 | ||
|
|
6c7cd05f10 | ||
|
|
79627395c2 | ||
|
|
280bcb5bf3 | ||
|
|
b2bc425fc9 | ||
|
|
a025d852af | ||
|
|
20076d0d73 | ||
|
|
290a549911 | ||
|
|
c878fbdade | ||
|
|
f9217ac284 | ||
|
|
cf88c88d1d | ||
|
|
21df4a71ec | ||
|
|
34cb074fa8 | ||
|
|
c9639c681c | ||
|
|
58f8edb4a2 | ||
|
|
4e2d6abbee | ||
|
|
4b492fca2e | ||
|
|
92e32b3857 | ||
|
|
d68f62a808 | ||
|
|
b8a6bb2650 | ||
|
|
55c9c9aa9c | ||
|
|
bec467f32e | ||
|
|
0f794690ea | ||
|
|
cb27ae8449 | ||
|
|
21033f6527 | ||
|
|
e95159f9f9 | ||
|
|
7ebe0551e1 | ||
|
|
6e1d4e0c4d | ||
|
|
7aef56c610 | ||
|
|
27e1a34097 | ||
|
|
b25dc6610e | ||
|
|
fa67bba631 | ||
|
|
e6590bef08 | ||
|
|
60b0e70651 | ||
|
|
0d9f8bbb36 | ||
|
|
e75dcd63d1 | ||
|
|
a4fc1442bf | ||
|
|
fb85ceacb0 | ||
|
|
7d9644ba51 | ||
|
|
39c856b69a | ||
|
|
4a4c375f66 | ||
|
|
d22df3e554 | ||
|
|
ed4dadc3f6 | ||
|
|
c2e5e39019 | ||
|
|
f383e5a52f | ||
|
|
914b7c63c9 | ||
|
|
5a17a5ed68 | ||
|
|
bb1a46950f | ||
|
|
679d3eae58 | ||
|
|
a9cd80e496 | ||
|
|
a96cc307bb | ||
|
|
f2b2a282e5 | ||
|
|
5bd7695ce8 | ||
|
|
b42387a23f | ||
|
|
6aa1e6f9ad | ||
|
|
414fcf8278 | ||
|
|
a3c26484a4 | ||
|
|
fbc8883c96 | ||
|
|
baba3f669d | ||
|
|
2fe098adac | ||
|
|
1c770049b4 | ||
|
|
71b854f36a | ||
|
|
61b944a293 | ||
|
|
46ed6d0492 | ||
|
|
72058bb56f | ||
|
|
a7b28ed936 | ||
|
|
96fce55688 | ||
|
|
85daf496d8 | ||
|
|
7b4b498877 | ||
|
|
0ee32c7fd3 | ||
|
|
2c2c1b0cf4 | ||
|
|
218edf680b | ||
|
|
7598a0dacc | ||
|
|
7327a4ddb5 | ||
|
|
f1d3e7b12b | ||
|
|
410ea6be87 | ||
|
|
399dfc33c5 | ||
|
|
26e39bb37d | ||
|
|
4ff7df63c0 | ||
|
|
1d1f749d6d | ||
|
|
d6e4b9c1a6 | ||
|
|
15d3ee0d49 | ||
|
|
de0ed1ab41 | ||
|
|
81d930afae | ||
|
|
b83d75f30f | ||
|
|
5814c1a5d6 | ||
|
|
a45fec50a4 | ||
|
|
576b6ea767 | ||
|
|
792287cb5a | ||
|
|
42ad084dbe | ||
|
|
b9bd61f3dc | ||
|
|
c6d6f98d03 | ||
|
|
abbd17faf7 | ||
|
|
c159137a70 | ||
|
|
03628631f7 | ||
|
|
e5e61df4b2 | ||
|
|
f07c4bf5b1 | ||
|
|
0e3fd520f0 | ||
|
|
935f3100d2 | ||
|
|
8b32764ce3 | ||
|
|
3e5a57ea20 | ||
|
|
6ee94aa55b | ||
|
|
bd5185e69e | ||
|
|
5e8df4609b | ||
|
|
289d1474a6 | ||
|
|
e4604c0d13 | ||
|
|
d4f91fa945 | ||
|
|
5c52a9a31a | ||
|
|
db2efcb48e | ||
|
|
3bcbe2fb45 | ||
|
|
c7202cc869 | ||
|
|
269e18786b | ||
|
|
bd79a4ecfb | ||
|
|
3c3a8b1af9 | ||
|
|
11e2ed34e5 | ||
|
|
1500d6cdf1 | ||
|
|
acbbe2a1ba | ||
|
|
0fe6bc918c | ||
|
|
d399b3e29a | ||
|
|
acc6f119e1 | ||
|
|
932a2c375c | ||
|
|
142eebe9e6 | ||
|
|
36f19c9180 | ||
|
|
beb8fed6bd | ||
|
|
142284a17c | ||
|
|
f1ea86362a | ||
|
|
ec3361ad91 | ||
|
|
ca7c36ce15 | ||
|
|
f7c73728d7 | ||
|
|
1992a23edc | ||
|
|
dad28135cc | ||
|
|
e41d13dd53 | ||
|
|
64cae53d82 | ||
|
|
c9bf0bd8d7 | ||
|
|
97d2047aee | ||
|
|
811f8abed7 | ||
|
|
ab02a54f28 | ||
|
|
6e0c1aefcc | ||
|
|
e887b6c43c | ||
|
|
25172c2bc9 | ||
|
|
929b90173a | ||
|
|
70a65f6ffe | ||
|
|
db7d3f01d8 |
@@ -49,8 +49,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
|
||||
@@ -104,13 +109,7 @@ import com.cobblemon.mod.common.pokemon.properties.tags.PokemonFlagProperty
|
||||
import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
|
||||
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
|
||||
@@ -125,6 +124,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
|
||||
import org.apache.logging.log4j.Logger
|
||||
|
||||
@@ -11,6 +11,7 @@ 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.fishing.PokeRodFishingBobberEntity
|
||||
import com.cobblemon.mod.common.entity.generic.GenericBedrockEntity
|
||||
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
@@ -66,6 +67,15 @@ object CobblemonEntities : PlatformRegistry<Registry<EntityType<*>>, RegistryKey
|
||||
.build(CHEST_BOAT_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())
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val GENERIC_BEDROCK_ENTITY_KEY = cobblemonResource("generic_bedrock")
|
||||
@JvmField
|
||||
|
||||
@@ -14,6 +14,8 @@ import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.api.pokemon.Natures
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.api.text.blue
|
||||
import com.cobblemon.mod.common.api.text.gray
|
||||
import com.cobblemon.mod.common.block.BerryBlock
|
||||
import com.cobblemon.mod.common.block.MintBlock
|
||||
import com.cobblemon.mod.common.block.MintBlock.MintType
|
||||
@@ -45,6 +47,7 @@ import net.minecraft.registry.Registries
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.registry.RegistryKey
|
||||
import net.minecraft.registry.RegistryKeys
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.world.World
|
||||
|
||||
@@ -932,12 +935,121 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
@JvmField
|
||||
val BLACK_TUMBLESTONE_BLOCK = blockItem("black_tumblestone_block", CobblemonBlocks.BLACK_TUMBLESTONE_BLOCK)
|
||||
|
||||
@JvmField
|
||||
val POKEROD_SMITHING_TEMPLATE = create("pokerod_smithing_template", SmithingTemplateItem(
|
||||
Text.translatable("item.minecraft.fishing_rod").blue(),
|
||||
Text.translatable("item.cobblemon.smithing_template.pokerod.ingredients").blue(),
|
||||
Text.translatable("upgrade.cobblemon.pokerod").gray(),
|
||||
Text.translatable("item.cobblemon.smithing_template.pokerod.base_slot_description"),
|
||||
Text.translatable("item.cobblemon.smithing_template.pokerod.additions_slot_description"),
|
||||
listOf(cobblemonResource("item/empty_slot_fishing_rod")),
|
||||
listOf(cobblemonResource("item/empty_slot_pokeball"))
|
||||
))
|
||||
|
||||
@JvmField
|
||||
val AUTOMATON_ARMOR_TRIM_SMITHING_TEMPLATE: SmithingTemplateItem = this.create(
|
||||
"automaton_armor_trim_smithing_template",
|
||||
SmithingTemplateItem.of(CobblemonArmorTrims.AUTOMATON)
|
||||
)
|
||||
|
||||
val pokeRods = mutableListOf<PokerodItem>()
|
||||
@JvmField
|
||||
val POKE_ROD = pokerodItem(cobblemonResource("poke_rod"))
|
||||
@JvmField
|
||||
val CITRINE_ROD = pokerodItem(cobblemonResource("citrine_rod"))
|
||||
@JvmField
|
||||
val VERDANT_ROD = pokerodItem(cobblemonResource("verdant_rod"))
|
||||
@JvmField
|
||||
val AZURE_ROD = pokerodItem(cobblemonResource("azure_rod"))
|
||||
@JvmField
|
||||
val ROSEATE_ROD = pokerodItem(cobblemonResource("roseate_rod"))
|
||||
@JvmField
|
||||
val SLATE_ROD = pokerodItem(cobblemonResource("slate_rod"))
|
||||
@JvmField
|
||||
val PREMIER_ROD = pokerodItem(cobblemonResource("premier_rod"))
|
||||
@JvmField
|
||||
val GREAT_ROD = pokerodItem(cobblemonResource("great_rod"))
|
||||
@JvmField
|
||||
val ULTRA_ROD = pokerodItem(cobblemonResource("ultra_rod"))
|
||||
@JvmField
|
||||
val SAFARI_ROD = pokerodItem(cobblemonResource("safari_rod"))
|
||||
@JvmField
|
||||
val FAST_ROD = pokerodItem(cobblemonResource("fast_rod"))
|
||||
@JvmField
|
||||
val LEVEL_ROD = pokerodItem(cobblemonResource("level_rod"))
|
||||
@JvmField
|
||||
val LURE_ROD = pokerodItem(cobblemonResource("lure_rod"))
|
||||
@JvmField
|
||||
val HEAVY_ROD = pokerodItem(cobblemonResource("heavy_rod"))
|
||||
@JvmField
|
||||
val LOVE_ROD = pokerodItem(cobblemonResource("love_rod"))
|
||||
@JvmField
|
||||
val FRIEND_ROD = pokerodItem(cobblemonResource("friend_rod"))
|
||||
@JvmField
|
||||
val MOON_ROD = pokerodItem(cobblemonResource("moon_rod"))
|
||||
@JvmField
|
||||
val SPORT_ROD = pokerodItem(cobblemonResource("sport_rod"))
|
||||
@JvmField
|
||||
val PARK_ROD = pokerodItem(cobblemonResource("park_rod"))
|
||||
@JvmField
|
||||
val NET_ROD = pokerodItem(cobblemonResource("net_rod"))
|
||||
@JvmField
|
||||
val DIVE_ROD = pokerodItem(cobblemonResource("dive_rod"))
|
||||
@JvmField
|
||||
val NEST_ROD = pokerodItem(cobblemonResource("nest_rod"))
|
||||
@JvmField
|
||||
val REPEAT_ROD = pokerodItem(cobblemonResource("repeat_rod"))
|
||||
@JvmField
|
||||
val TIMER_ROD = pokerodItem(cobblemonResource("timer_rod"))
|
||||
@JvmField
|
||||
val LUXURY_ROD = pokerodItem(cobblemonResource("luxury_rod"))
|
||||
@JvmField
|
||||
val DUSK_ROD = pokerodItem(cobblemonResource("dusk_rod"))
|
||||
@JvmField
|
||||
val HEAL_ROD = pokerodItem(cobblemonResource("heal_rod"))
|
||||
@JvmField
|
||||
val QUICK_ROD = pokerodItem(cobblemonResource("quick_rod"))
|
||||
@JvmField
|
||||
val DREAM_ROD = pokerodItem(cobblemonResource("dream_rod"))
|
||||
@JvmField
|
||||
val BEAST_ROD = pokerodItem(cobblemonResource("beast_rod"))
|
||||
@JvmField
|
||||
val MASTER_ROD = pokerodItem(cobblemonResource("master_rod"))
|
||||
@JvmField
|
||||
val CHERISH_ROD = pokerodItem(cobblemonResource("cherish_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_POKE_ROD = pokerodItem(cobblemonResource("ancient_poke_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_CITRINE_ROD = pokerodItem(cobblemonResource("ancient_citrine_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_VERDANT_ROD = pokerodItem(cobblemonResource("ancient_verdant_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_AZURE_ROD = pokerodItem(cobblemonResource("ancient_azure_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_ROSEATE_ROD = pokerodItem(cobblemonResource("ancient_roseate_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_SLATE_ROD = pokerodItem(cobblemonResource("ancient_slate_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_IVORY_ROD = pokerodItem(cobblemonResource("ancient_ivory_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_GREAT_ROD = pokerodItem(cobblemonResource("ancient_great_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_ULTRA_ROD = pokerodItem(cobblemonResource("ancient_ultra_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_FEATHER_ROD = pokerodItem(cobblemonResource("ancient_feather_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_WING_ROD = pokerodItem(cobblemonResource("ancient_wing_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_JET_ROD = pokerodItem(cobblemonResource("ancient_jet_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_HEAVY_ROD = pokerodItem(cobblemonResource("ancient_heavy_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_LEADEN_ROD = pokerodItem(cobblemonResource("ancient_leaden_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_GIGATON_ROD = pokerodItem(cobblemonResource("ancient_gigaton_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_ORIGIN_ROD = pokerodItem(cobblemonResource("ancient_origin_rod"))
|
||||
|
||||
// Misc
|
||||
@JvmField
|
||||
val POKEMON_MODEL = this.create("pokemon_model", PokemonItem())
|
||||
@@ -1003,6 +1115,13 @@ 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(pokeRodId: Identifier): PokerodItem {
|
||||
val settings = Item.Settings().maxCount(1).maxDamage(Items.FISHING_ROD.maxDamage)
|
||||
val item = create(pokeRodId.path, PokerodItem(pokeRodId, settings))
|
||||
pokeRods.add(item)
|
||||
return item
|
||||
}
|
||||
|
||||
private fun heldItem(name: String, remappedName: String? = null): CobblemonItem = create(
|
||||
name,
|
||||
CobblemonItem(Item.Settings()).also {
|
||||
|
||||
@@ -62,15 +62,7 @@ import com.cobblemon.mod.common.net.messages.client.battle.*
|
||||
import com.cobblemon.mod.common.net.messages.client.callback.OpenMoveCallbackPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyCallbackPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyMoveCallbackPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.AbilityRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.BerryRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.GlobalSpeciesFeatureSyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.MovesRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.PropertiesCompletionRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.SpeciesFeatureAssignmentSyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.SpeciesRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.StandardSpeciesFeatureSyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.UnlockReloadPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.*
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueClosedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueOpenedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
|
||||
@@ -308,6 +300,7 @@ object CobblemonNetwork : NetworkManager {
|
||||
this.createClientBound(SpeciesFeatureAssignmentSyncPacket.ID, SpeciesFeatureAssignmentSyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
this.createClientBound(NaturalMaterialRegistrySyncPacket.ID, NaturalMaterialRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
this.createClientBound(FossilRegistrySyncPacket.ID, FossilRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
this.createClientBound(PokeRodRegistrySyncPacket.ID, PokeRodRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
|
||||
// Effects
|
||||
this.createClientBound(SpawnSnowstormParticlePacket.ID, SpawnSnowstormParticlePacket::decode, SpawnSnowstormParticleHandler)
|
||||
|
||||
@@ -134,6 +134,15 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
|
||||
@JvmField
|
||||
val RELIC_COIN_POUCH_PLACE = this.create("relic_coin_pouch.place")
|
||||
|
||||
val COIN_POUCH_PLACE = this.create("coin_pouch.place")
|
||||
|
||||
@JvmField
|
||||
val FISHING_NOTIFICATION = this.create("fishing.notification")
|
||||
@JvmField
|
||||
val FISHING_SPLASH_BIG = this.create("fishing.splash_big")
|
||||
@JvmField
|
||||
val FISHING_SPLASH_SMALL = this.create("fishing.splash_small")
|
||||
|
||||
@JvmField
|
||||
val TUMBLESTONE_BREAK = this.create("tumblestone.break")
|
||||
@JvmField
|
||||
|
||||
@@ -32,7 +32,14 @@ object CobblemonTradeOffers {
|
||||
* @return The resulting list.
|
||||
*/
|
||||
fun tradeOffersFor(profession: VillagerProfession): List<VillagerTradeOffer> = when (profession) {
|
||||
VillagerProfession.FARMER -> listOf(VillagerTradeOffer(VillagerProfession.FARMER, 3, listOf(TradeOffers.SellItemFactory(CobblemonItems.VIVICHOKE_SEEDS, 24, 1, 1, 6))))
|
||||
VillagerProfession.FARMER -> listOf(
|
||||
VillagerTradeOffer(VillagerProfession.FARMER, 3, listOf(TradeOffers.SellItemFactory(CobblemonItems.VIVICHOKE_SEEDS, 24, 1, 1, 6)))
|
||||
)
|
||||
VillagerProfession.FISHERMAN -> listOf(
|
||||
VillagerTradeOffer(VillagerProfession.FISHERMAN, 5, listOf(
|
||||
TradeOffers.SellItemFactory(CobblemonItems.POKEROD_SMITHING_TEMPLATE, 12, 3, 30)
|
||||
))
|
||||
)
|
||||
else -> emptyList()
|
||||
}
|
||||
|
||||
|
||||
@@ -113,6 +113,13 @@ object CobblemonCriteria {
|
||||
)
|
||||
)
|
||||
|
||||
val CAST_POKE_ROD = this.create(
|
||||
SimpleCriterionTrigger(
|
||||
cobblemonResource("cast_poke_rod"),
|
||||
CastPokeRodCriterionCondition::class.java
|
||||
)
|
||||
)
|
||||
|
||||
// Advancement criteria for [grow_tumblestone.json]
|
||||
val PLANT_TUMBLESTONE = this.create(
|
||||
SimpleCriterionTrigger(
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.advancement.criterion
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import net.minecraft.predicate.entity.LootContextPredicate
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
class CastPokeRodCriterionCondition(id: Identifier, predicate: LootContextPredicate): SimpleCriterionCondition<Boolean>(id, predicate) {
|
||||
var hasBait: Boolean = false
|
||||
|
||||
override fun toJson(json: JsonObject) {
|
||||
json.addProperty("hasBait", hasBait)
|
||||
}
|
||||
|
||||
override fun fromJson(json: JsonObject) {
|
||||
hasBait = json.get("hasBait").asBoolean
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayerEntity, context: Boolean): Boolean {
|
||||
return hasBait == context
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.fishing
|
||||
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
data class FishingBait(
|
||||
val item: Identifier,
|
||||
val effects: Map<Identifier, Effect>,
|
||||
) {
|
||||
data class Effect(
|
||||
val nature: Identifier?,
|
||||
val ivs: List<Identifier>?,
|
||||
val useAll: Boolean?,
|
||||
val gender: Identifier?,
|
||||
val tera: Identifier?,
|
||||
val chance: Double = 0.0,
|
||||
val value: Double = 0.0
|
||||
)
|
||||
|
||||
object Effects {
|
||||
val NATURE = cobblemonResource("nature")
|
||||
val IV = cobblemonResource("iv")
|
||||
val EV = cobblemonResource("ev")
|
||||
val BITE_TIME = cobblemonResource("bite_time")
|
||||
val GENDER_CHANCE = cobblemonResource("gender_chance")
|
||||
val LEVEL_RAISE = cobblemonResource("level_raise")
|
||||
val TERA = cobblemonResource("tera")
|
||||
val SHINY_REROLL = cobblemonResource("shiny_reroll")
|
||||
val HIDDEN_ABILITY_CHANCE = cobblemonResource("ha_chance")
|
||||
val POKEMON_CHANCE = cobblemonResource("pokemon_chance")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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.fishing
|
||||
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.net.messages.client.fishing.FishingBaitRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.registry.Registries
|
||||
import net.minecraft.resource.ResourceType
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
object FishingBaits : JsonDataRegistry<FishingBait>{
|
||||
override val id = cobblemonResource("fishing_baits")
|
||||
override val type = ResourceType.SERVER_DATA
|
||||
override val observable = SimpleObservable<FishingBaits>()
|
||||
override val typeToken: TypeToken<FishingBait> = TypeToken.get(FishingBait::class.java)
|
||||
override val resourcePath = "fishing_baits"
|
||||
override val gson: Gson = GsonBuilder()
|
||||
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
|
||||
.setPrettyPrinting()
|
||||
.create()
|
||||
|
||||
private val itemMap = mutableMapOf<Identifier, FishingBait>()
|
||||
|
||||
override fun sync(player: ServerPlayerEntity) {
|
||||
FishingBaitRegistrySyncPacket(this.itemMap.values.toList()).sendToPlayer(player)
|
||||
}
|
||||
|
||||
override fun reload(data: Map<Identifier, FishingBait>) {
|
||||
itemMap.clear()
|
||||
data.forEach { id, bait ->
|
||||
itemMap[id] = bait
|
||||
}
|
||||
}
|
||||
|
||||
fun getFromItemStack(stack: ItemStack): FishingBait? {
|
||||
return itemMap[Registries.ITEM.getId(stack.item)]
|
||||
}
|
||||
|
||||
fun isFishingBait(stack: ItemStack) = itemMap.containsKey(Registries.ITEM.getId(stack.item))
|
||||
|
||||
//
|
||||
//
|
||||
// fun getBaitSubcategory(item: ItemStack): String? {
|
||||
// val itemId = Registries.ITEM.getId(item.item)
|
||||
// if (itemId in itemMap.keys) {
|
||||
// return itemMap[itemId]?.subcategory
|
||||
// }
|
||||
// val tag = tagMap.keys.firstOrNull { it.fits(item.item, Registries.ITEM) }
|
||||
// if (tag != null) {
|
||||
// return tagMap[tag]?.subcategory
|
||||
// }
|
||||
// return null
|
||||
// }
|
||||
//
|
||||
// fun getBaitSuccessChance(item: ItemStack): Double? {
|
||||
// val itemId = Registries.ITEM.getId(item.item)
|
||||
// if (itemId in itemMap.keys) {
|
||||
// return itemMap[itemId]?.chance
|
||||
// }
|
||||
// val tag = tagMap.keys.firstOrNull { it.fits(item.item, Registries.ITEM) }
|
||||
// if (tag != null) {
|
||||
// return tagMap[tag]?.chance
|
||||
// }
|
||||
// return null
|
||||
// }
|
||||
//
|
||||
// fun getBaitEffectValue(item: ItemStack): Double? {
|
||||
// val itemId = Registries.ITEM.getId(item.item)
|
||||
// if (itemId in itemMap.keys) {
|
||||
// return itemMap[itemId]?.value
|
||||
// }
|
||||
// val tag = tagMap.keys.firstOrNull { it.fits(item.item, Registries.ITEM) }
|
||||
// if (tag != null) {
|
||||
// return tagMap[tag]?.value
|
||||
// }
|
||||
// return null
|
||||
// }
|
||||
//
|
||||
//
|
||||
// fun getBaitNote(item: ItemStack): String? {
|
||||
// val itemId = Registries.ITEM.getId(item.item)
|
||||
// if (itemId in itemMap.keys) {
|
||||
// return itemMap[itemId]?.note
|
||||
// }
|
||||
// val tag = tagMap.keys.firstOrNull { it.fits(item.item, Registries.ITEM) }
|
||||
// if (tag != null) {
|
||||
// return tagMap[tag]?.note
|
||||
// }
|
||||
// return null
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.fishing
|
||||
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.pokeball.PokeBall
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* Base poke rod object
|
||||
* It is intended that there is one poke rod object initialized for a given poke rod type.
|
||||
*
|
||||
* @property name the poke rod registry name
|
||||
* @property pokeBallId The [Identifier] of the pokeball that is used as the bobber for this rod
|
||||
* @property lineColor list of [RGB] values that apply to the fishing line of the Pokérod
|
||||
*/
|
||||
data class PokeRod(
|
||||
val pokeBallId: Identifier,
|
||||
//Hex string of color
|
||||
val lineColor: String,
|
||||
var name: Identifier?
|
||||
) {
|
||||
internal fun encode(buffer: PacketByteBuf) {
|
||||
buffer.writeIdentifier(name)
|
||||
buffer.writeIdentifier(pokeBallId)
|
||||
buffer.writeString(lineColor)
|
||||
}
|
||||
|
||||
companion object {
|
||||
internal fun decode(buffer: PacketByteBuf): PokeRod {
|
||||
val name = buffer.readIdentifier()
|
||||
val pokeBallId = buffer.readIdentifier()
|
||||
val lineColor = buffer.readString()
|
||||
return PokeRod(pokeBallId, lineColor, name)
|
||||
}
|
||||
}
|
||||
|
||||
fun getPokeBall(): PokeBall? {
|
||||
return PokeBalls.getPokeBall(pokeBallId)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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.fishing
|
||||
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.net.messages.client.data.PokeRodRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import net.minecraft.resource.ResourceType
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* The data registry for [PokeRod]s.
|
||||
* All the pokerod fields are guaranteed to exist
|
||||
*/
|
||||
object PokeRods : JsonDataRegistry<PokeRod> {
|
||||
|
||||
override val id = cobblemonResource("pokerods")
|
||||
override val type = ResourceType.SERVER_DATA
|
||||
override val observable = SimpleObservable<PokeRods>()
|
||||
|
||||
// ToDo once datapack pokerod is implemented add required adapters here
|
||||
override val gson: Gson = GsonBuilder()
|
||||
.disableHtmlEscaping()
|
||||
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
|
||||
.setPrettyPrinting()
|
||||
.create()
|
||||
override val typeToken: TypeToken<PokeRod> = TypeToken.get(PokeRod::class.java)
|
||||
override val resourcePath = "pokerods"
|
||||
|
||||
private val rods = mutableMapOf<Identifier, PokeRod>()
|
||||
|
||||
override fun reload(data: Map<Identifier, PokeRod>) {
|
||||
{
|
||||
data.forEach {
|
||||
it.value.name = it.key
|
||||
rods[it.key] = it.value
|
||||
}
|
||||
}
|
||||
rods.putAll(data)
|
||||
this.observable.emit(this)
|
||||
}
|
||||
|
||||
override fun sync(player: ServerPlayerEntity) {
|
||||
PokeRodRegistrySyncPacket(rods.values).sendToPlayer(player)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a Pokerod from registry name.
|
||||
* @return the pokerod object if found otherwise null.
|
||||
*/
|
||||
fun getPokeRod(name : Identifier): PokeRod? = rods[name]
|
||||
|
||||
}
|
||||
@@ -168,7 +168,7 @@ object PokeBalls : JsonDataRegistry<PokeBall> {
|
||||
createDefault("fast_ball", BaseStatModifier(Stats.SPEED, { it >= 100 }, 4F))
|
||||
createDefault("level_ball", CatchRateModifiers.LEVEL)
|
||||
// ToDo we will need fishing context here once fishing is implemented for a multiplier
|
||||
createDefault("lure_ball", CatchRateModifiers.typeBoosting(2F, ElementalTypes.WATER))
|
||||
createDefault("lure_ball", CatchRateModifiers.LURE)
|
||||
createDefault("heavy_ball", CatchRateModifiers.WEIGHT_BASED)
|
||||
createDefault("love_ball", CatchRateModifiers.LOVE)
|
||||
createDefault("friend_ball", effects = listOf(CaptureEffects.friendshipSetter(150)))
|
||||
|
||||
+12
@@ -121,6 +121,18 @@ object CatchRateModifiers {
|
||||
1F
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by [PokeBalls.LURE_BALL].
|
||||
* Checks if the entity has an aspect for being spawned from fishing.
|
||||
* If yes boosts the catch rate by *4
|
||||
*/
|
||||
val LURE = WorldStateModifier { _, entity ->
|
||||
if (entity.pokemon.aspects.contains("fished")) // todo make aspect about this
|
||||
4f
|
||||
else
|
||||
1F
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by [PokeBalls.HEAVY_BALL].
|
||||
* The base implementation of the heavy ball modifier mechanics.
|
||||
|
||||
@@ -12,11 +12,13 @@ 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.FishingSpawningCondition
|
||||
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.FishingSpawningContext
|
||||
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
|
||||
@@ -32,6 +34,7 @@ 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.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 +86,7 @@ object BestSpawner {
|
||||
var config = BestSpawnerConfig()
|
||||
val spawnerManagers = mutableListOf<SpawnerManager>(CobblemonWorldSpawnerManager)
|
||||
var defaultPokemonDespawner: Despawner<PokemonEntity> = CobblemonAgingDespawner(getAgeTicks = { it.ticksLived })
|
||||
lateinit var fishingSpawner: FishingSpawner
|
||||
|
||||
fun loadConfig() {
|
||||
LOGGER.info("Starting the Best Spawner...")
|
||||
@@ -91,6 +95,7 @@ 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)
|
||||
|
||||
LOGGER.info("Loaded ${SpawningCondition.conditionTypes.size} spawning condition types.")
|
||||
SpawningContextCalculator.register(GroundedSpawningContextCalculator)
|
||||
@@ -104,6 +109,7 @@ 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)
|
||||
|
||||
LOGGER.info("Loaded ${SpawningContext.contexts.size} spawning context types.")
|
||||
|
||||
@@ -118,5 +124,7 @@ object BestSpawner {
|
||||
|
||||
fun onServerStarted() {
|
||||
spawnerManagers.forEach(SpawnerManager::onServerStarted)
|
||||
fishingSpawner = FishingSpawner()
|
||||
fishingSpawner.onServerStarted()
|
||||
}
|
||||
}
|
||||
+44
@@ -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"
|
||||
}
|
||||
}
|
||||
+31
@@ -11,12 +11,16 @@ package com.cobblemon.mod.common.api.spawning.condition
|
||||
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
|
||||
import com.cobblemon.mod.common.api.spawning.MoonPhaseRange
|
||||
import com.cobblemon.mod.common.api.spawning.TimeRange
|
||||
import com.cobblemon.mod.common.api.spawning.context.FishingSpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.util.Merger
|
||||
import com.cobblemon.mod.common.util.math.orMax
|
||||
import com.cobblemon.mod.common.util.math.orMin
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.enchantment.EnchantmentHelper
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.registry.Registries
|
||||
import net.minecraft.registry.tag.TagKey
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.world.biome.Biome
|
||||
@@ -56,6 +60,9 @@ abstract class SpawningCondition<T : SpawningContext> {
|
||||
var isThundering: Boolean? = null
|
||||
var timeRange: TimeRange? = null
|
||||
var structures: MutableList<Either<Identifier, TagKey<Structure>>>? = null
|
||||
var lureLevel: Int? = null
|
||||
var bait: String? = null
|
||||
var rodType: String? = null
|
||||
|
||||
@Transient
|
||||
var appendages = mutableListOf<AppendageCondition>()
|
||||
@@ -108,8 +115,32 @@ abstract class SpawningCondition<T : SpawningContext> {
|
||||
}
|
||||
) {
|
||||
return false
|
||||
} else if (lureLevel != null && ctx is FishingSpawningContext) { // check for the lureLevel of the rod
|
||||
val pokerodStack = (ctx as FishingSpawningContext).rodStack
|
||||
|
||||
if (EnchantmentHelper.getLure(pokerodStack) < lureLevel!!)
|
||||
return false
|
||||
} else if (bait != null && ctx is FishingSpawningContext) { // check for the bait on the bobber
|
||||
val pokerodItem = (ctx as FishingSpawningContext).rodItem
|
||||
|
||||
if (Registries.ITEM.getId(pokerodItem?.bait?.item).path != bait)
|
||||
return false
|
||||
} else if (rodType != null && ctx is FishingSpawningContext) { // check for the type of pokerod being used
|
||||
val pokerodItem = (ctx as FishingSpawningContext).rodItem
|
||||
|
||||
if (pokerodItem?.pokeRodId?.path != rodType)
|
||||
return false
|
||||
}
|
||||
|
||||
/*else if (ctx is FishingSpawningContext && (ctx as FishingSpawningContext).rodItem != null) { // check if the bait attracts certain EV yields
|
||||
val pokerodItem = (ctx as FishingSpawningContext).rodItem
|
||||
|
||||
// todo check if the EV yield of the berry matches the bait EV attract maybe?
|
||||
|
||||
if (// todo if bait EV yield != EV yield of pokemon consideration //Registries.ITEM.getId(pokerodItem?.bait?.item).path == )
|
||||
return false
|
||||
}*/
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
+47
@@ -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
|
||||
// }
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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
|
||||
val baitStack = cause.baitStack
|
||||
val baitItem = cause.baitItem
|
||||
}
|
||||
+34
@@ -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
|
||||
}
|
||||
+4
@@ -13,8 +13,10 @@ import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.feature.FishedFeatureHandler
|
||||
import com.cobblemon.mod.common.pokemon.feature.SeasonFeatureHandler
|
||||
import com.cobblemon.mod.common.util.weightedSelection
|
||||
import net.minecraft.world.gen.GenerationStep.Feature
|
||||
|
||||
/**
|
||||
* A [SpawnAction] that will spawn a single [PokemonEntity].
|
||||
@@ -45,6 +47,8 @@ class PokemonSpawnAction(
|
||||
null
|
||||
}?.createStack(ctx)
|
||||
val entity = props.createEntity(ctx.world)
|
||||
// add fishing aspect if fished with a pokerod
|
||||
FishedFeatureHandler.updateFished(entity.pokemon, ctx.spawner.name == "fishing")
|
||||
SeasonFeatureHandler.updateSeason(entity.pokemon, Cobblemon.seasonResolver(ctx.world, ctx.position))
|
||||
if (heldItem != null) {
|
||||
entity.pokemon.swapHeldItem(heldItem)
|
||||
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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.Cobblemon
|
||||
import com.cobblemon.mod.common.api.Priority
|
||||
import com.cobblemon.mod.common.api.fishing.FishingBait
|
||||
import com.cobblemon.mod.common.api.fishing.FishingBaits
|
||||
import com.cobblemon.mod.common.api.pokemon.Natures
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.spawning.context.FishingSpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.detail.PokemonSpawnAction
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.pokemon.IVs
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.util.Identifier
|
||||
import kotlin.math.min
|
||||
import kotlin.random.Random.Default.nextInt
|
||||
|
||||
class FishingBaitInfluence : SpawningInfluence {
|
||||
override fun affectAction(action: SpawnAction<*>) {
|
||||
if (action !is PokemonSpawnAction || action.ctx !is FishingSpawningContext) return
|
||||
val bait = FishingBaits.getFromItemStack(action.ctx.baitStack) ?: return
|
||||
|
||||
bait.effects.entries.forEach { (type, effect) ->
|
||||
if (Math.random() > effect.chance) return
|
||||
when (type) {
|
||||
FishingBait.Effects.SHINY_REROLL -> shinyReroll(action, effect)
|
||||
FishingBait.Effects.NATURE -> alterNatureAttempt(action, effect)
|
||||
FishingBait.Effects.IV -> alterIVAttempt(action, effect)
|
||||
FishingBait.Effects.GENDER_CHANCE -> alterGenderAttempt(action, effect)
|
||||
FishingBait.Effects.LEVEL_RAISE -> alterLevelAttempt(action, effect)
|
||||
FishingBait.Effects.TERA -> alterTeraAttempt(action, effect)
|
||||
FishingBait.Effects.HIDDEN_ABILITY_CHANCE -> alterHAAttempt(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun shinyReroll(action: PokemonSpawnAction, effect: FishingBait.Effect) {
|
||||
if (action.props.shiny != null) return
|
||||
|
||||
val shinyOdds = Cobblemon.config.shinyRate.toInt()
|
||||
val randomNumber = nextInt(0, shinyOdds + 1)
|
||||
|
||||
if (randomNumber <= (effect.value).toInt()) {
|
||||
action.props.shiny = true
|
||||
}
|
||||
}
|
||||
|
||||
private fun alterNatureAttempt(action: PokemonSpawnAction, effect: FishingBait.Effect) {
|
||||
if (action.props.nature != null) return
|
||||
if (effect.nature == null) return
|
||||
|
||||
// TIMNOTE: This replaces the static lists. It's less performant because it's being reviewed every time,
|
||||
// but also it's not something that goes off too often.
|
||||
val possibleNatures = Natures.all().filter { it.increasedStat?.identifier == effect.nature }
|
||||
if (possibleNatures.isEmpty()) return
|
||||
val takenNature = possibleNatures.random()
|
||||
|
||||
action.props.nature = takenNature.name.namespace
|
||||
}
|
||||
|
||||
private fun alterIVAttempt(action: PokemonSpawnAction, effect: FishingBait.Effect) {
|
||||
val ivs = effect.ivs ?: return
|
||||
val useAll = effect.useAll ?: return
|
||||
|
||||
if (action.props.ivs == null) {
|
||||
action.props.ivs = IVs.createRandomIVs()
|
||||
}
|
||||
|
||||
if (useAll) {
|
||||
ivs.forEach { iv -> boostIv(iv, action, effect) }
|
||||
} else {
|
||||
boostIv(ivs.random(), action, effect)
|
||||
}
|
||||
}
|
||||
|
||||
private fun boostIv(iv: Identifier, action: PokemonSpawnAction, effect: FishingBait.Effect) {
|
||||
val targetedStat = Stats.getStat(iv.path)
|
||||
val currentIv = action.props.ivs!![targetedStat] ?: 0
|
||||
action.props.ivs!![targetedStat] = min(currentIv + effect.value.toInt(), IVs.MAX_VALUE)
|
||||
}
|
||||
|
||||
private fun alterGenderAttempt(action: PokemonSpawnAction, effect: FishingBait.Effect) {
|
||||
if (effect.gender == null) return
|
||||
if (action.props.gender != null) return
|
||||
|
||||
when (effect.gender) {
|
||||
cobblemonResource("male") -> if (action.props.gender != Gender.MALE) action.props.gender = Gender.MALE
|
||||
cobblemonResource("female") -> if (action.props.gender != Gender.FEMALE) action.props.gender = Gender.FEMALE
|
||||
}
|
||||
}
|
||||
|
||||
private fun alterLevelAttempt(action: PokemonSpawnAction, effect: FishingBait.Effect) {
|
||||
action.props.level =
|
||||
(action.props.level ?: action.detail.getDerivedLevelRange().random()) + effect.value.toInt()
|
||||
}
|
||||
|
||||
private fun alterTeraAttempt(action: PokemonSpawnAction, effect: FishingBait.Effect) {
|
||||
if (effect.tera == null) return
|
||||
if (action.props.teraType != null) return
|
||||
|
||||
action.props.teraType = effect.tera.path
|
||||
}
|
||||
|
||||
private fun alterHAAttempt(action: PokemonSpawnAction) {
|
||||
if (action.props.ability != null) return
|
||||
|
||||
val species = action.props.species?.let { PokemonSpecies.getByName(it) } ?: return
|
||||
val ability = species.abilities.mapping[Priority.LOW]?.first()?.template?.name ?: return
|
||||
|
||||
action.props.ability = ability
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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 com.cobblemon.mod.common.item.interactive.PokerodItem
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.item.Item
|
||||
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,
|
||||
val baitStack: ItemStack
|
||||
) : SpawnCause(spawner, bucket, entity) {
|
||||
val rodItem = rodStack.item as? PokerodItem
|
||||
val baitItem = baitStack.item as Item
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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,
|
||||
world,
|
||||
pos,
|
||||
influences
|
||||
)
|
||||
return ctx
|
||||
}
|
||||
|
||||
fun onServerStarted() {
|
||||
// TODO: Register influences here
|
||||
influences.add(FishingBaitInfluence())
|
||||
}
|
||||
}
|
||||
+51
@@ -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 }
|
||||
}
|
||||
@@ -29,6 +29,7 @@ import com.cobblemon.mod.common.client.render.block.GildedChestBlockRenderer
|
||||
import com.cobblemon.mod.common.client.render.block.HealingMachineRenderer
|
||||
import com.cobblemon.mod.common.client.render.block.*
|
||||
import com.cobblemon.mod.common.client.render.boat.CobblemonBoatRenderer
|
||||
import com.cobblemon.mod.common.client.render.entity.PokeBobberEntityRenderer
|
||||
import com.cobblemon.mod.common.client.render.generic.GenericBedrockRenderer
|
||||
import com.cobblemon.mod.common.client.render.item.CobblemonBuiltinItemRendererRegistry
|
||||
import com.cobblemon.mod.common.client.render.item.PokemonItemRenderer
|
||||
@@ -266,6 +267,8 @@ object CobblemonClient {
|
||||
this.implementation.registerEntityRenderer(CobblemonEntities.CHEST_BOAT) { ctx -> CobblemonBoatRenderer(ctx, true) }
|
||||
LOGGER.info("Registering Generic Bedrock Entity renderer")
|
||||
this.implementation.registerEntityRenderer(CobblemonEntities.GENERIC_BEDROCK_ENTITY, ::GenericBedrockRenderer)
|
||||
LOGGER.info("Registering PokeRod Bobber renderer")
|
||||
this.implementation.registerEntityRenderer(CobblemonEntities.POKE_BOBBER) { ctx -> PokeBobberEntityRenderer(ctx) }
|
||||
}
|
||||
|
||||
fun reloadCodedAssets(resourceManager: ResourceManager) {
|
||||
|
||||
+2
-1
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.client.render.block
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBlocks
|
||||
import com.cobblemon.mod.common.CobblemonItems
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||
import com.cobblemon.mod.common.block.DisplayCaseBlock
|
||||
import com.cobblemon.mod.common.block.entity.DisplayCaseBlockEntity
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokemonModelRepository
|
||||
@@ -136,7 +137,7 @@ class DisplayCaseRenderer(ctx: BlockEntityRendererFactory.Context) : BlockEntity
|
||||
mobHeads.contains(stack.item) -> PositioningType.MOB_HEAD
|
||||
stack.item is BedItem -> PositioningType.BED
|
||||
stack.item is BannerItem -> PositioningType.BANNER
|
||||
stack.item is PokeBallItem -> PositioningType.POKE_BALL
|
||||
stack.isIn(CobblemonItemTags.POKE_BALLS) -> PositioningType.POKE_BALL
|
||||
stack.item == CobblemonItems.RELIC_COIN_POUCH -> PositioningType.COIN_POUCH
|
||||
stack.item == CobblemonItems.PASTURE -> PositioningType.PASTURE
|
||||
stack.item == CobblemonItems.POKEMON_MODEL -> PositioningType.ITEM_MODEL
|
||||
|
||||
+311
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
* 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.api.fishing.PokeRods
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.entity.fishing.PokeRodFishingBobberEntity
|
||||
import com.cobblemon.mod.common.item.interactive.PokerodItem
|
||||
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.model.json.ModelTransformationMode
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.registry.Registries
|
||||
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
|
||||
import org.joml.Quaterniond
|
||||
import org.joml.Quaternionf
|
||||
import org.joml.Vector3f
|
||||
import java.awt.Color
|
||||
|
||||
@Environment(value = EnvType.CLIENT)
|
||||
class PokeBobberEntityRenderer(context: EntityRendererFactory.Context?) : EntityRenderer<PokeRodFishingBobberEntity>(context) {
|
||||
|
||||
private var lastSpinAngle: Float = 0f
|
||||
private var randomPitch: Float = 0f
|
||||
private var randomYaw: Float = 0f
|
||||
|
||||
override fun render(fishingBobberEntity: PokeRodFishingBobberEntity, elapsedPartialTicks: Float, tickDelta: Float, matrixStack: MatrixStack, vertexConsumerProvider: VertexConsumerProvider, light: Int) {
|
||||
var playerPosXWorld: Double
|
||||
val eyeHeightOffset: Float
|
||||
val playerPosZWorld: Double
|
||||
val playerPosYWorld: Double
|
||||
val playerEyeYWorld: Double
|
||||
val playerEntity = fishingBobberEntity.playerOwner ?: return
|
||||
|
||||
val berryAdjustY = 0.0 // for tweaking height pos of some berry baits
|
||||
val berryAdjustX = 0.0 // for tweaking width pos of some berry baits
|
||||
|
||||
matrixStack.push() // prepare for overall rendering transforms
|
||||
|
||||
// Generate controlled random pitch and yaw for each cast, with constraints
|
||||
if (fishingBobberEntity.age <= 1) {
|
||||
// Random yaw within a constrained range to allow for limited tilting
|
||||
randomYaw = (-180 + Math.random() * 360).toFloat() // Example: -180 to +180 degrees
|
||||
// Random pitch to ensure the top of the Poke Ball leans towards the string
|
||||
randomPitch = (-40 + Math.random() * 80).toFloat() // Example: -40 to +40 degrees
|
||||
}
|
||||
|
||||
matrixStack.push() // prepare for bobber rendering transforms
|
||||
|
||||
// Apply spinning effect only if the bobber is in the air
|
||||
// Modify spinning effect based on whether the bobber is in open water
|
||||
if (!fishingBobberEntity.isOnGround) {
|
||||
// You might not need to change stopRotationAge if you want the slowing to happen faster
|
||||
val stopRotationAge = 220 // This could remain as your baseline for when rotation completely stops
|
||||
|
||||
// Adjust ageFactor calculation for faster slowing in open water
|
||||
val ageFactor = if (fishingBobberEntity.age < stopRotationAge) {
|
||||
if (fishingBobberEntity.inOpenWater) {
|
||||
1 + fishingBobberEntity.age / 15.0 // Slows down much faster in open water
|
||||
} else {
|
||||
1 + fishingBobberEntity.age / 100.0 // Standard slowing rate
|
||||
}
|
||||
} else {
|
||||
Double.POSITIVE_INFINITY // Stops spinning
|
||||
}
|
||||
|
||||
// Ensure ageFactor does not reduce the rotation speed to 0 or negative
|
||||
val adjustedAgeFactor = if (ageFactor > 0) ageFactor else 1.0
|
||||
|
||||
// Update and apply the spinning effect, incorporating the slowing factor
|
||||
// Stop increasing lastSpinAngle once the bobber reaches the stopRotationAge
|
||||
if (fishingBobberEntity.age < stopRotationAge) {
|
||||
lastSpinAngle = (((fishingBobberEntity.age + tickDelta) * 20 / adjustedAgeFactor) % 360).toFloat()
|
||||
}
|
||||
// After reaching stopRotationAge, lastSpinAngle remains constant, effectively stopping the rotation
|
||||
}
|
||||
|
||||
// When in water, gradually make the Poke Ball upright
|
||||
if (fishingBobberEntity.state == PokeRodFishingBobberEntity.State.BOBBING && !fishingBobberEntity.isOnGround) {
|
||||
// Assuming randomPitch is the rotation around X axis that needs to be adjusted
|
||||
// Simple linear interpolation towards 0 degrees; adjust 'lerpFactor' as needed for speed
|
||||
val lerpFactor = 0.04f // This controls the speed of the adjustment
|
||||
randomPitch = MathHelper.lerp(lerpFactor, randomPitch, 0f) // Adjust towards 0 degrees within range
|
||||
// Consider similar logic for yaw if needed to maintain visual consistency
|
||||
}
|
||||
|
||||
// Apply random pitch and yaw before rendering the Poke Ball
|
||||
matrixStack.multiply(RotationAxis.NEGATIVE_X.rotationDegrees(randomPitch))
|
||||
matrixStack.multiply(RotationAxis.NEGATIVE_Y.rotationDegrees(randomYaw))
|
||||
|
||||
// Apply rotation based on last spin angle
|
||||
matrixStack.multiply(RotationAxis.NEGATIVE_Y.rotationDegrees(lastSpinAngle))
|
||||
|
||||
// Scale down the Poke Ball to 70% of its original size
|
||||
matrixStack.scale(0.7f, 0.7f, 0.7f) // Apply the scaling transformation
|
||||
|
||||
// try to render the bobber sprite as well to have hook pop out the bottom of the Bobber model
|
||||
val entry = matrixStack.peek()
|
||||
val matrix4f = entry.positionMatrix
|
||||
val matrix3f = entry.normalMatrix
|
||||
|
||||
// Scale factor
|
||||
// Scale factor
|
||||
val scale = 0.75f
|
||||
|
||||
// Additional shift to the leeft
|
||||
val shiftHook = 0.045f // Adjust this value as needed to shift the geometry
|
||||
|
||||
val vertexConsumer = vertexConsumerProvider.getBuffer(PokeBobberEntityRenderer.Companion.LAYER)
|
||||
/*// Original vertices for one side
|
||||
PokeBobberEntityRenderer.Companion.vertex(vertexConsumer, matrix4f, matrix3f, light, 0.0f, 0, 0, 1)
|
||||
PokeBobberEntityRenderer.Companion.vertex(vertexConsumer, matrix4f, matrix3f, light, 1.0f, 0, 1, 1)
|
||||
PokeBobberEntityRenderer.Companion.vertex(vertexConsumer, matrix4f, matrix3f, light, 1.0f, 1, 1, 0)
|
||||
PokeBobberEntityRenderer.Companion.vertex(vertexConsumer, matrix4f, matrix3f, light, 0.0f, 1, 0, 0)
|
||||
|
||||
// Add vertices for the opposite side in reverse order
|
||||
PokeBobberEntityRenderer.Companion.vertex(vertexConsumer, matrix4f, matrix3f, light, 0.0f, 1, 0, 0)
|
||||
PokeBobberEntityRenderer.Companion.vertex(vertexConsumer, matrix4f, matrix3f, light, 1.0f, 1, 1, 0)
|
||||
PokeBobberEntityRenderer.Companion.vertex(vertexConsumer, matrix4f, matrix3f, light, 1.0f, 0, 1, 1)
|
||||
PokeBobberEntityRenderer.Companion.vertex(vertexConsumer, matrix4f, matrix3f, light, 0.0f, 0, 0, 1)*/
|
||||
|
||||
// Adjusted and flipped vertices for one side, scaled by 75% and shifted
|
||||
vertex(vertexConsumer, matrix4f, matrix3f, light, (1.0f - 0.0f) * scale + 0.125f + shiftHook, (0.0f * scale + 0.125f), 0, 1)
|
||||
vertex(vertexConsumer, matrix4f, matrix3f, light, (1.0f - 1.0f) * scale + 0.125f + shiftHook, (0.0f * scale + 0.125f), 1, 1)
|
||||
vertex(vertexConsumer, matrix4f, matrix3f, light, (1.0f - 1.0f) * scale + 0.125f + shiftHook, (1.0f * scale + 0.125f), 1, 0)
|
||||
vertex(vertexConsumer, matrix4f, matrix3f, light, (1.0f - 0.0f) * scale + 0.125f + shiftHook, (1.0f * scale + 0.125f), 0, 0)
|
||||
|
||||
// Adjusted and flipped vertices for the opposite side in reverse order, scaled by 75% and shifted
|
||||
vertex(vertexConsumer, matrix4f, matrix3f, light, (1.0f - 0.0f) * scale + 0.125f + shiftHook, (1.0f * scale + 0.125f), 0, 0)
|
||||
vertex(vertexConsumer, matrix4f, matrix3f, light, (1.0f - 1.0f) * scale + 0.125f + shiftHook, (1.0f * scale + 0.125f), 1, 0)
|
||||
vertex(vertexConsumer, matrix4f, matrix3f, light, (1.0f - 1.0f) * scale + 0.125f + shiftHook, (0.0f * scale + 0.125f), 1, 1)
|
||||
vertex(vertexConsumer, matrix4f, matrix3f, light, (1.0f - 0.0f) * scale + 0.125f + shiftHook, (0.0f * scale + 0.125f), 0, 1)
|
||||
|
||||
val pokeRodIdStr = fishingBobberEntity.dataTracker.get(PokeRodFishingBobberEntity.POKEROD_ID)
|
||||
val pokeBobberBaitItemStack = fishingBobberEntity.dataTracker.get(PokeRodFishingBobberEntity.POKEBOBBER_BAIT)
|
||||
val pokeRodId = Identifier.tryParse(pokeRodIdStr)
|
||||
val pokeRod = PokeRods.getPokeRod(pokeRodId!!)
|
||||
val ballItem = PokeBalls.getPokeBall(pokeRod?.pokeBallId!!)!!.item
|
||||
// render the pokebobber
|
||||
MinecraftClient.getInstance().itemRenderer.renderItem(
|
||||
ballItem.defaultStack,
|
||||
ModelTransformationMode.GROUND,
|
||||
light,
|
||||
OverlayTexture.DEFAULT_UV,
|
||||
matrixStack,
|
||||
vertexConsumerProvider,
|
||||
fishingBobberEntity.world,
|
||||
0
|
||||
)
|
||||
|
||||
matrixStack.push() // prepare for transforms for Bait rendering
|
||||
|
||||
// check if any adjustments are needed for the certain kind of bait
|
||||
val berryAdjust = adjustBerry(pokeBobberBaitItemStack)
|
||||
|
||||
// Scale down the bait to 70% of its original size
|
||||
matrixStack.scale(0.8f, 0.8f, 0.8f) // Apply the scaling transformation
|
||||
|
||||
// Translate the bait downwards to be on the hook
|
||||
matrixStack.translate(0.20 + berryAdjust.first, -0.5 + berryAdjust.second, 0.0); // Move the berry down
|
||||
|
||||
// Rotate the bait 90 degrees around the Y-axis
|
||||
val rotation = Quaternionf().rotateY(Math.toRadians(0.0).toFloat())
|
||||
matrixStack.multiply(rotation)
|
||||
|
||||
|
||||
// render the bait
|
||||
MinecraftClient.getInstance().itemRenderer.renderItem(
|
||||
pokeBobberBaitItemStack,
|
||||
ModelTransformationMode.GROUND,
|
||||
light,
|
||||
OverlayTexture.DEFAULT_UV,
|
||||
matrixStack,
|
||||
vertexConsumerProvider,
|
||||
fishingBobberEntity.world,
|
||||
0
|
||||
)
|
||||
|
||||
matrixStack.pop() // close bait rendering transforms
|
||||
matrixStack.pop() // close bobber rendering transforms
|
||||
|
||||
var armOffset = if (playerEntity.mainArm == Arm.RIGHT) 1 else -1
|
||||
val itemStack = playerEntity.mainHandStack
|
||||
if (itemStack.item !is PokerodItem) {
|
||||
armOffset = -armOffset
|
||||
}
|
||||
val handSwingProgress = playerEntity.getHandSwingProgress(tickDelta)
|
||||
val swingAngle = MathHelper.sin(MathHelper.sqrt(handSwingProgress) * Math.PI.toFloat())
|
||||
val bodyYawRadians = MathHelper.lerp(tickDelta, playerEntity.prevBodyYaw, playerEntity.bodyYaw) * (Math.PI.toFloat() / 180)
|
||||
val sinBodyYaw = MathHelper.sin(bodyYawRadians).toDouble()
|
||||
val cosBodyYaw = MathHelper.cos(bodyYawRadians).toDouble()
|
||||
val horizontalOffset = armOffset.toDouble() * 0.35
|
||||
if (dispatcher.gameOptions != null && !dispatcher.gameOptions.perspective.isFirstPerson || playerEntity !== MinecraftClient.getInstance().player) {
|
||||
playerEyeYWorld = MathHelper.lerp(tickDelta.toDouble(), playerEntity.prevX, playerEntity.x) - cosBodyYaw * horizontalOffset - sinBodyYaw * 0.8
|
||||
playerPosYWorld = playerEntity.prevY + playerEntity.standingEyeHeight.toDouble() + (playerEntity.y - playerEntity.prevY) * tickDelta.toDouble() - 0.45
|
||||
playerPosZWorld = MathHelper.lerp(tickDelta.toDouble(), playerEntity.prevZ, playerEntity.z) - sinBodyYaw * horizontalOffset + cosBodyYaw * 0.8
|
||||
eyeHeightOffset = if (playerEntity.isInSneakingPose) -0.1875f else 0.0f
|
||||
} else {
|
||||
playerPosXWorld = 960.0 / dispatcher.gameOptions.fov.value.toDouble()
|
||||
var vec3d = dispatcher.camera.projection.getPosition(armOffset.toFloat() * 0.525f, -0.1f)
|
||||
vec3d = vec3d.multiply(playerPosXWorld)
|
||||
vec3d = vec3d.rotateY(swingAngle * 0.5f)
|
||||
vec3d = vec3d.rotateX(-swingAngle * 0.7f)
|
||||
playerEyeYWorld = MathHelper.lerp(tickDelta.toDouble(), playerEntity.prevX, playerEntity.getX()) + vec3d.x
|
||||
playerPosYWorld = MathHelper.lerp(tickDelta.toDouble(), playerEntity.prevY, playerEntity.getY()) + vec3d.y
|
||||
playerPosZWorld = MathHelper.lerp(tickDelta.toDouble(), playerEntity.prevZ, playerEntity.getZ()) + vec3d.z
|
||||
eyeHeightOffset = playerEntity.getStandingEyeHeight()
|
||||
}
|
||||
playerPosXWorld = MathHelper.lerp(tickDelta.toDouble(), fishingBobberEntity.prevX, fishingBobberEntity.x)
|
||||
|
||||
val bobberPosY = MathHelper.lerp(tickDelta.toDouble(), fishingBobberEntity.prevY, fishingBobberEntity.y) + 0.25
|
||||
val bobberPosZ = MathHelper.lerp(tickDelta.toDouble(), fishingBobberEntity.prevZ, fishingBobberEntity.z)
|
||||
|
||||
val deltaX = (playerEyeYWorld - playerPosXWorld).toFloat()
|
||||
val deltaY = (playerPosYWorld - bobberPosY).toFloat() + eyeHeightOffset
|
||||
val deltaZ = (playerPosZWorld - bobberPosZ).toFloat()
|
||||
val vertexConsumer2 = vertexConsumerProvider.getBuffer(RenderLayer.getLineStrip())
|
||||
val entry2 = matrixStack.peek()
|
||||
for (lineIndex in 0..16) {
|
||||
renderFishingLine(pokeRod.lineColor, deltaX, deltaY, deltaZ, vertexConsumer2, entry2, percentage(lineIndex, 16), percentage(lineIndex + 1, 16))
|
||||
}
|
||||
|
||||
matrixStack.pop() // close main rendering transforms
|
||||
|
||||
super.render(fishingBobberEntity, elapsedPartialTicks, tickDelta, matrixStack, vertexConsumerProvider, light)
|
||||
}
|
||||
|
||||
fun adjustBerry(berryBait: ItemStack): Pair<Double, Double> {
|
||||
return when (Registries.ITEM.getId(berryBait.item).toString()) {
|
||||
"wacan_berry" -> Pair(0.03, 0.0)
|
||||
"cheri_berry" -> Pair(0.03, 0.0)
|
||||
else -> Pair(0.0, 0.0)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TEXTURE = cobblemonResource("textures/item/fishing/bobber_hook.png")
|
||||
private val LAYER = RenderLayer.getEntityCutout(TEXTURE)
|
||||
|
||||
private fun vertex(buffer: VertexConsumer, matrix: Matrix4f, normalMatrix: Matrix3f, light: Int, x: Float, y: Float, 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 percentage(value: Int, max: Int): Float {
|
||||
return value.toFloat() / max.toFloat()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
private fun renderFishingLine(color: String, deltaX: Float, deltaY: Float, deltaZ: Float, vertexBuffer: VertexConsumer, matrixEntry: MatrixStack.Entry, segmentStartFraction: Float, segmentEndFraction: Float) {
|
||||
val colorObj = Color.decode(color)
|
||||
// Calculate the starting X position of the current segment based on the start fraction
|
||||
val startX = deltaX * segmentStartFraction
|
||||
// Calculate the starting Y position of the current segment, adding a curvature effect and a base offset
|
||||
var startY = deltaY * (segmentStartFraction * segmentStartFraction + segmentStartFraction) * 0.5f + 0.25f
|
||||
// Calculate the starting Z position of the current segment based on the start fraction
|
||||
val startZ = deltaZ * segmentStartFraction
|
||||
|
||||
// Calculate the change in X position from the start to the end of the current segment
|
||||
var deltaXSegment = deltaX * segmentEndFraction - startX
|
||||
// Calculate the change in Y position from the start to the end of the current segment, adjusting for curvature and base offset
|
||||
var deltaYSegment = deltaY * (segmentEndFraction * segmentEndFraction + segmentEndFraction) * 0.5f + 0.25f - startY
|
||||
// Calculate the change in Z position from the start to the end of the current segment
|
||||
var deltaZSegment = deltaZ * segmentEndFraction - startZ
|
||||
|
||||
// Normalize the segment vector to use it for the normal vector in the vertex data
|
||||
val length = MathHelper.sqrt(deltaXSegment * deltaXSegment + deltaYSegment * deltaYSegment + deltaZSegment * deltaZSegment)
|
||||
deltaXSegment /= length
|
||||
deltaYSegment /= length
|
||||
deltaZSegment /= length
|
||||
|
||||
// New factor to adjust the curve so it ends lower
|
||||
// This could be a simple linear adjustment or more complex based on your needs
|
||||
val loweringFactor = 1.0f - segmentEndFraction // Becomes 0 at the start and approaches 1 towards the end
|
||||
val additionalLowering = loweringFactor * 0.1f // Adjust this factor to control how much lower the end goes
|
||||
|
||||
// Apply the lowering adjustment
|
||||
startY -= additionalLowering
|
||||
|
||||
|
||||
// Add the vertex for the start of this segment
|
||||
vertexBuffer.vertex(matrixEntry.positionMatrix, startX, startY, startZ).color(colorObj.red, colorObj.green, colorObj.blue, 255).normal(matrixEntry.normalMatrix, deltaXSegment, deltaYSegment, deltaZSegment).next()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getTexture(entity: PokeRodFishingBobberEntity): Identifier {
|
||||
return cobblemonResource("textures/item/fishing/bobber_hook.png")
|
||||
}
|
||||
|
||||
}
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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.interactive.PokerodItem
|
||||
import net.minecraft.client.item.ClampedModelPredicateProvider
|
||||
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.ItemStack
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
object CobblemonModelPredicateRegistry {
|
||||
|
||||
fun registerPredicates() {
|
||||
|
||||
val rods = listOf(
|
||||
CobblemonItems.AZURE_ROD,
|
||||
CobblemonItems.BEAST_ROD,
|
||||
CobblemonItems.CHERISH_ROD,
|
||||
CobblemonItems.CITRINE_ROD,
|
||||
CobblemonItems.DIVE_ROD,
|
||||
CobblemonItems.DREAM_ROD,
|
||||
CobblemonItems.DUSK_ROD,
|
||||
CobblemonItems.FAST_ROD,
|
||||
CobblemonItems.FRIEND_ROD,
|
||||
CobblemonItems.GREAT_ROD,
|
||||
CobblemonItems.HEAL_ROD,
|
||||
CobblemonItems.HEAVY_ROD,
|
||||
CobblemonItems.LEVEL_ROD,
|
||||
CobblemonItems.LOVE_ROD,
|
||||
CobblemonItems.LURE_ROD,
|
||||
CobblemonItems.LUXURY_ROD,
|
||||
CobblemonItems.MASTER_ROD,
|
||||
CobblemonItems.MOON_ROD,
|
||||
CobblemonItems.NEST_ROD,
|
||||
CobblemonItems.NET_ROD,
|
||||
CobblemonItems.PARK_ROD,
|
||||
CobblemonItems.POKE_ROD,
|
||||
CobblemonItems.PREMIER_ROD,
|
||||
CobblemonItems.QUICK_ROD,
|
||||
CobblemonItems.REPEAT_ROD,
|
||||
CobblemonItems.ROSEATE_ROD,
|
||||
CobblemonItems.SAFARI_ROD,
|
||||
CobblemonItems.SLATE_ROD,
|
||||
CobblemonItems.SPORT_ROD,
|
||||
CobblemonItems.TIMER_ROD,
|
||||
CobblemonItems.ULTRA_ROD,
|
||||
CobblemonItems.VERDANT_ROD,
|
||||
CobblemonItems.ANCIENT_AZURE_ROD,
|
||||
CobblemonItems.ANCIENT_CITRINE_ROD,
|
||||
CobblemonItems.ANCIENT_FEATHER_ROD,
|
||||
CobblemonItems.ANCIENT_GIGATON_ROD,
|
||||
CobblemonItems.ANCIENT_GREAT_ROD,
|
||||
CobblemonItems.ANCIENT_HEAVY_ROD,
|
||||
CobblemonItems.ANCIENT_IVORY_ROD,
|
||||
CobblemonItems.ANCIENT_JET_ROD,
|
||||
CobblemonItems.ANCIENT_LEADEN_ROD,
|
||||
CobblemonItems.ANCIENT_ORIGIN_ROD,
|
||||
CobblemonItems.ANCIENT_POKE_ROD,
|
||||
CobblemonItems.ANCIENT_ROSEATE_ROD,
|
||||
CobblemonItems.ANCIENT_SLATE_ROD,
|
||||
CobblemonItems.ANCIENT_ULTRA_ROD,
|
||||
CobblemonItems.ANCIENT_VERDANT_ROD,
|
||||
CobblemonItems.ANCIENT_WING_ROD
|
||||
)
|
||||
|
||||
rods.forEach { rod ->
|
||||
ModelPredicateProviderRegistry.register(rod, Identifier("cast"), ClampedModelPredicateProvider { stack, world, entity, seed ->
|
||||
if (entity == null) {
|
||||
0.0f
|
||||
} else {
|
||||
val isMainHand = entity.mainHandStack == stack
|
||||
var isOffHand = entity.offHandStack == stack
|
||||
if (entity.mainHandStack.item is PokerodItem) {
|
||||
isOffHand = false
|
||||
}
|
||||
|
||||
if ((isMainHand || isOffHand) && entity is PlayerEntity && entity.fishHook != null) 1.0f else 0.0f
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,8 @@ import com.cobblemon.mod.common.api.data.DataProvider
|
||||
import com.cobblemon.mod.common.api.data.DataRegistry
|
||||
import com.cobblemon.mod.common.api.dialogue.Dialogues
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.fishing.FishingBaits
|
||||
import com.cobblemon.mod.common.api.fishing.PokeRods
|
||||
import com.cobblemon.mod.common.api.fossil.Fossils
|
||||
import com.cobblemon.mod.common.api.fossil.NaturalMaterials
|
||||
import com.cobblemon.mod.common.api.moves.Moves
|
||||
@@ -74,7 +76,9 @@ object CobblemonDataProvider : DataProvider {
|
||||
this.register(Fossils)
|
||||
|
||||
CobblemonSpawnPools.load()
|
||||
this.register(PokeRods)
|
||||
this.register(Berries)
|
||||
this.register(FishingBaits)
|
||||
|
||||
PlatformEvents.SERVER_PLAYER_LOGOUT.subscribe {
|
||||
synchronizedPlayerIds.remove(it.player.uuid)
|
||||
|
||||
+721
@@ -0,0 +1,721 @@
|
||||
/*
|
||||
* 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.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.fishing.FishingBait
|
||||
import com.cobblemon.mod.common.api.fishing.FishingBaits
|
||||
import com.cobblemon.mod.common.api.pokemon.Natures
|
||||
import com.cobblemon.mod.common.api.spawning.BestSpawner
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.detail.EntitySpawnResult
|
||||
import com.cobblemon.mod.common.api.spawning.fishing.FishingSpawnCause
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.api.types.tera.TeraTypes
|
||||
import com.cobblemon.mod.common.battles.BattleBuilder
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.item.interactive.PokerodItem
|
||||
import com.cobblemon.mod.common.loot.CobblemonLootTables
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.abilities.HiddenAbility
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.cobblemon.mod.common.util.toBlockPos
|
||||
import kotlin.math.sqrt
|
||||
import net.minecraft.advancement.criterion.Criteria
|
||||
import net.minecraft.block.Blocks
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.entity.EntityType
|
||||
import net.minecraft.entity.ExperienceOrbEntity
|
||||
import net.minecraft.entity.ItemEntity
|
||||
import net.minecraft.entity.MovementType
|
||||
import net.minecraft.entity.data.DataTracker
|
||||
import net.minecraft.entity.data.TrackedData
|
||||
import net.minecraft.entity.data.TrackedDataHandlerRegistry
|
||||
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.context.LootContextParameterSet
|
||||
import net.minecraft.loot.context.LootContextParameters
|
||||
import net.minecraft.loot.context.LootContextTypes
|
||||
import net.minecraft.particle.DefaultParticleType
|
||||
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.SoundCategory
|
||||
import net.minecraft.stat.Stats
|
||||
import net.minecraft.util.Hand
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.hit.BlockHitResult
|
||||
import net.minecraft.util.hit.EntityHitResult
|
||||
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 net.minecraft.world.World
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
|
||||
class PokeRodFishingBobberEntity(type: EntityType<out PokeRodFishingBobberEntity>, world: World) : FishingBobberEntity(type, world) {
|
||||
|
||||
private val velocityRandom = Random.create()
|
||||
private var caughtFish = false
|
||||
private var outOfOpenWaterTicks = 0
|
||||
|
||||
// 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
|
||||
var inOpenWater = true
|
||||
private var hookedEntity: Entity? = null
|
||||
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 val pokemonSpawnChance = 85 // chance a Pokemon will be fished up % out of 100
|
||||
var pokeRodId: Identifier? = null
|
||||
var lineColor: String = "000000" // default line color is black
|
||||
var usedRod: Identifier? = null
|
||||
var bobberBait: ItemStack = ItemStack.EMPTY
|
||||
|
||||
constructor(thrower: PlayerEntity, pokeRodId: Identifier, bait: ItemStack, world: World, luckOfTheSea: Int, lure: Int) : this(CobblemonEntities.POKE_BOBBER, world) {
|
||||
owner = thrower
|
||||
luckOfTheSeaLevel = luckOfTheSea
|
||||
lureLevel = lure
|
||||
this.pokeRodId = pokeRodId
|
||||
this.bobberBait = bait
|
||||
dataTracker.set(POKEROD_ID, pokeRodId.toString())
|
||||
dataTracker.set(POKEBOBBER_BAIT, bobberBait)
|
||||
dataTracker.set(HOOK_ENTITY_ID, 0)
|
||||
dataTracker.set(CAUGHT_FISH, false)
|
||||
|
||||
this.usedRod = pokeRodId
|
||||
|
||||
|
||||
val throwerPitch = thrower.pitch
|
||||
val throwerYaw = thrower.yaw
|
||||
val cosYaw = MathHelper.cos(-throwerYaw * 0.017453292f - 3.1415927f)
|
||||
val sinYaw = MathHelper.sin(-throwerYaw * 0.017453292f - 3.1415927f)
|
||||
val cosPitch = -MathHelper.cos(-throwerPitch * 0.017453292f)
|
||||
val sinPitch = MathHelper.sin(-throwerPitch * 0.017453292f)
|
||||
val posX = thrower.x - sinYaw.toDouble() * 0.3
|
||||
val posY = thrower.eyeY
|
||||
val posZ = thrower.z - cosYaw.toDouble() * 0.3
|
||||
this.refreshPositionAndAngles(posX, posY, posZ, throwerYaw, throwerPitch)
|
||||
var vec3d = Vec3d((-sinYaw).toDouble(), MathHelper.clamp(-(sinPitch / cosPitch), -5.0f, 5.0f).toDouble(), (-cosYaw).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
|
||||
}
|
||||
|
||||
override fun initDataTracker() {
|
||||
this.dataTracker.startTracking(HOOK_ENTITY_ID, 0)
|
||||
this.dataTracker.startTracking(CAUGHT_FISH, false)
|
||||
this.dataTracker.startTracking(POKEROD_ID, "")
|
||||
this.dataTracker.startTracking(POKEBOBBER_BAIT, ItemStack.EMPTY)
|
||||
}
|
||||
|
||||
override fun onTrackedDataSet(data: TrackedData<*>) {
|
||||
if (HOOK_ENTITY_ID == data) {
|
||||
val i = getDataTracker().get(HOOK_ENTITY_ID) as Int
|
||||
this.hookedEntity = if (i > 0) world.getEntityById(i - 1) else null
|
||||
}
|
||||
|
||||
if (CAUGHT_FISH == data) {
|
||||
this.caughtFish = (getDataTracker().get(CAUGHT_FISH) as Boolean)
|
||||
if (this.caughtFish) {
|
||||
this.setVelocity(velocity.x, (-0.4f * MathHelper.nextFloat(this.velocityRandom, 0.3f, 0.5f)).toDouble(), velocity.z)
|
||||
}
|
||||
}
|
||||
|
||||
super.onTrackedDataSet(data)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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) { // create a fish trail that leads to the bobber visually
|
||||
this.fishTravelCountdown -= i
|
||||
if (this.fishTravelCountdown > 0) {
|
||||
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 offsetX = this.x + (g * this.fishTravelCountdown.toFloat() * 0.1f).toDouble()
|
||||
val offsetY = (MathHelper.floor(this.y).toFloat() + 1.0f).toDouble()
|
||||
val j = this.z + (h * this.fishTravelCountdown.toFloat() * 0.1f).toDouble()
|
||||
val blockState = serverWorld.getBlockState(BlockPos.ofFloored(offsetX, offsetY - 1.0, j))
|
||||
//val blockState = serverWorld.getBlockState(BlockPos.ofFloored(offsetX, (MathHelper.floor(this.y).toFloat() + 1.0f).toDouble().also { offsetY = 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, this.x, this.y, this.z, 3, g.toDouble(), 0.1, h.toDouble(), 0.0)
|
||||
serverWorld.spawnParticles(ParticleTypes.BUBBLE, offsetX, offsetY - 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, offsetX, offsetY, j, 0, l.toDouble(), 0.01, -k.toDouble(), 1.0)
|
||||
serverWorld.spawnParticles(ParticleTypes.FISHING, offsetX, offsetY, 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)
|
||||
// play bobber hook notification sound
|
||||
world.playSound(null, this.blockPos, CobblemonSounds.FISHING_NOTIFICATION, SoundCategory.BLOCKS, 1.0F, 1.0F)
|
||||
|
||||
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)
|
||||
|
||||
// check for chance to catch pokemon based on the bait
|
||||
if (MathHelper.nextInt(random, 0, 100) < getPokemonSpawnChance(bobberBait)) {
|
||||
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)
|
||||
|
||||
println("Player hooked a Pokemon from the bucket: " + chosenBucket.name)
|
||||
|
||||
}
|
||||
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) {
|
||||
val g = MathHelper.nextFloat(this.random, 0.0f, 360.0f) * 0.017453292f
|
||||
val h = MathHelper.nextFloat(this.random, 25.0f, 60.0f)
|
||||
val d = this.x + (MathHelper.sin(g) * h).toDouble() * 0.1 // X
|
||||
val e = (MathHelper.floor(this.y).toFloat() + 1.0f).toDouble() // Y
|
||||
val j = this.z + (MathHelper.cos(g) * h).toDouble() * 0.1 // randomized Z value
|
||||
val blockState = serverWorld.getBlockState(BlockPos.ofFloored(d, e - 1.0, j))
|
||||
if (blockState.isOf(Blocks.WATER)) {
|
||||
serverWorld.spawnParticles<DefaultParticleType>(ParticleTypes.SPLASH, d, e, j, 2 + random.nextInt(2), 0.10000000149011612, 0.0, 0.10000000149011612, 0.0)
|
||||
}
|
||||
}
|
||||
if (this.waitCountdown <= 0) {
|
||||
this.fishAngle = MathHelper.nextFloat(random, 0.0f, 360.0f)
|
||||
this.fishTravelCountdown = MathHelper.nextInt(random, 20, 80)
|
||||
}
|
||||
} else {
|
||||
// set the time it takes to wait for a hooked item or pokemon
|
||||
this.waitCountdown = MathHelper.nextInt(random, 100, 600)
|
||||
this.waitCountdown -= this.lureLevel * 20 * 5
|
||||
|
||||
// check for the bait on the hook and see if the waitCountdown is reduced
|
||||
this.waitCountdown = alterBiteTimeAttempt(this.waitCountdown, this.bobberBait)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeIfInvalid(player: PlayerEntity): Boolean {
|
||||
val itemStack = player.mainHandStack
|
||||
val itemStack2 = player.offHandStack
|
||||
val bl = Registries.ITEM[this.usedRod] == itemStack.item //(itemStack.item is PokerodItem) // todo make this work again so the line breaks when you swap items
|
||||
val bl2 = Registries.ITEM[this.usedRod] == itemStack2.item //(itemStack2.item is PokerodItem) // todo make this work again so the line breaks when you swap items
|
||||
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)
|
||||
}
|
||||
|
||||
override fun canHit(entity: Entity): Boolean {
|
||||
return super.canHit(entity) || entity.isAlive && entity is ItemEntity
|
||||
}
|
||||
|
||||
override fun onEntityHit(entityHitResult: EntityHitResult) {
|
||||
//super.onEntityHit(entityHitResult) // this calls the function in FishingBobberEntity which has null values which causes crash I think
|
||||
|
||||
// ProjectileEntity.onEntityHit(entityHitResult) // this is protected and cannot be reached
|
||||
if (!world.isClient) {
|
||||
this.updateHookedEntityId(entityHitResult.entity)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBlockHit(blockHitResult: BlockHitResult) {
|
||||
super.onBlockHit(blockHitResult)
|
||||
this.velocity = velocity.normalize().multiply(blockHitResult.squaredDistanceTo(this))
|
||||
}
|
||||
|
||||
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)
|
||||
inOpenWater = if (hookCountdown <= 0 && fishTravelCountdown <= 0) {
|
||||
true
|
||||
} else {
|
||||
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
|
||||
}
|
||||
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(CobblemonLootTables.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
|
||||
itemEntity.setVelocity(d * 0.1, e * 0.1 + sqrt(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
|
||||
|
||||
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, chosenBucket, bobberBait)
|
||||
|
||||
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, 6 + random.nextInt(4), 0.0, 0.2, 0.0, 0.0)
|
||||
|
||||
// spawn test particle when reeling in pokemon
|
||||
val particle = Identifier("cobblemon:impact_water")
|
||||
//SpawnSnowstormParticlePacket(particle, this.pos)
|
||||
SpawnSnowstormEntityParticlePacket(particle,this.id)
|
||||
|
||||
playerEntity.world.spawnEntity(ExperienceOrbEntity(playerEntity.world, playerEntity.x, playerEntity.y + 0.5, playerEntity.z + 0.5, random.nextInt(6) + 1))
|
||||
}
|
||||
}
|
||||
if (this.isOnGround) {
|
||||
i = 2
|
||||
}
|
||||
discard()
|
||||
i
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
// calculate the trajectory for the reeled in pokemon
|
||||
fun lobPokemonTowardsTarget(player: PlayerEntity, entity: Entity) {
|
||||
val rad = Math.toRadians(player.yaw.toDouble())
|
||||
val targetDirection = Vec3d(-sin(rad), 0.0, cos(rad))
|
||||
val targetPos = player.pos.add(targetDirection.multiply(5.0))
|
||||
|
||||
val delta = targetPos.subtract(entity.pos)
|
||||
val horizontalDistance = sqrt(delta.x * delta.x + delta.z * delta.z)
|
||||
|
||||
// Introduce a damping factor that reduces the velocity as the distance increases
|
||||
val dampingFactor = 1 - (horizontalDistance / 80).coerceIn(0.0, 0.8) // increase end of coerceIn to dampen more
|
||||
|
||||
val verticalVelocity = 0.30 // Base vertical velocity for a gentle arc
|
||||
val horizontalVelocityFactor = 0.13 // Base horizontal velocity factor
|
||||
|
||||
// Apply the damping factor to both horizontal and vertical velocities
|
||||
val adjustedHorizontalVelocity = horizontalDistance * horizontalVelocityFactor * dampingFactor
|
||||
val adjustedVerticalVelocity = (verticalVelocity + (horizontalDistance * 0.05)) * dampingFactor
|
||||
|
||||
// Calculate the final velocities
|
||||
val velocityX = delta.x / horizontalDistance * adjustedHorizontalVelocity
|
||||
val velocityZ = delta.z / horizontalDistance * adjustedHorizontalVelocity
|
||||
|
||||
val tossVelocity = Vec3d(velocityX, adjustedVerticalVelocity, velocityZ)
|
||||
entity.velocity = tossVelocity
|
||||
}
|
||||
|
||||
fun spawnPokemonFromFishing(player: PlayerEntity, chosenBucket: SpawnBucket, bobberBait: ItemStack) {
|
||||
var hookedEntityID: Int? = null
|
||||
|
||||
val spawner = BestSpawner.fishingSpawner
|
||||
|
||||
//val spawnCause = SpawnCause(spawner = spawner, bucket = spawner.chooseBucket(), entity = spawner.getCauseEntity())
|
||||
val spawnCause = FishingSpawnCause(
|
||||
spawner,
|
||||
chosenBucket,
|
||||
player,
|
||||
player.mainHandStack, // Crab, you should probably parse in the rod item connected to the bobber so we can check enchants in spawn conditions
|
||||
bobberBait
|
||||
)
|
||||
|
||||
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(lang("fishing.nocatch").red())
|
||||
return
|
||||
}
|
||||
|
||||
var spawnedPokemon: PokemonEntity? = null
|
||||
val resultingSpawn = result.get()
|
||||
|
||||
if (resultingSpawn !is EntitySpawnResult) {
|
||||
return
|
||||
}
|
||||
|
||||
for (entity in resultingSpawn.entities) {
|
||||
//pokemon.uuid = it.uuid
|
||||
hookedEntityID = entity.id
|
||||
spawnedPokemon = (entity as PokemonEntity)
|
||||
|
||||
// todo Check if there was a berry used on the bobber and if so then see how it may affect the pokemon
|
||||
if (bobberBait != ItemStack.EMPTY) {
|
||||
// look up how mints affect the pokemon
|
||||
|
||||
// remove the bait from the bobber
|
||||
val playerPokerod = if (this.playerOwner?.getStackInHand(Hand.MAIN_HAND)?.item is PokerodItem) this.playerOwner!!.getStackInHand(Hand.MAIN_HAND).item else this.playerOwner!!.getStackInHand(Hand.OFF_HAND).item
|
||||
(playerPokerod as PokerodItem).bait = ItemStack.EMPTY
|
||||
}
|
||||
|
||||
|
||||
if (spawnedPokemon.pokemon.species.weight < 900) { // if weight value of Pokemon is less than 200 lbs (in hectograms) which we store weight as) then reel it in to the player
|
||||
// play sound for small splash when this weight class is fished up
|
||||
world.playSound(null, this.blockPos, CobblemonSounds.FISHING_SPLASH_SMALL, SoundCategory.BLOCKS, 1.0F, 1.0F)
|
||||
|
||||
// Example of applying the new velocity
|
||||
lobPokemonTowardsTarget(player, entity)
|
||||
}
|
||||
else { // it is a big lad and you cannot reel it in
|
||||
world.playSound(null, this.blockPos, CobblemonSounds.FISHING_SPLASH_BIG, SoundCategory.BLOCKS, 1.0F, 1.0F)
|
||||
}
|
||||
}
|
||||
|
||||
// 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() } }
|
||||
}
|
||||
}
|
||||
|
||||
fun checkBaitSuccessRate(successChance: Double): Boolean {
|
||||
return Math.random() <= successChance
|
||||
}
|
||||
|
||||
// check if the bite time is reduced based on the bait bonus
|
||||
fun alterBiteTimeAttempt(waitCountdown: Int, stack: ItemStack): Int {
|
||||
val bait = FishingBaits.getFromItemStack(stack) ?: return waitCountdown
|
||||
val effect = bait.effects[FishingBait.Effects.BITE_TIME] ?: return waitCountdown
|
||||
if (!checkBaitSuccessRate(effect.chance)) return waitCountdown
|
||||
return if (waitCountdown * (effect.value) <= 0)
|
||||
1 // return min value
|
||||
else
|
||||
(waitCountdown * (effect.value)).toInt()
|
||||
}
|
||||
|
||||
// check the chance of a pokemon to spawn and if it is affected by bait
|
||||
fun getPokemonSpawnChance(stack: ItemStack): Int {
|
||||
val bait = FishingBaits.getFromItemStack(stack) ?: return this.pokemonSpawnChance
|
||||
val effect = bait.effects[FishingBait.Effects.POKEMON_CHANCE] ?: return this.pokemonSpawnChance
|
||||
return if (checkBaitSuccessRate(effect.chance)) {
|
||||
((effect.chance) * 100).toInt()
|
||||
} else this.pokemonSpawnChance
|
||||
}
|
||||
|
||||
companion object {
|
||||
val POKEROD_ID = DataTracker.registerData(PokeRodFishingBobberEntity::class.java, TrackedDataHandlerRegistry.STRING)
|
||||
val POKEBOBBER_BAIT = DataTracker.registerData(PokeRodFishingBobberEntity::class.java, TrackedDataHandlerRegistry.ITEM_STACK)
|
||||
val HOOK_ENTITY_ID = DataTracker.registerData(PokeRodFishingBobberEntity::class.java, TrackedDataHandlerRegistry.INTEGER)
|
||||
private val CAUGHT_FISH = DataTracker.registerData(PokeRodFishingBobberEntity::class.java, TrackedDataHandlerRegistry.BOOLEAN)
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.item.group
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonItems
|
||||
import com.cobblemon.mod.common.api.fishing.PokeRods
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.item.ItemConvertible
|
||||
import net.minecraft.item.ItemGroup
|
||||
@@ -210,6 +211,8 @@ object CobblemonItemGroups {
|
||||
entries.add(CobblemonItems.DARK_GEM)
|
||||
entries.add(CobblemonItems.STEEL_GEM)
|
||||
entries.add(CobblemonItems.FAIRY_GEM)
|
||||
|
||||
entries.add(CobblemonItems.POKEROD_SMITHING_TEMPLATE)
|
||||
}
|
||||
|
||||
private fun blockEntries(displayContext: DisplayContext, entries: Entries) {
|
||||
@@ -534,6 +537,7 @@ object CobblemonItemGroups {
|
||||
|
||||
private fun pokeballentries(displayContext: DisplayContext, entries: Entries) {
|
||||
CobblemonItems.pokeBalls.forEach(entries::add)
|
||||
CobblemonItems.pokeRods.forEach(entries::add)
|
||||
}
|
||||
|
||||
private fun foodInjections(injector: Injector) {
|
||||
@@ -558,6 +562,7 @@ object CobblemonItemGroups {
|
||||
injector.putAfter(CobblemonItems.SUSPICIOUS_SHERD, CobblemonItems.NOSTALGIC_SHERD)
|
||||
|
||||
injector.putAfter(CobblemonItems.AUTOMATON_ARMOR_TRIM_SMITHING_TEMPLATE, Items.SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE)
|
||||
injector.putAfter(CobblemonItems.POKEROD_SMITHING_TEMPLATE, Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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.item.interactive
|
||||
|
||||
import com.cobblemon.mod.common.advancement.CobblemonCriteria
|
||||
import com.cobblemon.mod.common.api.fishing.FishingBaits
|
||||
import com.cobblemon.mod.common.api.fishing.PokeRods
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.api.text.gray
|
||||
import com.cobblemon.mod.common.entity.fishing.PokeRodFishingBobberEntity
|
||||
import com.cobblemon.mod.common.item.BerryItem
|
||||
import net.minecraft.client.item.TooltipContext
|
||||
import net.minecraft.enchantment.EnchantmentHelper
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.item.FishingRodItem
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.sound.SoundCategory
|
||||
import net.minecraft.sound.SoundEvents
|
||||
import net.minecraft.stat.Stats
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.ActionResult
|
||||
import net.minecraft.util.Hand
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.TypedActionResult
|
||||
import net.minecraft.world.World
|
||||
import net.minecraft.world.event.GameEvent
|
||||
|
||||
class PokerodItem(val pokeRodId: Identifier, settings: Settings?) : FishingRodItem(settings) {
|
||||
var bait: ItemStack = ItemStack.EMPTY
|
||||
|
||||
override fun use(world: World, user: PlayerEntity, hand: Hand): TypedActionResult<ItemStack> {
|
||||
// if item in mainhand is berry item then don't do anything
|
||||
if (user.getStackInHand(Hand.MAIN_HAND).item is BerryItem)
|
||||
return TypedActionResult(ActionResult.FAIL, user.getStackInHand(hand))
|
||||
|
||||
val itemStack = user.getStackInHand(hand)
|
||||
val offHandItem = user.getStackInHand(Hand.OFF_HAND)
|
||||
if (!world.isClient && user.fishHook == null && FishingBaits.isFishingBait(offHandItem) && !ItemStack.areItemsEqual(offHandItem, bait) && !user.isSneaking) {
|
||||
// swap baits if one is already on the hook
|
||||
if (bait != ItemStack.EMPTY) {
|
||||
user.dropStack(bait) // drop old bait
|
||||
bait = itemStack // apply new bait
|
||||
}
|
||||
|
||||
// apply it to the rod as bait
|
||||
bait = offHandItem.item.defaultStack
|
||||
|
||||
// decrement 1 stack of that item from the other hand
|
||||
offHandItem.decrement(1)
|
||||
}
|
||||
if (!world.isClient && user.fishHook == null && user.isSneaking) {
|
||||
// remove bait if one is already on the hook
|
||||
if (bait != ItemStack.EMPTY) {
|
||||
user.dropStack(bait) // drop old bait on the ground
|
||||
bait = ItemStack.EMPTY
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
val bobberEntity = PokeRodFishingBobberEntity(user, pokeRodId, bait/*Registries.ITEM.getId(bait?.item)*/, world, j, i)
|
||||
world.spawnEntity(bobberEntity)
|
||||
CobblemonCriteria.CAST_POKE_ROD.trigger(user as ServerPlayerEntity, !bait.isEmpty)
|
||||
}
|
||||
user.incrementStat(Stats.USED.getOrCreateStat(this))
|
||||
user.emitGameEvent(GameEvent.ITEM_INTERACT_START)
|
||||
}
|
||||
return TypedActionResult.success(itemStack, world.isClient())
|
||||
}
|
||||
|
||||
override fun getEnchantability(): Int {
|
||||
return 1
|
||||
}
|
||||
|
||||
override fun appendTooltip(
|
||||
stack: ItemStack,
|
||||
world: World?,
|
||||
tooltip: MutableList<Text>,
|
||||
context: TooltipContext
|
||||
) {
|
||||
val rod = PokeRods.getPokeRod((stack.item as PokerodItem).pokeRodId) ?: return
|
||||
val ball = PokeBalls.getPokeBall(rod.pokeBallId) ?: return
|
||||
tooltip.add(ball.item.name.copy().gray())
|
||||
super.appendTooltip(stack, world, tooltip, context)
|
||||
}
|
||||
|
||||
override fun getTranslationKey(): String {
|
||||
return "item.cobblemon.poke_rod"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.loot
|
||||
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
|
||||
object CobblemonLootTables {
|
||||
|
||||
val FISHING_GAMEPLAY = cobblemonResource("fishing/pokerod")
|
||||
|
||||
}
|
||||
@@ -54,7 +54,9 @@ object LootInjector {
|
||||
LootTables.SIMPLE_DUNGEON_CHEST,
|
||||
LootTables.SPAWN_BONUS_CHEST,
|
||||
LootTables.STRONGHOLD_CORRIDOR_CHEST,
|
||||
LootTables.WOODLAND_MANSION_CHEST
|
||||
LootTables.WOODLAND_MANSION_CHEST,
|
||||
LootTables.FISHING_TREASURE_GAMEPLAY,
|
||||
LootTables.FISHING_JUNK_GAMEPLAY
|
||||
).apply { addAll(villageHouseLootTables) }
|
||||
|
||||
/**
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.net.messages.client.data
|
||||
|
||||
import com.cobblemon.mod.common.api.fishing.PokeRods
|
||||
import com.cobblemon.mod.common.api.fishing.PokeRod
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
|
||||
class PokeRodRegistrySyncPacket(rods: Collection<PokeRod>) : DataRegistrySyncPacket<PokeRod, PokeRodRegistrySyncPacket>(rods) {
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("pokerod_sync")
|
||||
|
||||
fun decode(buffer: PacketByteBuf) = PokeRodRegistrySyncPacket(emptyList()).apply { decodeBuffer(buffer) }
|
||||
}
|
||||
|
||||
override val id = ID
|
||||
|
||||
override fun encodeEntry(buffer: PacketByteBuf, entry: PokeRod) {
|
||||
entry.encode(buffer)
|
||||
}
|
||||
|
||||
override fun decodeEntry(buffer: PacketByteBuf) = PokeRod.decode(buffer)
|
||||
|
||||
override fun synchronizeDecoded(entries: Collection<PokeRod>) {
|
||||
PokeRods.reload(entries.associateBy { it.name!! })
|
||||
}
|
||||
}
|
||||
+38
@@ -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.net.messages.client.fishing
|
||||
|
||||
import com.cobblemon.mod.common.api.fishing.FishingBait
|
||||
import com.cobblemon.mod.common.api.fishing.FishingBaits
|
||||
import com.cobblemon.mod.common.net.messages.client.data.DataRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
|
||||
|
||||
class FishingBaitRegistrySyncPacket(fishingBaits: List<FishingBait>) : DataRegistrySyncPacket<FishingBait, FishingBaitRegistrySyncPacket>(fishingBaits) {
|
||||
companion object {
|
||||
val ID = cobblemonResource("fishing_baits")
|
||||
fun decode(buffer: PacketByteBuf) = FishingBaitRegistrySyncPacket(emptyList()).apply { decodeBuffer(buffer) }
|
||||
}
|
||||
|
||||
|
||||
override val id = ID
|
||||
override fun encodeEntry(buffer: PacketByteBuf, entry: FishingBait) {
|
||||
buffer.writeIdentifier(entry.item)
|
||||
}
|
||||
|
||||
override fun decodeEntry(buffer: PacketByteBuf): FishingBait {
|
||||
// server handles the effects so client doesnt need to know them
|
||||
return FishingBait(buffer.readIdentifier(), emptyMap())
|
||||
}
|
||||
|
||||
override fun synchronizeDecoded(entries: Collection<FishingBait>) {
|
||||
FishingBaits.reload(entries.associateBy { it.item })
|
||||
}
|
||||
}
|
||||
@@ -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.pokemon.feature
|
||||
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.FlagSpeciesFeature
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
|
||||
|
||||
/**
|
||||
* A fishing. You know the one.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since November 25th, 2022
|
||||
*/
|
||||
|
||||
const val FISHED = "fished"
|
||||
|
||||
object FishedFeatureHandler {
|
||||
|
||||
fun updateFished(pokemon: Pokemon, fished: Boolean?) {
|
||||
val feature = pokemon.getFeature<FlagSpeciesFeature>(FISHED) ?: return
|
||||
val currentFished = feature.enabled
|
||||
if (currentFished != fished && fished != null) {
|
||||
feature.enabled = fished
|
||||
pokemon.updateAspects()
|
||||
pokemon.markFeatureDirty(feature)
|
||||
}
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"format_version": "1.12.0",
|
||||
"minecraft:geometry": [
|
||||
{
|
||||
"description": {
|
||||
"identifier": "geometry.pokerod_hook",
|
||||
"texture_width": 16,
|
||||
"texture_height": 8,
|
||||
"visible_bounds_width": 2,
|
||||
"visible_bounds_height": 1.5,
|
||||
"visible_bounds_offset": [0, 0.25, 0]
|
||||
},
|
||||
"bones": [
|
||||
{
|
||||
"name": "pokerod_hook",
|
||||
"pivot": [0, 0, 0],
|
||||
"cubes": [
|
||||
{"origin": [-5, -8, 0], "size": [6, 8, 0], "uv": [0, 0]}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
{
|
||||
"format_version": "1.12.0",
|
||||
"minecraft:geometry": [
|
||||
{
|
||||
"description": {
|
||||
"identifier": "geometry.wooper_heart_female",
|
||||
"texture_width": 64,
|
||||
"texture_height": 64,
|
||||
"visible_bounds_width": 3,
|
||||
"visible_bounds_height": 2.5,
|
||||
"visible_bounds_offset": [0, 0.75, 0]
|
||||
},
|
||||
"bones": [
|
||||
{
|
||||
"name": "wooper",
|
||||
"pivot": [0, 0, 0]
|
||||
},
|
||||
{
|
||||
"name": "body",
|
||||
"parent": "wooper",
|
||||
"pivot": [0, 4, 0]
|
||||
},
|
||||
{
|
||||
"name": "foot_left",
|
||||
"parent": "body",
|
||||
"pivot": [1.75, 1, 0.25],
|
||||
"cubes": [
|
||||
{"origin": [0.25, 0, -4.25], "size": [3, 1, 6], "uv": [12, 31]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "foot_right",
|
||||
"parent": "body",
|
||||
"pivot": [-1.75, 1, 0.25],
|
||||
"cubes": [
|
||||
{"origin": [-3.25, 0, -4.25], "size": [3, 1, 6], "uv": [0, 27]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "torso",
|
||||
"parent": "body",
|
||||
"pivot": [0, 4, 0],
|
||||
"cubes": [
|
||||
{"origin": [0.2, 5.5, -2.01], "size": [1, 1, 0], "inflate": 0.01, "uv": [0, 9]},
|
||||
{"origin": [-0.5, 5.1, -2.01], "size": [1, 1, 0], "uv": [4, 9]},
|
||||
{"origin": [-1.2, 5.5, -2.01], "size": [1, 1, 0], "inflate": 0.01, "uv": [2, 9]},
|
||||
{"origin": [-2.5, 5, -2], "size": [5, 2, 4], "uv": [24, 31]},
|
||||
{"origin": [-3, 1, -2.5], "size": [6, 4, 5], "uv": [17, 22]},
|
||||
{"origin": [-2.5, 1.25, -2.525], "size": [5, 2, 0], "uv": [0, 4]},
|
||||
{"origin": [-1.5, 3.5, -2.525], "size": [3, 1, 0], "uv": [4, 6]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tail",
|
||||
"parent": "torso",
|
||||
"pivot": [0, 2.25, 2.5],
|
||||
"cubes": [
|
||||
{"origin": [-1.5, 1.25, 2], "size": [3, 2, 2], "uv": [0, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tail2",
|
||||
"parent": "tail",
|
||||
"pivot": [0, 2.25, 4],
|
||||
"cubes": [
|
||||
{"origin": [-2.5, 0.75, 4], "size": [5, 3, 6], "uv": [0, 18]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "head",
|
||||
"parent": "torso",
|
||||
"pivot": [0, 7, 0],
|
||||
"cubes": [
|
||||
{"origin": [-5.5, 7, -5], "size": [11, 8, 10], "uv": [0, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "mouth_open_wide",
|
||||
"parent": "head",
|
||||
"pivot": [0, -3, -3.4],
|
||||
"cubes": [
|
||||
{"origin": [-4.5, 7.5, -4.93], "size": [9, 3, 0], "uv": [16, 18]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "mouth_open_small",
|
||||
"parent": "head",
|
||||
"pivot": [-3, -3.25, -3.4],
|
||||
"cubes": [
|
||||
{"origin": [-1, 8, -4.93], "size": [2, 3, 0], "uv": [0, 6]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "mouth_closed",
|
||||
"parent": "head",
|
||||
"pivot": [0, -3, -3.5],
|
||||
"cubes": [
|
||||
{"origin": [-3.5, 9, -5.025], "size": [7, 1, 0], "uv": [32, 7]},
|
||||
{"origin": [-4.5, 9.5, -5.025], "size": [9, 1, 0], "uv": [16, 21]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "lefteye",
|
||||
"parent": "head",
|
||||
"pivot": [3.25, 12.25, -5.025],
|
||||
"cubes": [
|
||||
{"origin": [2, 11, -5.025], "size": [2, 2, 0], "uv": [0, 22]},
|
||||
{"origin": [2.5, 11.5, -5.026], "size": [1, 1, 0], "uv": [0, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "righteye",
|
||||
"parent": "head",
|
||||
"pivot": [-3.25, 12.25, -5.025],
|
||||
"cubes": [
|
||||
{"origin": [-4, 11, -5.025], "size": [2, 2, 0], "uv": [0, 20]},
|
||||
{"origin": [-3.5, 11.5, -5.026], "size": [1, 1, 0], "uv": [0, 1]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "lefteyelid",
|
||||
"parent": "head",
|
||||
"pivot": [3.25, 11.75, -4.475],
|
||||
"cubes": [
|
||||
{"origin": [2, 11, -4.93], "size": [2, 2, 0], "uv": [0, 18]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "righteyelid",
|
||||
"parent": "head",
|
||||
"pivot": [-3.25, 11.75, -4.425],
|
||||
"cubes": [
|
||||
{"origin": [-4, 11, -4.93], "size": [2, 2, 0], "uv": [4, 7]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "gills_right",
|
||||
"parent": "head",
|
||||
"pivot": [-5.5, 10.25, 0],
|
||||
"cubes": [
|
||||
{"origin": [-11.5, 6.75, 0], "size": [6, 7, 0], "uv": [12, 38]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "gills_left",
|
||||
"parent": "head",
|
||||
"pivot": [5.5, 10.25, 0],
|
||||
"cubes": [
|
||||
{"origin": [5.5, 6.75, 0], "size": [6, 7, 0], "uv": [12, 45]}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
{
|
||||
"format_version": "1.12.0",
|
||||
"minecraft:geometry": [
|
||||
{
|
||||
"description": {
|
||||
"identifier": "geometry.wooper_heart_male",
|
||||
"texture_width": 64,
|
||||
"texture_height": 64,
|
||||
"visible_bounds_width": 3,
|
||||
"visible_bounds_height": 2.5,
|
||||
"visible_bounds_offset": [0, 0.75, 0]
|
||||
},
|
||||
"bones": [
|
||||
{
|
||||
"name": "wooper",
|
||||
"pivot": [0, 0, 0]
|
||||
},
|
||||
{
|
||||
"name": "body",
|
||||
"parent": "wooper",
|
||||
"pivot": [0, 4, 0]
|
||||
},
|
||||
{
|
||||
"name": "foot_left",
|
||||
"parent": "body",
|
||||
"pivot": [1.75, 1, 0.25],
|
||||
"cubes": [
|
||||
{"origin": [0.25, 0, -4.25], "size": [3, 1, 6], "uv": [12, 31]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "foot_right",
|
||||
"parent": "body",
|
||||
"pivot": [-1.75, 1, 0.25],
|
||||
"cubes": [
|
||||
{"origin": [-3.25, 0, -4.25], "size": [3, 1, 6], "uv": [0, 27]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "torso",
|
||||
"parent": "body",
|
||||
"pivot": [0, 4, 0],
|
||||
"cubes": [
|
||||
{"origin": [-2.5, 5, -2], "size": [5, 2, 4], "uv": [24, 31]},
|
||||
{"origin": [-3, 1, -2.5], "size": [6, 4, 5], "uv": [17, 22]},
|
||||
{"origin": [0.2, 5.5, -2.01], "size": [1, 1, 0], "inflate": 0.01, "uv": [0, 9]},
|
||||
{"origin": [-1.2, 5.5, -2.01], "size": [1, 1, 0], "inflate": 0.01, "uv": [2, 9]},
|
||||
{"origin": [-0.5, 5.1, -2.01], "size": [1, 1, 0], "uv": [4, 9]},
|
||||
{"origin": [-2.5, 1.25, -2.525], "size": [5, 2, 0], "uv": [0, 4]},
|
||||
{"origin": [-1.5, 3.5, -2.525], "size": [3, 1, 0], "uv": [4, 6]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tail",
|
||||
"parent": "torso",
|
||||
"pivot": [0, 2.25, 2.5],
|
||||
"cubes": [
|
||||
{"origin": [-1.5, 1.25, 2], "size": [3, 2, 2], "uv": [0, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tail2",
|
||||
"parent": "tail",
|
||||
"pivot": [0, 2.25, 4],
|
||||
"cubes": [
|
||||
{"origin": [-2.5, 0.75, 4], "size": [5, 3, 6], "uv": [0, 18]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "head",
|
||||
"parent": "torso",
|
||||
"pivot": [0, 7, 0],
|
||||
"cubes": [
|
||||
{"origin": [-5.5, 7, -5], "size": [11, 8, 10], "uv": [0, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "mouth_open_wide",
|
||||
"parent": "head",
|
||||
"pivot": [0, -3, -3.4],
|
||||
"cubes": [
|
||||
{"origin": [-4.5, 7.5, -4.93], "size": [9, 3, 0], "uv": [16, 18]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "mouth_open_small",
|
||||
"parent": "head",
|
||||
"pivot": [-3, -3.25, -3.4],
|
||||
"cubes": [
|
||||
{"origin": [-1, 8, -4.93], "size": [2, 3, 0], "uv": [0, 6]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "mouth_closed",
|
||||
"parent": "head",
|
||||
"pivot": [0, -3, -3.5],
|
||||
"cubes": [
|
||||
{"origin": [-3.5, 9, -5.025], "size": [7, 1, 0], "uv": [32, 7]},
|
||||
{"origin": [-4.5, 9.5, -5.025], "size": [9, 1, 0], "uv": [16, 21]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "lefteye",
|
||||
"parent": "head",
|
||||
"pivot": [3.25, 12.25, -5.025],
|
||||
"cubes": [
|
||||
{"origin": [2, 11, -5.025], "size": [2, 2, 0], "uv": [0, 22]},
|
||||
{"origin": [2.5, 11.5, -5.026], "size": [1, 1, 0], "uv": [0, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "righteye",
|
||||
"parent": "head",
|
||||
"pivot": [-3.25, 12.25, -5.025],
|
||||
"cubes": [
|
||||
{"origin": [-4, 11, -5.025], "size": [2, 2, 0], "uv": [0, 20]},
|
||||
{"origin": [-3.5, 11.5, -5.026], "size": [1, 1, 0], "uv": [0, 1]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "lefteyelid",
|
||||
"parent": "head",
|
||||
"pivot": [3.25, 11.75, -4.475],
|
||||
"cubes": [
|
||||
{"origin": [2, 11, -4.93], "size": [2, 2, 0], "uv": [0, 18]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "righteyelid",
|
||||
"parent": "head",
|
||||
"pivot": [-3.25, 11.75, -4.425],
|
||||
"cubes": [
|
||||
{"origin": [-4, 11, -4.93], "size": [2, 2, 0], "uv": [4, 7]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "gills_right",
|
||||
"parent": "head",
|
||||
"pivot": [-5.5, 10.25, 0],
|
||||
"cubes": [
|
||||
{"origin": [-11.5, 6.75, 0], "size": [6, 7, 0], "uv": [0, 38]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "gills_left",
|
||||
"parent": "head",
|
||||
"pivot": [5.5, 10.25, 0],
|
||||
"cubes": [
|
||||
{"origin": [5.5, 6.75, 0], "size": [6, 7, 0], "uv": [0, 45]}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
+286
@@ -0,0 +1,286 @@
|
||||
{
|
||||
"format_version": "1.12.0",
|
||||
"minecraft:geometry": [
|
||||
{
|
||||
"description": {
|
||||
"identifier": "geometry.whiscash",
|
||||
"texture_width": 256,
|
||||
"texture_height": 128,
|
||||
"visible_bounds_width": 12,
|
||||
"visible_bounds_height": 3.5,
|
||||
"visible_bounds_offset": [0, 1.25, 0]
|
||||
},
|
||||
"bones": [
|
||||
{
|
||||
"name": "whiscash",
|
||||
"pivot": [0, 0, -13]
|
||||
},
|
||||
{
|
||||
"name": "body",
|
||||
"parent": "whiscash",
|
||||
"pivot": [0, 12, 0]
|
||||
},
|
||||
{
|
||||
"name": "torso",
|
||||
"parent": "body",
|
||||
"pivot": [0, 10.75, 8.75],
|
||||
"cubes": [
|
||||
{"origin": [-19, 0, -24], "size": [38, 24, 34], "uv": [0, 0]},
|
||||
{"origin": [-18, 8, -27], "size": [36, 3, 3], "inflate": 0.01, "uv": [74, 64]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "whisker_left",
|
||||
"parent": "torso",
|
||||
"pivot": [19, 10, -19],
|
||||
"cubes": [
|
||||
{"origin": [19, 9, -19], "size": [12, 2, 0], "uv": [232, 56]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "whisker_left2",
|
||||
"parent": "whisker_left",
|
||||
"pivot": [30.5, 10, -19],
|
||||
"cubes": [
|
||||
{"origin": [30.5, 9, -19], "size": [12, 2, 0], "uv": [232, 54]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "whisker_left3",
|
||||
"parent": "whisker_left2",
|
||||
"pivot": [42, 10, -19],
|
||||
"cubes": [
|
||||
{"origin": [42, 9, -19], "size": [12, 2, 0], "uv": [232, 52]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "whisker_left4",
|
||||
"parent": "whisker_left3",
|
||||
"pivot": [53.5, 10, -19],
|
||||
"cubes": [
|
||||
{"origin": [53.5, 9, -19], "size": [12, 2, 0], "uv": [232, 50]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "whisker_left5",
|
||||
"parent": "whisker_left4",
|
||||
"pivot": [65, 10, -19],
|
||||
"cubes": [
|
||||
{"origin": [65, 9, -19], "size": [12, 2, 0], "uv": [110, 92]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "whisker_left6",
|
||||
"parent": "whisker_left5",
|
||||
"pivot": [76.5, 10, -19],
|
||||
"cubes": [
|
||||
{"origin": [76.5, 2, -19], "size": [11, 9, 0], "uv": [200, 64]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "whisker_right",
|
||||
"parent": "torso",
|
||||
"pivot": [-19, 10, -19],
|
||||
"cubes": [
|
||||
{"origin": [-31, 9, -19], "size": [12, 2, 0], "uv": [110, 90]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "whisker_right2",
|
||||
"parent": "whisker_right",
|
||||
"pivot": [-30.5, 10, -19],
|
||||
"cubes": [
|
||||
{"origin": [-42.5, 9, -19], "size": [12, 2, 0], "uv": [110, 32]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "whisker_right3",
|
||||
"parent": "whisker_right2",
|
||||
"pivot": [-42, 10, -19],
|
||||
"cubes": [
|
||||
{"origin": [-54, 9, -19], "size": [12, 2, 0], "uv": [163, 21]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "whisker_right4",
|
||||
"parent": "whisker_right3",
|
||||
"pivot": [-53.5, 10, -19],
|
||||
"cubes": [
|
||||
{"origin": [-65.5, 9, -19], "size": [12, 2, 0], "uv": [0, 31]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "whisker_right5",
|
||||
"parent": "whisker_right4",
|
||||
"pivot": [-65, 10, -19],
|
||||
"cubes": [
|
||||
{"origin": [-77, 9, -19], "size": [12, 2, 0], "uv": [0, 11]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "whisker_right6",
|
||||
"parent": "whisker_right5",
|
||||
"pivot": [-76.5, 10, -19],
|
||||
"cubes": [
|
||||
{"origin": [-87.5, 2, -19], "size": [11, 9, 0], "uv": [178, 61]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fin_left",
|
||||
"parent": "torso",
|
||||
"pivot": [19, 5, -7.5],
|
||||
"cubes": [
|
||||
{"origin": [19, 5, -13], "size": [7, 0, 11], "uv": [99, 11]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fin_left2",
|
||||
"parent": "fin_left",
|
||||
"pivot": [26, 5, -7.5],
|
||||
"cubes": [
|
||||
{"origin": [26, 5, -13], "size": [7, 0, 11], "uv": [99, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fin_right",
|
||||
"parent": "torso",
|
||||
"pivot": [-18.5, 5, -7.5],
|
||||
"cubes": [
|
||||
{"origin": [-26, 5, -13], "size": [7, 0, 11], "uv": [207, 46]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fin_right2",
|
||||
"parent": "fin_right",
|
||||
"pivot": [-26, 5, -7.5],
|
||||
"cubes": [
|
||||
{"origin": [-33, 5, -13], "size": [7, 0, 11], "uv": [0, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "jaw",
|
||||
"parent": "torso",
|
||||
"pivot": [0, 6.5, -25.5],
|
||||
"cubes": [
|
||||
{"origin": [-18, 5, -27], "size": [36, 3, 3], "inflate": 0.01, "uv": [74, 58]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "dangle_left",
|
||||
"parent": "jaw",
|
||||
"pivot": [12.5, 5.5, -25.5],
|
||||
"cubes": [
|
||||
{"origin": [9.5, -5.5, -25.5], "size": [6, 12, 0], "inflate": 0.01, "uv": [167, 23]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "dangle_right",
|
||||
"parent": "jaw",
|
||||
"pivot": [-12.5, 5.5, -25.5],
|
||||
"cubes": [
|
||||
{"origin": [-15.5, -5.5, -25.5], "size": [6, 12, 0], "inflate": 0.01, "uv": [0, 58]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "mouth_opening",
|
||||
"parent": "jaw",
|
||||
"pivot": [0, -1, -13.1],
|
||||
"cubes": [
|
||||
{"origin": [-18, 5, -24.1], "size": [36, 6, 0], "uv": [88, 84]},
|
||||
{"origin": [15, 5, -27], "size": [3, 6, 3], "uv": [179, 25]},
|
||||
{"origin": [-18, 5, -27], "size": [3, 6, 3], "uv": [182, 70]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "eye_left",
|
||||
"parent": "torso",
|
||||
"pivot": [16.51, 14.5, -22.01],
|
||||
"cubes": [
|
||||
{"origin": [14.01, 11.5, -24.01], "size": [5, 6, 4], "uv": [110, 22]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "eyelid_left",
|
||||
"parent": "eye_left",
|
||||
"pivot": [16.41, 14.5, -21.91],
|
||||
"cubes": [
|
||||
{"origin": [13.91, 11.5, -23.91], "size": [5, 6, 4], "inflate": 0.01, "uv": [149, 21]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "eye_right",
|
||||
"parent": "torso",
|
||||
"pivot": [-16.51, 14.5, -22.01],
|
||||
"cubes": [
|
||||
{"origin": [-19.01, 11.5, -24.01], "size": [5, 6, 4], "uv": [131, 21]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "eyelid_right",
|
||||
"parent": "eye_right",
|
||||
"pivot": [-16.41, 14.5, -21.91],
|
||||
"cubes": [
|
||||
{"origin": [-18.91, 11.5, -23.91], "size": [5, 6, 4], "inflate": 0.01, "uv": [228, 60]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fin",
|
||||
"parent": "torso",
|
||||
"pivot": [0, 22, 6.5],
|
||||
"rotation": [-25, 0, 0],
|
||||
"cubes": [
|
||||
{"origin": [0, 20, 0], "size": [0, 18, 13], "uv": [0, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tail",
|
||||
"parent": "torso",
|
||||
"pivot": [0, 9.5, 9],
|
||||
"cubes": [
|
||||
{"origin": [-15, 1, 7], "size": [30, 17, 14], "uv": [0, 58]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tail2",
|
||||
"parent": "tail",
|
||||
"pivot": [0, 7.5, 20],
|
||||
"cubes": [
|
||||
{"origin": [-9, 2, 20], "size": [18, 11, 10], "uv": [131, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tail3",
|
||||
"parent": "tail2",
|
||||
"pivot": [0, 6.5, 29],
|
||||
"cubes": [
|
||||
{"origin": [-5, 3.5, 29], "size": [10, 6, 10], "uv": [178, 45]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tail4",
|
||||
"parent": "tail3",
|
||||
"pivot": [0, 6.5, 38],
|
||||
"cubes": [
|
||||
{"origin": [-9.5, 6.5, 36], "size": [19, 0, 14], "uv": [74, 70]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fin_left3",
|
||||
"parent": "tail2",
|
||||
"pivot": [9, 5, 22],
|
||||
"cubes": [
|
||||
{"origin": [9, 5, 22], "size": [7, 0, 7], "uv": [211, 57]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fin_right3",
|
||||
"parent": "tail2",
|
||||
"pivot": [-9, 5, 22],
|
||||
"cubes": [
|
||||
{"origin": [-16, 5, 22], "size": [7, 0, 7], "uv": [161, 45]}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
+192
@@ -9,6 +9,198 @@
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp.png",
|
||||
"layers": []
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-standard"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-apricot-striped"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_apricot_striped.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-apricot-tiger"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_apricot_tiger.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-apricot-zebra"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_apricot_zebra.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-black-forehead"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_black_forehead.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-black-masked"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_black_masked.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-blue-raindrops"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_blue_raindrops.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-blue-saucy"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_blue_saucy.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-brown-striped"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_brown_striped.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-brown-tiger"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_brown_tiger.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-brown-zebra"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_brown_zebra.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-calico-1"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_calico_1.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-calico-2"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_calico_2.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-calico-3"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_calico_3.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-calico-4"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_calico_4.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-dapples"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_dapples.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-gray-bubbles"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_gray_bubbles.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-gray-diamonds"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_gray_diamonds.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-gray-patches"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_gray_patches.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-orange-forehead"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_orange_forehead.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-orange-masked"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_orange_masked.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-orca"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_orca.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-pink-dapples"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_pink_dapples.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-pink-orca"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_pink_orca.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-pink-two_tone"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_pink_two_tone.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-purple-bubbles"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_purple_bubbles.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-purple-diamonds"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_purple_diamonds.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-purple-patches"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_purple_patches.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-skelly"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_skelly.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-two-tone"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_two_tone.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-violet-raindrops"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_violet_raindrops.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"magikarp-jump-violet-saucy"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0129_magikarp/magikarp_violet_saucy.png"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"shiny"
|
||||
|
||||
+6
@@ -9,6 +9,12 @@
|
||||
"texture": "cobblemon:textures/pokemon/0194_wooper/wooper.png",
|
||||
"layers": []
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"wooper_heart"
|
||||
],
|
||||
"model": "cobblemon:wooper_heart_male.geo"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"shiny"
|
||||
|
||||
+6
@@ -7,6 +7,12 @@
|
||||
"female"
|
||||
],
|
||||
"model": "cobblemon:wooper_female.geo"
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"wooper_heart", "female"
|
||||
],
|
||||
"model": "cobblemon:wooper_heart_female.geo"
|
||||
}
|
||||
]
|
||||
}
|
||||
+10
@@ -9,6 +9,16 @@
|
||||
"texture": "cobblemon:textures/pokemon/0340_whiscash/whiscash.png",
|
||||
"layers": []
|
||||
},
|
||||
{
|
||||
"aspects": ["whiscash_nero"],
|
||||
"model": "cobblemon:whiscash_nero.geo",
|
||||
"texture": "cobblemon:textures/pokemon/0340_whiscash/whiscash_nero.png"
|
||||
},
|
||||
{
|
||||
"aspects": ["whiscash_nero", "shiny"],
|
||||
"model": "cobblemon:whiscash_nero.geo",
|
||||
"texture": "cobblemon:textures/pokemon/0340_whiscash/whiscash_nero_shiny.png"
|
||||
},
|
||||
{
|
||||
"aspects": ["shiny"],
|
||||
"texture": "cobblemon:textures/pokemon/0340_whiscash/whiscash_shiny.png"
|
||||
|
||||
@@ -48,6 +48,13 @@
|
||||
"item.cobblemon.ancient_jet_ball": "Ancient Jet Ball",
|
||||
"item.cobblemon.ancient_origin_ball": "Ancient Origin Ball",
|
||||
|
||||
"item.cobblemon.pokerod_smithing_template": "Poké Rod Smithing Template",
|
||||
"item.cobblemon.smithing_template.pokerod.ingredients": "Poké Balls",
|
||||
"item.cobblemon.smithing_template.pokerod.base_slot_description": "Add fishing rod",
|
||||
"item.cobblemon.smithing_template.pokerod.additions_slot_description": "Add Poké Ball",
|
||||
"upgrade.cobblemon.pokerod": "Poké Rod Upgrade",
|
||||
"item.cobblemon.poke_rod": "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",
|
||||
@@ -942,7 +949,12 @@
|
||||
"advancements.cobblemon.grow_tumblestone.description": "Place a Tumblestone near Lava or Magma to grow it over time",
|
||||
"advancements.cobblemon.craft_ancient_balls": "A true Antiquarian",
|
||||
"advancements.cobblemon.craft_ancient_balls.description": "Utilize Tumblestones to craft all fifteen Ancient Balls",
|
||||
|
||||
"advancements.cobblemon.craft_rod": "Gone fishing",
|
||||
"advancements.cobblemon.craft_rod.description": "Craft a Poké Rod using a Poké Rod Smithing Template",
|
||||
"advancements.cobblemon.use_bait": "A Berry Good Lure",
|
||||
"advancements.cobblemon.use_bait.description": "Use a berry as bait for your Poké Rod",
|
||||
"advancements.cobblemon.craft_master_rod": "Masterful Dedication",
|
||||
"advancements.cobblemon.craft_master_rod.description": "Craft a Poké Rod using a Master Ball",
|
||||
|
||||
"cobblemon.battle.crash": "A battle error has occurred. If playing single-player, report this to the mod team. Otherwise, report this to the servers administrator.",
|
||||
"cobblemon.battle.damage_dealt": "%1$s took %2$s damage!",
|
||||
@@ -1416,6 +1428,8 @@
|
||||
|
||||
"cobblemon.battle.mega": "%1$s has Mega Evolved!",
|
||||
|
||||
"cobblemon.fishing.nocatch": "Not even a nibble...",
|
||||
|
||||
"cobblemon.experience.gained": "%1$s received %2$s experience.",
|
||||
"cobblemon.experience.level_up": "%1$s is now level %2$s!",
|
||||
"cobblemon.experience.learned_move": "%1$s has learned %2$s.",
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"parent": "item/handheld_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_azure_rod"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"cast": 1
|
||||
},
|
||||
"model": "cobblemon:item/ancient_azure_rod_cast"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "cobblemon:item/ancient_azure_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_azure_rod_cast"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"parent": "item/handheld_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_citrine_rod"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"cast": 1
|
||||
},
|
||||
"model": "cobblemon:item/ancient_citrine_rod_cast"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "cobblemon:item/ancient_citrine_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_citrine_rod_cast"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"parent": "item/handheld_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_feather_rod"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"cast": 1
|
||||
},
|
||||
"model": "cobblemon:item/ancient_feather_rod_cast"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "cobblemon:item/ancient_feather_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_feather_rod_cast"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"parent": "item/handheld_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_gigaton_rod"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"cast": 1
|
||||
},
|
||||
"model": "cobblemon:item/ancient_gigaton_rod_cast"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "cobblemon:item/ancient_gigaton_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_gigaton_rod_cast"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"parent": "item/handheld_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_great_rod"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"cast": 1
|
||||
},
|
||||
"model": "cobblemon:item/ancient_great_rod_cast"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "cobblemon:item/ancient_great_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_great_rod_cast"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"parent": "item/handheld_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_heavy_rod"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"cast": 1
|
||||
},
|
||||
"model": "cobblemon:item/ancient_heavy_rod_cast"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "cobblemon:item/ancient_heavy_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_heavy_rod_cast"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"parent": "item/handheld_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_ivory_rod"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"cast": 1
|
||||
},
|
||||
"model": "cobblemon:item/ancient_ivory_rod_cast"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "cobblemon:item/ancient_ivory_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_ivory_rod_cast"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"parent": "item/handheld_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_jet_rod"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"cast": 1
|
||||
},
|
||||
"model": "cobblemon:item/ancient_jet_rod_cast"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "cobblemon:item/ancient_jet_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_jet_rod_cast"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"parent": "item/handheld_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_leaden_rod"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"cast": 1
|
||||
},
|
||||
"model": "cobblemon:item/ancient_leaden_rod_cast"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "cobblemon:item/ancient_leaden_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_leaden_rod_cast"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"parent": "item/handheld_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_origin_rod"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"cast": 1
|
||||
},
|
||||
"model": "cobblemon:item/ancient_origin_rod_cast"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "cobblemon:item/ancient_origin_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_origin_rod_cast"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"parent": "item/handheld_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_poke_rod"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"cast": 1
|
||||
},
|
||||
"model": "cobblemon:item/ancient_poke_rod_cast"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "cobblemon:item/ancient_poke_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_poke_rod_cast"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"parent": "item/handheld_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_roseate_rod"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"cast": 1
|
||||
},
|
||||
"model": "cobblemon:item/ancient_roseate_rod_cast"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "cobblemon:item/ancient_roseate_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_roseate_rod_cast"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"parent": "item/handheld_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_slate_rod"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"cast": 1
|
||||
},
|
||||
"model": "cobblemon:item/ancient_slate_rod_cast"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "cobblemon:item/ancient_slate_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_slate_rod_cast"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"parent": "item/handheld_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_ultra_rod"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"cast": 1
|
||||
},
|
||||
"model": "cobblemon:item/ancient_ultra_rod_cast"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "cobblemon:item/ancient_ultra_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_ultra_rod_cast"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"parent": "item/handheld_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_verdant_rod"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"cast": 1
|
||||
},
|
||||
"model": "cobblemon:item/ancient_verdant_rod_cast"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "cobblemon:item/ancient_verdant_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_verdant_rod_cast"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"parent": "item/handheld_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_wing_rod"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"cast": 1
|
||||
},
|
||||
"model": "cobblemon:item/ancient_wing_rod_cast"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "cobblemon:item/ancient_wing_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/ancient_wing_rod_cast"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"parent": "item/handheld_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/azure_rod"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"cast": 1
|
||||
},
|
||||
"model": "cobblemon:item/azure_rod_cast"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "cobblemon:item/azure_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/azure_rod_cast"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"parent": "item/handheld_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/beast_rod"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"cast": 1
|
||||
},
|
||||
"model": "cobblemon:item/beast_rod_cast"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "cobblemon:item/beast_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/beast_rod_cast"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"parent": "item/handheld_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/cherish_rod"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"cast": 1
|
||||
},
|
||||
"model": "cobblemon:item/cherish_rod_cast"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "cobblemon:item/cherish_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/cherish_rod_cast"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"parent": "item/handheld_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/citrine_rod"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"cast": 1
|
||||
},
|
||||
"model": "cobblemon:item/citrine_rod_cast"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "cobblemon:item/citrine_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/citrine_rod_cast"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"parent": "item/handheld_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/dive_rod"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"cast": 1
|
||||
},
|
||||
"model": "cobblemon:item/dive_rod_cast"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "cobblemon:item/dive_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/dive_rod_cast"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"parent": "item/handheld_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/dream_rod"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"cast": 1
|
||||
},
|
||||
"model": "cobblemon:item/dream_rod_cast"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "cobblemon:item/dream_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/dream_rod_cast"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"parent": "item/handheld_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/dusk_rod"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"cast": 1
|
||||
},
|
||||
"model": "cobblemon:item/dusk_rod_cast"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "cobblemon:item/dusk_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/dusk_rod_cast"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"parent": "item/handheld_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/fast_rod"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"cast": 1
|
||||
},
|
||||
"model": "cobblemon:item/fast_rod_cast"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "cobblemon:item/fast_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/fast_rod_cast"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"parent": "item/handheld_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/friend_rod"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"cast": 1
|
||||
},
|
||||
"model": "cobblemon:item/friend_rod_cast"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "cobblemon:item/friend_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/friend_rod_cast"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"parent": "item/handheld_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/great_rod"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"cast": 1
|
||||
},
|
||||
"model": "cobblemon:item/great_rod_cast"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "cobblemon:item/great_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/great_rod_cast"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"parent": "item/handheld_rod",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/fishing/heal_rod"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"cast": 1
|
||||
},
|
||||
"model": "cobblemon:item/heal_rod_cast"
|
||||
}
|
||||
]
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user