export const Moves: {[k: string]: ModdedMoveData} = {
	toxicthread: {
		num: 672,
		accuracy: 100,
		basePower: 0,
		category: "Status",
		shortDesc: "Badly poisons and lowers the target's Speed by 2",
		name: "Toxic Thread",
		pp: 20,
		priority: 0,
		flags: {protect: 1, reflectable: 1, mirror: 1},
		status: 'tox',
		boosts: {
			spe: -2,
		},
		secondary: null,
		target: "normal",
		type: "Poison",
		zMove: {boost: {spe: 1}},
		contestType: "Tough",
	},
	meltingpoint: {
		accuracy: 100,
		basePower: 80,
		category: "Special",
		shortDesc: "Replaces the user's Ice-type with Water. 1.5x power when used by Ice-types. Soaks foe.",
		name: "Melting Point",
		pp: 10,
		priority: 0,
		flags: {protect: 1, mirror: 1, defrost: 1},
		onPrepareHit(target, source, move) {
			this.attrLastMove('[still]');
			this.add('-anim', source, "Scald", target);
			this.add('-anim', source, "Acid Armor", target);
		},
		onBasePower(basePower, pokemon, target) {
			if (pokemon.hasType('Ice')) {
				return this.chainModify(1.5);
			}
		},
		onHit(target) {
			if (target.getTypes().join() === 'Water' || !target.setType('Water')) {
				// Soak should animate even when it fails.
				// Returning false would suppress the animation.
				this.add('-fail', target);
				return null;
			}
			this.add('-start', target, 'typechange', 'Water');
		},
		self: {
			onHit(pokemon) {
				if (pokemon.hasType('Water')) {
					pokemon.setType(pokemon.getTypes(true).map(type => type === "Ice" ? "???" : type));
					this.add('-start', pokemon, 'typechange', pokemon.types.join('/'), '[from] move: Melting Point');
				} else {
					pokemon.setType(pokemon.getTypes(true).map(type => type === "Ice" ? "Water" : type));
					this.add('-start', pokemon, 'typechange', pokemon.types.join('/'), '[from] move: Melting Point');
				}
			},
		},
		secondary: null,
		target: "normal",
		type: "Water",
		contestType: "Clever",
	},
	/*
	reconstruct: {
		accuracy: true,
		basePower: 0,
		category: "Status",
		shortDesc: "(Bugged) Charges turn 1. Heals 50% and resets lowered stats turn 2.",
		name: "Reconstruct",
		pp: 10,
		priority: 0,
		flags: {charge: 1, heal: 1},
		heal: [1, 2],
		beforeTurnCallback(pokemon) {
			pokemon.addVolatile('reconstruct');
		},
		condition: {
			duration: 2,
			onStart(pokemon) {
				this.add('-start', pokemon, 'move: Reconstruct');
			},
			onSourceModifyDamage(damage, source, target, move) {
				if (move.category === 'Special' || move.category === 'Physical') {
					return this.chainModify(0.5);
				}
			},
			onTryMove(attacker, defender, move) {
				if (attacker.removeVolatile(move.id)) return;
				this.add('-prepare', attacker, move.name);
				if (!this.runEvent('ChargeMove', attacker, defender, move)) return;
				attacker.addVolatile('twoturnmove', defender);
				return null;
			},
		},
		onAfterMove(pokemon) {
			pokemon.removeVolatile('reconstruct');
		},
		self: {
			onHit(pokemon) {
				const boosts: SparseBoostsTable = {};
				let i: BoostName;
				for (i in pokemon.boosts) {
					if (pokemon.boosts[i] < 0) {
						boosts[i] = 0;
					}
				}
				pokemon.setBoost(boosts);
				this.add('-clearnegativeboost', pokemon, '[silent]');
				this.add('-message', pokemon.name + "'s negative stat changes were removed!");
			},
		},
		secondary: null,
		target: "self",
		type: "Steel",
	},
	reconstruct: {
		accuracy: true,
		basePower: 0,
		category: "Status",
		shortDesc: "Charges turn 1. Heals 50% and resets lowered stats turn 2.",
		name: "Reconstruct",
		pp: 10,
		priority: 0,
		flags: {charge: 1, heal: 1},
		heal: [1, 2],
		onTryMove(attacker, defender, move) {
			if (attacker.removeVolatile(move.id)) {
				return;
			}
			this.add('-prepare', attacker, move.name);
			if (!this.runEvent('ChargeMove', attacker, defender, move)) {
				return;
			}
			attacker.addVolatile('twoturnmove', defender);
			return null;
		},
		self: {
			onHit(pokemon) {
				const boosts: SparseBoostsTable = {};
				let i: BoostName;
				for (i in pokemon.boosts) {
					if (pokemon.boosts[i] < 0) {
						boosts[i] = 0;
					}
				}
				pokemon.setBoost(boosts);
				this.add('-clearnegativeboost', pokemon, '[silent]');
				this.add('-message', pokemon.name + "'s negative stat changes were removed!");
			},
		},
		secondary: null,
		target: "self",
		type: "Steel",
	},
	*/
	reconstruct: {
		accuracy: true,
		basePower: 0,
		category: "Status",
		shortDesc: "Charges turn 1. Heals 50% and resets lowered stats turn 2.",
		name: "Reconstruct",
		pp: 10,
		priority: 5,
		flags: {charge: 1, heal: 1},
		volatileStatus: 'reconstruct',
		onPrepareHit(target, source, move) {
			this.attrLastMove('[still]');
			this.add('-anim', source, "Recover", target);
		},
		beforeMoveCallback(pokemon) {
			if (pokemon.volatiles['reconstruct']) return true;
		},
		condition: {
			duration: 2,
			onLockMove: 'reconstruct',
			onStart(pokemon) {
				this.effectState.totalDamage = 0;
				this.add('-start', pokemon, 'move: Reconstruct');
			},
			onSourceModifyDamage(damage, source, target, move) {
				if (move.category === 'Special' || move.category === 'Physical') {
					return this.chainModify(0.5);
				}
			},
			onBeforeMove(pokemon, target, move) {
				if (this.effectState.duration === 1) {
					this.add('-end', pokemon, 'move: Reconstruct');
					const moveData: Partial<ActiveMove> = {
						id: 'reconstruct' as ID,
						name: "Reconstruct",
						accuracy: true,
						category: "Status",
						priority: 0,
						flags: {charge: 1, heal: 1},
						heal: [1, 2],
						effectType: 'Move',
						type: 'Steel',
					};
					this.actions.tryMoveHit(target, pokemon, moveData as ActiveMove);
					return false;
				}
				this.add('-activate', pokemon, 'move: Reconstruct');
			},
			onMoveAborted(pokemon) {
				pokemon.removeVolatile('reconstruct');
			},
			onEnd(pokemon) {
				this.add('-end', pokemon, 'move: Reconstruct', '[silent]');
			},
		},
		self: {
			onHit(pokemon) {
				const boosts: SparseBoostsTable = {};
				let i: BoostID;
				for (i in pokemon.boosts) {
					if (pokemon.boosts[i] < 0) {
						boosts[i] = 0;
					}
				}
				pokemon.setBoost(boosts);
				this.add('-clearnegativeboost', pokemon, '[silent]');
				this.add('-message', pokemon.name + "'s negative stat changes were removed!");
			},
		},
		secondary: null,
		target: "self",
		type: "Steel",
		contestType: "Tough",
	},
	focusblast: {
		num: 411,
		accuracy: 70,
		basePower: 120,
		category: "Special",
		shortDesc: "10% chance to lower the foe's SpD. Never misses if the user moves last.",
		name: "Focus Blast",
		pp: 5,
		priority: 0,
		flags: {bullet: 1, protect: 1, mirror: 1},
		onModifyMove(move, source, target) {
			if (target && (target.newlySwitched || !this.queue.willMove(target))) move.accuracy = true;
		},
		secondary: {
			chance: 10,
			boosts: {
				spd: -1,
			},
		},
		target: "normal",
		type: "Fighting",
		contestType: "Cool",
	},
	/*
	aridabsorption: {
		accuracy: true,
		basePower: 0,
		category: "Status",
		shortDesc: "(Placeholder, Currently a Life Dew clone)",
		name: "Arid Absorption",
		pp: 10,
		priority: 0,
		flags: {snatch: 1, heal: 1},
		onPrepareHit(target, source, move) {
			this.attrLastMove('[still]');
			this.add('-anim', source, "Shore Up", target);
		},
		heal: [1, 4],
		secondary: null,
		target: "self",
		type: "Ground",
	},
*/
	aridabsorption: {
		accuracy: true,
		basePower: 0,
		category: "Status",
		shortDesc: "Heals by 33% of its max HP +33% and +1 Atk for every active Water-type.",
		name: "Arid Absorption",
		pp: 10,
		priority: 0,
		flags: {snatch: 1, heal: 1},
		onPrepareHit(target, source, move) {
			this.attrLastMove('[still]');
			this.add('-anim', source, "Shore Up", target);
		},
		self: {
			onHit(pokemon, source, move) {
				this.heal(source.baseMaxhp / 3, source, pokemon);
			},
		},
		onHitField(target, source) {
			if (target.hasType('Water')) {
				this.heal(source.baseMaxhp / 3, source, target);
				this.boost({atk: 1}, source);
			}
			if (source.hasType('Water')) {
				this.heal(source.baseMaxhp / 3, source, target);
				this.boost({atk: 1}, source);
				this.damage(source.baseMaxhp / 3, source, target);
			}
		},
		secondary: null,
		target: "all",
		type: "Ground",
	},
	rototiller: {
		num: 563,
		accuracy: true,
		basePower: 0,
		category: "Status",
		shortDesc: "Raises Atk/Def of grounded Grass types by 1, sets Grassy Terrain.",
		name: "Rototiller",
		pp: 10,
		priority: 0,
		flags: {distance: 1, nonsky: 1},
		onHitField(target, source) {
			this.field.setTerrain('grassyterrain');
			const targets: Pokemon[] = [];
			let anyAirborne = false;
			for (const pokemon of this.getAllActive()) {
				if (!pokemon.runImmunity('Ground')) {
					this.add('-immune', pokemon);
					anyAirborne = true;
					continue;
				}
				if (pokemon.hasType('Grass')) {
					// This move affects every grounded Grass-type Pokemon in play.
					targets.push(pokemon);
				}
			}
			if (!targets.length && !anyAirborne) return false; // Fails when there are no grounded Grass types or airborne Pokemon
			for (const pokemon of targets) {
				this.boost({atk: 1, def: 1}, pokemon, source);
			}
		},
		secondary: null,
		target: "all",
		type: "Ground",
		zMove: {boost: {atk: 1}},
		contestType: "Tough",
	},
	armthrust: {
		num: 292,
		accuracy: 100,
		basePower: 25,
		category: "Physical",
		name: "Arm Thrust",
		pp: 20,
		priority: 0,
		flags: {contact: 1, protect: 1, mirror: 1, punch: 1},
		multihit: [2, 5],
		secondary: null,
		target: "normal",
		type: "Fighting",
		contestType: "Tough",
	},
	counterspell: {
		accuracy: 100,
		basePower: 110,
		category: "Special",
		shortDesc: "Uses target's SpA stat in damage calculation. -1 priority.",
		name: "Counterspell",
		pp: 15,
		priority: -1,
		flags: {protect: 1, mirror: 1},
		onPrepareHit(target, source, move) {
			this.attrLastMove('[still]');
			this.add('-anim', source, "Psybeam", target);
		},
		overrideOffensivePokemon: 'target',
		secondary: null,
		target: "normal",
		type: "Fairy",
		contestType: "Clever",
	},
	lightninglance: {
		accuracy: 100,
		basePower: 110,
		category: "Physical",
		shortDesc: "Lowers the user's Attack and Sp. Def by 1.",
		name: "Lightning Lance",
		pp: 10,
		priority: 0,
		flags: {contact: 1, protect: 1, mirror: 1, defrost: 1},
		onPrepareHit(target, source, move) {
			this.attrLastMove('[still]');
			this.add('-anim', source, "Charge", target);
			this.add('-anim', source, "Sacred Sword", target);
		},
		self: {
			boosts: {
				atk: -1,
				spd: -1,
			},
		},
		secondary: null,
		target: "normal",
		type: "Electric",
		contestType: "Cool",
	},
	lifedew: {
		num: 791,
		accuracy: true,
		basePower: 0,
		category: "Status",
		shortDesc: "Heals the user by 50% of its max HP; 66% in Rain.",
		name: "Life Dew",
		pp: 10,
		priority: 0,
		flags: {snatch: 1, heal: 1, bypasssub: 1},
		onHit(pokemon) {
			let factor = 0.5;
			if (this.field.isWeather('raindance')) {
				factor = 0.667;
			}
			return !!this.heal(this.modify(pokemon.maxhp, factor));
		},
		secondary: null,
		target: "allies",
		type: "Water",
	},
	trashtalk: {
		accuracy: 100,
		basePower: 85,
		category: "Special",
		shortDesc: "Prevents the target from using status moves for 1 turn.",
		name: "Trash Talk",
		pp: 15,
		priority: 0,
		flags: {protect: 1, mirror: 1, sound: 1, bypasssub: 1},
		onPrepareHit(target, source, move) {
			this.attrLastMove('[still]');
			this.add('-anim', source, "Confide", target);
			this.add('-anim', source, "Gunk Shot", target);
		},
		volatileStatus: 'trashtalk',
		condition: {
			duration: 1,
			onStart(target) {
				this.add('-singleturn', target, 'move: Trash Talk');
			},
			onResidualOrder: 12,
			onEnd(target) {
				this.add('-end', target, 'move: Trash Talk');
			},
			onBeforeMovePriority: 5,
			onBeforeMove(attacker, defender, move) {
				if (!move.isZ && !move.isMax && move.category === 'Status' && move.id !== 'mefirst') {
					this.add('cant', attacker, 'move: Trash Talk', move);
					return false;
				}
			},
		},
		secondary: null,
		target: "normal",
		type: "Poison",
		contestType: "Cool",
	},
	deafeningshriek: {
		accuracy: 100,
		basePower: 100,
		category: "Special",
		shortDesc: "Target becomes immune to sound moves after being hit.",
		name: "Deafening Shriek",
		pp: 5,
		priority: 0,
		flags: {protect: 1, mirror: 1, sound: 1, bypasssub: 1},
		onPrepareHit(target, source, move) {
			this.attrLastMove('[still]');
			this.add('-anim', source, "Hyper Voice", target);
			this.add('-anim', source, "Boomburst", target);
		},
		volatileStatus: 'deafeningshriek',
		condition: {
			onStart(target) {
				this.add('-start', target, 'move: Deafening Shriek');
			},
			onTryHitPriority: 3,
			onTryHit(target, source, move) {
				if (move.target !== 'self' && move.flags['sound']) {
					this.add('-immune', target, '[from] move: Deafening Shriek');
					return null;
				}
			},
		},
		target: "normal",
		type: "Ghost",
		contestType: "Cool",
	},
	enchantedpunch: {
		accuracy: 100,
		basePower: 80,
		category: "Physical",
		overrideDefensiveStat: 'spd',
		shortDesc: "Damages target based on Sp. Def, not Defense.",
		name: "Enchanted Punch",
		pp: 10,
		priority: 0,
		flags: {protect: 1, mirror: 1, contact: 1, punch: 1},
		onPrepareHit(target, source, move) {
			this.attrLastMove('[still]');
			this.add('-anim', source, "Meteor Mash", target);
		},
		secondary: null,
		target: "normal",
		type: "Fairy",
		contestType: "Beautiful",
	},
	electroball: {
		num: 486,
		accuracy: 100,
		basePower: 80,
		category: "Special",
		name: "Electro Ball",
		pp: 10,
		priority: 0,
		flags: {bullet: 1, protect: 1, mirror: 1},
		overrideOffensiveStat: 'spe',
		secondary: null,
		target: "normal",
		type: "Electric",
		contestType: "Clever",
		shortDesc: "Uses user's Spe stat as SpA in damage calculation.",
	},
	firepunch: {
		num: 7,
		accuracy: 100,
		basePower: 85,
		category: "Physical",
		name: "Fire Punch",
		pp: 15,
		priority: 0,
		flags: {contact: 1, protect: 1, mirror: 1, punch: 1},
		secondary: {
			chance: 10,
			status: 'brn',
		},
		target: "normal",
		type: "Fire",
		contestType: "Tough",
	},
	icepunch: {
		num: 8,
		accuracy: 100,
		basePower: 85,
		category: "Physical",
		name: "Ice Punch",
		pp: 15,
		priority: 0,
		flags: {contact: 1, protect: 1, mirror: 1, punch: 1},
		secondary: {
			chance: 10,
			status: 'frz',
		},
		target: "normal",
		type: "Ice",
		contestType: "Beautiful",
	},
	thunderpunch: {
		num: 9,
		accuracy: 100,
		basePower: 85,
		category: "Physical",
		name: "Thunder Punch",
		pp: 15,
		priority: 0,
		flags: {contact: 1, protect: 1, mirror: 1, punch: 1},
		secondary: {
			chance: 10,
			status: 'par',
		},
		target: "normal",
		type: "Electric",
		contestType: "Cool",
	},
	skyuppercut: {
		num: 327,
		accuracy: 100,
		basePower: 70,
		category: "Physical",
		shortDesc: "Hits Flying-types super effectively. Can hit Pokemon using Bounce, Fly, or Sky Drop.",
		name: "Sky Uppercut",
		pp: 15,
		priority: 0,
		flags: {contact: 1, protect: 1, mirror: 1, punch: 1},
		onEffectiveness(typeMod, target, type) {
			if (type === 'Flying') return 1;
		},
		secondary: null,
		target: "normal",
		type: "Fighting",
		contestType: "Cool",
	},
	crushclaw: {
		inherit: true,
		accuracy: 100,
		basePower: 20,
		shortDesc: "Hits twice. Lowers the target's Def after each hit.",
		pp: 20,
		multihit: 2,
		secondary: {
			chance: 100,
			boosts: {
				def: -1,
			},
		},
		type: "Dark",
		maxMove: {basePower: 100},
	},
	poisondart: {
		accuracy: true,
		basePower: 40,
		category: "Physical",
		shortDesc: "Usually goes first. 10% chance to poison foe.",
		name: "Poison Dart",
		pp: 30,
		priority: 1,
		flags: {protect: 1, mirror: 1},
		onPrepareHit(target, source, move) {
			this.attrLastMove('[still]');
			this.add('-anim', source, "Poison Sting", target);
		},
		secondary: {
			chance: 10,
			status: 'psn',
		},
		target: "normal",
		type: "Poison",
		contestType: "Cool",
	},
	acidicfists: {
		accuracy: 100,
		basePower: 90,
		category: "Physical",
		shortDesc: "Destroys screens, unless the target is immune. 10% poison chance.",
		name: "Acidic Fists",
		pp: 10,
		priority: 0,
		flags: {punch: 1, contact: 1, protect: 1, mirror: 1},
		onPrepareHit(target, source, move) {
			this.attrLastMove('[still]');
			this.add('-anim', source, "Poison Jab", target);
			this.add('-anim', source, "Corrosive Gas", target);
		},
		onTryHit(pokemon) {
			// will shatter screens through sub, before you hit
			if (pokemon.runImmunity('Poison')) {
				pokemon.side.removeSideCondition('reflect');
				pokemon.side.removeSideCondition('lightscreen');
				pokemon.side.removeSideCondition('auroraveil');
			}
		},
		secondary: {
			chance: 10,
			status: 'psn',
		},
		target: "normal",
		type: "Poison",
		contestType: "Cool",
	},
	mudspike: {
		num: 398,
		accuracy: 100,
		basePower: 85,
		category: "Physical",
		shortDesc: "10% poison chance, 30% if the user is a Poison-type",
		name: "Mud Spike",
		pp: 10,
		priority: 0,
		flags: {protect: 1, mirror: 1},
		onPrepareHit(target, source, move) {
			this.attrLastMove('[still]');
			this.add('-anim', source, "Muddy Water", target);
			this.add('-anim', source, "Corrosive Gas", target);
		},
		onModifyMove(move, pokemon) {
			if (!pokemon.hasType('Poison')) return;
			if (!move.secondaries) move.secondaries = [];
			move.secondaries = move.secondaries.filter(s => s.chance !== 10 && s.status !== 'psn');
			move.secondaries.push({
				chance: 30,
				status: 'psn',
			});
		},
		secondary: {
			chance: 10,
			status: 'psn',
		},
		target: "normal",
		type: "Ground",
		contestType: "Tough",
	},
	bonemerang: {
		num: 155,
		accuracy: 100,
		basePower: 50,
		category: "Physical",
		shortDesc: "(Bugged) First hit has +1 priority, second hit has -1 priority.",
		name: "Bonemerang",
		pp: 10,
		priority: 1,
		flags: {protect: 1, mirror: 1},
		onModifyMove(move) {
			if (move.hit !== 1) move.priority = -1;
		},
		secondary: null,
		target: "normal",
		type: "Ground",
		maxMove: {basePower: 130},
		contestType: "Tough",
	},
	rashpowder: {
		accuracy: 75,
		basePower: 0,
		category: "Status",
		shortDesc: "Burns the target.",
		name: "Rash Powder",
		pp: 30,
		priority: 0,
		flags: {powder: 1, protect: 1, reflectable: 1, mirror: 1},
		onPrepareHit(target, source, move) {
			this.attrLastMove('[still]');
			this.add('-anim', source, "Spore", target);
		},
		status: 'brn',
		secondary: null,
		target: "normal",
		type: "Grass",
		zMove: {boost: {def: 1}},
		contestType: "Clever",
	},
	payback: {
		num: 371,
		accuracy: 100,
		basePower: 50,
		basePowerCallback(pokemon, target, move) {
			if (this.queue.willMove(target)) {
				this.debug('Payback NOT boosted');
				return move.basePower;
			}
			this.debug('Payback damage boost');
			return move.basePower * 2;
		},
		category: "Physical",
		shortDesc: "Power doubles if the user moves last or the foe switches.",
		name: "Payback",
		pp: 10,
		priority: 0,
		flags: {contact: 1, protect: 1, mirror: 1},
		secondary: null,
		target: "normal",
		type: "Dark",
		contestType: "Tough",
	},
	revenge: {
		num: 279,
		accuracy: 100,
		basePower: 50,
		basePowerCallback(pokemon, target, move) {
			if (this.queue.willMove(target)) {
				this.debug('Revenge NOT boosted');
				return move.basePower;
			}
			this.debug('Revenge damage boost');
			return move.basePower * 2;
		},
		category: "Physical",
		shortDesc: "Power doubles if the user moves last or the foe switches.",
		name: "Revenge",
		pp: 10,
		priority: 0,
		flags: {contact: 1, protect: 1, mirror: 1},
		secondary: null,
		target: "normal",
		type: "Fighting",
		contestType: "Tough",
	},
	avalanche: {
		num: 419,
		accuracy: 100,
		basePower: 50,
		basePowerCallback(pokemon, target, move) {
			if (this.queue.willMove(target)) {
				this.debug('Avalanche NOT boosted');
				return move.basePower;
			}
			this.debug('Avalanche damage boost');
			return move.basePower * 2;
		},
		category: "Physical",
		shortDesc: "Power doubles if the user moves last or the foe switches.",
		name: "Avalanche",
		pp: 10,
		priority: 0,
		flags: {contact: 1, protect: 1, mirror: 1},
		secondary: null,
		target: "normal",
		type: "Ice",
		contestType: "Beautiful",
	},
	technoblast: {
		num: 546,
		accuracy: 100,
		basePower: 90,
		onBasePower(basePower, source) {
			if (source.hasItem(['burndrive', 'dousedrive', 'chilldrive', 'shockdrive'])) {
				return this.chainModify(1.2);
			}
		},
		category: "Special",
		shortDesc: "Type varies based on the held Drive. 1.2x power when holding a Drive.",
		name: "Techno Blast",
		pp: 10,
		priority: 0,
		flags: {protect: 1, mirror: 1, pulse: 1, bullet: 1},
		onModifyType(move, pokemon) {
			if (pokemon.ignoringItem()) return;
			move.type = this.runEvent('Drive', pokemon, null, move, 'Normal');
		},
		secondary: null,
		target: "normal",
		type: "Normal",
		contestType: "Cool",
	},
	aggravate: {
		accuracy: 100,
		basePower: 85,
		category: "Physical",
		shortDesc: "If the target is statused, applies Taunt.",
		name: "Aggravate",
		pp: 10,
		priority: 0,
		flags: {contact: 1, protect: 1, mirror: 1},
		onPrepareHit(target, source, move) {
			this.attrLastMove('[still]');
			this.add('-anim', source, "Power Trip", target);
		},
		secondary: {
			chance: 100,
			onHit(target, source, move) {
				if (target.status) {
					return !!target.addVolatile('taunt');
				}
				return false;
			},
		},
		target: "normal",
		type: "Dark",
		contestType: "Clever",
	},
	curse: {
		num: 174,
		accuracy: true,
		basePower: 0,
		category: "Status",
		shortDesc: "Curses if Ghost, else -1 Spe, +2 Atk, +1 Def.",
		name: "Curse",
		pp: 10,
		priority: 0,
		flags: {},
		volatileStatus: 'curse',
		onModifyMove(move, source, target) {
			if (!source.hasType('Ghost')) {
				move.target = move.nonGhostTarget as MoveTarget;
			}
		},
		onTryHit(target, source, move) {
			if (!source.hasType('Ghost')) {
				delete move.volatileStatus;
				move.self = {boosts: {spe: -1, atk: 2, def: 1}};
			} else if ((move.volatileStatus && target.volatiles['curse']) || target.hasType(['Normal', 'Ghost']) ||
				target.volatiles['protect'] || target.volatiles['spikyshield'] || target.volatiles['banefulbunker']) {
				return false;
			}
		},
		condition: {
			onStart(target) {
				this.add('-start', target, 'move: Curse');
			},
			onResidualOrder: 8,
			onResidual(pokemon) {
				const target = this.effectState.source.side.active[pokemon.volatiles['curse'].sourcePosition];
				if (!target || target.fainted || target.hp <= 0) {
					this.debug('Nothing to curse');
					return;
				}
				const damage = this.damage(pokemon.baseMaxhp / 8, pokemon, target);
				if (damage) {
					this.heal(damage, target, pokemon);
				}
			},
		},
		onTryImmunity(target) {
			return (!target.hasType('Normal') || !target.hasType('Ghost'));
		},
		secondary: null,
		target: "randomNormal",
		nonGhostTarget: "self",
		type: "Ghost",
		zMove: {effect: 'curse'},
		contestType: "Tough",
	},
	octazooka: {
		num: 190,
		accuracy: 100,
		basePower: 75,
		category: "Special",
		shortDesc: "100% chance to lower the target's Evasion by 1.",
		name: "Octazooka",
		pp: 10,
		priority: 0,
		flags: {protect: 1, mirror: 1, pulse: 1, bullet: 1},
		secondary: {
			chance: 100,
			boosts: {
				evasion: -1,
			},
		},
		target: "normal",
		type: "Water",
		contestType: "Tough",
	},
	signalbeam: {
		num: 324,
		accuracy: 100,
		basePower: 75,
		category: "Special",
		shortDesc: "100% chance to lower the target's Speed by 1.",
		name: "Signal Beam",
		pp: 10,
		priority: 0,
		flags: {protect: 1, mirror: 1},
		secondary: {
			chance: 100,
			boosts: {
				spe: -1,
			},
		},
		target: "normal",
		type: "Bug",
		contestType: "Tough",
	},
	aurorabeam: {
		num: 62,
		accuracy: 100,
		basePower: 75,
		category: "Special",
		shortDesc: "100% chance to lower the target's Attack by 1.",
		name: "Aurora Beam",
		pp: 10,
		priority: 0,
		flags: {protect: 1, mirror: 1},
		secondary: {
			chance: 100,
			boosts: {
				atk: -1,
			},
		},
		target: "normal",
		type: "Ice",
		contestType: "Tough",
	},
	venoshock: {
		num: 474,
		accuracy: 100,
		basePower: 65,
		basePowerCallback(pokemon, target, move) {
			if (target.status || target.hasAbility('comatose')) return move.basePower * 2;
			return move.basePower;
		},
		category: "Special",
		shortDesc: "Power doubles if the target has a status ailment.",
		name: "Venoshock",
		pp: 10,
		priority: 0,
		flags: {protect: 1, mirror: 1},
		secondary: null,
		target: "normal",
		type: "Poison",
		contestType: "Beautiful",
	},
	attackorder: {
		num: 454,
		accuracy: 100,
		basePower: 75,
		basePowerCallback(pokemon, target, move) {
			if (target.status || target.hasAbility('comatose')) return move.basePower * 2;
			return move.basePower;
		},
		category: "Physical",
		shortDesc: "Power doubles if the target has a status ailment.",
		name: "Attack Order",
		pp: 15,
		priority: 0,
		flags: {protect: 1, mirror: 1},
		secondary: null,
		target: "normal",
		type: "Flying",
		contestType: "Clever",
	},
	smother: {
		accuracy: 100,
		basePower: 65,
		basePowerCallback(pokemon, target, move) {
			if (target.newlySwitched || this.queue.willMove(target)) {
				this.debug('Smother damage boost');
				return move.basePower * 1.5;
			}
			this.debug('Smother NOT boosted');
			return move.basePower;
		},
		category: "Physical",
		shortDesc: "The target must move last next turn. 1.5x if the user moves first.",
		name: "Smother",
		pp: 10,
		priority: 0,
		flags: {contact: 1, protect: 1, mirror: 1},
		onPrepareHit(target, source, move) {
			this.attrLastMove('[still]');
			this.add('-anim', source, "Wrap", target);
		},
		onHit(target, source) {
			target.addVolatile('smother', source);
		},
		condition: {
			duration: 2,
			onStart(target) {
				this.add('-start', target, 'Smother', '[silent]');
			},
			onFractionalPriority: -0.1,
			onResidualOrder: 22,
			onEnd(target) {
				this.add('-end', target, 'Smother', '[silent]');
			},
		},
		secondary: null,
		target: "normal",
		type: "Fairy",
		contestType: "Clever",
	},
	fierydance: {
		num: 552,
		accuracy: 100,
		basePower: 85,
		category: "Special",
		name: "Fiery Dance",
		pp: 10,
		priority: 0,
		flags: {protect: 1, mirror: 1, dance: 1},
		secondary: {
			chance: 50,
			self: {
				boosts: {
					spa: 1,
				},
			},
		},
		target: "normal",
		type: "Fire",
		contestType: "Beautiful",
	},
	snowmanjazz: {
		accuracy: 100,
		basePower: 85,
		category: "Special",
		shortDesc: "50% chance to raise the user's Sp. Atk by 1.",
		name: "Snowman Jazz",
		pp: 10,
		priority: 0,
		flags: {protect: 1, mirror: 1, dance: 1},
		onPrepareHit(target, source, move) {
			this.attrLastMove('[still]');
			this.add('-anim', source, "Quiver Dance", target);
			this.add('-anim', source, "Ice Beam", target);
		},
		secondary: {
			chance: 50,
			self: {
				boosts: {
					spa: 1,
				},
			},
		},
		target: "normal",
		type: "Ice",
		contestType: "Beautiful",
	},
	moonlitwaltz: {
		accuracy: 100,
		basePower: 85,
		category: "Special",
		shortDesc: "50% chance to raise the user's Sp. Atk by 1.",
		name: "Moonlit Waltz",
		pp: 10,
		priority: 0,
		flags: {protect: 1, mirror: 1, dance: 1},
		onPrepareHit(target, source, move) {
			this.attrLastMove('[still]');
			this.add('-anim', source, "Quiver Dance", target);
			this.add('-anim', source, "Dark Pulse", target);
		},
		secondary: {
			chance: 50,
			self: {
				boosts: {
					spa: 1,
				},
			},
		},
		target: "normal",
		type: "Dark",
		contestType: "Beautiful",
	},
	petaldance: {
		num: 80,
		accuracy: 100,
		basePower: 85,
		category: "Special",
		shortDesc: "50% chance to raise the user's Sp. Atk by 1.",
		name: "Petal Dance",
		pp: 10,
		priority: 0,
		flags: {protect: 1, mirror: 1, dance: 1},
		secondary: {
			chance: 50,
			self: {
				boosts: {
					spa: 1,
				},
			},
		},
		target: "normal",
		type: "Grass",
		contestType: "Beautiful",
	},
	skysoiree: {
		accuracy: 100,
		basePower: 85,
		category: "Special",
		shortDesc: "50% chance to raise the user's Sp. Atk by 1.",
		name: "Sky Soiree",
		pp: 10,
		priority: 0,
		flags: {protect: 1, mirror: 1, dance: 1},
		onPrepareHit(target, source, move) {
			this.attrLastMove('[still]');
			this.add('-anim', source, "Quiver Dance", target);
			this.add('-anim', source, "Gust", target);
		},
		secondary: {
			chance: 50,
			self: {
				boosts: {
					spa: 1,
				},
			},
		},
		target: "normal",
		type: "Flying",
		contestType: "Beautiful",
	},
	shadowpunch: {
		num: 325,
		accuracy: true,
		basePower: 80,
		category: "Physical",
		shortDesc: "Ignores burn, screens, and Substitute.",
		name: "Shadow Punch",
		pp: 20,
		priority: 0,
		flags: {protect: 1, mirror: 1, punch: 1},
		onBasePower(basePower, pokemon) {
			if (pokemon.status === 'brn') {
				return this.chainModify(2);
			}
		},
		infiltrates: true,
		secondary: null,
		target: "normal",
		type: "Ghost",
		contestType: "Clever",
	},
	bouncybubble: {
		inherit: true,
		isNonstandard: null,
		onPrepareHit(target, source, move) {
			this.attrLastMove('[still]');
			this.add('-anim', source, "Bubble", target);
		},
	},
	buzzybuzz: {
		inherit: true,
		isNonstandard: null,
		onPrepareHit(target, source, move) {
			this.attrLastMove('[still]');
			this.add('-anim', source, "Discharge", target);
		},
	},
	sizzlyslide: {
		inherit: true,
		isNonstandard: null,
		onPrepareHit(target, source, move) {
			this.attrLastMove('[still]');
			this.add('-anim', source, "Flame Charge", target);
		},
	},
	glitzyglow: {
		inherit: true,
		isNonstandard: null,
		onPrepareHit(target, source, move) {
			this.attrLastMove('[still]');
			this.add('-anim', source, "Psychic", target);
		},
	},
	baddybad: {
		inherit: true,
		isNonstandard: null,
		onPrepareHit(target, source, move) {
			this.attrLastMove('[still]');
			this.add('-anim', source, "Photon Geyser", target);
		},
	},
	freezyfrost: {
		inherit: true,
		isNonstandard: null,
		onPrepareHit(target, source, move) {
			this.attrLastMove('[still]');
			this.add('-anim', source, "Blizzard", target);
		},
	},
	sappyseed: {
		inherit: true,
		isNonstandard: null,
		onPrepareHit(target, source, move) {
			this.attrLastMove('[still]');
			this.add('-anim', source, "Horn Leech", target);
		},
	},
	sparklyswirl: {
		inherit: true,
		isNonstandard: null,
		onPrepareHit(target, source, move) {
			this.attrLastMove('[still]');
			this.add('-anim', source, "Dazzling Gleam", target);
		},
	},
	// stuff that needs to be edited because of other stuff
	fling: {
		num: 374,
		accuracy: 100,
		basePower: 0,
		category: "Physical",
		name: "Fling",
		pp: 10,
		priority: 0,
		flags: {protect: 1, mirror: 1, allyanim: 1},
		onPrepareHit(target, source, move) {
			if (source.ignoringItem()) return false;
			const item = source.getItem();
			if (!this.singleEvent('TakeItem', item, source.itemState, source, source, move, item)) return false;
			if (!item.fling) return false;
			move.basePower = item.fling.basePower;
			if (item.isBerry) {
				move.onHit = function (foe) {
					if (this.singleEvent('Eat', item, null, foe, null, null)) {
						this.runEvent('EatItem', foe, null, null, item);
						if (item.id === 'leppaberry') foe.staleness = 'external';
					}
					if (item.onEat) foe.ateBerry = true;
				};
			} else if (item.fling.effect) {
				move.onHit = item.fling.effect;
			} else {
				if (!move.secondaries) move.secondaries = [];
				if (item.fling.status) {
					move.secondaries.push({status: item.fling.status});
				} else if (item.fling.volatileStatus) {
					move.secondaries.push({volatileStatus: item.fling.volatileStatus});
				}
			}
			source.addVolatile('fling');
			if (item.id === 'boomerang') {
				source.removeVolatile('fling');
			}
		},
		condition: {
			onUpdate(pokemon) {
				const item = pokemon.getItem();
				pokemon.setItem('');
				pokemon.lastItem = item.id;
				pokemon.usedItemThisTurn = true;
				this.add('-enditem', pokemon, item.name, '[from] move: Fling');
				this.runEvent('AfterUseItem', pokemon, null, null, item);
				pokemon.removeVolatile('fling');
			},
		},
		secondary: null,
		target: "normal",
		type: "Dark",
		contestType: "Cute",
	},
	knockoff: {
		num: 282,
		accuracy: 100,
		basePower: 65,
		category: "Physical",
		name: "Knock Off",
		pp: 20,
		priority: 0,
		flags: {contact: 1, protect: 1, mirror: 1},
		onBasePower(basePower, source, target, move) {
			const item = target.getItem();
			if (!this.singleEvent('TakeItem', item, target.itemState, target, target, move, item)) return;
			if (item.id && item.id !== 'boomerang') {
				return this.chainModify(1.5);
			}
		},
		onAfterHit(target, source) {
			if (source.hp) {
				const item = target.takeItem();
				if (item) {
					this.add('-enditem', target, item.name, '[from] move: Knock Off', '[of] ' + source);
					if (item.id === 'boomerang') {
						this.add('-item', target, this.dex.items.get(item), '[from] item: Boomerang');
						target.setItem(item);
					}
				}
			}
		},
		secondary: null,
		target: "normal",
		type: "Dark",
		contestType: "Clever",
	},
	stealthrock: {
		inherit: true,
		condition: {
			// this is a side condition
			onStart(side) {
				this.add('-sidestart', side, 'move: Stealth Rock');
			},
			onSwitchIn(pokemon) {
				if (
					pokemon.hasItem('heavydutyboots') || pokemon.hasItem('coalengine')
				) return;
				const typeMod = this.clampIntRange(pokemon.runEffectiveness(this.dex.getActiveMove('stealthrock')), -6, 6);
				this.damage(pokemon.maxhp * Math.pow(2, typeMod) / 8);
			},
		},
	},
	gravity: {
		num: 356,
		accuracy: true,
		basePower: 0,
		category: "Status",
		name: "Gravity",
		pp: 5,
		priority: 0,
		flags: {nonsky: 1},
		pseudoWeather: 'gravity',
		condition: {
			duration: 5,
			durationCallback(source, effect) {
				if (source?.hasAbility('persistent')) {
					this.add('-activate', source, 'ability: Persistent', effect);
					return 7;
				} else if (source && source.hasItem('ironball')) {
					return 8;
				}
				return 5;
			},
			onStart() {
				this.add('-fieldstart', 'move: Gravity');
				for (const pokemon of this.getAllActive()) {
					let applies = false;
					if (pokemon.removeVolatile('bounce') || pokemon.removeVolatile('fly')) {
						applies = true;
						this.queue.cancelMove(pokemon);
						pokemon.removeVolatile('twoturnmove');
					}
					if (pokemon.volatiles['skydrop']) {
						applies = true;
						this.queue.cancelMove(pokemon);

						if (pokemon.volatiles['skydrop'].source) {
							this.add('-end', pokemon.volatiles['twoturnmove'].source, 'Sky Drop', '[interrupt]');
						}
						pokemon.removeVolatile('skydrop');
						pokemon.removeVolatile('twoturnmove');
					}
					if (pokemon.volatiles['magnetrise']) {
						applies = true;
						delete pokemon.volatiles['magnetrise'];
					}
					if (pokemon.volatiles['telekinesis']) {
						applies = true;
						delete pokemon.volatiles['telekinesis'];
					}
					if (applies) this.add('-activate', pokemon, 'move: Gravity');
				}
			},
			onModifyAccuracy(accuracy) {
				if (typeof accuracy !== 'number') return;
				return accuracy * 5 / 3;
			},
			onDisableMove(pokemon) {
				for (const moveSlot of pokemon.moveSlots) {
					if (this.dex.moves.get(moveSlot.id).flags['gravity']) {
						pokemon.disableMove(moveSlot.id);
					}
				}
			},
			// groundedness implemented in battle.engine.js:BattlePokemon#isGrounded
			onBeforeMovePriority: 6,
			onBeforeMove(pokemon, target, move) {
				if (move.flags['gravity']) {
					this.add('cant', pokemon, 'move: Gravity', move);
					return false;
				}
			},
			onResidualOrder: 22,
			onEnd() {
				this.add('-fieldend', 'move: Gravity');
			},
		},
		secondary: null,
		target: "all",
		type: "Psychic",
		zMove: {boost: {spa: 1}},
		contestType: "Clever",
	},
	rapidspin: {
		num: 229,
		accuracy: 100,
		basePower: 50,
		category: "Physical",
		name: "Rapid Spin",
		pp: 40,
		priority: 0,
		flags: {contact: 1, protect: 1, mirror: 1},
		onAfterHit(target, pokemon) {
			if (pokemon.hp && pokemon.removeVolatile('leechseed')) {
				this.add('-end', pokemon, 'Leech Seed', '[from] move: Rapid Spin', '[of] ' + pokemon);
			}
			if (pokemon.hp && pokemon.removeVolatile('curse')) {
				this.add('-end', pokemon, 'Curse', '[from] move: Rapid Spin', '[of] ' + pokemon);
			}
			const sideConditions = ['spikes', 'toxicspikes', 'stealthrock', 'stickyweb', 'gmaxsteelsurge'];
			for (const condition of sideConditions) {
				if (pokemon.hp && pokemon.side.removeSideCondition(condition)) {
					this.add('-sideend', pokemon.side, this.dex.conditions.get(condition).name, '[from] move: Rapid Spin', '[of] ' + pokemon);
				}
			}
			if (pokemon.hp && pokemon.volatiles['partiallytrapped']) {
				pokemon.removeVolatile('partiallytrapped');
			}
		},
		onAfterSubDamage(damage, target, pokemon) {
			if (pokemon.hp && pokemon.removeVolatile('leechseed')) {
				this.add('-end', pokemon, 'Leech Seed', '[from] move: Rapid Spin', '[of] ' + pokemon);
			}
			if (pokemon.hp && pokemon.removeVolatile('curse')) {
				this.add('-end', pokemon, 'Curse', '[from] move: Rapid Spin', '[of] ' + pokemon);
			}
			const sideConditions = ['spikes', 'toxicspikes', 'stealthrock', 'stickyweb', 'gmaxsteelsurge'];
			for (const condition of sideConditions) {
				if (pokemon.hp && pokemon.side.removeSideCondition(condition)) {
					this.add('-sideend', pokemon.side, this.dex.conditions.get(condition).name, '[from] move: Rapid Spin', '[of] ' + pokemon);
				}
			}
			if (pokemon.hp && pokemon.volatiles['partiallytrapped']) {
				pokemon.removeVolatile('partiallytrapped');
			}
		},
		secondary: {
			chance: 100,
			self: {
				boosts: {
					spe: 1,
				},
			},
		},
		target: "normal",
		type: "Normal",
		contestType: "Cool",
	},
};
