text: 'use strict';
  
  exports.BattleScripts = {
  	moveHit: function (target, pokemon, move, moveData, isSecondary, isSelf) {
  		let damage;
  		move = this.getMoveCopy(move);
  
  		if (!moveData) moveData = move;
  		if (!moveData.flags) moveData.flags = {};
  		let hitResult = true;
  
  		// TryHit events:
  		//   STEP 1: we see if the move will succeed at all:
  		//   - TryHit, TryHitSide, or TryHitField are run on the move,
  		//     depending on move target (these events happen in useMove
  		//     or tryMoveHit, not below)
  		//   == primary hit line ==
  		//   Everything after this only happens on the primary hit (not on
  		//   secondary or self-hits)
  		//   STEP 2: we see if anything blocks the move from hitting:
  		//   - TryFieldHit is run on the target
  		//   STEP 3: we see if anything blocks the move from hitting the target:
  		//   - If the move's target is a pokemon, TryHit is run on that pokemon
  
  		// Note:
  		//   If the move target is `foeSide`:
  		//     event target = pokemon 0 on the target side
  		//   If the move target is `allySide` or `all`:
  		//     event target = the move user
  		//
  		//   This is because events can't accept actual sides or fields as
  		//   targets. Choosing these event targets ensures that the correct
  		//   side or field is hit.
  		//
  		//   It is the `TryHitField` event handler's responsibility to never
  		//   use `target`.
  		//   It is the `TryFieldHit` event handler's responsibility to read
  		//   move.target and react accordingly.
  		//   An exception is `TryHitSide` as a single event (but not as a normal
  		//   event), which is passed the target side.
  
  		if (move.target === 'all' && !isSelf) {
  			hitResult = this.singleEvent('TryHitField', moveData, {}, target, pokemon, move);
  		} else if ((move.target === 'foeSide' || move.target === 'allySide') && !isSelf) {
  			hitResult = this.singleEvent('TryHitSide', moveData, {}, target.side, pokemon, move);
  		} else if (target) {
  			hitResult = this.singleEvent('TryHit', moveData, {}, target, pokemon, move);
  		}
  		if (!hitResult) {
  			if (hitResult === false) this.add('-fail', target);
  			return false;
  		}
  
  		if (target && !isSecondary && !isSelf) {
  			if (move.target !== 'all' && move.target !== 'allySide' && move.target !== 'foeSide') {
  				hitResult = this.runEvent('TryPrimaryHit', target, pokemon, moveData);
  				if (hitResult === 0) {
  					// special Substitute flag
  					hitResult = true;
  					target = null;
  				}
  			}
  		}
  		if (target && isSecondary && !moveData.self) {
  			hitResult = true;
  		}
  		if (!hitResult) {
  			return false;
  		}
  
  		if (target) {
  			let didSomething = false;
  
  			damage = this.getDamage(pokemon, target, moveData);
  
  			// getDamage has several possible return values:
  			//
  			//   a number:
  			//     means that much damage is dealt (0 damage still counts as dealing
  			//     damage for the purposes of things like Static)
  			//   false:
  			//     gives error message: "But it failed!" and move ends
  			//   null:
  			//     the move ends, with no message (usually, a custom fail message
  			//     was already output by an event handler)
  			//   undefined:
  			//     means no damage is dealt and the move continues
  			//
  			// basically, these values have the same meanings as they do for event
  			// handlers.
  
  			if ((damage || damage === 0) && !target.fainted) {
  				if (move.noFaint && damage >= target.hp) {
  					damage = target.hp - 1;
  				}
  				damage = this.damage(damage, target, pokemon, move);
  				if (!(damage || damage === 0)) {
  					this.debug('damage interrupted');
  					return false;
  				}
  				didSomething = true;
  			}
  			if (damage === false || damage === null) {
  				if (damage === false && !isSecondary && !isSelf) {
  					this.add('-fail', target);
  				}
  				this.debug('damage calculation interrupted');
  				return false;
  			}
  
  			if (moveData.boosts && !target.fainted) {
  				hitResult = this.boost(moveData.boosts, target, pokemon, move, isSecondary, isSelf);
  				didSomething = didSomething || hitResult;
  			}
  			if (moveData.heal && !target.fainted) {
  				let d = target.heal((this.gen < 5 ? Math.floor : Math.round)(target.maxhp * moveData.heal[0] / moveData.heal[1]));
  				if (!d && d !== 0) {
  					this.add('-fail', target);
  					this.debug('heal interrupted');
  					return false;
  				}
  				this.add('-heal', target, target.getHealth);
  				didSomething = true;
  			}
  			if (moveData.status) {
  				hitResult = target.trySetStatus(moveData.status, pokemon, moveData.ability ? moveData.ability : move);
  				if (!hitResult && move.status) return hitResult;
  				didSomething = didSomething || hitResult;
  			}
  			if (moveData.forceStatus) {
  				hitResult = target.setStatus(moveData.forceStatus, pokemon, move);
  				didSomething = didSomething || hitResult;
  			}
  			if (moveData.volatileStatus) {
  				hitResult = target.addVolatile(moveData.volatileStatus, pokemon, move);
  				didSomething = didSomething || hitResult;
  			}
  			if (moveData.sideCondition) {
  				hitResult = target.side.addSideCondition(moveData.sideCondition, pokemon, move);
  				didSomething = didSomething || hitResult;
  			}
  			if (moveData.weather) {
  				hitResult = this.setWeather(moveData.weather, pokemon, move);
  				didSomething = didSomething || hitResult;
  			}
  			if (moveData.terrain) {
  				hitResult = this.setTerrain(moveData.terrain, pokemon, move);
  				didSomething = didSomething || hitResult;
  			}
  			if (moveData.pseudoWeather) {
  				hitResult = this.addPseudoWeather(moveData.pseudoWeather, pokemon, move);
  				didSomething = didSomething || hitResult;
  			}
  			if (moveData.forceSwitch) {
  				if (this.canSwitch(target.side)) didSomething = true; // at least defer the fail message to later
  			}
  			if (moveData.selfSwitch) {
  				if (this.canSwitch(pokemon.side)) didSomething = true; // at least defer the fail message to later
  			}
  			// Hit events
  			//   These are like the TryHit events, except we don't need a FieldHit event.
  			//   Scroll up for the TryHit event documentation, and just ignore the "Try" part. ;)
  			hitResult = null;
  			if (move.target === 'all' && !isSelf) {
  				if (moveData.onHitField) hitResult = this.singleEvent('HitField', moveData, {}, target, pokemon, move);
  			} else if ((move.target === 'foeSide' || move.target === 'allySide') && !isSelf) {
  				if (moveData.onHitSide) hitResult = this.singleEvent('HitSide', moveData, {}, target.side, pokemon, move);
  			} else {
  				if (moveData.onHit) hitResult = this.singleEvent('Hit', moveData, {}, target, pokemon, move);
  				if (!isSelf && !isSecondary) {
  					this.runEvent('Hit', target, pokemon, move);
  				}
  				if (moveData.onAfterHit) hitResult = this.singleEvent('AfterHit', moveData, {}, target, pokemon, move);
  			}
  
  			if (!hitResult && !didSomething && !moveData.self && !moveData.selfdestruct) {
  				if (!isSelf && !isSecondary) {
  					if (hitResult === false || didSomething === false) this.add('-fail', target);
  				}
  				this.debug('move failed because it did nothing');
  				return false;
  			}
  		}
  		if (moveData.self) {
  			let selfRoll;
  			if (!isSecondary && moveData.self.boosts) selfRoll = this.random(100);
  			// This is done solely to mimic in-game RNG behaviour. All self drops have a 100% chance of happening but still grab a random number.
  			if (typeof moveData.self.chance === 'undefined' || selfRoll < moveData.self.chance) {
  				this.moveHit(pokemon, pokemon, move, moveData.self, isSecondary, true);
  			}
  		}
  		if (moveData.secondaries) {
  			let secondaryRoll;
  			let secondaries = this.runEvent('ModifySecondaries', target, pokemon, moveData, moveData.secondaries.slice());
  			for (let i = 0; i < secondaries.length; i++) {
  				secondaryRoll = this.random(100);
  				if (typeof secondaries[i].chance === 'undefined' || secondaryRoll < secondaries[i].chance) {
  					// mod for automagic start
  					let flag = true;
  
  					let canSetStatus = function (status, target, pokemon) {
  						if (target.status) return false;
  						let cantStatus = {
  							brn: ['Fire', 'comatose', 'waterveil', 'waterbubble'],
  							frz: ['Ice', 'comatose', 'magmaarmor'],
  							par: ['Electric', 'comatose', 'limber'],
  							psn: ['comatose', 'immunity'],
  							slp: ['comatose', 'insomnia', 'vitalspirit'],
  							tox: ['comatose', 'immunity'],
  						};
  						if (target.hasType(['Poison', 'Steel']) && (status === 'psn' || status === 'tox')) {
  							if (pokemon.hasAbility('corrosion')) {
  								return true;
  							} else {
  								return false;
  							}
  						}
  						if (target.hasType(cantStatus[status][0])) return false;
  						if (move.ignoreAbility) return true;
  						if (target.hasAbility('leafguard') && this.isWeather(['sunnyday', 'desolateland'])) return false;
  						if (target.hasAbility('shieldsdown') && target.template.speciesid === 'miniormeteor') return false;
  						if (target.hasAbility(cantStatus[status])) return false;
  						return true;
  					};
  					if (moveData.secondary.status) flag = canSetStatus(moveData.secondary.status, target, pokemon);
  					if (moveData.secondary.volatileStatus) flag = !(moveData.secondary.volatileStatus in target.volatiles);
  					if (moveData.secondary.volatileStatus === 'flinch') flag = flag && target.activeTurns && !target.moveThisTurn;
  					this.moveHit(target, pokemon, move, secondaries[i], true, isSelf);
  					if (moveData.secondary.self && moveData.secondary.self.boosts) {
  						Object.keys(moveData.secondary.self.boosts).forEach(boost => {
  							if (pokemon.boosts[boost] === 6) flag = false;
  						});
  					} else {
  						flag = flag && target && !(target.hp === undefined || target.hp <= 0);
  					}
  					if (moveData.target !== 'self' && moveData.secondary.boosts) {
  						let cantLower = {
  							'atk': ['clearbody', 'fullmetalbody', 'hypercutter', 'whitesmoke'],
  							'def': ['bigpecks', 'clearbody', 'fullmetalbody', 'whitesmoke'],
  							'spa': ['clearbody', 'fullmetalbody', 'whitesmoke'],
  							'spd': ['clearbody', 'fullmetalbody', 'whitesmoke'],
  							'spe': ['clearbody', 'fullmetalbody', 'whitesmoke'],
  							'accuracy': ['clearbody', 'fullmetalbody', 'keeneye', 'whitesmoke'],
  						};
  						for (let k in moveData.secondary.boosts) {
  							if (target.boosts[k] === -6) {
  								flag = false;
  								continue;
  							}
  							if (moveData.secondary.boosts[k] < 0 && target.hasAbility(cantLower[k]) && !move.ignoreAbility) {
  								flag = false;
  								break;
  							}
  						}
  					}
  					if (pokemon.hasAbility('sheerforce')) flag = false;
  					if (target && target.hasAbility('shielddust') && !move.ignoreAbility && !move.secondary.self.boosts) {
  						flag = false;
  					}
  					if (flag) this.runEvent('AfterSecondaryEffect', target, pokemon, moveData);
  					// mod for automagic end
  				}
  			}
  		}
  		if (target && target.hp > 0 && pokemon.hp > 0 && moveData.forceSwitch && this.canSwitch(target.side)) {
  			hitResult = this.runEvent('DragOut', target, pokemon, move);
  			if (hitResult) {
  				target.forceSwitchFlag = true;
  			} else if (hitResult === false && move.category === 'Status') {
  				this.add('-fail', target);
  			}
  		}
  		if (move.selfSwitch && pokemon.hp) {
  			pokemon.switchFlag = move.selfSwitch;
  		}
  		return damage;
  	},
  };
  