mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-21 14:46:25 -04:00
Compare commits
85
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea99b339ea | ||
|
|
5b23b0cfbe | ||
|
|
778ceff183 | ||
|
|
f32050c8b5 | ||
|
|
3522bac72a | ||
|
|
ecf037666f | ||
|
|
618d062ca9 | ||
|
|
49841b40ec | ||
|
|
87141e1137 | ||
|
|
1f962d664f | ||
|
|
09797f25b1 | ||
|
|
3911413c69 | ||
|
|
12f3e7b78b | ||
|
|
fdb37ba5e8 | ||
|
|
7a99845d0f | ||
|
|
247052ee67 | ||
|
|
29f6524c49 | ||
|
|
1e617a684b | ||
|
|
c9a0352a7c | ||
|
|
d157536e1e | ||
|
|
fb90ccb86e | ||
|
|
c112f9615c | ||
|
|
fc882190fe | ||
|
|
15d7cd815d | ||
|
|
fefdfd877b | ||
|
|
35fb170225 | ||
|
|
d2e405131f | ||
|
|
b6ec0205ef | ||
|
|
e57a42e755 | ||
|
|
5119617f00 | ||
|
|
6e84efb53c | ||
|
|
de3191b768 | ||
|
|
76ec4b4d5a | ||
|
|
25702ade61 | ||
|
|
c6da88d0b2 | ||
|
|
b22a31909d | ||
|
|
cbbbacc215 | ||
|
|
d22d81209d | ||
|
|
8571d78894 | ||
|
|
65c5e95ddf | ||
|
|
0fae95aabc | ||
|
|
bbfd864b33 | ||
|
|
b107d76762 | ||
|
|
8d4f10349c | ||
|
|
f36787e67f | ||
|
|
fc198c599e | ||
|
|
26f753880c | ||
|
|
a9ebb0b6f2 | ||
|
|
a7158ee57a | ||
|
|
06c3fd3f09 | ||
|
|
4e196e8a29 | ||
|
|
871f33f442 | ||
|
|
21c1f912a7 | ||
|
|
776fb5413f | ||
|
|
f645fd9b60 | ||
|
|
ac161ae5b4 | ||
|
|
fc3542e3eb | ||
|
|
f75e3d11da | ||
|
|
3439aeff1e | ||
|
|
2ada7e0b68 | ||
|
|
7f6197ab8b | ||
|
|
4b8196685a | ||
|
|
08c2a0d07b | ||
|
|
1f68fdac8c | ||
|
|
e8d4f0fcf4 | ||
|
|
5d522bd608 | ||
|
|
3894a99bc4 | ||
|
|
9036a2f317 | ||
|
|
c75ab28002 | ||
|
|
62a8320068 | ||
|
|
f21b38f66a | ||
|
|
596765bb52 | ||
|
|
297aafba45 | ||
|
|
a0a682e224 | ||
|
|
d161b11892 | ||
|
|
d70bb243b2 | ||
|
|
301a3efb7c | ||
|
|
05b7cbe20a | ||
|
|
48cbbc1bef | ||
|
|
f8f7c28274 | ||
|
|
0ebb53888a | ||
|
|
c0071c1525 | ||
|
|
71f7b3b3d8 | ||
|
|
bd6d7b7149 | ||
|
|
63de8fe44a |
+20
-2
@@ -54,6 +54,8 @@
|
||||
- `PokemonRecallEvent`
|
||||
- `TradeEvent`
|
||||
- Added a new gamerule, 'healerHealsPC', when set to true a successful use of a healer will also heal all of the Pokemon in that player's PC.
|
||||
- Mooshtanks will switch between their red and brown variant when hit by lightning
|
||||
- Smeargle spawns with differing tail colour depending on its [Characteristic](https://bulbapedia.bulbagarden.net/wiki/Characteristic) stat
|
||||
|
||||
### Pokémon Added
|
||||
|
||||
@@ -474,7 +476,7 @@
|
||||
- Updated `HatchEggEvent.Post` to include the Pokemon that hatched.
|
||||
- Roseli Berry Trees now naturally generate in their preferred biomes.
|
||||
- Refactored dynamic lights compat to be more future proof. The dynamic light support is only tested with LambDynamicLights, on NeoForged use that mod in combination with Sinytra Connector
|
||||
- Shulker Boxes and Traveler's Backpacks can no longer be held by Pokémon. Thanks Monocle ;) You could re-enable this with a datapack but you'd be crazy.
|
||||
- Shulker Boxes and Traveler's Backpacks AND Packed Up backpacks can no longer be held by Pokémon. Thanks Monocle ;) You could re-enable this with our datapack (but you'd be crazy).
|
||||
- Moomoo Milk now clears Pokémon stat changes when used in battle.
|
||||
|
||||
### Fixes
|
||||
@@ -599,10 +601,25 @@
|
||||
- Added a `hoverText` option to PartySelectCallback, to display a tooltip on hovering over a Pokémon in the selection screen.
|
||||
- `PokemonEntity` instances spawned into the world now appropriately finalize the spawn for mod compatibility.
|
||||
- Added PokedexManager.obtain as a replacement for .catch which is not a friendly function name in Java.
|
||||
|
||||
- Added `Pokemon#hyperTrainIV()` and `IVs#setHyperTrainedIV(Stat, Int)`
|
||||
- `ElementalType` now implements `ShowdownIdentifiable` to ensure the communcation with showdown stays consistent (also in regards to TeraTypes)
|
||||
- Pokemon no longer have a change observable
|
||||
- Pokémon can now have a behaviour changing the value of a species feature on lightning hit:
|
||||
```JSON
|
||||
{
|
||||
"behaviour": {
|
||||
"lightningHit": {
|
||||
"rotateFeatures": [
|
||||
{
|
||||
"key": "mooshtank",
|
||||
"chain": ["red", "brown"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
This will change the value of `mooshtank` from `red` to `brown` and vice versa when a lightning strikes this Pokémon. Only chains of which a value is the current value will be considered, so multiple entries for the same key with different chains can be added.
|
||||
|
||||
### MoLang & Datapacks
|
||||
- The following usages for item predicates can now use item conditions like advancements do, you can learn about them in the [Minecraft wiki](https://minecraft.wiki/w/Advancement_definition#minecraft:filled_bucket)
|
||||
@@ -709,6 +726,7 @@
|
||||
- Fixed `cobblemon:reel_in_pokemon` criteria not working when used together with a `baitId`
|
||||
- Also changed the default from `cobblemon:empty_bait` to `any`
|
||||
- The previous default is still available by using the above as baitId
|
||||
- Added support for species-specific move action effects, using the format `{move_id}_{species}.json`.
|
||||
|
||||
### Particles
|
||||
Added new/updated particles for the following moves:
|
||||
|
||||
+2
-1
@@ -17,6 +17,7 @@ import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawner;
|
||||
* @author Hiroku
|
||||
* @since October 27th, 2025
|
||||
*/
|
||||
public interface PlayerSpawnerGetter {
|
||||
public interface PlayerSpawnerAccessor {
|
||||
PlayerSpawner getPlayerSpawner();
|
||||
void setPlayerSpawner(PlayerSpawner spawner);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.duck;
|
||||
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public interface RidePassenger {
|
||||
void cobblemon$setRideXRot(float rideXRot);
|
||||
float cobblemon$getRideXRot();
|
||||
void cobblemon$setRideYRot(float rideYRot);
|
||||
float cobblemon$getRideYRot();
|
||||
void cobblemon$setRideEyePos(Vec3 rideEyePos);
|
||||
Vec3 cobblemon$getRideEyePos();
|
||||
}
|
||||
@@ -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.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.projectile.AbstractArrow;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(AbstractArrow.class)
|
||||
public abstract class AbstractArrowMixin {
|
||||
|
||||
// Target the constructor that takes a LivingEntity owner
|
||||
@Inject(
|
||||
method = "<init>(Lnet/minecraft/world/entity/EntityType;Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/level/Level;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/item/ItemStack;)V",
|
||||
at = @At("TAIL") // Inject at the very end of the constructor
|
||||
)
|
||||
private void cobblemon$adjustSpawnPosition(
|
||||
EntityType<? extends AbstractArrow> entityType,
|
||||
LivingEntity owner,
|
||||
Level level,
|
||||
ItemStack pickupItemStack,
|
||||
@Nullable ItemStack firedFromWeapon,
|
||||
CallbackInfo ci
|
||||
) {
|
||||
AbstractArrow arrow = (AbstractArrow)(Object)this;
|
||||
if(!(owner.getVehicle() instanceof OrientationControllable vehicle)) return;
|
||||
var vehicleController = vehicle.getOrientationController();
|
||||
|
||||
// If this is a rolling ride passenger then use the rider eye position to set the arrow spawn position.
|
||||
if (owner instanceof RidePassenger ridePassenger && vehicleController != null && vehicleController.getActive()) {
|
||||
var eyePos = ridePassenger.cobblemon$getRideEyePos().add(0.0, -2.0, 0.0);
|
||||
arrow.setPos(eyePos);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,18 +8,23 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.api.pokemon.effect.ShoulderEffectRegistry;
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle;
|
||||
import com.cobblemon.mod.common.api.riding.Seat;
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.SubmarineBehaviour;
|
||||
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate;
|
||||
import com.cobblemon.mod.common.client.render.MatrixWrapper;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.net.messages.server.orientation.ServerboundUpdateOrientationPacket;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.ClipContext;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
@@ -32,6 +37,7 @@ import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(LivingEntity.class)
|
||||
public abstract class LivingEntityMixin extends Entity implements OrientationControllable {
|
||||
@@ -55,9 +61,51 @@ public abstract class LivingEntityMixin extends Entity implements OrientationCon
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HitResult pick(double hitDistance, float partialTicks, boolean hitFluids) {
|
||||
Entity vehicle = this.getVehicle();
|
||||
if (vehicle instanceof PokemonEntity pokemonEntity && pokemonEntity.getDelegate() instanceof PokemonClientDelegate delegate) {
|
||||
int seatIndex = pokemonEntity.getPassengers().indexOf(this);
|
||||
Seat seat = pokemonEntity.getSeats().get(seatIndex);
|
||||
MatrixWrapper locator = delegate.getLocatorStates().get(seat.getLocator());
|
||||
|
||||
Vec3 locatorOffset = new Vec3(locator.getMatrix().getTranslation(new Vector3f()));
|
||||
|
||||
Vec3 eyePosition = cobblemon$getEyePosition(partialTicks, pokemonEntity, locatorOffset);
|
||||
|
||||
Vec3 viewVector = this.getViewVector(partialTicks);
|
||||
Vec3 viewDistanceVector = eyePosition.add(viewVector.x * hitDistance, viewVector.y * hitDistance, viewVector.z * hitDistance);
|
||||
|
||||
return this.level()
|
||||
.clip(
|
||||
new ClipContext(
|
||||
eyePosition, viewDistanceVector, ClipContext.Block.OUTLINE, hitFluids ? net.minecraft.world.level.ClipContext.Fluid.ANY : net.minecraft.world.level.ClipContext.Fluid.NONE, this
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return super.pick(hitDistance, partialTicks, hitFluids);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private Vec3 cobblemon$getEyePosition(float partialTicks, PokemonEntity pokemonEntity, Vec3 locatorOffset) {
|
||||
OrientationController controller = this.getOrientationController();
|
||||
|
||||
float currEyeHeight = this.getEyeHeight();
|
||||
Vec3 offset = locatorOffset.add(pokemonEntity.position());
|
||||
if (controller.isActive() && controller.getOrientation() != null) {
|
||||
Quaternionf orientation = controller.getRenderOrientation(partialTicks);
|
||||
Vec3 rotatedEyeHeight = new Vec3(orientation.transform(new Vector3f(0f, currEyeHeight - (this.getBbHeight() / 2), 0f)));
|
||||
|
||||
offset.add(rotatedEyeHeight);
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
@Inject(method = "tick", at = @At("HEAD"))
|
||||
private void cobblemon$updateRenderOrientation(CallbackInfo ci) {
|
||||
this.cobblemon$orientationController.tick();
|
||||
//this.cobblemon$orientationController.tick();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -74,4 +122,31 @@ public abstract class LivingEntityMixin extends Entity implements OrientationCon
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "decreaseAirSupply", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$conditionalWaterBreathing(
|
||||
int currentAir,
|
||||
CallbackInfoReturnable<Integer> cir
|
||||
) {
|
||||
var entity = (LivingEntity) (Object) this;
|
||||
if (!(entity instanceof Player player)) return;
|
||||
if (!(player.getVehicle() instanceof PokemonEntity vehicle)) return;
|
||||
|
||||
var ridingController = vehicle.getRidingController();
|
||||
if (ridingController == null) return;
|
||||
|
||||
var activeContext = ridingController.getContext();
|
||||
if (activeContext == null) return;
|
||||
|
||||
// If the rider is currently on a submarine and the ride still has stamina.
|
||||
var stamina = activeContext.getState().getStamina().get();
|
||||
if (
|
||||
activeContext.getStyle() == RidingStyle.LIQUID &&
|
||||
activeContext.getBehaviour().equals(SubmarineBehaviour.Companion.getKEY()) &&
|
||||
stamina > 0.0f
|
||||
) {
|
||||
cir.setReturnValue(currentAir);
|
||||
cir.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.cobblemon.mod.common.api.storage.party.PartyStore;
|
||||
import com.cobblemon.mod.common.api.storage.party.PlayerPartyStore;
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags;
|
||||
import com.cobblemon.mod.common.duck.PlayerDuck;
|
||||
import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.pokedex.scanner.PokedexEntityData;
|
||||
import com.cobblemon.mod.common.pokedex.scanner.ScannableEntity;
|
||||
@@ -47,6 +48,7 @@ import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.food.FoodProperties;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.joml.Vector3f;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
@@ -63,7 +65,7 @@ import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Mixin(Player.class)
|
||||
public abstract class PlayerMixin extends LivingEntity implements ScannableEntity, OrientationControllable, PlayerDuck {
|
||||
public abstract class PlayerMixin extends LivingEntity implements ScannableEntity, OrientationControllable, PlayerDuck, RidePassenger {
|
||||
|
||||
@Unique
|
||||
private Vector3f cobblemon$driverInput;
|
||||
@@ -91,6 +93,12 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
@Shadow protected int jumpTriggerTime;
|
||||
@Unique private final OrientationController cobblemon$orientationController = new OrientationController(this);
|
||||
|
||||
@Unique private float cobblemon$rideXRot = 0.0f;
|
||||
|
||||
@Unique private float cobblemon$rideYRot = 0.0f;
|
||||
|
||||
@Unique private Vec3 cobblemon$rideEyePos = Vec3.ZERO;
|
||||
|
||||
protected PlayerMixin(EntityType<? extends LivingEntity> p_20966_, Level p_20967_) {
|
||||
super(p_20966_, p_20967_);
|
||||
}
|
||||
@@ -117,11 +125,6 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "tick", at = @At("HEAD"))
|
||||
private void cobblemon$updateRenderOrientation(CallbackInfo ci) {
|
||||
this.cobblemon$orientationController.tick();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityDimensions getDefaultDimensions(Pose pose) {
|
||||
if (this.getVehicle() instanceof PokemonEntity) {
|
||||
@@ -307,4 +310,34 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
return cobblemon$lastSentDriverInput;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float cobblemon$getRideXRot() {
|
||||
return this.cobblemon$rideXRot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$setRideXRot(float rideXRot) {
|
||||
this.cobblemon$rideXRot = rideXRot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float cobblemon$getRideYRot() {
|
||||
return this.cobblemon$rideYRot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$setRideYRot(float rideYRot) {
|
||||
this.cobblemon$rideYRot = rideYRot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3 cobblemon$getRideEyePos() {
|
||||
return this.cobblemon$rideEyePos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$setRideEyePos(Vec3 rideEyePos) {
|
||||
this.cobblemon$rideEyePos = rideEyePos;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.PlayerSpawnerGetter;
|
||||
import com.cobblemon.mod.common.PlayerSpawnerAccessor;
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawner;
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawnerFactory;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
@@ -28,7 +28,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ServerPlayer.class)
|
||||
public abstract class ServerPlayerMixin implements PlayerSpawnerGetter {
|
||||
public abstract class ServerPlayerMixin implements PlayerSpawnerAccessor {
|
||||
@Shadow
|
||||
public abstract ServerLevel serverLevel();
|
||||
|
||||
@@ -44,6 +44,11 @@ public abstract class ServerPlayerMixin implements PlayerSpawnerGetter {
|
||||
return cobblemon$spawner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerSpawner(PlayerSpawner spawner) {
|
||||
this.cobblemon$spawner = spawner;
|
||||
}
|
||||
|
||||
@Inject(method = "tick", at = @At("TAIL"))
|
||||
private void cobblemon$tickSpawner(CallbackInfo ci) {
|
||||
if (!Cobblemon.config.getEnableSpawning()) {
|
||||
@@ -56,16 +61,17 @@ public abstract class ServerPlayerMixin implements PlayerSpawnerGetter {
|
||||
|
||||
@Inject(method = "rideTick", at = @At("HEAD"))
|
||||
private void cobblemon$updateOrientationControllerRideTick(CallbackInfo ci) {
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
var shouldUseCustomOrientation = cobblemon$shouldUseCustomOrientation((ServerPlayer)(Object)this);
|
||||
controllable.getOrientationController().setActive(shouldUseCustomOrientation);
|
||||
ServerPlayer player = (ServerPlayer)(Object)this;
|
||||
Entity vehicle = player.getVehicle();
|
||||
if (!(vehicle instanceof OrientationControllable controllableVehicle)) return;
|
||||
var shouldUseCustomOrientation = cobblemon$shouldUseCustomOrientation(vehicle);
|
||||
controllableVehicle.getOrientationController().setActive(shouldUseCustomOrientation);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private boolean cobblemon$shouldUseCustomOrientation(ServerPlayer player) {
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return false;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return false;
|
||||
private boolean cobblemon$shouldUseCustomOrientation(Entity entity) {
|
||||
if (entity == null) return false;
|
||||
if (!(entity instanceof PokemonEntity pokemonEntity)) return false;
|
||||
return pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) -> {
|
||||
return behaviour.shouldRoll(settings, state, pokemonEntity);
|
||||
});
|
||||
@@ -73,8 +79,9 @@ public abstract class ServerPlayerMixin implements PlayerSpawnerGetter {
|
||||
|
||||
@Inject(method = "stopRiding", at = @At("HEAD"))
|
||||
public void cobblemon$resetOrientationOnDismount(CallbackInfo ci) {
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
controllable.getOrientationController().setActive(false);
|
||||
ServerPlayer player = (ServerPlayer)(Object)this;
|
||||
if (!(player.getVehicle() instanceof OrientationControllable controllableVehicle)) return;
|
||||
controllableVehicle.getOrientationController().setActive(false);
|
||||
}
|
||||
|
||||
//TODO: Switch to sending out on load instead of preventing saving
|
||||
|
||||
+2
-1
@@ -34,7 +34,8 @@ public class AbstractClientPlayerMixin {
|
||||
} else {
|
||||
// Only modify fov through riding if the pokedex is not open
|
||||
LocalPlayer player = (LocalPlayer) (Object) this;
|
||||
if (player != null && player.isPassenger() && player.getVehicle() instanceof PokemonEntity) {
|
||||
// Only modify fov for the driver and not the passengers
|
||||
if (player != null && player.isPassenger() && player.getVehicle() instanceof PokemonEntity && player.getVehicle().getControllingPassenger() == player) {
|
||||
PokemonEntity ride = (PokemonEntity) player.getVehicle();
|
||||
|
||||
// Return custom fov mult for riding
|
||||
|
||||
@@ -14,12 +14,15 @@ import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.api.riding.Rideable;
|
||||
import com.cobblemon.mod.common.client.MountedPokemonAnimationRenderController;
|
||||
import com.cobblemon.mod.common.client.render.camera.MountedCameraRenderer;
|
||||
import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import com.mojang.blaze3d.Blaze3D;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.joml.Matrix3f;
|
||||
@@ -48,45 +51,44 @@ public abstract class CameraMixin {
|
||||
|
||||
@Shadow protected abstract void setPosition(Vec3 pos);
|
||||
|
||||
@Unique private float returnTimer = 0;
|
||||
@Unique private float rollAngleStart = 0;
|
||||
@Unique Minecraft minecraft = Minecraft.getInstance();
|
||||
@Shadow private float partialTickTime;
|
||||
|
||||
// Used to help in camera rotation rendering when transitioning
|
||||
// from rolled to unrolled.
|
||||
@Unique private float cobblemon$returnTimer = 0;
|
||||
@Unique private float cobblemon$rollAngleStart = 0;
|
||||
|
||||
@Unique private double cobblemon$lastHandledRotationTime = Double.MIN_VALUE;
|
||||
@Unique private double cobblemon$frameTime = 0.0;
|
||||
|
||||
@Inject(method = "setRotation", at = @At("HEAD"), cancellable = true)
|
||||
|
||||
public void cobblemon$setRotation(float f, float g, CallbackInfo ci) {
|
||||
if (!(this.entity instanceof OrientationControllable controllable)) return;
|
||||
var controller = controllable.getOrientationController();
|
||||
if (!controller.isActive() && controller.getOrientation() != null) {
|
||||
if(this.returnTimer < 1) {
|
||||
//Rotation is taken from entity since we no longer handle mouse ourselves
|
||||
//Stops a period of time when you can't input anything.
|
||||
controller.getOrientation().set(
|
||||
new Matrix3f()
|
||||
.rotateY((float) Math.toRadians(180 - this.entity.getYRot()))
|
||||
.rotateX((float) Math.toRadians(-this.entity.getXRot()))
|
||||
);
|
||||
if(rollAngleStart == 0){
|
||||
this.returnTimer = 1;
|
||||
controller.reset();
|
||||
return;
|
||||
}
|
||||
controller.getOrientation().rotateZ((float) Math.toRadians(-rollAngleStart*(1-returnTimer)));
|
||||
cobblemon$applyRotation();
|
||||
this.returnTimer += .05F;
|
||||
ci.cancel();
|
||||
} else {
|
||||
this.returnTimer = 1;
|
||||
controller.reset();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (controller.getOrientation() == null) return;
|
||||
cobblemon$applyRotation();
|
||||
// Calculate the current frametime
|
||||
double d = Blaze3D.getTime();
|
||||
this.cobblemon$frameTime = (this.cobblemon$lastHandledRotationTime != Double.MIN_VALUE) ? d - this.cobblemon$lastHandledRotationTime : 0.0;
|
||||
this.cobblemon$lastHandledRotationTime = d;
|
||||
|
||||
this.returnTimer = 0;
|
||||
this.rollAngleStart = controller.getRoll();
|
||||
ci.cancel();
|
||||
// Don't assume the camera to be attached to an entity. Ponder Scenes from create et.al. for example aren't.
|
||||
if (this.entity == null) return;
|
||||
var vehicle = this.entity.getVehicle();
|
||||
if (!(vehicle instanceof OrientationControllable controllableVehicle)) return;
|
||||
var instance = (Camera)(Object)this;
|
||||
|
||||
// If the current vehicle has no orientation then return and perform
|
||||
// vanilla camera rotations
|
||||
var vehicleController = controllableVehicle.getOrientationController();
|
||||
if (vehicleController.getOrientation() == null) return;
|
||||
|
||||
// If the controller has been deactivated but the orientation isn't null yet
|
||||
// then perform transition from rolled ride/camera to vanilla
|
||||
if (!vehicleController.isActive() && vehicleController.getOrientation() != null) {
|
||||
cobblemon$applyTransitionRotation(vehicleController, ci);
|
||||
} else { // Otherwise perform cobblemon specific camera rotation and set transition helper variables
|
||||
cobblemon$applyRotation();
|
||||
this.cobblemon$returnTimer = 0;
|
||||
this.cobblemon$rollAngleStart = instance.rotation().getEulerAnglesYXZ(new Vector3f()).z();
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@WrapOperation(method = "setup", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;setPosition(DDD)V"))
|
||||
@@ -119,20 +121,128 @@ public abstract class CameraMixin {
|
||||
|
||||
@Unique
|
||||
private void cobblemon$applyRotation(){
|
||||
if (!(this.entity instanceof OrientationControllable controllable) || controllable.getOrientationController().getOrientation() == null) return;
|
||||
var controller = controllable.getOrientationController();
|
||||
var newRotation = controller.getOrientation().normal(new Matrix3f()).getNormalizedRotation(new Quaternionf());
|
||||
if (this.minecraft.options.getCameraType().isMirrored()) {
|
||||
var driver = this.entity;
|
||||
if (!(driver.getVehicle() instanceof OrientationControllable controllableVehicle) ||
|
||||
controllableVehicle.getOrientationController().getOrientation() == null ||
|
||||
!controllableVehicle.getOrientationController().getActive()
|
||||
) return;
|
||||
|
||||
// Grab the driver and vehicle orientation controllers.
|
||||
var vehicleController = controllableVehicle.getOrientationController();
|
||||
|
||||
var isDriving = driver.getControlledVehicle() != null;
|
||||
|
||||
// Grab the ride orientation
|
||||
var newRotation = new Quaternionf();
|
||||
|
||||
// If the player is driving then use the current orientation since the driver sets it.
|
||||
// If not then use the smoothed render orientation for passengers otherwise the vehicle rotation will be jerky
|
||||
if (isDriving) {
|
||||
newRotation = vehicleController.getOrientation().normal(new Matrix3f()).getNormalizedRotation(new Quaternionf());
|
||||
} else {
|
||||
newRotation = vehicleController.getRenderOrientation(this.partialTickTime);
|
||||
}
|
||||
|
||||
// Unroll the current rotation if no roll is requested
|
||||
if (Cobblemon.config.getDisableRoll()) {
|
||||
var eulerAngs = newRotation.getEulerAnglesYXZ(new Vector3f());
|
||||
var currAngs = this.rotation.getEulerAnglesYXZ(new Vector3f());
|
||||
var vehicle = (PokemonEntity)driver.getVehicle();
|
||||
var vel = vehicle.getRidingAnimationData().getVelocitySpring().getInterpolated(this.partialTickTime, 0);
|
||||
|
||||
// lerp the new rotation towards this y rot at a rate proportional to the horizontal movement speed?
|
||||
var yaw = Mth.wrapDegrees(Math.toDegrees(Mth.atan2(vel.x(), vel.z())) + 180.0f);
|
||||
|
||||
var degDiff = Mth.degreesDifference((float)Math.toDegrees(currAngs.y()), (float)yaw);
|
||||
var pitchDeadzoneDeg = 15.0; // x degrees of deadzone about +-90 degrees of pitch.
|
||||
var pitchDeg = vehicleController.getPitch();
|
||||
// ConsiderPitch to be already 90 if within the deadzone around it.
|
||||
var cutoffPitch = Math.min(1.0,(Mth.abs(pitchDeg) / (90.0f - pitchDeadzoneDeg))) * 90.0f * Math.signum(pitchDeg);
|
||||
var lerpRateMod = Mth.cos((float)Math.toRadians(cutoffPitch));
|
||||
|
||||
// Apply smoothing from the cameras current yaw to the yaw of the velocity vector of the ride.
|
||||
var k = 5.0f; // Some smoothing constant k
|
||||
var smoothingFactor = lerpRateMod * cobblemon$frameTime * k;
|
||||
var newYaw = currAngs.y() + (Math.toRadians(degDiff) * smoothingFactor);
|
||||
|
||||
newRotation.set(new Quaternionf().rotateYXZ((float)newYaw, eulerAngs.x(), 0.0f));
|
||||
}
|
||||
|
||||
var rotationOffset = 0;
|
||||
if (Minecraft.getInstance().options.getCameraType().isMirrored()) {
|
||||
newRotation.rotateY((float)Math.toRadians(180));
|
||||
rotationOffset = 180;
|
||||
}
|
||||
|
||||
// Get the drivers local look angle in relation to the ride and apply it.
|
||||
if (vehicleController.getActive()) {
|
||||
var vehicleMatrix = new Matrix3f().set(newRotation);
|
||||
var driverMatrix = new Matrix3f();// Base the driver
|
||||
var playerRotater = (RidePassenger)driver;
|
||||
newRotation = vehicleMatrix.mul(
|
||||
driverMatrix.rotateYXZ(
|
||||
-Mth.DEG_TO_RAD * (playerRotater.cobblemon$getRideYRot()),
|
||||
-Mth.DEG_TO_RAD * playerRotater.cobblemon$getRideXRot(),
|
||||
0.0f)
|
||||
).normal(new Matrix3f()).getNormalizedRotation(new Quaternionf());
|
||||
}
|
||||
this.rotation.set(newRotation);
|
||||
this.xRot = controller.getPitch();
|
||||
this.yRot = controller.getYaw();
|
||||
var eulerAngs = newRotation.getEulerAnglesXYZ(new Vector3f());
|
||||
this.xRot = eulerAngs.x() * Mth.RAD_TO_DEG;
|
||||
this.yRot = eulerAngs.y() * Mth.RAD_TO_DEG;
|
||||
// Set the drivers rotations to match
|
||||
var driverEulerAngs = new Quaternionf(this.rotation).getEulerAnglesYXZ(new Vector3f());
|
||||
driver.setXRot(-driverEulerAngs.x() * Mth.RAD_TO_DEG + rotationOffset);
|
||||
driver.setYRot(180.0f - (driverEulerAngs.y() * Mth.RAD_TO_DEG));
|
||||
|
||||
OrientationController.Companion.getFORWARDS().rotate(this.rotation, this.forwards);
|
||||
OrientationController.Companion.getUP().rotate(this.rotation, this.up);
|
||||
OrientationController.Companion.getLEFT().rotate(this.rotation, this.left);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private void cobblemon$applyTransitionRotation(
|
||||
OrientationController vehicleController,
|
||||
CallbackInfo ci
|
||||
) {
|
||||
// If the transition has just started then
|
||||
if (this.cobblemon$returnTimer == 0.0) {
|
||||
MountedCameraRenderer.INSTANCE.resetDriverRotations((Camera)(Object)this, this.entity);
|
||||
}
|
||||
|
||||
if(this.cobblemon$returnTimer < 1) {
|
||||
//Rotation is taken from entity since we no longer handle mouse ourselves
|
||||
//Stops a period of time when you can't input anything.
|
||||
float interpolatedRoll = Mth.lerp(this.cobblemon$returnTimer, this.cobblemon$rollAngleStart, 0.0f);
|
||||
float pitch = (float) Math.toRadians(-this.entity.getXRot());
|
||||
float yaw = (float) Math.toRadians(180 - this.entity.getYRot());
|
||||
|
||||
Quaternionf interRot = new Quaternionf();
|
||||
interRot.rotationYXZ(yaw, pitch, interpolatedRoll);
|
||||
|
||||
this.rotation.set(interRot);
|
||||
var eulerAngs = interRot.getEulerAnglesXYZ(new Vector3f());
|
||||
this.xRot = eulerAngs.x() * Mth.RAD_TO_DEG;
|
||||
this.yRot = eulerAngs.y() * Mth.RAD_TO_DEG;
|
||||
OrientationController.Companion.getFORWARDS().rotate(this.rotation, this.forwards);
|
||||
OrientationController.Companion.getUP().rotate(this.rotation, this.up);
|
||||
OrientationController.Companion.getLEFT().rotate(this.rotation, this.left);
|
||||
|
||||
if(cobblemon$rollAngleStart == 0){
|
||||
this.cobblemon$returnTimer = 1;
|
||||
vehicleController.reset();
|
||||
MountedCameraRenderer.INSTANCE.resetDriverRotations((Camera)(Object)this, this.entity);
|
||||
return;
|
||||
}
|
||||
this.cobblemon$returnTimer += (partialTickTime * (1.0f/20.0f));
|
||||
ci.cancel();
|
||||
} else {
|
||||
this.cobblemon$returnTimer = 1;
|
||||
vehicleController.reset();
|
||||
MountedCameraRenderer.INSTANCE.resetDriverRotations((Camera)(Object)this, this.entity);
|
||||
}
|
||||
}
|
||||
|
||||
@WrapOperation(method = "setup", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;move(FFF)V", ordinal = 0))
|
||||
public void stopMoveIfRolling(Camera instance, float zoom, float dy, float dx, Operation<Void> original) {
|
||||
Entity entity = instance.getEntity();
|
||||
|
||||
@@ -19,9 +19,11 @@ import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState;
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PosableModel;
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.VaryingModelRepository;
|
||||
import com.cobblemon.mod.common.duck.PlayerDuck;
|
||||
import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.net.messages.server.orientation.ServerboundUpdateOrientationPacket;
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateDriverInputPacket;
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateRiderRotationPacket;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import net.minecraft.client.CameraType;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@@ -29,12 +31,10 @@ import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.player.Input;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.ClipContext;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -55,6 +55,10 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
|
||||
|
||||
@Unique Matrix3f cobblemon$lastOrientation;
|
||||
|
||||
@Unique float cobblemon$lastRideXRot;
|
||||
@Unique float cobblemon$lastRideYRot;
|
||||
@Unique Vec3 cobblemon$lastRideEyePos;
|
||||
|
||||
@Unique boolean cobblemon$isDoubleJumping = false;
|
||||
|
||||
@Shadow
|
||||
@@ -72,30 +76,35 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
|
||||
super(clientLevel, gameProfile);
|
||||
}
|
||||
|
||||
// @Inject(method = "sendPosition", at = @At("TAIL"))
|
||||
// private void cobblemon$updateRotationMatrix(CallbackInfo ci) {
|
||||
// if (!(this instanceof OrientationControllable controllable)) return;
|
||||
// var controller = controllable.getOrientationController();
|
||||
// if (!controller.isActive() || controller.getOrientation() == cobblemon$lastOrientation) return;
|
||||
// cobblemon$lastOrientation = controller.getOrientation() != null ? new Matrix3f(controller.getOrientation()) : null;
|
||||
// CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateOrientationPacket(controller.getOrientation()));
|
||||
// }
|
||||
|
||||
@Inject(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/ClientPacketListener;send(Lnet/minecraft/network/protocol/Packet;)V"))
|
||||
private void cobblemon$updateRotationMatrixPassenger(CallbackInfo ci) {
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
var controller = controllable.getOrientationController();
|
||||
if (!controller.isActive() || controller.getOrientation() == cobblemon$lastOrientation) return;
|
||||
cobblemon$lastOrientation = controller.getOrientation() != null ? new Matrix3f(controller.getOrientation()) : null;
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateOrientationPacket(controller.getOrientation()));
|
||||
if (!(this.getVehicle() instanceof OrientationControllable controllableVehicle)) return;
|
||||
var vehicleController = controllableVehicle.getOrientationController();
|
||||
if (!vehicleController.isActive() || vehicleController.getOrientation() == cobblemon$lastOrientation) return;
|
||||
cobblemon$lastOrientation = vehicleController.getOrientation() != null ? new Matrix3f(vehicleController.getOrientation()) : null;
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateOrientationPacket(this.getVehicle().getId(), vehicleController.getOrientation()));
|
||||
}
|
||||
|
||||
@Inject(method = "rideTick", at = @At("HEAD"))
|
||||
private void cobblemon$updateOrientationControllerRideTick(CallbackInfo ci) {
|
||||
if (Minecraft.getInstance().player != (Object)this) return;
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
var driver = (LocalPlayer)(Object)this;
|
||||
var vehicle = driver.getVehicle();
|
||||
if (!(this.getVehicle() instanceof OrientationControllable controllableVehicle)) return;
|
||||
var shouldUseCustomOrientation = cobblemon$shouldUseCustomOrientation((LocalPlayer)(Object)this);
|
||||
controllable.getOrientationController().setActive(shouldUseCustomOrientation);
|
||||
var vehicleController = controllableVehicle.getOrientationController();
|
||||
|
||||
// If the player has just switched to riding a custom orientation ride then set their
|
||||
// x and y rots local to the vehicle rots(if the controller wasn't active and will now be active)
|
||||
// This ensures that on transition your camera stays in the same spot
|
||||
if (!vehicleController.isActive() && shouldUseCustomOrientation) {
|
||||
// Set local to the vehicle x and yrot so
|
||||
var playerRotater = (RidePassenger)driver;
|
||||
playerRotater.cobblemon$setRideXRot(Mth.wrapDegrees(driver.getXRot() - vehicle.getXRot()));
|
||||
playerRotater.cobblemon$setRideYRot(Mth.wrapDegrees(driver.getYRot() - vehicle.getYRot()));
|
||||
}
|
||||
|
||||
vehicleController.setActive(shouldUseCustomOrientation);
|
||||
}
|
||||
|
||||
@Inject(method = "rideTick", at = @At("HEAD"))
|
||||
@@ -115,6 +124,40 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateDriverInputPacket(driverInput));
|
||||
}
|
||||
|
||||
@Inject(method = "rideTick", at = @At("HEAD"))
|
||||
private void cobblemon$updateRiderRotationsRideTick(CallbackInfo ci) {
|
||||
if (Minecraft.getInstance().player != (Object)this) return;
|
||||
if (!(this.getVehicle() instanceof PokemonEntity pokemonEntity)) return;
|
||||
|
||||
// Only send rotation updates if the player is riding a vehicle that is currently rollable
|
||||
if (!(this.getVehicle() instanceof OrientationControllable controllableVehicle)) return;
|
||||
if (!controllableVehicle.getOrientationController().getActive()) return;
|
||||
|
||||
var passenger = (LocalPlayer)(Object)this;
|
||||
var playerRotater = (RidePassenger)passenger;
|
||||
|
||||
// Gather Rider Rotation info
|
||||
var rideXRot = playerRotater.cobblemon$getRideXRot();
|
||||
var rideYRot = playerRotater.cobblemon$getRideYRot();
|
||||
var rideEyePos = playerRotater.cobblemon$getRideEyePos();
|
||||
|
||||
// Check for a change in the values before sending them.
|
||||
if (cobblemon$lastRideXRot != rideXRot ||
|
||||
cobblemon$lastRideYRot != rideYRot ||
|
||||
cobblemon$lastRideEyePos != rideEyePos
|
||||
) {
|
||||
|
||||
// Update 'last' values
|
||||
cobblemon$lastRideXRot = rideXRot;
|
||||
cobblemon$lastRideYRot = rideYRot;
|
||||
cobblemon$lastRideEyePos = rideEyePos;
|
||||
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateRiderRotationPacket(rideXRot, rideYRot, rideEyePos));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Unique
|
||||
private boolean cobblemon$shouldUseCustomOrientation(LocalPlayer player) {
|
||||
var playerVehicle = player.getVehicle();
|
||||
@@ -129,8 +172,8 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
|
||||
public void stopRiding() {
|
||||
super.stopRiding();
|
||||
if (Minecraft.getInstance().player != (Object)this) return;
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
controllable.getOrientationController().setActive(false);
|
||||
if (!(this instanceof OrientationControllable controllableVehicle)) return;
|
||||
controllableVehicle.getOrientationController().setActive(false);
|
||||
}
|
||||
|
||||
@Inject(method = "getJumpRidingScale", at = @At("HEAD"), cancellable = true)
|
||||
|
||||
@@ -10,13 +10,16 @@ package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.client.CobblemonClient;
|
||||
import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding;
|
||||
import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
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 kotlin.Pair;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.MouseHandler;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
@@ -32,6 +35,9 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import static com.google.common.primitives.Floats.min;
|
||||
import static net.minecraft.util.Mth.lerp;
|
||||
|
||||
@Mixin(MouseHandler.class)
|
||||
public abstract class MouseHandlerMixin {
|
||||
@Shadow private double accumulatedScrollY;
|
||||
@@ -117,8 +123,6 @@ public abstract class MouseHandlerMixin {
|
||||
@Local(argsOnly = true) double d,
|
||||
@Local(argsOnly = true) double movementTime
|
||||
) {
|
||||
boolean returnValue = true;
|
||||
|
||||
PokedexUsageContext usageContext = CobblemonClient.INSTANCE.getPokedexUsageContext();
|
||||
if (usageContext.getScanningGuiOpen()) {
|
||||
this.smoothTurnY.reset();
|
||||
@@ -126,34 +130,78 @@ public abstract class MouseHandlerMixin {
|
||||
var defaultSensitivity = this.minecraft.options.sensitivity().get() * 0.6 + 0.2;
|
||||
var spyglassSensitivity = Math.pow(defaultSensitivity, 3);
|
||||
var lookSensitivity = spyglassSensitivity * 8.0;
|
||||
var sensitivity = Mth.lerp(usageContext.getFovMultiplier(), spyglassSensitivity, lookSensitivity);
|
||||
var sensitivity = lerp(usageContext.getFovMultiplier(), spyglassSensitivity, lookSensitivity);
|
||||
var yRotationFlip = this.minecraft.options.invertYMouse().get() ? -1 : 1;
|
||||
player.turn(this.accumulatedDX * sensitivity, (this.accumulatedDY * sensitivity * yRotationFlip));
|
||||
returnValue = false;
|
||||
}
|
||||
|
||||
var vehicle = player.getVehicle();
|
||||
if (!(vehicle instanceof PokemonEntity)) return true;
|
||||
|
||||
// Clamp player rotation if riding and the vehicle demands it
|
||||
if (player.isPassenger() && player.getVehicle() instanceof PokemonEntity vehicle) {
|
||||
vehicle.clampPassengerRotation(player);
|
||||
if (player.isPassenger() && vehicle instanceof PokemonEntity pokeVehicle) {
|
||||
pokeVehicle.clampPassengerRotation(player);
|
||||
}
|
||||
|
||||
if (!(player instanceof OrientationControllable controllable)) return true;
|
||||
|
||||
if (!controllable.getOrientationController().isActive()) {
|
||||
// If the ride is not orientation controllable then return and perform the normal turnPlayer logic
|
||||
if (!(vehicle instanceof OrientationControllable controllableVehicle) || !controllableVehicle.getOrientationController().isActive()) {
|
||||
xMouseSmoother.reset();
|
||||
yMouseSmoother.reset();
|
||||
pitchSmoother.reset();
|
||||
rollSmoother.reset();
|
||||
yawSmoother.reset();
|
||||
return returnValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Send mouse input to be interpreted into rotation
|
||||
// deltas by the ride controller
|
||||
var vehicleController = controllableVehicle.getOrientationController();
|
||||
var lookaroundButtonPressed = Minecraft.getInstance().mouseHandler.isMiddlePressed();
|
||||
Pair<Boolean, Boolean> mouseShouldModifyDriver = ((PokemonEntity) vehicle).ifRidingAvailableSupply(new Pair(false, false), (behaviour, settings, state) -> {
|
||||
return behaviour.mouseModifiesDriverRotation(
|
||||
settings,
|
||||
state,
|
||||
(PokemonEntity) vehicle
|
||||
);
|
||||
});
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// If looking around then modify the players orientation instead and zero the mouse deltas so the mouse doesn't
|
||||
// affect the vehicle orientation when looking around.
|
||||
// If the client is a passenger it will modify these rotations and return
|
||||
//-------------------------------------------------------------------------
|
||||
if (lookaroundButtonPressed || player.getControlledVehicle() == null) {
|
||||
// Modify driver rotations
|
||||
cobblemon$setDriverRotations(player, cursorDeltaX, cursorDeltaY);
|
||||
|
||||
// If the player/passenger is not the driver then return and ignore all vehicle rotation logic
|
||||
if (player.getControlledVehicle() == null) return false;
|
||||
|
||||
// Set to zero so that vehicle rotations don't also get affected by movement.
|
||||
cursorDeltaX = 0.0;
|
||||
cursorDeltaY = 0.0;
|
||||
} else if (mouseShouldModifyDriver.getFirst()) { // If not freelooking then check modification per mouse input dimension
|
||||
cobblemon$setDriverRotations(player, cursorDeltaX, 0.0);
|
||||
cursorDeltaX = 0.0;
|
||||
} else if (mouseShouldModifyDriver.getSecond()) {
|
||||
cobblemon$setDriverRotations(player, 0.0, cursorDeltaY);
|
||||
cursorDeltaY = 0.0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Smoothly return driver rotations to zero when needed
|
||||
//-------------------------------------------------------------------------
|
||||
var playerRotater = (RidePassenger)player;
|
||||
if( !lookaroundButtonPressed && !mouseShouldModifyDriver.getFirst()){
|
||||
playerRotater.cobblemon$setRideYRot(lerp(min(5.0f * (float)movementTime, 1.0f), Mth.wrapDegrees(playerRotater.cobblemon$getRideYRot()), 0.0f));
|
||||
}
|
||||
if( !lookaroundButtonPressed && !mouseShouldModifyDriver.getSecond()) {
|
||||
playerRotater.cobblemon$setRideXRot(lerp(min(5.0f * (float)movementTime, 1.0f), Mth.wrapDegrees(playerRotater.cobblemon$getRideXRot()), 0.0f));
|
||||
}
|
||||
|
||||
// Send mouse input to be interpreted into rotation deltas by the ride controller
|
||||
Vec3 angVecMouse = cobblemon$getRideMouseRotation(cursorDeltaX, cursorDeltaY, movementTime);
|
||||
|
||||
// Perform Rotation using mouse influenced rotation deltas.
|
||||
controllable.getOrientationController().rotate(
|
||||
vehicleController.rotate(
|
||||
(float) angVecMouse.x,
|
||||
(float) angVecMouse.y,
|
||||
(float) angVecMouse.z
|
||||
@@ -163,17 +211,16 @@ public abstract class MouseHandlerMixin {
|
||||
var angRot = cobblemon$getAngularVelocity(movementTime);
|
||||
|
||||
// Apply smoothing if requested by the controller.
|
||||
// This Might be best if done by the controller itself?
|
||||
if(cobblemon$shouldUseAngVelSmoothing()) {
|
||||
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);
|
||||
controllable.getOrientationController().rotate((float) yaw, (float) pitch, (float) roll);
|
||||
vehicleController.rotate((float) yaw, (float) pitch, (float) roll);
|
||||
}
|
||||
// Otherwise simply apply the smoothing
|
||||
else {
|
||||
controllable.getOrientationController().rotate((float) (angRot.x * 10 * d), (float) (angRot.y * 10 * d), (float) (angRot.z * 10 * d));
|
||||
vehicleController.rotate((float) (angRot.x * 10 * d), (float) (angRot.y * 10 * d), (float) (angRot.z * 10 * d));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -186,10 +233,11 @@ public abstract class MouseHandlerMixin {
|
||||
@Inject(method = "handleAccumulatedMovement", at = @At("TAIL"))
|
||||
private void cobblemon$maintainMovementWhenInScreens(CallbackInfo ci) {
|
||||
if (minecraft.player == null) return;
|
||||
if (!(minecraft.player instanceof OrientationControllable controllable)) return;
|
||||
if (!controllable.getOrientationController().isActive()) return;
|
||||
if (!(minecraft.player.getVehicle() instanceof OrientationControllable vehicleControllable)) return;
|
||||
if (!(vehicleControllable.getOrientationController() instanceof OrientationController vehicleController)) return;
|
||||
if (vehicleController.getOrientation() == null) return;
|
||||
if (minecraft.isPaused()) return;
|
||||
if (isMouseGrabbed()) return;
|
||||
if (this.isMouseGrabbed()) return; // return if turnPlayer() has already run this pass
|
||||
|
||||
this.turnPlayer(cobblemon$timeDelta);
|
||||
}
|
||||
@@ -251,6 +299,20 @@ public abstract class MouseHandlerMixin {
|
||||
return Math.pow(sensitivity, 3);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private void cobblemon$setDriverRotations(LocalPlayer player, double cursorDeltaX, double cursorDeltaY) {
|
||||
// the vanilla turn() method redone so that it uses rideRotations.
|
||||
float f = (float)cursorDeltaY * 0.15F; // Note: turn() uses xRot for pitch (up/down)
|
||||
float g = (float)cursorDeltaX * 0.15F; // Note: turn() uses yRot for yaw (left/right)
|
||||
var playerRotater = (RidePassenger)player;
|
||||
playerRotater.cobblemon$setRideXRot(playerRotater.cobblemon$getRideXRot() + f);
|
||||
playerRotater.cobblemon$setRideYRot(playerRotater.cobblemon$getRideYRot() + g);
|
||||
playerRotater.cobblemon$setRideXRot(Mth.clamp(playerRotater.cobblemon$getRideXRot(), -90.0F, 90.0F));
|
||||
if (player.getVehicle() != null) {
|
||||
player.getVehicle().onPassengerTurned(player);
|
||||
}
|
||||
}
|
||||
|
||||
@Unique
|
||||
private boolean cobblemon$shouldUseAngVelSmoothing() {
|
||||
var player = minecraft.player;
|
||||
|
||||
@@ -8,20 +8,24 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin.entity;
|
||||
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(Entity.class)
|
||||
public abstract class EntityMixin {
|
||||
@@ -57,5 +61,46 @@ public abstract class EntityMixin {
|
||||
return original.call(entity);
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "getEyePosition(F)Lnet/minecraft/world/phys/Vec3;",
|
||||
at = @At("HEAD"),
|
||||
cancellable = true
|
||||
)
|
||||
private void cobblemon$modifyEyePosition_partial(float partialTicks, CallbackInfoReturnable<Vec3> cir) {
|
||||
var entity = (Entity)(Object)this;
|
||||
if (!(entity instanceof Player player)) return;
|
||||
if (!(player instanceof RidePassenger ridePassenger)) return;
|
||||
if (!(player.getVehicle() instanceof OrientationControllable vehicle)) return;
|
||||
var vehicleController = vehicle.getOrientationController();
|
||||
if (vehicleController == null) return;
|
||||
|
||||
// If Orientation is currently being controlled then use the stored eye position from camera positioning.
|
||||
if (vehicleController.getActive() && vehicleController.getOrientation() != null) {
|
||||
// TODO: Determine if it needs partialtick involved.
|
||||
Vec3 customEyePos = ridePassenger.cobblemon$getRideEyePos();
|
||||
cir.setReturnValue(customEyePos);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "getEyePosition()Lnet/minecraft/world/phys/Vec3;",
|
||||
at = @At("HEAD"),
|
||||
cancellable = true
|
||||
)
|
||||
private void cobblemon$modifyEyePosition_noPartial(CallbackInfoReturnable<Vec3> cir) {
|
||||
var entity = (Entity)(Object)this;
|
||||
if (!(entity instanceof Player player)) return;
|
||||
if (!(player instanceof RidePassenger ridePassenger)) return;
|
||||
if (!(player.getVehicle() instanceof OrientationControllable vehicle)) return;
|
||||
var vehicleController = vehicle.getOrientationController();
|
||||
if (vehicleController == null) return;
|
||||
|
||||
// If Orientation is currently being controlled then use the stored eye position from camera positioning.
|
||||
if (vehicleController.getActive() && vehicleController.getOrientation() != null) {
|
||||
// TODO: Determine if it needs partialtick involved.
|
||||
Vec3 customEyePos = ridePassenger.cobblemon$getRideEyePos();
|
||||
cir.setReturnValue(customEyePos);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ import com.cobblemon.mod.common.net.messages.client.settings.ServerSettingsPacke
|
||||
import com.cobblemon.mod.common.permission.LaxPermissionValidator
|
||||
import com.cobblemon.mod.common.platform.events.PlatformEvents
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.aspects.CHARACTERISTIC_RAINBOW_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.aspects.COSMETIC_SLOT_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.aspects.GENDER_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.aspects.SHINY_ASPECT
|
||||
@@ -293,6 +294,7 @@ object Cobblemon {
|
||||
SHINY_ASPECT.register()
|
||||
GENDER_ASPECT.register()
|
||||
COSMETIC_SLOT_ASPECT.register()
|
||||
CHARACTERISTIC_RAINBOW_ASPECT.register()
|
||||
|
||||
SpeciesFeatures.types["choice"] = ChoiceSpeciesFeatureProvider::class.java
|
||||
SpeciesFeatures.types["flag"] = FlagSpeciesFeatureProvider::class.java
|
||||
|
||||
@@ -33,7 +33,7 @@ import com.cobblemon.mod.common.client.net.gui.PokedexUIPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.SummaryUIPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.npc.CloseNPCEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.npc.OpenNPCEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.orientation.S2CUpdateOrientationHandler
|
||||
import com.cobblemon.mod.common.client.net.orientation.ClientboundUpdateOrientationHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.ClosePastureHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.OpenPastureHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.PokemonPasturedHandler
|
||||
@@ -179,6 +179,7 @@ import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetNicknamePa
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.evolution.AcceptEvolutionPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.DismountPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateDriverInputPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateRiderRotationPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.starter.RequestStarterScreenPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.SwapPCPartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.party.MovePartyPokemonPacket
|
||||
@@ -216,7 +217,7 @@ import com.cobblemon.mod.common.net.serverhandling.dialogue.EscapeDialogueHandle
|
||||
import com.cobblemon.mod.common.net.serverhandling.dialogue.InputToDialogueHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.evolution.AcceptEvolutionHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.npc.SaveNPCHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.orientation.OrientationPacketHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.orientation.ServerboundUpdateOrientationHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pasture.PasturePokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pasture.SetPastureConflictHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pasture.UnpastureAllPokemonHandler
|
||||
@@ -231,6 +232,7 @@ import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetMarkingsHan
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetNicknameHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.riding.DismountPokemonPacketHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.riding.DriverInputPacketHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.riding.ServerboundUpdateRiderRotationHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.starter.RequestStarterScreenHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.starter.SelectStarterPacketHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.BenchMoveHandler
|
||||
@@ -442,7 +444,7 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(UpdatePastureConflictFlagPacket.ID, UpdatePastureConflictFlagPacket::decode, UpdatePastureConflictFlagHandler))
|
||||
|
||||
// Orientation
|
||||
list.add(PacketRegisterInfo(ClientboundUpdateOrientationPacket.ID, ClientboundUpdateOrientationPacket::decode, S2CUpdateOrientationHandler))
|
||||
list.add(PacketRegisterInfo(ClientboundUpdateOrientationPacket.ID, ClientboundUpdateOrientationPacket::decode, ClientboundUpdateOrientationHandler))
|
||||
|
||||
// Behaviours
|
||||
list.add(PacketRegisterInfo(PlayPosableAnimationPacket.ID, PlayPosableAnimationPacket::decode, PlayPosableAnimationHandler))
|
||||
@@ -577,13 +579,14 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(SaveNPCPacket.ID, SaveNPCPacket::decode, SaveNPCHandler))
|
||||
|
||||
// Riding packet(s)
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateOrientationPacket.ID, ServerboundUpdateOrientationPacket::decode, OrientationPacketHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateOrientationPacket.ID, ServerboundUpdateOrientationPacket::decode, ServerboundUpdateOrientationHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatePacket.ID, ServerboundUpdateRidingStatePacket::decode, ServerboundUpdateRidingStateHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatsPacket.ID, ServerboundUpdateRidingStatsPacket::decode, ServerboundUpdateRidingStatsHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatRangePacket.ID, ServerboundUpdateRidingStatRangePacket::decode, ServerboundUpdateRidingStatRangeHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateRidingSettingsPacket.ID, ServerboundUpdateRidingSettingsPacket::decode, ServerboundUpdateRidingSettingsHandler))
|
||||
list.add(PacketRegisterInfo(DismountPokemonPacket.ID, DismountPokemonPacket::decode, DismountPokemonPacketHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateDriverInputPacket.ID, ServerboundUpdateDriverInputPacket::decode, DriverInputPacketHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateRiderRotationPacket.ID, ServerboundUpdateRiderRotationPacket::decode, ServerboundUpdateRiderRotationHandler))
|
||||
|
||||
// Cooking
|
||||
list.add(PacketRegisterInfo(ToggleCookingPotLidPacket.ID, ToggleCookingPotLidPacket::decode, ToggleCookingPotLidHandler))
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.cobblemon.mod.common.api.riding.behaviour.types.land.VehicleSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.BoatSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.BurstSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.DolphinSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.SubmarineSettings
|
||||
import com.cobblemon.mod.common.net.messages.client.data.RideSettingsSyncPacket
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
|
||||
@@ -63,6 +64,7 @@ object CobblemonRideSettings : DataRegistry {
|
||||
var boat = BoatSettings()
|
||||
var burst = BurstSettings()
|
||||
var dolphin = DolphinSettings()
|
||||
var submarine = SubmarineSettings()
|
||||
|
||||
override fun sync(player: ServerPlayer) {
|
||||
player.sendPacket(
|
||||
@@ -78,7 +80,8 @@ object CobblemonRideSettings : DataRegistry {
|
||||
vehicle = vehicle,
|
||||
boat = boat,
|
||||
burst = burst,
|
||||
dolphin = dolphin
|
||||
dolphin = dolphin,
|
||||
submarine = submarine
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -96,6 +99,7 @@ object CobblemonRideSettings : DataRegistry {
|
||||
boat = loadStyle(manager, "boat", BoatSettings::class.java)
|
||||
burst = loadStyle(manager, "burst", BurstSettings::class.java)
|
||||
dolphin = loadStyle(manager, "dolphin", DolphinSettings::class.java)
|
||||
submarine = loadStyle(manager, "submarine", SubmarineSettings::class.java)
|
||||
}
|
||||
|
||||
private fun <T : RidingBehaviourSettings> loadStyle(manager: ResourceManager, name: String, clazz: Class<T>): T {
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ class MoveToOwnerTaskConfig : SingleTaskConfig {
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
): BehaviorControl<in LivingEntity> {
|
||||
behaviourConfigurationContext.addMemories(
|
||||
MemoryModuleType.WALK_TARGET,
|
||||
MemoryModuleType.LOOK_TARGET
|
||||
|
||||
+1
-1
@@ -110,7 +110,7 @@ class PlaceHoneyInSaccLeavesTaskConfig : SingleTaskConfig {
|
||||
override fun stop(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
|
||||
if (successfulPollinationTicks > REQUIRED_SUCCESSFUL_POLLINATION_TICKS) {
|
||||
val blockPos = entity.brain.getMemorySafely(CobblemonMemories.NEARBY_SACC_LEAVES).orElse(null)
|
||||
blockPos.let {
|
||||
blockPos?.let {
|
||||
val blockState = level.getBlockState(blockPos)
|
||||
if (blockState.block == CobblemonBlocks.SACCHARINE_LEAVES) {
|
||||
val saccAge = blockState.getValue( SaccharineLeafBlock.AGE)
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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.berry.spawncondition
|
||||
|
||||
import com.cobblemon.mod.common.api.berry.Berry
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.core.Holder
|
||||
import net.minecraft.tags.TagKey
|
||||
import net.minecraft.util.RandomSource
|
||||
import net.minecraft.world.level.biome.Biome
|
||||
|
||||
class SpecificBiomeCondition : BerrySpawnCondition {
|
||||
lateinit var biome: TagKey<Biome>
|
||||
val minGroveSize: Int = 1
|
||||
val maxGroveSize: Int = 1
|
||||
|
||||
override fun canSpawn(berry: Berry, biome: Holder<Biome>) = biome.`is`(this.biome)
|
||||
override fun getGroveSize(random: RandomSource) = random.nextIntBetweenInclusive(minGroveSize, maxGroveSize)
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("specific_biome")
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ interface PokemonSideDelegate : EntitySideDelegate<PokemonEntity> {
|
||||
fun handleStatus(status: Byte) {}
|
||||
fun spawnShinyParticle(player: Player) {}
|
||||
fun spawnAspectParticle() {}
|
||||
fun applyRenderRotation(partialTick: Float) {}
|
||||
fun positionRider(passenger: Entity, positionUpdater: MoveFunction)
|
||||
fun updateAge(age: Int) {}
|
||||
}
|
||||
|
||||
@@ -17,18 +17,11 @@ object SpawnBaitUtils {
|
||||
return grouped.map { (key, groupEffects) ->
|
||||
val (type, subcategory) = key
|
||||
|
||||
val count = groupEffects.size
|
||||
val totalChance = groupEffects.sumOf { it.chance }
|
||||
val totalValue = groupEffects.sumOf { it.value }
|
||||
|
||||
val multiplier = when (count) {
|
||||
2 -> 0.8
|
||||
3 -> 0.6
|
||||
else -> 1.0
|
||||
}
|
||||
|
||||
val adjustedChance = (totalChance * multiplier).coerceAtMost(1.0)
|
||||
val adjustedValue = ceil(totalValue * multiplier)
|
||||
val adjustedChance = totalChance.coerceAtMost(1.0)
|
||||
val adjustedValue = ceil(totalValue)
|
||||
|
||||
SpawnBait.Effect(type, subcategory, adjustedChance, adjustedValue)
|
||||
}
|
||||
|
||||
@@ -53,8 +53,7 @@ open class MoveTemplate(
|
||||
val pp: Int,
|
||||
val priority: Int,
|
||||
val critRatio: Double,
|
||||
val effectChances: Array<Double>,
|
||||
val actionEffect: ActionEffectTimeline?
|
||||
val effectChances: Array<Double>
|
||||
) {
|
||||
val struct: MoStruct by lazy {
|
||||
QueryStruct(hashMapOf())
|
||||
@@ -87,8 +86,7 @@ open class MoveTemplate(
|
||||
pp = 5,
|
||||
priority = 0,
|
||||
critRatio = 0.0,
|
||||
effectChances = emptyArray(),
|
||||
actionEffect = null
|
||||
effectChances = emptyArray()
|
||||
)
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -92,18 +92,7 @@ object Moves : DataRegistry {
|
||||
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)
|
||||
val move = MoveTemplate(id, num, elementalType, damageCategory, power, target, accuracy, pp, priority, critRatio, effectChances.toTypedArray())
|
||||
this.register(move)
|
||||
} catch (e: Exception) {
|
||||
Cobblemon.LOGGER.error("Caught exception trying to resolve the move '{}'", id, e)
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.moves.animations.keyframes.*
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stat
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.pokemon.adapters.CobblemonStatTypeAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.*
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
@@ -91,5 +92,11 @@ object ActionEffects : JsonDataRegistry<ActionEffectTimeline> {
|
||||
observable.emit(this)
|
||||
}
|
||||
|
||||
fun getEffectWithBattleContext(id: ResourceLocation, pokemon: BattlePokemon): ActionEffectTimeline? {
|
||||
val species = pokemon.entity?.exposedSpecies ?: pokemon.effectedPokemon.species
|
||||
val contextedEffect = actionEffects[ResourceLocation.fromNamespaceAndPath(id.namespace, id.path + "_" + species)]
|
||||
return contextedEffect ?: actionEffects[id]
|
||||
}
|
||||
|
||||
override fun sync(player: ServerPlayer) {}
|
||||
}
|
||||
+96
-12
@@ -10,13 +10,17 @@ package com.cobblemon.mod.common.api.orientation
|
||||
|
||||
import com.cobblemon.mod.common.util.math.geometry.toDegrees
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import com.mojang.blaze3d.Blaze3D
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import org.joml.AxisAngle4f
|
||||
import org.joml.Matrix3f
|
||||
import org.joml.Quaternionf
|
||||
import org.joml.Vector3f
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.asin
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.sign
|
||||
|
||||
open class OrientationController(val entity: LivingEntity) {
|
||||
@@ -35,6 +39,11 @@ open class OrientationController(val entity: LivingEntity) {
|
||||
private var renderOrientationO: Matrix3f? = null
|
||||
private var renderOrientation: Matrix3f? = null
|
||||
|
||||
|
||||
private var angularVelocity: Vector3f = Vector3f(0.0f, 0.0f, 0.0f)
|
||||
private var lastHandledRotationTime = Double.MIN_VALUE
|
||||
private var frameTime = 0.0
|
||||
|
||||
/** Adding this simply because it irritates me seeing `getActive` when most of this is Java. */
|
||||
fun isActive() = active
|
||||
|
||||
@@ -63,7 +72,7 @@ open class OrientationController(val entity: LivingEntity) {
|
||||
}
|
||||
|
||||
fun getRenderOrientation(delta: Float): Quaternionf {
|
||||
val old = renderOrientationO ?: renderOrientation ?: orientation
|
||||
val old = renderOrientationO ?: renderOrientation ?: orientation ?: Matrix3f()
|
||||
val new = renderOrientation ?: old
|
||||
val oldQuat = Quaternionf().setFromUnnormalized(old)
|
||||
val newQuat = Quaternionf().setFromUnnormalized(new)
|
||||
@@ -72,18 +81,93 @@ open class OrientationController(val entity: LivingEntity) {
|
||||
}
|
||||
|
||||
fun tick() {
|
||||
if (!active || orientation == null) return
|
||||
renderOrientationO = renderOrientation
|
||||
val current = orientation
|
||||
val renderMatrix = this.renderOrientation ?: current
|
||||
val renderQuat = Quaternionf().setFromUnnormalized(renderMatrix)
|
||||
val targetQuat = Quaternionf().setFromUnnormalized(current)
|
||||
val dampingFactor = 0.66f // We can change this factor for faster transitions
|
||||
renderQuat.slerp(targetQuat, dampingFactor)
|
||||
// val d = Blaze3D.getTime();
|
||||
// this.frameTime =
|
||||
// if (this.lastHandledRotationTime != Double.MIN_VALUE) d - this.lastHandledRotationTime else 0.0;
|
||||
// this.lastHandledRotationTime = d;
|
||||
//
|
||||
// if (!active || orientation == null) return
|
||||
//
|
||||
// // Find the desired angular velocity
|
||||
// // lerp the current ang vel towards the desired at a set rate (does this need to take into account frametime?
|
||||
// val current = orientation
|
||||
// val renderMatrix = this.renderOrientation ?: Matrix3f()
|
||||
// val renderQuat = Quaternionf().setFromUnnormalized(renderMatrix)
|
||||
// val targetQuat = Quaternionf().setFromUnnormalized(current)
|
||||
//
|
||||
// // Max rate of angular change in radians per second
|
||||
// val maxAngVel = Math.toRadians(180.0).toFloat()
|
||||
//
|
||||
// // Find the difference between the current render orientation and the target orientation
|
||||
// val qDiff: Quaternionf = targetQuat.mul(renderQuat.invert())
|
||||
//
|
||||
// // Construct the target rate of change from the difference quat
|
||||
// val axAng = qDiff.get(AxisAngle4f())
|
||||
// val capdRate = axAng.angle.coerceIn(-maxAngVel, maxAngVel)
|
||||
// val targetAngVel = Vector3f(
|
||||
// axAng.x,
|
||||
// axAng.y,
|
||||
// axAng.z
|
||||
// ).mul(capdRate)
|
||||
//
|
||||
// // lerp the current angular velocity towards the target
|
||||
// val k = 10.0f // Some smoothing constant k
|
||||
// val smoothingFactor = Math.min(1.0f, this.frameTime.toFloat() * k)
|
||||
// angularVelocity = angularVelocity.lerp(targetAngVel, smoothingFactor)
|
||||
//
|
||||
// // Use the angular velocity to slerp the renderQuat toward the targetQuat
|
||||
// val frameDisplacement =
|
||||
// angularVelocity.mul(this.frameTime.toFloat()) // Angular displacement happening on this frame
|
||||
//
|
||||
// val fAng = frameDisplacement.length() // Angle of displacement for this given pass/frame
|
||||
// if (fAng > 0.0001f) { // Ensure that the angle is significant enough that its worth normalizing and carrying out rotation
|
||||
// val fAx = frameDisplacement.normalize()
|
||||
// // Construct a rotation quat from the
|
||||
// val rotQuat = Quaternionf().fromAxisAngleRad(fAx, fAng)
|
||||
//
|
||||
// // Set the new orientation post frame stepped rotation.
|
||||
// renderOrientation = Matrix3f().set(renderQuat.mul(rotQuat))
|
||||
// }
|
||||
//
|
||||
//// this.renderOrientation = orientation
|
||||
//
|
||||
// // apply the new current angular velocity to the current render orientation
|
||||
// // construct a quat out of the angular velocity
|
||||
// // slerp the quat with a value of frametime
|
||||
|
||||
val newRenderOrientation = Matrix3f()
|
||||
renderQuat.get(newRenderOrientation)
|
||||
renderOrientation = newRenderOrientation
|
||||
val d = Blaze3D.getTime();
|
||||
this.frameTime = if (this.lastHandledRotationTime != Double.MIN_VALUE) d - this.lastHandledRotationTime else 0.0;
|
||||
this.lastHandledRotationTime = d;
|
||||
|
||||
if (!active || orientation == null) return
|
||||
|
||||
val current = orientation
|
||||
val renderMatrix = this.renderOrientation ?: Matrix3f()
|
||||
|
||||
// Create mutable copies for manipulation
|
||||
val renderQuat = Quaternionf().setFromUnnormalized(renderMatrix)
|
||||
var targetQuat = Quaternionf().setFromUnnormalized(current)
|
||||
|
||||
// --- Shortest Path Check (Still mandatory for Slerp) ---
|
||||
if (renderQuat.dot(targetQuat) < 0) {
|
||||
targetQuat = targetQuat.invert()
|
||||
}
|
||||
// --------------------------------------------------------
|
||||
|
||||
// K is the speed (rad/s) we want to close the gap at.
|
||||
val k_rate = 10.0f // E.g., target 10 units/second closing rate.
|
||||
|
||||
// Calculate the frame-rate independent alpha (t) for Slerp.
|
||||
// This makes the smoothing constant 'k_rate' a rate of change, not an arbitrary alpha value.
|
||||
val slerpAlpha = 1.0f - Math.exp(-(k_rate * this.frameTime)).toFloat()
|
||||
|
||||
// Use Slerp to interpolate the renderQuat towards the targetQuat
|
||||
val newRenderQuat = renderQuat.slerp(targetQuat, slerpAlpha, Quaternionf())
|
||||
|
||||
// Set the new orientation
|
||||
renderOrientation = Matrix3f().set(newRenderQuat)
|
||||
|
||||
// Angular velocity is now redundant for rendering, but could be used for particle effects, etc.
|
||||
}
|
||||
|
||||
val forwardVector: Vector3f
|
||||
|
||||
@@ -170,11 +170,8 @@ object Natures {
|
||||
* Utility method to get a nature by string
|
||||
* @return a nature type or null
|
||||
*/
|
||||
fun getNature(identifier: String): Nature? {
|
||||
val nature = getNature(cobblemonResource(identifier))
|
||||
if(nature != null) return nature
|
||||
return getNature(ResourceLocation.parse(identifier))
|
||||
}
|
||||
fun getNature(identifier: String) = getNature(cobblemonResource(identifier))
|
||||
?: getNature(ResourceLocation.parse(identifier))
|
||||
|
||||
/**
|
||||
* Helper function for a random Nature
|
||||
|
||||
+12
@@ -103,6 +103,18 @@ interface RidingBehaviour<Settings : RidingBehaviourSettings, State : RidingBeha
|
||||
*/
|
||||
fun damageOnCollision(settings: Settings, state: State, vehicle: PokemonEntity, impactVec: Vec3): Boolean = false
|
||||
|
||||
/**
|
||||
* Called in [com.cobblemon.mod.common.client.render.pokemon.PokemonRenderer] to allow the controller to set rotations
|
||||
* through code using partialTicks and right before rendering.
|
||||
* //TODO: This needs to be further refined. Maybe only the orientationController needs affected? Maybe the rotations set here don't need to be applied to the controller/camera
|
||||
*/
|
||||
fun applyRenderRotation(settings: Settings, state: State, vehicle: PokemonEntity, partialTicks: Float) {}
|
||||
|
||||
/**
|
||||
* Determines if the pair of mouse inputs Pair(mouseX, mouseY) get used to modify the driverRotations or the vehicle rotations themselves.
|
||||
* Driver rotations are the rotations used by passengers or a driver that is freelooking. This does not override the freelook button.
|
||||
*/
|
||||
fun mouseModifiesDriverRotation(settings: Settings, state: State, vehicle: PokemonEntity): Pair<Boolean, Boolean> = Pair(false, false)
|
||||
|
||||
/**
|
||||
* Internal helpers to help behaviour specific calculations
|
||||
|
||||
+2
@@ -16,6 +16,7 @@ import com.cobblemon.mod.common.api.riding.behaviour.types.land.MinekartBehaviou
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.BoatBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.BurstBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.DolphinBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.SubmarineBehaviour
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
object RidingBehaviours {
|
||||
@@ -34,6 +35,7 @@ object RidingBehaviours {
|
||||
register(MinekartBehaviour.KEY, MinekartBehaviour())
|
||||
register(HoverBehaviour.KEY, HoverBehaviour())
|
||||
register(RocketBehaviour.KEY, RocketBehaviour())
|
||||
register(SubmarineBehaviour.KEY, SubmarineBehaviour())
|
||||
register(CompositeBehaviour.KEY, CompositeBehaviour())
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ class RidingController(
|
||||
val newKey = behaviourSettings.key
|
||||
for (passenger in entity.passengers) {
|
||||
if (passenger is Player && passenger !is ServerPlayer) {
|
||||
MountedCameraTypeHandler.handleTransition(previousKey ?: continue, newKey)
|
||||
MountedCameraTypeHandler.handleTransition(passenger, previousKey ?: continue, newKey)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+85
-137
@@ -34,6 +34,7 @@ import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import org.joml.Vector3f
|
||||
import kotlin.math.*
|
||||
|
||||
class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
@@ -88,7 +89,8 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
) {
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
// Also checks stamina
|
||||
val controller = (vehicle as OrientationControllable).orientationController
|
||||
if (cos(controller.roll.toRadians()) < 0.0) {
|
||||
val upsideDownRate = 1.0 / (2.0 * 20.0) // 2 seconds to max out upsideDown force
|
||||
state.currUpsideDownForce.set( min(1.0, state.currUpsideDownForce.get() + upsideDownRate * abs(cos(controller.roll.toRadians()))))
|
||||
@@ -109,6 +111,10 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
val stam = state.stamina.get()
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
|
||||
if (vehicle.runtime.resolveBoolean(settings.infiniteStamina ?: globalBird.infiniteStamina!!)) {
|
||||
return
|
||||
}
|
||||
|
||||
// Grab the boost time in seconds and convert to ticks. Then calculate the drain rate as inversely
|
||||
// proportional to the number of ticks of boost thus making a full boost take x ticks
|
||||
// in short: "Stamina drains slower at higher values and also replenishes slower"
|
||||
@@ -135,7 +141,7 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
return Vec2(driver.xRot * 0.5f, driver.yRot)
|
||||
return Vec2.ZERO//Vec2(driver.xRot * 0.5f, driver.yRot)
|
||||
}
|
||||
|
||||
override fun velocity(
|
||||
@@ -145,29 +151,26 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
var upForce = 0.0
|
||||
var forwardForce = 0.0
|
||||
val controller = (vehicle as? OrientationControllable)?.orientationController
|
||||
if (controller == null || controller.orientation == null) return Vec3.ZERO
|
||||
|
||||
//Perform ride velocity update
|
||||
calculateRideSpaceVel(settings, state, vehicle, driver)
|
||||
|
||||
//Translate ride space velocity to world space velocity.
|
||||
val controller = (driver as? OrientationControllable)?.orientationController
|
||||
if (controller != null) {
|
||||
//Need to deadzone this when straight up or down
|
||||
|
||||
upForce += -1.0 * sin(Math.toRadians(controller.pitch.toDouble())) * state.rideVelocity.get().z
|
||||
forwardForce += cos(Math.toRadians(controller.pitch.toDouble())) * state.rideVelocity.get().z
|
||||
|
||||
upForce += cos(Math.toRadians(controller.pitch.toDouble())) * state.rideVelocity.get().y
|
||||
forwardForce += sin(Math.toRadians(controller.pitch.toDouble())) * state.rideVelocity.get().y
|
||||
}
|
||||
|
||||
// The downward force used to encourage players to stop flying upside down.
|
||||
val extraDownwardForce = state.currUpsideDownForce.get().pow(2) * -0.3 // 6 blocks a second downward
|
||||
|
||||
val velocity = Vec3(state.rideVelocity.get().x , upForce + extraDownwardForce, forwardForce)
|
||||
return velocity
|
||||
// Convert the local velocity vector into a world vector
|
||||
val localVelVec = Vector3f(
|
||||
state.rideVelocity.get().x.toFloat(),
|
||||
(state.rideVelocity.get().y).toFloat(),
|
||||
state.rideVelocity.get().z.toFloat() * -1.0f // Flip the z axis to make this left handed
|
||||
)
|
||||
// Unrotate preemptively as this vector gets rotatee later down the line in MC logic.
|
||||
var worldVelVec = localVelVec.mul(controller.orientation).toVec3d().yRot(vehicle.yRot.toRadians())
|
||||
worldVelVec = worldVelVec.add(0.0, extraDownwardForce, 0.0) // Add the stamina depletion force to bring the ride down.
|
||||
|
||||
return worldVelVec
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -206,7 +209,7 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
activeInput = true
|
||||
}
|
||||
|
||||
val controller = (driver as? OrientationControllable)?.orientationController
|
||||
val controller = (vehicle as? OrientationControllable)?.orientationController
|
||||
if (controller != null) {
|
||||
//Base glide speed change on current pitch of the ride.
|
||||
glideSpeedChange = sin(Math.toRadians(controller.pitch.toDouble()))
|
||||
@@ -282,15 +285,13 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (Cobblemon.config.disableRoll) return Vec3.ZERO
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
if (vehicle !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (vehicle as OrientationControllable).orientationController
|
||||
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr ?: globalBird.handlingExpr!!)
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr ?: globalBird.speedExpr!!) / 20.0
|
||||
|
||||
val yawDeltaDeg = deltaTime * handling * sin(Math.toRadians(controller.roll.toDouble())) //* sin(Math.toRadians(controller.roll.toDouble())).sign
|
||||
val trueYawDelt = yawDeltaDeg * abs(cos(Math.toRadians(controller.pitch.toDouble())))// * sqrt(RidingBehaviour.scaleToRange(state.rideVelocity.get().length(), 0.0, topSpeed))
|
||||
val yawDeltaDeg = deltaTime * handling * sin(Math.toRadians(controller.roll.toDouble()))
|
||||
val trueYawDelt = yawDeltaDeg * abs(cos(Math.toRadians(controller.pitch.toDouble()))*2).coerceIn(-1.0, 1.0)
|
||||
|
||||
// Dampen yaw when upside down
|
||||
val yawDampen = (1 - abs(min(cos(controller.roll.toRadians()),0.0f)).pow(2))
|
||||
@@ -299,10 +300,13 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
// Correct orientation when at low speeds
|
||||
correctOrientation(settings, state, vehicle, controller, deltaTime)
|
||||
|
||||
controller.applyGlobalPitch(state.currPitchCorrectionForce.get().toRadians())
|
||||
val pCorr = (state.currPitchCorrectionForce.get() * deltaTime).toFloat()
|
||||
val rCorr = (state.currRollCorrectionForce.get() * deltaTime).toFloat()
|
||||
controller.applyGlobalPitch(pCorr)
|
||||
controller.rotateRoll(rCorr)
|
||||
|
||||
//yaw, pitch, roll
|
||||
return Vec3(0.0, 0.0, state.currRollCorrectionForce.get())
|
||||
return Vec3(0.0, 0.0, 0.0)
|
||||
}
|
||||
|
||||
private fun correctOrientation(
|
||||
@@ -313,42 +317,48 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
deltaTime: Double
|
||||
) {
|
||||
// Calculate correcting roll force.
|
||||
// Mult by cos(pitch) to ensure that it doesn't roll correct at when diving or climbing
|
||||
val rollCorrectionTimer = vehicle.runtime.resolveDouble(settings.timeToRollCorrect ?: globalBird.timeToRollCorrect!!)
|
||||
val maxRollCorrectionRate = if (state.rideVelocity.get().length() < 0.1) 15.0f else 8.0f * (cos(controller.pitch.toRadians())).pow(2) * ((state.noInputTimeRoll.get() - rollCorrectionTimer)).coerceIn(0.0, 1.0).toFloat()
|
||||
val maxRollForce = maxRollCorrectionRate / 40.0
|
||||
val rollArrivalDeg = 90.0
|
||||
if(state.rideVelocity.get().length() < 0.1 || state.noInputTimeRoll.get() > rollCorrectionTimer) {
|
||||
val arrivalInfluence = (min(rollArrivalDeg,abs(controller.roll).toDouble()) / rollArrivalDeg)
|
||||
val desiredRollForce = (0 - controller.roll).sign * maxRollCorrectionRate * arrivalInfluence
|
||||
var steeredRollForce = desiredRollForce - state.currRollCorrectionForce.get()
|
||||
// If the ride is moving then have the correction rate be an equal proportion of:
|
||||
// - how rolled are you
|
||||
// - how long has it been since last mouse input (higher is stronger correction)
|
||||
// Also the correction is proportional as a whole to how NOT pitched are you so you don't spin endlessly when looking up or down
|
||||
val howRolledAmI = sqrt(abs((cos(controller.roll.toRadians()) - 1.0f) * 0.5f)) // sqrt so it trends towards one pretty quickly
|
||||
val maxRollCorrectionRate =
|
||||
if (state.rideVelocity.get().length() < 0.2) 45.0f
|
||||
else 45.0f * cos(controller.pitch.toRadians()).pow(2) * (
|
||||
howRolledAmI*1.0f +
|
||||
(state.noInputTimeRoll.get() - rollCorrectionTimer).coerceIn(0.0, 1.0).pow(2).toFloat()*0.5f
|
||||
)
|
||||
val maxRollForce = maxRollCorrectionRate / 40.0f
|
||||
val rollArrivalDeg = 35.0f
|
||||
val desiredRoll = 0.0f
|
||||
|
||||
// Ensure the 'steering' correction force doesn't exceed our maxForce
|
||||
if (abs(steeredRollForce) > maxRollForce) {
|
||||
steeredRollForce = steeredRollForce.sign * maxRollForce
|
||||
}
|
||||
|
||||
// Apply the 'steered' force (its really not a steering force I need a better name)
|
||||
state.currRollCorrectionForce.set(
|
||||
state.currRollCorrectionForce.get() + steeredRollForce
|
||||
)
|
||||
} else {
|
||||
state.currRollCorrectionForce.set(
|
||||
//reduce rollCorrection gradually
|
||||
lerp(state.currRollCorrectionForce.get(), 0.0, deltaTime * 0.96)
|
||||
)
|
||||
// Calculate the signed error (how far and in what direction)
|
||||
val rollError = Mth.wrapDegrees(desiredRoll.angleDifference(controller.roll))
|
||||
// Use the absolute error to calculate the magnitude of the influence
|
||||
val influenceMagnitude = (min(rollArrivalDeg, abs(rollError)) / rollArrivalDeg)
|
||||
val desiredRollForce = maxRollCorrectionRate * influenceMagnitude * -rollError.sign
|
||||
var steeredRollForce = desiredRollForce - state.currRollCorrectionForce.get()
|
||||
// Ensure the 'steering' correction force doesn't exceed our maxForce
|
||||
if (abs(steeredRollForce) > maxRollForce) {
|
||||
steeredRollForce = steeredRollForce.sign * maxRollForce
|
||||
}
|
||||
// Apply the 'steered' force (its really not a steering force I need a better name)
|
||||
state.currRollCorrectionForce.set(
|
||||
state.currRollCorrectionForce.get() + steeredRollForce
|
||||
)
|
||||
|
||||
//Calculate correcting pitch force.
|
||||
val maxPitchCorrectionRate = if (state.currUpsideDownForce.get() != 0.0) 8f * state.currUpsideDownForce.get() else 15f
|
||||
val maxPitchForce = maxPitchCorrectionRate.toFloat() / 40.0f
|
||||
val pitchArrivalDeg = 45.0f
|
||||
var desiredPitch = if (state.currUpsideDownForce.get() != 0.0) 90.0 else 0.0
|
||||
val maxPitchCorrectionRate = if (state.currUpsideDownForce.get() != 0.0) 15.0f * state.currUpsideDownForce.get().toFloat() else 30.0f
|
||||
val maxPitchForce = maxPitchCorrectionRate / 40.0f
|
||||
val pitchArrivalDeg = 35.0f
|
||||
val desiredPitch = if (state.currUpsideDownForce.get() != 0.0) 90.0f else 0.0f
|
||||
|
||||
if((state.rideVelocity.get().length() < 0.1 && controller.pitch < 0.0) || state.currUpsideDownForce.get() != 0.0) {
|
||||
val arrivalInfluence = (min(pitchArrivalDeg,abs(Mth.wrapDegrees(desiredPitch.toFloat().angleDifference(controller.pitch)))) / pitchArrivalDeg)
|
||||
val desiredPitchForce = maxPitchCorrectionRate.toFloat() * arrivalInfluence
|
||||
var steeredPitchForce = (desiredPitchForce - state.currPitchCorrectionForce.get())
|
||||
if((state.rideVelocity.get().length() < 0.1) || state.currUpsideDownForce.get() != 0.0) {
|
||||
val pitchErrror = Mth.wrapDegrees(desiredPitch.angleDifference(controller.pitch))
|
||||
val arrivalInfluence = (min(pitchArrivalDeg,abs(pitchErrror)) / pitchArrivalDeg)
|
||||
val desiredPitchForce = maxPitchCorrectionRate * arrivalInfluence * -pitchErrror.sign
|
||||
var steeredPitchForce = desiredPitchForce - state.currPitchCorrectionForce.get()
|
||||
|
||||
// Ensure the 'steering' correction force doesn't exceed our maxForce
|
||||
if (abs(steeredPitchForce) > maxPitchForce) {
|
||||
@@ -398,80 +408,18 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
state.noInputTimePitch.set(0.0)
|
||||
}
|
||||
|
||||
return when {
|
||||
Cobblemon.config.disableRoll -> noRollRotation(
|
||||
settings,
|
||||
state,
|
||||
vehicle,
|
||||
driver,
|
||||
mouseY,
|
||||
mouseX,
|
||||
mouseYSmoother,
|
||||
mouseXSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
return rollRotation(
|
||||
settings,
|
||||
state,
|
||||
vehicle,
|
||||
driver,
|
||||
mouseY,
|
||||
mouseX,
|
||||
mouseYSmoother,
|
||||
mouseXSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
)
|
||||
else -> rollRotation(
|
||||
settings,
|
||||
state,
|
||||
vehicle,
|
||||
driver,
|
||||
mouseY,
|
||||
mouseX,
|
||||
mouseYSmoother,
|
||||
mouseXSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun noRollRotation(
|
||||
settings: BirdSettings,
|
||||
state: BirdState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
|
||||
// Set roll to zero if transitioning to noroll config
|
||||
controller.rotateRoll(controller.roll * -1.0f)
|
||||
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr ?: globalBird.handlingExpr!!)
|
||||
val mouseInputMult = vehicle.runtime.resolveDouble(settings.mouseInputMult ?: globalBird.mouseInputMult!!)
|
||||
|
||||
//Smooth out mouse input.
|
||||
val smoothingSpeed = 4.0
|
||||
val mouseXc = ((mouseX).coerceIn(-60.0, 60.0) / 60.0) * mouseInputMult
|
||||
val mouseYc = ((mouseY).coerceIn(-60.0, 60.0) / 60.0) * mouseInputMult
|
||||
val xInput = mouseXSmoother.getNewDeltaValue(mouseXc * 0.1, deltaTime * smoothingSpeed);
|
||||
val yInput = mouseYSmoother.getNewDeltaValue(mouseYc * 0.1, deltaTime * smoothingSpeed);
|
||||
|
||||
//Give the ability to yaw with x mouse input when at low speeds.
|
||||
val yawForce = xInput * handling //* ( 1.0 - min(sqrt(RidingBehaviour.scaleToRange(state.rideVelocity.get().length(), 0.0, topSpeed)), 0.5))
|
||||
|
||||
//Apply yaw globally as we don't want roll or pitch changes due to local yaw when looking up or down.
|
||||
controller.applyGlobalYaw(yawForce.toFloat() * abs(cos(controller.pitch.toRadians())).pow(2))
|
||||
|
||||
var pitchRot = yInput * handling
|
||||
|
||||
// Pitch up globally
|
||||
if (abs(controller.pitch + pitchRot) >= 89.5 ) {
|
||||
pitchRot = 0.0
|
||||
mouseYSmoother.reset()
|
||||
} else {
|
||||
controller.applyGlobalPitch(pitchRot.toFloat() * -1.0f)
|
||||
}
|
||||
|
||||
//yaw, pitch, roll
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
fun rollRotation(
|
||||
@@ -486,21 +434,23 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
if (vehicle !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (vehicle as OrientationControllable).orientationController
|
||||
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr ?: globalBird.speedExpr!!) / 20.0
|
||||
val mouseInputMult = vehicle.runtime.resolveDouble(settings.mouseInputMult ?: globalBird.mouseInputMult!!)
|
||||
// Applied to mouseX to prevent turning upside down when trying to roll hard.
|
||||
val rollDegreeDebuff = if(mouseX.sign.toFloat() == controller.roll.sign) 1 - 0.9f*sqrt(abs(sin(controller.roll.toRadians())))*sqrt(abs(cos(controller.pitch))) else 1.0f
|
||||
|
||||
//Smooth out mouse input.
|
||||
val smoothingSpeed = 2.0
|
||||
val mouseXc = (mouseX).coerceIn(-45.0, 45.0) * mouseInputMult
|
||||
val mouseXc = (mouseX).coerceIn(-45.0, 45.0) * mouseInputMult * rollDegreeDebuff
|
||||
// When upside down apply a pitching force to nudge the player towards a dive. This reduces the 'weirdness'
|
||||
// of being upside down
|
||||
val rolledOverPitchCorrection = -8*sqrt(abs(min(cos(controller.roll.toRadians()),0.0f))) * (cos(controller.pitch.toRadians())).pow(2)
|
||||
val mouseYc = ((mouseY).coerceIn(-45.0, 45.0) * mouseInputMult) + rolledOverPitchCorrection
|
||||
val xInput = mouseXSmoother.getNewDeltaValue(mouseXc * 0.1, deltaTime * smoothingSpeed);
|
||||
val yInput = mouseYSmoother.getNewDeltaValue(mouseYc * 0.1, deltaTime * smoothingSpeed);
|
||||
val xInput = mouseXSmoother.getNewDeltaValue(mouseXc * 0.1, deltaTime * smoothingSpeed)
|
||||
val yInput = mouseYSmoother.getNewDeltaValue(mouseYc * 0.1, deltaTime * smoothingSpeed)
|
||||
val currSpeed = state.rideVelocity.get().length()
|
||||
val currHorzSpeed = state.rideVelocity.get().horizontalDistance()
|
||||
val hoverSpeed = 0.1
|
||||
@@ -508,8 +458,6 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
|
||||
// Yaw locally when at or below hoverSpeed but not when pitched up or rolled over
|
||||
val globalYaw = xInput * (1 - sqrt(RidingBehaviour.scaleToRange(currHorzSpeed, hoverSpeed, topSpeed))).coerceIn(0.0, 1.0)
|
||||
//xInput * 0.4 * cos(controller.roll.toRadians()).coerceIn(0.0f, 1.0f) * yawDampen
|
||||
|
||||
controller.applyGlobalYaw(globalYaw.toFloat())
|
||||
|
||||
// Pitch locally up or down depending upon a number of factors:
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
|
||||
|
||||
val poseProvider = PoseProvider<HoverSettings, HoverState>(PoseType.STAND)
|
||||
.with(PoseOption(PoseType.WALK) { _, state, _ ->
|
||||
return@PoseOption abs(state.rideVelocity.get().z) > 0.2
|
||||
return@PoseOption abs(state.rideVelocity.get().length()) > 0.01
|
||||
})
|
||||
|
||||
override fun isActive(
|
||||
|
||||
+4
-113
@@ -161,7 +161,7 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
val controller = (driver as? OrientationControllable)?.orientationController
|
||||
val controller = (vehicle as? OrientationControllable)?.orientationController
|
||||
if (controller == null || controller.orientation == null) return Vec3.ZERO
|
||||
|
||||
//Calculate ride space velocity
|
||||
@@ -265,8 +265,6 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
//don't yaw this way if
|
||||
if (Cobblemon.config.disableRoll) return Vec3.ZERO
|
||||
|
||||
//Cap at a rate of 5fps so frame skips dont lead to huge jumps
|
||||
val cappedDeltaTime = min(deltaTime, 0.2)
|
||||
@@ -298,107 +296,8 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
return when {
|
||||
Cobblemon.config.disableRoll -> noRollRotation(
|
||||
settings,
|
||||
state,
|
||||
vehicle,
|
||||
driver,
|
||||
mouseY,
|
||||
mouseX,
|
||||
mouseYSmoother,
|
||||
mouseXSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
)
|
||||
else -> rollRotation(
|
||||
settings,
|
||||
state,
|
||||
vehicle,
|
||||
driver,
|
||||
mouseY,
|
||||
mouseX,
|
||||
mouseYSmoother,
|
||||
mouseXSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
)
|
||||
}
|
||||
}
|
||||
if (vehicle !is OrientationControllable) return Vec3.ZERO
|
||||
|
||||
fun noRollRotation(
|
||||
settings: JetSettings,
|
||||
state: JetState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
|
||||
// Set roll to zero if transitioning to noroll config
|
||||
controller.rotateRoll(controller.roll * -1.0f)
|
||||
|
||||
//Cap at a rate of 5fps so frame skips dont lead to huge jumps
|
||||
val cappedDeltaTime = min(deltaTime, 0.2)
|
||||
|
||||
// Accumulate the mouse input
|
||||
state.currMouseXForce.set((state.currMouseXForce.get() + (0.0015 * mouseX)).coerceIn(-1.0, 1.0))
|
||||
state.currMouseYForce.set((state.currMouseYForce.get() + (0.0015 * mouseY)).coerceIn(-1.0, 1.0))
|
||||
|
||||
//Get handling in degrees per second
|
||||
val handlingDebuff = if(state.stamina.get() == 0.0f) 0.5 else 1.0
|
||||
var handling = vehicle.runtime.resolveDouble(settings.handlingExpr ?: globalJet.handlingExpr!!) * handlingDebuff
|
||||
//convert it to delta time
|
||||
handling *= (cappedDeltaTime)
|
||||
|
||||
var pitchRot = handling * state.currMouseYForce.get()
|
||||
|
||||
// Yaw
|
||||
val yawRot = handling * 0.5 * state.currMouseXForce.get()
|
||||
controller.applyGlobalYaw(yawRot.toFloat())
|
||||
|
||||
if (abs(controller.pitch + pitchRot) >= 89.5 ) {
|
||||
pitchRot = 0.0
|
||||
state.currMouseYForce.set(0.0)
|
||||
mouseYSmoother.reset()
|
||||
} else {
|
||||
controller.applyGlobalPitch(pitchRot.toFloat() * -1.0f)
|
||||
}
|
||||
|
||||
// Have accumulated input begin decay when no input detected
|
||||
if (abs(mouseX) == 0.0) {
|
||||
// Have decay on roll be much stronger.
|
||||
state.currMouseXForce.set(lerp(state.currMouseXForce.get(), 0.0, 0.02))
|
||||
}
|
||||
if (mouseY == 0.0) {
|
||||
state.currMouseYForce.set(lerp(state.currMouseYForce.get(), 0.0, 0.005))
|
||||
}
|
||||
|
||||
//yaw, pitch, roll
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
fun rollRotation(
|
||||
settings: JetSettings,
|
||||
state: JetState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
//TODO: figure out a cleaner solution to this issue of large jumps when skipping frames or lagging
|
||||
//Cap at a rate of 5fps so frame skips dont lead to huge jumps
|
||||
val cappedDeltaTime = min(deltaTime, 0.2)
|
||||
|
||||
// Accumulate the mouse input
|
||||
@@ -412,14 +311,6 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
//convert it to delta time
|
||||
handling *= (cappedDeltaTime)
|
||||
|
||||
|
||||
val poke = driver.vehicle as? PokemonEntity
|
||||
|
||||
//TODO: reevaluate if deadzones are needed and if they are still causing issues.
|
||||
//create deadzones for the constant input values.
|
||||
//val xInput = remapWithDeadzone(state.currMouseXForce, 0.025, 1.0)
|
||||
//val yInput = remapWithDeadzone(state.currMouseYForce, 0.025, 1.0)
|
||||
|
||||
val pitchRot = handling * state.currMouseYForce.get()
|
||||
|
||||
// Roll
|
||||
@@ -430,10 +321,10 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
// Have accumulated input begin decay when no input detected
|
||||
if (abs(mouseX) == 0.0) {
|
||||
// Have decay on roll be much stronger.
|
||||
state.currMouseXForce.set(lerp(state.currMouseXForce.get(), 0.0, 0.02))
|
||||
state.currMouseXForce.set(lerp(state.currMouseXForce.get(), 0.0, 0.08))
|
||||
}
|
||||
if (mouseY == 0.0) {
|
||||
state.currMouseYForce.set(lerp(state.currMouseYForce.get(), 0.0, 0.005))
|
||||
state.currMouseYForce.set(lerp(state.currMouseYForce.get(), 0.0, 0.02))
|
||||
}
|
||||
|
||||
//yaw, pitch, roll
|
||||
|
||||
+147
-177
@@ -20,6 +20,7 @@ import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourState
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.Side
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.ridingState
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.air.angleDifference
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseOption
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.api.riding.sound.RideSoundSettingsList
|
||||
@@ -47,6 +48,7 @@ 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 org.joml.Vector3f
|
||||
|
||||
class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
companion object {
|
||||
@@ -62,7 +64,7 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
}
|
||||
|
||||
val poseProvider = PoseProvider<DolphinSettings, DolphinState>(PoseType.FLOAT)
|
||||
.with(PoseOption(PoseType.SWIM) { _, _, entity -> entity.deltaMovement.length() > 0.1 })
|
||||
.with(PoseOption(PoseType.SWIM) { _, state, entity -> abs(state.rideVelocity.get().length()) > 0.05 })
|
||||
|
||||
override fun isActive(settings: DolphinSettings, state: DolphinState, vehicle: PokemonEntity): Boolean {
|
||||
return vehicle.isInWater || !vehicle.onGround()
|
||||
@@ -151,37 +153,46 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
if (vehicle !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (vehicle as OrientationControllable).orientationController
|
||||
val orientation = controller.orientation ?: return Vec3.ZERO
|
||||
|
||||
val runtime = vehicle.runtime
|
||||
val boostMod = if (state.boosting.get()) runtime.resolveDouble(settings.jumpExpr ?: globalDolphin.jumpExpr!!) else 1.0
|
||||
val topSpeed = (vehicle.runtime.resolveDouble(settings.speedExpr ?: globalDolphin.speedExpr!!) / 20.0) * boostMod
|
||||
val accel = (topSpeed / (vehicle.runtime.resolveDouble(settings.accelerationExpr ?: globalDolphin.accelerationExpr!!) * 20.0)) * boostMod
|
||||
val strafeFactor = runtime.resolveDouble(settings.strafeFactor ?: globalDolphin.strafeFactor!!)
|
||||
val reverseDriveFactor = runtime.resolveDouble(settings.reverseDriveFactor ?: globalDolphin.reverseDriveFactor!!)
|
||||
var currVel = state.rideVelocity.get()
|
||||
|
||||
/*********************************************
|
||||
* Breaching logic
|
||||
*********************************************/
|
||||
if (!vehicle.isInWater && !vehicle.isUnderWater)
|
||||
{
|
||||
val currVel = state.lastVelocity.get()
|
||||
val breachBoost = 1.5
|
||||
var prevVel = state.lastVelocity.get()
|
||||
val breachBoost = 0.3
|
||||
state.clearMouseSmoothers.set(false)
|
||||
if (!state.hasBreached.get()) {
|
||||
// Apply an upwards breaching force if boosting. This will enhance jumping out of water to feel more
|
||||
// fun
|
||||
// Apply an upwards breaching force if boosting. This will enhance jumping out of water to feel more fun
|
||||
if (state.boosting.get()) {
|
||||
state.lastVelocity.set(Vec3(currVel.x, currVel.y + breachBoost*sin(-controller.pitch.toRadians()).coerceIn(0.0f,0.5f), currVel.z))
|
||||
prevVel = Vec3(prevVel.x, prevVel.y + breachBoost*(sin(-controller.pitch.toRadians()).coerceIn(0.0f,0.5f)*2.0).pow(2), prevVel.z)
|
||||
}
|
||||
state.hasBreached.set(true)
|
||||
} else {
|
||||
val gravity = (9.8 / ( 20.0)) * 0.2 * 0.4
|
||||
val terminalVel = 2.0
|
||||
state.lastVelocity.set(Vec3(currVel.x, max(-terminalVel, currVel.y - gravity), currVel.z)) //.yRot(vehicle.yRot.toRadians()))
|
||||
prevVel = Vec3(prevVel.x, max(-terminalVel, prevVel.y - gravity), prevVel.z)
|
||||
}
|
||||
return state.lastVelocity.get()
|
||||
|
||||
state.lastVelocity.set(prevVel)
|
||||
return state.lastVelocity.get().yRot(vehicle.yRot.toRadians())
|
||||
} else {
|
||||
state.lastVelocity.set(vehicle.deltaMovement.yRot(vehicle.yRot.toRadians()))
|
||||
if(state.hasBreached.get()) {
|
||||
state.clearMouseSmoothers.set(true)
|
||||
}
|
||||
state.hasBreached.set(false)
|
||||
currVel = Vec3(currVel.x, 0.0, currVel.z) // Reset y velocity to account for y vel persistance edgecase
|
||||
}
|
||||
|
||||
/*********************************************
|
||||
@@ -190,32 +201,30 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
if (vehicle.horizontalCollision || vehicle.verticalCollision) {
|
||||
// not actually friction
|
||||
val frictionLimit = 0.1
|
||||
val postColSpeed = min(max(vehicle.deltaMovement.length(), frictionLimit), state.speed.get())
|
||||
val postColSpeed = min(max(state.rideVelocity.get().length(), frictionLimit), state.speed.get())
|
||||
state.speed.set(postColSpeed)
|
||||
}
|
||||
|
||||
val currSpeed = state.speed.get()
|
||||
val strafeFactor = runtime.resolveDouble(settings.strafeFactor ?: globalDolphin.strafeFactor!!)
|
||||
val reverseDriveFactor = runtime.resolveDouble(settings.reverseDriveFactor ?: globalDolphin.reverseDriveFactor!!)
|
||||
val f = -driver.xxa * strafeFactor
|
||||
when {
|
||||
driver.zza > 0.0 -> state.speed.set(min(topSpeed, currSpeed + accel))
|
||||
driver.zza < 0.0 -> state.speed.set(max( -topSpeed * reverseDriveFactor, currSpeed - accel))
|
||||
else -> state.speed.set( lerp(currSpeed, 0.0, 0.05))
|
||||
val currZVel = state.rideVelocity.get().z
|
||||
val newZVel = when {
|
||||
driver.zza > 0.0 -> min(topSpeed, currZVel + accel)
|
||||
driver.zza < 0.0 -> max( -topSpeed * reverseDriveFactor, currZVel - accel)
|
||||
else -> lerp(currZVel, 0.0, 0.05)
|
||||
}
|
||||
val vertInput = when {
|
||||
driver.jumping && state.stamina.get() != 0.0f -> 1.0
|
||||
driver.isShiftKeyDown -> -1.0
|
||||
else -> 0.0
|
||||
} * strafeFactor
|
||||
state.rideVelocity.set(Vec3(currVel.x, currVel.y, newZVel))
|
||||
|
||||
var newVelocity = Vec3(f, vertInput,-state.speed.get())
|
||||
// Convert the local velocity vector into a world vector
|
||||
val localVelVec = Vector3f(
|
||||
state.rideVelocity.get().x.toFloat(),
|
||||
(state.rideVelocity.get().y).toFloat(),
|
||||
state.rideVelocity.get().z.toFloat() * -1.0f // Flip the z axis to make this left handed
|
||||
)
|
||||
|
||||
// Align to the ride
|
||||
newVelocity = controller.orientation?.transform(newVelocity.toVector3f())?.toVec3d() ?: Vec3.ZERO
|
||||
newVelocity = newVelocity.yRot(vehicle.yRot.toRadians())
|
||||
val desiredVec = newVelocity.subtract(vehicle.deltaMovement)
|
||||
return vehicle.deltaMovement.add(desiredVec)
|
||||
val worldVelVec = localVelVec.mul(orientation).toVec3d()
|
||||
state.lastVelocity.set(worldVelVec) // Set last velocity to be used during breaching
|
||||
|
||||
// Unrotate preemptively as this vector gets rotated later down the line in MC logic.
|
||||
return worldVelVec.yRot(vehicle.yRot.toRadians())
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
@@ -225,9 +234,8 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (Cobblemon.config.disableRoll) return Vec3.ZERO
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
if (vehicle !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (vehicle as OrientationControllable).orientationController
|
||||
|
||||
val currSpeed = vehicle.deltaMovement.length()
|
||||
|
||||
@@ -235,7 +243,7 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr ?: globalDolphin.speedExpr!!) / 20.0
|
||||
|
||||
val yawDeltaDeg = deltaTime * handling * sin(Math.toRadians(controller.roll.toDouble())).pow(2) * sin(Math.toRadians(controller.roll.toDouble())).sign
|
||||
val trueYawDelt = yawDeltaDeg * abs(cos(Math.toRadians(controller.pitch.toDouble()))) * sqrt(RidingBehaviour.scaleToRange(currSpeed, 0.0, topSpeed))
|
||||
val trueYawDelt = yawDeltaDeg * abs(cos(Math.toRadians(controller.pitch.toDouble()))*2).coerceIn(-1.0, 1.0) * sqrt(RidingBehaviour.scaleToRange(currSpeed, 0.0, topSpeed))
|
||||
|
||||
// Dampen yaw when upside down
|
||||
val yawDampen = (1 - abs(min(cos(controller.roll.toRadians()),0.0f)))
|
||||
@@ -256,45 +264,62 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
) {
|
||||
// Calculate correcting roll force.
|
||||
// Mult by cos(pitch) to ensure that it doesn't roll correct at when diving or climbing
|
||||
val currSpeed = vehicle.deltaMovement.length()
|
||||
val rollCorrectionTimer = vehicle.runtime.resolveDouble(settings.timeToRollCorrect ?: globalDolphin.timeToRollCorrect!!)
|
||||
val maxRollCorrectionRate = if (!(vehicle.isInWater || vehicle.isUnderWater)) 15.0f
|
||||
else 10.0f * (cos(controller.pitch.toRadians())).pow(2) * ((state.noInputTime.get() - rollCorrectionTimer) * 2).coerceIn(0.0, 1.0).toFloat()
|
||||
val maxRollForce = maxRollCorrectionRate / 40.0
|
||||
val rollArrivalDeg = 90.0
|
||||
|
||||
if((state.speed.get() < 0.1 && driver.zza.toDouble() == 0.0) || state.noInputTime.get() > rollCorrectionTimer || !(vehicle.isInWater || vehicle.isUnderWater)) {
|
||||
val arrivalInfluence = (min(rollArrivalDeg,abs(controller.roll).toDouble()) / rollArrivalDeg)
|
||||
val desiredRollForce = (0 - controller.roll).sign * maxRollCorrectionRate * arrivalInfluence
|
||||
var steeredRollForce = desiredRollForce - state.currRollCorrectionForce.get()
|
||||
|
||||
// Ensure the 'steering' correction force doesn't exceed our maxForce
|
||||
if (abs(steeredRollForce) > maxRollForce) {
|
||||
steeredRollForce = steeredRollForce.sign * maxRollForce
|
||||
}
|
||||
|
||||
// Apply the 'steered' force (its really not a steering force I need a better name)
|
||||
// Stop roll and pitch correction when breached
|
||||
if (state.hasBreached.get()) {
|
||||
state.currRollCorrectionForce.set(
|
||||
state.currRollCorrectionForce.get() + steeredRollForce
|
||||
lerp(state.currRollCorrectionForce.get(), 0.0, deltaTime * 0.98)
|
||||
)
|
||||
} else {
|
||||
state.currRollCorrectionForce.set(
|
||||
//reduce rollCorrection gradually
|
||||
lerp(state.currRollCorrectionForce.get(), 0.0, deltaTime * 0.96)
|
||||
state.currPitchCorrectionForce.set(
|
||||
lerp(state.currPitchCorrectionForce.get(), 0.0, deltaTime * 0.98)
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
//Calculate correcting pitch force.
|
||||
val maxPitchCorrectionRate = if (!(vehicle.isInWater || vehicle.isUnderWater)) 15.0 else 5.0f * ((state.noInputTime.get() - rollCorrectionTimer) * 2).coerceIn(0.0, 1.0).toFloat() * (1 - (currSpeed * 0.5).coerceIn(0.0, 1.0))
|
||||
val maxPitchForce = maxPitchCorrectionRate / 40.0
|
||||
val pitchArrivalDeg = 45.0
|
||||
val targetPitch = if ((vehicle.isInWater || vehicle.isUnderWater)) 0.0f else (-asin(vehicle.deltaMovement.y / vehicle.deltaMovement.length()).toDegrees()).coerceIn(-45.0f, 45.0f)
|
||||
// Calculate correcting roll force.
|
||||
val rollCorrectionTimer = vehicle.runtime.resolveDouble(settings.timeToRollCorrect ?: globalDolphin.timeToRollCorrect!!)
|
||||
// If the ride is moving then have the correction rate be an equal proportion of:
|
||||
// - how rolled are you
|
||||
// - how long has it been since last mouse input (higher is stronger correction)
|
||||
// Also the correction is proportional as a whole to how NOT pitched are you so you don't spin endlessly when looking up or down
|
||||
val howRolledAmI = sqrt(abs((cos(controller.roll.toRadians()) - 1.0f) * 0.5f)) // sqrt so it trends towards one pretty quickly
|
||||
val maxRollCorrectionRate =
|
||||
if (state.rideVelocity.get().length() < 0.2) 10.0f * abs(cos(controller.pitch.toRadians()))
|
||||
else 10.0f * cos(controller.pitch.toRadians()).pow(2) * (
|
||||
howRolledAmI*1.0f +
|
||||
(state.noInputTime.get() - rollCorrectionTimer).coerceIn(0.0, 1.0).pow(2).toFloat()*0.5f
|
||||
)
|
||||
val maxRollForce = maxRollCorrectionRate / 40.0f
|
||||
val rollArrivalDeg = 60.0f
|
||||
val desiredRoll = 0.0f
|
||||
|
||||
if((state.noInputTime.get() > rollCorrectionTimer && driver.zza.toDouble() == 0.0) || !(vehicle.isInWater || vehicle.isUnderWater)) {
|
||||
val arrivalInfluence = min(rollArrivalDeg, abs(Mth.wrapDegrees(targetPitch - controller.pitch.toDouble()))) / pitchArrivalDeg
|
||||
val desiredPitchForce = (targetPitch - controller.pitch).sign * maxPitchCorrectionRate * arrivalInfluence
|
||||
// Calculate the signed error (how far and in what direction)
|
||||
val rollError = Mth.wrapDegrees(desiredRoll.angleDifference(controller.roll))
|
||||
|
||||
// Use the absolute error to calculate the magnitude of the influence
|
||||
val influenceMagnitude = (min(rollArrivalDeg, abs(rollError)) / rollArrivalDeg)
|
||||
val desiredRollForce = maxRollCorrectionRate * influenceMagnitude * -rollError.sign
|
||||
var steeredRollForce = desiredRollForce - state.currRollCorrectionForce.get()
|
||||
|
||||
// Ensure the 'steering' correction force doesn't exceed our maxForce
|
||||
if (abs(steeredRollForce) > maxRollForce) {
|
||||
steeredRollForce = steeredRollForce.sign * maxRollForce
|
||||
}
|
||||
|
||||
// Apply the 'steered' force (its really not a steering force I need a better name)
|
||||
state.currRollCorrectionForce.set(
|
||||
state.currRollCorrectionForce.get() + steeredRollForce
|
||||
)
|
||||
|
||||
//Calculate correcting pitch force.
|
||||
val maxPitchCorrectionRate = 5.0f * (state.noInputTime.get() - rollCorrectionTimer).coerceIn(0.0, 1.0).pow(2).toFloat()*0.5f
|
||||
val maxPitchForce = maxPitchCorrectionRate / 40.0f
|
||||
val pitchArrivalDeg = 45.0f
|
||||
val desiredPitch = 0.0f
|
||||
|
||||
if(state.rideVelocity.get().length() < 0.1 && state.noInputTime.get() > rollCorrectionTimer) {
|
||||
val pitchErrror = Mth.wrapDegrees(desiredPitch.angleDifference(controller.pitch))
|
||||
val arrivalInfluence = (min(pitchArrivalDeg,abs(pitchErrror)) / pitchArrivalDeg)
|
||||
val desiredPitchForce = maxPitchCorrectionRate * arrivalInfluence * -pitchErrror.sign
|
||||
var steeredPitchForce = desiredPitchForce - state.currPitchCorrectionForce.get()
|
||||
|
||||
// Ensure the 'steering' correction force doesn't exceed our maxForce
|
||||
@@ -333,130 +358,72 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
} else {
|
||||
state.noInputTime.set(0.0)
|
||||
}
|
||||
return when {
|
||||
Cobblemon.config.disableRoll -> noRollRotation(
|
||||
settings,
|
||||
state,
|
||||
vehicle,
|
||||
driver,
|
||||
mouseY,
|
||||
mouseX,
|
||||
mouseYSmoother,
|
||||
mouseXSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
)
|
||||
else -> rollRotation(
|
||||
settings,
|
||||
state,
|
||||
vehicle,
|
||||
driver,
|
||||
mouseY,
|
||||
mouseX,
|
||||
mouseYSmoother,
|
||||
mouseXSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun noRollRotation(
|
||||
settings: DolphinSettings,
|
||||
state: DolphinState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
|
||||
// Set roll to zero if transitioning to noroll config
|
||||
controller.rotateRoll(controller.roll * -1.0f)
|
||||
|
||||
val boostingHandleDebuff = if (state.boosting.get()) 0.2 else 1.0
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr ?: globalDolphin.handlingExpr!!) * boostingHandleDebuff
|
||||
val mouseInputMult = vehicle.runtime.resolveDouble(settings.mouseInputMult ?: globalDolphin.mouseInputMult!!)
|
||||
|
||||
//Smooth out mouse input.
|
||||
val smoothingSpeed = 4.0
|
||||
val mouseXc = ((mouseX).coerceIn(-60.0, 60.0) / 60.0) * mouseInputMult
|
||||
val mouseYc = ((mouseY).coerceIn(-60.0, 60.0) / 60.0) * mouseInputMult
|
||||
val xInput = mouseXSmoother.getNewDeltaValue(mouseXc * 0.1, deltaTime * smoothingSpeed);
|
||||
val yInput = mouseYSmoother.getNewDeltaValue(mouseYc * 0.1, deltaTime * smoothingSpeed);
|
||||
|
||||
//Give the ability to yaw with x mouse input when at low speeds.
|
||||
val yawForce = xInput * handling
|
||||
|
||||
//Apply yaw globally as we don't want roll or pitch changes due to local yaw when looking up or down.
|
||||
controller.applyGlobalYaw(yawForce.toFloat() * abs(cos(controller.pitch.toRadians())).pow(2))
|
||||
|
||||
var pitchRot = yInput * handling
|
||||
|
||||
// Pitch up globally
|
||||
if (abs(controller.pitch + pitchRot) >= 89.5 ) {
|
||||
pitchRot = 0.0
|
||||
mouseYSmoother.reset()
|
||||
} else {
|
||||
controller.applyGlobalPitch(pitchRot.toFloat() * -1.0f)
|
||||
}
|
||||
|
||||
//yaw, pitch, roll
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
fun rollRotation(
|
||||
settings: DolphinSettings,
|
||||
state: DolphinState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
if (vehicle !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (vehicle as OrientationControllable).orientationController
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr ?: globalDolphin.speedExpr!!) / 20.0
|
||||
val boostingHandleDebuff = if (state.boosting.get()) 0.2 else 1.0
|
||||
val boostingHandleDebuff = if (state.boosting.get()) 0.5 else 1.0
|
||||
val mouseInputMult = vehicle.runtime.resolveDouble(settings.mouseInputMult ?: globalDolphin.mouseInputMult!!) * boostingHandleDebuff
|
||||
// Applied to mouseX to prevent turning upside down when trying to roll hard.
|
||||
val rollDegreeDebuff = if(mouseX.sign.toFloat() == controller.roll.sign) 1 - 0.9f*sqrt(abs(sin(controller.roll.toRadians())))*sqrt(abs(cos(controller.pitch))) else 1.0f
|
||||
|
||||
//Smooth out mouse input.
|
||||
val smoothingSpeed = 4.0
|
||||
val mouseXc = (mouseX).coerceIn(-45.0, 45.0) * mouseInputMult
|
||||
val mouseYc = (mouseY).coerceIn(-45.0, 45.0) * mouseInputMult
|
||||
val xInput = mouseXSmoother.getNewDeltaValue(mouseXc * 0.1, deltaTime * smoothingSpeed);
|
||||
val yInput = mouseYSmoother.getNewDeltaValue(mouseYc * 0.1, deltaTime * smoothingSpeed);
|
||||
val currSpeed = vehicle.deltaMovement.length()
|
||||
val smoothingSpeed = if(state.hasBreached.get()) 1.0f else 2.0f
|
||||
// When upside down apply a pitching force to nudge the player towards a dive. This reduces the 'weirdness'
|
||||
// of being upside down
|
||||
val rolledOverPitchCorrection = -8*sqrt(abs(min(cos(controller.roll.toRadians()),0.0f))) * (cos(controller.pitch.toRadians())).pow(2)
|
||||
val mouseXc = (mouseX).coerceIn(-45.0, 45.0) * mouseInputMult * rollDegreeDebuff
|
||||
val mouseYc = (mouseY).coerceIn(-45.0, 45.0) * mouseInputMult + rolledOverPitchCorrection
|
||||
val mouseModForce = if (state.hasBreached.get()) 0.15 else 0.1 // Used to effect more spin momentum during breaching
|
||||
|
||||
// Yaw locally
|
||||
// Dampen yaw when rolled or pitched substantially
|
||||
val yawDampen = abs(cos(controller.pitch.toRadians())).pow(2) * abs(cos(controller.roll.toRadians())).pow(2)
|
||||
val localYaw = xInput * (1 - (RidingBehaviour.scaleToRange(currSpeed, 0.0, topSpeed))).coerceIn(0.4, 1.0) * yawDampen
|
||||
if (state.clearMouseSmoothers.get()) {
|
||||
mouseXSmoother.reset()
|
||||
mouseYSmoother.reset()
|
||||
state.clearMouseSmoothers.set(false)
|
||||
}
|
||||
val xInput = mouseXSmoother.getNewDeltaValue(mouseXc * mouseModForce, deltaTime * smoothingSpeed);
|
||||
val yInput = mouseYSmoother.getNewDeltaValue(mouseYc * mouseModForce, deltaTime * smoothingSpeed);
|
||||
val currSpeed = state.rideVelocity.get().length()
|
||||
val currHorzSpeed = state.rideVelocity.get().horizontalDistance()
|
||||
val hoverSpeed = 0.2
|
||||
val pitchDamping = abs(cos(controller.pitch.toRadians())).pow(2) // Helper value used when wanting to discard the influence of another value at steep pitches
|
||||
|
||||
// Yaw locally when at or below hoverSpeed but not when pitched up or rolled over
|
||||
val globalYaw = xInput * (1 - sqrt(RidingBehaviour.scaleToRange(currSpeed, 0.0, hoverSpeed))).coerceIn(0.0, 1.0)
|
||||
controller.rotateYaw(pitchDamping*globalYaw.toFloat())
|
||||
controller.rotateRoll((1-pitchDamping)*globalYaw.toFloat())
|
||||
|
||||
// Pitch locally up or down depending upon a number of factors:
|
||||
// - Reduce pitch substantially when rolled and in a steep yaw. This prevents the player from ignoring a slow handling stat
|
||||
// - Do not pitch at all when at or below hover speed
|
||||
// - pitch faster at higher speeds
|
||||
val p = 1.0 - vehicle.runtime.resolveDouble(settings.horizontalPitchExpr ?: globalDolphin.horizontalPitchExpr!!)
|
||||
val localPitch = yInput * (1 - abs(sin(controller.roll.toRadians())) * p * hypot(controller.forwardVector.x.toDouble(), controller.forwardVector.z.toDouble()).toFloat())
|
||||
// localPitch *= if (currSpeed > hoverSpeed) RidingBehaviour.scaleToRange(currSpeed, hoverSpeed, topSpeed)
|
||||
// else 0.0
|
||||
val localPitch = yInput * (1 - abs(sin(controller.roll.toRadians())).pow(2) * p * hypot(controller.forwardVector.x.toDouble(), controller.forwardVector.z.toDouble()).toFloat())
|
||||
|
||||
var localYawForce = 0.0
|
||||
var rollForce = 0.0
|
||||
|
||||
// If it has breached then turn the yaw into roll
|
||||
if (state.hasBreached.get()) {
|
||||
localYawForce = xInput
|
||||
} else {
|
||||
// Roll less when slow and not at all when at hoverSpeed or lower.
|
||||
// Apply a roll righting force when trying to pitch hard while rolled sideways. This nudges the player towards
|
||||
// pitching globally
|
||||
val pitchInfluencedRollCorrection = 0.0
|
||||
val howRolledAmI = (( cos(controller.roll.toRadians()) - 1).coerceIn(-1.0f, 0.0f) * -2) //Coerce into how much roll you want to let in in the deadzone
|
||||
val isInputtingTowardsRoll = if ( xInput.sign == controller.roll.sign.toDouble()) 1.0 else 0.0
|
||||
val inputInRolledDir = if (isInputtingTowardsRoll == 1.0) 1.0 else -cos(controller.roll.toRadians()).coerceIn(-1.0f, 0.0f).toDouble()
|
||||
val rollDampen = (1 - howRolledAmI.coerceIn(0.0f, 0.5f) * pitchDamping * inputInRolledDir)
|
||||
rollForce = xInput * sqrt(abs(RidingBehaviour.scaleToRange(currHorzSpeed, 0.0, topSpeed)).coerceIn(0.0,1.0)) * rollDampen + pitchInfluencedRollCorrection
|
||||
|
||||
// When already rolled significantly part of the roll force should turn to local yaw force
|
||||
localYawForce = rollForce * abs(sin(controller.roll.toRadians())).pow(2) * pitchDamping * isInputtingTowardsRoll
|
||||
}
|
||||
|
||||
// Roll less when slow and not at all when at hoverSpeed or lower.
|
||||
// Apply a roll righting force when trying to pitch hard while rolled sideways. This nudges the player towards
|
||||
// pitching globally
|
||||
val rollForce = xInput * ((RidingBehaviour.scaleToRange(currSpeed, 0.0, topSpeed))).coerceIn(0.2, 1.0) //+ pitchInfluencedRollCorrection
|
||||
|
||||
//yaw, pitch, roll
|
||||
return Vec3(localYaw, localPitch, rollForce)
|
||||
return Vec3(localYawForce, localPitch, rollForce)
|
||||
}
|
||||
|
||||
override fun canJump(
|
||||
@@ -640,6 +607,7 @@ class DolphinState : RidingBehaviourState() {
|
||||
var boostIsToggleable = ridingState(false, Side.CLIENT)
|
||||
var speed = ridingState(0.0, Side.CLIENT)
|
||||
var hasBreached = ridingState(false, Side.CLIENT)
|
||||
var clearMouseSmoothers = ridingState(false, Side.CLIENT)
|
||||
|
||||
override fun encode(buffer: FriendlyByteBuf) {
|
||||
super.encode(buffer)
|
||||
@@ -661,6 +629,7 @@ class DolphinState : RidingBehaviourState() {
|
||||
boostIsToggleable.set(true, forced = true)
|
||||
speed.set(0.0, forced = true)
|
||||
hasBreached.set(false, forced = true)
|
||||
clearMouseSmoothers.set(false, forced = true)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
@@ -678,6 +647,7 @@ class DolphinState : RidingBehaviourState() {
|
||||
it.boostIsToggleable.set(this.boosting.get(), forced = true)
|
||||
it.speed.set(this.speed.get(), forced = true)
|
||||
it.hasBreached.set(this.hasBreached.get(), forced = true)
|
||||
it.clearMouseSmoothers.set(this.clearMouseSmoothers.get(), forced = true)
|
||||
}
|
||||
|
||||
override fun shouldSync(previous: RidingBehaviourState): Boolean {
|
||||
|
||||
+647
@@ -0,0 +1,647 @@
|
||||
/*
|
||||
* 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.behaviour.types.liquid
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.MoLangMath.lerp
|
||||
import com.cobblemon.mod.common.CobblemonRideSettings
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.*
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseOption
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.api.riding.sound.RideSoundSettingsList
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import com.cobblemon.mod.common.util.readNullableExpression
|
||||
import com.cobblemon.mod.common.util.readRidingStats
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.resolveDouble
|
||||
import com.cobblemon.mod.common.util.toVec3d
|
||||
import com.cobblemon.mod.common.util.writeNullableExpression
|
||||
import com.cobblemon.mod.common.util.writeRidingStats
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.tags.FluidTags
|
||||
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 org.joml.Vector3f
|
||||
import kotlin.math.*
|
||||
|
||||
class SubmarineBehaviour : RidingBehaviour<SubmarineSettings, SubmarineState> {
|
||||
companion object {
|
||||
val KEY = cobblemonResource("liquid/submarine")
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
val globalSubmarine: SubmarineSettings
|
||||
get() = CobblemonRideSettings.submarine
|
||||
|
||||
override fun getRidingStyle(settings: SubmarineSettings, state: SubmarineState): RidingStyle {
|
||||
return RidingStyle.LIQUID
|
||||
}
|
||||
|
||||
val poseProvider = PoseProvider<SubmarineSettings, SubmarineState>(PoseType.FLOAT)
|
||||
.with(PoseOption(PoseType.SWIM) { _, state, entity -> abs(state.rideVelocity.get().z) > 0.05 && !state.onSurface.get()})
|
||||
.with(PoseOption(PoseType.STAND) { _, state, entity -> abs(state.rideVelocity.get().z) <= 0.05 && state.onSurface.get()})
|
||||
.with(PoseOption(PoseType.STAND) { _, state, entity -> abs(state.rideVelocity.get().z) > 0.05 && state.onSurface.get()})
|
||||
|
||||
override fun isActive(settings: SubmarineSettings, state: SubmarineState, vehicle: PokemonEntity): Boolean {
|
||||
return vehicle.isInWater || !vehicle.onGround()
|
||||
}
|
||||
|
||||
override fun pose(settings: SubmarineSettings, state: SubmarineState, vehicle: PokemonEntity): PoseType {
|
||||
return poseProvider.select(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun speed(settings: SubmarineSettings, state: SubmarineState, vehicle: PokemonEntity, driver: Player): Float {
|
||||
return state.speed.get().toFloat()
|
||||
}
|
||||
|
||||
override fun tick(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
) {
|
||||
if(vehicle.level().isClientSide) {
|
||||
tickStamina(settings, state, vehicle)
|
||||
surfaceCheck(settings, state, vehicle, driver)
|
||||
}
|
||||
}
|
||||
|
||||
fun tickStamina(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity
|
||||
) {
|
||||
val stam = state.stamina.get()
|
||||
|
||||
if (vehicle.runtime.resolveBoolean(settings.infiniteStamina ?: globalSubmarine.infiniteStamina!!)) {
|
||||
return
|
||||
}
|
||||
|
||||
// Grab the boost time in seconds and convert to ticks. Then calculate the drain rate as inversely
|
||||
// proportional to the number of ticks of boost thus making a full boost take x ticks
|
||||
// in short: "Stamina drains slower at higher values and also replenishes slower"
|
||||
val breathTime = vehicle.runtime.resolveDouble(settings.staminaExpr ?: globalSubmarine.staminaExpr!!) * 20.0f
|
||||
val stamRegenRate = 1.0f / (vehicle.runtime.resolveDouble(settings.staminaRegenTime ?: globalSubmarine.staminaRegenTime!!).toFloat() * 20.0f)
|
||||
val stamDrainRate = (1.0f / breathTime).toFloat()
|
||||
val driver = vehicle.controllingPassenger
|
||||
val newStam = if (driver?.isEyeInFluid(FluidTags.WATER) ?: false) max(0.0f,stam - stamDrainRate)
|
||||
else min(1.0f,stam + stamRegenRate)
|
||||
|
||||
state.stamina.set(newStam)
|
||||
}
|
||||
|
||||
private fun surfaceCheck(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
) {
|
||||
// determine if the vehicle is in water.
|
||||
// if it isn't then set surface flag to false and return
|
||||
if (!vehicle.isInWater) {
|
||||
state.onSurface.set(false)
|
||||
return
|
||||
}
|
||||
|
||||
val hitboxBreachPercentage = vehicle.runtime.resolveDouble(settings.hitboxBreachPercentage ?: globalSubmarine.hitboxBreachPercentage!!)
|
||||
|
||||
// Grab the position of the vehicle that when out of the water is considered breached
|
||||
val vehicleBreachPoint = vehicle.position().add(0.0, vehicle.bbHeight * hitboxBreachPercentage, 0.0)
|
||||
|
||||
// If the block above the center is not fluid but this one is then move the center
|
||||
val centerBlockPos = BlockPos.containing(vehicleBreachPoint)
|
||||
val centerInWater = !vehicle.level().getFluidState(centerBlockPos).isEmpty
|
||||
|
||||
val abovePos = centerBlockPos.above()
|
||||
val aboveInWater = !vehicle.level().getFluidState(abovePos).isEmpty
|
||||
|
||||
if (!centerInWater && !aboveInWater) {
|
||||
state.onSurface.set(true)
|
||||
} else {
|
||||
state.onSurface.set(false)
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
// Function for if x mouse and y mouse "get through" to affecting the mounts rotation. Return a Pair<Boolean, Boolean>
|
||||
}
|
||||
|
||||
override fun rotation(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
return Vec2(driver.xRot * 0.5f, driver.yRot)
|
||||
}
|
||||
|
||||
override fun velocity(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
if (vehicle !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (vehicle as OrientationControllable).orientationController
|
||||
val orientation = controller.orientation ?: return Vec3.ZERO
|
||||
|
||||
val runtime = vehicle.runtime
|
||||
val topSpeed = (vehicle.runtime.resolveDouble(settings.speedExpr ?: globalSubmarine.speedExpr!!) / 20.0)
|
||||
val accel = (topSpeed / (vehicle.runtime.resolveDouble(settings.accelerationExpr ?: globalSubmarine.accelerationExpr!!) * 20.0))
|
||||
val strafeSpeed = (runtime.resolveDouble(settings.jumpExpr ?: globalSubmarine.jumpExpr!!) / 20.0)
|
||||
val strafeAccel = (strafeSpeed / (vehicle.runtime.resolveDouble(settings.accelerationExpr ?: globalSubmarine.accelerationExpr!!) * 20.0))
|
||||
var currVel = state.rideVelocity.get()
|
||||
|
||||
/*********************************************
|
||||
* Handle collisions
|
||||
*********************************************/
|
||||
if (vehicle.horizontalCollision || vehicle.verticalCollision) {
|
||||
// not actually friction
|
||||
val frictionLimit = 0.1
|
||||
val postColSpeed = min(max(state.rideVelocity.get().length(), frictionLimit), state.speed.get())
|
||||
state.speed.set(postColSpeed)
|
||||
}
|
||||
if (vehicle.verticalCollision) {
|
||||
state.rideVelocity.set(Vec3(state.rideVelocity.get().x, 0.0, state.rideVelocity.get().z))
|
||||
}
|
||||
|
||||
/*********************************************
|
||||
* Calculate Forward Velocity
|
||||
*********************************************/
|
||||
val currZVel = state.rideVelocity.get().z
|
||||
val newZVel = when {
|
||||
driver.zza > 0.0 -> min(topSpeed, currZVel + accel)
|
||||
driver.zza < 0.0 -> max( -strafeSpeed, currZVel - strafeAccel) //TODO: Might need to be applied in addition to the normal braking force?
|
||||
else -> lerp(currZVel, 0.0, 0.05)
|
||||
}
|
||||
currVel = Vec3(currVel.x, currVel.y, newZVel)
|
||||
|
||||
/*********************************************
|
||||
* Calculate up/down Velocity and gravity
|
||||
*********************************************/
|
||||
val vertTopSpeed = strafeSpeed
|
||||
val currYVel = state.rideVelocity.get().y
|
||||
val gravity = (9.8 / ( 20.0)) * 0.2 * 0.4
|
||||
val terminalYVel = 2.0
|
||||
val driverYInput = if(driver.jumping) 1.0 else if (driver.isShiftKeyDown) -1.0 else 0.0
|
||||
val newYVel = when {
|
||||
(!vehicle.isInWater) -> max(-terminalYVel, currYVel - gravity)
|
||||
//(vehicle.isInWater && !vehicle.isUnderWater && currYVel > 0.001) -> lerp(currYVel, 0.0, 0.1) // Make sure that yVel is above a threshold before doing this otherwise it'll block submerging.
|
||||
//driverYInput != 0.0 && currYVel > 0.001 && driverYInput.sign != currYVel.sign -> lerp(currYVel, 0.0, 0.05)
|
||||
driverYInput > 0.0 -> min(vertTopSpeed, currYVel + strafeAccel)
|
||||
driverYInput < 0.0 -> max(-vertTopSpeed, currYVel - strafeAccel)
|
||||
else -> lerp(currYVel, 0.0, 0.05)
|
||||
}
|
||||
currVel = Vec3(currVel.x, newYVel, currVel.z)
|
||||
|
||||
/*********************************************
|
||||
* Calculate left/right strafing Velocity
|
||||
*********************************************/
|
||||
val currXVel = state.rideVelocity.get().x
|
||||
val horzTopSpeed = strafeSpeed
|
||||
val newXVel = when {
|
||||
driver.xxa > 0.0 -> min(horzTopSpeed, currXVel + strafeAccel)
|
||||
driver.xxa < 0.0 -> max( -horzTopSpeed, currXVel - strafeAccel)
|
||||
else -> lerp(currXVel, 0.0, 0.01)
|
||||
}
|
||||
currVel = Vec3(newXVel, currVel.y, currVel.z)
|
||||
|
||||
// Set the new velocity
|
||||
state.rideVelocity.set(currVel)
|
||||
|
||||
/*********************************************
|
||||
* Separate and apply velocities
|
||||
*********************************************/
|
||||
// If the driver and vehicles eyes are out of the water but the vehicle is still in it then move only horizontally or downwards as you have surfaced
|
||||
if (state.onSurface.get()) {
|
||||
val worldVelVec = Vec3(currVel.x, min(0.0, currVel.y), currVel.z)
|
||||
return worldVelVec
|
||||
} else {
|
||||
val vertVec = Vec3(0.0, currVel.y, 0.0)
|
||||
val horzVec = Vec3(currVel.x, 0.0, 0.0)
|
||||
val localZVelVec = Vector3f(0.0f, 0.0f, currVel.z.toFloat() * -1.0f) // Flip the z axis to make this left handed
|
||||
// Unrotate preemptively as this vector gets rotated later down the line in MC logic.
|
||||
val worldVelVec = localZVelVec.mul(orientation).toVec3d().yRot(vehicle.yRot.toRadians())
|
||||
// Add back the horizontal and vertical components.
|
||||
return worldVelVec.add(vertVec).add(horzVec)
|
||||
}
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun applyRenderRotation(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity,
|
||||
partialTicks: Float
|
||||
) {
|
||||
if (vehicle !is OrientationControllable) return
|
||||
val controller = (vehicle as OrientationControllable).orientationController
|
||||
|
||||
var handling = vehicle.runtime.resolveDouble(settings.handlingExpr ?: globalSubmarine.handlingExpr!!)
|
||||
val surfaceHandlingBoost = if(state.onSurface.get()) 3.0 else 1.0
|
||||
handling *= surfaceHandlingBoost
|
||||
|
||||
val strafeSpeed = (vehicle.runtime.resolveDouble(settings.jumpExpr ?: globalSubmarine.jumpExpr!!) / 20.0)
|
||||
|
||||
// Grab the roll and see if its hit the limit yet. If it hasn't then trend it towards its desired roll
|
||||
val maxRollDeg = if (state.onSurface.get()) 5 else 15
|
||||
val maxPitchDeg = 15
|
||||
var rollAmount = 0.0
|
||||
var pitchAmount = 0.0
|
||||
|
||||
// Do horizontal speed based rolling
|
||||
val maxHorzSpeed = strafeSpeed
|
||||
val currHorzSpeed = state.rideVelocity.get().x
|
||||
var desiredRoll = -(currHorzSpeed / maxHorzSpeed).coerceIn(-1.0, 1.0) * maxRollDeg
|
||||
rollAmount += lerp(controller.roll.toDouble(), desiredRoll, partialTicks.toDouble()) - controller.roll
|
||||
//val rotAmount //Maybe use some lerp?
|
||||
controller.rotateRoll(rollAmount.toFloat())
|
||||
|
||||
// Do yawRate based rolling
|
||||
val maxYawRate = handling
|
||||
val currYawRate = vehicle.ridingAnimationData.rotDeltaSpring.getInterpolated(partialTicks.toDouble(), 2).y()
|
||||
desiredRoll = -(currYawRate / maxYawRate).coerceIn(-1.0, 1.0) * maxRollDeg
|
||||
rollAmount += desiredRoll - controller.roll
|
||||
controller.rotateRoll(rollAmount.toFloat())
|
||||
|
||||
//TODO: why does this affect the actual controller but rolling doesn't??
|
||||
// Do upwards movement based pitching
|
||||
// val maxVertSpeed = 0.25 //TODO: CONNECT UP TO JUMP
|
||||
// val currVertSpeed = state.rideVelocity.get().y
|
||||
// var desiredPitch = -(currVertSpeed / maxVertSpeed) * maxPitchDeg
|
||||
// pitchAmount += lerp(controller.pitch.toDouble(), desiredPitch, partialTicks.toDouble()) - controller.pitch
|
||||
// controller.rotatePitch(pitchAmount.toFloat())
|
||||
|
||||
}
|
||||
|
||||
private fun correctOrientation(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity,
|
||||
controller: OrientationController,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
) {
|
||||
|
||||
// TODO: remove if not needed
|
||||
|
||||
// // Calculate correcting roll force.
|
||||
// // If the ride is moving then have the correction rate be an equal proportion of:
|
||||
// // - how rolled are you
|
||||
// // - how long has it been since last mouse input (higher is stronger correction)
|
||||
// // Also the correction is proportional as a whole to how NOT pitched are you so you don't spin endlessly when looking up or down
|
||||
// val howRolledAmI = sqrt(abs((cos(controller.roll.toRadians()) - 1.0f) * 0.5f)) // sqrt so it trends towards one pretty quickly
|
||||
// val maxRollCorrectionRate =
|
||||
// if (state.rideVelocity.get().length() < 0.2) 10.0f * abs(cos(controller.pitch.toRadians()))
|
||||
// else 10.0f * cos(controller.pitch.toRadians()).pow(2) * (
|
||||
// howRolledAmI*1.0f +
|
||||
// (state.noInputTime.get() - rollCorrectionTimer).coerceIn(0.0, 1.0).pow(2).toFloat()*0.5f
|
||||
// )
|
||||
// val maxRollForce = maxRollCorrectionRate / 40.0f
|
||||
// val rollArrivalDeg = 60.0f
|
||||
// val desiredRoll = 0.0f
|
||||
//
|
||||
// // Calculate the signed error (how far and in what direction)
|
||||
// val rollError = Mth.wrapDegrees(desiredRoll.angleDifference(controller.roll))
|
||||
//
|
||||
// // Use the absolute error to calculate the magnitude of the influence
|
||||
// val influenceMagnitude = (min(rollArrivalDeg, abs(rollError)) / rollArrivalDeg)
|
||||
// val desiredRollForce = maxRollCorrectionRate * influenceMagnitude * -rollError.sign
|
||||
// var steeredRollForce = desiredRollForce - state.currRollCorrectionForce.get()
|
||||
//
|
||||
// // Ensure the 'steering' correction force doesn't exceed our maxForce
|
||||
// if (abs(steeredRollForce) > maxRollForce) {
|
||||
// steeredRollForce = steeredRollForce.sign * maxRollForce
|
||||
// }
|
||||
//
|
||||
// // Apply the 'steered' force (its really not a steering force I need a better name)
|
||||
// state.currRollCorrectionForce.set(
|
||||
// state.currRollCorrectionForce.get() + steeredRollForce
|
||||
// )
|
||||
|
||||
//Calculate correcting pitch force.
|
||||
// val rollCorrectionTimer = vehicle.runtime.resolveDouble(settings.timeToRollCorrect ?: globalSubmarine.timeToRollCorrect!!)
|
||||
// val maxPitchCorrectionRate = 5.0f * (state.noInputTime.get() - rollCorrectionTimer).coerceIn(0.0, 1.0).pow(2).toFloat()*0.5f
|
||||
// val maxPitchForce = maxPitchCorrectionRate / 40.0f
|
||||
// val pitchArrivalDeg = 45.0f
|
||||
// val desiredPitch = 0.0f
|
||||
//
|
||||
// if(state.rideVelocity.get().length() < 0.1 && state.noInputTime.get() > rollCorrectionTimer) {
|
||||
// val pitchErrror = Mth.wrapDegrees(desiredPitch.angleDifference(controller.pitch))
|
||||
// val arrivalInfluence = (min(pitchArrivalDeg,abs(pitchErrror)) / pitchArrivalDeg)
|
||||
// val desiredPitchForce = maxPitchCorrectionRate * arrivalInfluence * -pitchErrror.sign
|
||||
// var steeredPitchForce = desiredPitchForce - state.currPitchCorrectionForce.get()
|
||||
//
|
||||
// // Ensure the 'steering' correction force doesn't exceed our maxForce
|
||||
// if (abs(steeredPitchForce) > maxPitchForce) {
|
||||
// steeredPitchForce = steeredPitchForce.sign * maxPitchForce
|
||||
// }
|
||||
//
|
||||
// // Apply the 'steered' force (its really not a steering force I need a better name)
|
||||
// state.currPitchCorrectionForce.set(
|
||||
// state.currPitchCorrectionForce.get() + steeredPitchForce
|
||||
// )
|
||||
// } else {
|
||||
// state.currPitchCorrectionForce.set(
|
||||
// //reduce rollCorrection gradually
|
||||
// lerp(state.currPitchCorrectionForce.get(), 0.0, deltaTime * 0.98)
|
||||
// )
|
||||
// }
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (vehicle !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (vehicle as OrientationControllable).orientationController
|
||||
|
||||
// Set roll to zero if transitioning to noroll config
|
||||
controller.rotateRoll(controller.roll * -1.0f)
|
||||
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr ?: globalSubmarine.handlingExpr!!)
|
||||
val surfaceHandlingBoost = if(state.onSurface.get()) 3.0 else 1.0
|
||||
val effHandling = if(state.onSurface.get()) 1000 * deltaTime else handling * deltaTime
|
||||
//Smooth out mouse input.
|
||||
val smoothingSpeed = if(state.onSurface.get()) 10.0 else 2.0
|
||||
val mouseXc = (mouseX * 0.1).coerceIn(-effHandling, effHandling)
|
||||
val mouseYc = (mouseY * 0.1).coerceIn(-effHandling, effHandling)
|
||||
val xInput = mouseXSmoother.getNewDeltaValue(mouseXc, deltaTime * smoothingSpeed);
|
||||
val yInput = mouseYSmoother.getNewDeltaValue(mouseYc, deltaTime * smoothingSpeed);
|
||||
|
||||
// Give the ability to yaw with x mouse input when at low speeds.
|
||||
val yawForce = xInput
|
||||
|
||||
// Apply yaw globally as we don't want roll or pitch changes due to local yaw when looking up or down.
|
||||
controller.applyGlobalYaw(yawForce.toFloat())
|
||||
|
||||
var pitchRot = yInput
|
||||
// Pitch up globally
|
||||
val pitchLimit = 45.0
|
||||
if (abs(controller.pitch + pitchRot) >= pitchLimit ) {
|
||||
pitchRot = 0.0
|
||||
mouseYSmoother.reset()
|
||||
} else {
|
||||
controller.applyGlobalPitch(pitchRot.toFloat())
|
||||
}
|
||||
|
||||
// If on the surface then conditionally bring the pitch to 0 degrees.
|
||||
if (state.onSurface.get()) {
|
||||
//move back at max 30 degrees per second.
|
||||
val maxCorrectionSpeed = 30.0
|
||||
val arrivalDegreeWidth = 30.0
|
||||
val currentPitch = controller.pitch
|
||||
val correctionDegrees = (-currentPitch / arrivalDegreeWidth).coerceIn(-1.0, 1.0) * maxCorrectionSpeed * deltaTime
|
||||
|
||||
controller.applyGlobalPitch(correctionDegrees.toFloat())
|
||||
|
||||
// Compensate player ride rotations
|
||||
// val playerRotater = driver as RideRotation
|
||||
// playerRotater.`cobblemon$setRideXRot`(playerRotater.`cobblemon$getRideXRot`() - correctionDegrees.toFloat() )
|
||||
}
|
||||
|
||||
//yaw, pitch, roll
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun canJump(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun setRideBar(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return (state.stamina.get() / 1.0f)
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
): Vec3 {
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun gravity(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity,
|
||||
regularGravity: Double
|
||||
): Double {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
override fun rideFovMultiplier(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return 1.0f
|
||||
}
|
||||
|
||||
override fun useAngVelSmoothing(settings: SubmarineSettings, state: SubmarineState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun useRidingAltPose(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): ResourceLocation {
|
||||
return cobblemonResource("no_pose")
|
||||
}
|
||||
|
||||
override fun inertia(settings: SubmarineSettings, state: SubmarineState, vehicle: PokemonEntity): Double {
|
||||
return if (!vehicle.isUnderWater) 1.0 else 0.1
|
||||
}
|
||||
|
||||
override fun shouldRoll(settings: SubmarineSettings, state: SubmarineState, vehicle: PokemonEntity): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun turnOffOnGround(settings: SubmarineSettings, state: SubmarineState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun dismountOnShift(settings: SubmarineSettings, state: SubmarineState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun mouseModifiesDriverRotation(settings: SubmarineSettings, state: SubmarineState, vehicle: PokemonEntity): Pair<Boolean, Boolean> {
|
||||
return Pair(false, state.onSurface.get())
|
||||
}
|
||||
|
||||
override fun shouldRotatePokemonHead(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotateRiderHead(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun getRideSounds(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity
|
||||
): RideSoundSettingsList {
|
||||
return settings.rideSounds
|
||||
}
|
||||
|
||||
override fun createDefaultState(settings: SubmarineSettings) = SubmarineState()
|
||||
|
||||
}
|
||||
|
||||
class SubmarineSettings : RidingBehaviourSettings {
|
||||
override val key = SubmarineBehaviour.KEY
|
||||
override val stats = mutableMapOf<RidingStat, IntRange>()
|
||||
|
||||
var infiniteStamina: Expression? = null
|
||||
private set
|
||||
|
||||
var staminaRegenTime: Expression? = null
|
||||
private set
|
||||
|
||||
// Percentage (0.0->1.0) of ride needing to be breached out of the water to be considered surfaced.
|
||||
var hitboxBreachPercentage: Expression? = null
|
||||
private set
|
||||
|
||||
// Tope strafe speed in Bl/s
|
||||
var jumpExpr: Expression? = null
|
||||
// Yaw rate in degrees per second
|
||||
var handlingExpr: Expression? = null
|
||||
// Top speed in Bl/s
|
||||
var speedExpr: Expression? = null
|
||||
// Seconds to get to top speed
|
||||
var accelerationExpr: Expression? = null
|
||||
// Seconds of air provided by mount
|
||||
var staminaExpr: Expression? = null
|
||||
|
||||
var rideSounds: RideSoundSettingsList = RideSoundSettingsList()
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeRidingStats(stats)
|
||||
rideSounds.encode(buffer)
|
||||
buffer.writeNullableExpression(infiniteStamina)
|
||||
buffer.writeNullableExpression(staminaRegenTime)
|
||||
buffer.writeNullableExpression(hitboxBreachPercentage)
|
||||
buffer.writeNullableExpression(jumpExpr)
|
||||
buffer.writeNullableExpression(handlingExpr)
|
||||
buffer.writeNullableExpression(speedExpr)
|
||||
buffer.writeNullableExpression(accelerationExpr)
|
||||
buffer.writeNullableExpression(staminaExpr)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
stats.putAll(buffer.readRidingStats())
|
||||
rideSounds = RideSoundSettingsList.decode(buffer)
|
||||
infiniteStamina = buffer.readNullableExpression()
|
||||
staminaRegenTime = buffer.readNullableExpression()
|
||||
hitboxBreachPercentage = buffer.readNullableExpression()
|
||||
jumpExpr = buffer.readNullableExpression()
|
||||
handlingExpr = buffer.readNullableExpression()
|
||||
speedExpr = buffer.readNullableExpression()
|
||||
accelerationExpr = buffer.readNullableExpression()
|
||||
staminaExpr = buffer.readNullableExpression()
|
||||
}
|
||||
}
|
||||
|
||||
class SubmarineState : RidingBehaviourState() {
|
||||
var speed = ridingState(0.0, Side.CLIENT)
|
||||
var currRollCorrectionForce = ridingState(0.0, Side.CLIENT)
|
||||
var currPitchCorrectionForce = ridingState(0.0, Side.CLIENT)
|
||||
var noInputTime = ridingState(0.0, Side.CLIENT)
|
||||
var onSurface = ridingState(false, Side.BOTH)
|
||||
|
||||
override fun encode(buffer: FriendlyByteBuf) {
|
||||
super.encode(buffer)
|
||||
buffer.writeBoolean(onSurface.get())
|
||||
}
|
||||
|
||||
override fun decode(buffer: FriendlyByteBuf) {
|
||||
super.decode(buffer)
|
||||
onSurface.set(buffer.readBoolean(), forced = true)
|
||||
}
|
||||
|
||||
override fun reset() {
|
||||
super.reset()
|
||||
speed.set(0.0, forced = true)
|
||||
currRollCorrectionForce.set(0.0, forced = true)
|
||||
currPitchCorrectionForce.set(0.0, forced = true)
|
||||
noInputTime.set(0.0, forced = true)
|
||||
onSurface.set(false, forced = true)
|
||||
}
|
||||
|
||||
override fun copy() = SubmarineState().also {
|
||||
it.stamina.set(stamina.get(), forced = true)
|
||||
it.speed.set(speed.get(), forced = true)
|
||||
it.rideVelocity.set(rideVelocity.get(), forced = true)
|
||||
it.currRollCorrectionForce.set(this.currRollCorrectionForce.get(), forced = true)
|
||||
it.currPitchCorrectionForce.set(this.currPitchCorrectionForce.get(), forced = true)
|
||||
it.noInputTime.set(this.noInputTime.get(), forced = true)
|
||||
it.onSurface.set(this.onSurface.get(), forced = true)
|
||||
}
|
||||
|
||||
override fun shouldSync(previous: RidingBehaviourState): Boolean {
|
||||
if (previous !is SubmarineState) return false
|
||||
if (previous.onSurface.get() != onSurface.get()) return true
|
||||
return super.shouldSync(previous)
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -74,7 +74,7 @@ class RidingAnimationData(val ride: PokemonEntity)
|
||||
}
|
||||
if( r ) {
|
||||
//TODO: should this return?
|
||||
val controller = (ride.firstPassenger as? OrientationControllable)?.orientationController ?: return
|
||||
val controller = (ride as? OrientationControllable)?.orientationController ?: return
|
||||
val orientation = controller.orientation ?: Matrix3f()
|
||||
|
||||
val currPitch = controller.pitch
|
||||
|
||||
@@ -33,15 +33,15 @@ class TimeRange : IntRanges {
|
||||
"any" to TimeRange(0..23999),
|
||||
"day" to TimeRange(23460..23999, 0..12541),
|
||||
"night" to TimeRange(12542..23459),
|
||||
"noon" to TimeRange(5000..6999),
|
||||
"midnight" to TimeRange(17000..18999),
|
||||
"dawn" to TimeRange(22300..23999, 0..999),
|
||||
"dusk" to TimeRange(11834..13701),
|
||||
"twilight" to TimeRange(11834..13701, 22300..23999, 0..166),
|
||||
"morning" to TimeRange(23000..23999, 0..4999),
|
||||
"noon" to TimeRange(5000..6999),
|
||||
"afternoon" to TimeRange(7000..12999),
|
||||
"predawn" to TimeRange(19000..22999),
|
||||
"evening" to TimeRange(13000..16999)
|
||||
"evening" to TimeRange(13000..16999),
|
||||
"midnight" to TimeRange(17000..18999),
|
||||
"predawn" to TimeRange(19000..22999),
|
||||
"dawn" to TimeRange(22300..23999, 0..166),
|
||||
"dusk" to TimeRange(11834..13701),
|
||||
"twilight" to TimeRange(11834..13701, 22300..23999, 0..166)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+2
-3
@@ -12,16 +12,15 @@ import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.fishing.BobberSpawnPokemonEvent
|
||||
import com.cobblemon.mod.common.api.fishing.SpawnBaitEffects
|
||||
import com.cobblemon.mod.common.api.fishing.SpawnBait
|
||||
import com.cobblemon.mod.common.api.fishing.SpawnBaitEffects
|
||||
import com.cobblemon.mod.common.api.pokemon.Natures
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnCause
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawnBaitInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.item.interactive.PokerodItem
|
||||
|
||||
+5
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.api.spawning.influence
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBlocks
|
||||
import com.cobblemon.mod.common.api.Priority
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
|
||||
import com.cobblemon.mod.common.api.spawning.fishing.FishingSpawnCause
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
|
||||
@@ -43,6 +44,10 @@ class SaccharineLogSlatheredInfluence(val pos: BlockPos? = null) : SpawningInflu
|
||||
|
||||
override fun affectSpawn(action: SpawnAction<*>, entity: Entity) {
|
||||
if (entity is PokemonEntity) {
|
||||
// avoid double application or applying to a pokemon that already has a hidden ability
|
||||
if (entity.pokemon.forcedAspects.contains(HONEY_DRENCHED_ASPECT)
|
||||
|| entity.pokemon.ability.priority !== Priority.LOWEST) return
|
||||
|
||||
if (Math.random() <= HIDDEN_ABILITY_CHANCE) {
|
||||
FishingSpawnCause.alterHAAttempt(entity)
|
||||
}
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ import kotlin.random.Random
|
||||
* @author Hiroku
|
||||
* @since February 14th, 2022
|
||||
*/
|
||||
class PlayerSpawner(
|
||||
open class PlayerSpawner(
|
||||
player: ServerPlayer,
|
||||
spawnPool: SpawnPool
|
||||
) : BasicSpawner(
|
||||
|
||||
+6
-1
@@ -20,6 +20,8 @@ import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
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.ActionEffectTimeline
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
|
||||
import com.cobblemon.mod.common.api.moves.animations.TargetsProvider
|
||||
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
@@ -31,6 +33,7 @@ import com.cobblemon.mod.common.battles.dispatch.UntilDispatch
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.pokemon.evolution.progress.UseMoveEvolutionProgress
|
||||
import com.cobblemon.mod.common.util.asArrayValue
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import java.util.concurrent.CompletableFuture
|
||||
@@ -49,7 +52,7 @@ class MoveInstruction(
|
||||
) : InterpreterInstruction, CauserInstruction {
|
||||
val effect = message.effectAt(1) ?: Effect.pure("", "")
|
||||
val move = Moves.getByNameOrDummy(effect.id)
|
||||
val actionEffect = move.actionEffect
|
||||
val actionEffect: ActionEffectTimeline? by lazy { ActionEffects.getEffectWithBattleContext(cobblemonResource(move.name), userPokemon) }
|
||||
val spreadTargets = message.optionalArgument("spread")?.split(",") ?: emptyList()
|
||||
|
||||
var future = CompletableFuture.completedFuture(Unit)
|
||||
@@ -61,6 +64,8 @@ class MoveInstruction(
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
userPokemon = message.battlePokemon(0, battle)!!
|
||||
targetPokemon = message.battlePokemon(2, battle)
|
||||
|
||||
val actionEffect = actionEffect ?: ActionEffects.actionEffects["generic_move".asIdentifierDefaultingNamespace()]
|
||||
val targetPokemon = targetPokemon // So smart non-null casts can happen
|
||||
|
||||
val optionalEffect = message.effect()
|
||||
|
||||
+9
-6
@@ -69,14 +69,17 @@ open class PokeSnackBlockEntity(pos: BlockPos, state: BlockState) :
|
||||
|
||||
val baitEffects = getBaitEffects()
|
||||
|
||||
val highestLureTier = baitEffects
|
||||
val stackedLureTier = baitEffects
|
||||
.filter { it.type == SpawnBait.Effects.RARITY_BUCKET }
|
||||
.maxOfOrNull { it.value }
|
||||
?.toInt()
|
||||
?: 0
|
||||
.sumOf { it.value }
|
||||
.toInt()
|
||||
|
||||
if (highestLureTier > 0) {
|
||||
it.influences += BucketNormalizingInfluence(tier = highestLureTier)
|
||||
if (stackedLureTier > 0) {
|
||||
it.influences += BucketNormalizingInfluence(
|
||||
tier = stackedLureTier,
|
||||
gradient = 0.2F,
|
||||
firstTier = 1.2F
|
||||
)
|
||||
}
|
||||
|
||||
it.influences += BucketMultiplyingInfluence(
|
||||
|
||||
@@ -56,8 +56,11 @@ object MountedCameraTypeHandler {
|
||||
data.updatePerspective(key, currentCameraType)
|
||||
}
|
||||
|
||||
fun handleTransition(fromKey: ResourceLocation, toKey: ResourceLocation) {
|
||||
fun handleTransition(passenger: Entity, fromKey: ResourceLocation, toKey: ResourceLocation) {
|
||||
val mc = Minecraft.getInstance()
|
||||
if (passenger == mc.player) {
|
||||
return
|
||||
}
|
||||
val currentCameraType = mc.options.cameraType
|
||||
val data = ClientPersistedData.ridingPerspectives
|
||||
data.updatePerspective(fromKey, currentCameraType)
|
||||
|
||||
@@ -491,6 +491,12 @@ class PokemonClientDelegate : PosableState(), PokemonSideDelegate {
|
||||
cryAnimation = animation
|
||||
}
|
||||
|
||||
override fun applyRenderRotation(partialTick: Float) {
|
||||
currentEntity.ifRidingAvailable { behaviour, settings, state ->
|
||||
behaviour.applyRenderRotation(settings, state, currentEntity, partialTick)
|
||||
}
|
||||
}
|
||||
|
||||
fun getSeatLocator(passenger: Entity): String {
|
||||
val seatIndex = this.getEntity().occupiedSeats.indexOf(passenger)
|
||||
if (seatIndex == -1) throw IllegalArgumentException("Entity is not currently riding a seat")
|
||||
|
||||
@@ -11,26 +11,25 @@ package com.cobblemon.mod.common.client.gui
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonItems
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.gui.drawPosablePortrait
|
||||
import com.cobblemon.mod.common.api.text.darkGray
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.client.CobblemonClient
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.gui.battle.BattleGUI
|
||||
import com.cobblemon.mod.common.client.gui.portrait.FullyAnimatedPortraitDrawer
|
||||
import com.cobblemon.mod.common.client.gui.portrait.SelectedAnimatedPortraitDrawer
|
||||
import com.cobblemon.mod.common.client.gui.portrait.InanimatePortraitDrawer
|
||||
import com.cobblemon.mod.common.client.gui.portrait.PortraitStyle
|
||||
import com.cobblemon.mod.common.client.gui.toast.CobblemonToast
|
||||
import com.cobblemon.mod.common.client.keybind.boundKey
|
||||
import com.cobblemon.mod.common.client.keybind.keybinds.HidePartyBinding
|
||||
import com.cobblemon.mod.common.client.keybind.keybinds.SummaryBinding
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.render.getDepletableRedGreen
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState
|
||||
import com.cobblemon.mod.common.client.render.renderScaledGuiItemIcon
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import java.util.UUID
|
||||
import net.minecraft.client.DeltaTracker
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.Gui
|
||||
@@ -58,12 +57,10 @@ class PartyOverlay : Gui(Minecraft.getInstance()) {
|
||||
private val genderIconMale = cobblemonResource("textures/gui/party/party_gender_male.png")
|
||||
private val genderIconFemale = cobblemonResource("textures/gui/party/party_gender_female.png")
|
||||
private val portraitBackground = cobblemonResource("textures/gui/party/party_slot_portrait_background.png")
|
||||
|
||||
private val inanimatePortraitDrawer = InanimatePortraitDrawer()
|
||||
private val selectedAnimatedPortraitDrawer = SelectedAnimatedPortraitDrawer()
|
||||
private val fullyAnimatedPortraitDrawer = FullyAnimatedPortraitDrawer()
|
||||
}
|
||||
|
||||
private val stateAtIndex = hashMapOf<Int, Pair<UUID, FloatingState>>()
|
||||
|
||||
private val screenExemptions: List<Class<out Screen>> = listOf(
|
||||
ChatScreen::class.java,
|
||||
BattleGUI::class.java
|
||||
@@ -88,6 +85,16 @@ class PartyOverlay : Gui(Minecraft.getInstance()) {
|
||||
attachedToast = false
|
||||
}
|
||||
|
||||
fun getPokemonState(index: Int, pokemonUUID: UUID): FloatingState {
|
||||
val state = this.stateAtIndex.getOrPut(index) { pokemonUUID to FloatingState() }
|
||||
if (state.first != pokemonUUID) {
|
||||
val newState = FloatingState()
|
||||
this.stateAtIndex[index] = pokemonUUID to newState
|
||||
return newState
|
||||
}
|
||||
return state.second
|
||||
}
|
||||
|
||||
override fun render(context: GuiGraphics, tickCounter: DeltaTracker) {
|
||||
val partialDeltaTicks = tickCounter.realtimeDeltaTicks
|
||||
|
||||
@@ -160,13 +167,20 @@ class PartyOverlay : Gui(Minecraft.getInstance()) {
|
||||
0.0
|
||||
)
|
||||
|
||||
val portraitDrawer = when (Cobblemon.config.partyPortraitAnimations) {
|
||||
PortraitStyle.NEVER_ANIMATE -> inanimatePortraitDrawer
|
||||
PortraitStyle.ANIMATE_SELECTED -> selectedAnimatedPortraitDrawer
|
||||
PortraitStyle.ALWAYS_ANIMATE -> fullyAnimatedPortraitDrawer
|
||||
val shouldAnimate = when (Cobblemon.config.partyPortraitAnimations) {
|
||||
PokemonGUIAnimationStyle.NEVER_ANIMATE -> false
|
||||
PokemonGUIAnimationStyle.ANIMATE_SELECTED -> selectedSlot == index
|
||||
PokemonGUIAnimationStyle.ALWAYS_ANIMATE -> true
|
||||
}
|
||||
|
||||
portraitDrawer.draw(pokemon, matrices, partialDeltaTicks, selectedSlot == index, index)
|
||||
drawPosablePortrait(
|
||||
identifier = pokemon.species.resourceIdentifier,
|
||||
matrixStack = matrices,
|
||||
doQuirks = false,
|
||||
partialTicks = if (shouldAnimate) partialDeltaTicks else 0F,
|
||||
contextScale = pokemon.form.baseScale,
|
||||
state = getPokemonState(index = index, pokemonUUID = pokemon.uuid).also { it.currentAspects = pokemon.aspects }
|
||||
)
|
||||
|
||||
matrices.popPose()
|
||||
context.disableScissor()
|
||||
|
||||
+4
-8
@@ -6,24 +6,20 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.portrait
|
||||
package com.cobblemon.mod.common.client.gui
|
||||
|
||||
import com.mojang.serialization.Codec
|
||||
import net.minecraft.util.StringRepresentable
|
||||
|
||||
enum class PortraitStyle : StringRepresentable {
|
||||
enum class PokemonGUIAnimationStyle : StringRepresentable {
|
||||
|
||||
NEVER_ANIMATE,
|
||||
ANIMATE_SELECTED,
|
||||
ALWAYS_ANIMATE;
|
||||
|
||||
override fun getSerializedName(): String = this.name
|
||||
|
||||
override fun getSerializedName() = this.name
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
val CODEC: Codec<PortraitStyle> = StringRepresentable.fromEnum(PortraitStyle::values)
|
||||
|
||||
val CODEC: Codec<PokemonGUIAnimationStyle> = StringRepresentable.fromEnum(PokemonGUIAnimationStyle::values)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.battle
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.gui.drawPosablePortrait
|
||||
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
|
||||
@@ -322,7 +323,7 @@ class BattleOverlay : Gui(Minecraft.getInstance()), Schedulable {
|
||||
reversed = reversed,
|
||||
doQuirks = false,
|
||||
state = state,
|
||||
partialTicks = partialTicks
|
||||
partialTicks = if (Cobblemon.config.animateBattleTiles) partialTicks else 0F
|
||||
)
|
||||
}
|
||||
matrixStack.popPose()
|
||||
|
||||
+1
-3
@@ -13,7 +13,6 @@ import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.moves.MoveTemplate
|
||||
import com.cobblemon.mod.common.api.moves.Moves
|
||||
import com.cobblemon.mod.common.battles.*
|
||||
import com.cobblemon.mod.common.client.gui.battle.subscreen.BattleGimmickButton.GimmickTile
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.math.toRGB
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
@@ -139,8 +138,7 @@ abstract class BattleGimmickButton(gimmick: ShowdownMoveset.Gimmick, val x: Floa
|
||||
pp = gimmickTemplate?.pp ?: moveTemplate.pp,
|
||||
priority = gimmickTemplate?.priority ?: moveTemplate.priority,
|
||||
critRatio = gimmickTemplate?.critRatio ?: moveTemplate.critRatio,
|
||||
effectChances = gimmickTemplate?.effectChances ?: moveTemplate.effectChances,
|
||||
actionEffect = null
|
||||
effectChances = gimmickTemplate?.effectChances ?: moveTemplate.effectChances
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -299,7 +299,7 @@ class DialogueScreen(var dialogueDTO: DialogueDTO) : Screen("gui.dialogue".asTra
|
||||
fun playGibberSpeak(delta: Float, text: String, gibber: DialogueGibberDTO) {
|
||||
timeElapsedSinceGibber += delta / 20
|
||||
|
||||
if (timeElapsedSinceGibber < gibber.interval) {
|
||||
if (timeElapsedSinceGibber < gibber.interval || gibberDone) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -8,10 +8,12 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.pc
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
|
||||
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
|
||||
import com.cobblemon.mod.common.client.gui.pasture.PasturePCGUIConfiguration
|
||||
import com.cobblemon.mod.common.client.gui.PokemonGUIAnimationStyle
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState
|
||||
import com.cobblemon.mod.common.client.render.renderScaledGuiItemIcon
|
||||
@@ -72,12 +74,19 @@ open class StorageSlot(
|
||||
matrices.translate(posX + (SIZE / 2.0), posY + 1.0, 0.0)
|
||||
matrices.scale(2.5F, 2.5F, 1F)
|
||||
|
||||
val animationConfig = if (this is PartyStorageSlot) Cobblemon.config.summaryProfileAnimations else Cobblemon.config.pcProfileAnimations
|
||||
val shouldAnimate = when (animationConfig) {
|
||||
PokemonGUIAnimationStyle.ALWAYS_ANIMATE -> true
|
||||
PokemonGUIAnimationStyle.NEVER_ANIMATE -> false
|
||||
PokemonGUIAnimationStyle.ANIMATE_SELECTED -> isHoveredOrFocused
|
||||
}
|
||||
|
||||
drawProfilePokemon(
|
||||
renderablePokemon = pokemon.asRenderablePokemon(),
|
||||
matrixStack = matrices,
|
||||
rotation = Quaternionf().fromEulerXYZDegrees(Vector3f(13F, 35F, 0F)),
|
||||
state = state,
|
||||
partialTicks = partialTicks,
|
||||
partialTicks = if (shouldAnimate) partialTicks else 0F,
|
||||
scale = 4.5F
|
||||
)
|
||||
matrices.popPose()
|
||||
|
||||
-64
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.portrait
|
||||
|
||||
import com.cobblemon.mod.common.api.gui.drawPosablePortrait
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import java.util.UUID
|
||||
|
||||
/**
|
||||
* Base logic for a [PortraitDrawer] that animates a portrait based on conditions.
|
||||
*/
|
||||
abstract class AnimatedPortraitDrawer : PortraitDrawer {
|
||||
|
||||
private val state = FloatingState()
|
||||
|
||||
private val stateAtIndex = hashMapOf<Int, Pair<UUID, FloatingState>>()
|
||||
|
||||
override fun draw(pokemon: Pokemon, poseStack: PoseStack, partialTicks: Float, isSelected: Boolean, index: Int) {
|
||||
state.currentAspects = pokemon.aspects
|
||||
drawPosablePortrait(
|
||||
identifier = pokemon.species.resourceIdentifier,
|
||||
matrixStack = poseStack,
|
||||
partialTicks = this.ticksFor(pokemon, isSelected, partialTicks),
|
||||
contextScale = pokemon.form.baseScale,
|
||||
state = this.stateFor(pokemon, isSelected, index)
|
||||
)
|
||||
}
|
||||
|
||||
protected abstract fun shouldAnimate(pokemon: Pokemon, isSelected: Boolean): Boolean
|
||||
|
||||
protected open fun ticksFor(pokemon: Pokemon, isSelected: Boolean, partialTicks: Float): Float {
|
||||
return if (this.shouldAnimate(pokemon, isSelected)) partialTicks else 0F
|
||||
}
|
||||
|
||||
protected open fun stateFor(pokemon: Pokemon, isSelected: Boolean, index: Int): FloatingState {
|
||||
if (!this.shouldAnimate(pokemon, isSelected)) {
|
||||
return this.state
|
||||
}
|
||||
val state = this.stateAtIndex.getOrPut(index) { pokemon.uuid to this.createState(pokemon) }
|
||||
if (state.first != pokemon.uuid) {
|
||||
val newState = this.createState(pokemon)
|
||||
this.stateAtIndex[index] = pokemon.uuid to newState
|
||||
return newState
|
||||
}
|
||||
return state.second
|
||||
}
|
||||
|
||||
protected open fun createState(pokemon: Pokemon): FloatingState {
|
||||
val state = FloatingState()
|
||||
state.currentAspects = pokemon.aspects
|
||||
return state
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.portrait
|
||||
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import net.minecraft.client.GraphicsStatus
|
||||
|
||||
/**
|
||||
* Draws portraits if the Pokemon is not fainted.
|
||||
*
|
||||
* Meant for client with [GraphicsStatus.FABULOUS].
|
||||
*/
|
||||
class FullyAnimatedPortraitDrawer : AnimatedPortraitDrawer() {
|
||||
|
||||
override fun shouldAnimate(pokemon: Pokemon, isSelected: Boolean): Boolean {
|
||||
return !pokemon.isFainted()
|
||||
}
|
||||
|
||||
}
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.portrait
|
||||
|
||||
import com.cobblemon.mod.common.api.gui.drawPosablePortrait
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import net.minecraft.client.GraphicsStatus
|
||||
|
||||
/**
|
||||
* The simplest implementation, the Pokemon is drawn staying still.
|
||||
*
|
||||
* Meant for client with [GraphicsStatus.FAST].
|
||||
*/
|
||||
class InanimatePortraitDrawer : PortraitDrawer {
|
||||
|
||||
private val state = FloatingState()
|
||||
|
||||
override fun draw(pokemon: Pokemon, poseStack: PoseStack, partialTicks: Float, isSelected: Boolean, index: Int) {
|
||||
state.currentAspects = pokemon.aspects
|
||||
drawPosablePortrait(
|
||||
identifier = pokemon.species.resourceIdentifier,
|
||||
matrixStack = poseStack,
|
||||
partialTicks = 0F,
|
||||
contextScale = pokemon.form.baseScale,
|
||||
state = this.state
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.portrait
|
||||
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
|
||||
/**
|
||||
* Responsible for drawing a Pokemon portrait.
|
||||
*
|
||||
* Keep in mind any scaling and handling of the [PoseStack] must be done on the implementations using this system.
|
||||
*/
|
||||
fun interface PortraitDrawer {
|
||||
|
||||
/**
|
||||
* Draws the portrait.
|
||||
*
|
||||
* @param pokemon The [Pokemon] being drawn.
|
||||
* @param poseStack The [PoseStack] being used.
|
||||
* @param partialTicks The partial ticks of the screen using this.
|
||||
* @param isSelected If the [pokemon] is considered in a selected state for example hovered or the current party member.
|
||||
* @param index The index of the [pokemon] in the screen using this.
|
||||
*/
|
||||
fun draw(
|
||||
pokemon: Pokemon,
|
||||
poseStack: PoseStack,
|
||||
partialTicks: Float,
|
||||
isSelected: Boolean,
|
||||
index: Int
|
||||
)
|
||||
|
||||
}
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.portrait
|
||||
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import net.minecraft.client.GraphicsStatus
|
||||
|
||||
/**
|
||||
* Draws portraits if the Pokemon is not fainted and selected.
|
||||
*
|
||||
* Meant for client with [GraphicsStatus.FANCY].
|
||||
*/
|
||||
class SelectedAnimatedPortraitDrawer : AnimatedPortraitDrawer() {
|
||||
|
||||
override fun shouldAnimate(pokemon: Pokemon, isSelected: Boolean): Boolean {
|
||||
return !pokemon.isFainted() && isSelected
|
||||
}
|
||||
|
||||
}
|
||||
+10
-1
@@ -8,9 +8,11 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.summary.widgets
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.gui.PokemonGUIAnimationStyle
|
||||
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
|
||||
import com.cobblemon.mod.common.client.gui.summary.Summary
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
@@ -154,13 +156,20 @@ class PartySlotWidget(
|
||||
matrices.pushPose()
|
||||
matrices.translate(x + (PORTRAIT_DIAMETER / 2.0), y - 3.0, 0.0)
|
||||
matrices.scale(2.5F, 2.5F, 1F)
|
||||
|
||||
val shouldAnimate = when (Cobblemon.config.summaryProfileAnimations) {
|
||||
PokemonGUIAnimationStyle.ALWAYS_ANIMATE -> true
|
||||
PokemonGUIAnimationStyle.NEVER_ANIMATE -> false
|
||||
PokemonGUIAnimationStyle.ANIMATE_SELECTED -> isHovered || isSelected
|
||||
}
|
||||
|
||||
drawProfilePokemon(
|
||||
species = slotPokemon.species.resourceIdentifier,
|
||||
matrixStack = matrices,
|
||||
rotation = Quaternionf().fromEulerXYZDegrees(Vector3f(13F, 35F, 0F)),
|
||||
state = state,
|
||||
scale = 4.5F,
|
||||
partialTicks = delta
|
||||
partialTicks = if (shouldAnimate) delta else 0F
|
||||
)
|
||||
matrices.popPose()
|
||||
|
||||
|
||||
+13
-12
@@ -78,14 +78,17 @@ object PartySendBinding : CobblemonBlockingKeyBinding(
|
||||
return
|
||||
}
|
||||
|
||||
if (CobblemonClient.storage.selectedSlot == -1) return
|
||||
if (Minecraft.getInstance().screen != null) return
|
||||
|
||||
val selectedPartyPokemon = CobblemonClient.storage.party.get(CobblemonClient.storage.selectedSlot) ?: return
|
||||
val selectedPartyPokemon = if (CobblemonClient.storage.selectedSlot >= 0) {
|
||||
CobblemonClient.storage.party.get(CobblemonClient.storage.selectedSlot)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
if (isRidingPokemon(player) && canAttemptDismount(player, selectedPartyPokemon)) {
|
||||
sendToServer(DismountPokemonPacket())
|
||||
}
|
||||
else if (!isRidingSelectedPokemon(player, selectedPartyPokemon)){
|
||||
} else if (selectedPartyPokemon != null && !isRidingSelectedPokemon(player, selectedPartyPokemon)){
|
||||
checkForTargetInteractions(player, selectedPartyPokemon)
|
||||
}
|
||||
}
|
||||
@@ -105,8 +108,7 @@ object PartySendBinding : CobblemonBlockingKeyBinding(
|
||||
collideBlock = ClipContext.Fluid.NONE)
|
||||
if (canSendOutPokemon(player, targetEntity)) {
|
||||
sendToServer(SendOutPokemonPacket(CobblemonClient.storage.selectedSlot))
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
processEntityTarget(player, selectedPartyPokemon, targetEntity)
|
||||
}
|
||||
}
|
||||
@@ -140,7 +142,7 @@ object PartySendBinding : CobblemonBlockingKeyBinding(
|
||||
}
|
||||
}
|
||||
|
||||
private fun canAttemptDismount(player: LocalPlayer, selectedPartyPokemon: Pokemon): Boolean {
|
||||
private fun canAttemptDismount(player: LocalPlayer, selectedPartyPokemon: Pokemon?): Boolean {
|
||||
if (player.vehicle !is PokemonEntity) return false
|
||||
val vehicle = player.vehicle as PokemonEntity
|
||||
if (player != vehicle.controllingPassenger) {
|
||||
@@ -148,11 +150,10 @@ object PartySendBinding : CobblemonBlockingKeyBinding(
|
||||
}
|
||||
val isAirRide = vehicle.ridingController?.context?.style == RidingStyle.AIR
|
||||
val hasLandRide = vehicle.rideProp.behaviours?.get(RidingStyle.LAND) != null
|
||||
if (isAirRide && hasLandRide) {
|
||||
return false
|
||||
}
|
||||
else {
|
||||
return vehicle.pokemon.uuid == selectedPartyPokemon.uuid
|
||||
return if (isAirRide && hasLandRide) {
|
||||
false
|
||||
} else {
|
||||
vehicle.pokemon.uuid == selectedPartyPokemon?.uuid
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -29,5 +29,6 @@ object RideSettingsSyncHandler : ClientNetworkPacketHandler<RideSettingsSyncPack
|
||||
CobblemonRideSettings.boat = packet.boat
|
||||
CobblemonRideSettings.burst = packet.burst
|
||||
CobblemonRideSettings.dolphin = packet.dolphin
|
||||
CobblemonRideSettings.submarine = packet.submarine
|
||||
}
|
||||
}
|
||||
+27
-8
@@ -10,22 +10,41 @@ package com.cobblemon.mod.common.client.net.orientation
|
||||
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.duck.RidePassenger
|
||||
import com.cobblemon.mod.common.net.messages.client.orientation.ClientboundUpdateOrientationPacket
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.util.Mth
|
||||
|
||||
object S2CUpdateOrientationHandler : ClientNetworkPacketHandler<ClientboundUpdateOrientationPacket> {
|
||||
object ClientboundUpdateOrientationHandler : ClientNetworkPacketHandler<ClientboundUpdateOrientationPacket> {
|
||||
override fun handle(packet: ClientboundUpdateOrientationPacket, client: Minecraft) {
|
||||
client.executeIfPossible {
|
||||
val level = client.level ?: return@executeIfPossible
|
||||
val entity = level.getEntity(packet.entityId)
|
||||
if (entity is OrientationControllable) {
|
||||
packet.active?.let {
|
||||
entity.orientationController.active = it
|
||||
if (!it) {
|
||||
entity.orientationController.reset()
|
||||
val player = client.player ?: return@executeIfPossible
|
||||
val vehicle = level.getEntity(packet.entityId)
|
||||
val vehicleController = if (vehicle is OrientationControllable) vehicle.orientationController else return@executeIfPossible
|
||||
|
||||
// If the client is also the driver of this entity then don't update it as the driver is the source
|
||||
// of truth on vehicle orientation updates.
|
||||
if (vehicle.controllingPassenger != player) {
|
||||
packet.active?.let { shouldUseCustomOrientation ->
|
||||
|
||||
val playerIsPassenger = vehicle.passengers.contains(player)
|
||||
|
||||
// If the player has just switched to riding a custom orientation ride then set their
|
||||
// ride x and y rots local to the vehicle rots(if the controller wasn't active and will now be active)
|
||||
// This ensures that on transition your camera stays in the same spot
|
||||
if (!vehicleController.isActive() && shouldUseCustomOrientation && playerIsPassenger) {
|
||||
// Set local to the vehicle x and yrot
|
||||
val playerRotater = player as RidePassenger?
|
||||
if (playerRotater != null) {
|
||||
playerRotater.`cobblemon$setRideXRot`(Mth.wrapDegrees(player.getXRot() - vehicle.getXRot()))
|
||||
playerRotater.`cobblemon$setRideYRot`(Mth.wrapDegrees(player.getYRot() - vehicle.getYRot()))
|
||||
}
|
||||
}
|
||||
|
||||
vehicle.orientationController.active = shouldUseCustomOrientation
|
||||
}
|
||||
entity.orientationController.updateOrientation { _ -> packet.orientation }
|
||||
vehicle.orientationController.updateOrientation { _ -> packet.orientation }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+65
-75
@@ -15,23 +15,23 @@ import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.VaryingModelRepository.getPoser
|
||||
import com.cobblemon.mod.common.duck.RidePassenger
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.mixin.accessor.CameraAccessor
|
||||
import com.mojang.math.Axis
|
||||
import net.minecraft.client.Camera
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.level.ClipContext
|
||||
import net.minecraft.world.phys.HitResult
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import org.joml.Matrix3f
|
||||
import org.joml.Quaternionf
|
||||
import org.joml.Vector3f
|
||||
|
||||
object MountedCameraRenderer
|
||||
{
|
||||
fun getCameraPosition(
|
||||
instance: Camera,
|
||||
entity: Entity,
|
||||
driver: Entity,
|
||||
vehicle: Entity,
|
||||
x: Double,
|
||||
y: Double,
|
||||
@@ -51,99 +51,86 @@ object MountedCameraRenderer
|
||||
Mth.lerp(instance.partialTickTime.toDouble(), vehicle.zOld, vehicle.z)
|
||||
)
|
||||
setup(vehicle, instance.partialTickTime)
|
||||
val rollable = entity as OrientationControllable
|
||||
val controller = rollable.getOrientationController()
|
||||
val rollable = vehicle as OrientationControllable
|
||||
val vehicleController = rollable.getOrientationController()
|
||||
|
||||
val model = getPoser(vehicle.pokemon.species.resourceIdentifier, FloatingState())
|
||||
|
||||
val locatorName = delegate.getSeatLocator(driver)
|
||||
val locator = delegate.locatorStates[locatorName] ?: return null
|
||||
|
||||
// First person and view bobbing are handled the same way.
|
||||
if (!instance.isDetached || Cobblemon.config.thirdPersonViewBobbing) {
|
||||
val delegate = vehicle.delegate as PokemonClientDelegate
|
||||
val locatorName = delegate.getSeatLocator(entity)
|
||||
val locator = delegate.locatorStates[locatorName]
|
||||
val currEyeHeight: Double = Mth.lerp(instance.partialTickTime.toDouble(), eyeHeight, eyeHeightOld)
|
||||
var offset = Vector3f(0f, (currEyeHeight - (driver.bbHeight / 2)).toFloat(), 0f)
|
||||
var eyeOffset = Vector3f(0f, (currEyeHeight - (driver.bbHeight / 2)).toFloat(), 0f)
|
||||
|
||||
if (locator == null) {
|
||||
return null
|
||||
}
|
||||
// Get additional offset from poser and add to the eyeHeight offset
|
||||
val shouldFlip = !(vehicleController.active && vehicleController.orientation != null) // Do not flip the offset for 3rd person reverse unless we are using normal mc camera rotation.
|
||||
|
||||
val locatorOffset = Vec3(locator.matrix.getTranslation(Vector3f()))
|
||||
|
||||
// Get Eye height
|
||||
val currEyeHeight: Double = Mth.lerp(instance.partialTickTime.toDouble(), eyeHeight, eyeHeightOld)
|
||||
var offset = Vector3f(0f, (currEyeHeight - (entity.bbHeight / 2)).toFloat(), 0f)
|
||||
|
||||
// Get additional offset from poser and add to the eyeHeight offset
|
||||
if (!instance.isDetached) {
|
||||
offset.add(
|
||||
getFirstPersonOffset(model, locatorName)
|
||||
)
|
||||
} else {
|
||||
offset.add(
|
||||
getThirdPersonOffset(thirdPersonReverse, model.thirdPersonCameraOffset, locatorName)
|
||||
)
|
||||
}
|
||||
|
||||
if (controller.isActive()) {
|
||||
offset = controller.getRenderOrientation(instance.partialTickTime).transform(offset)
|
||||
} else {
|
||||
offset = Axis.YP.rotationDegrees(180f - instance.yRot).transform(offset)
|
||||
}
|
||||
|
||||
val pos = locatorOffset.add(entityPos).toVector3f()
|
||||
val offsetDistance = offset.length()
|
||||
val offsetDirection = offset.mul(1 / offsetDistance)
|
||||
|
||||
// Use getMaxZoom to calculate clipping
|
||||
val maxZoom: Float = getMaxZoom(offsetDistance, offsetDirection, pos, instance)
|
||||
|
||||
return Vec3(offsetDirection.mul(maxZoom).add(pos))
|
||||
eyeOffset.add(getFirstPersonOffset(model, locatorName))
|
||||
if (!instance.isDetached) {
|
||||
offset.add(
|
||||
getFirstPersonOffset(model, locatorName)
|
||||
)
|
||||
} else if( Cobblemon.config.thirdPersonViewBobbing) {
|
||||
offset.add(
|
||||
getThirdPersonOffset(thirdPersonReverse, model.thirdPersonCameraOffset, locatorName, shouldFlip)
|
||||
)
|
||||
} else {
|
||||
val xRot = (-1 * Math.toRadians(instance.xRot.toDouble())).toFloat()
|
||||
offset.add(
|
||||
getThirdPersonOffset(thirdPersonReverse, model.thirdPersonCameraOffsetNoViewBobbing, locatorName, shouldFlip)
|
||||
)
|
||||
}
|
||||
|
||||
// get orientation based on OrientationController or normal rotations
|
||||
val orientation =
|
||||
if (controller.isActive() && controller.orientation != null)
|
||||
controller.orientation!!
|
||||
else
|
||||
Matrix3f()
|
||||
.rotateY(Math.toRadians((180f - instance.yRot).toDouble()).toFloat())
|
||||
.rotateX(xRot)
|
||||
// Grab the current camera rotation to use as the offset rotation.
|
||||
val offsetRot = instance.rotation()
|
||||
offset = offsetRot.transform(offset)
|
||||
eyeOffset = offsetRot.transform(eyeOffset)
|
||||
|
||||
// Get pivot from poser
|
||||
val pivotOffsets = model.thirdPersonPivotOffset
|
||||
val pokemonCenter = Vector3f(0f, entity.bbHeight/2, 0f)
|
||||
val eyeLocatorOffset = Vec3(locator.matrix.getTranslation(Vector3f()))
|
||||
val eyePos = eyeLocatorOffset.add(entityPos).toVector3f()
|
||||
|
||||
var pivot = Vector3f(pokemonCenter)
|
||||
val locatorName = delegate.getSeatLocator(entity)
|
||||
if (pivotOffsets.containsKey(locatorName)) {
|
||||
pivot = pivotOffsets[locatorName]!!.toVector3f()
|
||||
pivot.sub(pokemonCenter)
|
||||
orientation.transform(pivot)
|
||||
pivot.add(pokemonCenter)
|
||||
// Get the camera position. If 3rd person viewbobbing is enabled or the player is
|
||||
// in first person then base the camera position off the seat locator offset
|
||||
val pos = if (!instance.isDetached || Cobblemon.config.thirdPersonViewBobbing) {
|
||||
val locatorOffset = Vec3(locator.matrix.getTranslation(Vector3f()))
|
||||
locatorOffset.add(entityPos).toVector3f()
|
||||
} else {
|
||||
val pokemonCenter = Vector3f(0f, driver.bbHeight/2, 0f)
|
||||
entityPos.toVector3f().add(pokemonCenter)
|
||||
}
|
||||
|
||||
val pos = entityPos.toVector3f().add(pivot)
|
||||
val offsetDistance = offset.length()
|
||||
val offsetDirection = offset.mul(1 / offsetDistance)
|
||||
|
||||
// Get offset from poser
|
||||
val offset = getThirdPersonOffset(thirdPersonReverse, model.thirdPersonCameraOffsetNoViewBobbing, locatorName)
|
||||
val eyeOffsetDistance = eyeOffset.length()
|
||||
val eyeOffsetDirection = eyeOffset.mul(1 / eyeOffsetDistance)
|
||||
|
||||
val rotatedOffset = orientation.transform(offset)
|
||||
val offsetDistance = rotatedOffset.length()
|
||||
val offsetDirection = rotatedOffset.mul(1 / offsetDistance)
|
||||
// Use getMaxZoom to calculate clipping
|
||||
val maxZoom: Float = getMaxZoom(offsetDistance, offsetDirection, pos, instance)
|
||||
val eyeMaxZoom: Float = getMaxZoom(eyeOffsetDistance, eyeOffsetDirection, eyePos, instance)
|
||||
|
||||
// Use getMaxZoom to calculate clipping
|
||||
val maxZoom: Float = getMaxZoom(offsetDistance, offsetDirection, pos, instance)
|
||||
val playerRotater = driver as RidePassenger
|
||||
playerRotater.`cobblemon$setRideEyePos`(Vec3(eyeOffsetDirection.mul(eyeMaxZoom).add(eyePos)).add(0.0, 2.0, 0.0))
|
||||
return Vec3(offsetDirection.mul(maxZoom).add(pos))
|
||||
}
|
||||
|
||||
return Vec3(offsetDirection.mul(maxZoom).add(pos))
|
||||
}
|
||||
fun resetDriverRotations(
|
||||
instance: Camera,
|
||||
driver: Entity,
|
||||
) {
|
||||
val eulerAngs = Quaternionf(instance.rotation()).getEulerAnglesYXZ(Vector3f())
|
||||
val playerRotater = driver as RidePassenger
|
||||
// Backticks because kotlin explodes otherwise due to syntax
|
||||
playerRotater.`cobblemon$setRideXRot`(-eulerAngs.x() * Mth.RAD_TO_DEG)
|
||||
playerRotater.`cobblemon$setRideYRot`(180.0f - (eulerAngs.y() * Mth.RAD_TO_DEG))
|
||||
}
|
||||
|
||||
|
||||
private fun getThirdPersonOffset(
|
||||
thirdPersonReverse: Boolean,
|
||||
cameraOffsets: Map<String, Vec3>,
|
||||
locatorName: String
|
||||
locatorName: String,
|
||||
shouldFlip: Boolean = true
|
||||
): Vector3f {
|
||||
val offset = if (thirdPersonReverse && cameraOffsets.containsKey(locatorName + "_reverse")) {
|
||||
cameraOffsets[locatorName + "_reverse"]!!.toVector3f()
|
||||
@@ -152,7 +139,10 @@ object MountedCameraRenderer
|
||||
} else {
|
||||
Vector3f(0f, 2f, 4f)
|
||||
}
|
||||
if (thirdPersonReverse) offset.z *= -1
|
||||
|
||||
// Don't need to account for this since orientation is derived from camera rotation and that z is already flipped.
|
||||
// Flip only when not on a rollable.
|
||||
if (thirdPersonReverse && shouldFlip) offset.z *= -1
|
||||
return offset
|
||||
}
|
||||
|
||||
|
||||
+10
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.render.entity
|
||||
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.api.riding.Rideable
|
||||
import com.cobblemon.mod.common.client.MountedPokemonAnimationRenderController
|
||||
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
|
||||
@@ -30,11 +31,20 @@ object MountedLivingEntityRenderer {
|
||||
partialTicks: Float,
|
||||
i: Float
|
||||
) {
|
||||
val vehicle = entity.vehicle
|
||||
if (entity.vehicle !is Rideable) return
|
||||
val matrix = stack.last().pose()
|
||||
val delegate = pokemon.delegate as PokemonClientDelegate
|
||||
val locator = delegate.locatorStates[delegate.getSeatLocator(entity)]
|
||||
|
||||
|
||||
if (vehicle is OrientationControllable) {
|
||||
val vehicleController = vehicle.orientationController
|
||||
if (vehicleController.isActive() && vehicleController.orientation != null) {
|
||||
vehicleController.tick()
|
||||
}
|
||||
}
|
||||
|
||||
//Positions entity
|
||||
if (locator != null) {
|
||||
MountedPokemonAnimationRenderController.setup(pokemon, partialTicks)
|
||||
|
||||
+2
-3
@@ -747,9 +747,8 @@ open class PosableModel(@Transient override val rootPart: Bone) : ModelFrame {
|
||||
// If scale is 0 we start getting NaNs
|
||||
scale.coerceAtLeast(0.01f)
|
||||
if (entity.passengers.isNotEmpty() && entity.controllingPassenger is OrientationControllable
|
||||
&& (entity.controllingPassenger as OrientationControllable).orientationController.active){
|
||||
val controllingPassenger = entity.controllingPassenger as OrientationControllable
|
||||
val controller = controllingPassenger.orientationController
|
||||
&& (entity as OrientationControllable).orientationController.active){
|
||||
val controller = entity.orientationController
|
||||
val transformationMatrix = Matrix4f()
|
||||
val center = Vector3f(0f, entity.bbHeight/2, 0f)
|
||||
transformationMatrix.translate(center)
|
||||
|
||||
+7
-13
@@ -42,14 +42,9 @@ import com.cobblemon.mod.common.util.lang
|
||||
import com.cobblemon.mod.common.util.math.DoubleRange
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import com.cobblemon.mod.common.util.math.remap
|
||||
import com.google.common.primitives.Floats
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import com.mojang.math.Axis
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sqrt
|
||||
import net.minecraft.ChatFormatting
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.Font.DisplayMode
|
||||
@@ -67,11 +62,8 @@ import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import org.joml.Math
|
||||
import org.joml.Matrix4f
|
||||
import org.joml.Quaternionf
|
||||
import org.joml.Vector3f
|
||||
import org.joml.Vector4f
|
||||
import org.joml.*
|
||||
import kotlin.math.*
|
||||
|
||||
class PokemonRenderer(
|
||||
context: EntityRendererProvider.Context
|
||||
@@ -189,12 +181,14 @@ class PokemonRenderer(
|
||||
buffer: MultiBufferSource,
|
||||
packedLight: Int
|
||||
) {
|
||||
val driver = entity.firstPassenger ?: return
|
||||
val rollable = driver as? OrientationControllable ?: return
|
||||
val rollable = entity as? OrientationControllable ?: return
|
||||
val controller = rollable.orientationController
|
||||
poseMatrix.pushPose()
|
||||
|
||||
if (!DISABLE_ROLLING_DEBUG && controller.active) {
|
||||
// Allow the ride controller to modify its rotations using partialTick
|
||||
entity.delegate.applyRenderRotation(partialTicks)
|
||||
|
||||
val matrix = poseMatrix.last().pose()
|
||||
val yaw = Mth.rotLerp(partialTicks, entity.yBodyRotO, entity.yBodyRot)
|
||||
val center = Vector3f(0f, entity.bbHeight/2, 0f)
|
||||
|
||||
@@ -11,7 +11,7 @@ package com.cobblemon.mod.common.config
|
||||
import com.cobblemon.mod.common.api.drop.ItemDropMethod
|
||||
import com.cobblemon.mod.common.api.pokeball.catching.calculators.CaptureCalculator
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.client.gui.portrait.PortraitStyle
|
||||
import com.cobblemon.mod.common.client.gui.PokemonGUIAnimationStyle
|
||||
import com.cobblemon.mod.common.config.CobblemonConfigField.CobblemonConfigSide.CLIENT
|
||||
import com.cobblemon.mod.common.config.CobblemonConfigField.CobblemonConfigSide.SERVER
|
||||
import com.cobblemon.mod.common.config.constraint.IntConstraint
|
||||
@@ -276,7 +276,16 @@ class CobblemonConfig {
|
||||
var summaryPokemonFollowCursor = true
|
||||
|
||||
@CobblemonConfigField(Category.Interface, lang = "party_portrait_animations", CLIENT)
|
||||
var partyPortraitAnimations = PortraitStyle.ANIMATE_SELECTED
|
||||
var partyPortraitAnimations = PokemonGUIAnimationStyle.NEVER_ANIMATE
|
||||
|
||||
@CobblemonConfigField(Category.Interface, lang = "pc_profile_animations", CLIENT)
|
||||
var pcProfileAnimations = PokemonGUIAnimationStyle.ANIMATE_SELECTED
|
||||
|
||||
@CobblemonConfigField(Category.Interface, lang = "summary_profile_animations", CLIENT)
|
||||
var summaryProfileAnimations = PokemonGUIAnimationStyle.ANIMATE_SELECTED
|
||||
|
||||
@CobblemonConfigField(Category.Interface, lang = "animate_battle_tiles", CLIENT)
|
||||
var animateBattleTiles = false
|
||||
|
||||
@CobblemonConfigField(Category.Riding, lang = "third_person_view_bobbing", CLIENT)
|
||||
var thirdPersonViewBobbing = true
|
||||
|
||||
+4
-4
@@ -373,11 +373,11 @@ class PokeRodFishingBobberEntity(type: EntityType<out PokeRodFishingBobberEntity
|
||||
if (Mth.nextInt(random, 0, 100) < getPokemonSpawnChance(rodStack)) {
|
||||
val player = playerOwner as? ServerPlayer ?: return
|
||||
this.typeCaught = TypeCaught.POKEMON
|
||||
val lureBoost = SpawnBaitEffects.getEffectsFromItemStack(bobberBait)
|
||||
val stackedLureTier = SpawnBaitEffects.getEffectsFromItemStack(bobberBait)
|
||||
.filter { it.type == SpawnBait.Effects.RARITY_BUCKET }
|
||||
.maxOfOrNull { it.value.toInt() }
|
||||
?: 0
|
||||
planSpawn(player, rodStack, lureBoost)
|
||||
.sumOf { it.value }
|
||||
.toInt()
|
||||
planSpawn(player, rodStack, stackedLureTier)
|
||||
val selectedWeight = plannedSpawnAction?.bucket?.weight ?: 50F
|
||||
val reactionMinMax = calculateMinMaxCountdown(selectedWeight)
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import com.cobblemon.mod.common.CobblemonItems
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.drop.DropTable
|
||||
import com.cobblemon.mod.common.api.entity.Despawner
|
||||
@@ -300,6 +301,8 @@ open class PokemonEntity(
|
||||
get() = entityData.get(SHOWN_HELD_ITEM)
|
||||
set(value) = entityData.set(SHOWN_HELD_ITEM, value)
|
||||
|
||||
var lastLightningBoltUUID: UUID? = null
|
||||
|
||||
var drops: DropTable? = null
|
||||
|
||||
var tethering: PokemonPastureBlockEntity.Tethering? = null
|
||||
@@ -554,22 +557,55 @@ open class PokemonEntity(
|
||||
}
|
||||
|
||||
override fun thunderHit(level: ServerLevel, lightning: LightningBolt) {
|
||||
// Ground types shouldn't take lightning damage
|
||||
val isTypeImmune = ElementalTypes.GROUND in pokemon.types
|
||||
|
||||
// Deals with special cases in which Pokemon should either be immune or buffed by lightning strikes.
|
||||
when (pokemon.ability.name) {
|
||||
val isAbilityImmune = when (pokemon.ability.name) {
|
||||
"lightningrod" -> {
|
||||
this.addEffect(MobEffectInstance(MobEffects.DAMAGE_BOOST, 1200, 1))
|
||||
true
|
||||
}
|
||||
"motordrive" -> {
|
||||
this.addEffect(MobEffectInstance(MobEffects.MOVEMENT_SPEED, 1200, 0))
|
||||
true
|
||||
}
|
||||
"voltabsorb" -> {
|
||||
this.addEffect(MobEffectInstance(MobEffects.HEAL, 1, 1))
|
||||
true
|
||||
}
|
||||
// Ground types shouldn't take lightning damage
|
||||
else -> if (this.pokemon.types.none { it == ElementalTypes.GROUND }) super.thunderHit(level, lightning)
|
||||
else -> false
|
||||
}
|
||||
|
||||
// Lightning hits entities multiple times, if this Pokémon changed a feature because of this lighting strike it should be immune to all remaining hits of this specific lightning strike as well.
|
||||
var rotated = this.lastLightningBoltUUID == lightning.uuid
|
||||
if (!rotated && pokemon.form.behaviour.lightningHit.isSpecial()) {
|
||||
for (rotateFeature in pokemon.form.behaviour.lightningHit.rotateFeatures) {
|
||||
val feature: StringSpeciesFeature = pokemon.getFeature(rotateFeature.key) ?: continue
|
||||
val index = rotateFeature.chain.indexOf(feature.value)
|
||||
// index is -1 if the element wasn't found, i.e. here if the feature's value is not part of the chain
|
||||
if (index < 0) continue
|
||||
|
||||
val next = index.inc()
|
||||
val nextIndex = if (next < rotateFeature.chain.size) next else 0
|
||||
feature.value = rotateFeature.chain[nextIndex]
|
||||
pokemon.markFeatureDirty(feature)
|
||||
rotated = true
|
||||
}
|
||||
|
||||
if (rotated) {
|
||||
this.lastLightningBoltUUID = lightning.uuid
|
||||
this.playSound(SoundEvents.MOOSHROOM_CONVERT, 2.0F, 1.0F)
|
||||
pokemon.updateAspects()
|
||||
}
|
||||
}
|
||||
|
||||
if (!isTypeImmune && !isAbilityImmune && !rotated) {
|
||||
super.thunderHit(level, lightning)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun tick() {
|
||||
/* Addresses watchdog hanging that is completely bloody inexplicable. */
|
||||
yBodyRot = Mth.wrapDegrees(yBodyRot)
|
||||
@@ -590,8 +626,7 @@ open class PokemonEntity(
|
||||
if (passengers.isNotEmpty() && level().isClientSide) {
|
||||
rideSoundManager.tick()
|
||||
ridingAnimationData.update()
|
||||
} else if (!passengers.isNotEmpty() && level().isClientSide)
|
||||
{
|
||||
} else if (!passengers.isNotEmpty() && level().isClientSide) {
|
||||
rideSoundManager.stop()
|
||||
}
|
||||
|
||||
@@ -2080,7 +2115,7 @@ open class PokemonEntity(
|
||||
private fun createSidedPokemon(): Pokemon = Pokemon().apply { isClient = this@PokemonEntity.level().isClientSide }
|
||||
|
||||
override fun canRide(entity: Entity): Boolean {
|
||||
return platform == PlatformType.NONE && super.canRide(entity)
|
||||
return platform == PlatformType.NONE && super.canRide(entity) && seats.isNotEmpty()
|
||||
}
|
||||
|
||||
// Takes in a requested stat type with a base minimum and base maximum and returns the interpolated
|
||||
@@ -2096,6 +2131,10 @@ open class PokemonEntity(
|
||||
return max(statVal, 1e-6)
|
||||
}
|
||||
|
||||
override fun couldAcceptPassenger(): Boolean {
|
||||
return seats.isNotEmpty() && super.couldAcceptPassenger()
|
||||
}
|
||||
|
||||
fun getRawRideStat(stat: RidingStat, style: RidingStyle): Double {
|
||||
if (rideStatOverrides[style] != null && rideStatOverrides[style]!![stat] != null) {
|
||||
return rideStatOverrides[style]!![stat]!!
|
||||
@@ -2188,9 +2227,19 @@ open class PokemonEntity(
|
||||
}
|
||||
|
||||
this.yRotO = this.yRot
|
||||
val rotation = behaviour.rotation(settings, state, this, driver)
|
||||
|
||||
setRot(rotation.y, rotation.x)
|
||||
if (this is OrientationControllable) {
|
||||
val controller = this.orientationController
|
||||
if (!controller.isActive()) {
|
||||
val rotation = behaviour.rotation(settings, state, this, driver)
|
||||
// TODO: Find a better solution than setting the vehicle xrot to zero.
|
||||
// The problem is that nothing actually effects the vehicle/pokemon xrot so when it gets set to
|
||||
// -45 degrees by a rollable ride controller it gets saved off and not modified until you try
|
||||
// and takeoff again. And at that point you snap to -45 pitch in the orientationControllers matrix
|
||||
setRot(rotation.y, 0.0f)
|
||||
}
|
||||
}
|
||||
|
||||
this.yHeadRot = this.yRot
|
||||
this.yBodyRot = this.yRot
|
||||
this.passengers.filterIsInstance<LivingEntity>()
|
||||
|
||||
@@ -38,6 +38,9 @@ class AprijuiceItem(val type: Apricorn): CobblemonItem(Properties().stacksTo(16)
|
||||
|
||||
const val STRONG_APRICORN_MULTIPLIER = 1.25F
|
||||
const val WEAK_APRICORN_MULTIPLIER = 0.75F
|
||||
|
||||
const val TRIPLE_POINT_THRESHOLD = 30
|
||||
const val DOUBLE_POINT_THRESHOLD = 15
|
||||
}
|
||||
|
||||
override fun use(world: Level, user: Player, hand: InteractionHand): InteractionResultHolder<ItemStack> {
|
||||
@@ -131,7 +134,14 @@ class AprijuiceItem(val type: Apricorn): CobblemonItem(Properties().stacksTo(16)
|
||||
1F
|
||||
}
|
||||
|
||||
return value * apricornMultiplier * tasteMultiplier
|
||||
val applyFlavour = value * apricornMultiplier * tasteMultiplier
|
||||
return if (applyFlavour >= TRIPLE_POINT_THRESHOLD) {
|
||||
3F
|
||||
} else if (applyFlavour >= DOUBLE_POINT_THRESHOLD) {
|
||||
2F
|
||||
} else {
|
||||
1F
|
||||
}
|
||||
}
|
||||
|
||||
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
|
||||
|
||||
+2
-2
@@ -35,7 +35,7 @@ class MovesRegistrySyncPacket(moves: List<MoveTemplate>) : DataRegistrySyncPacke
|
||||
entry.effectChances.forEach { chance -> buffer.writeDouble(chance) }
|
||||
}
|
||||
|
||||
override fun decodeEntry(buffer: RegistryFriendlyByteBuf): MoveTemplate? {
|
||||
override fun decodeEntry(buffer: RegistryFriendlyByteBuf): MoveTemplate {
|
||||
val name = buffer.readString()
|
||||
val num = buffer.readInt()
|
||||
val type = ElementalTypes.getOrException(buffer.readString())
|
||||
@@ -50,7 +50,7 @@ class MovesRegistrySyncPacket(moves: List<MoveTemplate>) : DataRegistrySyncPacke
|
||||
repeat(buffer.readInt()) {
|
||||
effectChances += buffer.readDouble()
|
||||
}
|
||||
return MoveTemplate(name, num, type, damageCategory, power, target, accuracy, pp, priority, critRatio, effectChances.toTypedArray(), null)
|
||||
return MoveTemplate(name, num, type, damageCategory, power, target, accuracy, pp, priority, critRatio, effectChances.toTypedArray())
|
||||
}
|
||||
|
||||
override fun synchronizeDecoded(entries: Collection<MoveTemplate>) {
|
||||
|
||||
+7
-2
@@ -21,6 +21,7 @@ import com.cobblemon.mod.common.api.riding.behaviour.types.land.VehicleSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.BoatSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.BurstSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.DolphinSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.SubmarineSettings
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
|
||||
@@ -39,7 +40,8 @@ class RideSettingsSyncPacket(
|
||||
val vehicle: VehicleSettings,
|
||||
val boat: BoatSettings,
|
||||
val burst: BurstSettings,
|
||||
val dolphin: DolphinSettings
|
||||
val dolphin: DolphinSettings,
|
||||
val submarine: SubmarineSettings
|
||||
) : NetworkPacket<RideSettingsSyncPacket> {
|
||||
override val id = ID
|
||||
|
||||
@@ -56,6 +58,7 @@ class RideSettingsSyncPacket(
|
||||
boat.encode(buffer)
|
||||
burst.encode(buffer)
|
||||
dolphin.encode(buffer)
|
||||
submarine.encode(buffer)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@@ -73,7 +76,8 @@ class RideSettingsSyncPacket(
|
||||
vehicle = VehicleSettings(),
|
||||
boat = BoatSettings(),
|
||||
burst = BurstSettings(),
|
||||
dolphin = DolphinSettings()
|
||||
dolphin = DolphinSettings(),
|
||||
submarine = SubmarineSettings()
|
||||
).apply {
|
||||
bird.decode(buffer)
|
||||
glider.decode(buffer)
|
||||
@@ -87,6 +91,7 @@ class RideSettingsSyncPacket(
|
||||
boat.decode(buffer)
|
||||
burst.decode(buffer)
|
||||
dolphin.decode(buffer)
|
||||
submarine.decode(buffer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-2
@@ -15,9 +15,13 @@ import com.cobblemon.mod.common.util.writeMatrix3f
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import org.joml.Matrix3f
|
||||
|
||||
class ServerboundUpdateOrientationPacket internal constructor(val orientation: Matrix3f?) : NetworkPacket<ServerboundUpdateOrientationPacket> {
|
||||
class ServerboundUpdateOrientationPacket internal constructor(
|
||||
val entity: Int,
|
||||
val orientation: Matrix3f?
|
||||
) : NetworkPacket<ServerboundUpdateOrientationPacket> {
|
||||
override val id = ID
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeInt(entity)
|
||||
buffer.writeBoolean(orientation != null)
|
||||
if (orientation != null) {
|
||||
buffer.writeMatrix3f(orientation)
|
||||
@@ -27,8 +31,9 @@ class ServerboundUpdateOrientationPacket internal constructor(val orientation: M
|
||||
companion object {
|
||||
val ID = cobblemonResource("c2s_update_orientation")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): ServerboundUpdateOrientationPacket {
|
||||
val entity = buffer.readInt()
|
||||
val orientation = if (buffer.readBoolean()) buffer.readMatrix3f() else null
|
||||
return ServerboundUpdateOrientationPacket(orientation)
|
||||
return ServerboundUpdateOrientationPacket(entity, orientation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.net.messages.server.riding
|
||||
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class ServerboundUpdateRiderRotationPacket internal constructor(
|
||||
val riderXRot: Float,
|
||||
val riderYRot: Float,
|
||||
val rideEyePos: Vec3
|
||||
) : NetworkPacket<ServerboundUpdateRiderRotationPacket> {
|
||||
override val id = ID
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeFloat(riderXRot)
|
||||
buffer.writeFloat(riderYRot)
|
||||
buffer.writeVec3(rideEyePos)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("c2s_update_rider_rotation")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): ServerboundUpdateRiderRotationPacket {
|
||||
val riderXRot = buffer.readFloat()
|
||||
val riderYRot = buffer.readFloat()
|
||||
val rideEyePos = buffer.readVec3()
|
||||
return ServerboundUpdateRiderRotationPacket(riderXRot, riderYRot, rideEyePos)
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-5
@@ -10,15 +10,19 @@ package com.cobblemon.mod.common.net.serverhandling.orientation
|
||||
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.net.messages.server.orientation.ServerboundUpdateOrientationPacket
|
||||
import net.minecraft.server.MinecraftServer
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import kotlin.math.atan2
|
||||
|
||||
object OrientationPacketHandler : ServerNetworkPacketHandler<ServerboundUpdateOrientationPacket> {
|
||||
object ServerboundUpdateOrientationHandler : ServerNetworkPacketHandler<ServerboundUpdateOrientationPacket> {
|
||||
override fun handle(packet: ServerboundUpdateOrientationPacket, server: MinecraftServer, player: ServerPlayer) {
|
||||
if (player is OrientationControllable) {
|
||||
player.orientationController.updateOrientation { _ -> packet.orientation }
|
||||
}
|
||||
val entity = player.level().getEntity(packet.entity) ?: return
|
||||
|
||||
if (entity !is PokemonEntity) return
|
||||
if (entity.controllingPassenger != player) return
|
||||
if (entity !is OrientationControllable) return
|
||||
|
||||
entity.orientationController.updateOrientation { _ -> packet.orientation }
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.net.serverhandling.riding
|
||||
|
||||
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.duck.RidePassenger
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateRiderRotationPacket
|
||||
import net.minecraft.server.MinecraftServer
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
object ServerboundUpdateRiderRotationHandler : ServerNetworkPacketHandler<ServerboundUpdateRiderRotationPacket> {
|
||||
|
||||
override fun handle(
|
||||
packet: ServerboundUpdateRiderRotationPacket,
|
||||
server: MinecraftServer,
|
||||
player: ServerPlayer
|
||||
) {
|
||||
if (player is RidePassenger) {
|
||||
player.`cobblemon$setRideXRot`(packet.riderXRot)
|
||||
player.`cobblemon$setRideYRot`(packet.riderYRot)
|
||||
player.`cobblemon$setRideEyePos`(packet.rideEyePos)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.pokemon
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stat
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.util.collections.RotatedIterable
|
||||
import java.util.UUID
|
||||
import kotlin.math.abs
|
||||
|
||||
const val CHARACTERISTIC_MODULUS: Int = 5
|
||||
|
||||
data class Characteristic(val relevantStat: Stat, val mod: Int) {
|
||||
companion object {
|
||||
fun calculate(ivs: IVs, uuid: UUID): Characteristic {
|
||||
val ivList = ivs.toList()
|
||||
// If multiple IVs are the highest maxWithOrNull always returns the first one found, so we rotate the first one
|
||||
// found to depend on UUID (vis-à-vis Personality value)
|
||||
val startAt = abs(uuid.hashCode()) % ivList.size
|
||||
val relevantIv = RotatedIterable(ivList, startAt).maxByOrNull { it.value } ?: return empty()
|
||||
val mod = relevantIv.value % CHARACTERISTIC_MODULUS
|
||||
return Characteristic(relevantIv.key, mod)
|
||||
}
|
||||
|
||||
// Provide an empty default Characteristic for the extremely rare cases that a Pokémon has no proper IVs
|
||||
fun empty(): Characteristic = Characteristic(Stats.HP, 0)
|
||||
}
|
||||
}
|
||||
@@ -210,12 +210,18 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
}
|
||||
|
||||
// Need to happen before currentHealth init due to the calc
|
||||
var ivs = IVs.createRandomIVs().also { it.changeFunction = { onChange(IVsUpdatePacket({ this }, it as IVs)) } }
|
||||
var ivs = IVs.createRandomIVs()
|
||||
.also { it.changeFunction = { it ->
|
||||
onChange(IVsUpdatePacket({ this }, it as IVs))
|
||||
characteristic = Characteristic.calculate(it, uuid)
|
||||
} }
|
||||
internal set(value) {
|
||||
val oldChangeFunction = field.changeFunction
|
||||
field.changeFunction = {}
|
||||
field = value
|
||||
value.changeFunction = oldChangeFunction
|
||||
// Recalculate the characteristic on IV update
|
||||
characteristic = Characteristic.calculate(value, uuid)
|
||||
}
|
||||
|
||||
var evs = EVs.createEmpty().also { it.changeFunction = { onChange(EVsUpdatePacket({ this }, it as EVs)) } }
|
||||
@@ -226,6 +232,9 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
value.changeFunction = oldChangeFunction
|
||||
}
|
||||
|
||||
var characteristic: Characteristic = Characteristic.calculate(ivs, uuid)
|
||||
private set
|
||||
|
||||
fun setIV(stat : Stat, value : Int) {
|
||||
val quotient = clamp(currentHealth / maxHealth.toFloat(), 0F, 1F)
|
||||
ivs[stat] = value
|
||||
@@ -1390,6 +1399,7 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
this.customProperties.clear()
|
||||
this.customProperties += other.customProperties
|
||||
this.nature = other.nature
|
||||
this.characteristic = other.characteristic
|
||||
this.mintedNature = other.mintedNature
|
||||
this.heldItem = other.heldItem
|
||||
this.canDropHeldItem = other.canDropHeldItem
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.pokemon.ai
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
@@ -43,6 +44,9 @@ class FormPokemonBehaviour {
|
||||
@SerializedName("blockInteract")
|
||||
private val _blockInteract: BlockBehavior? = null
|
||||
|
||||
@SerializedName("lightningHit")
|
||||
private val _lightningHit: ThunderstruckBehaviour? = null
|
||||
|
||||
@SerializedName("combat")
|
||||
private val _combat: CombatBehaviour? = null
|
||||
|
||||
@@ -52,6 +56,10 @@ class FormPokemonBehaviour {
|
||||
@SerializedName("herd")
|
||||
private val _herd: HerdBehaviour? = null
|
||||
|
||||
|
||||
@SerializedName("characteristicRainbow")
|
||||
private val _characteristicRainbow: Boolean? = null
|
||||
|
||||
val resting: RestBehaviour
|
||||
get() = _resting ?: parent.resting
|
||||
|
||||
@@ -67,6 +75,9 @@ class FormPokemonBehaviour {
|
||||
val entityInteract: EntityBehaviour
|
||||
get() = _entityInteract ?: parent.entityInteract
|
||||
|
||||
val lightningHit: ThunderstruckBehaviour
|
||||
get() = _lightningHit ?: parent.lightningHit
|
||||
|
||||
val dampensVibrations: Boolean
|
||||
get() = _dampensVibrations ?: parent.dampensVibrations
|
||||
|
||||
@@ -82,12 +93,17 @@ class FormPokemonBehaviour {
|
||||
val itemInteract: ItemBehavior
|
||||
get() = _itemInteract ?: parent.itemInteract
|
||||
|
||||
val characteristicRainbow: Boolean
|
||||
get() = _characteristicRainbow ?: parent.characteristicRainbow
|
||||
|
||||
@Transient
|
||||
val struct = ObjectValue(this).also {
|
||||
it.addFunction("resting") { resting.struct }
|
||||
it.addFunction("moving") { moving.struct }
|
||||
it.addFunction("idle") { idle.struct }
|
||||
it.addFunction("entity_interact") { entityInteract.struct }
|
||||
it.addFunction("lightning_hit") { lightningHit.struct }
|
||||
it.addFunction("characteristic_rainbow") { DoubleValue(characteristicRainbow) }
|
||||
it.addFunction("block_interact") { blockInteract.struct }
|
||||
it.addFunction("item_interact") { itemInteract.struct }
|
||||
it.addFunction("combat") { combat.struct }
|
||||
|
||||
@@ -35,5 +35,6 @@ class MoveBehaviour {
|
||||
it.addFunction("wander_chance") { DoubleValue(wanderChance) }
|
||||
it.addFunction("wander_speed") { DoubleValue(wanderSpeed) }
|
||||
it.addFunction("can_look") { DoubleValue(canLook) }
|
||||
it.addFunction("can_move") { DoubleValue(walk.canWalk || swim.canSwimInWater || swim.canSwimInLava || fly.canFly) }
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.pokemon.ai
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
|
||||
/**
|
||||
@@ -23,9 +24,11 @@ open class PokemonBehaviour {
|
||||
val fireImmune = false
|
||||
val dampensVibrations = false
|
||||
val entityInteract = EntityBehaviour()
|
||||
val lightningHit = ThunderstruckBehaviour()
|
||||
val blockInteract = BlockBehavior()
|
||||
val combat = CombatBehaviour()
|
||||
val herd = HerdBehaviour()
|
||||
val characteristicRainbow = false
|
||||
val itemInteract = ItemBehavior()
|
||||
|
||||
@Transient
|
||||
@@ -35,6 +38,8 @@ open class PokemonBehaviour {
|
||||
it.addFunction("idle") { idle.struct }
|
||||
it.addFunction("entity_interact") { entityInteract.struct }
|
||||
it.addFunction("block_interact") { blockInteract.struct }
|
||||
it.addFunction("lightning_hit") { lightningHit.struct }
|
||||
it.addFunction("characteristic_rainbow") { DoubleValue(characteristicRainbow) }
|
||||
it.addFunction("combat") { combat.struct }
|
||||
it.addFunction("herd") { herd.struct }
|
||||
it.addFunction("item_interact") { itemInteract.struct }
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.pokemon.ai
|
||||
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
|
||||
class ThunderstruckBehaviour {
|
||||
val rotateFeatures = mutableListOf<RotateFeature>()
|
||||
|
||||
// shorthand of ‘should run special code in thunderHit’
|
||||
fun isSpecial(): Boolean = rotateFeatures.isNotEmpty()
|
||||
|
||||
@Transient
|
||||
val struct = ObjectValue(this).also {
|
||||
it.addFunction("has_rotating_features") { this.rotateFeatures.isNotEmpty() }
|
||||
}
|
||||
|
||||
data class RotateFeature(val key: String, val chain: List<String>) {
|
||||
@Transient
|
||||
val struct = ObjectValue(this)
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,10 @@ import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.pokemon.aspect.AspectProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.aspect.SingleConditionalAspectProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.pokemon.Characteristic
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.pokemon.Nature
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.getMemorySafely
|
||||
import com.cobblemon.mod.common.util.server
|
||||
@@ -48,4 +51,80 @@ val COSMETIC_SLOT_ASPECT = object : AspectProvider {
|
||||
}
|
||||
|
||||
override fun provide(properties: PokemonProperties) = emptySet<String>()
|
||||
}
|
||||
}
|
||||
|
||||
val CHARACTERISTIC_RAINBOW_ASPECT = object : AspectProvider {
|
||||
fun calculateColourAspect(nature: Nature, characteristic: Characteristic): String? {
|
||||
return when (nature.increasedStat to characteristic.relevantStat) {
|
||||
(Stats.ATTACK to Stats.ATTACK),
|
||||
(Stats.ATTACK to Stats.HP),
|
||||
(null to Stats.ATTACK),
|
||||
(Stats.SPEED to Stats.DEFENCE),
|
||||
(Stats.DEFENCE to Stats.SPEED)
|
||||
-> "rainbow-red"
|
||||
|
||||
(Stats.ATTACK to Stats.DEFENCE),
|
||||
(Stats.DEFENCE to Stats.ATTACK)
|
||||
-> "rainbow-orange"
|
||||
|
||||
(Stats.DEFENCE to Stats.DEFENCE),
|
||||
(Stats.DEFENCE to Stats.HP),
|
||||
(null to Stats.DEFENCE),
|
||||
(Stats.ATTACK to Stats.SPECIAL_DEFENCE),
|
||||
(Stats.SPECIAL_DEFENCE to Stats.ATTACK)
|
||||
-> "rainbow-yellow"
|
||||
|
||||
(Stats.DEFENCE to Stats.SPECIAL_DEFENCE),
|
||||
(Stats.SPECIAL_DEFENCE to Stats.DEFENCE)
|
||||
-> "rainbow-lime"
|
||||
|
||||
(Stats.SPECIAL_DEFENCE to Stats.SPECIAL_DEFENCE),
|
||||
(Stats.SPECIAL_DEFENCE to Stats.HP),
|
||||
(null to Stats.SPECIAL_DEFENCE),
|
||||
(Stats.DEFENCE to Stats.SPECIAL_ATTACK),
|
||||
(Stats.SPECIAL_ATTACK to Stats.DEFENCE)
|
||||
-> "rainbow-green"
|
||||
|
||||
(Stats.SPECIAL_DEFENCE to Stats.SPECIAL_ATTACK),
|
||||
(Stats.SPECIAL_ATTACK to Stats.SPECIAL_DEFENCE)
|
||||
-> "rainbow-cyan"
|
||||
|
||||
(Stats.SPECIAL_ATTACK to Stats.SPECIAL_ATTACK),
|
||||
(Stats.SPECIAL_ATTACK to Stats.HP),
|
||||
(null to Stats.SPECIAL_ATTACK),
|
||||
(Stats.SPECIAL_DEFENCE to Stats.SPEED),
|
||||
(Stats.SPEED to Stats.SPECIAL_DEFENCE)
|
||||
-> "rainbow-blue"
|
||||
|
||||
(Stats.SPECIAL_ATTACK to Stats.SPEED),
|
||||
(Stats.SPEED to Stats.SPECIAL_ATTACK)
|
||||
-> "rainbow-purple"
|
||||
|
||||
(Stats.SPEED to Stats.SPEED),
|
||||
(Stats.SPEED to Stats.HP),
|
||||
(null to Stats.SPEED),
|
||||
(Stats.SPECIAL_ATTACK to Stats.ATTACK),
|
||||
(Stats.ATTACK to Stats.SPECIAL_ATTACK)
|
||||
-> "rainbow-magenta"
|
||||
|
||||
(Stats.SPEED to Stats.ATTACK),
|
||||
(Stats.ATTACK to Stats.SPEED),
|
||||
-> "rainbow-pink"
|
||||
|
||||
(null to Stats.HP)
|
||||
-> "rainbow-light-blue"
|
||||
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
override fun provide(pokemon: Pokemon): Set<String> {
|
||||
if (!pokemon.form.behaviour.characteristicRainbow) {
|
||||
return emptySet()
|
||||
}
|
||||
val char = pokemon.characteristic
|
||||
return setOf(calculateColourAspect(pokemon.nature, char) ?: return emptySet())
|
||||
}
|
||||
|
||||
override fun provide(properties: PokemonProperties): Set<String> = emptySet()
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ package com.cobblemon.mod.common.util
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.PlayerSpawnerGetter
|
||||
import com.cobblemon.mod.common.PlayerSpawnerAccessor
|
||||
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.dialogue.ActiveDialogue
|
||||
@@ -100,8 +100,9 @@ fun ServerPlayer.didSleep(): Boolean {
|
||||
}
|
||||
|
||||
fun ServerPlayer.isInBattle() = BattleRegistry.getBattleByParticipatingPlayer(this) != null
|
||||
val ServerPlayer.spawner: PlayerSpawner
|
||||
get() = (this as PlayerSpawnerGetter).getPlayerSpawner()
|
||||
var ServerPlayer.spawner: PlayerSpawner
|
||||
get() = (this as PlayerSpawnerAccessor).getPlayerSpawner()
|
||||
set(value) = (this as PlayerSpawnerAccessor).setPlayerSpawner(value)
|
||||
fun ServerPlayer.getBattleState(): Pair<PokemonBattle, BattleActor>? {
|
||||
val battle = BattleRegistry.getBattleByParticipatingPlayer(this)
|
||||
if (battle != null) {
|
||||
|
||||
+2
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.api.berry.adapter.SpawnConditionAdapter
|
||||
import com.cobblemon.mod.common.api.berry.spawncondition.AllBiomeCondition
|
||||
import com.cobblemon.mod.common.api.berry.spawncondition.BerrySpawnCondition
|
||||
import com.cobblemon.mod.common.api.berry.spawncondition.PreferredBiomeCondition
|
||||
import com.cobblemon.mod.common.api.berry.spawncondition.SpecificBiomeCondition
|
||||
import com.google.gson.JsonDeserializationContext
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonSerializationContext
|
||||
@@ -33,6 +34,7 @@ object CobblemonBerrySpawnConditionAdapter : SpawnConditionAdapter{
|
||||
init {
|
||||
this.register(PreferredBiomeCondition::class, PreferredBiomeCondition.ID)
|
||||
this.register(AllBiomeCondition::class, AllBiomeCondition.ID)
|
||||
this.register(SpecificBiomeCondition::class, SpecificBiomeCondition.ID)
|
||||
}
|
||||
override fun register(type: KClass<out BerrySpawnCondition>, identifier: ResourceLocation) {
|
||||
val existing = this.types.put(identifier.toString(), type)
|
||||
|
||||
+1
@@ -50,6 +50,7 @@ object RidingBehaviourSettingsAdapter : JsonDeserializer<RidingBehaviourSettings
|
||||
MinekartBehaviour.KEY to MinekartSettings::class.java,
|
||||
HoverBehaviour.KEY to HoverSettings::class.java,
|
||||
RocketBehaviour.KEY to RocketSettings::class.java,
|
||||
SubmarineBehaviour.KEY to SubmarineSettings::class.java,
|
||||
CompositeBehaviour.KEY to CompositeSettings::class.java,
|
||||
|
||||
/*
|
||||
|
||||
@@ -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.util.collections
|
||||
|
||||
/**
|
||||
* An Iterable over a List<T> that provides values rotated by some value.
|
||||
*
|
||||
* e.g. a list [0, 1, 2, 3] with a startAt of 2 will be iterated over as if the list read [2, 3, 0, 1]
|
||||
*/
|
||||
class RotatedIterable<out T>: Iterable<T> {
|
||||
private val iter: RotatedListIterator<T>
|
||||
|
||||
constructor(list: List<T>, startAt: Int) {
|
||||
this.iter = RotatedListIterator(list, startAt)
|
||||
}
|
||||
|
||||
override fun iterator(): Iterator<T> = iter
|
||||
|
||||
inner class RotatedListIterator<out T>: Iterator<T> {
|
||||
private val list: List<T>
|
||||
private val startAt: Int
|
||||
private var outerIdx = 0
|
||||
|
||||
constructor(list: List<T>, startAt: Int) {
|
||||
this.list = list
|
||||
this.startAt = startAt
|
||||
}
|
||||
|
||||
override fun hasNext(): Boolean = outerIdx < list.size
|
||||
|
||||
private fun nextIndex(): Int {
|
||||
val idx = startAt + outerIdx
|
||||
outerIdx = outerIdx.inc()
|
||||
return if (idx < list.size) {
|
||||
idx
|
||||
} else {
|
||||
idx - list.size
|
||||
}
|
||||
}
|
||||
|
||||
override fun next(): T = list[nextIndex()]
|
||||
}
|
||||
}
|
||||
|
||||
+12
-43
@@ -22,6 +22,7 @@ import net.minecraft.world.level.block.Block.UPDATE_CLIENTS
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.block.LeavesBlock
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties
|
||||
import net.minecraft.world.level.chunk.status.ChunkStatus
|
||||
import net.minecraft.world.level.levelgen.feature.Feature
|
||||
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext
|
||||
@@ -119,10 +120,11 @@ class SaccharineTreeFeature : Feature<BlockStateConfiguration>(BlockStateConfigu
|
||||
|
||||
// Random extension or Leaf Topper Pattern
|
||||
if (random.nextBoolean()) {
|
||||
placeLeafTopperPattern(
|
||||
placeSmallLeafPattern(
|
||||
worldGenLevel,
|
||||
origin.relative(UP, currentHeight),
|
||||
CobblemonBlocks.SACCHARINE_LEAVES.defaultBlockState(),
|
||||
CobblemonBlocks.SACCHARINE_LEAVES.defaultBlockState().setValue(LeavesBlock.DISTANCE, UPDATE_CLIENTS),
|
||||
Blocks.AIR.defaultBlockState(),
|
||||
CobblemonBlocks.SACCHARINE_LEAVES.defaultBlockState(),
|
||||
random
|
||||
)
|
||||
@@ -143,10 +145,11 @@ class SaccharineTreeFeature : Feature<BlockStateConfiguration>(BlockStateConfigu
|
||||
currentHeight++
|
||||
|
||||
// Leaf Topper Pattern
|
||||
placeLeafTopperPattern(
|
||||
placeSmallLeafPattern(
|
||||
worldGenLevel,
|
||||
origin.relative(UP, currentHeight),
|
||||
CobblemonBlocks.SACCHARINE_LEAVES.defaultBlockState(),
|
||||
CobblemonBlocks.SACCHARINE_LEAVES.defaultBlockState().setValue(LeavesBlock.DISTANCE, UPDATE_CLIENTS),
|
||||
Blocks.AIR.defaultBlockState(),
|
||||
CobblemonBlocks.SACCHARINE_LEAVES.defaultBlockState(),
|
||||
random
|
||||
)
|
||||
@@ -207,11 +210,11 @@ class SaccharineTreeFeature : Feature<BlockStateConfiguration>(BlockStateConfigu
|
||||
}?.relative(Direction.SOUTH) ?: nestPos
|
||||
|
||||
if (validNestPos != null && worldGenLevel.isEmptyBlock(validNestPos)) {
|
||||
val southFacingBeeNest = Blocks.BEE_NEST.defaultBlockState().setValue(net.minecraft.world.level.block.state.properties.BlockStateProperties.HORIZONTAL_FACING, Direction.SOUTH)
|
||||
val southFacingBeeNest = Blocks.BEE_NEST.defaultBlockState().setValue(BlockStateProperties.HORIZONTAL_FACING, Direction.SOUTH)
|
||||
setBlockIfClear(worldGenLevel, validNestPos, southFacingBeeNest)
|
||||
} else if (nestPos != null && worldGenLevel.isEmptyBlock(nestPos)) {
|
||||
// Natural Generation
|
||||
val southFacingBeeNest = Blocks.BEE_NEST.defaultBlockState().setValue(net.minecraft.world.level.block.state.properties.BlockStateProperties.HORIZONTAL_FACING, Direction.SOUTH)
|
||||
val southFacingBeeNest = Blocks.BEE_NEST.defaultBlockState().setValue(BlockStateProperties.HORIZONTAL_FACING, Direction.SOUTH)
|
||||
setBlockIfClear(worldGenLevel, nestPos, southFacingBeeNest)
|
||||
}
|
||||
}
|
||||
@@ -259,7 +262,7 @@ class SaccharineTreeFeature : Feature<BlockStateConfiguration>(BlockStateConfigu
|
||||
)
|
||||
|
||||
for (pos in positions) {
|
||||
setBlockIfClear(worldGenLevel, pos, leafBlock.setValue(LeavesBlock.DISTANCE, UPDATE_CLIENTS))
|
||||
setBlockIfClear(worldGenLevel, pos, CobblemonBlocks.SACCHARINE_LEAVES.defaultBlockState().setValue(LeavesBlock.DISTANCE, UPDATE_CLIENTS))
|
||||
}
|
||||
|
||||
val specialPositions = listOf(
|
||||
@@ -272,7 +275,7 @@ class SaccharineTreeFeature : Feature<BlockStateConfiguration>(BlockStateConfigu
|
||||
for (pos in specialPositions) {
|
||||
if (random.nextFloat() < 0.25f) {
|
||||
setBlockIfClear(worldGenLevel, pos, specialBlock)
|
||||
} else {
|
||||
} else if (leafBlock.block != Blocks.AIR) {
|
||||
setBlockIfClear(worldGenLevel, pos, leafBlock.setValue(LeavesBlock.DISTANCE, UPDATE_CLIENTS))
|
||||
}
|
||||
}
|
||||
@@ -281,30 +284,6 @@ class SaccharineTreeFeature : Feature<BlockStateConfiguration>(BlockStateConfigu
|
||||
worldGenLevel.setBlock(origin, logBlock, UPDATE_CLIENTS)
|
||||
}
|
||||
|
||||
private fun placeLeafTopperPattern(worldGenLevel: WorldGenLevel, origin: BlockPos, leafBlock: BlockState, specialBlock: BlockState, random: RandomSource) {
|
||||
val positions = listOf(
|
||||
origin.offset(-1, 0, 0),
|
||||
origin.offset(1, 0, 0),
|
||||
origin.offset(0, 0, -1),
|
||||
origin.offset(0, 0, 1),
|
||||
origin.offset(-1, 0, -1),
|
||||
origin.offset(1, 0, 1),
|
||||
origin.offset(-1, 0, 1),
|
||||
origin.offset(1, 0, -1)
|
||||
)
|
||||
|
||||
for (pos in positions) {
|
||||
if (random.nextFloat() < 0.25f) {
|
||||
setBlockIfClear(worldGenLevel, pos, specialBlock)
|
||||
} else {
|
||||
setBlockIfClear(worldGenLevel, pos, leafBlock.setValue(LeavesBlock.DISTANCE, UPDATE_CLIENTS))
|
||||
}
|
||||
}
|
||||
|
||||
// Center leaf
|
||||
setBlockIfClear(worldGenLevel, origin, leafBlock.setValue(LeavesBlock.DISTANCE, UPDATE_CLIENTS))
|
||||
}
|
||||
|
||||
private fun placeLeafStartPattern(worldGenLevel: WorldGenLevel, origin: BlockPos, logBlock: BlockState, leafBlock: BlockState, potentialBeeNestPositions: MutableList<BlockPos>, random: RandomSource) {
|
||||
val positions = listOf(
|
||||
origin.offset(-1, 0, 0),
|
||||
@@ -318,7 +297,7 @@ class SaccharineTreeFeature : Feature<BlockStateConfiguration>(BlockStateConfigu
|
||||
)
|
||||
|
||||
for (pos in positions) {
|
||||
if (random.nextFloat() < 0.25f) {
|
||||
if (random.nextFloat() < 0.25F) {
|
||||
potentialBeeNestPositions.add(pos)
|
||||
} else {
|
||||
setBlockIfClear(worldGenLevel, pos, leafBlock.setValue(LeavesBlock.DISTANCE, UPDATE_CLIENTS))
|
||||
@@ -349,14 +328,4 @@ class SaccharineTreeFeature : Feature<BlockStateConfiguration>(BlockStateConfigu
|
||||
}
|
||||
worldGenLevel.setBlock(blockPos, blockState, UPDATE_ALL)
|
||||
}
|
||||
|
||||
/*private fun isAir(testableWorld: TestableWorld, blockPos: BlockPos?): Boolean {
|
||||
return testableWorld.testBlockState(
|
||||
blockPos
|
||||
) { blockState: BlockState ->
|
||||
blockState.`is`(
|
||||
Blocks.AIR
|
||||
)
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
+177
-67
@@ -27,17 +27,47 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["color-black"],
|
||||
"aspects": ["rainbow-light_blue"],
|
||||
"layers": [
|
||||
{
|
||||
"name": "paint",
|
||||
"translucent": true,
|
||||
"texture": "cobblemon:textures/pokemon/0235_smeargle/smeargle_paint_black.png"
|
||||
"texture": "cobblemon:textures/pokemon/0235_smeargle/smeargle_paint_light_blue.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["color-blue"],
|
||||
"aspects": ["rainbow-pink"],
|
||||
"layers": [
|
||||
{
|
||||
"name": "paint",
|
||||
"translucent": true,
|
||||
"texture": "cobblemon:textures/pokemon/0235_smeargle/smeargle_paint_pink.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["rainbow-magenta"],
|
||||
"layers": [
|
||||
{
|
||||
"name": "paint",
|
||||
"translucent": true,
|
||||
"texture": "cobblemon:textures/pokemon/0235_smeargle/smeargle_paint_magenta.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["rainbow-purple"],
|
||||
"layers": [
|
||||
{
|
||||
"name": "paint",
|
||||
"translucent": true,
|
||||
"texture": "cobblemon:textures/pokemon/0235_smeargle/smeargle_paint_purple.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["rainbow-blue"],
|
||||
"layers": [
|
||||
{
|
||||
"name": "paint",
|
||||
@@ -47,17 +77,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["color-brown"],
|
||||
"layers": [
|
||||
{
|
||||
"name": "paint",
|
||||
"translucent": true,
|
||||
"texture": "cobblemon:textures/pokemon/0235_smeargle/smeargle_paint_brown.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["color-cyan"],
|
||||
"aspects": ["rainbow-cyan"],
|
||||
"layers": [
|
||||
{
|
||||
"name": "paint",
|
||||
@@ -67,17 +87,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["color-gray"],
|
||||
"layers": [
|
||||
{
|
||||
"name": "paint",
|
||||
"translucent": true,
|
||||
"texture": "cobblemon:textures/pokemon/0235_smeargle/smeargle_paint_gray.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["color-green"],
|
||||
"aspects": ["rainbow-green"],
|
||||
"layers": [
|
||||
{
|
||||
"name": "paint",
|
||||
@@ -86,6 +96,46 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["rainbow-lime"],
|
||||
"layers": [
|
||||
{
|
||||
"name": "paint",
|
||||
"translucent": true,
|
||||
"texture": "cobblemon:textures/pokemon/0235_smeargle/smeargle_paint_lime.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["rainbow-yellow"],
|
||||
"layers": [
|
||||
{
|
||||
"name": "paint",
|
||||
"translucent": true,
|
||||
"texture": "cobblemon:textures/pokemon/0235_smeargle/smeargle_paint_yellow.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["rainbow-orange"],
|
||||
"layers": [
|
||||
{
|
||||
"name": "paint",
|
||||
"translucent": true,
|
||||
"texture": "cobblemon:textures/pokemon/0235_smeargle/smeargle_paint_orange.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["rainbow-red"],
|
||||
"layers": [
|
||||
{
|
||||
"name": "paint",
|
||||
"translucent": true,
|
||||
"texture": "cobblemon:textures/pokemon/0235_smeargle/smeargle_paint_red.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["color-light_blue"],
|
||||
"layers": [
|
||||
@@ -97,22 +147,12 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["color-light_gray"],
|
||||
"aspects": ["color-pink"],
|
||||
"layers": [
|
||||
{
|
||||
"name": "paint",
|
||||
"translucent": true,
|
||||
"texture": "cobblemon:textures/pokemon/0235_smeargle/smeargle_paint_light_gray.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["color-lime"],
|
||||
"layers": [
|
||||
{
|
||||
"name": "paint",
|
||||
"translucent": true,
|
||||
"texture": "cobblemon:textures/pokemon/0235_smeargle/smeargle_paint_lime.png"
|
||||
"texture": "cobblemon:textures/pokemon/0235_smeargle/smeargle_paint_pink.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -126,26 +166,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["color-orange"],
|
||||
"layers": [
|
||||
{
|
||||
"name": "paint",
|
||||
"translucent": true,
|
||||
"texture": "cobblemon:textures/pokemon/0235_smeargle/smeargle_paint_orange.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["color-pink"],
|
||||
"layers": [
|
||||
{
|
||||
"name": "paint",
|
||||
"translucent": true,
|
||||
"texture": "cobblemon:textures/pokemon/0235_smeargle/smeargle_paint_pink.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["color-purple"],
|
||||
"layers": [
|
||||
@@ -156,6 +176,66 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["color-blue"],
|
||||
"layers": [
|
||||
{
|
||||
"name": "paint",
|
||||
"translucent": true,
|
||||
"texture": "cobblemon:textures/pokemon/0235_smeargle/smeargle_paint_blue.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["color-cyan"],
|
||||
"layers": [
|
||||
{
|
||||
"name": "paint",
|
||||
"translucent": true,
|
||||
"texture": "cobblemon:textures/pokemon/0235_smeargle/smeargle_paint_cyan.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["color-green"],
|
||||
"layers": [
|
||||
{
|
||||
"name": "paint",
|
||||
"translucent": true,
|
||||
"texture": "cobblemon:textures/pokemon/0235_smeargle/smeargle_paint_green.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["color-lime"],
|
||||
"layers": [
|
||||
{
|
||||
"name": "paint",
|
||||
"translucent": true,
|
||||
"texture": "cobblemon:textures/pokemon/0235_smeargle/smeargle_paint_lime.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["color-yellow"],
|
||||
"layers": [
|
||||
{
|
||||
"name": "paint",
|
||||
"translucent": true,
|
||||
"texture": "cobblemon:textures/pokemon/0235_smeargle/smeargle_paint_yellow.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["color-orange"],
|
||||
"layers": [
|
||||
{
|
||||
"name": "paint",
|
||||
"translucent": true,
|
||||
"texture": "cobblemon:textures/pokemon/0235_smeargle/smeargle_paint_orange.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["color-red"],
|
||||
"layers": [
|
||||
@@ -166,6 +246,46 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["color-black"],
|
||||
"layers": [
|
||||
{
|
||||
"name": "paint",
|
||||
"translucent": true,
|
||||
"texture": "cobblemon:textures/pokemon/0235_smeargle/smeargle_paint_black.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["color-brown"],
|
||||
"layers": [
|
||||
{
|
||||
"name": "paint",
|
||||
"translucent": true,
|
||||
"texture": "cobblemon:textures/pokemon/0235_smeargle/smeargle_paint_brown.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["color-gray"],
|
||||
"layers": [
|
||||
{
|
||||
"name": "paint",
|
||||
"translucent": true,
|
||||
"texture": "cobblemon:textures/pokemon/0235_smeargle/smeargle_paint_gray.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["color-light_gray"],
|
||||
"layers": [
|
||||
{
|
||||
"name": "paint",
|
||||
"translucent": true,
|
||||
"texture": "cobblemon:textures/pokemon/0235_smeargle/smeargle_paint_light_gray.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["color-white"],
|
||||
"layers": [
|
||||
@@ -175,16 +295,6 @@
|
||||
"texture": "cobblemon:textures/pokemon/0235_smeargle/smeargle_paint_white.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["color-yellow"],
|
||||
"layers": [
|
||||
{
|
||||
"name": "paint",
|
||||
"translucent": true,
|
||||
"texture": "cobblemon:textures/pokemon/0235_smeargle/smeargle_paint_yellow.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2050,6 +2050,7 @@
|
||||
"key.cobblemon.translateportraitleft": "Translate Portrait Left",
|
||||
"key.cobblemon.translateportraitright": "Translate Portrait Right",
|
||||
"key.cobblemon.printmodelsettings": "Print Model Settings",
|
||||
"key.cobblemon.toggleridingstatsgui": "Toggle Riding Stats GUI",
|
||||
"key.cobblemon.categories.cobblemon.debug": "Cobblemon Debug",
|
||||
|
||||
"cobblemon.subtitle.poke_ball.capture_succeeded": "Poké Ball capture succeeds",
|
||||
@@ -2082,10 +2083,10 @@
|
||||
"cobblemon.pc.inbattle": "You cannot use a PC while in battle!",
|
||||
|
||||
"cobblemon.held_item": "Held Item",
|
||||
"cobblemon.held_item.give": "%1$s was given %2$s to hold.",
|
||||
"cobblemon.held_item.replace": "You retrieved %1$s from %2$s and gave it %3$s to hold.",
|
||||
"cobblemon.held_item.give": "%1$s was given %2$s.",
|
||||
"cobblemon.held_item.replace": "You retrieved %1$s from %2$s and gave it %3$s.",
|
||||
"cobblemon.held_item.take": "You retrieved %1$s from %2$s.",
|
||||
"cobblemon.held_item.forbidden": "You can't give %1$s for %2$s to hold.",
|
||||
"cobblemon.held_item.forbidden": "You can't give %1$s to %2$s.",
|
||||
"cobblemon.held_item.already_holding": "%1$s is already holding %2$s!",
|
||||
|
||||
"cobblemon.cosmetic_item": "Cosmetic Item",
|
||||
@@ -2554,6 +2555,9 @@
|
||||
"cobblemon.config.ui.hide_unimplemented_pokemon_in_the_pokedex.tooltip": "Whether to hide unimplemented Pokémon from the Pokédex.",
|
||||
"cobblemon.config.ui.summary_pokemon_follow_cursor": "Make Pokémon Follow Cursor",
|
||||
"cobblemon.config.ui.summary_pokemon_follow_cursor.tooltip": "Whether or not Pokémon should follow the mouse cursor with their heads in the Summary screen.",
|
||||
"cobblemon.config.ui.animate_battle_tiles": "Animate Battle Tiles",
|
||||
"cobblemon.config.ui.animate_battle_tiles.tooltip": "Whether or not the battle portraits of Pokemon should be animated.",
|
||||
|
||||
"cobblemon.config.ui.party_portrait_animations": "Party Portrait Animations",
|
||||
"cobblemon.config.ui.party_portrait_animations.never_animate": "Never Animate",
|
||||
"cobblemon.config.ui.party_portrait_animations.never_animate.tooltip": "No portraits animate",
|
||||
@@ -2561,6 +2565,23 @@
|
||||
"cobblemon.config.ui.party_portrait_animations.animate_selected.tooltip": "Selected Pokémon animates unless fainted",
|
||||
"cobblemon.config.ui.party_portrait_animations.always_animate": "Always animate",
|
||||
"cobblemon.config.ui.party_portrait_animations.always_animate.tooltip": "Entire party animates unless fainted",
|
||||
|
||||
"cobblemon.config.ui.pc_profile_animations": "PC Profile Animations",
|
||||
"cobblemon.config.ui.pc_profile_animations.never_animate": "Never Animate",
|
||||
"cobblemon.config.ui.pc_profile_animations.never_animate.tooltip": "No profiles animate",
|
||||
"cobblemon.config.ui.pc_profile_animations.animate_selected": "Animate Selected",
|
||||
"cobblemon.config.ui.pc_profile_animations.animate_selected.tooltip": "Selected Pokémon animates unless fainted",
|
||||
"cobblemon.config.ui.pc_profile_animations.always_animate": "Always animate",
|
||||
"cobblemon.config.ui.pc_profile_animations.always_animate.tooltip": "Entire PC animates unless fainted",
|
||||
|
||||
"cobblemon.config.ui.summary_profile_animations": "Summary Profile Animations",
|
||||
"cobblemon.config.ui.summary_profile_animations.never_animate": "Never Animate",
|
||||
"cobblemon.config.ui.summary_profile_animations.never_animate.tooltip": "No portraits animate",
|
||||
"cobblemon.config.ui.summary_profile_animations.animate_selected": "Animate Selected",
|
||||
"cobblemon.config.ui.summary_profile_animations.animate_selected.tooltip": "Selected Pokémon animates unless fainted",
|
||||
"cobblemon.config.ui.summary_profile_animations.always_animate": "Always animate",
|
||||
"cobblemon.config.ui.summary_profile_animations.always_animate.tooltip": "Entire party animates unless fainted",
|
||||
|
||||
"cobblemon.config.ui.third_person_view_bobbing": "Third Person View Bobbing",
|
||||
"cobblemon.config.ui.third_person_view_bobbing.tooltip": "If true then use default Minecraft behavior to follow directly behind the player's head. If false then follow a fixed offset from the pokemon.",
|
||||
"cobblemon.config.ui.invert_pitch": "Invert Pitch",
|
||||
@@ -3802,6 +3823,18 @@
|
||||
"cobblemon.entity.variable.resource_identifier.name": "Resource Identifier",
|
||||
"cobblemon.entity.variable.resource_identifier.desc": "The resource identifier to be used for controlling the NPC's appearance, such as cobblemon:standard or cobblemon:mudkip.",
|
||||
|
||||
"cobblemon.behaviour.name_tag_display.name": "Name Tag Display",
|
||||
"cobblemon.behaviour.name_tag_display.desc": "Allows toggling the visibility of the entity's name tag.",
|
||||
|
||||
"cobblemon.entity.variable.display_name_tag.name": "Display Name Tag",
|
||||
"cobblemon.entity.variable.display_name_tag.desc": "Whether or not the entity's name tag is visible.",
|
||||
|
||||
"cobblemon.behaviour.dialogue_selection.name": "Dialogue Selection",
|
||||
"cobblemon.behaviour.dialogue_selection.desc": "Allows configuring NPC interaction to open a specific dialogue.",
|
||||
|
||||
"cobblemon.entity.variable.dialogue_selection.name": "Dialogue",
|
||||
"cobblemon.entity.variable.dialogue_selection.desc": "The resource identifier of the dialogue to open on interaction, such as cobblemon:your_dialogue",
|
||||
|
||||
"npc.sacchi.name": "Professor Sacchi",
|
||||
|
||||
"cobblemon.move.pound": "Pound",
|
||||
|
||||
@@ -524,11 +524,11 @@
|
||||
"cobblemon.ui.stats.other": "Otros",
|
||||
"cobblemon.ui.stats.friendship": "Amistad",
|
||||
"cobblemon.ui.stats.hp": "PS",
|
||||
"cobblemon.ui.stats.atk": "Atk",
|
||||
"cobblemon.ui.stats.def": "Def",
|
||||
"cobblemon.ui.stats.sp_atk": "Atk Esp",
|
||||
"cobblemon.ui.stats.sp_def": "Def Esp",
|
||||
"cobblemon.ui.stats.speed": "Vel",
|
||||
"cobblemon.ui.stats.atk": "At.",
|
||||
"cobblemon.ui.stats.def": "Def.",
|
||||
"cobblemon.ui.stats.sp_atk": "At. esp.",
|
||||
"cobblemon.ui.stats.sp_def": "Def. esp.",
|
||||
"cobblemon.ui.stats.speed": "Vel.",
|
||||
"cobblemon.ui.gold_hoard": "Alijo de Monedas",
|
||||
"cobblemon.ui.netherite_hoard": "Alijo de Chatarra",
|
||||
"cobblemon.ui.info": "Datos",
|
||||
@@ -6468,7 +6468,7 @@
|
||||
"item.cobblemon.icy_rock.tooltip": "Prolonga la duración de la Nevada o el Granizo",
|
||||
"item.cobblemon.medicinal_leek.tooltip_1": "Usado para hacer brebajes medicinales",
|
||||
"item.cobblemon.energy_root.tooltip": "Restaura 80 PS de un Pokémon y reduce su amistad",
|
||||
"item.cobblemon.revival_herb.tooltip": "Revive completamente un Pokémon debilitado y reduce su amistad",
|
||||
"item.cobblemon.revival_herb.tooltip": "Revive a un Pokémon debilitado con un 25% de sus PS y reduce su amistad",
|
||||
"item.cobblemon.berry_juice.tooltip": "Restaura 20 PS cuando un Pokémon que lo sostiene cae por debajo del 50% de sus PS",
|
||||
"item.cobblemon.remedy.tooltip": "Restaura 20 PS a un Pokémon y reduce su amistad",
|
||||
"item.cobblemon.fine_remedy.tooltip": "Restaura 60 PS a un Pokémon y reduce su amistad",
|
||||
@@ -7550,9 +7550,9 @@
|
||||
"cobblemon.config.ui.drops_after_death_animation": "Suelta objetos tras la animación",
|
||||
"cobblemon.config.ui.third_person_view_bobbing": "Sacudida de cámara en tercera persona",
|
||||
"cobblemon.config.ui.invert_pitch": "Invertir cabeceo",
|
||||
"cobblemon.config.ui.invert_pitch.tooltip": "Invierte la dirección de cabeceo (izquierda y derecha).",
|
||||
"cobblemon.config.ui.invert_pitch.tooltip": "Invierte la dirección de cabeceo (arriba y abajo).",
|
||||
"cobblemon.config.ui.invert_yaw": "Invertir guiñada",
|
||||
"cobblemon.config.ui.invert_yaw.tooltip": "Invierte la dirección de guiñada (arriba y abajo).",
|
||||
"cobblemon.config.ui.invert_yaw.tooltip": "Invierte la dirección de guiñada (izquierda y derecha).",
|
||||
"cobblemon.config.ui.invert_roll.tooltip": "Invierte la dirección de alabeo (rotar a izquierda y derecha).",
|
||||
"cobblemon.config.ui.automatic_righting_delay": "Demora de corrección automática",
|
||||
"cobblemon.config.ui.automatic_righting_delay.tooltip": "El tiempo que transcurre antes de que se deshaga el alabeo en segundos. Un valor negativo significa que la corrección está deshabilitada, mientras que cero significa que siempre que se deje de mover el ratón la corrección comienza inmediatamente.",
|
||||
@@ -7933,14 +7933,14 @@
|
||||
"item.cobblemon.potato_mochi": "Mochi de patata",
|
||||
"item.cobblemon.fried_rice": "Arroz frito",
|
||||
"item.cobblemon.moomoo_milk": "Leche Mu-mu",
|
||||
"item.cobblemon.health_mochi.tooltip": "Aumenta los PS de base de un Pokémon por 10",
|
||||
"item.cobblemon.health_mochi.tooltip": "Aumenta en 4 los puntos de esfuerzo de PS",
|
||||
"item.cobblemon.muscle_mochi": "Mochi músculo",
|
||||
"item.cobblemon.resist_mochi": "Mochi aguante",
|
||||
"item.cobblemon.resist_mochi.tooltip": "Aumenta la Defensa de base de un Pokémon por 10",
|
||||
"item.cobblemon.resist_mochi.tooltip": "Aumenta en 4 los puntos de esfuerzo de defensa",
|
||||
"item.cobblemon.genius_mochi": "Mochi intelecto",
|
||||
"item.cobblemon.genius_mochi.tooltip": "Aumenta el Ataque Especial de base de un Pokémon por 10",
|
||||
"item.cobblemon.genius_mochi.tooltip": "Aumenta en 4 los puntos de esfuerzo de ataque especial",
|
||||
"item.cobblemon.clever_mochi": "Mochi mente",
|
||||
"item.cobblemon.clever_mochi.tooltip": "Aumenta la Defensa Especial de base de un Pokémon por 10",
|
||||
"item.cobblemon.clever_mochi.tooltip": "Aumenta en 4 los puntos de esfuerzo de defensa especial",
|
||||
"item.cobblemon.swift_mochi": "Mochi ímpetu",
|
||||
"item.cobblemon.fresh_start_mochi": "Mochi reinicio",
|
||||
"item.cobblemon.fresh_start_mochi.tooltip": "Restablece todos los puntos de base de un Pokémon a 0",
|
||||
@@ -7972,10 +7972,10 @@
|
||||
"cobblemon.item_class.seasonings": "Sazonadores",
|
||||
"cobblemon.item_class.flavor_seasoning": "Sazonadores de sabor",
|
||||
"cobblemon.item_class.bait_effect_seasoning": "Sazonadores de cebo",
|
||||
"cobblemon.item_class.food_seasoning": "Sazonadores de comida",
|
||||
"cobblemon.item_class.food_seasoning": "Sazonadores nutritivos",
|
||||
"cobblemon.seasoning_bait_effect_header": "Cebo",
|
||||
"cobblemon.seasoning_mob_effect_header": "Efecto",
|
||||
"cobblemon.seasoning_food_header": "Comida",
|
||||
"cobblemon.seasoning_food_header": "Nutrición",
|
||||
"cobblemon.seasoning_flavor_header": "Sabor",
|
||||
"cobblemon.item_class.mob_effect_seasoning": "Sazonadores con efecto",
|
||||
"cobblemon.tooltip.food.hunger": "Hambre: %s",
|
||||
@@ -7996,10 +7996,10 @@
|
||||
"cobblemon.seasoning_mob_effect_info_header": "Información de los efectos:",
|
||||
"block.cobblemon.potted_saccharine_sapling": "Maceta con brote de sacarino",
|
||||
"item.cobblemon.saccharine_chest_boat": "Bote de sacarino con cofre",
|
||||
"item.cobblemon.swift_mochi.tooltip": "Aumenta la Velocidad de base de un Pokémon por 10",
|
||||
"item.cobblemon.muscle_mochi.tooltip": "Aumenta el Ataque de base de un Pokémon por 10",
|
||||
"item.cobblemon.swift_mochi.tooltip": "Aumenta en 4 los puntos de esfuerzo de velocidad",
|
||||
"item.cobblemon.muscle_mochi.tooltip": "Aumenta en 4 los puntos de esfuerzo de ataque",
|
||||
"cobblemon.seasoning_bait_effect_info_header": "Información del cebo:",
|
||||
"cobblemon.seasoning_food_info_header": "Información de la comida:",
|
||||
"cobblemon.seasoning_food_info_header": "Información nutricional:",
|
||||
"cobblemon.seasoning_flavor_info_header": "Información del sabor:",
|
||||
"cobblemon.tooltip.mob_effect_entry": "%1$s %2$s (%3$s)",
|
||||
"block.cobblemon.potted_black_apricorn_sapling": "Maceta con brote de bonguri negro",
|
||||
@@ -8618,5 +8618,28 @@
|
||||
"cobblemon.entity.variable.challenge_cooldown.name": "Tiempo entre enfrentamientos",
|
||||
"cobblemon.config.ui.despawner_near_distance.tooltip": "La distancia mínima desde un jugador dentro de la cual los Pokémon no desaparecen, sin importar su edad.",
|
||||
"cobblemon.config.ui.despawner_max_age_ticks.tooltip": "La edad (en ticks del juego) que un Pokémon debe alcanzar para que pueda desaparecer en el límite de distancia cercana.",
|
||||
"cobblemon.config.ui.despawner_near_distance": "Distancia cercana"
|
||||
"cobblemon.config.ui.despawner_near_distance": "Distancia cercana",
|
||||
"advancements.cobblemon.place_campfire_pot": "Tenemos que cocinar",
|
||||
"block.cobblemon.saccharine_log_slathered": "Leño de sacarino untado de miel",
|
||||
"block.cobblemon.poke_snack": "Poké Snack",
|
||||
"cobblemon.snapshots.warning.dont_show_again": "No mostrar de nuevo",
|
||||
"advancements.cobblemon.use_iv_candy.description": "Modifica alguno de los valores individuales de un Pokémon usando un caramelo",
|
||||
"cobblemon.snapshots.warning.dont_show_again_tip": "Lo que selecciones puede que sea ignorado en futuras versiones de prueba. Cuando el ciclo cambie entre la 1.7.0 y la 1.8.0, por ejemplo.",
|
||||
"cobblemon.ui.ride_style.air": "Aéreo",
|
||||
"cobblemon.ui.ride_style.land": "Terrestre",
|
||||
"cobblemon.ui.ride_style.liquid": "Acuático",
|
||||
"cobblemon.ui.stats.ride": "Montura",
|
||||
"cobblemon.ui.stats.ride.acceleration": "Accel.",
|
||||
"cobblemon.ui.stats.ride.stamina": "Resistencia",
|
||||
"cobblemon.ui.stats.ride.speed": "Velocidad",
|
||||
"cobblemon.ui.stats.fullness": "Empacho",
|
||||
"cobblemon.ui.stats.ride.skill": "Destreza",
|
||||
"cobblemon.ui.stats.ride.jump": "Salto",
|
||||
"cobblemon.ui.stats.ride.boost_maximum": "Máximo mejorado",
|
||||
"cobblemon.ui.pokedex.info.stats_ride": "Estadísticas de montura",
|
||||
"cobblemon.ui.pokedex.info.stats_ride.seats": "Asientos: %1$s",
|
||||
"advancements.cobblemon.place_campfire_pot.description": "Coloca una cacerola sobre una hoguera encendida",
|
||||
"advancements.cobblemon.use_iv_candy": "Estadísticas azucaradas",
|
||||
"cobblemon.snapshots.warning.title": "Aviso: Versión de prueba de Cobblemon",
|
||||
"cobblemon.snapshots.warning.description": "Estás usando una versión de prueba %s de Cobblemon. Contiene funcionalidad aún en desarrollo, y puede que no sea seguro usarla en tus mundos. ¿Deseas continuar sabiendo estos riesgos?"
|
||||
}
|
||||
|
||||
@@ -857,7 +857,7 @@
|
||||
"advancements.cobblemon.obtain_mutated_berry.description": "Plantez des Baies de différents types les unes à côté des autres et observez la mutation en action",
|
||||
"advancements.cobblemon.obtain_all_berries": "Oups, sont toutes là!",
|
||||
"advancements.cobblemon.obtain_all_berries.description": "Obtenez toutes les types de Baies dans Cobblemon",
|
||||
"advancements.cobblemon.use_pasture": "Liberté : Activé",
|
||||
"advancements.cobblemon.use_pasture": "Liberté: Activé",
|
||||
"advancements.cobblemon.use_pasture.description": "Fabriquez un bloc de pâturage et laissez vos amis se balader",
|
||||
"advancements.cobblemon.catch_all_vivillon": "Aspirant Prismillonnaire",
|
||||
"advancements.cobblemon.catch_all_vivillon.description": "Obtenez toutes les formes de Prismillon...",
|
||||
@@ -886,7 +886,7 @@
|
||||
"advancements.cobblemon.obtain_tumblestone": "Le Rolling Stone",
|
||||
"advancements.cobblemon.obtain_tumblestone.description": "Extrayez avec précaution un Galet d'un sable ou d'une gravelle suspecte",
|
||||
"advancements.cobblemon.grow_tumblestone": "Chaud, chaud!",
|
||||
"advancements.cobblemon.grow_tumblestone.description": "Placez un Galet près de la lave ou du magma pour la faire pousser au fil du temps",
|
||||
"advancements.cobblemon.grow_tumblestone.description": "Placez un Galet près de la lave ou du magma pour le faire pousser au fil du temps",
|
||||
"advancements.cobblemon.craft_ancient_balls": "Un vrai antiquaire",
|
||||
"advancements.cobblemon.craft_ancient_balls.description": "Utilisez les Galets pour fabriquer toutes les quinze Balls Anciennes",
|
||||
"cobblemon.battle.crash": "Une erreur lors du combat est survenue. Si vous jouez seul, signalez ceci à l'équipe de modération. Sinon, signalez à l'administrateur du serveur.",
|
||||
@@ -7950,7 +7950,7 @@
|
||||
"item.cobblemon.psychic_seed": "Graine Psychique",
|
||||
"item.cobblemon.damp_rock.tooltip": "Prolonge la durée de la pluie quand elle est déclenchée par le porteur",
|
||||
"item.cobblemon.heat_rock.tooltip": "Prolonge la durée du temps ensoleillé quand il est déclenché par le porteur",
|
||||
"item.cobblemon.revival_herb.tooltip": "Ranime un Pokémon K.O. et restaure tous ses PV mais réduit son Bohneur",
|
||||
"item.cobblemon.revival_herb.tooltip": "Ranime un Pokémon K.O. et restaure 25% de ses PV max mais réduit son Bohneur",
|
||||
"item.cobblemon.remedy.tooltip": "Restaure 20 PV d'un Pokémon mais réduit légèrement son Bonheur",
|
||||
"item.cobblemon.fine_remedy.tooltip": "Restaure 60 PV d'un Pokémon mais réduit légèrement son Bonheur",
|
||||
"item.cobblemon.superb_remedy.tooltip": "Restaure 120 PV d'un Pokémon mais réduit légèrement son Bonheur",
|
||||
@@ -8093,8 +8093,8 @@
|
||||
"cobblemon.config.ui.hide_unimplemented_pokemon_in_the_pokedex.tooltip": "Masquer ou non les Pokémon non implémentés dans le Pokédex.",
|
||||
"cobblemon.config.ui.summary_pokemon_follow_cursor.tooltip": "Permet aux Pokémon de suivre ou non le curseur de la souris avec leur tête dans l'écran de résumé.",
|
||||
"cobblemon.config.ui.party_portrait_animations.animate_selected.tooltip": "Le Pokémon sélectionné est animé à moins d'être K.O.",
|
||||
"cobblemon.config.ui.invert_pitch.tooltip": "Inverse la direction de tangage (gauche et droite).",
|
||||
"cobblemon.config.ui.invert_yaw.tooltip": "Inverse le sens de la rotation (haut et bas).",
|
||||
"cobblemon.config.ui.invert_pitch.tooltip": "Inverse la direction de tangage (haut et bas).",
|
||||
"cobblemon.config.ui.invert_yaw.tooltip": "Inverse le sens de la rotation (gauche et droite).",
|
||||
"cobblemon.config.ui.invert_roll.tooltip": "Inverse le sens de la caméra (rotation à gauche et à droite).",
|
||||
"cobblemon.config.ui.disable_roll.tooltip": "Arrête la caméra de tourner.",
|
||||
"item.cobblemon.electric_seed": "Graine Électrik",
|
||||
@@ -8227,7 +8227,7 @@
|
||||
"cobblemon.trade.error.insufficient_pokemon.self": "Vous n'avez pas de Pokémon à échanger !",
|
||||
"cobblemon.trade.error.insufficient_pokemon.other": "%1$s n'a pas de Pokémon à échanger !",
|
||||
"cobblemon.trade.error.duplicate": "Vous avez déjà envoyé une requête d'échange à %1$s !",
|
||||
"cobblemon.ui.interact.ride": "Chevaucher",
|
||||
"cobblemon.ui.interact.ride": "Monter",
|
||||
"cobblemon.pokedex.variation.netherite_coating": "Revêtement en netherite",
|
||||
"cobblemon.pokedex.variation.ice": "Glace",
|
||||
"cobblemon.pokedex.variation.region_bias": "Aspect régional",
|
||||
@@ -8566,7 +8566,7 @@
|
||||
"item.cobblemon.scroll_of_darkness.tooltip": "Évolue Wushours en Shifours Style Poing Final",
|
||||
"item.cobblemon.moomoo_milk": "Lait Meumeu",
|
||||
"item.cobblemon.health_mochi": "Mochi Santé",
|
||||
"item.cobblemon.health_mochi.tooltip": "Augmente de 10 EV les PV de base d'un Pokémon",
|
||||
"item.cobblemon.health_mochi.tooltip": "Augmente de 4 EV les PV de base d'un Pokémon",
|
||||
"block.cobblemon.potted_saccharine_sapling": "Pousse de saccarine en pot",
|
||||
"item.cobblemon.hearty_grains": "Riz Zélé",
|
||||
"item.cobblemon.bugwort": "Plante Répulsive",
|
||||
@@ -8580,17 +8580,17 @@
|
||||
"item.cobblemon.fried_rice": "Riz Frit",
|
||||
"item.cobblemon.candied_apple": "Pomme de Tire",
|
||||
"item.cobblemon.muscle_mochi": "Mochi Force",
|
||||
"item.cobblemon.muscle_mochi.tooltip": "Augmente de 10 EV l'Attaque de base d'un Pokémon",
|
||||
"item.cobblemon.muscle_mochi.tooltip": "Augmente de 4 EV l'Attaque de base d'un Pokémon",
|
||||
"item.cobblemon.resist_mochi": "Mochi Armure",
|
||||
"item.cobblemon.resist_mochi.tooltip": "Augmente de 10 EV la Défense de base d'un Pokémon",
|
||||
"item.cobblemon.resist_mochi.tooltip": "Augmente de 4 EV la Défense de base d'un Pokémon",
|
||||
"item.cobblemon.genius_mochi": "Mochi Esprit",
|
||||
"item.cobblemon.genius_mochi.tooltip": "Augmente de 10 EV l'Attaque Spéciale de base d'un Pokémon",
|
||||
"item.cobblemon.genius_mochi.tooltip": "Augmente de 4 EV l'Attaque Spéciale de base d'un Pokémon",
|
||||
"item.cobblemon.clever_mochi": "Mochi Mental",
|
||||
"item.cobblemon.clever_mochi.tooltip": "Augmente de 10 EV la Défense Spéciale de base d'un Pokémon",
|
||||
"item.cobblemon.clever_mochi.tooltip": "Augmente de 4 EV la Défense Spéciale de base d'un Pokémon",
|
||||
"item.cobblemon.aprijuice.prefix.plain": "Simple",
|
||||
"item.cobblemon.aprijuice.quality_format": "%2$s %1$s",
|
||||
"item.cobblemon.swift_mochi": "Mochi Sprint",
|
||||
"item.cobblemon.swift_mochi.tooltip": "Augmente de 10 EV la Vitesse de base d'un Pokémon",
|
||||
"item.cobblemon.swift_mochi.tooltip": "Augmente de 4 EV la Vitesse de base d'un Pokémon",
|
||||
"item.cobblemon.fresh_start_mochi": "Mochi Renouveau",
|
||||
"item.cobblemon.fresh_start_mochi.tooltip": "Réinitialise à 0 tous les EV de base d'un Pokémon",
|
||||
"item.cobblemon.poke_bait": "Poké Appât",
|
||||
@@ -8622,11 +8622,11 @@
|
||||
"cobblemon.item_class.bait_effect_seasoning": "Assaisonnement d'appât",
|
||||
"cobblemon.seasoning_bait_effect_header": "Appât",
|
||||
"cobblemon.seasoning_mob_effect_header": "Effet",
|
||||
"cobblemon.item_class.food_seasoning": "Assaisonnement d'aliment",
|
||||
"cobblemon.seasoning_food_header": "Aliment",
|
||||
"cobblemon.item_class.food_seasoning": "Assaisonnement nutritif",
|
||||
"cobblemon.seasoning_food_header": "Nutrition",
|
||||
"cobblemon.seasoning_bait_effect_info_header": "Info de l'appât :",
|
||||
"cobblemon.seasoning_mob_effect_info_header": "Info de l'effet :",
|
||||
"cobblemon.seasoning_food_info_header": "Info de l'aliment :",
|
||||
"cobblemon.seasoning_food_info_header": "Info nutritive :",
|
||||
"cobblemon.item_class.flavor_seasoning": "Assaisonnement du goût",
|
||||
"cobblemon.seasoning_flavor_header": "Goût",
|
||||
"cobblemon.seasoning_flavor_info_header": "Info du goût :",
|
||||
@@ -8775,7 +8775,7 @@
|
||||
"cobblemon.config.ui.despawner_min_age_ticks": "Âge minimum (Ticks)",
|
||||
"cobblemon.config.ui.despawner_near_distance": "Petite distance",
|
||||
"cobblemon.config.ui.despawner_far_distance": "Grande distance",
|
||||
"advancements.cobblemon.ride_pokemon": "Pokémon chevauché!",
|
||||
"advancements.cobblemon.ride_pokemon": "Pokémon Jockey!",
|
||||
"advancements.cobblemon.ride_pokemon.description": "Montez sur un Pokémon pour la première fois",
|
||||
"cobblemon.battle.sidestart.ally.luckychant": "L'Air Veinard immunise votre équipe contre les coups critiques !",
|
||||
"cobblemon.battle.sidestart.ally.safeguard": "Votre équipe est recouverte par un voile mystérieux !",
|
||||
@@ -8965,5 +8965,74 @@
|
||||
"cobblemon.behaviour.pokemon_sleeps_on_trainer_bed.name": "Pokémon dort sur le lit de son dresseur",
|
||||
"cobblemon.behaviour.moves_to_water.name": "Aller vers l'eau",
|
||||
"cobblemon.behaviour.moves_to_lava.name": "Aller vers la lave",
|
||||
"cobblemon.behaviour.wanders_hover.name": "Bouger dans les airs"
|
||||
"cobblemon.behaviour.wanders_hover.name": "Bouger dans les airs",
|
||||
"cobblemon.ui.ride_style.air": "Air",
|
||||
"cobblemon.ui.ride_style.land": "Terre",
|
||||
"cobblemon.ui.ride_style.liquid": "Liquide",
|
||||
"cobblemon.ui.stats.ride": "Monte",
|
||||
"cobblemon.config.ui.swap_x_and_y_axes": "Permuter les Axes X et Y",
|
||||
"cobblemon.config.ui.x_axis_sensitivity.tooltip": "Multiplie l’entrée de l’axe X par cette valeur.",
|
||||
"cobblemon.entity.variable.npc_box_scale.desc": "L'échelle du masque de collision du PNJ. 1.0 est la taille normale. Cela affecte aussi la taille visible du PNJ.",
|
||||
"cobblemon.entity.variable.npc_box_eyes_ratio.name": "Rapport de position des yeux du masque de collision",
|
||||
"cobblemon.entity.variable.npc_box_eyes_ratio.desc": "Rapport entre la hauteur du masque de collision de l'entité du PNJ et la hauteur des yeux, utilisé pour les angles de vision. 0.85 est utilisée pour la plupart des modèles humanoïdes.",
|
||||
"cobblemon.ui.pokedex.info.form.unown-!": "Forme Unique",
|
||||
"cobblemon.behaviour.attack_hostile_mobs.desc": "Attaque les mobs hostiles qui se trouvent à proximité, même sans provocation.",
|
||||
"cobblemon.behaviour.pokemon_picks_up_items.desc": "Le Pokémon ramassera les objets qui l'intéressent.",
|
||||
"cobblemon.species.unown-!.desc": "Ce Pokémon a la forme d'un caractère d'écriture antique. Personne ne sait si ces écritures antiques sont apparues avant les Zarbi ou le contraire. Des études sont en cours, mais aucun résultat n'a été annoncé.",
|
||||
"cobblemon.snapshots.warning.description": "Vous utilisez une snapshot %s de Cobblemon. Les fonctionnalités de cette version sont encore en cours de développement et peuvent ne pas être stables à utiliser dans vos mondes. Souhaitez-vous continuer en connaissant ces risques ?",
|
||||
"cobblemon.snapshots.warning.title": "Avertissement concernant la snapshot de Cobblemon",
|
||||
"cobblemon.ui.stats.ride.acceleration": "Accél.",
|
||||
"cobblemon.ui.stats.ride.jump": "Saut",
|
||||
"cobblemon.ui.stats.ride.skill": "Aptitude",
|
||||
"cobblemon.ui.stats.ride.speed": "Vitesse",
|
||||
"cobblemon.ui.stats.ride.stamina": "Endurance",
|
||||
"cobblemon.ui.stats.ride.boost_maximum": "Au maximum",
|
||||
"cobblemon.ui.pokedex.info.stats_ride": "Stats de monte",
|
||||
"cobblemon.ui.pokedex.info.stats_ride.seats": "Place : %1$s",
|
||||
"cobblemon.command.molang.out": "Sortie MoLang : %1$s",
|
||||
"cobblemon.config.ui.x_axis_sensitivity": "Sensibilité de l'Axe X",
|
||||
"cobblemon.config.ui.y_axis_sensitivity": "Sensibilité de l'Axe Y",
|
||||
"cobblemon.config.ui.swap_x_and_y_axes.tooltip": "Échange les axes d'entrée X et Y.",
|
||||
"cobblemon.config.ui.y_axis_sensitivity.tooltip": "Multiplie l’entrée de l’axe Y par cette valeur.",
|
||||
"cobblemon.config.ui.display_controls_duration_seconds": "Durée d’affichage des commandes",
|
||||
"cobblemon.config.ui.display_controls_duration_seconds.tooltip": "Temps d’affichage de l’overlay des commandes en secondes après la montée sur un Pokémon.",
|
||||
"cobblemon.config.ui.infinite_ride_stamina": "Endurance illimitée",
|
||||
"cobblemon.config.ui.remember_riding_camera": "Mémoriser la vue de monte",
|
||||
"cobblemon.config.ui.remember_riding_camera.tooltip": "Détermine si la caméra revient automatiquement au dernier mode de caméra utilisé lors de la montée sur un Pokémon.",
|
||||
"cobblemon.config.ui.infinite_ride_stamina.tooltip": "Détermine si les Pokémon montés disposent d’une endurance infinie.",
|
||||
"cobblemon.battle.end.sandtomb": "%1$s est libéré de la capacité Tourbi-Sable !",
|
||||
"cobblemon.entity.variable.npc_render_scale.name": "Échelle de rendu",
|
||||
"cobblemon.entity.variable.npc_render_scale.desc": "L'échelle de l'entité du PNJ lors du rendu. 1.0 est la taille normale.",
|
||||
"cobblemon.entity.variable.npc_box_scale.name": "Échelle du masque de collision",
|
||||
"cobblemon.entity.variable.npc_box_width.name": "Largeur du masque de collision",
|
||||
"cobblemon.entity.variable.npc_box_width.desc": "La largeur du masque de collision de l'entité du PNJ.",
|
||||
"cobblemon.entity.variable.npc_box_height.name": "Hauteur du masque de collision",
|
||||
"cobblemon.entity.variable.npc_box_height.desc": "La hauteur du masque de collision de l'entité du PNJ.",
|
||||
"cobblemon.behaviour.npc_scale_configuration.name": "Échelles de l'entité du PNJ",
|
||||
"cobblemon.behaviour.npc_scale_configuration.desc": "Permet de configurer l'échelle de rendu et du masque de collision du PNJ.",
|
||||
"cobblemon.behaviour.pokemon_gets_mad_at_thrower.name": "S'énerver contre le lanceur de Poké Ball",
|
||||
"cobblemon.behaviour.pokemon_gets_mad_at_thrower.desc": "Se met en colère contre le joueur qui lui a lancé une Poké Ball. Les Pokémon agressifs attaqueront le joueur, tandis que les Pokémon non agressifs fuiront.",
|
||||
"cobblemon.behaviour.attack_hostile_mobs.name": "Attaquer les mobs hostiles",
|
||||
"cobblemon.behaviour.pokemon_picks_up_items.name": "Ramasser les objets",
|
||||
"cobblemon.ui.pokedex.info.form.unown-?": "Forme Unique",
|
||||
"cobblemon.species.unown-?.desc": "Ce Pokémon a la forme d'un caractère d'écriture antique. Personne ne sait si ces écritures antiques sont apparues avant les Zarbi ou le contraire. Des études sont en cours, mais aucun résultat n'a été annoncé.",
|
||||
"cobblemon.snapshots.warning.dont_show_again": "Ne plus afficher",
|
||||
"cobblemon.snapshots.warning.dont_show_again_tip": "Ce paramètre peut être ignoré sur les snapshots Cobblemon plus récentes (ex: 1.7.0 vs 1.8.0)",
|
||||
"advancements.cobblemon.place_campfire_pot": "Il faut qu'on produise",
|
||||
"tag.item.cobblemon.iv_candies": "Bonbons pour Entraînement Ultime",
|
||||
"tag.item.cobblemon.subtractive_iv_candies": "Bonbons soustractifs pour Entraînement Ultime",
|
||||
"advancements.cobblemon.place_campfire_pot.description": "Placez une Marmite sur un feu de camp allumé",
|
||||
"tag.item.cobblemon.poke_puff_berries": "Baies pour Profiteroles",
|
||||
"block.cobblemon.saccharine_log_slathered": "Bûche de saccarine enduite de miel",
|
||||
"cobblemon.ui.stats.fullness": "Appétit",
|
||||
"advancements.cobblemon.use_iv_candy": "Stats gonflées à bloc",
|
||||
"advancements.cobblemon.use_iv_candy.description": "Utilisez n'importe quel bonbon qui modifie les IV d'un Pokémon",
|
||||
"block.cobblemon.poke_snack": "Poké Snack",
|
||||
"tag.item.cobblemon.small_flowers": "Petites fleurs",
|
||||
"tag.item.cobblemon.held.blacklisted_items_to_hold": "Objets tenus sur liste noire",
|
||||
"tag.item.cobblemon.held.whitelisted_items_to_hold": "Objets tenus sur liste blanche",
|
||||
"tag.item.cobblemon.candies": "Bonbons",
|
||||
"tag.item.cobblemon.additive_iv_candies": "Bonbons additifs pour Entraînement Ultime",
|
||||
"cobblemon.behaviour.pokemon_bee.name": "Polliniser les fleurs",
|
||||
"cobblemon.behaviour.pokemon_bee.desc": "Pollinise les fleurs et ajoute du miel aux ruches et aux feuilles d'arbre de saccarine."
|
||||
}
|
||||
|
||||
@@ -805,7 +805,7 @@
|
||||
"advancements.cobblemon.harvest_apricorn_seed.description": "Occasionnellement, les Noigrumes lâcheront un germe. Utilisez-en un pour planter un nouvel arbre",
|
||||
"advancements.cobblemon.bone_meal_apricorn": "Pas besoin de Carapuce à O",
|
||||
"advancements.cobblemon.bone_meal_apricorn.description": "Utilisez de la poudre d'os pour accélérer la croissance d'un Noigrume",
|
||||
"advancements.cobblemon.rainbow_apricorns": "Une Forêt bien colorée",
|
||||
"advancements.cobblemon.rainbow_apricorns": "Une forêt bien colorée",
|
||||
"advancements.cobblemon.rainbow_apricorns.description": "Plantez un arbre de Noigrume de chaque couleur",
|
||||
"advancements.cobblemon.craft_poke_ball": "La première d'une longue série",
|
||||
"advancements.cobblemon.craft_poke_ball.description": "En utilisant quatre Noigrumes d'une même couleur et un lingot de cuivre, fabriquez votre première Poké Ball",
|
||||
@@ -813,7 +813,7 @@
|
||||
"advancements.cobblemon.craft_base_balls.description": "Fabriquez des Poké Balls des sept couleurs de base",
|
||||
"advancements.cobblemon.craft_apricorn_balls": "Fargas serait fier",
|
||||
"advancements.cobblemon.craft_apricorn_balls.description": "Fabriquez les sept Noigrume Balls originales",
|
||||
"advancements.cobblemon.craft_all_balls": "Un Maniaque des balls",
|
||||
"advancements.cobblemon.craft_all_balls": "Un maniaque des Balls",
|
||||
"advancements.cobblemon.craft_all_balls.description": "Fabriquez une Poké Ball de chaque type disponible dans le jeu",
|
||||
"advancements.cobblemon.first_catch": "Un nouvel ami !",
|
||||
"advancements.cobblemon.first_catch.description": "Utilisez une Poké Ball et attrapez votre premier Pokémon",
|
||||
@@ -827,7 +827,7 @@
|
||||
"advancements.cobblemon.first_shiny_catch.description": "Attrapez votre premier Pokémon chromatique",
|
||||
"advancements.cobblemon.healing_machine": "Repos bien mérité",
|
||||
"advancements.cobblemon.healing_machine.description": "Attendez que la machine de soin soit chargée, puis soignez votre équipe",
|
||||
"advancements.cobblemon.obtain_leek": "Mare de Poireauter",
|
||||
"advancements.cobblemon.obtain_leek": "Mare de poireauter",
|
||||
"advancements.cobblemon.obtain_leek.description": "Obtenez un Soignon, une plante sauvage qui pousse dans l'eau douce",
|
||||
"advancements.cobblemon.medicinal_brew": "Apothicaire local",
|
||||
"advancements.cobblemon.medicinal_brew.description": "Utilisez un Soignon pour confectionner la base de vos remèdes",
|
||||
@@ -885,9 +885,9 @@
|
||||
"advancements.cobblemon.resurrect_pokemon.description": "Obtenez un Pokémon fossile à partir d'une machine de résurrection",
|
||||
"advancements.cobblemon.obtain_tumblestone": "Pierre qui roule, n'amasse pas mousse !",
|
||||
"advancements.cobblemon.obtain_tumblestone.description": "Extrayez avec précaution un Galet d'un sable ou d'un gravier suspect",
|
||||
"advancements.cobblemon.grow_tumblestone": "Chaud, Chaud !",
|
||||
"advancements.cobblemon.grow_tumblestone": "Chaud, chaud !",
|
||||
"advancements.cobblemon.grow_tumblestone.description": "Placez un Galet près de la lave ou du magma pour le faire pousser au fil du temps",
|
||||
"advancements.cobblemon.craft_ancient_balls": "Un Véritable Antiquaire",
|
||||
"advancements.cobblemon.craft_ancient_balls": "Un véritable antiquaire",
|
||||
"advancements.cobblemon.craft_ancient_balls.description": "Utilisez les Galets pour fabriquer toutes les quinze Balls Anciennes",
|
||||
"cobblemon.battle.crash": "Une erreur lors du combat est survenue. Si vous jouez seul, signalez ceci à l'équipe de modération. Sinon, signalez à l'administrateur du serveur.",
|
||||
"cobblemon.battle.damage_dealt": "%1$s a subi %2$s dégâts !",
|
||||
@@ -6609,7 +6609,7 @@
|
||||
"item.cobblemon.icy_rock.tooltip": "Prolonge la durée de la neige ou grêle quand elle est déclenchée par le porteur",
|
||||
"item.cobblemon.medicinal_leek.tooltip_1": "Utilisé dans les préparations médicinales",
|
||||
"item.cobblemon.energy_root.tooltip": "Restaure 80 PV d'un Pokémon mais réduit son Bonheur",
|
||||
"item.cobblemon.revival_herb.tooltip": "Ranime un Pokémon K.O. et restaure tous ses PV mais réduit son Bohneur",
|
||||
"item.cobblemon.revival_herb.tooltip": "Ranime un Pokémon K.O. et restaure 25% de ses PV max mais réduit son Bohneur",
|
||||
"item.cobblemon.berry_juice.tooltip": "Restaure 20 PV au porteur lorsque ses PV descendent sous 50%",
|
||||
"item.cobblemon.remedy.tooltip": "Restaure 20 PV d'un Pokémon mais réduit légèrement son Bonheur",
|
||||
"item.cobblemon.fine_remedy.tooltip": "Restaure 60 PV d'un Pokémon mais réduit légèrement son Bonheur",
|
||||
@@ -6712,7 +6712,7 @@
|
||||
"cobblemon.ui.wallpapers": "Fonds d'écran",
|
||||
"cobblemon.ui.pc.search": "Rechercher",
|
||||
"cobblemon.ui.interact.give.cosmetic_item": "Changer le cosmétique",
|
||||
"cobblemon.ui.interact.ride": "Chevaucher",
|
||||
"cobblemon.ui.interact.ride": "Monter",
|
||||
"cobblemon.ui.pokedex.search.search_by": "Rechercher par %1$s",
|
||||
"cobblemon.ui.pokedex.search.type.species": "nom",
|
||||
"cobblemon.ui.pokedex.search.type.abilities": "talent",
|
||||
@@ -8307,8 +8307,8 @@
|
||||
"cobblemon.config.ui.party_portrait_animations.never_animate.tooltip": "Aucun portrait animé",
|
||||
"cobblemon.config.ui.party_portrait_animations.animate_selected.tooltip": "Le Pokémon sélectionné est animé à moins d'être K.O.",
|
||||
"cobblemon.config.ui.party_portrait_animations.always_animate.tooltip": "Toute l'équipe est animée à moins d'être K.O.",
|
||||
"cobblemon.config.ui.invert_pitch.tooltip": "Inverse la direction de tangage (gauche et droite).",
|
||||
"cobblemon.config.ui.invert_yaw.tooltip": "Inverse le sens de la rotation (haut et bas).",
|
||||
"cobblemon.config.ui.invert_pitch.tooltip": "Inverse la direction de tangage (haut et bas).",
|
||||
"cobblemon.config.ui.invert_yaw.tooltip": "Inverse le sens de la rotation (gauche et droite).",
|
||||
"cobblemon.config.ui.invert_roll.tooltip": "Inverse le sens de la caméra (rotation à gauche et à droite).",
|
||||
"cobblemon.config.ui.enable_debug_keys.tooltip": "Active des commandes supplémentaires et l'historique des événements pour aider à la mise en œuvre de Pokémon (voir le wiki pour une liste de commandes).",
|
||||
"cobblemon.held_item.forbidden": "Vous ne pouvez pas donner %1$s à %2$s.",
|
||||
@@ -8356,7 +8356,7 @@
|
||||
"cobblemon.config.ui.third_person_view_bobbing": "Mouvement de tête en troisième personne",
|
||||
"advancements.cobblemon.craft_pokedex.description": "Fabriquez un Pokédex à partir de Noigrume, Fer, Cuivre et n'importe quelle poudre brillante",
|
||||
"advancements.cobblemon.craft_pokedex": "Chercheur débutant",
|
||||
"advancements.cobblemon.use_all_berry_bait": "Essayez Les Toutes !",
|
||||
"advancements.cobblemon.use_all_berry_bait": "Essayez les toutes !",
|
||||
"painting.cobblemon.slumber.title": "Le Sommeil",
|
||||
"painting.cobblemon.altar.title": "L'Autel",
|
||||
"painting.cobblemon.premonition.title": "La Prémonition",
|
||||
@@ -8619,22 +8619,22 @@
|
||||
"cobblemon.item_class.seasonings": "Assaisonnements",
|
||||
"cobblemon.item_class.flavor_seasoning": "Assaisonnement du goût",
|
||||
"cobblemon.item_class.bait_effect_seasoning": "Assaisonnement d'appât",
|
||||
"cobblemon.item_class.food_seasoning": "Assaisonnement d'aliment",
|
||||
"cobblemon.item_class.food_seasoning": "Assaisonnement nutritionnel",
|
||||
"cobblemon.seasoning_bait_effect_header": "Appât",
|
||||
"cobblemon.seasoning_mob_effect_header": "Effet",
|
||||
"cobblemon.seasoning_food_header": "Aliment",
|
||||
"cobblemon.seasoning_food_header": "Nutrition",
|
||||
"cobblemon.seasoning_flavor_header": "Goût",
|
||||
"block.cobblemon.potted_saccharine_sapling": "Pousse de saccarine en pot",
|
||||
"item.cobblemon.saccharine_boat": "Bateau en saccarine",
|
||||
"item.cobblemon.saccharine_chest_boat": "Bateau de stockage en saccarine",
|
||||
"item.cobblemon.health_mochi.tooltip": "Augmente de 10 EV les PV de base d'un Pokémon",
|
||||
"item.cobblemon.muscle_mochi.tooltip": "Augmente de 10 EV l'Attaque de base d'un Pokémon",
|
||||
"item.cobblemon.resist_mochi.tooltip": "Augmente de 10 EV la Défense de base d'un Pokémon",
|
||||
"item.cobblemon.genius_mochi.tooltip": "Augmente de 10 EV l'Attaque Spéciale de base d'un Pokémon",
|
||||
"item.cobblemon.clever_mochi.tooltip": "Augmente de 10 EV la Défense Spéciale de base d'un Pokémon",
|
||||
"item.cobblemon.health_mochi.tooltip": "Augmente de 4 EV les PV de base d'un Pokémon",
|
||||
"item.cobblemon.muscle_mochi.tooltip": "Augmente de 4 EV l'Attaque de base d'un Pokémon",
|
||||
"item.cobblemon.resist_mochi.tooltip": "Augmente de 4 EV la Défense de base d'un Pokémon",
|
||||
"item.cobblemon.genius_mochi.tooltip": "Augmente de 4 EV l'Attaque Spéciale de base d'un Pokémon",
|
||||
"item.cobblemon.clever_mochi.tooltip": "Augmente de 4 EV la Défense Spéciale de base d'un Pokémon",
|
||||
"item.cobblemon.fresh_start_mochi.tooltip": "Réinitialise à 0 tous les EV de base d'un Pokémon",
|
||||
"item.cobblemon.aprijuice.prefix.plain": "Simple",
|
||||
"item.cobblemon.swift_mochi.tooltip": "Augmente de 10 EV la Vitesse de base d'un Pokémon",
|
||||
"item.cobblemon.swift_mochi.tooltip": "Augmente de 4 EV la Vitesse de base d'un Pokémon",
|
||||
"block.cobblemon.potted_black_apricorn_sapling": "Pousse de Noigrume Noir en pot",
|
||||
"block.cobblemon.potted_white_apricorn_sapling": "Pousse de Noigrume Blanc en pot",
|
||||
"item.cobblemon.aprijuice.quality_format": "%2$s %1$s",
|
||||
@@ -8643,7 +8643,7 @@
|
||||
"cobblemon.item_class.mob_effect_seasoning": "Assaisonnement d'effet",
|
||||
"cobblemon.seasoning_bait_effect_info_header": "Info de l'appât :",
|
||||
"cobblemon.seasoning_mob_effect_info_header": "Info de l'effet :",
|
||||
"cobblemon.seasoning_food_info_header": "Info de l'aliment :",
|
||||
"cobblemon.seasoning_food_info_header": "Info nutritionnelle :",
|
||||
"cobblemon.seasoning_flavor_info_header": "Info du goût :",
|
||||
"cobblemon.seasoning_flavor.spicy": "Épicé",
|
||||
"cobblemon.seasoning_flavor.dry": "Sec",
|
||||
@@ -8979,5 +8979,74 @@
|
||||
"cobblemon.behaviour.pokemon_sleeps_on_trainer_bed.name": "Pokémon dort sur le lit de son dresseur",
|
||||
"cobblemon.behaviour.wanders_hover.name": "Bouger dans les airs",
|
||||
"cobblemon.behaviour.moves_to_water.name": "Aller vers l'eau",
|
||||
"cobblemon.behaviour.moves_to_lava.name": "Aller vers la lave"
|
||||
"cobblemon.behaviour.moves_to_lava.name": "Aller vers la lave",
|
||||
"cobblemon.ui.ride_style.air": "Air",
|
||||
"cobblemon.ui.stats.ride.speed": "Vitesse",
|
||||
"cobblemon.ui.pokedex.info.stats_ride": "Stats de monte",
|
||||
"cobblemon.config.ui.infinite_ride_stamina": "Endurance illimitée",
|
||||
"cobblemon.config.ui.display_controls_duration_seconds": "Durée d’affichage des commandes",
|
||||
"advancements.cobblemon.place_campfire_pot": "Let Him Cook",
|
||||
"cobblemon.ui.ride_style.land": "Terre",
|
||||
"cobblemon.command.molang.out": "Sortie MoLang : %1$s",
|
||||
"cobblemon.config.ui.infinite_ride_stamina.tooltip": "Détermine si les Pokémon montés disposent d’une endurance infinie.",
|
||||
"advancements.cobblemon.place_campfire_pot.description": "Placez une Marmite sur un feu de camp allumé",
|
||||
"cobblemon.ui.ride_style.liquid": "Liquide",
|
||||
"cobblemon.ui.stats.ride": "Monte",
|
||||
"cobblemon.ui.stats.fullness": "Appétit",
|
||||
"cobblemon.ui.stats.ride.acceleration": "Accél.",
|
||||
"cobblemon.ui.stats.ride.jump": "Saut",
|
||||
"cobblemon.ui.stats.ride.skill": "Aptitude",
|
||||
"cobblemon.ui.stats.ride.stamina": "Endurance",
|
||||
"cobblemon.ui.stats.ride.boost_maximum": "Au maximum",
|
||||
"cobblemon.ui.pokedex.info.stats_ride.seats": "Place : %1$s",
|
||||
"cobblemon.config.ui.x_axis_sensitivity": "Sensibilité de l'Axe X",
|
||||
"cobblemon.config.ui.y_axis_sensitivity": "Sensibilité de l'Axe Y",
|
||||
"cobblemon.config.ui.y_axis_sensitivity.tooltip": "Multiplie l’entrée de l’axe Y par cette valeur.",
|
||||
"cobblemon.config.ui.x_axis_sensitivity.tooltip": "Multiplie l’entrée de l’axe X par cette valeur.",
|
||||
"cobblemon.config.ui.swap_x_and_y_axes": "Permuter les Axes X et Y",
|
||||
"cobblemon.config.ui.swap_x_and_y_axes.tooltip": "Échange les axes d'entrée X et Y.",
|
||||
"cobblemon.config.ui.display_controls_duration_seconds.tooltip": "Temps d’affichage de l’overlay des commandes en secondes après la montée sur un Pokémon.",
|
||||
"cobblemon.config.ui.remember_riding_camera": "Mémoriser la vue de monte",
|
||||
"cobblemon.config.ui.remember_riding_camera.tooltip": "Détermine si la caméra revient automatiquement au dernier mode de caméra utilisé lors de la montée sur un Pokémon.",
|
||||
"advancements.cobblemon.use_iv_candy": "Tel Lance Armstrong",
|
||||
"cobblemon.battle.end.sandtomb": "%1$s est libéré de la capacité Tourbi-Sable !",
|
||||
"cobblemon.entity.variable.npc_render_scale.name": "Échelle de rendu",
|
||||
"cobblemon.behaviour.npc_scale_configuration.name": "Échelles de l'entité du PNJ",
|
||||
"cobblemon.entity.variable.npc_box_scale.desc": "L'échelle de la hitbox du PNJ. 1.0 est la taille normale. Cela affecte également la taille visible du PNJ.",
|
||||
"cobblemon.behaviour.pokemon_gets_mad_at_thrower.desc": "Se met en colère contre le joueur qui lui a lancé une Poké Ball. Les Pokémon agressifs attaqueront le joueur, tandis que les Pokémon non agressifs fuiront.",
|
||||
"cobblemon.entity.variable.npc_box_eyes_ratio.desc": "Rapport entre la hauteur de la hitbox de l'entité du PNJ et la hauteur des yeux, utilisé pour les angles de vision. 0.85 est utilisée pour la plupart des modèles humanoïdes.",
|
||||
"cobblemon.snapshots.warning.title": "Avertissement concernant la snapshot de Cobblemon",
|
||||
"cobblemon.snapshots.warning.description": "Vous utilisez une snapshot %s de Cobblemon. Les fonctionnalités de cette version sont encore en cours de développement et peuvent ne pas être stables à utiliser dans vos mondes. Souhaitez-vous continuer en connaissant ces risques ?",
|
||||
"cobblemon.species.unown-!.desc": "Ce Pokémon a la forme d'un caractère d'écriture antique. Personne ne sait si ces écritures antiques sont apparues avant les Zarbi ou le contraire. Des études sont en cours, mais aucun résultat n'a été annoncé.",
|
||||
"cobblemon.entity.variable.npc_render_scale.desc": "L'échelle de l'entité du PNJ lors du rendu. 1.0 est la taille normale.",
|
||||
"cobblemon.entity.variable.npc_box_scale.name": "Échelle de la hitbox",
|
||||
"cobblemon.entity.variable.npc_box_width.name": "Largeur de la hitbox",
|
||||
"cobblemon.entity.variable.npc_box_width.desc": "La largeur de la hitbox de l'entité du PNJ.",
|
||||
"cobblemon.entity.variable.npc_box_height.name": "Hauteur de la hitbox",
|
||||
"cobblemon.entity.variable.npc_box_height.desc": "La hauteur de la hitbox de l'entité du PNJ.",
|
||||
"cobblemon.entity.variable.npc_box_eyes_ratio.name": "Rapport de position des yeux de la hitbox",
|
||||
"cobblemon.behaviour.npc_scale_configuration.desc": "Permet de configurer l'échelle de rendu et de la hitbox du PNJ.",
|
||||
"cobblemon.behaviour.pokemon_gets_mad_at_thrower.name": "S'énerver contre le lanceur de Poké Ball",
|
||||
"cobblemon.behaviour.attack_hostile_mobs.name": "Attaquer les mobs hostiles",
|
||||
"cobblemon.behaviour.attack_hostile_mobs.desc": "Attaque les mobs hostiles qui se trouvent à proximité, même sans provocation.",
|
||||
"cobblemon.behaviour.pokemon_picks_up_items.name": "Ramasser les objets",
|
||||
"cobblemon.behaviour.pokemon_picks_up_items.desc": "Le Pokémon ramassera les objets qui l'intéressent.",
|
||||
"cobblemon.ui.pokedex.info.form.unown-!": "Forme Unique",
|
||||
"cobblemon.ui.pokedex.info.form.unown-?": "Forme Unique",
|
||||
"cobblemon.species.unown-?.desc": "Ce Pokémon a la forme d'un caractère d'écriture antique. Personne ne sait si ces écritures antiques sont apparues avant les Zarbi ou le contraire. Des études sont en cours, mais aucun résultat n'a été annoncé.",
|
||||
"cobblemon.snapshots.warning.dont_show_again": "Ne plus afficher",
|
||||
"cobblemon.snapshots.warning.dont_show_again_tip": "Ce paramètre peut être ignoré sur les snapshots Cobblemon plus récentes (ex: 1.7.0 vs 1.8.0)",
|
||||
"block.cobblemon.poke_snack": "Poké Snack",
|
||||
"tag.item.cobblemon.iv_candies": "Bonbons pour Entraînement Ultime",
|
||||
"advancements.cobblemon.use_iv_candy.description": "Utilisez n'importe quel bonbon qui modifie les IV d'un Pokémon",
|
||||
"tag.item.cobblemon.small_flowers": "Petites fleurs",
|
||||
"block.cobblemon.saccharine_log_slathered": "Bûche de saccarine enduite de miel",
|
||||
"tag.item.cobblemon.held.blacklisted_items_to_hold": "Objets tenus sur liste noire",
|
||||
"tag.item.cobblemon.held.whitelisted_items_to_hold": "Objets tenus sur liste blanche",
|
||||
"tag.item.cobblemon.candies": "Bonbons",
|
||||
"tag.item.cobblemon.poke_puff_berries": "Baies pour Profiteroles",
|
||||
"tag.item.cobblemon.additive_iv_candies": "Bonbons additifs pour Entraînement Ultime",
|
||||
"tag.item.cobblemon.subtractive_iv_candies": "Bonbons soustractifs pour Entraînement Ultime",
|
||||
"cobblemon.behaviour.pokemon_bee.name": "Polliniser les fleurs",
|
||||
"cobblemon.behaviour.pokemon_bee.desc": "Pollinise les fleurs et ajoute du miel aux ruches et aux feuilles d'arbre de saccarine."
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -616,7 +616,7 @@
|
||||
"cobblemon.ui.status.slp": "СОН",
|
||||
"cobblemon.ui.status.tox": "ОТР",
|
||||
"cobblemon.battle.ui.fight": "Битва",
|
||||
"cobblemon.battle.ui.switch": "Смена",
|
||||
"cobblemon.battle.ui.switch": "Замена",
|
||||
"cobblemon.battle.ui.capture": "Поимка",
|
||||
"cobblemon.battle.ui.run": "Побег",
|
||||
"cobblemon.battle.ui.forfeit": "Сдаться",
|
||||
@@ -1535,11 +1535,11 @@
|
||||
"tag.item.cobblemon.ability_changers": "Сменщики способности",
|
||||
"tag.item.cobblemon.held.is_friendship_booster": "Повышатели дружбы",
|
||||
"cobblemon.move.10000000voltthunderbolt": "Удар молнии в 10,000,000 Вольт",
|
||||
"cobblemon.move.10000000voltthunderbolt.desc": "The user, Pikachu wearing a cap, powers up a jolt of electricity using its Z-Power and unleashes it. Critical hits land more easily.",
|
||||
"cobblemon.move.10000000voltthunderbolt.desc": "Пикачу в кепке усиливает разряд электричества с помощью своей Z-Силы и выпускает его. Критические удары наносятся чаще.",
|
||||
"cobblemon.move.absorb": "Поглощение",
|
||||
"cobblemon.move.absorb.desc": "A nutrient-draining attack. The user’s HP is restored by half the damage taken by the target.",
|
||||
"cobblemon.move.accelerock": "Ускоряющийся камень",
|
||||
"cobblemon.move.accelerock.desc": "The user smashes into the target at high speed. This move always goes first.",
|
||||
"cobblemon.move.accelerock.desc": "Пользователь врезается в цель на высокой скорости. Этот приём всегда атакует первым.",
|
||||
"cobblemon.move.acid": "Кислота",
|
||||
"cobblemon.move.acid.desc": "Opposing Pokémon are attacked with a spray of harsh acid. This may also lower their Sp. Def stats.",
|
||||
"cobblemon.move.acidarmor": "Кислотная броня",
|
||||
@@ -1571,7 +1571,7 @@
|
||||
"cobblemon.move.amnesia": "Амнезия",
|
||||
"cobblemon.move.amnesia.desc": "The user temporarily empties its mind to forget its concerns. This sharply raises the user’s Sp. Def stat.",
|
||||
"cobblemon.move.anchorshot": "Выстрел якорем",
|
||||
"cobblemon.move.anchorshot.desc": "The user entangles the target with its anchor chain while attacking. The target becomes unable to flee.",
|
||||
"cobblemon.move.anchorshot.desc": "Пользователь обвязывает цель своей якорной цепью во время атаки. После этого цель не может сбежать.",
|
||||
"cobblemon.move.ancientpower": "Древняя Сила",
|
||||
"cobblemon.move.ancientpower.desc": "The user attacks with a prehistoric power. This may also raise all the user’s stats at once.",
|
||||
"cobblemon.move.appleacid": "Яблочная кислота",
|
||||
@@ -1613,7 +1613,7 @@
|
||||
"cobblemon.move.aurorabeam": "Луч авроры",
|
||||
"cobblemon.move.aurorabeam.desc": "The target is hit with a rainbow-colored beam. This may also lower the target’s Attack stat.",
|
||||
"cobblemon.move.auroraveil": "Вуаль авроры",
|
||||
"cobblemon.move.auroraveil.desc": "This move reduces damage from physical and special moves for five turns. This can be used only in a hailstorm.",
|
||||
"cobblemon.move.auroraveil.desc": "Этот приём уменьшает урон от физических и специальных приёмов на пять ходов. Его можно использовать только во время снегопада.",
|
||||
"cobblemon.move.autotomize": "Автомизация",
|
||||
"cobblemon.move.autotomize.desc": "The user sheds part of its body to make itself lighter and sharply raise its Speed stat.",
|
||||
"cobblemon.move.avalanche": "Лавина",
|
||||
@@ -1623,7 +1623,7 @@
|
||||
"cobblemon.move.babydolleyes": "Щенячьи Глазки",
|
||||
"cobblemon.move.babydolleyes.desc": "The user stares at the target with its baby-doll eyes, which lowers the target’s Attack stat. This move always goes first.",
|
||||
"cobblemon.move.baddybad": "Плохой плохиш",
|
||||
"cobblemon.move.baddybad.desc": "The user acts bad and attacks the target. A wondrous wall of light is put up to weaken the power of the opposing Pokémon’s physical moves.",
|
||||
"cobblemon.move.baddybad.desc": "Пользователь ведёт себя плохо и атакует цель. Появляется удивительная стена из света, которая ослабляет физические приёмы противника.",
|
||||
"cobblemon.move.banefulbunker": "Пагубный бункер",
|
||||
"cobblemon.move.banefulbunker.desc": "In addition to protecting the user from attacks, this move also poisons any attacker that makes direct contact.",
|
||||
"cobblemon.move.barbbarrage": "Обстрел шипами",
|
||||
@@ -1635,7 +1635,7 @@
|
||||
"cobblemon.move.batonpass": "Передача эстафеты",
|
||||
"cobblemon.move.batonpass.desc": "The user switches places with a party Pokémon in waiting and passes along any stat changes.",
|
||||
"cobblemon.move.beakblast": "Удар клювом",
|
||||
"cobblemon.move.beakblast.desc": "The user first heats up its beak, and then it attacks the target. Making direct contact with the Pokémon while it’s heating up its beak results in a burn.",
|
||||
"cobblemon.move.beakblast.desc": "Пользователь сначала нагревает свой клюв, а затем атакует цель. Прямой контакт с пользователем во время нагрева клюва приводит к ожогу.",
|
||||
"cobblemon.move.beatup": "Избиение",
|
||||
"cobblemon.move.beatup.desc": "The user gets all party Pokémon to attack the target. The more party Pokémon, the greater the number of attacks.",
|
||||
"cobblemon.move.behemothbash": "Громадный пролом",
|
||||
@@ -1677,11 +1677,11 @@
|
||||
"cobblemon.move.blueflare": "Синяя вспышка",
|
||||
"cobblemon.move.blueflare.desc": "The user attacks by engulfing the target in an intense, yet beautiful, blue flame. This may also leave the target with a burn.",
|
||||
"cobblemon.move.bodypress": "Натиск",
|
||||
"cobblemon.move.bodypress.desc": "The user attacks by slamming its body into the target. The higher the user’s Defense, the more damage it can inflict on the target.",
|
||||
"cobblemon.move.bodypress.desc": "Пользователь атакует, бросаясь на цель всем телом. Чем выше Защита пользователя, тем больше урона наносит этот приём.",
|
||||
"cobblemon.move.bodyslam": "Удар телом",
|
||||
"cobblemon.move.bodyslam.desc": "The user drops onto the target with its full body weight. This may also leave the target with paralysis.",
|
||||
"cobblemon.move.boltbeak": "Громовой клюв",
|
||||
"cobblemon.move.boltbeak.desc": "The user stabs the target with its electrified beak. If the user attacks before the target, the power of this move is doubled.",
|
||||
"cobblemon.move.boltbeak.desc": "Пользователь пронзает цель своим электрифицированным клювом. Сила этого приёма удваивается, если пользователь быстрее цели.",
|
||||
"cobblemon.move.boltstrike": "Громовой удар",
|
||||
"cobblemon.move.boltstrike.desc": "The user surrounds itself with a great amount of electricity and charges its target. This may also leave the target with paralysis.",
|
||||
"cobblemon.move.boneclub": "Костяная дубина",
|
||||
@@ -1695,7 +1695,7 @@
|
||||
"cobblemon.move.bounce": "Прыжок",
|
||||
"cobblemon.move.bounce.desc": "The user bounces up high, then drops on the target on the second turn. This may also leave the target with paralysis.",
|
||||
"cobblemon.move.bouncybubble": "Задорные пузыри",
|
||||
"cobblemon.move.bouncybubble.desc": "The user attacks by shooting water bubbles at the target. It then absorbs water and restores its HP by half the damage taken by the target.",
|
||||
"cobblemon.move.bouncybubble.desc": "Пользователь атакует, стреляя в цель пузырьками. Затем он поглощает воду и восстанавливает половину своего ОЗ от урона, нанесённого цели.",
|
||||
"cobblemon.move.branchpoke": "Тычок веткой",
|
||||
"cobblemon.move.branchpoke.desc": "Пользователь атакует цель, тыкая в неё острой веткой.",
|
||||
"cobblemon.move.bravebird": "Храбрая птица",
|
||||
@@ -1709,7 +1709,7 @@
|
||||
"cobblemon.move.brine": "Солёная вода",
|
||||
"cobblemon.move.brine.desc": "If the target’s HP is half or less, this attack will hit with double the power.",
|
||||
"cobblemon.move.brutalswing": "Жестокий размах",
|
||||
"cobblemon.move.brutalswing.desc": "The user swings its body around violently to inflict damage on everything in its vicinity.",
|
||||
"cobblemon.move.brutalswing.desc": "Пользователь резко размахивает телом, чтобы нанести урон всему, что находится поблизости.",
|
||||
"cobblemon.move.bubble": "Пузыри",
|
||||
"cobblemon.move.bubble.desc": "A spray of countless bubbles is jetted at the opposing Pokémon. This may also lower their Speed stat.",
|
||||
"cobblemon.move.bubblebeam": "Луч пузырей",
|
||||
@@ -1729,9 +1729,9 @@
|
||||
"cobblemon.move.burningjealousy": "Жгучая зависть",
|
||||
"cobblemon.move.burningjealousy.desc": "Пользователь атакует энергией, вызванной ревностью. Это обжигает всех вражеских Покемонов, чьи показатели были повышены в течение хода.",
|
||||
"cobblemon.move.burnup": "Выгорание",
|
||||
"cobblemon.move.burnup.desc": "To inflict massive damage, the user burns itself out. After using this move, the user will no longer be Fire type.",
|
||||
"cobblemon.move.burnup.desc": "Чтобы нанести огромный урон, пользователь выгорает. После использования этого приёма пользователь больше не будет иметь Огненный тип.",
|
||||
"cobblemon.move.buzzybuzz": "Шумный вжик",
|
||||
"cobblemon.move.buzzybuzz.desc": "The user shoots a jolt of electricity to attack the target. This also leaves the target with paralysis.",
|
||||
"cobblemon.move.buzzybuzz.desc": "Пользователь стреляет разрядом электричества, чтобы атаковать цель. Это также парализует цель.",
|
||||
"cobblemon.move.calmmind": "Спокойствие",
|
||||
"cobblemon.move.calmmind.desc": "The user quietly focuses its mind and calms its spirit to raise its Sp. Atk and Sp. Def stats.",
|
||||
"cobblemon.move.camouflage": "Камуфляж",
|
||||
@@ -1755,7 +1755,7 @@
|
||||
"cobblemon.move.chillingwater": "Холодная вода",
|
||||
"cobblemon.move.chillingwater.desc": "Пользователь атакует цель, поливая её водой, которая настолько холодна, что лишает её сил. Это также понижает Атаку цели.",
|
||||
"cobblemon.move.chillyreception": "Холодный приём",
|
||||
"cobblemon.move.chillyreception.desc": "Пользователь рассказывает леденящую душу злую шутку, после чего меняется местами с ожидающим его Покемоном. Это призывает снежную бурю на пять ходов.",
|
||||
"cobblemon.move.chillyreception.desc": "Пользователь рассказывает леденящую душу злую шутку, после чего меняется местами с ожидающим его Покемоном. Это призывает метель на пять ходов.",
|
||||
"cobblemon.move.chipaway": "Постепенная атака",
|
||||
"cobblemon.move.chipaway.desc": "Looking for an opening, the user strikes consistently. The target’s stat changes don’t affect this attack’s damage.",
|
||||
"cobblemon.move.chloroblast": "Хлоровзрыв",
|
||||
@@ -1765,11 +1765,11 @@
|
||||
"cobblemon.move.clamp": "Ракушка",
|
||||
"cobblemon.move.clamp.desc": "The target is clamped and squeezed by the user’s very thick and sturdy shell for four to five turns.",
|
||||
"cobblemon.move.clangingscales": "Звенящая чешуя",
|
||||
"cobblemon.move.clangingscales.desc": "The user rubs the scales on its entire body and makes a huge noise to attack opposing Pokémon. The user’s Defense stat goes down after the attack.",
|
||||
"cobblemon.move.clangingscales.desc": "Пользователь трёт чешуйками по всему телу и издаёт громкий звук, чтобы атаковать противника. После атаки Защита пользователя понижается.",
|
||||
"cobblemon.move.clangoroussoul": "Лязгаяющая душа",
|
||||
"cobblemon.move.clangoroussoul.desc": "The user raises all its stats by using some of its HP.",
|
||||
"cobblemon.move.clangoroussoul.desc": "Пользователь повышает все свои показатели, используя часть своих собственных ОЗ.",
|
||||
"cobblemon.move.clangoroussoulblaze": "Лязгающий взрыв души",
|
||||
"cobblemon.move.clangoroussoulblaze.desc": "After obtaining Z-Power, the user, Kommo-o, attacks the opposing Pokémon with full force. This move boosts the user’s stats.",
|
||||
"cobblemon.move.clangoroussoulblaze.desc": "После получения Z-Силы, Коммо-о атакует противника с полной силой. Этот приём повышает показатели пользователя.",
|
||||
"cobblemon.move.clearsmog": "Очищающий смог",
|
||||
"cobblemon.move.clearsmog.desc": "The user attacks the target by throwing a clump of special mud. All stat changes are returned to normal.",
|
||||
"cobblemon.move.closecombat": "Ближний бой",
|
||||
@@ -1803,7 +1803,7 @@
|
||||
"cobblemon.move.copycat": "Подражание",
|
||||
"cobblemon.move.copycat.desc": "The user mimics the move used immediately before it. The move fails if no other move has been used yet.",
|
||||
"cobblemon.move.coreenforcer": "Усиление ядра",
|
||||
"cobblemon.move.coreenforcer.desc": "If the Pokémon the user has inflicted damage on have already used their moves, this move eliminates the effect of the target’s Ability.",
|
||||
"cobblemon.move.coreenforcer.desc": "Если Покемоны, получившие урон от этого приёма, уже использовали свои приёмы в этом ходу, этот приём устраняет эффекты Способностей этих Покемонов.",
|
||||
"cobblemon.move.corkscrewcrash": "Штопорное крушение",
|
||||
"cobblemon.move.corkscrewcrash.desc": "The user spins very fast and rams into the target with the full force of its Z-Power. The power varies, depending on the original move.",
|
||||
"cobblemon.move.corrosivegas": "Разъедающий газ",
|
||||
@@ -1817,7 +1817,7 @@
|
||||
"cobblemon.move.counter": "Противостояние",
|
||||
"cobblemon.move.counter.desc": "A retaliation move that counters any physical attack, inflicting double the damage taken.",
|
||||
"cobblemon.move.courtchange": "Смена поля",
|
||||
"cobblemon.move.courtchange.desc": "With its mysterious power, the user swaps the effects on either side of the field.",
|
||||
"cobblemon.move.courtchange.desc": "С помощью своей таинственной силы пользователь меняет местами эффекты по обе стороны поля битвы.",
|
||||
"cobblemon.move.covet": "Жажда",
|
||||
"cobblemon.move.covet.desc": "The user endearingly approaches the target, then steals the target’s held item.",
|
||||
"cobblemon.move.crabhammer": "Крабовый молот",
|
||||
@@ -1847,7 +1847,7 @@
|
||||
"cobblemon.move.dazzlinggleam": "Ослепительный блеск",
|
||||
"cobblemon.move.dazzlinggleam.desc": "The user damages opposing Pokémon by emitting a powerful flash.",
|
||||
"cobblemon.move.decorate": "Декорация",
|
||||
"cobblemon.move.decorate.desc": "The user sharply raises the target’s Attack and Sp. Atk stats by decorating the target.",
|
||||
"cobblemon.move.decorate.desc": "Пользователь резко повышает Атаку и Спец. Атаку цели, украшая её.",
|
||||
"cobblemon.move.defendorder": "Приказ для защиты",
|
||||
"cobblemon.move.defendorder.desc": "The user calls out its underlings to shield its body, raising its Defense and Sp. Def stats.",
|
||||
"cobblemon.move.defensecurl": "Защитное скручивание",
|
||||
@@ -1885,7 +1885,7 @@
|
||||
"cobblemon.move.doublehit": "Двойной удар",
|
||||
"cobblemon.move.doublehit.desc": "The user slams the target with a long tail, vines, or a tentacle. The target is hit twice in a row.",
|
||||
"cobblemon.move.doubleironbash": "Двойной железный пролом",
|
||||
"cobblemon.move.doubleironbash.desc": "The user rotates, centering the hex nut in its chest, and then strikes with its arms twice in a row. This may also make the target flinch.",
|
||||
"cobblemon.move.doubleironbash.desc": "Пользователь использует гайку в своей груди в качестве оси для вращения, дважды ударяя цель руками. Это также может заставить цель вздрогнуть.",
|
||||
"cobblemon.move.doublekick": "Двойной пинок",
|
||||
"cobblemon.move.doublekick.desc": "The target is quickly kicked twice in succession using both feet.",
|
||||
"cobblemon.move.doubleshock": "Двойной шок",
|
||||
@@ -1905,11 +1905,11 @@
|
||||
"cobblemon.move.dragondance": "Драконий танец",
|
||||
"cobblemon.move.dragondance.desc": "The user vigorously performs a mystic, powerful dance that raises its Attack and Speed stats.",
|
||||
"cobblemon.move.dragondarts": "Драконьи заряды",
|
||||
"cobblemon.move.dragondarts.desc": "The user attacks twice using Dreepy. If there are two targets, this move hits each target once.",
|
||||
"cobblemon.move.dragondarts.desc": "Пользователь атакует дважды, используя Дрипи. Если противников двое, этот приём атакует каждого из них по одному разу.",
|
||||
"cobblemon.move.dragonenergy": "Драконья энергия",
|
||||
"cobblemon.move.dragonenergy.desc": "Превращая свою жизненную силу в энергию, пользователь атакует противника. Чем меньше ОЗ у пользователя, тем слабее этот приём.",
|
||||
"cobblemon.move.dragonhammer": "Драконий молот",
|
||||
"cobblemon.move.dragonhammer.desc": "The user uses its body like a hammer to attack the target and inflict damage.",
|
||||
"cobblemon.move.dragonhammer.desc": "Пользователь использует своё тело как молот, чтобы атаковать цель и нанести ей урон.",
|
||||
"cobblemon.move.dragonpulse": "Драконий пульс",
|
||||
"cobblemon.move.dragonpulse.desc": "The target is attacked with a shock wave generated by the user’s gaping mouth.",
|
||||
"cobblemon.move.dragonrage": "Драконья ярость",
|
||||
@@ -1929,13 +1929,13 @@
|
||||
"cobblemon.move.drillrun": "Бурение",
|
||||
"cobblemon.move.drillrun.desc": "The user crashes into its target while rotating its body like a drill. Critical hits land more easily.",
|
||||
"cobblemon.move.drumbeating": "Игра на барабане",
|
||||
"cobblemon.move.drumbeating.desc": "The user plays its drum, controlling the drum’s roots to attack the target. This also lowers the target’s Speed stat.",
|
||||
"cobblemon.move.drumbeating.desc": "Пользователь играет на барабане, управляя его корнями, чтобы атаковать цель. Это также понижает Скорость цели.",
|
||||
"cobblemon.move.dualchop": "Двойная атака",
|
||||
"cobblemon.move.dualchop.desc": "The user attacks its target by hitting it with brutal strikes. The target is hit twice in a row.",
|
||||
"cobblemon.move.dualwingbeat": "Двойной взмах крыльями",
|
||||
"cobblemon.move.dualwingbeat.desc": "Пользователь ударяет цель крыльями, нанося ей урон. Этот приём атакует дважды подряд.",
|
||||
"cobblemon.move.dynamaxcannon": "Динамакс пушка",
|
||||
"cobblemon.move.dynamaxcannon.desc": "The user unleashes a strong beam from its core. This move deals twice the damage if the target is Dynamaxed.",
|
||||
"cobblemon.move.dynamaxcannon.desc": "Пользователь собирает энергию внутри своего тела и высвобождает её из своего ядра, чтобы нанести урон.",
|
||||
"cobblemon.move.dynamicpunch": "Динамичный кулак",
|
||||
"cobblemon.move.dynamicpunch.desc": "The user punches the target with full, concentrated power. This confuses the target if it hits.",
|
||||
"cobblemon.move.earthpower": "Сила земли",
|
||||
@@ -1987,7 +1987,7 @@
|
||||
"cobblemon.move.extrasensory": "Экстрасенсорика",
|
||||
"cobblemon.move.extrasensory.desc": "The user attacks with an odd, unseeable power. This may also make the target flinch.",
|
||||
"cobblemon.move.extremeevoboost": "Экстремальное эвоусиление",
|
||||
"cobblemon.move.extremeevoboost.desc": "After obtaining Z-Power, the user, Eevee, gets energy from its evolved friends and boosts its stats sharply.",
|
||||
"cobblemon.move.extremeevoboost.desc": "После получения Z-Силы, Иви получает энергию от своих эволюционировавших друзей и резко повышает свои показатели.",
|
||||
"cobblemon.move.extremespeed": "Экстремальная скорость",
|
||||
"cobblemon.move.extremespeed.desc": "The user charges the target at blinding speed. This move always goes first.",
|
||||
"cobblemon.move.facade": "Бравада",
|
||||
@@ -2025,7 +2025,7 @@
|
||||
"cobblemon.move.firefang": "Огненный клык",
|
||||
"cobblemon.move.firefang.desc": "The user bites with flame-cloaked fangs. This may also make the target flinch or leave it with a burn.",
|
||||
"cobblemon.move.firelash": "Огненная плеть",
|
||||
"cobblemon.move.firelash.desc": "The user strikes the target with a burning lash. This also lowers the target’s Defense stat.",
|
||||
"cobblemon.move.firelash.desc": "Пользователь поражает цель горящим хлыстом. Это также понижает Защиту цели.",
|
||||
"cobblemon.move.firepledge": "Огненная клятва",
|
||||
"cobblemon.move.firepledge.desc": "A column of fire hits the target. When used with its grass equivalent, its power increases and a vast sea of fire appears.",
|
||||
"cobblemon.move.firepunch": "Огненный кулак",
|
||||
@@ -2035,7 +2035,7 @@
|
||||
"cobblemon.move.firstimpression": "Первое впечатление",
|
||||
"cobblemon.move.firstimpression.desc": "Although this move has great power, it only works the first turn each time the user enters battle.",
|
||||
"cobblemon.move.fishiousrend": "Рыбное раздирание",
|
||||
"cobblemon.move.fishiousrend.desc": "The user rends the target with its hard gills. If the user attacks before the target, the power of this move is doubled.",
|
||||
"cobblemon.move.fishiousrend.desc": "Пользователь разрывает цель своими твёрдыми жабрами. Сила этого приёма удваивается, если пользователь быстрее цели.",
|
||||
"cobblemon.move.fissure": "Разлом",
|
||||
"cobblemon.move.fissure.desc": "The user opens up a fissure in the ground and drops the target in. The target faints instantly if this attack hits.",
|
||||
"cobblemon.move.flail": "Размахивание",
|
||||
@@ -2057,15 +2057,15 @@
|
||||
"cobblemon.move.flatter": "Лесть",
|
||||
"cobblemon.move.flatter.desc": "Flattery is used to confuse the target. However, this also raises the target’s Sp. Atk stat.",
|
||||
"cobblemon.move.fleurcannon": "Цветочная пушка",
|
||||
"cobblemon.move.fleurcannon.desc": "The user unleashes a strong beam. The attack’s recoil harshly lowers the user’s Sp. Atk stat.",
|
||||
"cobblemon.move.fleurcannon.desc": "Пользователь выпускает мощный луч. Отдача от этого приёма резко понижает Спец. Атаку пользователя.",
|
||||
"cobblemon.move.fling": "Швырок",
|
||||
"cobblemon.move.fling.desc": "The user flings its held item at the target to attack. This move’s power and effects depend on the item.",
|
||||
"cobblemon.move.flipturn": "Смена хода",
|
||||
"cobblemon.move.flipturn.desc": "После атаки пользователь спешит обратно, чтобы поменяться местами с ожидающим Покемоном из команды.",
|
||||
"cobblemon.move.floatyfall": "Замедленное падение",
|
||||
"cobblemon.move.floatyfall.desc": "The user floats in the air, and then dives at a steep angle to attack the target. This may also make the target flinch.",
|
||||
"cobblemon.move.floatyfall.desc": "Пользователь парит в воздухе, а затем пикирует под крутым углом, чтобы атаковать цель. Это также может заставить цель вздрогнуть.",
|
||||
"cobblemon.move.floralhealing": "Цветочное лечение",
|
||||
"cobblemon.move.floralhealing.desc": "The user restores the target’s HP by up to half of its max HP. It restores more HP when the terrain is grass.",
|
||||
"cobblemon.move.floralhealing.desc": "Пользователь восстанавливает ОЗ цели до половины её максимального ОЗ. Пользователь может восстановить больше ОЗ, если активировано Травяное поле.",
|
||||
"cobblemon.move.flowershield": "Цветочный щит",
|
||||
"cobblemon.move.flowershield.desc": "The user raises the Defense stats of all Grass-type Pokémon in battle with a mysterious power.",
|
||||
"cobblemon.move.flowertrick": "Цветочный трюк",
|
||||
@@ -2097,7 +2097,7 @@
|
||||
"cobblemon.move.freezingglare": "Замораживающий взгляд",
|
||||
"cobblemon.move.freezingglare.desc": "Пользователь стреляет своей психической силой из глаз, чтобы атаковать. Это также может заморозить цель.",
|
||||
"cobblemon.move.freezyfrost": "Морозный холод",
|
||||
"cobblemon.move.freezyfrost.desc": "The user attacks with a crystal made of cold frozen haze. It eliminates every stat change among all the Pokémon engaged in battle.",
|
||||
"cobblemon.move.freezyfrost.desc": "Пользователь атакует кристаллом, сделанным из холодного замороженного тумана. Это устраняет изменения показателей у всех Покемонов, участвующих в битве.",
|
||||
"cobblemon.move.frenzyplant": "Безумное растение",
|
||||
"cobblemon.move.frenzyplant.desc": "The user slams the target with the roots of an enormous tree. The user can’t move on the next turn.",
|
||||
"cobblemon.move.frostbreath": "Морозное дыхание",
|
||||
@@ -2121,9 +2121,9 @@
|
||||
"cobblemon.move.geargrind": "Измельчение шестерёнками",
|
||||
"cobblemon.move.geargrind.desc": "The user attacks by throwing steel gears at its target twice.",
|
||||
"cobblemon.move.gearup": "Вспомогательные шестерёнки",
|
||||
"cobblemon.move.gearup.desc": "The user engages its gears to raise the Attack and Sp. Atk stats of ally Pokémon with the Plus or Minus Ability.",
|
||||
"cobblemon.move.gearup.desc": "Пользователь задействует свои механизмы, чтобы повысить Атаку и Спец. Атаку союзников с способностью Плюс или Минус.",
|
||||
"cobblemon.move.genesissupernova": "Супернова истоков",
|
||||
"cobblemon.move.genesissupernova.desc": "After obtaining Z-Power, the user, Mew, attacks the target with full force. The terrain will be charged with psychic energy.",
|
||||
"cobblemon.move.genesissupernova.desc": "После получения Z-Силы, Мью атакует цель с полной силой. Поле битвы заряжается психической энергией.",
|
||||
"cobblemon.move.geomancy": "Геомантия",
|
||||
"cobblemon.move.geomancy.desc": "The user absorbs energy and sharply raises its Sp. Atk, Sp. Def, and Speed stats on the next turn.",
|
||||
"cobblemon.move.gigadrain": "Гига истощение",
|
||||
@@ -2143,7 +2143,7 @@
|
||||
"cobblemon.move.glare": "Сглаз",
|
||||
"cobblemon.move.glare.desc": "The user intimidates the target with the pattern on its belly to cause paralysis.",
|
||||
"cobblemon.move.glitzyglow": "Блестящий свет",
|
||||
"cobblemon.move.glitzyglow.desc": "The user bombards the target with telekinetic force. A wondrous wall of light is put up to weaken the power of the opposing Pokémon’s special moves.",
|
||||
"cobblemon.move.glitzyglow.desc": "Пользователь бомбардирует цель телекинетической силой. Появляется удивительная стена из света, которая ослабляет специальные приёмы противника.",
|
||||
"cobblemon.move.gmaxbefuddle": "Г-макс Одурманивание",
|
||||
"cobblemon.move.gmaxbefuddle.desc": "Приём Насекомого типа, который использует Гигантамакс Баттерфри. Этот приём отравляет, парализует, или усыпляет противников.",
|
||||
"cobblemon.move.gmaxcannonade": "Г-макс Канонада",
|
||||
@@ -2229,7 +2229,7 @@
|
||||
"cobblemon.move.grudge": "Обида",
|
||||
"cobblemon.move.grudge.desc": "If the user faints, the user’s grudge fully depletes the PP of the opponent’s move that knocked it out.",
|
||||
"cobblemon.move.guardianofalola": "Хранитель Алолы",
|
||||
"cobblemon.move.guardianofalola.desc": "The user, the Land Spirit Pokémon, obtains Alola’s energy using its Z-Power and attacks the target with full force. This reduces the target’s HP greatly.",
|
||||
"cobblemon.move.guardianofalola.desc": "Пользователь, Покемон-дух земли, получает энергию Алолы с помощью своей Z-Силы и атакует цель с полной силой. Это значительно уменьшает ОЗ цели.",
|
||||
"cobblemon.move.guardsplit": "Разделение защиты",
|
||||
"cobblemon.move.guardsplit.desc": "The user employs its psychic power to average its Defense and Sp. Def stats with those of the target.",
|
||||
"cobblemon.move.guardswap": "Обмен защитой",
|
||||
@@ -2287,7 +2287,7 @@
|
||||
"cobblemon.move.hiddenpower": "Скрытая сила",
|
||||
"cobblemon.move.hiddenpower.desc": "A unique attack that varies in type depending on the Pokémon using it.",
|
||||
"cobblemon.move.highhorsepower": "Лошадиная сила",
|
||||
"cobblemon.move.highhorsepower.desc": "The user fiercely attacks the target using its entire body.",
|
||||
"cobblemon.move.highhorsepower.desc": "Пользователь яростно атакует цель, используя всё своё тело.",
|
||||
"cobblemon.move.highjumpkick": "Высокий удар в прыжке",
|
||||
"cobblemon.move.highjumpkick.desc": "The target is attacked with a knee kick from a jump. If it misses, the user is hurt instead.",
|
||||
"cobblemon.move.holdback": "Сдерживание",
|
||||
@@ -2335,7 +2335,7 @@
|
||||
"cobblemon.move.icefang": "Ледяной клык",
|
||||
"cobblemon.move.icefang.desc": "The user bites with cold-infused fangs. This may also make the target flinch or leave it frozen.",
|
||||
"cobblemon.move.icehammer": "Ледяной молот",
|
||||
"cobblemon.move.icehammer.desc": "The user swings and hits with its strong, heavy fist. It lowers the user’s Speed, however.",
|
||||
"cobblemon.move.icehammer.desc": "Пользователь наносит сильный удар кулаком по цели,. Это также понижает Скорость пользователя.",
|
||||
"cobblemon.move.icepunch": "Ледяной кулак",
|
||||
"cobblemon.move.icepunch.desc": "The target is punched with an icy fist. This may also leave the target frozen.",
|
||||
"cobblemon.move.iceshard": "Ледяной осколок",
|
||||
@@ -2363,7 +2363,7 @@
|
||||
"cobblemon.move.ingrain": "Укоренение",
|
||||
"cobblemon.move.ingrain.desc": "The user lays roots that restore its HP on every turn. Because it’s rooted, it can’t switch out.",
|
||||
"cobblemon.move.instruct": "Инструктаж",
|
||||
"cobblemon.move.instruct.desc": "The user instructs the target to use the target’s last move again.",
|
||||
"cobblemon.move.instruct.desc": "Пользователь даёт цели инструктаж по тому, как повторить последний приём, который использовала цель.",
|
||||
"cobblemon.move.iondeluge": "Ионный поток",
|
||||
"cobblemon.move.iondeluge.desc": "The user disperses electrically charged particles, which changes Normal-type moves to Electric-type moves.",
|
||||
"cobblemon.move.irondefense": "Железная защита",
|
||||
@@ -2373,7 +2373,7 @@
|
||||
"cobblemon.move.irontail": "Железный хвост",
|
||||
"cobblemon.move.irontail.desc": "The target is slammed with a steel-hard tail. This may also lower the target’s Defense stat.",
|
||||
"cobblemon.move.jawlock": "Сомкнутые челюсти",
|
||||
"cobblemon.move.jawlock.desc": "This move prevents the user and the target from switching out until either of them faints. The effect goes away if either of the Pokémon leaves the field.",
|
||||
"cobblemon.move.jawlock.desc": "Этот приём не позволяет пользователю и цели заменить себя, пока один из них не будет повержен. Эффект исчезает, если один из Покемонов покидает поле.",
|
||||
"cobblemon.move.jetpunch": "Кулак-струя",
|
||||
"cobblemon.move.jetpunch.desc": "Пользователь вызывает смерч вокруг своего кулака и наносит удары с ослепительной скоростью. Этот приём всегда атакует первым.",
|
||||
"cobblemon.move.judgment": "Суд",
|
||||
@@ -2395,7 +2395,7 @@
|
||||
"cobblemon.move.landswrath": "Гнев земли",
|
||||
"cobblemon.move.landswrath.desc": "The user gathers the energy of the land and focuses that power on opposing Pokémon to damage them.",
|
||||
"cobblemon.move.laserfocus": "Лазерный фокус",
|
||||
"cobblemon.move.laserfocus.desc": "The user concentrates intensely. The attack on the next turn always results in a critical hit.",
|
||||
"cobblemon.move.laserfocus.desc": "Пользователь интенсивно концентрируется. Атака в следующем ходу обязательно нанесёт критический урон.",
|
||||
"cobblemon.move.lashout": "Срыв",
|
||||
"cobblemon.move.lashout.desc": "Пользователь срывается на цель, чтобы выразить своё недовольство. Сила этого приёма удваивается, если показатели пользователя были снижены в течение этого хода.",
|
||||
"cobblemon.move.lastresort": "Последняя надежда",
|
||||
@@ -2405,7 +2405,7 @@
|
||||
"cobblemon.move.lavaplume": "Выброс лавы",
|
||||
"cobblemon.move.lavaplume.desc": "The user torches everything around it in an inferno of scarlet flames. This may also leave those it hits with a burn.",
|
||||
"cobblemon.move.leafage": "Листва",
|
||||
"cobblemon.move.leafage.desc": "The user attacks by pelting the target with leaves.",
|
||||
"cobblemon.move.leafage.desc": "Пользователь атакует, забрасывая цель листьями.",
|
||||
"cobblemon.move.leafblade": "Лиственное лезвие",
|
||||
"cobblemon.move.leafblade.desc": "The user handles a sharp leaf like a sword and attacks by cutting its target. Critical hits land more easily.",
|
||||
"cobblemon.move.leafstorm": "Лиственный шторм",
|
||||
@@ -2419,7 +2419,7 @@
|
||||
"cobblemon.move.leer": "Косой взгляд",
|
||||
"cobblemon.move.leer.desc": "The user gives opposing Pokémon an intimidating leer that lowers the Defense stat.",
|
||||
"cobblemon.move.letssnuggleforever": "Давай обниматься вечность",
|
||||
"cobblemon.move.letssnuggleforever.desc": "After obtaining Z-Power, the user, Mimikyu, punches the target with full force.",
|
||||
"cobblemon.move.letssnuggleforever.desc": "После получения Z-Силы, Мимикью бьёт цель с полной силой.",
|
||||
"cobblemon.move.lick": "Облизывание",
|
||||
"cobblemon.move.lick.desc": "The target is licked with a long tongue, causing damage. This may also leave the target with paralysis.",
|
||||
"cobblemon.move.lifedew": "Роса жизни",
|
||||
@@ -2429,9 +2429,9 @@
|
||||
"cobblemon.move.lightscreen": "Световой экран",
|
||||
"cobblemon.move.lightscreen.desc": "A wondrous wall of light is put up to reduce damage from special attacks for five turns.",
|
||||
"cobblemon.move.lightthatburnsthesky": "Свет, что прожигает небеса",
|
||||
"cobblemon.move.lightthatburnsthesky.desc": "This attack inflicts Attack or Sp. Atk damage— whichever stat is higher for the user, Necrozma. This move ignores the target’s Ability.",
|
||||
"cobblemon.move.lightthatburnsthesky.desc": "Этот приём наносить или физический, или специальный урон в зависимости от того, какой из этих показателей у Некрозмы выше. Этот приём игнорирует Способность цели.",
|
||||
"cobblemon.move.liquidation": "Ликвидация",
|
||||
"cobblemon.move.liquidation.desc": "The user slams into the target using a full-force blast of water. This may also lower the target’s Defense stat.",
|
||||
"cobblemon.move.liquidation.desc": "Пользователь атакует цель сильной струёй воды. Это также может понизить Защиту цели.",
|
||||
"cobblemon.move.lockon": "Прицеливание",
|
||||
"cobblemon.move.lockon.desc": "The user takes sure aim at the target. This ensures the next attack does not miss the target.",
|
||||
"cobblemon.move.lovelykiss": "Любовный поцелуй",
|
||||
@@ -2449,7 +2449,7 @@
|
||||
"cobblemon.move.lunardance": "Лунный танец",
|
||||
"cobblemon.move.lunardance.desc": "The user faints. In return, the Pokémon taking its place will have its status and HP fully restored.",
|
||||
"cobblemon.move.lunge": "Выпад",
|
||||
"cobblemon.move.lunge.desc": "The user makes a lunge at the target, attacking with full force. This also lowers the target’s Attack stat.",
|
||||
"cobblemon.move.lunge.desc": "Пользователь делает выпад в сторону цели, атакуя с полной силой. Это также понижает Атаку цели.",
|
||||
"cobblemon.move.lusterpurge": "Сияющее очищение",
|
||||
"cobblemon.move.lusterpurge.desc": "The user lets loose a damaging burst of light. This may also lower the target’s Sp. Def stat.",
|
||||
"cobblemon.move.machpunch": "Маховый кулак",
|
||||
@@ -2461,7 +2461,7 @@
|
||||
"cobblemon.move.magiccoat": "Волшебное покрытие",
|
||||
"cobblemon.move.magiccoat.desc": "Moves like Leech Seed and moves that inflict status conditions are blocked by a barrier and reflected back to the user of those moves.",
|
||||
"cobblemon.move.magicpowder": "Волшебная пыль",
|
||||
"cobblemon.move.magicpowder.desc": "The user scatters a cloud of magic powder that changes the target to Psychic type.",
|
||||
"cobblemon.move.magicpowder.desc": "Пользователь рассыпает облако волшебной пыли, которая меняет тип цели на Психический.",
|
||||
"cobblemon.move.magicroom": "Волшебная комната",
|
||||
"cobblemon.move.magicroom.desc": "The user creates a bizarre area in which Pokémon’s held items lose their effects for five turns.",
|
||||
"cobblemon.move.magmastorm": "Магмовый шторм",
|
||||
@@ -2476,50 +2476,50 @@
|
||||
"cobblemon.move.magnitude.desc": "The user attacks everything around it with a ground-shaking quake. Its power varies.",
|
||||
"cobblemon.move.makeitrain": "Денежный дождь",
|
||||
"cobblemon.move.makeitrain.desc": "Пользователь атакует, выбрасывая массу монет. Это также понижает Спец. Атаку пользователя. Деньги зарабатываются после битвы.",
|
||||
"cobblemon.move.maliciousmoonsault": "Злобное лунное сальто",
|
||||
"cobblemon.move.maliciousmoonsault.desc": "The user, Incineroar, strengthens its body using its Z-Power and crashes into the target with full force.",
|
||||
"cobblemon.move.maliciousmoonsault": "Злодейский мунсолт",
|
||||
"cobblemon.move.maliciousmoonsault.desc": "Инсинерор укрепляет своё тело, используя свою Z-Силу, и врезается в цель с полной силой.",
|
||||
"cobblemon.move.malignantchain": "Ядовитая цепь",
|
||||
"cobblemon.move.malignantchain.desc": "Пользователь вливает в цель токсины, окутывая её ядовитой, разъедающей цепью. Это может сильно отравить цель.",
|
||||
"cobblemon.move.matblock": "Блокировка матом",
|
||||
"cobblemon.move.matblock.desc": "Using a pulled-up mat as a shield, the user protects itself and its allies from damaging moves. This does not stop status moves.",
|
||||
"cobblemon.move.maxairstream": "Макс Воздушный поток",
|
||||
"cobblemon.move.maxairstream.desc": "This is a Flying-type attack Dynamax Pokémon use. This raises ally Pokémon’s Speed stats.",
|
||||
"cobblemon.move.maxairstream.desc": "Это приём Летающего типа, который используют Динамакс Покемоны. Он повышает Скорость союзников.",
|
||||
"cobblemon.move.maxdarkness": "Макс Темнота",
|
||||
"cobblemon.move.maxdarkness.desc": "This is a Dark-type attack Dynamax Pokémon use. This lowers the target’s Sp. Def stat.",
|
||||
"cobblemon.move.maxdarkness.desc": "Это приём Тёмного типа, который используют Динамакс Покемоны. Он понижает Спец. Защиту цели.",
|
||||
"cobblemon.move.maxflare": "Макс Вспышка",
|
||||
"cobblemon.move.maxflare.desc": "This is a Fire-type attack Dynamax Pokémon use. The user intensifies the sun for five turns.",
|
||||
"cobblemon.move.maxflare.desc": "Это приём Огненного типа, который используют Динамакс Покемоны. Пользователь усиливает солнечный свет на пять ходов.",
|
||||
"cobblemon.move.maxflutterby": "Макс Пархание",
|
||||
"cobblemon.move.maxflutterby.desc": "This is a Bug-type attack Dynamax Pokémon use. This lowers the target’s Sp. Atk stat.",
|
||||
"cobblemon.move.maxflutterby.desc": "Это приём Насекомого типа, который используют Динамакс Покемоны. Он понижает Спец. Атаку цели.",
|
||||
"cobblemon.move.maxgeyser": "Макс Гейщер",
|
||||
"cobblemon.move.maxgeyser.desc": "This is a Water-type attack Dynamax Pokémon use. The user summons a heavy rain that falls for five turns.",
|
||||
"cobblemon.move.maxgeyser.desc": "Это приём Водного типа, который используют Динамакс Покемоны. Пользователь призывает сильный дождь на пять ходов.",
|
||||
"cobblemon.move.maxguard": "Макс Защита",
|
||||
"cobblemon.move.maxguard.desc": "This move enables the user to protect itself from all attacks. Its chance of failing rises if it is used in succession.",
|
||||
"cobblemon.move.maxguard.desc": "Этот приём позволяет пользователю защитить себя от всех атак. Вероятность его провала возрастает, если этот приём используется несколько раз подряд.",
|
||||
"cobblemon.move.maxhailstorm": "Макс Град",
|
||||
"cobblemon.move.maxhailstorm.desc": "This is an Ice-type attack Dynamax Pokémon use. The user summons a hailstorm lasting five turns.",
|
||||
"cobblemon.move.maxhailstorm.desc": "Это приём Ледяного типа, который используют Динамакс Покемоны. Пользователь призывает метель на пять ходов.",
|
||||
"cobblemon.move.maxknuckle": "Макс Кулак",
|
||||
"cobblemon.move.maxknuckle.desc": "This is a Fighting-type attack Dynamax Pokémon use. This raises ally Pokémon’s Attack stats.",
|
||||
"cobblemon.move.maxknuckle.desc": "Это приём Боевого типа, который используют Динамакс Покемоны. Он повышает Атаку союзников.",
|
||||
"cobblemon.move.maxlightning": "Макс Гроза",
|
||||
"cobblemon.move.maxlightning.desc": "This is an Electric-type attack Dynamax Pokémon use. The user turns the ground into Electric Terrain for five turns.",
|
||||
"cobblemon.move.maxlightning.desc": "Это приём Электрического типа, который используют Динамакс Покемоны. Пользователь превращает поле битвы в Электрическое поле на пять ходов.",
|
||||
"cobblemon.move.maxmindstorm": "Макс Мозговой штурм",
|
||||
"cobblemon.move.maxmindstorm.desc": "This is a Psychic-type attack Dynamax Pokémon use. The user turns the ground into Psychic Terrain for five turns.",
|
||||
"cobblemon.move.maxmindstorm.desc": "Это приём Психического типа, который используют Динамакс Покемоны. Пользователь превращает поле битвы в Психическое поле на пять ходов.",
|
||||
"cobblemon.move.maxooze": "Макс Слизь",
|
||||
"cobblemon.move.maxooze.desc": "This is a Poison-type attack Dynamax Pokémon use. This raises ally Pokémon’s Sp. Atk stats.",
|
||||
"cobblemon.move.maxooze.desc": "Это приём Ядовитого типа, который используют Динамакс Покемоны. Он повышает Спец. Атаку союзников.",
|
||||
"cobblemon.move.maxovergrowth": "Макс Зарастание",
|
||||
"cobblemon.move.maxovergrowth.desc": "This is a Grass-type attack Dynamax Pokémon use. The user turns the ground into Grassy Terrain for five turns.",
|
||||
"cobblemon.move.maxphantasm": "Макс Фантом",
|
||||
"cobblemon.move.maxphantasm.desc": "This is a Ghost-type attack Dynamax Pokémon use. This lowers the target’s Defense stat.",
|
||||
"cobblemon.move.maxovergrowth.desc": "Это приём Травяного типа, который используют Динамакс Покемоны. Пользователь превращает поле битвы в Травяное поле на пять ходов.",
|
||||
"cobblemon.move.maxphantasm": "Макс Фантазм",
|
||||
"cobblemon.move.maxphantasm.desc": "Это приём Призрачного типа, который используют Динамакс Покемоны. Он понижает Защиту цели.",
|
||||
"cobblemon.move.maxquake": "Макс Землетрясение",
|
||||
"cobblemon.move.maxquake.desc": "This is a Ground-type attack Dynamax Pokémon use. This raises ally Pokémon’s Sp. Def stats.",
|
||||
"cobblemon.move.maxquake.desc": "Это приём Земляного типа, который используют Динамакс Покемоны. Он повышает Спец. Защиту союзников.",
|
||||
"cobblemon.move.maxrockfall": "Макс Камнепад",
|
||||
"cobblemon.move.maxrockfall.desc": "This is a Rock-type attack Dynamax Pokémon use. The user summons a sandstorm lasting five turns.",
|
||||
"cobblemon.move.maxrockfall.desc": "Это приём Каменного типа, который используют Динамакс Покемоны. Пользователь призывает песчаную бурю на пять ходов.",
|
||||
"cobblemon.move.maxstarfall": "Макс Звездопад",
|
||||
"cobblemon.move.maxstarfall.desc": "This is a Fairy-type attack Dynamax Pokémon use. The user turns the ground into Misty Terrain for five turns.",
|
||||
"cobblemon.move.maxstarfall.desc": "Это приём Волшебного типа, который используют Динамакс Покемоны. Пользователь превращает поле битвы в Туманное поле на пять ходов.",
|
||||
"cobblemon.move.maxsteelspike": "Макс Стальной шип",
|
||||
"cobblemon.move.maxsteelspike.desc": "This is a Steel-type attack Dynamax Pokémon use. This raises ally Pokémon’s Defense stats.",
|
||||
"cobblemon.move.maxsteelspike.desc": "Это приём Стального типа, который используют Динамакс Покемоны. Он повышает Защиту союзников.",
|
||||
"cobblemon.move.maxstrike": "Макс Удар",
|
||||
"cobblemon.move.maxstrike.desc": "This is a Normal-type attack Dynamax Pokémon use. This lowers the target’s Speed stat.",
|
||||
"cobblemon.move.maxstrike.desc": "Это приём Нормального типа, который используют Динамакс Покемоны. Он понижает Скорость цели.",
|
||||
"cobblemon.move.maxwyrmwind": "Макс Ураган",
|
||||
"cobblemon.move.maxwyrmwind.desc": "This is a Dragon-type attack Dynamax Pokémon use. This lowers the target’s Attack stat.",
|
||||
"cobblemon.move.maxwyrmwind.desc": "Это приём Драконьего типа, который используют Динамакс Покемоны. Он понижает Атаку цели.",
|
||||
"cobblemon.move.meanlook": "Злобный взгляд",
|
||||
"cobblemon.move.meanlook.desc": "The user pins the target with a dark, arresting look. The target becomes unable to flee.",
|
||||
"cobblemon.move.meditate": "Медитация",
|
||||
@@ -2536,8 +2536,8 @@
|
||||
"cobblemon.move.megapunch.desc": "The target is slugged by a punch thrown with muscle-packed power.",
|
||||
"cobblemon.move.memento": "Воспоминание",
|
||||
"cobblemon.move.memento.desc": "The user faints when using this move. In return, this harshly lowers the target’s Attack and Sp. Atk stats.",
|
||||
"cobblemon.move.menacingmoonrazemaelstrom": "Грозно-лунный омут",
|
||||
"cobblemon.move.menacingmoonrazemaelstrom.desc": "After obtaining Z-Power, the user, Lunala, attacks the target with full force. This move can ignore the effect of the target’s Ability.",
|
||||
"cobblemon.move.menacingmoonrazemaelstrom": "Грозный лунный омут",
|
||||
"cobblemon.move.menacingmoonrazemaelstrom.desc": "После получения Z-Силы, Лунала атакует цель с полной силой. Этот приём может игнорировать эффекты от Способности у цели.",
|
||||
"cobblemon.move.metalburst": "Металлический взрыв",
|
||||
"cobblemon.move.metalburst.desc": "The user retaliates with much greater force against the opponent that last inflicted damage on it.",
|
||||
"cobblemon.move.metalclaw": "Металлический коготь",
|
||||
@@ -2557,7 +2557,7 @@
|
||||
"cobblemon.move.mimic": "Подражание",
|
||||
"cobblemon.move.mimic.desc": "The user copies the target’s last move. The move can be used during battle until the Pokémon is switched out.",
|
||||
"cobblemon.move.mindblown": "Взрыв мозга",
|
||||
"cobblemon.move.mindblown.desc": "The user attacks everything around it by causing its own head to explode. This also damages the user.",
|
||||
"cobblemon.move.mindblown.desc": "Пользователь атакует всё вокруг, взрывая свою голову. Это также наносит урон пользователю.",
|
||||
"cobblemon.move.mindreader": "Чтение мыслей",
|
||||
"cobblemon.move.mindreader.desc": "The user senses the target’s movements with its mind to ensure its next attack does not miss the target.",
|
||||
"cobblemon.move.minimize": "Уменьшение",
|
||||
@@ -2580,8 +2580,8 @@
|
||||
"cobblemon.move.mistyterrain.desc": "This protects Pokémon on the ground from status conditions and halves damage from Dragon-type moves for five turns.",
|
||||
"cobblemon.move.moonblast": "Лунный залп",
|
||||
"cobblemon.move.moonblast.desc": "Borrowing the power of the moon, the user attacks the target. This may also lower the target’s Sp. Atk stat.",
|
||||
"cobblemon.move.moongeistbeam": "Луч лунного духа",
|
||||
"cobblemon.move.moongeistbeam.desc": "The user emits a sinister ray to attack the target. This move can be used on the target regardless of its Abilities.",
|
||||
"cobblemon.move.moongeistbeam": "Лунно-призрачный луч",
|
||||
"cobblemon.move.moongeistbeam.desc": "Пользователь выпускает зловещий луч, чтобы атаковать цель. Этот приём можно использовать на цели независимо от её способности.",
|
||||
"cobblemon.move.moonlight": "Лунный свет",
|
||||
"cobblemon.move.moonlight.desc": "The user restores its own HP. The amount of HP regained varies with the weather.",
|
||||
"cobblemon.move.morningsun": "Утреннее солнце",
|
||||
@@ -2601,7 +2601,7 @@
|
||||
"cobblemon.move.mudsport": "Грязевая игра",
|
||||
"cobblemon.move.mudsport.desc": "The user kicks up mud on the battlefield. This weakens Electric-type moves for five turns.",
|
||||
"cobblemon.move.multiattack": "Мультиатака",
|
||||
"cobblemon.move.multiattack.desc": "Cloaking itself in high energy, the user slams into the target. The memory held determines the move’s type.",
|
||||
"cobblemon.move.multiattack.desc": "Окутывая себя мощной энергией, пользователь наносит урон цели. Тип этого приёма меняется в зависимости от типа диска памяти, который держит пользователь.",
|
||||
"cobblemon.move.mysticalfire": "Таинственный огонь",
|
||||
"cobblemon.move.mysticalfire.desc": "The user attacks by breathing a special, hot fire. This also lowers the target’s Sp. Atk stat.",
|
||||
"cobblemon.move.mysticalpower": "Таинственная сила",
|
||||
@@ -2613,7 +2613,7 @@
|
||||
"cobblemon.move.naturepower": "Природная сила",
|
||||
"cobblemon.move.naturepower.desc": "This attack makes use of nature’s power. Its effects vary depending on the user’s environment.",
|
||||
"cobblemon.move.naturesmadness": "Безумие природы",
|
||||
"cobblemon.move.naturesmadness.desc": "The user hits the target with the force of nature. It halves the target’s HP.",
|
||||
"cobblemon.move.naturesmadness.desc": "Пользователь наносит удар по цели со всей яростью природы. Это уменьшает ОЗ цели вдвое.",
|
||||
"cobblemon.move.needlearm": "Колючая рука",
|
||||
"cobblemon.move.needlearm.desc": "The user attacks by wildly swinging its thorny arms. This may also make the target flinch.",
|
||||
"cobblemon.move.neverendingnightmare": "Бесконечный кошмар",
|
||||
@@ -2629,7 +2629,7 @@
|
||||
"cobblemon.move.nobleroar": "Благородный рёв",
|
||||
"cobblemon.move.nobleroar.desc": "Letting out a noble roar, the user intimidates the target and lowers its Attack and Sp. Atk stats.",
|
||||
"cobblemon.move.noretreat": "Без отступления",
|
||||
"cobblemon.move.noretreat.desc": "This move raises all the user’s stats but prevents the user from switching out or fleeing.",
|
||||
"cobblemon.move.noretreat.desc": "Этот приём повышает все показатели пользователя, но не позволяет ему уйти на замену или сбежать.",
|
||||
"cobblemon.move.noxioustorque": "Ядовитый дрифт",
|
||||
"cobblemon.move.noxioustorque.desc": "Has a 30% chance to poison the target.",
|
||||
"cobblemon.move.nuzzle": "Трение",
|
||||
@@ -2639,11 +2639,11 @@
|
||||
"cobblemon.move.obstruct": "Препятствие",
|
||||
"cobblemon.move.obstruct.desc": "Этот приём позволяет пользователю защитить себя от всех атак. Вероятность провала возрастает при последовательном использовании. Прямой контакт резко понижает Защиту атакующего.",
|
||||
"cobblemon.move.oceanicoperetta": "Океанская оперетта",
|
||||
"cobblemon.move.oceanicoperetta.desc": "The user, Primarina, summons a massive amount of water using its Z-Power and attacks the target with full force.",
|
||||
"cobblemon.move.oceanicoperetta.desc": "Примарина призывает огромное количество воды, используя свою Z-Силу, и атакует цель с полной силой.",
|
||||
"cobblemon.move.octazooka": "Осьмизука",
|
||||
"cobblemon.move.octazooka.desc": "The user attacks by spraying ink in the target’s face or eyes. This may also lower the target’s accuracy.",
|
||||
"cobblemon.move.octolock": "Осьмихват",
|
||||
"cobblemon.move.octolock.desc": "The user locks the target in and prevents it from fleeing. This move also lowers the target’s Defense and Sp. Def every turn.",
|
||||
"cobblemon.move.octolock.desc": "Пользователь захватывает цель и не дает ей убежать. Этот приёма также понижает Защиту и Спец. Защиту цели каждый ход.",
|
||||
"cobblemon.move.odorsleuth": "Поиск запаха",
|
||||
"cobblemon.move.odorsleuth.desc": "Enables a Ghost-type target to be hit by Normal- and Fighting-type attacks. This also enables an evasive target to be hit.",
|
||||
"cobblemon.move.ominouswind": "Зловещий ветер",
|
||||
@@ -2679,13 +2679,13 @@
|
||||
"cobblemon.move.phantomforce": "Фантомная сила",
|
||||
"cobblemon.move.phantomforce.desc": "The user vanishes somewhere, then strikes the target on the next turn. This move hits even if the target protects itself.",
|
||||
"cobblemon.move.photongeyser": "Фотонный гейзер",
|
||||
"cobblemon.move.photongeyser.desc": "The user attacks a target with a pillar of light. This move inflicts Attack or Sp. Atk damage—whichever stat is higher for the user.",
|
||||
"cobblemon.move.photongeyser.desc": "Пользователь атакует цель столбом света. Этот приём наносит или физический, или специальный урон в зависимости от того, какой из этих показателей у пользователя выше.",
|
||||
"cobblemon.move.pikapapow": "Пика тыдыщ",
|
||||
"cobblemon.move.pikapapow.desc": "The more Pikachu loves its Trainer, the greater the move’s power. It never misses.",
|
||||
"cobblemon.move.pikapapow.desc": "Чем больше Пикачу любит своего Тренера, тем сильнее становится этот приём. Он никогда не промахивается.",
|
||||
"cobblemon.move.pinmissile": "Шип-снаряд",
|
||||
"cobblemon.move.pinmissile.desc": "Sharp spikes are shot at the target in rapid succession. They hit two to five times in a row.",
|
||||
"cobblemon.move.plasmafists": "Плазменные кулаки",
|
||||
"cobblemon.move.plasmafists.desc": "The user attacks with electrically charged fists. This move changes Normal-type moves to Electric-type moves.",
|
||||
"cobblemon.move.plasmafists.desc": "Пользователь атакует электрически заряженными кулаками. Этот приём меняет приёмы Нормального типа на Электрический.",
|
||||
"cobblemon.move.playnice": "Хорошее поведение",
|
||||
"cobblemon.move.playnice.desc": "The user and the target become friends, and the target loses its will to fight. This lowers the target’s Attack stat.",
|
||||
"cobblemon.move.playrough": "Грубая игра",
|
||||
@@ -2705,7 +2705,7 @@
|
||||
"cobblemon.move.poisontail": "Ядовитый хвост",
|
||||
"cobblemon.move.poisontail.desc": "The user hits the target with its tail. This may also poison the target. Critical hits land more easily.",
|
||||
"cobblemon.move.pollenpuff": "Шарик пыльцы",
|
||||
"cobblemon.move.pollenpuff.desc": "The user attacks the enemy with a pollen puff that explodes. If the target is an ally, it gives the ally a pollen puff that restores its HP instead.",
|
||||
"cobblemon.move.pollenpuff.desc": "Пользователь атакует врага взрывающимся облаком пыльцы. Если цель является союзником, то вместо этого он даёт ему облако пыльцы, которое восстанавливает его ОЗ.",
|
||||
"cobblemon.move.poltergeist": "Полтергейст",
|
||||
"cobblemon.move.poltergeist.desc": "Пользователь атакует, контролируя предмет цели. Этот приём не сработает, если цель не держит предмет.",
|
||||
"cobblemon.move.populationbomb": "Популяционная бомба",
|
||||
@@ -2729,7 +2729,7 @@
|
||||
"cobblemon.move.powertrick": "Силовой трюк",
|
||||
"cobblemon.move.powertrick.desc": "The user employs its psychic power to switch its Attack stat with its Defense stat.",
|
||||
"cobblemon.move.powertrip": "Хвастовство",
|
||||
"cobblemon.move.powertrip.desc": "The user boasts its strength and attacks the target. The more the user’s stats are raised, the greater the move’s power.",
|
||||
"cobblemon.move.powertrip.desc": "Пользователь хвастается своей силой и атакует цель. Чем выше показатели пользователя, тем сильнее этот приём.",
|
||||
"cobblemon.move.poweruppunch": "Усиливающий кулак",
|
||||
"cobblemon.move.poweruppunch.desc": "Striking opponents over and over makes the user’s fists harder. Hitting a target raises the Attack stat.",
|
||||
"cobblemon.move.powerwhip": "Силовой хлыст",
|
||||
@@ -2739,7 +2739,7 @@
|
||||
"cobblemon.move.present": "Подарок",
|
||||
"cobblemon.move.present.desc": "The user attacks by giving the target a gift with a hidden trap. It restores HP sometimes, however.",
|
||||
"cobblemon.move.prismaticlaser": "Призматический лазер",
|
||||
"cobblemon.move.prismaticlaser.desc": "The user shoots powerful lasers using the power of a prism. The user can’t move on the next turn.",
|
||||
"cobblemon.move.prismaticlaser.desc": "Пользователь стреляет мощными лазерами, используя силу призмы. Пользователь не может атаковать в следующем ходу.",
|
||||
"cobblemon.move.protect": "Щит",
|
||||
"cobblemon.move.protect.desc": "This move enables the user to protect itself from all attacks. Its chance of failing rises if it is used in succession.",
|
||||
"cobblemon.move.psybeam": "Психолуч",
|
||||
@@ -2747,9 +2747,9 @@
|
||||
"cobblemon.move.psychic": "Психокинез",
|
||||
"cobblemon.move.psychic.desc": "The target is hit by a strong telekinetic force. This may also lower the target’s Sp. Def stat.",
|
||||
"cobblemon.move.psychicfangs": "Психический клык",
|
||||
"cobblemon.move.psychicfangs.desc": "The user bites the target with its psychic capabilities. This can also destroy Light Screen and Reflect.",
|
||||
"cobblemon.move.psychicfangs.desc": "Пользователь атакует, кусая цель своими психическими способностями. Этот приём также может разрушать барьеры, такие как Световой экран и Отражение.",
|
||||
"cobblemon.move.psychicterrain": "Психическое поле",
|
||||
"cobblemon.move.psychicterrain.desc": "This protects Pokémon on the ground from priority moves and powers up Psychic-type moves for five turns.",
|
||||
"cobblemon.move.psychicterrain.desc": "Этот приём защищает Покемонов на земле от приоритетных приёмов и усиливает приёмы Психического типа на пять ходов.",
|
||||
"cobblemon.move.psychoboost": "Психо усиление",
|
||||
"cobblemon.move.psychoboost.desc": "The user attacks the target at full power. The attack’s recoil harshly lowers the user’s Sp. Atk stat.",
|
||||
"cobblemon.move.psychocut": "Психо порез",
|
||||
@@ -2767,11 +2767,11 @@
|
||||
"cobblemon.move.psywave": "Психоволна",
|
||||
"cobblemon.move.psywave.desc": "The target is attacked with an odd psychic wave. The attack varies in intensity.",
|
||||
"cobblemon.move.pulverizingpancake": "Размельчающий блин",
|
||||
"cobblemon.move.pulverizingpancake.desc": "Z-Power brings out the true capabilities of the user, Snorlax. The Pokémon moves its enormous body energetically and attacks the target with full force.",
|
||||
"cobblemon.move.pulverizingpancake.desc": "Z-Сила раскрывает истинные способности Снорлакса. Покемон энергично двигает своим огромным телом и атакует цель с полной силой.",
|
||||
"cobblemon.move.punishment": "Наказание",
|
||||
"cobblemon.move.punishment.desc": "The more the target has powered up with stat changes, the greater the move’s power.",
|
||||
"cobblemon.move.purify": "Очищение",
|
||||
"cobblemon.move.purify.desc": "The user heals the target’s status condition. If the move succeeds, it also restores the user’s own HP.",
|
||||
"cobblemon.move.purify.desc": "Пользователь лечит статусные эффекты цели. Если приём проходит успешно, он также восстанавливает ОЗ пользователя.",
|
||||
"cobblemon.move.pursuit": "Преследование",
|
||||
"cobblemon.move.pursuit.desc": "The power of this attack move is doubled if it’s used on a target that’s switching out of battle.",
|
||||
"cobblemon.move.pyroball": "Пиро шар",
|
||||
@@ -2824,7 +2824,7 @@
|
||||
"cobblemon.move.return": "Возврат",
|
||||
"cobblemon.move.return.desc": "This full-power attack grows more powerful the more the user likes its Trainer.",
|
||||
"cobblemon.move.revelationdance": "Танец откровения",
|
||||
"cobblemon.move.revelationdance.desc": "The user attacks the target by dancing very hard. The user’s type determines the type of this move.",
|
||||
"cobblemon.move.revelationdance.desc": "Пользователь атакует цель, танцуя со всей своей силой. Этот приём становится такого же типа, как и тип пользователя.",
|
||||
"cobblemon.move.revenge": "Месть",
|
||||
"cobblemon.move.revenge.desc": "This attack move’s power is doubled if the user has been hurt by the opponent in the same turn.",
|
||||
"cobblemon.move.reversal": "Переворот",
|
||||
@@ -2884,7 +2884,7 @@
|
||||
"cobblemon.move.sandtomb": "Песчаная могила",
|
||||
"cobblemon.move.sandtomb.desc": "The user traps the target inside a harshly raging sandstorm for four to five turns.",
|
||||
"cobblemon.move.sappyseed": "Истощающее семя",
|
||||
"cobblemon.move.sappyseed.desc": "The user grows a gigantic stalk that scatters seeds to attack the target. The seeds drain the target’s HP every turn.",
|
||||
"cobblemon.move.sappyseed.desc": "Пользователь выращивает гигантский стебель, который разбрасывает семена, чтобы атаковать цель. Семена уменьшают ОЗ цели каждый ход.",
|
||||
"cobblemon.move.savagespinout": "Жестокая закрутка",
|
||||
"cobblemon.move.savagespinout.desc": "The user binds the target with full force with threads of silk that the user spits using its Z-Power. The power varies, depending on the original move.",
|
||||
"cobblemon.move.scald": "Кипяток",
|
||||
@@ -2902,7 +2902,7 @@
|
||||
"cobblemon.move.searingshot": "Жгучий выстрел",
|
||||
"cobblemon.move.searingshot.desc": "The user torches everything around it in an inferno of scarlet flames. This may also leave those it hits with a burn.",
|
||||
"cobblemon.move.searingsunrazesmash": "Жгучий солнечный удар",
|
||||
"cobblemon.move.searingsunrazesmash.desc": "After obtaining Z-Power, the user, Solgaleo, attacks the target with full force. This move can ignore the effect of the target’s Ability.",
|
||||
"cobblemon.move.searingsunrazesmash.desc": "После получения Z-Силы, Солгалео атакует цель с полной силой. Этот приём может игнорировать эффекты от Способности у цели.",
|
||||
"cobblemon.move.secretpower": "Тайная сила",
|
||||
"cobblemon.move.secretpower.desc": "The additional effects of this attack depend upon where it was used.",
|
||||
"cobblemon.move.secretsword": "Тайный меч",
|
||||
@@ -2918,7 +2918,7 @@
|
||||
"cobblemon.move.shadowball": "Теневой шар",
|
||||
"cobblemon.move.shadowball.desc": "The user hurls a shadowy blob at the target. This may also lower the target’s Sp. Def stat.",
|
||||
"cobblemon.move.shadowbone": "Теневая кость",
|
||||
"cobblemon.move.shadowbone.desc": "The user attacks by beating the target with a bone that contains a spirit. This may also lower the target’s Defense stat.",
|
||||
"cobblemon.move.shadowbone.desc": "Пользователь атакует, ударяя цель костью, в которой заключён дух. Это также может понизить Защиту цели.",
|
||||
"cobblemon.move.shadowclaw": "Теневой коготь",
|
||||
"cobblemon.move.shadowclaw.desc": "The user slashes with a sharp claw made from shadows. Critical hits land more easily.",
|
||||
"cobblemon.move.shadowforce": "Теневая сила",
|
||||
@@ -2940,7 +2940,7 @@
|
||||
"cobblemon.move.shellsmash": "Разлом панциря",
|
||||
"cobblemon.move.shellsmash.desc": "The user breaks its shell, which lowers Defense and Sp. Def stats but sharply raises its Attack, Sp. Atk, and Speed stats.",
|
||||
"cobblemon.move.shelltrap": "Панцирь-ловушка",
|
||||
"cobblemon.move.shelltrap.desc": "The user sets a shell trap. If the user is hit by a physical move, the trap will explode and inflict damage on opposing Pokémon.",
|
||||
"cobblemon.move.shelltrap.desc": "Пользователь устанавливает ловушку. Если пользователь получает удар физическим приёмом, ловушка взрывается и наносит урон противнику.",
|
||||
"cobblemon.move.shelter": "Убежище",
|
||||
"cobblemon.move.shelter.desc": "Пользователь делает свою кожу твёрдой, как железный щит, резко повышая свою Защиту.",
|
||||
"cobblemon.move.shiftgear": "Сдвиг шестерёнок",
|
||||
@@ -2960,9 +2960,9 @@
|
||||
"cobblemon.move.sing": "Пение",
|
||||
"cobblemon.move.sing.desc": "A soothing lullaby is sung in a calming voice that puts the target into a deep slumber.",
|
||||
"cobblemon.move.sinisterarrowraid": "Зловещий град стрел",
|
||||
"cobblemon.move.sinisterarrowraid.desc": "The user, Decidueye, creates countless arrows using its Z-Power and shoots the target with full force.",
|
||||
"cobblemon.move.sinisterarrowraid.desc": "Десиджуай создаёт бесчисленное количество стрел, используя свою Z-Силу, и стреляет в цель с полной силой.",
|
||||
"cobblemon.move.sizzlyslide": "Шипящее скольжение",
|
||||
"cobblemon.move.sizzlyslide.desc": "The user cloaks itself in fire and charges at the target. This also leaves the target with a burn.",
|
||||
"cobblemon.move.sizzlyslide.desc": "Пользователь окружает себя огнём и бросается на цель. Это также обжигает цель.",
|
||||
"cobblemon.move.sketch": "Набросок",
|
||||
"cobblemon.move.sketch.desc": "It enables the user to permanently learn the move last used by the target. Once used, Sketch disappears.",
|
||||
"cobblemon.move.skillswap": "Обмен навыками",
|
||||
@@ -2996,7 +2996,7 @@
|
||||
"cobblemon.move.smackdown": "Сбивание",
|
||||
"cobblemon.move.smackdown.desc": "The user throws a stone or similar projectile to attack the target. A flying Pokémon will fall to the ground when it’s hit.",
|
||||
"cobblemon.move.smartstrike": "Умный удар",
|
||||
"cobblemon.move.smartstrike.desc": "The user stabs the target with a sharp horn. This attack never misses.",
|
||||
"cobblemon.move.smartstrike.desc": "Пользователь наносит удар по цели острым рогом. Этот приём никогда не промахивается.",
|
||||
"cobblemon.move.smellingsalts": "Нюхательная соль",
|
||||
"cobblemon.move.smellingsalts.desc": "This attack’s power is doubled when used on a target with paralysis. This also cures the target’s paralysis, however.",
|
||||
"cobblemon.move.smog": "Смог",
|
||||
@@ -3004,13 +3004,13 @@
|
||||
"cobblemon.move.smokescreen": "Дымовая завеса",
|
||||
"cobblemon.move.smokescreen.desc": "The user releases an obscuring cloud of smoke or ink. This lowers the target’s accuracy.",
|
||||
"cobblemon.move.snaptrap": "Капкан",
|
||||
"cobblemon.move.snaptrap.desc": "The user snares the target in a snap trap for four to five turns.",
|
||||
"cobblemon.move.snaptrap.desc": "Пользователь ловит цель в ловушку, которая наносит урон в течение четырёх-пяти ходов.",
|
||||
"cobblemon.move.snarl": "Ворчание",
|
||||
"cobblemon.move.snarl.desc": "The user yells as if it’s ranting about something, which lowers the Sp. Atk stats of opposing Pokémon.",
|
||||
"cobblemon.move.snatch": "Похищение",
|
||||
"cobblemon.move.snatch.desc": "The user steals the effects of any attempts to use a healing or stat-changing move.",
|
||||
"cobblemon.move.snipeshot": "Снайперский выстрел",
|
||||
"cobblemon.move.snipeshot.desc": "The user ignores the effects of opposing Pokémon’s moves and Abilities that draw in moves, allowing this move to hit the chosen target.",
|
||||
"cobblemon.move.snipeshot.desc": "Пользователь игнорирует эффекты приёмов и способностей противника, которые притягивают к себе приёмы, позволяя этому приёму поразить выбранную цель.",
|
||||
"cobblemon.move.snore": "Храп",
|
||||
"cobblemon.move.snore.desc": "This attack can be used only if the user is asleep. The harsh noise may also make the target flinch.",
|
||||
"cobblemon.move.snowscape": "Снежный ландшафт",
|
||||
@@ -3022,23 +3022,23 @@
|
||||
"cobblemon.move.solarbeam": "Солнечный луч",
|
||||
"cobblemon.move.solarbeam.desc": "In this two-turn attack, the user gathers light, then blasts a bundled beam on the next turn.",
|
||||
"cobblemon.move.solarblade": "Солнечное лезвие",
|
||||
"cobblemon.move.solarblade.desc": "In this two-turn attack, the user gathers light and fills a blade with the light’s energy, attacking the target on the next turn.",
|
||||
"cobblemon.move.solarblade.desc": "Пользователь собирает свет в первом ходу, затем наполняет лезвие энергией света и атакует в следующем ходу.",
|
||||
"cobblemon.move.sonicboom": "Звуковой удар",
|
||||
"cobblemon.move.sonicboom.desc": "The target is hit with a destructive shock wave that always inflicts 20 HP damage.",
|
||||
"cobblemon.move.soulstealing7starstrike": "Крадущий душу 7-ми звёздный удар",
|
||||
"cobblemon.move.soulstealing7starstrike.desc": "After obtaining Z-Power, the user, Marshadow, punches and kicks the target consecutively with full force.",
|
||||
"cobblemon.move.soulstealing7starstrike.desc": "После получения Z-Силы, Маршадоу последовательно бьёт и пинает цель с полной силой.",
|
||||
"cobblemon.move.spacialrend": "Раздирание пространства",
|
||||
"cobblemon.move.spacialrend.desc": "The user tears the target along with the space around it. Critical hits land more easily.",
|
||||
"cobblemon.move.spark": "Искра",
|
||||
"cobblemon.move.spark.desc": "The user throws an electrically charged tackle at the target. This may also leave the target with paralysis.",
|
||||
"cobblemon.move.sparklingaria": "Блестящая ария",
|
||||
"cobblemon.move.sparklingaria.desc": "The user bursts into song, emitting many bubbles. Any Pokémon suffering from a burn will be healed by the touch of these bubbles.",
|
||||
"cobblemon.move.sparklingaria.desc": "Пользователь начинает петь, выпуская множество пузырей. Любой Покемон, страдающий от ожога, будет исцелён прикосновением этих пузырьков.",
|
||||
"cobblemon.move.sparklyswirl": "Блестящий вихрь",
|
||||
"cobblemon.move.sparklyswirl.desc": "The user attacks the target by wrapping it with a whirlwind of an overpowering scent. This also heals all status conditions of the user’s party.",
|
||||
"cobblemon.move.sparklyswirl.desc": "Пользователь атакует цель, обволакивая её вихрем сильного запаха. Это также лечит все статусные эффекты в команде пользователя.",
|
||||
"cobblemon.move.spectralthief": "Призрачный вор",
|
||||
"cobblemon.move.spectralthief.desc": "The user hides in the target’s shadow, steals the target’s stat boosts, and then attacks.",
|
||||
"cobblemon.move.spectralthief.desc": "Пользователь скрывается в тени цели, крадёт повышения её показателей, а затем атакует.",
|
||||
"cobblemon.move.speedswap": "Обмен скоростью",
|
||||
"cobblemon.move.speedswap.desc": "The user exchanges Speed stats with the target.",
|
||||
"cobblemon.move.speedswap.desc": "Пользователь обменивается Скоростью с целью.",
|
||||
"cobblemon.move.spicyextract": "Острый экстракт",
|
||||
"cobblemon.move.spicyextract.desc": "Пользователь испускает невероятно острый экстракт, резко повышающий Атаку цели и резко понижающий её Защиту.",
|
||||
"cobblemon.move.spiderweb": "Паутина",
|
||||
@@ -3062,13 +3062,13 @@
|
||||
"cobblemon.move.splash": "Всплеск",
|
||||
"cobblemon.move.splash.desc": "The user just flops and splashes around to no effect at all...",
|
||||
"cobblemon.move.splinteredstormshards": "Штормовые осколки",
|
||||
"cobblemon.move.splinteredstormshards.desc": "After obtaining Z-Power, the user, Lycanroc, attacks the target with full force. This move negates the effect on the battlefield.",
|
||||
"cobblemon.move.splinteredstormshards.desc": "После получения Z-Силы, Ликанрок атакует цель с полной силой. Этот приём отменяет эффекты на поле битвы.",
|
||||
"cobblemon.move.splishysplash": "Плюх плюх",
|
||||
"cobblemon.move.splishysplash.desc": "The user charges a huge wave with electricity and hits the opposing Pokémon with the wave. This may also leave the opposing Pokémon with paralysis.",
|
||||
"cobblemon.move.splishysplash.desc": "Пользователь заряжает огромную волну электричеством и поражает ею противника. Это также может парализовать противника.",
|
||||
"cobblemon.move.spore": "Спора",
|
||||
"cobblemon.move.spore.desc": "The user scatters bursts of spores that induce sleep.",
|
||||
"cobblemon.move.spotlight": "Прожектор",
|
||||
"cobblemon.move.spotlight.desc": "The user shines a spotlight on the target so that only the target will be attacked during the turn.",
|
||||
"cobblemon.move.spotlight.desc": "Пользователь направляет прожектор на цель, чтобы в течение хода атаковалась только она.",
|
||||
"cobblemon.move.springtidestorm": "Весенний шторм",
|
||||
"cobblemon.move.springtidestorm.desc": "Пользователь атакует, обволакивая противника яростным ветром, наполненным любовью и ненавистью. Это также может понизить Атаку противника.",
|
||||
"cobblemon.move.stealthrock": "Потайной камень",
|
||||
@@ -3088,11 +3088,11 @@
|
||||
"cobblemon.move.stockpile": "Накопление",
|
||||
"cobblemon.move.stockpile.desc": "The user charges up power and raises both its Defense and Sp. Def stats. The move can be used three times.",
|
||||
"cobblemon.move.stokedsparksurfer": "Неугасающий сёрфер",
|
||||
"cobblemon.move.stokedsparksurfer.desc": "After obtaining Z-Power, the user, Alolan Raichu, attacks the target with full force. This move leaves the target with paralysis.",
|
||||
"cobblemon.move.stokedsparksurfer.desc": "После получения Z-Силы, Алольский Райчу атакует цель с полной силой. Этот приём парализует цель.",
|
||||
"cobblemon.move.stomp": "Топот",
|
||||
"cobblemon.move.stomp.desc": "The target is stomped with a big foot. This may also make the target flinch.",
|
||||
"cobblemon.move.stompingtantrum": "Топчащая истерика",
|
||||
"cobblemon.move.stompingtantrum.desc": "Driven by frustration, the user attacks the target. If the user’s previous move has failed, the power of this move doubles.",
|
||||
"cobblemon.move.stompingtantrum.desc": "Движимый разочарованием, пользователь атакует цель. Сила этого приёма удваивается, если предыдущая атака пользователя не удалась.",
|
||||
"cobblemon.move.stoneaxe": "Каменный топор",
|
||||
"cobblemon.move.stoneaxe.desc": "Пользователь замахивается каменными топорами на цель. Каменные осколки, оставшиеся после этого приёма, парят вокруг цели.",
|
||||
"cobblemon.move.stoneedge": "Каменное остриё",
|
||||
@@ -3106,7 +3106,7 @@
|
||||
"cobblemon.move.strength": "Сила",
|
||||
"cobblemon.move.strength.desc": "The target is slugged with a punch thrown at maximum power.",
|
||||
"cobblemon.move.strengthsap": "Кража силы",
|
||||
"cobblemon.move.strengthsap.desc": "The user restores its HP by the same amount as the target’s Attack stat. It also lowers the target’s Attack stat.",
|
||||
"cobblemon.move.strengthsap.desc": "Пользователь восстанавливает свои ОЗ на количество, равное показателю Атаки цели. Затем он понижает Атаку цели.",
|
||||
"cobblemon.move.stringshot": "Выстрел паутиной",
|
||||
"cobblemon.move.stringshot.desc": "Opposing Pokémon are bound with silk blown from the user’s mouth that harshly lowers the Speed stat.",
|
||||
"cobblemon.move.struggle": "Сопротивление",
|
||||
@@ -3114,7 +3114,7 @@
|
||||
"cobblemon.move.strugglebug": "Насекомое сопротивление",
|
||||
"cobblemon.move.strugglebug.desc": "While resisting, the user attacks opposing Pokémon. This lowers the Sp. Atk stats of those hit.",
|
||||
"cobblemon.move.stuffcheeks": "Набивание щёк",
|
||||
"cobblemon.move.stuffcheeks.desc": "The user eats its held Berry, then sharply raises its Defense stat.",
|
||||
"cobblemon.move.stuffcheeks.desc": "Пользователь съедает удерживаемую ягоду, после чего резко повышает свою Защиту.",
|
||||
"cobblemon.move.stunspore": "Оглушающая спора",
|
||||
"cobblemon.move.stunspore.desc": "The user scatters a cloud of numbing powder that paralyzes the target.",
|
||||
"cobblemon.move.submission": "Подчинение",
|
||||
@@ -3128,7 +3128,7 @@
|
||||
"cobblemon.move.sunnyday": "Солнечный день",
|
||||
"cobblemon.move.sunnyday.desc": "The user intensifies the sun for five turns, powering up Fire-type moves. It lowers the power of Water-type moves.",
|
||||
"cobblemon.move.sunsteelstrike": "Солнечно-стальной удар",
|
||||
"cobblemon.move.sunsteelstrike.desc": "The user slams into the target with the force of a meteor. This move can be used on the target regardless of its Abilities.",
|
||||
"cobblemon.move.sunsteelstrike.desc": "Пользователь врезается в цель с силой метеорита. Этот приём можно использовать на цели независимо от её способности.",
|
||||
"cobblemon.move.superfang": "Супер клык",
|
||||
"cobblemon.move.superfang.desc": "The user chomps hard on the target with its sharp front fangs. This cuts the target’s HP in half.",
|
||||
"cobblemon.move.superpower": "Суперсила",
|
||||
@@ -3174,13 +3174,13 @@
|
||||
"cobblemon.move.takeheart": "Воодушевление",
|
||||
"cobblemon.move.takeheart.desc": "Пользователь поднимает себе настроение, леча свои состояния и повышая Спец. Атаку и Спец. Защиту.",
|
||||
"cobblemon.move.tarshot": "Дёготный выстрел",
|
||||
"cobblemon.move.tarshot.desc": "The user pours sticky tar over the target, lowering the target’s Speed stat. The target becomes weaker to Fire-type moves.",
|
||||
"cobblemon.move.tarshot.desc": "Пользователь выливает липкую дёготь на цель, понижая её Скорость. Цель становится более уязвимой к приёмам Огненного типа.",
|
||||
"cobblemon.move.taunt": "Насмешка",
|
||||
"cobblemon.move.taunt.desc": "The target is taunted into a rage that allows it to use only attack moves for three turns.",
|
||||
"cobblemon.move.tearfullook": "Слезливый взгляд",
|
||||
"cobblemon.move.tearfullook.desc": "The user gets teary eyed to make the target lose its combative spirit. This lowers the target’s Attack and Sp. Atk stats.",
|
||||
"cobblemon.move.tearfullook.desc": "Глаза пользователя начинают слезиться, чтобы лишить цель боевого духа. Это понижает Атаку и Спец. Атаку цели.",
|
||||
"cobblemon.move.teatime": "Чаепитие",
|
||||
"cobblemon.move.teatime.desc": "The user has teatime with all the Pokémon in the battle. Each Pokémon eats its held Berry.",
|
||||
"cobblemon.move.teatime.desc": "Пользователь устраивает чаепитие со всеми Покемонами, участвующими в битве. Каждый Покемон съедает свою ягоду.",
|
||||
"cobblemon.move.technoblast": "Техно залп",
|
||||
"cobblemon.move.technoblast.desc": "The user fires a beam of light at its target. The move’s type changes depending on the Drive the user holds.",
|
||||
"cobblemon.move.tectonicrage": "Тектоническая ярость",
|
||||
@@ -3204,7 +3204,7 @@
|
||||
"cobblemon.move.thrash": "Разгром",
|
||||
"cobblemon.move.thrash.desc": "The user rampages and attacks for two to three turns. The user then becomes confused.",
|
||||
"cobblemon.move.throatchop": "Удар в горло",
|
||||
"cobblemon.move.throatchop.desc": "The user attacks the target’s throat, and the resultant suffering prevents the target from using moves that emit sound for two turns.",
|
||||
"cobblemon.move.throatchop.desc": "Пользователь наносит удар по горлу цели, и полученные страдания не позволяют цели использовать звуковые приёмы в течение двух ходов.",
|
||||
"cobblemon.move.thunder": "Гром",
|
||||
"cobblemon.move.thunder.desc": "A wicked thunderbolt is dropped on the target to inflict damage. This may also leave the target with paralysis.",
|
||||
"cobblemon.move.thunderbolt": "Удар молнии",
|
||||
@@ -3236,7 +3236,7 @@
|
||||
"cobblemon.move.toxicspikes": "Токсичные шипы",
|
||||
"cobblemon.move.toxicspikes.desc": "The user lays a trap of poison spikes at the feet of the opposing team. The spikes will poison opposing Pokémon that switch into battle.",
|
||||
"cobblemon.move.toxicthread": "Токсчиная нить",
|
||||
"cobblemon.move.toxicthread.desc": "The user shoots poisonous threads to poison the target and lower the target’s Speed stat.",
|
||||
"cobblemon.move.toxicthread.desc": "Пользователь стреляет ядовитыми нитями, чтобы отравить цель и понизить её Скорость.",
|
||||
"cobblemon.move.trailblaze": "Первопроходец",
|
||||
"cobblemon.move.trailblaze.desc": "Пользователь внезапно атакует, словно выпрыгивая из высокой травы. Ловкость ног пользователя повышает его Скорость.",
|
||||
"cobblemon.move.transform": "Трансформация",
|
||||
@@ -3258,7 +3258,7 @@
|
||||
"cobblemon.move.triplekick": "Тройной пинок",
|
||||
"cobblemon.move.triplekick.desc": "A consecutive three-kick attack that becomes more powerful with each successful hit.",
|
||||
"cobblemon.move.tropkick": "Тропический пинок",
|
||||
"cobblemon.move.tropkick.desc": "The user lands an intense kick of tropical origins on the target. This also lowers the target’s Attack stat.",
|
||||
"cobblemon.move.tropkick.desc": "Пользователь наносит цели мощный удар тропического происхождения. Это также понижает Атаку цели.",
|
||||
"cobblemon.move.trumpcard": "Козырь",
|
||||
"cobblemon.move.trumpcard.desc": "The fewer PP this move has, the greater its power.",
|
||||
"cobblemon.move.twinbeam": "Двойной луч",
|
||||
@@ -3278,7 +3278,7 @@
|
||||
"cobblemon.move.vcreate": "V-творение",
|
||||
"cobblemon.move.vcreate.desc": "With a hot flame on its forehead, the user hurls itself at its target. This lowers the user’s Defense, Sp. Def, and Speed stats.",
|
||||
"cobblemon.move.veeveevolley": "Виви залп",
|
||||
"cobblemon.move.veeveevolley.desc": "The more Eevee loves its Trainer, the greater the move’s power. It never misses.",
|
||||
"cobblemon.move.veeveevolley.desc": "Чем больше Иви любит своего Тренера, тем сильнее становится этот приём. Он никогда не промахивается.",
|
||||
"cobblemon.move.venomdrench": "Пропитка ядом",
|
||||
"cobblemon.move.venomdrench.desc": "Opposing Pokémon are drenched in an odd poisonous liquid. This lowers the Attack, Sp. Atk, and Speed stats of a poisoned target.",
|
||||
"cobblemon.move.venoshock": "Ядошок",
|
||||
@@ -3358,9 +3358,9 @@
|
||||
"cobblemon.move.zenheadbutt": "Зен удар",
|
||||
"cobblemon.move.zenheadbutt.desc": "The user focuses its willpower to its head and attacks the target. This may also make the target flinch.",
|
||||
"cobblemon.move.zingzap": "Электровжик",
|
||||
"cobblemon.move.zingzap.desc": "A strong electric blast crashes down on the target, giving it an electric shock. This may also make the target flinch.",
|
||||
"cobblemon.move.zingzap.desc": "Пользователь врезается в цель, нанося ей мощный электрический удар. Это также может заставить цель вздрогнуть.",
|
||||
"cobblemon.move.zippyzap": "Шустрый вжик",
|
||||
"cobblemon.move.zippyzap.desc": "The user attacks the target with bursts of electricity at high speed. This move always goes first and results in a critical hit.",
|
||||
"cobblemon.move.zippyzap.desc": "Пользователь атакует цель электрическими разрядами с высокой скоростью. Пользователь всегда ходит первым и наносит критический урон.",
|
||||
"cobblemon.entity.pokemon": "Покемон",
|
||||
"entity.cobblemon.empty_pokeball": "Пустой Покебол",
|
||||
"cobblemon.species.bulbasaur.name": "Бульбазавр",
|
||||
|
||||
@@ -6570,7 +6570,7 @@
|
||||
"item.cobblemon.damp_rock.tooltip": "携带后,将天气变为下雨的话,下雨的时间就会比平时更长",
|
||||
"item.cobblemon.icy_rock.tooltip": "携带后,将天气变为下雪的话,下雪的时间就会比平时更长",
|
||||
"item.cobblemon.medicinal_leek.tooltip_2": "当大葱鸭或葱游兵携带后,击中要害等级提高2级",
|
||||
"item.cobblemon.revival_herb.tooltip": "使一只昏厥的宝可梦回复所有HP,同时降低它的亲密度",
|
||||
"item.cobblemon.revival_herb.tooltip": "使一只昏厥的宝可梦回复最大HP的25%,同时降低它的亲密度",
|
||||
"item.cobblemon.berry_juice.tooltip": "携带后,当宝可梦的HP低于50%时,会回复20HP",
|
||||
"item.cobblemon.max_revive.tooltip": "使一只昏厥的宝可梦回复所有HP",
|
||||
"item.cobblemon.x_attack.tooltip": "在战斗中使用时,会使目标的攻击提升一级",
|
||||
@@ -7078,7 +7078,7 @@
|
||||
"cobblemon.command.unlockablepcboxwallpaper.invalid-wallpaper": "无效的壁纸标识",
|
||||
"cobblemon.ui.pc.wallpaper": "壁纸",
|
||||
"cobblemon.ui.pc.filter": "筛选",
|
||||
"cobblemon.ui.pc.filter.tooltip": "格式:pikachu shiny held_item lvl=1......",
|
||||
"cobblemon.ui.pc.filter.tooltip": "格式:皮卡丘 shiny held_item lvl=1......",
|
||||
"cobblemon.mark.ribbon_ability": "才能奖章",
|
||||
"cobblemon.mark.ribbon_ability.desc": "在对战塔战胜塔主获得的纪念奖章。",
|
||||
"cobblemon.mark.ribbon_ability_pair.desc": "在对战塔获得通信多人模式的冠军时获得的纪念奖章。",
|
||||
@@ -8582,10 +8582,10 @@
|
||||
"item.cobblemon.health_mochi": "体力粘糕",
|
||||
"item.cobblemon.scroll_of_waters.tooltip": "当对熊徒弟使用时,会使其进化为武道熊师(连击流)",
|
||||
"item.cobblemon.potato_mochi": "马铃薯粘糕",
|
||||
"item.cobblemon.aprijuice_black": "黑圆柑果汁",
|
||||
"item.cobblemon.health_mochi.tooltip": "提升宝可梦的HP基础点数10点",
|
||||
"item.cobblemon.clever_mochi.tooltip": "提升宝可梦的特防基础点数10点",
|
||||
"item.cobblemon.aprijuice_white": "白圆柑果汁",
|
||||
"item.cobblemon.aprijuice_black": "黑球果汁",
|
||||
"item.cobblemon.health_mochi.tooltip": "提升宝可梦的HP基础点数4点",
|
||||
"item.cobblemon.clever_mochi.tooltip": "提升宝可梦的特防基础点数4点",
|
||||
"item.cobblemon.aprijuice_white": "白球果汁",
|
||||
"item.cobblemon.hearty_grains": "旺旺谷",
|
||||
"item.cobblemon.bugwort": "除虫草",
|
||||
"item.cobblemon.saccharine_boat": "蜜露木船",
|
||||
@@ -8598,22 +8598,22 @@
|
||||
"item.cobblemon.candied_apple": "蜜饯苹果",
|
||||
"item.cobblemon.moomoo_milk": "哞哞鲜奶",
|
||||
"item.cobblemon.muscle_mochi": "肌力粘糕",
|
||||
"item.cobblemon.muscle_mochi.tooltip": "提升宝可梦的攻击基础点数10点",
|
||||
"item.cobblemon.muscle_mochi.tooltip": "提升宝可梦的攻击基础点数4点",
|
||||
"item.cobblemon.resist_mochi": "抵抗粘糕",
|
||||
"item.cobblemon.resist_mochi.tooltip": "提升宝可梦的防御基础点数10点",
|
||||
"item.cobblemon.resist_mochi.tooltip": "提升宝可梦的防御基础点数4点",
|
||||
"item.cobblemon.genius_mochi": "智力粘糕",
|
||||
"item.cobblemon.genius_mochi.tooltip": "提升宝可梦的特攻基础点数10点",
|
||||
"item.cobblemon.genius_mochi.tooltip": "提升宝可梦的特攻基础点数4点",
|
||||
"item.cobblemon.clever_mochi": "精神粘糕",
|
||||
"item.cobblemon.swift_mochi": "瞬发粘糕",
|
||||
"item.cobblemon.swift_mochi.tooltip": "提升宝可梦的速度基础点数10点",
|
||||
"item.cobblemon.swift_mochi.tooltip": "提升宝可梦的速度基础点数4点",
|
||||
"item.cobblemon.fresh_start_mochi": "净空粘糕",
|
||||
"item.cobblemon.fresh_start_mochi.tooltip": "将宝可梦的全部基础点数清空",
|
||||
"item.cobblemon.poke_bait": "宝可梦诱饵",
|
||||
"item.cobblemon.aprijuice_blue": "蓝圆柑果汁",
|
||||
"item.cobblemon.aprijuice_green": "绿圆柑果汁",
|
||||
"item.cobblemon.aprijuice_pink": "粉圆柑果汁",
|
||||
"item.cobblemon.aprijuice_red": "红圆柑果汁",
|
||||
"item.cobblemon.aprijuice_yellow": "黄圆柑果汁",
|
||||
"item.cobblemon.aprijuice_blue": "蓝球果汁",
|
||||
"item.cobblemon.aprijuice_green": "绿球果汁",
|
||||
"item.cobblemon.aprijuice_pink": "粉球果汁",
|
||||
"item.cobblemon.aprijuice_red": "红球果汁",
|
||||
"item.cobblemon.aprijuice_yellow": "黄球果汁",
|
||||
"item.cobblemon.aprijuice.quality_format": "%1$s %2$s",
|
||||
"block.cobblemon.saccharine_log": "蜜露原木",
|
||||
"block.cobblemon.stripped_saccharine_log": "去皮蜜露原木",
|
||||
@@ -8622,7 +8622,7 @@
|
||||
"item.cobblemon.aprijuice.prefix.delicious": "美味的",
|
||||
"item.cobblemon.lumiose_galette": "密阿雷格雷派饼",
|
||||
"cobblemon.item_class.mob_effect_seasoning": "效果调料",
|
||||
"cobblemon.item_class.food_seasoning": "食物调料",
|
||||
"cobblemon.item_class.food_seasoning": "营养调料",
|
||||
"cobblemon.tooltip.food.hunger": "饥饿值:%s",
|
||||
"cobblemon.tooltip.mob_effect_entry": "%1$s %2$s (%3$s)",
|
||||
"item.cobblemon.aprijuice.prefix.plain": "平淡的",
|
||||
@@ -8643,7 +8643,7 @@
|
||||
"cobblemon.item_class.cooking_pot_recipe_absorbs": "可添加",
|
||||
"cobblemon.seasoning_bait_effect_header": "诱饵",
|
||||
"cobblemon.seasoning_mob_effect_header": "效果",
|
||||
"cobblemon.seasoning_food_header": "食物",
|
||||
"cobblemon.seasoning_food_header": "营养",
|
||||
"cobblemon.seasoning_bait_effect_info_header": "诱饵信息:",
|
||||
"cobblemon.seasoning_flavor_header": "口味",
|
||||
"cobblemon.item_class.bait_effect_seasoning": "诱饵调料",
|
||||
@@ -8654,7 +8654,7 @@
|
||||
"cobblemon.seasoning_flavor.sour": "酸味",
|
||||
"cobblemon.item_class.flavor_seasoning": "口味调料",
|
||||
"cobblemon.seasoning_mob_effect_info_header": "效果信息:",
|
||||
"cobblemon.seasoning_food_info_header": "食物信息:",
|
||||
"cobblemon.seasoning_food_info_header": "营养信息:",
|
||||
"cobblemon.seasoning_flavor_info_header": "口味信息:",
|
||||
"cobblemon.cooking.cooking_quality": "质量:%1$s",
|
||||
"cobblemon.cooking.cooking_quality.low": "低",
|
||||
@@ -8707,8 +8707,8 @@
|
||||
"flavour.cobblemon.poke_puff.dry": "清爽",
|
||||
"flavour.cobblemon.poke_puff.bitter": "微苦",
|
||||
"flavour.cobblemon.poke_puff.mild": "清淡",
|
||||
"tooltip.cobblemon.poke_puff.friendship_increase": "对 %2$s 的性格 +%1$s 亲密度",
|
||||
"tooltip.cobblemon.poke_puff.friendship_decrease": "对 其他 的性格 -%1$s 亲密度",
|
||||
"tooltip.cobblemon.poke_puff.friendship_increase": "对 %2$s↑ 的性格 +%1$s 亲密度",
|
||||
"tooltip.cobblemon.poke_puff.friendship_decrease": "对 其他↑ 的性格 -%1$s 亲密度",
|
||||
"cobblemon.tooltip.poke_puff.friendship_effects": "亲密度影响",
|
||||
"item.cobblemon.health_candy": "元气糖果",
|
||||
"item.cobblemon.mighty_candy": "力量糖果",
|
||||
@@ -8752,7 +8752,7 @@
|
||||
"cobblemon.config.ui.maximum_spawning_zone_distance_from_player.tooltip": "宝可梦生成时,距玩家所需的最大方块数。",
|
||||
"cobblemon.config.ui.maximum_spawns_per_pass": "单次生成最大数量",
|
||||
"cobblemon.config.ui.despawner_far_distance.tooltip": "以玩家为中心的最大距离范围。在此范围之外,且存在时间超过最小活动时间的宝可梦会被系统移除。",
|
||||
"advancements.cobblemon.resurrect_galar_fossil.description": "复活由化石鸟和化石鱼与化石海兽和化石龙组成的宝可梦",
|
||||
"advancements.cobblemon.resurrect_galar_fossil.description": "复活一只由化石鸟或化石鱼以及化石海兽或化石龙组成的宝可梦",
|
||||
"cobblemon.battle.sidestart.ally.auroraveil": "极光幕使我方的物理和特殊抗性提高了!",
|
||||
"cobblemon.battle.sidestart.ally.safeguard": "我方被神秘之幕包围了!",
|
||||
"cobblemon.battle.sidestart.opponent.auroraveil": "极光幕使对手的物理和特殊抗性提高了!",
|
||||
@@ -8824,7 +8824,7 @@
|
||||
"tag.item.cobblemon.remedy_berries": "中药浆果",
|
||||
"tag.item.cobblemon.full_heal_ingredients": "万灵药成分",
|
||||
"tag.item.cobblemon.regional_delicacies": "地区美食",
|
||||
"tag.item.cobblemon.aprijuices": "圆柑果汁",
|
||||
"tag.item.cobblemon.aprijuices": "球果汁",
|
||||
"tag.item.cobblemon.mochis": "粘糕",
|
||||
"tag.item.cobblemon.poke_food": "宝可梦食物",
|
||||
"tag.item.cobblemon.full_heal_bottles": "万灵药药瓶",
|
||||
@@ -8980,5 +8980,74 @@
|
||||
"cobblemon.behaviour.moves_to_lava.name": "返回至熔岩",
|
||||
"cobblemon.behaviour.moves_to_water.desc": "当水在附近时移动到水里。",
|
||||
"cobblemon.behaviour.pokemon_herds.name": "宝可梦群体",
|
||||
"cobblemon.behaviour.pokemon_herds.desc": "宝可梦会认为合适的领导宝可梦,并跟随它。"
|
||||
"cobblemon.behaviour.pokemon_herds.desc": "宝可梦会认为合适的领导宝可梦,并跟随它。",
|
||||
"block.cobblemon.saccharine_log_slathered": "涂抹甜甜蜜的蜜露原木",
|
||||
"cobblemon.ui.ride_style.land": "陆地",
|
||||
"cobblemon.ui.ride_style.air": "空中",
|
||||
"cobblemon.ui.ride_style.liquid": "水域",
|
||||
"cobblemon.ui.stats.fullness": "饱食度",
|
||||
"cobblemon.ui.stats.ride": "乘骑",
|
||||
"cobblemon.ui.stats.ride.acceleration": "加速",
|
||||
"cobblemon.ui.stats.ride.jump": "跳跃",
|
||||
"cobblemon.ui.stats.ride.skill": "转向",
|
||||
"cobblemon.ui.stats.ride.speed": "速度",
|
||||
"cobblemon.ui.stats.ride.stamina": "耐力",
|
||||
"cobblemon.ui.stats.ride.boost_maximum": "可提升最大值",
|
||||
"cobblemon.ui.pokedex.info.stats_ride": "乘骑属性",
|
||||
"cobblemon.ui.pokedex.info.stats_ride.seats": "座位:%1$s",
|
||||
"cobblemon.command.molang.out": "MoLang输出:%1$s",
|
||||
"cobblemon.entity.variable.npc_render_scale.desc": "渲染时NPC的尺寸比例,1.0为正常尺寸。",
|
||||
"cobblemon.battle.end.sandtomb": "%1$s摆脱了流沙地狱的束缚!",
|
||||
"cobblemon.config.ui.infinite_ride_stamina.tooltip": "是否在骑上宝可梦后拥有无限耐力。",
|
||||
"tag.item.cobblemon.additive_iv_candies": "增加型极限特训糖果",
|
||||
"cobblemon.entity.variable.npc_render_scale.name": "渲染比例",
|
||||
"cobblemon.entity.variable.npc_box_eyes_ratio.desc": "NPC实体碰撞箱的高度中,眼睛所在的比例,用于看向角度。大多人形模型使用的值为0.85。",
|
||||
"cobblemon.behaviour.npc_scale_configuration.name": "NPC实体尺寸",
|
||||
"cobblemon.snapshots.warning.description": "您正在使用 方块宝可梦 的 %s 快照版本。此版本中的功能仍在开发中,可能不适合在您的世界中使用。您是否希望在了解这些风险的情况下继续?",
|
||||
"cobblemon.config.ui.x_axis_sensitivity": "X轴灵敏度",
|
||||
"cobblemon.config.ui.x_axis_sensitivity.tooltip": "将X轴的输入乘以此值。",
|
||||
"cobblemon.config.ui.y_axis_sensitivity": "Y轴灵敏度",
|
||||
"cobblemon.config.ui.y_axis_sensitivity.tooltip": "将Y轴的输入乘以此值。",
|
||||
"cobblemon.config.ui.swap_x_and_y_axes": "反转XY轴",
|
||||
"cobblemon.config.ui.swap_x_and_y_axes.tooltip": "反转X轴和Y轴的输入。",
|
||||
"cobblemon.config.ui.display_controls_duration_seconds": "控制提示持续时间",
|
||||
"cobblemon.config.ui.display_controls_duration_seconds.tooltip": "在骑上宝可梦后,控制提示的持续时间(秒)。",
|
||||
"cobblemon.config.ui.infinite_ride_stamina": "无限耐力",
|
||||
"cobblemon.config.ui.remember_riding_camera": "记住骑乘视角",
|
||||
"cobblemon.config.ui.remember_riding_camera.tooltip": "是否在骑乘宝可梦后,恢复到上一次使用的视角模式。",
|
||||
"advancements.cobblemon.place_campfire_pot": "我们得开始烹饪了",
|
||||
"advancements.cobblemon.place_campfire_pot.description": "在点燃的营火上放置一个营火锅",
|
||||
"advancements.cobblemon.use_iv_candy.description": "对宝可梦使用能够改变有效个体值的糖果",
|
||||
"advancements.cobblemon.use_iv_candy": "数值拉满",
|
||||
"block.cobblemon.poke_snack": "宝可粮",
|
||||
"tag.item.cobblemon.small_flowers": "小型花",
|
||||
"tag.item.cobblemon.held.blacklisted_items_to_hold": "携带道具黑名单",
|
||||
"tag.item.cobblemon.held.whitelisted_items_to_hold": "携带道具白名单",
|
||||
"tag.item.cobblemon.poke_puff_berries": "宝芙蕾树果",
|
||||
"tag.item.cobblemon.candies": "糖果",
|
||||
"tag.item.cobblemon.iv_candies": "极限特训糖果",
|
||||
"tag.item.cobblemon.subtractive_iv_candies": "减少型极限特训糖果",
|
||||
"cobblemon.entity.variable.npc_box_scale.name": "碰撞箱尺寸",
|
||||
"cobblemon.entity.variable.npc_box_scale.desc": "NPC的实体碰撞箱尺寸。1.0为正常尺寸。这个值会影响NPC的可见度。",
|
||||
"cobblemon.entity.variable.npc_box_width.name": "碰撞箱宽度",
|
||||
"cobblemon.entity.variable.npc_box_width.desc": "NPC实体碰撞箱的宽度。",
|
||||
"cobblemon.entity.variable.npc_box_height.name": "碰撞箱高度",
|
||||
"cobblemon.entity.variable.npc_box_height.desc": "NPC实体碰撞箱的高度。",
|
||||
"cobblemon.entity.variable.npc_box_eyes_ratio.name": "碰撞箱眼睛位置比例",
|
||||
"cobblemon.behaviour.npc_scale_configuration.desc": "允许配置NPC的渲染和碰撞箱尺寸。",
|
||||
"cobblemon.behaviour.pokemon_gets_mad_at_thrower.name": "对投掷精灵球的人生气",
|
||||
"cobblemon.behaviour.pokemon_gets_mad_at_thrower.desc": "对向它投掷精灵球的玩家生气。具有攻击性的宝可梦会攻击玩家,不具备攻击性则会逃跑。",
|
||||
"cobblemon.behaviour.attack_hostile_mobs.name": "攻击敌对生物",
|
||||
"cobblemon.behaviour.attack_hostile_mobs.desc": "攻击附近的敌对生物,即使这是无端的。",
|
||||
"cobblemon.behaviour.pokemon_bee.name": "授粉花朵",
|
||||
"cobblemon.behaviour.pokemon_bee.desc": "为花朵进行授粉,并在蜂箱和蜜露树叶中产蜜。",
|
||||
"cobblemon.behaviour.pokemon_picks_up_items.name": "捡起物品",
|
||||
"cobblemon.behaviour.pokemon_picks_up_items.desc": "宝可梦会捡起它关心的物品。",
|
||||
"cobblemon.ui.pokedex.info.form.unown-!": "!",
|
||||
"cobblemon.species.unown-!.desc": "身体像是古代文字的宝可梦。虽然已有人在研究先出现的是文字还是未知图腾,但至今仍是个谜。",
|
||||
"cobblemon.ui.pokedex.info.form.unown-?": "?",
|
||||
"cobblemon.species.unown-?.desc": "身体像是古代文字的宝可梦。虽然已有人在研究先出现的是文字还是未知图腾,但至今仍是个谜。",
|
||||
"cobblemon.snapshots.warning.title": "方块宝可梦快照版警告",
|
||||
"cobblemon.snapshots.warning.dont_show_again": "不再显示",
|
||||
"cobblemon.snapshots.warning.dont_show_again_tip": "在较新的 方块宝可梦 快照中(例如 1.7.0 与 1.8.0),此设置可能会被忽略"
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"cobblemon:energy_root",
|
||||
"cobblemon:vivichoke",
|
||||
"cobblemon:hearty_grains",
|
||||
"#cobblemon:mint_leaf",
|
||||
"#cobblemon:mint_leaves",
|
||||
"cobblemon:revival_herb",
|
||||
"#cobblemon:berries"
|
||||
]
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "cobblemon.behaviour.name_tag_display.name",
|
||||
"description": "cobblemon.behaviour.name_tag_display.desc",
|
||||
"entityType": "cobblemon:npc",
|
||||
"undo": [
|
||||
"q.entity.set_name_tag_visible(true);q.entity.delete_variable('name_tag_display');"
|
||||
],
|
||||
"configurations": [
|
||||
{
|
||||
"type": "script",
|
||||
"variables": [
|
||||
{
|
||||
"variableName": "name_tag_display",
|
||||
"displayName": "cobblemon.entity.variable.display_name_tag.name",
|
||||
"description": "cobblemon.entity.variable.display_name_tag.desc",
|
||||
"type": "BOOLEAN",
|
||||
"defaultValue": "true"
|
||||
}
|
||||
],
|
||||
"script": [
|
||||
"q.entity.set_name_tag_visible(q.entity.config.name_tag_display)"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "cobblemon.behaviour.dialogue_selection.name",
|
||||
"description": "cobblemon.behaviour.dialogue_selection.desc",
|
||||
"entityType": "cobblemon:npc",
|
||||
"undo": [
|
||||
"q.entity.unset_interaction();"
|
||||
],
|
||||
"configurations": [
|
||||
{
|
||||
"type": "script",
|
||||
"variables": [
|
||||
{
|
||||
"variableName": "dialogue_selection",
|
||||
"displayName": "cobblemon.entity.variable.dialogue_selection.name",
|
||||
"description": "cobblemon.entity.variable.dialogue_selection.desc",
|
||||
"type": "TEXT",
|
||||
"defaultValue": "npc-example"
|
||||
}
|
||||
],
|
||||
"script": [
|
||||
"q.entity.set_dialogue_interaction(q.entity.config.dialogue_selection);"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
+2
-2
@@ -11,8 +11,8 @@
|
||||
"4": [
|
||||
{
|
||||
"type": "move_to_owner",
|
||||
"teleportDistance": "q.entity.is_in_party ? 40 : 99999" ,
|
||||
"maxDistance": "q.entity.is_in_party ? 5 : 8"
|
||||
"teleportDistance": "q.entity.is_in_party ? 32 : 99999" ,
|
||||
"maxDistance": "q.entity.behaviour.moving.can_move ? (q.entity.is_in_party ? 5 : 8) : 99999"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -28,7 +28,13 @@
|
||||
}
|
||||
],
|
||||
"randomizedGrowthPoints": true,
|
||||
"spawnConditions": [],
|
||||
"spawnConditions": [
|
||||
{
|
||||
"variant": "cobblemon:preferred_biome",
|
||||
"minGroveSize": 3,
|
||||
"maxGroveSize": 5
|
||||
}
|
||||
],
|
||||
"growthPoints": [
|
||||
{
|
||||
"position": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"pokemon": ["electrode", "furfrou", "alakazam", "gengar", "jigglypuff"],
|
||||
"pokemon": ["electrode", "furfrou", "alakazam", "gengar", "jigglypuff", "smeargle"],
|
||||
"cosmeticItems": [
|
||||
{
|
||||
"consumedItem": "minecraft:white_dye",
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
"canJump": "true",
|
||||
"reverseDriveFactor": "0.25",
|
||||
"strafeFactor": "0.2",
|
||||
"timeToRollCorrect": "0.5",
|
||||
"jumpExpr": "q.get_ride_stats('JUMP', 'LIQUID', 2.2, 1.2)",
|
||||
"handlingExpr": "q.get_ride_stats('SKILL', 'LIQUID', 100.0, 45.0)",
|
||||
"timeToRollCorrect": "1.2",
|
||||
"jumpExpr": "q.get_ride_stats('JUMP', 'LIQUID', 2.0, 1.0)",
|
||||
"handlingExpr": "q.get_ride_stats('SKILL', 'LIQUID', 75.0, 10.0)",
|
||||
"horizontalPitchExpr": "q.get_ride_stats('SKILL', 'LIQUID', 0.3, 0.2)",
|
||||
"mouseInputMult": "q.get_ride_stats('SKILL', 'LIQUID', 1.2, 0.8)",
|
||||
"speedExpr": "q.get_ride_stats('SPEED', 'LIQUID', 15.0, 5.0)",
|
||||
"accelerationExpr": "q.get_ride_stats('ACCELERATION', 'LIQUID', 2.0, 5.0)",
|
||||
"staminaExpr": "q.get_ride_stats('STAMINA', 'LIQUID', 7.0, 3.0)"
|
||||
"speedExpr": "q.get_ride_stats('SPEED', 'LIQUID', 24.0, 2.0)",
|
||||
"accelerationExpr": "q.get_ride_stats('ACCELERATION', 'LIQUID', 0.1, 8.0)",
|
||||
"staminaExpr": "q.get_ride_stats('STAMINA', 'LIQUID', 20.0, 2.0)"
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"infiniteStamina": "false",
|
||||
"staminaRegenTime": "5.0",
|
||||
"hitboxBreachPercentage": "0.5",
|
||||
"jumpExpr": "q.get_ride_stats('JUMP', 'LIQUID', 4.0, 1.0)",
|
||||
"handlingExpr": "q.get_ride_stats('SKILL', 'LIQUID', 90.0, 30.0)",
|
||||
"speedExpr": "q.get_ride_stats('SPEED', 'LIQUID', 12.0, 2.0)",
|
||||
"accelerationExpr": "q.get_ride_stats('ACCELERATION', 'LIQUID', 1.2, 8.0)",
|
||||
"staminaExpr": "q.get_ride_stats('STAMINA', 'LIQUID', 180.0, 10.0)"
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ingredient": "minecraft:golden_carrot",
|
||||
"colour": "red",
|
||||
"baitEffects": [
|
||||
{
|
||||
"type": "cobblemon:bite_time",
|
||||
"chance": 1.0,
|
||||
"value": 0.5
|
||||
}
|
||||
]
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user