package TerrainModder
//The Terrainers appear as heroes, and which with the builders change tiles.
import ChannelAbilityPreset
import TerrainBlocker
import PlayerData

public constant WALKABLE_ID = compiletime(HERO_ID_GEN.next())
public constant UNWALKABLE_ID = compiletime(HERO_ID_GEN.next())
public constant SLIDEABLE_ICE_ID = compiletime(HERO_ID_GEN.next())
public constant SLIDEABLE_UNC_ICE_ID = compiletime(HERO_ID_GEN.next())

constant ICE_ABILITY = 'A063'
constant REVICE_ABILITY = 'A00C'
let UNWALKABLE_MOD_ABILITY_ID = ['A04Z', 'A04Y', 'A04X']

public constant BRUSH_1_IDLE_ABILITY = compiletime(ABIL_ID_GEN.next())
public constant BRUSH_1_ACTIVE_ABILITY = compiletime(ABIL_ID_GEN.next())
public constant BRUSH_3_IDLE_ABILITY = compiletime(ABIL_ID_GEN.next())
public constant BRUSH_3_ACTIVE_ABILITY = compiletime(ABIL_ID_GEN.next())
public constant BRUSH_5_IDLE_ABILITY = compiletime(ABIL_ID_GEN.next())
public constant BRUSH_5_ACTIVE_ABILITY = compiletime(ABIL_ID_GEN.next())
public constant BRUSH_CIRCLE_ID = compiletime(ABIL_ID_GEN.next())
public constant BRUSH_RECT_ID = compiletime(ABIL_ID_GEN.next())

public class TerrainModder extends UnitEntity
	var brushsize = 0
	var brushshape = TShape.RECT
	var modification = 0// 0 = basic terrain, 1 = lava/revice 2 = poison

	construct(unit u)
		super(u)
		actor..setPos(hidden)..setPropWindow(0 .fromDeg())
		..addAbility(BRUSH_1_ACTIVE_ABILITY)..addAbility(BRUSH_3_IDLE_ABILITY)..addAbility(BRUSH_5_IDLE_ABILITY)
		..addAbility(BRUSH_RECT_ID)

		EventListener.add(actor, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, () -> changeTerrain())
		EventListener.add(actor, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, () -> changeTerrain())
		EventListener.add(actor, EVENT_PLAYER_UNIT_SPELL_EFFECT, () -> switchMode())

	function changeTerrain()
		var orderPos = EventData.getOrderPos()
		let oW = GetOrderTarget()

		if oW != null
			orderPos = oW.getPos()

		let rdata = getRegionData(orderPos)
		if rdata == null
			return
		let owner = actor.getOwner()
		let id = GetUnitTypeId(actor)
		if rdata.canBuild(owner) and not orderPos.getEBRTile().modifiers.get(TileModifier.RESERVED castTo int)
			idleSeconds = 0
			if id == SLIDEABLE_ICE_ID
				if modification == 1
					orderPos.changeTerrain(REVICE, brushsize, brushsize, brushshape, owner)
				else
					orderPos.changeTerrain(CONTROLLABLEICE, brushsize, brushsize, brushshape, owner)
			else if id == SLIDEABLE_UNC_ICE_ID
				orderPos.changeTerrain(UNCONTROLLABLEICE, brushsize, brushsize, brushshape, owner)
			else if id == WALKABLE_ID
				orderPos.changeTerrain(rdata.getTypeSet().walkableId, brushsize, brushsize, brushshape, owner)
			else if id == UNWALKABLE_ID
				if modification == 0
					orderPos.changeTerrain(rdata.getTypeSet().unwalkableId, brushsize, brushsize, brushshape, owner)
				else if modification == 1
					orderPos.changeTerrain(LAVA, brushsize, brushsize, brushshape, owner)
				else if modification == 2
					orderPos.changeTerrain(POISON, brushsize, brushsize, brushshape, owner)
		else
			DisplayTextToPlayer(owner, 0, 0, "|cffC51019You have no permission to change terrain here!")

	override function slowUpdate()
		super.slowUpdate()
		if idleSeconds > 20 and brushsize > 0
			idleSeconds = 0
			removeAllActive()
			actor..removeAbility(BRUSH_1_IDLE_ABILITY)
			..addAbility(BRUSH_1_ACTIVE_ABILITY)
			brushsize = 0

	function switchMode()
		let spell_id = GetSpellAbilityId()
		idleSeconds = 0
		switch spell_id
			case UNWALKABLE_MOD_ABILITY_ID[1]
				UnitRemoveAbility(actor,UNWALKABLE_MOD_ABILITY_ID[1])
				UnitAddAbility(actor,UNWALKABLE_MOD_ABILITY_ID[modification])
				modification = 1
				DisplayTextToPlayer(GetOwningPlayer(GetSpellAbilityUnit()), 0, 0, "Poison")
			case UNWALKABLE_MOD_ABILITY_ID[2]
				UnitRemoveAbility(actor,UNWALKABLE_MOD_ABILITY_ID[2])
				UnitAddAbility(actor,UNWALKABLE_MOD_ABILITY_ID[modification])
				modification = 2
				DisplayTextToPlayer(GetOwningPlayer(GetSpellAbilityUnit()), 0, 0, "Lava")
			case UNWALKABLE_MOD_ABILITY_ID[0]
				UnitRemoveAbility(actor,UNWALKABLE_MOD_ABILITY_ID[0])
				UnitAddAbility(actor,UNWALKABLE_MOD_ABILITY_ID[modification])
				modification = 0
				DisplayTextToPlayer(GetOwningPlayer(GetSpellAbilityUnit()), 0, 0, "Normal")
			case ICE_ABILITY
				UnitRemoveAbility(actor,ICE_ABILITY)
				UnitAddAbility(actor,REVICE_ABILITY)
				modification = 0
				DisplayTextToPlayer(GetOwningPlayer(GetSpellAbilityUnit()), 0, 0, "Normal")
			case REVICE_ABILITY
				UnitRemoveAbility(actor,REVICE_ABILITY)
				UnitAddAbility(actor,ICE_ABILITY)
				modification = 1
				DisplayTextToPlayer(GetOwningPlayer(GetSpellAbilityUnit()), 0, 0, "Reverse")
			case BRUSH_1_IDLE_ABILITY
				removeAllActive()
				actor..removeAbility(BRUSH_1_IDLE_ABILITY)
				..addAbility(BRUSH_1_ACTIVE_ABILITY)
				brushsize = 0
			case BRUSH_3_IDLE_ABILITY
				removeAllActive()
				actor..removeAbility(BRUSH_3_IDLE_ABILITY)
				..addAbility(BRUSH_3_ACTIVE_ABILITY)
				brushsize = 1
			case BRUSH_5_IDLE_ABILITY
				removeAllActive()
				actor..removeAbility(BRUSH_5_IDLE_ABILITY)
				..addAbility(BRUSH_5_ACTIVE_ABILITY)
				brushsize = 2
			case BRUSH_RECT_ID
				brushshape = TShape.CIRCLE
				actor..removeAbility(BRUSH_RECT_ID)
				..addAbility(BRUSH_CIRCLE_ID)
			case BRUSH_CIRCLE_ID
				brushshape = TShape.RECT
				actor..removeAbility(BRUSH_CIRCLE_ID)
				..addAbility(BRUSH_RECT_ID)
			default

	function removeAllActive()
		if actor.removeAbility(BRUSH_1_ACTIVE_ABILITY)
			actor.addAbility(BRUSH_1_IDLE_ABILITY)
		if actor.removeAbility(BRUSH_3_ACTIVE_ABILITY)
			actor.addAbility(BRUSH_3_IDLE_ABILITY)
		if actor.removeAbility(BRUSH_5_ACTIVE_ABILITY)
			actor.addAbility(BRUSH_5_IDLE_ABILITY)


	boolean legit = false
	ondestroy
		if not legit
			error("Shouldn't happen ok.")


enum TShape
	RECT
	CIRCLE

public function vec2.changeTerrain(int ttype, int hsize, int vsize, TShape shape, player caster)
	switch shape
		case RECT
			this.changeRect(ttype, hsize, vsize, caster)
		case CIRCLE
			this.changeCircle(ttype, hsize, vsize, caster)


public function vec2.changeRect(int ttype, int hsize, int vsize, player caster)
	let hhalf = (hsize*2) div 2
	let vhalf = (vsize*2) div 2
	for i = -hhalf to hhalf
		for j = -vhalf to vhalf
			this.setTerrain(ttype, vec2(i * 128., j * 128.), caster)

public function vec2.changeCircle(int ttype, int hsize, int vsize, player caster)
	let hhalf = (hsize*2) div 2
	let vhalf = (vsize*2) div 2
	for i = -hhalf to hhalf
		for j = -vhalf to vhalf
			if i == 0 or j == 0
				this.setTerrain(ttype, vec2(i * 128., j * 128.), caster)
	if vsize > 1 and hsize > 1
		this.changeRect(ttype, 1, 1, caster)

public function vec2.setTerrain(int ttype, vec2 off, player caster)
	var offset = this + off
	offset.x = (offset.x / 128).round() * 128.
	offset.y = (offset.y / 128).round() * 128.
	let rdata = getRegionData(offset)
	if rdata != null and rdata.canBuild(caster)
		offset.getEBRTile().setType(ttype)

@objectgen public function genTerrainModder()
	new ChannelAbilityPreset(BRUSH_1_IDLE_ABILITY, 1, true)
	..makeUnitSpell(0,0)
	..setName("Tmod: 1x1 Brush Idle")
	..presetIcon("BTN1x1inactive")
	..presetHotkey("Y")
	..presetTooltipNormal(lvl -> "|cffFF8C291|rx|cffFF8C291 |rBrush Size [|cffFFCC00Y|r]")
	..presetTooltipNormalExtended(lvl -> "|cffFFCC00Click to select")
	..presetButtonPosNormal(0, 2)

	new ChannelAbilityPreset(BRUSH_1_ACTIVE_ABILITY, 1, true)
	..makeUnitSpell(0,0)
	..setName("Tmod: 1x1 Brush Active")
	..presetIcon("BTN1x1active")
	..presetHotkey("Y")
	..presetTooltipNormal(lvl -> "|cffFF8C291|rx|cffFF8C291 |rBrush Size |cffFFCC00Selected!")
	..presetTooltipNormalExtended(lvl -> "")
	..presetButtonPosNormal(0, 2)

	new ChannelAbilityPreset(BRUSH_3_IDLE_ABILITY, 1, true)
	..makeUnitSpell(0,0)
	..setName("Tmod: 3x3 Brush Idle")
	..presetIcon("BTN3x3inactive")
	..presetHotkey("X")
	..presetTooltipNormal(lvl -> "|cffFF8C293|rx|cffFF8C293 |rBrush Size [|cffFFCC00X|r]")
	..presetTooltipNormalExtended(lvl -> "|cffFFCC00Click to select")
	..presetButtonPosNormal(1, 2)

	new ChannelAbilityPreset(BRUSH_3_ACTIVE_ABILITY, 1, true)
	..makeUnitSpell(0,0)
	..setName("Tmod: 3x3 Brush Active")
	..presetIcon("BTN3x3active.blp")
	..presetHotkey("X")
	..presetTooltipNormal(lvl -> "|cffFF8C293|rx|cffFF8C293 |rBrush Size |cffFFCC00Selected!")
	..presetTooltipNormalExtended(lvl -> "")
	..presetButtonPosNormal(1, 2)

	new ChannelAbilityPreset(BRUSH_5_IDLE_ABILITY, 1, true)
	..makeUnitSpell(0,0)
	..setName("Tmod: 5x5 Brush Idle")
	..presetIcon("BTN5x5inactive.blp")
	..presetHotkey("C")
	..presetTooltipNormal(lvl -> "|cffFF8C295|rx|cffFF8C295 |rBrush Size [|cffFFCC00C|r]")
	..presetTooltipNormalExtended(lvl -> "|cffFFCC00Click to select")
	..presetButtonPosNormal(2, 2)

	new ChannelAbilityPreset(BRUSH_5_ACTIVE_ABILITY, 1, true)
	..makeUnitSpell(0,0)
	..setName("Tmod: 3x3 Brush Active")
	..presetIcon("BTN5x5active.blp")
	..presetHotkey("C")
	..presetTooltipNormal(lvl -> "|cffFF8C295|rx|cffFF8C295 |rBrush Size |cffFFCC00Selected!")
	..presetTooltipNormalExtended(lvl -> "")
	..presetButtonPosNormal(2, 2)

	new ChannelAbilityPreset(BRUSH_RECT_ID, 1, true)
	..makeUnitSpell(0,0)
	..setName("Tmod: Rectengular Brush Shape")
	..presetIcon("BTNrectangle")
	..presetHotkey("A")
	..presetTooltipNormal(lvl -> "|cffFF8C29Rectangular |cffF7F7F7brush |cffFFCC00selected")
	..presetTooltipNormalExtended(lvl -> "|cffFFCC00Click to change to circular brush")
	..presetButtonPosNormal(0, 1)

	new ChannelAbilityPreset(BRUSH_CIRCLE_ID, 1, true)
	..makeUnitSpell(0,0)
	..setName("Tmod: Circular Brush Shape")
	..presetIcon("BTNcircle")
	..presetHotkey("A")
	..presetTooltipNormal(lvl -> "|cffFF8C29Circular |cffF7F7F7brush |cffFFCC00selected")
	..presetTooltipNormalExtended(lvl -> "|cffFFCC00Click to change to rectangular brush")
	..presetButtonPosNormal(0, 1)

	new HeroDefinition(WALKABLE_ID, 'Hblm')
	..setName("|cff08B552Walkable")
	..setHotkey("")
	..setIconGameInterface("ReplaceableTextures\\CommandButtons\\BTNWalkableTerrain.blp")
	..setNormalAbilities(commaList(INVULNERABILITY_ID))
	..setAttacksEnabled(0)
	..setAnimationBlendTimeseconds(0)
	..setAnimationCastBackswing(0)
	..setAnimationRunSpeed(0)
	..setAnimationWalkSpeed(0)
	..setAnimationCastPoint(0)
	..setScalingValue(0.1)
	..setShadowImageUnit("")
	..setSelectionScale(-0.03)
	..setSpeedBase(1)
	..setTurnRate(0.1)
	..setProperNames("Terrainmenu")
	..setProperNamesUsed(0)
	..setHeroAbilities("")
	..setMovementType(MovementType.None)
	..setModelFile(" .mdl")
	..setUnitSoundSet("")
	..setCollisionSize(0)
	..setHitPointsMaximumBase(10000000)
	..setSightRadiusDay(0)
	..setSightRadiusNight(0)
	..setStartingAgility(0)
	..setStartingIntelligence(0)
	..setStartingStrength(0)
	..setTintingColorBlue(150)
	..setTintingColorGreen(150)
	..setTintingColorRed(150)
	..setTeamColor(12)
	..setPriority(4)
	..setHideMinimapDisplay(true)
	..setRace(Race.Commoner)

	new HeroDefinition(UNWALKABLE_ID, 'Hblm')
	..setName("|cffFF6331Unwalkable")
	..setHotkey("")
	..setIconGameInterface("ReplaceableTextures\\CommandButtons\\BTNUnwalkableTerrain.blp")
	..setNormalAbilities(commaList('A04Y', 'A04X', INVULNERABILITY_ID))
	..setAttacksEnabled(0)
	..setAnimationBlendTimeseconds(0)
	..setAnimationCastBackswing(0)
	..setAnimationRunSpeed(0)
	..setAnimationWalkSpeed(0)
	..setAnimationCastPoint(0)
	..setScalingValue(0.1)
	..setShadowImageUnit("")
	..setSelectionScale(-0.03)
	..setProperNames("Terrainmenu")
	..setProperNamesUsed(0)
	..setSpeedBase(1)
	..setTurnRate(0.1)
	..setHeroAbilities("")
	..setMovementType(MovementType.None)
	..setModelFile(" .mdl")
	..setUnitSoundSet("")
	..setCollisionSize(0)
	..setHitPointsMaximumBase(10000000)
	..setSightRadiusDay(0)
	..setSightRadiusNight(0)
	..setStartingAgility(0)
	..setStartingIntelligence(0)
	..setStartingStrength(0)
	..setTintingColorBlue(0)
	..setTintingColorRed(0)
	..setTeamColor(12)
	..setPriority(9)
	..setHideMinimapDisplay(true)
	..setRace(Race.Commoner)

	new HeroDefinition(SLIDEABLE_ICE_ID, 'Hblm')
	..setName("|cff08ADF7Slideable Ice")
	..setHotkey("")
	..setIconGameInterface("ReplaceableTextures\\CommandButtons\\BTNIce1.blp")
	..setNormalAbilities(commaList('A00C', INVULNERABILITY_ID))
	..setAttacksEnabled(0)
	..setAnimationBlendTimeseconds(0)
	..setAnimationCastBackswing(0)
	..setAnimationRunSpeed(0)
	..setAnimationWalkSpeed(0)
	..setAnimationCastPoint(0)
	..setScalingValue(0.1)
	..setShadowImageUnit("")
	..setSelectionScale(-0.03)
	..setSpeedBase(1)
	..setTurnRate(0.1)
	..setProperNames("Terrainmenu")
	..setProperNamesUsed(0)
	..setMovementType(MovementType.None)
	..setModelFile(" .mdl")
	..setUnitSoundSet("")
	..setCollisionSize(0)
	..setHitPointsMaximumBase(10000000)
	..setSightRadiusDay(0)
	..setHeroAbilities("")
	..setSightRadiusNight(0)
	..setStartingAgility(0)
	..setStartingIntelligence(0)
	..setStartingStrength(0)
	..setTintingColorGreen(100)
	..setTintingColorRed(50)
	..setTeamColor(12)
	..setPriority(2)
	..setHideMinimapDisplay(true)
	..setRace(Race.Commoner)

	new HeroDefinition(SLIDEABLE_UNC_ICE_ID, 'Hblm')
	..setName("|cff2952B5Slideable Ice (Uncontrolled)")
	..setHotkey("")
	..setIconGameInterface("ReplaceableTextures\\CommandButtons\\BTNIce2.blp")
	..setNormalAbilities(commaList(INVULNERABILITY_ID))
	..setAttacksEnabled(0)
	..setAnimationBlendTimeseconds(0)
	..setAnimationCastBackswing(0)
	..setAnimationRunSpeed(0)
	..setAnimationWalkSpeed(0)
	..setAnimationCastPoint(0)
	..setScalingValue(0.1)
	..setShadowImageUnit("")
	..setSelectionScale(-0.03)
	..setSpeedBase(1)
	..setProperNames("Terrainmenu")
	..setProperNamesUsed(0)
	..setTurnRate(0.1)
	..setHeroAbilities("")
	..setMovementType(MovementType.None)
	..setModelFile(" .mdl")
	..setUnitSoundSet("")
	..setCollisionSize(0)
	..setHitPointsMaximumBase(10000000)
	..setSightRadiusDay(0)
	..setSightRadiusNight(0)
	..setStartingAgility(0)
	..setStartingIntelligence(0)
	..setStartingStrength(0)
	..setTintingColorGreen(50)
	..setTintingColorRed(0)
	..setTeamColor(12)
	..setPriority(1)
	..setHideMinimapDisplay(true)
	..setRace(Race.Commoner)