package Executer import TerrainModder import BaseObject import Escaper import EscaperKillers import Door import Pointer import Assets import Knockbacker import Builder constant INFO_EXECUTER_ID = compiletime(ABIL_ID_GEN.next()) constant EFFECT_STRING = Abilities.manaFlareBase constant LEVER_DUMMY_ID = 'DTlv' constant PLATE_DUMMY_ID = 'B001' constant EVENT_RADIUS = 42. constant ONESHOT_ABIL = 'A068' constant REPEATING_ABIL = 'A069' constant LEVER_ABIL = 'A067' constant PRESSURE_ABIL = 'A066' constant REACTIVATE_ABIL = 'A06Z' constant TERRAIN_CHANGE_ABIL = 'A036' constant TERRAIN_WALKABLE_ABIL = 'A015' constant TERRAIN_UNWALKABLE_ABIL = 'A016' constant TERRAIN_ICE_ABIL = 'A019' constant TERRAIN_UNICE_ABIL = 'A01A' constant TERRAIN_REVICE_ABIL = 'A00A' constant TERRAIN_W_O_ABIL = 'A03A' constant TERRAIN_UW_O_ABIL = 'A039' constant TERRAIN_I_O_ABIL = 'A038' constant TERRAIN_UI_O_ABIL = 'A037' constant TERRAIN_RI_O_ABIL = 'A00O' constant TERRAIN_INCREASE_H_ABIL = 'A01K' constant TERRAIN_INCREASE_V_ABIL = 'A01M' constant TERRAIN_DECREASE_H_ABIL = 'A01U' constant TERRAIN_DECREASE_V_ABIL = 'A01T' constant TERRAIN_BOOK_ABIL = 'A035' constant TERRAIN_ANTIBOOK_ABIL = 'A06B' constant DOOR_OPEN_ABIL = 'A018' constant DOOR_CLOSE_ABIL = 'A01N' constant DOOR_TOGGLE_ABIL = 'A01Q' constant MOVE_UNIT_DIRECT_ABIL = 'A04R' constant MOVE_UNIT_PATROL_ABIL = 'A064' constant MOVE_UNIT_STOP_ABIL = 'A065' constant MOVE_UNIT_SELECT_ABIL = 'A06A' constant TRAIN_BOOK_ABIL = 'A042' constant SPAWN_UNIT_ID = 'A06S' constant TRAIN_BK_ABIL = 'A045' constant TRAIN_SK_ABIL = 'A046' constant TRAIN_BRK_ABIL = 'A048' constant TRAIN_SRK_ABIL = 'A04B' constant TRAIN_TANK_ABIL = 'A04C' constant TRAIN_GLAIVE_ABIL = 'A04W' constant TRAIN_POINTER_ABIL = 'A04D' constant TRAIN_KNOCK_ABIL = 'A07R' constant executerUnitLeave = CreateTrigger() constant executerUnitEnter = CreateTrigger() public enum Emode NONE REPEATING ONESHOT LEVER PRESSUREPLATE public enum Amode NONE ENABLEOBJ DISABLEOBJ TOGGLEOBJ CREATEUNIT MOVEUNIT CHANGETERRAIN enum ActionUnit NONE TANK GLAIVE SMALLKILLER BIGKILLER SMALLRANDOMKILLER BIGRANDOMKILLER POINTER KNOCKER public class Executer extends StaticBaseObject boolean canKillerTrigger = false boolean canEscaperTrigger = true rect eventRect = null // only for pressureplate region eventRegion = null LinkedList entitiesOnPlate = null Emode eventMode = Emode.NONE Amode actionMode = Amode.NONE boolean ON = false// only for lever and pressureplate //effect oneffect // when lever and pressurplate is active int tiletype //Terrain Change tile type int nottiletype = '0001' // The basic is Unwalkable int verticalTileSize = 0 int horizontalTileSize = 0 unit unitToMove = null // for unitMover ActionUnit actionUnit // only for UnitCreator Executer string moveOrderString // only for unitMover boolean disabled = false // only for oneshot, so you can re-activate destructable dummy = null // model for pressure plate, and lever construct(unit existing) super(existing.getPos(), existing, EVENT_RADIUS, () -> (GetTriggeringTrigger().getSource().getEntity() castTo Executer).onEvent(), null) construct(vec2 pos, player owner) super(pos, createUnit(owner, EXECUTER_ID, pos, angle(0)), EVENT_RADIUS, () -> (GetTriggeringTrigger().getSource().getEntity() castTo Executer).onEvent(), null) EventListener.add(actor, EVENT_PLAYER_UNIT_SPELL_CAST, () -> onCast()) function onEvent() let entity = GetTriggerUnit().getEntity() if canTrigger(entity) switch eventMode case Emode.NONE DisplayTextToPlayer(owner, 0, 0, "|cffC51019Please select an Event Mode for the Executer") case Emode.REPEATING findAction() case Emode.ONESHOT if not disabled flashEffect(Abilities.charmTarget, getPos()) findAction() disable() case Emode.LEVER if ON negativeAction() ON = false if dummy != null SetDestructableAnimation(dummy, "death") else findAction() ON = true if dummy != null SetDestructableAnimation(dummy, "stand") //obj.oneffect = AddSpecialEffect(EFFECT_STRING, obj.actor.getX(), obj.actor.getY()) case Emode.PRESSUREPLATE function onLeave() let leftEntity = GetLeavingUnit().getEntity() if enabled and canTrigger(leftEntity) entitiesOnPlate.remove(leftEntity) if entitiesOnPlate.isEmpty() and ON negativeAction() ON = false if dummy != null SetDestructableAnimation(dummy, "stand alternate") function onEnter() let e = GetEnteringUnit().getEntity() if enabled and canTrigger(e) entitiesOnPlate.add(e) if not ON findAction() ON = true if dummy != null SetDestructableAnimation(dummy, "death") override function slowUpdate() if eventMode == Emode.PRESSUREPLATE and actionMode != Amode.NONE and ON and not entitiesOnPlate.isEmpty() entitiesOnPlate.removeIf(entity -> not entity.actor.isAlive() or not entity.getPos().toVec2().isInRegion(eventRegion)) if entitiesOnPlate.isEmpty() negativeAction() ON = false if dummy != null SetDestructableAnimation(dummy, "stand alternate") function findAction() let target = getRallyUnit().getEntity() switch actionMode case Amode.NONE DisplayTextToPlayer(owner, 0, 0, "|cffC51019Please select an Action Mode for the Executer") case Amode.DISABLEOBJ if target == null DisplayTextToPlayer(owner, 0, 0, "|cffC51019Must select an object with the Executer") else if target instanceof StaticBaseObject (target castTo StaticBaseObject).setEnabled(false) else if target instanceof SetupObject (target castTo SetupObject).setEnabled(true) else if target instanceof Door (target castTo Door).closeDoor() else DisplayTextToPlayer(owner, 0, 0, "|cffC51019Invalid object selected") case Amode.TOGGLEOBJ if target == null DisplayTextToPlayer(owner, 0, 0, "|cffC51019Must select an object with the Executer") else if target instanceof StaticBaseObject (target castTo StaticBaseObject).setEnabled(not (target castTo StaticBaseObject).enabled) else if target instanceof SetupObject (target castTo SetupObject).setEnabled(not (target castTo SetupObject).enabled) else if target instanceof Door let door = target castTo Door if door.opened door.closeDoor() else door.openDoor() else DisplayTextToPlayer(owner, 0, 0, "|cffC51019Invalid object selected") case Amode.ENABLEOBJ if target == null DisplayTextToPlayer(owner, 0, 0, "|cffC51019Must select an object with the Executer") else if target instanceof StaticBaseObject (target castTo StaticBaseObject).setEnabled(true) else if target instanceof SetupObject (target castTo SetupObject).setEnabled(true) else if target instanceof Door (target castTo Door).openDoor() else DisplayTextToPlayer(owner, 0, 0, "|cffC51019Invalid object selected") case Amode.CHANGETERRAIN changeTerrain(true) case Amode.MOVEUNIT moveUnit() case Amode.CREATEUNIT createUnitInternal() default printTimedToPlayer("Executer has no action set", 15, owner) function negativeAction() let target = getRallyUnit().getEntity() switch actionMode case Amode.DISABLEOBJ if target == null DisplayTextToPlayer(owner, 0, 0, "|cffC51019Must select an object with the Executer") if target instanceof StaticBaseObject (target castTo StaticBaseObject).setEnabled(true) else if target instanceof SetupObject (target castTo SetupObject).setEnabled(true) else if target instanceof Door (target castTo Door).openDoor() else DisplayTextToPlayer(owner, 0, 0, "|cffC51019Invalid object selected") case Amode.TOGGLEOBJ if target == null DisplayTextToPlayer(owner, 0, 0, "|cffC51019Must select an object with the Executer") if target instanceof StaticBaseObject (target castTo StaticBaseObject).setEnabled(not (target castTo StaticBaseObject).enabled) else if target instanceof SetupObject (target castTo SetupObject).setEnabled(not (target castTo SetupObject).enabled) else if target instanceof Door let door = target castTo Door if door.opened door.closeDoor() else door.openDoor() else DisplayTextToPlayer(owner, 0, 0, "|cffC51019Invalid object selected") case Amode.ENABLEOBJ if target == null DisplayTextToPlayer(owner, 0, 0, "|cffC51019Must select an object with the Executer") if target instanceof StaticBaseObject (target castTo StaticBaseObject).setEnabled(false) else if target instanceof SetupObject (target castTo SetupObject).setEnabled(false) else if target instanceof Door (target castTo Door).closeDoor() else DisplayTextToPlayer(owner, 0, 0, "|cffC51019Invalid object selected") case Amode.CHANGETERRAIN changeTerrain(false) default printTimedToPlayer("Executer has no action set", 15, owner) function moveUnit() let rallyPos = getRallyPoint() if moveOrderString == "stop" IssueImmediateOrder(unitToMove, moveOrderString) else IssuePointOrder(unitToMove, moveOrderString, rallyPos.x, rallyPos.y) function toggleObject() let ru = getRallyUnit() if ru != null let data = ru.getEntity() if data instanceof StaticBaseObject let bo = data castTo StaticBaseObject bo.setEnabled(not bo.enabled) else printLog(owner, Loglevel.WARNING, "Executer: No object selected") function createUnitInternal() let rallyPos = getRallyPoint().toVec2() let data = getRegionData(rallyPos) if data.canBuild(owner) switch actionUnit case ActionUnit.SMALLKILLER new SmallKiller(rallyPos,owner, getRallyAngle()) case ActionUnit.BIGKILLER new BigKiller(rallyPos,owner, getRallyAngle()) case ActionUnit.SMALLRANDOMKILLER new SmallRandomKiller(rallyPos,owner, getRallyAngle()) case ActionUnit.BIGRANDOMKILLER new BigRandomKiller(rallyPos,owner, getRallyAngle()) case ActionUnit.TANK new TankKiller(rallyPos,owner, getRallyAngle()) case ActionUnit.GLAIVE new GlaiveKiller(rallyPos,owner, getRallyAngle()) case ActionUnit.POINTER new Pointer(vec2(rallyPos.x,rallyPos.y), owner, getRallyAngle()) case ActionUnit.KNOCKER new Knockbacker(vec2(rallyPos.x,rallyPos.y), owner, getRallyAngle()) default error("Unitcreator - Wrong Unittype") else DisplayTextToPlayer(owner, 0, 0, "|cffC51019You have no permission to place units in this region!") function changeTerrain(boolean isAction) let rallyPos = getRallyPoint() int tileID let data = getRegionData(rallyPos) if isAction tileID = tiletype else tileID = nottiletype if tileID == '0000' tileID = data.getTypeSet().walkableId else if tileID== '0001' tileID = data.getTypeSet().unwalkableId rallyPos.toVec2().changeRect(tileID, horizontalTileSize, verticalTileSize, owner) function addActionAbilsNormal() actor..addAbility(DOOR_CLOSE_ABIL)..addAbility(DOOR_OPEN_ABIL)..addAbility(DOOR_TOGGLE_ABIL) ..addAbility(TERRAIN_CHANGE_ABIL)..addAbility(MOVE_UNIT_DIRECT_ABIL)..addAbility(SPAWN_UNIT_ID) function addActionAbilsReversable() actor..addAbility(DOOR_CLOSE_ABIL)..addAbility(DOOR_OPEN_ABIL)..addAbility(DOOR_TOGGLE_ABIL) ..addAbility(TERRAIN_CHANGE_ABIL) function removeModeAbils() actor..removeAbility(ONESHOT_ABIL)..removeAbility(REPEATING_ABIL)..removeAbility(LEVER_ABIL) ..removeAbility(PRESSURE_ABIL) function removeActionAbils() actor..removeAbility(DOOR_CLOSE_ABIL)..removeAbility(DOOR_OPEN_ABIL)..removeAbility(DOOR_TOGGLE_ABIL) ..removeAbility(TERRAIN_CHANGE_ABIL)..removeAbility(MOVE_UNIT_DIRECT_ABIL)..removeAbility(SPAWN_UNIT_ID) actor..addAbility(TURN_OFF_ID) function addTerrainAdjuster() actor..addAbility(TERRAIN_INCREASE_V_ABIL)..addAbility(TERRAIN_INCREASE_H_ABIL)..addAbility(TERRAIN_DECREASE_V_ABIL) ..addAbility(TERRAIN_DECREASE_H_ABIL)..addAbility(TERRAIN_BOOK_ABIL) if eventMode == Emode.LEVER or eventMode == Emode.PRESSUREPLATE UnitAddAbility(actor, TERRAIN_ANTIBOOK_ABIL) function addMoveUnitAdjuster() actor..addAbility(MOVE_UNIT_STOP_ABIL)..addAbility(MOVE_UNIT_DIRECT_ABIL) ..addAbility(MOVE_UNIT_PATROL_ABIL)..addAbility(MOVE_UNIT_SELECT_ABIL) function changeVis(boolean invis) if eventMode == Emode.PRESSUREPLATE if invis ShowDestructable(dummy, false) else ShowDestructable(dummy, true) SetDestructableAnimation(dummy, "death") else if eventMode == Emode.LEVER if invis ShowDestructable(dummy, false) else ShowDestructable(dummy, true) SetDestructableAnimation(dummy, "stand alternate") function registerRect(real centerx, real centery, real offset) //note: with movable circles, itll be necessarallyPos.y to move the rect too. actor.clearRegister() inRangeTrig..clearConditions()..clearActions()..destr() entitiesOnPlate = new LinkedList() eventRect = Rect(centerx - offset, centery - offset, centerx + offset, centery + offset) eventRegion = CreateRegion() eventRegion.addRect(eventRect) eventRegion.setRegionData(this castTo int) TriggerRegisterLeaveRegion(executerUnitLeave, eventRegion, null) executerUnitLeave.addCondition(Condition(() -> GetTriggeringRegion().loadRegionData() castTo Executer.onLeave())) TriggerRegisterEnterRegion(executerUnitEnter, eventRegion, null) executerUnitEnter.addCondition(Condition(() -> GetTriggeringRegion().loadRegionData() castTo Executer.onEnter())) function disable() actor.setVertexColor(44, 44, 44, 255) disabled = true actor.addAbility(REACTIVATE_ABIL) createFText(pos, vec2(0,0.05), "Deactivated", 10, 2., colorA(50,50,50,0), owner) ondestroy if eventRect != null RemoveRect(eventRect) if eventRegion != null eventRegion.removeRegionData() eventRegion.destr() if dummy != null RemoveDestructable(dummy) if entitiesOnPlate != null destroy entitiesOnPlate function canTrigger(Entity e) returns boolean if canEscaperTrigger and e instanceof Escaper return true if canKillerTrigger and e instanceof EscaperSensorSetup return true return false function onCast() returns boolean let id = GetSpellAbilityId() switch id case ONESHOT_ABIL eventMode = Emode.ONESHOT addActionAbilsNormal() removeModeAbils() case REPEATING_ABIL eventMode = Emode.REPEATING addActionAbilsNormal() removeModeAbils() case LEVER_ABIL eventMode = Emode.LEVER addActionAbilsReversable() removeModeAbils() dummy = CreateDestructable(LEVER_DUMMY_ID, actor.getX(), actor.getY(), 0,1,0) SetDestructableAnimation(dummy, "death") case PRESSURE_ABIL eventMode = Emode.PRESSUREPLATE addActionAbilsReversable() removeModeAbils() registerRect(actor.getX(), actor.getY(), 54) dummy = CreateDestructable(PLATE_DUMMY_ID, actor.getX(), actor.getY(), 0,1,0) SetDestructableAnimation(dummy, "stand alternate") case REACTIVATE_ABIL disabled = false SetUnitVertexColor(actor, 0,128,0,255) UnitRemoveAbility(actor, REACTIVATE_ABIL) case MAKE_UNIT_VISIBLE_ID changeVis(false) case MAKE_UNIT_INVISIBLE_ID changeVis(true) case MODE_KILLERS_ID canKillerTrigger = true canEscaperTrigger = true UnitRemoveAbility(actor, MODE_KILLERS_ID) UnitAddAbility(actor, MODE_BOTH_ID) case MODE_ESCAPERS_ID canKillerTrigger = true canEscaperTrigger = false UnitRemoveAbility(actor, MODE_ESCAPERS_ID) UnitAddAbility(actor, MODE_KILLERS_ID) case MODE_BOTH_ID canKillerTrigger = false canEscaperTrigger = true UnitRemoveAbility(actor, MODE_BOTH_ID) UnitAddAbility(actor, MODE_ESCAPERS_ID) case DOOR_OPEN_ABIL actionMode = Amode.ENABLEOBJ removeActionAbils() case DOOR_CLOSE_ABIL actionMode = Amode.DISABLEOBJ removeActionAbils() case DOOR_TOGGLE_ABIL actionMode = Amode.TOGGLEOBJ removeActionAbils() case TERRAIN_CHANGE_ABIL actionMode = Amode.CHANGETERRAIN removeActionAbils() addTerrainAdjuster() tiletype = '0000' nottiletype = '0001' case TERRAIN_WALKABLE_ABIL tiletype = '0000' case TERRAIN_W_O_ABIL nottiletype = '0000' case TERRAIN_UNWALKABLE_ABIL tiletype = '0001' case TERRAIN_UW_O_ABIL nottiletype = '0001' case TERRAIN_ICE_ABIL tiletype = CONTROLLABLEICE case TERRAIN_REVICE_ABIL tiletype = REVICE case TERRAIN_I_O_ABIL nottiletype = CONTROLLABLEICE case TERRAIN_UNICE_ABIL tiletype = UNCONTROLLABLEICE case TERRAIN_UI_O_ABIL nottiletype = UNCONTROLLABLEICE case TERRAIN_RI_O_ABIL nottiletype = REVICE case SPAWN_UNIT_ID actionMode = Amode.CREATEUNIT actionUnit = ActionUnit.TANK removeActionAbils() UnitAddAbility(actor,TRAIN_BOOK_ABIL) case TRAIN_BK_ABIL actionUnit = ActionUnit.BIGKILLER case TRAIN_SK_ABIL actionUnit = ActionUnit.SMALLKILLER case TRAIN_BRK_ABIL actionUnit = ActionUnit.BIGRANDOMKILLER case TRAIN_SRK_ABIL actionUnit = ActionUnit.SMALLRANDOMKILLER case TRAIN_TANK_ABIL actionUnit = ActionUnit.TANK case TRAIN_GLAIVE_ABIL actionUnit = ActionUnit.GLAIVE case TRAIN_POINTER_ABIL actionUnit = ActionUnit.POINTER case TRAIN_KNOCK_ABIL actionUnit = ActionUnit.KNOCKER case MOVE_UNIT_DIRECT_ABIL moveOrderString = "move" if actionMode == Amode.NONE actionMode = Amode.MOVEUNIT removeActionAbils() addMoveUnitAdjuster() case MOVE_UNIT_PATROL_ABIL moveOrderString = "patrol" case MOVE_UNIT_STOP_ABIL moveOrderString = "stop" case MOVE_UNIT_SELECT_ABIL let target = GetSpellTargetUnit() if target.getOwner() == owner and target.getEntity().getCurrentRegion() == this.getCurrentRegion() and not target.getEntity() instanceof Builder unitToMove = target case TERRAIN_INCREASE_H_ABIL if not horizontalTileSize > 3 horizontalTileSize ++ case TERRAIN_INCREASE_V_ABIL if not verticalTileSize > 3 verticalTileSize ++ case TERRAIN_DECREASE_H_ABIL if not horizontalTileSize < 1 horizontalTileSize -- case TERRAIN_DECREASE_V_ABIL if not verticalTileSize < 1 verticalTileSize -- return false override function serialize() returns Json let json = super.serialize() json..addProperty(new Property(KEY_TYPE, EXECUTER_INDEX.toString())) return json @objectgen function genExecuter() new ChannelAbilityPreset(INFO_EXECUTER_ID, 1, TRUE) ..setName("Information: Executer") ..presetTooltipNormal(lvl -> "Information: Executer") ..presetTooltipNormalExtended(lvl -> "The Executer does some advanced actions when an Escaper walks in." + "\nYou define the Action by using the Spell once." + "\nThe Action will be executed at the RallyPoint or RallyUnit." + "\nYou can change the executer to loop or be a one-shot") ..presetIcon("ReplaceableTextures\\CommandButtons\\PASInfo.blp") ..presetButtonPosNormal(0, 0) ..presetTargetTypes(Targettype.PASSIVE) ..setHeroAbility(FALSE) new BuildingDefinition(EXECUTER_ID, 'ncop') ..setName("|cff84C54AExecuter") ..setHotkey("X") ..setTooltipBasic("|cffFFCC00Build |cff84C54AExecuter [X]") ..setTooltipExtended("Executes specified actions on other units or positions like opening and closing gates," + "creating units and changing terrain when an escaper and/or killer walks over it." + "\nIt has 3 available modes: Pressure Plate, Standard and Lever.") ..setIconGameInterface("ReplaceableTextures\\CommandButtons\\BTNExecuter.blp") ..setNormalAbilities(commaList('A066', 'A068', 'A069', 'A067', MODE_ESCAPERS_ID, REMOVE_OBJECT_ID, MAKE_UNIT_INVISIBLE_ID, RALLY_POINT, INVULNERABILITY_ID, GHOST_VIS_ID)) ..setButtonPositionX(1) ..setButtonPositionY(2) ..setTintingColorRed(0) ..setTintingColorGreen(128) ..setTintingColorBlue(0) ..setSightRadiusDay(0) ..setSightRadiusNight(0) ..setBuildTime(1) ..setCollisionSize(0) ..setScalingValue(0.8) ..setSelectionScale(2.2) ..setUnitClassification("ancient,standon") ..setHideMinimapDisplay(true)