├── Images ├── AoeShapes.png └── DllLocation.png ├── Linqpad ├── Examples │ ├── ForcedMovement │ │ ├── AwayWithTheeDemo.linq │ │ ├── KnockbackDemo.linq │ │ └── TerrainDemo.linq │ ├── MechanicRecursion │ │ ├── ExaflareDemo.linq │ │ └── InnocenceAoeDemo.linq │ ├── RotationDemo.linq │ ├── SimpleAoeDemo.linq │ ├── TargetedAoeDemo.linq │ └── TowerDemo.linq └── MechanicSets │ ├── AnnihilationDemo.linq │ ├── BlackfireDemo.linq │ ├── CircleProgramDemo.linq │ ├── CloudOfDarknessDemo.linq │ ├── FellruinDemo.linq │ ├── Grand Octet.linq │ ├── HeavensfallDemo.linq │ ├── LightRampantDemo.linq │ ├── LightRampantDemo2.linq │ ├── LightRampantDemo3.linq │ ├── LimitCutDemo.linq │ ├── Quickmarch.linq │ ├── RunDeltaDemo.linq │ ├── RunSigmaDemo.linq │ ├── SuppressionDemo.linq │ ├── TenstrikeDemo.linq │ ├── UcobAddsDemo.linq │ ├── WormholeDemo.linq │ ├── WrathOfTheHeavensDemo.linq │ └── WyrmholeDemo.linq ├── Mechanics ├── AwayWithTheeDemo.json ├── ExaflareDemo.json ├── InnocenceAoeDemo.json ├── KnockbackDemo.json ├── RotationDemo.json ├── SimpleAoeDemo.json ├── TargetedAoeDemo.json ├── TerrainDemo.json └── TowerDemo.json └── README.md /Images/AoeShapes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiv-stats/xiv-sim-documentation/f93f01c62219755ddd470db3393e15fdda29dd57/Images/AoeShapes.png -------------------------------------------------------------------------------- /Images/DllLocation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiv-stats/xiv-sim-documentation/f93f01c62219755ddd470db3393e15fdda29dd57/Images/DllLocation.png -------------------------------------------------------------------------------- /Linqpad/Examples/ForcedMovement/AwayWithTheeDemo.linq: -------------------------------------------------------------------------------- 1 | 2 | D:\src\Unity\xiv-sim\Library\ScriptAssemblies\Assembly-CSharp.dll 3 | <ProgramFilesX64>\Unity\Hub\Editor\2020.3.6f1\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll 4 | UnityEngine 5 | 6 | 7 | var mechanicName = "AwayWithTheeDemo"; 8 | var baseOutputPath = @"D:\src\Unity\xiv-sim"; 9 | var buildOutputPath = @"D:\src\Unity\xiv-sim-documentation"; 10 | 11 | var mechanicData = new MechanicData(); 12 | 13 | mechanicData.referenceMechanicProperties = new Dictionary 14 | { 15 | { 16 | "DrawIn", 17 | new MechanicProperties 18 | { 19 | visible = true, 20 | collisionShapeParams = new Vector4(0.3f, 360), 21 | colorHtml = "#d800ff99", 22 | mechanic = new ExecuteMultipleEvents 23 | { 24 | events = new List 25 | { 26 | new WaitEvent { timeToWait = 1 }, 27 | new ApplyEffectToTargetOnly { 28 | effects = new List 29 | { 30 | new KnockbackEffect { knockbackDistance = 1, isDrawIn = true, additionalKnockbackSpeed = 5 }, 31 | } 32 | }, 33 | } 34 | } 35 | } 36 | }, 37 | { 38 | "DrawInLeft", 39 | new MechanicProperties 40 | { 41 | visible = false, 42 | mechanic = new ExecuteMultipleEvents 43 | { 44 | events = new List 45 | { 46 | new ApplyEffectToTargetOnly { effect = new ApplyStatusEffect { referenceStatusName = "Stun" } }, 47 | new SpawnTargetedEvents { referenceMechanicName = "DrawIn", isPositionRelative = true, isRotationRelative = true, spawnOnTarget = true, position = new Vector2(-3, 0), targetingScheme = new TargetExistingTarget() } 48 | } 49 | }, 50 | } 51 | }, 52 | { 53 | "LeftWithThee", 54 | new MechanicProperties 55 | { 56 | visible = false, 57 | mechanic = new ExecuteMultipleEvents 58 | { 59 | events = new List { 60 | new ApplyEffectToTargetOnly { effect = new ApplyStatusEffect { referenceStatusName = "LeftWithThee" } }, 61 | new SpawnVisualObject 62 | { 63 | textureFilePath = "Mechanics/Resources/Mark1.png", 64 | colorHtml = "#d800ff", 65 | visualDuration = 5, 66 | spawnOnPlayer = true, 67 | relativePosition = new Vector3(-3, 0.6f, 0), 68 | scale = new Vector3(0.8f, 0.8f, 1), 69 | isBillboard = true 70 | }, 71 | new SpawnVisualObject 72 | { 73 | textureFilePath = "Mechanics/Resources/LimitCut-1.png", 74 | colorHtml = "#d800ff99", 75 | visualDuration = 5, 76 | spawnOnPlayer = true, 77 | relativePosition = new Vector3(-3, 0.1f, 0), 78 | eulerAngles = new Vector3(90, 0, 0), 79 | }, 80 | } 81 | } 82 | } 83 | } 84 | }; 85 | 86 | 87 | mechanicData.referenceStatusProperties = new Dictionary 88 | { 89 | { 90 | "LeftWithThee", 91 | new SpawnMechanicOnExpire 92 | { 93 | statusIconPath = "Mechanics/Resources/LeftWithThee.png", 94 | statusName = "Larboard With Thee", 95 | statusDescription = "When this effect ends, you will be spawned and forcibly moved leftwards.", 96 | duration = 5, 97 | referenceMechanicName = "DrawInLeft" 98 | } 99 | }, 100 | { 101 | "Stun", 102 | new StatusEffectData 103 | { 104 | statusIconPath = "Mechanics/Resources/Stun.png", 105 | statusName = "Stun", 106 | statusDescription = "Unable to execute actions.", 107 | duration = 3f, 108 | disableType = DisableType.Movement | DisableType.Actions 109 | } 110 | }, 111 | }; 112 | 113 | mechanicData.mechanicEvents = new List 114 | { 115 | new SpawnVisualObject 116 | { 117 | textureFilePath = "Mechanics/Resources/ArenaSquare4x4.png", 118 | visualDuration = float.PositiveInfinity, 119 | relativePosition = new Vector3(0, -0.001f, 0), 120 | eulerAngles = new Vector3(90, 0, 0), 121 | scale = new Vector3(15.8637f, 15.8637f, 1), 122 | }, 123 | new SpawnTargetedEvents { referenceMechanicName = "LeftWithThee", targetingScheme = new TargetAllPlayers() }, 124 | }; 125 | 126 | var resultText = mechanicData.ToString(); 127 | 128 | File.WriteAllText($@"{baseOutputPath}\Mechanics\{mechanicName}.json", resultText); 129 | File.WriteAllText($@"{baseOutputPath}\Build\Mechanics\{mechanicName}.json", resultText); 130 | File.WriteAllText($@"{buildOutputPath}\Mechanics\{mechanicName}.json", resultText); 131 | 132 | $"Finished writing json to Mechanics/{mechanicName}.json".Dump(); -------------------------------------------------------------------------------- /Linqpad/Examples/ForcedMovement/KnockbackDemo.linq: -------------------------------------------------------------------------------- 1 | 2 | D:\src\Unity\xiv-sim\Library\ScriptAssemblies\Assembly-CSharp.dll 3 | <ProgramFilesX64>\Unity\Hub\Editor\2020.3.6f1\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll 4 | UnityEngine 5 | 6 | 7 | var mechanicName = "KnockbackDemo"; 8 | var baseOutputPath = @"D:\src\Unity\xiv-sim"; 9 | var buildOutputPath = @"D:\src\Unity\xiv-sim-documentation"; 10 | 11 | var mechanicData = new MechanicData(); 12 | 13 | mechanicData.referenceMechanicProperties = new Dictionary 14 | { 15 | { 16 | "Knockback", 17 | new MechanicProperties 18 | { 19 | collisionShape = CollisionShape.Round, 20 | collisionShapeParams = new Vector4(3, 360), 21 | colorHtml = "#ff9600", 22 | mechanic = new ExecuteMultipleEvents 23 | { 24 | events = new List 25 | { 26 | new WaitEvent { timeToWait = 3 }, 27 | new ApplyEffectToPlayers { 28 | effects = new List 29 | { 30 | new DamageEffect { damageAmount = 10000, damageType = "Damage", name = "Knockback" }, 31 | new KnockbackEffect { knockbackDistance = 3, canArmsLength = true }, 32 | } 33 | } 34 | } 35 | } 36 | } 37 | }, 38 | { 39 | "DrawIn", 40 | new MechanicProperties 41 | { 42 | collisionShape = CollisionShape.Round, 43 | collisionShapeParams = new Vector4(3, 360), 44 | colorHtml = "#0078ff", 45 | mechanic = new ExecuteMultipleEvents 46 | { 47 | events = new List 48 | { 49 | new WaitEvent { timeToWait = 3 }, 50 | new ApplyEffectToPlayers { 51 | effects = new List 52 | { 53 | new DamageEffect { damageAmount = 10000, damageType = "Damage", name = "Draw In" }, 54 | new KnockbackEffect { knockbackDistance = 1, isDrawIn = true, additionalKnockbackSpeed = 5 }, 55 | } 56 | } 57 | } 58 | } 59 | } 60 | }, 61 | }; 62 | 63 | mechanicData.mechanicEvents = new List 64 | { 65 | new SpawnMechanicEvent { referenceMechanicName = "Knockback", position = new Vector2(-2, 0) }, 66 | new SpawnMechanicEvent { referenceMechanicName = "DrawIn", position = new Vector2(2, 0) } 67 | }; 68 | 69 | var resultText = mechanicData.ToString(); 70 | 71 | File.WriteAllText($@"{baseOutputPath}\Mechanics\{mechanicName}.json", resultText); 72 | File.WriteAllText($@"{baseOutputPath}\Build\Mechanics\{mechanicName}.json", resultText); 73 | File.WriteAllText($@"{buildOutputPath}\Mechanics\{mechanicName}.json", resultText); 74 | 75 | $"Finished writing json to Mechanics/{mechanicName}.json".Dump(); -------------------------------------------------------------------------------- /Linqpad/Examples/ForcedMovement/TerrainDemo.linq: -------------------------------------------------------------------------------- 1 | 2 | D:\src\Unity\xiv-sim\Library\ScriptAssemblies\Assembly-CSharp.dll 3 | <ProgramFilesX64>\Unity\Hub\Editor\2020.3.6f1\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll 4 | UnityEngine 5 | 6 | 7 | var mechanicName = "TerrainDemo"; 8 | var baseOutputPath = @"D:\src\Unity\xiv-sim"; 9 | var buildOutputPath = @"D:\src\Unity\xiv-sim-documentation"; 10 | 11 | var mechanicData = new MechanicData(); 12 | 13 | mechanicData.referenceMechanicProperties = new Dictionary 14 | { 15 | { 16 | "Knockback", 17 | new MechanicProperties 18 | { 19 | collisionShape = CollisionShape.Round, 20 | collisionShapeParams = new Vector4(3, 360), 21 | colorHtml = "#ff9600", 22 | mechanic = new ExecuteMultipleEvents 23 | { 24 | events = new List 25 | { 26 | new WaitEvent { timeToWait = 3 }, 27 | new ApplyEffectToPlayers { 28 | effects = new List 29 | { 30 | new DamageEffect { damageAmount = 10000, damageType = "Damage", name = "Knockback" }, 31 | new KnockbackEffect { knockbackDistance = 20 }, 32 | } 33 | } 34 | } 35 | } 36 | } 37 | }, 38 | { 39 | "Wall", 40 | new MechanicProperties 41 | { 42 | collisionShape = CollisionShape.Rectangle, 43 | collisionShapeParams = new Vector4(10, 3), 44 | colorHtml = "#0078ff", 45 | mechanic = new WaitEvent { timeToWait = float.PositiveInfinity }, 46 | isTerrain = true 47 | } 48 | }, 49 | }; 50 | 51 | mechanicData.mechanicEvents = new List 52 | { 53 | new SpawnMechanicEvent { referenceMechanicName = "Knockback", position = new Vector2(-2, 0) }, 54 | new SpawnMechanicEvent { referenceMechanicName = "Wall", position = new Vector2(4, -5) }, 55 | }; 56 | 57 | var resultText = mechanicData.ToString(); 58 | 59 | File.WriteAllText($@"{baseOutputPath}\Mechanics\{mechanicName}.json", resultText); 60 | File.WriteAllText($@"{baseOutputPath}\Build\Mechanics\{mechanicName}.json", resultText); 61 | File.WriteAllText($@"{buildOutputPath}\Mechanics\{mechanicName}.json", resultText); 62 | 63 | $"Finished writing json to Mechanics/{mechanicName}.json".Dump(); -------------------------------------------------------------------------------- /Linqpad/Examples/MechanicRecursion/ExaflareDemo.linq: -------------------------------------------------------------------------------- 1 | 2 | D:\src\Unity\xiv-sim\Library\ScriptAssemblies\Assembly-CSharp.dll 3 | <ProgramFilesX64>\Unity\Hub\Editor\2020.3.6f1\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll 4 | UnityEngine 5 | 6 | 7 | var mechanicName = "ExaflareDemo"; 8 | var baseOutputPath = @"D:\src\Unity\xiv-sim"; 9 | var buildOutputPath = @"D:\src\Unity\xiv-sim-documentation"; 10 | 11 | var mechanicData = new MechanicData(); 12 | 13 | mechanicData.referenceMechanicProperties = new Dictionary 14 | { 15 | { 16 | "Exaflare", 17 | new MechanicProperties 18 | { 19 | collisionShape = CollisionShape.Round, 20 | collisionShapeParams = new Vector4(1, 360), 21 | colorHtml = "#ff9600", 22 | mechanic = new ExecuteMultipleEvents 23 | { 24 | events = new List 25 | { 26 | new WaitEvent { timeToWait = 2 }, 27 | new CheckMechanicDepth { 28 | expressionFormat = "{0} < 5", 29 | successEvent = new SpawnMechanicEvent { referenceMechanicName = "Exaflare", isPositionRelative = true, isRotationRelative = true, position = new Vector2(0, 1.5f) } 30 | }, 31 | new WaitEvent { timeToWait = 1 }, 32 | new ApplyEffectToPlayers { 33 | effect = new DamageEffect { damageAmount = 90000, damageType = "Damage", name = "Exaflare" } 34 | } 35 | } 36 | } 37 | } 38 | }, 39 | }; 40 | 41 | mechanicData.mechanicEvents = new List 42 | { 43 | new SpawnMechanicEvent { referenceMechanicName = "Exaflare", position = new Vector3(0, 3) }, 44 | new SpawnMechanicEvent { referenceMechanicName = "Exaflare", position = new Vector3(3, 0), rotation = 90 }, 45 | new SpawnMechanicEvent { referenceMechanicName = "Exaflare", position = new Vector3(0, -3), rotation = 180 }, 46 | new SpawnMechanicEvent { referenceMechanicName = "Exaflare", position = new Vector3(-3, 0), rotation = 270 }, 47 | }; 48 | 49 | var resultText = mechanicData.ToString(); 50 | 51 | File.WriteAllText($@"{baseOutputPath}\Mechanics\{mechanicName}.json", resultText); 52 | File.WriteAllText($@"{baseOutputPath}\Build\Mechanics\{mechanicName}.json", resultText); 53 | File.WriteAllText($@"{buildOutputPath}\Mechanics\{mechanicName}.json", resultText); 54 | 55 | $"Finished writing json to Mechanics/{mechanicName}.json".Dump(); -------------------------------------------------------------------------------- /Linqpad/Examples/MechanicRecursion/InnocenceAoeDemo.linq: -------------------------------------------------------------------------------- 1 | 2 | D:\src\Unity\xiv-sim\Library\ScriptAssemblies\Assembly-CSharp.dll 3 | <ProgramFilesX64>\Unity\Hub\Editor\2020.3.6f1\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll 4 | UnityEngine 5 | 6 | 7 | var mechanicName = "InnocenceAoeDemo"; 8 | var baseOutputPath = @"D:\src\Unity\xiv-sim"; 9 | var buildOutputPath = @"D:\src\Unity\xiv-sim-documentation"; 10 | 11 | var mechanicData = new MechanicData(); 12 | 13 | mechanicData.referenceMechanicProperties = new Dictionary 14 | { 15 | { 16 | "Donut Cone", 17 | new MechanicProperties 18 | { 19 | collisionShape = CollisionShape.Round, 20 | collisionShapeParams = new Vector4(5, 120, 3), 21 | colorHtml = "#ff9600", 22 | mechanic = new ExecuteMultipleEvents 23 | { 24 | events = new List 25 | { 26 | new WaitEvent { timeToWait = 3 }, 27 | new ApplyEffectToPlayers { 28 | effect = new DamageEffect { damageAmount = 90000, damageType = "Damage", name = "Innocence Aoe" } 29 | } 30 | } 31 | } 32 | } 33 | }, 34 | { 35 | "Donut Cone Offset", 36 | new MechanicProperties 37 | { 38 | visible = false, 39 | mechanic = new ExecuteMultipleEvents 40 | { 41 | events = new List 42 | { 43 | new SpawnMechanicEvent 44 | { 45 | referenceMechanicName = "Donut Cone", 46 | isPositionRelative = true, 47 | isRotationRelative = true, 48 | position = new Vector3(4, 0), 49 | rotation = -30 50 | }, 51 | new WaitEvent { timeToWait = 2 }, 52 | new SpawnMechanicEvent { referenceMechanicName = "Donut Cone Offset", isPositionRelative = true, isRotationRelative = true, rotation = -25 } 53 | } 54 | } 55 | } 56 | } 57 | }; 58 | 59 | mechanicData.mechanicEvents = new List 60 | { 61 | new SpawnMechanicEvent { referenceMechanicName = "Donut Cone Offset", position = new Vector2(0, 0) }, 62 | new SpawnMechanicEvent { referenceMechanicName = "Donut Cone Offset", position = new Vector2(0, 0), rotation = 180 }, 63 | }; 64 | 65 | var resultText = mechanicData.ToString(); 66 | 67 | File.WriteAllText($@"{baseOutputPath}\Mechanics\{mechanicName}.json", resultText); 68 | File.WriteAllText($@"{baseOutputPath}\Build\Mechanics\{mechanicName}.json", resultText); 69 | File.WriteAllText($@"{buildOutputPath}\Mechanics\{mechanicName}.json", resultText); 70 | 71 | $"Finished writing json to Mechanics/{mechanicName}.json".Dump(); -------------------------------------------------------------------------------- /Linqpad/Examples/RotationDemo.linq: -------------------------------------------------------------------------------- 1 | 2 | D:\src\Unity\xiv-sim\Library\ScriptAssemblies\Assembly-CSharp.dll 3 | <ProgramFilesX64>\Unity\Hub\Editor\2020.3.6f1\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll 4 | UnityEngine 5 | 6 | 7 | var mechanicName = "RotationDemo"; 8 | var baseOutputPath = @"D:\src\Unity\xiv-sim"; 9 | var buildOutputPath = @"D:\src\Unity\xiv-sim-documentation"; 10 | 11 | 12 | var planetVisual = new SpawnVisualObject 13 | { 14 | textureFilePath = "Mechanics/Resources/Cat.png", 15 | visualDuration = 6, 16 | colorHtml = "#b429bd", 17 | isBillboard = true, 18 | relativePosition = new Vector3(0, 1.5f, 0), 19 | scale = new Vector3(2, 2, 2), 20 | }; 21 | 22 | var platformRotateVisuals = new List(); 23 | 24 | for (int i = 0; i < 50; i++) 25 | { 26 | var angle = 360f/ 50 * i; 27 | var rads = angle * Mathf.Deg2Rad; 28 | 29 | platformRotateVisuals.Add(new SpawnVisualObject 30 | { 31 | textureFilePath = "Mechanics/Resources/Arrow.png", 32 | visualDuration = 5, 33 | colorHtml = "#2579bd", 34 | relativePosition = new Vector3(Mathf.Cos(rads), 0, Mathf.Sin(rads)) * 8 + Vector3.up, 35 | eulerAngles = new Vector3(0, 90 - angle , 0), 36 | scale = new Vector3(1, 1, 1), 37 | }); 38 | } 39 | 40 | var mechanicData = new MechanicData(); 41 | mechanicData.referenceMechanicProperties = new Dictionary 42 | { 43 | { 44 | "ArenaBoundary", 45 | new MechanicProperties 46 | { 47 | collisionShape = CollisionShape.Round, 48 | collisionShapeParams = new Vector4(25, 360, 7), 49 | colorHtml = "#8800FF", 50 | persistentTickInterval = 0.2f, 51 | persistentMechanic = new ApplyEffectToPlayers { effect = new DamageEffect { damageAmount = 9999999, damageType = "TrueDamage" } }, 52 | } 53 | }, 54 | { 55 | "Explosion", 56 | new MechanicProperties 57 | { 58 | collisionShape = CollisionShape.Round, 59 | collisionShapeParams = new Vector4(12, 360), 60 | colorHtml = "#ff9600", 61 | mechanic = new ExecuteMultipleEvents 62 | { 63 | events = new List 64 | { 65 | new WaitEvent { timeToWait = 0.5f }, 66 | new ApplyEffectToPlayers { 67 | effect = new DamageEffect { damageAmount = 30000, damageType = "Damage", name = "CAT-Astrophe" } 68 | } 69 | } 70 | } 71 | } 72 | }, 73 | { 74 | "SnakeAOE", 75 | new MechanicProperties 76 | { 77 | collisionShape = CollisionShape.Rectangle, 78 | collisionShapeParams = new Vector4(14, 3.5f), 79 | colorHtml = "#ff9600", 80 | mechanic = new ExecuteMultipleEvents 81 | { 82 | events = new List 83 | { 84 | new WaitEvent { timeToWait = 1 }, 85 | new ApplyEffectToPlayers { 86 | effect = new DamageEffect { damageAmount = 30000, damageType = "Damage", name = "Snake" } 87 | } 88 | } 89 | } 90 | } 91 | }, 92 | { 93 | "SpawnPlanets", 94 | new MechanicProperties 95 | { 96 | visible = false, 97 | mechanic = new ExecuteMultipleEvents 98 | { 99 | events = new List 100 | { 101 | new SpawnEnemy { 102 | enemyName = "Doomed Stars", 103 | textureFilePath = "Mechanics/Resources/Cat.png", 104 | maxHp = 35000000, 105 | hitboxSize = 1, 106 | referenceMechanicName = "SlowPlanet", 107 | visualScale = Vector3.zero, 108 | isTargetable = false, 109 | showInEnemyList = false, 110 | }, 111 | new SpawnEnemy { 112 | enemyName = "Doomed Stars", 113 | textureFilePath = "Mechanics/Resources/Cat.png", 114 | maxHp = 35000000, 115 | hitboxSize = 1, 116 | referenceMechanicName = "FastPlanet", 117 | visualScale = Vector3.zero, 118 | isTargetable = false, 119 | showInEnemyList = false, 120 | }, 121 | new WaitEvent { timeToWait = 5.5f }, 122 | new SpawnMechanicEvent { referenceMechanicName = "Explosion", position = new Vector2(7, 0) }, 123 | } 124 | } 125 | } 126 | }, 127 | { 128 | "SpawnSnakes", 129 | new MechanicProperties 130 | { 131 | visible = false, 132 | mechanic = new ExecuteMultipleEvents 133 | { 134 | events = new List 135 | { 136 | new SpawnEnemy { 137 | enemyName = "Snake", 138 | textureFilePath = "Mechanics/Resources/Snake.png", 139 | maxHp = 35000000, 140 | hitboxSize = 1, 141 | referenceMechanicName = "Snake", 142 | visualScale = Vector3.zero, 143 | isTargetable = true, 144 | showInEnemyList = false, 145 | position = new Vector2(0f, 0.01f), 146 | rotation = 90 147 | } 148 | } 149 | } 150 | } 151 | }, 152 | { 153 | "Snake", 154 | new MechanicProperties 155 | { 156 | visible = false, 157 | mechanic = new ExecuteMultipleEvents 158 | { 159 | events = new List 160 | { 161 | new SpawnVisualObject 162 | { 163 | textureFilePath = "Mechanics/Resources/Snake.png", 164 | visualDuration = 7.5f, 165 | colorHtml = "#2529bd", 166 | relativePosition = new Vector3(5.25f, 1, -1.75f), 167 | eulerAngles = new Vector3(0, 180, 0), 168 | isRotationRelative = true, 169 | scale = new Vector3(2, 2, 2), 170 | }, 171 | new SpawnVisualObject 172 | { 173 | textureFilePath = "Mechanics/Resources/Snake.png", 174 | visualDuration = 7.5f, 175 | colorHtml = "#2529bd", 176 | relativePosition = new Vector3(5.25f, 1, 5.25f), 177 | eulerAngles = new Vector3(0, 180, 0), 178 | isRotationRelative = true, 179 | scale = new Vector3(2, 2, 2), 180 | }, 181 | new WaitEvent { timeToWait = 4 }, 182 | new SetEnemyMovementPath { path = new CircleMovementPath { radius = 0.01f, degreesPerSecond = -30, startAngle = 90} }, 183 | new WaitEvent { timeToWait = 3.05f }, 184 | new SpawnMechanicEvent { referenceMechanicName = "SnakeAOE", position = new Vector2(7, -1.75f), rotation = -90, isPositionRelative = true, isRotationRelative = true }, 185 | new SpawnMechanicEvent { referenceMechanicName = "SnakeAOE", position = new Vector2(7, 5.25f), rotation = -90, isPositionRelative = true, isRotationRelative = true }, 186 | } 187 | } 188 | } 189 | }, 190 | { 191 | "SlowPlanet", 192 | new MechanicProperties 193 | { 194 | visible = false, 195 | mechanic = new ExecuteMultipleEvents 196 | { 197 | events = new List 198 | { 199 | new SetEnemyMovementPath { path = new CircleMovementPath { radius = 7.5f, degreesPerSecond = 0, startAngle = -90} }, 200 | planetVisual, 201 | new WaitEvent { timeToWait = 1 }, 202 | new SetEnemyMovementPath { path = new CircleMovementPath { radius = 7.5f, degreesPerSecond = 18, startAngle = -90} }, 203 | new WaitEvent { timeToWait = 5 }, 204 | } 205 | } 206 | } 207 | }, 208 | { 209 | "FastPlanet", 210 | new MechanicProperties 211 | { 212 | visible = false, 213 | mechanic = new ExecuteMultipleEvents 214 | { 215 | events = new List 216 | { 217 | new SetEnemyMovementPath { path = new CircleMovementPath { radius = 7.5f, degreesPerSecond = 0, startAngle = 180} }, 218 | planetVisual, 219 | new WaitEvent { timeToWait = 1 }, 220 | new SetEnemyMovementPath { path = new CircleMovementPath { radius = 7.5f, degreesPerSecond = 36, startAngle = 180} }, 221 | new WaitEvent { timeToWait = 5 }, 222 | } 223 | } 224 | } 225 | }, 226 | { 227 | "StunPlayers", 228 | new MechanicProperties 229 | { 230 | visible = false, 231 | mechanic = new ApplyEffectToTargetOnly { effect = new ApplyStatusEffect { referenceStatusName = "Stun" } } 232 | } 233 | } 234 | }; 235 | 236 | mechanicData.referenceStatusProperties = new Dictionary 237 | { 238 | { 239 | "Stun", 240 | new StatusEffectData 241 | { 242 | statusIconPath = "Mechanics/Resources/Stun.png", 243 | statusName = "Bind", 244 | statusDescription = "Unable to move.", 245 | duration = 5f, 246 | disableType = DisableType.Movement 247 | } 248 | }, 249 | }; 250 | 251 | mechanicData.mechanicEvents = new List 252 | { 253 | new SpawnMechanicEvent { referenceMechanicName = "ArenaBoundary" }, 254 | new SpawnVisualObject 255 | { 256 | textureFilePath = "Mechanics/Resources/ArenaSquare4x4.png", 257 | visualDuration = float.PositiveInfinity, 258 | relativePosition = new Vector3(0, -0.001f, 0), 259 | eulerAngles = new Vector3(90, 0, 0), 260 | scale = new Vector3(18f, 18, 1), 261 | }, 262 | new ExecuteMultipleEvents 263 | { 264 | events = new List 265 | { 266 | new SpawnMechanicEvent { referenceMechanicName = "SpawnPlanets" }, 267 | new SpawnMechanicEvent { referenceMechanicName = "SpawnSnakes" }, 268 | 269 | new WaitEvent { timeToWait = 2 }, 270 | new ExecuteMultipleEventsParallel { events = platformRotateVisuals }, 271 | 272 | new WaitEvent { timeToWait = 2 }, 273 | new SpawnTargetedEvents { referenceMechanicName = "StunPlayers", targetingScheme = new TargetAllPlayers() }, 274 | } 275 | } 276 | }; 277 | 278 | var resultText = mechanicData.ToString(); 279 | 280 | File.WriteAllText($@"{baseOutputPath}\Mechanics\{mechanicName}.json", resultText); 281 | File.WriteAllText($@"{baseOutputPath}\Build\Mechanics\{mechanicName}.json", resultText); 282 | File.WriteAllText($@"{buildOutputPath}\Mechanics\{mechanicName}.json", resultText); 283 | 284 | $"Finished writing json to Mechanics/{mechanicName}.json".Dump(); -------------------------------------------------------------------------------- /Linqpad/Examples/SimpleAoeDemo.linq: -------------------------------------------------------------------------------- 1 | 2 | D:\src\Unity\xiv-sim\Library\ScriptAssemblies\Assembly-CSharp.dll 3 | <ProgramFilesX64>\Unity\Hub\Editor\2020.3.6f1\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll 4 | UnityEngine 5 | 6 | 7 | var mechanicName = "SimpleAoeDemo"; 8 | var baseOutputPath = @"D:\src\Unity\xiv-sim"; 9 | var buildOutputPath = @"D:\src\Unity\xiv-sim-documentation"; 10 | 11 | var mechanicData = new MechanicData(); 12 | 13 | mechanicData.referenceMechanicProperties = new Dictionary 14 | { 15 | { 16 | "Circle", 17 | new MechanicProperties 18 | { 19 | collisionShape = CollisionShape.Round, 20 | collisionShapeParams = new Vector4(1, 360), 21 | colorHtml = "#ff9600", 22 | mechanic = new ExecuteMultipleEvents 23 | { 24 | events = new List 25 | { 26 | new WaitEvent { timeToWait = 3 }, 27 | new ApplyEffectToPlayers { 28 | effect = new DamageEffect { damageAmount = 90000, damageType = "Damage", name = "Circle Aoe" } 29 | } 30 | } 31 | } 32 | } 33 | }, 34 | { 35 | "Cone", 36 | new MechanicProperties 37 | { 38 | collisionShape = CollisionShape.Round, 39 | collisionShapeParams = new Vector4(1, 120), 40 | colorHtml = "#ff9600", 41 | mechanic = new ExecuteMultipleEvents 42 | { 43 | events = new List 44 | { 45 | new WaitEvent { timeToWait = 3 }, 46 | new ApplyEffectToPlayers { 47 | effect = new DamageEffect { damageAmount = 90000, damageType = "Damage", name = "Cone Aoe" } 48 | } 49 | } 50 | } 51 | } 52 | }, 53 | { 54 | "Donut", 55 | new MechanicProperties 56 | { 57 | collisionShape = CollisionShape.Round, 58 | collisionShapeParams = new Vector4(2, 360, 1), 59 | colorHtml = "#ff9600", 60 | mechanic = new ExecuteMultipleEvents 61 | { 62 | events = new List 63 | { 64 | new WaitEvent { timeToWait = 3 }, 65 | new ApplyEffectToPlayers { 66 | effect = new DamageEffect { damageAmount = 90000, damageType = "Damage", name = "Donut Aoe" } 67 | } 68 | } 69 | } 70 | } 71 | }, 72 | { 73 | "Donut Cone", 74 | new MechanicProperties 75 | { 76 | collisionShape = CollisionShape.Round, 77 | collisionShapeParams = new Vector4(2, 120, 1), 78 | colorHtml = "#ff9600", 79 | mechanic = new ExecuteMultipleEvents 80 | { 81 | events = new List 82 | { 83 | new WaitEvent { timeToWait = 3 }, 84 | new ApplyEffectToPlayers { 85 | effect = new DamageEffect { damageAmount = 90000, damageType = "Damage", name = "Donut Cone Aoe" } 86 | } 87 | } 88 | } 89 | } 90 | }, 91 | { 92 | "Rectangle", 93 | new MechanicProperties 94 | { 95 | collisionShape = CollisionShape.Rectangle, 96 | collisionShapeParams = new Vector4(10, 1), 97 | colorHtml = "#ff9600", 98 | mechanic = new ExecuteMultipleEvents 99 | { 100 | events = new List 101 | { 102 | new WaitEvent { timeToWait = 3 }, 103 | new ApplyEffectToPlayers { 104 | effect = new DamageEffect { damageAmount = 90000, damageType = "Damage", name = "Rectangle Aoe" } 105 | } 106 | } 107 | } 108 | } 109 | }, 110 | }; 111 | 112 | mechanicData.mechanicEvents = new List 113 | { 114 | new SpawnMechanicEvent { referenceMechanicName = "Circle" }, 115 | new SpawnMechanicEvent { referenceMechanicName = "Cone", position = new Vector2(2, 0) }, 116 | new SpawnMechanicEvent { referenceMechanicName = "Donut", position = new Vector2(6, 0) }, 117 | new SpawnMechanicEvent { referenceMechanicName = "Donut Cone", position = new Vector2(10, 0) }, 118 | new SpawnMechanicEvent { referenceMechanicName = "Rectangle", position = new Vector2(0, 4), rotation = 90 }, 119 | }; 120 | 121 | var resultText = mechanicData.ToString(); 122 | 123 | File.WriteAllText($@"{baseOutputPath}\Mechanics\{mechanicName}.json", resultText); 124 | File.WriteAllText($@"{baseOutputPath}\Build\Mechanics\{mechanicName}.json", resultText); 125 | File.WriteAllText($@"{buildOutputPath}\Mechanics\{mechanicName}.json", resultText); 126 | 127 | $"Finished writing json to Mechanics/{mechanicName}.json".Dump(); -------------------------------------------------------------------------------- /Linqpad/Examples/TargetedAoeDemo.linq: -------------------------------------------------------------------------------- 1 | 2 | D:\src\Unity\xiv-sim\Library\ScriptAssemblies\Assembly-CSharp.dll 3 | <ProgramFilesX64>\Unity\Hub\Editor\2020.3.6f1\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll 4 | UnityEngine 5 | 6 | 7 | var mechanicName = "TargetedAoeDemo"; 8 | var baseOutputPath = @"D:\src\Unity\xiv-sim"; 9 | var buildOutputPath = @"D:\src\Unity\xiv-sim-documentation"; 10 | 11 | var mechanicData = new MechanicData(); 12 | 13 | mechanicData.referenceMechanicProperties = new Dictionary 14 | { 15 | { 16 | "TargetedCircle", 17 | new MechanicProperties 18 | { 19 | collisionShape = CollisionShape.Round, 20 | collisionShapeParams = new Vector4(1, 360), 21 | colorHtml = "#ff9600", 22 | isTargeted = true, 23 | followSpeed = 10000, 24 | mechanic = new ExecuteMultipleEvents 25 | { 26 | events = new List 27 | { 28 | new WaitEvent { timeToWait = 15 }, 29 | new ApplyEffectToPlayers { 30 | effect = new DamageEffect { damageAmount = 10000, damageType = "Damage", name = "Circle Aoe" } 31 | }, 32 | } 33 | }, 34 | } 35 | }, 36 | { 37 | "AimedRectangle", 38 | new MechanicProperties 39 | { 40 | collisionShape = CollisionShape.Rectangle, 41 | collisionShapeParams = new Vector4(50, 1), 42 | colorHtml = "#0196ff", 43 | isTargeted = true, 44 | mechanic = new ExecuteMultipleEvents 45 | { 46 | events = new List 47 | { 48 | new WaitEvent { timeToWait = 15 }, 49 | new ApplyEffectToPlayers { 50 | effect = new DamageEffect { damageAmount = 10000, damageType = "Damage", name = "Rectangle Aoe" } 51 | }, 52 | } 53 | }, 54 | } 55 | }, 56 | }; 57 | 58 | mechanicData.mechanicEvents = new List 59 | { 60 | new SpawnTargetedEvents { referenceMechanicName = "TargetedCircle", targetingScheme = new TargetAllPlayers() }, 61 | new SpawnTargetedEvents { referenceMechanicName = "AimedRectangle", targetingScheme = new TargetAllPlayers() } 62 | }; 63 | 64 | var resultText = mechanicData.ToString(); 65 | 66 | File.WriteAllText($@"{baseOutputPath}\Mechanics\{mechanicName}.json", resultText); 67 | File.WriteAllText($@"{baseOutputPath}\Build\Mechanics\{mechanicName}.json", resultText); 68 | File.WriteAllText($@"{buildOutputPath}\Mechanics\{mechanicName}.json", resultText); 69 | 70 | $"Finished writing json to Mechanics/{mechanicName}.json".Dump(); -------------------------------------------------------------------------------- /Linqpad/Examples/TowerDemo.linq: -------------------------------------------------------------------------------- 1 | 2 | D:\src\Unity\xiv-sim\Library\ScriptAssemblies\Assembly-CSharp.dll 3 | <ProgramFilesX64>\Unity\Hub\Editor\2020.3.6f1\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll 4 | UnityEngine 5 | 6 | 7 | var mechanicName = "TowerDemo"; 8 | var baseOutputPath = @"D:\src\Unity\xiv-sim"; 9 | var buildOutputPath = @"D:\src\Unity\xiv-sim-documentation"; 10 | 11 | var mechanicData = new MechanicData(); 12 | 13 | mechanicData.referenceMechanicProperties = new Dictionary 14 | { 15 | { 16 | "Aoe-Green", 17 | new MechanicProperties 18 | { 19 | colorHtml = "#00ff00", 20 | } 21 | }, 22 | { 23 | "Tower", 24 | new MechanicProperties 25 | { 26 | collisionShape = CollisionShape.Round, 27 | collisionShapeParams = new Vector4(1, 360), 28 | colorHtml = "#ff9600", 29 | mechanic = new ExecuteMultipleEvents 30 | { 31 | events = new List 32 | { 33 | new WaitEvent { timeToWait = 5 }, 34 | new ApplyEffectToPlayers { 35 | effect = new DamageEffect { damageAmount = 10000, damageType = "Damage", name = "Tower" } 36 | }, 37 | new CheckNumberOfPlayers { 38 | expressionFormat = "{0} = 1", 39 | failEvent = new SpawnMechanicEvent { referenceMechanicName = "TowerFailed", isPositionRelative = true } 40 | }, 41 | } 42 | }, 43 | persistentTickInterval = 0.1f, 44 | persistentMechanic = new CheckNumberOfPlayers { 45 | expressionFormat = "{0} = 1", 46 | successEvent = new ModifyMechanicEvent { referenceMechanicName = "Aoe-Green" }, 47 | failEvent = new ModifyMechanicEvent { referenceMechanicName = "Tower" } 48 | }, 49 | } 50 | }, 51 | { 52 | "TowerFailed", 53 | new MechanicProperties 54 | { 55 | collisionShape = CollisionShape.Round, 56 | collisionShapeParams = new Vector4(3, 360), 57 | colorHtml = "#ff0000", 58 | mechanic = new ExecuteMultipleEvents 59 | { 60 | events = new List 61 | { 62 | new WaitEvent { timeToWait = 0.2f }, 63 | new ApplyEffectToPlayers { 64 | effect = new DamageEffect { damageAmount = 9999999, damageType = "TrueDamage", name = "TowerFailed" } 65 | } 66 | } 67 | } 68 | } 69 | } 70 | }; 71 | 72 | mechanicData.mechanicEvents = new List 73 | { 74 | new SpawnMechanicEvent { referenceMechanicName = "Tower" }, 75 | }; 76 | 77 | var resultText = mechanicData.ToString(); 78 | 79 | File.WriteAllText($@"{baseOutputPath}\Mechanics\{mechanicName}.json", resultText); 80 | File.WriteAllText($@"{baseOutputPath}\Build\Mechanics\{mechanicName}.json", resultText); 81 | File.WriteAllText($@"{buildOutputPath}\Mechanics\{mechanicName}.json", resultText); 82 | 83 | $"Finished writing json to Mechanics/{mechanicName}.json".Dump(); -------------------------------------------------------------------------------- /Linqpad/MechanicSets/BlackfireDemo.linq: -------------------------------------------------------------------------------- 1 | 2 | D:\src\Unity\xiv-sim\Library\ScriptAssemblies\Assembly-CSharp.dll 3 | <ProgramFilesX64>\Unity\Hub\Editor\2020.3.6f1\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll 4 | UnityEngine 5 | 6 | 7 | var mechanicName = "BlackfireDemo"; 8 | var baseOutputPath = @"D:\src\Unity\xiv-sim"; 9 | var buildOutputPath = @"D:\src\Unity\xiv-sim-mechanics"; 10 | 11 | var mechanicData = new MechanicData(); 12 | 13 | mechanicData.referenceMechanicProperties = new Dictionary 14 | { 15 | { 16 | "SnapshotDive", 17 | new MechanicProperties 18 | { 19 | isTargeted = false, 20 | } 21 | }, 22 | { 23 | "SetVisible", 24 | new MechanicProperties 25 | { 26 | visible = true 27 | } 28 | }, 29 | { 30 | "BahamutMechanics", 31 | new MechanicProperties 32 | { 33 | collisionShape = CollisionShape.Rectangle, 34 | collisionShapeParams = new Vector4(14, 4), 35 | colorHtml = "#0a4d8b", 36 | visible = false, 37 | isTargeted = true, 38 | mechanic = new ExecuteMultipleEvents 39 | { 40 | events = new List 41 | { 42 | new SpawnVisualObject { textureFilePath = "Mechanics/Resources/Bahamut.png", colorHtml = "#0a4d8b", visualDuration = 5, relativePosition = Vector3.up, scale = new Vector3(1, 1, 1), eulerAngles = new Vector3(0, 180, 0), isRotationRelative = true }, 43 | new WaitEvent { timeToWait = 2 }, 44 | new ModifyMechanicEvent { referenceMechanicName = "SnapshotDive" }, 45 | new SpawnVisualObject { textureFilePath = "Mechanics/Resources/Mark1.png", colorHtml = "#0a4d8b", visualDuration = 4, spawnOnPlayer = true, relativePosition = Vector3.up, scale = new Vector3(1, 1, 1), isBillboard = true }, 46 | new WaitEvent { timeToWait = 3.8f }, 47 | new ModifyMechanicEvent { referenceMechanicName = "SetVisible" }, 48 | new WaitEvent { timeToWait = 0.2f }, 49 | new ApplyEffectToPlayers { 50 | effects = new List { 51 | new DamageEffect { damageAmount = 90000, damageType = "Damage", name = "Megaflare Dive" }, 52 | new KnockbackEffect { knockbackDistance = 10 }, 53 | } 54 | }, 55 | new SpawnMechanicEvent { referenceMechanicName = "BahamutMechanics2" } 56 | } 57 | } 58 | } 59 | }, 60 | { 61 | "BahamutMechanics2", 62 | new MechanicProperties { 63 | visible = false, 64 | mechanic = new ExecuteMultipleEvents 65 | { 66 | events = new List 67 | { 68 | new WaitEvent { timeToWait = 3 }, 69 | new ReshufflePlayerIds(), 70 | new SpawnTargetedEvents { referenceMechanicName = "MegaflareTarget", targetingScheme = 71 | new UnionTargetingSchemes { 72 | targetingSchemes = new List { 73 | new TargetSpecificPlayerIdsByClass {classType = PlayerClassType.Tank, targetIds = new List{0} }, 74 | new TargetSpecificPlayerIdsByClass {classType = PlayerClassType.Healer, targetIds = new List{0} }, 75 | new TargetSpecificPlayerIdsByClass {classType = PlayerClassType.Dps, targetIds = new List{0, 1} }, 76 | } 77 | } 78 | }, 79 | new SpawnTargetedEvents 80 | { 81 | referenceMechanicName = "MegaflareStack", 82 | targetingScheme = new TargetRandomPlayers 83 | { 84 | numTargets = 0, // Get all players in a random order 85 | targetCondition = new CheckPlayerStatus { statusName = "MegaflareMark" }, // Filter to only players marked by megaflare 86 | totalTargetsNeeded = 1, // Select one of the players to place the stack on 87 | } 88 | }, 89 | } 90 | } 91 | } 92 | }, 93 | { 94 | "NaelMechanics", 95 | new MechanicProperties 96 | { 97 | visible = false, 98 | mechanic = new ExecuteMultipleEvents 99 | { 100 | events = new List 101 | { 102 | new SpawnVisualObject { textureFilePath = "Mechanics/Resources/Nael.png", colorHtml = "#a917bf", visualDuration = float.PositiveInfinity, relativePosition = Vector3.up, scale = new Vector3(1, 1, 1), eulerAngles = new Vector3(0, 180, 0), isRotationRelative = true }, 103 | new WaitEvent { timeToWait = 4.9f }, 104 | new SpawnTargetedEvents { referenceMechanicName = "Stack", spawnOnTarget = true, isPositionRelative = true, targetingScheme = new TargetRandomPlayers() }, 105 | new WaitEvent { timeToWait = 8 }, 106 | new SpawnTargetedEvents { referenceMechanicName = "Hypernova", spawnOnTarget = true, isPositionRelative = true, targetingScheme = new TargetRandomPlayers() }, 107 | new WaitEvent { timeToWait = 1.6f }, 108 | new SpawnTargetedEvents { referenceMechanicName = "Hypernova", spawnOnTarget = true, isPositionRelative = true, targetingScheme = new TargetRandomPlayers() }, 109 | new WaitEvent { timeToWait = 1.6f }, 110 | new SpawnTargetedEvents { referenceMechanicName = "Hypernova", spawnOnTarget = true, isPositionRelative = true, targetingScheme = new TargetRandomPlayers() }, 111 | new WaitEvent { timeToWait = 1.6f }, 112 | new SpawnTargetedEvents { referenceMechanicName = "Hypernova", spawnOnTarget = true, isPositionRelative = true, targetingScheme = new TargetRandomPlayers() }, 113 | } 114 | } 115 | } 116 | }, 117 | { 118 | "Stack", 119 | new MechanicProperties 120 | { 121 | collisionShape = CollisionShape.Round, 122 | collisionShapeParams = new Vector4(1.4f, 360), 123 | colorHtml = "#ff60ab", 124 | mechanic = new ExecuteMultipleEvents 125 | { 126 | events = new List 127 | { 128 | new WaitEvent { timeToWait = 0.2f }, 129 | new ApplyEffectToPlayers { 130 | effect = new DamageEffect { damageAmount = 700000, damageType = "Damage", name = "Thermionic Beam", maxStackAmount = 8 } 131 | } 132 | } 133 | } 134 | } 135 | }, 136 | { 137 | "Hypernova", 138 | new MechanicProperties 139 | { 140 | collisionShape = CollisionShape.Round, 141 | collisionShapeParams = new Vector4(1.5f, 360), 142 | colorHtml = "#352a43", 143 | mechanic = new ExecuteMultipleEvents 144 | { 145 | events = new List 146 | { 147 | new ApplyEffectToPlayers { effect = new DamageEffect { damageAmount = 10000, damageType = "Damage", name = "Hypernova" } }, 148 | new WaitEvent { timeToWait = 10 }, 149 | } 150 | }, 151 | 152 | persistentTickInterval = 0.3f, 153 | persistentActivationDelay = 2, 154 | persistentMechanic = new ApplyEffectToPlayers { effect = new DamageEffect { damageAmount = 999999, damageType = "Damage", name = "Bleed" } }, 155 | } 156 | }, 157 | { 158 | "TwinMechanics", 159 | new MechanicProperties 160 | { 161 | visible = false, 162 | mechanic = new ExecuteMultipleEvents 163 | { 164 | events = new List 165 | { 166 | new SpawnVisualObject { textureFilePath = "Mechanics/Resources/Twintania.png", colorHtml = "#067743", visualDuration = float.PositiveInfinity, relativePosition = Vector3.up, scale = new Vector3(1, 1, 1), eulerAngles = new Vector3(0, 180, 0), isRotationRelative = true }, 167 | new WaitEvent { timeToWait = 2 }, 168 | new SpawnTargetedEvents { referenceMechanicName = "Liquid Hell", spawnOnTarget = true, targetingScheme = new TargetSpecificPlayerIds { targetIds = new List { 0 } } }, 169 | new WaitEvent { timeToWait = 1.2f }, 170 | new SpawnTargetedEvents { referenceMechanicName = "Liquid Hell", spawnOnTarget = true, targetingScheme = new TargetSpecificPlayerIds { targetIds = new List { 0 } } }, 171 | new WaitEvent { timeToWait = 1.2f }, 172 | new SpawnTargetedEvents { referenceMechanicName = "Liquid Hell", spawnOnTarget = true, targetingScheme = new TargetSpecificPlayerIds { targetIds = new List { 0 } } }, 173 | new WaitEvent { timeToWait = 1.2f }, 174 | new SpawnTargetedEvents { referenceMechanicName = "Liquid Hell", spawnOnTarget = true, targetingScheme = new TargetSpecificPlayerIds { targetIds = new List { 0 } } }, 175 | new WaitEvent { timeToWait = 1.2f }, 176 | new SpawnTargetedEvents { referenceMechanicName = "Liquid Hell", spawnOnTarget = true, targetingScheme = new TargetSpecificPlayerIds { targetIds = new List { 0 } } }, 177 | } 178 | } 179 | } 180 | }, 181 | { 182 | "Liquid Hell", 183 | new MechanicProperties 184 | { 185 | collisionShape = CollisionShape.Round, 186 | collisionShapeParams = new Vector4(2, 360), 187 | colorHtml = "#ff7200", 188 | mechanic = new ExecuteMultipleEvents 189 | { 190 | events = new List 191 | { 192 | new ApplyEffectToPlayers { effect = new DamageEffect { damageAmount = 10000, damageType = "Damage", name = "Liquid Hell" } }, 193 | new WaitEvent { timeToWait = 12 }, 194 | } 195 | }, 196 | persistentTickInterval = 0.3f, 197 | persistentActivationDelay = 3, 198 | persistentMechanic = new ApplyEffectToPlayers { effect = new DamageEffect { damageAmount = 999999, damageType = "Damage", name = "Burns" } }, 199 | } 200 | }, 201 | { 202 | "MegaflareTarget", 203 | new MechanicProperties 204 | { 205 | visible = false, 206 | mechanic = new ExecuteMultipleEvents 207 | { 208 | events = new List 209 | { 210 | new SpawnVisualObject { textureFilePath = "Mechanics/Resources/Mark1.png", colorHtml = "#ff4200", visualDuration = 4, spawnOnPlayer = true, relativePosition = Vector3.up * 0.8f, scale = new Vector3(0.5f, 0.5f, 1), isBillboard = true }, 211 | new ApplyEffectToTargetOnly { effect = new ApplyStatusEffect { referenceStatusName = "MegaflareMark" } } 212 | } 213 | }, 214 | } 215 | }, 216 | { 217 | "MegaflareStack", 218 | new MechanicProperties 219 | { 220 | collisionShape = CollisionShape.Round, 221 | collisionShapeParams = new Vector4(1.68f, 360), 222 | colorHtml = "#ff4200", 223 | isTargeted = true, 224 | followSpeed = 10000, 225 | visible = false, 226 | mechanic = new ExecuteMultipleEvents 227 | { 228 | events = new List 229 | { 230 | new WaitEvent { timeToWait = 5 }, 231 | new ModifyMechanicEvent { referenceMechanicName = "SetVisible" }, 232 | new ApplyEffectToPlayers { 233 | condition = new CheckPlayerStatus { statusName = "MegaflareMark" }, 234 | effect = new DamageEffect { damageAmount = 350000, damageType = "Damage", name = "Megaflare", maxStackAmount = 4 }, 235 | failedConditionEffect = new DamageEffect { damageAmount = 200000, damageType = "Damage", name = "Megaflare" }, 236 | }, 237 | } 238 | } 239 | } 240 | }, 241 | { 242 | "SpawnTowers", 243 | new MechanicProperties 244 | { 245 | visible = false, 246 | mechanic = new ExecuteMultipleEvents 247 | { 248 | events = new List 249 | { 250 | new SpawnMechanicEvent { referenceMechanicName = "Tower", isPositionRelative = true, isRotationRelative = true, position = new Vector2(3.5f, 0) }, 251 | new SpawnMechanicEvent { referenceMechanicName = "Tower", isPositionRelative = true, isRotationRelative = true, position = new Vector2(-3.5f, 0) }, 252 | new SpawnMechanicEvent { referenceMechanicName = "Tower", isPositionRelative = true, isRotationRelative = true, position = new Vector2(0, 3.5f) }, 253 | new SpawnMechanicEvent { referenceMechanicName = "Tower", isPositionRelative = true, isRotationRelative = true, position = new Vector2(0, -3.5f) } 254 | } 255 | } 256 | } 257 | }, 258 | { 259 | "Tower Fail", 260 | new MechanicProperties 261 | { 262 | collisionShape = CollisionShape.Round, 263 | collisionShapeParams = new Vector4(50, 360), 264 | colorHtml = "#FF0000", 265 | mechanic = new ExecuteMultipleEvents 266 | { 267 | events = new List 268 | { 269 | new WaitEvent { timeToWait = 0.2f }, 270 | new ApplyEffectToPlayers { 271 | effect = new DamageEffect { damageAmount = 9999999, damageType = "Damage", name = "Tower Failed" } 272 | } 273 | } 274 | } 275 | } 276 | }, 277 | { 278 | "Tower", 279 | new MechanicProperties 280 | { 281 | collisionShape = CollisionShape.Round, 282 | collisionShapeParams = new Vector4(1, 360), 283 | colorHtml = "#FFFF00", 284 | mechanic = new ExecuteMultipleEvents 285 | { 286 | events = new List 287 | { 288 | new SpawnVisualObject { textureFilePath = "Mechanics/Resources/Tower.png", colorHtml = "#FFFF00", visualDuration = 8, relativePosition = Vector3.up, scale = new Vector3(1, 1.8876f, 1) * 0.6f, eulerAngles = new Vector3(0, 0, 0) }, 289 | new SpawnVisualObject { textureFilePath = "Mechanics/Resources/Tower.png", colorHtml = "#FFFF00", visualDuration = 8, relativePosition = Vector3.up, scale = new Vector3(1, 1.8876f, 1) * 0.6f, eulerAngles = new Vector3(0, 90, 0) }, 290 | new WaitEvent { timeToWait = 8 }, 291 | new CheckNumberOfPlayers 292 | { 293 | expressionFormat = "{0} >= 1", 294 | failEvent = new SpawnMechanicEvent { referenceMechanicName = "Tower Fail", isPositionRelative = true } 295 | }, 296 | new ApplyEffectToPlayers { 297 | effect = new DamageEffect { damageAmount = 10000, damageType = "Damage", name = "Megaflare" } 298 | } 299 | } 300 | } 301 | } 302 | }, 303 | { 304 | "ArenaBoundary", 305 | new MechanicProperties 306 | { 307 | collisionShape = CollisionShape.Round, 308 | collisionShapeParams = new Vector4(25, 360, 7), 309 | colorHtml = "#8800FF", 310 | persistentTickInterval = 0.2f, 311 | persistentMechanic = new ApplyEffectToPlayers { effect = new DamageEffect { damageAmount = 9999999, damageType = "TrueDamage" } }, 312 | } 313 | }, 314 | { 315 | "SpawnBosses", 316 | new MechanicProperties 317 | { 318 | visible = false, 319 | mechanic = new ExecuteMultipleEvents 320 | { 321 | events = new List 322 | { 323 | new WaitEvent { timeToWait = 2 }, 324 | new SpawnTargetedEvents { referenceMechanicName = "BahamutMechanics", position = new Vector2(0, 7), isPositionRelative = true, isRotationRelative = true, targetingScheme = new TargetRandomPlayers() }, 325 | new SpawnMechanicEvent { referenceMechanicName = "TwinMechanics", position = new Vector2(-5, -5), isPositionRelative = true, isRotationRelative = true, rotation = 60 }, 326 | new SpawnMechanicEvent { referenceMechanicName = "NaelMechanics", position = new Vector2(5, -5), isPositionRelative = true, isRotationRelative = true, rotation = -60 }, 327 | new WaitEvent { timeToWait = 8 }, 328 | new SpawnMechanicEvent { referenceMechanicName = "SpawnTowers", isRotationRelative = true }, 329 | } 330 | } 331 | } 332 | }, 333 | { 334 | "SpawnBossesB", 335 | new MechanicProperties 336 | { 337 | visible = false, 338 | mechanic = new ExecuteMultipleEvents 339 | { 340 | events = new List 341 | { 342 | new WaitEvent { timeToWait = 2 }, 343 | new SpawnTargetedEvents { referenceMechanicName = "BahamutMechanics", position = new Vector2(0, 7), isPositionRelative = true, isRotationRelative = true, targetingScheme = new TargetRandomPlayers() }, 344 | new SpawnMechanicEvent { referenceMechanicName = "NaelMechanics", position = new Vector2(-5, -5), isPositionRelative = true, isRotationRelative = true, rotation = 60 }, 345 | new SpawnMechanicEvent { referenceMechanicName = "TwinMechanics", position = new Vector2(5, -5), isPositionRelative = true, isRotationRelative = true, rotation = -60 }, 346 | new WaitEvent { timeToWait = 8 }, 347 | new SpawnMechanicEvent { referenceMechanicName = "SpawnTowers", isRotationRelative = true }, 348 | } 349 | } 350 | } 351 | }, 352 | }; 353 | 354 | mechanicData.referenceStatusProperties = new Dictionary 355 | { 356 | { 357 | "MegaflareMark", 358 | new StatusEffectData 359 | { 360 | statusName = "MegaflareMark", 361 | statusDescription = "Chosen to share the Megaflare stack.", 362 | duration = 7, 363 | } 364 | } 365 | }; 366 | 367 | mechanicData.mechanicPools = new Dictionary> 368 | { 369 | { 370 | "BossPool", 371 | new List { 372 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBosses" }, 373 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBosses", rotation = 45 }, 374 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBosses", rotation = 90 }, 375 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBosses", rotation = 135 }, 376 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBosses", rotation = 180 }, 377 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBosses", rotation = 225 }, 378 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBosses", rotation = 270 }, 379 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBosses", rotation = 315 }, 380 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBossesB" }, 381 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBossesB", rotation = 45 }, 382 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBossesB", rotation = 90 }, 383 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBossesB", rotation = 135 }, 384 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBossesB", rotation = 180 }, 385 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBossesB", rotation = 225 }, 386 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBossesB", rotation = 270 }, 387 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBossesB", rotation = 315 }, 388 | } 389 | } 390 | }; 391 | 392 | mechanicData.mechanicEvents = new List 393 | { 394 | new SpawnVisualObject 395 | { 396 | textureFilePath = "Mechanics/Resources/ArenaCircle.png", 397 | visualDuration = float.PositiveInfinity, 398 | relativePosition = new Vector3(0, -0.001f, 0), 399 | eulerAngles = new Vector3(90, 0, 0), 400 | scale = new Vector3(15.8637f, 15.8637f, 1), 401 | }, 402 | new SpawnMechanicEvent { referenceMechanicName = "ArenaBoundary" }, 403 | new ExecuteRandomEvents { mechanicPoolName = "BossPool" } 404 | }; 405 | 406 | var resultText = mechanicData.ToString(); 407 | 408 | File.WriteAllText($@"{baseOutputPath}\Mechanics\{mechanicName}.json", resultText); 409 | File.WriteAllText($@"{baseOutputPath}\Build\Mechanics\{mechanicName}.json", resultText); 410 | File.WriteAllText($@"{buildOutputPath}\Mechanics\{mechanicName}.json", resultText); 411 | 412 | $"Finished writing json to Mechanics/{mechanicName}.json".Dump(); -------------------------------------------------------------------------------- /Linqpad/MechanicSets/CircleProgramDemo.linq: -------------------------------------------------------------------------------- 1 | 2 | D:\src\Unity\xiv-sim\Library\ScriptAssemblies\Assembly-CSharp.dll 3 | <ProgramFilesX64>\Unity\Hub\Editor\2020.3.6f1\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll 4 | UnityEngine 5 | 6 | 7 | var mechanicName = "CircleProgramDemo"; 8 | var baseOutputPath = @"D:\src\Unity\xiv-sim"; 9 | var buildOutputPath = @"D:\src\Unity\xiv-sim-mechanics"; 10 | 11 | var mechanicData = new MechanicData(); 12 | 13 | mechanicData.referenceMechanicProperties = new Dictionary 14 | { 15 | { 16 | "OmegaMechanics", 17 | new MechanicProperties 18 | { 19 | visible = false, 20 | mechanic = new ExecuteMultipleEvents 21 | { 22 | events = new List 23 | { 24 | new WaitForAggro(), 25 | new WaitEvent { timeToWait = 3 }, 26 | new StartCastBar { castName = "Circle Program", duration = 5}, 27 | new WaitEvent { timeToWait = 5 }, 28 | new SpawnTargetedEvents { referenceMechanicName = "AutoAttack", targetingScheme = new TargetNthHighestAggro() }, 29 | new SpawnTargetedEvents {referenceMechanicName = "Looper-1", targetingScheme = new TargetSpecificPlayerIds { targetIds = new List {0, 1} } }, 30 | new SpawnTargetedEvents {referenceMechanicName = "Looper-2", targetingScheme = new TargetSpecificPlayerIds { targetIds = new List {2, 3} } }, 31 | new SpawnTargetedEvents {referenceMechanicName = "Looper-3", targetingScheme = new TargetSpecificPlayerIds { targetIds = new List {4, 5} } }, 32 | new SpawnTargetedEvents {referenceMechanicName = "Looper-4", targetingScheme = new TargetSpecificPlayerIds { targetIds = new List {6, 7} } }, 33 | new ReshufflePlayerIds(), 34 | new WaitEvent { timeToWait = 3 }, 35 | new SpawnTargetedEvents { referenceMechanicName = "AutoAttack", targetingScheme = new TargetNthHighestAggro() }, 36 | new WaitEvent { timeToWait = 1 }, 37 | new ExecuteRandomEvents { mechanicPoolName = "Towers-Pool" }, 38 | new WaitEvent { timeToWait = 1 }, 39 | new SpawnTethersToPlayers { referenceTetherName = "Blaster", tetherOffset = new Vector3(0, 1, 0), targetingScheme = new TargetSpecificPlayerIds { targetIds = new List {0, 1} } }, 40 | new StartCastBar { castName = "Blaster", duration = 8}, 41 | new WaitEvent { timeToWait = 9 }, 42 | new StartCastBar { castName = "", duration = 100000 }, 43 | new SpawnTargetedEvents { referenceMechanicName = "TetherAoe", targetingScheme = new TargetTetheredPlayers(), spawnOnTarget = true }, 44 | new WaitEvent { timeToWait = 9 }, 45 | new SpawnTargetedEvents { referenceMechanicName = "TetherAoe", targetingScheme = new TargetTetheredPlayers(), spawnOnTarget = true }, 46 | new WaitEvent { timeToWait = 9 }, 47 | new SpawnTargetedEvents { referenceMechanicName = "TetherAoe", targetingScheme = new TargetTetheredPlayers(), spawnOnTarget = true }, 48 | new WaitEvent { timeToWait = 9 }, 49 | new SpawnTargetedEvents { referenceMechanicName = "TetherAoe", targetingScheme = new TargetTetheredPlayers(), spawnOnTarget = true }, 50 | new WaitEvent {timeToWait = float.PositiveInfinity } 51 | } 52 | } 53 | } 54 | }, 55 | { 56 | "TetherAoe" , 57 | new MechanicProperties 58 | { 59 | collisionShape = CollisionShape.Round, 60 | collisionShapeParams = new Vector4(5, 360), 61 | colorHtml = "#614879", 62 | mechanic = new ExecuteMultipleEvents 63 | { 64 | events = new List 65 | { 66 | new WaitEvent { timeToWait = 0.2f }, 67 | new ApplyEffectToPlayers { 68 | condition = new CheckPlayerIsMechanicTarget(), 69 | effects = new List 70 | { 71 | new DamageEffect { damageAmount = 60000, damageType = "Damage", name = "Blaster" }, 72 | new ApplyStatusEffect { referenceStatusName = "HpDown" }, 73 | new ApplyStatusEffect { referenceStatusName = "DoomStack" }, 74 | }, 75 | failedConditionEffects = new List 76 | { 77 | new DamageEffect { damageAmount = 999999, damageType = "TrueDamage", name = "Blaster" }, 78 | new ApplyStatusEffect { referenceStatusName = "HpDown" }, 79 | new ApplyStatusEffect { referenceStatusName = "DoomStack" }, 80 | } 81 | } 82 | } 83 | } 84 | } 85 | }, 86 | { 87 | "ArenaBoundary", 88 | new MechanicProperties 89 | { 90 | collisionShape = CollisionShape.Round, 91 | collisionShapeParams = new Vector4(25, 360, 6.67f), 92 | colorHtml = "#8800FF", 93 | persistentTickInterval = 0.2f, 94 | persistentMechanic = new ApplyEffectToPlayers { effect = new DamageEffect { damageAmount = 9999999, damageType = "TrueDamage" } }, 95 | } 96 | }, 97 | { 98 | "Tower Fail", 99 | new MechanicProperties 100 | { 101 | collisionShape = CollisionShape.Round, 102 | collisionShapeParams = new Vector4(50, 360), 103 | colorHtml = "#FF0000", 104 | mechanic = new ExecuteMultipleEvents 105 | { 106 | events = new List 107 | { 108 | new WaitEvent { timeToWait = 0.2f }, 109 | new ApplyEffectToPlayers { 110 | effect = new DamageEffect { damageAmount = 9999999, damageType = "Damage", name = "Tower Failed" } 111 | } 112 | } 113 | } 114 | } 115 | }, 116 | { 117 | "Tower", 118 | new MechanicProperties 119 | { 120 | collisionShape = CollisionShape.Round, 121 | collisionShapeParams = new Vector4(1, 360), 122 | colorHtml = "#FFFF00", 123 | mechanic = new ExecuteMultipleEvents 124 | { 125 | events = new List 126 | { 127 | new WaitEvent { timeToWait = 10 }, 128 | new CheckNumberOfPlayers 129 | { 130 | expressionFormat = "{0} = 1", 131 | failEvent = new SpawnMechanicEvent { referenceMechanicName = "Tower Fail", isPositionRelative = true } 132 | }, 133 | new ApplyEffectToPlayers { 134 | condition = new CheckPlayerStatus 135 | { 136 | statusName = "Circle Program", 137 | }, 138 | effects = new List 139 | { 140 | new DamageEffect { damageAmount = 60000, damageType = "Damage", name = "Circle Program" }, 141 | new RemoveStatusEffect { referenceStatusName = "Looper-1", doExpireEvent = false }, 142 | new RemoveStatusEffect { referenceStatusName = "Looper-1", doExpireEvent = false }, 143 | new RemoveStatusEffect { referenceStatusName = "Looper-2", doExpireEvent = false }, 144 | new RemoveStatusEffect { referenceStatusName = "Looper-2", doExpireEvent = false }, 145 | new RemoveStatusEffect { referenceStatusName = "Looper-3", doExpireEvent = false }, 146 | new RemoveStatusEffect { referenceStatusName = "Looper-3", doExpireEvent = false }, 147 | new RemoveStatusEffect { referenceStatusName = "Looper-4", doExpireEvent = false }, 148 | new RemoveStatusEffect { referenceStatusName = "Looper-4", doExpireEvent = false }, 149 | new RemoveStatusEffect { referenceStatusName = "Line-1" }, 150 | new RemoveStatusEffect { referenceStatusName = "Line-1" }, 151 | new RemoveStatusEffect { referenceStatusName = "Line-2" }, 152 | new RemoveStatusEffect { referenceStatusName = "Line-2" }, 153 | new RemoveStatusEffect { referenceStatusName = "Line-3" }, 154 | new RemoveStatusEffect { referenceStatusName = "Line-3" }, 155 | new RemoveStatusEffect { referenceStatusName = "Line-4" }, 156 | new RemoveStatusEffect { referenceStatusName = "Line-4" }, 157 | }, 158 | failedConditionEffect = new DamageEffect { damageAmount = 120000, damageType = "Damage", name = "Circle Program" } 159 | } 160 | } 161 | } 162 | } 163 | }, 164 | { 165 | "Tower-Offset", 166 | new MechanicProperties { 167 | visible = false, 168 | mechanic = new SpawnMechanicEvent {referenceMechanicName = "Tower", isPositionRelative = true, isRotationRelative = true, position = Vector3.right * 4.5f } 169 | } 170 | }, 171 | { 172 | "TowerSet-A", 173 | new MechanicProperties 174 | { 175 | visible = false, 176 | mechanic = new ExecuteMultipleEvents 177 | { 178 | events = new List 179 | { 180 | new SpawnMechanicEvent {referenceMechanicName = "Tower-Offset", isPositionRelative = true, isRotationRelative = true}, 181 | new SpawnMechanicEvent {referenceMechanicName = "Tower-Offset", isPositionRelative = true, isRotationRelative = true, rotation = 90}, 182 | new WaitEvent { timeToWait = 9 }, 183 | new SpawnMechanicEvent {referenceMechanicName = "Tower-Offset", isPositionRelative = true, isRotationRelative = true, rotation = 180}, 184 | new SpawnMechanicEvent {referenceMechanicName = "Tower-Offset", isPositionRelative = true, isRotationRelative = true, rotation = 270}, 185 | new WaitEvent { timeToWait = 9 }, 186 | new SpawnMechanicEvent {referenceMechanicName = "Tower-Offset", isPositionRelative = true, isRotationRelative = true}, 187 | new SpawnMechanicEvent {referenceMechanicName = "Tower-Offset", isPositionRelative = true, isRotationRelative = true, rotation = 90}, 188 | new WaitEvent { timeToWait = 9 }, 189 | new SpawnMechanicEvent {referenceMechanicName = "Tower-Offset", isPositionRelative = true, isRotationRelative = true, rotation = 180}, 190 | new SpawnMechanicEvent {referenceMechanicName = "Tower-Offset", isPositionRelative = true, isRotationRelative = true, rotation = 270}, 191 | } 192 | } 193 | } 194 | }, 195 | { 196 | "TowerSet-B", 197 | new MechanicProperties 198 | { 199 | visible = false, 200 | mechanic = new ExecuteMultipleEvents 201 | { 202 | events = new List 203 | { 204 | new SpawnMechanicEvent {referenceMechanicName = "Tower-Offset", isPositionRelative = true, isRotationRelative = true}, 205 | new SpawnMechanicEvent {referenceMechanicName = "Tower-Offset", isPositionRelative = true, isRotationRelative = true, rotation = 180}, 206 | new WaitEvent { timeToWait = 9 }, 207 | new SpawnMechanicEvent {referenceMechanicName = "Tower-Offset", isPositionRelative = true, isRotationRelative = true, rotation = 90}, 208 | new SpawnMechanicEvent {referenceMechanicName = "Tower-Offset", isPositionRelative = true, isRotationRelative = true, rotation = 270}, 209 | new WaitEvent { timeToWait = 9 }, 210 | new SpawnMechanicEvent {referenceMechanicName = "Tower-Offset", isPositionRelative = true, isRotationRelative = true}, 211 | new SpawnMechanicEvent {referenceMechanicName = "Tower-Offset", isPositionRelative = true, isRotationRelative = true, rotation = 180}, 212 | new WaitEvent { timeToWait = 9 }, 213 | new SpawnMechanicEvent {referenceMechanicName = "Tower-Offset", isPositionRelative = true, isRotationRelative = true, rotation = 90}, 214 | new SpawnMechanicEvent {referenceMechanicName = "Tower-Offset", isPositionRelative = true, isRotationRelative = true, rotation = 270}, 215 | } 216 | } 217 | } 218 | }, 219 | { 220 | "Looper", 221 | new MechanicProperties 222 | { 223 | visible = false, 224 | mechanic = new ApplyEffectToTargetOnly 225 | { 226 | effect = new DamageEffect { damageAmount = 99999999, damageType = "TrueDamage", name = "Circle Program" } 227 | } 228 | } 229 | }, 230 | { 231 | "ApplyDoom", 232 | new MechanicProperties 233 | { 234 | visible = false, 235 | mechanic = new ApplyEffectToTargetOnly 236 | { 237 | effects = new List { 238 | new ApplyStatusEffect { referenceStatusName = "Doom" }, 239 | new RemoveStatusEffect { referenceStatusName = "DoomStack" }, 240 | } 241 | } 242 | } 243 | }, 244 | { 245 | "Doom", 246 | new MechanicProperties 247 | { 248 | visible = false, 249 | mechanic = new ApplyEffectToTargetOnly 250 | { 251 | effect = new DamageEffect { damageAmount = 99999999, damageType = "TrueDamage", name = "Doom" } 252 | } 253 | } 254 | }, 255 | { 256 | "AutoAttack", 257 | new MechanicProperties 258 | { 259 | visible = false, 260 | mechanic = new ApplyEffectToTargetOnly 261 | { 262 | effect = new DamageEffect { damageAmount = 100000, damageType = "Damage" } 263 | } 264 | } 265 | }, 266 | { 267 | "StartButton", 268 | new MechanicProperties 269 | { 270 | collisionShape = CollisionShape.Round, 271 | collisionShapeParams = new Vector4(0.5f, 360), 272 | colorHtml = "#00ff00", 273 | persistentTickInterval = 0.1f, 274 | persistentActivationDelay = 1, 275 | mechanicTag = "StartButton", 276 | persistentMechanic = new CheckNumberOfPlayers 277 | { 278 | expressionFormat = "{0} = 0", 279 | failEvent = new ExecuteMultipleEvents{ 280 | events = new List { 281 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBosses" }, 282 | new ClearMechanicsWithTag { mechanicTag = "StartButton" }, 283 | } 284 | } 285 | }, 286 | } 287 | }, 288 | { 289 | "SpawnBosses", 290 | new MechanicProperties 291 | { 292 | visible = false, 293 | mechanic = new ExecuteMultipleEvents 294 | { 295 | events = new List 296 | { 297 | new SpawnEnemy { 298 | enemyName = "Omega", 299 | textureFilePath = "Mechanics/Resources/Omega.png", 300 | colorHtml = "#0a4d8b", 301 | maxHp = 35000000, 302 | baseMoveSpeed = 2, 303 | hitboxSize = 10, 304 | visualPosition = new Vector3(0, 1.5f, 0), 305 | visualScale = Vector3.one * 4, 306 | referenceMechanicName = "OmegaMechanics", 307 | position = new Vector2(0, 0), 308 | isPositionRelative = true, 309 | isRotationRelative = true, 310 | }, 311 | } 312 | } 313 | } 314 | }, 315 | }; 316 | 317 | mechanicData.referenceTetherProperties = new Dictionary 318 | { 319 | { 320 | "Blaster", 321 | new TetherProperties 322 | { 323 | colorHtml = "#ff8400", 324 | tetherDuration = 99, 325 | interceptMechanic = new SwitchTetheredPlayer(), 326 | oneTetherPerPlayer = true, 327 | tetherTag = "Blaster", 328 | retargetRandomPlayerOnDeath = true 329 | } 330 | }, 331 | }; 332 | 333 | mechanicData.referenceStatusProperties = new Dictionary 334 | { 335 | { 336 | "HpDown", 337 | new DamageModifier 338 | { 339 | statusIconPath = "Mechanics/Resources/HpDown.png", 340 | statusName = "HP Down", 341 | statusDescription = "This is actually just a vuln.", 342 | damageMultiplier = 100, 343 | duration = 10, 344 | } 345 | }, 346 | { 347 | "DoomStack", 348 | new SpawnMechanicOnReachStacks 349 | { 350 | statusIconPath = "Mechanics/Resources/DoomStack.png", 351 | statusName = "Twice-come Ruin", 352 | statusDescription = "Too many stacks will result in Doom.", 353 | referenceMechanicName = "ApplyDoom", 354 | requiredStacks = 2, 355 | maxStacks = 2, 356 | duration = 40, 357 | } 358 | }, 359 | { 360 | "Doom", 361 | new SpawnMechanicOnExpire 362 | { 363 | statusIconPath = "Mechanics/Resources/Doom.png", 364 | statusName = "Doom", 365 | statusDescription = "Certain death when counter reaches zero.", 366 | referenceMechanicName = "Doom", 367 | duration = 3, 368 | } 369 | }, 370 | }; 371 | 372 | mechanicData.mechanicEvents = new List 373 | { 374 | new SpawnMechanicEvent { referenceMechanicName = "ArenaBoundary" }, 375 | new SpawnVisualObject 376 | { 377 | textureFilePath = "Mechanics/Resources/ArenaCircle.png", 378 | visualDuration = float.PositiveInfinity, 379 | relativePosition = new Vector3(0, -0.001f, 0), 380 | eulerAngles = new Vector3(90, 0, 0), 381 | scale = new Vector3(15.0931f, 15.0931f, 1), 382 | }, 383 | new ExecuteMultipleEvents 384 | { 385 | events = new List 386 | { 387 | new SpawnMechanicEvent { referenceMechanicName = "StartButton", position = new Vector2(0, 3) }, 388 | } 389 | } 390 | }; 391 | 392 | var towerPool = new List(); 393 | for (int i = 0; i < 12; i++) 394 | { 395 | towerPool.Add(new SpawnMechanicEvent { referenceMechanicName = "TowerSet-A", rotation = 45 + 30 * i }); 396 | towerPool.Add(new SpawnMechanicEvent { referenceMechanicName = "TowerSet-B", rotation = 45 + 30 * i }); 397 | } 398 | 399 | mechanicData.mechanicPools = new Dictionary> 400 | { 401 | {"Towers-Pool", towerPool}, 402 | }; 403 | 404 | var lineNames = new string[] { "Zero", "First", "Second", "Third", "Fourth" }; 405 | 406 | for (int i = 1; i <= 4; i++) 407 | { 408 | mechanicData.referenceStatusProperties[$"Looper-{i}"] = new SpawnMechanicOnExpire 409 | { 410 | statusIconPath = "Mechanics/Resources/Looper.png", 411 | statusName = "Circle Program", 412 | statusDescription = "Certain death if not cleansed by a tower.", 413 | duration = i * 10 + 7, 414 | referenceMechanicName = "Looper", 415 | shouldKeepOnDeath = false, 416 | allowDuplicates = true, 417 | }; 418 | mechanicData.referenceStatusProperties[$"Line-{i}"] = new StatusEffectData 419 | { 420 | statusIconPath = $"Mechanics/Resources/Line{i}.png", 421 | statusName = $"{lineNames[i]} in Line", 422 | statusDescription = $"Marked as target #{i}.", 423 | duration = i * 10 + 7, 424 | shouldKeepOnDeath = false, 425 | allowDuplicates = true, 426 | }; 427 | mechanicData.referenceMechanicProperties[$"Looper-{i}"] = new MechanicProperties 428 | { 429 | visible = false, 430 | mechanic = new ExecuteMultipleEvents 431 | { 432 | events = new List 433 | { 434 | new ApplyEffectToTargetOnly { effect = new ApplyStatusEffect { referenceStatusName = $"Looper-{i}" } }, 435 | new ApplyEffectToTargetOnly { effect = new ApplyStatusEffect { referenceStatusName = $"Line-{i}" } }, 436 | } 437 | } 438 | }; 439 | } 440 | 441 | var resultText = mechanicData.ToString(); 442 | 443 | File.WriteAllText($@"{baseOutputPath}\Mechanics\{mechanicName}.json", resultText); 444 | File.WriteAllText($@"{baseOutputPath}\Build\Mechanics\{mechanicName}.json", resultText); 445 | File.WriteAllText($@"{buildOutputPath}\Mechanics\{mechanicName}.json", resultText); 446 | 447 | $"Finished writing json to Mechanics/{mechanicName}.json".Dump(); -------------------------------------------------------------------------------- /Linqpad/MechanicSets/FellruinDemo.linq: -------------------------------------------------------------------------------- 1 | 2 | D:\src\Unity\xiv-sim\Library\ScriptAssemblies\Assembly-CSharp.dll 3 | <ProgramFilesX64>\Unity\Hub\Editor\2020.3.6f1\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll 4 | UnityEngine 5 | 6 | 7 | var mechanicName = "FellruinDemo"; 8 | var baseOutputPath = @"D:\src\Unity\xiv-sim"; 9 | var buildOutputPath = @"D:\src\Unity\xiv-sim-mechanics"; 10 | 11 | var mechanicData = new MechanicData(); 12 | 13 | mechanicData.referenceMechanicProperties = new Dictionary 14 | { 15 | { 16 | "BahamutMechanics", 17 | new MechanicProperties 18 | { 19 | visible = false, 20 | mechanic = new ExecuteMultipleEvents 21 | { 22 | events = new List 23 | { 24 | new WaitEvent { timeToWait = 6 }, 25 | new SpawnTethersToPlayers { referenceTetherName = "TempestWing", tetherOffset = new Vector3(0, 1, 0), targetingScheme = new TargetSpecificPlayerIds { targetIds = new List {0, 1} } }, 26 | new WaitEvent { timeToWait = 8 }, 27 | new SpawnTargetedEvents { referenceMechanicName = "TetherAoe", targetingScheme = new TargetTetheredPlayers(), spawnOnTarget = true }, 28 | new SpawnMechanicEvent { referenceMechanicName = "Raidwide1" }, 29 | new WaitEvent {timeToWait = float.PositiveInfinity } 30 | } 31 | } 32 | } 33 | }, 34 | { 35 | "TwintaniaMechanics", 36 | new MechanicProperties 37 | { 38 | visible = false, 39 | mechanic = new ExecuteMultipleEvents 40 | { 41 | events = new List 42 | { 43 | new WaitEvent {timeToWait = float.PositiveInfinity } 44 | } 45 | } 46 | } 47 | }, 48 | { 49 | "NaelMechanics", 50 | new MechanicProperties 51 | { 52 | visible = false, 53 | mechanic = new ExecuteMultipleEvents 54 | { 55 | events = new List 56 | { 57 | new WaitEvent {timeToWait = 1}, 58 | new ExecuteRandomEventSequence { mechanicPoolName = "Quote-Pool" }, 59 | new WaitEvent {timeToWait = 7}, 60 | new ReshufflePlayerIds(), 61 | new SpawnTargetedEvents { referenceMechanicName = "SpreadAoe", spawnOnTarget = true, targetingScheme = new TargetSpecificPlayerIds {targetIds = new List{0, 1, 2, 3} } }, 62 | new WaitEvent {timeToWait = float.PositiveInfinity } 63 | } 64 | } 65 | } 66 | }, 67 | { 68 | "Neurolink", 69 | new MechanicProperties 70 | { 71 | collisionShape = CollisionShape.Round, 72 | collisionShapeParams = new Vector4(0.4f, 360), 73 | colorHtml = "#9cff00", 74 | 75 | persistentTickInterval = 0.2f, 76 | persistentMechanic = new ApplyEffectToPlayers { effect = new ApplyStatusEffect { referenceStatusName = "Neurolink" } }, 77 | } 78 | }, 79 | { 80 | "Dynamo", 81 | new MechanicProperties 82 | { 83 | collisionShape = CollisionShape.Round, 84 | collisionShapeParams = new Vector4(8, 360, 2f), 85 | colorHtml = "#910044", 86 | mechanic = new ExecuteMultipleEvents 87 | { 88 | events = new List 89 | { 90 | new WaitEvent { timeToWait = 0.2f }, 91 | new ApplyEffectToPlayers { 92 | effect = new DamageEffect { damageAmount = 300000, damageType = "Damage", name = "Lunar Dynamo" } 93 | } 94 | } 95 | } 96 | } 97 | }, 98 | { 99 | "Dive", 100 | new MechanicProperties 101 | { 102 | collisionShape = CollisionShape.Round, 103 | collisionShapeParams = new Vector4(1.5f, 360), 104 | colorHtml = "#370091", 105 | mechanic = new ExecuteMultipleEvents 106 | { 107 | events = new List 108 | { 109 | new WaitEvent { timeToWait = 0.2f }, 110 | new ApplyEffectToPlayers { 111 | condition = new CheckPlayerIsMechanicTarget(), 112 | effects = new List 113 | { 114 | new DamageEffect { damageAmount = 40000, damageType = "Damage", name = "Raven's Dive" }, 115 | }, 116 | failedConditionEffects = new List 117 | { 118 | new DamageEffect { damageAmount = 40000, damageType = "Damage", name = "Raven's Dive" }, 119 | new KnockbackEffect { knockbackDistance = 10}, 120 | } 121 | } 122 | } 123 | } 124 | } 125 | }, 126 | { 127 | "SpreadAoe" , 128 | new MechanicProperties 129 | { 130 | collisionShape = CollisionShape.Round, 131 | collisionShapeParams = new Vector4(1.5f, 360), 132 | colorHtml = "#dcdcdc", 133 | mechanic = new ExecuteMultipleEvents 134 | { 135 | events = new List 136 | { 137 | new WaitEvent { timeToWait = 0.2f }, 138 | new ApplyEffectToPlayers { 139 | effect = new DamageEffect { damageAmount = 80000, damageType = "Damage", name = "Meteor Stream" } 140 | } 141 | } 142 | } 143 | } 144 | }, 145 | { 146 | "TetherAoe" , 147 | new MechanicProperties 148 | { 149 | collisionShape = CollisionShape.Round, 150 | collisionShapeParams = new Vector4(1.5f, 360), 151 | colorHtml = "#59ce85", 152 | mechanic = new ExecuteMultipleEvents 153 | { 154 | events = new List 155 | { 156 | new WaitEvent { timeToWait = 0.2f }, 157 | new ApplyEffectToPlayers { 158 | condition = new CheckPlayerIsMechanicTarget(), 159 | effects = new List 160 | { 161 | new DamageEffect { damageAmount = 120000, damageType = "Damage", name = "Tempest Wing" }, 162 | }, 163 | failedConditionEffects = new List 164 | { 165 | new DamageEffect { damageAmount = 120000, damageType = "Damage", name = "Tempest Wing" }, 166 | new KnockbackEffect { knockbackDistance = 10}, 167 | } 168 | } 169 | } 170 | } 171 | } 172 | }, 173 | { 174 | "Raidwide1", 175 | new MechanicProperties 176 | { 177 | collisionShape = CollisionShape.Round, 178 | collisionShapeParams = new Vector4(100, 360), 179 | visible = false, 180 | mechanic = new ExecuteMultipleEvents 181 | { 182 | events = new List 183 | { 184 | new ApplyEffectToPlayers { 185 | condition = new CheckPlayerStatus { statusName = "Neurolink" }, 186 | effect = new DamageEffect { damageAmount = 80000, damageType = "Magic", name = "Aetheric Profusion" }, 187 | failedConditionEffect = new DamageEffect { damageAmount = 800000, damageType = "Magic", name = "Aetheric Profusion" }, 188 | } 189 | } 190 | } 191 | } 192 | }, 193 | { 194 | "SpawnBosses-A", 195 | new MechanicProperties 196 | { 197 | visible = false, 198 | mechanic = new ExecuteMultipleEvents 199 | { 200 | events = new List 201 | { 202 | new SpawnEnemy { 203 | enemyName = "Bahamut", 204 | textureFilePath = "Mechanics/Resources/Bahamut.png", 205 | colorHtml = "#0a4d8b", 206 | maxHp = 35000000, 207 | baseMoveSpeed = 2, 208 | hitboxSize = 2, 209 | visualPosition = new Vector3(0, 1, 0), 210 | visualScale = Vector3.one, 211 | referenceMechanicName = "BahamutMechanics", 212 | position = new Vector2(0, -3.7f), 213 | isPositionRelative = true, 214 | isRotationRelative = true, 215 | isTargetable = false, 216 | }, 217 | new SpawnEnemy { 218 | enemyName = "Nael Deus Darnus", 219 | textureFilePath = "Mechanics/Resources/Nael.png", 220 | colorHtml = "#a917bf", 221 | maxHp = 35000000, 222 | baseMoveSpeed = 2, 223 | hitboxSize = 2, 224 | visualPosition = new Vector3(0, 1, 0), 225 | visualScale = Vector3.one, 226 | referenceMechanicName = "NaelMechanics", 227 | position = new Vector2(3.7f * 0.866f, 1.85f), 228 | rotation = 240, 229 | isPositionRelative = true, 230 | isRotationRelative = true, 231 | isTargetable = false 232 | }, 233 | new SpawnEnemy { 234 | enemyName = "Twintania", 235 | textureFilePath = "Mechanics/Resources/Twintania.png", 236 | colorHtml = "#067743", 237 | maxHp = 35000000, 238 | baseMoveSpeed = 2, 239 | hitboxSize = 2, 240 | visualPosition = new Vector3(0, 1, 0), 241 | visualScale = Vector3.one, 242 | referenceMechanicName = "TwintaniaMechanics", 243 | position = new Vector2(-3.7f * 0.866f, 1.85f), 244 | rotation = 120, 245 | isPositionRelative = true, 246 | isRotationRelative = true, 247 | isTargetable = false 248 | }, 249 | } 250 | } 251 | } 252 | }, 253 | { 254 | "SpawnBosses-B", 255 | new MechanicProperties 256 | { 257 | visible = false, 258 | mechanic = new ExecuteMultipleEvents 259 | { 260 | events = new List 261 | { 262 | new SpawnEnemy { 263 | enemyName = "Bahamut", 264 | textureFilePath = "Mechanics/Resources/Bahamut.png", 265 | colorHtml = "#0a4d8b", 266 | maxHp = 35000000, 267 | baseMoveSpeed = 2, 268 | hitboxSize = 2, 269 | visualPosition = new Vector3(0, 1, 0), 270 | visualScale = Vector3.one, 271 | referenceMechanicName = "BahamutMechanics", 272 | position = new Vector2(0, -3.7f), 273 | isPositionRelative = true, 274 | isRotationRelative = true, 275 | isTargetable = false, 276 | }, 277 | new SpawnEnemy { 278 | enemyName = "Nael Deus Darnus", 279 | textureFilePath = "Mechanics/Resources/Nael.png", 280 | colorHtml = "#a917bf", 281 | maxHp = 35000000, 282 | baseMoveSpeed = 2, 283 | hitboxSize = 2, 284 | visualPosition = new Vector3(0, 1, 0), 285 | visualScale = Vector3.one, 286 | referenceMechanicName = "NaelMechanics", 287 | position = new Vector2(-3.7f * 0.866f, 1.85f), 288 | rotation = 120, 289 | isPositionRelative = true, 290 | isRotationRelative = true, 291 | isTargetable = false 292 | }, 293 | new SpawnEnemy { 294 | enemyName = "Twintania", 295 | textureFilePath = "Mechanics/Resources/Twintania.png", 296 | colorHtml = "#067743", 297 | maxHp = 35000000, 298 | baseMoveSpeed = 2, 299 | hitboxSize = 2, 300 | visualPosition = new Vector3(0, 1, 0), 301 | visualScale = Vector3.one, 302 | referenceMechanicName = "TwintaniaMechanics", 303 | position = new Vector2(3.7f * 0.866f, 1.85f), 304 | rotation = 240, 305 | isPositionRelative = true, 306 | isRotationRelative = true, 307 | isTargetable = false 308 | }, 309 | } 310 | } 311 | } 312 | }, 313 | { 314 | "ArenaBoundary", 315 | new MechanicProperties 316 | { 317 | collisionShape = CollisionShape.Round, 318 | collisionShapeParams = new Vector4(25, 360, 7), 319 | colorHtml = "#8800FF", 320 | persistentTickInterval = 0.2f, 321 | persistentMechanic = new ApplyEffectToPlayers { effect = new DamageEffect { damageAmount = 9999999, damageType = "TrueDamage" } }, 322 | } 323 | }, 324 | { 325 | "Neurolinks-A", 326 | new MechanicProperties 327 | { 328 | visible = false, 329 | mechanic = new ExecuteMultipleEvents 330 | { 331 | events = new List { 332 | new SpawnMechanicEvent { referenceMechanicName = "Neurolink", position = new Vector2(0, 3.7f) }, 333 | new SpawnMechanicEvent { referenceMechanicName = "Neurolink", position = new Vector2(3.7f * 0.866f, -1.85f) }, 334 | new SpawnMechanicEvent { referenceMechanicName = "Neurolink", position = new Vector2(-3.7f * 0.866f, -1.85f) }, 335 | } 336 | } 337 | } 338 | }, 339 | { 340 | "Neurolinks-B", 341 | new MechanicProperties 342 | { 343 | visible = false, 344 | mechanic = new ExecuteMultipleEvents 345 | { 346 | events = new List { 347 | new SpawnMechanicEvent { referenceMechanicName = "Neurolink", position = new Vector2(0, -3.7f) }, 348 | new SpawnMechanicEvent { referenceMechanicName = "Neurolink", position = new Vector2(3.7f * 0.866f, 1.85f) }, 349 | new SpawnMechanicEvent { referenceMechanicName = "Neurolink", position = new Vector2(-3.7f * 0.866f, 1.85f) }, 350 | } 351 | } 352 | } 353 | }, 354 | { 355 | "StartButton-A", 356 | new MechanicProperties 357 | { 358 | collisionShape = CollisionShape.Round, 359 | collisionShapeParams = new Vector4(0.5f, 360), 360 | colorHtml = "#00ff00", 361 | persistentTickInterval = 0.1f, 362 | persistentActivationDelay = 1, 363 | mechanicTag = "StartButton", 364 | persistentMechanic = new CheckNumberOfPlayers 365 | { 366 | expressionFormat = "{0} = 0", 367 | failEvent = new ExecuteMultipleEvents{ 368 | events = new List { 369 | new SpawnMechanicEvent { referenceMechanicName = "Neurolinks-A" }, 370 | new SpawnMechanicEvent { referenceMechanicName = "StartMechanics" }, 371 | new ClearMechanicsWithTag { mechanicTag = "StartButton" }, 372 | } 373 | } 374 | }, 375 | } 376 | }, 377 | { 378 | "StartButton-B", 379 | new MechanicProperties 380 | { 381 | collisionShape = CollisionShape.Round, 382 | collisionShapeParams = new Vector4(0.5f, 360), 383 | colorHtml = "#00ff00", 384 | persistentTickInterval = 0.1f, 385 | persistentActivationDelay = 1, 386 | mechanicTag = "StartButton", 387 | persistentMechanic = new CheckNumberOfPlayers 388 | { 389 | expressionFormat = "{0} = 0", 390 | failEvent = new ExecuteMultipleEvents{ 391 | events = new List { 392 | new SpawnMechanicEvent { referenceMechanicName = "Neurolinks-B" }, 393 | new SpawnMechanicEvent { referenceMechanicName = "StartMechanics" }, 394 | new ClearMechanicsWithTag { mechanicTag = "StartButton" }, 395 | } 396 | } 397 | }, 398 | } 399 | }, 400 | { 401 | "StartMechanics", 402 | new MechanicProperties 403 | { 404 | visible = false, 405 | mechanic = new ExecuteMultipleEvents 406 | { 407 | events = new List 408 | { 409 | new WaitEvent { timeToWait = 2}, 410 | new ExecuteRandomEvents { mechanicPoolName = "Spawn-Bosses-Pool" }, 411 | } 412 | } 413 | } 414 | } 415 | }; 416 | 417 | mechanicData.referenceTetherProperties = new Dictionary 418 | { 419 | { 420 | "TempestWing", 421 | new TetherProperties 422 | { 423 | colorHtml = "#00ff60", 424 | tetherDuration = 9, 425 | interceptMechanic = new SwitchTetheredPlayer(), 426 | oneTetherPerPlayer = true, 427 | tetherTag = "TempestWing", 428 | retargetRandomPlayerOnDeath = true 429 | } 430 | }, 431 | }; 432 | 433 | mechanicData.referenceStatusProperties = new Dictionary 434 | { 435 | { 436 | "Neurolink", 437 | new StatusEffectData 438 | { 439 | statusIconPath = "Mechanics/Resources/Neurolink.png", 440 | statusName = "Neurolink", 441 | statusDescription = "Neurolink", 442 | duration = 0.3f, 443 | } 444 | }, 445 | }; 446 | 447 | mechanicData.mechanicEvents = new List 448 | { 449 | new SpawnMechanicEvent { referenceMechanicName = "ArenaBoundary" }, 450 | new SpawnVisualObject 451 | { 452 | textureFilePath = "Mechanics/Resources/ArenaCircle.png", 453 | visualDuration = float.PositiveInfinity, 454 | relativePosition = new Vector3(0, -0.001f, 0), 455 | eulerAngles = new Vector3(90, 0, 0), 456 | scale = new Vector3(15.8637f, 15.8637f, 1), 457 | }, 458 | new ExecuteMultipleEvents 459 | { 460 | events = new List 461 | { 462 | new SpawnMechanicEvent { referenceMechanicName = "StartButton-A", position = new Vector2(0, 3) }, 463 | new SpawnMechanicEvent { referenceMechanicName = "StartButton-B", position = new Vector2(0, -3) }, 464 | } 465 | } 466 | }; 467 | mechanicData.mechanicPools = new Dictionary> 468 | { 469 | { 470 | "Spawn-Bosses-Pool", 471 | new List 472 | { 473 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBosses-A" }, 474 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBosses-A", rotation = 120 }, 475 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBosses-A", rotation = 240 }, 476 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBosses-B" }, 477 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBosses-B", rotation = 120 }, 478 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBosses-B", rotation = 240 }, 479 | } 480 | }, 481 | { 482 | "Quote-Pool", 483 | new List 484 | { 485 | new ExecuteMultipleEvents 486 | { 487 | events = new List 488 | { 489 | new SpawnVisualObject { textureFilePath = "Mechanics/Resources/Fellruin-In-Spread.png", visualDuration = 6, isBillboard = true, relativePosition = Vector3.up * 2, scale = new Vector3(4.17f, 1, 1) }, 490 | new WaitEvent { timeToWait = 6 }, 491 | new SpawnMechanicEvent { referenceMechanicName = "Dynamo", isPositionRelative = true }, 492 | new WaitEvent { timeToWait = 3 }, 493 | new ReshufflePlayerIds(), 494 | new SetEnemyMovement {movementTime = 0.2f, moveToTarget = new TargetSpecificPlayerIds {targetIds = new List {0} } }, 495 | new SpawnTargetedEvents { referenceMechanicName = "Dive", isPositionRelative = true, spawnOnTarget = true, targetingScheme = new TargetSpecificPlayerIds { targetIds = new List {0} } }, 496 | } 497 | }, 498 | new ExecuteMultipleEvents 499 | { 500 | events = new List 501 | { 502 | new SpawnVisualObject { textureFilePath = "Mechanics/Resources/Fellruin-Spread-In.png", visualDuration = 6, isBillboard = true, relativePosition = Vector3.up * 2, scale = new Vector3(4.17f, 1, 1) }, 503 | new WaitEvent { timeToWait = 6 }, 504 | new ReshufflePlayerIds(), 505 | new SetEnemyMovement {movementTime = 0.2f, moveToTarget = new TargetSpecificPlayerIds {targetIds = new List {0} } }, 506 | new SpawnTargetedEvents { referenceMechanicName = "Dive", isPositionRelative = true, spawnOnTarget = true, targetingScheme = new TargetSpecificPlayerIds { targetIds = new List {0} } }, 507 | new WaitEvent { timeToWait = 3 }, 508 | new SpawnMechanicEvent { referenceMechanicName = "Dynamo", isPositionRelative = true }, 509 | } 510 | }, 511 | } 512 | }, 513 | }; 514 | 515 | var resultText = mechanicData.ToString(); 516 | 517 | File.WriteAllText($@"{baseOutputPath}\Mechanics\{mechanicName}.json", resultText); 518 | File.WriteAllText($@"{baseOutputPath}\Build\Mechanics\{mechanicName}.json", resultText); 519 | File.WriteAllText($@"{buildOutputPath}\Mechanics\{mechanicName}.json", resultText); 520 | 521 | $"Finished writing json to Mechanics/{mechanicName}.json".Dump(); -------------------------------------------------------------------------------- /Linqpad/MechanicSets/Grand Octet.linq: -------------------------------------------------------------------------------- 1 | 2 | C:\Users\exces\Desktop\XIV SIM\xiv-sim_Data\Managed\Assembly-CSharp.dll 3 | C:\Users\exces\Desktop\XIV SIM\xiv-sim_Data\Managed\UnityEngine.CoreModule.dll 4 | UnityEngine 5 | 6 | 7 | var buildOutputPath = @"C:\Users\exces\Desktop\XIV SIM\Mechanic Builds"; 8 | 9 | var mechanicName = "GrandOctetDemo"; 10 | var mechanicData = new MechanicData(); 11 | 12 | //Re-usable constants 13 | const int DIVE_WIDTH = 7; 14 | const float BOSS_DISTANCE = 7.5f; 15 | 16 | //Starting Parameters 17 | mechanicData.mechanicEvents = new List 18 | { 19 | new SpawnVisualObject 20 | { 21 | textureFilePath = "Mechanics/Resources/ArenaCircle.png", 22 | visualDuration = float.PositiveInfinity, 23 | relativePosition = new Vector3(0, -0.001f, 0), 24 | eulerAngles = new Vector3(90, 0, 0), 25 | scale = new Vector3(15.8637f, 15.8637f, 1), 26 | }, 27 | new SpawnMechanicEvent { referenceMechanicName = "ArenaBoundary" }, 28 | new WaitEvent { timeToWait = 1 }, 29 | 30 | new SpawnEnemy { 31 | enemyName = "Bahamut", 32 | textureFilePath = "Mechanics/Resources/Bahamut.png", 33 | colorHtml = "#0a4d8b", 34 | maxHp = 10000000, 35 | baseMoveSpeed = 0, 36 | hitboxSize = 3, 37 | visualPosition = new Vector3(0, 1.2f, 0), 38 | visualScale = new Vector3(1, 1.5f, 1) * 1.5f, 39 | referenceMechanicName = "BahamutStart", 40 | rotation = 180 41 | } 42 | }; 43 | 44 | 45 | mechanicData.referenceMechanicProperties = new Dictionary 46 | { 47 | //Modifiers 48 | { 49 | "Snapshot", 50 | new MechanicProperties 51 | { 52 | isTargeted = false, 53 | followSpeed = 0, 54 | } 55 | }, 56 | { 57 | "SetVisible", 58 | new MechanicProperties 59 | { 60 | visible = true 61 | } 62 | }, 63 | //Mechanics 64 | { 65 | "ArenaBoundary", 66 | new MechanicProperties 67 | { 68 | collisionShape = CollisionShape.Round, 69 | collisionShapeParams = new Vector4(25, 360, 7), 70 | colorHtml = "#8800FF", 71 | persistentTickInterval = 0.2f, 72 | persistentMechanic = new ApplyEffectToPlayers { effect = new DamageEffect { damageAmount = 9999999, damageType = "TrueDamage" } }, 73 | } 74 | }, 75 | { 76 | "BahamutStart", 77 | new MechanicProperties 78 | { 79 | visible = false, 80 | mechanic = new ExecuteMultipleEvents { 81 | events = new List { 82 | new WaitForAggro(), 83 | new ExecuteRandomEvents { mechanicPoolName = "RotationPool" }, 84 | new SpawnMechanicEvent { referenceMechanicName = "MechanicsPart2" }, 85 | 86 | new SetEnemyMovement { movementTime = -100, moveToTarget = new TargetNthHighestAggro() }, 87 | new StartCastBar { castName = "Grand Octet", duration = 4}, 88 | new WaitEvent { timeToWait = 6.5f }, 89 | new EndMechanic() 90 | } 91 | } 92 | } 93 | }, 94 | { 95 | "SpawnBosses", 96 | new MechanicProperties 97 | { 98 | visible = false, 99 | mechanic = new ExecuteMultipleEvents 100 | { 101 | events = new List 102 | { 103 | new ExecuteRandomEvents { mechanicPoolName = "OrderPool" }, 104 | new WaitEvent { timeToWait = 0.5f } 105 | } 106 | } 107 | } 108 | }, 109 | { 110 | "MechanicsPart2", 111 | new MechanicProperties { 112 | visible = false, 113 | mechanic = new ExecuteMultipleEvents 114 | { 115 | events = new List 116 | { 117 | new WaitEvent { timeToWait = 35.9f }, 118 | new ExecuteRandomEvents { mechanicPoolName = "TowerPool", numberToSpawn = 4}, 119 | new WaitEvent { timeToWait = 1 }, 120 | new SpawnTargetedEvents { referenceMechanicName = "MegaflareTarget", targetingScheme = new TargetRandomPlayers { totalTargetsNeeded = 4 } }, 121 | new WaitEvent { timeToWait = 4.6f }, 122 | new SpawnTargetedEvents 123 | { 124 | referenceMechanicName = "MegaflareStack", 125 | targetingScheme = new TargetRandomPlayers 126 | { 127 | numTargets = 0, // Get all players in a random order 128 | targetCondition = new CheckPlayerStatus { statusName = "MegaflareMark" }, // Filter to only players marked by megaflare 129 | totalTargetsNeeded = 1, // Select one of the players to place the stack on 130 | }, 131 | spawnOnTarget = true 132 | }, 133 | new WaitEvent { timeToWait = 2f }, 134 | new SpawnTargetedEvents { referenceMechanicName = "Twister", spawnOnTarget = true, targetingScheme = new TargetRandomPlayers { totalTargetsNeeded = 4 } }, 135 | } 136 | } 137 | } 138 | }, 139 | { 140 | "Tower", 141 | new MechanicProperties 142 | { 143 | collisionShape = CollisionShape.Round, 144 | collisionShapeParams = new Vector4(1, 360), 145 | colorHtml = "#FFFF00", 146 | mechanic = new ExecuteMultipleEvents 147 | { 148 | events = new List 149 | { 150 | new SpawnVisualObject { textureFilePath = "Mechanics/Resources/Tower.png", colorHtml = "#FFFF00", visualDuration = 7.8f, 151 | relativePosition = Vector3.up, scale = new Vector3(1, 1.9f, 1) * 0.6f, eulerAngles = new Vector3(0, 0, 0) }, 152 | new SpawnVisualObject { textureFilePath = "Mechanics/Resources/Tower.png", colorHtml = "#FFFF00", visualDuration = 7.8f, 153 | relativePosition = Vector3.up, scale = new Vector3(1, 1.9f, 1) * 0.6f, eulerAngles = new Vector3(0, 90, 0) }, 154 | new WaitEvent { timeToWait = 7.8f }, 155 | new CheckNumberOfPlayers 156 | { 157 | expressionFormat = "{0} >= 1", 158 | failEvent = new SpawnMechanicEvent { referenceMechanicName = "Tower Fail", isPositionRelative = true } 159 | }, 160 | new ApplyEffectToPlayers { 161 | effect = new DamageEffect { damageAmount = 10000, damageType = "Damage", name = "Megaflare" } 162 | } 163 | } 164 | } 165 | } 166 | }, 167 | { 168 | "Tower Fail", 169 | new MechanicProperties 170 | { 171 | collisionShape = CollisionShape.Round, 172 | collisionShapeParams = new Vector4(50, 360), 173 | colorHtml = "#FF0000", 174 | mechanic = new ExecuteMultipleEvents 175 | { 176 | events = new List 177 | { 178 | new WaitEvent { timeToWait = 0.2f }, 179 | new ApplyEffectToPlayers { 180 | effect = new DamageEffect { damageAmount = 200000, damageType = "Damage", name = "Tower Failed" } 181 | } 182 | } 183 | } 184 | } 185 | }, 186 | { 187 | "MegaflareTarget", 188 | new MechanicProperties 189 | { 190 | visible = false, 191 | mechanic = new ExecuteMultipleEvents 192 | { 193 | events = new List 194 | { 195 | new SpawnVisualObject { textureFilePath = "Mechanics/Resources/Mark1.png", colorHtml = "#ff4200", visualDuration = 4, 196 | spawnOnPlayer = true, relativePosition = Vector3.up * 0.8f, scale = new Vector3(0.5f, 0.5f, 1), isBillboard = true }, 197 | new ApplyEffectToTargetOnly { effect = new ApplyStatusEffect { referenceStatusName = "MegaflareMark" } } 198 | } 199 | }, 200 | } 201 | }, 202 | { 203 | "MegaflareStack", 204 | new MechanicProperties 205 | { 206 | collisionShape = CollisionShape.Round, 207 | collisionShapeParams = new Vector4(1.68f, 360), 208 | colorHtml = "#ff4200", 209 | isTargeted = true, 210 | followSpeed = 10000, 211 | visible = true, 212 | mechanic = new ExecuteMultipleEvents 213 | { 214 | events = new List 215 | { 216 | new ApplyEffectToPlayers { effect = new DamageEffect { damageAmount = 350000, damageType = "Damage", name = "Megaflare", maxStackAmount = 4 } } 217 | } 218 | } 219 | } 220 | }, 221 | { 222 | "Twister", 223 | new MechanicProperties 224 | { 225 | collisionShape = CollisionShape.Round, 226 | collisionShapeParams = new Vector4(0.25f, 360), 227 | colorHtml = "#008542", 228 | visible = false, 229 | isTargeted = true, 230 | followSpeed = 100, 231 | mechanic = new ExecuteMultipleEvents 232 | { 233 | events = new List 234 | { 235 | new ModifyMechanicEvent { referenceMechanicName = "Snapshot" }, 236 | new WaitEvent { timeToWait = 0.8f }, 237 | new ModifyMechanicEvent { referenceMechanicName = "SetVisible" }, 238 | new WaitEvent { timeToWait = 5 }, 239 | } 240 | }, 241 | persistentTickInterval = 0.1f, 242 | persistentActivationDelay = 1.6f, 243 | persistentMechanic = new ExecuteMultipleEvents 244 | { 245 | events = new List 246 | { 247 | new CheckNumberOfPlayers 248 | { 249 | expressionFormat = "{0} = 0", 250 | failEvent = new ExecuteMultipleEvents{ 251 | events = new List { 252 | new SpawnMechanicEvent { referenceMechanicName = "Twister Explode", isPositionRelative = true }, 253 | new EndMechanic() 254 | } 255 | } 256 | }, 257 | } 258 | }, 259 | } 260 | }, 261 | { 262 | "Twister Explode", 263 | new MechanicProperties 264 | { 265 | collisionShape = CollisionShape.Round, 266 | collisionShapeParams = new Vector4(3, 360), 267 | colorHtml = "#008542", 268 | mechanic = new ExecuteMultipleEvents 269 | { 270 | events = new List 271 | { 272 | new WaitEvent { timeToWait = 0.2f }, 273 | new ApplyEffectToPlayers { 274 | effects = new List { 275 | new DamageEffect { damageAmount = 90000, damageType = "Damage", name = "Twister" }, 276 | new KnockbackEffect { knockbackDistance = 10 }, 277 | } 278 | } 279 | } 280 | } 281 | } 282 | }, 283 | }; 284 | 285 | int targetID = 0; 286 | void addDiveMechanic(string boss, string bossColor, string markerColor, string diveColor, 287 | float spawnTime, float markerTime, float snapshotTime, float markerDuration, 288 | string damageText, bool extraDragons = false) 289 | { 290 | for (int i = 0; i <= (extraDragons ? 4 : 0); i++) 291 | { 292 | mechanicData.referenceMechanicProperties[boss + (extraDragons ? i : "")] = new MechanicProperties 293 | { 294 | visible = false, 295 | mechanic = new ExecuteMultipleEvents 296 | { 297 | events = new List 298 | { 299 | new WaitEvent { timeToWait = spawnTime }, 300 | new SpawnVisualObject() 301 | { 302 | textureFilePath = $"Mechanics/Resources/{boss}.png", 303 | colorHtml = bossColor, 304 | //The imprecise floats in JSON were bothering me, so I had to round some of these, sorry 305 | visualDuration = MathF.Round(snapshotTime - spawnTime + 2*i, 2), 306 | relativePosition = new Vector3(0, 1, -BOSS_DISTANCE), 307 | scale = new Vector3(1, 1, 1), 308 | eulerAngles = new Vector3(0, 180, 0), 309 | isRotationRelative = true 310 | }, 311 | new WaitEvent { timeToWait = MathF.Round(markerTime - spawnTime + 2*i, 2) }, 312 | new SpawnTargetedEvents 313 | { 314 | referenceMechanicName = $"{boss}Dive", 315 | position = new Vector2(0, -BOSS_DISTANCE), 316 | targetingScheme = new TargetSpecificPlayerIds { targetIds = new List { targetID++ } }, 317 | isPositionRelative = true, 318 | isRotationRelative = true 319 | } 320 | } 321 | } 322 | }; 323 | } 324 | 325 | mechanicData.referenceMechanicProperties[$"{boss}Dive"] = new MechanicProperties 326 | { 327 | collisionShape = CollisionShape.Rectangle, 328 | collisionShapeParams = new Vector4(16, DIVE_WIDTH), 329 | colorHtml = diveColor, 330 | visible = false, 331 | isTargeted = true, 332 | mechanic = new ExecuteMultipleEvents 333 | { 334 | events = new List 335 | { 336 | new SpawnVisualObject() 337 | { 338 | textureFilePath = "Mechanics/Resources/Mark1.png", 339 | colorHtml = markerColor, 340 | visualDuration = markerDuration, 341 | relativePosition = Vector3.up, 342 | spawnOnPlayer = true, 343 | scale = Vector3.one * 0.8f, 344 | isBillboard = true 345 | }, 346 | new WaitEvent { timeToWait = MathF.Round(snapshotTime - markerTime, 2) }, 347 | new SpawnVisualObject() 348 | { 349 | textureFilePath = $"Mechanics/Resources/{boss}.png", 350 | colorHtml = bossColor, 351 | visualDuration = 4, 352 | relativePosition = new Vector3(0, 1, 0), 353 | scale = new Vector3(1, 1, 1), 354 | eulerAngles = new Vector3(0, 180, 0), 355 | isRotationRelative = true 356 | }, 357 | new ModifyMechanicEvent { referenceMechanicName = "Snapshot" }, 358 | new WaitEvent { timeToWait = 4 }, 359 | new ModifyMechanicEvent { referenceMechanicName = "SetVisible" }, 360 | new ApplyEffectToPlayers { 361 | effects = new List { 362 | new DamageEffect { damageAmount = 90000, damageType = "Damage", name = damageText }, 363 | new KnockbackEffect { knockbackDistance = 10 }, 364 | } 365 | }, 366 | new WaitEvent { timeToWait = 0.5f } 367 | } 368 | } 369 | }; 370 | } 371 | 372 | addDiveMechanic(boss: "Nael", bossColor: "#a917bf", markerColor: "#c4c278", diveColor: "#c4c278", 373 | spawnTime: 8, markerTime: 12.4f, snapshotTime: 12.5f, markerDuration: 3, 374 | damageText: "Lunar Dive"); 375 | 376 | addDiveMechanic(boss: "Bahamut", bossColor: "#0a4d8b", markerColor: "#f07b22", diveColor: "#b81515", 377 | spawnTime: 8, markerTime: 29.6f, snapshotTime: 29.7f, markerDuration: 2.8f, 378 | damageText: "Megaflare Dive"); 379 | 380 | addDiveMechanic(boss: "Twintania", bossColor: "#067743", markerColor: "#32730a", diveColor: "#0a4d8b", 381 | spawnTime: 8, markerTime: 38.6f, snapshotTime: 38.7f, markerDuration: 3, 382 | damageText: "Twisting Dive"); 383 | 384 | addDiveMechanic(boss: "Dragon", bossColor: null, markerColor: "#32730a", diveColor: "#7d1876", 385 | spawnTime: 2.9f, markerTime: 12.5f, snapshotTime: 19.5f, markerDuration: 6.4f, 386 | damageText: "Cauterize", extraDragons: true); 387 | 388 | 389 | //Mechanic Pools 390 | mechanicData.mechanicPools = new Dictionary> 391 | { 392 | { 393 | "RotationPool", 394 | new List() 395 | { 396 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBosses", rotation = 0}, 397 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBosses", rotation = 90}, 398 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBosses", rotation = 180}, 399 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBosses", rotation = 270} 400 | } 401 | }, 402 | { "OrderPool", new List() }, 403 | { "TowerPool", new List() } 404 | }; 405 | foreach (int orientation in new [] { 1, -1 }) 406 | { 407 | //For the sake of a smaller file size, and better practice, I have opted to remove some easier patterns. 408 | //Otherwise these loops should be from 0 through 5, and from 0 through 6. 409 | for (int twin = 1; twin <= 5; twin++) 410 | { 411 | for (int nael = 2; nael <= 4; nael++) 412 | { 413 | var mech = new List { "Dragon0", "Dragon1", "Dragon2", "Dragon3", "Dragon4" }; 414 | mech.Insert(twin, "Twintania"); 415 | mech.Insert(nael, "Nael"); 416 | mech.Insert(0, "Bahamut"); 417 | var spawnEvents = new List(); 418 | for (int i = 0; i < 8; i++) 419 | { 420 | float a = ((orientation == 1 ? 1 : 0) + i * orientation) * Mathf.PI / 4; 421 | // Postion is now calculated within the boss mechanic to reduce OrderPool size in JSON 422 | // Removes 5 lines * 8 bosses * 2*5*3 order variations = -1200 lines from the JSON file 423 | //float x = MathF.Round(BOSS_DISTANCE * Mathf.Cos(3 * Mathf.PI / 2 - a), 3); 424 | //float y = MathF.Round(BOSS_DISTANCE * Mathf.Sin(3 * Mathf.PI / 2 - a), 3); 425 | spawnEvents.Add( 426 | new SpawnMechanicEvent 427 | { 428 | referenceMechanicName = mech[i], 429 | rotation = MathF.Round(a * Mathf.Rad2Deg), 430 | //position = new Vector2(x, y), 431 | //isPositionRelative = true, 432 | isRotationRelative = true 433 | } 434 | ); 435 | } 436 | mechanicData.mechanicPools["OrderPool"].Add(new ExecuteMultipleEvents { events = spawnEvents }); 437 | } 438 | } 439 | } 440 | for (int i = 0; i < 8; i++) 441 | { 442 | float a = i * Mathf.PI / 4; 443 | float x = MathF.Round(3.5f * Mathf.Cos(a), 3); 444 | float y = MathF.Round(3.5f * Mathf.Sin(a), 3); 445 | mechanicData.mechanicPools["TowerPool"].Add(new SpawnMechanicEvent { referenceMechanicName = "Tower", position = new Vector2(x, y) }); 446 | } 447 | 448 | 449 | //Status Effects 450 | mechanicData.referenceStatusProperties = new Dictionary 451 | { 452 | { 453 | "MegaflareMark", 454 | new StatusEffectData 455 | { 456 | statusName = "Marked for Megaflare", 457 | statusDescription = "Chosen to share the Megaflare stack.", 458 | duration = 7, 459 | } 460 | } 461 | }; 462 | 463 | 464 | var resultText = mechanicData.ToString(); 465 | File.WriteAllText($@"{buildOutputPath}\{mechanicName}.json", resultText); 466 | 467 | $"Finished writing json to {mechanicName}.json".Dump(); -------------------------------------------------------------------------------- /Linqpad/MechanicSets/HeavensfallDemo.linq: -------------------------------------------------------------------------------- 1 | 2 | D:\src\Unity\xiv-sim\Library\ScriptAssemblies\Assembly-CSharp.dll 3 | <ProgramFilesX64>\Unity\Hub\Editor\2020.3.6f1\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll 4 | UnityEngine 5 | 6 | 7 | var mechanicName = "HeavensfallDemo"; 8 | var baseOutputPath = $@"D:\src\Unity\xiv-sim"; 9 | var buildOutputPath = @"D:\src\Unity\xiv-sim-mechanics"; 10 | 11 | var mechanicData = new MechanicData(); 12 | 13 | mechanicData.referenceMechanicProperties = new Dictionary 14 | { 15 | { 16 | "Megaflare", 17 | new MechanicProperties 18 | { 19 | collisionShape = CollisionShape.Round, 20 | collisionShapeParams = new Vector4(2, 360), 21 | colorHtml = "#FF4400", 22 | mechanic = new ExecuteMultipleEvents 23 | { 24 | events = new List 25 | { 26 | new WaitEvent { timeToWait = 3 }, 27 | new ApplyEffectToPlayers { effect = new DamageEffect { damageAmount = 90000, damageType = "Damage", name = "Megaflare" } } 28 | } 29 | } 30 | } 31 | }, 32 | { 33 | "HeavensfallDeathZone", 34 | new MechanicProperties 35 | { 36 | collisionShape = CollisionShape.Rectangle, 37 | collisionShapeParams = new Vector4(2, 2.5f), 38 | colorHtml = "#0096ff", 39 | 40 | persistentTickInterval = 0.2f, 41 | persistentMechanic = new ApplyEffectToPlayers { effect = new DamageEffect { damageAmount = 9999999, damageType = "OutOfBounds" } }, 42 | mechanic = new WaitEvent {timeToWait = 10} 43 | } 44 | }, 45 | { 46 | "HeavensfallConeCW", 47 | new MechanicProperties 48 | { 49 | collisionShape = CollisionShape.Round, 50 | collisionShapeParams = new Vector4(7, 360 / 16f), 51 | colorHtml = "#FFFF00", 52 | mechanic = new ExecuteMultipleEvents 53 | { 54 | events = new List 55 | { 56 | new WaitEvent { timeToWait = 0.5f }, 57 | new CheckMechanicDepth 58 | { 59 | expressionFormat = "{0} < 9", 60 | successEvent = new SpawnMechanicEvent { referenceMechanicName = "HeavensfallConeCW", rotation = 360 / 16f, isRotationRelative = true } 61 | }, 62 | new WaitEvent { timeToWait = 2 }, 63 | new ApplyEffectToPlayers { 64 | effect = new DamageEffect { damageAmount = 90000, damageType = "Damage", name = "Heavensfall Cone" } 65 | } 66 | } 67 | } 68 | } 69 | }, 70 | { 71 | "HeavensfallConeInitialCW", 72 | new MechanicProperties 73 | { 74 | collisionShape = CollisionShape.Round, 75 | collisionShapeParams = new Vector4(7, 360 / 16f), 76 | colorHtml = "#FFFF00", 77 | mechanic = new ExecuteMultipleEvents 78 | { 79 | events = new List 80 | { 81 | new WaitEvent { timeToWait = 2 }, 82 | new SpawnMechanicEvent { referenceMechanicName = "HeavensfallConeCW", rotation = 360 / 16f, isRotationRelative = true }, 83 | new WaitEvent { timeToWait = 0.5f }, 84 | new ApplyEffectToPlayers { 85 | effect = new DamageEffect { damageAmount = 90000, damageType = "Damage", name = "Heavensfall Cone" } 86 | } 87 | } 88 | } 89 | } 90 | }, 91 | { 92 | "HeavensfallConeCCW", 93 | new MechanicProperties 94 | { 95 | collisionShape = CollisionShape.Round, 96 | collisionShapeParams = new Vector4(7, 360 / 16f), 97 | colorHtml = "#FFFF00", 98 | mechanic = new ExecuteMultipleEvents 99 | { 100 | events = new List 101 | { 102 | new WaitEvent { timeToWait = 0.5f }, 103 | new CheckMechanicDepth 104 | { 105 | expressionFormat = "{0} < 9", 106 | successEvent = new SpawnMechanicEvent { referenceMechanicName = "HeavensfallConeCCW", rotation = -360 / 16f, isRotationRelative = true } 107 | }, 108 | new WaitEvent { timeToWait = 2 }, 109 | new ApplyEffectToPlayers { 110 | effect = new DamageEffect { damageAmount = 90000, damageType = "Damage", name = "Heavensfall Cone" } 111 | } 112 | } 113 | } 114 | } 115 | }, 116 | { 117 | "HeavensfallConeInitialCCW", 118 | new MechanicProperties 119 | { 120 | collisionShape = CollisionShape.Round, 121 | collisionShapeParams = new Vector4(7, 360 / 16f), 122 | colorHtml = "#FFFF00", 123 | mechanic = new ExecuteMultipleEvents 124 | { 125 | events = new List 126 | { 127 | new WaitEvent { timeToWait = 2 }, 128 | new SpawnMechanicEvent { referenceMechanicName = "HeavensfallConeCCW", rotation = -360 / 16f, isRotationRelative = true }, 129 | new WaitEvent { timeToWait = 0.5f }, 130 | new ApplyEffectToPlayers { 131 | effect = new DamageEffect { damageAmount = 90000, damageType = "Damage", name = "Heavensfall Cone" } 132 | } 133 | } 134 | } 135 | } 136 | }, 137 | { 138 | "SpawnHeavensfallConesCW", 139 | new MechanicProperties 140 | { 141 | visible = false, 142 | mechanic = new ExecuteMultipleEvents 143 | { 144 | events = new List 145 | { 146 | new SpawnMechanicEvent { referenceMechanicName = "HeavensfallConeInitialCW", isRotationRelative = true }, 147 | new SpawnMechanicEvent { referenceMechanicName = "HeavensfallConeInitialCW", isRotationRelative = true, rotation = 180 }, 148 | } 149 | } 150 | } 151 | }, 152 | { 153 | "SpawnHeavensfallConesCCW", 154 | new MechanicProperties 155 | { 156 | visible = false, 157 | mechanic = new ExecuteMultipleEvents 158 | { 159 | events = new List 160 | { 161 | new SpawnMechanicEvent { referenceMechanicName = "HeavensfallConeInitialCCW", isRotationRelative = true }, 162 | new SpawnMechanicEvent { referenceMechanicName = "HeavensfallConeInitialCCW", isRotationRelative = true, rotation = 180 }, 163 | } 164 | } 165 | } 166 | }, 167 | { 168 | "SpawnHeavensfallCones", 169 | new MechanicProperties 170 | { 171 | visible = false, 172 | mechanic = new ExecuteMultipleEvents 173 | { 174 | events = new List 175 | { 176 | new ExecuteRandomEvents { mechanicPoolName = "HeavensfallConeDirectionPool" } 177 | } 178 | } 179 | } 180 | }, 181 | { 182 | "Mechanics-B", 183 | new MechanicProperties 184 | { 185 | collisionShape = CollisionShape.Rectangle, 186 | collisionShapeParams = new Vector4(14, 3), 187 | colorHtml = "#0a4d8b", 188 | mechanic = new ExecuteMultipleEvents 189 | { 190 | events = new List 191 | { 192 | new SpawnVisualObject { textureFilePath = "Mechanics/Resources/Bahamut.png", colorHtml = "#0a4d8b", visualDuration = 5, relativePosition = Vector3.up, scale = new Vector3(1, 1, 1), eulerAngles = new Vector3(0, 180, 0), isRotationRelative = true }, 193 | new WaitEvent { timeToWait = 5 }, 194 | new ApplyEffectToPlayers { 195 | effects = new List { 196 | new DamageEffect { damageAmount = 90000, damageType = "Damage", name = "Divebomb" }, 197 | new KnockbackEffect { knockbackDistance = 10 }, 198 | } 199 | } 200 | } 201 | } 202 | } 203 | }, 204 | { 205 | "Twister Explode", 206 | new MechanicProperties 207 | { 208 | collisionShape = CollisionShape.Round, 209 | collisionShapeParams = new Vector4(3, 360), 210 | colorHtml = "#008542", 211 | mechanic = new ExecuteMultipleEvents 212 | { 213 | events = new List 214 | { 215 | new WaitEvent { timeToWait = 0.2f }, 216 | new ApplyEffectToPlayers { 217 | effects = new List { 218 | new DamageEffect { damageAmount = 90000, damageType = "Damage", name = "Twister" }, 219 | new KnockbackEffect { knockbackDistance = 10 }, 220 | } 221 | } 222 | } 223 | } 224 | } 225 | }, 226 | { 227 | "TwisterSnapshot", 228 | new MechanicProperties 229 | { 230 | isTargeted = false, 231 | followSpeed = 0, 232 | } 233 | }, 234 | { 235 | "TwisterVisible", 236 | new MechanicProperties 237 | { 238 | visible = true, 239 | } 240 | }, 241 | { 242 | "Twister", 243 | new MechanicProperties 244 | { 245 | collisionShape = CollisionShape.Round, 246 | collisionShapeParams = new Vector4(0.25f, 360), 247 | colorHtml = "#008542", 248 | visible = false, 249 | isTargeted = true, 250 | followSpeed = 100, 251 | mechanic = new ExecuteMultipleEvents 252 | { 253 | events = new List 254 | { 255 | new WaitEvent { timeToWait = 1.5f }, 256 | new ModifyMechanicEvent { referenceMechanicName = "TwisterSnapshot" }, 257 | new WaitEvent { timeToWait = 0.5f }, 258 | new ModifyMechanicEvent { referenceMechanicName = "TwisterVisible" }, 259 | new WaitEvent { timeToWait = 5 }, 260 | } 261 | }, 262 | persistentTickInterval = 0.1f, 263 | persistentActivationDelay = 2.5f, 264 | persistentMechanic = new ExecuteMultipleEvents 265 | { 266 | events = new List 267 | { 268 | new CheckNumberOfPlayers 269 | { 270 | expressionFormat = "{0} = 0", 271 | failEvent = new ExecuteMultipleEvents{ 272 | events = new List { 273 | new SpawnMechanicEvent { referenceMechanicName = "Twister Explode", isPositionRelative = true }, 274 | new EndMechanic() 275 | } 276 | } 277 | }, 278 | } 279 | }, 280 | } 281 | }, 282 | { 283 | "Mechanics-T", 284 | new MechanicProperties 285 | { 286 | collisionShape = CollisionShape.Rectangle, 287 | collisionShapeParams = new Vector4(14, 3), 288 | colorHtml = "#067743", 289 | mechanic = new ExecuteMultipleEvents 290 | { 291 | events = new List 292 | { 293 | new SpawnVisualObject { textureFilePath = "Mechanics/Resources/Twintania.png", colorHtml = "#067743", visualDuration = 5, relativePosition = Vector3.up, scale = new Vector3(1, 1, 1), eulerAngles = new Vector3(0, 180, 0), isRotationRelative = true }, 294 | new WaitEvent { timeToWait = 3 }, 295 | new SpawnTargetedEvents 296 | { 297 | referenceMechanicName = "Twister", 298 | spawnOnTarget = true, 299 | targetingScheme = new TargetSpecificPlayerIds { targetIds = new List {0, 1, 2, 3 }, dropExtraEvents = true} 300 | }, 301 | new WaitEvent { timeToWait = 2 }, 302 | new ApplyEffectToPlayers 303 | { 304 | effects = new List 305 | { 306 | new DamageEffect { damageAmount = 90000, damageType = "Damage", name = "Divebomb" }, 307 | new KnockbackEffect { knockbackDistance = 10 }, 308 | } 309 | } 310 | } 311 | } 312 | } 313 | }, 314 | { 315 | "Hypernova", 316 | new MechanicProperties 317 | { 318 | collisionShape = CollisionShape.Round, 319 | collisionShapeParams = new Vector4(1.5f, 360), 320 | colorHtml = "#352a43", 321 | mechanic = new ExecuteMultipleEvents 322 | { 323 | events = new List 324 | { 325 | new ApplyEffectToPlayers { effect = new DamageEffect { damageAmount = 10000, damageType = "Damage", name = "Hypernova" } }, 326 | new WaitEvent { timeToWait = 10 }, 327 | } 328 | }, 329 | 330 | persistentTickInterval = 0.3f, 331 | persistentActivationDelay = 2, 332 | persistentMechanic = new ApplyEffectToPlayers { effect = new DamageEffect { damageAmount = 999999, damageType = "Damage", name = "Bleed" } }, 333 | } 334 | }, 335 | { 336 | "Mechanics-N", 337 | new MechanicProperties 338 | { 339 | visible = false, 340 | mechanic = new ExecuteMultipleEvents 341 | { 342 | events = new List 343 | { 344 | new SpawnVisualObject { textureFilePath = "Mechanics/Resources/Nael.png", colorHtml = "#a917bf", visualDuration = 15, relativePosition = Vector3.up, scale = new Vector3(1, 1, 1), eulerAngles = new Vector3(0, 180, 0), isRotationRelative = true }, 345 | new WaitEvent { timeToWait = 15 }, 346 | new SpawnTargetedEvents {referenceMechanicName = "Hypernova", spawnOnTarget = true, targetingScheme = new TargetRandomPlayers() }, 347 | new WaitEvent { timeToWait = 1 }, 348 | new SpawnTargetedEvents {referenceMechanicName = "Hypernova", spawnOnTarget = true, targetingScheme = new TargetRandomPlayers() }, 349 | new WaitEvent { timeToWait = 1 }, 350 | new SpawnTargetedEvents {referenceMechanicName = "Hypernova", spawnOnTarget = true, targetingScheme = new TargetRandomPlayers() }, 351 | new WaitEvent { timeToWait = 1 }, 352 | new SpawnTargetedEvents {referenceMechanicName = "Hypernova", spawnOnTarget = true, targetingScheme = new TargetRandomPlayers() }, 353 | new SpawnTargetedEvents {referenceMechanicName = "Fireball", spawnOnTarget = true, targetingScheme = new TargetRandomPlayers() }, 354 | } 355 | } 356 | } 357 | }, 358 | { 359 | "FireballVisible", 360 | new MechanicProperties 361 | { 362 | visible = true, 363 | } 364 | }, 365 | { 366 | "Fireball", 367 | new MechanicProperties 368 | { 369 | collisionShape = CollisionShape.Round, 370 | collisionShapeParams = new Vector4(1, 360), 371 | colorHtml = "#ff4200", 372 | isTargeted = true, 373 | followSpeed = 10000, 374 | visible = false, 375 | mechanic = new ExecuteMultipleEvents 376 | { 377 | events = new List 378 | { 379 | new SpawnVisualObject { textureFilePath = "Mechanics/Resources/Mark1.png", colorHtml = "#ff4200", visualDuration = 5, spawnOnPlayer = true, relativePosition = Vector3.up * 0.8f, scale = new Vector3(0.5f, 0.5f, 1), eulerAngles = new Vector3(0, 0, 0) }, 380 | new SpawnVisualObject { textureFilePath = "Mechanics/Resources/Mark1.png", colorHtml = "#ff4200", visualDuration = 5, spawnOnPlayer = true, relativePosition = Vector3.up * 0.8f, scale = new Vector3(0.5f, 0.5f, 1), eulerAngles = new Vector3(0, 90, 0) }, 381 | new WaitEvent { timeToWait = 4 }, 382 | new ModifyMechanicEvent { referenceMechanicName = "FireballVisible" }, 383 | new ApplyEffectToPlayers { effect = new DamageEffect { damageAmount = 600000, damageType = "Damage", name = "Fireball", maxStackAmount = 8 } }, 384 | } 385 | } 386 | } 387 | }, 388 | { 389 | "SpawnBosses", 390 | new MechanicProperties 391 | { 392 | visible = false, 393 | mechanic = new ExecuteMultipleEvents 394 | { 395 | events = new List 396 | { 397 | new ExecuteRandomEvents { mechanicPoolName = "DivebombPool" }, 398 | } 399 | } 400 | } 401 | }, 402 | { 403 | "KnockbackFromCenter", 404 | new MechanicProperties 405 | { 406 | collisionShape = CollisionShape.Round, 407 | collisionShapeParams = new Vector4(15, 360), 408 | visible = false, 409 | mechanic = new ExecuteMultipleEvents 410 | { 411 | events = new List 412 | { 413 | new ApplyEffectToPlayers { 414 | effects = new List { 415 | new DamageEffect { damageAmount = 10000, damageType = "Damage", name = "Heavensfall" }, 416 | new KnockbackEffect { knockbackDistance = 4 }, 417 | } 418 | } 419 | } 420 | } 421 | } 422 | }, 423 | { 424 | "Tower Fail", 425 | new MechanicProperties 426 | { 427 | collisionShape = CollisionShape.Round, 428 | collisionShapeParams = new Vector4(50, 360), 429 | colorHtml = "#FF0000", 430 | mechanic = new ExecuteMultipleEvents 431 | { 432 | events = new List 433 | { 434 | new WaitEvent { timeToWait = 0.2f }, 435 | new ApplyEffectToPlayers { 436 | effect = new DamageEffect { damageAmount = 9999999, damageType = "Damage", name = "Tower Failed" } 437 | } 438 | } 439 | } 440 | } 441 | }, 442 | { 443 | "Tower", 444 | new MechanicProperties 445 | { 446 | collisionShape = CollisionShape.Round, 447 | collisionShapeParams = new Vector4(0.75f, 360), 448 | colorHtml = "#FFFF00", 449 | mechanic = new ExecuteMultipleEvents 450 | { 451 | events = new List 452 | { 453 | new SpawnVisualObject { textureFilePath = "Mechanics/Resources/Tower.png", colorHtml = "#FFFF00", visualDuration = 8, relativePosition = Vector3.up, scale = new Vector3(1, 1.8876f, 1) * 0.6f, eulerAngles = new Vector3(0, 0, 0) }, 454 | new SpawnVisualObject { textureFilePath = "Mechanics/Resources/Tower.png", colorHtml = "#FFFF00", visualDuration = 8, relativePosition = Vector3.up, scale = new Vector3(1, 1.8876f, 1) * 0.6f, eulerAngles = new Vector3(0, 90, 0) }, 455 | new WaitEvent { timeToWait = 8 }, 456 | new CheckNumberOfPlayers 457 | { 458 | expressionFormat = "{0} = 1", 459 | failEvent = new SpawnMechanicEvent { referenceMechanicName = "Tower Fail", isPositionRelative = true } 460 | }, 461 | new ApplyEffectToPlayers { 462 | effect = new DamageEffect { damageAmount = 10000, damageType = "Damage", name = "Megaflare" } 463 | } 464 | } 465 | } 466 | } 467 | }, 468 | { 469 | "ArenaBoundary", 470 | new MechanicProperties 471 | { 472 | collisionShape = CollisionShape.Round, 473 | collisionShapeParams = new Vector4(15, 360, 7), 474 | colorHtml = "#8800FF", 475 | 476 | persistentTickInterval = 0.2f, 477 | persistentMechanic = new ApplyEffectToPlayers { effect = new DamageEffect { damageAmount = 9999999, damageType = "OutOfBounds" } }, 478 | } 479 | } 480 | }; 481 | 482 | mechanicData.mechanicPools = new Dictionary>(); 483 | 484 | var divebombPool = new List(); 485 | mechanicData.mechanicPools["DivebombPool"] = divebombPool; 486 | 487 | foreach (var spawnCombo in new List { "TNB", "TBN", "BNT", "BTN", "NTB", "NBT" }) 488 | { 489 | var divebombsToSpawn = new ExecuteMultipleEvents(); 490 | divebombsToSpawn.events = new List(); 491 | 492 | var angleOffset = 0f; 493 | 494 | if (spawnCombo[0] == 'N') { 495 | angleOffset = 7.5f; 496 | } 497 | else if (spawnCombo[2] == 'N') { 498 | angleOffset = -7.5f; 499 | } 500 | 501 | for (int i = -1; i <= 1; i++) 502 | { 503 | float a = (30 * i + angleOffset) * Mathf.Deg2Rad; 504 | float x = 7 * Mathf.Cos(a); 505 | float y = 7 * Mathf.Sin(a); 506 | 507 | var spawnId = spawnCombo[i + 1]; 508 | 509 | divebombsToSpawn.events.Add(new SpawnMechanicEvent { referenceMechanicName = $"Mechanics-{spawnId}", position = new Vector2(x, y), rotation = -90 - a * Mathf.Rad2Deg, isPositionRelative = true, isRotationRelative = true }); 510 | } 511 | 512 | mechanicData.referenceMechanicProperties[$"Mechanics-{spawnCombo}"] = new MechanicProperties 513 | { 514 | visible = false, 515 | mechanic = divebombsToSpawn 516 | }; 517 | 518 | divebombPool.Add(new SpawnMechanicEvent { referenceMechanicName = $"Mechanics-{spawnCombo}", isPositionRelative = true, isRotationRelative = true }); 519 | } 520 | 521 | var bossRotationPool = new List(); 522 | mechanicData.mechanicPools["SpawnBossesRotationPool"] = bossRotationPool; 523 | 524 | var heavensfallTowerPool = new List(); 525 | mechanicData.mechanicPools["HeavensfallTowerPool"] = heavensfallTowerPool; 526 | 527 | var heavensfallConePool = new List(); 528 | mechanicData.mechanicPools["HeavensfallConePool"] = heavensfallConePool; 529 | 530 | for (int i = 0; i < 16; i++) 531 | { 532 | float a = 2 * Mathf.PI / 16 * i; 533 | float x = 7 * Mathf.Cos(a); 534 | float y = 7 * Mathf.Sin(a); 535 | bossRotationPool.Add(new SpawnMechanicEvent { referenceMechanicName = "SpawnBosses", rotation = a * Mathf.Rad2Deg }); 536 | heavensfallConePool.Add(new SpawnMechanicEvent { referenceMechanicName = "SpawnHeavensfallCones", rotation = a * Mathf.Rad2Deg }); 537 | heavensfallTowerPool.Add(new SpawnMechanicEvent { referenceMechanicName = "Tower", position = new Vector2(x, y) }); 538 | } 539 | 540 | var heavensfallConeDirectionPool = new List(); 541 | mechanicData.mechanicPools["HeavensfallConeDirectionPool"] = new List 542 | { 543 | new SpawnMechanicEvent { referenceMechanicName = "SpawnHeavensfallConesCW" }, 544 | new SpawnMechanicEvent { referenceMechanicName = "SpawnHeavensfallConesCCW" } 545 | }; 546 | 547 | var mechanicSequence = new List{ 548 | new WaitEvent {timeToWait = 3}, 549 | new ExecuteRandomEvents { mechanicPoolName = "SpawnBossesRotationPool"}, 550 | new WaitEvent {timeToWait = 5}, 551 | new ExecuteRandomEvents { mechanicPoolName = "HeavensfallTowerPool", numberToSpawn = 8}, 552 | new WaitEvent {timeToWait = 1}, 553 | new ReshufflePlayerIds(), 554 | new SpawnTargetedEvents { referenceMechanicName = "Megaflare", spawnOnTarget = true, targetingScheme = new TargetSpecificPlayerIds { targetIds = new List { 0, 1, 2, 3 } } }, 555 | new WaitEvent {timeToWait = 4}, 556 | new SpawnMechanicEvent { referenceMechanicName = "KnockbackFromCenter"}, 557 | new SpawnMechanicEvent { referenceMechanicName = "HeavensfallDeathZone", position = new Vector2(0, -1)}, 558 | new WaitEvent {timeToWait = 3}, 559 | new ExecuteRandomEvents { mechanicPoolName = "HeavensfallConePool"}, 560 | }; 561 | 562 | mechanicData.mechanicEvents = new List 563 | { 564 | new SpawnVisualObject 565 | { 566 | textureFilePath = "Mechanics/Resources/ArenaCircle.png", 567 | visualDuration = float.PositiveInfinity, 568 | relativePosition = new Vector3(0, -0.001f, 0), 569 | eulerAngles = new Vector3(90, 0, 0), 570 | scale = new Vector3(15.8637f, 15.8637f, 1), 571 | }, 572 | new SpawnMechanicEvent { referenceMechanicName = "ArenaBoundary" }, 573 | new ExecuteMultipleEvents { events = mechanicSequence } 574 | }; 575 | 576 | var resultText = mechanicData.ToString(); 577 | 578 | File.WriteAllText($@"{baseOutputPath}\Mechanics\{mechanicName}.json", resultText); 579 | File.WriteAllText($@"{baseOutputPath}\Build\Mechanics\{mechanicName}.json", resultText); 580 | File.WriteAllText($@"{buildOutputPath}\Mechanics\{mechanicName}.json", resultText); 581 | 582 | $"Finished writing json to Mechanics/{mechanicName}.json".Dump(); -------------------------------------------------------------------------------- /Linqpad/MechanicSets/LimitCutDemo.linq: -------------------------------------------------------------------------------- 1 | 2 | D:\src\Unity\xiv-sim\Library\ScriptAssemblies\Assembly-CSharp.dll 3 | <ProgramFilesX64>\Unity\Hub\Editor\2020.3.6f1\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll 4 | UnityEngine 5 | 6 | 7 | var mechanicName = "LimitCutDemo"; 8 | var baseOutputPath = @"D:\src\Unity\xiv-sim"; 9 | var buildOutputPath = @"D:\src\Unity\xiv-sim-mechanics"; 10 | 11 | var mechanicData = new MechanicData(); 12 | 13 | var hawkBlasterGap = 2.2f; 14 | 15 | var limitcutGap = 1.8f; 16 | var alphaSwordDelay = 1.0f; 17 | var blasstyChargeDelay = 1.7f; 18 | 19 | mechanicData.referenceMechanicProperties = new Dictionary 20 | { 21 | { 22 | "HawkBlasterSequence", 23 | new MechanicProperties 24 | { 25 | visible = false, 26 | mechanic = new ExecuteMultipleEvents 27 | { 28 | events = new List 29 | { 30 | new SpawnMechanicEvent { referenceMechanicName = "HawkBlasterOffset", isRotationRelative = true }, 31 | new SpawnMechanicEvent { referenceMechanicName = "HawkBlasterOffset", isRotationRelative = true, rotation = 180 }, 32 | new WaitEvent { timeToWait = hawkBlasterGap }, 33 | new SpawnMechanicEvent { referenceMechanicName = "HawkBlasterOffset", isRotationRelative = true, rotation = 45 }, 34 | new SpawnMechanicEvent { referenceMechanicName = "HawkBlasterOffset", isRotationRelative = true, rotation = 225 }, 35 | new WaitEvent { timeToWait = hawkBlasterGap }, 36 | new SpawnMechanicEvent { referenceMechanicName = "HawkBlasterOffset", isRotationRelative = true, rotation = 90 }, 37 | new SpawnMechanicEvent { referenceMechanicName = "HawkBlasterOffset", isRotationRelative = true, rotation = 270 }, 38 | new WaitEvent { timeToWait = hawkBlasterGap }, 39 | new SpawnMechanicEvent { referenceMechanicName = "HawkBlasterOffset", isRotationRelative = true, rotation = 135 }, 40 | new SpawnMechanicEvent { referenceMechanicName = "HawkBlasterOffset", isRotationRelative = true, rotation = 315 }, 41 | new WaitEvent { timeToWait = hawkBlasterGap }, 42 | new SpawnMechanicEvent { referenceMechanicName = "HawkBlaster" }, 43 | new WaitEvent { timeToWait = hawkBlasterGap }, 44 | new SpawnMechanicEvent { referenceMechanicName = "HawkBlasterOffset", isRotationRelative = true }, 45 | new SpawnMechanicEvent { referenceMechanicName = "HawkBlasterOffset", isRotationRelative = true, rotation = 180 }, 46 | new WaitEvent { timeToWait = hawkBlasterGap }, 47 | new SpawnMechanicEvent { referenceMechanicName = "HawkBlasterOffset", isRotationRelative = true, rotation = 45 }, 48 | new SpawnMechanicEvent { referenceMechanicName = "HawkBlasterOffset", isRotationRelative = true, rotation = 225 }, 49 | new WaitEvent { timeToWait = hawkBlasterGap }, 50 | new SpawnMechanicEvent { referenceMechanicName = "HawkBlasterOffset", isRotationRelative = true, rotation = 90 }, 51 | new SpawnMechanicEvent { referenceMechanicName = "HawkBlasterOffset", isRotationRelative = true, rotation = 270 }, 52 | new WaitEvent { timeToWait = hawkBlasterGap }, 53 | new SpawnMechanicEvent { referenceMechanicName = "HawkBlasterOffset", isRotationRelative = true, rotation = 135 }, 54 | new SpawnMechanicEvent { referenceMechanicName = "HawkBlasterOffset", isRotationRelative = true, rotation = 315 }, 55 | new WaitEvent { timeToWait = hawkBlasterGap }, 56 | new SpawnMechanicEvent { referenceMechanicName = "HawkBlaster" }, 57 | } 58 | } 59 | } 60 | }, 61 | { 62 | "HawkBlasterOffset", 63 | new MechanicProperties 64 | { 65 | visible = false, 66 | mechanic = new SpawnMechanicEvent { referenceMechanicName = "HawkBlaster", position = new Vector2(4.75f, 0), isPositionRelative = true, isRotationRelative = true } 67 | } 68 | }, 69 | { 70 | "HawkBlaster", 71 | new MechanicProperties 72 | { 73 | collisionShapeParams = new Vector4(3.3333f, 360), 74 | visible = false, 75 | mechanic = new ExecuteMultipleEvents 76 | { 77 | events = new List 78 | { 79 | new ApplyEffectToPlayers 80 | { 81 | effects = new List 82 | { 83 | new DamageEffect {damageAmount = 400000, damageType = "Magic", name = "Hawk Blaster" }, 84 | new ApplyStatusEffect { referenceStatusName = "MagicVuln" } 85 | } 86 | }, 87 | new WaitEvent { timeToWait = 1 }, 88 | new SpawnMechanicEvent { referenceMechanicName = "HawkBlasterVisual", isPositionRelative = true } 89 | } 90 | } 91 | } 92 | }, 93 | { 94 | "HawkBlasterVisual", 95 | new MechanicProperties 96 | { 97 | collisionShapeParams = new Vector4(3.3333f, 360), 98 | colorHtml = "#ff5a00", 99 | visible = true, 100 | mechanic = new WaitEvent { timeToWait = 0.2f }, 101 | } 102 | }, 103 | { 104 | "Spawn-CruiseChaser-LC", 105 | new MechanicProperties 106 | { 107 | visible = false, 108 | mechanic = new SpawnEnemy 109 | { 110 | enemyName = "Cruise Chaser", 111 | textureFilePath = "Mechanics/Resources/CruiseChaser.png", 112 | colorHtml = "#8b4800", 113 | maxHp = int.MaxValue, 114 | baseMoveSpeed = 2, 115 | hitboxSize = 2, 116 | visualPosition = new Vector3(0, 1, 0), 117 | visualScale = Vector3.one * 2, 118 | referenceMechanicName = "LimitCutSequence", 119 | isTargetable = false, 120 | showInEnemyList = false, 121 | isVisible = false, 122 | }, 123 | } 124 | }, 125 | { 126 | "LimitCutSequence", 127 | new MechanicProperties 128 | { 129 | visible = false, 130 | mechanic = new ExecuteMultipleEvents 131 | { 132 | events = new List 133 | { 134 | new SpawnTargetedEvents { referenceMechanicName = "LimitCutMarker-1", targetingScheme = new TargetSpecificPlayerIds { targetIds = new List{0}, dropExtraEvents = true } }, 135 | new SpawnTargetedEvents { referenceMechanicName = "LimitCutMarker-2", targetingScheme = new TargetSpecificPlayerIds { targetIds = new List{1}, dropExtraEvents = true } }, 136 | new SpawnTargetedEvents { referenceMechanicName = "LimitCutMarker-3", targetingScheme = new TargetSpecificPlayerIds { targetIds = new List{2}, dropExtraEvents = true } }, 137 | new SpawnTargetedEvents { referenceMechanicName = "LimitCutMarker-4", targetingScheme = new TargetSpecificPlayerIds { targetIds = new List{3}, dropExtraEvents = true } }, 138 | new SpawnTargetedEvents { referenceMechanicName = "LimitCutMarker-5", targetingScheme = new TargetSpecificPlayerIds { targetIds = new List{4}, dropExtraEvents = true } }, 139 | new SpawnTargetedEvents { referenceMechanicName = "LimitCutMarker-6", targetingScheme = new TargetSpecificPlayerIds { targetIds = new List{5}, dropExtraEvents = true } }, 140 | new SpawnTargetedEvents { referenceMechanicName = "LimitCutMarker-7", targetingScheme = new TargetSpecificPlayerIds { targetIds = new List{6}, dropExtraEvents = true } }, 141 | new SpawnTargetedEvents { referenceMechanicName = "LimitCutMarker-8", targetingScheme = new TargetSpecificPlayerIds { targetIds = new List{7}, dropExtraEvents = true } }, 142 | new WaitEvent { timeToWait = 2 }, 143 | new ExecuteRandomEvents { mechanicPoolName = "Hawkblaster-Pool" }, 144 | new WaitEvent { timeToWait = 6 }, 145 | new SetEnemyMovement { movementTime = 0.01f, moveToTarget = new TargetSpecificPlayerIds { targetIds = new List{0} }, position = new Vector3(0, -1) }, 146 | new WaitEvent { timeToWait = 0.01f }, 147 | new SetEnemyMovement { movementTime = -1, moveToTarget =new TargetSpecificPlayerIds { targetIds = new List{0} } }, 148 | new SetEnemyVisible { visible = true }, 149 | new WaitEvent { timeToWait = alphaSwordDelay }, 150 | new SpawnTargetedEvents { referenceMechanicName = "AlphaSword", isPositionRelative = true, targetingScheme = new TargetSpecificPlayerIds { targetIds = new List {0} } }, 151 | new WaitEvent { timeToWait = blasstyChargeDelay }, 152 | new SpawnTargetedEvents { referenceMechanicName = "BlasstyCharge", isPositionRelative = true, targetingScheme = new TargetSpecificPlayerIds { targetIds = new List {1} } }, 153 | new SetEnemyVisible { visible = false }, 154 | 155 | new WaitEvent { timeToWait = limitcutGap }, 156 | new SetEnemyMovement { movementTime = 0.01f, moveToTarget = new TargetSpecificPlayerIds { targetIds = new List{2} }, position = new Vector3(0, -1) }, 157 | new WaitEvent { timeToWait = 0.01f }, 158 | new SetEnemyMovement { movementTime = -1, moveToTarget =new TargetSpecificPlayerIds { targetIds = new List{2} } }, 159 | new SetEnemyVisible { visible = true }, 160 | new WaitEvent { timeToWait = alphaSwordDelay }, 161 | new SpawnTargetedEvents { referenceMechanicName = "AlphaSword", isPositionRelative = true, targetingScheme = new TargetSpecificPlayerIds { targetIds = new List {2} } }, 162 | new WaitEvent { timeToWait = blasstyChargeDelay }, 163 | new SpawnTargetedEvents { referenceMechanicName = "BlasstyCharge", isPositionRelative = true, targetingScheme = new TargetSpecificPlayerIds { targetIds = new List {3} } }, 164 | new SetEnemyVisible { visible = false }, 165 | 166 | new WaitEvent { timeToWait = limitcutGap }, 167 | new SetEnemyMovement { movementTime = 0.01f, moveToTarget = new TargetSpecificPlayerIds { targetIds = new List{4} }, position = new Vector3(0, -1) }, 168 | new WaitEvent { timeToWait = 0.01f }, 169 | new SetEnemyMovement { movementTime = -1, moveToTarget =new TargetSpecificPlayerIds { targetIds = new List{4} } }, 170 | new SetEnemyVisible { visible = true }, 171 | new WaitEvent { timeToWait = alphaSwordDelay }, 172 | new SpawnTargetedEvents { referenceMechanicName = "AlphaSword", isPositionRelative = true, targetingScheme = new TargetSpecificPlayerIds { targetIds = new List {4} } }, 173 | new WaitEvent { timeToWait = blasstyChargeDelay }, 174 | new SpawnTargetedEvents { referenceMechanicName = "BlasstyCharge", isPositionRelative = true, targetingScheme = new TargetSpecificPlayerIds { targetIds = new List {5} } }, 175 | new SetEnemyVisible { visible = false }, 176 | 177 | new WaitEvent { timeToWait = limitcutGap }, 178 | new SetEnemyMovement { movementTime = 0.01f, moveToTarget = new TargetSpecificPlayerIds { targetIds = new List{6} }, position = new Vector3(0, -1) }, 179 | new WaitEvent { timeToWait = 0.01f }, 180 | new SetEnemyMovement { movementTime = -1, moveToTarget =new TargetSpecificPlayerIds { targetIds = new List{6} } }, 181 | new SetEnemyVisible { visible = true }, 182 | new WaitEvent { timeToWait = alphaSwordDelay }, 183 | new SpawnTargetedEvents { referenceMechanicName = "AlphaSword", isPositionRelative = true, targetingScheme = new TargetSpecificPlayerIds { targetIds = new List {6} } }, 184 | new WaitEvent { timeToWait = blasstyChargeDelay }, 185 | new SpawnTargetedEvents { referenceMechanicName = "BlasstyCharge", isPositionRelative = true, targetingScheme = new TargetSpecificPlayerIds { targetIds = new List {7} } }, 186 | new SetEnemyVisible { visible = false }, 187 | } 188 | } 189 | } 190 | }, 191 | { 192 | "SetVisible", 193 | new MechanicProperties { 194 | visible = true, 195 | } 196 | }, 197 | { 198 | "AlphaSword", 199 | new MechanicProperties 200 | { 201 | collisionShapeParams = new Vector4(10, 90), 202 | colorHtml = "#ffff00", 203 | visible = true, 204 | isTargeted = true, 205 | mechanic = new ExecuteMultipleEvents 206 | { 207 | events = new List 208 | { 209 | new WaitEvent { timeToWait = 0.2f }, 210 | new ApplyEffectToPlayers 211 | { 212 | effects = new List 213 | { 214 | new DamageEffect {damageAmount = 50000, damageType = "Physical", name = "Alpha Sword" }, 215 | new ApplyStatusEffect { referenceStatusName = "MagicVuln" }, 216 | new ApplyStatusEffect { referenceStatusName = "PhysVuln" }, 217 | new KnockbackEffect { knockbackDistance = 2, canArmsLength = true } 218 | } 219 | } 220 | } 221 | } 222 | } 223 | }, 224 | { 225 | "BlasstyCharge", 226 | new MechanicProperties 227 | { 228 | collisionShape = CollisionShape.Rectangle, 229 | collisionShapeParams = new Vector4(40, 3.33f), 230 | colorHtml = "#ffff00", 231 | isTargeted = true, 232 | visible = true, 233 | mechanic = new ExecuteMultipleEvents 234 | { 235 | events = new List 236 | { 237 | new WaitEvent { timeToWait = 0.2f }, 238 | new ApplyEffectToPlayers 239 | { 240 | condition = new CheckPlayerFacingAway(), 241 | effects = new List 242 | { 243 | new DamageEffect {damageAmount = 45000, damageType = "Physical", name = "Super Blassty Charge" }, 244 | new ApplyStatusEffect { referenceStatusName = "MagicVuln" }, 245 | new ApplyStatusEffect { referenceStatusName = "PhysVuln" }, 246 | new KnockbackEffect { knockbackDistance = 10, canArmsLength = true } 247 | }, 248 | failedConditionEffects = new List 249 | { 250 | new DamageEffect {damageAmount = 45000, damageType = "Physical", name = "Super Blassty Charge" }, 251 | new ApplyStatusEffect { referenceStatusName = "MagicVuln" }, 252 | new ApplyStatusEffect { referenceStatusName = "PhysVuln" }, 253 | }, 254 | } 255 | } 256 | } 257 | } 258 | }, 259 | { 260 | "ArenaBoundary", 261 | new MechanicProperties 262 | { 263 | collisionShape = CollisionShape.Round, 264 | collisionShapeParams = new Vector4(25, 360, 6.6667f), 265 | colorHtml = "#8800FF", 266 | persistentTickInterval = 0.2f, 267 | persistentMechanic = new ApplyEffectToPlayers { effect = new DamageEffect { damageAmount = 9999999, damageType = "TrueDamage" } }, 268 | } 269 | }, 270 | }; 271 | 272 | for (int i = 1; i <= 8; i++) 273 | { 274 | var scale = Vector3.one * 0.5f; 275 | if (i == 5) { 276 | scale = new Vector3(1.78f, 1, 1) * 0.5f; 277 | } 278 | else if (i > 5) 279 | { 280 | scale = new Vector3(2.16f, 1, 1) * 0.5f; 281 | } 282 | mechanicData.referenceMechanicProperties[$"LimitCutMarker-{i}"] = new MechanicProperties { 283 | visible = false, 284 | mechanic = new SpawnVisualObject { 285 | textureFilePath = $"Mechanics/Resources/LimitCut-{i}.png", 286 | colorHtml = i % 2 == 0 ? "#ff0000" : "#0000ff", 287 | visualDuration = 8, 288 | scale = scale, 289 | relativePosition = Vector3.up, 290 | isBillboard = true, 291 | spawnOnPlayer = true, 292 | } 293 | }; 294 | } 295 | 296 | mechanicData.referenceStatusProperties = new Dictionary 297 | { 298 | { 299 | "MagicVuln", 300 | new DamageModifier 301 | { 302 | statusIconPath = "Mechanics/Resources/MagicVuln.png", 303 | statusName = "Magic Vulnerability Up", 304 | statusDescription = "Magic damage taken is increased.", 305 | damageType = "Magic", 306 | damageMultiplier = 8, 307 | duration = 10, 308 | } 309 | }, 310 | { 311 | "PhysVuln", 312 | new DamageModifier 313 | { 314 | statusIconPath = "Mechanics/Resources/PhysVuln.png", 315 | statusName = "Physical Vulnerability Up", 316 | statusDescription = "Physical damage taken is increased.", 317 | damageType = "Physical", 318 | damageMultiplier = 8, 319 | duration = 17, 320 | } 321 | } 322 | }; 323 | 324 | mechanicData.mechanicEvents = new List 325 | { 326 | new SpawnMechanicEvent { referenceMechanicName = "ArenaBoundary" }, 327 | new SpawnVisualObject 328 | { 329 | textureFilePath = "Mechanics/Resources/ArenaCircle.png", 330 | visualDuration = float.PositiveInfinity, 331 | relativePosition = new Vector3(0, -0.001f, 0), 332 | eulerAngles = new Vector3(90, 0, 0), 333 | scale = new Vector3(15.1082f, 15.1082f, 1), 334 | }, 335 | new ExecuteMultipleEvents 336 | { 337 | events = new List 338 | { 339 | new WaitEvent { timeToWait = 2}, 340 | new SpawnMechanicEvent { referenceMechanicName = "Spawn-CruiseChaser-LC" }, 341 | } 342 | } 343 | }; 344 | mechanicData.mechanicPools = new Dictionary> 345 | { 346 | { 347 | "Hawkblaster-Pool", 348 | new List 349 | { 350 | new SpawnMechanicEvent { referenceMechanicName = "HawkBlasterSequence"}, 351 | new SpawnMechanicEvent { referenceMechanicName = "HawkBlasterSequence", rotation = 45 }, 352 | new SpawnMechanicEvent { referenceMechanicName = "HawkBlasterSequence", rotation = 90 }, 353 | new SpawnMechanicEvent { referenceMechanicName = "HawkBlasterSequence", rotation = 135 }, 354 | } 355 | }, 356 | }; 357 | 358 | var resultText = mechanicData.ToString(); 359 | 360 | File.WriteAllText($@"{baseOutputPath}\Mechanics\{mechanicName}.json", resultText); 361 | File.WriteAllText($@"{baseOutputPath}\Build\Mechanics\{mechanicName}.json", resultText); 362 | File.WriteAllText($@"{buildOutputPath}\Mechanics\{mechanicName}.json", resultText); 363 | 364 | $"Finished writing json to Mechanics/{mechanicName}.json".Dump(); -------------------------------------------------------------------------------- /Linqpad/MechanicSets/Quickmarch.linq: -------------------------------------------------------------------------------- 1 | 2 | D:\src\Unity\xiv-sim\Library\ScriptAssemblies\Assembly-CSharp.dll 3 | <ProgramFilesX64>\Unity\Hub\Editor\2020.3.6f1\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll 4 | UnityEngine 5 | 6 | 7 | var mechanicName = "QuickmarchDemo"; 8 | var baseOutputPath = @"D:\src\Unity\xiv-sim"; 9 | var buildOutputPath = @"D:\src\Unity\xiv-sim-mechanics"; 10 | 11 | var mechanicData = new MechanicData(); 12 | 13 | mechanicData.referenceMechanicProperties = new Dictionary 14 | { 15 | { 16 | "BahaDive", 17 | new MechanicProperties 18 | { 19 | collisionShape = CollisionShape.Rectangle, 20 | collisionShapeParams = new Vector4(14, 4), 21 | colorHtml = "#0a4d8b", 22 | visible = false, 23 | mechanic = new ExecuteMultipleEvents 24 | { 25 | events = new List 26 | { 27 | new SpawnVisualObject { textureFilePath = "Mechanics/Resources/Bahamut.png", colorHtml = "#0a4d8b", visualDuration = 5, relativePosition = Vector3.up, scale = new Vector3(1, 1, 1), eulerAngles = new Vector3(0, 180, 0), isRotationRelative = true }, 28 | new WaitEvent { timeToWait = 4.3f }, 29 | new ModifyMechanicEvent { referenceMechanicName = "SetVisible" }, 30 | new WaitEvent { timeToWait = 0.2f }, 31 | new ApplyEffectToPlayers { 32 | effects = new List { 33 | new DamageEffect { damageAmount = 90000, damageType = "Damage", name = "Megaflare Dive" }, 34 | new KnockbackEffect { knockbackDistance = 10 }, 35 | } 36 | } 37 | } 38 | } 39 | } 40 | }, 41 | { 42 | "NaelDive", 43 | new MechanicProperties 44 | { 45 | collisionShape = CollisionShape.Rectangle, 46 | collisionShapeParams = new Vector4(14, 4), 47 | colorHtml = "#a917bf", 48 | visible = false, 49 | mechanic = new ExecuteMultipleEvents 50 | { 51 | events = new List 52 | { 53 | new SpawnVisualObject { textureFilePath = "Mechanics/Resources/Nael.png", colorHtml = "#a917bf", visualDuration = 5, relativePosition = Vector3.up, scale = new Vector3(1, 1, 1), eulerAngles = new Vector3(0, 180, 0), isRotationRelative = true }, 54 | new WaitEvent { timeToWait = 4.3f }, 55 | new ModifyMechanicEvent { referenceMechanicName = "SetVisible" }, 56 | new WaitEvent { timeToWait = 0.2f }, 57 | new ApplyEffectToPlayers { 58 | effects = new List { 59 | new DamageEffect { damageAmount = 90000, damageType = "Damage", name = "Raven Dive" }, 60 | new KnockbackEffect { knockbackDistance = 10 }, 61 | } 62 | } 63 | } 64 | } 65 | } 66 | }, 67 | { 68 | "TwinDive", 69 | new MechanicProperties 70 | { 71 | collisionShape = CollisionShape.Rectangle, 72 | collisionShapeParams = new Vector4(14, 4), 73 | colorHtml = "#067743", 74 | visible = false, 75 | mechanic = new ExecuteMultipleEvents 76 | { 77 | events = new List 78 | { 79 | new SpawnVisualObject { textureFilePath = "Mechanics/Resources/Twintania.png", colorHtml = "#067743", visualDuration = 5, relativePosition = Vector3.up, scale = new Vector3(1, 1, 1), eulerAngles = new Vector3(0, 180, 0), isRotationRelative = true }, 80 | new WaitEvent { timeToWait = 4.3f }, 81 | new ModifyMechanicEvent { referenceMechanicName = "SetVisible" }, 82 | new WaitEvent { timeToWait = 0.2f }, 83 | new ApplyEffectToPlayers { 84 | effects = new List { 85 | new DamageEffect { damageAmount = 90000, damageType = "Damage", name = "Twisting Dive" }, 86 | new KnockbackEffect { knockbackDistance = 10 }, 87 | } 88 | } 89 | } 90 | } 91 | } 92 | }, 93 | { 94 | "Twister Explode", 95 | new MechanicProperties 96 | { 97 | collisionShape = CollisionShape.Round, 98 | collisionShapeParams = new Vector4(3, 360), 99 | colorHtml = "#008542", 100 | mechanic = new ExecuteMultipleEvents 101 | { 102 | events = new List 103 | { 104 | new WaitEvent { timeToWait = 0.2f }, 105 | new ApplyEffectToPlayers { 106 | effects = new List { 107 | new DamageEffect { damageAmount = 90000, damageType = "Damage", name = "Twister" }, 108 | new KnockbackEffect { knockbackDistance = 10 }, 109 | } 110 | } 111 | } 112 | } 113 | } 114 | }, 115 | { 116 | "TwisterSnapshot", 117 | new MechanicProperties 118 | { 119 | isTargeted = false, 120 | followSpeed = 0, 121 | } 122 | }, 123 | { 124 | "Twister", 125 | new MechanicProperties 126 | { 127 | collisionShape = CollisionShape.Round, 128 | collisionShapeParams = new Vector4(0.25f, 360), 129 | colorHtml = "#008542", 130 | visible = false, 131 | isTargeted = true, 132 | followSpeed = 100, 133 | mechanic = new ExecuteMultipleEvents 134 | { 135 | events = new List 136 | { 137 | new WaitEvent { timeToWait = 1.5f }, 138 | new ModifyMechanicEvent { referenceMechanicName = "TwisterSnapshot" }, 139 | new WaitEvent { timeToWait = 0.5f }, 140 | new ModifyMechanicEvent { referenceMechanicName = "SetVisible" }, 141 | new WaitEvent { timeToWait = 5 }, 142 | } 143 | }, 144 | persistentTickInterval = 0.1f, 145 | persistentActivationDelay = 2.5f, 146 | persistentMechanic = new ExecuteMultipleEvents 147 | { 148 | events = new List 149 | { 150 | new CheckNumberOfPlayers 151 | { 152 | expressionFormat = "{0} = 0", 153 | failEvent = new ExecuteMultipleEvents{ 154 | events = new List { 155 | new SpawnMechanicEvent { referenceMechanicName = "Twister Explode", isPositionRelative = true }, 156 | new EndMechanic() 157 | } 158 | } 159 | }, 160 | } 161 | }, 162 | } 163 | }, 164 | { 165 | "Megaflare", 166 | new MechanicProperties 167 | { 168 | visible = false, 169 | mechanic = new ExecuteMultipleEvents 170 | { 171 | events = new List 172 | { 173 | new SpawnTargetedEvents { referenceMechanicName = "MegaflarePuddles", spawnOnTarget = true, targetingScheme = new TargetSpecificPlayerIds { targetIds = new List { 0, 1, 2, 3 } } }, 174 | new ReshufflePlayerIds(), 175 | new SpawnTargetedEvents { referenceMechanicName = "MegaflareStrikePending", spawnOnTarget = true, targetingScheme = new TargetSpecificPlayerIds { targetIds = new List { 0, 1, 2, 3 } } }, 176 | new ReshufflePlayerIds(), 177 | new SpawnTargetedEvents { referenceMechanicName = "MegaflareTarget", targetingScheme = new TargetSpecificPlayerIdsByClass { classType = PlayerClassType.Dps, targetIds = new List {0, 1, 2} } }, 178 | new SpawnTargetedEvents { referenceMechanicName = "MegaflareStack", targetingScheme = new TargetSpecificPlayerIdsByClass { classType = PlayerClassType.Dps, targetIds = new List {0} } }, 179 | new SpawnTargetedEvents { referenceMechanicName = "MegaflareStackFake", targetingScheme = new TargetSpecificPlayerIdsByClass { classType = PlayerClassType.Dps, targetIds = new List {1, 2} } } 180 | } 181 | } 182 | } 183 | }, 184 | { 185 | "MegaflareTarget", 186 | new MechanicProperties 187 | { 188 | visible = false, 189 | mechanic = new ApplyEffectToTargetOnly 190 | { 191 | effect = new ApplyStatusEffect { referenceStatusName = "MegaflareMark" } 192 | } 193 | } 194 | }, 195 | { 196 | "MegaflarePuddles", 197 | new MechanicProperties 198 | { 199 | collisionShape = CollisionShape.Round, 200 | collisionShapeParams = new Vector4(2, 360), 201 | colorHtml = "#FF4400", 202 | mechanic = new ExecuteMultipleEvents 203 | { 204 | events = new List 205 | { 206 | new WaitEvent { timeToWait = 3 }, 207 | new ApplyEffectToPlayers { effect = new DamageEffect { damageAmount = 90000, damageType = "Damage", name = "Megaflare Puddle" } } 208 | } 209 | } 210 | } 211 | }, 212 | { 213 | "MegaflareStack", 214 | new MechanicProperties 215 | { 216 | collisionShape = CollisionShape.Round, 217 | collisionShapeParams = new Vector4(1, 360), 218 | colorHtml = "#ff4200", 219 | isTargeted = true, 220 | followSpeed = 10000, 221 | visible = false, 222 | mechanic = new ExecuteMultipleEvents 223 | { 224 | events = new List 225 | { 226 | new SpawnVisualObject { textureFilePath = "Mechanics/Resources/Mark1.png", colorHtml = "#ff4200", visualDuration = 4, spawnOnPlayer = true, relativePosition = Vector3.up * 0.8f, scale = new Vector3(0.5f, 0.5f, 1), eulerAngles = new Vector3(0, 0, 0) }, 227 | new WaitEvent { timeToWait = 5 }, 228 | new ModifyMechanicEvent { referenceMechanicName = "SetVisible" }, 229 | new ApplyEffectToPlayers { 230 | condition = new CheckPlayerStatus 231 | { 232 | statusName = "Marked for Megaflare", 233 | }, 234 | effects = new List 235 | { 236 | new DamageEffect { damageAmount = 200000, damageType = "Damage", name = "Megaflare Stack", maxStackAmount = 3 }, 237 | new RemoveStatusEffect { referenceStatusName = "MegaflareMark" } 238 | }, 239 | failedConditionEffects = new List 240 | { 241 | new DamageEffect { damageAmount = 200000, damageType = "Damage", name = "Megaflare Stack" } 242 | } 243 | }, 244 | } 245 | } 246 | } 247 | }, 248 | { 249 | "MegaflareStackFake", 250 | new MechanicProperties 251 | { 252 | isTargeted = true, 253 | followSpeed = 10000, 254 | visible = false, 255 | mechanic = new ExecuteMultipleEvents 256 | { 257 | events = new List 258 | { 259 | new SpawnVisualObject { textureFilePath = "Mechanics/Resources/Mark1.png", colorHtml = "#ff4200", visualDuration = 4, spawnOnPlayer = true, relativePosition = Vector3.up * 0.8f, scale = new Vector3(0.5f, 0.5f, 1), eulerAngles = new Vector3(0, 0, 0) }, 260 | new WaitEvent { timeToWait = 5 } 261 | } 262 | } 263 | } 264 | }, 265 | { 266 | "MegaflareStrikePending" , 267 | new MechanicProperties 268 | { 269 | collisionShape = CollisionShape.Round, 270 | collisionShapeParams = new Vector4(1.5f, 360), 271 | colorHtml = "#dcdcdc", 272 | isTargeted = true, 273 | visible = false, 274 | mechanic = new ExecuteMultipleEvents 275 | { 276 | events = new List 277 | { 278 | new WaitEvent { timeToWait = 1 }, 279 | new SpawnTargetedEvents { referenceMechanicName = "MegaflareStrike", spawnOnTarget = true, targetingScheme = new TargetExistingTarget() } 280 | } 281 | } 282 | } 283 | }, 284 | { 285 | "MegaflareStrike" , 286 | new MechanicProperties 287 | { 288 | collisionShape = CollisionShape.Round, 289 | collisionShapeParams = new Vector4(1.5f, 360), 290 | colorHtml = "#dcdcdc", 291 | isTargeted = true, 292 | visible = false, 293 | mechanic = new ExecuteMultipleEvents 294 | { 295 | events = new List 296 | { 297 | new ModifyMechanicEvent { referenceMechanicName = "SetVisible" }, 298 | new WaitEvent { timeToWait = 0.2f }, 299 | new ApplyEffectToPlayers { 300 | effect = new DamageEffect { damageAmount = 80000, damageType = "Damage", name = "Megaflare AoE" } 301 | } 302 | } 303 | } 304 | } 305 | }, 306 | { 307 | "SetVisible", 308 | new MechanicProperties 309 | { 310 | visible = true 311 | } 312 | }, 313 | { 314 | "Earthshaker", 315 | new MechanicProperties 316 | { 317 | collisionShape = CollisionShape.Round, 318 | collisionShapeParams = new Vector4(20, 90), 319 | colorHtml = "#c78825", 320 | isTargeted = true, 321 | visible = false, 322 | mechanic = new ExecuteMultipleEvents 323 | { 324 | events = new List 325 | { 326 | new SpawnVisualObject { textureFilePath = "Mechanics/Resources/Mark1.png", colorHtml = "#f0ba00", visualDuration = 6, spawnOnPlayer = true, relativePosition = Vector3.up * 0.6f, scale = new Vector3(0.8f, 0.8f, 1), isBillboard = true }, 327 | new WaitEvent { timeToWait = 4.8f }, 328 | new ModifyMechanicEvent { referenceMechanicName = "SetVisible" }, 329 | new WaitEvent { timeToWait = 0.2f }, 330 | new ApplyEffectToPlayers { 331 | effects = new List 332 | { 333 | new DamageEffect { damageAmount = 80000, damageType = "Physical", name = "Earthshaker" }, 334 | new ApplyStatusEffect { referenceStatusName = "PhysVuln" }, 335 | }, 336 | }, 337 | new SpawnTargetedEvents { referenceMechanicName = "EarthshakerPuddle", spawnOnTarget = true, targetingScheme = new TargetExistingTarget() } 338 | } 339 | } 340 | } 341 | }, 342 | { 343 | "EarthshakerPuddle", 344 | new MechanicProperties 345 | { 346 | collisionShape = CollisionShape.Round, 347 | collisionShapeParams = new Vector4(1.5f, 360), 348 | colorHtml = "#c78825", 349 | mechanic = new WaitEvent { timeToWait = 10 }, 350 | persistentTickInterval = 0.3f, 351 | persistentActivationDelay = 2, 352 | persistentMechanic = new ApplyEffectToPlayers { effect = new DamageEffect { damageAmount = 300000, damageType = "Physical", name = "Sludge" } }, 353 | } 354 | }, 355 | { 356 | "ArenaBoundary", 357 | new MechanicProperties 358 | { 359 | collisionShape = CollisionShape.Round, 360 | collisionShapeParams = new Vector4(25, 360, 7), 361 | colorHtml = "#8800FF", 362 | persistentTickInterval = 0.2f, 363 | persistentMechanic = new ApplyEffectToPlayers { effect = new DamageEffect { damageAmount = 9999999, damageType = "TrueDamage" } }, 364 | } 365 | }, 366 | { 367 | "TetherAoe" , 368 | new MechanicProperties 369 | { 370 | collisionShape = CollisionShape.Round, 371 | collisionShapeParams = new Vector4(1.5f, 360), 372 | colorHtml = "#59ce85", 373 | mechanic = new ExecuteMultipleEvents 374 | { 375 | events = new List 376 | { 377 | new WaitEvent { timeToWait = 0.2f }, 378 | new ApplyEffectToPlayers { 379 | condition = new CheckPlayerIsMechanicTarget(), 380 | effects = new List 381 | { 382 | new DamageEffect { damageAmount = 120000, damageType = "Damage", name = "Tempest Wing" }, 383 | }, 384 | failedConditionEffects = new List 385 | { 386 | new DamageEffect { damageAmount = 120000, damageType = "Damage", name = "Tempest Wing" }, 387 | new KnockbackEffect { knockbackDistance = 10}, 388 | } 389 | } 390 | } 391 | } 392 | } 393 | }, 394 | { 395 | "SpawnBosses", 396 | new MechanicProperties 397 | { 398 | visible = false, 399 | mechanic = new ExecuteMultipleEvents 400 | { 401 | events = new List 402 | { 403 | new SpawnMechanicEvent { referenceMechanicName = "BahaDive", isPositionRelative = true, isRotationRelative = true }, 404 | new SpawnMechanicEvent { referenceMechanicName = "TwinDive", position = new Vector3(-2.5f, 0, 0), isPositionRelative = true, isRotationRelative = true }, 405 | new SpawnMechanicEvent { referenceMechanicName = "NaelDive", position = new Vector3(2.5f, 0, 0), isPositionRelative = true, isRotationRelative = true } 406 | } 407 | } 408 | } 409 | }, 410 | { 411 | "SpawnCenterBahamut", 412 | new MechanicProperties 413 | { 414 | visible = false, 415 | mechanic = new ExecuteMultipleEvents 416 | { 417 | events = new List 418 | { 419 | new SpawnEnemy { 420 | enemyName = "Bahamut", 421 | textureFilePath = "Mechanics/Resources/Bahamut.png", 422 | colorHtml = "#0a4d8b", 423 | maxHp = 35000000, 424 | baseMoveSpeed = 2, 425 | hitboxSize = 2, 426 | visualPosition = new Vector3(0, 1, 0), 427 | visualScale = Vector3.one, 428 | referenceMechanicName = "BahamutMechanics", 429 | position = new Vector2(0, 0), 430 | rotation = 180, 431 | isRotationRelative = true, 432 | isTargetable = false, 433 | } 434 | } 435 | } 436 | } 437 | }, 438 | { 439 | "BahamutMechanics", 440 | new MechanicProperties 441 | { 442 | visible = false, 443 | mechanic = new ExecuteMultipleEvents 444 | { 445 | events = new List 446 | { 447 | new WaitEvent { timeToWait = 0.5f }, 448 | new SpawnTargetedEvents { referenceMechanicName = "Earthshaker", targetingScheme = new TargetSpecificPlayerIdsByClass { classType = PlayerClassType.Healer, targetIds = new List {0, 1} } }, 449 | new SpawnTargetedEvents { referenceMechanicName = "Earthshaker", targetingScheme = new TargetSpecificPlayerIdsByClass { classType = PlayerClassType.Dps, targetIds = new List {3} } }, 450 | new WaitEvent { timeToWait = 1 }, 451 | new SpawnTethersToPlayers { referenceTetherName = "TempestWing", tetherOffset = new Vector3(0, 1, 0), targetingScheme = new TargetSpecificPlayerIds { targetIds = new List {0, 1} } }, 452 | new WaitEvent { timeToWait = 6 }, 453 | new SpawnTargetedEvents { referenceMechanicName = "TetherAoe", targetingScheme = new TargetTetheredPlayers(), spawnOnTarget = true }, 454 | new WaitEvent {timeToWait = float.PositiveInfinity } 455 | } 456 | } 457 | } 458 | }, 459 | }; 460 | 461 | mechanicData.referenceTetherProperties = new Dictionary 462 | { 463 | { 464 | "TempestWing", 465 | new TetherProperties 466 | { 467 | colorHtml = "#00ff60", 468 | tetherDuration = 7, 469 | interceptMechanic = new SwitchTetheredPlayer(), 470 | oneTetherPerPlayer = true, 471 | tetherTag = "TempestWing", 472 | retargetRandomPlayerOnDeath = true 473 | } 474 | }, 475 | }; 476 | 477 | mechanicData.referenceStatusProperties = new Dictionary 478 | { 479 | { 480 | "PhysVuln", 481 | new DamageModifier 482 | { 483 | statusIconPath = "Mechanics/Resources/PhysVuln.png", 484 | statusName = "Physical Vulnerability Up", 485 | statusDescription = "Physical damage taken is increased.", 486 | damageType = "Physical", 487 | damageMultiplier = 10, 488 | duration = 16, 489 | } 490 | }, 491 | { 492 | "MegaflareMark", 493 | new StatusEffectData 494 | { 495 | statusName = "Marked for Megaflare", 496 | statusDescription = "Chosen to share the Megaflare stack.", 497 | duration = 7, 498 | } 499 | } 500 | }; 501 | 502 | mechanicData.mechanicPools = new Dictionary>(); 503 | var startPool = new List(); 504 | mechanicData.mechanicPools["StartPool"] = startPool; 505 | 506 | for (int i = 0; i < 8; i++) 507 | { 508 | float a = 2 * Mathf.PI / 8 * i; 509 | float x = 7 * Mathf.Cos(3 * Mathf.PI / 2 - a); 510 | float y = 7 * Mathf.Sin(3 * Mathf.PI / 2 - a); 511 | startPool.Add(new SpawnMechanicEvent { referenceMechanicName = "SpawnBosses", rotation = a * Mathf.Rad2Deg, position = new Vector2(x, y), isPositionRelative = true, isRotationRelative = true }); 512 | } 513 | 514 | var mechanicSequence = new List{ 515 | new WaitEvent {timeToWait = 2}, 516 | new ExecuteRandomEvents { mechanicPoolName = "StartPool"}, 517 | new WaitEvent {timeToWait = 3.5f}, 518 | new ReshufflePlayerIds(), 519 | new SpawnTargetedEvents { referenceMechanicName = "Twister", spawnOnTarget = true, targetingScheme = new TargetSpecificPlayerIds { targetIds = new List { 0, 1, 2, 3 } } }, 520 | new WaitEvent {timeToWait = 3}, 521 | new ReshufflePlayerIds(), 522 | new SpawnMechanicEvent { referenceMechanicName = "Megaflare" }, 523 | new WaitEvent {timeToWait = 2}, 524 | new SpawnMechanicEvent { referenceMechanicName = "SpawnCenterBahamut"}, 525 | }; 526 | 527 | mechanicData.mechanicEvents = new List 528 | { 529 | new SpawnVisualObject 530 | { 531 | textureFilePath = "Mechanics/Resources/ArenaCircle.png", 532 | visualDuration = float.PositiveInfinity, 533 | relativePosition = new Vector3(0, -0.001f, 0), 534 | eulerAngles = new Vector3(90, 0, 0), 535 | scale = new Vector3(15.8637f, 15.8637f, 1), 536 | }, 537 | new SpawnMechanicEvent { referenceMechanicName = "ArenaBoundary" }, 538 | new ExecuteMultipleEvents { events = mechanicSequence } 539 | }; 540 | 541 | var resultText = mechanicData.ToString(); 542 | 543 | File.WriteAllText($@"{baseOutputPath}\Mechanics\{mechanicName}.json", resultText); 544 | File.WriteAllText($@"{baseOutputPath}\Build\Mechanics\{mechanicName}.json", resultText); 545 | File.WriteAllText($@"{buildOutputPath}\Mechanics\{mechanicName}.json", resultText); 546 | 547 | $"Finished writing json to Mechanics/{mechanicName}.json".Dump(); -------------------------------------------------------------------------------- /Linqpad/MechanicSets/TenstrikeDemo.linq: -------------------------------------------------------------------------------- 1 | 2 | D:\src\Unity\xiv-sim\Library\ScriptAssemblies\Assembly-CSharp.dll 3 | <ProgramFilesX64>\Unity\Hub\Editor\2020.3.6f1\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll 4 | UnityEngine 5 | 6 | 7 | var mechanicName = "TenstrikeDemo"; 8 | var baseOutputPath = @"D:\src\Unity\xiv-sim"; 9 | var buildOutputPath = @"D:\src\Unity\xiv-sim-mechanics"; 10 | 11 | var mechanicData = new MechanicData(); 12 | 13 | mechanicData.referenceMechanicProperties = new Dictionary 14 | { 15 | { 16 | "TwintaniaMechanics", 17 | new MechanicProperties 18 | { 19 | visible = false, 20 | mechanic = new ExecuteMultipleEvents 21 | { 22 | events = new List 23 | { 24 | new WaitEvent {timeToWait = float.PositiveInfinity } 25 | } 26 | } 27 | } 28 | }, 29 | { 30 | "NaelMechanics", 31 | new MechanicProperties 32 | { 33 | visible = false, 34 | mechanic = new ExecuteMultipleEvents 35 | { 36 | events = new List 37 | { 38 | new WaitEvent {timeToWait = 1}, 39 | new ExecuteRandomEventSequence { mechanicPoolName = "Quote-Pool" }, 40 | new WaitEvent {timeToWait = 7}, 41 | new ReshufflePlayerIds(), 42 | new SpawnTargetedEvents { referenceMechanicName = "SpreadAoe", spawnOnTarget = true, targetingScheme = new TargetSpecificPlayerIds {targetIds = new List{0, 1, 2, 3} } }, 43 | new WaitEvent {timeToWait = float.PositiveInfinity } 44 | } 45 | } 46 | } 47 | }, 48 | { 49 | "Neurolink", 50 | new MechanicProperties 51 | { 52 | collisionShape = CollisionShape.Round, 53 | collisionShapeParams = new Vector4(0.4f, 360), 54 | colorHtml = "#9cff00", 55 | 56 | persistentTickInterval = 0.2f, 57 | persistentMechanic = new ApplyEffectToPlayers { effect = new ApplyStatusEffect { referenceStatusName = "Neurolink" } }, 58 | } 59 | }, 60 | { 61 | "HatchMove", 62 | new MechanicProperties { 63 | followSpeed = 1.2f, 64 | } 65 | }, 66 | { 67 | "Hatch", 68 | new MechanicProperties 69 | { 70 | collisionShape = CollisionShape.Round, 71 | collisionShapeParams = new Vector4(0.4f, 360), 72 | colorHtml = "#a800ff", 73 | isTargeted = true, 74 | followSpeed = 0, 75 | mechanic = new ExecuteMultipleEvents 76 | { 77 | events = new List 78 | { 79 | new WaitEvent { timeToWait = 3 }, 80 | new ModifyMechanicEvent { referenceMechanicName = "HatchMove" }, 81 | new WaitEvent { timeToWait = 20 }, 82 | new SpawnMechanicEvent { referenceMechanicName = "HatchExplode", isPositionRelative = true }, 83 | } 84 | }, 85 | persistentTickInterval = 0.1f, 86 | persistentActivationDelay = 1, 87 | persistentMechanic = new CheckNumberOfPlayers 88 | { 89 | expressionFormat = "{0} = 0", 90 | failEvent = new CheckNumberOfPlayers { 91 | expressionFormat = "{0} = 1", 92 | condition = new CheckPlayerStatus { statusName = "Neurolink" }, 93 | successEvent = new ExecuteMultipleEvents{ 94 | events = new List { 95 | new SpawnMechanicEvent { referenceMechanicName = "HatchPopped", isPositionRelative = true }, 96 | new EndMechanic() 97 | } 98 | }, 99 | failEvent = new ExecuteMultipleEvents{ 100 | events = new List { 101 | new SpawnMechanicEvent { referenceMechanicName = "HatchExplode", isPositionRelative = true }, 102 | new EndMechanic() 103 | } 104 | } 105 | } 106 | }, 107 | } 108 | }, 109 | { 110 | "HatchPopped", 111 | new MechanicProperties 112 | { 113 | collisionShape = CollisionShape.Round, 114 | collisionShapeParams = new Vector4(2, 360), 115 | colorHtml = "#a800ff", 116 | mechanic = new ExecuteMultipleEvents 117 | { 118 | events = new List 119 | { 120 | new WaitEvent { timeToWait = 0.2f }, 121 | new ApplyEffectToPlayers { 122 | condition = new CheckPlayerStatus 123 | { 124 | statusName = "Neurolink", 125 | }, 126 | effects = new List 127 | { 128 | new DamageEffect { damageAmount = 30000, damageType = "Magic", name = "Hatch" }, 129 | new ApplyStatusEffect { referenceStatusName = "MagicVuln" } 130 | }, 131 | failedConditionEffects = new List 132 | { 133 | new DamageEffect { damageAmount = 300000, damageType = "Magic", name = "Hatch" }, 134 | new ApplyStatusEffect { referenceStatusName = "MagicVuln" } 135 | } 136 | } 137 | } 138 | } 139 | } 140 | }, 141 | { 142 | "HatchExplode", 143 | new MechanicProperties 144 | { 145 | collisionShape = CollisionShape.Round, 146 | collisionShapeParams = new Vector4(50, 360), 147 | colorHtml = "#a800ff", 148 | mechanic = new ExecuteMultipleEvents 149 | { 150 | events = new List 151 | { 152 | new WaitEvent { timeToWait = 0.2f }, 153 | new ApplyEffectToPlayers { 154 | effects = new List 155 | { 156 | new DamageEffect { damageAmount = 9999999, damageType = "TrueDamage", name = "Deep Hatch" }, 157 | } 158 | } 159 | } 160 | } 161 | } 162 | }, 163 | { 164 | "SpreadAoe" , 165 | new MechanicProperties 166 | { 167 | collisionShape = CollisionShape.Round, 168 | collisionShapeParams = new Vector4(1.5f, 360), 169 | colorHtml = "#dcdcdc", 170 | mechanic = new ExecuteMultipleEvents 171 | { 172 | events = new List 173 | { 174 | new WaitEvent { timeToWait = 0.2f }, 175 | new ApplyEffectToPlayers { 176 | effect = new DamageEffect { damageAmount = 80000, damageType = "Damage", name = "Meteor Stream" } 177 | } 178 | } 179 | } 180 | } 181 | }, 182 | { 183 | "SetVisible", 184 | new MechanicProperties 185 | { 186 | visible = true 187 | } 188 | }, 189 | { 190 | "Earthshaker", 191 | new MechanicProperties 192 | { 193 | collisionShape = CollisionShape.Round, 194 | collisionShapeParams = new Vector4(20, 90), 195 | colorHtml = "#c78825", 196 | isTargeted = true, 197 | visible = false, 198 | mechanic = new ExecuteMultipleEvents 199 | { 200 | events = new List 201 | { 202 | new SpawnVisualObject { textureFilePath = "Mechanics/Resources/Mark1.png", colorHtml = "#f0ba00", visualDuration = 6, spawnOnPlayer = true, relativePosition = Vector3.up * 0.6f, scale = new Vector3(0.8f, 0.8f, 1), isBillboard = true }, 203 | new WaitEvent { timeToWait = 5.8f }, 204 | new ModifyMechanicEvent { referenceMechanicName = "SetVisible" }, 205 | new WaitEvent { timeToWait = 0.2f }, 206 | new ApplyEffectToPlayers { 207 | effects = new List 208 | { 209 | new DamageEffect { damageAmount = 80000, damageType = "Physical", name = "Earthshaker" }, 210 | new ApplyStatusEffect { referenceStatusName = "PhysVuln" }, 211 | }, 212 | }, 213 | new SpawnTargetedEvents { referenceMechanicName = "EarthshakerPuddle", spawnOnTarget = true, targetingScheme = new TargetExistingTarget() } 214 | } 215 | } 216 | } 217 | }, 218 | { 219 | "EarthshakerPuddle", 220 | new MechanicProperties 221 | { 222 | collisionShape = CollisionShape.Round, 223 | collisionShapeParams = new Vector4(1.5f, 360), 224 | colorHtml = "#c78825", 225 | mechanic = new WaitEvent { timeToWait = 10 }, 226 | persistentTickInterval = 0.3f, 227 | persistentActivationDelay = 2, 228 | persistentMechanic = new ApplyEffectToPlayers { effect = new DamageEffect { damageAmount = 300000, damageType = "Physical", name = "Sludge" } }, 229 | } 230 | }, 231 | { 232 | "ArenaBoundary", 233 | new MechanicProperties 234 | { 235 | collisionShape = CollisionShape.Round, 236 | collisionShapeParams = new Vector4(25, 360, 7), 237 | colorHtml = "#8800FF", 238 | persistentTickInterval = 0.2f, 239 | persistentMechanic = new ApplyEffectToPlayers { effect = new DamageEffect { damageAmount = 9999999, damageType = "TrueDamage" } }, 240 | } 241 | }, 242 | { 243 | "Neurolinks-A", 244 | new MechanicProperties 245 | { 246 | visible = false, 247 | mechanic = new ExecuteMultipleEvents 248 | { 249 | events = new List { 250 | new SpawnMechanicEvent { referenceMechanicName = "Neurolink", position = new Vector2(0, 3.7f) }, 251 | new SpawnMechanicEvent { referenceMechanicName = "Neurolink", position = new Vector2(3.7f * 0.866f, -1.85f) }, 252 | new SpawnMechanicEvent { referenceMechanicName = "Neurolink", position = new Vector2(-3.7f * 0.866f, -1.85f) }, 253 | } 254 | } 255 | } 256 | }, 257 | { 258 | "Neurolinks-B", 259 | new MechanicProperties 260 | { 261 | visible = false, 262 | mechanic = new ExecuteMultipleEvents 263 | { 264 | events = new List { 265 | new SpawnMechanicEvent { referenceMechanicName = "Neurolink", position = new Vector2(0, -3.7f) }, 266 | new SpawnMechanicEvent { referenceMechanicName = "Neurolink", position = new Vector2(3.7f * 0.866f, 1.85f) }, 267 | new SpawnMechanicEvent { referenceMechanicName = "Neurolink", position = new Vector2(-3.7f * 0.866f, 1.85f) }, 268 | } 269 | } 270 | } 271 | }, 272 | { 273 | "DoubleHatch", 274 | new MechanicProperties 275 | { 276 | visible = false, 277 | mechanic = new ExecuteMultipleEvents 278 | { 279 | events = new List 280 | { 281 | new SpawnVisualObject { textureFilePath = "Mechanics/Resources/LimitCut-3.png", colorHtml = "#a800ff", spawnOnPlayer = true, visualDuration = 5, isBillboard = true, relativePosition = Vector3.up * 0.8f, scale = Vector3.one * 0.5f}, 282 | new SpawnTargetedEvents { referenceMechanicName = "Hatch", isPositionRelative = true, targetingScheme = new TargetExistingTarget() }, 283 | new WaitEvent { timeToWait = 4.2f }, 284 | new SpawnTargetedEvents { referenceMechanicName = "Hatch", isPositionRelative = true, targetingScheme = new TargetExistingTarget() }, 285 | } 286 | } 287 | } 288 | }, 289 | { 290 | "StartButton-A", 291 | new MechanicProperties 292 | { 293 | collisionShape = CollisionShape.Round, 294 | collisionShapeParams = new Vector4(0.5f, 360), 295 | colorHtml = "#00ff00", 296 | persistentTickInterval = 0.1f, 297 | persistentActivationDelay = 1, 298 | mechanicTag = "StartButton", 299 | persistentMechanic = new CheckNumberOfPlayers 300 | { 301 | expressionFormat = "{0} = 0", 302 | failEvent = new ExecuteMultipleEvents{ 303 | events = new List { 304 | new SpawnMechanicEvent { referenceMechanicName = "Neurolinks-A" }, 305 | new SpawnMechanicEvent { referenceMechanicName = "StartMechanics" }, 306 | new ClearMechanicsWithTag { mechanicTag = "StartButton" }, 307 | } 308 | } 309 | }, 310 | } 311 | }, 312 | { 313 | "StartButton-B", 314 | new MechanicProperties 315 | { 316 | collisionShape = CollisionShape.Round, 317 | collisionShapeParams = new Vector4(0.5f, 360), 318 | colorHtml = "#00ff00", 319 | persistentTickInterval = 0.1f, 320 | persistentActivationDelay = 1, 321 | mechanicTag = "StartButton", 322 | persistentMechanic = new CheckNumberOfPlayers 323 | { 324 | expressionFormat = "{0} = 0", 325 | failEvent = new ExecuteMultipleEvents{ 326 | events = new List { 327 | new SpawnMechanicEvent { referenceMechanicName = "Neurolinks-B" }, 328 | new SpawnMechanicEvent { referenceMechanicName = "StartMechanics" }, 329 | new ClearMechanicsWithTag { mechanicTag = "StartButton" }, 330 | } 331 | } 332 | }, 333 | } 334 | }, 335 | { 336 | "StartMechanics", 337 | new MechanicProperties 338 | { 339 | visible = false, 340 | mechanic = new ExecuteMultipleEvents 341 | { 342 | events = new List 343 | { 344 | new WaitEvent { timeToWait = 2 }, 345 | new SpawnTargetedEvents { referenceMechanicName = "DoubleHatch", targetingScheme = new TargetSpecificPlayerIds { targetIds = new List {0, 1, 2} } }, 346 | new WaitEvent { timeToWait = 4 }, 347 | 348 | new ReshufflePlayerIds(), 349 | new SpawnTargetedEvents { referenceMechanicName = "SpreadAoe", spawnOnTarget = true, targetingScheme = new TargetSpecificPlayerIds {targetIds = new List {0} } }, 350 | new WaitEvent { timeToWait = 1 }, 351 | new SpawnTargetedEvents { referenceMechanicName = "SpreadAoe", spawnOnTarget = true, targetingScheme = new TargetSpecificPlayerIds {targetIds = new List {1} } }, 352 | new WaitEvent { timeToWait = 1 }, 353 | new SpawnTargetedEvents { referenceMechanicName = "SpreadAoe", spawnOnTarget = true, targetingScheme = new TargetSpecificPlayerIds {targetIds = new List {2} } }, 354 | new WaitEvent { timeToWait = 1 }, 355 | new SpawnTargetedEvents { referenceMechanicName = "SpreadAoe", spawnOnTarget = true, targetingScheme = new TargetSpecificPlayerIds {targetIds = new List {3} } }, 356 | new WaitEvent { timeToWait = 1 }, 357 | new SpawnTargetedEvents { referenceMechanicName = "SpreadAoe", spawnOnTarget = true, targetingScheme = new TargetSpecificPlayerIds {targetIds = new List {4} } }, 358 | new WaitEvent { timeToWait = 1 }, 359 | new SpawnTargetedEvents { referenceMechanicName = "SpreadAoe", spawnOnTarget = true, targetingScheme = new TargetSpecificPlayerIds {targetIds = new List {5} } }, 360 | new WaitEvent { timeToWait = 1 }, 361 | new SpawnTargetedEvents { referenceMechanicName = "SpreadAoe", spawnOnTarget = true, targetingScheme = new TargetSpecificPlayerIds {targetIds = new List {6} } }, 362 | new WaitEvent { timeToWait = 1 }, 363 | new SpawnTargetedEvents { referenceMechanicName = "SpreadAoe", spawnOnTarget = true, targetingScheme = new TargetSpecificPlayerIds {targetIds = new List {7} } }, 364 | 365 | new ReshufflePlayerIds(), 366 | new SpawnTargetedEvents { referenceMechanicName = "Earthshaker", targetingScheme = new TargetSpecificPlayerIds {targetIds = new List {0, 1, 2, 3} } }, 367 | new WaitEvent {timeToWait = 5 }, 368 | new SpawnTargetedEvents { referenceMechanicName = "Earthshaker", targetingScheme = new TargetSpecificPlayerIds {targetIds = new List {4, 5, 6, 7} } }, 369 | } 370 | } 371 | } 372 | } 373 | }; 374 | 375 | mechanicData.referenceStatusProperties = new Dictionary 376 | { 377 | { 378 | "Neurolink", 379 | new StatusEffectData 380 | { 381 | statusIconPath = "Mechanics/Resources/Neurolink.png", 382 | statusName = "Neurolink", 383 | statusDescription = "Neurolink", 384 | duration = 0.3f, 385 | } 386 | }, 387 | { 388 | "MagicVuln", 389 | new DamageModifier 390 | { 391 | statusIconPath = "Mechanics/Resources/MagicVuln.png", 392 | statusName = "Magic Vulnerability Up", 393 | statusDescription = "Magic damage taken is increased.", 394 | damageType = "Magic", 395 | damageMultiplier = 10, 396 | duration = 16, 397 | } 398 | }, 399 | { 400 | "PhysVuln", 401 | new DamageModifier 402 | { 403 | statusIconPath = "Mechanics/Resources/PhysVuln.png", 404 | statusName = "Physical Vulnerability Up", 405 | statusDescription = "Physical damage taken is increased.", 406 | damageType = "Physical", 407 | damageMultiplier = 10, 408 | duration = 16, 409 | } 410 | }, 411 | }; 412 | 413 | mechanicData.mechanicEvents = new List 414 | { 415 | new SpawnMechanicEvent { referenceMechanicName = "ArenaBoundary" }, 416 | new SpawnVisualObject 417 | { 418 | textureFilePath = "Mechanics/Resources/ArenaCircle.png", 419 | visualDuration = float.PositiveInfinity, 420 | relativePosition = new Vector3(0, -0.001f, 0), 421 | eulerAngles = new Vector3(90, 0, 0), 422 | scale = new Vector3(15.8637f, 15.8637f, 1), 423 | }, 424 | new ExecuteMultipleEvents 425 | { 426 | events = new List 427 | { 428 | new SpawnMechanicEvent { referenceMechanicName = "StartButton-A", position = new Vector2(0, 3) }, 429 | new SpawnMechanicEvent { referenceMechanicName = "StartButton-B", position = new Vector2(0, -3) }, 430 | } 431 | } 432 | }; 433 | mechanicData.mechanicPools = new Dictionary> 434 | { 435 | { 436 | "Spawn-Bosses-Pool", 437 | new List 438 | { 439 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBosses-A" }, 440 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBosses-A", rotation = 120 }, 441 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBosses-A", rotation = 240 }, 442 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBosses-B" }, 443 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBosses-B", rotation = 120 }, 444 | new SpawnMechanicEvent { referenceMechanicName = "SpawnBosses-B", rotation = 240 }, 445 | } 446 | }, 447 | { 448 | "Quote-Pool", 449 | new List 450 | { 451 | new ExecuteMultipleEvents 452 | { 453 | events = new List 454 | { 455 | new SpawnVisualObject { textureFilePath = "Mechanics/Resources/Fellruin-In-Spread.png", visualDuration = 6, isBillboard = true, relativePosition = Vector3.up * 2, scale = new Vector3(4.17f, 1, 1) }, 456 | new WaitEvent { timeToWait = 6 }, 457 | new SpawnMechanicEvent { referenceMechanicName = "Dynamo", isPositionRelative = true }, 458 | new WaitEvent { timeToWait = 3 }, 459 | new ReshufflePlayerIds(), 460 | new SetEnemyMovement {movementTime = 0.2f, moveToTarget = new TargetSpecificPlayerIds {targetIds = new List {0} } }, 461 | new SpawnTargetedEvents { referenceMechanicName = "Dive", isPositionRelative = true, spawnOnTarget = true, targetingScheme = new TargetSpecificPlayerIds { targetIds = new List {0} } }, 462 | } 463 | }, 464 | new ExecuteMultipleEvents 465 | { 466 | events = new List 467 | { 468 | new SpawnVisualObject { textureFilePath = "Mechanics/Resources/Fellruin-Spread-In.png", visualDuration = 6, isBillboard = true, relativePosition = Vector3.up * 2, scale = new Vector3(4.17f, 1, 1) }, 469 | new WaitEvent { timeToWait = 6 }, 470 | new ReshufflePlayerIds(), 471 | new SetEnemyMovement {movementTime = 0.2f, moveToTarget = new TargetSpecificPlayerIds {targetIds = new List {0} } }, 472 | new SpawnTargetedEvents { referenceMechanicName = "Dive", isPositionRelative = true, spawnOnTarget = true, targetingScheme = new TargetSpecificPlayerIds { targetIds = new List {0} } }, 473 | new WaitEvent { timeToWait = 3 }, 474 | new SpawnMechanicEvent { referenceMechanicName = "Dynamo", isPositionRelative = true }, 475 | } 476 | }, 477 | } 478 | }, 479 | }; 480 | 481 | var resultText = mechanicData.ToString(); 482 | 483 | File.WriteAllText($@"{baseOutputPath}\Mechanics\{mechanicName}.json", resultText); 484 | File.WriteAllText($@"{baseOutputPath}\Build\Mechanics\{mechanicName}.json", resultText); 485 | File.WriteAllText($@"{buildOutputPath}\Mechanics\{mechanicName}.json", resultText); 486 | 487 | $"Finished writing json to Mechanics/{mechanicName}.json".Dump(); -------------------------------------------------------------------------------- /Mechanics/AwayWithTheeDemo.json: -------------------------------------------------------------------------------- 1 | { 2 | "referenceMechanicProperties": { 3 | "DrawIn": { 4 | "collisionShapeParams": { 5 | "x": 0.3, 6 | "y": 360.0, 7 | "z": 0.0, 8 | "w": 0.0 9 | }, 10 | "colorHtml": "#d800ff99", 11 | "visible": true, 12 | "mechanic": { 13 | "$type": "ExecuteMultipleEvents", 14 | "events": [ 15 | { 16 | "$type": "WaitEvent", 17 | "timeToWait": 1.0 18 | }, 19 | { 20 | "$type": "ApplyEffectToTargetOnly", 21 | "effects": [ 22 | { 23 | "$type": "KnockbackEffect", 24 | "isDrawIn": true, 25 | "knockbackDistance": 1.0, 26 | "additionalKnockbackSpeed": 5.0 27 | } 28 | ] 29 | } 30 | ] 31 | } 32 | }, 33 | "DrawInLeft": { 34 | "visible": false, 35 | "mechanic": { 36 | "$type": "ExecuteMultipleEvents", 37 | "events": [ 38 | { 39 | "$type": "ApplyEffectToTargetOnly", 40 | "effect": { 41 | "$type": "ApplyStatusEffect", 42 | "referenceStatusName": "Stun" 43 | } 44 | }, 45 | { 46 | "$type": "SpawnTargetedEvents", 47 | "targetingScheme": { 48 | "$type": "TargetExistingTarget" 49 | }, 50 | "referenceMechanicName": "DrawIn", 51 | "position": { 52 | "x": -3.0, 53 | "y": 0.0 54 | }, 55 | "isPositionRelative": true, 56 | "isRotationRelative": true, 57 | "spawnOnTarget": true 58 | } 59 | ] 60 | } 61 | }, 62 | "LeftWithThee": { 63 | "visible": false, 64 | "mechanic": { 65 | "$type": "ExecuteMultipleEvents", 66 | "events": [ 67 | { 68 | "$type": "ApplyEffectToTargetOnly", 69 | "effect": { 70 | "$type": "ApplyStatusEffect", 71 | "referenceStatusName": "LeftWithThee" 72 | } 73 | }, 74 | { 75 | "$type": "SpawnVisualObject", 76 | "textureFilePath": "Mechanics/Resources/Mark1.png", 77 | "relativePosition": { 78 | "x": -3.0, 79 | "y": 0.6, 80 | "z": 0.0 81 | }, 82 | "scale": { 83 | "x": 0.8, 84 | "y": 0.8, 85 | "z": 1.0 86 | }, 87 | "colorHtml": "#d800ff", 88 | "spawnOnPlayer": true, 89 | "isBillboard": true, 90 | "visualDuration": 5.0 91 | }, 92 | { 93 | "$type": "SpawnVisualObject", 94 | "textureFilePath": "Mechanics/Resources/LimitCut-1.png", 95 | "relativePosition": { 96 | "x": -3.0, 97 | "y": 0.1, 98 | "z": 0.0 99 | }, 100 | "eulerAngles": { 101 | "x": 90.0, 102 | "y": 0.0, 103 | "z": 0.0 104 | }, 105 | "scale": { 106 | "x": 1.0, 107 | "y": 1.0, 108 | "z": 1.0 109 | }, 110 | "colorHtml": "#d800ff99", 111 | "spawnOnPlayer": true, 112 | "visualDuration": 5.0 113 | } 114 | ] 115 | } 116 | } 117 | }, 118 | "referenceTetherProperties": {}, 119 | "mechanicPools": {}, 120 | "referenceStatusProperties": { 121 | "LeftWithThee": { 122 | "$type": "SpawnMechanicOnExpire", 123 | "referenceMechanicName": "DrawInLeft", 124 | "statusIconPath": "Mechanics/Resources/LeftWithThee.png", 125 | "statusName": "Larboard With Thee", 126 | "statusDescription": "When this effect ends, you will be spawned and forcibly moved leftwards.", 127 | "duration": 5.0 128 | }, 129 | "Stun": { 130 | "statusIconPath": "Mechanics/Resources/Stun.png", 131 | "statusName": "Stun", 132 | "statusDescription": "Unable to execute actions.", 133 | "disableType": 3, 134 | "duration": 3.0 135 | } 136 | }, 137 | "mechanicEvents": [ 138 | { 139 | "$type": "SpawnVisualObject", 140 | "textureFilePath": "Mechanics/Resources/ArenaSquare4x4.png", 141 | "relativePosition": { 142 | "x": 0.0, 143 | "y": -0.001, 144 | "z": 0.0 145 | }, 146 | "eulerAngles": { 147 | "x": 90.0, 148 | "y": 0.0, 149 | "z": 0.0 150 | }, 151 | "scale": { 152 | "x": 15.8637, 153 | "y": 15.8637, 154 | "z": 1.0 155 | }, 156 | "visualDuration": "Infinity" 157 | }, 158 | { 159 | "$type": "SpawnTargetedEvents", 160 | "targetingScheme": { 161 | "$type": "TargetAllPlayers" 162 | }, 163 | "referenceMechanicName": "LeftWithThee" 164 | } 165 | ] 166 | } -------------------------------------------------------------------------------- /Mechanics/ExaflareDemo.json: -------------------------------------------------------------------------------- 1 | { 2 | "referenceMechanicProperties": { 3 | "Exaflare": { 4 | "collisionShape": "Round", 5 | "collisionShapeParams": { 6 | "x": 1.0, 7 | "y": 360.0, 8 | "z": 0.0, 9 | "w": 0.0 10 | }, 11 | "colorHtml": "#ff9600", 12 | "mechanic": { 13 | "$type": "ExecuteMultipleEvents", 14 | "events": [ 15 | { 16 | "$type": "WaitEvent", 17 | "timeToWait": 2.0 18 | }, 19 | { 20 | "$type": "CheckMechanicDepth", 21 | "expressionFormat": "{0} < 5", 22 | "successEvent": { 23 | "$type": "SpawnMechanicEvent", 24 | "referenceMechanicName": "Exaflare", 25 | "position": { 26 | "x": 0.0, 27 | "y": 1.5 28 | }, 29 | "isPositionRelative": true, 30 | "isRotationRelative": true 31 | } 32 | }, 33 | { 34 | "$type": "WaitEvent", 35 | "timeToWait": 1.0 36 | }, 37 | { 38 | "$type": "ApplyEffectToPlayers", 39 | "effect": { 40 | "$type": "DamageEffect", 41 | "name": "Exaflare", 42 | "damageType": "Damage", 43 | "damageAmount": 90000.0 44 | } 45 | } 46 | ] 47 | } 48 | } 49 | }, 50 | "referenceTetherProperties": {}, 51 | "mechanicPools": {}, 52 | "referenceStatusProperties": {}, 53 | "mechanicEvents": [ 54 | { 55 | "$type": "SpawnMechanicEvent", 56 | "referenceMechanicName": "Exaflare", 57 | "position": { 58 | "x": 0.0, 59 | "y": 3.0 60 | } 61 | }, 62 | { 63 | "$type": "SpawnMechanicEvent", 64 | "referenceMechanicName": "Exaflare", 65 | "position": { 66 | "x": 3.0, 67 | "y": 0.0 68 | }, 69 | "rotation": 90.0 70 | }, 71 | { 72 | "$type": "SpawnMechanicEvent", 73 | "referenceMechanicName": "Exaflare", 74 | "position": { 75 | "x": 0.0, 76 | "y": -3.0 77 | }, 78 | "rotation": 180.0 79 | }, 80 | { 81 | "$type": "SpawnMechanicEvent", 82 | "referenceMechanicName": "Exaflare", 83 | "position": { 84 | "x": -3.0, 85 | "y": 0.0 86 | }, 87 | "rotation": 270.0 88 | } 89 | ] 90 | } -------------------------------------------------------------------------------- /Mechanics/InnocenceAoeDemo.json: -------------------------------------------------------------------------------- 1 | { 2 | "referenceMechanicProperties": { 3 | "Donut Cone": { 4 | "collisionShape": "Round", 5 | "collisionShapeParams": { 6 | "x": 5.0, 7 | "y": 120.0, 8 | "z": 3.0, 9 | "w": 0.0 10 | }, 11 | "colorHtml": "#ff9600", 12 | "mechanic": { 13 | "$type": "ExecuteMultipleEvents", 14 | "events": [ 15 | { 16 | "$type": "WaitEvent", 17 | "timeToWait": 3.0 18 | }, 19 | { 20 | "$type": "ApplyEffectToPlayers", 21 | "effect": { 22 | "$type": "DamageEffect", 23 | "name": "Innocence Aoe", 24 | "damageType": "Damage", 25 | "damageAmount": 90000.0 26 | } 27 | } 28 | ] 29 | } 30 | }, 31 | "Donut Cone Offset": { 32 | "visible": false, 33 | "mechanic": { 34 | "$type": "ExecuteMultipleEvents", 35 | "events": [ 36 | { 37 | "$type": "SpawnMechanicEvent", 38 | "referenceMechanicName": "Donut Cone", 39 | "position": { 40 | "x": 4.0, 41 | "y": 0.0 42 | }, 43 | "rotation": -30.0, 44 | "isPositionRelative": true, 45 | "isRotationRelative": true 46 | }, 47 | { 48 | "$type": "WaitEvent", 49 | "timeToWait": 2.0 50 | }, 51 | { 52 | "$type": "SpawnMechanicEvent", 53 | "referenceMechanicName": "Donut Cone Offset", 54 | "rotation": -25.0, 55 | "isPositionRelative": true, 56 | "isRotationRelative": true 57 | } 58 | ] 59 | } 60 | } 61 | }, 62 | "referenceTetherProperties": {}, 63 | "mechanicPools": {}, 64 | "referenceStatusProperties": {}, 65 | "mechanicEvents": [ 66 | { 67 | "$type": "SpawnMechanicEvent", 68 | "referenceMechanicName": "Donut Cone Offset", 69 | "position": { 70 | "x": 0.0, 71 | "y": 0.0 72 | } 73 | }, 74 | { 75 | "$type": "SpawnMechanicEvent", 76 | "referenceMechanicName": "Donut Cone Offset", 77 | "position": { 78 | "x": 0.0, 79 | "y": 0.0 80 | }, 81 | "rotation": 180.0 82 | } 83 | ] 84 | } -------------------------------------------------------------------------------- /Mechanics/KnockbackDemo.json: -------------------------------------------------------------------------------- 1 | { 2 | "referenceMechanicProperties": { 3 | "Knockback": { 4 | "collisionShape": "Round", 5 | "collisionShapeParams": { 6 | "x": 3.0, 7 | "y": 360.0, 8 | "z": 0.0, 9 | "w": 0.0 10 | }, 11 | "colorHtml": "#ff9600", 12 | "mechanic": { 13 | "$type": "ExecuteMultipleEvents", 14 | "events": [ 15 | { 16 | "$type": "WaitEvent", 17 | "timeToWait": 3.0 18 | }, 19 | { 20 | "$type": "ApplyEffectToPlayers", 21 | "effects": [ 22 | { 23 | "$type": "DamageEffect", 24 | "name": "Knockback", 25 | "damageType": "Damage", 26 | "damageAmount": 10000.0 27 | }, 28 | { 29 | "$type": "KnockbackEffect", 30 | "canArmsLength": true, 31 | "knockbackDistance": 3.0 32 | } 33 | ] 34 | } 35 | ] 36 | } 37 | }, 38 | "DrawIn": { 39 | "collisionShape": "Round", 40 | "collisionShapeParams": { 41 | "x": 3.0, 42 | "y": 360.0, 43 | "z": 0.0, 44 | "w": 0.0 45 | }, 46 | "colorHtml": "#0078ff", 47 | "mechanic": { 48 | "$type": "ExecuteMultipleEvents", 49 | "events": [ 50 | { 51 | "$type": "WaitEvent", 52 | "timeToWait": 3.0 53 | }, 54 | { 55 | "$type": "ApplyEffectToPlayers", 56 | "effects": [ 57 | { 58 | "$type": "DamageEffect", 59 | "name": "Draw In", 60 | "damageType": "Damage", 61 | "damageAmount": 10000.0 62 | }, 63 | { 64 | "$type": "KnockbackEffect", 65 | "isDrawIn": true, 66 | "knockbackDistance": 1.0, 67 | "additionalKnockbackSpeed": 5.0 68 | } 69 | ] 70 | } 71 | ] 72 | } 73 | } 74 | }, 75 | "referenceTetherProperties": {}, 76 | "mechanicPools": {}, 77 | "referenceStatusProperties": {}, 78 | "mechanicEvents": [ 79 | { 80 | "$type": "SpawnMechanicEvent", 81 | "referenceMechanicName": "Knockback", 82 | "position": { 83 | "x": -2.0, 84 | "y": 0.0 85 | } 86 | }, 87 | { 88 | "$type": "SpawnMechanicEvent", 89 | "referenceMechanicName": "DrawIn", 90 | "position": { 91 | "x": 2.0, 92 | "y": 0.0 93 | } 94 | } 95 | ] 96 | } -------------------------------------------------------------------------------- /Mechanics/SimpleAoeDemo.json: -------------------------------------------------------------------------------- 1 | { 2 | "referenceMechanicProperties": { 3 | "Circle": { 4 | "collisionShape": "Round", 5 | "collisionShapeParams": { 6 | "x": 1.0, 7 | "y": 360.0, 8 | "z": 0.0, 9 | "w": 0.0 10 | }, 11 | "colorHtml": "#ff9600", 12 | "mechanic": { 13 | "$type": "ExecuteMultipleEvents", 14 | "events": [ 15 | { 16 | "$type": "WaitEvent", 17 | "timeToWait": 3.0 18 | }, 19 | { 20 | "$type": "ApplyEffectToPlayers", 21 | "effect": { 22 | "$type": "DamageEffect", 23 | "name": "Circle Aoe", 24 | "damageType": "Damage", 25 | "damageAmount": 90000.0 26 | } 27 | } 28 | ] 29 | } 30 | }, 31 | "Cone": { 32 | "collisionShape": "Round", 33 | "collisionShapeParams": { 34 | "x": 1.0, 35 | "y": 120.0, 36 | "z": 0.0, 37 | "w": 0.0 38 | }, 39 | "colorHtml": "#ff9600", 40 | "mechanic": { 41 | "$type": "ExecuteMultipleEvents", 42 | "events": [ 43 | { 44 | "$type": "WaitEvent", 45 | "timeToWait": 3.0 46 | }, 47 | { 48 | "$type": "ApplyEffectToPlayers", 49 | "effect": { 50 | "$type": "DamageEffect", 51 | "name": "Cone Aoe", 52 | "damageType": "Damage", 53 | "damageAmount": 90000.0 54 | } 55 | } 56 | ] 57 | } 58 | }, 59 | "Donut": { 60 | "collisionShape": "Round", 61 | "collisionShapeParams": { 62 | "x": 2.0, 63 | "y": 360.0, 64 | "z": 1.0, 65 | "w": 0.0 66 | }, 67 | "colorHtml": "#ff9600", 68 | "mechanic": { 69 | "$type": "ExecuteMultipleEvents", 70 | "events": [ 71 | { 72 | "$type": "WaitEvent", 73 | "timeToWait": 3.0 74 | }, 75 | { 76 | "$type": "ApplyEffectToPlayers", 77 | "effect": { 78 | "$type": "DamageEffect", 79 | "name": "Donut Aoe", 80 | "damageType": "Damage", 81 | "damageAmount": 90000.0 82 | } 83 | } 84 | ] 85 | } 86 | }, 87 | "Donut Cone": { 88 | "collisionShape": "Round", 89 | "collisionShapeParams": { 90 | "x": 2.0, 91 | "y": 120.0, 92 | "z": 1.0, 93 | "w": 0.0 94 | }, 95 | "colorHtml": "#ff9600", 96 | "mechanic": { 97 | "$type": "ExecuteMultipleEvents", 98 | "events": [ 99 | { 100 | "$type": "WaitEvent", 101 | "timeToWait": 3.0 102 | }, 103 | { 104 | "$type": "ApplyEffectToPlayers", 105 | "effect": { 106 | "$type": "DamageEffect", 107 | "name": "Donut Cone Aoe", 108 | "damageType": "Damage", 109 | "damageAmount": 90000.0 110 | } 111 | } 112 | ] 113 | } 114 | }, 115 | "Rectangle": { 116 | "collisionShape": "Rectangle", 117 | "collisionShapeParams": { 118 | "x": 10.0, 119 | "y": 1.0, 120 | "z": 0.0, 121 | "w": 0.0 122 | }, 123 | "colorHtml": "#ff9600", 124 | "mechanic": { 125 | "$type": "ExecuteMultipleEvents", 126 | "events": [ 127 | { 128 | "$type": "WaitEvent", 129 | "timeToWait": 3.0 130 | }, 131 | { 132 | "$type": "ApplyEffectToPlayers", 133 | "effect": { 134 | "$type": "DamageEffect", 135 | "name": "Rectangle Aoe", 136 | "damageType": "Damage", 137 | "damageAmount": 90000.0 138 | } 139 | } 140 | ] 141 | } 142 | } 143 | }, 144 | "referenceTetherProperties": {}, 145 | "mechanicPools": {}, 146 | "referenceStatusProperties": {}, 147 | "mechanicEvents": [ 148 | { 149 | "$type": "SpawnMechanicEvent", 150 | "referenceMechanicName": "Circle" 151 | }, 152 | { 153 | "$type": "SpawnMechanicEvent", 154 | "referenceMechanicName": "Cone", 155 | "position": { 156 | "x": 2.0, 157 | "y": 0.0 158 | } 159 | }, 160 | { 161 | "$type": "SpawnMechanicEvent", 162 | "referenceMechanicName": "Donut", 163 | "position": { 164 | "x": 6.0, 165 | "y": 0.0 166 | } 167 | }, 168 | { 169 | "$type": "SpawnMechanicEvent", 170 | "referenceMechanicName": "Donut Cone", 171 | "position": { 172 | "x": 10.0, 173 | "y": 0.0 174 | } 175 | }, 176 | { 177 | "$type": "SpawnMechanicEvent", 178 | "referenceMechanicName": "Rectangle", 179 | "position": { 180 | "x": 0.0, 181 | "y": 4.0 182 | }, 183 | "rotation": 90.0 184 | } 185 | ] 186 | } -------------------------------------------------------------------------------- /Mechanics/TargetedAoeDemo.json: -------------------------------------------------------------------------------- 1 | { 2 | "referenceMechanicProperties": { 3 | "TargetedCircle": { 4 | "isTargeted": true, 5 | "followSpeed": 10000.0, 6 | "collisionShape": "Round", 7 | "collisionShapeParams": { 8 | "x": 1.0, 9 | "y": 360.0, 10 | "z": 0.0, 11 | "w": 0.0 12 | }, 13 | "colorHtml": "#ff9600", 14 | "mechanic": { 15 | "$type": "ExecuteMultipleEvents", 16 | "events": [ 17 | { 18 | "$type": "WaitEvent", 19 | "timeToWait": 15.0 20 | }, 21 | { 22 | "$type": "ApplyEffectToPlayers", 23 | "effect": { 24 | "$type": "DamageEffect", 25 | "name": "Circle Aoe", 26 | "damageType": "Damage", 27 | "damageAmount": 10000.0 28 | } 29 | } 30 | ] 31 | } 32 | }, 33 | "AimedRectangle": { 34 | "isTargeted": true, 35 | "collisionShape": "Rectangle", 36 | "collisionShapeParams": { 37 | "x": 50.0, 38 | "y": 1.0, 39 | "z": 0.0, 40 | "w": 0.0 41 | }, 42 | "colorHtml": "#0196ff", 43 | "mechanic": { 44 | "$type": "ExecuteMultipleEvents", 45 | "events": [ 46 | { 47 | "$type": "WaitEvent", 48 | "timeToWait": 15.0 49 | }, 50 | { 51 | "$type": "ApplyEffectToPlayers", 52 | "effect": { 53 | "$type": "DamageEffect", 54 | "name": "Rectangle Aoe", 55 | "damageType": "Damage", 56 | "damageAmount": 10000.0 57 | } 58 | } 59 | ] 60 | } 61 | } 62 | }, 63 | "referenceTetherProperties": {}, 64 | "mechanicPools": {}, 65 | "referenceStatusProperties": {}, 66 | "mechanicEvents": [ 67 | { 68 | "$type": "SpawnTargetedEvents", 69 | "targetingScheme": { 70 | "$type": "TargetAllPlayers" 71 | }, 72 | "referenceMechanicName": "TargetedCircle" 73 | }, 74 | { 75 | "$type": "SpawnTargetedEvents", 76 | "targetingScheme": { 77 | "$type": "TargetAllPlayers" 78 | }, 79 | "referenceMechanicName": "AimedRectangle" 80 | } 81 | ] 82 | } -------------------------------------------------------------------------------- /Mechanics/TerrainDemo.json: -------------------------------------------------------------------------------- 1 | { 2 | "referenceMechanicProperties": { 3 | "Knockback": { 4 | "collisionShape": "Round", 5 | "collisionShapeParams": { 6 | "x": 3.0, 7 | "y": 360.0, 8 | "z": 0.0, 9 | "w": 0.0 10 | }, 11 | "colorHtml": "#ff9600", 12 | "mechanic": { 13 | "$type": "ExecuteMultipleEvents", 14 | "events": [ 15 | { 16 | "$type": "WaitEvent", 17 | "timeToWait": 3.0 18 | }, 19 | { 20 | "$type": "ApplyEffectToPlayers", 21 | "effects": [ 22 | { 23 | "$type": "DamageEffect", 24 | "name": "Knockback", 25 | "damageType": "Damage", 26 | "damageAmount": 10000.0 27 | }, 28 | { 29 | "$type": "KnockbackEffect", 30 | "knockbackDistance": 20.0 31 | } 32 | ] 33 | } 34 | ] 35 | } 36 | }, 37 | "Wall": { 38 | "isTerrain": true, 39 | "collisionShape": "Rectangle", 40 | "collisionShapeParams": { 41 | "x": 10.0, 42 | "y": 3.0, 43 | "z": 0.0, 44 | "w": 0.0 45 | }, 46 | "colorHtml": "#0078ff", 47 | "mechanic": { 48 | "$type": "WaitEvent", 49 | "timeToWait": "Infinity" 50 | } 51 | } 52 | }, 53 | "referenceTetherProperties": {}, 54 | "mechanicPools": {}, 55 | "referenceStatusProperties": {}, 56 | "mechanicEvents": [ 57 | { 58 | "$type": "SpawnMechanicEvent", 59 | "referenceMechanicName": "Knockback", 60 | "position": { 61 | "x": -2.0, 62 | "y": 0.0 63 | } 64 | }, 65 | { 66 | "$type": "SpawnMechanicEvent", 67 | "referenceMechanicName": "Wall", 68 | "position": { 69 | "x": 4.0, 70 | "y": -5.0 71 | } 72 | } 73 | ] 74 | } -------------------------------------------------------------------------------- /Mechanics/TowerDemo.json: -------------------------------------------------------------------------------- 1 | { 2 | "referenceMechanicProperties": { 3 | "Aoe-Green": { 4 | "colorHtml": "#00ff00" 5 | }, 6 | "Tower": { 7 | "collisionShape": "Round", 8 | "collisionShapeParams": { 9 | "x": 1.0, 10 | "y": 360.0, 11 | "z": 0.0, 12 | "w": 0.0 13 | }, 14 | "colorHtml": "#ff9600", 15 | "persistentTickInterval": 0.1, 16 | "mechanic": { 17 | "$type": "ExecuteMultipleEvents", 18 | "events": [ 19 | { 20 | "$type": "WaitEvent", 21 | "timeToWait": 5.0 22 | }, 23 | { 24 | "$type": "ApplyEffectToPlayers", 25 | "effect": { 26 | "$type": "DamageEffect", 27 | "name": "Tower", 28 | "damageType": "Damage", 29 | "damageAmount": 10000.0 30 | } 31 | }, 32 | { 33 | "$type": "CheckNumberOfPlayers", 34 | "expressionFormat": "{0} = 1", 35 | "failEvent": { 36 | "$type": "SpawnMechanicEvent", 37 | "referenceMechanicName": "TowerFailed", 38 | "isPositionRelative": true 39 | } 40 | } 41 | ] 42 | }, 43 | "persistentMechanic": { 44 | "$type": "CheckNumberOfPlayers", 45 | "expressionFormat": "{0} = 1", 46 | "successEvent": { 47 | "$type": "ModifyMechanicEvent", 48 | "referenceMechanicName": "Aoe-Green" 49 | }, 50 | "failEvent": { 51 | "$type": "ModifyMechanicEvent", 52 | "referenceMechanicName": "Tower" 53 | } 54 | } 55 | }, 56 | "TowerFailed": { 57 | "collisionShape": "Round", 58 | "collisionShapeParams": { 59 | "x": 3.0, 60 | "y": 360.0, 61 | "z": 0.0, 62 | "w": 0.0 63 | }, 64 | "colorHtml": "#ff0000", 65 | "mechanic": { 66 | "$type": "ExecuteMultipleEvents", 67 | "events": [ 68 | { 69 | "$type": "WaitEvent", 70 | "timeToWait": 0.2 71 | }, 72 | { 73 | "$type": "ApplyEffectToPlayers", 74 | "effect": { 75 | "$type": "DamageEffect", 76 | "name": "TowerFailed", 77 | "damageType": "TrueDamage", 78 | "damageAmount": 9999999.0 79 | } 80 | } 81 | ] 82 | } 83 | } 84 | }, 85 | "referenceTetherProperties": {}, 86 | "mechanicPools": {}, 87 | "referenceStatusProperties": {}, 88 | "mechanicEvents": [ 89 | { 90 | "$type": "SpawnMechanicEvent", 91 | "referenceMechanicName": "Tower" 92 | } 93 | ] 94 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Downloads 2 | 3 | **Simulator Download:** [Releases](https://github.com/xiv-stats/xiv-sim-documentation/releases) 4 | 5 | **Other Links:** [Discord](https://discord.gg/XjP3f2HXYy) | [Twitter](https://twitter.com/xiv_sim) | [Youtube](https://www.youtube.com/channel/UC_pX9gr7B-wd5nIBHafqiKw) | [Documentation (Wiki)](https://github.com/xiv-stats/xiv-sim-documentation/wiki) 6 | 7 | #### Setup Guide [(Google Doc Guide by Hoppy)](https://docs.google.com/document/d/e/2PACX-1vT9yEN-lBq05fPb5d0PgAWng3TIT2Zcb7_bSlbOFmpdnJd_Yk0uk_husdVzvniA9pcDo9bXiCRol7RR/pub) 8 | 1. Download and extract the latest version from the [releases](https://github.com/xiv-stats/xiv-sim-documentation/releases) page. 9 | 2. If it is the first time you are running the simulator, you can click the **"Redownload Mechanic Files From Github"** button, which will automatically download the latest mechanic files files and place them in the correct place. 10 | - You can also download the mechanics folder manually from [here](https://github.com/xiv-stats/xiv-sim-mechanics) as well, and put it in the root directory of the app. 11 | 12 | #### Host Setup 13 | 1. In order to host a room for multiplayer, you will need to enable port forwarding on your router. The steps for this will be different for each router. 14 | 2. The following settings should be used for port forwarding: 15 | - **Service Type:** TCP/UDP 16 | - **Internal Ports:** 7777~7778 17 | - **External Ports:** 7777~7778 18 | - **Server IPv4:** (The local IP of the computer that you will be running the simulator on.) 19 | 2. Once port forwarding is set up, you will be able to host by sharing your [public IP](https://whatismyipaddress.com/). 20 | 21 | > ⚠**Note about checking if port forwarding is working:** Many online port forward checkers are not reliable and will report your port is closed even if it isn't. The best way to check is to have someone try to connect to you using the simulator. It should take a couple seconds for them to connect. 22 | 23 | --- 24 | 25 | # Scripting Setup (C#) 26 | As of the [`20210624-v2`](https://github.com/xiv-stats/xiv-sim-documentation/releases/tag/20210624-v2) release, you can now create the mechanic json files using C#. You can use any IDE/scripting environment that you would like. 27 | 28 | In order to set up your project, you will need to reference the following 2 DLLs in your project, located in the `XivMechanicSimNetworked_Data/Managed` folder: 29 | 30 |

31 | 32 |

33 | 34 | For development, I use [Linqpad](https://www.linqpad.net/) to write my scripts for generating the mechanic files. I have included all of the scripts that I have used to create the existing demos in this repo as a reference for how to create mechanics: [xiv-sim-documentation/Linqpad](https://github.com/xiv-stats/xiv-sim-documentation/tree/main/Linqpad) 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | --------------------------------------------------------------------------------