mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-11-06 00:08:53 -05:00
Compare commits
419
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4eba39562a | ||
|
|
b8f73f277d | ||
|
|
6df2b996e2 | ||
|
|
ddc4bd358d | ||
|
|
40c5df46ce | ||
|
|
1b1d22fdf3 | ||
|
|
1ee1001774 | ||
|
|
533272ef09 | ||
|
|
91300e4d03 | ||
|
|
fc135faf57 | ||
|
|
cdd72c664e | ||
|
|
5f025d0f68 | ||
|
|
6af2c807ab | ||
|
|
c45c90c6c7 | ||
|
|
1ec97c4c90 | ||
|
|
f0bcd38ac7 | ||
|
|
f4ba446c79 | ||
|
|
60f98ebfce | ||
|
|
36a93bda5a | ||
|
|
8d60b07c54 | ||
|
|
5f9cc86044 | ||
|
|
a6b7e07cf5 | ||
|
|
0ba6215b8d | ||
|
|
e2f6fae689 | ||
|
|
296aa01d0f | ||
|
|
12ab3f2d07 | ||
|
|
5a7a374bc9 | ||
|
|
ceece45ad4 | ||
|
|
b344ad66c5 | ||
|
|
dbc7af4ad4 | ||
|
|
5f5bf01cb5 | ||
|
|
04f2af22f3 | ||
|
|
ea916a0db8 | ||
|
|
3f03afc7eb | ||
|
|
e940483863 | ||
|
|
9e3d3df3a9 | ||
|
|
c18368d777 | ||
|
|
aab5b55204 | ||
|
|
3e6e346eb9 | ||
|
|
7bef6db7b7 | ||
|
|
71775328ef | ||
|
|
727785b0b3 | ||
|
|
762241420e | ||
|
|
93011f084b | ||
|
|
7c90a8425e | ||
|
|
8674cbe788 | ||
|
|
8075fe0bae | ||
|
|
0152803192 | ||
|
|
5e094241e3 | ||
|
|
bd028c328d | ||
|
|
598cb1d964 | ||
|
|
79d264fd94 | ||
|
|
5f691d3f1c | ||
|
|
7be0163e76 | ||
|
|
c0b3068824 | ||
|
|
dd35adc05d | ||
|
|
26b5707317 | ||
|
|
75e39f5595 | ||
|
|
7fdeaeabef | ||
|
|
809ffd8b90 | ||
|
|
da7610951d | ||
|
|
76fdd1fa98 | ||
|
|
156983bf58 | ||
|
|
c69930b836 | ||
|
|
6926932340 | ||
|
|
221b3308fa | ||
|
|
66840670b6 | ||
|
|
5d6a7807e5 | ||
|
|
20b7eb17f3 | ||
|
|
103ac86345 | ||
|
|
8f705a698d | ||
|
|
f4fb09947e | ||
|
|
97e31e341b | ||
|
|
813789235d | ||
|
|
5a82e7e185 | ||
|
|
3bc8d3ce75 | ||
|
|
d9e9fd0f4e | ||
|
|
fddb203db3 | ||
|
|
8a8cace5e8 | ||
|
|
5f5b4ee3c1 | ||
|
|
aa6581ae39 | ||
|
|
8aa9e0191f | ||
|
|
8dc09796f8 | ||
|
|
8f93712edb | ||
|
|
b91d1b931e | ||
|
|
9d84cbb3ac | ||
|
|
8e730f2b5c | ||
|
|
7b5809fd55 | ||
|
|
bc682ddf62 | ||
|
|
990ead0544 | ||
|
|
4cf55dc95d | ||
|
|
27a9f3c704 | ||
|
|
83aba7e4a6 | ||
|
|
db10ae2183 | ||
|
|
548b8522a8 | ||
|
|
4791b146dc | ||
|
|
b7a9931393 | ||
|
|
9a35a11440 | ||
|
|
6d4a50cee2 | ||
|
|
818a637897 | ||
|
|
4c96ab9b28 | ||
|
|
d5a316b9ae | ||
|
|
87e32f0e9b | ||
|
|
73275626a3 | ||
|
|
0686428138 | ||
|
|
f05e6008e5 | ||
|
|
53372e5400 | ||
|
|
2fbb1f354c | ||
|
|
bf06476558 | ||
|
|
2e3a742477 | ||
|
|
94c7542d2c | ||
|
|
fa2b6b5996 | ||
|
|
8e77dc70f6 | ||
|
|
51e3748adb | ||
|
|
d8cf2701c7 | ||
|
|
4450164d9c | ||
|
|
31b7c83369 | ||
|
|
a170123e2c | ||
|
|
b99899353c | ||
|
|
c3c17a228e | ||
|
|
41d607ad56 | ||
|
|
58b3596948 | ||
|
|
ed4456d756 | ||
|
|
608b711833 | ||
|
|
3adc1b9f30 | ||
|
|
478cbc2489 | ||
|
|
481734e6b1 | ||
|
|
636792fa1f | ||
|
|
ad65002b19 | ||
|
|
903f3b6d5a | ||
|
|
4456743e97 | ||
|
|
d0989e5ece | ||
|
|
03edb5a385 | ||
|
|
180229db61 | ||
|
|
cf77713860 | ||
|
|
b6e10c016e | ||
|
|
0494193c9b | ||
|
|
7bee34170d | ||
|
|
ce09236dab | ||
|
|
0bb968dd73 | ||
|
|
f3d4cb34e0 | ||
|
|
3a22e387b6 | ||
|
|
956b3bfcbd | ||
|
|
3b6e1bd429 | ||
|
|
1eb7354fc0 | ||
|
|
52ad6a3250 | ||
|
|
aa57bbbf34 | ||
|
|
26278eeb46 | ||
|
|
a9ceddd94a | ||
|
|
e99c55e812 | ||
|
|
5053d559bc | ||
|
|
1a30109f1c | ||
|
|
efd4a72287 | ||
|
|
5088497575 | ||
|
|
bba8a12a2a | ||
|
|
31129ef14d | ||
|
|
1cdf664dce | ||
|
|
2ea5eb2823 | ||
|
|
e109b0fc9f | ||
|
|
5de7f96fef | ||
|
|
1f62f447b5 | ||
|
|
674e1df96d | ||
|
|
a4a2ae6133 | ||
|
|
17c71efb17 | ||
|
|
e80eb91e69 | ||
|
|
a5b6a954fd | ||
|
|
a5c3d2f800 | ||
|
|
00d2bbbe42 | ||
|
|
2a295a8796 | ||
|
|
40b351a303 | ||
|
|
dc32bd1845 | ||
|
|
a096485155 | ||
|
|
f1ae7c4476 | ||
|
|
bcfac2f68a | ||
|
|
ff1902770c | ||
|
|
ebb01d4fcc | ||
|
|
0b392c66eb | ||
|
|
5733074bd8 | ||
|
|
88ff4e37b8 | ||
|
|
245226f4f6 | ||
|
|
35b7a80501 | ||
|
|
91949414cc | ||
|
|
d3e1c2c79d | ||
|
|
10bfe3b29d | ||
|
|
ff88a3c756 | ||
|
|
4d47cb8385 | ||
|
|
8aba2bc279 | ||
|
|
fe91e912d0 | ||
|
|
680bc1d205 | ||
|
|
e04e82c6de | ||
|
|
d0c4bd5a16 | ||
|
|
500069e5d8 | ||
|
|
13ae174c66 | ||
|
|
95589dd48b | ||
|
|
4cb17135bd | ||
|
|
8dc23160fc | ||
|
|
4a96a41c8e | ||
|
|
3bf777c2a9 | ||
|
|
b5174686b4 | ||
|
|
26a7bc29b3 | ||
|
|
05cd37eb38 | ||
|
|
3f18e7c0bf | ||
|
|
3ac3fcbcda | ||
|
|
27b3884f27 | ||
|
|
15e8f46702 | ||
|
|
e91b1061d3 | ||
|
|
3c3a23a397 | ||
|
|
438de6ed6d | ||
|
|
c754d820a5 | ||
|
|
81c819ddd3 | ||
|
|
f042d167d1 | ||
|
|
eff3bd91d7 | ||
|
|
ec3e0bfd04 | ||
|
|
1391bfee01 | ||
|
|
b61d739e46 | ||
|
|
7a050d5374 | ||
|
|
52076de76a | ||
|
|
e8b6bee139 | ||
|
|
a98bc80005 | ||
|
|
06d25a043c | ||
|
|
6aa3b8b92f | ||
|
|
7381b47830 | ||
|
|
b2a704fa12 | ||
|
|
41ed476c00 | ||
|
|
44ddf097d6 | ||
|
|
cb1386fdb3 | ||
|
|
0dafe79032 | ||
|
|
51cd929d1c | ||
|
|
5468d5e888 | ||
|
|
0174b8bc67 | ||
|
|
e3b8fbb973 | ||
|
|
7103df0116 | ||
|
|
42fba85241 | ||
|
|
f9f11c7137 | ||
|
|
a51acead21 | ||
|
|
7a3ab17e57 | ||
|
|
d4e741c614 | ||
|
|
bee1797ff5 | ||
|
|
72fa7d42d5 | ||
|
|
7a4bf4cc5d | ||
|
|
ab66e13c8c | ||
|
|
eaeea493a1 | ||
|
|
0bfaedbf6e | ||
|
|
52f9f45608 | ||
|
|
dfa9dc1e2b | ||
|
|
c8f5538ae8 | ||
|
|
5af5a59ff1 | ||
|
|
eb37ecbe56 | ||
|
|
d7b528aef1 | ||
|
|
2908ca3a89 | ||
|
|
aa04dc077b | ||
|
|
c1c064e657 | ||
|
|
c0a509820f | ||
|
|
aa0b71aad7 | ||
|
|
55c5dfddc4 | ||
|
|
b40c69a1d9 | ||
|
|
ca20f432b3 | ||
|
|
63fe61b913 | ||
|
|
7605b526c8 | ||
|
|
189f39f1c1 | ||
|
|
8c718069c7 | ||
|
|
c2facdf5ce | ||
|
|
0c5dcb26f6 | ||
|
|
b88634691b | ||
|
|
df9dcdd622 | ||
|
|
15943fae47 | ||
|
|
78a71ba252 | ||
|
|
7f1acd16b5 | ||
|
|
be038d2348 | ||
|
|
b3b11012f4 | ||
|
|
095c466b89 | ||
|
|
4c3cd6fdc4 | ||
|
|
2379b22135 | ||
|
|
f36fa861da | ||
|
|
3b4f9d0fba | ||
|
|
42dabbf16a | ||
|
|
07abff7583 | ||
|
|
dbd9bfacc5 | ||
|
|
6ed1ea0cad | ||
|
|
5384fec57e | ||
|
|
1868bcf4d7 | ||
|
|
42059b9931 | ||
|
|
24890225a2 | ||
|
|
e4e32769dc | ||
|
|
3420422a4b | ||
|
|
18564baec7 | ||
|
|
b0c6d83913 | ||
|
|
5016b2b227 | ||
|
|
4727321d47 | ||
|
|
6e96e92d33 | ||
|
|
a8c92ce641 | ||
|
|
032d2e5c95 | ||
|
|
ec9d7d9dae | ||
|
|
217dab4dea | ||
|
|
452a92daa9 | ||
|
|
fb364deff9 | ||
|
|
ac824ce39c | ||
|
|
fa74a1c45a | ||
|
|
1cce1d1a44 | ||
|
|
b7f537e34c | ||
|
|
0311a8a4ef | ||
|
|
14ecc13cb3 | ||
|
|
5baca56d6d | ||
|
|
91c9692db1 | ||
|
|
bb7b1a8dee | ||
|
|
e6322e5fb7 | ||
|
|
3c5f04b52a | ||
|
|
5d78a5b573 | ||
|
|
4f58615065 | ||
|
|
32a4161a69 | ||
|
|
c5708145cd | ||
|
|
118f207adb | ||
|
|
a5826028b3 | ||
|
|
fa3f6053c3 | ||
|
|
bc60fe58b1 | ||
|
|
f9a5e9a9e4 | ||
|
|
6f6ee6f160 | ||
|
|
8a3dbd5e4a | ||
|
|
e052ad2281 | ||
|
|
8938ea13a4 | ||
|
|
907aed4c63 | ||
|
|
60798aae03 | ||
|
|
6f09957fbf | ||
|
|
6fc2344473 | ||
|
|
c82059ae72 | ||
|
|
a080db690f | ||
|
|
d82849ddd3 | ||
|
|
71a3fe6e48 | ||
|
|
5e934ac7a6 | ||
|
|
6aa5bde424 | ||
|
|
fee7488090 | ||
|
|
f5e5e3411e | ||
|
|
818f9365ec | ||
|
|
f81db9df3d | ||
|
|
8162e3a30d | ||
|
|
5a00bbf02d | ||
|
|
ff7fff52ec | ||
|
|
087fab4065 | ||
|
|
bed2897950 | ||
|
|
d51f0711b7 | ||
|
|
728860332d | ||
|
|
fe0ca14b3b | ||
|
|
7e57c3c862 | ||
|
|
0f4fdfcedd | ||
|
|
1cb77f35b5 | ||
|
|
9ac23be59b | ||
|
|
e469409a22 | ||
|
|
28db8e98d7 | ||
|
|
08bf3d4f8f | ||
|
|
88380bfb76 | ||
|
|
83d7cbbefa | ||
|
|
426d7c8e5e | ||
|
|
602d88db5e | ||
|
|
751d3be872 | ||
|
|
358a62d5b1 | ||
|
|
409814823b | ||
|
|
5d8f45b058 | ||
|
|
3001e8bf84 | ||
|
|
80de268987 | ||
|
|
b08004b6c6 | ||
|
|
2783a52495 | ||
|
|
3ae3f0db95 | ||
|
|
a15f026739 | ||
|
|
bc8ed8bb38 | ||
|
|
efa246272b | ||
|
|
e29d84a71a | ||
|
|
6c671b5e08 | ||
|
|
3ffd9ecc28 | ||
|
|
281131f5b3 | ||
|
|
3c67cd2a59 | ||
|
|
74f5c69bb5 | ||
|
|
8f82e1d960 | ||
|
|
c5497cfb2b | ||
|
|
94b6b3b948 | ||
|
|
8855c5ad7f | ||
|
|
5015a0a56c | ||
|
|
ec51fc0701 | ||
|
|
13287e6f76 | ||
|
|
a65dfcd3cd | ||
|
|
18183dd649 | ||
|
|
40c1f074bb | ||
|
|
5d1219e467 | ||
|
|
568773f1a8 | ||
|
|
f0c3cde213 | ||
|
|
def5d09903 | ||
|
|
ad5e2ddc41 | ||
|
|
2d2f92c7a7 | ||
|
|
2bd4d1fb08 | ||
|
|
4c342c2047 | ||
|
|
24cee748d5 | ||
|
|
fbec6f03e7 | ||
|
|
8ab0288ab2 | ||
|
|
cc426a5ca9 | ||
|
|
e4f04b605a | ||
|
|
48441b1232 | ||
|
|
589d3614b8 | ||
|
|
fe386095de | ||
|
|
5640177c99 | ||
|
|
ff8c8b1bfa | ||
|
|
4bccd9b5aa | ||
|
|
8c1c5ac957 | ||
|
|
a20ec4d1c5 | ||
|
|
12b4e58dea | ||
|
|
be8dfd7fa2 | ||
|
|
940ec82182 | ||
|
|
67c01ce5f2 | ||
|
|
e603325eef | ||
|
|
afd09e93eb | ||
|
|
92775a4b8a | ||
|
|
6a2668171e | ||
|
|
5b7dc9f8f4 | ||
|
|
75dc76020f | ||
|
|
56289ce5bf | ||
|
|
e4ec7b0ae7 | ||
|
|
f38ef0b6b9 | ||
|
|
d5bb3e2d97 | ||
|
|
66f6555711 | ||
|
|
472ca9c748 | ||
|
|
054e4dffdc |
No files matched your search
@@ -2,6 +2,7 @@
|
||||
## [1.7.0 (Month xth, 2025)](#1-7-0)
|
||||
|
||||
### Additions
|
||||
- Added `/npcdelete` uuid parameter support and usuable to console
|
||||
- Added `/spectateBattle <player>` command to spectate battles without having to manually walk up to the target.
|
||||
- Added an in-game configuration screen, allowing all settings from `main.json` to be edited directly in-game.
|
||||
- Added `/cobblemonconfig reload` command to reload `main.json` configuration. **Note:** Some settings require a server restart to take effect; use this command cautiously.
|
||||
@@ -33,6 +34,7 @@
|
||||
- Added Hyper Training items (IV Modification) as well as some additional candy items to do so (Health Candy, Sickly Candy)
|
||||
- Added Galarica Nut Bushes
|
||||
- Many Pokémon (mostly cats) are now feared by phantoms
|
||||
- Combees are now capable of gathering nectar from flowers and delivering it to either Saccharine leaves or hives. (Hive interactions are restricted to wild Combees)
|
||||
- Lightning is now affected by a Pokemon's ability/typing
|
||||
- Pokémon with the ability Lightning Rod draw in lightning similar to a lightning rod block albeit with a lower priority and range, gain immunity to lightning damage, and receive a temporary damage buff.
|
||||
- Pokémon with the ability Motor Drive are immune to lightning damage and receive a temporary speed buff when struck by lightning
|
||||
@@ -292,6 +294,7 @@
|
||||
- Tauros - Paldea Blaze
|
||||
- Tauros - Paldea Combat
|
||||
- Dewgong
|
||||
- Exeggutor - Kanto
|
||||
|
||||
### Model updates for the following Pokémon
|
||||
- Cleffa
|
||||
@@ -402,6 +405,9 @@
|
||||
- Revavroom
|
||||
- Nickit
|
||||
- Thievul
|
||||
- Litwick
|
||||
- Lampent
|
||||
- Chandelure
|
||||
|
||||
### Changes
|
||||
- Changed pokemon caught and seen count to update based on the current pokedex being looked
|
||||
@@ -415,6 +421,8 @@
|
||||
- Updated some item tags to better integrate behaviours between Cobblemon, Vanilla Minecraft, and other mods
|
||||
- Removed Cooked Meat, Raw Meat, Protein Ingredients, and Zinc Ingredients, the first two are now using `c` namespace tags, the latter have better integrated use of tags within their recipes which removes need for custom tags.
|
||||
- Added our seeds tag into `#c:seeds`, which is now made use of for the Miracle Seed recipe.
|
||||
- Updated the `#cobblemon:berries` tag to use subtags located in `data/cobblemon/tags/item/berries`, such as `#cobblemon:berries/hp_recovery` for sorting purposes
|
||||
- Moved the tag `#cobblemon:mutated_berries` to `#cobblemon:berries/mutation_result`
|
||||
- Added herbs and snowballs to the consumable in PvE and Wild battle tags
|
||||
- Tweaked the Natural Materials Vanilla file to fit with the changes to tags
|
||||
- Substantially optimised spawning checks mainly by front-loading biome filtering.
|
||||
@@ -466,6 +474,8 @@
|
||||
- Updated `HatchEggEvent.Post` to include the Pokemon that hatched.
|
||||
- Roseli Berry Trees now naturally generate in their preferred biomes.
|
||||
- Refactored dynamic lights compat to be more future proof. The dynamic light support is only tested with LambDynamicLights, on NeoForged use that mod in combination with Sinytra Connector
|
||||
- Shulker Boxes and Traveler's Backpacks can no longer be held by Pokémon. Thanks Monocle ;) You could re-enable this with a datapack but you'd be crazy.
|
||||
- Moomoo Milk now clears Pokémon stat changes when used in battle.
|
||||
|
||||
### Fixes
|
||||
- Fixed game crashing when removing national pokedex using datapacks
|
||||
@@ -549,6 +559,9 @@
|
||||
- Fixed busted abilities and moves in Pokémon data due to removed datapacks etc. causing storage corruption. It now just rerolls their ability / uses Tackle.
|
||||
- Fixed singular Pokémon corruption causing entire storage corruption. Storages will now skip corrupted Pokémon and print an error to console.
|
||||
- Fixed species additions not being able to properly mark a species as implemented.
|
||||
- Fixed Pokémon item models not showing a glint when enchanted.
|
||||
- Fixed some specific bag items not being dropped when used in battle.
|
||||
- Fixed the "use all berry bait" achievement not being progressed
|
||||
|
||||
### Developer
|
||||
- A finished battle now has winners and losers set inside of `PokemonBattle` instead of them always being empty.
|
||||
@@ -693,6 +706,9 @@
|
||||
- Mechanics
|
||||
- Unlockable Wallpapers
|
||||
- Starter Data
|
||||
- Fixed `cobblemon:reel_in_pokemon` criteria not working when used together with a `baitId`
|
||||
- Also changed the default from `cobblemon:empty_bait` to `any`
|
||||
- The previous default is still available by using the above as baitId
|
||||
|
||||
### Particles
|
||||
Added new/updated particles for the following moves:
|
||||
@@ -988,6 +1004,7 @@ Added new/updated particles for the following moves:
|
||||
- Parametric particle motion now works.
|
||||
- Event-spawned particles now work.
|
||||
- Particles can now have independent coordinate spaces.
|
||||
- Fixed suffocation of Pokémon when a pokeball breaks near a wall
|
||||
|
||||
### Developer
|
||||
- Updated the Pokédex data updated events to always include a `Pokemon` instance, and optionally a `DisguiseData` instance.
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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.CobblemonMemories;
|
||||
import com.cobblemon.mod.common.api.ai.config.task.PathToBeeHiveTaskConfig;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.item.component.CustomData;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.BeehiveBlock;
|
||||
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
|
||||
import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
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(BeehiveBlockEntity.Occupant.class)
|
||||
public abstract class BeeOccupantMixin {
|
||||
|
||||
@Inject(method = "createEntity", at = @At("RETURN"), cancellable = true)
|
||||
private void cobblemon$createEntity(Level level, BlockPos pos, CallbackInfoReturnable<Entity> cir) {
|
||||
// Needing to replicate all the post op stuff on the hive isn't great
|
||||
if (cir.getReturnValue() == null) {
|
||||
final BeehiveBlockEntity.Occupant occupant = (BeehiveBlockEntity.Occupant) (Object) this;
|
||||
CompoundTag compoundTag = occupant.entityData().copyTag();
|
||||
Entity entity = EntityType.loadEntityRecursive(compoundTag, level, (entityx) -> entityx);
|
||||
if (entity instanceof PokemonEntity pokemonEntity) {
|
||||
var state = level.getBlockState(pos);
|
||||
var newPos = Vec3.ZERO;
|
||||
var newYaw = 0f;
|
||||
var brain = pokemonEntity.getBrain();
|
||||
if (state.is(BlockTags.BEEHIVES)) {
|
||||
// position in front of the entrance, face away from the block
|
||||
var facing = state.getValue(HorizontalDirectionalBlock.FACING);
|
||||
newPos = pos.relative(facing).getCenter();
|
||||
newYaw = facing.toYRot();
|
||||
brain.setMemory(CobblemonMemories.INSTANCE.getHIVE_LOCATION(), pos); // This needs to be set in the case that the hive was picked up and moved.
|
||||
} else {
|
||||
// Block has likely been destroyed
|
||||
var center = pos.getCenter();
|
||||
newPos = new Vec3(
|
||||
center.x + level.random.nextFloat() * 0.6 - 0.3,
|
||||
center.y + level.random.nextFloat() * 0.6 - 0.3,
|
||||
center.z + level.random.nextFloat() * 0.6 - 0.3
|
||||
);
|
||||
newYaw = level.random.nextFloat() * 360F;
|
||||
brain.eraseMemory(CobblemonMemories.INSTANCE.getHIVE_LOCATION());
|
||||
}
|
||||
entity.yRotO = newYaw;
|
||||
entity.setPos(newPos);
|
||||
// Do honey logic
|
||||
var hasNectar = brain.getMemory(CobblemonMemories.INSTANCE.getHAS_NECTAR()).orElse(false);
|
||||
if (hasNectar) {
|
||||
// Remove nectar and reset got to hive cooldown
|
||||
brain.eraseMemory(CobblemonMemories.INSTANCE.getHAS_NECTAR());
|
||||
brain.setMemoryWithExpiry(CobblemonMemories.INSTANCE.getHIVE_COOLDOWN(), true, PathToBeeHiveTaskConfig.STAY_OUT_OF_HIVE_COOLDOWN);
|
||||
// Increment honey level of the hive
|
||||
if (state.is(BlockTags.BEEHIVES, (blockStateBase) -> blockStateBase.hasProperty(BeehiveBlock.HONEY_LEVEL))) {
|
||||
int i = state.getValue(BeehiveBlock.HONEY_LEVEL);
|
||||
if (i < 5) {
|
||||
int j = level.random.nextInt(100) == 0 ? 2 : 1;
|
||||
if (i + j > 5) {
|
||||
--j;
|
||||
}
|
||||
level.setBlockAndUpdate(pos, state.setValue(BeehiveBlock.HONEY_LEVEL, i + j));
|
||||
}
|
||||
}
|
||||
}
|
||||
cir.setReturnValue(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "of", at = @At("HEAD"), cancellable = true)
|
||||
private static void cobblemon$of(Entity entity, CallbackInfoReturnable<BeehiveBlockEntity.Occupant> cir) {
|
||||
if (entity instanceof PokemonEntity pokemonEntity) {
|
||||
CompoundTag compoundTag = new CompoundTag();
|
||||
entity.save(compoundTag);
|
||||
Boolean hasNectar = pokemonEntity.getBrain().getMemory(CobblemonMemories.INSTANCE.getHAS_NECTAR()).orElse(false);
|
||||
cir.setReturnValue(new BeehiveBlockEntity.Occupant(CustomData.of(compoundTag), 0, hasNectar ? 2400 : 600));
|
||||
cir.cancel();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.mixin.accessor.BeeDataAccessor;
|
||||
import com.cobblemon.mod.common.mixin.accessor.BeehiveBlockEntityAccessor;
|
||||
import com.cobblemon.mod.common.mixin.accessor.BlockEntityAccessor;
|
||||
import com.google.common.collect.Lists;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(BeehiveBlockEntity.class)
|
||||
public abstract class BeehiveBlockEntityMixin {
|
||||
|
||||
|
||||
// Accessor for the private 'stored' field in BeehiveBlockEntity
|
||||
@Accessor("stored")
|
||||
public abstract List<BeeDataAccessor> getStored();
|
||||
|
||||
@Inject(method = "emptyAllLivingFromHive", at = @At("HEAD"))
|
||||
private void cobblemon$emptyAllLivingFromHive(@Nullable Player player, BlockState state, BeehiveBlockEntity.BeeReleaseStatus releaseStatus, CallbackInfo ci) {
|
||||
if (player != null) {
|
||||
final BeehiveBlockEntity blockEntity = (BeehiveBlockEntity) (Object) this;
|
||||
// if the block is sedated or the player is too far away, no aggro should be applied
|
||||
if (blockEntity.isSedated() || player.position().distanceToSqr(blockEntity.getBlockPos().getCenter()) > 16.0)
|
||||
return;
|
||||
// from this point need to access private members of the block entity
|
||||
final BeehiveBlockEntityAccessor blockEntityAccessor = (BeehiveBlockEntityAccessor) this;
|
||||
List<Object> storedList = blockEntityAccessor.getStored();
|
||||
|
||||
List<Entity> list = Lists.newArrayList();
|
||||
storedList.removeIf((beeData) -> {
|
||||
BeehiveBlockEntity.Occupant occupant = ((BeeDataAccessor) beeData).invokeToOccupant();
|
||||
// Checking the for the tag allows us to make sure it's one of our pokemon before trying to rehydrate it into an entity
|
||||
boolean isPokemon = false;
|
||||
if (occupant.entityData().contains("id")) {
|
||||
isPokemon = "cobblemon:pokemon".equals(occupant.entityData().getUnsafe().getString("id"));
|
||||
}
|
||||
if (isPokemon) {
|
||||
return BeehiveBlockEntityAccessor.releaseOccupant(
|
||||
((BlockEntityAccessor) blockEntityAccessor).getLevel(),
|
||||
((BlockEntityAccessor) blockEntityAccessor).getWorldPosition(),
|
||||
state,
|
||||
occupant,
|
||||
list,
|
||||
releaseStatus,
|
||||
blockEntityAccessor.savedFlowerPos());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
);
|
||||
for (Entity entity : list) {
|
||||
if (entity instanceof PokemonEntity) {
|
||||
((PokemonEntity) entity).getBrain().setMemory(MemoryModuleType.ATTACK_TARGET, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Redirect(
|
||||
method = "releaseOccupant",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/level/Level;addFreshEntity(Lnet/minecraft/world/entity/Entity;)Z"
|
||||
)
|
||||
)
|
||||
private static boolean cobblemon$captureReleasedEntity(
|
||||
Level level, Entity entity,
|
||||
Level lvl, BlockPos pos, BlockState state,
|
||||
BeehiveBlockEntity.Occupant occupant, @Nullable List<Entity> bees,
|
||||
BeehiveBlockEntity.BeeReleaseStatus releaseStatus, @Nullable BlockPos flowerPos) {
|
||||
|
||||
if (bees != null && !bees.contains(entity)) {
|
||||
// Avoid duplicates if vanilla also adds bees to the list on your version
|
||||
bees.add(entity);
|
||||
}
|
||||
return level.addFreshEntity(entity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.mixin;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.util.ByIdMap;
|
||||
import net.minecraft.util.StringRepresentable;
|
||||
import net.minecraft.world.item.component.FireworkExplosion;
|
||||
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.gen.Invoker;
|
||||
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.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.IntFunction;
|
||||
|
||||
@Mixin(FireworkExplosion.Shape.class)
|
||||
public abstract class FireworkExplosionShapeMixin {
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
@Mutable
|
||||
private static FireworkExplosion.Shape[] $VALUES;
|
||||
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
@Mutable
|
||||
private static IntFunction<FireworkExplosion.Shape> BY_ID;
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
@Mutable
|
||||
public static StreamCodec<ByteBuf, FireworkExplosion.Shape> STREAM_CODEC;
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
@Mutable
|
||||
public static Codec<FireworkExplosion.Shape> CODEC;
|
||||
|
||||
@Invoker("<init>")
|
||||
private static FireworkExplosion.Shape cobblemon$createFireworkExplosionShape(String enumName, int internalId, int id, String name) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "<clinit>",
|
||||
at = @At("TAIL")
|
||||
)
|
||||
private static void cobblemon$addFireworkExplosionShape(CallbackInfo ci) {
|
||||
ArrayList<FireworkExplosion.Shape> types = new ArrayList<>(List.of($VALUES));
|
||||
|
||||
types.add(cobblemon$createFireworkExplosionShape("POKEBALL", $VALUES.length, 5, "pokeball"));
|
||||
|
||||
$VALUES = types.toArray(FireworkExplosion.Shape[]::new);
|
||||
|
||||
BY_ID = ByIdMap.continuous(FireworkExplosion.Shape::getId, FireworkExplosion.Shape.values(), ByIdMap.OutOfBoundsStrategy.ZERO);
|
||||
STREAM_CODEC = ByteBufCodecs.idMapper(BY_ID, FireworkExplosion.Shape::getId);
|
||||
CODEC = StringRepresentable.fromValues(FireworkExplosion.Shape::values);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import net.minecraft.client.particle.FireworkParticles;
|
||||
import net.minecraft.world.item.component.FireworkExplosion;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
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 org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
@Mixin(FireworkParticles.Starter.class)
|
||||
public abstract class FireworkParticlesMixin {
|
||||
|
||||
@Shadow
|
||||
protected abstract void createParticleShape(double speed, double[][] coords, IntList colors, IntList fadeColors, boolean trail, boolean twinkle, boolean isCreeper);
|
||||
|
||||
@Inject(
|
||||
method = "tick()V",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/client/particle/Particle;setColor(FFF)V",
|
||||
shift = At.Shift.BEFORE,
|
||||
by = 2
|
||||
)
|
||||
)
|
||||
private void cobblemon$createPokeballParticleShape(
|
||||
CallbackInfo ci,
|
||||
@Local FireworkExplosion fireworkExplosion2,
|
||||
@Local(ordinal = 0) int bl3,
|
||||
@Local(ordinal = 0) int bl4,
|
||||
@Local(ordinal = 0) IntList intList,
|
||||
@Local(ordinal = 0) IntList intList2
|
||||
) {
|
||||
if (fireworkExplosion2.shape().getSerializedName().equals("pokeball")) {
|
||||
final double[][] POKEBALL_PARTICLE_COORDS = new double[][]{
|
||||
{0, 0.5},
|
||||
{0.05, 0.497494},
|
||||
{0.1, 0.489898},
|
||||
{0.15, 0.47697},
|
||||
{0.2, 0.458258},
|
||||
{0.25, 0.433013},
|
||||
{0.3, 0.4},
|
||||
{0.35, 0.357071},
|
||||
{0.4, 0.3},
|
||||
{0.45, 0.217945},
|
||||
{0.4975, 0.049937},
|
||||
{0.086606, 0.049994},
|
||||
{0.05, 0.086603},
|
||||
{0, 0.1},
|
||||
{0.05, 0.049994},
|
||||
|
||||
{0.05, -0.049994},
|
||||
{0, -0.1},
|
||||
{0.05, -0.086603},
|
||||
{0.086606, -0.049994},
|
||||
{0.0, -0.049937},
|
||||
{0.4975, -0.049937},
|
||||
{0.45, -0.217945},
|
||||
{0.4, -0.3},
|
||||
{0.35, -0.357071},
|
||||
{0.3, -0.4},
|
||||
{0.25, -0.433013},
|
||||
{0.2, -0.458258},
|
||||
{0.15, -0.47697},
|
||||
{0.1, -0.489898},
|
||||
{0.05, -0.497494},
|
||||
{0, -0.5},
|
||||
};
|
||||
|
||||
boolean b3 = bl3 == 1;
|
||||
boolean b4 = bl4 == 1;
|
||||
|
||||
this.createParticleShape(0.5, POKEBALL_PARTICLE_COORDS, intList, intList2, b3, b4, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.CobblemonItems;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.component.FireworkExplosion;
|
||||
import net.minecraft.world.item.crafting.FireworkStarRecipe;
|
||||
import net.minecraft.world.item.crafting.Ingredient;
|
||||
import net.minecraft.world.level.ItemLike;
|
||||
import org.spongepowered.asm.mixin.*;
|
||||
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.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(FireworkStarRecipe.class)
|
||||
public class FireworkStarRecipeMixin {
|
||||
|
||||
@Mutable
|
||||
@Shadow
|
||||
@Final
|
||||
private static Map<Item, FireworkExplosion.Shape> SHAPE_BY_ITEM;
|
||||
|
||||
@Mutable
|
||||
@Shadow
|
||||
@Final
|
||||
private static Ingredient SHAPE_INGREDIENT;
|
||||
|
||||
@Inject(method = "<clinit>", at = @At("TAIL"))
|
||||
private static void cobblemon$addCustomShape(CallbackInfo ci) {
|
||||
ItemStack[] existing = SHAPE_INGREDIENT.getItems();
|
||||
ItemStack[] extended = new ItemStack[existing.length + 1];
|
||||
System.arraycopy(existing, 0, extended, 0, existing.length);
|
||||
|
||||
extended[existing.length] = new ItemStack(CobblemonItems.POKE_BALL);
|
||||
|
||||
SHAPE_INGREDIENT = Ingredient.of(Arrays.stream(extended)
|
||||
.map(ItemStack::getItem)
|
||||
.toArray(ItemLike[]::new));
|
||||
SHAPE_BY_ITEM.put(CobblemonItems.POKE_BALL, FireworkExplosion.Shape.byId(5));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
|
||||
import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
@Mixin(targets = "net.minecraft.world.level.block.entity.BeehiveBlockEntity$BeeData")
|
||||
public interface BeeDataAccessor {
|
||||
@Invoker("toOccupant")
|
||||
BeehiveBlockEntity.Occupant invokeToOccupant();
|
||||
}
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(BeehiveBlockEntity.class)
|
||||
public interface BeehiveBlockEntityAccessor {
|
||||
@Accessor("stored")
|
||||
List<Object> getStored();
|
||||
@Accessor("savedFlowerPos")
|
||||
BlockPos savedFlowerPos();
|
||||
|
||||
|
||||
/**
|
||||
* Access the private static method:
|
||||
* private static void releaseOccupant(Level level, BlockPos pos, BeeData beeData, ...)
|
||||
*/
|
||||
@Invoker("releaseOccupant")
|
||||
static boolean releaseOccupant(Level level, BlockPos pos, BlockState state, BeehiveBlockEntity.Occupant occupant, @Nullable List<Entity> storedInHives, BeehiveBlockEntity.BeeReleaseStatus releaseStatus, @Nullable BlockPos storedFlowerPos) {
|
||||
throw new AssertionError(); // Mixin will overwrite
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(BlockEntity.class)
|
||||
public interface BlockEntityAccessor {
|
||||
@Accessor("level") Level getLevel();
|
||||
@Accessor("worldPosition") BlockPos getWorldPosition();
|
||||
}
|
||||
+3
-4
@@ -10,8 +10,7 @@ package com.cobblemon.mod.common.mixin.client.snapshots;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBuildDetails;
|
||||
import com.cobblemon.mod.common.client.gui.snapshots.SnapshotWarningScreen;
|
||||
import com.cobblemon.mod.common.client.snapshots.SnapshotAcknowledgementData;
|
||||
import com.cobblemon.mod.common.client.snapshots.SnapshotAcknowledgementReader;
|
||||
import com.cobblemon.mod.common.client.persisted.ClientPersistedData;
|
||||
import kotlin.Unit;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@@ -42,7 +41,7 @@ public final class SnapshotWarningMixin {
|
||||
return Unit.INSTANCE;
|
||||
}
|
||||
|
||||
SnapshotAcknowledgementReader.INSTANCE.write(new SnapshotAcknowledgementData(CobblemonBuildDetails.VERSION, dsa));
|
||||
ClientPersistedData.INSTANCE.writeSnapshotsData(new ClientPersistedData.SnapshotAcknowledgementData(CobblemonBuildDetails.VERSION, dsa));
|
||||
|
||||
runnable.run();
|
||||
return Unit.INSTANCE;
|
||||
@@ -54,7 +53,7 @@ public final class SnapshotWarningMixin {
|
||||
@Unique
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
private boolean cobblemon$isAcknowledged() {
|
||||
SnapshotAcknowledgementData data = SnapshotAcknowledgementReader.INSTANCE.read();
|
||||
ClientPersistedData.SnapshotAcknowledgementData data = ClientPersistedData.INSTANCE.readSnapshotsData();
|
||||
if (data == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -213,7 +213,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
@JvmField
|
||||
val SACCHARINE_SIGN = this.create("saccharine_sign", CobblemonSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_SIGN), SACCHARINE_WOOD_TYPE))
|
||||
@JvmField
|
||||
val SACCHARINE_WALL_SIGN = this.create("saccharine_wall_sign", CobblemonWallSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_WALL_SIGN), SACCHARINE_WOOD_TYPE))
|
||||
val SACCHARINE_WALL_SIGN = this.create("saccharine_wall_sign", CobblemonWallSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_SIGN), SACCHARINE_WOOD_TYPE))
|
||||
@JvmField
|
||||
val SACCHARINE_HANGING_SIGN = this.create("saccharine_hanging_sign", CobblemonHangingSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_WALL_HANGING_SIGN), SACCHARINE_WOOD_TYPE))
|
||||
@JvmField
|
||||
|
||||
@@ -696,7 +696,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val SUPERB_REMEDY = compostableItem("superb_remedy", RemedyItem(RemedyItem.SUPERB), 0.85f)
|
||||
@JvmField
|
||||
val MOOMOO_MILK = create("moomoo_milk", CobblemonItem(Item.Properties().craftRemainder(Items.GLASS_BOTTLE).stacksTo((16))))
|
||||
val MOOMOO_MILK = create("moomoo_milk", MoomooMilk(Item.Properties().craftRemainder(Items.GLASS_BOTTLE).stacksTo((16))))
|
||||
|
||||
@JvmField
|
||||
val POTION = create("potion", PotionItem(PotionType.POTION))
|
||||
|
||||
@@ -39,6 +39,7 @@ object CobblemonMechanics : DataRegistry {
|
||||
var potions = PotionsMechanic()
|
||||
|
||||
override fun sync(player: ServerPlayer) {}
|
||||
|
||||
override fun reload(manager: ResourceManager) {
|
||||
remedies = loadMechanic(manager, "remedies", RemediesMechanic::class.java)
|
||||
berries = loadMechanic(manager, "berries", BerriesMechanic::class.java)
|
||||
|
||||
@@ -15,12 +15,12 @@ import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.ListCodec
|
||||
import com.mojang.serialization.codecs.PrimitiveCodec
|
||||
import net.minecraft.core.UUIDUtil
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import java.util.Optional
|
||||
import java.util.UUID
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.GlobalPos
|
||||
import net.minecraft.core.UUIDUtil
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import java.util.*
|
||||
|
||||
object CobblemonMemories {
|
||||
val memories = mutableMapOf<String, MemoryModuleType<*>>()
|
||||
@@ -48,10 +48,13 @@ object CobblemonMemories {
|
||||
val TIME_TRYING_TO_REACH_BERRY_BUSH = register<Int>("time_trying_to_reach_berry_bush")
|
||||
val IS_CONSUMING_ITEM = register<Boolean>("is_consuming_item")
|
||||
val RECENTLY_ATE_GRASS = register<Boolean>("recently_ate_grass")
|
||||
val HIVE_LOCATION = register<BlockPos>("hive_location")
|
||||
val HIVE_LOCATION = register<BlockPos>("hive_location", BlockPos.CODEC)
|
||||
val HIVE_BLACKLIST = register<List<BlockPos>>("hive_blacklist")
|
||||
val HIVE_COOLDOWN = register<Boolean>("hive_cooldown")
|
||||
val NEARBY_FLOWERS = register<List<BlockPos>>("nearby_flower")
|
||||
val POLLINATED = register<Boolean>("pollinated", PrimitiveCodec.BOOL)
|
||||
val NEARBY_FLOWER = register<BlockPos>("nearby_flower", BlockPos.CODEC)
|
||||
val PATH_TO_NEARBY_FLOWER_COOLDOWN = register<Boolean>("path_to_nearby_flower_cooldown")
|
||||
val HAS_NECTAR = register<Boolean>("has_nectar", PrimitiveCodec.BOOL)
|
||||
val NEARBY_SACC_LEAVES = register<BlockPos>("nearby_sacc_leaves", BlockPos.CODEC)
|
||||
/** who am i following rn? */
|
||||
val HERD_LEADER = register<String>("herd_leader", PrimitiveCodec.STRING)
|
||||
/** how many are following me rn? */
|
||||
|
||||
@@ -20,6 +20,7 @@ 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.cooking.ToggleCookingPotLidHandler
|
||||
import com.cobblemon.mod.common.client.net.data.DataRegistrySyncPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.data.RideSettingsSyncHandler
|
||||
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.effect.PokeSnackBlockParticlesHandler
|
||||
@@ -311,6 +312,7 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(MarksPotentialUpdatePacket.ID, MarksPotentialUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(MarkingsUpdatePacket.ID, MarkingsUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(RideBoostsUpdatePacket.ID, RideBoostsUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(RideStaminaUpdatePacket.ID, RideStaminaUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
|
||||
// Evolution start
|
||||
list.add(PacketRegisterInfo(AddEvolutionPacket.ID, AddEvolutionPacket::decode, PokemonUpdatePacketHandler()))
|
||||
@@ -405,6 +407,7 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(CosmeticItemAssignmentSyncPacket.ID, CosmeticItemAssignmentSyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(BehaviourSyncPacket.ID, BehaviourSyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(MarkRegistrySyncPacket.ID, MarkRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(RideSettingsSyncPacket.ID, RideSettingsSyncPacket::decode, RideSettingsSyncHandler))
|
||||
|
||||
// Effects
|
||||
list.add(PacketRegisterInfo(SpawnSnowstormParticlePacket.ID, SpawnSnowstormParticlePacket::decode, SpawnSnowstormParticleHandler))
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.api.data.DataRegistry
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.air.BirdSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.air.GliderSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.air.HelicopterSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.air.HoverSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.air.JetSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.air.RocketSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.land.HorseSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.land.MinekartSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.land.VehicleSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.BoatSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.BurstSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.DolphinSettings
|
||||
import com.cobblemon.mod.common.net.messages.client.data.RideSettingsSyncPacket
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.FloatNumberRangeAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.GsonBuilder
|
||||
import net.minecraft.advancements.critereon.MinMaxBounds
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.server.packs.PackType
|
||||
import net.minecraft.server.packs.resources.ResourceManager
|
||||
|
||||
object CobblemonRideSettings : DataRegistry {
|
||||
override val id: ResourceLocation = cobblemonResource("ride_settings")
|
||||
override val type = PackType.SERVER_DATA
|
||||
override val observable = SimpleObservable<CobblemonRideSettings>()
|
||||
val gson = GsonBuilder()
|
||||
.setPrettyPrinting()
|
||||
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
|
||||
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
|
||||
.registerTypeAdapter(MinMaxBounds.Doubles::class.java, FloatNumberRangeAdapter)
|
||||
.create()
|
||||
|
||||
var bird = BirdSettings()
|
||||
var glider = GliderSettings()
|
||||
var helicopter = HelicopterSettings()
|
||||
var hover = HoverSettings()
|
||||
var jet = JetSettings()
|
||||
var rocket = RocketSettings()
|
||||
|
||||
var horse = HorseSettings()
|
||||
var minekart = MinekartSettings()
|
||||
var vehicle = VehicleSettings()
|
||||
|
||||
var boat = BoatSettings()
|
||||
var burst = BurstSettings()
|
||||
var dolphin = DolphinSettings()
|
||||
|
||||
override fun sync(player: ServerPlayer) {
|
||||
player.sendPacket(
|
||||
RideSettingsSyncPacket(
|
||||
bird = bird,
|
||||
glider = glider,
|
||||
helicopter = helicopter,
|
||||
hover = hover,
|
||||
jet = jet,
|
||||
rocket = rocket,
|
||||
horse = horse,
|
||||
minekart = minekart,
|
||||
vehicle = vehicle,
|
||||
boat = boat,
|
||||
burst = burst,
|
||||
dolphin = dolphin
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun reload(manager: ResourceManager) {
|
||||
bird = loadStyle(manager, "bird", BirdSettings::class.java)
|
||||
glider = loadStyle(manager, "glider", GliderSettings::class.java)
|
||||
helicopter = loadStyle(manager, "helicopter", HelicopterSettings::class.java)
|
||||
hover = loadStyle(manager, "hover", HoverSettings::class.java)
|
||||
jet = loadStyle(manager, "jet", JetSettings::class.java)
|
||||
rocket = loadStyle(manager, "rocket", RocketSettings::class.java)
|
||||
horse = loadStyle(manager, "horse", HorseSettings::class.java)
|
||||
minekart = loadStyle(manager, "minekart", MinekartSettings::class.java)
|
||||
vehicle = loadStyle(manager, "vehicle", VehicleSettings::class.java)
|
||||
boat = loadStyle(manager, "boat", BoatSettings::class.java)
|
||||
burst = loadStyle(manager, "burst", BurstSettings::class.java)
|
||||
dolphin = loadStyle(manager, "dolphin", DolphinSettings::class.java)
|
||||
}
|
||||
|
||||
private fun <T : RidingBehaviourSettings> loadStyle(manager: ResourceManager, name: String, clazz: Class<T>): T {
|
||||
manager.getResourceOrThrow(cobblemonResource("ride_settings/$name.json")).open().use {
|
||||
return gson.fromJson(it.reader(), clazz)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,8 @@ object CobblemonSensors {
|
||||
|
||||
val POKEMON_NEARBY_WANTED_ITEM = register("pokemon_nearby_wanted_item", ::PokemonItemSensor)
|
||||
|
||||
val NEARBY_SACC_LEAVES = register("nearby_sacc_leaves", ::SacLeavesSensor)
|
||||
|
||||
fun <E : Entity, U : Sensor<E>> register(id: String, supplier: Supplier<U>): SensorType<U> {
|
||||
val sensor = SensorType(supplier)
|
||||
sensors[id] = sensor
|
||||
|
||||
+5
-4
@@ -22,18 +22,19 @@ class ReelInPokemonContext(val species : ResourceLocation, val baitId: ResourceL
|
||||
class ReelInPokemonCriterionCondition(
|
||||
playerCtx: Optional<ContextAwarePredicate>,
|
||||
val species: String,
|
||||
val baitId: String
|
||||
val baitId: String // also allows "cobblemon:empty_bait" to indicate that no bait is allowed for this criterion to match
|
||||
) : SimpleCriterionCondition<ReelInPokemonContext>(playerCtx) {
|
||||
|
||||
companion object {
|
||||
val CODEC: Codec<ReelInPokemonCriterionCondition> = RecordCodecBuilder.create { it.group(
|
||||
EntityPredicate.ADVANCEMENT_CODEC.optionalFieldOf("player").forGetter { it.playerCtx },
|
||||
Codec.STRING.optionalFieldOf("species", "any").forGetter { it.species },
|
||||
Codec.STRING.optionalFieldOf("baitId", "empty_bait").forGetter { it.baitId }
|
||||
).apply(it, { playerCtx, pokemonId, baitId -> ReelInPokemonCriterionCondition(playerCtx, pokemonId, baitId.ifEmpty { "empty_bait" }) }) }
|
||||
Codec.STRING.optionalFieldOf("baitId", "any").forGetter { it.baitId }
|
||||
).apply(it, { playerCtx, pokemonId, baitId -> ReelInPokemonCriterionCondition(playerCtx, pokemonId, baitId) }) }
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayer, context: ReelInPokemonContext): Boolean {
|
||||
return (context.species == this.species.asIdentifierDefaultingNamespace() || this.species == "any") && (context.baitId == this.baitId.asIdentifierDefaultingNamespace() || this.baitId == "empty_bait")
|
||||
return (context.species == this.species.asIdentifierDefaultingNamespace() || this.species == "any")
|
||||
&& (context.baitId == this.baitId.asIdentifierDefaultingNamespace() || this.baitId == "any")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai
|
||||
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.Behavior
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.MemoryStatus
|
||||
import net.minecraft.world.entity.schedule.Activity
|
||||
|
||||
/**
|
||||
* A [Behavior] subclass that represents tasks that check that the entity is still in one
|
||||
* of the activities that this task is part of. If the entity is no longer doing any of those
|
||||
* activities, the task will be interrupted and you can handle any cleanup in [onInterrupted].
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 17th, 2025
|
||||
*/
|
||||
abstract class ActivityAwareBehavior<E : LivingEntity> : Behavior<E> {
|
||||
constructor(entryCondition: Map<MemoryModuleType<*>, MemoryStatus>) : super(entryCondition)
|
||||
constructor(entryCondition: Map<MemoryModuleType<*>, MemoryStatus>, duration: Int) : super(entryCondition, duration)
|
||||
constructor(entryCondition: Map<MemoryModuleType<*>, MemoryStatus>, minDuration: Int, maxDuration: Int) : super(entryCondition, minDuration, maxDuration)
|
||||
|
||||
val activities: MutableSet<Activity> = mutableSetOf()
|
||||
|
||||
fun isStillDoingActivity(entity: E): Boolean {
|
||||
return activities.any(entity.brain::isActive)
|
||||
}
|
||||
|
||||
override fun canStillUse(level: ServerLevel, entity: E, gameTime: Long) = isStillDoingActivity(entity)
|
||||
|
||||
open fun onInterrupted(level: ServerLevel, entity: E, gameTime: Long) {
|
||||
// No-op
|
||||
}
|
||||
|
||||
override fun stop(level: ServerLevel, entity: E, gameTime: Long) {
|
||||
super.stop(level, entity, gameTime)
|
||||
if (!isStillDoingActivity(entity)) {
|
||||
onInterrupted(level, entity, gameTime)
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-1
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.api.ai
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.mojang.datafixers.util.Pair
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.Mob
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.schedule.Activity
|
||||
|
||||
@@ -23,6 +22,13 @@ class ActivityConfigurationContext(val activity: Activity) {
|
||||
}
|
||||
|
||||
fun apply(entity: LivingEntity) {
|
||||
tasks.forEach {
|
||||
val activityAwareBehavior = it.second as? ActivityAwareBehavior<*>
|
||||
?: (it.second as? WrapperLivingEntityTask<*>)?.task as? ActivityAwareBehavior
|
||||
?: return@forEach
|
||||
activityAwareBehavior.activities += activity
|
||||
}
|
||||
|
||||
entity.brain.addActivity(activity, ImmutableList.copyOf(tasks))
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -23,7 +23,7 @@ import net.minecraft.world.entity.schedule.Activity
|
||||
|
||||
class ActivityChangeTaskConfig : SingleTaskConfig {
|
||||
val activity: Activity = Activity.IDLE
|
||||
val condition: ExpressionLike = "false".asExpressionLike()
|
||||
val condition: ExpressionLike = "true".asExpressionLike()
|
||||
|
||||
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext): List<MoLangConfigVariable> = emptyList()
|
||||
|
||||
|
||||
+2
-1
@@ -17,6 +17,7 @@ import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.getMemorySafely
|
||||
import com.cobblemon.mod.common.util.resolveString
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
@@ -62,7 +63,7 @@ class MemoryAspectTaskConfig : SingleTaskConfig {
|
||||
override fun canStillUse(level: ServerLevel, entity: LivingEntity, gameTime: Long) = true
|
||||
|
||||
override fun tick(level: ServerLevel, owner: LivingEntity, gameTime: Long) {
|
||||
val hasMemory = !owner.brain.hasMemoryValue(memory)
|
||||
val hasMemory = owner.brain.hasMemoryValue(memory)
|
||||
if (owner is PokemonEntity) {
|
||||
if (!hasMemory && aspect in owner.pokemon.forcedAspects) {
|
||||
owner.pokemon.forcedAspects -= aspect
|
||||
|
||||
+118
-2
@@ -8,16 +8,31 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.CobblemonSensors
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PathToBeeHiveTask
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PlaceHoneyInHiveTask
|
||||
import com.cobblemon.mod.common.util.distanceTo
|
||||
import com.cobblemon.mod.common.util.getMemorySafely
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.Behavior
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.MemoryStatus
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class PathToBeeHiveTaskConfig : SingleTaskConfig {
|
||||
companion object {
|
||||
const val HONEY = "honey"
|
||||
const val STAY_OUT_OF_HIVE_COOLDOWN = 400
|
||||
|
||||
}
|
||||
|
||||
val condition = booleanVariable(HONEY, "can_add_honey", true).asExpressible()
|
||||
@@ -36,6 +51,107 @@ class PathToBeeHiveTaskConfig : SingleTaskConfig {
|
||||
if (!checkCondition(behaviourConfigurationContext.runtime, condition)) {
|
||||
return null
|
||||
}
|
||||
return PathToBeeHiveTask.create()
|
||||
behaviourConfigurationContext.addSensors(CobblemonSensors.NEARBY_BEE_HIVE)
|
||||
return object : Behavior<LivingEntity>(
|
||||
mapOf(
|
||||
MemoryModuleType.LOOK_TARGET to MemoryStatus.REGISTERED,
|
||||
MemoryModuleType.WALK_TARGET to MemoryStatus.VALUE_ABSENT,
|
||||
CobblemonMemories.HAS_NECTAR to MemoryStatus.REGISTERED,
|
||||
CobblemonMemories.HIVE_LOCATION to MemoryStatus.VALUE_PRESENT,
|
||||
CobblemonMemories.HIVE_COOLDOWN to MemoryStatus.VALUE_ABSENT,
|
||||
CobblemonMemories.HIVE_BLACKLIST to MemoryStatus.REGISTERED,
|
||||
),
|
||||
400,
|
||||
400
|
||||
) {
|
||||
|
||||
val maxTicks = 400
|
||||
var traveledTicks = 0
|
||||
|
||||
override fun checkExtraStartConditions(level: ServerLevel, owner: LivingEntity): Boolean {
|
||||
return (owner is PathfinderMob && owner.isAlive && (owner is PokemonEntity && PlaceHoneyInHiveTask.wantsToEnterHive(owner))) && owner.brain.checkMemory(
|
||||
MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT)
|
||||
}
|
||||
|
||||
override fun canStillUse(level: ServerLevel, entity: LivingEntity, gameTime: Long): Boolean {
|
||||
if (maxTicks >= traveledTicks) return false
|
||||
val pos = entity.brain.getMemory(CobblemonMemories.HIVE_LOCATION)
|
||||
return !pos.isEmpty && entity.distanceTo(pos.get()) > 1.0
|
||||
}
|
||||
|
||||
override fun start(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
|
||||
super.start(level, entity, gameTime)
|
||||
val hiveLocation = entity.brain.getMemorySafely(CobblemonMemories.HIVE_LOCATION).orElse(null)
|
||||
val world = entity.level()
|
||||
val sidesByClosest = listOf(
|
||||
hiveLocation.north(),
|
||||
hiveLocation.south(),
|
||||
hiveLocation.east(),
|
||||
hiveLocation.west()
|
||||
).sortedBy { it.distSqr(entity.blockPosition()) }
|
||||
|
||||
var openSide = BlockPos.ZERO
|
||||
for (side in sidesByClosest) {
|
||||
if (world.getBlockState(side).isAir) {
|
||||
openSide = side
|
||||
break
|
||||
}
|
||||
}
|
||||
if (openSide == BlockPos.ZERO) {
|
||||
if (world.getBlockState(hiveLocation.above()).isAir) {
|
||||
// If the above position is also air, we can use it
|
||||
openSide = hiveLocation.above() // Fallback to above if no open sides found
|
||||
} else if (world.getBlockState(hiveLocation.below()).isAir) {
|
||||
// If the below position is also air, we can use it
|
||||
openSide = hiveLocation.below() // Fallback to below if no open sides found
|
||||
} else {
|
||||
// If no open sides or above/below positions are found, we cannot proceed
|
||||
return
|
||||
}
|
||||
}
|
||||
val targetVec = Vec3.atCenterOf(openSide)
|
||||
|
||||
// Set path target toward hive
|
||||
if (pathfindDirectlyTowards(openSide, entity)) {
|
||||
entity.brain.setMemory(MemoryModuleType.WALK_TARGET,WalkTarget(targetVec, 0.35F, 0))
|
||||
entity.brain.setMemory(MemoryModuleType.LOOK_TARGET,BlockPosTracker(targetVec.add(0.0, entity.eyeHeight.toDouble(), 0.0)))
|
||||
traveledTicks = 0
|
||||
} else {
|
||||
dropAndBlackListHive(entity)
|
||||
}
|
||||
}
|
||||
|
||||
override fun tick(level: ServerLevel, owner: LivingEntity, gameTime: Long) {
|
||||
traveledTicks++
|
||||
}
|
||||
|
||||
override fun stop(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
|
||||
if (maxTicks < traveledTicks) {
|
||||
dropAndBlackListHive(entity)
|
||||
entity.brain.setMemoryWithExpiry(CobblemonMemories.HIVE_COOLDOWN, true, 100)
|
||||
}
|
||||
}
|
||||
|
||||
fun dropAndBlackListHive(entity: LivingEntity) {
|
||||
val hivePos = entity.brain.getMemorySafely(CobblemonMemories.HIVE_LOCATION).orElse(null)
|
||||
if (hivePos == null) return
|
||||
val blackList = entity.brain.getMemorySafely(CobblemonMemories.HIVE_BLACKLIST).orElse(emptyList()).toMutableList()
|
||||
|
||||
blackList.add(hivePos)
|
||||
if (blackList.count() > 3) {
|
||||
blackList.removeFirst()
|
||||
}
|
||||
entity.brain.eraseMemory(CobblemonMemories.HIVE_LOCATION)
|
||||
entity.brain.setMemory(CobblemonMemories.HIVE_BLACKLIST, blackList)
|
||||
|
||||
}
|
||||
|
||||
private fun pathfindDirectlyTowards(pos: BlockPos, entity: LivingEntity): Boolean {
|
||||
if (entity !is PathfinderMob) return false
|
||||
val nav = entity.navigation
|
||||
val path = nav. createPath(pos, 0)
|
||||
return path != null && path.canReach()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-4
@@ -8,7 +8,6 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.CobblemonSensors
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
@@ -41,12 +40,14 @@ class PathToFlowerTaskConfig : SingleTaskConfig {
|
||||
return null
|
||||
}
|
||||
behaviourConfigurationContext.addMemories(
|
||||
CobblemonMemories.NEARBY_FLOWERS,
|
||||
CobblemonMemories.NEARBY_FLOWER,
|
||||
CobblemonMemories.PATH_TO_NEARBY_FLOWER_COOLDOWN,
|
||||
CobblemonMemories.HIVE_COOLDOWN,
|
||||
CobblemonMemories.HIVE_LOCATION,
|
||||
CobblemonMemories.POLLINATED
|
||||
CobblemonMemories.HIVE_BLACKLIST,
|
||||
CobblemonMemories.HAS_NECTAR,
|
||||
)
|
||||
behaviourConfigurationContext.addSensors(CobblemonSensors.NEARBY_BEE_HIVE, CobblemonSensors.NEARBY_FLOWER)
|
||||
behaviourConfigurationContext.addSensors(CobblemonSensors.NEARBY_FLOWER)
|
||||
return PathToFlowerTask.create()
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.CobblemonSensors
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PathToSacLeafTask
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class PathToSaccLeavesTaskConfig : SingleTaskConfig {
|
||||
companion object {
|
||||
const val POLLINATE = "pollinate"
|
||||
}
|
||||
|
||||
val condition = booleanVariable(POLLINATE, "can_pollinate", true).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = listOf(
|
||||
condition
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
if (entity !is PokemonEntity) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (!checkCondition(behaviourConfigurationContext.runtime, condition)) {
|
||||
return null
|
||||
}
|
||||
behaviourConfigurationContext.addMemories(
|
||||
CobblemonMemories.NEARBY_SACC_LEAVES,
|
||||
CobblemonMemories.HAS_NECTAR
|
||||
)
|
||||
behaviourConfigurationContext.addSensors(CobblemonSensors.NEARBY_SACC_LEAVES, CobblemonSensors.NEARBY_FLOWER)
|
||||
return PathToSacLeafTask.create()
|
||||
}
|
||||
}
|
||||
+5
-2
@@ -8,8 +8,8 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PlaceHoneyInHiveTask
|
||||
@@ -37,6 +37,9 @@ class PlaceHoneyInHiveTaskConfig : SingleTaskConfig {
|
||||
if (!checkCondition(behaviourConfigurationContext.runtime, condition)) {
|
||||
return null
|
||||
}
|
||||
return PlaceHoneyInHiveTask.create()
|
||||
return WrapperLivingEntityTask(
|
||||
PlaceHoneyInHiveTask.create(),
|
||||
PokemonEntity::class.java
|
||||
)
|
||||
}
|
||||
}
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonActivities
|
||||
import com.cobblemon.mod.common.CobblemonBlocks
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.block.SaccharineLeafBlock
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.getMemorySafely
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.sounds.SoundEvents
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.Behavior
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.MemoryStatus
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class PlaceHoneyInSaccLeavesTaskConfig : SingleTaskConfig {
|
||||
companion object {
|
||||
const val POLLINATE = "pollinate"
|
||||
const val MIN_DURATION : Int = 300
|
||||
const val MAX_DURATION : Int = 400
|
||||
const val REQUIRED_SUCCESSFUL_POLLINATION_TICKS = 250
|
||||
}
|
||||
|
||||
val condition = booleanVariable(POLLINATE, "can_pollinate", true).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = listOf(
|
||||
condition
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
if (entity !is PokemonEntity) {
|
||||
return null
|
||||
}
|
||||
if (!checkCondition(behaviourConfigurationContext.runtime, condition)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return object : Behavior<LivingEntity>(
|
||||
mapOf(
|
||||
CobblemonMemories.NEARBY_SACC_LEAVES to MemoryStatus.VALUE_PRESENT,
|
||||
MemoryModuleType.WALK_TARGET to MemoryStatus.VALUE_ABSENT,
|
||||
CobblemonMemories.HAS_NECTAR to MemoryStatus.VALUE_PRESENT,
|
||||
),
|
||||
MIN_DURATION,
|
||||
MAX_DURATION
|
||||
) {
|
||||
var successfulPollinationTicks = 0
|
||||
var lastSoundPlayedTick = 0
|
||||
var hoverPos: Vec3? = null
|
||||
|
||||
override fun checkExtraStartConditions(level: ServerLevel, owner: LivingEntity): Boolean {
|
||||
if (level.isNight || level.isRaining || !(entity.brain.getMemorySafely(CobblemonMemories.HAS_NECTAR).orElse(false))) return false
|
||||
val optionalBlockPos = entity.brain.getMemorySafely(CobblemonMemories.NEARBY_SACC_LEAVES)
|
||||
if (!optionalBlockPos.isPresent || level.getBlockState(optionalBlockPos.get()).block != CobblemonBlocks.SACCHARINE_LEAVES) return false
|
||||
return Vec3.atCenterOf(optionalBlockPos.get()).distanceTo(entity.position()) <= 0.6
|
||||
}
|
||||
|
||||
override fun canStillUse(level: ServerLevel, entity: LivingEntity, gameTime: Long): Boolean {
|
||||
return checkExtraStartConditions(level, entity) && entity.brain.activeActivities.indexOf(
|
||||
CobblemonActivities.POKEMON_POLLINATION) != -1
|
||||
}
|
||||
|
||||
override fun start(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
|
||||
super.start(level, entity, gameTime)
|
||||
hoverPos = null
|
||||
}
|
||||
|
||||
override fun tick(level: ServerLevel, owner: LivingEntity, gameTime: Long) {
|
||||
++successfulPollinationTicks
|
||||
if (entity.random.nextFloat() < 0.05f && successfulPollinationTicks > this.lastSoundPlayedTick + 60) {
|
||||
this.lastSoundPlayedTick = successfulPollinationTicks
|
||||
entity.playSound(SoundEvents.BEEHIVE_DRIP, 1.0f, 1.0f)
|
||||
}
|
||||
val leavesPos = entity.brain.getMemorySafely(CobblemonMemories.NEARBY_SACC_LEAVES).orElse(null)
|
||||
|
||||
val bl = hoverPos == null || entity.position().distanceTo(hoverPos!!) <= 0.1
|
||||
val bl3 = entity.random.nextInt(40) == 0
|
||||
if (bl && bl3) {
|
||||
// mimics the wriggling over a flower the vanilla bees do
|
||||
if (hoverPos == null) {
|
||||
hoverPos = leavesPos.bottomCenter.add(0.0, 0.4, 0.0)
|
||||
}
|
||||
if (leavesPos != null) {
|
||||
hoverPos = leavesPos.bottomCenter.add(Vec3((entity.random.nextDouble() * 2.0 - 1.0) * (1.0/5.0), 0.3 + (entity.random.nextDouble() * 2.0 - 1.0) * (1.0/7.0), (entity.random.nextDouble() * 2.0 - 1.0) * (1.0/5.0)))
|
||||
entity.getMoveControl()
|
||||
.setWantedPosition(hoverPos!!.x(), hoverPos!!.y(), hoverPos!!.z(), 0.35)
|
||||
entity.lookControl.setLookAt(leavesPos.bottomCenter.add(0.0,0.5,0.0))
|
||||
}
|
||||
} else if (!bl) {
|
||||
entity.getMoveControl()
|
||||
.setWantedPosition(hoverPos!!.x(), hoverPos!!.y(), hoverPos!!.z(), 0.35)
|
||||
}
|
||||
}
|
||||
|
||||
override fun stop(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
|
||||
if (successfulPollinationTicks > REQUIRED_SUCCESSFUL_POLLINATION_TICKS) {
|
||||
val blockPos = entity.brain.getMemorySafely(CobblemonMemories.NEARBY_SACC_LEAVES).orElse(null)
|
||||
blockPos.let {
|
||||
val blockState = level.getBlockState(blockPos)
|
||||
if (blockState.block == CobblemonBlocks.SACCHARINE_LEAVES) {
|
||||
val saccAge = blockState.getValue( SaccharineLeafBlock.AGE)
|
||||
if (saccAge < SaccharineLeafBlock.MAX_AGE) {
|
||||
entity.brain.eraseMemory(CobblemonMemories.HAS_NECTAR)
|
||||
val newBlockState = blockState.setValue(SaccharineLeafBlock.AGE, saccAge + 1)
|
||||
level.setBlock(blockPos, newBlockState, 3)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
successfulPollinationTicks = 0
|
||||
entity.brain.eraseMemory(MemoryModuleType.WALK_TARGET)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+52
-24
@@ -8,17 +8,14 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonActivities
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.getMemorySafely
|
||||
import com.cobblemon.mod.common.util.sendParticlesServer
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.core.particles.ParticleTypes
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.sounds.SoundEvents
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.Behavior
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
@@ -29,10 +26,11 @@ import net.minecraft.world.phys.Vec3
|
||||
class PollinateFlowerTaskConfig : SingleTaskConfig {
|
||||
companion object {
|
||||
const val POLLINATE = "pollinate"
|
||||
const val PATH_TO_FLOWER_COOLDOWN_TICKS : Long = 200
|
||||
const val HAS_NECTAR_ASPECT = "has_nectar"
|
||||
}
|
||||
|
||||
val condition = booleanVariable(POLLINATE, "can_pollinate", true).asExpressible()
|
||||
val durationTicks: ExpressionOrEntityVariable = Either.left("30".asExpression())
|
||||
|
||||
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = listOf(
|
||||
condition
|
||||
@@ -51,22 +49,28 @@ class PollinateFlowerTaskConfig : SingleTaskConfig {
|
||||
|
||||
return object : Behavior<LivingEntity>(
|
||||
mapOf(
|
||||
CobblemonMemories.NEARBY_FLOWERS to MemoryStatus.VALUE_PRESENT,
|
||||
CobblemonMemories.NEARBY_FLOWER to MemoryStatus.VALUE_PRESENT,
|
||||
MemoryModuleType.WALK_TARGET to MemoryStatus.VALUE_ABSENT,
|
||||
CobblemonMemories.POLLINATED to MemoryStatus.VALUE_ABSENT,
|
||||
CobblemonMemories.HAS_NECTAR to MemoryStatus.REGISTERED,
|
||||
CobblemonMemories.HIVE_COOLDOWN to MemoryStatus.VALUE_ABSENT,
|
||||
),
|
||||
15,
|
||||
45
|
||||
600,
|
||||
625
|
||||
) {
|
||||
val REQUIRED_SUCCESSFUL_POLLINATION_TICKS = 400
|
||||
var successfulPollinationTicks = 0
|
||||
var lastSoundPlayedTick = 0
|
||||
var hoverPos: Vec3? = null
|
||||
|
||||
override fun checkExtraStartConditions(level: ServerLevel, owner: LivingEntity): Boolean {
|
||||
return entity.brain.getMemorySafely(CobblemonMemories.NEARBY_FLOWERS).orElse(emptyList()).any {
|
||||
Vec3.atCenterOf(it).distanceTo(entity.position()) <= 1.0
|
||||
}
|
||||
if (level.isNight || level.isRaining || entity.brain.getMemorySafely(CobblemonMemories.HAS_NECTAR).orElse(false)) return false
|
||||
val optionalBlockPos = entity.brain.getMemorySafely(CobblemonMemories.NEARBY_FLOWER)
|
||||
return optionalBlockPos.isPresent && Vec3.atCenterOf(optionalBlockPos.get()).distanceTo(entity.position()) <= 1.0
|
||||
}
|
||||
|
||||
override fun canStillUse(level: ServerLevel, entity: LivingEntity, gameTime: Long): Boolean {
|
||||
return checkExtraStartConditions(level, entity)
|
||||
return checkExtraStartConditions(level, entity) && entity.brain.activeActivities.indexOf(
|
||||
CobblemonActivities.POKEMON_POLLINATION) != -1
|
||||
}
|
||||
|
||||
override fun start(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
|
||||
@@ -74,20 +78,44 @@ class PollinateFlowerTaskConfig : SingleTaskConfig {
|
||||
}
|
||||
|
||||
override fun tick(level: ServerLevel, owner: LivingEntity, gameTime: Long) {
|
||||
level.sendParticlesServer(
|
||||
particleType = ParticleTypes.DRIPPING_HONEY,
|
||||
position = owner.eyePosition,
|
||||
particles = 3,
|
||||
offset = Vec3.ZERO,
|
||||
speed = 0.0
|
||||
)
|
||||
++successfulPollinationTicks
|
||||
if (entity.random.nextFloat() < 0.05f && successfulPollinationTicks > this.lastSoundPlayedTick + 60) {
|
||||
this.lastSoundPlayedTick = successfulPollinationTicks
|
||||
entity.playSound(SoundEvents.BEE_POLLINATE, 1.0f, 1.0f)
|
||||
}
|
||||
val flowerPos = entity.brain.getMemorySafely(CobblemonMemories.NEARBY_FLOWER).orElse(null)
|
||||
|
||||
|
||||
val bl = hoverPos == null || entity.position().distanceTo(hoverPos!!) <= 0.1
|
||||
val bl3 = entity.random.nextInt(40) == 0
|
||||
if (bl && bl3) {
|
||||
// mimics the wriggling over a flower the vanilla bees do
|
||||
if (hoverPos == null) {
|
||||
hoverPos = flowerPos.bottomCenter.add(0.0, 0.4, 0.0)
|
||||
}
|
||||
|
||||
if (flowerPos != null) {
|
||||
hoverPos = flowerPos.bottomCenter.add(Vec3((entity.random.nextDouble() * 2.0 - 1.0) * (1.0/5.0), 0.3 + (entity.random.nextDouble() * 2.0 - 1.0) * (1.0/7.0), (entity.random.nextDouble() * 2.0 - 1.0) * (1.0/5.0)))
|
||||
entity.getMoveControl()
|
||||
.setWantedPosition(hoverPos!!.x(), hoverPos!!.y(), hoverPos!!.z(), 0.35)
|
||||
entity.lookControl.setLookAt(flowerPos.bottomCenter.add(0.0,0.5,0.0))
|
||||
}
|
||||
} else if (!bl) {
|
||||
entity.getMoveControl()
|
||||
.setWantedPosition(hoverPos!!.x(), hoverPos!!.y(), hoverPos!!.z(), 0.35)
|
||||
}
|
||||
entity.lookControl.setLookAt(flowerPos.bottomCenter.add(0.0,0.5,0.0))
|
||||
|
||||
}
|
||||
|
||||
override fun stop(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
|
||||
val flowerStillThere = canStillUse(level, entity, gameTime)
|
||||
if (flowerStillThere) {
|
||||
entity.brain.setMemory(CobblemonMemories.POLLINATED, true)
|
||||
|
||||
if (successfulPollinationTicks > REQUIRED_SUCCESSFUL_POLLINATION_TICKS) {
|
||||
entity.brain.setMemory(CobblemonMemories.HAS_NECTAR, true)
|
||||
}
|
||||
successfulPollinationTicks = 0
|
||||
entity.brain.setMemoryWithExpiry(CobblemonMemories.PATH_TO_NEARBY_FLOWER_COOLDOWN, true, PATH_TO_FLOWER_COOLDOWN_TICKS)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +97,9 @@ interface TaskConfig {
|
||||
cobblemonResource("go_to_land") to GoToLandTaskConfig::class.java,
|
||||
cobblemonResource("path_to_hive") to PathToBeeHiveTaskConfig::class.java,
|
||||
cobblemonResource("place_honey_in_hive") to PlaceHoneyInHiveTaskConfig::class.java,
|
||||
cobblemonResource("place_honey_in_sacc_leaves") to PlaceHoneyInSaccLeavesTaskConfig::class.java,
|
||||
cobblemonResource("path_to_flower") to PathToFlowerTaskConfig::class.java,
|
||||
cobblemonResource("path_to_sacc_leaves") to PathToSaccLeavesTaskConfig::class.java,
|
||||
cobblemonResource("pollinate_flower") to PollinateFlowerTaskConfig::class.java,
|
||||
cobblemonResource("go_to_land") to GoToLandTaskConfig::class.java,
|
||||
cobblemonResource("manage_flight_in_battle") to ManageFlightInBattleTaskConfig::class.java,
|
||||
|
||||
+29
@@ -31,8 +31,10 @@ import net.minecraft.world.entity.ai.behavior.BlockPosTracker
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.level.material.Fluids
|
||||
import net.minecraft.world.level.pathfinder.PathType
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import kotlin.math.ceil
|
||||
|
||||
class WaterWanderTaskConfig : SingleTaskConfig {
|
||||
val condition = booleanVariable(WANDER, "water_wanders", true).asExpressible()
|
||||
@@ -100,6 +102,33 @@ class WaterWanderTaskConfig : SingleTaskConfig {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
// Move target pos down so that we don't move out of water too much
|
||||
val requiredDepth = ceil(0.5 + entity.eyeHeight)
|
||||
// Get the current depth of the block
|
||||
var depth = 1
|
||||
var testPos = pos.above()
|
||||
var blockState = entity.level().getBlockState(testPos)
|
||||
while (blockState.fluidState.type == Fluids.WATER) {
|
||||
depth++
|
||||
testPos = testPos!!.above()
|
||||
blockState = entity.level().getBlockState(testPos)
|
||||
}
|
||||
|
||||
if (depth < requiredDepth) {
|
||||
// Iterate down until we reach the desired min depth or we reach a non water block
|
||||
pos = pos.below()
|
||||
blockState = entity.level().getBlockState(pos)
|
||||
while (blockState.fluidState.type == Fluids.WATER && depth < requiredDepth) {
|
||||
depth ++
|
||||
pos = pos!!.below()
|
||||
blockState = entity.level().getBlockState(pos)
|
||||
}
|
||||
}
|
||||
|
||||
if (depth < requiredDepth) {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
walkTarget.set(
|
||||
CobblemonWalkTarget(
|
||||
pos = pos,
|
||||
|
||||
@@ -9,13 +9,11 @@
|
||||
package com.cobblemon.mod.common.api.cooking
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonItemComponents
|
||||
import com.cobblemon.mod.common.item.PokePuffItem
|
||||
import com.cobblemon.mod.common.item.PokePuffItem.Companion.DISLIKED_FLAVOR_MULTIPLIER
|
||||
import com.cobblemon.mod.common.item.PokePuffItem.Companion.LIKED_FLAVOR_MULTIPLIER
|
||||
import com.cobblemon.mod.common.pokemon.Nature
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
import net.minecraft.world.item.ItemStack
|
||||
|
||||
object PokePuffUtils {
|
||||
|
||||
@@ -25,11 +23,12 @@ object PokePuffUtils {
|
||||
|
||||
val (baseFriendship) = calculateBaseFriendship(stack)
|
||||
|
||||
return when {
|
||||
dominantFlavour == nature.favouriteFlavour -> (baseFriendship / LIKED_FLAVOR_MULTIPLIER).toInt()
|
||||
dominantFlavour == Flavour.MILD && isNeutralNature -> (baseFriendship / 2.0).coerceAtLeast(1.0).toInt()
|
||||
else -> (-baseFriendship / DISLIKED_FLAVOR_MULTIPLIER).toInt()
|
||||
}
|
||||
val multiplier = if (
|
||||
dominantFlavour == nature.favouriteFlavour ||
|
||||
(dominantFlavour == Flavour.MILD && isNeutralNature)
|
||||
) LIKED_FLAVOR_MULTIPLIER else -DISLIKED_FLAVOR_MULTIPLIER
|
||||
|
||||
return (baseFriendship / multiplier).toInt()
|
||||
}
|
||||
|
||||
fun calculateBaseFriendship(stack: ItemStack): Pair<Double, Double> {
|
||||
@@ -77,8 +76,8 @@ object PokePuffUtils {
|
||||
Flavour.SPICY -> "attack"
|
||||
Flavour.DRY -> "special_attack"
|
||||
Flavour.SWEET -> "speed"
|
||||
Flavour.BITTER -> "special_defense"
|
||||
Flavour.SOUR -> "defense"
|
||||
Flavour.BITTER -> "special_defence"
|
||||
Flavour.SOUR -> "defence"
|
||||
Flavour.MILD -> "neutral"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,6 +152,9 @@ object CobblemonEvents {
|
||||
@JvmField
|
||||
val RIDE_EVENT_PRE = CancelableObservable<RidePokemonEvent.Pre>()
|
||||
|
||||
@JvmField
|
||||
val RIDE_EVENT_APPLY_STAMINA = EventObservable<RidePokemonEvent.ApplyStamina>()
|
||||
|
||||
@JvmField
|
||||
val RIDE_EVENT_POST = EventObservable<RidePokemonEvent.Post>()
|
||||
|
||||
|
||||
+32
-2
@@ -8,9 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.events.pokemon
|
||||
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.cobblemon.mod.common.api.events.Cancelable
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
|
||||
@@ -49,4 +47,36 @@ interface RidePokemonEvent {
|
||||
"pokemon" to pokemon.struct
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Event published when stamina is being applied. At this point you can modify the stamina that will get used on the
|
||||
* mount or you can make the stamina infinite. Handy hey.
|
||||
*/
|
||||
class ApplyStamina(
|
||||
override val player: ServerPlayer,
|
||||
override val pokemon: PokemonEntity,
|
||||
var rideStamina: Float
|
||||
) : RidePokemonEvent {
|
||||
val context = mutableMapOf(
|
||||
"player" to player.asMoLangValue(),
|
||||
"pokemon" to pokemon.struct,
|
||||
"ride_stamina" to DoubleValue(rideStamina)
|
||||
)
|
||||
val functions = moLangFunctionMap(
|
||||
"set_ride_stamina" to { params ->
|
||||
rideStamina = params.getDouble(0).toFloat().coerceIn(0F, 1F)
|
||||
DoubleValue.ONE
|
||||
},
|
||||
"set_infinite_stamina" to { _ ->
|
||||
rideStamina = -1F
|
||||
DoubleValue.ONE
|
||||
},
|
||||
)
|
||||
|
||||
fun setInfiniteStamina() {
|
||||
rideStamina = -1F
|
||||
}
|
||||
|
||||
fun isInfiniteStamina() = rideStamina == -1F
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,6 @@ import com.bedrockk.molang.runtime.MoLangEnvironment
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.MoParams
|
||||
import com.bedrockk.molang.runtime.struct.ArrayStruct
|
||||
import com.bedrockk.molang.runtime.struct.MoStruct
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.struct.VariableStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
@@ -40,7 +39,6 @@ import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
|
||||
import com.cobblemon.mod.common.api.moves.animations.NPCProvider
|
||||
import com.cobblemon.mod.common.api.moves.animations.TargetsProvider
|
||||
import com.cobblemon.mod.common.api.npc.NPCClass
|
||||
import com.cobblemon.mod.common.api.npc.NPCClasses
|
||||
import com.cobblemon.mod.common.api.npc.configuration.interaction.DialogueNPCInteractionConfiguration
|
||||
import com.cobblemon.mod.common.api.npc.configuration.interaction.ScriptNPCInteractionConfiguration
|
||||
@@ -57,7 +55,6 @@ import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.api.pokemon.experience.SidemodExperienceSource
|
||||
import com.cobblemon.mod.common.api.pokemon.moves.LearnsetQuery
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.riding.Rideable
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.api.scheduling.ClientTaskTracker
|
||||
import com.cobblemon.mod.common.api.scheduling.Schedulable
|
||||
@@ -137,7 +134,6 @@ import net.minecraft.world.entity.LightningBolt
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.Mob
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.PlayerRideable
|
||||
import net.minecraft.world.entity.TamableAnimal
|
||||
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
@@ -145,7 +141,6 @@ import net.minecraft.world.entity.ai.memory.MemoryStatus
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.entity.animal.Animal
|
||||
import net.minecraft.world.entity.item.ItemEntity
|
||||
import net.minecraft.world.entity.monster.Enemy
|
||||
import net.minecraft.world.entity.monster.Monster
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.ItemStack
|
||||
@@ -160,9 +155,6 @@ import net.minecraft.world.level.levelgen.Heightmap
|
||||
import net.minecraft.world.level.pathfinder.PathType
|
||||
import net.minecraft.world.phys.AABB
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import kotlin.text.get
|
||||
import kotlin.text.toInt
|
||||
import kotlin.toString
|
||||
|
||||
/**
|
||||
* Holds a bunch of useful MoLang trickery that can be used or extended in API
|
||||
@@ -1185,16 +1177,28 @@ object MoLangFunctions {
|
||||
return@put DoubleValue.ONE
|
||||
}
|
||||
map.put("has_memory_value") { params ->
|
||||
val memoryTypes = params.params.map {
|
||||
it.asString().asIdentifierDefaultingNamespace()
|
||||
}.map(BuiltInRegistries.MEMORY_MODULE_TYPE::get)
|
||||
return@put DoubleValue(memoryTypes.all { entity.brain.checkMemory(it, MemoryStatus.VALUE_PRESENT) })
|
||||
for (param in params.params) {
|
||||
if (!entity.hasMemoryFromString(param.asString())) {
|
||||
return@put DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
return@put DoubleValue.ONE
|
||||
}
|
||||
map.put("lacks_memory_value") { params ->
|
||||
val memoryTypes = params.params.map {
|
||||
it.asString().asIdentifierDefaultingNamespace()
|
||||
}.map(BuiltInRegistries.MEMORY_MODULE_TYPE::get)
|
||||
return@put DoubleValue(memoryTypes.none { entity.brain.checkMemory(it, MemoryStatus.VALUE_PRESENT) })
|
||||
for (param in params.params) {
|
||||
if (entity.hasMemoryFromString(param.asString())) {
|
||||
return@put DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
return@put DoubleValue.ONE
|
||||
}
|
||||
map.put("is_doing_activity") { params ->
|
||||
for (param in params.params) {
|
||||
if (entity.isDoingActivityFromString(param.asString())) {
|
||||
return@put DoubleValue.ONE
|
||||
}
|
||||
}
|
||||
return@put DoubleValue.ZERO
|
||||
}
|
||||
map.put("can_see") { params ->
|
||||
val target = params.get<MoValue>(0)
|
||||
@@ -1252,15 +1256,6 @@ object MoLangFunctions {
|
||||
map.put("in_battle") { DoubleValue(npc.isInBattle()) }
|
||||
map.put("battles") { ArrayStruct(npc.battleIds.mapNotNull { BattleRegistry.getBattle(it)?.struct }.mapIndexed { index, value -> "$index" to value }.toMap()) }
|
||||
map.put("stop_battles") { _ -> npc.battleIds.forEach { BattleRegistry.getBattle(it)?.stop() } }
|
||||
map.put("is_doing_activity") { params ->
|
||||
val identifiers = params.params.map { it.asString().asIdentifierDefaultingNamespace(namespace = "minecraft") }
|
||||
val activities = identifiers.mapNotNull { identifier -> BuiltInRegistries.ACTIVITY.get(identifier) }
|
||||
if (activities.isNotEmpty()) {
|
||||
return@put DoubleValue(activities.any { activity -> npc.brain.isActive(activity) })
|
||||
} else {
|
||||
return@put DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
map.put("run_script_on_client") { params ->
|
||||
val world = npc.level()
|
||||
if (world is ServerLevel) {
|
||||
@@ -1905,6 +1900,9 @@ object MoLangFunctions {
|
||||
map.put("is_holding_item") { DoubleValue(!pokemonEntity.entityData.get(PokemonEntity.SHOWN_HELD_ITEM).let {
|
||||
it.isEmpty || it.`is`(CobblemonItemTags.WEARABLE_HAT_ITEMS) || it.`is`(CobblemonItemTags.WEARABLE_FACE_ITEMS)
|
||||
}) }
|
||||
map.put("riding_style") {
|
||||
StringValue(pokemonEntity.ifRidingAvailableSupply("") { behaviour, settings, state -> behaviour.getRidingStyle(settings, state).name })
|
||||
}
|
||||
map.put("is_wearing_hat") { DoubleValue(pokemonEntity.entityData.get(PokemonEntity.SHOWN_HELD_ITEM).`is`(CobblemonItemTags.WEARABLE_HAT_ITEMS)) }
|
||||
map.put("is_wearing_face") { DoubleValue(pokemonEntity.entityData.get(PokemonEntity.SHOWN_HELD_ITEM).`is`(CobblemonItemTags.WEARABLE_FACE_ITEMS)) }
|
||||
map.put("is_pastured") {
|
||||
|
||||
@@ -131,6 +131,7 @@ open class PokemonProperties {
|
||||
props.species = parseSpeciesIdentifier(keyPairs)
|
||||
props.form = parseForm(keyPairs)
|
||||
props.friendship = parseIntProperty(keyPairs, listOf("friendship"))?.coerceIn(0, Cobblemon.config.maxPokemonFriendship)
|
||||
props.fullness = parseIntProperty(keyPairs, listOf("fullness"))
|
||||
props.pokeball = parseIdentifierOfRegistry(keyPairs, listOf("pokeball")) { identifier -> PokeBalls.getPokeBall(identifier)?.name?.toString() }
|
||||
props.nature = parseIdentifierOfRegistry(keyPairs, listOf("nature")) { identifier -> Natures.getNature(identifier)?.name?.toString() }
|
||||
props.ability = parseStringOfRegistry(keyPairs, listOf("ability")) { Abilities.get(it)?.name }
|
||||
@@ -326,6 +327,7 @@ open class PokemonProperties {
|
||||
var gender: Gender? = null
|
||||
var level: Int? = null
|
||||
var friendship: Int? = null
|
||||
var fullness: Int? = null
|
||||
var pokeball: String? = null
|
||||
var nature: String? = null
|
||||
var ability: String? = null
|
||||
@@ -397,6 +399,7 @@ open class PokemonProperties {
|
||||
pokemon.setFriendship(pokemon.form.baseFriendship)
|
||||
}
|
||||
}
|
||||
fullness?.let { pokemon.currentFullness = it }
|
||||
pokeball?.let { PokeBalls.getPokeBall(it.asIdentifierDefaultingNamespace())?.let { pokeball -> pokemon.caughtBall = pokeball } }
|
||||
nature?.let { Natures.getNature(it.asIdentifierDefaultingNamespace())?.let { nature -> pokemon.nature = nature } }
|
||||
customProperties.forEach { it.apply(pokemon) }
|
||||
@@ -504,6 +507,7 @@ open class PokemonProperties {
|
||||
nickname?.takeIf { it.string != pokemon.nickname?.string }?.let { return false }
|
||||
form?.takeIf { !it.equals(pokemon.form.name, true) }?.let { return false }
|
||||
friendship?.takeIf { it != pokemon.friendship }?.let { return false }
|
||||
fullness?.takeIf { it != pokemon.currentFullness }?.let { return false }
|
||||
pokeball?.takeIf { it != pokemon.caughtBall.name.toString() }?.let { return false }
|
||||
nature?.takeIf { it != pokemon.nature.name.toString() }?.let { return false }
|
||||
ability?.takeIf { it != pokemon.ability.name }?.let { return false }
|
||||
@@ -588,6 +592,7 @@ open class PokemonProperties {
|
||||
originalTrainer?.takeIf { it != properties.originalTrainer }?.let{ return false }
|
||||
originalTrainerType?.takeIf { it != properties.originalTrainerType }?.let{ return false }
|
||||
moves?.takeIf { it.any { move -> properties.moves?.none { it == move } == true } }?.let { return false }
|
||||
fullness?.takeIf { it != properties.fullness }?.let { return false }
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -636,6 +641,7 @@ open class PokemonProperties {
|
||||
nickname?.let { nbt.putString(DataKeys.POKEMON_NICKNAME, Component.Serializer.toJson(it, registryLookup)) }
|
||||
form?.let { nbt.putString(DataKeys.POKEMON_FORM_ID, it) }
|
||||
friendship?.let { nbt.putInt(DataKeys.POKEMON_FRIENDSHIP, it) }
|
||||
fullness?.let { nbt.putInt(DataKeys.POKEMON_FULLNESS, it) }
|
||||
pokeball?.let { nbt.putString(DataKeys.POKEMON_CAUGHT_BALL, it) }
|
||||
nature?.let { nbt.putString(DataKeys.POKEMON_NATURE, it) }
|
||||
ability?.let { nbt.putString(DataKeys.POKEMON_ABILITY, it) }
|
||||
@@ -667,6 +673,7 @@ open class PokemonProperties {
|
||||
nickname = if (tag.contains(DataKeys.POKEMON_NICKNAME)) Component.Serializer.fromJson(tag.getString(DataKeys.POKEMON_NICKNAME), registryLookup) else null
|
||||
form = if (tag.contains(DataKeys.POKEMON_FORM_ID)) tag.getString(DataKeys.POKEMON_FORM_ID) else null
|
||||
friendship = if (tag.contains(DataKeys.POKEMON_FRIENDSHIP)) tag.getInt(DataKeys.POKEMON_FRIENDSHIP) else null
|
||||
fullness = if (tag.contains(DataKeys.POKEMON_FULLNESS)) tag.getInt(DataKeys.POKEMON_FULLNESS) else null
|
||||
pokeball = if (tag.contains(DataKeys.POKEMON_CAUGHT_BALL)) tag.getString(DataKeys.POKEMON_CAUGHT_BALL) else null
|
||||
nature = if (tag.contains(DataKeys.POKEMON_NATURE)) tag.getString(DataKeys.POKEMON_NATURE) else null
|
||||
ability = if (tag.contains(DataKeys.POKEMON_ABILITY)) tag.getString(DataKeys.POKEMON_ABILITY) else null
|
||||
@@ -700,6 +707,7 @@ open class PokemonProperties {
|
||||
//nickname?.let { json.addProperty(DataKeys.POKEMON_NICKNAME, Text.Serialization.toJsonString(it)) }
|
||||
form?.let { json.addProperty(DataKeys.POKEMON_FORM_ID, it) }
|
||||
friendship?.let { json.addProperty(DataKeys.POKEMON_FRIENDSHIP, it) }
|
||||
fullness?.let {json.addProperty(DataKeys.POKEMON_FULLNESS, it)}
|
||||
pokeball?.let { json.addProperty(DataKeys.POKEMON_CAUGHT_BALL, it) }
|
||||
nature?.let { json.addProperty(DataKeys.POKEMON_NATURE, it) }
|
||||
ability?.let { json.addProperty(DataKeys.POKEMON_ABILITY, it) }
|
||||
@@ -732,6 +740,7 @@ open class PokemonProperties {
|
||||
//nickname = json.get(DataKeys.POKEMON_NICKNAME)?.asString?.let { Text.Serialization.fromJson(it) }
|
||||
form = json.get(DataKeys.POKEMON_FORM_ID)?.asString
|
||||
friendship = json.get(DataKeys.POKEMON_FRIENDSHIP)?.asInt
|
||||
fullness = json.get(DataKeys.POKEMON_FULLNESS)?.asInt
|
||||
pokeball = json.get(DataKeys.POKEMON_CAUGHT_BALL)?.asString
|
||||
nature = json.get(DataKeys.POKEMON_NATURE)?.asString
|
||||
ability = json.get(DataKeys.POKEMON_ABILITY)?.asString
|
||||
@@ -763,6 +772,7 @@ open class PokemonProperties {
|
||||
shiny?.let { pieces.add("shiny=$it") }
|
||||
gender?.let { pieces.add("gender=$it")}
|
||||
friendship?.let { pieces.add("friendship=$it") }
|
||||
fullness?.let {pieces.add("fullness=$it")}
|
||||
pokeball?.let { pieces.add("pokeball=$it") }
|
||||
nature?.let { pieces.add("nature=$it") }
|
||||
ability?.let { pieces.add("ability=$it") }
|
||||
|
||||
+2
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.api.pokemon.aspect
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBlocks
|
||||
import com.cobblemon.mod.common.api.ai.config.task.PollinateFlowerTaskConfig
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SaccharineLogSlatheredInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.prospecting.LurePokeSnackDetector
|
||||
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
|
||||
@@ -27,6 +28,7 @@ val aspectParticleMap: Map<String, ParticleData> = mapOf(
|
||||
ParticleTypes.BLOCK,
|
||||
CobblemonBlocks.POKE_SNACK.defaultBlockState()
|
||||
), 0.05, 3),
|
||||
PollinateFlowerTaskConfig.HAS_NECTAR_ASPECT to ParticleData.MinecraftParticle(ParticleTypes.FALLING_NECTAR, 0.075, 1)
|
||||
)
|
||||
|
||||
sealed class ParticleData {
|
||||
|
||||
@@ -9,10 +9,7 @@
|
||||
package com.cobblemon.mod.common.api.riding
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStatDefinition
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.util.adapters.RidingBehaviourSettingsAdapter
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
@@ -32,10 +29,10 @@ class RidingProperties(
|
||||
{ buffer.readEnumConstant(RidingStyle::class.java) },
|
||||
{
|
||||
val key = buffer.readResourceLocation()
|
||||
val settings = RidingBehaviourSettingsAdapter.types[key]?.getConstructor()?.newInstance()
|
||||
val behaviour = RidingBehaviourSettingsAdapter.types[key]?.getConstructor()?.newInstance()
|
||||
?: error("Unknown controller key: $key")
|
||||
settings.decode(buffer)
|
||||
settings
|
||||
behaviour.decode(buffer)
|
||||
behaviour
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -51,7 +48,10 @@ class RidingProperties(
|
||||
buffer.writeMap(
|
||||
v,
|
||||
{ _, style -> buffer.writeEnumConstant(style) },
|
||||
{ _, behaviour -> behaviour.encode(buffer) }
|
||||
{ _, behaviour ->
|
||||
buffer.writeResourceLocation(behaviour.key)
|
||||
behaviour.encode(buffer)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+4
-3
@@ -19,6 +19,9 @@ import net.minecraft.resources.ResourceLocation
|
||||
* Typically this will be initialized for each pokemon form during deserialization
|
||||
* to determine how they should ride.
|
||||
*
|
||||
* These also exist in a datapacked folder, ride_settings, which are used for the fallback
|
||||
* values if non-stat settings are omitted in the pokemon form JSON.
|
||||
*
|
||||
* @author landonjw
|
||||
*/
|
||||
interface RidingBehaviourSettings: Encodable, Decodable {
|
||||
@@ -27,8 +30,6 @@ interface RidingBehaviourSettings: Encodable, Decodable {
|
||||
|
||||
fun calculate(stat: RidingStat, boostAmount: Float): Float {
|
||||
val range = stats[stat] ?: return 0F
|
||||
return range.first + boostAmount
|
||||
return (range.first + boostAmount).coerceAtMost(range.endInclusive.toFloat())
|
||||
}
|
||||
|
||||
fun hasStat(stat: RidingStat) = stats.containsKey(stat)
|
||||
}
|
||||
+1
-1
@@ -18,7 +18,7 @@ import net.minecraft.world.phys.Vec3
|
||||
* This is intended to contain mutable state that is passed between the client and server
|
||||
* or temporary state that is used during the riding process.
|
||||
*
|
||||
* This will be destroyed when the a user dismounts the Pokemon.
|
||||
* This will be destroyed when the main rider dismounts the Pokemon.
|
||||
*
|
||||
* @author landonjw
|
||||
*/
|
||||
|
||||
+25
-2
@@ -8,13 +8,18 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.riding.behaviour
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.DoubleJump
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.client.MountedCameraTypeHandler
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.tags.FluidTags
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import kotlin.collections.get
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import kotlin.collections.get
|
||||
|
||||
/**
|
||||
* Small wrapper around a RidingBehaviour to provide sane defaults in the event that the behaviour is not active.
|
||||
@@ -50,6 +55,14 @@ class RidingController(
|
||||
val newState = RidingBehaviours.get(behaviourSettings.key).createDefaultState(behaviourSettings)
|
||||
context?.let { newState.stamina.set(it.state.stamina.get(), forced = true) }
|
||||
context?.let { newState.rideVelocity.set(it.state.rideVelocity.get(), forced = true) }
|
||||
val previousKey = context?.behaviour
|
||||
val newKey = behaviourSettings.key
|
||||
for (passenger in entity.passengers) {
|
||||
if (passenger is Player && passenger !is ServerPlayer) {
|
||||
MountedCameraTypeHandler.handleTransition(previousKey ?: continue, newKey)
|
||||
}
|
||||
}
|
||||
|
||||
context = ActiveRidingContext(behaviourSettings.key, behaviourSettings, newState, newTransition)
|
||||
lastTransitionAge = entity.ticksLived
|
||||
} else {
|
||||
@@ -97,12 +110,22 @@ class RidingController(
|
||||
}
|
||||
|
||||
private fun canTransitionToLand(): Boolean {
|
||||
if (entity.isInLiquid || entity.isUnderWater) return false
|
||||
val hasLandController = entity.pokemon.riding.behaviours?.get(RidingStyle.LAND) != null
|
||||
if (hasLandController && (entity.isInLiquid || entity.isUnderWater)) return false
|
||||
if (!hasLandController && (entity.isEyeInFluid(FluidTags.WATER) || entity.isEyeInFluid(FluidTags.LAVA))) return false
|
||||
return entity.onGround()
|
||||
}
|
||||
|
||||
private fun canTransitionToLiquid(): Boolean {
|
||||
return entity.isInLiquid || entity.isUnderWater
|
||||
// If it has a liquid controller to transition to and it isn't currently an air controller then transition on
|
||||
// touching water. If not then check for eyes in water. This allows fliers to fly closely above water and
|
||||
// for walkers that don't have a liquid controller to be able to walk in not deep water
|
||||
return if (entity.pokemon.riding.behaviours?.get(RidingStyle.LIQUID) != null && context?.style != RidingStyle.AIR) {
|
||||
entity.isInLiquid || entity.isUnderWater
|
||||
} else {
|
||||
entity.isEyeInFluid(FluidTags.WATER) || entity.isEyeInFluid(FluidTags.LAVA)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun canTransitionToAir(driver: LivingEntity?): Boolean {
|
||||
|
||||
+100
-75
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.api.riding.behaviour.types.air
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.MoLangMath.lerp
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonRideSettings
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
@@ -49,19 +50,11 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
val poseProvider = PoseProvider<BirdSettings, BirdState>(PoseType.HOVER)
|
||||
.with(PoseOption(PoseType.FLY) { _, state, _ -> state.rideVelocity.get().z > 0.2 })
|
||||
|
||||
val globalBird: BirdSettings
|
||||
get() = CobblemonRideSettings.bird
|
||||
|
||||
override fun isActive(settings: BirdSettings, state: BirdState, vehicle: PokemonEntity): Boolean {
|
||||
return Shapes.create(vehicle.boundingBox).blockPositionsAsListRounded().any {
|
||||
//Need to check other fluids
|
||||
if (vehicle.isInWater || vehicle.isUnderWater) {
|
||||
return@any false
|
||||
}
|
||||
//This might not actually work, depending on what the yPos actually is. yPos of the middle of the entity? the feet?
|
||||
if (it.y.toDouble() == (vehicle.position().y)) {
|
||||
val blockState = vehicle.level().getBlockState(it.below())
|
||||
return@any !(!blockState.isAir && blockState.fluidState.isEmpty)
|
||||
}
|
||||
true
|
||||
}
|
||||
return !(vehicle.isInWater || vehicle.isUnderWater)
|
||||
}
|
||||
|
||||
override fun pose(settings: BirdSettings, state: BirdState, vehicle: PokemonEntity): PoseType {
|
||||
@@ -114,16 +107,24 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
driver: Player
|
||||
) {
|
||||
val stam = state.stamina.get()
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
|
||||
// Grab the boost time in seconds and convert to ticks. Then calculate the drain rate as inversely
|
||||
// proportional to the number of ticks of boost thus making a full boost take x ticks
|
||||
// in short: "Stamina drains slower at higher values and also replenishes slower"
|
||||
val totalStam = vehicle.runtime.resolveDouble(settings.staminaExpr) * 20.0f
|
||||
val stamDrainRate = (1.0f / totalStam).toFloat()
|
||||
val totalStam = vehicle.runtime.resolveDouble(settings.staminaExpr ?: globalBird.staminaExpr!!) * 20.0f
|
||||
val horzMod = vehicle.runtime.resolveDouble(settings.stamDrainHorzMod ?: globalBird.stamDrainHorzMod!!)
|
||||
val glideMod = vehicle.runtime.resolveFloat(settings.stamDrainPercRateGlide ?: globalBird.stamDrainPercRateGlide!!)
|
||||
val stamDrainPerRateDive = vehicle.runtime.resolveDouble(settings.stamDrainPerRateDive ?: globalBird.stamDrainPerRateDive!!).coerceIn(0.0, 1.0) // Ensure its between 1 and 0 or things get weird
|
||||
|
||||
val newStam = if (driver.zza > 0.0) max(0.0f,stam - stamDrainRate)
|
||||
else if (!state.gliding.get()) max(0.0f,stam - stamDrainRate * 0.5f) // if hovering half the stam drain
|
||||
else min(1.0f,stam + stamDrainRate * 0.2f)
|
||||
val stamDrainHorz = if(vehicle.deltaMovement.horizontalDistance() < 1e-6) horzMod else max(1.0 + ((horzMod - 1.0) * atan( vehicle.deltaMovement.y / vehicle.deltaMovement.horizontalDistance())), 1.0)
|
||||
val diveAmount = sin(controller.pitch.toRadians()).coerceIn(0.0f, 1.0f)// from 0.0 -> 1.0 how steep is the current dive angle
|
||||
val diveMod = ((1.0 - diveAmount) * ( 1.0 - stamDrainPerRateDive ) + stamDrainPerRateDive).toFloat() // smooth between 1.0 and the dive drain mod depending upon how dived the ride is
|
||||
val stamDrainRate = (1.0f / totalStam).toFloat() * stamDrainHorz.toFloat()
|
||||
|
||||
val newStam = if (driver.deltaMovement.length() > 0.1) max(0.0f,stam - stamDrainRate) // Drain at normal fly rate
|
||||
else if (state.gliding.get()) min(1.0f,stam - stamDrainRate * glideMod * diveMod) // Gliding drain logic
|
||||
else max(0.0f,stam - stamDrainRate * 0.5f) // if hovering half the stam drain
|
||||
|
||||
state.stamina.set(newStam)
|
||||
}
|
||||
@@ -174,9 +175,9 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
*/
|
||||
fun calculateRideSpaceVel(settings: BirdSettings, state: BirdState, vehicle: PokemonEntity, driver: Player) {
|
||||
// retrieve stats
|
||||
val topSpeed = (vehicle.runtime.resolveDouble(settings.speedExpr) / 20.0)
|
||||
val accel = topSpeed / (vehicle.runtime.resolveDouble(settings.accelerationExpr) * 20.0)
|
||||
val glideTopSpeed = topSpeed * vehicle.runtime.resolveDouble(settings.glidespeedExpr)
|
||||
val topSpeed = (vehicle.runtime.resolveDouble(settings.speedExpr ?: globalBird.speedExpr!!) / 20.0)
|
||||
val accel = topSpeed / (vehicle.runtime.resolveDouble(settings.accelerationExpr ?: globalBird.accelerationExpr!!) * 20.0)
|
||||
val glideTopSpeed = topSpeed * vehicle.runtime.resolveDouble(settings.glideSpeedExpr ?: globalBird.glideSpeedExpr!!)
|
||||
var glideSpeedChange = 0.0
|
||||
var activeInput = false
|
||||
|
||||
@@ -187,8 +188,8 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
newVelocity = newVelocity.normalize().scale(vehicle.deltaMovement.length())
|
||||
}
|
||||
|
||||
//speed up and slow down based on input
|
||||
if (driver.zza != 0.0f && state.stamina.get() > 0.0) {
|
||||
// speed up and slow down based on input
|
||||
if (driver.zza != 0.0f && state.stamina.get() > 0.0 && newVelocity.length() < glideTopSpeed) {
|
||||
//make sure it can't exceed top speed
|
||||
val forwardInput = when {
|
||||
state.stamina.get() == 0.0f -> 0.0
|
||||
@@ -285,8 +286,8 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr)
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr) / 20.0
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr ?: globalBird.handlingExpr!!)
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr ?: globalBird.speedExpr!!) / 20.0
|
||||
|
||||
val yawDeltaDeg = deltaTime * handling * sin(Math.toRadians(controller.roll.toDouble())) //* sin(Math.toRadians(controller.roll.toDouble())).sign
|
||||
val trueYawDelt = yawDeltaDeg * abs(cos(Math.toRadians(controller.pitch.toDouble())))// * sqrt(RidingBehaviour.scaleToRange(state.rideVelocity.get().length(), 0.0, topSpeed))
|
||||
@@ -313,7 +314,7 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
) {
|
||||
// Calculate correcting roll force.
|
||||
// Mult by cos(pitch) to ensure that it doesn't roll correct at when diving or climbing
|
||||
val rollCorrectionTimer = vehicle.runtime.resolveDouble(settings.timeToRollCorrect)
|
||||
val rollCorrectionTimer = vehicle.runtime.resolveDouble(settings.timeToRollCorrect ?: globalBird.timeToRollCorrect!!)
|
||||
val maxRollCorrectionRate = if (state.rideVelocity.get().length() < 0.1) 15.0f else 8.0f * (cos(controller.pitch.toRadians())).pow(2) * ((state.noInputTimeRoll.get() - rollCorrectionTimer)).coerceIn(0.0, 1.0).toFloat()
|
||||
val maxRollForce = maxRollCorrectionRate / 40.0
|
||||
val rollArrivalDeg = 90.0
|
||||
@@ -343,9 +344,6 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
val maxPitchForce = maxPitchCorrectionRate.toFloat() / 40.0f
|
||||
val pitchArrivalDeg = 45.0f
|
||||
var desiredPitch = if (state.currUpsideDownForce.get() != 0.0) 90.0 else 0.0
|
||||
// if (cos(controller.roll.toRadians()) < 0.0) {
|
||||
// desiredPitch *= -1 // If not rolled over then flip the pitch force. There are better ways to do this :(
|
||||
// }
|
||||
|
||||
if((state.rideVelocity.get().length() < 0.1 && controller.pitch < 0.0) || state.currUpsideDownForce.get() != 0.0) {
|
||||
val arrivalInfluence = (min(pitchArrivalDeg,abs(Mth.wrapDegrees(desiredPitch.toFloat().angleDifference(controller.pitch)))) / pitchArrivalDeg)
|
||||
@@ -446,8 +444,8 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
// Set roll to zero if transitioning to noroll config
|
||||
controller.rotateRoll(controller.roll * -1.0f)
|
||||
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr)
|
||||
val mouseInputMult = vehicle.runtime.resolveDouble(settings.mouseInputMult)
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr ?: globalBird.handlingExpr!!)
|
||||
val mouseInputMult = vehicle.runtime.resolveDouble(settings.mouseInputMult ?: globalBird.mouseInputMult!!)
|
||||
|
||||
//Smooth out mouse input.
|
||||
val smoothingSpeed = 4.0
|
||||
@@ -491,8 +489,8 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr) / 20.0
|
||||
val mouseInputMult = vehicle.runtime.resolveDouble(settings.mouseInputMult)
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr ?: globalBird.speedExpr!!) / 20.0
|
||||
val mouseInputMult = vehicle.runtime.resolveDouble(settings.mouseInputMult ?: globalBird.mouseInputMult!!)
|
||||
|
||||
//Smooth out mouse input.
|
||||
val smoothingSpeed = 2.0
|
||||
@@ -506,17 +504,19 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
val currSpeed = state.rideVelocity.get().length()
|
||||
val currHorzSpeed = state.rideVelocity.get().horizontalDistance()
|
||||
val hoverSpeed = 0.1
|
||||
val pitchDamping = abs(cos(controller.pitch.toRadians())).pow(2) // Helper value used when wanting to discard the influence of another value at steep pitches
|
||||
|
||||
// Yaw locally when at or below hoverSpeed but not when pitched up or rolled over
|
||||
val yawDampen = abs(cos(controller.pitch.toRadians())).pow(2) * abs(cos(controller.roll.toRadians())).pow(2)
|
||||
val localYaw = if (currHorzSpeed < hoverSpeed) xInput * (1 - sqrt(RidingBehaviour.scaleToRange(currHorzSpeed, hoverSpeed, topSpeed))).coerceIn(0.0, 1.0)
|
||||
else 0.0 //xInput * 0.4 * cos(controller.roll.toRadians()).coerceIn(0.0f, 1.0f) * yawDampen
|
||||
val globalYaw = xInput * (1 - sqrt(RidingBehaviour.scaleToRange(currHorzSpeed, hoverSpeed, topSpeed))).coerceIn(0.0, 1.0)
|
||||
//xInput * 0.4 * cos(controller.roll.toRadians()).coerceIn(0.0f, 1.0f) * yawDampen
|
||||
|
||||
controller.applyGlobalYaw(globalYaw.toFloat())
|
||||
|
||||
// Pitch locally up or down depending upon a number of factors:
|
||||
// - Reduce pitch substantially when rolled and in a steep yaw. This prevents the player from ignoring a slow handling stat
|
||||
// - Do not pitch at all when at or below hover speed
|
||||
// - pitch faster at higher speeds
|
||||
val p = 1.0 - vehicle.runtime.resolveDouble(settings.horizontalPitchExpr)
|
||||
val p = 1.0 - vehicle.runtime.resolveDouble(settings.horizontalPitchExpr ?: globalBird.horizontalPitchExpr!!)
|
||||
var localPitch = yInput * (1 - abs(sin(controller.roll.toRadians())).pow(2) * p * hypot(controller.forwardVector.x.toDouble(), controller.forwardVector.z.toDouble()).toFloat())
|
||||
localPitch *= if (currSpeed > hoverSpeed || yInput > 0.0) RidingBehaviour.scaleToRange(currSpeed, 0.0, topSpeed).coerceIn(0.2, 1.0)
|
||||
else 0.0
|
||||
@@ -525,14 +525,18 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
// Apply a roll righting force when trying to pitch hard while rolled sideways. This nudges the player towards
|
||||
// pitching globally
|
||||
val pitchInfluencedRollCorrection = 0.0
|
||||
val howRolledAmI = (( cos(controller.roll.toRadians()) - 1).coerceIn(-1.0f, 0.0f) * -2).coerceIn(0.0f, 0.7f) //Coerce into how much roll you want to let in in the deadzone
|
||||
val inputInRolledDir = if (xInput.sign.toFloat() == controller.roll.sign) 1.0 else -cos(controller.roll.toRadians()).coerceIn(-1.0f, 0.0f).toDouble()
|
||||
val rollDampen = (1 - howRolledAmI * abs(cos(controller.pitch.toRadians())).pow(2) * inputInRolledDir)
|
||||
val howRolledAmI = (( cos(controller.roll.toRadians()) - 1).coerceIn(-1.0f, 0.0f) * -2) //Coerce into how much roll you want to let in in the deadzone
|
||||
val isInputtingTowardsRoll = if ( xInput.sign == controller.roll.sign.toDouble()) 1.0 else 0.0
|
||||
val inputInRolledDir = if (isInputtingTowardsRoll == 1.0) 1.0 else -cos(controller.roll.toRadians()).coerceIn(-1.0f, 0.0f).toDouble()
|
||||
val rollDampen = (1 - howRolledAmI.coerceIn(0.0f, 0.7f) * pitchDamping * inputInRolledDir)
|
||||
val rollForce = if (currHorzSpeed > hoverSpeed) xInput * sqrt(abs(RidingBehaviour.scaleToRange(currHorzSpeed, hoverSpeed, topSpeed)).coerceIn(0.0,1.0)) * rollDampen + pitchInfluencedRollCorrection
|
||||
else 0.0
|
||||
|
||||
// When already rolled significantly part of the roll force should turn to local yaw force
|
||||
val localYawForce = rollForce * abs(sin(controller.roll.toRadians())).pow(2) * pitchDamping * isInputtingTowardsRoll
|
||||
|
||||
//yaw, pitch, roll
|
||||
return Vec3(localYaw, localPitch, rollForce)
|
||||
return Vec3(localYawForce, localPitch, rollForce)
|
||||
}
|
||||
|
||||
|
||||
@@ -579,12 +583,12 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr) / 20.0
|
||||
val glideTopSpeed = topSpeed * vehicle.runtime.resolveDouble(settings.glidespeedExpr)
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr ?: globalBird.speedExpr!!) / 20.0
|
||||
val currSpeed = state.rideVelocity.get().length()
|
||||
|
||||
// Must I ensure that topspeed is greater than minimum?
|
||||
val normalizedGlideSpeed = RidingBehaviour.scaleToRange(currSpeed, topSpeed, glideTopSpeed)
|
||||
val speedOverTopSpeed = max( 0.0, currSpeed - topSpeed)
|
||||
|
||||
val normalizedGlideSpeed = RidingBehaviour.scaleToRange(speedOverTopSpeed, 0.0, 0.3)
|
||||
|
||||
// Only ever want the fov change to be a max of 0.2 and for it to have non linear scaling.
|
||||
return 1.0f + normalizedGlideSpeed.pow(2).toFloat() * 0.2f
|
||||
@@ -668,57 +672,78 @@ class BirdSettings : RidingBehaviourSettings {
|
||||
override val key = BirdBehaviour.KEY
|
||||
override val stats = mutableMapOf<RidingStat, IntRange>()
|
||||
|
||||
var infiniteAltitude: Expression = "false".asExpression()
|
||||
var infiniteAltitude: Expression? = null
|
||||
private set
|
||||
|
||||
var infiniteStamina: Expression = "false".asExpression()
|
||||
var infiniteStamina: Expression? = null
|
||||
private set
|
||||
|
||||
var timeToRollCorrect: Expression = "0.5".asExpression()
|
||||
var timeToRollCorrect: Expression? = null
|
||||
private set
|
||||
|
||||
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 45.0, 10.0)".asExpression()
|
||||
var horizontalPitchExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 0.2, 0.1)".asExpression()
|
||||
var mouseInputMult: Expression = "q.get_ride_stats('SKILL', 'AIR', 1.2, 0.8)".asExpression()
|
||||
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 20.0, 4.0)".asExpression()
|
||||
var handlingExpr: Expression? = null
|
||||
var horizontalPitchExpr: Expression? = null
|
||||
var mouseInputMult: Expression? = null
|
||||
var speedExpr: Expression? = null
|
||||
// Seconds from stationary to top speed
|
||||
var accelerationExpr: Expression = "q.get_ride_stats('ACCELERATION', 'AIR', 2.0, 8.0)".asExpression()
|
||||
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'AIR', 15.0, 2.0)".asExpression()
|
||||
var accelerationExpr: Expression? = null
|
||||
var staminaExpr: Expression? = null
|
||||
|
||||
var glidespeedExpr: Expression = "q.get_ride_stats('JUMP', 'AIR', 2.0, 1.0)".asExpression()
|
||||
var glideSpeedExpr: Expression? = null
|
||||
private set
|
||||
|
||||
// debuff to stamina drain (increases stamina drain?) depending on how horizontal you're looking (so just drain more when climbing in altitude)
|
||||
// So for the base 1.5: If looking straight up and holding forward you drain at 150 percent the rate you would if
|
||||
// you were horizontal.
|
||||
var stamDrainHorzMod: Expression? = null
|
||||
private set
|
||||
|
||||
// long ass variable name
|
||||
// Percent of stamina drain during glide (percent of normal drain rate) So base is 25 percent. (change to 0 if you want no drain or negative if you want regen)
|
||||
var stamDrainPercRateGlide: Expression? = null
|
||||
private set
|
||||
|
||||
// Percent of stamina drain as a factor of how hard you're diving. So if its zero then at full dive you drain no stam.
|
||||
// This stacks with `stamDrainPercRateGlide`
|
||||
// This is coerced between 1 and 0 or things would get weird.
|
||||
var stamDrainPerRateDive: Expression? = null
|
||||
private set
|
||||
var rideSounds: RideSoundSettingsList = RideSoundSettingsList()
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeResourceLocation(key)
|
||||
buffer.writeRidingStats(stats)
|
||||
rideSounds.encode(buffer)
|
||||
buffer.writeExpression(infiniteAltitude)
|
||||
buffer.writeExpression(infiniteStamina)
|
||||
buffer.writeExpression(glidespeedExpr)
|
||||
buffer.writeExpression(handlingExpr)
|
||||
buffer.writeExpression(horizontalPitchExpr)
|
||||
buffer.writeExpression(mouseInputMult)
|
||||
buffer.writeExpression(speedExpr)
|
||||
buffer.writeExpression(accelerationExpr)
|
||||
buffer.writeExpression(staminaExpr)
|
||||
buffer.writeExpression(timeToRollCorrect)
|
||||
buffer.writeNullableExpression(infiniteAltitude)
|
||||
buffer.writeNullableExpression(infiniteStamina)
|
||||
buffer.writeNullableExpression(glideSpeedExpr)
|
||||
buffer.writeNullableExpression(handlingExpr)
|
||||
buffer.writeNullableExpression(horizontalPitchExpr)
|
||||
buffer.writeNullableExpression(mouseInputMult)
|
||||
buffer.writeNullableExpression(speedExpr)
|
||||
buffer.writeNullableExpression(accelerationExpr)
|
||||
buffer.writeNullableExpression(staminaExpr)
|
||||
buffer.writeNullableExpression(stamDrainHorzMod)
|
||||
buffer.writeNullableExpression(stamDrainPercRateGlide)
|
||||
buffer.writeNullableExpression(stamDrainPerRateDive)
|
||||
buffer.writeNullableExpression(timeToRollCorrect)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
stats.putAll(buffer.readRidingStats())
|
||||
rideSounds = RideSoundSettingsList.decode(buffer)
|
||||
infiniteAltitude = buffer.readExpression()
|
||||
infiniteStamina = buffer.readExpression()
|
||||
glidespeedExpr = buffer.readExpression()
|
||||
handlingExpr = buffer.readExpression()
|
||||
horizontalPitchExpr = buffer.readExpression()
|
||||
mouseInputMult = buffer.readExpression()
|
||||
speedExpr = buffer.readExpression()
|
||||
accelerationExpr = buffer.readExpression()
|
||||
staminaExpr = buffer.readExpression()
|
||||
timeToRollCorrect = buffer.readExpression()
|
||||
infiniteAltitude = buffer.readNullableExpression()
|
||||
infiniteStamina = buffer.readNullableExpression()
|
||||
glideSpeedExpr = buffer.readNullableExpression()
|
||||
handlingExpr = buffer.readNullableExpression()
|
||||
horizontalPitchExpr = buffer.readNullableExpression()
|
||||
mouseInputMult = buffer.readNullableExpression()
|
||||
speedExpr = buffer.readNullableExpression()
|
||||
accelerationExpr = buffer.readNullableExpression()
|
||||
staminaExpr = buffer.readNullableExpression()
|
||||
stamDrainHorzMod = buffer.readNullableExpression()
|
||||
stamDrainPercRateGlide = buffer.readNullableExpression()
|
||||
stamDrainPerRateDive = buffer.readNullableExpression()
|
||||
timeToRollCorrect = buffer.readNullableExpression()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+16
-13
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.api.riding.behaviour.types.air
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonRideSettings
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourState
|
||||
@@ -37,6 +38,9 @@ class GliderBehaviour : RidingBehaviour<GliderSettings, RidingBehaviourState> {
|
||||
|
||||
override val key = KEY
|
||||
|
||||
val globalGlider: GliderSettings
|
||||
get() = CobblemonRideSettings.glider
|
||||
|
||||
override fun getRidingStyle(settings: GliderSettings, state: RidingBehaviourState): RidingStyle {
|
||||
return RidingStyle.AIR
|
||||
}
|
||||
@@ -53,7 +57,7 @@ class GliderBehaviour : RidingBehaviour<GliderSettings, RidingBehaviourState> {
|
||||
}
|
||||
|
||||
override fun speed(settings: GliderSettings, state: RidingBehaviourState, vehicle: PokemonEntity, driver: Player): Float {
|
||||
return vehicle.runtime.resolveFloat(settings.speed)
|
||||
return vehicle.runtime.resolveFloat(settings.speed ?: globalGlider.speed!!)
|
||||
}
|
||||
|
||||
override fun rotation(
|
||||
@@ -72,8 +76,8 @@ class GliderBehaviour : RidingBehaviour<GliderSettings, RidingBehaviourState> {
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
val xVector = if (vehicle.runtime.resolveBoolean(settings.canStrafe)) driver.xxa.toDouble() else 0.0
|
||||
val yVector = -vehicle.runtime.resolveDouble(settings.glideSpeed)
|
||||
val xVector = if (vehicle.runtime.resolveBoolean(settings.canStrafe ?: globalGlider.canStrafe!!)) driver.xxa.toDouble() else 0.0
|
||||
val yVector = -vehicle.runtime.resolveDouble(settings.glideSpeed ?: globalGlider.glideSpeed!!)
|
||||
val zVector = driver.zza.toDouble()
|
||||
return Vec3(xVector, yVector, zVector)
|
||||
}
|
||||
@@ -195,31 +199,30 @@ class GliderSettings : RidingBehaviourSettings {
|
||||
override val key = GliderBehaviour.KEY
|
||||
override val stats = mutableMapOf<RidingStat, IntRange>()
|
||||
|
||||
var glideSpeed: Expression = "0.1".asExpression()
|
||||
var glideSpeed: Expression? = null
|
||||
private set
|
||||
|
||||
var speed: Expression = "1.0".asExpression()
|
||||
var speed: Expression? = null
|
||||
private set
|
||||
|
||||
var canStrafe: Expression = "false".asExpression()
|
||||
var canStrafe: Expression? = null
|
||||
private set
|
||||
|
||||
var rideSounds: RideSoundSettingsList = RideSoundSettingsList()
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeResourceLocation(key)
|
||||
buffer.writeRidingStats(stats)
|
||||
rideSounds.encode(buffer)
|
||||
buffer.writeExpression(glideSpeed)
|
||||
buffer.writeExpression(speed)
|
||||
buffer.writeExpression(canStrafe)
|
||||
buffer.writeNullableExpression(glideSpeed)
|
||||
buffer.writeNullableExpression(speed)
|
||||
buffer.writeNullableExpression(canStrafe)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
stats.putAll(buffer.readRidingStats())
|
||||
rideSounds = RideSoundSettingsList.decode(buffer)
|
||||
glideSpeed = buffer.readExpression()
|
||||
speed = buffer.readExpression()
|
||||
canStrafe = buffer.readExpression()
|
||||
glideSpeed = buffer.readNullableExpression()
|
||||
speed = buffer.readNullableExpression()
|
||||
canStrafe = buffer.readNullableExpression()
|
||||
}
|
||||
}
|
||||
+27
-19
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.api.riding.behaviour.types.air
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonRideSettings
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviour
|
||||
@@ -21,7 +22,16 @@ import com.cobblemon.mod.common.api.riding.sound.RideSoundSettingsList
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.util.blockPositionsAsListRounded
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.readNullableExpression
|
||||
import com.cobblemon.mod.common.util.readRidingStats
|
||||
import com.cobblemon.mod.common.util.resolveDouble
|
||||
import com.cobblemon.mod.common.util.writeNullableExpression
|
||||
import com.cobblemon.mod.common.util.writeRidingStats
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sin
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.SmoothDouble
|
||||
@@ -30,9 +40,6 @@ import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sin
|
||||
|
||||
class HelicopterBehaviour : RidingBehaviour<HelicopterSettings, RidingBehaviourState> {
|
||||
companion object {
|
||||
@@ -41,6 +48,8 @@ class HelicopterBehaviour : RidingBehaviour<HelicopterSettings, RidingBehaviourS
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
val globalHelicopter: HelicopterSettings
|
||||
get() = CobblemonRideSettings.helicopter
|
||||
|
||||
override fun getRidingStyle(settings: HelicopterSettings, state: RidingBehaviourState): RidingStyle {
|
||||
return RidingStyle.AIR
|
||||
@@ -93,8 +102,8 @@ class HelicopterBehaviour : RidingBehaviour<HelicopterSettings, RidingBehaviourS
|
||||
val runtime = vehicle.runtime
|
||||
|
||||
//If the player is not modulating height then hover
|
||||
var yVel = if (driver.jumping) runtime.resolveDouble(settings.verticalVelocity)
|
||||
else if (driver.isShiftKeyDown) -runtime.resolveDouble(settings.verticalVelocity)
|
||||
var yVel = if (driver.jumping) runtime.resolveDouble(settings.verticalVelocity ?: globalHelicopter.verticalVelocity!!)
|
||||
else if (driver.isShiftKeyDown) -runtime.resolveDouble(settings.verticalVelocity ?: globalHelicopter.verticalVelocity!!)
|
||||
else (0.0)
|
||||
|
||||
yVel *= 0.25
|
||||
@@ -290,36 +299,35 @@ class HelicopterSettings : RidingBehaviourSettings {
|
||||
override val key = HelicopterBehaviour.KEY
|
||||
override val stats = mutableMapOf<RidingStat, IntRange>()
|
||||
|
||||
var gravity: Expression = "1.0".asExpression()
|
||||
var gravity: Expression? = null
|
||||
private set
|
||||
|
||||
var horizontalAcceleration: Expression = "0.1".asExpression()
|
||||
var horizontalAcceleration: Expression? = null
|
||||
private set
|
||||
|
||||
var verticalVelocity: Expression = "1.0".asExpression()
|
||||
var verticalVelocity: Expression? = null
|
||||
private set
|
||||
|
||||
var speed: Expression = "1.0".asExpression()
|
||||
var speed: Expression? = null
|
||||
private set
|
||||
|
||||
var rideSounds: RideSoundSettingsList = RideSoundSettingsList()
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeResourceLocation(key)
|
||||
buffer.writeRidingStats(stats)
|
||||
rideSounds.encode(buffer)
|
||||
buffer.writeExpression(gravity)
|
||||
buffer.writeExpression(horizontalAcceleration)
|
||||
buffer.writeExpression(verticalVelocity)
|
||||
buffer.writeExpression(speed)
|
||||
buffer.writeNullableExpression(gravity)
|
||||
buffer.writeNullableExpression(horizontalAcceleration)
|
||||
buffer.writeNullableExpression(verticalVelocity)
|
||||
buffer.writeNullableExpression(speed)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
stats.putAll(buffer.readRidingStats())
|
||||
rideSounds = RideSoundSettingsList.decode(buffer)
|
||||
gravity = buffer.readExpression()
|
||||
horizontalAcceleration = buffer.readExpression()
|
||||
verticalVelocity = buffer.readExpression()
|
||||
speed = buffer.readExpression()
|
||||
gravity = buffer.readNullableExpression()
|
||||
horizontalAcceleration = buffer.readNullableExpression()
|
||||
verticalVelocity = buffer.readNullableExpression()
|
||||
speed = buffer.readNullableExpression()
|
||||
}
|
||||
}
|
||||
+39
-26
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.api.riding.behaviour.types.air
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.CobblemonRideSettings
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.*
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseOption
|
||||
@@ -41,6 +42,8 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
val globalHover: HoverSettings
|
||||
get() = CobblemonRideSettings.hover
|
||||
|
||||
override fun getRidingStyle(settings: HoverSettings, state: HoverState): RidingStyle {
|
||||
return RidingStyle.AIR
|
||||
@@ -105,7 +108,7 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
|
||||
state: HoverState,
|
||||
vehicle: PokemonEntity,
|
||||
) {
|
||||
val heightLimit = vehicle.runtime.resolveDouble(settings.jumpExpr)
|
||||
val heightLimit = vehicle.runtime.resolveDouble(settings.jumpExpr ?: globalHover.jumpExpr!!)
|
||||
val pos = vehicle.position()
|
||||
val level = Minecraft.getInstance().player?.level() ?: return
|
||||
val hit = level.clip(
|
||||
@@ -126,9 +129,12 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
|
||||
state: HoverState,
|
||||
vehicle: PokemonEntity
|
||||
) {
|
||||
if (vehicle.runtime.resolveBoolean(settings.infiniteStamina ?: globalHover.infiniteStamina!!)) {
|
||||
return
|
||||
}
|
||||
val stam = state.stamina.get()
|
||||
val stamDrainRate = (1.0f / vehicle.runtime.resolveDouble(settings.staminaExpr)).toFloat() / 20.0f
|
||||
val stamReplenishRate = (1.0f / vehicle.runtime.resolveDouble(settings.stamReplenishTimeSeconds) ).toFloat() / 20.0f // 2 seconds to replenish a full bar of stamina
|
||||
val stamDrainRate = (1.0f / vehicle.runtime.resolveDouble(settings.staminaExpr ?: globalHover.staminaExpr!!)).toFloat() / 20.0f
|
||||
val stamReplenishRate = (1.0f / vehicle.runtime.resolveDouble(settings.stamReplenishTimeSeconds ?: globalHover.stamReplenishTimeSeconds!!) ).toFloat() / 20.0f // 2 seconds to replenish a full bar of stamina
|
||||
val newStam = if (state.tooHigh.get()) max(0.0f, stam - stamDrainRate) else min(1.0f,stam + stamReplenishRate)
|
||||
|
||||
state.stamina.set(newStam)
|
||||
@@ -175,8 +181,8 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Float {
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr) / 20.0
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr) / 20.0
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr ?: globalHover.speedExpr!!) / 20.0
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr ?: globalHover.handlingExpr!!) / 20.0
|
||||
val maxYawDiff = 90.0f
|
||||
|
||||
// Normalize the current rotation diff
|
||||
@@ -211,8 +217,8 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
|
||||
driver: Player
|
||||
): Vec3 {
|
||||
// Convert these to their tick values
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr) / 20.0
|
||||
val accel = topSpeed / (vehicle.runtime.resolveDouble(settings.accelerationExpr) * 20.0)
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr ?: globalHover.speedExpr!!) / 20.0
|
||||
val accel = topSpeed / (vehicle.runtime.resolveDouble(settings.accelerationExpr ?: globalHover.accelerationExpr!!) * 20.0)
|
||||
|
||||
var newVelocity = state.rideVelocity.get()
|
||||
|
||||
@@ -427,54 +433,61 @@ class HoverSettings : RidingBehaviourSettings {
|
||||
override val key = HoverBehaviour.KEY
|
||||
override val stats = mutableMapOf<RidingStat, IntRange>()
|
||||
|
||||
var canJump = "true".asExpression()
|
||||
var infiniteStamina: Expression? = null
|
||||
private set
|
||||
|
||||
var stamReplenishTimeSeconds = "2.0".asExpression()
|
||||
var canJump: Expression? = null
|
||||
private set
|
||||
|
||||
var stamReplenishTimeSeconds: Expression? = null
|
||||
private set
|
||||
|
||||
// Speed in block per second
|
||||
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 7.0, 1.0)".asExpression()
|
||||
var speedExpr: Expression? = null
|
||||
private set
|
||||
|
||||
// Acceleration in number of seconds to top speed
|
||||
var accelerationExpr: Expression =
|
||||
"q.get_ride_stats('ACCELERATION', 'AIR', 2.0, 8.0)".asExpression()
|
||||
var accelerationExpr: Expression? = null
|
||||
private set
|
||||
|
||||
// Amount of seconds between boosts
|
||||
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'AIR', 30.0, 2.0)".asExpression()
|
||||
var staminaExpr: Expression? = null
|
||||
private set
|
||||
|
||||
// Blocks before stamina drain
|
||||
var jumpExpr: Expression = "q.get_ride_stats('JUMP', 'AIR', 16.0, 2.0)".asExpression()
|
||||
var jumpExpr: Expression? = null
|
||||
private set
|
||||
|
||||
// Turn rate in degrees per second when stationary
|
||||
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 270.0, 45.0)".asExpression()
|
||||
var handlingExpr: Expression? = null
|
||||
private set
|
||||
|
||||
var rideSounds: RideSoundSettingsList = RideSoundSettingsList()
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeResourceLocation(key)
|
||||
buffer.writeRidingStats(stats)
|
||||
rideSounds.encode(buffer)
|
||||
buffer.writeExpression(speedExpr)
|
||||
buffer.writeExpression(accelerationExpr)
|
||||
buffer.writeExpression(staminaExpr)
|
||||
buffer.writeExpression(jumpExpr)
|
||||
buffer.writeExpression(handlingExpr)
|
||||
buffer.writeNullableExpression(infiniteStamina)
|
||||
buffer.writeNullableExpression(canJump)
|
||||
buffer.writeNullableExpression(stamReplenishTimeSeconds)
|
||||
buffer.writeNullableExpression(speedExpr)
|
||||
buffer.writeNullableExpression(accelerationExpr)
|
||||
buffer.writeNullableExpression(staminaExpr)
|
||||
buffer.writeNullableExpression(jumpExpr)
|
||||
buffer.writeNullableExpression(handlingExpr)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
stats.putAll(buffer.readRidingStats())
|
||||
rideSounds = RideSoundSettingsList.decode(buffer)
|
||||
speedExpr = buffer.readExpression()
|
||||
accelerationExpr = buffer.readExpression()
|
||||
staminaExpr = buffer.readExpression()
|
||||
jumpExpr = buffer.readExpression()
|
||||
handlingExpr = buffer.readExpression()
|
||||
infiniteStamina = buffer.readNullableExpression()
|
||||
canJump = buffer.readNullableExpression()
|
||||
stamReplenishTimeSeconds = buffer.readNullableExpression()
|
||||
speedExpr = buffer.readNullableExpression()
|
||||
accelerationExpr = buffer.readNullableExpression()
|
||||
staminaExpr = buffer.readNullableExpression()
|
||||
jumpExpr = buffer.readNullableExpression()
|
||||
handlingExpr = buffer.readNullableExpression()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+63
-51
@@ -11,23 +11,35 @@ package com.cobblemon.mod.common.api.riding.behaviour.types.air
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.MoLangMath.lerp
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonRideSettings
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.*
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.land.HorseSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.land.HorseState
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourState
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.Side
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.ridingState
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseOption
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import com.cobblemon.mod.common.api.riding.sound.RideSoundSettingsList
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.config.CobblemonConfig
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.blockPositionsAsListRounded
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import com.cobblemon.mod.common.util.readNullableExpression
|
||||
import com.cobblemon.mod.common.util.readRidingStats
|
||||
import com.cobblemon.mod.common.util.resolveDouble
|
||||
import com.cobblemon.mod.common.util.toVec3d
|
||||
import com.cobblemon.mod.common.util.writeNullableExpression
|
||||
import com.cobblemon.mod.common.util.writeRidingStats
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.SmoothDouble
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
@@ -36,7 +48,6 @@ import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import org.joml.Vector3f
|
||||
import kotlin.math.*
|
||||
|
||||
class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
companion object {
|
||||
@@ -49,6 +60,9 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
return RidingStyle.AIR
|
||||
}
|
||||
|
||||
val globalJet: JetSettings
|
||||
get() = CobblemonRideSettings.jet
|
||||
|
||||
val poseProvider = PoseProvider<JetSettings, JetState>(PoseType.HOVER)
|
||||
.with(PoseOption(PoseType.FLY) { _, state, _ -> state.rideVelocity.get().z > 0.1 })
|
||||
|
||||
@@ -113,7 +127,7 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
) {
|
||||
val stam = state.stamina.get()
|
||||
var newStam = stam
|
||||
val stamDrainRate = (1.0f / vehicle.runtime.resolveDouble(settings.staminaExpr)).toFloat() / 20.0f
|
||||
val stamDrainRate = (1.0f / vehicle.runtime.resolveDouble(settings.staminaExpr ?: globalJet.staminaExpr!!)).toFloat() / 20.0f
|
||||
|
||||
if (state.boosting.get()) {
|
||||
newStam = max(0.0f,stam - stamDrainRate * 1.5f)
|
||||
@@ -178,12 +192,12 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
) {
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr) / 20.0
|
||||
val accel = topSpeed / (vehicle.runtime.resolveDouble(settings.accelerationExpr) * 20.0)
|
||||
val deccel = vehicle.runtime.resolveDouble(settings.deccelRate)//0.005
|
||||
val minSpeed = topSpeed * vehicle.runtime.resolveDouble(settings.minSpeedFactor)
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr ?: globalJet.speedExpr!!) / 20.0
|
||||
val accel = topSpeed / (vehicle.runtime.resolveDouble(settings.accelerationExpr ?: globalJet.accelerationExpr!!) * 20.0)
|
||||
val deccel = vehicle.runtime.resolveDouble(settings.deccelRate ?: globalJet.deccelRate!!)//0.005
|
||||
val minSpeed = topSpeed * vehicle.runtime.resolveDouble(settings.minSpeedFactor ?: globalJet.minSpeedFactor!!)
|
||||
val speed = state.rideVelocity.get().z
|
||||
val boostMult = vehicle.runtime.resolveDouble(settings.jumpExpr)
|
||||
val boostMult = vehicle.runtime.resolveDouble(settings.jumpExpr ?: globalJet.jumpExpr!!)
|
||||
|
||||
val boostTopSpeed = topSpeed * boostMult
|
||||
val boostAccel = accel * boostMult
|
||||
@@ -258,7 +272,7 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
val cappedDeltaTime = min(deltaTime, 0.2)
|
||||
|
||||
//Get handling in degrees per second
|
||||
val yawRotRate = vehicle.runtime.resolveDouble(settings.handlingYawExpr)
|
||||
val yawRotRate = vehicle.runtime.resolveDouble(settings.handlingYawExpr ?: globalJet.handlingYawExpr!!)
|
||||
|
||||
//Base the change off of deltatime.
|
||||
var handlingYaw = yawRotRate * (cappedDeltaTime)
|
||||
@@ -339,7 +353,7 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
|
||||
//Get handling in degrees per second
|
||||
val handlingDebuff = if(state.stamina.get() == 0.0f) 0.5 else 1.0
|
||||
var handling = vehicle.runtime.resolveDouble(settings.handlingExpr) * handlingDebuff
|
||||
var handling = vehicle.runtime.resolveDouble(settings.handlingExpr ?: globalJet.handlingExpr!!) * handlingDebuff
|
||||
//convert it to delta time
|
||||
handling *= (cappedDeltaTime)
|
||||
|
||||
@@ -393,7 +407,7 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
|
||||
//Get handling in degrees per second
|
||||
val handlingDebuff = if(state.stamina.get() == 0.0f) 0.5 else 1.0
|
||||
var handling = vehicle.runtime.resolveDouble(settings.handlingExpr) * handlingDebuff
|
||||
var handling = vehicle.runtime.resolveDouble(settings.handlingExpr ?: globalJet.handlingExpr!!) * handlingDebuff
|
||||
|
||||
//convert it to delta time
|
||||
handling *= (cappedDeltaTime)
|
||||
@@ -547,72 +561,70 @@ class JetSettings : RidingBehaviourSettings {
|
||||
override val key = JetBehaviour.KEY
|
||||
override val stats = mutableMapOf<RidingStat, IntRange>()
|
||||
|
||||
var gravity: Expression = "0".asExpression()
|
||||
var gravity: Expression? = null
|
||||
private set
|
||||
|
||||
var deccelRate: Expression = "0.005".asExpression()
|
||||
var deccelRate: Expression? = null
|
||||
private set
|
||||
|
||||
// Mult to top speed in order to derive minSpeed
|
||||
var minSpeedFactor: Expression = "0.25".asExpression()
|
||||
var minSpeedFactor: Expression? = null
|
||||
private set
|
||||
|
||||
var handlingYawExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 50.0, 25.0)".asExpression()
|
||||
var handlingYawExpr: Expression? = null
|
||||
private set
|
||||
|
||||
// Make configurable by json
|
||||
var infiniteStamina: Expression = "false".asExpression()
|
||||
var infiniteStamina: Expression? = null
|
||||
private set
|
||||
|
||||
// Boost power. Mult for top speed and accel while boosting
|
||||
var jumpExpr: Expression = "q.get_ride_stats('JUMP', 'AIR', 2.0, 1.0)".asExpression()
|
||||
var jumpExpr: Expression? = null
|
||||
private set
|
||||
|
||||
// Turn rate in degrees per second
|
||||
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 60.0, 10.0)".asExpression()
|
||||
var handlingExpr: Expression? = null
|
||||
private set
|
||||
// Top Speed in blocks per second
|
||||
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 24.0, 4.0)".asExpression()
|
||||
var speedExpr: Expression? = null
|
||||
private set
|
||||
// Seconds to get to top speed
|
||||
var accelerationExpr: Expression =
|
||||
"q.get_ride_stats('ACCELERATION', 'AIR', 2.0, 8.0)".asExpression()
|
||||
var accelerationExpr: Expression? = null
|
||||
private set
|
||||
// Time in seconds to drain full bar of stamina flying
|
||||
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'AIR', 60.0, 4.0)".asExpression()
|
||||
var staminaExpr: Expression? = null
|
||||
private set
|
||||
|
||||
var rideSounds: RideSoundSettingsList = RideSoundSettingsList()
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeResourceLocation(key)
|
||||
buffer.writeRidingStats(stats)
|
||||
rideSounds.encode(buffer)
|
||||
buffer.writeExpression(gravity)
|
||||
buffer.writeExpression(deccelRate)
|
||||
buffer.writeExpression(minSpeedFactor)
|
||||
buffer.writeExpression(handlingYawExpr)
|
||||
buffer.writeExpression(infiniteStamina)
|
||||
buffer.writeExpression(jumpExpr)
|
||||
buffer.writeExpression(handlingExpr)
|
||||
buffer.writeExpression(speedExpr)
|
||||
buffer.writeExpression(accelerationExpr)
|
||||
buffer.writeExpression(staminaExpr)
|
||||
buffer.writeNullableExpression(gravity)
|
||||
buffer.writeNullableExpression(deccelRate)
|
||||
buffer.writeNullableExpression(minSpeedFactor)
|
||||
buffer.writeNullableExpression(handlingYawExpr)
|
||||
buffer.writeNullableExpression(infiniteStamina)
|
||||
buffer.writeNullableExpression(jumpExpr)
|
||||
buffer.writeNullableExpression(handlingExpr)
|
||||
buffer.writeNullableExpression(speedExpr)
|
||||
buffer.writeNullableExpression(accelerationExpr)
|
||||
buffer.writeNullableExpression(staminaExpr)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
stats.putAll(buffer.readRidingStats())
|
||||
rideSounds = RideSoundSettingsList.decode(buffer)
|
||||
gravity = buffer.readExpression()
|
||||
deccelRate = buffer.readExpression()
|
||||
minSpeedFactor = buffer.readExpression()
|
||||
handlingYawExpr = buffer.readExpression()
|
||||
infiniteStamina = buffer.readExpression()
|
||||
jumpExpr = buffer.readExpression()
|
||||
handlingExpr = buffer.readExpression()
|
||||
speedExpr = buffer.readExpression()
|
||||
accelerationExpr = buffer.readExpression()
|
||||
staminaExpr = buffer.readExpression()
|
||||
gravity = buffer.readNullableExpression()
|
||||
deccelRate = buffer.readNullableExpression()
|
||||
minSpeedFactor = buffer.readNullableExpression()
|
||||
handlingYawExpr = buffer.readNullableExpression()
|
||||
infiniteStamina = buffer.readNullableExpression()
|
||||
jumpExpr = buffer.readNullableExpression()
|
||||
handlingExpr = buffer.readNullableExpression()
|
||||
speedExpr = buffer.readNullableExpression()
|
||||
accelerationExpr = buffer.readNullableExpression()
|
||||
staminaExpr = buffer.readNullableExpression()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+46
-32
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.api.riding.behaviour.types.air
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.MoLangMath.lerp
|
||||
import com.cobblemon.mod.common.CobblemonRideSettings
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.*
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseOption
|
||||
@@ -40,6 +41,8 @@ class RocketBehaviour : RidingBehaviour<RocketSettings, RocketState> {
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
val globalRocket: RocketSettings
|
||||
get() = CobblemonRideSettings.rocket
|
||||
|
||||
override fun getRidingStyle(settings: RocketSettings, state: RocketState): RidingStyle {
|
||||
return RidingStyle.AIR
|
||||
@@ -84,7 +87,7 @@ class RocketBehaviour : RidingBehaviour<RocketSettings, RocketState> {
|
||||
driver: Player
|
||||
): Float {
|
||||
// Use this as a "tick" function and check to see if the driver is "boosting"
|
||||
if(vehicle.level().isClientSide) {
|
||||
if (vehicle.level().isClientSide) {
|
||||
handleBoosting(settings, state, vehicle, driver)
|
||||
tickStamina(settings, state, vehicle, driver)
|
||||
}
|
||||
@@ -124,10 +127,14 @@ class RocketBehaviour : RidingBehaviour<RocketSettings, RocketState> {
|
||||
) {
|
||||
val stam = state.stamina.get()
|
||||
|
||||
if (vehicle.runtime.resolveBoolean(settings.infiniteStamina ?: globalRocket.infiniteStamina!!)) {
|
||||
return
|
||||
}
|
||||
|
||||
// Grab the boost time in seconds and convert to ticks. Then calculate the drain rate as inversely
|
||||
// proportional to the number of ticks of boost thus making a full boost take x ticks
|
||||
// in short: "Stamina drains slower at higher values and also replenishes slower"
|
||||
val boostTime = vehicle.runtime.resolveDouble(settings.staminaExpr) * 20.0f
|
||||
val boostTime = vehicle.runtime.resolveDouble(settings.staminaExpr ?: globalRocket.staminaExpr!!) * 20.0f
|
||||
val stamDrainRate = (1.0f / boostTime).toFloat()
|
||||
|
||||
val newStam = if(state.boosting.get() || driver.jumping) max(0.0f,stam - stamDrainRate) else stam
|
||||
@@ -179,13 +186,13 @@ class RocketBehaviour : RidingBehaviour<RocketSettings, RocketState> {
|
||||
|
||||
var newMomentum = state.turnMomentum.get().toDouble()
|
||||
// Degrees per tick
|
||||
val maxTurnMomentum = vehicle.runtime.resolveDouble(settings.maxTurnRate) / 20.0f
|
||||
val maxTurnMomentum = vehicle.runtime.resolveDouble(settings.maxTurnRate ?: globalRocket.maxTurnRate!!) / 20.0f
|
||||
// Turn rate increase per tick. Based off number of seconds to get to max turn rate
|
||||
val turningAcceleration = maxTurnMomentum / (vehicle.runtime.resolveDouble(settings.handlingExpr) * 20.0f)
|
||||
val turningAcceleration = maxTurnMomentum / (vehicle.runtime.resolveDouble(settings.handlingExpr ?: globalRocket.handlingExpr!!) * 20.0f)
|
||||
val turnInput = (driver.xxa *-1.0f) * turningAcceleration
|
||||
|
||||
// Base boost stats off of normal turning stats
|
||||
val boostHandlingMod = vehicle.runtime.resolveDouble(settings.boostHandlingMod)
|
||||
val boostHandlingMod = vehicle.runtime.resolveDouble(settings.boostHandlingMod ?: globalRocket.boostHandlingMod!!)
|
||||
val boostMaxTurnMomentum = maxTurnMomentum * boostHandlingMod
|
||||
val boostTurnInput = turnInput * boostHandlingMod
|
||||
|
||||
@@ -230,9 +237,9 @@ class RocketBehaviour : RidingBehaviour<RocketSettings, RocketState> {
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Vec3 {
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val accel = vehicle.runtime.resolveDouble(settings.accelerationExpr)
|
||||
val jump = vehicle.runtime.resolveDouble(settings.jumpExpr)
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr ?: globalRocket.speedExpr!!)
|
||||
val accel = vehicle.runtime.resolveDouble(settings.accelerationExpr ?: globalRocket.accelerationExpr!!)
|
||||
val jump = vehicle.runtime.resolveDouble(settings.jumpExpr ?: globalRocket.jumpExpr!!)
|
||||
|
||||
var newVelocity = vehicle.deltaMovement
|
||||
|
||||
@@ -256,7 +263,7 @@ class RocketBehaviour : RidingBehaviour<RocketSettings, RocketState> {
|
||||
(newVelocity.z + (accel * forwardInput.toDouble())))
|
||||
|
||||
} else if ((state.boosting.get())) {
|
||||
val boostMod = vehicle.runtime.resolveDouble(settings.boostSpeedMod)
|
||||
val boostMod = vehicle.runtime.resolveDouble(settings.boostSpeedMod ?: globalRocket.boostSpeedMod!!)
|
||||
val boostSpeed = topSpeed * boostMod
|
||||
val boostAccel = if(newVelocity.length() < boostSpeed) accel * (boostMod/1.5) else 0.0
|
||||
val forwardInput = 1.0f
|
||||
@@ -398,8 +405,8 @@ class RocketBehaviour : RidingBehaviour<RocketSettings, RocketState> {
|
||||
driver: Player
|
||||
): Float {
|
||||
if (state.boosting.get()) {
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val boostMod = vehicle.runtime.resolveDouble(settings.boostSpeedMod)
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr ?: globalRocket.speedExpr!!)
|
||||
val boostMod = vehicle.runtime.resolveDouble(settings.boostSpeedMod ?: globalRocket.boostSpeedMod!!)
|
||||
val normalizedBoostSpeed = RidingBehaviour.scaleToRange(state.rideVelocity.get().length(), topSpeed, topSpeed * boostMod)
|
||||
return 1.0f + normalizedBoostSpeed.pow(2).toFloat() * 0.2f
|
||||
} else {
|
||||
@@ -499,60 +506,67 @@ class RocketSettings : RidingBehaviourSettings {
|
||||
override val key = RocketBehaviour.KEY
|
||||
override val stats = mutableMapOf<RidingStat, IntRange>()
|
||||
|
||||
var infiniteStamina: Expression? = null
|
||||
private set
|
||||
// Boost multiplier for speed
|
||||
var boostSpeedMod: Expression = "5.0".asExpression()
|
||||
var boostSpeedMod: Expression? = null
|
||||
private set
|
||||
|
||||
// Boost multiplier for handling
|
||||
var boostHandlingMod: Expression = "0.3".asExpression()
|
||||
var boostHandlingMod: Expression? = null
|
||||
private set
|
||||
|
||||
// Max turn rate in degrees per second
|
||||
var maxTurnRate: Expression = "100.0".asExpression()
|
||||
var maxTurnRate: Expression? = null
|
||||
private set
|
||||
|
||||
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 1.2, 0.6)".asExpression()
|
||||
var speedExpr: Expression? = null
|
||||
private set
|
||||
|
||||
// Max accel is a whole 1.0 in 1 second. The conversion in the function below is to convert seconds to ticks
|
||||
var accelerationExpr: Expression =
|
||||
"q.get_ride_stats('ACCELERATION', 'AIR', (1.0 / (20.0 * 1.5)), (1.0 / (20.0 * 3.0))) * 0.5".asExpression()
|
||||
var accelerationExpr: Expression? = null
|
||||
private set
|
||||
|
||||
// air time in seconds
|
||||
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'AIR', 20.0, 10.0)".asExpression()
|
||||
var staminaExpr: Expression? = null
|
||||
private set
|
||||
|
||||
var jumpExpr: Expression = "q.get_ride_stats('JUMP', 'AIR', 2.0, 1.0)".asExpression()
|
||||
var jumpExpr: Expression? = null
|
||||
private set
|
||||
|
||||
// How long it takes to get to max turn rate from rest (in seconds)
|
||||
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 0.5, 3.0)".asExpression()
|
||||
var handlingExpr: Expression? = null
|
||||
private set
|
||||
|
||||
var rideSounds: RideSoundSettingsList = RideSoundSettingsList()
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeResourceLocation(key)
|
||||
buffer.writeRidingStats(stats)
|
||||
rideSounds.encode(buffer)
|
||||
buffer.writeExpression(speedExpr)
|
||||
buffer.writeExpression(accelerationExpr)
|
||||
buffer.writeExpression(staminaExpr)
|
||||
buffer.writeExpression(jumpExpr)
|
||||
buffer.writeExpression(handlingExpr)
|
||||
buffer.writeNullableExpression(infiniteStamina)
|
||||
buffer.writeNullableExpression(boostSpeedMod)
|
||||
buffer.writeNullableExpression(boostHandlingMod)
|
||||
buffer.writeNullableExpression(maxTurnRate)
|
||||
buffer.writeNullableExpression(speedExpr)
|
||||
buffer.writeNullableExpression(accelerationExpr)
|
||||
buffer.writeNullableExpression(staminaExpr)
|
||||
buffer.writeNullableExpression(jumpExpr)
|
||||
buffer.writeNullableExpression(handlingExpr)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
stats.putAll(buffer.readRidingStats())
|
||||
rideSounds = RideSoundSettingsList.decode(buffer)
|
||||
speedExpr = buffer.readExpression()
|
||||
accelerationExpr = buffer.readExpression()
|
||||
staminaExpr = buffer.readExpression()
|
||||
jumpExpr = buffer.readExpression()
|
||||
handlingExpr = buffer.readExpression()
|
||||
infiniteStamina = buffer.readNullableExpression()
|
||||
boostSpeedMod = buffer.readNullableExpression()
|
||||
boostHandlingMod = buffer.readNullableExpression()
|
||||
maxTurnRate = buffer.readNullableExpression()
|
||||
speedExpr = buffer.readNullableExpression()
|
||||
accelerationExpr = buffer.readNullableExpression()
|
||||
staminaExpr = buffer.readNullableExpression()
|
||||
jumpExpr = buffer.readNullableExpression()
|
||||
handlingExpr = buffer.readNullableExpression()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class RocketState : RidingBehaviourState() {
|
||||
|
||||
+2
-1
@@ -387,9 +387,10 @@ open class CompositeSettings : RidingBehaviourSettings {
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeRidingStats(stats)
|
||||
buffer.writeResourceLocation(key)
|
||||
buffer.writeResourceLocation(transitionStrategy)
|
||||
buffer.writeResourceLocation(defaultBehaviour.key)
|
||||
defaultBehaviour.encode(buffer)
|
||||
buffer.writeResourceLocation(alternateBehaviour.key)
|
||||
alternateBehaviour.encode(buffer)
|
||||
}
|
||||
|
||||
|
||||
+4
@@ -41,6 +41,10 @@ interface CompositeRidingStrategy<T : CompositeSettings> {
|
||||
toState: RidingBehaviourState,
|
||||
toSettings: RidingBehaviourSettings
|
||||
) {
|
||||
if (vehicle.level().isClientSide) {
|
||||
val fromSettings = if (settings.defaultBehaviour == toSettings) settings.alternateBehaviour else settings.defaultBehaviour
|
||||
|
||||
}
|
||||
toState.stamina.set(fromState.stamina.get())
|
||||
toState.rideVelocity.set(fromState.rideVelocity.get())
|
||||
fromState.reset()
|
||||
|
||||
+70
-39
@@ -9,16 +9,34 @@
|
||||
package com.cobblemon.mod.common.api.riding.behaviour.types.land
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.CobblemonRideSettings
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.*
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourState
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.Side
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.ridingState
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseOption
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.api.riding.sound.RideSoundSettingsList
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import com.cobblemon.mod.common.util.blockPositionsAsListRounded
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.readNullableExpression
|
||||
import com.cobblemon.mod.common.util.readRidingStats
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.resolveDouble
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
import com.cobblemon.mod.common.util.writeNullableExpression
|
||||
import com.cobblemon.mod.common.util.writeRidingStats
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sign
|
||||
import kotlin.math.sqrt
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
@@ -31,8 +49,6 @@ import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import org.joml.Matrix3f
|
||||
import kotlin.math.*
|
||||
|
||||
class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
|
||||
companion object {
|
||||
@@ -40,6 +56,8 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
val globalHorse: HorseSettings
|
||||
get() = CobblemonRideSettings.horse
|
||||
|
||||
override fun getRidingStyle(settings: HorseSettings, state: HorseState): RidingStyle {
|
||||
return RidingStyle.LAND
|
||||
@@ -134,8 +152,13 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
|
||||
vehicle: PokemonEntity,
|
||||
) {
|
||||
val stam = state.stamina.get()
|
||||
|
||||
if (vehicle.runtime.resolveBoolean(settings.infiniteStamina ?: globalHorse.infiniteStamina!!)) {
|
||||
return
|
||||
}
|
||||
|
||||
var newStam = stam
|
||||
val stamDrainRate = (1.0f / vehicle.runtime.resolveDouble(settings.staminaExpr)).toFloat() / 20.0f
|
||||
val stamDrainRate = (1.0f / vehicle.runtime.resolveDouble(settings.staminaExpr ?: globalHorse.staminaExpr!!)).toFloat() / 20.0f
|
||||
|
||||
if (state.sprinting.get()) {
|
||||
newStam = max(0.0f,stam - stamDrainRate)
|
||||
@@ -185,10 +208,10 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Float {
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr)
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr ?: globalHorse.speedExpr!!)
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr ?: globalHorse.handlingExpr!!)
|
||||
val walkHandlingBoost = 5
|
||||
val maxYawDiff = vehicle.runtime.resolveFloat(settings.lookYawLimit)
|
||||
val maxYawDiff = vehicle.runtime.resolveFloat(settings.lookYawLimit ?: globalHorse.lookYawLimit!!)
|
||||
|
||||
// Normalize the current rotation diff
|
||||
val rotDiff = Mth.wrapDegrees(driver.yRot - vehicle.yRot).coerceIn(-maxYawDiff,maxYawDiff)
|
||||
@@ -232,13 +255,13 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Vec3 {
|
||||
val canSprint = vehicle.runtime.resolveBoolean(settings.canSprint)
|
||||
val canJump = vehicle.runtime.resolveBoolean(settings.canJump)
|
||||
val jumpForce = vehicle.runtime.resolveDouble(settings.jumpExpr) * 0.75
|
||||
val rideTopSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val canSprint = vehicle.runtime.resolveBoolean(settings.canSprint ?: globalHorse.canSprint!!)
|
||||
val canJump = vehicle.runtime.resolveBoolean(settings.canJump ?: globalHorse.canJump!!)
|
||||
val jumpForce = vehicle.runtime.resolveDouble(settings.jumpExpr ?: globalHorse.jumpExpr!!) * 0.75
|
||||
val rideTopSpeed = vehicle.runtime.resolveDouble(settings.speedExpr ?: globalHorse.speedExpr!!)
|
||||
val walkSpeed = getWalkSpeed(vehicle)
|
||||
val topSpeed = if(canSprint && state.sprinting.get()) rideTopSpeed else walkSpeed
|
||||
val accel = topSpeed / (vehicle.runtime.resolveDouble(settings.accelerationExpr) * 20.0)
|
||||
val accel = topSpeed / (vehicle.runtime.resolveDouble(settings.accelerationExpr ?: globalHorse.accelerationExpr!!) * 20.0)
|
||||
var activeInput = false
|
||||
|
||||
/******************************************************
|
||||
@@ -271,7 +294,7 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
|
||||
|
||||
// If on a tight turn then do not speed up past half of top speed in order to turn quicker
|
||||
// Also determine how fast to be slowing down based on how far turned you are
|
||||
val lookYawLimit = vehicle.runtime.resolveFloat(settings.lookYawLimit)
|
||||
val lookYawLimit = vehicle.runtime.resolveFloat(settings.lookYawLimit ?: globalHorse.lookYawLimit!!)
|
||||
val percOfMaxTurnSpeed = abs(Mth.wrapDegrees(driver.yRot - vehicle.yRot) / lookYawLimit) * 100.0f
|
||||
val turnPercThresh = 0.0f
|
||||
val s = min(((percOfMaxTurnSpeed - turnPercThresh) / (100.0f - turnPercThresh)).pow(1),1.0f)
|
||||
@@ -513,59 +536,67 @@ class HorseSettings : RidingBehaviourSettings {
|
||||
override val key = HorseBehaviour.KEY
|
||||
override val stats = mutableMapOf<RidingStat, IntRange>()
|
||||
|
||||
var canJump = "true".asExpression()
|
||||
var infiniteStamina: Expression? = null
|
||||
private set
|
||||
var canJump: Expression? = null
|
||||
private set
|
||||
|
||||
var canSprint = "true".asExpression()
|
||||
var canSprint: Expression? = null
|
||||
private set
|
||||
|
||||
var lookYawLimit = "90.0f".asExpression()
|
||||
var lookYawLimit: Expression? = null
|
||||
private set
|
||||
|
||||
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'LAND', 1.2, 0.1)".asExpression()
|
||||
var speedExpr: Expression? = null
|
||||
private set
|
||||
|
||||
// Max accel is a whole 1.0 in 1 second. The conversion in the function below is to convert seconds to ticks
|
||||
var accelerationExpr: Expression =
|
||||
"q.get_ride_stats('ACCELERATION', 'LAND', 0.1, 12.0)".asExpression()
|
||||
var accelerationExpr: Expression? = null
|
||||
private set
|
||||
|
||||
// Between 30 seconds and 10 seconds at the lowest when at full speed.
|
||||
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'LAND', 60.0, 4.0)".asExpression()
|
||||
var staminaExpr: Expression? = null
|
||||
private set
|
||||
|
||||
//Between a one block jump and a six block jump
|
||||
var jumpExpr: Expression = "q.get_ride_stats('JUMP', 'LAND', 1.6, 0.2)".asExpression()
|
||||
var jumpExpr: Expression? = null
|
||||
private set
|
||||
|
||||
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'LAND', 90.0, 30.0)".asExpression()
|
||||
var handlingExpr: Expression? = null
|
||||
private set
|
||||
|
||||
var rideSounds: RideSoundSettingsList = RideSoundSettingsList()
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeResourceLocation(key)
|
||||
buffer.writeRidingStats(stats)
|
||||
rideSounds.encode(buffer)
|
||||
buffer.writeExpression(speedExpr)
|
||||
buffer.writeExpression(accelerationExpr)
|
||||
buffer.writeExpression(staminaExpr)
|
||||
buffer.writeExpression(jumpExpr)
|
||||
buffer.writeExpression(handlingExpr)
|
||||
buffer.writeExpression(canJump)
|
||||
buffer.writeExpression(canSprint)
|
||||
buffer.writeNullableExpression(infiniteStamina)
|
||||
buffer.writeNullableExpression(canJump)
|
||||
buffer.writeNullableExpression(canSprint)
|
||||
buffer.writeNullableExpression(lookYawLimit)
|
||||
buffer.writeNullableExpression(speedExpr)
|
||||
buffer.writeNullableExpression(accelerationExpr)
|
||||
buffer.writeNullableExpression(staminaExpr)
|
||||
buffer.writeNullableExpression(jumpExpr)
|
||||
buffer.writeNullableExpression(handlingExpr)
|
||||
buffer.writeNullableExpression(canJump)
|
||||
buffer.writeNullableExpression(canSprint)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
stats.putAll(buffer.readRidingStats())
|
||||
rideSounds = RideSoundSettingsList.decode(buffer)
|
||||
speedExpr = buffer.readExpression()
|
||||
accelerationExpr = buffer.readExpression()
|
||||
staminaExpr = buffer.readExpression()
|
||||
jumpExpr = buffer.readExpression()
|
||||
handlingExpr = buffer.readExpression()
|
||||
canJump = buffer.readExpression()
|
||||
canSprint = buffer.readExpression()
|
||||
infiniteStamina = buffer.readNullableExpression()
|
||||
canJump = buffer.readNullableExpression()
|
||||
canSprint = buffer.readNullableExpression()
|
||||
lookYawLimit = buffer.readNullableExpression()
|
||||
speedExpr = buffer.readNullableExpression()
|
||||
accelerationExpr = buffer.readNullableExpression()
|
||||
staminaExpr = buffer.readNullableExpression()
|
||||
jumpExpr = buffer.readNullableExpression()
|
||||
handlingExpr = buffer.readNullableExpression()
|
||||
canJump = buffer.readNullableExpression()
|
||||
canSprint = buffer.readNullableExpression()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+54
-28
@@ -10,18 +10,36 @@ package com.cobblemon.mod.common.api.riding.behaviour.types.land
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.MoLangMath.lerp
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonRideSettings
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.*
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourState
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.Side
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.SidedRidingState
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.ridingState
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseOption
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.api.riding.sound.RideSoundSettingsList
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.util.blockPositionsAsListRounded
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import com.cobblemon.mod.common.util.readNullableExpression
|
||||
import com.cobblemon.mod.common.util.readRidingStats
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.resolveDouble
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
import com.cobblemon.mod.common.util.writeNullableExpression
|
||||
import com.cobblemon.mod.common.util.writeRidingStats
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sign
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
@@ -32,12 +50,6 @@ import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import org.joml.Matrix3f
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sign
|
||||
|
||||
class MinekartBehaviour : RidingBehaviour<MinekartSettings, MinekartState> {
|
||||
companion object {
|
||||
@@ -45,6 +57,8 @@ class MinekartBehaviour : RidingBehaviour<MinekartSettings, MinekartState> {
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
val globalMinekart: MinekartSettings
|
||||
get() = CobblemonRideSettings.minekart
|
||||
|
||||
override fun getRidingStyle(settings: MinekartSettings, state: MinekartState): RidingStyle {
|
||||
return RidingStyle.LAND
|
||||
@@ -84,7 +98,7 @@ class MinekartBehaviour : RidingBehaviour<MinekartSettings, MinekartState> {
|
||||
driver: Player
|
||||
): Float {
|
||||
|
||||
val boostMax = vehicle.runtime.resolveFloat(settings.boostLimit)
|
||||
val boostMax = vehicle.runtime.resolveFloat(settings.boostLimit ?: globalMinekart.boostLimit!!)
|
||||
//TODO: should this be by how much turn has accumulated or simply time turning... or both?
|
||||
val boostPerSecond = 20.0f
|
||||
val boostLoss = 40.0f
|
||||
@@ -142,8 +156,8 @@ class MinekartBehaviour : RidingBehaviour<MinekartSettings, MinekartState> {
|
||||
var newMomentum = state.turnMomentum.get().toDouble()
|
||||
|
||||
//TODO: maybe tie this to max turnspeeds rather than the turn acceleration
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val turningAcceleration = (vehicle.runtime.resolveDouble(settings.handlingExpr) * 1.5 / 20.0f) / 20.0f * 4.0
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr ?: globalMinekart.speedExpr!!)
|
||||
val turningAcceleration = (vehicle.runtime.resolveDouble(settings.handlingExpr ?: globalMinekart.handlingExpr!!) * 1.5 / 20.0f) / 20.0f * 4.0
|
||||
val turnInput = (driver.xxa *-1.0f) * turningAcceleration
|
||||
val driftInput = turnInput * 0.25f
|
||||
|
||||
@@ -202,9 +216,9 @@ class MinekartBehaviour : RidingBehaviour<MinekartSettings, MinekartState> {
|
||||
): Vec3 {
|
||||
|
||||
// Check to see if the ride should be walking or sprinting
|
||||
val rideTopSpeed = vehicle.runtime.resolveDouble(settings.speedExpr) * 0.6 * 2.0
|
||||
val rideTopSpeed = vehicle.runtime.resolveDouble(settings.speedExpr ?: globalMinekart.speedExpr!!) * 0.6 * 2.0
|
||||
val topSpeed = if (state.drifting.get()) rideTopSpeed * 0.7 else rideTopSpeed
|
||||
val accel = vehicle.runtime.resolveDouble(settings.accelerationExpr) * 0.3 * 3 * 2.0
|
||||
val accel = vehicle.runtime.resolveDouble(settings.accelerationExpr ?: globalMinekart.accelerationExpr!!) * 0.3 * 3 * 2.0
|
||||
val driftAngle = 20.0f
|
||||
|
||||
//Align the direction of this vector with the vehicles current heading.
|
||||
@@ -327,7 +341,7 @@ class MinekartBehaviour : RidingBehaviour<MinekartSettings, MinekartState> {
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return vehicle.runtime.resolveBoolean(settings.canJump)
|
||||
return vehicle.runtime.resolveBoolean(settings.canJump ?: globalMinekart.canJump!!)
|
||||
}
|
||||
|
||||
override fun setRideBar(
|
||||
@@ -447,45 +461,57 @@ class MinekartSettings : RidingBehaviourSettings {
|
||||
override val key = MinekartBehaviour.KEY
|
||||
override val stats = mutableMapOf<RidingStat, IntRange>()
|
||||
|
||||
var canJump = "true".asExpression()
|
||||
var infiniteStamina: Expression? = null
|
||||
private set
|
||||
var canJump: Expression? = null
|
||||
private set
|
||||
|
||||
var boostLimit = "100.0f".asExpression()
|
||||
var boostLimit: Expression? = null
|
||||
private set
|
||||
|
||||
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'LAND', 1.0, 0.3)".asExpression()
|
||||
var speedExpr: Expression? = null
|
||||
private set
|
||||
|
||||
// Max accel is a whole 1.0 in 1 second. The conversion in the function below is to convert seconds to ticks
|
||||
var accelerationExpr: Expression =
|
||||
"q.get_ride_stats('ACCELERATION', 'LAND', (1.0 / (20.0 * 1.5)), (1.0 / (20.0 * 5.0)))".asExpression()
|
||||
var accelerationExpr: Expression? = null
|
||||
private set
|
||||
|
||||
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'LAND', 30.0, 10.0)".asExpression()
|
||||
var staminaExpr: Expression? = null
|
||||
private set
|
||||
|
||||
//Between a one block jump and a ten block jump
|
||||
var jumpExpr: Expression = "q.get_ride_stats('JUMP', 'LAND', 10.0, 1.0)".asExpression()
|
||||
var jumpExpr: Expression? = null
|
||||
private set
|
||||
|
||||
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'LAND', 140.0, 20.0)".asExpression()
|
||||
var handlingExpr: Expression? = null
|
||||
private set
|
||||
|
||||
var rideSounds: RideSoundSettingsList = RideSoundSettingsList()
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeResourceLocation(key)
|
||||
buffer.writeRidingStats(stats)
|
||||
rideSounds.encode(buffer)
|
||||
buffer.writeExpression(canJump)
|
||||
buffer.writeExpression(boostLimit)
|
||||
buffer.writeNullableExpression(infiniteStamina)
|
||||
buffer.writeNullableExpression(canJump)
|
||||
buffer.writeNullableExpression(boostLimit)
|
||||
buffer.writeNullableExpression(speedExpr)
|
||||
buffer.writeNullableExpression(accelerationExpr)
|
||||
buffer.writeNullableExpression(staminaExpr)
|
||||
buffer.writeNullableExpression(jumpExpr)
|
||||
buffer.writeNullableExpression(handlingExpr)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
stats.putAll(buffer.readRidingStats())
|
||||
rideSounds = RideSoundSettingsList.decode(buffer)
|
||||
canJump = buffer.readExpression()
|
||||
boostLimit = buffer.readExpression()
|
||||
infiniteStamina = buffer.readNullableExpression()
|
||||
canJump = buffer.readNullableExpression()
|
||||
boostLimit = buffer.readNullableExpression()
|
||||
speedExpr = buffer.readNullableExpression()
|
||||
accelerationExpr = buffer.readNullableExpression()
|
||||
staminaExpr = buffer.readNullableExpression()
|
||||
jumpExpr = buffer.readNullableExpression()
|
||||
handlingExpr = buffer.readNullableExpression()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+66
-38
@@ -10,18 +10,35 @@ package com.cobblemon.mod.common.api.riding.behaviour.types.land
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.MoLangMath.lerp
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonRideSettings
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.*
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourState
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.Side
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.SidedRidingState
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.ridingState
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseOption
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.api.riding.sound.RideSoundSettingsList
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.util.blockPositionsAsListRounded
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import com.cobblemon.mod.common.util.readNullableExpression
|
||||
import com.cobblemon.mod.common.util.readRidingStats
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.resolveDouble
|
||||
import com.cobblemon.mod.common.util.toVec3d
|
||||
import com.cobblemon.mod.common.util.writeNullableExpression
|
||||
import com.cobblemon.mod.common.util.writeRidingStats
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.sign
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
@@ -33,10 +50,6 @@ import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import org.joml.Matrix3f
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.sign
|
||||
|
||||
class VehicleBehaviour : RidingBehaviour<VehicleSettings, VehicleState> {
|
||||
companion object {
|
||||
@@ -44,6 +57,8 @@ class VehicleBehaviour : RidingBehaviour<VehicleSettings, VehicleState> {
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
val globalVehicle: VehicleSettings
|
||||
get() = CobblemonRideSettings.vehicle
|
||||
|
||||
override fun getRidingStyle(settings: VehicleSettings, state: VehicleState): RidingStyle {
|
||||
return RidingStyle.LAND
|
||||
@@ -126,7 +141,7 @@ class VehicleBehaviour : RidingBehaviour<VehicleSettings, VehicleState> {
|
||||
var newMomentum = state.turnMomentum.get().toDouble()
|
||||
|
||||
// Grab turningAcceleration and divide 20 twice to get
|
||||
val turningAcceleration = (vehicle.runtime.resolveDouble(settings.handlingExpr) * 1.5 / 20.0f) / 20.0f * 4.0
|
||||
val turningAcceleration = (vehicle.runtime.resolveDouble(settings.handlingExpr ?: globalVehicle.handlingExpr!!) * 1.5 / 20.0f) / 20.0f * 4.0
|
||||
val turnInput = (driver.xxa *-1.0f) * turningAcceleration
|
||||
|
||||
val maxTurnMomentum = 80.0f / 20.0f
|
||||
@@ -137,7 +152,7 @@ class VehicleBehaviour : RidingBehaviour<VehicleSettings, VehicleState> {
|
||||
|
||||
if(state.drifting.get() || state.inAir.get()) {
|
||||
if( newMomentum < driftMaxTurnMomentum) {
|
||||
driftTurnInput = driftTurnInput * (vehicle.deltaMovement.horizontalDistance() / vehicle.runtime.resolveDouble(settings.speedExpr))
|
||||
driftTurnInput = driftTurnInput * (vehicle.deltaMovement.horizontalDistance() / vehicle.runtime.resolveDouble(settings.speedExpr ?: globalVehicle.speedExpr!!))
|
||||
newMomentum += driftTurnInput
|
||||
}
|
||||
newMomentum = lerp(newMomentum, 0.0, 0.03)
|
||||
@@ -177,10 +192,10 @@ class VehicleBehaviour : RidingBehaviour<VehicleSettings, VehicleState> {
|
||||
|
||||
// Check to see if the ride should be walking or sprinting
|
||||
//val walkSpeed = getWalkSpeed(vehicle)
|
||||
val rideTopSpeed = vehicle.runtime.resolveDouble(settings.speedExpr) * 0.6 * 2.0
|
||||
val rideTopSpeed = vehicle.runtime.resolveDouble(settings.speedExpr ?: globalVehicle.speedExpr!!) * 0.6 * 2.0
|
||||
val topSpeed = if (state.drifting.get()) rideTopSpeed * 0.5 else rideTopSpeed
|
||||
|
||||
val accel = vehicle.runtime.resolveDouble(settings.accelerationExpr) * 0.3 * 3 * 2.0
|
||||
val accel = vehicle.runtime.resolveDouble(settings.accelerationExpr ?: globalVehicle.accelerationExpr!!) * 0.3 * 3 * 2.0
|
||||
|
||||
//Flag for determining if player is actively inputting
|
||||
var activeInput = false
|
||||
@@ -250,7 +265,7 @@ class VehicleBehaviour : RidingBehaviour<VehicleSettings, VehicleState> {
|
||||
}
|
||||
|
||||
//TODO: Change this so its tied to a jumping stat and representative of the amount of jumps
|
||||
val canJump = vehicle.runtime.resolveBoolean(settings.canJump)
|
||||
val canJump = vehicle.runtime.resolveBoolean(settings.canJump ?: globalVehicle.canJump!!)
|
||||
//Jump the thang!
|
||||
if (driver.jumping && vehicle.onGround() && canJump) {
|
||||
val jumpForce = 0.5
|
||||
@@ -296,7 +311,7 @@ class VehicleBehaviour : RidingBehaviour<VehicleSettings, VehicleState> {
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return vehicle.runtime.resolveBoolean(settings.canJump)
|
||||
return vehicle.runtime.resolveBoolean(settings.canJump ?: globalVehicle.canJump!!)
|
||||
}
|
||||
|
||||
override fun setRideBar(
|
||||
@@ -412,66 +427,79 @@ class VehicleSettings : RidingBehaviourSettings {
|
||||
override val key = VehicleBehaviour.KEY
|
||||
override val stats = mutableMapOf<RidingStat, IntRange>()
|
||||
|
||||
var canJump = "true".asExpression()
|
||||
var infiniteStamina: Expression? = null
|
||||
private set
|
||||
|
||||
var speed = "0.3".asExpression()
|
||||
var canJump: Expression? = null
|
||||
private set
|
||||
|
||||
var driveFactor = "1.0".asExpression()
|
||||
var speed: Expression? = null
|
||||
private set
|
||||
|
||||
var reverseDriveFactor = "0.25".asExpression()
|
||||
var driveFactor: Expression? = null
|
||||
private set
|
||||
|
||||
var rotationSpeed = "45/20".asExpression()
|
||||
var reverseDriveFactor: Expression? = null
|
||||
private set
|
||||
|
||||
var lookYawLimit = "101".asExpression()
|
||||
var rotationSpeed: Expression? = null
|
||||
private set
|
||||
|
||||
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'LAND', 1.0, 0.3)".asExpression()
|
||||
var lookYawLimit: Expression? = null
|
||||
private set
|
||||
|
||||
var speedExpr: Expression? = null
|
||||
private set
|
||||
|
||||
// Max accel is a whole 1.0 in 1 second. The conversion in the function below is to convert seconds to ticks
|
||||
var accelerationExpr: Expression =
|
||||
"q.get_ride_stats('ACCELERATION', 'LAND', (1.0 / (20.0 * 1.5)), (1.0 / (20.0 * 5.0)))".asExpression()
|
||||
var accelerationExpr: Expression? = null
|
||||
private set
|
||||
|
||||
// Between 30 seconds and 10 seconds at the lowest when at full speed.
|
||||
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'LAND', 30.0, 10.0)".asExpression()
|
||||
var staminaExpr: Expression? = null
|
||||
private set
|
||||
|
||||
//Between a one block jump and a ten block jump
|
||||
var jumpExpr: Expression = "q.get_ride_stats('JUMP', 'LAND', 10.0, 1.0)".asExpression()
|
||||
var jumpExpr: Expression? = null
|
||||
private set
|
||||
|
||||
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'LAND', 140.0, 20.0)".asExpression()
|
||||
var handlingExpr: Expression? = null
|
||||
private set
|
||||
|
||||
var rideSounds: RideSoundSettingsList = RideSoundSettingsList()
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeResourceLocation(key)
|
||||
buffer.writeRidingStats(stats)
|
||||
rideSounds.encode(buffer)
|
||||
buffer.writeExpression(canJump)
|
||||
buffer.writeExpression(speed)
|
||||
buffer.writeExpression(driveFactor)
|
||||
buffer.writeExpression(reverseDriveFactor)
|
||||
buffer.writeExpression(rotationSpeed)
|
||||
buffer.writeExpression(lookYawLimit)
|
||||
buffer.writeNullableExpression(infiniteStamina)
|
||||
buffer.writeNullableExpression(canJump)
|
||||
buffer.writeNullableExpression(speed)
|
||||
buffer.writeNullableExpression(driveFactor)
|
||||
buffer.writeNullableExpression(reverseDriveFactor)
|
||||
buffer.writeNullableExpression(rotationSpeed)
|
||||
buffer.writeNullableExpression(lookYawLimit)
|
||||
buffer.writeNullableExpression(speedExpr)
|
||||
buffer.writeNullableExpression(accelerationExpr)
|
||||
buffer.writeNullableExpression(staminaExpr)
|
||||
buffer.writeNullableExpression(jumpExpr)
|
||||
buffer.writeNullableExpression(handlingExpr)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
stats.putAll(buffer.readRidingStats())
|
||||
rideSounds = RideSoundSettingsList.decode(buffer)
|
||||
canJump = buffer.readExpression()
|
||||
speed = buffer.readExpression()
|
||||
driveFactor = buffer.readExpression()
|
||||
reverseDriveFactor = buffer.readExpression()
|
||||
rotationSpeed = buffer.readExpression()
|
||||
lookYawLimit = buffer.readExpression()
|
||||
infiniteStamina = buffer.readNullableExpression()
|
||||
canJump = buffer.readNullableExpression()
|
||||
speed = buffer.readNullableExpression()
|
||||
driveFactor = buffer.readNullableExpression()
|
||||
reverseDriveFactor = buffer.readNullableExpression()
|
||||
rotationSpeed = buffer.readNullableExpression()
|
||||
lookYawLimit = buffer.readNullableExpression()
|
||||
speedExpr = buffer.readNullableExpression()
|
||||
accelerationExpr = buffer.readNullableExpression()
|
||||
staminaExpr = buffer.readNullableExpression()
|
||||
jumpExpr = buffer.readNullableExpression()
|
||||
handlingExpr = buffer.readNullableExpression()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+77
-34
@@ -8,16 +8,33 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.riding.behaviour.types.liquid
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.CobblemonRideSettings
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.*
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourState
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.Side
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.ridingState
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseOption
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.api.riding.sound.RideSoundSettingsList
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.util.blockPositionsAsListRounded
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.readNullableExpression
|
||||
import com.cobblemon.mod.common.util.readRidingStats
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.resolveDouble
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
import com.cobblemon.mod.common.util.writeNullableExpression
|
||||
import com.cobblemon.mod.common.util.writeRidingStats
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
@@ -28,9 +45,6 @@ import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
class BoatBehaviour : RidingBehaviour<BoatSettings, BoatState> {
|
||||
companion object {
|
||||
@@ -38,6 +52,8 @@ class BoatBehaviour : RidingBehaviour<BoatSettings, BoatState> {
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
val globalBoat: BoatSettings
|
||||
get() = CobblemonRideSettings.boat
|
||||
|
||||
override fun getRidingStyle(settings: BoatSettings, state: BoatState): RidingStyle {
|
||||
return RidingStyle.LIQUID
|
||||
@@ -87,12 +103,12 @@ class BoatBehaviour : RidingBehaviour<BoatSettings, BoatState> {
|
||||
|
||||
if (!state.isVehicleSprinting.get()) {
|
||||
if (state.staminaBuffer.get() >= 20) {
|
||||
val staminaIncrease = vehicle.runtime.resolveDouble(settings.staminaIncreaseExpr)
|
||||
state.stamina.set(min(1.0f, state.stamina.get() + 0.01f * staminaIncrease.toFloat()))
|
||||
val staminaIncrease = (1.0f / vehicle.runtime.resolveDouble(settings.stamReplenishTimeSeconds ?: globalBoat.stamReplenishTimeSeconds!!) ).toFloat() / 20.0f
|
||||
state.stamina.set(min(1.0f, state.stamina.get() + staminaIncrease))
|
||||
}
|
||||
}
|
||||
else if (abs(state.rideVelocity.get().z) > 0.1 && state.isVehicleSprinting.get()) {
|
||||
consumeStamina(vehicle, driver, settings, state, 0.01f)
|
||||
consumeStamina(vehicle, driver, settings, state)
|
||||
}
|
||||
state.staminaBuffer.set(state.staminaBuffer.get() + 1)
|
||||
super.tick(settings, state, vehicle, driver, input)
|
||||
@@ -134,14 +150,14 @@ class BoatBehaviour : RidingBehaviour<BoatSettings, BoatState> {
|
||||
}
|
||||
|
||||
private fun applyVelocityFromInput(velocity: Vec3, vehicle: PokemonEntity, driver: Player, settings: BoatSettings, state: BoatState): Vec3 {
|
||||
val speed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val acceleration = speed / (vehicle.runtime.resolveDouble(settings.accelerationExpr) * 20)
|
||||
val speed = vehicle.runtime.resolveDouble(settings.speedExpr ?: globalBoat.speedExpr!!)
|
||||
val acceleration = speed / (vehicle.runtime.resolveDouble(settings.accelerationExpr ?: globalBoat.accelerationExpr!!) * 20)
|
||||
|
||||
if (state.jumpBuffer.get() != -1 || !(vehicle.isInWater || vehicle.isUnderWater)) {
|
||||
return velocity
|
||||
}
|
||||
|
||||
val sprintModifier = vehicle.runtime.resolveDouble(settings.sprintSpeedModifier)
|
||||
val sprintModifier = vehicle.runtime.resolveDouble(settings.sprintSpeedModifier ?: globalBoat.sprintSpeedModifier!!)
|
||||
val activeSprintModifier = if (state.isVehicleSprinting.get() && hasStamina(state)) sprintModifier else 1.0
|
||||
val forwardInput = driver.zza.toDouble()
|
||||
val delta = when {
|
||||
@@ -164,7 +180,7 @@ class BoatBehaviour : RidingBehaviour<BoatSettings, BoatState> {
|
||||
if (!driver.jumping) return velocity // Not jumping
|
||||
if (state.jumpBuffer.get() != -1) return velocity // Already jumped very recently
|
||||
|
||||
val jumpStrength = vehicle.runtime.resolveDouble(settings.jumpStrengthExpr)
|
||||
val jumpStrength = vehicle.runtime.resolveDouble(settings.jumpStrengthExpr ?: globalBoat.jumpStrengthExpr!!)
|
||||
state.jumpBuffer.set(0)
|
||||
return Vec3(velocity.x, velocity.y + jumpStrength, velocity.z)
|
||||
}
|
||||
@@ -178,20 +194,20 @@ class BoatBehaviour : RidingBehaviour<BoatSettings, BoatState> {
|
||||
return Vec3(velocity.x, 0.0, velocity.z)
|
||||
}
|
||||
}
|
||||
val terminalVelocity = vehicle.runtime.resolveDouble(settings.terminalVelocity)
|
||||
val terminalVelocity = vehicle.runtime.resolveDouble(settings.terminalVelocity ?: globalBoat.terminalVelocity!!)
|
||||
val gravity = (9.8 / ( 20.0)) * 0.2
|
||||
return Vec3(velocity.x, max(velocity.y - gravity, terminalVelocity), velocity.z)
|
||||
}
|
||||
|
||||
private fun shouldFloatHigher(vehicle: PokemonEntity, settings: BoatSettings): Boolean {
|
||||
val surfaceOffset = vehicle.runtime.resolveFloat(settings.surfaceLevelOffset)
|
||||
val surfaceOffset = vehicle.runtime.resolveFloat(settings.surfaceLevelOffset ?: globalBoat.surfaceLevelOffset!!)
|
||||
val blockPos = BlockPos.containing(vehicle.x, vehicle.eyeY + surfaceOffset, vehicle.z)
|
||||
val fluidState = vehicle.level().getFluidState(blockPos)
|
||||
return !fluidState.isEmpty
|
||||
}
|
||||
|
||||
private fun applyStrafeRotation(vehicle: PokemonEntity, driver: Player, settings: BoatSettings, state: BoatState) {
|
||||
val skillModifier = vehicle.runtime.resolveDouble(settings.rotationspeedModifierExpr)
|
||||
val skillModifier = vehicle.runtime.resolveDouble(settings.rotationSpeedModifierExpr ?: globalBoat.rotationSpeedModifierExpr!!)
|
||||
val strafe = driver.xxa
|
||||
if (abs(strafe) > 0) {
|
||||
val increase = if (strafe > 0) -1 else 1
|
||||
@@ -203,9 +219,12 @@ class BoatBehaviour : RidingBehaviour<BoatSettings, BoatState> {
|
||||
return state.stamina.get() != 0f
|
||||
}
|
||||
|
||||
private fun consumeStamina(vehicle: PokemonEntity, driver: Player, settings: BoatSettings, state: BoatState, drain: Float) {
|
||||
val staminaModifier = vehicle.runtime.resolveFloat(settings.staminaDecreaseExpr)
|
||||
state.stamina.set(max(0f, state.stamina.get() - drain / staminaModifier))
|
||||
private fun consumeStamina(vehicle: PokemonEntity, driver: Player, settings: BoatSettings, state: BoatState) {
|
||||
if (vehicle.runtime.resolveBoolean(settings.infiniteStamina ?: globalBoat.infiniteStamina!!)) {
|
||||
return
|
||||
}
|
||||
val stamDrainRate = (1.0f / vehicle.runtime.resolveDouble(settings.staminaExpr ?: globalBoat.staminaExpr!!)).toFloat() / 20.0f
|
||||
state.stamina.set(max(0f, state.stamina.get() - stamDrainRate))
|
||||
if (state.stamina.get() == 0f) {
|
||||
state.isVehicleSprinting.set(false)
|
||||
driver.isSprinting = false
|
||||
@@ -310,7 +329,7 @@ class BoatBehaviour : RidingBehaviour<BoatSettings, BoatState> {
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
val sprintFov = vehicle.runtime.resolveFloat(settings.sprintFovModifier)
|
||||
val sprintFov = vehicle.runtime.resolveFloat(settings.sprintFovModifier ?: globalBoat.sprintFovModifier!!)
|
||||
return if (state.isVehicleSprinting.get()) sprintFov else 1.0f
|
||||
}
|
||||
|
||||
@@ -355,7 +374,7 @@ class BoatBehaviour : RidingBehaviour<BoatSettings, BoatState> {
|
||||
state: BoatState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return vehicle.runtime.resolveBoolean(settings.rotatePokemonHead)
|
||||
return vehicle.runtime.resolveBoolean(settings.rotatePokemonHead ?: globalBoat.rotatePokemonHead!!)
|
||||
}
|
||||
|
||||
override fun shouldRotateRiderHead(
|
||||
@@ -385,48 +404,72 @@ class BoatSettings : RidingBehaviourSettings {
|
||||
override val stats = mutableMapOf<RidingStat, IntRange>()
|
||||
var rideSounds: RideSoundSettingsList = RideSoundSettingsList()
|
||||
|
||||
var terminalVelocity = "-2.0".asExpression()
|
||||
var infiniteStamina: Expression? = null
|
||||
private set
|
||||
|
||||
var rotatePokemonHead = "true".asExpression()
|
||||
var terminalVelocity: Expression? = null
|
||||
private set
|
||||
|
||||
var staminaIncreaseExpr = "q.get_ride_stats('STAMINA', 'LIQUID', 2.0, 1.0)".asExpression()
|
||||
var rotatePokemonHead: Expression? = null
|
||||
private set
|
||||
|
||||
var staminaDecreaseExpr = "q.get_ride_stats('STAMINA', 'LIQUID', 5.0, 1.0)".asExpression()
|
||||
var stamReplenishTimeSeconds: Expression? = null
|
||||
private set
|
||||
|
||||
var rotationspeedModifierExpr = "q.get_ride_stats('SKILL', 'LIQUID', 1.5, 0.5)".asExpression()
|
||||
var staminaExpr: Expression? = null
|
||||
private set
|
||||
|
||||
var jumpStrengthExpr = "q.get_ride_stats('JUMP', 'LIQUID', 2.5, 1.0)".asExpression()
|
||||
var rotationSpeedModifierExpr: Expression? = null
|
||||
private set
|
||||
|
||||
var speedExpr = "q.get_ride_stats('SPEED', 'LIQUID', 2.0, 0.5)".asExpression()
|
||||
var jumpStrengthExpr: Expression? = null
|
||||
private set
|
||||
|
||||
var accelerationExpr = "q.get_ride_stats('ACCELERATION', 'LIQUID', 0.1, 12.0)".asExpression()
|
||||
var speedExpr: Expression? = null
|
||||
private set
|
||||
|
||||
var sprintSpeedModifier = "q.get_ride_stats('JUMP', 'LIQUID', 1.5, 1.25)".asExpression()
|
||||
var accelerationExpr: Expression? = null
|
||||
private set
|
||||
|
||||
var sprintFovModifier = "1.2".asExpression()
|
||||
var sprintSpeedModifier: Expression? = null
|
||||
private set
|
||||
|
||||
var surfaceLevelOffset = "0".asExpression()
|
||||
var sprintFovModifier: Expression? = null
|
||||
|
||||
var surfaceLevelOffset: Expression? = null
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeResourceLocation(key)
|
||||
buffer.writeRidingStats(stats)
|
||||
rideSounds.encode(buffer)
|
||||
buffer.writeExpression(terminalVelocity)
|
||||
buffer.writeNullableExpression(infiniteStamina)
|
||||
buffer.writeNullableExpression(terminalVelocity)
|
||||
buffer.writeNullableExpression(rotatePokemonHead)
|
||||
buffer.writeNullableExpression(stamReplenishTimeSeconds)
|
||||
buffer.writeNullableExpression(staminaExpr)
|
||||
buffer.writeNullableExpression(rotationSpeedModifierExpr)
|
||||
buffer.writeNullableExpression(jumpStrengthExpr)
|
||||
buffer.writeNullableExpression(speedExpr)
|
||||
buffer.writeNullableExpression(accelerationExpr)
|
||||
buffer.writeNullableExpression(sprintSpeedModifier)
|
||||
buffer.writeNullableExpression(sprintFovModifier)
|
||||
buffer.writeNullableExpression(surfaceLevelOffset)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
stats.putAll(buffer.readRidingStats())
|
||||
rideSounds = RideSoundSettingsList.decode(buffer)
|
||||
terminalVelocity = buffer.readExpression()
|
||||
infiniteStamina = buffer.readNullableExpression()
|
||||
terminalVelocity = buffer.readNullableExpression()
|
||||
rotatePokemonHead = buffer.readNullableExpression()
|
||||
stamReplenishTimeSeconds = buffer.readNullableExpression()
|
||||
staminaExpr = buffer.readNullableExpression()
|
||||
rotationSpeedModifierExpr = buffer.readNullableExpression()
|
||||
jumpStrengthExpr = buffer.readNullableExpression()
|
||||
speedExpr = buffer.readNullableExpression()
|
||||
accelerationExpr = buffer.readNullableExpression()
|
||||
sprintSpeedModifier = buffer.readNullableExpression()
|
||||
sprintFovModifier = buffer.readNullableExpression()
|
||||
surfaceLevelOffset = buffer.readNullableExpression()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+14
-8
@@ -8,10 +8,14 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.riding.behaviour.types.liquid
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonRideSettings
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.*
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourState
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.Side
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.ridingState
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseOption
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.api.riding.sound.RideSoundSettingsList
|
||||
@@ -21,6 +25,7 @@ import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.blockPositionsAsListRounded
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.readRidingStats
|
||||
import com.cobblemon.mod.common.util.writeNullable
|
||||
import com.cobblemon.mod.common.util.writeRidingStats
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
@@ -38,6 +43,8 @@ class BurstBehaviour : RidingBehaviour<BurstSettings, BurstState> {
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
val globalBurst: BurstSettings
|
||||
get() = CobblemonRideSettings.burst
|
||||
|
||||
override fun getRidingStyle(settings: BurstSettings, state: BurstState): RidingStyle {
|
||||
return RidingStyle.LIQUID
|
||||
@@ -67,7 +74,7 @@ class BurstBehaviour : RidingBehaviour<BurstSettings, BurstState> {
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
if(state.dashing.get()) {
|
||||
if (state.dashing.get()) {
|
||||
state.ticks.set(state.ticks.get() + 1)
|
||||
if(state.ticks.get() >= DASH_TICKS) {
|
||||
state.dashing.set(false)
|
||||
@@ -77,7 +84,7 @@ class BurstBehaviour : RidingBehaviour<BurstSettings, BurstState> {
|
||||
}
|
||||
|
||||
state.dashing.set(true)
|
||||
return settings.dashSpeed
|
||||
return settings.dashSpeed ?: globalBurst.dashSpeed!!
|
||||
}
|
||||
|
||||
override fun rotation(
|
||||
@@ -239,22 +246,21 @@ class BurstSettings : RidingBehaviourSettings {
|
||||
override val key = BurstBehaviour.KEY
|
||||
override val stats = mutableMapOf<RidingStat, IntRange>()
|
||||
|
||||
var dashSpeed = 1F
|
||||
var dashSpeed: Float? = null
|
||||
private set
|
||||
|
||||
var rideSounds: RideSoundSettingsList = RideSoundSettingsList()
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeResourceLocation(key)
|
||||
buffer.writeRidingStats(stats)
|
||||
rideSounds.encode(buffer)
|
||||
buffer.writeFloat(dashSpeed)
|
||||
buffer.writeNullable(dashSpeed) { buf, speed -> buf.writeFloat(speed) }
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
stats.putAll(buffer.readRidingStats())
|
||||
rideSounds = RideSoundSettingsList.decode(buffer)
|
||||
dashSpeed = buffer.readFloat()
|
||||
dashSpeed = buffer.readNullable { buf -> buf.readFloat() }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+73
-61
@@ -10,21 +10,33 @@ package com.cobblemon.mod.common.api.riding.behaviour.types.liquid
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.MoLangMath.lerp
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonRideSettings
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.*
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourState
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.Side
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.ridingState
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseOption
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.api.riding.sound.RideSoundSettingsList
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.math.geometry.toDegrees
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import com.cobblemon.mod.common.util.readNullableExpression
|
||||
import com.cobblemon.mod.common.util.readRidingStats
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.resolveDouble
|
||||
import com.cobblemon.mod.common.util.toVec3d
|
||||
import com.cobblemon.mod.common.util.writeNullableExpression
|
||||
import com.cobblemon.mod.common.util.writeRidingStats
|
||||
import kotlin.math.*
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
@@ -35,18 +47,6 @@ import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import org.joml.Vector3f
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.asin
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.hypot
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sign
|
||||
import kotlin.math.sin
|
||||
import kotlin.math.sqrt
|
||||
|
||||
class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
companion object {
|
||||
@@ -54,6 +54,8 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
val globalDolphin: DolphinSettings
|
||||
get() = CobblemonRideSettings.dolphin
|
||||
|
||||
override fun getRidingStyle(settings: DolphinSettings, state: DolphinState): RidingStyle {
|
||||
return RidingStyle.LIQUID
|
||||
@@ -117,10 +119,14 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
) {
|
||||
val stam = state.stamina.get()
|
||||
|
||||
if (vehicle.runtime.resolveBoolean(settings.infiniteStamina ?: globalDolphin.infiniteStamina!!)) {
|
||||
return
|
||||
}
|
||||
|
||||
// Grab the boost time in seconds and convert to ticks. Then calculate the drain rate as inversely
|
||||
// proportional to the number of ticks of boost thus making a full boost take x ticks
|
||||
// in short: "Stamina drains slower at higher values and also replenishes slower"
|
||||
val boostTime = vehicle.runtime.resolveDouble(settings.staminaExpr) * 20.0f
|
||||
val boostTime = vehicle.runtime.resolveDouble(settings.staminaExpr ?: globalDolphin.staminaExpr!!) * 20.0f
|
||||
val stamDrainRate = (1.0f / boostTime).toFloat()
|
||||
|
||||
val newStam = if (state.boosting.get()) max(0.0f,stam - stamDrainRate)
|
||||
@@ -149,9 +155,9 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
|
||||
val runtime = vehicle.runtime
|
||||
val boostMod = if (state.boosting.get()) runtime.resolveDouble(settings.jumpExpr) else 1.0
|
||||
val topSpeed = (vehicle.runtime.resolveDouble(settings.speedExpr) / 20.0) * boostMod
|
||||
val accel = (topSpeed / (vehicle.runtime.resolveDouble(settings.accelerationExpr) * 20.0)) * boostMod
|
||||
val boostMod = if (state.boosting.get()) runtime.resolveDouble(settings.jumpExpr ?: globalDolphin.jumpExpr!!) else 1.0
|
||||
val topSpeed = (vehicle.runtime.resolveDouble(settings.speedExpr ?: globalDolphin.speedExpr!!) / 20.0) * boostMod
|
||||
val accel = (topSpeed / (vehicle.runtime.resolveDouble(settings.accelerationExpr ?: globalDolphin.accelerationExpr!!) * 20.0)) * boostMod
|
||||
|
||||
/*********************************************
|
||||
* Breaching logic
|
||||
@@ -189,8 +195,8 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
}
|
||||
|
||||
val currSpeed = state.speed.get()
|
||||
val strafeFactor = runtime.resolveDouble(settings.strafeFactor)
|
||||
val reverseDriveFactor = runtime.resolveDouble(settings.reverseDriveFactor)
|
||||
val strafeFactor = runtime.resolveDouble(settings.strafeFactor ?: globalDolphin.strafeFactor!!)
|
||||
val reverseDriveFactor = runtime.resolveDouble(settings.reverseDriveFactor ?: globalDolphin.reverseDriveFactor!!)
|
||||
val f = -driver.xxa * strafeFactor
|
||||
when {
|
||||
driver.zza > 0.0 -> state.speed.set(min(topSpeed, currSpeed + accel))
|
||||
@@ -225,8 +231,8 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
|
||||
val currSpeed = vehicle.deltaMovement.length()
|
||||
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr)
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr) / 20.0
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr ?: globalDolphin.handlingExpr!!)
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr ?: globalDolphin.speedExpr!!) / 20.0
|
||||
|
||||
val yawDeltaDeg = deltaTime * handling * sin(Math.toRadians(controller.roll.toDouble())).pow(2) * sin(Math.toRadians(controller.roll.toDouble())).sign
|
||||
val trueYawDelt = yawDeltaDeg * abs(cos(Math.toRadians(controller.pitch.toDouble()))) * sqrt(RidingBehaviour.scaleToRange(currSpeed, 0.0, topSpeed))
|
||||
@@ -253,7 +259,7 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
// Calculate correcting roll force.
|
||||
// Mult by cos(pitch) to ensure that it doesn't roll correct at when diving or climbing
|
||||
val currSpeed = vehicle.deltaMovement.length()
|
||||
val rollCorrectionTimer = vehicle.runtime.resolveDouble(settings.timeToRollCorrect)
|
||||
val rollCorrectionTimer = vehicle.runtime.resolveDouble(settings.timeToRollCorrect ?: globalDolphin.timeToRollCorrect!!)
|
||||
val maxRollCorrectionRate = if (!(vehicle.isInWater || vehicle.isUnderWater)) 15.0f
|
||||
else 10.0f * (cos(controller.pitch.toRadians())).pow(2) * ((state.noInputTime.get() - rollCorrectionTimer) * 2).coerceIn(0.0, 1.0).toFloat()
|
||||
val maxRollForce = maxRollCorrectionRate / 40.0
|
||||
@@ -374,8 +380,8 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
controller.rotateRoll(controller.roll * -1.0f)
|
||||
|
||||
val boostingHandleDebuff = if (state.boosting.get()) 0.2 else 1.0
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr) * boostingHandleDebuff
|
||||
val mouseInputMult = vehicle.runtime.resolveDouble(settings.mouseInputMult)
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr ?: globalDolphin.handlingExpr!!) * boostingHandleDebuff
|
||||
val mouseInputMult = vehicle.runtime.resolveDouble(settings.mouseInputMult ?: globalDolphin.mouseInputMult!!)
|
||||
|
||||
//Smooth out mouse input.
|
||||
val smoothingSpeed = 4.0
|
||||
@@ -418,9 +424,9 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
): Vec3 {
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr) / 20.0
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr ?: globalDolphin.speedExpr!!) / 20.0
|
||||
val boostingHandleDebuff = if (state.boosting.get()) 0.2 else 1.0
|
||||
val mouseInputMult = vehicle.runtime.resolveDouble(settings.mouseInputMult) * boostingHandleDebuff
|
||||
val mouseInputMult = vehicle.runtime.resolveDouble(settings.mouseInputMult ?: globalDolphin.mouseInputMult!!) * boostingHandleDebuff
|
||||
|
||||
//Smooth out mouse input.
|
||||
val smoothingSpeed = 4.0
|
||||
@@ -439,7 +445,7 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
// - Reduce pitch substantially when rolled and in a steep yaw. This prevents the player from ignoring a slow handling stat
|
||||
// - Do not pitch at all when at or below hover speed
|
||||
// - pitch faster at higher speeds
|
||||
val p = 1.0 - vehicle.runtime.resolveDouble(settings.horizontalPitchExpr)
|
||||
val p = 1.0 - vehicle.runtime.resolveDouble(settings.horizontalPitchExpr ?: globalDolphin.horizontalPitchExpr!!)
|
||||
val localPitch = yInput * (1 - abs(sin(controller.roll.toRadians())) * p * hypot(controller.forwardVector.x.toDouble(), controller.forwardVector.z.toDouble()).toFloat())
|
||||
// localPitch *= if (currSpeed > hoverSpeed) RidingBehaviour.scaleToRange(currSpeed, hoverSpeed, topSpeed)
|
||||
// else 0.0
|
||||
@@ -560,62 +566,68 @@ class DolphinSettings : RidingBehaviourSettings {
|
||||
override val key = DolphinBehaviour.KEY
|
||||
override val stats = mutableMapOf<RidingStat, IntRange>()
|
||||
|
||||
var canJump = "true".asExpression()
|
||||
var infiniteStamina: Expression? = null
|
||||
private set
|
||||
|
||||
var reverseDriveFactor = "0.25".asExpression()
|
||||
var canJump: Expression? = null
|
||||
private set
|
||||
|
||||
var strafeFactor = "0.2".asExpression()
|
||||
var reverseDriveFactor: Expression? = null
|
||||
private set
|
||||
|
||||
var timeToRollCorrect: Expression = "0.5".asExpression()
|
||||
var strafeFactor: Expression? = null
|
||||
private set
|
||||
|
||||
var timeToRollCorrect: Expression? = null
|
||||
private set
|
||||
|
||||
// Boost influence when boosting
|
||||
var jumpExpr: Expression = "q.get_ride_stats('JUMP', 'LIQUID', 2.2, 1.2)".asExpression()
|
||||
var jumpExpr: Expression? = null
|
||||
// Yaw rate in degrees per second
|
||||
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'LIQUID', 100.0, 45.0)".asExpression()
|
||||
var horizontalPitchExpr: Expression = "q.get_ride_stats('SKILL', 'LIQUID', 0.3, 0.2)".asExpression()
|
||||
var mouseInputMult: Expression = "q.get_ride_stats('SKILL', 'LIQUID', 1.2, 0.8)".asExpression()
|
||||
var handlingExpr: Expression? = null
|
||||
var horizontalPitchExpr: Expression? = null
|
||||
var mouseInputMult: Expression? = null
|
||||
// Top speed in Bl/s
|
||||
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'LIQUID', 15.0, 5.0)".asExpression()
|
||||
var speedExpr: Expression? = null
|
||||
// Seconds to get to top speed
|
||||
var accelerationExpr: Expression = "q.get_ride_stats('ACCELERATION', 'LIQUID', 2.0, 5.0)".asExpression()
|
||||
var accelerationExpr: Expression? = null
|
||||
// Seconds of boost
|
||||
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'LIQUID', 7.0, 3.0)".asExpression()
|
||||
var staminaExpr: Expression? = null
|
||||
|
||||
var rideSounds: RideSoundSettingsList = RideSoundSettingsList()
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeResourceLocation(key)
|
||||
buffer.writeRidingStats(stats)
|
||||
rideSounds.encode(buffer)
|
||||
buffer.writeExpression(canJump)
|
||||
buffer.writeExpression(reverseDriveFactor)
|
||||
buffer.writeExpression(strafeFactor)
|
||||
buffer.writeExpression(jumpExpr)
|
||||
buffer.writeExpression(handlingExpr)
|
||||
buffer.writeExpression(horizontalPitchExpr)
|
||||
buffer.writeExpression(mouseInputMult)
|
||||
buffer.writeExpression(speedExpr)
|
||||
buffer.writeExpression(accelerationExpr)
|
||||
buffer.writeExpression(staminaExpr)
|
||||
buffer.writeNullableExpression(infiniteStamina)
|
||||
buffer.writeNullableExpression(canJump)
|
||||
buffer.writeNullableExpression(reverseDriveFactor)
|
||||
buffer.writeNullableExpression(strafeFactor)
|
||||
buffer.writeNullableExpression(timeToRollCorrect)
|
||||
buffer.writeNullableExpression(jumpExpr)
|
||||
buffer.writeNullableExpression(handlingExpr)
|
||||
buffer.writeNullableExpression(horizontalPitchExpr)
|
||||
buffer.writeNullableExpression(mouseInputMult)
|
||||
buffer.writeNullableExpression(speedExpr)
|
||||
buffer.writeNullableExpression(accelerationExpr)
|
||||
buffer.writeNullableExpression(staminaExpr)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
stats.putAll(buffer.readRidingStats())
|
||||
rideSounds = RideSoundSettingsList.decode(buffer)
|
||||
canJump = buffer.readExpression()
|
||||
reverseDriveFactor = buffer.readExpression()
|
||||
strafeFactor = buffer.readExpression()
|
||||
jumpExpr = buffer.readExpression()
|
||||
handlingExpr = buffer.readExpression()
|
||||
horizontalPitchExpr = buffer.readExpression()
|
||||
mouseInputMult = buffer.readExpression()
|
||||
speedExpr = buffer.readExpression()
|
||||
accelerationExpr = buffer.readExpression()
|
||||
staminaExpr = buffer.readExpression()
|
||||
infiniteStamina = buffer.readNullableExpression()
|
||||
canJump = buffer.readNullableExpression()
|
||||
reverseDriveFactor = buffer.readNullableExpression()
|
||||
strafeFactor = buffer.readNullableExpression()
|
||||
timeToRollCorrect = buffer.readNullableExpression()
|
||||
jumpExpr = buffer.readNullableExpression()
|
||||
handlingExpr = buffer.readNullableExpression()
|
||||
horizontalPitchExpr = buffer.readNullableExpression()
|
||||
mouseInputMult = buffer.readNullableExpression()
|
||||
speedExpr = buffer.readNullableExpression()
|
||||
accelerationExpr = buffer.readNullableExpression()
|
||||
staminaExpr = buffer.readNullableExpression()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-70
@@ -24,14 +24,12 @@ import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.PokeSnackBlockParticlesPacket
|
||||
import com.cobblemon.mod.common.util.math.pow
|
||||
import com.cobblemon.mod.common.util.toBlockPos
|
||||
import com.cobblemon.mod.common.util.toVec3d
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.sqrt
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.core.Holder
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.entity.ai.village.poi.PoiManager
|
||||
import net.minecraft.world.entity.ai.village.poi.PoiType
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
@@ -114,73 +112,6 @@ object LurePokeSnackDetector : SpawningInfluenceDetector {
|
||||
}
|
||||
}
|
||||
|
||||
fun attemptSafeMove2(level: ServerLevel, startPos: BlockPos, entity: PokemonEntity, ) {
|
||||
val inWater = entity.isInWater
|
||||
|
||||
// Random offset in a cardinal direction (north, south, east, west)
|
||||
val randomDirection = listOf(Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST).random()
|
||||
val initialOffsetPos = startPos.relative(randomDirection)
|
||||
|
||||
// Variables to track the best (closest) safe position
|
||||
var safePos: BlockPos? = null
|
||||
var bestDistanceSq = Double.MAX_VALUE
|
||||
|
||||
val maxRadius = 10
|
||||
|
||||
// Search within a sphere around the initial offset position
|
||||
for (dx in -maxRadius..maxRadius) {
|
||||
for (dy in -maxRadius..maxRadius) {
|
||||
for (dz in -maxRadius..maxRadius) {
|
||||
val candidatePos = initialOffsetPos.offset(dx, dy, dz)
|
||||
val distanceSq = startPos.distSqr(candidatePos)
|
||||
|
||||
// Check if within sphere radius
|
||||
if (dx*dx + dy*dy + dz*dz <= maxRadius*maxRadius) {
|
||||
// Check collision at candidate position
|
||||
val currentBox = entity.boundingBox.move(
|
||||
candidatePos.x - entity.x,
|
||||
candidatePos.y - entity.y,
|
||||
candidatePos.z - entity.z
|
||||
)
|
||||
|
||||
if (level.noCollision(entity, currentBox)) {
|
||||
val blockBelowPos = candidatePos.below()
|
||||
val blockState = level.getBlockState(blockBelowPos)
|
||||
|
||||
val isWater = blockState.block == Blocks.WATER
|
||||
if (inWater) {
|
||||
if (isWater) {
|
||||
if (distanceSq < bestDistanceSq) {
|
||||
bestDistanceSq = distanceSq
|
||||
safePos = candidatePos
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!blockState.isAir) {
|
||||
if (distanceSq < bestDistanceSq) {
|
||||
bestDistanceSq = distanceSq
|
||||
safePos = candidatePos
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (safePos != null) {
|
||||
entity.moveTo(safePos.toVec3d())
|
||||
PokeSnackBlockParticlesPacket(startPos, safePos).sendToPlayersAround(
|
||||
startPos.x.toDouble(),
|
||||
startPos.y.toDouble(),
|
||||
startPos.z.toDouble(),
|
||||
64.0,
|
||||
level.dimension()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun attemptSafeMove(level: ServerLevel, startPos: BlockPos, entity: PokemonEntity) {
|
||||
val inWater = entity.isInWater
|
||||
val maxDistance = 10 // maximum search radius
|
||||
@@ -255,4 +186,4 @@ object LurePokeSnackDetector : SpawningInfluenceDetector {
|
||||
}
|
||||
|
||||
override fun detectFromBlock(level: ServerLevel, pos: BlockPos, blockState: BlockState) = emptyList<SpawningZoneInfluence>()
|
||||
}
|
||||
}
|
||||
@@ -161,6 +161,10 @@ open class PlayerPartyStore(
|
||||
if (pokemon.interactionCooldowns.any()) {
|
||||
pokemon.tickInteractionCooldown()
|
||||
}
|
||||
|
||||
if (pokemon.entity?.passengers?.isNotEmpty() != true) {
|
||||
pokemon.rideStamina += 0.1F // Recover all stamina in 10 seconds, as long as no one's on it
|
||||
}
|
||||
}
|
||||
// Friendship
|
||||
// ToDo expand this down the line just a very basic implementation for the first releases
|
||||
|
||||
@@ -51,12 +51,13 @@ import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.CollisionContext
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import net.minecraft.world.phys.shapes.VoxelShape
|
||||
import kotlin.math.floor
|
||||
import kotlin.random.Random
|
||||
|
||||
class PokeSnackBlock(settings: Properties, val isLure: Boolean): BaseEntityBlock(settings) {
|
||||
companion object {
|
||||
val MAX_BITES = 8
|
||||
val CAKE_HEIGHT = 0.4375
|
||||
const val MAX_BITES = 8
|
||||
const val CAKE_HEIGHT = 0.4375
|
||||
|
||||
val CANDLE_PARTICLE_POSITION = Vec3(0.5, CAKE_HEIGHT + 0.5, 0.5)
|
||||
|
||||
@@ -135,6 +136,7 @@ class PokeSnackBlock(settings: Properties, val isLure: Boolean): BaseEntityBlock
|
||||
if (hasCandle(state)) {
|
||||
return Shapes.or(SHAPES[state.getValue(BITES)], CANDLE_SHAPE)
|
||||
}
|
||||
|
||||
return SHAPES[state.getValue(BITES)]
|
||||
}
|
||||
|
||||
@@ -294,15 +296,27 @@ class PokeSnackBlock(settings: Properties, val isLure: Boolean): BaseEntityBlock
|
||||
|
||||
fun eat(level: Level, pos: BlockPos, state: BlockState, player: Player?) {
|
||||
val bites = state.getValue(BITES) as Int
|
||||
if (bites < MAX_BITES) {
|
||||
level.setBlock(pos, state.setValue(BITES, bites + 1) as BlockState, UPDATE_ALL)
|
||||
} else {
|
||||
val newBites =
|
||||
if (isLure) {
|
||||
val pokeSnackBlockEntity = level.getBlockEntity(pos) as PokeSnackBlockEntity? ?: return
|
||||
pokeSnackBlockEntity.amountSpawned += 1
|
||||
|
||||
floor(pokeSnackBlockEntity.amountSpawned / PokeSnackBlockEntity.SPAWNS_PER_BITE.toDouble()).toInt()
|
||||
} else {
|
||||
bites + 1
|
||||
}
|
||||
|
||||
if (newBites > MAX_BITES) {
|
||||
dropCandle(level, pos, state, player)
|
||||
level.removeBlock(pos, false)
|
||||
level.removeBlockEntity(pos)
|
||||
} else {
|
||||
level.setBlock(pos, state.setValue(BITES, newBites) as BlockState, UPDATE_ALL)
|
||||
}
|
||||
|
||||
level.playSound(null, player?.blockPosition() ?: pos, SoundEvents.GENERIC_EAT, if (player != null) SoundSource.PLAYERS else SoundSource.NEUTRAL)
|
||||
spawnEatParticles(level, pos)
|
||||
|
||||
player?.let {
|
||||
level.gameEvent(it, GameEvent.BLOCK_DESTROY, pos)
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
package com.cobblemon.mod.common.block
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.entity.MoLangScriptingEntity
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.core.dispenser.DispenseItemBehavior
|
||||
@@ -25,6 +27,7 @@ import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.level.BlockGetter
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.LevelAccessor
|
||||
import net.minecraft.world.level.block.Block
|
||||
@@ -40,6 +43,9 @@ import net.minecraft.world.level.material.FluidState
|
||||
import net.minecraft.world.level.material.Fluids
|
||||
import net.minecraft.world.level.pathfinder.PathComputationType
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
import net.minecraft.world.phys.shapes.CollisionContext
|
||||
import net.minecraft.world.phys.shapes.EntityCollisionContext
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import net.minecraft.world.phys.shapes.VoxelShape
|
||||
|
||||
class SaccharineLeafBlock(settings: Properties) : LeavesBlock(settings) {
|
||||
@@ -90,7 +96,13 @@ class SaccharineLeafBlock(settings: Properties) : LeavesBlock(settings) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!added) Containers.dropItemStack(level, source.pos.x.toDouble(), source.pos.y.toDouble(), source.pos.z.toDouble(), outputStack)
|
||||
if (!added) Containers.dropItemStack(
|
||||
level,
|
||||
source.pos.x.toDouble(),
|
||||
source.pos.y.toDouble(),
|
||||
source.pos.z.toDouble(),
|
||||
outputStack
|
||||
)
|
||||
}
|
||||
}
|
||||
stack
|
||||
@@ -108,7 +120,27 @@ class SaccharineLeafBlock(settings: Properties) : LeavesBlock(settings) {
|
||||
)
|
||||
}
|
||||
|
||||
override fun isRandomlyTicking(state: BlockState): Boolean = !state.getValue(PERSISTENT) && state.getValue(DISTANCE) > 6
|
||||
override fun getCollisionShape(
|
||||
state: BlockState,
|
||||
level: BlockGetter,
|
||||
pos: BlockPos,
|
||||
context: CollisionContext
|
||||
): VoxelShape? {
|
||||
|
||||
if (context is EntityCollisionContext) {
|
||||
val entity = context.entity
|
||||
if (entity != null
|
||||
&& entity is MoLangScriptingEntity
|
||||
&& entity.config.map.getOrDefault("can_path_through_sacc_leaves", DoubleValue.ZERO).asDouble() == 1.0
|
||||
) {
|
||||
return Shapes.empty()
|
||||
}
|
||||
}
|
||||
return super.getCollisionShape(state, level, pos, context)
|
||||
}
|
||||
|
||||
override fun isRandomlyTicking(state: BlockState): Boolean =
|
||||
true //!state.getValue(PERSISTENT) && state.getValue(DISTANCE) > 6
|
||||
|
||||
override fun randomTick(state: BlockState, world: ServerLevel, pos: BlockPos, random: RandomSource) {
|
||||
val currentAge = state.getValue(AGE)
|
||||
@@ -123,8 +155,8 @@ class SaccharineLeafBlock(settings: Properties) : LeavesBlock(settings) {
|
||||
} else if (belowState.block is SaccharineLeafBlock) {
|
||||
val belowAge = belowState.getValue(AGE)
|
||||
if (belowAge < MAX_AGE) {
|
||||
changeAge(state, -1)
|
||||
changeAge(belowState, 1)
|
||||
world.setBlock(pos, changeAge(state, -1), UPDATE_CLIENTS)
|
||||
world.setBlock(belowPos, changeAge(belowState, 1), UPDATE_CLIENTS)
|
||||
}
|
||||
break
|
||||
} else {
|
||||
@@ -217,7 +249,15 @@ class SaccharineLeafBlock(settings: Properties) : LeavesBlock(settings) {
|
||||
|
||||
override fun isPathfindable(state: BlockState, type: PathComputationType): Boolean = false
|
||||
|
||||
override fun useItemOn(stack: ItemStack, state: BlockState, level: Level, pos: BlockPos, player: Player, hand: InteractionHand, hit: BlockHitResult): ItemInteractionResult {
|
||||
override fun useItemOn(
|
||||
stack: ItemStack,
|
||||
state: BlockState,
|
||||
level: Level,
|
||||
pos: BlockPos,
|
||||
player: Player,
|
||||
hand: InteractionHand,
|
||||
hit: BlockHitResult
|
||||
): ItemInteractionResult {
|
||||
if (!state.getValue(WATERLOGGED)) {
|
||||
val itemStack = player.getItemInHand(hand)
|
||||
val isGlassBottle = itemStack.`is`(Items.GLASS_BOTTLE)
|
||||
|
||||
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.block.entity
|
||||
import com.cobblemon.mod.common.CobblemonBlockEntities
|
||||
import com.cobblemon.mod.common.CobblemonRecipeTypes
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.cooking.Seasonings
|
||||
import com.cobblemon.mod.common.api.cooking.getColourMixFromSeasonings
|
||||
import com.cobblemon.mod.common.block.campfirepot.CampfireBlock
|
||||
import com.cobblemon.mod.common.item.components.PotComponent
|
||||
@@ -133,6 +134,8 @@ class CampfireBlockEntity(pos: BlockPos, state: BlockState) : BaseContainerBlock
|
||||
|
||||
campfireBlockEntity.particleCooldown = 20
|
||||
}
|
||||
|
||||
campfireBlockEntity.time++
|
||||
}
|
||||
|
||||
fun serverTick(level: Level, pos: BlockPos, state: BlockState, campfireBlockEntity: CampfireBlockEntity) {
|
||||
@@ -236,6 +239,7 @@ class CampfireBlockEntity(pos: BlockPos, state: BlockState) : BaseContainerBlock
|
||||
private var particleCooldown: Int = 0
|
||||
var brothColor: Int = BASE_BROTH_COLOR
|
||||
var bubbleColor: Int = BASE_BROTH_BUBBLE_COLOR
|
||||
var time: Int = 0
|
||||
|
||||
var dataAccess: ContainerData = object : ContainerData {
|
||||
override fun get(index: Int): Int {
|
||||
@@ -477,9 +481,10 @@ class CampfireBlockEntity(pos: BlockPos, state: BlockState) : BaseContainerBlock
|
||||
}
|
||||
|
||||
override fun canPlaceItemThroughFace(index: Int, itemStack: ItemStack, direction: Direction?): Boolean {
|
||||
return when (direction) {
|
||||
Direction.UP -> SEASONING_SLOTS.contains(index)
|
||||
else -> CRAFTING_GRID_SLOTS.contains(index)
|
||||
return if(direction == Direction.UP && Seasonings.isSeasoning(itemStack)){
|
||||
SEASONING_SLOTS.contains(index)
|
||||
} else {
|
||||
CRAFTING_GRID_SLOTS.contains(index)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,11 @@ import kotlin.collections.orEmpty
|
||||
|
||||
open class PokeSnackBlockEntity(pos: BlockPos, state: BlockState) : TintBlockEntity(CobblemonBlockEntities.POKE_SNACK, pos, state) {
|
||||
|
||||
companion object {
|
||||
const val SPAWNS_PER_BITE = 4
|
||||
}
|
||||
|
||||
var amountSpawned: Int = 0
|
||||
var flavourComponent: FlavourComponent? = null
|
||||
var baitEffectsComponent: BaitEffectsComponent? = null
|
||||
var ingredientComponent: IngredientComponent? = null
|
||||
@@ -54,12 +59,19 @@ open class PokeSnackBlockEntity(pos: BlockPos, state: BlockState) : TintBlockEnt
|
||||
|
||||
fun toItemStack(): ItemStack {
|
||||
val stack = ItemStack(this.blockState.block)
|
||||
|
||||
if (isLure() && baitEffectsComponent != null) {
|
||||
stack.set(CobblemonItemComponents.BAIT_EFFECTS, baitEffectsComponent)
|
||||
}
|
||||
|
||||
if (flavourComponent != null) {
|
||||
stack.set(CobblemonItemComponents.FLAVOUR, flavourComponent)
|
||||
}
|
||||
|
||||
if (ingredientComponent != null) {
|
||||
stack.set(CobblemonItemComponents.INGREDIENT, ingredientComponent)
|
||||
}
|
||||
|
||||
return stack
|
||||
}
|
||||
|
||||
@@ -73,6 +85,8 @@ open class PokeSnackBlockEntity(pos: BlockPos, state: BlockState) : TintBlockEnt
|
||||
override fun saveAdditional(tag: CompoundTag, registries: HolderLookup.Provider) {
|
||||
super.saveAdditional(tag, registries)
|
||||
|
||||
tag.putInt(DataKeys.AMOUNT_SPAWNED, amountSpawned)
|
||||
|
||||
flavourComponent?.let { component ->
|
||||
CobblemonItemComponents.FLAVOUR.codec()!!
|
||||
.encodeStart(NbtOps.INSTANCE, component)
|
||||
@@ -104,6 +118,8 @@ open class PokeSnackBlockEntity(pos: BlockPos, state: BlockState) : TintBlockEnt
|
||||
override fun loadAdditional(tag: CompoundTag, registries: HolderLookup.Provider) {
|
||||
super.loadAdditional(tag, registries)
|
||||
|
||||
amountSpawned = tag.getInt(DataKeys.AMOUNT_SPAWNED)
|
||||
|
||||
if (tag.contains(DataKeys.FLAVOUR)) {
|
||||
CobblemonItemComponents.FLAVOUR.codec()
|
||||
?.parse(NbtOps.INSTANCE, tag.get(DataKeys.FLAVOUR))
|
||||
|
||||
@@ -29,7 +29,15 @@ import com.cobblemon.mod.common.client.gui.cookingpot.CookingPotScreen
|
||||
import com.cobblemon.mod.common.client.particle.BedrockParticleOptionsRepository
|
||||
import com.cobblemon.mod.common.client.render.ClientPlayerIcon
|
||||
import com.cobblemon.mod.common.client.render.DeferredRenderer
|
||||
import com.cobblemon.mod.common.client.render.block.*
|
||||
import com.cobblemon.mod.common.client.render.block.BerryBlockRenderer
|
||||
import com.cobblemon.mod.common.client.render.block.CampfireBlockEntityRenderer
|
||||
import com.cobblemon.mod.common.client.render.block.DisplayCaseRenderer
|
||||
import com.cobblemon.mod.common.client.render.block.FossilAnalyzerRenderer
|
||||
import com.cobblemon.mod.common.client.render.block.GildedChestBlockRenderer
|
||||
import com.cobblemon.mod.common.client.render.block.HealingMachineRenderer
|
||||
import com.cobblemon.mod.common.client.render.block.LecternBlockEntityRenderer
|
||||
import com.cobblemon.mod.common.client.render.block.PokeSnackBlockEntityRenderer
|
||||
import com.cobblemon.mod.common.client.render.block.RestorationTankRenderer
|
||||
import com.cobblemon.mod.common.client.render.boat.CobblemonBoatRenderer
|
||||
import com.cobblemon.mod.common.client.render.color.AprijuiceItemColorProvider
|
||||
import com.cobblemon.mod.common.client.render.color.PokeBaitItemColorProvider
|
||||
@@ -42,7 +50,9 @@ import com.cobblemon.mod.common.client.render.item.CobblemonBuiltinItemRendererR
|
||||
import com.cobblemon.mod.common.client.render.item.PokemonItemRenderer
|
||||
import com.cobblemon.mod.common.client.render.layer.PokemonOnShoulderRenderer
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.bedrock.animation.BedrockAnimationRepository
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.*
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.BerryModelRepository
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.MiscModelRepository
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.VaryingModelRepository
|
||||
import com.cobblemon.mod.common.client.render.npc.NPCRenderer
|
||||
import com.cobblemon.mod.common.client.render.pokeball.PokeBallRenderer
|
||||
import com.cobblemon.mod.common.client.render.pokemon.PokemonRenderer
|
||||
@@ -50,18 +60,22 @@ import com.cobblemon.mod.common.client.requests.ClientPlayerActionRequests
|
||||
import com.cobblemon.mod.common.client.sound.BattleMusicController
|
||||
import com.cobblemon.mod.common.client.sound.EntitySoundTracker
|
||||
import com.cobblemon.mod.common.client.storage.ClientStorageManager
|
||||
import com.cobblemon.mod.common.client.tooltips.*
|
||||
import com.cobblemon.mod.common.client.tooltips.AprijuiceTooltipGenerator
|
||||
import com.cobblemon.mod.common.client.tooltips.CobblemonTooltipGenerator
|
||||
import com.cobblemon.mod.common.client.tooltips.FishingBaitTooltipGenerator
|
||||
import com.cobblemon.mod.common.client.tooltips.FishingRodTooltipGenerator
|
||||
import com.cobblemon.mod.common.client.tooltips.PokePuffTooltipGenerator
|
||||
import com.cobblemon.mod.common.client.tooltips.RecipeSeasoningAbsorbtionTooltipGenerator
|
||||
import com.cobblemon.mod.common.client.tooltips.SeasoningTooltipGenerator
|
||||
import com.cobblemon.mod.common.client.tooltips.TooltipManager
|
||||
import com.cobblemon.mod.common.client.trade.ClientTrade
|
||||
import com.cobblemon.mod.common.data.CobblemonDataProvider
|
||||
import com.cobblemon.mod.common.entity.boat.CobblemonBoatType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.item.food.SinisterTeaItem
|
||||
import com.cobblemon.mod.common.platform.events.PlatformEvents
|
||||
import com.cobblemon.mod.common.pokedex.scanner.PokedexUsageContext
|
||||
import com.cobblemon.mod.common.util.isLookingAt
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.color.block.BlockColor
|
||||
import net.minecraft.client.color.item.ItemColor
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.client.gui.screens.MenuScreens
|
||||
import net.minecraft.client.gui.screens.Screen
|
||||
@@ -421,5 +435,4 @@ object CobblemonClient {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.client.persisted.ClientPersistedData
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.client.CameraType
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.entity.Entity
|
||||
|
||||
/**
|
||||
* The purpose here is to keep track of the last camera type that was used for each riding behaviour or just
|
||||
* the last overall, then change the camera type where necessary when mounting/dismounting or switching
|
||||
* between different riding behaviours. This is dependent on a config option, but the general idea is we
|
||||
* want the camera to be whatever the player feels most comfy with without them having to fiddle with it
|
||||
* more than once.
|
||||
*/
|
||||
object MountedCameraTypeHandler {
|
||||
var unmountedCameraType: CameraType = CameraType.FIRST_PERSON
|
||||
|
||||
fun handleMount(passenger: Entity, vehicle: PokemonEntity) {
|
||||
val mc = Minecraft.getInstance()
|
||||
val key = vehicle.ridingController?.context?.settings?.key
|
||||
if (passenger != mc.player || key == null) {
|
||||
return
|
||||
}
|
||||
unmountedCameraType = mc.options.cameraType
|
||||
val data = ClientPersistedData.ridingPerspectives
|
||||
if (Cobblemon.config.rememberRidingCamera) {
|
||||
val lastCameraTypeForKey = data.perspectives[key]
|
||||
if (lastCameraTypeForKey != null) {
|
||||
mc.options.cameraType = lastCameraTypeForKey
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun handleDismount(passenger: Entity, vehicle: PokemonEntity) {
|
||||
val mc = Minecraft.getInstance()
|
||||
val key = vehicle.ridingController?.context?.settings?.key
|
||||
if (passenger != mc.player || key == null) {
|
||||
return
|
||||
}
|
||||
val currentCameraType = mc.options.cameraType
|
||||
if (currentCameraType != unmountedCameraType) {
|
||||
mc.options.cameraType = unmountedCameraType
|
||||
}
|
||||
val data = ClientPersistedData.ridingPerspectives
|
||||
data.updatePerspective(key, currentCameraType)
|
||||
}
|
||||
|
||||
fun handleTransition(fromKey: ResourceLocation, toKey: ResourceLocation) {
|
||||
val mc = Minecraft.getInstance()
|
||||
val currentCameraType = mc.options.cameraType
|
||||
val data = ClientPersistedData.ridingPerspectives
|
||||
data.updatePerspective(fromKey, currentCameraType)
|
||||
if (Cobblemon.config.rememberRidingCamera) {
|
||||
val lastCameraTypeForKey = data.perspectives[toKey]
|
||||
if (lastCameraTypeForKey != null) {
|
||||
mc.options.cameraType = lastCameraTypeForKey
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
@@ -12,7 +12,9 @@ import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
|
||||
import com.cobblemon.mod.common.config.CobblemonConfig
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
import com.cobblemon.mod.common.util.ifServer
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.cobblemon.mod.common.util.runOnServer
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.components.Button
|
||||
import net.minecraft.client.gui.components.EditBox
|
||||
@@ -43,6 +45,7 @@ class CobblemonConfigScreen(
|
||||
|
||||
val clonedConfig = Cobblemon.config.clone()
|
||||
val defaultConfig = CobblemonConfig()
|
||||
val hideServerConfigs = Minecraft.getInstance().currentServer != null && !Minecraft.getInstance().isLocalServer
|
||||
|
||||
private lateinit var layout: HeaderAndFooterLayout
|
||||
private lateinit var searchEdit: EditBox
|
||||
|
||||
+7
@@ -21,6 +21,7 @@ import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.config.Category
|
||||
import com.cobblemon.mod.common.config.CobblemonConfig
|
||||
import com.cobblemon.mod.common.config.CobblemonConfigField
|
||||
import com.cobblemon.mod.common.config.CobblemonConfigField.CobblemonConfigSide.SERVER
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
import net.minecraft.SharedConstants
|
||||
import net.minecraft.client.Minecraft
|
||||
@@ -32,6 +33,7 @@ import net.minecraft.client.gui.narration.NarratableEntry
|
||||
import kotlin.math.min
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KMutableProperty1
|
||||
import kotlin.reflect.full.findAnnotation
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.jvm.javaField
|
||||
|
||||
@@ -62,6 +64,11 @@ class CobblemonConfigVariableList(
|
||||
return@map null
|
||||
}
|
||||
|
||||
val fieldAnnotation = property.javaField!!.getAnnotation(CobblemonConfigField::class.java)
|
||||
if (parent.hideServerConfigs && fieldAnnotation.side == SERVER) {
|
||||
return@map null
|
||||
}
|
||||
|
||||
val entry: CobblemonConfigVariable? =
|
||||
when (val classifier = property.returnType.classifier) {
|
||||
String::class -> CobblemonConfigStringVariable(this, property as KMutableProperty1<out CobblemonConfig, String>)
|
||||
|
||||
+26
-4
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.client.gui.debug.riding
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.CobblemonNetwork
|
||||
import com.cobblemon.mod.common.CobblemonRideSettings
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
@@ -89,7 +90,7 @@ class RideSettingsEditorGUI(val parentScreen: Screen, val vehicle: PokemonEntity
|
||||
for (variable in expressionVariables) {
|
||||
val (name, value) = variable
|
||||
|
||||
val editBox = EditBox(this.minecraft!!.font, 110, currentY, 300, 20, name.text())
|
||||
val editBox = EditBox(this.minecraft!!.font, 130, currentY, 300, 20, name.text())
|
||||
editBox.setMaxLength(256)
|
||||
editBox.value = value
|
||||
|
||||
@@ -158,6 +159,10 @@ class RideSettingsEditorGUI(val parentScreen: Screen, val vehicle: PokemonEntity
|
||||
val clazz = settings.javaClass
|
||||
val fields = clazz.declaredFields
|
||||
|
||||
val gsField = CobblemonRideSettings.javaClass.declaredFields.firstOrNull { it.type == clazz }
|
||||
gsField?.isAccessible = true
|
||||
val controllerGlobalSettings = gsField?.get(CobblemonRideSettings) as? RidingBehaviourSettings?
|
||||
|
||||
// Iterate through all expression fields and return the list of those that
|
||||
// aer expressions
|
||||
return fields.mapNotNull { field ->
|
||||
@@ -165,10 +170,18 @@ class RideSettingsEditorGUI(val parentScreen: Screen, val vehicle: PokemonEntity
|
||||
field.isAccessible = true // Make private fields accessible
|
||||
val name = field.name
|
||||
// Get the value, cast it, and call .getString() on it
|
||||
val value = (field.get(settings) as Expression).getString()
|
||||
if (field.get(settings) != null) {
|
||||
val value = (field.get(settings) as Expression).getString()
|
||||
|
||||
// Create the pair and return it for the list
|
||||
name to value
|
||||
// Create the pair and return it for the list
|
||||
name to value
|
||||
|
||||
} else {
|
||||
// If the settings field is null then check for a global setting
|
||||
val value = getMatchingGlobalSettingsValue(settings, controllerGlobalSettings, name) ?: "novalue"
|
||||
|
||||
name to value
|
||||
}
|
||||
} else {
|
||||
// If it's not an Expression (they all honestly should be if being used by the
|
||||
// behaviour in question) then ignore
|
||||
@@ -176,4 +189,13 @@ class RideSettingsEditorGUI(val parentScreen: Screen, val vehicle: PokemonEntity
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMatchingGlobalSettingsValue(settings: RidingBehaviourSettings, globalSettings: RidingBehaviourSettings?, fieldName: String): String? {
|
||||
if (globalSettings == null) return null
|
||||
val gssField = globalSettings.javaClass.declaredFields.firstOrNull {
|
||||
it.name == fieldName
|
||||
}
|
||||
gssField?.isAccessible = true
|
||||
return (gssField?.get(globalSettings) as? Expression)?.getString()
|
||||
}
|
||||
}
|
||||
+28
-23
@@ -25,6 +25,8 @@ import com.cobblemon.mod.common.client.gui.summary.widgets.SoundlessWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.stats.features.FriendshipFeatureRenderer
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.stats.features.FullnessFeatureRenderer
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.pokemon.EVs
|
||||
import com.cobblemon.mod.common.pokemon.IVs
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
@@ -74,6 +76,7 @@ class StatWidget(
|
||||
private val statsBaseResource = cobblemonResource("textures/gui/summary/summary_stats_chart_base.png")
|
||||
private val statsChartResource = cobblemonResource("textures/gui/summary/summary_stats_chart.png")
|
||||
private val statsChartPentagonResource = cobblemonResource("textures/gui/summary/summary_stats_chart_pentagon.png")
|
||||
private val statsChartPentagonHighlightResource = cobblemonResource("textures/gui/summary/summary_stats_chart_pentagon_highlight.png")
|
||||
private val statsOtherBaseResource = cobblemonResource("textures/gui/summary/summary_stats_other_base.png")
|
||||
private val statsOtherSidebarsResource = cobblemonResource("textures/gui/summary/summary_stats_other_sidebars.png")
|
||||
private val statsOtherSidebarArrowLeft = cobblemonResource("textures/gui/summary/summary_stats_other_sidebar_arrow_left.png")
|
||||
@@ -290,33 +293,34 @@ class StatWidget(
|
||||
}
|
||||
} else {
|
||||
if (renderPentagonStats) {
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = statsChartPentagonResource,
|
||||
x= (x + 20.5) / SCALE,
|
||||
y = (y + 22) / SCALE,
|
||||
width = 186,
|
||||
height = 176,
|
||||
scale = SCALE
|
||||
)
|
||||
|
||||
pokemon.form.riding.behaviours?.let {
|
||||
val behaviours = it.entries.toList()
|
||||
val selectedBehaviour = behaviours[rideBehaviourIndex]
|
||||
val canSwitchStyle = behaviours.size > 1 && centerHovered(pMouseX, pMouseY)
|
||||
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = if (canSwitchStyle) statsChartPentagonHighlightResource else statsChartPentagonResource,
|
||||
x= (x + 20.5) / SCALE,
|
||||
y = (y + 22) / SCALE,
|
||||
width = 186,
|
||||
height = 176,
|
||||
scale = SCALE
|
||||
)
|
||||
|
||||
val pentagonColour = when (selectedBehaviour.key) {
|
||||
RidingStyle.AIR -> {
|
||||
if (behaviours.size > 1 && centerHovered(pMouseX, pMouseY))
|
||||
if (canSwitchStyle)
|
||||
Vector3f(70F/255F, 235F/225F, 195F/255F)
|
||||
else Vector3f(40F/255F, 205F/255F, 165F/255F)
|
||||
}
|
||||
RidingStyle.LIQUID -> {
|
||||
if (behaviours.size > 1 && centerHovered(pMouseX, pMouseY))
|
||||
if (canSwitchStyle)
|
||||
Vector3f(95F/255F, 165F/255F, 1F)
|
||||
else Vector3f(65F/255F, 135F/255F, 1F)
|
||||
}
|
||||
else -> {
|
||||
if (behaviours.size > 1 && centerHovered(pMouseX, pMouseY))
|
||||
if (canSwitchStyle)
|
||||
Vector3f(1F, 195F/255F, 30F/255F)
|
||||
else Vector3f(1F, 165F/255F, 0F)
|
||||
}
|
||||
@@ -353,8 +357,8 @@ class StatWidget(
|
||||
context = context,
|
||||
labels = RidingStat.entries.toList().map { stat ->
|
||||
if (statLabelsHovered(pentagonVerticesOffset, pMouseX, pMouseY))
|
||||
"${floor((pokemon.getRideStat(selectedBehaviour.key, stat) / (selectedBehaviour.value.stats[stat]?.endInclusive ?: 1)) * 100)}%".text()
|
||||
else floor(pokemon.getRideStat(selectedBehaviour.key, stat)).toString().text()
|
||||
"+${floor(pokemon.getRideBoost(stat) / pokemon.getMaxRideBoost(stat) * 100)}%".text()
|
||||
else floor(pokemon.getRideStat(selectedBehaviour.key, stat)).toString().text()
|
||||
},
|
||||
verticesOffset = pentagonVerticesOffset,
|
||||
offsetY = 5.5
|
||||
@@ -389,7 +393,7 @@ class StatWidget(
|
||||
colour = Vector3f(216F/255, 100F/255, 1F)
|
||||
)
|
||||
EV -> drawStatPolygon(
|
||||
statLabels.values.map { (pokemon.evs[it]?.toFloat() ?: 0F) / 252F },
|
||||
statLabels.values.map { (pokemon.evs[it]?.toFloat() ?: 0F) / EVs.MAX_STAT_VALUE.toFloat() },
|
||||
colour = Vector3f(1F, 1F, 100F/255F)
|
||||
)
|
||||
}
|
||||
@@ -403,9 +407,9 @@ class StatWidget(
|
||||
"${
|
||||
if (pokemon.ivs.isHyperTrained(stat.value)) "${pokemon.ivs[stat.value]} (${pokemon.ivs.hyperTrainedIVs[stat.value]})"
|
||||
else pokemon.ivs[stat.value].toString()
|
||||
}/31".text()
|
||||
}/${IVs.MAX_VALUE}".text()
|
||||
}
|
||||
EV -> "${pokemon.evs.getOrDefault(stat.value)}/252".text()
|
||||
EV -> "${pokemon.evs.getOrDefault(stat.value)}/${EVs.MAX_STAT_VALUE}".text()
|
||||
else -> stat.key
|
||||
}
|
||||
} else { stat.key }
|
||||
@@ -427,8 +431,7 @@ class StatWidget(
|
||||
labelsHovered
|
||||
),
|
||||
verticesOffset = hexagonVerticesOffset,
|
||||
offsetY = 5.5,
|
||||
enableColour = true
|
||||
offsetY = 5.5
|
||||
)
|
||||
|
||||
// Nature-modified Stat Icons
|
||||
@@ -491,14 +494,14 @@ class StatWidget(
|
||||
STATS -> (if (stat == Stats.HP) "${pokemon.currentHealth} / ${pokemon.maxHealth}" else pokemon.getStat(stat).toString()).text()
|
||||
IV -> {
|
||||
(if (asPercent) {
|
||||
"${floor((((if (pokemon.ivs.isHyperTrained(stat)) pokemon.ivs.hyperTrainedIVs[stat] else pokemon.ivs[stat]) ?: 0) / 31.0) * 100)}%"
|
||||
"${floor((((if (pokemon.ivs.isHyperTrained(stat)) pokemon.ivs.hyperTrainedIVs[stat] else pokemon.ivs[stat]) ?: 0) / IVs.MAX_VALUE.toDouble()) * 100)}%"
|
||||
} else {
|
||||
if (pokemon.ivs.isHyperTrained(stat)) "${pokemon.ivs[stat]} (${pokemon.ivs.hyperTrainedIVs[stat]})"
|
||||
else pokemon.ivs[stat].toString()
|
||||
}).text()
|
||||
}
|
||||
EV -> {
|
||||
(if (asPercent) "${floor((pokemon.evs.getOrDefault(stat) / 252.0) * 100)}%"
|
||||
(if (asPercent) "${floor((pokemon.evs.getOrDefault(stat) / EVs.MAX_STAT_VALUE.toDouble()) * 100)}%"
|
||||
else pokemon.evs.getOrDefault(stat).toString()).text()
|
||||
}
|
||||
else -> "0".text()
|
||||
@@ -559,7 +562,9 @@ class StatWidget(
|
||||
}
|
||||
|
||||
private fun centerHovered(pMouseX: Number, pMouseY: Number): Boolean {
|
||||
return (pMouseX.toInt() in (x + 44)..(x + 90)) && (pMouseY.toInt() in (y + 47)..(y + 93))
|
||||
val centerX = x + (WIDTH / 2)
|
||||
val centerY = y + (HEIGHT / 2)
|
||||
return (pMouseX.toInt() in (centerX - 30)..(centerX + 30)) && (pMouseY.toInt() in (centerY - 30)..(centerY + 30))
|
||||
}
|
||||
|
||||
private fun statLabelsHovered(labelOffsets: List<Pair<Double, Double>>, mouseX: Int, mouseY: Int): Boolean {
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.net.data
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonRideSettings
|
||||
import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.net.messages.client.data.RideSettingsSyncPacket
|
||||
import net.minecraft.client.Minecraft
|
||||
|
||||
object RideSettingsSyncHandler : ClientNetworkPacketHandler<RideSettingsSyncPacket> {
|
||||
override fun handle(packet: RideSettingsSyncPacket, client: Minecraft) {
|
||||
CobblemonRideSettings.bird = packet.bird
|
||||
CobblemonRideSettings.glider = packet.glider
|
||||
CobblemonRideSettings.helicopter = packet.helicopter
|
||||
CobblemonRideSettings.hover = packet.hover
|
||||
CobblemonRideSettings.jet = packet.jet
|
||||
CobblemonRideSettings.rocket = packet.rocket
|
||||
|
||||
CobblemonRideSettings.horse = packet.horse
|
||||
CobblemonRideSettings.minekart = packet.minekart
|
||||
CobblemonRideSettings.vehicle = packet.vehicle
|
||||
|
||||
CobblemonRideSettings.boat = packet.boat
|
||||
CobblemonRideSettings.burst = packet.burst
|
||||
CobblemonRideSettings.dolphin = packet.dolphin
|
||||
}
|
||||
}
|
||||
+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.client.persisted
|
||||
|
||||
import com.cobblemon.mod.common.config.CobblemonConfig
|
||||
import java.io.BufferedReader
|
||||
import java.io.BufferedWriter
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileWriter
|
||||
import java.io.InputStreamReader
|
||||
import java.nio.file.Paths
|
||||
import kotlin.io.path.exists
|
||||
import net.minecraft.client.CameraType
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
object ClientPersistedData {
|
||||
|
||||
val gson = CobblemonConfig.GSON
|
||||
|
||||
val snapshotsPath = Paths.get("cobblemon").resolve("snapshots.json")
|
||||
val ridingPerspectivesPath = Paths.get("cobblemon").resolve("riding_perspectives.json")
|
||||
|
||||
var ridingPerspectives: RidingPerspectiveData = readRidingPerspectivesData() ?: RidingPerspectiveData()
|
||||
|
||||
fun readSnapshotsData() : SnapshotAcknowledgementData? {
|
||||
if (snapshotsPath.exists()) {
|
||||
BufferedReader(InputStreamReader(FileInputStream(snapshotsPath.toFile()))).use { reader ->
|
||||
return gson.fromJson(reader, SnapshotAcknowledgementData::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
fun writeSnapshotsData(data: SnapshotAcknowledgementData) {
|
||||
snapshotsPath.toFile().parentFile.mkdirs()
|
||||
BufferedWriter(FileWriter(snapshotsPath.toFile())).use { writer -> gson.toJson(data, writer) }
|
||||
}
|
||||
|
||||
fun readRidingPerspectivesData() : RidingPerspectiveData? {
|
||||
if (ridingPerspectivesPath.exists()) {
|
||||
BufferedReader(InputStreamReader(FileInputStream(ridingPerspectivesPath.toFile()))).use { reader ->
|
||||
return gson.fromJson(reader, RidingPerspectiveData::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
fun saveRidingPerspectivesData() {
|
||||
ridingPerspectivesPath.toFile().parentFile.mkdirs()
|
||||
BufferedWriter(FileWriter(ridingPerspectivesPath.toFile())).use { writer -> gson.toJson(ridingPerspectives, writer) }
|
||||
}
|
||||
|
||||
data class SnapshotAcknowledgementData(val version: String, val dontShowAgain: Boolean)
|
||||
data class RidingPerspectiveData(
|
||||
val perspectives: MutableMap<ResourceLocation, CameraType> = mutableMapOf()
|
||||
) {
|
||||
fun updatePerspective(key: ResourceLocation, cameraType: CameraType) {
|
||||
perspectives[key] = cameraType
|
||||
saveRidingPerspectivesData()
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -125,7 +125,7 @@ class CampfireBlockEntityRenderer(ctx: BlockEntityRendererProvider.Context) : Bl
|
||||
) {
|
||||
val seasonings = blockEntity.getSeasonings()
|
||||
|
||||
val gameTime = (blockEntity.level?.gameTime ?: 0) + tickDelta
|
||||
val gameTime = blockEntity.time + tickDelta
|
||||
val rotationAngle = (gameTime * ROTATION_SPEED) % 360
|
||||
|
||||
seasonings.forEachIndexed { index, seasoning ->
|
||||
|
||||
+15
-3
@@ -17,10 +17,12 @@ import com.cobblemon.mod.common.util.math.fromEulerXYZDegrees
|
||||
import com.mojang.blaze3d.platform.Lighting
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer
|
||||
import com.mojang.blaze3d.vertex.VertexMultiConsumer
|
||||
import net.minecraft.client.renderer.LightTexture
|
||||
import net.minecraft.client.renderer.MultiBufferSource
|
||||
import net.minecraft.client.renderer.RenderType
|
||||
import net.minecraft.client.renderer.texture.OverlayTexture
|
||||
import net.minecraft.core.component.DataComponents
|
||||
import net.minecraft.world.item.ItemDisplayContext
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import org.joml.Quaternionf
|
||||
@@ -46,8 +48,6 @@ class PokemonItemRenderer : CobblemonBuiltinItemRenderer {
|
||||
context.put(RenderContext.POSABLE_STATE, state)
|
||||
state.currentModel = model
|
||||
|
||||
val renderLayer = RenderType.entityCutout(VaryingModelRepository.getTexture(species.resourceIdentifier, state))
|
||||
|
||||
val transformations = positions[mode]!!
|
||||
|
||||
if (mode == ItemDisplayContext.GUI) {
|
||||
@@ -64,7 +64,19 @@ class PokemonItemRenderer : CobblemonBuiltinItemRenderer {
|
||||
val rotation = Quaternionf().fromEulerXYZDegrees(Vector3f(transformations.rotation.x, transformations.rotation.y, transformations.rotation.z))
|
||||
matrices.mulPose(rotation)
|
||||
rotation.conjugate()
|
||||
val vertexConsumer: VertexConsumer = vertexConsumers.getBuffer(renderLayer)
|
||||
|
||||
val renderLayer = RenderType.entityCutout(VaryingModelRepository.getTexture(species.resourceIdentifier, state))
|
||||
val isEnchanted = stack.get(DataComponents.ENCHANTMENTS)?.isEmpty == false
|
||||
val vertexConsumer: VertexConsumer =
|
||||
if (isEnchanted) {
|
||||
VertexMultiConsumer.create(
|
||||
vertexConsumers.getBuffer(RenderType.entityGlintDirect()),
|
||||
vertexConsumers.getBuffer(renderLayer),
|
||||
)
|
||||
} else {
|
||||
vertexConsumers.getBuffer(renderLayer)
|
||||
}
|
||||
|
||||
matrices.pushPose()
|
||||
val packedLight = if (mode == ItemDisplayContext.GUI) {
|
||||
LightTexture.pack(13, 13)
|
||||
|
||||
+1
-1
@@ -267,7 +267,7 @@ class TexturedModel {
|
||||
var counter = 0
|
||||
subParts.forEachIndexed { index, part ->
|
||||
parts[bone.name]!!.addOrReplaceChild(
|
||||
bone.name + counter++.toString(),
|
||||
"%" + bone.name + "%" + counter++.toString(),
|
||||
part,
|
||||
modelTransforms[index]
|
||||
)
|
||||
|
||||
-67
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen5
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class BeheeyemModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame, BimanualFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("beheeyem")
|
||||
override val head = getPart("head")
|
||||
override val rightArm = getPart("arm_right")
|
||||
override val leftArm = getPart("arm_left")
|
||||
override val rightLeg = getPart("leg_right")
|
||||
override val leftLeg = getPart("leg_left")
|
||||
|
||||
override var portraitScale = 3.0F
|
||||
override var portraitTranslation = Vec3(-0.34, -0.8, 0.0)
|
||||
|
||||
override var profileScale = 0.8F
|
||||
override var profileTranslation = Vec3(0.0, 0.6, 0.0)
|
||||
|
||||
lateinit var sleep: Pose
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("beheeyem", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
animations = arrayOf(bedrock("beheeyem", "sleep"))
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
|
||||
transformTicks = 10,
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("beheeyem", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = PoseType.MOVING_POSES,
|
||||
transformTicks = 5,
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("beheeyem", "ground_walk")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
-94
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen5
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.CobblemonPose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.util.isBattling
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class ChandelureModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("chandelure")
|
||||
override val head = getPart("head")
|
||||
|
||||
override var portraitScale = 1.85F
|
||||
override var portraitTranslation = Vec3(-0.3, -0.19, 0.0)
|
||||
|
||||
override var profileScale = 0.81F
|
||||
override var profileTranslation = Vec3(0.0, 0.68, 0.0)
|
||||
|
||||
lateinit var standing: CobblemonPose
|
||||
lateinit var walk: CobblemonPose
|
||||
lateinit var hover: CobblemonPose
|
||||
lateinit var flying: CobblemonPose
|
||||
lateinit var battle_idle: CobblemonPose
|
||||
lateinit var sleep: CobblemonPose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("chandelure", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("chandelure", "blink") }
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES - PoseType.HOVER,
|
||||
quirks = arrayOf(blink),
|
||||
condition = { !it.isBattling },
|
||||
animations = arrayOf(
|
||||
bedrock("chandelure", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = PoseType.MOVING_POSES - PoseType.FLY,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("chandelure", "ground_walk")
|
||||
)
|
||||
)
|
||||
|
||||
hover = registerPose(
|
||||
poseName = "hover",
|
||||
poseType = PoseType.HOVER,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("chandelure", "air_idle")
|
||||
)
|
||||
)
|
||||
|
||||
flying = registerPose(
|
||||
poseName = "flying",
|
||||
poseType = PoseType.FLY,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("chandelure", "air_fly")
|
||||
)
|
||||
)
|
||||
|
||||
battle_idle = registerPose(
|
||||
poseName = "battle_idle",
|
||||
poseTypes = PoseType.STATIONARY_POSES,
|
||||
quirks = arrayOf(blink),
|
||||
condition = { it.isBattling },
|
||||
animations = arrayOf(
|
||||
bedrock("chandelure", "battle_idle")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// override fun getFaintAnimation(
|
||||
// pokemonEntity: PokemonEntity,
|
||||
// state: PosableState<PokemonEntity>
|
||||
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("chandelure", "faint") else null
|
||||
}
|
||||
-113
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen5
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.createTransformation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.ModelPartTransformation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.util.isBattling
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class ElgyemModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame, BimanualFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("elgyem")
|
||||
override val head = getPart("head")
|
||||
override val rightArm = getPart("arm_right")
|
||||
override val leftArm = getPart("arm_left")
|
||||
override val rightLeg = getPart("leg_right")
|
||||
override val leftLeg = getPart("leg_left")
|
||||
|
||||
override var portraitScale = 2.5F
|
||||
override var portraitTranslation = Vec3(-0.2, -0.8, 0.0)
|
||||
|
||||
override var profileScale = 0.85F
|
||||
override var profileTranslation = Vec3(0.0, 0.5, 0.0)
|
||||
|
||||
lateinit var sleep: Pose
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
lateinit var battleidle: Pose
|
||||
lateinit var shoulderLeft: Pose
|
||||
lateinit var shoulderRight: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("elgyem", "cry") }
|
||||
|
||||
val shoulderOffset = 5.6
|
||||
|
||||
override fun registerPoses() {
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
animations = arrayOf(bedrock("elgyem", "sleep"))
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
|
||||
transformTicks = 10,
|
||||
condition = { !it.isBattling },
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("elgyem", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = PoseType.MOVING_POSES,
|
||||
transformTicks = 5,
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("elgyem", "ground_walk")
|
||||
)
|
||||
)
|
||||
|
||||
battleidle = registerPose(
|
||||
poseName = "battle_idle",
|
||||
poseTypes = PoseType.STATIONARY_POSES,
|
||||
transformTicks = 10,
|
||||
condition = { it.isBattling },
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("elgyem", "battle_idle")
|
||||
)
|
||||
)
|
||||
|
||||
shoulderLeft = registerPose(
|
||||
poseType = PoseType.SHOULDER_LEFT,
|
||||
//quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("elgyem", "ground_idle")
|
||||
),
|
||||
transformedParts = arrayOf(
|
||||
rootPart.createTransformation().addPosition(ModelPartTransformation.X_AXIS, shoulderOffset)
|
||||
)
|
||||
)
|
||||
|
||||
shoulderRight = registerPose(
|
||||
poseType = PoseType.SHOULDER_RIGHT,
|
||||
//quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("elgyem", "ground_idle")
|
||||
),
|
||||
transformedParts = arrayOf(
|
||||
rootPart.createTransformation().addPosition(ModelPartTransformation.X_AXIS, -shoulderOffset)
|
||||
)
|
||||
)
|
||||
}
|
||||
override fun getFaintAnimation(state: PosableState) = if (state.isPosedIn(standing, walk, battleidle, sleep)) bedrockStateful("elgyem", "faint") else null
|
||||
}
|
||||
-102
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen5
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.CobblemonPose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.util.isBattling
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class LampentModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("lampent")
|
||||
override val head = getPart("head")
|
||||
|
||||
override var portraitScale = 2.2F
|
||||
override var portraitTranslation = Vec3(-0.19, -0.17, 0.0)
|
||||
|
||||
override var profileScale = 0.8F
|
||||
override var profileTranslation = Vec3(0.0, 0.7, 0.0)
|
||||
|
||||
lateinit var standing: CobblemonPose
|
||||
lateinit var walk: CobblemonPose
|
||||
lateinit var hover: CobblemonPose
|
||||
lateinit var flying: CobblemonPose
|
||||
lateinit var battle_idle: CobblemonPose
|
||||
lateinit var sleep: CobblemonPose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("lampent", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("lampent", "blink") }
|
||||
|
||||
sleep = registerPose(
|
||||
poseName = "sleep",
|
||||
poseType = PoseType.SLEEP,
|
||||
animations = arrayOf(
|
||||
bedrock("lampent", "sleep")
|
||||
)
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES - PoseType.HOVER,
|
||||
quirks = arrayOf(blink),
|
||||
condition = { !it.isBattling },
|
||||
animations = arrayOf(
|
||||
bedrock("lampent", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = PoseType.MOVING_POSES - PoseType.FLY,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("lampent", "ground_walk")
|
||||
)
|
||||
)
|
||||
|
||||
hover = registerPose(
|
||||
poseName = "hover",
|
||||
poseType = PoseType.HOVER,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("lampent", "air_idle")
|
||||
)
|
||||
)
|
||||
|
||||
flying = registerPose(
|
||||
poseName = "flying",
|
||||
poseType = PoseType.FLY,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("lampent", "air_fly")
|
||||
)
|
||||
)
|
||||
|
||||
battle_idle = registerPose(
|
||||
poseName = "battle_idle",
|
||||
poseTypes = PoseType.STATIONARY_POSES,
|
||||
quirks = arrayOf(blink),
|
||||
condition = { it.isBattling },
|
||||
animations = arrayOf(
|
||||
bedrock("lampent", "battle_idle")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// override fun getFaintAnimation(
|
||||
// pokemonEntity: PokemonEntity,
|
||||
// state: PosableState<PokemonEntity>
|
||||
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("lampent", "faint") else null
|
||||
}
|
||||
-110
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen5
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.createTransformation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.CobblemonPose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.util.isBattling
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class LitwickModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("litwick")
|
||||
override val head = getPart("head")
|
||||
|
||||
override var portraitScale = 2.33F
|
||||
override var portraitTranslation = Vec3(0.01, -1.9, 0.0)
|
||||
|
||||
override var profileScale = 0.86F
|
||||
override var profileTranslation = Vec3(0.0, 0.44, 0.0)
|
||||
|
||||
lateinit var standing: CobblemonPose
|
||||
lateinit var walk: CobblemonPose
|
||||
lateinit var sleep: CobblemonPose
|
||||
lateinit var battle_idle: CobblemonPose
|
||||
lateinit var shoulderLeft: CobblemonPose
|
||||
lateinit var shoulderRight: CobblemonPose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("litwick", "cry") }
|
||||
|
||||
val shoulderOffset = 5.5
|
||||
val wax = getPart("wax_trail")
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("litwick", "blink") }
|
||||
|
||||
sleep = registerPose(
|
||||
poseName = "sleep",
|
||||
poseType = PoseType.SLEEP,
|
||||
animations = arrayOf(
|
||||
bedrock("litwick", "sleep")
|
||||
)
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
|
||||
condition = { !it.isBattling },
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("litwick", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = PoseType.MOVING_POSES,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("litwick", "ground_walk")
|
||||
)
|
||||
)
|
||||
|
||||
battle_idle = registerPose(
|
||||
poseName = "battle_idle",
|
||||
poseTypes = PoseType.STATIONARY_POSES,
|
||||
quirks = arrayOf(blink),
|
||||
condition = { it.isBattling },
|
||||
animations = arrayOf(
|
||||
bedrock("litwick", "battle_idle")
|
||||
)
|
||||
)
|
||||
|
||||
shoulderLeft = registerPose(
|
||||
poseType = PoseType.SHOULDER_LEFT,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("litwick", "ground_idle")
|
||||
),
|
||||
transformedParts = arrayOf(
|
||||
wax.createTransformation().withVisibility(visibility = false)
|
||||
)
|
||||
)
|
||||
|
||||
shoulderRight = registerPose(
|
||||
poseType = PoseType.SHOULDER_RIGHT,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("litwick", "ground_idle")
|
||||
),
|
||||
transformedParts = arrayOf(
|
||||
wax.createTransformation().withVisibility(visibility = false)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// override fun getFaintAnimation(
|
||||
// pokemonEntity: PokemonEntity,
|
||||
// state: PosableState<PokemonEntity>
|
||||
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("litwick", "faint") else null
|
||||
}
|
||||
-5
@@ -361,8 +361,6 @@ object VaryingModelRepository {
|
||||
inbuilt("chespin", :: ChespinModel)
|
||||
inbuilt("quilladin", :: QuilladinModel)
|
||||
inbuilt("chesnaught", :: ChesnaughtModel)
|
||||
inbuilt("elgyem", :: ElgyemModel)
|
||||
inbuilt("beheeyem", :: BeheeyemModel)
|
||||
inbuilt("pineco", :: PinecoModel)
|
||||
inbuilt("forretress", :: ForretressModel)
|
||||
inbuilt("lotad", :: LotadModel)
|
||||
@@ -554,9 +552,6 @@ object VaryingModelRepository {
|
||||
inbuilt("gurdurr", ::GurdurrModel)
|
||||
inbuilt("conkeldurr", ::ConkeldurrModel)
|
||||
inbuilt("clodsire", ::ClodsireModel)
|
||||
inbuilt("litwick", ::LitwickModel)
|
||||
inbuilt("lampent", ::LampentModel)
|
||||
inbuilt("chandelure", ::ChandelureModel)
|
||||
inbuilt("gimmighoulchest", ::GimmighoulChestModel)
|
||||
inbuilt("drifloon", ::DrifloonModel)
|
||||
inbuilt("lileep", ::LileepModel)
|
||||
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.snapshots
|
||||
|
||||
import com.cobblemon.mod.common.config.CobblemonConfig
|
||||
import java.io.BufferedReader
|
||||
import java.io.BufferedWriter
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileWriter
|
||||
import java.io.InputStreamReader
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
import kotlin.io.path.exists
|
||||
|
||||
object SnapshotAcknowledgementReader {
|
||||
|
||||
val gson = CobblemonConfig.GSON
|
||||
val target: Path = Paths.get("cobblemon").resolve("snapshots.json")
|
||||
|
||||
fun read() : SnapshotAcknowledgementData? {
|
||||
if (target.exists()) {
|
||||
BufferedReader(InputStreamReader(FileInputStream(target.toFile()))).use { reader ->
|
||||
return gson.fromJson(reader, SnapshotAcknowledgementData::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
fun write(data: SnapshotAcknowledgementData) {
|
||||
target.toFile().parentFile.mkdirs()
|
||||
BufferedWriter(FileWriter(target.toFile())).use { writer -> gson.toJson(data, writer) }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
data class SnapshotAcknowledgementData(val version: String, val dontShowAgain: Boolean)
|
||||
-3
@@ -23,9 +23,6 @@ object CobblemonTooltipGenerator : TooltipGenerator() {
|
||||
val resultLines = mutableListOf<Component>()
|
||||
|
||||
if (stack.item.builtInRegistryHolder().unwrapKey().isPresent && stack.item.builtInRegistryHolder().unwrapKey().get().location().namespace == Cobblemon.MODID) {
|
||||
if (stack.get(DataComponents.HIDE_ADDITIONAL_TOOLTIP) != null) {
|
||||
return null
|
||||
}
|
||||
val language = Language.getInstance()
|
||||
val key = this.baseLangKeyForItem(stack)
|
||||
if (language.has(key)) {
|
||||
|
||||
-6
@@ -31,9 +31,6 @@ object FishingBaitTooltipGenerator : TooltipGenerator() {
|
||||
private val fishingBaitItemClass by lazy { lang("item_class.fishing_bait").blue() }
|
||||
|
||||
override fun generateCategoryTooltip(stack: ItemStack, lines: MutableList<Component>): MutableList<Component>? {
|
||||
if (stack.get(DataComponents.HIDE_ADDITIONAL_TOOLTIP) != null) {
|
||||
return null
|
||||
}
|
||||
if (!SpawnBaitEffects.isFishingBait(stack)) {
|
||||
return null
|
||||
}
|
||||
@@ -41,9 +38,6 @@ object FishingBaitTooltipGenerator : TooltipGenerator() {
|
||||
}
|
||||
|
||||
override fun generateAdditionalTooltip(stack: ItemStack, lines: MutableList<Component>): MutableList<Component>? {
|
||||
if (stack.get(DataComponents.HIDE_ADDITIONAL_TOOLTIP) != null) {
|
||||
return null
|
||||
}
|
||||
val resultLines = mutableListOf<Component>()
|
||||
|
||||
if (SpawnBaitEffects.isFishingBait(stack)) resultLines.add(this.fishingBaitItemClass)
|
||||
|
||||
-3
@@ -23,9 +23,6 @@ import net.minecraft.world.item.ItemStack
|
||||
|
||||
object FishingRodTooltipGenerator : TooltipGenerator() {
|
||||
override fun generateTooltip(stack: ItemStack, lines: MutableList<Component>): MutableList<Component>? {
|
||||
if (stack.get(DataComponents.HIDE_ADDITIONAL_TOOLTIP) != null) {
|
||||
return null
|
||||
}
|
||||
val resultLines = mutableListOf<Component>()
|
||||
|
||||
val rod = (stack.item as? PokerodItem)?.pokeRodId?.let { PokeRods.getPokeRod(it) } ?: return null
|
||||
|
||||
-4
@@ -61,10 +61,6 @@ object SeasoningTooltipGenerator : TooltipGenerator() {
|
||||
}
|
||||
|
||||
override fun generateAdditionalTooltip(stack: ItemStack, lines: MutableList<Component>): MutableList<Component>? {
|
||||
if (stack.get(DataComponents.HIDE_ADDITIONAL_TOOLTIP) != null) {
|
||||
return null
|
||||
}
|
||||
|
||||
val isSeasoningIngredient = Seasonings.isSeasoning(stack)
|
||||
val flavors = stack.get(CobblemonItemComponents.FLAVOUR)?.flavours
|
||||
val food = stack.get(CobblemonItemComponents.FOOD)
|
||||
|
||||
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.client.tooltips
|
||||
|
||||
import com.cobblemon.mod.common.api.text.yellow
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import net.minecraft.core.component.DataComponents
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.item.ItemStack
|
||||
|
||||
@@ -22,6 +23,12 @@ object TooltipManager {
|
||||
}
|
||||
|
||||
fun generateTooltips(stack: ItemStack, lines: MutableList<Component>, hasShiftDown: Boolean) {
|
||||
// This will need to be changed in 1.21.5 as 25w04a changed the following:
|
||||
// "Removed the hide_tooltip and hide_additional_tooltip components in favor of the new tooltip_display component."
|
||||
if (stack.get(DataComponents.HIDE_ADDITIONAL_TOOLTIP) != null) {
|
||||
return
|
||||
}
|
||||
|
||||
val standardLines = tooltipGenerators.flatMap {
|
||||
val innerLines = mutableListOf<Component>()
|
||||
val regularTooltip = it.generateTooltip(stack, lines)
|
||||
|
||||
@@ -9,34 +9,60 @@
|
||||
package com.cobblemon.mod.common.command
|
||||
|
||||
import com.cobblemon.mod.common.api.permission.CobblemonPermissions
|
||||
import com.cobblemon.mod.common.api.text.green
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.cobblemon.mod.common.util.commandLang
|
||||
import com.cobblemon.mod.common.util.requiresWithPermission
|
||||
import com.cobblemon.mod.common.util.permission
|
||||
import com.cobblemon.mod.common.util.traceFirstEntityCollision
|
||||
import com.mojang.brigadier.Command
|
||||
import com.mojang.brigadier.CommandDispatcher
|
||||
import com.mojang.brigadier.context.CommandContext
|
||||
import net.minecraft.commands.CommandSourceStack
|
||||
import net.minecraft.commands.Commands
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.commands.arguments.EntityArgument
|
||||
import net.minecraft.world.entity.Entity
|
||||
|
||||
object NPCDeleteCommand {
|
||||
fun register(dispatcher : CommandDispatcher<CommandSourceStack>) {
|
||||
dispatcher.register(
|
||||
Commands.literal("npcdelete")
|
||||
.requiresWithPermission(CobblemonPermissions.NPC_DELETE) { it.player != null }
|
||||
.executes { execute(it, it.source.playerOrException) })
|
||||
.permission(CobblemonPermissions.NPC_DELETE)
|
||||
.then(
|
||||
Commands.argument("target", EntityArgument.entity())
|
||||
.executes {context ->
|
||||
val source = context.source
|
||||
val entity = EntityArgument.getEntity(context, "target")
|
||||
execute(entity, source)
|
||||
}
|
||||
)
|
||||
.executes {context ->
|
||||
val source = context.source
|
||||
val player = source.player
|
||||
if (player == null) {
|
||||
source.sendSystemMessage(commandLang("npcdelete.not_player").red())
|
||||
return@executes 0
|
||||
}
|
||||
|
||||
val targetEntity = player.traceFirstEntityCollision(entityClass = NPCEntity::class.java)
|
||||
|
||||
if (targetEntity == null) {
|
||||
player.sendSystemMessage(commandLang("npcedit.non_npc").red())
|
||||
return@executes 0
|
||||
}
|
||||
execute(targetEntity, source)
|
||||
}
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
private fun execute(context: CommandContext<CommandSourceStack>, player: ServerPlayer) : Int {
|
||||
val targetEntity = player.traceFirstEntityCollision(entityClass = NPCEntity::class.java)
|
||||
if (targetEntity == null) {
|
||||
player.sendSystemMessage(commandLang("npcedit.non_npc").red())
|
||||
private fun execute(entity: Entity, source: CommandSourceStack) : Int {
|
||||
if(entity !is NPCEntity){
|
||||
source.sendSystemMessage(commandLang("npcedit.non_npc").red())
|
||||
return 0
|
||||
}
|
||||
|
||||
targetEntity.discard()
|
||||
entity.discard()
|
||||
source.sendSystemMessage(commandLang("npcdelete.deleted", entity.name.string).green())
|
||||
return Command.SINGLE_SUCCESS
|
||||
}
|
||||
}
|
||||
@@ -12,12 +12,16 @@ import com.cobblemon.mod.common.api.drop.ItemDropMethod
|
||||
import com.cobblemon.mod.common.api.pokeball.catching.calculators.CaptureCalculator
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.client.gui.portrait.PortraitStyle
|
||||
import com.cobblemon.mod.common.config.CobblemonConfigField.CobblemonConfigSide.CLIENT
|
||||
import com.cobblemon.mod.common.config.CobblemonConfigField.CobblemonConfigSide.SERVER
|
||||
import com.cobblemon.mod.common.config.constraint.IntConstraint
|
||||
import com.cobblemon.mod.common.pokeball.catching.calculators.CobblemonCaptureCalculator
|
||||
import com.cobblemon.mod.common.util.adapters.CaptureCalculatorAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.IntRangeAdapter
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.jvm.isAccessible
|
||||
|
||||
@@ -29,128 +33,129 @@ class CobblemonConfig {
|
||||
.registerTypeAdapter(IntRange::class.java, IntRangeAdapter)
|
||||
.registerTypeAdapter(ItemDropMethod::class.java, ItemDropMethod.adapter)
|
||||
.registerTypeAdapter(CaptureCalculator::class.java, CaptureCalculatorAdapter)
|
||||
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
|
||||
.create()
|
||||
}
|
||||
|
||||
var lastSavedVersion: String = "0.0.1"
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "max_pokemon_level")
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "max_pokemon_level", SERVER)
|
||||
@IntConstraint(min = 1, max = 1000)
|
||||
var maxPokemonLevel = 100
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "max_pokemon_friendship")
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "max_pokemon_friendship", SERVER)
|
||||
@IntConstraint(min = 0, max = 1000)
|
||||
var maxPokemonFriendship = 255
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "announce_drop_items")
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "announce_drop_items", SERVER)
|
||||
var announceDropItems = true
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "default_drop_item_method")
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "default_drop_item_method", SERVER)
|
||||
var defaultDropItemMethod = ItemDropMethod.ON_ENTITY
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "drops_after_death_animation")
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "drops_after_death_animation", SERVER)
|
||||
var dropAfterDeathAnimation = false
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "ambient_pokemon_cry_ticks")
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "ambient_pokemon_cry_ticks", SERVER)
|
||||
@LastChangedVersion("1.4.0")
|
||||
var ambientPokemonCryTicks = 1080
|
||||
|
||||
@CobblemonConfigField(Category.Storage, lang = "default_box_count")
|
||||
@CobblemonConfigField(Category.Storage, lang = "default_box_count", SERVER)
|
||||
@IntConstraint(min = 1, max = 1000)
|
||||
@LastChangedVersion("1.7.0")
|
||||
var defaultBoxCount = 40
|
||||
@CobblemonConfigField(Category.Storage, lang = "pokemon_save_interval_seconds")
|
||||
@CobblemonConfigField(Category.Storage, lang = "pokemon_save_interval_seconds", SERVER)
|
||||
@IntConstraint(min = 1, max = 120)
|
||||
var pokemonSaveIntervalSeconds = 30
|
||||
|
||||
@CobblemonConfigField(Category.Storage, lang = "storage_format")
|
||||
@CobblemonConfigField(Category.Storage, lang = "storage_format", SERVER)
|
||||
var storageFormat = "nbt"
|
||||
|
||||
@CobblemonConfigField(Category.Storage, lang = "prevent_complete_party_deposit")
|
||||
@CobblemonConfigField(Category.Storage, lang = "prevent_complete_party_deposit", SERVER)
|
||||
var preventCompletePartyDeposit = false
|
||||
|
||||
@CobblemonConfigField(Category.Storage, lang = "mongo_db_connection_string")
|
||||
@CobblemonConfigField(Category.Storage, lang = "mongo_db_connection_string", SERVER)
|
||||
var mongoDBConnectionString = "mongodb://localhost:27017"
|
||||
@CobblemonConfigField(Category.Storage, lang = "mongo_db_database_name")
|
||||
@CobblemonConfigField(Category.Storage, lang = "mongo_db_database_name", SERVER)
|
||||
var mongoDBDatabaseName = "cobblemon"
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "max_vertical_correction_blocks")
|
||||
@CobblemonConfigField(Category.Spawning, lang = "max_vertical_correction_blocks", SERVER)
|
||||
@IntConstraint(min = 1, max = 200)
|
||||
var maxVerticalCorrectionBlocks = 64
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "minimum_level_range_max")
|
||||
@CobblemonConfigField(Category.Spawning, lang = "minimum_level_range_max", SERVER)
|
||||
@IntConstraint(min = 1, max = 1000)
|
||||
var minimumLevelRangeMax = 10
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "enable_spawning")
|
||||
@CobblemonConfigField(Category.Spawning, lang = "enable_spawning", SERVER)
|
||||
var enableSpawning = true
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "minimum_distance_between_entities")
|
||||
@CobblemonConfigField(Category.Spawning, lang = "minimum_distance_between_entities", SERVER)
|
||||
var minimumDistanceBetweenEntities = 8.0
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "max_nearby_blocks_horizontal_range")
|
||||
@CobblemonConfigField(Category.Spawning, lang = "max_nearby_blocks_horizontal_range", SERVER)
|
||||
var maxNearbyBlocksHorizontalRange = 4
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "max_nearby_blocks_vertical_range")
|
||||
@CobblemonConfigField(Category.Spawning, lang = "max_nearby_blocks_vertical_range", SERVER)
|
||||
var maxNearbyBlocksVerticalRange = 2
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "max_vertical_space")
|
||||
@CobblemonConfigField(Category.Spawning, lang = "max_vertical_space", SERVER)
|
||||
var maxVerticalSpace = 8
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "spawning_zone_diameter")
|
||||
@CobblemonConfigField(Category.Spawning, lang = "spawning_zone_diameter", SERVER)
|
||||
@SerializedName("spawningZoneDiameter", alternate = ["worldSliceDiameter"])
|
||||
var spawningZoneDiameter = 8
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "spawning_zone_height")
|
||||
@CobblemonConfigField(Category.Spawning, lang = "spawning_zone_height", SERVER)
|
||||
@SerializedName("spawningZoneHeight", alternate = ["worldSliceHeight"])
|
||||
var spawningZoneHeight = 16
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "ticks_between_spawn_attempts")
|
||||
@CobblemonConfigField(Category.Spawning, lang = "ticks_between_spawn_attempts", SERVER)
|
||||
var ticksBetweenSpawnAttempts = 20F
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "minimum_spawning_zone_distance_from_player")
|
||||
@CobblemonConfigField(Category.Spawning, lang = "minimum_spawning_zone_distance_from_player", SERVER)
|
||||
@SerializedName("minimumSpawningZoneDistanceFromPlayer", alternate = ["minimumSliceDistanceFromPlayer"])
|
||||
var minimumSpawningZoneDistanceFromPlayer = 16F
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "maximum_spawning_zone_distance_from_player")
|
||||
@CobblemonConfigField(Category.Spawning, lang = "maximum_spawning_zone_distance_from_player", SERVER)
|
||||
@SerializedName("maximumSpawningZoneDistanceFromPlayer", alternate = ["maximumSliceDistanceFromPlayer"])
|
||||
var maximumSpawningZoneDistanceFromPlayer = 16 * 4F
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "maximum_spawns_per_pass")
|
||||
@CobblemonConfigField(Category.Spawning, lang = "maximum_spawns_per_pass", SERVER)
|
||||
var maximumSpawnsPerPass = 8
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "export_spawn_config")
|
||||
@CobblemonConfigField(Category.Spawning, lang = "export_spawn_config", SERVER)
|
||||
var exportSpawnConfig = false
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "save_pokemon_to_world")
|
||||
@CobblemonConfigField(Category.Spawning, lang = "save_pokemon_to_world", SERVER)
|
||||
var savePokemonToWorld = true
|
||||
|
||||
@CobblemonConfigField(Category.Starter, lang = "export_starter_config")
|
||||
@CobblemonConfigField(Category.Starter, lang = "export_starter_config", SERVER)
|
||||
var exportStarterConfig = false
|
||||
|
||||
@CobblemonConfigField(Category.Battles, lang = "auto_update_showdown")
|
||||
@CobblemonConfigField(Category.Battles, lang = "auto_update_showdown", SERVER)
|
||||
var autoUpdateShowdown = true
|
||||
|
||||
@CobblemonConfigField(Category.Battles, lang = "default_flee_distance")
|
||||
@CobblemonConfigField(Category.Battles, lang = "default_flee_distance", SERVER)
|
||||
var defaultFleeDistance = 16F * 2
|
||||
|
||||
@CobblemonConfigField(Category.Battles, lang = "allow_experience_from_pvp")
|
||||
@CobblemonConfigField(Category.Battles, lang = "allow_experience_from_pvp", SERVER)
|
||||
var allowExperienceFromPvP = true
|
||||
|
||||
@CobblemonConfigField(Category.Battles, lang = "experience_share_multiplier")
|
||||
@CobblemonConfigField(Category.Battles, lang = "experience_share_multiplier", SERVER)
|
||||
var experienceShareMultiplier = .5
|
||||
|
||||
@CobblemonConfigField(Category.Battles, lang = "lucky_egg_multiplier")
|
||||
@CobblemonConfigField(Category.Battles, lang = "lucky_egg_multiplier", SERVER)
|
||||
var luckyEggMultiplier = 1.5
|
||||
|
||||
@CobblemonConfigField(Category.Battles, lang = "allow_spectating")
|
||||
@CobblemonConfigField(Category.Battles, lang = "allow_spectating", SERVER)
|
||||
var allowSpectating = true
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "experience_multiplier")
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "experience_multiplier", SERVER)
|
||||
var experienceMultiplier = 2F
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "pokemon_per_chunk")
|
||||
@CobblemonConfigField(Category.Spawning, lang = "pokemon_per_chunk", SERVER)
|
||||
var pokemonPerChunk = 1F
|
||||
|
||||
@CobblemonConfigField(Category.PassiveStatus, lang = "passive_statuses")
|
||||
@CobblemonConfigField(Category.PassiveStatus, lang = "passive_statuses", SERVER)
|
||||
var passiveStatuses = mutableMapOf(
|
||||
Statuses.POISON.configEntry(),
|
||||
Statuses.POISON_BADLY.configEntry(),
|
||||
@@ -160,159 +165,165 @@ class CobblemonConfig {
|
||||
Statuses.BURN.configEntry()
|
||||
)
|
||||
|
||||
@CobblemonConfigField(Category.Healing, lang = "infinite_healer_charge")
|
||||
@CobblemonConfigField(Category.Healing, lang = "infinite_healer_charge", SERVER)
|
||||
var infiniteHealerCharge = false
|
||||
|
||||
@CobblemonConfigField(Category.Healing, lang = "max_healer_charge")
|
||||
@CobblemonConfigField(Category.Healing, lang = "max_healer_charge", SERVER)
|
||||
var maxHealerCharge = 6.0f
|
||||
|
||||
@CobblemonConfigField(Category.Healing, lang = "seconds_to_charge_healing_machine")
|
||||
@CobblemonConfigField(Category.Healing, lang = "seconds_to_charge_healing_machine", SERVER)
|
||||
var secondsToChargeHealingMachine = 900.0
|
||||
|
||||
@CobblemonConfigField(Category.Healing, lang = "default_faint_timer")
|
||||
@CobblemonConfigField(Category.Healing, lang = "default_faint_timer", SERVER)
|
||||
var defaultFaintTimer = 300
|
||||
|
||||
@CobblemonConfigField(Category.Healing, lang = "faint_awaken_health_percent")
|
||||
@CobblemonConfigField(Category.Healing, lang = "faint_awaken_health_percent", SERVER)
|
||||
var faintAwakenHealthPercent = 0.2f
|
||||
|
||||
@CobblemonConfigField(Category.Healing, lang = "heal_percent")
|
||||
@CobblemonConfigField(Category.Healing, lang = "heal_percent", SERVER)
|
||||
var healPercent = 0.05
|
||||
|
||||
@CobblemonConfigField(Category.Healing, lang = "heal_timer")
|
||||
@CobblemonConfigField(Category.Healing, lang = "heal_timer", SERVER)
|
||||
var healTimer = 60
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "base_apricorn_tree_generation_chance")
|
||||
@CobblemonConfigField(Category.Spawning, lang = "base_apricorn_tree_generation_chance", SERVER)
|
||||
var baseApricornTreeGenerationChance = 0.1F
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "display_entity_level_label")
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "display_entity_level_label", CLIENT)
|
||||
var displayEntityLevelLabel = true
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "display_entity_name_label")
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "display_entity_name_label", CLIENT)
|
||||
var displayEntityNameLabel = true
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "display_name_for_unknown_pokemon")
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "display_name_for_unknown_pokemon", CLIENT)
|
||||
var displayNameForUnknownPokemon = false
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "display_entity_labels_when_crouching_only")
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "display_entity_labels_when_crouching_only", CLIENT)
|
||||
var displayEntityLabelsWhenCrouchingOnly = false
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "shiny_rate")
|
||||
@CobblemonConfigField(Category.Spawning, lang = "shiny_rate", SERVER)
|
||||
var shinyRate = 8192F
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "shiny_notice_particles_distance")
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "shiny_notice_particles_distance", CLIENT)
|
||||
var shinyNoticeParticlesDistance = 24F
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "capture_calculator")
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "capture_calculator", SERVER)
|
||||
var captureCalculator: CaptureCalculator = CobblemonCaptureCalculator
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "player_damage_pokemon")
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "player_damage_pokemon", SERVER)
|
||||
var playerDamagePokemon = true
|
||||
|
||||
@CobblemonConfigField(Category.World, lang = "apple_leftovers_chance")
|
||||
@CobblemonConfigField(Category.World, lang = "apple_leftovers_chance", SERVER)
|
||||
var appleLeftoversChance = 0.025
|
||||
|
||||
@CobblemonConfigField(Category.World, lang = "max_roots_in_area")
|
||||
@CobblemonConfigField(Category.World, lang = "max_roots_in_area", SERVER)
|
||||
var maxRootsInArea = 5
|
||||
|
||||
@CobblemonConfigField(Category.World, lang = "big_root_propagation_chance")
|
||||
@CobblemonConfigField(Category.World, lang = "big_root_propagation_chance", SERVER)
|
||||
var bigRootPropagationChance = 0.1
|
||||
|
||||
@CobblemonConfigField(Category.World, lang = "energy_root_chance")
|
||||
@CobblemonConfigField(Category.World, lang = "energy_root_chance", SERVER)
|
||||
var energyRootChance = 0.25
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "max_dynamax_level")
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "max_dynamax_level", SERVER)
|
||||
@IntConstraint(min = 0, max = 10)
|
||||
var maxDynamaxLevel = 10
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "tera_type_rate")
|
||||
@CobblemonConfigField(Category.Spawning, lang = "tera_type_rate", SERVER)
|
||||
var teraTypeRate = 20F
|
||||
|
||||
@CobblemonConfigField(Category.World, lang = "default_pastured_pokemon_limit")
|
||||
@CobblemonConfigField(Category.World, lang = "default_pastured_pokemon_limit", SERVER)
|
||||
var defaultPasturedPokemonLimit = 16
|
||||
|
||||
@CobblemonConfigField(Category.World, lang = "pasture_block_update_ticks")
|
||||
@CobblemonConfigField(Category.World, lang = "pasture_block_update_ticks", SERVER)
|
||||
var pastureBlockUpdateTicks = 40
|
||||
|
||||
@CobblemonConfigField(Category.World, lang = "pasture_max_wander_distance")
|
||||
@CobblemonConfigField(Category.World, lang = "pasture_max_wander_distance", SERVER)
|
||||
var pastureMaxWanderDistance = 64
|
||||
|
||||
@CobblemonConfigField(Category.World, lang = "pasture_max_per_chunk")
|
||||
@CobblemonConfigField(Category.World, lang = "pasture_max_per_chunk", SERVER)
|
||||
var pastureMaxPerChunk = 4F
|
||||
|
||||
@CobblemonConfigField(Category.World, lang = "max_inserted_fossil_items")
|
||||
@CobblemonConfigField(Category.World, lang = "max_inserted_fossil_items", SERVER)
|
||||
var maxInsertedFossilItems = 2
|
||||
|
||||
@CobblemonConfigField(Category.Battles, lang = "walking_in_battle_animations")
|
||||
@CobblemonConfigField(Category.Battles, lang = "walking_in_battle_animations", CLIENT)
|
||||
var walkingInBattleAnimations = false
|
||||
|
||||
@CobblemonConfigField(Category.Battles, lang = "battle_wild_max_distance")
|
||||
@CobblemonConfigField(Category.Battles, lang = "battle_wild_max_distance", SERVER)
|
||||
var battleWildMaxDistance = 12F
|
||||
|
||||
@CobblemonConfigField(Category.World, lang = "trade_max_distance")
|
||||
@CobblemonConfigField(Category.World, lang = "trade_max_distance", SERVER)
|
||||
var tradeMaxDistance = 12F
|
||||
|
||||
@CobblemonConfigField(Category.Battles, lang = "battle_pvp_max_distance")
|
||||
@CobblemonConfigField(Category.Battles, lang = "battle_pvp_max_distance", SERVER)
|
||||
@SerializedName("battlePvPMaxDistance", alternate = ["BattlePvPMaxDistance"])
|
||||
var battlePvPMaxDistance = 32F
|
||||
|
||||
@CobblemonConfigField(Category.Battles, lang = "battle_spectate_max_distance")
|
||||
@CobblemonConfigField(Category.Battles, lang = "battle_spectate_max_distance", SERVER)
|
||||
var battleSpectateMaxDistance = 64F
|
||||
|
||||
@CobblemonConfigField(Category.Pokedex, lang = "max_pokedex_scanning_detection_range")
|
||||
@CobblemonConfigField(Category.Pokedex, lang = "max_pokedex_scanning_detection_range", SERVER)
|
||||
var maxPokedexScanningDetectionRange = 10.0
|
||||
|
||||
@CobblemonConfigField(Category.Pokedex, lang = "hide_unimplemented_pokemon_in_the_pokedex")
|
||||
@CobblemonConfigField(Category.Pokedex, lang = "hide_unimplemented_pokemon_in_the_pokedex", CLIENT)
|
||||
var hideUnimplementedPokemonInThePokedex = false
|
||||
|
||||
@CobblemonConfigField(Category.Interface, lang = "summary_pokemon_follow_cursor")
|
||||
@CobblemonConfigField(Category.Interface, lang = "summary_pokemon_follow_cursor", CLIENT)
|
||||
var summaryPokemonFollowCursor = true
|
||||
|
||||
@CobblemonConfigField(Category.Interface, lang = "party_portrait_animations")
|
||||
@CobblemonConfigField(Category.Interface, lang = "party_portrait_animations", CLIENT)
|
||||
var partyPortraitAnimations = PortraitStyle.NEVER_ANIMATE
|
||||
|
||||
@CobblemonConfigField(Category.Riding, lang = "third_person_view_bobbing")
|
||||
@CobblemonConfigField(Category.Riding, lang = "third_person_view_bobbing", CLIENT)
|
||||
var thirdPersonViewBobbing = true
|
||||
|
||||
@CobblemonConfigField(Category.Riding, lang = "invert_roll")
|
||||
@CobblemonConfigField(Category.Riding, lang = "invert_roll", CLIENT)
|
||||
var invertRoll = false
|
||||
|
||||
@CobblemonConfigField(Category.Riding, lang = "invert_pitch")
|
||||
@CobblemonConfigField(Category.Riding, lang = "invert_pitch", CLIENT)
|
||||
var invertPitch = false
|
||||
|
||||
@CobblemonConfigField(Category.Riding, lang = "invert_yaw")
|
||||
@CobblemonConfigField(Category.Riding, lang = "invert_yaw", CLIENT)
|
||||
var invertYaw = false
|
||||
|
||||
@CobblemonConfigField(Category.Riding, lang = "x_axis_sensitivity")
|
||||
@CobblemonConfigField(Category.Riding, lang = "x_axis_sensitivity", CLIENT)
|
||||
var xAxisSensitivity = 1.0
|
||||
|
||||
@CobblemonConfigField(Category.Riding, lang = "y_axis_sensitivity")
|
||||
@CobblemonConfigField(Category.Riding, lang = "y_axis_sensitivity", CLIENT)
|
||||
var yAxisSensitivity = 1.0
|
||||
|
||||
@CobblemonConfigField(Category.Riding, lang = "swap_x_and_y_axes")
|
||||
@CobblemonConfigField(Category.Riding, lang = "swap_x_and_y_axes", CLIENT)
|
||||
var swapXAndYAxes = false
|
||||
|
||||
@CobblemonConfigField(Category.Riding, lang = "automatic_righting_delay")
|
||||
@CobblemonConfigField(Category.Riding, lang = "automatic_righting_delay", CLIENT)
|
||||
var rightingDelay = -1.0
|
||||
|
||||
@CobblemonConfigField(Category.Riding, lang = "disable_roll")
|
||||
@CobblemonConfigField(Category.Riding, lang = "disable_roll", CLIENT)
|
||||
var disableRoll = false
|
||||
|
||||
@CobblemonConfigField(Category.Riding, lang = "display_controls_duration_seconds")
|
||||
@CobblemonConfigField(Category.Riding, lang = "display_controls_duration_seconds", CLIENT)
|
||||
var displayControlSeconds = 3
|
||||
|
||||
@CobblemonConfigField(Category.Debug, lang = "enable_debug_keys")
|
||||
@CobblemonConfigField(Category.Riding, lang = "infinite_ride_stamina", SERVER)
|
||||
var infiniteRideStamina = false
|
||||
|
||||
@CobblemonConfigField(Category.Riding, lang = "remember_riding_camera", CLIENT)
|
||||
var rememberRidingCamera = true
|
||||
|
||||
@CobblemonConfigField(Category.Debug, lang = "enable_debug_keys", CLIENT)
|
||||
var enableDebugKeys = true
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "despawner_near_distance")
|
||||
@CobblemonConfigField(Category.Spawning, lang = "despawner_near_distance", SERVER)
|
||||
var despawnerNearDistance = 32f
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "despawner_far_distance")
|
||||
@CobblemonConfigField(Category.Spawning, lang = "despawner_far_distance", SERVER)
|
||||
var despawnerFarDistance = 96f
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "despawner_min_age_ticks")
|
||||
@CobblemonConfigField(Category.Spawning, lang = "despawner_min_age_ticks", SERVER)
|
||||
var despawnerMinAgeTicks = 600
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "despawner_max_age_ticks")
|
||||
@CobblemonConfigField(Category.Spawning, lang = "despawner_max_age_ticks", SERVER)
|
||||
var despawnerMaxAgeTicks = 3600
|
||||
|
||||
fun clone(): CobblemonConfig {
|
||||
|
||||
@@ -13,4 +13,10 @@ package com.cobblemon.mod.common.config
|
||||
annotation class CobblemonConfigField(
|
||||
val category: Category,
|
||||
val lang: String,
|
||||
)
|
||||
val side: CobblemonConfigSide,
|
||||
) {
|
||||
enum class CobblemonConfigSide {
|
||||
CLIENT,
|
||||
SERVER,
|
||||
}
|
||||
}
|
||||
@@ -10,8 +10,9 @@ package com.cobblemon.mod.common.config.starter
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.config.Category
|
||||
import com.cobblemon.mod.common.config.LastChangedVersion
|
||||
import com.cobblemon.mod.common.config.CobblemonConfigField
|
||||
import com.cobblemon.mod.common.config.CobblemonConfigField.CobblemonConfigSide.SERVER
|
||||
import com.cobblemon.mod.common.config.LastChangedVersion
|
||||
import com.cobblemon.mod.common.util.adapters.pokemonPropertiesShortAdapter
|
||||
import com.google.gson.GsonBuilder
|
||||
|
||||
@@ -24,17 +25,17 @@ class StarterConfig {
|
||||
.create()
|
||||
}
|
||||
|
||||
@CobblemonConfigField(Category.Starter, lang = "allow_starter_on_join")
|
||||
@CobblemonConfigField(Category.Starter, lang = "allow_starter_on_join", SERVER)
|
||||
var allowStarterOnJoin = true
|
||||
|
||||
@CobblemonConfigField(Category.Starter, lang = "prompt_starter_once_only")
|
||||
@CobblemonConfigField(Category.Starter, lang = "prompt_starter_once_only", SERVER)
|
||||
@LastChangedVersion("1.5.0")
|
||||
var promptStarterOnceOnly = true
|
||||
|
||||
@CobblemonConfigField(Category.Starter, lang = "use_config_starters")
|
||||
@CobblemonConfigField(Category.Starter, lang = "use_config_starters", SERVER)
|
||||
var useConfigStarters = false
|
||||
|
||||
@CobblemonConfigField(Category.Starter, lang = "starters")
|
||||
@CobblemonConfigField(Category.Starter, lang = "starters", SERVER)
|
||||
var starters = mutableListOf(
|
||||
StarterCategory(
|
||||
name = "Kanto",
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.cobblemon.mod.common.CobblemonBehaviours
|
||||
import com.cobblemon.mod.common.CobblemonCallbacks
|
||||
import com.cobblemon.mod.common.CobblemonCosmeticItems
|
||||
import com.cobblemon.mod.common.CobblemonMechanics
|
||||
import com.cobblemon.mod.common.CobblemonRideSettings
|
||||
import com.cobblemon.mod.common.CobblemonUnlockableWallpapers
|
||||
import com.cobblemon.mod.common.api.abilities.Abilities
|
||||
import com.cobblemon.mod.common.api.berry.Berries
|
||||
@@ -109,6 +110,7 @@ object CobblemonDataProvider : DataProvider {
|
||||
this.register(Seasonings, reloadable = false)
|
||||
this.register(PokemonInteractions, reloadable = false)
|
||||
this.register(SpawnBaitEffects, reloadable = false)
|
||||
this.register(CobblemonRideSettings, reloadable = true)
|
||||
SpawnBait.Effects.setupEffects()
|
||||
|
||||
PlatformEvents.SERVER_PLAYER_LOGOUT.subscribe {
|
||||
|
||||
@@ -25,6 +25,7 @@ interface OmniPathingEntity {
|
||||
fun canSwimInLava(): Boolean
|
||||
fun canWalkOnLava(): Boolean
|
||||
fun canSwimUnderFluid(fluidState: FluidState): Boolean
|
||||
fun canPathThroughSaccLeaves(): Boolean
|
||||
fun canFly(): Boolean
|
||||
fun isFlying(): Boolean
|
||||
fun setFlying(state: Boolean)
|
||||
|
||||
@@ -11,16 +11,17 @@ package com.cobblemon.mod.common.entity.ai
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.PokemonMoveControl
|
||||
import com.cobblemon.mod.common.util.toBlockPos
|
||||
import com.google.common.collect.ImmutableMap
|
||||
import java.util.UUID
|
||||
import kotlin.math.pow
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.MoverType
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.world.entity.ai.behavior.Behavior
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.MemoryStatus
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import java.util.*
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
|
||||
class FollowHerdLeaderTask : Behavior<PokemonEntity>(
|
||||
ImmutableMap.of(
|
||||
@@ -34,7 +35,7 @@ class FollowHerdLeaderTask : Behavior<PokemonEntity>(
|
||||
var tooFar = 8F
|
||||
var closeEnough = 4F
|
||||
/** Chance per tick of following the herd leader. */
|
||||
val chance = 1 / 20F
|
||||
val chance = 1 / 60F
|
||||
|
||||
override fun checkExtraStartConditions(level: ServerLevel, owner: PokemonEntity): Boolean {
|
||||
leader = level.getEntity(owner.brain.getMemory(CobblemonMemories.HERD_LEADER).map(UUID::fromString).orElse(null) ?: return false) as? PokemonEntity
|
||||
@@ -50,16 +51,19 @@ class FollowHerdLeaderTask : Behavior<PokemonEntity>(
|
||||
|
||||
override fun tick(level: ServerLevel, entity: PokemonEntity, gameTime: Long) {
|
||||
val leader = leader ?: return
|
||||
|
||||
if (entity.brain.hasMemoryValue(MemoryModuleType.WALK_TARGET)) {
|
||||
return // We're busy goin' n' shit
|
||||
}
|
||||
|
||||
val moveControl = entity.moveControl as? PokemonMoveControl ?: return
|
||||
val leaderMoveControl = leader.moveControl as? PokemonMoveControl ?: return
|
||||
|
||||
if (leader.distanceTo(entity) > tooFar) {
|
||||
entity.brain.setMemory(
|
||||
MemoryModuleType.WALK_TARGET,
|
||||
CobblemonWalkTarget(
|
||||
pos = leader.blockPosition(),
|
||||
pos = leader.position().add(getRandomOffset(entity, level)).toBlockPos(),
|
||||
speedModifier = 0.4F,
|
||||
completionRange = closeEnough.toInt()
|
||||
)
|
||||
@@ -69,10 +73,11 @@ class FollowHerdLeaderTask : Behavior<PokemonEntity>(
|
||||
entity.brain.eraseMemory(CobblemonMemories.HERD_LEADER) // We can't go where this guy's going
|
||||
return
|
||||
}
|
||||
|
||||
entity.brain.setMemory(
|
||||
MemoryModuleType.WALK_TARGET,
|
||||
CobblemonWalkTarget(
|
||||
pos = leader.blockPosition(),
|
||||
pos = leader.position().add(getRandomOffset(entity, level)).toBlockPos(),
|
||||
speedModifier = 0.3F,
|
||||
completionRange = closeEnough.toInt()
|
||||
)
|
||||
@@ -83,7 +88,7 @@ class FollowHerdLeaderTask : Behavior<PokemonEntity>(
|
||||
entity.brain.setMemory(
|
||||
MemoryModuleType.WALK_TARGET,
|
||||
CobblemonWalkTarget(
|
||||
pos = leader.blockPosition(),
|
||||
pos = leader.position().add(getRandomOffset(entity, level)).toBlockPos(),
|
||||
speedModifier = 0.4F,
|
||||
completionRange = 1
|
||||
)
|
||||
@@ -105,14 +110,15 @@ class FollowHerdLeaderTask : Behavior<PokemonEntity>(
|
||||
// Go to the leader's walk target, roughly.
|
||||
val walkTarget = leader.brain.getMemory(MemoryModuleType.WALK_TARGET).orElse(null) ?: return
|
||||
|
||||
if (entity.distanceToSqr(walkTarget.target.currentPosition()) < leader.distanceToSqr(walkTarget.target.currentPosition())) {
|
||||
return // We're already closer to the walk target than the leader is, so no need to move, if anything we should get out of the way
|
||||
// We're already closer to the walk target than the leader is, so no need to move, if anything we should get out of the way
|
||||
if (entity.distanceToSqr(walkTarget.target.currentPosition()) + closeEnough < leader.distanceToSqr(walkTarget.target.currentPosition())) {
|
||||
return
|
||||
}
|
||||
|
||||
entity.brain.setMemory(
|
||||
MemoryModuleType.WALK_TARGET,
|
||||
CobblemonWalkTarget(
|
||||
pos = walkTarget.target.currentBlockPosition(),
|
||||
pos = walkTarget.target.currentPosition().add(getRandomOffset(entity, level)).toBlockPos(),
|
||||
speedModifier = walkTarget.speedModifier,
|
||||
nodeTypeFilter = (walkTarget as? CobblemonWalkTarget)?.nodeTypeFilter ?: { true },
|
||||
completionRange = closeEnough.toInt()
|
||||
@@ -120,4 +126,23 @@ class FollowHerdLeaderTask : Behavior<PokemonEntity>(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun getRandomOffset(entity: PokemonEntity, level: ServerLevel): Vec3 {
|
||||
val leader = leader ?: return Vec3.ZERO
|
||||
|
||||
val minRange = closeEnough.toDouble()
|
||||
val maxRange = (tooFar - closeEnough / 2).toDouble()
|
||||
val randomDistance = Mth.nextDouble(level.random, minRange, maxRange)
|
||||
val randomAngle = Mth.nextDouble(level.random, 0.0, 2 * Math.PI)
|
||||
|
||||
var offset = Vec3(cos(randomAngle) * randomDistance, 0.0, sin(randomAngle) * randomDistance)
|
||||
|
||||
if ((entity.isInLiquid && leader.isInLiquid) || (entity.isFlying() && leader.isFlying())) {
|
||||
val verticalRange = randomDistance * 0.5
|
||||
val randomY = Mth.nextDouble(level.random, -verticalRange, verticalRange)
|
||||
offset = offset.add(0.0, randomY, 0.0)
|
||||
}
|
||||
|
||||
return offset
|
||||
}
|
||||
}
|
||||
@@ -8,13 +8,16 @@
|
||||
|
||||
package com.cobblemon.mod.common.entity.ai
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBlocks
|
||||
import com.cobblemon.mod.common.entity.OmniPathingEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.ai.OmniPathNodeMaker
|
||||
import com.cobblemon.mod.common.util.deleteNode
|
||||
import com.cobblemon.mod.common.util.getWaterAndLavaIn
|
||||
import com.cobblemon.mod.common.util.toVec3d
|
||||
import com.google.common.collect.ImmutableSet
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.tags.BlockTags
|
||||
import net.minecraft.tags.FluidTags
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.world.damagesource.DamageSource
|
||||
@@ -132,7 +135,7 @@ class OmniPathNavigation(val world: Level, val entity: Mob) : GroundPathNavigati
|
||||
val f = abs(mob.z - targetVec3d.z)
|
||||
val closeEnough = d < maxDistanceToWaypoint.toDouble()
|
||||
&& f < this.maxDistanceToWaypoint.toDouble()
|
||||
&& e < (if (currentNode.type in verticallyPreciseNodeTypes && (mob.isUnderWater || pather.isFlying())) 1.0 else 1.0).toDouble()
|
||||
&& e < (if (currentNode.type in verticallyPreciseNodeTypes && (mob.isUnderWater || pather.isFlying())) maxDistanceToWaypoint else 1.0).toDouble()
|
||||
|
||||
// Corner cutting is commented out because it makes pokemon and NPCs 'cut' the corner and fall into water or lava
|
||||
if (closeEnough) {// || mob.navigation.canCutCorner(path!!.nextNode.type) && shouldTargetNextNodeInDirection(vec3d)) {
|
||||
@@ -181,7 +184,9 @@ class OmniPathNavigation(val world: Level, val entity: Mob) : GroundPathNavigati
|
||||
target = blockPos
|
||||
}
|
||||
|
||||
val path = if (!this.world.getBlockState(target).isSolid) {
|
||||
val blockState = this.world.getBlockState(target)
|
||||
val path = if (!blockState.isSolid
|
||||
|| (blockState.`is`(BlockTags.LEAVES) && blockState.block == CobblemonBlocks.SACCHARINE_LEAVES && (this.entity as PokemonEntity).canPathThroughSaccLeaves())) {
|
||||
findPath(target, distance)
|
||||
} else {
|
||||
blockPos = target.above()
|
||||
@@ -264,6 +269,9 @@ class OmniPathNavigation(val world: Level, val entity: Mob) : GroundPathNavigati
|
||||
// If we can fly and we're airborne, return the current Y position
|
||||
return vec.y
|
||||
}
|
||||
if (world.getBlockState(blockPos).block == CobblemonBlocks.SACCHARINE_LEAVES && (this.entity as PokemonEntity).canPathThroughSaccLeaves()) {
|
||||
return vec.y + 0.5
|
||||
}
|
||||
return if ((canFloat()) && blockGetter.getFluidState(blockPos).`is`(FluidTags.WATER)) vec.y + 0.5 else super.getGroundY(vec)
|
||||
}
|
||||
|
||||
|
||||
+6
-3
@@ -811,8 +811,11 @@ class PokeRodFishingBobberEntity(type: EntityType<out PokeRodFishingBobberEntity
|
||||
// create accessory splash particle when you fish something up
|
||||
particleEntityHandler(this, ResourceLocation.fromNamespaceAndPath("cobblemon", "accessory_fish_splash"))
|
||||
|
||||
var baitId = PokerodItem.getBaitStackOnRod(this.bobberBait).takeUnless { it.isEmpty }?.itemHolder?.unwrapKey()
|
||||
?.orElse(null)?.location() ?: "empty_bait".asIdentifierDefaultingNamespace()
|
||||
val baitId =
|
||||
if (bobberBait.isEmpty)
|
||||
"empty_bait".asIdentifierDefaultingNamespace()
|
||||
else
|
||||
bobberBait.itemHolder.unwrapKey().map { it.location() }.orElse("empty_bait".asIdentifierDefaultingNamespace())
|
||||
val pokemonId = spawnedPokemon.pokemon.species.resourceIdentifier
|
||||
CobblemonCriteria.REEL_IN_POKEMON.trigger(player, ReelInPokemonContext(pokemonId, baitId))
|
||||
|
||||
@@ -850,7 +853,7 @@ class PokeRodFishingBobberEntity(type: EntityType<out PokeRodFishingBobberEntity
|
||||
BobberSpawnPokemonEvent.Post(
|
||||
this,
|
||||
spawnAction,
|
||||
rodItemStack,
|
||||
bobberBait,
|
||||
entity
|
||||
)
|
||||
)
|
||||
|
||||
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.entity.npc
|
||||
import com.cobblemon.mod.common.CobblemonBehaviours
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.config.AddVariablesConfig
|
||||
import com.cobblemon.mod.common.api.ai.config.ApplyBehaviours
|
||||
import com.cobblemon.mod.common.api.ai.config.BehaviourConfig
|
||||
import com.cobblemon.mod.common.api.npc.NPCClass
|
||||
@@ -22,6 +23,7 @@ object NPCBrain {
|
||||
if (npcEntity.behavioursAreCustom) {
|
||||
behaviourConfigurations = listOf(ApplyBehaviours().apply { behaviours.addAll(npcEntity.behaviours) })
|
||||
}
|
||||
behaviourConfigurations = behaviourConfigurations + AddVariablesConfig(npcClass.config)
|
||||
|
||||
val ctx = BehaviourConfigurationContext()
|
||||
ctx.addMemories(CobblemonMemories.DIALOGUES)
|
||||
|
||||
@@ -708,6 +708,10 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
|
||||
return false
|
||||
}
|
||||
|
||||
override fun canPathThroughSaccLeaves(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun canFly(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
+2
-2
@@ -393,7 +393,8 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
|
||||
|
||||
private fun breakFree() {
|
||||
val pokemon = capturingPokemon ?: return
|
||||
pokemon.setPos(position())
|
||||
pokemon.setPositionSafely(position())
|
||||
|
||||
pokemon.beamMode = 2
|
||||
pokemon.isInvisible = false
|
||||
pokemon.isSilent = false
|
||||
@@ -490,7 +491,6 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
|
||||
|
||||
fun beginCapture() {
|
||||
// We have hit the ground, time to stop falling and start shaking! Calculate capture.
|
||||
capturingPokemon?.setPositionSafely(position())
|
||||
val thrower = owner as LivingEntity
|
||||
val captureResult = Cobblemon.config.captureCalculator.processCapture(thrower, this, capturingPokemon!!).let {
|
||||
val event = PokeBallCaptureCalculatedEvent(thrower = thrower, pokemonEntity = capturingPokemon!!, pokeBallEntity = this, captureResult = it)
|
||||
|
||||
@@ -73,6 +73,7 @@ import com.cobblemon.mod.common.battles.BattleBuilder
|
||||
import com.cobblemon.mod.common.battles.BattleRegistry
|
||||
import com.cobblemon.mod.common.battles.SuccessfulBattleStart
|
||||
import com.cobblemon.mod.common.block.entity.PokemonPastureBlockEntity
|
||||
import com.cobblemon.mod.common.client.MountedCameraTypeHandler
|
||||
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
|
||||
import com.cobblemon.mod.common.entity.BehaviourEditingTracker
|
||||
import com.cobblemon.mod.common.entity.EntityCallbacks
|
||||
@@ -119,6 +120,7 @@ import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.Dynamic
|
||||
import net.minecraft.client.Minecraft
|
||||
import java.util.Optional
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.CompletableFuture
|
||||
@@ -164,6 +166,7 @@ import net.minecraft.world.entity.ai.attributes.AttributeSupplier
|
||||
import net.minecraft.world.entity.ai.attributes.Attributes
|
||||
import net.minecraft.world.entity.ai.control.MoveControl
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.MemoryStatus
|
||||
import net.minecraft.world.entity.ai.sensing.Sensor
|
||||
import net.minecraft.world.entity.ai.sensing.SensorType
|
||||
import net.minecraft.world.entity.animal.Animal
|
||||
@@ -216,6 +219,7 @@ open class PokemonEntity(
|
||||
@JvmStatic val EVOLUTION_STARTED = SynchedEntityData.defineId(PokemonEntity::class.java, EntityDataSerializers.BOOLEAN)
|
||||
@JvmStatic var SHOWN_HELD_ITEM = SynchedEntityData.defineId(PokemonEntity::class.java, EntityDataSerializers.ITEM_STACK)
|
||||
@JvmStatic var RIDE_BOOSTS = SynchedEntityData.defineId(PokemonEntity::class.java, RideBoostsDataSerializer)
|
||||
@JvmStatic var RIDE_STAMINA = SynchedEntityData.defineId(PokemonEntity::class.java, EntityDataSerializers.FLOAT)
|
||||
|
||||
const val BATTLE_LOCK = "battle"
|
||||
const val EVOLUTION_LOCK = "evolving"
|
||||
@@ -460,6 +464,7 @@ open class PokemonEntity(
|
||||
builder.define(EVOLUTION_STARTED, false)
|
||||
builder.define(SHOWN_HELD_ITEM, ItemStack.EMPTY)
|
||||
builder.define(RIDE_BOOSTS, emptyMap())
|
||||
builder.define(RIDE_STAMINA, 1F)
|
||||
}
|
||||
|
||||
override fun onSyncedDataUpdated(data: EntityDataAccessor<*>) {
|
||||
@@ -537,8 +542,12 @@ open class PokemonEntity(
|
||||
if (passengerIndex != -1) {
|
||||
occupiedSeats[passengerIndex] = null
|
||||
}
|
||||
if (level().isClientSide) {
|
||||
MountedCameraTypeHandler.handleDismount(passenger, this)
|
||||
}
|
||||
super.removePassenger(passenger)
|
||||
if (passengers.isEmpty()) {
|
||||
ifRidingAvailable { _, _, state -> pokemon.rideStamina = state.stamina.get() }
|
||||
ridingController?.context?.state?.reset()
|
||||
ridingAnimationData.clear()
|
||||
}
|
||||
@@ -1179,6 +1188,7 @@ open class PokemonEntity(
|
||||
if (!this.canRide(player)) return@ifRidingAvailableSupply false
|
||||
if (tethering != null) return@ifRidingAvailableSupply false
|
||||
if (seats.isEmpty()) return@ifRidingAvailableSupply false
|
||||
if ((owner as? ServerPlayer)?.isInBattle() == true) return@ifRidingAvailableSupply false
|
||||
if (this.owner != player && this.passengers.isEmpty()) return@ifRidingAvailableSupply false
|
||||
return@ifRidingAvailableSupply behaviour.isActive(settings, state, this)
|
||||
}
|
||||
@@ -1237,11 +1247,19 @@ open class PokemonEntity(
|
||||
}
|
||||
|
||||
override fun checkDespawn() {
|
||||
if (pokemon.getOwnerUUID() == null && !isPersistenceRequired && (!this.pokemon.canDropHeldItem || this.pokemon.heldItem.isEmpty) && despawner.shouldDespawn(this) ) {
|
||||
if (pokemon.getOwnerUUID() == null && !isPersistenceRequired && despawner.shouldDespawn(this) ) {
|
||||
discard()
|
||||
}
|
||||
}
|
||||
|
||||
override fun isPersistenceRequired(): Boolean {
|
||||
return super.isPersistenceRequired()
|
||||
|| (this.pokemon.canDropHeldItem && !this.pokemon.heldItem.isEmpty)
|
||||
|| this.brain.checkMemory(CobblemonMemories.HIVE_LOCATION, MemoryStatus.VALUE_PRESENT)
|
||||
|| this.brain.checkMemory(CobblemonMemories.HIVE_COOLDOWN, MemoryStatus.VALUE_PRESENT)
|
||||
|| this.brain.checkMemory(CobblemonMemories.NEARBY_SACC_LEAVES, MemoryStatus.VALUE_PRESENT)
|
||||
}
|
||||
|
||||
fun setBehaviourFlag(flag: PokemonBehaviourFlag, on: Boolean) {
|
||||
entityData.set(BEHAVIOUR_FLAGS, setBitForByte(entityData.get(BEHAVIOUR_FLAGS), flag.bit, on))
|
||||
}
|
||||
@@ -1455,7 +1473,7 @@ open class PokemonEntity(
|
||||
fun tryRidingPokemon(player: ServerPlayer): Boolean {
|
||||
val event = RidePokemonEvent.Pre(player, this)
|
||||
CobblemonEvents.RIDE_EVENT_PRE.post(event)
|
||||
if(!event.isCanceled) {
|
||||
if (!event.isCanceled) {
|
||||
player.startRiding(this)
|
||||
CobblemonEvents.RIDE_EVENT_POST.post(RidePokemonEvent.Post(player, this))
|
||||
return true
|
||||
@@ -2098,16 +2116,37 @@ open class PokemonEntity(
|
||||
|
||||
public override fun addPassenger(passenger: Entity) {
|
||||
if (passenger is ServerPlayer) {
|
||||
// Recall all the rest of the player's party pokes
|
||||
passenger.party()
|
||||
.mapNotNull { it.entity }
|
||||
.filter { it != this }
|
||||
.forEach { it.recallWithAnimation() }
|
||||
|
||||
// Driver is hopping on, figure out the stamina situation
|
||||
if (passengers.isEmpty()) {
|
||||
CobblemonEvents.RIDE_EVENT_APPLY_STAMINA.post(
|
||||
RidePokemonEvent.ApplyStamina(
|
||||
player = passenger,
|
||||
pokemon = this,
|
||||
rideStamina = if (Cobblemon.config.infiniteRideStamina) -1F else entityData.get(RIDE_STAMINA)
|
||||
),
|
||||
then = { event -> entityData.set(RIDE_STAMINA, event.rideStamina) }
|
||||
)
|
||||
}
|
||||
} else if (level().isClientSide) {
|
||||
MountedCameraTypeHandler.handleMount(passenger, this)
|
||||
}
|
||||
val passengerIndex = occupiedSeats.indexOfFirst { it == null }
|
||||
if (passengerIndex != -1) {
|
||||
occupiedSeats[passengerIndex] = passenger
|
||||
}
|
||||
super.addPassenger(passenger)
|
||||
if (passengers.size == 1) {
|
||||
// Someone just started riding, fill in the stamina value! Gets run from both sides.
|
||||
ifRidingAvailable { _, _, state ->
|
||||
state.stamina.set(entityData.get(RIDE_STAMINA))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getIsJumping() = jumping
|
||||
@@ -2137,6 +2176,9 @@ open class PokemonEntity(
|
||||
super.tickRidden(driver, movementInput)
|
||||
ifRidingAvailable { behaviour, settings, state ->
|
||||
behaviour.tick(settings, state, this, driver, movementInput)
|
||||
if (entityData.get(RIDE_STAMINA) == -1F) {
|
||||
state.stamina.set(1F, forced = true)
|
||||
}
|
||||
|
||||
if (!this.level().isClientSide) {
|
||||
val pose = behaviour.pose(settings, state, this)
|
||||
@@ -2366,8 +2408,12 @@ open class PokemonEntity(
|
||||
|
||||
fun rideFovMult(): Float {
|
||||
val driver = this.controllingPassenger as? Player ?: return 1.0f
|
||||
val fovEffectScale = Minecraft.getInstance().options.fovEffectScale().get().toFloat()
|
||||
|
||||
return ifRidingAvailableSupply(fallback = 1.0f) { behaviour, settings, state ->
|
||||
behaviour.rideFovMultiplier(settings, state, this, driver)
|
||||
val rideFov = behaviour.rideFovMultiplier(settings, state, this, driver)
|
||||
|
||||
1f + (rideFov - 1f) * fovEffectScale
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2399,6 +2445,7 @@ open class PokemonEntity(
|
||||
override fun canWalkOnWater() = exposedForm.behaviour.moving.swim.canWalkOnWater
|
||||
override fun canFly() = exposedForm.behaviour.moving.fly.canFly
|
||||
override fun canSwimInLava() = exposedForm.behaviour.moving.swim.canSwimInLava
|
||||
override fun canPathThroughSaccLeaves() = this.config.getMap().getOrDefault("can_path_through_sacc_leaves", DoubleValue.ZERO).asDouble() == 1.0
|
||||
override fun canWalkOnLava() = exposedForm.behaviour.moving.swim.canWalkOnLava
|
||||
override fun entityOnGround() = onGround()
|
||||
|
||||
|
||||
+3
@@ -235,6 +235,9 @@ class PokemonServerDelegate : PokemonSideDelegate {
|
||||
|
||||
entity.entityData.set(PokemonEntity.FRIENDSHIP, entity.pokemon.friendship)
|
||||
entity.entityData.set(PokemonEntity.CAUGHT_BALL, trackedBall)
|
||||
if (entity.pokemon.rideStamina != entity.entityData.get(PokemonEntity.RIDE_STAMINA) && entity.passengers.isEmpty()) {
|
||||
entity.entityData.set(PokemonEntity.RIDE_STAMINA, entity.pokemon.rideStamina)
|
||||
}
|
||||
|
||||
val currentRideBoosts = entity.entityData.get(PokemonEntity.RIDE_BOOSTS)
|
||||
val newRideBoosts = entity.pokemon.getRideBoosts()
|
||||
|
||||
+50
-40
@@ -9,17 +9,22 @@
|
||||
package com.cobblemon.mod.common.entity.pokemon.ai.sensors
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.block.SaccharineLeafBlock
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.tags.PoiTypeTags
|
||||
import net.minecraft.world.entity.ai.sensing.Sensor
|
||||
import net.minecraft.world.level.block.BeehiveBlock
|
||||
import net.minecraft.world.entity.ai.village.poi.PoiManager
|
||||
import net.minecraft.world.entity.ai.village.poi.PoiRecord
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.block.entity.BeehiveBlockEntity
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
|
||||
|
||||
class BeeHiveSensor : Sensor<PokemonEntity>(300) {
|
||||
override fun requires() = setOf(CobblemonMemories.HIVE_LOCATION)
|
||||
override fun requires() = setOf(CobblemonMemories.HIVE_LOCATION, CobblemonMemories.HIVE_BLACKLIST)
|
||||
override fun doTick(world: ServerLevel, entity: PokemonEntity) {
|
||||
val brain = entity.brain
|
||||
val currentHive = brain.getMemory(CobblemonMemories.HIVE_LOCATION).orElse(null)
|
||||
@@ -27,35 +32,30 @@ class BeeHiveSensor : Sensor<PokemonEntity>(300) {
|
||||
if (currentHive != null) {
|
||||
val state = world.getBlockState(currentHive)
|
||||
|
||||
if (!isValidHiveOrLeaf(state) || !hasReachableAdjacentSide(world, entity, currentHive)) {
|
||||
brain.eraseMemory(CobblemonMemories.HIVE_LOCATION)
|
||||
} else if (isAtMaxHoney(state)) {
|
||||
if (!isValidHive(state) || !hasReachableAdjacentSide(world, currentHive)) {
|
||||
brain.eraseMemory(CobblemonMemories.HIVE_LOCATION)
|
||||
} else {
|
||||
return // We already have a valid hive, no need to search for another
|
||||
}
|
||||
}
|
||||
|
||||
// Search for nearest hive/nest
|
||||
val searchRadius = 16 // is this too big for us to use?
|
||||
val centerPos = entity.blockPosition()
|
||||
|
||||
var closestHivePos: BlockPos? = null
|
||||
var closestDistance = Double.MAX_VALUE
|
||||
|
||||
BlockPos.betweenClosedStream(
|
||||
centerPos.offset(-searchRadius, -2, -searchRadius),
|
||||
centerPos.offset(searchRadius, 2, searchRadius)
|
||||
).forEach { pos ->
|
||||
val state = world.getBlockState(pos)
|
||||
val list = findNearbyHivesWithSpace(entity)
|
||||
|
||||
if (isValidHiveOrLeaf(state) && !isAtMaxHoney(state) && hasReachableAdjacentSide(world, entity, pos)) {
|
||||
val distance = pos.distToCenterSqr(centerPos.x + 0.5, centerPos.y + 0.5, centerPos.z + 0.5)
|
||||
if (distance < closestDistance) {
|
||||
closestDistance = distance
|
||||
closestHivePos = pos.immutable()
|
||||
if (!list.isEmpty()) {
|
||||
val blackList = brain.getMemory(CobblemonMemories.HIVE_BLACKLIST).orElse(emptyList())
|
||||
for (blockPos in list) {
|
||||
if (blackList.contains(blockPos)) continue
|
||||
if (hasReachableAdjacentSide(world, blockPos)) {
|
||||
closestHivePos = blockPos
|
||||
break
|
||||
}
|
||||
}
|
||||
if (closestHivePos == null) {
|
||||
brain.eraseMemory(CobblemonMemories.HIVE_BLACKLIST)
|
||||
closestHivePos = list.first()
|
||||
}
|
||||
}
|
||||
|
||||
if (closestHivePos != null) {
|
||||
@@ -63,37 +63,47 @@ class BeeHiveSensor : Sensor<PokemonEntity>(300) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun isAtMaxHoney(state: net.minecraft.world.level.block.state.BlockState): Boolean {
|
||||
return when {
|
||||
isHiveBlock(state) -> state.getValue(BeehiveBlock.HONEY_LEVEL) == BeehiveBlock.MAX_HONEY_LEVELS
|
||||
isSaccharineLeafBlock(state) -> state.getValue(SaccharineLeafBlock.AGE) == SaccharineLeafBlock.MAX_AGE
|
||||
else -> true // Unknown block type
|
||||
}
|
||||
private fun isValidHive(state: net.minecraft.world.level.block.state.BlockState): Boolean {
|
||||
return isHiveBlock(state)
|
||||
}
|
||||
|
||||
private fun isValidHiveOrLeaf(state: net.minecraft.world.level.block.state.BlockState): Boolean {
|
||||
return isHiveBlock(state) || isSaccharineLeafBlock(state)
|
||||
}
|
||||
|
||||
private fun isSaccharineLeafBlock(state: net.minecraft.world.level.block.state.BlockState): Boolean {
|
||||
return state.block is SaccharineLeafBlock
|
||||
}
|
||||
|
||||
private fun isHiveBlock(state: net.minecraft.world.level.block.state.BlockState): Boolean {
|
||||
return state.`is`(Blocks.BEEHIVE) || state.`is`(Blocks.BEE_NEST)
|
||||
}
|
||||
|
||||
private fun hasReachableAdjacentSide(world: ServerLevel, entity: PokemonEntity, pos: BlockPos): Boolean {
|
||||
private fun hasReachableAdjacentSide(world: ServerLevel, pos: BlockPos): Boolean {
|
||||
for (dir in Direction.entries) {
|
||||
val adjacentPos = pos.relative(dir)
|
||||
if (world.isEmptyBlock(adjacentPos)) {
|
||||
val nav = entity.navigation
|
||||
val path = nav.createPath(adjacentPos, 0)
|
||||
if (path != null && path.canReach()) {
|
||||
return true
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun findNearbyHivesWithSpace(entity: PokemonEntity): List<BlockPos> {
|
||||
val blockPos = entity.blockPosition()
|
||||
val poiManager = (entity.level() as ServerLevel).poiManager
|
||||
val stream = poiManager.getInRange(
|
||||
{ holder -> holder.`is`(PoiTypeTags.BEE_HOME) },
|
||||
blockPos,
|
||||
20,
|
||||
PoiManager.Occupancy.ANY
|
||||
)
|
||||
return stream
|
||||
.map(PoiRecord::getPos)
|
||||
.filter { pos -> doesHiveHaveSpace(pos, entity.level()) }
|
||||
.sorted { pos1, pos2 -> pos1.distSqr(blockPos).toInt() - pos2.distSqr(blockPos).toInt() }
|
||||
.toList()
|
||||
}
|
||||
|
||||
private fun doesHiveHaveSpace(hivePos: BlockPos, world: Level): Boolean {
|
||||
val blockEntity: BlockEntity? = world.getBlockEntity(hivePos)
|
||||
if (blockEntity is BeehiveBlockEntity) {
|
||||
return !blockEntity.isFull
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -45,10 +45,12 @@ class DrowsySensor : Sensor<PokemonEntity>(20) {
|
||||
entity.brain.eraseMemory(CobblemonMemories.POKEMON_DROWSY)
|
||||
}
|
||||
} else {
|
||||
if (!isDrowsy && shouldBeDrowsy) {
|
||||
if (!isDrowsy && shouldBeDrowsy && entity.random.nextFloat() < rest.drowsyChance) {
|
||||
entity.brain.setMemory(CobblemonMemories.POKEMON_DROWSY, true)
|
||||
} else if (isDrowsy && !shouldBeDrowsy) {
|
||||
entity.brain.eraseMemory(CobblemonMemories.POKEMON_DROWSY)
|
||||
} else if (isDrowsy && entity.random.nextFloat() < rest.rouseChance) {
|
||||
entity.brain.eraseMemory(CobblemonMemories.POKEMON_DROWSY)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+43
-16
@@ -10,46 +10,73 @@ package com.cobblemon.mod.common.entity.pokemon.ai.sensors
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.distanceTo
|
||||
import com.cobblemon.mod.common.util.getMemorySafely
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Vec3i
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.tags.BlockTags
|
||||
import net.minecraft.world.entity.ai.sensing.Sensor
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.block.DoublePlantBlock
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties
|
||||
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf
|
||||
|
||||
class FlowerSensor : Sensor<PokemonEntity>(120) {
|
||||
override fun requires() = setOf(CobblemonMemories.NEARBY_FLOWERS)
|
||||
|
||||
override fun requires() = setOf(CobblemonMemories.NEARBY_FLOWER)
|
||||
|
||||
override fun doTick(world: ServerLevel, entity: PokemonEntity) {
|
||||
val brain = entity.brain
|
||||
|
||||
val searchRadius = 32
|
||||
val centerPos = entity.blockPosition()
|
||||
val flowers = mutableListOf<BlockPos>()
|
||||
// Check curr memory
|
||||
val currPos = brain.getMemorySafely(CobblemonMemories.NEARBY_FLOWER).orElse(null)
|
||||
if (currPos != null && isFlower(entity.level().getBlockState(currPos)) && entity.distanceTo(currPos) <= 32) {
|
||||
return
|
||||
}
|
||||
|
||||
val searchRadius = 5
|
||||
val centerPos = entity.blockPosition()
|
||||
var flowerPos: BlockPos? = null
|
||||
var shortestDist = Double.MAX_VALUE
|
||||
BlockPos.betweenClosedStream(
|
||||
centerPos.offset(-searchRadius, -2, -searchRadius),
|
||||
centerPos.offset(searchRadius, 2, searchRadius)
|
||||
).forEach { pos ->
|
||||
val state = world.getBlockState(pos)
|
||||
if (isFlower(state) && isPathfindableTo(entity, pos)) {
|
||||
flowers += pos.immutable()
|
||||
if (isFlower(state)) {
|
||||
val distance = pos.distSqr(Vec3i(centerPos.x, centerPos.y, centerPos.z))
|
||||
if (distance < shortestDist) {
|
||||
flowerPos = BlockPos(pos)
|
||||
shortestDist = distance
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!flowers.isEmpty()) {
|
||||
brain.setMemory(CobblemonMemories.NEARBY_FLOWERS, flowers)
|
||||
|
||||
if (flowerPos != null) {
|
||||
brain.setMemory(CobblemonMemories.NEARBY_FLOWER, flowerPos)
|
||||
} else {
|
||||
brain.eraseMemory(CobblemonMemories.NEARBY_FLOWERS)
|
||||
brain.eraseMemory(CobblemonMemories.NEARBY_FLOWER)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isFlower(state: BlockState): Boolean {
|
||||
return state.`is`(BlockTags.FLOWERS)
|
||||
}
|
||||
|
||||
private fun isPathfindableTo(entity: PokemonEntity, pos: BlockPos): Boolean {
|
||||
val nav = entity.navigation
|
||||
val path = nav.createPath(pos, 0)
|
||||
return path != null && path.canReach()
|
||||
// Borrowed from Bee.class
|
||||
if (state.hasProperty(BlockStateProperties.WATERLOGGED) && state.getValue(
|
||||
BlockStateProperties.WATERLOGGED
|
||||
) as Boolean
|
||||
) {
|
||||
return false
|
||||
} else if (state.`is`(BlockTags.FLOWERS)) {
|
||||
if (state.`is`(Blocks.SUNFLOWER)) {
|
||||
return state.getValue(DoublePlantBlock.HALF) == DoubleBlockHalf.UPPER
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
Loaded 100 of 774 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user