mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-21 14:46:25 -04:00
Compare commits
235
Commits
1.5.0
...
sandbox-stuff
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a0f389c6b | ||
|
|
df8f078d13 | ||
|
|
309b223da9 | ||
|
|
75f688fa30 | ||
|
|
d7fadd58ed | ||
|
|
996c7189b6 | ||
|
|
e1d5f07aed | ||
|
|
6afe77ef0c | ||
|
|
bf54f28b58 | ||
|
|
aac10e967f | ||
|
|
0cd9da80d7 | ||
|
|
d33f1150d2 | ||
|
|
216ed85da1 | ||
|
|
4b70b20ab7 | ||
|
|
125e193b81 | ||
|
|
1ebd249351 | ||
|
|
74727cda48 | ||
|
|
6a8a2489d1 | ||
|
|
3524931596 | ||
|
|
43d9347c9c | ||
|
|
60303504cd | ||
|
|
63db0066d3 | ||
|
|
6e0270ac80 | ||
|
|
333e1fe9ae | ||
|
|
c0c8c103f4 | ||
|
|
a414784cca | ||
|
|
b4b01ef0b6 | ||
|
|
04f725d72e | ||
|
|
0257f591de | ||
|
|
dfeeed8796 | ||
|
|
0e304a81e8 | ||
|
|
03acc21af1 | ||
|
|
2233e6903b | ||
|
|
ac281faa3b | ||
|
|
6891272516 | ||
|
|
eba784071a | ||
|
|
a4435af9c0 | ||
|
|
4b0b0f813e | ||
|
|
c32da0825c | ||
|
|
803703b6a6 | ||
|
|
668914275e | ||
|
|
af90ff6733 | ||
|
|
c657c2ea68 | ||
|
|
2f567830d4 | ||
|
|
569f3c624e | ||
|
|
f30be418f9 | ||
|
|
2c50dc2d0c | ||
|
|
dde2e9f52a | ||
|
|
50a21d91e8 | ||
|
|
58f3de13fa | ||
|
|
8d67a3a909 | ||
|
|
ad4cb8a290 | ||
|
|
d9e5de5f97 | ||
|
|
e4a47af06d | ||
|
|
cc741c0478 | ||
|
|
6887887d6b | ||
|
|
cf1100a20e | ||
|
|
ebc7b97e4f | ||
|
|
d65ce9222a | ||
|
|
706221aead | ||
|
|
26bfca893b | ||
|
|
5f65f3c20c | ||
|
|
1e5239da10 | ||
|
|
7d8ec3470b | ||
|
|
389d2a0adc | ||
|
|
7fa0022095 | ||
|
|
9fde7a7618 | ||
|
|
6c1f7ddd70 | ||
|
|
241b83cec9 | ||
|
|
f0feb81a16 | ||
|
|
00f4052b75 | ||
|
|
407c24b7c5 | ||
|
|
c8904c3e38 | ||
|
|
6bfc711129 | ||
|
|
3d914f47ee | ||
|
|
61891d8fe4 | ||
|
|
1b66ee8ce3 | ||
|
|
5e6091c782 | ||
|
|
5a2e5479e0 | ||
|
|
fc03682140 | ||
|
|
07fbffaa71 | ||
|
|
5e2f5dadb4 | ||
|
|
fc682d1cd1 | ||
|
|
7759c91f3b | ||
|
|
c13654f60c | ||
|
|
289e9df52b | ||
|
|
5dca5a1579 | ||
|
|
3ebad9dc9d | ||
|
|
c93fa02616 | ||
|
|
4e1b82917b | ||
|
|
3b1d257241 | ||
|
|
0b8f916648 | ||
|
|
5897fff954 | ||
|
|
2fd2137d78 | ||
|
|
42c4d6625e | ||
|
|
b0381d1685 | ||
|
|
5ad7d5406a | ||
|
|
3b00043b13 | ||
|
|
2b403df6ef | ||
|
|
f0d5622bab | ||
|
|
ec28ca0c45 | ||
|
|
0d68eedc74 | ||
|
|
6ec008ee83 | ||
|
|
c969e1731b | ||
|
|
bb77c6d4a9 | ||
|
|
5dfc90c0bd | ||
|
|
26a72fe6a9 | ||
|
|
4bb9547822 | ||
|
|
ffe88d75b5 | ||
|
|
d8980fabbe | ||
|
|
7598413e93 | ||
|
|
b0cc4714fc | ||
|
|
5aa3f34880 | ||
|
|
21363405fc | ||
|
|
340be0b2a1 | ||
|
|
933e29b134 | ||
|
|
41b27e5d75 | ||
|
|
e80bf0e331 | ||
|
|
f4d2226ec2 | ||
|
|
0fc5d5e9d7 | ||
|
|
972c0f6430 | ||
|
|
86db95a7dc | ||
|
|
be95b79e4d | ||
|
|
683aa354ed | ||
|
|
aa19ff2c95 | ||
|
|
7d5e790f75 | ||
|
|
5753443ab2 | ||
|
|
c6b7186032 | ||
|
|
32f3be2687 | ||
|
|
9012d78806 | ||
|
|
fffdfb7654 | ||
|
|
76f17c9760 | ||
|
|
b314733f0b | ||
|
|
d5aa07fe91 | ||
|
|
3b0d2cd980 | ||
|
|
27bedc2d2c | ||
|
|
86744c23a5 | ||
|
|
f5a3c93039 | ||
|
|
00dc501df7 | ||
|
|
8d1a64136f | ||
|
|
39fee0bcea | ||
|
|
1162689172 | ||
|
|
bc550dd32c | ||
|
|
b295644070 | ||
|
|
21df0085e2 | ||
|
|
3009af8c42 | ||
|
|
bfd34eb621 | ||
|
|
2dc2c96176 | ||
|
|
df4db17cfd | ||
|
|
08c4f4a0ff | ||
|
|
c4a1704a8b | ||
|
|
45bec488f1 | ||
|
|
9287374504 | ||
|
|
90c5180712 | ||
|
|
51af37b37a | ||
|
|
f2a36cd74a | ||
|
|
158aa05f24 | ||
|
|
8924d0fe0f | ||
|
|
d510eaa462 | ||
|
|
8b63057d9d | ||
|
|
d572b3c505 | ||
|
|
8edc60224a | ||
|
|
a634c4f046 | ||
|
|
7139d4708b | ||
|
|
50e99736a3 | ||
|
|
68c4acf0eb | ||
|
|
5b5e7109f5 | ||
|
|
837aa5acf5 | ||
|
|
37596523db | ||
|
|
eb80c20dbf | ||
|
|
7ab3951613 | ||
|
|
e6d51c4d56 | ||
|
|
3813ec3c92 | ||
|
|
b9364304ca | ||
|
|
9be212d2b8 | ||
|
|
2559257b3a | ||
|
|
8236c6fb11 | ||
|
|
2041d43db4 | ||
|
|
a1687e8304 | ||
|
|
94d92b6fc0 | ||
|
|
3aa95b9339 | ||
|
|
4e97f70801 | ||
|
|
404ca565f5 | ||
|
|
93db0e1cda | ||
|
|
4a4d292228 | ||
|
|
0fef9eec3d | ||
|
|
5f3dc395ec | ||
|
|
1bf9d36dbd | ||
|
|
b19c5ed125 | ||
|
|
e3cca0d9cf | ||
|
|
1aa55f8199 | ||
|
|
4c16b2ce2e | ||
|
|
969d6ac7fc | ||
|
|
920e314444 | ||
|
|
3e4fdc0f22 | ||
|
|
209ac71e06 | ||
|
|
ecfc77f311 | ||
|
|
e64de3aa7d | ||
|
|
46bb9e1aec | ||
|
|
9792ff3392 | ||
|
|
fd7b82dbe3 | ||
|
|
7ef48402fb | ||
|
|
81ac6f3b44 | ||
|
|
978d9e76a1 | ||
|
|
a0b263e392 | ||
|
|
1e067cb7e4 | ||
|
|
2f464f82b1 | ||
|
|
28c0e17a48 | ||
|
|
31136435fe | ||
|
|
bdeb83c62c | ||
|
|
15bf726421 | ||
|
|
7f1889db7b | ||
|
|
548c18bea4 | ||
|
|
d9203bef2a | ||
|
|
5e24799295 | ||
|
|
a7243102d5 | ||
|
|
de6a84a75b | ||
|
|
be3c35eb43 | ||
|
|
b4508bf87e | ||
|
|
dcb4f52cdb | ||
|
|
1e9b390f38 | ||
|
|
7edd47f995 | ||
|
|
dd220c5c85 | ||
|
|
bea84a37d4 | ||
|
|
ac30da3c15 | ||
|
|
3861835d47 | ||
|
|
d62fb5c4c7 | ||
|
|
ca9dde92cd | ||
|
|
6ba264ddcb | ||
|
|
ab6c088ddf | ||
|
|
18105a8b3f | ||
|
|
acb5984a9e | ||
|
|
0a3ba8d4fa | ||
|
|
15259f0a95 | ||
|
|
9f66c053e1 |
@@ -36,6 +36,7 @@ common/src/main/resources/assets/cobblemon/showdown
|
||||
*/generated/resources/*
|
||||
/fabric/src/generated/resources/cobblemon-common.accesswidener
|
||||
/.ignored/
|
||||
common/.fabric
|
||||
|
||||
# MacOS
|
||||
.DS_Store
|
||||
+112
-1
@@ -1,5 +1,116 @@
|
||||
# Changelog
|
||||
## [1.5.0 - The Ruins and Revival Update (May Xth, 2024)](#1-5-0)
|
||||
|
||||
## [1.5.2 (May 27th, 2024)](#1-5-2)
|
||||
### Fixes
|
||||
- Fixed Wooloo and Dubwool dyeing making your game start dying. Only if you do it on a server.
|
||||
- Fixed Gimmighoul causing PCs and parties to look glitched out, also only in a server.
|
||||
- Fixed players being able to dye other people's sheep Pokémon.
|
||||
|
||||
## [1.5.1 (May 27th, 2024)](#1-5-1)
|
||||
|
||||
### Additions
|
||||
- Added unique send out particles for Cherish, Dream, Beast, and Ancient Origin balls.
|
||||
- Made Wooloo and Dubwool dye-able like sheep. So cute!
|
||||
- Added stat up and down particles.
|
||||
- Most status effects now have particles! These include: Paralysis, Poison, Sleep, Confusion, Infatuation.
|
||||
#### Move Particle Effects
|
||||
- Confusion
|
||||
- Cotton Guard
|
||||
- Growl
|
||||
- Ice Punch
|
||||
- Fire Punch
|
||||
- Thunder Punch
|
||||
- Minimize
|
||||
- Quick Attack
|
||||
- Protect
|
||||
- Swords Dance
|
||||
- Sand Attack
|
||||
- Poison Powder
|
||||
- Sleep Powder
|
||||
- Stun Spore
|
||||
- Powder
|
||||
- Rage Powder
|
||||
- Spore
|
||||
- Thunder Wave
|
||||
|
||||
### Changes
|
||||
- Sounds for Relic Coin Sacks have been correctly renamed. Relic Coin Pouches received new sounds for breaking and placing.
|
||||
- Readjusted Petilil portraits so they fit a bit better.
|
||||
- Improved handling of Pokémon taken from the Restoration Tank block to be a bit more stable.
|
||||
- Made Mulch cheaper to craft.
|
||||
|
||||
### Fixes
|
||||
- Fixed a bug in which adding organic material to the restoration tank via right click was adding the full count of the stack currently in hand - but only taking 1 of the item.
|
||||
- Fixed a niche issue where some properties of entities were not initialized correctly, causing Pokémon that appeared to be level 1 until you battle them.
|
||||
- Fixed Fossilized Drake being missing from the Fossils item tag.
|
||||
- Fixed Gilded Chest block entity not being cleared on block break, creating spooky ghost blocks. Old ones can be fixed by placing something like a furnace where it was, then breaking the furnace.
|
||||
- Fixed sherd brokenness on Forge.
|
||||
- Fixed Supplementaries incompatibility.
|
||||
- Fixed Fossil Compartment crash with Jade / WAILA forks.
|
||||
- Fixed pasture block PC lookups when the player is offline.
|
||||
- Fixed an untranslated battle message that occurs when using a move that just ran out of PP (e.g. Fire Blast that just got spited mid-turn).
|
||||
- Fixed held items being eaten even when the held item evolutions are already unlocked.
|
||||
- Fixed Hisuian Decidueye not being Grass/Fighting.
|
||||
- Fixed both Decidueye forms learning both Triple Arrows and Spirit Shackle.
|
||||
- Fixed Pineco being unable to evolve into Shulker Forretress.
|
||||
- Fixed Kabutops T-posing when underwater. It doesn't have proper swimming animations yet, though.
|
||||
- Fixed Pidgey's missing walk animation.
|
||||
- Fixed Cyndaquil's hidden flames clipping if it was swimming.
|
||||
- Fixed Chimecho and Chingling being unable to spawn near bells. They are meant to!
|
||||
- Fixed Tyrantrum and Wailord Party Overlay models peeking through the chat box. It was kinda funny though.
|
||||
- Fixed hitbox sizes for Seedot, Nuzleaf, and Shiftry.
|
||||
- Fixed Budew and Lechonk sliding if they walked for too long.
|
||||
- Fixed Shedinja T-posing in battle.
|
||||
- Fixed recoil evolution condition not working, making things like Basculegion unobtainable.
|
||||
- Fixed issue where poser debug tools didn't work on JSON posers.
|
||||
- Fixed issue where gilded chests don't close when going far away.
|
||||
- Fixed issue where the restoration tank's renderer was reading old data, making it appear wrong.
|
||||
- Fixed issue where the lights on the restoration tank would not animate if it was facing east. Very specific.
|
||||
- Fixed client crash with the fossil machine when updating block state on a chunk that is unloaded in the client. I don't understand this but the devs are sure that all of those are real words.
|
||||
- Fixed Restoration Tank crash with Create upon the tank block's destruction.
|
||||
- Fixed Restoration Tank over consuming items when interacting with Create blocks.
|
||||
- Fixed addons that add very many moves to a learn-set causing disappearing Pokémon (visually) issues on servers.
|
||||
- Fixed Hyper Cutter and Big Pecks incorrectly stating that it prevented accuracy from being lowered in battle.
|
||||
- Fixed missing messages for Rough Skin and Iron Barbs in battle.
|
||||
- Fixed a bug where sometimes Pokémon sendouts wouldn't create an entity, or the entity would spawn at 0 0 0 which is not a good place for a Pokémon to be. Or any of us, really.
|
||||
- Fixed issue in which a locked gilded chest would animate to the open state when the client fails to open it, such as when it is locked.
|
||||
- Fixed a bug where aspects of a form would not be properly reflected on form changes (eg. Normal -> Hisui).
|
||||
- Fixed generic battle effect sounds not sounding the way they were intended to.
|
||||
- Fixed particle effects often not having access to some specific entity functions from MoLang.
|
||||
- Fixed particles sometimes lasting a single tick too long, causing (very quick) visual glitches.
|
||||
- Fixed particle rotations being inverted.
|
||||
- Fixed particle events not spawning at the instigating particle's location.
|
||||
- Fixed a bunch of spam during world generation.
|
||||
- Fixed a bug in which throwing a Poké Ball at a player owned Pokémon with the ability Illusion would reveal its true species. Hilarious meta strategy.
|
||||
- Fixed root-part animations not working for JSON posed Pokémon. You didn't notice this but if we didn't fix this in this update then if you use Quick Attack a lot you'd have seen a whole lot of [this](https://cdn.discordapp.com/attachments/1076993968803434627/1242660506783715369/Minecraft__1.20.1_-_Singleplayer_2024-05-21_22-08-17.mp4?ex=66549408&is=66534288&hm=ff95ee293eb15634fd63e6546534ea279540a1c892605e8d561593ca2c5600c5&) which is damn funny but very unintended.
|
||||
|
||||
### Developer
|
||||
- Changed SpawnAction#complete to return a nullable generic R (the spawn action result) instead of a boolean. Provides more information this way.
|
||||
- Added an event that fires when a fossil is revived, with or without a player.
|
||||
- Added IVS and EVS property extractors.
|
||||
- Fixed PCStore#resize not allowing PC boxes size reduction.
|
||||
|
||||
### Data Pack & Resource Pack Creators
|
||||
- Added support for MoLang conditions for quirks and poses.
|
||||
- Changed the AttackDefenceRatio requirement to StatCompare and StatEqual. There is some backwards compatibility for AttackDefenceRatio, though.
|
||||
- Changed "dimensions" spawn condition to check with dimension IDs instead of effects, so custom dimension IDs can be used.
|
||||
- Added parametric motion and rotation support to particle effects.
|
||||
- Added entity_scale as a molang var for particles (likely only applicable to Pokemon)
|
||||
- Added support for primary quirk animations using the following format:
|
||||
```JSON
|
||||
{
|
||||
"quirks": [
|
||||
"q.bedrock_primary_quirk('<pokemon>', '<animation>', <minSeconds>, <maxSeconds>, <loopTimes>, '<excludedLabels>', q.curve('<waveFunction>'))"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Localization
|
||||
- Updated translations for:
|
||||
- Simplified and Traditional Chinese.
|
||||
- Spanish.
|
||||
|
||||
## [1.5.0 - The Ruins and Revival Update (May 12th, 2024)](#1-5-0)
|
||||
#### "You're telling me that Mojang has added archaeology to the game? Hmm... that gives me an idea."
|
||||
|
||||
### Additions
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import ca.stellardrift.build.configurate.ConfigFormats
|
||||
import ca.stellardrift.build.configurate.catalog.PolyglotVersionCatalogExtension
|
||||
|
||||
plugins {
|
||||
id("ca.stellardrift.polyglot-version-catalogs") version "5.0.1"
|
||||
}
|
||||
|
||||
extensions.configure<PolyglotVersionCatalogExtension> {
|
||||
from(ConfigFormats.YAML, file("../gradle/libs.versions.yml"))
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
plugins {
|
||||
`java-library`
|
||||
}
|
||||
|
||||
tasks {
|
||||
val collectJars by registering(Copy::class) {
|
||||
val tasks = subprojects.filter { it.path != ":common" }.map { it.tasks.named("remapJar") }
|
||||
dependsOn(tasks)
|
||||
|
||||
from(tasks)
|
||||
into(buildDir.resolve("libs"))
|
||||
}
|
||||
|
||||
assemble {
|
||||
dependsOn(collectJars)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<Test> {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
+2
-3
@@ -1,13 +1,12 @@
|
||||
plugins {
|
||||
base
|
||||
id("cobblemon.root-conventions")
|
||||
id ("net.nemerosa.versioning") version "2.8.2"
|
||||
}
|
||||
|
||||
group = "com.cobblemon.mod"
|
||||
version = "${project.property("mod_version")}+${project.property("mc_version")}"
|
||||
|
||||
val isSnapshot = project.property("snapshot")?.equals("true") ?: false
|
||||
if (isSnapshot) {
|
||||
version = "$version-${versioning.info.branch}-${versioning.info.build}"
|
||||
val fixedBranchName = versioning.info.branch.substringAfter("/")
|
||||
version = "$version-${fixedBranchName}-${versioning.info.build}"
|
||||
}
|
||||
|
||||
+18
-24
@@ -1,5 +1,5 @@
|
||||
import extensions.isSnapshot
|
||||
import extensions.version
|
||||
import utilities.isSnapshot
|
||||
import utilities.version
|
||||
import java.time.OffsetDateTime
|
||||
import java.time.ZoneOffset
|
||||
import java.time.format.DateTimeFormatter
|
||||
@@ -20,7 +20,7 @@ plugins {
|
||||
|
||||
id("net.kyori.blossom")
|
||||
id("org.jetbrains.gradle.plugin.idea-ext")
|
||||
id ("net.nemerosa.versioning") version "2.8.2"
|
||||
id("net.nemerosa.versioning") version "2.8.2"
|
||||
}
|
||||
|
||||
architectury {
|
||||
@@ -34,31 +34,26 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.stdlib)
|
||||
implementation(libs.reflect)
|
||||
|
||||
modImplementation(libs.fabricLoader)
|
||||
//Flywheel has no common dep so just pick one and don't use any platform specific code in common
|
||||
// modCompileOnly(libs.flywheelFabric)
|
||||
implementation(libs.bundles.kotlin)
|
||||
modImplementation(libs.fabric.loader)
|
||||
modApi(libs.molang)
|
||||
compileOnlyApi(libs.jeiApi)
|
||||
modCompileOnly(libs.adornFabric)
|
||||
modCompileOnly(libs.lambDynamicLights) { isTransitive = false }
|
||||
|
||||
// For Showdown
|
||||
// Integrations
|
||||
compileOnlyApi(libs.jei.api)
|
||||
modCompileOnly(libs.bundles.fabric.integrations.compileOnly) {
|
||||
isTransitive = false
|
||||
}
|
||||
// Flywheel has no common dep so just pick one and don't use any platform specific code in common
|
||||
// modCompileOnly(libs.flywheelFabric)
|
||||
|
||||
// Showdown
|
||||
modCompileOnly(libs.graal)
|
||||
|
||||
//shadowCommon group: 'commons-io', name: 'commons-io', version: '2.6'
|
||||
// Data Storage
|
||||
modCompileOnly(libs.bundles.mongo)
|
||||
|
||||
// For datastore
|
||||
modCompileOnly(libs.mongoDriverCore)
|
||||
modCompileOnly(libs.mongoDriverSync)
|
||||
|
||||
testImplementation(libs.fabricJunit)
|
||||
testImplementation(libs.junitParams)
|
||||
testImplementation(libs.mockito)
|
||||
testImplementation(libs.mockk)
|
||||
testImplementation(libs.classgraph)
|
||||
// Unit Testing
|
||||
testImplementation(libs.bundles.unitTesting)
|
||||
}
|
||||
|
||||
tasks.withType<Test> {
|
||||
@@ -94,7 +89,6 @@ sourceSets {
|
||||
property("gitCommit", versioning.info.commit)
|
||||
property("branch", versioning.info.branch)
|
||||
System.getProperty("buildNumber")?.let { property("buildNumber", it) }
|
||||
property("timestamp", OffsetDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ofPattern("MM/dd/yyyy hh:mm:ss")) + " UTC")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ public final class CrashReportMixin {
|
||||
cobblemon.add("Is Snapshot", CobblemonBuildDetails.SNAPSHOT);
|
||||
cobblemon.add("Git Commit", CobblemonBuildDetails.INSTANCE.smallCommitHash() + " (" + "https://gitlab.com/cable-mc/cobblemon/-/commit/" + CobblemonBuildDetails.GIT_COMMIT + ")");
|
||||
cobblemon.add("Branch", CobblemonBuildDetails.BRANCH);
|
||||
cobblemon.add("Timestamp", CobblemonBuildDetails.TIMESTAMP);
|
||||
|
||||
cobblemon.addStackTrace(builder);
|
||||
builder.append("\n\n");
|
||||
|
||||
@@ -10,7 +10,6 @@ object CobblemonBuildDetails {
|
||||
|
||||
const val GIT_COMMIT = "{{ gitCommit | default("Not Specified") }}"
|
||||
const val BRANCH = "{{ branch | default("Not Specified") }}"
|
||||
const val TIMESTAMP = "{{ timestamp }}"
|
||||
|
||||
fun smallCommitHash(): String {
|
||||
return this.GIT_COMMIT.substring(0, 7)
|
||||
|
||||
@@ -102,7 +102,6 @@ import com.cobblemon.mod.common.pokemon.properties.HiddenAbilityPropertyType
|
||||
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
|
||||
import com.cobblemon.mod.common.pokemon.properties.tags.PokemonFlagProperty
|
||||
import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
|
||||
import com.cobblemon.mod.common.sherds.CobblemonSherds
|
||||
import com.cobblemon.mod.common.starter.CobblemonStarterHandler
|
||||
import com.cobblemon.mod.common.trade.TradeManager
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
@@ -179,7 +178,6 @@ object Cobblemon {
|
||||
if(CobblemonBuildDetails.SNAPSHOT) {
|
||||
this.LOGGER.info(" - Git Commit: ${smallCommitHash()} (https://gitlab.com/cable-mc/cobblemon/-/commit/${CobblemonBuildDetails.GIT_COMMIT})")
|
||||
this.LOGGER.info(" - Branch: ${CobblemonBuildDetails.BRANCH}")
|
||||
this.LOGGER.info(" - Timestamp: ${CobblemonBuildDetails.TIMESTAMP}")
|
||||
}
|
||||
|
||||
implementation.registerPermissionValidator()
|
||||
@@ -236,7 +234,7 @@ object Cobblemon {
|
||||
val player = event.player
|
||||
val block = player.world.getBlockState(event.pos).block
|
||||
player.party().forEach { pokemon ->
|
||||
pokemon.evolutions
|
||||
pokemon.lockedEvolutions
|
||||
.filterIsInstance<BlockClickEvolution>()
|
||||
.forEach { evolution ->
|
||||
evolution.attemptEvolution(pokemon, BlockClickEvolution.BlockInteractionContext(block, player.world))
|
||||
@@ -417,7 +415,6 @@ object Cobblemon {
|
||||
).ifSuccessful { it.mute = true }
|
||||
}
|
||||
|
||||
CobblemonSherds.registerSherds()
|
||||
}
|
||||
|
||||
fun getLevel(dimension: RegistryKey<World>): World? {
|
||||
|
||||
@@ -234,7 +234,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
"relic_coin_pouch",
|
||||
CoinPouchBlock(
|
||||
AbstractBlock.Settings.create()
|
||||
.sounds(CobblemonSounds.COIN_POUCH_SOUNDS)
|
||||
.sounds(CobblemonSounds.RELIC_COIN_POUCH_SOUNDS)
|
||||
.pistonBehavior(PistonBehavior.DESTROY)
|
||||
.strength(0.4f)
|
||||
.nonOpaque(), true
|
||||
@@ -245,7 +245,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
"relic_coin_sack",
|
||||
CoinPouchBlock(
|
||||
AbstractBlock.Settings.create()
|
||||
.sounds(CobblemonSounds.COIN_POUCH_SOUNDS)
|
||||
.sounds(CobblemonSounds.RELIC_COIN_SACK_SOUNDS)
|
||||
.pistonBehavior(PistonBehavior.DESTROY)
|
||||
.strength(0.4f), false
|
||||
))
|
||||
|
||||
@@ -48,6 +48,7 @@ object CobblemonCommands {
|
||||
PokemonRestartCommand.register(dispatcher)
|
||||
BedrockParticleCommand.register(dispatcher)
|
||||
OpenDialogueCommand.register(dispatcher)
|
||||
ChallengeCommand.register(dispatcher)
|
||||
|
||||
// Possibly lock down registration if and only if under dev environment or running in an environment
|
||||
// with a certain system environment variable set
|
||||
|
||||
@@ -235,6 +235,7 @@ object CobblemonNetwork : NetworkManager {
|
||||
this.createClientBound(TradeableUpdatePacket.ID, TradeableUpdatePacket::decode, PokemonUpdatePacketHandler())
|
||||
this.createClientBound(SpeciesFeatureUpdatePacket.ID, SpeciesFeatureUpdatePacket::decode, PokemonUpdatePacketHandler())
|
||||
this.createClientBound(OriginalTrainerUpdatePacket.ID, OriginalTrainerUpdatePacket::decode, PokemonUpdatePacketHandler())
|
||||
this.createClientBound(FormUpdatePacket.ID, FormUpdatePacket::decode, PokemonUpdatePacketHandler())
|
||||
|
||||
// Evolution start
|
||||
this.createClientBound(AddEvolutionPacket.ID, AddEvolutionPacket::decode, PokemonUpdatePacketHandler())
|
||||
|
||||
@@ -122,13 +122,18 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
|
||||
val FOSSIL_MACHINE_UNPROTECTED = this.create("fossil_machine.unprotected")
|
||||
|
||||
@JvmField
|
||||
val COIN_POUCH_BREAK = this.create("coin_pouch.break")
|
||||
val RELIC_COIN_SACK_BREAK = this.create("relic_coin_sack.break")
|
||||
@JvmField
|
||||
val COIN_POUCH_HIT = this.create("coin_pouch.hit")
|
||||
val RELIC_COIN_SACK_HIT = this.create("relic_coin_sack.hit")
|
||||
@JvmField
|
||||
val COIN_POUCH_STEP = this.create("coin_pouch.step")
|
||||
val RELIC_COIN_SACK_STEP = this.create("relic_coin_sack.step")
|
||||
@JvmField
|
||||
val COIN_POUCH_PLACE = this.create("coin_pouch.place")
|
||||
val RELIC_COIN_SACK_PLACE = this.create("relic_coin_sack.place")
|
||||
@JvmField
|
||||
val RELIC_COIN_POUCH_BREAK = this.create("relic_coin_pouch.break")
|
||||
@JvmField
|
||||
val RELIC_COIN_POUCH_PLACE = this.create("relic_coin_pouch.place")
|
||||
|
||||
@JvmField
|
||||
val TUMBLESTONE_BREAK = this.create("tumblestone.break")
|
||||
@JvmField
|
||||
@@ -189,13 +194,22 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
|
||||
val GILDED_CHEST_PLACE = this.create("gilded_chest.place")
|
||||
|
||||
@JvmField
|
||||
val COIN_POUCH_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
COIN_POUCH_BREAK,
|
||||
COIN_POUCH_STEP,
|
||||
COIN_POUCH_PLACE,
|
||||
COIN_POUCH_HIT,
|
||||
COIN_POUCH_STEP
|
||||
val RELIC_COIN_SACK_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
RELIC_COIN_SACK_BREAK,
|
||||
RELIC_COIN_SACK_STEP,
|
||||
RELIC_COIN_SACK_PLACE,
|
||||
RELIC_COIN_SACK_HIT,
|
||||
RELIC_COIN_SACK_STEP
|
||||
)
|
||||
@JvmField
|
||||
val RELIC_COIN_POUCH_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
RELIC_COIN_POUCH_BREAK,
|
||||
RELIC_COIN_SACK_STEP,
|
||||
RELIC_COIN_POUCH_PLACE,
|
||||
RELIC_COIN_SACK_HIT,
|
||||
RELIC_COIN_SACK_STEP
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val IMPACT_NORMAL = this.create("impact.normal")
|
||||
@JvmField
|
||||
|
||||
@@ -226,7 +226,7 @@ open class PokemonBattle(
|
||||
val facedFainted = opponentPokemon.facedOpponents.contains(faintedPokemon)
|
||||
val pokemon = opponentPokemon.effectedPokemon
|
||||
if (facedFainted) {
|
||||
pokemon.evolutions.forEach { evolution ->
|
||||
pokemon.lockedEvolutions.forEach { evolution ->
|
||||
evolution.requirements.filterIsInstance<DefeatRequirement>().forEach { defeatRequirement ->
|
||||
if (defeatRequirement.target.matches(faintedPokemon.effectedPokemon)) {
|
||||
val progress = pokemon.evolutionProxy.current().progressFirstOrCreate({ it is DefeatEvolutionProgress && it.currentProgress().target == defeatRequirement.target }) { DefeatEvolutionProgress() }
|
||||
|
||||
@@ -78,6 +78,8 @@ object CobblemonEvents {
|
||||
val POKE_BALL_CAPTURE_CALCULATED = EventObservable<PokeBallCaptureCalculatedEvent>()
|
||||
@JvmField
|
||||
val POKEMON_CAPTURED = EventObservable<PokemonCapturedEvent>()
|
||||
@JvmField
|
||||
val FOSSIL_REVIVED = EventObservable<FossilRevivedEvent>()
|
||||
// @JvmField
|
||||
// val EGG_HATCH = EventObservable<HatchEggEvent>()
|
||||
@JvmField
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.events.pokemon
|
||||
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
|
||||
data class FossilRevivedEvent (
|
||||
val pokemon: Pokemon,
|
||||
val player: ServerPlayerEntity?
|
||||
)
|
||||
+4
-2
@@ -10,9 +10,7 @@ package com.cobblemon.mod.common.api.moves.animations
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.struct.VariableStruct
|
||||
import com.cobblemon.mod.common.api.moves.animations.keyframes.ActionEffectKeyframe
|
||||
import com.cobblemon.mod.common.api.scheduling.ScheduledTask
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import java.util.concurrent.CompletableFuture
|
||||
@@ -43,6 +41,9 @@ class ActionEffectTimeline(
|
||||
// .toList copy because I'm paranoid about iterators being trying to share between identical effects playing
|
||||
chainKeyframes(context, timeline.toList().iterator(), finalFuture)
|
||||
finalFuture
|
||||
}.exceptionallyCompose {
|
||||
it.printStackTrace()
|
||||
CompletableFuture.completedFuture(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +56,7 @@ class ActionEffectTimeline(
|
||||
keyframe.play(context)
|
||||
.thenRun { context.currentKeyframes.remove(keyframe) }
|
||||
.thenApply { chainKeyframes(context, iterator, finalFuture) }
|
||||
.exceptionally { finalFuture.completeExceptionally(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -8,7 +8,6 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.EntityProvider
|
||||
@@ -40,7 +39,7 @@ class EntityParticlesActionEffectKeyframe : ConditionalActionEffectKeyframe(), E
|
||||
.flatMap { prov -> prov.entities.filter { test(context, it, isUser = prov is UsersProvider) } }
|
||||
|
||||
val effectIdentifier = try {
|
||||
effect?.asExpressionLike()?.resolveString(context.runtime)
|
||||
effect?.asExpressionLike()?.resolveString(context.runtime)?.takeIf { it != "0.0" } ?: effect
|
||||
} catch (e: Exception) {
|
||||
effect
|
||||
}?.asIdentifierDefaultingNamespace() ?: return skip()
|
||||
|
||||
@@ -60,13 +60,14 @@ abstract class MultiblockBlock(properties: Settings) : BlockWithEntity(propertie
|
||||
}
|
||||
|
||||
override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity?) {
|
||||
super.onBreak(world, pos, state, player)
|
||||
if (!world.isClient) {
|
||||
val entity = world.getBlockEntity(pos)
|
||||
if (entity is MultiblockEntity && entity.multiblockStructure != null) {
|
||||
entity.multiblockStructure!!.onBreak(world, pos, state, player)
|
||||
}
|
||||
entity?.markRemoved()
|
||||
}
|
||||
super.onBreak(world, pos, state, player)
|
||||
}
|
||||
|
||||
override fun createBlockEntity(pos: BlockPos, state: BlockState): BlockEntity? {
|
||||
@@ -78,6 +79,7 @@ abstract class MultiblockBlock(properties: Settings) : BlockWithEntity(propertie
|
||||
return BlockRenderType.MODEL
|
||||
}
|
||||
|
||||
//This is done so a block picked with NBT doesnt absolutely DESTROY multiblocks
|
||||
override fun getPickStack(world: BlockView, pos: BlockPos, state: BlockState): ItemStack {
|
||||
val blockEntity = world.getBlockEntity(pos) as? MultiblockEntity ?: return ItemStack.EMPTY
|
||||
return if (blockEntity.multiblockStructure == null) super.getPickStack(world, pos, state) else ItemStack.EMPTY
|
||||
|
||||
+4
@@ -47,6 +47,10 @@ fun interface PokemonPropertyExtractor {
|
||||
val NICKNAME = add { pokemon, properties -> properties.nickname = pokemon.nickname }
|
||||
@JvmField
|
||||
val STATUS = add { pokemon, properties -> properties.status = pokemon.status?.status?.showdownName }
|
||||
@JvmField
|
||||
val IVS = add { pokemon, properties -> properties.ivs = pokemon.ivs }
|
||||
@JvmField
|
||||
val EVS = add { pokemon, properties -> properties.evs = pokemon.evs }
|
||||
|
||||
@JvmField
|
||||
val ILLUSION = mutableListOf(SPECIES, FORM, ASPECTS, GENDER, NICKNAME, SHINY)
|
||||
|
||||
@@ -153,7 +153,7 @@ interface Evolution : EvolutionLike {
|
||||
pokemon.getOwnerPlayer()?.sendMessage(lang("experience.learned_move", pokemon.getDisplayName(), move.displayName))
|
||||
}
|
||||
// we want to instantly tick for example you might only evolve your Bulbasaur at level 34 so Venusaur should be immediately available
|
||||
pokemon.evolutions.filterIsInstance<PassiveEvolution>().forEach { evolution -> evolution.attemptEvolution(pokemon) }
|
||||
pokemon.lockedEvolutions.filterIsInstance<PassiveEvolution>().forEach { evolution -> evolution.attemptEvolution(pokemon) }
|
||||
pokemon.getOwnerPlayer()?.playSound(CobblemonSounds.EVOLVING, SoundCategory.NEUTRAL, 1F, 1F)
|
||||
CobblemonEvents.EVOLUTION_COMPLETE.post(EvolutionCompleteEvent(pokemon, this))
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ open class Learnset : ClientDataSynchronizer<Learnset> {
|
||||
repeat(times = buffer.readSizedInt(IntSize.U_BYTE)) {
|
||||
val level = buffer.readSizedInt(IntSize.U_SHORT)
|
||||
val moves = mutableListOf<MoveTemplate>()
|
||||
repeat(times = buffer.readSizedInt(IntSize.U_BYTE)) {
|
||||
repeat(times = buffer.readSizedInt(IntSize.U_SHORT)) {
|
||||
Moves.getByNumericalId(buffer.readInt())?.let(moves::add)
|
||||
}
|
||||
levelUpMoves[level] = moves
|
||||
@@ -112,7 +112,7 @@ open class Learnset : ClientDataSynchronizer<Learnset> {
|
||||
buffer.writeSizedInt(IntSize.U_BYTE, levelUpMoves.size)
|
||||
for ((level, moves) in levelUpMoves) {
|
||||
buffer.writeSizedInt(IntSize.U_SHORT, level)
|
||||
buffer.writeSizedInt(IntSize.U_BYTE, moves.size)
|
||||
buffer.writeSizedInt(IntSize.U_SHORT, moves.size)
|
||||
for (move in moves) {
|
||||
buffer.writeInt(move.num)
|
||||
}
|
||||
|
||||
@@ -51,8 +51,8 @@ enum class Stats(override val identifier: Identifier, override val displayName:
|
||||
|
||||
/** Gets the [Stat] from the respective Showdown id. */
|
||||
fun getStat(statKey: String) = when(statKey) {
|
||||
"atk" -> ATTACK
|
||||
"def" -> DEFENCE
|
||||
"atk", "Attack" -> ATTACK // Hyper Cutter states the full stat name "Attack"
|
||||
"def", "Defense" -> DEFENCE // Big Pecks states the full stat name "Defense"
|
||||
"spa" -> SPECIAL_ATTACK
|
||||
"spd" -> SPECIAL_DEFENCE
|
||||
"spe" -> SPEED
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.status
|
||||
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectTimeline
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
@@ -20,4 +23,6 @@ open class Status(
|
||||
val showdownName: String = "",
|
||||
val applyMessage: String,
|
||||
val removeMessage: String
|
||||
)
|
||||
) {
|
||||
fun getActionEffect() = ActionEffects.actionEffects[name]
|
||||
}
|
||||
@@ -9,21 +9,29 @@
|
||||
package com.cobblemon.mod.common.api.pokemon.status
|
||||
|
||||
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.BurnStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.FrozenStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.ParalysisStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonBadlyStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.SleepStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.VolatileStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.BurnStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.FrozenStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.ParalysisStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.PoisonBadlyStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.PoisonStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.SleepStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.nonpersistent.ConfuseStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.nonpersistent.AttractStatus
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* Main API point for Statuses
|
||||
* Get or register Statuses
|
||||
*
|
||||
* NOTE: May seem weird to have so many things called volatile statuses but the package is called nonpersistent.
|
||||
* Its because volatile is a reserved keyword in Java. Cant use it in a package name
|
||||
*
|
||||
* @author Deltric
|
||||
*/
|
||||
object Statuses {
|
||||
private val persistentStatuses = mutableListOf<Status>()
|
||||
private val volatileStatuses = mutableListOf<Status>()
|
||||
private val allStatuses = mutableListOf<Status>()
|
||||
|
||||
val POISON = registerStatus(PoisonStatus())
|
||||
@@ -32,13 +40,23 @@ object Statuses {
|
||||
val SLEEP = registerStatus(SleepStatus())
|
||||
val FROZEN = registerStatus(FrozenStatus())
|
||||
val BURN = registerStatus(BurnStatus())
|
||||
val ATTRACT = registerStatus(AttractStatus())
|
||||
val CONFUSE = registerStatus(ConfuseStatus())
|
||||
|
||||
|
||||
|
||||
fun <T: Status> registerStatus(status: T) : T {
|
||||
if (status is PersistentStatus) {
|
||||
persistentStatuses.add(status)
|
||||
}
|
||||
else if (status is VolatileStatus) {
|
||||
volatileStatuses.add(status)
|
||||
}
|
||||
allStatuses.add(status)
|
||||
return status
|
||||
}
|
||||
|
||||
fun getStatus(name: Identifier) = allStatuses.find { status -> status.name == name }
|
||||
fun getStatus(showdownName: String) = allStatuses.find { it.showdownName == showdownName }
|
||||
fun getPersistentStatuses() = allStatuses.filterIsInstance<PersistentStatus>()
|
||||
fun getPersistentStatuses() = persistentStatuses
|
||||
}
|
||||
@@ -79,15 +79,15 @@ class ParticleEvent(
|
||||
particleEffect?.let { effect ->
|
||||
val bedrockParticleEffect = BedrockParticleEffectRepository.getEffect(effect.effect) ?: return@let
|
||||
val rootMatrix = when (effect.type) {
|
||||
EventParticleEffect.EventParticleType.EMITTER -> MatrixWrapper().updatePosition(storm.matrixWrapper.getOrigin())
|
||||
EventParticleEffect.EventParticleType.EMITTER_BOUND -> storm.matrixWrapper
|
||||
EventParticleEffect.EventParticleType.EMITTER,// -> MatrixWrapper().updatePosition(storm.matrixWrapper.getOrigin())
|
||||
EventParticleEffect.EventParticleType.EMITTER_BOUND,// -> storm.matrixWrapper
|
||||
EventParticleEffect.EventParticleType.PARTICLE,
|
||||
EventParticleEffect.EventParticleType.PARTICLE_WITH_VELOCITY -> (particle?.let { Vec3d(it.getX(), it.getY(), it.getZ()) } ?: Vec3d(storm.getX(), storm.getY(), storm.getZ())).let { MatrixWrapper().updatePosition(it) }
|
||||
}
|
||||
|
||||
val sourceVelocity = when (effect.type) {
|
||||
EventParticleEffect.EventParticleType.EMITTER -> storm.sourceVelocity().let { { it } }
|
||||
EventParticleEffect.EventParticleType.EMITTER_BOUND -> storm.sourceVelocity
|
||||
EventParticleEffect.EventParticleType.EMITTER,// -> storm.sourceVelocity().let { { it } }
|
||||
EventParticleEffect.EventParticleType.EMITTER_BOUND,// -> storm.sourceVelocity
|
||||
EventParticleEffect.EventParticleType.PARTICLE -> { { Vec3d.ZERO } }
|
||||
EventParticleEffect.EventParticleType.PARTICLE_WITH_VELOCITY -> (particle?.let { Vec3d(it.getVelocityX(), it.getVelocityY(), it.getVelocityZ()) } ?: Vec3d.ZERO).let { { it } }
|
||||
}
|
||||
|
||||
@@ -15,10 +15,12 @@ import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.codec.CodecMapped
|
||||
import com.cobblemon.mod.common.api.data.ArbitrarilyMappedSerializableCompanion
|
||||
import com.cobblemon.mod.common.client.particle.ParticleStorm
|
||||
import com.cobblemon.mod.common.client.render.SnowstormParticle
|
||||
import com.cobblemon.mod.common.util.codec.EXPRESSION_CODEC
|
||||
import com.cobblemon.mod.common.util.getString
|
||||
import com.cobblemon.mod.common.util.math.geometry.transformDirection
|
||||
import com.cobblemon.mod.common.util.resolveDouble
|
||||
import com.cobblemon.mod.common.util.resolveVec3d
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.DynamicOps
|
||||
import com.mojang.serialization.codecs.PrimitiveCodec
|
||||
@@ -35,20 +37,79 @@ interface ParticleMotion : CodecMapped {
|
||||
init {
|
||||
registerSubtype(ParticleMotionType.DYNAMIC, DynamicParticleMotion::class.java, DynamicParticleMotion.CODEC)
|
||||
registerSubtype(ParticleMotionType.STATIC, StaticParticleMotion::class.java, StaticParticleMotion.CODEC)
|
||||
registerSubtype(ParticleMotionType.PARAMETRIC, ParametricParticleMotion::class.java, ParametricParticleMotion.CODEC)
|
||||
}
|
||||
}
|
||||
|
||||
val type: ParticleMotionType
|
||||
fun getInitialVelocity(runtime: MoLangRuntime, storm: ParticleStorm, particlePos: Vec3d, emitterPos: Vec3d): Vec3d
|
||||
fun getAcceleration(runtime: MoLangRuntime, velocity: Vec3d): Vec3d
|
||||
fun getVelocity(runtime: MoLangRuntime, particle: SnowstormParticle, velocity: Vec3d): Vec3d
|
||||
fun getParticleDirection(runtime: MoLangRuntime, storm: ParticleStorm, velocity: Vec3d, minSpeed: Float): Vec3d
|
||||
}
|
||||
|
||||
enum class ParticleMotionType {
|
||||
DYNAMIC,
|
||||
PARAMETRIC, // TODO figure out how that even works
|
||||
PARAMETRIC,
|
||||
STATIC
|
||||
}
|
||||
|
||||
class ParametricParticleMotion(
|
||||
var offset: Triple<Expression, Expression, Expression> = Triple(
|
||||
NumberExpression(0.0),
|
||||
NumberExpression(0.0),
|
||||
NumberExpression(0.0)
|
||||
),
|
||||
var direction: Triple<Expression, Expression, Expression> = Triple(
|
||||
NumberExpression(0.0),
|
||||
NumberExpression(0.0),
|
||||
NumberExpression(0.0)
|
||||
)
|
||||
) : ParticleMotion {
|
||||
companion object {
|
||||
val CODEC: Codec<ParametricParticleMotion> = RecordCodecBuilder.create { instance ->
|
||||
instance.group(
|
||||
PrimitiveCodec.STRING.fieldOf("type").forGetter { it.type.name },
|
||||
EXPRESSION_CODEC.listOf().fieldOf("offset").forGetter { listOf(it.offset.first, it.offset.second, it.offset.third) },
|
||||
EXPRESSION_CODEC.listOf().fieldOf("direction").forGetter { listOf(it.direction.first, it.direction.second, it.direction.third) }
|
||||
).apply(instance) { _, offset, direction -> ParametricParticleMotion(Triple(offset[0], offset[1], offset[2]), Triple(direction[0], direction[1], direction[2])) }
|
||||
}
|
||||
}
|
||||
|
||||
override val type = ParticleMotionType.PARAMETRIC
|
||||
|
||||
override fun getInitialVelocity(runtime: MoLangRuntime, storm: ParticleStorm, particlePos: Vec3d, emitterPos: Vec3d) = Vec3d.ZERO
|
||||
override fun getVelocity(runtime: MoLangRuntime, particle: SnowstormParticle, velocity: Vec3d): Vec3d {
|
||||
val stormPosition = Vec3d(particle.storm.getX(), particle.storm.getY(), particle.storm.getZ())
|
||||
val offset = runtime.resolveVec3d(this.offset)
|
||||
val particlePosition = Vec3d(particle.getX(), particle.getY(), particle.getZ())
|
||||
val desiredPosition = stormPosition.add(offset)
|
||||
return desiredPosition.subtract(particlePosition)
|
||||
}
|
||||
|
||||
override fun getParticleDirection(runtime: MoLangRuntime, storm: ParticleStorm, velocity: Vec3d, minSpeed: Float) = runtime.resolveVec3d(direction).normalize()
|
||||
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
||||
override fun readFromBuffer(buffer: PacketByteBuf) {
|
||||
offset = Triple(
|
||||
MoLang.createParser(buffer.readString()).parseExpression(),
|
||||
MoLang.createParser(buffer.readString()).parseExpression(),
|
||||
MoLang.createParser(buffer.readString()).parseExpression()
|
||||
)
|
||||
direction = Triple(
|
||||
MoLang.createParser(buffer.readString()).parseExpression(),
|
||||
MoLang.createParser(buffer.readString()).parseExpression(),
|
||||
MoLang.createParser(buffer.readString()).parseExpression()
|
||||
)
|
||||
}
|
||||
override fun writeToBuffer(buffer: PacketByteBuf) {
|
||||
buffer.writeString(offset.first.getString())
|
||||
buffer.writeString(offset.second.getString())
|
||||
buffer.writeString(offset.third.getString())
|
||||
buffer.writeString(direction.first.getString())
|
||||
buffer.writeString(direction.second.getString())
|
||||
buffer.writeString(direction.third.getString())
|
||||
}
|
||||
}
|
||||
|
||||
class DynamicParticleMotion(
|
||||
var direction: ParticleMotionDirection = InwardsMotionDirection(),
|
||||
var speed: Expression = NumberExpression(0.0),
|
||||
@@ -79,14 +140,23 @@ class DynamicParticleMotion(
|
||||
return direction.getDirectionVector(runtime, storm, emitterPos, particlePos).normalize().multiply(runtime.resolveDouble(speed))
|
||||
}
|
||||
|
||||
override fun getAcceleration(runtime: MoLangRuntime, velocity: Vec3d): Vec3d {
|
||||
return Vec3d(
|
||||
override fun getVelocity(runtime: MoLangRuntime, particle: SnowstormParticle, velocity: Vec3d): Vec3d {
|
||||
val acceleration = Vec3d(
|
||||
runtime.resolveDouble(acceleration.first),
|
||||
runtime.resolveDouble(acceleration.second),
|
||||
runtime.resolveDouble(acceleration.third)
|
||||
).subtract(velocity.multiply(runtime.resolveDouble(drag)))
|
||||
)
|
||||
.subtract(velocity.multiply(20 * runtime.resolveDouble(drag)))
|
||||
.multiply(1 / 20.0).multiply(1 / 20.0) // blocks per second per second -> blocks per tick per tick
|
||||
|
||||
return Vec3d(
|
||||
velocity.x + acceleration.x,
|
||||
velocity.y + acceleration.y,
|
||||
velocity.z + acceleration.z
|
||||
)
|
||||
}
|
||||
|
||||
override fun getParticleDirection(runtime: MoLangRuntime, storm: ParticleStorm, velocity: Vec3d, minSpeed: Float) = velocity.normalize()
|
||||
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
||||
|
||||
override fun readFromBuffer(buffer: PacketByteBuf) {
|
||||
@@ -234,7 +304,8 @@ class StaticParticleMotion : ParticleMotion {
|
||||
override val type = ParticleMotionType.STATIC
|
||||
|
||||
override fun getInitialVelocity(runtime: MoLangRuntime, storm: ParticleStorm, particlePos: Vec3d, emitterPos: Vec3d) = Vec3d.ZERO
|
||||
override fun getAcceleration(runtime: MoLangRuntime, velocity: Vec3d) = Vec3d.ZERO
|
||||
override fun getVelocity(runtime: MoLangRuntime, particle: SnowstormParticle, velocity: Vec3d) = velocity
|
||||
override fun getParticleDirection(runtime: MoLangRuntime, storm: ParticleStorm, velocity: Vec3d, minSpeed: Float) = velocity.normalize()
|
||||
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
||||
override fun readFromBuffer(buffer: PacketByteBuf) {}
|
||||
override fun writeToBuffer(buffer: PacketByteBuf) {}
|
||||
|
||||
@@ -32,6 +32,7 @@ interface ParticleRotation : CodecMapped {
|
||||
) {
|
||||
init {
|
||||
registerSubtype(ParticleRotationType.DYNAMIC, DynamicParticleRotation::class.java, DynamicParticleRotation.CODEC)
|
||||
registerSubtype(ParticleRotationType.PARAMETRIC, ParametricParticleRotation::class.java, ParametricParticleRotation.CODEC)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +40,34 @@ interface ParticleRotation : CodecMapped {
|
||||
|
||||
fun getInitialRotation(runtime: MoLangRuntime): Double
|
||||
fun getInitialAngularVelocity(runtime: MoLangRuntime): Double
|
||||
fun getAngularAcceleration(runtime: MoLangRuntime, angularVelocity: Double): Double
|
||||
fun getAngularVelocity(runtime: MoLangRuntime, angle: Double, angularVelocity: Double): Double
|
||||
}
|
||||
|
||||
class ParametricParticleRotation(var expression: Expression = NumberExpression(0.0)): ParticleRotation {
|
||||
companion object {
|
||||
val CODEC: Codec<ParametricParticleRotation> = RecordCodecBuilder.create { instance ->
|
||||
instance.group(
|
||||
PrimitiveCodec.STRING.fieldOf("type").forGetter { it.type.name },
|
||||
EXPRESSION_CODEC.fieldOf("expression").forGetter { it.expression }
|
||||
).apply(instance) { _, expression ->
|
||||
ParametricParticleRotation(expression)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val type = ParticleRotationType.PARAMETRIC
|
||||
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
||||
override fun getInitialRotation(runtime: MoLangRuntime) = runtime.resolveDouble(expression)
|
||||
override fun getInitialAngularVelocity(runtime: MoLangRuntime) = 0.0
|
||||
override fun getAngularVelocity(runtime: MoLangRuntime, angle: Double, angularVelocity: Double) = runtime.resolveDouble(expression) - angle
|
||||
|
||||
override fun readFromBuffer(buffer: PacketByteBuf) {
|
||||
expression = MoLang.createParser(buffer.readString()).parseExpression()
|
||||
}
|
||||
|
||||
override fun writeToBuffer(buffer: PacketByteBuf) {
|
||||
buffer.writeString(expression.getString())
|
||||
}
|
||||
}
|
||||
|
||||
class DynamicParticleRotation(
|
||||
@@ -66,15 +94,15 @@ class DynamicParticleRotation(
|
||||
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
||||
override fun getInitialRotation(runtime: MoLangRuntime) = runtime.resolveDouble(startRotation)
|
||||
override fun getInitialAngularVelocity(runtime: MoLangRuntime) = runtime.resolveDouble(speed) / 20
|
||||
override fun getAngularAcceleration(runtime: MoLangRuntime, angularVelocity: Double): Double {
|
||||
override fun getAngularVelocity(runtime: MoLangRuntime, angle: Double, angularVelocity: Double): Double {
|
||||
val acceleration = runtime.resolveDouble(acceleration)
|
||||
val nextVelocity = angularVelocity + acceleration
|
||||
val nextVelocity = angularVelocity * 20 + acceleration
|
||||
val drag = nextVelocity * runtime.resolveDouble(drag)
|
||||
return if (abs(drag) > abs(nextVelocity)) {
|
||||
return angularVelocity + (if (abs(drag) > abs(nextVelocity)) {
|
||||
0.0
|
||||
} else {
|
||||
nextVelocity - drag - angularVelocity
|
||||
}
|
||||
nextVelocity - drag - angularVelocity * 20
|
||||
})
|
||||
}
|
||||
|
||||
override fun readFromBuffer(buffer: PacketByteBuf) {
|
||||
|
||||
+1
-1
@@ -78,7 +78,7 @@ abstract class SpawningCondition<T : SpawningContext> {
|
||||
return false
|
||||
} else if (ctx.position.z < minZ.orMin() || ctx.position.z > maxZ.orMax()) {
|
||||
return false
|
||||
} else if (dimensions != null && dimensions!!.isNotEmpty() && ctx.world.dimension.effects !in dimensions!!) {
|
||||
} else if (dimensions != null && dimensions!!.isNotEmpty() && ctx.world.dimensionKey.value !in dimensions!!) {
|
||||
return false
|
||||
} else if (moonPhase != null && ctx.moonPhase !in moonPhase!!) {
|
||||
return false
|
||||
|
||||
@@ -34,15 +34,19 @@ abstract class SpawnAction<R>(
|
||||
/**
|
||||
* Runs the spawn action and processes any non-null result.
|
||||
*/
|
||||
open fun complete(): Boolean {
|
||||
open fun complete(): R? {
|
||||
if (future.isDone) {
|
||||
return null
|
||||
}
|
||||
|
||||
ctx.influences.forEach { it.affectAction(this) }
|
||||
val result = run()
|
||||
return if (result != null) {
|
||||
if (result != null) {
|
||||
future.complete(result)
|
||||
true
|
||||
} else {
|
||||
future.completeExceptionally(Exception("Nothing was spawned."))
|
||||
false
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -124,7 +124,7 @@ open class PlayerPartyStore(
|
||||
}
|
||||
|
||||
// Passive evolutions
|
||||
pokemon.evolutions.filterIsInstance<PassiveEvolution>().forEach { it.attemptEvolution(pokemon) }
|
||||
pokemon.lockedEvolutions.filterIsInstance<PassiveEvolution>().forEach { it.attemptEvolution(pokemon) }
|
||||
val removeList = mutableListOf<Evolution>()
|
||||
pokemon.evolutionProxy.server().forEach {
|
||||
if (!it.test(pokemon) && it is LevelUpEvolution && !it.permanent)
|
||||
|
||||
@@ -99,7 +99,7 @@ open class PCStore(
|
||||
this.lockedSize = lockNewSize
|
||||
if (boxes.size > newSize) {
|
||||
// reduce
|
||||
val slicedBoxes = boxes.slice(boxes.size until newSize)
|
||||
val slicedBoxes = boxes.slice(newSize until boxes.size)
|
||||
boxes.removeAll(slicedBoxes)
|
||||
slicedBoxes.flatMap { it.asIterable() }.forEach(overflowHandler)
|
||||
} else {
|
||||
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.dispatch
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||
import net.minecraft.util.Identifier
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
/**
|
||||
* An [InterpreterInstruction] that triggers an [ActionEffectTimeline]
|
||||
* I think it might be better to have this as an abstract class so we can default the fields
|
||||
*
|
||||
* @author Apion
|
||||
* @since May 19, 2024
|
||||
*/
|
||||
interface ActionEffectInstruction : InterpreterInstruction {
|
||||
var future: CompletableFuture<*>
|
||||
var holds: MutableSet<String>
|
||||
//To expose via molang, so action effects can do different stuff in different instructions
|
||||
//e.g. "x is confused" vs "x hit itself in confusion"
|
||||
val id: Identifier
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
preActionEffect(battle)
|
||||
val runtime = MoLangRuntime()
|
||||
battle.addQueryFunctions(runtime.environment.getQueryStruct())
|
||||
runtime.environment.getQueryStruct().addStandardFunctions()
|
||||
addMolangQueries(runtime)
|
||||
runActionEffect(battle, runtime)
|
||||
postActionEffect(battle)
|
||||
}
|
||||
|
||||
fun preActionEffect(battle: PokemonBattle)
|
||||
fun runActionEffect(battle: PokemonBattle, runtime: MoLangRuntime)
|
||||
fun postActionEffect(battle: PokemonBattle)
|
||||
|
||||
fun addMolangQueries(runtime: MoLangRuntime) {
|
||||
runtime.environment.getQueryStruct()
|
||||
.addFunction("instruction_id") { StringValue(id.toString()) }
|
||||
}
|
||||
|
||||
}
|
||||
+52
-6
@@ -8,16 +8,28 @@
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.ActionEffectInstruction
|
||||
import com.cobblemon.mod.common.battles.dispatch.CauserInstruction
|
||||
import com.cobblemon.mod.common.battles.dispatch.GO
|
||||
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.battles.dispatch.UntilDispatch
|
||||
import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
/**
|
||||
* Format: |-activate|POKEMON|EFFECT
|
||||
@@ -28,19 +40,52 @@ import net.minecraft.text.Text
|
||||
* @author Hunter
|
||||
* @since September 25th, 2022
|
||||
*/
|
||||
class ActivateInstruction(val instructionSet: InstructionSet, val message: BattleMessage) : InterpreterInstruction, CauserInstruction {
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
class ActivateInstruction(val instructionSet: InstructionSet, val message: BattleMessage) : ActionEffectInstruction, CauserInstruction {
|
||||
override var future: CompletableFuture<*> = CompletableFuture.completedFuture(Unit)
|
||||
override var holds = mutableSetOf<String>()
|
||||
override val id = cobblemonResource("activate")
|
||||
|
||||
override fun preActionEffect(battle: PokemonBattle) {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return
|
||||
val effect = message.effectAt(1) ?: return
|
||||
val extraEffect = message.effectAt(2)?.typelessData ?: Text.literal("UNKNOWN")
|
||||
ShowdownInterpreter.broadcastOptionalAbility(battle, effect, pokemon)
|
||||
|
||||
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
|
||||
GO
|
||||
}
|
||||
}
|
||||
|
||||
override fun runActionEffect(battle: PokemonBattle, runtime: MoLangRuntime) {
|
||||
battle.dispatch {
|
||||
val effect = message.effectAt(1) ?: return@dispatch GO
|
||||
val status = Statuses.getStatus(effect.id)
|
||||
val actionEffect = status?.getActionEffect() ?: return@dispatch GO
|
||||
val providers = mutableListOf<Any>(battle)
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatch GO
|
||||
if (!SwitchInstruction.isVirtual) {
|
||||
pokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
|
||||
}
|
||||
val context = ActionEffectContext(
|
||||
actionEffect = actionEffect,
|
||||
runtime = runtime,
|
||||
providers = providers
|
||||
)
|
||||
this.future = actionEffect.run(context)
|
||||
holds = context.holds // Reference so future things can check on this action effect's holds
|
||||
future.thenApply { holds.clear() }
|
||||
return@dispatch GO
|
||||
}
|
||||
}
|
||||
|
||||
override fun postActionEffect(battle: PokemonBattle) {
|
||||
battle.dispatch {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatch GO
|
||||
val extraEffect = message.effectAt(2)?.typelessData ?: Text.literal("UNKNOWN")
|
||||
val effect = message.effectAt(1) ?: return@dispatch GO
|
||||
val pokemonName = pokemon.getName()
|
||||
val sourceName = message.battlePokemonFromOptional(battle)?.getName() ?: Text.literal("UNKNOWN")
|
||||
val lang = when (effect.id) {
|
||||
// Includes a 3rd argument being the magnitude level as a number
|
||||
"magnitude" -> battleLang("activate.magnitude", message.argumentAt(2)?.toIntOrNull() ?: 1)
|
||||
@@ -59,7 +104,8 @@ class ActivateInstruction(val instructionSet: InstructionSet, val message: Battl
|
||||
else -> battleLang("activate.${effect.id}", pokemonName, sourceName, extraEffect)
|
||||
}
|
||||
battle.broadcastChatMessage(lang)
|
||||
WaitDispatch(1F)
|
||||
//We check holds here so the chat msg + particle effect happen more concurrently, instead of sequentially
|
||||
UntilDispatch { "effects" !in holds}
|
||||
}
|
||||
}
|
||||
}
|
||||
+47
-3
@@ -8,14 +8,25 @@
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
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.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
|
||||
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.ActionEffectInstruction
|
||||
import com.cobblemon.mod.common.battles.dispatch.GO
|
||||
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.battles.dispatch.UntilDispatch
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.util.Identifier
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
/**
|
||||
* Format: |-boost|POKEMON|STAT|AMOUNT or |-unboost|POKEMON|STAT|AMOUNT
|
||||
@@ -25,9 +36,35 @@ import com.cobblemon.mod.common.util.battleLang
|
||||
* @author Hiroku
|
||||
* @since August 20th, 2022
|
||||
*/
|
||||
class BoostInstruction(val instructionSet: InstructionSet, val message: BattleMessage, val remainingLines: Iterator<BattleMessage>, val isBoost: Boolean = true): InterpreterInstruction {
|
||||
class BoostInstruction(val instructionSet: InstructionSet, val message: BattleMessage, val remainingLines: Iterator<BattleMessage>, val isBoost: Boolean = true): ActionEffectInstruction {
|
||||
override var future: CompletableFuture<*> = CompletableFuture.completedFuture(Unit)
|
||||
override var holds = mutableSetOf<String>()
|
||||
override val id = cobblemonResource("boost")
|
||||
override fun preActionEffect(battle: PokemonBattle) {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
}
|
||||
|
||||
override fun runActionEffect(battle: PokemonBattle, runtime: MoLangRuntime) {
|
||||
battle.dispatch {
|
||||
val actionEffect = if (isBoost) BOOST_EFFECT else UNBOOST_EFFECT
|
||||
val providers = mutableListOf<Any>(battle)
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatch GO
|
||||
if (!SwitchInstruction.isVirtual) {
|
||||
pokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
|
||||
}
|
||||
val context = ActionEffectContext(
|
||||
actionEffect = actionEffect,
|
||||
runtime = runtime,
|
||||
providers = providers
|
||||
)
|
||||
this.future = actionEffect.run(context)
|
||||
holds = context.holds // Reference so future things can check on this action effect's holds
|
||||
future.thenApply { holds.clear() }
|
||||
return@dispatch GO
|
||||
}
|
||||
}
|
||||
|
||||
override fun postActionEffect(battle: PokemonBattle) {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return
|
||||
val statKey = message.argumentAt(1) ?: return
|
||||
val stages = message.argumentAt(2)?.toInt() ?: return
|
||||
@@ -35,7 +72,7 @@ class BoostInstruction(val instructionSet: InstructionSet, val message: BattleMe
|
||||
val severity = Stats.getSeverity(stages)
|
||||
val rootKey = if (isBoost) "boost" else "unboost"
|
||||
|
||||
battle.dispatchWaiting {
|
||||
battle.dispatch {
|
||||
val lang = when {
|
||||
message.hasOptionalArgument("zeffect") -> battleLang("$rootKey.$severity.zeffect", pokemon.getName(), stat)
|
||||
else -> battleLang("$rootKey.$severity", pokemon.getName(), stat)
|
||||
@@ -47,6 +84,13 @@ class BoostInstruction(val instructionSet: InstructionSet, val message: BattleMe
|
||||
// TODO: replace with context that tracks detailed information such as # of stages
|
||||
repeat(stages) { pokemon.contextManager.add(context) }
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
return@dispatch UntilDispatch { "effects" !in holds }
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val BOOST_EFFECT = ActionEffects.actionEffects[cobblemonResource("boost")]!!
|
||||
val UNBOOST_EFFECT = ActionEffects.actionEffects[cobblemonResource("unboost")]!!
|
||||
}
|
||||
|
||||
}
|
||||
+53
-6
@@ -8,14 +8,27 @@
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.TargetsProvider
|
||||
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.battles.dispatch.ActionEffectInstruction
|
||||
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.battles.dispatch.WaitDispatch
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import net.minecraft.util.Identifier
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
/**
|
||||
* Formats: |cant|POKEMON|REASON and |cant|POKEMON|REASON|MOVE
|
||||
@@ -24,12 +37,42 @@ import com.cobblemon.mod.common.util.lang
|
||||
* @author Deltric
|
||||
* @since January 22nd, 2022
|
||||
*/
|
||||
class CantInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
class CantInstruction(val message: BattleMessage): ActionEffectInstruction {
|
||||
override var future: CompletableFuture<*> = CompletableFuture.completedFuture(Unit)
|
||||
override var holds = mutableSetOf<String>()
|
||||
override val id = cobblemonResource("cant")
|
||||
override fun preActionEffect(battle: PokemonBattle) {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchWaiting
|
||||
val effectID = message.effectAt(1)?.id ?: return@dispatchWaiting
|
||||
}
|
||||
|
||||
override fun runActionEffect(battle: PokemonBattle, runtime: MoLangRuntime) {
|
||||
battle.dispatch {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatch GO
|
||||
val effectID = message.effectAt(1)?.id ?: return@dispatch GO
|
||||
val name = pokemon.getName()
|
||||
val status = Statuses.getStatus(effectID)
|
||||
val actionEffect = status?.getActionEffect() ?: return@dispatch GO
|
||||
val providers = mutableListOf<Any>(battle)
|
||||
if (!SwitchInstruction.isVirtual) {
|
||||
pokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
|
||||
}
|
||||
|
||||
val context = ActionEffectContext(
|
||||
actionEffect = actionEffect,
|
||||
runtime = runtime,
|
||||
providers = providers
|
||||
)
|
||||
this.future = actionEffect.run(context)
|
||||
holds = context.holds // Reference so future things can check on this action effect's holds
|
||||
future.thenApply { holds.clear() }
|
||||
GO
|
||||
}
|
||||
}
|
||||
|
||||
override fun postActionEffect(battle: PokemonBattle) {
|
||||
battle.dispatch {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatch GO
|
||||
val effectID = message.effectAt(1)?.id ?: return@dispatch GO
|
||||
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() }
|
||||
@@ -38,7 +81,7 @@ class CantInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
// 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
|
||||
val status = Statuses.getStatus(effectID)?.name?.path ?: return@dispatch GO
|
||||
lang("status.$status.is", name)
|
||||
}
|
||||
else -> battleLang("cant.$effectID", name, moveName)
|
||||
@@ -46,6 +89,10 @@ class CantInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
battle.broadcastChatMessage(lang.red())
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
UntilDispatch { "effects" !in holds }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+78
-25
@@ -8,15 +8,21 @@
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter.lastCauser
|
||||
import com.cobblemon.mod.common.battles.dispatch.ActionEffectInstruction
|
||||
import com.cobblemon.mod.common.battles.dispatch.GO
|
||||
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.battles.dispatch.UntilDispatch
|
||||
import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
@@ -25,11 +31,13 @@ import com.cobblemon.mod.common.net.messages.client.battle.BattleHealthChangePac
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
|
||||
import com.cobblemon.mod.common.pokemon.evolution.progress.DamageTakenEvolutionProgress
|
||||
import com.cobblemon.mod.common.pokemon.evolution.progress.RecoilEvolutionProgress
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.PoisonStatus
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import kotlin.math.roundToInt
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* Format: |-damage|POKEMON|HP STATUS
|
||||
@@ -43,46 +51,90 @@ class DamageInstruction(
|
||||
val actor: BattleActor,
|
||||
val publicMessage: BattleMessage,
|
||||
val privateMessage: BattleMessage
|
||||
) : InterpreterInstruction {
|
||||
var future = CompletableFuture.completedFuture(Unit)
|
||||
) : ActionEffectInstruction {
|
||||
val expectedTarget = publicMessage.battlePokemon(0, actor.battle)
|
||||
override var future: CompletableFuture<*> = CompletableFuture.completedFuture(Unit)
|
||||
override var holds = mutableSetOf<String>()
|
||||
override val id = cobblemonResource("damage")
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
override fun preActionEffect(battle: PokemonBattle) {
|
||||
val battlePokemon = publicMessage.battlePokemon(0, actor.battle) ?: return
|
||||
val recoiling = privateMessage.optionalArgument("from")?.equals("recoil", true) == true
|
||||
val lastCauser = instructionSet.getMostRecentCauser(comparedTo = this)
|
||||
if (recoiling) {
|
||||
battlePokemon.effectedPokemon.let { pokemon ->
|
||||
if (RecoilEvolutionProgress.supports(pokemon)) {
|
||||
val newPercentage = privateMessage.argumentAt(1)?.split("/")?.getOrNull(0)?.toIntOrNull() ?: 0
|
||||
val newHealth = (pokemon.hp * (newPercentage / 100.0)).roundToInt()
|
||||
val difference = pokemon.currentHealth - newHealth
|
||||
if (difference > 0) {
|
||||
val progress = pokemon.evolutionProxy.current().progressFirstOrCreate({ it is RecoilEvolutionProgress }) { RecoilEvolutionProgress() }
|
||||
progress.updateProgress(RecoilEvolutionProgress.Progress(progress.currentProgress().recoil + difference))
|
||||
}
|
||||
doRecoilEvoChecks(battlePokemon)
|
||||
if (lastCauser is MoveInstruction) {
|
||||
battle.dispatch {
|
||||
//Is the recoil hold currently used anywhere?
|
||||
UntilDispatch { "recoil" !in lastCauser.holds }
|
||||
}
|
||||
}
|
||||
}
|
||||
val newHealth = privateMessage.argumentAt(1)?.split(" ")?.get(0) ?: return
|
||||
val effect = privateMessage.effect()
|
||||
val source = privateMessage.battlePokemonFromOptional(battle)
|
||||
var causedFaint = newHealth == "0"
|
||||
source?.let { ShowdownInterpreter.broadcastOptionalAbility(battle, effect, it) }
|
||||
}
|
||||
|
||||
battle.dispatch {
|
||||
if (lastCauser is MoveInstruction && recoiling) {
|
||||
UntilDispatch { "recoil" !in lastCauser.holds }
|
||||
} else {
|
||||
GO
|
||||
private fun doRecoilEvoChecks(battlePokemon: BattlePokemon) {
|
||||
battlePokemon.effectedPokemon.let { pokemon ->
|
||||
if (RecoilEvolutionProgress.supports(pokemon)) {
|
||||
val healthStr = privateMessage.argumentAt(1) ?: throw UnsupportedOperationException(
|
||||
"Cant get recoil string"
|
||||
)
|
||||
val newHealth =
|
||||
"([0-9]+).*".toRegex().find(healthStr)?.groups?.get(1)?.value?.toIntOrNull()
|
||||
?: throw UnsupportedOperationException("Cant get recoil string")
|
||||
val difference = pokemon.currentHealth - newHealth
|
||||
if (difference > 0) {
|
||||
val progress = pokemon.evolutionProxy.current()
|
||||
.progressFirstOrCreate({ it is RecoilEvolutionProgress }) { RecoilEvolutionProgress() }
|
||||
progress.updateProgress(RecoilEvolutionProgress.Progress(progress.currentProgress().recoil + difference))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
source?.let { ShowdownInterpreter.broadcastOptionalAbility(battle, effect, it) }
|
||||
override fun runActionEffect(battle: PokemonBattle, runtime: MoLangRuntime) {
|
||||
val effect = privateMessage.effect()
|
||||
val battlePokemon = publicMessage.battlePokemon(0, actor.battle) ?: return
|
||||
var status = effect?.id?.let { Statuses.getStatus(it) }
|
||||
battle.dispatch {
|
||||
val pokemon = privateMessage.battlePokemon(0, battle) ?: return@dispatch GO
|
||||
//Showdown doesnt tell us on damage if its poison or toxic so we gotta consult the entity
|
||||
if (status is PoisonStatus) {
|
||||
status = pokemon.effectedPokemon.status?.status ?: status
|
||||
}
|
||||
val actionEffect = status?.getActionEffect() ?: return@dispatch GO
|
||||
val providers = mutableListOf<Any>(battle)
|
||||
if (!SwitchInstruction.isVirtual) {
|
||||
battlePokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
|
||||
}
|
||||
|
||||
val context = ActionEffectContext(
|
||||
actionEffect = actionEffect,
|
||||
runtime = runtime,
|
||||
providers = providers
|
||||
)
|
||||
this.future = actionEffect.run(context)
|
||||
holds = context.holds // Reference so future things can check on this action effect's holds
|
||||
future.thenApply { holds.clear() }
|
||||
return@dispatch GO
|
||||
}
|
||||
}
|
||||
|
||||
override fun postActionEffect(battle: PokemonBattle) {
|
||||
val newHealth = privateMessage.argumentAt(1)?.split(" ")?.get(0) ?: return
|
||||
val battlePokemon = publicMessage.battlePokemon(0, actor.battle) ?: return
|
||||
var causedFaint = newHealth == "0"
|
||||
val effect = privateMessage.effect()
|
||||
val source = privateMessage.battlePokemonFromOptional(battle)
|
||||
val lastCauser = instructionSet.getMostRecentCauser(comparedTo = this)
|
||||
battle.dispatch {
|
||||
val pokemonName = battlePokemon.getName()
|
||||
val pokemonEntity = battlePokemon.entity
|
||||
if (!causedFaint && pokemonEntity != null) {
|
||||
//Play recoil animation if the pokemon recoiling isnt dead
|
||||
if (!causedFaint && pokemonEntity != null && !SwitchInstruction.isVirtual) {
|
||||
val pkt = PlayPoseableAnimationPacket(pokemonEntity.id, setOf("recoil"), emptySet())
|
||||
pkt.sendToPlayersAround(
|
||||
x = pokemonEntity.x,
|
||||
@@ -92,8 +144,8 @@ class DamageInstruction(
|
||||
distance = 50.0
|
||||
)
|
||||
}
|
||||
|
||||
if (pokemonEntity != null) {
|
||||
//Play hit particle
|
||||
if (pokemonEntity != null && !SwitchInstruction.isVirtual) {
|
||||
RunPosableMoLangPacket(pokemonEntity.id, setOf("q.particle('cobblemon:hit', 'target')")).sendToPlayersAround(
|
||||
x = pokemonEntity.x,
|
||||
y = pokemonEntity.y,
|
||||
@@ -157,8 +209,9 @@ class DamageInstruction(
|
||||
} else if (causedFaint) {
|
||||
GO
|
||||
} else {
|
||||
WaitDispatch(1F)
|
||||
UntilDispatch {"effects" !in holds}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -47,7 +47,7 @@ class DragInstruction(val instructionSet: InstructionSet, val battleActor: Battl
|
||||
val entity = if (battleActor is EntityBackedBattleActor<*>) battleActor.entity else null
|
||||
setOf(
|
||||
BattleDispatch {
|
||||
if (entity != null) {
|
||||
if (entity != null && !SwitchInstruction.isVirtual) {
|
||||
SwitchInstruction.createEntitySwitch(battle, battleActor, entity, pnx, activePokemon, pokemon, illusion, imposter)
|
||||
} else {
|
||||
SwitchInstruction.createNonEntitySwitch(battle, battleActor, pnx, activePokemon, pokemon, illusion)
|
||||
|
||||
+3
-1
@@ -38,7 +38,9 @@ class EndItemInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
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)
|
||||
if (!SwitchInstruction.isVirtual) {
|
||||
battlePokemon.entity?.playSound(CobblemonSounds.BERRY_EAT, 1F, 1F)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-1
@@ -10,10 +10,10 @@ package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
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.molang.MoLangFunctions.addFunction
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||
import com.cobblemon.mod.common.api.moves.Moves
|
||||
@@ -29,6 +29,7 @@ import com.cobblemon.mod.common.battles.dispatch.UntilDispatch
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.pokemon.evolution.progress.UseMoveEvolutionProgress
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
/**
|
||||
@@ -85,6 +86,7 @@ class MoveInstruction(
|
||||
battle.majorBattleActions[userPokemon.uuid] = message
|
||||
|
||||
val providers = mutableListOf<Any>(battle)
|
||||
if (SwitchInstruction.isVirtual) return@dispatch GO
|
||||
userPokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
|
||||
targetPokemon?.effectedPokemon?.entity?.let { TargetsProvider(it) }?.let(providers::add)
|
||||
val runtime = MoLangRuntime().also {
|
||||
@@ -121,6 +123,7 @@ class MoveInstruction(
|
||||
}
|
||||
|
||||
runtime.environment.getQueryStruct().addFunction("move") { move.struct }
|
||||
runtime.environment.getQueryStruct().addFunction("instruction_id") { StringValue(cobblemonResource("move").toString()) }
|
||||
|
||||
this.future = actionEffect.run(context)
|
||||
holds = context.holds // Reference so future things can check on this action effect's holds
|
||||
|
||||
+4
-2
@@ -32,8 +32,10 @@ class ReplaceInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return
|
||||
|
||||
battle.dispatchGo {
|
||||
val entity = pokemon.entity
|
||||
entity?.let { it.effects.mockEffect?.end(it) }
|
||||
if (!SwitchInstruction.isVirtual) {
|
||||
val entity = pokemon.entity
|
||||
entity?.let { it.effects.mockEffect?.end(it) }
|
||||
}
|
||||
|
||||
battle.sendSidedUpdate(
|
||||
source = actor,
|
||||
|
||||
+4
-2
@@ -48,7 +48,7 @@ class SwitchInstruction(val instructionSet: InstructionSet, val battleActor: Bat
|
||||
activePokemon.battlePokemon = pokemon
|
||||
activePokemon.illusion = illusion
|
||||
val pokemonEntity = pokemon.entity
|
||||
if (pokemonEntity == null && entity != null) {
|
||||
if (pokemonEntity == null && entity != null && !isVirtual) {
|
||||
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))
|
||||
@@ -87,7 +87,7 @@ class SwitchInstruction(val instructionSet: InstructionSet, val battleActor: Bat
|
||||
|
||||
setOf(
|
||||
BattleDispatch {
|
||||
if (entity != null) {
|
||||
if (entity != null && !isVirtual) {
|
||||
createEntitySwitch(battle, actor, entity, pnx, activePokemon, pokemon, illusion, imposter)
|
||||
} else {
|
||||
createNonEntitySwitch(battle, actor, pnx, activePokemon, pokemon, illusion)
|
||||
@@ -99,6 +99,8 @@ class SwitchInstruction(val instructionSet: InstructionSet, val battleActor: Bat
|
||||
}
|
||||
|
||||
companion object{
|
||||
val isVirtual = true
|
||||
|
||||
fun createEntitySwitch(
|
||||
battle: PokemonBattle,
|
||||
actor: BattleActor,
|
||||
|
||||
+11
-7
@@ -40,22 +40,26 @@ class TransformInstruction(val battle: PokemonBattle, val message: BattleMessage
|
||||
ShowdownInterpreter.broadcastOptionalAbility(battle, effect, pokemon)
|
||||
|
||||
battle.dispatch {
|
||||
if (SwitchInstruction.isVirtual) return@dispatch GO
|
||||
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)
|
||||
)
|
||||
if (!SwitchInstruction.isVirtual) {
|
||||
val mock = pokemon.entity?.effects?.mockEffect?.mock
|
||||
|
||||
mock?.let {
|
||||
battle.sendSidedUpdate(
|
||||
source = actor,
|
||||
allyPacket = BattleTransformPokemonPacket(pnx, pokemon, it, true),
|
||||
opponentPacket = BattleTransformPokemonPacket(pnx, pokemon, it, false)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val lang = battleLang("transform", pokemonName, targetPokemonName)
|
||||
|
||||
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.battles.runner
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.runner.graal.GraalShowdownService
|
||||
import com.cobblemon.mod.common.battles.runner.socket.SocketShowdownService
|
||||
import com.google.gson.JsonArray
|
||||
import java.util.UUID
|
||||
|
||||
@@ -36,6 +37,6 @@ interface ShowdownService {
|
||||
|
||||
|
||||
companion object {
|
||||
val service: ShowdownService by lazy { GraalShowdownService() }
|
||||
val service: ShowdownService by lazy { SocketShowdownService() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+18
-2
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.battles.runner.socket
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonImplementation
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.battles.BagItems
|
||||
@@ -16,9 +17,11 @@ import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.runner.ShowdownService
|
||||
import com.cobblemon.mod.common.pokemon.FormData
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonArray
|
||||
import java.io.BufferedReader
|
||||
import java.io.File
|
||||
import java.io.InputStreamReader
|
||||
import java.io.OutputStreamWriter
|
||||
import java.net.InetAddress
|
||||
@@ -83,7 +86,9 @@ class SocketShowdownService(val host: String = "localhost", val port: Int = 1846
|
||||
|
||||
private fun readMessage(): String {
|
||||
val payloadSize = read(reader, 8).toInt()
|
||||
println("Reading payload of size: $payloadSize")
|
||||
val payload = read(reader, payloadSize)
|
||||
println("Response: $payload")
|
||||
return payload
|
||||
}
|
||||
|
||||
@@ -113,7 +118,18 @@ class SocketShowdownService(val host: String = "localhost", val port: Int = 1846
|
||||
writer.write(">getCobbledMoves\n")
|
||||
writer.flush()
|
||||
val response = readMessage()
|
||||
return gson.fromJson(response, JsonArray::class.java)
|
||||
try {
|
||||
return gson.fromJson(response, JsonArray::class.java)
|
||||
}
|
||||
catch (e: Exception) {
|
||||
println("Error, JSON logged to logs/showdown.log")
|
||||
File("./showdown.log").writer().use {
|
||||
server()?.getFile("./logs/showdown.log")?.writer().use { writer ->
|
||||
writer?.write(response)
|
||||
}
|
||||
}
|
||||
}
|
||||
return JsonArray()
|
||||
}
|
||||
|
||||
override fun getItemIds(): JsonArray {
|
||||
@@ -166,4 +182,4 @@ class SocketShowdownService(val host: String = "localhost", val port: Int = 1846
|
||||
acknowledge()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import net.minecraft.entity.LivingEntity
|
||||
import net.minecraft.entity.ai.pathing.NavigationType
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.inventory.SidedInventory
|
||||
import net.minecraft.inventory.SimpleInventory
|
||||
import net.minecraft.item.ItemPlacementContext
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
@@ -38,6 +39,7 @@ import net.minecraft.util.shape.VoxelShapes
|
||||
import net.minecraft.world.BlockView
|
||||
import net.minecraft.world.World
|
||||
import net.minecraft.world.WorldAccess
|
||||
import net.minecraft.world.WorldEvents
|
||||
import net.minecraft.world.WorldView
|
||||
|
||||
|
||||
@@ -72,10 +74,12 @@ class RestorationTankBlock(properties: Settings) : MultiblockBlock(properties),
|
||||
|
||||
override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity?) {
|
||||
super.onBreak(world, pos, state, player)
|
||||
val otherPart = world.getBlockState(getPositionOfOtherPart(state, pos))
|
||||
if (otherPart.block is RestorationTankBlock) {
|
||||
world.setBlockState(getPositionOfOtherPart(state, pos), Blocks.AIR.defaultState, 35)
|
||||
world.syncWorldEvent(player, 2001, getPositionOfOtherPart(state, pos), getRawIdFromState(otherPart))
|
||||
if (!world.isClient) {
|
||||
val otherPart = world.getBlockState(getPositionOfOtherPart(state, pos))
|
||||
if (otherPart.block is RestorationTankBlock) {
|
||||
world.setBlockState(getPositionOfOtherPart(state, pos), Blocks.AIR.defaultState, Block.NOTIFY_ALL)
|
||||
world.syncWorldEvent(player, WorldEvents.BLOCK_BROKEN, getPositionOfOtherPart(state, pos), getRawIdFromState(otherPart))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,9 +91,9 @@ class RestorationTankBlock(properties: Settings) : MultiblockBlock(properties),
|
||||
itemStack: ItemStack?
|
||||
) {
|
||||
//Place the full block before we call to super to validate the multiblock
|
||||
world.setBlockState(pos.up(), state.with(PART, TankPart.TOP) as BlockState, 3)
|
||||
world.setBlockState(pos.up(), state.with(PART, TankPart.TOP) as BlockState, Block.NOTIFY_ALL)
|
||||
world.updateNeighbors(pos, Blocks.AIR)
|
||||
state.updateNeighbors(world, pos, 3)
|
||||
state.updateNeighbors(world, pos, Block.NOTIFY_ALL)
|
||||
super.onPlaced(world, pos, state, placer, itemStack)
|
||||
}
|
||||
|
||||
@@ -100,7 +104,7 @@ class RestorationTankBlock(properties: Settings) : MultiblockBlock(properties),
|
||||
val tankBottomPos = pos.down()
|
||||
val tankBottomState = world.getBlockState(tankBottomPos)
|
||||
if(tankBottomState.block.equals(CobblemonBlocks.RESTORATION_TANK.asBlock()) && tankBottomState.get(PART) == TankPart.BOTTOM) {
|
||||
return super.onUse(tankBottomState, world, tankBottomPos, player, hand, hit)
|
||||
return onUse(tankBottomState, world, tankBottomPos, player, hand, hit)
|
||||
}
|
||||
}
|
||||
return super.onUse(state, world, pos, player, hand, hit)
|
||||
@@ -206,9 +210,8 @@ class RestorationTankBlock(properties: Settings) : MultiblockBlock(properties),
|
||||
): SidedInventory {
|
||||
val tankEntity =
|
||||
(if (state.get(PART) == TankPart.TOP) world.getBlockEntity(pos.down())
|
||||
else world.getBlockEntity(pos)) as RestorationTankBlockEntity
|
||||
|
||||
return tankEntity.inv
|
||||
else world.getBlockEntity(pos))
|
||||
return if(tankEntity != null && tankEntity is RestorationTankBlockEntity) tankEntity.inv else DummyInventory()
|
||||
}
|
||||
|
||||
enum class TankPart(private val label: String) : StringIdentifiable {
|
||||
@@ -226,5 +229,18 @@ class RestorationTankBlock(properties: Settings) : MultiblockBlock(properties),
|
||||
val PART = EnumProperty.of("part", TankPart::class.java)
|
||||
val TRIGGERED = Properties.TRIGGERED
|
||||
val ON = BooleanProperty.of("on")
|
||||
class DummyInventory : SimpleInventory(0), SidedInventory {
|
||||
override fun getAvailableSlots(side: Direction): IntArray {
|
||||
return IntArray(0)
|
||||
}
|
||||
|
||||
override fun canInsert(slot: Int, stack: ItemStack, dir: Direction?): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun canExtract(slot: Int, stack: ItemStack, dir: Direction): Boolean {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import net.minecraft.item.ItemPlacementContext
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.screen.ScreenHandler
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.sound.SoundCategory
|
||||
import net.minecraft.state.StateManager
|
||||
import net.minecraft.state.property.BooleanProperty
|
||||
@@ -37,6 +38,7 @@ import net.minecraft.util.*
|
||||
import net.minecraft.util.hit.BlockHitResult
|
||||
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.util.shape.VoxelShapes
|
||||
import net.minecraft.world.BlockView
|
||||
@@ -125,11 +127,13 @@ class GildedChestBlock(settings: Settings, val type: Type = Type.RED) : BlockWit
|
||||
fun isFake() = (type == Type.FAKE)
|
||||
|
||||
override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity) {
|
||||
if (isFake()) {
|
||||
if (player is ServerPlayerEntity) {
|
||||
if (!world.isClient) {
|
||||
if (isFake() && (player is ServerPlayerEntity)) {
|
||||
spawnPokemon(world, pos, state, player)
|
||||
}
|
||||
world.setBlockState(pos, if (state.fluidState.isOf(Fluids.WATER)) Blocks.WATER.defaultState else Blocks.AIR.defaultState)
|
||||
val bEntity = world.getBlockEntity(pos) as? GildedChestBlockEntity
|
||||
bEntity?.markRemoved()
|
||||
} else super.onBreak(world, pos, state, player)
|
||||
}
|
||||
|
||||
@@ -183,10 +187,6 @@ class GildedChestBlock(settings: Settings, val type: Type = Type.RED) : BlockWit
|
||||
if (!player.world.isClient) {
|
||||
PiglinBrain.onGuardedBlockInteracted(player, true)
|
||||
}
|
||||
val state = entity.poseableState
|
||||
state.currentModel?.let {
|
||||
it.moveToPose(null, state, it.getPose("OPEN")!!)
|
||||
}
|
||||
return ActionResult.SUCCESS
|
||||
}
|
||||
|
||||
@@ -197,9 +197,11 @@ class GildedChestBlock(settings: Settings, val type: Type = Type.RED) : BlockWit
|
||||
newState: BlockState,
|
||||
moved: Boolean
|
||||
) {
|
||||
if (!state.isOf(newState.block)) {
|
||||
val chest = world.getBlockEntity(pos) as GildedChestBlockEntity
|
||||
ItemScatterer.spawn(world, pos, chest.inventoryContents)
|
||||
if (!state.isOf(newState.block) && !world.isClient) {
|
||||
val chest = world.getBlockEntity(pos) as? GildedChestBlockEntity
|
||||
chest?.let {
|
||||
ItemScatterer.spawn(world, pos, chest.inventoryContents)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,4 +263,14 @@ class GildedChestBlock(settings: Settings, val type: Type = Type.RED) : BlockWit
|
||||
}
|
||||
}
|
||||
|
||||
override fun scheduledTick(
|
||||
state: BlockState?,
|
||||
world: ServerWorld?,
|
||||
pos: BlockPos?,
|
||||
random: Random?
|
||||
) {
|
||||
val blockEntity = world?.getBlockEntity(pos) as? GildedChestBlockEntity ?: return
|
||||
blockEntity.onScheduledTick()
|
||||
}
|
||||
|
||||
}
|
||||
+21
-6
@@ -29,11 +29,17 @@ class FossilAnalyzerBlockEntity(
|
||||
|
||||
class FossilAnalyzerInventory(val analyzerEntity: FossilAnalyzerBlockEntity) : SidedInventory {
|
||||
override fun clear() {
|
||||
TODO("Not yet implemented")
|
||||
if(analyzerEntity.multiblockStructure != null && analyzerEntity.multiblockStructure is FossilMultiblockStructure) {
|
||||
val fossilMultiblockStructure = analyzerEntity.multiblockStructure as FossilMultiblockStructure
|
||||
fossilMultiblockStructure.fossilInventory.clear()
|
||||
}
|
||||
}
|
||||
|
||||
override fun size(): Int {
|
||||
TODO("Not yet implemented")
|
||||
if (analyzerEntity.multiblockStructure != null) {
|
||||
return 3
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
override fun isEmpty(): Boolean {
|
||||
@@ -41,11 +47,18 @@ class FossilAnalyzerBlockEntity(
|
||||
}
|
||||
|
||||
override fun getStack(slot: Int): ItemStack {
|
||||
if (analyzerEntity.multiblockStructure != null && analyzerEntity.multiblockStructure is FossilMultiblockStructure) {
|
||||
val fossilMultiblockStructure = analyzerEntity.multiblockStructure as FossilMultiblockStructure
|
||||
if (fossilMultiblockStructure.fossilInventory.size > slot) {
|
||||
return fossilMultiblockStructure.fossilInventory[slot]
|
||||
}
|
||||
}
|
||||
return ItemStack.EMPTY
|
||||
}
|
||||
|
||||
//Unimplemented since no extract
|
||||
override fun removeStack(slot: Int, amount: Int): ItemStack {
|
||||
return ItemStack.EMPTY
|
||||
return removeStack(slot)
|
||||
}
|
||||
|
||||
override fun removeStack(slot: Int): ItemStack {
|
||||
@@ -53,7 +66,7 @@ class FossilAnalyzerBlockEntity(
|
||||
}
|
||||
|
||||
override fun setStack(slot: Int, stack: ItemStack) {
|
||||
if (analyzerEntity.multiblockStructure != null) {
|
||||
if (analyzerEntity.multiblockStructure != null && analyzerEntity.multiblockStructure is FossilMultiblockStructure) {
|
||||
val struct = analyzerEntity.multiblockStructure as FossilMultiblockStructure
|
||||
analyzerEntity.world?.let {
|
||||
struct.insertFossil(stack, it)
|
||||
@@ -72,7 +85,10 @@ class FossilAnalyzerBlockEntity(
|
||||
}
|
||||
|
||||
override fun getAvailableSlots(side: Direction?): IntArray {
|
||||
return IntArray(1)
|
||||
if(analyzerEntity.multiblockStructure != null && analyzerEntity.multiblockStructure is FossilMultiblockStructure) {
|
||||
return intArrayOf(0,1,2)
|
||||
}
|
||||
return IntArray(0)
|
||||
}
|
||||
|
||||
override fun canInsert(slot: Int, stack: ItemStack?, dir: Direction?): Boolean {
|
||||
@@ -89,6 +105,5 @@ class FossilAnalyzerBlockEntity(
|
||||
override fun canExtract(slot: Int, stack: ItemStack?, dir: Direction?): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+2
-6
@@ -38,18 +38,14 @@ open class FossilMultiblockEntity(
|
||||
}
|
||||
}
|
||||
get() {
|
||||
return if (field != null) {
|
||||
field
|
||||
} else if (masterBlockPos != null && masterBlockPos != pos) {
|
||||
if(masterBlockPos != null && masterBlockPos != pos) {
|
||||
val chunkPos = ChunkPos(masterBlockPos)
|
||||
if (world?.chunkManager?.isChunkLoaded(chunkPos.x, chunkPos.z) == true) {
|
||||
val entity: FossilMultiblockEntity? = world?.getBlockEntity(masterBlockPos) as FossilMultiblockEntity?
|
||||
field = entity?.multiblockStructure
|
||||
}
|
||||
field
|
||||
} else {
|
||||
null
|
||||
}
|
||||
return field
|
||||
}
|
||||
|
||||
override fun markRemoved() {
|
||||
|
||||
+8
-5
@@ -20,6 +20,7 @@ import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.entity.player.PlayerInventory
|
||||
import net.minecraft.inventory.DoubleInventory
|
||||
import net.minecraft.inventory.Inventories
|
||||
import net.minecraft.inventory.Inventory
|
||||
import net.minecraft.inventory.SidedInventory
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
@@ -58,9 +59,7 @@ class GildedChestBlockEntity(pos: BlockPos, state: BlockState, val type: Type =
|
||||
override fun isPlayerViewing(player: PlayerEntity): Boolean {
|
||||
if (player.currentScreenHandler is GenericContainerScreenHandler) {
|
||||
val inventory = (player.currentScreenHandler as GenericContainerScreenHandler).inventory
|
||||
return inventory === this@GildedChestBlockEntity || inventory is DoubleInventory && inventory.isPart(
|
||||
this@GildedChestBlockEntity
|
||||
)
|
||||
return inventory === this@GildedChestBlockEntity
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -99,8 +98,6 @@ class GildedChestBlockEntity(pos: BlockPos, state: BlockState, val type: Type =
|
||||
return dir == Direction.DOWN
|
||||
}
|
||||
|
||||
override fun canPlayerUse(player: PlayerEntity) = !player.isSpectator
|
||||
|
||||
override fun getInvStackList(): DefaultedList<ItemStack> = inventoryContents
|
||||
|
||||
override fun setInvStackList(list: DefaultedList<ItemStack>) {
|
||||
@@ -164,4 +161,10 @@ class GildedChestBlockEntity(pos: BlockPos, state: BlockState, val type: Type =
|
||||
Inventories.readNbt(nbt, inventoryContents)
|
||||
}
|
||||
}
|
||||
|
||||
fun onScheduledTick() {
|
||||
if (!this.removed) {
|
||||
stateManager.updateViewerCount(this.getWorld(), this.getPos(), this.cachedState)
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
-19
@@ -12,13 +12,11 @@ import com.cobblemon.mod.common.CobblemonBlockEntities
|
||||
import com.cobblemon.mod.common.api.fossil.NaturalMaterials
|
||||
import com.cobblemon.mod.common.api.multiblock.builder.MultiblockStructureBuilder
|
||||
import com.cobblemon.mod.common.block.multiblock.FossilMultiblockStructure
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.inventory.Inventories
|
||||
import net.minecraft.inventory.SidedInventory
|
||||
import net.minecraft.inventory.SimpleInventory
|
||||
import net.minecraft.item.Item
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.nbt.NbtList
|
||||
@@ -55,7 +53,9 @@ class RestorationTankBlockEntity(
|
||||
|
||||
constructor(tankEntity: RestorationTankBlockEntity) : this(tankEntity, *Array(8) { ItemStack.EMPTY })
|
||||
|
||||
|
||||
override fun getMaxCountPerStack(): Int {
|
||||
return 1
|
||||
}
|
||||
|
||||
override fun markDirty() {
|
||||
super.markDirty()
|
||||
@@ -64,7 +64,6 @@ class RestorationTankBlockEntity(
|
||||
if(!itemStack.isEmpty) {
|
||||
val struct = tankEntity.multiblockStructure as? FossilMultiblockStructure
|
||||
val returnIdentifier = NaturalMaterials.getReturnItem(itemStack)
|
||||
|
||||
if(tankEntity.world != null) {
|
||||
if(struct?.insertOrganicMaterial(itemStack, tankEntity.world!!) == true) {
|
||||
removeStack(i)
|
||||
@@ -72,16 +71,15 @@ class RestorationTankBlockEntity(
|
||||
val returnItem = Registries.ITEM.get(returnIdentifier)
|
||||
val returnStack = ItemStack(returnItem, itemStack.count)
|
||||
var done = false
|
||||
if (returnStack.maxCount > 1) { // Only search for a merge if merging could be possible
|
||||
for(j in 0 until size()) {
|
||||
for(j in 1 until size()) {
|
||||
// Look for a inventory slot to merge with
|
||||
val existingStack : ItemStack = getStack(j)
|
||||
if (Registries.ITEM.getId(existingStack.item) == returnIdentifier && existingStack.count + returnStack.count < existingStack.maxCount) {
|
||||
if (existingStack.isEmpty
|
||||
|| (Registries.ITEM.getId(existingStack.item) == returnIdentifier && existingStack.count + returnStack.count < existingStack.maxCount)) {
|
||||
setStack(j, ItemStack(returnItem, existingStack.count + returnStack.count))
|
||||
done = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!done) {
|
||||
setStack(i, ItemStack(returnItem, itemStack.count))
|
||||
}
|
||||
@@ -104,7 +102,7 @@ class RestorationTankBlockEntity(
|
||||
}
|
||||
|
||||
override fun getAvailableSlots(side: Direction?): IntArray {
|
||||
return intArrayOf(0,1,2,3,4,5,6,7)
|
||||
return if (side == Direction.DOWN) intArrayOf(0,1,2,3,4,5,6,7) else intArrayOf(0)
|
||||
}
|
||||
|
||||
override fun canInsert(slot: Int, stack: ItemStack?, dir: Direction?): Boolean {
|
||||
@@ -113,16 +111,16 @@ class RestorationTankBlockEntity(
|
||||
val structure = tankEntity.multiblockStructure as FossilMultiblockStructure
|
||||
val canUtilize = stack?.let { NaturalMaterials.isNaturalMaterial(it) } == true
|
||||
&& structure.organicMaterialInside < FossilMultiblockStructure.MATERIAL_TO_START
|
||||
&& structure.createdPokemon == null
|
||||
&& !structure.hasCreatedPokemon
|
||||
val returnItem = NaturalMaterials.getReturnItem(stack!!) ?: return canUtilize
|
||||
val returnStack = ItemStack(Registries.ITEM.get(returnItem), stack.count)
|
||||
if(canUtilize && super.canInsert(returnStack)) {
|
||||
// See if there's room for the return
|
||||
if(returnStack == ItemStack.EMPTY) {
|
||||
if(returnStack == ItemStack.EMPTY && getStack(0) == ItemStack.EMPTY) {
|
||||
return true
|
||||
}
|
||||
// See if there's room for the return item
|
||||
var emptyCount = 0
|
||||
for(i in 0 until size()) {
|
||||
for(i in 1 until size()) {
|
||||
val existingStack : ItemStack = getStack(i)
|
||||
if(existingStack == ItemStack.EMPTY) {
|
||||
emptyCount += 1
|
||||
@@ -130,14 +128,8 @@ class RestorationTankBlockEntity(
|
||||
// 2 empty slots, safe to insert
|
||||
return true
|
||||
}
|
||||
} else if(returnStack.maxCount > 1) {
|
||||
if(Registries.ITEM.getId(existingStack.item) == returnItem && existingStack.count + returnStack.count < existingStack.maxCount) {
|
||||
// Return item can merge with an item already in the inventory
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+63
-54
@@ -10,7 +10,8 @@ package com.cobblemon.mod.common.block.multiblock
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.advancement.CobblemonCriteria
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.pokemon.FossilRevivedEvent
|
||||
import com.cobblemon.mod.common.api.fossil.Fossil
|
||||
import com.cobblemon.mod.common.api.fossil.Fossils
|
||||
import com.cobblemon.mod.common.api.fossil.NaturalMaterials
|
||||
@@ -72,7 +73,7 @@ class FossilMultiblockStructure (
|
||||
var organicMaterialInside = 0
|
||||
private set
|
||||
|
||||
var createdPokemon: Pokemon? = null
|
||||
var hasCreatedPokemon: Boolean = false
|
||||
private set
|
||||
var timeRemaining = -1
|
||||
private set
|
||||
@@ -102,8 +103,7 @@ class FossilMultiblockStructure (
|
||||
if (player !is ServerPlayerEntity) {
|
||||
return ActionResult.SUCCESS
|
||||
}
|
||||
if (this.createdPokemon != null) {
|
||||
|
||||
if (this.hasCreatedPokemon) {
|
||||
if (this.fossilOwnerUUID != null && player.uuid != this.fossilOwnerUUID) {
|
||||
var ownerName : String = "UNKNOWN_USER" // TODO: lang agnostic fallback
|
||||
server()?.userCache?.getByUuid(this.fossilOwnerUUID)?.orElse(null)?.name?.let {
|
||||
@@ -114,25 +114,28 @@ class FossilMultiblockStructure (
|
||||
}
|
||||
|
||||
|
||||
|
||||
val ballType = (stack.item as PokeBallItem).pokeBall
|
||||
if (!player.isCreative) {
|
||||
stack?.decrement(1)
|
||||
}
|
||||
|
||||
this.createdPokemon!!.caughtBall = ballType
|
||||
player.party().add(this.createdPokemon!!)
|
||||
this.fossilState.growthState = "Taken"
|
||||
player.playSound(CobblemonSounds.FOSSIL_MACHINE_RETRIEVE_POKEMON, SoundCategory.BLOCKS, 1.0F, 1.0F)
|
||||
CobblemonCriteria.RESURRECT_POKEMON.trigger(player, createdPokemon!!)
|
||||
val pokemon = this.resultingFossil?.result?.create()
|
||||
|
||||
if(pokemon != null) {
|
||||
pokemon.caughtBall = ballType
|
||||
player.party().add(pokemon)
|
||||
this.fossilState.growthState = "Taken"
|
||||
player.playSound(CobblemonSounds.FOSSIL_MACHINE_RETRIEVE_POKEMON, SoundCategory.BLOCKS, 1.0F, 1.0F)
|
||||
CobblemonEvents.FOSSIL_REVIVED.post(FossilRevivedEvent(pokemon, player))
|
||||
}
|
||||
|
||||
// Turn the monitor off
|
||||
val monitorState = world.getBlockState(monitorPos)
|
||||
if(!monitorState.equals(MonitorBlock.MonitorScreen.OFF)) {
|
||||
if(monitorState.contains(MonitorBlock.SCREEN) && !monitorState.equals(MonitorBlock.MonitorScreen.OFF)) {
|
||||
world.setBlockState(monitorPos, monitorState.with(MonitorBlock.SCREEN, MonitorBlock.MonitorScreen.OFF))
|
||||
}
|
||||
|
||||
this.createdPokemon = null
|
||||
this.hasCreatedPokemon = false
|
||||
this.fossilOwnerUUID = null
|
||||
this.protectionTime = -1
|
||||
this.updateFossilType(world)
|
||||
@@ -144,15 +147,14 @@ class FossilMultiblockStructure (
|
||||
|
||||
// Reclaim the last fossil from the machine if their hand is empty
|
||||
if (player.getStackInHand(interactionHand).isEmpty) {
|
||||
if(!this.isRunning() && this.createdPokemon == null) {
|
||||
if(!this.isRunning() && !this.hasCreatedPokemon) {
|
||||
if (fossilInventory.isEmpty()) {
|
||||
return ActionResult.CONSUME
|
||||
}
|
||||
player.setStackInHand(interactionHand, fossilInventory.last())
|
||||
|
||||
// remove last fossil in the fossil machine stack when grabbed out of the machine
|
||||
this.fossilInventory.removeAt(fossilInventory.size - 1)
|
||||
if(!world.isClient) {
|
||||
if(player is ServerPlayerEntity) {
|
||||
player.setStackInHand(interactionHand, fossilInventory.last())
|
||||
// remove last fossil in the fossil machine stack when grabbed out of the machine
|
||||
this.fossilInventory.removeAt(fossilInventory.size - 1)
|
||||
world.playSound(null, analyzerPos, CobblemonSounds.FOSSIL_MACHINE_RETRIEVE_FOSSIL, SoundCategory.BLOCKS)
|
||||
this.updateFossilType(world)
|
||||
this.syncToClient(world)
|
||||
@@ -164,19 +166,17 @@ class FossilMultiblockStructure (
|
||||
|
||||
// Check if the player is holding a fossil and if so insert it into the machine.
|
||||
if (Fossils.isFossilIngredient(stack)) {
|
||||
if(!this.isRunning() && this.createdPokemon == null) {
|
||||
if (!this.isRunning() && !this.hasCreatedPokemon) {
|
||||
if (fossilInventory.size > Cobblemon.config.maxInsertedFossilItems) {
|
||||
return ActionResult.FAIL
|
||||
}
|
||||
|
||||
val copyFossilStack = stack.copyWithCount(1)
|
||||
if (!player.isCreative) {
|
||||
stack?.decrement(1)
|
||||
}
|
||||
|
||||
fossilOwnerUUID = player.uuid
|
||||
fossilInventory.add(copyFossilStack)
|
||||
if(!world.isClient) {
|
||||
if (player is ServerPlayerEntity) {
|
||||
val copyFossilStack = stack.copyWithCount(1)
|
||||
if (!player.isCreative) {
|
||||
stack?.decrement(1)
|
||||
}
|
||||
fossilOwnerUUID = player.uuid
|
||||
fossilInventory.add(copyFossilStack)
|
||||
this.updateFossilType(world)
|
||||
world.playSound(null, analyzerPos, CobblemonSounds.FOSSIL_MACHINE_INSERT_FOSSIL, SoundCategory.BLOCKS)
|
||||
this.syncToClient(world)
|
||||
@@ -188,7 +188,11 @@ class FossilMultiblockStructure (
|
||||
|
||||
// Check if the player is holding a natural material and if so, feed it to the machine.
|
||||
if (NaturalMaterials.isNaturalMaterial(stack)) {
|
||||
if (!this.isRunning() && this.createdPokemon == null && this.organicMaterialInside < MATERIAL_TO_START && insertOrganicMaterial(stack, world)) {
|
||||
if (player is ServerPlayerEntity
|
||||
&& !this.isRunning()
|
||||
&& !this.hasCreatedPokemon
|
||||
&& this.organicMaterialInside < MATERIAL_TO_START
|
||||
&& insertOrganicMaterial(ItemStack(stack.item, 1), world)) {
|
||||
this.lastInteraction = world.time
|
||||
if (!player.isCreative) {
|
||||
val returnItem = NaturalMaterials.getReturnItem(stack)
|
||||
@@ -220,6 +224,7 @@ class FossilMultiblockStructure (
|
||||
entity.setPosition(fixedPosition.toCenterPos().subtract(0.0, 0.5, 0.0))
|
||||
// TODO: Find a correct way to set the new entity's Yaw rotation. (Face away from the machine)
|
||||
if (world.spawnEntity(entity)) {
|
||||
CobblemonEvents.FOSSIL_REVIVED.post(FossilRevivedEvent(pokemon, null))
|
||||
return true
|
||||
} else {
|
||||
Cobblemon.LOGGER.warn("Couldn't spawn resurrected Pokémon for some reason")
|
||||
@@ -271,7 +276,7 @@ class FossilMultiblockStructure (
|
||||
return 0
|
||||
}
|
||||
if(monitorPos == pos) {
|
||||
if(createdPokemon != null) {
|
||||
if(hasCreatedPokemon) {
|
||||
return 15
|
||||
}
|
||||
if(!isRunning()) {
|
||||
@@ -287,13 +292,13 @@ class FossilMultiblockStructure (
|
||||
override fun onTriggerEvent(state: BlockState?, world: ServerWorld?, pos: BlockPos?, random: Random?) {
|
||||
// instantiate the pokemon as a new entity and spawn it at the location of the machine
|
||||
if(this.protectionTime <= 0) {
|
||||
val wildPokemon: Pokemon = this.createdPokemon ?: return
|
||||
val wildPokemon: Pokemon = if (hasCreatedPokemon) resultingFossil?.result?.create() ?: return else return
|
||||
val direction = state?.get(HorizontalFacingBlock.FACING)?.opposite
|
||||
if(pos != null && direction != null && world != null) {
|
||||
val success = this.spawn(world, pos, direction, wildPokemon)
|
||||
if(success) {
|
||||
this.fossilState.growthState = "Taken"
|
||||
this.createdPokemon = null
|
||||
this.hasCreatedPokemon = false
|
||||
this.fossilOwnerUUID = null
|
||||
this.protectionTime = -1
|
||||
world.playSound(null, tankBasePos, CobblemonSounds.FOSSIL_MACHINE_RETRIEVE_POKEMON, SoundCategory.BLOCKS)
|
||||
@@ -310,9 +315,9 @@ class FossilMultiblockStructure (
|
||||
val analyzerEntity = world.getBlockEntity(analyzerPos) as? MultiblockEntity
|
||||
val tankBaseEntity = world.getBlockEntity(tankBasePos) as? MultiblockEntity
|
||||
val tankTopEntity = world.getBlockEntity(tankBasePos.up()) as? MultiblockEntity
|
||||
val state = world.getBlockState(tankBaseEntity?.pos)
|
||||
val direction = state.get(HorizontalFacingBlock.FACING).getOpposite()
|
||||
val wildPokemon: Pokemon? = this.createdPokemon
|
||||
val tankBaseBlockState = world.getBlockState(tankBaseEntity?.pos)
|
||||
val direction = tankBaseBlockState.get(HorizontalFacingBlock.FACING).opposite
|
||||
val wildPokemon: Pokemon? = if(hasCreatedPokemon) resultingFossil?.result?.create() else null
|
||||
|
||||
monitorEntity?.multiblockStructure = null
|
||||
analyzerEntity?.multiblockStructure = null
|
||||
@@ -372,7 +377,7 @@ class FossilMultiblockStructure (
|
||||
world.playSound(null, tankBasePos, CobblemonSounds.FOSSIL_MACHINE_UNPROTECTED, SoundCategory.BLOCKS)
|
||||
}
|
||||
|
||||
if (this.createdPokemon != null) {
|
||||
if (this.hasCreatedPokemon) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -401,10 +406,7 @@ class FossilMultiblockStructure (
|
||||
if (this.timeRemaining == 0) {
|
||||
world.playSound(null, tankBasePos, CobblemonSounds.FOSSIL_MACHINE_FINISHED, SoundCategory.BLOCKS)
|
||||
fossilInventory.clear()
|
||||
|
||||
this.resultingFossil?.let {
|
||||
this.createdPokemon = it.result.create()
|
||||
}
|
||||
this.hasCreatedPokemon = true
|
||||
if(this.fossilOwnerUUID != null) {
|
||||
protectionTime = PROTECTION_TIME
|
||||
}
|
||||
@@ -475,20 +477,26 @@ class FossilMultiblockStructure (
|
||||
val upperTankPos = tankBasePos.up()
|
||||
val analyzerState = world.getBlockState(analyzerPos)
|
||||
val tankState = world.getBlockState(tankBasePos.up())
|
||||
world.setBlockState(analyzerPos, analyzerState.with(FossilAnalyzerBlock.ON, timeRemaining >= 0))
|
||||
world.setBlockState(upperTankPos, tankState.with(RestorationTankBlock.ON, timeRemaining >= 0))
|
||||
if (analyzerState.contains(FossilAnalyzerBlock.ON)) {
|
||||
world.setBlockState(analyzerPos, analyzerState.with(FossilAnalyzerBlock.ON, timeRemaining >= 0))
|
||||
}
|
||||
if (tankState.contains(RestorationTankBlock.ON)) {
|
||||
world.setBlockState(upperTankPos, tankState.with(RestorationTankBlock.ON, timeRemaining >= 0))
|
||||
}
|
||||
}
|
||||
|
||||
fun updateProgress(world: World) {
|
||||
val screenID = if(protectionTime > 0F ) {
|
||||
MonitorBlock.MonitorScreen.GREEN_PROGRESS_9
|
||||
} else if (timeRemaining <= 0) {
|
||||
MonitorBlock.MonitorScreen.OFF
|
||||
} else {
|
||||
getProgressScreen((TIME_TO_TAKE - timeRemaining) / TIME_PER_STAGE)
|
||||
}
|
||||
val monitorState = world.getBlockState(monitorPos)
|
||||
world.setBlockState(monitorPos, monitorState.with(MonitorBlock.SCREEN, screenID))
|
||||
if (monitorState.contains(MonitorBlock.SCREEN)) {
|
||||
val screenID = if (protectionTime > 0F) {
|
||||
MonitorBlock.MonitorScreen.GREEN_PROGRESS_9
|
||||
} else if (timeRemaining <= 0) {
|
||||
MonitorBlock.MonitorScreen.OFF
|
||||
} else {
|
||||
getProgressScreen((TIME_TO_TAKE - timeRemaining) / TIME_PER_STAGE)
|
||||
}
|
||||
world.setBlockState(monitorPos, monitorState.with(MonitorBlock.SCREEN, screenID))
|
||||
}
|
||||
}
|
||||
|
||||
fun getProgressScreen(progress:Int) : MonitorBlock.MonitorScreen {
|
||||
@@ -603,9 +611,7 @@ class FossilMultiblockStructure (
|
||||
result.putString(DataKeys.INSERTED_FOSSIL, this.resultingFossil!!.asString())
|
||||
}
|
||||
|
||||
if (this.createdPokemon != null) {
|
||||
result.put(DataKeys.CREATED_POKEMON, createdPokemon!!.saveToNBT(NbtCompound()))
|
||||
}
|
||||
result.putBoolean(DataKeys.HAS_CREATED_POKEMON, hasCreatedPokemon)
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -654,7 +660,10 @@ class FossilMultiblockStructure (
|
||||
}
|
||||
|
||||
if (nbt.contains(DataKeys.CREATED_POKEMON)) {
|
||||
result.createdPokemon = Pokemon.loadFromNBT(nbt.getCompound(DataKeys.CREATED_POKEMON))
|
||||
// migration of instances that saved the created pokeon in the nbt
|
||||
result.hasCreatedPokemon = true
|
||||
} else if (nbt.contains(DataKeys.HAS_CREATED_POKEMON)){
|
||||
result.hasCreatedPokemon = nbt.getBoolean(DataKeys.HAS_CREATED_POKEMON)
|
||||
}
|
||||
result.fillLevel = result.organicMaterialInside * 8 / MATERIAL_TO_START
|
||||
return result
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.sound.PositionedSoundInstance
|
||||
@@ -31,6 +32,13 @@ object ClientMoLangFunctions {
|
||||
MinecraftClient.getInstance().soundManager.play(PositionedSoundInstance.master(soundEvent, pitch))
|
||||
}
|
||||
},
|
||||
"is_time" to java.util.function.Function { params ->
|
||||
val time = (MinecraftClient.getInstance().world?.timeOfDay ?: 0) % 24000
|
||||
val min = params.getInt(0)
|
||||
val max = params.getInt(1)
|
||||
time in min..max
|
||||
},
|
||||
"say" to java.util.function.Function { params -> MinecraftClient.getInstance().player?.sendMessage(params.getString(0).text()) ?: Unit },
|
||||
)
|
||||
|
||||
fun MoLangRuntime.setupClient(): MoLangRuntime {
|
||||
|
||||
@@ -272,6 +272,9 @@ class PokemonClientDelegate : PoseableEntityState<PokemonEntity>(), PokemonSideD
|
||||
},
|
||||
"weight" to java.util.function.Function {
|
||||
return@Function DoubleValue(currentEntity.pokemon.species.weight.toDouble())
|
||||
},
|
||||
"friendship" to java.util.function.Function {
|
||||
return@Function DoubleValue(currentEntity.pokemon.friendship.toDouble())
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
-3
@@ -15,9 +15,6 @@ import com.cobblemon.mod.common.client.render.MatrixWrapper
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticlePacket
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.util.math.RotationAxis.NEGATIVE_X
|
||||
import net.minecraft.util.math.RotationAxis.POSITIVE_X
|
||||
import net.minecraft.util.math.RotationAxis.POSITIVE_Y
|
||||
|
||||
object SpawnSnowstormParticleHandler : ClientNetworkPacketHandler<SpawnSnowstormParticlePacket> {
|
||||
override fun handle(packet: SpawnSnowstormParticlePacket, client: MinecraftClient) {
|
||||
|
||||
@@ -10,16 +10,20 @@ package com.cobblemon.mod.common.client.particle
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunction
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies.species
|
||||
import com.cobblemon.mod.common.api.snowstorm.BedrockParticleEffect
|
||||
import com.cobblemon.mod.common.api.snowstorm.ParticleEmitterAction
|
||||
import com.cobblemon.mod.common.client.render.MatrixWrapper
|
||||
import com.cobblemon.mod.common.client.render.SnowstormParticle
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.particle.SnowstormParticleEffect
|
||||
import com.cobblemon.mod.common.util.math.geometry.transformDirection
|
||||
import kotlin.random.Random
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.particle.NoRenderParticle
|
||||
import net.minecraft.client.util.ParticleUtil.spawnParticle
|
||||
import net.minecraft.client.world.ClientWorld
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.util.math.Vec3d
|
||||
@@ -48,12 +52,22 @@ class ParticleStorm(
|
||||
.addFunction("entity_height") { DoubleValue(entity.boundingBox.yLength) }
|
||||
.addFunction("entity_size") { DoubleValue(entity.boundingBox.run { if (xLength > yLength) xLength else yLength }) }
|
||||
.addFunction("entity_radius") { DoubleValue(entity.boundingBox.run { if (xLength > yLength) xLength else yLength } / 2) }
|
||||
.addFunction("entity_scale") {
|
||||
val pokeEntity = entity as? PokemonEntity
|
||||
val pokemon = pokeEntity?.pokemon
|
||||
//Use form data if available, species as fall back
|
||||
val baseScale = pokemon?.form?.baseScale ?: pokemon?.species?.baseScale ?: 1.0F
|
||||
val pokemonScale = pokemon?.scaleModifier ?: 1.0F
|
||||
val entityScale = pokeEntity?.scaleFactor ?: 1.0F
|
||||
DoubleValue(baseScale * pokemonScale * entityScale)
|
||||
}
|
||||
// TODO replace with a generified call to if (entity is MoLangEntity) entity.applyVariables(env) or w/e
|
||||
runtime.environment.setSimpleVariable("entity_width", DoubleValue(entity.boundingBox.xLength))
|
||||
runtime.environment.setSimpleVariable("entity_height", DoubleValue(entity.boundingBox.yLength))
|
||||
val longerDiameter = entity.boundingBox.run { if (xLength > yLength) xLength else yLength }
|
||||
runtime.environment.setSimpleVariable("entity_size", DoubleValue(longerDiameter))
|
||||
runtime.environment.setSimpleVariable("entity_radius", DoubleValue(longerDiameter / 2))
|
||||
runtime.environment.setSimpleVariable("entity_scale", DoubleValue((entity as? PokemonEntity)?.scaleFactor ?: 1.0))
|
||||
}
|
||||
MinecraftClient.getInstance().particleManager.addParticle(this)
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ class SnowstormParticle(
|
||||
|
||||
init {
|
||||
setVelocity(initialVelocity.x, initialVelocity.y, initialVelocity.z)
|
||||
angle = storm.effect.particle.rotation.getInitialRotation(storm.runtime).toFloat()
|
||||
angle = -storm.effect.particle.rotation.getInitialRotation(storm.runtime).toFloat()
|
||||
prevAngle = angle
|
||||
angularVelocity = storm.effect.particle.rotation.getInitialAngularVelocity(storm.runtime)
|
||||
velocityMultiplier = 1F
|
||||
@@ -256,24 +256,20 @@ class SnowstormParticle(
|
||||
setParticleAgeInRuntime()
|
||||
storm.effect.curves.forEach { it.apply(storm.runtime) }
|
||||
storm.runtime.execute(storm.effect.particle.updateExpressions)
|
||||
angularVelocity += storm.effect.particle.rotation.getAngularAcceleration(storm.runtime, angularVelocity) / 20
|
||||
angularVelocity = storm.effect.particle.rotation.getAngularVelocity(storm.runtime, -angle.toDouble(), angularVelocity) / 20
|
||||
|
||||
if (age > maxAge || storm.runtime.resolveBoolean(storm.effect.particle.killExpression)) {
|
||||
if (age >= maxAge || storm.runtime.resolveBoolean(storm.effect.particle.killExpression)) {
|
||||
runExpirationEvents()
|
||||
markDead()
|
||||
return
|
||||
} else {
|
||||
val acceleration = storm.effect.particle.motion.getAcceleration(
|
||||
storm.runtime,
|
||||
Vec3d(velocityX, velocityY, velocityZ).multiply(20.0) // Uses blocks per second, not blocks per tick
|
||||
).multiply(1 / 20.0).multiply(1 / 20.0) // blocks per second per second -> blocks per tick per tick
|
||||
|
||||
velocityX += acceleration.x
|
||||
velocityY += acceleration.y
|
||||
velocityZ += acceleration.z
|
||||
|
||||
val velocity = storm.effect.particle.motion.getVelocity(storm.runtime, this, Vec3d(velocityX, velocityY, velocityZ))
|
||||
velocityX = velocity.x
|
||||
velocityY = velocity.y
|
||||
velocityZ = velocity.z
|
||||
prevAngle = angle
|
||||
angle = prevAngle + angularVelocity.toFloat()
|
||||
// Subtract because Bedrock particles are counter-clockwise and Java Edition is clockwise.
|
||||
angle = prevAngle - angularVelocity.toFloat()
|
||||
}
|
||||
|
||||
viewDirection = storm.effect.particle.viewDirection.getDirection(
|
||||
|
||||
+3
-3
@@ -61,17 +61,17 @@ class RestorationTankRenderer(ctx: BlockEntityRendererFactory.Context) : BlockEn
|
||||
matrices.pop()
|
||||
}
|
||||
val fillLevel = struct.fillLevel
|
||||
if (fillLevel == 0 && struct.createdPokemon == null) {
|
||||
if (fillLevel == 0 && !struct.hasCreatedPokemon) {
|
||||
return
|
||||
}
|
||||
|
||||
if (struct.isRunning() or (struct.createdPokemon != null)) renderFetus(entity, tickDelta, matrices, vertexConsumers, light, overlay)
|
||||
if (struct.isRunning() or (struct.hasCreatedPokemon)) renderFetus(entity, tickDelta, matrices, vertexConsumers, light, overlay)
|
||||
|
||||
matrices.push()
|
||||
val transparentBuffer = vertexConsumers.getBuffer(RenderLayer.getTranslucent())
|
||||
|
||||
val fluidModel = if (struct.isRunning()) FLUID_MODELS[8]
|
||||
else if (struct.createdPokemon != null) FLUID_MODELS[7]
|
||||
else if (struct.hasCreatedPokemon) FLUID_MODELS[7]
|
||||
else FLUID_MODELS[fillLevel.coerceAtMost(FLUID_MODELS.size - 1) - 1]
|
||||
fluidModel.getQuads(entity.cachedState, null, entity.world?.random).forEach { quad ->
|
||||
transparentBuffer?.quad(matrices.peek(), quad, 0.75f, 0.75f, 0.75f, light, OverlayTexture.DEFAULT_UV)
|
||||
|
||||
+9
-2
@@ -20,7 +20,10 @@ import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFram
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.quirk.SimpleQuirk
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.normalizeToArray
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.resolveObject
|
||||
import com.cobblemon.mod.common.util.singularToPluralList
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonPrimitive
|
||||
@@ -34,6 +37,8 @@ class JsonPose<T : Entity>(model: PoseableEntityModel<T>, json: JsonObject) {
|
||||
it.environment.getQueryStruct().addFunctions(model.functions.functions)
|
||||
}
|
||||
|
||||
val condition: ExpressionLike = json.singularToPluralList("condition").get("conditions")?.normalizeToArray()?.map { it.asString }?.asExpressionLike() ?: "true".asExpressionLike()
|
||||
|
||||
val poseName = json.get("poseName")?.asString ?: "pose"
|
||||
val poseTypes = (json.get("poseTypes")?.asJsonArray?.map { name ->
|
||||
PoseType.values().find { it.name.lowercase() == name.asString.lowercase() }
|
||||
@@ -81,8 +86,9 @@ class JsonPose<T : Entity>(model: PoseableEntityModel<T>, json: JsonObject) {
|
||||
}
|
||||
|
||||
json as JsonObject
|
||||
json.singularToPluralList("animation")
|
||||
val animations: (state: PoseableEntityState<T>) -> List<StatefulAnimation<T, *>> = { _ ->
|
||||
(json.get("animations")?.asJsonArray ?: JsonArray()).map { animJson ->
|
||||
(json.get("animations")?.normalizeToArray()?.asJsonArray ?: JsonArray()).map { animJson ->
|
||||
try {
|
||||
val expr = animJson.asString.asExpressionLike()
|
||||
runtime.resolveObject(expr).obj as StatefulAnimation<T, *>
|
||||
@@ -97,10 +103,11 @@ class JsonPose<T : Entity>(model: PoseableEntityModel<T>, json: JsonObject) {
|
||||
val loopTimes = json.get("loopTimes")?.asInt ?: 1
|
||||
val minSeconds = json.get("minSecondsBetweenOccurrences")?.asFloat ?: 8F
|
||||
val maxSeconds = json.get("maxSecondsBetweenOccurrences")?.asFloat ?: 30F
|
||||
val condition = json.get("condition")?.asString?.asExpressionLike() ?: "true".asExpressionLike()
|
||||
|
||||
model.quirkMultiple(
|
||||
secondsBetweenOccurrences = minSeconds to maxSeconds,
|
||||
condition = { true },
|
||||
condition = { it.runtime.resolveBoolean(condition) },
|
||||
loopTimes = 1..loopTimes,
|
||||
animations = animations
|
||||
)
|
||||
|
||||
+29
-3
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.client.render.models.blockbench
|
||||
import com.cobblemon.mod.common.client.render.MatrixWrapper
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Bone
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.entity.Entity
|
||||
|
||||
/**
|
||||
* A storage of locator information for a model, attached to its [joint].
|
||||
@@ -68,20 +69,45 @@ class LocatorAccess(
|
||||
* Updates all of the locator states with the position at this current frame.
|
||||
* This is the same logic as ModelPart uses, that's why we reuse ModelPart#rotate.
|
||||
*/
|
||||
fun update(matrixStack: MatrixStack, state: MutableMap<String, MatrixWrapper>) {
|
||||
fun update(matrixStack: MatrixStack, entity: Entity, scale: Float, state: MutableMap<String, MatrixWrapper>, isRoot: Boolean = false) {
|
||||
matrixStack.push()
|
||||
joint.transform(matrixStack)
|
||||
|
||||
if (isRoot) {
|
||||
matrixStack.push()
|
||||
matrixStack.scale(-1F, -1F, 1F)
|
||||
state.getOrPut("root") { MatrixWrapper() }.updateMatrix(matrixStack.peek().positionMatrix)
|
||||
matrixStack.pop()
|
||||
|
||||
// Put in an approximation of the target locator. If the model has one defined,
|
||||
// this will be overridden.
|
||||
matrixStack.push()
|
||||
matrixStack.translate(0.0, -entity.boundingBox.yLength / 2.0 / scale, -entity.width * 0.6 / scale)
|
||||
matrixStack.scale(-1F, -1F, 1F)
|
||||
state.getOrPut("target") { MatrixWrapper() }.updateMatrix(matrixStack.peek().positionMatrix)
|
||||
state.getOrPut("special_attack") { MatrixWrapper() }.updateMatrix(matrixStack.peek().positionMatrix)
|
||||
matrixStack.pop()
|
||||
|
||||
// If we have the entity, put in a "middle" locator for center of mass
|
||||
// this will be overridden.
|
||||
matrixStack.push()
|
||||
matrixStack.translate(0.0, -entity.boundingBox.yLength / 2.0 / scale, 0.0)
|
||||
matrixStack.scale(-1F, -1F, 1F)
|
||||
state.getOrPut("middle") { MatrixWrapper() }.updateMatrix(matrixStack.peek().positionMatrix)
|
||||
matrixStack.pop()
|
||||
|
||||
}
|
||||
|
||||
for ((name, locator) in locators) {
|
||||
matrixStack.push()
|
||||
locator.transform(matrixStack)
|
||||
matrixStack.scale(1F, -1F, 1F)
|
||||
matrixStack.scale(-1F, -1F, 1F)
|
||||
state.getOrPut(name) { MatrixWrapper() }.updateMatrix(matrixStack.peek().positionMatrix)
|
||||
matrixStack.pop()
|
||||
}
|
||||
|
||||
children.forEach {
|
||||
it.update(matrixStack, state)
|
||||
it.update(matrixStack, entity, scale, state, isRoot = false)
|
||||
}
|
||||
|
||||
matrixStack.pop()
|
||||
|
||||
+49
-15
@@ -46,6 +46,7 @@ import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.getDoubleOrNull
|
||||
import com.cobblemon.mod.common.util.getStringOrNull
|
||||
import com.cobblemon.mod.common.util.plus
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import net.minecraft.client.model.ModelPart
|
||||
import net.minecraft.client.render.OverlayTexture
|
||||
import net.minecraft.client.render.RenderLayer
|
||||
@@ -260,6 +261,41 @@ abstract class PoseableEntityModel<T : Entity>(
|
||||
)
|
||||
)
|
||||
}
|
||||
.addFunction("bedrock_primary_quirk") { params ->
|
||||
val animationGroup = params.getString(0)
|
||||
val animationNames = params.get<MoValue>(1)?.let { if (it is ArrayStruct) it.map.values.map { it.asString() } else listOf(it.asString()) } ?: listOf()
|
||||
val minSeconds = params.getDoubleOrNull(2) ?: 8F
|
||||
val maxSeconds = params.getDoubleOrNull(3) ?: 30F
|
||||
val loopTimes = params.getDoubleOrNull(4)?.toInt() ?: 1
|
||||
val excludedLabels = mutableSetOf<String>()
|
||||
var curve: WaveFunction = { t ->
|
||||
if (t < 0.1) {
|
||||
t * 10
|
||||
} else if (t < 0.9) {
|
||||
1F
|
||||
} else {
|
||||
1F
|
||||
}
|
||||
}
|
||||
for (index in 5 until params.params.size) {
|
||||
val param = params.get<MoValue>(index)
|
||||
if (param is ObjectValue<*>) {
|
||||
curve = param.obj as WaveFunction
|
||||
continue
|
||||
}
|
||||
|
||||
val label = params.getString(index) ?: continue
|
||||
excludedLabels.add(label)
|
||||
}
|
||||
ObjectValue(
|
||||
quirk(
|
||||
secondsBetweenOccurrences = minSeconds.toFloat() to maxSeconds.toFloat(),
|
||||
condition = { true },
|
||||
loopTimes = 1..loopTimes,
|
||||
animation = { PrimaryAnimation(bedrockStateful(animationGroup, animationNames.random()), excludedLabels = excludedLabels, curve = curve) }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Transient
|
||||
val runtime = MoLangRuntime().setup().setupClient().also { it.environment.getQueryStruct().addFunctions(functions.functions) }
|
||||
@@ -787,7 +823,6 @@ abstract class PoseableEntityModel<T : Entity>(
|
||||
matrixStack.push()
|
||||
matrixStack.scale(-1F, -1F, 1F)
|
||||
scale = entity.pokemon.form.baseScale * entity.pokemon.scaleModifier * (entity.delegate as PokemonClientDelegate).entityScaleModifier
|
||||
|
||||
matrixStack.scale(scale, scale, scale)
|
||||
} else if (entity is EmptyPokeBallEntity) {
|
||||
matrixStack.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(entity.yaw))
|
||||
@@ -802,27 +837,14 @@ abstract class PoseableEntityModel<T : Entity>(
|
||||
matrixStack.scale(1F, -1F, 1F)
|
||||
}
|
||||
|
||||
matrixStack.push()
|
||||
matrixStack.scale(1F, -1F, 1F)
|
||||
val states = state.locatorStates
|
||||
states.getOrPut("root") { MatrixWrapper() }.updateMatrix(matrixStack.peek().positionMatrix)
|
||||
matrixStack.pop()
|
||||
|
||||
if (isForLivingEntityRenderer) {
|
||||
// Standard living entity offset, only God knows why Mojang did this.
|
||||
matrixStack.translate(0.0, -1.5, 0.0)
|
||||
}
|
||||
|
||||
// If we have the entity, put in an approximation of the target locator. If the model has one defined,
|
||||
// this will be overridden.
|
||||
matrixStack.push()
|
||||
matrixStack.translate(0.0, -entity.boundingBox.yLength / 2.0 / scale + 1.5F, -entity.width * 0.6 / scale)
|
||||
matrixStack.scale(1F, -1F, 1F)
|
||||
states.getOrPut("target") { MatrixWrapper() }.updateMatrix(matrixStack.peek().positionMatrix)
|
||||
states.getOrPut("special_attack") { MatrixWrapper() }.updateMatrix(matrixStack.peek().positionMatrix)
|
||||
matrixStack.pop()
|
||||
|
||||
locatorAccess.update(matrixStack, states)
|
||||
locatorAccess.update(matrixStack, entity, scale, states, isRoot = true)
|
||||
}
|
||||
|
||||
fun ModelPart.translation(
|
||||
@@ -878,6 +900,18 @@ abstract class PoseableEntityModel<T : Entity>(
|
||||
animations = { listOf(animation(it)) }
|
||||
)
|
||||
|
||||
fun quirkMoLangCondition(
|
||||
secondsBetweenOccurrences: Pair<Float, Float> = 8F to 30F,
|
||||
loopTimes: IntRange = 1..1,
|
||||
conditionExpression: ExpressionLike = "true".asExpressionLike(),
|
||||
animation: (state: PoseableEntityState<T>) -> StatefulAnimation<T, *>
|
||||
) = SimpleQuirk<T>(
|
||||
secondsBetweenOccurrences = secondsBetweenOccurrences,
|
||||
loopTimes = loopTimes,
|
||||
condition = { it.runtime.resolveBoolean(conditionExpression) },
|
||||
animations = { listOf(animation(it)) }
|
||||
)
|
||||
|
||||
fun quirkMultiple(
|
||||
secondsBetweenOccurrences: Pair<Float, Float> = 8F to 30F,
|
||||
loopTimes: IntRange = 1..1,
|
||||
|
||||
+2
-1
@@ -78,7 +78,7 @@ abstract class PoseableEntityState<T : Entity> : Schedulable {
|
||||
"anim_time" to java.util.function.Function { return@Function reusableAnimTime.also { it.value = animationSeconds.toDouble() } },
|
||||
"pose_type" to java.util.function.Function { return@Function StringValue((getEntity() as Poseable).getCurrentPoseType().name) },
|
||||
"pose" to java.util.function.Function { _ -> return@Function StringValue(currentPose ?: "") },
|
||||
"say" to java.util.function.Function { params -> MinecraftClient.getInstance().player?.sendMessage(params.getString(0).text()) ?: Unit },
|
||||
"has_entity" to java.util.function.Function { _ -> return@Function DoubleValue(getEntity() != null) },
|
||||
"sound" to java.util.function.Function { params ->
|
||||
val entity = getEntity() ?: return@Function Unit
|
||||
if (params.get<MoValue>(0) !is StringValue) {
|
||||
@@ -135,6 +135,7 @@ abstract class PoseableEntityState<T : Entity> : Schedulable {
|
||||
|
||||
val storm = ParticleStorm(
|
||||
effect = effect,
|
||||
entity = entity,
|
||||
matrixWrapper = matrixWrapper,
|
||||
world = world,
|
||||
runtime = particleRuntime,
|
||||
|
||||
+9
-20
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon
|
||||
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.JsonPose
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.JsonPoseableEntityModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityState
|
||||
@@ -24,6 +25,7 @@ import com.cobblemon.mod.common.util.isDusk
|
||||
import com.cobblemon.mod.common.util.isStandingOnRedSand
|
||||
import com.cobblemon.mod.common.util.isStandingOnSand
|
||||
import com.cobblemon.mod.common.util.isStandingOnSandOrRedSand
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.google.gson.ExclusionStrategy
|
||||
import com.google.gson.FieldAttributes
|
||||
import com.google.gson.GsonBuilder
|
||||
@@ -37,6 +39,7 @@ import com.google.gson.annotations.SerializedName
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import java.lang.reflect.Type
|
||||
import java.util.function.Supplier
|
||||
import net.minecraft.client.model.ModelPart
|
||||
import net.minecraft.util.math.Vec3d
|
||||
|
||||
/**
|
||||
@@ -47,7 +50,8 @@ import net.minecraft.util.math.Vec3d
|
||||
* @author Hiroku
|
||||
* @since August 7th, 2022
|
||||
*/
|
||||
class JsonPokemonPoseableModel(override val rootPart: Bone) : PokemonPoseableModel(), HeadedFrame {
|
||||
class JsonPokemonPoseableModel(rootPart: Bone) : PokemonPoseableModel(), HeadedFrame {
|
||||
override val rootPart = (rootPart as ModelPart).children.entries.first().let { rootPart.registerChildWithAllChildren(it.key) }
|
||||
companion object {
|
||||
val gson = GsonBuilder()
|
||||
.setPrettyPrinting()
|
||||
@@ -84,30 +88,12 @@ class JsonPokemonPoseableModel(override val rootPart: Bone) : PokemonPoseableMod
|
||||
|
||||
override val head: Bone by lazy { headJoint?.let { getPart(it) } ?: rootPart }
|
||||
|
||||
|
||||
@SerializedName("portraitScale")
|
||||
private val _portraitScale: Float? = null
|
||||
@SerializedName("portraitTranslation")
|
||||
private val _portraitTranslation: Vec3d? = null
|
||||
|
||||
@SerializedName("profileScale")
|
||||
private val _profileScale: Float? = null
|
||||
@SerializedName("profileTranslation")
|
||||
private val _profileTranslation: Vec3d? = null
|
||||
|
||||
//Some weirdness going on here, vars have to be initialized, gson doesn't like multiple fields with the same name
|
||||
@Transient
|
||||
//Idk, works fine with Blastoise
|
||||
override var portraitScale = 1F
|
||||
get() = _portraitScale ?: 1F
|
||||
@Transient
|
||||
override var portraitTranslation = Vec3d.ZERO
|
||||
get() = _portraitTranslation ?: Vec3d(0.0, 0.0, 0.0)
|
||||
@Transient
|
||||
override var profileScale = 1F
|
||||
get() = _profileScale ?: 1F
|
||||
@Transient
|
||||
override var profileTranslation = Vec3d.ZERO
|
||||
get() = _profileTranslation ?: Vec3d(0.0, 0.0, 0.0)
|
||||
|
||||
|
||||
val faint: Supplier<StatefulAnimation<PokemonEntity, ModelFrame>>? = null
|
||||
@@ -146,6 +132,7 @@ class JsonPokemonPoseableModel(override val rootPart: Bone) : PokemonPoseableMod
|
||||
override fun createInstance(type: Type): JsonPokemonPoseableModel {
|
||||
return JsonPokemonPoseableModel(modelPart!!).also {
|
||||
model = it
|
||||
modelPart as ModelPart
|
||||
it.loadAllNamedChildren(modelPart!!)
|
||||
}
|
||||
}
|
||||
@@ -192,6 +179,8 @@ class JsonPokemonPoseableModel(override val rootPart: Bone) : PokemonPoseableMod
|
||||
conditionsList.add { mustBeDusk == it.isDusk() }
|
||||
}
|
||||
|
||||
conditionsList.add { (it.delegate as PokemonClientDelegate).runtime.resolveBoolean(pose.condition) }
|
||||
|
||||
val poseCondition: ((PokemonEntity) -> Boolean)? = if (conditionsList.isEmpty()) null else conditionsList.reduce { acc, function -> { acc(it) && function(it) } }
|
||||
|
||||
return Pose(
|
||||
|
||||
+4
-3
@@ -8,13 +8,14 @@
|
||||
|
||||
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
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
|
||||
import net.minecraft.client.model.ModelPart
|
||||
import net.minecraft.util.math.Vec3d
|
||||
@@ -56,7 +57,7 @@ class KabutopsModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Bipe
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = UI_POSES + PoseType.STAND,
|
||||
poseTypes = UI_POSES + STATIONARY_POSES,
|
||||
condition = { !it.isBattling },
|
||||
quirks = arrayOf(blink),
|
||||
idleAnimations = arrayOf(
|
||||
@@ -67,7 +68,7 @@ class KabutopsModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Bipe
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseType = PoseType.WALK,
|
||||
poseTypes = MOVING_POSES,
|
||||
quirks = arrayOf(blink),
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
|
||||
+1
-8
@@ -8,21 +8,14 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.WingFlapIdleAnimation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.createTransformation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BiWingedFrame
|
||||
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
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.parabolaFunction
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.sineFunction
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.SHOULDER_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import net.minecraft.client.model.ModelPart
|
||||
import net.minecraft.util.math.Vec3d
|
||||
|
||||
@@ -66,7 +59,7 @@ class PidgeyModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
|
||||
stand = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = SHOULDER_POSES + UI_POSES + PoseType.STANDING_POSES,
|
||||
poseTypes = SHOULDER_POSES + UI_POSES + PoseType.STATIONARY_POSES - PoseType.HOVER,
|
||||
transformTicks = 10,
|
||||
transformedParts = arrayOf(
|
||||
wingClosedLeft.createTransformation().withVisibility(visibility = true),
|
||||
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen2
|
||||
|
||||
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.PokemonPose
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import net.minecraft.client.model.ModelPart
|
||||
import net.minecraft.util.math.Vec3d
|
||||
|
||||
class SmeargleModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, BipedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("smeargle")
|
||||
override val head = getPart("head")
|
||||
|
||||
/* No arm swinging because it's holding its tail */
|
||||
override val leftLeg = getPart("leg_left")
|
||||
override val rightLeg = getPart("leg_right")
|
||||
|
||||
override var portraitScale = 1.29F
|
||||
override var portraitTranslation = Vec3d(-0.03, 0.96, 0.0)
|
||||
|
||||
override var profileScale = 0.67F
|
||||
override var profileTranslation = Vec3d(0.05, 0.8, 0.0)
|
||||
|
||||
lateinit var standing: PokemonPose
|
||||
lateinit var walk: PokemonPose
|
||||
|
||||
//override val cryAnimation = CryProvider { _, _ -> bedrockStateful("smeargle", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("smeargle", "blink") }
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES + PoseType.SLEEP,
|
||||
quirks = arrayOf(blink),
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("smeargle", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = PoseType.MOVING_POSES,
|
||||
quirks = arrayOf(blink),
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("smeargle", "ground_idle"),
|
||||
BipedWalkAnimation(this, periodMultiplier = 0.6F, amplitudeMultiplier = 0.9F)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
-1
@@ -47,7 +47,6 @@ class ShedinjaModel (root: ModelPart) : PokemonPoseableModel() {
|
||||
poseName = "standing",
|
||||
poseTypes = PoseType.UI_POSES + PoseType.STAND,
|
||||
transformTicks = 10,
|
||||
condition = { !it.isBattling },
|
||||
quirks = arrayOf(blink),
|
||||
idleAnimations = arrayOf(
|
||||
bedrock("shedinja", "ground_idle")
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ import net.minecraft.util.math.Vec3d
|
||||
class WailordModel(root: ModelPart) : PokemonPoseableModel() {
|
||||
override val rootPart = root.registerChildWithAllChildren("wailord")
|
||||
override var portraitScale = 0.45F
|
||||
override var portraitTranslation = Vec3d(-0.38, 0.8, 0.0)
|
||||
override var portraitTranslation = Vec3d(-0.38, 0.8, 6.69)
|
||||
|
||||
override var profileScale = 0.25F
|
||||
override var profileTranslation = Vec3d(0.0, 1.2, -10.0)
|
||||
|
||||
+2
-2
@@ -25,8 +25,8 @@ class PetililHisuiBiasModel (root: ModelPart) : PokemonPoseableModel(), HeadedFr
|
||||
val leaf_left = getPart("leaf_left_rotation")
|
||||
val leaf_right = getPart("leaf_right_rotation")
|
||||
|
||||
override var portraitScale = 1.75F
|
||||
override var portraitTranslation = Vec3d(0.01, -0.39, 0.0)
|
||||
override var portraitScale = 1.52F
|
||||
override var portraitTranslation = Vec3d(0.1, -0.25, 0.0)
|
||||
|
||||
override var profileScale = 0.8F
|
||||
override var profileTranslation = Vec3d(0.0, 0.5, 0.0)
|
||||
|
||||
+2
-2
@@ -22,8 +22,8 @@ class PetililModel (root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("petilil")
|
||||
override val head = getPart("head")
|
||||
|
||||
override var portraitScale = 2.0F
|
||||
override var portraitTranslation = Vec3d(-0.3, -1.2, 0.0)
|
||||
override var portraitScale = 1.52F
|
||||
override var portraitTranslation = Vec3d(0.1, -0.25, 0.0)
|
||||
|
||||
override var profileScale = 0.8F
|
||||
override var profileTranslation = Vec3d(0.0, 0.5, 0.0)
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ class TyrantrumModel (root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
|
||||
override val head = getPart("head")
|
||||
|
||||
override var portraitTranslation = Vec3d(-0.86, 2.0, 0.0)
|
||||
override var portraitTranslation = Vec3d(-0.86, 2.0, 5.0)
|
||||
override var portraitScale = 0.59F
|
||||
|
||||
override var profileTranslation = Vec3d(0.02, 1.28, -10.0)
|
||||
|
||||
+2
-2
@@ -28,8 +28,8 @@ class DubwoolModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Quadr
|
||||
override val foreRightLeg = getPart("leg_front_right")
|
||||
override val hindLeftLeg = getPart("leg_back_left")
|
||||
override val hindRightLeg = getPart("leg_back_right")
|
||||
val wool = getPart("wool")
|
||||
val neckWool = getPart("neck_wool")
|
||||
val wool = getPart("wool_shearable")
|
||||
val neckWool = getPart("neck_wool_shearable")
|
||||
|
||||
override var portraitScale = 3.1F
|
||||
override var portraitTranslation = Vec3d(-1.2, -0.7, 0.0)
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ class WoolooModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Quadru
|
||||
override val foreRightLeg = getPart("leg_front_right")
|
||||
override val hindLeftLeg = getPart("leg_back_left")
|
||||
override val hindRightLeg = getPart("leg_back_right")
|
||||
val wool = getPart("wool")
|
||||
val wool = getPart("wool_shearable")
|
||||
|
||||
override var portraitScale = 3.1F
|
||||
override var portraitTranslation = Vec3d(-0.85, -1.8, 0.0)
|
||||
|
||||
+1
@@ -714,6 +714,7 @@ object PokemonModelRepository : VaryingModelRepository<PokemonEntity, PokemonPos
|
||||
inbuilt("rowlet_hisui_bias", ::RowletHisuiBiasModel)
|
||||
inbuilt("dartrix_hisui_bias", ::DartrixHisuiBiasModel)
|
||||
inbuilt("decidueye_hisuian", ::DecidueyeHisuianModel)
|
||||
inbuilt("smeargle", ::SmeargleModel)
|
||||
}
|
||||
|
||||
override fun loadJsonPoser(json: String): (Bone) -> PokemonPoseableModel {
|
||||
|
||||
-2
@@ -41,7 +41,6 @@ import net.minecraft.client.render.entity.model.EntityModel
|
||||
import net.minecraft.client.render.item.ItemRenderer
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.MathConstants.PI
|
||||
@@ -153,7 +152,6 @@ class PokemonRenderer(
|
||||
var beamSourcePosition = if (phaseTarget is EmptyPokeBallEntity) {
|
||||
(phaseTarget.delegate as PokeBallPoseableState).locatorStates["beam"]?.getOrigin() ?: phaseTarget.pos
|
||||
} else {
|
||||
phaseTarget as PlayerEntity
|
||||
if (phaseTarget.uuid == MinecraftClient.getInstance().player?.uuid) {
|
||||
val lookVec = phaseTarget.rotationVector.rotateY(PI / 2).multiply(1.0, 0.0, 1.0).normalize()
|
||||
phaseTarget.getCameraPosVec(partialTicks).subtract(0.0, 0.4, 0.0).subtract(lookVec.multiply(0.3))
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.cobblemon.mod.common.command
|
||||
|
||||
import com.cobblemon.mod.common.battles.BattleBuilder
|
||||
import com.cobblemon.mod.common.util.party
|
||||
import com.mojang.brigadier.Command
|
||||
import com.mojang.brigadier.CommandDispatcher
|
||||
import com.mojang.brigadier.context.CommandContext
|
||||
import net.minecraft.command.argument.EntityArgumentType
|
||||
import net.minecraft.server.command.CommandManager
|
||||
import net.minecraft.server.command.ServerCommandSource
|
||||
|
||||
object ChallengeCommand {
|
||||
|
||||
fun register(dispatcher : CommandDispatcher<ServerCommandSource>) {
|
||||
val command = CommandManager.literal("battle")
|
||||
.then(
|
||||
CommandManager
|
||||
.argument("target", EntityArgumentType.player())
|
||||
.executes(::execute)
|
||||
)
|
||||
|
||||
dispatcher.register(command)
|
||||
}
|
||||
|
||||
private fun execute(context: CommandContext<ServerCommandSource>) : Int {
|
||||
val player = context.source.playerOrThrow
|
||||
val target = EntityArgumentType.getPlayer(context, "target")
|
||||
|
||||
val leadingPlayerPokemon = player.party().filterNotNull().firstOrNull() ?: return 0
|
||||
val leadingTargetPokemon = target.party().filterNotNull().firstOrNull() ?: return 0
|
||||
BattleBuilder.pvp1v1(player, target, leadingPlayerPokemon.uuid, leadingTargetPokemon.uuid)
|
||||
return Command.SINGLE_SUCCESS
|
||||
}
|
||||
|
||||
}
|
||||
@@ -65,12 +65,6 @@ object CobblemonInfoCommand {
|
||||
.append(this.SPACE)
|
||||
.append(CobblemonBuildDetails.BRANCH)
|
||||
|
||||
message.append(this.NEW_LINE)
|
||||
.append(this.INDENT)
|
||||
.append(Text.literal("Timestamp:").styled { it.withColor(Formatting.GRAY) })
|
||||
.append(this.SPACE)
|
||||
.append(CobblemonBuildDetails.TIMESTAMP)
|
||||
|
||||
ctx.source.sendMessage(message)
|
||||
0
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import com.cobblemon.mod.common.api.Priority
|
||||
import com.cobblemon.mod.common.api.abilities.Abilities
|
||||
import com.cobblemon.mod.common.api.item.ability.AbilityChanger
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.scheduling.ClientTaskTracker.after
|
||||
import com.cobblemon.mod.common.api.scheduling.ServerTaskTracker
|
||||
import com.cobblemon.mod.common.api.scheduling.taskBuilder
|
||||
import com.cobblemon.mod.common.api.text.green
|
||||
@@ -25,10 +26,13 @@ import com.cobblemon.mod.common.battles.BattleSide
|
||||
import com.cobblemon.mod.common.battles.actor.PlayerBattleActor
|
||||
import com.cobblemon.mod.common.battles.actor.PokemonBattleActor
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.entity.generic.GenericBedrockEntity
|
||||
import com.cobblemon.mod.common.net.messages.client.animation.PlayPoseableAnimationPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeStartedPacket
|
||||
import com.cobblemon.mod.common.trade.ActiveTrade
|
||||
import com.cobblemon.mod.common.trade.DummyTradeParticipant
|
||||
import com.cobblemon.mod.common.trade.PlayerTradeParticipant
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.party
|
||||
import com.cobblemon.mod.common.util.toPokemon
|
||||
import com.google.gson.GsonBuilder
|
||||
@@ -61,6 +65,22 @@ object TestCommand {
|
||||
}
|
||||
|
||||
try {
|
||||
val player = context.source.entity as ServerPlayerEntity
|
||||
val evolutionEntity = GenericBedrockEntity(world = player.world)
|
||||
evolutionEntity?.apply {
|
||||
category = cobblemonResource("evolution")
|
||||
colliderHeight = 1.5F
|
||||
colliderWidth = 1.5F
|
||||
scale = 1F
|
||||
syncAge = true // Otherwise particle animation will be starting from zero even if you come along partway through
|
||||
setPosition(player.x, player.y, player.z + 4)
|
||||
}
|
||||
player.world.spawnEntity(evolutionEntity)
|
||||
after(seconds = 0.5F) {
|
||||
player.sendPacket(PlayPoseableAnimationPacket(evolutionEntity.id, setOf("evolution:animation.evolution.evolution"), emptySet()))
|
||||
}
|
||||
|
||||
|
||||
// readBerryDataFromCSV()
|
||||
|
||||
// this.testClosestBattle(context)
|
||||
|
||||
+6
-4
@@ -20,6 +20,7 @@ import com.cobblemon.mod.common.api.net.serializers.StringSetDataSerializer
|
||||
import com.cobblemon.mod.common.api.net.serializers.Vec3DataSerializer
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.api.pokeball.catching.CaptureContext
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.api.scheduling.Schedulable
|
||||
@@ -57,6 +58,7 @@ import net.minecraft.network.packet.s2c.play.EntitySpawnS2CPacket
|
||||
import net.minecraft.particle.ParticleTypes
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.sound.SoundEvents
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.hit.BlockHitResult
|
||||
import net.minecraft.util.hit.EntityHitResult
|
||||
import net.minecraft.util.hit.HitResult
|
||||
@@ -189,7 +191,7 @@ class EmptyPokeBallEntity : ThrownItemEntity, Poseable, WaterDragModifier, Sched
|
||||
val owner = owner
|
||||
|
||||
if (!pokemonEntity.pokemon.isWild()) {
|
||||
owner?.sendMessage(lang("capture.not_wild", pokemonEntity.pokemon.species.translatedName).red())
|
||||
owner?.sendMessage(lang("capture.not_wild", pokemonEntity.exposedSpecies.translatedName).red())
|
||||
return drop()
|
||||
}
|
||||
|
||||
@@ -204,7 +206,7 @@ class EmptyPokeBallEntity : ThrownItemEntity, Poseable, WaterDragModifier, Sched
|
||||
val hitBattlePokemon = hitActor?.activePokemon?.find { it.battlePokemon?.effectedPokemon?.entity == pokemonEntity }
|
||||
|
||||
if (throwerActor == null) {
|
||||
owner.sendMessage(lang("capture.in_battle", pokemonEntity.pokemon.species.translatedName).red())
|
||||
owner.sendMessage(lang("capture.in_battle", pokemonEntity.exposedSpecies.translatedName).red())
|
||||
return drop()
|
||||
}
|
||||
|
||||
@@ -230,13 +232,13 @@ class EmptyPokeBallEntity : ThrownItemEntity, Poseable, WaterDragModifier, Sched
|
||||
"capture.attempted_capture",
|
||||
throwerActor.getName(),
|
||||
pokeBall.item().name,
|
||||
pokemonEntity.pokemon.species.translatedName
|
||||
pokemonEntity.exposedSpecies.translatedName
|
||||
).yellow()
|
||||
)
|
||||
battle.sendUpdate(BattleCaptureStartPacket(pokeBall.name, aspects, hitBattlePokemon.getPNX()))
|
||||
throwerActor.forceChoose(ForcePassActionResponse())
|
||||
} else if (pokemonEntity.isBusy) {
|
||||
owner?.sendMessage(lang("capture.busy", pokemonEntity.pokemon.species.translatedName).red())
|
||||
owner?.sendMessage(lang("capture.busy", pokemonEntity.exposedSpecies.translatedName).red())
|
||||
return drop()
|
||||
} else if (owner is ServerPlayerEntity && BattleRegistry.getBattleByParticipatingPlayer(owner) != null) {
|
||||
owner.sendMessage(lang("you_in_battle").red())
|
||||
|
||||
@@ -21,7 +21,10 @@ import com.cobblemon.mod.common.api.interaction.PokemonEntityInteraction
|
||||
import com.cobblemon.mod.common.api.net.serializers.PoseTypeDataSerializer
|
||||
import com.cobblemon.mod.common.api.net.serializers.StringSetDataSerializer
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.ChoiceSpeciesFeatureProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.FlagSpeciesFeature
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.StringSpeciesFeature
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.api.reactive.ObservableSubscription
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
@@ -59,7 +62,6 @@ import com.cobblemon.mod.common.pokemon.evolution.variants.ItemInteractionEvolut
|
||||
import com.cobblemon.mod.common.pokemon.misc.GimmighoulStashHandler
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
|
||||
import net.minecraft.block.Blocks
|
||||
import java.util.EnumSet
|
||||
import java.util.Optional
|
||||
import java.util.UUID
|
||||
@@ -82,6 +84,7 @@ import net.minecraft.entity.passive.PassiveEntity
|
||||
import net.minecraft.entity.passive.TameableShoulderEntity
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.fluid.FluidState
|
||||
import net.minecraft.item.DyeItem
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.item.ItemUsage
|
||||
import net.minecraft.item.Items
|
||||
@@ -102,8 +105,11 @@ import net.minecraft.sound.SoundEvents
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.text.TextContent
|
||||
import net.minecraft.util.ActionResult
|
||||
import net.minecraft.util.Colors
|
||||
import net.minecraft.util.DyeColor
|
||||
import net.minecraft.util.Hand
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.Util
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.math.Box
|
||||
import net.minecraft.util.math.Vec3d
|
||||
@@ -136,6 +142,7 @@ open class PokemonEntity(
|
||||
@JvmStatic val UNBATTLEABLE = DataTracker.registerData(PokemonEntity::class.java, TrackedDataHandlerRegistry.BOOLEAN)
|
||||
@JvmStatic val COUNTS_TOWARDS_SPAWN_CAP = DataTracker.registerData(PokemonEntity::class.java, TrackedDataHandlerRegistry.BOOLEAN)
|
||||
@JvmStatic val SPAWN_DIRECTION = DataTracker.registerData(PokemonEntity::class.java, TrackedDataHandlerRegistry.FLOAT)
|
||||
@JvmStatic val FRIENDSHIP = DataTracker.registerData(PokemonEntity::class.java, TrackedDataHandlerRegistry.INTEGER)
|
||||
|
||||
const val BATTLE_LOCK = "battle"
|
||||
|
||||
@@ -181,6 +188,8 @@ open class PokemonEntity(
|
||||
set(value) = dataTracker.set(BATTLE_ID, Optional.ofNullable(value))
|
||||
val isBattling: Boolean
|
||||
get() = dataTracker.get(BATTLE_ID).isPresent
|
||||
val friendship: Int
|
||||
get() = dataTracker.get(FRIENDSHIP)
|
||||
|
||||
var drops: DropTable? = null
|
||||
|
||||
@@ -246,7 +255,9 @@ open class PokemonEntity(
|
||||
dataTracker.startTracking(LABEL_LEVEL, 1)
|
||||
dataTracker.startTracking(HIDE_LABEL, false)
|
||||
dataTracker.startTracking(UNBATTLEABLE, false)
|
||||
dataTracker.startTracking(COUNTS_TOWARDS_SPAWN_CAP, true)
|
||||
dataTracker.startTracking(SPAWN_DIRECTION, world.random.nextFloat() * 360F)
|
||||
dataTracker.startTracking(FRIENDSHIP, 0)
|
||||
}
|
||||
|
||||
override fun onTrackedDataSet(data: TrackedData<*>) {
|
||||
@@ -326,6 +337,21 @@ open class PokemonEntity(
|
||||
this.tethering = null
|
||||
this.pokemon.recall()
|
||||
}
|
||||
//This is so that pokemon in the pasture block are ALWAYS in sync with the pokemon box
|
||||
//Before, pokemon entities in pastures would hold an old ref to a pokemon obj and changes to that would not appear to the underlying file
|
||||
if (this.tethering != null) {
|
||||
//Only for online players
|
||||
if (world.getPlayerByUuid(ownerUuid) != null){
|
||||
this.ownerUuid?.let {
|
||||
val actualPokemon = Cobblemon.storage.getPC(it)[this.pokemon.uuid]
|
||||
actualPokemon?.let {
|
||||
if (it !== pokemon) {
|
||||
pokemon = it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
schedulingTracker.update(1/20F)
|
||||
}
|
||||
@@ -590,114 +616,153 @@ open class PokemonEntity(
|
||||
|
||||
override fun interactMob(player: PlayerEntity, hand: Hand) : ActionResult {
|
||||
val itemStack = player.getStackInHand(hand)
|
||||
val colorFeatureType = SpeciesFeatures.getFeaturesFor(pokemon.species).find { it is ChoiceSpeciesFeatureProvider && DataKeys.CAN_BE_COLORED in it.keys }
|
||||
val colorFeature = pokemon.getFeature<StringSpeciesFeature>(DataKeys.CAN_BE_COLORED)
|
||||
|
||||
if (itemStack.isOf(Items.SHEARS) && this.isShearable) {
|
||||
this.sheared(SoundCategory.PLAYERS)
|
||||
this.emitGameEvent(GameEvent.SHEAR, player)
|
||||
itemStack.damage(1, player) { it.sendToolBreakStatus(hand) }
|
||||
return ActionResult.SUCCESS
|
||||
}
|
||||
else if (itemStack.isOf(Items.BUCKET)) {
|
||||
if (pokemon.getFeature<FlagSpeciesFeature>(DataKeys.CAN_BE_MILKED) != null) {
|
||||
player.playSound(SoundEvents.ENTITY_GOAT_MILK, 1.0f, 1.0f)
|
||||
val milkBucket = ItemUsage.exchangeStack(itemStack, player, Items.MILK_BUCKET.defaultStack)
|
||||
player.setStackInHand(hand, milkBucket)
|
||||
return ActionResult.success(world.isClient)
|
||||
}
|
||||
} else if (itemStack.isOf(Items.BOWL)) {
|
||||
if (pokemon.aspects.any() {it.contains("mooshtank")}) {
|
||||
player.playSound(SoundEvents.ENTITY_MOOSHROOM_MILK, 1.0f, 1.0f)
|
||||
// if the Mooshtank ate a Flower beforehand
|
||||
if (pokemon.lastFlowerFed != ItemStack.EMPTY && pokemon.aspects.any() {it.contains("mooshtank-brown")}) {
|
||||
var effect: StatusEffect? = null
|
||||
var duration = 0
|
||||
if (ownerUuid == player.uuid || ownerUuid == null) {
|
||||
if (itemStack.isOf(Items.SHEARS) && this.isShearable) {
|
||||
this.sheared(SoundCategory.PLAYERS)
|
||||
this.emitGameEvent(GameEvent.SHEAR, player)
|
||||
itemStack.damage(1, player) { it.sendToolBreakStatus(hand) }
|
||||
return ActionResult.SUCCESS
|
||||
} else if (itemStack.isOf(Items.BUCKET)) {
|
||||
if (pokemon.getFeature<FlagSpeciesFeature>(DataKeys.CAN_BE_MILKED) != null) {
|
||||
player.playSound(SoundEvents.ENTITY_GOAT_MILK, 1.0f, 1.0f)
|
||||
val milkBucket = ItemUsage.exchangeStack(itemStack, player, Items.MILK_BUCKET.defaultStack)
|
||||
player.setStackInHand(hand, milkBucket)
|
||||
return ActionResult.success(world.isClient)
|
||||
}
|
||||
} else if (itemStack.isOf(Items.BOWL)) {
|
||||
if (pokemon.aspects.any { it.contains("mooshtank") }) {
|
||||
player.playSound(SoundEvents.ENTITY_MOOSHROOM_MILK, 1.0f, 1.0f)
|
||||
// if the Mooshtank ate a Flower beforehand
|
||||
if (pokemon.lastFlowerFed != ItemStack.EMPTY && pokemon.aspects.any() { it.contains("mooshtank-brown") }) {
|
||||
var effect: StatusEffect? = null
|
||||
var duration = 0
|
||||
|
||||
if (pokemon.lastFlowerFed.isOf(Items.ALLIUM)) {
|
||||
effect = StatusEffect.byRawId(12) // Fire Resistance
|
||||
duration = 80 // 4 seconds
|
||||
} else if (pokemon.lastFlowerFed.isOf(Items.AZURE_BLUET)) {
|
||||
effect = StatusEffect.byRawId(15) // Blindness
|
||||
duration = 160 // 8 seconds
|
||||
} else if (pokemon.lastFlowerFed.isOf(Items.BLUE_ORCHID) || pokemon.lastFlowerFed.isOf(Items.DANDELION)) {
|
||||
effect = StatusEffect.byRawId(23) // Saturation
|
||||
duration = 7 // .35 seconds
|
||||
} else if (pokemon.lastFlowerFed.isOf(Items.CORNFLOWER)) {
|
||||
effect = StatusEffect.byRawId(8) // Jump Boost
|
||||
duration = 120 // 6 seconds
|
||||
} else if (pokemon.lastFlowerFed.isOf(Items.LILY_OF_THE_VALLEY)) {
|
||||
effect = StatusEffect.byRawId(19) // Poison
|
||||
duration = 240 // 12 seconds
|
||||
} else if (pokemon.lastFlowerFed.isOf(Items.OXEYE_DAISY)) {
|
||||
effect = StatusEffect.byRawId(10) // Regeneration
|
||||
duration = 160 // 8 seconds
|
||||
} else if (pokemon.lastFlowerFed.isOf(Items.POPPY) || pokemon.lastFlowerFed.isOf(Items.TORCHFLOWER)) {
|
||||
effect = StatusEffect.byRawId(16) // Night Vision
|
||||
duration = 100 // 5 seconds
|
||||
} else if (pokemon.lastFlowerFed.isOf(Items.PINK_TULIP) || pokemon.lastFlowerFed.isOf(Items.RED_TULIP) || pokemon.lastFlowerFed.isOf(Items.WHITE_TULIP) || pokemon.lastFlowerFed.isOf(Items.ORANGE_TULIP)) {
|
||||
effect = StatusEffect.byRawId(18) // Weakness
|
||||
duration = 180 // 9 seconds
|
||||
} else if (pokemon.lastFlowerFed.isOf(Items.WITHER_ROSE)) {
|
||||
effect = StatusEffect.byRawId(20) // Wither
|
||||
duration = 160 // 8 seconds
|
||||
} else if (pokemon.lastFlowerFed.isOf(CobblemonItems.PEP_UP_FLOWER)) {
|
||||
effect = StatusEffect.byRawId(25) // Levitation
|
||||
duration = 160 // 8 seconds
|
||||
if (pokemon.lastFlowerFed.isOf(Items.ALLIUM)) {
|
||||
effect = StatusEffect.byRawId(12) // Fire Resistance
|
||||
duration = 80 // 4 seconds
|
||||
} else if (pokemon.lastFlowerFed.isOf(Items.AZURE_BLUET)) {
|
||||
effect = StatusEffect.byRawId(15) // Blindness
|
||||
duration = 160 // 8 seconds
|
||||
} else if (pokemon.lastFlowerFed.isOf(Items.BLUE_ORCHID) || pokemon.lastFlowerFed.isOf(Items.DANDELION)) {
|
||||
effect = StatusEffect.byRawId(23) // Saturation
|
||||
duration = 7 // .35 seconds
|
||||
} else if (pokemon.lastFlowerFed.isOf(Items.CORNFLOWER)) {
|
||||
effect = StatusEffect.byRawId(8) // Jump Boost
|
||||
duration = 120 // 6 seconds
|
||||
} else if (pokemon.lastFlowerFed.isOf(Items.LILY_OF_THE_VALLEY)) {
|
||||
effect = StatusEffect.byRawId(19) // Poison
|
||||
duration = 240 // 12 seconds
|
||||
} else if (pokemon.lastFlowerFed.isOf(Items.OXEYE_DAISY)) {
|
||||
effect = StatusEffect.byRawId(10) // Regeneration
|
||||
duration = 160 // 8 seconds
|
||||
} else if (pokemon.lastFlowerFed.isOf(Items.POPPY) || pokemon.lastFlowerFed.isOf(Items.TORCHFLOWER)) {
|
||||
effect = StatusEffect.byRawId(16) // Night Vision
|
||||
duration = 100 // 5 seconds
|
||||
} else if (pokemon.lastFlowerFed.isOf(Items.PINK_TULIP) || pokemon.lastFlowerFed.isOf(Items.RED_TULIP) || pokemon.lastFlowerFed.isOf(
|
||||
Items.WHITE_TULIP
|
||||
) || pokemon.lastFlowerFed.isOf(Items.ORANGE_TULIP)
|
||||
) {
|
||||
effect = StatusEffect.byRawId(18) // Weakness
|
||||
duration = 180 // 9 seconds
|
||||
} else if (pokemon.lastFlowerFed.isOf(Items.WITHER_ROSE)) {
|
||||
effect = StatusEffect.byRawId(20) // Wither
|
||||
duration = 160 // 8 seconds
|
||||
} else if (pokemon.lastFlowerFed.isOf(CobblemonItems.PEP_UP_FLOWER)) {
|
||||
effect = StatusEffect.byRawId(25) // Levitation
|
||||
duration = 160 // 8 seconds
|
||||
}
|
||||
|
||||
|
||||
// modify the suspicious stew with the effect
|
||||
val susStewStack = Items.SUSPICIOUS_STEW.defaultStack
|
||||
SuspiciousStewItem.addEffectToStew(susStewStack, effect, duration)
|
||||
val susStewEffect = ItemUsage.exchangeStack(itemStack, player, susStewStack)
|
||||
//give player modified Suspicious Stew
|
||||
player.setStackInHand(hand, susStewEffect)
|
||||
// reset the flower fed state
|
||||
pokemon.lastFlowerFed = ItemStack.EMPTY
|
||||
return ActionResult.success(world.isClient)
|
||||
} else {
|
||||
val mushroomStew = ItemUsage.exchangeStack(itemStack, player, Items.MUSHROOM_STEW.defaultStack)
|
||||
player.setStackInHand(hand, mushroomStew)
|
||||
return ActionResult.success(world.isClient)
|
||||
}
|
||||
|
||||
|
||||
// modify the suspicious stew with the effect
|
||||
val susStewStack = Items.SUSPICIOUS_STEW.defaultStack
|
||||
SuspiciousStewItem.addEffectToStew(susStewStack, effect, duration)
|
||||
val susStewEffect = ItemUsage.exchangeStack(itemStack, player, susStewStack)
|
||||
//give player modified Suspicious Stew
|
||||
player.setStackInHand(hand, susStewEffect)
|
||||
// reset the flower fed state
|
||||
pokemon.lastFlowerFed = ItemStack.EMPTY
|
||||
return ActionResult.success(world.isClient)
|
||||
}
|
||||
|
||||
else {
|
||||
val mushroomStew = ItemUsage.exchangeStack(itemStack, player, Items.MUSHROOM_STEW.defaultStack)
|
||||
player.setStackInHand(hand, mushroomStew)
|
||||
return ActionResult.success(world.isClient)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
// Flowers used on brown MooshTanks
|
||||
else if (itemStack.isOf(Items.ALLIUM) ||
|
||||
itemStack.isOf(Items.AZURE_BLUET) ||
|
||||
itemStack.isOf(Items.BLUE_ORCHID) ||
|
||||
itemStack.isOf(Items.DANDELION) ||
|
||||
itemStack.isOf(Items.CORNFLOWER) ||
|
||||
itemStack.isOf(Items.LILY_OF_THE_VALLEY) ||
|
||||
itemStack.isOf(Items.OXEYE_DAISY) ||
|
||||
itemStack.isOf(Items.POPPY) ||
|
||||
itemStack.isOf(Items.TORCHFLOWER) ||
|
||||
itemStack.isOf(Items.PINK_TULIP) ||
|
||||
itemStack.isOf(Items.RED_TULIP) ||
|
||||
itemStack.isOf(Items.WHITE_TULIP) ||
|
||||
itemStack.isOf(Items.ORANGE_TULIP) ||
|
||||
itemStack.isOf(Items.WITHER_ROSE) ||
|
||||
itemStack.isOf(CobblemonItems.PEP_UP_FLOWER)) {
|
||||
if (pokemon.aspects.any() {it.contains("mooshtank")}) {
|
||||
player.playSound(SoundEvents.ENTITY_MOOSHROOM_EAT, 1.0f, 1.0f)
|
||||
pokemon.lastFlowerFed = itemStack
|
||||
// Flowers used on brown MooshTanks
|
||||
else if (itemStack.isOf(Items.ALLIUM) ||
|
||||
itemStack.isOf(Items.AZURE_BLUET) ||
|
||||
itemStack.isOf(Items.BLUE_ORCHID) ||
|
||||
itemStack.isOf(Items.DANDELION) ||
|
||||
itemStack.isOf(Items.CORNFLOWER) ||
|
||||
itemStack.isOf(Items.LILY_OF_THE_VALLEY) ||
|
||||
itemStack.isOf(Items.OXEYE_DAISY) ||
|
||||
itemStack.isOf(Items.POPPY) ||
|
||||
itemStack.isOf(Items.TORCHFLOWER) ||
|
||||
itemStack.isOf(Items.PINK_TULIP) ||
|
||||
itemStack.isOf(Items.RED_TULIP) ||
|
||||
itemStack.isOf(Items.WHITE_TULIP) ||
|
||||
itemStack.isOf(Items.ORANGE_TULIP) ||
|
||||
itemStack.isOf(Items.WITHER_ROSE) ||
|
||||
itemStack.isOf(CobblemonItems.PEP_UP_FLOWER)
|
||||
) {
|
||||
if (pokemon.aspects.any { it.contains("mooshtank") }) {
|
||||
player.playSound(SoundEvents.ENTITY_MOOSHROOM_EAT, 1.0f, 1.0f)
|
||||
pokemon.lastFlowerFed = itemStack
|
||||
return ActionResult.success(world.isClient)
|
||||
}
|
||||
} else if (!player.isSneaking && player.uuid == ownerUuid && (itemStack.isOf(CobblemonItems.RELIC_COIN)
|
||||
|| itemStack.isOf(CobblemonItems.RELIC_COIN_POUCH)
|
||||
|| itemStack.isOf(CobblemonItems.RELIC_COIN_SACK)
|
||||
|| itemStack.isOf(Items.NETHERITE_SCRAP)
|
||||
|| itemStack.isOf(Items.NETHERITE_INGOT)
|
||||
|| itemStack.isOf(Items.NETHERITE_BLOCK))
|
||||
) {
|
||||
if (GimmighoulStashHandler.interactMob(player, hand, pokemon)) {
|
||||
return ActionResult.SUCCESS
|
||||
}
|
||||
} else if (itemStack.item is DyeItem && colorFeatureType != null) {
|
||||
val currentColor = colorFeature?.value ?: ""
|
||||
val item = itemStack.item as DyeItem
|
||||
if (!item.color.name.equals(currentColor, ignoreCase = true)) {
|
||||
if (player is ServerPlayerEntity) {
|
||||
if (colorFeature != null) {
|
||||
colorFeature.value = item.color.name.lowercase()
|
||||
this.pokemon.markFeatureDirty(colorFeature)
|
||||
} else {
|
||||
val newColorFeature =
|
||||
StringSpeciesFeature(DataKeys.CAN_BE_COLORED, item.color.name.lowercase())
|
||||
this.pokemon.features.add(newColorFeature)
|
||||
this.pokemon.anyChangeObservable.emit(pokemon)
|
||||
}
|
||||
|
||||
this.pokemon.updateAspects()
|
||||
if (!player.isCreative) {
|
||||
itemStack.decrement(1)
|
||||
}
|
||||
}
|
||||
return ActionResult.success(world.isClient)
|
||||
}
|
||||
} else if (itemStack.item.equals(Items.WATER_BUCKET) && colorFeatureType != null) {
|
||||
if (player is ServerPlayerEntity) {
|
||||
if (colorFeature != null) {
|
||||
if (!player.isCreative) {
|
||||
itemStack.decrement(1)
|
||||
player.giveOrDropItemStack(Items.BUCKET.defaultStack)
|
||||
}
|
||||
colorFeature.value = ""
|
||||
this.pokemon.markFeatureDirty(colorFeature)
|
||||
this.pokemon.updateAspects()
|
||||
}
|
||||
}
|
||||
return ActionResult.success(world.isClient)
|
||||
}
|
||||
} else if(!player.isSneaking && (itemStack.isOf(CobblemonItems.RELIC_COIN)
|
||||
|| itemStack.isOf(CobblemonItems.RELIC_COIN_POUCH)
|
||||
|| itemStack.isOf(CobblemonItems.RELIC_COIN_SACK)
|
||||
|| itemStack.isOf(Items.NETHERITE_SCRAP)
|
||||
|| itemStack.isOf(Items.NETHERITE_INGOT)
|
||||
|| itemStack.isOf(Items.NETHERITE_BLOCK))) {
|
||||
|
||||
if(GimmighoulStashHandler.interactMob(player, hand, pokemon)) {
|
||||
return ActionResult.SUCCESS
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (hand == Hand.MAIN_HAND && player is ServerPlayerEntity && pokemon.getOwnerPlayer() == player) {
|
||||
if (player.isSneaking) {
|
||||
InteractPokemonUIPacket(this.getUuid(), isReadyToSitOnPlayer && pokemon in player.party()).sendToPlayer(player)
|
||||
@@ -824,7 +889,7 @@ open class PokemonEntity(
|
||||
// Check evolution item interaction
|
||||
if (pokemon.getOwnerPlayer() == player) {
|
||||
val context = ItemInteractionEvolution.ItemInteractionContext(stack, player.world)
|
||||
pokemon.evolutions
|
||||
pokemon.lockedEvolutions
|
||||
.filterIsInstance<ItemInteractionEvolution>()
|
||||
.forEach { evolution ->
|
||||
if (evolution.attemptEvolution(pokemon, context)) {
|
||||
@@ -1122,8 +1187,26 @@ open class PokemonEntity(
|
||||
this.pokemon.markFeatureDirty(feature)
|
||||
this.pokemon.updateAspects()
|
||||
val i = this.random.nextInt(3) + 1
|
||||
for (j in 0 until i) {
|
||||
val itemEntity = this.dropItem(Items.WHITE_WOOL, 1) ?: return
|
||||
for (j in 0 .. i) {
|
||||
val color = this.pokemon.getFeature<StringSpeciesFeature>(DataKeys.CAN_BE_COLORED)?.value ?: "white"
|
||||
val woolItem = when (color) {
|
||||
"black" -> Items.BLACK_WOOL
|
||||
"blue" -> Items.BLUE_WOOL
|
||||
"brown" -> Items.BROWN_WOOL
|
||||
"cyan" -> Items.CYAN_WOOL
|
||||
"gray" -> Items.GRAY_WOOL
|
||||
"green" -> Items.GREEN_WOOL
|
||||
"light-blue" -> Items.LIGHT_BLUE_WOOL
|
||||
"light-gray" -> Items.LIGHT_GRAY_WOOL
|
||||
"lime" -> Items.LIME_WOOL
|
||||
"magenta" -> Items.MAGENTA_WOOL
|
||||
"orange" -> Items.ORANGE_WOOL
|
||||
"purple" -> Items.PURPLE_WOOL
|
||||
"red" -> Items.RED_WOOL
|
||||
"yellow" -> Items.YELLOW_WOOL
|
||||
else -> Items.WHITE_WOOL
|
||||
}
|
||||
val itemEntity = this.dropItem(woolItem, 1) ?: return
|
||||
itemEntity.velocity = itemEntity.velocity.add(
|
||||
((this.random.nextFloat() - this.random.nextFloat()) * 0.1f).toDouble(),
|
||||
(this.random.nextFloat() * 0.05f).toDouble(),
|
||||
@@ -1137,6 +1220,8 @@ open class PokemonEntity(
|
||||
return !this.isBusy && !this.pokemon.isFainted() && !feature.enabled
|
||||
}
|
||||
|
||||
|
||||
|
||||
override fun canUsePortals() = false
|
||||
|
||||
override fun setAir(air: Int) {
|
||||
|
||||
+19
-13
@@ -92,10 +92,28 @@ class PokemonServerDelegate : PokemonSideDelegate {
|
||||
speed = 0.1F
|
||||
entity.despawner.beginTracking(this)
|
||||
}
|
||||
updateTrackedValues()
|
||||
}
|
||||
|
||||
fun getBattle() = entity.battleId?.let(BattleRegistry::getBattle)
|
||||
|
||||
fun updateTrackedValues() {
|
||||
val trackedSpecies = mock?.species ?: entity.pokemon.species.resourceIdentifier.toString()
|
||||
val trackedNickname = mock?.nickname ?: entity.pokemon.nickname ?: Text.empty()
|
||||
val trackedAspects = mock?.aspects ?: entity.pokemon.aspects
|
||||
|
||||
entity.dataTracker.set(PokemonEntity.SPECIES, trackedSpecies)
|
||||
if (entity.dataTracker.get(PokemonEntity.NICKNAME) != trackedNickname) {
|
||||
entity.dataTracker.set(PokemonEntity.NICKNAME, trackedNickname)
|
||||
}
|
||||
entity.dataTracker.set(PokemonEntity.ASPECTS, trackedAspects)
|
||||
entity.dataTracker.set(PokemonEntity.LABEL_LEVEL, entity.pokemon.level)
|
||||
entity.dataTracker.set(PokemonEntity.MOVING, entity.velocity.multiply(1.0, if (entity.isOnGround) 0.0 else 1.0, 1.0).length() > 0.005F)
|
||||
entity.dataTracker.set(PokemonEntity.FRIENDSHIP, entity.pokemon.friendship)
|
||||
|
||||
updatePoseType()
|
||||
}
|
||||
|
||||
override fun onTrackedDataSet(data: TrackedData<*>) {
|
||||
super.onTrackedDataSet(data)
|
||||
if (this::entity.isInitialized) {
|
||||
@@ -162,19 +180,7 @@ class PokemonServerDelegate : PokemonSideDelegate {
|
||||
entity.remove(Entity.RemovalReason.DISCARDED)
|
||||
}
|
||||
|
||||
val trackedSpecies = mock?.species ?: entity.pokemon.species.resourceIdentifier.toString()
|
||||
val trackedNickname = mock?.nickname ?: entity.pokemon.nickname ?: Text.empty()
|
||||
val trackedAspects = mock?.aspects ?: entity.pokemon.aspects
|
||||
|
||||
entity.dataTracker.set(PokemonEntity.SPECIES, trackedSpecies)
|
||||
if (entity.dataTracker.get(PokemonEntity.NICKNAME) != trackedNickname) {
|
||||
entity.dataTracker.set(PokemonEntity.NICKNAME, trackedNickname)
|
||||
}
|
||||
entity.dataTracker.set(PokemonEntity.ASPECTS, trackedAspects)
|
||||
entity.dataTracker.set(PokemonEntity.LABEL_LEVEL, entity.pokemon.level)
|
||||
entity.dataTracker.set(PokemonEntity.MOVING, entity.velocity.multiply(1.0, if (entity.isOnGround) 0.0 else 1.0, 1.0).length() > 0.005F)
|
||||
|
||||
updatePoseType()
|
||||
updateTrackedValues()
|
||||
}
|
||||
|
||||
fun updatePoseType() {
|
||||
|
||||
@@ -87,9 +87,7 @@ object AdvancementHandler {
|
||||
event.battle.actors.forEach { battleActor ->
|
||||
if (!event.winners.contains(battleActor) && battleActor.type == ActorType.WILD) {
|
||||
battleActor.pokemonList.forEach { battlePokemon ->
|
||||
battlePokemon.entity?.pokemon?.let {
|
||||
advancementData.updateTotalDefeatedCount(it)
|
||||
}
|
||||
advancementData.updateTotalDefeatedCount(battlePokemon.originalPokemon)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ class LinkCableItem : CobblemonItem(Settings()), PokemonEntityInteraction {
|
||||
override val accepted = setOf(PokemonEntityInteraction.Ownership.OWNER)
|
||||
override fun processInteraction(player: ServerPlayerEntity, entity: PokemonEntity, stack: ItemStack): Boolean {
|
||||
val pokemon = entity.pokemon
|
||||
pokemon.evolutions.filterIsInstance<TradeEvolution>().forEach { evolution ->
|
||||
pokemon.lockedEvolutions.filterIsInstance<TradeEvolution>().forEach { evolution ->
|
||||
// If an evolution is possible non-optional or has been successfully queued we will consume the item and stop
|
||||
// validate requirements to respect required held items and such.
|
||||
if (evolution.requirements.all { it.check(pokemon) } && evolution.evolve(pokemon)) {
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.net.messages.client.pokemon.update
|
||||
|
||||
import com.cobblemon.mod.common.pokemon.FormData
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
class FormUpdatePacket(pokemon: () -> Pokemon, form: FormData) : SingleUpdatePacket<FormData, FormUpdatePacket>(pokemon, form) {
|
||||
override fun encodeValue(buffer: PacketByteBuf) {
|
||||
this.value.encode(buffer)
|
||||
}
|
||||
|
||||
override fun set(pokemon: Pokemon, value: FormData) {
|
||||
pokemon.form = value
|
||||
}
|
||||
|
||||
override val id: Identifier = ID
|
||||
|
||||
companion object {
|
||||
val ID: Identifier = cobblemonResource("packets/form-update")
|
||||
fun decode(buffer: PacketByteBuf): FormUpdatePacket {
|
||||
val pokemon = decodePokemon(buffer)
|
||||
val form = FormData()
|
||||
form.species = pokemon().species
|
||||
form.decode(buffer)
|
||||
return FormUpdatePacket(pokemon, form)
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-1
@@ -39,6 +39,7 @@ class SpawnPokemonPacket(
|
||||
private val hideLabel: Boolean,
|
||||
private val caughtBall: Identifier,
|
||||
private val spawnYaw: Float,
|
||||
private val friendship: Int,
|
||||
vanillaSpawnPacket: EntitySpawnS2CPacket
|
||||
) : SpawnExtraDataEntityPacket<SpawnPokemonPacket, PokemonEntity>(vanillaSpawnPacket) {
|
||||
|
||||
@@ -60,6 +61,7 @@ class SpawnPokemonPacket(
|
||||
entity.dataTracker.get(PokemonEntity.HIDE_LABEL),
|
||||
entity.pokemon.caughtBall.name,
|
||||
entity.dataTracker.get(PokemonEntity.SPAWN_DIRECTION),
|
||||
entity.dataTracker.get(PokemonEntity.FRIENDSHIP),
|
||||
vanillaSpawnPacket
|
||||
)
|
||||
|
||||
@@ -79,6 +81,7 @@ class SpawnPokemonPacket(
|
||||
buffer.writeBoolean(this.hideLabel)
|
||||
buffer.writeIdentifier(this.caughtBall)
|
||||
buffer.writeFloat(this.spawnYaw)
|
||||
buffer.writeInt(this.friendship)
|
||||
}
|
||||
|
||||
override fun applyData(entity: PokemonEntity) {
|
||||
@@ -101,6 +104,7 @@ class SpawnPokemonPacket(
|
||||
entity.dataTracker.set(PokemonEntity.UNBATTLEABLE, unbattlable)
|
||||
entity.dataTracker.set(PokemonEntity.HIDE_LABEL, hideLabel)
|
||||
entity.dataTracker.set(PokemonEntity.SPAWN_DIRECTION, spawnYaw)
|
||||
entity.dataTracker.set(PokemonEntity.FRIENDSHIP, friendship)
|
||||
}
|
||||
|
||||
override fun checkType(entity: Entity): Boolean = entity is PokemonEntity
|
||||
@@ -124,9 +128,10 @@ class SpawnPokemonPacket(
|
||||
val hideLabel = buffer.readBoolean()
|
||||
val caughtBall = buffer.readIdentifier()
|
||||
val spawnAngle = buffer.readFloat()
|
||||
val friendship = buffer.readInt()
|
||||
val vanillaPacket = decodeVanillaPacket(buffer)
|
||||
|
||||
return SpawnPokemonPacket(ownerId, scaleModifier, species, form, aspects, battleId, phasingTargetId, beamModeEmitter, nickname, labelLevel, poseType, unbattlable, hideLabel, caughtBall, spawnAngle, vanillaPacket)
|
||||
return SpawnPokemonPacket(ownerId, scaleModifier, species, form, aspects, battleId, phasingTargetId, beamModeEmitter, nickname, labelLevel, poseType, unbattlable, hideLabel, caughtBall, spawnAngle, friendship, vanillaPacket)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+24
-7
@@ -43,6 +43,7 @@ object SnowstormParticleReader {
|
||||
val emitterShapeEntityBoundingBoxJson = componentsJson.get("minecraft:emitter_shape_entity_aabb")?.asJsonObject
|
||||
val emitterLifetimeEventsJson = componentsJson.get("minecraft:emitter_lifetime_events")?.asJsonObject
|
||||
val dynamicMotionJson = componentsJson.get("minecraft:particle_motion_dynamic")?.asJsonObject
|
||||
val parametricMotionJson = componentsJson.get("minecraft:particle_motion_parametric")?.asJsonObject
|
||||
val particleAppearanceJson = componentsJson.get("minecraft:particle_appearance_billboard").asJsonObject
|
||||
val sizeJson = particleAppearanceJson.get("size")?.asJsonArray
|
||||
val particleLifetimeJson = componentsJson.get("minecraft:particle_lifetime_expression")?.asJsonObject
|
||||
@@ -234,13 +235,22 @@ object SnowstormParticleReader {
|
||||
val motion = if (dynamicMotionJson != null) {
|
||||
val accelerationExpressions = dynamicMotionJson.get("linear_acceleration")?.asJsonArray?.map { it.asString.asExpression() }
|
||||
?: listOf(0.0.asExpression(), 0.0.asExpression(), 0.0.asExpression())
|
||||
val drag= dynamicMotionJson.get("linear_drag_coefficient")?.asString?.asExpression() ?: 0.0.asExpression()
|
||||
val drag = dynamicMotionJson.get("linear_drag_coefficient")?.asString?.asExpression() ?: 0.0.asExpression()
|
||||
DynamicParticleMotion(
|
||||
direction = direction!!,
|
||||
speed = speed,
|
||||
acceleration = Triple(accelerationExpressions[0], accelerationExpressions[1], accelerationExpressions[2]),
|
||||
drag = drag
|
||||
)
|
||||
} else if (parametricMotionJson != null) {
|
||||
val offsetExpressions = parametricMotionJson.get("relative_position")?.asJsonArray?.map { it.asString.asExpression() }
|
||||
?: listOf(0.0.asExpression(), 0.0.asExpression(), 0.0.asExpression())
|
||||
val directionExpressions = parametricMotionJson.get("direction")?.asJsonArray?.map { it.asString.asExpression() }
|
||||
?: listOf(0.0.asExpression(), 0.0.asExpression(), 0.0.asExpression())
|
||||
ParametricParticleMotion(
|
||||
offset = Triple(offsetExpressions[0], offsetExpressions[1], offsetExpressions[2]),
|
||||
direction = Triple(directionExpressions[0], directionExpressions[1], directionExpressions[2])
|
||||
)
|
||||
} else {
|
||||
StaticParticleMotion()
|
||||
}
|
||||
@@ -299,12 +309,19 @@ object SnowstormParticleReader {
|
||||
textureSizeY = uvModeJson.get("texture_height")?.asInt ?: 128
|
||||
)
|
||||
}
|
||||
val rotation = DynamicParticleRotation(
|
||||
startRotation = startRotation,
|
||||
speed = rotationSpeed,
|
||||
acceleration = dynamicMotionJson?.get("rotation_acceleration")?.asString?.asExpression() ?: 0.0.asExpression(),
|
||||
drag = dynamicMotionJson?.get("rotation_drag_coefficient")?.asString?.asExpression() ?: 0.0.asExpression()
|
||||
)
|
||||
|
||||
val motionJson = dynamicMotionJson ?: parametricMotionJson
|
||||
val parametricParticleRotation = motionJson?.get("rotation")?.asString?.asExpression()
|
||||
val rotation = if (parametricParticleRotation != null) {
|
||||
ParametricParticleRotation(expression = parametricParticleRotation)
|
||||
} else {
|
||||
DynamicParticleRotation(
|
||||
startRotation = startRotation,
|
||||
speed = rotationSpeed,
|
||||
acceleration = dynamicMotionJson?.get("rotation_acceleration")?.asString?.asExpression() ?: 0.0.asExpression(),
|
||||
drag = dynamicMotionJson?.get("rotation_drag_coefficient")?.asString?.asExpression() ?: 0.0.asExpression()
|
||||
)
|
||||
}
|
||||
val tinting = if (colourJson is JsonObject) {
|
||||
GradientParticleTinting(
|
||||
interpolant = colourJson.get("interpolant").asString.asExpression(),
|
||||
|
||||
+6
-6
@@ -18,12 +18,12 @@ import com.cobblemon.mod.common.battles.actor.PlayerBattleActor
|
||||
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.BurnStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.FrozenStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.ParalysisStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonBadlyStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.SleepStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.BurnStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.FrozenStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.ParalysisStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.PoisonBadlyStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.PoisonStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.SleepStatus
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.pow
|
||||
|
||||
+6
-6
@@ -14,12 +14,12 @@ import com.cobblemon.mod.common.api.pokeball.catching.calculators.CaptureCalcula
|
||||
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.BurnStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.FrozenStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.ParalysisStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonBadlyStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.SleepStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.BurnStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.FrozenStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.ParalysisStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.PoisonBadlyStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.PoisonStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.SleepStatus
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.random.Random
|
||||
import net.minecraft.entity.LivingEntity
|
||||
|
||||
+6
-6
@@ -12,12 +12,12 @@ import com.cobblemon.mod.common.api.pokeball.catching.CaptureContext
|
||||
import com.cobblemon.mod.common.api.pokeball.catching.calculators.CaptureCalculator
|
||||
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.BurnStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.FrozenStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.ParalysisStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonBadlyStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.SleepStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.BurnStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.FrozenStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.ParalysisStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.PoisonBadlyStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.PoisonStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.SleepStatus
|
||||
import kotlin.math.max
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.random.Random
|
||||
|
||||
+6
-6
@@ -13,12 +13,12 @@ import com.cobblemon.mod.common.api.pokeball.catching.CaptureContext
|
||||
import com.cobblemon.mod.common.api.pokeball.catching.calculators.CaptureCalculator
|
||||
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.BurnStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.FrozenStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.ParalysisStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonBadlyStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.SleepStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.BurnStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.FrozenStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.ParalysisStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.PoisonBadlyStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.PoisonStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.SleepStatus
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.math.sqrt
|
||||
import kotlin.random.Random
|
||||
|
||||
+6
-6
@@ -15,12 +15,12 @@ import com.cobblemon.mod.common.api.pokeball.catching.calculators.CriticalCaptur
|
||||
import com.cobblemon.mod.common.api.pokeball.catching.calculators.PokedexProgressCaptureMultiplierProvider
|
||||
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.BurnStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.FrozenStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.ParalysisStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonBadlyStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.SleepStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.BurnStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.FrozenStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.ParalysisStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.PoisonBadlyStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.PoisonStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.SleepStatus
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.math.sqrt
|
||||
import kotlin.random.Random
|
||||
|
||||
+6
-6
@@ -15,12 +15,12 @@ import com.cobblemon.mod.common.api.pokeball.catching.calculators.CriticalCaptur
|
||||
import com.cobblemon.mod.common.api.pokeball.catching.calculators.PokedexProgressCaptureMultiplierProvider
|
||||
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.BurnStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.FrozenStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.ParalysisStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonBadlyStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.SleepStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.BurnStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.FrozenStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.ParalysisStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.PoisonBadlyStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.PoisonStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.SleepStatus
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.random.Random
|
||||
|
||||
+6
-6
@@ -15,12 +15,12 @@ import com.cobblemon.mod.common.api.pokeball.catching.calculators.CriticalCaptur
|
||||
import com.cobblemon.mod.common.api.pokeball.catching.calculators.PokedexProgressCaptureMultiplierProvider
|
||||
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.BurnStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.FrozenStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.ParalysisStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonBadlyStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.SleepStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.BurnStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.FrozenStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.ParalysisStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.PoisonBadlyStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.PoisonStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.SleepStatus
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.random.Random
|
||||
|
||||
+6
-6
@@ -13,12 +13,12 @@ import com.cobblemon.mod.common.api.pokeball.catching.calculators.CaptureCalcula
|
||||
import com.cobblemon.mod.common.api.pokeball.catching.calculators.CriticalCaptureProvider
|
||||
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.BurnStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.FrozenStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.ParalysisStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonBadlyStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.SleepStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.BurnStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.FrozenStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.ParalysisStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.PoisonBadlyStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.PoisonStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.SleepStatus
|
||||
import kotlin.math.max
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
+6
-6
@@ -14,12 +14,12 @@ import com.cobblemon.mod.common.api.pokeball.catching.calculators.CriticalCaptur
|
||||
import com.cobblemon.mod.common.api.pokeball.catching.calculators.PokedexProgressCaptureMultiplierProvider
|
||||
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.BurnStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.FrozenStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.ParalysisStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonBadlyStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.SleepStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.BurnStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.FrozenStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.ParalysisStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.PoisonBadlyStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.PoisonStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.SleepStatus
|
||||
import kotlin.math.max
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@@ -34,6 +34,7 @@ import com.cobblemon.mod.common.api.pokemon.experience.ExperienceSource
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeature
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.SynchronizedSpeciesFeature
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.SynchronizedSpeciesFeatureProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.friendship.FriendshipMutationCalculator
|
||||
import com.cobblemon.mod.common.api.pokemon.labels.CobblemonPokemonLabels
|
||||
import com.cobblemon.mod.common.api.pokemon.moves.LearnsetQuery
|
||||
@@ -426,6 +427,8 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
|
||||
// We want non-optional evolutions to trigger first to avoid unnecessary packets and any cost associate with an optional one that would just be lost
|
||||
val evolutions: Iterable<Evolution> get() = this.form.evolutions.sortedBy { evolution -> evolution.optional }
|
||||
val lockedEvolutions: Iterable<Evolution>
|
||||
get() = evolutions.filter { it !in evolutionProxy.current() }
|
||||
|
||||
val preEvolution: PreEvolution? get() = this.form.preEvolution
|
||||
|
||||
@@ -470,7 +473,11 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
SeasonFeatureHandler.updateSeason(this, level, position.toBlockPos())
|
||||
val entity = PokemonEntity(level, this)
|
||||
illusion?.start(entity)
|
||||
entity.setPositionSafely(position)
|
||||
val sentOut = entity.setPositionSafely(position)
|
||||
//If sendout failed, fall back
|
||||
if (!sentOut) {
|
||||
entity.setPos(position.x, position.y, position.z)
|
||||
}
|
||||
mutation(entity)
|
||||
level.spawnEntity(entity)
|
||||
state = SentOutState(entity)
|
||||
@@ -1584,7 +1591,7 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
}
|
||||
}
|
||||
|
||||
private val _form = SimpleObservable<FormData>()
|
||||
private val _form = registerObservable(SimpleObservable<FormData>()) { FormUpdatePacket({ this }, it) }
|
||||
private val _species = registerObservable(SimpleObservable<Species>()) { SpeciesUpdatePacket({ this }, it) }
|
||||
private val _nickname = registerObservable(SimpleObservable<MutableText?>()) { NicknameUpdatePacket({ this }, it) }
|
||||
private val _experience = registerObservable(SimpleObservable<Int>()) { ExperienceUpdatePacket({ this }, it) }
|
||||
@@ -1612,7 +1619,8 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
private val _originalTrainerName = registerObservable(SimpleObservable<String?>()) { OriginalTrainerUpdatePacket({ this }, it) }
|
||||
|
||||
private val _features = registerObservable(SimpleObservable<SpeciesFeature>()) {
|
||||
if (it is SynchronizedSpeciesFeature) {
|
||||
val featureProvider = SpeciesFeatures.getFeature(it.name)
|
||||
if (it is SynchronizedSpeciesFeature && featureProvider is SynchronizedSpeciesFeatureProvider && featureProvider.visible) {
|
||||
SpeciesFeatureUpdatePacket({ this }, species.resourceIdentifier, it)
|
||||
} else {
|
||||
null
|
||||
|
||||
+2
@@ -43,6 +43,8 @@ object CobblemonRequirementAdapter : RequirementAdapter {
|
||||
this.registerType(TimeRangeRequirement.ADAPTER_VARIANT, TimeRangeRequirement::class)
|
||||
this.registerType(LevelRequirement.ADAPTER_VARIANT, LevelRequirement::class)
|
||||
this.registerType(WeatherRequirement.ADAPTER_VARIANT, WeatherRequirement::class)
|
||||
this.registerType(StatCompareRequirement.ADAPTER_VARIANT, StatCompareRequirement::class)
|
||||
this.registerType(StatEqualRequirement.ADAPTER_VARIANT, StatEqualRequirement::class)
|
||||
this.registerType(AttackDefenceRatioRequirement.ADAPTER_VARIANT, AttackDefenceRatioRequirement::class)
|
||||
this.registerType(BattleCriticalHitsRequirement.ADAPTER_VARIANT, BattleCriticalHitsRequirement::class)
|
||||
this.registerType(DamageTakenRequirement.ADAPTER_VARIANT, DamageTakenRequirement::class)
|
||||
|
||||
+1
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.pokemon.evolution.requirements
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.requirement.EvolutionRequirement
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
|
||||
class AttackDefenceRatioRequirement : EvolutionRequirement {
|
||||
companion object {
|
||||
const val ADAPTER_VARIANT = "attack_defence_ratio"
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.pokemon.evolution.requirements
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.requirement.EvolutionRequirement
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
|
||||
class StatCompareRequirement : EvolutionRequirement {
|
||||
companion object {
|
||||
const val ADAPTER_VARIANT = "stat_compare"
|
||||
}
|
||||
|
||||
val highStat = Stats.ATTACK.name
|
||||
val lowStat = Stats.DEFENCE.name
|
||||
|
||||
override fun check(pokemon: Pokemon): Boolean {
|
||||
return pokemon.getStat(Stats.getStat(highStat)) > pokemon.getStat(Stats.getStat(lowStat))
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.pokemon.evolution.requirements
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.requirement.EvolutionRequirement
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
|
||||
class StatEqualRequirement : EvolutionRequirement {
|
||||
companion object {
|
||||
const val ADAPTER_VARIANT = "stat_equal"
|
||||
}
|
||||
|
||||
val statOne = Stats.ATTACK.name
|
||||
val statTwo = Stats.DEFENCE.name
|
||||
|
||||
override fun check(pokemon: Pokemon): Boolean {
|
||||
return pokemon.getStat(Stats.getStat(statOne)) == pokemon.getStat(Stats.getStat(statTwo))
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user