package DummyRecycler import NoWurst import public Unit import public Timer import Basics import ErrorHandling import MapBounds import AbilityObjEditing import ObjectIds import Colors import Annotations import UnitIds import Icons import ObjectIdGenerator import LinkedList import TypeCasting import ClosureTimers /** Id of the dummy unit */ public constant DUMMY_UNIT_ID = compiletime(UNIT_ID_GEN.next()) /** Id of the root ability it makes unit: 1. not need to turn when spell or attack 2. can't move or turn by order like a building 3. but you can still set it's postion with code 4. the effect remains even if this ability is removed */ public constant ROOT_ENABLER = compiletime(ABIL_ID_GEN.next()) public constant DISABLE_AUTO_ACQUIRE_ATTACK_TARGETS_ABILITY_ID = compiletime(ABIL_ID_GEN.next()) constant DIFFERENT_ANGLES = 8 constant ANGLE_DEGREE = 360 / DIFFERENT_ANGLES constant SAVED_UNITS_PER_ANGLE = 6 public class DummyRecycler static LinkedList array angleQueues static function get(vec2 pos, angle a) returns unit let angleIndex = (a.degrees() % 360 / ANGLE_DEGREE).round() mod DIFFERENT_ANGLES if angleQueues[angleIndex].size() > 0 return angleQueues[angleIndex].dequeue()..setXY(pos)..unpause() else return createDummy(pos, a) static function recycle(unit u) var smallestQueue = 0 for i = 1 to DIFFERENT_ANGLES - 1 if angleQueues[smallestQueue].size() > angleQueues[i].size() smallestQueue = i if angleQueues[smallestQueue].size() >= SAVED_UNITS_PER_ANGLE u.remove() else angleQueues[smallestQueue].enqueue(u) u..setXY(boundMax - vec2(16, 16)) ..pause() ..setFacing((smallestQueue * ANGLE_DEGREE).asAngleDegrees()) ..setScale(1) ..setVertexColor(COLOR_WHITE) ..setOwner(DUMMY_PLAYER, true) static function recycle(unit u, real delay) doAfter(delay) -> DummyRecycler.recycle(u) function createDummy(vec2 pos, angle facing) returns unit let u = createUnit(DUMMY_PLAYER, DUMMY_UNIT_ID, pos, facing) u..addAbility(HEIGHT_ENABLER)..removeAbility(HEIGHT_ENABLER) ..addAbility(ROOT_ENABLER)..removeAbility(ROOT_ENABLER) ..setXY(pos)..setFacing(facing) return u init realToIndex(1) for i = 0 to DIFFERENT_ANGLES - 1 DummyRecycler.angleQueues[i] = new LinkedList() let facing = angle(i * ANGLE_DEGREE) for j = 0 to SAVED_UNITS_PER_ANGLE - 1 let dummy = createDummy(boundMax - vec2(16, 16), facing) DummyRecycler.angleQueues[i].enqueue(dummy) @compiletime function generateDummyUnit() new AbilityDefinitionRootAncients(ROOT_ENABLER) new AbilityDefinitionPermanentInvisibility(DISABLE_AUTO_ACQUIRE_ATTACK_TARGETS_ABILITY_ID) ..presetAutoAcquireAttackTargets(_ -> false) ..presetDurationNormal(_ -> -1) ..presetDurationHero(_ -> -1) new UnitDefinition(DUMMY_UNIT_ID, UnitIds.wisp) ..setName("Effect Dummy Unit") ..setUpgradesUsed("") ..setStructuresBuilt("") ..setManaRegeneration(0.1) ..setManaInitialAmount(1000) ..setManaMaximum(1000) ..setCollisionSize(0.0) ..setRace(Race.Commoner) ..setFoodCost(0) ..setArmorType(ArmorType.Divine) ..setIconGameInterface(Icons.bTNTemp) ..setSpeedBase(522) ..setModelFile("dummy.mdl") ..setAnimationBlendTimeseconds(0.0) ..setAnimationCastBackswing(0.0) ..setMaximumPitchAngledegrees(0.0) ..setMaximumRollAngledegrees(0.0) ..setArtSpecial("") ..setProjectileImpactZ(0.0) ..setProjectileLaunchZ(0.0) ..setNameEditorSuffix("(Basics)") ..setSightRadiusDay(1) ..setSightRadiusNight(1) ..setUnitClassification("_") ..setPropulsionWindowdegrees(1.0) ..setTooltipBasic("") ..setAttacksEnabled(AttacksEnabled.AttackOneOnly.toObjectInt()) ..setAttack1AnimationBackswingPoint(0) ..setAttack1AnimationDamagePoint(0) ..setAttack1CooldownTime(0) ..setAttack1AttackType(AttackType.Unknown) ..setAttack1DamageBase(-1) ..setAttack1DamageNumberofDice(1) ..setAttack1DamageSidesperDie(1) ..setAttack1ProjectileSpeed(INT_MAX) ..setAttack1Range(INT_MAX) ..setAttack1TargetsAllowed( commaList(TargetsAllowed.air, TargetsAllowed.debris, TargetsAllowed.ground, TargetsAllowed.invulnerable, TargetsAllowed.item_t, TargetsAllowed.structure, TargetsAllowed.vulnerable, TargetsAllowed.ward)) ..setAttack1WeaponSound(WeaponSound.Nothing) ..setAttack1WeaponType(WeaponType.Instant) ..setAcquisitionRange(INT_MAX.toReal()) ..setNormalAbilities( commaList(AbilityIds.invulnerable, AbilityIds.locust, DISABLE_AUTO_ACQUIRE_ATTACK_TARGETS_ABILITY_ID))