mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-27 20:46:27 -04:00
Compare commits
26
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
308c9d61c6 | ||
|
|
07ad22608d | ||
|
|
b50f924ce0 | ||
|
|
c0b55ebb6f | ||
|
|
cdc0a790fb | ||
|
|
13e8084f0d | ||
|
|
3daa3d31a3 | ||
|
|
979d6f02a6 | ||
|
|
8fdb32273d | ||
|
|
d5c9d8d5b1 | ||
|
|
b7b6185ada | ||
|
|
211b886bf3 | ||
|
|
585371bb08 | ||
|
|
aee97ff96e | ||
|
|
fbbd450d0d | ||
|
|
83612b50fc | ||
|
|
434faea210 | ||
|
|
6e24ee6b4e | ||
|
|
3d6a3fbfec | ||
|
|
708b810e6b | ||
|
|
509016e133 | ||
|
|
690183b994 | ||
|
|
33d56124f5 | ||
|
|
a5a65abe2b | ||
|
|
f73ab3b001 | ||
|
|
9a571984db |
@@ -13,6 +13,7 @@
|
||||
|
||||
### Changes
|
||||
- Renamed `chargeGainedPerTick` config to `secondsToChargeHealingMachine`.
|
||||
- Made Blocks of Gold count as Big Nuggets when held by a Pokémon (for Fling functionality)
|
||||
|
||||
### Fixes
|
||||
- Fixed Particles sometimes facing the wrong direction (looking at you, Swords Dance)
|
||||
|
||||
@@ -36,8 +36,6 @@ repositories {
|
||||
|
||||
dependencies {
|
||||
implementation(libs.bundles.kotlin)
|
||||
implementation("jakarta.websocket:jakarta.websocket-api:2.2.0")
|
||||
|
||||
modImplementation(libs.fabric.loader)
|
||||
modApi(libs.molang)
|
||||
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
package com.cobblemon.mod.common;
|
||||
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.util.SmoothDouble;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Vector3f;
|
||||
@@ -117,8 +120,24 @@ public interface Rollable {
|
||||
return (float) Mth.wrapDegrees(-Math.toDegrees(getUpVector().angleSigned(UP, getForwardVector())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the angular velocity in degrees per second as a Vec3
|
||||
*/
|
||||
Vec3 angRollVel( double deltaTime );
|
||||
|
||||
public Vec3 rotationOnMouseXY(
|
||||
double yMouse,
|
||||
double xMouse,
|
||||
SmoothDouble yMouseSmoother,
|
||||
SmoothDouble xMouseSmoother,
|
||||
double sensitivity,
|
||||
double deltaTime
|
||||
);
|
||||
|
||||
boolean shouldRoll();
|
||||
|
||||
boolean useAngVelSmoothing();
|
||||
|
||||
void clearRotation();
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(LocalPlayer.class)
|
||||
public abstract class LocalPlayerMixin {
|
||||
@Shadow
|
||||
private float jumpRidingScale;
|
||||
|
||||
@Inject(method = "getJumpRidingScale", at = @At("HEAD"), cancellable = true)
|
||||
public void modifyJumpRidingScale(CallbackInfoReturnable<Float> cir) {
|
||||
|
||||
LocalPlayer player = (LocalPlayer) (Object) this;
|
||||
if (player.isPassenger() && player.getVehicle() instanceof PokemonEntity) {
|
||||
PokemonEntity ride = (PokemonEntity) player.getVehicle();
|
||||
|
||||
//Use custom jump bar logic if the current ride does not jump using it.
|
||||
if( !ride.getRiding().canJump(ride, player))
|
||||
{
|
||||
cir.setReturnValue(ride.setRideBar());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@ import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.util.SmoothDouble;
|
||||
import net.minecraft.world.damagesource.DamageSource;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
@@ -47,6 +48,7 @@ import net.minecraft.world.food.FoodProperties;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.joml.Matrix3f;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
@@ -55,6 +57,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.ModifyArg;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@@ -271,6 +274,7 @@ public abstract class PlayerMixin extends LivingEntity implements Rollable, Scan
|
||||
|
||||
@Override
|
||||
public Rollable updateOrientation(Function<Matrix3f, Matrix3f> update) {
|
||||
//Disabled to allow non mouse inputs to modify roll
|
||||
if (!shouldRoll()) return this;
|
||||
|
||||
if (this.orientation == null) {
|
||||
@@ -296,6 +300,60 @@ public abstract class PlayerMixin extends LivingEntity implements Rollable, Scan
|
||||
return pokemonEntity.getRiding().shouldRoll(pokemonEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3 rotationOnMouseXY(
|
||||
double yMouse,
|
||||
double xMouse,
|
||||
SmoothDouble yMouseSmoother,
|
||||
SmoothDouble xMouseSmoother,
|
||||
double sensitivity,
|
||||
double deltaTime
|
||||
) {
|
||||
LocalPlayer player = Minecraft.getInstance().player;
|
||||
if (!this.equals(player)) return Vec3.ZERO;
|
||||
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return Vec3.ZERO;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return Vec3.ZERO;
|
||||
|
||||
return pokemonEntity.getRiding().rotationOnMouseXY(
|
||||
pokemonEntity,
|
||||
player,
|
||||
yMouse,
|
||||
xMouse,
|
||||
yMouseSmoother,
|
||||
xMouseSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useAngVelSmoothing() {
|
||||
LocalPlayer player = Minecraft.getInstance().player;
|
||||
if (!this.equals(player)) return true;
|
||||
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return true;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return true;
|
||||
|
||||
return pokemonEntity.getRiding().useAngVelSmoothing(pokemonEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3 angRollVel( double deltaTime ) {
|
||||
var ret = new Vec3(0.0, 0.0, 0.0);
|
||||
LocalPlayer player = Minecraft.getInstance().player;
|
||||
if (!this.equals(player)) return ret;
|
||||
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return ret;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return ret;
|
||||
|
||||
return pokemonEntity.getRiding().angRollVel( pokemonEntity, player, deltaTime );
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void clearRotation() {
|
||||
this.orientation = null;
|
||||
|
||||
+12
@@ -9,8 +9,10 @@
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.client.CobblemonClient;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.pokedex.scanner.PokedexUsageContext;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
@@ -30,5 +32,15 @@ public class AbstractClientPlayerMixin {
|
||||
if (usageContext.getScanningGuiOpen()) {
|
||||
cir.setReturnValue(usageContext.getFovMultiplier());
|
||||
}
|
||||
|
||||
//TODO: find a better solution that just tagging this logic on here. Likely just change it to a more general
|
||||
//name?
|
||||
LocalPlayer player = (LocalPlayer) (Object) this;
|
||||
if (player != null && player.isPassenger() && player.getVehicle() instanceof PokemonEntity) {
|
||||
PokemonEntity ride = (PokemonEntity) player.getVehicle();
|
||||
|
||||
//Return custom fov mult
|
||||
cir.setReturnValue(ride.rideFovMult());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,11 +14,13 @@ import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding;
|
||||
import com.cobblemon.mod.common.pokedex.scanner.PokedexUsageContext;
|
||||
import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import com.mojang.blaze3d.Blaze3D;
|
||||
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.objectweb.asm.Opcodes;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
@@ -33,8 +35,11 @@ public class MouseHandlerMixin {
|
||||
@Shadow private double accumulatedScrollY;
|
||||
@Shadow @Final private Minecraft minecraft;
|
||||
|
||||
@Unique SmoothDouble xMouseSmoother = new SmoothDouble();
|
||||
@Unique SmoothDouble yMouseSmoother = new SmoothDouble();
|
||||
@Unique SmoothDouble pitchSmoother = new SmoothDouble();
|
||||
@Unique SmoothDouble rollSmoother = new SmoothDouble();
|
||||
@Unique SmoothDouble yawSmoother = new SmoothDouble();
|
||||
|
||||
@Shadow @Final private SmoothDouble smoothTurnY;
|
||||
|
||||
@@ -44,6 +49,8 @@ public class MouseHandlerMixin {
|
||||
|
||||
@Shadow private double accumulatedDY;
|
||||
|
||||
@Shadow private double accumulatedScrollX;
|
||||
|
||||
@Inject(
|
||||
method = "onScroll",
|
||||
at = @At(
|
||||
@@ -95,7 +102,13 @@ public class MouseHandlerMixin {
|
||||
target = "Lnet/minecraft/client/player/LocalPlayer;turn(DD)V"
|
||||
)
|
||||
)
|
||||
public boolean cobblemon$modifyRotation(LocalPlayer player, double cursorDeltaX, double cursorDeltaY, @Local(argsOnly = true) double d) {
|
||||
public boolean cobblemon$modifyRotation(
|
||||
LocalPlayer player,
|
||||
double cursorDeltaX,
|
||||
double cursorDeltaY,
|
||||
@Local(argsOnly = true) double d,
|
||||
@Local(argsOnly = true) double movementTime
|
||||
) {
|
||||
PokedexUsageContext usageContext = CobblemonClient.INSTANCE.getPokedexUsageContext();
|
||||
if (usageContext.getScanningGuiOpen()) {
|
||||
this.smoothTurnY.reset();
|
||||
@@ -109,16 +122,66 @@ public class MouseHandlerMixin {
|
||||
}
|
||||
|
||||
if (!(player instanceof Rollable rollable)) return true;
|
||||
|
||||
if (!rollable.shouldRoll()) {
|
||||
xMouseSmoother.reset();
|
||||
yMouseSmoother.reset();
|
||||
pitchSmoother.reset();
|
||||
rollSmoother.reset();
|
||||
yawSmoother.reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
var pitch = pitchSmoother.getNewDeltaValue(cursorDeltaY * 0.15f, d);
|
||||
var roll = rollSmoother.getNewDeltaValue(cursorDeltaX * 0.15f, d);
|
||||
rollable.rotate(0.0F, (float)pitch, (float)roll);
|
||||
var defaultSensitivity = this.minecraft.options.sensitivity().get() * 0.6000000238418579 + 0.20000000298023224;
|
||||
var ridingSensitivity = Math.pow(defaultSensitivity, 3);
|
||||
|
||||
//Send mouse input to be interpreted into rotation
|
||||
//deltas by the ride controller
|
||||
Vec3 angVecMouse = rollable.rotationOnMouseXY(
|
||||
cursorDeltaY,
|
||||
cursorDeltaX ,
|
||||
yMouseSmoother,
|
||||
xMouseSmoother,
|
||||
ridingSensitivity,
|
||||
movementTime
|
||||
);
|
||||
|
||||
//Perform Rotation using mouse influenced rotation deltas.
|
||||
rollable.rotate(
|
||||
(float) angVecMouse.x,
|
||||
(float) angVecMouse.y,
|
||||
(float) angVecMouse.z
|
||||
);
|
||||
|
||||
|
||||
//Gather and apply the current rotation deltas
|
||||
var angRot = rollable.angRollVel(movementTime);
|
||||
|
||||
//Apply smoothing if requested by the controller.
|
||||
//This Might be best if done by the controller itself?
|
||||
if( rollable.useAngVelSmoothing() )
|
||||
{
|
||||
if( angRot != null ) {
|
||||
var yaw = yawSmoother.getNewDeltaValue(angRot.x * 0.5f, d);
|
||||
var pitch = pitchSmoother.getNewDeltaValue(angRot.y * 0.5f, d);
|
||||
var roll = rollSmoother.getNewDeltaValue(angRot.z * 0.5f, d);
|
||||
rollable.rotate((float) yaw, (float) pitch, (float) roll);
|
||||
}
|
||||
}
|
||||
//Otherwise simply apply the smoothing
|
||||
else
|
||||
{
|
||||
if( angRot != null ) {
|
||||
rollable.rotate((float) (
|
||||
angRot.x * 10 * d),
|
||||
(float) (angRot.y * 10 * d),
|
||||
(float) (angRot.z * 10 * d)
|
||||
);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Inject(method = "handleAccumulatedMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MouseHandler;isMouseGrabbed()Z", ordinal = 0))
|
||||
|
||||
@@ -62,24 +62,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.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.*
|
||||
import com.cobblemon.mod.common.battles.actor.PokemonBattleActor
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.client.CobblemonPack
|
||||
import com.cobblemon.mod.common.command.argument.DexArgumentType
|
||||
import com.cobblemon.mod.common.command.argument.DialogueArgumentType
|
||||
import com.cobblemon.mod.common.command.argument.FormArgumentType
|
||||
import com.cobblemon.mod.common.command.argument.MoveArgumentType
|
||||
import com.cobblemon.mod.common.command.argument.NPCClassArgumentType
|
||||
import com.cobblemon.mod.common.command.argument.PartySlotArgumentType
|
||||
import com.cobblemon.mod.common.command.argument.PokemonPropertiesArgumentType
|
||||
import com.cobblemon.mod.common.command.argument.PokemonStoreArgumentType
|
||||
import com.cobblemon.mod.common.command.argument.SpawnBucketArgumentType
|
||||
import com.cobblemon.mod.common.command.argument.SpeciesArgumentType
|
||||
import com.cobblemon.mod.common.command.argument.*
|
||||
import com.cobblemon.mod.common.config.CobblemonConfig
|
||||
import com.cobblemon.mod.common.config.LastChangedVersion
|
||||
import com.cobblemon.mod.common.config.constraint.IntConstraint
|
||||
@@ -99,26 +86,11 @@ import com.cobblemon.mod.common.pokemon.aspects.SHINY_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.BlockClickEvolution
|
||||
import com.cobblemon.mod.common.pokemon.feature.TagSeasonResolver
|
||||
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
|
||||
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.NoAIProperty
|
||||
import com.cobblemon.mod.common.pokemon.properties.UnaspectPropertyType
|
||||
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
|
||||
import com.cobblemon.mod.common.pokemon.properties.*
|
||||
import com.cobblemon.mod.common.pokemon.properties.tags.PokemonFlagProperty
|
||||
import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
|
||||
import com.cobblemon.mod.common.showdown.runner.CobblemonShowdownBattleServer
|
||||
import com.cobblemon.mod.common.showdown.runner.ShowdownBattleServer
|
||||
import com.cobblemon.mod.common.showdown.runner.remote.RemoteShowdownBattleServer
|
||||
import com.cobblemon.mod.common.starter.CobblemonStarterHandler
|
||||
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.util.*
|
||||
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
|
||||
@@ -141,8 +113,7 @@ import java.io.File
|
||||
import java.io.FileReader
|
||||
import java.io.FileWriter
|
||||
import java.io.PrintWriter
|
||||
import java.util.UUID
|
||||
import kotlin.collections.set
|
||||
import java.util.*
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.properties.Delegates
|
||||
import kotlin.reflect.full.memberProperties
|
||||
@@ -182,10 +153,6 @@ object Cobblemon {
|
||||
var statProvider: StatProvider = CobblemonStatProvider
|
||||
var seasonResolver: SeasonResolver = TagSeasonResolver
|
||||
var wallpapers = mapOf<UUID, List<ResourceLocation>>()
|
||||
val showdownServer = RemoteShowdownBattleServer(
|
||||
"wss://sim3.psim.us:443/showdown/websocket",
|
||||
"https://play.pokemonshowdown.com"
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
val builtinPacks = listOf<CobblemonPack>(
|
||||
@@ -348,7 +315,6 @@ object Cobblemon {
|
||||
}
|
||||
PlatformEvents.SERVER_TICK_PRE.subscribe {
|
||||
ServerRealTimeTaskTracker.update()
|
||||
showdownServer.onTick()
|
||||
}
|
||||
PlatformEvents.SERVER_STARTING.subscribe { event ->
|
||||
val server = event.server
|
||||
@@ -425,24 +391,21 @@ object Cobblemon {
|
||||
PlatformEvents.SERVER_STARTED.subscribe {
|
||||
bestSpawner.onServerStarted()
|
||||
battleRegistry.onServerStarted()
|
||||
showdownServer.onServerStarted()
|
||||
}
|
||||
PlatformEvents.SERVER_TICK_POST.subscribe { ServerTickHandler.onTick(it.server) }
|
||||
|
||||
if (showdownServer is CobblemonShowdownBattleServer) {
|
||||
BagItems.observable.subscribe {
|
||||
LOGGER.info("Starting dummy Showdown battle to force it to pre-load data.")
|
||||
battleRegistry.startBattle(
|
||||
BattleFormat.GEN_9_SINGLES,
|
||||
BattleSide(PokemonBattleActor(UUID.randomUUID(), BattlePokemon(Pokemon().initialize()), -1F)),
|
||||
BattleSide(PokemonBattleActor(UUID.randomUUID(), BattlePokemon(Pokemon().initialize()), -1F)),
|
||||
false
|
||||
).ifSuccessful {
|
||||
it.mute = true
|
||||
}.ifErrored {
|
||||
val errors = it.errors.joinToString("\n") { it.javaClass.name }
|
||||
LOGGER.error("Failed to start dummy Showdown battle: $errors")
|
||||
}
|
||||
BagItems.observable.subscribe {
|
||||
LOGGER.info("Starting dummy Showdown battle to force it to pre-load data.")
|
||||
battleRegistry.startBattle(
|
||||
BattleFormat.GEN_9_SINGLES,
|
||||
BattleSide(PokemonBattleActor(UUID.randomUUID(), BattlePokemon(Pokemon().initialize()), -1F)),
|
||||
BattleSide(PokemonBattleActor(UUID.randomUUID(), BattlePokemon(Pokemon().initialize()), -1F)),
|
||||
false
|
||||
).ifSuccessful {
|
||||
it.mute = true
|
||||
}.ifErrored {
|
||||
val errors = it.errors.joinToString("\n") { it.javaClass.name }
|
||||
LOGGER.error("Failed to start dummy Showdown battle: $errors")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,53 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.cobblemon.mod.common.command.AbandonMultiTeam
|
||||
import com.cobblemon.mod.common.command.ApplyPlayerTextureCommand
|
||||
import com.cobblemon.mod.common.command.BedrockParticleCommand
|
||||
import com.cobblemon.mod.common.command.ChangeBoxWallpaperCommand
|
||||
import com.cobblemon.mod.common.command.ChangeEyeHeight
|
||||
import com.cobblemon.mod.common.command.ChangeJointScaleCommand
|
||||
import com.cobblemon.mod.common.command.ChangeScaleAndSize
|
||||
import com.cobblemon.mod.common.command.ChangeWalkSpeed
|
||||
import com.cobblemon.mod.common.command.CheckSpawnsCommand
|
||||
import com.cobblemon.mod.common.command.ClearPCCommand
|
||||
import com.cobblemon.mod.common.command.ClearPartyCommand
|
||||
import com.cobblemon.mod.common.command.ClickTextCommand
|
||||
import com.cobblemon.mod.common.command.CobblemonConfigCommand
|
||||
import com.cobblemon.mod.common.command.CobblemonInfoCommand
|
||||
import com.cobblemon.mod.common.command.FreezePokemonCommand
|
||||
import com.cobblemon.mod.common.command.FriendshipCommand
|
||||
import com.cobblemon.mod.common.command.GetNBT
|
||||
import com.cobblemon.mod.common.command.GiveAllPokemon
|
||||
import com.cobblemon.mod.common.command.GivePokemon
|
||||
import com.cobblemon.mod.common.command.HealPokemonCommand
|
||||
import com.cobblemon.mod.common.command.HeldItemCommand
|
||||
import com.cobblemon.mod.common.command.LevelUp
|
||||
import com.cobblemon.mod.common.command.NPCDeleteCommand
|
||||
import com.cobblemon.mod.common.command.NPCEditCommand
|
||||
import com.cobblemon.mod.common.command.OpenDialogueCommand
|
||||
import com.cobblemon.mod.common.command.OpenStarterScreenCommand
|
||||
import com.cobblemon.mod.common.command.PcCommand
|
||||
import com.cobblemon.mod.common.command.PokeboxCommand
|
||||
import com.cobblemon.mod.common.command.PokedexCommand
|
||||
import com.cobblemon.mod.common.command.PokemonEditCommand
|
||||
import com.cobblemon.mod.common.command.PokemonRestartCommand
|
||||
import com.cobblemon.mod.common.command.QueryLearnsetCommand
|
||||
import com.cobblemon.mod.common.command.ReloadShowdownCommand
|
||||
import com.cobblemon.mod.common.command.RenameBoxCommand
|
||||
import com.cobblemon.mod.common.command.RunMolangScriptCommand
|
||||
import com.cobblemon.mod.common.command.ShowdownCommand
|
||||
import com.cobblemon.mod.common.command.SpawnAllPokemon
|
||||
import com.cobblemon.mod.common.command.SpawnNPCCommand
|
||||
import com.cobblemon.mod.common.command.SpawnPokemon
|
||||
import com.cobblemon.mod.common.command.SpawnPokemonFromPool
|
||||
import com.cobblemon.mod.common.command.StopBattleCommand
|
||||
import com.cobblemon.mod.common.command.TakePokemon
|
||||
import com.cobblemon.mod.common.command.TeachCommand
|
||||
import com.cobblemon.mod.common.command.TestCommand
|
||||
import com.cobblemon.mod.common.command.TestPartySlotCommand
|
||||
import com.cobblemon.mod.common.command.TestPcSlotCommand
|
||||
import com.cobblemon.mod.common.command.TestStoreCommand
|
||||
import com.cobblemon.mod.common.command.*
|
||||
import com.mojang.brigadier.CommandDispatcher
|
||||
import net.minecraft.commands.CommandBuildContext
|
||||
import net.minecraft.commands.CommandSourceStack
|
||||
@@ -111,6 +65,5 @@ object CobblemonCommands {
|
||||
// Possibly lock down registration if and only if under dev environment or running in an environment
|
||||
// with a certain system environment variable set
|
||||
CobblemonInfoCommand.register(dispatcher)
|
||||
ShowdownCommand.register(dispatcher)
|
||||
}
|
||||
}
|
||||
@@ -1278,6 +1278,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
CobblemonHeldItemManager.registerRemap(it, remappedName)
|
||||
CobblemonHeldItemManager.registerRemap(Items.BONE, "thickclub")
|
||||
CobblemonHeldItemManager.registerRemap(Items.SNOWBALL, "snowball")
|
||||
CobblemonHeldItemManager.registerRemap(Items.GOLD_BLOCK, "bignugget")
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ class BattleCountableCriterion(
|
||||
val CODEC: Codec<BattleCountableCriterion> = RecordCodecBuilder.create { it.group(
|
||||
ContextAwarePredicate.CODEC.optionalFieldOf("player").forGetter(BattleCountableCriterion::playerCtx),
|
||||
Codec.STRING.listOf().optionalFieldOf("battle_types", listOf("any")).forGetter(BattleCountableCriterion::battleTypes),
|
||||
Codec.INT.optionalFieldOf( "count", 0).forGetter(BattleCountableCriterion::count)
|
||||
Codec.INT.optionalFieldOf("count", 0).forGetter(BattleCountableCriterion::count)
|
||||
).apply(it, ::BattleCountableCriterion) }
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.api.abilities
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.data.DataRegistry
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.battles.runner.ShowdownService
|
||||
import com.cobblemon.mod.common.net.messages.client.data.AbilityRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.pokemon.abilities.HiddenAbilityType
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
@@ -36,8 +37,11 @@ object Abilities : DataRegistry {
|
||||
PotentialAbility.types.add(CommonAbilityType)
|
||||
PotentialAbility.types.add(HiddenAbilityType)
|
||||
this.abilityMap.clear()
|
||||
Cobblemon.showdownServer.getAbilityIds().forEach { abilityId ->
|
||||
this.register(AbilityTemplate(abilityId))
|
||||
val abilitiesJson = ShowdownService.service.getAbilityIds()
|
||||
for (i in 0 until abilitiesJson.size()) {
|
||||
val id = abilitiesJson[i].asString
|
||||
val ability = AbilityTemplate(id)
|
||||
this.register(ability)
|
||||
}
|
||||
Cobblemon.LOGGER.info("Loaded {} abilities", this.abilityMap.size)
|
||||
this.observable.emit(this)
|
||||
|
||||
+6
-7
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.api.battles.interpreter
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.queryStructOf
|
||||
import com.cobblemon.mod.common.battles.pokemon.AbstractBattlePokemon
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
|
||||
/**
|
||||
@@ -31,8 +30,8 @@ interface BattleContext {
|
||||
/** The [BattleContext.Type] tied to this [BattleContext]. */
|
||||
val type: Type
|
||||
|
||||
/** The [AbstractBattlePokemon] that directly or indirectly caused this [BattleContext]. */
|
||||
val origin: AbstractBattlePokemon?
|
||||
/** The [BattlePokemon] that directly or indirectly caused this [BattleContext]. */
|
||||
val origin: BattlePokemon?
|
||||
|
||||
fun getStruct() = queryStructOf(
|
||||
"type" to { StringValue(type.name) },
|
||||
@@ -70,10 +69,10 @@ interface BattleContext {
|
||||
}
|
||||
|
||||
data class BasicContext(
|
||||
override val id: String,
|
||||
override val turn: Int,
|
||||
override val type: BattleContext.Type,
|
||||
override val origin: AbstractBattlePokemon?
|
||||
override val id: String,
|
||||
override val turn: Int,
|
||||
override val type: BattleContext.Type,
|
||||
override val origin: BattlePokemon?
|
||||
) : BattleContext
|
||||
|
||||
data class MissingContext(
|
||||
|
||||
+5
-6
@@ -13,7 +13,6 @@ import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
import com.cobblemon.mod.common.api.moves.MoveTemplate
|
||||
import com.cobblemon.mod.common.api.moves.Moves
|
||||
import com.cobblemon.mod.common.battles.ActiveBattlePokemon
|
||||
import com.cobblemon.mod.common.battles.pokemon.AbstractBattlePokemon
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import java.util.UUID
|
||||
|
||||
@@ -120,8 +119,8 @@ class BattleMessage(rawMessage: String) {
|
||||
return this
|
||||
}
|
||||
|
||||
fun pokemonByUuid(index: Int, battle: PokemonBattle): AbstractBattlePokemon? {
|
||||
return this.argumentAt(index)?.let { UUID.fromString(it) }?.let { uuid -> battle.actors.flatMap { it.battlePokemonProvider.getKnownPokemon() }.find { it.uuid == uuid } }
|
||||
fun pokemonByUuid(index: Int, battle: PokemonBattle): BattlePokemon? {
|
||||
return this.argumentAt(index)?.let { UUID.fromString(it) }?.let { uuid -> battle.actors.flatMap { it.pokemonList }.find { it.uuid == uuid } }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,7 +142,7 @@ class BattleMessage(rawMessage: String) {
|
||||
* @param battle The [PokemonBattle] being queried.
|
||||
* @return The [BattlePokemon] if the argument exists and is successfully parsed; otherwise null.
|
||||
*/
|
||||
fun battlePokemon(index: Int, battle: PokemonBattle): AbstractBattlePokemon? {
|
||||
fun battlePokemon(index: Int, battle: PokemonBattle): BattlePokemon? {
|
||||
val (actorID, pokemonID) = this.pnxAndUuid(index) ?: return null
|
||||
return this.battlePokemon(actorID, pokemonID, battle)
|
||||
}
|
||||
@@ -155,7 +154,7 @@ class BattleMessage(rawMessage: String) {
|
||||
* @param battle The [PokemonBattle] being queried.
|
||||
* @return The [BattlePokemon] if the argument exists and is successfully parsed; otherwise null.
|
||||
*/
|
||||
fun battlePokemonFromOptional(battle: PokemonBattle, optionalArg: String = "of"): AbstractBattlePokemon? {
|
||||
fun battlePokemonFromOptional(battle: PokemonBattle, optionalArg: String = "of"): BattlePokemon? {
|
||||
val optional = this.optionalArguments.get(optionalArg) ?: return null
|
||||
val pokemonID = optional.takeIf { it.length >= 2 }?.split(":")?.takeIf { it.size == 2 } ?: return null
|
||||
val pnx = pokemonID[0].takeIf { it.matches(PNX_MATCHER) || it.matches(PN_MATCHER) } ?: return null
|
||||
@@ -238,7 +237,7 @@ class BattleMessage(rawMessage: String) {
|
||||
null
|
||||
}
|
||||
|
||||
private fun battlePokemon(pnx: String, pokemonID: String, battle: PokemonBattle): AbstractBattlePokemon? = try {
|
||||
private fun battlePokemon(pnx: String, pokemonID: String, battle: PokemonBattle): BattlePokemon? = try {
|
||||
battle.getBattlePokemon(pnx, pokemonID)
|
||||
} catch (_: Exception) {
|
||||
null
|
||||
|
||||
+23
-31
@@ -40,8 +40,8 @@ import com.cobblemon.mod.common.battles.dispatch.DispatchResult
|
||||
import com.cobblemon.mod.common.battles.dispatch.GO
|
||||
import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
|
||||
import com.cobblemon.mod.common.battles.interpreter.ContextManager
|
||||
import com.cobblemon.mod.common.battles.pokemon.AbstractBattlePokemon
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.battles.runner.ShowdownService
|
||||
import com.cobblemon.mod.common.entity.PlatformType
|
||||
import com.cobblemon.mod.common.entity.npc.NPCBattleActor
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
@@ -51,7 +51,6 @@ import com.cobblemon.mod.common.net.messages.client.battle.BattleMessagePacket
|
||||
import com.cobblemon.mod.common.pokemon.evolution.progress.DefeatEvolutionProgress
|
||||
import com.cobblemon.mod.common.pokemon.evolution.progress.LastBattleCriticalHitsEvolutionProgress
|
||||
import com.cobblemon.mod.common.pokemon.evolution.requirements.DefeatRequirement
|
||||
import com.cobblemon.mod.common.showdown.runner.ShowdownBattle
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.getPlayer
|
||||
import com.cobblemon.mod.common.util.giveOrDropItemStack
|
||||
@@ -75,28 +74,27 @@ import net.minecraft.world.item.ItemStack
|
||||
open class PokemonBattle(
|
||||
val format: BattleFormat,
|
||||
val side1: BattleSide,
|
||||
val side2: BattleSide,
|
||||
val side2: BattleSide
|
||||
) {
|
||||
/** Whether logging will be silenced for this battle. */
|
||||
var mute = true
|
||||
val struct = this.asMoLangValue()
|
||||
val runtime = MoLangRuntime().also { it.environment.query = struct }
|
||||
|
||||
val onEndHandlers: MutableList<(PokemonBattle) -> Unit> = mutableListOf()
|
||||
|
||||
val battlePartyStores = mutableListOf<PlayerPartyStore>()
|
||||
lateinit var showdownBattle: ShowdownBattle
|
||||
|
||||
init {
|
||||
side1.battle = this
|
||||
side2.battle = this
|
||||
this.actors.forEach { actor ->
|
||||
actor.battle = this
|
||||
actor.battlePokemonProvider.getKnownPokemon()
|
||||
.filterIsInstance<BattlePokemon>()
|
||||
.forEach { battlePokemon ->
|
||||
battlePokemon.effectedPokemon.evolutionProxy.current().progress()
|
||||
.filterIsInstance<LastBattleCriticalHitsEvolutionProgress>()
|
||||
.forEach { it.reset() }
|
||||
}
|
||||
actor.pokemonList.forEach { battlePokemon ->
|
||||
battlePokemon.effectedPokemon.evolutionProxy.current().progress()
|
||||
.filterIsInstance<LastBattleCriticalHitsEvolutionProgress>()
|
||||
.forEach { it.reset() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +109,7 @@ open class PokemonBattle(
|
||||
val players = playerUUIDs.mapNotNull { it.getPlayer() }
|
||||
val spectators = mutableSetOf<UUID>()
|
||||
|
||||
val battleId = UUID.randomUUID().toString()
|
||||
val battleId = UUID.randomUUID()
|
||||
|
||||
val showdownMessages = mutableListOf<String>()
|
||||
val battleLog = mutableListOf<String>()
|
||||
@@ -212,10 +210,10 @@ open class PokemonBattle(
|
||||
*
|
||||
* Returns null if the pnx key is invalid or the uuid does not exist.
|
||||
*/
|
||||
fun getBattlePokemon(pnx: String, pokemonID: String): AbstractBattlePokemon {
|
||||
fun getBattlePokemon(pnx: String, pokemonID: String): BattlePokemon {
|
||||
val actor = actors.find { it.showdownId == pnx.substring(0, 2) }
|
||||
?: throw IllegalStateException("Invalid pnx: $pnx - unknown actor")
|
||||
return actor.battlePokemonProvider.getKnownPokemon().find { it.uuid.toString() == pokemonID }
|
||||
return actor.pokemonList.find { it.uuid.toString() == pokemonID }
|
||||
?: throw IllegalStateException("Invalid pnx: $pnx - unknown pokemon")
|
||||
}
|
||||
|
||||
@@ -227,7 +225,7 @@ open class PokemonBattle(
|
||||
|
||||
fun writeShowdownAction(vararg messages: String) {
|
||||
log(messages.joinToString("\n"))
|
||||
showdownBattle.sendMessages(messages.toList())
|
||||
ShowdownService.service.send(battleId, messages.toList().toTypedArray())
|
||||
}
|
||||
|
||||
fun turn(newTurnNumber: Int) {
|
||||
@@ -246,13 +244,9 @@ open class PokemonBattle(
|
||||
fun end() {
|
||||
ended = true
|
||||
this.actors.forEach { actor ->
|
||||
val faintedPokemons = actor.battlePokemonProvider.getKnownPokemon()
|
||||
.filter { it.health <= 0 }
|
||||
.filterIsInstance<BattlePokemon>()
|
||||
val faintedPokemons = actor.pokemonList.filter { it.health <= 0 }
|
||||
actor.getSide().getOppositeSide().actors.forEach { opponent ->
|
||||
val opponentNonFaintedPokemons = opponent.battlePokemonProvider.getKnownPokemon()
|
||||
.filter { it.health > 0 }
|
||||
.filterIsInstance<BattlePokemon>()
|
||||
val opponentNonFaintedPokemons = opponent.pokemonList.filter { it.health > 0 }
|
||||
faintedPokemons.forEach { faintedPokemon ->
|
||||
for (opponentPokemon in opponentNonFaintedPokemons) {
|
||||
val facedFainted = opponentPokemon.facedOpponents.contains(faintedPokemon)
|
||||
@@ -275,7 +269,7 @@ open class PokemonBattle(
|
||||
else -> continue
|
||||
}
|
||||
val experience = Cobblemon.experienceCalculator.calculate(opponentPokemon, faintedPokemon, multiplier)
|
||||
if (experience > 0 && actor.battlePokemonProvider.getKnownPokemon().all { it.health <= 0 }) {
|
||||
if (experience > 0 && actor.pokemonList.all { it.health <= 0 }) {
|
||||
opponent.awardExperience(opponentPokemon, experience)
|
||||
}
|
||||
Cobblemon.evYieldCalculator.calculate(opponentPokemon, faintedPokemon).forEach { (stat, amount) ->
|
||||
@@ -308,15 +302,13 @@ open class PokemonBattle(
|
||||
.filterIsInstance<PokemonEntity>()
|
||||
.forEach{it.pokemon.heal()}
|
||||
actors.forEach { actor ->
|
||||
actor.battlePokemonProvider.getKnownPokemon()
|
||||
.filterIsInstance<BattlePokemon>()
|
||||
.forEach { battlePokemon ->
|
||||
battlePokemon.entity?.let { entity -> battlePokemon.postBattleEntityOperation(entity) }
|
||||
if (battlePokemon.effectedPokemon.entity != null
|
||||
&& battlePokemon.effectedPokemon.entity?.beamMode == 0
|
||||
&& battlePokemon.effectedPokemon.entity?.platform != PlatformType.NONE) {
|
||||
battlePokemon.effectedPokemon.tryRecallWithAnimation()
|
||||
}
|
||||
actor.pokemonList.forEach { battlePokemon ->
|
||||
battlePokemon.entity?.let { entity -> battlePokemon.postBattleEntityOperation(entity) }
|
||||
if (battlePokemon.effectedPokemon.entity != null
|
||||
&& battlePokemon.effectedPokemon.entity?.beamMode == 0
|
||||
&& battlePokemon.effectedPokemon.entity?.platform != PlatformType.NONE) {
|
||||
battlePokemon.effectedPokemon.tryRecallWithAnimation()
|
||||
}
|
||||
}
|
||||
}
|
||||
sendUpdate(BattleEndPacket())
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.battles.model.actor
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.api.battles.model.ai.BattleAI
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.battles.PassActionResponse
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.exception.IllegalActionChoiceException
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleMakeChoicePacket
|
||||
import java.util.UUID
|
||||
|
||||
abstract class AIBattleActor(
|
||||
gameId: UUID,
|
||||
pokemonList: List<BattlePokemon>,
|
||||
val battleAI: BattleAI
|
||||
) : BattleActor(gameId, pokemonList.toMutableList()) {
|
||||
override fun sendUpdate(packet: NetworkPacket<*>) {
|
||||
super.sendUpdate(packet)
|
||||
|
||||
if (packet is BattleMakeChoicePacket) {
|
||||
this.onChoiceRequested()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the AI is requested to make a choice.
|
||||
*/
|
||||
open fun onChoiceRequested() {
|
||||
try {
|
||||
setActionResponses(request!!.iterate(this.activePokemon, battleAI::choose))
|
||||
} catch (exception: IllegalActionChoiceException) {
|
||||
LOGGER.error("AI was unable to choose a move, we're going to need to pass!")
|
||||
exception.printStackTrace()
|
||||
setActionResponses(request!!.iterate(this.activePokemon) { _, _, _ -> PassActionResponse })
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
-20
@@ -8,12 +8,15 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.battles.model.actor
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.battles.model.ai.BattleAI
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.battles.*
|
||||
import com.cobblemon.mod.common.battles.ActiveBattlePokemon
|
||||
import com.cobblemon.mod.common.battles.ForcePassActionResponse
|
||||
import com.cobblemon.mod.common.battles.ShowdownActionRequest
|
||||
import com.cobblemon.mod.common.battles.ShowdownActionResponse
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.exception.IllegalActionChoiceException
|
||||
@@ -28,11 +31,10 @@ import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
abstract class BattleActor(
|
||||
val uuid: UUID,
|
||||
val battlePokemonProvider: BattlePokemonProvider,
|
||||
val battleAi: BattleAI? = null
|
||||
val pokemonList: MutableList<BattlePokemon>
|
||||
) {
|
||||
init {
|
||||
battlePokemonProvider.getKnownPokemon().forEach { it.actor = this }
|
||||
pokemonList.forEach { it.actor = this }
|
||||
}
|
||||
|
||||
val struct = asMoLangValue()
|
||||
@@ -71,7 +73,7 @@ abstract class BattleActor(
|
||||
open fun isForPlayer(serverPlayerEntity: ServerPlayer) = serverPlayerEntity.uuid in getPlayerUUIDs()
|
||||
open fun isForPokemon(pokemonEntity: PokemonEntity) = activePokemon.any { it.battlePokemon?.effectedPokemon?.entity == pokemonEntity }
|
||||
|
||||
open fun turn() {
|
||||
fun turn() {
|
||||
val request = request ?: return
|
||||
responses.clear()
|
||||
if(activePokemon.any { it.isAlive() }) {
|
||||
@@ -153,19 +155,7 @@ abstract class BattleActor(
|
||||
sendUpdate(BattleMessagePacket(component))
|
||||
}
|
||||
open fun awardExperience(battlePokemon: BattlePokemon, experience: Int) {}
|
||||
open fun sendUpdate(packet: NetworkPacket<*>) {
|
||||
if (battleAi != null) {
|
||||
if (packet is BattleMakeChoicePacket) {
|
||||
try {
|
||||
setActionResponses(request!!.iterate(this.activePokemon, battleAi::choose))
|
||||
} catch (exception: IllegalActionChoiceException) {
|
||||
LOGGER.error("AI was unable to choose a move, we're going to need to pass!")
|
||||
exception.printStackTrace()
|
||||
setActionResponses(request!!.iterate(this.activePokemon) { _, _, _ -> PassActionResponse })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
open fun sendUpdate(packet: NetworkPacket<*>) {}
|
||||
|
||||
open fun win(otherWinners: List<BattleActor>, losers: List<BattleActor>) {}
|
||||
open fun lose(winners: List<BattleActor>, otherLosers: List<BattleActor>) {}
|
||||
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
package com.cobblemon.mod.common.api.battles.model.actor
|
||||
|
||||
import com.cobblemon.mod.common.battles.pokemon.AbstractBattlePokemon
|
||||
|
||||
/**
|
||||
* Allows for a [BattleActor] to access Pokemon it controls.
|
||||
*
|
||||
* We don't always know what Pokemon an actor has when starting a battle
|
||||
*/
|
||||
interface BattlePokemonProvider {
|
||||
fun getKnownPokemon(): List<AbstractBattlePokemon>;
|
||||
}
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
package com.cobblemon.mod.common.api.battles.model.actor
|
||||
|
||||
import com.cobblemon.mod.common.battles.pokemon.AbstractBattlePokemon
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
|
||||
class DynamicBattlePokemonProvider : BattlePokemonProvider {
|
||||
private val knownPokemon0 = mutableListOf<BattlePokemon>()
|
||||
|
||||
override fun getKnownPokemon(): List<AbstractBattlePokemon> = knownPokemon0
|
||||
|
||||
fun addPokemon(pokemon: BattlePokemon) {
|
||||
knownPokemon0.add(pokemon)
|
||||
}
|
||||
}
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
package com.cobblemon.mod.common.api.battles.model.actor
|
||||
|
||||
import com.cobblemon.mod.common.battles.pokemon.AbstractBattlePokemon
|
||||
|
||||
class StaticBattlePokemonProvider(val pokemon: List<AbstractBattlePokemon>) : BattlePokemonProvider{
|
||||
override fun getKnownPokemon(): List<AbstractBattlePokemon> = pokemon
|
||||
}
|
||||
+2
@@ -13,6 +13,8 @@ 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.api.battles.model.actor.BattleActor
|
||||
import com.cobblemon.mod.common.battles.actor.PlayerBattleActor
|
||||
import com.cobblemon.mod.common.entity.npc.NPCBattleActor
|
||||
import com.cobblemon.mod.common.util.asArrayValue
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ data class PokemonInteractionGUICreationEvent(
|
||||
|
||||
private fun getNextFreeOrientation(): Orientation {
|
||||
var largest = Orientation.TOP_LEFT
|
||||
for(orientation in Orientation.values()) {
|
||||
for (orientation in Orientation.entries) {
|
||||
if(!options.containsKey(orientation)) {
|
||||
return orientation
|
||||
} else {
|
||||
|
||||
+7
-12
@@ -19,6 +19,7 @@ import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.item.battle.BagItem
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.getBattleState
|
||||
import com.cobblemon.mod.common.util.isHeld
|
||||
import com.cobblemon.mod.common.util.isLookingAt
|
||||
import com.cobblemon.mod.common.util.party
|
||||
@@ -43,7 +44,6 @@ interface PokemonAndMoveSelectingItem {
|
||||
.filter { player.isLookingAt(it, stepDistance = 0.1F) }
|
||||
.minByOrNull { it.distanceTo(player) } as? PokemonEntity?
|
||||
|
||||
/*
|
||||
player.getBattleState()?.let { (_, actor) ->
|
||||
if (bagItem == null) {
|
||||
return InteractionResultHolder.fail(stack)
|
||||
@@ -52,16 +52,13 @@ interface PokemonAndMoveSelectingItem {
|
||||
player.sendSystemMessage(battleLang("bagitem.cannot").red())
|
||||
return InteractionResultHolder.fail(stack)
|
||||
}
|
||||
//val battlePokemon = actor.battlePokemonProvider.getKnownPokemon().find { it.effectedPokemon == entity?.pokemon }
|
||||
val battlePokemon = actor.pokemonList.find { it.effectedPokemon == entity?.pokemon }
|
||||
if (entity == null) {
|
||||
return interactGeneralBattle(player, stack, actor)
|
||||
} else if (battlePokemon != null) {
|
||||
return interactWithSpecificBattle(player, stack, battlePokemon)
|
||||
}
|
||||
|
||||
} ?:
|
||||
*/
|
||||
run {
|
||||
} ?: run {
|
||||
if (entity != null) {
|
||||
val pokemon = entity.pokemon
|
||||
if (entity.ownerUUID == player.uuid) {
|
||||
@@ -143,16 +140,14 @@ interface PokemonAndMoveSelectingItem {
|
||||
}
|
||||
|
||||
fun interactGeneralBattle(player: ServerPlayer, stack: ItemStack, actor: BattleActor): InteractionResultHolder<ItemStack>? {
|
||||
/*
|
||||
PartyMoveSelectCallbacks.createFromPokemon(
|
||||
player = player,
|
||||
pokemon = actor.battlePokemonProvider.getKnownPokemon().map { it.effectedPokemon },
|
||||
moves = { pk -> actor.battlePokemonProvider.getKnownPokemon().find { it.effectedPokemon == pk }!!.moveSet.getMoves() },
|
||||
canSelectPokemon = { pk -> canUseOnBattlePokemon(actor.battlePokemonProvider.getKnownPokemon().find { it.effectedPokemon == pk }!!) },
|
||||
pokemon = actor.pokemonList.map { it.effectedPokemon },
|
||||
moves = { pk -> actor.pokemonList.find { it.effectedPokemon == pk }!!.moveSet.getMoves() },
|
||||
canSelectPokemon = { pk -> canUseOnBattlePokemon(actor.pokemonList.find { it.effectedPokemon == pk }!!) },
|
||||
canSelectMove = ::canUseOnMove,
|
||||
handler = { pk, mv -> applyToBattlePokemon(player, stack, actor.battlePokemonProvider.getKnownPokemon().find { it.effectedPokemon == pk }!!, mv) }
|
||||
handler = { pk, mv -> applyToBattlePokemon(player, stack, actor.pokemonList.find { it.effectedPokemon == pk }!!, mv) }
|
||||
)
|
||||
*/
|
||||
|
||||
return InteractionResultHolder.success(stack)
|
||||
}
|
||||
|
||||
@@ -18,11 +18,7 @@ import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.item.battle.BagItem
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.getBattleState
|
||||
import com.cobblemon.mod.common.util.isHeld
|
||||
import com.cobblemon.mod.common.util.isLookingAt
|
||||
import com.cobblemon.mod.common.util.party
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.InteractionResultHolder
|
||||
@@ -50,7 +46,7 @@ interface PokemonSelectingItem {
|
||||
|
||||
player.getBattleState()?.let { (_, actor) ->
|
||||
if (bagItem == null) return InteractionResultHolder.fail(stack)
|
||||
// val battlePokemon = actor.battlePokemonProvider.getKnownPokemon().find { it.effectedPokemon == entity?.pokemon }
|
||||
val battlePokemon = actor.pokemonList.find { it.effectedPokemon == entity?.pokemon }
|
||||
|
||||
if (!actor.canFitForcedAction()) {
|
||||
player.sendSystemMessage(battleLang("bagitem.cannot").red())
|
||||
@@ -59,12 +55,9 @@ interface PokemonSelectingItem {
|
||||
|
||||
if (entity == null) {
|
||||
return interactGeneralBattle(player, stack, actor)
|
||||
}
|
||||
/*
|
||||
else if (battlePokemon != null) {
|
||||
} else if (battlePokemon != null) {
|
||||
return interactWithSpecificBattle(player, stack, battlePokemon)
|
||||
}
|
||||
*/
|
||||
} ?: run {
|
||||
if (!player.isShiftKeyDown) {
|
||||
return if (entity != null) {
|
||||
@@ -147,16 +140,13 @@ interface PokemonSelectingItem {
|
||||
}
|
||||
|
||||
fun interactGeneralBattle(player: ServerPlayer, stack: ItemStack, actor: BattleActor): InteractionResultHolder<ItemStack> {
|
||||
/*
|
||||
PartySelectCallbacks.createBattleSelect(
|
||||
player = player,
|
||||
pokemon = actor.battlePokemonProvider.getKnownPokemon(),
|
||||
canSelect = { pk -> canUseOnBattlePokemon(actor.battlePokemonProvider.getKnownPokemon().find { it.effectedPokemon == pk.effectedPokemon }!!) },
|
||||
handler = { pk -> applyToBattlePokemon(player, stack, actor.battlePokemonProvider.getKnownPokemon().find { it.effectedPokemon == pk.effectedPokemon }!!) }
|
||||
pokemon = actor.pokemonList,
|
||||
canSelect = { pk -> canUseOnBattlePokemon(actor.pokemonList.find { it.effectedPokemon == pk.effectedPokemon }!!) },
|
||||
handler = { pk -> applyToBattlePokemon(player, stack, actor.pokemonList.find { it.effectedPokemon == pk.effectedPokemon }!!) }
|
||||
)
|
||||
|
||||
*/
|
||||
|
||||
return InteractionResultHolder.success(stack)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,8 @@ import com.cobblemon.mod.common.api.pokedex.SeenPercent
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
import com.cobblemon.mod.common.api.storage.PokemonStore
|
||||
|
||||
@@ -13,7 +13,6 @@ import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectTimeline
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
|
||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategories
|
||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategory
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
@@ -22,10 +21,7 @@ import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.cobblemon.mod.common.battles.MoveTarget
|
||||
import com.cobblemon.mod.common.util.codec.CodecUtils
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import com.mojang.serialization.Codec
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
@@ -122,56 +118,6 @@ open class MoveTemplate(
|
||||
ElementalTypes.DRAGON,
|
||||
ElementalTypes.DARK
|
||||
)
|
||||
|
||||
fun decodeJsonMove(json: JsonObject, id: String? = null): MoveTemplate {
|
||||
val id = id ?: json.get("id").asString
|
||||
val num = json.get("num").asInt
|
||||
val elementalType = ElementalTypes.getOrException(json.get("type").asString)
|
||||
val damageCategory = DamageCategories.getOrException(json.get("category").asString)
|
||||
val power = json.get("basePower").asDouble
|
||||
val target = MoveTarget.fromShowdownId(json.get("target").asString)
|
||||
// If not a double it's always true
|
||||
val accuracyJson = json.get("accuracy").asJsonPrimitive
|
||||
val accuracy = if (accuracyJson.isNumber) accuracyJson.asDouble else -1.0
|
||||
val pp = json.get("pp").asInt
|
||||
val priority = json.get("priority").asInt
|
||||
val critRatio = json.get("critRatio")?.asDouble ?: 1.0
|
||||
val effectChances = arrayListOf<Double>()
|
||||
val secondariesMember = json.get("secondaries")
|
||||
val secondaryMember = json.get("secondary")
|
||||
if (secondariesMember != null && secondariesMember is JsonArray) {
|
||||
for (j in 0 until secondariesMember.size()) {
|
||||
val element = secondariesMember[j].asJsonObject
|
||||
// They declare moves without data on secondary effects for sheer force compatibility
|
||||
if (element.has("chance")) {
|
||||
effectChances += element.get("chance").asDouble
|
||||
}
|
||||
}
|
||||
} else if (secondaryMember != null && secondaryMember is JsonObject) {
|
||||
// They declare moves without data on secondary effects for sheer force compatibility
|
||||
if (secondaryMember.has("chance")) {
|
||||
effectChances += secondaryMember.get("chance").asDouble
|
||||
}
|
||||
}
|
||||
val actionEffect = ActionEffects.actionEffects[id.asIdentifierDefaultingNamespace()]
|
||||
?: run {
|
||||
ActionEffects.actionEffects["generic_move".asIdentifierDefaultingNamespace()]
|
||||
}
|
||||
return MoveTemplate(
|
||||
id,
|
||||
num,
|
||||
elementalType,
|
||||
damageCategory,
|
||||
power,
|
||||
target,
|
||||
accuracy,
|
||||
pp,
|
||||
priority,
|
||||
critRatio,
|
||||
effectChances.toTypedArray(),
|
||||
actionEffect
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -220,7 +166,7 @@ open class MoveTemplate(
|
||||
// TODO: Handle Liquid Voice: need to know what moves have the sound flag
|
||||
// TODO: Handle weatherball, naturalgift, judgement, technoblast, terrainpulse, and terrablast
|
||||
if (this.elementalType == ElementalTypes.NORMAL) {
|
||||
if( this.damageCategory != DamageCategories.STATUS) {
|
||||
if (this.damageCategory != DamageCategories.STATUS) {
|
||||
return when (pokemon.ability.name) {
|
||||
"pixilate" -> ElementalTypes.FAIRY
|
||||
"aerilate" -> ElementalTypes.FLYING
|
||||
|
||||
@@ -10,9 +10,17 @@ package com.cobblemon.mod.common.api.moves
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.data.DataRegistry
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
|
||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategories
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.cobblemon.mod.common.battles.MoveTarget
|
||||
import com.cobblemon.mod.common.battles.runner.ShowdownService
|
||||
import com.cobblemon.mod.common.net.messages.client.data.MovesRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.server.packs.PackType
|
||||
import net.minecraft.server.packs.resources.ResourceManager
|
||||
@@ -32,7 +40,57 @@ object Moves : DataRegistry {
|
||||
override fun reload(manager: ResourceManager) {
|
||||
this.allMoves.clear()
|
||||
this.idMapping.clear()
|
||||
Cobblemon.showdownServer.getMoves().forEach(::register)
|
||||
val movesJson = ShowdownService.service.getMoves()
|
||||
for (i in 0 until movesJson.size()) {
|
||||
val jsMove = movesJson[i].asJsonObject
|
||||
val id = jsMove.get("id").asString
|
||||
try {
|
||||
val num = jsMove.get("num").asInt
|
||||
val elementalType = ElementalTypes.getOrException(jsMove.get("type").asString)
|
||||
val damageCategory = DamageCategories.getOrException(jsMove.get("category").asString)
|
||||
val power = jsMove.get("basePower").asDouble
|
||||
val target = MoveTarget.fromShowdownId(jsMove.get("target").asString)
|
||||
// If not a double it's always true
|
||||
val accuracyJson = jsMove.get("accuracy").asJsonPrimitive
|
||||
val accuracy = if (accuracyJson.isNumber) accuracyJson.asDouble else -1.0
|
||||
val pp = jsMove.get("pp").asInt
|
||||
val priority = jsMove.get("priority").asInt
|
||||
val critRatio = jsMove.get("critRatio")?.asDouble ?: 1.0
|
||||
val effectChances = arrayListOf<Double>()
|
||||
val secondariesMember = jsMove.get("secondaries")
|
||||
val secondaryMember = jsMove.get("secondary")
|
||||
if (secondariesMember != null && secondariesMember is JsonArray) {
|
||||
for (j in 0 until secondariesMember.size()) {
|
||||
val element = secondariesMember[j].asJsonObject
|
||||
// They declare moves without data on secondary effects for sheer force compatibility
|
||||
if (element.has("chance")) {
|
||||
effectChances += element.get("chance").asDouble
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (secondaryMember != null && secondaryMember is JsonObject) {
|
||||
// They declare moves without data on secondary effects for sheer force compatibility
|
||||
if (secondaryMember.has("chance")) {
|
||||
effectChances += secondaryMember.get("chance").asDouble
|
||||
}
|
||||
}
|
||||
val actionEffect = ActionEffects.actionEffects[id.asIdentifierDefaultingNamespace()]
|
||||
?: run {
|
||||
ActionEffects.actionEffects["generic_move".asIdentifierDefaultingNamespace()]
|
||||
// if (damageCategory == DamageCategories.STATUS) {
|
||||
// ActionEffects.actionEffects[cobblemonResource("status")]
|
||||
// } else {
|
||||
// val type = elementalType.name.lowercase()
|
||||
// val category = damageCategory.name.lowercase()
|
||||
// ActionEffects.actionEffects["${category}_$type".asIdentifierDefaultingNamespace()]
|
||||
// }
|
||||
}
|
||||
val move = MoveTemplate(id, num, elementalType, damageCategory, power, target, accuracy, pp, priority, critRatio, effectChances.toTypedArray(), actionEffect)
|
||||
this.register(move)
|
||||
} catch (e: Exception) {
|
||||
Cobblemon.LOGGER.error("Caught exception trying to resolve the move '{}'", id, e)
|
||||
}
|
||||
}
|
||||
Cobblemon.LOGGER.info("Loaded {} moves", this.allMoves.size)
|
||||
this.observable.emit(this)
|
||||
}
|
||||
|
||||
@@ -47,29 +47,8 @@ import com.cobblemon.mod.common.pokemon.evolution.adapters.CobblemonPreEvolution
|
||||
import com.cobblemon.mod.common.pokemon.evolution.adapters.CobblemonRequirementAdapter
|
||||
import com.cobblemon.mod.common.pokemon.evolution.adapters.LegacyItemConditionWrapperAdapter
|
||||
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
|
||||
import com.cobblemon.mod.common.showdown.runner.CobblemonShowdownBattleServer
|
||||
import com.cobblemon.mod.common.util.adapters.AbilityPoolAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.AbilityTemplateAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.BiomeLikeConditionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.BlockLikeConditionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.BoxAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.DropEntryAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.EggGroupAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.IntRangeAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.IntRangesAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ItemLikeConditionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.LazySetAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.LearnsetAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.NbtCompoundAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.RegistryElementAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.*
|
||||
import com.cobblemon.mod.common.util.adapters.RideControllerAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.RidingStatDefinitionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.StructureLikeConditionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.TextAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.pokemonPropertiesShortAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.common.collect.HashBasedTable
|
||||
import com.google.gson.Gson
|
||||
@@ -82,6 +61,7 @@ import net.minecraft.network.chat.Component
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.server.packs.PackType
|
||||
import net.minecraft.sounds.SoundEvent
|
||||
import net.minecraft.world.effect.MobEffect
|
||||
import net.minecraft.world.entity.EntityDimensions
|
||||
import net.minecraft.world.item.Item
|
||||
@@ -129,6 +109,7 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
.registerTypeAdapter(ItemPredicate::class.java, LegacyItemConditionWrapperAdapter)
|
||||
.registerTypeAdapter(RideController::class.java, RideControllerAdapter)
|
||||
.registerTypeAdapter(RidingStatDefinition::class.java, RidingStatDefinitionAdapter)
|
||||
.registerTypeAdapter(SoundEvent::class.java, SoundEventAdapter)
|
||||
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
|
||||
.disableHtmlEscaping()
|
||||
.enableComplexMapKeySerialization()
|
||||
@@ -151,10 +132,8 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
this.species.forEach(Species::initialize)
|
||||
this.species.forEach(Species::resolveEvolutionMoves)
|
||||
Cobblemon.showdownThread.queue {
|
||||
if (it is CobblemonShowdownBattleServer) {
|
||||
it.registerSpecies()
|
||||
it.indicateSpeciesInitialized()
|
||||
}
|
||||
it.registerSpecies()
|
||||
it.indicateSpeciesInitialized()
|
||||
// Reload this with the mod
|
||||
CobblemonHeldItemManager.load()
|
||||
Cobblemon.LOGGER.info("Loaded {} Pokémon species", this.speciesByIdentifier.size)
|
||||
|
||||
@@ -176,7 +176,7 @@ interface Evolution : EvolutionLike {
|
||||
pokemonEntity.after(11.2F) {
|
||||
evolutionMethod(pokemon)
|
||||
}
|
||||
pokemonEntity.after( seconds = 12F ) {
|
||||
pokemonEntity.after(seconds = 12F) {
|
||||
cryAnimation(pokemonEntity)
|
||||
pokemonEntity.entityData.set(PokemonEntity.EVOLUTION_STARTED, false)
|
||||
pokemon.getOwnerPlayer()?.sendSystemMessage(lang("ui.evolve.into", preEvoName, pokemon.species.translatedName))
|
||||
|
||||
+1
-1
@@ -15,8 +15,8 @@ import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.helditem.BaseCobblemonHeldItemManager
|
||||
import com.cobblemon.mod.common.pokemon.helditem.CobblemonEmptyHeldItemManager
|
||||
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.network.chat.Component
|
||||
|
||||
/**
|
||||
* Responsible for querying [BattlePokemon] for the presence of held items and their consumption.
|
||||
|
||||
@@ -10,15 +10,23 @@ package com.cobblemon.mod.common.api.riding
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.Rollable
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.riding.controller.RideController
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.toProperties
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.ChatFormatting
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.SmoothDouble
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import kotlin.math.sin
|
||||
import kotlin.math.sin
|
||||
|
||||
data class RidingManager(val entity: PokemonEntity) {
|
||||
var lastSpeed = 0F
|
||||
@@ -31,6 +39,17 @@ data class RidingManager(val entity: PokemonEntity) {
|
||||
.withQueryValue("entity", entity.struct)
|
||||
.also {
|
||||
it.environment.query.addFunction("passenger_count") { DoubleValue(entity.passengers.size.toDouble()) }
|
||||
it.environment.query.addFunction("get_ride_stats") { params ->
|
||||
val rideStat = RidingStat.valueOf(params.getString(0).uppercase())
|
||||
val rideStyle = RidingStyle.valueOf(params.getString(1).uppercase())
|
||||
val maxVal = params.getDouble(2)
|
||||
val minVal = params.getDouble(3)
|
||||
//TODO: Use the mons actual boost once implemented
|
||||
val normalizedStat = entity.rideProp.calculate(rideStat, rideStyle, 0) / 100.0f
|
||||
val trueStatVal = (normalizedStat * (maxVal - minVal)) + minVal
|
||||
|
||||
DoubleValue(trueStatVal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,8 +77,17 @@ data class RidingManager(val entity: PokemonEntity) {
|
||||
|
||||
val pose = controller.pose(entity)
|
||||
entity.entityData.set(PokemonEntity.POSE_TYPE, pose)
|
||||
//val speedPlayer = driver.deltaMovement.horizontalDistance()
|
||||
//driver.displayClientMessage(Component.literal("Speed player: ").withStyle { it.withColor(ChatFormatting.GREEN) }.append(Component.literal("$speedPlayer b/t")), true)
|
||||
//val speedEntity = entity.deltaMovement.length() //* 20 * 60 * 60) / ( 1000 )
|
||||
//println(speedEntity)
|
||||
//driver.displayClientMessage(Component.literal("Speed: ").withStyle { it.withColor(ChatFormatting.GREEN) }.append(Component.literal("${String.format("%.2f", speedEntity)} km/h")), true)
|
||||
//val speedPlayer = driver.deltaMovement.horizontalDistance()
|
||||
//driver.displayClientMessage(Component.literal("Speed player: ").withStyle { it.withColor(ChatFormatting.GREEN) }.append(Component.literal("$speedPlayer b/t")), true)
|
||||
//val speedEntity = entity.deltaMovement.length() //* 20 * 60 * 60) / ( 1000 )
|
||||
//println(speedEntity)
|
||||
//driver.displayClientMessage(Component.literal("Speed: ").withStyle { it.withColor(ChatFormatting.GREEN) }.append(Component.literal("${String.format("%.2f", speedEntity)} km/h")), true)
|
||||
|
||||
// driver.displayClientMessage(Component.literal("Speed: ").withStyle { it.withColor(ChatFormatting.GREEN) }.append(Component.literal("$lastSpeed b/t")), true)
|
||||
}
|
||||
|
||||
fun speed(entity: PokemonEntity, driver: Player): Float {
|
||||
@@ -91,6 +119,16 @@ data class RidingManager(val entity: PokemonEntity) {
|
||||
return controller.velocity(entity, driver, input)
|
||||
}
|
||||
|
||||
fun setRideBar(entity: PokemonEntity, driver: Player): Float {
|
||||
val controller = getController(entity) ?: return 0.0f
|
||||
return controller.setRideBar(entity, driver)
|
||||
}
|
||||
|
||||
fun rideFovMult(entity: PokemonEntity, driver: Player): Float {
|
||||
val controller = getController(entity) ?: return 1.0f
|
||||
return controller.rideFovMult(entity, driver)
|
||||
}
|
||||
|
||||
fun canJump(entity: PokemonEntity, driver: Player): Boolean {
|
||||
val controller = getController(entity) ?: return false
|
||||
return controller.canJump(entity, driver)
|
||||
@@ -101,11 +139,23 @@ data class RidingManager(val entity: PokemonEntity) {
|
||||
return controller.jumpForce(entity, driver, jumpStrength)
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to supply the delta for the lerp() between velocity
|
||||
* vectors. Called inertia for now as the way it feels when
|
||||
* affecting the ride is somewhat akin to inertia.
|
||||
*/
|
||||
fun inertia(entity: PokemonEntity): Double {
|
||||
val controller = getController(entity) ?: return 0.5
|
||||
return controller.inertia(entity)
|
||||
}
|
||||
|
||||
fun gravity(entity: PokemonEntity, regularGravity: Double): Double? {
|
||||
val controller = getController(entity) ?: return null
|
||||
return controller.gravity(entity, regularGravity)
|
||||
}
|
||||
|
||||
//Maybe should be changed to be a function that conveys:
|
||||
// "turn on use our camera system function"
|
||||
fun shouldRoll(entity: PokemonEntity): Boolean {
|
||||
val controller = getController(entity) ?: return false
|
||||
return controller.shouldRoll(entity)
|
||||
@@ -121,8 +171,50 @@ data class RidingManager(val entity: PokemonEntity) {
|
||||
return controller.shouldRotatePokemonHead()
|
||||
}
|
||||
|
||||
//FIXME: Make this not just be false for all controllers lol
|
||||
fun rotationOnMouseXY(
|
||||
entity: PokemonEntity,
|
||||
driver: Player,
|
||||
yMouse: Double,
|
||||
xMouse: Double,
|
||||
yMouseSmoother: SmoothDouble,
|
||||
xMouseSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
val controller = getController(entity) ?: return Vec3.ZERO
|
||||
return controller.rotationOnMouseXY(
|
||||
entity,
|
||||
driver,
|
||||
yMouse,
|
||||
xMouse,
|
||||
yMouseSmoother,
|
||||
xMouseSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
) }
|
||||
|
||||
/**
|
||||
* Determines whether mouse input will affect the rotation of
|
||||
* the rollable object. Need to remove this as it's not used anymore
|
||||
*/
|
||||
//I think this might better serve as a "use smoothing on angular velocity"
|
||||
fun useAngVelSmoothing(entity: PokemonEntity): Boolean {
|
||||
val controller = getController(entity) ?: return true
|
||||
return controller.useAngVelSmoothing(entity)
|
||||
}
|
||||
|
||||
fun turnOffOnGround(entity: PokemonEntity): Boolean {
|
||||
val controller = getController(entity) ?: return false
|
||||
return controller.turnOffOnGround(entity)
|
||||
}
|
||||
|
||||
fun angRollVel(entity: PokemonEntity, driver: Player, deltaTime: Double): Vec3 {
|
||||
val controller = getController(entity) ?: return Vec3(0.0, 0.0, 0.0)
|
||||
return controller.angRollVel(entity, driver, deltaTime)
|
||||
}
|
||||
|
||||
fun dismountOnShift(): Boolean {
|
||||
return false
|
||||
val controller = getController(entity) ?: return false
|
||||
return controller.dismountOnShift(entity)
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.riding
|
||||
|
||||
import net.minecraft.client.player.LocalPlayer
|
||||
import net.minecraft.client.resources.sounds.AbstractTickableSoundInstance
|
||||
import net.minecraft.client.resources.sounds.SoundInstance
|
||||
import net.minecraft.sounds.SoundEvent
|
||||
import net.minecraft.sounds.SoundSource
|
||||
|
||||
/**
|
||||
* put what it is here
|
||||
*
|
||||
* @author Jackowes
|
||||
* @since March 4th, 2025
|
||||
*/
|
||||
class RidingOnPlayerSoundEventInstance(
|
||||
private val player: LocalPlayer,
|
||||
soundEvent: SoundEvent
|
||||
) : AbstractTickableSoundInstance(soundEvent, SoundSource.PLAYERS, SoundInstance.createUnseededRandom()) {
|
||||
|
||||
|
||||
init {
|
||||
this.looping = true
|
||||
this.delay = 0
|
||||
this.volume = 0.1f
|
||||
}
|
||||
|
||||
fun setPitch( pitch: Float ){
|
||||
this.pitch = pitch
|
||||
}
|
||||
|
||||
fun setVolume( volume: Float){
|
||||
this.volume = volume
|
||||
}
|
||||
|
||||
override fun tick() {
|
||||
//TODO: implement effectively
|
||||
//For now it should just play the sound?
|
||||
setPitch(1.0f)
|
||||
println("ticking")
|
||||
}
|
||||
|
||||
}
|
||||
+41
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.riding.controller
|
||||
|
||||
import com.cobblemon.mod.common.Rollable
|
||||
import com.cobblemon.mod.common.api.net.Decodable
|
||||
import com.cobblemon.mod.common.api.net.Encodable
|
||||
import com.cobblemon.mod.common.api.riding.RidingState
|
||||
@@ -17,6 +18,7 @@ import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.writeIdentifier
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.SmoothDouble
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.phys.Vec2
|
||||
@@ -71,6 +73,14 @@ interface RideController : Encodable, Decodable {
|
||||
*/
|
||||
fun rotation(entity: PokemonEntity, driver: LivingEntity) : Vec2
|
||||
|
||||
/**
|
||||
* Sets the change current change in rotation for that tick in three
|
||||
* dimensions
|
||||
*/
|
||||
fun angRollVel(entity: PokemonEntity, driver: Player, deltaTime: Double): Vec3 {
|
||||
return Vec3(0.0, 0.0, 0.0)
|
||||
}
|
||||
|
||||
fun clampPassengerRotation(entity: PokemonEntity, driver: LivingEntity) {}
|
||||
|
||||
fun updatePassengerRotation(entity: PokemonEntity, driver: LivingEntity) {
|
||||
@@ -84,13 +94,44 @@ interface RideController : Encodable, Decodable {
|
||||
*/
|
||||
fun velocity(entity: PokemonEntity, driver: Player, input: Vec3) : Vec3
|
||||
|
||||
fun setRideBar(entity: PokemonEntity, driver: Player): Float = 0.0f
|
||||
|
||||
fun rideFovMult(entity: PokemonEntity, driver: Player): Float = 1.0f
|
||||
|
||||
fun canJump(entity: PokemonEntity, driver: Player) : Boolean
|
||||
fun jumpForce(entity: PokemonEntity, driver: Player, jumpStrength: Int) : Vec3
|
||||
|
||||
fun gravity(entity: PokemonEntity, regularGravity: Double) : Double? = null
|
||||
|
||||
fun inertia(entity: PokemonEntity ) : Double = 0.5
|
||||
|
||||
fun shouldRoll(entity: PokemonEntity): Boolean = false
|
||||
|
||||
fun useAngVelSmoothing(entity: PokemonEntity): Boolean = false
|
||||
|
||||
//If function is not overwritten by controllers then just perform the defualt
|
||||
//rolling function which is roll on mousex and pitch on mousey
|
||||
fun rotationOnMouseXY(
|
||||
entity: PokemonEntity,
|
||||
driver: Player,
|
||||
yMouse: Double,
|
||||
xMouse: Double,
|
||||
yMouseSmoother: SmoothDouble,
|
||||
xMouseSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if(driver !is Rollable) return Vec3.ZERO
|
||||
|
||||
//Might need to add the smoothing here for default.
|
||||
val rollable = driver as Rollable
|
||||
return Vec3(0.0, yMouse, xMouse )
|
||||
}
|
||||
|
||||
fun turnOffOnGround(entity: PokemonEntity): Boolean = false
|
||||
|
||||
fun dismountOnShift(entity: PokemonEntity): Boolean = false
|
||||
|
||||
fun getRuntime(entity: PokemonEntity) = entity.riding.runtime
|
||||
|
||||
fun shouldRotatePokemonHead(): Boolean = false
|
||||
|
||||
@@ -110,7 +110,7 @@ open class BottomlessStore(override val uuid: UUID) : PokemonStore<BottomlessPos
|
||||
} else {
|
||||
this.pokemon.removeAt(position.currentIndex)
|
||||
}
|
||||
for(i in startIndex until this.pokemon.size) {
|
||||
for (i in startIndex until this.pokemon.size) {
|
||||
this.pokemon[i].storeCoordinates.set(StoreCoordinates(this, BottomlessPosition(i)))
|
||||
}
|
||||
storeChangeObservable.emit(Unit)
|
||||
|
||||
@@ -13,9 +13,9 @@ import com.cobblemon.mod.common.api.PrioritizedList
|
||||
import com.cobblemon.mod.common.api.data.DataRegistry
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.battles.BagItems.bagItems
|
||||
import com.cobblemon.mod.common.battles.runner.ShowdownService
|
||||
import com.cobblemon.mod.common.item.battle.BagItem
|
||||
import com.cobblemon.mod.common.item.battle.BagItemLike
|
||||
import com.cobblemon.mod.common.showdown.runner.CobblemonShowdownBattleServer
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
@@ -42,11 +42,7 @@ object BagItems : DataRegistry {
|
||||
|
||||
init {
|
||||
observable.subscribe {
|
||||
if (Cobblemon.showdownServer is CobblemonShowdownBattleServer) {
|
||||
Cobblemon.showdownThread.queue {
|
||||
(Cobblemon.showdownServer as CobblemonShowdownBattleServer).registerBagItems()
|
||||
}
|
||||
}
|
||||
Cobblemon.showdownThread.queue(ShowdownService::registerBagItems)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.battles
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
import com.cobblemon.mod.common.api.storage.party.PartyStore
|
||||
@@ -24,15 +25,29 @@ import com.cobblemon.mod.common.util.effectiveName
|
||||
import com.cobblemon.mod.common.util.getBattleTheme
|
||||
import com.cobblemon.mod.common.util.getPlayer
|
||||
import com.cobblemon.mod.common.util.party
|
||||
import com.cobblemon.mod.common.util.swap
|
||||
import java.util.UUID
|
||||
import com.cobblemon.mod.common.util.update
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import java.util.UUID
|
||||
import kotlin.collections.HashMap
|
||||
import kotlin.collections.Iterable
|
||||
import kotlin.collections.MutableSet
|
||||
import kotlin.collections.all
|
||||
import kotlin.collections.filterIsInstance
|
||||
import kotlin.collections.first
|
||||
import kotlin.collections.flatMap
|
||||
import kotlin.collections.forEach
|
||||
import kotlin.collections.isNotEmpty
|
||||
import kotlin.collections.mapNotNull
|
||||
import kotlin.collections.mutableSetOf
|
||||
import kotlin.collections.plus
|
||||
import kotlin.collections.plusAssign
|
||||
import kotlin.collections.set
|
||||
import kotlin.collections.sortedBy
|
||||
|
||||
object BattleBuilder {
|
||||
@JvmOverloads
|
||||
@@ -77,21 +92,18 @@ object BattleBuilder {
|
||||
val errors = ErroredBattleStart()
|
||||
|
||||
for ((player, actor) in arrayOf(player1 to player1Actor, player2 to player2Actor)) {
|
||||
/*
|
||||
if (actor.battlePokemonProvider.getKnownPokemon().filter { it.health > 0 }.size < battleFormat.battleType.slotsPerActor) {
|
||||
if (actor.pokemonList.filter { it.health > 0 }.size < battleFormat.battleType.slotsPerActor) {
|
||||
errors.participantErrors[actor] += BattleStartError.insufficientPokemon(
|
||||
actorEntity = player,
|
||||
requiredCount = battleFormat.battleType.slotsPerActor,
|
||||
hadCount = actor.battlePokemonProvider.getKnownPokemon().filter { it.health > 0 }.size
|
||||
hadCount = actor.pokemonList.filter { it.health > 0 }.size
|
||||
)
|
||||
}
|
||||
|
||||
if (actor.battlePokemonProvider.getKnownPokemon().any { it.entity?.isBusy == true }) {
|
||||
if (actor.pokemonList.any { it.entity?.isBusy == true }) {
|
||||
errors.participantErrors[actor] += BattleStartError.targetIsBusy(player.displayName ?: player.name)
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
if (BattleRegistry.getBattleByParticipatingPlayer(player) != null) {
|
||||
errors.participantErrors[actor] += BattleStartError.alreadyInBattle(player)
|
||||
}
|
||||
@@ -159,21 +171,18 @@ object BattleBuilder {
|
||||
}
|
||||
|
||||
for ((player, actor) in players.zip(playerActors)) {
|
||||
/*
|
||||
if (actor.battlePokemonProvider.getKnownPokemon().size < battleFormat.battleType.slotsPerActor) {
|
||||
if (actor.pokemonList.size < battleFormat.battleType.slotsPerActor) {
|
||||
errors.participantErrors[actor] += BattleStartError.insufficientPokemon(
|
||||
actorEntity = player,
|
||||
requiredCount = battleFormat.battleType.slotsPerActor,
|
||||
hadCount = actor.battlePokemonProvider.getKnownPokemon().size
|
||||
hadCount = actor.pokemonList.size
|
||||
)
|
||||
}
|
||||
|
||||
if (actor.battlePokemonProvider.getKnownPokemon().any { it.entity?.isBusy == true }) {
|
||||
if (actor.pokemonList.any { it.entity?.isBusy == true }) {
|
||||
errors.participantErrors[actor] += BattleStartError.targetIsBusy(player.displayName ?: player.name)
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
if (BattleRegistry.getBattleByParticipatingPlayer(player) != null) {
|
||||
errors.participantErrors[actor] += BattleStartError.alreadyInBattle(player)
|
||||
}
|
||||
@@ -243,30 +252,26 @@ object BattleBuilder {
|
||||
val wildActor = PokemonBattleActor(pokemonEntity.pokemon.uuid, BattlePokemon(pokemonEntity.pokemon), fleeDistance)
|
||||
val errors = ErroredBattleStart()
|
||||
|
||||
/*
|
||||
if (playerTeam.isNotEmpty() && playerTeam[0].health <= 0){
|
||||
errors.participantErrors[playerActor] += BattleStartError.insufficientPokemon(
|
||||
actorEntity = player,
|
||||
requiredCount = battleFormat.battleType.slotsPerActor,
|
||||
hadCount = playerActor.battlePokemonProvider.getKnownPokemon().size
|
||||
hadCount = playerActor.pokemonList.size
|
||||
)
|
||||
}
|
||||
|
||||
if (playerActor.battlePokemonProvider.getKnownPokemon().size < battleFormat.battleType.slotsPerActor) {
|
||||
if (playerActor.pokemonList.size < battleFormat.battleType.slotsPerActor) {
|
||||
errors.participantErrors[playerActor] += BattleStartError.insufficientPokemon(
|
||||
actorEntity = player,
|
||||
requiredCount = battleFormat.battleType.slotsPerActor,
|
||||
hadCount = playerActor.battlePokemonProvider.getKnownPokemon().size
|
||||
hadCount = playerActor.pokemonList.size
|
||||
)
|
||||
}
|
||||
|
||||
if (playerActor.battlePokemonProvider.getKnownPokemon().any { it.entity?.isBusy == true }) {
|
||||
if (playerActor.pokemonList.any { it.entity?.isBusy == true }) {
|
||||
errors.participantErrors[playerActor] += BattleStartError.targetIsBusy(player.displayName ?: player.name)
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
if (BattleRegistry.getBattleByParticipatingPlayer(player) != null) {
|
||||
errors.participantErrors[playerActor] += BattleStartError.alreadyInBattle(playerActor)
|
||||
}
|
||||
@@ -275,8 +280,6 @@ object BattleBuilder {
|
||||
errors.participantErrors[wildActor] += BattleStartError.alreadyInBattle(wildActor)
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
playerActor.battleTheme = pokemonEntity.getBattleTheme()
|
||||
|
||||
return if (errors.isEmpty) {
|
||||
@@ -315,16 +318,16 @@ object BattleBuilder {
|
||||
healFirst: Boolean = false,
|
||||
party: PartyStore = player.party()
|
||||
): BattleStartResult {
|
||||
/*
|
||||
val playerTeam = party.toBattleTeam(clone = cloneParties, healPokemon = healFirst, leadingPokemon = leadingPokemon)
|
||||
val playerActor = PlayerBattleActor(player.uuid, playerTeam)
|
||||
val npcParty = npcEntity.getPartyForChallenge(listOf(player))
|
||||
val errors = ErroredBattleStart()
|
||||
if (playerActor.battlePokemonProvider.getKnownPokemon().size < battleFormat.battleType.slotsPerActor) {
|
||||
|
||||
if (playerActor.pokemonList.size < battleFormat.battleType.slotsPerActor) {
|
||||
errors.participantErrors[playerActor] += BattleStartError.insufficientPokemon(
|
||||
actorEntity = player,
|
||||
requiredCount = battleFormat.battleType.slotsPerActor,
|
||||
hadCount = playerActor.battlePokemonProvider.getKnownPokemon().size
|
||||
hadCount = playerActor.pokemonList.size
|
||||
)
|
||||
}
|
||||
|
||||
@@ -337,20 +340,20 @@ object BattleBuilder {
|
||||
return errors
|
||||
}
|
||||
|
||||
val npcActor = NPCBattleActor(npcEntity, npcParty)
|
||||
val npcActor = NPCBattleActor(npcEntity, npcParty, npcEntity.skill ?: npcEntity.npc.skill)
|
||||
// if (npcEntity.battleIds.get().isPresent) {
|
||||
// errors.participantErrors[npcActor] += BattleStartError.alreadyInBattle(npcActor)
|
||||
// }
|
||||
|
||||
if (npcActor.battlePokemonProvider.getKnownPokemon().filter { it.health > 0 }.size < battleFormat.battleType.slotsPerActor) {
|
||||
if (npcActor.pokemonList.filter { it.health > 0 }.size < battleFormat.battleType.slotsPerActor) {
|
||||
errors.participantErrors[npcActor] += BattleStartError.insufficientPokemon(
|
||||
actorEntity = npcEntity,
|
||||
requiredCount = battleFormat.battleType.slotsPerActor,
|
||||
hadCount = npcActor.battlePokemonProvider.getKnownPokemon().size
|
||||
hadCount = npcActor.pokemonList.size
|
||||
)
|
||||
}
|
||||
|
||||
if (playerActor.battlePokemonProvider.getKnownPokemon().any { it.entity?.isBusy == true }) {
|
||||
if (playerActor.pokemonList.any { it.entity?.isBusy == true }) {
|
||||
errors.participantErrors[playerActor] += BattleStartError.targetIsBusy(player.displayName ?: player.name)
|
||||
}
|
||||
|
||||
@@ -367,8 +370,6 @@ object BattleBuilder {
|
||||
} else {
|
||||
errors
|
||||
}
|
||||
*/
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -397,7 +398,7 @@ interface BattleStartError {
|
||||
companion object {
|
||||
fun alreadyInBattle(player: ServerPlayer) = AlreadyInBattleError(player.uuid, player.effectiveName())
|
||||
fun alreadyInBattle(pokemonEntity: PokemonEntity) = AlreadyInBattleError(pokemonEntity.uuid, pokemonEntity.effectiveName())
|
||||
//fun alreadyInBattle(actor: BattleActor) = AlreadyInBattleError(actor.uuid, actor.getName())
|
||||
fun alreadyInBattle(actor: BattleActor) = AlreadyInBattleError(actor.uuid, actor.getName())
|
||||
fun noParty(npcEntity: NPCEntity) = NoPartyError(npcEntity)
|
||||
fun targetIsBusy(targetName: Component) = BusyError(targetName)
|
||||
fun insufficientPokemon(
|
||||
|
||||
@@ -17,11 +17,11 @@ import com.cobblemon.mod.common.api.pokemon.helditem.HeldItemProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.showdown.runner.remote.RemoteShowdownBattle
|
||||
import com.cobblemon.mod.common.battles.runner.ShowdownService
|
||||
import com.google.gson.GsonBuilder
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
object BattleRegistry {
|
||||
|
||||
@@ -29,7 +29,7 @@ object BattleRegistry {
|
||||
.disableHtmlEscaping()
|
||||
.registerTypeAdapter(ShowdownMoveset::class.java, ShowdownMovesetAdapter)
|
||||
.create()
|
||||
private val battleMap = ConcurrentHashMap<String, PokemonBattle>()
|
||||
private val battleMap = ConcurrentHashMap<UUID, PokemonBattle>()
|
||||
|
||||
fun onServerStarted() {
|
||||
battleMap.clear()
|
||||
@@ -161,23 +161,22 @@ object BattleRegistry {
|
||||
repeat(battle.format.battleType.slotsPerActor) {
|
||||
actor.activePokemon.add(ActiveBattlePokemon(actor))
|
||||
}
|
||||
val entities = actor.battlePokemonProvider.getKnownPokemon().mapNotNull { it.entity }
|
||||
val entities = actor.pokemonList.mapNotNull { it.entity }
|
||||
entities.forEach { it.battleId = battle.battleId }
|
||||
}
|
||||
|
||||
// -> Add the players and team
|
||||
for (actor in battle.actors.sortedBy { it.showdownId }) {
|
||||
//messages.add(""">player ${actor.showdownId} {"name":"${actor.uuid}","team":"${actor.battlePokemonProvider.getKnownPokemon().packTeam()}"}""")
|
||||
messages.add(""">player ${actor.showdownId} {"name":"${actor.uuid}","team":"${actor.pokemonList.packTeam()}"}""")
|
||||
}
|
||||
|
||||
// -> Set team size
|
||||
for (actor in battle.actors.sortedBy { it.showdownId }) {
|
||||
messages.add(">${actor.showdownId} team ${actor.battlePokemonProvider.getKnownPokemon().count()}")
|
||||
messages.add(">${actor.showdownId} team ${actor.pokemonList.count()}")
|
||||
}
|
||||
|
||||
// Compiles the request and sends it off
|
||||
val showdownBattle = Cobblemon.showdownServer.initializeNewBattle(battle.battleId.toString(), messages.toTypedArray())
|
||||
battle.showdownBattle = showdownBattle
|
||||
ShowdownService.service.startBattle(battle, messages.toTypedArray())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -215,32 +214,12 @@ object BattleRegistry {
|
||||
return ErroredBattleStart(mutableSetOf(BattleStartError.canceledByEvent(preBattleEvent.reason)))
|
||||
}
|
||||
|
||||
fun initializeShowdownControlledBattle(showdownBattle: RemoteShowdownBattle, playerId: UUID) {
|
||||
/*
|
||||
val battleId = showdownBattle.id
|
||||
val battle = PokemonBattle(
|
||||
BattleFormat.GEN_9_SINGLES,
|
||||
BattleSide(
|
||||
PlayerBattleActor(playerId, )
|
||||
)
|
||||
)
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
private fun createBattlePokemonFromShowdownJson(jsonObject: JsonObject): BattlePokemon {
|
||||
val pokemon = PokemonProperties.parse("")
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
fun closeBattle(battle: PokemonBattle) {
|
||||
battle.onEndHandlers.forEach { it(battle) }
|
||||
battleMap.remove(battle.battleId)
|
||||
}
|
||||
|
||||
fun getBattle(id: String) : PokemonBattle? {
|
||||
fun getBattle(id: UUID) : PokemonBattle? {
|
||||
return battleMap[id]
|
||||
}
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@ data class SwitchActionResponse(var newPokemonId: UUID) : ShowdownActionResponse
|
||||
}
|
||||
|
||||
override fun isValid(activeBattlePokemon: ActiveBattlePokemon, showdownMoveSet: ShowdownMoveset?, forceSwitch: Boolean): Boolean {
|
||||
val pokemon = activeBattlePokemon.actor.battlePokemonProvider.getKnownPokemon().find { it.uuid == newPokemonId }
|
||||
val pokemon = activeBattlePokemon.actor.pokemonList.find { it.uuid == newPokemonId }
|
||||
return when {
|
||||
pokemon == null -> false // No such Pokémon
|
||||
(!activeBattlePokemon.actor.request?.side?.pokemon?.any{ it.uuid == activeBattlePokemon.battlePokemon?.uuid && it.reviving }!! && pokemon.health <= 0) -> false // Checks if the active Pokémon is reviving, if so ignore this check. If not, return false if dead
|
||||
@@ -223,7 +223,7 @@ data class SwitchActionResponse(var newPokemonId: UUID) : ShowdownActionResponse
|
||||
}
|
||||
|
||||
override fun toShowdownString(activeBattlePokemon: ActiveBattlePokemon, showdownMoveSet: ShowdownMoveset?): String {
|
||||
return "switch ${activeBattlePokemon.actor.battlePokemonProvider.getKnownPokemon().indexOfFirst { it.uuid == newPokemonId } + 1}"
|
||||
return "switch ${activeBattlePokemon.actor.pokemonList.indexOfFirst { it.uuid == newPokemonId } + 1}"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,11 +19,11 @@ import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.battles.interpreter.ContextManager
|
||||
import com.cobblemon.mod.common.battles.interpreter.instructions.*
|
||||
import com.cobblemon.mod.common.battles.pokemon.AbstractBattlePokemon
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.runOnServer
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import java.util.UUID
|
||||
import kotlin.collections.Iterator
|
||||
import kotlin.collections.filter
|
||||
import kotlin.collections.forEach
|
||||
@@ -38,7 +38,7 @@ import kotlin.collections.toTypedArray
|
||||
@Suppress("KotlinPlaceholderCountMatchesArgumentCount", "UNUSED_PARAMETER")
|
||||
object ShowdownInterpreter {
|
||||
// Stores a reference to the previous ability, activate, or move message in a battle so a minor action can refer back to it (Battle UUID : BattleMessage)
|
||||
val lastCauser = mutableMapOf<String, BattleMessage>()
|
||||
val lastCauser = mutableMapOf<UUID, BattleMessage>()
|
||||
|
||||
private val updateInstructionParser = mutableMapOf<String, (PokemonBattle, InstructionSet, BattleMessage, Iterator<BattleMessage>) -> InterpreterInstruction>()
|
||||
private val splitInstructionParser = mutableMapOf<String, (PokemonBattle, BattleActor, InstructionSet, BattleMessage, BattleMessage, Iterator<BattleMessage>) -> InterpreterInstruction>()
|
||||
@@ -218,7 +218,7 @@ object ShowdownInterpreter {
|
||||
|
||||
|
||||
|
||||
fun interpretMessage(battleId: String, message: String) {
|
||||
fun interpretMessage(battleId: UUID, message: String) {
|
||||
// Check key map and use function if matching
|
||||
if (message.startsWith("{\"winner\":\"")) {
|
||||
// The post-win message is something we don't care about just yet. It's basically a summary of what happened in the battle.
|
||||
@@ -290,13 +290,13 @@ object ShowdownInterpreter {
|
||||
}
|
||||
}
|
||||
|
||||
fun broadcastOptionalAbility(battle: PokemonBattle, effect: Effect?, pokemon: AbstractBattlePokemon) {
|
||||
fun broadcastOptionalAbility(battle: PokemonBattle, effect: Effect?, pokemon: BattlePokemon) {
|
||||
if (effect == null) return
|
||||
broadcastAbility(battle, effect, pokemon)
|
||||
}
|
||||
|
||||
// Broadcasts a generic lang to notify players of ability activations (effects are broadcasted separately)
|
||||
fun broadcastAbility(battle: PokemonBattle, effect: Effect, pokemon: AbstractBattlePokemon) {
|
||||
fun broadcastAbility(battle: PokemonBattle, effect: Effect, pokemon: BattlePokemon) {
|
||||
if (effect.type != Effect.Type.ABILITY) return
|
||||
battle.dispatchWaiting(0.5F) {
|
||||
val lang = battleLang("ability.generic", pokemon.getName(), effect.typelessData).yellow()
|
||||
|
||||
@@ -8,30 +8,28 @@
|
||||
|
||||
package com.cobblemon.mod.common.battles
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.showdown.runner.ShowdownBattleServer
|
||||
import java.util.LinkedList
|
||||
import java.util.Queue
|
||||
import com.cobblemon.mod.common.battles.runner.ShowdownService
|
||||
import java.util.*
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
||||
class ShowdownThread : Thread("Cobblemon Showdown") {
|
||||
|
||||
private val latch = CountDownLatch(1)
|
||||
|
||||
private val whenReady : Queue<(ShowdownBattleServer) -> Unit> = LinkedList()
|
||||
private val whenReady : Queue<(ShowdownService) -> Unit> = LinkedList()
|
||||
|
||||
fun launch() {
|
||||
this.start()
|
||||
this.latch.await()
|
||||
for (action in whenReady) {
|
||||
action(Cobblemon.showdownServer)
|
||||
action(ShowdownService.service)
|
||||
}
|
||||
}
|
||||
|
||||
fun queue(action: (ShowdownBattleServer) -> Unit) {
|
||||
fun queue(action: (ShowdownService) -> Unit) {
|
||||
if (this.latch.count == 0L) {
|
||||
action(Cobblemon.showdownServer)
|
||||
action(ShowdownService.service)
|
||||
} else {
|
||||
this.whenReady.add(action)
|
||||
}
|
||||
@@ -39,7 +37,7 @@ class ShowdownThread : Thread("Cobblemon Showdown") {
|
||||
|
||||
override fun run() {
|
||||
LOGGER.info("Starting showdown service...")
|
||||
Cobblemon.showdownServer.connect()
|
||||
ShowdownService.service.openConnection()
|
||||
LOGGER.info("Showdown has been started!")
|
||||
this.latch.countDown()
|
||||
}
|
||||
|
||||
+10
-8
@@ -8,19 +8,21 @@
|
||||
|
||||
package com.cobblemon.mod.common.battles.actor
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.AIBattleActor
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.StaticBattlePokemonProvider
|
||||
import com.cobblemon.mod.common.api.battles.model.ai.BattleAI
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.battles.ai.RandomBattleAI
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
import java.util.UUID
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
import net.minecraft.network.chat.Component
|
||||
|
||||
open class MultiPokemonBattleActor(
|
||||
uuid: UUID = UUID.randomUUID(),
|
||||
pokemonList: List<BattlePokemon>
|
||||
) : BattleActor(uuid, StaticBattlePokemonProvider(pokemonList)) {
|
||||
class MultiPokemonBattleActor(
|
||||
pokemonList: List<BattlePokemon>,
|
||||
artificialDecider: BattleAI = RandomBattleAI(),
|
||||
uuid: UUID = UUID.randomUUID()
|
||||
) : AIBattleActor(uuid, pokemonList, artificialDecider) {
|
||||
override fun getName(): MutableComponent = "Wild Pokémon".text() // TODO probably remove by making it nullable
|
||||
override fun nameOwned(name: String): MutableComponent = Component.literal(name)
|
||||
override val type = ActorType.WILD
|
||||
|
||||
@@ -13,25 +13,24 @@ import com.cobblemon.mod.common.CobblemonNetwork
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.EntityBackedBattleActor
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.StaticBattlePokemonProvider
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.api.pokemon.experience.BattleExperienceSource
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.battles.pokemon.AbstractBattlePokemon
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleMusicPacket
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.getPlayer
|
||||
import java.util.UUID
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.sounds.SoundEvent
|
||||
import net.minecraft.sounds.SoundEvents
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import java.util.UUID
|
||||
|
||||
class PlayerBattleActor(
|
||||
uuid: UUID,
|
||||
pokemonList: List<AbstractBattlePokemon>,
|
||||
) : BattleActor(uuid, StaticBattlePokemonProvider(pokemonList.toMutableList())), EntityBackedBattleActor<ServerPlayer> {
|
||||
pokemonList: List<BattlePokemon>,
|
||||
) : BattleActor(uuid, pokemonList.toMutableList()), EntityBackedBattleActor<ServerPlayer> {
|
||||
|
||||
override val initialPos: Vec3?
|
||||
override val entity: ServerPlayer?
|
||||
|
||||
+10
-6
@@ -8,24 +8,28 @@
|
||||
|
||||
package com.cobblemon.mod.common.battles.actor
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.AIBattleActor
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.EntityBackedBattleActor
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.FleeableBattleActor
|
||||
import com.cobblemon.mod.common.api.battles.model.ai.BattleAI
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.battles.ai.RandomBattleAI
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleEndPacket
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import java.util.UUID
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class PokemonBattleActor(
|
||||
uuid: UUID,
|
||||
val pokemon: BattlePokemon,
|
||||
override val fleeDistance: Float,
|
||||
) : MultiPokemonBattleActor(uuid, listOf(pokemon)), EntityBackedBattleActor<PokemonEntity>, FleeableBattleActor {
|
||||
artificialDecider: BattleAI = RandomBattleAI()
|
||||
) : AIBattleActor(uuid, listOf(pokemon), artificialDecider), EntityBackedBattleActor<PokemonEntity>, FleeableBattleActor {
|
||||
|
||||
override val initialPos: Vec3?
|
||||
init {
|
||||
@@ -52,7 +56,7 @@ class PokemonBattleActor(
|
||||
if (packet is BattleEndPacket) {
|
||||
// Do some shit
|
||||
val entity = entity ?: return
|
||||
entity.battleId = ""
|
||||
entity.battleId = null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
|
||||
package com.cobblemon.mod.common.battles.actor
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.*
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.AIBattleActor
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
|
||||
import com.cobblemon.mod.common.api.battles.model.ai.BattleAI
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
@@ -19,7 +21,8 @@ class TrainerBattleActor(
|
||||
val trainerName: String,
|
||||
uuid: UUID,
|
||||
pokemonList: List<BattlePokemon>,
|
||||
) : BattleActor(uuid, StaticBattlePokemonProvider(pokemonList)) {
|
||||
artificialDecider: BattleAI
|
||||
) : AIBattleActor(uuid, pokemonList, artificialDecider) {
|
||||
override fun getName() = trainerName.asTranslated()
|
||||
override fun nameOwned(name: String): MutableComponent = battleLang("owned_pokemon", this.getName(), name)
|
||||
override val type = ActorType.NPC
|
||||
|
||||
@@ -8,13 +8,21 @@
|
||||
|
||||
package com.cobblemon.mod.common.battles.ai
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.model.ai.BattleAI
|
||||
import com.cobblemon.mod.common.battles.ActiveBattlePokemon
|
||||
import com.cobblemon.mod.common.battles.DefaultActionResponse
|
||||
import com.cobblemon.mod.common.battles.MoveActionResponse
|
||||
import com.cobblemon.mod.common.battles.PassActionResponse
|
||||
import com.cobblemon.mod.common.battles.ShowdownActionResponse
|
||||
import com.cobblemon.mod.common.battles.ShowdownMoveset
|
||||
import com.cobblemon.mod.common.battles.SwitchActionResponse
|
||||
|
||||
/**
|
||||
* AI that randomly chooses a move from its moveset at a random target.
|
||||
*
|
||||
* @since January 16th, 2022
|
||||
* @author Deltric, Hiroku
|
||||
*/
|
||||
/*
|
||||
class RandomBattleAI : BattleAI {
|
||||
override fun choose(
|
||||
activeBattlePokemon: ActiveBattlePokemon,
|
||||
@@ -22,7 +30,7 @@ class RandomBattleAI : BattleAI {
|
||||
forceSwitch: Boolean
|
||||
): ShowdownActionResponse {
|
||||
if (forceSwitch || activeBattlePokemon.isGone()) {
|
||||
val switchTo = activeBattlePokemon.actor.battlePokemonProvider.getKnownPokemon().filter { it.canBeSentOut() }.randomOrNull()
|
||||
val switchTo = activeBattlePokemon.actor.pokemonList.filter { it.canBeSentOut() }.randomOrNull()
|
||||
?: return DefaultActionResponse() //throw IllegalStateException("Need to switch but no Pokémon to switch to")
|
||||
switchTo.willBeSwitchedIn = true
|
||||
return SwitchActionResponse(switchTo.uuid)
|
||||
@@ -46,6 +54,4 @@ class RandomBattleAI : BattleAI {
|
||||
MoveActionResponse(move.id, (chosenTarget as ActiveBattlePokemon).getPNX())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
@@ -10,31 +10,32 @@ package com.cobblemon.mod.common.battles.ai
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonItems
|
||||
import com.cobblemon.mod.common.api.abilities.Abilities
|
||||
import com.cobblemon.mod.common.api.abilities.AbilityPool
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.battles.model.ai.BattleAI
|
||||
import com.cobblemon.mod.common.api.data.ShowdownIdentifiable
|
||||
import com.cobblemon.mod.common.api.moves.Move
|
||||
import com.cobblemon.mod.common.api.moves.MoveTemplate
|
||||
import com.cobblemon.mod.common.api.moves.Moves
|
||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategories
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.api.pokemon.*
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stat
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Status
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.cobblemon.mod.common.battles.ActiveBattlePokemon
|
||||
import com.cobblemon.mod.common.battles.DefaultActionResponse
|
||||
import com.cobblemon.mod.common.battles.InBattleMove
|
||||
import com.cobblemon.mod.common.battles.MoveActionResponse
|
||||
import com.cobblemon.mod.common.battles.PassActionResponse
|
||||
import com.cobblemon.mod.common.battles.ShowdownActionRequest
|
||||
import com.cobblemon.mod.common.battles.ShowdownActionResponse
|
||||
import com.cobblemon.mod.common.battles.ShowdownMoveset
|
||||
import com.cobblemon.mod.common.battles.SwitchActionResponse
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.battles.*
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import java.util.UUID
|
||||
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.PersistentStatusContainer
|
||||
import com.cobblemon.mod.common.util.party
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import kotlin.random.Random
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* AI that tries to choose the best move for the given situations. Based off of the Pokemon Trainer Tournament Simulator Github
|
||||
@@ -350,7 +351,7 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
forceSwitch: Boolean
|
||||
): ShowdownActionResponse {
|
||||
if (forceSwitch || activeBattlePokemon.isGone()) {
|
||||
val switchTo = activeBattlePokemon.actor.battlePokemonProvider.getKnownPokemon().filter { it.canBeSentOut() }.randomOrNull()
|
||||
val switchTo = activeBattlePokemon.actor.pokemonList.filter { it.canBeSentOut() }.randomOrNull()
|
||||
?: return DefaultActionResponse() //throw IllegalStateException("Need to switch but no Pokémon to switch to")
|
||||
switchTo.willBeSwitchedIn = true
|
||||
return SwitchActionResponse(switchTo.uuid)
|
||||
@@ -628,19 +629,14 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
|
||||
if (forceSwitch || activeBattlePokemon.isGone()) {
|
||||
if ((forceSwitch && battle.turn == 1) || (activeBattlePokemon.isGone() && battle.turn == 1)) {
|
||||
val switchTo = activeBattlePokemon.actor.battlePokemonProvider.getKnownPokemon()
|
||||
.filterIsInstance<BattlePokemon>()
|
||||
.filter { it.canBeSentOut() }
|
||||
.randomOrNull()
|
||||
val switchTo = activeBattlePokemon.actor.pokemonList.filter { it.canBeSentOut() }.randomOrNull()
|
||||
?: return DefaultActionResponse() //throw IllegalStateException("Need to switch but no Pokémon to switch to")
|
||||
switchTo.willBeSwitchedIn = true
|
||||
return SwitchActionResponse(switchTo.uuid)
|
||||
}
|
||||
else if ((forceSwitch && battle.turn > 1) || (activeBattlePokemon.isGone() && battle.turn > 1)) {
|
||||
|
||||
val availableSwitches = activeBattlePokemon.actor.battlePokemonProvider.getKnownPokemon()
|
||||
.filterIsInstance<BattlePokemon>()
|
||||
.filter { (it.health > 0) && (it.uuid != (activeBattlePokemon.battlePokemon?.uuid ?: true)) } //it.uuid != mon.pokemon!!.uuid && it.health > 0 }
|
||||
val availableSwitches = activeBattlePokemon.actor.pokemonList.filter { (it.health > 0) && (it.uuid != (activeBattlePokemon.battlePokemon?.uuid ?: true)) } //it.uuid != mon.pokemon!!.uuid && it.health > 0 }
|
||||
|
||||
// this gets null error after NPC faints
|
||||
val bestEstimation = availableSwitches.maxOfOrNull { estimatePartyMatchup(request, battle, it.effectedPokemon) }
|
||||
@@ -655,7 +651,7 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
|
||||
//return SwitchActionResponse(switchTo.uuid)
|
||||
|
||||
/*val availableSwitches = p2Actor.battlePokemonProvider.getKnownPokemon().filter { it.health > 0 } //it.uuid != mon.pokemon!!.uuid && it.health > 0 }
|
||||
/*val availableSwitches = p2Actor.pokemonList.filter { it.health > 0 } //it.uuid != mon.pokemon!!.uuid && it.health > 0 }
|
||||
val bestEstimation = availableSwitches.maxOfOrNull { estimateMatchup(request, battle, it.effectedPokemon) }
|
||||
*//*availableSwitches.forEach {
|
||||
estimateMatchup(request, battle, it.effectedPokemon)
|
||||
@@ -778,10 +774,8 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
|
||||
// switch out based on current matchup on the field
|
||||
if (checkSwitchOutSkill(skill) && shouldSwitchOut(request, battle, activeBattlePokemon, moveset)) {
|
||||
val availableSwitches = p2Actor.battlePokemonProvider.getKnownPokemon()
|
||||
.filter { it.uuid != mon.pokemon!!.uuid && it.health > 0 }
|
||||
.filterIsInstance<BattlePokemon>()
|
||||
val availablePlayerSwitches = p1Actor.battlePokemonProvider.getKnownPokemon().filter { it.uuid != opponent.pokemon!!.uuid && it.health > 0 }
|
||||
val availableSwitches = p2Actor.pokemonList.filter { it.uuid != mon.pokemon!!.uuid && it.health > 0 }
|
||||
val availablePlayerSwitches = p1Actor.pokemonList.filter { it.uuid != opponent.pokemon!!.uuid && it.health > 0 }
|
||||
|
||||
// todo try to detect a player switch-in based on if they do that a lot
|
||||
// todo if player is in bad matchup against current AI pokemon, and they have switched out before, then they have a chance of switching to a favorable matchup
|
||||
@@ -791,7 +785,7 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
/*availableSwitches.forEach {
|
||||
estimateMatchup(request, battle, it.effectedPokemon)
|
||||
}*/
|
||||
val bestEstimation = if ( 1 == 1 /* todo if player is in bad matchup and switches out a lot and has a better matchup in revealed party */) {
|
||||
val bestEstimation = if (1 == 1 /* todo if player is in bad matchup and switches out a lot and has a better matchup in revealed party */) {
|
||||
// todo make it so that bestEstimation is actually in comparison to that potential pokemon instead and be sure to switch to that instead
|
||||
|
||||
availableSwitches.maxOfOrNull { estimateMatchup(activeBattlePokemon, request, battle, it.effectedPokemon) }
|
||||
@@ -856,12 +850,10 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
|
||||
// Deal with non-weather related field changing effects
|
||||
for (move in moveset.moves.filter { !it.disabled }) {
|
||||
val availableSwitches = p2Actor.battlePokemonProvider.getKnownPokemon()
|
||||
.filter { it.uuid != mon.pokemon!!.uuid && it.health > 0 }
|
||||
.filterIsInstance<BattlePokemon>()
|
||||
val availableSwitches = p2Actor.pokemonList.filter { it.uuid != mon.pokemon!!.uuid && it.health > 0 }
|
||||
|
||||
// Tailwind
|
||||
if (move.pp > 0 && move.id == "tailwind" && move.id != npcSideTailwindCondition && p2Actor.battlePokemonProvider.getKnownPokemon().filter { it.uuid != mon.pokemon!!.uuid && it.health > 0 }.size > 2) {
|
||||
if (move.pp > 0 && move.id == "tailwind" && move.id != npcSideTailwindCondition && p2Actor.pokemonList.filter { it.uuid != mon.pokemon!!.uuid && it.health > 0 }.size > 2) {
|
||||
return chooseMove(move, activeBattlePokemon)
|
||||
}
|
||||
|
||||
@@ -882,7 +874,7 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
// Light Screen
|
||||
if (move.pp > 0 && move.id == "lightscreen" && move.id != npcSideScreenCondition
|
||||
&& getBaseStats(opponent.pokemon!!, "spa") > getBaseStats(opponent.pokemon!!, "atk")
|
||||
&& p2Actor.battlePokemonProvider.getKnownPokemon().filter { it.uuid != mon.pokemon!!.uuid && it.health > 0 }.size > 1) {
|
||||
&& p2Actor.pokemonList.filter { it.uuid != mon.pokemon!!.uuid && it.health > 0 }.size > 1) {
|
||||
return chooseMove(move, activeBattlePokemon)
|
||||
}
|
||||
|
||||
@@ -890,7 +882,7 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
// Reflect
|
||||
if (move.pp > 0 && move.id == "reflect" && move.id != npcSideScreenCondition
|
||||
&& getBaseStats(opponent.pokemon!!, "atk") > getBaseStats(opponent.pokemon!!, "spa")
|
||||
&& p2Actor.battlePokemonProvider.getKnownPokemon().filter { it.uuid != mon.pokemon!!.uuid && it.health > 0 }.size > 1) {
|
||||
&& p2Actor.pokemonList.filter { it.uuid != mon.pokemon!!.uuid && it.health > 0 }.size > 1) {
|
||||
return chooseMove(move, activeBattlePokemon)
|
||||
}
|
||||
}
|
||||
@@ -1283,9 +1275,7 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
|
||||
// switch out
|
||||
if (shouldSwitchOut(request, battle, activeBattlePokemon, moveset)) {
|
||||
val availableSwitches = p1Actor.battlePokemonProvider.getKnownPokemon()
|
||||
.filter { it.uuid != mon.pokemon!!.uuid && it.health > 0 }
|
||||
.filterIsInstance<BattlePokemon>()
|
||||
val availableSwitches = p1Actor.pokemonList.filter { it.uuid != mon.pokemon!!.uuid && it.health > 0 }
|
||||
val bestEstimation = availableSwitches.maxOfOrNull { estimateMatchup(activeBattlePokemon, request, battle, it.effectedPokemon) }
|
||||
/*availableSwitches.forEach {
|
||||
estimateMatchup(request, battle, it.effectedPokemon)
|
||||
@@ -1487,9 +1477,7 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
//val requestActor = request.side?.
|
||||
//val availableSwitches = request.side?.pokemon?.filter { !it.active && getHpFraction(it.condition) != 0.0 }
|
||||
//val playerAvailableSwitches =
|
||||
val availableSwitches = p2Actor.battlePokemonProvider.getKnownPokemon()
|
||||
.filter { it.uuid != mon.activePokemon.pokemon!!.uuid && it.health > 0 }
|
||||
.filterIsInstance<BattlePokemon>()
|
||||
val availableSwitches = p2Actor.pokemonList.filter { it.uuid != mon.activePokemon.pokemon!!.uuid && it.health > 0 }
|
||||
|
||||
val currentNPCAbility = request.side?.pokemon!!.first().ability
|
||||
|
||||
@@ -1796,7 +1784,7 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
|
||||
val p1Boosts = battle.side1.activePokemon.firstOrNull()?.battlePokemon?.statChanges
|
||||
val playerSide1 = battle.side1.actors.first()
|
||||
val numPlayerPokemon = playerSide1.battlePokemonProvider.getKnownPokemon().count()
|
||||
val numPlayerPokemon = playerSide1.pokemonList.count()
|
||||
|
||||
|
||||
/*val lastMajorBattleMessage = if (battle.majorBattleActions.entries.isNotEmpty()) battle.majorBattleActions?.entries?.last()?.value?.rawMessage else ""
|
||||
@@ -1841,9 +1829,9 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
val pokemon2 = battle.side2.activePokemon.firstOrNull()?.battlePokemon?.effectedPokemon
|
||||
val p2Boosts = battle.side2.activePokemon.firstOrNull()?.battlePokemon?.statChanges
|
||||
val playerSide2 = battle.side2.actors.first()
|
||||
val numNPCPokemon = playerSide2.battlePokemonProvider.getKnownPokemon().count()
|
||||
val numNPCPokemon = playerSide2.pokemonList.count()
|
||||
|
||||
//val nextAvailablePokemon = playerSide2.battlePokemonProvider.getKnownPokemon().filter { it.health != 0 }.first().effectedPokemon.uuid
|
||||
//val nextAvailablePokemon = playerSide2.pokemonList.filter { it.health != 0 }.first().effectedPokemon.uuid
|
||||
// todo make nice function for knowing what is the best switchout
|
||||
|
||||
// convert p2Boosts to a regular Map rather than a MutableMap
|
||||
@@ -1870,7 +1858,7 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
//mon.stats = pokemon.stats
|
||||
p1.activePokemon.moves = pokemon1.moveSet.getMoves()
|
||||
p1.nRemainingMons = battle.side1.actors.sumOf { actor ->
|
||||
actor.battlePokemonProvider.getKnownPokemon().count { pokemon ->
|
||||
actor.pokemonList.count { pokemon ->
|
||||
pokemon.health != 0
|
||||
}
|
||||
}
|
||||
@@ -1883,7 +1871,7 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
p1.party[partyPokemonIndex] = p1.activePokemon
|
||||
}
|
||||
|
||||
//p1.availableSwitches = playerSide1.battlePokemonProvider.getKnownPokemon().filter { it.uuid != p1.pokemon.uuid && it.health > 0 }
|
||||
//p1.availableSwitches = playerSide1.pokemonList.filter { it.uuid != p1.pokemon.uuid && it.health > 0 }
|
||||
//p1.sideConditions = pokemon.sideConditions //todo what the hell does this mean
|
||||
|
||||
p2.activePokemon = getActiveTrackerPokemon(p2, pokemon2?.uuid)
|
||||
@@ -1901,7 +1889,7 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
//mon.stats = pokemon.stats
|
||||
p2.activePokemon.moves = pokemon2.moveSet.getMoves()
|
||||
p2.nRemainingMons = battle.side2.actors.sumOf { actor ->
|
||||
actor.battlePokemonProvider.getKnownPokemon().count { pokemon ->
|
||||
actor.pokemonList.count { pokemon ->
|
||||
pokemon.health != 0
|
||||
}
|
||||
}
|
||||
|
||||
+4
-5
@@ -11,7 +11,9 @@ package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.moves.Moves
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.ActionEffectInstruction
|
||||
@@ -21,8 +23,8 @@ import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.UntilDispatch
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.network.chat.Component
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import net.minecraft.network.chat.Component
|
||||
|
||||
/**
|
||||
* Format: |-activate|POKEMON|EFFECT
|
||||
@@ -57,7 +59,7 @@ class ActivateInstruction(val instructionSet: InstructionSet, val message: Battl
|
||||
val actionEffect = status?.getActionEffect() ?: return@dispatch GO
|
||||
val providers = mutableListOf<Any>(battle)
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatch GO
|
||||
//pokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
|
||||
pokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
|
||||
val context = ActionEffectContext(
|
||||
actionEffect = actionEffect,
|
||||
runtime = runtime,
|
||||
@@ -79,7 +81,6 @@ class ActivateInstruction(val instructionSet: InstructionSet, val message: Battl
|
||||
val pokemonName = pokemon.getName()
|
||||
val sourceName = message.battlePokemonFromOptional(battle)?.getName() ?: Component.literal("UNKNOWN")
|
||||
|
||||
/*
|
||||
if (effect.id == "sketch" && pokemon.effectedPokemon.moveSet.any { it.name == "sketch" } && extraEffect is String) {
|
||||
// Apply Sketch to the pokemon's current moveset if it was successfully used in battle
|
||||
val moveTemplate = Moves.getByName(extraEffect.replace(" ", ""))
|
||||
@@ -91,8 +92,6 @@ class ActivateInstruction(val instructionSet: InstructionSet, val message: Battl
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
val lang = when (effect.id) {
|
||||
// Includes a 3rd argument being the magnitude level as a number
|
||||
"magnitude" -> battleLang("activate.magnitude", message.argumentAt(2)?.toIntOrNull() ?: 1)
|
||||
|
||||
+4
-2
@@ -15,6 +15,7 @@ import com.cobblemon.mod.common.api.battles.interpreter.InvalidInstructionExcept
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
|
||||
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.ActionEffectInstruction
|
||||
@@ -51,11 +52,12 @@ class BoostInstruction(battle: PokemonBattle, val message: BattleMessage, val is
|
||||
battle.dispatch {
|
||||
val actionEffect = if (isBoost) BOOST_EFFECT else UNBOOST_EFFECT
|
||||
val providers = mutableListOf<Any>(battle)
|
||||
// pokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
|
||||
pokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
|
||||
val context = ActionEffectContext(
|
||||
actionEffect = actionEffect,
|
||||
runtime = runtime,
|
||||
providers = providers
|
||||
providers = providers,
|
||||
level = battle.players.firstOrNull()?.level()
|
||||
)
|
||||
this.future = actionEffect.run(context)
|
||||
holds = context.holds // Reference so future things can check on this action effect's holds
|
||||
|
||||
+4
-2
@@ -12,6 +12,7 @@ import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
@@ -46,12 +47,13 @@ class CantInstruction(val message: BattleMessage): ActionEffectInstruction {
|
||||
val status = Statuses.getStatus(effectID)
|
||||
val actionEffect = status?.getActionEffect() ?: return@dispatch GO
|
||||
val providers = mutableListOf<Any>(battle)
|
||||
// pokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
|
||||
pokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
|
||||
|
||||
val context = ActionEffectContext(
|
||||
actionEffect = actionEffect,
|
||||
runtime = runtime,
|
||||
providers = providers
|
||||
providers = providers,
|
||||
level = battle.players.firstOrNull()?.level()
|
||||
)
|
||||
this.future = actionEffect.run(context)
|
||||
holds = context.holds // Reference so future things can check on this action effect's holds
|
||||
|
||||
+3
-5
@@ -11,10 +11,11 @@ package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.text.yellow
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.pokemon.evolution.progress.LastBattleCriticalHitsEvolutionProgress
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
|
||||
/**
|
||||
* Format: |-crit|POKEMON
|
||||
@@ -38,13 +39,10 @@ class CritInstruction(val message: BattleMessage, val instructionSet: Instructio
|
||||
} else {
|
||||
battle.broadcastChatMessage(battleLang("crit").yellow())
|
||||
}
|
||||
/*
|
||||
if (LastBattleCriticalHitsEvolutionProgress.supports(battlePokemon.effectedPokemon)) {
|
||||
val progress = battlePokemon.effectedPokemon.evolutionProxy.current().progressFirstOrCreate({ it is LastBattleCriticalHitsEvolutionProgress }) { LastBattleCriticalHitsEvolutionProgress() }
|
||||
progress.updateProgress(LastBattleCriticalHitsEvolutionProgress.Progress(progress.currentProgress().amount + 1))
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ class CureStatusInstruction(val message: BattleMessage): InterpreterInstruction
|
||||
|
||||
battle.dispatchWaiting {
|
||||
val pokemonName = pokemon.getName()
|
||||
// pokemon.effectedPokemon.status = null
|
||||
pokemon.effectedPokemon.status = null
|
||||
pokemon.sendUpdate()
|
||||
|
||||
if (maybeActivePokemon != null) {
|
||||
|
||||
+8
-14
@@ -25,14 +25,16 @@ import com.cobblemon.mod.common.battles.dispatch.UntilDispatch
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.net.messages.client.animation.PlayPosableAnimationPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleHealthChangePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
|
||||
import com.cobblemon.mod.common.pokemon.evolution.progress.DamageTakenEvolutionProgress
|
||||
import com.cobblemon.mod.common.pokemon.evolution.progress.RecoilEvolutionProgress
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.PoisonStatus
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import net.minecraft.network.chat.Component
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import net.minecraft.network.chat.Component
|
||||
|
||||
/**
|
||||
* Format: |-damage|POKEMON|HP STATUS
|
||||
@@ -57,9 +59,7 @@ class DamageInstruction(
|
||||
val recoiling = privateMessage.optionalArgument("from")?.equals("recoil", true) == true
|
||||
val lastCauser = instructionSet.getMostRecentCauser(comparedTo = this)
|
||||
if (recoiling) {
|
||||
if (battlePokemon is BattlePokemon) {
|
||||
doRecoilEvoChecks(battlePokemon)
|
||||
}
|
||||
doRecoilEvoChecks(battlePokemon)
|
||||
if (lastCauser is MoveInstruction) {
|
||||
battle.dispatch {
|
||||
//Is the recoil hold currently used anywhere?
|
||||
@@ -98,12 +98,9 @@ class DamageInstruction(
|
||||
var status = effect?.id?.let { Statuses.getStatus(it) }
|
||||
battle.dispatch {
|
||||
val pokemon = privateMessage.battlePokemon(0, battle) ?: return@dispatch GO
|
||||
//FIXME: This should be tracked on the AbstractBattlePokemon
|
||||
//Showdown doesnt tell us on damage if its poison or toxic so we gotta consult the entity
|
||||
if (status is PoisonStatus) {
|
||||
if (pokemon is BattlePokemon) {
|
||||
status = pokemon.effectedPokemon.status?.status ?: status
|
||||
}
|
||||
status = pokemon.effectedPokemon.status?.status ?: status
|
||||
}
|
||||
|
||||
// Damage effects without a action effect receive the generic damage effect
|
||||
@@ -112,7 +109,7 @@ class DamageInstruction(
|
||||
} ?: return@dispatch GO
|
||||
|
||||
val providers = mutableListOf<Any>(battle)
|
||||
battlePokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
|
||||
battlePokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
|
||||
|
||||
val context = ActionEffectContext(
|
||||
actionEffect = actionEffect,
|
||||
@@ -170,7 +167,7 @@ class DamageInstruction(
|
||||
if (causedFaint) {
|
||||
newHealthRatio = 0F
|
||||
battle.dispatch {
|
||||
battlePokemon.health = 0
|
||||
battlePokemon.effectedPokemon.currentHealth = 0
|
||||
battlePokemon.sendUpdate()
|
||||
GO
|
||||
}
|
||||
@@ -180,17 +177,14 @@ class DamageInstruction(
|
||||
val difference = maxHealth - remainingHealth
|
||||
newHealthRatio = remainingHealth.toFloat() / maxHealth
|
||||
battle.dispatchToFront {
|
||||
//battlePokemon.curr = remainingHealth
|
||||
battlePokemon.effectedPokemon.currentHealth = remainingHealth
|
||||
if (difference > 0) {
|
||||
/*
|
||||
battlePokemon.effectedPokemon.let { pokemon ->
|
||||
if (DamageTakenEvolutionProgress.supports(pokemon)) {
|
||||
val progress = pokemon.evolutionProxy.current().progressFirstOrCreate({ it is DamageTakenEvolutionProgress }) { DamageTakenEvolutionProgress() }
|
||||
progress.updateProgress(DamageTakenEvolutionProgress.Progress(progress.currentProgress().amount + difference))
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
battlePokemon.sendUpdate()
|
||||
GO
|
||||
|
||||
+2
-3
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.EntityBackedBattleActor
|
||||
import com.cobblemon.mod.common.battles.dispatch.BattleDispatch
|
||||
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
@@ -38,7 +39,7 @@ class DragInstruction(val instructionSet: InstructionSet, val battleActor: Battl
|
||||
|
||||
val newHealth = privateMessage.argumentAt(2)!!.split(" ")[0]
|
||||
val remainingHealth = newHealth.split("/")[0].toInt()
|
||||
// pokemon.effectedPokemon.currentHealth = remainingHealth
|
||||
pokemon.effectedPokemon.currentHealth = remainingHealth
|
||||
|
||||
battle.broadcastChatMessage(battleLang("dragged_out", pokemon.getName()))
|
||||
activePokemon.battlePokemon?.let { oldPokemon ->
|
||||
@@ -49,7 +50,6 @@ class DragInstruction(val instructionSet: InstructionSet, val battleActor: Battl
|
||||
|
||||
val entity = if (battleActor is EntityBackedBattleActor<*>) battleActor.entity else null
|
||||
setOf(
|
||||
/*
|
||||
BattleDispatch {
|
||||
if (entity != null) {
|
||||
SwitchInstruction.createEntitySwitch(battle, battleActor, entity, pnx, activePokemon, pokemon, illusion, imposter)
|
||||
@@ -57,7 +57,6 @@ class DragInstruction(val instructionSet: InstructionSet, val battleActor: Battl
|
||||
SwitchInstruction.createNonEntitySwitch(battle, battleActor, pnx, activePokemon, pokemon, illusion)
|
||||
}
|
||||
}
|
||||
*/
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
|
||||
+3
-1
@@ -12,7 +12,9 @@ import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-enditem|POKEMON|ITEM|(from)EFFECT
|
||||
@@ -32,7 +34,7 @@ class EndItemInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
// All logic regarding broadcasting battle messages is handled in CobblemonHeldItemManager
|
||||
val battlePokemon = message.battlePokemon(0, battle) ?: return@dispatchWaiting
|
||||
val itemEffect = message.effectAt(1) ?: return@dispatchWaiting
|
||||
//battlePokemon.heldItemManager.handleEndInstruction(battlePokemon, battle, message)
|
||||
battlePokemon.heldItemManager.handleEndInstruction(battlePokemon, battle, message)
|
||||
battle.minorBattleActions[battlePokemon.uuid] = message
|
||||
battlePokemon.contextManager.remove(itemEffect.id, BattleContext.Type.ITEM)
|
||||
if (message.hasOptionalArgument("eat")) {
|
||||
|
||||
+8
-5
@@ -13,8 +13,11 @@ import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.EntityBackedBattleActor
|
||||
import com.cobblemon.mod.common.api.entity.PokemonSender
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.battles.BattleFaintedEvent
|
||||
import com.cobblemon.mod.common.api.scheduling.delayedFuture
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleFaintPacket
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
@@ -38,20 +41,20 @@ class FaintInstruction(battle: PokemonBattle, val message: BattleMessage) : Inte
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchFuture CompletableFuture.completedFuture(Unit)
|
||||
battle.sendUpdate(BattleFaintPacket(pnx))
|
||||
val actor = pokemon.actor
|
||||
//pokemon.effectedPokemon.currentHealth = 0
|
||||
pokemon.effectedPokemon.currentHealth = 0
|
||||
val preamble = if (actor is EntityBackedBattleActor<*>) {
|
||||
(actor.entity as? PokemonSender)?.let { sender -> pokemon.entity?.recallWithAnimation()}
|
||||
} else {
|
||||
null
|
||||
} ?: delayedFuture(seconds = waitTime)
|
||||
//val context = ShowdownInterpreter.getContextFromFaint(faintingPokemon, battle)
|
||||
val context = ShowdownInterpreter.getContextFromFaint(faintingPokemon, battle)
|
||||
|
||||
preamble.thenAccept {
|
||||
//faintingPokemon.effectedPokemon.currentHealth = 0
|
||||
faintingPokemon.effectedPokemon.currentHealth = 0
|
||||
faintingPokemon.sendUpdate()
|
||||
//CobblemonEvents.BATTLE_FAINTED.post(BattleFaintedEvent(battle, pokemon, context))
|
||||
CobblemonEvents.BATTLE_FAINTED.post(BattleFaintedEvent(battle, pokemon, context))
|
||||
battle.getActorAndActiveSlotFromPNX(pnx).second.battlePokemon = null
|
||||
//faintingPokemon.contextManager.add(context)
|
||||
faintingPokemon.contextManager.add(context)
|
||||
faintingPokemon.contextManager.clear(BattleContext.Type.STATUS, BattleContext.Type.VOLATILE, BattleContext.Type.BOOST, BattleContext.Type.UNBOOST)
|
||||
battle.majorBattleActions[faintingPokemon.uuid] = message
|
||||
}
|
||||
|
||||
+3
-1
@@ -10,6 +10,8 @@ package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.battles.instruction.FormeChangeEvent
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
@@ -35,7 +37,7 @@ class FormeChangeInstruction(val message: BattleMessage): InterpreterInstruction
|
||||
battle.dispatchWaiting {
|
||||
battle.minorBattleActions[battlePokemon.uuid] = message
|
||||
|
||||
//CobblemonEvents.FORME_CHANGE.post(FormeChangeEvent(battle, battlePokemon, formName))
|
||||
CobblemonEvents.FORME_CHANGE.post(FormeChangeEvent(battle, battlePokemon, formName))
|
||||
val pokemonName = battlePokemon.getName()
|
||||
val lang = when(formName) {
|
||||
"busted", "hero", "complete" -> return@dispatchWaiting
|
||||
|
||||
+7
-7
@@ -17,6 +17,9 @@ import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleHealthChangePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattlePersistentStatusPacket
|
||||
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
@@ -50,9 +53,9 @@ class HealInstruction(val actor: BattleActor, val publicMessage: BattleMessage,
|
||||
privateMessage.hasOptionalArgument("wisher") -> {
|
||||
val name = privateMessage.optionalArgument("wisher")!!
|
||||
val showdownId = name.lowercase().replace(ShowdownIdentifiable.REGEX, "")
|
||||
//val wisher = actor.battlePokemonProvider.getKnownPokemon().firstOrNull { it.effectedPokemon.showdownId() == showdownId }
|
||||
val wisher = actor.pokemonList.firstOrNull { it.effectedPokemon.showdownId() == showdownId }
|
||||
// If no Pokémon is found this is a nickname
|
||||
//battleLang("heal.wish", wisher?.getName() ?: actor.nameOwned(name))
|
||||
battleLang("heal.wish", wisher?.getName() ?: actor.nameOwned(name))
|
||||
}
|
||||
privateMessage.hasOptionalArgument("from") -> {
|
||||
when (effect!!.type) {
|
||||
@@ -73,15 +76,14 @@ class HealInstruction(val actor: BattleActor, val publicMessage: BattleMessage,
|
||||
battleLang("heal.generic", battlePokemon.getName())
|
||||
}
|
||||
}
|
||||
//battle.broadcastChatMessage(lang)
|
||||
battle.broadcastChatMessage(lang)
|
||||
}
|
||||
battle.minorBattleActions[battlePokemon.uuid] = privateMessage
|
||||
//battlePokemon.effectedPokemon.currentHealth = newHealth[0].toInt()
|
||||
battlePokemon.effectedPokemon.currentHealth = newHealth[0].toInt()
|
||||
|
||||
// This part is not always present
|
||||
val rawStatus = rawHpAndStatus.getOrNull(1) ?: return@dispatchWaiting
|
||||
val status = Statuses.getStatus(rawStatus) ?: return@dispatchWaiting
|
||||
/*
|
||||
if (status is PersistentStatus && battlePokemon.effectedPokemon.status?.status != status) {
|
||||
battlePokemon.effectedPokemon.applyStatus(status)
|
||||
activePokemon?.let { battle.sendUpdate(BattlePersistentStatusPacket(it.getPNX(), status)) }
|
||||
@@ -89,8 +91,6 @@ class HealInstruction(val actor: BattleActor, val publicMessage: BattleMessage,
|
||||
status.applyMessage.let { battle.broadcastChatMessage(it.asTranslated(battlePokemon.getName())) }
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-10
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.scheduling.afterOnServer
|
||||
@@ -15,7 +16,6 @@ import com.cobblemon.mod.common.battles.actor.PlayerBattleActor
|
||||
import com.cobblemon.mod.common.battles.dispatch.DispatchResult
|
||||
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleInitializePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleMusicPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleQueueRequestPacket
|
||||
@@ -40,12 +40,12 @@ class InitializeInstruction(val instructionSet: InstructionSet, val message: Bat
|
||||
// If a Pokémon entity is being recalled with an animation,
|
||||
// wrap up the animation and recall the Pokémon immediately.
|
||||
if (it.beamMode == 3 && battle.battlePartyStores.isEmpty()) {
|
||||
// pokemon.effectedPokemon.recall()
|
||||
pokemon.effectedPokemon.recall()
|
||||
}
|
||||
// If already on the field, initialize for the BattleInitializePacket
|
||||
else {
|
||||
// activePokemon.battlePokemon = pokemon
|
||||
// activePokemon.illusion = illusion
|
||||
activePokemon.battlePokemon = pokemon
|
||||
activePokemon.illusion = illusion
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -57,12 +57,7 @@ class InitializeInstruction(val instructionSet: InstructionSet, val message: Bat
|
||||
}
|
||||
|
||||
battle.actors.forEach { actor ->
|
||||
actor.sendUpdate(BattleSetTeamPokemonPacket(
|
||||
actor.battlePokemonProvider.getKnownPokemon()
|
||||
.filterIsInstance<BattlePokemon>()
|
||||
.map { it.effectedPokemon }
|
||||
.toList()
|
||||
))
|
||||
actor.sendUpdate(BattleSetTeamPokemonPacket(actor.pokemonList.map { it.effectedPokemon }))
|
||||
val req = actor.request ?: return@forEach
|
||||
actor.sendUpdate(BattleQueueRequestPacket(req))
|
||||
}
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ class ItemInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
battle.dispatchWaiting(1.5F) {
|
||||
val battlePokemon = message.battlePokemon(0, battle) ?: return@dispatchWaiting
|
||||
//battlePokemon.heldItemManager.handleStartInstruction(battlePokemon, battle, message)
|
||||
battlePokemon.heldItemManager.handleStartInstruction(battlePokemon, battle, message)
|
||||
battle.minorBattleActions[battlePokemon.uuid] = message
|
||||
battlePokemon.contextManager.add(ShowdownInterpreter.getContextFromAction(message, BattleContext.Type.ITEM, battle))
|
||||
}
|
||||
|
||||
+3
-1
@@ -10,6 +10,8 @@ package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.battles.instruction.MegaEvolutionEvent
|
||||
import com.cobblemon.mod.common.api.text.yellow
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
@@ -28,7 +30,7 @@ class MegaInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
battle.dispatchWaiting {
|
||||
val pokemonName = battlePokemon.getName()
|
||||
battle.broadcastChatMessage(battleLang("mega", pokemonName).yellow())
|
||||
//CobblemonEvents.MEGA_EVOLUTION.post(MegaEvolutionEvent(battle, battlePokemon))
|
||||
CobblemonEvents.MEGA_EVOLUTION.post(MegaEvolutionEvent(battle, battlePokemon))
|
||||
battle.minorBattleActions[battlePokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -54,8 +54,8 @@ class MoveInstruction(
|
||||
var targetPokemon: BattlePokemon? = null
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
//userPokemon = message.battlePokemon(0, battle)!!
|
||||
//targetPokemon = message.battlePokemon(2, battle)
|
||||
userPokemon = message.battlePokemon(0, battle)!!
|
||||
targetPokemon = message.battlePokemon(2, battle)
|
||||
val targetPokemon = targetPokemon // So smart non-null casts can happen
|
||||
|
||||
val optionalEffect = message.effect()
|
||||
@@ -90,7 +90,7 @@ class MoveInstruction(
|
||||
val providers = mutableListOf<Any>(battle)
|
||||
userPokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
|
||||
if (spreadTargetPokemon.isNotEmpty()) {
|
||||
providers.add(TargetsProvider( spreadTargetPokemon.filter { it?.effectedPokemon?.entity != null}.mapNotNull { spreadTarget -> spreadTarget?.effectedPokemon?.entity } ))
|
||||
providers.add(TargetsProvider(spreadTargetPokemon.filter { it?.effectedPokemon?.entity != null}.mapNotNull { spreadTarget -> spreadTarget?.effectedPokemon?.entity }))
|
||||
} else {
|
||||
targetPokemon?.effectedPokemon?.entity?.let { TargetsProvider(it) }?.let(providers::add)
|
||||
}
|
||||
|
||||
+2
-2
@@ -29,8 +29,8 @@ class PpUpdateInstruction( val message: BattleMessage): InterpreterInstruction {
|
||||
val moveIdAndPp = moveData.split(": ")
|
||||
val moveId = moveIdAndPp[0]
|
||||
val movePp = moveIdAndPp[1]
|
||||
// val move = pokemon.effectedPokemon.moveSet.firstOrNull { move -> move.name.equals(moveId, true) } ?: return@dispatch GO
|
||||
// move.currentPp = movePp.toInt()
|
||||
val move = pokemon.effectedPokemon.moveSet.firstOrNull { move -> move.name.equals(moveId, true) } ?: return@dispatch GO
|
||||
move.currentPp = movePp.toInt()
|
||||
}
|
||||
GO
|
||||
}
|
||||
|
||||
+4
-3
@@ -10,7 +10,11 @@ package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.text.yellow
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleReplacePokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleTransformPokemonPacket
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |replace|POKEMON|DETAILS|HP STATUS
|
||||
@@ -31,15 +35,12 @@ class ReplaceInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
val entity = pokemon.entity
|
||||
entity?.let { it.effects.mockEffect?.end(it) }
|
||||
|
||||
/*
|
||||
battle.sendSidedUpdate(
|
||||
source = actor,
|
||||
allyPacket = BattleReplacePokemonPacket(pnx, pokemon, true),
|
||||
opponentPacket = BattleReplacePokemonPacket(pnx, pokemon, false)
|
||||
)
|
||||
|
||||
*/
|
||||
|
||||
activePokemon.illusion = null
|
||||
//lang done by EndInstruction
|
||||
}
|
||||
|
||||
+2
-1
@@ -14,6 +14,7 @@ import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleHealthChangePacket
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
/**
|
||||
* Format: |-sethp|POKEMON|HP
|
||||
@@ -30,7 +31,7 @@ class SetHpInstruction(val actor: BattleActor, val publicMessage: BattleMessage,
|
||||
val flatHp = privateMessage.argumentAt(1)?.split("/")?.getOrNull(0)?.toFloatOrNull() ?: return@dispatchWaiting
|
||||
val ratioHp = publicMessage.argumentAt(1)?.split("/")?.getOrNull(0)?.toFloatOrNull()?.times(0.01F) ?: return@dispatchWaiting
|
||||
val battlePokemon = privateMessage.battlePokemon(0, battle) ?: return@dispatchWaiting
|
||||
// battlePokemon.effectedPokemon.currentHealth = flatHp.roundToInt()
|
||||
battlePokemon.effectedPokemon.currentHealth = flatHp.roundToInt()
|
||||
battle.sendSidedUpdate(actor, BattleHealthChangePacket(pnx, flatHp), BattleHealthChangePacket(pnx, ratioHp))
|
||||
// It doesn't matter which we check when silent both have it
|
||||
if (!publicMessage.hasOptionalArgument("silent")) {
|
||||
|
||||
+2
-2
@@ -26,7 +26,7 @@ import com.cobblemon.mod.common.util.asTranslated
|
||||
* @author Hiroku
|
||||
* @since October 3rd, 2022
|
||||
*/
|
||||
class StatusInstruction( val message: BattleMessage): InterpreterInstruction {
|
||||
class StatusInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val (pnx, _) = message.pnxAndUuid(0) ?: return
|
||||
@@ -39,7 +39,7 @@ class StatusInstruction( val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
battle.dispatchWaiting {
|
||||
if (status is PersistentStatus) {
|
||||
//pokemon.effectedPokemon.applyStatus(status)
|
||||
pokemon.effectedPokemon.applyStatus(status)
|
||||
battle.sendUpdate(BattlePersistentStatusPacket(pnx, status))
|
||||
pokemon.sendUpdate()
|
||||
}
|
||||
|
||||
+1
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.entity.pokemon.effects.IllusionEffect
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleSwapPokemonPacket
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.setPositionSafely
|
||||
|
||||
+11
-19
@@ -19,22 +19,21 @@ import com.cobblemon.mod.common.api.scheduling.afterOnServer
|
||||
import com.cobblemon.mod.common.battles.ActiveBattlePokemon
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.actor.PokemonBattleActor
|
||||
import com.cobblemon.mod.common.battles.dispatch.DispatchResult
|
||||
import com.cobblemon.mod.common.battles.dispatch.GO
|
||||
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.battles.dispatch.UntilDispatch
|
||||
import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
|
||||
import com.cobblemon.mod.common.battles.dispatch.*
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.entity.pokemon.effects.IllusionEffect
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleSwitchPokemonPacket
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.SendOutPokemonHandler.SEND_OUT_DURATION
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.SendOutPokemonHandler.SEND_OUT_STAGGER_BASE_DURATION
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.SendOutPokemonHandler.SEND_OUT_STAGGER_RANDOM_MAX_DURATION
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.getPlayer
|
||||
import com.cobblemon.mod.common.util.party
|
||||
import com.cobblemon.mod.common.util.swap
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import kotlin.random.Random
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
/**
|
||||
* Format: |switch|POKEMON|DETAILS|HP STATUS
|
||||
@@ -64,12 +63,11 @@ class SwitchInstruction(val instructionSet: InstructionSet, val battleActor: Bat
|
||||
val pokemonEntity = pokemon.entity
|
||||
if (pokemonEntity != null && actor !is PokemonBattleActor) { // pokemon entities starting on the field should already have battlePokemon init; see InitializeInstruction
|
||||
|
||||
//illusion?.let { IllusionEffect(it.effectedPokemon).start(pokemonEntity) }
|
||||
//broadcastSwitch(battle, actor, pokemon, illusion)
|
||||
illusion?.let { IllusionEffect(it.effectedPokemon).start(pokemonEntity) }
|
||||
broadcastSwitch(battle, actor, pokemon, illusion)
|
||||
WaitDispatch(0.5F)
|
||||
}
|
||||
else if (pokemonEntity == null && entity != null) {
|
||||
/*
|
||||
activePokemon.battlePokemon = pokemon
|
||||
activePokemon.illusion = illusion
|
||||
val targetPos = ShowdownInterpreter.getSendoutPosition(battle, activePokemon, battleActor)
|
||||
@@ -92,11 +90,8 @@ class SwitchInstruction(val instructionSet: InstructionSet, val battleActor: Bat
|
||||
WaitDispatch(0.5F) // we're already waiting 1.5 seconds. this prevents flooding from consecutive SwitchInstructions
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
GO
|
||||
|
||||
}
|
||||
|
||||
val futureSwitches = instructionSet.getSubsequentInstructions(this).filterIsInstance<SwitchInstruction>()
|
||||
@@ -125,7 +120,7 @@ class SwitchInstruction(val instructionSet: InstructionSet, val battleActor: Bat
|
||||
battle.dispatchInsert {
|
||||
val newHealth = privateMessage.argumentAt(2)!!.split(" ")[0]
|
||||
val remainingHealth = newHealth.split("/")[0].toInt()
|
||||
// pokemon.effectedPokemon.currentHealth = remainingHealth
|
||||
pokemon.effectedPokemon.currentHealth = remainingHealth
|
||||
pokemon.sendUpdate()
|
||||
|
||||
if (activePokemon.battlePokemon == pokemon) {
|
||||
@@ -144,7 +139,6 @@ class SwitchInstruction(val instructionSet: InstructionSet, val battleActor: Bat
|
||||
battle.majorBattleActions[pokemon.uuid] = publicMessage
|
||||
|
||||
setOf(
|
||||
/*
|
||||
BattleDispatch {
|
||||
if (entity != null) {
|
||||
createEntitySwitch(battle, actor, entity, pnx, activePokemon, pokemon, illusion, imposter)
|
||||
@@ -152,8 +146,6 @@ class SwitchInstruction(val instructionSet: InstructionSet, val battleActor: Bat
|
||||
createNonEntitySwitch(battle, actor, pnx, activePokemon, pokemon, illusion)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -175,7 +167,7 @@ class SwitchInstruction(val instructionSet: InstructionSet, val battleActor: Bat
|
||||
val sendOutFuture = CompletableFuture<Unit>()
|
||||
(pokemonEntity?.recallWithAnimation() ?: CompletableFuture.completedFuture(Unit)).thenApply {
|
||||
// Queue actual swap and send-in after the animation has ended
|
||||
//actor.battlePokemonProvider.getKnownPokemon().swap(actor.activePokemon.indexOf(activePokemon), actor.battlePokemonProvider.getKnownPokemon().indexOf(newPokemon))
|
||||
actor.pokemonList.swap(actor.activePokemon.indexOf(activePokemon), actor.pokemonList.indexOf(newPokemon))
|
||||
activePokemon.battlePokemon = newPokemon
|
||||
activePokemon.illusion = illusion
|
||||
battle.sendSidedUpdate(actor, BattleSwitchPokemonPacket(pnx, newPokemon, true, illusion), BattleSwitchPokemonPacket(pnx, newPokemon, false, illusion))
|
||||
@@ -209,7 +201,7 @@ class SwitchInstruction(val instructionSet: InstructionSet, val battleActor: Bat
|
||||
}
|
||||
|
||||
fun createNonEntitySwitch(battle: PokemonBattle, actor: BattleActor, pnx: String, activePokemon: ActiveBattlePokemon, newPokemon: BattlePokemon, illusion: BattlePokemon? = null): DispatchResult {
|
||||
//actor.pokemonList.swap(actor.activePokemon.indexOf(activePokemon), actor.pokemonList.indexOf(newPokemon))
|
||||
actor.pokemonList.swap(actor.activePokemon.indexOf(activePokemon), actor.pokemonList.indexOf(newPokemon))
|
||||
activePokemon.battlePokemon = newPokemon
|
||||
activePokemon.illusion = illusion
|
||||
battle.sendSidedUpdate(actor, BattleSwitchPokemonPacket(pnx, newPokemon, true, illusion), BattleSwitchPokemonPacket(pnx, newPokemon, false, illusion))
|
||||
|
||||
+3
-1
@@ -10,6 +10,8 @@ package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.battles.instruction.TerastallizationEvent
|
||||
import com.cobblemon.mod.common.api.text.yellow
|
||||
import com.cobblemon.mod.common.api.types.tera.TeraTypes
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
@@ -30,7 +32,7 @@ class TerastallizeInstruction(val message: BattleMessage): InterpreterInstructio
|
||||
battle.dispatchWaiting {
|
||||
val pokemonName = battlePokemon.getName()
|
||||
battle.broadcastChatMessage(battleLang("terastallize", pokemonName, type.displayName).yellow())
|
||||
//CobblemonEvents.TERASTALLIZATION.post(TerastallizationEvent(battle, battlePokemon, type))
|
||||
CobblemonEvents.TERASTALLIZATION.post(TerastallizationEvent(battle, battlePokemon, type))
|
||||
battle.minorBattleActions[battlePokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
|
||||
+6
-7
@@ -13,6 +13,9 @@ import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.GO
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.battles.dispatch.UntilDispatch
|
||||
import com.cobblemon.mod.common.entity.pokemon.effects.TransformEffect
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleTransformPokemonPacket
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
@@ -37,10 +40,9 @@ class TransformInstruction(val battle: PokemonBattle, val message: BattleMessage
|
||||
ShowdownInterpreter.broadcastOptionalAbility(battle, effect, pokemon)
|
||||
|
||||
battle.dispatch {
|
||||
GO
|
||||
//val entity = pokemon.entity ?: return@dispatch GO
|
||||
//val future = TransformEffect(targetPokemon.effectedPokemon, battle.started).start(entity)
|
||||
//UntilDispatch { future?.isDone != false }
|
||||
val entity = pokemon.entity ?: return@dispatch GO
|
||||
val future = TransformEffect(targetPokemon.effectedPokemon, battle.started).start(entity)
|
||||
UntilDispatch { future?.isDone != false }
|
||||
}
|
||||
|
||||
battle.dispatchWaiting {
|
||||
@@ -49,14 +51,11 @@ class TransformInstruction(val battle: PokemonBattle, val message: BattleMessage
|
||||
val targetPokemonName = targetPokemon.getName()
|
||||
|
||||
mock?.let {
|
||||
/*
|
||||
battle.sendSidedUpdate(
|
||||
source = actor,
|
||||
allyPacket = BattleTransformPokemonPacket(pnx, pokemon, it, true),
|
||||
opponentPacket = BattleTransformPokemonPacket(pnx, pokemon, it, false)
|
||||
)
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
val lang = battleLang("transform", pokemonName, targetPokemonName)
|
||||
|
||||
+5
-4
@@ -21,6 +21,7 @@ import com.cobblemon.mod.common.battles.actor.PlayerBattleActor
|
||||
import com.cobblemon.mod.common.battles.dispatch.GO
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import java.util.UUID
|
||||
|
||||
@@ -46,11 +47,11 @@ class WinInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
// If the battle was a PvW battle, we need to set the killer of the wild Pokémon to the player
|
||||
if (battle.isPvW) {
|
||||
val nonPlayerActor = battle.actors.first { it.type == ActorType.WILD }
|
||||
// val wildPokemon: BattlePokemon = nonPlayerActor.battlePokemonProvider.getKnownPokemon().first()
|
||||
val wildPokemon: BattlePokemon = nonPlayerActor.pokemonList.first()
|
||||
|
||||
// if (!wasCaught && losers.any { it.uuid == wildPokemon.uuid }) {
|
||||
// wildPokemon.effectedPokemon.entity?.killer = (battle.actors.firstOrNull { it.type == ActorType.PLAYER } as? PlayerBattleActor)?.entity
|
||||
//}
|
||||
if (!wasCaught && losers.any { it.uuid == wildPokemon.uuid }) {
|
||||
wildPokemon.effectedPokemon.entity?.killer = (battle.actors.firstOrNull { it.type == ActorType.PLAYER } as? PlayerBattleActor)?.entity
|
||||
}
|
||||
}
|
||||
|
||||
// broadcast victory / defeat
|
||||
|
||||
+3
-1
@@ -10,6 +10,8 @@ package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.battles.instruction.ZMoveUsedEvent
|
||||
import com.cobblemon.mod.common.api.text.yellow
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
@@ -28,7 +30,7 @@ class ZPowerInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
battle.dispatchWaiting {
|
||||
val pokemonName = battlePokemon.getName()
|
||||
battle.broadcastChatMessage(battleLang("zpower", pokemonName).yellow())
|
||||
//CobblemonEvents.ZPOWER_USED.post(ZMoveUsedEvent(battle, battlePokemon))
|
||||
CobblemonEvents.ZPOWER_USED.post(ZMoveUsedEvent(battle, battlePokemon))
|
||||
battle.minorBattleActions[battlePokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
|
||||
-52
@@ -1,52 +0,0 @@
|
||||
package com.cobblemon.mod.common.battles.pokemon
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
import com.cobblemon.mod.common.api.moves.MoveSet
|
||||
import com.cobblemon.mod.common.api.pokemon.helditem.HeldItemManager
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stat
|
||||
import com.cobblemon.mod.common.battles.interpreter.ContextManager
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.Nature
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
import java.util.UUID
|
||||
import java.util.function.Function
|
||||
|
||||
abstract class AbstractBattlePokemon {
|
||||
lateinit var actor: BattleActor
|
||||
val struct = QueryStruct(
|
||||
hashMapOf(
|
||||
"actor" to Function { actor.struct },
|
||||
"battle" to Function { actor.battle.struct },
|
||||
"uuid" to Function { StringValue(uuid.toString()) },
|
||||
"health" to Function { DoubleValue(health.toDouble()) },
|
||||
"max_health" to Function { DoubleValue(maxHealth.toDouble()) },
|
||||
"nature" to Function { StringValue(nature.name.toString()) },
|
||||
"moveset" to Function { moveSet.toStruct() }
|
||||
))
|
||||
|
||||
val statChanges = mutableMapOf<Stat, Int>()
|
||||
//For when a wild pokemon is being captured in a ball
|
||||
var gone = false
|
||||
|
||||
abstract val uuid: UUID
|
||||
abstract var health: Int
|
||||
abstract val maxHealth: Int
|
||||
abstract val nature: Nature
|
||||
abstract val moveSet: MoveSet
|
||||
abstract val entity: PokemonEntity?
|
||||
abstract val heldItemManager: HeldItemManager
|
||||
|
||||
abstract fun canBeSentOut(): Boolean
|
||||
abstract fun getName(): MutableComponent
|
||||
abstract fun sendUpdate()
|
||||
|
||||
/** The set of all the BattlePokemon that they faced during the battle (for exp purposes) */
|
||||
val facedOpponents = mutableSetOf<BattlePokemon>()
|
||||
val contextManager = ContextManager()
|
||||
|
||||
fun isSentOut() = actor.battle.activePokemon.any { it.battlePokemon == this }
|
||||
fun getIllusion(): AbstractBattlePokemon? = this.actor.activePokemon.find { it.battlePokemon == this }?.illusion
|
||||
}
|
||||
@@ -8,19 +8,28 @@
|
||||
|
||||
package com.cobblemon.mod.common.battles.pokemon
|
||||
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunctions
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asStruct
|
||||
import com.cobblemon.mod.common.api.moves.MoveSet
|
||||
import com.cobblemon.mod.common.api.pokemon.helditem.HeldItemManager
|
||||
import com.cobblemon.mod.common.api.pokemon.helditem.HeldItemProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stat
|
||||
import com.cobblemon.mod.common.battles.actor.MultiPokemonBattleActor
|
||||
import com.cobblemon.mod.common.battles.actor.PokemonBattleActor
|
||||
import com.cobblemon.mod.common.battles.interpreter.ContextManager
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleUpdateTeamPokemonPacket
|
||||
import com.cobblemon.mod.common.pokemon.IVs
|
||||
import com.cobblemon.mod.common.pokemon.Nature
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.properties.BattleCloneProperty
|
||||
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import java.util.UUID
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
import java.util.function.Function
|
||||
|
||||
@@ -28,48 +37,8 @@ open class BattlePokemon(
|
||||
val originalPokemon: Pokemon,
|
||||
val effectedPokemon: Pokemon = originalPokemon,
|
||||
val postBattleEntityOperation: (PokemonEntity) -> Unit = {}
|
||||
) : AbstractBattlePokemon() {
|
||||
override val uuid = effectedPokemon.uuid
|
||||
override var health = effectedPokemon.currentHealth
|
||||
override val maxHealth = effectedPokemon.maxHealth
|
||||
override val nature = effectedPokemon.nature
|
||||
override val moveSet = effectedPokemon.moveSet
|
||||
override val entity = effectedPokemon.entity
|
||||
override val heldItemManager: HeldItemManager by lazy {
|
||||
HeldItemProvider.provide(this)
|
||||
}
|
||||
|
||||
var willBeSwitchedIn = false
|
||||
|
||||
override fun canBeSentOut(): Boolean {
|
||||
return if (actor.request?.side?.pokemon?.any { it.reviving } == true) {
|
||||
!isSentOut() && !willBeSwitchedIn && health <= 0
|
||||
} else {
|
||||
!isSentOut() && !willBeSwitchedIn && health > 0
|
||||
}
|
||||
}
|
||||
|
||||
override fun getName(): MutableComponent {
|
||||
val displayPokemon = ((getIllusion() ?: this) as BattlePokemon).effectedPokemon
|
||||
return if (actor is PokemonBattleActor || actor is MultiPokemonBattleActor) {
|
||||
displayPokemon.getDisplayName()
|
||||
} else {
|
||||
battleLang("owned_pokemon", actor.getName(), displayPokemon.getDisplayName())
|
||||
}
|
||||
}
|
||||
|
||||
override fun sendUpdate() {
|
||||
actor.sendUpdate(BattleUpdateTeamPokemonPacket(effectedPokemon))
|
||||
}
|
||||
|
||||
init {
|
||||
struct.addFunctions(mutableMapOf(
|
||||
"pokemon" to Function { effectedPokemon.asStruct() },
|
||||
"original_pokemon" to Function {
|
||||
originalPokemon.asStruct()
|
||||
},
|
||||
))
|
||||
}
|
||||
) {
|
||||
lateinit var actor: BattleActor
|
||||
|
||||
companion object {
|
||||
fun safeCopyOf(pokemon: Pokemon): BattlePokemon {
|
||||
@@ -92,4 +61,74 @@ open class BattlePokemon(
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
val struct = QueryStruct(
|
||||
hashMapOf(
|
||||
"pokemon" to Function { effectedPokemon.asStruct() },
|
||||
"original_pokemon" to Function {
|
||||
originalPokemon.asStruct()
|
||||
},
|
||||
"actor" to Function { actor.struct },
|
||||
"battle" to Function { actor.battle.struct },
|
||||
"uuid" to Function { StringValue(uuid.toString()) },
|
||||
"health" to Function { DoubleValue(health.toDouble()) },
|
||||
"max_health" to Function { DoubleValue(maxHealth.toDouble()) },
|
||||
"ivs" to Function { effectedPokemon.ivs.struct },
|
||||
"nature" to Function { StringValue(effectedPokemon.nature.name.toString()) },
|
||||
"moveset" to Function { effectedPokemon.moveSet.toStruct() }
|
||||
))
|
||||
|
||||
val uuid: UUID
|
||||
get() = effectedPokemon.uuid
|
||||
val health: Int
|
||||
get() = effectedPokemon.currentHealth
|
||||
val maxHealth: Int
|
||||
get() = effectedPokemon.maxHealth
|
||||
val ivs: IVs
|
||||
get() = effectedPokemon.ivs
|
||||
val nature: Nature
|
||||
get() = effectedPokemon.nature
|
||||
val moveSet: MoveSet
|
||||
get() = effectedPokemon.moveSet
|
||||
val statChanges = mutableMapOf<Stat, Int>()
|
||||
var gone = false
|
||||
// etc
|
||||
|
||||
val entity: PokemonEntity?
|
||||
get() = effectedPokemon.entity
|
||||
|
||||
var willBeSwitchedIn = false
|
||||
|
||||
/** A set of all the BattlePokemon that they faced during the battle (for exp purposes) */
|
||||
val facedOpponents = mutableSetOf<BattlePokemon>()
|
||||
|
||||
/**
|
||||
* The [HeldItemManager] backing this [BattlePokemon].
|
||||
*/
|
||||
val heldItemManager: HeldItemManager by lazy { HeldItemProvider.provide(this) }
|
||||
|
||||
val contextManager = ContextManager()
|
||||
|
||||
open fun getName(): MutableComponent {
|
||||
val displayPokemon = getIllusion()?.effectedPokemon ?: effectedPokemon
|
||||
return if (actor is PokemonBattleActor || actor is MultiPokemonBattleActor) {
|
||||
displayPokemon.getDisplayName()
|
||||
} else {
|
||||
battleLang("owned_pokemon", actor.getName(), displayPokemon.getDisplayName())
|
||||
}
|
||||
}
|
||||
|
||||
fun sendUpdate() {
|
||||
actor.sendUpdate(BattleUpdateTeamPokemonPacket(effectedPokemon))
|
||||
}
|
||||
|
||||
fun isSentOut() = actor.battle.activePokemon.any { it.battlePokemon == this }
|
||||
fun canBeSentOut() =
|
||||
if (actor.request?.side?.pokemon?.any { it.reviving } == true) {
|
||||
!isSentOut() && !willBeSwitchedIn && health <= 0
|
||||
} else {
|
||||
!isSentOut() && !willBeSwitchedIn && health > 0
|
||||
}
|
||||
|
||||
fun getIllusion(): BattlePokemon? = this.actor.activePokemon.find { it.battlePokemon == this }?.illusion
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.runner
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.runner.graal.GraalShowdownService
|
||||
import com.google.gson.JsonArray
|
||||
import java.util.UUID
|
||||
|
||||
/**
|
||||
* Mediator service for communicating between the Cobblemon Minecraft mod and Cobblemon showdown service.
|
||||
*
|
||||
* All outgoing calls to showdown should be done through this layer to decouple the mod from a specific implementation.
|
||||
* To get an instance of the service, use the singleton provided via `ShowdownService.get()`
|
||||
*
|
||||
* @since February 27th, 2023
|
||||
* @author landonjw
|
||||
*/
|
||||
interface ShowdownService {
|
||||
fun openConnection()
|
||||
fun closeConnection()
|
||||
fun startBattle(battle: PokemonBattle, messages: Array<String>)
|
||||
fun send(battleId: UUID, messages: Array<String>)
|
||||
fun getAbilityIds(): JsonArray
|
||||
fun getMoves(): JsonArray
|
||||
fun getItemIds(): JsonArray
|
||||
fun registerSpecies()
|
||||
fun registerBagItems()
|
||||
fun indicateSpeciesInitialized() {}
|
||||
|
||||
|
||||
companion object {
|
||||
val service: ShowdownService by lazy { GraalShowdownService() }
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.showdown.runner.graal
|
||||
package com.cobblemon.mod.common.battles.runner.graal
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import java.util.logging.Handler
|
||||
+81
-86
@@ -6,23 +6,16 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.showdown.runner.graal
|
||||
package com.cobblemon.mod.common.battles.runner.graal
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.moves.MoveTemplate
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.battles.BagItems
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.showdown.runner.CobblemonShowdownBattleServer
|
||||
import com.cobblemon.mod.common.showdown.runner.ShowdownBattle
|
||||
import com.cobblemon.mod.common.battles.runner.ShowdownService
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonArray
|
||||
import org.graalvm.polyglot.Context
|
||||
import org.graalvm.polyglot.HostAccess
|
||||
import org.graalvm.polyglot.HostAccess.Export
|
||||
import org.graalvm.polyglot.PolyglotAccess
|
||||
import org.graalvm.polyglot.Value
|
||||
import org.graalvm.polyglot.io.FileSystem
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.net.URI
|
||||
@@ -34,6 +27,12 @@ import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
import java.nio.file.attribute.FileAttribute
|
||||
import java.util.UUID
|
||||
import org.graalvm.polyglot.Context
|
||||
import org.graalvm.polyglot.HostAccess
|
||||
import org.graalvm.polyglot.HostAccess.Export
|
||||
import org.graalvm.polyglot.PolyglotAccess
|
||||
import org.graalvm.polyglot.Value
|
||||
import org.graalvm.polyglot.io.FileSystem
|
||||
|
||||
/**
|
||||
* Mediator service for communicating between the Cobblemon Minecraft mod and Cobblemon showdown service via
|
||||
@@ -44,7 +43,8 @@ import java.util.UUID
|
||||
* @since February 27, 2023
|
||||
* @author Hiroku, landonjw
|
||||
*/
|
||||
class GraalCobblemonShowdownBattleServer : CobblemonShowdownBattleServer {
|
||||
class GraalShowdownService : ShowdownService {
|
||||
|
||||
@Transient
|
||||
lateinit var context: Context
|
||||
@Transient
|
||||
@@ -54,13 +54,69 @@ class GraalCobblemonShowdownBattleServer : CobblemonShowdownBattleServer {
|
||||
@Transient
|
||||
val gson = Gson()
|
||||
|
||||
override fun connect() {
|
||||
override fun openConnection() {
|
||||
unbundler.attemptUnbundle()
|
||||
createContext()
|
||||
boot()
|
||||
}
|
||||
|
||||
override fun disconnect() {
|
||||
private fun createContext() {
|
||||
val wd = Paths.get("./showdown")
|
||||
val access = HostAccess.newBuilder(HostAccess.EXPLICIT)
|
||||
.allowIterableAccess(true)
|
||||
.allowArrayAccess(true)
|
||||
.allowListAccess(true)
|
||||
.allowMapAccess(true)
|
||||
.build()
|
||||
context = Context.newBuilder("js")
|
||||
.allowIO(true)
|
||||
.fileSystem(object : FileSystem
|
||||
{
|
||||
val default = FileSystem.newDefaultFileSystem()
|
||||
override fun parsePath(uri: URI) = default.parsePath(uri)
|
||||
override fun parsePath(path: String) = default.parsePath(path)
|
||||
override fun createDirectory(dir: Path, vararg attrs: FileAttribute<*>) = default.createDirectory(dir, *attrs)
|
||||
override fun delete(path: Path) = default.delete(path)
|
||||
override fun newByteChannel(path: Path, options: MutableSet<out OpenOption>, vararg attrs: FileAttribute<*>) = default.newByteChannel(path, options, *attrs)
|
||||
override fun newDirectoryStream(dir: Path, filter: DirectoryStream.Filter<in Path>) = default.newDirectoryStream(dir, filter)
|
||||
override fun toAbsolutePath(path: Path) = default.toAbsolutePath(path)
|
||||
override fun toRealPath(path: Path, vararg linkOptions: LinkOption) = default.toRealPath(path, *linkOptions)
|
||||
override fun readAttributes(path: Path, attributes: String, vararg options: LinkOption) = default.readAttributes(path, attributes, *options)
|
||||
override fun checkAccess(path: Path, modes: MutableSet<out AccessMode>, vararg linkOptions: LinkOption) {
|
||||
if (!path.toRealPath(LinkOption.NOFOLLOW_LINKS).startsWith(wd.toRealPath(LinkOption.NOFOLLOW_LINKS))) {
|
||||
Cobblemon.LOGGER.error("Hacked JS files in datapacks or some weird file system setup that Hiroku failed to anticipate.")
|
||||
throw IOException("Someone has put hacked JS files into datapacks because file access is being attempted outside of controlled folders.")
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
.allowExperimentalOptions(true)
|
||||
.allowPolyglotAccess(PolyglotAccess.ALL)
|
||||
.allowHostAccess(access)
|
||||
.allowCreateThread(true)
|
||||
.logHandler(GraalLogger)
|
||||
.option("engine.WarnInterpreterOnly", "false")
|
||||
.option("js.commonjs-require", "true")
|
||||
.option("js.commonjs-require-cwd", "showdown")
|
||||
.option(
|
||||
"js.commonjs-core-modules-replacements",
|
||||
"buffer:buffer/,crypto:crypto-browserify,path:path-browserify"
|
||||
)
|
||||
.allowHostClassLoading(true)
|
||||
.allowNativeAccess(true)
|
||||
.allowCreateProcess(true)
|
||||
.build()
|
||||
|
||||
context.eval("js", """
|
||||
globalThis.process = {
|
||||
cwd: function() {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
override fun closeConnection() {
|
||||
context.close()
|
||||
}
|
||||
|
||||
@@ -69,36 +125,31 @@ class GraalCobblemonShowdownBattleServer : CobblemonShowdownBattleServer {
|
||||
sendBattleMessageFunction = context.getBindings("js").getMember("sendBattleMessage")
|
||||
}
|
||||
|
||||
override fun initializeNewBattle(battleId: String, messages: Array<String>): ShowdownBattle {
|
||||
override fun startBattle(battle: PokemonBattle, messages: Array<String>) {
|
||||
val startBattleFunction = context.getBindings("js").getMember("startBattle")
|
||||
startBattleFunction.execute(this, battleId, messages)
|
||||
return GraalShowdownBattle(battleId, sendBattleMessageFunction)
|
||||
startBattleFunction.execute(this, battle.battleId.toString(), messages)
|
||||
}
|
||||
|
||||
override fun sendServerMessage(msg: String) {
|
||||
throw NotImplementedError("You shouldn't be sending server messages to a GraalShowdownBattleServer, all messages should be sent in a GraalShowdownBattle")
|
||||
override fun send(battleId: UUID, messages: Array<String>) {
|
||||
sendToShowdown(battleId, messages)
|
||||
}
|
||||
|
||||
override fun getAbilityIds(): Collection<String> {
|
||||
override fun getAbilityIds(): JsonArray {
|
||||
val getCobbledAbilityIdsFn = context.getBindings("js").getMember("getCobbledAbilityIds")
|
||||
val arrayResult = getCobbledAbilityIdsFn.execute().asString()
|
||||
return gson.fromJson(arrayResult, JsonArray::class.java).map { it.asString }.toSet()
|
||||
return gson.fromJson(arrayResult, JsonArray::class.java)
|
||||
}
|
||||
|
||||
override fun getMoves(): Collection<MoveTemplate> {
|
||||
override fun getMoves(): JsonArray {
|
||||
val getCobbledMovesFn = context.getBindings("js").getMember("getCobbledMoves")
|
||||
val arrayResult = getCobbledMovesFn.execute().asString()
|
||||
return gson.fromJson(arrayResult, JsonArray::class.java).map { MoveTemplate.decodeJsonMove(it.asJsonObject) }.toSet()
|
||||
return gson.fromJson(arrayResult, JsonArray::class.java)
|
||||
}
|
||||
|
||||
override fun getItemIds(): Collection<String> {
|
||||
override fun getItemIds(): JsonArray {
|
||||
val getCobbledItemIdsFn = context.getBindings("js").getMember("getCobbledItemIds")
|
||||
val arrayResult = getCobbledItemIdsFn.execute().asString()
|
||||
return gson.fromJson(arrayResult, JsonArray::class.java).map { it.asString }.toSet()
|
||||
}
|
||||
|
||||
override fun onServerStarted() {
|
||||
|
||||
return gson.fromJson(arrayResult, JsonArray::class.java)
|
||||
}
|
||||
|
||||
override fun registerSpecies() {
|
||||
@@ -128,69 +179,13 @@ class GraalCobblemonShowdownBattleServer : CobblemonShowdownBattleServer {
|
||||
}
|
||||
}
|
||||
|
||||
private fun createContext() {
|
||||
val wd = Paths.get("./showdown")
|
||||
val access = HostAccess.newBuilder(HostAccess.EXPLICIT)
|
||||
.allowIterableAccess(true)
|
||||
.allowArrayAccess(true)
|
||||
.allowListAccess(true)
|
||||
.allowMapAccess(true)
|
||||
.build()
|
||||
context = Context.newBuilder("js")
|
||||
.allowIO(true)
|
||||
.fileSystem(object : FileSystem
|
||||
{
|
||||
val default = FileSystem.newDefaultFileSystem()
|
||||
override fun parsePath(uri: URI) = default.parsePath(uri)
|
||||
override fun parsePath(path: String) = default.parsePath(path)
|
||||
override fun createDirectory(dir: Path, vararg attrs: FileAttribute<*>) = default.createDirectory(dir, *attrs)
|
||||
override fun delete(path: Path) = default.delete(path)
|
||||
override fun newByteChannel(path: Path, options: MutableSet<out OpenOption>, vararg attrs: FileAttribute<*>) = default.newByteChannel(path, options, *attrs)
|
||||
override fun newDirectoryStream(dir: Path, filter: DirectoryStream.Filter<in Path>) = default.newDirectoryStream(dir, filter)
|
||||
override fun toAbsolutePath(path: Path) = default.toAbsolutePath(path)
|
||||
override fun toRealPath(path: Path, vararg linkOptions: LinkOption) = default.toRealPath(path, *linkOptions)
|
||||
override fun readAttributes(path: Path, attributes: String, vararg options: LinkOption) = default.readAttributes(path, attributes, *options)
|
||||
override fun checkAccess(path: Path, modes: MutableSet<out AccessMode>, vararg linkOptions: LinkOption) {
|
||||
if (!path.toRealPath(LinkOption.NOFOLLOW_LINKS).startsWith(wd.toRealPath(LinkOption.NOFOLLOW_LINKS))) {
|
||||
Cobblemon.LOGGER.error("Hacked JS files in datapacks or some weird file system setup that Hiroku failed to anticipate.")
|
||||
throw IOException("Someone has put hacked JS files into datapacks because file access is being attempted outside of controlled folders.")
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
.allowExperimentalOptions(true)
|
||||
.allowPolyglotAccess(PolyglotAccess.ALL)
|
||||
.allowHostAccess(access)
|
||||
.allowCreateThread(true)
|
||||
.logHandler(GraalLogger)
|
||||
.option("engine.WarnInterpreterOnly", "false")
|
||||
.option("js.commonjs-require", "true")
|
||||
.option("js.commonjs-require-cwd", "showdown")
|
||||
.option(
|
||||
"js.commonjs-core-modules-replacements",
|
||||
"buffer:buffer/,crypto:crypto-browserify,path:path-browserify"
|
||||
)
|
||||
.allowHostClassLoading(true)
|
||||
.allowNativeAccess(true)
|
||||
.allowCreateProcess(true)
|
||||
.build()
|
||||
|
||||
context.eval("js", """
|
||||
globalThis.process = {
|
||||
cwd: function() {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
private fun sendToShowdown(battleId: UUID, messages: Array<String>) {
|
||||
sendBattleMessageFunction.execute(battleId, messages)
|
||||
sendBattleMessageFunction.execute(battleId.toString(), messages)
|
||||
}
|
||||
|
||||
@Export
|
||||
fun sendFromShowdown(battleId: String, message: String) {
|
||||
ShowdownInterpreter.interpretMessage(battleId, message)
|
||||
ShowdownInterpreter.interpretMessage(UUID.fromString(battleId), message)
|
||||
}
|
||||
|
||||
@Export
|
||||
+6
-1
@@ -6,15 +6,20 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.showdown.runner.graal
|
||||
package com.cobblemon.mod.common.battles.runner.graal
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.util.FileUtils
|
||||
import com.cobblemon.mod.common.util.extractTo
|
||||
import com.cobblemon.mod.common.util.fromJson
|
||||
import com.google.gson.GsonBuilder
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import oshi.util.FileUtil
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.InputStreamReader
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.StandardCopyOption
|
||||
|
||||
/**
|
||||
* Unbundles a zipped Showdown file found within {@code resources/data/showdown.zip} for use within the GraalShowdownService.
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.runner.socket
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.battles.BagItems
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.runner.ShowdownService
|
||||
import com.cobblemon.mod.common.pokemon.FormData
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonArray
|
||||
import java.io.BufferedReader
|
||||
import java.io.InputStreamReader
|
||||
import java.io.OutputStreamWriter
|
||||
import java.net.InetAddress
|
||||
import java.net.Socket
|
||||
import java.nio.charset.Charset
|
||||
import java.util.UUID
|
||||
|
||||
/**
|
||||
* Mediator service for communicating between the Cobblemon Minecraft mod and Cobblemon showdown service via
|
||||
* a socket client.
|
||||
*
|
||||
* This is primarily used for debugging purposes, but could be extended in the future to provide
|
||||
* a means of connecting to a remote Showdown server. This does not provide any fault handling in the
|
||||
* event that the server goes down.
|
||||
*
|
||||
* When messages are sent to showdown, this will await a response from showdown.
|
||||
* The protocol for messages sent from showdown is <length of characters in payload><payload>,
|
||||
* and a payload length of 0 indicates that there is no response.
|
||||
*
|
||||
* @see {@code sim/cobbled-debug-server.ts} within cobblemon-showdown repository
|
||||
* @since February 27, 2023
|
||||
* @author landonjw
|
||||
*/
|
||||
class SocketShowdownService(val host: String = "localhost", val port: Int = 18468, val localPort: Int = 0) : ShowdownService {
|
||||
|
||||
private lateinit var socket: Socket
|
||||
private lateinit var writer: OutputStreamWriter
|
||||
private lateinit var reader: BufferedReader
|
||||
val gson = Gson()
|
||||
|
||||
override fun openConnection() {
|
||||
socket = Socket(InetAddress.getLocalHost(), port, InetAddress.getLocalHost(), localPort)
|
||||
writer = socket.getOutputStream().writer(charset = Charset.forName("ascii"))
|
||||
reader = BufferedReader(InputStreamReader(socket.getInputStream()))
|
||||
}
|
||||
|
||||
override fun closeConnection() {
|
||||
socket.close()
|
||||
}
|
||||
|
||||
override fun startBattle(battle: PokemonBattle, messages: Array<String>) {
|
||||
writer.write(">startbattle ${battle.battleId}\n")
|
||||
acknowledge { Cobblemon.LOGGER.error("Failed to start battle!") }
|
||||
send(battle.battleId, messages)
|
||||
}
|
||||
|
||||
override fun send(battleId: UUID, messages: Array<String>) {
|
||||
for (message in messages) {
|
||||
writer.write("$battleId~$message\n")
|
||||
writer.flush()
|
||||
readBattleInput().forEach { interpretMessage(battleId, it) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun read(reader: BufferedReader, size: Int): String {
|
||||
val buffer = CharArray(size)
|
||||
while (true) {
|
||||
if(reader.read(buffer) == 0) continue
|
||||
return String(buffer)
|
||||
}
|
||||
}
|
||||
|
||||
private fun readMessage(): String {
|
||||
val payloadSize = read(reader, 8).toInt()
|
||||
val payload = read(reader, payloadSize)
|
||||
return payload
|
||||
}
|
||||
|
||||
private fun readBattleInput(): List<String> {
|
||||
val lines = mutableListOf<String>()
|
||||
val numLines = read(reader, 8).toInt()
|
||||
if (numLines != 0) {
|
||||
for (i in 0 until numLines) {
|
||||
lines.add(readMessage())
|
||||
}
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
||||
private fun interpretMessage(battleId: UUID, message: String) {
|
||||
ShowdownInterpreter.interpretMessage(battleId, message)
|
||||
}
|
||||
|
||||
override fun getAbilityIds(): JsonArray {
|
||||
writer.write(">getCobbledAbilityIds")
|
||||
writer.flush()
|
||||
val response = readMessage()
|
||||
return gson.fromJson(response, JsonArray::class.java)
|
||||
}
|
||||
|
||||
override fun getMoves(): JsonArray {
|
||||
writer.write(">getCobbledMoves\n")
|
||||
writer.flush()
|
||||
val response = readMessage()
|
||||
return gson.fromJson(response, JsonArray::class.java)
|
||||
}
|
||||
|
||||
override fun getItemIds(): JsonArray {
|
||||
writer.write(">getCobbledItemIds")
|
||||
writer.flush()
|
||||
val response = readMessage()
|
||||
return gson.fromJson(response, JsonArray::class.java)
|
||||
}
|
||||
|
||||
private fun sendSpeciesData(species: Species, form: FormData?) {
|
||||
writer.write(">receiveSpeciesData ${gson.toJson(PokemonSpecies.ShowdownSpecies(species, form))}\n")
|
||||
acknowledge()
|
||||
}
|
||||
|
||||
private fun sendBagItem(itemId: String, js: String) {
|
||||
writer.write(">receiveBagItemData $itemId $js")
|
||||
acknowledge { Cobblemon.LOGGER.error("Failed to send bag item to Showdown: $itemId") }
|
||||
}
|
||||
|
||||
override fun registerSpecies() {
|
||||
writer.write(">resetSpeciesData\n")
|
||||
acknowledge()
|
||||
PokemonSpecies.species.forEach { species ->
|
||||
sendSpeciesData(species, null)
|
||||
species.forms.forEach { form ->
|
||||
if (form != species.standardForm) {
|
||||
sendSpeciesData(species, form)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun acknowledge(ifFails: () -> Unit = {}) {
|
||||
writer.flush()
|
||||
val ack = CharArray(3)
|
||||
reader.read(ack)
|
||||
if (String(ack) != "ACK") {
|
||||
ifFails()
|
||||
}
|
||||
}
|
||||
|
||||
override fun registerBagItems() {
|
||||
for ((itemId, js) in BagItems.bagItemsScripts) {
|
||||
sendBagItem(itemId, js.replace("\n", " "))
|
||||
}
|
||||
}
|
||||
|
||||
override fun indicateSpeciesInitialized() {
|
||||
writer.write(">afterCobbledSpeciesInit")
|
||||
acknowledge()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -114,8 +114,8 @@ class RevivalHerbBlock(settings: Properties) : CropBlock(settings), Mulchable {
|
||||
var growthSpeed = 1.0F
|
||||
var ground = pos.below()
|
||||
|
||||
for(x in -1..1) {
|
||||
for(z in -1..1) {
|
||||
for (x in -1..1) {
|
||||
for (z in -1..1) {
|
||||
var nearbyFarmLandBoost = 0.0F
|
||||
var blockState = level.getBlockState(ground.offset(x, 0, z))
|
||||
if (blockState.`is`(Blocks.FARMLAND)) {
|
||||
|
||||
+1
-1
@@ -94,7 +94,7 @@ class FossilAnalyzerBlockEntity(
|
||||
return stack?.let { Fossils.isFossilIngredient(it) } == true
|
||||
&& structure.fossilInventory.size < Cobblemon.config.maxInsertedFossilItems
|
||||
&& structure.isRunning() == false && structure.resultingFossil == null
|
||||
&& Fossils.getSubFossilByItemStacks( structure.fossilInventory + mutableListOf(stack) ) != null
|
||||
&& Fossils.getSubFossilByItemStacks(structure.fossilInventory + mutableListOf(stack)) != null
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -72,10 +72,12 @@ 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 java.util.UUID
|
||||
|
||||
object CobblemonClient {
|
||||
|
||||
@@ -327,7 +329,7 @@ object CobblemonClient {
|
||||
|
||||
fun endBattle() {
|
||||
battle = null
|
||||
battleOverlay.lastKnownBattle = ""
|
||||
battleOverlay.lastKnownBattle = null
|
||||
BattleMusicController.endMusic()
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import com.cobblemon.mod.common.net.messages.server.battle.BattleSelectActionsPa
|
||||
import java.util.UUID
|
||||
|
||||
class ClientBattle(
|
||||
val battleId: String,
|
||||
val battleId: UUID,
|
||||
val battleFormat: BattleFormat
|
||||
) {
|
||||
var minimised = true
|
||||
|
||||
@@ -108,7 +108,7 @@ class BattleOverlay : Gui(Minecraft.getInstance()), Schedulable {
|
||||
get() = (opacity - MIN_OPACITY) / (MAX_OPACITY - MIN_OPACITY)
|
||||
var passedSeconds = 0F
|
||||
|
||||
var lastKnownBattle: String = ""
|
||||
var lastKnownBattle: UUID? = null
|
||||
lateinit var messagePane: BattleMessagePane
|
||||
var hidePortraits = false
|
||||
override val schedulingTracker = SchedulingTracker()
|
||||
@@ -530,7 +530,7 @@ class BattleOverlay : Gui(Minecraft.getInstance()), Schedulable {
|
||||
fun onLogout() {
|
||||
this.opacity = MIN_OPACITY
|
||||
this.passedSeconds = 0F
|
||||
this.lastKnownBattle = ""
|
||||
this.lastKnownBattle = null
|
||||
}
|
||||
|
||||
}
|
||||
@@ -491,16 +491,16 @@ class PokedexGUI private constructor(
|
||||
|
||||
when (tabIndex) {
|
||||
TAB_DESCRIPTION -> {
|
||||
tabInfoElement = DescriptionWidget( x + 180, y + 135)
|
||||
tabInfoElement = DescriptionWidget(x + 180, y + 135)
|
||||
}
|
||||
TAB_ABILITIES -> {
|
||||
tabInfoElement = AbilitiesWidget( x + 180, y + 135)
|
||||
tabInfoElement = AbilitiesWidget(x + 180, y + 135)
|
||||
}
|
||||
TAB_SIZE -> {
|
||||
tabInfoElement = SizeWidget( x + 180, y + 135)
|
||||
tabInfoElement = SizeWidget(x + 180, y + 135)
|
||||
}
|
||||
TAB_STATS -> {
|
||||
tabInfoElement = StatsWidget( x + 180, y + 135)
|
||||
tabInfoElement = StatsWidget(x + 180, y + 135)
|
||||
}
|
||||
TAB_DROPS -> {
|
||||
tabInfoElement = DropsScrollingWidget(x + 189, y + 135)
|
||||
|
||||
+1
-1
@@ -224,7 +224,7 @@ class PokeBobberEntityRenderer(context: EntityRendererProvider.Context?) : Entit
|
||||
// Iris Shader Compatibility: Keeps Iris from connecting the fishing lines of multiple players' Pokerods.
|
||||
// Iris performs a mixin into FishingHookRenderer to achieve the same result.
|
||||
// So we mimic their fix here.
|
||||
vertexConsumer2.addVertex( 0f, 0f, 0f).setColor(0, 0, 0, 255).setNormal( 0f, 0f, 0f);
|
||||
vertexConsumer2.addVertex(0f, 0f, 0f).setColor(0, 0, 0, 255).setNormal(0f, 0f, 0f);
|
||||
|
||||
super.render(fishingBobberEntity, elapsedPartialTicks, tickDelta, matrixStack, vertexConsumerProvider, light)
|
||||
}
|
||||
|
||||
+2
-2
@@ -83,12 +83,12 @@ class VibravaModel (root: ModelPart) : PokemonPosableModel(root), QuadrupedFram
|
||||
singleBoneLook(pitchMultiplier = 0.6F, yawMultiplier = 0.3F),
|
||||
bedrock("vibrava", "ground_idle"),
|
||||
wingFrame1.wingFlap(
|
||||
flapFunction = triangleFunction( period = 0.08F, amplitude = 0.6F),
|
||||
flapFunction = triangleFunction(period = 0.08F, amplitude = 0.6F),
|
||||
timeVariable = { state, _, _ -> state.animationSeconds },
|
||||
axis = ModelPartTransformation.Z_AXIS
|
||||
),
|
||||
wingFrame2.wingFlap(
|
||||
flapFunction = triangleFunction( period = 0.1F, amplitude = 0.4F),
|
||||
flapFunction = triangleFunction(period = 0.1F, amplitude = 0.4F),
|
||||
timeVariable = { state, _, _ -> 0.01F + state.animationSeconds },
|
||||
axis = ModelPartTransformation.Z_AXIS
|
||||
)
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ class DarumakaModel (root: ModelPart) : PokemonPosableModel(root) {
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("darumaka", "blink") }
|
||||
val quirk = quirk(secondsBetweenOccurrences = 15F to 100F) { bedrockStateful("darumaka", "quirk") }
|
||||
val quirk2 = quirk(secondsBetweenOccurrences = 20F to 360F) { bedrockStateful( "darumaka","quirk2")}
|
||||
val quirk2 = quirk(secondsBetweenOccurrences = 20F to 360F) { bedrockStateful("darumaka","quirk2")}
|
||||
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
|
||||
+4
-4
@@ -62,12 +62,12 @@ class VolcaronaModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame
|
||||
singleBoneLook(pitchMultiplier = 0.2F, yawMultiplier = 0.3F),
|
||||
bedrock("volcarona", "ground_idle"),
|
||||
wingFrame.wingFlap(
|
||||
flapFunction = sineFunction( period = 1F, amplitude = 0.25F),
|
||||
flapFunction = sineFunction(period = 1F, amplitude = 0.25F),
|
||||
timeVariable = { state, _, _ -> state.animationSeconds },
|
||||
axis = ModelPartTransformation.Y_AXIS
|
||||
),
|
||||
fluffFrame.wingFlap(
|
||||
flapFunction = sineFunction( period = 1F, amplitude = 0.3F),
|
||||
flapFunction = sineFunction(period = 1F, amplitude = 0.3F),
|
||||
timeVariable = { state, _, _ -> state.animationSeconds },
|
||||
axis = ModelPartTransformation.Y_AXIS
|
||||
)
|
||||
@@ -88,12 +88,12 @@ class VolcaronaModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame
|
||||
singleBoneLook(pitchMultiplier = 0.2F, yawMultiplier = 0.3F),
|
||||
bedrock("volcarona", "ground_idle"),
|
||||
wingFrame.wingFlap(
|
||||
flapFunction = sineFunction( period = 0.8F, amplitude = 0.25F),
|
||||
flapFunction = sineFunction(period = 0.8F, amplitude = 0.25F),
|
||||
timeVariable = { state, _, _ -> state.animationSeconds },
|
||||
axis = ModelPartTransformation.Y_AXIS
|
||||
),
|
||||
fluffFrame.wingFlap(
|
||||
flapFunction = sineFunction( period = 0.8F, amplitude = 0.3F),
|
||||
flapFunction = sineFunction(period = 0.8F, amplitude = 0.3F),
|
||||
timeVariable = { state, _, _ -> state.animationSeconds },
|
||||
axis = ModelPartTransformation.Y_AXIS
|
||||
)
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ class CancellableSoundInstance(sound: SoundEvent, pos: BlockPos = BlockPos.ZERO,
|
||||
// listener is very far away, kill it
|
||||
this.done = true
|
||||
BlockEntitySoundTracker.stop(this.pos, this)
|
||||
} else if( listenerPos > ATTENUATION_DISTANCE_MAX_SQUARED) {
|
||||
} else if (listenerPos > ATTENUATION_DISTANCE_MAX_SQUARED) {
|
||||
++unheardTicks
|
||||
// Purpose of this is if a client is pushing in and out of the attenuation range, they won't notice the sound abruptly stopping
|
||||
if(unheardTicks > UNHEARD_TICKS_MAX) {
|
||||
|
||||
@@ -28,8 +28,7 @@ object ClearPartyCommand {
|
||||
fun register(dispatcher : CommandDispatcher<CommandSourceStack>) {
|
||||
val command = Commands.literal(NAME)
|
||||
.permission(CobblemonPermissions.CLEAR_PARTY)
|
||||
.then( Commands.argument(PLAYER, EntityArgument.players()).executes(::execute)
|
||||
)
|
||||
.then(Commands.argument(PLAYER, EntityArgument.players()).executes(::execute))
|
||||
dispatcher.register(command)
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ import net.minecraft.commands.arguments.selector.EntitySelector
|
||||
import net.minecraft.network.chat.Component
|
||||
|
||||
object PokedexCommand {
|
||||
|
||||
private const val NAME = "pokedex"
|
||||
private const val GRANT_NAME = "grant"
|
||||
private const val REVOKE_NAME = "revoke"
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.command
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.showdown.runner.CobblemonShowdownBattleServer
|
||||
import com.cobblemon.mod.common.battles.runner.ShowdownService
|
||||
import com.mojang.brigadier.Command
|
||||
import com.mojang.brigadier.CommandDispatcher
|
||||
import com.mojang.brigadier.context.CommandContext
|
||||
@@ -28,13 +27,10 @@ object ReloadShowdownCommand {
|
||||
|
||||
private fun execute(context: CommandContext<CommandSourceStack>): Int {
|
||||
try {
|
||||
Cobblemon.showdownServer.disconnect()
|
||||
Cobblemon.showdownServer.connect()
|
||||
val showdownServer = Cobblemon.showdownServer
|
||||
if (showdownServer is CobblemonShowdownBattleServer) {
|
||||
showdownServer.registerSpecies()
|
||||
showdownServer.registerBagItems()
|
||||
}
|
||||
ShowdownService.service.closeConnection()
|
||||
ShowdownService.service.openConnection()
|
||||
ShowdownService.service.registerSpecies()
|
||||
ShowdownService.service.registerBagItems()
|
||||
context.source.sendSystemMessage(Component.literal("Reloaded showdown"))
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
package com.cobblemon.mod.common.command
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.showdown.runner.remote.RemoteShowdownBattleServer
|
||||
import com.cobblemon.mod.common.showdown.runner.remote.ShowdownGameServerLoginManager
|
||||
import com.cobblemon.mod.common.showdown.runner.remote.ShowdownGameServerLoginState
|
||||
import com.mojang.brigadier.Command
|
||||
import com.mojang.brigadier.CommandDispatcher
|
||||
import com.mojang.brigadier.arguments.StringArgumentType
|
||||
import com.mojang.brigadier.context.CommandContext
|
||||
import net.minecraft.commands.CommandSourceStack
|
||||
import net.minecraft.commands.Commands.argument
|
||||
import net.minecraft.commands.Commands.literal
|
||||
import net.minecraft.network.chat.Component
|
||||
|
||||
object ShowdownCommand {
|
||||
private const val NAME = "showdown"
|
||||
|
||||
fun register(dispatcher : CommandDispatcher<CommandSourceStack>) {
|
||||
dispatcher.register(
|
||||
literal(NAME)
|
||||
.then(
|
||||
literal("setnickname").then(
|
||||
argument("name", StringArgumentType.string()).executes(::executeSetNick)
|
||||
)
|
||||
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun executeSetNick(context: CommandContext<CommandSourceStack>): Int {
|
||||
val name = StringArgumentType.getString(context, "name")
|
||||
val showdownServer = Cobblemon.showdownServer
|
||||
if (showdownServer !is RemoteShowdownBattleServer) {
|
||||
context.source.sendFailure(Component.literal("Configured showdown server is not a showdown game server!!"))
|
||||
return Command.SINGLE_SUCCESS
|
||||
}
|
||||
val assertion = ShowdownGameServerLoginManager.loginGuest(name, showdownServer.getLoginState())
|
||||
showdownServer.setLoginState(ShowdownGameServerLoginState(assertion = assertion, username = name))
|
||||
showdownServer.sendServerMessage("|/trn $name,0,$assertion")
|
||||
return Command.SINGLE_SUCCESS
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ class RaisedPPStagesFix(output: Schema) : PokemonFix(output) {
|
||||
}
|
||||
|
||||
var moves = moveSetJson.get()
|
||||
for(i in 0..moves.size) {
|
||||
for (i in 0..moves.size) {
|
||||
var move = moves.getOrNull(i)
|
||||
if(move != null && move.get("RaisedPPStages").asNumber(0).toInt() > 3) {
|
||||
moves[i] = move.set("RaisedPPStages", dynamic.createInt(3))
|
||||
|
||||
@@ -26,6 +26,7 @@ enum class PoseType {
|
||||
FLY,
|
||||
FLOAT,
|
||||
SWIM,
|
||||
GLIDE,
|
||||
/** A pose for rendering on the left shoulder. Pose animations are given the player head yaw, pitch, and ageInTicks. */
|
||||
SHOULDER_LEFT,
|
||||
/** A pose for rendering on the right shoulder. Pose animations are given the player head yaw, pitch, and ageInTicks. */
|
||||
|
||||
@@ -8,9 +8,14 @@
|
||||
|
||||
package com.cobblemon.mod.common.entity.npc
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.*
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.AIBattleActor
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.EntityBackedBattleActor
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.api.storage.party.PartyStore
|
||||
import com.cobblemon.mod.common.battles.ai.StrongBattleAI
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleEndPacket
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.chainFutures
|
||||
@@ -20,8 +25,13 @@ import java.util.concurrent.CompletableFuture
|
||||
|
||||
class NPCBattleActor(
|
||||
val npc: NPCEntity,
|
||||
pokemonProvider: BattlePokemonProvider
|
||||
) : BattleActor(npc.uuid, pokemonProvider), EntityBackedBattleActor<NPCEntity> {
|
||||
pokemonList: List<BattlePokemon>,
|
||||
val skill: Int
|
||||
) : AIBattleActor(
|
||||
gameId = npc.uuid,
|
||||
pokemonList = pokemonList.let { if (npc.npc.randomizePartyOrder) it.shuffled() else it },
|
||||
battleAI = StrongBattleAI(skill)
|
||||
), EntityBackedBattleActor<NPCEntity> {
|
||||
override val entity = npc
|
||||
override val type = ActorType.NPC
|
||||
override fun getName() = npc.effectiveName().copy()
|
||||
@@ -30,17 +40,19 @@ class NPCBattleActor(
|
||||
|
||||
constructor(
|
||||
npc: NPCEntity,
|
||||
party: PartyStore
|
||||
party: PartyStore,
|
||||
skill: Int
|
||||
): this(
|
||||
npc,
|
||||
StaticBattlePokemonProvider(party.toBattleTeam(healPokemon = npc.npc.autoHealParty))
|
||||
party.toBattleTeam(healPokemon = npc.npc.autoHealParty),
|
||||
skill
|
||||
)
|
||||
|
||||
override fun sendUpdate(packet: NetworkPacket<*>) {
|
||||
super.sendUpdate(packet)
|
||||
if (packet is BattleEndPacket) {
|
||||
if (npc.isAlive) {
|
||||
val allEntities = battlePokemonProvider.getKnownPokemon().mapNotNull { it.entity }.toMutableList()
|
||||
val allEntities = pokemonList.mapNotNull { it.entity }.toMutableList()
|
||||
val finalFuture = CompletableFuture<Unit>()
|
||||
chainFutures(allEntities.map { pokemonEntity -> { pokemonEntity.recallWithAnimation() } }.iterator(), finalFuture)
|
||||
if (allEntities.isEmpty()) {
|
||||
|
||||
@@ -164,7 +164,7 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
|
||||
val aspects: Set<String>
|
||||
get() = entityData.get(ASPECTS)
|
||||
|
||||
val battleIds: Set<String>
|
||||
val battleIds: Set<UUID>
|
||||
get() = entityData.get(BATTLE_IDS)
|
||||
|
||||
var actionEffect: ActionEffectContext? = null
|
||||
@@ -207,7 +207,7 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
|
||||
val NPC_CLASS = SynchedEntityData.defineId(NPCEntity::class.java, IdentifierDataSerializer)
|
||||
val ASPECTS = SynchedEntityData.defineId(NPCEntity::class.java, StringSetDataSerializer)
|
||||
val POSE_TYPE = SynchedEntityData.defineId(NPCEntity::class.java, PoseTypeDataSerializer)
|
||||
val BATTLE_IDS = SynchedEntityData.defineId(NPCEntity::class.java, StringSetDataSerializer)
|
||||
val BATTLE_IDS = SynchedEntityData.defineId(NPCEntity::class.java, UUIDSetDataSerializer)
|
||||
val NPC_PLAYER_TEXTURE = SynchedEntityData.defineId(NPCEntity::class.java, NPCPlayerTextureSerializer)
|
||||
val LEVEL = SynchedEntityData.defineId(NPCEntity::class.java, EntityDataSerializers.INT)
|
||||
val HIDE_NAME_TAG = SynchedEntityData.defineId(NPCEntity::class.java, EntityDataSerializers.BOOLEAN)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user