mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-21 14:46:25 -04:00
Compare commits
409
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d0baab2ba | ||
|
|
767e279cf1 | ||
|
|
6ace08aaa6 | ||
|
|
8b81b13d01 | ||
|
|
f19d9410c0 | ||
|
|
9ac3a9249d | ||
|
|
4f340b2eee | ||
|
|
5cff52df5f | ||
|
|
ca311fa97c | ||
|
|
27020d3068 | ||
|
|
3ac4b8622f | ||
|
|
acd7a0583c | ||
|
|
e341948bd4 | ||
|
|
1a465abf9d | ||
|
|
e56a6e5b1a | ||
|
|
33d707a73b | ||
|
|
ba8e40d5a7 | ||
|
|
e3c3cd380c | ||
|
|
578ce789b1 | ||
|
|
460e8f7501 | ||
|
|
2fee86e7bc | ||
|
|
f73e631f81 | ||
|
|
0ca0c1a552 | ||
|
|
b3bf2c5ded | ||
|
|
7875006c8e | ||
|
|
67bb63b638 | ||
|
|
511f97b963 | ||
|
|
54c426f5ff | ||
|
|
f89902ece8 | ||
|
|
52c6bbd842 | ||
|
|
8246a822cf | ||
|
|
54202bed98 | ||
|
|
e6313cf4c5 | ||
|
|
7debc6e047 | ||
|
|
bf9b69a143 | ||
|
|
d7f34972c1 | ||
|
|
fa7356d2ed | ||
|
|
8d1f41919d | ||
|
|
b40c21d99e | ||
|
|
461d8bd282 | ||
|
|
84d34709a3 | ||
|
|
b6c04e8746 | ||
|
|
81a96afaa6 | ||
|
|
724332dd34 | ||
|
|
f5bfd64495 | ||
|
|
bf8f7f628f | ||
|
|
898fdf983f | ||
|
|
a547e0f535 | ||
|
|
564ced926c | ||
|
|
a93dd14fd8 | ||
|
|
f0535901cb | ||
|
|
7a42df591f | ||
|
|
616419880f | ||
|
|
9fa38430c0 | ||
|
|
26012278e7 | ||
|
|
2c0967d293 | ||
|
|
885fc72d93 | ||
|
|
8130cd0998 | ||
|
|
447d35f28b | ||
|
|
bf82def925 | ||
|
|
dace364701 | ||
|
|
d737444ac9 | ||
|
|
95f58ba557 | ||
|
|
8993b007a5 | ||
|
|
c84f9dd112 | ||
|
|
eea7477f7f | ||
|
|
241abd79d7 | ||
|
|
35618cea46 | ||
|
|
31b97d391d | ||
|
|
7769a73246 | ||
|
|
65bf9507d3 | ||
|
|
6d336fc27b | ||
|
|
16df7695c4 | ||
|
|
8fd63912a3 | ||
|
|
04941a9a38 | ||
|
|
1853a1677a | ||
|
|
94f8de8ddc | ||
|
|
7ea866d82a | ||
|
|
ea529a52c2 | ||
|
|
1f6dd03064 | ||
|
|
d62ea394ee | ||
|
|
d0b8a3368c | ||
|
|
6d23e762d6 | ||
|
|
6edb0c19c4 | ||
|
|
71e9adae1f | ||
|
|
35b53daa09 | ||
|
|
937c30fca5 | ||
|
|
141249e6c7 | ||
|
|
94f9bf9f50 | ||
|
|
4638b01279 | ||
|
|
e39d59c37a | ||
|
|
072071d679 | ||
|
|
aa4400395b | ||
|
|
09ad3d0a4d | ||
|
|
de7df10f36 | ||
|
|
897bcf6fc0 | ||
|
|
1e14042455 | ||
|
|
8583c9af4d | ||
|
|
ce756997d6 | ||
|
|
4efc5b6748 | ||
|
|
7ed6075410 | ||
|
|
320d995672 | ||
|
|
8ae91587aa | ||
|
|
61362fa1b1 | ||
|
|
d010129864 | ||
|
|
282f002895 | ||
|
|
863f6de059 | ||
|
|
8ddf628f19 | ||
|
|
8762d518c1 | ||
|
|
46798d694e | ||
|
|
056dd0fd4b | ||
|
|
3ac00d976b | ||
|
|
b30a76855b | ||
|
|
e976556ae3 | ||
|
|
9f16eca621 | ||
|
|
f4a94bd732 | ||
|
|
b6c964e03b | ||
|
|
aed2204483 | ||
|
|
3ed46cb7af | ||
|
|
cf9efe9b8c | ||
|
|
02b9431731 | ||
|
|
a30ae0ccef | ||
|
|
a2905f4d37 | ||
|
|
b3aba1532c | ||
|
|
6369bdb612 | ||
|
|
b5db5605ef | ||
|
|
0207459a0f | ||
|
|
0e2fdfbce8 | ||
|
|
8c9da885c7 | ||
|
|
a5b6529f3c | ||
|
|
6e9bdb6019 | ||
|
|
b430b7db76 | ||
|
|
8015ff0e20 | ||
|
|
ee78657e3d | ||
|
|
6cc84cd38c | ||
|
|
31d6ff541e | ||
|
|
841a40c973 | ||
|
|
e1a4086f24 | ||
|
|
df049a315c | ||
|
|
9ce5486189 | ||
|
|
b1992a94d3 | ||
|
|
167a1ea8eb | ||
|
|
f95beaa7a1 | ||
|
|
1c0f7bbf8f | ||
|
|
34cc2cda46 | ||
|
|
696e58bd1a | ||
|
|
10412b80ca | ||
|
|
458c2ce0ed | ||
|
|
6182715644 | ||
|
|
b41c4c21a8 | ||
|
|
e1893f50ae | ||
|
|
a1bdf3ded6 | ||
|
|
a458b31c9f | ||
|
|
03b5336eb8 | ||
|
|
a270371632 | ||
|
|
a9caf92d2f | ||
|
|
9e2d00df63 | ||
|
|
e8003bb29a | ||
|
|
a248d661fa | ||
|
|
59390f4d84 | ||
|
|
99b7e4a89e | ||
|
|
fb37e543cf | ||
|
|
c0c75a9735 | ||
|
|
3febee21b6 | ||
|
|
c3a017687c | ||
|
|
afd082c966 | ||
|
|
a6a1f7b75b | ||
|
|
72738a45e6 | ||
|
|
ff4d9ae208 | ||
|
|
a87d522f6d | ||
|
|
8a0076acb4 | ||
|
|
f7e1def555 | ||
|
|
c13f6ae627 | ||
|
|
c24ab2049d | ||
|
|
b7b1850a4e | ||
|
|
8995c107f7 | ||
|
|
dca6b5273d | ||
|
|
d6a412b91a | ||
|
|
2e8483cdc7 | ||
|
|
5984d7a126 | ||
|
|
6d8e645092 | ||
|
|
6b1c2e2074 | ||
|
|
8af5b5e07a | ||
|
|
7ae19ca774 | ||
|
|
830f00553e | ||
|
|
55f0db2263 | ||
|
|
411788a07e | ||
|
|
f6151041c5 | ||
|
|
c87f56c83f | ||
|
|
4478532bcb | ||
|
|
184348d6fa | ||
|
|
04d288ed7e | ||
|
|
0d5cce730e | ||
|
|
3e01535203 | ||
|
|
f0d99a9d83 | ||
|
|
b4eb46d632 | ||
|
|
7e52336255 | ||
|
|
2b40b5b689 | ||
|
|
da889f220b | ||
|
|
ac65910380 | ||
|
|
ba6847be9a | ||
|
|
5ddbcd1830 | ||
|
|
47605646d0 | ||
|
|
d9fdf089c2 | ||
|
|
41db2a53ce | ||
|
|
85d8779818 | ||
|
|
e9a405694c | ||
|
|
d817ce1471 | ||
|
|
ce09b66db5 | ||
|
|
d0c666a20d | ||
|
|
04cef915e4 | ||
|
|
e50412443e | ||
|
|
3fe1f87f18 | ||
|
|
5a0fc199ff | ||
|
|
beb769c2a5 | ||
|
|
a7b6fae4ed | ||
|
|
af2ff7bbfa | ||
|
|
4f3575b2c6 | ||
|
|
8555168a6a | ||
|
|
98c248ef13 | ||
|
|
4a2c69d47c | ||
|
|
1b5c0be975 | ||
|
|
5924398eff | ||
|
|
a08855ab37 | ||
|
|
91abe39cdd | ||
|
|
ad8aab7c19 | ||
|
|
aa6b196c29 | ||
|
|
c23cb644d9 | ||
|
|
a8b12cfca3 | ||
|
|
5268447fa3 | ||
|
|
b489e747bb | ||
|
|
acf467c8a3 | ||
|
|
08f957e33b | ||
|
|
e17d38c53a | ||
|
|
0ff5b95c44 | ||
|
|
818b39e945 | ||
|
|
0397e39735 | ||
|
|
6ca1d23f45 | ||
|
|
30666349a1 | ||
|
|
44def2be76 | ||
|
|
507f70c2d5 | ||
|
|
d91118d05f | ||
|
|
07d8e6ed09 | ||
|
|
fb34d4bd23 | ||
|
|
6ca1337ff9 | ||
|
|
98106cad12 | ||
|
|
0d344337dd | ||
|
|
64d160020b | ||
|
|
fb4c80f68c | ||
|
|
3d27681aaa | ||
|
|
2b5433f9da | ||
|
|
352202203a | ||
|
|
62cfbd7087 | ||
|
|
5a64e8ea1b | ||
|
|
8dc9863a5d | ||
|
|
9bad141c3f | ||
|
|
9280258413 | ||
|
|
51a11163dd | ||
|
|
fe8e4dcaff | ||
|
|
e0bd6766fc | ||
|
|
4da800d396 | ||
|
|
f3246ae14a | ||
|
|
8d7ebeef4f | ||
|
|
d5ad84a495 | ||
|
|
1560b142d2 | ||
|
|
47f87b1be3 | ||
|
|
b01086270a | ||
|
|
da6a09c942 | ||
|
|
8d5eb5883d | ||
|
|
d5fa693f43 | ||
|
|
0d12bf1190 | ||
|
|
4f773f63cb | ||
|
|
3f3ae74535 | ||
|
|
7429fea802 | ||
|
|
ac5cd47715 | ||
|
|
9901d39f9b | ||
|
|
c635a1d331 | ||
|
|
cf2173a281 | ||
|
|
710d37f453 | ||
|
|
1fb3416211 | ||
|
|
f49f2a7305 | ||
|
|
b0e9c1ab28 | ||
|
|
ac1c7d8b78 | ||
|
|
dec5151eb8 | ||
|
|
196edc2711 | ||
|
|
18015a26fd | ||
|
|
aa296a79a9 | ||
|
|
92dd85643e | ||
|
|
8849de1bfd | ||
|
|
2a349697b4 | ||
|
|
a4055e6206 | ||
|
|
03bda4e27d | ||
|
|
5d8abbd4c7 | ||
|
|
6b167a7a17 | ||
|
|
5c64bc94ff | ||
|
|
d36c24075c | ||
|
|
d1a8122296 | ||
|
|
a8e6e684ab | ||
|
|
188fc2b5d9 | ||
|
|
2bc2e3f020 | ||
|
|
7a15e6b004 | ||
|
|
6ee6beddeb | ||
|
|
b92960da77 | ||
|
|
99618184e7 | ||
|
|
fcdff126fd | ||
|
|
3b285cc8bd | ||
|
|
4dead98e6b | ||
|
|
db36f8da2a | ||
|
|
3a448071d7 | ||
|
|
7215860d74 | ||
|
|
dc899ffc1b | ||
|
|
88fe55bbb9 | ||
|
|
3d3c421b5c | ||
|
|
3c2cfa4ffc | ||
|
|
89a4edb327 | ||
|
|
ab37580258 | ||
|
|
c116c01fd6 | ||
|
|
e3ad8f8079 | ||
|
|
a491d508b6 | ||
|
|
3e11d0550f | ||
|
|
e8b50f8115 | ||
|
|
02fb825328 | ||
|
|
8df6eea107 | ||
|
|
1376bb68f4 | ||
|
|
beb8f2ccf1 | ||
|
|
d9de8f2678 | ||
|
|
510dfec0e5 | ||
|
|
e54932c876 | ||
|
|
dd14c3bbdd | ||
|
|
5ea237f8a0 | ||
|
|
fb154ba457 | ||
|
|
f7812896a8 | ||
|
|
b0d57dd875 | ||
|
|
6c09e2b553 | ||
|
|
593104fb0a | ||
|
|
e314664731 | ||
|
|
d0a38a9704 | ||
|
|
6e155d7651 | ||
|
|
ae8f8a2fb8 | ||
|
|
5a6a83aac1 | ||
|
|
e8236b55a4 | ||
|
|
2ea07899ea | ||
|
|
d0ce03cd5e | ||
|
|
8ae0c409a3 | ||
|
|
2782cb5f34 | ||
|
|
2f10707211 | ||
|
|
f40a9d762a | ||
|
|
17587f97e5 | ||
|
|
5230820657 | ||
|
|
61c55e136f | ||
|
|
22cced74f5 | ||
|
|
3cd2dec8e0 | ||
|
|
cea930893a | ||
|
|
8662364ca8 | ||
|
|
1fd079b1b4 | ||
|
|
244876a26c | ||
|
|
e7790f530f | ||
|
|
04a9ab0e67 | ||
|
|
3f338d27c3 | ||
|
|
5da3dfb451 | ||
|
|
fd329e00cd | ||
|
|
6da47a8b2c | ||
|
|
860c73fac9 | ||
|
|
e26fdd4bdd | ||
|
|
8e642f71b8 | ||
|
|
f17884b4e1 | ||
|
|
c40b456948 | ||
|
|
7e74e85315 | ||
|
|
21fd4d7cbf | ||
|
|
908bff9892 | ||
|
|
fa14f70bbb | ||
|
|
188ae2ac85 | ||
|
|
346559f292 | ||
|
|
331b282fcf | ||
|
|
7f97eeafed | ||
|
|
51f5a1f5a8 | ||
|
|
7c0535b8bd | ||
|
|
4f15ac0cbc | ||
|
|
35a0d8a80d | ||
|
|
c0270d3ef0 | ||
|
|
82a1eb2a55 | ||
|
|
a528ea952a | ||
|
|
af2df51a2a | ||
|
|
95a0f9603c | ||
|
|
d38aa6b1a2 | ||
|
|
4566e1b33f | ||
|
|
f2d16ca9b7 | ||
|
|
d6fbb70db0 | ||
|
|
150a5c668a | ||
|
|
1bf01a2826 | ||
|
|
4d1bf677a1 | ||
|
|
069f56acfd | ||
|
|
19cdc8fbef | ||
|
|
1408b94f06 | ||
|
|
de081dc514 | ||
|
|
1538f12934 | ||
|
|
857f67604c | ||
|
|
ae49e3f977 | ||
|
|
ec01a03820 | ||
|
|
96cc3671da | ||
|
|
ad7c9c560c | ||
|
|
ee15ff6b35 | ||
|
|
ca83103703 | ||
|
|
1aeb894b09 | ||
|
|
8e9ab26963 | ||
|
|
44b4fbcfe3 | ||
|
|
42cc1dd8a9 | ||
|
|
d69310e52c | ||
|
|
a0f89274d1 |
+4
-1
@@ -33,4 +33,7 @@ common/src/main/resources/assets/cobblemon/showdown
|
||||
# Generated files
|
||||
*/generated/resources/*
|
||||
/fabric/src/generated/resources/cobblemon-common.accesswidener
|
||||
/.ignored/
|
||||
/.ignored/
|
||||
|
||||
# MacOS
|
||||
.DS_Store
|
||||
+141
-1
@@ -1,5 +1,6 @@
|
||||
# Changelog
|
||||
## [1.5.0](#1-5-0)
|
||||
|
||||
### Additions
|
||||
- Added over (number here) ruin structures, where you can find Pokémon-themed Armor Trims and Pottery Sherds, Tumblestones, and more.
|
||||
- Added (number here) fossil structures, where you can brush Suspicious Sand/Gravel for Fossils.
|
||||
@@ -14,15 +15,133 @@
|
||||
- Added the hidden "True Vivillionaire" advancement.
|
||||
- The "Poké Ball" Vivillon variant is now obtainable by evolving a Spewpa after obtaining the "Aspiring Vivillionaire" advancement.
|
||||
- Added dynamic lighting support for any Species or Forms when using [LambDynamicLights](https://modrinth.com/mod/lambdynamiclights) or [Dynamic Lights Reforged](https://www.curseforge.com/minecraft/mc-mods/dynamiclights-reforged), at this time we don't ship with any defaults for this feature but addon creators can make use of this feature.
|
||||
- Added a Display Case block! Use it to display your archaeological findings, or other items.
|
||||
- Added 6 Pokémon-themed Pottery Sherds, obtained from ruin structures.
|
||||
- Added a Pokémon-themed armor trim, obtained from ruin structures.
|
||||
- You can now find Nether Fire Stone Ore in, surprisingly, the Nether.
|
||||
- You'll also find Terracotta Sun Stone Ore in Badlands biomes.
|
||||
- Added effects for many Poké Balls when sending out Pokémon or capturing.
|
||||
- Added a new send-out ball toss animation that showcases the ball used for the Pokémon.
|
||||
- Added simple move animations for Pokémon in battle with a proof of concept for more complicated animations.
|
||||
- Added the EV Boosting Feathers.
|
||||
- Added Type Gems.
|
||||
- Added various new tags for searchability and better compatibility.
|
||||
- Added the [Ability Capsule](https://bulbapedia.bulbagarden.net/wiki/Ability_Capsule) and [Patch](https://bulbapedia.bulbagarden.net/wiki/Ability_Patch), these have no acquisition method for now and only work as intended with the traditional ability format of 1 to 2 common abilities and 1 hidden ability.
|
||||
- Added Gilded Chests, available in all Apricorn colors.
|
||||
- Added Relic Coins, Relic Coin Pouches, and Relic Coin Sacks.
|
||||
- Added various new tags for searchability and better compatibility.
|
||||
- Added Type Gems. These items hold no functionality for now. Start collecting though...
|
||||
- Added 6 custom Pottery Sherds, obtained from ruin structures.
|
||||
- Added cries to Meowth, Alolan Meowth, Galaraian Meowth,
|
||||
- Completed the advancement for placing a Tumblestone near Lava or Magma to make it grow.
|
||||
- Added new held items: Ability Shield, Absorb Bulb, Air Balloon, Binding Band, Blunder Policy, Cell Battery, Covert Cloak, Damp Rock, Eject Button, Eviolite, Expert Belt, Float Stone, Focus Sash, Heat Rock, Icy Rock, Iron Ball, Light Ball, Loaded Dice, Red Card, Shell Bell, Sticky Barb, Smooth Rock, Soothe Bell and Weakness Policy.
|
||||
|
||||
### Pokémon Added
|
||||
#### Gen 2
|
||||
- Sentret
|
||||
- Furret
|
||||
- Qwilfish
|
||||
- Heracross
|
||||
- Skarmory
|
||||
- Ferroseed
|
||||
- Ferrothorn
|
||||
|
||||
#### Gen 3
|
||||
- Lileep
|
||||
- Cradily
|
||||
- Anorith
|
||||
- Armaldo
|
||||
- Tropius
|
||||
- Roselia
|
||||
|
||||
#### Gen 4
|
||||
- Shieldon
|
||||
- Bastiodon
|
||||
- Cranidos
|
||||
- Rampardos
|
||||
- Budew
|
||||
- Roserade
|
||||
|
||||
#### Gen 5
|
||||
- Tirtouga
|
||||
- Carracosta
|
||||
- Archen
|
||||
- Archeops
|
||||
- Zorua
|
||||
- Zoroark
|
||||
- Petilil
|
||||
- Lilligant
|
||||
- Darumaka
|
||||
- Darmanitan
|
||||
- Woobat
|
||||
- Swoobat
|
||||
- Sandile
|
||||
- Krokorok
|
||||
- Krookodile
|
||||
- Frillish
|
||||
- Jellicent
|
||||
- Cubchoo
|
||||
- Beartic
|
||||
- Deino
|
||||
- Zweilous
|
||||
- Hydreigon
|
||||
- Larvesta
|
||||
- Volcarona
|
||||
|
||||
#### Gen 6
|
||||
- Tyrunt
|
||||
- Tyrantrum
|
||||
- Amaura
|
||||
- Aurorus
|
||||
- Goomy
|
||||
- Sliggoo
|
||||
- Goodra
|
||||
|
||||
#### Gen 7
|
||||
- Turtonator
|
||||
- Fomantis
|
||||
- Lurantis
|
||||
- Salandit
|
||||
- Salazzle
|
||||
- Jangmo-o
|
||||
- Hakamo-o
|
||||
- Kommo-o
|
||||
|
||||
#### Gen 8
|
||||
- Gossifleur
|
||||
- Eldegoss
|
||||
- Arctozolt
|
||||
- Arctovish
|
||||
- Dracozolt
|
||||
- Dracovish
|
||||
- Basculegion
|
||||
- Hisuian Zorua
|
||||
- Hisuian Zoroark
|
||||
- Hisuian Voltorb
|
||||
- Hisuian Electrode
|
||||
- Hisuian Qwilfish
|
||||
- Overqwil
|
||||
- Hisuian Sneasel
|
||||
- Sneasler
|
||||
- Stonjourner
|
||||
- Cufant
|
||||
- Copperajah
|
||||
- Dreepy
|
||||
- Drakloak
|
||||
- Dragapult
|
||||
- Hisuian Sliggoo
|
||||
- Hisuian Goodra
|
||||
|
||||
#### Gen 9
|
||||
- Gimmighoul.
|
||||
- Using Relic Coins, you can increase Gimmighoul's Coin Stash. Upon reaching 999, it can be evolved into Gholdengo.
|
||||
- Additionally, if you give Gimmighoul a Netherite Scrap, you can increase its Netherite Stash. Who knows what might happen if it fills up?
|
||||
|
||||
|
||||
### Changes
|
||||
- Pokémon now transition more smoothly between different poses.
|
||||
- Updated models for Mimikyu, Alcremie, Squirtle, Wartortle, Blastoise, Omanyte, Omastar, Growlithe, Swinub, Piloswine, Basculine, Rowlet, Dartrix, Decidueye, Kabuto, Kabutops, Piplup, Prinplup, Elekid, Electabuzz, Cubone, Marowak, Paras, Drifloon, Drifblim, Venonat, Venomoth, Yanma, Yanmega, and Raboot.
|
||||
- Updated animations for Diglett, Dugtrio, Dragonite, Omanyte, Omastar, Pinsir, Falinks, Lechonk, Litwick, Lampent, Chandelure, Carnivine, Galarian Meowth, Galarian Rapidash, Venonat, Venomoth, Phanphy, Donphan, Dratini, Dragonair, Happiny, Chansey, Blissey, Volbeat, Illumise, Numel, Drifloon, and Drifblim.
|
||||
- Added more held items to the held item tag, and Metal Coat to the held item tab.
|
||||
- Added all ores to the modloader ore tags, and added tags for each ore type to the mod (both blocks and items).
|
||||
- Changed the Destiny Knot to be crafted with a Ghast Tear, rather than a diamond.
|
||||
@@ -32,8 +151,12 @@
|
||||
- Updated movesets to add Gen 9 DLC moves.
|
||||
- Apricorn Sprouts can now be planted directly on Apricorn leaves to create a new Apricorn of the same color.
|
||||
- Added tooltips to interaction GUIs to make it clearer what they do.
|
||||
- Poké Ball recipes now use tags for their center ingredient, rather than specificied Copper Ingot, Iron Ingot, Gold Ingot, and Diamond, allowing for further datapack customisation.
|
||||
- Starter Toast now closes once corresponding button is pressed once.
|
||||
- Moved some items in the vanilla Food & Drinks category.
|
||||
|
||||
### Fixes
|
||||
- Resized Snorlax
|
||||
- Re-added the recipe for the Iron Vitamin.
|
||||
- Cleaned up empty evolutions declaration in species files (no, I'm not listing all 169 by name).
|
||||
- Fixed Exeggcute not being able to evolve.
|
||||
@@ -46,6 +169,14 @@
|
||||
- Fixed Poké Balls freezing in an open state if you look away when it's meant to close.
|
||||
- Adds a translation string name to the Empty Pokeball entity.
|
||||
- Fixed very many issues with Bedrock particle effects.
|
||||
- Fixed Arbok patterns not being as specific in spawning as they were intended.
|
||||
- Fixed Pokémon not avoiding danger at all when pathfinding.
|
||||
- Fixed Sobble line not being able to swim or breathe underwater.
|
||||
- Fixed incompatibility with [Just Enough Resources](https://modrinth.com/mod/just-enough-resources-jer).
|
||||
- Fixed incompatibility with [Visual Overhaul](https://modrinth.com/mod/visual-overhaul).
|
||||
- Fixed an issue that allowed Pokemon to spawn on rails.
|
||||
- Fixed the data set on Pokémon when abilities are given via properties such as in ``/spawnpokemon``.
|
||||
- Fixed sometimes Pokémon losing hidden abilities when evolving, this fix will only take effect to newly created Pokémon.
|
||||
|
||||
### Developer
|
||||
- Significantly changed the way properties in PokemonEntity work. This could break some plugins (not in a big way, but changes will be needed).
|
||||
@@ -57,6 +188,13 @@
|
||||
- Made PokemonProperties.parse more interoperable with Java.
|
||||
- Added the ``HeldItemEvent``, this comes with 2 implementation ``HeldItemEvent.Pre`` and ``HeldItemEvent.Post``.
|
||||
- API to support dynamic lighting in any mod that implements this feature has been added to all Species & Forms, see LightingData class for details.
|
||||
- Added a Mixin for the BrewingStandScreenHandler to fix the incorrect handling of quickMove in Fabric.
|
||||
- Corrections to the ability implementation have been made that make ``Ability.forced`` function as intended and never reroll an ability for a Pokémon, please check your implementations to ensure the corrected behavior is intended for your use case.
|
||||
- ``Pokemon.ability`` no longer has a public setter, please migrate to using ``Pokemon#updateAbility``, this handles the ability coordinate storage for you when necessary.
|
||||
- ``Ability.forced``, ``Ability.index`` and ``Ability.priority`` have all had their setters internalized, there is no longer any need to manually adjust these migrate to the method mentioned above to handle that process for you.
|
||||
- ``AbilityChanger`` has been added to API alongside some implementations, this is subject to change as the ability capsule and patch currently only expect the traditional behaviour in the Pokémon games of 1 to 2 regular abilities and 1 hidden.
|
||||
- ``Pokemon#rollAbility`` has been added, this rerolls a legal ability for the Pokémon.
|
||||
- `docs/cobblemon-tags` tags and spawn-presets can now be auto-generated from the current tags in the cobblemon mod with the `generateSpawnPresetList.py` and `generateTagList.py` scripts.
|
||||
|
||||
### Datapack & Resourcepack Creators
|
||||
- The maximum amount of fossils that can fit in the Fossil Analyzer can be adjusted in the config.
|
||||
@@ -91,6 +229,8 @@
|
||||
}
|
||||
```
|
||||
- Following up on this change ``light_source`` was removed as a possible shoulder effect due to becoming unnecessary and never having had a default implementation.
|
||||
- Added the item tag ``cobblemon:ability_changers``, contains the ``cobblemon:ability_capsule`` & ``cobblemon:ability_patch`` by default.
|
||||
- Added the item tag ``cobblemon:held/is_friendship_booster``, allows items to give the Soothe Bell effect of a boost of 1.5x Friendship gained, contains ``cobblemon:soothe_bell`` by default.
|
||||
|
||||
## [1.4.1 (December 23rd, 2023)](#1-4-1)
|
||||
|
||||
@@ -1026,4 +1166,4 @@ Thank you so much to all of our community translators that bring the mod to the
|
||||
- Added species, ability, and move translations for `ko_ko`, `jp_jp`, `fr_fr`, `es_es`, `it_it`, and `zh_cn`.
|
||||
|
||||
## [1.0.0 (November 12th, 2022)](#1-0-0)
|
||||
- Initial release.
|
||||
- Initial release.
|
||||
@@ -15,4 +15,7 @@ dependencies {
|
||||
implementation(libs.shadow)
|
||||
implementation(libs.loom)
|
||||
implementation(libs.architecturyPlugin)
|
||||
|
||||
implementation(libs.blossom)
|
||||
implementation(libs.ideaExt)
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
import extensions.VersionType
|
||||
import extensions.writeVersion
|
||||
|
||||
plugins {
|
||||
java
|
||||
`java-library`
|
||||
@@ -31,7 +34,7 @@ publishing {
|
||||
|
||||
groupId = "com.cobblemon"
|
||||
artifactId = project.findProperty("maven.artifactId")?.toString() ?: project.name
|
||||
version = rootProject.version.toString()
|
||||
version = project.writeVersion(VersionType.PUBLISHING)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package extensions
|
||||
|
||||
import org.gradle.api.Project
|
||||
|
||||
fun Project.version(): String {
|
||||
return rootProject.property("mod_version").toString()
|
||||
}
|
||||
|
||||
fun Project.isSnapshot(): Boolean {
|
||||
return rootProject.property("snapshot") == "true"
|
||||
}
|
||||
|
||||
fun Project.writeVersion(type: VersionType = VersionType.FULL): String {
|
||||
val version = "${rootProject.property("mod_version")}+${rootProject.property("mc_version")}"
|
||||
return when (type) {
|
||||
VersionType.PUBLISHING -> if(this.isSnapshot()) "$version-SNAPSHOT" else version
|
||||
VersionType.FULL -> if(this.isSnapshot()) rootProject.version.toString() else version
|
||||
}
|
||||
}
|
||||
|
||||
enum class VersionType {
|
||||
PUBLISHING,
|
||||
FULL
|
||||
}
|
||||
+2
-2
@@ -9,5 +9,5 @@ version = "${project.property("mod_version")}+${project.property("mc_version")}"
|
||||
|
||||
val isSnapshot = project.property("snapshot")?.equals("true") ?: false
|
||||
if (isSnapshot) {
|
||||
version = "$version-SNAPSHOT-${versioning.info.branch}-${versioning.info.build}"
|
||||
}
|
||||
version = "$version-${versioning.info.branch}-${versioning.info.build}"
|
||||
}
|
||||
|
||||
+42
-2
@@ -1,3 +1,9 @@
|
||||
import extensions.isSnapshot
|
||||
import extensions.version
|
||||
import java.time.OffsetDateTime
|
||||
import java.time.ZoneOffset
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
/*
|
||||
*
|
||||
* * Copyright (C) 2023 Cobblemon Contributors
|
||||
@@ -11,6 +17,10 @@
|
||||
plugins {
|
||||
id("cobblemon.base-conventions")
|
||||
id("cobblemon.publish-conventions")
|
||||
|
||||
id("net.kyori.blossom")
|
||||
id("org.jetbrains.gradle.plugin.idea-ext")
|
||||
id ("net.nemerosa.versioning") version "2.8.2"
|
||||
}
|
||||
|
||||
architectury {
|
||||
@@ -44,8 +54,7 @@ dependencies {
|
||||
modCompileOnly(libs.mongoDriverCore)
|
||||
modCompileOnly(libs.mongoDriverSync)
|
||||
|
||||
testRuntimeOnly(libs.junitEngine)
|
||||
testImplementation(libs.junitApi)
|
||||
testImplementation(libs.fabricJunit)
|
||||
testImplementation(libs.junitParams)
|
||||
testImplementation(libs.mockito)
|
||||
testImplementation(libs.mockk)
|
||||
@@ -59,3 +68,34 @@ tasks.withType<Test> {
|
||||
setExceptionFormat("full")
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
blossom {
|
||||
kotlinSources {
|
||||
fun generateLicenseHeader() : String {
|
||||
val builder = StringBuilder()
|
||||
builder.append("/*\n")
|
||||
rootProject.file("HEADER").forEachLine {
|
||||
if(it.isEmpty()) {
|
||||
builder.append(" *").append("\n")
|
||||
} else {
|
||||
builder.append(" * ").append(it).append("\n")
|
||||
}
|
||||
}
|
||||
|
||||
return builder.append(" */").append("\n").toString()
|
||||
}
|
||||
|
||||
property("license", generateLicenseHeader())
|
||||
property("modid", "cobblemon")
|
||||
property("version", project.version())
|
||||
property("isSnapshot", if(rootProject.isSnapshot()) "true" else "false")
|
||||
property("gitCommit", versioning.info.commit)
|
||||
property("branch", versioning.info.branch)
|
||||
System.getProperty("buildNumber")?.let { property("buildNumber", it) }
|
||||
property("timestamp", OffsetDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ofPattern("MM/dd/yyyy hh:mm:ss")) + " UTC")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBuildDetails;
|
||||
import net.minecraft.util.crash.CrashReport;
|
||||
import net.minecraft.util.crash.CrashReportSection;
|
||||
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.CallbackInfo;
|
||||
|
||||
@Mixin(CrashReport.class)
|
||||
public final class CrashReportMixin {
|
||||
|
||||
@Inject(method = "addStackTrace", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/SystemDetails;writeTo(Ljava/lang/StringBuilder;)V"))
|
||||
public void cobblemon$printCobblemonDetails(StringBuilder builder, CallbackInfo callback) {
|
||||
CrashReportSection cobblemon = new CrashReportSection("Cobblemon");
|
||||
cobblemon.add("Version", CobblemonBuildDetails.VERSION);
|
||||
cobblemon.add("Is Snapshot", CobblemonBuildDetails.SNAPSHOT);
|
||||
cobblemon.add("Git Commit", CobblemonBuildDetails.INSTANCE.smallCommitHash() + " (" + "https://gitlab.com/cable-mc/cobblemon/-/commit/" + CobblemonBuildDetails.GIT_COMMIT + ")");
|
||||
cobblemon.add("Branch", CobblemonBuildDetails.BRANCH);
|
||||
cobblemon.add("Timestamp", CobblemonBuildDetails.TIMESTAMP);
|
||||
|
||||
cobblemon.addStackTrace(builder);
|
||||
builder.append("\n\n");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonItems;
|
||||
import net.minecraft.entity.mob.PiglinBrain;
|
||||
import net.minecraft.item.ItemStack;
|
||||
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(PiglinBrain.class)
|
||||
public class PiglinBarterMixin {
|
||||
|
||||
@Inject(method = "acceptsForBarter", at = @At(value = "RETURN"), cancellable = true)
|
||||
private static void cobblemon$acceptsForBarter(ItemStack stack, CallbackInfoReturnable<Boolean> ci) {
|
||||
if(!ci.getReturnValue()) {
|
||||
//TODO: Make a tag?
|
||||
if(stack.isOf(CobblemonItems.RELIC_COIN_POUCH))
|
||||
ci.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonItems;
|
||||
import net.minecraft.entity.EquipmentSlot;
|
||||
import net.minecraft.entity.mob.PiglinEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
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.CallbackInfo;
|
||||
|
||||
@Mixin(PiglinEntity.class)
|
||||
public abstract class PiglinEntityMixin {
|
||||
@Inject(method = "equipToOffHand", at = @At(value = "HEAD"), cancellable = true)
|
||||
public void cobblemon$isValidBarteringItem(ItemStack stack, CallbackInfo ci) {
|
||||
PiglinEntity entity = (PiglinEntity)(Object) this;
|
||||
if (stack.isOf(CobblemonItems.RELIC_COIN_POUCH)) {
|
||||
entity.equipStack(EquipmentSlot.OFFHAND, stack);
|
||||
entity.updateDropChances(EquipmentSlot.OFFHAND);
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{{ license }}
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
object CobblemonBuildDetails {
|
||||
|
||||
const val MOD_ID = "{{ modid }}"
|
||||
const val VERSION = "{{ version }}"
|
||||
const val SNAPSHOT = {{ isSnapshot }}
|
||||
|
||||
const val GIT_COMMIT = "{{ gitCommit | default("Not Specified") }}"
|
||||
const val BRANCH = "{{ branch | default("Not Specified") }}"
|
||||
const val TIMESTAMP = "{{ timestamp }}"
|
||||
|
||||
fun smallCommitHash(): String {
|
||||
return this.GIT_COMMIT.substring(0, 7)
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBuildDetails.smallCommitHash
|
||||
import com.cobblemon.mod.common.advancement.CobblemonCriteria
|
||||
import com.cobblemon.mod.common.advancement.criterion.EvolvePokemonContext
|
||||
import com.cobblemon.mod.common.api.Priority
|
||||
@@ -16,6 +17,7 @@ import com.cobblemon.mod.common.api.data.DataProvider
|
||||
import com.cobblemon.mod.common.api.drop.CommandDropEntry
|
||||
import com.cobblemon.mod.common.api.drop.DropEntry
|
||||
import com.cobblemon.mod.common.api.drop.ItemDropEntry
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents.BATTLE_VICTORY
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents.DATA_SYNCHRONIZED
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents.EVOLUTION_COMPLETE
|
||||
@@ -36,6 +38,7 @@ import com.cobblemon.mod.common.api.pokemon.experience.ExperienceGroups
|
||||
import com.cobblemon.mod.common.api.pokemon.experience.StandardExperienceCalculator
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.ChoiceSpeciesFeatureProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.FlagSpeciesFeatureProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.IntSpeciesFeatureProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
|
||||
import com.cobblemon.mod.common.api.pokemon.helditem.HeldItemProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.EvCalculator
|
||||
@@ -46,13 +49,8 @@ import com.cobblemon.mod.common.api.scheduling.ServerRealTimeTaskTracker
|
||||
import com.cobblemon.mod.common.api.scheduling.ServerTaskTracker
|
||||
import com.cobblemon.mod.common.api.spawning.BestSpawner
|
||||
import com.cobblemon.mod.common.api.spawning.CobblemonSpawningProspector
|
||||
import com.cobblemon.mod.common.api.spawning.WorldSlice
|
||||
import com.cobblemon.mod.common.api.spawning.context.AreaContextResolver
|
||||
import com.cobblemon.mod.common.api.spawning.context.AreaSpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.context.calculators.AreaSpawningContextCalculator
|
||||
import com.cobblemon.mod.common.api.spawning.context.calculators.AreaSpawningInput
|
||||
import com.cobblemon.mod.common.api.spawning.prospecting.SpawningProspector
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
|
||||
import com.cobblemon.mod.common.api.starter.StarterHandler
|
||||
import com.cobblemon.mod.common.api.storage.PokemonStoreManager
|
||||
import com.cobblemon.mod.common.api.storage.adapter.conversions.ReforgedConversion
|
||||
@@ -68,6 +66,7 @@ import com.cobblemon.mod.common.api.storage.player.PlayerDataStoreManager
|
||||
import com.cobblemon.mod.common.api.storage.player.factory.JsonPlayerDataStoreFactory
|
||||
import com.cobblemon.mod.common.api.storage.player.factory.MongoPlayerDataStoreFactory
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonEntityTypeTags
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||
import com.cobblemon.mod.common.battles.BagItems
|
||||
import com.cobblemon.mod.common.battles.BattleFormat
|
||||
import com.cobblemon.mod.common.battles.BattleRegistry
|
||||
@@ -106,7 +105,13 @@ import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
|
||||
import com.cobblemon.mod.common.sherds.CobblemonSherds
|
||||
import com.cobblemon.mod.common.starter.CobblemonStarterHandler
|
||||
import com.cobblemon.mod.common.trade.TradeManager
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.ifDedicatedServer
|
||||
import com.cobblemon.mod.common.util.isLaterVersion
|
||||
import com.cobblemon.mod.common.util.party
|
||||
import com.cobblemon.mod.common.util.removeAmountIf
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import com.cobblemon.mod.common.world.feature.CobblemonPlacedFeatures
|
||||
import com.cobblemon.mod.common.world.feature.ore.CobblemonOrePlacedFeatures
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
|
||||
@@ -114,15 +119,6 @@ import com.mongodb.ConnectionString
|
||||
import com.mongodb.MongoClientSettings
|
||||
import com.mongodb.client.MongoClient
|
||||
import com.mongodb.client.MongoClients
|
||||
import java.io.File
|
||||
import java.io.FileReader
|
||||
import java.io.FileWriter
|
||||
import java.io.PrintWriter
|
||||
import java.util.UUID
|
||||
import kotlin.properties.Delegates
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.jvm.isAccessible
|
||||
import kotlin.reflect.jvm.javaField
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.command.argument.serialize.ConstantArgumentSerializer
|
||||
import net.minecraft.entity.data.TrackedDataHandlerRegistry
|
||||
@@ -130,15 +126,25 @@ import net.minecraft.item.Items
|
||||
import net.minecraft.item.NameTagItem
|
||||
import net.minecraft.registry.RegistryKey
|
||||
import net.minecraft.util.WorldSavePath
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.world.World
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.apache.logging.log4j.Logger
|
||||
import java.io.File
|
||||
import java.io.FileReader
|
||||
import java.io.FileWriter
|
||||
import java.io.PrintWriter
|
||||
import java.util.*
|
||||
import kotlin.properties.Delegates
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.jvm.isAccessible
|
||||
import kotlin.reflect.jvm.javaField
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
object Cobblemon {
|
||||
const val MODID = "cobblemon"
|
||||
const val VERSION = "1.4.0"
|
||||
const val CONFIG_PATH = "config/$MODID/main.json"
|
||||
val LOGGER = LogManager.getLogger()
|
||||
val LOGGER: Logger = LogManager.getLogger()
|
||||
|
||||
lateinit var implementation: CobblemonImplementation
|
||||
@Deprecated("This field is now a config value", ReplaceWith("Cobblemon.config.captureCalculator"))
|
||||
@@ -168,6 +174,14 @@ object Cobblemon {
|
||||
|
||||
fun preInitialize(implementation: CobblemonImplementation) {
|
||||
this.implementation = implementation
|
||||
|
||||
this.LOGGER.info("Launching Cobblemon ${CobblemonBuildDetails.VERSION}${if(CobblemonBuildDetails.SNAPSHOT) "-SNAPSHOT" else ""} ")
|
||||
if(CobblemonBuildDetails.SNAPSHOT) {
|
||||
this.LOGGER.info(" - Git Commit: ${smallCommitHash()} (https://gitlab.com/cable-mc/cobblemon/-/commit/${CobblemonBuildDetails.GIT_COMMIT})")
|
||||
this.LOGGER.info(" - Branch: ${CobblemonBuildDetails.BRANCH}")
|
||||
this.LOGGER.info(" - Timestamp: ${CobblemonBuildDetails.TIMESTAMP}")
|
||||
}
|
||||
|
||||
implementation.registerPermissionValidator()
|
||||
implementation.registerSoundEvents()
|
||||
implementation.registerBlocks()
|
||||
@@ -230,6 +244,9 @@ object Cobblemon {
|
||||
}
|
||||
}
|
||||
|
||||
// Register the grow_tumblestone advancement
|
||||
PlatformEvents.RIGHT_CLICK_BLOCK.subscribe { AdvancementHandler.onTumbleStonePlaced(it) }
|
||||
|
||||
PlatformEvents.CHANGE_DIMENSION.subscribe {
|
||||
it.player.party().forEach { pokemon -> pokemon.entity?.recallWithAnimation() }
|
||||
}
|
||||
@@ -239,6 +256,16 @@ object Cobblemon {
|
||||
TrackedDataHandlerRegistry.register(PoseTypeDataSerializer)
|
||||
TrackedDataHandlerRegistry.register(IdentifierDataSerializer)
|
||||
|
||||
// Lowest priority because this applies after luxury ball bonus as of gen 4
|
||||
CobblemonEvents.FRIENDSHIP_UPDATED.subscribe(Priority.LOWEST) { event ->
|
||||
var increment = (event.newFriendship - event.pokemon.friendship).toFloat()
|
||||
// Our Luxury ball spec is diff from official, but we will still assume these stack
|
||||
if (event.pokemon.heldItemNoCopy().isIn(CobblemonItemTags.IS_FRIENDSHIP_BOOSTER)) {
|
||||
increment += increment * 0.5F
|
||||
}
|
||||
event.newFriendship = event.pokemon.friendship + increment.roundToInt()
|
||||
}
|
||||
|
||||
HeldItemProvider.register(CobblemonHeldItemManager, Priority.LOWEST)
|
||||
}
|
||||
|
||||
@@ -253,6 +280,7 @@ object Cobblemon {
|
||||
|
||||
SpeciesFeatures.types["choice"] = ChoiceSpeciesFeatureProvider::class.java
|
||||
SpeciesFeatures.types["flag"] = FlagSpeciesFeatureProvider::class.java
|
||||
SpeciesFeatures.types["integer"] = IntSpeciesFeatureProvider::class.java
|
||||
|
||||
SpeciesFeatures.register(
|
||||
DataKeys.CAN_BE_MILKED,
|
||||
|
||||
@@ -17,6 +17,7 @@ import com.cobblemon.mod.common.block.entity.FossilMultiblockEntity
|
||||
import com.cobblemon.mod.common.block.entity.RestorationTankBlockEntity
|
||||
import com.cobblemon.mod.common.block.multiblock.FossilMultiblockBuilder
|
||||
import com.cobblemon.mod.common.block.entity.*
|
||||
import com.cobblemon.mod.common.block.entity.DisplayCaseBlockEntity
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
import net.minecraft.block.entity.BlockEntityType
|
||||
import net.minecraft.registry.Registries
|
||||
@@ -45,6 +46,18 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
|
||||
@JvmField
|
||||
val HANGING_SIGN: BlockEntityType<CobblemonHangingSignBlockEntity> = this.create("hanging_sign", BlockEntityType.Builder.create(::CobblemonHangingSignBlockEntity, CobblemonBlocks.APRICORN_HANGING_SIGN, CobblemonBlocks.APRICORN_WALL_HANGING_SIGN).build(null))
|
||||
|
||||
@JvmField
|
||||
val GILDED_CHEST: BlockEntityType<GildedChestBlockEntity> = this.create("chest", BlockEntityType.Builder.create(::GildedChestBlockEntity,
|
||||
CobblemonBlocks.GILDED_CHEST,
|
||||
CobblemonBlocks.BLUE_GILDED_CHEST,
|
||||
CobblemonBlocks.YELLOW_GILDED_CHEST,
|
||||
CobblemonBlocks.PINK_GILDED_CHEST,
|
||||
CobblemonBlocks.BLACK_GILDED_CHEST,
|
||||
CobblemonBlocks.WHITE_GILDED_CHEST,
|
||||
CobblemonBlocks.GREEN_GILDED_CHEST,
|
||||
CobblemonBlocks.GIMMIGHOUL_CHEST
|
||||
).build(null))
|
||||
|
||||
@JvmField
|
||||
val FOSSIL_MULTIBLOCK: BlockEntityType<FossilMultiblockEntity> = this.create("fossil_multiblock",
|
||||
BlockEntityType.Builder.create({ pos, state -> FossilMultiblockEntity(pos, state, FossilMultiblockBuilder(pos)) },
|
||||
@@ -67,8 +80,7 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val DYNITE_ORE: BlockEntityType<DyniteOreBlockEntity> = this.create("dynite_ore",
|
||||
BlockEntityType.Builder.create(::DyniteOreBlockEntity, CobblemonBlocks.DYNITE_ORE)
|
||||
.build(null)
|
||||
val DISPLAY_CASE: BlockEntityType<DisplayCaseBlockEntity> = this.create("display_case",
|
||||
BlockEntityType.Builder.create(::DisplayCaseBlockEntity, CobblemonBlocks.DISPLAY_CASE).build(null)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.cobblemon.mod.common.mixin.invoker.*
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.block.BerryBlock
|
||||
import com.cobblemon.mod.common.block.chest.GildedChestBlock
|
||||
import com.cobblemon.mod.common.block.sign.CobblemonHangingSignBlock
|
||||
import com.cobblemon.mod.common.block.sign.CobblemonSignBlock
|
||||
import com.cobblemon.mod.common.block.sign.CobblemonWallHangingSignBlock
|
||||
@@ -71,6 +72,8 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
@JvmField
|
||||
val SUN_STONE_ORE = evolutionStoneOre("sun_stone_ore")
|
||||
@JvmField
|
||||
val TERRACOTTA_SUN_STONE_ORE = evolutionStoneOre("terracotta_sun_stone_ore")
|
||||
@JvmField
|
||||
val THUNDER_STONE_ORE = evolutionStoneOre("thunder_stone_ore")
|
||||
@JvmField
|
||||
val WATER_STONE_ORE = evolutionStoneOre("water_stone_ore")
|
||||
@@ -96,15 +99,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
@JvmField
|
||||
val DEEPSLATE_WATER_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_water_stone_ore")
|
||||
|
||||
@JvmField
|
||||
val DYNITE_ORE = this.create("dynite_ore", DyniteOreBlock(
|
||||
AbstractBlock.Settings.create()
|
||||
.mapColor(MapColor.BRIGHT_RED)
|
||||
.strength(4.5f, 3f)
|
||||
.requiresTool()
|
||||
.sounds(BlockSoundGroup.METAL)
|
||||
))
|
||||
|
||||
// Apricorns
|
||||
@JvmField
|
||||
val APRICORN_LOG = log("apricorn_log", arg2 = MapColor.BROWN)
|
||||
@@ -160,11 +154,11 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
val YELLOW_APRICORN_SAPLING = this.create("yellow_apricorn_sapling", ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.YELLOW))
|
||||
|
||||
@JvmField
|
||||
val MEDICINAL_LEEK = this.create("medicinal_leek", MedicinalLeekBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DULL_RED).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
|
||||
val MEDICINAL_LEEK = this.create("medicinal_leek", MedicinalLeekBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DULL_RED).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MEDICINAL_LEEK_SOUNDS)))
|
||||
@JvmField
|
||||
val ENERGY_ROOT = this.create("energy_root", EnergyRootBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DIRT_BROWN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.ROOTS)))
|
||||
val ENERGY_ROOT = this.create("energy_root", EnergyRootBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DIRT_BROWN).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.ENERGY_ROOT_SOUNDS)))
|
||||
@JvmField
|
||||
val BIG_ROOT = this.create("big_root", BigRootBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DARK_GREEN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.ROOTS)))
|
||||
val BIG_ROOT = this.create("big_root", BigRootBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DARK_GREEN).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.BIG_ROOT_SOUNDS)))
|
||||
@JvmField
|
||||
val REVIVAL_HERB = this.create("revival_herb", RevivalHerbBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).mapColor(MapColor.DARK_GREEN).burnable().noCollision().breakInstantly().sounds(BlockSoundGroup.CROP)))
|
||||
|
||||
@@ -200,6 +194,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
.mapColor(MapColor.TERRACOTTA_ORANGE)
|
||||
.strength(1.0F)
|
||||
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
|
||||
.requiresTool()
|
||||
.instrument(Instrument.BASEDRUM)
|
||||
))
|
||||
@JvmField
|
||||
@@ -207,6 +202,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
.mapColor(MapColor.LIGHT_BLUE)
|
||||
.strength(1.0F)
|
||||
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
|
||||
.requiresTool()
|
||||
.instrument(Instrument.BASEDRUM)
|
||||
))
|
||||
@JvmField
|
||||
@@ -214,6 +210,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
.mapColor(MapColor.TERRACOTTA_BLACK)
|
||||
.strength(1.0F)
|
||||
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
|
||||
.requiresTool()
|
||||
.instrument(Instrument.BASEDRUM)
|
||||
))
|
||||
|
||||
@@ -232,6 +229,99 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
@JvmField
|
||||
val YELLOW_APRICORN = apricornBlock("yellow_apricorn", Apricorn.YELLOW)
|
||||
|
||||
@JvmField
|
||||
val RELIC_COIN_POUCH = create(
|
||||
"relic_coin_pouch",
|
||||
CoinPouchBlock(
|
||||
AbstractBlock.Settings.create()
|
||||
.sounds(CobblemonSounds.COIN_POUCH_SOUNDS)
|
||||
.pistonBehavior(PistonBehavior.DESTROY)
|
||||
.strength(0.4f)
|
||||
.nonOpaque(), true
|
||||
)
|
||||
)
|
||||
@JvmField
|
||||
val RELIC_COIN_SACK = create(
|
||||
"relic_coin_sack",
|
||||
CoinPouchBlock(
|
||||
AbstractBlock.Settings.create()
|
||||
.sounds(CobblemonSounds.COIN_POUCH_SOUNDS)
|
||||
.pistonBehavior(PistonBehavior.DESTROY)
|
||||
.strength(0.4f), false
|
||||
))
|
||||
|
||||
@JvmField
|
||||
val GILDED_CHEST = create(
|
||||
"gilded_chest",
|
||||
GildedChestBlock(
|
||||
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
|
||||
GildedChestBlock.Type.RED
|
||||
)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val BLUE_GILDED_CHEST = create(
|
||||
"blue_gilded_chest",
|
||||
GildedChestBlock(
|
||||
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
|
||||
GildedChestBlock.Type.BLUE
|
||||
)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val BLACK_GILDED_CHEST = create(
|
||||
"black_gilded_chest",
|
||||
GildedChestBlock(
|
||||
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
|
||||
GildedChestBlock.Type.BLACK
|
||||
)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val YELLOW_GILDED_CHEST = create(
|
||||
"yellow_gilded_chest",
|
||||
GildedChestBlock(
|
||||
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
|
||||
GildedChestBlock.Type.YELLOW
|
||||
)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val WHITE_GILDED_CHEST = create(
|
||||
"white_gilded_chest",
|
||||
GildedChestBlock(
|
||||
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
|
||||
GildedChestBlock.Type.WHITE
|
||||
)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val GREEN_GILDED_CHEST = create(
|
||||
"green_gilded_chest",
|
||||
GildedChestBlock(
|
||||
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
|
||||
GildedChestBlock.Type.GREEN
|
||||
)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val PINK_GILDED_CHEST = create(
|
||||
"pink_gilded_chest",
|
||||
GildedChestBlock(
|
||||
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
|
||||
GildedChestBlock.Type.PINK
|
||||
)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val GIMMIGHOUL_CHEST = create(
|
||||
"gimmighoul_chest",
|
||||
GildedChestBlock(
|
||||
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
|
||||
GildedChestBlock.Type.FAKE
|
||||
)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val MONITOR = create(
|
||||
"monitor",
|
||||
@@ -264,7 +354,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
RestorationTankBlock(
|
||||
AbstractBlock.Settings.create()
|
||||
.mapColor(MapColor.IRON_GRAY)
|
||||
.sounds(BlockSoundGroup.METAL)
|
||||
.sounds(BlockSoundGroup.GLASS)
|
||||
.pistonBehavior(PistonBehavior.BLOCK)
|
||||
.requiresTool()
|
||||
.strength(5.0F, 6.0F)
|
||||
@@ -299,17 +389,29 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val RED_MINT = create("red_mint", MintBlock(MintType.RED, AbstractBlock.Settings.create().mapColor(MapColor.RED).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
|
||||
val DISPLAY_CASE = create(
|
||||
"display_case",
|
||||
DisplayCaseBlock(
|
||||
AbstractBlock.Settings.create()
|
||||
.sounds(CobblemonSounds.DISPLAY_CASE_SOUNDS)
|
||||
.nonOpaque()
|
||||
.pistonBehavior(PistonBehavior.BLOCK)
|
||||
.mapColor(MapColor.STONE_GRAY)
|
||||
.strength(0.3f)
|
||||
)
|
||||
)
|
||||
|
||||
val RED_MINT = create("red_mint", MintBlock(MintType.RED, AbstractBlock.Settings.create().mapColor(MapColor.RED).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
|
||||
@JvmField
|
||||
val BLUE_MINT = create("blue_mint", MintBlock(MintType.BLUE, AbstractBlock.Settings.create().mapColor(MapColor.BLUE).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
|
||||
val BLUE_MINT = create("blue_mint", MintBlock(MintType.BLUE, AbstractBlock.Settings.create().mapColor(MapColor.BLUE).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
|
||||
@JvmField
|
||||
val CYAN_MINT = create("cyan_mint", MintBlock(MintType.CYAN, AbstractBlock.Settings.create().mapColor(MapColor.CYAN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
|
||||
val CYAN_MINT = create("cyan_mint", MintBlock(MintType.CYAN, AbstractBlock.Settings.create().mapColor(MapColor.CYAN).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
|
||||
@JvmField
|
||||
val PINK_MINT = create("pink_mint", MintBlock(MintType.PINK, AbstractBlock.Settings.create().mapColor(MapColor.PINK).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
|
||||
val PINK_MINT = create("pink_mint", MintBlock(MintType.PINK, AbstractBlock.Settings.create().mapColor(MapColor.PINK).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
|
||||
@JvmField
|
||||
val GREEN_MINT = create("green_mint", MintBlock(MintType.GREEN, AbstractBlock.Settings.create().mapColor(MapColor.GREEN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
|
||||
val GREEN_MINT = create("green_mint", MintBlock(MintType.GREEN, AbstractBlock.Settings.create().mapColor(MapColor.GREEN).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
|
||||
@JvmField
|
||||
val WHITE_MINT = create("white_mint", MintBlock(MintType.WHITE, AbstractBlock.Settings.create().mapColor(MapColor.WHITE).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
|
||||
val WHITE_MINT = create("white_mint", MintBlock(MintType.WHITE, AbstractBlock.Settings.create().mapColor(MapColor.WHITE).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
|
||||
|
||||
@JvmField
|
||||
val PASTURE = create(
|
||||
@@ -450,7 +552,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
|
||||
private fun berryBlock(name: String): BerryBlock {
|
||||
val identifier = cobblemonResource("${name}_berry")
|
||||
val block = this.create(identifier.path, BerryBlock(identifier, AbstractBlock.Settings.copy(Blocks.WHEAT).dynamicBounds().sounds(BlockSoundGroup.CROP).strength(0.2F)))
|
||||
val block = this.create(identifier.path, BerryBlock(identifier, AbstractBlock.Settings.copy(Blocks.WHEAT).dynamicBounds().sounds(CobblemonSounds.BERRY_BUSH_SOUNDS).strength(0.2F)))
|
||||
this.berries[identifier] = block
|
||||
return block
|
||||
}
|
||||
|
||||
@@ -48,5 +48,9 @@ object CobblemonCommands {
|
||||
PokemonRestartCommand.register(dispatcher)
|
||||
BedrockParticleCommand.register(dispatcher)
|
||||
OpenDialogueCommand.register(dispatcher)
|
||||
|
||||
// Possibly lock down registration if and only if under dev environment or running in an environment
|
||||
// with a certain system environment variable set
|
||||
CobblemonInfoCommand.register(dispatcher)
|
||||
}
|
||||
}
|
||||
@@ -11,9 +11,7 @@ package com.cobblemon.mod.common
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.entity.boat.CobblemonBoatEntity
|
||||
import com.cobblemon.mod.common.entity.boat.CobblemonChestBoatEntity
|
||||
import com.cobblemon.mod.common.entity.fallingstar.FallingStarEntity
|
||||
import com.cobblemon.mod.common.entity.generic.GenericBedrockEntity
|
||||
import com.cobblemon.mod.common.entity.fishing.PokeRodFishingBobberEntity
|
||||
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
@@ -77,24 +75,6 @@ object CobblemonEntities : PlatformRegistry<Registry<EntityType<*>>, RegistryKey
|
||||
.build(GENERIC_BEDROCK_ENTITY_KEY.toString())
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val FALLING_STAR_ENTITY_KEY = cobblemonResource("falling_star")
|
||||
@JvmField
|
||||
val FALLING_STAR_ENTITY: EntityType<FallingStarEntity> = this.create(
|
||||
FALLING_STAR_ENTITY_KEY.path,
|
||||
EntityType.Builder.create({ _, world -> FallingStarEntity(world) }, SpawnGroup.MISC)
|
||||
.build(FALLING_STAR_ENTITY_KEY.toString())
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val POKE_BOBBER_KEY = cobblemonResource("poke_bobber")
|
||||
@JvmField
|
||||
val POKE_BOBBER: EntityType<PokeRodFishingBobberEntity> = this.create(
|
||||
POKE_BOBBER_KEY.path,
|
||||
EntityType.Builder.create(::PokeRodFishingBobberEntity, SpawnGroup.MISC).setDimensions(0.5F, 0.5F).maxTrackingRange(10)
|
||||
.build(POKE_BOBBER_KEY.toString())
|
||||
)
|
||||
|
||||
fun registerAttributes(consumer: (EntityType<out LivingEntity>, DefaultAttributeContainer.Builder) -> Unit) {
|
||||
consumer(POKEMON, PokemonEntity.createAttributes())
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.cobblemon.mod.common.api.item.ability.AbilityChanger
|
||||
import com.cobblemon.mod.common.api.mulch.MulchVariant
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.api.pokemon.Natures
|
||||
@@ -30,6 +31,7 @@ import com.cobblemon.mod.common.item.berry.StatusCuringBerryItem
|
||||
import com.cobblemon.mod.common.item.berry.VolatileCuringBerryItem
|
||||
import com.cobblemon.mod.common.item.interactive.*
|
||||
import com.cobblemon.mod.common.item.interactive.PotionItem
|
||||
import com.cobblemon.mod.common.item.interactive.ability.AbilityChangeItem
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
import com.cobblemon.mod.common.pokeball.PokeBall
|
||||
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
|
||||
@@ -39,14 +41,6 @@ import net.minecraft.entity.LivingEntity
|
||||
import net.minecraft.entity.effect.StatusEffectInstance
|
||||
import net.minecraft.entity.effect.StatusEffects
|
||||
import net.minecraft.item.*
|
||||
import net.minecraft.item.BlockItem
|
||||
import net.minecraft.item.FoodComponent
|
||||
import net.minecraft.item.HangingSignItem
|
||||
import net.minecraft.item.Item
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.item.SignItem
|
||||
import net.minecraft.item.SmithingTemplateItem
|
||||
import net.minecraft.item.StewItem
|
||||
import net.minecraft.registry.Registries
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.registry.RegistryKey
|
||||
@@ -231,6 +225,22 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
val APRICORN_SIGN = this.create("apricorn_sign", SignItem(Item.Settings().maxCount(16), CobblemonBlocks.APRICORN_SIGN, CobblemonBlocks.APRICORN_WALL_SIGN))
|
||||
@JvmField
|
||||
val APRICORN_HANGING_SIGN = this.create("apricorn_hanging_sign", HangingSignItem(CobblemonBlocks.APRICORN_HANGING_SIGN, CobblemonBlocks.APRICORN_WALL_HANGING_SIGN, Item.Settings().maxCount(16)))
|
||||
@JvmField
|
||||
val GILDED_CHEST = this.create("gilded_chest", BlockItem(CobblemonBlocks.GILDED_CHEST, Item.Settings()))
|
||||
@JvmField
|
||||
val BLUE_GILDED_CHEST = this.create("blue_gilded_chest", BlockItem(CobblemonBlocks.BLUE_GILDED_CHEST, Item.Settings()))
|
||||
@JvmField
|
||||
val YELLOW_GILDED_CHEST = this.create("yellow_gilded_chest", BlockItem(CobblemonBlocks.YELLOW_GILDED_CHEST, Item.Settings()))
|
||||
@JvmField
|
||||
val PINK_GILDED_CHEST = this.create("pink_gilded_chest", BlockItem(CobblemonBlocks.PINK_GILDED_CHEST, Item.Settings()))
|
||||
@JvmField
|
||||
val BLACK_GILDED_CHEST = this.create("black_gilded_chest", BlockItem(CobblemonBlocks.BLACK_GILDED_CHEST, Item.Settings()))
|
||||
@JvmField
|
||||
val WHITE_GILDED_CHEST = this.create("white_gilded_chest", BlockItem(CobblemonBlocks.WHITE_GILDED_CHEST, Item.Settings()))
|
||||
@JvmField
|
||||
val GREEN_GILDED_CHEST = this.create("green_gilded_chest", BlockItem(CobblemonBlocks.GREEN_GILDED_CHEST, Item.Settings()))
|
||||
@JvmField
|
||||
val GIMMIGHOUL_CHEST = this.create("gimmighoul_chest", BlockItem(CobblemonBlocks.GIMMIGHOUL_CHEST, Item.Settings()))
|
||||
|
||||
@JvmField
|
||||
val RESTORATION_TANK = blockItem("restoration_tank", CobblemonBlocks.RESTORATION_TANK)
|
||||
@@ -244,6 +254,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
val PC = blockItem("pc", CobblemonBlocks.PC)
|
||||
@JvmField
|
||||
val PASTURE = blockItem("pasture", CobblemonBlocks.PASTURE)
|
||||
@JvmField
|
||||
val DISPLAY_CASE = blockItem("display_case", CobblemonBlocks.DISPLAY_CASE)
|
||||
|
||||
// Evolution items
|
||||
@JvmField val LINK_CABLE = create("link_cable", LinkCableItem())
|
||||
@@ -271,6 +283,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
@JvmField val RIBBON_SWEET = noSettingsItem("ribbon_sweet")
|
||||
@JvmField val CHIPPED_POT = noSettingsItem("chipped_pot")
|
||||
@JvmField val CRACKED_POT = noSettingsItem("cracked_pot")
|
||||
@JvmField val MASTERPIECE_TEACUP = noSettingsItem("masterpiece_teacup")
|
||||
@JvmField val UNREMARKABLE_TEACUP = noSettingsItem("unremarkable_teacup")
|
||||
@JvmField val SWEET_APPLE = noSettingsItem("sweet_apple")
|
||||
@JvmField val TART_APPLE = noSettingsItem("tart_apple")
|
||||
@JvmField val GALARICA_CUFF = noSettingsItem("galarica_cuff")
|
||||
@@ -382,7 +396,19 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
@JvmField
|
||||
val ZINC = create("zinc", VitaminItem(Stats.SPECIAL_DEFENCE))
|
||||
@JvmField
|
||||
val MEDICINAL_LEEK = create("medicinal_leek", MedicinalLeekItem(CobblemonBlocks.MEDICINAL_LEEK, Item.Settings().food(FoodComponent.Builder().snack().hunger(1).saturationModifier(0.2f).build())))
|
||||
val GENIUS_FEATHER = create("genius_feather", FeatherItem(Stats.SPECIAL_ATTACK))
|
||||
@JvmField
|
||||
val SWIFT_FEATHER = create("swift_feather", FeatherItem(Stats.SPEED))
|
||||
@JvmField
|
||||
val HEALTH_FEATHER = create("health_feather", FeatherItem(Stats.HP))
|
||||
@JvmField
|
||||
val RESIST_FEATHER = create("resist_feather", FeatherItem(Stats.DEFENCE))
|
||||
@JvmField
|
||||
val MUSCLE_FEATHER = create("muscle_feather", FeatherItem(Stats.ATTACK))
|
||||
@JvmField
|
||||
val CLEVER_FEATHER = create("clever_feather", FeatherItem(Stats.SPECIAL_DEFENCE))
|
||||
@JvmField
|
||||
val MEDICINAL_LEEK = heldItem("medicinal_leek", MedicinalLeekItem(CobblemonBlocks.MEDICINAL_LEEK, Item.Settings().food(FoodComponent.Builder().snack().hunger(1).saturationModifier(0.2f).build())), "leek")
|
||||
@JvmField
|
||||
val ROASTED_LEEK = create("roasted_leek", Item(Item.Settings().food(FoodComponent.Builder().snack().hunger(3).saturationModifier(0.3f).build())))
|
||||
@JvmField
|
||||
@@ -532,6 +558,11 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
@JvmField val ELIXIR = create("elixir", ElixirItem(max = false))
|
||||
@JvmField val MAX_ELIXIR = create("max_elixir", ElixirItem(max = true))
|
||||
|
||||
@JvmField
|
||||
val ABILITY_CAPSULE = this.create("ability_capsule", AbilityChangeItem(AbilityChanger.COMMON_ABILITY))
|
||||
@JvmField
|
||||
val ABILITY_PATCH = this.create("ability_patch", AbilityChangeItem(AbilityChanger.HIDDEN_ABILITY))
|
||||
|
||||
/**
|
||||
* Evolution Ores and Stones
|
||||
*/
|
||||
@@ -552,6 +583,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
@JvmField
|
||||
val SUN_STONE_ORE = blockItem("sun_stone_ore", CobblemonBlocks.SUN_STONE_ORE)
|
||||
@JvmField
|
||||
val TERRACOTTA_SUN_STONE_ORE = blockItem("terracotta_sun_stone_ore", CobblemonBlocks.TERRACOTTA_SUN_STONE_ORE)
|
||||
@JvmField
|
||||
val THUNDER_STONE_ORE = blockItem("thunder_stone_ore", CobblemonBlocks.THUNDER_STONE_ORE)
|
||||
@JvmField
|
||||
val WATER_STONE_ORE = blockItem("water_stone_ore", CobblemonBlocks.WATER_STONE_ORE)
|
||||
@@ -580,9 +613,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
@JvmField
|
||||
val NETHER_FIRE_STONE_ORE = blockItem("nether_fire_stone_ore", CobblemonBlocks.NETHER_FIRE_STONE_ORE)
|
||||
|
||||
@JvmField
|
||||
val DYNITE_ORE = blockItem("dynite_ore", CobblemonBlocks.DYNITE_ORE)
|
||||
|
||||
@JvmField
|
||||
val DAWN_STONE = noSettingsItem("dawn_stone")
|
||||
@JvmField
|
||||
@@ -606,16 +636,28 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
|
||||
// Held Items
|
||||
@JvmField
|
||||
val ABILITY_SHIELD = heldItem("ability_shield")
|
||||
@JvmField
|
||||
val ABSORB_BULB = heldItem("absorb_bulb")
|
||||
@JvmField
|
||||
val AIR_BALLOON = heldItem("air_balloon")
|
||||
@JvmField
|
||||
val ASSAULT_VEST = heldItem("assault_vest")
|
||||
@JvmField
|
||||
val BIG_ROOT = blockItem("big_root", CobblemonBlocks.BIG_ROOT)
|
||||
@JvmField
|
||||
val BINDING_BAND = heldItem("binding_band")
|
||||
@JvmField
|
||||
val BLACK_BELT = heldItem("black_belt")
|
||||
@JvmField
|
||||
val BLACK_GLASSES = heldItem("black_glasses")
|
||||
@JvmField
|
||||
val BLACK_SLUDGE = heldItem("black_sludge")
|
||||
@JvmField
|
||||
val BLUNDER_POLICY = heldItem("blunder_policy")
|
||||
@JvmField
|
||||
val CELL_BATTERY = heldItem("cell_battery")
|
||||
@JvmField
|
||||
val CHARCOAL = heldItem("charcoal_stick", remappedName = "charcoal")
|
||||
@JvmField
|
||||
val CHOICE_BAND = heldItem("choice_band")
|
||||
@@ -626,26 +668,64 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
@JvmField
|
||||
val CLEANSE_TAG = heldItem("cleanse_tag")
|
||||
@JvmField
|
||||
val CLEAR_AMULET = heldItem("clear_amulet")
|
||||
@JvmField
|
||||
val COVERT_CLOAK = heldItem("covert_cloak")
|
||||
@JvmField
|
||||
val DESTINY_KNOT = heldItem("destiny_knot")
|
||||
@JvmField
|
||||
val DRAGON_FANG = heldItem("dragon_fang")
|
||||
@JvmField
|
||||
val EJECT_BUTTON = heldItem("eject_button")
|
||||
@JvmField
|
||||
val EJECT_PACK = heldItem("eject_pack")
|
||||
@JvmField
|
||||
val EVERSTONE = heldItem("everstone")
|
||||
@JvmField
|
||||
val EVIOLITE = heldItem("eviolite")
|
||||
@JvmField
|
||||
val EXP_SHARE = heldItem("exp_share")
|
||||
@JvmField
|
||||
val EXPERT_BELT = heldItem("expert_belt")
|
||||
@JvmField
|
||||
val FAIRY_FEATHER = heldItem("fairy_feather")
|
||||
@JvmField
|
||||
val FLAME_ORB = heldItem("flame_orb")
|
||||
@JvmField
|
||||
val FLOAT_STONE = heldItem("float_stone")
|
||||
@JvmField
|
||||
val FOCUS_BAND = heldItem("focus_band")
|
||||
@JvmField
|
||||
val FOCUS_SASH = heldItem("focus_sash")
|
||||
@JvmField
|
||||
val GRIP_CLAW = heldItem("grip_claw")
|
||||
@JvmField
|
||||
val HARD_STONE = heldItem("hard_stone")
|
||||
@JvmField
|
||||
val HEAVY_DUTY_BOOTS = heldItem("heavy_duty_boots")
|
||||
@JvmField
|
||||
val IRON_BALL = heldItem("iron_ball")
|
||||
@JvmField
|
||||
val LAGGING_TAIL = heldItem("lagging_tail")
|
||||
@JvmField
|
||||
val LEFTOVERS = heldItem("leftovers")
|
||||
@JvmField
|
||||
val LIFE_ORB = heldItem("life_orb")
|
||||
@JvmField
|
||||
val LIGHT_BALL = heldItem("light_ball")
|
||||
@JvmField
|
||||
val LIGHT_CLAY = heldItem("light_clay")
|
||||
@JvmField
|
||||
val LOADED_DICE = heldItem("loaded_dice")
|
||||
@JvmField
|
||||
val LUCKY_EGG = heldItem("lucky_egg")
|
||||
@JvmField
|
||||
val LUMINOUS_MOSS = heldItem("luminous_moss")
|
||||
@JvmField
|
||||
val MAGNET = heldItem("magnet")
|
||||
@JvmField
|
||||
val METRONOME = heldItem("metronome")
|
||||
@JvmField
|
||||
val MIRACLE_SEED = heldItem("miracle_seed")
|
||||
@JvmField
|
||||
val MUSCLE_BAND = heldItem("muscle_band")
|
||||
@@ -656,14 +736,42 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
@JvmField
|
||||
val POISON_BARB = heldItem("poison_barb")
|
||||
@JvmField
|
||||
val POWER_ANKLET = heldItem("power_anklet")
|
||||
@JvmField
|
||||
val POWER_BAND = heldItem("power_band")
|
||||
@JvmField
|
||||
val POWER_BELT = heldItem("power_belt")
|
||||
@JvmField
|
||||
val POWER_BRACER = heldItem("power_bracer")
|
||||
@JvmField
|
||||
val POWER_LENS = heldItem("power_lens")
|
||||
@JvmField
|
||||
val POWER_WEIGHT = heldItem("power_weight")
|
||||
@JvmField
|
||||
val PROTECTIVE_PADS = heldItem("protective_pads")
|
||||
@JvmField
|
||||
val PUNCHING_GLOVE = heldItem("punching_glove")
|
||||
@JvmField
|
||||
val QUICK_CLAW = heldItem("quick_claw")
|
||||
@JvmField
|
||||
val RED_CARD = heldItem("red_card")
|
||||
@JvmField
|
||||
val RING_TARGET = heldItem("ring_target")
|
||||
@JvmField
|
||||
val ROCKY_HELMET = heldItem("rocky_helmet")
|
||||
@JvmField
|
||||
val ROOM_SERVICE = heldItem("room_service")
|
||||
@JvmField
|
||||
val SAFETY_GOGGLES = heldItem("safety_goggles")
|
||||
@JvmField
|
||||
val SCOPE_LENS = heldItem("scope_lens")
|
||||
@JvmField
|
||||
val SHARP_BEAK = heldItem("sharp_beak")
|
||||
@JvmField
|
||||
val SHED_SHELL = heldItem("shed_shell")
|
||||
@JvmField
|
||||
val SHELL_BELL = heldItem("shell_bell")
|
||||
@JvmField
|
||||
val SILK_SCARF = heldItem("silk_scarf")
|
||||
@JvmField
|
||||
val SILVER_POWDER = heldItem("silver_powder")
|
||||
@@ -672,10 +780,30 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
@JvmField
|
||||
val SPELL_TAG = heldItem("spell_tag")
|
||||
@JvmField
|
||||
val SMOKE_BALL = heldItem("smoke_ball")
|
||||
@JvmField
|
||||
val SOOTHE_BELL = heldItem("soothe_bell")
|
||||
@JvmField
|
||||
val STICKY_BARB = heldItem("sticky_barb")
|
||||
@JvmField
|
||||
val TERRAIN_EXTENDER = heldItem("terrain_extender")
|
||||
@JvmField
|
||||
val THROAT_SPRAY = heldItem("throat_spray")
|
||||
@JvmField
|
||||
val TOXIC_ORB = heldItem("toxic_orb")
|
||||
@JvmField
|
||||
val TWISTED_SPOON = heldItem("twisted_spoon")
|
||||
@JvmField
|
||||
val UTILITY_UMBRELLA = heldItem("utility_umbrella")
|
||||
@JvmField
|
||||
val WEAKNESS_POLICY = heldItem("weakness_policy")
|
||||
@JvmField
|
||||
val WIDE_LENS = heldItem("wide_lens")
|
||||
@JvmField
|
||||
val WISE_GLASSES = heldItem("wise_glasses")
|
||||
@JvmField
|
||||
val ZOOM_LENS = heldItem("zoom_lens")
|
||||
@JvmField
|
||||
val MENTAL_HERB = compostableHeldItem("mental_herb", null, 1F)
|
||||
@JvmField
|
||||
val MIRROR_HERB = compostableHeldItem("mirror_herb", null, 1F)
|
||||
@@ -690,29 +818,13 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
@JvmField
|
||||
val QUICK_POWDER = heldItem("quick_powder")
|
||||
@JvmField
|
||||
val DESTINY_KNOT = heldItem("destiny_knot")
|
||||
val DAMP_ROCK = heldItem("damp_rock")
|
||||
@JvmField
|
||||
val EVERSTONE = heldItem("everstone")
|
||||
val HEAT_ROCK = heldItem("heat_rock")
|
||||
@JvmField
|
||||
val POWER_ANKLET = heldItem("power_anklet")
|
||||
val SMOOTH_ROCK = heldItem("smooth_rock")
|
||||
@JvmField
|
||||
val POWER_BAND = heldItem("power_band")
|
||||
@JvmField
|
||||
val POWER_BELT = heldItem("power_belt")
|
||||
@JvmField
|
||||
val POWER_BRACER = heldItem("power_bracer")
|
||||
@JvmField
|
||||
val POWER_LENS = heldItem("power_lens")
|
||||
@JvmField
|
||||
val POWER_WEIGHT = heldItem("power_weight")
|
||||
@JvmField
|
||||
val FLAME_ORB = heldItem("flame_orb")
|
||||
@JvmField
|
||||
val LIFE_ORB = heldItem("life_orb")
|
||||
@JvmField
|
||||
val TOXIC_ORB = heldItem("toxic_orb")
|
||||
@JvmField
|
||||
val SMOKE_BALL = heldItem("smoke_ball")
|
||||
val ICY_ROCK = heldItem("icy_rock")
|
||||
|
||||
// Mulch
|
||||
@JvmField
|
||||
@@ -738,19 +850,19 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
@JvmField
|
||||
val ARMOR_FOSSIL = noSettingsItem("armor_fossil")
|
||||
@JvmField
|
||||
val BIRD_FOSSIL = noSettingsItem("bird_fossil")
|
||||
val FOSSILIZED_BIRD = noSettingsItem("fossilized_bird")
|
||||
@JvmField
|
||||
val CLAW_FOSSIL = noSettingsItem("claw_fossil")
|
||||
@JvmField
|
||||
val COVER_FOSSIL = noSettingsItem("cover_fossil")
|
||||
@JvmField
|
||||
val DINO_FOSSIL = noSettingsItem("dino_fossil")
|
||||
val FOSSILIZED_DINO = noSettingsItem("fossilized_dino")
|
||||
@JvmField
|
||||
val DOME_FOSSIL = noSettingsItem("dome_fossil")
|
||||
@JvmField
|
||||
val DRAKE_FOSSIL = noSettingsItem("drake_fossil")
|
||||
val FOSSILIZED_DRAKE = noSettingsItem("fossilized_drake")
|
||||
@JvmField
|
||||
val FISH_FOSSIL = noSettingsItem("fish_fossil")
|
||||
val FOSSILIZED_FISH = noSettingsItem("fossilized_fish")
|
||||
@JvmField
|
||||
val HELIX_FOSSIL = noSettingsItem("helix_fossil")
|
||||
@JvmField
|
||||
@@ -826,12 +938,53 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
SmithingTemplateItem.of(CobblemonArmorTrims.AUTOMATON)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val POKEROD = pokerodItem("pokerod")
|
||||
|
||||
// Misc
|
||||
@JvmField
|
||||
val POKEMON_MODEL = this.create("pokemon_model", PokemonItem())
|
||||
@JvmField
|
||||
val RELIC_COIN = noSettingsItem("relic_coin")
|
||||
@JvmField
|
||||
val RELIC_COIN_POUCH = blockItem("relic_coin_pouch", CobblemonBlocks.RELIC_COIN_POUCH)
|
||||
@JvmField
|
||||
val RELIC_COIN_SACK = blockItem("relic_coin_sack", CobblemonBlocks.RELIC_COIN_SACK)
|
||||
|
||||
// Type Gems
|
||||
@JvmField
|
||||
val NORMAL_GEM = noSettingsItem("normal_gem")
|
||||
@JvmField
|
||||
val FIRE_GEM = noSettingsItem("fire_gem")
|
||||
@JvmField
|
||||
val WATER_GEM = noSettingsItem("water_gem")
|
||||
@JvmField
|
||||
val GRASS_GEM = noSettingsItem("grass_gem")
|
||||
@JvmField
|
||||
val ELECTRIC_GEM = noSettingsItem("electric_gem")
|
||||
@JvmField
|
||||
val ICE_GEM = noSettingsItem("ice_gem")
|
||||
@JvmField
|
||||
val FIGHTING_GEM = noSettingsItem("fighting_gem")
|
||||
@JvmField
|
||||
val POISON_GEM = noSettingsItem("poison_gem")
|
||||
@JvmField
|
||||
val GROUND_GEM = noSettingsItem("ground_gem")
|
||||
@JvmField
|
||||
val FLYING_GEM = noSettingsItem("flying_gem")
|
||||
@JvmField
|
||||
val PSYCHIC_GEM = noSettingsItem("psychic_gem")
|
||||
@JvmField
|
||||
val BUG_GEM = noSettingsItem("bug_gem")
|
||||
@JvmField
|
||||
val ROCK_GEM = noSettingsItem("rock_gem")
|
||||
@JvmField
|
||||
val GHOST_GEM = noSettingsItem("ghost_gem")
|
||||
@JvmField
|
||||
val DRAGON_GEM = noSettingsItem("dragon_gem")
|
||||
@JvmField
|
||||
val DARK_GEM = noSettingsItem("dark_gem")
|
||||
@JvmField
|
||||
val STEEL_GEM = noSettingsItem("steel_gem")
|
||||
@JvmField
|
||||
val FAIRY_GEM = noSettingsItem("fairy_gem")
|
||||
|
||||
private fun blockItem(name: String, block: Block): BlockItem = this.create(name, BlockItem(block, Item.Settings()))
|
||||
|
||||
@@ -850,12 +1003,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
|
||||
private fun candyItem(name: String, calculator: CandyItem.Calculator): CandyItem = this.create(name, CandyItem(calculator))
|
||||
|
||||
private fun pokerodItem(name: String): PokerodItem {
|
||||
var settings = Item.Settings()
|
||||
val item = create(name, PokerodItem(settings))
|
||||
return item
|
||||
}
|
||||
|
||||
private fun heldItem(name: String, remappedName: String? = null): CobblemonItem = create(
|
||||
name,
|
||||
CobblemonItem(Item.Settings()).also {
|
||||
@@ -864,6 +1011,16 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
}
|
||||
}
|
||||
)
|
||||
private fun heldItem(name: String, item: Item, remappedName: String? = null) = create(
|
||||
name = name,
|
||||
entry = item.also {
|
||||
if (remappedName != null) {
|
||||
CobblemonHeldItemManager.registerRemap(it, remappedName)
|
||||
CobblemonHeldItemManager.registerRemap(Items.BONE, "thickclub")
|
||||
CobblemonHeldItemManager.registerRemap(Items.SNOWBALL, "snowball")
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
private fun compostable(item: Item, increaseLevelChance: Float) = Cobblemon.implementation.registerCompostable(item, increaseLevelChance)
|
||||
|
||||
|
||||
@@ -82,9 +82,12 @@ import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyCallbackPa
|
||||
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyMoveCallbackPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.AbilityRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.BerryRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.GlobalSpeciesFeatureSyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.MovesRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.PropertiesCompletionRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.SpeciesFeatureAssignmentSyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.SpeciesRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.StandardSpeciesFeatureSyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.UnlockReloadPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueClosedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueOpenedPacket
|
||||
@@ -248,6 +251,7 @@ object CobblemonNetwork : NetworkManager {
|
||||
this.createClientBound(PokemonStateUpdatePacket.ID, PokemonStateUpdatePacket::decode, PokemonUpdatePacketHandler())
|
||||
this.createClientBound(TetheringUpdatePacket.ID, TetheringUpdatePacket::decode, PokemonUpdatePacketHandler())
|
||||
this.createClientBound(TradeableUpdatePacket.ID, TradeableUpdatePacket::decode, PokemonUpdatePacketHandler())
|
||||
this.createClientBound(SpeciesFeatureUpdatePacket.ID, SpeciesFeatureUpdatePacket::decode, PokemonUpdatePacketHandler())
|
||||
this.createClientBound(OriginalTrainerUpdatePacket.ID, OriginalTrainerUpdatePacket::decode, PokemonUpdatePacketHandler())
|
||||
|
||||
// Evolution start
|
||||
@@ -314,6 +318,9 @@ object CobblemonNetwork : NetworkManager {
|
||||
this.createClientBound(PropertiesCompletionRegistrySyncPacket.ID, PropertiesCompletionRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
this.createClientBound(UnlockReloadPacket.ID, UnlockReloadPacket::decode, UnlockReloadPacketHandler)
|
||||
this.createClientBound(BerryRegistrySyncPacket.ID, BerryRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
this.createClientBound(StandardSpeciesFeatureSyncPacket.ID, StandardSpeciesFeatureSyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
this.createClientBound(GlobalSpeciesFeatureSyncPacket.ID, GlobalSpeciesFeatureSyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
this.createClientBound(SpeciesFeatureAssignmentSyncPacket.ID, SpeciesFeatureAssignmentSyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
this.createClientBound(NaturalMaterialRegistrySyncPacket.ID, NaturalMaterialRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
this.createClientBound(FossilRegistrySyncPacket.ID, FossilRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import net.minecraft.registry.RegistryKey
|
||||
import net.minecraft.registry.RegistryKeys
|
||||
import net.minecraft.sound.BlockSoundGroup
|
||||
import net.minecraft.sound.SoundEvent
|
||||
import net.minecraft.sound.SoundEvents
|
||||
|
||||
object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Registry<SoundEvent>>, SoundEvent>() {
|
||||
|
||||
@@ -84,6 +85,8 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
|
||||
val MEDICINE_PILLS_USE = this.create("medicine_pills.use")
|
||||
@JvmField
|
||||
val MEDICINE_SPRAY_USE = this.create("medicine_spray.use")
|
||||
@JvmField
|
||||
val MEDICINE_FEATHER_USE = this.create("medicine_feather.use")
|
||||
|
||||
@JvmField
|
||||
val BERRY_HARVEST = this.create("berry.harvest")
|
||||
@@ -118,6 +121,14 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_UNPROTECTED = this.create("fossilmachine.unprotected")
|
||||
|
||||
@JvmField
|
||||
val COIN_POUCH_BREAK = this.create("coin_pouch.break")
|
||||
@JvmField
|
||||
val COIN_POUCH_HIT = this.create("coin_pouch.hit")
|
||||
@JvmField
|
||||
val COIN_POUCH_STEP = this.create("coin_pouch.step")
|
||||
@JvmField
|
||||
val COIN_POUCH_PLACE = this.create("coin_pouch.place")
|
||||
@JvmField
|
||||
val TUMBLESTONE_BREAK = this.create("tumblestone.break")
|
||||
@JvmField
|
||||
@@ -129,6 +140,52 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
|
||||
@JvmField
|
||||
val TUMBLESTONE_STEP = this.create("tumblestone.step")
|
||||
|
||||
@JvmField
|
||||
val GIMMIGHOUL_GIVE_ITEM_SMALL = this.create("gimmighoul.give_item_small")
|
||||
@JvmField
|
||||
val GIMMIGHOUL_REVEAL = this.create("gimmighoul.reveal")
|
||||
|
||||
@JvmField
|
||||
val BERRY_BUSH_BREAK = this.create("berry_bush.break")
|
||||
@JvmField
|
||||
val BERRY_BUSH_PLACE = this.create("berry_bush.place")
|
||||
|
||||
@JvmField
|
||||
val BIG_ROOT_BREAK = this.create("big_root.break")
|
||||
@JvmField
|
||||
val ENERGY_ROOT_PLACE = this.create("energy_root.place")
|
||||
|
||||
@JvmField
|
||||
val MINT_BREAK = this.create("mint.break")
|
||||
@JvmField
|
||||
val MINT_PLACE = this.create("mint.place")
|
||||
|
||||
@JvmField
|
||||
val MEDICINAL_LEEK_BREAK = this.create("medicinal_leek.break")
|
||||
@JvmField
|
||||
val MEDICINAL_LEEK_PLACE = this.create("medicinal_leek.plant")
|
||||
|
||||
@JvmField
|
||||
val GILDED_CHEST_OPEN = this.create("gilded_chest.open")
|
||||
@JvmField
|
||||
val GILDED_CHEST_CLOSE = this.create("gilded_chest.close")
|
||||
@JvmField
|
||||
val GILDED_CHEST_STEP = this.create("gilded_chest.step")
|
||||
@JvmField
|
||||
val GILDED_CHEST_HIT = this.create("gilded_chest.hit")
|
||||
@JvmField
|
||||
val GILDED_CHEST_BREAK = this.create("gilded_chest.break")
|
||||
@JvmField
|
||||
val GILDED_CHEST_PLACE = this.create("gilded_chest.place")
|
||||
|
||||
@JvmField
|
||||
val COIN_POUCH_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
COIN_POUCH_BREAK,
|
||||
COIN_POUCH_STEP,
|
||||
COIN_POUCH_PLACE,
|
||||
COIN_POUCH_HIT,
|
||||
COIN_POUCH_STEP
|
||||
)
|
||||
@JvmField
|
||||
val IMPACT_NORMAL = this.create("impact.normal")
|
||||
@JvmField
|
||||
@@ -184,5 +241,81 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
|
||||
TUMBLESTONE_STEP
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val BERRY_BUSH_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
BERRY_BUSH_BREAK,
|
||||
SoundEvents.BLOCK_GRASS_STEP,
|
||||
BERRY_BUSH_PLACE,
|
||||
SoundEvents.BLOCK_GRASS_HIT,
|
||||
SoundEvents.BLOCK_GRASS_STEP
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val BIG_ROOT_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
BIG_ROOT_BREAK,
|
||||
SoundEvents.BLOCK_ROOTS_STEP,
|
||||
SoundEvents.BLOCK_ROOTS_PLACE,
|
||||
SoundEvents.BLOCK_ROOTS_HIT,
|
||||
SoundEvents.BLOCK_ROOTS_FALL
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val ENERGY_ROOT_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
SoundEvents.BLOCK_ROOTS_BREAK,
|
||||
SoundEvents.BLOCK_ROOTS_STEP,
|
||||
ENERGY_ROOT_PLACE,
|
||||
SoundEvents.BLOCK_ROOTS_HIT,
|
||||
SoundEvents.BLOCK_ROOTS_FALL
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val MEDICINAL_LEEK_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
MEDICINAL_LEEK_BREAK,
|
||||
SoundEvents.BLOCK_GRASS_STEP,
|
||||
MEDICINAL_LEEK_PLACE,
|
||||
SoundEvents.BLOCK_GRASS_HIT,
|
||||
SoundEvents.BLOCK_GRASS_FALL
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val MINT_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
MINT_BREAK,
|
||||
SoundEvents.BLOCK_GRASS_STEP,
|
||||
MINT_PLACE,
|
||||
SoundEvents.BLOCK_GRASS_HIT,
|
||||
SoundEvents.BLOCK_GRASS_FALL
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val GILDED_CHEST_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
GILDED_CHEST_BREAK,
|
||||
GILDED_CHEST_STEP,
|
||||
GILDED_CHEST_PLACE,
|
||||
GILDED_CHEST_HIT,
|
||||
GILDED_CHEST_STEP
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val DISPLAY_CASE_ADD_ITEM = this.create("display_case.add_item")
|
||||
@JvmField
|
||||
val DISPLAY_CASE_REMOVE_ITEM = this.create("display_case.remove_item")
|
||||
@JvmField
|
||||
val DISPLAY_CASE_BREAK = this.create("display_case.break")
|
||||
@JvmField
|
||||
val DISPLAY_CASE_HIT = this.create("display_case.hit")
|
||||
@JvmField
|
||||
val DISPLAY_CASE_PLACE = this.create("display_case.place")
|
||||
@JvmField
|
||||
val DISPLAY_CASE_STEP = this.create("display_case.step")
|
||||
|
||||
@JvmField
|
||||
val DISPLAY_CASE_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
DISPLAY_CASE_BREAK,
|
||||
DISPLAY_CASE_STEP,
|
||||
DISPLAY_CASE_PLACE,
|
||||
DISPLAY_CASE_HIT,
|
||||
DISPLAY_CASE_STEP
|
||||
)
|
||||
|
||||
private fun create(name: String): SoundEvent = this.create(name, SoundEvent.of(cobblemonResource(name)))
|
||||
}
|
||||
@@ -113,6 +113,14 @@ object CobblemonCriteria {
|
||||
)
|
||||
)
|
||||
|
||||
// Advancement criteria for [grow_tumblestone.json]
|
||||
val PLANT_TUMBLESTONE = this.create(
|
||||
SimpleCriterionTrigger(
|
||||
cobblemonResource("plant_tumblestone"),
|
||||
PlantTumblestoneCriterionCondition::class.java
|
||||
)
|
||||
)
|
||||
|
||||
private fun <T : Criterion<*>> create(criteria: T): T = Cobblemon.implementation.registerCriteria(criteria)
|
||||
|
||||
}
|
||||
+52
@@ -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.advancement.criterion
|
||||
|
||||
import com.cobblemon.mod.common.block.TumblestoneBlock
|
||||
import com.google.gson.JsonObject
|
||||
import net.minecraft.predicate.entity.LootContextPredicate
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.BlockPos
|
||||
|
||||
/**
|
||||
* A criterion condition for when a tumblestone block is planted
|
||||
* @param id The identifier of the criterion
|
||||
* @param predicate The predicate for the criterion
|
||||
*
|
||||
* @author Aethen
|
||||
* @since 02/28/2024
|
||||
*/
|
||||
class PlantTumblestoneCriterionCondition(id: Identifier, predicate: LootContextPredicate) :
|
||||
SimpleCriterionCondition<PlantTumblestoneContext>(id, predicate) {
|
||||
override fun toJson(json: JsonObject) {
|
||||
// Add properties to json if needed. None needed for this criterion
|
||||
}
|
||||
|
||||
override fun fromJson(json: JsonObject) {
|
||||
// Parse properties from json if needed. None needed for this criterion
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the tumblestone block can grow at the given position
|
||||
* @param player The player that planted the tumblestone block
|
||||
* @param context The context of the criterion
|
||||
* @return True if the tumblestone block can grow at the given position, false otherwise
|
||||
*/
|
||||
override fun matches(player: ServerPlayerEntity, context: PlantTumblestoneContext): Boolean {
|
||||
return context.tumbleStoneBlock.canGrow(context.pos, player.world)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The context of the [PlantTumblestoneCriterionCondition]
|
||||
* @param pos The position of the tumblestone block
|
||||
* @param tumbleStoneBlock The tumblestone block
|
||||
*/
|
||||
open class PlantTumblestoneContext(var pos: BlockPos, var tumbleStoneBlock: TumblestoneBlock)
|
||||
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.api.abilities
|
||||
|
||||
import com.cobblemon.mod.common.api.Priority
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import com.google.gson.JsonObject
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
@@ -21,7 +22,7 @@ import net.minecraft.nbt.NbtCompound
|
||||
* @author Qu
|
||||
* @since January 9th, 2022
|
||||
*/
|
||||
open class Ability internal constructor(var template: AbilityTemplate, var forced: Boolean) {
|
||||
open class Ability internal constructor(var template: AbilityTemplate, forced: Boolean) {
|
||||
|
||||
val name: String
|
||||
get() = template.name
|
||||
@@ -34,16 +35,26 @@ open class Ability internal constructor(var template: AbilityTemplate, var force
|
||||
|
||||
/**
|
||||
* This represents the last known index of this backing ability in the species data.
|
||||
* If -1 the ability will attempt to find the correct index or reroll itself, this is done in order to be compatible with existing data
|
||||
* The value can be mutated however this is not recommended by API users.
|
||||
* @see [Pokemon.updateAbility].
|
||||
*/
|
||||
var forced: Boolean = forced
|
||||
internal set
|
||||
|
||||
/**
|
||||
* This represents the last known index of this backing ability in the species data.
|
||||
*
|
||||
* @see [Pokemon.updateAbility].
|
||||
*/
|
||||
var index: Int = -1
|
||||
internal set
|
||||
|
||||
/**
|
||||
* The last known priority of this ability in the species data.
|
||||
* The value can be mutated however this is not recommended by API users.
|
||||
*
|
||||
* @see [Pokemon.updateAbility].
|
||||
*/
|
||||
var priority = Priority.LOWEST
|
||||
internal set
|
||||
|
||||
open fun saveToNBT(nbt: NbtCompound): NbtCompound {
|
||||
nbt.putString(DataKeys.POKEMON_ABILITY_NAME, name)
|
||||
@@ -62,19 +73,23 @@ open class Ability internal constructor(var template: AbilityTemplate, var force
|
||||
}
|
||||
|
||||
open fun loadFromNBT(nbt: NbtCompound): Ability {
|
||||
forced = nbt.getBoolean(DataKeys.POKEMON_ABILITY_FORCED)
|
||||
this.template = Abilities.getOrException(nbt.getString(DataKeys.POKEMON_ABILITY_NAME))
|
||||
this.forced = nbt.getBoolean(DataKeys.POKEMON_ABILITY_FORCED)
|
||||
if (nbt.contains(DataKeys.POKEMON_ABILITY_INDEX) && nbt.contains(DataKeys.POKEMON_ABILITY_PRIORITY)) {
|
||||
this.index = nbt.getInt(DataKeys.POKEMON_ABILITY_INDEX)
|
||||
this.priority = Priority.valueOf(nbt.getString(DataKeys.POKEMON_ABILITY_PRIORITY))
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
open fun loadFromJSON(json: JsonObject): Ability {
|
||||
forced = json.get(DataKeys.POKEMON_ABILITY_FORCED)?.asBoolean ?: false
|
||||
this.template = Abilities.getOrException(json.get(DataKeys.POKEMON_ABILITY_NAME).asString)
|
||||
this.forced = json.get(DataKeys.POKEMON_ABILITY_FORCED)?.asBoolean ?: false
|
||||
if (json.has(DataKeys.POKEMON_ABILITY_INDEX) && json.has(DataKeys.POKEMON_ABILITY_PRIORITY)) {
|
||||
this.index = json.get(DataKeys.POKEMON_ABILITY_INDEX).asInt
|
||||
this.priority = Priority.valueOf(json.get(DataKeys.POKEMON_ABILITY_PRIORITY).asString)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
}
|
||||
@@ -28,7 +28,6 @@ class AbilityTemplate(
|
||||
*/
|
||||
fun create(forced: Boolean = false) = builder(this, forced)
|
||||
|
||||
|
||||
/**
|
||||
* Returns the Ability and loads the given NBT Tag into it.
|
||||
*
|
||||
@@ -42,4 +41,5 @@ class AbilityTemplate(
|
||||
* Ability extensions need to write and read their needed data from here.
|
||||
*/
|
||||
fun create(json: JsonObject) = create().loadFromJSON(json)
|
||||
|
||||
}
|
||||
+23
-20
@@ -135,28 +135,31 @@ class BattleMessage(rawMessage: String) {
|
||||
return this.actorAndActivePokemon(pnx, battle)
|
||||
}
|
||||
|
||||
/*
|
||||
Example:
|
||||
|-curestatus|p1: a8e5710e-6835-4387-99d3-331b45f848e6|slp|[msg]
|
||||
|-curestatus|p1: 0686b20d-3019-4167-92e2-786834245743|slp|[msg]
|
||||
// Function used to grab BattlePokemon (As we need to be able to grab non active pokemon to cure their status)
|
||||
// by using playerNumber(actorID) and pokemon uuid(pokemonID)
|
||||
/**
|
||||
* Queries an argument at the given [index] for a 'pnx' and uuid that will be parsed into a [BattlePokemon].
|
||||
*
|
||||
* @param index The index of the argument referencing the [BattlePokemon].
|
||||
* @param battle The [PokemonBattle] being queried.
|
||||
* @return The [BattlePokemon] if the argument exists and is successfully parsed; otherwise null.
|
||||
*/
|
||||
fun getBattlePokemon(index: Int, battle: PokemonBattle): BattlePokemon? {
|
||||
val actorAndPokemonID = this.argumentAt(index)?.takeIf { it.length >= 2 }?.split(": ") ?: return null
|
||||
if (actorAndPokemonID.count() < 2) return null
|
||||
val actorID = actorAndPokemonID[0]
|
||||
val pokemonID = actorAndPokemonID[1]
|
||||
return this.getBattlePokemon(actorID, pokemonID, battle)
|
||||
fun battlePokemon(index: Int, battle: PokemonBattle): BattlePokemon? {
|
||||
val (actorID, pokemonID) = this.pnxAndUuid(index) ?: return null
|
||||
return this.battlePokemon(actorID, pokemonID, battle)
|
||||
}
|
||||
|
||||
fun getSourceBattlePokemon(battle: PokemonBattle): BattlePokemon? {
|
||||
val sourcePokemonArgument = this.optionalArguments.get("of") ?: return null
|
||||
val actorAndPokemonID = sourcePokemonArgument.takeIf { it.length >= 2 }?.split(": ") ?: return null
|
||||
if (actorAndPokemonID.count() < 2) return null
|
||||
val actorID = actorAndPokemonID[0]
|
||||
val pokemonID = actorAndPokemonID[1]
|
||||
return this.getBattlePokemon(actorID, pokemonID, battle)
|
||||
/**
|
||||
* Queries an optional argument identified by [optionalArg] for a 'pnx' and uuid that will be parsed into a [BattlePokemon].
|
||||
*
|
||||
* @param optionalArg The id of the optional argument referencing the [BattlePokemon].
|
||||
* @param battle The [PokemonBattle] being queried.
|
||||
* @return The [BattlePokemon] if the argument exists and is successfully parsed; otherwise null.
|
||||
*/
|
||||
fun battlePokemonFromOptional(battle: PokemonBattle, optionalArg: String = "of"): BattlePokemon? {
|
||||
val optional = this.optionalArguments.get(optionalArg) ?: return null
|
||||
val pokemonID = optional.takeIf { it.length >= 2 }?.split(":")?.takeIf { it.size == 2 } ?: return null
|
||||
val pnx = pokemonID[0].takeIf { it.matches(PNX_MATCHER) || it.matches(PN_MATCHER) } ?: return null
|
||||
val uuid = pokemonID[1].trim()
|
||||
return this.battlePokemon(pnx, uuid, battle)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -234,7 +237,7 @@ class BattleMessage(rawMessage: String) {
|
||||
null
|
||||
}
|
||||
|
||||
private fun getBattlePokemon(pnx: String, pokemonID: String, battle: PokemonBattle): BattlePokemon? = try {
|
||||
private fun battlePokemon(pnx: String, pokemonID: String, battle: PokemonBattle): BattlePokemon? = try {
|
||||
battle.getBattlePokemon(pnx, pokemonID)
|
||||
} catch (_: Exception) {
|
||||
null
|
||||
|
||||
@@ -8,13 +8,11 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.battles.model
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangEnvironment
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.CobblemonNetwork
|
||||
import com.cobblemon.mod.common.Environment
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
@@ -22,8 +20,6 @@ import com.cobblemon.mod.common.api.battles.model.actor.EntityBackedBattleActor
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.FleeableBattleActor
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.battles.BattleFledEvent
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunction
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
@@ -44,7 +40,6 @@ import com.cobblemon.mod.common.battles.runner.ShowdownService
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleEndPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleMessagePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleMusicPacket
|
||||
import com.cobblemon.mod.common.pokemon.evolution.progress.DefeatEvolutionProgress
|
||||
import com.cobblemon.mod.common.pokemon.evolution.progress.LastBattleCriticalHitsEvolutionProgress
|
||||
import com.cobblemon.mod.common.pokemon.evolution.requirements.DefeatRequirement
|
||||
@@ -107,6 +102,11 @@ open class PokemonBattle(
|
||||
var turn: Int = 1
|
||||
private set
|
||||
|
||||
private var ticks: Int = 0
|
||||
set(value) { field = value.coerceAtMost(Int.MAX_VALUE) } // go outside
|
||||
|
||||
/** The current duration of the battle in seconds. */
|
||||
val time: Int get() = ticks % 20
|
||||
|
||||
var dispatchResult = GO
|
||||
val dispatches = ConcurrentLinkedDeque<BattleDispatch>()
|
||||
@@ -166,7 +166,7 @@ open class PokemonBattle(
|
||||
fun getActor(player: ServerPlayerEntity) = actors.firstOrNull { it.isForPlayer(player) }
|
||||
|
||||
/**
|
||||
* Gets a BattleActor and an [ActiveBattlePokemon] from a pnx key, e.g. p2a
|
||||
* Gets a [BattleActor] and an [ActiveBattlePokemon] from a pnx key, e.g. p2a
|
||||
*
|
||||
* Returns null if either the pn or x is invalid.
|
||||
*/
|
||||
@@ -179,6 +179,11 @@ open class PokemonBattle(
|
||||
return actor to pokemon
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a [BattlePokemon] from a pnx key and uuid.
|
||||
*
|
||||
* Returns null if the pnx key is invalid or the uuid does not exist.
|
||||
*/
|
||||
fun getBattlePokemon(pnx: String, pokemonID: String): BattlePokemon {
|
||||
val actor = actors.find { it.showdownId == pnx.substring(0, 2) }
|
||||
?: throw IllegalStateException("Invalid pnx: $pnx - unknown actor")
|
||||
@@ -390,8 +395,9 @@ open class PokemonBattle(
|
||||
return
|
||||
}
|
||||
|
||||
if (started && isPvW && !ended && dispatches.isEmpty()) {
|
||||
checkFlee()
|
||||
if (started) {
|
||||
ticks++
|
||||
if (isPvW && !ended && dispatches.isEmpty()) checkFlee()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.api.drop
|
||||
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents.LOOT_DROPPED
|
||||
import com.cobblemon.mod.common.api.events.drops.LootDroppedEvent
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.entity.LivingEntity
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
@@ -88,6 +89,8 @@ class DropTable {
|
||||
amount: IntRange = this.amount
|
||||
) {
|
||||
val drops = getDrops(amount).toMutableList()
|
||||
val heldItem = (entity as PokemonEntity).pokemon.heldItemNoCopy()
|
||||
if (!heldItem.isEmpty) entity.dropItem(heldItem.item)
|
||||
LOOT_DROPPED.postThen(
|
||||
event = LootDroppedEvent(this, player, entity, drops),
|
||||
ifSucceeded = { it.drops.forEach { it.drop(entity, world, pos, player) } }
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.cobblemon.mod.common.api.entity.pokemon
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.effects.IllusionEffect
|
||||
import com.cobblemon.mod.common.entity.pokemon.effects.TransformEffect
|
||||
import com.cobblemon.mod.common.pokemon.FormData
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* Represents a temporary alteration to how a [PokemonEntity] is rendered and behaves. May include a temporary visual effect
|
||||
* when applied.
|
||||
*
|
||||
* @author Segfault Guy
|
||||
* @since March 5th, 2024
|
||||
*/
|
||||
interface EntityEffect {
|
||||
|
||||
/**
|
||||
* Starts this effect for the provided [PokemonEntity].
|
||||
*
|
||||
* @return A [CompletableFuture] that completes after the effect has been applied. Or null if the effect failed to start.
|
||||
*/
|
||||
fun start(entity: PokemonEntity): CompletableFuture<PokemonEntity>?
|
||||
|
||||
/**
|
||||
* Ends this effect for the provided [PokemonEntity].
|
||||
*
|
||||
* @return A [CompletableFuture] that completes after the effect has been reverted. Or null if the effect failed to end.
|
||||
*/
|
||||
fun end(entity: PokemonEntity): CompletableFuture<PokemonEntity>?
|
||||
|
||||
/** Saves this effect to NBT. */
|
||||
fun saveToNbt(): NbtCompound
|
||||
|
||||
/** Loads this effect from NBT. */
|
||||
fun loadFromNBT(nbt: NbtCompound)
|
||||
|
||||
companion object {
|
||||
|
||||
private val effects = mutableMapOf<String, KClass<out EntityEffect>>()
|
||||
private val defaults = mutableMapOf<String, () -> EntityEffect>()
|
||||
|
||||
init {
|
||||
register(IllusionEffect.ID, IllusionEffect::class, ::IllusionEffect)
|
||||
register(TransformEffect.ID, TransformEffect::class, ::TransformEffect)
|
||||
}
|
||||
|
||||
fun <T : EntityEffect> register(id: String, type: KClass<T>, default: () -> T) {
|
||||
effects[id] = type
|
||||
defaults[id] = default
|
||||
}
|
||||
|
||||
fun createDefault(id: String): EntityEffect? = defaults[id]?.invoke()
|
||||
|
||||
fun loadFromNbt(nbt: NbtCompound): EntityEffect? {
|
||||
if (nbt.contains(DataKeys.ENTITY_EFFECT_ID)) {
|
||||
val id = nbt.getString(DataKeys.ENTITY_EFFECT_ID)
|
||||
return createDefault(id)?.also { it.loadFromNBT(nbt) }
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** An [EntityEffect] that modifies the dimensions of a [PokemonEntity]. */
|
||||
interface PhysicalEffect : EntityEffect {
|
||||
val scale: Float
|
||||
}
|
||||
|
||||
/** An [EntityEffect] that alters the physical appearance of a [PokemonEntity] to match a [mock]. */
|
||||
interface MocKEffect : PhysicalEffect {
|
||||
val mock: PokemonProperties
|
||||
|
||||
val exposedSpecies: Species?
|
||||
get() = this.mock.species?.let { PokemonSpecies.getByIdentifier(it.asIdentifierDefaultingNamespace()) }
|
||||
|
||||
val exposedForm: FormData?
|
||||
get() = this.mock.form?.let {
|
||||
formID -> this.exposedSpecies?.forms?.firstOrNull { it.formOnlyShowdownId().equals(formID, true) } }
|
||||
?: this.exposedSpecies?.standardForm
|
||||
}
|
||||
@@ -33,6 +33,7 @@ import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionCompleteEv
|
||||
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionDisplayEvent
|
||||
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionTestedEvent
|
||||
import com.cobblemon.mod.common.api.events.pokemon.interaction.ExperienceCandyUseEvent
|
||||
import com.cobblemon.mod.common.api.events.pokemon.interaction.HeldItemUpdatedEvent
|
||||
import com.cobblemon.mod.common.api.events.pokemon.interaction.PokemonInteractionGUICreationEvent
|
||||
import com.cobblemon.mod.common.api.events.starter.StarterChosenEvent
|
||||
import com.cobblemon.mod.common.api.events.storage.ReleasePokemonEvent
|
||||
@@ -66,6 +67,8 @@ object CobblemonEvents {
|
||||
val EVOLUTION_COMPLETE = EventObservable<EvolutionCompleteEvent>()
|
||||
@JvmField
|
||||
val POKEMON_NICKNAMED = CancelableObservable<PokemonNicknamedEvent>()
|
||||
@JvmField
|
||||
val HELD_ITEM_UPDATED = CancelableObservable<HeldItemUpdatedEvent>()
|
||||
|
||||
@JvmField
|
||||
val THROWN_POKEBALL_HIT = CancelableObservable<ThrownPokeballHitEvent>()
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.events.pokemon.interaction
|
||||
|
||||
import com.cobblemon.mod.common.api.events.Cancelable
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import net.minecraft.entity.LivingEntity
|
||||
import net.minecraft.item.ItemStack
|
||||
|
||||
/**
|
||||
* Event published when a held item is being updated on a [Pokemon].
|
||||
* Cancelling the event will prevent any action from being taken on
|
||||
* the Pokémon.
|
||||
*
|
||||
* [newItem] differs from [originalStack] in that the former is a
|
||||
* one-sized version of the original (Pokémon cannot hold stacks) and
|
||||
* changing it in any way will not affect the original item held by
|
||||
* the player.
|
||||
*
|
||||
* @author Whatsy, Hiroku
|
||||
* @since November 13th, 2023
|
||||
*/
|
||||
data class HeldItemUpdatedEvent(
|
||||
val cause: LivingEntity?,
|
||||
val pokemon: Pokemon,
|
||||
val originalStack: ItemStack,
|
||||
val decrement: Boolean,
|
||||
val oldItem: ItemStack,
|
||||
val newItem: ItemStack
|
||||
) : Cancelable()
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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.item.ability
|
||||
|
||||
import com.cobblemon.mod.common.api.abilities.*
|
||||
import com.cobblemon.mod.common.item.interactive.ability.AbilityTypeChanger
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.abilities.HiddenAbility
|
||||
import com.cobblemon.mod.common.pokemon.abilities.HiddenAbilityType
|
||||
|
||||
/**
|
||||
* Represents a change operation for a [Pokemon.ability].
|
||||
* This is backed by the associated [PotentialAbility].
|
||||
*
|
||||
* @param T The type of [PotentialAbility].
|
||||
*/
|
||||
interface AbilityChanger<T : PotentialAbility> {
|
||||
|
||||
/**
|
||||
* The [PotentialAbilityType] of type [T].
|
||||
*/
|
||||
val type: PotentialAbilityType<T>
|
||||
|
||||
/**
|
||||
* Collects all the possible targets for the [type] and the given [pokemon].
|
||||
*
|
||||
* @param pokemon The [Pokemon] being queried.
|
||||
* @return A set containing all their legal abilities associated with [type], can be empty.
|
||||
*/
|
||||
fun queryPossible(pokemon: Pokemon): Set<AbilityTemplate>
|
||||
|
||||
/**
|
||||
* Attempts to update the ability of the given [pokemon].
|
||||
*
|
||||
* @param pokemon The [Pokemon] attempting to change an ability.
|
||||
* @return If the operation was successful.
|
||||
*/
|
||||
fun performChange(pokemon: Pokemon): Boolean
|
||||
|
||||
/**
|
||||
* Checks if the current [PotentialAbilityType] of a [Pokemon.ability] is possible to swap from with this.
|
||||
*
|
||||
* @param type The [PotentialAbilityType] or null if the ability is forced and/or illegal.
|
||||
* @return If the operation can be performed.
|
||||
*/
|
||||
fun canChangeFrom(type: PotentialAbilityType<*>?): Boolean
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* An implementation of [AbilityChanger] for [CommonAbility].
|
||||
*
|
||||
* While this can be used in custom data scenarios this functions most "game-like" if the Pokémon only has 2 common abilities.
|
||||
*/
|
||||
@JvmStatic
|
||||
val COMMON_ABILITY: AbilityChanger<CommonAbility> = AbilityTypeChanger(CommonAbilityType) { other -> other == CommonAbilityType }
|
||||
|
||||
/**
|
||||
* An implementation of [AbilityChanger] for [HiddenAbility].
|
||||
*
|
||||
* While this can be used in custom data scenarios this functions most "game-like" if the Pokémon only has 1 hidden ability.
|
||||
*/
|
||||
@JvmStatic
|
||||
val HIDDEN_ABILITY: AbilityChanger<HiddenAbility> = AbilityTypeChanger(HiddenAbilityType) { other -> other == CommonAbilityType || other == HiddenAbilityType }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import net.minecraft.util.ActionResult
|
||||
import net.minecraft.util.Hand
|
||||
import net.minecraft.util.hit.BlockHitResult
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.world.BlockView
|
||||
import net.minecraft.world.World
|
||||
|
||||
/**
|
||||
@@ -77,6 +78,11 @@ abstract class MultiblockBlock(properties: Settings) : BlockWithEntity(propertie
|
||||
return BlockRenderType.MODEL
|
||||
}
|
||||
|
||||
override fun getPickStack(world: BlockView, pos: BlockPos, state: BlockState): ItemStack {
|
||||
val blockEntity = world.getBlockEntity(pos) as? MultiblockEntity ?: return ItemStack.EMPTY
|
||||
return if (blockEntity.multiblockStructure == null) super.getPickStack(world, pos, state) else ItemStack.EMPTY
|
||||
}
|
||||
|
||||
abstract fun createMultiBlockEntity(pos: BlockPos, state: BlockState): FossilMultiblockEntity
|
||||
|
||||
}
|
||||
|
||||
@@ -205,8 +205,8 @@ object PokeBalls : JsonDataRegistry<PokeBall> {
|
||||
createDefault("ancient_wing_ball", throwPower = 2.5f, ancient = true)
|
||||
createDefault("ancient_jet_ball", throwPower = 2.5f, ancient = true)
|
||||
createDefault("ancient_origin_ball", GuaranteedModifier(), ancient = true)
|
||||
// Luxury ball effect
|
||||
CobblemonEvents.FRIENDSHIP_UPDATED.subscribe(priority = Priority.LOWEST) { event ->
|
||||
// Luxury ball effect, low priority as it must be triggered before soothe bell as of gen 4
|
||||
CobblemonEvents.FRIENDSHIP_UPDATED.subscribe(priority = Priority.LOW) { event ->
|
||||
var increment = (event.newFriendship - event.pokemon.friendship).toFloat()
|
||||
if (increment <= 1F) {
|
||||
event.pokemon.caughtBall.effects.filterIsInstance<FriendshipEarningBoostEffect>()
|
||||
|
||||
@@ -13,12 +13,14 @@ import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.abilities.Abilities
|
||||
import com.cobblemon.mod.common.api.abilities.Ability
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.api.pokemon.aspect.AspectProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.cobblemon.mod.common.api.types.tera.TeraTypes
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.*
|
||||
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
|
||||
@@ -294,6 +296,18 @@ open class PokemonProperties {
|
||||
)
|
||||
|
||||
fun apply(pokemon: Pokemon) {
|
||||
// Custom properties check could be duplicated but can't assume 3rd party hasn't done anything type specific
|
||||
this.customProperties.forEach { it.apply(pokemon) }
|
||||
this.commonApply(pokemon)
|
||||
}
|
||||
|
||||
fun apply(pokemonEntity: PokemonEntity) {
|
||||
// Custom properties check could be duplicated but can't assume 3rd party hasn't done anything type specific
|
||||
this.customProperties.forEach { it.apply(pokemonEntity) }
|
||||
this.commonApply(pokemonEntity.pokemon)
|
||||
}
|
||||
|
||||
private fun commonApply(pokemon: Pokemon) {
|
||||
species?.let {
|
||||
return@let try {
|
||||
if (it == "random") {
|
||||
@@ -313,8 +327,8 @@ open class PokemonProperties {
|
||||
friendship?.let { pokemon.setFriendship(it) }
|
||||
pokeball?.let { PokeBalls.getPokeBall(it.asIdentifierDefaultingNamespace())?.let { pokeball -> pokemon.caughtBall = pokeball } }
|
||||
nature?.let { Natures.getNature(it.asIdentifierDefaultingNamespace())?.let { nature -> pokemon.nature = nature } }
|
||||
ability?.let { Abilities.getOrException(it).create(true).let { ability -> pokemon.ability = ability } }
|
||||
status?.let { Statuses.getStatus(it)?.let { pokemon.applyStatus(it as PersistentStatus) } }
|
||||
ability?.let { this.createAbility(it, pokemon.form)?.let(pokemon::updateAbility) }
|
||||
status?.let { Statuses.getStatus(it)?.let { status -> if (status is PersistentStatus) pokemon.applyStatus(status) } }
|
||||
customProperties.forEach { it.apply(pokemon) }
|
||||
ivs?.let { ivs ->
|
||||
ivs.forEach { stat ->
|
||||
@@ -326,7 +340,7 @@ open class PokemonProperties {
|
||||
pokemon.setEV(stat.key, stat.value)
|
||||
}
|
||||
}
|
||||
teraType?.let { ElementalTypes.get(it)?.let { type -> pokemon.teraType = type } }
|
||||
teraType?.let { TeraTypes.get(it.asIdentifierDefaultingNamespace())?.let { type -> pokemon.teraType = type } }
|
||||
dmaxLevel?.let { pokemon.dmaxLevel = it }
|
||||
gmaxFactor?.let { pokemon.gmaxFactor = it }
|
||||
tradeable?.let { pokemon.tradeable = it }
|
||||
@@ -355,69 +369,17 @@ open class PokemonProperties {
|
||||
pokemon.updateAspects()
|
||||
}
|
||||
|
||||
fun apply(pokemonEntity: PokemonEntity) {
|
||||
species?.let {
|
||||
return@let try {
|
||||
if (it == "random") {
|
||||
PokemonSpecies.species.random()
|
||||
} else {
|
||||
PokemonSpecies.getByIdentifier(it.asIdentifierDefaultingNamespace())
|
||||
}
|
||||
} catch (e: InvalidIdentifierException) {
|
||||
null
|
||||
}
|
||||
}?.let { pokemonEntity.pokemon.species = it }
|
||||
nickname?.let { pokemonEntity.pokemon.nickname = it }
|
||||
form?.let { formID -> pokemonEntity.pokemon.species.forms.firstOrNull { it.formOnlyShowdownId().equals(formID, true) } }?.let { form -> pokemonEntity.pokemon.form = form }
|
||||
level?.let { pokemonEntity.pokemon.level = it }
|
||||
shiny?.let { pokemonEntity.pokemon.shiny = it }
|
||||
gender?.let { pokemonEntity.pokemon.gender = it }
|
||||
friendship?.let { pokemonEntity.pokemon.setFriendship(it) }
|
||||
pokeball?.let { PokeBalls.getPokeBall(it.asIdentifierDefaultingNamespace())?.let { pokeball -> pokemonEntity.pokemon.caughtBall = pokeball } }
|
||||
nature?.let { Natures.getNature(it.asIdentifierDefaultingNamespace())?.let { nature -> pokemonEntity.pokemon.nature = nature } }
|
||||
ability?.let { Abilities.getOrException(it).create(true).let { ability -> pokemonEntity.pokemon.ability = ability } }
|
||||
status?.let { Statuses.getStatus(it)?.let { pokemonEntity.pokemon.applyStatus(it as PersistentStatus) } }
|
||||
customProperties.forEach { it.apply(pokemonEntity) }
|
||||
ivs?.let { ivs ->
|
||||
ivs.forEach { stat ->
|
||||
pokemonEntity.pokemon.setIV(stat.key, stat.value)
|
||||
}
|
||||
}
|
||||
evs?.let { evs ->
|
||||
evs.forEach { stat ->
|
||||
pokemonEntity.pokemon.setEV(stat.key, stat.value)
|
||||
}
|
||||
}
|
||||
teraType?.let { ElementalTypes.get(it)?.let { type -> pokemonEntity.pokemon.teraType = type } }
|
||||
dmaxLevel?.let { pokemonEntity.pokemon.dmaxLevel = it }
|
||||
gmaxFactor?.let { pokemonEntity.pokemon.gmaxFactor = it }
|
||||
tradeable?.let { pokemonEntity.pokemon.tradeable = it }
|
||||
// If it has been explicitly set to NONE, clear the stored information, including the originalTrainer property
|
||||
originalTrainerType?.let {
|
||||
if (it == OriginalTrainerType.NONE) {
|
||||
pokemonEntity.pokemon.removeOriginalTrainer()
|
||||
originalTrainer = null
|
||||
}
|
||||
}
|
||||
originalTrainer?.let { ot ->
|
||||
val type = originalTrainerType ?: pokemonEntity.pokemon.originalTrainerType
|
||||
when (type) {
|
||||
OriginalTrainerType.PLAYER -> {
|
||||
when (ot.length) {
|
||||
in 3..16 -> server()?.userCache?.findByName(ot)?.get()?.id // OT is a Username
|
||||
36 -> UUID.fromString(ot) // OT is a UUID
|
||||
else -> null // OT is invalid
|
||||
}?.let { uuid -> pokemonEntity.pokemon.setOriginalTrainer(uuid) }
|
||||
}
|
||||
OriginalTrainerType.NPC -> pokemonEntity.pokemon.setOriginalTrainer(ot)
|
||||
else -> {}
|
||||
}
|
||||
pokemonEntity.pokemon.refreshOriginalTrainer()
|
||||
}
|
||||
pokemonEntity.pokemon.updateAspects()
|
||||
fun matches(pokemon: Pokemon): Boolean {
|
||||
// Custom properties check could be duplicated but can't assume 3rd party hasn't done anything type specific
|
||||
return this.commonMatches(pokemon) && this.customProperties.none { !it.matches(pokemon) }
|
||||
}
|
||||
|
||||
fun matches(pokemon: Pokemon): Boolean {
|
||||
fun matches(pokemonEntity: PokemonEntity): Boolean {
|
||||
// Custom properties check could be duplicated but can't assume 3rd party hasn't done anything type specific
|
||||
return this.commonMatches(pokemonEntity.pokemon) && this.customProperties.none { !it.matches(pokemonEntity) }
|
||||
}
|
||||
|
||||
private fun commonMatches(pokemon: Pokemon): Boolean {
|
||||
level?.takeIf { it != pokemon.level }?.let { return false }
|
||||
shiny?.takeIf { it != pokemon.shiny }?.let { return false }
|
||||
gender?.takeIf { it != pokemon.gender }?.let { return false }
|
||||
@@ -448,59 +410,23 @@ open class PokemonProperties {
|
||||
evs?.forEach{ stat ->
|
||||
if (stat.value != pokemon.evs[stat.key]) { return false }
|
||||
}
|
||||
teraType?.takeIf { it != pokemon.teraType.name }?.let { return false }
|
||||
teraType?.takeIf { it.asIdentifierDefaultingNamespace() != pokemon.teraType.id }?.let { return false }
|
||||
dmaxLevel?.takeIf { it != pokemon.dmaxLevel }?.let { return false }
|
||||
gmaxFactor?.takeIf { it != pokemon.gmaxFactor }?.let { return false }
|
||||
tradeable?.takeIf { it != pokemon.tradeable }?.let { return false }
|
||||
originalTrainer?.takeIf { it != pokemon.originalTrainer }?.let{ return false }
|
||||
originalTrainerType?.takeIf { it != pokemon.originalTrainerType }?.let{ return false }
|
||||
return customProperties.none { !it.matches(pokemon) }
|
||||
}
|
||||
|
||||
fun matches(pokemonEntity: PokemonEntity): Boolean {
|
||||
level?.takeIf { it != pokemonEntity.pokemon.level }?.let { return false }
|
||||
shiny?.takeIf { it != ("shiny" in pokemonEntity.pokemon.aspects) }?.let { return false }
|
||||
gender?.takeIf { it != pokemonEntity.pokemon.gender }?.let { return false }
|
||||
species?.run {
|
||||
try {
|
||||
val species = if (this == "random") {
|
||||
PokemonSpecies.species.random()
|
||||
} else {
|
||||
PokemonSpecies.getByIdentifier(this.asIdentifierDefaultingNamespace()) ?: return@run
|
||||
}
|
||||
if (pokemonEntity.pokemon.species != species) {
|
||||
return false
|
||||
}
|
||||
} catch (e: InvalidIdentifierException) {}
|
||||
}
|
||||
nickname?.takeIf { it != pokemonEntity.pokemon.nickname }?.let { return false }
|
||||
form?.takeIf { !it.equals(pokemonEntity.pokemon.form.name, true) }?.let { return false }
|
||||
friendship?.takeIf { it != pokemonEntity.pokemon.friendship }?.let { return false }
|
||||
pokeball?.takeIf { it != pokemonEntity.pokemon.caughtBall.name.toString() }?.let { return false }
|
||||
nature?.takeIf { it != pokemonEntity.pokemon.nature.name.toString() }?.let { return false }
|
||||
ability?.takeIf { it != pokemonEntity.pokemon.ability.name }?.let { return false }
|
||||
status?.takeIf { it != pokemonEntity.pokemon.status?.status?.showdownName }?.let { return false }
|
||||
ivs?.forEach{ stat ->
|
||||
if (stat.value != pokemonEntity.pokemon.ivs[stat.key]) { return false }
|
||||
}
|
||||
evs?.forEach{ stat ->
|
||||
if (stat.value != pokemonEntity.pokemon.evs[stat.key]) { return false }
|
||||
}
|
||||
teraType?.takeIf { it != pokemonEntity.pokemon.teraType.name }?.let { return false }
|
||||
dmaxLevel?.takeIf { it != pokemonEntity.pokemon.dmaxLevel }?.let { return false }
|
||||
gmaxFactor?.takeIf { it != pokemonEntity.pokemon.gmaxFactor }?.let { return false }
|
||||
tradeable?.takeIf { it != pokemonEntity.pokemon.tradeable }?.let { return false }
|
||||
originalTrainer?.takeIf { it != pokemonEntity.pokemon.originalTrainer }?.let{ return false }
|
||||
originalTrainerType?.takeIf { it != pokemonEntity.pokemon.originalTrainerType }?.let{ return false }
|
||||
return customProperties.none { !it.matches(pokemonEntity) }
|
||||
return true
|
||||
}
|
||||
|
||||
// TODO Review the need for this, usage for us is in commands that deviate from the behavior established by multiple Pokémon query equivalent
|
||||
fun isSubSetOf(properties: PokemonProperties): Boolean {
|
||||
level?.takeIf { it != properties.level }?.let { return false }
|
||||
shiny?.takeIf { it != ("shiny" in properties.aspects) }?.let { return false }
|
||||
gender?.takeIf { it != properties.gender }?.let { return false }
|
||||
species?.run {
|
||||
try {
|
||||
// TODO get context on this bit, it's highly unlikely two randoms would result in the same Pokémon, doesn't mean the prop is not equal?
|
||||
val species = if (this == "random") {
|
||||
PokemonSpecies.species.random()
|
||||
} else {
|
||||
@@ -509,7 +435,7 @@ open class PokemonProperties {
|
||||
if (properties.species != species.toString()) {
|
||||
return false
|
||||
}
|
||||
} catch (e: InvalidIdentifierException) {}
|
||||
} catch (_: InvalidIdentifierException) {}
|
||||
}
|
||||
nickname?.takeIf { it != properties.nickname }?.let { return false }
|
||||
form?.takeIf { !it.equals(properties.form, true) }?.let { return false }
|
||||
@@ -551,20 +477,18 @@ open class PokemonProperties {
|
||||
|
||||
// TEST YOUR LUCK!
|
||||
fun roll(pokemon: Pokemon) {
|
||||
val baseTypes = pokemon.species.types.toList()
|
||||
val baseTypes = pokemon.form.types.toList()
|
||||
if (this.shiny == null) pokemon.shiny = Cobblemon.config.shinyRate.checkRate()
|
||||
if (this.teraType == null) pokemon.teraType =
|
||||
if (Cobblemon.config.teraTypeRate.checkRate()) ElementalTypes.all().filter { !baseTypes.contains(it) }.random()
|
||||
else baseTypes.random()
|
||||
if (Cobblemon.config.teraTypeRate.checkRate()) TeraTypes.random(true)
|
||||
else TeraTypes.forElementalType(baseTypes.random())
|
||||
}
|
||||
|
||||
// If the config value is at least 1, then do 1/x and use that as the property chance
|
||||
private fun Float.checkRate(): Boolean = this >= 1 && (Random.Default.nextFloat() < 1 / this)
|
||||
|
||||
fun createEntity(world: World): PokemonEntity {
|
||||
return PokemonEntity(world, create())
|
||||
}
|
||||
|
||||
// TODO Codecs at some point
|
||||
fun saveToNBT(): NbtCompound {
|
||||
val nbt = NbtCompound()
|
||||
originalString.let { nbt.putString(DataKeys.POKEMON_PROPERTIES_ORIGINAL_TEXT, it) }
|
||||
@@ -593,6 +517,7 @@ open class PokemonProperties {
|
||||
return nbt
|
||||
}
|
||||
|
||||
// TODO Codecs at some point
|
||||
fun loadFromNBT(tag: NbtCompound): PokemonProperties {
|
||||
originalString = tag.getString(DataKeys.POKEMON_PROPERTIES_ORIGINAL_TEXT)
|
||||
level = if (tag.contains(DataKeys.POKEMON_LEVEL)) tag.getInt(DataKeys.POKEMON_LEVEL) else null
|
||||
@@ -621,6 +546,7 @@ open class PokemonProperties {
|
||||
return this
|
||||
}
|
||||
|
||||
// TODO Codecs at some point
|
||||
fun saveToJSON(): JsonObject {
|
||||
val json = JsonObject()
|
||||
originalString.let { json.addProperty(DataKeys.POKEMON_PROPERTIES_ORIGINAL_TEXT, it) }
|
||||
@@ -650,6 +576,7 @@ open class PokemonProperties {
|
||||
return json
|
||||
}
|
||||
|
||||
// TODO Codecs at some point
|
||||
fun loadFromJSON(json: JsonObject): PokemonProperties {
|
||||
originalString = json.get(DataKeys.POKEMON_PROPERTIES_ORIGINAL_TEXT)?.asString ?: ""
|
||||
level = json.get(DataKeys.POKEMON_LEVEL)?.asInt
|
||||
@@ -727,4 +654,21 @@ open class PokemonProperties {
|
||||
fun copy(): PokemonProperties {
|
||||
return PokemonProperties().loadFromJSON(saveToJSON())
|
||||
}
|
||||
|
||||
// If the config value is at least 1, then do 1/x and use that as the property chance
|
||||
private fun Float.checkRate(): Boolean = this >= 1 && (Random.Default.nextFloat() < 1 / this)
|
||||
|
||||
/**
|
||||
* Attempts to find an ability by ID and resolve if it should be forced or if it's legal for the given form.
|
||||
*
|
||||
* @param id The literal ID of the [Ability] being mapped.
|
||||
* @param form The [FormData] whose [FormData.abilities] is queried for legality.
|
||||
* @return The [Ability] with the [Ability.forced] state necessary for the given [form].
|
||||
*/
|
||||
private fun createAbility(id: String, form: FormData): Ability? {
|
||||
val ability = Abilities.get(id) ?: return null
|
||||
val potentialAbility = form.abilities.firstOrNull { potential -> potential.template == ability } ?: return ability.create(true)
|
||||
return potentialAbility.template.create(false)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
@@ -48,6 +48,11 @@ fun interface PokemonPropertyExtractor {
|
||||
@JvmField
|
||||
val STATUS = add { pokemon, properties -> properties.status = pokemon.status?.status?.showdownName }
|
||||
|
||||
@JvmField
|
||||
val ILLUSION = mutableListOf(SPECIES, FORM, ASPECTS, GENDER, NICKNAME, SHINY)
|
||||
@JvmField
|
||||
val TRANSFORM = mutableListOf(SPECIES, FORM, ASPECTS, GENDER)
|
||||
|
||||
fun add(extractor: PokemonPropertyExtractor): PokemonPropertyExtractor {
|
||||
ALL.add(extractor)
|
||||
return extractor
|
||||
|
||||
+6
@@ -34,4 +34,10 @@ interface PassiveEvolution : Evolution {
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* If the evolution will disappear once the conditions are no longer met.
|
||||
*/
|
||||
val permanent: Boolean
|
||||
|
||||
|
||||
}
|
||||
+39
-6
@@ -11,10 +11,12 @@ package com.cobblemon.mod.common.api.pokemon.feature
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.pokemon.aspect.AspectProvider
|
||||
import com.cobblemon.mod.common.api.properties.CustomPokemonPropertyType
|
||||
import com.cobblemon.mod.common.client.gui.summary.featurerenderers.SummarySpeciesFeatureRenderer
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.substitute
|
||||
import com.google.gson.JsonObject
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
|
||||
/**
|
||||
* A [SpeciesFeatureProvider] which is a string value selected from a fixed list of choices. Parameters exist
|
||||
@@ -24,15 +26,46 @@ import net.minecraft.nbt.NbtCompound
|
||||
* @since November 30th, 2022
|
||||
*/
|
||||
open class ChoiceSpeciesFeatureProvider(
|
||||
override val keys: List<String>,
|
||||
override var keys: List<String>,
|
||||
var default: String? = null,
|
||||
var choices: List<String> = listOf(),
|
||||
var isAspect: Boolean = true,
|
||||
var aspectFormat: String = "{{choice}}"
|
||||
) : SpeciesFeatureProvider<StringSpeciesFeature>, CustomPokemonPropertyType<StringSpeciesFeature>, AspectProvider {
|
||||
override val needsKey = true
|
||||
) : SynchronizedSpeciesFeatureProvider<StringSpeciesFeature>, CustomPokemonPropertyType<StringSpeciesFeature>, AspectProvider {
|
||||
override var needsKey = true
|
||||
override var visible = false
|
||||
fun getAspect(feature: StringSpeciesFeature) = aspectFormat.substitute("choice", feature.value)
|
||||
|
||||
override fun encode(buffer: PacketByteBuf) {
|
||||
buffer.writeCollection(keys) { _, value -> buffer.writeString(value) }
|
||||
buffer.writeNullable(default) { _, value -> buffer.writeString(value) }
|
||||
buffer.writeCollection(choices) { _, value -> buffer.writeString(value) }
|
||||
buffer.writeBoolean(isAspect)
|
||||
buffer.writeString(aspectFormat)
|
||||
buffer.writeBoolean(needsKey)
|
||||
}
|
||||
|
||||
override fun decode(buffer: PacketByteBuf) {
|
||||
keys = buffer.readList { buffer.readString() }
|
||||
default = buffer.readNullable { buffer.readString() }
|
||||
choices = buffer.readList { buffer.readString() }
|
||||
isAspect = buffer.readBoolean()
|
||||
aspectFormat = buffer.readString()
|
||||
needsKey = buffer.readBoolean()
|
||||
}
|
||||
|
||||
override fun getRenderer(pokemon: Pokemon): SummarySpeciesFeatureRenderer<StringSpeciesFeature>? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun invoke(buffer: PacketByteBuf, name: String): StringSpeciesFeature? {
|
||||
return if (name in keys) {
|
||||
StringSpeciesFeature(name, "").also { it.decode(buffer) }
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun getAllAspects(): MutableList<String> {
|
||||
val aspects = choices.toMutableList()
|
||||
choices.forEach {
|
||||
@@ -45,10 +78,10 @@ open class ChoiceSpeciesFeatureProvider(
|
||||
|
||||
internal constructor(): this(emptyList())
|
||||
|
||||
fun get(pokemon: Pokemon) = pokemon.getFeature<StringSpeciesFeature>(keys.first())
|
||||
override fun get(pokemon: Pokemon) = pokemon.getFeature<StringSpeciesFeature>(keys.first())
|
||||
|
||||
override fun invoke(pokemon: Pokemon): StringSpeciesFeature? {
|
||||
val existing = pokemon.getFeature<StringSpeciesFeature>(keys.first())
|
||||
val existing = get(pokemon)
|
||||
return if (existing != null && existing.value in choices) {
|
||||
existing
|
||||
} else {
|
||||
@@ -88,7 +121,7 @@ open class ChoiceSpeciesFeatureProvider(
|
||||
|
||||
override fun provide(pokemon: Pokemon): Set<String> {
|
||||
return if (isAspect) {
|
||||
pokemon.getFeature<StringSpeciesFeature>(keys.first())?.let { setOf(getAspect(it)) } ?: emptySet()
|
||||
get(pokemon)?.let { setOf(getAspect(it)) } ?: emptySet()
|
||||
} else {
|
||||
emptySet()
|
||||
}
|
||||
|
||||
+43
-5
@@ -12,10 +12,12 @@ import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.pokemon.aspect.AspectProvider
|
||||
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
|
||||
import com.cobblemon.mod.common.api.properties.CustomPokemonPropertyType
|
||||
import com.cobblemon.mod.common.client.gui.summary.featurerenderers.SummarySpeciesFeatureRenderer
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.google.gson.JsonObject
|
||||
import kotlin.random.Random
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
|
||||
/**
|
||||
* A simple [SpeciesFeature] that is a true/false flag value. It implements [CustomPokemonProperty] for use in
|
||||
@@ -26,7 +28,7 @@ import net.minecraft.nbt.NbtCompound
|
||||
* @author Hiroku
|
||||
* @since May 13th, 2022
|
||||
*/
|
||||
open class FlagSpeciesFeature(override val name: String) : SpeciesFeature, CustomPokemonProperty {
|
||||
open class FlagSpeciesFeature(override val name: String) : SynchronizedSpeciesFeature, CustomPokemonProperty {
|
||||
constructor(name: String, enabled: Boolean): this(name) {
|
||||
this.enabled = enabled
|
||||
}
|
||||
@@ -53,6 +55,14 @@ open class FlagSpeciesFeature(override val name: String) : SpeciesFeature, Custo
|
||||
return this
|
||||
}
|
||||
|
||||
override fun encode(buffer: PacketByteBuf) {
|
||||
buffer.writeBoolean(enabled)
|
||||
}
|
||||
|
||||
override fun decode(buffer: PacketByteBuf) {
|
||||
enabled = buffer.readBoolean()
|
||||
}
|
||||
|
||||
override fun asString() = "$name=$enabled"
|
||||
|
||||
override fun apply(pokemon: Pokemon) {
|
||||
@@ -71,11 +81,37 @@ open class FlagSpeciesFeature(override val name: String) : SpeciesFeature, Custo
|
||||
override fun matches(pokemon: Pokemon) = pokemon.getFeature<FlagSpeciesFeature>(name)?.enabled == enabled
|
||||
}
|
||||
|
||||
class FlagSpeciesFeatureProvider : SpeciesFeatureProvider<FlagSpeciesFeature>, CustomPokemonPropertyType<FlagSpeciesFeature>, AspectProvider {
|
||||
override val keys: List<String>
|
||||
class FlagSpeciesFeatureProvider : SynchronizedSpeciesFeatureProvider<FlagSpeciesFeature>, CustomPokemonPropertyType<FlagSpeciesFeature>, AspectProvider {
|
||||
override var keys: List<String> = emptyList()
|
||||
// Uses get() = true because that way there's no backing field. It MUST be true, this way no JSON trickery will overwrite it
|
||||
override val needsKey get() = true
|
||||
var default: String? = null
|
||||
val isAspect = true
|
||||
var isAspect = true
|
||||
override var visible: Boolean = false
|
||||
|
||||
override fun invoke(buffer: PacketByteBuf, name: String): FlagSpeciesFeature? {
|
||||
return if (name in keys) {
|
||||
FlagSpeciesFeature(name).also { it.decode(buffer) }
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
override fun encode(buffer: PacketByteBuf) {
|
||||
buffer.writeCollection(keys) { _, value -> buffer.writeString(value) }
|
||||
buffer.writeNullable(default) { _, value -> buffer.writeString(value) }
|
||||
buffer.writeBoolean(isAspect)
|
||||
}
|
||||
|
||||
override fun decode(buffer: PacketByteBuf) {
|
||||
keys = buffer.readList { it.readString() }
|
||||
default = buffer.readNullable { it.readString() }
|
||||
isAspect = buffer.readBoolean()
|
||||
}
|
||||
|
||||
override fun getRenderer(pokemon: Pokemon): SummarySpeciesFeatureRenderer<FlagSpeciesFeature>? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun examples() = setOf("true", "false")
|
||||
|
||||
@@ -94,8 +130,10 @@ class FlagSpeciesFeatureProvider : SpeciesFeatureProvider<FlagSpeciesFeature>, C
|
||||
|
||||
constructor(vararg keys: String) : this(keys.toList())
|
||||
|
||||
override fun get(pokemon: Pokemon) = pokemon.getFeature<FlagSpeciesFeature>(keys.first())
|
||||
|
||||
override fun invoke(pokemon: Pokemon): FlagSpeciesFeature? {
|
||||
return pokemon.getFeature(keys.first())
|
||||
return get(pokemon)
|
||||
?: when (default) {
|
||||
"random" -> FlagSpeciesFeature(keys.first(), Random.Default.nextBoolean())
|
||||
in setOf("true", "false") -> FlagSpeciesFeature(keys.first(), default.toBoolean())
|
||||
|
||||
+14
-1
@@ -8,13 +8,17 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.feature
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.pokemon.aspect.AspectProvider
|
||||
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
|
||||
import com.cobblemon.mod.common.api.properties.CustomPokemonPropertyType
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.net.messages.client.data.GlobalSpeciesFeatureSyncPacket
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.SpeciesFeatureProviderAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.Vec3dAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
@@ -24,6 +28,7 @@ import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.resource.ResourceType
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.Vec3d
|
||||
|
||||
/**
|
||||
* A registry very similar to [SpeciesFeatures] but the [SpeciesFeatureProvider] contained within it
|
||||
@@ -42,11 +47,15 @@ object GlobalSpeciesFeatures : JsonDataRegistry<SpeciesFeatureProvider<*>> {
|
||||
override val gson: Gson = GsonBuilder()
|
||||
.setPrettyPrinting()
|
||||
.registerTypeAdapter(SpeciesFeatureProvider::class.java, SpeciesFeatureProviderAdapter)
|
||||
.registerTypeAdapter(Vec3d::class.java, Vec3dAdapter)
|
||||
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
|
||||
.create()
|
||||
override val typeToken: TypeToken<SpeciesFeatureProvider<*>> = TypeToken.get(SpeciesFeatureProvider::class.java)
|
||||
override val resourcePath: String = "global_species_features"
|
||||
|
||||
override fun sync(player: ServerPlayerEntity) {}
|
||||
override fun sync(player: ServerPlayerEntity) {
|
||||
player.sendPacket(GlobalSpeciesFeatureSyncPacket(codeFeatures + resourceFeatures))
|
||||
}
|
||||
|
||||
override fun reload(data: Map<Identifier, SpeciesFeatureProvider<*>>) {
|
||||
resourceFeatures.keys.toList().forEach(this::unregister)
|
||||
@@ -59,6 +68,10 @@ object GlobalSpeciesFeatures : JsonDataRegistry<SpeciesFeatureProvider<*>> {
|
||||
|
||||
fun getFeatures() = (resourceFeatures.keys + codeFeatures.keys).mapNotNull(this::getFeature)
|
||||
|
||||
fun loadOnClient(entries: Collection<Map.Entry<String, SpeciesFeatureProvider<*>>>) {
|
||||
codeFeatures.putAll(entries.map { it.toPair() })
|
||||
}
|
||||
|
||||
private fun register(name: String, provider: SpeciesFeatureProvider<*>, isCoded: Boolean) {
|
||||
val mapping = if (isCoded) codeFeatures else resourceFeatures
|
||||
if (provider is AspectProvider) {
|
||||
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* 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.pokemon.feature
|
||||
|
||||
import com.cobblemon.mod.common.api.net.Decodable
|
||||
import com.cobblemon.mod.common.api.net.Encodable
|
||||
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
|
||||
import com.cobblemon.mod.common.api.properties.CustomPokemonPropertyType
|
||||
import com.cobblemon.mod.common.client.gui.summary.featurerenderers.BarSummarySpeciesFeatureRenderer
|
||||
import com.cobblemon.mod.common.client.gui.summary.featurerenderers.SummarySpeciesFeatureRenderer
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.Vec3d
|
||||
|
||||
/**
|
||||
* A species feature value that's just an integer. Complex stuff.
|
||||
* @author Hiroku
|
||||
*/
|
||||
class IntSpeciesFeature(override var name: String) : SynchronizedSpeciesFeature, CustomPokemonProperty {
|
||||
var value = 0
|
||||
|
||||
constructor(): this("")
|
||||
constructor(name: String, value: Int): this(name) {
|
||||
this.value = value
|
||||
}
|
||||
|
||||
override fun saveToNBT(pokemonNBT: NbtCompound): NbtCompound {
|
||||
pokemonNBT.putInt(name, value)
|
||||
return pokemonNBT
|
||||
}
|
||||
|
||||
override fun loadFromNBT(pokemonNBT: NbtCompound): SynchronizedSpeciesFeature {
|
||||
value = pokemonNBT.getInt(name)
|
||||
return this
|
||||
}
|
||||
|
||||
override fun saveToJSON(pokemonJSON: JsonObject): JsonObject {
|
||||
pokemonJSON.addProperty(name, value)
|
||||
return pokemonJSON
|
||||
}
|
||||
|
||||
override fun loadFromJSON(pokemonJSON: JsonObject): SpeciesFeature {
|
||||
value = pokemonJSON.get(name).asInt
|
||||
return this
|
||||
}
|
||||
|
||||
override fun encode(buffer: PacketByteBuf) {
|
||||
buffer.writeInt(value)
|
||||
}
|
||||
|
||||
override fun decode(buffer: PacketByteBuf) {
|
||||
value = buffer.readInt()
|
||||
}
|
||||
|
||||
override fun asString() = "$name=$value"
|
||||
override fun apply(pokemon: Pokemon) {
|
||||
val featureProvider = SpeciesFeatures.getFeature(name) ?: return
|
||||
if (featureProvider in SpeciesFeatures.getFeaturesFor(pokemon.species)) {
|
||||
val existingFeature = pokemon.getFeature<IntSpeciesFeature>(name)
|
||||
if (existingFeature != null) {
|
||||
existingFeature.value = value
|
||||
} else {
|
||||
pokemon.features.add(IntSpeciesFeature(name, value))
|
||||
}
|
||||
pokemon.updateAspects()
|
||||
}
|
||||
}
|
||||
|
||||
override fun matches(pokemon: Pokemon) = pokemon.getFeature<IntSpeciesFeature>(name)?.value == value
|
||||
}
|
||||
|
||||
class IntSpeciesFeatureProvider : SynchronizedSpeciesFeatureProvider<IntSpeciesFeature>, CustomPokemonPropertyType<IntSpeciesFeature> {
|
||||
class DisplayData : Encodable, Decodable {
|
||||
var name: String = ""
|
||||
@SerializedName(value = "colour" /* fuck you we use real english */, alternate = ["color"])
|
||||
var colour = Vec3d(255.0, 255.0, 255.0)
|
||||
var underlay: Identifier? = null
|
||||
var overlay: Identifier? = null
|
||||
|
||||
override fun decode(buffer: PacketByteBuf) {
|
||||
name = buffer.readString()
|
||||
colour = Vec3d(buffer.readDouble(), buffer.readDouble(), buffer.readDouble())
|
||||
underlay = buffer.readNullable { buffer.readIdentifier() }
|
||||
overlay = buffer.readNullable { buffer.readIdentifier() }
|
||||
}
|
||||
|
||||
override fun encode(buffer: PacketByteBuf) {
|
||||
buffer.writeString(name)
|
||||
buffer.writeDouble(colour.x)
|
||||
buffer.writeDouble(colour.y)
|
||||
buffer.writeDouble(colour.z)
|
||||
buffer.writeNullable(underlay) { _, value -> buffer.writeIdentifier(value) }
|
||||
buffer.writeNullable(overlay) { _, value -> buffer.writeIdentifier(value) }
|
||||
}
|
||||
}
|
||||
|
||||
override var keys = listOf<String>()
|
||||
// Uses get() = true because that way there's no backing field. It MUST be true, this way no JSON trickery will overwrite it
|
||||
override val needsKey get() = true
|
||||
override var visible = false
|
||||
var default: Int? = null
|
||||
var min = 0
|
||||
var max = 100
|
||||
var display: DisplayData? = null
|
||||
|
||||
override fun fromString(value: String?) = value?.toIntOrNull()?.takeIf { it in min..max }?.let { IntSpeciesFeature(keys.first(), it) }
|
||||
|
||||
override fun examples() = emptyList<String>()
|
||||
override fun invoke(buffer: PacketByteBuf, name: String): IntSpeciesFeature? {
|
||||
return if (name in keys) {
|
||||
IntSpeciesFeature(name, buffer.readInt())
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
override fun invoke(pokemon: Pokemon): IntSpeciesFeature? {
|
||||
return get(pokemon) ?: default?.let { IntSpeciesFeature(keys.first(), it) }
|
||||
}
|
||||
|
||||
override fun invoke(nbt: NbtCompound): IntSpeciesFeature? {
|
||||
return if (nbt.contains(keys.first())) {
|
||||
IntSpeciesFeature(keys.first(), nbt.getInt(keys.first()))
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
override fun invoke(json: JsonObject): IntSpeciesFeature? {
|
||||
return if (json.has(keys.first())) {
|
||||
IntSpeciesFeature(keys.first(), json.get(keys.first()).asInt)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
override fun get(pokemon: Pokemon) = pokemon.features.filterIsInstance<IntSpeciesFeature>().find { it.name in keys }
|
||||
|
||||
override fun encode(buffer: PacketByteBuf) {
|
||||
buffer.writeCollection(keys) { _, value -> buffer.writeString(value) }
|
||||
buffer.writeNullable(default) { _, value -> buffer.writeInt(value) }
|
||||
buffer.writeInt(min)
|
||||
buffer.writeInt(max)
|
||||
buffer.writeNullable(display) { _, value -> value.encode(buffer) }
|
||||
}
|
||||
|
||||
override fun decode(buffer: PacketByteBuf) {
|
||||
keys = buffer.readList { buffer.readString() }
|
||||
default = buffer.readNullable { buffer.readInt() }
|
||||
min = buffer.readInt()
|
||||
max = buffer.readInt()
|
||||
display = buffer.readNullable { DisplayData().also { it.decode(buffer) } }
|
||||
}
|
||||
|
||||
override fun getRenderer(pokemon: Pokemon): SummarySpeciesFeatureRenderer<IntSpeciesFeature>? {
|
||||
return display?.let {
|
||||
BarSummarySpeciesFeatureRenderer(
|
||||
name = keys.first(),
|
||||
displayName = it.name.asTranslated(),
|
||||
min = min,
|
||||
max = max,
|
||||
colour = it.colour,
|
||||
underlay = it.underlay ?: cobblemonResource("textures/gui/summary/summary_stats_other_bar.png"),
|
||||
overlay = it.overlay ?: cobblemonResource("textures/gui/summary/summary_stats_generic_overlay.png"),
|
||||
pokemon = pokemon
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
-4
@@ -8,10 +8,13 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.feature
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.net.messages.client.data.SpeciesFeatureAssignmentSyncPacket
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
@@ -38,17 +41,24 @@ object SpeciesFeatureAssignments : JsonDataRegistry<SpeciesFeatureAssignment> {
|
||||
override val typeToken = TypeToken.get(SpeciesFeatureAssignment::class.java)
|
||||
override val resourcePath = "species_feature_assignments"
|
||||
|
||||
private val assignments = mutableMapOf<String, MutableSet<String>>()
|
||||
private val assignments = mutableMapOf<Identifier, MutableSet<String>>()
|
||||
|
||||
override fun sync(player: ServerPlayerEntity) {}
|
||||
override fun sync(player: ServerPlayerEntity) {
|
||||
player.sendPacket(SpeciesFeatureAssignmentSyncPacket(assignments))
|
||||
}
|
||||
override fun reload(data: Map<Identifier, SpeciesFeatureAssignment>) {
|
||||
data.values.forEach {
|
||||
it.pokemon.forEach { pokemon ->
|
||||
assignments.getOrPut(pokemon) { mutableSetOf() }.addAll(it.features)
|
||||
assignments.getOrPut(pokemon.asIdentifierDefaultingNamespace()) { mutableSetOf() }.addAll(it.features)
|
||||
}
|
||||
}
|
||||
this.observable.emit(this)
|
||||
}
|
||||
|
||||
fun getFeatures(species: Species) = assignments[species.showdownId()] ?: emptySet()
|
||||
fun loadOnClient(data: Map<Identifier, MutableSet<String>>) {
|
||||
this.assignments.clear()
|
||||
this.assignments.putAll(data)
|
||||
}
|
||||
|
||||
fun getFeatures(species: Species) = assignments[species.resourceIdentifier] ?: emptySet()
|
||||
}
|
||||
+1
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.api.pokemon.feature
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.google.gson.JsonObject
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
|
||||
/**
|
||||
* A provider of [SpeciesFeature]s. These must be registered via [SpeciesFeatures] either programmatically or
|
||||
|
||||
+13
-1
@@ -8,13 +8,17 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.feature
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.pokemon.aspect.AspectProvider
|
||||
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
|
||||
import com.cobblemon.mod.common.api.properties.CustomPokemonPropertyType
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.net.messages.client.data.StandardSpeciesFeatureSyncPacket
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.SpeciesFeatureProviderAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.Vec3dAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
@@ -22,6 +26,7 @@ import com.google.gson.reflect.TypeToken
|
||||
import net.minecraft.resource.ResourceType
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.Vec3d
|
||||
|
||||
/**
|
||||
* A registry for [SpeciesFeatureProvider]s. This is the backbone of species-specific data such as
|
||||
@@ -48,11 +53,15 @@ object SpeciesFeatures : JsonDataRegistry<SpeciesFeatureProvider<*>> {
|
||||
override val gson: Gson = GsonBuilder()
|
||||
.setPrettyPrinting()
|
||||
.registerTypeAdapter(SpeciesFeatureProvider::class.java, SpeciesFeatureProviderAdapter)
|
||||
.registerTypeAdapter(Vec3d::class.java, Vec3dAdapter)
|
||||
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
|
||||
.create()
|
||||
override val typeToken: TypeToken<SpeciesFeatureProvider<*>> = TypeToken.get(SpeciesFeatureProvider::class.java)
|
||||
override val resourcePath: String = "species_features"
|
||||
|
||||
override fun sync(player: ServerPlayerEntity) {}
|
||||
override fun sync(player: ServerPlayerEntity) {
|
||||
player.sendPacket(StandardSpeciesFeatureSyncPacket(codeFeatures + resourceFeatures))
|
||||
}
|
||||
|
||||
override fun reload(data: Map<Identifier, SpeciesFeatureProvider<*>>) {
|
||||
resourceFeatures.keys.toList().forEach(this::unregister)
|
||||
@@ -62,6 +71,9 @@ object SpeciesFeatures : JsonDataRegistry<SpeciesFeatureProvider<*>> {
|
||||
fun getCodeFeature(name: String) = resourceFeatures[name]
|
||||
fun getResourceFeature(name: String) = codeFeatures[name]
|
||||
fun getFeature(name: String) = getCodeFeature(name) ?: getResourceFeature(name)
|
||||
fun loadOnClient(entries: Collection<Map.Entry<String, SpeciesFeatureProvider<*>>>) {
|
||||
codeFeatures.putAll(entries.map { it.toPair() })
|
||||
}
|
||||
|
||||
fun getFeatures() = (resourceFeatures.keys + codeFeatures.keys).mapNotNull(this::getFeature)
|
||||
fun getFeaturesFor(species: Species): List<SpeciesFeatureProvider<*>> {
|
||||
|
||||
+10
-1
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.google.gson.JsonObject
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
|
||||
/**
|
||||
* A species feature value that is a string value.
|
||||
@@ -22,7 +23,7 @@ import net.minecraft.nbt.NbtCompound
|
||||
class StringSpeciesFeature(
|
||||
override val name: String,
|
||||
var value: String
|
||||
) : SpeciesFeature, CustomPokemonProperty {
|
||||
) : SynchronizedSpeciesFeature, CustomPokemonProperty {
|
||||
override fun saveToNBT(pokemonNBT: NbtCompound): NbtCompound {
|
||||
pokemonNBT.putString(name, value)
|
||||
return pokemonNBT
|
||||
@@ -43,6 +44,14 @@ class StringSpeciesFeature(
|
||||
return this
|
||||
}
|
||||
|
||||
override fun encode(buffer: PacketByteBuf) {
|
||||
buffer.writeString(value)
|
||||
}
|
||||
|
||||
override fun decode(buffer: PacketByteBuf) {
|
||||
value = buffer.readString()
|
||||
}
|
||||
|
||||
override fun asString() = "$name=$value"
|
||||
|
||||
override fun apply(pokemon: Pokemon) {
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.feature
|
||||
|
||||
import com.cobblemon.mod.common.api.net.Decodable
|
||||
import com.cobblemon.mod.common.api.net.Encodable
|
||||
|
||||
/**
|
||||
* A species feature that can be synchronized to the client. These must be managed by a [SynchronizedSpeciesFeatureProvider].
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since November 13th, 2023
|
||||
*/
|
||||
interface SynchronizedSpeciesFeature : SpeciesFeature, Encodable, Decodable
|
||||
+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.api.pokemon.feature
|
||||
|
||||
import com.cobblemon.mod.common.api.net.Decodable
|
||||
import com.cobblemon.mod.common.api.net.Encodable
|
||||
import com.cobblemon.mod.common.client.gui.summary.featurerenderers.SummarySpeciesFeatureRenderer
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
|
||||
/**
|
||||
* A species feature provider that will be synchronized to the client. For it to be renderable in the summary
|
||||
* screen of a Pokémon it must also provide a [SummarySpeciesFeatureRenderer] in [getRenderer]. Note that you
|
||||
* really don't want to initialize a renderer outside of that function call because if the server ever initializes
|
||||
* it then you're going to get crashes on dedicated servers (this is a bad thing).
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since November 13th, 2023
|
||||
*/
|
||||
interface SynchronizedSpeciesFeatureProvider<T : SynchronizedSpeciesFeature> : SpeciesFeatureProvider<T>, Encodable, Decodable {
|
||||
var visible: Boolean
|
||||
operator fun invoke(buffer: PacketByteBuf, name: String): T?
|
||||
/** Gets the feature from this Pokémon, if it has been created yet. */
|
||||
fun get(pokemon: Pokemon): T?
|
||||
/** Only run this from the client. */
|
||||
fun getRenderer(pokemon: Pokemon): SummarySpeciesFeatureRenderer<T>?
|
||||
}
|
||||
@@ -49,6 +49,25 @@ enum class Stats(override val identifier: Identifier, override val displayName:
|
||||
*/
|
||||
val BATTLE_ONLY: Set<Stat> = EnumSet.of(EVASION, ACCURACY)
|
||||
|
||||
/** Gets the [Stat] from the respective Showdown id. */
|
||||
fun getStat(statKey: String) = when(statKey) {
|
||||
"atk" -> ATTACK
|
||||
"def" -> DEFENCE
|
||||
"spa" -> SPECIAL_ATTACK
|
||||
"spd" -> SPECIAL_DEFENCE
|
||||
"spe" -> SPEED
|
||||
"evasion" -> EVASION
|
||||
else -> ACCURACY
|
||||
}
|
||||
|
||||
/** Gets the severity lang key from the respective boost/unboost stage. */
|
||||
fun getSeverity(stages: Int) = when(stages) {
|
||||
0 -> "cap.single"
|
||||
1 -> "slight"
|
||||
2 -> "sharp"
|
||||
else -> "severe"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,7 +20,6 @@ import com.mojang.serialization.codecs.PrimitiveCodec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.Vec3d
|
||||
|
||||
/**
|
||||
* Effect details for the actual particles of a particle effect.
|
||||
@@ -29,7 +28,7 @@ import net.minecraft.util.math.Vec3d
|
||||
* @since January 4th, 2023
|
||||
*/
|
||||
class BedrockParticle(
|
||||
var texture: Identifier = Identifier("minecraft:textures/particle/bubble.png"),
|
||||
var texture: Identifier = Identifier("minecraft:textures/particles/bubble.png"),
|
||||
var material: ParticleMaterial = ParticleMaterial.ALPHA,
|
||||
var uvMode: ParticleUVMode = StaticParticleUVMode(),
|
||||
var sizeX: Expression = NumberExpression(0.15),
|
||||
@@ -44,48 +43,106 @@ class BedrockParticle(
|
||||
var cameraMode: ParticleCameraMode = RotateXYZCameraMode(),
|
||||
var tinting: ParticleTinting = ExpressionParticleTinting(),
|
||||
var collision: ParticleCollision = ParticleCollision(),
|
||||
var environmentLighting: Boolean = false
|
||||
var environmentLighting: Boolean = false,
|
||||
var creationEvents: MutableList<SimpleEventTrigger> = mutableListOf(),
|
||||
var expirationEvents: MutableList<SimpleEventTrigger> = mutableListOf(),
|
||||
var timeline: EventTriggerTimeline = EventTriggerTimeline(mutableMapOf())
|
||||
) {
|
||||
class ExpressionSet(
|
||||
val sizeX: Expression,
|
||||
val sizeY: Expression,
|
||||
val maxAge: Expression,
|
||||
val killExpression: Expression,
|
||||
val updateExpressions: MutableList<Expression>,
|
||||
val renderExpressions: MutableList<Expression>
|
||||
)
|
||||
|
||||
/*
|
||||
"creation_event": "event_sendspark",
|
||||
"expiration_event": ["event_spark", "event_afterspark", "event_capturestar"],
|
||||
"timeline": {
|
||||
"21.00": "event_spark"
|
||||
}
|
||||
*/
|
||||
|
||||
class EventSet(
|
||||
val creationEvents: MutableList<SimpleEventTrigger>,
|
||||
val expirationEvents: MutableList<SimpleEventTrigger>,
|
||||
val timeline: EventTriggerTimeline
|
||||
)
|
||||
|
||||
// kill plane maybe
|
||||
companion object {
|
||||
val CODEC: Codec<BedrockParticle> = RecordCodecBuilder.create { instance ->
|
||||
val EXPRESSION_SET_CODEC = RecordCodecBuilder.create<ExpressionSet> { instance ->
|
||||
instance.group(
|
||||
Identifier.CODEC.fieldOf("texture").forGetter { it.texture },
|
||||
PrimitiveCodec.STRING.fieldOf("material").forGetter { it.material.name },
|
||||
ParticleUVMode.codec.fieldOf("uvMode").forGetter { it.uvMode },
|
||||
EXPRESSION_CODEC.fieldOf("sizeX").forGetter { it.sizeX },
|
||||
EXPRESSION_CODEC.fieldOf("sizeY").forGetter { it.sizeY },
|
||||
EXPRESSION_CODEC.fieldOf("maxAge").forGetter { it.maxAge },
|
||||
EXPRESSION_CODEC.fieldOf("killExpression").forGetter { it.killExpression },
|
||||
ListCodec(EXPRESSION_CODEC).fieldOf("updateExpressions").forGetter { it.updateExpressions },
|
||||
ListCodec(EXPRESSION_CODEC).fieldOf("renderExpressions").forGetter { it.renderExpressions },
|
||||
ListCodec(EXPRESSION_CODEC).fieldOf("renderExpressions").forGetter { it.renderExpressions }
|
||||
).apply(instance, ::ExpressionSet)
|
||||
}
|
||||
|
||||
val EVENT_SET_CODEC = RecordCodecBuilder.create<EventSet> { instance ->
|
||||
instance.group(
|
||||
ListCodec(SimpleEventTrigger.CODEC).fieldOf("creationEvents").forGetter { it.creationEvents },
|
||||
ListCodec(SimpleEventTrigger.CODEC).fieldOf("expirationEvents").forGetter { it.expirationEvents },
|
||||
EventTriggerTimeline.CODEC.fieldOf("timeline").forGetter { it.timeline }
|
||||
).apply(instance, ::EventSet)
|
||||
}
|
||||
|
||||
val CODEC: Codec<BedrockParticle> = RecordCodecBuilder.create { instance ->
|
||||
instance.group(
|
||||
Identifier.CODEC.fieldOf("texture").forGetter { it.texture },
|
||||
PrimitiveCodec.STRING.fieldOf("material").forGetter { it.material.name },
|
||||
ParticleUVMode.codec.fieldOf("uvMode").forGetter { it.uvMode },
|
||||
EXPRESSION_SET_CODEC.fieldOf("expressionSet").forGetter {
|
||||
ExpressionSet(
|
||||
it.sizeX,
|
||||
it.sizeY,
|
||||
it.maxAge,
|
||||
it.killExpression,
|
||||
it.updateExpressions,
|
||||
it.renderExpressions
|
||||
)
|
||||
},
|
||||
ParticleMotion.codec.fieldOf("motion").forGetter { it.motion },
|
||||
ParticleRotation.codec.fieldOf("rotation").forGetter { it.rotation },
|
||||
ParticleViewDirection.codec.fieldOf("viewDirection").forGetter { it.viewDirection },
|
||||
ParticleCameraMode.codec.fieldOf("cameraMode").forGetter { it.cameraMode },
|
||||
ParticleTinting.codec.fieldOf("tinting").forGetter { it.tinting },
|
||||
ParticleCollision.CODEC.fieldOf("collision").forGetter { it.collision },
|
||||
PrimitiveCodec.BOOL.fieldOf("environmentLighting").forGetter { it.environmentLighting }
|
||||
PrimitiveCodec.BOOL.fieldOf("environmentLighting").forGetter { it.environmentLighting },
|
||||
EVENT_SET_CODEC.fieldOf("eventSet").forGetter {
|
||||
EventSet(
|
||||
it.creationEvents,
|
||||
it.expirationEvents,
|
||||
it.timeline
|
||||
)
|
||||
}
|
||||
).apply(instance) {
|
||||
texture, materialStr, uvMode, sizeX, sizeY, maxAge, killExpression, updateExpressions,
|
||||
renderExpressions, motion, rotation, viewDirection, cameraMode, tinting, collision, environmentLighting ->
|
||||
texture, materialStr, uvMode, expressionSet, motion, rotation, viewDirection, cameraMode, tinting, collision, environmentLighting, eventSet ->
|
||||
BedrockParticle(
|
||||
texture = texture,
|
||||
material = ParticleMaterial.valueOf(materialStr),
|
||||
uvMode = uvMode,
|
||||
sizeX = sizeX,
|
||||
sizeY = sizeY,
|
||||
maxAge = maxAge,
|
||||
killExpression = killExpression,
|
||||
updateExpressions = updateExpressions,
|
||||
renderExpressions = renderExpressions,
|
||||
sizeX = expressionSet.sizeX,
|
||||
sizeY = expressionSet.sizeY,
|
||||
maxAge = expressionSet.maxAge,
|
||||
killExpression = expressionSet.killExpression,
|
||||
updateExpressions = expressionSet.updateExpressions,
|
||||
renderExpressions = expressionSet.renderExpressions,
|
||||
motion = motion,
|
||||
rotation = rotation,
|
||||
viewDirection = viewDirection,
|
||||
cameraMode = cameraMode,
|
||||
tinting = tinting,
|
||||
collision = collision,
|
||||
environmentLighting = environmentLighting
|
||||
environmentLighting = environmentLighting,
|
||||
creationEvents = eventSet.creationEvents,
|
||||
expirationEvents = eventSet.expirationEvents,
|
||||
timeline = eventSet.timeline
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -108,6 +165,9 @@ class BedrockParticle(
|
||||
ParticleTinting.writeToBuffer(buffer, tinting)
|
||||
collision.writeToBuffer(buffer)
|
||||
buffer.writeBoolean(environmentLighting)
|
||||
buffer.writeCollection(creationEvents) { pb, event -> event.encode(pb) }
|
||||
buffer.writeCollection(expirationEvents) { pb, event -> event.encode(pb) }
|
||||
timeline.encode(buffer)
|
||||
}
|
||||
|
||||
fun readFromBuffer(buffer: PacketByteBuf) {
|
||||
@@ -127,5 +187,8 @@ class BedrockParticle(
|
||||
tinting = ParticleTinting.readFromBuffer(buffer)
|
||||
collision.readFromBuffer(buffer)
|
||||
environmentLighting = buffer.readBoolean()
|
||||
creationEvents = buffer.readList { SimpleEventTrigger("").also { it.decode(buffer) } }
|
||||
expirationEvents = buffer.readList { SimpleEventTrigger("").also { it.decode(buffer) } }
|
||||
timeline.decode(buffer)
|
||||
}
|
||||
}
|
||||
+11
-4
@@ -10,7 +10,9 @@ package com.cobblemon.mod.common.api.snowstorm
|
||||
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.ListCodec
|
||||
import com.mojang.serialization.codecs.PrimitiveCodec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import com.mojang.serialization.codecs.UnboundedMapCodec
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
@@ -27,7 +29,8 @@ class BedrockParticleEffect(
|
||||
var emitter: BedrockParticleEmitter = BedrockParticleEmitter(),
|
||||
var particle: BedrockParticle = BedrockParticle(),
|
||||
var curves: MutableList<MoLangCurve> = mutableListOf(),
|
||||
var space: ParticleSpace = ParticleSpace()
|
||||
var space: ParticleSpace = ParticleSpace(),
|
||||
var events: MutableMap<String, ParticleEvent> = mutableMapOf()
|
||||
) {
|
||||
companion object {
|
||||
val CODEC: Codec<BedrockParticleEffect> = RecordCodecBuilder.create { instance ->
|
||||
@@ -36,14 +39,16 @@ class BedrockParticleEffect(
|
||||
BedrockParticleEmitter.CODEC.fieldOf("emitter").forGetter { it.emitter },
|
||||
BedrockParticle.CODEC.fieldOf("particle").forGetter { it.particle },
|
||||
ListCodec(MoLangCurve.codec).fieldOf("curves").forGetter { it.curves },
|
||||
ParticleSpace.CODEC.fieldOf("space").forGetter { it.space }
|
||||
).apply(instance) { id, emitter, particle, curves, space ->
|
||||
ParticleSpace.CODEC.fieldOf("space").forGetter { it.space },
|
||||
UnboundedMapCodec(PrimitiveCodec.STRING, ParticleEvent.CODEC).fieldOf("events").forGetter { it.events }
|
||||
).apply(instance) { id, emitter, particle, curves, space, events ->
|
||||
BedrockParticleEffect(
|
||||
id = id,
|
||||
emitter = emitter,
|
||||
particle = particle,
|
||||
curves = curves.toMutableList(),
|
||||
space = space
|
||||
space = space,
|
||||
events = events
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -55,6 +60,7 @@ class BedrockParticleEffect(
|
||||
particle.writeToBuffer(buffer)
|
||||
buffer.writeCollection(curves) { pb, curve -> MoLangCurve.writeToBuffer(buffer, curve) }
|
||||
space.writeToBuffer(buffer)
|
||||
buffer.writeMap(events, { _, v -> buffer.writeString(v) }) { _, event -> event.encode(buffer) }
|
||||
}
|
||||
|
||||
fun readFromBuffer(buffer: PacketByteBuf) {
|
||||
@@ -63,5 +69,6 @@ class BedrockParticleEffect(
|
||||
particle.readFromBuffer(buffer)
|
||||
curves = buffer.readList { MoLangCurve.readFromBuffer(buffer) }
|
||||
space.readFromBuffer(buffer)
|
||||
events = buffer.readMap({ buffer.readString() }) { ParticleEvent().also { it.decode(buffer) } }
|
||||
}
|
||||
}
|
||||
+29
-4
@@ -29,7 +29,12 @@ class BedrockParticleEmitter(
|
||||
var updateExpressions: MutableList<Expression> = mutableListOf(),
|
||||
var rate: ParticleEmitterRate = InstantParticleEmitterRate(),
|
||||
var shape: ParticleEmitterShape = SphereParticleEmitterShape(),
|
||||
var lifetime: ParticleEmitterLifetime = OnceEmitterLifetime(NumberExpression(1.0))
|
||||
var lifetime: ParticleEmitterLifetime = OnceEmitterLifetime(NumberExpression(1.0)),
|
||||
var eventTimeline: EventTriggerTimeline = EventTriggerTimeline(mutableMapOf()),
|
||||
var creationEvents: MutableList<SimpleEventTrigger> = mutableListOf(),
|
||||
var expirationEvents: MutableList<SimpleEventTrigger> = mutableListOf(),
|
||||
var travelDistanceEvents: EventTriggerTimeline = EventTriggerTimeline(mutableMapOf()),
|
||||
var loopingTravelDistanceEvents: MutableList<LoopingTravelDistanceEventTrigger> = mutableListOf()
|
||||
) {
|
||||
companion object {
|
||||
val CODEC: Codec<BedrockParticleEmitter> = RecordCodecBuilder.create { instance ->
|
||||
@@ -38,14 +43,24 @@ class BedrockParticleEmitter(
|
||||
ListCodec(EXPRESSION_CODEC).fieldOf("updateExpressions").forGetter { it.updateExpressions },
|
||||
ParticleEmitterRate.codec.fieldOf("rate").forGetter { it.rate },
|
||||
ParticleEmitterShape.codec.fieldOf("shape").forGetter { it.shape },
|
||||
ParticleEmitterLifetime.codec.fieldOf("lifetime").forGetter { it.lifetime }
|
||||
).apply(instance) { startExpressions, updateExpressions, rate, shape, lifetime ->
|
||||
ParticleEmitterLifetime.codec.fieldOf("lifetime").forGetter { it.lifetime },
|
||||
EventTriggerTimeline.CODEC.fieldOf("eventTimeline").forGetter { it.eventTimeline },
|
||||
ListCodec(SimpleEventTrigger.CODEC).fieldOf("creationEvents").forGetter { it.creationEvents },
|
||||
ListCodec(SimpleEventTrigger.CODEC).fieldOf("expirationEvents").forGetter { it.expirationEvents },
|
||||
EventTriggerTimeline.CODEC.fieldOf("travelDistanceEvents").forGetter { it.travelDistanceEvents },
|
||||
ListCodec(LoopingTravelDistanceEventTrigger.CODEC).fieldOf("loopingTravelDistanceEvents").forGetter { it.loopingTravelDistanceEvents }
|
||||
).apply(instance) { startExpressions, updateExpressions, rate, shape, lifetime, eventTimeline, creationEvents, expirationEvents, travelDistanceEvents, loopingTravelDistanceEvents ->
|
||||
BedrockParticleEmitter(
|
||||
startExpressions = startExpressions,
|
||||
updateExpressions = updateExpressions,
|
||||
shape = shape,
|
||||
rate = rate,
|
||||
lifetime = lifetime
|
||||
lifetime = lifetime,
|
||||
eventTimeline = eventTimeline,
|
||||
creationEvents = creationEvents,
|
||||
expirationEvents = expirationEvents,
|
||||
travelDistanceEvents = travelDistanceEvents,
|
||||
loopingTravelDistanceEvents = loopingTravelDistanceEvents
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -57,6 +72,11 @@ class BedrockParticleEmitter(
|
||||
ParticleEmitterRate.writeToBuffer(buffer, rate)
|
||||
ParticleEmitterShape.writeToBuffer(buffer, shape)
|
||||
ParticleEmitterLifetime.writeToBuffer(buffer, lifetime)
|
||||
eventTimeline.encode(buffer)
|
||||
buffer.writeCollection(creationEvents) { pb, event -> event.encode(pb) }
|
||||
buffer.writeCollection(expirationEvents) { pb, event -> event.encode(pb) }
|
||||
travelDistanceEvents.encode(buffer)
|
||||
buffer.writeCollection(loopingTravelDistanceEvents) { pb, event -> event.encode(pb) }
|
||||
}
|
||||
|
||||
fun readFromBuffer(buffer: PacketByteBuf) {
|
||||
@@ -65,5 +85,10 @@ class BedrockParticleEmitter(
|
||||
rate = ParticleEmitterRate.readFromBuffer(buffer)
|
||||
shape = ParticleEmitterShape.readFromBuffer(buffer)
|
||||
lifetime = ParticleEmitterLifetime.readFromBuffer(buffer)
|
||||
eventTimeline.decode(buffer)
|
||||
creationEvents = buffer.readList { SimpleEventTrigger("").also { it.decode(buffer) } }
|
||||
expirationEvents = buffer.readList { SimpleEventTrigger("").also { it.decode(buffer) } }
|
||||
travelDistanceEvents.decode(buffer)
|
||||
loopingTravelDistanceEvents = buffer.readList { LoopingTravelDistanceEventTrigger(0.0, mutableListOf()).also { it.decode(buffer) } }
|
||||
}
|
||||
}
|
||||
+5
@@ -136,6 +136,11 @@ class LoopingEmitterLifetime(var activeTime: Expression = 1.0.asExpression(), va
|
||||
val interval = activeTimeValue + sleepTime
|
||||
val displacement = emitterAge % interval
|
||||
runtime.environment.setSimpleVariable("emitter_lifetime", activeTime)
|
||||
|
||||
if (emitterAge > activeTimeValue && sleepTime == 0.0) {
|
||||
return ParticleEmitterAction.STOP
|
||||
}
|
||||
|
||||
return if (displacement < activeTimeValue) {
|
||||
ParticleEmitterAction.GO
|
||||
} else {
|
||||
|
||||
+1
-1
@@ -145,7 +145,7 @@ class PointParticleEmitterShape(
|
||||
override val type = ParticleEmitterShapeType.POINT
|
||||
override fun getNewParticlePosition(runtime: MoLangRuntime, entity: Entity?) = runtime.resolveVec3d(offset)
|
||||
override fun getCenter(runtime: MoLangRuntime, entity: Entity?): Vec3d {
|
||||
return getNewParticlePosition(runtime, entity) // Questionable
|
||||
return Vec3d.ZERO
|
||||
}
|
||||
|
||||
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.snowstorm
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.net.Decodable
|
||||
import com.cobblemon.mod.common.api.net.Encodable
|
||||
import com.cobblemon.mod.common.client.particle.BedrockParticleEffectRepository
|
||||
import com.cobblemon.mod.common.client.particle.ParticleStorm
|
||||
import com.cobblemon.mod.common.client.render.MatrixWrapper
|
||||
import com.cobblemon.mod.common.client.render.SnowstormParticle
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.PrimitiveCodec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.sound.SoundCategory
|
||||
import net.minecraft.sound.SoundEvent
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.Vec3d
|
||||
|
||||
/**
|
||||
* An event that can be referenced from various particle event triggers. The events are not necessarily particles,
|
||||
* but can be combinations of particles, sounds, and MoLang expressions.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since March 2nd, 2024
|
||||
*/
|
||||
class ParticleEvent(
|
||||
var particleEffect: EventParticleEffect? = null,
|
||||
var soundEffect: EventSoundEffect? = null,
|
||||
var expression: ExpressionLike? = null
|
||||
): Encodable, Decodable {
|
||||
companion object {
|
||||
val CODEC: Codec<ParticleEvent> = RecordCodecBuilder.create { instance ->
|
||||
instance.group(
|
||||
EventParticleEffect.CODEC.optionalFieldOf("particle_effect", null).forGetter { it.particleEffect },
|
||||
EventSoundEffect.CODEC.optionalFieldOf("sound_effect", null).forGetter { it.soundEffect },
|
||||
PrimitiveCodec.STRING.optionalFieldOf("expression", null).forGetter { it.expression?.toString() }
|
||||
).apply(instance) { particleEffect, soundEffect, expression ->
|
||||
ParticleEvent(
|
||||
particleEffect,
|
||||
soundEffect,
|
||||
expression?.asExpressionLike()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun encode(buffer: PacketByteBuf) {
|
||||
buffer.writeNullable(particleEffect) { pb, effect ->
|
||||
pb.writeIdentifier(effect.effect)
|
||||
pb.writeEnumConstant(effect.type)
|
||||
pb.writeNullable(effect.expression) { pb, expr -> pb.writeString(expr.toString()) }
|
||||
}
|
||||
buffer.writeNullable(soundEffect) { pb, effect -> pb.writeIdentifier(effect.sound) }
|
||||
buffer.writeNullable(expression) { pb, expr -> pb.writeString(expr.toString()) }
|
||||
}
|
||||
override fun decode(buffer: PacketByteBuf) {
|
||||
particleEffect = buffer.readNullable { pb -> EventParticleEffect(
|
||||
pb.readIdentifier(),
|
||||
pb.readEnumConstant(EventParticleEffect.EventParticleType::class.java),
|
||||
pb.readNullable { pb.readString().asExpressionLike() }
|
||||
) }
|
||||
soundEffect = buffer.readNullable { pb -> EventSoundEffect(pb.readIdentifier()) }
|
||||
expression = buffer.readNullable { pb -> pb.readString().asExpressionLike() }
|
||||
}
|
||||
|
||||
fun run(storm: ParticleStorm, particle: SnowstormParticle?) {
|
||||
particleEffect?.let { effect ->
|
||||
val bedrockParticleEffect = BedrockParticleEffectRepository.getEffect(effect.effect) ?: return@let
|
||||
val rootMatrix = when (effect.type) {
|
||||
EventParticleEffect.EventParticleType.EMITTER -> MatrixWrapper().updatePosition(storm.matrixWrapper.getOrigin())
|
||||
EventParticleEffect.EventParticleType.EMITTER_BOUND -> storm.matrixWrapper
|
||||
EventParticleEffect.EventParticleType.PARTICLE,
|
||||
EventParticleEffect.EventParticleType.PARTICLE_WITH_VELOCITY -> (particle?.let { Vec3d(it.getX(), it.getY(), it.getZ()) } ?: Vec3d(storm.getX(), storm.getY(), storm.getZ())).let { MatrixWrapper().updatePosition(it) }
|
||||
}
|
||||
|
||||
val sourceVelocity = when (effect.type) {
|
||||
EventParticleEffect.EventParticleType.EMITTER -> storm.sourceVelocity().let { { it } }
|
||||
EventParticleEffect.EventParticleType.EMITTER_BOUND -> storm.sourceVelocity
|
||||
EventParticleEffect.EventParticleType.PARTICLE -> { { Vec3d.ZERO } }
|
||||
EventParticleEffect.EventParticleType.PARTICLE_WITH_VELOCITY -> (particle?.let { Vec3d(it.getVelocityX(), it.getVelocityY(), it.getVelocityZ()) } ?: Vec3d.ZERO).let { { it } }
|
||||
}
|
||||
|
||||
val newStorm = ParticleStorm(
|
||||
effect = bedrockParticleEffect,
|
||||
matrixWrapper = rootMatrix,
|
||||
world = storm.world,
|
||||
sourceVelocity = sourceVelocity,
|
||||
sourceAlive = storm.sourceAlive,
|
||||
sourceVisible = storm.sourceVisible,
|
||||
onDespawn = {},
|
||||
runtime = MoLangRuntime().setup().also { it.environment.structs["query"] = storm.runtime.environment.getQueryStruct() },
|
||||
entity = storm.entity
|
||||
)
|
||||
|
||||
effect.expression?.resolve(newStorm.runtime)
|
||||
|
||||
newStorm.spawn()
|
||||
}
|
||||
soundEffect?.let { effect ->
|
||||
val position = particle?.let { Vec3d(it.getX(), it.getY(), it.getZ()) } ?: Vec3d(storm.getX(), storm.getY(), storm.getZ())
|
||||
val world = storm.world
|
||||
val soundEvent = SoundEvent.of(effect.sound)
|
||||
world.playSound(position.x, position.y, position.z, soundEvent, SoundCategory.NEUTRAL, 1F, 1F, true)
|
||||
}
|
||||
expression?.resolve(storm.runtime)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A particle component of a [ParticleEvent]. It contains the effect to play, the spawning type, and a pre-run
|
||||
* expression to run in the new storm's runtime.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since March 2nd, 2024
|
||||
*/
|
||||
class EventParticleEffect(
|
||||
val effect: Identifier,
|
||||
val type: EventParticleType,
|
||||
val expression: ExpressionLike? = null
|
||||
) {
|
||||
companion object {
|
||||
val CODEC = RecordCodecBuilder.create<EventParticleEffect> { instance ->
|
||||
instance.group(
|
||||
Identifier.CODEC.fieldOf("effect").forGetter { it.effect },
|
||||
PrimitiveCodec.STRING.fieldOf("type").forGetter { it.type.name },
|
||||
PrimitiveCodec.STRING.optionalFieldOf("expression", null).forGetter { it.expression?.toString() }
|
||||
).apply(instance) { effect, type, expression ->
|
||||
EventParticleEffect(
|
||||
effect,
|
||||
EventParticleType.valueOf(type),
|
||||
expression?.asExpressionLike()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class EventParticleType {
|
||||
EMITTER,
|
||||
EMITTER_BOUND,
|
||||
PARTICLE,
|
||||
PARTICLE_WITH_VELOCITY
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple sound effect component of a [ParticleEvent]. Plays a sound at the particle location, or if run from an
|
||||
* emitter event, at the emitter's location.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since March 2nd, 2024
|
||||
*/
|
||||
class EventSoundEffect(
|
||||
val sound: Identifier,
|
||||
) {
|
||||
companion object {
|
||||
val CODEC = RecordCodecBuilder.create<EventSoundEffect> { instance ->
|
||||
instance.group(
|
||||
Identifier.CODEC.fieldOf("sound").forGetter { it.sound }
|
||||
).apply(instance, ::EventSoundEffect)
|
||||
}
|
||||
}
|
||||
}
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.snowstorm
|
||||
|
||||
import com.cobblemon.mod.common.api.net.Decodable
|
||||
import com.cobblemon.mod.common.api.net.Encodable
|
||||
import com.cobblemon.mod.common.client.particle.ParticleStorm
|
||||
import com.cobblemon.mod.common.client.render.SnowstormParticle
|
||||
import com.mojang.serialization.codecs.PrimitiveCodec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import com.mojang.serialization.codecs.UnboundedMapCodec
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
|
||||
/*
|
||||
* The different references to events that can be triggered by an effect.
|
||||
*/
|
||||
|
||||
/**
|
||||
* It really is simple.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since March 2nd, 2024
|
||||
*/
|
||||
class SimpleEventTrigger(var event: String): Encodable, Decodable {
|
||||
companion object {
|
||||
val CODEC = RecordCodecBuilder.create<SimpleEventTrigger> { instance ->
|
||||
instance.group(
|
||||
PrimitiveCodec.STRING.fieldOf("event").forGetter { it.event }
|
||||
).apply(instance, ::SimpleEventTrigger)
|
||||
}
|
||||
}
|
||||
|
||||
override fun encode(buffer: PacketByteBuf) {
|
||||
buffer.writeString(event)
|
||||
}
|
||||
|
||||
override fun decode(buffer: PacketByteBuf) {
|
||||
event = buffer.readString()
|
||||
}
|
||||
|
||||
fun trigger(storm: ParticleStorm, particle: SnowstormParticle?) {
|
||||
val event = storm.effect.events[event] ?: return
|
||||
event.run(storm, particle)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An event trigger that outlines specific times at which point groups of effects will play. This can be used
|
||||
* on the basis of time but is also used in the case of travel distance.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since March 2nd, 2024
|
||||
*/
|
||||
class EventTriggerTimeline(var map: MutableMap<Double, MutableList<String>>): Encodable, Decodable {
|
||||
companion object {
|
||||
val CODEC = RecordCodecBuilder.create<EventTriggerTimeline> { instance ->
|
||||
instance.group(
|
||||
UnboundedMapCodec(PrimitiveCodec.DOUBLE, PrimitiveCodec.STRING.listOf()).fieldOf("map").forGetter { it.map }
|
||||
).apply(instance, ::EventTriggerTimeline)
|
||||
}
|
||||
}
|
||||
|
||||
override fun encode(buffer: PacketByteBuf) {
|
||||
buffer.writeMap(map, { pb, k -> pb.writeDouble(k) }, { pb, v -> pb.writeCollection(v) { _, s -> pb.writeString(s) } })
|
||||
}
|
||||
|
||||
override fun decode(buffer: PacketByteBuf) {
|
||||
map = buffer.readMap({ pb -> pb.readDouble() }, { pb -> pb.readList { pb.readString() } })
|
||||
}
|
||||
|
||||
fun check(storm: ParticleStorm, particle: SnowstormParticle?, previousTime: Double, newTime: Double) {
|
||||
val events = map.entries.filter { it.key in previousTime..newTime }.flatMap { it.value }
|
||||
events.forEach { event ->
|
||||
val event = storm.effect.events[event] ?: return
|
||||
event.run(storm, particle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An event trigger that takes the total distance travelled by the emitter and modulos it across [distance] to know
|
||||
* if we need to play it again.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since March 2nd, 2024
|
||||
*/
|
||||
class LoopingTravelDistanceEventTrigger(var distance: Double, var events: MutableList<String>): Encodable, Decodable {
|
||||
companion object {
|
||||
val CODEC = RecordCodecBuilder.create<LoopingTravelDistanceEventTrigger> { instance ->
|
||||
instance.group(
|
||||
PrimitiveCodec.DOUBLE.fieldOf("distance").forGetter { it.distance },
|
||||
PrimitiveCodec.STRING.listOf().fieldOf("events").forGetter { it.events }
|
||||
).apply(instance, ::LoopingTravelDistanceEventTrigger)
|
||||
}
|
||||
}
|
||||
|
||||
override fun encode(buffer: PacketByteBuf) {
|
||||
buffer.writeDouble(distance)
|
||||
buffer.writeCollection(events) { _, s -> buffer.writeString(s) }
|
||||
}
|
||||
|
||||
override fun decode(buffer: PacketByteBuf) {
|
||||
distance = buffer.readDouble()
|
||||
events = buffer.readList { buffer.readString() }
|
||||
}
|
||||
|
||||
fun check(storm: ParticleStorm, particle: SnowstormParticle?, previousDistance: Double, currentDistance: Double) {
|
||||
if (previousDistance < distance && currentDistance >= distance) {
|
||||
events.mapNotNull { storm.effect.events[it] }.forEach { it.run(storm, particle) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -140,7 +140,7 @@ class InwardsMotionDirection : ParticleMotionDirection {
|
||||
return if (particlePos == emitterPos) {
|
||||
Vec3d(storm.world.random.nextDouble() - 0.5, storm.world.random.nextDouble() - 0.5, storm.world.random.nextDouble() - 0.5)
|
||||
} else {
|
||||
particlePos.subtract(emitterPos)
|
||||
emitterPos.subtract(particlePos)
|
||||
}.normalize()
|
||||
}
|
||||
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
||||
|
||||
@@ -10,8 +10,19 @@ package com.cobblemon.mod.common.api.spawning
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.api.entity.Despawner
|
||||
import com.cobblemon.mod.common.api.spawning.condition.*
|
||||
import com.cobblemon.mod.common.api.spawning.context.*
|
||||
import com.cobblemon.mod.common.api.spawning.condition.AreaSpawningCondition
|
||||
import com.cobblemon.mod.common.api.spawning.condition.BasicSpawningCondition
|
||||
import com.cobblemon.mod.common.api.spawning.condition.GroundedSpawningCondition
|
||||
import com.cobblemon.mod.common.api.spawning.condition.SpawningCondition
|
||||
import com.cobblemon.mod.common.api.spawning.condition.SubmergedSpawningCondition
|
||||
import com.cobblemon.mod.common.api.spawning.condition.SurfaceSpawningCondition
|
||||
import com.cobblemon.mod.common.api.spawning.context.AreaContextResolver
|
||||
import com.cobblemon.mod.common.api.spawning.context.GroundedSpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.context.LavafloorSpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.context.SeafloorSpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.context.SubmergedSpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.context.SurfaceSpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.context.calculators.GroundedSpawningContextCalculator
|
||||
import com.cobblemon.mod.common.api.spawning.context.calculators.LavafloorSpawningContextCalculator
|
||||
import com.cobblemon.mod.common.api.spawning.context.calculators.SeafloorSpawningContextCalculator
|
||||
@@ -21,8 +32,6 @@ import com.cobblemon.mod.common.api.spawning.context.calculators.SurfaceSpawning
|
||||
import com.cobblemon.mod.common.api.spawning.detail.PokemonSpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.fallingstar.FallingStarSpawner
|
||||
import com.cobblemon.mod.common.api.spawning.fishing.FishingSpawner
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.preset.BasicSpawnDetailPreset
|
||||
import com.cobblemon.mod.common.api.spawning.preset.BestSpawnerConfig
|
||||
@@ -74,8 +83,6 @@ object BestSpawner {
|
||||
var config = BestSpawnerConfig()
|
||||
val spawnerManagers = mutableListOf<SpawnerManager>(CobblemonWorldSpawnerManager)
|
||||
var defaultPokemonDespawner: Despawner<PokemonEntity> = CobblemonAgingDespawner(getAgeTicks = { it.ticksLived })
|
||||
lateinit var fishingSpawner: FishingSpawner
|
||||
lateinit var starSpawner: FallingStarSpawner
|
||||
|
||||
fun loadConfig() {
|
||||
LOGGER.info("Starting the Best Spawner...")
|
||||
@@ -84,8 +91,6 @@ object BestSpawner {
|
||||
SpawningCondition.register(SubmergedSpawningCondition.NAME, SubmergedSpawningCondition::class.java)
|
||||
SpawningCondition.register(GroundedSpawningCondition.NAME, GroundedSpawningCondition::class.java)
|
||||
SpawningCondition.register(SurfaceSpawningCondition.NAME, SurfaceSpawningCondition::class.java)
|
||||
SpawningCondition.register(FishingSpawningCondition.NAME, FishingSpawningCondition::class.java)
|
||||
SpawningCondition.register(FallingStarSpawningCondition.NAME, FallingStarSpawningCondition::class.java)
|
||||
|
||||
LOGGER.info("Loaded ${SpawningCondition.conditionTypes.size} spawning condition types.")
|
||||
SpawningContextCalculator.register(GroundedSpawningContextCalculator)
|
||||
@@ -99,8 +104,6 @@ object BestSpawner {
|
||||
SpawningContext.register(name = "lavafloor", clazz = LavafloorSpawningContext::class.java, defaultCondition = GroundedSpawningCondition.NAME)
|
||||
SpawningContext.register(name = "submerged", clazz = SubmergedSpawningContext::class.java, defaultCondition = SubmergedSpawningCondition.NAME)
|
||||
SpawningContext.register(name = "surface", clazz = SurfaceSpawningContext::class.java, defaultCondition = SurfaceSpawningCondition.NAME)
|
||||
SpawningContext.register(name = "fishing", clazz = FishingSpawningContext::class.java, defaultCondition = FishingSpawningCondition.NAME)
|
||||
SpawningContext.register(name = "fallingstar", clazz = FallingStarSpawningContext::class.java, defaultCondition = FallingStarSpawningCondition.NAME)
|
||||
|
||||
LOGGER.info("Loaded ${SpawningContext.contexts.size} spawning context types.")
|
||||
|
||||
@@ -115,7 +118,5 @@ object BestSpawner {
|
||||
|
||||
fun onServerStarted() {
|
||||
spawnerManagers.forEach(SpawnerManager::onServerStarted)
|
||||
fishingSpawner = FishingSpawner()
|
||||
starSpawner = FallingStarSpawner()
|
||||
}
|
||||
}
|
||||
-23
@@ -1,23 +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.api.spawning.condition
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.context.FallingStarSpawningContext
|
||||
|
||||
class FallingStarSpawningCondition: SpawningCondition<FallingStarSpawningContext>() {
|
||||
override fun contextClass() = FallingStarSpawningContext::class.java
|
||||
|
||||
override fun fits(ctx: FallingStarSpawningContext): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val NAME = "fallingstar"
|
||||
}
|
||||
}
|
||||
-44
@@ -1,44 +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.api.spawning.condition
|
||||
|
||||
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
|
||||
import com.cobblemon.mod.common.api.spawning.context.FishingSpawningContext
|
||||
import com.cobblemon.mod.common.util.itemRegistry
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.item.Item
|
||||
|
||||
/**
|
||||
* A spawning condition that applies to [FishingSpawningContext]s.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since February 3rd, 2024
|
||||
*/
|
||||
class FishingSpawningCondition: SpawningCondition<FishingSpawningContext>() {
|
||||
override fun contextClass() = FishingSpawningContext::class.java
|
||||
|
||||
var rod: RegistryLikeCondition<Item>? = null
|
||||
var neededNearbyBlocks: MutableList<RegistryLikeCondition<Block>>? = null
|
||||
|
||||
override fun fits(ctx: FishingSpawningContext): Boolean {
|
||||
if (!super.fits(ctx)) {
|
||||
return false
|
||||
} else if (rod != null && !rod!!.fits(ctx.rodItem ?: return false, ctx.world.itemRegistry)) {
|
||||
return false
|
||||
} else if (neededNearbyBlocks != null && neededNearbyBlocks!!.none { cond -> ctx.nearbyBlockTypes.any { cond.fits(it, ctx.blockRegistry) } }) {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val NAME = "fishing"
|
||||
}
|
||||
}
|
||||
-47
@@ -76,51 +76,4 @@ interface AreaContextResolver {
|
||||
|
||||
return contexts
|
||||
}
|
||||
|
||||
// fun resolveFishing(
|
||||
// spawner: Spawner,
|
||||
// contextCalculators: List<AreaSpawningContextCalculator<*>>,
|
||||
// slice: WorldSlice
|
||||
// ): List<AreaSpawningContext> {
|
||||
// var pos = BlockPos.Mutable(1, 2, 3)
|
||||
// val input = AreaSpawningInput(spawner, pos, slice)
|
||||
// val contexts = mutableListOf<AreaSpawningContext>()
|
||||
//
|
||||
// var x = slice.baseX
|
||||
// var y = slice.baseY
|
||||
// var z = slice.baseZ
|
||||
//
|
||||
// while (x < slice.baseX + slice.length) {
|
||||
// while (y < slice.baseY + slice.height) {
|
||||
// while (z < slice.baseZ + slice.width) {
|
||||
// pos.set(x, y, z)
|
||||
// val vec = pos.toVec3d()
|
||||
// if (slice.nearbyEntityPositions.none { it.isInRange(vec, 50.0) && it != slice.cause.entity }) {
|
||||
// val fittedContextCalculator = contextCalculators
|
||||
// .firstOrNull { calc -> calc.fits(input) && input.spawner.influences.none { !it.isAllowedPosition(input.world, input.position, calc) } }
|
||||
// if (fittedContextCalculator != null) {
|
||||
// val context = fittedContextCalculator.calculate(input)
|
||||
// if (context != null) {
|
||||
// contexts.add(context)
|
||||
// // The position BlockPos has been used in a context, editing the same one
|
||||
// // will cause entities to spawn at the wrong location (buried in walls, usually)
|
||||
// // I made it so that our context calculators specifically take a copy of the
|
||||
// // BlockPos but it'd still be exposed in custom contexts so fixing it here too.
|
||||
// pos = BlockPos.Mutable(1, 2, 3)
|
||||
// input.position = pos
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// z++
|
||||
// }
|
||||
// y++
|
||||
// z = slice.baseZ
|
||||
// }
|
||||
// x++
|
||||
// y = slice.baseY
|
||||
// z = slice.baseZ
|
||||
// }
|
||||
//
|
||||
// return contexts
|
||||
// }
|
||||
}
|
||||
-31
@@ -1,31 +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.api.spawning.context
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.fallingstar.FallingStarSpawnCause
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.util.math.BlockPos
|
||||
|
||||
class FallingStarSpawningContext(
|
||||
cause: FallingStarSpawnCause,
|
||||
world: ServerWorld,
|
||||
pos: BlockPos,
|
||||
influences: MutableList<SpawningInfluence>
|
||||
) : TriggerSpawningContext(
|
||||
cause = cause,
|
||||
world = world,
|
||||
position = pos,
|
||||
light = world.getLightLevel(pos),
|
||||
skyLight = world.getLightLevel(pos.up()),
|
||||
canSeeSky = world.isSkyVisibleAllowingSea(pos),
|
||||
influences = influences
|
||||
) {
|
||||
|
||||
}
|
||||
-44
@@ -1,44 +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.api.spawning.context
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.fishing.FishingSpawnCause
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
||||
import com.cobblemon.mod.common.util.getBlockStates
|
||||
import com.cobblemon.mod.common.util.toVec3d
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.math.Box
|
||||
|
||||
/**
|
||||
* A spawning context that was generated for a fishing action.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since February 3rd, 2024
|
||||
*/
|
||||
class FishingSpawningContext(
|
||||
cause: FishingSpawnCause,
|
||||
world: ServerWorld,
|
||||
pos: BlockPos,
|
||||
influences: MutableList<SpawningInfluence>
|
||||
) : TriggerSpawningContext(
|
||||
cause = cause,
|
||||
world = world,
|
||||
position = pos,
|
||||
light = world.getLightLevel(pos),
|
||||
skyLight = world.getLightLevel(pos.up()),
|
||||
canSeeSky = world.isSkyVisibleAllowingSea(pos),
|
||||
influences = influences
|
||||
) {
|
||||
val nearbyBlocks = world.getBlockStates(Box.of(pos.toVec3d(), 10.0, 10.0, 10.0))
|
||||
val nearbyBlockTypes: List<Block> by lazy { nearbyBlocks.mapNotNull { it.block }.distinct() }
|
||||
val rodStack = cause.rodStack
|
||||
val rodItem = cause.rodItem
|
||||
}
|
||||
-34
@@ -1,34 +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.api.spawning.context
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnCause
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.util.math.BlockPos
|
||||
|
||||
/**
|
||||
* A spawning context relating to triggered spawning. Uses a single-point structure cache which is
|
||||
* the only contribution of this implementation.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since February 3rd, 2024
|
||||
*/
|
||||
open class TriggerSpawningContext(
|
||||
override val cause: SpawnCause,
|
||||
override val world: ServerWorld,
|
||||
override val position: BlockPos,
|
||||
override val light: Int,
|
||||
override val skyLight: Int,
|
||||
override val canSeeSky: Boolean,
|
||||
override val influences: MutableList<SpawningInfluence>
|
||||
) : SpawningContext() {
|
||||
val triggerStructureCache = StructureChunkCache()
|
||||
override fun getStructureCache(pos: BlockPos) = triggerStructureCache
|
||||
}
|
||||
+10
-3
@@ -30,9 +30,16 @@ abstract class SingleEntitySpawnAction<T : Entity>(
|
||||
override fun run(): EntitySpawnResult? {
|
||||
val e = createEntity() ?: return null
|
||||
e.setPosition(ctx.position.toVec3d().add(0.5, 1.0, 0.5))
|
||||
entity.emit(e)
|
||||
CobblemonEvents.ENTITY_SPAWN.postThen(SpawnEvent(e, ctx), ifSucceeded = { ctx.world.spawnEntity(e) })
|
||||
return EntitySpawnResult(listOf(e))
|
||||
var shouldSpawn = false
|
||||
CobblemonEvents.ENTITY_SPAWN.postThen(SpawnEvent(e, ctx), ifSucceeded = {
|
||||
ctx.world.spawnEntity(e)
|
||||
shouldSpawn = true
|
||||
})
|
||||
|
||||
return if (shouldSpawn) {
|
||||
this.entity.emit(e)
|
||||
EntitySpawnResult(listOf(e))
|
||||
} else null
|
||||
}
|
||||
|
||||
|
||||
|
||||
-20
@@ -1,20 +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.api.spawning.fallingstar
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnCause
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
|
||||
import net.minecraft.entity.Entity
|
||||
|
||||
class FallingStarSpawnCause(
|
||||
spawner: Spawner,
|
||||
bucket: SpawnBucket,
|
||||
entity: Entity?
|
||||
) : SpawnCause(spawner, bucket, entity)
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.fallingstar
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnPools
|
||||
import com.cobblemon.mod.common.api.spawning.context.FallingStarSpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.TriggerSpawner
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.util.math.BlockPos
|
||||
|
||||
open class FallingStarSpawner(
|
||||
override val name: String = "fallingstar",
|
||||
pool: SpawnPool = CobblemonSpawnPools.WORLD_SPAWN_POOL
|
||||
) : TriggerSpawner<FallingStarSpawnCause>(name, pool) {
|
||||
override fun parseContext(cause: FallingStarSpawnCause, world: ServerWorld, pos: BlockPos): FallingStarSpawningContext? {
|
||||
return FallingStarSpawningContext(cause, world, pos, influences)
|
||||
}
|
||||
}
|
||||
-32
@@ -1,32 +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.api.spawning.fishing
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnCause
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.item.FishingRodItem
|
||||
import net.minecraft.item.ItemStack
|
||||
|
||||
/**
|
||||
* A spawning cause that is embellished with fishing information. Could probably also
|
||||
* have the bobber entity or something.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since February 3rd, 2024
|
||||
*/
|
||||
class FishingSpawnCause(
|
||||
spawner: Spawner,
|
||||
bucket: SpawnBucket,
|
||||
entity: Entity?,
|
||||
val rodStack: ItemStack
|
||||
) : SpawnCause(spawner, bucket, entity) {
|
||||
val rodItem = rodStack.item as? FishingRodItem
|
||||
}
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.fishing
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnPools
|
||||
import com.cobblemon.mod.common.api.spawning.context.FishingSpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.TriggerSpawner
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.util.math.BlockPos
|
||||
|
||||
/**
|
||||
* A spawner that takes in a [FishingSpawnCause] and spawns things.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since February 3rd, 2024
|
||||
*/
|
||||
open class FishingSpawner(
|
||||
override val name: String = "fishing",
|
||||
pool: SpawnPool = CobblemonSpawnPools.WORLD_SPAWN_POOL
|
||||
) : TriggerSpawner<FishingSpawnCause>(name, pool) {
|
||||
override fun parseContext(cause: FishingSpawnCause, world: ServerWorld, pos: BlockPos): FishingSpawningContext? {
|
||||
// Maybe confirm that it's water we're fishing in?
|
||||
val ctx = FishingSpawningContext(
|
||||
cause = cause,
|
||||
world = world,
|
||||
pos = pos,
|
||||
influences = influences
|
||||
)
|
||||
return ctx
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.influence
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import net.minecraft.registry.tag.BlockTags
|
||||
|
||||
/**
|
||||
* Implements a [SpawningInfluence] that prevents Pokémon spawning on certain blocks.
|
||||
* This ensures that Pokémon don't spawn in areas that could disrupt player-built structures or mechanisms.
|
||||
* The influence checks the block directly above the potential spawn location; if the block is in the restricted list,
|
||||
* the spawn is disallowed.
|
||||
*
|
||||
* @author Aethen
|
||||
* @since February 20th, 2024
|
||||
*/
|
||||
open class RestrictedSpawnBlocksInfluence
|
||||
: SpawningInfluence {
|
||||
|
||||
// The list of blocks that Pokémon are not allowed to spawn on.
|
||||
private val restrictedBlocks = BlockTags.RAILS
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Affects the spawnable status of a Pokémon spawn detail.
|
||||
* If the block directly above the spawn location is in the restricted list, the spawn is disallowed.
|
||||
*
|
||||
* @param detail The Pokémon spawn detail to be affected.
|
||||
* @param ctx The context of the spawning event.
|
||||
* @return `true` if the spawn is allowed, `false` if it is disallowed.
|
||||
*/
|
||||
override fun affectSpawnable(detail: SpawnDetail, ctx: SpawningContext): Boolean {
|
||||
// If the spawn detail is not a Pokémon, it is not affected by this influence.
|
||||
if (detail.type != "pokemon") return true
|
||||
|
||||
// Get the position of the potential spawn location.
|
||||
val pokemonSpawnPos = ctx.position
|
||||
|
||||
// Examine the block immediately above the spawn block to check for a rail
|
||||
// Potentially need a refactor if we ever want to check the spawn block itself.
|
||||
return ctx.world.getBlockState(pokemonSpawnPos.withY(pokemonSpawnPos.y + 1)).isIn(restrictedBlocks).not()
|
||||
}
|
||||
}
|
||||
+22
-3
@@ -13,8 +13,10 @@ import com.cobblemon.mod.common.api.spawning.CobblemonSpawnRules
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnerManager
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
|
||||
import com.cobblemon.mod.common.api.spawning.influence.PlayerLevelRangeInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.influence.RestrictedSpawnBlocksInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.rules.SpawnRule
|
||||
import com.cobblemon.mod.common.util.mutableLazy
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
|
||||
/**
|
||||
@@ -26,14 +28,31 @@ import net.minecraft.server.network.ServerPlayerEntity
|
||||
* @since February 14th, 2022
|
||||
*/
|
||||
object PlayerSpawnerFactory {
|
||||
var spawns: SpawnPool = CobblemonSpawnPools.WORLD_SPAWN_POOL
|
||||
var influenceBuilders = mutableListOf<(player: ServerPlayerEntity) -> SpawningInfluence?>({ PlayerLevelRangeInfluence(it, variation = 5) })
|
||||
var spawns: SpawnPool by mutableLazy {
|
||||
CobblemonSpawnPools.WORLD_SPAWN_POOL
|
||||
}
|
||||
|
||||
/**
|
||||
* The list of influences for a new [PlayerSpawner].
|
||||
* The influences will be added to the spawner in the order they are added to this list.
|
||||
*
|
||||
* [PlayerLevelRangeInfluence] adjusts the level range of Pokémon that can spawn based on the player's level.
|
||||
* [RestrictedSpawnBlocksInfluence] prevents Pokémon from spawning on certain blocks.
|
||||
*/
|
||||
var influenceBuilders = mutableListOf<(player: ServerPlayerEntity) -> SpawningInfluence?>({
|
||||
PlayerLevelRangeInfluence(
|
||||
it,
|
||||
variation = 5
|
||||
)
|
||||
}, { RestrictedSpawnBlocksInfluence() })
|
||||
|
||||
fun create(spawnerManager: SpawnerManager, player: ServerPlayerEntity): PlayerSpawner {
|
||||
val influences = influenceBuilders.mapNotNull { it(player) }
|
||||
return PlayerSpawner(player, spawns, spawnerManager).also {
|
||||
it.influences.addAll(influences)
|
||||
it.influences.addAll(CobblemonSpawnRules.rules.values.filter(SpawnRule::enabled).flatMap(SpawnRule::components))
|
||||
it.influences.addAll(
|
||||
CobblemonSpawnRules.rules.values.filter(SpawnRule::enabled).flatMap(SpawnRule::components)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-51
@@ -1,51 +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.api.spawning.spawner
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnCause
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.selection.FlatContextWeightedSelector
|
||||
import com.cobblemon.mod.common.api.spawning.selection.SpawningSelector
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.util.math.BlockPos
|
||||
|
||||
/**
|
||||
* A type of spawner that occurs at a single point and provides its own means of generating a
|
||||
* context from a particular cause and position. The trigger spawner must be directly called to
|
||||
* spawn things (almost as if it was being triggered) as opposed to being scheduled on a ticker.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since February 3rd, 2024
|
||||
*/
|
||||
abstract class TriggerSpawner<T : SpawnCause>(override val name: String, var spawns: SpawnPool) : Spawner {
|
||||
private var selector: SpawningSelector = FlatContextWeightedSelector()
|
||||
override val influences = mutableListOf<SpawningInfluence>()
|
||||
|
||||
open fun run(cause: T, world: ServerWorld, pos: BlockPos): CompletableFuture<*>? {
|
||||
val context = parseContext(cause, world, pos) ?: return null
|
||||
selector.select(this, listOf(context))?.let { (_, spawn) ->
|
||||
val action = spawn.doSpawn(context)
|
||||
action.complete()
|
||||
return action.future
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/** Parses a context, if possible, from the given cause and position. */
|
||||
abstract fun parseContext(cause: T, world: ServerWorld, pos: BlockPos): SpawningContext?
|
||||
|
||||
override fun canSpawn() = true
|
||||
override fun getSpawningSelector() = selector
|
||||
override fun setSpawningSelector(selector: SpawningSelector) { this.selector = selector }
|
||||
override fun getSpawnPool() = spawns
|
||||
override fun setSpawnPool(spawnPool: SpawnPool) { spawns = spawnPool }
|
||||
}
|
||||
+4
-2
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.storage.adapter.conversions
|
||||
|
||||
import com.cobblemon.mod.common.api.abilities.Abilities
|
||||
import com.cobblemon.mod.common.api.moves.Moves
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.api.pokemon.Natures
|
||||
@@ -98,8 +99,9 @@ class ReforgedConversion(val base: Path) : CobblemonConverter<NbtCompound> {
|
||||
result.level = nbt.getInt("Level")
|
||||
result.addExperience(SidemodExperienceSource("Reforged"), nbt.getInt("EXP"))
|
||||
result.setFriendship(nbt.getInt("Friendship"))
|
||||
result.ability = (result.form.abilities.find { it.template.name == nbt.getString("Ability") } ?: result.form.abilities.first())
|
||||
.template.create()
|
||||
Abilities.get(nbt.getString("Ability"))?.let { template ->
|
||||
result.updateAbility(template.create(forced = result.form.abilities.none { it.template == template }))
|
||||
}
|
||||
result.nature = Natures.getNature(Identifier(ReforgedNatures.values()[nbt.getInt("Nature")].name.lowercase())) ?: Natures.getRandomNature()
|
||||
result.mintedNature = Natures.getNature(Identifier(ReforgedNatures.values()[nbt.getInt("MintNature")].name.lowercase()))
|
||||
result.currentHealth = nbt.getInt("Health")
|
||||
|
||||
@@ -260,7 +260,7 @@ open class PartyStore(override val uuid: UUID) : PokemonStore<PartyPosition>() {
|
||||
return@mapNotNull if (clone) {
|
||||
BattlePokemon.safeCopyOf(it)
|
||||
} else {
|
||||
BattlePokemon(it)
|
||||
BattlePokemon.playerOwned(it)
|
||||
}
|
||||
}.sortedBy { if (it.uuid == leadingPokemon) 0 else (indexOf(it.originalPokemon) + 1) }
|
||||
|
||||
|
||||
@@ -11,12 +11,14 @@ package com.cobblemon.mod.common.api.storage.party
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.advancement.CobblemonCriteria
|
||||
import com.cobblemon.mod.common.advancement.criterion.PartyCheckContext
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.PassiveEvolution
|
||||
import com.cobblemon.mod.common.api.storage.pc.PCStore
|
||||
import com.cobblemon.mod.common.battles.BattleRegistry
|
||||
import com.cobblemon.mod.common.pokemon.OriginalTrainerType
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.activestate.ShoulderedState
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.LevelUpEvolution
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
@@ -123,6 +125,12 @@ open class PlayerPartyStore(
|
||||
|
||||
// Passive evolutions
|
||||
pokemon.evolutions.filterIsInstance<PassiveEvolution>().forEach { it.attemptEvolution(pokemon) }
|
||||
val removeList = mutableListOf<Evolution>()
|
||||
pokemon.evolutionProxy.server().forEach {
|
||||
if (!it.test(pokemon) && it is LevelUpEvolution && !it.permanent)
|
||||
removeList.add(it)
|
||||
}
|
||||
removeList.forEach { pokemon.evolutionProxy.server().remove(it) }
|
||||
}
|
||||
// Friendship
|
||||
// ToDo expand this down the line just a very basic implementation for the first releases
|
||||
|
||||
@@ -22,107 +22,15 @@ import net.minecraft.registry.tag.TagKey
|
||||
object CobblemonBiomeTags {
|
||||
|
||||
@JvmField
|
||||
val IS_DEEP_DARK = create("is_deep_dark")
|
||||
val IS_AUTUMN = create("has_season/autumn")
|
||||
@JvmField
|
||||
val IS_ARID = create("is_arid")
|
||||
val IS_SPRING = create("has_season/spring")
|
||||
@JvmField
|
||||
val IS_AUTUMN = create("is_autumn")
|
||||
@JvmField
|
||||
val IS_BADLANDS = create("is_badlands")
|
||||
@JvmField
|
||||
val IS_BAMBOO = create("is_bamboo")
|
||||
@JvmField
|
||||
val IS_CAVE = create("is_cave")
|
||||
@JvmField
|
||||
val IS_COAST = create("is_coast")
|
||||
@JvmField
|
||||
val IS_COLD = create("is_cold")
|
||||
@JvmField
|
||||
val IS_DEEP_OCEAN = create("is_deep_ocean")
|
||||
@JvmField
|
||||
val IS_DESERT = create("is_desert")
|
||||
@JvmField
|
||||
val IS_DRIPSTONE = create("is_dripstone")
|
||||
@JvmField
|
||||
val IS_FLORAL = create("is_floral")
|
||||
@JvmField
|
||||
val IS_FOREST = create("is_forest")
|
||||
@JvmField
|
||||
val IS_FREEZING = create("is_freezing")
|
||||
@JvmField
|
||||
val IS_FRESHWATER = create("is_freshwater")
|
||||
@JvmField
|
||||
val IS_COLD_OCEAN = create("is_cold_ocean")
|
||||
@JvmField
|
||||
val IS_FROZEN_OCEAN = create("is_frozen_ocean")
|
||||
@JvmField
|
||||
val IS_GLACIAL = create("is_glacial")
|
||||
@JvmField
|
||||
val IS_GRASSLAND = create("is_grassland")
|
||||
@JvmField
|
||||
val IS_HIGHLANDS = create("is_highlands")
|
||||
@JvmField
|
||||
val IS_HILLS = create("is_hills")
|
||||
@JvmField
|
||||
val IS_ISLAND = create("is_island")
|
||||
@JvmField
|
||||
val IS_JUNGLE = create("is_jungle")
|
||||
@JvmField
|
||||
val IS_LUKEWARM_OCEAN = create("is_lukewarm_ocean")
|
||||
@JvmField
|
||||
val IS_LUSH = create("is_lush")
|
||||
@JvmField
|
||||
val IS_MAGICAL = create("is_magical")
|
||||
@JvmField
|
||||
val IS_MOUNTAIN = create("is_mountain")
|
||||
@JvmField
|
||||
val IS_MUSHROOM = create("is_mushroom")
|
||||
@JvmField
|
||||
val IS_OVERWORLD = create("is_overworld")
|
||||
@JvmField
|
||||
val IS_PEAK = create("is_peak")
|
||||
@JvmField
|
||||
val IS_PLAINS = create("is_plains")
|
||||
@JvmField
|
||||
val IS_PLATEAU = create("is_plateau")
|
||||
@JvmField
|
||||
val IS_WARM_OCEAN = create("is_warm_ocean")
|
||||
@JvmField
|
||||
val IS_RIVER = create("is_river")
|
||||
@JvmField
|
||||
val IS_SANDY = create("is_sandy")
|
||||
@JvmField
|
||||
val IS_SAVANNA = create("is_savanna")
|
||||
@JvmField
|
||||
val IS_SKY = create("is_sky")
|
||||
@JvmField
|
||||
val IS_SNOWY_FOREST = create("is_snowy_forest")
|
||||
@JvmField
|
||||
val IS_SPOOKY = create("is_spooky")
|
||||
@JvmField
|
||||
val IS_SPRING = create("is_spring")
|
||||
@JvmField
|
||||
val IS_SUMMER = create("is_summer")
|
||||
@JvmField
|
||||
val IS_SWAMP = create("is_swamp")
|
||||
@JvmField
|
||||
val IS_TAIGA = create("is_taiga")
|
||||
val IS_SUMMER = create("has_season/summer")
|
||||
@JvmField
|
||||
val IS_TEMPERATE = create("is_temperate")
|
||||
@JvmField
|
||||
val IS_THERMAL = create("is_thermal")
|
||||
@JvmField
|
||||
val IS_TUNDRA = create("is_tundra")
|
||||
@JvmField
|
||||
val IS_VOID = create("is_void")
|
||||
@JvmField
|
||||
val IS_VOlCANIC = create("is_volcanic")
|
||||
@JvmField
|
||||
val IS_WINTER = create("is_winter")
|
||||
@JvmField
|
||||
val IS_SPARSE = create("is_sparse")
|
||||
@JvmField
|
||||
val IS_DENSE = create("is_dense")
|
||||
val IS_WINTER = create("has_season/winter")
|
||||
|
||||
// Has Feature tags
|
||||
@JvmField
|
||||
@@ -180,16 +88,5 @@ object CobblemonBiomeTags {
|
||||
@JvmField
|
||||
val HAS_WATER_STONE_ORE_RARE = create("has_ore/ore_water_stone_rare")
|
||||
|
||||
// ToDo remove in 1.3
|
||||
@Deprecated(message = "This tag no longer exists", level = DeprecationLevel.ERROR)
|
||||
@JvmField
|
||||
val IS_CRAG = create("is_crag")
|
||||
@Deprecated(message = "This tag no longer exists", level = DeprecationLevel.ERROR)
|
||||
@JvmField
|
||||
val IS_ICY = create("is_icy")
|
||||
@Deprecated(message = "This tag no longer exists", replaceWith = ReplaceWith("com.cobblemon.mod.common.api.tags.CobblemonBiomeTags.IS_CAVE"), level = DeprecationLevel.ERROR)
|
||||
@JvmField
|
||||
val IS_UNDERGROUND = create("is_underground")
|
||||
|
||||
private fun create(path: String) = TagKey.of(RegistryKeys.BIOME, cobblemonResource(path))
|
||||
}
|
||||
@@ -144,6 +144,12 @@ object CobblemonItemTags {
|
||||
@JvmField
|
||||
val POTTERY_SHERDS = create("decorated_pot_sherds")
|
||||
|
||||
@JvmField
|
||||
val ABILITY_CHANGERS = create("ability_changers")
|
||||
|
||||
@JvmField
|
||||
val IS_FRIENDSHIP_BOOSTER = create("is_friendship_booster")
|
||||
|
||||
private fun create(path: String) = TagKey.of(RegistryKeys.ITEM, cobblemonResource(path))
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.types.tera
|
||||
|
||||
import com.cobblemon.mod.common.api.data.ShowdownIdentifiable
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* The representation of the Pokémons Tera type.
|
||||
*
|
||||
* @see [Bulbapedia](https://bulbapedia.bulbagarden.net/wiki/Terastal_phenomenon)
|
||||
*
|
||||
*/
|
||||
interface TeraType : ShowdownIdentifiable {
|
||||
|
||||
/**
|
||||
* The [Identifier] associated to this type.
|
||||
*/
|
||||
val id: Identifier
|
||||
|
||||
/**
|
||||
* If this tera type can be selected naturally.
|
||||
*/
|
||||
val legalAsStatic: Boolean
|
||||
|
||||
/**
|
||||
* The display name of this type.
|
||||
*/
|
||||
val displayName: Text
|
||||
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* 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.types.tera
|
||||
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.cobblemon.mod.common.api.types.tera.elemental.ElementalTypeTeraType
|
||||
import com.cobblemon.mod.common.api.types.tera.gimmick.StellarTeraType
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* The registry of all [TeraType]s.
|
||||
*/
|
||||
@Suppress("unused")
|
||||
object TeraTypes {
|
||||
private val types = hashMapOf<Identifier, TeraType>()
|
||||
|
||||
@JvmStatic
|
||||
val NORMAL = this.create(cobblemonResource("normal"), ElementalTypeTeraType(ElementalTypes.NORMAL))
|
||||
|
||||
@JvmStatic
|
||||
val FIRE = this.create(cobblemonResource("fire"), ElementalTypeTeraType(ElementalTypes.FIRE))
|
||||
|
||||
@JvmStatic
|
||||
val WATER = this.create(cobblemonResource("water"), ElementalTypeTeraType(ElementalTypes.WATER))
|
||||
|
||||
@JvmStatic
|
||||
val GRASS = this.create(cobblemonResource("grass"), ElementalTypeTeraType(ElementalTypes.GRASS))
|
||||
|
||||
@JvmStatic
|
||||
val ELECTRIC = this.create(cobblemonResource("electric"), ElementalTypeTeraType(ElementalTypes.ELECTRIC))
|
||||
|
||||
@JvmStatic
|
||||
val ICE = this.create(cobblemonResource("ice"), ElementalTypeTeraType(ElementalTypes.ICE))
|
||||
|
||||
@JvmStatic
|
||||
val FIGHTING = this.create(cobblemonResource("fighting"), ElementalTypeTeraType(ElementalTypes.FIGHTING))
|
||||
|
||||
@JvmStatic
|
||||
val POISON = this.create(cobblemonResource("poison"), ElementalTypeTeraType(ElementalTypes.POISON))
|
||||
|
||||
@JvmStatic
|
||||
val GROUND = this.create(cobblemonResource("ground"), ElementalTypeTeraType(ElementalTypes.GROUND))
|
||||
|
||||
@JvmStatic
|
||||
val FLYING = this.create(cobblemonResource("flying"), ElementalTypeTeraType(ElementalTypes.FLYING))
|
||||
|
||||
@JvmStatic
|
||||
val PSYCHIC = this.create(cobblemonResource("psychic"), ElementalTypeTeraType(ElementalTypes.PSYCHIC))
|
||||
|
||||
@JvmStatic
|
||||
val BUG = this.create(cobblemonResource("bug"), ElementalTypeTeraType(ElementalTypes.BUG))
|
||||
|
||||
@JvmStatic
|
||||
val ROCK = this.create(cobblemonResource("rock"), ElementalTypeTeraType(ElementalTypes.ROCK))
|
||||
|
||||
@JvmStatic
|
||||
val GHOST = this.create(cobblemonResource("ghost"), ElementalTypeTeraType(ElementalTypes.GHOST))
|
||||
|
||||
@JvmStatic
|
||||
val DRAGON = this.create(cobblemonResource("dragon"), ElementalTypeTeraType(ElementalTypes.DRAGON))
|
||||
|
||||
@JvmStatic
|
||||
val DARK = this.create(cobblemonResource("dark"), ElementalTypeTeraType(ElementalTypes.DARK))
|
||||
|
||||
@JvmStatic
|
||||
val STEEL = this.create(cobblemonResource("steel"), ElementalTypeTeraType(ElementalTypes.STEEL))
|
||||
|
||||
@JvmStatic
|
||||
val FAIRY = this.create(cobblemonResource("fairy"), ElementalTypeTeraType(ElementalTypes.FAIRY))
|
||||
|
||||
@JvmStatic
|
||||
val STELLAR = this.create(StellarTeraType.ID, StellarTeraType())
|
||||
|
||||
/**
|
||||
* Pick a random [TeraType].
|
||||
*
|
||||
* @param legalOnly If [TeraType.legalAsStatic] should be respected.
|
||||
* @return The selected [TeraType].
|
||||
*/
|
||||
@JvmStatic
|
||||
fun random(legalOnly: Boolean): TeraType {
|
||||
val possible = this.types.values
|
||||
if (legalOnly) {
|
||||
return possible.filter(TeraType::legalAsStatic).random()
|
||||
}
|
||||
return possible.random()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a [TeraType] by its [id].
|
||||
*
|
||||
* @param id The [Identifier] expected to match against a [TeraType.id].
|
||||
* @return The found [TeraType] or null.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun get(id: Identifier): TeraType? = this.types[id]
|
||||
|
||||
/**
|
||||
* Gets a [TeraType] by its [id].
|
||||
*
|
||||
* @param id The string representation of a [Identifier] if no namespace is present assumes Cobblemon' instead of Minecraft'.
|
||||
* @return The found [TeraType] or null.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun get(id: String): TeraType? = this.get(cobblemonResource(id))
|
||||
|
||||
/**
|
||||
* Gets the corresponding tera type for a [ElementalType].
|
||||
*
|
||||
* @param type The [ElementalType] being checked.
|
||||
* @return The associated [TeraType].
|
||||
*/
|
||||
@JvmStatic
|
||||
fun forElementalType(type: ElementalType): TeraType = this.get(cobblemonResource(type.name))!! // it's safe to do
|
||||
|
||||
private fun create(id: Identifier, type: TeraType): TeraType {
|
||||
this.types[id] = type
|
||||
return type
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.types.tera.elemental
|
||||
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.api.types.tera.TeraType
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
class ElementalTypeTeraType(val type: ElementalType) : TeraType {
|
||||
override val legalAsStatic: Boolean = true
|
||||
|
||||
override val id: Identifier = cobblemonResource(this.type.name)
|
||||
|
||||
override val displayName: Text = this.type.displayName
|
||||
|
||||
override fun showdownId(): String = this.type.name
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.types.tera.gimmick
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.types.tera.TeraType
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
class StellarTeraType : TeraType {
|
||||
override val id: Identifier = ID
|
||||
|
||||
override val legalAsStatic: Boolean = false
|
||||
|
||||
override val displayName: Text = LANG
|
||||
|
||||
override fun showdownId(): String = ID.path
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("stellar")
|
||||
private val LANG = Text.translatable("${Cobblemon.MODID}.terra_type.stellar")
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,8 @@ class ActiveBattlePokemon(val actor: BattleActor, var battlePokemon: BattlePokem
|
||||
fun getSide() = actor.getSide()
|
||||
var position: Pair<ServerWorld, Vec3d>? = null
|
||||
|
||||
var illusion: BattlePokemon? = null
|
||||
|
||||
override fun getAllActivePokemon() = battle.activePokemon
|
||||
override fun getActorShowdownId() = actor.showdownId
|
||||
override fun getActorPokemon() = actor.activePokemon
|
||||
|
||||
@@ -22,7 +22,6 @@ import com.cobblemon.mod.common.net.messages.client.battle.BattleChallengeExpire
|
||||
import com.cobblemon.mod.common.util.getPlayer
|
||||
import com.google.gson.GsonBuilder
|
||||
import java.time.Instant
|
||||
import java.util.Optional
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
@@ -139,7 +138,7 @@ object BattleRegistry {
|
||||
// 0 - 9, empty == 10
|
||||
packedTeamBuilder.append("${if (pk.dmaxLevel < 10) pk.dmaxLevel else ""},")
|
||||
// Teratype
|
||||
packedTeamBuilder.append("${pokemon.effectedPokemon.teraType.name},")
|
||||
packedTeamBuilder.append("${pokemon.effectedPokemon.teraType.showdownId()},")
|
||||
|
||||
team.add(packedTeamBuilder.toString())
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+8
-8
@@ -19,23 +19,23 @@ import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format:
|
||||
* |-ability|POKEMON|ABILITY|(from)EFFECT
|
||||
* Format: |-ability|POKEMON|ABILITY|(from)EFFECT
|
||||
*
|
||||
* The ABILITY of the POKEMON has been changed due to a move/ability EFFECT.
|
||||
* The ABILITY of POKEMON has been changed due to a move/ability EFFECT.
|
||||
*
|
||||
* Format:
|
||||
* |-ability|POKEMON|ABILITY
|
||||
* Alt format: |-ability|POKEMON|ABILITY
|
||||
*
|
||||
* POKEMON has just switched-in, and its ability ABILITY is being announced to have a long-term effect.
|
||||
* POKEMON has just switched-in, and its ABILITY is being announced to have a long-term effect.
|
||||
* @author Xylopia
|
||||
* @since January 31, 2023
|
||||
*/
|
||||
class AbilityInstruction(val instructionSet: InstructionSet, val message: BattleMessage) : InterpreterInstruction, CauserInstruction {
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val pokemon = message.getBattlePokemon(0, battle) ?: return
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return
|
||||
val pokemonName = pokemon.getName()
|
||||
val effect = message.effectAt(1) ?: return
|
||||
val optionalEffect = message.effect()
|
||||
val optionalPokemon = message.getSourceBattlePokemon(battle)
|
||||
val optionalPokemon = message.battlePokemonFromOptional(battle)
|
||||
val optionalPokemonName = optionalPokemon?.getName()
|
||||
|
||||
// If there is an optional effect causing the activation, broadcast that instead of the standard effect
|
||||
|
||||
+8
-5
@@ -20,16 +20,19 @@ import com.cobblemon.mod.common.util.battleLang
|
||||
import net.minecraft.text.Text
|
||||
|
||||
/**
|
||||
* Format:
|
||||
* |-activate|POKEMON|EFFECT
|
||||
* Format: |-activate|POKEMON|EFFECT
|
||||
*
|
||||
* A miscellaneous effect has activated.This is triggered whenever an effect could not be better described by one of the other minor messages.
|
||||
* A miscellaneous EFFECT has activated for POKEMON. This is triggered whenever an effect could not be better described
|
||||
* by one of the other minor messages.
|
||||
*
|
||||
* @author Hunter
|
||||
* @since September 25, 2022
|
||||
*/
|
||||
class ActivateInstruction(val instructionSet: InstructionSet, val message: BattleMessage) : InterpreterInstruction, CauserInstruction {
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val pokemon = message.getBattlePokemon(0, battle) ?: return
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return
|
||||
val pokemonName = pokemon.getName()
|
||||
val sourceName = message.getSourceBattlePokemon(battle)?.getName() ?: Text.literal("UNKNOWN")
|
||||
val sourceName = message.battlePokemonFromOptional(battle)?.getName() ?: Text.literal("UNKNOWN")
|
||||
val effect = message.effectAt(1) ?: return
|
||||
val extraEffect = message.effectAt(2)?.typelessData ?: Text.literal("UNKNOWN")
|
||||
ShowdownInterpreter.broadcastOptionalAbility(battle, effect, pokemonName)
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |bagitem|POKEMON|ITEM
|
||||
*
|
||||
* POKEMON had ITEM used on it from the 'bag'.
|
||||
* @author landonjw
|
||||
* @since July 31, 2023
|
||||
*/
|
||||
class BagItemInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchGo {
|
||||
val pokemon = message.pokemonByUuid(0, battle)!!
|
||||
val item = message.argumentAt(1)!!
|
||||
|
||||
val ownerName = pokemon.actor.getName()
|
||||
val itemName = item.asTranslated()
|
||||
|
||||
battle.broadcastChatMessage(battleLang("bagitem.use", ownerName, itemName, pokemon.getName()))
|
||||
}
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-block|POKEMON|EFFECT|MOVE|ATTACKER|(of)SOURCE
|
||||
*
|
||||
* An effect targeted at POKEMON was blocked by EFFECT. This may optionally specify that the effect was a MOVE from ATTACKER.
|
||||
*
|
||||
* An optional SOURCE will note the owner of the EFFECT, in the case that it's not EFFECT (for instance, an ally with Aroma Veil.)
|
||||
* @author jeffw773
|
||||
* @since November 6, 2023
|
||||
*/
|
||||
class BlockInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting(1.5F) {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchWaiting
|
||||
val pokemonName = pokemon.getName()
|
||||
val effectID = message.effectAt(1)?.id ?: return@dispatchWaiting
|
||||
val lang = battleLang("block.$effectID", pokemonName)
|
||||
|
||||
battle.broadcastChatMessage(lang)
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-boost|POKEMON|STAT|AMOUNT or |-unboost|POKEMON|STAT|AMOUNT
|
||||
*
|
||||
* POKEMON has gained or lost AMOUNT in STAT, using the standard rules for stat changes in-battle.
|
||||
* STAT is a standard three-letter abbreviation fot the stat in question.
|
||||
* @author Hiroku
|
||||
* @since August 20, 2022
|
||||
*/
|
||||
class BoostInstruction(val instructionSet: InstructionSet, val message: BattleMessage, val remainingLines: Iterator<BattleMessage>, val isBoost: Boolean = true): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return
|
||||
val statKey = message.argumentAt(1) ?: return
|
||||
val stages = message.argumentAt(2)?.toInt() ?: return
|
||||
val stat = Stats.getStat(statKey).displayName
|
||||
val severity = Stats.getSeverity(stages)
|
||||
val rootKey = if (isBoost) "boost" else "unboost"
|
||||
|
||||
battle.dispatchWaiting(1.5F) {
|
||||
val lang = when {
|
||||
message.hasOptionalArgument("zeffect") -> battleLang("$rootKey.$severity.zeffect", pokemon.getName(), stat)
|
||||
else -> battleLang("$rootKey.$severity", pokemon.getName(), stat)
|
||||
}
|
||||
battle.broadcastChatMessage(lang)
|
||||
|
||||
val boostBucket = if (isBoost) BattleContext.Type.BOOST else BattleContext.Type.UNBOOST
|
||||
val context = ShowdownInterpreter.getContextFromAction(message, boostBucket, battle)
|
||||
// TODO: replace with context that tracks detailed information such as # of stages
|
||||
repeat(stages) { pokemon.contextManager.add(context) }
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
|
||||
/**
|
||||
* Formats: |cant|POKEMON|REASON and |cant|POKEMON|REASON|MOVE
|
||||
*
|
||||
* The POKEMON could not perform a move because of the indicated REASON.
|
||||
* @author Deltric
|
||||
* @since January 22, 2022
|
||||
*/
|
||||
class CantInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchWaiting
|
||||
val effectID = message.effectAt(1)?.id ?: return@dispatchWaiting
|
||||
val name = pokemon.getName()
|
||||
// Move may be null as it's not always given
|
||||
val moveName = message.moveAt(2)?.displayName ?: run { "(Unrecognized: ${message.argumentAt(2)})".text() }
|
||||
|
||||
val lang = when (effectID) {
|
||||
// TODO: in the games they use a generic image because there is a popup of the ability and the sprite of the mon, it may be good to have a similar system here
|
||||
"armortail", "damp", "dazzling", "queenlymajesty" -> battleLang("cant.generic", name, moveName)
|
||||
"par", "slp", "frz" -> {
|
||||
val status = Statuses.getStatus(effectID)?.name?.path ?: return@dispatchWaiting
|
||||
lang("status.$status.is", name)
|
||||
}
|
||||
else -> battleLang("cant.$effectID", name, moveName)
|
||||
}
|
||||
|
||||
battle.broadcastChatMessage(lang.red())
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-clearallboost|
|
||||
*
|
||||
* Clears all boosts from all Pokémon on both sides.
|
||||
* @author Segfault Guy
|
||||
* @since April 26, 2023
|
||||
*/
|
||||
class ClearAllBoostInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting(1.5F) {
|
||||
battle.activePokemon.forEach {
|
||||
it.battlePokemon?.contextManager?.clear(BattleContext.Type.BOOST, BattleContext.Type.UNBOOST)
|
||||
}
|
||||
battle.broadcastChatMessage(battleLang("clearallboost"))
|
||||
}
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-clearnegativeboost|POKEMON
|
||||
*
|
||||
* Clear the negative boosts from the target POKEMON (usually as the result of a zeffect).
|
||||
* @author Segfault Guy
|
||||
* @since September 10, 2023
|
||||
*/
|
||||
class ClearNegativeBoostInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val battlePokemon = message.battlePokemon(0, battle) ?: return
|
||||
val pokemonName = battlePokemon.getName()
|
||||
battle.dispatchWaiting(1.5F) {
|
||||
val lang = when {
|
||||
message.hasOptionalArgument("zeffect") -> battleLang("clearallnegativeboost.zeffect", pokemonName)
|
||||
else -> battleLang("clearallnegativeboost", pokemonName)
|
||||
}
|
||||
if (!message.hasOptionalArgument("silent")) {
|
||||
battle.broadcastChatMessage(lang)
|
||||
}
|
||||
|
||||
battlePokemon.contextManager.clear(BattleContext.Type.UNBOOST)
|
||||
battle.minorBattleActions[battlePokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-copyboost|SOURCE|TARGET|(from)EFFECT
|
||||
*
|
||||
* Copies any stat changes from the TARGET Pokémon to the SOURCE Pokémon due to EFFECT.
|
||||
* @author JMMCP
|
||||
* @since November 27, 2023
|
||||
*/
|
||||
class CopyBoostInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchWaiting
|
||||
val pokemonName = pokemon.getName()
|
||||
val targetPokemon = message.battlePokemon(1, battle) ?: return@dispatchWaiting
|
||||
val targetPokemonName = targetPokemon.getName()
|
||||
val lang = battleLang("copyboost.generic", pokemonName, targetPokemonName)
|
||||
battle.broadcastChatMessage(lang)
|
||||
|
||||
pokemon.contextManager.copy(targetPokemon.contextManager, BattleContext.Type.BOOST, BattleContext.Type.UNBOOST)
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.text.yellow
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.pokemon.evolution.progress.LastBattleCriticalHitsEvolutionProgress
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-crit|POKEMON
|
||||
*
|
||||
* POKEMON received a critical hit.
|
||||
* @author Hunter
|
||||
* @since August 18, 2022
|
||||
*/
|
||||
class CritInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchGo {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchGo
|
||||
battle.broadcastChatMessage(battleLang("crit").yellow())
|
||||
ShowdownInterpreter.lastCauser[battle.battleId]?.let { message ->
|
||||
val battlePokemon = message.battlePokemon(0, battle) ?: return@let
|
||||
if (LastBattleCriticalHitsEvolutionProgress.supports(battlePokemon.effectedPokemon)) {
|
||||
val progress = battlePokemon.effectedPokemon.evolutionProxy.current().progressFirstOrCreate({ it is LastBattleCriticalHitsEvolutionProgress }) { LastBattleCriticalHitsEvolutionProgress() }
|
||||
progress.updateProgress(LastBattleCriticalHitsEvolutionProgress.Progress(progress.currentProgress().amount + 1))
|
||||
}
|
||||
}
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.Effect
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattlePersistentStatusPacket
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-curestatus|POKEMON|STATUS
|
||||
*
|
||||
* The POKEMON has recovered from its STATUS.
|
||||
* @author Hiroku
|
||||
* @since November 5, 2022
|
||||
*/
|
||||
class CureStatusInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val maybeActivePokemon = message.actorAndActivePokemon(0, battle)?.second?.battlePokemon
|
||||
val maybePartyPokemon = message.battlePokemon(0, battle)
|
||||
val pokemon = maybeActivePokemon ?: maybePartyPokemon ?: return
|
||||
val pokemonName = pokemon.getName()
|
||||
val status = message.argumentAt(1)?.let(Statuses::getStatus) ?: return
|
||||
val effect = message.effect()
|
||||
ShowdownInterpreter.broadcastOptionalAbility(battle, effect, pokemonName)
|
||||
|
||||
battle.dispatchWaiting {
|
||||
pokemon.effectedPokemon.status = null
|
||||
pokemon.sendUpdate()
|
||||
|
||||
if (maybeActivePokemon != null) {
|
||||
message.pnxAndUuid(0)?.let {
|
||||
battle.sendUpdate(BattlePersistentStatusPacket(it.first, null))
|
||||
}
|
||||
}
|
||||
val lang = when (effect?.type) {
|
||||
Effect.Type.ABILITY -> battleLang("curestatus.${effect.id}", pokemonName)
|
||||
else -> status.removeMessage.asTranslated(pokemonName)
|
||||
}
|
||||
battle.broadcastChatMessage(lang)
|
||||
pokemon.contextManager.remove(status.showdownName, BattleContext.Type.STATUS)
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
+31
-14
@@ -19,8 +19,10 @@ import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.battles.dispatch.UntilDispatch
|
||||
import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.net.messages.client.animation.PlayPoseableAnimationPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleHealthChangePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
|
||||
import com.cobblemon.mod.common.pokemon.evolution.progress.DamageTakenEvolutionProgress
|
||||
import com.cobblemon.mod.common.pokemon.evolution.progress.RecoilEvolutionProgress
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
@@ -29,6 +31,13 @@ import java.util.concurrent.CompletableFuture
|
||||
import kotlin.math.roundToInt
|
||||
import net.minecraft.text.Text
|
||||
|
||||
/**
|
||||
* Format: |-damage|POKEMON|HP STATUS
|
||||
*
|
||||
* POKEMON has taken damage and is now at HP STATUS
|
||||
* @author Hiroku
|
||||
* @since March 11, 2022
|
||||
*/
|
||||
class DamageInstruction(
|
||||
val instructionSet: InstructionSet,
|
||||
val actor: BattleActor,
|
||||
@@ -36,10 +45,10 @@ class DamageInstruction(
|
||||
val privateMessage: BattleMessage
|
||||
) : InterpreterInstruction {
|
||||
var future = CompletableFuture.completedFuture(Unit)
|
||||
val battlePokemon = publicMessage.getBattlePokemon(0, actor.battle)
|
||||
val expectedTarget = publicMessage.battlePokemon(0, actor.battle)
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battlePokemon ?: return
|
||||
val battlePokemon = publicMessage.battlePokemon(0, actor.battle) ?: return
|
||||
val recoiling = privateMessage.optionalArgument("from")?.equals("recoil", true) == true
|
||||
val lastCauser = instructionSet.getMostRecentCauser(comparedTo = this)
|
||||
if (recoiling) {
|
||||
@@ -58,7 +67,7 @@ class DamageInstruction(
|
||||
val newHealth = privateMessage.argumentAt(1)?.split(" ")?.get(0) ?: return
|
||||
val effect = privateMessage.effect()
|
||||
val pokemonName = battlePokemon.getName()
|
||||
val sourceName = privateMessage.getSourceBattlePokemon(battle)?.getName() ?: Text.literal("UNKNOWN")
|
||||
val sourceName = privateMessage.battlePokemonFromOptional(battle)?.getName() ?: Text.literal("UNKNOWN")
|
||||
var causedFaint = newHealth == "0"
|
||||
|
||||
battle.dispatch {
|
||||
@@ -70,18 +79,26 @@ class DamageInstruction(
|
||||
}
|
||||
|
||||
battle.dispatch {
|
||||
if (!causedFaint) {
|
||||
val pokemonEntity = battlePokemon.entity
|
||||
if (!causedFaint && pokemonEntity != null) {
|
||||
val pkt = PlayPoseableAnimationPacket(pokemonEntity.id, setOf("recoil"), emptySet())
|
||||
pkt.sendToPlayersAround(
|
||||
x = pokemonEntity.x,
|
||||
y = pokemonEntity.y,
|
||||
z = pokemonEntity.z,
|
||||
worldKey = pokemonEntity.world.registryKey,
|
||||
distance = 50.0
|
||||
)
|
||||
}
|
||||
|
||||
battlePokemon.entity?.let { pokemonEntity ->
|
||||
val pkt = PlayPoseableAnimationPacket(pokemonEntity.id, setOf("recoil"), emptySet())
|
||||
pkt.sendToPlayersAround(
|
||||
x = pokemonEntity.x,
|
||||
y = pokemonEntity.y,
|
||||
z = pokemonEntity.z,
|
||||
worldKey = pokemonEntity.world.registryKey,
|
||||
distance = 50.0
|
||||
)
|
||||
}
|
||||
if (pokemonEntity != null) {
|
||||
RunPosableMoLangPacket(pokemonEntity.id, setOf("q.particle('cobblemon:hit', 'target')")).sendToPlayersAround(
|
||||
x = pokemonEntity.x,
|
||||
y = pokemonEntity.y,
|
||||
z = pokemonEntity.z,
|
||||
worldKey = pokemonEntity.world.registryKey,
|
||||
distance = 50.0
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
-19
@@ -1,19 +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.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
|
||||
class DeprecatedInstruction(val message: BattleMessage, val function: (PokemonBattle, BattleMessage, MutableList<String>) -> Unit) : InterpreterInstruction {
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
function(battle, message, mutableListOf())
|
||||
}
|
||||
}
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
|
||||
class DeprecatedSplitInstruction(
|
||||
val battleActor: BattleActor,
|
||||
val publicMessage: BattleMessage,
|
||||
val privateMessage: BattleMessage,
|
||||
val function: (PokemonBattle, BattleActor, BattleMessage, BattleMessage) -> Unit
|
||||
) : InterpreterInstruction {
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
function(battle, battleActor, publicMessage, privateMessage)
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |detailschange|POKEMON|DETAILS|HP STATUS
|
||||
*
|
||||
* POKEMON has changed formes permanently (i.e. Mega Evolution) to DETAILS.
|
||||
* @author Segfault Guy
|
||||
* @since September 10, 2023
|
||||
*/
|
||||
class DetailsChangeInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val battlePokemon = message.battlePokemon(0, battle) ?: return
|
||||
val pokemonName = battlePokemon.getName()
|
||||
val formName = message.argumentAt(1)?.split(',')?.get(0)?.substringAfter('-')?.lowercase() ?: return
|
||||
battle.dispatchWaiting {
|
||||
battle.broadcastChatMessage(battleLang("detailschange.$formName", pokemonName))
|
||||
battle.majorBattleActions[battlePokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.EntityBackedBattleActor
|
||||
import com.cobblemon.mod.common.battles.dispatch.BattleDispatch
|
||||
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |drag|POKEMON|DETAILS|HP STATUS
|
||||
*
|
||||
* POKEMON has switched in (if there was an old Pokémon in that position, it is switched out).
|
||||
* POKEMON|DETAILS represents all the information that can be used to tell Pokémon apart.
|
||||
* The switched Pokémon has HP health points and STATUS status.
|
||||
* @author
|
||||
*/
|
||||
class DragInstruction(val instructionSet: InstructionSet, val battleActor: BattleActor, val publicMessage: BattleMessage, val privateMessage: BattleMessage): InterpreterInstruction {
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchInsert {
|
||||
val (pnx, _) = publicMessage.pnxAndUuid(0)!!
|
||||
val (_, activePokemon) = battle.getActorAndActiveSlotFromPNX(pnx)
|
||||
|
||||
val illusion = publicMessage.battlePokemonFromOptional(battle , "is")
|
||||
val pokemon = publicMessage.battlePokemon(0, battle) ?: return@dispatchInsert emptySet()
|
||||
|
||||
battle.broadcastChatMessage(battleLang("dragged_out", pokemon.getName()))
|
||||
activePokemon.battlePokemon?.let { oldPokemon ->
|
||||
oldPokemon.contextManager.clear(BattleContext.Type.VOLATILE, BattleContext.Type.BOOST, BattleContext.Type.UNBOOST)
|
||||
battle.majorBattleActions[oldPokemon.uuid] = publicMessage
|
||||
}
|
||||
battle.majorBattleActions[pokemon.uuid] = publicMessage
|
||||
|
||||
val entity = if (battleActor is EntityBackedBattleActor<*>) battleActor.entity else null
|
||||
setOf(
|
||||
BattleDispatch {
|
||||
if (entity != null) {
|
||||
SwitchInstruction.createEntitySwitch(battle, battleActor, entity, pnx, activePokemon, pokemon, illusion)
|
||||
} else {
|
||||
SwitchInstruction.createNonEntitySwitch(battle, battleActor, pnx, activePokemon, pokemon, illusion)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-endability|POKEMON
|
||||
*
|
||||
* The POKEMON's Ability was suppressed.
|
||||
* @author jeffw773
|
||||
* @since November 28, 2023
|
||||
*/
|
||||
class EndAbilityInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting(1.5F) {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchWaiting
|
||||
val pokemonName = pokemon.getName()
|
||||
|
||||
val lang = battleLang("endability", pokemonName)
|
||||
battle.broadcastChatMessage(lang)
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
|
||||
/**
|
||||
* Format: |-end|POKEMON|EFFECT
|
||||
*
|
||||
* The volatile status from EFFECT inflicted on POKEMON has ended.
|
||||
* @author Hiroku
|
||||
* @since October 3, 2022
|
||||
*/
|
||||
class EndInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchWaiting
|
||||
val pokemonName = pokemon.getName()
|
||||
val effectID = message.effectAt(1)?.id ?: return@dispatchWaiting
|
||||
if (!message.hasOptionalArgument("silent")) {
|
||||
val lang = when (effectID) {
|
||||
"yawn" -> lang("status.sleep.apply", pokemonName)
|
||||
else -> battleLang("end.$effectID", pokemonName)
|
||||
}
|
||||
battle.broadcastChatMessage(lang)
|
||||
}
|
||||
pokemon.contextManager.remove(effectID, BattleContext.Type.VOLATILE)
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-enditem|POKEMON|ITEM|(from)EFFECT
|
||||
*
|
||||
* ITEM held by POKEMON has been destroyed by a move or ability EFFECT, and it now holds no item.
|
||||
*
|
||||
* Alt format: |-enditem|POKEMON|ITEM
|
||||
*
|
||||
* POKEMON's ITEM has destroyed itself (consumed or used).
|
||||
* @author Licious
|
||||
* @since December 30, 2022
|
||||
*/
|
||||
class EndItemInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchGo {
|
||||
// All logic regarding broadcasting battle messages is handled in CobblemonHeldItemManager
|
||||
val battlePokemon = message.battlePokemon(0, battle) ?: return@dispatchGo
|
||||
val itemEffect = message.effectAt(1) ?: return@dispatchGo
|
||||
battlePokemon.heldItemManager.handleEndInstruction(battlePokemon, battle, message)
|
||||
battle.minorBattleActions[battlePokemon.uuid] = message
|
||||
battlePokemon.contextManager.remove(itemEffect.id, BattleContext.Type.ITEM)
|
||||
if (message.hasOptionalArgument("eat")) {
|
||||
battlePokemon.entity?.playSound(CobblemonSounds.BERRY_EAT, 1F, 1F)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user