forked from mirrors/cobblemon
Compare commits
297
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64f7556bdc | ||
|
|
9fea42bce0 | ||
|
|
7abe83c413 | ||
|
|
2d70f48176 | ||
|
|
8f9c1c40d7 | ||
|
|
89c9cd9fb4 | ||
|
|
9335eb9650 | ||
|
|
7a7be6f25a | ||
|
|
e6fda6137e | ||
|
|
afae39acc8 | ||
|
|
37264aff0f | ||
|
|
2b60e6de77 | ||
|
|
4f29e7457c | ||
|
|
04a6ab31f4 | ||
|
|
a2cdc847dd | ||
|
|
0bca678f56 | ||
|
|
067c3607aa | ||
|
|
823c1f6444 | ||
|
|
bfc00635cd | ||
|
|
b2e5b85ac5 | ||
|
|
2c27476954 | ||
|
|
76ed55ebe8 | ||
|
|
b004b13eda | ||
|
|
aab78d84fc | ||
|
|
cb632c2a65 | ||
|
|
8d219f1338 | ||
|
|
1e6a4ed984 | ||
|
|
64240c31fc | ||
|
|
d2222c3858 | ||
|
|
c7f31c3e14 | ||
|
|
740e846b2d | ||
|
|
06f9d60595 | ||
|
|
dbe8a1a9f5 | ||
|
|
25e8e3c990 | ||
|
|
b84012f98f | ||
|
|
d54439ce14 | ||
|
|
a0979b28d3 | ||
|
|
32ee4bb72a | ||
|
|
e7d2a46cc0 | ||
|
|
3ee94ec076 | ||
|
|
589293abc4 | ||
|
|
279865cc7c | ||
|
|
b597b149c3 | ||
|
|
b7f592f2a8 | ||
|
|
70e17c22e7 | ||
|
|
51b18ca0f6 | ||
|
|
a83f243a3b | ||
|
|
f5b088c708 | ||
|
|
dc454cbb68 | ||
|
|
3b99e38da2 | ||
|
|
483af57964 | ||
|
|
a941bdddf3 | ||
|
|
246ba4a93b | ||
|
|
f459c64073 | ||
|
|
3347c084ed | ||
|
|
8175cee454 | ||
|
|
37d54053a5 | ||
|
|
b8846bd74c | ||
|
|
1716e135c4 | ||
|
|
0ac804cfcb | ||
|
|
aecc132814 | ||
|
|
8b47876dff | ||
|
|
ffc108953a | ||
|
|
0a106174fe | ||
|
|
90210bee3c | ||
|
|
8603cd4ad0 | ||
|
|
7b2c6827c2 | ||
|
|
902b4a6d21 | ||
|
|
a847cb5926 | ||
|
|
050c6f5adc | ||
|
|
fb95fb3cf7 | ||
|
|
d507367411 | ||
|
|
faa19cebcb | ||
|
|
aced374367 | ||
|
|
d424a6f1d3 | ||
|
|
71bb1c32de | ||
|
|
f726fcedb9 | ||
|
|
77344ccc2f | ||
|
|
90bc16be90 | ||
|
|
d1b743a01f | ||
|
|
aed651c0a0 | ||
|
|
4c477e1675 | ||
|
|
d1cdc6789c | ||
|
|
cd3127b983 | ||
|
|
68f5eff048 | ||
|
|
c3d2918a2b | ||
|
|
0432525c06 | ||
|
|
a60f27e282 | ||
|
|
5f0182cb7e | ||
|
|
4a3ae9407b | ||
|
|
766c2838d2 | ||
|
|
4cb95589b4 | ||
|
|
a8d3c2dd52 | ||
|
|
cb5d7b6ad7 | ||
|
|
c7dcc64595 | ||
|
|
6573e08da7 | ||
|
|
cd695ade4a | ||
|
|
55cb413cfc | ||
|
|
4f1bf7fcbb | ||
|
|
154ee80ead | ||
|
|
1c9f9bb198 | ||
|
|
6836343f11 | ||
|
|
8a7abb9a11 | ||
|
|
aa0d1cd943 | ||
|
|
798f1da8b3 | ||
|
|
d98efb52b6 | ||
|
|
2f27a03f08 | ||
|
|
e33025b1fa | ||
|
|
ade2481f42 | ||
|
|
576e2301ce | ||
|
|
a568d45d75 | ||
|
|
bc19a7e4c1 | ||
|
|
616e438f17 | ||
|
|
9bb11c46d5 | ||
|
|
5f470bb703 | ||
|
|
276f13cea5 | ||
|
|
ac069687f1 | ||
|
|
f248c22eed | ||
|
|
65a5687f92 | ||
|
|
ea50fa534b | ||
|
|
4bd3c4af58 | ||
|
|
283d80f7ed | ||
|
|
0238ca80f0 | ||
|
|
d24c5fe874 | ||
|
|
e65e21f2ff | ||
|
|
e1d417718f | ||
|
|
d4308b0a4f | ||
|
|
56650418d2 | ||
|
|
0543b84d34 | ||
|
|
1f50687a59 | ||
|
|
ed04faf0d8 | ||
|
|
1ed020f3e0 | ||
|
|
7e385d8c94 | ||
|
|
ee509b5438 | ||
|
|
ac9394131c | ||
|
|
d058a306a7 | ||
|
|
b9be0c3fcb | ||
|
|
b59b46568a | ||
|
|
408cbc8c49 | ||
|
|
7be8beb71e | ||
|
|
a8ce3c2175 | ||
|
|
80ae127379 | ||
|
|
bd3a9fb3af | ||
|
|
d0eaccb81b | ||
|
|
0b531d967e | ||
|
|
b0d1aec9ab | ||
|
|
f4d47098b5 | ||
|
|
1989b8aa92 | ||
|
|
e290fe9c75 | ||
|
|
06a50cfeeb | ||
|
|
00888c8ad5 | ||
|
|
637274c7ee | ||
|
|
3963e83717 | ||
|
|
7893e365da | ||
|
|
b6a7051b2c | ||
|
|
2cb1cf2f83 | ||
|
|
f13a4e0e24 | ||
|
|
17e1bbd6a1 | ||
|
|
c36ff0a0fe | ||
|
|
8dbb350230 | ||
|
|
52f9ffb1f6 | ||
|
|
030195e3ff | ||
|
|
d21a52ae68 | ||
|
|
3c1f1dbacb | ||
|
|
787c4851ff | ||
|
|
bf6e7fafd3 | ||
|
|
ea6df764c0 | ||
|
|
f242de272d | ||
|
|
5232e2e9bc | ||
|
|
ca35898243 | ||
|
|
869457d235 | ||
|
|
6736c8160b | ||
|
|
243c50550d | ||
|
|
fe7d3ef23a | ||
|
|
57ad77fc39 | ||
|
|
d70e7bd1b3 | ||
|
|
254cc931ea | ||
|
|
01fe5cffe8 | ||
|
|
3e18995a37 | ||
|
|
ff161c9c9b | ||
|
|
6b7b4f326d | ||
|
|
f50f7dec29 | ||
|
|
a5def20c58 | ||
|
|
b23204f9c9 | ||
|
|
4972de0aaa | ||
|
|
58a1f3d7b4 | ||
|
|
f516edb858 | ||
|
|
161aa952fa | ||
|
|
3b26a13ad6 | ||
|
|
014189217a | ||
|
|
978debb40c | ||
|
|
5be707811e | ||
|
|
ac44a98f8a | ||
|
|
03ecc2ae8d | ||
|
|
1518379107 | ||
|
|
a58c8c59e1 | ||
|
|
37959b5048 | ||
|
|
cbcc9fc6f1 | ||
|
|
d236aaa7da | ||
|
|
a2cd5a671c | ||
|
|
1d6a45bf4d | ||
|
|
5bfe703ed7 | ||
|
|
fc8485388e | ||
|
|
a5593b3131 | ||
|
|
9541bf3267 | ||
|
|
1037fe0a0e | ||
|
|
a6eea3198a | ||
|
|
b28e2313a8 | ||
|
|
0f0b4e6c86 | ||
|
|
e033467054 | ||
|
|
0f092bf6bf | ||
|
|
66ba762360 | ||
|
|
c7c11838a0 | ||
|
|
301d80fabe | ||
|
|
fade5502d9 | ||
|
|
63786357b9 | ||
|
|
ce55035408 | ||
|
|
d4665ddaeb | ||
|
|
4375c6f667 | ||
|
|
fa3e85b054 | ||
|
|
61c1c6b21f | ||
|
|
a347844986 | ||
|
|
d78a92f069 | ||
|
|
f4a7c6e873 | ||
|
|
3bef1dad4a | ||
|
|
ba3207d176 | ||
|
|
da50ee59cf | ||
|
|
6e8985d97e | ||
|
|
19c4c0d50d | ||
|
|
b23110950e | ||
|
|
60c213c44b | ||
|
|
3df8dea71b | ||
|
|
3cca50b7cc | ||
|
|
1ff5622694 | ||
|
|
762f9ce5f1 | ||
|
|
6c12198344 | ||
|
|
411f388bd3 | ||
|
|
5b8d35604a | ||
|
|
619d002bc4 | ||
|
|
7049656f64 | ||
|
|
e6e7c2982d | ||
|
|
82686b0511 | ||
|
|
f4eca30163 | ||
|
|
2814183012 | ||
|
|
bbc3c2a8d6 | ||
|
|
7eeb7feeae | ||
|
|
b2f850c1c8 | ||
|
|
23db346070 | ||
|
|
d3b7d739bb | ||
|
|
99a0ec7f0d | ||
|
|
aacebc9726 | ||
|
|
378c85b7dd | ||
|
|
c4614ff418 | ||
|
|
8cbbd2de27 | ||
|
|
067c59a636 | ||
|
|
98a02438da | ||
|
|
eb6c134f4b | ||
|
|
26b25c8c39 | ||
|
|
aa0b8d88e8 | ||
|
|
bfd78c1a85 | ||
|
|
239485ccb5 | ||
|
|
ff959daaef | ||
|
|
3cf9425247 | ||
|
|
32bb340260 | ||
|
|
b5578e72bd | ||
|
|
3aea0909a4 | ||
|
|
5adef3336e | ||
|
|
1a96b418bc | ||
|
|
e373e86b60 | ||
|
|
6f3035184c | ||
|
|
7ae8b1957c | ||
|
|
824b9718ee | ||
|
|
ef43f6c087 | ||
|
|
c8a70caf79 | ||
|
|
b7bfc6d0a1 | ||
|
|
ba11758e1f | ||
|
|
f0412d6b1d | ||
|
|
f5f87ce1a3 | ||
|
|
f28b269734 | ||
|
|
d545efd843 | ||
|
|
f8682c2123 | ||
|
|
f62e31a1eb | ||
|
|
ea623b08a6 | ||
|
|
ce3d5a413c | ||
|
|
d23fd6e23c | ||
|
|
59395a254d | ||
|
|
5d7c6c8d6f | ||
|
|
d86879095f | ||
|
|
6529293d21 | ||
|
|
a1fce624ea | ||
|
|
b7773f7471 | ||
|
|
f927e47bfe | ||
|
|
48a37b2018 | ||
|
|
f6b2da6ed6 | ||
|
|
275779b20e | ||
|
|
2102f8ff88 | ||
|
|
8f462aab40 |
+67
-58
@@ -1,9 +1,12 @@
|
||||
# Changelog
|
||||
## [1.7.2 (MONTH Xth, YEAR)](#1-7-2)
|
||||
## [1.7.2 (January 25th, 2026)](#1-7-2)
|
||||
|
||||
### Additions
|
||||
- Added riding statistics: `Distance by Pokémon on Land`, `Distance by Pokémon in Air` and `Distance by Pokémon in Liquid`.
|
||||
- Added Saccharine wood furniture for Adorn.
|
||||
- Added the Partner Mark, which party Pokémon have a very small chance to earn as the player walks, provided they have enough friendship.
|
||||
- Added trades for Saccharine Saplings, Hearty Grains, Chipped Pot, and Masterpiece Teacup to the Wandering Trader.
|
||||
- Added brewing recipe for Throat Spray.
|
||||
- Added official Controlify Support
|
||||
- Added new effects
|
||||
- Mental Restoration: Reduces "Time Since Last Rest" statistic, which controls Insomnia, by half a minute per second per effect level
|
||||
- Negative Effect Cleanse: Removes all negative effects
|
||||
@@ -13,73 +16,79 @@
|
||||
- White Herb - Negative Effect Cleanse
|
||||
- Milk - Effect Cleanse
|
||||
- Moomoo Milk - Effect Cleanse
|
||||
- Added `label` as an alternate key to the `tag` property.
|
||||
- Added Saccharine wood furniture for Adorn.
|
||||
- Added block models for existing items: Potion, Super Potion, Hyper Potion, Max Potion, Full Restore, Antidote, Awakening, Burn Heal, Ice Heal, Paralyze Heal, Full Heal, Ether, Elixir, Max Ether, Max Elixir, X Accuracy, X Attack, X Defence, X Special Attack, X Special Defence, X Speed, Dire Hit, Guard Spec, Weakness Policy, Blunder Policy, Cleanse Tag, and Spell Tag.
|
||||
- Added decorative sign blocks, Plaques.
|
||||
- Added decorative block models for existing items: Potion, Super Potion, Hyper Potion, Max Potion, Full Restore, Antidote, Awakening, Burn Heal, Ice Heal, Paralyze Heal, Full Heal, Ether, Elixir, Max Ether, Max Elixir, X Accuracy, X Attack, X Defence, X Special Attack, X Special Defence, X Speed, Dire Hit, Guard Spec, Weakness Policy, Blunder Policy, Cleanse Tag, and Spell Tag.
|
||||
- Added decorative sign blocks called Plaques.
|
||||
- Added ride style labels to ride stats in Pokédex, as well as ride style icons in the summary GUI.
|
||||
- Added more seasonings for sinister tea:
|
||||
- Mental Herb - Mental Restoration I for 10 seconds, which staves off Insomnia.
|
||||
- White Herb - Removes negative effects.
|
||||
- Milk, Moomoo Milk - Removes effects.
|
||||
- Added dispenser support for:
|
||||
- Applying a Honey Bottle to Saccharine Logs.
|
||||
- Washing honey off of Saccharine Slathered Logs.
|
||||
- Applying and removing honey on Saccharine Leaves.
|
||||
- Added riding statistics: `Distance by Pokémon on Land`, `Distance by Pokémon in Air` and `Distance by Pokémon in Liquid`.
|
||||
|
||||
### New rideable Pokémon
|
||||
- Honchkrow
|
||||
- Mantine
|
||||
|
||||
### Pokémon Added
|
||||
|
||||
#### Gen 5
|
||||
- Throh
|
||||
- Sawk
|
||||
|
||||
#### Gen 6
|
||||
- Litleo
|
||||
- Pyroar
|
||||
- Spritzee
|
||||
- Aromatisse
|
||||
- Swirlix
|
||||
- Slurpuff
|
||||
|
||||
### Model updates for the following Pokémon
|
||||
- Falinks
|
||||
- Cottonee
|
||||
- Whimsicott
|
||||
- Ferroseed
|
||||
- Ferrothorn
|
||||
- Chingling
|
||||
- Chimecho
|
||||
|
||||
### Animation updates for the following Pokémon
|
||||
- Mantine (ride animations)
|
||||
- Flygon (ride jump animation)
|
||||
- Honchkrow (ride animations)
|
||||
- Croagunk
|
||||
- Toxicroak
|
||||
|
||||
### Changes
|
||||
- Added a new config option, `Enable In-Flight Dismounting` (default: off), which lets you dismount while riding a Pokémon in the air. This is the textbook definition of caveat emptor.
|
||||
- Ride sounds have been separated into stereo for passengers and mono for other players. Riding will now sound more spacious.
|
||||
- Added a new config option, `Enable In-Flight Dismounting` (default: off), which lets you dismount while riding a Pokémon in the air.
|
||||
- Battle AI now uses a smarter threshold for switching, reducing unnecessary switches.
|
||||
- AI will always use the most damaging move when at low HP and when it is not switching, improving endgame decision-making.
|
||||
- Added support for optional message variants in battle activate instructions for more context-specific battle text.
|
||||
- Example: `this.add('-activate', pokemon, 'ability: example', '[msg]message1');` will parse to lang key `cobblemon.battle.activate.example.message1`
|
||||
- Items given from interacting with Saccharine Leaves are placed in the active hotbar slot if possible.
|
||||
- Added `label` as an alternate key to the `tag` property.
|
||||
## [1.7.3 (January 31st, 2026)](#1-7-3)
|
||||
|
||||
### Fixes
|
||||
- Fixed an issue in the OmniPathNodeMaker/Navigation that prevented Combee from pathing into and out of Saccharine Leaves.
|
||||
- Fixed orientation not getting reset after crashing while flying and getting back on the Pokémon.
|
||||
- Fixed Furfrou not being trimmable on NeoForge.
|
||||
- Fixed shiny Pokémon not respecting the silent flag on spawn.
|
||||
- Fixed honey from Saccharine Leaves being harvestable at less than the max age.
|
||||
- Items given from interacting with Saccharine Leaves are placed in the active hotbar slot if possible.
|
||||
- Fix all Pokémon being saved to chunks and never despawning.
|
||||
- Fixed possible error on world generation when Combee are placed in naturally generated bee nests.
|
||||
- Fixed Poké Snacks crashing if there was no available spawn.
|
||||
- Fixed Pokémon spawn influences not being specific to regional forms.
|
||||
- Fixed crashing when viewing another player in spectator mode.
|
||||
- Fixed missing apricorn textures for Adorn blocks.
|
||||
- Fixed crashing when riding due to malformed json file instead of resetting it.
|
||||
- Fixed mochi items consuming two items at a time.
|
||||
- Fix item interaction sometimes not working properly when playing on servers.
|
||||
- Fixed Soothe Bell not being properly tagged as a held item.
|
||||
- Fixed Mint Leaves not being usable for filling the Resurrection Machine.
|
||||
- Added Saccharine Boats and Saccharine Boat with Chests to relevant boat tags.
|
||||
- Fixed the `run_script` Molang function to not fail if the environment's context is null.
|
||||
- Fixed battle item duplication issue.
|
||||
- Fixed the movesets of certain Pokémon being incorrectly sanitized upon reload.
|
||||
- Fixed the ordering of Aprijuice's riding stat boosts to always have the same order.
|
||||
- Fixed the Molang functions `date_local_time`, `date_of`, `date_is_after` to use the correct date format.
|
||||
- Fixed the bottom half of pasture blocks having an incorrect hit-box when facing north or south.
|
||||
- Fixed Galarian Mr. Mime incorrectly being rideable.
|
||||
- Fixed gimmicks not being usable in double / triple battles.
|
||||
- Fixed gimmick buttons showing when already used in the same turn in double / triple battles.
|
||||
- Fixed Apricorn block model rotation for counters/sinks/cupboards/drawers to match that of most recent version of Adorn.
|
||||
- Fixed Fresh Start Mochi EV reset not syncing health changes properly.
|
||||
- Fixed requirements such as `biomeCondition` crashing the game when used to define Pokémon interactions.
|
||||
- Fixed Pokémon interactions not playing sound effects when the volume was not specified.
|
||||
- Fixed Pokémon interaction cooldowns taking longer than intended when the Pokémon was in the player’s party.
|
||||
- Fixed Pokémon interactions occasionally crashing the game when spamming an interaction with a 0 cooldown.
|
||||
- Fixed Pokémon fullness decreasing more than intended when the Pokémon was pastured.
|
||||
- Fixed crashing when sending a Pokémon out after editing its form.
|
||||
- Fixed Super Potion recipes incorrectly using Hondew Berry instead of Aguav Berry.
|
||||
- Fixed `/calculateseatpositions` expecting a locator format that even we don't use. It needs an underscore after "seat".
|
||||
- Fixed invulnerability-bypassed damage being resisted by invulnerable NPC entities.
|
||||
- Fixed selected leading Pokémon in battle not being used when levels are raised.
|
||||
- Fixed killer not being set early enough on a wild wild Pokémon entity from WinInstruction.
|
||||
- Fixed mounted Pokémon not playing sounds.
|
||||
- Fixed players failing to join servers randomly.
|
||||
- Fixed some Pokémon having no stamina for flying.
|
||||
- Fixed `/pctake` not respecting the actual size of the PC.
|
||||
|
||||
### Developer
|
||||
- Changed the `owner` parameter in the `OwnerQueryRequirement` interface from `ServerPlayer` to `Player`. This method is now also called on the client to verify whether a Pokémon interaction succeeded, so make sure to update your implementations to handle both server and client contexts.
|
||||
- Added `pnx` to the `BattleFaintedEvent` and `FormeChangeEvent`.
|
||||
- Added register methods for custom instructions to `ShowdownInterpreter`.
|
||||
- Changed callback operations in `BattlePokemon` to allow multiple callbacks and is now mutable.
|
||||
- Poké Ball GUI textures now respect the ball's namespace, enabling proper texture loading for custom balls from other mods.
|
||||
|
||||
### Molang & Datapacks
|
||||
- Ride sounds can now be set as exclusive to passengers.
|
||||
- Ride sounds no longer play when submerged unless specified with a new setting.
|
||||
- Exception handling has been added to `run_molang`, resolving some crashes caused by malformed MoLang expressions.
|
||||
|
||||
### Particles
|
||||
- Added a `chance` requirement type for Pokémon interactions.
|
||||
|
||||
### Localization
|
||||
- Updated translations for:
|
||||
- French
|
||||
- Canadian French
|
||||
- Korean
|
||||
- Portuguese
|
||||
- Simplified Chinese
|
||||
- Spanish
|
||||
@@ -0,0 +1,137 @@
|
||||
# Changelog
|
||||
## [1.7.2 (January 25th, 2026)](#1-7-2)
|
||||
|
||||
### Additions
|
||||
- Added Saccharine wood furniture for Adorn.
|
||||
- Added the Partner Mark, which party Pokémon have a very small chance to earn as the player walks, provided they have enough friendship.
|
||||
- Added decorative block models for existing items: Potion, Super Potion, Hyper Potion, Max Potion, Full Restore, Antidote, Awakening, Burn Heal, Ice Heal, Paralyze Heal, Full Heal, Ether, Elixir, Max Ether, Max Elixir, X Accuracy, X Attack, X Defence, X Special Attack, X Special Defence, X Speed, Dire Hit, Guard Spec, Weakness Policy, Blunder Policy, Cleanse Tag, and Spell Tag.
|
||||
- Added decorative sign blocks called Plaques.
|
||||
- Added ride style labels to ride stats in Pokédex, as well as ride style icons in the summary GUI.
|
||||
- Added more seasonings for sinister tea:
|
||||
- Mental Herb - Mental Restoration I for 10 seconds, which staves off Insomnia.
|
||||
- White Herb - Removes negative effects.
|
||||
- Milk, Moomoo Milk - Removes effects.
|
||||
- Added dispenser support for:
|
||||
- Applying a Honey Bottle to Saccharine Logs.
|
||||
- Washing honey off of Saccharine Slathered Logs.
|
||||
- Applying and removing honey on Saccharine Leaves.
|
||||
- Added riding statistics: `Distance by Pokémon on Land`, `Distance by Pokémon in Air` and `Distance by Pokémon in Liquid`.
|
||||
|
||||
### New rideable Pokémon
|
||||
- Honchkrow
|
||||
- Mantine
|
||||
|
||||
### Pokémon Added
|
||||
|
||||
#### Gen 5
|
||||
- Throh
|
||||
- Sawk
|
||||
|
||||
#### Gen 6
|
||||
- Litleo
|
||||
- Pyroar
|
||||
- Spritzee
|
||||
- Aromatisse
|
||||
- Swirlix
|
||||
- Slurpuff
|
||||
|
||||
### Model updates for the following Pokémon
|
||||
- Falinks
|
||||
- Cottonee
|
||||
- Whimsicott
|
||||
- Ferroseed
|
||||
- Ferrothorn
|
||||
- Chingling
|
||||
- Chimecho
|
||||
|
||||
### Animation updates for the following Pokémon
|
||||
- Mantine (ride animations)
|
||||
- Flygon (ride jump animation)
|
||||
- Honchkrow (ride animations)
|
||||
- Croagunk
|
||||
- Toxicroak
|
||||
|
||||
### Changes
|
||||
- Added a new config option, `Enable In-Flight Dismounting` (default: off), which lets you dismount while riding a Pokémon in the air. This is the textbook definition of caveat emptor.
|
||||
- Ride sounds have been separated into stereo for passengers and mono for other players. Riding will now sound more spacious.
|
||||
- Battle AI now uses a smarter threshold for switching, reducing unnecessary switches.
|
||||
- AI will always use the most damaging move when at low HP and when it is not switching, improving endgame decision-making.
|
||||
- Items given from interacting with Saccharine Leaves are placed in the active hotbar slot if possible.
|
||||
- Added `label` as an alternate key to the `tag` property.
|
||||
|
||||
### Fixes
|
||||
- Fixed crashing when viewing another player in spectator mode. Some said this was reason to release this update a month ago. They were probably right.
|
||||
- Fixed crashing when sending a Pokémon out after editing its form.
|
||||
- Fixed all Pokémon being saved to chunks and never despawning even when they should be.
|
||||
- Fixed Poké Snacks crashing if there was no available spawn.
|
||||
- Fixed Poké Snack / Bait effects so that EV Yield, Type, and Egg Group filters now all apply together when weighting spawns. And you thought you were going crazy.
|
||||
- Fixed Furfrou not being trimmable on NeoForge specifically.
|
||||
- Fixed honey from Saccharine Leaves being harvestable at less than the max age.
|
||||
- Fixed possible error on world generation when Combee are placed in naturally generated bee nests.
|
||||
- Fixed Galarian Weezing crashing the world if it decides to blink the wrong way. The same could happen to you!
|
||||
- Fixed Galarian Mr. Mime incorrectly being rideable. Some would argue that regular Mr. Mime shouldn't be rideable, but that would make them wrong.
|
||||
- Fixed missing apricorn textures for Adorn blocks.
|
||||
- Fixed Apricorn block model rotation for counters/sinks/cupboards/drawers to match that of most recent version of Adorn.
|
||||
- Fixed item interaction sometimes not working properly when playing on servers.
|
||||
- Fixed Mint Leaves not being usable for filling the Resurrection Machine.
|
||||
- Fixed Super Potion recipes incorrectly using Hondew Berry instead of Aguav Berry. They look similar, to be fair.
|
||||
- Fixed Wishiwashi not schooling properly.
|
||||
- Fixed battle item duplication issue. How did it work? Wouldn't you like to know, weather boy.
|
||||
- Fixed the ordering of Aprijuice's riding stat boosts so they always have the same order.
|
||||
- Fixed the movesets of certain Pokémon being incorrectly sanitized upon reload, causing some forms to keep losing moves.
|
||||
- Fixed selected leading Pokémon in battle not being used when levels are set.
|
||||
- Fixed the bottom half of pasture blocks having an incorrect hit-box when facing north or south.
|
||||
- Fixed gimmicks not being usable in double and triple battles.
|
||||
- Fixed gimmick buttons showing when already used in the same turn in double and triple battles.
|
||||
- Fixed mochi items consuming two items at a time.
|
||||
- Fixed Fresh Start Mochi's EV reset not syncing health changes properly.
|
||||
- Fixed Pokémon spawn influences not being specific to regional forms.
|
||||
- Fixed memory leak from battles not being cleaned up after ending.
|
||||
- Fixed orientation not getting reset after crashing while flying and getting back on the Pokémon.
|
||||
- Fixed shiny Pokémon not respecting the `silent` flag on spawn.
|
||||
- Fixed 'Plain' prefix not being applied to all low-quality Aprijuice.
|
||||
- Fixed Pokémon interactions not playing sound effects when the volume was not specified.
|
||||
- Fixed Pokémon interaction cooldowns taking longer than intended when the Pokémon was in the player’s party.
|
||||
- Fixed Pokémon interactions occasionally crashing the game when spamming an interaction with a 0 cooldown.
|
||||
- Fixed Pokémon fullness decreasing more than intended when the Pokémon was pastured.
|
||||
- Fixed Scraggy line, Milcery line, and Morpeko spawning on unnatural blocks.
|
||||
- Fixed invulnerability-bypassed damage being resisted by invulnerable NPC entities.
|
||||
- Fixed Fabric network packets not being handled immediately, fixing incompatibilities with Supplementaries, Prometheus, Sleep Tight, and others.
|
||||
- Fixed killer not being set early enough on a wild Pokémon entity from `WinInstruction`.
|
||||
- Fixed requirements such as `biomeCondition` crashing the game when used to define Pokémon interactions.
|
||||
- Fixed an issue that prevented registering custom dispenser behaviours (no longer overrides vanilla behaviour).
|
||||
- Fixed an issue navigation that prevented Combee from pathing into and out of Saccharine Leaves.
|
||||
- Added Saccharine Boats and Saccharine Boat with Chests to relevant boat tags.
|
||||
- Fixed Soothe Bell not being properly tagged as a held item.
|
||||
- Fixed `/calculateseatpositions` expecting a locator format that even we don't use. It needs an underscore after "seat".
|
||||
- Fixed the `run_script` Molang function to not fail if the environment's context is null.
|
||||
- Fixed the Molang functions `date_local_time`, `date_of`, `date_is_after` to use the correct date format.
|
||||
|
||||
### Developer
|
||||
- Changed the `owner` parameter in the `OwnerQueryRequirement` interface from `ServerPlayer` to `Player`. This method is now also called on the client to verify whether a Pokémon interaction succeeded, so make sure to update your implementations to handle both server and client contexts.
|
||||
- Added the `pnx` to the `BattleFaintedEvent` and `FormeChangeEvent`.
|
||||
- Added register methods for custom instructions to `ShowdownInterpreter`.
|
||||
- Changed callback operations in `BattlePokemon` to allow multiple callbacks and be mutable.
|
||||
- Added `display_name`, `description`, and `max_pp` functions to the `MoveTemplate` struct.
|
||||
- Changed the implementations of `AIBattleActor` to be open classes to allow extension.
|
||||
- Changed the resource location of Poké Ball icons in the GUI to use the balls namespace instead of Cobblemon's, allowing mods to properly use their own namespace for these textures.
|
||||
|
||||
### Molang & Datapacks
|
||||
- Ride sounds can now be set as exclusive to passengers.
|
||||
- Ride sounds no longer play when submerged unless specified with a new setting.
|
||||
- Exception handling has been added to `run_molang`, resolving some crashes caused by malformed MoLang expressions.
|
||||
- Added the `create_itemstack`, `has_inventory_space`, `set_inventory_slot`, and `give_item` MoLang functions for item and inventory utility.
|
||||
- Added the `get_move_from_id` MoLang function for general move info queries without requiring a Moveset object to access.
|
||||
- Added support for optional message variants in battle activate instructions for more context-specific battle text.
|
||||
- Example: `this.add('-activate', pokemon, 'ability: example', '[msg]message1');` will parse to lang key `cobblemon.battle.activate.example.message1`.
|
||||
|
||||
### Localization
|
||||
- Updated translations for:
|
||||
- French
|
||||
- Canadian French
|
||||
- Simplified Chinese
|
||||
- Ukrainian
|
||||
- Brazilian Portuguese
|
||||
- Spanish
|
||||
- Korean
|
||||
- Japanese
|
||||
@@ -32,6 +32,10 @@ repositories {
|
||||
maven(url = "https://api.modrinth.com/maven")
|
||||
maven(url = "https://maven.neoforged.net/releases")
|
||||
maven(url = "https://maven.gegy.dev")
|
||||
exclusiveContent {
|
||||
forRepository { maven(url = "https://maven.isxander.dev/releases") }
|
||||
filter { includeGroup("dev.isxander") }
|
||||
}
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
@@ -62,6 +66,11 @@ dependencies {
|
||||
|
||||
// Unit Testing
|
||||
testImplementation(libs.bundles.unitTesting)
|
||||
|
||||
// Controlify Compat, same as flywheel so we pick one and only use the api
|
||||
modCompileOnlyApi("dev.isxander:controlify:2.4.3+1.21.1-fabric") {
|
||||
isTransitive = false
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<Test> {
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.core.dispenser.DispenseItemBehavior;
|
||||
import net.minecraft.world.level.block.DispenserBlock;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(DispenserBlock.class)
|
||||
public interface DispenserBlockAccessor {
|
||||
@Accessor("DISPENSER_REGISTRY")
|
||||
static Map<Item, DispenseItemBehavior> getItemBehaviors() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
@@ -21,12 +21,14 @@ import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import com.mojang.blaze3d.Blaze3D;
|
||||
import kotlin.Pair;
|
||||
import kotlin.jvm.functions.Function4;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.MouseHandler;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.util.SmoothDouble;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.joml.Vector2d;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
@@ -146,6 +148,12 @@ public abstract class MouseHandlerMixin {
|
||||
pokeVehicle.clampPassengerRotation(player);
|
||||
}
|
||||
|
||||
for(Function4<LocalPlayer, Double, Double, Double, Vector2d> rideFun : CobblemonClient.INSTANCE.getRidingTurnInputHandler().values()) {
|
||||
Vector2d vec = rideFun.invoke(player, cursorDeltaX, cursorDeltaY, d);
|
||||
cursorDeltaX = vec.x;
|
||||
cursorDeltaY = vec.y;
|
||||
}
|
||||
|
||||
// If the ride is not orientation controllable then return and perform the normal turnPlayer logic
|
||||
if (!(vehicle instanceof OrientationControllable controllableVehicle) || !controllableVehicle.getOrientationController().isActive()) {
|
||||
xMouseSmoother.reset();
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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.integration.controlify;
|
||||
|
||||
import com.cobblemon.mod.common.client.CobblemonClient;
|
||||
import com.cobblemon.mod.common.client.integration.controlify.CobblemonControlifyEntrypoint;
|
||||
import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding;
|
||||
import com.cobblemon.mod.common.pokedex.scanner.PokedexUsageContext;
|
||||
import dev.isxander.controlify.controller.ControllerEntity;
|
||||
import dev.isxander.controlify.ingame.InGameInputHandler;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(InGameInputHandler.class)
|
||||
public class InGameInputHandlerMixin {
|
||||
@Shadow @Final private ControllerEntity controller;
|
||||
|
||||
@Redirect(
|
||||
method = "handleKeybinds()V",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/entity/player/Inventory;swapPaint(D)V"
|
||||
)
|
||||
)
|
||||
public void cobblemon$onHotbarSwitch(Inventory instance, double direction) {
|
||||
PokedexUsageContext usageContext = CobblemonClient.INSTANCE.getPokedexUsageContext();
|
||||
if (usageContext.getScanningGuiOpen()) {
|
||||
usageContext.adjustZoom(direction);
|
||||
return;
|
||||
}
|
||||
|
||||
if (CobblemonControlifyEntrypoint.Companion.getSEND_OUT_POKEMON().on(controller).digitalNow()) {
|
||||
CobblemonClient.INSTANCE.getStorage().shiftSelected(direction < 0);
|
||||
PartySendBinding.INSTANCE.actioned();
|
||||
return;
|
||||
}
|
||||
|
||||
instance.swapPaint(direction);
|
||||
}
|
||||
}
|
||||
@@ -68,7 +68,7 @@ import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||
import com.cobblemon.mod.common.battles.*
|
||||
import com.cobblemon.mod.common.battles.actor.PokemonBattleActor
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.block.DispenserBehaviorRegistry
|
||||
import com.cobblemon.mod.common.block.dispenser.DispenserBehaviorRegistry
|
||||
import com.cobblemon.mod.common.client.CobblemonPack
|
||||
import com.cobblemon.mod.common.command.argument.*
|
||||
import com.cobblemon.mod.common.config.CobblemonConfig
|
||||
@@ -165,7 +165,7 @@ object Cobblemon {
|
||||
val statistics: CobblemonStats = CobblemonStats
|
||||
|
||||
@JvmStatic
|
||||
val builtinPacks = listOf<CobblemonPack>(
|
||||
val builtinPacks = listOf(
|
||||
CobblemonPack(id = "adorncompatibility", name = "Adorn Compatibility", packType = PackType.CLIENT_RESOURCES, activationBehaviour = ResourcePackActivationBehaviour.ALWAYS_ENABLED, neededMods = setOf("adorn")),
|
||||
CobblemonPack(id = "gyaradosjump", name = "Gyarados Jump Patterns", packType = PackType.CLIENT_RESOURCES, activationBehaviour = ResourcePackActivationBehaviour.DEFAULT_ENABLED),
|
||||
CobblemonPack(id = "regionbiasforms", name = "Region Bias Forms", packType = PackType.CLIENT_RESOURCES, activationBehaviour = ResourcePackActivationBehaviour.DEFAULT_ENABLED),
|
||||
|
||||
@@ -21,12 +21,15 @@ import com.cobblemon.mod.common.client.net.callback.partymove.OpenPartyMoveCallb
|
||||
import com.cobblemon.mod.common.client.net.cooking.ToggleCookingPotLidHandler
|
||||
import com.cobblemon.mod.common.client.net.data.CobblemonMechanicsSyncHandler
|
||||
import com.cobblemon.mod.common.client.net.data.DataRegistrySyncPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.data.PokemonInteractionsSyncHandler
|
||||
import com.cobblemon.mod.common.client.net.data.RideSettingsSyncHandler
|
||||
import com.cobblemon.mod.common.client.net.debug.OpenRidingStatsDebugGUIHandler
|
||||
import com.cobblemon.mod.common.client.net.dialogue.DialogueClosedHandler
|
||||
import com.cobblemon.mod.common.client.net.dialogue.DialogueOpenedHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.*
|
||||
import com.cobblemon.mod.common.client.net.effect.PokeSnackBlockParticlesHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.RunPosableMoLangHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.SaccharineLogBlockParticlesHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormEntityParticleHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormParticleHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.ExpGainedDataPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.InteractPokemonUIPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.PokedexUIPacketHandler
|
||||
@@ -34,7 +37,11 @@ import com.cobblemon.mod.common.client.net.gui.SummaryUIPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.npc.CloseNPCEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.npc.OpenNPCEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.orientation.ClientboundUpdateOrientationHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.*
|
||||
import com.cobblemon.mod.common.client.net.pasture.ClosePastureHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.OpenPastureHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.PokemonPasturedHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.PokemonUnpasturedHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.UpdatePastureConflictFlagHandler
|
||||
import com.cobblemon.mod.common.client.net.pokedex.ServerConfirmedRegisterHandler
|
||||
import com.cobblemon.mod.common.client.net.pokemon.update.ClientboundUpdateRidingStateHandler
|
||||
import com.cobblemon.mod.common.client.net.pokemon.update.PokemonUpdatePacketHandler
|
||||
@@ -52,7 +59,14 @@ import com.cobblemon.mod.common.client.net.storage.party.SetPartyPokemonHandler
|
||||
import com.cobblemon.mod.common.client.net.storage.party.SetPartyReferenceHandler
|
||||
import com.cobblemon.mod.common.client.net.storage.pc.*
|
||||
import com.cobblemon.mod.common.client.net.toast.ToastPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.*
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeAcceptanceChangedHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeCancelledHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeCompletedHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeOfferExpiredHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeOfferNotificationHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeProcessStartedHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeStartedHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeUpdatedHandler
|
||||
import com.cobblemon.mod.common.net.PacketRegisterInfo
|
||||
import com.cobblemon.mod.common.net.messages.client.CalculateSeatPositionsPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.OpenBehaviourEditorPacket
|
||||
@@ -69,12 +83,20 @@ import com.cobblemon.mod.common.net.messages.client.data.*
|
||||
import com.cobblemon.mod.common.net.messages.client.debug.RequestOpenRidingStatsDebugGUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueClosedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueOpenedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.*
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.PokeSnackBlockParticlesPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SaccharineLogBlockParticlesPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticlePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.npc.CloseNPCEditorPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.npc.OpenNPCEditorPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.orientation.ClientboundUpdateDriverInputPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.orientation.ClientboundUpdateOrientationPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.*
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.ClosePasturePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.OpenPasturePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonPasturedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonUnpasturedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.UpdatePastureConflictFlagPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pokedex.ServerConfirmedRegisterPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.*
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.AddEvolutionPacket
|
||||
@@ -94,19 +116,43 @@ import com.cobblemon.mod.common.net.messages.client.storage.party.InitializePart
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.party.MoveClientPartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.party.SetPartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.party.SetPartyReferencePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.*
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.ClosePCPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.InitializePCPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.MoveClientPCPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.OpenPCPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.RenamePCBoxPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.SetPCBoxPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.SetPCPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.ChangePCBoxWallpaperPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.RequestPCBoxWallpapersPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.SetPCBoxWallpapersPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.UnlockPCBoxWallpaperPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.toast.ToastPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.*
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeAcceptanceChangedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeCancelledPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeCompletedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferExpiredPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferNotificationPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeProcessStartedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeStartedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeUpdatedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.ExpGainedDataPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.InteractPokemonUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.PokedexUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.SummaryUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.*
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.*
|
||||
import com.cobblemon.mod.common.net.messages.server.BattleChallengePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.BattleChallengeResponsePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.BenchMovePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.RequestMoveSwapPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.RequestPlayerInteractionsPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.SelectStarterPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.SendOutPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.BattleSelectActionsPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamLeavePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamRequestPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamResponsePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.RemoveSpectatorPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.SpectateBattlePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.behaviour.DamageOnCollisionPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.behaviour.SetEntityBehaviourPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.block.AdjustBlockEntityViewerCountPacket
|
||||
@@ -131,7 +177,11 @@ import com.cobblemon.mod.common.net.messages.server.pasture.UnpasturePokemonPack
|
||||
import com.cobblemon.mod.common.net.messages.server.pokedex.scanner.FinishScanningPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokedex.scanner.StartScanningPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.interact.InteractPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.*
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.ServerboundUpdateRidingStatePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetActiveMarkPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetItemHiddenPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetMarkingsPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetNicknamePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.evolution.AcceptEvolutionPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.DismountPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateDriverInputPacket
|
||||
@@ -142,11 +192,21 @@ import com.cobblemon.mod.common.net.messages.server.storage.party.MovePartyPokem
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.party.ReleasePartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.party.SwapPartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.pc.*
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.*
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.AcceptTradeRequestPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.CancelTradePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.ChangeTradeAcceptancePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.OfferTradePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.PerformTradePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.UpdateTradeOfferPacket
|
||||
import com.cobblemon.mod.common.net.serverhandling.ChallengeHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.ChallengeResponseHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.RequestInteractionsHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.*
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.BattleSelectActionsHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.RemoveSpectatorHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.SpectateBattleHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.TeamLeaveHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.TeamRequestHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.TeamRequestResponseHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.behaviour.DamageOnCollisionPacketHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.behaviour.SetEntityBehaviourHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.block.AdjustBlockEntityViewerCountHandler
|
||||
@@ -172,7 +232,11 @@ import com.cobblemon.mod.common.net.serverhandling.pasture.UnpasturePokemonHandl
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokedex.scanner.FinishScanningHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokedex.scanner.StartScanningHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.interact.InteractPokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.*
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.ServerboundUpdateRidingStateHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetActiveMarkHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetItemHiddenHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetMarkingsHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetNicknameHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.riding.DismountPokemonPacketHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.riding.DriverInputPacketHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.riding.ServerboundUpdateRiderRotationHandler
|
||||
@@ -186,7 +250,12 @@ import com.cobblemon.mod.common.net.serverhandling.storage.party.MovePartyPokemo
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.party.ReleasePCPokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.party.SwapPartyPokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.pc.*
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.*
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.AcceptTradeRequestHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.CancelTradeHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.ChangeTradeAcceptanceHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.OfferTradeHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.PerformTradeHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.UpdateTradeOfferHandler
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
@@ -332,7 +401,7 @@ object CobblemonNetwork {
|
||||
// Data registries
|
||||
list.add(PacketRegisterInfo(AbilityRegistrySyncPacket.ID, AbilityRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(CobblemonMechanicsSyncPacket.ID, CobblemonMechanicsSyncPacket::decode, CobblemonMechanicsSyncHandler))
|
||||
list.add(PacketRegisterInfo(PokemonInteractionsSyncPacket.ID, PokemonInteractionsSyncPacket::decode, PokemonInteractionsSyncHandler))
|
||||
list.add(PacketRegisterInfo(PokemonInteractionsSyncPacket.ID, PokemonInteractionsSyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(MovesRegistrySyncPacket.ID, MovesRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(BerryRegistrySyncPacket.ID, BerryRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(SpeciesRegistrySyncPacket.ID, SpeciesRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
|
||||
@@ -499,8 +499,8 @@ open class PokemonBattle(
|
||||
}
|
||||
|
||||
fun stop() {
|
||||
end()
|
||||
writeShowdownAction(">forcetie") // This will terminate the Showdown connection
|
||||
end()
|
||||
}
|
||||
|
||||
fun checkForInputDispatch() {
|
||||
|
||||
+15
-23
@@ -59,40 +59,32 @@ object PokemonInteractions : JsonDataRegistry<PokemonInteractionSet> {
|
||||
.setPrettyPrinting()
|
||||
.create()
|
||||
|
||||
val speciesInteractions = mutableListOf<PokemonInteractionSet>()
|
||||
val generalInteractions = mutableListOf<PokemonInteractionSet>()
|
||||
val interactions = mutableListOf<PokemonInteractionSet>()
|
||||
|
||||
override fun sync(player: ServerPlayer) {
|
||||
PokemonInteractionsSyncPacket(
|
||||
speciesInteractions,
|
||||
generalInteractions,
|
||||
).sendToPlayer(player)
|
||||
PokemonInteractionsSyncPacket(interactions).sendToPlayer(player)
|
||||
}
|
||||
|
||||
override fun reload(data: Map<ResourceLocation, PokemonInteractionSet>) {
|
||||
speciesInteractions.clear()
|
||||
generalInteractions.clear()
|
||||
val split = data.entries.partition { it.value.requirements.any { requirement -> requirement is PokemonPropertiesRequirement && requirement.target.species != null } }
|
||||
speciesInteractions.addAll(split.first.map {it.value})
|
||||
generalInteractions.addAll(split.second.map {it.value})
|
||||
Cobblemon.LOGGER.info("Loaded {} Pokémon interaction sets", data.size)
|
||||
interactions.clear()
|
||||
val split = data.entries
|
||||
.partition {
|
||||
it.value.requirements.any { requirement -> requirement is PokemonPropertiesRequirement && requirement.target.species != null }
|
||||
}
|
||||
|
||||
// Put the species specific interactions first as they take priority
|
||||
interactions.addAll(split.first.map {it.value})
|
||||
interactions.addAll(split.second.map {it.value})
|
||||
|
||||
Cobblemon.LOGGER.info("Loaded {} Pokémon interaction sets", interactions.size)
|
||||
}
|
||||
|
||||
fun findInteraction(pokemon: PokemonEntity): PokemonInteraction? {
|
||||
val setCheck: (PokemonInteractionSet) -> Boolean = { it.requirements.all { req -> req.check(pokemon.pokemon) }}
|
||||
val interactionCheck: (PokemonInteraction) -> Boolean = { it.requirements.all { req -> req.check(pokemon.pokemon) } && !pokemon.pokemon.isOnInteractionCooldown(it.grouping) }
|
||||
// species-specific interactions take priority
|
||||
val validInteractions = speciesInteractions
|
||||
return interactions
|
||||
.filter(setCheck)
|
||||
.flatMap { it.interactions }
|
||||
.filter(interactionCheck)
|
||||
.toMutableList()
|
||||
if (validInteractions.isEmpty()) { // if all species-specific interactions are absent/on cooldown, fallback to more generic ones
|
||||
validInteractions.addAll(generalInteractions.filter(setCheck).flatMap { it.interactions }
|
||||
.filter(interactionCheck)
|
||||
)
|
||||
}
|
||||
|
||||
return validInteractions.randomOrNull()
|
||||
.firstOrNull(interactionCheck)
|
||||
}
|
||||
}
|
||||
+3
-11
@@ -43,17 +43,9 @@ data class PokemonInteractionSet(
|
||||
|
||||
companion object {
|
||||
fun decode(buffer: FriendlyByteBuf): PokemonInteractionSet {
|
||||
val requirements = buffer.readList { it ->
|
||||
CobblemonRequirementAdapter.decode(it)
|
||||
}
|
||||
val interactions = buffer.readList { it ->
|
||||
PokemonInteraction.decode(it)
|
||||
}
|
||||
|
||||
return PokemonInteractionSet(
|
||||
requirements,
|
||||
interactions,
|
||||
)
|
||||
val requirements = buffer.readList(CobblemonRequirementAdapter::decode)
|
||||
val interactions = buffer.readList(PokemonInteraction::decode)
|
||||
return PokemonInteractionSet(requirements, interactions)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,6 +368,11 @@ object MoLangFunctions {
|
||||
val b = format.parse(dateB)
|
||||
DoubleValue(a.after(b))
|
||||
},
|
||||
"get_move_from_id" to java.util.function.Function { params ->
|
||||
val moveId = params.getString(0)
|
||||
val moveTemplate = Moves.getByName(moveId)
|
||||
return@Function moveTemplate?.struct ?: DoubleValue.ZERO
|
||||
},
|
||||
"create_simple_party_provider" to java.util.function.Function { params ->
|
||||
val partyProvider = SimplePartyProvider()
|
||||
return@Function partyProvider.struct
|
||||
@@ -378,6 +383,13 @@ object MoLangFunctions {
|
||||
val pickupItem = ObtainableItem(item = item, pickupPriority = pickupPriority)
|
||||
return@Function pickupItem.struct
|
||||
},
|
||||
"create_itemstack" to java.util.function.Function { params ->
|
||||
val itemId = params.getString(0).asIdentifierDefaultingNamespace()
|
||||
val item = BuiltInRegistries.ITEM.get(itemId) ?: return@Function DoubleValue.ZERO
|
||||
val count = params.getIntOrNull(1) ?: 1
|
||||
val itemStack = ItemStack(item, count)
|
||||
return@Function ObjectValue(itemStack)
|
||||
},
|
||||
"file" to java.util.function.Function { MoLangLoadedFilesCache.struct }
|
||||
)
|
||||
val biomeFunctions = mutableListOf<(Holder<Biome>) -> HashMap<String, java.util.function.Function<MoParams, Any>>>()
|
||||
@@ -583,6 +595,62 @@ object MoLangFunctions {
|
||||
}
|
||||
return@put items
|
||||
}
|
||||
map.put("has_inventory_space") { _ ->
|
||||
val inventory = player.inventory
|
||||
return@put if (inventory.getFreeSlot() != -1) DoubleValue.ONE else DoubleValue.ZERO
|
||||
}
|
||||
map.put("set_inventory_slot") { params ->
|
||||
val slot = params.getInt(0)
|
||||
val inventory = player.inventory
|
||||
if (slot !in 0 until inventory.containerSize) return@put DoubleValue.ZERO
|
||||
|
||||
val value = params.getOrNull<MoValue>(1) ?: return@put DoubleValue.ZERO
|
||||
|
||||
val stack: ItemStack? = when (value) {
|
||||
is ObjectValue<*> -> value.obj as? ItemStack
|
||||
is StringValue -> {
|
||||
val id = ResourceLocation.parse(value.value)
|
||||
val item = player.registryAccess().registryOrThrow(Registries.ITEM).get(id) ?: return@put DoubleValue.ZERO
|
||||
ItemStack(item)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
|
||||
if (stack == null) return@put DoubleValue.ZERO
|
||||
|
||||
inventory.setItem(slot, stack)
|
||||
return@put DoubleValue.ONE
|
||||
}
|
||||
map.put("give_item") { params ->
|
||||
val inventory = player.inventory
|
||||
val freeSlot = inventory.getFreeSlot()
|
||||
val value = params.getOrNull<MoValue>(0) ?: return@put DoubleValue.ZERO
|
||||
val dropIfFull = params.getBooleanOrNull(1) ?: false
|
||||
|
||||
val stack: ItemStack? = when (value) {
|
||||
is ObjectValue<*> -> value.obj as? ItemStack
|
||||
is StringValue -> {
|
||||
val id = ResourceLocation.parse(value.value)
|
||||
val item = player.registryAccess().registryOrThrow(Registries.ITEM).get(id) ?: return@put DoubleValue.ZERO
|
||||
ItemStack(item)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
|
||||
if (stack == null) return@put DoubleValue.ZERO
|
||||
|
||||
if (freeSlot == -1) {
|
||||
if (dropIfFull) {
|
||||
player.drop(stack, false)
|
||||
return@put DoubleValue.ONE
|
||||
} else {
|
||||
return@put DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
|
||||
inventory.setItem(freeSlot, stack)
|
||||
return@put DoubleValue.ONE
|
||||
}
|
||||
map.put("face") { params -> ObjectValue(PlayerDialogueFaceProvider(player.uuid, params.getBooleanOrNull(0) != false)) }
|
||||
map.put("swing_hand") { _ -> player.swing(player.usedItemHand) }
|
||||
map.put("food_level") { _ -> DoubleValue(player.foodData.foodLevel) }
|
||||
@@ -626,8 +694,7 @@ object MoLangFunctions {
|
||||
}
|
||||
map.put("active_dialogue") { _ ->
|
||||
if (player.isInDialogue) {
|
||||
player.activeDialogue?.dialogueId.toString()
|
||||
return@put DoubleValue.ONE
|
||||
return@put player.activeDialogue?.toMoLangStruct() ?: DoubleValue.ZERO
|
||||
} else {
|
||||
DoubleValue.ZERO
|
||||
}
|
||||
|
||||
@@ -58,12 +58,15 @@ open class MoveTemplate(
|
||||
val struct: MoStruct by lazy {
|
||||
QueryStruct(hashMapOf())
|
||||
.addFunction("name") { StringValue(name) }
|
||||
.addFunction("display_name") { StringValue(displayName.string) }
|
||||
.addFunction("description") { StringValue(description.string) }
|
||||
.addFunction("type") { StringValue(elementalType.showdownId) }
|
||||
.addFunction("damage_category") { StringValue(damageCategory.name) }
|
||||
.addFunction("power") { DoubleValue(power) }
|
||||
.addFunction("target") { StringValue(target.name) }
|
||||
.addFunction("accuracy") { DoubleValue(accuracy) }
|
||||
.addFunction("pp") { DoubleValue(pp) }
|
||||
.addFunction("max_pp") { DoubleValue(maxPp) }
|
||||
.addFunction("priority") { DoubleValue(priority) }
|
||||
.addFunction("crit_ratio") { DoubleValue(critRatio) }
|
||||
}
|
||||
|
||||
-4
@@ -41,10 +41,6 @@ interface CompositeRidingStrategy<T : CompositeSettings> {
|
||||
toState: RidingBehaviourState,
|
||||
toSettings: RidingBehaviourSettings
|
||||
) {
|
||||
if (vehicle.level().isClientSide) {
|
||||
val fromSettings = if (settings.defaultBehaviour == toSettings) settings.alternateBehaviour else settings.defaultBehaviour
|
||||
|
||||
}
|
||||
toState.stamina.set(fromState.stamina.get())
|
||||
toState.rideVelocity.set(fromState.rideVelocity.get())
|
||||
fromState.reset()
|
||||
|
||||
+13
-12
@@ -22,6 +22,7 @@ import com.cobblemon.mod.common.api.riding.posing.PoseOption
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.api.riding.sound.RideSoundSettingsList
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.client.CobblemonClient
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.blockPositionsAsListRounded
|
||||
@@ -144,11 +145,12 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
|
||||
) {
|
||||
val sprintTimerTickLength = 7 // Emulate vanillas tick timer length
|
||||
var hasDoubleTapped = false
|
||||
val forward = Minecraft.getInstance().player?.input?.up == true
|
||||
|
||||
// If you are not sprinting and you just pressed down and theres no
|
||||
if (!state.forwardHeldLastTick.get() && Minecraft.getInstance().options.keyUp.isDown() && !state.sprinting.get() && state.sprintTickTimer.get() == 0) {
|
||||
if (!state.forwardHeldLastTick.get() && forward && !state.sprinting.get() && state.sprintTickTimer.get() == 0) {
|
||||
state.sprintTickTimer.set(sprintTimerTickLength)
|
||||
} else if (!state.forwardHeldLastTick.get() && Minecraft.getInstance().options.keyUp.isDown() && state.sprintTickTimer.get() != 0) { // If has double tapped
|
||||
} else if (!state.forwardHeldLastTick.get() && forward && state.sprintTickTimer.get() != 0) { // If has double tapped
|
||||
hasDoubleTapped = true
|
||||
}else if(!state.sprinting.get() && state.sprintTickTimer.get() > 0) {
|
||||
state.sprintTickTimer.set(state.sprintTickTimer.get() - 1)
|
||||
@@ -156,9 +158,9 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
|
||||
state.sprintTickTimer.set(0)
|
||||
}
|
||||
|
||||
val tryingToSprint = (Minecraft.getInstance().options.keySprint.isDown() && Minecraft.getInstance().options.keyUp.isDown()) || hasDoubleTapped
|
||||
val tryingToSprint = hasDoubleTapped || CobblemonClient.ridingSprintHandler.any { it.value.invoke() }
|
||||
|
||||
if (state.stamina.get() <= 0.0f || !Minecraft.getInstance().options.keyUp.isDown()) {
|
||||
if (state.stamina.get() <= 0.0f || !forward) {
|
||||
// If stamina runs out or the player is not holding forward then stop sprinting
|
||||
state.sprinting.set(false)
|
||||
if (state.stamina.get() <= 0.0f) {
|
||||
@@ -172,8 +174,8 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
|
||||
state.sprinting.set(true)
|
||||
}
|
||||
|
||||
// Take not of whether forward was held last tick
|
||||
state.forwardHeldLastTick.set(Minecraft.getInstance().options.keyUp.isDown())
|
||||
// Take note of whether forward was held last tick
|
||||
state.forwardHeldLastTick.set(forward)
|
||||
}
|
||||
|
||||
fun tickStamina(
|
||||
@@ -187,17 +189,16 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
|
||||
return
|
||||
}
|
||||
|
||||
var newStam = stam
|
||||
|
||||
val stamDrainRate = (1.0f / vehicle.runtime.resolveDouble(settings.staminaExpr ?: globalHorse.staminaExpr!!)).toFloat() / 20.0f
|
||||
|
||||
if (state.sprinting.get()) {
|
||||
newStam = max(0.0f,stam - stamDrainRate)
|
||||
|
||||
val newStam = if (state.sprinting.get()) {
|
||||
max(0.0f,stam - stamDrainRate)
|
||||
} else {
|
||||
newStam = min(1.0f,stam + stamDrainRate * 4)
|
||||
min(1.0f,stam + stamDrainRate * 4)
|
||||
}
|
||||
|
||||
state.stamina.set(newStam)
|
||||
state.stamina.set(newStam.coerceIn(0F, 1F))
|
||||
}
|
||||
|
||||
override fun updatePassengerRotation(
|
||||
|
||||
+2
-2
@@ -100,7 +100,7 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
) {
|
||||
if(vehicle.level().isClientSide) {
|
||||
if (vehicle.level().isClientSide) {
|
||||
handleBoosting(state, vehicle)
|
||||
tickStamina(settings, state, vehicle)
|
||||
}
|
||||
@@ -147,7 +147,7 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
val stamDrainRate = (1.0f / boostTime).toFloat()
|
||||
|
||||
val newStam = if (state.boosting.get()) max(0.0f,stam - stamDrainRate)
|
||||
else min(1.0f,stam + stamDrainRate)
|
||||
else (stam + stamDrainRate).coerceIn(0F, 1F)
|
||||
|
||||
state.stamina.set(newStam)
|
||||
}
|
||||
|
||||
+62
-63
@@ -26,7 +26,7 @@ import net.minecraft.world.entity.Entity
|
||||
/**
|
||||
* A [SpawningInfluence] that applies some number of SpawnBait effects.
|
||||
*
|
||||
* @author Hiroku, Plastered_Crab
|
||||
* @author Hiroku, Plastered_Crab, ppVon
|
||||
* @since March 18th, 2025
|
||||
*/
|
||||
open class SpawnBaitInfluence(val effects: List<SpawnBait.Effect>, val onUsed: (time: Int, entity: PokemonEntity?) -> Unit = { _, _ -> }) : SpawningInfluence {
|
||||
@@ -50,85 +50,84 @@ open class SpawnBaitInfluence(val effects: List<SpawnBait.Effect>, val onUsed: (
|
||||
}
|
||||
}
|
||||
|
||||
// EV related bait effects
|
||||
// EV, Type, and Egg Group related bait effects
|
||||
override fun affectWeight(detail: SpawnDetail, spawnablePosition: SpawnablePosition, weight: Float): Float {
|
||||
val merged = SpawnBaitUtils.mergeEffects(effects)
|
||||
|
||||
val hasRelevantEffects =
|
||||
merged.any { it.type == Effects.EV } ||
|
||||
merged.any { it.type == Effects.TYPING } ||
|
||||
merged.any { it.type == Effects.EGG_GROUP }
|
||||
|
||||
if (!hasRelevantEffects) {
|
||||
return super.affectWeight(detail, spawnablePosition, weight)
|
||||
}
|
||||
|
||||
val pokemonDetail = detail as? PokemonSpawnDetail
|
||||
?: return super.affectWeight(detail, spawnablePosition, weight)
|
||||
|
||||
val detailSpecies = pokemonDetail.pokemon.species
|
||||
?.let { PokemonSpecies.getByName(it) }
|
||||
?: return super.affectWeight(detail, spawnablePosition, weight)
|
||||
|
||||
val formData = detailSpecies.getForm(pokemonDetail.pokemon.aspects)
|
||||
|
||||
var newWeight = weight
|
||||
var used = false
|
||||
|
||||
// if bait exists and any effects are related to EV yields
|
||||
if (merged.any { it.type == Effects.EV }){
|
||||
if (detail is PokemonSpawnDetail) {
|
||||
val detailSpecies = detail.pokemon.species?.let { PokemonSpecies.getByName(it) }
|
||||
val baitEVStat = effects.firstOrNull { it.type == Effects.EV }?.subcategory?.path?.let { Stats.getStat(it) }
|
||||
if (merged.any { it.type == Effects.EV }) {
|
||||
val evEffect = effects.firstOrNull { it.type == Effects.EV }
|
||||
val baitEVStat = evEffect?.subcategory?.path?.let { Stats.getStat(it) }
|
||||
|
||||
if (detailSpecies != null && baitEVStat != null) {
|
||||
val detailAspects = detail.pokemon.aspects
|
||||
val formData = detailSpecies.getForm(detailAspects)
|
||||
val evYieldValue = formData.evYield[baitEVStat]?.toFloat() ?: 0f
|
||||
return when {
|
||||
evYieldValue > 0 -> {
|
||||
markUsed()
|
||||
super.affectWeight(detail, spawnablePosition, weight)
|
||||
}
|
||||
else -> {
|
||||
markUsed()
|
||||
super.affectWeight(detail, spawnablePosition, 0f)
|
||||
}
|
||||
}
|
||||
if (baitEVStat != null) {
|
||||
val evYieldValue = formData.evYield[baitEVStat]?.toFloat() ?: 0f
|
||||
used = true
|
||||
|
||||
if (evYieldValue <= 0f) {
|
||||
newWeight = 0f
|
||||
} else {
|
||||
LOGGER.debug("Boosted weight value");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if bait exists and any effects are related to Typing
|
||||
if (merged.any { it.type == Effects.TYPING }){
|
||||
if (detail is PokemonSpawnDetail) {
|
||||
val detailSpecies = detail.pokemon.species?.let { PokemonSpecies.getByName(it) }
|
||||
val baitEffect = effects.firstOrNull { it.type == Effects.TYPING }
|
||||
val baitTypingEffect = baitEffect?.subcategory?.path?.let { ElementalTypes.get(it) }
|
||||
if (newWeight > 0f && merged.any { it.type == Effects.TYPING }) {
|
||||
val baitEffect = effects.firstOrNull { it.type == Effects.TYPING }
|
||||
val baitTypingEffect = baitEffect?.subcategory?.path?.let { ElementalTypes.get(it) }
|
||||
|
||||
if (detailSpecies != null && baitTypingEffect != null) {
|
||||
val detailAspects = detail.pokemon.aspects
|
||||
val formData = detailSpecies.getForm(detailAspects)
|
||||
val isMatchingType = formData.types.contains(baitTypingEffect)
|
||||
return when {
|
||||
isMatchingType -> {
|
||||
markUsed()
|
||||
super.affectWeight(detail, spawnablePosition, weight * baitEffect.value.toFloat())
|
||||
}
|
||||
else -> super.affectWeight(detail, spawnablePosition, weight)
|
||||
}
|
||||
if (baitEffect != null && baitTypingEffect != null) {
|
||||
val isMatchingType = formData.types.contains(baitTypingEffect)
|
||||
used = true
|
||||
|
||||
if (isMatchingType) {
|
||||
newWeight *= baitEffect.value.toFloat()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if bait exists and any effects are related to Egg Groups
|
||||
if (merged.any { it.type == Effects.EGG_GROUP }) {
|
||||
if (detail is PokemonSpawnDetail) {
|
||||
val detailSpecies = detail.pokemon.species?.let { PokemonSpecies.getByName(it) }
|
||||
if (newWeight > 0f && merged.any { it.type == Effects.EGG_GROUP }) {
|
||||
val eggGroupEffects = effects.filter { it.type == Effects.EGG_GROUP }
|
||||
|
||||
if (detailSpecies != null) {
|
||||
val detailAspects = detail.pokemon.aspects
|
||||
val formData = detailSpecies.getForm(detailAspects)
|
||||
|
||||
// Collect all the egg group effects
|
||||
val eggGroupEffects = effects.filter { it.type == Effects.EGG_GROUP }
|
||||
|
||||
// Check if any of the egg group effects match the species' egg groups
|
||||
val matchingEffect = eggGroupEffects.firstOrNull { effect ->
|
||||
val effectEggGroupKey = effect.subcategory?.path ?: return@firstOrNull false
|
||||
val eggGroup = EggGroup.fromIdentifier(effectEggGroupKey)
|
||||
if (eggGroup == null) {
|
||||
LOGGER.warn("Unknown egg group identifier: $effectEggGroupKey")
|
||||
return@firstOrNull false
|
||||
}
|
||||
formData.eggGroups.contains(eggGroup)
|
||||
}
|
||||
|
||||
if (matchingEffect != null) {
|
||||
markUsed()
|
||||
val multiplier = matchingEffect.value
|
||||
return super.affectWeight(detail, spawnablePosition, (weight * multiplier).toFloat())
|
||||
}
|
||||
val matchingEffect = eggGroupEffects.firstOrNull { effect ->
|
||||
val key = effect.subcategory?.path ?: return@firstOrNull false
|
||||
val eggGroup = EggGroup.fromIdentifier(key)
|
||||
if (eggGroup == null) {
|
||||
LOGGER.warn("Unknown egg group identifier: $key")
|
||||
return@firstOrNull false
|
||||
}
|
||||
formData.eggGroups.contains(eggGroup)
|
||||
}
|
||||
|
||||
if (matchingEffect != null) {
|
||||
used = true
|
||||
newWeight *= matchingEffect.value.toFloat()
|
||||
}
|
||||
}
|
||||
return super.affectWeight(detail, spawnablePosition, weight)
|
||||
|
||||
if (used) markUsed()
|
||||
return super.affectWeight(detail, spawnablePosition, newWeight)
|
||||
}
|
||||
}
|
||||
@@ -221,6 +221,7 @@ object BattleRegistry {
|
||||
fun closeBattle(battle: PokemonBattle) {
|
||||
battle.onEndHandlers.forEach { it(battle) }
|
||||
battleMap.remove(battle.battleId)
|
||||
ShowdownService.service.endBattle(battle)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ import java.util.UUID
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
import net.minecraft.network.chat.Component
|
||||
|
||||
class MultiPokemonBattleActor(
|
||||
open class MultiPokemonBattleActor(
|
||||
pokemonList: List<BattlePokemon>,
|
||||
artificialDecider: BattleAI = RandomBattleAI(),
|
||||
uuid: UUID = UUID.randomUUID()
|
||||
|
||||
@@ -24,17 +24,14 @@ import net.minecraft.network.chat.MutableComponent
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class PokemonBattleActor(
|
||||
open class PokemonBattleActor(
|
||||
uuid: UUID,
|
||||
val pokemon: BattlePokemon,
|
||||
override val fleeDistance: Float,
|
||||
artificialDecider: BattleAI = RandomBattleAI()
|
||||
artificialDecider: BattleAI = RandomBattleAI(),
|
||||
) : AIBattleActor(uuid, listOf(pokemon), artificialDecider), EntityBackedBattleActor<PokemonEntity>, FleeableBattleActor {
|
||||
|
||||
override val initialPos: Vec3?
|
||||
init {
|
||||
initialPos = entity?.position()
|
||||
}
|
||||
override val initialPos: Vec3? = pokemon.entity?.position()
|
||||
override fun getName() = pokemon.effectedPokemon.species.translatedName
|
||||
override fun nameOwned(name: String): MutableComponent = Component.literal(name)
|
||||
override fun getWorldAndPosition(): Pair<ServerLevel, Vec3>? {
|
||||
|
||||
@@ -17,7 +17,7 @@ import com.cobblemon.mod.common.util.battleLang
|
||||
import java.util.UUID
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
|
||||
class TrainerBattleActor(
|
||||
open class TrainerBattleActor(
|
||||
val trainerName: String,
|
||||
uuid: UUID,
|
||||
pokemonList: List<BattlePokemon>,
|
||||
|
||||
@@ -27,6 +27,7 @@ interface ShowdownService {
|
||||
fun openConnection()
|
||||
fun closeConnection()
|
||||
fun startBattle(battle: PokemonBattle, messages: Array<String>)
|
||||
fun endBattle(battle: PokemonBattle)
|
||||
fun send(battleId: UUID, messages: Array<String>)
|
||||
fun getRegistryData(type: String): JsonArray
|
||||
fun sendRegistryData(data: Map<String, String>, type: String)
|
||||
|
||||
+5
@@ -129,6 +129,11 @@ class GraalShowdownService : ShowdownService {
|
||||
startBattleFunction.execute(this, battle.battleId.toString(), messages)
|
||||
}
|
||||
|
||||
override fun endBattle(battle: PokemonBattle) {
|
||||
val endBattleFunction = context.getBindings("js").getMember("endBattle")
|
||||
endBattleFunction.execute(battle.battleId.toString())
|
||||
}
|
||||
|
||||
override fun send(battleId: UUID, messages: Array<String>) {
|
||||
sendToShowdown(battleId, messages)
|
||||
}
|
||||
|
||||
+5
@@ -62,6 +62,11 @@ class SocketShowdownService(val host: String = "localhost", val port: Int = 1846
|
||||
send(battle.battleId, messages)
|
||||
}
|
||||
|
||||
override fun endBattle(battle: PokemonBattle) {
|
||||
writer.write(">endbattle ${battle.battleId}\n")
|
||||
acknowledge { Cobblemon.LOGGER.error("Failed to end battle ${battle.battleId}!") }
|
||||
}
|
||||
|
||||
override fun send(battleId: UUID, messages: Array<String>) {
|
||||
for (message in messages) {
|
||||
writer.write("$battleId~$message\n")
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.block
|
||||
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.core.dispenser.DispenseItemBehavior
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.item.alchemy.PotionContents
|
||||
import net.minecraft.world.item.alchemy.Potions
|
||||
import net.minecraft.world.level.block.DispenserBlock
|
||||
|
||||
object DispenserBehaviorRegistry {
|
||||
private val behaviors = mutableMapOf<Item, DispenseItemBehavior>()
|
||||
|
||||
fun register(items: List<Item>, behaviorProvider: (Item) -> DispenseItemBehavior) {
|
||||
for (item in items) {
|
||||
behaviors[item] = behaviorProvider(item)
|
||||
}
|
||||
}
|
||||
|
||||
fun applyBehaviors() {
|
||||
behaviors.forEach { (item, behavior) ->
|
||||
DispenserBlock.registerBehavior(item, behavior)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Seems like there can only 1 behavior per item, so registering the leaves with the honey bottle overrode the honey bottle behavior for the log.
|
||||
// Registering a new behavior with `DispenserBlock.registerBehavior` will override any existing ones for that item, possibly even ones from Minecraft and other mods
|
||||
// Will probably need to use an alternate way of implementing this to avoid conflicts.
|
||||
fun registerDispenserBehaviors() {
|
||||
// register(listOf(PotionContents.createItemStack(Items.POTION, Potions.WATER).item)) { SaccharineLogSlatheredBlock.createBehavior() }
|
||||
// register(listOf(Items.HONEY_BOTTLE)) { SaccharineLogBlock.createBehavior() }
|
||||
// register(listOf(Items.HONEY_BOTTLE, Items.GLASS_BOTTLE)) { item -> SaccharineLeafBlock.createBehavior(item)}
|
||||
applyBehaviors()
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,8 @@ import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.item.alchemy.PotionContents
|
||||
import net.minecraft.world.item.alchemy.Potions
|
||||
import net.minecraft.world.level.BlockGetter
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.LevelAccessor
|
||||
@@ -67,9 +69,16 @@ class SaccharineLeafBlock(settings: Properties) : LeavesBlock(settings) {
|
||||
|
||||
if (blockState.block is SaccharineLeafBlock) {
|
||||
val currentAge = blockState.getValue(AGE)
|
||||
val newAge = when {
|
||||
item == Items.HONEY_BOTTLE && currentAge < MAX_AGE -> (currentAge + 2).coerceAtMost(MAX_AGE)
|
||||
item == Items.GLASS_BOTTLE && currentAge > MIN_AGE -> (currentAge - 2).coerceAtLeast(MIN_AGE)
|
||||
|
||||
val waterBottle = PotionContents.createItemStack(Items.POTION, Potions.WATER).item
|
||||
|
||||
val newAge = when (item) {
|
||||
Items.HONEY_BOTTLE if currentAge < MAX_AGE ->
|
||||
(currentAge + 2).coerceAtMost(MAX_AGE)
|
||||
|
||||
waterBottle if currentAge > MIN_AGE ->
|
||||
(currentAge - 2).coerceAtLeast(MIN_AGE)
|
||||
|
||||
else -> currentAge
|
||||
}
|
||||
|
||||
@@ -79,21 +88,23 @@ class SaccharineLeafBlock(settings: Properties) : LeavesBlock(settings) {
|
||||
stack.shrink(1)
|
||||
|
||||
val dispenserEntity = source.blockEntity
|
||||
val outputItem = if (item == Items.HONEY_BOTTLE) Items.GLASS_BOTTLE else Items.HONEY_BOTTLE
|
||||
val outputItem = Items.GLASS_BOTTLE
|
||||
val outputStack = ItemStack(outputItem)
|
||||
var added = false
|
||||
|
||||
for (i in 0 until dispenserEntity.containerSize) {
|
||||
val slotStack = dispenserEntity.getItem(i)
|
||||
if (dispenserEntity != null) {
|
||||
for (i in 0 until dispenserEntity.containerSize) {
|
||||
val slotStack = dispenserEntity.getItem(i)
|
||||
|
||||
if (slotStack.isEmpty) {
|
||||
dispenserEntity.setItem(i, outputStack.copy())
|
||||
added = true
|
||||
break
|
||||
} else if (slotStack.`is`(outputItem) && slotStack.count < slotStack.maxStackSize) {
|
||||
slotStack.grow(1)
|
||||
added = true
|
||||
break
|
||||
if (slotStack.isEmpty) {
|
||||
dispenserEntity.setItem(i, outputStack.copy())
|
||||
added = true
|
||||
break
|
||||
} else if (slotStack.`is`(outputItem) && slotStack.count < slotStack.maxStackSize) {
|
||||
slotStack.grow(1)
|
||||
added = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.DispenserBlock
|
||||
import net.minecraft.world.level.block.HorizontalDirectionalBlock
|
||||
import net.minecraft.world.level.block.RotatedPillarBlock
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
@@ -37,7 +38,7 @@ class SaccharineLogBlock(properties: Properties) : RotatedPillarBlock(properties
|
||||
fun createBehavior(): DispenseItemBehavior {
|
||||
return DispenseItemBehavior { source, stack ->
|
||||
val level = source.level
|
||||
val facing = source.state.getValue(HorizontalDirectionalBlock.FACING)
|
||||
val facing = source.state.getValue(DispenserBlock.FACING)
|
||||
val pos = source.pos.relative(facing)
|
||||
val blockState = level.getBlockState(pos)
|
||||
|
||||
@@ -50,7 +51,13 @@ class SaccharineLogBlock(properties: Properties) : RotatedPillarBlock(properties
|
||||
}
|
||||
}
|
||||
|
||||
fun changeLogTypeDispenser(level: ServerLevel, pos: BlockPos, newState: BlockState, stack: ItemStack, source: BlockSource) {
|
||||
fun changeLogTypeDispenser(
|
||||
level: ServerLevel,
|
||||
pos: BlockPos,
|
||||
newState: BlockState,
|
||||
stack: ItemStack,
|
||||
source: BlockSource
|
||||
) {
|
||||
level.setBlock(pos, newState, 3)
|
||||
level.gameEvent(null, GameEvent.BLOCK_CHANGE, pos)
|
||||
|
||||
@@ -75,11 +82,23 @@ class SaccharineLogBlock(properties: Properties) : RotatedPillarBlock(properties
|
||||
}
|
||||
|
||||
if (!added) {
|
||||
Containers.dropItemStack(level, source.pos.x.toDouble(), source.pos.y.toDouble(), source.pos.z.toDouble(), glassBottle)
|
||||
Containers.dropItemStack(
|
||||
level,
|
||||
source.pos.x.toDouble(),
|
||||
source.pos.y.toDouble(),
|
||||
source.pos.z.toDouble(),
|
||||
glassBottle
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun changeLogType(level: Level, pos: BlockPos, newState: BlockState, player: Player? = null, itemStack: ItemStack? = null) {
|
||||
fun changeLogType(
|
||||
level: Level,
|
||||
pos: BlockPos,
|
||||
newState: BlockState,
|
||||
player: Player? = null,
|
||||
itemStack: ItemStack? = null
|
||||
) {
|
||||
level.setBlock(pos, newState, 3)
|
||||
level.gameEvent(null, GameEvent.BLOCK_CHANGE, pos)
|
||||
|
||||
@@ -93,7 +112,15 @@ class SaccharineLogBlock(properties: Properties) : RotatedPillarBlock(properties
|
||||
}
|
||||
}
|
||||
|
||||
override fun useItemOn(stack: ItemStack, state: BlockState, level: Level, pos: BlockPos, player: Player, hand: InteractionHand, hitResult: BlockHitResult): ItemInteractionResult {
|
||||
override fun useItemOn(
|
||||
stack: ItemStack,
|
||||
state: BlockState,
|
||||
level: Level,
|
||||
pos: BlockPos,
|
||||
player: Player,
|
||||
hand: InteractionHand,
|
||||
hitResult: BlockHitResult
|
||||
): ItemInteractionResult {
|
||||
val axis = state.getValue(AXIS)
|
||||
val itemStack = player.getItemInHand(hand)
|
||||
if (!level.isClientSide && itemStack.`is`(Items.HONEY_BOTTLE) && axis == Direction.Axis.Y) {
|
||||
|
||||
@@ -16,7 +16,9 @@ import net.minecraft.core.Direction
|
||||
import net.minecraft.util.StringRepresentable
|
||||
import net.minecraft.world.item.context.BlockPlaceContext
|
||||
import net.minecraft.world.level.BlockGetter
|
||||
import net.minecraft.world.level.LevelAccessor
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.block.HorizontalDirectionalBlock
|
||||
import net.minecraft.world.level.block.SimpleWaterloggedBlock
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
@@ -24,6 +26,8 @@ import net.minecraft.world.level.block.state.StateDefinition
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties.HORIZONTAL_FACING
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED
|
||||
import net.minecraft.world.level.block.state.properties.IntegerProperty
|
||||
import net.minecraft.world.level.material.FluidState
|
||||
import net.minecraft.world.level.material.Fluids
|
||||
import net.minecraft.world.phys.shapes.CollisionContext
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import net.minecraft.world.phys.shapes.VoxelShape
|
||||
@@ -45,7 +49,7 @@ class StackableItemBlock(settings: Properties, val type: StackableItemBlockType)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val MAX_AMOUNT: Int = 8
|
||||
val MAX_AMOUNT: Int = 4
|
||||
val AMOUNT: IntegerProperty = IntegerProperty.create("amount", 1, MAX_AMOUNT)
|
||||
|
||||
val CODEC: MapCodec<StackableItemBlock> = RecordCodecBuilder.mapCodec { it.group(
|
||||
@@ -163,6 +167,16 @@ class StackableItemBlock(settings: Properties, val type: StackableItemBlockType)
|
||||
builder.add(HORIZONTAL_FACING, AMOUNT, WATERLOGGED)
|
||||
}
|
||||
|
||||
override fun getFluidState(blockState: BlockState): FluidState? = if (blockState.getValue(WATERLOGGED)) Fluids.WATER.getSource(false) else super.getFluidState(blockState)
|
||||
|
||||
override fun updateShape(state: BlockState, direction: Direction, neighborState: BlockState, world: LevelAccessor, pos: BlockPos, neighborPos: BlockPos): BlockState {
|
||||
if (state.getValue(WATERLOGGED)) {
|
||||
world.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world))
|
||||
}
|
||||
return if (state.getValue(HORIZONTAL_FACING).opposite == direction && !state.canSurvive(world, pos)) Blocks.AIR.defaultBlockState()
|
||||
else super.updateShape(state, direction, neighborState, world, pos, neighborPos)
|
||||
}
|
||||
|
||||
override fun getCollisionShape(state: BlockState, level: BlockGetter, pos: BlockPos, context: CollisionContext): VoxelShape {
|
||||
val direction = state.getValue(HORIZONTAL_FACING)
|
||||
val count = state.getValue(AMOUNT)
|
||||
@@ -175,8 +189,9 @@ class StackableItemBlock(settings: Properties, val type: StackableItemBlockType)
|
||||
|
||||
override fun getStateForPlacement(context: BlockPlaceContext): BlockState? {
|
||||
val blockState = context.level.getBlockState(context.clickedPos)
|
||||
val fluidState = context.level.getFluidState(context.clickedPos)
|
||||
return if (blockState.`is`(this)) blockState.setValue(AMOUNT, min(getMaxAmount(type), (blockState.getValue(AMOUNT) + 1)))
|
||||
else super.getStateForPlacement(context)?.setValue(HORIZONTAL_FACING, context.horizontalDirection.opposite)
|
||||
else super.getStateForPlacement(context)?.setValue(HORIZONTAL_FACING, context.horizontalDirection.opposite)?.setValue(WATERLOGGED, fluidState.type === Fluids.WATER)
|
||||
}
|
||||
|
||||
override fun canBeReplaced(state: BlockState, useContext: BlockPlaceContext): Boolean {
|
||||
|
||||
+4
-2
@@ -8,8 +8,6 @@
|
||||
|
||||
package com.cobblemon.mod.common.block
|
||||
|
||||
import com.cobblemon.mod.common.block.StackableItemBlock.Companion.AMOUNT
|
||||
import com.cobblemon.mod.common.block.StackableItemBlock.Companion.MAX_AMOUNT
|
||||
import com.cobblemon.mod.common.util.rotateShape
|
||||
import com.mojang.serialization.MapCodec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
@@ -23,6 +21,7 @@ import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.state.StateDefinition
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties.HORIZONTAL_FACING
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED
|
||||
import net.minecraft.world.level.block.state.properties.IntegerProperty
|
||||
import net.minecraft.world.phys.shapes.CollisionContext
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import net.minecraft.world.phys.shapes.VoxelShape
|
||||
@@ -40,6 +39,9 @@ class WallAttachedStackableItemBlock(settings: Properties, val type: WallStackab
|
||||
}
|
||||
|
||||
companion object {
|
||||
val MAX_AMOUNT: Int = 8
|
||||
val AMOUNT: IntegerProperty = IntegerProperty.create("amount", 1, MAX_AMOUNT)
|
||||
|
||||
val CODEC: MapCodec<WallAttachedStackableItemBlock> = RecordCodecBuilder.mapCodec { it.group(
|
||||
propertiesCodec(),
|
||||
WallStackableItemBlockType.CODEC.fieldOf("type").forGetter(WallAttachedStackableItemBlock::type)
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.block.dispenser
|
||||
|
||||
import net.minecraft.core.dispenser.BlockSource
|
||||
import net.minecraft.core.dispenser.DispenseItemBehavior
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
|
||||
class ChainedDispenseItemBehavior(private val base: DispenseItemBehavior) : DispenseItemBehavior {
|
||||
private val extras = CopyOnWriteArrayList<DispenseItemBehavior>()
|
||||
|
||||
fun add(behavior: DispenseItemBehavior) {
|
||||
extras.add(behavior)
|
||||
}
|
||||
|
||||
override fun dispense(blockSource: BlockSource, itemStack: ItemStack): ItemStack {
|
||||
|
||||
var current = itemStack
|
||||
for (b in extras) {
|
||||
val prev = current.copy()
|
||||
val next = try {
|
||||
b.dispense(blockSource, current)
|
||||
} catch (t: Throwable) {
|
||||
continue
|
||||
}
|
||||
current = next
|
||||
if (handled(prev, current)) {
|
||||
return current
|
||||
}
|
||||
}
|
||||
|
||||
val beforeBase = current.copy()
|
||||
val afterBase = try {
|
||||
base.dispense(blockSource, current)
|
||||
} catch (_: Throwable) {
|
||||
return current
|
||||
}
|
||||
|
||||
if (handled(beforeBase, afterBase)) {
|
||||
return afterBase
|
||||
}
|
||||
|
||||
return afterBase
|
||||
}
|
||||
|
||||
private fun handled(before: ItemStack, after: ItemStack): Boolean {
|
||||
return !ItemStack.matches(before, after)
|
||||
}
|
||||
|
||||
}
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.block.dispenser
|
||||
|
||||
import com.cobblemon.mod.common.block.SaccharineLeafBlock
|
||||
import com.cobblemon.mod.common.block.SaccharineLogBlock
|
||||
import com.cobblemon.mod.common.block.SaccharineLogSlatheredBlock
|
||||
import com.cobblemon.mod.common.mixin.accessor.DispenserBlockAccessor
|
||||
import net.minecraft.core.dispenser.DispenseItemBehavior
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.item.alchemy.PotionContents
|
||||
import net.minecraft.world.item.alchemy.Potions
|
||||
import net.minecraft.world.level.block.DispenserBlock
|
||||
|
||||
object DispenserBehaviorRegistry {
|
||||
private val behaviors = mutableMapOf<Item, DispenseItemBehavior>()
|
||||
|
||||
fun register(items: List<Item>, behaviorProvider: (Item) -> DispenseItemBehavior) {
|
||||
register(behaviorProvider, items = items)
|
||||
}
|
||||
|
||||
fun register(vararg behaviorProviders: (Item) -> DispenseItemBehavior, items: List<Item>) {
|
||||
for (item in items) {
|
||||
val providedBehaviors = behaviorProviders.map { provider -> provider(item) }
|
||||
|
||||
val existingLocal = behaviors[item]
|
||||
if (existingLocal is ChainedDispenseItemBehavior) {
|
||||
providedBehaviors.forEach { existingLocal.add(it) }
|
||||
continue
|
||||
}
|
||||
|
||||
val currentRegistered = getCurrentRegisteredBehavior(item)
|
||||
if (currentRegistered is ChainedDispenseItemBehavior) {
|
||||
behaviors[item] = currentRegistered
|
||||
providedBehaviors.forEach { currentRegistered.add(it) }
|
||||
continue
|
||||
}
|
||||
|
||||
val base = currentRegistered ?: DispenseItemBehavior.NOOP
|
||||
val chained = ChainedDispenseItemBehavior(base)
|
||||
providedBehaviors.forEach { chained.add(it) }
|
||||
|
||||
behaviors[item] = chained
|
||||
DispenserBlock.registerBehavior(item, chained)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getCurrentRegisteredBehavior(item: Item): DispenseItemBehavior? {
|
||||
return try {
|
||||
val map = DispenserBlockAccessor.getItemBehaviors()
|
||||
map[item]
|
||||
} catch (t: Throwable) {
|
||||
DispenseItemBehavior.LOGGER.error("Failed to read existing dispenser behaviors via mixin accessor", t)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun registerDispenserBehaviors() {
|
||||
register(
|
||||
{ SaccharineLogSlatheredBlock.createBehavior() },
|
||||
items = listOf(
|
||||
PotionContents.createItemStack(
|
||||
Items.POTION,
|
||||
Potions.WATER
|
||||
).item
|
||||
)
|
||||
)
|
||||
register(
|
||||
{ SaccharineLogBlock.createBehavior() },
|
||||
items = listOf(Items.HONEY_BOTTLE)
|
||||
)
|
||||
register(
|
||||
{ item -> SaccharineLeafBlock.createBehavior(item) },
|
||||
items = listOf(
|
||||
Items.HONEY_BOTTLE,
|
||||
PotionContents.createItemStack(
|
||||
Items.POTION,
|
||||
Potions.WATER
|
||||
).item
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -74,6 +74,7 @@ import com.cobblemon.mod.common.entity.boat.CobblemonBoatType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.platform.events.PlatformEvents
|
||||
import com.cobblemon.mod.common.pokedex.scanner.PokedexUsageContext
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.isLookingAt
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.color.block.BlockColor
|
||||
@@ -83,16 +84,19 @@ import net.minecraft.client.gui.screens.Screen
|
||||
import net.minecraft.client.model.BoatModel
|
||||
import net.minecraft.client.model.ChestBoatModel
|
||||
import net.minecraft.client.model.PlayerModel
|
||||
import net.minecraft.client.player.LocalPlayer
|
||||
import net.minecraft.client.renderer.RenderType
|
||||
import net.minecraft.client.renderer.blockentity.HangingSignRenderer
|
||||
import net.minecraft.client.renderer.blockentity.SignRenderer
|
||||
import net.minecraft.client.renderer.entity.EntityRenderer
|
||||
import net.minecraft.client.renderer.entity.LivingEntityRenderer
|
||||
import net.minecraft.client.resources.PlayerSkin
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.packs.resources.ResourceManager
|
||||
import net.minecraft.world.InteractionHand
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.phys.AABB
|
||||
import org.joml.Vector2d
|
||||
|
||||
object CobblemonClient {
|
||||
|
||||
@@ -112,6 +116,8 @@ object CobblemonClient {
|
||||
val battleOverlay: BattleOverlay by lazy { BattleOverlay() }
|
||||
val pokedexUsageContext: PokedexUsageContext by lazy { PokedexUsageContext() }
|
||||
val rideControlsOverlay: RideControlsOverlay by lazy { RideControlsOverlay() }
|
||||
val ridingTurnInputHandler: MutableMap<ResourceLocation, (LocalPlayer, Double, Double, Double) -> Vector2d> = mutableMapOf()
|
||||
val ridingSprintHandler: MutableMap<ResourceLocation, () -> Boolean> = mutableMapOf()
|
||||
|
||||
fun onLogin() {
|
||||
clientPlayerData = ClientGeneralPlayerData()
|
||||
@@ -195,6 +201,8 @@ object CobblemonClient {
|
||||
ClientPlayerIcon.onTick()
|
||||
PartyOverlayDataControl.tick(event.client.isPaused)
|
||||
}
|
||||
|
||||
ridingSprintHandler.put(cobblemonResource("normal")) { Minecraft.getInstance().options.keySprint.isDown }
|
||||
}
|
||||
|
||||
private fun registerTooltipManagers() {
|
||||
|
||||
+1
-3
@@ -507,9 +507,7 @@ class PokemonClientDelegate : PosableState(), PokemonSideDelegate {
|
||||
|
||||
override fun positionRider(passenger: Entity, positionUpdater: MoveFunction) {
|
||||
val locatorName = getSeatLocator(passenger)
|
||||
val locator = this.locatorStates[locatorName]
|
||||
|
||||
if (locator == null) return
|
||||
val locator = this.locatorStates[locatorName] ?: return
|
||||
|
||||
val offset = locator.matrix.getTranslation(Vector3f())
|
||||
.sub(
|
||||
|
||||
@@ -29,6 +29,7 @@ import com.cobblemon.mod.common.client.render.renderScaledGuiItemIcon
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.cobblemon.mod.common.util.toAssetPath
|
||||
import java.util.UUID
|
||||
import net.minecraft.client.DeltaTracker
|
||||
import net.minecraft.client.Minecraft
|
||||
@@ -38,6 +39,7 @@ import net.minecraft.client.gui.components.toasts.AdvancementToast
|
||||
import net.minecraft.client.gui.components.toasts.Toast
|
||||
import net.minecraft.client.gui.screens.ChatScreen
|
||||
import net.minecraft.client.gui.screens.Screen
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.Mth
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.floor
|
||||
@@ -126,6 +128,10 @@ class PartyOverlay : Gui(Minecraft.getInstance()) {
|
||||
val panelX = 0
|
||||
val party = CobblemonClient.storage.party
|
||||
val matrices = context.pose()
|
||||
|
||||
matrices.pushPose()
|
||||
matrices.translate(0.0, 0.0, -100.0)
|
||||
|
||||
if (party.slots.none { it != null }) {
|
||||
if (CobblemonClient.clientPlayerData.promptStarter &&
|
||||
!CobblemonClient.clientPlayerData.starterLocked &&
|
||||
@@ -171,10 +177,11 @@ class PartyOverlay : Gui(Minecraft.getInstance()) {
|
||||
)
|
||||
|
||||
matrices.pushPose()
|
||||
matrices.scale(1F, 1F, 0.2F)
|
||||
matrices.translate(
|
||||
panelX + portraitFrameOffsetX + selectedOffsetX + PORTRAIT_DIAMETER / 2.0 - 1.0,
|
||||
y.toDouble() - 12,
|
||||
0.0
|
||||
-50.0
|
||||
)
|
||||
|
||||
val shouldAnimate = when (Cobblemon.config.partyPortraitAnimations) {
|
||||
@@ -467,7 +474,7 @@ class PartyOverlay : Gui(Minecraft.getInstance()) {
|
||||
)
|
||||
}
|
||||
|
||||
val ballIcon = cobblemonResource("textures/gui/ball/" + pokemon.caughtBall.name.path + ".png")
|
||||
val ballIcon = pokemon.caughtBall.name.toAssetPath("textures/gui/ball/", ".png")
|
||||
val ballHeight = 22
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
@@ -508,5 +515,7 @@ class PartyOverlay : Gui(Minecraft.getInstance()) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
matrices.popPose()
|
||||
}
|
||||
}
|
||||
@@ -195,7 +195,7 @@ abstract class ScrollingWidget<T : ObjectSelectionList.Entry<T>>(
|
||||
return this.width
|
||||
}
|
||||
|
||||
override fun getRowTop(index: Int): Int {
|
||||
public override fun getRowTop(index: Int): Int {
|
||||
return this.y - scrollAmount.toInt() + (index * this.itemHeight)
|
||||
}
|
||||
|
||||
@@ -205,6 +205,19 @@ abstract class ScrollingWidget<T : ObjectSelectionList.Entry<T>>(
|
||||
|
||||
override fun getScrollbarPosition(): Int = this.left + this.width - this.scrollBarWidth
|
||||
|
||||
public override fun ensureVisible(entry: T) {
|
||||
val i = getRowTop(children().indexOf(entry))
|
||||
val topDifference = i - y
|
||||
if (topDifference < 0) {
|
||||
scroll(topDifference)
|
||||
}
|
||||
|
||||
val bottomDifference = bottom - i - itemHeight - 4
|
||||
if (bottomDifference < 0) {
|
||||
scroll(-bottomDifference)
|
||||
}
|
||||
}
|
||||
|
||||
abstract class Slot<T : Slot<T>>(): Entry<T>() {
|
||||
// Override render to show each individual element
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.battle
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.battles.PassActionResponse
|
||||
import com.cobblemon.mod.common.battles.ShowdownActionResponse
|
||||
import com.cobblemon.mod.common.client.CobblemonClient
|
||||
@@ -17,9 +18,18 @@ import com.cobblemon.mod.common.client.gui.CobblemonRenderable
|
||||
import com.cobblemon.mod.common.client.gui.battle.subscreen.BattleActionSelection
|
||||
import com.cobblemon.mod.common.client.gui.battle.subscreen.BattleBackButton
|
||||
import com.cobblemon.mod.common.client.gui.battle.subscreen.BattleGeneralActionSelection
|
||||
import com.cobblemon.mod.common.client.gui.battle.subscreen.BattleMoveSelection
|
||||
import com.cobblemon.mod.common.client.gui.battle.subscreen.BattleSwitchPokemonSelection
|
||||
import com.cobblemon.mod.common.client.gui.battle.subscreen.BattleTargetSelection
|
||||
import com.cobblemon.mod.common.client.gui.battle.subscreen.ForfeitConfirmationSelection
|
||||
import com.cobblemon.mod.common.client.gui.battle.widgets.BattleMessagePane
|
||||
import com.cobblemon.mod.common.client.gui.battle.widgets.BattleOptionTile
|
||||
import com.cobblemon.mod.common.client.gui.summary.Summary.Companion.PARTY
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.PartyWidget
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponent
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponentManager
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerScreen
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.SubManagerComponent
|
||||
import com.cobblemon.mod.common.client.keybind.boundKey
|
||||
import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
@@ -29,8 +39,11 @@ import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.client.gui.screens.Screen
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import org.joml.Vector4i
|
||||
|
||||
class BattleGUI : Screen(battleLang("gui.title")), CobblemonRenderable {
|
||||
class BattleGUI : Screen(battleLang("gui.title")), CobblemonRenderable, ControllerScreen {
|
||||
companion object {
|
||||
const val OPTION_VERTICAL_SPACING = 3
|
||||
const val OPTION_HORIZONTAL_SPACING = 3
|
||||
@@ -51,11 +64,49 @@ class BattleGUI : Screen(battleLang("gui.title")), CobblemonRenderable {
|
||||
|
||||
var queuedActions = mutableListOf<() -> Unit>()
|
||||
|
||||
val controllerComponentManager = ControllerComponentManager(this)
|
||||
|
||||
override fun getComponentManager(): ControllerComponentManager {
|
||||
return controllerComponentManager
|
||||
}
|
||||
|
||||
override fun init() {
|
||||
super.init()
|
||||
messagePane = BattleMessagePane(CobblemonClient.battle!!.messages)
|
||||
messagePane.opacity = CobblemonClient.battleOverlay.opacityRatio.toFloat().coerceAtLeast(0.3F)
|
||||
addRenderableWidget(messagePane)
|
||||
|
||||
controllerComponentManager.componentList["spectating_quit"] = ControllerComponent().also {
|
||||
it.onPress = {
|
||||
quitSpectating()
|
||||
}
|
||||
}
|
||||
controllerComponentManager.componentList["battle_action"] = SubManagerComponent().also {
|
||||
it.subManager = { getCurrentActionSelection()?.controllerComponentManager }
|
||||
}
|
||||
controllerComponentManager.let {
|
||||
it.focused = it.componentList["battle_action"]
|
||||
it.onActiveChange = { state ->
|
||||
if (!state) {
|
||||
getCurrentActionSelection()?.controllerComponentManager?.active = false
|
||||
} else {
|
||||
if (it.currentSelectedComponent == "battle_action") getCurrentActionSelection()?.controllerComponentManager?.active = true
|
||||
}
|
||||
}
|
||||
it.onBack = {
|
||||
if (it.currentSelectedComponent == "battle_action") {
|
||||
getCurrentActionSelection()?.controllerComponentManager?.onBack?.invoke()
|
||||
} else {
|
||||
minimizeBattle()
|
||||
}
|
||||
}
|
||||
it.buttonGuides.add(ControllerComponentManager.ButtonGuide(
|
||||
ControllerComponentManager.ButtonGuideType.SPECIAL_1,
|
||||
{ (getCurrentActionSelection() as? BattleMoveSelection)?.shiftButtonActive() ?: false },
|
||||
Component.translatable("cobblemon.controller.battle.swap_position"),
|
||||
true
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fun changeActionSelection(newSelection: BattleActionSelection?) {
|
||||
@@ -65,6 +116,11 @@ class BattleGUI : Screen(battleLang("gui.title")), CobblemonRenderable {
|
||||
if (newSelection != null) {
|
||||
addRenderableWidget(newSelection)
|
||||
}
|
||||
if (controllerComponentManager.currentSelectedComponent == "battle_action" && controllerComponentManager.active) {
|
||||
focused = null
|
||||
getCurrentActionSelection()?.controllerComponentManager?.active = true
|
||||
controllerComponentManager.focused?.onFocus?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +141,38 @@ class BattleGUI : Screen(battleLang("gui.title")), CobblemonRenderable {
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSelectionPosAndSize(): Vector4i? {
|
||||
val data = super.getSelectionPosAndSize()
|
||||
if (data != null) {
|
||||
return data
|
||||
}
|
||||
|
||||
val actionSelection = getCurrentActionSelection()
|
||||
var newData: Vector4i? = null
|
||||
when (actionSelection) {
|
||||
is BattleGeneralActionSelection -> {
|
||||
val tile = actionSelection.controllerComponentManager.focused?.associatedGUIElement as? BattleOptionTile
|
||||
if (tile != null) {
|
||||
newData = Vector4i(tile.x - 2, tile.y - 2, BattleOptionTile.OPTION_WIDTH + 4, BattleOptionTile.OPTION_HEIGHT + 4)
|
||||
}
|
||||
}
|
||||
is BattleMoveSelection -> {
|
||||
val move = actionSelection.moveTiles[actionSelection.selectedMoveIndex]
|
||||
newData = Vector4i(move.x.toInt() - 10, move.y.toInt() - 2, BattleMoveSelection.MOVE_WIDTH + 12, BattleMoveSelection.MOVE_HEIGHT + 4)
|
||||
}
|
||||
is BattleSwitchPokemonSelection -> {
|
||||
val tile = actionSelection.tiles[actionSelection.selectedTileIndex]
|
||||
newData = Vector4i(tile.x.toInt() - 2, tile.y.toInt() - 2, BattleSwitchPokemonSelection.SwitchTile.SELECT_WIDTH + 2, BattleSwitchPokemonSelection.SwitchTile.SELECT_HEIGHT - 1)
|
||||
}
|
||||
is BattleTargetSelection -> {
|
||||
val tile = actionSelection.baseTiles[actionSelection.selectedTileIndex]
|
||||
newData = Vector4i(tile.x.toInt() - 2, tile.y.toInt() - 2, BattleTargetSelection.TARGET_WIDTH + 4, BattleTargetSelection.TARGET_HEIGHT + 2)
|
||||
}
|
||||
}
|
||||
|
||||
return newData
|
||||
}
|
||||
|
||||
override fun render(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
super.render(context, mouseX, mouseY, delta)
|
||||
|
||||
@@ -122,9 +210,10 @@ class BattleGUI : Screen(battleLang("gui.title")), CobblemonRenderable {
|
||||
|
||||
val currentSelection = getCurrentActionSelection()
|
||||
if (currentSelection == null || currentSelection is BattleGeneralActionSelection ) {
|
||||
val hideLabelButton = if (controllerComponentManager.active) controllerComponentManager.getVisual(ResourceLocation.fromNamespaceAndPath("controlify", "gui_back")) else PartySendBinding.boundKey().displayName
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = battleLang("ui.hide_label", PartySendBinding.boundKey().displayName),
|
||||
text = battleLang("ui.hide_label", hideLabelButton),
|
||||
x = Minecraft.getInstance().window.guiScaledWidth / 2,
|
||||
y = (Minecraft.getInstance().window.guiScaledHeight / 5),
|
||||
opacity = 0.75F * opacity,
|
||||
@@ -141,6 +230,17 @@ class BattleGUI : Screen(battleLang("gui.title")), CobblemonRenderable {
|
||||
)
|
||||
}
|
||||
|
||||
renderSelection(context.pose())
|
||||
|
||||
val activeComponent: ControllerComponent?
|
||||
if (battle.spectating) {
|
||||
activeComponent = controllerComponentManager.componentList["spectator_quit"]
|
||||
} else {
|
||||
activeComponent = controllerComponentManager.componentList["battle_action"]
|
||||
}
|
||||
if (controllerComponentManager.focused != activeComponent) {
|
||||
controllerComponentManager.focused = activeComponent
|
||||
}
|
||||
|
||||
queuedActions.forEach { it() }
|
||||
queuedActions.clear()
|
||||
@@ -151,8 +251,6 @@ class BattleGUI : Screen(battleLang("gui.title")), CobblemonRenderable {
|
||||
}
|
||||
|
||||
fun deriveRootActionSelection(actor: ClientBattleActor, request: SingleActionRequest): BattleActionSelection? {
|
||||
|
||||
|
||||
return if (request.forceSwitch) {
|
||||
BattleSwitchPokemonSelection(this, request)
|
||||
} else {
|
||||
@@ -192,15 +290,21 @@ class BattleGUI : Screen(battleLang("gui.title")), CobblemonRenderable {
|
||||
return minimizeBattle()
|
||||
}
|
||||
|
||||
val battle = CobblemonClient.battle
|
||||
if (battle?.spectating == true && specBackButton.isHovered(mouseX, mouseY)) {
|
||||
RemoveSpectatorPacket(battle.battleId).sendToServer()
|
||||
CobblemonClient.endBattle()
|
||||
if (specBackButton.isHovered(mouseX, mouseY)) {
|
||||
quitSpectating()
|
||||
}
|
||||
return super.mouseClicked(mouseX, mouseY, button)
|
||||
}
|
||||
|
||||
private fun minimizeBattle(): Boolean {
|
||||
fun quitSpectating() {
|
||||
val battle = CobblemonClient.battle
|
||||
if (battle?.spectating == true) {
|
||||
RemoveSpectatorPacket(battle.battleId).sendToServer()
|
||||
CobblemonClient.endBattle()
|
||||
}
|
||||
}
|
||||
|
||||
fun minimizeBattle(): Boolean {
|
||||
val battle = CobblemonClient.battle ?: return false
|
||||
battle.minimised = !battle.minimised
|
||||
PartySendBinding.actioned()
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.battle.ActiveClientBattlePokemon
|
||||
import com.cobblemon.mod.common.client.battle.ClientBallDisplay
|
||||
import com.cobblemon.mod.common.client.gui.battle.widgets.BattleMessagePane
|
||||
import com.cobblemon.mod.common.client.integration.controlify.CobblemonControlifyEntrypoint
|
||||
import com.cobblemon.mod.common.client.keybind.boundKey
|
||||
import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
@@ -142,9 +143,14 @@ class BattleOverlay : Gui(Minecraft.getInstance()), Schedulable {
|
||||
|
||||
if (Minecraft.getInstance().screen !is BattleGUI && battle.mustChoose) {
|
||||
val textOpacity = PROMPT_TEXT_OPACITY_CURVE(passedSeconds)
|
||||
|
||||
val bindingComponent = if (Cobblemon.implementation.isModInstalled("controlify") && CobblemonControlifyEntrypoint.controllerActive())
|
||||
CobblemonControlifyEntrypoint.SEND_OUT_POKEMON!!.inputGlyph()
|
||||
else PartySendBinding.boundKey().displayName
|
||||
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = battleLang("ui.actions_label", PartySendBinding.boundKey().displayName),
|
||||
text = battleLang("ui.actions_label", bindingComponent),
|
||||
x = Minecraft.getInstance().window.guiScaledWidth / 2,
|
||||
y = Minecraft.getInstance().window.guiScaledHeight / 5,
|
||||
opacity = textOpacity,
|
||||
|
||||
+3
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.client.gui.battle.subscreen
|
||||
import com.cobblemon.mod.common.api.gui.ParentWidget
|
||||
import com.cobblemon.mod.common.client.battle.SingleActionRequest
|
||||
import com.cobblemon.mod.common.client.gui.battle.BattleGUI
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponentManager
|
||||
import com.mojang.blaze3d.platform.InputConstants
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
|
||||
@@ -26,6 +27,8 @@ abstract class BattleActionSelection(
|
||||
val opacity: Float
|
||||
get() = battleGUI.opacity
|
||||
|
||||
val controllerComponentManager = ControllerComponentManager(battleGUI)
|
||||
|
||||
override fun mouseClicked(pMouseX: Double, pMouseY: Double, pButton: Int): Boolean {
|
||||
if(pButton == InputConstants.MOUSE_BUTTON_LEFT){
|
||||
return mousePrimaryClicked(pMouseX, pMouseY)
|
||||
|
||||
+30
-9
@@ -14,6 +14,7 @@ import com.cobblemon.mod.common.client.CobblemonClient
|
||||
import com.cobblemon.mod.common.client.battle.SingleActionRequest
|
||||
import com.cobblemon.mod.common.client.gui.battle.BattleGUI
|
||||
import com.cobblemon.mod.common.client.gui.battle.widgets.BattleOptionTile
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponent
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
@@ -40,6 +41,7 @@ class BattleGeneralActionSelection(
|
||||
val lastAnwseredRequest = CobblemonClient.battle?.getLastAnsweredRequest()
|
||||
|
||||
val tiles = mutableListOf<BattleOptionTile>()
|
||||
|
||||
init {
|
||||
var rank = 0
|
||||
|
||||
@@ -75,22 +77,41 @@ class BattleGeneralActionSelection(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
controllerComponentManager.let {
|
||||
it.focused = it.componentList["tile_0_0"]
|
||||
it.onBack = {
|
||||
battleGUI.minimizeBattle()
|
||||
}
|
||||
it.onActiveChange = { state ->
|
||||
if (state) it.focused?.onSelect?.invoke() else it.focused?.onUnselect?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun addOption(rank: Int, text: MutableComponent, texture: ResourceLocation, onClick: () -> Unit) {
|
||||
val startY = Minecraft.getInstance().window.guiScaledHeight - BattleGUI.OPTION_VERTICAL_OFFSET
|
||||
val x = if (rank % 2 == 0) BattleGUI.OPTION_ROOT_X else BattleGUI.OPTION_ROOT_X + BattleGUI.OPTION_HORIZONTAL_SPACING + BattleOptionTile.OPTION_WIDTH
|
||||
val y = if (rank > 1) startY + BattleOptionTile.OPTION_HEIGHT + BattleGUI.OPTION_HORIZONTAL_SPACING else startY
|
||||
tiles.add(
|
||||
BattleOptionTile(
|
||||
battleGUI = battleGUI,
|
||||
x = x,
|
||||
y = y,
|
||||
resource = texture,
|
||||
text = text,
|
||||
onClick = onClick
|
||||
)
|
||||
val tile = BattleOptionTile(
|
||||
battleGUI = battleGUI,
|
||||
x = x,
|
||||
y = y,
|
||||
resource = texture,
|
||||
text = text,
|
||||
onClick = onClick
|
||||
)
|
||||
tiles.add(tile)
|
||||
val row = rank / 2
|
||||
val column = rank % 2
|
||||
controllerComponentManager.componentList["tile_${row}_${column}"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = tile
|
||||
if (row == 1) it.up = { controllerComponentManager.componentList["tile_0_${column}"] }
|
||||
else it.down = { controllerComponentManager.componentList["tile_1_${column}"] }
|
||||
if (column == 1) it.left = { controllerComponentManager.componentList["tile_${row}_0"] }
|
||||
else it.right = { controllerComponentManager.componentList["tile_${row}_1"] }
|
||||
it.onPress = { tile.onClick.invoke() }
|
||||
}
|
||||
}
|
||||
|
||||
override fun renderWidget(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
|
||||
+63
-4
@@ -21,10 +21,12 @@ import com.cobblemon.mod.common.client.battle.SingleActionRequest
|
||||
import com.cobblemon.mod.common.client.gui.MoveCategoryIcon
|
||||
import com.cobblemon.mod.common.client.gui.TypeIcon
|
||||
import com.cobblemon.mod.common.client.gui.battle.BattleGUI
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponent
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.math.toRGB
|
||||
import com.cobblemon.mod.common.util.startWith
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.client.resources.sounds.SimpleSoundInstance
|
||||
@@ -66,6 +68,10 @@ class BattleMoveSelection(
|
||||
MoveTile(this, inBattleMove, x, y)
|
||||
}
|
||||
var moveTiles = baseTiles
|
||||
set(value) {
|
||||
field = value
|
||||
recalculateMoveGrid()
|
||||
}
|
||||
|
||||
val backButton = BattleBackButton(x - 11F, Minecraft.getInstance().window.guiScaledHeight - 22F)
|
||||
val gimmickButtons = moveSet.getGimmicks().filter { it !in moveSet.pendingGimmickUsedThisTurn }.mapIndexed { index, gimmick ->
|
||||
@@ -76,6 +82,53 @@ class BattleMoveSelection(
|
||||
|
||||
val shiftButton = BattleShiftButton(x + 22.5F, Minecraft.getInstance().window.guiScaledHeight - 22F )
|
||||
|
||||
private fun recalculateMoveGrid() {
|
||||
controllerComponentManager.componentList.filter { it.key.startsWith("move_") }.forEach { controllerComponentManager.componentList.remove(it.key) }
|
||||
moveTiles.forEachIndexed { index, tile ->
|
||||
val column = index % 2
|
||||
val row = index / 2
|
||||
controllerComponentManager.componentList["move_${row}_${column}"] = ControllerComponent().also {
|
||||
if (row == 1) it.up = { controllerComponentManager.componentList["move_${0}_${column}"] }
|
||||
else it.down = { controllerComponentManager.componentList["move_${1}_${column}"] }
|
||||
if (column == 1) it.left = { controllerComponentManager.componentList["move_${row}_0"] }
|
||||
else it.right = { controllerComponentManager.componentList["move_${row}_1"] }
|
||||
it.onPress = {
|
||||
if(request.activePokemon.getFormat().battleType.pokemonPerSide == 1) {
|
||||
tile.onClick()
|
||||
} else {
|
||||
battleGUI.changeActionSelection(BattleTargetSelection(battleGUI, request, tile.move, tile.response.gimmickID, tile.move.gimmickMove))
|
||||
playDownSound(Minecraft.getInstance().soundManager)
|
||||
}
|
||||
}
|
||||
it.onSpecial1 = {
|
||||
if (shiftButtonActive()) {
|
||||
playDownSound(Minecraft.getInstance().soundManager)
|
||||
battleGUI.selectAction(request, ShiftActionResponse())
|
||||
}
|
||||
}
|
||||
it.onFocus = { tile.controllerSelected = true }
|
||||
it.onUnfocus = { tile.controllerSelected = false }
|
||||
it.onSelect = { selectedMoveIndex = index }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var selectedMoveIndex = 0
|
||||
|
||||
init {
|
||||
recalculateMoveGrid()
|
||||
controllerComponentManager.let {
|
||||
it.focused = it.componentList["move_0_0"]
|
||||
it.onBack = {
|
||||
playDownSound(Minecraft.getInstance().soundManager)
|
||||
battleGUI.changeActionSelection(null)
|
||||
}
|
||||
it.onActiveChange = { state ->
|
||||
if (state) it.focused?.onSelect?.invoke() else it.focused?.onUnselect?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open class MoveTile(
|
||||
val moveSelection: BattleMoveSelection,
|
||||
val move: InBattleMove,
|
||||
@@ -99,6 +152,8 @@ class BattleMoveSelection(
|
||||
}
|
||||
}
|
||||
|
||||
var controllerSelected = false
|
||||
|
||||
fun render(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
|
||||
val selectConditionOpacity = moveSelection.opacity * if (!selectable) 0.5F else 1F
|
||||
@@ -110,7 +165,7 @@ class BattleMoveSelection(
|
||||
y = y,
|
||||
width = MOVE_WIDTH,
|
||||
height = MOVE_HEIGHT,
|
||||
vOffset = if (selectable && isHovered(mouseX.toDouble(), mouseY.toDouble())) MOVE_HEIGHT else 0,
|
||||
vOffset = if (selectable && (isHovered(mouseX.toDouble(), mouseY.toDouble()) || controllerSelected)) MOVE_HEIGHT else 0,
|
||||
textureHeight = MOVE_HEIGHT * 2,
|
||||
red = rgb.first,
|
||||
green = rgb.second,
|
||||
@@ -175,7 +230,7 @@ class BattleMoveSelection(
|
||||
)
|
||||
}
|
||||
|
||||
fun isHovered(mouseX: Double, mouseY: Double) = mouseX >= x && mouseX <= x + MOVE_WIDTH && mouseY >= y && mouseY <= y + MOVE_HEIGHT
|
||||
fun isHovered(mouseX: Double, mouseY: Double) = (mouseX >= x && mouseX <= x + MOVE_WIDTH && mouseY >= y && mouseY <= y + MOVE_HEIGHT)
|
||||
|
||||
fun onClick() {
|
||||
if (!selectable) return
|
||||
@@ -184,6 +239,10 @@ class BattleMoveSelection(
|
||||
}
|
||||
}
|
||||
|
||||
fun shiftButtonActive(): Boolean {
|
||||
return this.request.activePokemon.getFormat().battleType.slotsPerActor == 3 && (request.activePokemon.getPNX()[2] == 'a' || request.activePokemon.getPNX()[2] == 'c')
|
||||
}
|
||||
|
||||
override fun renderWidget(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
moveTiles.forEach {
|
||||
it.render(context, mouseX, mouseY, delta)
|
||||
@@ -192,7 +251,7 @@ class BattleMoveSelection(
|
||||
gimmickButtons.forEach {
|
||||
it.render(context.pose(), mouseX, mouseY, delta)
|
||||
}
|
||||
if(this.request.activePokemon.getFormat().battleType.slotsPerActor == 3 && (request.activePokemon.getPNX()[2] == 'a' || request.activePokemon.getPNX()[2] == 'c')) {
|
||||
if(shiftButtonActive()) {
|
||||
shiftButton.render(context, mouseX, mouseY, delta)
|
||||
}
|
||||
}
|
||||
@@ -214,7 +273,7 @@ class BattleMoveSelection(
|
||||
} else if (gimmick != null) {
|
||||
gimmickButtons.filter { it != gimmick }.forEach { it.toggled = false }
|
||||
moveTiles = if (gimmick.toggle()) gimmick.tiles else baseTiles
|
||||
} else if(shiftButton.isHovered(mouseX,mouseY)) {
|
||||
} else if(shiftButton.isHovered(mouseX,mouseY) && shiftButtonActive()) {
|
||||
playDownSound(Minecraft.getInstance().soundManager)
|
||||
battleGUI.selectAction(request, ShiftActionResponse())
|
||||
}
|
||||
|
||||
+44
-6
@@ -21,6 +21,7 @@ import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.battle.SingleActionRequest
|
||||
import com.cobblemon.mod.common.client.gui.battle.BattleGUI
|
||||
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponent
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.render.getDepletableRedGreen
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState
|
||||
@@ -31,12 +32,14 @@ import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.cobblemon.mod.common.util.math.fromEulerXYZDegrees
|
||||
import com.cobblemon.mod.common.util.toAssetPath
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.client.gui.narration.NarratableEntry
|
||||
import net.minecraft.client.gui.narration.NarrationElementOutput
|
||||
import net.minecraft.client.resources.sounds.SimpleSoundInstance
|
||||
import net.minecraft.client.sounds.SoundManager
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import org.joml.Quaternionf
|
||||
import org.joml.Vector3f
|
||||
|
||||
@@ -66,6 +69,8 @@ class BattleSwitchPokemonSelection(
|
||||
|
||||
var isReviving = false
|
||||
|
||||
var selectedTileIndex = 0
|
||||
|
||||
init {
|
||||
val pendingActionRequests = CobblemonClient.battle!!.pendingActionRequests
|
||||
val switchingInPokemon = pendingActionRequests.mapNotNull { it.response }.filterIsInstance<SwitchActionResponse>().map { it.newPokemonId }
|
||||
@@ -90,6 +95,33 @@ class BattleSwitchPokemonSelection(
|
||||
|
||||
tiles.add(SwitchTile(this, slotX, slotY, pokemon, showdownPokemon, isFainted, isCurrentlyInBattle))
|
||||
}
|
||||
|
||||
tiles.forEachIndexed { index, tile ->
|
||||
val row = index / 2
|
||||
val column = index % 2
|
||||
val maxRow = (tiles.size + 1) / 2
|
||||
controllerComponentManager.componentList["tile_${row}_${column}"] = ControllerComponent().also {
|
||||
if (row - 1 >= 0) it.up = { controllerComponentManager.componentList["tile_${row-1}_${column}"] }
|
||||
if (row + 1 < maxRow) it.down = { controllerComponentManager.componentList["tile_${row+1}_${column}"] }
|
||||
if (column == 1) it.left = { controllerComponentManager.componentList["tile_${row}_0"] }
|
||||
else if (row != maxRow || tiles.size % 2 == 0) it.right = { controllerComponentManager.componentList["tile_${row}_1"] }
|
||||
it.onPress = { clickTile(tile) }
|
||||
it.onFocus = { tile.controllerSelected = true }
|
||||
it.onUnfocus = { tile.controllerSelected = false }
|
||||
it.onSelect = { selectedTileIndex = index }
|
||||
}
|
||||
}
|
||||
|
||||
controllerComponentManager.let {
|
||||
it.focused = it.componentList["tile_0_0"]
|
||||
it.onBack = {
|
||||
battleGUI.changeActionSelection(null)
|
||||
playDownSound(Minecraft.getInstance().soundManager)
|
||||
}
|
||||
it.onActiveChange = { state ->
|
||||
if (state) it.focused?.onSelect?.invoke() else it.focused?.onUnselect?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getSlotPosition(index: Int): Pair<Float, Float> {
|
||||
@@ -152,11 +184,15 @@ class BattleSwitchPokemonSelection(
|
||||
playDownSound(Minecraft.getInstance().soundManager)
|
||||
return true
|
||||
}
|
||||
val clicked = tiles.find { it.isHovered(mouseX, mouseY) && if (isReviving) it.isFainted else (!it.isFainted && !it.isCurrentlyInBattle) } ?: return false
|
||||
val pokemon = clicked.pokemon
|
||||
val clicked = tiles.find { it.isHovered(mouseX, mouseY) } ?: return false
|
||||
return clickTile(clicked)
|
||||
}
|
||||
|
||||
fun clickTile(tile: SwitchTile): Boolean {
|
||||
if (!(if (isReviving) tile.isFainted else (!tile.isFainted && !tile.isCurrentlyInBattle))) return false
|
||||
val pokemon = tile.pokemon
|
||||
playDownSound(Minecraft.getInstance().soundManager)
|
||||
battleGUI.selectAction(request, SwitchActionResponse(pokemon.uuid))
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -188,7 +224,9 @@ class BattleSwitchPokemonSelection(
|
||||
|
||||
val state = FloatingState()
|
||||
|
||||
fun isHovered(mouseX: Double, mouseY: Double) = mouseX in x..(x + SELECT_WIDTH) && mouseY in (y..(y + SELECT_HEIGHT))
|
||||
var controllerSelected = false
|
||||
|
||||
fun isHovered(mouseX: Double, mouseY: Double) = (mouseX in x..(x + SELECT_WIDTH) && mouseY in (y..(y + SELECT_HEIGHT)))
|
||||
|
||||
fun render(context: GuiGraphics, mouseX: Double, mouseY: Double, deltaTicks: Float) {
|
||||
state.currentAspects = pokemon.aspects
|
||||
@@ -227,11 +265,11 @@ class BattleSwitchPokemonSelection(
|
||||
y = y,
|
||||
width = SELECT_WIDTH,
|
||||
height = SELECT_HEIGHT,
|
||||
vOffset = if (!isFainted && (isHovered(mouseX, mouseY) || isCurrentlyInBattle)) SELECT_HEIGHT else 0,
|
||||
vOffset = if (!isFainted && (isHovered(mouseX, mouseY) || isCurrentlyInBattle || controllerSelected)) SELECT_HEIGHT else 0,
|
||||
textureHeight = SELECT_HEIGHT * 2,
|
||||
)
|
||||
|
||||
val ballIcon = cobblemonResource("textures/gui/ball/" + pokemon.caughtBall.name.path + ".png")
|
||||
val ballIcon = pokemon.caughtBall.name.toAssetPath("textures/gui/ball/", ".png")
|
||||
val ballHeight = 22
|
||||
blitk(
|
||||
matrixStack = matrixStack,
|
||||
|
||||
+31
-3
@@ -26,6 +26,7 @@ import com.cobblemon.mod.common.client.gui.battle.BattleGUI
|
||||
import com.cobblemon.mod.common.client.gui.battle.BattleOverlay
|
||||
import com.cobblemon.mod.common.client.gui.battle.subscreen.BattleSwitchPokemonSelection.Companion
|
||||
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponent
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
@@ -111,10 +112,35 @@ class BattleTargetSelection(
|
||||
else -> if (isAlly) ArrowDirection.UP else ArrowDirection.DOWN
|
||||
}
|
||||
}
|
||||
TargetTile(this, target, x, y, arrowDirection)
|
||||
var out = TargetTile(this, target, x, y, arrowDirection)
|
||||
controllerComponentManager.componentList["tile_${if (isAlly) 0 else 1}_${fieldPos}"] = ControllerComponent().also {
|
||||
if (isAlly) it.up = { controllerComponentManager.componentList["tile_1_${fieldPos}"] }
|
||||
else it.down = { controllerComponentManager.componentList["tile_0_${fieldPos}"] }
|
||||
if (fieldPos - 1 >= 0) it.left = { controllerComponentManager.componentList["tile_${if (isAlly) 0 else 1}_${fieldPos-1}"] }
|
||||
if (fieldPos + 1 < teamSize) it.right = { controllerComponentManager.componentList["tile_${if (isAlly) 0 else 1}_${fieldPos+1}"] }
|
||||
it.onPress = { out.onClick() }
|
||||
it.onFocus = { out.controllerSelected = true }
|
||||
it.onUnfocus = { out.controllerSelected = false }
|
||||
it.onSelect = { selectedTileIndex = index }
|
||||
}
|
||||
out
|
||||
}
|
||||
var targetTiles = baseTiles
|
||||
|
||||
var selectedTileIndex = 0
|
||||
|
||||
init {
|
||||
controllerComponentManager.let {
|
||||
it.focused = it.componentList["tile_0_0"]
|
||||
it.onBack = {
|
||||
playDownSound(Minecraft.getInstance().soundManager)
|
||||
battleGUI.changeActionSelection(BattleMoveSelection(battleGUI, request))
|
||||
}
|
||||
it.onActiveChange = { state ->
|
||||
if (state) it.focused?.onSelect?.invoke() else it.focused?.onUnselect?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open inner class TargetTile(
|
||||
val targetSelection: BattleTargetSelection,
|
||||
@@ -151,6 +177,8 @@ class BattleTargetSelection(
|
||||
ArrowDirection.DOWN -> Pair(this.x + TARGET_WIDTH / 2 - 4F, this.y - 7)
|
||||
}
|
||||
|
||||
var controllerSelected = false
|
||||
|
||||
fun render(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
val passedSeconds = CobblemonClient.battleOverlay.passedSeconds // This syncs the role throbbers
|
||||
val selectConditionOpacity = targetSelection.opacity * if (!selectable) 0.5F else 1F
|
||||
@@ -304,9 +332,9 @@ class BattleTargetSelection(
|
||||
|
||||
fun isHovered(mouseX: Double, mouseY: Double): Boolean {
|
||||
if(isMultiTarget) {
|
||||
return targetTiles.firstOrNull { it.selectable && mouseX >= it.x && mouseX <= it.x + TARGET_WIDTH && mouseY >= it.y && mouseY <= it.y + TARGET_HEIGHT } != null
|
||||
return targetTiles.firstOrNull { it.selectable && ((mouseX >= it.x && mouseX <= it.x + TARGET_WIDTH && mouseY >= it.y && mouseY <= it.y + TARGET_HEIGHT) || it.controllerSelected) } != null
|
||||
}
|
||||
return mouseX >= x && mouseX <= x + TARGET_WIDTH && mouseY >= y && mouseY <= y + TARGET_HEIGHT
|
||||
return mouseX >= x && mouseX <= x + TARGET_WIDTH && mouseY >= y && mouseY <= y + TARGET_HEIGHT || controllerSelected
|
||||
}
|
||||
|
||||
fun onClick() {
|
||||
|
||||
+41
-9
@@ -17,6 +17,7 @@ import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.battle.SingleActionRequest
|
||||
import com.cobblemon.mod.common.client.gui.battle.BattleGUI
|
||||
import com.cobblemon.mod.common.client.gui.interact.battleRequest.BattleResponseButton
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponent
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
@@ -51,21 +52,52 @@ class ForfeitConfirmationSelection(
|
||||
|
||||
acceptButton = BattleResponseButton(xPos + 22, yPos + 18, true) {}
|
||||
declineButton = BattleResponseButton(xPos + 57, yPos + 18, false) {}
|
||||
|
||||
controllerComponentManager.componentList["accept_button"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = acceptButton
|
||||
it.onPress = {
|
||||
onAccept()
|
||||
playDownSound(Minecraft.getInstance().soundManager)
|
||||
}
|
||||
it.right = { controllerComponentManager.componentList["decline_button"] }
|
||||
}
|
||||
controllerComponentManager.componentList["decline_button"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = declineButton
|
||||
it.onPress = {
|
||||
onDecline()
|
||||
playDownSound(Minecraft.getInstance().soundManager)
|
||||
}
|
||||
it.left = { controllerComponentManager.componentList["accept_button"] }
|
||||
}
|
||||
controllerComponentManager.let {
|
||||
it.focused = it.componentList["decline_button"]
|
||||
it.onBack = {
|
||||
it.componentList["decline_button"]?.onPress?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onAccept() {
|
||||
battleGUI.selectAction(request, ForfeitActionResponse())
|
||||
|
||||
// Need to fill out any other pending requests
|
||||
var pendingRequest = CobblemonClient.battle?.getFirstUnansweredRequest()
|
||||
while (pendingRequest != null) {
|
||||
battleGUI.selectAction(pendingRequest, PassActionResponse)
|
||||
pendingRequest = CobblemonClient.battle?.getFirstUnansweredRequest()
|
||||
}
|
||||
}
|
||||
|
||||
fun onDecline() {
|
||||
battleGUI.changeActionSelection(null)
|
||||
}
|
||||
|
||||
override fun mousePrimaryClicked(mouseX: Double, mouseY: Double): Boolean {
|
||||
if (declineButton.isHovered(mouseX, mouseY) || acceptButton.isHovered(mouseX, mouseY)) {
|
||||
if (declineButton.isHovered(mouseX, mouseY)) {
|
||||
battleGUI.changeActionSelection(null)
|
||||
onDecline()
|
||||
} else {
|
||||
battleGUI.selectAction(request, ForfeitActionResponse())
|
||||
|
||||
// Need to fill out any other pending requests
|
||||
var pendingRequest = CobblemonClient.battle?.getFirstUnansweredRequest()
|
||||
while (pendingRequest != null) {
|
||||
battleGUI.selectAction(pendingRequest, PassActionResponse)
|
||||
pendingRequest = CobblemonClient.battle?.getFirstUnansweredRequest()
|
||||
}
|
||||
onAccept()
|
||||
}
|
||||
playDownSound(Minecraft.getInstance().soundManager)
|
||||
return true
|
||||
|
||||
+2
-2
@@ -50,7 +50,7 @@ class BattleOptionTile(
|
||||
alpha = opacity,
|
||||
width = OPTION_WIDTH,
|
||||
height = OPTION_HEIGHT,
|
||||
vOffset = if (isHovered(mouseX.toDouble(), mouseY.toDouble())) OPTION_HEIGHT else 0,
|
||||
vOffset = if (isHovered(mouseX.toDouble(), mouseY.toDouble()) || focused) OPTION_HEIGHT else 0,
|
||||
textureHeight = OPTION_HEIGHT * 2
|
||||
)
|
||||
|
||||
@@ -80,7 +80,7 @@ class BattleOptionTile(
|
||||
|
||||
override fun isFocused() = focused
|
||||
|
||||
fun isHovered(mouseX: Double, mouseY: Double) = mouseX > x && mouseY > y && mouseX < x + OPTION_WIDTH && mouseY < y + OPTION_HEIGHT
|
||||
fun isHovered(mouseX: Double, mouseY: Double) = (mouseX > x && mouseY > y && mouseX < x + OPTION_WIDTH && mouseY < y + OPTION_HEIGHT)
|
||||
|
||||
override fun updateNarration(builder: NarrationElementOutput) {
|
||||
builder.add(NarratedElementType.TITLE, text)
|
||||
|
||||
+55
-1
@@ -10,6 +10,10 @@ package com.cobblemon.mod.common.client.gui.config
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
|
||||
import com.cobblemon.mod.common.client.gui.config.variable.CobblemonConfigVariable
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponent
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponentManager
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerScreen
|
||||
import com.cobblemon.mod.common.config.CobblemonConfig
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
import com.cobblemon.mod.common.util.ifServer
|
||||
@@ -22,11 +26,14 @@ import net.minecraft.client.gui.components.StringWidget
|
||||
import net.minecraft.client.gui.layouts.HeaderAndFooterLayout
|
||||
import net.minecraft.client.gui.layouts.LinearLayout
|
||||
import net.minecraft.client.gui.screens.Screen
|
||||
import net.minecraft.client.resources.sounds.SimpleSoundInstance
|
||||
import net.minecraft.network.chat.CommonComponents
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.sounds.SoundEvents
|
||||
|
||||
class CobblemonConfigScreen(
|
||||
private val previousScreen: Screen?,
|
||||
) : Screen("gui.cobblemon_config.title".asTranslated()), CobblemonRenderable {
|
||||
) : Screen("gui.cobblemon_config.title".asTranslated()), CobblemonRenderable, ControllerScreen {
|
||||
|
||||
companion object {
|
||||
const val HEIGHT = 240
|
||||
@@ -54,6 +61,13 @@ class CobblemonConfigScreen(
|
||||
|
||||
private var searchString: String = ""
|
||||
|
||||
val controllerComponentManager = ControllerComponentManager(this)
|
||||
var lastSelectedEntry = 0
|
||||
|
||||
override fun getComponentManager(): ControllerComponentManager {
|
||||
return controllerComponentManager
|
||||
}
|
||||
|
||||
override fun init() {
|
||||
super.init()
|
||||
|
||||
@@ -97,6 +111,46 @@ class CobblemonConfigScreen(
|
||||
addRenderableWidget(widget)
|
||||
}
|
||||
arrangeLayoutElements()
|
||||
|
||||
controllerComponentManager.componentList["search"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = searchEdit
|
||||
it.down = {
|
||||
val variableEntries = variableList.children().filter { it is CobblemonConfigVariable }
|
||||
if (variableEntries.isNotEmpty()) {
|
||||
controllerComponentManager.componentList["entry_${lastSelectedEntry}_input"]
|
||||
} else {
|
||||
controllerComponentManager.componentList["done"]
|
||||
}
|
||||
}
|
||||
}
|
||||
controllerComponentManager.componentList["done"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = doneButton
|
||||
it.up = {
|
||||
val variableEntries = variableList.children().filter { it is CobblemonConfigVariable }
|
||||
if (variableEntries.isNotEmpty()) {
|
||||
controllerComponentManager.componentList["entry_${lastSelectedEntry}_input"]
|
||||
} else {
|
||||
controllerComponentManager.componentList["search"]
|
||||
}
|
||||
}
|
||||
}
|
||||
controllerComponentManager.let {
|
||||
it.focused = it.componentList["search"]
|
||||
it.onBack = {
|
||||
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK.value(), 1.0F))
|
||||
doneButtonClick()
|
||||
}
|
||||
it.onStart = {
|
||||
it.focused = it.componentList["search"]
|
||||
it.openKeyboard.invoke(it.focused!!.associatedGUIElement as EditBox)
|
||||
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK.value(), 1.0F))
|
||||
}
|
||||
it.buttonGuides.add(ControllerComponentManager.ButtonGuide(
|
||||
ControllerComponentManager.ButtonGuideType.START,
|
||||
{ true },
|
||||
Component.translatable("cobblemon.controller.quick_search")
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
private fun arrangeLayoutElements() {
|
||||
|
||||
+58
@@ -17,6 +17,7 @@ import com.cobblemon.mod.common.client.gui.config.CobblemonConfigScreen.Companio
|
||||
import com.cobblemon.mod.common.client.gui.config.CobblemonConfigScreen.Companion.SLOT_WIDTH
|
||||
import com.cobblemon.mod.common.client.gui.config.CobblemonConfigVariableList.CobblemonConfigVariableListEntry
|
||||
import com.cobblemon.mod.common.client.gui.config.variable.*
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponent
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.config.Category
|
||||
import com.cobblemon.mod.common.config.CobblemonConfig
|
||||
@@ -134,6 +135,63 @@ class CobblemonConfigVariableList(
|
||||
}
|
||||
|
||||
scrollAmount = min(maxScroll.toDouble(), scrollAmount)
|
||||
|
||||
val variableEntries = children().filter { it is CobblemonConfigVariable }
|
||||
variableEntries.forEachIndexed { index, entry ->
|
||||
parent.controllerComponentManager.componentList["entry_${index}_input"] = ControllerComponent().also {
|
||||
when (entry) {
|
||||
is CobblemonConfigButtonVariable -> it.associatedGUIElement = entry.button
|
||||
is CobblemonConfigEditBoxVariable -> it.associatedGUIElement = entry.editBox
|
||||
}
|
||||
it.right = {
|
||||
if ((entry as CobblemonConfigVariable).resetButton.active) {
|
||||
parent.controllerComponentManager.componentList["entry_${index}_reset"]
|
||||
}
|
||||
else null
|
||||
}
|
||||
if (index + 1 <= variableEntries.size - 1) it.down = { parent.controllerComponentManager.componentList["entry_${index+1}_input"] }
|
||||
else it.down = { parent.controllerComponentManager.componentList["done"] }
|
||||
if (index - 1 >= 0) it.up = { parent.controllerComponentManager.componentList["entry_${index-1}_input"] }
|
||||
else it.up = { parent.controllerComponentManager.componentList["search"] }
|
||||
it.onSelect = { parent.lastSelectedEntry = index }
|
||||
it.onFocus = { ensureVisible(entry) }
|
||||
}
|
||||
parent.controllerComponentManager.componentList["entry_${index}_reset"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = (entry as CobblemonConfigVariable).resetButton
|
||||
it.left = { parent.controllerComponentManager.componentList["entry_${index}_input"] }
|
||||
if (index + 1 <= variableEntries.size - 1) it.down = {
|
||||
if ((variableEntries[index+1] as CobblemonConfigVariable).resetButton.active) {
|
||||
parent.controllerComponentManager.componentList["entry_${index+1}_reset"]
|
||||
}
|
||||
else null
|
||||
}
|
||||
else it.down = { parent.controllerComponentManager.componentList["done"] }
|
||||
if (index - 1 >= 0) it.up = {
|
||||
if ((variableEntries[index-1] as CobblemonConfigVariable).resetButton.active) {
|
||||
parent.controllerComponentManager.componentList["entry_${index-1}_reset"]
|
||||
}
|
||||
else null
|
||||
}
|
||||
else it.up = { parent.controllerComponentManager.componentList["search"] }
|
||||
it.onPress = {
|
||||
entry.resetButton.also { button ->
|
||||
button.onPress()
|
||||
button.playDownSound(Minecraft.getInstance().soundManager)
|
||||
parent.controllerComponentManager.also { manager ->
|
||||
manager.focused = manager.componentList["entry_${index}_input"]
|
||||
}
|
||||
}
|
||||
}
|
||||
it.onSelect = { parent.lastSelectedEntry = index }
|
||||
it.onFocus = { ensureVisible(entry) }
|
||||
}
|
||||
}
|
||||
parent.controllerComponentManager.let {
|
||||
if (it.currentSelectedComponent.startsWith("entry_")) {
|
||||
it.focused = it.componentList["search"]
|
||||
}
|
||||
}
|
||||
parent.lastSelectedEntry = 0
|
||||
}
|
||||
|
||||
abstract class CobblemonConfigVariableListEntry(
|
||||
|
||||
+41
-1
@@ -26,6 +26,9 @@ import com.cobblemon.mod.common.client.gui.dialogue.widgets.DialogueOptionWidget
|
||||
import com.cobblemon.mod.common.client.gui.dialogue.widgets.DialoguePortraitWidget
|
||||
import com.cobblemon.mod.common.client.gui.dialogue.widgets.DialogueTextInputWidget
|
||||
import com.cobblemon.mod.common.client.gui.dialogue.widgets.DialogueTimerWidget
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponent
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponentManager
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerScreen
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.dto.DialogueDTO
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.dto.DialogueGibberDTO
|
||||
@@ -45,9 +48,10 @@ import net.minecraft.client.gui.components.EditBox
|
||||
import net.minecraft.client.gui.screens.Screen
|
||||
import net.minecraft.client.resources.sounds.SimpleSoundInstance
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.sounds.SoundEvent
|
||||
|
||||
class DialogueScreen(var dialogueDTO: DialogueDTO) : Screen("gui.dialogue".asTranslated()), CobblemonRenderable {
|
||||
class DialogueScreen(var dialogueDTO: DialogueDTO) : Screen("gui.dialogue".asTranslated()), CobblemonRenderable, ControllerScreen {
|
||||
val speakers = dialogueDTO.speakers?.mapNotNull { (key, value) ->
|
||||
val name = value.name
|
||||
when (val face = value.face) {
|
||||
@@ -141,6 +145,12 @@ class DialogueScreen(var dialogueDTO: DialogueDTO) : Screen("gui.dialogue".asTra
|
||||
)
|
||||
}
|
||||
|
||||
var controllerComponentManager = ControllerComponentManager(this)
|
||||
|
||||
override fun getComponentManager(): ControllerComponentManager {
|
||||
return controllerComponentManager
|
||||
}
|
||||
|
||||
override fun renderBackground(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {}
|
||||
|
||||
override fun renderBlurredBackground(delta: Float) {}
|
||||
@@ -242,6 +252,34 @@ class DialogueScreen(var dialogueDTO: DialogueDTO) : Screen("gui.dialogue".asTra
|
||||
}
|
||||
|
||||
this.dialogueStartTick = minecraft!!.player!!.tickCount
|
||||
|
||||
controllerComponentManager = ControllerComponentManager(this)
|
||||
|
||||
controllerComponentManager.componentList["none"] = ControllerComponent().also {
|
||||
it.onPress = { dialogueBox.onClick() }
|
||||
}
|
||||
dialogueOptionWidgets.forEachIndexed { index, option ->
|
||||
controllerComponentManager.componentList["option_${index}"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = option
|
||||
if (index + 1 <= dialogueOptionWidgets.size - 1) it.right = { controllerComponentManager.componentList["option_${index+1}"] }
|
||||
if (index - 1 >= 0) it.left = { controllerComponentManager.componentList["option_${index-1}"] }
|
||||
it.onPress = { if (!option.onClick()) dialogueBox.onClick() }
|
||||
}
|
||||
}
|
||||
controllerComponentManager.let {
|
||||
it.focused = if (dialogueOptionWidgets.isNotEmpty()) {
|
||||
it.componentList["option_0"]
|
||||
} else {
|
||||
it.componentList["none"]
|
||||
}
|
||||
it.onSpecial1 = { dialogueBox.onClick() }
|
||||
it.buttonGuides.add(ControllerComponentManager.ButtonGuide(
|
||||
ControllerComponentManager.ButtonGuideType.SPECIAL_1,
|
||||
{ dialogueBox.dialogue.dialogueInput.allowSkip && dialogueBox.dialogue.dialogueInput.inputType in listOf(DialogueInputDTO.InputType.NONE, DialogueInputDTO.InputType.AUTO_CONTINUE)},
|
||||
Component.translatable("cobblemon.controller.dialogue.skip"),
|
||||
true
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
var gibberIndex = 0
|
||||
@@ -265,6 +303,8 @@ class DialogueScreen(var dialogueDTO: DialogueDTO) : Screen("gui.dialogue".asTra
|
||||
super.render(guiGraphics, mouseX, mouseY, delta)
|
||||
expressionsToRun.forEach { runtime.resolve(it) }
|
||||
expressionsToRun = emptyList()
|
||||
|
||||
renderSelection(guiGraphics.pose())
|
||||
}
|
||||
|
||||
override fun isPauseScreen() = false
|
||||
|
||||
+10
-4
@@ -161,10 +161,17 @@ class DialogueBox(
|
||||
|
||||
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
|
||||
// TODO change this coordinate check to just be "anywhere the scroll bar isn't"
|
||||
if (!dialogueScreen.waitingForServerUpdate &&
|
||||
mouseX > this.x && mouseX < this.scrollbarPosition &&
|
||||
if (mouseX > this.x && mouseX < this.scrollbarPosition &&
|
||||
mouseY > this.y && mouseY < this.bottom
|
||||
) {
|
||||
if (onClick()) return true
|
||||
}
|
||||
|
||||
return super.mouseClicked(mouseX, mouseY, button)
|
||||
}
|
||||
|
||||
fun onClick(): Boolean {
|
||||
if (!dialogueScreen.waitingForServerUpdate) {
|
||||
if (dialogue.dialogueInput.allowSkip && dialogue.dialogueInput.inputType in listOf(DialogueInputDTO.InputType.NONE, DialogueInputDTO.InputType.AUTO_CONTINUE)) {
|
||||
val gibber = dialogueScreen.gibber
|
||||
if (gibber != null && gibber.graduallyShowText && !dialogueScreen.gibberDone) {
|
||||
@@ -178,8 +185,7 @@ class DialogueBox(
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return super.mouseClicked(mouseX, mouseY, button)
|
||||
return false
|
||||
}
|
||||
|
||||
class DialogueLine(val line: FormattedCharSequence, val lineColor: Int) : Entry<DialogueLine>() {
|
||||
|
||||
+6
-2
@@ -42,7 +42,7 @@ class DialogueOptionWidget(
|
||||
y = y,
|
||||
width = width,
|
||||
height = height,
|
||||
vOffset = if (selectable) (if (isHovered) height else 0) else (height * 2),
|
||||
vOffset = if (selectable) (if (isHovered || isFocused) height else 0) else (height * 2),
|
||||
textureHeight = height * 3,
|
||||
)
|
||||
|
||||
@@ -58,10 +58,14 @@ class DialogueOptionWidget(
|
||||
}
|
||||
|
||||
override fun mouseClicked(pMouseX: Double, pMouseY: Double, pButton: Int): Boolean {
|
||||
if (!isHovered) return false
|
||||
return onClick()
|
||||
}
|
||||
|
||||
fun onClick(): Boolean {
|
||||
if (!dialogueScreen.renderInput()) {
|
||||
return false
|
||||
}
|
||||
if (!isHovered) return false
|
||||
|
||||
if (!selectable || dialogueScreen.waitingForServerUpdate) return true
|
||||
|
||||
|
||||
+68
-21
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.interact.battleRequest
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.gui.ColourLibrary
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.text.bold
|
||||
@@ -16,6 +17,9 @@ import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.battle.ClientBattleChallenge
|
||||
import com.cobblemon.mod.common.client.battle.ClientTeamRequest
|
||||
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponent
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponentManager
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerScreen
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.net.messages.client.PlayerInteractOptionsPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.*
|
||||
@@ -27,16 +31,18 @@ import com.cobblemon.mod.common.util.lang
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.client.gui.screens.Screen
|
||||
import net.minecraft.client.resources.sounds.SimpleSoundInstance
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.sounds.SoundEvent
|
||||
import java.util.*
|
||||
|
||||
class BattleConfigureGUI(
|
||||
private val packet: PlayerInteractOptionsPacket,
|
||||
private val activeRequest: ClientBattleChallenge? = null,
|
||||
private val activeTeamRequest: ClientTeamRequest? = null
|
||||
) : Screen(lang("ui.challenge.challenge_title")), CobblemonRenderable {
|
||||
) : Screen(lang("ui.challenge.challenge_title")), CobblemonRenderable, ControllerScreen {
|
||||
companion object {
|
||||
const val SIZE = 113
|
||||
private val backgroundResource = cobblemonResource("textures/gui/interact/request/battle_request.png")
|
||||
@@ -200,6 +206,12 @@ class BattleConfigureGUI(
|
||||
private var hasRequest = false
|
||||
private var ticksPassed = 0F
|
||||
|
||||
val controllerComponentManager = ControllerComponentManager(this)
|
||||
|
||||
override fun getComponentManager(): ControllerComponentManager {
|
||||
return controllerComponentManager
|
||||
}
|
||||
|
||||
override fun renderBlurredBackground(delta: Float) { }
|
||||
override fun renderMenuBackground(context: GuiGraphics) { }
|
||||
|
||||
@@ -218,29 +230,29 @@ class BattleConfigureGUI(
|
||||
}
|
||||
val (x, y) = getDimensions()
|
||||
|
||||
var battleAccept: BattleResponseButton? = null
|
||||
var battleDecline: BattleResponseButton? = null
|
||||
if(pendingRequest != null) {
|
||||
// Draw Accept/Decline buttons
|
||||
this.addRenderableWidget(
|
||||
BattleResponseButton(
|
||||
x + 22,
|
||||
y + 99,
|
||||
true
|
||||
) {
|
||||
battleRequestMap[options[currentPage]]?.onResponse?.let { it1 -> it1(packet, pendingRequest.requestID, true) }
|
||||
closeGUI()
|
||||
}
|
||||
)
|
||||
battleAccept = BattleResponseButton(
|
||||
x + 22,
|
||||
y + 99,
|
||||
true
|
||||
) {
|
||||
battleRequestMap[options[currentPage]]?.onResponse?.let { it1 -> it1(packet, pendingRequest.requestID, true) }
|
||||
closeGUI()
|
||||
}
|
||||
this.addRenderableWidget(battleAccept)
|
||||
|
||||
this.addRenderableWidget(
|
||||
BattleResponseButton(
|
||||
x + 56,
|
||||
y + 99,
|
||||
false
|
||||
) {
|
||||
battleRequestMap[options[currentPage]]?.onResponse?.let { it1 -> it1(packet, pendingRequest.requestID, false) }
|
||||
closeGUI()
|
||||
}
|
||||
)
|
||||
battleDecline = BattleResponseButton(
|
||||
x + 56,
|
||||
y + 99,
|
||||
false
|
||||
) {
|
||||
battleRequestMap[options[currentPage]]?.onResponse?.let { it1 -> it1(packet, pendingRequest.requestID, false) }
|
||||
closeGUI()
|
||||
}
|
||||
this.addRenderableWidget(battleDecline)
|
||||
|
||||
}
|
||||
else {
|
||||
@@ -306,6 +318,36 @@ class BattleConfigureGUI(
|
||||
this.addRenderableWidget(autoLevelNavButtonRight)
|
||||
}
|
||||
}
|
||||
|
||||
controllerComponentManager.componentList["battle_accept"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = battleAccept
|
||||
it.right = { controllerComponentManager.componentList["battle_decline"] }
|
||||
}
|
||||
controllerComponentManager.componentList["battle_decline"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = battleDecline
|
||||
it.left = { controllerComponentManager.componentList["battle_accept"] }
|
||||
}
|
||||
controllerComponentManager.componentList["request"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = requestButton
|
||||
}
|
||||
controllerComponentManager.let {
|
||||
if (pendingRequest != null) {
|
||||
it.focused = it.componentList["battle_decline"]
|
||||
} else {
|
||||
it.focused = it.componentList["request"]
|
||||
it.onTabNav = { nextTab ->
|
||||
currentPage = (currentPage + (if (nextTab) 1 else -1)) % options.count()
|
||||
updateRequestButtonText()
|
||||
playSound(CobblemonSounds.GUI_CLICK)
|
||||
}
|
||||
if (battleRequestMap[options[currentPage]]?.option != PlayerInteractOptionsPacket.Options.TEAM_REQUEST) {
|
||||
it.onSecondaryTabNav = { nextTab ->
|
||||
levelRulesetOptionIndex += if (nextTab) 1 else -1
|
||||
playSound(CobblemonSounds.GUI_CLICK)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updateRequestButtonText() {
|
||||
@@ -438,6 +480,8 @@ class BattleConfigureGUI(
|
||||
)
|
||||
|
||||
super.render(context, mouseX, mouseY, delta)
|
||||
|
||||
renderSelection(context.pose())
|
||||
}
|
||||
|
||||
private fun getDimensions(): Pair<Int, Int> {
|
||||
@@ -454,4 +498,7 @@ class BattleConfigureGUI(
|
||||
Minecraft.getInstance().setScreen(null)
|
||||
}
|
||||
|
||||
fun playSound(soundEvent: SoundEvent) {
|
||||
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(soundEvent, 1.0F))
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -35,7 +35,7 @@ class BattleResponseButton(
|
||||
}
|
||||
|
||||
override fun renderWidget(context: GuiGraphics, pMouseX: Int, pMouseY: Int, pPartialTicks: Float) {
|
||||
val hovered = (isHovered(pMouseX.toDouble(), pMouseY.toDouble()))
|
||||
val hovered = (isHovered(pMouseX.toDouble(), pMouseY.toDouble()) || isFocused)
|
||||
blitk(
|
||||
matrixStack = context.pose(),
|
||||
x = x / SCALE,
|
||||
|
||||
+31
-11
@@ -14,6 +14,9 @@ import com.cobblemon.mod.common.api.callback.MoveSelectDTO
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
|
||||
import com.cobblemon.mod.common.client.gui.ExitButton
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponent
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponentManager
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerScreen
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.move.MoveSelectCancelledPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.move.MoveSelectedPacket
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
@@ -36,7 +39,7 @@ class MoveSelectConfiguration(
|
||||
|
||||
class MoveSelectGUI(
|
||||
val config: MoveSelectConfiguration
|
||||
) : Screen(Component.translatable("cobblemon.ui.interact.moveselect")), CobblemonRenderable {
|
||||
) : Screen(Component.translatable("cobblemon.ui.interact.moveselect")), CobblemonRenderable, ControllerScreen {
|
||||
companion object {
|
||||
const val WIDTH = 122
|
||||
const val HEIGHT = 133
|
||||
@@ -46,6 +49,8 @@ class MoveSelectGUI(
|
||||
|
||||
var closed = false
|
||||
|
||||
val controllerComponentManager = ControllerComponentManager(this)
|
||||
|
||||
constructor(
|
||||
title: MutableComponent,
|
||||
moves: List<MoveSelectDTO>,
|
||||
@@ -63,6 +68,10 @@ class MoveSelectGUI(
|
||||
)
|
||||
)
|
||||
|
||||
override fun getComponentManager(): ControllerComponentManager {
|
||||
return controllerComponentManager
|
||||
}
|
||||
|
||||
fun closeProperly() {
|
||||
closed = true
|
||||
onClose()
|
||||
@@ -73,16 +82,21 @@ class MoveSelectGUI(
|
||||
val y = (height - HEIGHT) / 2
|
||||
|
||||
config.moves.forEachIndexed { index, move ->
|
||||
addRenderableWidget(
|
||||
MoveSlotButton(
|
||||
x = x + 7,
|
||||
y = y + 7 + ((MoveSlotButton.HEIGHT + 3) * index),
|
||||
move = move.moveTemplate,
|
||||
pp = move.pp,
|
||||
ppMax = move.ppMax,
|
||||
enabled = move.enabled
|
||||
) { onPress(move) }
|
||||
)
|
||||
val moveSlot = MoveSlotButton(
|
||||
x = x + 7,
|
||||
y = y + 7 + ((MoveSlotButton.HEIGHT + 3) * index),
|
||||
move = move.moveTemplate,
|
||||
pp = move.pp,
|
||||
ppMax = move.ppMax,
|
||||
enabled = move.enabled
|
||||
) { onPress(move) }
|
||||
addRenderableWidget(moveSlot)
|
||||
|
||||
controllerComponentManager.componentList["move_${index}"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = moveSlot
|
||||
if (index + 1 <= config.moves.size - 1) it.down = { controllerComponentManager.componentList["move_${index+1}"] }
|
||||
if (index - 1 >= 0) it.up = { controllerComponentManager.componentList["move_${index-1}"] }
|
||||
}
|
||||
}
|
||||
|
||||
// Add Exit Button
|
||||
@@ -97,6 +111,10 @@ class MoveSelectGUI(
|
||||
)
|
||||
|
||||
super.init()
|
||||
|
||||
controllerComponentManager.let {
|
||||
it.focused = it.componentList["move_0"]
|
||||
}
|
||||
}
|
||||
|
||||
override fun render(context: GuiGraphics, mouseX: Int, mouseY: Int, partialTicks: Float) {
|
||||
@@ -114,6 +132,8 @@ class MoveSelectGUI(
|
||||
|
||||
// Render all added Widgets
|
||||
super.render(context, mouseX, mouseY, partialTicks)
|
||||
|
||||
renderSelection(context.pose())
|
||||
}
|
||||
|
||||
private fun onPress(move: MoveSelectDTO) {
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ class MoveSlotButton(
|
||||
}
|
||||
|
||||
override fun renderWidget(context: GuiGraphics, pMouseX: Int, pMouseY: Int, pPartialTicks: Float) {
|
||||
isHovered = pMouseX >= x && pMouseY >= y && pMouseX < x + width && pMouseY < y + height && enabled
|
||||
isHovered = ((pMouseX >= x && pMouseY >= y && pMouseX < x + width && pMouseY < y + height) || isFocused) && enabled
|
||||
|
||||
val moveTemplate = Moves.getByNameOrDummy(move.name)
|
||||
val rgb = moveTemplate.elementalType.hue.toRGB()
|
||||
|
||||
+39
-15
@@ -16,6 +16,9 @@ import com.cobblemon.mod.common.api.text.bold
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
|
||||
import com.cobblemon.mod.common.client.gui.ExitButton
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponent
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponentManager
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerScreen
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.party.PartyPokemonSelectedPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.party.PartySelectCancelledPacket
|
||||
@@ -38,7 +41,7 @@ class PartySelectConfiguration(
|
||||
)
|
||||
class PartySelectGUI(
|
||||
val config: PartySelectConfiguration
|
||||
) : Screen(Component.translatable("cobblemon.ui.interact.moveselect")), CobblemonRenderable {
|
||||
) : Screen(Component.translatable("cobblemon.ui.interact.moveselect")), CobblemonRenderable, ControllerScreen {
|
||||
companion object {
|
||||
const val WIDTH = 163
|
||||
const val HEIGHT = 132
|
||||
@@ -50,6 +53,8 @@ class PartySelectGUI(
|
||||
|
||||
var closed = false
|
||||
|
||||
val controllerComponentManager = ControllerComponentManager(this)
|
||||
|
||||
constructor(
|
||||
title: MutableComponent,
|
||||
pokemon: List<PartySelectPokemonDTO>,
|
||||
@@ -67,6 +72,10 @@ class PartySelectGUI(
|
||||
)
|
||||
)
|
||||
|
||||
override fun getComponentManager(): ControllerComponentManager {
|
||||
return controllerComponentManager
|
||||
}
|
||||
|
||||
fun closeProperly() {
|
||||
closed = true
|
||||
onClose()
|
||||
@@ -90,20 +99,29 @@ class PartySelectGUI(
|
||||
slotY += (31 * offsetIndex) + offsetY
|
||||
}
|
||||
|
||||
addRenderableWidget(
|
||||
PartySlotButton(
|
||||
parent = this,
|
||||
x = slotX,
|
||||
y = slotY,
|
||||
pokemon = pokemon.pokemonProperties,
|
||||
aspects = pokemon.aspects,
|
||||
heldItem = pokemon.heldItem,
|
||||
currentHealth = pokemon.currentHealth,
|
||||
maxHealth = pokemon.maxHealth,
|
||||
enabled = pokemon.enabled,
|
||||
hoverText = pokemon.hoverText,
|
||||
) { onPress(pokemon) }
|
||||
)
|
||||
val slot = PartySlotButton(
|
||||
parent = this,
|
||||
x = slotX,
|
||||
y = slotY,
|
||||
pokemon = pokemon.pokemonProperties,
|
||||
aspects = pokemon.aspects,
|
||||
heldItem = pokemon.heldItem,
|
||||
currentHealth = pokemon.currentHealth,
|
||||
maxHealth = pokemon.maxHealth,
|
||||
enabled = pokemon.enabled,
|
||||
hoverText = pokemon.hoverText,
|
||||
) { onPress(pokemon) }
|
||||
addRenderableWidget(slot)
|
||||
|
||||
val row = index / 2
|
||||
val column = index % 2
|
||||
controllerComponentManager.componentList["slot_${row}_${column}"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = slot
|
||||
if (column == 0) it.right = { controllerComponentManager.componentList["slot_${row}_${1}"] }
|
||||
else it.left = { controllerComponentManager.componentList["slot_${row}_${0}"] }
|
||||
if (row - 1 >= 0) it.up = { controllerComponentManager.componentList["slot_${row-1}_${column}"] }
|
||||
if (row + 1 <= 2) it.down = { controllerComponentManager.componentList["slot_${row+1}_${column}"] }
|
||||
}
|
||||
}
|
||||
|
||||
// Add Exit Button
|
||||
@@ -118,6 +136,10 @@ class PartySelectGUI(
|
||||
)
|
||||
|
||||
super.init()
|
||||
|
||||
controllerComponentManager.let {
|
||||
it.focused = it.componentList["slot_0_0"]
|
||||
}
|
||||
}
|
||||
|
||||
override fun render(context: GuiGraphics, mouseX: Int, mouseY: Int, partialTicks: Float) {
|
||||
@@ -155,6 +177,8 @@ class PartySelectGUI(
|
||||
|
||||
// Render all added Widgets
|
||||
super.render(context, mouseX, mouseY, partialTicks)
|
||||
|
||||
renderSelection(context.pose())
|
||||
}
|
||||
|
||||
private fun onPress(pokemon: PartySelectPokemonDTO) {
|
||||
|
||||
+4
-2
@@ -24,11 +24,13 @@ import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.cobblemon.mod.common.util.math.fromEulerXYZDegrees
|
||||
import com.cobblemon.mod.common.util.toAssetPath
|
||||
import com.google.common.collect.Lists
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.client.gui.components.Button
|
||||
import net.minecraft.client.sounds.SoundManager
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.FormattedCharSequence
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import org.joml.Quaternionf
|
||||
@@ -61,7 +63,7 @@ class PartySlotButton(
|
||||
private val renderablePokemon = pokemon.asRenderablePokemon().also { it.aspects = aspects }
|
||||
|
||||
override fun renderWidget(context: GuiGraphics, pMouseX: Int, pMouseY: Int, pPartialTicks: Float) {
|
||||
isHovered = pMouseX >= x && pMouseY >= y && pMouseX < x + width && pMouseY < y + height && enabled
|
||||
isHovered = ((pMouseX >= x && pMouseY >= y && pMouseX < x + width && pMouseY < y + height) || isFocused) && enabled
|
||||
val alpha = if (enabled) 1.0 else 0.7
|
||||
val matrices = context.pose()
|
||||
|
||||
@@ -111,7 +113,7 @@ class PartySlotButton(
|
||||
)
|
||||
context.pose().popPose()
|
||||
|
||||
val ballIcon = cobblemonResource("textures/gui/ball/" + pokemon.pokeball!!.asIdentifierDefaultingNamespace().path + ".png")
|
||||
val ballIcon = pokemon.pokeball!!.asIdentifierDefaultingNamespace().toAssetPath("textures/gui/ball/", ".png")
|
||||
val ballHeight = 22
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
|
||||
+4
-4
@@ -28,7 +28,7 @@ class InteractWheelButton(
|
||||
private val tooltipText: String?,
|
||||
x: Int,
|
||||
y: Int,
|
||||
private val isEnabled: Boolean,
|
||||
val isEnabled: Boolean,
|
||||
private val colour: () -> Vector3f?,
|
||||
onPress: OnPress,
|
||||
private val canHover: (Double, Double) -> Boolean
|
||||
@@ -74,12 +74,12 @@ class InteractWheelButton(
|
||||
y = y,
|
||||
width = width,
|
||||
height = height,
|
||||
vOffset = if (isHovered(mouseX.toFloat(), mouseY.toFloat()) && isEnabled) height else 0,
|
||||
vOffset = if ((isHovered(mouseX.toFloat(), mouseY.toFloat()) || isFocused) && isEnabled) height else 0,
|
||||
textureHeight = height * 2,
|
||||
alpha = if (isEnabled) 1f else 0.4F
|
||||
)
|
||||
|
||||
if(isEnabled && isHovered(mouseX.toFloat(), mouseY.toFloat())){
|
||||
if(isEnabled && (isHovered(mouseX.toFloat(), mouseY.toFloat()) || isFocused)){
|
||||
tooltipText?.let {
|
||||
context.renderTooltip(Minecraft.getInstance().font, Component.translatable(it), mouseX, mouseY)
|
||||
}
|
||||
@@ -162,7 +162,7 @@ class InteractWheelButton(
|
||||
}
|
||||
|
||||
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
|
||||
return if (isHovered(mouseX.toFloat(), mouseY.toFloat())) super.mouseClicked(mouseX, mouseY, button) else false
|
||||
return if (isHovered(mouseX.toFloat(), mouseY.toFloat()) || isFocused) super.mouseClicked(mouseX, mouseY, button) else false
|
||||
}
|
||||
|
||||
override fun getTooltip(): Tooltip? {
|
||||
|
||||
+4
-4
@@ -23,9 +23,9 @@ class InteractWheelGUI(private val options: Multimap<Orientation, InteractWheelO
|
||||
private val backgroundResource = cobblemonResource("textures/gui/interact/interact_wheel_base.png")
|
||||
}
|
||||
|
||||
private val buttons = mutableListOf<InteractWheelButton>()
|
||||
private var maxPage = 1
|
||||
private var currentPage = 0
|
||||
val buttons = mutableListOf<InteractWheelButton>()
|
||||
var maxPage = 1
|
||||
var currentPage = 0
|
||||
override fun renderBlurredBackground(delta: Float) { }
|
||||
override fun renderMenuBackground(context: GuiGraphics) {}
|
||||
|
||||
@@ -77,7 +77,7 @@ class InteractWheelGUI(private val options: Multimap<Orientation, InteractWheelO
|
||||
currentPage = page
|
||||
buttons.forEach { removeWidget(it) }
|
||||
buttons.clear()
|
||||
val orientations = Orientation.values()
|
||||
val orientations = Orientation.entries.toTypedArray()
|
||||
orientations.forEach { orientation ->
|
||||
val option = options[orientation].toList().getOrNull(page)
|
||||
addButton(orientation, option)
|
||||
|
||||
+54
-3
@@ -19,6 +19,7 @@ import com.cobblemon.mod.common.client.gui.CobblemonRenderable
|
||||
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
|
||||
import com.cobblemon.mod.common.client.gui.pc.StorageSlot
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.PartySlotWidget
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponent
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.render.drawScaledTextJustifiedRight
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState
|
||||
@@ -76,11 +77,58 @@ class PasturePokemonScrollList(
|
||||
|
||||
removedEntries.forEach(this::removeEntry)
|
||||
newEntries.forEach { addEntry(PastureSlot(it, parent)) }
|
||||
|
||||
rebuildControllerSelection()
|
||||
}
|
||||
}
|
||||
|
||||
fun rebuildControllerSelection() {
|
||||
if (parent.lastSelectedIndex > 0 && parent.lastSelectedIndex >= children().size) parent.lastSelectedIndex = children().size - 1
|
||||
children().forEachIndexed { index, slot ->
|
||||
parent.controllerComponentManager.componentList["slot_${index}"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = slot
|
||||
if (index - 1 >= 0) it.up = { parent.controllerComponentManager.componentList["slot_${index - 1}"] }
|
||||
if (index + 1 <= children().size - 1) it.down =
|
||||
{ parent.controllerComponentManager.componentList["slot_${index + 1}"] }
|
||||
else it.down = { parent.controllerComponentManager.componentList["recall_all"] }
|
||||
it.onPress = { slot.moveButton.onPress() }
|
||||
it.onSpecial1 = { slot.conflictButton.onPress() }
|
||||
it.onFocus = {
|
||||
slot.controllerFocused = true
|
||||
ensureVisible(slot)
|
||||
}
|
||||
it.onUnfocus = {
|
||||
slot.controllerFocused = false
|
||||
}
|
||||
}
|
||||
}
|
||||
if (parent.controllerComponentManager.currentSelectedComponent.let { it.startsWith("slot_") || it == "empty" }) {
|
||||
parent.controllerComponentManager.focused =
|
||||
if (children().isEmpty()) parent.controllerComponentManager.componentList["empty"]
|
||||
else parent.controllerComponentManager.componentList["slot_${parent.lastSelectedIndex}"]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun getScrollbarPosition() = x + width - 3
|
||||
|
||||
public override fun ensureVisible(entry: PastureSlot) {
|
||||
val i = getRowTop(children().indexOf(entry))
|
||||
val topDifference = i - y
|
||||
if (topDifference < 0) {
|
||||
scroll(topDifference)
|
||||
}
|
||||
|
||||
val bottomDifference = bottom - i - itemHeight - 4
|
||||
if (bottomDifference < 0) {
|
||||
scroll(-bottomDifference)
|
||||
}
|
||||
}
|
||||
|
||||
public override fun getRowTop(index: Int): Int {
|
||||
return super.getRowTop(index)
|
||||
}
|
||||
|
||||
public override fun addEntry(entry: PastureSlot) = super.addEntry(entry)
|
||||
public override fun removeEntry(entry: PastureSlot) = super.removeEntry(entry)
|
||||
override fun renderSelection(context: GuiGraphics, y: Int, entryWidth: Int, entryHeight: Int, borderColor: Int, fillColor: Int) {}
|
||||
@@ -166,6 +214,8 @@ class PasturePokemonScrollList(
|
||||
val client: Minecraft = Minecraft.getInstance()
|
||||
val state = FloatingState()
|
||||
|
||||
var controllerFocused = false
|
||||
|
||||
fun isOwned() = client.player?.uuid == pokemon.playerId
|
||||
fun canUnpasture() = isOwned() || parent.pasturePCGUIConfiguration.permissions.canUnpastureOthers
|
||||
fun canDefend() = PokemonSpecies.getByIdentifier(pokemon.species)?.behaviour?.combat?.willDefendOwner
|
||||
@@ -182,7 +232,7 @@ class PasturePokemonScrollList(
|
||||
setEnabled(PokemonBehaviourFlag.PASTURE_CONFLICT in pokemon.behaviourFlags)
|
||||
}
|
||||
|
||||
private val moveButton: PastureSlotIconButton = PastureSlotIconButton(
|
||||
val moveButton: PastureSlotIconButton = PastureSlotIconButton(
|
||||
xPos = 0,
|
||||
yPos = 0,
|
||||
onPress = {
|
||||
@@ -191,7 +241,8 @@ class PasturePokemonScrollList(
|
||||
pastureId = parent.pasturePCGUIConfiguration.pastureId,
|
||||
pokemonId = pokemon.pokemonId
|
||||
).sendToServer()
|
||||
}
|
||||
},
|
||||
parent = this@PastureSlot
|
||||
)
|
||||
|
||||
override fun getNarration() = pokemon.displayName
|
||||
@@ -219,7 +270,7 @@ class PasturePokemonScrollList(
|
||||
y = y,
|
||||
height = SLOT_HEIGHT,
|
||||
width = rowWidth,
|
||||
vOffset = if (isHovered) SLOT_HEIGHT else 0,
|
||||
vOffset = if (isHovered || controllerFocused) SLOT_HEIGHT else 0,
|
||||
textureHeight = SLOT_HEIGHT * 2
|
||||
)
|
||||
|
||||
|
||||
+3
-2
@@ -18,7 +18,8 @@ import net.minecraft.network.chat.Component
|
||||
|
||||
class PastureSlotIconButton(
|
||||
var xPos: Int, var yPos: Int,
|
||||
onPress: OnPress
|
||||
onPress: OnPress,
|
||||
var parent: PasturePokemonScrollList.PastureSlot
|
||||
) : Button(xPos, yPos, (SIZE * SCALE).toInt(), (SIZE * SCALE).toInt(), Component.literal("Pasture Move"), onPress, DEFAULT_NARRATION), CobblemonRenderable {
|
||||
|
||||
companion object {
|
||||
@@ -35,7 +36,7 @@ class PastureSlotIconButton(
|
||||
y = yPos / SCALE,
|
||||
width = SIZE,
|
||||
height = SIZE,
|
||||
vOffset = if (isHovered(mouseX.toDouble(), mouseY.toDouble())) SIZE else 0,
|
||||
vOffset = if (isHovered(mouseX.toDouble(), mouseY.toDouble()) || parent.controllerFocused) SIZE else 0,
|
||||
textureHeight = SIZE * 2,
|
||||
texture = baseResource,
|
||||
scale = SCALE
|
||||
|
||||
@@ -15,6 +15,8 @@ import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.gui.pc.PCGUI
|
||||
import com.cobblemon.mod.common.client.gui.pc.StorageWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.SoundlessWidget
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponent
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponentManager
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.net.messages.server.pasture.UnpastureAllPokemonPacket
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
@@ -34,6 +36,9 @@ class PastureWidget(
|
||||
private val baseResource = cobblemonResource("textures/gui/pasture/pasture_panel.png")
|
||||
}
|
||||
|
||||
val controllerComponentManager = ControllerComponentManager(storageWidget.pcGui)
|
||||
var lastSelectedIndex = 0
|
||||
|
||||
private val recallButton = RecallButton(
|
||||
x = x + 6,
|
||||
y = y + 153
|
||||
@@ -48,6 +53,23 @@ class PastureWidget(
|
||||
parent = this
|
||||
)
|
||||
|
||||
init {
|
||||
controllerComponentManager.componentList["recall_all"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = recallButton
|
||||
it.up = {
|
||||
if (pastureScrollList.children().isEmpty()) controllerComponentManager.componentList["empty"]
|
||||
else controllerComponentManager.componentList["slot_${pastureScrollList.children().size-1}"]
|
||||
}
|
||||
}
|
||||
controllerComponentManager.componentList["empty"] = ControllerComponent().also {
|
||||
it.down = { controllerComponentManager.componentList["recall_all"] }
|
||||
}
|
||||
controllerComponentManager.let {
|
||||
it.focused = if (pastureScrollList.children().isEmpty()) it.componentList["empty"]
|
||||
else it.componentList["slot_0"]
|
||||
}
|
||||
}
|
||||
|
||||
override fun renderWidget(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
blitk(
|
||||
matrixStack = context.pose(),
|
||||
|
||||
@@ -40,7 +40,7 @@ class RecallButton(
|
||||
y = y,
|
||||
width = WIDTH,
|
||||
height = HEIGHT,
|
||||
vOffset = if (isHovered(mouseX.toDouble(), mouseY.toDouble())) HEIGHT else 0,
|
||||
vOffset = if (isHovered(mouseX.toDouble(), mouseY.toDouble()) || isFocused) HEIGHT else 0,
|
||||
textureHeight = HEIGHT * 2
|
||||
)
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
|
||||
import com.cobblemon.mod.common.client.gui.ExitButton
|
||||
import com.cobblemon.mod.common.client.gui.TypeIcon
|
||||
import com.cobblemon.mod.common.client.gui.pasture.PasturePokemonScrollList
|
||||
import com.cobblemon.mod.common.client.gui.summary.Summary
|
||||
import com.cobblemon.mod.common.client.gui.summary.Summary.Companion.iconCosmeticItemResource
|
||||
import com.cobblemon.mod.common.client.gui.summary.Summary.Companion.iconHeldItemResource
|
||||
@@ -28,6 +29,10 @@ import com.cobblemon.mod.common.client.gui.summary.SummaryButton
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.MarkingsWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.ModelWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.common.reformatNatureTextIfMinted
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponent
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponentManager
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerScreen
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.SubManagerComponent
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.storage.ClientPC
|
||||
import com.cobblemon.mod.common.client.storage.ClientParty
|
||||
@@ -40,15 +45,19 @@ import com.cobblemon.mod.common.util.asTranslated
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.isInventoryKeyPressed
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.cobblemon.mod.common.util.toAssetPath
|
||||
import com.mojang.blaze3d.platform.InputConstants
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.client.gui.components.EditBox
|
||||
import net.minecraft.client.gui.screens.Screen
|
||||
import net.minecraft.client.resources.sounds.SimpleSoundInstance
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.sounds.SoundEvent
|
||||
import kotlin.isInitialized
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.sounds.SoundEvents
|
||||
import org.joml.Vector4i
|
||||
|
||||
class PCGUI(
|
||||
val pc: ClientPC,
|
||||
@@ -56,7 +65,7 @@ class PCGUI(
|
||||
val configuration: PCGUIConfiguration,
|
||||
val openOnBox: Int = CobblemonClient.lastPcBoxViewed,
|
||||
val unseenWallpapers: MutableSet<ResourceLocation> = mutableSetOf()
|
||||
) : Screen(Component.translatable("cobblemon.ui.pc.title")), CobblemonRenderable {
|
||||
) : Screen(Component.translatable("cobblemon.ui.pc.title")), CobblemonRenderable, ControllerScreen {
|
||||
|
||||
companion object {
|
||||
const val BASE_WIDTH = 349
|
||||
@@ -127,6 +136,14 @@ class PCGUI(
|
||||
var selectPointerOffsetIncrement = false
|
||||
var displayOptions = false
|
||||
|
||||
val controllerComponentManager = ControllerComponentManager(this)
|
||||
var lastSelectedBeforeOptions = ""
|
||||
var controllerShiftToggle = false
|
||||
|
||||
override fun getComponentManager(): ControllerComponentManager {
|
||||
return controllerComponentManager
|
||||
}
|
||||
|
||||
override fun renderBlurredBackground(delta: Float) {}
|
||||
|
||||
override fun renderMenuBackground(context: GuiGraphics) {}
|
||||
@@ -197,30 +214,39 @@ class PCGUI(
|
||||
this.addRenderableWidget(boxNameWidget)
|
||||
|
||||
// Initialise box options if not pasture
|
||||
var optionsButton: IconButton? = null
|
||||
var wallpaperButton: IconButton? = null
|
||||
if (storageWidget.pastureWidget == null) {
|
||||
optionButtons.clear()
|
||||
addRenderableWidget(
|
||||
IconButton(
|
||||
pX = x + 218,
|
||||
pY = y + 186,
|
||||
buttonWidth = 16,
|
||||
buttonHeight = 16,
|
||||
resource = buttonOptionsResource,
|
||||
label = "options"
|
||||
) {
|
||||
displayOptions = !displayOptions
|
||||
if (!displayOptions && wallpaperWidget.visible) {
|
||||
configuration.showParty = true
|
||||
wallpaperWidget.visible = false
|
||||
}
|
||||
(it as IconButton).highlighted = displayOptions
|
||||
storageWidget.setupStorageSlots()
|
||||
for (button in optionButtons) {
|
||||
button.visible = displayOptions
|
||||
button.highlighted = false
|
||||
}
|
||||
}.also { it.highlighted = displayOptions }
|
||||
)
|
||||
optionsButton = IconButton(
|
||||
pX = x + 218,
|
||||
pY = y + 186,
|
||||
buttonWidth = 16,
|
||||
buttonHeight = 16,
|
||||
resource = buttonOptionsResource,
|
||||
label = "options"
|
||||
) {
|
||||
if (!displayOptions) {
|
||||
lastSelectedBeforeOptions = controllerComponentManager.currentSelectedComponent
|
||||
controllerComponentManager.focused = controllerComponentManager.componentList["setting_button_0"]
|
||||
controllerShiftToggle = false
|
||||
} else {
|
||||
controllerComponentManager.focused = controllerComponentManager.componentList[lastSelectedBeforeOptions]
|
||||
}
|
||||
|
||||
displayOptions = !displayOptions
|
||||
if (!displayOptions && wallpaperWidget.visible) {
|
||||
configuration.showParty = true
|
||||
wallpaperWidget.visible = false
|
||||
}
|
||||
(it as IconButton).highlighted = displayOptions
|
||||
storageWidget.setupStorageSlots()
|
||||
for (button in optionButtons) {
|
||||
button.visible = displayOptions
|
||||
button.highlighted = false
|
||||
}
|
||||
}.also { it.highlighted = displayOptions }
|
||||
addRenderableWidget(optionsButton)
|
||||
|
||||
// Add Wallpaper Widget
|
||||
this.wallpaperWidget = WallpapersScrollingWidget(
|
||||
@@ -236,7 +262,7 @@ class PCGUI(
|
||||
this.addRenderableWidget(wallpaperWidget)
|
||||
|
||||
// Add Wallpaper Settings Button
|
||||
this.addRenderableWidget(IconButton(
|
||||
wallpaperButton = IconButton(
|
||||
pX = x + 242,
|
||||
pY = y + 31,
|
||||
buttonWidth = 20,
|
||||
@@ -249,14 +275,16 @@ class PCGUI(
|
||||
wallpaperWidget.visible = !isVisible
|
||||
(it as IconButton).highlighted = !isVisible
|
||||
if (!unseenWallpapers.isEmpty()) MarkPCBoxWallpapersSeenPacket(unseenWallpapers).sendToServer()
|
||||
controllerComponentManager.focused = if (wallpaperWidget.visible) controllerComponentManager.componentList["wallpaper_widget"] else controllerComponentManager.componentList["wallpaper_button"]
|
||||
}.also {
|
||||
it.visible = displayOptions
|
||||
optionButtons.add(it)
|
||||
})
|
||||
}
|
||||
this.addRenderableWidget(wallpaperButton)
|
||||
|
||||
PokemonSortMode.entries.forEachIndexed { index, sortType ->
|
||||
val typeName = sortType.name.lowercase()
|
||||
this.addRenderableWidget(IconButton(
|
||||
val button = IconButton(
|
||||
pX = x + 92 + (12 * index),
|
||||
pY = y + 31,
|
||||
buttonWidth = 20,
|
||||
@@ -267,33 +295,58 @@ class PCGUI(
|
||||
label = "sort_${typeName}"
|
||||
) {
|
||||
storageWidget.resetSelected()
|
||||
SortPCBoxPacket(pc.uuid, storageWidget.box, sortType, hasShiftDown()).sendToServer()
|
||||
SortPCBoxPacket(pc.uuid, storageWidget.box, sortType, hasShiftDown() || (controllerComponentManager.active && controllerShiftToggle)).sendToServer()
|
||||
}.also {
|
||||
it.visible = displayOptions
|
||||
optionButtons.add(it)
|
||||
})
|
||||
}
|
||||
this.addRenderableWidget(button)
|
||||
|
||||
controllerComponentManager.componentList["setting_button_${index}"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = button
|
||||
if (index - 1 >= 0) it.left = { controllerComponentManager.componentList["setting_button_${index-1}"] }
|
||||
if (index + 1 <= PokemonSortMode.entries.size - 1) it.right = { controllerComponentManager.componentList["setting_button_${index+1}"] }
|
||||
else it.right = { controllerComponentManager.componentList["wallpaper_button"] }
|
||||
it.onSpecial1 = {
|
||||
controllerShiftToggle = !controllerShiftToggle
|
||||
playSound(CobblemonSounds.PC_CLICK)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
controllerComponentManager.componentList["wallpaper_button"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = wallpaperButton
|
||||
it.left = { controllerComponentManager.componentList["setting_button_${PokemonSortMode.entries.size - 1}"] }
|
||||
}
|
||||
controllerComponentManager.componentList["wallpaper_widget"] = SubManagerComponent().also {
|
||||
it.subManager = { wallpaperWidget.controllerComponentManager }
|
||||
it.onSpecial1 = {
|
||||
controllerShiftToggle = !controllerShiftToggle
|
||||
playSound(CobblemonSounds.PC_CLICK)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.markingsWidget = MarkingsWidget(x + 29, y + 96.5, null, false)
|
||||
this.addRenderableWidget(markingsWidget)
|
||||
|
||||
// Held/Cosmetic Item Button
|
||||
addRenderableWidget(
|
||||
SummaryButton(
|
||||
buttonX = x + 67F,
|
||||
buttonY = y + 107F,
|
||||
buttonWidth = 12,
|
||||
buttonHeight = 12,
|
||||
scale = 0.5F,
|
||||
resource = iconCosmeticItemResource,
|
||||
activeResource = iconHeldItemResource,
|
||||
clickAction = {
|
||||
showCosmeticItem = !showCosmeticItem
|
||||
(it as SummaryButton).buttonActive = showCosmeticItem
|
||||
}
|
||||
)
|
||||
|
||||
val switchCosmetic = SummaryButton(
|
||||
buttonX = x + 67F,
|
||||
buttonY = y + 107F,
|
||||
buttonWidth = 12,
|
||||
buttonHeight = 12,
|
||||
scale = 0.5F,
|
||||
resource = iconCosmeticItemResource,
|
||||
activeResource = iconHeldItemResource,
|
||||
clickAction = {
|
||||
showCosmeticItem = !showCosmeticItem
|
||||
(it as SummaryButton).buttonActive = showCosmeticItem
|
||||
}
|
||||
)
|
||||
// Held/Cosmetic Item Button
|
||||
addRenderableWidget(switchCosmetic)
|
||||
|
||||
|
||||
addRenderableWidget(
|
||||
IconButton(
|
||||
@@ -311,6 +364,149 @@ class PCGUI(
|
||||
this.setPreviewPokemon(null)
|
||||
|
||||
super.init()
|
||||
|
||||
controllerComponentManager.componentList["box_name"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = boxNameWidget
|
||||
it.down = { controllerComponentManager.componentList["storage"] }
|
||||
}
|
||||
controllerComponentManager.componentList["storage"] = SubManagerComponent().also {
|
||||
it.subManager = { storageWidget.controllerComponentManager }
|
||||
it.up = {
|
||||
var returnVal: ControllerComponent? = null
|
||||
val manager = storageWidget.controllerComponentManager
|
||||
if (manager.up() && manager.currentSelectedComponent.startsWith("slot") && storageWidget.grabbedSlot == null) {
|
||||
returnVal = controllerComponentManager.componentList["box_name"]
|
||||
}
|
||||
returnVal
|
||||
}
|
||||
it.down = {
|
||||
var returnVal: ControllerComponent? = null
|
||||
val manager = storageWidget.controllerComponentManager
|
||||
if (manager.down() && manager.currentSelectedComponent.startsWith("slot") && storageWidget.grabbedSlot == null) {
|
||||
returnVal = controllerComponentManager.componentList["filter"]
|
||||
}
|
||||
returnVal
|
||||
}
|
||||
it.onSpecial1 = {
|
||||
if (storageWidget.controllerComponentManager.currentSelectedComponent == "pasture") {
|
||||
storageWidget.controllerComponentManager.special1()
|
||||
} else {
|
||||
switchCosmetic.onPress()
|
||||
playSound(CobblemonSounds.PC_CLICK)
|
||||
}
|
||||
|
||||
}
|
||||
it.onSpecial2 = { if (storageWidget.pastureWidget == null) displayOptions = !displayOptions }
|
||||
}
|
||||
controllerComponentManager.componentList["filter"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = filterWidget
|
||||
it.up = { controllerComponentManager.componentList["storage"] }
|
||||
}
|
||||
controllerComponentManager.let {
|
||||
it.focused = it.componentList["storage"]
|
||||
it.onTabNav = { nextTab ->
|
||||
storageWidget.box += if (nextTab) 1 else -1
|
||||
playSound(CobblemonSounds.PC_CLICK)
|
||||
}
|
||||
it.onSecondaryTabNav = { nextTab ->
|
||||
var nextValue = currentStatIndex + if (nextTab) 1 else -1
|
||||
if (nextValue > 2) nextValue = 0
|
||||
if (nextValue < 0) nextValue = 2
|
||||
currentStatIndex = nextValue
|
||||
playSound(CobblemonSounds.PC_CLICK)
|
||||
}
|
||||
it.onStart = {
|
||||
if (it.currentSelectedComponent != "storage" || storageWidget.grabbedSlot == null) {
|
||||
it.focused = controllerComponentManager.componentList["filter"]
|
||||
storageWidget.controllerComponentManager.focused =
|
||||
storageWidget.controllerComponentManager.componentList["slot_4_0"]
|
||||
it.openKeyboard.invoke(it.focused!!.associatedGUIElement as EditBox)
|
||||
playSound(SoundEvents.UI_BUTTON_CLICK.value())
|
||||
}
|
||||
}
|
||||
it.onSpecial2 = {
|
||||
if (storageWidget.pastureWidget == null && storageWidget.grabbedSlot == null) {
|
||||
optionsButton!!.onPress()
|
||||
playSound(CobblemonSounds.PC_CLICK)
|
||||
}
|
||||
}
|
||||
it.onBack = {
|
||||
if (storageWidget.pastureWidget == null && wallpaperWidget.visible) {
|
||||
wallpaperButton?.onPress()
|
||||
playSound(CobblemonSounds.PC_CLICK)
|
||||
} else if (displayOptions) {
|
||||
optionsButton!!.onPress()
|
||||
playSound(CobblemonSounds.PC_CLICK)
|
||||
} else if (storageWidget.grabbedSlot != null) {
|
||||
storageWidget.resetSelected()
|
||||
} else {
|
||||
closeNormally(true)
|
||||
}
|
||||
}
|
||||
it.onActiveChange = { state ->
|
||||
if (!state) {
|
||||
storageWidget.controllerComponentManager.active = false
|
||||
} else {
|
||||
if (it.currentSelectedComponent == "storage") storageWidget.controllerComponentManager.active = true
|
||||
}
|
||||
}
|
||||
it.buttonGuides.add(ControllerComponentManager.ButtonGuide(
|
||||
ControllerComponentManager.ButtonGuideType.START,
|
||||
{ true },
|
||||
Component.translatable("cobblemon.controller.quick_search")
|
||||
))
|
||||
it.buttonGuides.add(ControllerComponentManager.ButtonGuide(
|
||||
ControllerComponentManager.ButtonGuideType.TAB,
|
||||
{ true },
|
||||
Component.translatable("cobblemon.controller.pc.switch_box")
|
||||
))
|
||||
it.buttonGuides.add(ControllerComponentManager.ButtonGuide(
|
||||
ControllerComponentManager.ButtonGuideType.SECONDARY_TAB,
|
||||
{ true },
|
||||
Component.translatable("cobblemon.controller.pc.switch_stats")
|
||||
))
|
||||
it.buttonGuides.add(ControllerComponentManager.ButtonGuide(
|
||||
ControllerComponentManager.ButtonGuideType.SPECIAL_1,
|
||||
{ it.currentSelectedComponent == "storage" && storageWidget.controllerComponentManager.currentSelectedComponent != "pasture" },
|
||||
Component.translatable("cobblemon.controller.toggle_held_item_type"),
|
||||
true
|
||||
))
|
||||
it.buttonGuides.add(ControllerComponentManager.ButtonGuide(
|
||||
ControllerComponentManager.ButtonGuideType.SPECIAL_1,
|
||||
{ it.currentSelectedComponent == "storage" && storageWidget.controllerComponentManager.currentSelectedComponent == "pasture" &&
|
||||
storageWidget.pastureWidget!!.controllerComponentManager.currentSelectedComponent.startsWith("slot_") },
|
||||
Component.translatable("cobblemon.controller.pc.toggle_defence"),
|
||||
true
|
||||
))
|
||||
it.buttonGuides.add(ControllerComponentManager.ButtonGuide(
|
||||
ControllerComponentManager.ButtonGuideType.SPECIAL_2,
|
||||
{ it.currentSelectedComponent == "storage" && storageWidget.controllerComponentManager.currentSelectedComponent != "pasture" },
|
||||
Component.translatable("cobblemon.controller.pc.box_settings"),
|
||||
true
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSelectionPosAndSize(): Vector4i? {
|
||||
val data = super.getSelectionPosAndSize()
|
||||
if (data == null) {
|
||||
when (controllerComponentManager.currentSelectedComponent) {
|
||||
"wallpaper_widget" -> return Vector4i(wallpaperWidget.rowLeft - 2, wallpaperWidget.getRowTop(wallpaperWidget.children().indexOf(focused)) + 2,
|
||||
WallpapersScrollingWidget.SLOT_WIDTH + 4, WallpapersScrollingWidget.SLOT_HEIGHT + 4)
|
||||
"storage" -> {
|
||||
if (storageWidget.pastureWidget != null && storageWidget.controllerComponentManager.currentSelectedComponent == "pasture") {
|
||||
val scrollWidget = storageWidget.pastureWidget!!.pastureScrollList
|
||||
if (storageWidget.pastureWidget!!.controllerComponentManager.currentSelectedComponent.startsWith("slot_")) {
|
||||
return Vector4i(scrollWidget.rowLeft - 6, scrollWidget.getRowTop(scrollWidget.children().indexOf(focused)),
|
||||
PasturePokemonScrollList.SLOT_WIDTH + 4, PasturePokemonScrollList.SLOT_HEIGHT + 4)
|
||||
} else if (storageWidget.pastureWidget!!.controllerComponentManager.currentSelectedComponent == "empty") {
|
||||
return Vector4i(scrollWidget.x - 2, scrollWidget.y - 11, scrollWidget.width + 4, scrollWidget.height + 13)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
override fun render(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
@@ -463,7 +659,7 @@ class PCGUI(
|
||||
)
|
||||
|
||||
// Poké Ball
|
||||
val ballResource = cobblemonResource("textures/item/poke_balls/" + pokemon.caughtBall.name.path + ".png")
|
||||
val ballResource = pokemon.caughtBall.name.toAssetPath("textures/item/poke_balls/", ".png")
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = ballResource,
|
||||
@@ -684,7 +880,7 @@ class PCGUI(
|
||||
)
|
||||
|
||||
if (!optionButtons.isEmpty() && displayOptions) {
|
||||
for (button in optionButtons) button.showAlt = hasShiftDown()
|
||||
for (button in optionButtons) button.showAlt = hasShiftDown() || (controllerComponentManager.active && controllerShiftToggle)
|
||||
}
|
||||
|
||||
super.render(context, mouseX, mouseY, delta)
|
||||
@@ -699,6 +895,8 @@ class PCGUI(
|
||||
if (itemHovered) context.renderTooltip(Minecraft.getInstance().font, displayedItem, mouseX, mouseY)
|
||||
}
|
||||
}
|
||||
|
||||
renderSelection(matrices)
|
||||
}
|
||||
|
||||
fun closeNormally(unlink: Boolean = true) {
|
||||
|
||||
@@ -27,8 +27,8 @@ class ReleaseButton(
|
||||
) : Button(x, y, WIDTH, HEIGHT, Component.literal("Release"), onPress, DEFAULT_NARRATION), CobblemonRenderable {
|
||||
|
||||
companion object {
|
||||
private const val WIDTH = 58
|
||||
private const val HEIGHT = 16
|
||||
const val WIDTH = 58
|
||||
const val HEIGHT = 16
|
||||
|
||||
private val buttonResource = cobblemonResource("textures/gui/pc/pc_release_button.png")
|
||||
}
|
||||
@@ -42,7 +42,7 @@ class ReleaseButton(
|
||||
y = y,
|
||||
width = WIDTH,
|
||||
height = HEIGHT,
|
||||
vOffset = if (isHovered(mouseX.toDouble(), mouseY.toDouble())) HEIGHT else 0,
|
||||
vOffset = if (isHovered(mouseX.toDouble(), mouseY.toDouble()) || isFocused) HEIGHT else 0,
|
||||
textureHeight = HEIGHT * 2
|
||||
)
|
||||
|
||||
|
||||
+3
-3
@@ -28,8 +28,8 @@ class ReleaseConfirmButton(
|
||||
) : Button(x, y, WIDTH, HEIGHT, Component.literal("ReleaseConfirm"), onPress, DEFAULT_NARRATION), CobblemonRenderable {
|
||||
|
||||
companion object {
|
||||
private const val WIDTH = 30
|
||||
private const val HEIGHT = 13
|
||||
const val WIDTH = 30
|
||||
const val HEIGHT = 13
|
||||
|
||||
private val buttonResource = cobblemonResource("textures/gui/pc/pc_release_button_confirm.png")
|
||||
}
|
||||
@@ -43,7 +43,7 @@ class ReleaseConfirmButton(
|
||||
y = y,
|
||||
width = WIDTH,
|
||||
height = HEIGHT,
|
||||
vOffset = if (isHovered(mouseX.toDouble(), mouseY.toDouble())) HEIGHT else 0,
|
||||
vOffset = if (isHovered(mouseX.toDouble(), mouseY.toDouble()) || isFocused) HEIGHT else 0,
|
||||
textureHeight = HEIGHT * 2
|
||||
)
|
||||
|
||||
|
||||
@@ -20,6 +20,9 @@ import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.gui.pasture.PasturePCGUIConfiguration
|
||||
import com.cobblemon.mod.common.client.gui.pasture.PastureWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.SoundlessWidget
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponent
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponentManager
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.SubManagerComponent
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.render.gui.PCBoxWallpaperRepository
|
||||
import com.cobblemon.mod.common.client.settings.ServerSettings
|
||||
@@ -41,6 +44,7 @@ import net.minecraft.client.resources.sounds.SimpleSoundInstance
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.sounds.SoundEvent
|
||||
import org.joml.Vector2i
|
||||
|
||||
class StorageWidget(
|
||||
pX: Int, pY: Int,
|
||||
@@ -91,6 +95,9 @@ class StorageWidget(
|
||||
this.setupStorageSlots()
|
||||
}
|
||||
|
||||
val controllerComponentManager = ControllerComponentManager(pcGui)
|
||||
var grabbedSlotControllerPos = Vector2i()
|
||||
|
||||
init {
|
||||
this.setupStorageSlots()
|
||||
|
||||
@@ -102,6 +109,7 @@ class StorageWidget(
|
||||
if (!displayConfirmRelease && canDeleteSelected()) {
|
||||
displayConfirmRelease = true
|
||||
playSound(CobblemonSounds.PC_CLICK)
|
||||
controllerComponentManager.focused = controllerComponentManager.componentList["release_no"]
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -126,6 +134,7 @@ class StorageWidget(
|
||||
playSound(CobblemonSounds.PC_RELEASE)
|
||||
resetSelected()
|
||||
displayConfirmRelease = false
|
||||
controllerComponentManager.focused = controllerComponentManager.componentList["slot_0_0"]
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -139,6 +148,7 @@ class StorageWidget(
|
||||
if (displayConfirmRelease) {
|
||||
displayConfirmRelease = false
|
||||
playSound(CobblemonSounds.PC_CLICK)
|
||||
controllerComponentManager.focused = controllerComponentManager.componentList["release"]
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -146,6 +156,47 @@ class StorageWidget(
|
||||
if (pcGui.configuration is PasturePCGUIConfiguration) {
|
||||
this.pastureWidget = PastureWidget(this, pcGui.configuration, x + 182, y - 19)
|
||||
}
|
||||
|
||||
controllerComponentManager.componentList["release"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = releaseButton
|
||||
it.up = { controllerComponentManager.componentList["party_slot_2_0"] }
|
||||
it.left = { controllerComponentManager.componentList["slot_4_5"] }
|
||||
it.onSelect = {
|
||||
grabbedSlotControllerPos = Vector2i(releaseButton.x + ReleaseButton.WIDTH / 2 + 4, releaseButton.y + ReleaseButton.HEIGHT / 2 + 4)
|
||||
}
|
||||
}
|
||||
controllerComponentManager.componentList["release_no"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = releaseNoButton
|
||||
it.up = { controllerComponentManager.componentList["party_slot_2_1"] }
|
||||
it.left = { controllerComponentManager.componentList["release_yes"] }
|
||||
it.onSelect = {
|
||||
grabbedSlotControllerPos = Vector2i(releaseNoButton.x + ReleaseConfirmButton.WIDTH / 2 + 4, releaseNoButton.y + ReleaseConfirmButton.HEIGHT / 2 + 4)
|
||||
}
|
||||
it.onUnselect = {
|
||||
if (!controllerComponentManager.currentSelectedComponent.startsWith("release")) displayConfirmRelease = false
|
||||
}
|
||||
}
|
||||
controllerComponentManager.componentList["release_yes"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = releaseYesButton
|
||||
it.up = { controllerComponentManager.componentList["party_slot_2_0"] }
|
||||
it.left = { controllerComponentManager.componentList["slot_4_5"] }
|
||||
it.right = { controllerComponentManager.componentList["release_no"] }
|
||||
it.onSelect = {
|
||||
grabbedSlotControllerPos = Vector2i(releaseYesButton.x + ReleaseConfirmButton.WIDTH / 2 + 4, releaseYesButton.y + ReleaseConfirmButton.HEIGHT / 2 + 4)
|
||||
}
|
||||
it.onUnselect = {
|
||||
if (!controllerComponentManager.currentSelectedComponent.startsWith("release")) displayConfirmRelease = false
|
||||
}
|
||||
}
|
||||
if (pastureWidget != null) {
|
||||
controllerComponentManager.componentList["pasture"] = SubManagerComponent().also {
|
||||
it.subManager = { pastureWidget!!.controllerComponentManager }
|
||||
it.left = { controllerComponentManager.componentList["slot_0_5"] }
|
||||
}
|
||||
}
|
||||
controllerComponentManager.let {
|
||||
it.focused = it.componentList["slot_0_0"]
|
||||
}
|
||||
}
|
||||
|
||||
fun canDeleteSelected(): Boolean {
|
||||
@@ -164,7 +215,7 @@ class StorageWidget(
|
||||
|
||||
for (row in 1..5) {
|
||||
for (col in 1..6) {
|
||||
BoxStorageSlot(
|
||||
val slot = BoxStorageSlot(
|
||||
x = boxStartX + ((col - 1) * (StorageSlot.SIZE + BOX_SLOT_PADDING)),
|
||||
y = boxStartY + ((row - 1) * (StorageSlot.SIZE + BOX_SLOT_PADDING)),
|
||||
parent = this,
|
||||
@@ -176,6 +227,27 @@ class StorageWidget(
|
||||
this.boxSlots.add(widget)
|
||||
}
|
||||
index++
|
||||
|
||||
val adjCol = col - 1
|
||||
val adjRow = row - 1
|
||||
controllerComponentManager.componentList["slot_${adjRow}_${adjCol}"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = slot
|
||||
if (adjCol - 1 >= 0) it.left = { controllerComponentManager.componentList["slot_${adjRow}_${adjCol-1}"] }
|
||||
if (adjCol + 1 <= 5) it.right = { controllerComponentManager.componentList["slot_${adjRow}_${adjCol+1}"] }
|
||||
else if (pastureWidget == null) {
|
||||
it.right = when (adjRow) {
|
||||
4 -> {{ if (canDeleteSelected()) controllerComponentManager.componentList["release"] else null }}
|
||||
3 -> {{ controllerComponentManager.componentList["party_slot_2_0"] }}
|
||||
else -> {{ controllerComponentManager.componentList["party_slot_${adjRow}_0"] }}
|
||||
}
|
||||
} else {
|
||||
it.right = { controllerComponentManager.componentList["pasture"] }
|
||||
}
|
||||
if (adjRow - 1 >= 0) it.up = { controllerComponentManager.componentList["slot_${adjRow-1}_${adjCol}"] }
|
||||
if (adjRow + 1 <= 4) it.down = { controllerComponentManager.componentList["slot_${adjRow+1}_${adjCol}"] }
|
||||
it.onSelect = { grabbedSlotControllerPos = Vector2i(slot.x + slot.width / 2 + 4, slot.y + slot.height / 2 + 4) }
|
||||
it.onPress = { if (slot.clickable()) slot.onPress() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,7 +266,7 @@ class StorageWidget(
|
||||
partyY += ((StorageSlot.SIZE + PARTY_SLOT_PADDING) * offsetIndex) + offsetY
|
||||
}
|
||||
|
||||
PartyStorageSlot(
|
||||
val slot = PartyStorageSlot(
|
||||
x = partyX,
|
||||
y = partyY,
|
||||
parent = this,
|
||||
@@ -205,6 +277,22 @@ class StorageWidget(
|
||||
this.addWidget(widget)
|
||||
this.partySlots.add(widget)
|
||||
}
|
||||
|
||||
val row = partyIndex / 2
|
||||
val col = partyIndex % 2
|
||||
controllerComponentManager.componentList["party_slot_${row}_${col}"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = slot
|
||||
if (col == 1) it.left = { controllerComponentManager.componentList["party_slot_${row}_0"] }
|
||||
else {
|
||||
it.right = { controllerComponentManager.componentList["party_slot_${row}_1"] }
|
||||
it.left = { controllerComponentManager.componentList["slot_${row}_5"] }
|
||||
}
|
||||
if (row - 1 >= 0) it.up = { controllerComponentManager.componentList["party_slot_${row-1}_${col}"] }
|
||||
if (row + 1 <= 2) it.down = { controllerComponentManager.componentList["party_slot_${row+1}_${col}"] }
|
||||
else it.down = { if (canDeleteSelected()) controllerComponentManager.componentList["release"] else null }
|
||||
it.onSelect = { grabbedSlotControllerPos = Vector2i(slot.x + slot.width / 2 + 4, slot.y + slot.height / 2 + 4) }
|
||||
it.onPress = { if (slot.clickable()) slot.onPress() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,7 +395,7 @@ class StorageWidget(
|
||||
this.boxSlots.forEach { slot ->
|
||||
slot.render(context, mouseX, mouseY, delta)
|
||||
val pokemon = slot.getPokemon()
|
||||
if (grabbedSlot == null && slot.isHovered(mouseX, mouseY)
|
||||
if (grabbedSlot == null && (slot.isHovered(mouseX, mouseY) || slot.isFocused)
|
||||
&& pokemon != null && pokemon != pcGui.previewPokemon
|
||||
) {
|
||||
pcGui.setPreviewPokemon(pokemon, pcGui.isPreviewInParty ?: false)
|
||||
@@ -323,7 +411,7 @@ class StorageWidget(
|
||||
this.partySlots.forEach { slot ->
|
||||
slot.render(context, mouseX, mouseY, delta)
|
||||
val pokemon = slot.getPokemon()
|
||||
if (grabbedSlot == null && slot.isHovered(mouseX, mouseY)
|
||||
if (grabbedSlot == null && (slot.isHovered(mouseX, mouseY) || slot.isFocused)
|
||||
&& pokemon != null && pokemon != pcGui.previewPokemon
|
||||
) {
|
||||
pcGui.setPreviewPokemon(pokemon, pcGui.isPreviewInParty ?: true)
|
||||
@@ -335,7 +423,11 @@ class StorageWidget(
|
||||
pastureWidget?.render(context, mouseX, mouseY, delta)
|
||||
matrices.pushPose()
|
||||
matrices.translate(0.0, 0.0, 1000.0)
|
||||
grabbedSlot?.render(context, mouseX, mouseY, delta)
|
||||
if (controllerComponentManager.active) {
|
||||
grabbedSlot?.render(context, grabbedSlotControllerPos.x, grabbedSlotControllerPos.y, delta)
|
||||
} else {
|
||||
grabbedSlot?.render(context, mouseX, mouseY, delta)
|
||||
}
|
||||
matrices.popPose()
|
||||
}
|
||||
|
||||
@@ -372,6 +464,9 @@ class StorageWidget(
|
||||
}
|
||||
|
||||
// Reset release confirmation
|
||||
if (controllerComponentManager.currentSelectedComponent.startsWith("release")) {
|
||||
controllerComponentManager.focused = controllerComponentManager.componentList["slot_0_0"]
|
||||
}
|
||||
displayConfirmRelease = false
|
||||
|
||||
// Clicking on itself, so unselect position
|
||||
|
||||
+36
-8
@@ -15,6 +15,8 @@ import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.gui.ScrollingWidget
|
||||
import com.cobblemon.mod.common.client.gui.pc.WallpapersScrollingWidget.WallpaperEntry
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponent
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponentManager
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.render.gui.PCBoxWallpaperRepository
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.pc.RequestChangePCBoxWallpaperPacket
|
||||
@@ -49,10 +51,14 @@ class WallpapersScrollingWidget(
|
||||
val backgroundResource = cobblemonResource("textures/gui/pc/wallpaper_scroll_background.png")
|
||||
}
|
||||
|
||||
val controllerComponentManager = ControllerComponentManager(pcGui)
|
||||
|
||||
init {
|
||||
this.visible = false
|
||||
this.y = pY
|
||||
createEntries()
|
||||
|
||||
|
||||
}
|
||||
|
||||
override fun getScrollbarPosition(): Int = x + width - 3
|
||||
@@ -90,6 +96,24 @@ class WallpapersScrollingWidget(
|
||||
}
|
||||
}
|
||||
|
||||
override fun addEntry(entry: WallpaperEntry): Int {
|
||||
val i = super.addEntry(entry)
|
||||
controllerComponentManager.componentList["wallpaper_${i}"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = entry
|
||||
it.onPress = { entry.selectWallpaper() }
|
||||
it.onFocus = { ensureVisible(entry) }
|
||||
}
|
||||
if (children().size > 1) {
|
||||
controllerComponentManager.componentList["wallpaper_${i}"]?.let {
|
||||
it.pairUp(controllerComponentManager.componentList["wallpaper_${i-1}"])
|
||||
it.pairDown(controllerComponentManager.componentList["wallpaper_${0}"])
|
||||
}
|
||||
} else {
|
||||
controllerComponentManager.focused = controllerComponentManager.componentList["wallpaper_${i}"]
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
override fun getRowLeft(): Int {
|
||||
return this.left + SLOT_PADDING
|
||||
}
|
||||
@@ -116,7 +140,7 @@ class WallpapersScrollingWidget(
|
||||
partialTick: Float
|
||||
) {
|
||||
val matrices = guiGraphics.pose()
|
||||
val resource = if (Screen.hasShiftDown() && altWallpaper !== null) altWallpaper else wallpaper
|
||||
val resource = if ((Screen.hasShiftDown() || (pcGui.controllerComponentManager.active && pcGui.controllerShiftToggle)) && altWallpaper !== null) altWallpaper else wallpaper
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = resource,
|
||||
@@ -133,24 +157,28 @@ class WallpapersScrollingWidget(
|
||||
y = top + SLOT_PADDING,
|
||||
width = width,
|
||||
height = SLOT_HEIGHT,
|
||||
vOffset = if (hovering) SLOT_HEIGHT else 0,
|
||||
vOffset = if (hovering || isFocused) SLOT_HEIGHT else 0,
|
||||
textureHeight = SLOT_HEIGHT * 2
|
||||
)
|
||||
}
|
||||
|
||||
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
|
||||
if (this@WallpapersScrollingWidget.visible && isMouseOver(mouseX, mouseY)) {
|
||||
val appliedWallpaper = if (Screen.hasShiftDown()) altWallpaper ?: wallpaper else wallpaper
|
||||
RequestChangePCBoxWallpaperPacket(pcGui.pc.uuid, storageWidget.box, wallpaper, if (Screen.hasShiftDown()) altWallpaper else null).sendToServer()
|
||||
pcGui.pc.boxes[storageWidget.box].wallpaper = appliedWallpaper
|
||||
pcGui.unseenWallpapers.remove(wallpaper)
|
||||
isNew = false
|
||||
minecraft.soundManager.play(SimpleSoundInstance.forUI(CobblemonSounds.PC_CLICK, 1.0F))
|
||||
selectWallpaper()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun selectWallpaper() {
|
||||
val appliedWallpaper = if (Screen.hasShiftDown() || (pcGui.controllerComponentManager.active && pcGui.controllerShiftToggle)) altWallpaper ?: wallpaper else wallpaper
|
||||
RequestChangePCBoxWallpaperPacket(pcGui.pc.uuid, storageWidget.box, wallpaper, if (Screen.hasShiftDown() || (pcGui.controllerComponentManager.active && pcGui.controllerShiftToggle)) altWallpaper else null).sendToServer()
|
||||
pcGui.pc.boxes[storageWidget.box].wallpaper = appliedWallpaper
|
||||
pcGui.unseenWallpapers.remove(wallpaper)
|
||||
isNew = false
|
||||
minecraft.soundManager.play(SimpleSoundInstance.forUI(CobblemonSounds.PC_CLICK, 1.0F))
|
||||
}
|
||||
|
||||
override fun getNarration(): Component? {
|
||||
return wallpaper.toString().text()
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.pokedex.CaughtCount
|
||||
import com.cobblemon.mod.common.api.pokedex.Dexes
|
||||
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
|
||||
import com.cobblemon.mod.common.api.pokedex.SeenCount
|
||||
import com.cobblemon.mod.common.api.pokedex.def.PokedexDef
|
||||
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
|
||||
@@ -25,7 +26,6 @@ import com.cobblemon.mod.common.api.pokedex.filter.SearchFilter
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.api.storage.player.client.ClientPokedexManager
|
||||
import com.cobblemon.mod.common.api.text.bold
|
||||
import com.cobblemon.mod.common.api.text.font
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.client.ClientMoLangFunctions.setupClient
|
||||
import com.cobblemon.mod.common.client.CobblemonClient
|
||||
@@ -42,6 +42,9 @@ import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.TAB_ICON_
|
||||
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.TAB_SIZE
|
||||
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.TAB_STATS
|
||||
import com.cobblemon.mod.common.client.gui.pokedex.widgets.*
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponent
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponentManager
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerScreen
|
||||
import com.cobblemon.mod.common.client.pokedex.PokedexType
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.net.messages.server.block.AdjustBlockEntityViewerCountPacket
|
||||
@@ -61,6 +64,8 @@ import net.minecraft.core.BlockPos
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.sounds.SoundEvent
|
||||
import net.minecraft.sounds.SoundEvents
|
||||
import org.joml.Vector4i
|
||||
|
||||
/**
|
||||
* Pokedex GUI
|
||||
@@ -72,7 +77,7 @@ class PokedexGUI private constructor(
|
||||
val type: PokedexType,
|
||||
val initSpecies: ResourceLocation?,
|
||||
val blockPos: BlockPos?
|
||||
): Screen(Component.translatable("cobblemon.ui.pokedex.title")), CobblemonRenderable {
|
||||
): Screen(Component.translatable("cobblemon.ui.pokedex.title")), CobblemonRenderable, ControllerScreen {
|
||||
companion object {
|
||||
private val screenBackground = cobblemonResource("textures/gui/pokedex/pokedex_screen.png")
|
||||
|
||||
@@ -137,6 +142,14 @@ class PokedexGUI private constructor(
|
||||
lateinit var tabInfoElement: GuiEventListener
|
||||
var tabInfoIndex = TAB_DESCRIPTION
|
||||
|
||||
val controllerComponentManager = ControllerComponentManager(this)
|
||||
var lastTileComponent: ControllerComponent? = null
|
||||
var lastSelectedColumn = 0
|
||||
|
||||
override fun getComponentManager(): ControllerComponentManager {
|
||||
return controllerComponentManager
|
||||
}
|
||||
|
||||
override fun renderBlurredBackground(delta: Float) {}
|
||||
override fun renderMenuBackground(context: GuiGraphics) {}
|
||||
|
||||
@@ -209,6 +222,232 @@ class PokedexGUI private constructor(
|
||||
addRenderableWidget(searchByTypeButton)
|
||||
|
||||
updateFilters(true)
|
||||
|
||||
fun hasKnowledge(): Boolean {
|
||||
val currentEntry = pokemonInfoWidget.currentEntry
|
||||
return currentEntry != null && CobblemonClient.clientPokedexData.getKnowledgeForSpecies(currentEntry.speciesId) != PokedexEntryProgress.NONE
|
||||
}
|
||||
|
||||
controllerComponentManager.componentList["search"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = searchWidget
|
||||
it.down = {
|
||||
val returnVal = if (scrollScreen.children().isNotEmpty()) {
|
||||
controllerComponentManager.componentList["tile_0_0"]
|
||||
} else {
|
||||
controllerComponentManager.componentList["empty_entries"]
|
||||
}
|
||||
returnVal
|
||||
}
|
||||
it.onSpecial1 = {
|
||||
searchByTypeButton.onPress()
|
||||
playSound(CobblemonSounds.POKEDEX_CLICK_SHORT)
|
||||
}
|
||||
}
|
||||
controllerComponentManager.componentList["empty_entries"] = ControllerComponent().also {
|
||||
it.up = { controllerComponentManager.componentList["search"] }
|
||||
it.right = { controllerComponentManager.componentList["pokemon_render"] }
|
||||
}
|
||||
controllerComponentManager.componentList["pokemon_render"] = ControllerComponent().also {
|
||||
it.left = {
|
||||
val returnVal = if (scrollScreen.children().isNotEmpty()) {
|
||||
lastTileComponent
|
||||
} else {
|
||||
controllerComponentManager.componentList["empty_entries"]
|
||||
}
|
||||
returnVal
|
||||
}
|
||||
it.down = { controllerComponentManager.componentList["info_widget"] }
|
||||
it.onPress = {
|
||||
if (hasKnowledge()) {
|
||||
pokemonInfoWidget.playCry()
|
||||
}
|
||||
}
|
||||
it.onSpecial1 = {
|
||||
if (hasKnowledge() && pokemonInfoWidget.genderButton.visible) {
|
||||
pokemonInfoWidget.genderButton.onPress()
|
||||
playSound(CobblemonSounds.POKEDEX_CLICK_SHORT)
|
||||
}
|
||||
}
|
||||
it.onSpecial2 = {
|
||||
if (hasKnowledge() && pokemonInfoWidget.shinyButton.visible) {
|
||||
pokemonInfoWidget.shinyButton.onPress()
|
||||
playSound(CobblemonSounds.POKEDEX_CLICK_SHORT)
|
||||
}
|
||||
}
|
||||
}
|
||||
controllerComponentManager.componentList["info_widget"] = ControllerComponent().also {
|
||||
it.left = {
|
||||
val returnVal = if (scrollScreen.children().isNotEmpty()) {
|
||||
lastTileComponent
|
||||
} else {
|
||||
controllerComponentManager.componentList["empty_entries"]
|
||||
}
|
||||
returnVal
|
||||
}
|
||||
it.up = { controllerComponentManager.componentList["pokemon_render"] }
|
||||
}
|
||||
controllerComponentManager.let {
|
||||
it.focused = it.componentList["tile_0_0"] ?: it.componentList["empty_entries"]
|
||||
it.onTabNav = { nextTab ->
|
||||
if (it.currentSelectedComponent == "empty_entries" || it.currentSelectedComponent.startsWith("tile_")) {
|
||||
updatePokedexRegion(nextTab)
|
||||
playSound(CobblemonSounds.POKEDEX_CLICK_SHORT)
|
||||
} else if (it.currentSelectedComponent == "pokemon_render") {
|
||||
val currentEntry = pokemonInfoWidget.currentEntry
|
||||
if (currentEntry != null) {
|
||||
val hasKnowledge = CobblemonClient.clientPokedexData.getKnowledgeForSpecies(currentEntry.speciesId) != PokedexEntryProgress.NONE
|
||||
val showableForms = CobblemonClient.clientPokedexData.getEncounteredForms(currentEntry)
|
||||
if (hasKnowledge && showableForms.size > 1 && showableForms.size > pokemonInfoWidget.selectedFormIndex) {
|
||||
pokemonInfoWidget.switchForm(nextTab)
|
||||
playSound(CobblemonSounds.POKEDEX_CLICK_SHORT)
|
||||
}
|
||||
}
|
||||
} else if (it.currentSelectedComponent == "info_widget") {
|
||||
val trimmedTabs = tabButtons.filterIndexed { index, _ -> tabInfoIndex == index || canSelectTab(index) }.map { tabButtons.indexOf(it) }.toMutableList()
|
||||
var currentTab = trimmedTabs.indexOf(tabInfoIndex) + if (nextTab) 1 else -1
|
||||
if (currentTab > trimmedTabs.size - 1) currentTab = 0
|
||||
else if (currentTab < 0) currentTab = trimmedTabs.size - 1
|
||||
displaytabInfoElement(trimmedTabs[currentTab])
|
||||
if (trimmedTabs.size > 1) playSound(CobblemonSounds.POKEDEX_CLICK_SHORT)
|
||||
}
|
||||
}
|
||||
it.onSecondaryTabNav = { nextTab ->
|
||||
if (it.currentSelectedComponent == "pokemon_render") {
|
||||
pokemonInfoWidget.switchPose(nextTab)
|
||||
playSound(CobblemonSounds.POKEDEX_CLICK_SHORT)
|
||||
} else if (it.currentSelectedComponent == "info_widget") {
|
||||
(tabInfoElement as? AbilitiesWidget)?.let {
|
||||
it.switchAbility(nextTab)
|
||||
playSound(CobblemonSounds.POKEDEX_CLICK_SHORT)
|
||||
}
|
||||
(tabInfoElement as? StatsWidget)?.let { widget ->
|
||||
if (nextTab) {
|
||||
if (children().contains(widget.rightButton)) {
|
||||
widget.rightButton.onPress()
|
||||
playSound(CobblemonSounds.POKEDEX_CLICK_SHORT)
|
||||
}
|
||||
} else {
|
||||
if (children().contains(widget.leftButton)) {
|
||||
widget.leftButton.onPress()
|
||||
playSound(CobblemonSounds.POKEDEX_CLICK_SHORT)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
it.onRHorizontalHeld = { right ->
|
||||
if (it.currentSelectedComponent == "pokemon_render") {
|
||||
pokemonInfoWidget.rotationY = ((pokemonInfoWidget.rotationY + if (right) -5F else 5F ) % 360 + 360) % 360
|
||||
}
|
||||
}
|
||||
it.onRVerticalHeld = { up ->
|
||||
if (it.currentSelectedComponent == "info_widget") {
|
||||
(tabInfoElement as? InfoTextScrollWidget)?.scroll(if (up) -3 else 3)
|
||||
}
|
||||
}
|
||||
it.onRHorizontal = { right ->
|
||||
if (it.currentSelectedComponent == "info_widget") {
|
||||
(tabInfoElement as? StatsWidget)?.let { widget ->
|
||||
if (widget.selectedStatTypeIndex == StatsWidget.STAT_TYPE_RIDE) {
|
||||
if (right) {
|
||||
if (children().contains(widget.rightSubButton)) {
|
||||
widget.rightSubButton.onPress()
|
||||
playSound(CobblemonSounds.POKEDEX_CLICK_SHORT)
|
||||
}
|
||||
} else {
|
||||
if (children().contains(widget.leftSubButton)) {
|
||||
widget.leftSubButton.onPress()
|
||||
playSound(CobblemonSounds.POKEDEX_CLICK_SHORT)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
it.onStart = {
|
||||
it.focused = it.componentList["search"]
|
||||
it.openKeyboard.invoke(it.focused!!.associatedGUIElement as EditBox)
|
||||
playSound(SoundEvents.UI_BUTTON_CLICK.value())
|
||||
}
|
||||
it.buttonGuides.add(ControllerComponentManager.ButtonGuide(
|
||||
ControllerComponentManager.ButtonGuideType.START,
|
||||
{ true },
|
||||
Component.translatable("cobblemon.controller.quick_search")
|
||||
))
|
||||
it.buttonGuides.add(ControllerComponentManager.ButtonGuide(
|
||||
ControllerComponentManager.ButtonGuideType.TAB,
|
||||
{ it.currentSelectedComponent == "empty_entries" || it.currentSelectedComponent.startsWith("tile_") },
|
||||
Component.translatable("cobblemon.controller.dex.cycle_region")
|
||||
))
|
||||
it.buttonGuides.add(ControllerComponentManager.ButtonGuide(
|
||||
ControllerComponentManager.ButtonGuideType.TAB,
|
||||
{ it.currentSelectedComponent == "pokemon_render" && hasKnowledge() && pokemonInfoWidget.visibleForms.size > 1},
|
||||
Component.translatable("cobblemon.controller.dex.cycle_form"),
|
||||
true
|
||||
))
|
||||
it.buttonGuides.add(ControllerComponentManager.ButtonGuide(
|
||||
ControllerComponentManager.ButtonGuideType.SECONDARY_TAB,
|
||||
{ it.currentSelectedComponent == "pokemon_render" && hasKnowledge() },
|
||||
Component.translatable("cobblemon.controller.dex.cycle_animation")
|
||||
))
|
||||
it.buttonGuides.add(ControllerComponentManager.ButtonGuide(
|
||||
ControllerComponentManager.ButtonGuideType.SECONDARY_TAB,
|
||||
{ it.currentSelectedComponent == "info_widget" && tabInfoElement is AbilitiesWidget },
|
||||
Component.translatable("cobblemon.controller.dex.cycle_ability")
|
||||
))
|
||||
it.buttonGuides.add(ControllerComponentManager.ButtonGuide(
|
||||
ControllerComponentManager.ButtonGuideType.SECONDARY_TAB,
|
||||
{ it.currentSelectedComponent == "info_widget" && (tabInfoElement as? StatsWidget)?.let { children().contains(it.rightButton) } ?: false },
|
||||
Component.translatable("cobblemon.controller.dex.cycle_stats")
|
||||
))
|
||||
it.buttonGuides.add(ControllerComponentManager.ButtonGuide(
|
||||
ControllerComponentManager.ButtonGuideType.JOYSTICK_HORIZONTAL,
|
||||
{ it.currentSelectedComponent == "info_widget" && (tabInfoElement as? StatsWidget)?.let { it.selectedStatTypeIndex == StatsWidget.STAT_TYPE_RIDE && children().contains(it.rightSubButton) } ?: false },
|
||||
Component.translatable("cobblemon.controller.dex.cycle_ride_style")
|
||||
))
|
||||
it.buttonGuides.add(ControllerComponentManager.ButtonGuide(
|
||||
ControllerComponentManager.ButtonGuideType.SPECIAL_1,
|
||||
{ it.currentSelectedComponent == "search" },
|
||||
Component.translatable("cobblemon.controller.dex.cycle_search_by"),
|
||||
true
|
||||
))
|
||||
it.buttonGuides.add(ControllerComponentManager.ButtonGuide(
|
||||
ControllerComponentManager.ButtonGuideType.SPECIAL_1,
|
||||
{ it.currentSelectedComponent == "pokemon_render" && hasKnowledge() && pokemonInfoWidget.genderButton.visible },
|
||||
Component.translatable("cobblemon.controller.dex.toggle_gender"),
|
||||
true
|
||||
))
|
||||
it.buttonGuides.add(ControllerComponentManager.ButtonGuide(
|
||||
ControllerComponentManager.ButtonGuideType.SPECIAL_2,
|
||||
{ it.currentSelectedComponent == "pokemon_render" && hasKnowledge() && pokemonInfoWidget.shinyButton.visible },
|
||||
Component.translatable("cobblemon.controller.dex.toggle_shiny"),
|
||||
true
|
||||
))
|
||||
it.buttonGuides.add(ControllerComponentManager.ButtonGuide(
|
||||
ControllerComponentManager.ButtonGuideType.PRESS,
|
||||
{ it.currentSelectedComponent == "pokemon_render" && hasKnowledge() },
|
||||
Component.translatable("cobblemon.controller.dex.play_cry"),
|
||||
true
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSelectionPosAndSize(): Vector4i? {
|
||||
return when (controllerComponentManager.currentSelectedComponent) {
|
||||
"search" -> Vector4i(searchWidget.x - 2, searchWidget.y - 2, searchWidget.width + 15, searchWidget.height + 4)
|
||||
"pokemon_render" -> Vector4i(pokemonInfoWidget.x - 2, pokemonInfoWidget.y + 12, pokemonInfoWidget.width + 6, pokemonInfoWidget.height + 16)
|
||||
"info_widget" -> Vector4i(pokemonInfoWidget.x - 2, pokemonInfoWidget.y + 94, pokemonInfoWidget.width + 6, pokemonInfoWidget.height + 3)
|
||||
"empty_entries" -> Vector4i(scrollScreen.x - 2, scrollScreen.y - 2, scrollScreen.width + 4, scrollScreen.height + 4)
|
||||
else -> {
|
||||
if (controllerComponentManager.currentSelectedComponent.startsWith("tile_")) {
|
||||
val scrollWidget = controllerComponentManager.focused?.associatedGUIElement as? EntriesScrollingWidget.PokemonScrollSlotRow
|
||||
val startX = scrollScreen.x + lastSelectedColumn * (PokedexGUIConstants.SCROLL_SLOT_SIZE + PokedexGUIConstants.SCROLL_SLOT_SPACING)
|
||||
if (scrollWidget != null) {
|
||||
Vector4i(startX - 2, scrollScreen.getRowTop(scrollScreen.children().indexOf(scrollWidget)) + 1, PokedexGUIConstants.SCROLL_SLOT_SIZE + 4, PokedexGUIConstants.SCROLL_SLOT_SIZE + 4)
|
||||
} else null
|
||||
} else null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun render(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
@@ -320,6 +559,8 @@ class PokedexGUI private constructor(
|
||||
|
||||
super.render(context, mouseX, mouseY, delta)
|
||||
|
||||
renderSelection(context.pose())
|
||||
|
||||
// Search type tooltip
|
||||
if (searchByTypeButton.isButtonHovered(mouseX, mouseY)) {
|
||||
val searchTypeText = lang("ui.pokedex.search.search_by", lang("ui.pokedex.search.type.${selectedSearchByType.name.lowercase()}")).bold()
|
||||
@@ -435,6 +676,45 @@ class PokedexGUI private constructor(
|
||||
} else {
|
||||
setSelectedEntry(entries.first())
|
||||
}
|
||||
|
||||
val totalRows = scrollScreen.children().size
|
||||
val lastRowCount = scrollScreen.children()[totalRows-1].dexDataList.size
|
||||
scrollScreen.children().forEachIndexed { row, scrollRow ->
|
||||
scrollRow.dexDataList.forEachIndexed { column, slot ->
|
||||
controllerComponentManager.componentList["tile_${row}_${column}"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = scrollRow
|
||||
if (row - 1 >= 0) it.up = { controllerComponentManager.componentList["tile_${row-1}_${column}"] }
|
||||
else it.up = { controllerComponentManager.componentList["search"] }
|
||||
if (row + 1 <= scrollScreen.children().size - 1 &&
|
||||
(row + 1 != totalRows || column <= lastRowCount - 1)) it.down = { controllerComponentManager.componentList["tile_${row+1}_${column}"] }
|
||||
if (column - 1 >= 0) it.left = { controllerComponentManager.componentList["tile_${row}_${column-1}"] }
|
||||
if (column + 1 <= scrollRow.dexDataList.size - 1) it.right = { controllerComponentManager.componentList["tile_${row}_${column+1}"] }
|
||||
else it.right = { controllerComponentManager.componentList["pokemon_render"] }
|
||||
it.onPress = {
|
||||
scrollRow.setPokedexEntry.invoke(slot)
|
||||
playSound(CobblemonSounds.POKEDEX_CLICK)
|
||||
}
|
||||
it.onSelect = {
|
||||
lastTileComponent = it
|
||||
lastSelectedColumn = column
|
||||
scrollScreen.ensureVisible(scrollRow)
|
||||
}
|
||||
it.onFocus = {
|
||||
scrollRow.slotControllerSelected = column
|
||||
}
|
||||
it.onUnfocus = {
|
||||
scrollRow.slotControllerSelected = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (controllerComponentManager.currentSelectedComponent.let { it == "empty_entries" || it.startsWith("tile_") }) {
|
||||
if (entries.isNotEmpty()) {
|
||||
controllerComponentManager.focused = controllerComponentManager.componentList["tile_0_0"]
|
||||
} else {
|
||||
controllerComponentManager.focused = controllerComponentManager.componentList["empty_entries"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ class AbilitiesWidget(x: Int, y: Int): InfoTextScrollWidget(pX = x, pY = y) {
|
||||
|
||||
init { setAbility() }
|
||||
|
||||
private fun switchAbility(nextIndex: Boolean) {
|
||||
fun switchAbility(nextIndex: Boolean) {
|
||||
val size = abilitiesList.size
|
||||
selectedAbilitiesIndex = if (nextIndex) {
|
||||
(selectedAbilitiesIndex + 1) % size
|
||||
|
||||
+3
-2
@@ -48,7 +48,6 @@ class EntriesScrollingWidget(val pX: Int, val pY: Int, val setPokedexEntry: (Pok
|
||||
top = pY - SCROLL_BASE_HEIGHT,
|
||||
slotHeight = SCROLL_SLOT_SIZE + 2
|
||||
) {
|
||||
|
||||
fun createEntries(filteredPokedex: Collection<PokedexEntry>) {
|
||||
filteredPokedex.chunked(5).forEachIndexed { index, listChunk ->
|
||||
val discoveryList = listChunk.map { CobblemonClient.clientPokedexData.getHighestKnowledgeFor(it) }.toMutableList()
|
||||
@@ -129,6 +128,8 @@ class EntriesScrollingWidget(val pX: Int, val pY: Int, val setPokedexEntry: (Pok
|
||||
var x: Int = 0
|
||||
var y: Int = 0
|
||||
|
||||
var slotControllerSelected = -1
|
||||
|
||||
override fun render(
|
||||
context: GuiGraphics,
|
||||
index: Int,
|
||||
@@ -170,7 +171,7 @@ class EntriesScrollingWidget(val pX: Int, val pY: Int, val setPokedexEntry: (Pok
|
||||
height = SCROLL_SLOT_SIZE
|
||||
)
|
||||
|
||||
if (getHoveredSlotIndex(mouseX, mouseY) == index) {
|
||||
if (getHoveredSlotIndex(mouseX, mouseY) == index || slotControllerSelected == index) {
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = slotHighlight,
|
||||
|
||||
+8
-13
@@ -59,6 +59,7 @@ import net.minecraft.sounds.SoundEvent
|
||||
import org.joml.Quaternionf
|
||||
import org.joml.Vector3f
|
||||
import java.io.FileNotFoundException
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm) -> (Unit)) : SoundlessWidget(
|
||||
pX,
|
||||
@@ -186,7 +187,7 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
|
||||
|
||||
val variationButtons = mutableListOf<VariationButtonWrapper>()
|
||||
|
||||
private val genderButton: ScaledButton = ScaledButton(
|
||||
val genderButton: ScaledButton = ScaledButton(
|
||||
pX + 114F,
|
||||
pY + 27F,
|
||||
20,
|
||||
@@ -198,7 +199,7 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
|
||||
}
|
||||
).apply { addWidget(this) }
|
||||
|
||||
private val shinyButton: ScaledButton = ScaledButton(
|
||||
val shinyButton: ScaledButton = ScaledButton(
|
||||
(pX + 126F),
|
||||
(pY + 27F),
|
||||
20,
|
||||
@@ -364,9 +365,9 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
|
||||
matrices.translate(
|
||||
pX.toDouble() + (POKEMON_PORTRAIT_WIDTH.toDouble() + 2)/2,
|
||||
pY.toDouble() + portraitStartY - 12,
|
||||
1000.0 // Prevent model from clipping into background
|
||||
50.0
|
||||
)
|
||||
matrices.scale(scaleAmount, scaleAmount, scaleAmount)
|
||||
matrices.scale(scaleAmount, scaleAmount, 0.1F) // Scaling Z scale way down to improve order of rendering, too low will cause model rendering to z fight
|
||||
val rotationVector = Vector3f(13F, rotationY, 0F)
|
||||
|
||||
drawProfilePokemon(
|
||||
@@ -392,10 +393,6 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
|
||||
)
|
||||
}
|
||||
|
||||
// Ensure elements are not hidden behind Pokémon render
|
||||
matrices.pushPose()
|
||||
matrices.translate(0.0, 0.0, 2000.0)
|
||||
|
||||
if (isSelectedPokemonOwned()) {
|
||||
val primaryType = type[0]
|
||||
val secondaryType = type[1]
|
||||
@@ -507,8 +504,6 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
matrices.popPose()
|
||||
}
|
||||
|
||||
fun setDexEntry(pokedexEntry : PokedexEntry) {
|
||||
@@ -586,12 +581,12 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
|
||||
type = arrayOf(form.primaryType, form.secondaryType)
|
||||
}
|
||||
|
||||
private fun playCry() {
|
||||
fun playCry() {
|
||||
state.activeAnimations.clear()
|
||||
state.addFirstAnimation(setOf("cry"))
|
||||
}
|
||||
|
||||
private fun switchForm(nextIndex: Boolean) {
|
||||
fun switchForm(nextIndex: Boolean) {
|
||||
if (visibleForms.isEmpty() || currentEntry == null) {
|
||||
return
|
||||
}
|
||||
@@ -612,7 +607,7 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
|
||||
updateAspects()
|
||||
}
|
||||
|
||||
private fun switchPose(nextIndex: Boolean) {
|
||||
fun switchPose(nextIndex: Boolean) {
|
||||
if (nextIndex) {
|
||||
if (selectedPoseIndex < poseList.lastIndex) selectedPoseIndex++
|
||||
else selectedPoseIndex = 0
|
||||
|
||||
+3
-1
@@ -237,9 +237,11 @@ class StatsWidget(val pX: Int, val pY: Int) : SoundlessWidget(
|
||||
blitk(matrixStack = matrices, texture = divider, x = pX + 51, y = pY + 10, height = 27.5, width = 1)
|
||||
blitk(matrixStack = matrices, texture = divider, x = pX + 9, y = pY + 2, height = 6, width = 121)
|
||||
|
||||
val rideStyle = selectedBehaviour.value.key.path.toString().split("/").last().lowercase()
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = lang("ui.ride_style.${selectedBehaviour.key.name.lowercase()}").bold(),
|
||||
text = lang("ui.ride_style.${selectedBehaviour.key.toString().lowercase()}.${rideStyle}")
|
||||
.append(" | ").append(lang("ui.ride_style.${selectedBehaviour.key.toString().lowercase()}")).bold(),
|
||||
x = pX + 69.5,
|
||||
y = pY + 3,
|
||||
colour = 0x3A96B6,
|
||||
|
||||
+41
-5
@@ -9,6 +9,9 @@
|
||||
package com.cobblemon.mod.common.client.gui.snapshots
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBuildDetails
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponent
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponentManager
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerScreen
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.OptionInstance
|
||||
|
||||
@@ -20,10 +23,12 @@ import net.minecraft.client.gui.components.Tooltip
|
||||
import net.minecraft.client.gui.layouts.FrameLayout
|
||||
import net.minecraft.client.gui.layouts.GridLayout
|
||||
import net.minecraft.client.gui.screens.Screen
|
||||
import net.minecraft.client.resources.sounds.SimpleSoundInstance
|
||||
import net.minecraft.network.chat.CommonComponents
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.sounds.SoundEvents
|
||||
|
||||
class SnapshotWarningScreen(val consumer: (Acknowledgement, Boolean) -> Unit) : Screen(TITLE) {
|
||||
class SnapshotWarningScreen(val consumer: (Acknowledgement, Boolean) -> Unit) : Screen(TITLE), ControllerScreen {
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -36,6 +41,12 @@ class SnapshotWarningScreen(val consumer: (Acknowledgement, Boolean) -> Unit) :
|
||||
private val layout = GridLayout().columnSpacing(10).rowSpacing(20)
|
||||
private val dontShowAgain = OptionInstance.createBoolean("cobblemon\$snapshots\$dont_show_again", false)
|
||||
|
||||
val controllerComponentManager = ControllerComponentManager(this)
|
||||
|
||||
override fun getComponentManager(): ControllerComponentManager {
|
||||
return controllerComponentManager
|
||||
}
|
||||
|
||||
override fun init() {
|
||||
super.init()
|
||||
|
||||
@@ -45,17 +56,42 @@ class SnapshotWarningScreen(val consumer: (Acknowledgement, Boolean) -> Unit) :
|
||||
helper.addChild(StringWidget(this.title, this.font), 2, settings)
|
||||
helper.addChild(MultiLineTextWidget(DESCRIPTION, this.font).setCentered(true).setMaxWidth(310), 2, settings)
|
||||
|
||||
helper.addChild(Checkbox.builder(Component.translatable("cobblemon.snapshots.warning.dont_show_again"), Minecraft.getInstance().font)
|
||||
val checkbox = Checkbox.builder(Component.translatable("cobblemon.snapshots.warning.dont_show_again"), Minecraft.getInstance().font)
|
||||
.selected(dontShowAgain)
|
||||
.tooltip(Tooltip.create(DONT_SHOW_AGAIN_TIP))
|
||||
.build(), 2, settings)
|
||||
.build()
|
||||
helper.addChild(checkbox, 2, settings)
|
||||
|
||||
helper.addChild(Button.builder(CommonComponents.GUI_YES) { this.consumer.invoke(Acknowledgement.YES, dontShowAgain.get()) }.build())
|
||||
helper.addChild(Button.builder(CommonComponents.GUI_NO) { this.consumer.invoke(Acknowledgement.NO, false) }.build())
|
||||
val yesButton = Button.builder(CommonComponents.GUI_YES) { this.consumer.invoke(Acknowledgement.YES, dontShowAgain.get()) }.build()
|
||||
helper.addChild(yesButton)
|
||||
val noButton = Button.builder(CommonComponents.GUI_NO) { this.consumer.invoke(Acknowledgement.NO, false) }.build()
|
||||
helper.addChild(noButton)
|
||||
|
||||
this.layout.visitWidgets { this.addRenderableWidget(it) }
|
||||
this.layout.arrangeElements()
|
||||
this.repositionElements()
|
||||
|
||||
controllerComponentManager.componentList["checkbox"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = checkbox
|
||||
it.down = { controllerComponentManager.componentList["yes_button"] }
|
||||
it.onPress = {
|
||||
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F))
|
||||
checkbox.onPress()
|
||||
}
|
||||
}
|
||||
controllerComponentManager.componentList["yes_button"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = yesButton
|
||||
it.up = { controllerComponentManager.componentList["checkbox"] }
|
||||
it.right = { controllerComponentManager.componentList["no_button"] }
|
||||
}
|
||||
controllerComponentManager.componentList["no_button"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = noButton
|
||||
it.up = { controllerComponentManager.componentList["checkbox"] }
|
||||
it.left = { controllerComponentManager.componentList["yes_button"] }
|
||||
}
|
||||
controllerComponentManager.let {
|
||||
it.focused = it.componentList["yes_button"]
|
||||
}
|
||||
}
|
||||
|
||||
override fun repositionElements() {
|
||||
|
||||
+75
-12
@@ -27,6 +27,9 @@ import com.cobblemon.mod.common.client.gui.summary.widgets.ModelWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.type.DualTypeWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.type.SingleTypeWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.type.TypeWidget
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponent
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponentManager
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerScreen
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.config.starter.RenderableStarterCategory
|
||||
import com.cobblemon.mod.common.net.messages.server.SelectStarterPacket
|
||||
@@ -41,6 +44,8 @@ import net.minecraft.client.gui.components.toasts.Toast
|
||||
import net.minecraft.client.gui.screens.Screen
|
||||
import net.minecraft.client.resources.sounds.SimpleSoundInstance
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.sounds.SoundEvent
|
||||
import org.joml.Vector4i
|
||||
|
||||
/**
|
||||
* Starterselection Screen Thingy
|
||||
@@ -48,7 +53,7 @@ import net.minecraft.network.chat.Component
|
||||
* @author Qu
|
||||
* @since 2022-06-18
|
||||
*/
|
||||
class StarterSelectionScreen(private val categories: List<RenderableStarterCategory>): Screen("cobblemon.ui.starter.title".asTranslated()), CobblemonRenderable {
|
||||
class StarterSelectionScreen(private val categories: List<RenderableStarterCategory>): Screen("cobblemon.ui.starter.title".asTranslated()), CobblemonRenderable, ControllerScreen {
|
||||
|
||||
companion object {
|
||||
// Size of UI at scale 1
|
||||
@@ -73,6 +78,14 @@ class StarterSelectionScreen(private val categories: List<RenderableStarterCateg
|
||||
private lateinit var starterRoundaboutCenter: StarterRoundabout
|
||||
private lateinit var starterRoundaboutLeft: StarterRoundabout
|
||||
private lateinit var starterRoundaboutRight: StarterRoundabout
|
||||
private lateinit var categoryWidget: CategoryList
|
||||
|
||||
val controllerComponentManager = ControllerComponentManager(this)
|
||||
var lastSelectedCategoryIndex = 0
|
||||
|
||||
override fun getComponentManager(): ControllerComponentManager {
|
||||
return controllerComponentManager
|
||||
}
|
||||
|
||||
override fun renderBlurredBackground(delta: Float) { }
|
||||
|
||||
@@ -95,17 +108,17 @@ class StarterSelectionScreen(private val categories: List<RenderableStarterCateg
|
||||
return
|
||||
}
|
||||
|
||||
addRenderableWidget(
|
||||
CategoryList(
|
||||
paneWidth = 71, paneHeight = BASE_HEIGHT - 11,
|
||||
topOffset = 6,
|
||||
entryHeight = 20, entryWidth = 57,
|
||||
categories = categories,
|
||||
listX = x - 2, listY = y + 8,
|
||||
starterSelectionScreen = this
|
||||
)
|
||||
categoryWidget = CategoryList(
|
||||
paneWidth = 71, paneHeight = BASE_HEIGHT - 11,
|
||||
topOffset = 6,
|
||||
entryHeight = 20, entryWidth = 57,
|
||||
categories = categories,
|
||||
listX = x - 2, listY = y + 8,
|
||||
starterSelectionScreen = this
|
||||
)
|
||||
|
||||
addRenderableWidget(categoryWidget)
|
||||
|
||||
val rightButton = ArrowButton(
|
||||
pX = x + 183, pY = y + 151,
|
||||
pWidth = 9, pHeight = 14,
|
||||
@@ -194,6 +207,50 @@ class StarterSelectionScreen(private val categories: List<RenderableStarterCateg
|
||||
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(CobblemonSounds.GUI_CLICK, 1.0F))
|
||||
}
|
||||
)
|
||||
|
||||
controllerComponentManager.componentList["select"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = selectionButton
|
||||
it.left = { controllerComponentManager.componentList["category_${lastSelectedCategoryIndex}"] }
|
||||
}
|
||||
categoryWidget.children().forEachIndexed { index, category ->
|
||||
controllerComponentManager.componentList["category_${index}"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = category
|
||||
it.right = { controllerComponentManager.componentList["select"] }
|
||||
if (index - 1 >= 0) it.up = { controllerComponentManager.componentList["category_${index-1}"] }
|
||||
if (index + 1 <= categoryWidget.children().size - 1) it.down = { controllerComponentManager.componentList["category_${index+1}"] }
|
||||
it.onPress = {
|
||||
changeCategory(category.category)
|
||||
playSound(CobblemonSounds.GUI_CLICK)
|
||||
}
|
||||
it.onSelect = {
|
||||
lastSelectedCategoryIndex = index
|
||||
categoryWidget.ensureVisible(category)
|
||||
}
|
||||
it.onFocus = { category.controllerSelected = true }
|
||||
it.onUnfocus = { category.controllerSelected = false }
|
||||
}
|
||||
}
|
||||
controllerComponentManager.let {
|
||||
it.focused = controllerComponentManager.componentList["select"]
|
||||
it.onTabNav = { nextTab ->
|
||||
if (nextTab) right() else left()
|
||||
}
|
||||
it.buttonGuides.add(ControllerComponentManager.ButtonGuide(
|
||||
ControllerComponentManager.ButtonGuideType.TAB,
|
||||
{ true },
|
||||
Component.translatable("cobblemon.controller.starter.cycle_starter")
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSelectionPosAndSize(): Vector4i? {
|
||||
val data = super.getSelectionPosAndSize()
|
||||
if (controllerComponentManager.currentSelectedComponent.startsWith("category_")) {
|
||||
val category = controllerComponentManager.focused?.associatedGUIElement as? CategoryList.Category
|
||||
return Vector4i(categoryWidget.rowLeft + 1, categoryWidget.getRowTop(categoryWidget.children().indexOf(category)) - 2,
|
||||
CategoryList.CATEGORY_BUTTON_WIDTH.toInt() + 4, CategoryList.CATEGORY_BUTTON_HEIGHT.toInt() + 4)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
override fun render(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
@@ -280,6 +337,8 @@ class StarterSelectionScreen(private val categories: List<RenderableStarterCateg
|
||||
typeWidget.render(context, mouseX, mouseY, delta)
|
||||
// Render the rest
|
||||
super.render(context, mouseX, mouseY, delta)
|
||||
|
||||
renderSelection(matrices)
|
||||
}
|
||||
|
||||
fun changeCategory(category: RenderableStarterCategory) {
|
||||
@@ -289,7 +348,7 @@ class StarterSelectionScreen(private val categories: List<RenderableStarterCateg
|
||||
}
|
||||
|
||||
private fun right() {
|
||||
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(CobblemonSounds.GUI_CLICK, 1.0F))
|
||||
playSound(CobblemonSounds.GUI_CLICK)
|
||||
currentSelection = rightOfCurrentSelection()
|
||||
updateSelection()
|
||||
}
|
||||
@@ -297,7 +356,7 @@ class StarterSelectionScreen(private val categories: List<RenderableStarterCateg
|
||||
private fun rightOfCurrentSelection() : Int = if (currentSelection + 1 <= currentCategory.pokemon.size - 1) currentSelection + 1 else 0
|
||||
|
||||
private fun left() {
|
||||
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(CobblemonSounds.GUI_CLICK, 1.0F))
|
||||
playSound(CobblemonSounds.GUI_CLICK)
|
||||
currentSelection = leftOfCurrentSelection()
|
||||
updateSelection()
|
||||
}
|
||||
@@ -340,4 +399,8 @@ class StarterSelectionScreen(private val categories: List<RenderableStarterCateg
|
||||
}
|
||||
|
||||
override fun isPauseScreen() = true
|
||||
|
||||
fun playSound(soundEvent: SoundEvent) {
|
||||
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(soundEvent, 1.0F))
|
||||
}
|
||||
}
|
||||
+21
-4
@@ -41,8 +41,8 @@ class CategoryList(
|
||||
), CobblemonRenderable {
|
||||
|
||||
companion object {
|
||||
private const val CATEGORY_BUTTON_WIDTH = 51.5f
|
||||
private const val CATEGORY_BUTTON_HEIGHT = 16f
|
||||
const val CATEGORY_BUTTON_WIDTH = 51.5f
|
||||
const val CATEGORY_BUTTON_HEIGHT = 16f
|
||||
private const val ENTRY_X_OFFSET = 10f
|
||||
private val categoryResource = cobblemonResource("textures/gui/starterselection/starterselection_slot.png")
|
||||
}
|
||||
@@ -76,8 +76,25 @@ class CategoryList(
|
||||
return this.listX + this.width - 5
|
||||
}
|
||||
|
||||
public override fun ensureVisible(entry: Category) {
|
||||
val i = getRowTop(children().indexOf(entry))
|
||||
val topDifference = i - y - 4
|
||||
if (topDifference < 0) {
|
||||
scroll(topDifference)
|
||||
}
|
||||
|
||||
inner class Category(private val category: RenderableStarterCategory) : Entry<Category>() {
|
||||
val bottomDifference = bottom - i - itemHeight
|
||||
if (bottomDifference < 0) {
|
||||
scroll(-bottomDifference)
|
||||
}
|
||||
}
|
||||
|
||||
public override fun getRowTop(index: Int): Int {
|
||||
return super.getRowTop(index)
|
||||
}
|
||||
|
||||
inner class Category(val category: RenderableStarterCategory) : Entry<Category>() {
|
||||
var controllerSelected = false
|
||||
|
||||
override fun render(
|
||||
context: GuiGraphics,
|
||||
@@ -93,7 +110,7 @@ class CategoryList(
|
||||
) {
|
||||
val matrices = context.pose()
|
||||
val isHovered = mouseX >= x && mouseY >= y && mouseX < x + entryWidth && mouseY < y + (entryHeight - 1)
|
||||
if (isHovered) {
|
||||
if (isHovered || controllerSelected) {
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
x = x + 2.5f, y = y,
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ class SelectionButton(
|
||||
|
||||
override fun renderWidget(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
val matrices = context.pose()
|
||||
if (isHovered)
|
||||
if (isHovered || isFocused)
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = buttonTexture,
|
||||
|
||||
@@ -28,13 +28,19 @@ import com.cobblemon.mod.common.client.gui.summary.widgets.EvolutionSelectScreen
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.MarkingsWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.ModelWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.NicknameEntryWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.PartySlotWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.PartyWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.SummaryTab
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.info.InfoWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.marks.MarksScrollingWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.marks.MarksWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.moves.MoveSwapScreen
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.moves.MovesWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.stats.StatWidget
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponent
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponentManager
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerScreen
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.SubManagerComponent
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.VaryingModelRepository
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetItemHiddenPacket
|
||||
@@ -45,6 +51,7 @@ import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.isInventoryKeyPressed
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.cobblemon.mod.common.util.toAssetPath
|
||||
import com.mojang.blaze3d.platform.InputConstants
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
@@ -56,6 +63,8 @@ import net.minecraft.client.gui.screens.Screen
|
||||
import net.minecraft.client.resources.sounds.SimpleSoundInstance
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.sounds.SoundEvent
|
||||
import org.joml.Vector2i
|
||||
import org.joml.Vector4i
|
||||
|
||||
/**
|
||||
* The screen responsible for displaying various information regarding a Pokémon team.
|
||||
@@ -66,7 +75,7 @@ import net.minecraft.sounds.SoundEvent
|
||||
* @param selection The index the [party] will have as the base [selectedPokemon].
|
||||
*/
|
||||
class Summary private constructor(party: Collection<Pokemon?>, private val editable: Boolean, private val selection: Int): Screen(
|
||||
Component.translatable("cobblemon.ui.summary.title")), Schedulable, CobblemonRenderable {
|
||||
Component.translatable("cobblemon.ui.summary.title")), Schedulable, CobblemonRenderable, ControllerScreen {
|
||||
|
||||
companion object {
|
||||
const val BASE_WIDTH = 331
|
||||
@@ -75,10 +84,10 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
private const val SCALE = 0.5F
|
||||
|
||||
// Main Screen Index
|
||||
private const val INFO = 0
|
||||
private const val MOVES = 1
|
||||
private const val STATS = 2
|
||||
private const val MARKS = 3
|
||||
const val INFO = 0
|
||||
const val MOVES = 1
|
||||
const val STATS = 2
|
||||
const val MARKS = 3
|
||||
|
||||
// Side Screen Index
|
||||
const val PARTY = 0
|
||||
@@ -122,19 +131,32 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
|
||||
override val schedulingTracker = SchedulingTracker()
|
||||
|
||||
private val party = ArrayList(party)
|
||||
val party = ArrayList(party)
|
||||
internal var selectedPokemon: Pokemon = this.party[selection] ?: this.party.first { it != null }!!
|
||||
private lateinit var mainScreen: AbstractWidget
|
||||
lateinit var mainScreen: AbstractWidget
|
||||
lateinit var sideScreen: GuiEventListener
|
||||
private lateinit var modelWidget: ModelWidget
|
||||
private lateinit var nicknameEntryWidget: NicknameEntryWidget
|
||||
lateinit var nicknameEntryWidget: NicknameEntryWidget
|
||||
private lateinit var markingsWidget: MarkingsWidget
|
||||
private val summaryTabs = mutableListOf<SummaryTab>()
|
||||
val summaryTabs = mutableListOf<SummaryTab>()
|
||||
private var showCosmeticItem = false
|
||||
private lateinit var heldItemVisibilityButton: SummaryButton
|
||||
private var mainScreenIndex = INFO
|
||||
lateinit var heldItemVisibilityButton: SummaryButton
|
||||
lateinit var heldItemSwitchTypeButton: SummaryButton
|
||||
lateinit var evolveButton: SummaryButton
|
||||
var mainScreenIndex = INFO
|
||||
var sideScreenIndex = PARTY
|
||||
|
||||
val controllerComponentManager = ControllerComponentManager(this)
|
||||
var mainScreenComponentManager: ControllerComponentManager? = null
|
||||
var sideScreenComponentManager: ControllerComponentManager? = null
|
||||
var selectedMoveIndex = 0
|
||||
var moveSwitchingMode = false
|
||||
var lastSelectedPartySlot = 0
|
||||
|
||||
override fun getComponentManager(): ControllerComponentManager {
|
||||
return controllerComponentManager
|
||||
}
|
||||
|
||||
override fun renderBlurredBackground(delta: Float) { }
|
||||
|
||||
/**
|
||||
@@ -164,7 +186,7 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
addRenderableWidget(markingsWidget)
|
||||
|
||||
// Evolve Button
|
||||
addRenderableWidget(
|
||||
evolveButton = addRenderableWidget(
|
||||
SummaryButton(
|
||||
buttonX = x + 12F,
|
||||
buttonY = y + 145F,
|
||||
@@ -210,22 +232,22 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
heldItemVisibilityButton.buttonActive = !selectedPokemon.heldItemVisible
|
||||
addRenderableWidget(heldItemVisibilityButton)
|
||||
|
||||
|
||||
// Held/Cosmetic Item Button
|
||||
addRenderableWidget(
|
||||
SummaryButton(
|
||||
buttonX = x + 67F,
|
||||
buttonY = y + 113F,
|
||||
buttonWidth = 12,
|
||||
buttonHeight = 12,
|
||||
scale = 0.5F,
|
||||
resource = iconCosmeticItemResource,
|
||||
activeResource = iconHeldItemResource,
|
||||
clickAction = {
|
||||
showCosmeticItem = !showCosmeticItem
|
||||
(it as SummaryButton).buttonActive = showCosmeticItem
|
||||
}
|
||||
)
|
||||
heldItemSwitchTypeButton = SummaryButton(
|
||||
buttonX = x + 67F,
|
||||
buttonY = y + 113F,
|
||||
buttonWidth = 12,
|
||||
buttonHeight = 12,
|
||||
scale = 0.5F,
|
||||
resource = iconCosmeticItemResource,
|
||||
activeResource = iconHeldItemResource,
|
||||
clickAction = {
|
||||
showCosmeticItem = !showCosmeticItem
|
||||
(it as SummaryButton).buttonActive = showCosmeticItem
|
||||
}
|
||||
)
|
||||
addRenderableWidget(heldItemSwitchTypeButton)
|
||||
|
||||
// Init Tabs
|
||||
summaryTabs.clear()
|
||||
@@ -259,14 +281,7 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
// Add Exit Button
|
||||
addRenderableWidget(
|
||||
ExitButton(pX = x + 302, pY = y + 145) {
|
||||
playSound(CobblemonSounds.GUI_CLICK)
|
||||
if (sideScreenIndex != PARTY) {
|
||||
displaySideScreen(PARTY)
|
||||
} else {
|
||||
saveActiveMark()
|
||||
saveMarkings()
|
||||
Minecraft.getInstance().setScreen(null)
|
||||
}
|
||||
onBack()
|
||||
}
|
||||
)
|
||||
|
||||
@@ -299,9 +314,214 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
addRenderableOnly(this.modelWidget)
|
||||
|
||||
updatePokemonInfo()
|
||||
|
||||
//Controller Support
|
||||
controllerComponentManager.componentList["nickname"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = nicknameEntryWidget
|
||||
it.right = { controllerComponentManager.componentList["center_screen"] }
|
||||
}
|
||||
controllerComponentManager.componentList["held_item"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = heldItemVisibilityButton
|
||||
it.right = { controllerComponentManager.componentList["center_screen"] }
|
||||
it.pairUp(controllerComponentManager.componentList["nickname"]!!)
|
||||
it.down = { if (evolveButton.renderRequirement.invoke(evolveButton)) controllerComponentManager.componentList["evolve"] else null }
|
||||
it.onSpecial1 = {
|
||||
playSound(CobblemonSounds.GUI_CLICK)
|
||||
heldItemSwitchTypeButton.onPress()
|
||||
}
|
||||
it.onPress = {
|
||||
if (heldItemVisibilityButton.clickRequirement.invoke(heldItemVisibilityButton)) heldItemVisibilityButton.onPress()
|
||||
}
|
||||
}
|
||||
controllerComponentManager.componentList["evolve"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = evolveButton
|
||||
it.right = { controllerComponentManager.componentList["center_screen"] }
|
||||
it.up = { controllerComponentManager.componentList["held_item"] }
|
||||
}
|
||||
controllerComponentManager.componentList["center_screen"] = SubManagerComponent().also {
|
||||
it.subManager = { mainScreenComponentManager }
|
||||
it.left = {
|
||||
var returnVal: ControllerComponent? = null
|
||||
if (mainScreenComponentManager?.left() ?: true && !moveSwitchingMode) {
|
||||
returnVal = controllerComponentManager.componentList["nickname"]
|
||||
}
|
||||
returnVal
|
||||
}
|
||||
it.right = {
|
||||
var returnVal: ControllerComponent? = null
|
||||
if (mainScreenComponentManager?.right() ?: true && !moveSwitchingMode) {
|
||||
returnVal = controllerComponentManager.componentList["right_screen"]
|
||||
}
|
||||
returnVal
|
||||
}
|
||||
it.up = {
|
||||
if (mainScreenIndex == STATS) {
|
||||
val statWidget = mainScreen as StatWidget
|
||||
var index = statWidget.statTabIndex + 1
|
||||
if (index > statWidget.statOptions.size - 1) {
|
||||
index = 0
|
||||
}
|
||||
statWidget.statTabIndex = index
|
||||
playSound(CobblemonSounds.GUI_CLICK)
|
||||
} else {
|
||||
mainScreenComponentManager?.up()
|
||||
}
|
||||
null
|
||||
}
|
||||
it.down = {
|
||||
if (mainScreenIndex == STATS) {
|
||||
val statWidget = mainScreen as StatWidget
|
||||
var index = statWidget.statTabIndex - 1
|
||||
if (index < 0) {
|
||||
index = statWidget.statOptions.size - 1
|
||||
}
|
||||
statWidget.statTabIndex = index
|
||||
playSound(CobblemonSounds.GUI_CLICK)
|
||||
} else {
|
||||
mainScreenComponentManager?.down()
|
||||
}
|
||||
null
|
||||
}
|
||||
it.onPress = {
|
||||
if (mainScreenIndex == STATS) {
|
||||
val statWidget = mainScreen as StatWidget
|
||||
if (statWidget.statOptions.get(statWidget.statTabIndex) == StatWidget.RIDE && (statWidget.pokemon.riding.behaviours?.size ?: 0) > 1) {
|
||||
statWidget.rideBehaviourIndex = (statWidget.rideBehaviourIndex + 1) % (statWidget.pokemon.riding.behaviours?.size ?: 1)
|
||||
playSound(CobblemonSounds.GUI_CLICK)
|
||||
}
|
||||
} else {
|
||||
mainScreenComponentManager?.press()
|
||||
}
|
||||
}
|
||||
}
|
||||
controllerComponentManager.componentList["right_screen"] = SubManagerComponent().also {
|
||||
it.subManager = { sideScreenComponentManager }
|
||||
it.left = {
|
||||
var returnVal: ControllerComponent? = null
|
||||
if (sideScreenComponentManager?.left() ?: true && sideScreenIndex == PARTY && (sideScreen as? PartyWidget)?.swapSource == null) {
|
||||
returnVal = controllerComponentManager.componentList["center_screen"]
|
||||
}
|
||||
returnVal
|
||||
}
|
||||
}
|
||||
|
||||
controllerComponentManager.let {
|
||||
it.focused = it.componentList["center_screen"]
|
||||
it.onTabNav = { nextTab ->
|
||||
var index = mainScreenIndex + if (nextTab) 1 else -1
|
||||
if (index < 0) index = summaryTabs.size - 1
|
||||
if (index > summaryTabs.size - 1) index = 0
|
||||
playSound(CobblemonSounds.GUI_CLICK)
|
||||
displayMainScreen(index)
|
||||
}
|
||||
it.onSecondaryTabNav = { nextTab ->
|
||||
val pokemonIndex = party.indexOf(selectedPokemon)
|
||||
val indexList = party.filter { it != null }.map { party.indexOf(it) }.toMutableList()
|
||||
var index = indexList.indexOf(pokemonIndex) + if (nextTab) 1 else -1
|
||||
if (index < 0) index = indexList.size - 1
|
||||
if (index > indexList.size - 1) index = 0
|
||||
playSound(CobblemonSounds.GUI_CLICK)
|
||||
displaySideScreen(PARTY)
|
||||
switchSelection(indexList[index])
|
||||
}
|
||||
it.onBack = {
|
||||
if (moveSwitchingMode) {
|
||||
playSound(CobblemonSounds.GUI_CLICK)
|
||||
moveSwitchingMode = false
|
||||
val movesWidget = mainScreen as? MovesWidget
|
||||
if (movesWidget != null) {
|
||||
movesWidget.controllerComponentManager.focused?.onUnselect()
|
||||
}
|
||||
} else {
|
||||
val partyWidget = sideScreen as? PartyWidget
|
||||
if (partyWidget != null && partyWidget.swapSource != null) {
|
||||
partyWidget.draggedSlot = null
|
||||
partyWidget.controllerComponentManager.let {
|
||||
it.focused = it.componentList["slot_${partyWidget.swapSource}"]
|
||||
}
|
||||
partyWidget.swapSource = null
|
||||
playSound(CobblemonSounds.PC_DROP)
|
||||
} else {
|
||||
onBack()
|
||||
}
|
||||
}
|
||||
}
|
||||
it.onActiveChange = { state ->
|
||||
if (!state) {
|
||||
moveSwitchingMode = false
|
||||
}
|
||||
if (mainScreenComponentManager != null) {
|
||||
if (!state) {
|
||||
mainScreenComponentManager?.active = false
|
||||
} else {
|
||||
if (it.currentSelectedComponent == "center_screen") mainScreenComponentManager?.active = true
|
||||
}
|
||||
}
|
||||
if (sideScreenComponentManager != null) {
|
||||
if (!state) {
|
||||
sideScreenComponentManager?.active = false
|
||||
} else {
|
||||
if (it.currentSelectedComponent == "right_screen") sideScreenComponentManager?.active = true
|
||||
}
|
||||
}
|
||||
}
|
||||
it.buttonGuides.add(ControllerComponentManager.ButtonGuide(
|
||||
ControllerComponentManager.ButtonGuideType.SECONDARY_TAB,
|
||||
{ true },
|
||||
Component.translatable("cobblemon.controller.summary.quick_switch"),
|
||||
))
|
||||
it.buttonGuides.add(ControllerComponentManager.ButtonGuide(
|
||||
ControllerComponentManager.ButtonGuideType.SPECIAL_1,
|
||||
{ it.currentSelectedComponent == "center_screen" && mainScreenIndex == MOVES },
|
||||
Component.translatable("cobblemon.controller.summary.change_move"),
|
||||
true
|
||||
))
|
||||
it.buttonGuides.add(ControllerComponentManager.ButtonGuide(
|
||||
ControllerComponentManager.ButtonGuideType.SPECIAL_1,
|
||||
{ it.currentSelectedComponent == "held_item" },
|
||||
Component.translatable("cobblemon.controller.toggle_held_item_type"),
|
||||
true
|
||||
))
|
||||
it.buttonGuides.add(ControllerComponentManager.ButtonGuide(
|
||||
ControllerComponentManager.ButtonGuideType.SPECIAL_2,
|
||||
{ it.currentSelectedComponent == "center_screen" && mainScreenIndex == MOVES },
|
||||
Component.translatable("cobblemon.controller.summary.adjust_move"),
|
||||
true
|
||||
))
|
||||
it.buttonGuides.add(ControllerComponentManager.ButtonGuide(
|
||||
ControllerComponentManager.ButtonGuideType.SPECIAL_2,
|
||||
{ it.currentSelectedComponent == "center_screen" && mainScreenIndex == MARKS },
|
||||
Component.translatable("cobblemon.controller.summary.clear_mark"),
|
||||
true
|
||||
))
|
||||
it.buttonGuides.add(ControllerComponentManager.ButtonGuide(
|
||||
ControllerComponentManager.ButtonGuideType.SPECIAL_2,
|
||||
{ it.currentSelectedComponent == "right_screen" && sideScreenIndex == PARTY },
|
||||
Component.translatable("cobblemon.controller.summary.swap_position"),
|
||||
true
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fun onBack() {
|
||||
playSound(CobblemonSounds.GUI_CLICK)
|
||||
if (sideScreenIndex != PARTY) {
|
||||
if (sideScreenIndex == EVOLVE) {
|
||||
controllerComponentManager.focused = controllerComponentManager.componentList["evolve"]
|
||||
} else {
|
||||
controllerComponentManager.focused = controllerComponentManager.componentList["center_screen"]
|
||||
}
|
||||
displaySideScreen(PARTY)
|
||||
} else {
|
||||
saveActiveMark()
|
||||
saveMarkings()
|
||||
Minecraft.getInstance().setScreen(null)
|
||||
}
|
||||
}
|
||||
|
||||
fun swapPartySlot(sourceIndex: Int, targetIndex: Int) {
|
||||
moveSwitchingMode = false
|
||||
|
||||
if (sourceIndex >= this.party.size || targetIndex >= this.party.size) {
|
||||
return
|
||||
}
|
||||
@@ -362,11 +582,11 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveMarkings() {
|
||||
fun saveMarkings() {
|
||||
if (::markingsWidget.isInitialized) markingsWidget.saveMarkingsToPokemon()
|
||||
}
|
||||
|
||||
private fun saveActiveMark() {
|
||||
fun saveActiveMark() {
|
||||
if (mainScreenIndex == MARKS && mainScreen is MarksWidget) (mainScreen as MarksWidget).saveActiveMarkToPokemon()
|
||||
}
|
||||
|
||||
@@ -378,12 +598,16 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
/**
|
||||
* Switch center screen
|
||||
*/
|
||||
private fun displayMainScreen(screen: Int) {
|
||||
fun displayMainScreen(screen: Int) {
|
||||
// Save mark to Pokémon if any changes when switching out of marks screen
|
||||
saveActiveMark()
|
||||
|
||||
// Get stat tab index if currently displaying stat screen
|
||||
val subIndex = if (mainScreenIndex == STATS && mainScreen is StatWidget) (mainScreen as StatWidget).statTabIndex else 0
|
||||
val subIndex = if (mainScreenIndex == STATS && mainScreen is StatWidget) (mainScreen as StatWidget).rawStatTabIndex else 0
|
||||
|
||||
if (screen != MOVES) {
|
||||
moveSwitchingMode = false
|
||||
}
|
||||
|
||||
mainScreenIndex = screen
|
||||
if (::mainScreen.isInitialized) removeWidget(mainScreen)
|
||||
@@ -403,6 +627,7 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
pY = y + 12,
|
||||
pokemon = this.selectedPokemon
|
||||
)
|
||||
mainScreenComponentManager = null
|
||||
}
|
||||
|
||||
MOVES -> {
|
||||
@@ -410,7 +635,13 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
pX = x + 77,
|
||||
pY = y + 12,
|
||||
summary = this
|
||||
)
|
||||
).also { movesWidget ->
|
||||
mainScreenComponentManager = movesWidget.controllerComponentManager
|
||||
movesWidget.controllerComponentManager.let {
|
||||
it.focused = it.componentList["move_${selectedMoveIndex}"]
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
STATS -> {
|
||||
@@ -418,25 +649,38 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
pX = x + 77,
|
||||
pY = y + 12,
|
||||
pokemon = this.selectedPokemon,
|
||||
tabIndex = subIndex
|
||||
tabIndex = subIndex,
|
||||
summary = this
|
||||
)
|
||||
mainScreenComponentManager = null
|
||||
}
|
||||
|
||||
MARKS -> {
|
||||
mainScreen = MarksWidget(
|
||||
pX = x + 77,
|
||||
pY = y + 12,
|
||||
pokemon = this.selectedPokemon
|
||||
)
|
||||
pokemon = this.selectedPokemon,
|
||||
summary = this
|
||||
).also {
|
||||
mainScreenComponentManager = it.controllerComponentManager
|
||||
}
|
||||
}
|
||||
}
|
||||
addRenderableWidget(mainScreen)
|
||||
|
||||
if (controllerComponentManager.currentSelectedComponent == "center_screen" && controllerComponentManager.active) {
|
||||
focused = null
|
||||
mainScreenComponentManager?.active = true
|
||||
controllerComponentManager.focused?.onFocus?.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch right screen
|
||||
*/
|
||||
fun displaySideScreen(screen: Int, move: Move? = null) {
|
||||
moveSwitchingMode = false
|
||||
|
||||
sideScreenIndex = screen
|
||||
if (::sideScreen.isInitialized) removeWidget(sideScreen)
|
||||
|
||||
@@ -451,7 +695,9 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
isParty = selectedPokemon in CobblemonClient.storage.party,
|
||||
summary = this,
|
||||
partyList = this.party
|
||||
)
|
||||
).also {
|
||||
sideScreenComponentManager = it.controllerComponentManager
|
||||
}
|
||||
}
|
||||
|
||||
MOVE_SWAP -> {
|
||||
@@ -473,7 +719,9 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
moveSlotList += MoveSwapScreen.MoveSlot(switchPane, null, 0, pokemon)
|
||||
}
|
||||
moveSlotList.forEach { switchPane.addEntry(it) }
|
||||
sideScreenComponentManager = switchPane.controllerComponentManager
|
||||
}
|
||||
controllerComponentManager.focused = controllerComponentManager.componentList["right_screen"]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -483,14 +731,67 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
sideScreen = EvolutionSelectScreen(
|
||||
x + 216,
|
||||
y + 23,
|
||||
pokemon = selectedPokemon
|
||||
)
|
||||
pokemon = selectedPokemon,
|
||||
summary = this
|
||||
).also {
|
||||
sideScreenComponentManager = it.controllerComponentManager
|
||||
}
|
||||
controllerComponentManager.focused = controllerComponentManager.componentList["right_screen"]
|
||||
}
|
||||
}
|
||||
val element = sideScreen
|
||||
if (element is Renderable && element is NarratableEntry) {
|
||||
addRenderableWidget(element)
|
||||
}
|
||||
|
||||
if (controllerComponentManager.currentSelectedComponent == "right_screen" && controllerComponentManager.active) {
|
||||
focused = null
|
||||
sideScreenComponentManager?.active = true
|
||||
controllerComponentManager.focused?.onFocus?.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSelectionPosAndSize(): Vector4i? {
|
||||
val data = super.getSelectionPosAndSize()
|
||||
if (data != null) {
|
||||
when (focused) {
|
||||
nicknameEntryWidget -> return Vector4i(nicknameEntryWidget.x - 12, nicknameEntryWidget.y - 4, 78, 17)
|
||||
heldItemVisibilityButton -> return Vector4i(data.x + 1, data.y + 1, data.z / 2, data.w / 2)
|
||||
is PartySlotWidget -> return data.add(-2, -2, 0, 2)
|
||||
else -> return data
|
||||
}
|
||||
} else {
|
||||
when (controllerComponentManager.currentSelectedComponent) {
|
||||
"center_screen" -> {
|
||||
when (mainScreenIndex) {
|
||||
MARKS -> {
|
||||
val marksScreen = mainScreen as MarksWidget
|
||||
val horizontalSpacing = if (marksScreen.marksScrollList.children().size > 5) MarksScrollingWidget.SLOT_SPACING else (MarksScrollingWidget.SLOT_SPACING + 1)
|
||||
val row = marksScreen.lastSelectedMark / 6
|
||||
val column = marksScreen.lastSelectedMark % 6
|
||||
val startX = marksScreen.marksScrollList.rowLeft + (horizontalSpacing + MarksScrollingWidget.SLOT_SIZE) * column
|
||||
val startY = marksScreen.marksScrollList.getRowTop(row) + MarksScrollingWidget.SLOT_SPACING
|
||||
return Vector4i(startX - 2, startY - 2, MarksScrollingWidget.SLOT_SIZE + 4, MarksScrollingWidget.SLOT_SIZE + 4)
|
||||
}
|
||||
else -> return Vector4i(mainScreen.x + 2, mainScreen.y + 2, 130, 144)
|
||||
}
|
||||
}
|
||||
"right_screen" -> {
|
||||
when (sideScreenIndex) {
|
||||
EVOLVE -> {
|
||||
val evolveScreen = sideScreen as EvolutionSelectScreen
|
||||
return Vector4i(evolveScreen.rowLeft - 5, evolveScreen.getRowTop(evolveScreen.children().indexOf(focused)) - 2, evolveScreen.rowWidth + 4, EvolutionSelectScreen.SLOT_HEIGHT + 4)
|
||||
}
|
||||
MOVE_SWAP -> {
|
||||
val moveSwapScreen = sideScreen as MoveSwapScreen
|
||||
return Vector4i(moveSwapScreen.rowLeft - 11, moveSwapScreen.getRowTop(moveSwapScreen.children().indexOf(focused)) - 2, moveSwapScreen.rowWidth + 13, MoveSwapScreen.SLOT_HEIGHT + 4)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
override fun renderMenuBackground(context: GuiGraphics) {}
|
||||
@@ -558,7 +859,7 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
}
|
||||
|
||||
// Poké Ball
|
||||
val ballResource = cobblemonResource("textures/item/poke_balls/" + selectedPokemon.caughtBall.name.path + ".png")
|
||||
val ballResource = selectedPokemon.caughtBall.name.toAssetPath("textures/item/poke_balls/", ".png")
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = ballResource,
|
||||
@@ -630,8 +931,11 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
val itemX = x + 3
|
||||
val itemY = y + 104
|
||||
if (!displayedItem.isEmpty) {
|
||||
matrices.pushPose()
|
||||
matrices.translate(0.0,0.0,-200.0)
|
||||
context.renderItem(displayedItem, itemX, itemY)
|
||||
context.renderItemDecorations(Minecraft.getInstance().font, displayedItem, itemX, itemY)
|
||||
matrices.popPose()
|
||||
}
|
||||
|
||||
drawScaledText(
|
||||
@@ -660,19 +964,25 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
scale = SCALE
|
||||
)
|
||||
|
||||
matrices.pushPose()
|
||||
// Prevent widgets from being overlapped by other components
|
||||
matrices.translate(0.0, 0.0, 1000.0)
|
||||
// Set Look View Pos
|
||||
val selectionData = getSelectionPosAndSize()
|
||||
if (controllerComponentManager.active && selectionData != null) {
|
||||
modelWidget.overrideLookPos = Vector2i(selectionData.x + selectionData.z / 2, selectionData.y + selectionData.w / 2)
|
||||
} else {
|
||||
modelWidget.overrideLookPos = null
|
||||
}
|
||||
|
||||
// Render all added Widgets
|
||||
super.render(context, mouseX, mouseY, delta)
|
||||
|
||||
// Selection Rendering
|
||||
renderSelection(matrices)
|
||||
|
||||
// Render Item Tooltip
|
||||
if (!displayedItem.isEmpty) {
|
||||
val itemHovered = mouseX.toFloat() in (itemX.toFloat()..(itemX.toFloat() + 16)) && mouseY.toFloat() in (itemY.toFloat()..(itemY.toFloat() + 16))
|
||||
if (itemHovered) context.renderTooltip(Minecraft.getInstance().font, displayedItem, mouseX, mouseY)
|
||||
}
|
||||
matrices.popPose()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -32,8 +32,8 @@ class SummaryButton(
|
||||
private val text: MutableComponent = Component.empty(),
|
||||
private val resource: ResourceLocation,
|
||||
private val activeResource: ResourceLocation? = null,
|
||||
private val renderRequirement: ((button: SummaryButton) -> Boolean) = { true },
|
||||
private val clickRequirement: ((button: SummaryButton) -> Boolean) = { true },
|
||||
val renderRequirement: ((button: SummaryButton) -> Boolean) = { true },
|
||||
val clickRequirement: ((button: SummaryButton) -> Boolean) = { true },
|
||||
private val hoverTexture: Boolean = true,
|
||||
private val silent: Boolean = false,
|
||||
private val boldText: Boolean = true,
|
||||
@@ -67,7 +67,7 @@ class SummaryButton(
|
||||
y = buttonY / scale,
|
||||
width = buttonWidth,
|
||||
height = buttonHeight,
|
||||
vOffset = if (hoverTexture && isButtonHovered(pMouseX, pMouseY)) buttonHeight else 0,
|
||||
vOffset = if (hoverTexture && (isButtonHovered(pMouseX, pMouseY) || isFocused)) buttonHeight else 0,
|
||||
textureHeight = if (hoverTexture) (buttonHeight.toFloat() * 2) else buttonHeight,
|
||||
scale = scale
|
||||
)
|
||||
|
||||
+34
-2
@@ -15,8 +15,11 @@ import com.cobblemon.mod.common.api.text.bold
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.gui.TypeIcon
|
||||
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
|
||||
import com.cobblemon.mod.common.client.gui.summary.Summary
|
||||
import com.cobblemon.mod.common.client.gui.summary.SummaryButton
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.common.SummaryScrollList
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponent
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponentManager
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState
|
||||
import com.cobblemon.mod.common.pokemon.FormData
|
||||
@@ -34,7 +37,8 @@ import org.joml.Vector3f
|
||||
class EvolutionSelectScreen(
|
||||
x: Int,
|
||||
y: Int,
|
||||
val pokemon: Pokemon
|
||||
val pokemon: Pokemon,
|
||||
val summary: Summary
|
||||
): SummaryScrollList<EvolutionSelectScreen.EvolveSlot>(
|
||||
x,
|
||||
y,
|
||||
@@ -52,8 +56,36 @@ class EvolutionSelectScreen(
|
||||
|
||||
private var entriesCreated = false
|
||||
|
||||
var controllerComponentManager = ControllerComponentManager(summary).also {
|
||||
it.onActiveChange = { state ->
|
||||
if (state) it.focused?.onSelect?.invoke() else it.focused?.onUnselect?.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
public override fun addEntry(entry: EvolveSlot): Int {
|
||||
return super.addEntry(entry)
|
||||
val i = super.addEntry(entry)
|
||||
controllerComponentManager.componentList["moves_${i}"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = entry
|
||||
it.onPress = {
|
||||
entry.selectButton.onPress()
|
||||
}
|
||||
it.onSelect = {
|
||||
ensureVisible(entry)
|
||||
entry.selectButton.isFocused = true
|
||||
}
|
||||
it.onUnselect = {
|
||||
entry.selectButton.isFocused = false
|
||||
}
|
||||
}
|
||||
if (children().size > 1) {
|
||||
controllerComponentManager.componentList["moves_${i}"]?.let {
|
||||
it.pairUp(controllerComponentManager.componentList["moves_${i-1}"])
|
||||
it.pairDown(controllerComponentManager.componentList["moves_${0}"])
|
||||
}
|
||||
} else {
|
||||
controllerComponentManager.focused = controllerComponentManager.componentList["moves_${i}"]
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
override fun renderWidget(context: GuiGraphics, mouseX: Int, mouseY: Int, partialTicks: Float) {
|
||||
|
||||
+14
-3
@@ -20,6 +20,7 @@ import com.cobblemon.mod.common.util.math.fromEulerXYZDegrees
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.network.chat.Component
|
||||
import org.joml.Quaternionf
|
||||
import org.joml.Vector2i
|
||||
import org.joml.Vector3f
|
||||
|
||||
class ModelWidget(
|
||||
@@ -57,6 +58,8 @@ class ModelWidget(
|
||||
var currentYawAndPitch: Pair<Float, Float> = Pair(0f, 0f)
|
||||
val rotationVector = Vector3f(13F, rotationY, 0F)
|
||||
|
||||
var overrideLookPos: Vector2i? = null
|
||||
|
||||
override fun renderWidget(context: GuiGraphics, pMouseX: Int, pMouseY: Int, partialTicks: Float) {
|
||||
if (!render) {
|
||||
return
|
||||
@@ -86,7 +89,7 @@ class ModelWidget(
|
||||
|
||||
val timeLooking = lookStartTime?.let { (System.currentTimeMillis() - it) / 1000 } ?: MAX_SECONDS_LOOKING
|
||||
val lookedTooMuch = timeLooking >= MAX_SECONDS_LOOKING
|
||||
val resetToCenter = (!isHovered && lookedTooMuch) || !shouldFollowCursor || !Cobblemon.config.summaryPokemonFollowCursor
|
||||
val resetToCenter = (!isHovered && lookedTooMuch && overrideLookPos == null) || !shouldFollowCursor || !Cobblemon.config.summaryPokemonFollowCursor
|
||||
|
||||
if (resetToCenter) {
|
||||
lookStartTime = null
|
||||
@@ -95,12 +98,19 @@ class ModelWidget(
|
||||
val rotation = Quaternionf().fromEulerXYZDegrees(rotationVector)
|
||||
|
||||
if (shouldFollowCursor) {
|
||||
var xPos = mouseX
|
||||
var yPos = mouseY
|
||||
if (overrideLookPos != null) {
|
||||
xPos = overrideLookPos!!.x
|
||||
yPos = overrideLookPos!!.y
|
||||
}
|
||||
|
||||
currentYawAndPitch = calculateHeadYawAndPitch(
|
||||
x + width / 2f,
|
||||
y + height / 2f,
|
||||
rotation,
|
||||
mouseX,
|
||||
mouseY,
|
||||
xPos,
|
||||
yPos,
|
||||
currentYawAndPitch.first,
|
||||
currentYawAndPitch.second,
|
||||
resetToCenter
|
||||
@@ -116,6 +126,7 @@ class ModelWidget(
|
||||
headYaw = currentYawAndPitch.first,
|
||||
headPitch = currentYawAndPitch.second,
|
||||
)
|
||||
context.flush()
|
||||
|
||||
heldItemRenderer.renderOnModel(
|
||||
pokemon.heldItem,
|
||||
|
||||
+13
-7
@@ -24,6 +24,7 @@ import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.cobblemon.mod.common.util.math.fromEulerXYZDegrees
|
||||
import com.cobblemon.mod.common.util.toAssetPath
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
@@ -87,7 +88,7 @@ class PartySlotWidget(
|
||||
y = y,
|
||||
width = width,
|
||||
height = height,
|
||||
vOffset = getSlotVOffset(slotPokemon, isHovered, isSelected),
|
||||
vOffset = getSlotVOffset(slotPokemon, isHovered || isFocused, isSelected),
|
||||
textureHeight = height * 2,
|
||||
)
|
||||
|
||||
@@ -107,7 +108,7 @@ class PartySlotWidget(
|
||||
)
|
||||
}
|
||||
|
||||
val ballIcon = cobblemonResource("textures/gui/ball/" + slotPokemon.caughtBall.name.path + ".png")
|
||||
val ballIcon = slotPokemon.caughtBall.name.toAssetPath("textures/gui/ball/", ".png")
|
||||
val ballHeight = 22
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
@@ -222,16 +223,21 @@ class PartySlotWidget(
|
||||
if (partyWidget.swapEnabled) {
|
||||
toggleDrag(true)
|
||||
} else {
|
||||
if ((index > -1) && (summary.selectedPokemon.uuid != pokemon?.uuid)) {
|
||||
summary.switchSelection(index)
|
||||
if (pokemon != null) partyWidget.playSound(CobblemonSounds.GUI_CLICK)
|
||||
return true
|
||||
}
|
||||
if (onPress()) return true
|
||||
}
|
||||
}
|
||||
return super.mouseClicked(pMouseX, pMouseY, pButton)
|
||||
}
|
||||
|
||||
fun onPress(): Boolean {
|
||||
if ((index > -1) && (summary.selectedPokemon.uuid != pokemon?.uuid)) {
|
||||
summary.switchSelection(index)
|
||||
if (pokemon != null) partyWidget.playSound(CobblemonSounds.GUI_CLICK)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun mouseReleased(pMouseX: Double, pMouseY: Double, pButton: Int): Boolean {
|
||||
if (partyWidget.swapEnabled) toggleDrag(false)
|
||||
return partyWidget.mouseReleased(pMouseX, pMouseY, pButton)
|
||||
|
||||
+85
-1
@@ -14,6 +14,8 @@ import com.cobblemon.mod.common.api.text.bold
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.gui.summary.Summary
|
||||
import com.cobblemon.mod.common.client.gui.summary.SummaryButton
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponent
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponentManager
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
@@ -67,6 +69,8 @@ class PartyWidget(
|
||||
}
|
||||
)
|
||||
|
||||
var controllerComponentManager = ControllerComponentManager(summary)
|
||||
|
||||
init {
|
||||
if (partySize > 6 || partySize < 1)
|
||||
throw InvalidParameterException("Invalid party size")
|
||||
@@ -85,7 +89,7 @@ class PartyWidget(
|
||||
y += (32 * offsetIndex) + offsetY
|
||||
}
|
||||
|
||||
PartySlotWidget(
|
||||
val slot = PartySlotWidget(
|
||||
pX = x,
|
||||
pY = y,
|
||||
partyWidget = this,
|
||||
@@ -97,6 +101,86 @@ class PartyWidget(
|
||||
this.addWidget(widget)
|
||||
partySlots.add(widget)
|
||||
}
|
||||
|
||||
controllerComponentManager.componentList["slot_${index}"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = slot
|
||||
it.onPress = {
|
||||
if (swapEnabled) {
|
||||
if (swapSource == null) {
|
||||
if (partyList[index] != null) {
|
||||
swapSource = index
|
||||
draggedSlot = PartySlotWidget(
|
||||
pX = slot.x + 4,
|
||||
pY = slot.y + 4,
|
||||
partyWidget = this,
|
||||
summary = summary,
|
||||
pokemon = partyList[index],
|
||||
index = -1,
|
||||
isClientPartyMember = isParty
|
||||
)
|
||||
draggedSlot?.isFocused = true
|
||||
playSound(CobblemonSounds.PC_GRAB)
|
||||
}
|
||||
} else {
|
||||
if (swapSource != index) {
|
||||
summary.swapPartySlot(swapSource!!, index)
|
||||
}
|
||||
swapSource = null
|
||||
draggedSlot = null
|
||||
playSound(CobblemonSounds.PC_DROP)
|
||||
}
|
||||
} else slot.onPress()
|
||||
}
|
||||
it.onSpecial1 = {
|
||||
swapEnabled = !swapEnabled
|
||||
swapButton.buttonActive = swapEnabled
|
||||
if (!swapEnabled) {
|
||||
swapSource = null
|
||||
draggedSlot = null
|
||||
}
|
||||
playSound(CobblemonSounds.GUI_CLICK)
|
||||
}
|
||||
|
||||
fun updateDraggedSlotPos() {
|
||||
draggedSlot?.let { theSlot ->
|
||||
theSlot.x = slot.x + 4
|
||||
theSlot.y = slot.y + 4
|
||||
}
|
||||
}
|
||||
|
||||
if (index-2 >= 0) {
|
||||
it.up = {
|
||||
controllerComponentManager.componentList["slot_${index-2}"]
|
||||
}
|
||||
}
|
||||
if (index+2 <= 5) {
|
||||
it.down = {
|
||||
controllerComponentManager.componentList["slot_${index+2}"]
|
||||
}
|
||||
}
|
||||
if (index.mod(2) == 0) {
|
||||
it.right = {
|
||||
controllerComponentManager.componentList["slot_${index+1}"]
|
||||
}
|
||||
} else {
|
||||
it.left = {
|
||||
controllerComponentManager.componentList["slot_${index-1}"]
|
||||
}
|
||||
}
|
||||
it.onSelect = {
|
||||
updateDraggedSlotPos()
|
||||
summary.lastSelectedPartySlot = index
|
||||
}
|
||||
}
|
||||
}
|
||||
controllerComponentManager.let {
|
||||
it.focused = it.componentList["slot_${summary.lastSelectedPartySlot}"]
|
||||
it.onActiveChange = { state ->
|
||||
if (!state) {
|
||||
swapSource = null
|
||||
draggedSlot = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+19
@@ -125,6 +125,23 @@ abstract class SummaryScrollList<T : ObjectSelectionList.Entry<T>>(
|
||||
return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)
|
||||
}
|
||||
|
||||
public override fun ensureVisible(entry: T) {
|
||||
val i = getRowTop(children().indexOf(entry))
|
||||
val topDifference = i - y - 4
|
||||
if (topDifference < 0) {
|
||||
scroll(topDifference)
|
||||
}
|
||||
|
||||
val bottomDifference = bottom - i - itemHeight
|
||||
if (bottomDifference < 0) {
|
||||
scroll(-bottomDifference)
|
||||
}
|
||||
}
|
||||
|
||||
public override fun getRowTop(index: Int): Int {
|
||||
return super.getRowTop(index)
|
||||
}
|
||||
|
||||
private fun updateScrollingState(mouseX: Double, mouseY: Double) {
|
||||
scrolling = mouseX >= this.scrollbarPosition.toDouble()
|
||||
&& mouseX < (this.scrollbarPosition + 3).toDouble()
|
||||
@@ -135,4 +152,6 @@ abstract class SummaryScrollList<T : ObjectSelectionList.Entry<T>>(
|
||||
private fun correctSize() {
|
||||
setRectangle(WIDTH, HEIGHT, listX, listY)
|
||||
}
|
||||
|
||||
open fun onPress(entry: T) {}
|
||||
}
|
||||
+4
-3
@@ -106,10 +106,11 @@ class MarksScrollingWidget(val pX: Int, val pY: Int, val setSelectedMark: () ->
|
||||
companion object {
|
||||
private val slotResource = cobblemonResource("textures/gui/summary/summary_mark_slot.png")
|
||||
}
|
||||
|
||||
var x: Int = 0
|
||||
var y: Int = 0
|
||||
|
||||
var slotSelected: (Int) -> Boolean = { false }
|
||||
|
||||
fun renderRow(context: GuiGraphics, y: Int, x: Int, mouseX: Int, mouseY: Int): Boolean {
|
||||
var anyHovered = false
|
||||
val horizontalSpacing = if (isScrollVisible()) SLOT_SPACING else (SLOT_SPACING + 1)
|
||||
@@ -133,7 +134,7 @@ class MarksScrollingWidget(val pX: Int, val pY: Int, val setSelectedMark: () ->
|
||||
y = startPosY,
|
||||
width = SLOT_SIZE,
|
||||
height = SLOT_SIZE,
|
||||
vOffset = if (slotHovered) SLOT_SIZE else 0,
|
||||
vOffset = if (slotHovered || (mark != null && slotSelected.invoke(index))) SLOT_SIZE else 0,
|
||||
textureHeight = SLOT_SIZE * 2
|
||||
)
|
||||
|
||||
@@ -160,7 +161,7 @@ class MarksScrollingWidget(val pX: Int, val pY: Int, val setSelectedMark: () ->
|
||||
return true
|
||||
}
|
||||
|
||||
private fun isScrollVisible(): Boolean = parent.children().size > 5
|
||||
fun isScrollVisible(): Boolean = parent.children().size > 5
|
||||
|
||||
private fun getHoveredSlotIndex(mouseX: Int, mouseY: Int): Int {
|
||||
val horizontalSpacing = if (isScrollVisible()) SLOT_SPACING else (SLOT_SPACING + 1)
|
||||
|
||||
+56
-1
@@ -15,7 +15,10 @@ import com.cobblemon.mod.common.api.gui.MultiLineLabelK
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.mark.Mark
|
||||
import com.cobblemon.mod.common.client.gui.common.MarkIcon
|
||||
import com.cobblemon.mod.common.client.gui.summary.Summary
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.SoundlessWidget
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponent
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponentManager
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetActiveMarkPacket
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
@@ -27,7 +30,8 @@ import net.minecraft.network.chat.Component
|
||||
|
||||
class MarksWidget(
|
||||
pX: Int, pY: Int,
|
||||
val pokemon: Pokemon
|
||||
val pokemon: Pokemon,
|
||||
val summary: Summary
|
||||
): SoundlessWidget(pX, pY, WIDTH, HEIGHT, Component.literal("MarksWidget")) {
|
||||
companion object {
|
||||
private const val WIDTH = 134
|
||||
@@ -53,6 +57,9 @@ class MarksWidget(
|
||||
setHoveredMark = { hoveredMark = it }
|
||||
)
|
||||
|
||||
val controllerComponentManager = ControllerComponentManager(summary)
|
||||
var lastSelectedMark = 0
|
||||
|
||||
init {
|
||||
children.clear()
|
||||
activeMark = pokemon.activeMark
|
||||
@@ -61,6 +68,54 @@ class MarksWidget(
|
||||
while ((marksList.size < 30) || (marksList.size > 30 && marksList.size % 6 != 0)) marksList.add(null)
|
||||
marksScrollList.createEntries(marksList)
|
||||
addWidget(marksScrollList)
|
||||
|
||||
marksScrollList.children().forEachIndexed { firstIndex, row ->
|
||||
row.markList.forEachIndexed { secondIndex, mark ->
|
||||
controllerComponentManager.componentList["mark_${firstIndex}_${secondIndex}"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = row
|
||||
it.onPress = {
|
||||
if (mark != null) {
|
||||
selectedMark = mark
|
||||
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(CobblemonSounds.GUI_CLICK, 1.0F))
|
||||
}
|
||||
}
|
||||
it.onSpecial1 = {
|
||||
if (selectedMark !== null) {
|
||||
selectedMark = null
|
||||
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(CobblemonSounds.GUI_CLICK, 1.0F))
|
||||
}
|
||||
}
|
||||
it.onSelect = {
|
||||
lastSelectedMark = firstIndex * 6 + secondIndex
|
||||
marksScrollList.ensureVisible(row)
|
||||
}
|
||||
if (firstIndex - 1 >= 0) {
|
||||
it.up = {
|
||||
controllerComponentManager.componentList["mark_${firstIndex-1}_${secondIndex}"]
|
||||
}
|
||||
}
|
||||
if (firstIndex + 1 <= marksScrollList.children().size - 1) {
|
||||
it.down = {
|
||||
controllerComponentManager.componentList["mark_${firstIndex+1}_${secondIndex}"]
|
||||
}
|
||||
}
|
||||
if (secondIndex - 1 >= 0) {
|
||||
it.left = {
|
||||
controllerComponentManager.componentList["mark_${firstIndex}_${secondIndex-1}"]
|
||||
}
|
||||
}
|
||||
if (secondIndex + 1 <= row.markList.size - 1) {
|
||||
it.right = {
|
||||
controllerComponentManager.componentList["mark_${firstIndex}_${secondIndex+1}"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
row.slotSelected = { index ->
|
||||
controllerComponentManager.active && lastSelectedMark / 6 == firstIndex && lastSelectedMark % 6 == index
|
||||
}
|
||||
}
|
||||
controllerComponentManager.let { it.focused = it.componentList["mark_${lastSelectedMark / 6}_${lastSelectedMark % 6}"] }
|
||||
}
|
||||
|
||||
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
|
||||
|
||||
+3
-3
@@ -44,13 +44,13 @@ class MoveSlotWidget(
|
||||
const val MOVE_HEIGHT = 22
|
||||
}
|
||||
|
||||
private val moveUpButton = ReorderMoveButton(x, y, true) {
|
||||
val moveUpButton = ReorderMoveButton(x, y, true) {
|
||||
movesWidget.selectMove(null)
|
||||
movesWidget.reorderMove(this, true)
|
||||
}.apply {
|
||||
addWidget(this)
|
||||
}
|
||||
private val moveDownButton = ReorderMoveButton(x, y, false) {
|
||||
val moveDownButton = ReorderMoveButton(x, y, false) {
|
||||
movesWidget.selectMove(null)
|
||||
movesWidget.reorderMove(this, false)
|
||||
}.apply {
|
||||
@@ -93,7 +93,7 @@ class MoveSlotWidget(
|
||||
y = y,
|
||||
width = MOVE_WIDTH,
|
||||
height = MOVE_HEIGHT,
|
||||
vOffset = if (isHovered) MOVE_HEIGHT else 0,
|
||||
vOffset = if (isHovered || isFocused) MOVE_HEIGHT else 0,
|
||||
textureHeight = MOVE_HEIGHT * 2,
|
||||
red = rgb.first,
|
||||
green = rgb.second,
|
||||
|
||||
+58
-16
@@ -20,6 +20,8 @@ import com.cobblemon.mod.common.client.gui.MoveCategoryIcon
|
||||
import com.cobblemon.mod.common.client.gui.TypeIcon
|
||||
import com.cobblemon.mod.common.client.gui.summary.Summary
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.common.SummaryScrollList
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponent
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponentManager
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.net.messages.server.BenchMovePacket
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
@@ -49,13 +51,45 @@ class MoveSwapScreen(
|
||||
private val forgetMoveIconResource = cobblemonResource("textures/gui/summary/summary_move_condensed_empty_icon.png")
|
||||
}
|
||||
|
||||
var controllerComponentManager = ControllerComponentManager(movesWidget.summary).also {
|
||||
it.onActiveChange = { state ->
|
||||
if (state) it.focused?.onSelect?.invoke() else it.focused?.onUnselect?.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
public override fun addEntry(entry: MoveSlot): Int {
|
||||
return super.addEntry(entry)
|
||||
val i = super.addEntry(entry)
|
||||
controllerComponentManager.componentList["moves_${i}"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = entry
|
||||
it.onPress = {
|
||||
entry.onPress()
|
||||
movesWidget.summary.controllerComponentManager.let { controller -> controller.focused = controller.componentList["center_screen"] }
|
||||
}
|
||||
it.onSelect = {
|
||||
ensureVisible(entry)
|
||||
entry.slotSelected = true
|
||||
}
|
||||
it.onUnselect = {
|
||||
entry.slotSelected = false
|
||||
}
|
||||
}
|
||||
if (children().size > 1) {
|
||||
controllerComponentManager.componentList["moves_${i}"]?.let {
|
||||
it.pairUp(controllerComponentManager.componentList["moves_${i-1}"])
|
||||
it.pairDown(controllerComponentManager.componentList["moves_${0}"])
|
||||
}
|
||||
} else {
|
||||
controllerComponentManager.focused = controllerComponentManager.componentList["moves_${i}"]
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
class MoveSlot(val pane: MoveSwapScreen, val move: MoveTemplate?, val ppRaisedStages: Int, pokemon: Pokemon) : Entry<MoveSlot>() {
|
||||
override fun getNarration() = move?.displayName ?: lang("ui.moves.forget")
|
||||
|
||||
val elementalType = move?.getEffectiveElementalType(pokemon) ?: ElementalTypes.NORMAL
|
||||
var slotSelected = false
|
||||
|
||||
override fun render(
|
||||
context: GuiGraphics,
|
||||
index: Int,
|
||||
@@ -80,7 +114,7 @@ class MoveSwapScreen(
|
||||
y = tweakedRowTop,
|
||||
height = SLOT_HEIGHT,
|
||||
width = rowWidth,
|
||||
vOffset = if (isHovered) SLOT_HEIGHT else 0,
|
||||
vOffset = if (isHovered || slotSelected) SLOT_HEIGHT else 0,
|
||||
textureHeight = SLOT_HEIGHT * 2,
|
||||
red = rgb.first,
|
||||
green = rgb.second,
|
||||
@@ -196,7 +230,7 @@ class MoveSwapScreen(
|
||||
y = tweakedRowTop,
|
||||
height = SLOT_HEIGHT,
|
||||
width = 100,
|
||||
vOffset = if (isHovered) SLOT_HEIGHT else 0,
|
||||
vOffset = if (isHovered || slotSelected) SLOT_HEIGHT else 0,
|
||||
textureHeight = SLOT_HEIGHT * 2,
|
||||
)
|
||||
blitk(
|
||||
@@ -206,7 +240,7 @@ class MoveSwapScreen(
|
||||
y = tweakedRowTop + SLOT_HEIGHT / 2 - 4,
|
||||
height = 7,
|
||||
width = 7,
|
||||
vOffset = if (isHovered) 7 else 0,
|
||||
vOffset = if (isHovered || slotSelected) 7 else 0,
|
||||
textureHeight = 14,
|
||||
)
|
||||
}
|
||||
@@ -215,21 +249,29 @@ class MoveSwapScreen(
|
||||
|
||||
override fun mouseClicked(d: Double, e: Double, i: Int): Boolean {
|
||||
if (isMouseOver(d, e)) {
|
||||
val pokemon = pane.movesWidget.summary.selectedPokemon
|
||||
val isParty = pokemon in CobblemonClient.storage.party
|
||||
CobblemonNetwork.sendToServer(
|
||||
BenchMovePacket(
|
||||
isParty = isParty,
|
||||
uuid = pokemon.uuid,
|
||||
oldMove = pane.replacedMove?.template,
|
||||
newMove = move
|
||||
)
|
||||
)
|
||||
pane.movesWidget.summary.playSound(CobblemonSounds.GUI_CLICK)
|
||||
pane.movesWidget.summary.displaySideScreen(Summary.PARTY)
|
||||
onPress()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun onPress() {
|
||||
switchMove()
|
||||
pane.movesWidget.summary.playSound(CobblemonSounds.GUI_CLICK)
|
||||
pane.movesWidget.summary.displaySideScreen(Summary.PARTY)
|
||||
}
|
||||
|
||||
fun switchMove() {
|
||||
val pokemon = pane.movesWidget.summary.selectedPokemon
|
||||
val isParty = pokemon in CobblemonClient.storage.party
|
||||
CobblemonNetwork.sendToServer(
|
||||
BenchMovePacket(
|
||||
isParty = isParty,
|
||||
uuid = pokemon.uuid,
|
||||
oldMove = pane.replacedMove?.template,
|
||||
newMove = move
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+80
-4
@@ -9,21 +9,24 @@
|
||||
package com.cobblemon.mod.common.client.gui.summary.widgets.screens.moves
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.moves.Move
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.client.CobblemonClient
|
||||
import com.cobblemon.mod.common.client.gui.summary.Summary
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.SoundlessWidget
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponent
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponentManager
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.net.messages.server.RequestMoveSwapPacket
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import java.math.RoundingMode
|
||||
import java.text.DecimalFormat
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.network.chat.Component
|
||||
import java.math.RoundingMode
|
||||
import java.text.DecimalFormat
|
||||
|
||||
class MovesWidget(
|
||||
pX: Int, pY: Int,
|
||||
@@ -47,8 +50,8 @@ class MovesWidget(
|
||||
|
||||
var selectedMove: Move? = null
|
||||
|
||||
private var index = -1
|
||||
private val moves = (
|
||||
var index = -1
|
||||
val moves = (
|
||||
if (summary.selectedPokemon.relearnableMoves.count() > 0)
|
||||
summary.selectedPokemon.moveSet.getMovesWithNulls()
|
||||
else summary.selectedPokemon.moveSet
|
||||
@@ -71,6 +74,79 @@ class MovesWidget(
|
||||
5
|
||||
)
|
||||
|
||||
val controllerComponentManager = ControllerComponentManager(summary).also { controller ->
|
||||
var i = 0
|
||||
moves.forEach { move ->
|
||||
controller.componentList["move_${i}"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = move
|
||||
var upLoc = i - 1
|
||||
if (upLoc < 0) upLoc = moves.size - 1
|
||||
it.up = {
|
||||
var returnVal: ControllerComponent?
|
||||
if (!summary.moveSwitchingMode) {
|
||||
returnVal = controller.componentList["move_${upLoc}"]
|
||||
} else {
|
||||
returnVal = null
|
||||
summary.selectedMoveIndex = upLoc
|
||||
reorderMove(move, true)
|
||||
}
|
||||
returnVal
|
||||
}
|
||||
var downLoc = i + 1
|
||||
if (downLoc > moves.size - 1) downLoc = 0
|
||||
it.down = {
|
||||
var returnVal: ControllerComponent?
|
||||
if (!summary.moveSwitchingMode) {
|
||||
returnVal = controller.componentList["move_${downLoc}"]
|
||||
} else {
|
||||
returnVal = null
|
||||
summary.selectedMoveIndex = downLoc
|
||||
reorderMove(move, false)
|
||||
}
|
||||
returnVal
|
||||
}
|
||||
it.onSpecial1 = {
|
||||
if (!summary.moveSwitchingMode) {
|
||||
summary.playSound(CobblemonSounds.GUI_CLICK)
|
||||
summary.displaySideScreen(Summary.MOVE_SWAP, move.move)
|
||||
}
|
||||
}
|
||||
it.onSpecial2 = {
|
||||
summary.playSound(CobblemonSounds.GUI_CLICK)
|
||||
summary.moveSwitchingMode = !summary.moveSwitchingMode
|
||||
if (summary.moveSwitchingMode) {
|
||||
move.moveUpButton.isFocused = true
|
||||
move.moveDownButton.isFocused = true
|
||||
} else {
|
||||
move.moveUpButton.isFocused = false
|
||||
move.moveDownButton.isFocused = false
|
||||
}
|
||||
}
|
||||
val staticI = i
|
||||
it.onSelect = {
|
||||
summary.selectedMoveIndex = staticI
|
||||
if (selectedMove != move.move) selectMove(move.move)
|
||||
if (summary.moveSwitchingMode) {
|
||||
move.moveUpButton.isFocused = true
|
||||
move.moveDownButton.isFocused = true
|
||||
}
|
||||
}
|
||||
it.onUnselect = {
|
||||
move.moveUpButton.isFocused = false
|
||||
move.moveDownButton.isFocused = false
|
||||
}
|
||||
}
|
||||
i++
|
||||
}
|
||||
controller.onNoneSelected = {
|
||||
summary.selectedMoveIndex = summary.selectedMoveIndex.coerceIn(0, moves.size - 1)
|
||||
controller.focused = controller.componentList["move_${summary.selectedMoveIndex}"]
|
||||
true
|
||||
}
|
||||
controller.onActiveChange = { state ->
|
||||
if (state) controller.focused?.onSelect?.invoke() else controller.focused?.onUnselect?.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
override fun renderWidget(context: GuiGraphics, pMouseX: Int, pMouseY: Int, pPartialTicks: Float) {
|
||||
val matrices = context.pose()
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ class ReorderMoveButton(
|
||||
texture = if (isUp) moveReorderUpResource else moveReorderDownResource,
|
||||
width = WIDTH,
|
||||
height = HEIGHT,
|
||||
vOffset = if (isHovered(pMouseX.toDouble(), pMouseY.toDouble(), offsetY.toFloat())) HEIGHT else 0,
|
||||
vOffset = if (isHovered(pMouseX.toDouble(), pMouseY.toDouble(), offsetY.toFloat()) || isFocused) HEIGHT else 0,
|
||||
textureHeight = HEIGHT * 2,
|
||||
scale = SCALE
|
||||
)
|
||||
|
||||
+34
-19
@@ -19,6 +19,7 @@ import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.api.text.bold
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.gui.summary.Summary
|
||||
import com.cobblemon.mod.common.client.gui.summary.SummaryButton
|
||||
import com.cobblemon.mod.common.client.gui.summary.featurerenderers.BarSummarySpeciesFeatureRenderer
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.SoundlessWidget
|
||||
@@ -49,16 +50,17 @@ import org.joml.Vector3f
|
||||
class StatWidget(
|
||||
pX: Int, pY: Int,
|
||||
val pokemon: Pokemon,
|
||||
val tabIndex: Int = 0
|
||||
val tabIndex: Int = 0,
|
||||
val summary: Summary
|
||||
): SoundlessWidget(pX, pY, WIDTH, HEIGHT, Component.literal("StatWidget")) {
|
||||
|
||||
companion object {
|
||||
// Stat tab options
|
||||
private const val STATS = "stats"
|
||||
private const val IV = "ivs"
|
||||
private const val EV = "evs"
|
||||
private const val RIDE = "ride"
|
||||
private const val OTHER = "other"
|
||||
const val STATS = "stats"
|
||||
const val IV = "ivs"
|
||||
const val EV = "evs"
|
||||
const val RIDE = "ride"
|
||||
const val OTHER = "other"
|
||||
|
||||
private const val OTHER_STAT_BARS_PER_PAGE = 4
|
||||
private const val STAT_TAB_WIDTH_6 = 22
|
||||
@@ -66,6 +68,7 @@ class StatWidget(
|
||||
private const val MARKER_WIDTH = 8
|
||||
private const val WIDTH = 134
|
||||
private const val HEIGHT = 148
|
||||
private const val RIDE_ICON_SIZE = 32
|
||||
const val SCALE = 0.5F
|
||||
|
||||
private const val WHITE = 0x00FFFFFF
|
||||
@@ -112,13 +115,13 @@ class StatWidget(
|
||||
)
|
||||
}
|
||||
|
||||
private val statOptions = if (pokemon.form.riding.behaviours != null) listOf(STATS, IV, EV, RIDE, OTHER) else listOf(STATS, IV, EV, OTHER)
|
||||
val statOptions = if (pokemon.form.riding.behaviours != null) listOf(STATS, IV, EV, RIDE, OTHER) else listOf(STATS, IV, EV, OTHER)
|
||||
|
||||
private var _statTabIndex: Int = tabIndex
|
||||
var rawStatTabIndex: Int = tabIndex
|
||||
var statTabIndex: Int
|
||||
get() = _statTabIndex.coerceIn(0, statOptions.size - 1)
|
||||
get() = rawStatTabIndex.coerceIn(0, statOptions.size - 1)
|
||||
set(value) {
|
||||
_statTabIndex = value.coerceIn(0, statOptions.size - 1)
|
||||
rawStatTabIndex = value.coerceIn(0, statOptions.size - 1)
|
||||
}
|
||||
|
||||
private var _rideBehaviourIndex: Int = 0
|
||||
@@ -301,7 +304,7 @@ class StatWidget(
|
||||
pokemon.form.riding.behaviours?.let {
|
||||
val behaviours = it.entries.toList()
|
||||
val selectedBehaviour = behaviours[rideBehaviourIndex]
|
||||
val canSwitchStyle = behaviours.size > 1 && centerHovered(pMouseX, pMouseY)
|
||||
val canSwitchStyle = behaviours.size > 1 && (centerHovered(pMouseX, pMouseY) || (summary.controllerComponentManager.let { it.active && it.currentSelectedComponent == "center_screen" }))
|
||||
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
@@ -336,14 +339,16 @@ class StatWidget(
|
||||
colour = pentagonColour
|
||||
)
|
||||
|
||||
drawScaledText(
|
||||
context = context,
|
||||
font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = lang("ui.ride_style.${selectedBehaviour.key.name.lowercase()}").bold(),
|
||||
x = x + (WIDTH / 2),
|
||||
y = y + 66,
|
||||
shadow = true,
|
||||
centered = true
|
||||
val rideStyle = selectedBehaviour.value.key.path.toString().split("/").last().lowercase()
|
||||
val iconResource = cobblemonResource("textures/gui/summary/icon_ride_${selectedBehaviour.key.toString().lowercase()}_${rideStyle}.png")
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = iconResource,
|
||||
x= (x + 59) / SCALE,
|
||||
y = (y + 62.5) / SCALE,
|
||||
width = RIDE_ICON_SIZE,
|
||||
height = RIDE_ICON_SIZE,
|
||||
scale = SCALE
|
||||
)
|
||||
|
||||
// Stat Labels
|
||||
@@ -368,6 +373,16 @@ class StatWidget(
|
||||
verticesOffset = pentagonVerticesOffset,
|
||||
offsetY = 5.5
|
||||
)
|
||||
|
||||
if (pMouseX >= (x + 59) && pMouseY >= (y + 62.5) && pMouseX <= ((x + 59) + (RIDE_ICON_SIZE * SCALE)) && pMouseY <= ((y + 62.5) + (RIDE_ICON_SIZE * SCALE))) {
|
||||
context.renderTooltip(
|
||||
Minecraft.getInstance().font,
|
||||
lang("ui.ride_style.${selectedBehaviour.key.toString().lowercase()}.${rideStyle}")
|
||||
.append(" | ").append(lang("ui.ride_style.${selectedBehaviour.key.toString().lowercase()}")),
|
||||
pMouseX,
|
||||
pMouseY
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
@@ -49,7 +49,7 @@ open class PartySlot(
|
||||
|
||||
override fun renderWidget(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
val matrices = context.pose()
|
||||
if (!isOpposing && isHovered(mouseX, mouseY)) {
|
||||
if (!isOpposing && (isHovered(mouseX, mouseY) || isFocused)) {
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = hoverBackgroundResource,
|
||||
|
||||
@@ -49,7 +49,7 @@ class TradeButton(
|
||||
y = y,
|
||||
width = WIDTH,
|
||||
height = HEIGHT,
|
||||
vOffset = if (isHovered(mouseX.toDouble(), mouseY.toDouble())) HEIGHT else 0,
|
||||
vOffset = if (isHovered(mouseX.toDouble(), mouseY.toDouble()) || isFocused) HEIGHT else 0,
|
||||
textureHeight = HEIGHT * 2
|
||||
)
|
||||
|
||||
|
||||
@@ -22,6 +22,9 @@ import com.cobblemon.mod.common.client.gui.TypeIcon
|
||||
import com.cobblemon.mod.common.client.gui.summary.Summary
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.MarkingsWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.common.reformatNatureTextIfMinted
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponentManager
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponent
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerScreen
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.render.drawScaledTextJustifiedRight
|
||||
import com.cobblemon.mod.common.client.trade.ClientTrade
|
||||
@@ -32,6 +35,7 @@ import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.cobblemon.mod.common.util.toAssetPath
|
||||
import com.mojang.blaze3d.platform.InputConstants
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
@@ -54,7 +58,7 @@ class TradeGUI(
|
||||
val traderName: MutableComponent,
|
||||
val traderParty: MutableList<TradeablePokemon?>,
|
||||
val party: MutableList<TradeablePokemon?>
|
||||
): Screen(lang("trade.gui.title")), CobblemonRenderable {
|
||||
): Screen(lang("trade.gui.title")), CobblemonRenderable, ControllerScreen {
|
||||
|
||||
companion object {
|
||||
const val BASE_WIDTH = 293
|
||||
@@ -117,6 +121,13 @@ class TradeGUI(
|
||||
|
||||
var tradeSoundInstance: SoundInstance? = null
|
||||
|
||||
val controllerComponentManager = ControllerComponentManager(this)
|
||||
var lastSelectedRow = 0
|
||||
|
||||
override fun getComponentManager(): ControllerComponentManager {
|
||||
return controllerComponentManager
|
||||
}
|
||||
|
||||
init {
|
||||
trade.cancelEmitter.subscribe {
|
||||
cancelTradeSound()
|
||||
@@ -177,21 +188,25 @@ class TradeGUI(
|
||||
)
|
||||
|
||||
// Trade Button
|
||||
this.addRenderableWidget(
|
||||
TradeButton(
|
||||
x = x + 120,
|
||||
y = y + 119,
|
||||
parent = this,
|
||||
onPress = {
|
||||
if (offeredPokemon != null && opposingOfferedPokemon != null && protectiveTicks <= 0 && !tradeProcessing) {
|
||||
ticksElapsed = 0
|
||||
readyProgress = 0
|
||||
CobblemonNetwork.sendToServer(ChangeTradeAcceptancePacket(opposingOfferedPokemon!!.uuid, !trade.acceptedOppositeOffer))
|
||||
playSound(CobblemonSounds.GUI_CLICK)
|
||||
}
|
||||
val tradeButton = TradeButton(
|
||||
x = x + 120,
|
||||
y = y + 119,
|
||||
parent = this,
|
||||
onPress = {
|
||||
if (offeredPokemon != null && opposingOfferedPokemon != null && protectiveTicks <= 0 && !tradeProcessing) {
|
||||
ticksElapsed = 0
|
||||
readyProgress = 0
|
||||
CobblemonNetwork.sendToServer(ChangeTradeAcceptancePacket(opposingOfferedPokemon!!.uuid, !trade.acceptedOppositeOffer))
|
||||
playSound(CobblemonSounds.GUI_CLICK)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
this.addRenderableWidget(tradeButton)
|
||||
|
||||
controllerComponentManager.componentList["trade"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = tradeButton
|
||||
it.left = { controllerComponentManager.componentList["slot_${lastSelectedRow}_${1}"] }
|
||||
}
|
||||
|
||||
// Party
|
||||
for (partyIndex in 0..5) {
|
||||
@@ -209,7 +224,7 @@ class TradeGUI(
|
||||
}
|
||||
|
||||
val pokemon = party[partyIndex]
|
||||
PartySlot(
|
||||
val slot = PartySlot(
|
||||
x = slotX,
|
||||
y = slotY,
|
||||
pokemon = pokemon,
|
||||
@@ -222,6 +237,22 @@ class TradeGUI(
|
||||
}
|
||||
}
|
||||
).also { widget -> addRenderableWidget(widget) }
|
||||
|
||||
val row = partyIndex / 2
|
||||
val column = partyIndex % 2
|
||||
controllerComponentManager.componentList["slot_${row}_${column}"] = ControllerComponent().also {
|
||||
it.associatedGUIElement = slot
|
||||
if (column == 0) it.right = { controllerComponentManager.componentList["slot_${row}_${1}"] }
|
||||
else {
|
||||
it.left = { controllerComponentManager.componentList["slot_${row}_${0}"] }
|
||||
it.right = { controllerComponentManager.componentList["trade"] }
|
||||
}
|
||||
if (row - 1 >= 0) it.up = { controllerComponentManager.componentList["slot_${row-1}_${column}"] }
|
||||
if (row + 1 <= 2) it.down = { controllerComponentManager.componentList["slot_${row+1}_${column}"] }
|
||||
it.onSelect = {
|
||||
lastSelectedRow = row
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Opposing Party
|
||||
@@ -256,6 +287,10 @@ class TradeGUI(
|
||||
opposingOfferedPokemonMarkings = MarkingsWidget(x + 177.5, y + 21, opposingOfferedPokemon, false)
|
||||
addRenderableWidget(offeredPokemonMarkings)
|
||||
addRenderableWidget(opposingOfferedPokemonMarkings)
|
||||
|
||||
controllerComponentManager.let {
|
||||
it.focused = it.componentList["slot_0_0"]
|
||||
}
|
||||
}
|
||||
|
||||
override fun render(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
@@ -444,6 +479,8 @@ class TradeGUI(
|
||||
val itemHovered = mouseX.toFloat() in (itemX.toFloat()..(itemX.toFloat() + 16)) && mouseY.toFloat() in (itemY.toFloat()..(itemY.toFloat() + 16))
|
||||
if (itemHovered) context.renderTooltip(Minecraft.getInstance().font, opposingOfferedPokemon!!.heldItemNoCopy(), mouseX, mouseY)
|
||||
}
|
||||
|
||||
renderSelection(matrices)
|
||||
}
|
||||
|
||||
override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean {
|
||||
@@ -584,7 +621,7 @@ class TradeGUI(
|
||||
|
||||
// Poké Ball
|
||||
val nameXOffset = if (isOpposing) 75 else 0
|
||||
val ballResource = cobblemonResource("textures/item/poke_balls/" + pokemon.caughtBall.name.path + ".png")
|
||||
val ballResource = pokemon.caughtBall.name.toAssetPath("textures/item/poke_balls/", ".png")
|
||||
blitk(
|
||||
matrixStack = context.pose(),
|
||||
texture = ballResource,
|
||||
|
||||
+354
@@ -0,0 +1,354 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.integration.controlify
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonItems
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.client.CobblemonClient
|
||||
import com.cobblemon.mod.common.client.CobblemonClient.ridingTurnInputHandler
|
||||
import com.cobblemon.mod.common.client.gui.battle.BattleGUI
|
||||
import com.cobblemon.mod.common.client.gui.config.CobblemonConfigScreen
|
||||
import com.cobblemon.mod.common.client.gui.cookingpot.CookingPotScreen
|
||||
import com.cobblemon.mod.common.client.gui.dialogue.DialogueScreen
|
||||
import com.cobblemon.mod.common.client.gui.interact.battleRequest.BattleConfigureGUI
|
||||
import com.cobblemon.mod.common.client.gui.interact.moveselect.MoveSelectGUI
|
||||
import com.cobblemon.mod.common.client.gui.interact.partyselect.PartySelectGUI
|
||||
import com.cobblemon.mod.common.client.gui.interact.wheel.InteractWheelGUI
|
||||
import com.cobblemon.mod.common.client.gui.pc.PCGUI
|
||||
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUI
|
||||
import com.cobblemon.mod.common.client.gui.snapshots.SnapshotWarningScreen
|
||||
import com.cobblemon.mod.common.client.gui.startselection.StarterSelectionScreen
|
||||
import com.cobblemon.mod.common.client.gui.summary.Summary
|
||||
import com.cobblemon.mod.common.client.gui.trade.TradeGUI
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.CobblemonGUIProcessor
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.InteractWheelProcessor
|
||||
import com.cobblemon.mod.common.client.keybind.CobblemonKeyBinds
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import dev.isxander.controlify.Controlify
|
||||
import dev.isxander.controlify.api.ControlifyApi
|
||||
import dev.isxander.controlify.api.bind.ControlifyBindApi
|
||||
import dev.isxander.controlify.api.bind.InputBindingBuilder
|
||||
import dev.isxander.controlify.api.bind.InputBindingSupplier
|
||||
import dev.isxander.controlify.api.entrypoint.ControlifyEntrypoint
|
||||
import dev.isxander.controlify.api.entrypoint.InitContext
|
||||
import dev.isxander.controlify.api.entrypoint.PreInitContext
|
||||
import dev.isxander.controlify.bindings.BindContext
|
||||
import dev.isxander.controlify.bindings.ControlifyBindings
|
||||
import dev.isxander.controlify.bindings.RadialIcons
|
||||
import dev.isxander.controlify.screenop.ScreenProcessor
|
||||
import dev.isxander.controlify.screenop.ScreenProcessorFactory
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.screens.Screen
|
||||
import net.minecraft.client.player.LocalPlayer
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.item.Items
|
||||
import org.joml.Vector2d
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.full.primaryConstructor
|
||||
|
||||
class CobblemonControlifyEntrypoint : ControlifyEntrypoint {
|
||||
override fun onControlifyInit(initContext: InitContext) {
|
||||
ridingTurnInputHandler.put(
|
||||
cobblemonResource("compat.controlify"),
|
||||
({ localPlayer: LocalPlayer, xDelta: Double, yDelta: Double, deltaTime: Double ->
|
||||
val vec = Vector2d(xDelta, yDelta)
|
||||
val controller = initContext.controlify().currentController.getOrNull()
|
||||
val vehicle = localPlayer.vehicle
|
||||
if (vehicle is OrientationControllable && vehicle.orientationController.isActive() && initContext.controlify().currentInputMode().isController && controller != null){
|
||||
val multiplier = deltaTime * 1500
|
||||
val config = controller.input().getOrNull()?.config()?.config()
|
||||
val vSensitivity = config?.vLookSensitivity ?: 0.9f
|
||||
val hSensitivity = config?.hLookSensitivity ?: 1f
|
||||
|
||||
// Should never be null once bindings are set
|
||||
var vAxis = (RIDING_DOWN!!.on(controller).analogueNow() - RIDING_UP!!.on(controller).analogueNow()).toDouble()
|
||||
var hAxis = (RIDING_RIGHT!!.on(controller).analogueNow() - RIDING_LEFT!!.on(controller).analogueNow()).toDouble()
|
||||
|
||||
vAxis *= multiplier * vSensitivity
|
||||
hAxis *= multiplier * hSensitivity
|
||||
vec.x = hAxis
|
||||
vec.y = vAxis
|
||||
}
|
||||
vec
|
||||
})
|
||||
)
|
||||
|
||||
CobblemonClient.ridingSprintHandler.put(
|
||||
cobblemonResource("compat.controlify")
|
||||
) {
|
||||
initContext.controlify().currentController.getOrNull()?.let { ControlifyBindings.SPRINT.on(it).digitalNow() } == true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onControlifyPreInit(initContext: PreInitContext) {
|
||||
val bindings = ControlifyBindApi.get()
|
||||
bindings.registerBindContext(RIDING_POKEMON)
|
||||
bindings.registerBindContext(ORIENTATION_CONTROLLER_ACTIVE)
|
||||
|
||||
bindings.registerBindContext(HAS_POKEMON)
|
||||
bindings.registerBindContext(INTERACT_WHEEL_SCREEN)
|
||||
|
||||
RIDING_UP =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("riding_up"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("controlify.bind.cobblemon.riding_up"))
|
||||
.allowedContexts(ORIENTATION_CONTROLLER_ACTIVE, BindContext.IN_GAME)
|
||||
}
|
||||
|
||||
RIDING_DOWN =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("riding_down"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("controlify.bind.cobblemon.riding_down"))
|
||||
.allowedContexts(ORIENTATION_CONTROLLER_ACTIVE, BindContext.IN_GAME)
|
||||
}
|
||||
|
||||
RIDING_LEFT =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("riding_left"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("controlify.bind.cobblemon.riding_left"))
|
||||
.allowedContexts(ORIENTATION_CONTROLLER_ACTIVE, BindContext.IN_GAME)
|
||||
}
|
||||
|
||||
RIDING_RIGHT =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("riding_right"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("controlify.bind.cobblemon.riding_right"))
|
||||
.allowedContexts(ORIENTATION_CONTROLLER_ACTIVE, BindContext.IN_GAME)
|
||||
}
|
||||
|
||||
HIDE_PARTY =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("hide_party"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("key.cobblemon.hideparty"))
|
||||
.allowedContexts(BindContext.IN_GAME)
|
||||
.radialCandidate(RadialIcons.getItem(Items.BARRIER))
|
||||
.addKeyCorrelation(CobblemonKeyBinds.HIDE_PARTY)
|
||||
.keyEmulation(CobblemonKeyBinds.HIDE_PARTY)
|
||||
}
|
||||
|
||||
SUMMARY =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("summary"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("key.cobblemon.summary"))
|
||||
.allowedContexts(BindContext.IN_GAME)
|
||||
.radialCandidate(RadialIcons.getItem(CobblemonItems.GREAT_BALL))
|
||||
.addKeyCorrelation(CobblemonKeyBinds.SUMMARY)
|
||||
.keyEmulation(CobblemonKeyBinds.SUMMARY)
|
||||
}
|
||||
|
||||
PARTY_OVERLAY_DOWN =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("party_overlay_down"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("key.cobblemon.downshiftparty"))
|
||||
.allowedContexts(HAS_POKEMON, BindContext.IN_GAME)
|
||||
.radialCandidate(RadialIcons.EMPTY)
|
||||
.addKeyCorrelation(CobblemonKeyBinds.PARTY_OVERLAY_DOWN)
|
||||
.keyEmulation(CobblemonKeyBinds.PARTY_OVERLAY_DOWN)
|
||||
}
|
||||
|
||||
PARTY_OVERLAY_UP =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("party_overlay_up"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("key.cobblemon.upshiftparty"))
|
||||
.allowedContexts(HAS_POKEMON, BindContext.IN_GAME)
|
||||
.radialCandidate(RadialIcons.EMPTY)
|
||||
.addKeyCorrelation(CobblemonKeyBinds.PARTY_OVERLAY_UP)
|
||||
.keyEmulation(CobblemonKeyBinds.PARTY_OVERLAY_DOWN)
|
||||
}
|
||||
|
||||
SEND_OUT_POKEMON =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("send_out_pokemon"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("key.cobblemon.throwpartypokemon"))
|
||||
.allowedContexts(HAS_POKEMON, BindContext.IN_GAME)
|
||||
.radialCandidate(RadialIcons.getItem(CobblemonItems.POKE_BALL))
|
||||
.addKeyCorrelation(CobblemonKeyBinds.SEND_OUT_POKEMON)
|
||||
.keyEmulation(CobblemonKeyBinds.SEND_OUT_POKEMON)
|
||||
}
|
||||
|
||||
|
||||
RIDING_FREELOOK =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("riding_freelook"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("key.cobblemon.ridingfreelook"))
|
||||
.allowedContexts(RIDING_POKEMON, BindContext.IN_GAME)
|
||||
.radialCandidate(RadialIcons.EMPTY)
|
||||
.addKeyCorrelation(CobblemonKeyBinds.RIDING_FREELOOK)
|
||||
.keyEmulation(CobblemonKeyBinds.RIDING_FREELOOK)
|
||||
}
|
||||
|
||||
INTERACT_WHEEL_UP_AXIS =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("interact_wheel_up"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("controlify.bind.cobblemon.interact_wheel_up"))
|
||||
.allowedContexts(INTERACT_WHEEL_SCREEN, BindContext.IN_GAME)
|
||||
}
|
||||
|
||||
INTERACT_WHEEL_DOWN_AXIS =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("interact_wheel_down"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("controlify.bind.cobblemon.interact_wheel_down"))
|
||||
.allowedContexts(INTERACT_WHEEL_SCREEN, BindContext.IN_GAME)
|
||||
}
|
||||
|
||||
INTERACT_WHEEL_RIGHT_AXIS =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("interact_wheel_right"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("controlify.bind.cobblemon.interact_wheel_right"))
|
||||
.allowedContexts(INTERACT_WHEEL_SCREEN, BindContext.IN_GAME)
|
||||
}
|
||||
|
||||
INTERACT_WHEEL_LEFT_AXIS =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("interact_wheel_left"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("controlify.bind.cobblemon.interact_wheel_left"))
|
||||
.allowedContexts(INTERACT_WHEEL_SCREEN, BindContext.IN_GAME)
|
||||
}
|
||||
|
||||
GUI_SECONDARY_NEXT_TAB =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("gui_secondary_next_tab"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("controlify.bind.cobblemon.gui_secondary_next_tab"))
|
||||
.allowedContexts(BindContext.ANY_SCREEN)
|
||||
}
|
||||
|
||||
GUI_SECONDARY_PREV_TAB =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("gui_secondary_prev_tab"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("controlify.bind.cobblemon.gui_secondary_prev_tab"))
|
||||
.allowedContexts(BindContext.ANY_SCREEN)
|
||||
}
|
||||
|
||||
GUI_START =
|
||||
bindings.registerBinding { builder: InputBindingBuilder ->
|
||||
builder
|
||||
.id(cobblemonResource("gui_start"))
|
||||
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
|
||||
.name(Component.translatable("controlify.bind.cobblemon.gui_start"))
|
||||
.allowedContexts(BindContext.ANY_SCREEN)
|
||||
}
|
||||
|
||||
|
||||
addProcessor(InteractWheelGUI::class, InteractWheelProcessor::class)
|
||||
// This is the lazy way to do all of these (just using the vmouse), if someone with more time and dedication did this that would be better
|
||||
addProcessor(DialogueScreen::class, CobblemonGUIProcessor::class)
|
||||
// Below are implemented processors for our GUIs
|
||||
addProcessor(Summary::class, CobblemonGUIProcessor::class)
|
||||
addProcessor(BattleGUI::class, CobblemonGUIProcessor::class)
|
||||
addProcessor(PokedexGUI::class, CobblemonGUIProcessor::class)
|
||||
addProcessor(StarterSelectionScreen::class, CobblemonGUIProcessor::class)
|
||||
addProcessor(TradeGUI::class, CobblemonGUIProcessor::class)
|
||||
addProcessor(PartySelectGUI::class, CobblemonGUIProcessor::class)
|
||||
addProcessor(MoveSelectGUI::class, CobblemonGUIProcessor::class)
|
||||
addProcessor(PCGUI::class, CobblemonGUIProcessor::class)
|
||||
addProcessor(BattleConfigureGUI::class, CobblemonGUIProcessor::class)
|
||||
addProcessor(SnapshotWarningScreen::class, CobblemonGUIProcessor::class)
|
||||
addProcessor(CobblemonConfigScreen::class, CobblemonGUIProcessor::class)
|
||||
// This once don't need any
|
||||
addProcessor(CookingPotScreen::class, CobblemonGUIProcessor::class)
|
||||
}
|
||||
|
||||
override fun onControllersDiscovered(controlifyApi: ControlifyApi) {
|
||||
}
|
||||
|
||||
// This is jank, but I did it after I got my wisdom teeth extracted so tbh I think I did good enough, but I won't be offended if someone changes it to something sane.
|
||||
fun addProcessor(t: KClass<out Screen>, processorClazz: KClass<out ScreenProcessor<Screen>>) {
|
||||
ScreenProcessorFactory.registerProvider(t.java) {
|
||||
processorClazz.primaryConstructor?.call(it)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
var RIDING_UP: InputBindingSupplier? = null
|
||||
var RIDING_DOWN: InputBindingSupplier? = null
|
||||
var RIDING_RIGHT: InputBindingSupplier? = null
|
||||
var RIDING_LEFT: InputBindingSupplier? = null
|
||||
var HIDE_PARTY: InputBindingSupplier? = null
|
||||
var SUMMARY: InputBindingSupplier? = null
|
||||
var PARTY_OVERLAY_DOWN: InputBindingSupplier? = null
|
||||
var PARTY_OVERLAY_UP: InputBindingSupplier? = null
|
||||
var SEND_OUT_POKEMON: InputBindingSupplier? = null
|
||||
var RIDING_FREELOOK: InputBindingSupplier? = null
|
||||
var INTERACT_WHEEL_UP_AXIS: InputBindingSupplier? = null
|
||||
var INTERACT_WHEEL_DOWN_AXIS: InputBindingSupplier? = null
|
||||
var INTERACT_WHEEL_LEFT_AXIS: InputBindingSupplier? = null
|
||||
var INTERACT_WHEEL_RIGHT_AXIS: InputBindingSupplier? = null
|
||||
//gui special keybinds
|
||||
var GUI_SECONDARY_NEXT_TAB: InputBindingSupplier? = null
|
||||
var GUI_SECONDARY_PREV_TAB: InputBindingSupplier? = null
|
||||
var GUI_START: InputBindingSupplier? = null
|
||||
|
||||
val RIDING_POKEMON: BindContext = BindContext(
|
||||
cobblemonResource("riding"),
|
||||
{ mc: Minecraft ->
|
||||
mc.player?.vehicle is PokemonEntity
|
||||
}
|
||||
)
|
||||
|
||||
val ORIENTATION_CONTROLLER_ACTIVE: BindContext = BindContext(
|
||||
cobblemonResource("orientation_controller_active"),
|
||||
{ mc: Minecraft ->
|
||||
val localPlayer = mc.player
|
||||
if (localPlayer == null) return@BindContext false
|
||||
val vehicle = localPlayer.vehicle
|
||||
vehicle is OrientationControllable && vehicle.getOrientationController().isActive()
|
||||
}
|
||||
)
|
||||
|
||||
val HAS_POKEMON: BindContext = BindContext(
|
||||
cobblemonResource("has_pokemon"),
|
||||
{mc: Minecraft ->
|
||||
!CobblemonClient.storage.party.isEmpty()
|
||||
}
|
||||
)
|
||||
|
||||
val INTERACT_WHEEL_SCREEN: BindContext = BindContext(
|
||||
cobblemonResource("wheel_screen"),
|
||||
{ it.screen is InteractWheelGUI}
|
||||
)
|
||||
|
||||
fun controllerActive(): Boolean {
|
||||
return Controlify.instance().currentInputMode().isController
|
||||
}
|
||||
}
|
||||
}
|
||||
+253
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.integration.controlify.gui
|
||||
|
||||
import com.cobblemon.mod.common.client.integration.controlify.CobblemonControlifyEntrypoint
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponentManager
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponentManager.ButtonGuideType
|
||||
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerScreen
|
||||
import dev.isxander.controlify.Controlify
|
||||
import dev.isxander.controlify.InputMode
|
||||
import dev.isxander.controlify.bindings.ControlifyBindings
|
||||
import dev.isxander.controlify.bindings.InputBindingSupplierImpl
|
||||
import dev.isxander.controlify.controller.ControllerEntity
|
||||
import dev.isxander.controlify.controller.input.GamepadInputs
|
||||
import dev.isxander.controlify.font.BindingFontHelper
|
||||
import dev.isxander.controlify.gui.guide.GuideRenderer
|
||||
import dev.isxander.controlify.gui.guide.PrecomputedLines
|
||||
import dev.isxander.controlify.screenop.ScreenProcessor
|
||||
import dev.isxander.controlify.virtualmouse.VirtualMouseBehaviour
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.client.gui.components.EditBox
|
||||
import net.minecraft.client.gui.screens.Screen
|
||||
import net.minecraft.network.chat.Component
|
||||
|
||||
open class CobblemonGUIProcessor(open val screen: Screen) : ScreenProcessor<Screen>(screen) {
|
||||
companion object {
|
||||
val typeToGlyth = mutableMapOf<ButtonGuideType, () -> Component>(
|
||||
ButtonGuideType.PRESS to { ControlifyBindings.GUI_PRESS.inputGlyph() },
|
||||
ButtonGuideType.BACK to { ControlifyBindings.GUI_BACK.inputGlyph() },
|
||||
ButtonGuideType.SPECIAL_1 to { ControlifyBindings.GUI_ABSTRACT_ACTION_1.inputGlyph() },
|
||||
ButtonGuideType.SPECIAL_2 to { ControlifyBindings.GUI_ABSTRACT_ACTION_2.inputGlyph() },
|
||||
ButtonGuideType.TAB to { Component.empty().append(ControlifyBindings.GUI_PREV_TAB.inputGlyph()).append(ControlifyBindings.GUI_NEXT_TAB.inputGlyph()) },
|
||||
ButtonGuideType.SECONDARY_TAB to { Component.empty().append(CobblemonControlifyEntrypoint.GUI_SECONDARY_PREV_TAB!!.inputGlyph()).append(CobblemonControlifyEntrypoint.GUI_SECONDARY_NEXT_TAB!!.inputGlyph()) },
|
||||
ButtonGuideType.START to { CobblemonControlifyEntrypoint.GUI_START!!.inputGlyph() },
|
||||
ButtonGuideType.JOYSTICK_HORIZONTAL to { Component.empty().append(ControlifyBindings.GUI_SECONDARY_NAVI_LEFT.inputGlyph()).append(ControlifyBindings.GUI_SECONDARY_NAVI_RIGHT.inputGlyph()) },
|
||||
ButtonGuideType.JOYSTICK_VERTICAL to { Component.empty().append(ControlifyBindings.GUI_SECONDARY_NAVI_UP.inputGlyph()).append(ControlifyBindings.GUI_SECONDARY_NAVI_DOWN.inputGlyph()) }
|
||||
)
|
||||
}
|
||||
|
||||
var editBoxWidget: EditBox? = null
|
||||
|
||||
// Until someone with more dedication than me adds non-vmouse support, we will make heavy use of the vmouse so make that the defualt for us
|
||||
override fun virtualMouseBehaviour(): VirtualMouseBehaviour {
|
||||
if (screen is ControllerScreen) {
|
||||
return VirtualMouseBehaviour.DISABLED
|
||||
}
|
||||
return VirtualMouseBehaviour.CURSOR_ONLY
|
||||
}
|
||||
|
||||
override fun onWidgetRebuild() {
|
||||
(screen as? ControllerScreen)?.getComponentManager()?.let {
|
||||
it.active = Controlify.instance().let { it.currentInputMode().isController && !it.virtualMouseHandler().isVirtualMouseEnabled }
|
||||
it.openKeyboard = { editBox ->
|
||||
editBoxWidget = editBox
|
||||
}
|
||||
it.getVisual = { location ->
|
||||
InputBindingSupplierImpl(location).inputGlyph()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onInputModeChanged(mode: InputMode) {
|
||||
(screen as? ControllerScreen)?.getComponentManager()?.let {
|
||||
val active = mode.isController && !Controlify.instance().virtualMouseHandler().isVirtualMouseEnabled
|
||||
it.active = active
|
||||
}
|
||||
}
|
||||
|
||||
override fun onVirtualMouseToggled(enabled: Boolean) {
|
||||
(screen as? ControllerScreen)?.getComponentManager()?.let{
|
||||
it.active = Controlify.instance().currentInputMode().isController && !enabled
|
||||
}
|
||||
}
|
||||
|
||||
override fun onControllerUpdate(controller: ControllerEntity) {
|
||||
val componentManager = (screen as? ControllerScreen)?.getComponentManager()
|
||||
|
||||
if (componentManager == null) {
|
||||
super.onControllerUpdate(controller)
|
||||
return
|
||||
}
|
||||
|
||||
//It was easier to fully handle this myself
|
||||
Controlify.instance().virtualMouseHandler().handleControllerInput(controller)
|
||||
|
||||
val repeatAvailable = holdRepeatHelper.canNavigate()
|
||||
|
||||
if (!Controlify.instance().virtualMouseHandler().isVirtualMouseEnabled) {
|
||||
//Handling Base
|
||||
if (ControlifyBindings.GUI_PRESS.on(controller).justPressed()) {
|
||||
componentManager.press()
|
||||
}
|
||||
if (ControlifyBindings.GUI_BACK.on(controller).justPressed()) {
|
||||
componentManager.onBack.invoke()
|
||||
}
|
||||
//Handling Special
|
||||
if (ControlifyBindings.GUI_ABSTRACT_ACTION_1.on(controller).justPressed()) {
|
||||
componentManager.special1()
|
||||
}
|
||||
if (ControlifyBindings.GUI_ABSTRACT_ACTION_2.on(controller).justPressed()) {
|
||||
componentManager.special2()
|
||||
}
|
||||
if (CobblemonControlifyEntrypoint.GUI_START!!.on(controller).justPressed()) {
|
||||
componentManager.onStart.invoke()
|
||||
}
|
||||
//Handling RJoystick
|
||||
val guiNaviRight = ControlifyBindings.GUI_SECONDARY_NAVI_RIGHT.on(controller)
|
||||
val guiNaviLeft = ControlifyBindings.GUI_SECONDARY_NAVI_LEFT.on(controller)
|
||||
val guiNaviUp = ControlifyBindings.GUI_SECONDARY_NAVI_UP.on(controller)
|
||||
val guiNaviDown = ControlifyBindings.GUI_SECONDARY_NAVI_DOWN.on(controller)
|
||||
|
||||
if (guiNaviRight.digitalNow()) {
|
||||
componentManager.onRHorizontalHeld.invoke(true)
|
||||
if (!guiNaviRight.digitalPrev() || repeatAvailable) {
|
||||
holdRepeatHelper.reset()
|
||||
componentManager.onRHorizontal.invoke(true)
|
||||
}
|
||||
} else if (guiNaviLeft.digitalNow()) {
|
||||
componentManager.onRHorizontalHeld.invoke(false)
|
||||
if (!guiNaviLeft.digitalPrev() || repeatAvailable) {
|
||||
holdRepeatHelper.reset()
|
||||
componentManager.onRHorizontal.invoke(false)
|
||||
}
|
||||
}
|
||||
if (guiNaviUp.digitalNow()) {
|
||||
componentManager.onRVerticalHeld.invoke(true)
|
||||
if (!guiNaviUp.digitalPrev() || repeatAvailable) {
|
||||
holdRepeatHelper.reset()
|
||||
componentManager.onRVertical.invoke(true)
|
||||
}
|
||||
} else if (guiNaviDown.digitalNow()) {
|
||||
componentManager.onRVerticalHeld.invoke(false)
|
||||
if (!guiNaviDown.digitalPrev() || repeatAvailable) {
|
||||
holdRepeatHelper.reset()
|
||||
componentManager.onRVertical.invoke(false)
|
||||
}
|
||||
}
|
||||
//Handle Navigation
|
||||
handleNavigation(controller, componentManager)
|
||||
} else {
|
||||
handleScreenVMouse(controller, Controlify.instance().virtualMouseHandler())
|
||||
}
|
||||
|
||||
//Main Tab
|
||||
if (ControlifyBindings.GUI_NEXT_TAB.on(controller).digitalNow() && (repeatAvailable || !ControlifyBindings.GUI_NEXT_TAB.on(controller).digitalPrev())) {
|
||||
holdRepeatHelper.reset()
|
||||
componentManager.onTabNav.invoke(true)
|
||||
} else if (ControlifyBindings.GUI_PREV_TAB.on(controller).digitalNow() && (repeatAvailable || !ControlifyBindings.GUI_PREV_TAB.on(controller).digitalPrev())) {
|
||||
holdRepeatHelper.reset()
|
||||
componentManager.onTabNav.invoke(false)
|
||||
}
|
||||
|
||||
//Secondary Tab
|
||||
if (CobblemonControlifyEntrypoint.GUI_SECONDARY_NEXT_TAB!!.on(controller).digitalNow() && (repeatAvailable || !CobblemonControlifyEntrypoint.GUI_SECONDARY_NEXT_TAB!!.on(controller).digitalPrev())) {
|
||||
holdRepeatHelper.reset()
|
||||
componentManager.onSecondaryTabNav.invoke(true)
|
||||
} else if (CobblemonControlifyEntrypoint.GUI_SECONDARY_PREV_TAB!!.on(controller).digitalNow() && (repeatAvailable || !CobblemonControlifyEntrypoint.GUI_SECONDARY_PREV_TAB!!.on(controller).digitalPrev())) {
|
||||
holdRepeatHelper.reset()
|
||||
componentManager.onSecondaryTabNav.invoke(false)
|
||||
}
|
||||
|
||||
if (editBoxWidget != null) {
|
||||
tryOpenKeyboard(controller, editBoxWidget)
|
||||
editBoxWidget = null
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleNavigation(controller: ControllerEntity, componentManager: ControllerComponentManager) {
|
||||
val repeatAvailable = holdRepeatHelper.canNavigate()
|
||||
|
||||
val input = controller.input().orElseThrow()
|
||||
val state = input.stateNow()
|
||||
val prevState = input.stateThen()
|
||||
|
||||
val guiNaviRight = ControlifyBindings.GUI_NAVI_RIGHT.on(controller)
|
||||
val guiNaviLeft = ControlifyBindings.GUI_NAVI_LEFT.on(controller)
|
||||
val guiNaviUp = ControlifyBindings.GUI_NAVI_UP.on(controller)
|
||||
val guiNaviDown = ControlifyBindings.GUI_NAVI_DOWN.on(controller)
|
||||
|
||||
if (guiNaviRight.digitalNow() && (repeatAvailable || !guiNaviRight.digitalPrev())) {
|
||||
componentManager.right()
|
||||
holdRepeatHelper.reset()
|
||||
} else if (guiNaviLeft.digitalNow() && (repeatAvailable || !guiNaviLeft.digitalPrev())) {
|
||||
componentManager.left()
|
||||
holdRepeatHelper.reset()
|
||||
} else if (guiNaviUp.digitalNow() && (repeatAvailable || !guiNaviUp.digitalPrev())) {
|
||||
componentManager.up()
|
||||
holdRepeatHelper.reset()
|
||||
} else if (guiNaviDown.digitalNow() && (repeatAvailable || !guiNaviDown.digitalPrev())) {
|
||||
componentManager.down()
|
||||
holdRepeatHelper.reset()
|
||||
} else if (state.isButtonDown(GamepadInputs.DPAD_RIGHT_BUTTON) && (repeatAvailable || !prevState.isButtonDown(GamepadInputs.DPAD_RIGHT_BUTTON))) {
|
||||
componentManager.right()
|
||||
holdRepeatHelper.reset()
|
||||
} else if (state.isButtonDown(GamepadInputs.DPAD_LEFT_BUTTON) && (repeatAvailable || !prevState.isButtonDown(GamepadInputs.DPAD_LEFT_BUTTON))) {
|
||||
componentManager.left()
|
||||
holdRepeatHelper.reset()
|
||||
} else if (state.isButtonDown(GamepadInputs.DPAD_UP_BUTTON) && (repeatAvailable || !prevState.isButtonDown(GamepadInputs.DPAD_UP_BUTTON))) {
|
||||
componentManager.up()
|
||||
holdRepeatHelper.reset()
|
||||
} else if (state.isButtonDown(GamepadInputs.DPAD_DOWN_BUTTON) && (repeatAvailable || !prevState.isButtonDown(GamepadInputs.DPAD_DOWN_BUTTON))) {
|
||||
componentManager.down()
|
||||
holdRepeatHelper.reset()
|
||||
}
|
||||
}
|
||||
|
||||
override fun render(controller: ControllerEntity, graphics: GuiGraphics, tickDelta: Float) {
|
||||
if (!controller.genericConfig().config().showScreenGuides) return
|
||||
val manager = (screen as? ControllerScreen)?.getComponentManager() ?: return
|
||||
if (!manager.active) return
|
||||
|
||||
val minecraft = Minecraft.getInstance()
|
||||
|
||||
val guideList = manager.buttonGuides.filter { it.condition.invoke() }
|
||||
|
||||
val font = minecraft.font
|
||||
|
||||
val leftLinesBuilder = PrecomputedLines.Builder()
|
||||
val rightLinesBuilder = PrecomputedLines.Builder()
|
||||
|
||||
guideList.forEach { guide ->
|
||||
val builder = if (guide.rightAligned) rightLinesBuilder else leftLinesBuilder
|
||||
|
||||
val glyphAfter = font.isBidirectional.xor(guide.rightAligned)
|
||||
val text = Component.empty()
|
||||
.append(if (glyphAfter) guide.text else typeToGlyth[guide.type]!!.invoke())
|
||||
.append(" ")
|
||||
.append(if (!glyphAfter) guide.text else typeToGlyth[guide.type]!!.invoke())
|
||||
|
||||
val ruleNameWidth: Int = font.width(guide.text)
|
||||
val width = font.width(text)
|
||||
val glyphWidth = width - ruleNameWidth
|
||||
val backgroundLeft = if (glyphAfter) 0 else glyphWidth
|
||||
val backgroundRight = backgroundLeft + ruleNameWidth
|
||||
|
||||
val height = BindingFontHelper.getComponentHeight(font, typeToGlyth[guide.type]!!.invoke())
|
||||
|
||||
builder.addLine(text, width, height, backgroundLeft, backgroundRight)
|
||||
}
|
||||
|
||||
val method = GuideRenderer::class.java.declaredMethods.first { it.name == "renderLines" } //We love Java Reflections
|
||||
method.isAccessible = true
|
||||
method.invoke(null,graphics, leftLinesBuilder.build(), font, minecraft.window.guiScaledWidth, minecraft.window.guiScaledHeight, false, false, true)
|
||||
method.invoke(null,graphics, rightLinesBuilder.build(), font, minecraft.window.guiScaledWidth, minecraft.window.guiScaledHeight, false, true, true)
|
||||
}
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.integration.controlify.gui
|
||||
|
||||
import com.cobblemon.mod.common.client.gui.interact.wheel.InteractWheelGUI
|
||||
import com.cobblemon.mod.common.client.integration.controlify.CobblemonControlifyEntrypoint
|
||||
import dev.isxander.controlify.bindings.ControlifyBindings
|
||||
import dev.isxander.controlify.controller.ControllerEntity
|
||||
import dev.isxander.controlify.controller.haptic.HapticEffects
|
||||
import dev.isxander.controlify.screenop.ScreenControllerEventListener
|
||||
import dev.isxander.controlify.screenop.ScreenProcessor
|
||||
import dev.isxander.controlify.virtualmouse.VirtualMouseBehaviour
|
||||
import net.minecraft.client.gui.screens.Screen
|
||||
import net.minecraft.util.Mth
|
||||
import kotlin.math.abs
|
||||
|
||||
|
||||
// Lots of this is taken from the RadialMenu in Controlify to make this screen feel consistent with it
|
||||
class InteractWheelProcessor(val screen: InteractWheelGUI) : ScreenProcessor<Screen>(screen), ScreenControllerEventListener {
|
||||
private var selectedButton = -1
|
||||
|
||||
override fun onWidgetRebuild() {}
|
||||
|
||||
override fun virtualMouseBehaviour(): VirtualMouseBehaviour {
|
||||
return VirtualMouseBehaviour.DISABLED
|
||||
}
|
||||
|
||||
override fun onControllerUpdate(controller: ControllerEntity) {
|
||||
if (ControlifyBindings.GUI_BACK.on(controller).justPressed()) {
|
||||
screen.onClose()
|
||||
return
|
||||
}
|
||||
|
||||
// If not created from entrypoint then something is very wrong
|
||||
val x = CobblemonControlifyEntrypoint.INTERACT_WHEEL_RIGHT_AXIS!!.on(controller).analogueNow() -
|
||||
CobblemonControlifyEntrypoint.INTERACT_WHEEL_LEFT_AXIS!!.on(controller).analogueNow()
|
||||
val y = CobblemonControlifyEntrypoint.INTERACT_WHEEL_DOWN_AXIS!!.on(controller).analogueNow() -
|
||||
CobblemonControlifyEntrypoint.INTERACT_WHEEL_UP_AXIS!!.on(controller).analogueNow()
|
||||
val threshold = controller.input().orElseThrow().config().config().buttonActivationThreshold
|
||||
|
||||
if (abs(x) >= threshold || abs(y) >= threshold) {
|
||||
val angle = Mth.wrapDegrees(Mth.RAD_TO_DEG * Mth.atan2(y.toDouble(), x.toDouble()) - 90f) + 180f
|
||||
val buttonCount = screen.buttons.size
|
||||
val each = 360f / buttonCount
|
||||
|
||||
val newSelected = Mth.floor((angle + each / 2f) / each) % buttonCount
|
||||
if (newSelected != selectedButton) {
|
||||
selectedButton = newSelected
|
||||
controller.hdHaptics().ifPresent { haptics -> haptics.playHaptic(HapticEffects.NAVIGATE) }
|
||||
}
|
||||
|
||||
for (button in 0..<buttonCount) {
|
||||
val selected = button == selectedButton
|
||||
screen.buttons[button].isFocused = selected
|
||||
}
|
||||
} else if (selectedButton != -1) {
|
||||
if (screen.buttons[selectedButton].isEnabled) {
|
||||
screen.buttons[selectedButton].onPress()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.integration.controlify.gui.component
|
||||
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.components.Button
|
||||
import net.minecraft.client.gui.components.EditBox
|
||||
import net.minecraft.client.gui.components.events.GuiEventListener
|
||||
import net.minecraft.client.gui.screens.Screen
|
||||
import kotlin.reflect.typeOf
|
||||
|
||||
open class ControllerComponent {
|
||||
var left: () -> ControllerComponent? = { null }
|
||||
var right: () -> ControllerComponent? = { null }
|
||||
var up: () -> ControllerComponent? = { null }
|
||||
var down: () -> ControllerComponent? = { null }
|
||||
|
||||
var onPress: (() -> Unit)? = null
|
||||
var onSpecial1: () -> Unit = {}
|
||||
var onSpecial2: () -> Unit = {}
|
||||
|
||||
var onSelect: () -> Unit = {}
|
||||
var onUnselect: () -> Unit = {}
|
||||
|
||||
var onFocus: () -> Unit = {}
|
||||
var onUnfocus: () -> Unit = {}
|
||||
|
||||
var associatedGUIElement: GuiEventListener? = null
|
||||
|
||||
fun pairLeft(leftComponent: ControllerComponent?) {
|
||||
left = { leftComponent }
|
||||
leftComponent?.right = { this }
|
||||
}
|
||||
|
||||
fun pairRight(rightComponent: ControllerComponent?) {
|
||||
right = { rightComponent }
|
||||
rightComponent?.left = { this }
|
||||
}
|
||||
|
||||
fun pairUp(upComponent: ControllerComponent?) {
|
||||
up = { upComponent }
|
||||
upComponent?.down = { this }
|
||||
}
|
||||
|
||||
fun pairDown(downComponent: ControllerComponent?) {
|
||||
down = { downComponent }
|
||||
downComponent?.up = { this }
|
||||
}
|
||||
}
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.integration.controlify.gui.component
|
||||
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.components.Button
|
||||
import net.minecraft.client.gui.components.EditBox
|
||||
import net.minecraft.client.gui.screens.Screen
|
||||
import net.minecraft.client.resources.sounds.SimpleSoundInstance
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.sounds.SoundEvents
|
||||
|
||||
class ControllerComponentManager(val screen: Screen) {
|
||||
var active: Boolean = false
|
||||
get() = field
|
||||
set(value) {
|
||||
if (field != value) {
|
||||
field = value
|
||||
onActiveChange.invoke(value)
|
||||
}
|
||||
if (mainScreenManager()) {
|
||||
if (!value) {
|
||||
screen.focused = null
|
||||
focused?.onUnfocus?.invoke()
|
||||
} else {
|
||||
screen.focused = focused?.associatedGUIElement
|
||||
focused?.onFocus?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var focused: ControllerComponent? = null
|
||||
get() = field
|
||||
set(value) {
|
||||
currentSelectedComponent = (componentList.entries.firstOrNull { it.value == value }?.key ?: "")
|
||||
field?.onUnselect?.invoke()
|
||||
if (active) { field?.onUnfocus?.invoke() }
|
||||
field = value
|
||||
if (active) {
|
||||
field?.associatedGUIElement.let { screen.focused = it }
|
||||
field?.onFocus?.invoke()
|
||||
}
|
||||
field?.onSelect?.invoke()
|
||||
}
|
||||
|
||||
val componentList: MutableMap<String, ControllerComponent> = mutableMapOf()
|
||||
var currentSelectedComponent = ""
|
||||
|
||||
var onTabNav: (Boolean) -> Unit = {}
|
||||
var onSecondaryTabNav: (Boolean) -> Unit = {}
|
||||
var onBack: () -> Unit = {
|
||||
screen.onClose()
|
||||
}
|
||||
var onStart: () -> Unit = {}
|
||||
|
||||
var onActiveChange: (Boolean) -> Unit = {}
|
||||
|
||||
var onNoneSelected: () -> Boolean = { false }
|
||||
|
||||
var onRHorizontalHeld: (Boolean) -> Unit = {}
|
||||
var onRVerticalHeld: (Boolean) -> Unit = {}
|
||||
|
||||
var onRHorizontal: (Boolean) -> Unit = {}
|
||||
var onRVertical: (Boolean) -> Unit = {}
|
||||
|
||||
var openKeyboard: (EditBox) -> Unit = {}
|
||||
val buttonGuides = mutableListOf<ButtonGuide>()
|
||||
var getVisual: (ResourceLocation) -> Component = { "".text() }
|
||||
|
||||
var onPress: (() -> Unit)? = null
|
||||
var onSpecial1: () -> Unit = { focused?.onSpecial1?.invoke() }
|
||||
var onSpecial2: () -> Unit = { focused?.onSpecial2?.invoke() }
|
||||
|
||||
fun left(): Boolean {
|
||||
if (focused == null && onNoneSelected.invoke()) return false
|
||||
focused?.left?.invoke()?.let {
|
||||
focused = it
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
fun right(): Boolean {
|
||||
if (focused == null && onNoneSelected.invoke()) return false
|
||||
focused?.right?.invoke()?.let {
|
||||
focused = it
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
fun up(): Boolean {
|
||||
if (focused == null && onNoneSelected.invoke()) return false
|
||||
focused?.up?.invoke()?.let {
|
||||
focused = it
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
fun down(): Boolean {
|
||||
if (focused == null && onNoneSelected.invoke()) return false
|
||||
focused?.down?.invoke()?.let {
|
||||
focused = it
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun press() {
|
||||
focused?.let {
|
||||
if (onPress != null) {
|
||||
onPress!!.invoke()
|
||||
} else {
|
||||
if (it.onPress != null) {
|
||||
it.onPress!!.invoke()
|
||||
} else {
|
||||
(it.associatedGUIElement as? Button)?.onPress()
|
||||
(it.associatedGUIElement as? Button)?.playDownSound(Minecraft.getInstance().soundManager)
|
||||
if (it.associatedGUIElement is EditBox) {
|
||||
openKeyboard.invoke(it.associatedGUIElement as EditBox)
|
||||
Minecraft.getInstance().soundManager.play(
|
||||
SimpleSoundInstance.forUI(
|
||||
SoundEvents.UI_BUTTON_CLICK,
|
||||
1.0F
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fun special1() = onSpecial1.invoke()
|
||||
fun special2() = onSpecial2.invoke()
|
||||
|
||||
private fun mainScreenManager(): Boolean {
|
||||
return screen is ControllerScreen && screen.getComponentManager() == this
|
||||
}
|
||||
|
||||
data class ButtonGuide(
|
||||
val type: ButtonGuideType,
|
||||
val condition: () -> Boolean,
|
||||
val text: Component,
|
||||
val rightAligned: Boolean = false
|
||||
)
|
||||
|
||||
enum class ButtonGuideType {
|
||||
PRESS,
|
||||
BACK,
|
||||
SPECIAL_1,
|
||||
SPECIAL_2,
|
||||
TAB,
|
||||
SECONDARY_TAB,
|
||||
START,
|
||||
JOYSTICK_HORIZONTAL,
|
||||
JOYSTICK_VERTICAL
|
||||
}
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.integration.controlify.gui.component
|
||||
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import net.minecraft.client.gui.components.AbstractWidget
|
||||
import org.joml.Vector4i
|
||||
|
||||
interface ControllerScreen {
|
||||
companion object {
|
||||
private val selectionTexture = cobblemonResource("textures/gui/common/selection_box.png")
|
||||
|
||||
const val BASE_SIZE = 3
|
||||
const val SHADOW_OFFSET = 1
|
||||
const val TOTAL_SIZE = BASE_SIZE + SHADOW_OFFSET
|
||||
}
|
||||
|
||||
fun getComponentManager(): ControllerComponentManager
|
||||
|
||||
fun getSelectionPosAndSize(): Vector4i? {
|
||||
val manager = getComponentManager()
|
||||
val focusedWidget = manager.screen.focused as? AbstractWidget ?: return null
|
||||
|
||||
return Vector4i(focusedWidget.x - 2, focusedWidget.y - 2, focusedWidget.width + 4, focusedWidget.height + 4)
|
||||
}
|
||||
|
||||
fun renderSelection(matrices: PoseStack) {
|
||||
if (!getComponentManager().active) return
|
||||
val positioningData = getSelectionPosAndSize() ?: return
|
||||
|
||||
val posX = positioningData.x
|
||||
val posY = positioningData.y
|
||||
|
||||
val width = positioningData.z
|
||||
val height = positioningData.w
|
||||
|
||||
blitk( //NW
|
||||
matrixStack = matrices,
|
||||
texture = selectionTexture,
|
||||
x = posX,
|
||||
y = posY,
|
||||
width = TOTAL_SIZE,
|
||||
height = TOTAL_SIZE,
|
||||
uOffset = 0,
|
||||
vOffset = 0,
|
||||
textureWidth = TOTAL_SIZE * 2,
|
||||
textureHeight = TOTAL_SIZE * 2
|
||||
)
|
||||
|
||||
blitk( //NE
|
||||
matrixStack = matrices,
|
||||
texture = selectionTexture,
|
||||
x = posX + width - BASE_SIZE,
|
||||
y = posY,
|
||||
width = TOTAL_SIZE,
|
||||
height = TOTAL_SIZE,
|
||||
uOffset = 4,
|
||||
vOffset = 0,
|
||||
textureWidth = TOTAL_SIZE * 2,
|
||||
textureHeight = TOTAL_SIZE * 2
|
||||
)
|
||||
|
||||
blitk( //SW
|
||||
matrixStack = matrices,
|
||||
texture = selectionTexture,
|
||||
x = posX,
|
||||
y = posY + height - BASE_SIZE,
|
||||
width = TOTAL_SIZE,
|
||||
height = TOTAL_SIZE,
|
||||
uOffset = 0,
|
||||
vOffset = 4,
|
||||
textureWidth = TOTAL_SIZE * 2,
|
||||
textureHeight = TOTAL_SIZE * 2
|
||||
)
|
||||
|
||||
blitk( //SE
|
||||
matrixStack = matrices,
|
||||
texture = selectionTexture,
|
||||
x = posX + width - BASE_SIZE,
|
||||
y = posY + height - BASE_SIZE,
|
||||
width = TOTAL_SIZE,
|
||||
height = TOTAL_SIZE,
|
||||
uOffset = 4,
|
||||
vOffset = 4,
|
||||
textureWidth = TOTAL_SIZE * 2,
|
||||
textureHeight = TOTAL_SIZE * 2
|
||||
)
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.integration.controlify.gui.component
|
||||
|
||||
class SubManagerComponent: ControllerComponent() {
|
||||
var subManager: () -> ControllerComponentManager? = { null }
|
||||
|
||||
init {
|
||||
left = { subManager.invoke()?.left(); null }
|
||||
right = { subManager.invoke()?.right(); null }
|
||||
up = { subManager.invoke()?.up(); null }
|
||||
down = { subManager.invoke()?.down(); null }
|
||||
|
||||
onPress = { subManager.invoke()?.press() }
|
||||
onSpecial1 = { subManager.invoke()?.special1() }
|
||||
onSpecial2 = { subManager.invoke()?.special2() }
|
||||
|
||||
onFocus = {
|
||||
subManager.invoke()?.active = true
|
||||
subManager.invoke()?.let { it.screen.focused = it.focused?.associatedGUIElement }
|
||||
subManager.invoke()?.focused?.onFocus?.invoke()
|
||||
}
|
||||
onUnfocus = {
|
||||
subManager.invoke()?.active = false
|
||||
subManager.invoke()?.focused?.onUnfocus?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-3
@@ -16,10 +16,8 @@ object SetClientPlayerDataHandler : ClientNetworkPacketHandler<SetClientPlayerDa
|
||||
override fun handle(packet: SetClientPlayerDataPacket, client: Minecraft) {
|
||||
if (packet.isIncremental) {
|
||||
packet.type.incrementalAfterDecodeAction.invoke(packet.playerData)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
packet.type.afterDecodeAction.invoke(packet.playerData)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user