forked from mirrors/cobblemon
Compare commits
26
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cdb37c70f6 | ||
|
|
e052947d7a | ||
|
|
8ee18f7da4 | ||
|
|
0ac418ec2c | ||
|
|
240804e201 | ||
|
|
d3e1f6be9d | ||
|
|
6d7760ce30 | ||
|
|
75e951191a | ||
|
|
2157e9c09e | ||
|
|
74ef1a61f9 | ||
|
|
23526824e8 | ||
|
|
859e586503 | ||
|
|
a9b6c07ac9 | ||
|
|
82548e0624 | ||
|
|
552a405e2e | ||
|
|
08918956db | ||
|
|
c139a1fea9 | ||
|
|
040ae26f22 | ||
|
|
4c9b4a4f1f | ||
|
|
7d34f83a8f | ||
|
|
8d89a37d93 | ||
|
|
65c5748c77 | ||
|
|
d4821c15bd | ||
|
|
c753ca54f1 | ||
|
|
ef581d1aa4 | ||
|
|
1f4224b029 |
+36
-72
@@ -1,94 +1,58 @@
|
||||
# Changelog
|
||||
## [1.7.2 (January 25th, 2026)](#1-7-2)
|
||||
## [1.7.4 (MONTH Xth, 2026)](#1-7-4)
|
||||
|
||||
### 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 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
|
||||
- Effect Cleanse: Removes all effects
|
||||
- Added more seasonings for sinister tea
|
||||
- Mental Herb - Mental Restoration I for 10 seconds
|
||||
- White Herb - Negative Effect Cleanse
|
||||
- Milk - Effect Cleanse
|
||||
- Moomoo Milk - Effect Cleanse
|
||||
- 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`.
|
||||
- Added config options to award experience to fainted Pokémon for opponents they helped defeat (`awardExperienceToFaintedPokemon`) and to still award experience for defeated enemies even after battle loss/forfeit (`awardExperienceOnBattleLoss`)
|
||||
- Party Overlay Exp Gained Animation will now display the amount of EXP the Pokémon gained
|
||||
- Added a toast to notify players of how they can scroll through their party. Did you know you can hold R and scroll instead of using arrow keys??!
|
||||
- Added new layer property that makes a layer scroll in a direction. "scrolling": {"speedU": 0.1, "speedV": 0.1}
|
||||
- Added missing crops to Botany Pots integration
|
||||
|
||||
### 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.
|
||||
## [1.7.3 (January 31st, 2026)](#1-7-3)
|
||||
- Restructured Botany Pots integration folder structure
|
||||
- Decrease default pastured mon wander radius to 32.
|
||||
- Factor in the weight of pokemon when calculating pushing forces between hitboxes.
|
||||
- Remade the Starter Selection Screen with new assets
|
||||
- Refactored berry trees to be less impactful on TPS (more performant)
|
||||
|
||||
### Fixes
|
||||
- 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.
|
||||
- Fixes https://gitlab.com/cable-mc/cobblemon/-/issues/1943
|
||||
- Fix occasional crash on retrieving revived fossils
|
||||
- Fixed a compatibility issue with World Game Rules which caused some log spam in specific cases.
|
||||
- Fixed improper validation of Pokémon when performing a trade.
|
||||
- Fixed issue where particle like beam can disappear when you don't see the beginning of the beam or you look away
|
||||
- Fixes https://gitlab.com/cable-mc/cobblemon/-/issues/1943
|
||||
- Fix occasional crash on retrieving revived fossils
|
||||
- Fix brushing not working on Neoforge
|
||||
- [Various Submarine Ride Fixes](https://gitlab.com/cable-mc/cobblemon/-/merge_requests/2157)
|
||||
- Fix Pastured mons despawning and running away.
|
||||
- Fix Apricorn trees crashing when other mods bonemeal it
|
||||
- [Various UFO Ride Improvements](https://gitlab.com/cable-mc/cobblemon/-/merge_requests/2156)
|
||||
- Fixed NeoForge brewing stand unexpectedly crashing users when shift clicking items within it's menu
|
||||
- Fixed NPCs switching pokemon very often during battles
|
||||
- Fixed Campfire pot causing crashes under certain circumstances
|
||||
- Fixed Type Gems not being consumed upon use
|
||||
- Fixed Ancient Pokeball's to their respective modifiers
|
||||
- Fixed a Server warning when recalling Pokemon
|
||||
|
||||
### Developer
|
||||
- Poké Ball GUI textures now respect the ball's namespace, enabling proper texture loading for custom balls from other mods.
|
||||
- Added `PokeSnackSpawnerFactory` which allows influence registration on PokeSnack encounters
|
||||
- Added `FishingSpawnerFactory` which allows influence registration on fishing encounters
|
||||
- Added `BattleFleeAttemptEvent` fired from `PokemonBattle.checkFleeAttempt`, allowing developers to intercept and control flee attempts
|
||||
|
||||
### Molang & Datapacks
|
||||
- Added a `chance` requirement type for Pokémon interactions.
|
||||
- q.item.is_enchanted()
|
||||
- q.item.has_enchantment(minecraft:sharpness, 3)
|
||||
- Added `has_chosen_starter` & `get_starter_uuid` as available Molang functions
|
||||
- Added `marks`, `has_mark`, & `remove_marks` as available Molang functions for pokemon
|
||||
|
||||
### Localization
|
||||
- Updated translations for:
|
||||
- French
|
||||
- Canadian French
|
||||
- Korean
|
||||
- Portuguese
|
||||
- Simplified Chinese
|
||||
- Spanish
|
||||
@@ -0,0 +1,22 @@
|
||||
# Changelog
|
||||
## [1.7.3 (January 31st, 2026)](#1-7-3)
|
||||
|
||||
### Fixes
|
||||
- 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
|
||||
- Poké Ball GUI textures now respect the ball's namespace, enabling proper texture loading for custom balls from other mods.
|
||||
|
||||
### Molang & Datapacks
|
||||
- Added a `chance` requirement type for Pokémon interactions.
|
||||
|
||||
### Localization
|
||||
- Updated translations for:
|
||||
- French
|
||||
- Canadian French
|
||||
- Korean
|
||||
- Portuguese
|
||||
- Simplified Chinese
|
||||
- Spanish
|
||||
+1
-10
@@ -32,10 +32,6 @@ 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()
|
||||
}
|
||||
|
||||
@@ -59,18 +55,13 @@ dependencies {
|
||||
// modCompileOnly(libs.flywheelFabric)
|
||||
|
||||
// Showdown
|
||||
modCompileOnly(libs.graal)
|
||||
modCompileOnly(libs.graal.core)
|
||||
|
||||
// Data Storage
|
||||
modCompileOnly(libs.bundles.mongo)
|
||||
|
||||
// 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> {
|
||||
|
||||
@@ -15,6 +15,8 @@ import com.cobblemon.mod.common.api.events.CobblemonEvents;
|
||||
import com.cobblemon.mod.common.api.events.item.LeftoversCreatedEvent;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies;
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle;
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.air.HoverBehaviour;
|
||||
import com.cobblemon.mod.common.api.storage.party.PartyStore;
|
||||
import com.cobblemon.mod.common.api.storage.party.PlayerPartyStore;
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags;
|
||||
@@ -59,6 +61,7 @@ import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@@ -169,6 +172,32 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
}
|
||||
}
|
||||
|
||||
@Redirect(
|
||||
method = "getDestroySpeed",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/entity/player/Player;onGround()Z"
|
||||
)
|
||||
)
|
||||
private boolean cobblemon$considerHoverOnGround(Player player) {
|
||||
// If riding a Hover Mount, return true to bypass the 5x slowdown
|
||||
if (player.getVehicle() instanceof PokemonEntity vehicle) {
|
||||
|
||||
var ridingController = vehicle.getRidingController();
|
||||
if (ridingController == null) player.onGround();
|
||||
|
||||
var activeContext = ridingController.getContext();
|
||||
if (activeContext == null) player.onGround();
|
||||
|
||||
if (activeContext.getStyle() == RidingStyle.AIR &&
|
||||
activeContext.getBehaviour().equals(HoverBehaviour.Companion.getKEY())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Otherwise, return the actual value
|
||||
return player.onGround();
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "eat",
|
||||
at = @At(
|
||||
|
||||
@@ -101,7 +101,7 @@ public abstract class ServerEntityMixin {
|
||||
cobblemon$broadcast(new ClientboundUpdateDriverInputPacket(driverInput, entity.getId()));
|
||||
}
|
||||
|
||||
private void cobblemon$broadcast(NetworkPacket<?> packet) {
|
||||
public void cobblemon$broadcast(NetworkPacket<?> packet) {
|
||||
if (!(entity.level() instanceof ServerLevel level)) return;
|
||||
ChunkMap chunkMap = level.getChunkSource().chunkMap;
|
||||
Int2ObjectMap<?> entityMap = ((ChunkMapAccessor) chunkMap).getEntityMap();
|
||||
|
||||
@@ -21,14 +21,12 @@ 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;
|
||||
@@ -37,6 +35,7 @@ import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import com.cobblemon.mod.common.client.gui.party.PartyTutorialToasts;
|
||||
|
||||
import static com.google.common.primitives.Floats.min;
|
||||
import static net.minecraft.util.Mth.lerp;
|
||||
@@ -87,11 +86,13 @@ public abstract class MouseHandlerMixin {
|
||||
CobblemonClient.INSTANCE.getStorage().shiftSelected(false);
|
||||
ci.cancel();
|
||||
PartySendBinding.INSTANCE.actioned();
|
||||
PartyTutorialToasts.INSTANCE.onHoldKeyScrollSwitchedSlot();
|
||||
} else if (i < 0) {
|
||||
accumulatedScrollY -= i;
|
||||
CobblemonClient.INSTANCE.getStorage().shiftSelected(true);
|
||||
ci.cancel();
|
||||
PartySendBinding.INSTANCE.actioned();
|
||||
PartyTutorialToasts.INSTANCE.onHoldKeyScrollSwitchedSlot();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -148,12 +149,6 @@ 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();
|
||||
@@ -318,7 +313,7 @@ public abstract class MouseHandlerMixin {
|
||||
var playerRotater = (RidePassenger)player;
|
||||
playerRotater.cobblemon$setRideXRot(playerRotater.cobblemon$getRideXRot() + f);
|
||||
playerRotater.cobblemon$setRideYRot(playerRotater.cobblemon$getRideYRot() + g);
|
||||
playerRotater.cobblemon$setRideXRot(Mth.clamp(playerRotater.cobblemon$getRideXRot(), -90.0F, 90.0F));
|
||||
playerRotater.cobblemon$setRideXRot(Mth.clamp(playerRotater.cobblemon$getRideXRot(), -89.0F, 89.0F));
|
||||
playerRotater.cobblemon$setRideYRot(Mth.clamp(playerRotater.cobblemon$getRideYRot(), -105.0F, 105.0F));
|
||||
if (player.getVehicle() != null) {
|
||||
player.getVehicle().onPassengerTurned(player);
|
||||
|
||||
@@ -14,9 +14,14 @@ import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import com.llamalad7.mixinextras.sugar.Share;
|
||||
import com.llamalad7.mixinextras.sugar.ref.LocalBooleanRef;
|
||||
import com.llamalad7.mixinextras.sugar.ref.LocalFloatRef;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
@@ -89,4 +94,61 @@ public abstract class EntityMixin {
|
||||
cir.setReturnValue(customEyePos);
|
||||
}
|
||||
|
||||
|
||||
@WrapOperation(
|
||||
method = "push(Lnet/minecraft/world/entity/Entity;)V",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;push(DDD)V", ordinal = 0)
|
||||
)
|
||||
public void cobblemon$customPusherLogic(Entity pusher, double x, double y, double z,
|
||||
Operation<Void> original,
|
||||
@Local(argsOnly = true) Entity pushee,
|
||||
@Local(name = "e") double e, @Local(name = "d") double d,
|
||||
@Share("pusherIsPlayerOrPokemon") LocalBooleanRef pusherIsPlayerOrPokemon,
|
||||
@Share("pusheeIsPlayerOrPokemon") LocalBooleanRef pusheeIsPlayerOrPokemon,
|
||||
@Share("pusheeReceivedForce")LocalFloatRef pusheeReceivedForce) {
|
||||
pusherIsPlayerOrPokemon.set(pusher instanceof PokemonEntity || pusher instanceof Player);
|
||||
pusheeIsPlayerOrPokemon.set(pushee instanceof PokemonEntity || pushee instanceof Player);
|
||||
|
||||
if (!pusheeIsPlayerOrPokemon.get() || !pusherIsPlayerOrPokemon.get()) {
|
||||
original.call(pusher, x, y, z);
|
||||
return;
|
||||
}
|
||||
|
||||
/**********************************************
|
||||
* Custom portion of the code:
|
||||
* Handle collisions with weight in mind. Use
|
||||
* the weight value of pokemon to determine
|
||||
* which side gets what portion of the total
|
||||
* force.
|
||||
*********************************************/
|
||||
// Weights in hectograms
|
||||
// Check to see if the pusher or pushee is a player. 200ish pounds. Steve's like a 6'6 miner
|
||||
var pusherWeight = pusher instanceof PokemonEntity pusherPokemon ? pusherPokemon.getPokemon().getSpecies().getWeight() : 900F;
|
||||
var pusheeWeight = pushee instanceof PokemonEntity pusheePokemon ? pusheePokemon.getPokemon().getSpecies().getWeight() : 900F;
|
||||
|
||||
// Calculate the portion of force received for both entities. Bigger receives less from the
|
||||
// collision than the smaller one.
|
||||
var totalWeight = pusherWeight + pusheeWeight;
|
||||
var pusherReceivedForce = pusheeWeight / totalWeight * 2F;
|
||||
pusheeReceivedForce.set((pusherWeight / totalWeight) * 2F);
|
||||
|
||||
original.call(pusher, -d * pusherReceivedForce, 0.0, -e * pusherReceivedForce);
|
||||
}
|
||||
|
||||
@WrapOperation(
|
||||
method = "push(Lnet/minecraft/world/entity/Entity;)V",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;push(DDD)V", ordinal = 1)
|
||||
)
|
||||
public void cobblemon$customPusheeLogic(Entity pusher, double x, double y, double z, Operation<Void> original,
|
||||
@Local(name = "e") double e, @Local(name = "d") double d,
|
||||
@Share("pusherIsPlayerOrPokemon") LocalBooleanRef pusherIsPlayerOrPokemon,
|
||||
@Share("pusheeIsPlayerOrPokemon") LocalBooleanRef pusheeIsPlayerOrPokemon,
|
||||
@Share("pusheeReceivedForce")LocalFloatRef pusheeReceivedForce) {
|
||||
if (!pusheeIsPlayerOrPokemon.get() || !pusherIsPlayerOrPokemon.get()) {
|
||||
original.call(pusher, x, y, z);
|
||||
return;
|
||||
}
|
||||
|
||||
original.call(pusher, d * pusheeReceivedForce.get(), 0.0, e * pusheeReceivedForce.get());
|
||||
}
|
||||
}
|
||||
|
||||
-53
@@ -1,53 +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.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);
|
||||
}
|
||||
}
|
||||
@@ -65,7 +65,11 @@ import com.cobblemon.mod.common.api.storage.player.adapter.PlayerDataMongoBacken
|
||||
import com.cobblemon.mod.common.api.storage.player.factory.CachedPlayerDataStoreFactory
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonEntityTypeTags
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||
import com.cobblemon.mod.common.battles.*
|
||||
import com.cobblemon.mod.common.battles.BagItems
|
||||
import com.cobblemon.mod.common.battles.BattleFormat
|
||||
import com.cobblemon.mod.common.battles.BattleRegistry
|
||||
import com.cobblemon.mod.common.battles.BattleSide
|
||||
import com.cobblemon.mod.common.battles.ShowdownThread
|
||||
import com.cobblemon.mod.common.battles.actor.PokemonBattleActor
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.block.dispenser.DispenserBehaviorRegistry
|
||||
@@ -76,7 +80,12 @@ import com.cobblemon.mod.common.config.LastChangedVersion
|
||||
import com.cobblemon.mod.common.config.constraint.IntConstraint
|
||||
import com.cobblemon.mod.common.config.starter.StarterConfig
|
||||
import com.cobblemon.mod.common.data.CobblemonDataProvider
|
||||
import com.cobblemon.mod.common.events.*
|
||||
import com.cobblemon.mod.common.events.AdvancementHandler
|
||||
import com.cobblemon.mod.common.events.CallbackHandler
|
||||
import com.cobblemon.mod.common.events.EntityCallbackHandler
|
||||
import com.cobblemon.mod.common.events.PokedexHandler
|
||||
import com.cobblemon.mod.common.events.ServerTickHandler
|
||||
import com.cobblemon.mod.common.events.StatHandler
|
||||
import com.cobblemon.mod.common.net.messages.client.settings.ServerSettingsPacket
|
||||
import com.cobblemon.mod.common.permission.LaxPermissionValidator
|
||||
import com.cobblemon.mod.common.platform.events.PlatformEvents
|
||||
@@ -90,11 +99,23 @@ import com.cobblemon.mod.common.pokemon.feature.SlowpokeTailRegrowthSpeciesFeatu
|
||||
import com.cobblemon.mod.common.pokemon.feature.SlowpokeTailRegrowthSpeciesFeatureProvider
|
||||
import com.cobblemon.mod.common.pokemon.feature.TagSeasonResolver
|
||||
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
|
||||
import com.cobblemon.mod.common.pokemon.properties.*
|
||||
import com.cobblemon.mod.common.pokemon.properties.AspectPropertyType
|
||||
import com.cobblemon.mod.common.pokemon.properties.BattleCloneProperty
|
||||
import com.cobblemon.mod.common.pokemon.properties.FreezeFrameProperty
|
||||
import com.cobblemon.mod.common.pokemon.properties.HiddenAbilityPropertyType
|
||||
import com.cobblemon.mod.common.pokemon.properties.LabelProperty
|
||||
import com.cobblemon.mod.common.pokemon.properties.NoAIProperty
|
||||
import com.cobblemon.mod.common.pokemon.properties.UnaspectPropertyType
|
||||
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
|
||||
import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
|
||||
import com.cobblemon.mod.common.starter.CobblemonStarterHandler
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.ifDedicatedServer
|
||||
import com.cobblemon.mod.common.util.isLaterVersion
|
||||
import com.cobblemon.mod.common.util.party
|
||||
import com.cobblemon.mod.common.util.requestWallpapers
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import com.cobblemon.mod.common.world.feature.CobblemonPlacedFeatures
|
||||
import com.cobblemon.mod.common.world.feature.ore.CobblemonOrePlacedFeatures
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
|
||||
@@ -102,6 +123,17 @@ import com.mongodb.ConnectionString
|
||||
import com.mongodb.MongoClientSettings
|
||||
import com.mongodb.client.MongoClient
|
||||
import com.mongodb.client.MongoClients
|
||||
import java.io.File
|
||||
import java.io.FileReader
|
||||
import java.io.FileWriter
|
||||
import java.io.PrintWriter
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.properties.Delegates
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.jvm.isAccessible
|
||||
import kotlin.reflect.jvm.javaField
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.commands.synchronization.SingletonArgumentInfo
|
||||
import net.minecraft.resources.ResourceKey
|
||||
@@ -114,17 +146,6 @@ import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.storage.LevelResource
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.apache.logging.log4j.Logger
|
||||
import java.io.File
|
||||
import java.io.FileReader
|
||||
import java.io.FileWriter
|
||||
import java.io.PrintWriter
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.properties.Delegates
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.jvm.isAccessible
|
||||
import kotlin.reflect.jvm.javaField
|
||||
|
||||
object Cobblemon {
|
||||
const val MODID = CobblemonBuildDetails.MOD_ID
|
||||
@@ -451,7 +472,7 @@ object Cobblemon {
|
||||
server()?.getLevel(dimension)
|
||||
} else {
|
||||
val mc = Minecraft.getInstance()
|
||||
return mc.singleplayerServer?.getLevel(dimension) ?: mc.level
|
||||
mc.singleplayerServer?.getLevel(dimension) ?: mc.level
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@ object CobblemonActivities {
|
||||
@JvmField
|
||||
val POKEMON_HERD = register(Activity("pokemon_herd"))
|
||||
@JvmField
|
||||
val POKEMON_BOIDS = register(Activity("pokemon_boid"))
|
||||
@JvmField
|
||||
val POKEMON_POLLINATION = register(Activity("pokemon_pollination"))
|
||||
|
||||
@JvmStatic
|
||||
|
||||
@@ -21,6 +21,7 @@ import net.minecraft.core.UUIDUtil
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import java.util.*
|
||||
import net.minecraft.world.entity.player.Player
|
||||
|
||||
object CobblemonMemories {
|
||||
val memories = mutableMapOf<String, MemoryModuleType<*>>()
|
||||
@@ -92,6 +93,9 @@ object CobblemonMemories {
|
||||
val DISABLE_WALK_TO_WANTED_ITEM = register<Boolean>("disable_walk_to_wanted_item")
|
||||
@JvmField
|
||||
val TIME_TRYING_TO_REACH_WANTED_ITEM = register<Int>("time_trying_to_wanted_item")
|
||||
/** Is the nearest player holding a diamond for debugging purposes? */
|
||||
@JvmField
|
||||
val DIAMOND_DEBUGGER = register<Player>("diamond_debugger")
|
||||
|
||||
@JvmStatic
|
||||
fun <U> register(id: String, codec: Codec<U>): MemoryModuleType<U> {
|
||||
|
||||
@@ -23,6 +23,7 @@ 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.RideSettingsSyncHandler
|
||||
import com.cobblemon.mod.common.client.net.debug.OpenRidingStatsDebugGUIHandler
|
||||
import com.cobblemon.mod.common.client.net.debug.S2CUpdateObsAvoidHandler
|
||||
import com.cobblemon.mod.common.client.net.dialogue.DialogueClosedHandler
|
||||
import com.cobblemon.mod.common.client.net.dialogue.DialogueOpenedHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.PokeSnackBlockParticlesHandler
|
||||
@@ -80,6 +81,7 @@ import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyMoveCallba
|
||||
import com.cobblemon.mod.common.net.messages.client.cooking.SeasoningRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.cooking.ToggleCookingPotLidPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.*
|
||||
import com.cobblemon.mod.common.net.messages.client.debug.ClientboundUpdateObsAvoidPacket
|
||||
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
|
||||
@@ -140,13 +142,7 @@ 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.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.*
|
||||
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
|
||||
@@ -189,6 +185,7 @@ import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateRide
|
||||
import com.cobblemon.mod.common.net.messages.server.starter.RequestStarterScreenPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.SwapPCPartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.party.MovePartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.party.PartyTutorialPacket
|
||||
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.*
|
||||
@@ -225,6 +222,7 @@ import com.cobblemon.mod.common.net.serverhandling.dialogue.InputToDialogueHandl
|
||||
import com.cobblemon.mod.common.net.serverhandling.evolution.AcceptEvolutionHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.npc.SaveNPCHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.orientation.ServerboundUpdateOrientationHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.party.PartyTutorialPacketHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pasture.PasturePokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pasture.SetPastureConflictHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pasture.UnpastureAllPokemonHandler
|
||||
@@ -257,7 +255,11 @@ 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.ServerLevel
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.entity.Entity
|
||||
import com.cobblemon.mod.common.mixin.accessor.ChunkMapAccessor
|
||||
import com.cobblemon.mod.common.mixin.accessor.TrackedEntityAccessor
|
||||
|
||||
/**
|
||||
* Registers Cobblemon network packets.
|
||||
@@ -280,6 +282,19 @@ object CobblemonNetwork {
|
||||
fun sendToAllPlayers(packet: NetworkPacket<*>) = sendPacketToPlayers(server()!!.playerList.players, packet)
|
||||
@JvmStatic
|
||||
fun sendPacketToPlayers(players: Iterable<ServerPlayer>, packet: NetworkPacket<*>) = players.forEach { sendPacketToPlayer(it, packet) }
|
||||
fun sendPacketToTrackingPlayers(entity: Entity, packet: NetworkPacket<*>) {
|
||||
val level = entity.level() as? ServerLevel ?: return
|
||||
|
||||
val chunkMap = level.chunkSource.chunkMap
|
||||
val entityTracker = (chunkMap as ChunkMapAccessor).entityMap[entity.id]
|
||||
|
||||
if (entityTracker is TrackedEntityAccessor) {
|
||||
entityTracker.seenBy.forEach { connection ->
|
||||
sendPacketToPlayer(connection.player, packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val s2cPayloads = generateS2CPacketInfoList()
|
||||
val c2sPayloads = generateC2SPacketInfoList()
|
||||
@@ -487,6 +502,7 @@ object CobblemonNetwork {
|
||||
|
||||
// Debug / cheats
|
||||
list.add(PacketRegisterInfo(CalculateSeatPositionsPacket.ID, CalculateSeatPositionsPacket::decode, CalculateSeatPositionsHandler))
|
||||
list.add(PacketRegisterInfo(ClientboundUpdateObsAvoidPacket.ID, ClientboundUpdateObsAvoidPacket::decode, S2CUpdateObsAvoidHandler))
|
||||
|
||||
// Riding
|
||||
list.add(PacketRegisterInfo(ClientboundUpdateRidingStatePacket.ID, ClientboundUpdateRidingStatePacket::decode, ClientboundUpdateRidingStateHandler))
|
||||
@@ -529,7 +545,7 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(ReleasePCPokemonPacket.ID, ReleasePCPokemonPacket::decode, ReleasePCPokemonHandler))
|
||||
list.add(PacketRegisterInfo(UnlinkPlayerFromPCPacket.ID, UnlinkPlayerFromPCPacket::decode, UnlinkPlayerFromPCHandler))
|
||||
|
||||
list.add(PacketRegisterInfo(RequestRenamePCBoxPacket.Companion.ID, RequestRenamePCBoxPacket.Companion::decode, RequestRenamePCBoxHandler))
|
||||
list.add(PacketRegisterInfo(RequestRenamePCBoxPacket.ID, RequestRenamePCBoxPacket::decode, RequestRenamePCBoxHandler))
|
||||
list.add(PacketRegisterInfo(PCBoxWallpapersPacket.ID, PCBoxWallpapersPacket::decode, PCBoxWallpapersHandler))
|
||||
list.add(PacketRegisterInfo(RequestChangePCBoxWallpaperPacket.ID, RequestChangePCBoxWallpaperPacket::decode, RequestChangePCBoxWallpaperHandler))
|
||||
list.add(PacketRegisterInfo(MarkPCBoxWallpapersSeenPacket.ID, MarkPCBoxWallpapersSeenPacket::decode, MarkPCBoxWallpapersSeenHandler))
|
||||
@@ -587,6 +603,9 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(PartyPokemonMoveSelectedPacket.ID, PartyPokemonMoveSelectedPacket::decode, PartyPokemonMoveSelectedHandler))
|
||||
list.add(PacketRegisterInfo(PartyMoveSelectCancelledPacket.ID, PartyMoveSelectCancelledPacket::decode, PartyMoveSelectCancelledHandler))
|
||||
|
||||
//Party move tutorial toasts packets
|
||||
list.add(PacketRegisterInfo(PartyTutorialPacket.ID, PartyTutorialPacket::decode, PartyTutorialPacketHandler))
|
||||
|
||||
// Dialogue packets
|
||||
list.add(PacketRegisterInfo(EscapeDialoguePacket.ID, EscapeDialoguePacket::decode, EscapeDialogueHandler))
|
||||
list.add(PacketRegisterInfo(InputToDialoguePacket.ID, InputToDialoguePacket::decode, InputToDialogueHandler))
|
||||
|
||||
@@ -49,6 +49,9 @@ object CobblemonSensors {
|
||||
@JvmField
|
||||
val NEARBY_SWEET_BERRY_BUSH = register("nearby_sweet_berry_bush", ::SweetBerryBushSensor)
|
||||
|
||||
@JvmField
|
||||
val PLAYER_DEBUGGING = register("player_debugging", ::PlayerDebuggingSensor)
|
||||
|
||||
@JvmField
|
||||
val POKEMON_NEARBY_WANTED_ITEM = register("pokemon_nearby_wanted_item", ::PokemonItemSensor)
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.CobblemonSensors
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.WakeUpTask
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class BoidsTaskConfig : SingleTaskConfig {
|
||||
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = emptyList<MoLangConfigVariable>()
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
if (entity !is PokemonEntity) {
|
||||
return null
|
||||
}
|
||||
behaviourConfigurationContext.addMemories(CobblemonMemories.POKEMON_DROWSY, CobblemonMemories.POKEMON_SLEEPING)
|
||||
behaviourConfigurationContext.addSensors(CobblemonSensors.POKEMON_DROWSY)
|
||||
return WrapperLivingEntityTask(WakeUpTask.create(), PokemonEntity::class.java)
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.BoidsMoveControl
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.PokemonMoveControl
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
|
||||
class SwitchFromBoidTaskConfig : SingleTaskConfig {
|
||||
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = emptyList<MoLangConfigVariable>()
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
behaviourConfigurationContext.addMemories(CobblemonMemories.DIAMOND_DEBUGGER)
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.absent(CobblemonMemories.DIAMOND_DEBUGGER)
|
||||
).apply(it) { _ ->
|
||||
Trigger { world, entity, time ->
|
||||
if(entity !is PokemonEntity) return@Trigger false
|
||||
if (entity.moveControl !is PokemonMoveControl) {
|
||||
entity.moveControl = PokemonMoveControl(entity)
|
||||
}
|
||||
entity.brain.updateActivityFromSchedule(world.dayTime, world.gameTime)
|
||||
return@Trigger true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonActivities
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.CobblemonSensors
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.BoidsMoveControl
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.player.Player
|
||||
|
||||
class SwitchToBoidTaskConfig : SingleTaskConfig {
|
||||
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = emptyList<MoLangConfigVariable>()
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
behaviourConfigurationContext.addMemories(CobblemonMemories.DIAMOND_DEBUGGER)
|
||||
behaviourConfigurationContext.addSensors(CobblemonSensors.PLAYER_DEBUGGING)
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.present(CobblemonMemories.DIAMOND_DEBUGGER)
|
||||
).apply(it) { _ ->
|
||||
Trigger { world, entity, time ->
|
||||
if(entity !is PokemonEntity) return@Trigger false
|
||||
val player = entity.brain.getMemory(CobblemonMemories.DIAMOND_DEBUGGER).orElse(null)
|
||||
if (entity.moveControl !is BoidsMoveControl && player is LivingEntity) {
|
||||
entity.moveControl = BoidsMoveControl(entity, player)
|
||||
} else {
|
||||
return@Trigger false
|
||||
}
|
||||
entity.brain.setActiveActivityIfPossible(CobblemonActivities.POKEMON_BOIDS)
|
||||
// SpawnSnowstormEntityParticlePacket(
|
||||
// cobblemonResource("evo_particles"),
|
||||
// entity.id,
|
||||
// listOf("shiny_particles", "middle")).sendToPlayersAround(
|
||||
// entity.x,
|
||||
// entity.y,
|
||||
// entity.z,
|
||||
// 64.0,
|
||||
// entity.level().dimension()
|
||||
// )
|
||||
return@Trigger true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -124,6 +124,8 @@ interface TaskConfig {
|
||||
cobblemonResource("target_entity") to TargetEntityTaskConfig::class.java,
|
||||
cobblemonResource("memory_aspect") to MemoryAspectTaskConfig::class.java,
|
||||
cobblemonResource("activity_change") to ActivityChangeTaskConfig::class.java,
|
||||
cobblemonResource("switch_from_boid") to SwitchFromBoidTaskConfig::class.java,
|
||||
cobblemonResource("switch_to_boid") to SwitchToBoidTaskConfig::class.java,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangV
|
||||
import com.cobblemon.mod.common.entity.OmniPathingEntity
|
||||
import com.cobblemon.mod.common.entity.ai.CobblemonRandomSurfacePos
|
||||
import com.cobblemon.mod.common.entity.ai.CobblemonWalkTarget
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.mainThreadRuntime
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
@@ -184,6 +185,12 @@ class WanderTaskConfig : SingleTaskConfig {
|
||||
|
||||
if (targetVec == null) continue
|
||||
|
||||
// Ignore pathing targets outside of the pasture zone if the pokemon is pastured.
|
||||
val tethering = (entity as? PokemonEntity)?.tethering
|
||||
if (tethering?.canRoamTo(BlockPos.containing(targetVec)) == false) {
|
||||
continue
|
||||
}
|
||||
|
||||
pos = applyHeightConstraints(
|
||||
pos = BlockPos.containing(targetVec),
|
||||
minimumHeight = minimumHeight,
|
||||
|
||||
@@ -22,18 +22,21 @@ import com.cobblemon.mod.common.api.battles.model.actor.EntityBackedBattleActor
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.FleeableBattleActor
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.battles.BattleFledEvent
|
||||
import com.cobblemon.mod.common.api.events.battles.BattleFleeAttemptEvent
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.BattleEvSource
|
||||
import com.cobblemon.mod.common.api.storage.party.PlayerPartyStore
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.api.text.white
|
||||
import com.cobblemon.mod.common.api.text.yellow
|
||||
import com.cobblemon.mod.common.battles.ActiveBattlePokemon
|
||||
import com.cobblemon.mod.common.battles.BattleCaptureAction
|
||||
import com.cobblemon.mod.common.battles.BattleFormat
|
||||
import com.cobblemon.mod.common.battles.BattleRegistry
|
||||
import com.cobblemon.mod.common.battles.BattleSide
|
||||
import com.cobblemon.mod.common.battles.FleeAttemptActionResponse
|
||||
import com.cobblemon.mod.common.battles.ForfeitActionResponse
|
||||
import com.cobblemon.mod.common.battles.actor.PlayerBattleActor
|
||||
import com.cobblemon.mod.common.battles.dispatch.BattleDispatch
|
||||
@@ -48,7 +51,9 @@ import com.cobblemon.mod.common.entity.npc.NPCBattleActor
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleEndPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleMakeChoicePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleMessagePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleQueueRequestPacket
|
||||
import com.cobblemon.mod.common.pokemon.evolution.progress.DefeatEvolutionProgress
|
||||
import com.cobblemon.mod.common.pokemon.evolution.progress.LastBattleCriticalHitsEvolutionProgress
|
||||
import com.cobblemon.mod.common.pokemon.requirements.DefeatRequirement
|
||||
@@ -137,6 +142,9 @@ open class PokemonBattle(
|
||||
val captureActions = mutableListOf<BattleCaptureAction>()
|
||||
|
||||
val majorBattleActions = hashMapOf<UUID, BattleMessage>()
|
||||
|
||||
/** Monotonically increasing counter to track faint ordering within this battle. */
|
||||
var faintCounter = 0
|
||||
val minorBattleActions = hashMapOf<UUID, BattleMessage>()
|
||||
val contextManager = ContextManager()
|
||||
|
||||
@@ -244,12 +252,23 @@ open class PokemonBattle(
|
||||
|
||||
fun end() {
|
||||
ended = true
|
||||
val awardToFainted = Cobblemon.config.awardExperienceToFaintedPokemon
|
||||
val awardOnLoss = Cobblemon.config.awardExperienceOnBattleLoss
|
||||
this.actors.forEach { actor ->
|
||||
val faintedPokemons = actor.pokemonList.filter { it.health <= 0 }
|
||||
actor.getSide().getOppositeSide().actors.forEach { opponent ->
|
||||
val opponentNonFaintedPokemons = opponent.pokemonList.filter { it.health > 0 }
|
||||
val opponentPokemons = if (awardToFainted) opponent.pokemonList else opponent.pokemonList.filter { it.health > 0 }
|
||||
faintedPokemons.forEach { faintedPokemon ->
|
||||
for (opponentPokemon in opponentNonFaintedPokemons) {
|
||||
for (opponentPokemon in opponentPokemons) {
|
||||
// Faint-order check: if awarding XP to fainted pokemon, only award for enemies that fainted before this pokemon did
|
||||
if (awardToFainted) {
|
||||
val enemyFaintedAt = faintedPokemon.faintedAt ?: continue
|
||||
val opponentFaintedAt = opponentPokemon.faintedAt
|
||||
if (opponentFaintedAt != null && opponentFaintedAt <= enemyFaintedAt) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
val facedFainted = opponentPokemon.facedOpponents.contains(faintedPokemon)
|
||||
val pokemon = opponentPokemon.effectedPokemon
|
||||
if (facedFainted) {
|
||||
@@ -270,7 +289,8 @@ open class PokemonBattle(
|
||||
else -> continue
|
||||
}
|
||||
val experience = Cobblemon.experienceCalculator.calculate(opponentPokemon, faintedPokemon, multiplier)
|
||||
if (experience > 0 && actor.pokemonList.all { it.health <= 0 }) {
|
||||
val enemyTeamWiped = actor.pokemonList.all { it.health <= 0 }
|
||||
if (experience > 0 && (enemyTeamWiped || awardOnLoss)) {
|
||||
opponent.awardExperience(opponentPokemon, experience)
|
||||
}
|
||||
Cobblemon.evYieldCalculator.calculate(opponentPokemon, faintedPokemon).forEach { (stat, amount) ->
|
||||
@@ -505,6 +525,7 @@ open class PokemonBattle(
|
||||
|
||||
fun checkForInputDispatch() {
|
||||
if (checkForfeit()) return // ignore actors that are still choosing, their choices don't matter anymore
|
||||
if (checkFleeAttempt()) return
|
||||
val readyToInput = (actors.any { !it.mustChoose && it.responses.isNotEmpty() } && actors.none { it.mustChoose })
|
||||
if (readyToInput && captureActions.isEmpty()) {
|
||||
actors.filter { it.responses.isNotEmpty() }.forEach { it.writeShowdownResponse() }
|
||||
@@ -512,6 +533,20 @@ open class PokemonBattle(
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkFleeAttempt(): Boolean {
|
||||
val runner = actors.find { it.responses.any { it is FleeAttemptActionResponse } } as? PlayerBattleActor ?: return false
|
||||
CobblemonEvents.BATTLE_FLEE_ATTEMPT.post(BattleFleeAttemptEvent(this, runner))
|
||||
runner.responses.clear()
|
||||
|
||||
runner.mustChoose = true
|
||||
runner.request?.let { runner.sendUpdate(BattleQueueRequestPacket(it)) }
|
||||
runner.sendUpdate(BattleMakeChoicePacket())
|
||||
|
||||
runner.entity?.sendSystemMessage(battleLang("run_prompt").white())
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/** Forces Showdown to end the battle when a [BattleActor] chooses to forfeit. */
|
||||
private fun checkForfeit(): Boolean {
|
||||
val forfeit = actors.find { it.responses.any { it is ForfeitActionResponse } }
|
||||
|
||||
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.api.events
|
||||
|
||||
import com.cobblemon.mod.common.api.events.battles.BattleFaintedEvent
|
||||
import com.cobblemon.mod.common.api.events.battles.BattleFledEvent
|
||||
import com.cobblemon.mod.common.api.events.battles.BattleFleeAttemptEvent
|
||||
import com.cobblemon.mod.common.api.events.battles.BattleStartedEvent
|
||||
import com.cobblemon.mod.common.api.events.battles.BattleVictoryEvent
|
||||
import com.cobblemon.mod.common.api.events.battles.instruction.FormeChangeEvent
|
||||
@@ -110,6 +111,9 @@ object CobblemonEvents {
|
||||
@JvmField
|
||||
val BATTLE_STARTED_POST = EventObservable<BattleStartedEvent.Post>()
|
||||
|
||||
@JvmField
|
||||
val BATTLE_FLEE_ATTEMPT = EventObservable<BattleFleeAttemptEvent>()
|
||||
|
||||
@JvmField
|
||||
val BATTLE_FLED = EventObservable<BattleFledEvent>()
|
||||
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.events.battles
|
||||
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
|
||||
import com.cobblemon.mod.common.battles.actor.PlayerBattleActor
|
||||
import com.cobblemon.mod.common.util.asArrayValue
|
||||
|
||||
/**
|
||||
* Event fired when a [PokemonBattle] is fled by a [PlayerBattleActor].
|
||||
*
|
||||
* @author saultsc
|
||||
* @since March 31th 2026
|
||||
*/
|
||||
|
||||
data class BattleFleeAttemptEvent(
|
||||
override val battle: PokemonBattle,
|
||||
val player: PlayerBattleActor
|
||||
) : BattleEvent {
|
||||
val context = mutableMapOf<String, MoValue>(
|
||||
"battle" to battle.struct,
|
||||
"players" to battle.actors.filter { it.type == ActorType.PLAYER }.asArrayValue { it.struct },
|
||||
"npcs" to battle.actors.filter { it.type == ActorType.NPC }.asArrayValue { it.struct },
|
||||
"wild_pokemon" to battle.actors.filter { it.type == ActorType.WILD }.asArrayValue { it.struct }
|
||||
)
|
||||
}
|
||||
@@ -145,6 +145,7 @@ import net.minecraft.world.entity.item.ItemEntity
|
||||
import net.minecraft.world.entity.monster.Monster
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.enchantment.EnchantmentHelper
|
||||
import net.minecraft.world.level.ClipContext
|
||||
import net.minecraft.world.level.GameType
|
||||
import net.minecraft.world.level.Level
|
||||
@@ -871,6 +872,8 @@ object MoLangFunctions {
|
||||
|
||||
DoubleValue(value)
|
||||
}
|
||||
map.put("get_starter_uuid") { _ -> Cobblemon.playerDataManager.getGenericData(player).starterUUID?.let{ StringValue(it.toString()) } ?: DoubleValue.ZERO }
|
||||
map.put("has_chosen_starter") { _ -> DoubleValue(Cobblemon.playerDataManager.getGenericData(player).starterSelected) }
|
||||
}
|
||||
map
|
||||
}
|
||||
@@ -891,6 +894,15 @@ object MoLangFunctions {
|
||||
map.put("is_of") { params -> DoubleValue(holder.`is`(params.getString(0).asIdentifierDefaultingNamespace())) }
|
||||
map.put("is_in") { params -> DoubleValue(holder.`is`(TagKey.create(Registries.ITEM, params.getString(0).replace("#", "").asIdentifierDefaultingNamespace()))) }
|
||||
map.put("is_food") { params -> DoubleValue(stack.has(DataComponents.FOOD)) }
|
||||
map.put("is_enchanted") { params -> DoubleValue(stack.hasFoil()) }
|
||||
map.put("has_enchantment") { params ->
|
||||
val enchantmentId = params.getString(0).asIdentifierDefaultingNamespace()
|
||||
val minLevel = params.getIntOrNull(1) ?: 1
|
||||
val enchantmentRegistry = registryAccess.registryOrThrow(Registries.ENCHANTMENT)
|
||||
val holder = enchantmentRegistry.getHolder(enchantmentId).orElse(null) ?: return@put DoubleValue.ZERO
|
||||
val level = EnchantmentHelper.getItemEnchantmentLevel(holder, stack)
|
||||
return@put DoubleValue(level >= minLevel)
|
||||
}
|
||||
return@mutableListOf map
|
||||
}
|
||||
)
|
||||
@@ -1830,6 +1842,30 @@ object MoLangFunctions {
|
||||
map.put("remove_cosmetic_item") { _ ->
|
||||
pokemon.removeCosmeticItem()
|
||||
}
|
||||
map.put("marks") { _ -> pokemon.marks.asArrayValue { StringValue(it.identifier.toString()) } }
|
||||
map.put("has_mark") { params ->
|
||||
var hasMark = false
|
||||
val identifier = params.getString(0).asIdentifierDefaultingNamespace()
|
||||
val mark = Marks.getByIdentifier(identifier)
|
||||
if (mark != null) {
|
||||
hasMark = pokemon.marks.contains(mark)
|
||||
}
|
||||
|
||||
DoubleValue(hasMark)
|
||||
}
|
||||
map.put("remove_marks") { params ->
|
||||
var removedMark = false
|
||||
for (param in params.params) {
|
||||
val identifier = param.asString().asIdentifierDefaultingNamespace()
|
||||
val mark = Marks.getByIdentifier(identifier)
|
||||
if (mark != null) {
|
||||
pokemon.exchangeMark(mark, false)
|
||||
removedMark = true
|
||||
}
|
||||
}
|
||||
|
||||
DoubleValue(removedMark)
|
||||
}
|
||||
map.put("add_marks") { params ->
|
||||
var appliedMark = false
|
||||
for (param in params.params) {
|
||||
@@ -2023,9 +2059,13 @@ object MoLangFunctions {
|
||||
}
|
||||
}
|
||||
map.put("is_sprinting") {
|
||||
pokemonEntity.ifRidingAvailableSupply(DoubleValue.ZERO) { behaviour, settings, state ->
|
||||
val moValue = behaviour.asMoLangValue(settings, state, pokemonEntity)
|
||||
return@ifRidingAvailableSupply moValue.functions.get("sprinting")?.apply(MoParams.EMPTY) as? MoValue ?: DoubleValue.ZERO
|
||||
if (pokemonEntity.hasControllingPassenger()) { // If its being ridden then the riding state sets the animation
|
||||
pokemonEntity.ifRidingAvailableSupply(DoubleValue.ZERO) { behaviour, settings, state ->
|
||||
val moValue = behaviour.asMoLangValue(settings, state, pokemonEntity)
|
||||
return@ifRidingAvailableSupply moValue.functions.get("sprinting")?.apply(MoParams.EMPTY) as? MoValue ?: DoubleValue.ZERO
|
||||
}
|
||||
} else {
|
||||
pokemonEntity.isPokemonSprinting
|
||||
}
|
||||
}
|
||||
map.put("is_drifting") {
|
||||
@@ -2815,8 +2855,8 @@ object MoLangFunctions {
|
||||
}
|
||||
variable
|
||||
}
|
||||
else -> null
|
||||
} ?: throw IllegalArgumentException("Invalid NBT element type: ${nbt.type}")
|
||||
else -> VariableStruct()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -289,11 +289,11 @@ object PokeBalls : JsonDataRegistry<PokeBall> {
|
||||
createDefault("ancient_great_ball", MultiplierModifier(1.5F), ancient = true)
|
||||
createDefault("ancient_ultra_ball", MultiplierModifier(2F), ancient = true)
|
||||
createDefault("ancient_heavy_ball", throwPower = 0.75f, ancient = true)
|
||||
createDefault("ancient_leaden_ball", throwPower = 0.75f, ancient = true)
|
||||
createDefault("ancient_gigaton_ball", throwPower = 0.75f, ancient = true)
|
||||
createDefault("ancient_leaden_ball", MultiplierModifier(1.5F), throwPower = 0.75f, ancient = true)
|
||||
createDefault("ancient_gigaton_ball", MultiplierModifier(2F), throwPower = 0.75f, ancient = true)
|
||||
createDefault("ancient_feather_ball", throwPower = 2.5f, ancient = true)
|
||||
createDefault("ancient_wing_ball", throwPower = 2.5f, ancient = true)
|
||||
createDefault("ancient_jet_ball", throwPower = 2.5f, ancient = true)
|
||||
createDefault("ancient_wing_ball", MultiplierModifier(1.5F), throwPower = 2.5f, ancient = true)
|
||||
createDefault("ancient_jet_ball", MultiplierModifier(2F), throwPower = 2.5f, ancient = true)
|
||||
createDefault("ancient_origin_ball", GuaranteedModifier(), ancient = true)
|
||||
// Luxury ball effect, low priority as it must be triggered before soothe bell as of gen 4
|
||||
CobblemonEvents.FRIENDSHIP_UPDATED.subscribe(priority = Priority.LOW) { event ->
|
||||
|
||||
@@ -314,11 +314,11 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
val result = mutableMapOf<String, String>()
|
||||
this.species.forEach {species ->
|
||||
val baseSpecies = ShowdownSpecies(species, null)
|
||||
result[ShowdownIdentifiable.REGEX.replace(baseSpecies.name, "")] = this.gson.toJson(baseSpecies)
|
||||
result[ShowdownIdentifiable.REGEX.replace(baseSpecies.name.lowercase(), "")] = this.gson.toJson(baseSpecies)
|
||||
species.forms.forEach { form ->
|
||||
if (form != species.standardForm) {
|
||||
val formSpecies = ShowdownSpecies(species, form)
|
||||
result[ShowdownIdentifiable.REGEX.replace(formSpecies.name, "")] = this.gson.toJson(formSpecies)
|
||||
result[ShowdownIdentifiable.REGEX.replace(formSpecies.name.lowercase(), "")] = this.gson.toJson(formSpecies)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-1
@@ -119,7 +119,10 @@ class RidingController(
|
||||
private fun canTransitionToLand(): Boolean {
|
||||
if ((entity.isUnderWater)) return false
|
||||
if ((entity.isEyeInFluid(FluidTags.WATER) || entity.isEyeInFluid(FluidTags.LAVA))) return false
|
||||
return entity.onGround()
|
||||
// If the currently in the air but has no land style then don't transition and render the ride useless.
|
||||
// Hover is a good example for this.
|
||||
val shouldStayInAir = entity.pokemon.riding.behaviours?.get(RidingStyle.LAND) == null && context?.style == RidingStyle.AIR
|
||||
return entity.onGround() && !shouldStayInAir
|
||||
}
|
||||
|
||||
private fun canTransitionToLiquid(): Boolean {
|
||||
|
||||
+15
-2
@@ -213,10 +213,23 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
|
||||
val accel = topSpeed / (vehicle.runtime.resolveDouble(settings.accelerationExpr ?: globalHover.accelerationExpr!!) * 20.0)
|
||||
|
||||
var newVelocity = state.rideVelocity.get()
|
||||
val unrotateVel = vehicle.deltaMovement.yRot(vehicle.yRot)
|
||||
|
||||
val vehicleFrontVec = Vec3(0.0, 0.0, 1.0)
|
||||
val faceVel = Vec3(vehicle.deltaMovement.x, 0.0, vehicle.deltaMovement.z)
|
||||
|
||||
val d = vehicle.deltaMovement.horizontalDistance()
|
||||
val v2 = Vec3(faceVel.dot(Vec3(1.0, 0.0, 0.0)) * d, newVelocity.y, faceVel.dot(Vec3(0.0, 0.0, 1.0)) * d)
|
||||
|
||||
// Check for collisions and if found, update the speed to reflect it
|
||||
if (vehicle.verticalCollision || vehicle.horizontalCollision) {
|
||||
state.speed.set(vehicle.deltaMovement.length())
|
||||
if (vehicle.horizontalCollision) {
|
||||
val smackingIntoWallSpeed = max( vehicle.deltaMovement.horizontalDistance(), 0.2)
|
||||
newVelocity = Vec3(newVelocity.x, 0.0, newVelocity.z).normalize().scale(smackingIntoWallSpeed).add(0.0, newVelocity.y, 0.0)
|
||||
}
|
||||
|
||||
|
||||
if (vehicle.verticalCollision) {
|
||||
newVelocity = Vec3(newVelocity.x, 0.0, newVelocity.z)
|
||||
}
|
||||
|
||||
// align the velocity vector to be in local vehicle space
|
||||
|
||||
+6
-8
@@ -22,7 +22,6 @@ 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
|
||||
@@ -145,12 +144,11 @@ 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() && forward && !state.sprinting.get() && state.sprintTickTimer.get() == 0) {
|
||||
if (!state.forwardHeldLastTick.get() && Minecraft.getInstance().options.keyUp.isDown() && !state.sprinting.get() && state.sprintTickTimer.get() == 0) {
|
||||
state.sprintTickTimer.set(sprintTimerTickLength)
|
||||
} else if (!state.forwardHeldLastTick.get() && forward && state.sprintTickTimer.get() != 0) { // If has double tapped
|
||||
} else if (!state.forwardHeldLastTick.get() && Minecraft.getInstance().options.keyUp.isDown() && 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)
|
||||
@@ -158,9 +156,9 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
|
||||
state.sprintTickTimer.set(0)
|
||||
}
|
||||
|
||||
val tryingToSprint = hasDoubleTapped || CobblemonClient.ridingSprintHandler.any { it.value.invoke() }
|
||||
val tryingToSprint = (Minecraft.getInstance().options.keySprint.isDown() && Minecraft.getInstance().options.keyUp.isDown()) || hasDoubleTapped
|
||||
|
||||
if (state.stamina.get() <= 0.0f || !forward) {
|
||||
if (state.stamina.get() <= 0.0f || !Minecraft.getInstance().options.keyUp.isDown()) {
|
||||
// If stamina runs out or the player is not holding forward then stop sprinting
|
||||
state.sprinting.set(false)
|
||||
if (state.stamina.get() <= 0.0f) {
|
||||
@@ -174,8 +172,8 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
|
||||
state.sprinting.set(true)
|
||||
}
|
||||
|
||||
// Take note of whether forward was held last tick
|
||||
state.forwardHeldLastTick.set(forward)
|
||||
// Take not of whether forward was held last tick
|
||||
state.forwardHeldLastTick.set(Minecraft.getInstance().options.keyUp.isDown())
|
||||
}
|
||||
|
||||
fun tickStamina(
|
||||
|
||||
+26
-83
@@ -60,7 +60,7 @@ class SubmarineBehaviour : RidingBehaviour<SubmarineSettings, SubmarineState> {
|
||||
val poseProvider = PoseProvider<SubmarineSettings, SubmarineState>(PoseType.FLOAT)
|
||||
.with(PoseOption(PoseType.SWIM) { _, state, entity -> state.rideVelocity.get().z > 0.05 && !state.onSurface.get()})
|
||||
.with(PoseOption(PoseType.STAND) { _, state, entity -> state.rideVelocity.get().z <= 0.05 && state.onSurface.get()})
|
||||
.with(PoseOption(PoseType.STAND) { _, state, entity -> state.rideVelocity.get().z > 0.05 && state.onSurface.get()})
|
||||
.with(PoseOption(PoseType.SWIM) { _, state, entity -> state.rideVelocity.get().z > 0.05 && state.onSurface.get()})
|
||||
|
||||
override fun isActive(settings: SubmarineSettings, state: SubmarineState, vehicle: PokemonEntity): Boolean {
|
||||
return vehicle.isInWater || !vehicle.onGround()
|
||||
@@ -191,11 +191,17 @@ class SubmarineBehaviour : RidingBehaviour<SubmarineSettings, SubmarineState> {
|
||||
* Calculate Forward Velocity
|
||||
*********************************************/
|
||||
val currZVel = state.rideVelocity.get().z
|
||||
val newZVel = when {
|
||||
var newZVel = when {
|
||||
driver.zza > 0.0 -> min(topSpeed, currZVel + accel)
|
||||
driver.zza < 0.0 -> max( -strafeSpeed, currZVel - strafeAccel) //TODO: Might need to be applied in addition to the normal braking force?
|
||||
else -> lerp(currZVel, 0.0, 0.05)
|
||||
driver.zza < 0.0 -> max( -strafeSpeed, currZVel - strafeAccel)
|
||||
else -> lerp(currZVel, 0.0, 0.02)
|
||||
}
|
||||
|
||||
// If trying to brake then add the friction to the braking force
|
||||
if (driver.zza != 0.0f && driver.zza.sign.toDouble() != newZVel.sign) {
|
||||
newZVel = lerp(newZVel, 0.0, 0.02)
|
||||
}
|
||||
|
||||
currVel = Vec3(currVel.x, currVel.y, newZVel)
|
||||
|
||||
/*********************************************
|
||||
@@ -206,14 +212,20 @@ class SubmarineBehaviour : RidingBehaviour<SubmarineSettings, SubmarineState> {
|
||||
val gravity = (9.8 / ( 20.0)) * 0.2 * 0.4
|
||||
val terminalYVel = 2.0
|
||||
val driverYInput = if(driver.jumping) 1.0 else if (driver.isShiftKeyDown) -1.0 else 0.0
|
||||
val newYVel = when {
|
||||
var newYVel = when {
|
||||
(!vehicle.isInWater) -> max(-terminalYVel, currYVel - gravity)
|
||||
//(vehicle.isInWater && !vehicle.isUnderWater && currYVel > 0.001) -> lerp(currYVel, 0.0, 0.1) // Make sure that yVel is above a threshold before doing this otherwise it'll block submerging.
|
||||
//driverYInput != 0.0 && currYVel > 0.001 && driverYInput.sign != currYVel.sign -> lerp(currYVel, 0.0, 0.05)
|
||||
driverYInput > 0.0 -> min(vertTopSpeed, currYVel + strafeAccel)
|
||||
driverYInput < 0.0 -> max(-vertTopSpeed, currYVel - strafeAccel)
|
||||
else -> lerp(currYVel, 0.0, 0.05)
|
||||
else -> lerp(currYVel, 0.0, 0.02)
|
||||
}
|
||||
|
||||
// If trying to brake then add the friction to the braking force
|
||||
if (driverYInput != 0.0 && driverYInput != newYVel.sign) {
|
||||
newYVel = lerp(newYVel, 0.0, 0.02)
|
||||
}
|
||||
|
||||
currVel = Vec3(currVel.x, newYVel, currVel.z)
|
||||
|
||||
/*********************************************
|
||||
@@ -221,11 +233,17 @@ class SubmarineBehaviour : RidingBehaviour<SubmarineSettings, SubmarineState> {
|
||||
*********************************************/
|
||||
val currXVel = state.rideVelocity.get().x
|
||||
val horzTopSpeed = strafeSpeed
|
||||
val newXVel = when {
|
||||
var newXVel = when {
|
||||
driver.xxa > 0.0 -> min(horzTopSpeed, currXVel + strafeAccel)
|
||||
driver.xxa < 0.0 -> max( -horzTopSpeed, currXVel - strafeAccel)
|
||||
else -> lerp(currXVel, 0.0, 0.01)
|
||||
else -> lerp(currXVel, 0.0, 0.02)
|
||||
}
|
||||
|
||||
// If trying to brake then add the friction to the braking force
|
||||
if (driver.xxa != 0.0f && driver.xxa.sign.toDouble() != newZVel.sign) {
|
||||
newXVel = lerp(newXVel, 0.0, 0.02)
|
||||
}
|
||||
|
||||
currVel = Vec3(newXVel, currVel.y, currVel.z)
|
||||
|
||||
// Set the new velocity
|
||||
@@ -305,81 +323,6 @@ class SubmarineBehaviour : RidingBehaviour<SubmarineSettings, SubmarineState> {
|
||||
|
||||
}
|
||||
|
||||
private fun correctOrientation(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity,
|
||||
controller: OrientationController,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
) {
|
||||
|
||||
// TODO: remove if not needed
|
||||
|
||||
// // Calculate correcting roll force.
|
||||
// // If the ride is moving then have the correction rate be an equal proportion of:
|
||||
// // - how rolled are you
|
||||
// // - how long has it been since last mouse input (higher is stronger correction)
|
||||
// // Also the correction is proportional as a whole to how NOT pitched are you so you don't spin endlessly when looking up or down
|
||||
// val howRolledAmI = sqrt(abs((cos(controller.roll.toRadians()) - 1.0f) * 0.5f)) // sqrt so it trends towards one pretty quickly
|
||||
// val maxRollCorrectionRate =
|
||||
// if (state.rideVelocity.get().length() < 0.2) 10.0f * abs(cos(controller.pitch.toRadians()))
|
||||
// else 10.0f * cos(controller.pitch.toRadians()).pow(2) * (
|
||||
// howRolledAmI*1.0f +
|
||||
// (state.noInputTime.get() - rollCorrectionTimer).coerceIn(0.0, 1.0).pow(2).toFloat()*0.5f
|
||||
// )
|
||||
// val maxRollForce = maxRollCorrectionRate / 40.0f
|
||||
// val rollArrivalDeg = 60.0f
|
||||
// val desiredRoll = 0.0f
|
||||
//
|
||||
// // Calculate the signed error (how far and in what direction)
|
||||
// val rollError = Mth.wrapDegrees(desiredRoll.angleDifference(controller.roll))
|
||||
//
|
||||
// // Use the absolute error to calculate the magnitude of the influence
|
||||
// val influenceMagnitude = (min(rollArrivalDeg, abs(rollError)) / rollArrivalDeg)
|
||||
// val desiredRollForce = maxRollCorrectionRate * influenceMagnitude * -rollError.sign
|
||||
// var steeredRollForce = desiredRollForce - state.currRollCorrectionForce.get()
|
||||
//
|
||||
// // Ensure the 'steering' correction force doesn't exceed our maxForce
|
||||
// if (abs(steeredRollForce) > maxRollForce) {
|
||||
// steeredRollForce = steeredRollForce.sign * maxRollForce
|
||||
// }
|
||||
//
|
||||
// // Apply the 'steered' force (its really not a steering force I need a better name)
|
||||
// state.currRollCorrectionForce.set(
|
||||
// state.currRollCorrectionForce.get() + steeredRollForce
|
||||
// )
|
||||
|
||||
//Calculate correcting pitch force.
|
||||
// val rollCorrectionTimer = vehicle.runtime.resolveDouble(settings.timeToRollCorrect ?: globalSubmarine.timeToRollCorrect!!)
|
||||
// val maxPitchCorrectionRate = 5.0f * (state.noInputTime.get() - rollCorrectionTimer).coerceIn(0.0, 1.0).pow(2).toFloat()*0.5f
|
||||
// val maxPitchForce = maxPitchCorrectionRate / 40.0f
|
||||
// val pitchArrivalDeg = 45.0f
|
||||
// val desiredPitch = 0.0f
|
||||
//
|
||||
// if(state.rideVelocity.get().length() < 0.1 && state.noInputTime.get() > rollCorrectionTimer) {
|
||||
// val pitchErrror = Mth.wrapDegrees(desiredPitch.angleDifference(controller.pitch))
|
||||
// val arrivalInfluence = (min(pitchArrivalDeg,abs(pitchErrror)) / pitchArrivalDeg)
|
||||
// val desiredPitchForce = maxPitchCorrectionRate * arrivalInfluence * -pitchErrror.sign
|
||||
// var steeredPitchForce = desiredPitchForce - state.currPitchCorrectionForce.get()
|
||||
//
|
||||
// // Ensure the 'steering' correction force doesn't exceed our maxForce
|
||||
// if (abs(steeredPitchForce) > maxPitchForce) {
|
||||
// steeredPitchForce = steeredPitchForce.sign * maxPitchForce
|
||||
// }
|
||||
//
|
||||
// // Apply the 'steered' force (its really not a steering force I need a better name)
|
||||
// state.currPitchCorrectionForce.set(
|
||||
// state.currPitchCorrectionForce.get() + steeredPitchForce
|
||||
// )
|
||||
// } else {
|
||||
// state.currPitchCorrectionForce.set(
|
||||
// //reduce rollCorrection gradually
|
||||
// lerp(state.currPitchCorrectionForce.get(), 0.0, deltaTime * 0.98)
|
||||
// )
|
||||
// }
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
|
||||
+9
-9
@@ -54,8 +54,6 @@ class RidingAnimationData(val ride: PokemonEntity)
|
||||
fun update() {
|
||||
val activeRide = ride.hasControllingPassenger()
|
||||
|
||||
if (!activeRide) return
|
||||
|
||||
var currRot = Vec3.ZERO
|
||||
var angDelta = Vec3.ZERO
|
||||
|
||||
@@ -153,14 +151,16 @@ class RidingAnimationData(val ride: PokemonEntity)
|
||||
/******************************************************
|
||||
* Update springs
|
||||
*****************************************************/
|
||||
val driver = ride.controllingPassenger
|
||||
val vertInput = when {
|
||||
driver != null && driver.jumping-> 1.0
|
||||
driver != null && driver.isShiftKeyDown -> -1.0
|
||||
else -> 0.0
|
||||
if (activeRide) {
|
||||
val driver = ride.controllingPassenger
|
||||
val vertInput = when {
|
||||
driver != null && driver.jumping-> 1.0
|
||||
driver != null && driver.isShiftKeyDown -> -1.0
|
||||
else -> 0.0
|
||||
}
|
||||
val input = if(driver != null) Vec3(driver.xxa.toDouble() * -1, vertInput, driver.zza.toDouble()) else Vec3.ZERO
|
||||
driverInputSpring.update(input, stiffness * 2, damping)
|
||||
}
|
||||
val input = if(driver != null) Vec3(driver.xxa.toDouble() * -1, vertInput, driver.zza.toDouble()) else Vec3.ZERO
|
||||
driverInputSpring.update(input, stiffness * 2, damping)
|
||||
rotDeltaSpring.update(angDelta, stiffness, damping)
|
||||
velocitySpring.update(currentVelocity, stiffness, damping)
|
||||
rotSpring.update(currRot, stiffness, damping)
|
||||
|
||||
@@ -44,6 +44,7 @@ import com.cobblemon.mod.common.api.spawning.preset.BestSpawnerConfig
|
||||
import com.cobblemon.mod.common.api.spawning.preset.PokemonSpawnDetailPreset
|
||||
import com.cobblemon.mod.common.api.spawning.selection.SpawningSelector
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.BasicSpawner
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.FishingSpawnerFactory
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.FixedAreaSpawner
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawner
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawnerFactory
|
||||
@@ -139,19 +140,6 @@ object BestSpawner {
|
||||
|
||||
fun onServerStarted(server: MinecraftServer) {
|
||||
CobblemonSpawnPools.onServerLoad(server)
|
||||
fishingSpawner = BasicSpawner(
|
||||
name = "fishing",
|
||||
spawnPool = CobblemonSpawnPools.WORLD_SPAWN_POOL
|
||||
).also {
|
||||
it.influences.add(
|
||||
BucketMultiplyingInfluence(
|
||||
multipliers = mapOf(
|
||||
"uncommon" to 2.25f,
|
||||
"rare" to 5.5f,
|
||||
"ultra-rare" to 5.5f,
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
fishingSpawner = FishingSpawnerFactory.createSharedSpawner()
|
||||
}
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.spawner
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnPools
|
||||
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnRules
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
|
||||
import com.cobblemon.mod.common.api.spawning.influence.BucketMultiplyingInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.influence.BucketNormalizingInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.influence.PlayerLevelRangeInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.influence.PlayerLevelRangeInfluence.Companion.TYPICAL_VARIATION
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
||||
import com.cobblemon.mod.common.util.mutableLazy
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import com.cobblemon.mod.common.api.spawning.BestSpawner;
|
||||
import com.cobblemon.mod.common.api.spawning.position.FishingSpawnablePosition
|
||||
|
||||
|
||||
/**
|
||||
* This isn't really a factory, one FishingSpawner is created as a field on [BestSpawner] on
|
||||
* server start. However, this emulates the systems that PlayerSpawner uses so extenders can
|
||||
* add influences that affect all fishing encounters.
|
||||
*
|
||||
* Responsible for creating [BasicSpawner]s for Fishing with whatever appropriate settings.
|
||||
* You can swap over the spawn pool and the influences here, and it will apply to all newly-generated
|
||||
* [BasicSpawner]s for Fishing. Has a global every-cast influence list, as well as a context-sensitive
|
||||
* influence list.
|
||||
*
|
||||
* @author Andy
|
||||
* @since January 23rd, 2026
|
||||
*/
|
||||
object FishingSpawnerFactory {
|
||||
var spawnPool: SpawnPool by mutableLazy {
|
||||
CobblemonSpawnPools.WORLD_SPAWN_POOL
|
||||
}
|
||||
|
||||
data class Context(
|
||||
val player: ServerPlayer,
|
||||
val rodStack: ItemStack,
|
||||
val lureLevel: Int,
|
||||
val luckOfTheSeaLevel: Int,
|
||||
val world: ServerLevel,
|
||||
val pos: BlockPos,
|
||||
val spawner: BasicSpawner
|
||||
)
|
||||
|
||||
/**
|
||||
* List of influences for a new cast of the fishing rod. Context is provided at
|
||||
* build time in [buildPositionInfluences]
|
||||
*/
|
||||
var positionInfluenceBuilders = mutableListOf<(ctx: Context) -> SpawningInfluence?>(
|
||||
{ ctx -> PlayerLevelRangeInfluence(ctx.player, TYPICAL_VARIATION) },
|
||||
{ ctx -> BucketNormalizingInfluence(tier = ctx.lureLevel + ctx.luckOfTheSeaLevel) }
|
||||
)
|
||||
|
||||
fun createSharedSpawner(): BasicSpawner {
|
||||
return BasicSpawner(
|
||||
name = "fishing",
|
||||
spawnPool = spawnPool
|
||||
).also { spawner ->
|
||||
spawner.influences += BucketMultiplyingInfluence(
|
||||
multipliers = mapOf(
|
||||
"uncommon" to 2.25f,
|
||||
"rare" to 5.5f,
|
||||
"ultra-rare" to 5.5f,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the per-cast influences for [FishingSpawnablePosition]
|
||||
*/
|
||||
fun buildPositionInfluences(ctx: Context): MutableList<SpawningInfluence> {
|
||||
return positionInfluenceBuilders.mapNotNullTo(mutableListOf()) { it(ctx) }
|
||||
}
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.spawner
|
||||
|
||||
import com.cobblemon.mod.common.api.fishing.SpawnBait
|
||||
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnPools
|
||||
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnRules
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
|
||||
import com.cobblemon.mod.common.api.spawning.influence.BucketMultiplyingInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.influence.BucketNormalizingInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawnBaitInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.rules.SpawnRule
|
||||
import com.cobblemon.mod.common.util.mutableLazy
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
|
||||
/**
|
||||
* Responsible for creating [FixedAreaSpawner]s for PokeSnacks with whatever appropriate settings.
|
||||
* You can swap over the spawn pool and the influences here, and it will apply to all newly-generated
|
||||
* [FixedAreaSpawner]s for PokeSnacks.
|
||||
*
|
||||
* @author Andy
|
||||
* @since January 23rd, 2026
|
||||
*/
|
||||
object PokeSnackSpawnerFactory {
|
||||
var spawnPool: SpawnPool by mutableLazy {
|
||||
CobblemonSpawnPools.WORLD_SPAWN_POOL
|
||||
}
|
||||
|
||||
data class Context(
|
||||
val world: ServerLevel,
|
||||
val pos: BlockPos,
|
||||
val horizontalRadius: Int,
|
||||
val verticalRadius: Int,
|
||||
val maxPokemonPerChunk: Float,
|
||||
val name: String,
|
||||
val baitEffects: List<SpawnBait.Effect>
|
||||
)
|
||||
|
||||
/**
|
||||
* The list of influences for a new [FixedAreaSpawner] for a PokeSnack.
|
||||
* The influences will be added to the spawner in the order they are added to this list.
|
||||
*/
|
||||
var influenceBuilders = mutableListOf<(ctx: Context) -> SpawningInfluence?>(
|
||||
{ ctx ->
|
||||
val stackedLureTier = ctx.baitEffects
|
||||
.filter { it.type == SpawnBait.Effects.RARITY_BUCKET }
|
||||
.sumOf { it.value }
|
||||
.toInt()
|
||||
|
||||
if (stackedLureTier <= 0) null else BucketNormalizingInfluence(
|
||||
tier = stackedLureTier,
|
||||
gradient = 0.2F,
|
||||
firstTier = 1.2F
|
||||
)
|
||||
},
|
||||
{ _ ->
|
||||
BucketMultiplyingInfluence(
|
||||
mapOf(
|
||||
"uncommon" to 2.25f,
|
||||
"rare" to 5.5f,
|
||||
"ultra-rare" to 5.5f,
|
||||
)
|
||||
)
|
||||
},
|
||||
{ ctx ->
|
||||
SpawnBaitInfluence(effects = ctx.baitEffects)
|
||||
},
|
||||
)
|
||||
|
||||
fun create(ctx: Context): FixedAreaSpawner {
|
||||
val influences = influenceBuilders.mapNotNull { it(ctx) }
|
||||
|
||||
return FixedAreaSpawner(
|
||||
name = ctx.name,
|
||||
spawnPool = spawnPool,
|
||||
world = ctx.world,
|
||||
position = ctx.pos,
|
||||
horizontalRadius = ctx.horizontalRadius,
|
||||
verticalRadius = ctx.verticalRadius,
|
||||
maxPokemonPerChunk = ctx.maxPokemonPerChunk
|
||||
).also { spawner ->
|
||||
spawner.influences.addAll(influences)
|
||||
|
||||
// TODO(Andy): PokeSnacks currently bypass pokemon spawn rules, should that be true?
|
||||
// Adding this rule will change that
|
||||
spawner.influences.addAll(
|
||||
CobblemonSpawnRules.rules.values
|
||||
.filter(SpawnRule::enabled)
|
||||
.flatMap(SpawnRule::components)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -28,6 +28,7 @@ data class GeneralPlayerData(
|
||||
var starterUUID: UUID?,
|
||||
var keyItems: MutableSet<ResourceLocation>,
|
||||
var battleTheme: ResourceLocation?,
|
||||
var partySelectTutorialDone: Boolean = false,
|
||||
val extraData: MutableMap<String, PlayerDataExtension>,
|
||||
) : InstancedPlayerData {
|
||||
var advancementData: PlayerAdvancementData = PlayerAdvancementData()
|
||||
@@ -53,7 +54,8 @@ data class GeneralPlayerData(
|
||||
starterSelected,
|
||||
starterUUID,
|
||||
advancementData.totalBattleVictoryCount == 0,
|
||||
battleTheme
|
||||
battleTheme,
|
||||
partySelectTutorialDone
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -36,7 +36,8 @@ class PlayerDataJsonBackend: JsonBackedPlayerDataStoreBackend<GeneralPlayerData>
|
||||
starterUUID = null,
|
||||
keyItems = Cobblemon.config.defaultKeyItems,
|
||||
extraData = mutableMapOf(),
|
||||
battleTheme = CobblemonSounds.PVP_BATTLE.location
|
||||
battleTheme = CobblemonSounds.PVP_BATTLE.location,
|
||||
partySelectTutorialDone = false
|
||||
)}
|
||||
|
||||
override val gson = GsonBuilder()
|
||||
|
||||
+2
-1
@@ -37,7 +37,8 @@ class PlayerDataMongoBackend(mongoClient: MongoClient, databaseName: String, col
|
||||
starterUUID = null,
|
||||
keyItems = Cobblemon.config.defaultKeyItems,
|
||||
extraData = mutableMapOf(),
|
||||
battleTheme = CobblemonSounds.PVP_BATTLE.location
|
||||
battleTheme = CobblemonSounds.PVP_BATTLE.location,
|
||||
partySelectTutorialDone = false
|
||||
)}
|
||||
|
||||
override val gson = GsonBuilder()
|
||||
|
||||
+6
-2
@@ -34,7 +34,8 @@ data class ClientGeneralPlayerData(
|
||||
var starterSelected: Boolean = false,
|
||||
var starterUUID: UUID? = null,
|
||||
var showChallengeLabel: Boolean = true,
|
||||
val battleTheme: ResourceLocation? = null
|
||||
val battleTheme: ResourceLocation? = null,
|
||||
var partySelectTutorialDone: Boolean = false
|
||||
) : ClientInstancedPlayerData {
|
||||
|
||||
override fun encode(buf: RegistryFriendlyByteBuf) {
|
||||
@@ -46,6 +47,7 @@ data class ClientGeneralPlayerData(
|
||||
buf.writeNullable(starterUUID) { pb, value -> pb.writeString(value.toString()) }
|
||||
buf.writeNullable(resetStarters) { pb, value -> pb.writeBoolean(value) }
|
||||
buf.writeNullable(battleTheme) {pb, value -> pb.writeIdentifier(value)}
|
||||
buf.writeBoolean(partySelectTutorialDone)
|
||||
}
|
||||
companion object {
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): SetClientPlayerDataPacket {
|
||||
@@ -57,6 +59,7 @@ data class ClientGeneralPlayerData(
|
||||
val starterUUID = buffer.readNullable { it.readString() }?.let { UUID.fromString(it) }
|
||||
val resetStarterPrompt = buffer.readNullable { it.readBoolean() }
|
||||
val battleTheme = buffer.readNullable { it.readIdentifier() }
|
||||
val partySelectTutorialDone = buffer.readBoolean()
|
||||
val data = ClientGeneralPlayerData(
|
||||
resetStarterPrompt,
|
||||
promptStarter,
|
||||
@@ -64,7 +67,8 @@ data class ClientGeneralPlayerData(
|
||||
starterSelected,
|
||||
starterUUID,
|
||||
showChallengeLabel,
|
||||
battleTheme
|
||||
battleTheme,
|
||||
partySelectTutorialDone
|
||||
)
|
||||
//Weird to do this, but since the flag doesn't get passed to the decoded obj, do it here
|
||||
//Should be fine, as long as decode doesn't get run on the server for some reason
|
||||
|
||||
@@ -94,7 +94,8 @@ enum class ShowdownActionResponseType(val loader: (RegistryFriendlyByteBuf) -> S
|
||||
PASS({ PassActionResponse }),
|
||||
SHIFT({ ShiftActionResponse()}),
|
||||
HEAL_ITEM({ HealItemActionResponse("potion") }),
|
||||
FORFEIT({ ForfeitActionResponse() });
|
||||
FORFEIT({ ForfeitActionResponse() }),
|
||||
FLEE_ATTEMPT({ FleeAttemptActionResponse() }),
|
||||
}
|
||||
|
||||
abstract class ShowdownActionResponse(val type: ShowdownActionResponseType) {
|
||||
@@ -280,6 +281,11 @@ class ForfeitActionResponse : ShowdownActionResponse(ShowdownActionResponseType.
|
||||
override fun toShowdownString(activeBattlePokemon: ActiveBattlePokemon, showdownMoveSet: ShowdownMoveset?) = "forfeit"
|
||||
}
|
||||
|
||||
class FleeAttemptActionResponse : ShowdownActionResponse(ShowdownActionResponseType.FLEE_ATTEMPT) {
|
||||
override fun isValid(activeBattlePokemon: ActiveBattlePokemon, showdownMoveSet: ShowdownMoveset?, forceSwitch: Boolean) = true
|
||||
override fun toShowdownString(activeBattlePokemon: ActiveBattlePokemon, showdownMoveSet: ShowdownMoveset?) = "flee-attempt"
|
||||
}
|
||||
|
||||
class ShowdownMoveset {
|
||||
lateinit var moves: List<InBattleMove>
|
||||
var trapped = false
|
||||
|
||||
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.battles
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.battles.runner.ShowdownService
|
||||
import net.minecraft.CrashReport
|
||||
import java.util.*
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
||||
@@ -37,8 +38,15 @@ class ShowdownThread : Thread("Cobblemon Showdown") {
|
||||
|
||||
override fun run() {
|
||||
LOGGER.info("Starting showdown service...")
|
||||
ShowdownService.service.openConnection()
|
||||
LOGGER.info("Showdown has been started!")
|
||||
this.latch.countDown()
|
||||
try {
|
||||
ShowdownService.service.openConnection()
|
||||
LOGGER.info("Showdown has been started!")
|
||||
} catch (e: Exception) {
|
||||
LOGGER.error("Failed to start showdown service!", e)
|
||||
} finally {
|
||||
this.latch.countDown()
|
||||
throw RuntimeException("Showdown service failed to initialize...")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,6 @@ import kotlin.collections.associateWith
|
||||
import kotlin.collections.partition
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
|
||||
/**
|
||||
* AI that tries to choose the best move for the given situations. Based off of the Pokemon Trainer Tournament Simulator Github
|
||||
* https://github.com/cRz-Shadows/Pokemon_Trainer_Tournament_Simulator/blob/main/pokemon-showdown/sim/examples/Simulation-test-1.ts#L330
|
||||
@@ -49,7 +48,7 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
private val hpWeightConsideration = 0.25 // how much HP difference is a consideration for switchins
|
||||
private val hpFractionCoefficient = 0.4 // how much HP differences should be taken into account for switch ins
|
||||
private val boostWeightCoefficient = 1 // the amount of boosts considered a baseline to be removed
|
||||
private val switchOutMatchupThreshold = 0 // todo change this to get it feeling just right (-7 never switches)
|
||||
private val switchOutMatchupThreshold = -2 // todo change this to get it feeling just right (-7 never switches)
|
||||
private val selfKoMoveMatchupThreshold = 0.3
|
||||
private val trickRoomThreshold = 85
|
||||
private val recoveryMoveThreshold = 0.50
|
||||
@@ -219,19 +218,14 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
.filter { it.second.canBeSentOut() }
|
||||
|
||||
if (forceSwitch || activeBattlePokemon.isGone()) {
|
||||
if (battle.turn == 1) {
|
||||
val switchTo = activeBattlePokemon.actor.pokemonList.filter { it.canBeSentOut() }.randomOrNull()
|
||||
?: return DefaultActionResponse()
|
||||
switchTo.willBeSwitchedIn = true
|
||||
return SwitchActionResponse(switchTo.uuid)
|
||||
}
|
||||
else {
|
||||
val bestEstimation = availableSwitches.maxByOrNull { estimateMatchup(activeBattlePokemon, aiSide, battle, it.first) }
|
||||
?: return PassActionResponse
|
||||
// When forced to switch, pick the Pokemon with the best matchup estimation
|
||||
val bestSwitchScore = availableSwitches.maxOfOrNull { estimateMatchup(activeBattlePokemon, aiSide, battle, it.first) }
|
||||
?: return PassActionResponse
|
||||
val bestSwitch = availableSwitches.firstOrNull { estimateMatchup(activeBattlePokemon, aiSide, battle, it.first) == bestSwitchScore }
|
||||
?: return PassActionResponse
|
||||
|
||||
bestEstimation.second.willBeSwitchedIn = true
|
||||
return SwitchActionResponse(bestEstimation.second.uuid)
|
||||
}
|
||||
bestSwitch.second.willBeSwitchedIn = true
|
||||
return SwitchActionResponse(bestSwitch.second.uuid)
|
||||
}
|
||||
if (moveset == null) {
|
||||
return PassActionResponse
|
||||
@@ -259,9 +253,9 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
|
||||
if (!checkSkillLevel()){
|
||||
val move = availableMoves
|
||||
.filter { it.first.target.targetList(activeBattlePokemon)?.isEmpty() != true }
|
||||
.randomOrNull()
|
||||
?: return MoveActionResponse("struggle")
|
||||
.filter { it.first.target.targetList(activeBattlePokemon)?.isEmpty() != true }
|
||||
.randomOrNull()
|
||||
?: return MoveActionResponse("struggle")
|
||||
|
||||
return chooseMove(move.first, activeBattlePokemon)
|
||||
}
|
||||
@@ -270,7 +264,6 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
if (checkSwitchOutSkill() && shouldSwitchOut(aiSide, battle, activeBattlePokemon, moveset)) {
|
||||
considerSwitching(activeBattlePokemon, activeTrackerPokemon, opponents, availableMoves, availableSwitches, battle, aiSide)
|
||||
}
|
||||
activeTrackerPokemon.firstTurn = false
|
||||
|
||||
// If HP is below 30% and not switching out, always use the most damaging move
|
||||
if (activeTrackerPokemon.currentHpPercent < 0.3 && !shouldSwitchOut(aiSide, battle, activeBattlePokemon, moveset)) {
|
||||
@@ -296,8 +289,6 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
return chooseMove(fakeOut.first, activeBattlePokemon, targets.firstOrNull { validTarget != null && validTarget.id == it.battlePokemon!!.uuid})
|
||||
}
|
||||
|
||||
activeTrackerPokemon.firstTurn = false
|
||||
|
||||
|
||||
// Explosion/Self destruct
|
||||
availableMoves.firstOrNull {
|
||||
@@ -315,7 +306,7 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
|
||||
// Deal with non-weather related field changing effects
|
||||
for (move in availableMoves) {
|
||||
|
||||
|
||||
// Tailwind
|
||||
if (move.first.id == "tailwind" && move.first.id != activeTracker.alliedSide.tailwindCondition &&
|
||||
availableSwitches.size > 2) {
|
||||
@@ -324,21 +315,21 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
|
||||
// Trick room
|
||||
if (move.first.id == "trickroom" && move.first.id != activeTracker.currentRoom
|
||||
&& availableSwitches.count { statEstimationActive(it.first, Stats.SPEED) <= trickRoomThreshold } >= 2) {
|
||||
&& availableSwitches.count { statEstimationActive(it.first, Stats.SPEED) <= trickRoomThreshold } >= 2) {
|
||||
return chooseMove(move.first, activeBattlePokemon)
|
||||
}
|
||||
|
||||
// todo find a way to get list of active screens
|
||||
// Aurora veil
|
||||
if (move.first.id == "auroraveil" && move.first.id != activeTracker.alliedSide.screenCondition
|
||||
&& activeTracker.currentWeather in listOf("hail", "snow")) {
|
||||
&& activeTracker.currentWeather in listOf("hail", "snow")) {
|
||||
return chooseMove(move.first, activeBattlePokemon)
|
||||
}
|
||||
|
||||
// todo find a way to get list of active screens
|
||||
// Light Screen
|
||||
if (move.first.id == "lightscreen" && move.first.id != activeTracker.alliedSide.screenCondition
|
||||
&& opponents.any { (it.species?.baseStats?.get(Stats.SPECIAL_ATTACK) ?: 0) > (it.species?.baseStats?.get(Stats.ATTACK) ?: 0) }
|
||||
&& opponents.any { (it.species?.baseStats?.get(Stats.SPECIAL_ATTACK) ?: 0) > (it.species?.baseStats?.get(Stats.ATTACK) ?: 0) }
|
||||
&& availableSwitches.size > 1) {
|
||||
return chooseMove(move.first, activeBattlePokemon)
|
||||
}
|
||||
@@ -356,13 +347,13 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
for (move in availableMoves) {
|
||||
// Setup
|
||||
if (nOppRemainingMons >= 3 && move.first.id in AIUtility.entryHazards
|
||||
&& !activeTracker.opponentSide.sideHazards.contains(move.first.id)) {
|
||||
&& !activeTracker.opponentSide.sideHazards.contains(move.first.id)) {
|
||||
return chooseMove(move.first, activeBattlePokemon)
|
||||
}
|
||||
|
||||
// Removal
|
||||
if (nRemainingMons >= 2 && move.first.id in AIUtility.antiHazardsMoves
|
||||
&& activeTracker.alliedSide.sideHazards.isNotEmpty()) {
|
||||
&& activeTracker.alliedSide.sideHazards.isNotEmpty()) {
|
||||
return chooseMove(move.first, activeBattlePokemon)
|
||||
}
|
||||
}
|
||||
@@ -372,10 +363,10 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
// Court Change
|
||||
for (move in availableMoves) {
|
||||
if (move.first.id == "courtchange"
|
||||
&& (!AIUtility.entryHazards.none { it in activeTracker.alliedSide.sideHazards }
|
||||
|| setOf("tailwind", "lightscreen", "reflect").any { it in activeTracker.opponentSide.sideHazards })
|
||||
&& setOf("tailwind", "lightscreen", "reflect").none { it in activeTracker.opponentSide.sideHazards }
|
||||
&& AIUtility.entryHazards.none { it in activeTracker.opponentSide.sideHazards }) {
|
||||
&& (!AIUtility.entryHazards.none { it in activeTracker.alliedSide.sideHazards }
|
||||
|| setOf("tailwind", "lightscreen", "reflect").any { it in activeTracker.opponentSide.sideHazards })
|
||||
&& setOf("tailwind", "lightscreen", "reflect").none { it in activeTracker.opponentSide.sideHazards }
|
||||
&& AIUtility.entryHazards.none { it in activeTracker.opponentSide.sideHazards }) {
|
||||
return chooseMove(move.first, activeBattlePokemon)
|
||||
}
|
||||
}
|
||||
@@ -383,7 +374,7 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
// Strength Sap
|
||||
for (move in availableMoves) {
|
||||
if (move.first.id == "strengthsap" && activeTrackerPokemon.currentHpPercent < 0.5
|
||||
&& activeTrackerPokemon.species!!.baseStats.getOrDefault(Stats.ATTACK, 0) > 80) {
|
||||
&& activeTrackerPokemon.species!!.baseStats.getOrDefault(Stats.ATTACK, 0) > 80) {
|
||||
return chooseMove(move.first, activeBattlePokemon)
|
||||
}
|
||||
}
|
||||
@@ -391,10 +382,10 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
// Belly Drum
|
||||
for (move in availableMoves) {
|
||||
if (move.first.id == "bellydrum"
|
||||
&& (activeTrackerPokemon.currentHpPercent > 0.6
|
||||
&& activeTrackerPokemon.pokemon!!.heldItem().item == CobblemonItems.SITRUS_BERRY
|
||||
|| activeTrackerPokemon.currentHpPercent > 0.8)
|
||||
&& activeTrackerPokemon.boosts.getOrDefault(Stats.ATTACK, 0) < 1) {
|
||||
&& (activeTrackerPokemon.currentHpPercent > 0.6
|
||||
&& activeTrackerPokemon.pokemon!!.heldItem().item == CobblemonItems.SITRUS_BERRY
|
||||
|| activeTrackerPokemon.currentHpPercent > 0.8)
|
||||
&& activeTrackerPokemon.boosts.getOrDefault(Stats.ATTACK, 0) < 1) {
|
||||
return chooseMove(move.first, activeBattlePokemon)
|
||||
}
|
||||
}
|
||||
@@ -404,8 +395,8 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
for (move in availableMoves) {
|
||||
AIUtility.weatherSetupMoves[move.first.id]?.let { requiredWeather ->
|
||||
if (activeTracker.currentWeather != requiredWeather.lowercase() &&
|
||||
!(activeTracker.currentWeather == "primordialsea" && requiredWeather == "raindance") &&
|
||||
!(activeTracker.currentWeather == "desolateland" && requiredWeather == "sunnyday")) {
|
||||
!(activeTracker.currentWeather == "primordialsea" && requiredWeather == "raindance") &&
|
||||
!(activeTracker.currentWeather == "desolateland" && requiredWeather == "sunnyday")) {
|
||||
return chooseMove(move.first, activeBattlePokemon)
|
||||
}
|
||||
}
|
||||
@@ -431,8 +422,8 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
// Stall out side conditions
|
||||
if ((activeTracker.opponentSide.screenCondition != null || activeTracker.opponentSide.tailwindCondition != null) &&
|
||||
(activeTracker.alliedSide.screenCondition == null || activeTracker.alliedSide.tailwindCondition == null) ||
|
||||
opponents.any { it.currentStatus == null } &&
|
||||
activeTrackerPokemon.protectCount == 0 && opponents.none { it.currentAbility?.name == "unseenfist"}) {
|
||||
opponents.any { it.currentStatus == null } &&
|
||||
activeTrackerPokemon.protectCount == 0 && opponents.none { it.currentAbility?.name == "unseenfist"}) {
|
||||
activeTrackerPokemon.protectCount = 3
|
||||
return chooseMove(move.first, activeBattlePokemon)
|
||||
}
|
||||
@@ -460,10 +451,10 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
activeTrackerPokemon.firstTurn = false
|
||||
|
||||
val move = availableMoves
|
||||
.filter { it.first.canBeUsed() }
|
||||
.filter { it.first.mustBeUsed() || it.first.target.targetList(activeBattlePokemon)?.isEmpty() != true }
|
||||
.randomOrNull()
|
||||
?: return MoveActionResponse("struggle")
|
||||
.filter { it.first.canBeUsed() }
|
||||
.filter { it.first.mustBeUsed() || it.first.target.targetList(activeBattlePokemon)?.isEmpty() != true }
|
||||
.randomOrNull()
|
||||
?: return MoveActionResponse("struggle")
|
||||
|
||||
return chooseMove(move.first, activeBattlePokemon)
|
||||
}
|
||||
@@ -520,6 +511,10 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
return false
|
||||
|
||||
val activeTrackerPokemon = activeTracker.alliedSide.activePokemon.first { it.id == activeBattlePokemon.battlePokemon!!.uuid }
|
||||
|
||||
// Don't switch out if we just switched in
|
||||
if (activeTrackerPokemon.firstTurn)
|
||||
return false
|
||||
val actorTracker = activeTracker.alliedSide.actors.first { activeTrackerPokemon in it.activePokemon }
|
||||
val availableSwitches = actorTracker.party.filter { it.currentHp!! > 0 }
|
||||
val currentAbility = activeTrackerPokemon.pokemon!!.ability
|
||||
@@ -532,7 +527,7 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
// Only switch if a switch-in is significantly better than the current Pokémon
|
||||
val currentScore = estimateMatchup(activeBattlePokemon, side, battle)
|
||||
val bestSwitchScore = availableSwitches.maxOfOrNull { estimateMatchup(activeBattlePokemon, side, battle, it) } ?: currentScore
|
||||
val improvementThreshold = currentScore.absoluteValue * 0.25 + 2
|
||||
val improvementThreshold = currentScore.absoluteValue * 0.5 + 3
|
||||
if (bestSwitchScore <= currentScore + improvementThreshold) {
|
||||
return false
|
||||
}
|
||||
@@ -567,7 +562,7 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
if (availableSwitches.isEmpty() || availableSwitches.none { estimateMatchup(activeBattlePokemon, side, battle, it) > 0 })
|
||||
return false
|
||||
|
||||
|
||||
|
||||
|
||||
// ...and a 'good' reason to switch out
|
||||
if (opponentActiveTracker.any { it.boosts.getOrDefault(Stats.ACCURACY, 0) <= accuracySwitchThreshold } ||
|
||||
@@ -995,6 +990,4 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
return MoveActionResponse(move.id, chosenTarget.getPNX())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+2
@@ -132,6 +132,7 @@ class TrackerActor(val uuid: UUID) {
|
||||
actor.activePokemon.filter { newActive -> activePokemon.none { it.id == newActive.battlePokemon?.uuid } }.forEach {
|
||||
val active = party.firstOrNull { trackMon -> trackMon.id == it.battlePokemon?.uuid } ?: return@forEach
|
||||
party.remove(active)
|
||||
active.firstTurn = true // Reset firstTurn when switching in
|
||||
activePokemon.add(active)
|
||||
}
|
||||
val swappedOut = activePokemon.filter { trackMon -> actor.activePokemon.none { it.battlePokemon?.uuid == trackMon.id } }
|
||||
@@ -145,6 +146,7 @@ class TrackerActor(val uuid: UUID) {
|
||||
actor.activePokemon.filter { newActive -> activePokemon.none { it.id == newActive.battlePokemon?.uuid } }.forEach {
|
||||
val active = party.firstOrNull { trackMon -> trackMon.id == it.battlePokemon?.uuid } ?: return@forEach
|
||||
party.remove(active)
|
||||
active.firstTurn = true // Reset firstTurn when switching in
|
||||
activePokemon.add(active)
|
||||
}
|
||||
val swappedOut = activePokemon.filter { trackMon -> actor.activePokemon.none { it.battlePokemon?.uuid == trackMon.id } }
|
||||
|
||||
+1
@@ -51,6 +51,7 @@ class FaintInstruction(battle: PokemonBattle, val message: BattleMessage) : Inte
|
||||
|
||||
preamble.thenAccept {
|
||||
faintingPokemon.effectedPokemon.currentHealth = 0
|
||||
faintingPokemon.faintedAt = battle.faintCounter++
|
||||
faintingPokemon.sendUpdate()
|
||||
CobblemonEvents.BATTLE_FAINTED.post(BattleFaintedEvent(battle, pokemon, context, pnx))
|
||||
battle.getActorAndActiveSlotFromPNX(pnx).second.battlePokemon = null
|
||||
|
||||
@@ -110,6 +110,9 @@ open class BattlePokemon(
|
||||
/** A set of all the BattlePokemon that they faced during the battle (for exp purposes) */
|
||||
val facedOpponents = mutableSetOf<BattlePokemon>()
|
||||
|
||||
/** The faint sequence number within the battle, or null if this pokemon has not fainted. */
|
||||
var faintedAt: Int? = null
|
||||
|
||||
/**
|
||||
* The [HeldItemManager] backing this [BattlePokemon].
|
||||
*/
|
||||
|
||||
@@ -133,7 +133,10 @@ class ApricornBlock(settings: Properties, val apricorn: Apricorn) : HorizontalDi
|
||||
override fun isBonemealSuccess(world: Level, random: RandomSource, pos: BlockPos, state: BlockState) = true
|
||||
|
||||
override fun performBonemeal(world: ServerLevel, random: RandomSource, pos: BlockPos, state: BlockState) {
|
||||
world.setBlock(pos, state.setValue(AGE, state.getValue(AGE) + 1), 2)
|
||||
val curAge = state.getValue(AGE)
|
||||
val newAge = curAge + 1
|
||||
if (newAge > MAX_AGE) return
|
||||
world.setBlock(pos, state.setValue(AGE, newAge), UPDATE_CLIENTS)
|
||||
}
|
||||
|
||||
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
|
||||
@@ -186,17 +189,17 @@ class ApricornBlock(settings: Properties, val apricorn: Apricorn) : HorizontalDi
|
||||
* This uses [Block.dropResources] to handle the drops.
|
||||
* It will also reset the [BlockState] of this block at the given location to the start of growth.
|
||||
*
|
||||
* @param world The [World] the apricorn is in.
|
||||
* @param world The [Level] the apricorn is in.
|
||||
* @param state The [BlockState] of the apricorn.
|
||||
* @param pos The [BlockPos] of the apricorn.
|
||||
* @return The [BlockState] after harvest.
|
||||
*/
|
||||
fun harvest(world: Level, state: BlockState, pos: BlockPos): BlockState {
|
||||
// Uses loot tables, to change the drops use 'data/cobblemon/loot_tables/blocks/<color>_apricorn.json'
|
||||
Block.dropResources(state, world, pos)
|
||||
dropResources(state, world, pos)
|
||||
// Don't use default as we want to keep the facing
|
||||
val resetState = state.setValue(AGE, MIN_AGE)
|
||||
world.setBlock(pos, resetState, Block.UPDATE_CLIENTS)
|
||||
world.setBlock(pos, resetState, UPDATE_CLIENTS)
|
||||
return resetState
|
||||
}
|
||||
|
||||
|
||||
@@ -81,7 +81,32 @@ class BerryBlock(private val berryIdentifier: ResourceLocation, settings: Proper
|
||||
|
||||
override fun isBonemealSuccess(world: Level, random: RandomSource, pos: BlockPos, state: BlockState) = !this.isMaxAge(state)
|
||||
|
||||
override fun <T : BlockEntity> getTicker(world: Level, blockState: BlockState, blockWithEntityType: BlockEntityType<T>): BlockEntityTicker<T>? = createTickerHelper(blockWithEntityType, CobblemonBlockEntities.BERRY, BerryBlockEntity.TICKER)
|
||||
// Use Random Tick instead of BlockEntityTicker for performance optimization
|
||||
override fun <T : BlockEntity> getTicker(world: Level, blockState: BlockState, blockWithEntityType: BlockEntityType<T>): BlockEntityTicker<T>? = null
|
||||
|
||||
// Enable Random Tick: only immature and non-rooted berries need to tick
|
||||
override fun isRandomlyTicking(state: BlockState): Boolean {
|
||||
return state.getValue(AGE) < FRUIT_AGE && !state.getValue(IS_ROOTED)
|
||||
}
|
||||
|
||||
// Random Tick handler: uses time compensation to ensure correct growth speed
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun randomTick(state: BlockState, world: ServerLevel, pos: BlockPos, random: RandomSource) {
|
||||
val blockEntity = world.getBlockEntity(pos) as? BerryBlockEntity ?: return
|
||||
|
||||
// processTick calculates elapsed time and updates timer, returns whether growth is needed
|
||||
if (blockEntity.processTick(world, pos, state) && !world.getBlockTicks().hasScheduledTick(pos, this)) {
|
||||
// Schedule growth for next tick to avoid tick scheduler conflicts during randomTick
|
||||
world.scheduleTick(pos, this, 1)
|
||||
}
|
||||
}
|
||||
|
||||
// Scheduled tick handler: performs the actual growth
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun tick(state: BlockState, world: ServerLevel, pos: BlockPos, random: RandomSource) {
|
||||
if (state.getValue(IS_ROOTED)) return
|
||||
growHelper(world, random, pos, state)
|
||||
}
|
||||
|
||||
init {
|
||||
registerDefaultState(stateDefinition.any()
|
||||
|
||||
@@ -151,12 +151,14 @@ class CampfireBlock(settings: Properties, val isSoul: Boolean) : BaseEntityBlock
|
||||
override fun placeLiquid(level: LevelAccessor, pos: BlockPos, state: BlockState, fluidState: FluidState): Boolean {
|
||||
val blockEntity = level.getBlockEntity(pos)
|
||||
if (fluidState.type === Fluids.WATER && blockEntity is CampfireBlockEntity) {
|
||||
if (!level.isClientSide) {
|
||||
removePotItem(blockEntity, state, level as Level, pos, null, true)
|
||||
level.playSoundServer(pos.center, SoundEvents.GENERIC_EXTINGUISH_FIRE, SoundSource.BLOCKS, 1.0F, 1.0F)
|
||||
}
|
||||
if (level is Level) {
|
||||
if (!level.isClientSide) {
|
||||
removePotItem(blockEntity, state, level, pos, null, true)
|
||||
level.playSoundServer(pos.center, SoundEvents.GENERIC_EXTINGUISH_FIRE, SoundSource.BLOCKS, 1.0F, 1.0F)
|
||||
}
|
||||
|
||||
if (level.isClientSide) for (i in 0..19) MCCampfireBlock.makeParticles(level as Level, pos, false, true)
|
||||
if (level.isClientSide) for (i in 0..19) MCCampfireBlock.makeParticles(level, pos, false, true)
|
||||
}
|
||||
|
||||
level.scheduleTick(pos, fluidState.type, fluidState.type.getTickDelay(level))
|
||||
return true
|
||||
|
||||
@@ -65,6 +65,9 @@ class BerryBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(Cobblemon
|
||||
private val growthPoints = arrayListOf<ResourceLocation>()
|
||||
var mulchVariant = MulchVariant.NONE
|
||||
|
||||
// For Random Tick compensation: records the game time of last tick
|
||||
var lastTickTime: Long = 0L
|
||||
|
||||
/**
|
||||
* The idea behind the growth point sequence is it's a 16-long string of
|
||||
* hexadecimal numbers. They represent the order of the growth points that
|
||||
@@ -267,6 +270,7 @@ class BerryBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(Cobblemon
|
||||
} catch (ignored: ResourceLocationException) {}
|
||||
}
|
||||
this.mulchDuration = nbt.getInt(MULCH_DURATION)
|
||||
this.lastTickTime = nbt.getLong(LAST_TICK_TIME)
|
||||
this.wasLoading = false
|
||||
if (nbt.contains(GROWTH_POINTS_SEQUENCE)) {
|
||||
growthPointSequence = nbt.getString(GROWTH_POINTS_SEQUENCE)
|
||||
@@ -287,6 +291,7 @@ class BerryBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(Cobblemon
|
||||
nbt.putInt(MULCH_DURATION, mulchDuration)
|
||||
nbt.putString(GROWTH_POINTS_SEQUENCE, growthPointSequence)
|
||||
nbt.putString(MULCH_VARIANT, mulchVariant.toString())
|
||||
nbt.putLong(LAST_TICK_TIME, lastTickTime)
|
||||
}
|
||||
|
||||
override fun setChanged() {
|
||||
@@ -346,24 +351,39 @@ class BerryBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(Cobblemon
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
* Process Random Tick compensation logic.
|
||||
* Calculates elapsed time since last tick and batch-decrements stageTimer.
|
||||
*/
|
||||
fun processTick(world: ServerLevel, pos: BlockPos, state: BlockState): Boolean {
|
||||
if (state.getValue(BerryBlock.IS_ROOTED)) return false
|
||||
|
||||
val currentTime = world.gameTime
|
||||
val elapsed = if (lastTickTime > 0L) {
|
||||
(currentTime - lastTickTime).toInt().coerceAtLeast(1)
|
||||
} else {
|
||||
1 // First tick, only decrement by 1
|
||||
}
|
||||
lastTickTime = currentTime
|
||||
|
||||
// Batch decrement the timer
|
||||
if (stageTimer > 0) {
|
||||
stageTimer = (stageTimer - elapsed).coerceAtLeast(0)
|
||||
}
|
||||
|
||||
// Return whether growth is needed
|
||||
return stageTimer <= 0
|
||||
}
|
||||
|
||||
//Using a similar approach to ComputerCraft, implement this client side
|
||||
interface RenderState : AutoCloseable {
|
||||
var needsRebuild: Boolean
|
||||
}
|
||||
|
||||
companion object {
|
||||
internal val TICKER = BlockEntityTicker<BerryBlockEntity> { world, pos, state, blockEntity ->
|
||||
if (world.isClientSide) return@BlockEntityTicker
|
||||
if (state.getValue(BerryBlock.IS_ROOTED)) return@BlockEntityTicker
|
||||
if (blockEntity.stageTimer >= 0) {
|
||||
blockEntity.stageTimer--
|
||||
}
|
||||
if (blockEntity.stageTimer <= 0) {
|
||||
(state.block as BerryBlock).growHelper(world as ServerLevel, world.random, pos, state)
|
||||
}
|
||||
}
|
||||
//private const val LIFE_CYCLES = "life_cycles"
|
||||
private const val GROWTH_POINTS = "GrowthPoints"
|
||||
private const val LAST_TICK_TIME = "LastTickTime"
|
||||
private const val GROWTH_POINTS_SEQUENCE = "GrowthPointsSequence"
|
||||
private const val GROWTH_TIMER = "GrowthTimer"
|
||||
private const val STAGE_TIMER = "StageTimer"
|
||||
|
||||
+14
-32
@@ -29,6 +29,7 @@ import com.cobblemon.mod.common.api.spawning.influence.SpawnBaitInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.FixedAreaSpawner
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.PokeSnackSpawnerFactory
|
||||
import com.cobblemon.mod.common.block.PokeSnackBlock
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.item.components.BaitEffectsComponent
|
||||
@@ -62,41 +63,22 @@ open class PokeSnackBlockEntity(pos: BlockPos, state: BlockState) :
|
||||
}
|
||||
|
||||
val spawner: FixedAreaSpawner by lazy {
|
||||
FixedAreaSpawner(
|
||||
name = "poke_snack_spawner_${level?.dimension()?.location()}}_$blockPos",
|
||||
spawnPool = CobblemonSpawnPools.WORLD_SPAWN_POOL,
|
||||
world = level as ServerLevel,
|
||||
position = blockPos,
|
||||
val server = level as ServerLevel
|
||||
|
||||
val baitEffects = getBaitEffects()
|
||||
|
||||
val ctx = PokeSnackSpawnerFactory.Context(
|
||||
world = server,
|
||||
pos = blockPos,
|
||||
horizontalRadius = RADIUS,
|
||||
verticalRadius = RADIUS,
|
||||
maxPokemonPerChunk = Cobblemon.config.pokeSnackPokemonPerChunk
|
||||
).also {
|
||||
it.influences.add(this)
|
||||
maxPokemonPerChunk = Cobblemon.config.pokeSnackPokemonPerChunk,
|
||||
name = "poke_snack_spawner_${server.dimension().location()}_$blockPos",
|
||||
baitEffects = baitEffects
|
||||
)
|
||||
|
||||
val baitEffects = getBaitEffects()
|
||||
|
||||
val stackedLureTier = baitEffects
|
||||
.filter { it.type == SpawnBait.Effects.RARITY_BUCKET }
|
||||
.sumOf { it.value }
|
||||
.toInt()
|
||||
|
||||
if (stackedLureTier > 0) {
|
||||
it.influences += BucketNormalizingInfluence(
|
||||
tier = stackedLureTier,
|
||||
gradient = 0.2F,
|
||||
firstTier = 1.2F
|
||||
)
|
||||
}
|
||||
|
||||
it.influences += BucketMultiplyingInfluence(
|
||||
mapOf(
|
||||
"uncommon" to 2.25f,
|
||||
"rare" to 5.5f,
|
||||
"ultra-rare" to 5.5f,
|
||||
)
|
||||
)
|
||||
|
||||
it.influences += SpawnBaitInfluence(effects = baitEffects)
|
||||
PokeSnackSpawnerFactory.create(ctx).also { spawner ->
|
||||
spawner.influences.add(this)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -128,11 +128,11 @@ class FossilMultiblockStructure (
|
||||
|
||||
if(pokemon != null) {
|
||||
pokemon.caughtBall = ballType
|
||||
player.party().add(pokemon)
|
||||
this.fossilState.growthState = "Taken"
|
||||
player.playSound(CobblemonSounds.FOSSIL_MACHINE_RETRIEVE_POKEMON, 1.0F, 1.0F)
|
||||
CobblemonEvents.FOSSIL_REVIVED.post(FossilRevivedEvent(pokemon, player))
|
||||
CobblemonCriteria.RESURRECT_POKEMON.trigger(player, pokemon)
|
||||
player.party().add(pokemon)
|
||||
}
|
||||
|
||||
// Turn the monitor off
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.cobblemon.mod.common.client.gui.PartyOverlayDataControl
|
||||
import com.cobblemon.mod.common.client.gui.RideControlsOverlay
|
||||
import com.cobblemon.mod.common.client.gui.battle.BattleOverlay
|
||||
import com.cobblemon.mod.common.client.gui.cookingpot.CookingPotScreen
|
||||
import com.cobblemon.mod.common.client.gui.party.PartyTutorialToasts
|
||||
import com.cobblemon.mod.common.client.particle.BedrockParticleOptionsRepository
|
||||
import com.cobblemon.mod.common.client.render.ClientPlayerIcon
|
||||
import com.cobblemon.mod.common.client.render.DeferredRenderer
|
||||
@@ -74,7 +75,6 @@ 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
|
||||
@@ -84,19 +84,16 @@ 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 {
|
||||
|
||||
@@ -116,8 +113,6 @@ 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()
|
||||
@@ -134,6 +129,8 @@ object CobblemonClient {
|
||||
battleOverlay.onLogout()
|
||||
ClientTaskTracker.clear()
|
||||
checkedStarterScreen = false
|
||||
overlay.resetAttachedToast()
|
||||
PartyTutorialToasts.reset()
|
||||
// CobblemonDataProvider.canReload = true
|
||||
DeferredRenderer.clearAll()
|
||||
ClientPlayerIcon.clear()
|
||||
@@ -171,13 +168,12 @@ object CobblemonClient {
|
||||
PlatformEvents.CLIENT_TICK_POST.subscribe { event ->
|
||||
val player = event.client.player
|
||||
if (player != null) {
|
||||
var selectedItem = player.inventory.getItem(player.inventory.selected)
|
||||
val selectedItem = player.inventory.getItem(player.inventory.selected)
|
||||
if (pokedexUsageContext.scanningGuiOpen &&
|
||||
!(selectedItem.`is`(CobblemonItemTags.POKEDEX)) &&
|
||||
!(player.offhandItem.`is`(CobblemonItemTags.POKEDEX) &&
|
||||
player.isUsingItem == true &&
|
||||
player.usedItemHand == InteractionHand.OFF_HAND
|
||||
)
|
||||
player.isUsingItem &&
|
||||
player.usedItemHand == InteractionHand.OFF_HAND)
|
||||
) {
|
||||
// Stop using Pokédex in main hand if player switches to a different slot in hotbar
|
||||
pokedexUsageContext.stopUsing(PokedexUsageContext.OPEN_SCANNER_BUFFER_TICKS + 1)
|
||||
@@ -201,8 +197,6 @@ object CobblemonClient {
|
||||
ClientPlayerIcon.onTick()
|
||||
PartyOverlayDataControl.tick(event.client.isPaused)
|
||||
}
|
||||
|
||||
ridingSprintHandler.put(cobblemonResource("normal")) { Minecraft.getInstance().options.keySprint.isDown }
|
||||
}
|
||||
|
||||
private fun registerTooltipManagers() {
|
||||
@@ -224,7 +218,7 @@ object CobblemonClient {
|
||||
}
|
||||
|
||||
fun registerColors() {
|
||||
this.implementation.registerBlockColors(BlockColor { blockState, view, blockPos, tintIndex ->
|
||||
this.implementation.registerBlockColors(BlockColor { _, view, blockPos, _ ->
|
||||
blockPos?.let { pos ->
|
||||
view?.getBlockEntity(pos)?.let { blockEntity ->
|
||||
if (blockEntity is TintBlockEntity) return@BlockColor blockEntity.getTint()
|
||||
|
||||
@@ -12,16 +12,17 @@ import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonItems
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.gui.drawPosablePortrait
|
||||
import com.cobblemon.mod.common.api.text.bold
|
||||
import com.cobblemon.mod.common.api.text.darkGray
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.client.CobblemonClient
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.gui.battle.BattleGUI
|
||||
import com.cobblemon.mod.common.client.gui.party.PartyTutorialToasts
|
||||
import com.cobblemon.mod.common.client.gui.toast.CobblemonToast
|
||||
import com.cobblemon.mod.common.client.keybind.boundKey
|
||||
import com.cobblemon.mod.common.client.keybind.keybinds.HidePartyBinding
|
||||
import com.cobblemon.mod.common.client.keybind.keybinds.SummaryBinding
|
||||
import com.cobblemon.mod.common.client.keybind.keybinds.*
|
||||
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
|
||||
@@ -128,10 +129,6 @@ 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 &&
|
||||
@@ -154,6 +151,9 @@ class PartyOverlay : Gui(Minecraft.getInstance()) {
|
||||
val portraitFrameOffsetY = 2
|
||||
val selectedSlot = CobblemonClient.storage.selectedSlot
|
||||
|
||||
val partySize = party.slots.count { it != null }
|
||||
PartyTutorialToasts.onOverlayRender(partySize)
|
||||
|
||||
party.forEachIndexed { index, pokemon ->
|
||||
if (pokemon != null) {
|
||||
val selectedOffsetX = if (selectedSlot == index) 6 else 0
|
||||
@@ -177,11 +177,10 @@ 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,
|
||||
-50.0
|
||||
0.0
|
||||
)
|
||||
|
||||
val shouldAnimate = when (Cobblemon.config.partyPortraitAnimations) {
|
||||
@@ -231,7 +230,7 @@ class PartyOverlay : Gui(Minecraft.getInstance()) {
|
||||
var levelScrollOffset = 0F
|
||||
var levelScrollPositionOffset = 0F
|
||||
var levelScrollSize = 17F
|
||||
if (expGainedData != null && expGainedData.oldLevel != null) {
|
||||
if (expGainedData?.oldLevel != null) {
|
||||
val ticksWithDelta = (expGainedData.ticks + partialDeltaTicks) - (PartyOverlayDataControl.BAR_UPDATE_BEFORE_TIME + PartyOverlayDataControl.BAR_FLASH_TIME)
|
||||
val transition = ticksWithDelta / PartyOverlayDataControl.LEVEL_UP_PORTRAIT_TIME
|
||||
if ((0F..<1F).contains(transition)) {
|
||||
@@ -405,10 +404,48 @@ class PartyOverlay : Gui(Minecraft.getInstance()) {
|
||||
blue = expBlue
|
||||
)
|
||||
|
||||
//Handling EXP Text
|
||||
|
||||
var expGained = 0
|
||||
var expTextTransparency = 0F
|
||||
var expTextOffset = 0F
|
||||
|
||||
if (expGainedData != null) {
|
||||
expGained = expGainedData.expGained
|
||||
val ticksWithDelta = expGainedData.ticks + partialDeltaTicks
|
||||
if (ticksWithDelta <= PartyOverlayDataControl.EXP_POPUP_TIME.fadeIn) {
|
||||
val transition = ticksWithDelta / PartyOverlayDataControl.EXP_POPUP_TIME.fadeIn
|
||||
val step = (floor(transition * 3)) + 1
|
||||
expTextTransparency = step * 0.25F
|
||||
expTextOffset = 4 - step
|
||||
} else if (ticksWithDelta <= PartyOverlayDataControl.EXP_POPUP_TIME.fadeIn + PartyOverlayDataControl.EXP_POPUP_TIME.hold) {
|
||||
expTextTransparency = 1F
|
||||
expTextOffset = 0F
|
||||
} else {
|
||||
val adjustedTicks = ticksWithDelta - (PartyOverlayDataControl.EXP_POPUP_TIME.fadeIn + PartyOverlayDataControl.EXP_POPUP_TIME.hold)
|
||||
val transition = adjustedTicks / PartyOverlayDataControl.EXP_POPUP_TIME.fadeOut
|
||||
val step = (floor(transition * 3)) + 1
|
||||
expTextTransparency = 1F - (step * 0.25F)
|
||||
expTextOffset = -step
|
||||
}
|
||||
}
|
||||
|
||||
if (expTextTransparency > 0) {
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = lang("ui.exp.number", expGained.toString()).bold(),
|
||||
x = panelX + selectedOffsetX + 57F,
|
||||
y = indexY + 17F + expTextOffset,
|
||||
scale = SCALE,
|
||||
shadow = true,
|
||||
opacity = expTextTransparency
|
||||
)
|
||||
}
|
||||
|
||||
//Handling Popups
|
||||
var ticksForMove = -1F
|
||||
var ticksForEvo = -1F
|
||||
|
||||
//Handling Popups
|
||||
if (expGainedData != null) {
|
||||
val ticksWithDelta = expGainedData.ticks + partialDeltaTicks
|
||||
val ticks = ticksWithDelta - (PartyOverlayDataControl.BAR_UPDATE_BEFORE_TIME + PartyOverlayDataControl.BAR_FLASH_TIME)
|
||||
@@ -439,7 +476,7 @@ class PartyOverlay : Gui(Minecraft.getInstance()) {
|
||||
return 0F to 1F
|
||||
} else {
|
||||
val adjustedPopupTicks = ticks - (PartyOverlayDataControl.POPUP_TIME.fadeIn + PartyOverlayDataControl.POPUP_TIME.hold)
|
||||
val transition = adjustedPopupTicks / PartyOverlayDataControl.POPUP_TIME.fadeIn
|
||||
val transition = adjustedPopupTicks / PartyOverlayDataControl.POPUP_TIME.fadeOut
|
||||
val step = (floor(transition * 3)) + 1
|
||||
return (-step) to (1F - (step * 0.25F))
|
||||
}
|
||||
@@ -453,7 +490,7 @@ class PartyOverlay : Gui(Minecraft.getInstance()) {
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = newEvoPopup,
|
||||
x = (panelX + selectedOffsetX + 56.5F) / SCALE,
|
||||
x = (panelX + selectedOffsetX + (if (expTextTransparency > 0 && movePopupTransparency > 0) 78F else 56.5F)) / SCALE,
|
||||
y = (indexY + 4 + evoPopupYOffset) / SCALE,
|
||||
width = 37,
|
||||
height = 20,
|
||||
@@ -466,7 +503,7 @@ class PartyOverlay : Gui(Minecraft.getInstance()) {
|
||||
matrixStack = matrices,
|
||||
texture = newMovesPopup,
|
||||
x = (panelX + selectedOffsetX + 56.5F) / SCALE,
|
||||
y = (indexY + 17 + movePopupYOffset) / SCALE,
|
||||
y = (indexY + (if (expTextTransparency > 0) 4 else 17) + movePopupYOffset) / SCALE,
|
||||
width = 37,
|
||||
height = 20,
|
||||
scale = SCALE,
|
||||
@@ -515,7 +552,5 @@ class PartyOverlay : Gui(Minecraft.getInstance()) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
matrices.popPose()
|
||||
}
|
||||
}
|
||||
+29
-17
@@ -19,10 +19,10 @@ object PartyOverlayDataControl {
|
||||
const val BAR_UPDATE_BEFORE_TIME = 15
|
||||
const val BAR_UPDATE_AFTER_TIME = 15
|
||||
const val BAR_FLASH_TIME = 2
|
||||
const val BAR_UPDATE_NO_LEVEL_TIME = BAR_UPDATE_BEFORE_TIME + BAR_UPDATE_AFTER_TIME + BAR_FLASH_TIME
|
||||
val POPUP_TIME = FadeTimings(3, 40, 3)
|
||||
const val LEVEL_UP_PORTRAIT_TIME = 10
|
||||
|
||||
val BAR_UPDATE_NO_LEVEL_TIME = BAR_UPDATE_BEFORE_TIME + BAR_UPDATE_AFTER_TIME + BAR_FLASH_TIME
|
||||
val EXP_POPUP_TIME = FadeTimings(3, BAR_UPDATE_BEFORE_TIME + BAR_FLASH_TIME + POPUP_TIME.total() - 6, 3)
|
||||
|
||||
private enum class RenderTarget {
|
||||
NONE,
|
||||
@@ -35,21 +35,19 @@ object PartyOverlayDataControl {
|
||||
|
||||
private var barFillupSound: SoundInstance? = null
|
||||
private var levelUpJingleSound: SoundInstance? = null
|
||||
private var levelUpJingleSoundType: SoundEvent? = null
|
||||
|
||||
fun pokemonGainedExp(pokemonUuid : UUID, oldLevel: Int?, expGained: Int, countOfMovesLearned: Int, countOfEvosUnlocked: Int = 0) {
|
||||
var time = BAR_UPDATE_NO_LEVEL_TIME
|
||||
if (countOfMovesLearned > 0 || countOfEvosUnlocked > 0) {
|
||||
time = BAR_UPDATE_BEFORE_TIME + BAR_FLASH_TIME + POPUP_TIME.total()
|
||||
}
|
||||
|
||||
val data = overlayData[pokemonUuid]
|
||||
val newData = ExpGainedData(oldLevel, expGained, countOfMovesLearned, countOfEvosUnlocked).also { it.ticksMax = time }
|
||||
val newData = ExpGainedData(oldLevel, expGained, countOfMovesLearned, countOfEvosUnlocked).also { it.ticksMax = BAR_UPDATE_BEFORE_TIME + BAR_FLASH_TIME + POPUP_TIME.total() }
|
||||
if (data != null) {
|
||||
if (data.movesGainedData != null) {
|
||||
if (data.movesGainedData != null) { //Absorb Data
|
||||
newData.countOfMovesLearned += data.movesGainedData!!.movesCount
|
||||
data.movesGainedData = null
|
||||
}
|
||||
if (data.evoGainedData != null) {
|
||||
if (data.evoGainedData != null) { //Absorb Data
|
||||
newData.countOfEvosUnlocked += data.evoGainedData!!.evolutionCount
|
||||
data.evoGainedData = null
|
||||
}
|
||||
|
||||
val expData = data.expGainedData
|
||||
@@ -72,8 +70,7 @@ object PartyOverlayDataControl {
|
||||
val data = overlayData[pokemonUuid]
|
||||
val newData = EvolutionGainedData(evoCount).also { it.ticksMax = POPUP_TIME.total() }
|
||||
if (data != null) {
|
||||
if (data.expGainedData != null && data.expGainedData!!.ticks < BAR_UPDATE_BEFORE_TIME + BAR_FLASH_TIME) {
|
||||
data.expGainedData!!.ticksMax = BAR_UPDATE_BEFORE_TIME + BAR_FLASH_TIME + POPUP_TIME.total()
|
||||
if (data.expGainedData != null) {
|
||||
data.expGainedData!!.countOfEvosUnlocked += evoCount
|
||||
return
|
||||
}
|
||||
@@ -93,8 +90,7 @@ object PartyOverlayDataControl {
|
||||
val data = overlayData[pokemonUuid]
|
||||
val newData = MovesGainedData(movesCount).also { it.ticksMax = POPUP_TIME.total() }
|
||||
if (data != null) {
|
||||
if (data.expGainedData != null && data.expGainedData!!.ticks < BAR_UPDATE_BEFORE_TIME + BAR_FLASH_TIME) {
|
||||
data.expGainedData!!.ticksMax = BAR_UPDATE_BEFORE_TIME + BAR_FLASH_TIME + POPUP_TIME.total()
|
||||
if (data.expGainedData != null) {
|
||||
data.expGainedData!!.countOfMovesLearned += movesCount
|
||||
return
|
||||
}
|
||||
@@ -137,13 +133,28 @@ object PartyOverlayDataControl {
|
||||
fun tick(paused: Boolean) {
|
||||
val deletion = mutableListOf<UUID>()
|
||||
if (paused) return
|
||||
|
||||
if (levelUpJingleSound != null && !Minecraft.getInstance().soundManager.isActive(levelUpJingleSound!!)) {
|
||||
levelUpJingleSound = null
|
||||
levelUpJingleSoundType = null
|
||||
}
|
||||
|
||||
overlayData.forEach { (id, data) ->
|
||||
if (data.expGainedData != null) { // We update this in order and render these in order, and as such we don't tick others
|
||||
val expGainedData = data.expGainedData!!
|
||||
expGainedData.ticks += 1
|
||||
if (expGainedData.ticks == BAR_UPDATE_BEFORE_TIME && expGainedData.oldLevel != null) {
|
||||
stopSound(levelUpJingleSound)
|
||||
levelUpJingleSound = playSound(CobblemonSounds.LEVELUP)
|
||||
if (expGainedData.countOfEvosUnlocked > 0) {
|
||||
stopSound(levelUpJingleSound)
|
||||
levelUpJingleSound = playSound(CobblemonSounds.EVOLUTION_NOTIFICATION)
|
||||
levelUpJingleSoundType = CobblemonSounds.EVOLUTION_NOTIFICATION
|
||||
} else {
|
||||
if (levelUpJingleSoundType != CobblemonSounds.EVOLUTION_NOTIFICATION) {
|
||||
stopSound(levelUpJingleSound)
|
||||
levelUpJingleSound = playSound(CobblemonSounds.LEVELUP)
|
||||
levelUpJingleSoundType = CobblemonSounds.LEVELUP
|
||||
}
|
||||
}
|
||||
}
|
||||
if (expGainedData.ticks >= expGainedData.ticksMax) {
|
||||
data.expGainedData = null
|
||||
@@ -166,6 +177,7 @@ object PartyOverlayDataControl {
|
||||
}
|
||||
if (getCurrentRenderTarget(id) == RenderTarget.NONE) deletion.add(id)
|
||||
}
|
||||
|
||||
deletion.forEach {
|
||||
overlayData.remove(it)
|
||||
}
|
||||
@@ -216,7 +228,7 @@ object PartyOverlayDataControl {
|
||||
//SOUNDS
|
||||
private fun playSound(soundEvent: SoundEvent): SoundInstance? {
|
||||
if (!PartyOverlay.canRender()) return null
|
||||
val soundInstance = SimpleSoundInstance.forUI(soundEvent, 1F)
|
||||
val soundInstance = SimpleSoundInstance.forUI(soundEvent, 1F, 1F)
|
||||
Minecraft.getInstance().soundManager.play(soundInstance)
|
||||
return soundInstance
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ fun drawProfilePokemon(
|
||||
a: Float = 1F,
|
||||
headYaw: Float = 0f,
|
||||
headPitch: Float = 0f,
|
||||
blockLight: Int = 13
|
||||
) = drawProfilePokemon(
|
||||
species = renderablePokemon.species.resourceIdentifier,
|
||||
matrixStack = matrixStack,
|
||||
@@ -63,6 +64,7 @@ fun drawProfilePokemon(
|
||||
a = a,
|
||||
headYaw = headYaw,
|
||||
headPitch = headPitch,
|
||||
blockLight = blockLight
|
||||
)
|
||||
|
||||
fun drawProfilePokemon(
|
||||
@@ -82,6 +84,7 @@ fun drawProfilePokemon(
|
||||
a: Float = 1F,
|
||||
headYaw: Float = 0f,
|
||||
headPitch: Float = 0f,
|
||||
blockLight: Int = 13
|
||||
) {
|
||||
RenderSystem.applyModelViewMatrix()
|
||||
matrixStack.scale(scale, scale, -scale)
|
||||
@@ -138,7 +141,7 @@ fun drawProfilePokemon(
|
||||
val light1 = Vector3f(-1F, 1F, 1.0F)
|
||||
val light2 = Vector3f(1.3F, -1F, 1.0F)
|
||||
RenderSystem.setShaderLights(light1, light2)
|
||||
val packedLight = LightTexture.pack(11, 7)
|
||||
val packedLight = LightTexture.pack(blockLight, 0)
|
||||
|
||||
val colour = toHex(r, g, b, a)
|
||||
model.withLayerContext(bufferSource, state, VaryingModelRepository.getLayers(species, state)) {
|
||||
|
||||
@@ -195,7 +195,7 @@ abstract class ScrollingWidget<T : ObjectSelectionList.Entry<T>>(
|
||||
return this.width
|
||||
}
|
||||
|
||||
public override fun getRowTop(index: Int): Int {
|
||||
override fun getRowTop(index: Int): Int {
|
||||
return this.y - scrollAmount.toInt() + (index * this.itemHeight)
|
||||
}
|
||||
|
||||
@@ -205,19 +205,6 @@ 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
|
||||
}
|
||||
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* 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.gui
|
||||
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.client.gui.components.AbstractWidget
|
||||
import net.minecraft.client.gui.components.events.GuiEventListener
|
||||
import net.minecraft.client.gui.narration.NarrationElementOutput
|
||||
import net.minecraft.network.chat.CommonComponents
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import kotlin.math.floor
|
||||
|
||||
open class VariableObjectSelectionList(x: Int, y: Int, width: Int, height: Int): AbstractWidget(x, y, width, height, CommonComponents.EMPTY) {
|
||||
val children = mutableListOf<Entry>()
|
||||
|
||||
var listHeight = 0
|
||||
var scrollAmount = 0.0
|
||||
|
||||
fun updateScroll(offset: Double) {
|
||||
setScroll(scrollAmount + offset)
|
||||
}
|
||||
|
||||
fun getMaxScroll(): Int {
|
||||
return (listHeight - height).coerceAtLeast(0)
|
||||
}
|
||||
|
||||
fun setScroll(scroll: Double) {
|
||||
scrollAmount = scroll.coerceIn(0.0, getMaxScroll().toDouble())
|
||||
}
|
||||
|
||||
fun removeEntry(index: Int) {
|
||||
listHeight -= children[index].height
|
||||
children.removeAt(index)
|
||||
updatePositions()
|
||||
}
|
||||
|
||||
fun removeEntry(entry: Entry) {
|
||||
listHeight -= entry.height
|
||||
children.remove(entry)
|
||||
updatePositions()
|
||||
}
|
||||
|
||||
fun removeLastEntry() {
|
||||
listHeight -= children.last().height
|
||||
children.removeLast()
|
||||
}
|
||||
|
||||
fun updatePositions() {
|
||||
var stackHeight = 0
|
||||
children.forEach {
|
||||
it.scrolledY = stackHeight
|
||||
stackHeight += it.height
|
||||
}
|
||||
updateScroll(0.0)
|
||||
}
|
||||
|
||||
fun addEntry(entry: Entry) {
|
||||
children.add(entry)
|
||||
entry.scrolledY = listHeight
|
||||
listHeight += entry.height
|
||||
}
|
||||
|
||||
override fun renderWidget(guiGraphics: GuiGraphics, mouseX: Int, mouseY: Int, partialTick: Float) {
|
||||
var stackHeight = -scrollAmount.toInt()
|
||||
guiGraphics.enableScissor(x, y, x + width, y + height)
|
||||
children.forEachIndexed { index, entry ->
|
||||
if (stackHeight in 1..<height || stackHeight + entry.height in 1..<height) {
|
||||
entry.render(guiGraphics, index, x, y + stackHeight, mouseX, mouseY, partialTick)
|
||||
}
|
||||
stackHeight += entry.height
|
||||
}
|
||||
guiGraphics.disableScissor()
|
||||
}
|
||||
|
||||
fun getEntryAtPosition(mouseX: Int, mouseY: Int): Entry? {
|
||||
if (mouseX in x..(x + width) && mouseY in y..(y + height)) {
|
||||
var stackHeight = -scrollAmount
|
||||
children.forEach {
|
||||
if (mouseY.toDouble() in (y + stackHeight)..(y + stackHeight + it.height)) {
|
||||
return it
|
||||
}
|
||||
stackHeight += it.height
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun ensureVisible(index: Int) {
|
||||
val entry = children[index]
|
||||
if (entry.scrolledY - scrollAmount < 0) {
|
||||
setScroll(entry.scrolledY.toDouble())
|
||||
} else if (entry.scrolledY + entry.height > height) {
|
||||
setScroll(entry.scrolledY.toDouble() + entry.height)
|
||||
}
|
||||
}
|
||||
|
||||
override fun mouseScrolled(mouseX: Double, mouseY: Double, horizontalAmount: Double, verticalAmount: Double): Boolean {
|
||||
updateScroll(-verticalAmount * (listHeight / children.size / 2))
|
||||
return true
|
||||
}
|
||||
|
||||
override fun mouseClicked(pMouseX: Double, pMouseY: Double, pButton: Int): Boolean {
|
||||
val entry = getEntryAtPosition(pMouseX.toInt(), pMouseY.toInt())
|
||||
if (entry != null) {
|
||||
return entry.mouseClicked(pMouseX, pMouseY, pButton)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun mouseReleased(pMouseX: Double, pMouseY: Double, pButton: Int): Boolean {
|
||||
return children.any {
|
||||
it.mouseReleased(pMouseX, pMouseY, pButton)
|
||||
} || super.mouseReleased(pMouseX, pMouseY, pButton)
|
||||
}
|
||||
|
||||
fun getRowTop(entry: Entry): Int {
|
||||
var stackHeight = -scrollAmount.toInt()
|
||||
children.forEach {
|
||||
if (it == entry) {
|
||||
return y + stackHeight
|
||||
}
|
||||
stackHeight += it.height
|
||||
}
|
||||
return y
|
||||
}
|
||||
|
||||
override fun defaultButtonNarrationText(pNarrationElementOutput: NarrationElementOutput) {}
|
||||
override fun updateWidgetNarration(narrationElementOutput: NarrationElementOutput) {}
|
||||
|
||||
abstract inner class Entry(var height: Int): GuiEventListener {
|
||||
var scrolledY: Int = 0
|
||||
private var widgetFocused = false
|
||||
|
||||
override fun setFocused(focused: Boolean) {
|
||||
this.widgetFocused = focused
|
||||
}
|
||||
|
||||
override fun isFocused(): Boolean = widgetFocused
|
||||
|
||||
abstract fun render(guiGraphics: GuiGraphics, index: Int, x: Int, y: Int, mouseX: Int, mouseY: Int, partialTick: Float)
|
||||
}
|
||||
|
||||
inner class EmptySeparator(height: Int): Entry(height) {
|
||||
override fun render(guiGraphics: GuiGraphics, index: Int, x: Int, y: Int, mouseX: Int, mouseY: Int, partialTick: Float) {}
|
||||
}
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui
|
||||
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.client.gui.components.AbstractWidget
|
||||
import net.minecraft.client.gui.narration.NarrationElementOutput
|
||||
import net.minecraft.client.sounds.SoundManager
|
||||
import net.minecraft.network.chat.CommonComponents
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
class VariableObjectSelectionScrollbar(var parent: VariableObjectSelectionList, x: Int, y: Int, width: Int, height: Int): AbstractWidget(x, y, width, height, CommonComponents.EMPTY) {
|
||||
companion object {
|
||||
private val scrollerResource: ResourceLocation = ResourceLocation("minecraft", "textures/gui/sprites/widget/scroller.png")
|
||||
private val scrollerBackgroundResource: ResourceLocation = ResourceLocation("minecraft", "textures/gui/sprites/widget/scroller_background.png")
|
||||
|
||||
private const val SCROLLER_HEIGHT = 32
|
||||
}
|
||||
|
||||
private var scrolling = false
|
||||
private var scrollHoldOffset = 0.0
|
||||
|
||||
fun scrollbarVisible(): Boolean = parent.getMaxScroll() > 0
|
||||
|
||||
override fun renderWidget(guiGraphics: GuiGraphics, mouseX: Int, mouseY: Int, partialTick: Float) {
|
||||
if (scrollbarVisible()) {
|
||||
val scrollPosition = (parent.scrollAmount / parent.getMaxScroll()) * (height - SCROLLER_HEIGHT)
|
||||
|
||||
blitk(
|
||||
matrixStack = guiGraphics.pose(),
|
||||
texture = scrollerBackgroundResource,
|
||||
x = x,
|
||||
y = y,
|
||||
width = width,
|
||||
height = height,
|
||||
)
|
||||
|
||||
blitk(
|
||||
matrixStack = guiGraphics.pose(),
|
||||
texture = scrollerResource,
|
||||
x = x,
|
||||
y = y + scrollPosition,
|
||||
width = width,
|
||||
height = SCROLLER_HEIGHT,
|
||||
textureWidth = 6,
|
||||
textureHeight = SCROLLER_HEIGHT
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun mouseScrolled(mouseX: Double, mouseY: Double, scrollX: Double, scrollY: Double): Boolean {
|
||||
return parent.mouseScrolled(mouseX, mouseY, scrollX, scrollY)
|
||||
}
|
||||
|
||||
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
|
||||
if (mouseX.toInt() in x..(x + width) && mouseY.toInt() in y..(y + height)) {
|
||||
if (button == 0) {
|
||||
var scrollPosition = (parent.scrollAmount / parent.getMaxScroll()) * (height - SCROLLER_HEIGHT)
|
||||
if (mouseY !in (y + scrollPosition)..(y + scrollPosition + SCROLLER_HEIGHT)) {
|
||||
val scrollRatio =
|
||||
((mouseY - y - SCROLLER_HEIGHT / 2) / (height - SCROLLER_HEIGHT)).coerceIn(0.0, 1.0)
|
||||
parent.setScroll(scrollRatio * parent.getMaxScroll())
|
||||
scrollPosition = (parent.scrollAmount / parent.getMaxScroll()) * (height - SCROLLER_HEIGHT)
|
||||
}
|
||||
scrollHoldOffset = mouseY - y - scrollPosition
|
||||
scrolling = true
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun mouseDragged(mouseX: Double, mouseY: Double, button: Int, dragX: Double, dragY: Double): Boolean {
|
||||
if (button == 0 && scrolling) {
|
||||
val scrollRatio = ((mouseY - y - scrollHoldOffset) / (height - SCROLLER_HEIGHT)).coerceIn(0.0,1.0)
|
||||
parent.setScroll(scrollRatio * parent.getMaxScroll())
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun mouseReleased(mouseX: Double, mouseY: Double, button: Int): Boolean {
|
||||
if (button == 0 && scrolling) {
|
||||
scrolling = false
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun playDownSound(handler: SoundManager) {}
|
||||
override fun updateWidgetNarration(narrationElementOutput: NarrationElementOutput) {}
|
||||
}
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
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
|
||||
@@ -18,18 +17,9 @@ 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
|
||||
@@ -39,11 +29,8 @@ 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, ControllerScreen {
|
||||
class BattleGUI : Screen(battleLang("gui.title")), CobblemonRenderable {
|
||||
companion object {
|
||||
const val OPTION_VERTICAL_SPACING = 3
|
||||
const val OPTION_HORIZONTAL_SPACING = 3
|
||||
@@ -64,49 +51,11 @@ class BattleGUI : Screen(battleLang("gui.title")), CobblemonRenderable, Controll
|
||||
|
||||
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?) {
|
||||
@@ -116,11 +65,6 @@ class BattleGUI : Screen(battleLang("gui.title")), CobblemonRenderable, Controll
|
||||
if (newSelection != null) {
|
||||
addRenderableWidget(newSelection)
|
||||
}
|
||||
if (controllerComponentManager.currentSelectedComponent == "battle_action" && controllerComponentManager.active) {
|
||||
focused = null
|
||||
getCurrentActionSelection()?.controllerComponentManager?.active = true
|
||||
controllerComponentManager.focused?.onFocus?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,38 +85,6 @@ class BattleGUI : Screen(battleLang("gui.title")), CobblemonRenderable, Controll
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
@@ -210,10 +122,9 @@ class BattleGUI : Screen(battleLang("gui.title")), CobblemonRenderable, Controll
|
||||
|
||||
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", hideLabelButton),
|
||||
text = battleLang("ui.hide_label", PartySendBinding.boundKey().displayName),
|
||||
x = Minecraft.getInstance().window.guiScaledWidth / 2,
|
||||
y = (Minecraft.getInstance().window.guiScaledHeight / 5),
|
||||
opacity = 0.75F * opacity,
|
||||
@@ -230,17 +141,6 @@ class BattleGUI : Screen(battleLang("gui.title")), CobblemonRenderable, Controll
|
||||
)
|
||||
}
|
||||
|
||||
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()
|
||||
@@ -251,6 +151,8 @@ class BattleGUI : Screen(battleLang("gui.title")), CobblemonRenderable, Controll
|
||||
}
|
||||
|
||||
fun deriveRootActionSelection(actor: ClientBattleActor, request: SingleActionRequest): BattleActionSelection? {
|
||||
|
||||
|
||||
return if (request.forceSwitch) {
|
||||
BattleSwitchPokemonSelection(this, request)
|
||||
} else {
|
||||
@@ -290,21 +192,15 @@ class BattleGUI : Screen(battleLang("gui.title")), CobblemonRenderable, Controll
|
||||
return minimizeBattle()
|
||||
}
|
||||
|
||||
if (specBackButton.isHovered(mouseX, mouseY)) {
|
||||
quitSpectating()
|
||||
val battle = CobblemonClient.battle
|
||||
if (battle?.spectating == true && specBackButton.isHovered(mouseX, mouseY)) {
|
||||
RemoveSpectatorPacket(battle.battleId).sendToServer()
|
||||
CobblemonClient.endBattle()
|
||||
}
|
||||
return super.mouseClicked(mouseX, mouseY, button)
|
||||
}
|
||||
|
||||
fun quitSpectating() {
|
||||
val battle = CobblemonClient.battle
|
||||
if (battle?.spectating == true) {
|
||||
RemoveSpectatorPacket(battle.battleId).sendToServer()
|
||||
CobblemonClient.endBattle()
|
||||
}
|
||||
}
|
||||
|
||||
fun minimizeBattle(): Boolean {
|
||||
private fun minimizeBattle(): Boolean {
|
||||
val battle = CobblemonClient.battle ?: return false
|
||||
battle.minimised = !battle.minimised
|
||||
PartySendBinding.actioned()
|
||||
|
||||
@@ -21,7 +21,6 @@ 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
|
||||
@@ -143,14 +142,9 @@ 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", bindingComponent),
|
||||
text = battleLang("ui.actions_label", PartySendBinding.boundKey().displayName),
|
||||
x = Minecraft.getInstance().window.guiScaledWidth / 2,
|
||||
y = Minecraft.getInstance().window.guiScaledHeight / 5,
|
||||
opacity = textOpacity,
|
||||
|
||||
-3
@@ -11,7 +11,6 @@ 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
|
||||
|
||||
@@ -27,8 +26,6 @@ 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)
|
||||
|
||||
+11
-31
@@ -10,11 +10,11 @@ package com.cobblemon.mod.common.client.gui.battle.subscreen
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
|
||||
import com.cobblemon.mod.common.battles.FleeAttemptActionResponse
|
||||
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
|
||||
@@ -41,7 +41,6 @@ class BattleGeneralActionSelection(
|
||||
val lastAnwseredRequest = CobblemonClient.battle?.getLastAnsweredRequest()
|
||||
|
||||
val tiles = mutableListOf<BattleOptionTile>()
|
||||
|
||||
init {
|
||||
var rank = 0
|
||||
|
||||
@@ -67,7 +66,7 @@ class BattleGeneralActionSelection(
|
||||
|
||||
addOption(rank++, battleLang("ui.run"), BattleGUI.runResource) {
|
||||
CobblemonClient.battle?.minimised = true
|
||||
Minecraft.getInstance().player?.displayClientMessage(battleLang("run_prompt"), false)
|
||||
battleGUI.selectAction(request, FleeAttemptActionResponse())
|
||||
playDownSound(Minecraft.getInstance().soundManager)
|
||||
}
|
||||
} else {
|
||||
@@ -77,41 +76,22 @@ 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
|
||||
val tile = BattleOptionTile(
|
||||
battleGUI = battleGUI,
|
||||
x = x,
|
||||
y = y,
|
||||
resource = texture,
|
||||
text = text,
|
||||
onClick = onClick
|
||||
tiles.add(
|
||||
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) {
|
||||
|
||||
+4
-63
@@ -21,12 +21,10 @@ 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
|
||||
@@ -68,10 +66,6 @@ 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 ->
|
||||
@@ -82,53 +76,6 @@ 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,
|
||||
@@ -152,8 +99,6 @@ 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
|
||||
@@ -165,7 +110,7 @@ class BattleMoveSelection(
|
||||
y = y,
|
||||
width = MOVE_WIDTH,
|
||||
height = MOVE_HEIGHT,
|
||||
vOffset = if (selectable && (isHovered(mouseX.toDouble(), mouseY.toDouble()) || controllerSelected)) MOVE_HEIGHT else 0,
|
||||
vOffset = if (selectable && isHovered(mouseX.toDouble(), mouseY.toDouble())) MOVE_HEIGHT else 0,
|
||||
textureHeight = MOVE_HEIGHT * 2,
|
||||
red = rgb.first,
|
||||
green = rgb.second,
|
||||
@@ -230,7 +175,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
|
||||
@@ -239,10 +184,6 @@ 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)
|
||||
@@ -251,7 +192,7 @@ class BattleMoveSelection(
|
||||
gimmickButtons.forEach {
|
||||
it.render(context.pose(), mouseX, mouseY, delta)
|
||||
}
|
||||
if(shiftButtonActive()) {
|
||||
if(this.request.activePokemon.getFormat().battleType.slotsPerActor == 3 && (request.activePokemon.getPNX()[2] == 'a' || request.activePokemon.getPNX()[2] == 'c')) {
|
||||
shiftButton.render(context, mouseX, mouseY, delta)
|
||||
}
|
||||
}
|
||||
@@ -273,7 +214,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) && shiftButtonActive()) {
|
||||
} else if(shiftButton.isHovered(mouseX,mouseY)) {
|
||||
playDownSound(Minecraft.getInstance().soundManager)
|
||||
battleGUI.selectAction(request, ShiftActionResponse())
|
||||
}
|
||||
|
||||
+5
-41
@@ -21,7 +21,6 @@ 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
|
||||
@@ -69,8 +68,6 @@ 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 }
|
||||
@@ -95,33 +92,6 @@ 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> {
|
||||
@@ -184,15 +154,11 @@ class BattleSwitchPokemonSelection(
|
||||
playDownSound(Minecraft.getInstance().soundManager)
|
||||
return true
|
||||
}
|
||||
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
|
||||
val clicked = tiles.find { it.isHovered(mouseX, mouseY) && if (isReviving) it.isFainted else (!it.isFainted && !it.isCurrentlyInBattle) } ?: return false
|
||||
val pokemon = clicked.pokemon
|
||||
playDownSound(Minecraft.getInstance().soundManager)
|
||||
battleGUI.selectAction(request, SwitchActionResponse(pokemon.uuid))
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -224,9 +190,7 @@ class BattleSwitchPokemonSelection(
|
||||
|
||||
val state = FloatingState()
|
||||
|
||||
var controllerSelected = false
|
||||
|
||||
fun isHovered(mouseX: Double, mouseY: Double) = (mouseX in x..(x + SELECT_WIDTH) && mouseY in (y..(y + SELECT_HEIGHT)))
|
||||
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
|
||||
@@ -265,7 +229,7 @@ class BattleSwitchPokemonSelection(
|
||||
y = y,
|
||||
width = SELECT_WIDTH,
|
||||
height = SELECT_HEIGHT,
|
||||
vOffset = if (!isFainted && (isHovered(mouseX, mouseY) || isCurrentlyInBattle || controllerSelected)) SELECT_HEIGHT else 0,
|
||||
vOffset = if (!isFainted && (isHovered(mouseX, mouseY) || isCurrentlyInBattle)) SELECT_HEIGHT else 0,
|
||||
textureHeight = SELECT_HEIGHT * 2,
|
||||
)
|
||||
|
||||
|
||||
+3
-31
@@ -26,7 +26,6 @@ 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
|
||||
@@ -112,35 +111,10 @@ class BattleTargetSelection(
|
||||
else -> if (isAlly) ArrowDirection.UP else ArrowDirection.DOWN
|
||||
}
|
||||
}
|
||||
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
|
||||
TargetTile(this, target, x, y, arrowDirection)
|
||||
}
|
||||
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,
|
||||
@@ -177,8 +151,6 @@ 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
|
||||
@@ -332,9 +304,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) || it.controllerSelected) } != null
|
||||
return targetTiles.firstOrNull { it.selectable && mouseX >= it.x && mouseX <= it.x + TARGET_WIDTH && mouseY >= it.y && mouseY <= it.y + TARGET_HEIGHT } != null
|
||||
}
|
||||
return mouseX >= x && mouseX <= x + TARGET_WIDTH && mouseY >= y && mouseY <= y + TARGET_HEIGHT || controllerSelected
|
||||
return mouseX >= x && mouseX <= x + TARGET_WIDTH && mouseY >= y && mouseY <= y + TARGET_HEIGHT
|
||||
}
|
||||
|
||||
fun onClick() {
|
||||
|
||||
+9
-41
@@ -17,7 +17,6 @@ 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
|
||||
@@ -52,52 +51,21 @@ 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)) {
|
||||
onDecline()
|
||||
battleGUI.changeActionSelection(null)
|
||||
} else {
|
||||
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()
|
||||
}
|
||||
}
|
||||
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()) || focused) OPTION_HEIGHT else 0,
|
||||
vOffset = if (isHovered(mouseX.toDouble(), mouseY.toDouble())) 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)
|
||||
|
||||
+1
-55
@@ -10,10 +10,6 @@ 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
|
||||
@@ -26,14 +22,11 @@ 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, ControllerScreen {
|
||||
) : Screen("gui.cobblemon_config.title".asTranslated()), CobblemonRenderable {
|
||||
|
||||
companion object {
|
||||
const val HEIGHT = 240
|
||||
@@ -61,13 +54,6 @@ class CobblemonConfigScreen(
|
||||
|
||||
private var searchString: String = ""
|
||||
|
||||
val controllerComponentManager = ControllerComponentManager(this)
|
||||
var lastSelectedEntry = 0
|
||||
|
||||
override fun getComponentManager(): ControllerComponentManager {
|
||||
return controllerComponentManager
|
||||
}
|
||||
|
||||
override fun init() {
|
||||
super.init()
|
||||
|
||||
@@ -111,46 +97,6 @@ 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,7 +17,6 @@ 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
|
||||
@@ -135,63 +134,6 @@ 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(
|
||||
|
||||
+1
-41
@@ -26,9 +26,6 @@ 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
|
||||
@@ -48,10 +45,9 @@ 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, ControllerScreen {
|
||||
class DialogueScreen(var dialogueDTO: DialogueDTO) : Screen("gui.dialogue".asTranslated()), CobblemonRenderable {
|
||||
val speakers = dialogueDTO.speakers?.mapNotNull { (key, value) ->
|
||||
val name = value.name
|
||||
when (val face = value.face) {
|
||||
@@ -145,12 +141,6 @@ 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) {}
|
||||
@@ -252,34 +242,6 @@ 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
|
||||
@@ -303,8 +265,6 @@ 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
|
||||
|
||||
+4
-10
@@ -161,17 +161,10 @@ 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 (mouseX > this.x && mouseX < this.scrollbarPosition &&
|
||||
if (!dialogueScreen.waitingForServerUpdate &&
|
||||
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) {
|
||||
@@ -185,7 +178,8 @@ class DialogueBox(
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
||||
return super.mouseClicked(mouseX, mouseY, button)
|
||||
}
|
||||
|
||||
class DialogueLine(val line: FormattedCharSequence, val lineColor: Int) : Entry<DialogueLine>() {
|
||||
|
||||
+2
-6
@@ -42,7 +42,7 @@ class DialogueOptionWidget(
|
||||
y = y,
|
||||
width = width,
|
||||
height = height,
|
||||
vOffset = if (selectable) (if (isHovered || isFocused) height else 0) else (height * 2),
|
||||
vOffset = if (selectable) (if (isHovered) height else 0) else (height * 2),
|
||||
textureHeight = height * 3,
|
||||
)
|
||||
|
||||
@@ -58,14 +58,10 @@ 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
|
||||
|
||||
|
||||
+21
-68
@@ -8,7 +8,6 @@
|
||||
|
||||
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
|
||||
@@ -17,9 +16,6 @@ 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.*
|
||||
@@ -31,18 +27,16 @@ 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, ControllerScreen {
|
||||
) : Screen(lang("ui.challenge.challenge_title")), CobblemonRenderable {
|
||||
companion object {
|
||||
const val SIZE = 113
|
||||
private val backgroundResource = cobblemonResource("textures/gui/interact/request/battle_request.png")
|
||||
@@ -206,12 +200,6 @@ 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) { }
|
||||
|
||||
@@ -230,29 +218,29 @@ class BattleConfigureGUI(
|
||||
}
|
||||
val (x, y) = getDimensions()
|
||||
|
||||
var battleAccept: BattleResponseButton? = null
|
||||
var battleDecline: BattleResponseButton? = null
|
||||
if(pendingRequest != null) {
|
||||
// Draw Accept/Decline buttons
|
||||
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 + 22,
|
||||
y + 99,
|
||||
true
|
||||
) {
|
||||
battleRequestMap[options[currentPage]]?.onResponse?.let { it1 -> it1(packet, pendingRequest.requestID, true) }
|
||||
closeGUI()
|
||||
}
|
||||
)
|
||||
|
||||
battleDecline = BattleResponseButton(
|
||||
x + 56,
|
||||
y + 99,
|
||||
false
|
||||
) {
|
||||
battleRequestMap[options[currentPage]]?.onResponse?.let { it1 -> it1(packet, pendingRequest.requestID, false) }
|
||||
closeGUI()
|
||||
}
|
||||
this.addRenderableWidget(battleDecline)
|
||||
this.addRenderableWidget(
|
||||
BattleResponseButton(
|
||||
x + 56,
|
||||
y + 99,
|
||||
false
|
||||
) {
|
||||
battleRequestMap[options[currentPage]]?.onResponse?.let { it1 -> it1(packet, pendingRequest.requestID, false) }
|
||||
closeGUI()
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
else {
|
||||
@@ -318,36 +306,6 @@ 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() {
|
||||
@@ -480,8 +438,6 @@ class BattleConfigureGUI(
|
||||
)
|
||||
|
||||
super.render(context, mouseX, mouseY, delta)
|
||||
|
||||
renderSelection(context.pose())
|
||||
}
|
||||
|
||||
private fun getDimensions(): Pair<Int, Int> {
|
||||
@@ -498,7 +454,4 @@ 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()) || isFocused)
|
||||
val hovered = (isHovered(pMouseX.toDouble(), pMouseY.toDouble()))
|
||||
blitk(
|
||||
matrixStack = context.pose(),
|
||||
x = x / SCALE,
|
||||
|
||||
+11
-31
@@ -14,9 +14,6 @@ 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
|
||||
@@ -39,7 +36,7 @@ class MoveSelectConfiguration(
|
||||
|
||||
class MoveSelectGUI(
|
||||
val config: MoveSelectConfiguration
|
||||
) : Screen(Component.translatable("cobblemon.ui.interact.moveselect")), CobblemonRenderable, ControllerScreen {
|
||||
) : Screen(Component.translatable("cobblemon.ui.interact.moveselect")), CobblemonRenderable {
|
||||
companion object {
|
||||
const val WIDTH = 122
|
||||
const val HEIGHT = 133
|
||||
@@ -49,8 +46,6 @@ class MoveSelectGUI(
|
||||
|
||||
var closed = false
|
||||
|
||||
val controllerComponentManager = ControllerComponentManager(this)
|
||||
|
||||
constructor(
|
||||
title: MutableComponent,
|
||||
moves: List<MoveSelectDTO>,
|
||||
@@ -68,10 +63,6 @@ class MoveSelectGUI(
|
||||
)
|
||||
)
|
||||
|
||||
override fun getComponentManager(): ControllerComponentManager {
|
||||
return controllerComponentManager
|
||||
}
|
||||
|
||||
fun closeProperly() {
|
||||
closed = true
|
||||
onClose()
|
||||
@@ -82,21 +73,16 @@ class MoveSelectGUI(
|
||||
val y = (height - HEIGHT) / 2
|
||||
|
||||
config.moves.forEachIndexed { index, 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}"] }
|
||||
}
|
||||
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) }
|
||||
)
|
||||
}
|
||||
|
||||
// Add Exit Button
|
||||
@@ -111,10 +97,6 @@ class MoveSelectGUI(
|
||||
)
|
||||
|
||||
super.init()
|
||||
|
||||
controllerComponentManager.let {
|
||||
it.focused = it.componentList["move_0"]
|
||||
}
|
||||
}
|
||||
|
||||
override fun render(context: GuiGraphics, mouseX: Int, mouseY: Int, partialTicks: Float) {
|
||||
@@ -132,8 +114,6 @@ 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) || isFocused) && enabled
|
||||
isHovered = pMouseX >= x && pMouseY >= y && pMouseX < x + width && pMouseY < y + height && enabled
|
||||
|
||||
val moveTemplate = Moves.getByNameOrDummy(move.name)
|
||||
val rgb = moveTemplate.elementalType.hue.toRGB()
|
||||
|
||||
+15
-39
@@ -16,9 +16,6 @@ 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
|
||||
@@ -41,7 +38,7 @@ class PartySelectConfiguration(
|
||||
)
|
||||
class PartySelectGUI(
|
||||
val config: PartySelectConfiguration
|
||||
) : Screen(Component.translatable("cobblemon.ui.interact.moveselect")), CobblemonRenderable, ControllerScreen {
|
||||
) : Screen(Component.translatable("cobblemon.ui.interact.moveselect")), CobblemonRenderable {
|
||||
companion object {
|
||||
const val WIDTH = 163
|
||||
const val HEIGHT = 132
|
||||
@@ -53,8 +50,6 @@ class PartySelectGUI(
|
||||
|
||||
var closed = false
|
||||
|
||||
val controllerComponentManager = ControllerComponentManager(this)
|
||||
|
||||
constructor(
|
||||
title: MutableComponent,
|
||||
pokemon: List<PartySelectPokemonDTO>,
|
||||
@@ -72,10 +67,6 @@ class PartySelectGUI(
|
||||
)
|
||||
)
|
||||
|
||||
override fun getComponentManager(): ControllerComponentManager {
|
||||
return controllerComponentManager
|
||||
}
|
||||
|
||||
fun closeProperly() {
|
||||
closed = true
|
||||
onClose()
|
||||
@@ -99,29 +90,20 @@ class PartySelectGUI(
|
||||
slotY += (31 * offsetIndex) + offsetY
|
||||
}
|
||||
|
||||
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}"] }
|
||||
}
|
||||
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) }
|
||||
)
|
||||
}
|
||||
|
||||
// Add Exit Button
|
||||
@@ -136,10 +118,6 @@ class PartySelectGUI(
|
||||
)
|
||||
|
||||
super.init()
|
||||
|
||||
controllerComponentManager.let {
|
||||
it.focused = it.componentList["slot_0_0"]
|
||||
}
|
||||
}
|
||||
|
||||
override fun render(context: GuiGraphics, mouseX: Int, mouseY: Int, partialTicks: Float) {
|
||||
@@ -177,8 +155,6 @@ class PartySelectGUI(
|
||||
|
||||
// Render all added Widgets
|
||||
super.render(context, mouseX, mouseY, partialTicks)
|
||||
|
||||
renderSelection(context.pose())
|
||||
}
|
||||
|
||||
private fun onPress(pokemon: PartySelectPokemonDTO) {
|
||||
|
||||
+1
-1
@@ -63,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) || isFocused) && enabled
|
||||
isHovered = pMouseX >= x && pMouseY >= y && pMouseX < x + width && pMouseY < y + height && enabled
|
||||
val alpha = if (enabled) 1.0 else 0.7
|
||||
val matrices = context.pose()
|
||||
|
||||
|
||||
+4
-4
@@ -28,7 +28,7 @@ class InteractWheelButton(
|
||||
private val tooltipText: String?,
|
||||
x: Int,
|
||||
y: Int,
|
||||
val isEnabled: Boolean,
|
||||
private 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()) || isFocused) && isEnabled) height else 0,
|
||||
vOffset = if (isHovered(mouseX.toFloat(), mouseY.toFloat()) && isEnabled) height else 0,
|
||||
textureHeight = height * 2,
|
||||
alpha = if (isEnabled) 1f else 0.4F
|
||||
)
|
||||
|
||||
if(isEnabled && (isHovered(mouseX.toFloat(), mouseY.toFloat()) || isFocused)){
|
||||
if(isEnabled && isHovered(mouseX.toFloat(), mouseY.toFloat())){
|
||||
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()) || isFocused) super.mouseClicked(mouseX, mouseY, button) else false
|
||||
return if (isHovered(mouseX.toFloat(), mouseY.toFloat())) 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")
|
||||
}
|
||||
|
||||
val buttons = mutableListOf<InteractWheelButton>()
|
||||
var maxPage = 1
|
||||
var currentPage = 0
|
||||
private val buttons = mutableListOf<InteractWheelButton>()
|
||||
private var maxPage = 1
|
||||
private 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.entries.toTypedArray()
|
||||
val orientations = Orientation.values()
|
||||
orientations.forEach { orientation ->
|
||||
val option = options[orientation].toList().getOrNull(page)
|
||||
addButton(orientation, option)
|
||||
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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.gui.party
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonItems
|
||||
import com.cobblemon.mod.common.api.text.darkGray
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.client.CobblemonClient
|
||||
import com.cobblemon.mod.common.client.gui.toast.CobblemonToast
|
||||
import com.cobblemon.mod.common.client.keybind.boundKey
|
||||
import com.cobblemon.mod.common.client.keybind.keybinds.DownShiftPartyBinding
|
||||
import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding
|
||||
import com.cobblemon.mod.common.client.keybind.keybinds.UpShiftPartyBinding
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.party.PartyTutorialPacket
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.mojang.blaze3d.platform.InputConstants
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.components.toasts.Toast
|
||||
import net.minecraft.client.gui.components.toasts.AdvancementToast
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.util.Mth
|
||||
|
||||
object PartyTutorialToasts {
|
||||
|
||||
private var toastAttached = false
|
||||
|
||||
val upKey = UpShiftPartyBinding.boundKey()
|
||||
val downKey = DownShiftPartyBinding.boundKey()
|
||||
|
||||
val upDisplay =
|
||||
if (upKey.type == InputConstants.Type.KEYSYM && upKey.value == InputConstants.KEY_UP)
|
||||
Component.literal("↑")
|
||||
else upKey.displayName
|
||||
|
||||
val downDisplay =
|
||||
if (downKey.type == InputConstants.Type.KEYSYM && downKey.value == InputConstants.KEY_DOWN)
|
||||
Component.literal("↓")
|
||||
else downKey.displayName
|
||||
|
||||
private val toast = CobblemonToast(
|
||||
Mth.createInsecureUUID(),
|
||||
CobblemonItems.POKEDEX_RED.defaultInstance,
|
||||
lang("ui.party.party_select_title").red(),
|
||||
lang(
|
||||
"ui.party.party_select_description",
|
||||
upDisplay,
|
||||
downDisplay,
|
||||
PartySendBinding.boundKey().displayName
|
||||
).darkGray(),
|
||||
AdvancementToast.BACKGROUND_SPRITE,
|
||||
-1F,
|
||||
0
|
||||
)
|
||||
|
||||
fun reset() {
|
||||
toastAttached = false
|
||||
}
|
||||
|
||||
fun onOverlayRender(partySize: Int) {
|
||||
if (partySize <= 1) return
|
||||
|
||||
if (!CobblemonClient.clientPlayerData.partySelectTutorialDone) {
|
||||
showToast()
|
||||
}
|
||||
}
|
||||
|
||||
fun onArrowKeySwitchedSlot() {
|
||||
if (CobblemonClient.clientPlayerData.partySelectTutorialDone) return
|
||||
if (CobblemonClient.storage.party.count { it != null } < 2) return
|
||||
PartyTutorialPacket().sendToServer()
|
||||
hideToast()
|
||||
}
|
||||
|
||||
fun onHoldKeyScrollSwitchedSlot() {
|
||||
if (CobblemonClient.clientPlayerData.partySelectTutorialDone) return
|
||||
if (CobblemonClient.storage.party.count { it != null } < 2) return
|
||||
PartyTutorialPacket().sendToServer()
|
||||
hideToast()
|
||||
}
|
||||
|
||||
private fun showToast() {
|
||||
val minecraft = Minecraft.getInstance()
|
||||
if (!toastAttached) {
|
||||
toast.nextVisibility = Toast.Visibility.SHOW
|
||||
minecraft.toasts.addToast(toast)
|
||||
toastAttached = true
|
||||
}
|
||||
}
|
||||
|
||||
private fun hideToast() {
|
||||
if (toastAttached) toast.nextVisibility = Toast.Visibility.HIDE
|
||||
}
|
||||
}
|
||||
+3
-54
@@ -19,7 +19,6 @@ 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
|
||||
@@ -77,58 +76,11 @@ 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) {}
|
||||
@@ -214,8 +166,6 @@ 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
|
||||
@@ -232,7 +182,7 @@ class PasturePokemonScrollList(
|
||||
setEnabled(PokemonBehaviourFlag.PASTURE_CONFLICT in pokemon.behaviourFlags)
|
||||
}
|
||||
|
||||
val moveButton: PastureSlotIconButton = PastureSlotIconButton(
|
||||
private val moveButton: PastureSlotIconButton = PastureSlotIconButton(
|
||||
xPos = 0,
|
||||
yPos = 0,
|
||||
onPress = {
|
||||
@@ -241,8 +191,7 @@ class PasturePokemonScrollList(
|
||||
pastureId = parent.pasturePCGUIConfiguration.pastureId,
|
||||
pokemonId = pokemon.pokemonId
|
||||
).sendToServer()
|
||||
},
|
||||
parent = this@PastureSlot
|
||||
}
|
||||
)
|
||||
|
||||
override fun getNarration() = pokemon.displayName
|
||||
@@ -270,7 +219,7 @@ class PasturePokemonScrollList(
|
||||
y = y,
|
||||
height = SLOT_HEIGHT,
|
||||
width = rowWidth,
|
||||
vOffset = if (isHovered || controllerFocused) SLOT_HEIGHT else 0,
|
||||
vOffset = if (isHovered) SLOT_HEIGHT else 0,
|
||||
textureHeight = SLOT_HEIGHT * 2
|
||||
)
|
||||
|
||||
|
||||
+2
-3
@@ -18,8 +18,7 @@ import net.minecraft.network.chat.Component
|
||||
|
||||
class PastureSlotIconButton(
|
||||
var xPos: Int, var yPos: Int,
|
||||
onPress: OnPress,
|
||||
var parent: PasturePokemonScrollList.PastureSlot
|
||||
onPress: OnPress
|
||||
) : Button(xPos, yPos, (SIZE * SCALE).toInt(), (SIZE * SCALE).toInt(), Component.literal("Pasture Move"), onPress, DEFAULT_NARRATION), CobblemonRenderable {
|
||||
|
||||
companion object {
|
||||
@@ -36,7 +35,7 @@ class PastureSlotIconButton(
|
||||
y = yPos / SCALE,
|
||||
width = SIZE,
|
||||
height = SIZE,
|
||||
vOffset = if (isHovered(mouseX.toDouble(), mouseY.toDouble()) || parent.controllerFocused) SIZE else 0,
|
||||
vOffset = if (isHovered(mouseX.toDouble(), mouseY.toDouble())) SIZE else 0,
|
||||
textureHeight = SIZE * 2,
|
||||
texture = baseResource,
|
||||
scale = SCALE
|
||||
|
||||
@@ -15,8 +15,6 @@ 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
|
||||
@@ -36,9 +34,6 @@ 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
|
||||
@@ -53,23 +48,6 @@ 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()) || isFocused) HEIGHT else 0,
|
||||
vOffset = if (isHovered(mouseX.toDouble(), mouseY.toDouble())) HEIGHT else 0,
|
||||
textureHeight = HEIGHT * 2
|
||||
)
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ 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
|
||||
@@ -29,10 +28,6 @@ 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
|
||||
@@ -49,15 +44,12 @@ 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,
|
||||
@@ -65,7 +57,7 @@ class PCGUI(
|
||||
val configuration: PCGUIConfiguration,
|
||||
val openOnBox: Int = CobblemonClient.lastPcBoxViewed,
|
||||
val unseenWallpapers: MutableSet<ResourceLocation> = mutableSetOf()
|
||||
) : Screen(Component.translatable("cobblemon.ui.pc.title")), CobblemonRenderable, ControllerScreen {
|
||||
) : Screen(Component.translatable("cobblemon.ui.pc.title")), CobblemonRenderable {
|
||||
|
||||
companion object {
|
||||
const val BASE_WIDTH = 349
|
||||
@@ -136,14 +128,6 @@ 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) {}
|
||||
@@ -214,39 +198,30 @@ 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()
|
||||
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)
|
||||
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 }
|
||||
)
|
||||
|
||||
// Add Wallpaper Widget
|
||||
this.wallpaperWidget = WallpapersScrollingWidget(
|
||||
@@ -262,7 +237,7 @@ class PCGUI(
|
||||
this.addRenderableWidget(wallpaperWidget)
|
||||
|
||||
// Add Wallpaper Settings Button
|
||||
wallpaperButton = IconButton(
|
||||
this.addRenderableWidget(IconButton(
|
||||
pX = x + 242,
|
||||
pY = y + 31,
|
||||
buttonWidth = 20,
|
||||
@@ -275,16 +250,14 @@ 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()
|
||||
val button = IconButton(
|
||||
this.addRenderableWidget(IconButton(
|
||||
pX = x + 92 + (12 * index),
|
||||
pY = y + 31,
|
||||
buttonWidth = 20,
|
||||
@@ -295,58 +268,33 @@ class PCGUI(
|
||||
label = "sort_${typeName}"
|
||||
) {
|
||||
storageWidget.resetSelected()
|
||||
SortPCBoxPacket(pc.uuid, storageWidget.box, sortType, hasShiftDown() || (controllerComponentManager.active && controllerShiftToggle)).sendToServer()
|
||||
SortPCBoxPacket(pc.uuid, storageWidget.box, sortType, hasShiftDown()).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)
|
||||
|
||||
|
||||
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(
|
||||
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
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
addRenderableWidget(
|
||||
IconButton(
|
||||
@@ -364,149 +312,6 @@ 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) {
|
||||
@@ -880,7 +685,7 @@ class PCGUI(
|
||||
)
|
||||
|
||||
if (!optionButtons.isEmpty() && displayOptions) {
|
||||
for (button in optionButtons) button.showAlt = hasShiftDown() || (controllerComponentManager.active && controllerShiftToggle)
|
||||
for (button in optionButtons) button.showAlt = hasShiftDown()
|
||||
}
|
||||
|
||||
super.render(context, mouseX, mouseY, delta)
|
||||
@@ -895,8 +700,6 @@ 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 {
|
||||
const val WIDTH = 58
|
||||
const val HEIGHT = 16
|
||||
private const val WIDTH = 58
|
||||
private 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()) || isFocused) HEIGHT else 0,
|
||||
vOffset = if (isHovered(mouseX.toDouble(), mouseY.toDouble())) 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 {
|
||||
const val WIDTH = 30
|
||||
const val HEIGHT = 13
|
||||
private const val WIDTH = 30
|
||||
private 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()) || isFocused) HEIGHT else 0,
|
||||
vOffset = if (isHovered(mouseX.toDouble(), mouseY.toDouble())) HEIGHT else 0,
|
||||
textureHeight = HEIGHT * 2
|
||||
)
|
||||
|
||||
|
||||
@@ -20,9 +20,6 @@ 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
|
||||
@@ -44,7 +41,6 @@ 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,
|
||||
@@ -95,9 +91,6 @@ class StorageWidget(
|
||||
this.setupStorageSlots()
|
||||
}
|
||||
|
||||
val controllerComponentManager = ControllerComponentManager(pcGui)
|
||||
var grabbedSlotControllerPos = Vector2i()
|
||||
|
||||
init {
|
||||
this.setupStorageSlots()
|
||||
|
||||
@@ -109,7 +102,6 @@ class StorageWidget(
|
||||
if (!displayConfirmRelease && canDeleteSelected()) {
|
||||
displayConfirmRelease = true
|
||||
playSound(CobblemonSounds.PC_CLICK)
|
||||
controllerComponentManager.focused = controllerComponentManager.componentList["release_no"]
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -134,7 +126,6 @@ class StorageWidget(
|
||||
playSound(CobblemonSounds.PC_RELEASE)
|
||||
resetSelected()
|
||||
displayConfirmRelease = false
|
||||
controllerComponentManager.focused = controllerComponentManager.componentList["slot_0_0"]
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -148,7 +139,6 @@ class StorageWidget(
|
||||
if (displayConfirmRelease) {
|
||||
displayConfirmRelease = false
|
||||
playSound(CobblemonSounds.PC_CLICK)
|
||||
controllerComponentManager.focused = controllerComponentManager.componentList["release"]
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -156,47 +146,6 @@ 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 {
|
||||
@@ -215,7 +164,7 @@ class StorageWidget(
|
||||
|
||||
for (row in 1..5) {
|
||||
for (col in 1..6) {
|
||||
val slot = BoxStorageSlot(
|
||||
BoxStorageSlot(
|
||||
x = boxStartX + ((col - 1) * (StorageSlot.SIZE + BOX_SLOT_PADDING)),
|
||||
y = boxStartY + ((row - 1) * (StorageSlot.SIZE + BOX_SLOT_PADDING)),
|
||||
parent = this,
|
||||
@@ -227,27 +176,6 @@ 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() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +194,7 @@ class StorageWidget(
|
||||
partyY += ((StorageSlot.SIZE + PARTY_SLOT_PADDING) * offsetIndex) + offsetY
|
||||
}
|
||||
|
||||
val slot = PartyStorageSlot(
|
||||
PartyStorageSlot(
|
||||
x = partyX,
|
||||
y = partyY,
|
||||
parent = this,
|
||||
@@ -277,22 +205,6 @@ 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() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,7 +307,7 @@ class StorageWidget(
|
||||
this.boxSlots.forEach { slot ->
|
||||
slot.render(context, mouseX, mouseY, delta)
|
||||
val pokemon = slot.getPokemon()
|
||||
if (grabbedSlot == null && (slot.isHovered(mouseX, mouseY) || slot.isFocused)
|
||||
if (grabbedSlot == null && slot.isHovered(mouseX, mouseY)
|
||||
&& pokemon != null && pokemon != pcGui.previewPokemon
|
||||
) {
|
||||
pcGui.setPreviewPokemon(pokemon, pcGui.isPreviewInParty ?: false)
|
||||
@@ -411,7 +323,7 @@ class StorageWidget(
|
||||
this.partySlots.forEach { slot ->
|
||||
slot.render(context, mouseX, mouseY, delta)
|
||||
val pokemon = slot.getPokemon()
|
||||
if (grabbedSlot == null && (slot.isHovered(mouseX, mouseY) || slot.isFocused)
|
||||
if (grabbedSlot == null && slot.isHovered(mouseX, mouseY)
|
||||
&& pokemon != null && pokemon != pcGui.previewPokemon
|
||||
) {
|
||||
pcGui.setPreviewPokemon(pokemon, pcGui.isPreviewInParty ?: true)
|
||||
@@ -423,11 +335,7 @@ class StorageWidget(
|
||||
pastureWidget?.render(context, mouseX, mouseY, delta)
|
||||
matrices.pushPose()
|
||||
matrices.translate(0.0, 0.0, 1000.0)
|
||||
if (controllerComponentManager.active) {
|
||||
grabbedSlot?.render(context, grabbedSlotControllerPos.x, grabbedSlotControllerPos.y, delta)
|
||||
} else {
|
||||
grabbedSlot?.render(context, mouseX, mouseY, delta)
|
||||
}
|
||||
grabbedSlot?.render(context, mouseX, mouseY, delta)
|
||||
matrices.popPose()
|
||||
}
|
||||
|
||||
@@ -464,9 +372,6 @@ 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
|
||||
|
||||
+8
-36
@@ -15,8 +15,6 @@ 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
|
||||
@@ -51,14 +49,10 @@ 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
|
||||
@@ -96,24 +90,6 @@ 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
|
||||
}
|
||||
@@ -140,7 +116,7 @@ class WallpapersScrollingWidget(
|
||||
partialTick: Float
|
||||
) {
|
||||
val matrices = guiGraphics.pose()
|
||||
val resource = if ((Screen.hasShiftDown() || (pcGui.controllerComponentManager.active && pcGui.controllerShiftToggle)) && altWallpaper !== null) altWallpaper else wallpaper
|
||||
val resource = if (Screen.hasShiftDown() && altWallpaper !== null) altWallpaper else wallpaper
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = resource,
|
||||
@@ -157,28 +133,24 @@ class WallpapersScrollingWidget(
|
||||
y = top + SLOT_PADDING,
|
||||
width = width,
|
||||
height = SLOT_HEIGHT,
|
||||
vOffset = if (hovering || isFocused) SLOT_HEIGHT else 0,
|
||||
vOffset = if (hovering) 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)) {
|
||||
selectWallpaper()
|
||||
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))
|
||||
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,7 +15,6 @@ 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
|
||||
@@ -26,6 +25,7 @@ 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,9 +42,6 @@ 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
|
||||
@@ -64,8 +61,6 @@ 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
|
||||
@@ -77,7 +72,7 @@ class PokedexGUI private constructor(
|
||||
val type: PokedexType,
|
||||
val initSpecies: ResourceLocation?,
|
||||
val blockPos: BlockPos?
|
||||
): Screen(Component.translatable("cobblemon.ui.pokedex.title")), CobblemonRenderable, ControllerScreen {
|
||||
): Screen(Component.translatable("cobblemon.ui.pokedex.title")), CobblemonRenderable {
|
||||
companion object {
|
||||
private val screenBackground = cobblemonResource("textures/gui/pokedex/pokedex_screen.png")
|
||||
|
||||
@@ -142,14 +137,6 @@ 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) {}
|
||||
|
||||
@@ -222,232 +209,6 @@ 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) {
|
||||
@@ -559,8 +320,6 @@ 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()
|
||||
@@ -676,45 +435,6 @@ 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() }
|
||||
|
||||
fun switchAbility(nextIndex: Boolean) {
|
||||
private fun switchAbility(nextIndex: Boolean) {
|
||||
val size = abilitiesList.size
|
||||
selectedAbilitiesIndex = if (nextIndex) {
|
||||
(selectedAbilitiesIndex + 1) % size
|
||||
|
||||
+2
-3
@@ -48,6 +48,7 @@ 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()
|
||||
@@ -128,8 +129,6 @@ 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,
|
||||
@@ -171,7 +170,7 @@ class EntriesScrollingWidget(val pX: Int, val pY: Int, val setPokedexEntry: (Pok
|
||||
height = SCROLL_SLOT_SIZE
|
||||
)
|
||||
|
||||
if (getHoveredSlotIndex(mouseX, mouseY) == index || slotControllerSelected == index) {
|
||||
if (getHoveredSlotIndex(mouseX, mouseY) == index) {
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = slotHighlight,
|
||||
|
||||
+15
-9
@@ -59,7 +59,6 @@ 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,
|
||||
@@ -187,7 +186,7 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
|
||||
|
||||
val variationButtons = mutableListOf<VariationButtonWrapper>()
|
||||
|
||||
val genderButton: ScaledButton = ScaledButton(
|
||||
private val genderButton: ScaledButton = ScaledButton(
|
||||
pX + 114F,
|
||||
pY + 27F,
|
||||
20,
|
||||
@@ -199,7 +198,7 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
|
||||
}
|
||||
).apply { addWidget(this) }
|
||||
|
||||
val shinyButton: ScaledButton = ScaledButton(
|
||||
private val shinyButton: ScaledButton = ScaledButton(
|
||||
(pX + 126F),
|
||||
(pY + 27F),
|
||||
20,
|
||||
@@ -365,9 +364,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,
|
||||
50.0
|
||||
1000.0 // Prevent model from clipping into background
|
||||
)
|
||||
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
|
||||
matrices.scale(scaleAmount, scaleAmount, scaleAmount)
|
||||
val rotationVector = Vector3f(13F, rotationY, 0F)
|
||||
|
||||
drawProfilePokemon(
|
||||
@@ -376,7 +375,8 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
|
||||
matrixStack = matrices,
|
||||
partialTicks = delta,
|
||||
rotation = Quaternionf().fromEulerXYZDegrees(rotationVector),
|
||||
state = state
|
||||
state = state,
|
||||
blockLight = 15
|
||||
)
|
||||
|
||||
matrices.popPose()
|
||||
@@ -393,6 +393,10 @@ 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]
|
||||
@@ -504,6 +508,8 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
matrices.popPose()
|
||||
}
|
||||
|
||||
fun setDexEntry(pokedexEntry : PokedexEntry) {
|
||||
@@ -581,12 +587,12 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
|
||||
type = arrayOf(form.primaryType, form.secondaryType)
|
||||
}
|
||||
|
||||
fun playCry() {
|
||||
private fun playCry() {
|
||||
state.activeAnimations.clear()
|
||||
state.addFirstAnimation(setOf("cry"))
|
||||
}
|
||||
|
||||
fun switchForm(nextIndex: Boolean) {
|
||||
private fun switchForm(nextIndex: Boolean) {
|
||||
if (visibleForms.isEmpty() || currentEntry == null) {
|
||||
return
|
||||
}
|
||||
@@ -607,7 +613,7 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
|
||||
updateAspects()
|
||||
}
|
||||
|
||||
fun switchPose(nextIndex: Boolean) {
|
||||
private fun switchPose(nextIndex: Boolean) {
|
||||
if (nextIndex) {
|
||||
if (selectedPoseIndex < poseList.lastIndex) selectedPoseIndex++
|
||||
else selectedPoseIndex = 0
|
||||
|
||||
+5
-41
@@ -9,9 +9,6 @@
|
||||
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
|
||||
|
||||
@@ -23,12 +20,10 @@ 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), ControllerScreen {
|
||||
class SnapshotWarningScreen(val consumer: (Acknowledgement, Boolean) -> Unit) : Screen(TITLE) {
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -41,12 +36,6 @@ 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()
|
||||
|
||||
@@ -56,42 +45,17 @@ 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)
|
||||
|
||||
val checkbox = Checkbox.builder(Component.translatable("cobblemon.snapshots.warning.dont_show_again"), Minecraft.getInstance().font)
|
||||
helper.addChild(Checkbox.builder(Component.translatable("cobblemon.snapshots.warning.dont_show_again"), Minecraft.getInstance().font)
|
||||
.selected(dontShowAgain)
|
||||
.tooltip(Tooltip.create(DONT_SHOW_AGAIN_TIP))
|
||||
.build()
|
||||
helper.addChild(checkbox, 2, settings)
|
||||
.build(), 2, settings)
|
||||
|
||||
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)
|
||||
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())
|
||||
|
||||
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() {
|
||||
|
||||
+190
-247
@@ -15,21 +15,19 @@ import com.cobblemon.mod.common.api.gui.ColourLibrary
|
||||
import com.cobblemon.mod.common.api.gui.MultiLineLabelK
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.text.bold
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.client.CobblemonClient
|
||||
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.VariableObjectSelectionScrollbar
|
||||
import com.cobblemon.mod.common.client.gui.startselection.widgets.CategoryList
|
||||
import com.cobblemon.mod.common.client.gui.startselection.widgets.ExitButton
|
||||
import com.cobblemon.mod.common.client.gui.startselection.widgets.preview.ArrowButton
|
||||
import com.cobblemon.mod.common.client.gui.startselection.widgets.preview.SelectionButton
|
||||
import com.cobblemon.mod.common.client.gui.startselection.widgets.SelectionButton
|
||||
import com.cobblemon.mod.common.client.gui.startselection.widgets.preview.StarterRoundabout
|
||||
import com.cobblemon.mod.common.client.gui.summary.Summary.Companion.PARTY
|
||||
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
|
||||
@@ -37,15 +35,14 @@ import com.cobblemon.mod.common.pokemon.RenderablePokemon
|
||||
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.math.toRGB
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
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.resources.ResourceLocation
|
||||
import net.minecraft.sounds.SoundEvent
|
||||
import org.joml.Vector4i
|
||||
import java.io.FileNotFoundException
|
||||
|
||||
/**
|
||||
* Starterselection Screen Thingy
|
||||
@@ -53,41 +50,32 @@ import org.joml.Vector4i
|
||||
* @author Qu
|
||||
* @since 2022-06-18
|
||||
*/
|
||||
class StarterSelectionScreen(private val categories: List<RenderableStarterCategory>): Screen("cobblemon.ui.starter.title".asTranslated()), CobblemonRenderable, ControllerScreen {
|
||||
|
||||
class StarterSelectionScreen(private val categories: List<RenderableStarterCategory>): Screen("cobblemon.ui.starter.title".asTranslated()), CobblemonRenderable {
|
||||
companion object {
|
||||
// Size of UI at scale 1
|
||||
private const val BASE_WIDTH = 200
|
||||
private const val BASE_HEIGHT = 175
|
||||
private const val BASE_WIDTH = 239
|
||||
private const val BASE_HEIGHT = 197
|
||||
|
||||
// Resources
|
||||
private val base = cobblemonResource("textures/gui/starterselection/starterselection_base.png")
|
||||
private val baseUnderlay = cobblemonResource("textures/gui/starterselection/starterselection_base_underlay.png")
|
||||
private val baseFrame = cobblemonResource("textures/gui/starterselection/starterselection_base_frame.png")
|
||||
private val baseResource = cobblemonResource("textures/gui/starterselection/base.png")
|
||||
private val backgroundResource = cobblemonResource("textures/gui/starterselection/background.png")
|
||||
private val backgroundBallResource = cobblemonResource("textures/gui/starterselection/background_poke_ball.png")
|
||||
|
||||
// Type Backgrounds
|
||||
private val singleTypeBackground = cobblemonResource("textures/gui/starterselection/starterselection_type_slot1.png")
|
||||
private val doubleTypeBackground = cobblemonResource("textures/gui/starterselection/starterselection_type_slot2.png")
|
||||
private val platformResource = cobblemonResource("textures/gui/starterselection/platform_base.png")
|
||||
private val platformShadow = cobblemonResource("textures/gui/pokedex/platform_shadow.png")
|
||||
private val typeSpacerResource = cobblemonResource("textures/gui/starterselection/type_spacer_single.png")
|
||||
private val ballResource = cobblemonResource("textures/item/poke_balls/poke_ball.png")
|
||||
}
|
||||
|
||||
private var currentSelection = 0
|
||||
private lateinit var currentCategory: RenderableStarterCategory
|
||||
var currentSelection = 0
|
||||
lateinit var currentCategory: RenderableStarterCategory
|
||||
private lateinit var modelWidget: ModelWidget
|
||||
private lateinit var currentPokemon: RenderablePokemon
|
||||
private lateinit var typeWidget: TypeWidget
|
||||
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
|
||||
var ticksElapsed = 0
|
||||
var currentBallBackgroundFrame = 0
|
||||
|
||||
override fun getComponentManager(): ControllerComponentManager {
|
||||
return controllerComponentManager
|
||||
}
|
||||
|
||||
override fun renderBlurredBackground(delta: Float) { }
|
||||
override fun renderBlurredBackground(delta: Float) {}
|
||||
|
||||
override fun renderMenuBackground(context: GuiGraphics) {}
|
||||
|
||||
@@ -108,55 +96,24 @@ class StarterSelectionScreen(private val categories: List<RenderableStarterCateg
|
||||
return
|
||||
}
|
||||
|
||||
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,
|
||||
right = true
|
||||
) {
|
||||
right()
|
||||
}
|
||||
|
||||
val leftButton = ArrowButton(
|
||||
pX = x + 72, pY = y + 151,
|
||||
pWidth = 9, pHeight = 14,
|
||||
right = false
|
||||
) {
|
||||
left()
|
||||
}
|
||||
|
||||
addRenderableWidget(rightButton)
|
||||
addRenderableWidget(leftButton)
|
||||
|
||||
currentCategory = categories.first()
|
||||
currentPokemon = currentCategory.pokemon[currentSelection]
|
||||
|
||||
with(currentPokemon) {
|
||||
modelWidget = ModelWidget(
|
||||
pX = x + 85, pY = y + 50,
|
||||
pWidth = 102, pHeight = 100,
|
||||
pX = x + 6, pY = y + 17,
|
||||
pWidth = 118, pHeight = 100,
|
||||
pokemon = this,
|
||||
baseScale = 2.0f,
|
||||
baseScale = 2.7f,
|
||||
playCryOnClick = true,
|
||||
offsetY = -12.0
|
||||
)
|
||||
|
||||
typeWidget = typeWidget(this, x, y)
|
||||
}
|
||||
|
||||
addRenderableWidget(modelWidget)
|
||||
|
||||
val selectionButton = SelectionButton(
|
||||
pX = x + 106, pY = y + 124,
|
||||
pX = x + 13, pY = y + 180,
|
||||
pWidth = SelectionButton.BUTTON_WIDTH, pHeight = SelectionButton.BUTTON_HEIGHT
|
||||
) {
|
||||
CobblemonNetwork.sendToServer(
|
||||
@@ -165,228 +122,214 @@ class StarterSelectionScreen(private val categories: List<RenderableStarterCateg
|
||||
selected = currentSelection
|
||||
)
|
||||
)
|
||||
Minecraft.getInstance().setScreen(null)
|
||||
playSound(CobblemonSounds.GUI_CLICK)
|
||||
onClose()
|
||||
}
|
||||
|
||||
addRenderableWidget(selectionButton)
|
||||
|
||||
starterRoundaboutCenter = StarterRoundabout(
|
||||
pX = x + 119, pY = height / 2 + 84,
|
||||
pWidth = StarterRoundabout.MODEL_WIDTH, pHeight = StarterRoundabout.MODEL_HEIGHT,
|
||||
pokemon = currentPokemon,
|
||||
rotationVector = this.modelWidget.rotationVector
|
||||
)
|
||||
|
||||
starterRoundaboutLeft = StarterRoundabout(
|
||||
pX = x + 89, pY = height / 2 + 84,
|
||||
pWidth = StarterRoundabout.MODEL_WIDTH, pHeight = StarterRoundabout.MODEL_HEIGHT,
|
||||
pokemon = currentCategory.pokemon[leftOfCurrentSelection()],
|
||||
clickAction = { _, _ -> this.left() },
|
||||
rotationVector = this.modelWidget.rotationVector
|
||||
)
|
||||
|
||||
starterRoundaboutRight = StarterRoundabout(
|
||||
pX = x + 149, pY = height / 2 + 84,
|
||||
pWidth = StarterRoundabout.MODEL_WIDTH, pHeight = StarterRoundabout.MODEL_HEIGHT,
|
||||
pokemon = currentCategory.pokemon[rightOfCurrentSelection()],
|
||||
clickAction = { _, _ -> this.right() },
|
||||
rotationVector = this.modelWidget.rotationVector
|
||||
)
|
||||
|
||||
addRenderableWidget(starterRoundaboutLeft)
|
||||
addRenderableWidget(starterRoundaboutCenter)
|
||||
addRenderableWidget(starterRoundaboutRight)
|
||||
|
||||
// Add Exit Button
|
||||
addRenderableWidget(
|
||||
ExitButton(
|
||||
pX = x + 181, pY = y + 2,
|
||||
pWidth = 16, pHeight = 12,
|
||||
pXTexStart = 0, pYTexStart = 0, pYDiffText = 0
|
||||
) {
|
||||
Minecraft.getInstance().setScreen(null)
|
||||
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(CobblemonSounds.GUI_CLICK, 1.0F))
|
||||
ExitButton(pX = x + 210, pY = y + 181) {
|
||||
playSound(CobblemonSounds.GUI_CLICK)
|
||||
onClose()
|
||||
}
|
||||
)
|
||||
|
||||
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")
|
||||
))
|
||||
}
|
||||
}
|
||||
val categoryList = CategoryList(
|
||||
paneWidth = 97, paneHeight = 145,
|
||||
categories = categories,
|
||||
listX = x + 134, listY = y + 27,
|
||||
starterSelectionScreen = this
|
||||
)
|
||||
addRenderableWidget(categoryList)
|
||||
|
||||
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
|
||||
addRenderableWidget(VariableObjectSelectionScrollbar(
|
||||
parent = categoryList,
|
||||
x = x + 231,
|
||||
y = y + 27,
|
||||
width = 3,
|
||||
height = 145
|
||||
))
|
||||
}
|
||||
|
||||
override fun render(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
val matrices = context.pose()
|
||||
val x = (width - BASE_WIDTH) / 2
|
||||
val y = (height - BASE_HEIGHT) / 2
|
||||
// Render Underlay
|
||||
|
||||
//Background
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = baseUnderlay,
|
||||
x = x, y = y,
|
||||
width = BASE_WIDTH, height = BASE_HEIGHT
|
||||
texture = backgroundResource,
|
||||
x = x + 6,
|
||||
y = y + 17,
|
||||
width = 118,
|
||||
height = 100
|
||||
)
|
||||
// Render Base
|
||||
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = base,
|
||||
x = x, y = y,
|
||||
width = BASE_WIDTH, height = BASE_HEIGHT
|
||||
texture = backgroundBallResource,
|
||||
x = x + 10.5,
|
||||
y = y + 12.5,
|
||||
width = 109,
|
||||
height = 109,
|
||||
textureHeight = 1744,
|
||||
vOffset = currentBallBackgroundFrame * 109
|
||||
)
|
||||
// Render Frame
|
||||
val (r, g, b) = currentPokemon.form.primaryType.hue.toRGB()
|
||||
|
||||
//Platform
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = baseFrame,
|
||||
red = r,
|
||||
green = g,
|
||||
blue = b,
|
||||
x = x, y = y,
|
||||
width = BASE_WIDTH, height = BASE_HEIGHT
|
||||
texture = platformResource,
|
||||
x = x + 8.5,
|
||||
y = y + 88,
|
||||
width = 113,
|
||||
height = 32
|
||||
)
|
||||
// Render Text
|
||||
val typePlatform = getPlatformResource(currentPokemon.form.primaryType)
|
||||
if (typePlatform != null) {
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = typePlatform,
|
||||
x = x + 8.5,
|
||||
y = y + 82,
|
||||
width = 113,
|
||||
height = 30
|
||||
)
|
||||
}
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = platformShadow,
|
||||
x = (x + 43) / 0.5F,
|
||||
y = (y + 93.5) / 0.5F,
|
||||
width = 90,
|
||||
height = 20,
|
||||
scale = 0.5F
|
||||
)
|
||||
|
||||
//Base
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = baseResource,
|
||||
x = x,
|
||||
y = y,
|
||||
width = BASE_WIDTH,
|
||||
height = BASE_HEIGHT
|
||||
)
|
||||
|
||||
//Type Icon
|
||||
TypeIcon(
|
||||
x = x + 65,
|
||||
y = y + 120,
|
||||
type = currentPokemon.form.primaryType,
|
||||
secondaryType = currentPokemon.form.secondaryType,
|
||||
centeredX = true
|
||||
).render(context)
|
||||
|
||||
if (currentPokemon.form.secondaryType == null) {
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = typeSpacerResource,
|
||||
x = x + 47,
|
||||
y = y + 123,
|
||||
width = 36,
|
||||
height = 12
|
||||
)
|
||||
}
|
||||
|
||||
//Name
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = ballResource,
|
||||
x = (x + 4) / 0.5F,
|
||||
y = (y + 3) / 0.5F,
|
||||
width = 16,
|
||||
height = 16,
|
||||
scale = 0.5F
|
||||
)
|
||||
|
||||
drawScaledText(
|
||||
context = context,
|
||||
font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = currentPokemon.species.translatedName.bold(),
|
||||
x = x + 14,
|
||||
y = y + 2,
|
||||
shadow = true
|
||||
)
|
||||
|
||||
// Pokédex Number
|
||||
// Add preceding zeroes if Pokédex number is less than 4 digits
|
||||
var dexNo = currentPokemon.species.nationalPokedexNumber.toString()
|
||||
while (dexNo.length < 4) {
|
||||
dexNo = "0$dexNo"
|
||||
}
|
||||
dexNo = "#$dexNo"
|
||||
|
||||
drawScaledText(
|
||||
context = context,
|
||||
font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = dexNo.text().bold(),
|
||||
x = x + 79,
|
||||
y = y + 1,
|
||||
shadow = true
|
||||
)
|
||||
|
||||
//"Title"
|
||||
drawScaledText(
|
||||
context = context,
|
||||
font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = lang("ui.starter.title").bold(),
|
||||
x = x + 125, y = y + 3F,
|
||||
centered = true,
|
||||
scale = 1.4F,
|
||||
maxCharacterWidth = 120,
|
||||
shadow = true
|
||||
x = x + 172,
|
||||
y = y + 11,
|
||||
shadow = true,
|
||||
centered = true
|
||||
)
|
||||
|
||||
// Render Name
|
||||
val pokemonName = currentPokemon.species.translatedName
|
||||
val scale = 0.8F
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = pokemonName,
|
||||
centered = true,
|
||||
scale = scale,
|
||||
maxCharacterWidth = 50,
|
||||
x = x + 94,
|
||||
y = y + 19.5,
|
||||
shadow = false
|
||||
)
|
||||
//Description Text
|
||||
val smallTextScale = 0.5F
|
||||
|
||||
// Render Description
|
||||
val scale2 = 0.60F
|
||||
matrices.pushPose()
|
||||
matrices.scale(scale2, scale2, 1F)
|
||||
|
||||
// TODO use all pokedex lines across multiple clickable pages in this screen
|
||||
matrices.scale(smallTextScale, smallTextScale, 1F)
|
||||
MultiLineLabelK.create(
|
||||
component = currentPokemon.form.pokedex.first().asTranslated(),
|
||||
width = 127,
|
||||
maxLines = 4
|
||||
width = 114 / smallTextScale,
|
||||
maxLines = 5
|
||||
).renderLeftAligned(
|
||||
context = context,
|
||||
x = (x + 119) / scale2 + 4, y = (y + 18) / scale2 + 4.0,
|
||||
ySpacing = (8.0 / scale2) - 1.25,
|
||||
colour = ColourLibrary.WHITE, shadow = false
|
||||
x = (x + 8) / smallTextScale,
|
||||
y = (y + 143) / smallTextScale,
|
||||
ySpacing = 5.5 / smallTextScale,
|
||||
colour = ColourLibrary.WHITE,
|
||||
shadow = true
|
||||
)
|
||||
matrices.popPose()
|
||||
|
||||
// Render the type background
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = currentPokemon.form.secondaryType?.let { doubleTypeBackground } ?: singleTypeBackground,
|
||||
x = (currentPokemon.form.secondaryType?.let { x + 76.75 } ?: (x + 85.25)), y = y + 29.4,
|
||||
width = currentPokemon.form.secondaryType?.let { 35.25 } ?: 19, height = 19.25
|
||||
)
|
||||
// Render the type widget
|
||||
typeWidget.render(context, mouseX, mouseY, delta)
|
||||
// Render the rest
|
||||
super.render(context, mouseX, mouseY, delta)
|
||||
|
||||
renderSelection(matrices)
|
||||
}
|
||||
|
||||
fun changeCategory(category: RenderableStarterCategory) {
|
||||
fun getPlatformResource(type: ElementalType): ResourceLocation? {
|
||||
return try {
|
||||
cobblemonResource("textures/gui/starterselection/starter_platform_base_${type.showdownId}.png")
|
||||
} catch (error: FileNotFoundException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun selectPokemon(category: RenderableStarterCategory, slot: Int) {
|
||||
currentCategory = category
|
||||
currentSelection = 0
|
||||
updateSelection()
|
||||
}
|
||||
|
||||
private fun right() {
|
||||
playSound(CobblemonSounds.GUI_CLICK)
|
||||
currentSelection = rightOfCurrentSelection()
|
||||
updateSelection()
|
||||
}
|
||||
|
||||
private fun rightOfCurrentSelection() : Int = if (currentSelection + 1 <= currentCategory.pokemon.size - 1) currentSelection + 1 else 0
|
||||
|
||||
private fun left() {
|
||||
playSound(CobblemonSounds.GUI_CLICK)
|
||||
currentSelection = leftOfCurrentSelection()
|
||||
updateSelection()
|
||||
}
|
||||
|
||||
private fun leftOfCurrentSelection() : Int = if (currentSelection - 1 == -1) currentCategory.pokemon.size - 1 else currentSelection - 1
|
||||
|
||||
private fun updateSelection() {
|
||||
currentSelection = slot
|
||||
currentPokemon = currentCategory.pokemon[currentSelection].also {
|
||||
modelWidget.pokemon = it
|
||||
typeWidget = typeWidget(it, (width - BASE_WIDTH) / 2, (height - BASE_HEIGHT) / 2)
|
||||
}
|
||||
starterRoundaboutLeft.pokemon = currentCategory.pokemon[leftOfCurrentSelection()]
|
||||
starterRoundaboutCenter.pokemon = currentPokemon
|
||||
starterRoundaboutRight.pokemon = currentCategory.pokemon[rightOfCurrentSelection()]
|
||||
}
|
||||
|
||||
private fun typeWidget(pokemon: RenderablePokemon, x: Int, y: Int) : TypeWidget {
|
||||
return pokemon.form.secondaryType?.let {
|
||||
DualTypeWidget(
|
||||
pX = x + 77, pY = y + 30,
|
||||
pWidth = 18, pHeight = 18,
|
||||
pMessage = Component.literal("What?"),
|
||||
mainType = pokemon.form.primaryType, secondaryType = it
|
||||
)
|
||||
} ?: SingleTypeWidget(
|
||||
pX = x + 85, pY = y + 30,
|
||||
pWidth = 18, pHeight = 18,
|
||||
type = pokemon.form.primaryType,
|
||||
renderText = false
|
||||
)
|
||||
override fun tick() {
|
||||
ticksElapsed++
|
||||
|
||||
val delay = 3
|
||||
if (ticksElapsed % delay == 0) currentBallBackgroundFrame++
|
||||
if (currentBallBackgroundFrame == 16) currentBallBackgroundFrame = 0
|
||||
}
|
||||
|
||||
override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean {
|
||||
|
||||
+162
-93
@@ -8,143 +8,212 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.startselection.widgets
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.text.bold
|
||||
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
|
||||
import com.cobblemon.mod.common.client.gui.PokemonGUIAnimationStyle
|
||||
import com.cobblemon.mod.common.client.gui.VariableObjectSelectionList
|
||||
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
|
||||
import com.cobblemon.mod.common.client.gui.startselection.StarterSelectionScreen
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState
|
||||
import com.cobblemon.mod.common.config.starter.RenderableStarterCategory
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.math.fromEulerXYZDegrees
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.client.gui.components.ObjectSelectionList
|
||||
import net.minecraft.client.resources.sounds.SimpleSoundInstance
|
||||
import net.minecraft.network.chat.Component
|
||||
import org.joml.Quaternionf
|
||||
import org.joml.Vector3f
|
||||
|
||||
class CategoryList(
|
||||
private val paneWidth: Int,
|
||||
private val paneHeight: Int,
|
||||
topOffset: Int,
|
||||
private val entryWidth: Int,
|
||||
entryHeight: Int,
|
||||
private val categories: List<RenderableStarterCategory>,
|
||||
val listX: Int,
|
||||
val listY: Int,
|
||||
private val minecraft: Minecraft = Minecraft.getInstance(),
|
||||
private val starterSelectionScreen: StarterSelectionScreen
|
||||
) : ObjectSelectionList<CategoryList.Category>(
|
||||
minecraft,
|
||||
) : VariableObjectSelectionList(
|
||||
listX,
|
||||
listY,
|
||||
paneWidth,
|
||||
paneHeight,
|
||||
topOffset,
|
||||
entryHeight
|
||||
paneHeight
|
||||
), CobblemonRenderable {
|
||||
|
||||
companion object {
|
||||
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")
|
||||
private val headerResource = cobblemonResource("textures/gui/starterselection/selection_container_header.png")
|
||||
private val footerResource = cobblemonResource("textures/gui/starterselection/selection_container_footer.png")
|
||||
private val edgeResource = cobblemonResource("textures/gui/starterselection/selection_container_edge.png")
|
||||
private val containerResource = cobblemonResource("textures/gui/starterselection/selection_container.png")
|
||||
|
||||
private val buttonResource = cobblemonResource("textures/gui/starterselection/starter_selection.png")
|
||||
private val buttonActiveResource = cobblemonResource("textures/gui/starterselection/starter_selection_active.png")
|
||||
|
||||
const val MARGIN = 4
|
||||
const val HEADER_HEIGHT = 7
|
||||
const val BUTTON_SEPERATION = 3
|
||||
const val CONTAINER_BUTTON_SIZE = 25
|
||||
const val CONTAINER_WIDTH = 89
|
||||
}
|
||||
|
||||
init {
|
||||
this.x = listX
|
||||
this.y = listY
|
||||
this.correctSize()
|
||||
createEntries().forEach { addEntry(it) }
|
||||
//this.setRenderBackground(false)
|
||||
}
|
||||
|
||||
private fun createEntries() = categories.map {
|
||||
Category(it)
|
||||
}
|
||||
|
||||
override fun renderListBackground(context: GuiGraphics) {}
|
||||
|
||||
override fun renderWidget(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
super.renderWidget(context, mouseX, mouseY, delta)
|
||||
correctSize()
|
||||
}
|
||||
|
||||
private fun correctSize() {
|
||||
this.setRectangle(this.paneWidth, this.paneHeight, this.listX, this.listY)
|
||||
}
|
||||
|
||||
private fun scale(n: Int): Int = (this.minecraft.window.guiScale * n).toInt()
|
||||
override fun getRowWidth() = this.entryWidth
|
||||
override fun getScrollbarPosition(): Int {
|
||||
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)
|
||||
}
|
||||
|
||||
val bottomDifference = bottom - i - itemHeight
|
||||
if (bottomDifference < 0) {
|
||||
scroll(-bottomDifference)
|
||||
addEntry(EmptySeparator(MARGIN))
|
||||
createEntries().forEach {
|
||||
addEntry(it)
|
||||
addEntry(EmptySeparator(MARGIN))
|
||||
}
|
||||
}
|
||||
|
||||
public override fun getRowTop(index: Int): Int {
|
||||
return super.getRowTop(index)
|
||||
private fun createEntries() = categories.map { category ->
|
||||
val rows = (category.pokemon.size - 1) / 3 + 1
|
||||
val height = CONTAINER_BUTTON_SIZE * rows + BUTTON_SEPERATION * (rows + 1) + HEADER_HEIGHT + 3
|
||||
Category(category, height)
|
||||
}
|
||||
|
||||
inner class Category(val category: RenderableStarterCategory) : Entry<Category>() {
|
||||
var controllerSelected = false
|
||||
inner class Category(private val category: RenderableStarterCategory, height: Int) : Entry(height) {
|
||||
|
||||
override fun render(
|
||||
context: GuiGraphics,
|
||||
guiGraphics: GuiGraphics,
|
||||
index: Int,
|
||||
y: Int,
|
||||
x: Int,
|
||||
entryWidth: Int,
|
||||
entryHeight: Int,
|
||||
y: Int,
|
||||
mouseX: Int,
|
||||
mouseY: Int,
|
||||
hovered: Boolean,
|
||||
tickDelta: Float
|
||||
partialTick: Float
|
||||
) {
|
||||
val matrices = context.pose()
|
||||
val isHovered = mouseX >= x && mouseY >= y && mouseX < x + entryWidth && mouseY < y + (entryHeight - 1)
|
||||
if (isHovered || controllerSelected) {
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
x = x + 2.5f, y = y,
|
||||
texture = categoryResource,
|
||||
width = CATEGORY_BUTTON_WIDTH, height = CATEGORY_BUTTON_HEIGHT,
|
||||
red = 0.75f, green = 0.75f, blue = 0.75f
|
||||
)
|
||||
} else
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
x = x + 2.5f, y = y,
|
||||
texture = categoryResource,
|
||||
width = CATEGORY_BUTTON_WIDTH, height = CATEGORY_BUTTON_HEIGHT
|
||||
)
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = category.displayNameText,
|
||||
x = x + 28,
|
||||
y = y + 4.5F,
|
||||
scale = 1F,
|
||||
maxCharacterWidth = 50,
|
||||
shadow = true,
|
||||
centered = true
|
||||
val rows = (category.pokemon.size - 1) / 3 + 1
|
||||
val matrices = guiGraphics.pose()
|
||||
//Header
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = headerResource,
|
||||
x = x + MARGIN,
|
||||
y = y,
|
||||
width = CONTAINER_WIDTH,
|
||||
height = HEADER_HEIGHT
|
||||
)
|
||||
|
||||
val smallTextScale = 0.5F
|
||||
drawScaledText(
|
||||
context = guiGraphics,
|
||||
text = category.displayNameText.bold(),
|
||||
x = x + MARGIN + CONTAINER_WIDTH / 2,
|
||||
y = y + 2,
|
||||
shadow = true,
|
||||
centered = true,
|
||||
scale = smallTextScale
|
||||
)
|
||||
|
||||
//Container
|
||||
var stackHeight = HEADER_HEIGHT
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = edgeResource,
|
||||
x = x + MARGIN,
|
||||
y = y + stackHeight,
|
||||
width = CONTAINER_WIDTH,
|
||||
height = 1
|
||||
)
|
||||
stackHeight += 1
|
||||
|
||||
val containerInnerHeight = CONTAINER_BUTTON_SIZE * rows + BUTTON_SEPERATION * (rows + 1)
|
||||
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = containerResource,
|
||||
x = x + MARGIN,
|
||||
y = y + stackHeight,
|
||||
width = CONTAINER_WIDTH,
|
||||
height = containerInnerHeight
|
||||
)
|
||||
stackHeight += containerInnerHeight
|
||||
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = edgeResource,
|
||||
x = x + MARGIN,
|
||||
y = y + stackHeight,
|
||||
width = CONTAINER_WIDTH,
|
||||
height = 1
|
||||
)
|
||||
stackHeight += 1
|
||||
|
||||
//Footer
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = footerResource,
|
||||
x = x + MARGIN,
|
||||
y = y + stackHeight,
|
||||
width = CONTAINER_WIDTH,
|
||||
height = 1
|
||||
)
|
||||
|
||||
//Buttons
|
||||
for (index in 0..<category.pokemon.size) {
|
||||
val row = index / 3
|
||||
val column = index % 3
|
||||
|
||||
val startX = x + MARGIN + 5 + column * (CONTAINER_BUTTON_SIZE + 2)
|
||||
val startY = y + HEADER_HEIGHT + 1 + BUTTON_SEPERATION + row * (BUTTON_SEPERATION + CONTAINER_BUTTON_SIZE)
|
||||
|
||||
val active = starterSelectionScreen.currentCategory == category && starterSelectionScreen.currentSelection == index
|
||||
val hovered = getEntryAtPosition(mouseX, mouseY) == this && mouseX in startX..(startX + CONTAINER_BUTTON_SIZE) && mouseY in startY..(startY + CONTAINER_BUTTON_SIZE)
|
||||
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = if (active) buttonActiveResource else buttonResource,
|
||||
x = startX,
|
||||
y = startY,
|
||||
width = CONTAINER_BUTTON_SIZE,
|
||||
height = CONTAINER_BUTTON_SIZE,
|
||||
textureHeight = CONTAINER_BUTTON_SIZE * 2,
|
||||
vOffset = if (hovered) CONTAINER_BUTTON_SIZE else 0
|
||||
)
|
||||
|
||||
matrices.pushPose()
|
||||
matrices.translate(startX + (CONTAINER_BUTTON_SIZE / 2.0), startY.toDouble() - 6, 0.0)
|
||||
matrices.scale(3.5F, 3.5F, 1F)
|
||||
|
||||
val state = FloatingState()
|
||||
drawProfilePokemon(
|
||||
species = category.pokemon[index].species.resourceIdentifier,
|
||||
matrixStack = matrices,
|
||||
rotation = Quaternionf().fromEulerXYZDegrees(Vector3f(13F, 35F, 0F)),
|
||||
state = state,
|
||||
scale = 4.5F,
|
||||
partialTicks = 0F
|
||||
)
|
||||
matrices.popPose()
|
||||
}
|
||||
}
|
||||
|
||||
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
|
||||
starterSelectionScreen.changeCategory(category = category)
|
||||
minecraft.soundManager.play(SimpleSoundInstance.forUI(CobblemonSounds.GUI_CLICK, 1.0F))
|
||||
return true
|
||||
val entryY = getRowTop(this)
|
||||
val hoveredButton = getButtonHovered(x, entryY, mouseX, mouseY)
|
||||
if (hoveredButton != -1) {
|
||||
starterSelectionScreen.selectPokemon(category, hoveredButton)
|
||||
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(CobblemonSounds.GUI_CLICK, 1.0F))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun getNarration(): Component {
|
||||
return Component.literal("Yes")
|
||||
private fun getButtonHovered(x: Int, y: Int, mouseX: Double, mouseY: Double): Int {
|
||||
for (index in 0..<category.pokemon.size) {
|
||||
val row = index / 3
|
||||
val column = index % 3
|
||||
|
||||
val startX = x + MARGIN + 5 + column * (CONTAINER_BUTTON_SIZE + 2)
|
||||
val startY = y + HEADER_HEIGHT + 1 + BUTTON_SEPERATION + row * (BUTTON_SEPERATION + CONTAINER_BUTTON_SIZE)
|
||||
|
||||
if (getEntryAtPosition(mouseX.toInt(), mouseY.toInt()) == this && mouseX.toInt() in startX..(startX + CONTAINER_BUTTON_SIZE) && mouseY.toInt() in startY..(startY + CONTAINER_BUTTON_SIZE)) {
|
||||
return index
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
}
|
||||
}
|
||||
+27
-31
@@ -6,11 +6,13 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.startselection.widgets.preview
|
||||
package com.cobblemon.mod.common.client.gui.startselection.widgets
|
||||
|
||||
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
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
@@ -26,45 +28,39 @@ class SelectionButton(
|
||||
pX: Int, pY: Int,
|
||||
pWidth: Int, pHeight: Int,
|
||||
onPress: OnPress
|
||||
): Button(pX, pY, pWidth, pHeight, Component.literal("SelectionButton"), onPress, DEFAULT_NARRATION), CobblemonRenderable {
|
||||
): Button(pX, pY, pWidth, pHeight, Component.literal("SelectionButton"), onPress, DEFAULT_NARRATION),
|
||||
CobblemonRenderable {
|
||||
|
||||
companion object {
|
||||
private val buttonTexture = cobblemonResource("textures/gui/starterselection/starterselection_button.png")
|
||||
const val BUTTON_WIDTH = 56
|
||||
const val BUTTON_HEIGHT = 12
|
||||
private const val SCALE = 0.7f
|
||||
private val buttonResource = cobblemonResource("textures/gui/starterselection/choose_button.png")
|
||||
const val BUTTON_WIDTH = 106
|
||||
const val BUTTON_HEIGHT = 14
|
||||
const val TEXT_HEIGHT = 10
|
||||
}
|
||||
|
||||
override fun playDownSound(soundManager: SoundManager) {
|
||||
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(CobblemonSounds.GUI_CLICK, 1.0F))
|
||||
}
|
||||
override fun playDownSound(soundManager: SoundManager) {}
|
||||
|
||||
override fun renderWidget(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
val matrices = context.pose()
|
||||
if (isHovered || isFocused)
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = buttonTexture,
|
||||
x = x + 0.6, y = y + 0.6,
|
||||
width = BUTTON_WIDTH - 0.25, height = BUTTON_HEIGHT - 0.25,
|
||||
red = 0.75f, green = 0.75f, blue = 0.75f
|
||||
)
|
||||
else
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = buttonTexture,
|
||||
x = x + 0.6, y = y + 0.6,
|
||||
width = BUTTON_WIDTH - 0.25, height = BUTTON_HEIGHT - 0.25
|
||||
)
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = buttonResource,
|
||||
x = x,
|
||||
y = y,
|
||||
width = BUTTON_WIDTH,
|
||||
height = BUTTON_HEIGHT,
|
||||
textureHeight = BUTTON_HEIGHT * 2,
|
||||
vOffset = if (isHovered) BUTTON_HEIGHT else 0
|
||||
)
|
||||
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = lang("ui.starter.choosebutton"),
|
||||
x = x + BUTTON_WIDTH / 2, y = y + BUTTON_HEIGHT / 2 - 2.4,
|
||||
colour = ColourLibrary.WHITE,
|
||||
centered = true,
|
||||
maxCharacterWidth = 68,
|
||||
scale = SCALE,
|
||||
shadow = true
|
||||
font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = lang("ui.starter.choosebutton").bold(),
|
||||
x = x + BUTTON_WIDTH / 2,
|
||||
y = y + BUTTON_HEIGHT / 2 - TEXT_HEIGHT / 2,
|
||||
shadow = true,
|
||||
centered = true
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -28,19 +28,13 @@ 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
|
||||
@@ -63,8 +57,6 @@ 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.
|
||||
@@ -75,7 +67,7 @@ import org.joml.Vector4i
|
||||
* @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, ControllerScreen {
|
||||
Component.translatable("cobblemon.ui.summary.title")), Schedulable, CobblemonRenderable {
|
||||
|
||||
companion object {
|
||||
const val BASE_WIDTH = 331
|
||||
@@ -84,10 +76,10 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
private const val SCALE = 0.5F
|
||||
|
||||
// Main Screen Index
|
||||
const val INFO = 0
|
||||
const val MOVES = 1
|
||||
const val STATS = 2
|
||||
const val MARKS = 3
|
||||
private const val INFO = 0
|
||||
private const val MOVES = 1
|
||||
private const val STATS = 2
|
||||
private const val MARKS = 3
|
||||
|
||||
// Side Screen Index
|
||||
const val PARTY = 0
|
||||
@@ -131,32 +123,19 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
|
||||
override val schedulingTracker = SchedulingTracker()
|
||||
|
||||
val party = ArrayList(party)
|
||||
private val party = ArrayList(party)
|
||||
internal var selectedPokemon: Pokemon = this.party[selection] ?: this.party.first { it != null }!!
|
||||
lateinit var mainScreen: AbstractWidget
|
||||
private lateinit var mainScreen: AbstractWidget
|
||||
lateinit var sideScreen: GuiEventListener
|
||||
private lateinit var modelWidget: ModelWidget
|
||||
lateinit var nicknameEntryWidget: NicknameEntryWidget
|
||||
private lateinit var nicknameEntryWidget: NicknameEntryWidget
|
||||
private lateinit var markingsWidget: MarkingsWidget
|
||||
val summaryTabs = mutableListOf<SummaryTab>()
|
||||
private val summaryTabs = mutableListOf<SummaryTab>()
|
||||
private var showCosmeticItem = false
|
||||
lateinit var heldItemVisibilityButton: SummaryButton
|
||||
lateinit var heldItemSwitchTypeButton: SummaryButton
|
||||
lateinit var evolveButton: SummaryButton
|
||||
var mainScreenIndex = INFO
|
||||
private lateinit var heldItemVisibilityButton: SummaryButton
|
||||
private 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) { }
|
||||
|
||||
/**
|
||||
@@ -186,7 +165,7 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
addRenderableWidget(markingsWidget)
|
||||
|
||||
// Evolve Button
|
||||
evolveButton = addRenderableWidget(
|
||||
addRenderableWidget(
|
||||
SummaryButton(
|
||||
buttonX = x + 12F,
|
||||
buttonY = y + 145F,
|
||||
@@ -232,22 +211,22 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
heldItemVisibilityButton.buttonActive = !selectedPokemon.heldItemVisible
|
||||
addRenderableWidget(heldItemVisibilityButton)
|
||||
|
||||
|
||||
// Held/Cosmetic Item Button
|
||||
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(
|
||||
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()
|
||||
@@ -281,7 +260,14 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
// Add Exit Button
|
||||
addRenderableWidget(
|
||||
ExitButton(pX = x + 302, pY = y + 145) {
|
||||
onBack()
|
||||
playSound(CobblemonSounds.GUI_CLICK)
|
||||
if (sideScreenIndex != PARTY) {
|
||||
displaySideScreen(PARTY)
|
||||
} else {
|
||||
saveActiveMark()
|
||||
saveMarkings()
|
||||
Minecraft.getInstance().setScreen(null)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@@ -314,214 +300,9 @@ 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
|
||||
}
|
||||
@@ -582,11 +363,11 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
}
|
||||
}
|
||||
|
||||
fun saveMarkings() {
|
||||
private fun saveMarkings() {
|
||||
if (::markingsWidget.isInitialized) markingsWidget.saveMarkingsToPokemon()
|
||||
}
|
||||
|
||||
fun saveActiveMark() {
|
||||
private fun saveActiveMark() {
|
||||
if (mainScreenIndex == MARKS && mainScreen is MarksWidget) (mainScreen as MarksWidget).saveActiveMarkToPokemon()
|
||||
}
|
||||
|
||||
@@ -598,16 +379,12 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
/**
|
||||
* Switch center screen
|
||||
*/
|
||||
fun displayMainScreen(screen: Int) {
|
||||
private 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).rawStatTabIndex else 0
|
||||
|
||||
if (screen != MOVES) {
|
||||
moveSwitchingMode = false
|
||||
}
|
||||
val subIndex = if (mainScreenIndex == STATS && mainScreen is StatWidget) (mainScreen as StatWidget).statTabIndex else 0
|
||||
|
||||
mainScreenIndex = screen
|
||||
if (::mainScreen.isInitialized) removeWidget(mainScreen)
|
||||
@@ -627,7 +404,6 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
pY = y + 12,
|
||||
pokemon = this.selectedPokemon
|
||||
)
|
||||
mainScreenComponentManager = null
|
||||
}
|
||||
|
||||
MOVES -> {
|
||||
@@ -635,13 +411,7 @@ 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 -> {
|
||||
@@ -649,38 +419,25 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
pX = x + 77,
|
||||
pY = y + 12,
|
||||
pokemon = this.selectedPokemon,
|
||||
tabIndex = subIndex,
|
||||
summary = this
|
||||
tabIndex = subIndex
|
||||
)
|
||||
mainScreenComponentManager = null
|
||||
}
|
||||
|
||||
MARKS -> {
|
||||
mainScreen = MarksWidget(
|
||||
pX = x + 77,
|
||||
pY = y + 12,
|
||||
pokemon = this.selectedPokemon,
|
||||
summary = this
|
||||
).also {
|
||||
mainScreenComponentManager = it.controllerComponentManager
|
||||
}
|
||||
pokemon = this.selectedPokemon
|
||||
)
|
||||
}
|
||||
}
|
||||
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)
|
||||
|
||||
@@ -695,9 +452,7 @@ 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 -> {
|
||||
@@ -719,9 +474,7 @@ 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"]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -731,67 +484,14 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
sideScreen = EvolutionSelectScreen(
|
||||
x + 216,
|
||||
y + 23,
|
||||
pokemon = selectedPokemon,
|
||||
summary = this
|
||||
).also {
|
||||
sideScreenComponentManager = it.controllerComponentManager
|
||||
}
|
||||
controllerComponentManager.focused = controllerComponentManager.componentList["right_screen"]
|
||||
pokemon = selectedPokemon
|
||||
)
|
||||
}
|
||||
}
|
||||
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) {}
|
||||
@@ -931,11 +631,8 @@ 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(
|
||||
@@ -964,25 +661,19 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
scale = SCALE
|
||||
)
|
||||
|
||||
// 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
|
||||
}
|
||||
matrices.pushPose()
|
||||
// Prevent widgets from being overlapped by other components
|
||||
matrices.translate(0.0, 0.0, 1000.0)
|
||||
|
||||
// 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,
|
||||
val renderRequirement: ((button: SummaryButton) -> Boolean) = { true },
|
||||
val clickRequirement: ((button: SummaryButton) -> Boolean) = { true },
|
||||
private val renderRequirement: ((button: SummaryButton) -> Boolean) = { true },
|
||||
private 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) || isFocused)) buttonHeight else 0,
|
||||
vOffset = if (hoverTexture && isButtonHovered(pMouseX, pMouseY)) buttonHeight else 0,
|
||||
textureHeight = if (hoverTexture) (buttonHeight.toFloat() * 2) else buttonHeight,
|
||||
scale = scale
|
||||
)
|
||||
|
||||
+2
-34
@@ -15,11 +15,8 @@ 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
|
||||
@@ -37,8 +34,7 @@ import org.joml.Vector3f
|
||||
class EvolutionSelectScreen(
|
||||
x: Int,
|
||||
y: Int,
|
||||
val pokemon: Pokemon,
|
||||
val summary: Summary
|
||||
val pokemon: Pokemon
|
||||
): SummaryScrollList<EvolutionSelectScreen.EvolveSlot>(
|
||||
x,
|
||||
y,
|
||||
@@ -56,36 +52,8 @@ 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 {
|
||||
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
|
||||
return super.addEntry(entry)
|
||||
}
|
||||
|
||||
override fun renderWidget(context: GuiGraphics, mouseX: Int, mouseY: Int, partialTicks: Float) {
|
||||
|
||||
+5
-14
@@ -20,7 +20,6 @@ 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(
|
||||
@@ -32,6 +31,7 @@ class ModelWidget(
|
||||
var offsetY: Double = 0.0,
|
||||
val playCryOnClick: Boolean = false,
|
||||
val shouldFollowCursor: Boolean = false,
|
||||
val blockLight: Int = 13
|
||||
): SoundlessWidget(pX, pY, pWidth, pHeight, Component.literal("Summary - ModelWidget")) {
|
||||
|
||||
companion object {
|
||||
@@ -58,8 +58,6 @@ 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
|
||||
@@ -89,7 +87,7 @@ class ModelWidget(
|
||||
|
||||
val timeLooking = lookStartTime?.let { (System.currentTimeMillis() - it) / 1000 } ?: MAX_SECONDS_LOOKING
|
||||
val lookedTooMuch = timeLooking >= MAX_SECONDS_LOOKING
|
||||
val resetToCenter = (!isHovered && lookedTooMuch && overrideLookPos == null) || !shouldFollowCursor || !Cobblemon.config.summaryPokemonFollowCursor
|
||||
val resetToCenter = (!isHovered && lookedTooMuch) || !shouldFollowCursor || !Cobblemon.config.summaryPokemonFollowCursor
|
||||
|
||||
if (resetToCenter) {
|
||||
lookStartTime = null
|
||||
@@ -98,19 +96,12 @@ 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,
|
||||
xPos,
|
||||
yPos,
|
||||
mouseX,
|
||||
mouseY,
|
||||
currentYawAndPitch.first,
|
||||
currentYawAndPitch.second,
|
||||
resetToCenter
|
||||
@@ -125,8 +116,8 @@ class ModelWidget(
|
||||
partialTicks = partialTicks,
|
||||
headYaw = currentYawAndPitch.first,
|
||||
headPitch = currentYawAndPitch.second,
|
||||
blockLight = blockLight
|
||||
)
|
||||
context.flush()
|
||||
|
||||
heldItemRenderer.renderOnModel(
|
||||
pokemon.heldItem,
|
||||
|
||||
+6
-11
@@ -88,7 +88,7 @@ class PartySlotWidget(
|
||||
y = y,
|
||||
width = width,
|
||||
height = height,
|
||||
vOffset = getSlotVOffset(slotPokemon, isHovered || isFocused, isSelected),
|
||||
vOffset = getSlotVOffset(slotPokemon, isHovered, isSelected),
|
||||
textureHeight = height * 2,
|
||||
)
|
||||
|
||||
@@ -223,21 +223,16 @@ class PartySlotWidget(
|
||||
if (partyWidget.swapEnabled) {
|
||||
toggleDrag(true)
|
||||
} else {
|
||||
if (onPress()) return true
|
||||
if ((index > -1) && (summary.selectedPokemon.uuid != pokemon?.uuid)) {
|
||||
summary.switchSelection(index)
|
||||
if (pokemon != null) partyWidget.playSound(CobblemonSounds.GUI_CLICK)
|
||||
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)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user