From 7ae58f81d6e3dce15922f670cfcbd07e8108e642 Mon Sep 17 00:00:00 2001
From: Kris Johnson <11083252+KrisXV@users.noreply.github.com>
Date: Fri, 13 Dec 2024 14:48:39 -0700
Subject: [PATCH] Mix and Mega: Fix exploit with Pokemon using their native
 mega stones

---
 config/formats.ts                 | 38 ++++++++++---------------
 data/mods/mixandmega/scripts.ts   | 46 +++++++++++++------------------
 server/chat-plugins/othermetas.ts |  4 +--
 3 files changed, 35 insertions(+), 53 deletions(-)

diff --git a/config/formats.ts b/config/formats.ts
index 423b8060a5b4..25ab240a28bd 100644
--- a/config/formats.ts
+++ b/config/formats.ts
@@ -562,11 +562,10 @@ export const Formats: import('../sim/dex-formats').FormatList = [
 			}
 		},
 		onSwitchIn(pokemon) {
-			// @ts-ignore
-			const originalFormeSecies = this.dex.species.get(pokemon.species.originalSpecies);
-			if (originalFormeSecies.exists && pokemon.m.originalSpecies !== originalFormeSecies.baseSpecies) {
+			const originalFormeSpecies = this.dex.species.get((pokemon.species as any).originalSpecies);
+			if (originalFormeSpecies.exists && pokemon.m.originalSpecies !== originalFormeSpecies.baseSpecies) {
 				// Place volatiles on the Pokémon to show its mega-evolved condition and details
-				this.add('-start', pokemon, originalFormeSecies.requiredItem || originalFormeSecies.requiredMove, '[silent]');
+				this.add('-start', pokemon, originalFormeSpecies.requiredItem || originalFormeSpecies.requiredMove, '[silent]');
 				const oSpecies = this.dex.species.get(pokemon.m.originalSpecies);
 				if (oSpecies.types.length !== pokemon.species.types.length || oSpecies.types[1] !== pokemon.species.types[1]) {
 					this.add('-start', pokemon, 'typechange', pokemon.species.types.join('/'), '[silent]');
@@ -574,8 +573,7 @@ export const Formats: import('../sim/dex-formats').FormatList = [
 			}
 		},
 		onSwitchOut(pokemon) {
-			// @ts-ignore
-			const oMegaSpecies = this.dex.species.get(pokemon.species.originalSpecies);
+			const oMegaSpecies = this.dex.species.get((pokemon.species as any).originalSpecies);
 			if (oMegaSpecies.exists && pokemon.m.originalSpecies !== oMegaSpecies.baseSpecies) {
 				this.add('-end', pokemon, oMegaSpecies.requiredItem || oMegaSpecies.requiredMove, '[silent]');
 			}
@@ -816,8 +814,7 @@ export const Formats: import('../sim/dex-formats').FormatList = [
 				if (pokemon.pokeball.includes('0')) {
 					const donor = pokemon.pokeball.split('0')[1];
 					pokemon.m.donor = this.toID(donor);
-					// @ts-ignore
-					pokemon.pokeball = this.toID(pokemon.pokeball.split('0')[0]);
+					(pokemon as any).pokeball = this.toID(pokemon.pokeball.split('0')[0]);
 				}
 			}
 		},
@@ -878,11 +875,10 @@ export const Formats: import('../sim/dex-formats').FormatList = [
 			}
 		},
 		onSwitchIn(pokemon) {
-			// @ts-ignore
-			const originalFormeSecies = this.dex.species.get(pokemon.species.originalSpecies);
-			if (originalFormeSecies.exists && pokemon.m.originalSpecies !== originalFormeSecies.baseSpecies) {
+			const originalFormeSpecies = this.dex.species.get((pokemon.species as any).originalSpecies);
+			if (originalFormeSpecies.exists && pokemon.m.originalSpecies !== originalFormeSpecies.baseSpecies) {
 				// Place volatiles on the Pokémon to show its mega-evolved condition and details
-				this.add('-start', pokemon, originalFormeSecies.requiredItem || originalFormeSecies.requiredMove, '[silent]');
+				this.add('-start', pokemon, originalFormeSpecies.requiredItem || originalFormeSpecies.requiredMove, '[silent]');
 				const oSpecies = this.dex.species.get(pokemon.m.originalSpecies);
 				if (oSpecies.types.length !== pokemon.species.types.length || oSpecies.types[1] !== pokemon.species.types[1]) {
 					this.add('-start', pokemon, 'typechange', pokemon.species.types.join('/'), '[silent]');
@@ -890,8 +886,7 @@ export const Formats: import('../sim/dex-formats').FormatList = [
 			}
 		},
 		onSwitchOut(pokemon) {
-			// @ts-ignore
-			const oMegaSpecies = this.dex.species.get(pokemon.species.originalSpecies);
+			const oMegaSpecies = this.dex.species.get((pokemon.species as any).originalSpecies);
 			if (oMegaSpecies.exists && pokemon.m.originalSpecies !== oMegaSpecies.baseSpecies) {
 				this.add('-end', pokemon, oMegaSpecies.requiredItem || oMegaSpecies.requiredMove, '[silent]');
 			}
@@ -1147,15 +1142,12 @@ export const Formats: import('../sim/dex-formats').FormatList = [
 			}
 		},
 		checkCanLearn(move, species, lsetData, set) {
-			// @ts-ignore
-			if (!set.sp?.exists || !set.crossSpecies?.exists) {
+			if (!(set as any).sp?.exists || !(set as any).crossSpecies?.exists) {
 				return this.checkCanLearn(move, species, lsetData, set);
 			}
-			// @ts-ignore
-			const problem = this.checkCanLearn(move, set.sp);
+			const problem = this.checkCanLearn(move, (set as any).sp);
 			if (!problem) return null;
-			// @ts-ignore
-			if (this.checkCanLearn(move, set.crossSpecies)) return problem;
+			if (this.checkCanLearn(move, (set as any).crossSpecies)) return problem;
 			return null;
 		},
 		validateSet(set, teamHas) {
@@ -1198,10 +1190,8 @@ export const Formats: import('../sim/dex-formats').FormatList = [
 				set.species = crossSpecies.name;
 			}
 
-			// @ts-ignore
-			set.sp = species;
-			// @ts-ignore
-			set.crossSpecies = crossSpecies;
+			(set as any).sp = species;
+			(set as any).crossSpecies = crossSpecies;
 			problems = this.validateSet(set, teamHas);
 			set.name = crossSpecies.name;
 			set.species = species.name;
diff --git a/data/mods/mixandmega/scripts.ts b/data/mods/mixandmega/scripts.ts
index 57afd6d9f06e..a8f591b12c5b 100644
--- a/data/mods/mixandmega/scripts.ts
+++ b/data/mods/mixandmega/scripts.ts
@@ -63,8 +63,7 @@ export const Scripts: ModdedBattleScriptsData = {
 				'adamantcrystal', 'griseouscore', 'lustrousglobe', 'wellspringmask',
 				'cornerstonemask', 'hearthflamemask', 'vilevial',
 			].includes(item.id) && item.forcedForme !== pokemon.species.name) {
-				// @ts-ignore
-				const rawSpecies = this.actions.getMixedSpecies(pokemon.m.originalSpecies, item.forcedForme!, pokemon);
+				const rawSpecies = (this.actions as any).getMixedSpecies(pokemon.m.originalSpecies, item.forcedForme!, pokemon);
 				const species = pokemon.setSpecies(rawSpecies);
 				if (!species) continue;
 				pokemon.baseSpecies = rawSpecies;
@@ -111,11 +110,9 @@ export const Scripts: ModdedBattleScriptsData = {
 				let rawSpecies: Species | null = null;
 				const item = pokemon.getItem();
 				if (item.id === 'rustedsword') {
-					// @ts-ignore
-					rawSpecies = this.actions.getMixedSpecies(pokemon.m.originalSpecies, 'Zacian-Crowned', pokemon);
+					rawSpecies = (this.actions as any).getMixedSpecies(pokemon.m.originalSpecies, 'Zacian-Crowned', pokemon);
 				} else if (item.id === 'rustedshield') {
-					// @ts-ignore
-					rawSpecies = this.actions.getMixedSpecies(pokemon.m.originalSpecies, 'Zamazenta-Crowned', pokemon);
+					rawSpecies = (this.actions as any).getMixedSpecies(pokemon.m.originalSpecies, 'Zamazenta-Crowned', pokemon);
 				}
 				if (!rawSpecies) continue;
 				const species = pokemon.setSpecies(rawSpecies);
@@ -411,22 +408,20 @@ export const Scripts: ModdedBattleScriptsData = {
 		runMegaEvo(pokemon) {
 			if (pokemon.species.isMega) return false;
 
-			// @ts-ignore
-			const species: Species = this.getMixedSpecies(pokemon.m.originalSpecies, pokemon.canMegaEvo, pokemon);
+			const species: Species = (this as any).getMixedSpecies(pokemon.m.originalSpecies, pokemon.canMegaEvo, pokemon);
 
-			// Do we have a proper sprite for it?
+			/* Do we have a proper sprite for it? Code for when megas actually exist
 			if (this.dex.species.get(pokemon.canMegaEvo!).baseSpecies === pokemon.m.originalSpecies) {
 				pokemon.formeChange(species, pokemon.getItem(), true);
-			} else {
-				const oSpecies = this.dex.species.get(pokemon.m.originalSpecies);
-				// @ts-ignore
-				const oMegaSpecies = this.dex.species.get(species.originalSpecies);
-				pokemon.formeChange(species, pokemon.getItem(), true);
-				this.battle.add('-start', pokemon, oMegaSpecies.requiredItem, '[silent]');
-				if (oSpecies.types.length !== pokemon.species.types.length || oSpecies.types[1] !== pokemon.species.types[1]) {
-					this.battle.add('-start', pokemon, 'typechange', pokemon.species.types.join('/'), '[silent]');
-				}
+			} else { */
+			const oSpecies = this.dex.species.get(pokemon.m.originalSpecies);
+			const oMegaSpecies = this.dex.species.get((species as any).originalSpecies);
+			pokemon.formeChange(species, pokemon.getItem(), true);
+			this.battle.add('-start', pokemon, oMegaSpecies.requiredItem, '[silent]');
+			if (oSpecies.types.length !== pokemon.species.types.length || oSpecies.types[1] !== pokemon.species.types[1]) {
+				this.battle.add('-start', pokemon, 'typechange', pokemon.species.types.join('/'), '[silent]');
 			}
+			// }
 
 			pokemon.canMegaEvo = null;
 			return true;
@@ -456,12 +451,10 @@ export const Scripts: ModdedBattleScriptsData = {
 				pokemon.formeChange(pokemon.species.id + tera, pokemon.getItem(), true);
 			} else {
 				if (pokemon.getItem().name.endsWith('Mask')) {
-					// @ts-ignore
-					const species: Species = this.getMixedSpecies(pokemon.m.originalSpecies,
+					const species: Species = (this as any).getMixedSpecies(pokemon.m.originalSpecies,
 						pokemon.getItem().forcedForme! + '-Tera', pokemon);
 					const oSpecies = this.dex.species.get(pokemon.m.originalSpecies);
-					// @ts-ignore
-					const originalTeraSpecies = this.dex.species.get(species.originalSpecies);
+					const originalTeraSpecies = this.dex.species.get((species as any).originalSpecies);
 					pokemon.formeChange(species, pokemon.getItem(), true);
 					this.battle.add('-start', pokemon, originalTeraSpecies.requiredItem, '[silent]');
 					if (oSpecies.types.length !== pokemon.species.types.length || oSpecies.types[1] !== pokemon.species.types[1]) {
@@ -477,11 +470,10 @@ export const Scripts: ModdedBattleScriptsData = {
 		getMixedSpecies(originalForme, megaForme, pokemon) {
 			const originalSpecies = this.dex.species.get(originalForme);
 			const megaSpecies = this.dex.species.get(megaForme);
-			if (originalSpecies.baseSpecies === megaSpecies.baseSpecies) return megaSpecies;
-			// @ts-ignore
-			const deltas = this.getFormeChangeDeltas(megaSpecies, pokemon);
-			// @ts-ignore
-			const species = this.mutateOriginalSpecies(originalSpecies, deltas);
+			// Uncomment if actual megas ever exist again
+			// if (originalSpecies.baseSpecies === megaSpecies.baseSpecies) return megaSpecies;
+			const deltas = (this as any).getFormeChangeDeltas(megaSpecies, pokemon);
+			const species = (this as any).mutateOriginalSpecies(originalSpecies, deltas);
 			return species;
 		},
 		getFormeChangeDeltas(formeChangeSpecies, pokemon) {
diff --git a/server/chat-plugins/othermetas.ts b/server/chat-plugins/othermetas.ts
index c23eff8048a5..579311408f24 100644
--- a/server/chat-plugins/othermetas.ts
+++ b/server/chat-plugins/othermetas.ts
@@ -275,7 +275,7 @@ export const commands: Chat.ChatCommands = {
 			const deltas: StoneDeltas = {
 				baseStats: Object.create(null),
 				weighthg: megaSpecies.weighthg - baseSpecies.weighthg,
-				heightm: megaSpecies.heightm - baseSpecies.heightm,
+				heightm: ((megaSpecies.heightm * 10) - (baseSpecies.heightm * 10)) / 10,
 				bst: megaSpecies.bst - baseSpecies.bst,
 			};
 			let statId: StatID;
@@ -340,7 +340,7 @@ export const commands: Chat.ChatCommands = {
 			buf += `</span>`;
 			buf += `</li>`;
 			this.sendReply(`|raw|<div class="message"><ul class="utilichart">${buf}<li style="clear:both"></li></ul></div>`);
-			this.sendReply(`|raw|<font size="1"><font color="#686868">Gen:</font> ${details["Gen"]}&nbsp;|&ThickSpace;<font color="#686868">Weight:</font> ${details["Weight"]}</font>`);
+			this.sendReply(`|raw|<font size="1">${Object.entries(details).map(([detail, value]) => `<font color="#686868">${detail}:</font> ${value}`).join("&nbsp;|&ThickSpace;")}</font>`);
 		}
 	},
 	stonehelp: [`/stone <mega stone or other>[, generation] - Shows the changes that a mega stone/orb applies to a Pok\u00e9mon.`],