forked from mirrors/cobblemon
Compare commits
177
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a077e74bf2 | ||
|
|
763f1de793 | ||
|
|
62a95b93c5 | ||
|
|
7991f70c09 | ||
|
|
70d393a899 | ||
|
|
5bace46aa6 | ||
|
|
c5fb411636 | ||
|
|
9a8159ee30 | ||
|
|
4217938ada | ||
|
|
4c5f88db06 | ||
|
|
cfd743c4c0 | ||
|
|
1bbfc6dce5 | ||
|
|
6f2235c751 | ||
|
|
50a0f2d858 | ||
|
|
27210512f6 | ||
|
|
53aa124de6 | ||
|
|
a18b54849f | ||
|
|
c868c63a5f | ||
|
|
31df7c92f4 | ||
|
|
3b65d1967e | ||
|
|
f30b15003f | ||
|
|
c4c1b7ac27 | ||
|
|
ea9287cfb5 | ||
|
|
02f845af5c | ||
|
|
3bb3a00cef | ||
|
|
f1ae4163c9 | ||
|
|
05957f2106 | ||
|
|
4b9ea1d4cd | ||
|
|
78dff75db9 | ||
|
|
dbab6404a1 | ||
|
|
e5c4240ae0 | ||
|
|
317112f9bb | ||
|
|
58fda2e261 | ||
|
|
3b442d387a | ||
|
|
2b575c888f | ||
|
|
6e5e572412 | ||
|
|
ce87d0dc48 | ||
|
|
d43c91129c | ||
|
|
d66b9c8d3b | ||
|
|
dc37b381a0 | ||
|
|
1206aaaf13 | ||
|
|
95bcb9a7b8 | ||
|
|
c7d879ec57 | ||
|
|
d5752982d7 | ||
|
|
f1439ec724 | ||
|
|
0cac5714ac | ||
|
|
8529bb119f | ||
|
|
b68b3ad55e | ||
|
|
70c6b74f0f | ||
|
|
5cb7a51163 | ||
|
|
a68b6928aa | ||
|
|
0c26cb026c | ||
|
|
6078e22b14 | ||
|
|
cb1226013d | ||
|
|
0c8318d317 | ||
|
|
8d80bcfd6b | ||
|
|
cfd4fa1785 | ||
|
|
86bd70177c | ||
|
|
ce668b31ff | ||
|
|
943d6e0c55 | ||
|
|
7d82a2f7c8 | ||
|
|
782ba524df | ||
|
|
c571d79035 | ||
|
|
054c22b926 | ||
|
|
d2fce5edb5 | ||
|
|
cba32b7443 | ||
|
|
4a81c24a3d | ||
|
|
776e629850 | ||
|
|
9afb8b04c2 | ||
|
|
90c74eddc8 | ||
|
|
3600178d3b | ||
|
|
66d8a01917 | ||
|
|
68e32b21b5 | ||
|
|
670882bb4d | ||
|
|
9c0708651f | ||
|
|
1b3bb3b5bc | ||
|
|
cd03ef68c3 | ||
|
|
69716b5050 | ||
|
|
015deb4eeb | ||
|
|
96023077ad | ||
|
|
d96c68b5b4 | ||
|
|
dc27867502 | ||
|
|
bfbea377c1 | ||
|
|
f5954fcb33 | ||
|
|
eaa909a9f2 | ||
|
|
5ba4d460b1 | ||
|
|
09143b7ad6 | ||
|
|
aa1e14b4ac | ||
|
|
0f29cdeaf9 | ||
|
|
b976b9dd68 | ||
|
|
fa94ca8033 | ||
|
|
f206352b6e | ||
|
|
cdee981933 | ||
|
|
f2fc32b6a9 | ||
|
|
f46b581327 | ||
|
|
ff1241304b | ||
|
|
dd746e6775 | ||
|
|
44956ec6da | ||
|
|
553ecc8509 | ||
|
|
7b0d488b7c | ||
|
|
3f7a5e1318 | ||
|
|
ce7485f557 | ||
|
|
b5ca5c29d4 | ||
|
|
43f60da22e | ||
|
|
0102c8b392 | ||
|
|
6bb5c5dadf | ||
|
|
dd21fe2ea3 | ||
|
|
656c46817a | ||
|
|
a373f437fa | ||
|
|
0fe3637034 | ||
|
|
4b4be0e2cc | ||
|
|
3e673ae8f0 | ||
|
|
4b3b7443d3 | ||
|
|
d4dc24ec49 | ||
|
|
f54bbe754f | ||
|
|
c3379ddf21 | ||
|
|
5983b17e87 | ||
|
|
8d0ee6dd6f | ||
|
|
a1c1c9bc90 | ||
|
|
87e4f94af5 | ||
|
|
43075f1cb8 | ||
|
|
e1b1e3d5e9 | ||
|
|
a7095b30a3 | ||
|
|
ac5a03eebc | ||
|
|
bd79b58571 | ||
|
|
5e1c233493 | ||
|
|
95e95afef3 | ||
|
|
bf9c54e539 | ||
|
|
b7addd0203 | ||
|
|
7e64938ec9 | ||
|
|
618f66c775 | ||
|
|
fd1d1075db | ||
|
|
1648926aa6 | ||
|
|
3ce22c0759 | ||
|
|
a786adee9e | ||
|
|
de89c11f24 | ||
|
|
f16d233693 | ||
|
|
54d2711583 | ||
|
|
e54f179ccf | ||
|
|
22441e0b09 | ||
|
|
8418bc87c8 | ||
|
|
94ad2f1250 | ||
|
|
bd4df4485e | ||
|
|
0ad45df8f5 | ||
|
|
03f377cf0a | ||
|
|
373092f572 | ||
|
|
8bfc0fefaf | ||
|
|
4e44807523 | ||
|
|
36251fea75 | ||
|
|
06206a7447 | ||
|
|
66e901f88d | ||
|
|
05f089d390 | ||
|
|
23df8f70cf | ||
|
|
bd25e8682a | ||
|
|
906cd54c98 | ||
|
|
a1897f69ca | ||
|
|
a88700969d | ||
|
|
91eb9e597e | ||
|
|
e762542e49 | ||
|
|
b3e5734f39 | ||
|
|
2d5296288f | ||
|
|
cab3f2bf38 | ||
|
|
31efdc4254 | ||
|
|
34aace8a1b | ||
|
|
a877ad5a69 | ||
|
|
5a8c090055 | ||
|
|
98ccf39728 | ||
|
|
3222e2ebca | ||
|
|
ba89ed1574 | ||
|
|
68ab953644 | ||
|
|
4d3030e20e | ||
|
|
2e324e65a1 | ||
|
|
a34b7481f5 | ||
|
|
d2a3905b03 | ||
|
|
16b3d76504 | ||
|
|
363fe76dd1 | ||
|
|
040a29f66e |
@@ -33,3 +33,4 @@ common/src/main/resources/assets/cobblemon/showdown
|
|||||||
# Generated files
|
# Generated files
|
||||||
*/generated/resources/*
|
*/generated/resources/*
|
||||||
/fabric/src/generated/resources/cobblemon-common.accesswidener
|
/fabric/src/generated/resources/cobblemon-common.accesswidener
|
||||||
|
/.ignored/
|
||||||
+35
-7
@@ -3,16 +3,23 @@
|
|||||||
### Additions
|
### Additions
|
||||||
- Added over (number here) ruin structures, where you can find Pokémon-themed Armor Trims and Pottery Sherds, Tumblestones, and more.
|
- Added over (number here) ruin structures, where you can find Pokémon-themed Armor Trims and Pottery Sherds, Tumblestones, and more.
|
||||||
- Added (number here) fossil structures, where you can brush Suspicious Sand/Gravel for Fossils.
|
- Added (number here) fossil structures, where you can brush Suspicious Sand/Gravel for Fossils.
|
||||||
- Added the Data Monitor, Fossil Compartment, and Restoration Tube. Placed in the correct formation, you can use these to create a Restoration Machine where you can bring fossils back to life.
|
- Added the Data Monitor, Fossil Compartment, and Restoration Tank. Placed in the correct formation, you can use these to create a Restoration Machine where you can bring fossils back to life.
|
||||||
- Added 3 variants of Tumblestones, which can be planted near Lava or Magma to grow harvestable Tumblestone Clusters.
|
- Added 3 variants of Tumblestones, which can be planted near Lava or Magma to grow harvestable Tumblestone Clusters.
|
||||||
- Added Tumblestone Blocks, a storage block crafted from 9 Tumblestones.
|
- Added Tumblestone Blocks, a storage block crafted from 9 Tumblestones.
|
||||||
- Added Ancient Poké Balls, which are aesthetic variants crafted from Tumblestones.
|
- Added Ancient Poké Balls, which are aesthetic variants crafted from Tumblestones.
|
||||||
- Added the Ancient Feather, Wing, and Jet Balls, which fly further than regular Poké Balls.
|
- Added the Ancient Feather, Wing, and Jet Balls, which fly further than regular Poké Balls.
|
||||||
- Added the Ancient Heavy, Leaden, and Gigaton Balls, which are heavier and don't fly as far as regular Poké Balls. These will recieve more functionality in a future update.
|
- Added the Ancient Heavy, Leaden, and Gigaton Balls, which are heavier and don't fly as far as regular Poké Balls. These will receive more functionality in a future update.
|
||||||
- Added Original Trainer functionality. To edit the OT through commands, you must specify originaltrainertype=<Player/NPC>, and originaltrainer=<Username or UUID/NPC Name>
|
- Added Original Trainer functionality. To edit the OT through commands, you must specify originaltrainertype=<Player/NPC>, and originaltrainer=<Username or UUID/NPC Name>
|
||||||
- Added support for planting Apricorn trees, berries, and mints in [Botany Pots](https://modrinth.com/mod/botany-pots)
|
- Added support for planting Apricorn trees, berries, and mints in [Botany Pots](https://modrinth.com/mod/botany-pots)
|
||||||
- Added the hidden "True Vivillionaire" advancement.
|
- Added the hidden "True Vivillionaire" advancement.
|
||||||
- The "Poké Ball" Vivillon variant is now obtainable by evolving a Spewpa after obtaining the "Aspiring Vivillionaire" advancement.
|
- The "Poké Ball" Vivillon variant is now obtainable by evolving a Spewpa after obtaining the "Aspiring Vivillionaire" advancement.
|
||||||
|
- Added dynamic lighting support for any Species or Forms when using [LambDynamicLights](https://modrinth.com/mod/lambdynamiclights) or [Dynamic Lights Reforged](https://www.curseforge.com/minecraft/mc-mods/dynamiclights-reforged), at this time we don't ship with any defaults for this feature but addon creators can make use of this feature.
|
||||||
|
- Added 6 Pokémon-themed Pottery Sherds, obtained from ruin structures.
|
||||||
|
- Added a Pokémon-themed armor trim, obtained from ruin structures.
|
||||||
|
- You can now find Nether Fire Stone Ore in, surprisingly, the Nether.
|
||||||
|
- Added effects for many Poké Balls when sending out Pokémon or capturing.
|
||||||
|
- Added a new send-out ball toss animation that showcases the ball used for the Pokémon.
|
||||||
|
- Added simple move animations for Pokémon in battle with a proof of concept for more complicated animations.
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
- Pokémon now transition more smoothly between different poses.
|
- Pokémon now transition more smoothly between different poses.
|
||||||
@@ -23,6 +30,8 @@
|
|||||||
- Renamed the "Vivillionaire" advancement to "Aspiring Vivillionaire"
|
- Renamed the "Vivillionaire" advancement to "Aspiring Vivillionaire"
|
||||||
- Removed the Inferno, Forsaken, Poké Ball, and Void patterns from the Aspiring Vivillionaire advancement.
|
- Removed the Inferno, Forsaken, Poké Ball, and Void patterns from the Aspiring Vivillionaire advancement.
|
||||||
- Updated movesets to add Gen 9 DLC moves.
|
- Updated movesets to add Gen 9 DLC moves.
|
||||||
|
- Apricorn Sprouts can now be planted directly on Apricorn leaves to create a new Apricorn of the same color.
|
||||||
|
- Added tooltips to interaction GUIs to make it clearer what they do.
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
- Re-added the recipe for the Iron Vitamin.
|
- Re-added the recipe for the Iron Vitamin.
|
||||||
@@ -31,21 +40,26 @@
|
|||||||
- Fixed battle lang for Poison Touch Ability
|
- Fixed battle lang for Poison Touch Ability
|
||||||
- Fixed Cubone not being able to evolve into Alolan Marowak.
|
- Fixed Cubone not being able to evolve into Alolan Marowak.
|
||||||
- Fixed Squawkabilly forms not being recognized.
|
- Fixed Squawkabilly forms not being recognized.
|
||||||
|
- Fixed the bounce animation for Poké Balls being delayed by like, a full second.
|
||||||
- Note blocks now play the correct sound on the Apricorn Plank based blocks.
|
- Note blocks now play the correct sound on the Apricorn Plank based blocks.
|
||||||
- Fixed an issue with transformed parts in posers causing whacky positional issues.
|
- Fixed an issue with transformed parts in posers causing whacky positional issues.
|
||||||
- Fixed Poké Balls freezing in an open state if you look away when it's meant to close.
|
- Fixed Poké Balls freezing in an open state if you look away when it's meant to close.
|
||||||
|
- Adds a translation string name to the Empty Pokeball entity.
|
||||||
|
- Fixed very many issues with Bedrock particle effects.
|
||||||
|
|
||||||
### Developer
|
### Developer
|
||||||
- Significantly changed the way properties in PokemonEntity work. This could break some plugins (albeit in a quick-fix way).
|
- Significantly changed the way properties in PokemonEntity work. This could break some plugins (not in a big way, but changes will be needed).
|
||||||
- Rebuilt the scheduling API to more clearly force side choices and allow more local temporal frames of reference for tasks.
|
- Rebuilt the scheduling API to more clearly force side choices and temporal frames of reference for tasks.
|
||||||
- Added dialogue API.
|
- Added dialogue API and data registry.
|
||||||
- Opened up the ItemDropEntry class to allow for it to be extended.
|
- Opened up the ItemDropEntry class to allow for it to be extended.
|
||||||
- Added a new "advancement" evolution variant that takes an advancement identifier and succeeds if the player has the advancement.
|
- Added a new "advancement" evolution variant that takes an advancement identifier and succeeds if the player has the advancement.
|
||||||
- Made spawning API capable of non-entity spawning
|
- Made spawning API capable of non-entity spawning
|
||||||
- Made PokemonProperties.parse more interoperable with Java.
|
- Made PokemonProperties.parse more interoperable with Java.
|
||||||
|
- Added the ``HeldItemEvent``, this comes with 2 implementation ``HeldItemEvent.Pre`` and ``HeldItemEvent.Post``.
|
||||||
|
- API to support dynamic lighting in any mod that implements this feature has been added to all Species & Forms, see LightingData class for details.
|
||||||
|
|
||||||
### Datapack & Resourcepack Creators
|
### Datapack & Resourcepack Creators
|
||||||
- The maximum amount of fossils that can fit in the Fossil Compartment can be adjusted in the config.
|
- The maximum amount of fossils that can fit in the Fossil Analyzer can be adjusted in the config.
|
||||||
- Custom fossils can be defined using a list of items and the resulting Pokémon. An example of `aerodactyl.json`:
|
- Custom fossils can be defined using a list of items and the resulting Pokémon. An example of `aerodactyl.json`:
|
||||||
```JSON
|
```JSON
|
||||||
{
|
{
|
||||||
@@ -64,6 +78,19 @@
|
|||||||
- Added 3 new item tags: `ancient_poke_balls`, `fossils`, and `tumblestones`.
|
- Added 3 new item tags: `ancient_poke_balls`, `fossils`, and `tumblestones`.
|
||||||
- Added a spawn rules system to modify general spawning behaviour, see the [wiki](https://wiki.cobblemon.com/index.php/Spawn_Rules) for more information.
|
- Added a spawn rules system to modify general spawning behaviour, see the [wiki](https://wiki.cobblemon.com/index.php/Spawn_Rules) for more information.
|
||||||
- Added dialogue datapack folder and /opendialogue command.
|
- Added dialogue datapack folder and /opendialogue command.
|
||||||
|
- Added the item tag ``cobblemon:held/leaves_leftovers`` this can be used to flag apple-like items that can create leftovers when eaten.
|
||||||
|
- You can now add support for dynamic lighting implementations, Cobblemon ships with a default implementation for [LambDynamicLights](https://modrinth.com/mod/lambdynamiclights) and the [Dynamic Lights Reforged](https://www.curseforge.com/minecraft/mc-mods/dynamiclights-reforged), add the following to any species or form:
|
||||||
|
```JSON
|
||||||
|
{
|
||||||
|
"lightingData": {
|
||||||
|
"lightLevel": 14,
|
||||||
|
"_lightLevelCommentRemoveMe": "Above supports 0 to 15",
|
||||||
|
"liquidGlowMode": "LAND",
|
||||||
|
"_liquidGlowModeCommentRemoveMe": "Above supports LAND, UNDERWATER or BOTH"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- Following up on this change ``light_source`` was removed as a possible shoulder effect due to becoming unnecessary and never having had a default implementation.
|
||||||
|
|
||||||
## [1.4.1 (December 23rd, 2023)](#1-4-1)
|
## [1.4.1 (December 23rd, 2023)](#1-4-1)
|
||||||
|
|
||||||
@@ -81,6 +108,7 @@
|
|||||||
- Added cries to Beldum, Metang and Metagross.
|
- Added cries to Beldum, Metang and Metagross.
|
||||||
- Added a /bedrockparticle command to run Snowstorm-format particle effects.
|
- Added a /bedrockparticle command to run Snowstorm-format particle effects.
|
||||||
- Added data for Dipplin, Fezandipiti, Munkidori, Ogerpon, Okidogi, Poltchageist and Sinistcha.
|
- Added data for Dipplin, Fezandipiti, Munkidori, Ogerpon, Okidogi, Poltchageist and Sinistcha.
|
||||||
|
- Added additional nickname trigger "Grumm" for Inkay's evolution.
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
- Using Potions, Status Heals, Ethers, and Antidotes will now return a glass bottle
|
- Using Potions, Status Heals, Ethers, and Antidotes will now return a glass bottle
|
||||||
@@ -998,4 +1026,4 @@ Thank you so much to all of our community translators that bring the mod to the
|
|||||||
- Added species, ability, and move translations for `ko_ko`, `jp_jp`, `fr_fr`, `es_es`, `it_it`, and `zh_cn`.
|
- Added species, ability, and move translations for `ko_ko`, `jp_jp`, `fr_fr`, `es_es`, `it_it`, and `zh_cn`.
|
||||||
|
|
||||||
## [1.0.0 (November 12th, 2022)](#1-0-0)
|
## [1.0.0 (November 12th, 2022)](#1-0-0)
|
||||||
- Initial release.
|
- Initial release.
|
||||||
|
|||||||
+2
-1
@@ -1,6 +1,7 @@
|
|||||||
plugins {
|
plugins {
|
||||||
base
|
base
|
||||||
id("cobblemon.root-conventions")
|
id("cobblemon.root-conventions")
|
||||||
|
id ("net.nemerosa.versioning") version "2.8.2"
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "com.cobblemon.mod"
|
group = "com.cobblemon.mod"
|
||||||
@@ -8,5 +9,5 @@ version = "${project.property("mod_version")}+${project.property("mc_version")}"
|
|||||||
|
|
||||||
val isSnapshot = project.property("snapshot")?.equals("true") ?: false
|
val isSnapshot = project.property("snapshot")?.equals("true") ?: false
|
||||||
if (isSnapshot) {
|
if (isSnapshot) {
|
||||||
version = "$version-SNAPSHOT"
|
version = "$version-SNAPSHOT-${versioning.info.branch}-${versioning.info.build}"
|
||||||
}
|
}
|
||||||
@@ -33,6 +33,7 @@ dependencies {
|
|||||||
modApi(libs.molang)
|
modApi(libs.molang)
|
||||||
compileOnlyApi(libs.jeiApi)
|
compileOnlyApi(libs.jeiApi)
|
||||||
modCompileOnly(libs.adornFabric)
|
modCompileOnly(libs.adornFabric)
|
||||||
|
modCompileOnly(libs.lambDynamicLights) { isTransitive = false }
|
||||||
|
|
||||||
// For Showdown
|
// For Showdown
|
||||||
modCompileOnly(libs.graal)
|
modCompileOnly(libs.graal)
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* 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.compat;
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.CobblemonEntities;
|
||||||
|
import com.cobblemon.mod.common.client.render.layer.PokemonOnShoulderRenderer;
|
||||||
|
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||||
|
import com.cobblemon.mod.common.pokemon.FormData;
|
||||||
|
import com.cobblemon.mod.common.pokemon.lighthing.LightingData;
|
||||||
|
import dev.lambdaurora.lambdynlights.api.DynamicLightHandler;
|
||||||
|
import dev.lambdaurora.lambdynlights.api.DynamicLightHandlers;
|
||||||
|
import net.minecraft.entity.EntityType;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.util.Pair;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
// Java class due to relying on entrypoint on Fabric side
|
||||||
|
public class LambDynamicLightsCompat {
|
||||||
|
|
||||||
|
// This is all called on client side
|
||||||
|
// These things are checked every tick so try to keep it as free as possible
|
||||||
|
// That being said it's unlikely school Toshiba person is running dynamic lighting and shaders to enjoy this
|
||||||
|
// Make sure not to call anything Fabric specific :)
|
||||||
|
public static void hookCompat() {
|
||||||
|
// Pokémon entities
|
||||||
|
DynamicLightHandlers.registerDynamicLightHandler(
|
||||||
|
CobblemonEntities.POKEMON,
|
||||||
|
DynamicLightHandler.makeHandler(
|
||||||
|
pokemon -> resolvedPokemonLightLevel(pokemon, false),
|
||||||
|
pokemon -> true
|
||||||
|
)
|
||||||
|
);
|
||||||
|
DynamicLightHandlers.registerDynamicLightHandler(
|
||||||
|
CobblemonEntities.POKEMON,
|
||||||
|
DynamicLightHandler.makeHandler(
|
||||||
|
pokemon -> resolvedPokemonLightLevel(pokemon, true),
|
||||||
|
pokemon -> false
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Shouldered Pokémon
|
||||||
|
DynamicLightHandlers.registerDynamicLightHandler(
|
||||||
|
EntityType.PLAYER,
|
||||||
|
DynamicLightHandler.makeHandler(
|
||||||
|
player -> resolvedShoulderLightLevel(player, false),
|
||||||
|
player -> true
|
||||||
|
)
|
||||||
|
);
|
||||||
|
DynamicLightHandlers.registerDynamicLightHandler(
|
||||||
|
EntityType.PLAYER,
|
||||||
|
DynamicLightHandler.makeHandler(
|
||||||
|
player -> resolvedShoulderLightLevel(player, true),
|
||||||
|
player -> false
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int resolvedPokemonLightLevel(PokemonEntity pokemon, boolean underwater) {
|
||||||
|
return extractFormLightLevel(pokemon.getForm(), underwater).orElse(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int resolvedShoulderLightLevel(PlayerEntity player, boolean underwater) {
|
||||||
|
final Pair<PokemonOnShoulderRenderer.ShoulderData, PokemonOnShoulderRenderer.ShoulderData> shoulderDataPair = PokemonOnShoulderRenderer.shoulderDataOf(player);
|
||||||
|
final Optional<Integer> leftLightLevel = extractShoulderLightLevel(shoulderDataPair.getLeft(), underwater);
|
||||||
|
final Optional<Integer> rightLightLevel = extractShoulderLightLevel(shoulderDataPair.getRight(), underwater);
|
||||||
|
return Math.max(leftLightLevel.orElse(0), rightLightLevel.orElse(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Optional<Integer> extractFormLightLevel(@NotNull FormData form, boolean underwater) {
|
||||||
|
if (form.getLightingData() == null || !liquidGlowModeSupport(form.getLightingData().getLiquidGlowMode(), underwater)) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
return Optional.of(form.getLightingData().getLightLevel());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Optional<Integer> extractShoulderLightLevel(@Nullable PokemonOnShoulderRenderer.ShoulderData shoulderData, boolean underwater) {
|
||||||
|
if (shoulderData == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
return extractFormLightLevel(shoulderData.getForm(), underwater);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean liquidGlowModeSupport(@NotNull LightingData.LiquidGlowMode liquidGlowMode, boolean underwater) {
|
||||||
|
return underwater ? liquidGlowMode.getGlowsUnderwater() : liquidGlowMode.getGlowsInLand();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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.mixin;
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.sherds.CobblemonSherds;
|
||||||
|
import net.minecraft.block.DecoratedPotPatterns;
|
||||||
|
import net.minecraft.item.Item;
|
||||||
|
import net.minecraft.registry.RegistryKey;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(DecoratedPotPatterns.class)
|
||||||
|
public abstract class DecoratedPotPatternsMixin {
|
||||||
|
@Inject(method = "fromSherd", at=@At("HEAD"), cancellable = true)
|
||||||
|
private static void cobblemon$getCobblemonSherdTexture(Item sherd,
|
||||||
|
CallbackInfoReturnable<RegistryKey<String>> cir) {
|
||||||
|
if (CobblemonSherds.INSTANCE.getSherdToPattern().containsKey(sherd)) {
|
||||||
|
cir.setReturnValue(CobblemonSherds.INSTANCE.getSherdToPattern().get(sherd));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -40,4 +40,5 @@ public class GameRendererMixin {
|
|||||||
}
|
}
|
||||||
lastTime = newTime;
|
lastTime = newTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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.mixin;
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.api.snowstorm.ParticleMaterials;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import net.minecraft.client.particle.ParticleManager;
|
||||||
|
import net.minecraft.client.particle.ParticleTextureSheet;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Mutable;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Mixin(ParticleManager.class)
|
||||||
|
final class ParticleManagerMixin {
|
||||||
|
@Mutable
|
||||||
|
@Final
|
||||||
|
@Shadow
|
||||||
|
private static List<ParticleTextureSheet> PARTICLE_TEXTURE_SHEETS;
|
||||||
|
|
||||||
|
@Inject(at = @At("RETURN"), method = "<clinit>")
|
||||||
|
private static void lodestone$addTypes(CallbackInfo ci) {
|
||||||
|
PARTICLE_TEXTURE_SHEETS = ImmutableList.<ParticleTextureSheet>builder().addAll(PARTICLE_TEXTURE_SHEETS)
|
||||||
|
.add(ParticleMaterials.INSTANCE.getADD(), ParticleMaterials.INSTANCE.getALPHA(), ParticleMaterials.INSTANCE.getBLEND(), ParticleMaterials.INSTANCE.getOPAQUE()).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ import com.cobblemon.mod.common.api.events.CobblemonEvents;
|
|||||||
import com.cobblemon.mod.common.api.events.item.LeftoversCreatedEvent;
|
import com.cobblemon.mod.common.api.events.item.LeftoversCreatedEvent;
|
||||||
import com.cobblemon.mod.common.api.storage.NoPokemonStoreException;
|
import com.cobblemon.mod.common.api.storage.NoPokemonStoreException;
|
||||||
import com.cobblemon.mod.common.api.storage.party.PartyStore;
|
import com.cobblemon.mod.common.api.storage.party.PartyStore;
|
||||||
|
import com.cobblemon.mod.common.api.tags.CobblemonItemTags;
|
||||||
import com.cobblemon.mod.common.pokemon.Pokemon;
|
import com.cobblemon.mod.common.pokemon.Pokemon;
|
||||||
import com.cobblemon.mod.common.util.CompoundTagExtensionsKt;
|
import com.cobblemon.mod.common.util.CompoundTagExtensionsKt;
|
||||||
import com.cobblemon.mod.common.util.DataKeys;
|
import com.cobblemon.mod.common.util.DataKeys;
|
||||||
@@ -22,11 +23,8 @@ import net.minecraft.entity.ItemEntity;
|
|||||||
import net.minecraft.entity.LivingEntity;
|
import net.minecraft.entity.LivingEntity;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.item.Items;
|
|
||||||
import net.minecraft.nbt.NbtCompound;
|
import net.minecraft.nbt.NbtCompound;
|
||||||
import net.minecraft.server.network.ServerPlayerEntity;
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
import net.minecraft.sound.SoundEvent;
|
|
||||||
import net.minecraft.sound.SoundEvents;
|
|
||||||
import net.minecraft.text.Text;
|
import net.minecraft.text.Text;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import org.objectweb.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
@@ -40,8 +38,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import static com.cobblemon.mod.common.util.LocalizationUtilsKt.lang;
|
|
||||||
|
|
||||||
@Mixin(PlayerEntity.class)
|
@Mixin(PlayerEntity.class)
|
||||||
public abstract class PlayerMixin extends LivingEntity {
|
public abstract class PlayerMixin extends LivingEntity {
|
||||||
|
|
||||||
@@ -144,7 +140,7 @@ public abstract class PlayerMixin extends LivingEntity {
|
|||||||
)
|
)
|
||||||
public void onEatFood(World world, ItemStack stack, CallbackInfoReturnable<ItemStack> cir) {
|
public void onEatFood(World world, ItemStack stack, CallbackInfoReturnable<ItemStack> cir) {
|
||||||
if (!getWorld().isClient) {
|
if (!getWorld().isClient) {
|
||||||
if (stack.getItem() == Items.APPLE && getWorld().random.nextDouble() < Cobblemon.config.getAppleLeftoversChance()) {
|
if (stack.isIn(CobblemonItemTags.LEAVES_LEFTOVERS) && getWorld().random.nextDouble() < Cobblemon.config.getAppleLeftoversChance()) {
|
||||||
ItemStack leftovers = new ItemStack(CobblemonItems.LEFTOVERS);
|
ItemStack leftovers = new ItemStack(CobblemonItems.LEFTOVERS);
|
||||||
ServerPlayerEntity player = Objects.requireNonNull(getServer()).getPlayerManager().getPlayer(uuid);
|
ServerPlayerEntity player = Objects.requireNonNull(getServer()).getPlayerManager().getPlayer(uuid);
|
||||||
assert player != null;
|
assert player != null;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import com.cobblemon.mod.common.api.events.CobblemonEvents.EVOLUTION_COMPLETE
|
|||||||
import com.cobblemon.mod.common.api.events.CobblemonEvents.LEVEL_UP_EVENT
|
import com.cobblemon.mod.common.api.events.CobblemonEvents.LEVEL_UP_EVENT
|
||||||
import com.cobblemon.mod.common.api.events.CobblemonEvents.POKEMON_CAPTURED
|
import com.cobblemon.mod.common.api.events.CobblemonEvents.POKEMON_CAPTURED
|
||||||
import com.cobblemon.mod.common.api.events.CobblemonEvents.TRADE_COMPLETED
|
import com.cobblemon.mod.common.api.events.CobblemonEvents.TRADE_COMPLETED
|
||||||
|
import com.cobblemon.mod.common.api.net.serializers.IdentifierDataSerializer
|
||||||
import com.cobblemon.mod.common.api.net.serializers.PoseTypeDataSerializer
|
import com.cobblemon.mod.common.api.net.serializers.PoseTypeDataSerializer
|
||||||
import com.cobblemon.mod.common.api.net.serializers.StringSetDataSerializer
|
import com.cobblemon.mod.common.api.net.serializers.StringSetDataSerializer
|
||||||
import com.cobblemon.mod.common.api.net.serializers.Vec3DataSerializer
|
import com.cobblemon.mod.common.api.net.serializers.Vec3DataSerializer
|
||||||
@@ -102,6 +103,7 @@ import com.cobblemon.mod.common.pokemon.properties.HiddenAbilityPropertyType
|
|||||||
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
|
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
|
||||||
import com.cobblemon.mod.common.pokemon.properties.tags.PokemonFlagProperty
|
import com.cobblemon.mod.common.pokemon.properties.tags.PokemonFlagProperty
|
||||||
import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
|
import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
|
||||||
|
import com.cobblemon.mod.common.sherds.CobblemonSherds
|
||||||
import com.cobblemon.mod.common.starter.CobblemonStarterHandler
|
import com.cobblemon.mod.common.starter.CobblemonStarterHandler
|
||||||
import com.cobblemon.mod.common.trade.TradeManager
|
import com.cobblemon.mod.common.trade.TradeManager
|
||||||
import com.cobblemon.mod.common.util.*
|
import com.cobblemon.mod.common.util.*
|
||||||
@@ -235,6 +237,7 @@ object Cobblemon {
|
|||||||
TrackedDataHandlerRegistry.register(Vec3DataSerializer)
|
TrackedDataHandlerRegistry.register(Vec3DataSerializer)
|
||||||
TrackedDataHandlerRegistry.register(StringSetDataSerializer)
|
TrackedDataHandlerRegistry.register(StringSetDataSerializer)
|
||||||
TrackedDataHandlerRegistry.register(PoseTypeDataSerializer)
|
TrackedDataHandlerRegistry.register(PoseTypeDataSerializer)
|
||||||
|
TrackedDataHandlerRegistry.register(IdentifierDataSerializer)
|
||||||
|
|
||||||
HeldItemProvider.register(CobblemonHeldItemManager, Priority.LOWEST)
|
HeldItemProvider.register(CobblemonHeldItemManager, Priority.LOWEST)
|
||||||
}
|
}
|
||||||
@@ -385,6 +388,8 @@ object Cobblemon {
|
|||||||
true
|
true
|
||||||
).ifSuccessful { it.mute = true }
|
).ifSuccessful { it.mute = true }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CobblemonSherds.registerSherds()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getLevel(dimension: RegistryKey<World>): World? {
|
fun getLevel(dimension: RegistryKey<World>): World? {
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ import com.cobblemon.mod.common.block.entity.BerryBlockEntity
|
|||||||
import com.cobblemon.mod.common.block.entity.HealingMachineBlockEntity
|
import com.cobblemon.mod.common.block.entity.HealingMachineBlockEntity
|
||||||
import com.cobblemon.mod.common.block.entity.PCBlockEntity
|
import com.cobblemon.mod.common.block.entity.PCBlockEntity
|
||||||
import com.cobblemon.mod.common.block.entity.PokemonPastureBlockEntity
|
import com.cobblemon.mod.common.block.entity.PokemonPastureBlockEntity
|
||||||
import com.cobblemon.mod.common.block.entity.fossil.FossilCompartmentBlockEntity
|
import com.cobblemon.mod.common.block.entity.FossilAnalyzerBlockEntity
|
||||||
import com.cobblemon.mod.common.block.entity.fossil.FossilMultiblockEntity
|
import com.cobblemon.mod.common.block.entity.FossilMultiblockEntity
|
||||||
import com.cobblemon.mod.common.block.entity.fossil.FossilTubeBlockEntity
|
import com.cobblemon.mod.common.block.entity.RestorationTankBlockEntity
|
||||||
import com.cobblemon.mod.common.block.multiblock.FossilMultiblockBuilder
|
import com.cobblemon.mod.common.block.multiblock.FossilMultiblockBuilder
|
||||||
import com.cobblemon.mod.common.block.entity.*
|
import com.cobblemon.mod.common.block.entity.*
|
||||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||||
@@ -48,21 +48,27 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
|
|||||||
@JvmField
|
@JvmField
|
||||||
val FOSSIL_MULTIBLOCK: BlockEntityType<FossilMultiblockEntity> = this.create("fossil_multiblock",
|
val FOSSIL_MULTIBLOCK: BlockEntityType<FossilMultiblockEntity> = this.create("fossil_multiblock",
|
||||||
BlockEntityType.Builder.create({ pos, state -> FossilMultiblockEntity(pos, state, FossilMultiblockBuilder(pos)) },
|
BlockEntityType.Builder.create({ pos, state -> FossilMultiblockEntity(pos, state, FossilMultiblockBuilder(pos)) },
|
||||||
CobblemonBlocks.FOSSIL_MONITOR
|
CobblemonBlocks.MONITOR
|
||||||
).build(null)
|
).build(null)
|
||||||
)
|
)
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val FOSSIL_TUBE: BlockEntityType<FossilTubeBlockEntity> = this.create("fossil_tube",
|
val RESTORATION_TANK: BlockEntityType<RestorationTankBlockEntity> = this.create("restoration_tank",
|
||||||
BlockEntityType.Builder.create({ pos, state -> FossilTubeBlockEntity(pos, state, FossilMultiblockBuilder(pos)) },
|
BlockEntityType.Builder.create({ pos, state -> RestorationTankBlockEntity(pos, state, FossilMultiblockBuilder(pos)) },
|
||||||
CobblemonBlocks.FOSSIL_TUBE
|
CobblemonBlocks.RESTORATION_TANK
|
||||||
).build(null)
|
).build(null)
|
||||||
)
|
)
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val FOSSIL_COMPARTMENT: BlockEntityType<FossilCompartmentBlockEntity> = this.create("fossil_compartment",
|
val FOSSIL_ANALYZER: BlockEntityType<FossilAnalyzerBlockEntity> = this.create("fossil_analyzer",
|
||||||
BlockEntityType.Builder.create({ pos, state -> FossilCompartmentBlockEntity(pos, state, FossilMultiblockBuilder(pos)) },
|
BlockEntityType.Builder.create({ pos, state -> FossilAnalyzerBlockEntity(pos, state, FossilMultiblockBuilder(pos)) },
|
||||||
CobblemonBlocks.FOSSIL_COMPARTMENT
|
CobblemonBlocks.FOSSIL_ANALYZER
|
||||||
).build(null)
|
).build(null)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
val DYNITE_ORE: BlockEntityType<DyniteOreBlockEntity> = this.create("dynite_ore",
|
||||||
|
BlockEntityType.Builder.create(::DyniteOreBlockEntity, CobblemonBlocks.DYNITE_ORE)
|
||||||
|
.build(null)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ package com.cobblemon.mod.common
|
|||||||
import com.cobblemon.mod.common.api.apricorn.Apricorn
|
import com.cobblemon.mod.common.api.apricorn.Apricorn
|
||||||
import com.cobblemon.mod.common.block.*
|
import com.cobblemon.mod.common.block.*
|
||||||
import com.cobblemon.mod.common.block.MintBlock.MintType
|
import com.cobblemon.mod.common.block.MintBlock.MintType
|
||||||
import com.cobblemon.mod.common.block.fossilmachine.FossilCompartmentBlock
|
import com.cobblemon.mod.common.block.FossilAnalyzerBlock
|
||||||
import com.cobblemon.mod.common.block.fossilmachine.FossilMonitorBlock
|
import com.cobblemon.mod.common.block.MonitorBlock
|
||||||
import com.cobblemon.mod.common.block.fossilmachine.FossilTubeBlock
|
import com.cobblemon.mod.common.block.RestorationTankBlock
|
||||||
import com.cobblemon.mod.common.mixin.invoker.DoorBlockInvoker
|
import com.cobblemon.mod.common.mixin.invoker.DoorBlockInvoker
|
||||||
import com.cobblemon.mod.common.mixin.invoker.PressurePlateBlockInvoker
|
import com.cobblemon.mod.common.mixin.invoker.PressurePlateBlockInvoker
|
||||||
import com.cobblemon.mod.common.mixin.invoker.StairsBlockInvoker
|
import com.cobblemon.mod.common.mixin.invoker.StairsBlockInvoker
|
||||||
@@ -57,6 +57,8 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
|||||||
@JvmField
|
@JvmField
|
||||||
val FIRE_STONE_ORE = evolutionStoneOre("fire_stone_ore")
|
val FIRE_STONE_ORE = evolutionStoneOre("fire_stone_ore")
|
||||||
@JvmField
|
@JvmField
|
||||||
|
val NETHER_FIRE_STONE_ORE = evolutionStoneOre("nether_fire_stone_ore")
|
||||||
|
@JvmField
|
||||||
val ICE_STONE_ORE = evolutionStoneOre("ice_stone_ore")
|
val ICE_STONE_ORE = evolutionStoneOre("ice_stone_ore")
|
||||||
@JvmField
|
@JvmField
|
||||||
val LEAF_STONE_ORE = evolutionStoneOre("leaf_stone_ore")
|
val LEAF_STONE_ORE = evolutionStoneOre("leaf_stone_ore")
|
||||||
@@ -94,6 +96,15 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
|||||||
@JvmField
|
@JvmField
|
||||||
val DEEPSLATE_WATER_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_water_stone_ore")
|
val DEEPSLATE_WATER_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_water_stone_ore")
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
val DYNITE_ORE = this.create("dynite_ore", DyniteOreBlock(
|
||||||
|
AbstractBlock.Settings.create()
|
||||||
|
.mapColor(MapColor.BRIGHT_RED)
|
||||||
|
.strength(4.5f, 3f)
|
||||||
|
.requiresTool()
|
||||||
|
.sounds(BlockSoundGroup.METAL)
|
||||||
|
))
|
||||||
|
|
||||||
// Apricorns
|
// Apricorns
|
||||||
@JvmField
|
@JvmField
|
||||||
val APRICORN_LOG = log("apricorn_log", arg2 = MapColor.BROWN)
|
val APRICORN_LOG = log("apricorn_log", arg2 = MapColor.BROWN)
|
||||||
@@ -158,31 +169,31 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
|||||||
val REVIVAL_HERB = this.create("revival_herb", RevivalHerbBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).mapColor(MapColor.DARK_GREEN).burnable().noCollision().breakInstantly().sounds(BlockSoundGroup.CROP)))
|
val REVIVAL_HERB = this.create("revival_herb", RevivalHerbBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).mapColor(MapColor.DARK_GREEN).burnable().noCollision().breakInstantly().sounds(BlockSoundGroup.CROP)))
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val TUMBLESTONE_CLUSTER = tumblestoneBlock("tumblestone_cluster", TumblestoneBlock.STAGE_3, 7, 3, null)
|
val TUMBLESTONE_CLUSTER = tumblestoneBlock("tumblestone_cluster", GrowableStoneBlock.STAGE_3, 7, 3, null)
|
||||||
@JvmField
|
@JvmField
|
||||||
val LARGE_BUDDING_TUMBLESTONE = tumblestoneBlock("large_budding_tumblestone", TumblestoneBlock.STAGE_2, 5, 3, TUMBLESTONE_CLUSTER)
|
val LARGE_BUDDING_TUMBLESTONE = tumblestoneBlock("large_budding_tumblestone", GrowableStoneBlock.STAGE_2, 5, 3, TUMBLESTONE_CLUSTER)
|
||||||
@JvmField
|
@JvmField
|
||||||
val MEDIUM_BUDDING_TUMBLESTONE = tumblestoneBlock("medium_budding_tumblestone", TumblestoneBlock.STAGE_1, 4, 3, LARGE_BUDDING_TUMBLESTONE)
|
val MEDIUM_BUDDING_TUMBLESTONE = tumblestoneBlock("medium_budding_tumblestone", GrowableStoneBlock.STAGE_1, 4, 3, LARGE_BUDDING_TUMBLESTONE)
|
||||||
@JvmField
|
@JvmField
|
||||||
val SMALL_BUDDING_TUMBLESTONE = tumblestoneBlock("small_budding_tumblestone", TumblestoneBlock.STAGE_0, 3, 4, MEDIUM_BUDDING_TUMBLESTONE)
|
val SMALL_BUDDING_TUMBLESTONE = tumblestoneBlock("small_budding_tumblestone", GrowableStoneBlock.STAGE_0, 3, 4, MEDIUM_BUDDING_TUMBLESTONE)
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val SKY_TUMBLESTONE_CLUSTER = tumblestoneBlock("sky_tumblestone_cluster", TumblestoneBlock.STAGE_3, 7, 3, null)
|
val SKY_TUMBLESTONE_CLUSTER = tumblestoneBlock("sky_tumblestone_cluster", GrowableStoneBlock.STAGE_3, 7, 3, null)
|
||||||
@JvmField
|
@JvmField
|
||||||
val LARGE_BUDDING_SKY_TUMBLESTONE = tumblestoneBlock("large_budding_sky_tumblestone", TumblestoneBlock.STAGE_2, 5, 3, SKY_TUMBLESTONE_CLUSTER)
|
val LARGE_BUDDING_SKY_TUMBLESTONE = tumblestoneBlock("large_budding_sky_tumblestone", GrowableStoneBlock.STAGE_2, 5, 3, SKY_TUMBLESTONE_CLUSTER)
|
||||||
@JvmField
|
@JvmField
|
||||||
val MEDIUM_BUDDING_SKY_TUMBLESTONE = tumblestoneBlock("medium_budding_sky_tumblestone", TumblestoneBlock.STAGE_1, 4, 3, LARGE_BUDDING_SKY_TUMBLESTONE)
|
val MEDIUM_BUDDING_SKY_TUMBLESTONE = tumblestoneBlock("medium_budding_sky_tumblestone", GrowableStoneBlock.STAGE_1, 4, 3, LARGE_BUDDING_SKY_TUMBLESTONE)
|
||||||
@JvmField
|
@JvmField
|
||||||
val SMALL_BUDDING_SKY_TUMBLESTONE = tumblestoneBlock("small_budding_sky_tumblestone", TumblestoneBlock.STAGE_0, 3, 4, MEDIUM_BUDDING_SKY_TUMBLESTONE)
|
val SMALL_BUDDING_SKY_TUMBLESTONE = tumblestoneBlock("small_budding_sky_tumblestone", GrowableStoneBlock.STAGE_0, 3, 4, MEDIUM_BUDDING_SKY_TUMBLESTONE)
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val BLACK_TUMBLESTONE_CLUSTER = tumblestoneBlock("black_tumblestone_cluster", TumblestoneBlock.STAGE_3, 7, 3, null)
|
val BLACK_TUMBLESTONE_CLUSTER = tumblestoneBlock("black_tumblestone_cluster", GrowableStoneBlock.STAGE_3, 7, 3, null)
|
||||||
@JvmField
|
@JvmField
|
||||||
val LARGE_BUDDING_BLACK_TUMBLESTONE = tumblestoneBlock("large_budding_black_tumblestone", TumblestoneBlock.STAGE_2, 5, 3, BLACK_TUMBLESTONE_CLUSTER)
|
val LARGE_BUDDING_BLACK_TUMBLESTONE = tumblestoneBlock("large_budding_black_tumblestone", GrowableStoneBlock.STAGE_2, 5, 3, BLACK_TUMBLESTONE_CLUSTER)
|
||||||
@JvmField
|
@JvmField
|
||||||
val MEDIUM_BUDDING_BLACK_TUMBLESTONE = tumblestoneBlock("medium_budding_black_tumblestone", TumblestoneBlock.STAGE_1, 4, 3, LARGE_BUDDING_BLACK_TUMBLESTONE)
|
val MEDIUM_BUDDING_BLACK_TUMBLESTONE = tumblestoneBlock("medium_budding_black_tumblestone", GrowableStoneBlock.STAGE_1, 4, 3, LARGE_BUDDING_BLACK_TUMBLESTONE)
|
||||||
@JvmField
|
@JvmField
|
||||||
val SMALL_BUDDING_BLACK_TUMBLESTONE = tumblestoneBlock("small_budding_black_tumblestone", TumblestoneBlock.STAGE_0, 3, 4, MEDIUM_BUDDING_BLACK_TUMBLESTONE)
|
val SMALL_BUDDING_BLACK_TUMBLESTONE = tumblestoneBlock("small_budding_black_tumblestone", GrowableStoneBlock.STAGE_0, 3, 4, MEDIUM_BUDDING_BLACK_TUMBLESTONE)
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val TUMBLESTONE_BLOCK = this.create("tumblestone_block", Block(AbstractBlock.Settings.create()
|
val TUMBLESTONE_BLOCK = this.create("tumblestone_block", Block(AbstractBlock.Settings.create()
|
||||||
@@ -222,38 +233,41 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
|||||||
val YELLOW_APRICORN = apricornBlock("yellow_apricorn", Apricorn.YELLOW)
|
val YELLOW_APRICORN = apricornBlock("yellow_apricorn", Apricorn.YELLOW)
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val FOSSIL_MONITOR = create(
|
val MONITOR = create(
|
||||||
"fossil_monitor",
|
"monitor",
|
||||||
FossilMonitorBlock(
|
MonitorBlock(
|
||||||
AbstractBlock.Settings.create()
|
AbstractBlock.Settings.create()
|
||||||
.mapColor(MapColor.IRON_GRAY)
|
.mapColor(MapColor.IRON_GRAY)
|
||||||
.sounds(BlockSoundGroup.METAL)
|
.sounds(BlockSoundGroup.METAL)
|
||||||
.pistonBehavior(PistonBehavior.BLOCK)
|
.pistonBehavior(PistonBehavior.BLOCK)
|
||||||
.strength(2f)
|
.requiresTool()
|
||||||
.luminance { if (it.get(FossilMonitorBlock.PROGRESS) > 0) 15 else 0 }
|
.strength(5.0F, 6.0F)
|
||||||
|
.luminance { if (it.get(MonitorBlock.SCREEN) != MonitorBlock.MonitorScreen.OFF) 15 else 0 }
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@JvmField
|
@JvmField
|
||||||
val FOSSIL_COMPARTMENT = create(
|
val FOSSIL_ANALYZER = create(
|
||||||
"fossil_compartment",
|
"fossil_analyzer",
|
||||||
FossilCompartmentBlock(
|
FossilAnalyzerBlock(
|
||||||
AbstractBlock.Settings.create()
|
AbstractBlock.Settings.create()
|
||||||
.mapColor(MapColor.IRON_GRAY)
|
.mapColor(MapColor.IRON_GRAY)
|
||||||
.sounds(BlockSoundGroup.METAL)
|
.sounds(BlockSoundGroup.METAL)
|
||||||
.pistonBehavior(PistonBehavior.BLOCK)
|
.pistonBehavior(PistonBehavior.BLOCK)
|
||||||
.strength(2f)
|
.requiresTool()
|
||||||
|
.strength(5.0F, 6.0F)
|
||||||
.nonOpaque()
|
.nonOpaque()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@JvmField
|
@JvmField
|
||||||
val FOSSIL_TUBE = create(
|
val RESTORATION_TANK = create(
|
||||||
"fossil_tube",
|
"restoration_tank",
|
||||||
FossilTubeBlock(
|
RestorationTankBlock(
|
||||||
AbstractBlock.Settings.create()
|
AbstractBlock.Settings.create()
|
||||||
.mapColor(MapColor.IRON_GRAY)
|
.mapColor(MapColor.IRON_GRAY)
|
||||||
.sounds(BlockSoundGroup.METAL)
|
.sounds(BlockSoundGroup.METAL)
|
||||||
.pistonBehavior(PistonBehavior.BLOCK)
|
.pistonBehavior(PistonBehavior.BLOCK)
|
||||||
.strength(2f)
|
.requiresTool()
|
||||||
|
.strength(5.0F, 6.0F)
|
||||||
.nonOpaque()
|
.nonOpaque()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ package com.cobblemon.mod.common
|
|||||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||||
import com.cobblemon.mod.common.entity.boat.CobblemonBoatEntity
|
import com.cobblemon.mod.common.entity.boat.CobblemonBoatEntity
|
||||||
import com.cobblemon.mod.common.entity.boat.CobblemonChestBoatEntity
|
import com.cobblemon.mod.common.entity.boat.CobblemonChestBoatEntity
|
||||||
|
import com.cobblemon.mod.common.entity.fallingstar.FallingStarEntity
|
||||||
|
import com.cobblemon.mod.common.entity.generic.GenericBedrockEntity
|
||||||
import com.cobblemon.mod.common.entity.fishing.PokeRodFishingBobberEntity
|
import com.cobblemon.mod.common.entity.fishing.PokeRodFishingBobberEntity
|
||||||
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
|
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
|
||||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||||
@@ -66,6 +68,24 @@ object CobblemonEntities : PlatformRegistry<Registry<EntityType<*>>, RegistryKey
|
|||||||
.build(CHEST_BOAT_KEY.toString())
|
.build(CHEST_BOAT_KEY.toString())
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
val GENERIC_BEDROCK_ENTITY_KEY = cobblemonResource("generic_bedrock")
|
||||||
|
@JvmField
|
||||||
|
val GENERIC_BEDROCK_ENTITY: EntityType<GenericBedrockEntity> = this.create(
|
||||||
|
GENERIC_BEDROCK_ENTITY_KEY.path,
|
||||||
|
EntityType.Builder.create({ _, world -> GenericBedrockEntity(world) }, SpawnGroup.MISC)
|
||||||
|
.build(GENERIC_BEDROCK_ENTITY_KEY.toString())
|
||||||
|
)
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
val FALLING_STAR_ENTITY_KEY = cobblemonResource("falling_star")
|
||||||
|
@JvmField
|
||||||
|
val FALLING_STAR_ENTITY: EntityType<FallingStarEntity> = this.create(
|
||||||
|
FALLING_STAR_ENTITY_KEY.path,
|
||||||
|
EntityType.Builder.create({ _, world -> FallingStarEntity(world) }, SpawnGroup.MISC)
|
||||||
|
.build(FALLING_STAR_ENTITY_KEY.toString())
|
||||||
|
)
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val POKE_BOBBER_KEY = cobblemonResource("poke_bobber")
|
val POKE_BOBBER_KEY = cobblemonResource("poke_bobber")
|
||||||
@JvmField
|
@JvmField
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import com.cobblemon.mod.common.block.MintBlock
|
|||||||
import com.cobblemon.mod.common.block.MintBlock.MintType
|
import com.cobblemon.mod.common.block.MintBlock.MintType
|
||||||
import com.cobblemon.mod.common.entity.boat.CobblemonBoatType
|
import com.cobblemon.mod.common.entity.boat.CobblemonBoatType
|
||||||
import com.cobblemon.mod.common.item.*
|
import com.cobblemon.mod.common.item.*
|
||||||
|
import com.cobblemon.mod.common.item.armor.CobblemonArmorTrims
|
||||||
import com.cobblemon.mod.common.item.battle.DireHitItem
|
import com.cobblemon.mod.common.item.battle.DireHitItem
|
||||||
import com.cobblemon.mod.common.item.battle.GuardSpecItem
|
import com.cobblemon.mod.common.item.battle.GuardSpecItem
|
||||||
import com.cobblemon.mod.common.item.battle.XStatItem
|
import com.cobblemon.mod.common.item.battle.XStatItem
|
||||||
@@ -38,6 +39,14 @@ import net.minecraft.entity.LivingEntity
|
|||||||
import net.minecraft.entity.effect.StatusEffectInstance
|
import net.minecraft.entity.effect.StatusEffectInstance
|
||||||
import net.minecraft.entity.effect.StatusEffects
|
import net.minecraft.entity.effect.StatusEffects
|
||||||
import net.minecraft.item.*
|
import net.minecraft.item.*
|
||||||
|
import net.minecraft.item.BlockItem
|
||||||
|
import net.minecraft.item.FoodComponent
|
||||||
|
import net.minecraft.item.HangingSignItem
|
||||||
|
import net.minecraft.item.Item
|
||||||
|
import net.minecraft.item.ItemStack
|
||||||
|
import net.minecraft.item.SignItem
|
||||||
|
import net.minecraft.item.SmithingTemplateItem
|
||||||
|
import net.minecraft.item.StewItem
|
||||||
import net.minecraft.registry.Registries
|
import net.minecraft.registry.Registries
|
||||||
import net.minecraft.registry.Registry
|
import net.minecraft.registry.Registry
|
||||||
import net.minecraft.registry.RegistryKey
|
import net.minecraft.registry.RegistryKey
|
||||||
@@ -171,19 +180,19 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
|||||||
val WHITE_APRICORN = apricornItem("white", ApricornItem(CobblemonBlocks.WHITE_APRICORN))
|
val WHITE_APRICORN = apricornItem("white", ApricornItem(CobblemonBlocks.WHITE_APRICORN))
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val RED_APRICORN_SEED = apricornSeedItem("red", ApricornSeedItem(CobblemonBlocks.RED_APRICORN_SAPLING))
|
val RED_APRICORN_SEED = apricornSeedItem("red", ApricornSeedItem(CobblemonBlocks.RED_APRICORN_SAPLING, CobblemonBlocks.RED_APRICORN))
|
||||||
@JvmField
|
@JvmField
|
||||||
val YELLOW_APRICORN_SEED = apricornSeedItem("yellow", ApricornSeedItem(CobblemonBlocks.YELLOW_APRICORN_SAPLING))
|
val YELLOW_APRICORN_SEED = apricornSeedItem("yellow", ApricornSeedItem(CobblemonBlocks.YELLOW_APRICORN_SAPLING, CobblemonBlocks.YELLOW_APRICORN))
|
||||||
@JvmField
|
@JvmField
|
||||||
val GREEN_APRICORN_SEED = apricornSeedItem("green", ApricornSeedItem(CobblemonBlocks.GREEN_APRICORN_SAPLING))
|
val GREEN_APRICORN_SEED = apricornSeedItem("green", ApricornSeedItem(CobblemonBlocks.GREEN_APRICORN_SAPLING, CobblemonBlocks.GREEN_APRICORN))
|
||||||
@JvmField
|
@JvmField
|
||||||
val BLUE_APRICORN_SEED = apricornSeedItem("blue", ApricornSeedItem(CobblemonBlocks.BLUE_APRICORN_SAPLING))
|
val BLUE_APRICORN_SEED = apricornSeedItem("blue", ApricornSeedItem(CobblemonBlocks.BLUE_APRICORN_SAPLING, CobblemonBlocks.BLUE_APRICORN))
|
||||||
@JvmField
|
@JvmField
|
||||||
val PINK_APRICORN_SEED = apricornSeedItem("pink", ApricornSeedItem(CobblemonBlocks.PINK_APRICORN_SAPLING))
|
val PINK_APRICORN_SEED = apricornSeedItem("pink", ApricornSeedItem(CobblemonBlocks.PINK_APRICORN_SAPLING, CobblemonBlocks.PINK_APRICORN))
|
||||||
@JvmField
|
@JvmField
|
||||||
val BLACK_APRICORN_SEED = apricornSeedItem("black", ApricornSeedItem(CobblemonBlocks.BLACK_APRICORN_SAPLING))
|
val BLACK_APRICORN_SEED = apricornSeedItem("black", ApricornSeedItem(CobblemonBlocks.BLACK_APRICORN_SAPLING, CobblemonBlocks.BLACK_APRICORN))
|
||||||
@JvmField
|
@JvmField
|
||||||
val WHITE_APRICORN_SEED = apricornSeedItem("white", ApricornSeedItem(CobblemonBlocks.WHITE_APRICORN_SAPLING))
|
val WHITE_APRICORN_SEED = apricornSeedItem("white", ApricornSeedItem(CobblemonBlocks.WHITE_APRICORN_SAPLING, CobblemonBlocks.WHITE_APRICORN))
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val APRICORN_LOG = blockItem("apricorn_log", CobblemonBlocks.APRICORN_LOG)
|
val APRICORN_LOG = blockItem("apricorn_log", CobblemonBlocks.APRICORN_LOG)
|
||||||
@@ -224,11 +233,11 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
|||||||
val APRICORN_HANGING_SIGN = this.create("apricorn_hanging_sign", HangingSignItem(CobblemonBlocks.APRICORN_HANGING_SIGN, CobblemonBlocks.APRICORN_WALL_HANGING_SIGN, Item.Settings().maxCount(16)))
|
val APRICORN_HANGING_SIGN = this.create("apricorn_hanging_sign", HangingSignItem(CobblemonBlocks.APRICORN_HANGING_SIGN, CobblemonBlocks.APRICORN_WALL_HANGING_SIGN, Item.Settings().maxCount(16)))
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val FOSSIL_TUBE = blockItem("fossil_tube", CobblemonBlocks.FOSSIL_TUBE)
|
val RESTORATION_TANK = blockItem("restoration_tank", CobblemonBlocks.RESTORATION_TANK)
|
||||||
@JvmField
|
@JvmField
|
||||||
val FOSSIL_COMPARTMENT = blockItem("fossil_compartment", CobblemonBlocks.FOSSIL_COMPARTMENT)
|
val FOSSIL_ANALYZER = blockItem("fossil_analyzer", CobblemonBlocks.FOSSIL_ANALYZER)
|
||||||
@JvmField
|
@JvmField
|
||||||
val FOSSIL_MONITOR = blockItem("fossil_monitor", CobblemonBlocks.FOSSIL_MONITOR)
|
val MONITOR = blockItem("monitor", CobblemonBlocks.MONITOR)
|
||||||
@JvmField
|
@JvmField
|
||||||
val HEALING_MACHINE = blockItem("healing_machine", CobblemonBlocks.HEALING_MACHINE)
|
val HEALING_MACHINE = blockItem("healing_machine", CobblemonBlocks.HEALING_MACHINE)
|
||||||
@JvmField
|
@JvmField
|
||||||
@@ -568,6 +577,12 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
|||||||
val DEEPSLATE_WATER_STONE_ORE = blockItem("deepslate_water_stone_ore", CobblemonBlocks.DEEPSLATE_WATER_STONE_ORE)
|
val DEEPSLATE_WATER_STONE_ORE = blockItem("deepslate_water_stone_ore", CobblemonBlocks.DEEPSLATE_WATER_STONE_ORE)
|
||||||
@JvmField
|
@JvmField
|
||||||
val DRIPSTONE_MOON_STONE_ORE = blockItem("dripstone_moon_stone_ore", CobblemonBlocks.DRIPSTONE_MOON_STONE_ORE)
|
val DRIPSTONE_MOON_STONE_ORE = blockItem("dripstone_moon_stone_ore", CobblemonBlocks.DRIPSTONE_MOON_STONE_ORE)
|
||||||
|
@JvmField
|
||||||
|
val NETHER_FIRE_STONE_ORE = blockItem("nether_fire_stone_ore", CobblemonBlocks.NETHER_FIRE_STONE_ORE)
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
val DYNITE_ORE = blockItem("dynite_ore", CobblemonBlocks.DYNITE_ORE)
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val DAWN_STONE = noSettingsItem("dawn_stone")
|
val DAWN_STONE = noSettingsItem("dawn_stone")
|
||||||
@JvmField
|
@JvmField
|
||||||
@@ -761,6 +776,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
|||||||
val HELIX_SHERD = noSettingsItem("helix_sherd")
|
val HELIX_SHERD = noSettingsItem("helix_sherd")
|
||||||
@JvmField
|
@JvmField
|
||||||
val NOSTALGIC_SHERD = noSettingsItem("nostalgic_sherd")
|
val NOSTALGIC_SHERD = noSettingsItem("nostalgic_sherd")
|
||||||
|
@JvmField
|
||||||
|
val SUSPICIOUS_SHERD = noSettingsItem("suspicious_sherd")
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val TUMBLESTONE = this.create("tumblestone", TumblestoneItem(Item.Settings(), CobblemonBlocks.SMALL_BUDDING_TUMBLESTONE))
|
val TUMBLESTONE = this.create("tumblestone", TumblestoneItem(Item.Settings(), CobblemonBlocks.SMALL_BUDDING_TUMBLESTONE))
|
||||||
@@ -803,6 +820,12 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
|||||||
@JvmField
|
@JvmField
|
||||||
val BLACK_TUMBLESTONE_BLOCK = blockItem("black_tumblestone_block", CobblemonBlocks.BLACK_TUMBLESTONE_BLOCK)
|
val BLACK_TUMBLESTONE_BLOCK = blockItem("black_tumblestone_block", CobblemonBlocks.BLACK_TUMBLESTONE_BLOCK)
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
val AUTOMATON_ARMOR_TRIM_SMITHING_TEMPLATE: SmithingTemplateItem = this.create(
|
||||||
|
"automaton_armor_trim_smithing_template",
|
||||||
|
SmithingTemplateItem.of(CobblemonArmorTrims.AUTOMATON)
|
||||||
|
)
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val POKEROD = pokerodItem("pokerod")
|
val POKEROD = pokerodItem("pokerod")
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.api.net.NetworkPacket
|
|||||||
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
|
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
|
||||||
import com.cobblemon.mod.common.client.net.PlayerInteractOptionsHandler
|
import com.cobblemon.mod.common.client.net.PlayerInteractOptionsHandler
|
||||||
import com.cobblemon.mod.common.client.net.SetClientPlayerDataHandler
|
import com.cobblemon.mod.common.client.net.SetClientPlayerDataHandler
|
||||||
|
import com.cobblemon.mod.common.client.net.animation.PlayPoseableAnimationHandler
|
||||||
import com.cobblemon.mod.common.client.net.battle.BattleApplyPassResponseHandler
|
import com.cobblemon.mod.common.client.net.battle.BattleApplyPassResponseHandler
|
||||||
import com.cobblemon.mod.common.client.net.battle.BattleCaptureEndHandler
|
import com.cobblemon.mod.common.client.net.battle.BattleCaptureEndHandler
|
||||||
import com.cobblemon.mod.common.client.net.battle.BattleCaptureShakeHandler
|
import com.cobblemon.mod.common.client.net.battle.BattleCaptureShakeHandler
|
||||||
@@ -37,8 +38,10 @@ import com.cobblemon.mod.common.client.net.callback.party.OpenPartyCallbackHandl
|
|||||||
import com.cobblemon.mod.common.client.net.callback.partymove.OpenPartyMoveCallbackHandler
|
import com.cobblemon.mod.common.client.net.callback.partymove.OpenPartyMoveCallbackHandler
|
||||||
import com.cobblemon.mod.common.client.net.data.DataRegistrySyncPacketHandler
|
import com.cobblemon.mod.common.client.net.data.DataRegistrySyncPacketHandler
|
||||||
import com.cobblemon.mod.common.client.net.data.UnlockReloadPacketHandler
|
import com.cobblemon.mod.common.client.net.data.UnlockReloadPacketHandler
|
||||||
|
import com.cobblemon.mod.common.client.net.effect.RunPosableMoLangHandler
|
||||||
import com.cobblemon.mod.common.client.net.dialogue.DialogueClosedHandler
|
import com.cobblemon.mod.common.client.net.dialogue.DialogueClosedHandler
|
||||||
import com.cobblemon.mod.common.client.net.dialogue.DialogueOpenedHandler
|
import com.cobblemon.mod.common.client.net.dialogue.DialogueOpenedHandler
|
||||||
|
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormEntityParticleHandler
|
||||||
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormParticleHandler
|
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormParticleHandler
|
||||||
import com.cobblemon.mod.common.client.net.gui.InteractPokemonUIPacketHandler
|
import com.cobblemon.mod.common.client.net.gui.InteractPokemonUIPacketHandler
|
||||||
import com.cobblemon.mod.common.client.net.gui.SummaryUIPacketHandler
|
import com.cobblemon.mod.common.client.net.gui.SummaryUIPacketHandler
|
||||||
@@ -48,7 +51,6 @@ import com.cobblemon.mod.common.client.net.pasture.PokemonPasturedHandler
|
|||||||
import com.cobblemon.mod.common.client.net.pasture.PokemonUnpasturedHandler
|
import com.cobblemon.mod.common.client.net.pasture.PokemonUnpasturedHandler
|
||||||
import com.cobblemon.mod.common.client.net.pokemon.update.PokemonUpdatePacketHandler
|
import com.cobblemon.mod.common.client.net.pokemon.update.PokemonUpdatePacketHandler
|
||||||
import com.cobblemon.mod.common.client.net.settings.ServerSettingsPacketHandler
|
import com.cobblemon.mod.common.client.net.settings.ServerSettingsPacketHandler
|
||||||
import com.cobblemon.mod.common.client.net.sound.PokemonCryHandler
|
|
||||||
import com.cobblemon.mod.common.client.net.sound.UnvalidatedPlaySoundS2CPacketHandler
|
import com.cobblemon.mod.common.client.net.sound.UnvalidatedPlaySoundS2CPacketHandler
|
||||||
import com.cobblemon.mod.common.client.net.spawn.SpawnExtraDataEntityHandler
|
import com.cobblemon.mod.common.client.net.spawn.SpawnExtraDataEntityHandler
|
||||||
import com.cobblemon.mod.common.client.net.starter.StarterUIPacketHandler
|
import com.cobblemon.mod.common.client.net.starter.StarterUIPacketHandler
|
||||||
@@ -73,6 +75,7 @@ import com.cobblemon.mod.common.client.net.trade.TradeOfferNotificationHandler
|
|||||||
import com.cobblemon.mod.common.client.net.trade.TradeStartedHandler
|
import com.cobblemon.mod.common.client.net.trade.TradeStartedHandler
|
||||||
import com.cobblemon.mod.common.client.net.trade.TradeUpdatedHandler
|
import com.cobblemon.mod.common.client.net.trade.TradeUpdatedHandler
|
||||||
import com.cobblemon.mod.common.net.messages.client.PlayerInteractOptionsPacket
|
import com.cobblemon.mod.common.net.messages.client.PlayerInteractOptionsPacket
|
||||||
|
import com.cobblemon.mod.common.net.messages.client.animation.PlayPoseableAnimationPacket
|
||||||
import com.cobblemon.mod.common.net.messages.client.battle.*
|
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.OpenMoveCallbackPacket
|
||||||
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyCallbackPacket
|
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyCallbackPacket
|
||||||
@@ -85,6 +88,8 @@ import com.cobblemon.mod.common.net.messages.client.data.SpeciesRegistrySyncPack
|
|||||||
import com.cobblemon.mod.common.net.messages.client.data.UnlockReloadPacket
|
import com.cobblemon.mod.common.net.messages.client.data.UnlockReloadPacket
|
||||||
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueClosedPacket
|
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.dialogue.DialogueOpenedPacket
|
||||||
|
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
|
||||||
|
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
|
||||||
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticlePacket
|
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticlePacket
|
||||||
import com.cobblemon.mod.common.net.messages.client.fossil.FossilRegistrySyncPacket
|
import com.cobblemon.mod.common.net.messages.client.fossil.FossilRegistrySyncPacket
|
||||||
import com.cobblemon.mod.common.net.messages.client.fossil.NaturalMaterialRegistrySyncPacket
|
import com.cobblemon.mod.common.net.messages.client.fossil.NaturalMaterialRegistrySyncPacket
|
||||||
@@ -97,8 +102,8 @@ import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.Add
|
|||||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.ClearEvolutionsPacket
|
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.ClearEvolutionsPacket
|
||||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.RemoveEvolutionPacket
|
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.RemoveEvolutionPacket
|
||||||
import com.cobblemon.mod.common.net.messages.client.settings.ServerSettingsPacket
|
import com.cobblemon.mod.common.net.messages.client.settings.ServerSettingsPacket
|
||||||
import com.cobblemon.mod.common.net.messages.client.sound.PokemonCryPacket
|
|
||||||
import com.cobblemon.mod.common.net.messages.client.sound.UnvalidatedPlaySoundS2CPacket
|
import com.cobblemon.mod.common.net.messages.client.sound.UnvalidatedPlaySoundS2CPacket
|
||||||
|
import com.cobblemon.mod.common.net.messages.client.spawn.SpawnGenericBedrockPacket
|
||||||
import com.cobblemon.mod.common.net.messages.client.spawn.SpawnPokeballPacket
|
import com.cobblemon.mod.common.net.messages.client.spawn.SpawnPokeballPacket
|
||||||
import com.cobblemon.mod.common.net.messages.client.spawn.SpawnPokemonPacket
|
import com.cobblemon.mod.common.net.messages.client.spawn.SpawnPokemonPacket
|
||||||
import com.cobblemon.mod.common.net.messages.client.starter.OpenStarterUIPacket
|
import com.cobblemon.mod.common.net.messages.client.starter.OpenStarterUIPacket
|
||||||
@@ -314,12 +319,15 @@ object CobblemonNetwork : NetworkManager {
|
|||||||
|
|
||||||
// Effects
|
// Effects
|
||||||
this.createClientBound(SpawnSnowstormParticlePacket.ID, SpawnSnowstormParticlePacket::decode, SpawnSnowstormParticleHandler)
|
this.createClientBound(SpawnSnowstormParticlePacket.ID, SpawnSnowstormParticlePacket::decode, SpawnSnowstormParticleHandler)
|
||||||
|
this.createClientBound(SpawnSnowstormEntityParticlePacket.ID, SpawnSnowstormEntityParticlePacket::decode, SpawnSnowstormEntityParticleHandler)
|
||||||
|
this.createClientBound(RunPosableMoLangPacket.ID, RunPosableMoLangPacket::decode, RunPosableMoLangHandler)
|
||||||
|
|
||||||
// Hax
|
// Hax
|
||||||
this.createClientBound(UnvalidatedPlaySoundS2CPacket.ID, UnvalidatedPlaySoundS2CPacket::decode, UnvalidatedPlaySoundS2CPacketHandler)
|
this.createClientBound(UnvalidatedPlaySoundS2CPacket.ID, UnvalidatedPlaySoundS2CPacket::decode, UnvalidatedPlaySoundS2CPacketHandler)
|
||||||
this.createClientBound(SpawnPokemonPacket.ID, SpawnPokemonPacket::decode, SpawnExtraDataEntityHandler())
|
this.createClientBound(SpawnPokemonPacket.ID, SpawnPokemonPacket::decode, SpawnExtraDataEntityHandler())
|
||||||
this.createClientBound(SpawnPokeballPacket.ID, SpawnPokeballPacket::decode, SpawnExtraDataEntityHandler())
|
this.createClientBound(SpawnPokeballPacket.ID, SpawnPokeballPacket::decode, SpawnExtraDataEntityHandler())
|
||||||
this.createClientBound(ToastPacket.ID, ToastPacket::decode, ToastPacketHandler)
|
this.createClientBound(ToastPacket.ID, ToastPacket::decode, ToastPacketHandler)
|
||||||
|
this.createClientBound(SpawnGenericBedrockPacket.ID, SpawnGenericBedrockPacket::decode, SpawnExtraDataEntityHandler())
|
||||||
|
|
||||||
// Trade packets
|
// Trade packets
|
||||||
this.createClientBound(TradeAcceptanceChangedPacket.ID, TradeAcceptanceChangedPacket::decode, TradeAcceptanceChangedHandler)
|
this.createClientBound(TradeAcceptanceChangedPacket.ID, TradeAcceptanceChangedPacket::decode, TradeAcceptanceChangedHandler)
|
||||||
@@ -337,7 +345,7 @@ object CobblemonNetwork : NetworkManager {
|
|||||||
this.createClientBound(PokemonUnpasturedPacket.ID, PokemonUnpasturedPacket::decode, PokemonUnpasturedHandler)
|
this.createClientBound(PokemonUnpasturedPacket.ID, PokemonUnpasturedPacket::decode, PokemonUnpasturedHandler)
|
||||||
|
|
||||||
// Behaviours
|
// Behaviours
|
||||||
this.createClientBound(PokemonCryPacket.ID, PokemonCryPacket::decode, PokemonCryHandler)
|
this.createClientBound(PlayPoseableAnimationPacket.ID, PlayPoseableAnimationPacket::decode, PlayPoseableAnimationHandler)
|
||||||
|
|
||||||
// Move select packets
|
// Move select packets
|
||||||
this.createClientBound(OpenMoveCallbackPacket.ID, OpenMoveCallbackPacket::decode, OpenMoveCallbackHandler)
|
this.createClientBound(OpenMoveCallbackPacket.ID, OpenMoveCallbackPacket::decode, OpenMoveCallbackHandler)
|
||||||
|
|||||||
@@ -55,6 +55,10 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
|
|||||||
val POKE_BALL_SEND_OUT = this.create("poke_ball.send_out")
|
val POKE_BALL_SEND_OUT = this.create("poke_ball.send_out")
|
||||||
@JvmField
|
@JvmField
|
||||||
val POKE_BALL_RECALL = this.create("poke_ball.recall")
|
val POKE_BALL_RECALL = this.create("poke_ball.recall")
|
||||||
|
@JvmField
|
||||||
|
val POKE_BALL_THROW = this.create("poke_ball.throw")
|
||||||
|
@JvmField
|
||||||
|
val POKE_BALL_TRAIL = this.create("poke_ball.trail")
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val ITEM_USE = this.create("item.use")
|
val ITEM_USE = this.create("item.use")
|
||||||
@@ -62,6 +66,8 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
|
|||||||
val CAN_EVOLVE = this.create("pokemon.can_evolve")
|
val CAN_EVOLVE = this.create("pokemon.can_evolve")
|
||||||
@JvmField
|
@JvmField
|
||||||
val EVOLVING = this.create("pokemon.evolving")
|
val EVOLVING = this.create("pokemon.evolving")
|
||||||
|
@JvmField
|
||||||
|
val EVOLVE = this.create("evolution.evolve")
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val PVN_BATTLE = this.create("battle.pvn.default")
|
val PVN_BATTLE = this.create("battle.pvn.default")
|
||||||
@@ -123,6 +129,43 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
|
|||||||
@JvmField
|
@JvmField
|
||||||
val TUMBLESTONE_STEP = this.create("tumblestone.step")
|
val TUMBLESTONE_STEP = this.create("tumblestone.step")
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
val IMPACT_NORMAL = this.create("impact.normal")
|
||||||
|
@JvmField
|
||||||
|
val IMPACT_BUG = this.create("impact.bug")
|
||||||
|
@JvmField
|
||||||
|
val IMPACT_DARK = this.create("impact.dark")
|
||||||
|
@JvmField
|
||||||
|
val IMPACT_DRAGON = this.create("impact.dragon")
|
||||||
|
@JvmField
|
||||||
|
val IMPACT_ELECTRIC = this.create("impact.electric")
|
||||||
|
@JvmField
|
||||||
|
val IMPACT_FAIRY = this.create("impact.fairy")
|
||||||
|
@JvmField
|
||||||
|
val IMPACT_FIGHTING = this.create("impact.fighting")
|
||||||
|
@JvmField
|
||||||
|
val IMPACT_FIRE = this.create("impact.fire")
|
||||||
|
@JvmField
|
||||||
|
val IMPACT_FLYING = this.create("impact.flying")
|
||||||
|
@JvmField
|
||||||
|
val IMPACT_GHOST = this.create("impact.ghost")
|
||||||
|
@JvmField
|
||||||
|
val IMPACT_GRASS = this.create("impact.grass")
|
||||||
|
@JvmField
|
||||||
|
val IMPACT_GROUND = this.create("impact.ground")
|
||||||
|
@JvmField
|
||||||
|
val IMPACT_ICE = this.create("impact.ice")
|
||||||
|
@JvmField
|
||||||
|
val IMPACT_POISON = this.create("impact.poison")
|
||||||
|
@JvmField
|
||||||
|
val IMPACT_PSYCHIC = this.create("impact.psychic")
|
||||||
|
@JvmField
|
||||||
|
val IMPACT_ROCK = this.create("impact.rock")
|
||||||
|
@JvmField
|
||||||
|
val IMPACT_STEEL = this.create("impact.steel")
|
||||||
|
@JvmField
|
||||||
|
val IMPACT_WATER = this.create("impact.water")
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val TUMBLESTONE_SOUNDS = BlockSoundGroup(1f, 1f,
|
val TUMBLESTONE_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||||
TUMBLESTONE_BREAK,
|
TUMBLESTONE_BREAK,
|
||||||
|
|||||||
@@ -8,9 +8,13 @@
|
|||||||
|
|
||||||
package com.cobblemon.mod.common.api.battles.model
|
package com.cobblemon.mod.common.api.battles.model
|
||||||
|
|
||||||
|
import com.bedrockk.molang.runtime.MoLangEnvironment
|
||||||
|
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||||
|
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||||
import com.cobblemon.mod.common.Cobblemon
|
import com.cobblemon.mod.common.Cobblemon
|
||||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||||
import com.cobblemon.mod.common.CobblemonNetwork
|
import com.cobblemon.mod.common.CobblemonNetwork
|
||||||
|
import com.cobblemon.mod.common.Environment
|
||||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||||
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
|
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
|
||||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||||
@@ -18,6 +22,8 @@ import com.cobblemon.mod.common.api.battles.model.actor.EntityBackedBattleActor
|
|||||||
import com.cobblemon.mod.common.api.battles.model.actor.FleeableBattleActor
|
import com.cobblemon.mod.common.api.battles.model.actor.FleeableBattleActor
|
||||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||||
import com.cobblemon.mod.common.api.events.battles.BattleFledEvent
|
import com.cobblemon.mod.common.api.events.battles.BattleFledEvent
|
||||||
|
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunction
|
||||||
|
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||||
import com.cobblemon.mod.common.api.text.red
|
import com.cobblemon.mod.common.api.text.red
|
||||||
@@ -464,4 +470,13 @@ open class PokemonBattle(
|
|||||||
LOGGER.error("Missing interpretation on '{}' action: \nPublic » {}\nPrivate » {}", publicMessage.id, publicMessage.rawMessage, privateMessage.rawMessage)
|
LOGGER.error("Missing interpretation on '{}' action: \nPublic » {}\nPrivate » {}", publicMessage.id, publicMessage.rawMessage, privateMessage.rawMessage)
|
||||||
return Text.literal("Missing interpretation on '${publicMessage.id}' action please report to the developers").red()
|
return Text.literal("Missing interpretation on '${publicMessage.id}' action please report to the developers").red()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun addQueryFunctions(queryStruct: QueryStruct): QueryStruct {
|
||||||
|
queryStruct.addFunction("pvp") { DoubleValue(isPvP) }
|
||||||
|
queryStruct.addFunction("pvn") { DoubleValue(isPvN) }
|
||||||
|
queryStruct.addFunction("pvw") { DoubleValue(isPvW) }
|
||||||
|
queryStruct.addFunction("has_rule") { params -> DoubleValue(params.getString(0) in format.ruleSet) }
|
||||||
|
|
||||||
|
return queryStruct
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionCompleteEv
|
|||||||
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionDisplayEvent
|
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionDisplayEvent
|
||||||
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionTestedEvent
|
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionTestedEvent
|
||||||
import com.cobblemon.mod.common.api.events.pokemon.interaction.ExperienceCandyUseEvent
|
import com.cobblemon.mod.common.api.events.pokemon.interaction.ExperienceCandyUseEvent
|
||||||
|
import com.cobblemon.mod.common.api.events.pokemon.interaction.PokemonInteractionGUICreationEvent
|
||||||
import com.cobblemon.mod.common.api.events.starter.StarterChosenEvent
|
import com.cobblemon.mod.common.api.events.starter.StarterChosenEvent
|
||||||
import com.cobblemon.mod.common.api.events.storage.ReleasePokemonEvent
|
import com.cobblemon.mod.common.api.events.storage.ReleasePokemonEvent
|
||||||
import com.cobblemon.mod.common.api.events.world.BigRootPropagatedEvent
|
import com.cobblemon.mod.common.api.events.world.BigRootPropagatedEvent
|
||||||
@@ -100,6 +101,9 @@ object CobblemonEvents {
|
|||||||
@JvmField
|
@JvmField
|
||||||
val LEVEL_UP_EVENT = EventObservable<LevelUpEvent>()
|
val LEVEL_UP_EVENT = EventObservable<LevelUpEvent>()
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
/** CLIENT ONLY! */
|
||||||
|
val POKEMON_INTERACTION_GUI_CREATION = EventObservable<PokemonInteractionGUICreationEvent>()
|
||||||
@JvmField
|
@JvmField
|
||||||
val POKEMON_ENTITY_SAVE = EventObservable<PokemonEntitySaveEvent>()
|
val POKEMON_ENTITY_SAVE = EventObservable<PokemonEntitySaveEvent>()
|
||||||
@JvmField
|
@JvmField
|
||||||
@@ -153,4 +157,8 @@ object CobblemonEvents {
|
|||||||
val LEFTOVERS_CREATED = CancelableObservable<LeftoversCreatedEvent>()
|
val LEFTOVERS_CREATED = CancelableObservable<LeftoversCreatedEvent>()
|
||||||
@JvmField
|
@JvmField
|
||||||
val BIG_ROOT_PROPAGATED = CancelableObservable<BigRootPropagatedEvent>()
|
val BIG_ROOT_PROPAGATED = CancelableObservable<BigRootPropagatedEvent>()
|
||||||
|
@JvmField
|
||||||
|
val HELD_ITEM_PRE = CancelableObservable<HeldItemEvent.Pre>()
|
||||||
|
@JvmField
|
||||||
|
val HELD_ITEM_POST = EventObservable<HeldItemEvent.Post>()
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Cobblemon Contributors
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.cobblemon.mod.common.api.events.pokemon
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.api.events.Cancelable
|
||||||
|
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||||
|
import net.minecraft.item.ItemStack
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base for all the events related to held items.
|
||||||
|
*
|
||||||
|
* @see [Pre]
|
||||||
|
* @see [Post]
|
||||||
|
*/
|
||||||
|
interface HeldItemEvent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The [Pokemon] triggering this event.
|
||||||
|
*/
|
||||||
|
val pokemon: Pokemon
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fired at the start of [Pokemon.swapHeldItem].
|
||||||
|
*
|
||||||
|
* This event should be used to mutate the results of this transaction.
|
||||||
|
*
|
||||||
|
* Canceling this event will prevent the operation and causes the return to be item attempted to be given originally.
|
||||||
|
*
|
||||||
|
* @property pokemon The [Pokemon] triggering this event.
|
||||||
|
* @property receiving The [ItemStack] being sent received from the transaction. By default, this is the item that triggered the interaction.
|
||||||
|
* @property returning The [ItemStack] being sent back from the transaction. By default, this is the currently held item.
|
||||||
|
* @property decrement If the operation should decrement the [receiving] [ItemStack.count], this is handled in the implementation.
|
||||||
|
*
|
||||||
|
* @see [Post]
|
||||||
|
*/
|
||||||
|
data class Pre(override val pokemon: Pokemon, var receiving: ItemStack, var returning: ItemStack, var decrement: Boolean) : HeldItemEvent, Cancelable()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fired at the end of [Pokemon.swapHeldItem].
|
||||||
|
*
|
||||||
|
* @property pokemon The [Pokemon] triggering this event.
|
||||||
|
* @property received The [ItemStack] considered as received and set to the [pokemon]. This is a copy and mutation will not be taken into account.
|
||||||
|
* @property returned The [ItemStack] returned by the method call. This is a copy and mutation will not be taken into account.
|
||||||
|
* @property decremented If the [received] [ItemStack] got decremented.
|
||||||
|
*
|
||||||
|
* @see [Pre]
|
||||||
|
*/
|
||||||
|
data class Post(override val pokemon: Pokemon, val received: ItemStack, val returned: ItemStack, val decremented: Boolean) : HeldItemEvent
|
||||||
|
|
||||||
|
}
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Cobblemon Contributors
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.cobblemon.mod.common.api.events.pokemon.interaction
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.client.gui.interact.wheel.InteractWheelOption
|
||||||
|
import com.cobblemon.mod.common.client.gui.interact.wheel.Orientation
|
||||||
|
import com.google.common.collect.Multimap
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
data class PokemonInteractionGUICreationEvent(
|
||||||
|
val pokemonID: UUID,
|
||||||
|
val mountShoulder: Boolean,
|
||||||
|
val options: Multimap<Orientation, InteractWheelOption>
|
||||||
|
) {
|
||||||
|
fun addFillingOption(option: InteractWheelOption) {
|
||||||
|
options.put(getNextFreeOrientation(), option)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addOption(orientation: Orientation, option: InteractWheelOption) {
|
||||||
|
options.put(orientation, option)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getNextFreeOrientation(): Orientation {
|
||||||
|
var largest = Orientation.TOP_LEFT
|
||||||
|
for(orientation in Orientation.values()) {
|
||||||
|
if(!options.containsKey(orientation)) {
|
||||||
|
return orientation
|
||||||
|
} else {
|
||||||
|
if(options.get(orientation).size < options.get(largest).size) {
|
||||||
|
largest = orientation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return largest
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,7 +19,8 @@ import com.bedrockk.molang.runtime.value.MoValue
|
|||||||
import com.bedrockk.molang.runtime.value.StringValue
|
import com.bedrockk.molang.runtime.value.StringValue
|
||||||
import com.cobblemon.mod.common.Cobblemon
|
import com.cobblemon.mod.common.Cobblemon
|
||||||
import com.cobblemon.mod.common.api.dialogue.PlayerDialogueFaceProvider
|
import com.cobblemon.mod.common.api.dialogue.PlayerDialogueFaceProvider
|
||||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
|
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.WaveFunction
|
||||||
|
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.WaveFunctions
|
||||||
import com.cobblemon.mod.common.util.isInt
|
import com.cobblemon.mod.common.util.isInt
|
||||||
import com.cobblemon.mod.common.util.itemRegistry
|
import com.cobblemon.mod.common.util.itemRegistry
|
||||||
import net.minecraft.block.Block
|
import net.minecraft.block.Block
|
||||||
@@ -51,7 +52,30 @@ object MoLangFunctions {
|
|||||||
"is_number" to java.util.function.Function { params -> DoubleValue(params.get<MoValue>(0).asString().toDoubleOrNull() != null) },
|
"is_number" to java.util.function.Function { params -> DoubleValue(params.get<MoValue>(0).asString().toDoubleOrNull() != null) },
|
||||||
"to_number" to java.util.function.Function { params -> DoubleValue(params.get<MoValue>(0).asString().toDoubleOrNull() ?: 0.0) },
|
"to_number" to java.util.function.Function { params -> DoubleValue(params.get<MoValue>(0).asString().toDoubleOrNull() ?: 0.0) },
|
||||||
"to_int" to java.util.function.Function { params -> DoubleValue(params.get<MoValue>(0).asString().toIntOrNull() ?: 0) },
|
"to_int" to java.util.function.Function { params -> DoubleValue(params.get<MoValue>(0).asString().toIntOrNull() ?: 0) },
|
||||||
"to_string" to java.util.function.Function { params -> StringValue(params.get<MoValue>(0).asString()) }
|
"to_string" to java.util.function.Function { params -> StringValue(params.get<MoValue>(0).asString()) },
|
||||||
|
"do_effect_walks" to java.util.function.Function { _ ->
|
||||||
|
DoubleValue(Cobblemon.config.walkingInBattleAnimations)
|
||||||
|
},
|
||||||
|
"random" to java.util.function.Function { params ->
|
||||||
|
val options = mutableListOf<MoValue>()
|
||||||
|
var index = 0
|
||||||
|
while (params.contains(index)) {
|
||||||
|
options.add(params.get(index))
|
||||||
|
index++
|
||||||
|
}
|
||||||
|
return@Function options.random() // Can throw an exception if they specified no args. They'd be idiots though.
|
||||||
|
},
|
||||||
|
"curve" to java.util.function.Function { params ->
|
||||||
|
val curveName = params.getString(0)
|
||||||
|
val curve = WaveFunctions.functions[curveName] ?: throw IllegalArgumentException("Unknown curve: $curveName")
|
||||||
|
return@Function ObjectValue(curve)
|
||||||
|
},
|
||||||
|
"array" to java.util.function.Function { params ->
|
||||||
|
val values = params.params
|
||||||
|
val array = ArrayStruct(hashMapOf())
|
||||||
|
values.forEachIndexed { index, moValue -> array.setDirectly("$index", moValue) }
|
||||||
|
return@Function array
|
||||||
|
}
|
||||||
)
|
)
|
||||||
val biomeFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
val biomeFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||||
val worldFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
val worldFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||||
@@ -110,6 +134,11 @@ object MoLangFunctions {
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <T : QueryStruct> T.addFunction(name: String, function: java.util.function.Function<MoParams, Any>): T {
|
||||||
|
this.functions[name] = function
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
fun MoLangEnvironment.getQueryStruct(name: String = "query") = structs.getOrPut(name) { QueryStruct(hashMapOf()) } as QueryStruct
|
fun MoLangEnvironment.getQueryStruct(name: String = "query") = structs.getOrPut(name) { QueryStruct(hashMapOf()) } as QueryStruct
|
||||||
|
|
||||||
fun MoLangRuntime.setup(): MoLangRuntime {
|
fun MoLangRuntime.setup(): MoLangRuntime {
|
||||||
|
|||||||
@@ -8,6 +8,12 @@
|
|||||||
|
|
||||||
package com.cobblemon.mod.common.api.moves
|
package com.cobblemon.mod.common.api.moves
|
||||||
|
|
||||||
|
import com.bedrockk.molang.runtime.struct.MoStruct
|
||||||
|
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||||
|
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||||
|
import com.bedrockk.molang.runtime.value.StringValue
|
||||||
|
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunction
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.ActionEffectTimeline
|
||||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategories
|
import com.cobblemon.mod.common.api.moves.categories.DamageCategories
|
||||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategory
|
import com.cobblemon.mod.common.api.moves.categories.DamageCategory
|
||||||
import com.cobblemon.mod.common.api.types.ElementalType
|
import com.cobblemon.mod.common.api.types.ElementalType
|
||||||
@@ -45,8 +51,22 @@ open class MoveTemplate(
|
|||||||
val pp: Int,
|
val pp: Int,
|
||||||
val priority: Int,
|
val priority: Int,
|
||||||
val critRatio: Double,
|
val critRatio: Double,
|
||||||
val effectChances: Array<Double>
|
val effectChances: Array<Double>,
|
||||||
|
val actionEffect: ActionEffectTimeline?
|
||||||
) {
|
) {
|
||||||
|
val struct: MoStruct by lazy {
|
||||||
|
QueryStruct(hashMapOf())
|
||||||
|
.addFunction("name") { StringValue(name) }
|
||||||
|
.addFunction("type") { StringValue(elementalType.name) }
|
||||||
|
.addFunction("damage_category") { StringValue(damageCategory.name) }
|
||||||
|
.addFunction("power") { DoubleValue(power) }
|
||||||
|
.addFunction("target") { StringValue(target.name) }
|
||||||
|
.addFunction("accuracy") { DoubleValue(accuracy) }
|
||||||
|
.addFunction("pp") { DoubleValue(pp) }
|
||||||
|
.addFunction("priority") { DoubleValue(priority) }
|
||||||
|
.addFunction("crit_ratio") { DoubleValue(critRatio) }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
val displayName: MutableText
|
val displayName: MutableText
|
||||||
get() = lang("move.$name")
|
get() = lang("move.$name")
|
||||||
@@ -65,7 +85,8 @@ open class MoveTemplate(
|
|||||||
pp = 5,
|
pp = 5,
|
||||||
priority = 0,
|
priority = 0,
|
||||||
critRatio = 0.0,
|
critRatio = 0.0,
|
||||||
effectChances = emptyArray()
|
effectChances = emptyArray(),
|
||||||
|
actionEffect = null
|
||||||
)
|
)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -10,12 +10,15 @@ package com.cobblemon.mod.common.api.moves
|
|||||||
|
|
||||||
import com.cobblemon.mod.common.Cobblemon
|
import com.cobblemon.mod.common.Cobblemon
|
||||||
import com.cobblemon.mod.common.api.data.DataRegistry
|
import com.cobblemon.mod.common.api.data.DataRegistry
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.ActionEffectTimeline
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
|
||||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategories
|
import com.cobblemon.mod.common.api.moves.categories.DamageCategories
|
||||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||||
import com.cobblemon.mod.common.battles.MoveTarget
|
import com.cobblemon.mod.common.battles.MoveTarget
|
||||||
import com.cobblemon.mod.common.battles.runner.ShowdownService
|
import com.cobblemon.mod.common.battles.runner.ShowdownService
|
||||||
import com.cobblemon.mod.common.net.messages.client.data.MovesRegistrySyncPacket
|
import com.cobblemon.mod.common.net.messages.client.data.MovesRegistrySyncPacket
|
||||||
|
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||||
import com.cobblemon.mod.common.util.cobblemonResource
|
import com.cobblemon.mod.common.util.cobblemonResource
|
||||||
import com.google.gson.JsonArray
|
import com.google.gson.JsonArray
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
@@ -72,7 +75,18 @@ object Moves : DataRegistry {
|
|||||||
effectChances += secondaryMember.get("chance").asDouble
|
effectChances += secondaryMember.get("chance").asDouble
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val move = MoveTemplate(id, num, elementalType, damageCategory, power, target, accuracy, pp, priority, critRatio, effectChances.toTypedArray())
|
val actionEffect = ActionEffects.actionEffects[id.asIdentifierDefaultingNamespace()]
|
||||||
|
?: run {
|
||||||
|
ActionEffects.actionEffects["generic_move".asIdentifierDefaultingNamespace()]
|
||||||
|
// if (damageCategory == DamageCategories.STATUS) {
|
||||||
|
// ActionEffects.actionEffects[cobblemonResource("status")]
|
||||||
|
// } else {
|
||||||
|
// val type = elementalType.name.lowercase()
|
||||||
|
// val category = damageCategory.name.lowercase()
|
||||||
|
// ActionEffects.actionEffects["${category}_$type".asIdentifierDefaultingNamespace()]
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
val move = MoveTemplate(id, num, elementalType, damageCategory, power, target, accuracy, pp, priority, critRatio, effectChances.toTypedArray(), actionEffect)
|
||||||
this.register(move)
|
this.register(move)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Cobblemon.LOGGER.error("Caught exception trying to resolve the move '{}'", id, e)
|
Cobblemon.LOGGER.error("Caught exception trying to resolve the move '{}'", id, e)
|
||||||
|
|||||||
+94
@@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* 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.moves.animations
|
||||||
|
|
||||||
|
import com.bedrockk.molang.Expression
|
||||||
|
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||||
|
import com.bedrockk.molang.runtime.struct.VariableStruct
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.keyframes.ActionEffectKeyframe
|
||||||
|
import com.cobblemon.mod.common.api.scheduling.ScheduledTask
|
||||||
|
import com.cobblemon.mod.common.util.asExpression
|
||||||
|
import com.cobblemon.mod.common.util.resolveBoolean
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
import net.minecraft.entity.Entity
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An action effect will run and execute a series of 'keyframes', with each running once
|
||||||
|
* the previous has completed. The entire effect is considered complete for the given context
|
||||||
|
* once all the 'holds' provided in the context have been cleared or once every keyframe
|
||||||
|
* has finished.
|
||||||
|
*
|
||||||
|
* @author Hiroku
|
||||||
|
* @since October 20th, 2023
|
||||||
|
*/
|
||||||
|
class ActionEffectTimeline(
|
||||||
|
val timeline: List<ActionEffectKeyframe> = mutableListOf(),
|
||||||
|
val condition: Expression = "true".asExpression()
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
val NONE = ActionEffectTimeline()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun run(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||||
|
return if (timeline.isEmpty() || !context.runtime.resolveBoolean(condition)) {
|
||||||
|
CompletableFuture.completedFuture(Unit)
|
||||||
|
} else {
|
||||||
|
val finalFuture = CompletableFuture<Unit>()
|
||||||
|
// .toList copy because I'm paranoid about iterators being trying to share between identical effects playing
|
||||||
|
chainKeyframes(context, timeline.toList().iterator(), finalFuture)
|
||||||
|
finalFuture
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun chainKeyframes(context: ActionEffectContext, iterator: Iterator<ActionEffectKeyframe>, finalFuture: CompletableFuture<Unit>) {
|
||||||
|
if (!iterator.hasNext()) {
|
||||||
|
finalFuture.complete(Unit)
|
||||||
|
} else {
|
||||||
|
val keyframe = iterator.next()
|
||||||
|
context.currentKeyframes.add(keyframe)
|
||||||
|
keyframe.play(context)
|
||||||
|
.thenRun { context.currentKeyframes.remove(keyframe) }
|
||||||
|
.thenApply { chainKeyframes(context, iterator, finalFuture) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ActionEffectContext(
|
||||||
|
val actionEffect: ActionEffectTimeline,
|
||||||
|
val holds: MutableSet<String> = mutableSetOf(),
|
||||||
|
val providers: MutableList<Any> = mutableListOf(),
|
||||||
|
val runtime: MoLangRuntime,
|
||||||
|
var canBeInterrupted: Boolean = false,
|
||||||
|
var interrupted: Boolean = false,
|
||||||
|
var currentKeyframes: MutableList<ActionEffectKeyframe> = mutableListOf()
|
||||||
|
) {
|
||||||
|
inline fun <reified T> findOneProvider() = providers.filterIsInstance<T>().firstOrNull()
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class UsersProvider(users: List<Entity>): EntityProvider {
|
||||||
|
override val entities = users
|
||||||
|
constructor(vararg users: Entity): this(users.toList())
|
||||||
|
}
|
||||||
|
|
||||||
|
class TargetsProvider(targets: List<Entity>): EntityProvider {
|
||||||
|
override val entities = targets
|
||||||
|
constructor(vararg targets: Entity): this(targets.toList())
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EntityProvider {
|
||||||
|
val entities: List<Entity>
|
||||||
|
}
|
||||||
|
|
||||||
|
//class MoveAnimationKeyframe(
|
||||||
|
// val sound: Identifier? = null,
|
||||||
|
// val animation: List<AnimationWithMoments> = listOf(),
|
||||||
|
// val effects: List<ActionEffect> = listOf()
|
||||||
|
//)
|
||||||
@@ -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.api.moves.animations
|
||||||
|
|
||||||
|
import com.bedrockk.molang.Expression
|
||||||
|
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||||
|
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.keyframes.*
|
||||||
|
import com.cobblemon.mod.common.api.pokemon.stats.Stat
|
||||||
|
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||||
|
import com.cobblemon.mod.common.pokemon.adapters.CobblemonStatTypeAdapter
|
||||||
|
import com.cobblemon.mod.common.util.adapters.*
|
||||||
|
import com.cobblemon.mod.common.util.cobblemonResource
|
||||||
|
import com.google.gson.GsonBuilder
|
||||||
|
import com.google.gson.reflect.TypeToken
|
||||||
|
import java.awt.Color
|
||||||
|
import net.minecraft.predicate.NumberRange
|
||||||
|
import net.minecraft.resource.ResourceType
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity
|
||||||
|
import net.minecraft.util.Identifier
|
||||||
|
import net.minecraft.util.math.Box
|
||||||
|
import net.minecraft.util.math.Vec3d
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data registry containing all of the [ActionEffectTimeline]s that can be triggered from various actions.
|
||||||
|
*
|
||||||
|
* @author Hiroku
|
||||||
|
* @since October 21st, 2023
|
||||||
|
*/
|
||||||
|
object ActionEffects : JsonDataRegistry<ActionEffectTimeline> {
|
||||||
|
override val id: Identifier = cobblemonResource("action_effects")
|
||||||
|
override val type: ResourceType = ResourceType.SERVER_DATA
|
||||||
|
override val observable = SimpleObservable<ActionEffects>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
ActionEffectKeyframe.register<AnimationActionEffectKeyframe>("animation")
|
||||||
|
ActionEffectKeyframe.register<EntityMoLangActionEffectKeyframe>("entity_molang")
|
||||||
|
ActionEffectKeyframe.register<MoLangActionEffectKeyframe>("molang")
|
||||||
|
ActionEffectKeyframe.register<ParallelActionEffectKeyframe>("parallel")
|
||||||
|
ActionEffectKeyframe.register<CanInterruptActionEffectKeyframe>("can_interrupt")
|
||||||
|
ActionEffectKeyframe.register<CannotInterruptActionEffectKeyframe>("cannot_interrupt")
|
||||||
|
ActionEffectKeyframe.register<RemoveHoldsActionEffectKeyframe>("remove_holds")
|
||||||
|
ActionEffectKeyframe.register<AddHoldsActionEffectKeyframe>("add_holds")
|
||||||
|
ActionEffectKeyframe.register<MoveToTargetActionEffectKeyframe>("move_to_target")
|
||||||
|
ActionEffectKeyframe.register<ReturnToPositionActionEffectKeyframe>("return_to_position")
|
||||||
|
ActionEffectKeyframe.register<PauseActionEffectKeyframe>("pause")
|
||||||
|
ActionEffectKeyframe.register<SavePositionActionEffectKeyframe>("save_position")
|
||||||
|
ActionEffectKeyframe.register<ForkActionEffectKeyframe>("fork")
|
||||||
|
ActionEffectKeyframe.register<SequenceActionEffectKeyframe>("sequence")
|
||||||
|
ActionEffectKeyframe.register<RunActionEffectKeyframe>("run_action_effect")
|
||||||
|
ActionEffectKeyframe.register<EntityParticlesActionEffectKeyframe>("entity_particles")
|
||||||
|
ActionEffectKeyframe.register<EntitySoundActionEffectKeyframe>("entity_sound")
|
||||||
|
}
|
||||||
|
|
||||||
|
override val gson = GsonBuilder()
|
||||||
|
.disableHtmlEscaping()
|
||||||
|
.setPrettyPrinting()
|
||||||
|
.registerTypeAdapter(ActionEffectKeyframe::class.java, ActionEffectKeyframeAdapter)
|
||||||
|
.registerTypeAdapter(NumberRange.FloatRange::class.java, FloatNumberRangeAdapter)
|
||||||
|
.registerTypeAdapter(TypeToken.getParameterized(Collection::class.java, Box::class.java).type, BoxCollectionAdapter)
|
||||||
|
.registerTypeAdapter(Box::class.java, BoxAdapter)
|
||||||
|
.registerTypeAdapter(Vec3d::class.java, VerboseVec3dAdapter)
|
||||||
|
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
|
||||||
|
.registerTypeAdapter(IntRange::class.java, VerboseIntRangeAdapter)
|
||||||
|
.registerTypeAdapter(Color::class.java, LiteralHexColorAdapter)
|
||||||
|
.registerTypeAdapter(Stat::class.java, CobblemonStatTypeAdapter)
|
||||||
|
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
|
||||||
|
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
|
||||||
|
.registerTypeAdapter(
|
||||||
|
TypeToken.getParameterized(
|
||||||
|
TypeToken.get(List::class.java).type,
|
||||||
|
TypeToken.get(ActionEffectKeyframe::class.java).type
|
||||||
|
).type,
|
||||||
|
SingleToPluralAdapter(ActionEffectKeyframe::class.java) { it }
|
||||||
|
)
|
||||||
|
.create()
|
||||||
|
|
||||||
|
override val typeToken: TypeToken<ActionEffectTimeline> = TypeToken.get(ActionEffectTimeline::class.java)
|
||||||
|
override val resourcePath = "action_effects"
|
||||||
|
|
||||||
|
val actionEffects = mutableMapOf<Identifier, ActionEffectTimeline>()
|
||||||
|
override fun reload(data: Map<Identifier, ActionEffectTimeline>) {
|
||||||
|
actionEffects.clear()
|
||||||
|
actionEffects.putAll(data)
|
||||||
|
observable.emit(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun sync(player: ServerPlayerEntity) {}
|
||||||
|
}
|
||||||
+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.moves.animations.keyframes
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A single component of an action effect. When played it must return a completable future that completes
|
||||||
|
* when the action this keyframe represents is finished. [interrupt] is provided for when something successfully
|
||||||
|
* interrupts the effect so that if any cancellation logic is necessary, it can be provided.
|
||||||
|
*
|
||||||
|
* @author Hiroku
|
||||||
|
* @since October 26th, 2023
|
||||||
|
*/
|
||||||
|
interface ActionEffectKeyframe {
|
||||||
|
companion object {
|
||||||
|
val types = mutableMapOf<String, Class<out ActionEffectKeyframe>>()
|
||||||
|
|
||||||
|
inline fun <reified T : ActionEffectKeyframe> register(type: String) {
|
||||||
|
types[type] = T::class.java
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun play(context: ActionEffectContext): CompletableFuture<Unit>
|
||||||
|
fun interrupt(context: ActionEffectContext) {}
|
||||||
|
fun skip(): CompletableFuture<Unit> = CompletableFuture.completedFuture(Unit)
|
||||||
|
}
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* 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.moves.animations.keyframes
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An [ActionEffectKeyframe] that adds some holds from the context for future code to recognize as blocking some
|
||||||
|
* functionality from proceeding.
|
||||||
|
*
|
||||||
|
* @author Hiroku
|
||||||
|
* @since October 27th, 2023
|
||||||
|
*/
|
||||||
|
class AddHoldsActionEffectKeyframe : ActionEffectKeyframe {
|
||||||
|
val holds = mutableSetOf<String>()
|
||||||
|
override fun play(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||||
|
context.holds.addAll(holds)
|
||||||
|
return CompletableFuture.completedFuture(Unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* 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.moves.animations.keyframes
|
||||||
|
|
||||||
|
import com.bedrockk.molang.Expression
|
||||||
|
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.EntityProvider
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||||
|
import com.cobblemon.mod.common.api.scheduling.delayedFuture
|
||||||
|
import com.cobblemon.mod.common.net.messages.client.animation.PlayPoseableAnimationPacket
|
||||||
|
import com.cobblemon.mod.common.util.asExpressionLike
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
import net.minecraft.server.world.ServerWorld
|
||||||
|
|
||||||
|
class AnimationActionEffectKeyframe : ConditionalActionEffectKeyframe(), EntityConditionalActionEffectKeyframe {
|
||||||
|
var delay = "0".asExpressionLike()
|
||||||
|
var visibilityRange = 200
|
||||||
|
var animation: Set<String> = setOf("physical")
|
||||||
|
var variables: List<Expression> = listOf()
|
||||||
|
override val entityCondition = "q.entity.is_user".asExpressionLike()
|
||||||
|
|
||||||
|
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||||
|
val entities = context.providers
|
||||||
|
.filterIsInstance<EntityProvider>()
|
||||||
|
.flatMap { prov -> prov.entities.filter { test(context, it, isUser = prov is UsersProvider) } }
|
||||||
|
|
||||||
|
val expressions = variables.map { it.originalString }.toSet()
|
||||||
|
|
||||||
|
// Treat them as expressions if possible but otherwise yeah just send them as strings
|
||||||
|
val animation = animation.map {
|
||||||
|
try {
|
||||||
|
it.asExpressionLike().resolveString(context.runtime).takeIf { it != "0.0" } ?: it
|
||||||
|
} catch (e: Exception) {
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}.toSet()
|
||||||
|
|
||||||
|
for (entity in entities) {
|
||||||
|
val world = entity.world as ServerWorld
|
||||||
|
val players = world.getPlayers { it.distanceTo(entity) <= visibilityRange }
|
||||||
|
val pkt = PlayPoseableAnimationPacket(entity.id, animation = animation, expressions = expressions)
|
||||||
|
players.forEach { it.sendPacket(pkt) }
|
||||||
|
}
|
||||||
|
|
||||||
|
return delayedFuture(seconds = delay.resolveFloat(context.runtime), serverThread = true)
|
||||||
|
}
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Cobblemon Contributors
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.cobblemon.mod.common.api.moves.animations.keyframes
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
|
||||||
|
class CanInterruptActionEffectKeyframe : ConditionalActionEffectKeyframe() {
|
||||||
|
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||||
|
context.canBeInterrupted = true
|
||||||
|
return CompletableFuture.completedFuture(Unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Cobblemon Contributors
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.cobblemon.mod.common.api.moves.animations.keyframes
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
|
||||||
|
class CannotInterruptActionEffectKeyframe : ConditionalActionEffectKeyframe() {
|
||||||
|
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||||
|
context.canBeInterrupted = true
|
||||||
|
return CompletableFuture.completedFuture(Unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* 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.moves.animations.keyframes
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||||
|
import com.cobblemon.mod.common.util.asExpressionLike
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
|
||||||
|
abstract class ConditionalActionEffectKeyframe : ActionEffectKeyframe {
|
||||||
|
var condition: ExpressionLike = "true".asExpressionLike()
|
||||||
|
override fun play(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||||
|
return if (condition.resolveBoolean(context.runtime)) {
|
||||||
|
playWhenTrue(context)
|
||||||
|
} else {
|
||||||
|
skip()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit>
|
||||||
|
}
|
||||||
+36
@@ -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.api.moves.animations.keyframes
|
||||||
|
|
||||||
|
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||||
|
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||||
|
import com.bedrockk.molang.runtime.value.StringValue
|
||||||
|
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||||
|
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||||
|
import net.minecraft.entity.Entity
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An action effect keyframe that plays for all entities for which the condition is true.
|
||||||
|
*
|
||||||
|
* @author Hiroku
|
||||||
|
* @since January 21st, 2024
|
||||||
|
*/
|
||||||
|
interface EntityConditionalActionEffectKeyframe {
|
||||||
|
val entityCondition: ExpressionLike
|
||||||
|
fun test(context: ActionEffectContext, entity: Entity, isUser: Boolean): Boolean {
|
||||||
|
// TODO this should use the entity's own query struct
|
||||||
|
context.runtime.environment.getQueryStruct().addFunction("entity") {
|
||||||
|
QueryStruct(hashMapOf())
|
||||||
|
.addFunction("uuid") { StringValue(entity.uuidAsString) }
|
||||||
|
.addFunction("is_user") { DoubleValue(isUser) }
|
||||||
|
}
|
||||||
|
return entityCondition.resolveBoolean(context.runtime)
|
||||||
|
}
|
||||||
|
}
|
||||||
+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.moves.animations.keyframes
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||||
|
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.EntityProvider
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||||
|
import com.cobblemon.mod.common.api.scheduling.delayedFuture
|
||||||
|
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
|
||||||
|
import com.cobblemon.mod.common.util.asExpressionLike
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
import net.minecraft.server.world.ServerWorld
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An action effect keyframe that will run client-side MoLang for all entities that fit the entity condition.
|
||||||
|
*
|
||||||
|
* This MoLang executes within that entity's runtime, meaning you can trigger animations or locational particles
|
||||||
|
* or sounds.
|
||||||
|
*
|
||||||
|
* @author Hiroku
|
||||||
|
* @since October 30th, 2023
|
||||||
|
*/
|
||||||
|
class EntityMoLangActionEffectKeyframe : ConditionalActionEffectKeyframe(), EntityConditionalActionEffectKeyframe {
|
||||||
|
var delay = "0".asExpressionLike()
|
||||||
|
val expressions = mutableSetOf<String>()
|
||||||
|
val visibilityRange = 200
|
||||||
|
override val entityCondition: ExpressionLike = "q.entity.is_user".asExpressionLike()
|
||||||
|
|
||||||
|
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||||
|
val entities = context.providers
|
||||||
|
.filterIsInstance<EntityProvider>()
|
||||||
|
.flatMap { prov -> prov.entities.filter { test(context, it, isUser = prov is UsersProvider) } }
|
||||||
|
|
||||||
|
for (entity in entities) {
|
||||||
|
val world = entity.world as ServerWorld
|
||||||
|
val players = world.getPlayers { it.distanceTo(entity) <= visibilityRange }
|
||||||
|
val pkt = RunPosableMoLangPacket(entityId = entity.id, expressions = expressions)
|
||||||
|
players.forEach { it.sendPacket(pkt) }
|
||||||
|
}
|
||||||
|
|
||||||
|
return delayedFuture(seconds = delay.resolveFloat(context.runtime), serverThread = true)
|
||||||
|
}
|
||||||
|
}
|
||||||
+56
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* 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.moves.animations.keyframes
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||||
|
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.EntityProvider
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||||
|
import com.cobblemon.mod.common.api.scheduling.delayedFuture
|
||||||
|
import com.cobblemon.mod.common.entity.Poseable
|
||||||
|
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
|
||||||
|
import com.cobblemon.mod.common.util.asExpressionLike
|
||||||
|
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
import net.minecraft.server.world.ServerWorld
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spawns particles on the entity based on the given particle effect and locator.
|
||||||
|
*
|
||||||
|
* @author Hiroku
|
||||||
|
* @since January 21st, 2024
|
||||||
|
*/
|
||||||
|
class EntityParticlesActionEffectKeyframe : ConditionalActionEffectKeyframe(), EntityConditionalActionEffectKeyframe {
|
||||||
|
override val entityCondition = "q.entity.is_user".asExpressionLike()
|
||||||
|
var effect: String? = null
|
||||||
|
var locator: String = "root"
|
||||||
|
val delay: ExpressionLike = "0".asExpressionLike()
|
||||||
|
val visibilityRange = 200
|
||||||
|
|
||||||
|
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||||
|
val entities = context.providers
|
||||||
|
.filterIsInstance<EntityProvider>()
|
||||||
|
.flatMap { prov -> prov.entities.filter { test(context, it, isUser = prov is UsersProvider) } }
|
||||||
|
|
||||||
|
val effectIdentifier = try {
|
||||||
|
effect?.asExpressionLike()?.resolveString(context.runtime)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
effect
|
||||||
|
}?.asIdentifierDefaultingNamespace() ?: return skip()
|
||||||
|
|
||||||
|
entities.filter { it is Poseable }.forEach { entity ->
|
||||||
|
val packet = SpawnSnowstormEntityParticlePacket(effectIdentifier, entity.id, locator)
|
||||||
|
val players = (entity.world as ServerWorld).getPlayers { it.distanceTo(entity) <= visibilityRange }
|
||||||
|
packet.sendToPlayers(players)
|
||||||
|
}
|
||||||
|
|
||||||
|
return delayedFuture(seconds = delay.resolveFloat(context.runtime), serverThread = true)
|
||||||
|
}
|
||||||
|
}
|
||||||
+50
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* 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.moves.animations.keyframes
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.EntityProvider
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||||
|
import com.cobblemon.mod.common.api.scheduling.delayedFuture
|
||||||
|
import com.cobblemon.mod.common.util.asExpressionLike
|
||||||
|
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
import net.minecraft.registry.RegistryKeys
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An action effect keyframe that plays a positioned sound for all matching entities.
|
||||||
|
*
|
||||||
|
* @author Hiroku
|
||||||
|
* @since January 21st, 2024
|
||||||
|
*/
|
||||||
|
class EntitySoundActionEffectKeyframe : ConditionalActionEffectKeyframe(), EntityConditionalActionEffectKeyframe {
|
||||||
|
override val entityCondition = "q.entity.is_user".asExpressionLike()
|
||||||
|
var sound: String? = null
|
||||||
|
val delay: ExpressionLike = "0".asExpressionLike()
|
||||||
|
|
||||||
|
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||||
|
val entities = context.providers
|
||||||
|
.filterIsInstance<EntityProvider>()
|
||||||
|
.flatMap { prov -> prov.entities.filter { test(context, it, isUser = prov is UsersProvider) } }
|
||||||
|
|
||||||
|
val soundIdentifier = try {
|
||||||
|
sound?.asExpressionLike()?.resolveString(context.runtime)?.takeIf { it != "0.0" } ?: sound
|
||||||
|
} catch (e: Exception) {
|
||||||
|
sound
|
||||||
|
}?.asIdentifierDefaultingNamespace() ?: return skip()
|
||||||
|
|
||||||
|
entities.forEach { entity ->
|
||||||
|
val soundEvent = entity.world.registryManager.get(RegistryKeys.SOUND_EVENT).get(soundIdentifier) ?: return skip()
|
||||||
|
entity.playSound(soundEvent, 1f, 1f)
|
||||||
|
}
|
||||||
|
|
||||||
|
return delayedFuture(seconds = delay.resolveFloat(context.runtime), serverThread = true)
|
||||||
|
}
|
||||||
|
}
|
||||||
+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.moves.animations.keyframes
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||||
|
import com.cobblemon.mod.common.util.asExpressionLike
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
|
||||||
|
class ForkActionEffectKeyframe(
|
||||||
|
val condition: ExpressionLike = "true".asExpressionLike(),
|
||||||
|
val ifTrue: List<ActionEffectKeyframe> = listOf(),
|
||||||
|
val ifFalse: List<ActionEffectKeyframe> = listOf()
|
||||||
|
) : ActionEffectKeyframe {
|
||||||
|
override fun play(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||||
|
val future = CompletableFuture<Unit>()
|
||||||
|
/*
|
||||||
|
* Using .toList() before running chainKeyframes because iterators can be weird about sharing,
|
||||||
|
* .toList() creates a copy of the list and then grabs its iterator so much safer (three parachutes)
|
||||||
|
*/
|
||||||
|
if (!condition.resolveBoolean(context.runtime)) {
|
||||||
|
context.actionEffect.chainKeyframes(context, ifFalse.toList().iterator(), future)
|
||||||
|
} else {
|
||||||
|
context.actionEffect.chainKeyframes(context, ifTrue.toList().iterator(), future)
|
||||||
|
}
|
||||||
|
|
||||||
|
return future
|
||||||
|
}
|
||||||
|
}
|
||||||
+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.api.moves.animations.keyframes
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||||
|
import com.cobblemon.mod.common.api.scheduling.delayedFuture
|
||||||
|
import com.cobblemon.mod.common.util.asExpressionLike
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An action effect keyframe that simply executes some MoLang on the effect context's runtime.
|
||||||
|
*
|
||||||
|
* @author Hiroku
|
||||||
|
* @since January 21st, 2024
|
||||||
|
*/
|
||||||
|
class MoLangActionEffectKeyframe : ActionEffectKeyframe {
|
||||||
|
val expressions: ExpressionLike = "0".asExpressionLike()
|
||||||
|
val delay: ExpressionLike = "0".asExpressionLike()
|
||||||
|
override fun play(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||||
|
expressions.resolve(context.runtime)
|
||||||
|
return delayedFuture(seconds = delay.resolveFloat(context.runtime), serverThread = true)
|
||||||
|
}
|
||||||
|
}
|
||||||
+75
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* 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.moves.animations.keyframes
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.ActionEffectTimeline
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.TargetsProvider
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||||
|
import com.cobblemon.mod.common.api.scheduling.afterOnServer
|
||||||
|
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||||
|
import com.cobblemon.mod.common.entity.pokemon.ai.PokemonNavigation
|
||||||
|
import com.cobblemon.mod.common.util.asExpressionLike
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
import kotlin.math.pow
|
||||||
|
import kotlin.math.sqrt
|
||||||
|
import net.minecraft.util.Identifier
|
||||||
|
|
||||||
|
class MoveToTargetActionEffectKeyframe : ActionEffectKeyframe {
|
||||||
|
val speed = 1F
|
||||||
|
val timeout = "4".asExpressionLike()
|
||||||
|
var proximity = -1F
|
||||||
|
val timeoutActionEffect: Identifier? = null
|
||||||
|
|
||||||
|
override fun play(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||||
|
val user = context.findOneProvider<UsersProvider>()?.entities?.firstOrNull() as? PokemonEntity ?: return CompletableFuture.completedFuture(Unit)
|
||||||
|
val target = context.findOneProvider<TargetsProvider>()?.entities?.firstOrNull() ?: return CompletableFuture.completedFuture(Unit)
|
||||||
|
|
||||||
|
val future = CompletableFuture<Unit>()
|
||||||
|
|
||||||
|
var timedOut = false
|
||||||
|
|
||||||
|
val proximity = this.proximity.takeIf { it != -1F } ?: (sqrt(2 * user.boundingBox.xLength.pow(2)) + 1.5F + sqrt(2 * target.boundingBox.xLength.pow(2))).toFloat()
|
||||||
|
|
||||||
|
if (target.distanceTo(user) !in proximity..20F) {
|
||||||
|
future.complete(Unit)
|
||||||
|
return future
|
||||||
|
}
|
||||||
|
|
||||||
|
val timeoutEffect = timeoutActionEffect?.let { ActionEffects.actionEffects[it] } ?: ActionEffectTimeline.NONE
|
||||||
|
|
||||||
|
val nav = user.navigation
|
||||||
|
val navContext = PokemonNavigation.NavigationContext(
|
||||||
|
destinationProximity = proximity,
|
||||||
|
onArrival = {
|
||||||
|
if (!future.isDone && !timedOut) {
|
||||||
|
future.complete(Unit)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onCannotReach = {
|
||||||
|
if (!future.isDone && !timedOut) {
|
||||||
|
timedOut = true
|
||||||
|
timeoutEffect.run(context).thenApply { future.complete(Unit) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
afterOnServer(seconds = timeout.resolveFloat(context.runtime)) {
|
||||||
|
if (!future.isDone && !timedOut) {
|
||||||
|
timedOut = true
|
||||||
|
timeoutEffect.run(context).thenApply { future.complete(Unit) }
|
||||||
|
nav.stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nav.startMovingTo(target.x, target.y, target.z, speed.toDouble(), navContext)
|
||||||
|
return future
|
||||||
|
}
|
||||||
|
}
|
||||||
+25
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Cobblemon Contributors
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.cobblemon.mod.common.api.moves.animations.keyframes
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
|
||||||
|
class ParallelActionEffectKeyframe : ConditionalActionEffectKeyframe() {
|
||||||
|
var keyframes: MutableList<ActionEffectKeyframe> = mutableListOf()
|
||||||
|
|
||||||
|
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||||
|
return CompletableFuture.allOf(
|
||||||
|
*keyframes.map {
|
||||||
|
context.currentKeyframes.add(it)
|
||||||
|
it.play(context).thenRun { context.currentKeyframes.remove(it) }
|
||||||
|
}.toTypedArray()
|
||||||
|
).thenApply {} // Map Void -> Unit at the end
|
||||||
|
}
|
||||||
|
}
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* 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.moves.animations.keyframes
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||||
|
import com.cobblemon.mod.common.api.scheduling.delayedFuture
|
||||||
|
import com.cobblemon.mod.common.util.asExpressionLike
|
||||||
|
|
||||||
|
class PauseActionEffectKeyframe : ConditionalActionEffectKeyframe() {
|
||||||
|
val pause = "1".asExpressionLike()
|
||||||
|
override fun playWhenTrue(context: ActionEffectContext) = delayedFuture(seconds = pause.resolveFloat(context.runtime), serverThread = true)
|
||||||
|
}
|
||||||
+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.moves.animations.keyframes
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||||
|
import com.cobblemon.mod.common.api.scheduling.delayedFuture
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An [ActionEffectKeyframe] that clears some holds from the context, potentially marking the effect as
|
||||||
|
* complete as far as any blocked actions are concerned. If no holds are specified, then all holds are
|
||||||
|
* removed.
|
||||||
|
*
|
||||||
|
* @author Hiroku
|
||||||
|
* @since October 27th, 2023
|
||||||
|
*/
|
||||||
|
class RemoveHoldsActionEffectKeyframe : ActionEffectKeyframe {
|
||||||
|
val delay = 0F
|
||||||
|
val holds = mutableSetOf<String>()
|
||||||
|
override fun play(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||||
|
return delayedFuture(seconds = delay, serverThread = true).thenApply {
|
||||||
|
if (holds.isEmpty()) {
|
||||||
|
context.holds.clear()
|
||||||
|
} else {
|
||||||
|
context.holds.removeAll(holds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+70
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* 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.moves.animations.keyframes
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.ActionEffectTimeline
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||||
|
import com.cobblemon.mod.common.api.scheduling.after
|
||||||
|
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||||
|
import com.cobblemon.mod.common.entity.pokemon.ai.PokemonNavigation
|
||||||
|
import com.cobblemon.mod.common.util.asExpressionLike
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
import net.minecraft.util.Identifier
|
||||||
|
import net.minecraft.util.math.Vec3d
|
||||||
|
|
||||||
|
class ReturnToPositionActionEffectKeyframe : ActionEffectKeyframe {
|
||||||
|
val speed = 1F
|
||||||
|
val timeout = "4".asExpressionLike()
|
||||||
|
val timeoutActionEffect: Identifier? = null
|
||||||
|
|
||||||
|
override fun play(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||||
|
val user = context.findOneProvider<UsersProvider>()?.entities?.firstOrNull() as? PokemonEntity ?: return skip()
|
||||||
|
val future = CompletableFuture<Unit>()
|
||||||
|
|
||||||
|
val pos = (context.runtime.environment.getValue(setOf("${user.uuidAsString}-pos").iterator())?.value() as? ObjectValue<*>)?.obj as? Vec3d ?: return skip()
|
||||||
|
|
||||||
|
var timedOut = false
|
||||||
|
|
||||||
|
if (pos.distanceTo(user.pos) > 20) {
|
||||||
|
future.complete(Unit)
|
||||||
|
return future
|
||||||
|
}
|
||||||
|
|
||||||
|
val timeoutEffect = timeoutActionEffect?.let { ActionEffects.actionEffects[it] } ?: ActionEffectTimeline.NONE
|
||||||
|
|
||||||
|
val nav = user.navigation
|
||||||
|
val navContext = PokemonNavigation.NavigationContext(
|
||||||
|
onArrival = {
|
||||||
|
if (!future.isDone && !timedOut) {
|
||||||
|
future.complete(Unit)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onCannotReach = {
|
||||||
|
if (!future.isDone && !timedOut) {
|
||||||
|
timedOut = true
|
||||||
|
timeoutEffect.run(context).thenApply { future.complete(Unit) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
after(seconds = timeout.resolveFloat(context.runtime), serverThread = true) {
|
||||||
|
if (!future.isDone && !timedOut) {
|
||||||
|
timedOut = true
|
||||||
|
timeoutEffect.run(context).thenApply { future.complete(Unit) }
|
||||||
|
nav.stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nav.startMovingTo(pos.x, pos.y, pos.z, speed.toDouble(), navContext)
|
||||||
|
return future
|
||||||
|
}
|
||||||
|
}
|
||||||
+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.moves.animations.keyframes
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
import net.minecraft.util.Identifier
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An action effect keyframe that simply runs another action effect based on an identifier. This action
|
||||||
|
* effect is marked complete only when the action effect it runs is complete unless [waitForActionEffect] is
|
||||||
|
* false.
|
||||||
|
*
|
||||||
|
* @author Hiroku
|
||||||
|
* @since January 21st, 2024
|
||||||
|
*/
|
||||||
|
class RunActionEffectKeyframe : ConditionalActionEffectKeyframe() {
|
||||||
|
val actionEffect: Identifier? = null
|
||||||
|
val waitForActionEffect = true
|
||||||
|
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||||
|
return if (actionEffect != null) {
|
||||||
|
ActionEffects.actionEffects[actionEffect]?.run(context)?.takeIf { waitForActionEffect } ?: skip()
|
||||||
|
} else {
|
||||||
|
skip()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* 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.moves.animations.keyframes
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
|
||||||
|
class SavePositionActionEffectKeyframe: ConditionalActionEffectKeyframe() {
|
||||||
|
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||||
|
val user = context.findOneProvider<UsersProvider>()?.entities?.firstOrNull() ?: return skip()
|
||||||
|
context.runtime.environment.setSimpleVariable("${user.uuidAsString}-pos", ObjectValue(user.pos))
|
||||||
|
return skip()
|
||||||
|
}
|
||||||
|
}
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Cobblemon Contributors
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.cobblemon.mod.common.api.moves.animations.keyframes
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A sequence of action effects that are dependent on a condition.
|
||||||
|
*
|
||||||
|
* @author Hiroku
|
||||||
|
* @since October 29th, 2023
|
||||||
|
*/
|
||||||
|
class SequenceActionEffectKeyframe(val keyframes: List<ActionEffectKeyframe> = listOf()) : ConditionalActionEffectKeyframe() {
|
||||||
|
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||||
|
val future = CompletableFuture<Unit>()
|
||||||
|
context.actionEffect.chainKeyframes(context, keyframes.toList().iterator(), future)
|
||||||
|
return future
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
package com.cobblemon.mod.common.api.multiblock
|
package com.cobblemon.mod.common.api.multiblock
|
||||||
|
|
||||||
import com.cobblemon.mod.common.block.entity.fossil.FossilMultiblockEntity
|
import com.cobblemon.mod.common.block.entity.FossilMultiblockEntity
|
||||||
import net.minecraft.block.*
|
import net.minecraft.block.*
|
||||||
import net.minecraft.block.entity.BlockEntity
|
import net.minecraft.block.entity.BlockEntity
|
||||||
import net.minecraft.entity.LivingEntity
|
import net.minecraft.entity.LivingEntity
|
||||||
|
|||||||
@@ -42,5 +42,7 @@ interface MultiblockStructure {
|
|||||||
fun getComparatorOutput(state: BlockState, world: World?, pos: BlockPos?): Int {
|
fun getComparatorOutput(state: BlockState, world: World?, pos: BlockPos?): Int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun markRemoved(world: World):Unit
|
||||||
fun onTriggerEvent(state: BlockState?, world: ServerWorld?, pos: BlockPos?, random: Random?)
|
fun onTriggerEvent(state: BlockState?, world: ServerWorld?, pos: BlockPos?, random: Random?)
|
||||||
}
|
}
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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.net.serializers
|
||||||
|
|
||||||
|
import net.minecraft.entity.data.TrackedDataHandler
|
||||||
|
import net.minecraft.network.PacketByteBuf
|
||||||
|
import net.minecraft.util.Identifier
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data serializer of [Identifier] for DataTracker things.
|
||||||
|
*
|
||||||
|
* @author Hiroku
|
||||||
|
* @since May 22nd, 2023
|
||||||
|
*/
|
||||||
|
object IdentifierDataSerializer : TrackedDataHandler<Identifier> {
|
||||||
|
override fun copy(value: Identifier) = Identifier(value.namespace, value.path)
|
||||||
|
override fun read(buf: PacketByteBuf) = Identifier(buf.readString(), buf.readString())
|
||||||
|
override fun write(buf: PacketByteBuf, value: Identifier) {
|
||||||
|
buf.writeString(value.namespace)
|
||||||
|
buf.writeString(value.path)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -204,7 +204,7 @@ object PokeBalls : JsonDataRegistry<PokeBall> {
|
|||||||
createDefault("ancient_feather_ball", throwPower = 2.5f, ancient = true)
|
createDefault("ancient_feather_ball", throwPower = 2.5f, ancient = true)
|
||||||
createDefault("ancient_wing_ball", throwPower = 2.5f, ancient = true)
|
createDefault("ancient_wing_ball", throwPower = 2.5f, ancient = true)
|
||||||
createDefault("ancient_jet_ball", throwPower = 2.5f, ancient = true)
|
createDefault("ancient_jet_ball", throwPower = 2.5f, ancient = true)
|
||||||
createDefault("ancient_origin_ball", ancient = true)
|
createDefault("ancient_origin_ball", GuaranteedModifier(), ancient = true)
|
||||||
// Luxury ball effect
|
// Luxury ball effect
|
||||||
CobblemonEvents.FRIENDSHIP_UPDATED.subscribe(priority = Priority.LOWEST) { event ->
|
CobblemonEvents.FRIENDSHIP_UPDATED.subscribe(priority = Priority.LOWEST) { event ->
|
||||||
var increment = (event.newFriendship - event.pokemon.friendship).toFloat()
|
var increment = (event.newFriendship - event.pokemon.friendship).toFloat()
|
||||||
|
|||||||
-2
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.api.pokemon.effect
|
|||||||
import com.cobblemon.mod.common.api.scheduling.ServerTaskTracker
|
import com.cobblemon.mod.common.api.scheduling.ServerTaskTracker
|
||||||
import com.cobblemon.mod.common.platform.events.PlatformEvents
|
import com.cobblemon.mod.common.platform.events.PlatformEvents
|
||||||
import com.cobblemon.mod.common.pokemon.activestate.ShoulderedState
|
import com.cobblemon.mod.common.pokemon.activestate.ShoulderedState
|
||||||
import com.cobblemon.mod.common.pokemon.effects.LightSourceEffect
|
|
||||||
import com.cobblemon.mod.common.pokemon.effects.PotionBaseEffect
|
import com.cobblemon.mod.common.pokemon.effects.PotionBaseEffect
|
||||||
import com.cobblemon.mod.common.util.party
|
import com.cobblemon.mod.common.util.party
|
||||||
import net.minecraft.server.network.ServerPlayerEntity
|
import net.minecraft.server.network.ServerPlayerEntity
|
||||||
@@ -29,7 +28,6 @@ object ShoulderEffectRegistry {
|
|||||||
private val effects = mutableMapOf<String, Class<out ShoulderEffect>>()
|
private val effects = mutableMapOf<String, Class<out ShoulderEffect>>()
|
||||||
|
|
||||||
// Effects - START
|
// Effects - START
|
||||||
val LIGHT_SOURCE = register("light_source", LightSourceEffect::class.java)
|
|
||||||
val POTION_EFFECT = register("potion_effect", PotionBaseEffect::class.java)
|
val POTION_EFFECT = register("potion_effect", PotionBaseEffect::class.java)
|
||||||
// Effects - END
|
// Effects - END
|
||||||
|
|
||||||
|
|||||||
@@ -16,11 +16,14 @@ import com.cobblemon.mod.common.api.moves.BenchedMove
|
|||||||
import com.cobblemon.mod.common.api.moves.MoveTemplate
|
import com.cobblemon.mod.common.api.moves.MoveTemplate
|
||||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||||
import com.cobblemon.mod.common.api.pokemon.evolution.requirement.EvolutionRequirement
|
import com.cobblemon.mod.common.api.pokemon.evolution.requirement.EvolutionRequirement
|
||||||
|
import com.cobblemon.mod.common.api.scheduling.afterOnServer
|
||||||
|
import com.cobblemon.mod.common.entity.generic.GenericBedrockEntity
|
||||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||||
import com.cobblemon.mod.common.pokemon.activestate.ShoulderedState
|
import com.cobblemon.mod.common.pokemon.activestate.ShoulderedState
|
||||||
import com.cobblemon.mod.common.pokemon.evolution.variants.ItemInteractionEvolution
|
import com.cobblemon.mod.common.pokemon.evolution.variants.ItemInteractionEvolution
|
||||||
import com.cobblemon.mod.common.pokemon.evolution.variants.LevelUpEvolution
|
import com.cobblemon.mod.common.pokemon.evolution.variants.LevelUpEvolution
|
||||||
import com.cobblemon.mod.common.pokemon.evolution.variants.TradeEvolution
|
import com.cobblemon.mod.common.pokemon.evolution.variants.TradeEvolution
|
||||||
|
import com.cobblemon.mod.common.util.cobblemonResource
|
||||||
import com.cobblemon.mod.common.util.lang
|
import com.cobblemon.mod.common.util.lang
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.minecraft.sound.SoundCategory
|
import net.minecraft.sound.SoundCategory
|
||||||
@@ -92,6 +95,7 @@ interface Evolution : EvolutionLike {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts this evolution as soon as possible.
|
* Starts this evolution as soon as possible.
|
||||||
* This will not present a choice to the client regardless of [optional].
|
* This will not present a choice to the client regardless of [optional].
|
||||||
@@ -99,25 +103,57 @@ interface Evolution : EvolutionLike {
|
|||||||
* @param pokemon The [Pokemon] being evolved.
|
* @param pokemon The [Pokemon] being evolved.
|
||||||
*/
|
*/
|
||||||
fun forceEvolve(pokemon: Pokemon) {
|
fun forceEvolve(pokemon: Pokemon) {
|
||||||
|
// This is a switch to enable/disable the evolution effect while we get particles improved
|
||||||
|
val useEvolutionEffect = false
|
||||||
|
|
||||||
if (pokemon.state is ShoulderedState) {
|
if (pokemon.state is ShoulderedState) {
|
||||||
pokemon.tryRecallWithAnimation()
|
pokemon.tryRecallWithAnimation()
|
||||||
}
|
}
|
||||||
// ToDo Once implemented queue evolution for a pokemon state that is not in battle, start animation instead of instantly doing all of this
|
|
||||||
|
val pokemonEntity = pokemon.entity
|
||||||
|
if (pokemonEntity == null || !useEvolutionEffect) {
|
||||||
|
evolutionMethod(pokemon)
|
||||||
|
} else {
|
||||||
|
pokemonEntity.evolutionEntity = pokemon.getOwnerPlayer()?.let { GenericBedrockEntity(world = it.world) }
|
||||||
|
val evolutionEntity = pokemon.entity!!.evolutionEntity
|
||||||
|
evolutionEntity?.apply {
|
||||||
|
category = cobblemonResource("evolution")
|
||||||
|
colliderHeight = pokemonEntity.height
|
||||||
|
colliderWidth = pokemonEntity.width
|
||||||
|
scale = pokemonEntity.scaleFactor
|
||||||
|
syncAge = true // Otherwise particle animation will be starting from zero even if you come along partway through
|
||||||
|
setPosition(pokemonEntity.x, pokemonEntity.y, pokemonEntity.z)
|
||||||
|
}
|
||||||
|
pokemon.getOwnerPlayer()?.world?.spawnEntity(evolutionEntity)
|
||||||
|
afterOnServer(seconds = 9F) {
|
||||||
|
if (!pokemonEntity.isRemoved) {
|
||||||
|
evolutionMethod(pokemon)
|
||||||
|
afterOnServer(seconds = 1.5F) { pokemonEntity.cry() }
|
||||||
|
afterOnServer(seconds = 3F) {
|
||||||
|
if (evolutionEntity != null) {
|
||||||
|
evolutionEntity.kill()
|
||||||
|
if (!pokemonEntity.isRemoved) {
|
||||||
|
pokemonEntity.evolutionEntity = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun evolutionMethod(pokemon: Pokemon) {
|
||||||
this.result.apply(pokemon)
|
this.result.apply(pokemon)
|
||||||
this.learnableMoves.forEach { move ->
|
this.learnableMoves.forEach { move ->
|
||||||
if (pokemon.moveSet.hasSpace()) {
|
if (pokemon.moveSet.hasSpace()) {
|
||||||
pokemon.moveSet.add(move.create())
|
pokemon.moveSet.add(move.create())
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
pokemon.benchedMoves.add(BenchedMove(move, 0))
|
pokemon.benchedMoves.add(BenchedMove(move, 0))
|
||||||
}
|
}
|
||||||
pokemon.getOwnerPlayer()?.sendMessage(lang("experience.learned_move", pokemon.getDisplayName(), move.displayName))
|
pokemon.getOwnerPlayer()?.sendMessage(lang("experience.learned_move", pokemon.getDisplayName(), move.displayName))
|
||||||
}
|
}
|
||||||
// we want to instantly tick for example you might only evolve your Bulbasaur at level 34 so Venusaur should be immediately available
|
// we want to instantly tick for example you might only evolve your Bulbasaur at level 34 so Venusaur should be immediately available
|
||||||
pokemon.evolutions.filterIsInstance<PassiveEvolution>()
|
pokemon.evolutions.filterIsInstance<PassiveEvolution>().forEach { evolution -> evolution.attemptEvolution(pokemon) }
|
||||||
.forEach { evolution ->
|
|
||||||
evolution.attemptEvolution(pokemon)
|
|
||||||
}
|
|
||||||
pokemon.getOwnerPlayer()?.playSound(CobblemonSounds.EVOLVING, SoundCategory.NEUTRAL, 1F, 1F)
|
pokemon.getOwnerPlayer()?.playSound(CobblemonSounds.EVOLVING, SoundCategory.NEUTRAL, 1F, 1F)
|
||||||
CobblemonEvents.EVOLUTION_COMPLETE.post(EvolutionCompleteEvent(pokemon, this))
|
CobblemonEvents.EVOLUTION_COMPLETE.post(EvolutionCompleteEvent(pokemon, this))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,13 +8,27 @@
|
|||||||
|
|
||||||
package com.cobblemon.mod.common.api.scheduling
|
package com.cobblemon.mod.common.api.scheduling
|
||||||
|
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
|
||||||
@Deprecated("Use afterOnServer or afterOnClient; ambiguous side is not good for your health")
|
@Deprecated("Use afterOnServer or afterOnClient; ambiguous side is not good for your health")
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
|
|
||||||
|
|
||||||
fun after(ticks: Int = 0, seconds: Float = 0F, serverThread: Boolean = false, action: () -> Unit) {
|
fun after(ticks: Int = 0, seconds: Float = 0F, serverThread: Boolean = false, action: () -> Unit) {
|
||||||
val scheduler = if (serverThread) ServerTaskTracker else ClientTaskTracker
|
val scheduler = if (serverThread) ServerTaskTracker else ClientTaskTracker
|
||||||
scheduler.after(seconds = seconds + ticks / 20F, action)
|
scheduler.after(seconds = seconds + ticks / 20F, action)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun delayedFuture(ticks: Int = 0, seconds: Float = 0F, serverThread: Boolean = false): CompletableFuture<Unit> {
|
||||||
|
val future = CompletableFuture<Unit>()
|
||||||
|
if (ticks == 0 && seconds == 0F) {
|
||||||
|
future.complete(Unit)
|
||||||
|
} else {
|
||||||
|
after(ticks = ticks, seconds = seconds, serverThread = serverThread) { future.complete(Unit) }
|
||||||
|
}
|
||||||
|
return future
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delayed task is created to run on the main thread. This is for when the task
|
* Delayed task is created to run on the main thread. This is for when the task
|
||||||
* being completed after the delay does things like entity removal or other thread-unsafe actions.
|
* being completed after the delay does things like entity removal or other thread-unsafe actions.
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import com.mojang.serialization.DynamicOps
|
|||||||
import com.mojang.serialization.codecs.ListCodec
|
import com.mojang.serialization.codecs.ListCodec
|
||||||
import com.mojang.serialization.codecs.PrimitiveCodec
|
import com.mojang.serialization.codecs.PrimitiveCodec
|
||||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||||
|
import com.mojang.serialization.codecs.UnboundedMapCodec
|
||||||
import kotlin.math.floor
|
import kotlin.math.floor
|
||||||
import net.minecraft.network.PacketByteBuf
|
import net.minecraft.network.PacketByteBuf
|
||||||
|
|
||||||
@@ -44,6 +45,7 @@ interface MoLangCurve : CodecMapped {
|
|||||||
registerSubtype(CurveType.LINEAR, LinearMoLangCurve::class.java, LinearMoLangCurve.CODEC)
|
registerSubtype(CurveType.LINEAR, LinearMoLangCurve::class.java, LinearMoLangCurve.CODEC)
|
||||||
registerSubtype(CurveType.CATMULL_ROM, CatmullRomMoLangCurve::class.java, CatmullRomMoLangCurve.CODEC)
|
registerSubtype(CurveType.CATMULL_ROM, CatmullRomMoLangCurve::class.java, CatmullRomMoLangCurve.CODEC)
|
||||||
registerSubtype(CurveType.BEZIER, BezierMoLangCurve::class.java, BezierMoLangCurve.CODEC)
|
registerSubtype(CurveType.BEZIER, BezierMoLangCurve::class.java, BezierMoLangCurve.CODEC)
|
||||||
|
registerSubtype(CurveType.BEZIER_CHAIN, BezierChainMoLangCurve::class.java, BezierChainMoLangCurve.CODEC)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,8 +54,7 @@ interface MoLangCurve : CodecMapped {
|
|||||||
var input: Expression
|
var input: Expression
|
||||||
fun resolve(runtime: MoLangRuntime, inputValue: Double): Double
|
fun resolve(runtime: MoLangRuntime, inputValue: Double): Double
|
||||||
fun apply(runtime: MoLangRuntime) {
|
fun apply(runtime: MoLangRuntime) {
|
||||||
val inputValue = runtime.resolveDouble(input)
|
runtime.environment.setSimpleVariable(name, DoubleValue(resolve(runtime, runtime.resolveDouble(input))))
|
||||||
runtime.environment.setSimpleVariable(name, DoubleValue(resolve(runtime, inputValue)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,6 +166,103 @@ class CatmullRomMoLangCurve(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class BezierChainMoLangCurve(
|
||||||
|
override var name: String = "variable",
|
||||||
|
override var input: Expression = NumberExpression(0.5),
|
||||||
|
var nodes: Map<Double, BezierChainNode> = emptyMap()
|
||||||
|
) : MoLangCurve {
|
||||||
|
var nodePairs: List<BezierChainNodePair> = emptyList()
|
||||||
|
|
||||||
|
fun deriveNodePairs() {
|
||||||
|
val nodePairs = mutableListOf<BezierChainNodePair>()
|
||||||
|
val sortedNodes = nodes.entries.sortedBy { it.key }
|
||||||
|
for (i in 1 until sortedNodes.size) {
|
||||||
|
val node1 = sortedNodes[i - 1]
|
||||||
|
val node2 = sortedNodes[i]
|
||||||
|
|
||||||
|
nodePairs.add(BezierChainNodePair(node1.key, node2.key, node1.value, node2.value))
|
||||||
|
}
|
||||||
|
this.nodePairs = nodePairs
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
deriveNodePairs()
|
||||||
|
}
|
||||||
|
|
||||||
|
class BezierChainNode(var value: Double, var slope: Double) {
|
||||||
|
fun writeToBuffer(buffer: PacketByteBuf) {
|
||||||
|
buffer.writeDouble(value)
|
||||||
|
buffer.writeDouble(slope)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun readFromBuffer(buffer: PacketByteBuf) {
|
||||||
|
value = buffer.readDouble()
|
||||||
|
slope = buffer.readDouble()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val CODEC = RecordCodecBuilder.create<BezierChainNode> { instance ->
|
||||||
|
instance.group(
|
||||||
|
PrimitiveCodec.DOUBLE.fieldOf("value").forGetter { it.value },
|
||||||
|
PrimitiveCodec.DOUBLE.fieldOf("slope").forGetter { it.slope }
|
||||||
|
).apply(instance, ::BezierChainNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BezierChainNodePair(
|
||||||
|
val startTime: Double,
|
||||||
|
val endTime: Double,
|
||||||
|
node1: BezierChainNode,
|
||||||
|
node2: BezierChainNode
|
||||||
|
) {
|
||||||
|
val curve: CubedBezierCurve
|
||||||
|
init {
|
||||||
|
val v1 = node1.value
|
||||||
|
val v2 = node1.value + node1.slope / 3
|
||||||
|
val v3 = node2.value - node2.slope / 3
|
||||||
|
val v4 = node2.value
|
||||||
|
curve = CubedBezierCurve(v1, v2, v3, v4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BezierChainPointData(val time: Double, val value: Double, val slope: Double)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val CODEC: Codec<BezierChainMoLangCurve> = RecordCodecBuilder.create { instance ->
|
||||||
|
instance.group(
|
||||||
|
PrimitiveCodec.STRING.fieldOf("type").forGetter { it.type.name },
|
||||||
|
PrimitiveCodec.STRING.fieldOf("name").forGetter { it.name },
|
||||||
|
EXPRESSION_CODEC.fieldOf("input").forGetter { it.input },
|
||||||
|
UnboundedMapCodec(PrimitiveCodec.DOUBLE, BezierChainNode.CODEC).fieldOf("nodes").forGetter { it.nodes }
|
||||||
|
).apply(instance) { _, name, input, nodes -> BezierChainMoLangCurve(name, input, nodes) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val type: CurveType = CurveType.BEZIER_CHAIN
|
||||||
|
override fun resolve(runtime: MoLangRuntime, inputValue: Double): Double {
|
||||||
|
val position = inputValue.coerceIn(0.0, 1.0)
|
||||||
|
val nodePair = nodePairs.last { position >= it.startTime }
|
||||||
|
val curve = nodePair.curve
|
||||||
|
val t = (position - nodePair.startTime) / (nodePair.endTime - nodePair.startTime)
|
||||||
|
return curve.getY(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
||||||
|
override fun readFromBuffer(buffer: PacketByteBuf) {
|
||||||
|
name = buffer.readString()
|
||||||
|
input = MoLang.createParser(buffer.readString()).parseExpression()
|
||||||
|
nodes = buffer.readMap({ buffer.readDouble() }, { BezierChainNode(0.0, 0.0).also { it.readFromBuffer(buffer) } })
|
||||||
|
deriveNodePairs()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun writeToBuffer(buffer: PacketByteBuf) {
|
||||||
|
buffer.writeString(name)
|
||||||
|
buffer.writeString(input.getString())
|
||||||
|
buffer.writeMap(nodes, { pb, key -> pb.writeDouble(key) }, { pb, value -> value.writeToBuffer(pb) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class BezierMoLangCurve(
|
class BezierMoLangCurve(
|
||||||
override var name: String = "variable",
|
override var name: String = "variable",
|
||||||
override var input: Expression = NumberExpression(0.5),
|
override var input: Expression = NumberExpression(0.5),
|
||||||
|
|||||||
+82
-6
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.api.codec.CodecMapped
|
|||||||
import com.cobblemon.mod.common.api.data.ArbitrarilyMappedSerializableCompanion
|
import com.cobblemon.mod.common.api.data.ArbitrarilyMappedSerializableCompanion
|
||||||
import com.cobblemon.mod.common.client.render.MatrixWrapper
|
import com.cobblemon.mod.common.client.render.MatrixWrapper
|
||||||
import com.cobblemon.mod.common.util.math.hamiltonProduct
|
import com.cobblemon.mod.common.util.math.hamiltonProduct
|
||||||
|
import com.cobblemon.mod.common.util.set
|
||||||
import com.mojang.serialization.Codec
|
import com.mojang.serialization.Codec
|
||||||
import com.mojang.serialization.DynamicOps
|
import com.mojang.serialization.DynamicOps
|
||||||
import com.mojang.serialization.codecs.PrimitiveCodec
|
import com.mojang.serialization.codecs.PrimitiveCodec
|
||||||
@@ -26,6 +27,7 @@ import net.minecraft.util.math.RotationAxis
|
|||||||
import net.minecraft.util.math.Vec3d
|
import net.minecraft.util.math.Vec3d
|
||||||
import org.joml.AxisAngle4d
|
import org.joml.AxisAngle4d
|
||||||
import org.joml.Quaternionf
|
import org.joml.Quaternionf
|
||||||
|
import org.joml.Vector3f
|
||||||
|
|
||||||
interface ParticleCameraMode : CodecMapped {
|
interface ParticleCameraMode : CodecMapped {
|
||||||
companion object : ArbitrarilyMappedSerializableCompanion<ParticleCameraMode, ParticleCameraModeType>(
|
companion object : ArbitrarilyMappedSerializableCompanion<ParticleCameraMode, ParticleCameraModeType>(
|
||||||
@@ -54,6 +56,8 @@ interface ParticleCameraMode : CodecMapped {
|
|||||||
prevAngle: Float,
|
prevAngle: Float,
|
||||||
angle: Float,
|
angle: Float,
|
||||||
deltaTicks: Float,
|
deltaTicks: Float,
|
||||||
|
particlePosition: Vec3d,
|
||||||
|
cameraPosition: Vec3d,
|
||||||
cameraAngle: Quaternionf,
|
cameraAngle: Quaternionf,
|
||||||
cameraYaw: Float,
|
cameraYaw: Float,
|
||||||
cameraPitch: Float,
|
cameraPitch: Float,
|
||||||
@@ -77,6 +81,8 @@ class RotateXYZCameraMode : ParticleCameraMode {
|
|||||||
prevAngle: Float,
|
prevAngle: Float,
|
||||||
angle: Float,
|
angle: Float,
|
||||||
deltaTicks: Float,
|
deltaTicks: Float,
|
||||||
|
particlePosition: Vec3d,
|
||||||
|
cameraPosition: Vec3d,
|
||||||
cameraAngle: Quaternionf,
|
cameraAngle: Quaternionf,
|
||||||
cameraYaw: Float,
|
cameraYaw: Float,
|
||||||
cameraPitch: Float,
|
cameraPitch: Float,
|
||||||
@@ -109,6 +115,8 @@ class RotateYCameraMode : ParticleCameraMode {
|
|||||||
prevAngle: Float,
|
prevAngle: Float,
|
||||||
angle: Float,
|
angle: Float,
|
||||||
deltaTicks: Float,
|
deltaTicks: Float,
|
||||||
|
particlePosition: Vec3d,
|
||||||
|
cameraPosition: Vec3d,
|
||||||
cameraAngle: Quaternionf,
|
cameraAngle: Quaternionf,
|
||||||
cameraYaw: Float,
|
cameraYaw: Float,
|
||||||
cameraPitch: Float,
|
cameraPitch: Float,
|
||||||
@@ -146,13 +154,15 @@ class LookAtXYZ : ParticleCameraMode {
|
|||||||
prevAngle: Float,
|
prevAngle: Float,
|
||||||
angle: Float,
|
angle: Float,
|
||||||
deltaTicks: Float,
|
deltaTicks: Float,
|
||||||
|
particlePosition: Vec3d,
|
||||||
|
cameraPosition: Vec3d,
|
||||||
cameraAngle: Quaternionf,
|
cameraAngle: Quaternionf,
|
||||||
cameraYaw: Float,
|
cameraYaw: Float,
|
||||||
cameraPitch: Float,
|
cameraPitch: Float,
|
||||||
viewDirection: Vec3d
|
viewDirection: Vec3d
|
||||||
): Quaternionf {
|
): Quaternionf {
|
||||||
val i = if (angle == 0F) 0F else MathHelper.lerp(deltaTicks, prevAngle, angle)
|
val i = if (angle == 0F) 0F else MathHelper.lerp(deltaTicks, prevAngle, angle)
|
||||||
val rotation = Quaternionf(0F, 0F, 0F, 1F)
|
val rotation = Quaternionf()
|
||||||
rotation.hamiltonProduct(RotationAxis.POSITIVE_Y.rotationDegrees(-cameraYaw))
|
rotation.hamiltonProduct(RotationAxis.POSITIVE_Y.rotationDegrees(-cameraYaw))
|
||||||
rotation.hamiltonProduct(RotationAxis.POSITIVE_X.rotationDegrees(cameraPitch))
|
rotation.hamiltonProduct(RotationAxis.POSITIVE_X.rotationDegrees(cameraPitch))
|
||||||
rotation.hamiltonProduct(RotationAxis.POSITIVE_Z.rotationDegrees(i))
|
rotation.hamiltonProduct(RotationAxis.POSITIVE_Z.rotationDegrees(i))
|
||||||
@@ -174,6 +184,8 @@ class LookAtY : ParticleCameraMode {
|
|||||||
prevAngle: Float,
|
prevAngle: Float,
|
||||||
angle: Float,
|
angle: Float,
|
||||||
deltaTicks: Float,
|
deltaTicks: Float,
|
||||||
|
particlePosition: Vec3d,
|
||||||
|
cameraPosition: Vec3d,
|
||||||
cameraAngle: Quaternionf,
|
cameraAngle: Quaternionf,
|
||||||
cameraYaw: Float,
|
cameraYaw: Float,
|
||||||
cameraPitch: Float,
|
cameraPitch: Float,
|
||||||
@@ -203,6 +215,8 @@ class DirectionZ : ParticleCameraMode {
|
|||||||
prevAngle: Float,
|
prevAngle: Float,
|
||||||
angle: Float,
|
angle: Float,
|
||||||
deltaTicks: Float,
|
deltaTicks: Float,
|
||||||
|
particlePosition: Vec3d,
|
||||||
|
cameraPosition: Vec3d,
|
||||||
cameraAngle: Quaternionf,
|
cameraAngle: Quaternionf,
|
||||||
cameraYaw: Float,
|
cameraYaw: Float,
|
||||||
cameraPitch: Float,
|
cameraPitch: Float,
|
||||||
@@ -236,6 +250,8 @@ class EmitterYZPlane : ParticleCameraMode {
|
|||||||
prevAngle: Float,
|
prevAngle: Float,
|
||||||
angle: Float,
|
angle: Float,
|
||||||
deltaTicks: Float,
|
deltaTicks: Float,
|
||||||
|
particlePosition: Vec3d,
|
||||||
|
cameraPosition: Vec3d,
|
||||||
cameraAngle: Quaternionf,
|
cameraAngle: Quaternionf,
|
||||||
cameraYaw: Float,
|
cameraYaw: Float,
|
||||||
cameraPitch: Float,
|
cameraPitch: Float,
|
||||||
@@ -274,6 +290,8 @@ class EmitterXZPlane : ParticleCameraMode {
|
|||||||
prevAngle: Float,
|
prevAngle: Float,
|
||||||
angle: Float,
|
angle: Float,
|
||||||
deltaTicks: Float,
|
deltaTicks: Float,
|
||||||
|
particlePosition: Vec3d,
|
||||||
|
cameraPosition: Vec3d,
|
||||||
cameraAngle: Quaternionf,
|
cameraAngle: Quaternionf,
|
||||||
cameraYaw: Float,
|
cameraYaw: Float,
|
||||||
cameraPitch: Float,
|
cameraPitch: Float,
|
||||||
@@ -311,6 +329,8 @@ class EmitterXYPlane : ParticleCameraMode {
|
|||||||
prevAngle: Float,
|
prevAngle: Float,
|
||||||
angle: Float,
|
angle: Float,
|
||||||
deltaTicks: Float,
|
deltaTicks: Float,
|
||||||
|
particlePosition: Vec3d,
|
||||||
|
cameraPosition: Vec3d,
|
||||||
cameraAngle: Quaternionf,
|
cameraAngle: Quaternionf,
|
||||||
cameraYaw: Float,
|
cameraYaw: Float,
|
||||||
cameraPitch: Float,
|
cameraPitch: Float,
|
||||||
@@ -347,6 +367,8 @@ class DirectionY : ParticleCameraMode {
|
|||||||
prevAngle: Float,
|
prevAngle: Float,
|
||||||
angle: Float,
|
angle: Float,
|
||||||
deltaTicks: Float,
|
deltaTicks: Float,
|
||||||
|
particlePosition: Vec3d,
|
||||||
|
cameraPosition: Vec3d,
|
||||||
cameraAngle: Quaternionf,
|
cameraAngle: Quaternionf,
|
||||||
cameraYaw: Float,
|
cameraYaw: Float,
|
||||||
cameraPitch: Float,
|
cameraPitch: Float,
|
||||||
@@ -380,6 +402,8 @@ class DirectionX : ParticleCameraMode {
|
|||||||
prevAngle: Float,
|
prevAngle: Float,
|
||||||
angle: Float,
|
angle: Float,
|
||||||
deltaTicks: Float,
|
deltaTicks: Float,
|
||||||
|
particlePosition: Vec3d,
|
||||||
|
cameraPosition: Vec3d,
|
||||||
cameraAngle: Quaternionf,
|
cameraAngle: Quaternionf,
|
||||||
cameraYaw: Float,
|
cameraYaw: Float,
|
||||||
cameraPitch: Float,
|
cameraPitch: Float,
|
||||||
@@ -398,6 +422,29 @@ class DirectionX : ParticleCameraMode {
|
|||||||
override fun writeToBuffer(buffer: PacketByteBuf) {}
|
override fun writeToBuffer(buffer: PacketByteBuf) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* You can think of this camera mode as the one that does the following:
|
||||||
|
*
|
||||||
|
* - Uses the direction of motion as the particle X axis
|
||||||
|
* - Uses a vector parallel to the camera plane and perpendicular to the direction of motion as the particle Y axis.
|
||||||
|
*
|
||||||
|
* The second requirement is difficult to accomplish. The way it was eventually solved is by
|
||||||
|
* thinking of the plane generated by two specific vectors. One is the camera to the particle,
|
||||||
|
* the other is the camera to where the particle will be after it continues moving on its
|
||||||
|
* trajectory for some amount of time.
|
||||||
|
*
|
||||||
|
* That plane slices right through the camera, and so the normal vector of that plane is parallel
|
||||||
|
* lies on the camera plane (hard to explain that one). Since the plane includes the direction vector,
|
||||||
|
* the normal vector of that plane is perpendicular to the direction vector. Since the direction
|
||||||
|
* vector is being used for the X axis, and the normal vector is perpendicular, we can use that as
|
||||||
|
* the Y axis safely.
|
||||||
|
*
|
||||||
|
* The chicanery of this look direction is all simply to calculate the correct Y axis, use it,
|
||||||
|
* and then use the direction vector for the X axis.
|
||||||
|
*
|
||||||
|
* @author Hiroku
|
||||||
|
* @since June 29th, 2023
|
||||||
|
*/
|
||||||
class LookAtDirection : ParticleCameraMode {
|
class LookAtDirection : ParticleCameraMode {
|
||||||
override val type: ParticleCameraModeType = ParticleCameraModeType.LOOK_AT_DIRECTION
|
override val type: ParticleCameraModeType = ParticleCameraModeType.LOOK_AT_DIRECTION
|
||||||
companion object {
|
companion object {
|
||||||
@@ -408,21 +455,50 @@ class LookAtDirection : ParticleCameraMode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reusable shit so fewer instantiations during rendering.
|
||||||
|
val viewDirectionF = Vector3f(0F, 0F, 0F)
|
||||||
|
val particlePositionF = Vector3f(0F, 0F, 0F)
|
||||||
|
val cameraPositionF = Vector3f(0F, 0F, 0F)
|
||||||
|
val axisAngle = AxisAngle4d()
|
||||||
|
|
||||||
override fun getRotation(
|
override fun getRotation(
|
||||||
matrixWrapper: MatrixWrapper,
|
matrixWrapper: MatrixWrapper,
|
||||||
prevAngle: Float,
|
prevAngle: Float,
|
||||||
angle: Float,
|
angle: Float,
|
||||||
deltaTicks: Float,
|
deltaTicks: Float,
|
||||||
|
particlePosition: Vec3d,
|
||||||
|
cameraPosition: Vec3d,
|
||||||
cameraAngle: Quaternionf,
|
cameraAngle: Quaternionf,
|
||||||
cameraYaw: Float,
|
cameraYaw: Float,
|
||||||
cameraPitch: Float,
|
cameraPitch: Float,
|
||||||
viewDirection: Vec3d
|
viewDirection: Vec3d
|
||||||
): Quaternionf {
|
): Quaternionf {
|
||||||
val i = if (angle == 0F) 0F else MathHelper.lerp(deltaTicks, prevAngle, angle)
|
viewDirectionF.set(viewDirection)
|
||||||
val rotation = Quaternionf(0F, 0F, 0F, 1F)
|
particlePositionF.set(particlePosition)
|
||||||
rotation.hamiltonProduct(RotationAxis.POSITIVE_Y.rotationDegrees((viewDirection.x * -cameraYaw).toFloat()))
|
cameraPositionF.set(cameraPosition)
|
||||||
rotation.hamiltonProduct(RotationAxis.POSITIVE_X.rotationDegrees((viewDirection.y * cameraPitch).toFloat()))
|
|
||||||
rotation.hamiltonProduct(RotationAxis.POSITIVE_Z.rotationDegrees((viewDirection.z * i).toFloat()))
|
// Perform a rotation around the axis that should later become the particle Y axis
|
||||||
|
Quaternionf().rotateTo(
|
||||||
|
// Camera -> Particle
|
||||||
|
particlePositionF.sub(cameraPositionF, Vector3f()),
|
||||||
|
// Camera -> (Particle + Direction)
|
||||||
|
particlePositionF.add(viewDirectionF, Vector3f()).sub(cameraPositionF)
|
||||||
|
).get(axisAngle) // Extract the rotation into axis + angle, so we can pluck the axis out.
|
||||||
|
|
||||||
|
// Extract the axis of rotation, it is what we want the particle's local Y axis to be.
|
||||||
|
val correctY = Vector3f(axisAngle.x.toFloat(), axisAngle.y.toFloat(), axisAngle.z.toFloat())
|
||||||
|
// First make X look along the direction vector
|
||||||
|
val rotation = Quaternionf().rotateTo(Vector3f(1F, 0F, 0F), viewDirectionF)
|
||||||
|
// Now figure out what the local Y axis is
|
||||||
|
val currentY = Vector3f(0F, 1F, 0F).rotate(rotation)
|
||||||
|
// Move that local Y to the correct local Y
|
||||||
|
// Pre-multiply is because the previous transform won't affect the correct Y, but vice versa absolutely would; we don't want that.
|
||||||
|
rotation.premul(Quaternionf().rotateTo(currentY, correctY))
|
||||||
|
|
||||||
|
// Do the regular rotation around Z to spin the particle, same as all other modes.
|
||||||
|
val particleAngle = if (angle == 0.0f) 0F else MathHelper.lerp(deltaTicks, prevAngle, angle)
|
||||||
|
rotation.hamiltonProduct(RotationAxis.POSITIVE_Z.rotationDegrees(particleAngle))
|
||||||
|
|
||||||
return rotation
|
return rotation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+9
-5
@@ -17,6 +17,7 @@ import com.cobblemon.mod.common.api.data.ArbitrarilyMappedSerializableCompanion
|
|||||||
import com.cobblemon.mod.common.util.asExpression
|
import com.cobblemon.mod.common.util.asExpression
|
||||||
import com.cobblemon.mod.common.util.codec.EXPRESSION_CODEC
|
import com.cobblemon.mod.common.util.codec.EXPRESSION_CODEC
|
||||||
import com.cobblemon.mod.common.util.getString
|
import com.cobblemon.mod.common.util.getString
|
||||||
|
import com.cobblemon.mod.common.util.resolve
|
||||||
import com.cobblemon.mod.common.util.resolveBoolean
|
import com.cobblemon.mod.common.util.resolveBoolean
|
||||||
import com.cobblemon.mod.common.util.resolveDouble
|
import com.cobblemon.mod.common.util.resolveDouble
|
||||||
import com.mojang.serialization.Codec
|
import com.mojang.serialization.Codec
|
||||||
@@ -55,7 +56,9 @@ class OnceEmitterLifetime(var activeTime: Expression = 1.0.asExpression()) : Par
|
|||||||
override val type = ParticleEmitterLifetimeType.ONCE
|
override val type = ParticleEmitterLifetimeType.ONCE
|
||||||
|
|
||||||
override fun getAction(runtime: MoLangRuntime, started: Boolean, emitterAge: Double): ParticleEmitterAction {
|
override fun getAction(runtime: MoLangRuntime, started: Boolean, emitterAge: Double): ParticleEmitterAction {
|
||||||
return if (emitterAge > runtime.resolveDouble(activeTime)) {
|
val activeTime = runtime.resolve(activeTime)
|
||||||
|
runtime.environment.setSimpleVariable("emitter_lifetime", activeTime)
|
||||||
|
return if (emitterAge > activeTime.asDouble()) {
|
||||||
ParticleEmitterAction.STOP
|
ParticleEmitterAction.STOP
|
||||||
} else {
|
} else {
|
||||||
ParticleEmitterAction.GO
|
ParticleEmitterAction.GO
|
||||||
@@ -127,11 +130,13 @@ class LoopingEmitterLifetime(var activeTime: Expression = 1.0.asExpression(), va
|
|||||||
override val type = ParticleEmitterLifetimeType.LOOPING
|
override val type = ParticleEmitterLifetimeType.LOOPING
|
||||||
|
|
||||||
override fun getAction(runtime: MoLangRuntime, started: Boolean, emitterAge: Double): ParticleEmitterAction {
|
override fun getAction(runtime: MoLangRuntime, started: Boolean, emitterAge: Double): ParticleEmitterAction {
|
||||||
val activeTime = runtime.resolveDouble(activeTime)
|
val activeTime = runtime.resolve(activeTime)
|
||||||
|
val activeTimeValue = activeTime.asDouble()
|
||||||
val sleepTime = runtime.resolveDouble(sleepTime)
|
val sleepTime = runtime.resolveDouble(sleepTime)
|
||||||
val interval = activeTime + sleepTime
|
val interval = activeTimeValue + sleepTime
|
||||||
val displacement = emitterAge % interval
|
val displacement = emitterAge % interval
|
||||||
return if (displacement < activeTime) {
|
runtime.environment.setSimpleVariable("emitter_lifetime", activeTime)
|
||||||
|
return if (displacement < activeTimeValue) {
|
||||||
ParticleEmitterAction.GO
|
ParticleEmitterAction.GO
|
||||||
} else {
|
} else {
|
||||||
ParticleEmitterAction.RESET
|
ParticleEmitterAction.RESET
|
||||||
@@ -145,7 +150,6 @@ class LoopingEmitterLifetime(var activeTime: Expression = 1.0.asExpression(), va
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun writeToBuffer(buffer: PacketByteBuf) {
|
override fun writeToBuffer(buffer: PacketByteBuf) {
|
||||||
val activeTimeString =
|
|
||||||
buffer.writeString(activeTime.getString())
|
buffer.writeString(activeTime.getString())
|
||||||
buffer.writeString(sleepTime.getString())
|
buffer.writeString(sleepTime.getString())
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-14
@@ -9,7 +9,6 @@
|
|||||||
package com.cobblemon.mod.common.api.snowstorm
|
package com.cobblemon.mod.common.api.snowstorm
|
||||||
|
|
||||||
import com.bedrockk.molang.Expression
|
import com.bedrockk.molang.Expression
|
||||||
import com.bedrockk.molang.MoLang
|
|
||||||
import com.bedrockk.molang.ast.NumberExpression
|
import com.bedrockk.molang.ast.NumberExpression
|
||||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||||
import com.bedrockk.molang.runtime.struct.VariableStruct
|
import com.bedrockk.molang.runtime.struct.VariableStruct
|
||||||
@@ -17,9 +16,11 @@ import com.bedrockk.molang.runtime.value.DoubleValue
|
|||||||
import com.cobblemon.mod.common.api.codec.CodecMapped
|
import com.cobblemon.mod.common.api.codec.CodecMapped
|
||||||
import com.cobblemon.mod.common.api.data.ArbitrarilyMappedSerializableCompanion
|
import com.cobblemon.mod.common.api.data.ArbitrarilyMappedSerializableCompanion
|
||||||
import com.cobblemon.mod.common.api.snowstorm.ParticleEmitterRate.Companion.OVERFLOW_VARIABLE
|
import com.cobblemon.mod.common.api.snowstorm.ParticleEmitterRate.Companion.OVERFLOW_VARIABLE
|
||||||
|
import com.cobblemon.mod.common.util.asExpression
|
||||||
import com.cobblemon.mod.common.util.codec.EXPRESSION_CODEC
|
import com.cobblemon.mod.common.util.codec.EXPRESSION_CODEC
|
||||||
import com.cobblemon.mod.common.util.getString
|
import com.cobblemon.mod.common.util.getString
|
||||||
import com.cobblemon.mod.common.util.resolveDouble
|
import com.cobblemon.mod.common.util.resolveDouble
|
||||||
|
import com.cobblemon.mod.common.util.resolveInt
|
||||||
import com.mojang.serialization.Codec
|
import com.mojang.serialization.Codec
|
||||||
import com.mojang.serialization.DynamicOps
|
import com.mojang.serialization.DynamicOps
|
||||||
import com.mojang.serialization.codecs.PrimitiveCodec
|
import com.mojang.serialization.codecs.PrimitiveCodec
|
||||||
@@ -49,12 +50,12 @@ enum class ParticleEmitterRateType {
|
|||||||
INSTANT
|
INSTANT
|
||||||
}
|
}
|
||||||
|
|
||||||
class InstantParticleEmitterRate(var amount: Int = 1) : ParticleEmitterRate {
|
class InstantParticleEmitterRate(var amount: Expression = "1".asExpression()) : ParticleEmitterRate {
|
||||||
companion object {
|
companion object {
|
||||||
val CODEC: Codec<InstantParticleEmitterRate> = RecordCodecBuilder.create { instance ->
|
val CODEC: Codec<InstantParticleEmitterRate> = RecordCodecBuilder.create { instance ->
|
||||||
instance.group(
|
instance.group(
|
||||||
PrimitiveCodec.STRING.fieldOf("type").forGetter { it.type.name },
|
PrimitiveCodec.STRING.fieldOf("type").forGetter { it.type.name },
|
||||||
PrimitiveCodec.INT.fieldOf("amount").forGetter { it.amount }
|
EXPRESSION_CODEC.fieldOf("amount").forGetter { it.amount }
|
||||||
).apply(instance) { _, amount -> InstantParticleEmitterRate(amount) }
|
).apply(instance) { _, amount -> InstantParticleEmitterRate(amount) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -65,17 +66,17 @@ class InstantParticleEmitterRate(var amount: Int = 1) : ParticleEmitterRate {
|
|||||||
if (started) {
|
if (started) {
|
||||||
return 0
|
return 0
|
||||||
} else {
|
} else {
|
||||||
return amount
|
return runtime.resolveInt(amount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
||||||
override fun readFromBuffer(buffer: PacketByteBuf) {
|
override fun readFromBuffer(buffer: PacketByteBuf) {
|
||||||
amount = buffer.readInt()
|
amount = buffer.readString().asExpression()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun writeToBuffer(buffer: PacketByteBuf) {
|
override fun writeToBuffer(buffer: PacketByteBuf) {
|
||||||
buffer.writeInt(amount)
|
buffer.writeString(amount.getString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,29 +100,38 @@ class SteadyParticleEmitterRate(
|
|||||||
override val type = ParticleEmitterRateType.STEADY
|
override val type = ParticleEmitterRateType.STEADY
|
||||||
|
|
||||||
override fun getEmitCount(runtime: MoLangRuntime, started: Boolean, currentlyActive: Int): Int {
|
override fun getEmitCount(runtime: MoLangRuntime, started: Boolean, currentlyActive: Int): Int {
|
||||||
|
// The emitting rates are all per second, but this runs every tick. Presents some difficulties.
|
||||||
|
|
||||||
val max = runtime.resolveDouble(maximum).toInt()
|
val max = runtime.resolveDouble(maximum).toInt()
|
||||||
val variables = runtime.environment.structs["variable"] as VariableStruct
|
val variables = runtime.environment.structs["variable"] as VariableStruct
|
||||||
var currentOverflow = variables.map[OVERFLOW_VARIABLE]?.asDouble() ?: 0.0
|
|
||||||
|
/*
|
||||||
|
* The strategy is that per tick it might be calculated to be 1.2 particles. We can't spawn a fifth
|
||||||
|
* of a particle, so we consider the .2 to be overflow which will be added to the next total. If the
|
||||||
|
* next tick we end up with 1.9, the overflow from last time will bring it to 2.1, so 2 particles with
|
||||||
|
* 0.1 overflow for the next tick.
|
||||||
|
*/
|
||||||
|
|
||||||
|
val currentOverflow = variables.map[OVERFLOW_VARIABLE]?.asDouble() ?: 0.0
|
||||||
if (currentlyActive >= max) {
|
if (currentlyActive >= max) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
val perSecond = runtime.resolveDouble(rate)
|
val perSecond = runtime.resolveDouble(rate)
|
||||||
|
|
||||||
val trySpawn = perSecond / 20.0 + currentOverflow
|
val trySpawn = perSecond / 20.0 + currentOverflow
|
||||||
|
|
||||||
val intComponent = trySpawn.toInt()
|
val intComponent = trySpawn.toInt() // round down
|
||||||
val doubleComponent = trySpawn - intComponent
|
val doubleComponent = trySpawn - intComponent // decimal portion (the overflow)
|
||||||
|
|
||||||
currentOverflow = doubleComponent
|
variables.map[OVERFLOW_VARIABLE] = DoubleValue(doubleComponent)
|
||||||
|
|
||||||
variables.map[OVERFLOW_VARIABLE] = DoubleValue(currentOverflow)
|
|
||||||
return min(intComponent, max - currentlyActive)
|
return min(intComponent, max - currentlyActive)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
||||||
override fun readFromBuffer(buffer: PacketByteBuf) {
|
override fun readFromBuffer(buffer: PacketByteBuf) {
|
||||||
rate = MoLang.createParser(buffer.readString()).parseExpression()
|
rate = buffer.readString().asExpression()
|
||||||
maximum = MoLang.createParser(buffer.readString()).parseExpression()
|
maximum = buffer.readString().asExpression()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun writeToBuffer(buffer: PacketByteBuf) {
|
override fun writeToBuffer(buffer: PacketByteBuf) {
|
||||||
|
|||||||
@@ -11,5 +11,6 @@ package com.cobblemon.mod.common.api.snowstorm
|
|||||||
enum class ParticleMaterial {
|
enum class ParticleMaterial {
|
||||||
ALPHA,
|
ALPHA,
|
||||||
OPAQUE,
|
OPAQUE,
|
||||||
BLEND
|
BLEND,
|
||||||
|
ADD
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* 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.snowstorm
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.client.render.shader.CobblemonShaders
|
||||||
|
import com.mojang.blaze3d.platform.GlStateManager
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem
|
||||||
|
import net.minecraft.client.particle.ParticleTextureSheet
|
||||||
|
import net.minecraft.client.render.*
|
||||||
|
import net.minecraft.client.texture.SpriteAtlasTexture
|
||||||
|
import net.minecraft.client.texture.TextureManager
|
||||||
|
|
||||||
|
object ParticleMaterials {
|
||||||
|
|
||||||
|
val ALPHA = object : ParticleTextureSheet {
|
||||||
|
override fun begin(builder: BufferBuilder, textureManager: TextureManager) {
|
||||||
|
RenderSystem.disableBlend()
|
||||||
|
RenderSystem.depthMask(true)
|
||||||
|
RenderSystem.setShader { CobblemonShaders.PARTICLE_CUTOUT }
|
||||||
|
RenderSystem.setShaderTexture(0, SpriteAtlasTexture.PARTICLE_ATLAS_TEXTURE)
|
||||||
|
|
||||||
|
|
||||||
|
builder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR_LIGHT)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun draw(tessellator: Tessellator) {
|
||||||
|
tessellator.draw()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "ALPHA"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val ADD = object : ParticleTextureSheet {
|
||||||
|
override fun begin(builder: BufferBuilder, textureManager: TextureManager) {
|
||||||
|
RenderSystem.enableBlend()
|
||||||
|
RenderSystem.depthMask(true)
|
||||||
|
RenderSystem.setShader { CobblemonShaders.PARTICLE_BLEND }
|
||||||
|
RenderSystem.setShaderTexture(0, SpriteAtlasTexture.PARTICLE_ATLAS_TEXTURE)
|
||||||
|
|
||||||
|
RenderSystem.blendFunc(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE_MINUS_SRC_ALPHA)
|
||||||
|
|
||||||
|
builder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR_LIGHT)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun draw(tessellator: Tessellator) {
|
||||||
|
tessellator.draw()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "ADD"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val BLEND = object : ParticleTextureSheet {
|
||||||
|
override fun begin(builder: BufferBuilder, textureManager: TextureManager) {
|
||||||
|
RenderSystem.enableBlend()
|
||||||
|
RenderSystem.depthMask(true)
|
||||||
|
RenderSystem.setShader { CobblemonShaders.PARTICLE_BLEND }
|
||||||
|
RenderSystem.setShaderTexture(0, SpriteAtlasTexture.PARTICLE_ATLAS_TEXTURE)
|
||||||
|
|
||||||
|
RenderSystem.blendFunc(GlStateManager.SrcFactor.DST_COLOR, GlStateManager.DstFactor.ZERO)
|
||||||
|
|
||||||
|
builder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR_LIGHT)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun draw(tessellator: Tessellator) {
|
||||||
|
tessellator.draw()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "BLEND"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val OPAQUE = object : ParticleTextureSheet {
|
||||||
|
override fun begin(builder: BufferBuilder, textureManager: TextureManager) {
|
||||||
|
RenderSystem.enableBlend()
|
||||||
|
RenderSystem.depthMask(true)
|
||||||
|
RenderSystem.setShader { CobblemonShaders.PARTICLE_BLEND }
|
||||||
|
RenderSystem.setShaderTexture(0, SpriteAtlasTexture.PARTICLE_ATLAS_TEXTURE)
|
||||||
|
|
||||||
|
RenderSystem.blendFunc(GlStateManager.SrcFactor.ONE, GlStateManager.DstFactor.ONE)
|
||||||
|
|
||||||
|
builder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR_LIGHT)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun draw(tessellator: Tessellator) {
|
||||||
|
tessellator.draw()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "OPAQUE"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,8 +14,10 @@ import com.bedrockk.molang.ast.NumberExpression
|
|||||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||||
import com.cobblemon.mod.common.api.codec.CodecMapped
|
import com.cobblemon.mod.common.api.codec.CodecMapped
|
||||||
import com.cobblemon.mod.common.api.data.ArbitrarilyMappedSerializableCompanion
|
import com.cobblemon.mod.common.api.data.ArbitrarilyMappedSerializableCompanion
|
||||||
|
import com.cobblemon.mod.common.client.particle.ParticleStorm
|
||||||
import com.cobblemon.mod.common.util.codec.EXPRESSION_CODEC
|
import com.cobblemon.mod.common.util.codec.EXPRESSION_CODEC
|
||||||
import com.cobblemon.mod.common.util.getString
|
import com.cobblemon.mod.common.util.getString
|
||||||
|
import com.cobblemon.mod.common.util.math.geometry.transformDirection
|
||||||
import com.cobblemon.mod.common.util.resolveDouble
|
import com.cobblemon.mod.common.util.resolveDouble
|
||||||
import com.mojang.serialization.Codec
|
import com.mojang.serialization.Codec
|
||||||
import com.mojang.serialization.DynamicOps
|
import com.mojang.serialization.DynamicOps
|
||||||
@@ -37,7 +39,7 @@ interface ParticleMotion : CodecMapped {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val type: ParticleMotionType
|
val type: ParticleMotionType
|
||||||
fun getInitialVelocity(runtime: MoLangRuntime, particlePos: Vec3d, emitterPos: Vec3d): Vec3d
|
fun getInitialVelocity(runtime: MoLangRuntime, storm: ParticleStorm, particlePos: Vec3d, emitterPos: Vec3d): Vec3d
|
||||||
fun getAcceleration(runtime: MoLangRuntime, velocity: Vec3d): Vec3d
|
fun getAcceleration(runtime: MoLangRuntime, velocity: Vec3d): Vec3d
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,8 +75,8 @@ class DynamicParticleMotion(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getInitialVelocity(runtime: MoLangRuntime, particlePos: Vec3d, emitterPos: Vec3d): Vec3d {
|
override fun getInitialVelocity(runtime: MoLangRuntime, storm: ParticleStorm, particlePos: Vec3d, emitterPos: Vec3d): Vec3d {
|
||||||
return direction.getDirectionVector(runtime, emitterPos, particlePos).multiply(runtime.resolveDouble(speed))
|
return direction.getDirectionVector(runtime, storm, emitterPos, particlePos).normalize().multiply(runtime.resolveDouble(speed))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getAcceleration(runtime: MoLangRuntime, velocity: Vec3d): Vec3d {
|
override fun getAcceleration(runtime: MoLangRuntime, velocity: Vec3d): Vec3d {
|
||||||
@@ -82,7 +84,7 @@ class DynamicParticleMotion(
|
|||||||
runtime.resolveDouble(acceleration.first),
|
runtime.resolveDouble(acceleration.first),
|
||||||
runtime.resolveDouble(acceleration.second),
|
runtime.resolveDouble(acceleration.second),
|
||||||
runtime.resolveDouble(acceleration.third)
|
runtime.resolveDouble(acceleration.third)
|
||||||
).subtract(velocity.multiply(runtime.resolveDouble(drag) / 20)/* Drag is measured in blocks per tick per tick, I know it sounds dumb. */)
|
).subtract(velocity.multiply(runtime.resolveDouble(drag)))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
||||||
@@ -122,7 +124,7 @@ interface ParticleMotionDirection : CodecMapped {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
val type: ParticleMotionDirectionType
|
val type: ParticleMotionDirectionType
|
||||||
fun getDirectionVector(runtime: MoLangRuntime, emitterPos: Vec3d, particlePos: Vec3d): Vec3d
|
fun getDirectionVector(runtime: MoLangRuntime, storm: ParticleStorm, emitterPos: Vec3d, particlePos: Vec3d): Vec3d
|
||||||
}
|
}
|
||||||
|
|
||||||
class InwardsMotionDirection : ParticleMotionDirection {
|
class InwardsMotionDirection : ParticleMotionDirection {
|
||||||
@@ -134,7 +136,13 @@ class InwardsMotionDirection : ParticleMotionDirection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override val type = ParticleMotionDirectionType.INWARDS
|
override val type = ParticleMotionDirectionType.INWARDS
|
||||||
override fun getDirectionVector(runtime: MoLangRuntime, emitterPos: Vec3d, particlePos: Vec3d) = emitterPos.subtract(particlePos).normalize()
|
override fun getDirectionVector(runtime: MoLangRuntime, storm: ParticleStorm, emitterPos: Vec3d, particlePos: Vec3d): Vec3d {
|
||||||
|
return if (particlePos == emitterPos) {
|
||||||
|
Vec3d(storm.world.random.nextDouble() - 0.5, storm.world.random.nextDouble() - 0.5, storm.world.random.nextDouble() - 0.5)
|
||||||
|
} else {
|
||||||
|
particlePos.subtract(emitterPos)
|
||||||
|
}.normalize()
|
||||||
|
}
|
||||||
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
||||||
override fun readFromBuffer(buffer: PacketByteBuf) {}
|
override fun readFromBuffer(buffer: PacketByteBuf) {}
|
||||||
override fun writeToBuffer(buffer: PacketByteBuf) {}
|
override fun writeToBuffer(buffer: PacketByteBuf) {}
|
||||||
@@ -149,8 +157,12 @@ class OutwardsMotionDirection : ParticleMotionDirection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override val type = ParticleMotionDirectionType.OUTWARDS
|
override val type = ParticleMotionDirectionType.OUTWARDS
|
||||||
override fun getDirectionVector(runtime: MoLangRuntime, emitterPos: Vec3d, particlePos: Vec3d): Vec3d {
|
override fun getDirectionVector(runtime: MoLangRuntime, storm: ParticleStorm, emitterPos: Vec3d, particlePos: Vec3d): Vec3d {
|
||||||
return particlePos.subtract(emitterPos).normalize()
|
return if (particlePos == emitterPos) {
|
||||||
|
Vec3d(storm.world.random.nextDouble() - 0.5, storm.world.random.nextDouble() - 0.5, storm.world.random.nextDouble() - 0.5)
|
||||||
|
} else {
|
||||||
|
particlePos.subtract(emitterPos)
|
||||||
|
}.normalize()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
||||||
@@ -178,12 +190,13 @@ class CustomMotionDirection(
|
|||||||
|
|
||||||
override val type = ParticleMotionDirectionType.CUSTOM
|
override val type = ParticleMotionDirectionType.CUSTOM
|
||||||
|
|
||||||
override fun getDirectionVector(runtime: MoLangRuntime, emitterPos: Vec3d, particlePos: Vec3d): Vec3d {
|
override fun getDirectionVector(runtime: MoLangRuntime, storm: ParticleStorm, emitterPos: Vec3d, particlePos: Vec3d): Vec3d {
|
||||||
return Vec3d(
|
val v = Vec3d(
|
||||||
runtime.resolveDouble(direction.first),
|
runtime.resolveDouble(direction.first),
|
||||||
runtime.resolveDouble(direction.second),
|
runtime.resolveDouble(direction.second),
|
||||||
runtime.resolveDouble(direction.third)
|
runtime.resolveDouble(direction.third)
|
||||||
)
|
)
|
||||||
|
return storm.matrixWrapper.matrix.transformDirection(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
||||||
@@ -220,7 +233,7 @@ class StaticParticleMotion : ParticleMotion {
|
|||||||
@Transient
|
@Transient
|
||||||
override val type = ParticleMotionType.STATIC
|
override val type = ParticleMotionType.STATIC
|
||||||
|
|
||||||
override fun getInitialVelocity(runtime: MoLangRuntime, particlePos: Vec3d, emitterPos: Vec3d) = Vec3d.ZERO
|
override fun getInitialVelocity(runtime: MoLangRuntime, storm: ParticleStorm, particlePos: Vec3d, emitterPos: Vec3d) = Vec3d.ZERO
|
||||||
override fun getAcceleration(runtime: MoLangRuntime, velocity: Vec3d) = Vec3d.ZERO
|
override fun getAcceleration(runtime: MoLangRuntime, velocity: Vec3d) = Vec3d.ZERO
|
||||||
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
||||||
override fun readFromBuffer(buffer: PacketByteBuf) {}
|
override fun readFromBuffer(buffer: PacketByteBuf) {}
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ class ParticleSpace(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val isLocalSpace: Boolean
|
||||||
|
get() = localPosition || localRotation
|
||||||
|
|
||||||
fun readFromBuffer(buffer: PacketByteBuf) {
|
fun readFromBuffer(buffer: PacketByteBuf) {
|
||||||
localPosition = buffer.readBoolean()
|
localPosition = buffer.readBoolean()
|
||||||
localRotation = buffer.readBoolean()
|
localRotation = buffer.readBoolean()
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ class AnimatedParticleUVMode(
|
|||||||
} else {
|
} else {
|
||||||
val fps = runtime.resolveDouble(fps)
|
val fps = runtime.resolveDouble(fps)
|
||||||
val effectiveFrame = ((age * fps) % maxFrame).toInt()
|
val effectiveFrame = ((age * fps) % maxFrame).toInt()
|
||||||
val frame = if (!loop && age * fps > maxFrame) {
|
val frame = if (!loop && age * fps >= maxFrame) {
|
||||||
maxFrame
|
maxFrame
|
||||||
} else {
|
} else {
|
||||||
effectiveFrame
|
effectiveFrame
|
||||||
|
|||||||
+1
-5
@@ -9,17 +9,13 @@
|
|||||||
package com.cobblemon.mod.common.api.snowstorm
|
package com.cobblemon.mod.common.api.snowstorm
|
||||||
|
|
||||||
import com.bedrockk.molang.Expression
|
import com.bedrockk.molang.Expression
|
||||||
import com.bedrockk.molang.MoLang
|
|
||||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||||
import com.cobblemon.mod.common.api.codec.CodecMapped
|
import com.cobblemon.mod.common.api.codec.CodecMapped
|
||||||
import com.cobblemon.mod.common.api.data.ArbitrarilyMappedSerializableCompanion
|
import com.cobblemon.mod.common.api.data.ArbitrarilyMappedSerializableCompanion
|
||||||
import com.cobblemon.mod.common.util.asExpression
|
import com.cobblemon.mod.common.util.asExpression
|
||||||
import com.cobblemon.mod.common.util.codec.EXPRESSION_CODEC
|
import com.cobblemon.mod.common.util.codec.EXPRESSION_CODEC
|
||||||
import com.cobblemon.mod.common.util.getString
|
import com.cobblemon.mod.common.util.getString
|
||||||
import com.cobblemon.mod.common.util.readVec3d
|
|
||||||
import com.cobblemon.mod.common.util.resolveDouble
|
|
||||||
import com.cobblemon.mod.common.util.resolveVec3d
|
import com.cobblemon.mod.common.util.resolveVec3d
|
||||||
import com.cobblemon.mod.common.util.writeVec3d
|
|
||||||
import com.mojang.serialization.Codec
|
import com.mojang.serialization.Codec
|
||||||
import com.mojang.serialization.DynamicOps
|
import com.mojang.serialization.DynamicOps
|
||||||
import com.mojang.serialization.codecs.PrimitiveCodec
|
import com.mojang.serialization.codecs.PrimitiveCodec
|
||||||
@@ -70,7 +66,7 @@ class FromMotionViewDirection(var minSpeed: Double = 0.01) : ParticleViewDirecti
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getDirection(runtime: MoLangRuntime, lastDirection: Vec3d, currentVelocity: Vec3d): Vec3d {
|
override fun getDirection(runtime: MoLangRuntime, lastDirection: Vec3d, currentVelocity: Vec3d): Vec3d {
|
||||||
return if (currentVelocity.length() / 20 >= minSpeed) {
|
return if (currentVelocity.length() * 20 >= minSpeed) {
|
||||||
currentVelocity.normalize()
|
currentVelocity.normalize()
|
||||||
} else {
|
} else {
|
||||||
lastDirection
|
lastDirection
|
||||||
|
|||||||
@@ -10,21 +10,8 @@ package com.cobblemon.mod.common.api.spawning
|
|||||||
|
|
||||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||||
import com.cobblemon.mod.common.api.entity.Despawner
|
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.*
|
||||||
import com.cobblemon.mod.common.api.spawning.condition.BasicSpawningCondition
|
import com.cobblemon.mod.common.api.spawning.context.*
|
||||||
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
|
|
||||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
|
||||||
import com.cobblemon.mod.common.api.spawning.context.SubmergedSpawningContext
|
|
||||||
import com.cobblemon.mod.common.api.spawning.context.SurfaceSpawningContext
|
|
||||||
import com.cobblemon.mod.common.api.spawning.context.calculators.GroundedSpawningContextCalculator
|
import com.cobblemon.mod.common.api.spawning.context.calculators.GroundedSpawningContextCalculator
|
||||||
import com.cobblemon.mod.common.api.spawning.context.calculators.LavafloorSpawningContextCalculator
|
import com.cobblemon.mod.common.api.spawning.context.calculators.LavafloorSpawningContextCalculator
|
||||||
import com.cobblemon.mod.common.api.spawning.context.calculators.SeafloorSpawningContextCalculator
|
import com.cobblemon.mod.common.api.spawning.context.calculators.SeafloorSpawningContextCalculator
|
||||||
@@ -34,6 +21,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.PokemonSpawnDetail
|
||||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
|
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.detail.SpawnDetail
|
||||||
|
import com.cobblemon.mod.common.api.spawning.fallingstar.FallingStarSpawner
|
||||||
import com.cobblemon.mod.common.api.spawning.fishing.FishingSpawner
|
import com.cobblemon.mod.common.api.spawning.fishing.FishingSpawner
|
||||||
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
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.BasicSpawnDetailPreset
|
||||||
@@ -87,6 +75,7 @@ object BestSpawner {
|
|||||||
val spawnerManagers = mutableListOf<SpawnerManager>(CobblemonWorldSpawnerManager)
|
val spawnerManagers = mutableListOf<SpawnerManager>(CobblemonWorldSpawnerManager)
|
||||||
var defaultPokemonDespawner: Despawner<PokemonEntity> = CobblemonAgingDespawner(getAgeTicks = { it.ticksLived })
|
var defaultPokemonDespawner: Despawner<PokemonEntity> = CobblemonAgingDespawner(getAgeTicks = { it.ticksLived })
|
||||||
lateinit var fishingSpawner: FishingSpawner
|
lateinit var fishingSpawner: FishingSpawner
|
||||||
|
lateinit var starSpawner: FallingStarSpawner
|
||||||
|
|
||||||
fun loadConfig() {
|
fun loadConfig() {
|
||||||
LOGGER.info("Starting the Best Spawner...")
|
LOGGER.info("Starting the Best Spawner...")
|
||||||
@@ -96,6 +85,7 @@ object BestSpawner {
|
|||||||
SpawningCondition.register(GroundedSpawningCondition.NAME, GroundedSpawningCondition::class.java)
|
SpawningCondition.register(GroundedSpawningCondition.NAME, GroundedSpawningCondition::class.java)
|
||||||
SpawningCondition.register(SurfaceSpawningCondition.NAME, SurfaceSpawningCondition::class.java)
|
SpawningCondition.register(SurfaceSpawningCondition.NAME, SurfaceSpawningCondition::class.java)
|
||||||
SpawningCondition.register(FishingSpawningCondition.NAME, FishingSpawningCondition::class.java)
|
SpawningCondition.register(FishingSpawningCondition.NAME, FishingSpawningCondition::class.java)
|
||||||
|
SpawningCondition.register(FallingStarSpawningCondition.NAME, FallingStarSpawningCondition::class.java)
|
||||||
|
|
||||||
LOGGER.info("Loaded ${SpawningCondition.conditionTypes.size} spawning condition types.")
|
LOGGER.info("Loaded ${SpawningCondition.conditionTypes.size} spawning condition types.")
|
||||||
SpawningContextCalculator.register(GroundedSpawningContextCalculator)
|
SpawningContextCalculator.register(GroundedSpawningContextCalculator)
|
||||||
@@ -110,6 +100,7 @@ object BestSpawner {
|
|||||||
SpawningContext.register(name = "submerged", clazz = SubmergedSpawningContext::class.java, defaultCondition = SubmergedSpawningCondition.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 = "surface", clazz = SurfaceSpawningContext::class.java, defaultCondition = SurfaceSpawningCondition.NAME)
|
||||||
SpawningContext.register(name = "fishing", clazz = FishingSpawningContext::class.java, defaultCondition = FishingSpawningCondition.NAME)
|
SpawningContext.register(name = "fishing", clazz = FishingSpawningContext::class.java, defaultCondition = FishingSpawningCondition.NAME)
|
||||||
|
SpawningContext.register(name = "fallingstar", clazz = FallingStarSpawningContext::class.java, defaultCondition = FallingStarSpawningCondition.NAME)
|
||||||
|
|
||||||
LOGGER.info("Loaded ${SpawningContext.contexts.size} spawning context types.")
|
LOGGER.info("Loaded ${SpawningContext.contexts.size} spawning context types.")
|
||||||
|
|
||||||
@@ -125,5 +116,6 @@ object BestSpawner {
|
|||||||
fun onServerStarted() {
|
fun onServerStarted() {
|
||||||
spawnerManagers.forEach(SpawnerManager::onServerStarted)
|
spawnerManagers.forEach(SpawnerManager::onServerStarted)
|
||||||
fishingSpawner = FishingSpawner()
|
fishingSpawner = FishingSpawner()
|
||||||
|
starSpawner = FallingStarSpawner()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Cobblemon Contributors
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.cobblemon.mod.common.api.spawning.condition
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.api.spawning.context.FallingStarSpawningContext
|
||||||
|
|
||||||
|
class FallingStarSpawningCondition: SpawningCondition<FallingStarSpawningContext>() {
|
||||||
|
override fun contextClass() = FallingStarSpawningContext::class.java
|
||||||
|
|
||||||
|
override fun fits(ctx: FallingStarSpawningContext): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val NAME = "fallingstar"
|
||||||
|
}
|
||||||
|
}
|
||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Cobblemon Contributors
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.cobblemon.mod.common.api.spawning.context
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.api.spawning.fallingstar.FallingStarSpawnCause
|
||||||
|
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
||||||
|
import net.minecraft.server.world.ServerWorld
|
||||||
|
import net.minecraft.util.math.BlockPos
|
||||||
|
|
||||||
|
class FallingStarSpawningContext(
|
||||||
|
cause: FallingStarSpawnCause,
|
||||||
|
world: ServerWorld,
|
||||||
|
pos: BlockPos,
|
||||||
|
influences: MutableList<SpawningInfluence>
|
||||||
|
) : TriggerSpawningContext(
|
||||||
|
cause = cause,
|
||||||
|
world = world,
|
||||||
|
position = pos,
|
||||||
|
light = world.getLightLevel(pos),
|
||||||
|
skyLight = world.getLightLevel(pos.up()),
|
||||||
|
canSeeSky = world.isSkyVisibleAllowingSea(pos),
|
||||||
|
influences = influences
|
||||||
|
) {
|
||||||
|
|
||||||
|
}
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Cobblemon Contributors
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.cobblemon.mod.common.api.spawning.fallingstar
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||||
|
import com.cobblemon.mod.common.api.spawning.SpawnCause
|
||||||
|
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
|
||||||
|
import net.minecraft.entity.Entity
|
||||||
|
|
||||||
|
class FallingStarSpawnCause(
|
||||||
|
spawner: Spawner,
|
||||||
|
bucket: SpawnBucket,
|
||||||
|
entity: Entity?
|
||||||
|
) : SpawnCause(spawner, bucket, entity)
|
||||||
+25
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Cobblemon Contributors
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.cobblemon.mod.common.api.spawning.fallingstar
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnPools
|
||||||
|
import com.cobblemon.mod.common.api.spawning.context.FallingStarSpawningContext
|
||||||
|
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
|
||||||
|
import com.cobblemon.mod.common.api.spawning.spawner.TriggerSpawner
|
||||||
|
import net.minecraft.server.world.ServerWorld
|
||||||
|
import net.minecraft.util.math.BlockPos
|
||||||
|
|
||||||
|
open class FallingStarSpawner(
|
||||||
|
override val name: String = "fallingstar",
|
||||||
|
pool: SpawnPool = CobblemonSpawnPools.WORLD_SPAWN_POOL
|
||||||
|
) : TriggerSpawner<FallingStarSpawnCause>(name, pool) {
|
||||||
|
override fun parseContext(cause: FallingStarSpawnCause, world: ServerWorld, pos: BlockPos): FallingStarSpawningContext? {
|
||||||
|
return FallingStarSpawningContext(cause, world, pos, influences)
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-2
@@ -32,11 +32,10 @@ open class NBTStoreAdapter(
|
|||||||
override fun save(file: File, serialized: NbtCompound) = NbtIo.writeCompressed(serialized, file)
|
override fun save(file: File, serialized: NbtCompound) = NbtIo.writeCompressed(serialized, file)
|
||||||
override fun <E, T : PokemonStore<E>> load(file: File, storeClass: Class<out T>, uuid: UUID): T? {
|
override fun <E, T : PokemonStore<E>> load(file: File, storeClass: Class<out T>, uuid: UUID): T? {
|
||||||
val store = try {
|
val store = try {
|
||||||
storeClass.getConstructor(UUID::class.java, UUID::class.java).newInstance(uuid, uuid)
|
storeClass.getConstructor(UUID::class.java).newInstance(uuid)
|
||||||
} catch (exception: NoSuchMethodException) {
|
} catch (exception: NoSuchMethodException) {
|
||||||
storeClass.getConstructor(UUID::class.java).newInstance(uuid)
|
storeClass.getConstructor(UUID::class.java).newInstance(uuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
val nbt = NbtIo.readCompressed(file)
|
val nbt = NbtIo.readCompressed(file)
|
||||||
store.loadFromNBT(nbt)
|
store.loadFromNBT(nbt)
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ open class PlayerPartyStore(
|
|||||||
|
|
||||||
private var secondsSinceFriendshipUpdate = 0
|
private var secondsSinceFriendshipUpdate = 0
|
||||||
|
|
||||||
|
constructor(playerUUID: UUID): this(playerUUID, playerUUID)
|
||||||
|
|
||||||
override fun initialize() {
|
override fun initialize() {
|
||||||
super.initialize()
|
super.initialize()
|
||||||
observerUUIDs.add(playerUUID)
|
observerUUIDs.add(playerUUID)
|
||||||
|
|||||||
@@ -148,6 +148,8 @@ object CobblemonBiomeTags {
|
|||||||
@JvmField
|
@JvmField
|
||||||
val HAS_FIRE_STONE_ORE_RARE = create("has_ore/ore_fire_stone_rare")
|
val HAS_FIRE_STONE_ORE_RARE = create("has_ore/ore_fire_stone_rare")
|
||||||
@JvmField
|
@JvmField
|
||||||
|
val HAS_FIRE_STONE_ORE_NETHER = create("has_ore/ore_fire_stone_nether")
|
||||||
|
@JvmField
|
||||||
val HAS_ICE_STONE_ORE = create("has_ore/ore_ice_stone_normal")
|
val HAS_ICE_STONE_ORE = create("has_ore/ore_ice_stone_normal")
|
||||||
@JvmField
|
@JvmField
|
||||||
val HAS_ICE_STONE_ORE_RARE = create("has_ore/ore_ice_stone_rare")
|
val HAS_ICE_STONE_ORE_RARE = create("has_ore/ore_ice_stone_rare")
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ object CobblemonBlockTags {
|
|||||||
@JvmField val SNOW_BLOCK = createTag("snow_block")
|
@JvmField val SNOW_BLOCK = createTag("snow_block")
|
||||||
@JvmField val ROOTS = createTag("roots")
|
@JvmField val ROOTS = createTag("roots")
|
||||||
@JvmField val STANDING_SIGNS = createTag("standing_signs")
|
@JvmField val STANDING_SIGNS = createTag("standing_signs")
|
||||||
|
@JvmField val TUMBLESTONE_HEAT_SOURCE = createTag("tumblestone_heat_source")
|
||||||
@JvmField val WALL_HANGING_SIGNS = createTag("wall_hanging_signs")
|
@JvmField val WALL_HANGING_SIGNS = createTag("wall_hanging_signs")
|
||||||
@JvmField val WALL_SIGNS = createTag("wall_signs")
|
@JvmField val WALL_SIGNS = createTag("wall_signs")
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
package com.cobblemon.mod.common.api.tags
|
package com.cobblemon.mod.common.api.tags
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.CobblemonItems
|
||||||
import com.cobblemon.mod.common.util.cobblemonResource
|
import com.cobblemon.mod.common.util.cobblemonResource
|
||||||
import net.minecraft.registry.Registries
|
import net.minecraft.registry.Registries
|
||||||
import net.minecraft.registry.RegistryKeys
|
import net.minecraft.registry.RegistryKeys
|
||||||
@@ -21,11 +22,12 @@ import net.minecraft.registry.tag.TagKey
|
|||||||
*/
|
*/
|
||||||
@Suppress("unused", "HasPlatformType")
|
@Suppress("unused", "HasPlatformType")
|
||||||
object CobblemonItemTags {
|
object CobblemonItemTags {
|
||||||
|
@JvmField
|
||||||
|
val ANCIENT_POKE_BALLS = create("ancient_poke_balls")
|
||||||
@JvmField
|
@JvmField
|
||||||
val APRICORN_LOGS = create("apricorn_logs")
|
val APRICORN_LOGS = create("apricorn_logs")
|
||||||
@JvmField
|
@JvmField
|
||||||
val APRICORN_SEEDS = create("apricorn_seeds")
|
val APRICORN_SPROUTS = create("apricorn_sprouts")
|
||||||
@JvmField
|
@JvmField
|
||||||
val APRICORNS = create("apricorns")
|
val APRICORNS = create("apricorns")
|
||||||
/**
|
/**
|
||||||
@@ -40,6 +42,15 @@ object CobblemonItemTags {
|
|||||||
val BOATS = create("boats")
|
val BOATS = create("boats")
|
||||||
@JvmField
|
@JvmField
|
||||||
val COBBLEMON_SEEDS = create("cobblemon_seeds")
|
val COBBLEMON_SEEDS = create("cobblemon_seeds")
|
||||||
|
/**
|
||||||
|
* This tag is used for Fossil Machine natural materials
|
||||||
|
*/
|
||||||
|
@JvmField
|
||||||
|
val COOKED_MEAT = create("cooked_meat")
|
||||||
|
@JvmField
|
||||||
|
val DAWN_STONE_ORES = create("dawn_stone_ores")
|
||||||
|
@JvmField
|
||||||
|
val DUSK_STONE_ORES = create("dusk_stone_ores")
|
||||||
@JvmField
|
@JvmField
|
||||||
val EVOLUTION_ITEMS = create("evolution_items")
|
val EVOLUTION_ITEMS = create("evolution_items")
|
||||||
@JvmField
|
@JvmField
|
||||||
@@ -47,27 +58,54 @@ object CobblemonItemTags {
|
|||||||
@JvmField
|
@JvmField
|
||||||
val EXPERIENCE_CANDIES = create("experience_candies")
|
val EXPERIENCE_CANDIES = create("experience_candies")
|
||||||
@JvmField
|
@JvmField
|
||||||
|
val FIRE_STONE_ORES = create("fire_stone_ores")
|
||||||
|
@JvmField
|
||||||
|
val FOSSILS = create("fossils")
|
||||||
|
@JvmField
|
||||||
val HANGING_SIGNS = create("hanging_signs")
|
val HANGING_SIGNS = create("hanging_signs")
|
||||||
@JvmField
|
@JvmField
|
||||||
val HERBS = create("herbs")
|
val HERBS = create("herbs")
|
||||||
@JvmField
|
@JvmField
|
||||||
|
val ICE_STONE_ORES = create("ice_stone_ores")
|
||||||
|
@JvmField
|
||||||
|
val LEAF_STONE_ORES = create("leaf_stone_ores")
|
||||||
|
@JvmField
|
||||||
val MINT_LEAF = create("mint_leaf")
|
val MINT_LEAF = create("mint_leaf")
|
||||||
@JvmField
|
@JvmField
|
||||||
|
val MINT_SEEDS = create("mint_seeds")
|
||||||
|
@JvmField
|
||||||
val MINTS = create("mints")
|
val MINTS = create("mints")
|
||||||
@JvmField
|
@JvmField
|
||||||
|
val MOON_STONE_ORES = create("moon_stone_ores")
|
||||||
|
@JvmField
|
||||||
val MUTATED_BERRIES = create("mutated_berries")
|
val MUTATED_BERRIES = create("mutated_berries")
|
||||||
@JvmField
|
@JvmField
|
||||||
val PLANTS = create("plants")
|
val PLANTS = create("plants")
|
||||||
@JvmField
|
@JvmField
|
||||||
val POKEBALLS = create("poke_balls")
|
val POKE_BALLS = create("poke_balls")
|
||||||
@JvmField
|
@JvmField
|
||||||
val PROTEIN_INGREDIENTS = create("protein_ingredients")
|
val PROTEIN_INGREDIENTS = create("protein_ingredients")
|
||||||
|
/** See [COOKED_MEAT] */
|
||||||
|
@JvmField
|
||||||
|
val RAW_MEAT = create("raw_meat")
|
||||||
@JvmField
|
@JvmField
|
||||||
val SEEDS = create("seeds")
|
val SEEDS = create("seeds")
|
||||||
@JvmField
|
@JvmField
|
||||||
|
val SHINY_STONE_ORES = create("shiny_stone_ores")
|
||||||
|
@JvmField
|
||||||
val SIGNS = create("signs")
|
val SIGNS = create("signs")
|
||||||
@JvmField
|
@JvmField
|
||||||
|
val SUN_STONE_ORES = create("sun_stone_ores")
|
||||||
|
@JvmField
|
||||||
|
val THUNDER_STONE_ORES = create("thunder_stone_ores")
|
||||||
|
@JvmField
|
||||||
|
val TUMBLESTONES = create("tumblestones")
|
||||||
|
@JvmField
|
||||||
|
val WATER_STONE_ORES = create("water_stone_ores")
|
||||||
|
@JvmField
|
||||||
val ZINC_INGREDIENTS = create("zinc_ingredients")
|
val ZINC_INGREDIENTS = create("zinc_ingredients")
|
||||||
|
|
||||||
|
// Held Item Tags
|
||||||
@JvmField
|
@JvmField
|
||||||
val ANY_HELD_ITEM = create("held/is_held_item")
|
val ANY_HELD_ITEM = create("held/is_held_item")
|
||||||
@JvmField
|
@JvmField
|
||||||
@@ -97,6 +135,15 @@ object CobblemonItemTags {
|
|||||||
@JvmField
|
@JvmField
|
||||||
val CONSUMED_IN_WILD_BATTLE = create("held/consumed_in_wild_battle")
|
val CONSUMED_IN_WILD_BATTLE = create("held/consumed_in_wild_battle")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tag that flags items as being able to "create" [CobblemonItems.LEFTOVERS].
|
||||||
|
*/
|
||||||
|
@JvmField
|
||||||
|
val LEAVES_LEFTOVERS = create("held/leaves_leftovers")
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
val POTTERY_SHERDS = create("decorated_pot_sherds")
|
||||||
|
|
||||||
private fun create(path: String) = TagKey.of(RegistryKeys.ITEM, cobblemonResource(path))
|
private fun create(path: String) = TagKey.of(RegistryKeys.ITEM, cobblemonResource(path))
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,11 @@ package com.cobblemon.mod.common.battles
|
|||||||
|
|
||||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||||
import com.cobblemon.mod.common.CobblemonSounds
|
import com.cobblemon.mod.common.CobblemonSounds
|
||||||
import com.cobblemon.mod.common.api.battles.interpreter.*
|
import com.cobblemon.mod.common.api.battles.interpreter.BasicContext
|
||||||
|
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||||
|
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||||
|
import com.cobblemon.mod.common.api.battles.interpreter.Effect
|
||||||
|
import com.cobblemon.mod.common.api.battles.interpreter.MissingContext
|
||||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||||
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
|
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
|
||||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||||
@@ -20,7 +24,11 @@ import com.cobblemon.mod.common.api.events.CobblemonEvents
|
|||||||
import com.cobblemon.mod.common.api.events.battles.BattleVictoryEvent
|
import com.cobblemon.mod.common.api.events.battles.BattleVictoryEvent
|
||||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||||
import com.cobblemon.mod.common.api.text.*
|
import com.cobblemon.mod.common.api.text.gold
|
||||||
|
import com.cobblemon.mod.common.api.text.plus
|
||||||
|
import com.cobblemon.mod.common.api.text.red
|
||||||
|
import com.cobblemon.mod.common.api.text.text
|
||||||
|
import com.cobblemon.mod.common.api.text.yellow
|
||||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||||
import com.cobblemon.mod.common.battles.actor.PlayerBattleActor
|
import com.cobblemon.mod.common.battles.actor.PlayerBattleActor
|
||||||
import com.cobblemon.mod.common.battles.dispatch.BattleDispatch
|
import com.cobblemon.mod.common.battles.dispatch.BattleDispatch
|
||||||
@@ -31,24 +39,46 @@ import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
|||||||
import com.cobblemon.mod.common.battles.dispatch.UntilDispatch
|
import com.cobblemon.mod.common.battles.dispatch.UntilDispatch
|
||||||
import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
|
import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
|
||||||
import com.cobblemon.mod.common.battles.interpreter.ContextManager
|
import com.cobblemon.mod.common.battles.interpreter.ContextManager
|
||||||
import com.cobblemon.mod.common.battles.interpreter.instructions.DamageInstruction
|
import com.cobblemon.mod.common.battles.interpreter.instructions.*
|
||||||
import com.cobblemon.mod.common.battles.interpreter.instructions.DeprecatedInstruction
|
|
||||||
import com.cobblemon.mod.common.battles.interpreter.instructions.DeprecatedSplitInstruction
|
|
||||||
import com.cobblemon.mod.common.battles.interpreter.instructions.FaintInstruction
|
|
||||||
import com.cobblemon.mod.common.battles.interpreter.instructions.IgnoredInstruction
|
|
||||||
import com.cobblemon.mod.common.battles.interpreter.instructions.MoveInstruction
|
|
||||||
import com.cobblemon.mod.common.battles.interpreter.instructions.TurnInstruction
|
|
||||||
import com.cobblemon.mod.common.battles.interpreter.instructions.UnknownInstruction
|
|
||||||
import com.cobblemon.mod.common.battles.interpreter.instructions.UpkeepInstruction
|
|
||||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||||
import com.cobblemon.mod.common.net.messages.client.battle.*
|
import com.cobblemon.mod.common.net.messages.client.battle.BattleHealthChangePacket
|
||||||
|
import com.cobblemon.mod.common.net.messages.client.battle.BattleMadeInvalidChoicePacket
|
||||||
|
import com.cobblemon.mod.common.net.messages.client.battle.BattleMakeChoicePacket
|
||||||
|
import com.cobblemon.mod.common.net.messages.client.battle.BattlePersistentStatusPacket
|
||||||
|
import com.cobblemon.mod.common.net.messages.client.battle.BattleQueueRequestPacket
|
||||||
|
import com.cobblemon.mod.common.net.messages.client.battle.BattleSwitchPokemonPacket
|
||||||
import com.cobblemon.mod.common.pokemon.evolution.progress.DamageTakenEvolutionProgress
|
import com.cobblemon.mod.common.pokemon.evolution.progress.DamageTakenEvolutionProgress
|
||||||
import com.cobblemon.mod.common.pokemon.evolution.progress.LastBattleCriticalHitsEvolutionProgress
|
import com.cobblemon.mod.common.pokemon.evolution.progress.LastBattleCriticalHitsEvolutionProgress
|
||||||
import com.cobblemon.mod.common.pokemon.evolution.progress.RecoilEvolutionProgress
|
import com.cobblemon.mod.common.pokemon.evolution.progress.RecoilEvolutionProgress
|
||||||
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
|
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
|
||||||
import com.cobblemon.mod.common.util.*
|
import com.cobblemon.mod.common.util.asTranslated
|
||||||
|
import com.cobblemon.mod.common.util.battleLang
|
||||||
|
import com.cobblemon.mod.common.util.lang
|
||||||
|
import com.cobblemon.mod.common.util.runOnServer
|
||||||
|
import com.cobblemon.mod.common.util.swap
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import java.util.concurrent.CompletableFuture
|
import java.util.concurrent.CompletableFuture
|
||||||
|
import kotlin.collections.Iterator
|
||||||
|
import kotlin.collections.MutableList
|
||||||
|
import kotlin.collections.any
|
||||||
|
import kotlin.collections.emptySet
|
||||||
|
import kotlin.collections.filter
|
||||||
|
import kotlin.collections.filterIsInstance
|
||||||
|
import kotlin.collections.find
|
||||||
|
import kotlin.collections.first
|
||||||
|
import kotlin.collections.firstOrNull
|
||||||
|
import kotlin.collections.forEach
|
||||||
|
import kotlin.collections.getOrNull
|
||||||
|
import kotlin.collections.listOf
|
||||||
|
import kotlin.collections.map
|
||||||
|
import kotlin.collections.mapNotNull
|
||||||
|
import kotlin.collections.mutableListOf
|
||||||
|
import kotlin.collections.mutableMapOf
|
||||||
|
import kotlin.collections.reduce
|
||||||
|
import kotlin.collections.set
|
||||||
|
import kotlin.collections.setOf
|
||||||
|
import kotlin.collections.toMutableList
|
||||||
|
import kotlin.collections.toTypedArray
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
import net.minecraft.entity.LivingEntity
|
import net.minecraft.entity.LivingEntity
|
||||||
import net.minecraft.server.world.ServerWorld
|
import net.minecraft.server.world.ServerWorld
|
||||||
@@ -86,12 +116,13 @@ object ShowdownInterpreter {
|
|||||||
updateInstructionParser["upkeep"] = { _, _, _, _ -> UpkeepInstruction() }
|
updateInstructionParser["upkeep"] = { _, _, _, _ -> UpkeepInstruction() }
|
||||||
updateInstructionParser["faint"] = { battle, _, message, _ -> FaintInstruction(battle, message) }
|
updateInstructionParser["faint"] = { battle, _, message, _ -> FaintInstruction(battle, message) }
|
||||||
updateInstructionParser["move"] = { _, instructionSet, message, _ -> MoveInstruction(instructionSet, message) }
|
updateInstructionParser["move"] = { _, instructionSet, message, _ -> MoveInstruction(instructionSet, message) }
|
||||||
splitInstructionParser["-damage"] = { _, targetActor, _, publicMessage, privateMessage, _ ->
|
updateInstructionParser["-activate"] = { _, instructionSet, message, _ -> ActivateInstruction(instructionSet, message) }
|
||||||
DamageInstruction(targetActor, publicMessage, privateMessage)
|
updateInstructionParser["-ability"] = { _, instructionSet, message, _ -> AbilityInstruction(instructionSet, message) }
|
||||||
|
updateInstructionParser["-miss"] = { battle, instructionSet, message, _ -> MissInstruction(battle, instructionSet, message) }
|
||||||
|
splitInstructionParser["-damage"] = { _, targetActor, instructionSet, publicMessage, privateMessage, _ ->
|
||||||
|
DamageInstruction(instructionSet, targetActor, publicMessage, privateMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Note '-cureteam' is a legacy thing that is only used in generation 2 and 4 mods for heal bell and aromatherapy respectively as such we can just ignore that
|
// Note '-cureteam' is a legacy thing that is only used in generation 2 and 4 mods for heal bell and aromatherapy respectively as such we can just ignore that
|
||||||
|
|
||||||
updateInstructions["|win|"] = this::handleWinInstruction
|
updateInstructions["|win|"] = this::handleWinInstruction
|
||||||
@@ -105,11 +136,9 @@ object ShowdownInterpreter {
|
|||||||
updateInstructions["|-fail|"] = this::handleFailInstruction
|
updateInstructions["|-fail|"] = this::handleFailInstruction
|
||||||
updateInstructions["|-start|"] = this::handleStartInstructions
|
updateInstructions["|-start|"] = this::handleStartInstructions
|
||||||
updateInstructions["|-block|"] = this::handleBlockInstructions
|
updateInstructions["|-block|"] = this::handleBlockInstructions
|
||||||
updateInstructions["|-activate|"] = this::handleActivateInstructions
|
|
||||||
updateInstructions["|-curestatus|"] = this::handleCureStatusInstruction
|
updateInstructions["|-curestatus|"] = this::handleCureStatusInstruction
|
||||||
updateInstructions["|-fieldstart|"] = this::handleFieldStartInstructions
|
updateInstructions["|-fieldstart|"] = this::handleFieldStartInstructions
|
||||||
updateInstructions["|-fieldend|"] = this::handleFieldEndInstructions
|
updateInstructions["|-fieldend|"] = this::handleFieldEndInstructions
|
||||||
updateInstructions["|-ability|"] = this::handleAbilityInstructions
|
|
||||||
updateInstructions["|-endability|"] = this::handleEndAbilityInstruction
|
updateInstructions["|-endability|"] = this::handleEndAbilityInstruction
|
||||||
updateInstructions["|-nothing"] = { battle, _, _ ->
|
updateInstructions["|-nothing"] = { battle, _, _ ->
|
||||||
battle.dispatchGo { battle.broadcastChatMessage(battleLang("nothing")) }
|
battle.dispatchGo { battle.broadcastChatMessage(battleLang("nothing")) }
|
||||||
@@ -131,7 +160,6 @@ object ShowdownInterpreter {
|
|||||||
updateInstructions["|-invertboost|"] = this::handleInvertBoostInstruction
|
updateInstructions["|-invertboost|"] = this::handleInvertBoostInstruction
|
||||||
updateInstructions["|-status|"] = this::handleStatusInstruction
|
updateInstructions["|-status|"] = this::handleStatusInstruction
|
||||||
updateInstructions["|-end|"] = this::handleEndInstruction
|
updateInstructions["|-end|"] = this::handleEndInstruction
|
||||||
updateInstructions["|-miss|"] = this::handleMissInstruction
|
|
||||||
updateInstructions["|-hitcount|"] = this::handleHitCountInstruction
|
updateInstructions["|-hitcount|"] = this::handleHitCountInstruction
|
||||||
updateInstructions["|-item|"] = this::handleItemInstruction
|
updateInstructions["|-item|"] = this::handleItemInstruction
|
||||||
updateInstructions["|-enditem|"] = this::handleEndItemInstruction
|
updateInstructions["|-enditem|"] = this::handleEndItemInstruction
|
||||||
@@ -556,20 +584,6 @@ object ShowdownInterpreter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Format:
|
|
||||||
* |-miss|SOURCE|TARGET
|
|
||||||
*
|
|
||||||
* The move used by the SOURCE Pokémon missed (maybe absent) the TARGET Pokémon.
|
|
||||||
*/
|
|
||||||
private fun handleMissInstruction(battle: PokemonBattle, message: BattleMessage, remainingLines: MutableList<String>) {
|
|
||||||
battle.dispatchWaiting(1.5F) {
|
|
||||||
val pokemon = message.getBattlePokemon(0, battle) ?: return@dispatchWaiting
|
|
||||||
battle.broadcastChatMessage(battleLang("missed").red())
|
|
||||||
battle.minorBattleActions[pokemon.uuid] = message
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format:
|
* Format:
|
||||||
* |-immune|POKEMON
|
* |-immune|POKEMON
|
||||||
@@ -625,7 +639,7 @@ object ShowdownInterpreter {
|
|||||||
val effectID = message.effectAt(1)?.id ?: return@dispatchWaiting
|
val effectID = message.effectAt(1)?.id ?: return@dispatchWaiting
|
||||||
val name = pokemon.getName()
|
val name = pokemon.getName()
|
||||||
// Move may be null as it's not always given
|
// Move may be null as it's not always given
|
||||||
val moveName = message.moveAt(2)?.displayName ?: run { println(message.argumentAt(2)); "(Unrecognized: ${message.argumentAt(2)})".text() }
|
val moveName = message.moveAt(2)?.displayName ?: run { "(Unrecognized: ${message.argumentAt(2)})".text() }
|
||||||
|
|
||||||
val lang = when (effectID) {
|
val lang = when (effectID) {
|
||||||
// TODO: in the games they use a generic image because there is a popup of the ability and the sprite of the mon, it may be good to have a similar system here
|
// TODO: in the games they use a generic image because there is a popup of the ability and the sprite of the mon, it may be good to have a similar system here
|
||||||
@@ -957,46 +971,6 @@ object ShowdownInterpreter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Format:
|
|
||||||
* |-activate|POKEMON|EFFECT
|
|
||||||
*
|
|
||||||
* A miscellaneous effect has activated.This is triggered whenever an effect could not be better described by one of the other minor messages.
|
|
||||||
*/
|
|
||||||
private fun handleActivateInstructions(battle: PokemonBattle, message: BattleMessage, remainingLines: MutableList<String>){
|
|
||||||
val pokemon = message.getBattlePokemon(0, battle) ?: return
|
|
||||||
val pokemonName = pokemon.getName()
|
|
||||||
val sourceName = message.getSourceBattlePokemon(battle)?.getName() ?: Text.literal("UNKNOWN")
|
|
||||||
val effect = message.effectAt(1) ?: return
|
|
||||||
val extraEffect = message.effectAt(2)?.typelessData ?: Text.literal("UNKNOWN")
|
|
||||||
broadcastOptionalAbility(battle, effect, pokemonName)
|
|
||||||
|
|
||||||
battle.dispatch{
|
|
||||||
this.lastCauser[battle.battleId] = message
|
|
||||||
battle.minorBattleActions[pokemon.uuid] = message
|
|
||||||
|
|
||||||
val lang = when (effect.id) {
|
|
||||||
// Includes a 3rd argument being the magnitude level as a number
|
|
||||||
"magnitude" -> battleLang("activate.magnitude", message.argumentAt(2)?.toIntOrNull() ?: 1)
|
|
||||||
// Includes spited move and the PP it was reduced by
|
|
||||||
"spite", "eeriespell" -> battleLang("activate.spite", pokemonName, extraEffect, message.argumentAt(3)!!)
|
|
||||||
// Don't need additional lang, announced elsewhere
|
|
||||||
"toxicdebris", "shedskin" -> return@dispatch GO
|
|
||||||
// Add activation to each Pokemon's history
|
|
||||||
"destinybond" -> {
|
|
||||||
battle.activePokemon.mapNotNull { it.battlePokemon?.uuid }.forEach { battle.minorBattleActions[it] = message }
|
|
||||||
battleLang("activate.destinybond", pokemonName)
|
|
||||||
}
|
|
||||||
"focussash", "focusband" -> battleLang("activate.focusband", pokemonName, effect.typelessData)
|
|
||||||
"maxguard", "protect" -> battleLang("activate.protect", pokemonName)
|
|
||||||
"shadowforce", "hyperspacefury", "hyperspacehole" -> battleLang("activate.phantomforce", pokemonName)
|
|
||||||
else -> battleLang("activate.${effect.id}", pokemonName, sourceName, extraEffect)
|
|
||||||
}
|
|
||||||
battle.broadcastChatMessage(lang)
|
|
||||||
WaitDispatch(1F)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format:
|
* Format:
|
||||||
* |-fieldstart|CONDITION
|
* |-fieldstart|CONDITION
|
||||||
@@ -1054,54 +1028,6 @@ object ShowdownInterpreter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Format:
|
|
||||||
* |-ability|POKEMON|ABILITY|(from)EFFECT
|
|
||||||
*
|
|
||||||
* The ABILITY of the POKEMON has been changed due to a move/ability EFFECT.
|
|
||||||
*
|
|
||||||
* Format:
|
|
||||||
* |-ability|POKEMON|ABILITY
|
|
||||||
*
|
|
||||||
* POKEMON has just switched-in, and its ability ABILITY is being announced to have a long-term effect.
|
|
||||||
*/
|
|
||||||
private fun handleAbilityInstructions(battle: PokemonBattle, message: BattleMessage, remainingLines: MutableList<String>) {
|
|
||||||
val pokemon = message.getBattlePokemon(0, battle) ?: return
|
|
||||||
val pokemonName = pokemon.getName()
|
|
||||||
val effect = message.effectAt(1) ?: return
|
|
||||||
val optionalEffect = message.effect()
|
|
||||||
val optionalPokemon = message.getSourceBattlePokemon(battle)
|
|
||||||
val optionalPokemonName = optionalPokemon?.getName()
|
|
||||||
|
|
||||||
// If there is an optional effect causing the activation, broadcast that instead of the standard effect
|
|
||||||
if (optionalEffect != null) {
|
|
||||||
broadcastAbility(battle, optionalEffect, pokemonName)
|
|
||||||
} else {
|
|
||||||
broadcastAbility(battle, effect, pokemonName)
|
|
||||||
}
|
|
||||||
|
|
||||||
battle.dispatch {
|
|
||||||
this.lastCauser[battle.battleId] = message
|
|
||||||
|
|
||||||
val lang = when (optionalEffect?.id) {
|
|
||||||
"trace" -> optionalPokemonName?.let { battleLang("ability.trace", pokemonName, it, effect.typelessData) }
|
|
||||||
"receiver", "powerofalchemy" -> optionalPokemonName?.let { battleLang("ability.receiver", it, effect.typelessData) } // Receiver and Power of Alchemy share the same text
|
|
||||||
else -> when (effect.id) {
|
|
||||||
"sturdy", "unnerve", "anticipation" -> battleLang("ability.${effect.id}", pokemonName) // Unique message
|
|
||||||
"airlock", "cloudnine" -> battleLang("ability.airlock") // Cloud Nine shares the same text as Air Lock
|
|
||||||
else -> null // Effect broadcasted by a succeeding instruction
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
battle.minorBattleActions[pokemon.uuid] = message
|
|
||||||
if (lang != null) {
|
|
||||||
battle.broadcastChatMessage(lang)
|
|
||||||
return@dispatch WaitDispatch(1F)
|
|
||||||
}
|
|
||||||
else return@dispatch GO
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun broadcastOptionalAbility(battle: PokemonBattle, effect: Effect?, pokemonName: MutableText) {
|
fun broadcastOptionalAbility(battle: PokemonBattle, effect: Effect?, pokemonName: MutableText) {
|
||||||
if (effect != null && effect.type == Effect.Type.ABILITY)
|
if (effect != null && effect.type == Effect.Type.ABILITY)
|
||||||
broadcastAbility(battle, effect, pokemonName)
|
broadcastAbility(battle, effect, pokemonName)
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* 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.battles.dispatch
|
||||||
|
|
||||||
|
interface CauserInstruction
|
||||||
@@ -9,9 +9,11 @@
|
|||||||
package com.cobblemon.mod.common.battles.dispatch
|
package com.cobblemon.mod.common.battles.dispatch
|
||||||
|
|
||||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||||
|
import org.objectweb.asm.tree.analysis.Interpreter
|
||||||
|
|
||||||
class InstructionSet {
|
class InstructionSet {
|
||||||
val instructions: MutableList<InterpreterInstruction> = mutableListOf()
|
val instructions: MutableList<InterpreterInstruction> = mutableListOf()
|
||||||
|
|
||||||
fun getSubsequentInstructions(instruction: InterpreterInstruction): List<InterpreterInstruction> {
|
fun getSubsequentInstructions(instruction: InterpreterInstruction): List<InterpreterInstruction> {
|
||||||
val index = instructions.indexOf(instruction)
|
val index = instructions.indexOf(instruction)
|
||||||
return instructions.subList(index + 1, instructions.size).toList()
|
return instructions.subList(index + 1, instructions.size).toList()
|
||||||
@@ -22,6 +24,31 @@ class InstructionSet {
|
|||||||
return instructions.subList(0, index).toList()
|
return instructions.subList(0, index).toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fun <reified T> getMostRecentInstruction(comparedTo: InterpreterInstruction, predicate: (T) -> Boolean = { true }): T? {
|
||||||
|
val index = instructions.indexOf(comparedTo)
|
||||||
|
return instructions.subList(0, index).filterIsInstance<T>().lastOrNull(predicate)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun findInstructionsCausedBy(causerInstruction: CauserInstruction): List<InterpreterInstruction> {
|
||||||
|
causerInstruction as InterpreterInstruction
|
||||||
|
val thisCauseIndex = instructions.indexOf(causerInstruction)
|
||||||
|
if (thisCauseIndex == instructions.size - 1) {
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
val nextCauseIndex = getNextInstruction<CauserInstruction>(causerInstruction)?.let { instructions.indexOf(it as InterpreterInstruction) }
|
||||||
|
return instructions.subList(thisCauseIndex + 1, nextCauseIndex ?: instructions.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T> getNextInstruction(comparedTo: InterpreterInstruction, predicate: (T) -> Boolean = { true }): T? {
|
||||||
|
val index = instructions.indexOf(comparedTo)
|
||||||
|
if (instructions.last() == comparedTo) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return instructions.subList(index + 1, instructions.size).filterIsInstance<T>().firstOrNull(predicate)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getMostRecentCauser(comparedTo: InterpreterInstruction) = getMostRecentInstruction<CauserInstruction>(comparedTo)
|
||||||
|
|
||||||
fun execute(battle: PokemonBattle) {
|
fun execute(battle: PokemonBattle) {
|
||||||
instructions.forEach { it(battle) }
|
instructions.forEach { it(battle) }
|
||||||
}
|
}
|
||||||
|
|||||||
+69
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* 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.battles.interpreter.instructions
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||||
|
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||||
|
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||||
|
import com.cobblemon.mod.common.battles.dispatch.CauserInstruction
|
||||||
|
import com.cobblemon.mod.common.battles.dispatch.GO
|
||||||
|
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||||
|
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||||
|
import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
|
||||||
|
import com.cobblemon.mod.common.util.battleLang
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format:
|
||||||
|
* |-ability|POKEMON|ABILITY|(from)EFFECT
|
||||||
|
*
|
||||||
|
* The ABILITY of the POKEMON has been changed due to a move/ability EFFECT.
|
||||||
|
*
|
||||||
|
* Format:
|
||||||
|
* |-ability|POKEMON|ABILITY
|
||||||
|
*
|
||||||
|
* POKEMON has just switched-in, and its ability ABILITY is being announced to have a long-term effect.
|
||||||
|
*/
|
||||||
|
class AbilityInstruction(val instructionSet: InstructionSet, val message: BattleMessage) : InterpreterInstruction, CauserInstruction {
|
||||||
|
override fun invoke(battle: PokemonBattle) {
|
||||||
|
val pokemon = message.getBattlePokemon(0, battle) ?: return
|
||||||
|
val pokemonName = pokemon.getName()
|
||||||
|
val effect = message.effectAt(1) ?: return
|
||||||
|
val optionalEffect = message.effect()
|
||||||
|
val optionalPokemon = message.getSourceBattlePokemon(battle)
|
||||||
|
val optionalPokemonName = optionalPokemon?.getName()
|
||||||
|
|
||||||
|
// If there is an optional effect causing the activation, broadcast that instead of the standard effect
|
||||||
|
if (optionalEffect != null) {
|
||||||
|
ShowdownInterpreter.broadcastAbility(battle, optionalEffect, pokemonName)
|
||||||
|
} else {
|
||||||
|
ShowdownInterpreter.broadcastAbility(battle, effect, pokemonName)
|
||||||
|
}
|
||||||
|
|
||||||
|
battle.dispatch {
|
||||||
|
ShowdownInterpreter.lastCauser[battle.battleId] = message
|
||||||
|
|
||||||
|
val lang = when (optionalEffect?.id) {
|
||||||
|
"trace" -> optionalPokemonName?.let { battleLang("ability.trace", pokemonName, it, effect.typelessData) }
|
||||||
|
"receiver", "powerofalchemy" -> optionalPokemonName?.let { battleLang("ability.receiver", it, effect.typelessData) } // Receiver and Power of Alchemy share the same text
|
||||||
|
else -> when (effect.id) {
|
||||||
|
"sturdy", "unnerve", "anticipation" -> battleLang("ability.${effect.id}", pokemonName) // Unique message
|
||||||
|
"airlock", "cloudnine" -> battleLang("ability.airlock") // Cloud Nine shares the same text as Air Lock
|
||||||
|
else -> null // Effect broadcasted by a succeeding instruction
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
battle.minorBattleActions[pokemon.uuid] = message
|
||||||
|
if (lang != null) {
|
||||||
|
battle.broadcastChatMessage(lang)
|
||||||
|
return@dispatch WaitDispatch(1F)
|
||||||
|
}
|
||||||
|
else return@dispatch GO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+62
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* 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.battles.interpreter.instructions
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||||
|
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||||
|
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||||
|
import com.cobblemon.mod.common.battles.dispatch.CauserInstruction
|
||||||
|
import com.cobblemon.mod.common.battles.dispatch.GO
|
||||||
|
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||||
|
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||||
|
import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
|
||||||
|
import com.cobblemon.mod.common.util.battleLang
|
||||||
|
import net.minecraft.text.Text
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format:
|
||||||
|
* |-activate|POKEMON|EFFECT
|
||||||
|
*
|
||||||
|
* A miscellaneous effect has activated.This is triggered whenever an effect could not be better described by one of the other minor messages.
|
||||||
|
*/
|
||||||
|
class ActivateInstruction(val instructionSet: InstructionSet, val message: BattleMessage) : InterpreterInstruction, CauserInstruction {
|
||||||
|
override fun invoke(battle: PokemonBattle) {
|
||||||
|
val pokemon = message.getBattlePokemon(0, battle) ?: return
|
||||||
|
val pokemonName = pokemon.getName()
|
||||||
|
val sourceName = message.getSourceBattlePokemon(battle)?.getName() ?: Text.literal("UNKNOWN")
|
||||||
|
val effect = message.effectAt(1) ?: return
|
||||||
|
val extraEffect = message.effectAt(2)?.typelessData ?: Text.literal("UNKNOWN")
|
||||||
|
ShowdownInterpreter.broadcastOptionalAbility(battle, effect, pokemonName)
|
||||||
|
|
||||||
|
battle.dispatch{
|
||||||
|
ShowdownInterpreter.lastCauser[battle.battleId] = message
|
||||||
|
battle.minorBattleActions[pokemon.uuid] = message
|
||||||
|
|
||||||
|
val lang = when (effect.id) {
|
||||||
|
// Includes a 3rd argument being the magnitude level as a number
|
||||||
|
"magnitude" -> battleLang("activate.magnitude", message.argumentAt(2)?.toIntOrNull() ?: 1)
|
||||||
|
// Includes spited move and the PP it was reduced by
|
||||||
|
"spite", "eeriespell" -> battleLang("activate.spite", pokemonName, extraEffect, message.argumentAt(3)!!)
|
||||||
|
// Don't need additional lang, announced elsewhere
|
||||||
|
"toxicdebris", "shedskin" -> return@dispatch GO
|
||||||
|
// Add activation to each Pokemon's history
|
||||||
|
"destinybond" -> {
|
||||||
|
battle.activePokemon.mapNotNull { it.battlePokemon?.uuid }.forEach { battle.minorBattleActions[it] = message }
|
||||||
|
battleLang("activate.destinybond", pokemonName)
|
||||||
|
}
|
||||||
|
"focussash", "focusband" -> battleLang("activate.focusband", pokemonName, effect.typelessData)
|
||||||
|
"maxguard", "protect" -> battleLang("activate.protect", pokemonName)
|
||||||
|
"shadowforce", "hyperspacefury", "hyperspacehole" -> battleLang("activate.phantomforce", pokemonName)
|
||||||
|
else -> battleLang("activate.${effect.id}", pokemonName, sourceName, extraEffect)
|
||||||
|
}
|
||||||
|
battle.broadcastChatMessage(lang)
|
||||||
|
WaitDispatch(1F)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+42
-7
@@ -15,24 +15,34 @@ import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
|||||||
import com.cobblemon.mod.common.api.text.red
|
import com.cobblemon.mod.common.api.text.red
|
||||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||||
import com.cobblemon.mod.common.battles.dispatch.GO
|
import com.cobblemon.mod.common.battles.dispatch.GO
|
||||||
|
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||||
|
import com.cobblemon.mod.common.battles.dispatch.UntilDispatch
|
||||||
import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
|
import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
|
||||||
|
import com.cobblemon.mod.common.net.messages.client.animation.PlayPoseableAnimationPacket
|
||||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleHealthChangePacket
|
import com.cobblemon.mod.common.net.messages.client.battle.BattleHealthChangePacket
|
||||||
import com.cobblemon.mod.common.pokemon.evolution.progress.DamageTakenEvolutionProgress
|
import com.cobblemon.mod.common.pokemon.evolution.progress.DamageTakenEvolutionProgress
|
||||||
import com.cobblemon.mod.common.pokemon.evolution.progress.RecoilEvolutionProgress
|
import com.cobblemon.mod.common.pokemon.evolution.progress.RecoilEvolutionProgress
|
||||||
import com.cobblemon.mod.common.util.battleLang
|
import com.cobblemon.mod.common.util.battleLang
|
||||||
import com.cobblemon.mod.common.util.lang
|
import com.cobblemon.mod.common.util.lang
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
import net.minecraft.text.Text
|
import net.minecraft.text.Text
|
||||||
|
|
||||||
class DamageInstruction(
|
class DamageInstruction(
|
||||||
|
val instructionSet: InstructionSet,
|
||||||
val actor: BattleActor,
|
val actor: BattleActor,
|
||||||
val publicMessage: BattleMessage,
|
val publicMessage: BattleMessage,
|
||||||
val privateMessage: BattleMessage
|
val privateMessage: BattleMessage
|
||||||
) : InterpreterInstruction {
|
) : InterpreterInstruction {
|
||||||
|
var future = CompletableFuture.completedFuture(Unit)
|
||||||
|
val battlePokemon = publicMessage.getBattlePokemon(0, actor.battle)
|
||||||
|
|
||||||
override fun invoke(battle: PokemonBattle) {
|
override fun invoke(battle: PokemonBattle) {
|
||||||
val battlePokemon = publicMessage.getBattlePokemon(0, battle) ?: return
|
battlePokemon ?: return
|
||||||
if (privateMessage.optionalArgument("from")?.equals("recoil", true) == true) {
|
val recoiling = privateMessage.optionalArgument("from")?.equals("recoil", true) == true
|
||||||
|
val lastCauser = instructionSet.getMostRecentCauser(comparedTo = this)
|
||||||
|
if (recoiling) {
|
||||||
battlePokemon.effectedPokemon.let { pokemon ->
|
battlePokemon.effectedPokemon.let { pokemon ->
|
||||||
if (RecoilEvolutionProgress.supports(pokemon)) {
|
if (RecoilEvolutionProgress.supports(pokemon)) {
|
||||||
val newPercentage = privateMessage.argumentAt(1)?.split("/")?.getOrNull(0)?.toIntOrNull() ?: 0
|
val newPercentage = privateMessage.argumentAt(1)?.split("/")?.getOrNull(0)?.toIntOrNull() ?: 0
|
||||||
@@ -48,10 +58,34 @@ class DamageInstruction(
|
|||||||
val newHealth = privateMessage.argumentAt(1)?.split(" ")?.get(0) ?: return
|
val newHealth = privateMessage.argumentAt(1)?.split(" ")?.get(0) ?: return
|
||||||
val effect = privateMessage.effect()
|
val effect = privateMessage.effect()
|
||||||
val pokemonName = battlePokemon.getName()
|
val pokemonName = battlePokemon.getName()
|
||||||
val sourceName = privateMessage.getSourceBattlePokemon(battle)?.getName() ?: Text.literal("UNKOWN")
|
val sourceName = privateMessage.getSourceBattlePokemon(battle)?.getName() ?: Text.literal("UNKNOWN")
|
||||||
ShowdownInterpreter.broadcastOptionalAbility(battle, effect, sourceName)
|
var causedFaint = newHealth == "0"
|
||||||
|
|
||||||
battle.dispatch {
|
battle.dispatch {
|
||||||
|
if (lastCauser is MoveInstruction && recoiling) {
|
||||||
|
UntilDispatch { "recoil" !in lastCauser.holds }
|
||||||
|
} else {
|
||||||
|
GO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
battle.dispatch {
|
||||||
|
if (!causedFaint) {
|
||||||
|
|
||||||
|
battlePokemon.entity?.let { pokemonEntity ->
|
||||||
|
val pkt = PlayPoseableAnimationPacket(pokemonEntity.id, setOf("recoil"), emptySet())
|
||||||
|
pkt.sendToPlayersAround(
|
||||||
|
x = pokemonEntity.x,
|
||||||
|
y = pokemonEntity.y,
|
||||||
|
z = pokemonEntity.z,
|
||||||
|
worldKey = pokemonEntity.world.registryKey,
|
||||||
|
distance = 50.0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ShowdownInterpreter.broadcastOptionalAbility(battle, effect, sourceName)
|
||||||
val newHealthRatio: Float
|
val newHealthRatio: Float
|
||||||
val remainingHealth = newHealth.split("/")[0].toInt()
|
val remainingHealth = newHealth.split("/")[0].toInt()
|
||||||
|
|
||||||
@@ -70,8 +104,7 @@ class DamageInstruction(
|
|||||||
battle.broadcastChatMessage(lang.red())
|
battle.broadcastChatMessage(lang.red())
|
||||||
}
|
}
|
||||||
|
|
||||||
var causedFaint = false
|
if (causedFaint) {
|
||||||
if (newHealth == "0") {
|
|
||||||
newHealthRatio = 0F
|
newHealthRatio = 0F
|
||||||
battle.dispatch {
|
battle.dispatch {
|
||||||
battlePokemon.effectedPokemon.currentHealth = 0
|
battlePokemon.effectedPokemon.currentHealth = 0
|
||||||
@@ -102,7 +135,9 @@ class DamageInstruction(
|
|||||||
battle.minorBattleActions[battlePokemon.uuid] = privateMessage
|
battle.minorBattleActions[battlePokemon.uuid] = privateMessage
|
||||||
|
|
||||||
// If they faint from this damage then don't bother waiting for the damage to be applied.
|
// If they faint from this damage then don't bother waiting for the damage to be applied.
|
||||||
if (causedFaint) {
|
if (lastCauser is MoveInstruction && lastCauser.actionEffect != null && !causedFaint) {
|
||||||
|
UntilDispatch { lastCauser.future.isDone }
|
||||||
|
} else if (causedFaint) {
|
||||||
GO
|
GO
|
||||||
} else {
|
} else {
|
||||||
WaitDispatch(1F)
|
WaitDispatch(1F)
|
||||||
|
|||||||
+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.battles.interpreter.instructions
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||||
|
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||||
|
import com.cobblemon.mod.common.api.text.red
|
||||||
|
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||||
|
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||||
|
import com.cobblemon.mod.common.util.battleLang
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format:
|
||||||
|
* |-miss|SOURCE|TARGET
|
||||||
|
*
|
||||||
|
* The move used by the SOURCE Pokémon missed (maybe absent) the TARGET Pokémon.
|
||||||
|
*/
|
||||||
|
class MissInstruction(val battle: PokemonBattle, val instructionSet: InstructionSet, val message: BattleMessage): InterpreterInstruction {
|
||||||
|
val target = message.getBattlePokemon(1, battle)
|
||||||
|
|
||||||
|
override fun invoke(battle: PokemonBattle) {
|
||||||
|
battle.dispatchGo {
|
||||||
|
val pokemon = message.getBattlePokemon(0, battle) ?: return@dispatchGo
|
||||||
|
battle.broadcastChatMessage(battleLang("missed").red())
|
||||||
|
battle.minorBattleActions[pokemon.uuid] = message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+74
-7
@@ -8,30 +8,55 @@
|
|||||||
|
|
||||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||||
|
|
||||||
|
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||||
|
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||||
|
import com.cobblemon.mod.common.api.battles.interpreter.Effect
|
||||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||||
|
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunction
|
||||||
|
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
|
||||||
|
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||||
import com.cobblemon.mod.common.api.moves.Moves
|
import com.cobblemon.mod.common.api.moves.Moves
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.TargetsProvider
|
||||||
|
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||||
|
import com.cobblemon.mod.common.battles.dispatch.CauserInstruction
|
||||||
|
import com.cobblemon.mod.common.battles.dispatch.GO
|
||||||
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||||
|
import com.cobblemon.mod.common.battles.dispatch.UntilDispatch
|
||||||
|
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||||
import com.cobblemon.mod.common.pokemon.evolution.progress.UseMoveEvolutionProgress
|
import com.cobblemon.mod.common.pokemon.evolution.progress.UseMoveEvolutionProgress
|
||||||
import com.cobblemon.mod.common.util.battleLang
|
import com.cobblemon.mod.common.util.battleLang
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
|
||||||
class MoveInstruction(
|
class MoveInstruction(
|
||||||
val instructionSet: InstructionSet,
|
val instructionSet: InstructionSet,
|
||||||
val message: BattleMessage
|
val message: BattleMessage
|
||||||
) : InterpreterInstruction {
|
) : InterpreterInstruction, CauserInstruction {
|
||||||
|
val effect = message.effectAt(1) ?: Effect.pure("", "")
|
||||||
|
val move = Moves.getByNameOrDummy(effect.id)
|
||||||
|
val actionEffect = move.actionEffect
|
||||||
|
|
||||||
|
var future = CompletableFuture.completedFuture(Unit)
|
||||||
|
var holds = mutableSetOf<String>()
|
||||||
|
|
||||||
|
lateinit var userPokemon: BattlePokemon
|
||||||
|
var targetPokemon: BattlePokemon? = null
|
||||||
|
|
||||||
override fun invoke(battle: PokemonBattle) {
|
override fun invoke(battle: PokemonBattle) {
|
||||||
val userPokemon = message.getBattlePokemon(0, battle) ?: return
|
userPokemon = message.getBattlePokemon(0, battle)!!
|
||||||
val targetPokemon = message.getBattlePokemon(2, battle)
|
targetPokemon = message.getBattlePokemon(2, battle)
|
||||||
val effect = message.effectAt(1) ?: return
|
val targetPokemon = targetPokemon // So smart non-null casts can happen
|
||||||
|
|
||||||
val optionalEffect = message.effect()
|
val optionalEffect = message.effect()
|
||||||
val move = Moves.getByNameOrDummy(effect.id)
|
|
||||||
val pokemonName = userPokemon.getName()
|
val pokemonName = userPokemon.getName()
|
||||||
ShowdownInterpreter.broadcastOptionalAbility(battle, optionalEffect, pokemonName)
|
ShowdownInterpreter.broadcastOptionalAbility(battle, optionalEffect, pokemonName)
|
||||||
|
|
||||||
|
battle.dispatch { UntilDispatch { instructionSet.getMostRecentInstruction<MoveInstruction>(this)?.future?.isDone != false } }
|
||||||
|
|
||||||
battle.dispatchGo {
|
battle.dispatch {
|
||||||
ShowdownInterpreter.lastCauser[battle.battleId] = message
|
ShowdownInterpreter.lastCauser[battle.battleId] = message
|
||||||
|
|
||||||
userPokemon.effectedPokemon.let { pokemon ->
|
userPokemon.effectedPokemon.let { pokemon ->
|
||||||
@@ -50,8 +75,50 @@ class MoveInstruction(
|
|||||||
battleLang("used_move", pokemonName, move.displayName)
|
battleLang("used_move", pokemonName, move.displayName)
|
||||||
}
|
}
|
||||||
battle.broadcastChatMessage(lang)
|
battle.broadcastChatMessage(lang)
|
||||||
|
|
||||||
battle.majorBattleActions[userPokemon.uuid] = message
|
battle.majorBattleActions[userPokemon.uuid] = message
|
||||||
|
|
||||||
|
val providers = mutableListOf<Any>(battle)
|
||||||
|
userPokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
|
||||||
|
targetPokemon?.effectedPokemon?.entity?.let { TargetsProvider(it) }?.let(providers::add)
|
||||||
|
val runtime = MoLangRuntime().also {
|
||||||
|
battle.addQueryFunctions(it.environment.getQueryStruct()).addStandardFunctions()
|
||||||
|
}
|
||||||
|
|
||||||
|
actionEffect ?: return@dispatch GO
|
||||||
|
val context = ActionEffectContext(
|
||||||
|
actionEffect = actionEffect,
|
||||||
|
runtime = runtime,
|
||||||
|
providers = providers
|
||||||
|
)
|
||||||
|
|
||||||
|
val subsequentInstructions = instructionSet.findInstructionsCausedBy(this)
|
||||||
|
val missedTargets = subsequentInstructions.filterIsInstance<MissInstruction>().mapNotNull { it.target }
|
||||||
|
|
||||||
|
runtime.environment.getQueryStruct().addFunction("missed") { params ->
|
||||||
|
if (params.params.size == 0) {
|
||||||
|
return@addFunction DoubleValue(missedTargets.isNotEmpty())
|
||||||
|
} else {
|
||||||
|
val entityUUID = params.getString(0)
|
||||||
|
return@addFunction DoubleValue(missedTargets.any { it.entity?.uuidAsString == entityUUID })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val hurtTargets = subsequentInstructions.filterIsInstance<DamageInstruction>().mapNotNull { it.battlePokemon }
|
||||||
|
runtime.environment.getQueryStruct().addFunction("hurt") { params ->
|
||||||
|
if (params.params.size == 0) {
|
||||||
|
return@addFunction DoubleValue(hurtTargets.isNotEmpty())
|
||||||
|
} else {
|
||||||
|
val entityUUID = params.getString(0)
|
||||||
|
return@addFunction DoubleValue(hurtTargets.any { it.entity?.uuidAsString == entityUUID })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
runtime.environment.getQueryStruct().addFunction("move") { move.struct }
|
||||||
|
|
||||||
|
this.future = actionEffect.run(context)
|
||||||
|
holds = context.holds // Reference so future things can check on this action effect's holds
|
||||||
|
future.thenApply { holds.clear() }
|
||||||
|
return@dispatch UntilDispatch { "effects" !in holds }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Cobblemon Contributors
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.cobblemon.mod.common.block
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.CobblemonBlockEntities
|
||||||
|
import com.cobblemon.mod.common.block.entity.DyniteOreBlockEntity
|
||||||
|
import net.minecraft.block.BlockRenderType
|
||||||
|
import net.minecraft.block.BlockState
|
||||||
|
import net.minecraft.block.BlockWithEntity
|
||||||
|
import net.minecraft.block.entity.BlockEntity
|
||||||
|
import net.minecraft.block.entity.BlockEntityTicker
|
||||||
|
import net.minecraft.block.entity.BlockEntityType
|
||||||
|
import net.minecraft.util.math.BlockPos
|
||||||
|
import net.minecraft.world.World
|
||||||
|
|
||||||
|
class DyniteOreBlock(settings: Settings) : BlockWithEntity(settings) {
|
||||||
|
override fun createBlockEntity(pos: BlockPos, state: BlockState): BlockEntity {
|
||||||
|
return DyniteOreBlockEntity(pos, state)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getRenderType(state: BlockState?) = BlockRenderType.MODEL
|
||||||
|
|
||||||
|
override fun <T : BlockEntity> getTicker(
|
||||||
|
world: World,
|
||||||
|
state: BlockState,
|
||||||
|
type: BlockEntityType<T>
|
||||||
|
): BlockEntityTicker<T>? {
|
||||||
|
return checkType(type, CobblemonBlockEntities.DYNITE_ORE, DyniteOreBlockEntity.TICKER::tick)
|
||||||
|
}
|
||||||
|
}
|
||||||
+8
-8
@@ -6,12 +6,12 @@
|
|||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.cobblemon.mod.common.block.fossilmachine
|
package com.cobblemon.mod.common.block
|
||||||
|
|
||||||
import com.cobblemon.mod.common.CobblemonBlockEntities
|
import com.cobblemon.mod.common.CobblemonBlockEntities
|
||||||
import com.cobblemon.mod.common.api.multiblock.MultiblockBlock
|
import com.cobblemon.mod.common.api.multiblock.MultiblockBlock
|
||||||
import com.cobblemon.mod.common.block.entity.fossil.FossilCompartmentBlockEntity
|
import com.cobblemon.mod.common.block.entity.FossilAnalyzerBlockEntity
|
||||||
import com.cobblemon.mod.common.block.entity.fossil.FossilMultiblockEntity
|
import com.cobblemon.mod.common.block.entity.FossilMultiblockEntity
|
||||||
import com.cobblemon.mod.common.block.multiblock.FossilMultiblockStructure
|
import com.cobblemon.mod.common.block.multiblock.FossilMultiblockStructure
|
||||||
import com.cobblemon.mod.common.block.multiblock.FossilMultiblockBuilder
|
import com.cobblemon.mod.common.block.multiblock.FossilMultiblockBuilder
|
||||||
import net.minecraft.block.Block
|
import net.minecraft.block.Block
|
||||||
@@ -30,7 +30,7 @@ import net.minecraft.util.math.Direction
|
|||||||
import net.minecraft.world.World
|
import net.minecraft.world.World
|
||||||
import net.minecraft.world.WorldAccess
|
import net.minecraft.world.WorldAccess
|
||||||
|
|
||||||
class FossilCompartmentBlock(properties: Settings) : MultiblockBlock(properties), InventoryProvider {
|
class FossilAnalyzerBlock(properties: Settings) : MultiblockBlock(properties), InventoryProvider {
|
||||||
init {
|
init {
|
||||||
defaultState = defaultState
|
defaultState = defaultState
|
||||||
.with(HorizontalFacingBlock.FACING, Direction.NORTH)
|
.with(HorizontalFacingBlock.FACING, Direction.NORTH)
|
||||||
@@ -38,14 +38,14 @@ class FossilCompartmentBlock(properties: Settings) : MultiblockBlock(properties)
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun createMultiBlockEntity(pos: BlockPos, state: BlockState): FossilMultiblockEntity {
|
override fun createMultiBlockEntity(pos: BlockPos, state: BlockState): FossilMultiblockEntity {
|
||||||
return FossilCompartmentBlockEntity(pos, state, FossilMultiblockBuilder(pos))
|
return FossilAnalyzerBlockEntity(pos, state, FossilMultiblockBuilder(pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <T : BlockEntity?> getTicker(
|
override fun <T : BlockEntity?> getTicker(
|
||||||
world: World?,
|
world: World?,
|
||||||
state: BlockState?,
|
state: BlockState?,
|
||||||
type: BlockEntityType<T>?
|
type: BlockEntityType<T>?
|
||||||
): BlockEntityTicker<T>? = checkType(type, CobblemonBlockEntities.FOSSIL_COMPARTMENT, FossilMultiblockStructure.TICKER::tick)
|
): BlockEntityTicker<T>? = checkType(type, CobblemonBlockEntities.FOSSIL_ANALYZER, FossilMultiblockStructure.TICKER::tick)
|
||||||
|
|
||||||
override fun getPlacementState(blockPlaceContext: ItemPlacementContext): BlockState? {
|
override fun getPlacementState(blockPlaceContext: ItemPlacementContext): BlockState? {
|
||||||
return defaultState.with(HorizontalFacingBlock.FACING, blockPlaceContext.horizontalPlayerFacing)
|
return defaultState.with(HorizontalFacingBlock.FACING, blockPlaceContext.horizontalPlayerFacing)
|
||||||
@@ -56,9 +56,9 @@ class FossilCompartmentBlock(properties: Settings) : MultiblockBlock(properties)
|
|||||||
world: WorldAccess,
|
world: WorldAccess,
|
||||||
pos: BlockPos
|
pos: BlockPos
|
||||||
): SidedInventory {
|
): SidedInventory {
|
||||||
val compartmentEntity = world.getBlockEntity(pos) as FossilCompartmentBlockEntity
|
val analyzerEntity = world.getBlockEntity(pos) as FossilAnalyzerBlockEntity
|
||||||
|
|
||||||
return compartmentEntity.inv
|
return analyzerEntity.inv
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
|
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Cobblemon Contributors
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.cobblemon.mod.common.block
|
||||||
|
|
||||||
|
import net.minecraft.block.*
|
||||||
|
import net.minecraft.item.ItemPlacementContext
|
||||||
|
import net.minecraft.server.world.ServerWorld
|
||||||
|
import net.minecraft.state.StateManager
|
||||||
|
import net.minecraft.util.math.BlockPos
|
||||||
|
import net.minecraft.util.math.Direction
|
||||||
|
import net.minecraft.util.math.random.Random
|
||||||
|
import net.minecraft.util.shape.VoxelShape
|
||||||
|
import net.minecraft.world.BlockView
|
||||||
|
import net.minecraft.world.WorldAccess
|
||||||
|
import net.minecraft.world.WorldView
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used for blocks that grow similarly to Amethyst.
|
||||||
|
*
|
||||||
|
* @param settings Block settings
|
||||||
|
* @param stage The stage of growth of the block
|
||||||
|
* @param height The height of this block's hitbox
|
||||||
|
* @param nextStage The next stage of this block's growth. Null if final stage
|
||||||
|
*
|
||||||
|
* @author whatsy
|
||||||
|
*/
|
||||||
|
abstract class GrowableStoneBlock(
|
||||||
|
settings: Settings,
|
||||||
|
val stage: Int,
|
||||||
|
val height: Int,
|
||||||
|
xzOffset: Int,
|
||||||
|
val nextStage: Block?
|
||||||
|
) : FacingBlock(settings) {
|
||||||
|
|
||||||
|
private val upShape: VoxelShape = Block.createCuboidShape(
|
||||||
|
xzOffset.toDouble(),
|
||||||
|
0.0,
|
||||||
|
xzOffset.toDouble(),
|
||||||
|
(16 - xzOffset).toDouble(),
|
||||||
|
height.toDouble(),
|
||||||
|
(16 - xzOffset).toDouble())
|
||||||
|
|
||||||
|
private val downShape: VoxelShape = createCuboidShape(
|
||||||
|
xzOffset.toDouble(),
|
||||||
|
(16 - height).toDouble(),
|
||||||
|
xzOffset.toDouble(),
|
||||||
|
(16 - xzOffset).toDouble(),
|
||||||
|
16.0,
|
||||||
|
(16 - xzOffset).toDouble())
|
||||||
|
|
||||||
|
private val northShape: VoxelShape = createCuboidShape(
|
||||||
|
xzOffset.toDouble(),
|
||||||
|
xzOffset.toDouble(),
|
||||||
|
(16 - height).toDouble(),
|
||||||
|
(16 - xzOffset).toDouble(),
|
||||||
|
(16 - xzOffset).toDouble(),
|
||||||
|
16.0)
|
||||||
|
|
||||||
|
private val southShape: VoxelShape = createCuboidShape(
|
||||||
|
xzOffset.toDouble(),
|
||||||
|
xzOffset.toDouble(),
|
||||||
|
0.0,
|
||||||
|
(16 - xzOffset).toDouble(),
|
||||||
|
(16 - xzOffset).toDouble(),
|
||||||
|
height.toDouble())
|
||||||
|
|
||||||
|
private val eastShape: VoxelShape = createCuboidShape(
|
||||||
|
0.0,
|
||||||
|
xzOffset.toDouble(),
|
||||||
|
xzOffset.toDouble(),
|
||||||
|
height.toDouble(),
|
||||||
|
(16 - xzOffset).toDouble(),
|
||||||
|
(16 - xzOffset).toDouble())
|
||||||
|
|
||||||
|
private val westShape: VoxelShape = createCuboidShape(
|
||||||
|
(16 - height).toDouble(),
|
||||||
|
xzOffset.toDouble(),
|
||||||
|
xzOffset.toDouble(),
|
||||||
|
16.0,
|
||||||
|
(16 - xzOffset).toDouble(),
|
||||||
|
(16 - xzOffset).toDouble())
|
||||||
|
|
||||||
|
init {
|
||||||
|
this.defaultState = this.stateManager.defaultState
|
||||||
|
.with(FACING, Direction.DOWN)
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun canGrow(pos: BlockPos, world: BlockView): Boolean
|
||||||
|
|
||||||
|
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
|
||||||
|
builder.add(FACING)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hasRandomTicks(state: BlockState?) = stage < MAX_STAGE
|
||||||
|
override fun randomTick(state: BlockState, world: ServerWorld, pos: BlockPos, random: Random) {
|
||||||
|
if (world.random.nextInt(5) == 0 && canGrow(pos, world)) {
|
||||||
|
val block = nextStage
|
||||||
|
|
||||||
|
if (block != null) {
|
||||||
|
val newState = block.defaultState.with(FACING, state.get(FACING)) as BlockState
|
||||||
|
world.setBlockState(pos, newState)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getPlacementState(ctx: ItemPlacementContext): BlockState? {
|
||||||
|
var blockState = defaultState
|
||||||
|
val worldView = ctx.world
|
||||||
|
val blockPos = ctx.blockPos
|
||||||
|
blockState = blockState.with(FACING, ctx.side) as BlockState
|
||||||
|
if (blockState.canPlaceAt(worldView, blockPos)) {
|
||||||
|
return blockState
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canPlaceAt(state: BlockState, world: WorldView, pos: BlockPos): Boolean {
|
||||||
|
val direction = state.get(FACING) as Direction
|
||||||
|
val blockState = world.getBlockState(pos.offset(direction.opposite))
|
||||||
|
return blockState.isSideSolidFullSquare(world, pos, direction)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getStateForNeighborUpdate(state: BlockState, direction: Direction, neighborState: BlockState, world: WorldAccess, pos: BlockPos, neighborPos: BlockPos): BlockState? {
|
||||||
|
return if (direction == state.get(FACING).opposite && !state.canPlaceAt(world, pos)) Blocks.AIR.defaultState
|
||||||
|
else super.getStateForNeighborUpdate(state, direction, neighborState, world, pos, neighborPos)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getOutlineShape(state: BlockState, world: BlockView, pos: BlockPos, context: ShapeContext): VoxelShape {
|
||||||
|
val direction = state.get(FACING) as Direction
|
||||||
|
return when (direction) {
|
||||||
|
Direction.NORTH -> northShape
|
||||||
|
Direction.SOUTH -> southShape
|
||||||
|
Direction.EAST -> eastShape
|
||||||
|
Direction.WEST -> westShape
|
||||||
|
Direction.DOWN -> downShape
|
||||||
|
Direction.UP -> upShape
|
||||||
|
else -> upShape
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val STAGE_0 = 0
|
||||||
|
const val STAGE_1 = 1
|
||||||
|
const val STAGE_2 = 2
|
||||||
|
const val STAGE_3 = 3
|
||||||
|
|
||||||
|
const val MAX_STAGE = STAGE_3
|
||||||
|
const val MIN_STAGE = STAGE_0
|
||||||
|
}
|
||||||
|
}
|
||||||
+28
-7
@@ -6,19 +6,21 @@
|
|||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.cobblemon.mod.common.block.fossilmachine
|
package com.cobblemon.mod.common.block
|
||||||
|
|
||||||
import com.cobblemon.mod.common.block.entity.fossil.FossilMultiblockEntity
|
|
||||||
import com.cobblemon.mod.common.api.multiblock.MultiblockBlock
|
import com.cobblemon.mod.common.api.multiblock.MultiblockBlock
|
||||||
import com.cobblemon.mod.common.api.multiblock.MultiblockEntity
|
import com.cobblemon.mod.common.api.multiblock.MultiblockEntity
|
||||||
|
import com.cobblemon.mod.common.block.entity.FossilMultiblockEntity
|
||||||
import com.cobblemon.mod.common.block.multiblock.FossilMultiblockBuilder
|
import com.cobblemon.mod.common.block.multiblock.FossilMultiblockBuilder
|
||||||
import net.minecraft.block.Block
|
import net.minecraft.block.Block
|
||||||
import net.minecraft.block.BlockState
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.block.HorizontalFacingBlock
|
import net.minecraft.block.HorizontalFacingBlock
|
||||||
import net.minecraft.block.ShapeContext
|
import net.minecraft.block.ShapeContext
|
||||||
|
import net.minecraft.entity.ai.pathing.NavigationType
|
||||||
import net.minecraft.item.ItemPlacementContext
|
import net.minecraft.item.ItemPlacementContext
|
||||||
import net.minecraft.state.StateManager
|
import net.minecraft.state.StateManager
|
||||||
import net.minecraft.state.property.IntProperty
|
import net.minecraft.state.property.EnumProperty
|
||||||
|
import net.minecraft.util.StringIdentifiable
|
||||||
import net.minecraft.util.math.BlockPos
|
import net.minecraft.util.math.BlockPos
|
||||||
import net.minecraft.util.math.Direction
|
import net.minecraft.util.math.Direction
|
||||||
import net.minecraft.util.shape.VoxelShape
|
import net.minecraft.util.shape.VoxelShape
|
||||||
@@ -26,7 +28,7 @@ import net.minecraft.util.shape.VoxelShapes
|
|||||||
import net.minecraft.world.BlockView
|
import net.minecraft.world.BlockView
|
||||||
import net.minecraft.world.World
|
import net.minecraft.world.World
|
||||||
|
|
||||||
class FossilMonitorBlock(properties: Settings) : MultiblockBlock(properties) {
|
class MonitorBlock(properties: Settings) : MultiblockBlock(properties) {
|
||||||
init {
|
init {
|
||||||
defaultState = defaultState.with(HorizontalFacingBlock.FACING, Direction.NORTH)
|
defaultState = defaultState.with(HorizontalFacingBlock.FACING, Direction.NORTH)
|
||||||
}
|
}
|
||||||
@@ -46,7 +48,7 @@ class FossilMonitorBlock(properties: Settings) : MultiblockBlock(properties) {
|
|||||||
|
|
||||||
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
|
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
|
||||||
builder.add(HorizontalFacingBlock.FACING)
|
builder.add(HorizontalFacingBlock.FACING)
|
||||||
builder.add(PROGRESS)
|
builder.add(SCREEN)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated("Deprecated in Java")
|
@Deprecated("Deprecated in Java")
|
||||||
@@ -76,10 +78,14 @@ class FossilMonitorBlock(properties: Settings) : MultiblockBlock(properties) {
|
|||||||
): VoxelShape {
|
): VoxelShape {
|
||||||
return HITBOX
|
return HITBOX
|
||||||
}
|
}
|
||||||
|
@Deprecated("Deprecated in Java")
|
||||||
|
override fun canPathfindThrough(state: BlockState?, world: BlockView?, pos: BlockPos?, type: NavigationType?): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
//0 is off
|
//0 is off
|
||||||
val PROGRESS = IntProperty.of("progress", 0, 9)
|
val SCREEN = EnumProperty.of("screen", MonitorScreen::class.java)
|
||||||
val HITBOX = VoxelShapes.union(
|
val HITBOX = VoxelShapes.union(
|
||||||
VoxelShapes.cuboid(0.0625, 0.0, 0.0625, 0.9375, 0.375, 0.9375),
|
VoxelShapes.cuboid(0.0625, 0.0, 0.0625, 0.9375, 0.375, 0.9375),
|
||||||
VoxelShapes.cuboid(0.0625, 0.875, 0.0625, 0.9375, 1.0, 0.9375),
|
VoxelShapes.cuboid(0.0625, 0.875, 0.0625, 0.9375, 1.0, 0.9375),
|
||||||
@@ -88,4 +94,19 @@ class FossilMonitorBlock(properties: Settings) : MultiblockBlock(properties) {
|
|||||||
VoxelShapes.cuboid(0.0625, 0.375, 0.0625, 0.1875, 0.875, 0.9375)
|
VoxelShapes.cuboid(0.0625, 0.375, 0.0625, 0.1875, 0.875, 0.9375)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
enum class MonitorScreen : StringIdentifiable {
|
||||||
|
OFF,
|
||||||
|
BLUE_PROGRESS_1,
|
||||||
|
BLUE_PROGRESS_2,
|
||||||
|
BLUE_PROGRESS_3,
|
||||||
|
BLUE_PROGRESS_4,
|
||||||
|
BLUE_PROGRESS_5,
|
||||||
|
BLUE_PROGRESS_6,
|
||||||
|
BLUE_PROGRESS_7,
|
||||||
|
BLUE_PROGRESS_8,
|
||||||
|
BLUE_PROGRESS_9,
|
||||||
|
GREEN_PROGRESS_9;
|
||||||
|
|
||||||
|
override fun asString(): String = this.name.lowercase()
|
||||||
|
}
|
||||||
|
}
|
||||||
+35
-33
@@ -6,13 +6,13 @@
|
|||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.cobblemon.mod.common.block.fossilmachine
|
package com.cobblemon.mod.common.block
|
||||||
|
|
||||||
import com.cobblemon.mod.common.CobblemonBlocks
|
import com.cobblemon.mod.common.CobblemonBlocks
|
||||||
import com.cobblemon.mod.common.api.multiblock.MultiblockBlock
|
import com.cobblemon.mod.common.api.multiblock.MultiblockBlock
|
||||||
import com.cobblemon.mod.common.api.multiblock.MultiblockEntity
|
import com.cobblemon.mod.common.api.multiblock.MultiblockEntity
|
||||||
import com.cobblemon.mod.common.block.entity.fossil.FossilMultiblockEntity
|
import com.cobblemon.mod.common.block.entity.FossilMultiblockEntity
|
||||||
import com.cobblemon.mod.common.block.entity.fossil.FossilTubeBlockEntity
|
import com.cobblemon.mod.common.block.entity.RestorationTankBlockEntity
|
||||||
import com.cobblemon.mod.common.block.multiblock.FossilMultiblockBuilder
|
import com.cobblemon.mod.common.block.multiblock.FossilMultiblockBuilder
|
||||||
import net.minecraft.block.*
|
import net.minecraft.block.*
|
||||||
import net.minecraft.entity.LivingEntity
|
import net.minecraft.entity.LivingEntity
|
||||||
@@ -22,6 +22,7 @@ import net.minecraft.item.ItemPlacementContext
|
|||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.minecraft.server.world.ServerWorld
|
import net.minecraft.server.world.ServerWorld
|
||||||
import net.minecraft.state.StateManager
|
import net.minecraft.state.StateManager
|
||||||
|
import net.minecraft.state.property.BooleanProperty
|
||||||
import net.minecraft.state.property.EnumProperty
|
import net.minecraft.state.property.EnumProperty
|
||||||
import net.minecraft.state.property.Properties
|
import net.minecraft.state.property.Properties
|
||||||
import net.minecraft.util.ActionResult
|
import net.minecraft.util.ActionResult
|
||||||
@@ -39,17 +40,19 @@ import net.minecraft.world.WorldAccess
|
|||||||
import net.minecraft.world.WorldView
|
import net.minecraft.world.WorldView
|
||||||
|
|
||||||
|
|
||||||
class FossilTubeBlock(properties: Settings) : MultiblockBlock(properties), InventoryProvider {
|
class RestorationTankBlock(properties: Settings) : MultiblockBlock(properties), InventoryProvider {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
defaultState = defaultState
|
defaultState = defaultState
|
||||||
.with(HorizontalFacingBlock.FACING, Direction.NORTH)
|
.with(HorizontalFacingBlock.FACING, Direction.NORTH)
|
||||||
.with(PART, TubePart.BOTTOM)
|
.with(PART, TankPart.BOTTOM)
|
||||||
.with(TRIGGERED, false)
|
.with(TRIGGERED, false)
|
||||||
|
.with(ON, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun getPositionOfOtherPart(state: BlockState, pos: BlockPos): BlockPos {
|
fun getPositionOfOtherPart(state: BlockState, pos: BlockPos): BlockPos {
|
||||||
return if (state.get(PART) == TubePart.BOTTOM) {
|
return if (state.get(PART) == TankPart.BOTTOM) {
|
||||||
pos.up()
|
pos.up()
|
||||||
} else {
|
} else {
|
||||||
pos.down()
|
pos.down()
|
||||||
@@ -64,12 +67,12 @@ class FossilTubeBlock(properties: Settings) : MultiblockBlock(properties), Inven
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isBase(state: BlockState): Boolean = state.get(PART) == TubePart.BOTTOM
|
private fun isBase(state: BlockState): Boolean = state.get(PART) == TankPart.BOTTOM
|
||||||
|
|
||||||
override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity?) {
|
override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity?) {
|
||||||
super.onBreak(world, pos, state, player)
|
super.onBreak(world, pos, state, player)
|
||||||
val otherPart = world.getBlockState(getPositionOfOtherPart(state, pos))
|
val otherPart = world.getBlockState(getPositionOfOtherPart(state, pos))
|
||||||
if (otherPart.block is FossilTubeBlock) {
|
if (otherPart.block is RestorationTankBlock) {
|
||||||
world.setBlockState(getPositionOfOtherPart(state, pos), Blocks.AIR.defaultState, 35)
|
world.setBlockState(getPositionOfOtherPart(state, pos), Blocks.AIR.defaultState, 35)
|
||||||
world.syncWorldEvent(player, 2001, getPositionOfOtherPart(state, pos), getRawIdFromState(otherPart))
|
world.syncWorldEvent(player, 2001, getPositionOfOtherPart(state, pos), getRawIdFromState(otherPart))
|
||||||
}
|
}
|
||||||
@@ -83,7 +86,7 @@ class FossilTubeBlock(properties: Settings) : MultiblockBlock(properties), Inven
|
|||||||
itemStack: ItemStack?
|
itemStack: ItemStack?
|
||||||
) {
|
) {
|
||||||
//Place the full block before we call to super to validate the multiblock
|
//Place the full block before we call to super to validate the multiblock
|
||||||
world.setBlockState(pos.up(), state.with(PART, TubePart.TOP) as BlockState, 3)
|
world.setBlockState(pos.up(), state.with(PART, TankPart.TOP) as BlockState, 3)
|
||||||
world.updateNeighbors(pos, Blocks.AIR)
|
world.updateNeighbors(pos, Blocks.AIR)
|
||||||
state.updateNeighbors(world, pos, 3)
|
state.updateNeighbors(world, pos, 3)
|
||||||
super.onPlaced(world, pos, state, placer, itemStack)
|
super.onPlaced(world, pos, state, placer, itemStack)
|
||||||
@@ -91,20 +94,20 @@ class FossilTubeBlock(properties: Settings) : MultiblockBlock(properties), Inven
|
|||||||
|
|
||||||
@Deprecated("Deprecated in Java")
|
@Deprecated("Deprecated in Java")
|
||||||
override fun onUse(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hit: BlockHitResult): ActionResult {
|
override fun onUse(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hit: BlockHitResult): ActionResult {
|
||||||
if(state.get(PART) == TubePart.TOP) {
|
if(state.get(PART) == TankPart.TOP) {
|
||||||
// TubeTop isn't reliably up to date on clients, need to look at the bottom half
|
// TankTop isn't reliably up to date on clients, need to look at the bottom half
|
||||||
val tubeBottomPos = pos.down()
|
val tankBottomPos = pos.down()
|
||||||
val tubeBottomState = world.getBlockState(tubeBottomPos)
|
val tankBottomState = world.getBlockState(tankBottomPos)
|
||||||
if(tubeBottomState.block.equals(CobblemonBlocks.FOSSIL_TUBE.asBlock()) && tubeBottomState.get(PART) == TubePart.BOTTOM) {
|
if(tankBottomState.block.equals(CobblemonBlocks.RESTORATION_TANK.asBlock()) && tankBottomState.get(PART) == TankPart.BOTTOM) {
|
||||||
return super.onUse(tubeBottomState, world, tubeBottomPos, player, hand, hit)
|
return super.onUse(tankBottomState, world, tankBottomPos, player, hand, hit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.onUse(state, world, pos, player, hand, hit)
|
return super.onUse(state, world, pos, player, hand, hit)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createMultiBlockEntity(pos: BlockPos, state: BlockState): FossilMultiblockEntity {
|
override fun createMultiBlockEntity(pos: BlockPos, state: BlockState): FossilMultiblockEntity {
|
||||||
return if (state.get(PART) == TubePart.BOTTOM) {
|
return if (state.get(PART) == TankPart.BOTTOM) {
|
||||||
FossilTubeBlockEntity(pos, state, FossilMultiblockBuilder(pos))
|
RestorationTankBlockEntity(pos, state, FossilMultiblockBuilder(pos))
|
||||||
} else {
|
} else {
|
||||||
FossilMultiblockEntity(pos, state, FossilMultiblockBuilder(pos))
|
FossilMultiblockEntity(pos, state, FossilMultiblockBuilder(pos))
|
||||||
}
|
}
|
||||||
@@ -116,7 +119,7 @@ class FossilTubeBlock(properties: Settings) : MultiblockBlock(properties), Inven
|
|||||||
if (world.getBlockState(abovePosition).canReplace(blockPlaceContext) && !world.isOutOfHeightLimit(abovePosition)) {
|
if (world.getBlockState(abovePosition).canReplace(blockPlaceContext) && !world.isOutOfHeightLimit(abovePosition)) {
|
||||||
return defaultState
|
return defaultState
|
||||||
.with(HorizontalFacingBlock.FACING, blockPlaceContext.horizontalPlayerFacing)
|
.with(HorizontalFacingBlock.FACING, blockPlaceContext.horizontalPlayerFacing)
|
||||||
.with(PART, TubePart.BOTTOM)
|
.with(PART, TankPart.BOTTOM)
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
@@ -125,13 +128,13 @@ class FossilTubeBlock(properties: Settings) : MultiblockBlock(properties), Inven
|
|||||||
override fun canPlaceAt(state: BlockState, world: WorldView, pos: BlockPos): Boolean {
|
override fun canPlaceAt(state: BlockState, world: WorldView, pos: BlockPos): Boolean {
|
||||||
val blockPos = pos.down()
|
val blockPos = pos.down()
|
||||||
val blockState = world.getBlockState(blockPos)
|
val blockState = world.getBlockState(blockPos)
|
||||||
return if (state.get(PART) == TubePart.BOTTOM) blockState.isSideSolidFullSquare(world, blockPos, Direction.UP) else blockState.isOf(this)
|
return if (state.get(PART) == TankPart.BOTTOM) true else blockState.isOf(this)
|
||||||
}
|
}
|
||||||
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
|
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
|
||||||
builder.add(HorizontalFacingBlock.FACING)
|
builder.add(HorizontalFacingBlock.FACING)
|
||||||
builder.add(PART)
|
builder.add(PART)
|
||||||
builder.add(TRIGGERED)
|
builder.add(TRIGGERED)
|
||||||
|
builder.add(ON)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated("Deprecated in Java")
|
@Deprecated("Deprecated in Java")
|
||||||
@@ -145,8 +148,8 @@ class FossilTubeBlock(properties: Settings) : MultiblockBlock(properties), Inven
|
|||||||
if(world == null || pos == null) {
|
if(world == null || pos == null) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
val tubeEntity = world.getBlockEntity(pos) as MultiblockEntity
|
val tankEntity = world.getBlockEntity(pos) as MultiblockEntity
|
||||||
val multiBlockEntity = tubeEntity.multiblockStructure
|
val multiBlockEntity = tankEntity.multiblockStructure
|
||||||
if(multiBlockEntity != null) {
|
if(multiBlockEntity != null) {
|
||||||
return multiBlockEntity.getComparatorOutput(state, world, pos)
|
return multiBlockEntity.getComparatorOutput(state, world, pos)
|
||||||
}
|
}
|
||||||
@@ -175,10 +178,8 @@ class FossilTubeBlock(properties: Settings) : MultiblockBlock(properties), Inven
|
|||||||
if(world == null || pos == null) {
|
if(world == null || pos == null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val tubeEntity = world.getBlockEntity(pos) as MultiblockEntity
|
val tankEntity = world.getBlockEntity(pos) as? MultiblockEntity
|
||||||
if (tubeEntity.multiblockStructure != null) {
|
tankEntity?.multiblockStructure!!.onTriggerEvent(state, world, pos, random)
|
||||||
tubeEntity.multiblockStructure!!.onTriggerEvent(state, world, pos, random)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getOutlineShape(
|
override fun getOutlineShape(
|
||||||
@@ -187,7 +188,7 @@ class FossilTubeBlock(properties: Settings) : MultiblockBlock(properties), Inven
|
|||||||
pos: BlockPos?,
|
pos: BlockPos?,
|
||||||
context: ShapeContext?
|
context: ShapeContext?
|
||||||
): VoxelShape {
|
): VoxelShape {
|
||||||
return if (state.get(PART) == TubePart.TOP) {
|
return if (state.get(PART) == TankPart.TOP) {
|
||||||
var shape = VoxelShapes.cuboid(0.0625, 0.0, 0.0625, 0.9375, 0.8125, 0.9375)
|
var shape = VoxelShapes.cuboid(0.0625, 0.0, 0.0625, 0.9375, 0.8125, 0.9375)
|
||||||
shape = VoxelShapes.union(shape, VoxelShapes.cuboid(0.0, 0.8125, 0.0, 1.0, 1.0, 1.0))
|
shape = VoxelShapes.union(shape, VoxelShapes.cuboid(0.0, 0.8125, 0.0, 1.0, 1.0, 1.0))
|
||||||
shape
|
shape
|
||||||
@@ -202,21 +203,22 @@ class FossilTubeBlock(properties: Settings) : MultiblockBlock(properties), Inven
|
|||||||
world: WorldAccess,
|
world: WorldAccess,
|
||||||
pos: BlockPos
|
pos: BlockPos
|
||||||
): SidedInventory {
|
): SidedInventory {
|
||||||
val tubeEntity =
|
val tankEntity =
|
||||||
(if (state.get(PART) == TubePart.TOP) world.getBlockEntity(pos.down())
|
(if (state.get(PART) == TankPart.TOP) world.getBlockEntity(pos.down())
|
||||||
else world.getBlockEntity(pos)) as FossilTubeBlockEntity
|
else world.getBlockEntity(pos)) as RestorationTankBlockEntity
|
||||||
|
|
||||||
return tubeEntity.inv
|
return tankEntity.inv
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class TubePart(private val label: String) : StringIdentifiable {
|
enum class TankPart(private val label: String) : StringIdentifiable {
|
||||||
TOP("top"),
|
TOP("top"),
|
||||||
BOTTOM("bottom");
|
BOTTOM("bottom");
|
||||||
override fun asString() = label
|
override fun asString() = label
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val PART = EnumProperty.of("part", TubePart::class.java)
|
val PART = EnumProperty.of("part", TankPart::class.java)
|
||||||
val TRIGGERED = Properties.TRIGGERED
|
val TRIGGERED = Properties.TRIGGERED
|
||||||
|
val ON = BooleanProperty.of("on")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
package com.cobblemon.mod.common.block
|
package com.cobblemon.mod.common.block
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.api.tags.CobblemonBlockTags
|
||||||
import net.minecraft.block.*
|
import net.minecraft.block.*
|
||||||
import net.minecraft.item.ItemPlacementContext
|
import net.minecraft.item.ItemPlacementContext
|
||||||
import net.minecraft.server.world.ServerWorld
|
import net.minecraft.server.world.ServerWorld
|
||||||
@@ -20,125 +21,15 @@ import net.minecraft.world.BlockView
|
|||||||
import net.minecraft.world.WorldAccess
|
import net.minecraft.world.WorldAccess
|
||||||
import net.minecraft.world.WorldView
|
import net.minecraft.world.WorldView
|
||||||
|
|
||||||
|
|
||||||
@Suppress("DEPRECATION", "OVERRIDE_DEPRECATION")
|
@Suppress("DEPRECATION", "OVERRIDE_DEPRECATION")
|
||||||
class TumblestoneBlock(
|
class TumblestoneBlock(
|
||||||
settings: Settings,
|
settings: Settings,
|
||||||
val stage: Int,
|
stage: Int,
|
||||||
val height: Int,
|
height: Int,
|
||||||
xzOffset: Int,
|
xzOffset: Int,
|
||||||
val nextStage: Block?
|
nextStage: Block?
|
||||||
) : FacingBlock(settings) {
|
) : GrowableStoneBlock(settings, stage, height, xzOffset, nextStage) {
|
||||||
|
override fun canGrow(pos: BlockPos, world: BlockView): Boolean {
|
||||||
private val upShape: VoxelShape = Block.createCuboidShape(
|
|
||||||
xzOffset.toDouble(),
|
|
||||||
0.0,
|
|
||||||
xzOffset.toDouble(),
|
|
||||||
(16 - xzOffset).toDouble(),
|
|
||||||
height.toDouble(),
|
|
||||||
(16 - xzOffset).toDouble())
|
|
||||||
|
|
||||||
private val downShape: VoxelShape = createCuboidShape(
|
|
||||||
xzOffset.toDouble(),
|
|
||||||
(16 - height).toDouble(),
|
|
||||||
xzOffset.toDouble(),
|
|
||||||
(16 - xzOffset).toDouble(),
|
|
||||||
16.0,
|
|
||||||
(16 - xzOffset).toDouble())
|
|
||||||
|
|
||||||
private val northShape: VoxelShape = createCuboidShape(
|
|
||||||
xzOffset.toDouble(),
|
|
||||||
xzOffset.toDouble(),
|
|
||||||
(16 - height).toDouble(),
|
|
||||||
(16 - xzOffset).toDouble(),
|
|
||||||
(16 - xzOffset).toDouble(),
|
|
||||||
16.0)
|
|
||||||
|
|
||||||
private val southShape: VoxelShape = createCuboidShape(
|
|
||||||
xzOffset.toDouble(),
|
|
||||||
xzOffset.toDouble(),
|
|
||||||
0.0,
|
|
||||||
(16 - xzOffset).toDouble(),
|
|
||||||
(16 - xzOffset).toDouble(),
|
|
||||||
height.toDouble())
|
|
||||||
|
|
||||||
private val eastShape: VoxelShape = createCuboidShape(
|
|
||||||
0.0,
|
|
||||||
xzOffset.toDouble(),
|
|
||||||
xzOffset.toDouble(),
|
|
||||||
height.toDouble(),
|
|
||||||
(16 - xzOffset).toDouble(),
|
|
||||||
(16 - xzOffset).toDouble())
|
|
||||||
|
|
||||||
private val westShape: VoxelShape = createCuboidShape(
|
|
||||||
(16 - height).toDouble(),
|
|
||||||
xzOffset.toDouble(),
|
|
||||||
xzOffset.toDouble(),
|
|
||||||
16.0,
|
|
||||||
(16 - xzOffset).toDouble(),
|
|
||||||
(16 - xzOffset).toDouble())
|
|
||||||
|
|
||||||
init {
|
|
||||||
this.defaultState = this.stateManager.defaultState
|
|
||||||
.with(FACING, Direction.DOWN)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
|
|
||||||
builder.add(FACING)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hasRandomTicks(state: BlockState?) = stage < MAX_STAGE
|
|
||||||
override fun randomTick(state: BlockState, world: ServerWorld, pos: BlockPos, random: Random) {
|
|
||||||
if (world.random.nextInt(5) == 0 && canGrow(pos, world)) {
|
|
||||||
val block = nextStage
|
|
||||||
|
|
||||||
if (block != null) {
|
|
||||||
val newState = block.defaultState.with(FACING, state.get(FACING)) as BlockState
|
|
||||||
world.setBlockState(pos, newState)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getPlacementState(ctx: ItemPlacementContext): BlockState? {
|
|
||||||
var blockState = defaultState
|
|
||||||
val worldView = ctx.world
|
|
||||||
val blockPos = ctx.blockPos
|
|
||||||
blockState = blockState.with(FACING, ctx.side) as BlockState
|
|
||||||
if (blockState.canPlaceAt(worldView, blockPos)) {
|
|
||||||
return blockState
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canPlaceAt(state: BlockState, world: WorldView, pos: BlockPos): Boolean {
|
|
||||||
val direction = state.get(FACING) as Direction
|
|
||||||
val blockState = world.getBlockState(pos.offset(direction.opposite))
|
|
||||||
return blockState.isSideSolidFullSquare(world, pos, direction)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getStateForNeighborUpdate(state: BlockState, direction: Direction, neighborState: BlockState, world: WorldAccess, pos: BlockPos, neighborPos: BlockPos): BlockState? {
|
|
||||||
return if (direction == state.get(FACING).opposite && !state.canPlaceAt(world, pos)) Blocks.AIR.defaultState
|
|
||||||
else super.getStateForNeighborUpdate(state, direction, neighborState, world, pos, neighborPos)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getOutlineShape(state: BlockState, world: BlockView, pos: BlockPos, context: ShapeContext): VoxelShape {
|
|
||||||
val direction = state.get(FACING) as Direction
|
|
||||||
return when (direction) {
|
|
||||||
Direction.NORTH -> northShape
|
|
||||||
Direction.SOUTH -> southShape
|
|
||||||
Direction.EAST -> eastShape
|
|
||||||
Direction.WEST -> westShape
|
|
||||||
Direction.DOWN -> downShape
|
|
||||||
Direction.UP -> upShape
|
|
||||||
else -> upShape
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isValidGrowthBlock(block: Block): Boolean {
|
|
||||||
return block == Blocks.MAGMA_BLOCK || block == Blocks.LAVA
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun canGrow(pos: BlockPos, world: BlockView): Boolean {
|
|
||||||
if (stage == MAX_STAGE) return false
|
if (stage == MAX_STAGE) return false
|
||||||
val iterator: Iterator<BlockPos> =
|
val iterator: Iterator<BlockPos> =
|
||||||
BlockPos.iterate(pos.add(-1, -1, -1), pos.add(1, 1, 1))
|
BlockPos.iterate(pos.add(-1, -1, -1), pos.add(1, 1, 1))
|
||||||
@@ -147,18 +38,9 @@ class TumblestoneBlock(
|
|||||||
var blockPos: BlockPos
|
var blockPos: BlockPos
|
||||||
do { if (!iterator.hasNext()) { return false }
|
do { if (!iterator.hasNext()) { return false }
|
||||||
blockPos = iterator.next()
|
blockPos = iterator.next()
|
||||||
} while (!isValidGrowthBlock(world.getBlockState(blockPos).block))
|
} while (!world.getBlockState(blockPos).isIn(CobblemonBlockTags.TUMBLESTONE_HEAT_SOURCE))
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val STAGE_0 = 0
|
|
||||||
const val STAGE_1 = 1
|
|
||||||
const val STAGE_2 = 2
|
|
||||||
const val STAGE_3 = 3
|
|
||||||
|
|
||||||
const val MAX_STAGE = STAGE_3
|
|
||||||
const val MIN_STAGE = STAGE_0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Cobblemon Contributors
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.cobblemon.mod.common.block.entity
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.CobblemonBlockEntities
|
||||||
|
import net.minecraft.block.BlockState
|
||||||
|
import net.minecraft.block.entity.BlockEntity
|
||||||
|
import net.minecraft.block.entity.BlockEntityTicker
|
||||||
|
import net.minecraft.util.math.BlockPos
|
||||||
|
|
||||||
|
class DyniteOreBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(CobblemonBlockEntities.DYNITE_ORE, pos, state) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
internal val TICKER = BlockEntityTicker<DyniteOreBlockEntity> { world, pos, state, blockEntity ->
|
||||||
|
if (world.isClient) return@BlockEntityTicker
|
||||||
|
// idk if i'll actually need this but i already made it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+12
-12
@@ -6,7 +6,7 @@
|
|||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.cobblemon.mod.common.block.entity.fossil
|
package com.cobblemon.mod.common.block.entity
|
||||||
|
|
||||||
import com.cobblemon.mod.common.Cobblemon
|
import com.cobblemon.mod.common.Cobblemon
|
||||||
import com.cobblemon.mod.common.CobblemonBlockEntities
|
import com.cobblemon.mod.common.CobblemonBlockEntities
|
||||||
@@ -20,14 +20,14 @@ import net.minecraft.item.ItemStack
|
|||||||
import net.minecraft.util.math.BlockPos
|
import net.minecraft.util.math.BlockPos
|
||||||
import net.minecraft.util.math.Direction
|
import net.minecraft.util.math.Direction
|
||||||
|
|
||||||
class FossilCompartmentBlockEntity(
|
class FossilAnalyzerBlockEntity(
|
||||||
pos: BlockPos, state: BlockState,
|
pos: BlockPos, state: BlockState,
|
||||||
multiblockBuilder: MultiblockStructureBuilder
|
multiblockBuilder: MultiblockStructureBuilder
|
||||||
): FossilMultiblockEntity(pos, state, multiblockBuilder, CobblemonBlockEntities.FOSSIL_COMPARTMENT) {
|
): FossilMultiblockEntity(pos, state, multiblockBuilder, CobblemonBlockEntities.FOSSIL_ANALYZER) {
|
||||||
|
|
||||||
val inv = FossilCompartmentInventory(this)
|
val inv = FossilAnalyzerInventory(this)
|
||||||
|
|
||||||
class FossilCompartmentInventory(val compartmentEntity: FossilCompartmentBlockEntity) : SidedInventory {
|
class FossilAnalyzerInventory(val analyzerEntity: FossilAnalyzerBlockEntity) : SidedInventory {
|
||||||
override fun clear() {
|
override fun clear() {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
@@ -53,17 +53,17 @@ class FossilCompartmentBlockEntity(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun setStack(slot: Int, stack: ItemStack) {
|
override fun setStack(slot: Int, stack: ItemStack) {
|
||||||
if (compartmentEntity.multiblockStructure != null) {
|
if (analyzerEntity.multiblockStructure != null) {
|
||||||
val struct = compartmentEntity.multiblockStructure as FossilMultiblockStructure
|
val struct = analyzerEntity.multiblockStructure as FossilMultiblockStructure
|
||||||
compartmentEntity.world?.let {
|
analyzerEntity.world?.let {
|
||||||
struct.insertFossil(stack, it)
|
struct.insertFossil(stack, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun markDirty() {
|
override fun markDirty() {
|
||||||
if (compartmentEntity.world != null) {
|
if (analyzerEntity.world != null) {
|
||||||
compartmentEntity.multiblockStructure?.markDirty(compartmentEntity.world!!)
|
analyzerEntity.multiblockStructure?.markDirty(analyzerEntity.world!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,8 +76,8 @@ class FossilCompartmentBlockEntity(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun canInsert(slot: Int, stack: ItemStack?, dir: Direction?): Boolean {
|
override fun canInsert(slot: Int, stack: ItemStack?, dir: Direction?): Boolean {
|
||||||
if (compartmentEntity.multiblockStructure is FossilMultiblockStructure) {
|
if (analyzerEntity.multiblockStructure is FossilMultiblockStructure) {
|
||||||
val structure = compartmentEntity.multiblockStructure as FossilMultiblockStructure
|
val structure = analyzerEntity.multiblockStructure as FossilMultiblockStructure
|
||||||
return stack?.let { Fossils.isFossilIngredient(it) } == true
|
return stack?.let { Fossils.isFossilIngredient(it) } == true
|
||||||
&& structure.fossilInventory.size < Cobblemon.config.maxInsertedFossilItems
|
&& structure.fossilInventory.size < Cobblemon.config.maxInsertedFossilItems
|
||||||
&& structure.isRunning() == false && structure.resultingFossil == null
|
&& structure.isRunning() == false && structure.resultingFossil == null
|
||||||
+18
-2
@@ -6,7 +6,7 @@
|
|||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.cobblemon.mod.common.block.entity.fossil
|
package com.cobblemon.mod.common.block.entity
|
||||||
|
|
||||||
import com.cobblemon.mod.common.CobblemonBlockEntities
|
import com.cobblemon.mod.common.CobblemonBlockEntities
|
||||||
import com.cobblemon.mod.common.api.multiblock.MultiblockEntity
|
import com.cobblemon.mod.common.api.multiblock.MultiblockEntity
|
||||||
@@ -47,9 +47,25 @@ open class FossilMultiblockEntity(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun markRemoved() {
|
||||||
|
super.markRemoved()
|
||||||
|
if(this.multiblockStructure != null && world != null) {
|
||||||
|
this.multiblockStructure!!.markRemoved(world!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun readNbt(nbt: NbtCompound) {
|
override fun readNbt(nbt: NbtCompound) {
|
||||||
|
val oldMultiblockStructure = this.multiblockStructure as? FossilMultiblockStructure
|
||||||
multiblockStructure = if (nbt.contains(DataKeys.MULTIBLOCK_STORAGE)) {
|
multiblockStructure = if (nbt.contains(DataKeys.MULTIBLOCK_STORAGE)) {
|
||||||
FossilMultiblockStructure.fromNbt(nbt.getCompound(DataKeys.MULTIBLOCK_STORAGE))
|
if(oldMultiblockStructure?.fossilState != null) {
|
||||||
|
// Copy the fossilState's previous animation time to the new instance
|
||||||
|
// Otherwise the fetus animation gets interrupted on every block update
|
||||||
|
val animAge = oldMultiblockStructure.fossilState.peekAge() // If someone knows a better way to fetch the age, please do.
|
||||||
|
val partialTicks = oldMultiblockStructure.fossilState.getPartialTicks()
|
||||||
|
FossilMultiblockStructure.fromNbt(nbt.getCompound(DataKeys.MULTIBLOCK_STORAGE), animAge, partialTicks )
|
||||||
|
} else {
|
||||||
|
FossilMultiblockStructure.fromNbt(nbt.getCompound(DataKeys.MULTIBLOCK_STORAGE))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
+152
@@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Cobblemon Contributors
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.cobblemon.mod.common.block.entity
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.CobblemonBlockEntities
|
||||||
|
import com.cobblemon.mod.common.api.fossil.NaturalMaterials
|
||||||
|
import com.cobblemon.mod.common.api.multiblock.builder.MultiblockStructureBuilder
|
||||||
|
import com.cobblemon.mod.common.block.multiblock.FossilMultiblockStructure
|
||||||
|
import net.minecraft.block.BlockState
|
||||||
|
import net.minecraft.entity.player.PlayerEntity
|
||||||
|
import net.minecraft.inventory.Inventories
|
||||||
|
import net.minecraft.inventory.SidedInventory
|
||||||
|
import net.minecraft.item.Item
|
||||||
|
import net.minecraft.item.ItemStack
|
||||||
|
import net.minecraft.nbt.NbtCompound
|
||||||
|
import net.minecraft.registry.Registries
|
||||||
|
import net.minecraft.util.collection.DefaultedList
|
||||||
|
import net.minecraft.util.math.BlockPos
|
||||||
|
import net.minecraft.util.math.Direction
|
||||||
|
|
||||||
|
class RestorationTankBlockEntity(
|
||||||
|
pos: BlockPos, state: BlockState,
|
||||||
|
multiblockBuilder: MultiblockStructureBuilder
|
||||||
|
) : FossilMultiblockEntity(pos, state, multiblockBuilder, CobblemonBlockEntities.RESTORATION_TANK) {
|
||||||
|
val inv = RestorationTankInventory(this)
|
||||||
|
|
||||||
|
override fun writeNbt(nbt: NbtCompound) {
|
||||||
|
super.writeNbt(nbt)
|
||||||
|
Inventories.writeNbt(nbt, inv.items)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun readNbt(nbt: NbtCompound) {
|
||||||
|
super.readNbt(nbt)
|
||||||
|
Inventories.readNbt(nbt, inv.items)
|
||||||
|
}
|
||||||
|
|
||||||
|
class RestorationTankInventory(val tankEntity: RestorationTankBlockEntity) : SidedInventory {
|
||||||
|
|
||||||
|
val items: DefaultedList<ItemStack> = DefaultedList.ofSize(8, ItemStack.EMPTY)
|
||||||
|
|
||||||
|
|
||||||
|
override fun clear() {
|
||||||
|
for (i in items.indices) {
|
||||||
|
items[i] = ItemStack.EMPTY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun size(): Int {
|
||||||
|
return 8
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isEmpty(): Boolean {
|
||||||
|
return items.all { it == ItemStack.EMPTY }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getStack(slot: Int): ItemStack {
|
||||||
|
if(slot == -1 || slot >= size()) {
|
||||||
|
return ItemStack.EMPTY
|
||||||
|
}
|
||||||
|
return items[slot]
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeStack(slot: Int, amount: Int): ItemStack {
|
||||||
|
if(slot < 0 || slot >= size()) {
|
||||||
|
return ItemStack.EMPTY
|
||||||
|
}
|
||||||
|
val result = items[slot].split(amount)
|
||||||
|
if(items[slot].count == 0) {
|
||||||
|
items[slot] = ItemStack.EMPTY
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeStack(slot: Int): ItemStack {
|
||||||
|
return removeStack(slot, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setStack(slot: Int, stack: ItemStack) {
|
||||||
|
val struct = tankEntity.multiblockStructure as? FossilMultiblockStructure
|
||||||
|
tankEntity.world?.let {
|
||||||
|
struct?.insertOrganicMaterial(stack, it)
|
||||||
|
val returnIdentifier = NaturalMaterials.getReturnItem((stack))
|
||||||
|
if(returnIdentifier != null ) {
|
||||||
|
// Store the return item
|
||||||
|
val returnItem = Registries.ITEM.get(returnIdentifier)
|
||||||
|
storeReturnItem(returnItem, stack.count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun storeReturnItem(returnItem: Item, count: Int) {
|
||||||
|
val destStack = items.withIndex().firstOrNull {
|
||||||
|
it.value == ItemStack.EMPTY || (it.value.count < it.value.maxCount && it.value.item == returnItem)
|
||||||
|
}
|
||||||
|
if (destStack != null) {
|
||||||
|
if(destStack.value == ItemStack.EMPTY) {
|
||||||
|
items[destStack.index] = ItemStack(returnItem, 1)
|
||||||
|
} else {
|
||||||
|
destStack.value.increment(count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun markDirty() {
|
||||||
|
tankEntity.world?.let {
|
||||||
|
tankEntity.multiblockStructure?.markDirty(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canPlayerUse(player: PlayerEntity?): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAvailableSlots(side: Direction?): IntArray {
|
||||||
|
return if(side == Direction.DOWN) intArrayOf(0,1,2,3,4,5,6,7) else intArrayOf(-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canInsert(slot: Int, stack: ItemStack?, dir: Direction?): Boolean {
|
||||||
|
if (tankEntity.multiblockStructure is FossilMultiblockStructure) {
|
||||||
|
if(dir != Direction.DOWN) {
|
||||||
|
val structure = tankEntity.multiblockStructure as FossilMultiblockStructure
|
||||||
|
val canUtilize = stack?.let { NaturalMaterials.isNaturalMaterial(it) } == true
|
||||||
|
&& structure.organicMaterialInside < FossilMultiblockStructure.MATERIAL_TO_START
|
||||||
|
&& structure.createdPokemon == null
|
||||||
|
val returnItem = NaturalMaterials.getReturnItem(stack!!) ?: return false
|
||||||
|
if(canUtilize) {
|
||||||
|
// See if there's room
|
||||||
|
for (i in items.indices ) {
|
||||||
|
if(items[i] == ItemStack.EMPTY || (items[i].count < items[i].maxCount
|
||||||
|
&& items[i].item == Registries.ITEM.get(returnItem))) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canExtract(slot: Int, stack: ItemStack?, dir: Direction?): Boolean {
|
||||||
|
return dir == Direction.DOWN && slot >= 0 && slot < size()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
-97
@@ -1,97 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2023 Cobblemon Contributors
|
|
||||||
*
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.cobblemon.mod.common.block.entity.fossil
|
|
||||||
|
|
||||||
import com.cobblemon.mod.common.CobblemonBlockEntities
|
|
||||||
import com.cobblemon.mod.common.api.fossil.NaturalMaterials
|
|
||||||
import com.cobblemon.mod.common.api.multiblock.builder.MultiblockStructureBuilder
|
|
||||||
import com.cobblemon.mod.common.block.multiblock.FossilMultiblockStructure
|
|
||||||
import com.cobblemon.mod.common.client.render.models.blockbench.fossil.FossilState
|
|
||||||
import com.cobblemon.mod.common.util.DataKeys
|
|
||||||
import net.minecraft.block.BlockState
|
|
||||||
import net.minecraft.entity.player.PlayerEntity
|
|
||||||
import net.minecraft.inventory.SidedInventory
|
|
||||||
import net.minecraft.item.ItemStack
|
|
||||||
import net.minecraft.nbt.NbtCompound
|
|
||||||
import net.minecraft.network.listener.ClientPlayPacketListener
|
|
||||||
import net.minecraft.network.packet.Packet
|
|
||||||
import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket
|
|
||||||
import net.minecraft.util.math.BlockPos
|
|
||||||
import net.minecraft.util.math.Direction
|
|
||||||
|
|
||||||
class FossilTubeBlockEntity(
|
|
||||||
pos: BlockPos, state: BlockState,
|
|
||||||
multiblockBuilder: MultiblockStructureBuilder
|
|
||||||
) : FossilMultiblockEntity(pos, state, multiblockBuilder, CobblemonBlockEntities.FOSSIL_TUBE) {
|
|
||||||
val inv = FossilTubeInventory(this)
|
|
||||||
|
|
||||||
class FossilTubeInventory(val tubeEntity: FossilTubeBlockEntity) : SidedInventory {
|
|
||||||
override fun clear() {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun size(): Int {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isEmpty(): Boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getStack(slot: Int): ItemStack {
|
|
||||||
return ItemStack.EMPTY
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun removeStack(slot: Int, amount: Int): ItemStack {
|
|
||||||
return ItemStack.EMPTY
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun removeStack(slot: Int): ItemStack {
|
|
||||||
return ItemStack.EMPTY
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setStack(slot: Int, stack: ItemStack) {
|
|
||||||
if (tubeEntity.multiblockStructure != null) {
|
|
||||||
val struct = tubeEntity.multiblockStructure as FossilMultiblockStructure
|
|
||||||
tubeEntity.world?.let {
|
|
||||||
struct.insertOrganicMaterial(stack, it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun markDirty() {
|
|
||||||
if (tubeEntity.world != null) {
|
|
||||||
tubeEntity.multiblockStructure?.markDirty(tubeEntity.world!!)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canPlayerUse(player: PlayerEntity?): Boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getAvailableSlots(side: Direction?): IntArray {
|
|
||||||
return IntArray(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canInsert(slot: Int, stack: ItemStack?, dir: Direction?): Boolean {
|
|
||||||
if (tubeEntity.multiblockStructure is FossilMultiblockStructure) {
|
|
||||||
val structure = tubeEntity.multiblockStructure as FossilMultiblockStructure
|
|
||||||
return stack?.let { NaturalMaterials.isNaturalMaterial(it) } == true
|
|
||||||
&& structure.organicMaterialInside < FossilMultiblockStructure.MATERIAL_TO_START
|
|
||||||
&& structure.createdPokemon == null
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canExtract(slot: Int, stack: ItemStack?, dir: Direction?): Boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+50
-53
@@ -13,11 +13,8 @@ import com.cobblemon.mod.common.CobblemonBlocks
|
|||||||
import com.cobblemon.mod.common.CobblemonSounds
|
import com.cobblemon.mod.common.CobblemonSounds
|
||||||
import com.cobblemon.mod.common.api.multiblock.MultiblockEntity
|
import com.cobblemon.mod.common.api.multiblock.MultiblockEntity
|
||||||
import com.cobblemon.mod.common.api.multiblock.builder.MultiblockStructureBuilder
|
import com.cobblemon.mod.common.api.multiblock.builder.MultiblockStructureBuilder
|
||||||
import com.cobblemon.mod.common.block.entity.fossil.FossilTubeBlockEntity
|
import com.cobblemon.mod.common.block.RestorationTankBlock
|
||||||
import com.cobblemon.mod.common.block.fossilmachine.FossilCompartmentBlock
|
|
||||||
import com.cobblemon.mod.common.block.fossilmachine.FossilTubeBlock
|
|
||||||
import com.cobblemon.mod.common.api.multiblock.condition.BlockRelativeCondition
|
import com.cobblemon.mod.common.api.multiblock.condition.BlockRelativeCondition
|
||||||
import com.cobblemon.mod.common.block.entity.fossil.FossilCompartmentBlockEntity
|
|
||||||
import com.cobblemon.mod.common.util.DataKeys
|
import com.cobblemon.mod.common.util.DataKeys
|
||||||
import com.cobblemon.mod.common.util.blockPositionsAsList
|
import com.cobblemon.mod.common.util.blockPositionsAsList
|
||||||
import net.minecraft.nbt.NbtCompound
|
import net.minecraft.nbt.NbtCompound
|
||||||
@@ -53,13 +50,13 @@ class FossilMultiblockBuilder(val centerPos: BlockPos) : MultiblockStructureBuil
|
|||||||
|
|
||||||
override val conditions = listOf(
|
override val conditions = listOf(
|
||||||
BlockRelativeCondition(
|
BlockRelativeCondition(
|
||||||
FOSSIL_COMPARTMENT_PRED,
|
FOSSIL_ANALYZER_PRED,
|
||||||
FOSSIL_MONITOR_PRED,
|
MONITOR_PRED,
|
||||||
arrayOf(Direction.UP)
|
arrayOf(Direction.UP)
|
||||||
),
|
),
|
||||||
BlockRelativeCondition(
|
BlockRelativeCondition(
|
||||||
FOSSIL_COMPARTMENT_PRED,
|
FOSSIL_ANALYZER_PRED,
|
||||||
FOSSIL_TUBE_PRED,
|
RESTORATION_TANK_PRED,
|
||||||
arrayOf(Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST)
|
arrayOf(Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -72,68 +69,68 @@ class FossilMultiblockBuilder(val centerPos: BlockPos) : MultiblockStructureBuil
|
|||||||
The process of identifying the constituent blocks is a bit of a clusterfuck so here's an explanation
|
The process of identifying the constituent blocks is a bit of a clusterfuck so here's an explanation
|
||||||
|
|
||||||
1. We find all of the monitors in the boundingBox
|
1. We find all of the monitors in the boundingBox
|
||||||
2. We map those positions to a new list representing valid compartment positions
|
2. We map those positions to a new list representing valid analyzer positions
|
||||||
(This is where it starts getting complicated) We want valid compartment positions, but we
|
(This is where it starts getting complicated) We want valid analyzer positions, but we
|
||||||
need to remember the index in the monitor position list that each compartment is valid for.
|
need to remember the index in the monitor position list that each analyzer is valid for.
|
||||||
So basically we take the monitor positions, check if they have a compartment underneath.
|
So basically we take the monitor positions, check if they have a analyzer underneath.
|
||||||
If they do, set the element in the NEW list to be the position of the compartment.
|
If they do, set the element in the NEW list to be the position of the analyzer.
|
||||||
If they dont, set the element in the new list to be null
|
If they don't, set the element in the new list to be null
|
||||||
3. Do a similar process for tubes.
|
3. Do a similar process for tanks.
|
||||||
(Make a copy of the compartment positions, set them to the tube position if theres a tube, null if not)
|
(Make a copy of the analyzer positions, set them to the tank position if there's a tank, null if not)
|
||||||
|
|
||||||
What this ends up doing is giving us a list at the end filled with either nulls or BlockPositions
|
What this ends up doing is giving us a list at the end filled with either nulls or BlockPositions
|
||||||
of tubes that have a valid structure. The index of any tube in the list corresponds to the index
|
of tanks that have a valid structure. The index of any tank in the list corresponds to the index
|
||||||
of the Monitor/Compartment in their respective lists. So if you have a fossilTubePositions list of
|
of the Monitor/Analyzer in their respective lists. So if you have a fossilTankPositions list of
|
||||||
[null BlockPos null], the fossilCompartment BlockPos is fossilCompPositions[1] and the monitor BlockPos
|
[null BlockPos null], the fossilAnalyzer BlockPos is fossilCompPositions[1] and the monitor BlockPos
|
||||||
is fossilMonitorPositions[1]
|
is monitorPositions[1]
|
||||||
|
|
||||||
- Apion
|
- Apion
|
||||||
*/
|
*/
|
||||||
var fossilMonitorPositions = blocks.filter {
|
var monitorPositions = blocks.filter {
|
||||||
FOSSIL_MONITOR_PRED.test(world, it)
|
MONITOR_PRED.test(world, it)
|
||||||
}
|
}
|
||||||
|
|
||||||
var fossilCompPositions = fossilMonitorPositions.map {
|
var fossilAnalyzerPositions = monitorPositions.map {
|
||||||
if (FOSSIL_COMPARTMENT_PRED.test(world, it.down())) it.down()
|
if (FOSSIL_ANALYZER_PRED.test(world, it.down())) it.down()
|
||||||
else null
|
else null
|
||||||
}
|
}
|
||||||
|
|
||||||
var fossilTubePositions = fossilCompPositions.map { compPosition ->
|
var restorationTankPositions = fossilAnalyzerPositions.map { analyzerPosition ->
|
||||||
if (compPosition == null) {
|
if (analyzerPosition == null) {
|
||||||
return@map null
|
return@map null
|
||||||
}
|
}
|
||||||
dirsToCheck.forEach {
|
dirsToCheck.forEach {
|
||||||
if (FOSSIL_TUBE_PRED.test(world, compPosition.offset(it))) {
|
if (RESTORATION_TANK_PRED.test(world, analyzerPosition.offset(it))) {
|
||||||
return@map compPosition.offset(it)
|
return@map analyzerPosition.offset(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return@map null
|
return@map null
|
||||||
}
|
}
|
||||||
|
|
||||||
val fossilTubeIndex = fossilTubePositions.indexOfFirst {
|
val fossilTankIndex = restorationTankPositions.indexOfFirst {
|
||||||
it != null
|
it != null
|
||||||
}
|
}
|
||||||
if (fossilTubeIndex == -1) {
|
if (fossilTankIndex == -1) {
|
||||||
Cobblemon.LOGGER.error("FossilMultiblockBuilder form called on invalid structure! This should never happen!")
|
Cobblemon.LOGGER.error("FossilMultiblockBuilder form called on invalid structure! This should never happen!")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val fossilMonitorPos = fossilMonitorPositions[fossilTubeIndex]
|
val monitorPos = monitorPositions[fossilTankIndex]
|
||||||
val fossilCompPos = fossilCompPositions[fossilTubeIndex]!!
|
val fossilAnalyzerPos = fossilAnalyzerPositions[fossilTankIndex]!!
|
||||||
val fossilTubePos = fossilTubePositions[fossilTubeIndex]!!
|
val restorationTankPos = restorationTankPositions[fossilTankIndex]!!
|
||||||
val monitorEntity = world.getBlockEntity(fossilMonitorPos) as MultiblockEntity
|
val monitorEntity = world.getBlockEntity(monitorPos) as MultiblockEntity
|
||||||
val compEntity = world.getBlockEntity(fossilCompPos) as MultiblockEntity
|
val analyzerEntity = world.getBlockEntity(fossilAnalyzerPos) as MultiblockEntity
|
||||||
val tubeBaseEntity = world.getBlockEntity(fossilTubePos) as MultiblockEntity
|
val tankBaseEntity = world.getBlockEntity(restorationTankPos) as MultiblockEntity
|
||||||
val tubeTopEntity = world.getBlockEntity(fossilTubePos.up()) as MultiblockEntity
|
val tankTopEntity = world.getBlockEntity(restorationTankPos.up()) as MultiblockEntity
|
||||||
val structure = FossilMultiblockStructure(fossilMonitorPos, fossilCompPos, fossilTubePos)
|
val structure = FossilMultiblockStructure(monitorPos, fossilAnalyzerPos, restorationTankPos)
|
||||||
|
|
||||||
structure.tubeConnectorDirection = dirsToCheck.filter {
|
structure.tankConnectorDirection = dirsToCheck.filter {
|
||||||
val adjPos = fossilTubePos.offset(it)
|
val adjPos = restorationTankPos.offset(it)
|
||||||
return@filter adjPos == fossilCompPos
|
return@filter adjPos == fossilAnalyzerPos
|
||||||
}.first()
|
}.first()
|
||||||
|
|
||||||
compEntity.multiblockStructure = structure
|
analyzerEntity.multiblockStructure = structure
|
||||||
tubeBaseEntity.multiblockStructure = structure
|
tankBaseEntity.multiblockStructure = structure
|
||||||
tubeTopEntity.multiblockStructure = structure
|
tankTopEntity.multiblockStructure = structure
|
||||||
monitorEntity.multiblockStructure = structure
|
monitorEntity.multiblockStructure = structure
|
||||||
structure.syncToClient(world)
|
structure.syncToClient(world)
|
||||||
structure.markDirty(world)
|
structure.markDirty(world)
|
||||||
@@ -141,9 +138,9 @@ class FossilMultiblockBuilder(val centerPos: BlockPos) : MultiblockStructureBuil
|
|||||||
world.playSound(null, centerPos, CobblemonSounds.FOSSIL_MACHINE_ASSEMBLE, SoundCategory.BLOCKS)
|
world.playSound(null, centerPos, CobblemonSounds.FOSSIL_MACHINE_ASSEMBLE, SoundCategory.BLOCKS)
|
||||||
|
|
||||||
//Set these to null so the builders can be freed
|
//Set these to null so the builders can be freed
|
||||||
compEntity.multiblockBuilder = null
|
analyzerEntity.multiblockBuilder = null
|
||||||
tubeBaseEntity.multiblockBuilder = null
|
tankBaseEntity.multiblockBuilder = null
|
||||||
tubeTopEntity.multiblockBuilder = null
|
tankTopEntity.multiblockBuilder = null
|
||||||
monitorEntity.multiblockBuilder = null
|
monitorEntity.multiblockBuilder = null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,18 +150,18 @@ class FossilMultiblockBuilder(val centerPos: BlockPos) : MultiblockStructureBuil
|
|||||||
nbt.putBoolean(DataKeys.FORMED, false)
|
nbt.putBoolean(DataKeys.FORMED, false)
|
||||||
return@run nbt
|
return@run nbt
|
||||||
}
|
}
|
||||||
val FOSSIL_MONITOR_PRED = BlockPredicate.Builder.create().blocks(CobblemonBlocks.FOSSIL_MONITOR)
|
val MONITOR_PRED = BlockPredicate.Builder.create().blocks(CobblemonBlocks.MONITOR)
|
||||||
.nbt(NBT_TO_CHECK)
|
.nbt(NBT_TO_CHECK)
|
||||||
.build()
|
.build()
|
||||||
val FOSSIL_COMPARTMENT_PRED = BlockPredicate.Builder.create()
|
val FOSSIL_ANALYZER_PRED = BlockPredicate.Builder.create()
|
||||||
.blocks(CobblemonBlocks.FOSSIL_COMPARTMENT)
|
.blocks(CobblemonBlocks.FOSSIL_ANALYZER)
|
||||||
.nbt(NBT_TO_CHECK)
|
.nbt(NBT_TO_CHECK)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
val FOSSIL_TUBE_PRED = BlockPredicate.Builder.create()
|
val RESTORATION_TANK_PRED = BlockPredicate.Builder.create()
|
||||||
.nbt(NBT_TO_CHECK)
|
.nbt(NBT_TO_CHECK)
|
||||||
.blocks(CobblemonBlocks.FOSSIL_TUBE)
|
.blocks(CobblemonBlocks.RESTORATION_TANK)
|
||||||
.state(StatePredicate.Builder.create().exactMatch(FossilTubeBlock.PART, FossilTubeBlock.TubePart.BOTTOM).build())
|
.state(StatePredicate.Builder.create().exactMatch(RestorationTankBlock.PART, RestorationTankBlock.TankPart.BOTTOM).build())
|
||||||
.build()
|
.build()
|
||||||
//lol thanks mojang for not allowing nbt puts to be chained
|
//lol thanks mojang for not allowing nbt puts to be chained
|
||||||
}
|
}
|
||||||
|
|||||||
+144
-75
@@ -17,22 +17,22 @@ import com.cobblemon.mod.common.api.fossil.NaturalMaterials
|
|||||||
import com.cobblemon.mod.common.api.multiblock.MultiblockEntity
|
import com.cobblemon.mod.common.api.multiblock.MultiblockEntity
|
||||||
import com.cobblemon.mod.common.api.multiblock.MultiblockStructure
|
import com.cobblemon.mod.common.api.multiblock.MultiblockStructure
|
||||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||||
import com.cobblemon.mod.common.block.entity.fossil.FossilMultiblockEntity
|
import com.cobblemon.mod.common.block.entity.FossilMultiblockEntity
|
||||||
import com.cobblemon.mod.common.block.fossilmachine.FossilCompartmentBlock
|
import com.cobblemon.mod.common.block.FossilAnalyzerBlock
|
||||||
import com.cobblemon.mod.common.block.fossilmachine.FossilMonitorBlock
|
import com.cobblemon.mod.common.block.MonitorBlock
|
||||||
|
import com.cobblemon.mod.common.block.RestorationTankBlock
|
||||||
|
import com.cobblemon.mod.common.block.entity.RestorationTankBlockEntity
|
||||||
import com.cobblemon.mod.common.client.render.models.blockbench.fossil.FossilState
|
import com.cobblemon.mod.common.client.render.models.blockbench.fossil.FossilState
|
||||||
|
import com.cobblemon.mod.common.client.sound.CancellableSoundController
|
||||||
|
import com.cobblemon.mod.common.client.sound.CancellableSoundInstance
|
||||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||||
import com.cobblemon.mod.common.item.PokeBallItem
|
import com.cobblemon.mod.common.item.PokeBallItem
|
||||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||||
import com.cobblemon.mod.common.util.DataKeys
|
import com.cobblemon.mod.common.util.*
|
||||||
import com.cobblemon.mod.common.util.giveOrDropItemStack
|
|
||||||
import com.cobblemon.mod.common.util.lang
|
|
||||||
import com.cobblemon.mod.common.util.party
|
|
||||||
import net.minecraft.block.Block
|
import net.minecraft.block.Block
|
||||||
import net.minecraft.block.BlockState
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.block.HorizontalFacingBlock
|
import net.minecraft.block.HorizontalFacingBlock
|
||||||
import net.minecraft.block.entity.BlockEntityTicker
|
import net.minecraft.block.entity.BlockEntityTicker
|
||||||
import net.minecraft.client.MinecraftClient
|
|
||||||
import net.minecraft.entity.EntityPose
|
import net.minecraft.entity.EntityPose
|
||||||
import net.minecraft.entity.player.PlayerEntity
|
import net.minecraft.entity.player.PlayerEntity
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
@@ -54,15 +54,18 @@ import net.minecraft.util.math.Box
|
|||||||
import net.minecraft.util.math.Direction
|
import net.minecraft.util.math.Direction
|
||||||
import net.minecraft.util.math.random.Random
|
import net.minecraft.util.math.random.Random
|
||||||
import net.minecraft.world.World
|
import net.minecraft.world.World
|
||||||
|
import java.util.UUID
|
||||||
import kotlin.math.ceil
|
import kotlin.math.ceil
|
||||||
|
|
||||||
class FossilMultiblockStructure (
|
class FossilMultiblockStructure (
|
||||||
val monitorPos: BlockPos,
|
val monitorPos: BlockPos,
|
||||||
val compartmentPos: BlockPos,
|
val analyzerPos: BlockPos,
|
||||||
val tubeBasePos: BlockPos
|
val tankBasePos: BlockPos,
|
||||||
|
animAge: Int = -1,
|
||||||
|
animPartialTicks: Float = 0F
|
||||||
) : MultiblockStructure {
|
) : MultiblockStructure {
|
||||||
|
|
||||||
override val controllerBlockPos = compartmentPos
|
override val controllerBlockPos = analyzerPos
|
||||||
|
|
||||||
|
|
||||||
// TODO: API method for this
|
// TODO: API method for this
|
||||||
@@ -78,10 +81,10 @@ class FossilMultiblockStructure (
|
|||||||
private var lastInteraction: Long = 0
|
private var lastInteraction: Long = 0
|
||||||
private var machineStartTime: Long = 0
|
private var machineStartTime: Long = 0
|
||||||
private var protectionTime: Int = -1
|
private var protectionTime: Int = -1
|
||||||
private var fossilOwner: PlayerEntity? = null
|
private var fossilOwnerUUID: UUID? = null
|
||||||
val fossilState = FossilState()
|
val fossilState = FossilState(animAge, animPartialTicks)
|
||||||
var fossilInventory: MutableList<ItemStack> = mutableListOf<ItemStack>()
|
var fossilInventory: MutableList<ItemStack> = mutableListOf<ItemStack>()
|
||||||
var tubeConnectorDirection: Direction? = null
|
var tankConnectorDirection: Direction? = null
|
||||||
|
|
||||||
//Only updated clientside
|
//Only updated clientside
|
||||||
var fillLevel = 0
|
var fillLevel = 0
|
||||||
@@ -97,7 +100,7 @@ class FossilMultiblockStructure (
|
|||||||
|
|
||||||
if (this.createdPokemon != null) {
|
if (this.createdPokemon != null) {
|
||||||
|
|
||||||
if (!stack.isIn(CobblemonItemTags.POKEBALLS) || stack.item !is PokeBallItem) {
|
if (!stack.isIn(CobblemonItemTags.POKE_BALLS) || stack.item !is PokeBallItem) {
|
||||||
return ActionResult.PASS
|
return ActionResult.PASS
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,8 +108,12 @@ class FossilMultiblockStructure (
|
|||||||
return ActionResult.CONSUME
|
return ActionResult.CONSUME
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.fossilOwner != null && player != this.fossilOwner) {
|
if (this.fossilOwnerUUID != null && player.uuid != this.fossilOwnerUUID) {
|
||||||
player.sendMessage(lang("fossilmachine.protected", this.fossilOwner!!.name), true)
|
var ownerName : String = "UNKNOWN_USER" // TODO: lang agnostic fallback
|
||||||
|
server()?.userCache?.getByUuid(this.fossilOwnerUUID)?.orElse(null)?.name?.let {
|
||||||
|
ownerName = it
|
||||||
|
}
|
||||||
|
player.sendMessage(lang("fossilmachine.protected", ownerName), true)
|
||||||
return ActionResult.FAIL
|
return ActionResult.FAIL
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,8 +130,14 @@ class FossilMultiblockStructure (
|
|||||||
player.playSound(CobblemonSounds.FOSSIL_MACHINE_RETRIEVE_POKEMON, SoundCategory.BLOCKS, 1.0F, 1.0F)
|
player.playSound(CobblemonSounds.FOSSIL_MACHINE_RETRIEVE_POKEMON, SoundCategory.BLOCKS, 1.0F, 1.0F)
|
||||||
CobblemonCriteria.RESURRECT_POKEMON.trigger(player, createdPokemon!!)
|
CobblemonCriteria.RESURRECT_POKEMON.trigger(player, createdPokemon!!)
|
||||||
|
|
||||||
|
// Turn the monitor off
|
||||||
|
val monitorState = world.getBlockState(monitorPos)
|
||||||
|
if(!monitorState.equals(MonitorBlock.MonitorScreen.OFF)) {
|
||||||
|
world.setBlockState(monitorPos, monitorState.with(MonitorBlock.SCREEN, MonitorBlock.MonitorScreen.OFF))
|
||||||
|
}
|
||||||
|
|
||||||
this.createdPokemon = null
|
this.createdPokemon = null
|
||||||
this.fossilOwner = null
|
this.fossilOwnerUUID = null
|
||||||
this.protectionTime = -1
|
this.protectionTime = -1
|
||||||
this.updateFossilType(world)
|
this.updateFossilType(world)
|
||||||
this.syncToClient(world)
|
this.syncToClient(world)
|
||||||
@@ -147,7 +160,7 @@ class FossilMultiblockStructure (
|
|||||||
// remove last fossil in the fossil machine stack when grabbed out of the machine
|
// remove last fossil in the fossil machine stack when grabbed out of the machine
|
||||||
this.fossilInventory.removeAt(fossilInventory.size - 1)
|
this.fossilInventory.removeAt(fossilInventory.size - 1)
|
||||||
if(!world.isClient) {
|
if(!world.isClient) {
|
||||||
world.playSound(null, compartmentPos, CobblemonSounds.FOSSIL_MACHINE_RETRIEVE_FOSSIL, SoundCategory.BLOCKS)
|
world.playSound(null, analyzerPos, CobblemonSounds.FOSSIL_MACHINE_RETRIEVE_FOSSIL, SoundCategory.BLOCKS)
|
||||||
this.updateFossilType(world)
|
this.updateFossilType(world)
|
||||||
this.syncToClient(world)
|
this.syncToClient(world)
|
||||||
this.markDirty(world)
|
this.markDirty(world)
|
||||||
@@ -166,11 +179,11 @@ class FossilMultiblockStructure (
|
|||||||
stack?.decrement(1)
|
stack?.decrement(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fossilOwner = player
|
fossilOwnerUUID = player.uuid
|
||||||
fossilInventory.add(copyFossilStack)
|
fossilInventory.add(copyFossilStack)
|
||||||
if(!world.isClient) {
|
if(!world.isClient) {
|
||||||
this.updateFossilType(world)
|
this.updateFossilType(world)
|
||||||
world.playSound(null, compartmentPos, CobblemonSounds.FOSSIL_MACHINE_INSERT_FOSSIL, SoundCategory.BLOCKS)
|
world.playSound(null, analyzerPos, CobblemonSounds.FOSSIL_MACHINE_INSERT_FOSSIL, SoundCategory.BLOCKS)
|
||||||
this.syncToClient(world)
|
this.syncToClient(world)
|
||||||
this.markDirty(world)
|
this.markDirty(world)
|
||||||
}
|
}
|
||||||
@@ -191,16 +204,18 @@ class FossilMultiblockStructure (
|
|||||||
return ActionResult.success(world.isClient)
|
return ActionResult.success(world.isClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pure client instances dont know what a valid fossil is so this is my janky workaround
|
||||||
|
if (stack.isIn(CobblemonItemTags.FOSSILS)) return ActionResult.SUCCESS
|
||||||
|
|
||||||
return ActionResult.PASS
|
return ActionResult.PASS
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun spawn(world: World, pos: BlockPos, directionToBehind: Direction, pokemon: Pokemon) : Boolean {
|
public fun spawn(world: World, pos: BlockPos, directionToBehind: Direction, pokemon: Pokemon) : Boolean {
|
||||||
val world = world ?: return false
|
|
||||||
val entity = PokemonEntity(world, pokemon = pokemon)
|
val entity = PokemonEntity(world, pokemon = pokemon)
|
||||||
entity.calculateDimensions()
|
entity.calculateDimensions()
|
||||||
val width = entity.boundingBox.xLength
|
val width = entity.boundingBox.xLength
|
||||||
|
|
||||||
val idealPlace = pos.add(directionToBehind.vector.multiply(ceil(width).toInt() + 1))
|
val idealPlace = pos.add(directionToBehind.vector.multiply(ceil(width / 2.0).toInt() + 1))
|
||||||
var box = entity.getDimensions(EntityPose.STANDING).getBoxAt(idealPlace.toCenterPos().subtract(0.0, 0.5, 0.0))
|
var box = entity.getDimensions(EntityPose.STANDING).getBoxAt(idealPlace.toCenterPos().subtract(0.0, 0.5, 0.0))
|
||||||
|
|
||||||
for (i in 0..5) {
|
for (i in 0..5) {
|
||||||
@@ -269,7 +284,7 @@ class FossilMultiblockStructure (
|
|||||||
}
|
}
|
||||||
return Math.max(15 - timeRemaining * 15 / TIME_TO_TAKE, 1)
|
return Math.max(15 - timeRemaining * 15 / TIME_TO_TAKE, 1)
|
||||||
}
|
}
|
||||||
if(tubeBasePos == pos || tubeBasePos.up() == pos) {
|
if(tankBasePos == pos || tankBasePos.up() == pos) {
|
||||||
return organicMaterialInside * 15 / MATERIAL_TO_START
|
return organicMaterialInside * 15 / MATERIAL_TO_START
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
@@ -284,9 +299,9 @@ class FossilMultiblockStructure (
|
|||||||
if(success) {
|
if(success) {
|
||||||
this.fossilState.growthState = "Taken"
|
this.fossilState.growthState = "Taken"
|
||||||
this.createdPokemon = null
|
this.createdPokemon = null
|
||||||
this.fossilOwner = null
|
this.fossilOwnerUUID = null
|
||||||
this.protectionTime = -1
|
this.protectionTime = -1
|
||||||
world.playSound(null, tubeBasePos, CobblemonSounds.FOSSIL_MACHINE_RETRIEVE_POKEMON, SoundCategory.BLOCKS)
|
world.playSound(null, tankBasePos, CobblemonSounds.FOSSIL_MACHINE_RETRIEVE_POKEMON, SoundCategory.BLOCKS)
|
||||||
this.updateFossilType(world)
|
this.updateFossilType(world)
|
||||||
this.syncToClient(world)
|
this.syncToClient(world)
|
||||||
this.markDirty(world)
|
this.markDirty(world)
|
||||||
@@ -297,22 +312,21 @@ class FossilMultiblockStructure (
|
|||||||
|
|
||||||
override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity?) {
|
override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity?) {
|
||||||
val monitorEntity = world.getBlockEntity(monitorPos) as MultiblockEntity
|
val monitorEntity = world.getBlockEntity(monitorPos) as MultiblockEntity
|
||||||
val compartmentEntity = world.getBlockEntity(compartmentPos) as MultiblockEntity
|
val analyzerEntity = world.getBlockEntity(analyzerPos) as MultiblockEntity
|
||||||
val tubeBaseEntity = world.getBlockEntity(tubeBasePos) as MultiblockEntity
|
val tankBaseEntity = world.getBlockEntity(tankBasePos) as MultiblockEntity
|
||||||
val tubeTopEntity = world.getBlockEntity(tubeBasePos.up()) as MultiblockEntity
|
val tankTopEntity = world.getBlockEntity(tankBasePos.up()) as MultiblockEntity
|
||||||
val state = world.getBlockState(monitorEntity.pos)
|
val state = world.getBlockState(tankBaseEntity.pos)
|
||||||
val direction = state.get(HorizontalFacingBlock.FACING).getOpposite()
|
val direction = state.get(HorizontalFacingBlock.FACING).getOpposite()
|
||||||
val wildPokemon: Pokemon? = this.createdPokemon
|
val wildPokemon: Pokemon? = this.createdPokemon
|
||||||
|
|
||||||
monitorEntity.multiblockStructure = null
|
monitorEntity.multiblockStructure = null
|
||||||
compartmentEntity.multiblockStructure = null
|
analyzerEntity.multiblockStructure = null
|
||||||
tubeBaseEntity.multiblockStructure = null
|
tankBaseEntity.multiblockStructure = null
|
||||||
tubeTopEntity.multiblockStructure = null
|
tankTopEntity.multiblockStructure = null
|
||||||
monitorEntity.masterBlockPos = null
|
monitorEntity.masterBlockPos = null
|
||||||
compartmentEntity.masterBlockPos = null
|
analyzerEntity.masterBlockPos = null
|
||||||
tubeBaseEntity.masterBlockPos = null
|
tankBaseEntity.masterBlockPos = null
|
||||||
tubeTopEntity.masterBlockPos = null
|
tankTopEntity.masterBlockPos = null
|
||||||
|
|
||||||
|
|
||||||
// Drop fossils from machine as long as the machine is not running
|
// Drop fossils from machine as long as the machine is not running
|
||||||
if (this.timeRemaining == TIME_TO_TAKE || this.timeRemaining == -1) {
|
if (this.timeRemaining == TIME_TO_TAKE || this.timeRemaining == -1) {
|
||||||
@@ -321,10 +335,17 @@ class FossilMultiblockStructure (
|
|||||||
ItemScatterer.spawn(world, pos.x.toDouble(), pos.y.toDouble(), pos.z.toDouble(), stack)
|
ItemScatterer.spawn(world, pos.x.toDouble(), pos.y.toDouble(), pos.z.toDouble(), stack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(tankBaseEntity is RestorationTankBlockEntity) {
|
||||||
|
tankBaseEntity.inv.items.forEach {
|
||||||
|
val stack = ItemStack(it.item, 1)
|
||||||
|
ItemScatterer.spawn(world, pos.x.toDouble(), pos.y.toDouble(), pos.z.toDouble(), stack)
|
||||||
|
}
|
||||||
|
tankBaseEntity.inv.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// if the machine is broken while the pokemon is done then spawn the pokemon at the location and make it a wild pokemon
|
// if the machine is broken while the pokemon is done then spawn the pokemon at the location and make it a wild pokemon
|
||||||
if (this.fossilState.growthState == "Fully Grown" && wildPokemon != null) {
|
if (wildPokemon != null) {
|
||||||
//world.createExplosion(this.createdPokemon?.entity, pos.x.toDouble(), pos.y.toDouble(), pos.z.toDouble(), 5F, World.ExplosionSourceType.TNT)
|
//world.createExplosion(this.createdPokemon?.entity, pos.x.toDouble(), pos.y.toDouble(), pos.z.toDouble(), 5F, World.ExplosionSourceType.TNT)
|
||||||
|
|
||||||
// instantiate the pokemon as a new entity and spawn it at the location of the machine
|
// instantiate the pokemon as a new entity and spawn it at the location of the machine
|
||||||
@@ -334,29 +355,39 @@ class FossilMultiblockStructure (
|
|||||||
this.spawn(world, pos, direction, wildPokemon)
|
this.spawn(world, pos, direction, wildPokemon)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
this.protectionTime = -1
|
||||||
MinecraftClient.getInstance().soundManager.stopSounds(CobblemonSounds.FOSSIL_MACHINE_ACTIVE_LOOP.id, SoundCategory.BLOCKS)
|
|
||||||
|
|
||||||
this.updateFossilType(world)
|
this.updateFossilType(world)
|
||||||
this.stopMachine(world)
|
this.stopMachine(world)
|
||||||
this.syncToClient(world)
|
this.syncToClient(world)
|
||||||
this.markDirty(world)
|
this.markDirty(world)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun markRemoved(world: World) {
|
||||||
|
if(world.isClient) {
|
||||||
|
CancellableSoundController.stopSound(this.tankBasePos, CobblemonSounds.FOSSIL_MACHINE_ACTIVE_LOOP.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun tick(world: World) {
|
override fun tick(world: World) {
|
||||||
if (protectionTime > 0) protectionTime--
|
if (protectionTime > 0) protectionTime--
|
||||||
if (protectionTime == 0) {
|
if (protectionTime == 0) {
|
||||||
protectionTime = -1
|
protectionTime = -1
|
||||||
this.fossilOwner = null
|
this.fossilOwnerUUID = null
|
||||||
world.playSound(null, tubeBasePos, CobblemonSounds.FOSSIL_MACHINE_UNPROTECTED, SoundCategory.BLOCKS)
|
this.updateProgress(world)
|
||||||
|
this.syncToClient(world)
|
||||||
|
this.markDirty(world)
|
||||||
|
world.playSound(null, tankBasePos, CobblemonSounds.FOSSIL_MACHINE_UNPROTECTED, SoundCategory.BLOCKS)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.createdPokemon != null) {
|
if (this.createdPokemon != null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isRunning() && (world.time - this.machineStartTime) % 160L == 0L) {
|
if (world.isClient && this.isRunning() && (world.time - this.machineStartTime) % 160L == 0L) {
|
||||||
world.playSound(null, this.tubeBasePos, CobblemonSounds.FOSSIL_MACHINE_ACTIVE_LOOP, SoundCategory.BLOCKS, 1.0F, 1.0F)
|
if(world.isClient) {
|
||||||
|
CancellableSoundController.playSound(CancellableSoundInstance(CobblemonSounds.FOSSIL_MACHINE_ACTIVE_LOOP,
|
||||||
|
tankBasePos, true, 1.0f, 1.0f, ))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.timeRemaining == -1 && this.organicMaterialInside >= MATERIAL_TO_START && this.resultingFossil != null) {
|
if (this.timeRemaining == -1 && this.organicMaterialInside >= MATERIAL_TO_START && this.resultingFossil != null) {
|
||||||
@@ -375,14 +406,13 @@ class FossilMultiblockStructure (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.timeRemaining == 0) {
|
if (this.timeRemaining == 0) {
|
||||||
world.playSound(null, tubeBasePos, CobblemonSounds.FOSSIL_MACHINE_FINISHED, SoundCategory.BLOCKS)
|
world.playSound(null, tankBasePos, CobblemonSounds.FOSSIL_MACHINE_FINISHED, SoundCategory.BLOCKS)
|
||||||
MinecraftClient.getInstance().soundManager.stopSounds(CobblemonSounds.FOSSIL_MACHINE_ACTIVE_LOOP.id, SoundCategory.BLOCKS)
|
|
||||||
fossilInventory.clear()
|
fossilInventory.clear()
|
||||||
|
|
||||||
this.resultingFossil?.let {
|
this.resultingFossil?.let {
|
||||||
this.createdPokemon = it.result.create()
|
this.createdPokemon = it.result.create()
|
||||||
}
|
}
|
||||||
if(this.fossilOwner != null) {
|
if(this.fossilOwnerUUID != null) {
|
||||||
protectionTime = PROTECTION_TIME
|
protectionTime = PROTECTION_TIME
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,20 +421,23 @@ class FossilMultiblockStructure (
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun syncToClient(world: World) {
|
override fun syncToClient(world: World) {
|
||||||
val tubeBaseEntity = world.getBlockEntity(tubeBasePos) as MultiblockEntity
|
val tankBaseEntity = world.getBlockEntity(tankBasePos) as? MultiblockEntity
|
||||||
val compartmentEntity = world.getBlockEntity(controllerBlockPos) as MultiblockEntity
|
val analyzerEntity = world.getBlockEntity(controllerBlockPos) as? MultiblockEntity
|
||||||
val monitorEntity = world.getBlockEntity(monitorPos) as MultiblockEntity
|
val monitorEntity = world.getBlockEntity(monitorPos) as? MultiblockEntity
|
||||||
|
|
||||||
world.updateListeners(tubeBasePos, tubeBaseEntity.cachedState, tubeBaseEntity.cachedState, Block.NOTIFY_LISTENERS)
|
if(tankBaseEntity != null)
|
||||||
world.updateListeners(compartmentPos, compartmentEntity.cachedState, compartmentEntity.cachedState, Block.NOTIFY_LISTENERS)
|
world.updateListeners(tankBasePos, tankBaseEntity.cachedState, tankBaseEntity.cachedState, Block.NOTIFY_LISTENERS)
|
||||||
world.updateListeners(monitorPos, monitorEntity.cachedState, monitorEntity.cachedState, Block.NOTIFY_LISTENERS)
|
if(analyzerEntity != null)
|
||||||
|
world.updateListeners(analyzerPos, analyzerEntity.cachedState, analyzerEntity.cachedState, Block.NOTIFY_LISTENERS)
|
||||||
|
if(monitorEntity != null)
|
||||||
|
world.updateListeners(monitorPos, monitorEntity.cachedState, monitorEntity.cachedState, Block.NOTIFY_LISTENERS)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun markDirty(world: World) {
|
override fun markDirty(world: World) {
|
||||||
val entities = listOf(
|
val entities = listOf(
|
||||||
world.getBlockEntity(compartmentPos),
|
world.getBlockEntity(analyzerPos),
|
||||||
world.getBlockEntity(tubeBasePos),
|
world.getBlockEntity(tankBasePos),
|
||||||
world.getBlockEntity(tubeBasePos.up()),
|
world.getBlockEntity(tankBasePos.up()),
|
||||||
world.getBlockEntity(monitorPos)
|
world.getBlockEntity(monitorPos)
|
||||||
)
|
)
|
||||||
entities.forEach {
|
entities.forEach {
|
||||||
@@ -416,8 +449,11 @@ class FossilMultiblockStructure (
|
|||||||
this.timeRemaining = TIME_TO_TAKE
|
this.timeRemaining = TIME_TO_TAKE
|
||||||
this.machineStartTime = world.time
|
this.machineStartTime = world.time
|
||||||
|
|
||||||
world.playSound(null, tubeBasePos, CobblemonSounds.FOSSIL_MACHINE_ACTIVATE, SoundCategory.BLOCKS)
|
world.playSound(null, tankBasePos, CobblemonSounds.FOSSIL_MACHINE_ACTIVATE, SoundCategory.BLOCKS)
|
||||||
world.playSound(null, tubeBasePos, CobblemonSounds.FOSSIL_MACHINE_ACTIVE_LOOP, SoundCategory.BLOCKS)
|
if(world.isClient) {
|
||||||
|
CancellableSoundController.playSound(CancellableSoundInstance(CobblemonSounds.FOSSIL_MACHINE_ACTIVE_LOOP,
|
||||||
|
tankBasePos, true, 1.0f, 1.0f, ))
|
||||||
|
}
|
||||||
|
|
||||||
this.updateOnStatus(world)
|
this.updateOnStatus(world)
|
||||||
this.updateProgress(world)
|
this.updateProgress(world)
|
||||||
@@ -432,6 +468,10 @@ class FossilMultiblockStructure (
|
|||||||
|
|
||||||
fossilInventory.clear()
|
fossilInventory.clear()
|
||||||
|
|
||||||
|
if(world.isClient) {
|
||||||
|
CancellableSoundController.stopSound(tankBasePos, CobblemonSounds.FOSSIL_MACHINE_ACTIVE_LOOP.id)
|
||||||
|
}
|
||||||
|
|
||||||
this.updateOnStatus(world)
|
this.updateOnStatus(world)
|
||||||
this.updateProgress(world)
|
this.updateProgress(world)
|
||||||
this.syncToClient(world)
|
this.syncToClient(world)
|
||||||
@@ -439,14 +479,38 @@ class FossilMultiblockStructure (
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun updateOnStatus(world: World) {
|
fun updateOnStatus(world: World) {
|
||||||
val compartmentState = world.getBlockState(compartmentPos)
|
val upperTankPos = tankBasePos.up()
|
||||||
world.setBlockState(compartmentPos, compartmentState.with(FossilCompartmentBlock.ON, timeRemaining >= 0))
|
val analyzerState = world.getBlockState(analyzerPos)
|
||||||
|
val tankState = world.getBlockState(tankBasePos.up())
|
||||||
|
world.setBlockState(analyzerPos, analyzerState.with(FossilAnalyzerBlock.ON, timeRemaining >= 0))
|
||||||
|
world.setBlockState(upperTankPos, tankState.with(RestorationTankBlock.ON, timeRemaining >= 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateProgress(world: World) {
|
fun updateProgress(world: World) {
|
||||||
val progress = if (timeRemaining <= 0) 0 else ((TIME_TO_TAKE - timeRemaining) / TIME_PER_STAGE) + 1
|
val screenID = if(protectionTime > 0F ) {
|
||||||
|
MonitorBlock.MonitorScreen.GREEN_PROGRESS_9
|
||||||
|
} else if (timeRemaining <= 0) {
|
||||||
|
MonitorBlock.MonitorScreen.OFF
|
||||||
|
} else {
|
||||||
|
getProgressScreen((TIME_TO_TAKE - timeRemaining) / TIME_PER_STAGE)
|
||||||
|
}
|
||||||
val monitorState = world.getBlockState(monitorPos)
|
val monitorState = world.getBlockState(monitorPos)
|
||||||
world.setBlockState(monitorPos, monitorState.with(FossilMonitorBlock.PROGRESS, progress))
|
world.setBlockState(monitorPos, monitorState.with(MonitorBlock.SCREEN, screenID))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getProgressScreen(progress:Int) : MonitorBlock.MonitorScreen {
|
||||||
|
return when (progress) {
|
||||||
|
0 -> MonitorBlock.MonitorScreen.BLUE_PROGRESS_1
|
||||||
|
1 -> MonitorBlock.MonitorScreen.BLUE_PROGRESS_2
|
||||||
|
2 -> MonitorBlock.MonitorScreen.BLUE_PROGRESS_3
|
||||||
|
3 -> MonitorBlock.MonitorScreen.BLUE_PROGRESS_4
|
||||||
|
4 -> MonitorBlock.MonitorScreen.BLUE_PROGRESS_5
|
||||||
|
5 -> MonitorBlock.MonitorScreen.BLUE_PROGRESS_6
|
||||||
|
6 -> MonitorBlock.MonitorScreen.BLUE_PROGRESS_7
|
||||||
|
7 -> MonitorBlock.MonitorScreen.BLUE_PROGRESS_8
|
||||||
|
8 -> MonitorBlock.MonitorScreen.BLUE_PROGRESS_9
|
||||||
|
else -> MonitorBlock.MonitorScreen.OFF
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -491,11 +555,11 @@ class FossilMultiblockStructure (
|
|||||||
organicMaterialInside += natureValue
|
organicMaterialInside += natureValue
|
||||||
}
|
}
|
||||||
if (this.organicMaterialInside >= MATERIAL_TO_START) {
|
if (this.organicMaterialInside >= MATERIAL_TO_START) {
|
||||||
world.playSound(null, this.tubeBasePos, CobblemonSounds.FOSSIL_MACHINE_DNA_FULL, SoundCategory.BLOCKS, 1.0F, 1.0F)
|
world.playSound(null, this.tankBasePos, CobblemonSounds.FOSSIL_MACHINE_DNA_FULL, SoundCategory.BLOCKS, 1.0F, 1.0F)
|
||||||
} else if (world.time - this.lastInteraction < 10) {
|
} else if (world.time - this.lastInteraction < 10) {
|
||||||
world.playSound(null, this.tubeBasePos, CobblemonSounds.FOSSIL_MACHINE_INSERT_DNA_SMALL, SoundCategory.BLOCKS, 1.0F, 1.0F)
|
world.playSound(null, this.tankBasePos, CobblemonSounds.FOSSIL_MACHINE_INSERT_DNA_SMALL, SoundCategory.BLOCKS, 1.0F, 1.0F)
|
||||||
} else {
|
} else {
|
||||||
world.playSound(null, this.tubeBasePos, CobblemonSounds.FOSSIL_MACHINE_INSERT_DNA, SoundCategory.BLOCKS, 1.0F, 1.0F)
|
world.playSound(null, this.tankBasePos, CobblemonSounds.FOSSIL_MACHINE_INSERT_DNA, SoundCategory.BLOCKS, 1.0F, 1.0F)
|
||||||
}
|
}
|
||||||
this.markDirty(world)
|
this.markDirty(world)
|
||||||
if (oldFillStage != (organicMaterialInside / 8)) {
|
if (oldFillStage != (organicMaterialInside / 8)) {
|
||||||
@@ -514,7 +578,7 @@ class FossilMultiblockStructure (
|
|||||||
|
|
||||||
//add fossil to the stack in the Compartment
|
//add fossil to the stack in the Compartment
|
||||||
this.fossilInventory.add(stack)
|
this.fossilInventory.add(stack)
|
||||||
world.playSound(null, compartmentPos, CobblemonSounds.FOSSIL_MACHINE_INSERT_FOSSIL, SoundCategory.BLOCKS)
|
world.playSound(null, analyzerPos, CobblemonSounds.FOSSIL_MACHINE_INSERT_FOSSIL, SoundCategory.BLOCKS)
|
||||||
|
|
||||||
this.updateFossilType(world)
|
this.updateFossilType(world)
|
||||||
this.markDirty(world)
|
this.markDirty(world)
|
||||||
@@ -527,16 +591,19 @@ class FossilMultiblockStructure (
|
|||||||
override fun writeToNbt(): NbtCompound {
|
override fun writeToNbt(): NbtCompound {
|
||||||
val result = NbtCompound()
|
val result = NbtCompound()
|
||||||
result.put(DataKeys.MONITOR_POS, NbtHelper.fromBlockPos(monitorPos))
|
result.put(DataKeys.MONITOR_POS, NbtHelper.fromBlockPos(monitorPos))
|
||||||
result.put(DataKeys.COMPARTMENT_POS, NbtHelper.fromBlockPos(compartmentPos))
|
result.put(DataKeys.ANALYZER_POS, NbtHelper.fromBlockPos(analyzerPos))
|
||||||
result.put(DataKeys.TUBE_BASE_POS, NbtHelper.fromBlockPos(tubeBasePos))
|
result.put(DataKeys.TANK_BASE_POS, NbtHelper.fromBlockPos(tankBasePos))
|
||||||
result.putInt(DataKeys.TIME_LEFT, timeRemaining)
|
result.putInt(DataKeys.TIME_LEFT, timeRemaining)
|
||||||
|
result.putInt(DataKeys.PROTECTED_TIME_LEFT, protectionTime)
|
||||||
|
if(fossilOwnerUUID != null)
|
||||||
|
result.putUuid(DataKeys.FOSSIL_OWNER, fossilOwnerUUID)
|
||||||
result.putInt(DataKeys.ORGANIC_MATERIAL, organicMaterialInside)
|
result.putInt(DataKeys.ORGANIC_MATERIAL, organicMaterialInside)
|
||||||
val fossilInv = NbtList()
|
val fossilInv = NbtList()
|
||||||
fossilInventory.forEach{ item ->
|
fossilInventory.forEach{ item ->
|
||||||
fossilInv.add(item.writeNbt(NbtCompound()))
|
fossilInv.add(item.writeNbt(NbtCompound()))
|
||||||
}
|
}
|
||||||
result.put(DataKeys.FOSSIL_INVENTORY, fossilInv)
|
result.put(DataKeys.FOSSIL_INVENTORY, fossilInv)
|
||||||
result.putString(DataKeys.CONNECTOR_DIRECTION, tubeConnectorDirection?.toString())
|
result.putString(DataKeys.CONNECTOR_DIRECTION, tankConnectorDirection?.toString())
|
||||||
|
|
||||||
if (this.resultingFossil != null) {
|
if (this.resultingFossil != null) {
|
||||||
result.putString(DataKeys.INSERTED_FOSSIL, this.resultingFossil!!.asString())
|
result.putString(DataKeys.INSERTED_FOSSIL, this.resultingFossil!!.asString())
|
||||||
@@ -562,14 +629,16 @@ class FossilMultiblockStructure (
|
|||||||
const val TIME_PER_STAGE = TIME_TO_TAKE / 8
|
const val TIME_PER_STAGE = TIME_TO_TAKE / 8
|
||||||
const val PROTECTION_TIME = 6000
|
const val PROTECTION_TIME = 6000
|
||||||
|
|
||||||
fun fromNbt(nbt: NbtCompound): FossilMultiblockStructure {
|
fun fromNbt(nbt: NbtCompound, animAge: Int = -1, partialTicks: Float = 0f): FossilMultiblockStructure {
|
||||||
val monitorPos = NbtHelper.toBlockPos(nbt.getCompound(DataKeys.MONITOR_POS))
|
val monitorPos = NbtHelper.toBlockPos(nbt.getCompound(DataKeys.MONITOR_POS))
|
||||||
val compartmentPos = NbtHelper.toBlockPos(nbt.getCompound(DataKeys.COMPARTMENT_POS))
|
val compartmentPos = NbtHelper.toBlockPos(nbt.getCompound(DataKeys.ANALYZER_POS))
|
||||||
val tubeBasePos = NbtHelper.toBlockPos(nbt.getCompound(DataKeys.TUBE_BASE_POS))
|
val tankBasePos = NbtHelper.toBlockPos(nbt.getCompound(DataKeys.TANK_BASE_POS))
|
||||||
|
|
||||||
val result = FossilMultiblockStructure(monitorPos, compartmentPos, tubeBasePos)
|
val result = FossilMultiblockStructure(monitorPos, compartmentPos, tankBasePos, animAge, partialTicks)
|
||||||
result.organicMaterialInside = nbt.getInt(DataKeys.ORGANIC_MATERIAL)
|
result.organicMaterialInside = nbt.getInt(DataKeys.ORGANIC_MATERIAL)
|
||||||
result.timeRemaining = nbt.getInt(DataKeys.TIME_LEFT)
|
result.timeRemaining = nbt.getInt(DataKeys.TIME_LEFT)
|
||||||
|
result.protectionTime = if(nbt.contains(DataKeys.PROTECTED_TIME_LEFT)) nbt.getInt(DataKeys.PROTECTED_TIME_LEFT) else -1
|
||||||
|
result.fossilOwnerUUID = if(nbt.contains(DataKeys.FOSSIL_OWNER)) nbt.getUuid(DataKeys.FOSSIL_OWNER) else null
|
||||||
|
|
||||||
val fossilInv = (nbt.get(DataKeys.FOSSIL_INVENTORY) as NbtList)
|
val fossilInv = (nbt.get(DataKeys.FOSSIL_INVENTORY) as NbtList)
|
||||||
val actualFossilList = mutableListOf<ItemStack>()
|
val actualFossilList = mutableListOf<ItemStack>()
|
||||||
@@ -577,7 +646,7 @@ class FossilMultiblockStructure (
|
|||||||
actualFossilList.add(ItemStack.fromNbt(it as NbtCompound))
|
actualFossilList.add(ItemStack.fromNbt(it as NbtCompound))
|
||||||
}
|
}
|
||||||
result.fossilInventory = actualFossilList
|
result.fossilInventory = actualFossilList
|
||||||
result.tubeConnectorDirection = Direction.byName(nbt.getString(DataKeys.CONNECTOR_DIRECTION))
|
result.tankConnectorDirection = Direction.byName(nbt.getString(DataKeys.CONNECTOR_DIRECTION))
|
||||||
|
|
||||||
if (nbt.contains(DataKeys.INSERTED_FOSSIL)) {
|
if (nbt.contains(DataKeys.INSERTED_FOSSIL)) {
|
||||||
val id = Identifier(nbt.getString(DataKeys.INSERTED_FOSSIL))
|
val id = Identifier(nbt.getString(DataKeys.INSERTED_FOSSIL))
|
||||||
|
|||||||
+28
-28
@@ -21,44 +21,44 @@ import net.minecraft.util.Identifier
|
|||||||
object CobblemonBakingOverrides {
|
object CobblemonBakingOverrides {
|
||||||
val models = mutableListOf<BakingOverride>()
|
val models = mutableListOf<BakingOverride>()
|
||||||
|
|
||||||
val FOSSIL_FLUID_BUBBLING = registerOverride(
|
val RESTORATION_TANK_FLUID_BUBBLING = registerOverride(
|
||||||
cobblemonResource("block/fossil/fossil_fluid_bubbling"),
|
cobblemonResource("block/restoration_tank_fluid_bubbling"),
|
||||||
cobblemonModel("fossil_fluid_bubbling", "none")
|
cobblemonModel("restoration_tank_fluid_bubbling", "none")
|
||||||
)
|
)
|
||||||
val FOSSIL_FLUID_CHUNKED_1 = registerOverride(
|
val RESTORATION_TANK_FLUID_CHUNKED_1 = registerOverride(
|
||||||
cobblemonResource("block/fossil/fossil_fluid_chunked_1"),
|
cobblemonResource("block/restoration_tank_fluid_chunked_1"),
|
||||||
cobblemonModel("fossil_fluid_chunked", "1")
|
cobblemonModel("restoration_tank_fluid_chunked", "1")
|
||||||
)
|
)
|
||||||
val FOSSIL_FLUID_CHUNKED_2 = registerOverride(
|
val RESTORATION_TANK_FLUID_CHUNKED_2 = registerOverride(
|
||||||
cobblemonResource("block/fossil/fossil_fluid_chunked_2"),
|
cobblemonResource("block/restoration_tank_fluid_chunked_2"),
|
||||||
cobblemonModel("fossil_fluid_chunked", "2")
|
cobblemonModel("restoration_tank_fluid_chunked", "2")
|
||||||
)
|
)
|
||||||
val FOSSIL_FLUID_CHUNKED_3 = registerOverride(
|
val RESTORATION_TANK_FLUID_CHUNKED_3 = registerOverride(
|
||||||
cobblemonResource("block/fossil/fossil_fluid_chunked_3"),
|
cobblemonResource("block/restoration_tank_fluid_chunked_3"),
|
||||||
cobblemonModel("fossil_fluid_chunked", "3")
|
cobblemonModel("restoration_tank_fluid_chunked", "3")
|
||||||
)
|
)
|
||||||
val FOSSIL_FLUID_CHUNKED_4 = registerOverride(
|
val RESTORATION_TANK_FLUID_CHUNKED_4 = registerOverride(
|
||||||
cobblemonResource("block/fossil/fossil_fluid_chunked_4"),
|
cobblemonResource("block/restoration_tank_fluid_chunked_4"),
|
||||||
cobblemonModel("fossil_fluid_chunked", "4")
|
cobblemonModel("restoration_tank_fluid_chunked", "4")
|
||||||
)
|
)
|
||||||
val FOSSIL_FLUID_CHUNKED_5 = registerOverride(
|
val RESTORATION_TANK_FLUID_CHUNKED_5 = registerOverride(
|
||||||
cobblemonResource("block/fossil/fossil_fluid_chunked_5"),
|
cobblemonResource("block/restoration_tank_fluid_chunked_5"),
|
||||||
cobblemonModel("fossil_fluid_chunked", "5")
|
cobblemonModel("restoration_tank_fluid_chunked", "5")
|
||||||
)
|
)
|
||||||
val FOSSIL_FLUID_CHUNKED_6 = registerOverride(
|
val RESTORATION_TANK_FLUID_CHUNKED_6 = registerOverride(
|
||||||
cobblemonResource("block/fossil/fossil_fluid_chunked_6"),
|
cobblemonResource("block/restoration_tank_fluid_chunked_6"),
|
||||||
cobblemonModel("fossil_fluid_chunked", "6")
|
cobblemonModel("restoration_tank_fluid_chunked", "6")
|
||||||
)
|
)
|
||||||
val FOSSIL_FLUID_CHUNKED_7 = registerOverride(
|
val RESTORATION_TANK_FLUID_CHUNKED_7 = registerOverride(
|
||||||
cobblemonResource("block/fossil/fossil_fluid_chunked_7"),
|
cobblemonResource("block/restoration_tank_fluid_chunked_7"),
|
||||||
cobblemonModel("fossil_fluid_chunked", "7")
|
cobblemonModel("restoration_tank_fluid_chunked", "7")
|
||||||
)
|
)
|
||||||
val FOSSIL_FLUID_CHUNKED_8 = registerOverride(
|
val RESTORATION_TANK_FLUID_CHUNKED_8 = registerOverride(
|
||||||
cobblemonResource("block/fossil/fossil_fluid_chunked_8"),
|
cobblemonResource("block/restoration_tank_fluid_chunked_8"),
|
||||||
cobblemonModel("fossil_fluid_chunked", "8")
|
cobblemonModel("restoration_tank_fluid_chunked", "8")
|
||||||
)
|
)
|
||||||
val RESTORATION_TANK_CONNECTOR = registerOverride(
|
val RESTORATION_TANK_CONNECTOR = registerOverride(
|
||||||
cobblemonResource("block/fossil/restoration_tank_connector"),
|
cobblemonResource("block/restoration_tank_connector"),
|
||||||
cobblemonModel("restoration_tank_connector", "none")
|
cobblemonModel("restoration_tank_connector", "none")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -23,11 +23,12 @@ import com.cobblemon.mod.common.client.gui.PartyOverlay
|
|||||||
import com.cobblemon.mod.common.client.gui.battle.BattleOverlay
|
import com.cobblemon.mod.common.client.gui.battle.BattleOverlay
|
||||||
import com.cobblemon.mod.common.client.particle.BedrockParticleEffectRepository
|
import com.cobblemon.mod.common.client.particle.BedrockParticleEffectRepository
|
||||||
import com.cobblemon.mod.common.client.render.block.BerryBlockRenderer
|
import com.cobblemon.mod.common.client.render.block.BerryBlockRenderer
|
||||||
import com.cobblemon.mod.common.client.render.block.FossilCompartmentRenderer
|
import com.cobblemon.mod.common.client.render.block.FossilAnalyzerRenderer
|
||||||
import com.cobblemon.mod.common.client.render.block.FossilTubeRenderer
|
import com.cobblemon.mod.common.client.render.block.RestorationTankRenderer
|
||||||
import com.cobblemon.mod.common.client.render.block.HealingMachineRenderer
|
import com.cobblemon.mod.common.client.render.block.HealingMachineRenderer
|
||||||
import com.cobblemon.mod.common.client.render.boat.CobblemonBoatRenderer
|
import com.cobblemon.mod.common.client.render.boat.CobblemonBoatRenderer
|
||||||
import com.cobblemon.mod.common.client.render.entity.PokeBobberEntityRenderer
|
import com.cobblemon.mod.common.client.render.entity.PokeBobberEntityRenderer
|
||||||
|
import com.cobblemon.mod.common.client.render.entity.FallingStarRenderer
|
||||||
import com.cobblemon.mod.common.client.render.item.CobblemonBuiltinItemRendererRegistry
|
import com.cobblemon.mod.common.client.render.item.CobblemonBuiltinItemRendererRegistry
|
||||||
import com.cobblemon.mod.common.client.render.item.PokemonItemRenderer
|
import com.cobblemon.mod.common.client.render.item.PokemonItemRenderer
|
||||||
import com.cobblemon.mod.common.client.render.layer.PokemonOnShoulderRenderer
|
import com.cobblemon.mod.common.client.render.layer.PokemonOnShoulderRenderer
|
||||||
@@ -45,6 +46,7 @@ import com.cobblemon.mod.common.data.CobblemonDataProvider
|
|||||||
import com.cobblemon.mod.common.entity.boat.CobblemonBoatType
|
import com.cobblemon.mod.common.entity.boat.CobblemonBoatType
|
||||||
import com.cobblemon.mod.common.item.PokeBallItem
|
import com.cobblemon.mod.common.item.PokeBallItem
|
||||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.FossilModelRepository
|
import com.cobblemon.mod.common.client.render.models.blockbench.repository.FossilModelRepository
|
||||||
|
import com.cobblemon.mod.common.client.render.models.blockbench.repository.MiscModelRepository
|
||||||
import com.cobblemon.mod.common.platform.events.PlatformEvents
|
import com.cobblemon.mod.common.platform.events.PlatformEvents
|
||||||
import com.cobblemon.mod.common.util.DataKeys
|
import com.cobblemon.mod.common.util.DataKeys
|
||||||
import com.cobblemon.mod.common.util.asTranslated
|
import com.cobblemon.mod.common.util.asTranslated
|
||||||
@@ -162,7 +164,7 @@ object CobblemonClient {
|
|||||||
|
|
||||||
this.implementation.registerBlockRenderType(
|
this.implementation.registerBlockRenderType(
|
||||||
RenderLayer.getCutout(),
|
RenderLayer.getCutout(),
|
||||||
CobblemonBlocks.FOSSIL_COMPARTMENT,
|
CobblemonBlocks.FOSSIL_ANALYZER,
|
||||||
CobblemonBlocks.APRICORN_DOOR,
|
CobblemonBlocks.APRICORN_DOOR,
|
||||||
CobblemonBlocks.APRICORN_TRAPDOOR,
|
CobblemonBlocks.APRICORN_TRAPDOOR,
|
||||||
CobblemonBlocks.APRICORN_SIGN,
|
CobblemonBlocks.APRICORN_SIGN,
|
||||||
@@ -202,7 +204,7 @@ object CobblemonClient {
|
|||||||
CobblemonBlocks.REVIVAL_HERB,
|
CobblemonBlocks.REVIVAL_HERB,
|
||||||
*CobblemonBlocks.berries().values.toTypedArray(),
|
*CobblemonBlocks.berries().values.toTypedArray(),
|
||||||
CobblemonBlocks.POTTED_PEP_UP_FLOWER,
|
CobblemonBlocks.POTTED_PEP_UP_FLOWER,
|
||||||
CobblemonBlocks.FOSSIL_TUBE,
|
CobblemonBlocks.RESTORATION_TANK,
|
||||||
CobblemonBlocks.SMALL_BUDDING_TUMBLESTONE,
|
CobblemonBlocks.SMALL_BUDDING_TUMBLESTONE,
|
||||||
CobblemonBlocks.MEDIUM_BUDDING_TUMBLESTONE,
|
CobblemonBlocks.MEDIUM_BUDDING_TUMBLESTONE,
|
||||||
CobblemonBlocks.LARGE_BUDDING_TUMBLESTONE,
|
CobblemonBlocks.LARGE_BUDDING_TUMBLESTONE,
|
||||||
@@ -242,8 +244,8 @@ object CobblemonClient {
|
|||||||
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.BERRY, ::BerryBlockRenderer)
|
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.BERRY, ::BerryBlockRenderer)
|
||||||
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.SIGN, ::SignBlockEntityRenderer)
|
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.SIGN, ::SignBlockEntityRenderer)
|
||||||
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.HANGING_SIGN, ::HangingSignBlockEntityRenderer)
|
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.HANGING_SIGN, ::HangingSignBlockEntityRenderer)
|
||||||
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.FOSSIL_COMPARTMENT, ::FossilCompartmentRenderer)
|
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.FOSSIL_ANALYZER, ::FossilAnalyzerRenderer)
|
||||||
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.FOSSIL_TUBE, ::FossilTubeRenderer)
|
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.RESTORATION_TANK, ::RestorationTankRenderer)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun registerEntityRenderers() {
|
private fun registerEntityRenderers() {
|
||||||
@@ -255,6 +257,8 @@ object CobblemonClient {
|
|||||||
this.implementation.registerEntityRenderer(CobblemonEntities.BOAT) { ctx -> CobblemonBoatRenderer(ctx, false) }
|
this.implementation.registerEntityRenderer(CobblemonEntities.BOAT) { ctx -> CobblemonBoatRenderer(ctx, false) }
|
||||||
LOGGER.info("Registering Boat with Chest renderer")
|
LOGGER.info("Registering Boat with Chest renderer")
|
||||||
this.implementation.registerEntityRenderer(CobblemonEntities.CHEST_BOAT) { ctx -> CobblemonBoatRenderer(ctx, true) }
|
this.implementation.registerEntityRenderer(CobblemonEntities.CHEST_BOAT) { ctx -> CobblemonBoatRenderer(ctx, true) }
|
||||||
|
LOGGER.info("Registering Falling Star renderer")
|
||||||
|
this.implementation.registerEntityRenderer(CobblemonEntities.FALLING_STAR_ENTITY) { ctx -> FallingStarRenderer(ctx) }
|
||||||
LOGGER.info("Registering PokeRod Bobber renderer")
|
LOGGER.info("Registering PokeRod Bobber renderer")
|
||||||
this.implementation.registerEntityRenderer(CobblemonEntities.POKE_BOBBER) { ctx -> PokeBobberEntityRenderer(ctx) }
|
this.implementation.registerEntityRenderer(CobblemonEntities.POKE_BOBBER) { ctx -> PokeBobberEntityRenderer(ctx) }
|
||||||
}
|
}
|
||||||
@@ -270,6 +274,7 @@ object CobblemonClient {
|
|||||||
PokeBallModelRepository.reload(resourceManager)
|
PokeBallModelRepository.reload(resourceManager)
|
||||||
BerryModelRepository.reload(resourceManager)
|
BerryModelRepository.reload(resourceManager)
|
||||||
FossilModelRepository.reload(resourceManager)
|
FossilModelRepository.reload(resourceManager)
|
||||||
|
MiscModelRepository.reload(resourceManager)
|
||||||
LOGGER.info("Loaded assets")
|
LOGGER.info("Loaded assets")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
@@ -8,7 +8,10 @@
|
|||||||
|
|
||||||
package com.cobblemon.mod.common.client.entity
|
package com.cobblemon.mod.common.client.entity
|
||||||
|
|
||||||
|
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||||
import com.cobblemon.mod.common.api.entity.EntitySideDelegate
|
import com.cobblemon.mod.common.api.entity.EntitySideDelegate
|
||||||
|
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunctions
|
||||||
|
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||||
import com.cobblemon.mod.common.api.reactive.SettableObservable
|
import com.cobblemon.mod.common.api.reactive.SettableObservable
|
||||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||||
import com.cobblemon.mod.common.api.scheduling.SchedulingTracker
|
import com.cobblemon.mod.common.api.scheduling.SchedulingTracker
|
||||||
@@ -37,6 +40,11 @@ class EmptyPokeBallClientDelegate : PokeBallPoseableState(), EntitySideDelegate<
|
|||||||
this.currentEntity = entity
|
this.currentEntity = entity
|
||||||
age = entity.age
|
age = entity.age
|
||||||
initSubscriptions()
|
initSubscriptions()
|
||||||
|
this.runtime.environment.getQueryStruct().addFunctions(mapOf(
|
||||||
|
"pokeball_type" to java.util.function.Function {
|
||||||
|
return@Function DoubleValue(currentEntity.pokeBall.name.toString())
|
||||||
|
}
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun tick(entity: EmptyPokeBallEntity) {
|
override fun tick(entity: EmptyPokeBallEntity) {
|
||||||
|
|||||||
+50
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* 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.entity
|
||||||
|
|
||||||
|
import com.cobblemon.mod.common.api.entity.EntitySideDelegate
|
||||||
|
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityState
|
||||||
|
import com.cobblemon.mod.common.client.render.models.blockbench.repository.GenericBedrockEntityModelRepository
|
||||||
|
import com.cobblemon.mod.common.client.render.models.blockbench.repository.RenderContext
|
||||||
|
import com.cobblemon.mod.common.entity.generic.GenericBedrockEntity
|
||||||
|
|
||||||
|
class GenericBedrockClientDelegate : EntitySideDelegate<GenericBedrockEntity>, PoseableEntityState<GenericBedrockEntity>() {
|
||||||
|
lateinit var currentEntity: GenericBedrockEntity
|
||||||
|
override val schedulingTracker
|
||||||
|
get() = getEntity().schedulingTracker
|
||||||
|
override fun getEntity() = currentEntity
|
||||||
|
|
||||||
|
override fun initialize(entity: GenericBedrockEntity) {
|
||||||
|
super.initialize(entity)
|
||||||
|
this.currentEntity = entity
|
||||||
|
this.age = entity.age
|
||||||
|
this.currentModel = GenericBedrockEntityModelRepository.getPoser(entity.category, entity.aspects)
|
||||||
|
|
||||||
|
val model = currentModel!!
|
||||||
|
model.context.put(RenderContext.ENTITY, entity)
|
||||||
|
currentModel!!.updateLocators(this)
|
||||||
|
updateLocatorPosition(entity.pos)
|
||||||
|
|
||||||
|
val currentPoseType = entity.getCurrentPoseType()
|
||||||
|
val pose = this.currentModel!!.poses.values.firstOrNull { currentPoseType in it.poseTypes && (it.condition == null || it.condition.invoke(entity)) }
|
||||||
|
if (pose != null) {
|
||||||
|
doLater { setPose(pose.poseName) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun tick(entity: GenericBedrockEntity) {
|
||||||
|
super.tick(entity)
|
||||||
|
updateLocatorPosition(entity.pos)
|
||||||
|
incrementAge(entity)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updatePartialTicks(partialTicks: Float) {
|
||||||
|
this.currentPartialTicks = partialTicks
|
||||||
|
}
|
||||||
|
}
|
||||||
+142
-9
@@ -8,25 +8,48 @@
|
|||||||
|
|
||||||
package com.cobblemon.mod.common.client.entity
|
package com.cobblemon.mod.common.client.entity
|
||||||
|
|
||||||
|
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||||
|
import com.bedrockk.molang.runtime.value.StringValue
|
||||||
|
import com.cobblemon.mod.common.CobblemonSounds
|
||||||
|
import com.cobblemon.mod.common.Cobblemon
|
||||||
import com.cobblemon.mod.common.api.entity.PokemonSideDelegate
|
import com.cobblemon.mod.common.api.entity.PokemonSideDelegate
|
||||||
|
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunctions
|
||||||
|
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||||
import com.cobblemon.mod.common.api.scheduling.SchedulingTracker
|
import com.cobblemon.mod.common.api.scheduling.SchedulingTracker
|
||||||
import com.cobblemon.mod.common.api.scheduling.afterOnClient
|
import com.cobblemon.mod.common.api.scheduling.afterOnClient
|
||||||
import com.cobblemon.mod.common.api.scheduling.lerpOnClient
|
import com.cobblemon.mod.common.api.scheduling.lerpOnClient
|
||||||
|
import com.cobblemon.mod.common.client.particle.BedrockParticleEffectRepository
|
||||||
|
import com.cobblemon.mod.common.client.particle.ParticleStorm
|
||||||
|
import com.cobblemon.mod.common.client.render.MatrixWrapper
|
||||||
|
import com.cobblemon.mod.common.client.render.SnowstormParticle
|
||||||
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityState
|
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityState
|
||||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.PrimaryAnimation
|
import com.cobblemon.mod.common.client.render.models.blockbench.animation.PrimaryAnimation
|
||||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.StatefulAnimation
|
import com.cobblemon.mod.common.client.render.models.blockbench.animation.StatefulAnimation
|
||||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
|
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
|
||||||
|
import com.cobblemon.mod.common.client.render.pokemon.PokemonRenderer.Companion.ease
|
||||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||||
|
import com.cobblemon.mod.common.util.MovingSoundInstance
|
||||||
|
import com.cobblemon.mod.common.util.cobblemonResource
|
||||||
|
import net.minecraft.client.MinecraftClient
|
||||||
|
import net.minecraft.client.util.math.MatrixStack
|
||||||
|
import java.lang.Float.min
|
||||||
|
import kotlin.math.abs
|
||||||
import net.minecraft.entity.Entity
|
import net.minecraft.entity.Entity
|
||||||
import net.minecraft.entity.data.TrackedData
|
import net.minecraft.entity.data.TrackedData
|
||||||
|
import net.minecraft.particle.ParticleTypes
|
||||||
|
import net.minecraft.sound.SoundCategory
|
||||||
|
import net.minecraft.sound.SoundEvent
|
||||||
|
import net.minecraft.util.Hand
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
|
import net.minecraft.util.math.Vec3d
|
||||||
|
|
||||||
class PokemonClientDelegate : PoseableEntityState<PokemonEntity>(), PokemonSideDelegate {
|
class PokemonClientDelegate : PoseableEntityState<PokemonEntity>(), PokemonSideDelegate {
|
||||||
companion object {
|
companion object {
|
||||||
const val BEAM_SHRINK_TIME = 0.8F
|
const val BEAM_SHRINK_TIME = 0.4F
|
||||||
const val BEAM_EXTEND_TIME = 0.2F
|
const val BEAM_EXTEND_TIME = 0.2F
|
||||||
|
const val POKEBALL_AIR_TIME = 0.5F
|
||||||
}
|
}
|
||||||
|
|
||||||
override val schedulingTracker: SchedulingTracker
|
override val schedulingTracker: SchedulingTracker
|
||||||
@@ -43,10 +66,21 @@ class PokemonClientDelegate : PoseableEntityState<PokemonEntity>(), PokemonSideD
|
|||||||
}
|
}
|
||||||
|
|
||||||
var beamStartTime = System.currentTimeMillis()
|
var beamStartTime = System.currentTimeMillis()
|
||||||
|
var ballStartTime = System.currentTimeMillis()
|
||||||
|
var ballDone = false
|
||||||
|
var ballOffset = 0f
|
||||||
|
var ballRotOffset = 0f
|
||||||
|
var sendOutPosition: Vec3d? = null
|
||||||
|
var sendOutOffset: Vec3d? = null
|
||||||
|
var playedSendOutSound: Boolean = false
|
||||||
|
var playedThrowingSound: Boolean = false
|
||||||
|
|
||||||
val secondsSinceBeamEffectStarted: Float
|
val secondsSinceBeamEffectStarted: Float
|
||||||
get() = (System.currentTimeMillis() - beamStartTime) / 1000F
|
get() = (System.currentTimeMillis() - beamStartTime) / 1000F
|
||||||
|
|
||||||
|
val secondsSinceBallThrown: Float
|
||||||
|
get() = (System.currentTimeMillis() - ballStartTime) / 1000F
|
||||||
|
|
||||||
private var cryAnimation: StatefulAnimation<PokemonEntity, *>? = null
|
private var cryAnimation: StatefulAnimation<PokemonEntity, *>? = null
|
||||||
|
|
||||||
override fun onTrackedDataSet(data: TrackedData<*>) {
|
override fun onTrackedDataSet(data: TrackedData<*>) {
|
||||||
@@ -61,7 +95,7 @@ class PokemonClientDelegate : PoseableEntityState<PokemonEntity>(), PokemonSideD
|
|||||||
if (isDying) {
|
if (isDying) {
|
||||||
val model = (currentModel ?: return) as PokemonPoseableModel
|
val model = (currentModel ?: return) as PokemonPoseableModel
|
||||||
val animation = try {
|
val animation = try {
|
||||||
model.getFaintAnimation(currentEntity, this)
|
model.getAnimation(this, "faint", runtime)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
null
|
null
|
||||||
@@ -76,21 +110,95 @@ class PokemonClientDelegate : PoseableEntityState<PokemonEntity>(), PokemonSideD
|
|||||||
0 -> { /* Do nothing */ }
|
0 -> { /* Do nothing */ }
|
||||||
1 -> {
|
1 -> {
|
||||||
// Scaling up out of pokeball
|
// Scaling up out of pokeball
|
||||||
|
playedSendOutSound = false
|
||||||
entityScaleModifier = 0F
|
entityScaleModifier = 0F
|
||||||
beamStartTime = System.currentTimeMillis()
|
beamStartTime = System.currentTimeMillis()
|
||||||
|
ballStartTime = System.currentTimeMillis()
|
||||||
currentEntity.isInvisible = true
|
currentEntity.isInvisible = true
|
||||||
afterOnClient(seconds = BEAM_EXTEND_TIME) {
|
ballDone = false
|
||||||
lerpOnClient(BEAM_SHRINK_TIME) { entityScaleModifier = it }
|
var soundPos = currentEntity.pos
|
||||||
currentEntity.isInvisible = false
|
currentEntity.pokemon.getOwnerUUID()?.let{
|
||||||
|
currentEntity.world.getPlayerByUuid(it)?.let {
|
||||||
|
val offset = it.pos.subtract(currentEntity.pos.add(0.0, 2.0 - (ballOffset.toDouble()/10f), 0.0)).normalize().multiply(-ease(ballOffset.toDouble()))
|
||||||
|
with(it.pos.subtract(currentEntity.pos)) {
|
||||||
|
var newOffset = offset.multiply(2.0)
|
||||||
|
val distance = it.pos.distanceTo(currentEntity.pos)
|
||||||
|
newOffset = newOffset.multiply((distance / 10.0) * 5)
|
||||||
|
soundPos = currentEntity.pos.add(newOffset)
|
||||||
|
}
|
||||||
|
it.swingHand(it.activeHand ?: Hand.MAIN_HAND)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val client = MinecraftClient.getInstance()
|
||||||
|
val sound = MovingSoundInstance(SoundEvent.of(CobblemonSounds.POKE_BALL_TRAIL.id), SoundCategory.PLAYERS, { sendOutPosition?.add(sendOutOffset) }, 0.1f, 1f, false, 20, 0)
|
||||||
|
if(!playedThrowingSound){
|
||||||
|
client.soundManager.play(sound)
|
||||||
|
playedThrowingSound = true
|
||||||
|
}
|
||||||
|
lerpOnClient(POKEBALL_AIR_TIME) { ballOffset = it }
|
||||||
|
ballRotOffset = ((Math.random()) * currentEntity.world.random.nextBetween(-15, 15)).toFloat()
|
||||||
|
|
||||||
|
currentEntity.after(seconds = POKEBALL_AIR_TIME){
|
||||||
|
beamStartTime = System.currentTimeMillis()
|
||||||
|
ballDone = true
|
||||||
|
if (client.soundManager.get(CobblemonSounds.POKE_BALL_OPEN.id) != null && !playedSendOutSound) {
|
||||||
|
currentEntity.owner?.let {
|
||||||
|
client.world?.playSound(client.player, soundPos.x, soundPos.y, soundPos.z, SoundEvent.of(CobblemonSounds.POKE_BALL_SEND_OUT.id), SoundCategory.PLAYERS, 0.6f, 1f)
|
||||||
|
playedSendOutSound = true
|
||||||
|
/// create end rod particles in a 0.1 radius around the soundPos with a count of 50 and a random velocity of 0.1
|
||||||
|
sendOutPosition?.let{
|
||||||
|
val newPos = it.add(sendOutOffset)
|
||||||
|
val ballType = currentEntity.pokemon.caughtBall.name.path.toLowerCase().replace("_","")
|
||||||
|
val mode = if(currentEntity.isBattling) "battle" else "casual"
|
||||||
|
val sendflash = BedrockParticleEffectRepository.getEffect(cobblemonResource("${ballType}/${mode}/sendflash"))
|
||||||
|
sendflash?.let { effect ->
|
||||||
|
val wrapper = MatrixWrapper()
|
||||||
|
val matrix = MatrixStack()
|
||||||
|
matrix.translate(newPos.x, newPos.y, newPos.z)
|
||||||
|
wrapper.updateMatrix(matrix.peek().positionMatrix)
|
||||||
|
val world = MinecraftClient.getInstance().world ?: return@let
|
||||||
|
ParticleStorm(effect, wrapper, world).spawn()
|
||||||
|
val ballsparks = BedrockParticleEffectRepository.getEffect(cobblemonResource("${ballType}/${mode}/ballsparks"))
|
||||||
|
val ballsendsparkle = BedrockParticleEffectRepository.getEffect(cobblemonResource("${ballType}/${mode}/ballsendsparkle"))
|
||||||
|
// using afterOnClient because it's such a small timeframe that it's unlikely the entity has been removed & we'd like the precision
|
||||||
|
afterOnClient(seconds = 0.01667f) {
|
||||||
|
ballsparks?.let { effect ->
|
||||||
|
ParticleStorm(effect, wrapper, world).spawn()
|
||||||
|
}
|
||||||
|
ballsendsparkle?.let { effect ->
|
||||||
|
ParticleStorm(effect, wrapper, world).spawn()
|
||||||
|
}
|
||||||
|
currentEntity.after(seconds = 0.4f) {
|
||||||
|
val ballsparkle = BedrockParticleEffectRepository.getEffect(cobblemonResource("${ballType}/ballsparkle"))
|
||||||
|
ballsparkle?.let { effect ->
|
||||||
|
ParticleStorm(effect, wrapper, world).spawn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currentEntity.after(seconds = BEAM_EXTEND_TIME) {
|
||||||
|
lerpOnClient(BEAM_SHRINK_TIME) { entityScaleModifier = it }
|
||||||
|
currentEntity.isInvisible = false
|
||||||
|
currentEntity.after(seconds = POKEBALL_AIR_TIME*2){
|
||||||
|
ballOffset = 0f
|
||||||
|
ballRotOffset = 0f
|
||||||
|
sendOutPosition = null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
// Scaling down into pokeball
|
// Scaling down into pokeball
|
||||||
entityScaleModifier = 1F
|
entityScaleModifier = 1F
|
||||||
beamStartTime = System.currentTimeMillis()
|
beamStartTime = System.currentTimeMillis()
|
||||||
|
ballOffset = 0f
|
||||||
|
ballRotOffset = 0f
|
||||||
|
sendOutPosition = null
|
||||||
afterOnClient(seconds = BEAM_EXTEND_TIME) {
|
afterOnClient(seconds = BEAM_EXTEND_TIME) {
|
||||||
val afterPoint2 = System.currentTimeMillis()
|
lerpOnClient(BEAM_SHRINK_TIME) {
|
||||||
lerpOnClient(BEAM_SHRINK_TIME) {
|
|
||||||
entityScaleModifier = (1 - it)
|
entityScaleModifier = (1 - it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,6 +226,27 @@ class PokemonClientDelegate : PoseableEntityState<PokemonEntity>(), PokemonSideD
|
|||||||
override fun initialize(entity: PokemonEntity) {
|
override fun initialize(entity: PokemonEntity) {
|
||||||
this.currentEntity = entity
|
this.currentEntity = entity
|
||||||
this.age = entity.age
|
this.age = entity.age
|
||||||
|
|
||||||
|
this.runtime.environment.getQueryStruct().addFunctions(mapOf(
|
||||||
|
"in_battle" to java.util.function.Function {
|
||||||
|
return@Function DoubleValue(currentEntity.isBattling)
|
||||||
|
},
|
||||||
|
"shiny" to java.util.function.Function {
|
||||||
|
return@Function DoubleValue(currentEntity.pokemon.shiny)
|
||||||
|
},
|
||||||
|
"form" to java.util.function.Function {
|
||||||
|
return@Function StringValue(currentEntity.pokemon.form.name)
|
||||||
|
},
|
||||||
|
"width" to java.util.function.Function {
|
||||||
|
return@Function DoubleValue(currentEntity.boundingBox.xLength)
|
||||||
|
},
|
||||||
|
"height" to java.util.function.Function {
|
||||||
|
return@Function DoubleValue(currentEntity.boundingBox.yLength)
|
||||||
|
},
|
||||||
|
"weight" to java.util.function.Function {
|
||||||
|
return@Function DoubleValue(currentEntity.pokemon.species.weight.toDouble())
|
||||||
|
}
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun tick(entity: PokemonEntity) {
|
override fun tick(entity: PokemonEntity) {
|
||||||
@@ -144,12 +273,16 @@ class PokemonClientDelegate : PoseableEntityState<PokemonEntity>(), PokemonSideD
|
|||||||
fun cry() {
|
fun cry() {
|
||||||
val model = currentModel ?: return
|
val model = currentModel ?: return
|
||||||
if (model is PokemonPoseableModel) {
|
if (model is PokemonPoseableModel) {
|
||||||
if (cryAnimation != null && cryAnimation in statefulAnimations) {
|
if (cryAnimation != null && (cryAnimation in statefulAnimations || cryAnimation == primaryAnimation)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val animation = model.cryAnimation(currentEntity, this) ?: return
|
val animation = model.cryAnimation(currentEntity, this) ?: return
|
||||||
statefulAnimations.add(animation)
|
if (animation is PrimaryAnimation) {
|
||||||
|
addPrimaryAnimation(animation)
|
||||||
|
} else {
|
||||||
|
statefulAnimations.add(animation)
|
||||||
|
}
|
||||||
cryAnimation = animation
|
cryAnimation = animation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -138,7 +138,8 @@ abstract class BattleGimmickButton(gimmick: ShowdownMoveset.Gimmick, val x: Floa
|
|||||||
pp = gimmickTemplate?.pp ?: moveTemplate.pp,
|
pp = gimmickTemplate?.pp ?: moveTemplate.pp,
|
||||||
priority = gimmickTemplate?.priority ?: moveTemplate.priority,
|
priority = gimmickTemplate?.priority ?: moveTemplate.priority,
|
||||||
critRatio = gimmickTemplate?.critRatio ?: moveTemplate.critRatio,
|
critRatio = gimmickTemplate?.critRatio ?: moveTemplate.critRatio,
|
||||||
effectChances = gimmickTemplate?.effectChances ?: moveTemplate.effectChances
|
effectChances = gimmickTemplate?.effectChances ?: moveTemplate.effectChances,
|
||||||
|
actionEffect = null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
@@ -9,7 +9,9 @@
|
|||||||
package com.cobblemon.mod.common.client.gui.interact.wheel
|
package com.cobblemon.mod.common.client.gui.interact.wheel
|
||||||
|
|
||||||
import com.cobblemon.mod.common.api.gui.blitk
|
import com.cobblemon.mod.common.api.gui.blitk
|
||||||
|
import net.minecraft.client.MinecraftClient
|
||||||
import net.minecraft.client.gui.DrawContext
|
import net.minecraft.client.gui.DrawContext
|
||||||
|
import net.minecraft.client.gui.tooltip.Tooltip
|
||||||
import net.minecraft.client.gui.widget.ButtonWidget
|
import net.minecraft.client.gui.widget.ButtonWidget
|
||||||
import net.minecraft.client.sound.SoundManager
|
import net.minecraft.client.sound.SoundManager
|
||||||
import net.minecraft.client.util.math.MatrixStack
|
import net.minecraft.client.util.math.MatrixStack
|
||||||
@@ -21,6 +23,7 @@ import org.joml.Vector4f
|
|||||||
class InteractWheelButton(
|
class InteractWheelButton(
|
||||||
private val iconResource: Identifier?,
|
private val iconResource: Identifier?,
|
||||||
private val buttonResource: Identifier,
|
private val buttonResource: Identifier,
|
||||||
|
private val tooltipText: String?,
|
||||||
x: Int,
|
x: Int,
|
||||||
y: Int,
|
y: Int,
|
||||||
private val isEnabled: Boolean,
|
private val isEnabled: Boolean,
|
||||||
@@ -50,6 +53,12 @@ class InteractWheelButton(
|
|||||||
alpha = if (isEnabled) 1f else 0.4f
|
alpha = if (isEnabled) 1f else 0.4f
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(isHovered(mouseX.toFloat(), mouseY.toFloat())){
|
||||||
|
tooltipText?.let {
|
||||||
|
context.drawTooltip(MinecraftClient.getInstance().textRenderer, Text.translatable(it), mouseX, mouseY)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (iconResource != null) {
|
if (iconResource != null) {
|
||||||
val (iconX, iconY) = getIconPosition()
|
val (iconX, iconY) = getIconPosition()
|
||||||
val colour = this.colour() ?: Vector3f(1F, 1F, 1F)
|
val colour = this.colour() ?: Vector3f(1F, 1F, 1F)
|
||||||
@@ -86,4 +95,8 @@ class InteractWheelButton(
|
|||||||
return mouseX in xMin..xMax && mouseY in yMin..yMax
|
return mouseX in xMin..xMax && mouseY in yMin..yMax
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getTooltip(): Tooltip? {
|
||||||
|
tooltipText?.let { return Tooltip.of(Text.translatable(it)) } ?: return super.getTooltip()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user