# Mugen style Training Mode global code
# maps set via Pause Menu (menu.lua)
# _iksys_trainingDummyControl: 0 - cooperative, 1 - ai, 2 - manual
# _iksys_trainingGuardMode: 0 - none, 1 - auto, 2 - all, 3 - random
# _iksys_trainingFallRecovery: 0 - none, 1 - ground, 2 - air, 3 - random
# _iksys_trainingDummyMode: 0 - stand, 1 - crouch, 2 - jump, 3 - wjump
# _iksys_trainingDistance: 0 - any, 1 - close, 2 - medium, 3 - far
# _iksys_trainingButtonJam: 0 - none, 1-9 - a/b/c/x/y/z/s/d/w

#===============================================================================
# Functions
#===============================================================================
[Function TrainingRecovery(pn)]
# Life recovery
if player($pn),moveType = H || player($pn),dizzy {
	mapSet{map: "_iksys_trainingLifeTimer"; value: 0; redirectid: player($pn),id}
} else if player($pn),map(_iksys_trainingLifeTimer) >= 60 {
	lifeSet{value: player($pn),lifeMax; redirectid: player($pn),id}
	redLifeSet{value: player($pn),lifeMax; redirectid: player($pn),id}
	mapSet{map: "_iksys_trainingLifeTimer"; value: 0; redirectid: player($pn),id}
} else {
	mapAdd{map: "_iksys_trainingLifeTimer"; value: 1; redirectid: player($pn),id}
}
# Power recovery
if player($pn),ctrl = 0 {
	mapSet{map: "_iksys_trainingPowerTimer"; value: 0; redirectid: player($pn),id}
} else if player($pn),map(_iksys_trainingPowerTimer) >= 60 {
	powerSet{value: player($pn),powerMax; redirectid: player($pn),id}
	mapSet{map: "_iksys_trainingPowerTimer"; value: 0; redirectid: player($pn),id}
} else {
	mapAdd{map: "_iksys_trainingPowerTimer"; value: 1; redirectid: player($pn),id}
}

#===============================================================================
# Global states (not halted by Pause/SuperPause, no helper limitations)
#===============================================================================
[StateDef -4]

ignoreHitPause if gameMode != "training" || isHelper || teamSide != 2 {
	# Do nothing, not training more or statedef executed by helper or not P2
} else ignoreHitPause if roundState = 0 {
	# Round start reset
	powerSet{value: player(1),powerMax; redirectid: player(1),id}
	powerSet{value: player(2),powerMax; redirectid: player(2),id}
	map(_iksys_trainingLifeTimer) := 0;
	map(_iksys_trainingPowerTimer) := 0;
	map(_iksys_trainingDirection) := 0;
	map(_iksys_trainingAirJumpNum) := 0;
} else ignoreHitPause if roundState = 2 {
	assertSpecial{flag: globalNoKo}
	# Life and Power recovery
	for i = 1; player(1),numPartner + 1; 1 {
		call TrainingRecovery($i * 2 - 1);
	}
	for i = 1; player(2),numPartner + 1; 1 {
		call TrainingRecovery($i * 2);
	}
	# Dummy Control: Cooperative
	if aiLevel = 0 && map(_iksys_trainingDummyControl) = 0 {
		# Guard mode: Random
		if map(_iksys_trainingGuardMode) = 3 {
			if random < 500 {
				assertSpecial{flag: autoGuard}
			}
		# Guard mode: All
		} else if map(_iksys_trainingGuardMode) = 2 {
			assertSpecial{flag: autoGuard}
		# Guard mode: Auto
		} else if map(_iksys_trainingGuardMode) = 1 {
			if moveType = H || stateNo = const(StateDownedGetHit_gettingUp) {
				map(_iksys_trainingAutoGuardTimer) := 15;
			} else {
				map(_iksys_trainingAutoGuardTimer) := (map(_iksys_trainingAutoGuardTimer) - 1);
			}
			if map(_iksys_trainingAutoGuardTimer) > 0 {
				assertSpecial{flag: autoGuard}
			}
		}
		# Fall Recovery
		if map(_iksys_trainingFallRecovery) {
			if stateNo != [const(StateAirGetHit_fallRecoveryOnGroundStillFalling), const(StateAirGetHit_fallRecoveryInAir)] {
				if moveType = H && stateType = A && hitFall && !getHitVar(isbound) && (pos y || vel y) {
					if (map(_iksys_trainingFallRecovery) = 1 && pos y >= const(movement.air.gethit.groundrecover.ground.threshold)) # Ground recovery
					|| (map(_iksys_trainingFallRecovery) = 2 && pos y < const(movement.air.gethit.groundrecover.ground.threshold)) # Air recovery
					|| (map(_iksys_trainingFallRecovery) = 3 && random < 100) { # Random recovery
						if gametime % 2 {
							assertInput{flag: x; flag2: y; flag3: z} # Ideally one would specifically force the character's "recovery" command
						} else {
							assertInput{flag: a; flag2: b; flag3: c}
						}
						# Random direction
						if map(_iksys_trainingFallRecovery) = 3 {
							if random < 333 {
								assertInput{flag: L}
							} else if random < 500 {
								assertInput{flag: R}
							}
							if random < 333 {
								assertInput{flag: U}
							} else if random < 500 {
								assertInput{flag: D}
							}
						}
					}
				}
			}
		}
		# Distance
		let dir = 0;
		if map(_iksys_trainingDistance) != 0 {
			# Close
			if map(_iksys_trainingDistance) = 1 && p2BodyDist x > const240p(10) {
				let dir = 1;
				map(_iksys_trainingDirection) := 1;
			# Medium
			} else if map(_iksys_trainingDistance) = 2 {
				if p2BodyDist x > const240p(130) {
					let dir = 1;
					map(_iksys_trainingDirection) := 1;
				} else if p2BodyDist x < const240p(80) && backEdgeBodyDist > const240p(10) {
					let dir = -1;
					map(_iksys_trainingDirection) := -1;
				}
			# Far
			} else if map(_iksys_trainingDistance) = 3 {
				if p2BodyDist x < const240p(260) && backEdgeBodyDist > const240p(10) {
					let dir = -1;
					map(_iksys_trainingDirection) := -1;
				}
			}
		}
		if map(_iksys_trainingDirection) != 0 {
			# if adjusting position is no longer needed
			if $dir = 0 {
				# maintain assertion only if dummy and nearest P1 are moving in the same direction
				if vel x * p2,vel x >= 0 || backEdgeBodyDist = 0 || p2,backEdgeBodyDist = 0 {
					map(_iksys_trainingDirection) := 0;
				}
			}
			# if dummy should move forward and player is not trying to move dummy back
			if map(_iksys_trainingDirection) = 1 && command != "holdback" {
				if facing = 1 {
					assertInput{flag: R}
				} else {
					assertInput{flag: L}
				}
			# if dummy should move backward and player is not trying to move dummy forward
			} else if map(_iksys_trainingDirection) = -1 && command != "holdfwd" {
				if facing = 1 {
					assertInput{flag: L}
				} else {
					assertInput{flag: R}
				}
			}
		} else {
			# Dummy mode
			switch map(_iksys_trainingDummyMode) {
			# Crouch
			case 1:
				assertInput{flag: D}
			# Jump
			case 2:
				assertInput{flag: U}
			# W Jump
			case 3:
				if vel y >= 0 {
					assertInput{flag: U}
				}
			default:
				# Do nothing
			}
			# Button jam
			if map(_iksys_trainingButtonJam) > 0 {
				if map(_iksys_trainingButtonJamDelay) > 0 {
					mapAdd{map: "_iksys_trainingButtonJamDelay"; value: -1}
				} else {
					map(_iksys_trainingButtonJamDelay) := 11;
					switch map(_iksys_trainingButtonJam) {
					case 1:
						assertInput{flag: a}
					case 2:
						assertInput{flag: b}
					case 3:
						assertInput{flag: c}
					case 4:
						assertInput{flag: x}
					case 5:
						assertInput{flag: y}
					case 6:
						assertInput{flag: z}
					case 7:
						assertInput{flag: s}
					case 8:
						assertInput{flag: d}
					case 9:
						assertInput{flag: w}
					default:
						map(_iksys_trainingButtonJamDelay) := 0;
					}
				}
			}
		}
	}
}
