Compare commits
19
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2895c0a2ef | ||
|
|
acc87f9eae | ||
|
|
928dfcdadf | ||
|
|
21363405fc | ||
|
|
08c4f4a0ff | ||
|
|
c4a1704a8b | ||
|
|
837aa5acf5 | ||
|
|
969d6ac7fc | ||
|
|
46bb9e1aec | ||
|
|
9792ff3392 | ||
|
|
e863c6d094 | ||
|
|
a070dc56bd | ||
|
|
79f9e0f0f2 | ||
|
|
8500eb58ef | ||
|
|
e835b833b3 | ||
|
|
3b653b745e | ||
|
|
d03541ff6f | ||
|
|
0d7aff0349 | ||
|
|
c904888c6a |
No files matched your search
+6
-63
@@ -35,10 +35,6 @@
|
||||
- Added cries to Meowth, Alolan Meowth, Galaraian Meowth,
|
||||
- Completed the advancement for placing a Tumblestone near Lava or Magma to make it grow.
|
||||
- Added new held items: Ability Shield, Absorb Bulb, Air Balloon, Binding Band, Blunder Policy, Cell Battery, Covert Cloak, Damp Rock, Eject Button, Eviolite, Expert Belt, Float Stone, Focus Sash, Heat Rock, Icy Rock, Iron Ball, Light Ball, Loaded Dice, Red Card, Shell Bell, Sticky Barb, Smooth Rock, Soothe Bell and Weakness Policy.
|
||||
- Added Hisui starters to the starter selection menu.
|
||||
- Added bubble quirk to Krabby that only play during clear sunset's.
|
||||
- Added forfeit option to PVP battles.
|
||||
- Added visual changes for entities affected by Illusion, Imposter, or Transform in battle.
|
||||
|
||||
### Pokémon Added
|
||||
#### Gen 2
|
||||
@@ -47,9 +43,8 @@
|
||||
- Qwilfish
|
||||
- Heracross
|
||||
- Skarmory
|
||||
- Larvitar
|
||||
- Pupitar
|
||||
- Tyranitar
|
||||
- Ferroseed
|
||||
- Ferrothorn
|
||||
|
||||
#### Gen 3
|
||||
- Lileep
|
||||
@@ -58,16 +53,6 @@
|
||||
- Armaldo
|
||||
- Tropius
|
||||
- Roselia
|
||||
- Aron
|
||||
- Lairon
|
||||
- Aggron
|
||||
- Solrock
|
||||
- Lunatone
|
||||
- Makuhita
|
||||
- Hariyama
|
||||
- Trapinch
|
||||
- Vibrava
|
||||
- Flygon
|
||||
|
||||
#### Gen 4
|
||||
- Shieldon
|
||||
@@ -76,8 +61,6 @@
|
||||
- Rampardos
|
||||
- Budew
|
||||
- Roserade
|
||||
- Hippopotas
|
||||
- Hippowdon
|
||||
|
||||
#### Gen 5
|
||||
- Tirtouga
|
||||
@@ -104,9 +87,6 @@
|
||||
- Hydreigon
|
||||
- Larvesta
|
||||
- Volcarona
|
||||
- Alomomola
|
||||
- Ferroseed
|
||||
- Ferrothorn
|
||||
|
||||
#### Gen 6
|
||||
- Tyrunt
|
||||
@@ -116,11 +96,6 @@
|
||||
- Goomy
|
||||
- Sliggoo
|
||||
- Goodra
|
||||
- Carbink
|
||||
- Flabébé
|
||||
- Floette
|
||||
- Florges
|
||||
- Klefki
|
||||
|
||||
#### Gen 7
|
||||
- Turtonator
|
||||
@@ -131,8 +106,6 @@
|
||||
- Jangmo-o
|
||||
- Hakamo-o
|
||||
- Kommo-o
|
||||
- Alolan Diglett
|
||||
- Alolan Dugtrio
|
||||
|
||||
#### Gen 8
|
||||
- Gossifleur
|
||||
@@ -142,12 +115,6 @@
|
||||
- Dracozolt
|
||||
- Dracovish
|
||||
- Basculegion
|
||||
- Hisuian Decidueye
|
||||
- Hisuian Typhlosion
|
||||
- Hisuian Samurott
|
||||
- Hisuian Lilligant
|
||||
- Hisuian Sliggoo
|
||||
- Hisuian Goodra
|
||||
- Hisuian Zorua
|
||||
- Hisuian Zoroark
|
||||
- Hisuian Voltorb
|
||||
@@ -164,32 +131,17 @@
|
||||
- Dragapult
|
||||
- Hisuian Sliggoo
|
||||
- Hisuian Goodra
|
||||
- Impidimp
|
||||
- Morgrem
|
||||
- Grimmsnarl
|
||||
|
||||
#### Gen 9
|
||||
- Gimmighoul
|
||||
- Gimmighoul.
|
||||
- Using Relic Coins, you can increase Gimmighoul's Coin Stash. Upon reaching 999, it can be evolved into Gholdengo.
|
||||
- Additionally, if you give Gimmighoul a Netherite Scrap, you can increase its Netherite Stash. Who knows what might happen if it fills up?
|
||||
- Gholdengo
|
||||
|
||||
#### Cobblemon Exclusive's
|
||||
- Hisui Bias Rowlet
|
||||
- Hisui Bias Dartrix
|
||||
- Hisui Bias Cyndaquil
|
||||
- Hisui Bias Quilava
|
||||
- Hisui Bias Oshawott
|
||||
- Hisui Bias Dewott
|
||||
- Hisui Bias Goomy
|
||||
- Hisui Bias Petilil
|
||||
|
||||
|
||||
### Changes
|
||||
- Alolan Pikachu and Exeggcute changed to Alola bias.
|
||||
- Pokémon now transition more smoothly between different poses.
|
||||
- Updated models for Mimikyu, Alcremie, Squirtle, Wartortle, Blastoise, Pidgey, Pidgeotto, Pidgeot, Omanyte, Omastar, Growlithe, Arcanine, Nidoran Male, Nidoran Female, Lapras, Swinub, Piloswine, Basculin, Rowlet, Dartrix, Decidueye, Kabuto, Kabutops, Piplup, Prinplup, Elekid, Electabuzz, Cubone, Marowak, Paras, Mawile, Drifloon, Drifblim, Venonat, Venomoth, Yanma, Yanmega, Psyduck, Dusknoir, Diglett, Dugtrio, Natu, Xatu, Oshawott, Samurott, Torchic, Grovyle, Sceptile, Sizzlipede, and Raboot.
|
||||
- Updated animations for Squirtle, Wartortle, Blastoise, Pidgey, Pidgeotto, Diglett, Dugtrio, Magikarp, Dragonite, Omanyte, Omastar, Kabuto, Pinsir, Chinchou, Lanturn, Ralts, Kirlia, Gardevoir, Gallade, Buizel, Garchomp, Pumpkaboo, Falinks, Lechonk, Litwick, Lampent, Chandelure, Carnivine, Galarian Meowth, Galarian Rapidash, Venonat, Venomoth, Phanphy, Donphan, Dratini, Dragonair, Happiny, Chansey, Blissey, Volbeat, Illumise, Numel, Sizzlipede, Centiskorch, Obstagoon, Timburr, Gurdurr, Conkeldurr, Drifloon, and Drifblim.
|
||||
- Updated models for Mimikyu, Alcremie, Squirtle, Wartortle, Blastoise, Omanyte, Omastar, Growlithe, Swinub, Piloswine, Basculine, Rowlet, Dartrix, Decidueye, Kabuto, Kabutops, Piplup, Prinplup, Elekid, Electabuzz, Cubone, Marowak, Paras, Drifloon, Drifblim, Venonat, Venomoth, Yanma, Yanmega, and Raboot.
|
||||
- Updated animations for Diglett, Dugtrio, Dragonite, Omanyte, Omastar, Pinsir, Falinks, Lechonk, Litwick, Lampent, Chandelure, Carnivine, Galarian Meowth, Galarian Rapidash, Venonat, Venomoth, Phanphy, Donphan, Dratini, Dragonair, Happiny, Chansey, Blissey, Volbeat, Illumise, Numel, Drifloon, and Drifblim.
|
||||
- Added more held items to the held item tag, and Metal Coat to the held item tab.
|
||||
- Added all ores to the modloader ore tags, and added tags for each ore type to the mod (both blocks and items).
|
||||
- Changed the Destiny Knot to be crafted with a Ghast Tear, rather than a diamond.
|
||||
@@ -207,12 +159,9 @@
|
||||
- Upped the rate that Gastly drop Ghast Tears from 2.5% to 5%.
|
||||
- Pokémon with a low Blaze Powder drop chance now drop it more frequently in the Nether.
|
||||
- Reorganised a few advancements.
|
||||
- Pokémon entity shadows now scale when the Pokémon is being sent out or recalled.
|
||||
- Remade Torkoal particles, now they only appear when in battle.
|
||||
- Updated shiny icon within summary and PC interfaces.
|
||||
|
||||
### Fixes
|
||||
- Resized Snorlax
|
||||
- Resized Snorlax.
|
||||
- Re-added the recipe for the Iron Vitamin.
|
||||
- Cleaned up empty evolutions declaration in species files (no, I'm not listing all 169 by name).
|
||||
- Fixed Exeggcute not being able to evolve.
|
||||
@@ -227,16 +176,12 @@
|
||||
- Fixed very many issues with Bedrock particle effects.
|
||||
- Fixed Arbok patterns not being as specific in spawning as they were intended.
|
||||
- Fixed Pokémon not avoiding danger at all when pathfinding.
|
||||
- Fixed Pokémon pathing over snow layers and carpets.
|
||||
- Fixed Sobble line not being able to swim or breathe underwater.
|
||||
- Fixed incompatibility with [Just Enough Resources](https://modrinth.com/mod/just-enough-resources-jer).
|
||||
- Fixed incompatibility with [Visual Overhaul](https://modrinth.com/mod/visual-overhaul).
|
||||
- Fixed an issue that allowed Pokemon to spawn on rails.
|
||||
- Fixed the data set on Pokémon when abilities are given via properties such as in ``/spawnpokemon``.
|
||||
- Fixed sometimes Pokémon losing hidden abilities when evolving, this fix will only take effect to newly created Pokémon.
|
||||
- Fixed capture messages not displaying.
|
||||
- Fixed illusion ability causing the wrong Pokémon to be targeted in battle.
|
||||
- Battles starting with fainted party members no longer cause a softlock on defeat.
|
||||
|
||||
### Developer
|
||||
- Significantly changed the way properties in PokemonEntity work. This could break some plugins (not in a big way, but changes will be needed).
|
||||
@@ -248,7 +193,6 @@
|
||||
- Made PokemonProperties.parse more interoperable with Java.
|
||||
- Added the ``HeldItemEvent``, this comes with 2 implementation ``HeldItemEvent.Pre`` and ``HeldItemEvent.Post``.
|
||||
- API to support dynamic lighting in any mod that implements this feature has been added to all Species & Forms, see LightingData class for details.
|
||||
- Added a Mixin for the BrewingStandScreenHandler to fix the incorrect handling of quickMove in Fabric.
|
||||
- Corrections to the ability implementation have been made that make ``Ability.forced`` function as intended and never reroll an ability for a Pokémon, please check your implementations to ensure the corrected behavior is intended for your use case.
|
||||
- ``Pokemon.ability`` no longer has a public setter, please migrate to using ``Pokemon#updateAbility``, this handles the ability coordinate storage for you when necessary.
|
||||
- ``Ability.forced``, ``Ability.index`` and ``Ability.priority`` have all had their setters internalized, there is no longer any need to manually adjust these migrate to the method mentioned above to handle that process for you.
|
||||
@@ -256,7 +200,6 @@
|
||||
- ``Pokemon#rollAbility`` has been added, this rerolls a legal ability for the Pokémon.
|
||||
- `docs/cobblemon-tags` tags and spawn-presets can now be auto-generated from the current tags in the cobblemon mod with the `generateSpawnPresetList.py` and `generateTagList.py` scripts.
|
||||
- `public_spawns_to_json.py` script has been added to give the powerful spawn.json generator a simplistic UI.
|
||||
- Updated Showdown with Gen 9 DLC.
|
||||
|
||||
### Datapack & Resourcepack Creators
|
||||
- The maximum amount of fossils that can fit in the Fossil Analyzer can be adjusted in the config.
|
||||
|
||||
@@ -14,7 +14,25 @@ import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.PlayerInteractOptionsHandler
|
||||
import com.cobblemon.mod.common.client.net.SetClientPlayerDataHandler
|
||||
import com.cobblemon.mod.common.client.net.animation.PlayPoseableAnimationHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.*
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleApplyPassResponseHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleCaptureEndHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleCaptureShakeHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleCaptureStartHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleChallengeExpiredHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleChallengeNotificationHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleEndHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleFaintHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleHealthChangeHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleInitializeHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleMadeInvalidChoiceHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleMakeChoiceHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleMessageHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleMusicHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattlePersistentStatusHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleQueueRequestHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleSetTeamPokemonHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleSwitchPokemonHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleUpdateTeamPokemonHandler
|
||||
import com.cobblemon.mod.common.client.net.callback.move.OpenMoveCallbackHandler
|
||||
import com.cobblemon.mod.common.client.net.callback.party.OpenPartyCallbackHandler
|
||||
import com.cobblemon.mod.common.client.net.callback.partymove.OpenPartyMoveCallbackHandler
|
||||
@@ -287,8 +305,6 @@ object CobblemonNetwork : NetworkManager {
|
||||
this.createClientBound(BattleMadeInvalidChoicePacket.ID, BattleMadeInvalidChoicePacket::decode, BattleMadeInvalidChoiceHandler)
|
||||
this.createClientBound(BattleMusicPacket.ID, BattleMusicPacket::decode, BattleMusicHandler)
|
||||
this.createClientBound(BattleChallengeExpiredPacket.ID, BattleChallengeExpiredPacket::decode, BattleChallengeExpiredHandler)
|
||||
this.createClientBound(BattleReplacePokemonPacket.ID, BattleReplacePokemonPacket::decode, BattleReplacePokemonHandler)
|
||||
this.createClientBound(BattleTransformPokemonPacket.ID, BattleTransformPokemonPacket::decode, BattleTransformPokemonHandler)
|
||||
|
||||
|
||||
|
||||
|
||||
+20
-23
@@ -135,31 +135,28 @@ class BattleMessage(rawMessage: String) {
|
||||
return this.actorAndActivePokemon(pnx, battle)
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries an argument at the given [index] for a 'pnx' and uuid that will be parsed into a [BattlePokemon].
|
||||
*
|
||||
* @param index The index of the argument referencing the [BattlePokemon].
|
||||
* @param battle The [PokemonBattle] being queried.
|
||||
* @return The [BattlePokemon] if the argument exists and is successfully parsed; otherwise null.
|
||||
/*
|
||||
Example:
|
||||
|-curestatus|p1: a8e5710e-6835-4387-99d3-331b45f848e6|slp|[msg]
|
||||
|-curestatus|p1: 0686b20d-3019-4167-92e2-786834245743|slp|[msg]
|
||||
// Function used to grab BattlePokemon (As we need to be able to grab non active pokemon to cure their status)
|
||||
// by using playerNumber(actorID) and pokemon uuid(pokemonID)
|
||||
*/
|
||||
fun battlePokemon(index: Int, battle: PokemonBattle): BattlePokemon? {
|
||||
val (actorID, pokemonID) = this.pnxAndUuid(index) ?: return null
|
||||
return this.battlePokemon(actorID, pokemonID, battle)
|
||||
fun getBattlePokemon(index: Int, battle: PokemonBattle): BattlePokemon? {
|
||||
val actorAndPokemonID = this.argumentAt(index)?.takeIf { it.length >= 2 }?.split(": ") ?: return null
|
||||
if (actorAndPokemonID.count() < 2) return null
|
||||
val actorID = actorAndPokemonID[0]
|
||||
val pokemonID = actorAndPokemonID[1]
|
||||
return this.getBattlePokemon(actorID, pokemonID, battle)
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries an optional argument identified by [optionalArg] for a 'pnx' and uuid that will be parsed into a [BattlePokemon].
|
||||
*
|
||||
* @param optionalArg The id of the optional argument referencing the [BattlePokemon].
|
||||
* @param battle The [PokemonBattle] being queried.
|
||||
* @return The [BattlePokemon] if the argument exists and is successfully parsed; otherwise null.
|
||||
*/
|
||||
fun battlePokemonFromOptional(battle: PokemonBattle, optionalArg: String = "of"): BattlePokemon? {
|
||||
val optional = this.optionalArguments.get(optionalArg) ?: return null
|
||||
val pokemonID = optional.takeIf { it.length >= 2 }?.split(":")?.takeIf { it.size == 2 } ?: return null
|
||||
val pnx = pokemonID[0].takeIf { it.matches(PNX_MATCHER) || it.matches(PN_MATCHER) } ?: return null
|
||||
val uuid = pokemonID[1].trim()
|
||||
return this.battlePokemon(pnx, uuid, battle)
|
||||
fun getSourceBattlePokemon(battle: PokemonBattle): BattlePokemon? {
|
||||
val sourcePokemonArgument = this.optionalArguments.get("of") ?: return null
|
||||
val actorAndPokemonID = sourcePokemonArgument.takeIf { it.length >= 2 }?.split(": ") ?: return null
|
||||
if (actorAndPokemonID.count() < 2) return null
|
||||
val actorID = actorAndPokemonID[0]
|
||||
val pokemonID = actorAndPokemonID[1]
|
||||
return this.getBattlePokemon(actorID, pokemonID, battle)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -237,7 +234,7 @@ class BattleMessage(rawMessage: String) {
|
||||
null
|
||||
}
|
||||
|
||||
private fun battlePokemon(pnx: String, pokemonID: String, battle: PokemonBattle): BattlePokemon? = try {
|
||||
private fun getBattlePokemon(pnx: String, pokemonID: String, battle: PokemonBattle): BattlePokemon? = try {
|
||||
battle.getBattlePokemon(pnx, pokemonID)
|
||||
} catch (_: Exception) {
|
||||
null
|
||||
|
||||
@@ -8,11 +8,13 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.battles.model
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangEnvironment
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.CobblemonNetwork
|
||||
import com.cobblemon.mod.common.Environment
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
@@ -20,6 +22,8 @@ import com.cobblemon.mod.common.api.battles.model.actor.EntityBackedBattleActor
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.FleeableBattleActor
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.battles.BattleFledEvent
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunction
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
@@ -37,10 +41,10 @@ import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
|
||||
import com.cobblemon.mod.common.battles.interpreter.ContextManager
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.battles.runner.ShowdownService
|
||||
import com.cobblemon.mod.common.battles.ForfeitActionResponse
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleEndPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleMessagePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleMusicPacket
|
||||
import com.cobblemon.mod.common.pokemon.evolution.progress.DefeatEvolutionProgress
|
||||
import com.cobblemon.mod.common.pokemon.evolution.progress.LastBattleCriticalHitsEvolutionProgress
|
||||
import com.cobblemon.mod.common.pokemon.evolution.requirements.DefeatRequirement
|
||||
@@ -103,11 +107,6 @@ open class PokemonBattle(
|
||||
var turn: Int = 1
|
||||
private set
|
||||
|
||||
private var ticks: Int = 0
|
||||
set(value) { field = value.coerceAtMost(Int.MAX_VALUE) } // go outside
|
||||
|
||||
/** The current duration of the battle in seconds. */
|
||||
val time: Int get() = ticks % 20
|
||||
|
||||
var dispatchResult = GO
|
||||
val dispatches = ConcurrentLinkedDeque<BattleDispatch>()
|
||||
@@ -167,7 +166,7 @@ open class PokemonBattle(
|
||||
fun getActor(player: ServerPlayerEntity) = actors.firstOrNull { it.isForPlayer(player) }
|
||||
|
||||
/**
|
||||
* Gets a [BattleActor] and an [ActiveBattlePokemon] from a pnx key, e.g. p2a
|
||||
* Gets a BattleActor and an [ActiveBattlePokemon] from a pnx key, e.g. p2a
|
||||
*
|
||||
* Returns null if either the pn or x is invalid.
|
||||
*/
|
||||
@@ -180,11 +179,6 @@ open class PokemonBattle(
|
||||
return actor to pokemon
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a [BattlePokemon] from a pnx key and uuid.
|
||||
*
|
||||
* Returns null if the pnx key is invalid or the uuid does not exist.
|
||||
*/
|
||||
fun getBattlePokemon(pnx: String, pokemonID: String): BattlePokemon {
|
||||
val actor = actors.find { it.showdownId == pnx.substring(0, 2) }
|
||||
?: throw IllegalStateException("Invalid pnx: $pnx - unknown actor")
|
||||
@@ -396,9 +390,8 @@ open class PokemonBattle(
|
||||
return
|
||||
}
|
||||
|
||||
if (started) {
|
||||
ticks++
|
||||
if (isPvW && !ended && dispatches.isEmpty()) checkFlee()
|
||||
if (started && isPvW && !ended && dispatches.isEmpty()) {
|
||||
checkFlee()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -440,24 +433,13 @@ open class PokemonBattle(
|
||||
}
|
||||
|
||||
fun checkForInputDispatch() {
|
||||
if (checkForfeit()) return // ignore actors that are still choosing, their choices don't matter anymore
|
||||
val readyToInput = (actors.any { !it.mustChoose && it.responses.isNotEmpty() } && actors.none { it.mustChoose })
|
||||
val readyToInput = actors.any { !it.mustChoose && it.responses.isNotEmpty() } && actors.none { it.mustChoose }
|
||||
if (readyToInput && captureActions.isEmpty()) {
|
||||
actors.filter { it.responses.isNotEmpty() }.forEach { it.writeShowdownResponse() }
|
||||
actors.forEach { it.responses.clear() ; it.request = null }
|
||||
}
|
||||
}
|
||||
|
||||
/** Forces Showdown to end the battle when a [BattleActor] chooses to forfeit. */
|
||||
private fun checkForfeit(): Boolean {
|
||||
val forfeit = actors.find { it.responses.any { it is ForfeitActionResponse } }
|
||||
return forfeit?.let {
|
||||
this.dispatchWaiting { this.broadcastChatMessage(battleLang("forfeit", it.getName()).red()) }
|
||||
writeShowdownAction(">forcelose ${it.showdownId}")
|
||||
true
|
||||
} ?: false
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a [Text] representation of an error to interpret a battle message.
|
||||
* This also logs the error, the goal of this function is to make sure users see missing interpretations and report them to us.
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.entity.pokemon
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.effects.IllusionEffect
|
||||
import com.cobblemon.mod.common.entity.pokemon.effects.TransformEffect
|
||||
import com.cobblemon.mod.common.pokemon.FormData
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* Represents a temporary alteration to how a [PokemonEntity] is rendered and behaves. May include a temporary visual effect
|
||||
* when applied.
|
||||
*
|
||||
* @author Segfault Guy
|
||||
* @since March 5th, 2024
|
||||
*/
|
||||
interface EntityEffect {
|
||||
|
||||
/**
|
||||
* Starts this effect for the provided [PokemonEntity].
|
||||
*
|
||||
* @return A [CompletableFuture] that completes after the effect has been applied. Or null if the effect failed to start.
|
||||
*/
|
||||
fun start(entity: PokemonEntity): CompletableFuture<PokemonEntity>?
|
||||
|
||||
/**
|
||||
* Ends this effect for the provided [PokemonEntity].
|
||||
*
|
||||
* @return A [CompletableFuture] that completes after the effect has been reverted. Or null if the effect failed to end.
|
||||
*/
|
||||
fun end(entity: PokemonEntity): CompletableFuture<PokemonEntity>?
|
||||
|
||||
/** Saves this effect to NBT. */
|
||||
fun saveToNbt(): NbtCompound
|
||||
|
||||
/** Loads this effect from NBT. */
|
||||
fun loadFromNBT(nbt: NbtCompound)
|
||||
|
||||
companion object {
|
||||
|
||||
private val effects = mutableMapOf<String, KClass<out EntityEffect>>()
|
||||
private val defaults = mutableMapOf<String, () -> EntityEffect>()
|
||||
|
||||
init {
|
||||
register(IllusionEffect.ID, IllusionEffect::class, ::IllusionEffect)
|
||||
register(TransformEffect.ID, TransformEffect::class, ::TransformEffect)
|
||||
}
|
||||
|
||||
fun <T : EntityEffect> register(id: String, type: KClass<T>, default: () -> T) {
|
||||
effects[id] = type
|
||||
defaults[id] = default
|
||||
}
|
||||
|
||||
fun createDefault(id: String): EntityEffect? = defaults[id]?.invoke()
|
||||
|
||||
fun loadFromNbt(nbt: NbtCompound): EntityEffect? {
|
||||
if (nbt.contains(DataKeys.ENTITY_EFFECT_ID)) {
|
||||
val id = nbt.getString(DataKeys.ENTITY_EFFECT_ID)
|
||||
return createDefault(id)?.also { it.loadFromNBT(nbt) }
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** An [EntityEffect] that modifies the dimensions of a [PokemonEntity]. */
|
||||
interface PhysicalEffect : EntityEffect {
|
||||
val scale: Float
|
||||
}
|
||||
|
||||
/** An [EntityEffect] that alters the physical appearance of a [PokemonEntity] to match a [mock]. */
|
||||
interface MocKEffect : PhysicalEffect {
|
||||
val mock: PokemonProperties
|
||||
|
||||
val exposedSpecies: Species?
|
||||
get() = this.mock.species?.let { PokemonSpecies.getByIdentifier(it.asIdentifierDefaultingNamespace()) }
|
||||
|
||||
val exposedForm: FormData?
|
||||
get() = this.mock.form?.let {
|
||||
formID -> this.exposedSpecies?.forms?.firstOrNull { it.formOnlyShowdownId().equals(formID, true) } }
|
||||
?: this.exposedSpecies?.standardForm
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package com.cobblemon.mod.common.api.events
|
||||
|
||||
import com.cobblemon.mod.common.api.events.client.ClientSendoutEvent
|
||||
import com.cobblemon.mod.common.api.reactive.CancelableObservable
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
|
||||
@Suppress("unused")
|
||||
object CobblemonClientEvents {
|
||||
@JvmField
|
||||
val CLIENT_SENDOUT = SimpleObservable<ClientSendoutEvent>()
|
||||
}
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
package com.cobblemon.mod.common.api.events.client
|
||||
|
||||
import com.cobblemon.mod.common.api.events.Cancelable
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.util.math.Vec3d
|
||||
import org.joml.Vector3f
|
||||
|
||||
data class ClientSendoutEvent(var sendoutOffset: Vec3d, var startPos: Vec3d, val pokemon: PokemonEntity)
|
||||
@@ -397,7 +397,7 @@ open class PokemonProperties {
|
||||
return false
|
||||
}
|
||||
}
|
||||
nickname?.takeIf { it.string != pokemon.nickname?.string }?.let { return false }
|
||||
nickname?.takeIf { it != pokemon.nickname }?.let { return false }
|
||||
form?.takeIf { !it.equals(pokemon.form.name, true) }?.let { return false }
|
||||
friendship?.takeIf { it != pokemon.friendship }?.let { return false }
|
||||
pokeball?.takeIf { it != pokemon.caughtBall.name.toString() }?.let { return false }
|
||||
@@ -437,7 +437,7 @@ open class PokemonProperties {
|
||||
}
|
||||
} catch (_: InvalidIdentifierException) {}
|
||||
}
|
||||
nickname?.takeIf { it.string != properties.nickname?.string }?.let { return false }
|
||||
nickname?.takeIf { it != properties.nickname }?.let { return false }
|
||||
form?.takeIf { !it.equals(properties.form, true) }?.let { return false }
|
||||
friendship?.takeIf { it != properties.friendship }?.let { return false }
|
||||
pokeball?.takeIf { it != properties.pokeball }?.let { return false }
|
||||
|
||||
-5
@@ -48,11 +48,6 @@ fun interface PokemonPropertyExtractor {
|
||||
@JvmField
|
||||
val STATUS = add { pokemon, properties -> properties.status = pokemon.status?.status?.showdownName }
|
||||
|
||||
@JvmField
|
||||
val ILLUSION = mutableListOf(SPECIES, FORM, ASPECTS, GENDER, NICKNAME, SHINY)
|
||||
@JvmField
|
||||
val TRANSFORM = mutableListOf(SPECIES, FORM, ASPECTS, GENDER)
|
||||
|
||||
fun add(extractor: PokemonPropertyExtractor): PokemonPropertyExtractor {
|
||||
ALL.add(extractor)
|
||||
return extractor
|
||||
|
||||
@@ -49,25 +49,6 @@ enum class Stats(override val identifier: Identifier, override val displayName:
|
||||
*/
|
||||
val BATTLE_ONLY: Set<Stat> = EnumSet.of(EVASION, ACCURACY)
|
||||
|
||||
/** Gets the [Stat] from the respective Showdown id. */
|
||||
fun getStat(statKey: String) = when(statKey) {
|
||||
"atk" -> ATTACK
|
||||
"def" -> DEFENCE
|
||||
"spa" -> SPECIAL_ATTACK
|
||||
"spd" -> SPECIAL_DEFENCE
|
||||
"spe" -> SPEED
|
||||
"evasion" -> EVASION
|
||||
else -> ACCURACY
|
||||
}
|
||||
|
||||
/** Gets the severity lang key from the respective boost/unboost stage. */
|
||||
fun getSeverity(stages: Int) = when(stages) {
|
||||
0 -> "cap.single"
|
||||
1 -> "slight"
|
||||
2 -> "sharp"
|
||||
else -> "severe"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -260,7 +260,7 @@ open class PartyStore(override val uuid: UUID) : PokemonStore<PartyPosition>() {
|
||||
return@mapNotNull if (clone) {
|
||||
BattlePokemon.safeCopyOf(it)
|
||||
} else {
|
||||
BattlePokemon.playerOwned(it)
|
||||
BattlePokemon(it)
|
||||
}
|
||||
}.sortedBy { if (it.uuid == leadingPokemon) 0 else (indexOf(it.originalPokemon) + 1) }
|
||||
|
||||
|
||||
@@ -17,8 +17,6 @@ class ActiveBattlePokemon(val actor: BattleActor, var battlePokemon: BattlePokem
|
||||
fun getSide() = actor.getSide()
|
||||
var position: Pair<ServerWorld, Vec3d>? = null
|
||||
|
||||
var illusion: BattlePokemon? = null
|
||||
|
||||
override fun getAllActivePokemon() = battle.activePokemon
|
||||
override fun getActorShowdownId() = actor.showdownId
|
||||
override fun getActorPokemon() = actor.activePokemon
|
||||
|
||||
@@ -100,19 +100,11 @@ object BattleBuilder {
|
||||
fleeDistance: Float = Cobblemon.config.defaultFleeDistance,
|
||||
party: PartyStore = player.party()
|
||||
): BattleStartResult {
|
||||
val playerTeam = party.toBattleTeam(clone = cloneParties, checkHealth = !healFirst, leadingPokemon = leadingPokemon).sortedBy { it.health <= 0 }
|
||||
val playerTeam = party.toBattleTeam(clone = cloneParties, checkHealth = !healFirst, leadingPokemon = leadingPokemon)
|
||||
val playerActor = PlayerBattleActor(player.uuid, playerTeam)
|
||||
val wildActor = PokemonBattleActor(pokemonEntity.pokemon.uuid, BattlePokemon(pokemonEntity.pokemon), fleeDistance)
|
||||
val errors = ErroredBattleStart()
|
||||
|
||||
if(playerTeam.isNotEmpty() && playerTeam[0].health <= 0){
|
||||
errors.participantErrors[playerActor] += BattleStartError.insufficientPokemon(
|
||||
player = player,
|
||||
requiredCount = battleFormat.battleType.slotsPerActor,
|
||||
hadCount = playerActor.pokemonList.size
|
||||
)
|
||||
}
|
||||
|
||||
if (playerActor.pokemonList.size < battleFormat.battleType.slotsPerActor) {
|
||||
errors.participantErrors[playerActor] += BattleStartError.insufficientPokemon(
|
||||
player = player,
|
||||
|
||||
@@ -44,10 +44,10 @@ class BattleCaptureAction(
|
||||
pokeBallEntity.captureFuture.thenAccept { successful ->
|
||||
if (successful) {
|
||||
targetPokemon.battlePokemon?.gone = true
|
||||
battle.dispatchWaiting(2F) { battle.broadcastChatMessage(lang("capture.succeeded", pokemonName).green()) }
|
||||
battle.writeShowdownAction(">capture ${targetPokemon.getPNX()}")
|
||||
battle.broadcastChatMessage(lang("capture.succeeded", pokemonName).green())
|
||||
} else {
|
||||
battle.dispatchWaiting(2F) { battle.broadcastChatMessage(lang("capture.broke_free", pokemonName).red()) }
|
||||
battle.broadcastChatMessage(lang("capture.broke_free", pokemonName).red())
|
||||
}
|
||||
battle.sendUpdate(BattleCaptureEndPacket(targetPokemon.getPNX(), successful))
|
||||
battle.finishCaptureAction(this)
|
||||
|
||||
@@ -95,8 +95,7 @@ enum class ShowdownActionResponseType(val loader: (PacketByteBuf) -> ShowdownAct
|
||||
DEFAULT({ DefaultActionResponse() }),
|
||||
FORCE_PASS({ ForcePassActionResponse() }),
|
||||
PASS({ PassActionResponse }),
|
||||
HEAL_ITEM({ HealItemActionResponse("potion") }),
|
||||
FORFEIT({ ForfeitActionResponse() });
|
||||
HEAL_ITEM({ HealItemActionResponse("potion") });
|
||||
}
|
||||
|
||||
abstract class ShowdownActionResponse(val type: ShowdownActionResponseType) {
|
||||
@@ -266,11 +265,6 @@ class BagItemActionResponse(val bagItem: BagItem, val target: BattlePokemon, val
|
||||
}
|
||||
}
|
||||
|
||||
class ForfeitActionResponse : ShowdownActionResponse(ShowdownActionResponseType.FORFEIT) {
|
||||
override fun isValid(activeBattlePokemon: ActiveBattlePokemon, showdownMoveSet: ShowdownMoveset?, forceSwitch: Boolean) = true
|
||||
override fun toShowdownString(activeBattlePokemon: ActiveBattlePokemon, showdownMoveSet: ShowdownMoveset?) = "forfeit"
|
||||
}
|
||||
|
||||
class ShowdownMoveset {
|
||||
lateinit var moves: List<InBattleMove>
|
||||
var trapped = false
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
+15
-11
@@ -19,29 +19,33 @@ import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-ability|POKEMON|ABILITY|(from)EFFECT
|
||||
* Format:
|
||||
* |-ability|POKEMON|ABILITY|(from)EFFECT
|
||||
*
|
||||
* The ABILITY of POKEMON has been changed due to a move/ability EFFECT.
|
||||
* The ABILITY of the POKEMON has been changed due to a move/ability EFFECT.
|
||||
*
|
||||
* Alt format: |-ability|POKEMON|ABILITY
|
||||
* Format:
|
||||
* |-ability|POKEMON|ABILITY
|
||||
*
|
||||
* POKEMON has just switched-in, and its ABILITY is being announced to have a long-term effect.
|
||||
* @author Xylopia
|
||||
* @since January 31st, 2023
|
||||
* POKEMON has just switched-in, and its ability ABILITY is being announced to have a long-term effect.
|
||||
*/
|
||||
class AbilityInstruction(val instructionSet: InstructionSet, val message: BattleMessage) : InterpreterInstruction, CauserInstruction {
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return
|
||||
val pokemon = message.getBattlePokemon(0, battle) ?: return
|
||||
val pokemonName = pokemon.getName()
|
||||
val effect = message.effectAt(1) ?: return
|
||||
val optionalEffect = message.effect()
|
||||
val optionalPokemon = message.battlePokemonFromOptional(battle)
|
||||
val optionalPokemon = message.getSourceBattlePokemon(battle)
|
||||
val optionalPokemonName = optionalPokemon?.getName()
|
||||
|
||||
// If there is an optional effect causing the activation, broadcast that instead of the standard effect
|
||||
ShowdownInterpreter.broadcastAbility(battle, optionalEffect ?: effect, pokemon)
|
||||
if (optionalEffect != null) {
|
||||
ShowdownInterpreter.broadcastAbility(battle, optionalEffect, pokemonName)
|
||||
} else {
|
||||
ShowdownInterpreter.broadcastAbility(battle, effect, pokemonName)
|
||||
}
|
||||
|
||||
battle.dispatch {
|
||||
val pokemonName = pokemon.getName()
|
||||
val optionalPokemonName = optionalPokemon?.getName()
|
||||
ShowdownInterpreter.lastCauser[battle.battleId] = message
|
||||
|
||||
val lang = when (optionalEffect?.id) {
|
||||
|
||||
+7
-10
@@ -20,24 +20,21 @@ import com.cobblemon.mod.common.util.battleLang
|
||||
import net.minecraft.text.Text
|
||||
|
||||
/**
|
||||
* Format: |-activate|POKEMON|EFFECT
|
||||
* Format:
|
||||
* |-activate|POKEMON|EFFECT
|
||||
*
|
||||
* A miscellaneous EFFECT has activated for POKEMON. This is triggered whenever an effect could not be better described
|
||||
* by one of the other minor messages.
|
||||
*
|
||||
* @author Hunter
|
||||
* @since September 25th, 2022
|
||||
* A miscellaneous effect has activated.This is triggered whenever an effect could not be better described by one of the other minor messages.
|
||||
*/
|
||||
class ActivateInstruction(val instructionSet: InstructionSet, val message: BattleMessage) : InterpreterInstruction, CauserInstruction {
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return
|
||||
val pokemon = message.getBattlePokemon(0, battle) ?: return
|
||||
val pokemonName = pokemon.getName()
|
||||
val sourceName = message.getSourceBattlePokemon(battle)?.getName() ?: Text.literal("UNKNOWN")
|
||||
val effect = message.effectAt(1) ?: return
|
||||
val extraEffect = message.effectAt(2)?.typelessData ?: Text.literal("UNKNOWN")
|
||||
ShowdownInterpreter.broadcastOptionalAbility(battle, effect, pokemon)
|
||||
ShowdownInterpreter.broadcastOptionalAbility(battle, effect, pokemonName)
|
||||
|
||||
battle.dispatch{
|
||||
val pokemonName = pokemon.getName()
|
||||
val sourceName = message.battlePokemonFromOptional(battle)?.getName() ?: Text.literal("UNKNOWN")
|
||||
ShowdownInterpreter.lastCauser[battle.battleId] = message
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
|
||||
|
||||
-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.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |bagitem|POKEMON|ITEM
|
||||
*
|
||||
* POKEMON had ITEM used on it from the 'bag'.
|
||||
* @author landonjw
|
||||
* @since July 31st, 2023
|
||||
*/
|
||||
class BagItemInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchGo {
|
||||
val pokemon = message.pokemonByUuid(0, battle)!!
|
||||
val item = message.argumentAt(1)!!
|
||||
|
||||
val ownerName = pokemon.actor.getName()
|
||||
val itemName = item.asTranslated()
|
||||
|
||||
battle.broadcastChatMessage(battleLang("bagitem.use", ownerName, itemName, pokemon.getName()))
|
||||
}
|
||||
}
|
||||
}
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-block|POKEMON|EFFECT|MOVE|ATTACKER|(of)SOURCE
|
||||
*
|
||||
* An effect targeted at POKEMON was blocked by EFFECT. This may optionally specify that the effect was a MOVE from ATTACKER.
|
||||
*
|
||||
* An optional SOURCE will note the owner of the EFFECT, in the case that it's not EFFECT (for instance, an ally with Aroma Veil.)
|
||||
* @author jeffw773
|
||||
* @since November 6th, 2023
|
||||
*/
|
||||
class BlockInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting(1.5F) {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchWaiting
|
||||
val pokemonName = pokemon.getName()
|
||||
val effectID = message.effectAt(1)?.id ?: return@dispatchWaiting
|
||||
val lang = battleLang("block.$effectID", pokemonName)
|
||||
|
||||
battle.broadcastChatMessage(lang)
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
-52
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-boost|POKEMON|STAT|AMOUNT or |-unboost|POKEMON|STAT|AMOUNT
|
||||
*
|
||||
* POKEMON has gained or lost AMOUNT in STAT, using the standard rules for stat changes in-battle.
|
||||
* STAT is a standard three-letter abbreviation fot the stat in question.
|
||||
* @author Hiroku
|
||||
* @since August 20th, 2022
|
||||
*/
|
||||
class BoostInstruction(val instructionSet: InstructionSet, val message: BattleMessage, val remainingLines: Iterator<BattleMessage>, val isBoost: Boolean = true): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return
|
||||
val statKey = message.argumentAt(1) ?: return
|
||||
val stages = message.argumentAt(2)?.toInt() ?: return
|
||||
val stat = Stats.getStat(statKey).displayName
|
||||
val severity = Stats.getSeverity(stages)
|
||||
val rootKey = if (isBoost) "boost" else "unboost"
|
||||
|
||||
battle.dispatchWaiting(1.5F) {
|
||||
val lang = when {
|
||||
message.hasOptionalArgument("zeffect") -> battleLang("$rootKey.$severity.zeffect", pokemon.getName(), stat)
|
||||
else -> battleLang("$rootKey.$severity", pokemon.getName(), stat)
|
||||
}
|
||||
battle.broadcastChatMessage(lang)
|
||||
|
||||
val boostBucket = if (isBoost) BattleContext.Type.BOOST else BattleContext.Type.UNBOOST
|
||||
val context = ShowdownInterpreter.getContextFromAction(message, boostBucket, battle)
|
||||
// TODO: replace with context that tracks detailed information such as # of stages
|
||||
repeat(stages) { pokemon.contextManager.add(context) }
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
-51
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
|
||||
/**
|
||||
* Formats: |cant|POKEMON|REASON and |cant|POKEMON|REASON|MOVE
|
||||
*
|
||||
* The POKEMON could not perform a move because of the indicated REASON.
|
||||
* @author Deltric
|
||||
* @since January 22nd, 2022
|
||||
*/
|
||||
class CantInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchWaiting
|
||||
val effectID = message.effectAt(1)?.id ?: return@dispatchWaiting
|
||||
val name = pokemon.getName()
|
||||
// Move may be null as it's not always given
|
||||
val moveName = message.moveAt(2)?.displayName ?: run { "(Unrecognized: ${message.argumentAt(2)})".text() }
|
||||
|
||||
val lang = when (effectID) {
|
||||
// TODO: in the games they use a generic image because there is a popup of the ability and the sprite of the mon, it may be good to have a similar system here
|
||||
"armortail", "damp", "dazzling", "queenlymajesty" -> battleLang("cant.generic", name, moveName)
|
||||
"par", "slp", "frz" -> {
|
||||
val status = Statuses.getStatus(effectID)?.name?.path ?: return@dispatchWaiting
|
||||
lang("status.$status.is", name)
|
||||
}
|
||||
else -> battleLang("cant.$effectID", name, moveName)
|
||||
}
|
||||
|
||||
battle.broadcastChatMessage(lang.red())
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-clearallboost|
|
||||
*
|
||||
* Clears all boosts from all Pokémon on both sides.
|
||||
* @author Segfault Guy
|
||||
* @since April 26th, 2023
|
||||
*/
|
||||
class ClearAllBoostInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting(1.5F) {
|
||||
battle.activePokemon.forEach {
|
||||
it.battlePokemon?.contextManager?.clear(BattleContext.Type.BOOST, BattleContext.Type.UNBOOST)
|
||||
}
|
||||
battle.broadcastChatMessage(battleLang("clearallboost"))
|
||||
}
|
||||
}
|
||||
}
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-clearnegativeboost|POKEMON
|
||||
*
|
||||
* Clear the negative boosts from the target POKEMON (usually as the result of a zeffect).
|
||||
* @author Segfault Guy
|
||||
* @since September 10th, 2023
|
||||
*/
|
||||
class ClearNegativeBoostInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val battlePokemon = message.battlePokemon(0, battle) ?: return
|
||||
|
||||
battle.dispatchWaiting(1.5F) {
|
||||
val pokemonName = battlePokemon.getName()
|
||||
val lang = when {
|
||||
message.hasOptionalArgument("zeffect") -> battleLang("clearallnegativeboost.zeffect", pokemonName)
|
||||
else -> battleLang("clearallnegativeboost", pokemonName)
|
||||
}
|
||||
if (!message.hasOptionalArgument("silent")) {
|
||||
battle.broadcastChatMessage(lang)
|
||||
}
|
||||
|
||||
battlePokemon.contextManager.clear(BattleContext.Type.UNBOOST)
|
||||
battle.minorBattleActions[battlePokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-copyboost|SOURCE|TARGET|(from)EFFECT
|
||||
*
|
||||
* Copies any stat changes from the TARGET Pokémon to the SOURCE Pokémon due to EFFECT.
|
||||
* @author JMMCP
|
||||
* @since November 27th, 2023
|
||||
*/
|
||||
class CopyBoostInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchWaiting
|
||||
val pokemonName = pokemon.getName()
|
||||
val targetPokemon = message.battlePokemon(1, battle) ?: return@dispatchWaiting
|
||||
val targetPokemonName = targetPokemon.getName()
|
||||
val lang = battleLang("copyboost.generic", pokemonName, targetPokemonName)
|
||||
battle.broadcastChatMessage(lang)
|
||||
|
||||
pokemon.contextManager.copy(targetPokemon.contextManager, BattleContext.Type.BOOST, BattleContext.Type.UNBOOST)
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.text.yellow
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.pokemon.evolution.progress.LastBattleCriticalHitsEvolutionProgress
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-crit|POKEMON
|
||||
*
|
||||
* POKEMON received a critical hit.
|
||||
* @author Hunter
|
||||
* @since August 18th, 2022
|
||||
*/
|
||||
class CritInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchGo {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchGo
|
||||
battle.broadcastChatMessage(battleLang("crit").yellow())
|
||||
ShowdownInterpreter.lastCauser[battle.battleId]?.let { message ->
|
||||
val battlePokemon = message.battlePokemon(0, battle) ?: return@let
|
||||
if (LastBattleCriticalHitsEvolutionProgress.supports(battlePokemon.effectedPokemon)) {
|
||||
val progress = battlePokemon.effectedPokemon.evolutionProxy.current().progressFirstOrCreate({ it is LastBattleCriticalHitsEvolutionProgress }) { LastBattleCriticalHitsEvolutionProgress() }
|
||||
progress.updateProgress(LastBattleCriticalHitsEvolutionProgress.Progress(progress.currentProgress().amount + 1))
|
||||
}
|
||||
}
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
-58
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.Effect
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattlePersistentStatusPacket
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-curestatus|POKEMON|STATUS
|
||||
*
|
||||
* The POKEMON has recovered from its STATUS.
|
||||
* @author Hiroku
|
||||
* @since November 5th, 2022
|
||||
*/
|
||||
class CureStatusInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val maybeActivePokemon = message.actorAndActivePokemon(0, battle)?.second?.battlePokemon
|
||||
val maybePartyPokemon = message.battlePokemon(0, battle)
|
||||
val pokemon = maybeActivePokemon ?: maybePartyPokemon ?: return
|
||||
val status = message.argumentAt(1)?.let(Statuses::getStatus) ?: return
|
||||
val effect = message.effect()
|
||||
ShowdownInterpreter.broadcastOptionalAbility(battle, effect, pokemon)
|
||||
|
||||
battle.dispatchWaiting {
|
||||
val pokemonName = pokemon.getName()
|
||||
pokemon.effectedPokemon.status = null
|
||||
pokemon.sendUpdate()
|
||||
|
||||
if (maybeActivePokemon != null) {
|
||||
message.pnxAndUuid(0)?.let {
|
||||
battle.sendUpdate(BattlePersistentStatusPacket(it.first, null))
|
||||
}
|
||||
}
|
||||
val lang = when (effect?.type) {
|
||||
Effect.Type.ABILITY -> battleLang("curestatus.${effect.id}", pokemonName)
|
||||
else -> status.removeMessage.asTranslated(pokemonName)
|
||||
}
|
||||
battle.broadcastChatMessage(lang)
|
||||
pokemon.contextManager.remove(status.showdownName, BattleContext.Type.STATUS)
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-15
@@ -19,7 +19,6 @@ import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.battles.dispatch.UntilDispatch
|
||||
import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.net.messages.client.animation.PlayPoseableAnimationPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleHealthChangePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
|
||||
@@ -31,13 +30,6 @@ import java.util.concurrent.CompletableFuture
|
||||
import kotlin.math.roundToInt
|
||||
import net.minecraft.text.Text
|
||||
|
||||
/**
|
||||
* Format: |-damage|POKEMON|HP STATUS
|
||||
*
|
||||
* POKEMON has taken damage and is now at HP STATUS
|
||||
* @author Hiroku
|
||||
* @since March 11th, 2022
|
||||
*/
|
||||
class DamageInstruction(
|
||||
val instructionSet: InstructionSet,
|
||||
val actor: BattleActor,
|
||||
@@ -45,10 +37,10 @@ class DamageInstruction(
|
||||
val privateMessage: BattleMessage
|
||||
) : InterpreterInstruction {
|
||||
var future = CompletableFuture.completedFuture(Unit)
|
||||
val expectedTarget = publicMessage.battlePokemon(0, actor.battle)
|
||||
val battlePokemon = publicMessage.getBattlePokemon(0, actor.battle)
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val battlePokemon = publicMessage.battlePokemon(0, actor.battle) ?: return
|
||||
battlePokemon ?: return
|
||||
val recoiling = privateMessage.optionalArgument("from")?.equals("recoil", true) == true
|
||||
val lastCauser = instructionSet.getMostRecentCauser(comparedTo = this)
|
||||
if (recoiling) {
|
||||
@@ -66,7 +58,8 @@ class DamageInstruction(
|
||||
}
|
||||
val newHealth = privateMessage.argumentAt(1)?.split(" ")?.get(0) ?: return
|
||||
val effect = privateMessage.effect()
|
||||
val source = privateMessage.battlePokemonFromOptional(battle)
|
||||
val pokemonName = battlePokemon.getName()
|
||||
val sourceName = privateMessage.getSourceBattlePokemon(battle)?.getName() ?: Text.literal("UNKNOWN")
|
||||
var causedFaint = newHealth == "0"
|
||||
|
||||
battle.dispatch {
|
||||
@@ -77,10 +70,7 @@ class DamageInstruction(
|
||||
}
|
||||
}
|
||||
|
||||
source?.let { ShowdownInterpreter.broadcastOptionalAbility(battle, effect, it) }
|
||||
|
||||
battle.dispatch {
|
||||
val pokemonName = battlePokemon.getName()
|
||||
val pokemonEntity = battlePokemon.entity
|
||||
if (!causedFaint && pokemonEntity != null) {
|
||||
val pkt = PlayPoseableAnimationPacket(pokemonEntity.id, setOf("recoil"), emptySet())
|
||||
@@ -103,6 +93,8 @@ class DamageInstruction(
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
ShowdownInterpreter.broadcastOptionalAbility(battle, effect, sourceName)
|
||||
val newHealthRatio: Float
|
||||
val remainingHealth = newHealth.split("/")[0].toInt()
|
||||
|
||||
@@ -116,7 +108,7 @@ class DamageInstruction(
|
||||
"aftermath" -> battleLang("damage.generic", pokemonName)
|
||||
"chloroblast", "steelbeam" -> battleLang("damage.mindblown", pokemonName)
|
||||
"jumpkick" -> battleLang("damage.highjumpkick", pokemonName)
|
||||
else -> battleLang("damage.${effect.id}", pokemonName, source?.getName() ?: Text.literal("UNKOWN"))
|
||||
else -> battleLang("damage.${effect.id}", pokemonName, sourceName)
|
||||
}
|
||||
battle.broadcastChatMessage(lang.red())
|
||||
}
|
||||
|
||||
+3
-11
@@ -8,20 +8,12 @@
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-nothing
|
||||
*
|
||||
* Pathetic. Your move did absolutely nothing. You should feel bad for being bad.
|
||||
* @author Hiroku
|
||||
* @since August 20th, 2022
|
||||
*/
|
||||
class NothingInstruction() : InterpreterInstruction {
|
||||
|
||||
class DeprecatedInstruction(val message: BattleMessage, val function: (PokemonBattle, BattleMessage, MutableList<String>) -> Unit) : InterpreterInstruction {
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchGo { battle.broadcastChatMessage(battleLang("nothing")) }
|
||||
function(battle, message, mutableListOf())
|
||||
}
|
||||
}
|
||||
+8
-15
@@ -10,23 +10,16 @@ package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-resisted|POKEMON
|
||||
*
|
||||
* POKEMON resisted the attack.
|
||||
* @author Hunter
|
||||
* @since August 18th, 2022
|
||||
*/
|
||||
class ResistedInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
class DeprecatedSplitInstruction(
|
||||
val battleActor: BattleActor,
|
||||
val publicMessage: BattleMessage,
|
||||
val privateMessage: BattleMessage,
|
||||
val function: (PokemonBattle, BattleActor, BattleMessage, BattleMessage) -> Unit
|
||||
) : InterpreterInstruction {
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchGo {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchGo
|
||||
battle.broadcastChatMessage(battleLang("resisted"))
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
function(battle, battleActor, publicMessage, privateMessage)
|
||||
}
|
||||
}
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |detailschange|POKEMON|DETAILS|HP STATUS
|
||||
*
|
||||
* POKEMON has changed formes permanently (i.e. Mega Evolution) to DETAILS.
|
||||
* @author Segfault Guy
|
||||
* @since September 10th, 2023
|
||||
*/
|
||||
class DetailsChangeInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val battlePokemon = message.battlePokemon(0, battle) ?: return
|
||||
val formName = message.argumentAt(1)?.split(',')?.get(0)?.substringAfter('-')?.lowercase() ?: return
|
||||
battle.dispatchWaiting {
|
||||
val pokemonName = battlePokemon.getName()
|
||||
battle.broadcastChatMessage(battleLang("detailschange.$formName", pokemonName))
|
||||
battle.majorBattleActions[battlePokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
-60
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.EntityBackedBattleActor
|
||||
import com.cobblemon.mod.common.battles.dispatch.BattleDispatch
|
||||
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |drag|POKEMON|DETAILS|HP STATUS
|
||||
*
|
||||
* POKEMON has switched in (if there was an old Pokémon in that position, it is switched out).
|
||||
* POKEMON|DETAILS represents all the information that can be used to tell Pokémon apart.
|
||||
* The switched Pokémon has HP health points and STATUS status.
|
||||
* @author Hiroku
|
||||
* @since April 24th, 2022
|
||||
*/
|
||||
class DragInstruction(val instructionSet: InstructionSet, val battleActor: BattleActor, val publicMessage: BattleMessage, val privateMessage: BattleMessage): InterpreterInstruction {
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchInsert {
|
||||
val (pnx, _) = publicMessage.pnxAndUuid(0)!!
|
||||
val (_, activePokemon) = battle.getActorAndActiveSlotFromPNX(pnx)
|
||||
|
||||
val imposter = instructionSet.getNextInstruction<TransformInstruction>(this)?.expectedTarget != null
|
||||
val illusion = publicMessage.battlePokemonFromOptional(battle , "is")
|
||||
val pokemon = publicMessage.battlePokemon(0, battle) ?: return@dispatchInsert emptySet()
|
||||
|
||||
battle.broadcastChatMessage(battleLang("dragged_out", pokemon.getName()))
|
||||
activePokemon.battlePokemon?.let { oldPokemon ->
|
||||
oldPokemon.contextManager.clear(BattleContext.Type.VOLATILE, BattleContext.Type.BOOST, BattleContext.Type.UNBOOST)
|
||||
battle.majorBattleActions[oldPokemon.uuid] = publicMessage
|
||||
}
|
||||
battle.majorBattleActions[pokemon.uuid] = publicMessage
|
||||
|
||||
val entity = if (battleActor is EntityBackedBattleActor<*>) battleActor.entity else null
|
||||
setOf(
|
||||
BattleDispatch {
|
||||
if (entity != null) {
|
||||
SwitchInstruction.createEntitySwitch(battle, battleActor, entity, pnx, activePokemon, pokemon, illusion, imposter)
|
||||
} else {
|
||||
SwitchInstruction.createNonEntitySwitch(battle, battleActor, pnx, activePokemon, pokemon, illusion)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-endability|POKEMON
|
||||
*
|
||||
* The POKEMON's Ability was suppressed.
|
||||
* @author jeffw773
|
||||
* @since November 28th, 2023
|
||||
*/
|
||||
class EndAbilityInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting(1.5F) {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchWaiting
|
||||
val pokemonName = pokemon.getName()
|
||||
|
||||
val lang = battleLang("endability", pokemonName)
|
||||
battle.broadcastChatMessage(lang)
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
|
||||
/**
|
||||
* Format: |-end|POKEMON|EFFECT
|
||||
*
|
||||
* The volatile status from EFFECT inflicted on POKEMON has ended.
|
||||
* @author Hiroku
|
||||
* @since October 3rd, 2022
|
||||
*/
|
||||
class EndInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchWaiting
|
||||
val pokemonName = pokemon.getName()
|
||||
val effectID = message.effectAt(1)?.id ?: return@dispatchWaiting
|
||||
if (!message.hasOptionalArgument("silent")) {
|
||||
val lang = when (effectID) {
|
||||
"yawn" -> lang("status.sleep.apply", pokemonName)
|
||||
else -> battleLang("end.$effectID", pokemonName)
|
||||
}
|
||||
battle.broadcastChatMessage(lang)
|
||||
}
|
||||
pokemon.contextManager.remove(effectID, BattleContext.Type.VOLATILE)
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
-45
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-enditem|POKEMON|ITEM|(from)EFFECT
|
||||
*
|
||||
* ITEM held by POKEMON has been destroyed by a move or ability EFFECT, and it now holds no item.
|
||||
*
|
||||
* Alt format: |-enditem|POKEMON|ITEM
|
||||
*
|
||||
* POKEMON's ITEM has destroyed itself (consumed or used).
|
||||
* @author Licious
|
||||
* @since December 30th, 2022
|
||||
*/
|
||||
class EndItemInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchGo {
|
||||
// All logic regarding broadcasting battle messages is handled in CobblemonHeldItemManager
|
||||
val battlePokemon = message.battlePokemon(0, battle) ?: return@dispatchGo
|
||||
val itemEffect = message.effectAt(1) ?: return@dispatchGo
|
||||
battlePokemon.heldItemManager.handleEndInstruction(battlePokemon, battle, message)
|
||||
battle.minorBattleActions[battlePokemon.uuid] = message
|
||||
battlePokemon.contextManager.remove(itemEffect.id, BattleContext.Type.ITEM)
|
||||
if (message.hasOptionalArgument("eat")) {
|
||||
battlePokemon.entity?.playSound(CobblemonSounds.BERRY_EAT, 1F, 1F)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleMadeInvalidChoicePacket
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |error|(Invalid choice) ERROR
|
||||
*
|
||||
* The actor needs to send a different decision due to ERROR.
|
||||
* @author Yaseen
|
||||
* @since April 22nd, 2023
|
||||
*/
|
||||
class ErrorInstruction(val battleActor: BattleActor, val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.log("Error Instruction")
|
||||
battle.dispatchGo {
|
||||
//TODO: some lang stuff for the error messages (Whats the protocol for adding to other langs )
|
||||
//Also is it okay to ignore the team preview error for now? - You bet!
|
||||
val lang = when(message.rawMessage) {
|
||||
"|error|[Unavailable choice] Can't switch: The active Pokémon is trapped" -> battleLang("error.pokemon_is_trapped").red()
|
||||
"|error|[Invalid choice] Can't choose for Team Preview: You're not in a Team Preview phase" -> return@dispatchGo
|
||||
else -> battle.createUnimplemented(message)
|
||||
}
|
||||
battleActor.sendMessage(lang)
|
||||
battleActor.mustChoose = true
|
||||
battleActor.sendUpdate(BattleMadeInvalidChoicePacket())
|
||||
}
|
||||
}
|
||||
}
|
||||
-56
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-fail|POKEMON|ACTION
|
||||
*
|
||||
* ACTION has failed against POKEMON.
|
||||
* @author Hunter
|
||||
* @since September 25th, 2022
|
||||
*/
|
||||
class FailInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting(1.5F){
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchWaiting
|
||||
val pokemonName = pokemon.getName()
|
||||
val effectID = message.effectAt(1)?.id
|
||||
val cause = message.effect("from")
|
||||
val of = message.battlePokemonFromOptional(battle)
|
||||
|
||||
val lang = when (effectID) {
|
||||
null, "burnup", "doubleshock" -> battleLang("fail") // Moves that use default fail lang. (Null included for moves that fail with no effect, for example: Baton Pass.)
|
||||
"shedtail" -> battleLang("fail.substitute", pokemonName)
|
||||
"hyperspacefury", "aurawheel" -> battleLang("fail.darkvoid", pokemonName) // Moves that can only be used by one species and fail when any others try
|
||||
"corrosivegas" -> battleLang("fail.healblock", pokemonName)
|
||||
"dynamax" -> battleLang("fail.grassknot", pokemonName) // Covers weight moves that fail against dynamaxed Pokémon
|
||||
"unboost" -> {
|
||||
val statKey = message.argumentAt(2)
|
||||
val stat = statKey?.let { Stats.getStat(it).displayName }
|
||||
if (stat != null) {
|
||||
battleLang("fail.$effectID.single", pokemonName, stat)
|
||||
} else {
|
||||
battleLang("fail.$effectID", pokemonName)
|
||||
}
|
||||
}
|
||||
else -> battleLang("fail.$effectID", pokemonName)
|
||||
}
|
||||
battle.broadcastChatMessage(lang.red())
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-10
@@ -19,18 +19,12 @@ import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleFaintPacket
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |faint|POKEMON
|
||||
*
|
||||
* POKEMON has fainted.
|
||||
* @author Deltric
|
||||
* @since January 22nd, 2022
|
||||
*/
|
||||
class FaintInstruction(battle: PokemonBattle, val message: BattleMessage) : InterpreterInstruction {
|
||||
var waitTime = 2.5F
|
||||
val faintingPokemon = message.battlePokemon(0, battle)!!
|
||||
val faintingPokemon = message.getBattlePokemon(0, battle)!!
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val faintMessage = battleLang("fainted", faintingPokemon.getName()).red()
|
||||
|
||||
battle.dispatchWaiting(waitTime) {
|
||||
val (pnx, _) = message.pnxAndUuid(0) ?: return@dispatchWaiting
|
||||
@@ -45,8 +39,7 @@ class FaintInstruction(battle: PokemonBattle, val message: BattleMessage) : Inte
|
||||
faintingPokemon.contextManager.clear(BattleContext.Type.STATUS, BattleContext.Type.VOLATILE, BattleContext.Type.BOOST, BattleContext.Type.UNBOOST)
|
||||
battle.majorBattleActions[faintingPokemon.uuid] = message
|
||||
}
|
||||
battle.dispatchWaiting(0.5F) {
|
||||
val faintMessage = battleLang("fainted", faintingPokemon.getName()).red()
|
||||
battle.dispatchGo {
|
||||
battle.broadcastChatMessage(faintMessage)
|
||||
}
|
||||
}
|
||||
|
||||
-41
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-fieldactivate|EFFECT
|
||||
*
|
||||
* A miscellaneous EFFECT has activated for the entire field.
|
||||
* @author Segfault Guy
|
||||
* @since April 5th, 2023
|
||||
*/
|
||||
class FieldActivateInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting(2.5F) {
|
||||
val effectID = message.effectAt(0)?.id ?: return@dispatchWaiting
|
||||
val lang = battleLang("fieldactivate.$effectID")
|
||||
battle.broadcastChatMessage(lang.red())
|
||||
|
||||
// share this action with all active Pokemon
|
||||
battle.activePokemon.forEach {
|
||||
it.battlePokemon?.contextManager?.addUnique(ShowdownInterpreter.getContextFromAction(message, BattleContext.Type.VOLATILE, battle))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-fieldend|CONDITION
|
||||
*
|
||||
* The field CONDITION has ended.
|
||||
* @author Licious
|
||||
* @since February 8th, 2023
|
||||
*/
|
||||
class FieldEndInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting(1.5F) {
|
||||
val effect = message.effectAt(0) ?: return@dispatchWaiting
|
||||
val lang = battleLang("fieldend.${effect.id}")
|
||||
battle.broadcastChatMessage(lang)
|
||||
|
||||
val type = BattleContext.Type.valueOf(effect.rawData.substringAfterLast(" ").uppercase())
|
||||
battle.contextManager.remove(effect.id, type)
|
||||
}
|
||||
}
|
||||
}
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import net.minecraft.text.Text
|
||||
|
||||
/**
|
||||
* Format: |-fieldstart|CONDITION
|
||||
*
|
||||
* The field CONDITION has started.
|
||||
* @author Xylopia
|
||||
* @since January 31st, 2023
|
||||
*/
|
||||
class FieldStartInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val effect = message.effectAt(0) ?: return
|
||||
val user = message.battlePokemonFromOptional(battle)
|
||||
user?.let { ShowdownInterpreter.broadcastOptionalAbility(battle, effect, user) }
|
||||
|
||||
battle.dispatchWaiting(1.5F) {
|
||||
// Note persistent is a CAP ability only we can ignore the flag
|
||||
val lang = battleLang("fieldstart.${effect.id}", user?.getName() ?: Text.literal("UNKNOWN"))
|
||||
battle.broadcastChatMessage(lang)
|
||||
|
||||
val type = BattleContext.Type.valueOf(effect.rawData.substringAfterLast(" ").uppercase())
|
||||
battle.contextManager.add(ShowdownInterpreter.getContextFromAction(message, type, battle))
|
||||
}
|
||||
}
|
||||
}
|
||||
-98
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.Effect
|
||||
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.data.ShowdownIdentifiable
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleHealthChangePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattlePersistentStatusPacket
|
||||
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-heal|POKEMON|HP STATUS
|
||||
*
|
||||
* POKEMON has healed damage and is now at HP STATUS.
|
||||
* @author Licious
|
||||
* @since February 6th, 2023
|
||||
*/
|
||||
class HealInstruction(val actor: BattleActor, val publicMessage: BattleMessage, val privateMessage: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val pnx = privateMessage.pnxAndUuid(0)?.first
|
||||
val battlePokemon = privateMessage.battlePokemon(0, battle) ?: return
|
||||
val rawHpAndStatus = privateMessage.argumentAt(1)?.split(" ") ?: return
|
||||
val rawHpRatio = rawHpAndStatus.getOrNull(0) ?: return
|
||||
val newHealth = rawHpRatio.split("/").map { it.toFloatOrNull() ?: return }
|
||||
val newHealthRatio = rawHpRatio.split("/").map { it.toFloatOrNull()?.div(newHealth[1]) ?: return }
|
||||
val effect = privateMessage.effect()
|
||||
ShowdownInterpreter.broadcastOptionalAbility(battle, effect, battlePokemon)
|
||||
|
||||
battle.dispatchWaiting {
|
||||
if (pnx != null) {
|
||||
// dynamax changes max health
|
||||
battle.sendSidedUpdate(actor, BattleHealthChangePacket(pnx, newHealth[0], newHealth[1]), BattleHealthChangePacket(pnx, newHealthRatio[0]))
|
||||
}
|
||||
val silent = privateMessage.hasOptionalArgument("silent")
|
||||
if (!silent) {
|
||||
val lang = when {
|
||||
privateMessage.hasOptionalArgument("zeffect") -> battleLang("heal.zeffect", battlePokemon.getName())
|
||||
privateMessage.hasOptionalArgument("wisher") -> {
|
||||
val name = privateMessage.optionalArgument("wisher")!!
|
||||
val showdownId = name.lowercase().replace(ShowdownIdentifiable.REGEX, "")
|
||||
val wisher = actor.pokemonList.firstOrNull { it.effectedPokemon.showdownId() == showdownId }
|
||||
// If no Pokémon is found this is a nickname
|
||||
battleLang("heal.wish", wisher?.getName() ?: actor.nameOwned(name))
|
||||
}
|
||||
privateMessage.hasOptionalArgument("from") -> {
|
||||
when (effect!!.type) {
|
||||
Effect.Type.ITEM -> when (effect.id) {
|
||||
"leftovers", "shellbell", "blacksludge" -> battleLang("heal.leftovers", battlePokemon.getName(), effect.typelessData)
|
||||
else -> battleLang("heal.item", battlePokemon.getName(), effect.typelessData)
|
||||
}
|
||||
else -> when (effect.id) {
|
||||
"drain" -> {
|
||||
val drained = privateMessage.battlePokemonFromOptional(battle) ?: return@dispatchWaiting
|
||||
battleLang("heal.drain", drained.getName())
|
||||
}
|
||||
else -> battleLang("heal.${effect.id}", battlePokemon.getName())
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
battleLang("heal.generic", battlePokemon.getName())
|
||||
}
|
||||
}
|
||||
battle.broadcastChatMessage(lang)
|
||||
}
|
||||
battle.minorBattleActions[battlePokemon.uuid] = privateMessage
|
||||
battlePokemon.effectedPokemon.currentHealth = newHealth[0].toInt()
|
||||
|
||||
// This part is not always present
|
||||
val rawStatus = rawHpAndStatus.getOrNull(1) ?: return@dispatchWaiting
|
||||
val status = Statuses.getStatus(rawStatus) ?: return@dispatchWaiting
|
||||
if (status is PersistentStatus && battlePokemon.effectedPokemon.status?.status != status) {
|
||||
battlePokemon.effectedPokemon.applyStatus(status)
|
||||
if (pnx != null) {
|
||||
battle.sendUpdate(BattlePersistentStatusPacket(pnx, status))
|
||||
}
|
||||
if (!silent) {
|
||||
status.applyMessage.let { battle.broadcastChatMessage(it.asTranslated(battlePokemon.getName())) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-hitcount|POKEMON|NUM
|
||||
*
|
||||
* A multi-hit move hit the POKEMON NUM times.
|
||||
* @author Licious
|
||||
* @since December 30th, 2022
|
||||
*/
|
||||
class HitCountInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchGo {
|
||||
val battlePokemon = message.battlePokemon(0, battle) ?: return@dispatchGo
|
||||
val hitCount = message.argumentAt(1)?.toIntOrNull() ?: return@dispatchGo
|
||||
val lang = if (hitCount == 1) battleLang("hit_count_singular") else battleLang("hit_count", hitCount)
|
||||
battle.minorBattleActions[battlePokemon.uuid] = message
|
||||
battle.broadcastChatMessage(lang)
|
||||
}
|
||||
}
|
||||
}
|
||||
-6
@@ -11,12 +11,6 @@ package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
|
||||
/**
|
||||
* Catch-all for instruction from Showdown that are not parsed.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 25th, 2023
|
||||
*/
|
||||
class IgnoredInstruction : InterpreterInstruction {
|
||||
override fun invoke(pokemonBattle: PokemonBattle) = Unit
|
||||
}
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-immune|POKEMON
|
||||
*
|
||||
* POKEMON was immune to a move.
|
||||
* @author Hiroku
|
||||
* @since October 3rd, 2022
|
||||
*/
|
||||
class ImmuneInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchWaiting
|
||||
val name = pokemon.getName()
|
||||
battle.broadcastChatMessage(battleLang("immune", name).red())
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BasicContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-invertboost|POKEMON
|
||||
*
|
||||
* POKEMON had its stat changes inverted.
|
||||
* @author JMMCP
|
||||
* @since November 26th, 2023
|
||||
*/
|
||||
class InvertBoostInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchWaiting
|
||||
val name = pokemon.getName()
|
||||
battle.broadcastChatMessage(battleLang("invertboost", name))
|
||||
|
||||
// update and invert BOOST and UNBOOST contexts
|
||||
val context = ShowdownInterpreter.getContextFromAction(message, BattleContext.Type.BOOST, battle)
|
||||
val newUnboosts = pokemon.contextManager.get(BattleContext.Type.BOOST)?.map {
|
||||
BasicContext(it.id, context.turn, BattleContext.Type.UNBOOST, context.origin)
|
||||
}?.toTypedArray()
|
||||
val newBoosts = pokemon.contextManager.get(BattleContext.Type.UNBOOST)?.map {
|
||||
BasicContext(it.id, context.turn, BattleContext.Type.BOOST, context.origin)
|
||||
}?.toTypedArray()
|
||||
|
||||
pokemon.contextManager.clear(BattleContext.Type.BOOST, BattleContext.Type.UNBOOST)
|
||||
newBoosts?.let { pokemon.contextManager.add(*it) }
|
||||
newUnboosts?.let { pokemon.contextManager.add(*it) }
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import net.minecraft.text.Text
|
||||
|
||||
/**
|
||||
* Format: |-item|POKEMON|ITEM|(from)EFFECT
|
||||
*
|
||||
* ITEM held by POKEMON has been changed or revealed due to a move or ability EFFECT.
|
||||
*
|
||||
* Alt format: |-item|POKEMON|ITEM
|
||||
*
|
||||
* POKEMON has just switched in, and its ITEM is being announced to have a long-term effect.
|
||||
* @author Licious
|
||||
* @since December 30th, 2022
|
||||
*/
|
||||
class ItemInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val source = message.battlePokemonFromOptional(battle)
|
||||
source?.let { ShowdownInterpreter.broadcastOptionalAbility(battle, message.effect(), source) }
|
||||
|
||||
battle.dispatchGo {
|
||||
val battlePokemon = message.battlePokemon(0, battle) ?: return@dispatchGo
|
||||
battlePokemon.heldItemManager.handleStartInstruction(battlePokemon, battle, message)
|
||||
battle.minorBattleActions[battlePokemon.uuid] = message
|
||||
battlePokemon.contextManager.add(ShowdownInterpreter.getContextFromAction(message, BattleContext.Type.ITEM, battle))
|
||||
}
|
||||
}
|
||||
}
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.text.yellow
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-mega|POKEMON|MEGASTONE
|
||||
*
|
||||
* POKEMON used item MEGASTONE to Mega Evolve.
|
||||
* @author Segfault Guy
|
||||
* @since September 10th, 2023
|
||||
*/
|
||||
class MegaInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val battlePokemon = message.battlePokemon(0, battle) ?: return
|
||||
battle.dispatchWaiting {
|
||||
val pokemonName = battlePokemon.getName()
|
||||
battle.broadcastChatMessage(battleLang("mega", pokemonName).yellow())
|
||||
battle.minorBattleActions[battlePokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-6
@@ -11,22 +11,22 @@ package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-miss|SOURCE|TARGET
|
||||
* Format:
|
||||
* |-miss|SOURCE|TARGET
|
||||
*
|
||||
* The move used by the SOURCE Pokémon missed (maybe absent) the TARGET Pokémon.
|
||||
* @author Hiroku
|
||||
* @since October 3rd, 2022
|
||||
*/
|
||||
class MissInstruction(val battle: PokemonBattle, val message: BattleMessage): InterpreterInstruction {
|
||||
val target = message.battlePokemon(1, battle)
|
||||
class MissInstruction(val battle: PokemonBattle, val instructionSet: InstructionSet, val message: BattleMessage): InterpreterInstruction {
|
||||
val target = message.getBattlePokemon(1, battle)
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchGo {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchGo
|
||||
val pokemon = message.getBattlePokemon(0, battle) ?: return@dispatchGo
|
||||
battle.broadcastChatMessage(battleLang("missed").red())
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
|
||||
+5
-12
@@ -31,13 +31,6 @@ import com.cobblemon.mod.common.pokemon.evolution.progress.UseMoveEvolutionProgr
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
/**
|
||||
* Format: |move|POKEMON|MOVE|TARGET
|
||||
*
|
||||
* POKEMON has used MOVE at TARGET.
|
||||
* @author Deltric
|
||||
* @since January 22nd, 2022
|
||||
*/
|
||||
class MoveInstruction(
|
||||
val instructionSet: InstructionSet,
|
||||
val message: BattleMessage
|
||||
@@ -53,17 +46,17 @@ class MoveInstruction(
|
||||
var targetPokemon: BattlePokemon? = null
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
userPokemon = message.battlePokemon(0, battle)!!
|
||||
targetPokemon = message.battlePokemon(2, battle)
|
||||
userPokemon = message.getBattlePokemon(0, battle)!!
|
||||
targetPokemon = message.getBattlePokemon(2, battle)
|
||||
val targetPokemon = targetPokemon // So smart non-null casts can happen
|
||||
|
||||
val optionalEffect = message.effect()
|
||||
ShowdownInterpreter.broadcastOptionalAbility(battle, optionalEffect, userPokemon)
|
||||
val pokemonName = userPokemon.getName()
|
||||
ShowdownInterpreter.broadcastOptionalAbility(battle, optionalEffect, pokemonName)
|
||||
|
||||
battle.dispatch { UntilDispatch { instructionSet.getMostRecentInstruction<MoveInstruction>(this)?.future?.isDone != false } }
|
||||
|
||||
battle.dispatch {
|
||||
val pokemonName = userPokemon.getName()
|
||||
ShowdownInterpreter.lastCauser[battle.battleId] = message
|
||||
|
||||
userPokemon.effectedPokemon.let { pokemon ->
|
||||
@@ -110,7 +103,7 @@ class MoveInstruction(
|
||||
}
|
||||
}
|
||||
|
||||
val hurtTargets = subsequentInstructions.filterIsInstance<DamageInstruction>().mapNotNull { it.expectedTarget }
|
||||
val hurtTargets = subsequentInstructions.filterIsInstance<DamageInstruction>().mapNotNull { it.battlePokemon }
|
||||
runtime.environment.getQueryStruct().addFunction("hurt") { params ->
|
||||
if (params.params.size == 0) {
|
||||
return@addFunction DoubleValue(hurtTargets.isNotEmpty())
|
||||
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.GO
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
|
||||
/**
|
||||
* Format: |pp_update|<side_id>: <pokemon_uuid>|...<move_id>: <move_pp>
|
||||
*
|
||||
* @author Licious
|
||||
* @since September 22nd, 2022
|
||||
*/
|
||||
class PpUpdateInstruction( val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatch {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatch GO
|
||||
val moveDatum = message.argumentAt(1)?.split(", ") ?: return@dispatch GO
|
||||
moveDatum.forEach { moveData ->
|
||||
val moveIdAndPp = moveData.split(": ")
|
||||
val moveId = moveIdAndPp[0]
|
||||
val movePp = moveIdAndPp[1]
|
||||
val move = pokemon.effectedPokemon.moveSet.firstOrNull { move -> move.name.equals(moveId, true) } ?: return@dispatch GO
|
||||
move.currentPp = movePp.toInt()
|
||||
}
|
||||
GO
|
||||
}
|
||||
}
|
||||
}
|
||||
-40
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-prepare|ATTACKER|MOVE and |-prepare|ATTACKER|MOVE|DEFENDER
|
||||
*
|
||||
* ATTACKER Pokémon is preparing to use a charge MOVE on DEFENDER or an unknown target.
|
||||
* @author Renaissance
|
||||
* @since March 24th, 2023
|
||||
*/
|
||||
class PrepareInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting(1.5F) {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchWaiting
|
||||
val pokemonName = pokemon.getName()
|
||||
val effectID = message.effectAt(1)?.id ?: return@dispatchWaiting
|
||||
//Prevents spam when the move Role Play is used
|
||||
val lang = when (effectID) {
|
||||
"shadowforce" -> battleLang("prepare.phantomforce", pokemonName) //Phantom Force and Shadow Force share the same text
|
||||
"solarblade" -> battleLang("prepare.solarbeam", pokemonName) //Solar Beam and Solar Blade share the same text
|
||||
else -> battleLang("prepare.$effectID", pokemonName)
|
||||
}
|
||||
battle.broadcastChatMessage(lang)
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-mustrecharge|POKEMON
|
||||
*
|
||||
* POKEMON must spend the turn recharging from a previous move.
|
||||
* @author Hunter
|
||||
* @since September 25th, 2022
|
||||
*/
|
||||
class RechargeInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting(2F){
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchWaiting
|
||||
battle.broadcastChatMessage(battleLang("recharge", pokemon.getName()))
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
-48
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.text.yellow
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleReplacePokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleTransformPokemonPacket
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |replace|POKEMON|DETAILS|HP STATUS
|
||||
*
|
||||
* Illusion has ended for POKEMON. Syntax is the same as [SwitchInstruction].
|
||||
* @author Segfault Guy
|
||||
* @since March 18th, 2024
|
||||
*/
|
||||
class ReplaceInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
|
||||
val (pnx, _) = message.pnxAndUuid(0) ?: return
|
||||
val (actor, activePokemon) = battle.getActorAndActiveSlotFromPNX(pnx)
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return
|
||||
|
||||
battle.dispatchGo {
|
||||
val entity = pokemon.entity
|
||||
entity?.let { it.effects.mockEffect?.end(it) }
|
||||
|
||||
battle.sendSidedUpdate(
|
||||
source = actor,
|
||||
allyPacket = BattleReplacePokemonPacket(pnx, pokemon, true),
|
||||
opponentPacket = BattleReplacePokemonPacket(pnx, pokemon, false)
|
||||
)
|
||||
|
||||
activePokemon.illusion = null
|
||||
//lang done by EndInstruction
|
||||
}
|
||||
}
|
||||
}
|
||||
-57
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
import com.cobblemon.mod.common.battles.BattleRegistry
|
||||
import com.cobblemon.mod.common.battles.ShowdownActionRequest
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleMakeChoicePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleQueueRequestPacket
|
||||
|
||||
/**
|
||||
* Format: |request|REQUEST
|
||||
*
|
||||
* It's time for the actor to make a decision.
|
||||
* @author Deltric
|
||||
* @since January 22nd, 2022
|
||||
*/
|
||||
class RequestInstruction(val battleActor: BattleActor, val message: BattleMessage): InterpreterInstruction {
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.log("Request Instruction")
|
||||
|
||||
if (message.rawMessage.contains("teamPreview")) // TODO probably change when we're allowing team preview
|
||||
return
|
||||
|
||||
// Parse Json message and update state info for actor
|
||||
val request = BattleRegistry.gson.fromJson(message.rawMessage.split("|request|")[1], ShowdownActionRequest::class.java)
|
||||
request.sanitize(battle, battleActor)
|
||||
if (battle.started) {
|
||||
battle.dispatchGo {
|
||||
// This request won't be acted on until the start of next turn
|
||||
battleActor.sendUpdate(BattleQueueRequestPacket(request))
|
||||
battleActor.request = request
|
||||
battleActor.responses.clear()
|
||||
// We need to send this out because 'upkeep' isn't received until the request is handled since the turn won't swap
|
||||
if (request.forceSwitch.contains(true)) {
|
||||
battle.doWhenClear {
|
||||
battleActor.mustChoose = true
|
||||
battleActor.sendUpdate(BattleMakeChoicePacket())
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
battleActor.request = request
|
||||
battleActor.responses.clear()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-setboost|POKEMON|STAT|AMOUNT
|
||||
*
|
||||
* Same as -boost and -unboost, but STAT is set to AMOUNT instead of boosted by AMOUNT.\
|
||||
* @author Renaissance
|
||||
* @since February 16th, 2023
|
||||
*/
|
||||
class SetBoostInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting(1.5F) {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchWaiting
|
||||
val pokemonName = pokemon.getName()
|
||||
val effectID = message.effect()?.id ?: return@dispatchWaiting
|
||||
val lang = battleLang("setboost.$effectID", pokemonName)
|
||||
battle.broadcastChatMessage(lang)
|
||||
pokemon.contextManager.add(ShowdownInterpreter.getContextFromAction(message, BattleContext.Type.BOOST, battle))
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
-45
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleHealthChangePacket
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
/**
|
||||
* Format: |-sethp|POKEMON|HP
|
||||
*
|
||||
* POKEMON now has HP hit points.
|
||||
* @author Licious
|
||||
* @since February 8th, 2023
|
||||
*/
|
||||
class SetHpInstruction(val actor: BattleActor, val publicMessage: BattleMessage, val privateMessage: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting {
|
||||
val (pnx, _) = privateMessage.pnxAndUuid(0) ?: return@dispatchWaiting
|
||||
val flatHp = privateMessage.argumentAt(1)?.split("/")?.getOrNull(0)?.toFloatOrNull() ?: return@dispatchWaiting
|
||||
val ratioHp = publicMessage.argumentAt(1)?.split("/")?.getOrNull(0)?.toFloatOrNull()?.times(0.01F) ?: return@dispatchWaiting
|
||||
val battlePokemon = privateMessage.battlePokemon(0, battle) ?: return@dispatchWaiting
|
||||
battlePokemon.effectedPokemon.currentHealth = flatHp.roundToInt()
|
||||
battle.sendSidedUpdate(actor, BattleHealthChangePacket(pnx, flatHp), BattleHealthChangePacket(pnx, ratioHp))
|
||||
// It doesn't matter which we check when silent both have it
|
||||
if (!publicMessage.hasOptionalArgument("silent")) {
|
||||
val effectID = publicMessage.effect()?.id ?: return@dispatchWaiting
|
||||
val lang = battleLang("sethp.$effectID")
|
||||
battle.broadcastChatMessage(lang)
|
||||
}
|
||||
battle.minorBattleActions[battlePokemon.uuid] = publicMessage
|
||||
}
|
||||
}
|
||||
}
|
||||
-45
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-sideend|SIDE|CONDITION
|
||||
*
|
||||
* Indicates that the side CONDITION ended for the given SIDE.
|
||||
* @author Segfault Guy
|
||||
* @since April 5th, 2023
|
||||
*/
|
||||
class SideEndInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting(2F) {
|
||||
val side = if (message.argumentAt(0)?.get(1) == '1') battle.side1 else battle.side2
|
||||
val effect = message.effectAt(1) ?: return@dispatchWaiting
|
||||
battle.sides.forEach {
|
||||
val subject = if (it == side) battleLang("side_subject.ally") else battleLang("side_subject.opponent")
|
||||
val lang = battleLang("sideend.${effect.id}", subject)
|
||||
it.broadcastChatMessage(lang)
|
||||
}
|
||||
|
||||
val bucket = when(effect.rawData.substringAfterLast(" ").lowercase()) {
|
||||
"reflect", "screen", "veil" -> BattleContext.Type.SCREEN
|
||||
"spikes", "rock", "web" -> BattleContext.Type.HAZARD
|
||||
"tailwind" -> BattleContext.Type.TAILWIND
|
||||
else -> BattleContext.Type.MISC
|
||||
}
|
||||
side.contextManager.remove(effect.id, bucket)
|
||||
}
|
||||
}
|
||||
}
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-sidestart|SIDE|CONDITION
|
||||
*
|
||||
* A side CONDITION has started on SIDE.
|
||||
* @author Segfault Guy
|
||||
* @since April 5th, 2023
|
||||
*/
|
||||
class SideStartInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting(2F) {
|
||||
val side = if (message.argumentAt(0)?.get(1) == '1') battle.side1 else battle.side2
|
||||
val effect = message.effectAt(1) ?: return@dispatchWaiting
|
||||
battle.sides.forEach {
|
||||
val subject = if (it == side) battleLang("side_subject.ally") else battleLang("side_subject.opponent")
|
||||
val lang = battleLang("sidestart.${effect.id}", subject)
|
||||
it.broadcastChatMessage(lang)
|
||||
}
|
||||
|
||||
val bucket = when(effect.rawData.substringAfterLast(" ").lowercase()) {
|
||||
"reflect", "screen", "veil" -> BattleContext.Type.SCREEN
|
||||
"spikes", "rock", "web" -> BattleContext.Type.HAZARD
|
||||
"tailwind" -> BattleContext.Type.TAILWIND
|
||||
else -> BattleContext.Type.MISC
|
||||
}
|
||||
side.contextManager.add(ShowdownInterpreter.getContextFromAction(message, bucket, battle))
|
||||
}
|
||||
}
|
||||
}
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-singlemove|POKEMON|MOVE
|
||||
*
|
||||
* POKEMON used MOVE which causes a temporary effect lasting the duration of the move.
|
||||
* @author Renaissance
|
||||
* @since March 24th, 2023
|
||||
*/
|
||||
class SingleMoveInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting(1.5F) {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchWaiting
|
||||
val pokemonName = pokemon.getName()
|
||||
val effectID = message.effectAt(1)?.id ?: return@dispatchWaiting
|
||||
val lang = battleLang("singlemove.$effectID", pokemonName)
|
||||
battle.broadcastChatMessage(lang)
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
-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.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import net.minecraft.text.Text
|
||||
|
||||
/**
|
||||
* Format: |-singleturn|POKEMON|MOVE
|
||||
*
|
||||
* POKEMON used MOVE which causes a temporary effect lasting the duration of the turn.
|
||||
* @author Renaissance
|
||||
* @since March 24th, 2023
|
||||
*/
|
||||
class SingleTurnInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting(1.5F) {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchWaiting
|
||||
val pokemonName = pokemon.getName()
|
||||
val sourceName = message.battlePokemonFromOptional(battle)?.getName() ?: Text.literal("UNKOWN")
|
||||
val effectID = message.effectAt(1)?.id ?: return@dispatchWaiting
|
||||
val lang = battleLang("singleturn.$effectID", pokemonName, sourceName)
|
||||
battle.broadcastChatMessage(lang)
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
-65
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.text.yellow
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.GO
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import net.minecraft.text.Text
|
||||
|
||||
/**
|
||||
* Format: |-start|POKEMON|EFFECT
|
||||
*
|
||||
* A volatile status has been inflicted on POKEMON by EFFECT.
|
||||
* @author Deltric
|
||||
* @since January 21st, 2022
|
||||
*/
|
||||
class StartInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatch {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatch GO
|
||||
val effectID = message.effectAt(1)?.id ?: return@dispatch GO
|
||||
|
||||
val optionalEffect = message.effect()
|
||||
val optionalPokemon = message.battlePokemonFromOptional(battle)
|
||||
val optionalPokemonName = optionalPokemon?.getName()
|
||||
val extraEffect = message.effectAt(2)?.typelessData ?: Text.literal("UNKOWN")
|
||||
|
||||
// skip adding contexts for every time the perish counter decrements
|
||||
if (!effectID.contains("perish")) {
|
||||
// don't need to add unique: showdown won't send -start instruction if volatile status is already present
|
||||
pokemon.contextManager.add(ShowdownInterpreter.getContextFromAction(message, BattleContext.Type.VOLATILE, battle))
|
||||
}
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
|
||||
if (!message.hasOptionalArgument("silent")) {
|
||||
val lang = if (optionalEffect?.id == "reflecttype" && optionalPokemonName != null)
|
||||
battleLang("start.reflecttype", pokemon.getName(), optionalPokemonName)
|
||||
else
|
||||
when (effectID) {
|
||||
"confusion", "perish3" -> return@dispatch GO // Skip
|
||||
"perish2", "perish1", "perish0",
|
||||
"stockpile1", "stockpile2", "stockpile3" -> battleLang("start.${effectID.dropLast(1)}", pokemon.getName(), effectID.last().digitToInt())
|
||||
"dynamax" -> battleLang("start.${message.effectAt(2)?.id ?: effectID}", pokemon.getName()).yellow()
|
||||
"curse" -> battleLang("start.curse", message.battlePokemonFromOptional(battle)!!.getName(), pokemon.getName())
|
||||
else -> battleLang("start.$effectID", pokemon.getName(), extraEffect)
|
||||
}
|
||||
battle.broadcastChatMessage(lang)
|
||||
}
|
||||
WaitDispatch(1F)
|
||||
}
|
||||
}
|
||||
}
|
||||
-51
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattlePersistentStatusPacket
|
||||
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
|
||||
/**
|
||||
* Format: |-status|POKEMON|STATUS
|
||||
*
|
||||
* POKEMON has been inflicted with STATUS.
|
||||
* @author Hiroku
|
||||
* @since October 3rd, 2022
|
||||
*/
|
||||
class StatusInstruction( val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val (pnx, _) = message.pnxAndUuid(0) ?: return
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return
|
||||
val otherPokemon = message.actorAndActivePokemonFromOptional(battle, "of")?.second?.battlePokemon
|
||||
val statusLabel = message.argumentAt(1) ?: return
|
||||
val status = Statuses.getStatus(statusLabel) ?: return Cobblemon.LOGGER.error("Unrecognized status: $statusLabel")
|
||||
|
||||
ShowdownInterpreter.broadcastOptionalAbility(battle, message.effect(), otherPokemon ?: pokemon)
|
||||
|
||||
battle.dispatchWaiting {
|
||||
if (status is PersistentStatus) {
|
||||
pokemon.effectedPokemon.applyStatus(status)
|
||||
battle.sendUpdate(BattlePersistentStatusPacket(pnx, status))
|
||||
}
|
||||
|
||||
battle.broadcastChatMessage(status.applyMessage.asTranslated(pokemon.getName()))
|
||||
pokemon.contextManager.add(ShowdownInterpreter.getContextFromAction(message, BattleContext.Type.STATUS, battle))
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-supereffective|POKEMON
|
||||
*
|
||||
* A move was super effective against POKEMON.
|
||||
* @author Hunter
|
||||
* @since August 18th, 2022
|
||||
*/
|
||||
class SuperEffectiveInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchGo {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchGo
|
||||
battle.broadcastChatMessage(battleLang("superEffective"))
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-swapboost|SOURCE|TARGET|STATS
|
||||
*
|
||||
* Swaps the boosts from STATS between the SOURCE Pokémon and TARGET Pokémon.
|
||||
* @author Renaissance
|
||||
* @since March 24th, 2023
|
||||
*/
|
||||
class SwapBoostInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting(2F) {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchWaiting
|
||||
val pokemonName = pokemon.getName()
|
||||
val targetPokemon = message.battlePokemon(1, battle) ?: return@dispatchWaiting
|
||||
val targetPokemonName = targetPokemon.getName()
|
||||
val effectID = message.effect()?.id ?: return@dispatchWaiting
|
||||
val lang = when (effectID) {
|
||||
"guardswap", "powerswap", "heartswap" -> battleLang("swapboost.$effectID", pokemonName)
|
||||
else -> battleLang("swapboost.generic", pokemonName, targetPokemonName)
|
||||
}
|
||||
battle.broadcastChatMessage(lang)
|
||||
|
||||
pokemon.contextManager.swap(targetPokemon.contextManager, BattleContext.Type.BOOST)
|
||||
pokemon.contextManager.swap(targetPokemon.contextManager, BattleContext.Type.UNBOOST)
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.BattleSide
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
|
||||
/**
|
||||
* Format: |-swapsideconditions
|
||||
*
|
||||
* Swaps side conditions between sides. Used for Court Change.
|
||||
* @author Segfault Guy
|
||||
* @since February 19th, 2024
|
||||
*/
|
||||
class SwapSideConditionsInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchGo {
|
||||
val sides = mutableListOf<BattleSide>()
|
||||
battle.sides.forEach { side ->
|
||||
if (!sides.contains(side)) {
|
||||
val oppositeManager = side.getOppositeSide().contextManager
|
||||
side.contextManager.swap(oppositeManager, BattleContext.Type.TAILWIND, BattleContext.Type.SCREEN, BattleContext.Type.HAZARD)
|
||||
}
|
||||
sides.add(side)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-156
@@ -1,156 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.EntityBackedBattleActor
|
||||
import com.cobblemon.mod.common.battles.ActiveBattlePokemon
|
||||
import com.cobblemon.mod.common.battles.dispatch.*
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.entity.pokemon.effects.IllusionEffect
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleSwitchPokemonPacket
|
||||
import com.cobblemon.mod.common.util.swap
|
||||
import net.minecraft.entity.LivingEntity
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
/**
|
||||
* Format: |switch|POKEMON|DETAILS|HP STATUS
|
||||
*
|
||||
* POKEMON has switched in (if there was an old Pokémon at that position, it is switched out).
|
||||
* POKEMON|DETAILS represents all the information that can be used to tell Pokémon apart.
|
||||
* The switched Pokémon has HP health points and STATUS status.
|
||||
* @author Deltric
|
||||
* @since January 22nd, 2022
|
||||
*/
|
||||
class SwitchInstruction(val instructionSet: InstructionSet, val battleActor: BattleActor, val publicMessage: BattleMessage, val privateMessage: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
|
||||
val (pnx, _) = publicMessage.pnxAndUuid(0) ?: return
|
||||
val (actor, activePokemon) = battle.getActorAndActiveSlotFromPNX(pnx)
|
||||
val entity = if (actor is EntityBackedBattleActor<*>) actor.entity else null
|
||||
|
||||
val imposter = instructionSet.getNextInstruction<TransformInstruction>(this)?.expectedTarget != null
|
||||
val illusion = publicMessage.battlePokemonFromOptional(battle, "is")
|
||||
val pokemon = publicMessage.battlePokemon(0, battle) ?: return
|
||||
|
||||
if (!battle.started) {
|
||||
activePokemon.battlePokemon = pokemon
|
||||
activePokemon.illusion = illusion
|
||||
val pokemonEntity = pokemon.entity
|
||||
if (pokemonEntity == null && entity != null) {
|
||||
val targetPos = battleActor.getSide().getOppositeSide().actors.filterIsInstance<EntityBackedBattleActor<*>>().firstOrNull()?.entity?.pos?.let { pos ->
|
||||
val offset = pos.subtract(entity.pos)
|
||||
val idealPos = entity.pos.add(offset.multiply(0.33))
|
||||
idealPos
|
||||
} ?: entity.pos
|
||||
|
||||
actor.stillSendingOutCount++
|
||||
pokemon.effectedPokemon.sendOutWithAnimation(
|
||||
source = entity,
|
||||
battleId = battle.battleId,
|
||||
level = entity.world as ServerWorld,
|
||||
doCry = false,
|
||||
position = targetPos,
|
||||
illusion = illusion?.let { IllusionEffect(it.effectedPokemon) }
|
||||
).thenApply {
|
||||
actor.stillSendingOutCount--
|
||||
}
|
||||
}
|
||||
else if (pokemonEntity != null) {
|
||||
illusion?.let { IllusionEffect(it.effectedPokemon).start(pokemonEntity) }
|
||||
}
|
||||
} else {
|
||||
battle.dispatchInsert {
|
||||
pokemon.sendUpdate()
|
||||
|
||||
if (activePokemon.battlePokemon == pokemon) {
|
||||
return@dispatchInsert emptySet() // Already switched in, Showdown does this if the pokemon is going to die before it can switch
|
||||
}
|
||||
|
||||
activePokemon.battlePokemon?.let { oldPokemon ->
|
||||
if (publicMessage.effect()?.id == "batonpass") oldPokemon.contextManager.swap(pokemon.contextManager, BattleContext.Type.BOOST, BattleContext.Type.UNBOOST)
|
||||
oldPokemon.contextManager.clear(BattleContext.Type.VOLATILE, BattleContext.Type.BOOST, BattleContext.Type.UNBOOST)
|
||||
battle.majorBattleActions[oldPokemon.uuid] = publicMessage
|
||||
}
|
||||
battle.majorBattleActions[pokemon.uuid] = publicMessage
|
||||
|
||||
setOf(
|
||||
BattleDispatch {
|
||||
if (entity != null) {
|
||||
createEntitySwitch(battle, actor, entity, pnx, activePokemon, pokemon, illusion, imposter)
|
||||
} else {
|
||||
createNonEntitySwitch(battle, actor, pnx, activePokemon, pokemon, illusion)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object{
|
||||
fun createEntitySwitch(
|
||||
battle: PokemonBattle,
|
||||
actor: BattleActor,
|
||||
entity: LivingEntity,
|
||||
pnx: String,
|
||||
activePokemon: ActiveBattlePokemon,
|
||||
newPokemon: BattlePokemon,
|
||||
illusion: BattlePokemon? = null,
|
||||
imposter: Boolean = false
|
||||
): DispatchResult {
|
||||
val pokemonEntity = activePokemon.battlePokemon?.entity
|
||||
// If we can't find the entity for some reason then we're going to skip the recall animation
|
||||
val sendOutFuture = CompletableFuture<Unit>()
|
||||
// skip if handled by respective EntityEffect
|
||||
val doCry = illusion == null && !imposter
|
||||
(pokemonEntity?.recallWithAnimation() ?: CompletableFuture.completedFuture(Unit)).thenApply {
|
||||
// Queue actual swap and send-in after the animation has ended
|
||||
actor.pokemonList.swap(actor.activePokemon.indexOf(activePokemon), actor.pokemonList.indexOf(newPokemon))
|
||||
activePokemon.battlePokemon = newPokemon
|
||||
activePokemon.illusion = illusion
|
||||
battle.sendSidedUpdate(actor, BattleSwitchPokemonPacket(pnx, newPokemon, true, illusion), BattleSwitchPokemonPacket(pnx, newPokemon, false, illusion))
|
||||
if (newPokemon.entity != null) {
|
||||
illusion?.let { IllusionEffect(it.effectedPokemon).start(newPokemon.entity!!) }
|
||||
if (doCry) newPokemon.entity?.cry()
|
||||
sendOutFuture.complete(Unit)
|
||||
} else {
|
||||
val lastPosition = activePokemon.position
|
||||
// Send out at previous Pokémon's location if it is known, otherwise actor location
|
||||
val world = lastPosition?.first ?: entity.world as ServerWorld
|
||||
val pos = lastPosition?.second ?: entity.pos
|
||||
newPokemon.effectedPokemon.sendOutWithAnimation(
|
||||
source = entity,
|
||||
battleId = battle.battleId,
|
||||
level = world,
|
||||
position = pos,
|
||||
doCry = doCry,
|
||||
illusion = illusion?.let { IllusionEffect(it.effectedPokemon) }
|
||||
).thenAccept { sendOutFuture.complete(Unit) }
|
||||
}
|
||||
}
|
||||
|
||||
return UntilDispatch { sendOutFuture.isDone }
|
||||
}
|
||||
|
||||
fun createNonEntitySwitch(battle: PokemonBattle, actor: BattleActor, pnx: String, activePokemon: ActiveBattlePokemon, newPokemon: BattlePokemon, illusion: BattlePokemon? = null): DispatchResult {
|
||||
actor.pokemonList.swap(actor.activePokemon.indexOf(activePokemon), actor.pokemonList.indexOf(newPokemon))
|
||||
activePokemon.battlePokemon = newPokemon
|
||||
activePokemon.illusion = illusion
|
||||
battle.sendSidedUpdate(actor, BattleSwitchPokemonPacket(pnx, newPokemon, true, illusion), BattleSwitchPokemonPacket(pnx, newPokemon, false, illusion))
|
||||
return WaitDispatch(1.5F)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
-36
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.text.yellow
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-terastallize|POKEMON|TYPE
|
||||
*
|
||||
* POKEMON terastallized into TYPE.
|
||||
* @author Segfault Guy
|
||||
* @since September 10th, 2023
|
||||
*/
|
||||
class TerastallizeInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val battlePokemon = message.battlePokemon(0, battle) ?: return
|
||||
val type = message.effectAt(1)?.let { ElementalTypes.get(it.id) } ?: return
|
||||
battle.dispatchWaiting {
|
||||
val pokemonName = battlePokemon.getName()
|
||||
battle.broadcastChatMessage(battleLang("terastallize", pokemonName, type.displayName).yellow())
|
||||
battle.minorBattleActions[battlePokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
-66
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.GO
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.battles.dispatch.UntilDispatch
|
||||
import com.cobblemon.mod.common.entity.pokemon.effects.TransformEffect
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleTransformPokemonPacket
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-transform|POKEMON|POKEMON
|
||||
*
|
||||
* POKEMON used Transform to turn into target POKEMON.
|
||||
* @author jeffw773
|
||||
* @since November 28th, 2023
|
||||
*/
|
||||
class TransformInstruction(val battle: PokemonBattle, val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
val expectedTarget = message.battlePokemon(0, battle)
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
|
||||
val (pnx, _) = message.pnxAndUuid(0) ?: return
|
||||
val (actor, _) = battle.getActorAndActiveSlotFromPNX(pnx)
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return
|
||||
val targetPokemon = message.battlePokemon(1, battle) ?: return
|
||||
|
||||
val effect = message.effect()
|
||||
ShowdownInterpreter.broadcastOptionalAbility(battle, effect, pokemon)
|
||||
|
||||
battle.dispatch {
|
||||
val entity = pokemon.entity ?: return@dispatch GO
|
||||
val future = TransformEffect(targetPokemon.effectedPokemon, battle.started).start(entity)
|
||||
UntilDispatch { future?.isDone != false }
|
||||
}
|
||||
|
||||
battle.dispatchWaiting {
|
||||
val mock = pokemon.entity?.effects?.mockEffect?.mock
|
||||
val pokemonName = pokemon.getName()
|
||||
val targetPokemonName = targetPokemon.getName()
|
||||
|
||||
mock?.let {
|
||||
battle.sendSidedUpdate(
|
||||
source = actor,
|
||||
allyPacket = BattleTransformPokemonPacket(pnx, pokemon, it, true),
|
||||
opponentPacket = BattleTransformPokemonPacket(pnx, pokemon, it, false)
|
||||
)
|
||||
}
|
||||
|
||||
val lang = battleLang("transform", pokemonName, targetPokemonName)
|
||||
battle.broadcastChatMessage(lang)
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-6
@@ -24,17 +24,13 @@ import com.cobblemon.mod.common.net.messages.client.battle.BattleSetTeamPokemonP
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |turn|NUMBER
|
||||
* Format:
|
||||
* |turn|NUMBER
|
||||
*
|
||||
* It is now turn NUMBER.
|
||||
* @author Deltric
|
||||
* @since January 22nd, 2022
|
||||
*/
|
||||
class TurnInstruction(val message: BattleMessage) : InterpreterInstruction {
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
// TODO maybe tell the client that the turn number has changed
|
||||
val turnNumber = message.argumentAt(0)?.toInt() ?: return
|
||||
|
||||
if (!battle.started) {
|
||||
battle.started = true
|
||||
battle.actors.filterIsInstance<PlayerBattleActor>().forEach { actor ->
|
||||
@@ -58,6 +54,9 @@ class TurnInstruction(val message: BattleMessage) : InterpreterInstruction {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO maybe tell the client that the turn number has changed
|
||||
val turnNumber = message.argumentAt(0)?.toInt() ?: return
|
||||
|
||||
battle.dispatch {
|
||||
battle.sendToActors(BattleMakeChoicePacket())
|
||||
battle.broadcastChatMessage(battleLang("turn", turnNumber).aqua())
|
||||
|
||||
-7
@@ -12,14 +12,7 @@ import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
|
||||
/**
|
||||
* Catch-all for unimplemented instructions that need to be added to the [ShowdownInterpreter].
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 25th, 2023
|
||||
*/
|
||||
class UnknownInstruction(val battleMessage: BattleMessage) : InterpreterInstruction {
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchGo { battle.broadcastChatMessage(battleMessage.rawMessage.red()) }
|
||||
|
||||
+2
-3
@@ -13,11 +13,10 @@ import com.cobblemon.mod.common.battles.dispatch.GO
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
|
||||
/**
|
||||
* Format: |upkeep|
|
||||
* Format:
|
||||
* |upkeep|
|
||||
*
|
||||
* Signals the upkeep phase of the turn where the number of turns left for field conditions are updated.
|
||||
* @author Hiroku
|
||||
* @since March 12th, 2022
|
||||
*/
|
||||
class UpkeepInstruction : InterpreterInstruction {
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
|
||||
-52
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import net.minecraft.text.Text
|
||||
|
||||
/**
|
||||
* Format: |-weather|WEATHER
|
||||
*
|
||||
* Indicates WEATHER is currently in effect.
|
||||
*
|
||||
* If upkeep is present, it means that WEATHER was active previously and is still in effect that turn.
|
||||
* Otherwise, it means that the weather has changed due to a move or ability, or has expired, in which case WEATHER will be none.
|
||||
* @author Hunter
|
||||
* @since September 25th, 2022
|
||||
*/
|
||||
class WeatherInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val weather = message.effectAt(0)?.id ?: return
|
||||
val user = message.battlePokemonFromOptional(battle) ?: return
|
||||
ShowdownInterpreter.broadcastOptionalAbility(battle, message.effect(), user)
|
||||
|
||||
battle.dispatchWaiting(1.5F) {
|
||||
val lang = when {
|
||||
message.hasOptionalArgument("upkeep") -> battleLang("weather.$weather.upkeep")
|
||||
weather != "none" -> {
|
||||
battle.contextManager.add(ShowdownInterpreter.getContextFromAction(message, BattleContext.Type.WEATHER, battle))
|
||||
battleLang("weather.$weather.start")
|
||||
}
|
||||
else -> {
|
||||
val oldWeather = battle.contextManager.get(BattleContext.Type.WEATHER)?.iterator()?.next()?.id ?: return@dispatchWaiting
|
||||
battle.contextManager.clear(BattleContext.Type.WEATHER)
|
||||
battleLang("weather.$oldWeather.end")
|
||||
}
|
||||
}
|
||||
battle.broadcastChatMessage(lang)
|
||||
}
|
||||
}
|
||||
}
|
||||
-74
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.battles.BattleVictoryEvent
|
||||
import com.cobblemon.mod.common.api.text.gold
|
||||
import com.cobblemon.mod.common.api.text.plus
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.actor.PlayerBattleActor
|
||||
import com.cobblemon.mod.common.battles.dispatch.GO
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import java.util.UUID
|
||||
|
||||
/**
|
||||
* Format: |win|USER
|
||||
*
|
||||
* USER has won the battle.
|
||||
* @author Deltric
|
||||
* @since January 22nd, 2022
|
||||
*/
|
||||
class WinInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val user = message.argumentAt(0) ?: return
|
||||
val ids = user.split("&").map { it.trim() }
|
||||
val winners = ids.map { battle.getActor(UUID.fromString(it))!! }
|
||||
val losers = battle.actors.filter { !winners.contains(it) }
|
||||
val winnersText = winners.map { it.getName() }.reduce { acc, next -> acc + " & " + next }
|
||||
val losersText = losers.map { it.getName() }.reduce { acc, next -> acc + " & " + next }
|
||||
val wasCaught = battle. showdownMessages.any { "capture" in it }
|
||||
|
||||
battle.dispatch {
|
||||
// If the battle was a PvW battle, we need to set the killer of the wild Pokémon to the player
|
||||
if (battle.isPvW) {
|
||||
val nonPlayerActor = battle.actors.first { it.type == ActorType.WILD }
|
||||
val wildPokemon: BattlePokemon = nonPlayerActor.pokemonList.first()
|
||||
|
||||
if (!wasCaught && losers.any { it.uuid == wildPokemon.uuid }) {
|
||||
wildPokemon.effectedPokemon.entity?.killer = (battle.actors.firstOrNull { it.type == ActorType.PLAYER } as? PlayerBattleActor)?.entity
|
||||
}
|
||||
}
|
||||
|
||||
// broadcast victory / defeat
|
||||
if (!wasCaught) {
|
||||
val blackedOut = battle.isPvW && losers.any { it is PlayerBattleActor }
|
||||
val lang = if (blackedOut) battleLang("lose", losersText).red() else battleLang("win", winnersText).gold()
|
||||
battle.broadcastChatMessage(lang)
|
||||
return@dispatch WaitDispatch(2F)
|
||||
}
|
||||
else {
|
||||
return@dispatch GO // see BattleCaptureAction
|
||||
}
|
||||
}
|
||||
battle.dispatchGo {
|
||||
battle.end()
|
||||
CobblemonEvents.BATTLE_VICTORY.post(BattleVictoryEvent(battle, winners, losers, wasCaught))
|
||||
ShowdownInterpreter.lastCauser.remove(battle.battleId)
|
||||
}
|
||||
}
|
||||
}
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-zbroken|POKEMON
|
||||
*
|
||||
* A z-move has broken through protect and hit POKEMON.
|
||||
* @author Segfault Guy
|
||||
* @since September 10th, 2023
|
||||
*/
|
||||
class ZBrokenInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val battlePokemon = message.battlePokemon(0, battle) ?: return
|
||||
battle.dispatchWaiting {
|
||||
val pokemonName = battlePokemon.getName()
|
||||
battle.broadcastChatMessage(battleLang("zbroken", pokemonName).red())
|
||||
battle.minorBattleActions[battlePokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.text.yellow
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-zpower|POKEMON
|
||||
*
|
||||
* POKEMON has used the z-move variant of its move.
|
||||
* @author Segfault Guy
|
||||
* @since September 10th, 2023
|
||||
*/
|
||||
class ZPowerInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val battlePokemon = message.battlePokemon(0, battle) ?: return
|
||||
battle.dispatchWaiting {
|
||||
val pokemonName = battlePokemon.getName()
|
||||
battle.broadcastChatMessage(battleLang("zpower", pokemonName).yellow())
|
||||
battle.minorBattleActions[battlePokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,14 +38,6 @@ open class BattlePokemon(
|
||||
effectedPokemon = pokemon.clone(),
|
||||
postBattleEntityOperation = { entity -> entity.discard() }
|
||||
)
|
||||
|
||||
fun playerOwned(pokemon: Pokemon): BattlePokemon = BattlePokemon(
|
||||
originalPokemon = pokemon,
|
||||
effectedPokemon = pokemon,
|
||||
postBattleEntityOperation = { entity ->
|
||||
entity.effects.wipe()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
val uuid: UUID
|
||||
@@ -80,11 +72,10 @@ open class BattlePokemon(
|
||||
val contextManager = ContextManager()
|
||||
|
||||
open fun getName(): MutableText {
|
||||
val displayPokemon = getIllusion()?.effectedPokemon ?: effectedPokemon
|
||||
return if (actor is PokemonBattleActor || actor is MultiPokemonBattleActor) {
|
||||
displayPokemon.getDisplayName()
|
||||
effectedPokemon.getDisplayName()
|
||||
} else {
|
||||
battleLang("owned_pokemon", actor.getName(), displayPokemon.getDisplayName())
|
||||
battleLang("owned_pokemon", actor.getName(), effectedPokemon.getDisplayName())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +94,4 @@ open class BattlePokemon(
|
||||
fun writeVariables(struct: VariableStruct) {
|
||||
effectedPokemon.writeVariables(struct)
|
||||
}
|
||||
|
||||
fun getIllusion(): BattlePokemon? = this.actor.activePokemon.find { it.battlePokemon == this }?.illusion
|
||||
}
|
||||
@@ -17,7 +17,6 @@ import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.item.BlockItem
|
||||
import net.minecraft.item.ItemPlacementContext
|
||||
import net.minecraft.state.StateManager
|
||||
import net.minecraft.state.property.DirectionProperty
|
||||
import net.minecraft.util.ActionResult
|
||||
import net.minecraft.util.Hand
|
||||
import net.minecraft.util.ItemScatterer
|
||||
@@ -33,11 +32,6 @@ class DisplayCaseBlock(settings: Settings) : BlockWithEntity(settings) {
|
||||
init {
|
||||
this.defaultState = this.stateManager.defaultState
|
||||
.with(FACING, Direction.NORTH)
|
||||
.with(ITEM_DIRECTION, Direction.NORTH)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val ITEM_DIRECTION = DirectionProperty.of("item_facing")
|
||||
}
|
||||
|
||||
override fun getPlacementState(ctx: ItemPlacementContext): BlockState? {
|
||||
@@ -46,10 +40,7 @@ class DisplayCaseBlock(settings: Settings) : BlockWithEntity(settings) {
|
||||
val blockPos = ctx.blockPos
|
||||
ctx.placementDirections.forEach { direction ->
|
||||
if (direction.axis.isHorizontal) {
|
||||
blockState = blockState
|
||||
.with(FACING, direction)
|
||||
.with(ITEM_DIRECTION, direction)
|
||||
as BlockState
|
||||
blockState = blockState.with(FACING, direction) as BlockState
|
||||
if (blockState.canPlaceAt(worldView, blockPos)) {
|
||||
return blockState
|
||||
}
|
||||
@@ -60,7 +51,6 @@ class DisplayCaseBlock(settings: Settings) : BlockWithEntity(settings) {
|
||||
|
||||
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
|
||||
builder.add(FACING)
|
||||
builder.add(ITEM_DIRECTION)
|
||||
}
|
||||
|
||||
override fun createBlockEntity(pos: BlockPos, state: BlockState): DisplayCaseBlockEntity {
|
||||
@@ -90,7 +80,7 @@ class DisplayCaseBlock(settings: Settings) : BlockWithEntity(settings) {
|
||||
val entity = world.getBlockEntity(pos) as DisplayCaseBlockEntity
|
||||
val result = entity.updateItem(player, hand)
|
||||
if ((hit.side != Direction.UP && hit.side != Direction.DOWN) && result == ActionResult.SUCCESS) {
|
||||
world.setBlockState(pos, state.with(ITEM_DIRECTION, hit.side.opposite))
|
||||
world.setBlockState(pos, state.with(FACING, hit.side.opposite))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -9,23 +9,15 @@
|
||||
package com.cobblemon.mod.common.block
|
||||
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonBlockTags
|
||||
import com.cobblemon.mod.common.block.chest.GildedChestBlock
|
||||
import net.minecraft.block.*
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.fluid.FluidState
|
||||
import net.minecraft.fluid.Fluids
|
||||
import net.minecraft.item.ItemPlacementContext
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.state.StateManager
|
||||
import net.minecraft.state.property.BooleanProperty
|
||||
import net.minecraft.state.property.Properties
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.math.Direction
|
||||
import net.minecraft.util.math.random.Random
|
||||
import net.minecraft.util.shape.VoxelShape
|
||||
import net.minecraft.world.BlockView
|
||||
import net.minecraft.world.World
|
||||
import net.minecraft.world.WorldAccess
|
||||
import net.minecraft.world.WorldView
|
||||
|
||||
@@ -36,18 +28,7 @@ class TumblestoneBlock(
|
||||
height: Int,
|
||||
xzOffset: Int,
|
||||
nextStage: Block?
|
||||
) : GrowableStoneBlock(settings, stage, height, xzOffset, nextStage), Waterloggable {
|
||||
|
||||
init {
|
||||
this.defaultState = this.stateManager.defaultState
|
||||
.with(FACING, Direction.DOWN)
|
||||
.with(WATERLOGGED, false)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val WATERLOGGED = BooleanProperty.of("waterlogged")
|
||||
}
|
||||
|
||||
) : GrowableStoneBlock(settings, stage, height, xzOffset, nextStage) {
|
||||
override fun canGrow(pos: BlockPos, world: BlockView): Boolean {
|
||||
if (stage == MAX_STAGE) return false
|
||||
val iterator: Iterator<BlockPos> =
|
||||
@@ -62,31 +43,4 @@ class TumblestoneBlock(
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getFluidState(state: BlockState): FluidState {
|
||||
return if (state.get(GildedChestBlock.WATERLOGGED)) {
|
||||
Fluids.WATER.getStill(false)
|
||||
} else super.getFluidState(state)
|
||||
}
|
||||
|
||||
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
|
||||
super.appendProperties(builder)
|
||||
builder.add(GildedChestBlock.WATERLOGGED)
|
||||
}
|
||||
|
||||
override fun getPlacementState(blockPlaceContext: ItemPlacementContext): BlockState? {
|
||||
return super.getPlacementState(blockPlaceContext)?.with(GildedChestBlock.WATERLOGGED, blockPlaceContext.world.getFluidState(blockPlaceContext.blockPos).fluid == Fluids.WATER)
|
||||
|
||||
}
|
||||
|
||||
override fun getStateForNeighborUpdate(
|
||||
state: BlockState,
|
||||
direction: Direction,
|
||||
neighborState: BlockState,
|
||||
world: WorldAccess,
|
||||
pos: BlockPos,
|
||||
neighborPos: BlockPos
|
||||
): BlockState? {
|
||||
if (state.get(GildedChestBlock.WATERLOGGED)) world.scheduleFluidTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world))
|
||||
return super.getStateForNeighborUpdate(state, direction, neighborState, world, pos, neighborPos)
|
||||
}
|
||||
}
|
||||
@@ -16,15 +16,20 @@ import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.party
|
||||
import com.cobblemon.mod.common.util.toVec3d
|
||||
import net.minecraft.block.*
|
||||
import net.minecraft.entity.LivingEntity
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.block.BlockRenderType
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.block.BlockWithEntity
|
||||
import net.minecraft.block.Blocks
|
||||
import net.minecraft.block.HorizontalFacingBlock
|
||||
import net.minecraft.block.ShapeContext
|
||||
import net.minecraft.block.Waterloggable
|
||||
import net.minecraft.entity.ai.pathing.NavigationType
|
||||
import net.minecraft.entity.mob.PiglinBrain
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.fluid.FluidState
|
||||
import net.minecraft.fluid.Fluids
|
||||
import net.minecraft.item.ItemPlacementContext
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.screen.ScreenHandler
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.sound.SoundCategory
|
||||
@@ -33,7 +38,12 @@ import net.minecraft.state.property.BooleanProperty
|
||||
import net.minecraft.state.property.Properties
|
||||
import net.minecraft.text.MutableText
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.*
|
||||
import net.minecraft.util.ActionResult
|
||||
import net.minecraft.util.BlockMirror
|
||||
import net.minecraft.util.BlockRotation
|
||||
import net.minecraft.util.Hand
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.ItemScatterer
|
||||
import net.minecraft.util.hit.BlockHitResult
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.math.Direction
|
||||
@@ -96,7 +106,7 @@ class GildedChestBlock(settings: Settings, val type: Type = Type.RED) : BlockWit
|
||||
neighborPos: BlockPos
|
||||
): BlockState {
|
||||
if (state.get(WATERLOGGED)) world.scheduleFluidTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world))
|
||||
return super.getStateForNeighborUpdate(state, direction, neighborState, world, pos, neighborPos)
|
||||
return super.getStateForNeighborUpdate(state, direction, neighborState, world, pos, neighborPos)
|
||||
}
|
||||
|
||||
override fun getFluidState(state: BlockState): FluidState {
|
||||
@@ -248,17 +258,4 @@ class GildedChestBlock(settings: Settings, val type: Type = Type.RED) : BlockWit
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onPlaced(
|
||||
world: World,
|
||||
pos: BlockPos,
|
||||
state: BlockState,
|
||||
placer: LivingEntity?,
|
||||
itemStack: ItemStack
|
||||
) {
|
||||
val blockEntity = world.getBlockEntity(pos)
|
||||
if (itemStack.hasCustomName() && blockEntity is GildedChestBlockEntity) {
|
||||
blockEntity.customName = itemStack.name
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+3
-2
@@ -92,7 +92,8 @@ class DisplayCaseBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(Cob
|
||||
} else {
|
||||
world!!.playSound(null, pos, CobblemonSounds.DISPLAY_CASE_ADD_ITEM, SoundCategory.BLOCKS)
|
||||
}
|
||||
onItemUpdated(world!!, oldState, world!!.getBlockState(pos))
|
||||
world!!.updateListeners(pos, oldState, world!!.getBlockState(pos), Block.NOTIFY_LISTENERS)
|
||||
world!!.updateComparators(pos, world!!.getBlockState(pos).block)
|
||||
}
|
||||
|
||||
override fun writeNbt(nbt: NbtCompound) {
|
||||
@@ -115,9 +116,9 @@ class DisplayCaseBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(Cob
|
||||
}
|
||||
|
||||
private fun onItemUpdated(world: World, oldState: BlockState, newState: BlockState) {
|
||||
markDirty()
|
||||
world.updateListeners(pos, oldState, newState, Block.NOTIFY_LISTENERS)
|
||||
world.updateComparators(pos, world.getBlockState(pos).block)
|
||||
markDirty()
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
|
||||
+1
-1
@@ -140,7 +140,7 @@ class PokemonPastureBlockEntity(pos: BlockPos, val state: BlockState) : BlockEnt
|
||||
if (fixedPosition != null) {
|
||||
entity.setPosition(fixedPosition.toCenterPos().subtract(0.0, 0.5, 0.0))
|
||||
val pc = Cobblemon.storage.getPC(player.uuid)
|
||||
entity.beamMode = 2
|
||||
entity.beamMode = 1
|
||||
afterOnServer(seconds = SendOutPokemonHandler.SEND_OUT_DURATION) {
|
||||
entity.beamMode = 0
|
||||
}
|
||||
|
||||
+38
-80
@@ -11,9 +11,8 @@ package com.cobblemon.mod.common.client.entity
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.entity.PokemonSideDelegate
|
||||
import com.cobblemon.mod.common.api.events.CobblemonClientEvents
|
||||
import com.cobblemon.mod.common.api.events.client.ClientSendoutEvent
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
@@ -23,11 +22,11 @@ import com.cobblemon.mod.common.api.scheduling.lerpOnClient
|
||||
import com.cobblemon.mod.common.client.particle.BedrockParticleEffectRepository
|
||||
import com.cobblemon.mod.common.client.particle.ParticleStorm
|
||||
import com.cobblemon.mod.common.client.render.MatrixWrapper
|
||||
import com.cobblemon.mod.common.client.render.SnowstormParticle
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityState
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.PrimaryAnimation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.StatefulAnimation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokemonModelRepository
|
||||
import com.cobblemon.mod.common.client.render.pokemon.PokemonRenderer.Companion.ease
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
@@ -35,8 +34,11 @@ import com.cobblemon.mod.common.util.MovingSoundInstance
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import java.lang.Float.min
|
||||
import kotlin.math.abs
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.entity.data.TrackedData
|
||||
import net.minecraft.particle.ParticleTypes
|
||||
import net.minecraft.sound.SoundCategory
|
||||
import net.minecraft.sound.SoundEvent
|
||||
import net.minecraft.util.Hand
|
||||
@@ -88,8 +90,6 @@ class PokemonClientDelegate : PoseableEntityState<PokemonEntity>(), PokemonSideD
|
||||
val identifier = Identifier(currentEntity.dataTracker.get(PokemonEntity.SPECIES))
|
||||
currentPose = null
|
||||
currentEntity.pokemon.species = PokemonSpecies.getByIdentifier(identifier)!! // TODO exception handling
|
||||
// force a model update - handles edge case where the PoseableEntityState's tracked PoseableEntityModel isn't updated until the LivingEntityRenderer render is run
|
||||
currentModel = PokemonModelRepository.getPoser(identifier, currentEntity.aspects)
|
||||
} else if (data == PokemonEntity.DYING_EFFECTS_STARTED) {
|
||||
val isDying = currentEntity.dataTracker.get(PokemonEntity.DYING_EFFECTS_STARTED)
|
||||
if (isDying) {
|
||||
@@ -105,8 +105,6 @@ class PokemonClientDelegate : PoseableEntityState<PokemonEntity>(), PokemonSideD
|
||||
this.addPrimaryAnimation(primaryAnimation)
|
||||
}
|
||||
} else if (data == PokemonEntity.BEAM_MODE) {
|
||||
// If you make adjustments to this code, make sure to Find Usages for both PokemonEntity.beamMode and PokemonEntity.BEAM_MODE
|
||||
// TODO: change beamMode to an enum, or a set of booleans (send-out vs recall, delay vs delay)
|
||||
val beamMode = currentEntity.beamMode
|
||||
when (beamMode) {
|
||||
0 -> { /* Do nothing */ }
|
||||
@@ -136,19 +134,6 @@ class PokemonClientDelegate : PoseableEntityState<PokemonEntity>(), PokemonSideD
|
||||
if(!playedThrowingSound){
|
||||
client.soundManager.play(sound)
|
||||
playedThrowingSound = true
|
||||
sendOutPosition?.let {
|
||||
sendOutOffset?.let { it1 ->
|
||||
ClientSendoutEvent(
|
||||
it1,
|
||||
it,
|
||||
currentEntity
|
||||
)
|
||||
}
|
||||
}?.let {
|
||||
CobblemonClientEvents.CLIENT_SENDOUT.emit(
|
||||
it
|
||||
)
|
||||
}
|
||||
}
|
||||
lerpOnClient(POKEBALL_AIR_TIME) { ballOffset = it }
|
||||
ballRotOffset = ((Math.random()) * currentEntity.world.random.nextBetween(-15, 15)).toFloat()
|
||||
@@ -156,37 +141,39 @@ class PokemonClientDelegate : PoseableEntityState<PokemonEntity>(), PokemonSideD
|
||||
currentEntity.after(seconds = POKEBALL_AIR_TIME){
|
||||
beamStartTime = System.currentTimeMillis()
|
||||
ballDone = true
|
||||
if (client.soundManager.get(CobblemonSounds.POKE_BALL_SEND_OUT.id) != null && !playedSendOutSound) {
|
||||
client.world?.playSound(client.player, soundPos.x, soundPos.y, soundPos.z, SoundEvent.of(CobblemonSounds.POKE_BALL_SEND_OUT.id), SoundCategory.PLAYERS, 0.6f, 1f)
|
||||
playedSendOutSound = true
|
||||
}
|
||||
// Display ball-specific particles
|
||||
sendOutPosition?.let{
|
||||
val newPos = it.add(sendOutOffset)
|
||||
val ballType = currentEntity.pokemon.caughtBall.name.path.lowercase().replace("_","")
|
||||
val mode = if(currentEntity.isBattling) "battle" else "casual"
|
||||
val sendflash = BedrockParticleEffectRepository.getEffect(cobblemonResource("${ballType}/${mode}/sendflash"))
|
||||
sendflash?.let { effect ->
|
||||
val wrapper = MatrixWrapper()
|
||||
val matrix = MatrixStack()
|
||||
matrix.translate(newPos.x, newPos.y, newPos.z)
|
||||
wrapper.updateMatrix(matrix.peek().positionMatrix)
|
||||
val world = MinecraftClient.getInstance().world ?: return@let
|
||||
ParticleStorm(effect, wrapper, world).spawn()
|
||||
val ballsparks = BedrockParticleEffectRepository.getEffect(cobblemonResource("${ballType}/${mode}/ballsparks"))
|
||||
val ballsendsparkle = BedrockParticleEffectRepository.getEffect(cobblemonResource("${ballType}/${mode}/ballsendsparkle"))
|
||||
// using afterOnClient because it's such a small timeframe that it's unlikely the entity has been removed & we'd like the precision
|
||||
afterOnClient(seconds = 0.01667f) {
|
||||
ballsparks?.let { effect ->
|
||||
if (client.soundManager.get(CobblemonSounds.POKE_BALL_OPEN.id) != null && !playedSendOutSound) {
|
||||
currentEntity.owner?.let {
|
||||
client.world?.playSound(client.player, soundPos.x, soundPos.y, soundPos.z, SoundEvent.of(CobblemonSounds.POKE_BALL_SEND_OUT.id), SoundCategory.PLAYERS, 0.6f, 1f)
|
||||
playedSendOutSound = true
|
||||
/// create end rod particles in a 0.1 radius around the soundPos with a count of 50 and a random velocity of 0.1
|
||||
sendOutPosition?.let{
|
||||
val newPos = it.add(sendOutOffset)
|
||||
val ballType = currentEntity.pokemon.caughtBall.name.path.toLowerCase().replace("_","")
|
||||
val mode = if(currentEntity.isBattling) "battle" else "casual"
|
||||
val sendflash = BedrockParticleEffectRepository.getEffect(cobblemonResource("${ballType}/${mode}/sendflash"))
|
||||
sendflash?.let { effect ->
|
||||
val wrapper = MatrixWrapper()
|
||||
val matrix = MatrixStack()
|
||||
matrix.translate(newPos.x, newPos.y, newPos.z)
|
||||
wrapper.updateMatrix(matrix.peek().positionMatrix)
|
||||
val world = MinecraftClient.getInstance().world ?: return@let
|
||||
ParticleStorm(effect, wrapper, world).spawn()
|
||||
}
|
||||
ballsendsparkle?.let { effect ->
|
||||
ParticleStorm(effect, wrapper, world).spawn()
|
||||
}
|
||||
currentEntity.after(seconds = 0.4f) {
|
||||
val ballsparkle = BedrockParticleEffectRepository.getEffect(cobblemonResource("${ballType}/ballsparkle"))
|
||||
ballsparkle?.let { effect ->
|
||||
ParticleStorm(effect, wrapper, world).spawn()
|
||||
val ballsparks = BedrockParticleEffectRepository.getEffect(cobblemonResource("${ballType}/${mode}/ballsparks"))
|
||||
val ballsendsparkle = BedrockParticleEffectRepository.getEffect(cobblemonResource("${ballType}/${mode}/ballsendsparkle"))
|
||||
// using afterOnClient because it's such a small timeframe that it's unlikely the entity has been removed & we'd like the precision
|
||||
afterOnClient(seconds = 0.01667f) {
|
||||
ballsparks?.let { effect ->
|
||||
ParticleStorm(effect, wrapper, world).spawn()
|
||||
}
|
||||
ballsendsparkle?.let { effect ->
|
||||
ParticleStorm(effect, wrapper, world).spawn()
|
||||
}
|
||||
currentEntity.after(seconds = 0.4f) {
|
||||
val ballsparkle = BedrockParticleEffectRepository.getEffect(cobblemonResource("${ballType}/ballsparkle"))
|
||||
ballsparkle?.let { effect ->
|
||||
ParticleStorm(effect, wrapper, world).spawn()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -203,35 +190,7 @@ class PokemonClientDelegate : PoseableEntityState<PokemonEntity>(), PokemonSideD
|
||||
}
|
||||
}
|
||||
}
|
||||
2 -> {
|
||||
// Scaling up with no delay and no particles
|
||||
playedSendOutSound = false
|
||||
entityScaleModifier = 0F
|
||||
currentEntity.isInvisible = false
|
||||
val soundPos = currentEntity.pos
|
||||
val client = MinecraftClient.getInstance()
|
||||
|
||||
if (client.soundManager.get(CobblemonSounds.POKE_BALL_SEND_OUT.id) != null && !playedSendOutSound) {
|
||||
client.world?.playSound(
|
||||
client.player,
|
||||
soundPos.x,
|
||||
soundPos.y,
|
||||
soundPos.z,
|
||||
CobblemonSounds.POKE_BALL_SEND_OUT,
|
||||
SoundCategory.PLAYERS,
|
||||
0.6f,
|
||||
1f
|
||||
)
|
||||
playedSendOutSound = true
|
||||
}
|
||||
lerpOnClient(BEAM_SHRINK_TIME) { entityScaleModifier = it }
|
||||
currentEntity.after(seconds = BEAM_SHRINK_TIME * 2) {
|
||||
ballOffset = 0f
|
||||
ballRotOffset = 0f
|
||||
sendOutPosition = null
|
||||
}
|
||||
}
|
||||
3 -> {
|
||||
else -> {
|
||||
// Scaling down into pokeball
|
||||
entityScaleModifier = 1F
|
||||
beamStartTime = System.currentTimeMillis()
|
||||
@@ -244,7 +203,6 @@ class PokemonClientDelegate : PoseableEntityState<PokemonEntity>(), PokemonSideD
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> { /* Do nothing */ }
|
||||
}
|
||||
} else if (data == PokemonEntity.LABEL_LEVEL) {
|
||||
currentEntity.dataTracker.get(PokemonEntity.LABEL_LEVEL)
|
||||
|
||||
@@ -16,7 +16,6 @@ import com.cobblemon.mod.common.client.gui.battle.subscreen.BattleActionSelectio
|
||||
import com.cobblemon.mod.common.client.gui.battle.subscreen.BattleBackButton
|
||||
import com.cobblemon.mod.common.client.gui.battle.subscreen.BattleGeneralActionSelection
|
||||
import com.cobblemon.mod.common.client.gui.battle.subscreen.BattleSwitchPokemonSelection
|
||||
import com.cobblemon.mod.common.client.gui.battle.subscreen.ForfeitConfirmationSelection
|
||||
import com.cobblemon.mod.common.client.gui.battle.widgets.BattleMessagePane
|
||||
import com.cobblemon.mod.common.client.keybind.boundKey
|
||||
import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding
|
||||
@@ -124,15 +123,6 @@ class BattleGUI : Screen(battleLang("gui.title")) {
|
||||
opacity = 0.75F * opacity,
|
||||
centered = true
|
||||
)
|
||||
} else if (currentSelection is ForfeitConfirmationSelection) {
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = battleLang("ui.forfeit_confirmation", PartySendBinding.boundKey().localizedText),
|
||||
x = MinecraftClient.getInstance().window.scaledWidth / 2,
|
||||
y = (MinecraftClient.getInstance().window.scaledHeight / 5),
|
||||
opacity = 0.75F * opacity,
|
||||
centered = true
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
-5
@@ -66,11 +66,6 @@ class BattleGeneralActionSelection(
|
||||
MinecraftClient.getInstance().player?.sendMessage(battleLang("run_prompt"), false)
|
||||
playDownSound(MinecraftClient.getInstance().soundManager)
|
||||
}
|
||||
} else {
|
||||
addOption(rank++, battleLang("ui.forfeit"), BattleGUI.runResource) {
|
||||
battleGUI.changeActionSelection(ForfeitConfirmationSelection(battleGUI, request))
|
||||
playDownSound(MinecraftClient.getInstance().soundManager)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-65
@@ -1,65 +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.battle.subscreen
|
||||
|
||||
import com.cobblemon.mod.common.battles.ForfeitActionResponse
|
||||
import com.cobblemon.mod.common.client.battle.SingleActionRequest
|
||||
import com.cobblemon.mod.common.client.gui.battle.BattleGUI
|
||||
import com.cobblemon.mod.common.client.gui.battle.BattleOverlay
|
||||
import com.cobblemon.mod.common.client.gui.battle.widgets.BattleOptionTile
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.gui.DrawContext
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
|
||||
class ForfeitConfirmationSelection(
|
||||
battleGUI: BattleGUI,
|
||||
request: SingleActionRequest
|
||||
) : BattleActionSelection(
|
||||
battleGUI,
|
||||
request,
|
||||
x = 12,
|
||||
y = 12,
|
||||
width = 250,
|
||||
height = 100,
|
||||
battleLang("ui.forfeit_confirmation")
|
||||
) {
|
||||
|
||||
val forfeitButton: BattleOptionTile
|
||||
val backButton = BattleBackButton(x - 3F, MinecraftClient.getInstance().window.scaledHeight - 22F )
|
||||
|
||||
init {
|
||||
val x = (MinecraftClient.getInstance().window.scaledWidth / 2) - (BattleOptionTile.OPTION_WIDTH / 2)
|
||||
val y = (MinecraftClient.getInstance().window.scaledHeight / 2) - (BattleOptionTile.OPTION_HEIGHT / 2)
|
||||
|
||||
forfeitButton = BattleOptionTile(battleGUI, x, y, BattleGUI.runResource, battleLang("ui.forfeit")) {
|
||||
battleGUI.selectAction(request, ForfeitActionResponse())
|
||||
playDownSound(MinecraftClient.getInstance().soundManager)
|
||||
}
|
||||
}
|
||||
|
||||
override fun renderButton(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
if (opacity <= 0.05F) {
|
||||
return
|
||||
}
|
||||
forfeitButton.render(context, mouseX, mouseY, delta)
|
||||
backButton.render(context.matrices, mouseX, mouseY, delta)
|
||||
}
|
||||
|
||||
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
|
||||
if (backButton.isHovered(mouseX, mouseY)) {
|
||||
battleGUI.changeActionSelection(null)
|
||||
playDownSound(MinecraftClient.getInstance().soundManager)
|
||||
return true
|
||||
}
|
||||
|
||||
return forfeitButton.mouseClicked(mouseX, mouseY, button)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -279,10 +279,10 @@ class PCGUI(
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = Summary.iconShinyResource,
|
||||
x = (x + 62.5) / SCALE,
|
||||
x = (x + 63.5) / SCALE,
|
||||
y = (y + 28.5) / SCALE,
|
||||
width = 16,
|
||||
height = 16,
|
||||
width = 14,
|
||||
height = 14,
|
||||
scale = SCALE
|
||||
)
|
||||
}
|
||||
|
||||
@@ -524,10 +524,10 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = iconShinyResource,
|
||||
x = (x + 62.5) / SCALE,
|
||||
x = (x + 63.5) / SCALE,
|
||||
y = (y + 33.5) / SCALE,
|
||||
width = 16,
|
||||
height = 16,
|
||||
width = 14,
|
||||
height = 14,
|
||||
scale = SCALE
|
||||
)
|
||||
}
|
||||
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.net.battle
|
||||
|
||||
import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.client.CobblemonClient
|
||||
import com.cobblemon.mod.common.client.battle.ClientBattlePokemon
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleReplacePokemonPacket
|
||||
import net.minecraft.client.MinecraftClient
|
||||
|
||||
/**
|
||||
* The handler for [BattleReplacePokemonPacket]s. Removes the illusion [ClientBattlePokemon] and replaces it with the actual data.
|
||||
*
|
||||
* @author Segfault Guy
|
||||
* @since March 30th, 2024
|
||||
*/
|
||||
object BattleReplacePokemonHandler : ClientNetworkPacketHandler<BattleReplacePokemonPacket> {
|
||||
override fun handle(packet: BattleReplacePokemonPacket, client: MinecraftClient) {
|
||||
val battle = CobblemonClient.battle ?: return
|
||||
val (actor, activeBattlePokemon) = battle.getPokemonFromPNX(packet.pnx)
|
||||
|
||||
with(packet.realPokemon) {
|
||||
activeBattlePokemon.battlePokemon = ClientBattlePokemon(
|
||||
uuid = uuid,
|
||||
displayName = displayName,
|
||||
properties = properties,
|
||||
aspects = aspects,
|
||||
hpValue = hpValue,
|
||||
maxHp = maxHp,
|
||||
isHpFlat = packet.isAlly,
|
||||
status = status,
|
||||
statChanges = statChanges
|
||||
).also {
|
||||
it.actor = actor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-40
@@ -1,40 +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.net.battle
|
||||
|
||||
import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.client.CobblemonClient
|
||||
import com.cobblemon.mod.common.client.battle.ClientBattlePokemon
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleTransformPokemonPacket
|
||||
import net.minecraft.client.MinecraftClient
|
||||
|
||||
/**
|
||||
* The handler for [BattleTransformPokemonPacket]s. Updates the [ClientBattlePokemon] after a transformation.
|
||||
*
|
||||
* @author Segfault Guy
|
||||
* @since April 22nd, 2023
|
||||
*/
|
||||
object BattleTransformPokemonHandler : ClientNetworkPacketHandler<BattleTransformPokemonPacket> {
|
||||
override fun handle(packet: BattleTransformPokemonPacket, client: MinecraftClient) {
|
||||
val battle = CobblemonClient.battle ?: return
|
||||
val (_, activeBattlePokemon) = battle.getPokemonFromPNX(packet.pnx)
|
||||
val update = packet.updatedPokemon
|
||||
|
||||
activeBattlePokemon.battlePokemon?.apply {
|
||||
displayName = update.displayName
|
||||
properties = update.properties
|
||||
aspects = update.aspects
|
||||
hpValue = update.hpValue
|
||||
maxHp = update.maxHp
|
||||
isHpFlat = update.isFlatHp
|
||||
status = update.status
|
||||
statChanges = update.statChanges
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -10,12 +10,12 @@ package com.cobblemon.mod.common.client.render.block
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBlocks
|
||||
import com.cobblemon.mod.common.CobblemonItems
|
||||
import com.cobblemon.mod.common.block.DisplayCaseBlock
|
||||
import com.cobblemon.mod.common.block.entity.DisplayCaseBlockEntity
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokemonModelRepository
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.item.PokeBallItem
|
||||
import com.cobblemon.mod.common.item.PokemonItem
|
||||
import net.minecraft.block.HorizontalFacingBlock
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.render.OverlayTexture
|
||||
import net.minecraft.client.render.VertexConsumer
|
||||
@@ -52,9 +52,9 @@ class DisplayCaseRenderer(ctx: BlockEntityRendererFactory.Context) : BlockEntity
|
||||
val world = entity.world ?: return
|
||||
val posType = getPositioningType(stack, world)
|
||||
val blockState = if (entity.world != null) entity.cachedState
|
||||
else (CobblemonBlocks.DISPLAY_CASE.defaultState.with(DisplayCaseBlock.ITEM_DIRECTION, Direction.NORTH))
|
||||
val yRot = if (posType == PositioningType.ITEM_MODEL) blockState.get(DisplayCaseBlock.ITEM_DIRECTION).opposite.asRotation()
|
||||
else blockState.get(DisplayCaseBlock.ITEM_DIRECTION).asRotation()
|
||||
else (CobblemonBlocks.DISPLAY_CASE.defaultState.with(HorizontalFacingBlock.FACING, Direction.NORTH))
|
||||
val yRot = if (posType == PositioningType.ITEM_MODEL) blockState.get(HorizontalFacingBlock.FACING).opposite.asRotation()
|
||||
else blockState.get(HorizontalFacingBlock.FACING).asRotation()
|
||||
|
||||
if (stack.item is PokemonItem) {
|
||||
renderPokemon(
|
||||
|
||||
+3
-11
@@ -383,7 +383,7 @@ abstract class PoseableEntityModel<T : Entity>(
|
||||
transformedParts,
|
||||
quirks
|
||||
).also {
|
||||
setPose(poseType.name, it)
|
||||
poses[poseType.name] = it
|
||||
}
|
||||
}
|
||||
|
||||
@@ -409,7 +409,7 @@ abstract class PoseableEntityModel<T : Entity>(
|
||||
transformedParts,
|
||||
quirks
|
||||
).also {
|
||||
setPose(poseName, it)
|
||||
poses[poseName] = it
|
||||
}
|
||||
}
|
||||
|
||||
@@ -435,18 +435,10 @@ abstract class PoseableEntityModel<T : Entity>(
|
||||
transformedParts,
|
||||
quirks
|
||||
).also {
|
||||
setPose(poseName, it)
|
||||
poses[poseName] = it
|
||||
}
|
||||
}
|
||||
|
||||
fun <F : ModelFrame> setPose(poseName: String, pose: Pose<T, F>) {
|
||||
// if pose already exists for poseName, log the name of the class and pose name
|
||||
if (poses.containsKey(poseName)) {
|
||||
LOGGER.error("Pose with name $poseName already exists for class ${this::class.simpleName}")
|
||||
}
|
||||
poses[poseName] = pose
|
||||
}
|
||||
|
||||
fun ModelPart.registerChildWithAllChildren(name: String): ModelPart {
|
||||
val child = this.getChild(name)!!
|
||||
registerRelevantPart(name to child)
|
||||
|
||||
+7
-15
@@ -35,29 +35,21 @@ class SingleBoneLookAnimation<T : Entity>(
|
||||
val maxPitch: Float = 70F,
|
||||
val minPitch: Float = 45F,
|
||||
val maxYaw: Float = 45F,
|
||||
val minYaw: Float = -45F,
|
||||
) : StatelessAnimation<T, ModelFrame>(frame) {
|
||||
constructor(
|
||||
frame: HeadedFrame,
|
||||
invertX: Boolean,
|
||||
invertY: Boolean,
|
||||
disableX: Boolean,
|
||||
disableY: Boolean,
|
||||
pitchMultiplier: Float? = null,
|
||||
yawMultiplier: Float? = null,
|
||||
maxPitch: Float? = null,
|
||||
minPitch: Float? = null,
|
||||
maxYaw: Float? = null,
|
||||
minYaw: Float? = null,
|
||||
disableY: Boolean
|
||||
): this(
|
||||
frame = frame,
|
||||
bone = frame.head,
|
||||
pitchMultiplier = pitchMultiplier ?: if (disableX) 0F else if (invertX) -1F else 1F,
|
||||
yawMultiplier = yawMultiplier ?: if (disableY) 0F else if (invertY) -1F else 1F,
|
||||
maxPitch = maxPitch ?: 45F,
|
||||
minPitch = minPitch ?: -70F,
|
||||
maxYaw = maxYaw ?: 45F,
|
||||
minYaw = minYaw ?: -45F,
|
||||
pitchMultiplier = if (disableX) 0F else if (invertX) -1F else 1F,
|
||||
yawMultiplier = if (disableY) 0F else if (invertY) -1F else 1F,
|
||||
maxPitch = if (invertX) -45F else 45F,
|
||||
minPitch = if (invertX) -70F else -45F,
|
||||
maxYaw = if (invertY) -45F else 45F,
|
||||
)
|
||||
|
||||
|
||||
@@ -66,7 +58,7 @@ class SingleBoneLookAnimation<T : Entity>(
|
||||
override fun setAngles(entity: T?, model: PoseableEntityModel<T>, state: PoseableEntityState<T>?, limbSwing: Float, limbSwingAmount: Float, ageInTicks: Float, headYaw: Float, headPitch: Float, intensity: Float) {
|
||||
val head = bone ?: return
|
||||
val pitch = pitchMultiplier * headPitch.coerceIn(minPitch, maxPitch)
|
||||
val yaw = yawMultiplier * headYaw.coerceIn(minYaw, maxYaw)
|
||||
val yaw = yawMultiplier * headYaw.coerceIn(-maxYaw, maxYaw)
|
||||
head.addRotation(X_AXIS, pitch.toRadians() * intensity)
|
||||
head.addRotation(Y_AXIS, yaw.toRadians() * intensity)
|
||||
}
|
||||
|
||||
+1
-1
@@ -15,5 +15,5 @@ import net.minecraft.entity.Entity
|
||||
interface HeadedFrame : ModelFrame {
|
||||
val head: Bone
|
||||
|
||||
fun <T : Entity> singleBoneLook(invertX: Boolean = false, invertY: Boolean = false, disableX: Boolean = false, disableY: Boolean = false, pitchMultiplier: Float? = null, yawMultiplier: Float? = null, maxPitch: Float? = null, minPitch: Float? = null, maxYaw: Float? = null, minYaw: Float? = null) = SingleBoneLookAnimation<T>(this, invertX, invertY, disableX, disableY, pitchMultiplier, yawMultiplier, maxPitch, minPitch, maxYaw, minYaw)
|
||||
fun <T : Entity> singleBoneLook(invertX: Boolean = false, invertY: Boolean = false, disableX: Boolean = false, disableY: Boolean = false) = SingleBoneLookAnimation<T>(this, invertX, invertY, disableX, disableY)
|
||||
}
|
||||
-3
@@ -9,7 +9,6 @@
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
@@ -33,8 +32,6 @@ class AerodactylModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
lateinit var hover: PokemonPose
|
||||
lateinit var fly: PokemonPose
|
||||
|
||||
override val cryAnimation = CryProvider { _, _ -> bedrockStateful("aerodactyl", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("aerodactyl", "blink")}
|
||||
sleep = registerPose(
|
||||
|
||||
+1
-1
@@ -91,7 +91,7 @@ class ArbokModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
quirks = arrayOf(blink),
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("arbok", "summary_idle"),
|
||||
bedrock("arbok", "ground_idle"),
|
||||
wave
|
||||
)
|
||||
)
|
||||
|
||||
+22
-29
@@ -9,7 +9,6 @@
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.QuadrupedWalkAnimation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.QuadrupedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
|
||||
@@ -23,45 +22,39 @@ class ArcanineModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Quad
|
||||
override val rootPart = root.registerChildWithAllChildren("arcanine")
|
||||
override val head = getPart("head")
|
||||
|
||||
override val foreLeftLeg = getPart("left_shoulder")
|
||||
override val foreRightLeg = getPart("right_shoulder")
|
||||
override val hindLeftLeg = getPart("left_thigh")
|
||||
override val hindRightLeg = getPart("right_thigh")
|
||||
override val foreLeftLeg = getPart("leg_front_left")
|
||||
override val foreRightLeg = getPart("leg_front_right")
|
||||
override val hindLeftLeg = getPart("leg_back_left")
|
||||
override val hindRightLeg = getPart("leg_back_right")
|
||||
|
||||
override var portraitScale = 1.37F
|
||||
override var portraitTranslation = Vec3d(-0.58, 1.21, 0.0)
|
||||
override var portraitScale = 1.5F
|
||||
override var portraitTranslation = Vec3d(-0.4, 0.7, 0.0)
|
||||
|
||||
override var profileScale = 0.58F
|
||||
override var profileTranslation = Vec3d(0.14, 0.92, 0.0)
|
||||
override var profileScale = 0.76F
|
||||
override var profileTranslation = Vec3d(0.0, 0.57, 0.0)
|
||||
|
||||
lateinit var standing: PokemonPose
|
||||
lateinit var walk: PokemonPose
|
||||
|
||||
//override val cryAnimation = CryProvider { _, _ -> bedrockStateful("arcanine", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("arcanine", "blink") }
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = STATIONARY_POSES + UI_POSES,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("arcanine", "idle")
|
||||
)
|
||||
poseName = "standing",
|
||||
poseTypes = STATIONARY_POSES + UI_POSES,
|
||||
transformTicks = 10,
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook()
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = MOVING_POSES,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("arcanine", "idle"),
|
||||
QuadrupedWalkAnimation(this)
|
||||
)
|
||||
poseName = "walk",
|
||||
poseTypes = MOVING_POSES,
|
||||
transformTicks = 10,
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
QuadrupedWalkAnimation(this, periodMultiplier = 0.75F, amplitudeMultiplier = 1F)
|
||||
//bedrock("arcanine", "ground_walk")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+1
-13
@@ -35,7 +35,6 @@ class ChanseyModel(root: ModelPart) : PokemonPoseableModel(), BipedFrame {
|
||||
lateinit var standing: PokemonPose
|
||||
lateinit var walk: PokemonPose
|
||||
lateinit var sleep: PokemonPose
|
||||
lateinit var battleIdle: PokemonPose
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("chansey", "blink") }
|
||||
@@ -44,14 +43,13 @@ class ChanseyModel(root: ModelPart) : PokemonPoseableModel(), BipedFrame {
|
||||
poseName = "sleep",
|
||||
poseType = PoseType.SLEEP,
|
||||
idleAnimations = arrayOf(
|
||||
bedrock("chansey", "sleep")
|
||||
bedrock("chansey", "ground_sleep")
|
||||
)
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = STATIONARY_POSES + UI_POSES,
|
||||
condition = { !it.isBattling },
|
||||
transformTicks = 10,
|
||||
idleAnimations = arrayOf(
|
||||
bedrock("chansey", "ground_idle")
|
||||
@@ -67,16 +65,6 @@ class ChanseyModel(root: ModelPart) : PokemonPoseableModel(), BipedFrame {
|
||||
bedrock("chansey", "ground_walk")
|
||||
)
|
||||
)
|
||||
|
||||
battleIdle = registerPose(
|
||||
poseName = "battle_idle",
|
||||
poseTypes = PoseType.STATIONARY_POSES,
|
||||
condition = { it.isBattling },
|
||||
transformTicks = 10,
|
||||
idleAnimations = arrayOf(
|
||||
bedrock("chansey", "battle_idle")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun getFaintAnimation(
|
||||
|
||||
-3
@@ -13,7 +13,6 @@ import com.cobblemon.mod.common.client.render.models.blockbench.frame.BiWingedFr
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.ModelPartTransformation.Companion.Y_AXIS
|
||||
@@ -47,8 +46,6 @@ class CharizardModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Bip
|
||||
lateinit var flyIdle: PokemonPose
|
||||
lateinit var fly: PokemonPose
|
||||
|
||||
override val cryAnimation = CryProvider { _, _ -> bedrockStateful("charizard", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
animations["physical"] = "q.bedrock_primary('charizard', 'physical', 'look', q.curve('symmetrical_wide'))".asExpressionLike()
|
||||
animations["special"] = "q.bedrock_primary('charizard', 'special', 'look', q.curve('symmetrical_wide'))".asExpressionLike()
|
||||
|
||||
-3
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BipedWalkAnimation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
|
||||
@@ -36,8 +35,6 @@ class CuboneModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, BipedF
|
||||
lateinit var standing: PokemonPose
|
||||
lateinit var walk: PokemonPose
|
||||
|
||||
override val cryAnimation = CryProvider { _, _ -> bedrockStateful("cubone", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("cubone", "blink") }
|
||||
|
||||
|
||||
Loaded 100 of 1282 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user