1+ package generations.gg.generations.core.generationscore.common.battle
2+
3+ import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
4+ import com.cobblemon.mod.common.api.battles.model.PokemonBattle
5+ import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
6+ import com.cobblemon.mod.common.battles.BattleSide
7+ import com.cobblemon.mod.common.battles.actor.PlayerBattleActor
8+ import com.cobblemon.mod.common.battles.actor.PokemonBattleActor
9+ import com.cobblemon.mod.common.battles.actor.TrainerBattleActor
10+ import com.cobblemon.mod.common.entity.npc.NPCBattleActor
11+ import com.cobblemon.mod.common.util.getPlayer
12+ import generations.gg.generations.core.generationscore.common.network.packets.BattleConditionsPacket
13+ import java.util.UUID
14+
15+ object BattleConditionsProcessor {
16+ val conditionsDataMap = mutableMapOf<UUID , ConditionsData >()
17+
18+ @JvmStatic
19+ fun processAbility (battle : PokemonBattle , message : BattleMessage ) {
20+ val conditionsData = conditionsDataMap[battle.battleId]
21+
22+ val abilityName = message.effectAt(1 )?.id ? : return
23+
24+ var neutGasPresent = false
25+ battle.activePokemon.forEach { activePokemon ->
26+ val abilityName = activePokemon.battlePokemon?.originalPokemon?.ability?.name ? : return
27+ if (abilityName.isNeutGas()) neutGasPresent = true
28+ }
29+
30+ if (conditionsData != null ) {
31+ val originalDisabled = conditionsData.weatherTracker.disabled
32+
33+ if (abilityName.canDisableWeather() && ! neutGasPresent) {
34+ conditionsData.weatherTracker.disabled = true
35+ } else {
36+ conditionsData.weatherTracker.disabled = false
37+ }
38+
39+ if (conditionsData.weatherTracker.disabled != originalDisabled) {
40+ battle.sendToPlayersAndSpectators()
41+ }
42+ }
43+ }
44+
45+ @JvmStatic
46+ fun processWeatherDisabling (battle : PokemonBattle ) {
47+ val conditionsData = conditionsDataMap[battle.battleId]
48+ var neutGasPresent = false
49+ var weatherDisablingAbility = false
50+ if (conditionsData != null ) {
51+ battle.activePokemon.forEach { activePokemon ->
52+ val abilityName = activePokemon.battlePokemon?.originalPokemon?.ability?.name ? : return
53+ if (abilityName.isNeutGas()) neutGasPresent = true
54+ if (abilityName.canDisableWeather()) weatherDisablingAbility = true
55+ }
56+
57+ val originalDisabled = conditionsData.weatherTracker.disabled
58+
59+ if (weatherDisablingAbility && ! neutGasPresent) {
60+ conditionsData.weatherTracker.disabled = true
61+ } else {
62+ conditionsData.weatherTracker.disabled = false
63+ }
64+
65+ if (conditionsData.weatherTracker.disabled != originalDisabled) {
66+ battle.sendToPlayersAndSpectators()
67+ }
68+ }
69+ }
70+
71+ @JvmStatic
72+ fun processFieldStart (battle : PokemonBattle , message : BattleMessage ): String {
73+ val conditionsData = conditionsDataMap[battle.battleId]
74+
75+ val effect = processFieldMessage(message)
76+
77+ conditionsData?.fieldList?.removeIf { it.first.contains(" Terrain" ) }
78+ conditionsData?.fieldList?.add(effect to 0 ) ? : return " "
79+
80+ battle.sendToPlayersAndSpectators()
81+
82+ return effect
83+ }
84+
85+ @JvmStatic
86+ fun processFieldEnd (battle : PokemonBattle , message : BattleMessage ) {
87+ val conditionsData = conditionsDataMap[battle.battleId]
88+ val effect = processFieldMessage(message)
89+ if (conditionsData != null ) {
90+ conditionsData.fieldList.removeIf { it.first == effect }
91+ battle.sendToPlayersAndSpectators()
92+ }
93+ }
94+
95+ @JvmStatic
96+ fun processSideStart (battle : PokemonBattle , message : BattleMessage ) {
97+ val conditionsData = conditionsDataMap[battle.battleId]
98+ val sidePair = processSideMessage(message)
99+
100+ if (sidePair.first == " " || sidePair.second == " " ) return
101+
102+ val pSideRaw = sidePair.first
103+ val sideEffect = sidePair.second
104+
105+ val pSide = pSideRaw.take(2 ).substring(1 )
106+ val pUUID = pSideRaw.substring(2 ).toUUIDFromPlainString()
107+ var playerName = " Unknown"
108+
109+ for (actor in battle.actors) {
110+ if (actor.uuid == pUUID) {
111+ playerName = actor.getTypeName()
112+ break
113+ }
114+ }
115+
116+ if (conditionsData != null ) {
117+ val existing = conditionsData.sideList.find { it.side == pSide && it.effect == sideEffect }
118+ if (existing != null ) {
119+ when (sideEffect) {
120+ " Spikes" , " Toxic Spikes" -> {
121+ existing.layers++
122+ }
123+ }
124+ } else {
125+ val newData = BattleSideData (pSide, playerName, sideEffect, 0 , 0 )
126+ if (sideEffect == " Spikes" || sideEffect == " Toxic Spikes" ) {
127+ newData.layers = 1
128+ }
129+ conditionsData.sideList.add(newData)
130+ }
131+
132+ battle.sendToPlayersAndSpectators()
133+ }
134+ }
135+
136+ @JvmStatic
137+ fun processSideEnd (battle : PokemonBattle , message : BattleMessage ) {
138+ val conditionsData = conditionsDataMap[battle.battleId]
139+ val sidePair = processSideMessage(message)
140+ val pSide = sidePair.first.take(2 ).substring(1 )
141+ val sideEffect = sidePair.second
142+ if (conditionsData != null ) {
143+ for (sideData in conditionsData.sideList) {
144+ if (sideData.side == pSide && sideData.effect == sideEffect) {
145+ conditionsData.sideList.remove(sideData)
146+ battle.sendToPlayersAndSpectators()
147+ break
148+ }
149+ }
150+ }
151+ }
152+
153+ @JvmStatic
154+ fun processSwapSideConditions (battle : PokemonBattle ) {
155+ val conditionsData = conditionsDataMap[battle.battleId] ? : return
156+
157+ for (sideData in conditionsData.sideList) {
158+ when (sideData.side) {
159+ " 1" -> {
160+ sideData.side = " 2"
161+ sideData.playerName = getPlayerNameBySide(battle, battle.side2) ? : sideData.playerName
162+ }
163+
164+ " 2" -> {
165+ sideData.side = " 1"
166+ sideData.playerName = getPlayerNameBySide(battle, battle.side1) ? : sideData.playerName
167+ }
168+ }
169+ }
170+
171+ battle.sendToPlayersAndSpectators()
172+ }
173+
174+ @JvmStatic
175+ fun updateCounters (battle : PokemonBattle ) {
176+ val conditionsData = conditionsDataMap[battle.battleId]
177+ if (conditionsData != null ) {
178+ if (conditionsData.weatherTracker.weather != " " ) {
179+ conditionsData.weatherTracker.turns++
180+ }
181+
182+ for ((index, effectPair) in conditionsData.fieldList.withIndex()) {
183+ conditionsData.fieldList[index] = effectPair.first to (effectPair.second + 1 )
184+ }
185+
186+ for ((index, sideData) in conditionsData.sideList.withIndex()) {
187+ if (! (sideData.effect.contains(" Spikes" ) || sideData.effect == " Sticky Web" || sideData.effect == " Stealth Rock" )) {
188+ conditionsData.sideList[index].turnCounter++
189+ }
190+ }
191+
192+ var neutGasPresent = false
193+ var weatherDisablingAbility = false
194+ battle.activePokemon.forEach { activePokemon ->
195+ val abilityName = activePokemon.battlePokemon?.originalPokemon?.ability?.name ? : return
196+ if (abilityName.isNeutGas()) neutGasPresent = true
197+ if (abilityName.canDisableWeather()) weatherDisablingAbility = true
198+ }
199+
200+ if (weatherDisablingAbility && ! neutGasPresent) {
201+ conditionsData.weatherTracker.disabled = true
202+ } else {
203+ conditionsData.weatherTracker.disabled = false
204+ }
205+
206+ battle.sendToPlayersAndSpectators()
207+ }
208+ }
209+
210+ @JvmStatic
211+ fun processWeatherTurns (battle : PokemonBattle , message : BattleMessage ) {
212+ val conditionsData = conditionsDataMap[battle.battleId]
213+ val weatherRaw = message.effectAt(0 )?.id ? : return
214+ val weather = when (weatherRaw) {
215+ " raindance" -> " Rain"
216+ " sunnyday" -> " Sun"
217+ " sandstorm" -> " Sand"
218+ " hail" -> " Hail"
219+ " snow" -> " Snow"
220+ " deltastream" -> " Delta Stream"
221+ " desolateland" -> " Desolate Land"
222+ " primordialsea" -> " Primordial Sea"
223+
224+ else -> weatherRaw
225+ }
226+
227+ val weatherTracker = conditionsData?.weatherTracker ? : return
228+ weatherTracker.upkeep = message.hasOptionalArgument(" upkeep" )
229+
230+ if (weatherTracker.weather != weather) {
231+ weatherTracker.weather = weather
232+ weatherTracker.turns = 0
233+ battle.sendToPlayersAndSpectators()
234+ }
235+ }
236+
237+ @JvmStatic
238+ fun processBattleEnd (battle : PokemonBattle ) {
239+ conditionsDataMap.remove(battle.battleId)
240+ }
241+
242+ fun processFieldMessage (message : BattleMessage ): String {
243+ val effectRaw = message.effectAt(0 )?.id ? : return " "
244+ return when {
245+ effectRaw.endsWith(" terrain" ) -> {
246+ val name = effectRaw.removeSuffix(" terrain" ).replaceFirstChar { it.uppercaseChar() }
247+ " $name Terrain"
248+ }
249+
250+ effectRaw == " gravity" -> " Gravity"
251+
252+ effectRaw.endsWith(" room" ) -> {
253+ val name = effectRaw.removeSuffix(" room" ).replaceFirstChar { it.uppercaseChar() }
254+ " $name Room"
255+ }
256+
257+ else -> effectRaw
258+ }
259+ }
260+
261+ fun processSideMessage (message : BattleMessage ): Pair <String , String > {
262+ val pSideRaw = message.effectAt(0 )?.id ? : return " " to " "
263+ val rawEffect = message.effectAt(1 )?.id ? : return " " to " "
264+ val sideEffect = when (rawEffect) {
265+ " spikes" -> " Spikes"
266+ " stealthrock" -> " Stealth Rock"
267+ " stickyweb" -> " Sticky Web"
268+ " toxicspikes" -> " Toxic Spikes"
269+
270+ " auroraveil" -> " Aurora Veil"
271+ " lightscreen" -> " Light Screen"
272+ " reflect" -> " Reflect"
273+
274+ " luckychant" -> " Lucky Chant"
275+ " safeguard" -> " Safeguard"
276+ " tailwind" -> " Tailwind"
277+
278+ else -> rawEffect
279+ }
280+ return pSideRaw to sideEffect
281+ }
282+
283+ fun String.toUUIDFromPlainString (): UUID {
284+ return UUID .fromString(
285+ " ${this .substring(0 , 8 )} -${this .substring(8 , 12 )} -${this .substring(12 , 16 )} -${
286+ this .substring(
287+ 16 ,
288+ 20
289+ )
290+ } -${this .substring(20 )} "
291+ )
292+ }
293+
294+ fun String.canDisableWeather (): Boolean {
295+ return this == " airlock" || this == " cloudnine"
296+ }
297+
298+ fun String.isNeutGas (): Boolean {
299+ return this == " neutralizinggas"
300+ }
301+
302+ fun PokemonBattle.sendToPlayersAndSpectators () {
303+ val conditionsData = conditionsDataMap[this .battleId] ? : return
304+ this .sendToActors(BattleConditionsPacket (true , conditionsData.copy()))
305+ this .sendSpectatorUpdate(BattleConditionsPacket (false , conditionsData.copy()))
306+ }
307+
308+ fun getPlayerNameBySide (battle : PokemonBattle , side : BattleSide ): String? {
309+ for (actor in battle.actors) {
310+ if (side.actors.contains(actor)) {
311+ return actor.getTypeName()
312+ }
313+ }
314+ return null
315+ }
316+
317+ fun BattleActor.getTypeName (): String {
318+ return when (this ) {
319+ is PlayerBattleActor -> this .uuid.getPlayer()?.name?.string ? : " Unknown"
320+ is PokemonBattleActor -> this .pokemon.originalPokemon.species.name
321+ is TrainerBattleActor -> this .trainerName
322+ is NPCBattleActor -> this .npc.name.string ? : " Unknown"
323+ else -> " Unknown"
324+ }
325+ }
326+ }
0 commit comments