diff --git a/Directory.Build.props b/Directory.Build.props index 0de1add1f..fd20b1bc7 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -3,7 +3,7 @@ net7.0-windows enable ArchiTed - 3.3.6 + 3.4.0 x64 AnyCPU diff --git a/RotationSolver/Logos/0001.png b/Images/0001.png similarity index 100% rename from RotationSolver/Logos/0001.png rename to Images/0001.png diff --git a/RotationSolver/Logos/0002.png b/Images/0002.png similarity index 100% rename from RotationSolver/Logos/0002.png rename to Images/0002.png diff --git a/RotationSolver/Logos/0003.png b/Images/0003.png similarity index 100% rename from RotationSolver/Logos/0003.png rename to Images/0003.png diff --git a/RotationSolver/Logos/0004.png b/Images/0004.png similarity index 100% rename from RotationSolver/Logos/0004.png rename to Images/0004.png diff --git a/RotationSolver/Logos/0005.png b/Images/0005.png similarity index 100% rename from RotationSolver/Logos/0005.png rename to Images/0005.png diff --git a/RotationSolver/Logos/0006.png b/Images/0006.png similarity index 100% rename from RotationSolver/Logos/0006.png rename to Images/0006.png diff --git a/RotationSolver/Logos/0007.png b/Images/0007.png similarity index 100% rename from RotationSolver/Logos/0007.png rename to Images/0007.png diff --git a/RotationSolver/Logos/0008.png b/Images/0008.png similarity index 100% rename from RotationSolver/Logos/0008.png rename to Images/0008.png diff --git a/RotationSolver/Logos/0009.png b/Images/0009.png similarity index 100% rename from RotationSolver/Logos/0009.png rename to Images/0009.png diff --git a/RotationSolver/Logos/0010.png b/Images/0010.png similarity index 100% rename from RotationSolver/Logos/0010.png rename to Images/0010.png diff --git a/RotationSolver/Logos/0011.png b/Images/0011.png similarity index 100% rename from RotationSolver/Logos/0011.png rename to Images/0011.png diff --git a/RotationSolver/Logos/0012.png b/Images/0012.png similarity index 100% rename from RotationSolver/Logos/0012.png rename to Images/0012.png diff --git a/RotationSolver/Logos/0013.png b/Images/0013.png similarity index 100% rename from RotationSolver/Logos/0013.png rename to Images/0013.png diff --git a/RotationSolver/Logos/0014.png b/Images/0014.png similarity index 100% rename from RotationSolver/Logos/0014.png rename to Images/0014.png diff --git a/RotationSolver/Logos/0015.png b/Images/0015.png similarity index 100% rename from RotationSolver/Logos/0015.png rename to Images/0015.png diff --git a/RotationSolver/Logos/0016.png b/Images/0016.png similarity index 100% rename from RotationSolver/Logos/0016.png rename to Images/0016.png diff --git a/RotationSolver/Logos/0017.png b/Images/0017.png similarity index 100% rename from RotationSolver/Logos/0017.png rename to Images/0017.png diff --git a/RotationSolver/Logos/0018.png b/Images/0018.png similarity index 100% rename from RotationSolver/Logos/0018.png rename to Images/0018.png diff --git a/RotationSolver/Logos/0019.png b/Images/0019.png similarity index 100% rename from RotationSolver/Logos/0019.png rename to Images/0019.png diff --git a/RotationSolver/Logos/0020.png b/Images/0020.png similarity index 100% rename from RotationSolver/Logos/0020.png rename to Images/0020.png diff --git a/RotationSolver/Logos/0021.png b/Images/0021.png similarity index 100% rename from RotationSolver/Logos/0021.png rename to Images/0021.png diff --git a/RotationSolver/Logos/0022.png b/Images/0022.png similarity index 100% rename from RotationSolver/Logos/0022.png rename to Images/0022.png diff --git a/RotationSolver/Logos/0023.png b/Images/0023.png similarity index 100% rename from RotationSolver/Logos/0023.png rename to Images/0023.png diff --git a/RotationSolver/Logos/0024.png b/Images/0024.png similarity index 100% rename from RotationSolver/Logos/0024.png rename to Images/0024.png diff --git a/RotationSolver/Logos/0025.png b/Images/0025.png similarity index 100% rename from RotationSolver/Logos/0025.png rename to Images/0025.png diff --git a/RotationSolver/Logos/0026.png b/Images/0026.png similarity index 100% rename from RotationSolver/Logos/0026.png rename to Images/0026.png diff --git a/RotationSolver/Logos/0027.png b/Images/0027.png similarity index 100% rename from RotationSolver/Logos/0027.png rename to Images/0027.png diff --git a/RotationSolver/Logos/0028.png b/Images/0028.png similarity index 100% rename from RotationSolver/Logos/0028.png rename to Images/0028.png diff --git a/RotationSolver/Logos/0029.png b/Images/0029.png similarity index 100% rename from RotationSolver/Logos/0029.png rename to Images/0029.png diff --git a/RotationSolver/Logos/0030.png b/Images/0030.png similarity index 100% rename from RotationSolver/Logos/0030.png rename to Images/0030.png diff --git a/RotationSolver/Logos/0031.png b/Images/0031.png similarity index 100% rename from RotationSolver/Logos/0031.png rename to Images/0031.png diff --git a/RotationSolver/Logos/0032.png b/Images/0032.png similarity index 100% rename from RotationSolver/Logos/0032.png rename to Images/0032.png diff --git a/RotationSolver/Logos/0033.png b/Images/0033.png similarity index 100% rename from RotationSolver/Logos/0033.png rename to Images/0033.png diff --git a/RotationSolver/Logos/0034.png b/Images/0034.png similarity index 100% rename from RotationSolver/Logos/0034.png rename to Images/0034.png diff --git a/RotationSolver/Logos/0035.png b/Images/0035.png similarity index 100% rename from RotationSolver/Logos/0035.png rename to Images/0035.png diff --git a/RotationSolver/Logos/0036.png b/Images/0036.png similarity index 100% rename from RotationSolver/Logos/0036.png rename to Images/0036.png diff --git a/RotationSolver/Logos/0037.png b/Images/0037.png similarity index 100% rename from RotationSolver/Logos/0037.png rename to Images/0037.png diff --git a/RotationSolver/Logos/0038.png b/Images/0038.png similarity index 100% rename from RotationSolver/Logos/0038.png rename to Images/0038.png diff --git a/RotationSolver/Logos/0039.png b/Images/0039.png similarity index 100% rename from RotationSolver/Logos/0039.png rename to Images/0039.png diff --git a/RotationSolver/Logos/0040.png b/Images/0040.png similarity index 100% rename from RotationSolver/Logos/0040.png rename to Images/0040.png diff --git a/RotationSolver/Logos/0041.png b/Images/0041.png similarity index 100% rename from RotationSolver/Logos/0041.png rename to Images/0041.png diff --git a/RotationSolver/Logos/0042.png b/Images/0042.png similarity index 100% rename from RotationSolver/Logos/0042.png rename to Images/0042.png diff --git a/RotationSolver/Logos/0043.png b/Images/0043.png similarity index 100% rename from RotationSolver/Logos/0043.png rename to Images/0043.png diff --git a/RotationSolver/Logos/0044.png b/Images/0044.png similarity index 100% rename from RotationSolver/Logos/0044.png rename to Images/0044.png diff --git a/RotationSolver/Logos/0045.png b/Images/0045.png similarity index 100% rename from RotationSolver/Logos/0045.png rename to Images/0045.png diff --git a/RotationSolver/Logos/0046.png b/Images/0046.png similarity index 100% rename from RotationSolver/Logos/0046.png rename to Images/0046.png diff --git a/RotationSolver/Logos/0047.png b/Images/0047.png similarity index 100% rename from RotationSolver/Logos/0047.png rename to Images/0047.png diff --git a/RotationSolver/Logos/0048.png b/Images/0048.png similarity index 100% rename from RotationSolver/Logos/0048.png rename to Images/0048.png diff --git a/RotationSolver/Logos/0049.png b/Images/0049.png similarity index 100% rename from RotationSolver/Logos/0049.png rename to Images/0049.png diff --git a/RotationSolver/Logos/0050.png b/Images/0050.png similarity index 100% rename from RotationSolver/Logos/0050.png rename to Images/0050.png diff --git a/RotationSolver/Logos/0051.png b/Images/0051.png similarity index 100% rename from RotationSolver/Logos/0051.png rename to Images/0051.png diff --git a/RotationSolver/Logos/0052.png b/Images/0052.png similarity index 100% rename from RotationSolver/Logos/0052.png rename to Images/0052.png diff --git a/RotationSolver/Logos/0053.png b/Images/0053.png similarity index 100% rename from RotationSolver/Logos/0053.png rename to Images/0053.png diff --git a/RotationSolver/Logos/0054.png b/Images/0054.png similarity index 100% rename from RotationSolver/Logos/0054.png rename to Images/0054.png diff --git a/RotationSolver/Logos/0055.png b/Images/0055.png similarity index 100% rename from RotationSolver/Logos/0055.png rename to Images/0055.png diff --git a/RotationSolver/Logos/0056.png b/Images/0056.png similarity index 100% rename from RotationSolver/Logos/0056.png rename to Images/0056.png diff --git a/RotationSolver/Logos/0057.png b/Images/0057.png similarity index 100% rename from RotationSolver/Logos/0057.png rename to Images/0057.png diff --git a/RotationSolver/Logos/0058.png b/Images/0058.png similarity index 100% rename from RotationSolver/Logos/0058.png rename to Images/0058.png diff --git a/RotationSolver/Logos/0059.png b/Images/0059.png similarity index 100% rename from RotationSolver/Logos/0059.png rename to Images/0059.png diff --git a/RotationSolver/Logos/0060.png b/Images/0060.png similarity index 100% rename from RotationSolver/Logos/0060.png rename to Images/0060.png diff --git a/RotationSolver/Logos/0061.png b/Images/0061.png similarity index 100% rename from RotationSolver/Logos/0061.png rename to Images/0061.png diff --git a/RotationSolver/Logos/0062.png b/Images/0062.png similarity index 100% rename from RotationSolver/Logos/0062.png rename to Images/0062.png diff --git a/RotationSolver/Logos/0063.png b/Images/0063.png similarity index 100% rename from RotationSolver/Logos/0063.png rename to Images/0063.png diff --git a/RotationSolver/Logos/0064.png b/Images/0064.png similarity index 100% rename from RotationSolver/Logos/0064.png rename to Images/0064.png diff --git a/RotationSolver/Logos/0065.png b/Images/0065.png similarity index 100% rename from RotationSolver/Logos/0065.png rename to Images/0065.png diff --git a/RotationSolver/Logos/0066.png b/Images/0066.png similarity index 100% rename from RotationSolver/Logos/0066.png rename to Images/0066.png diff --git a/RotationSolver/Logos/0067.png b/Images/0067.png similarity index 100% rename from RotationSolver/Logos/0067.png rename to Images/0067.png diff --git a/RotationSolver/Logos/0068.png b/Images/0068.png similarity index 100% rename from RotationSolver/Logos/0068.png rename to Images/0068.png diff --git a/RotationSolver/Logos/0069.png b/Images/0069.png similarity index 100% rename from RotationSolver/Logos/0069.png rename to Images/0069.png diff --git a/RotationSolver/Logos/0070.png b/Images/0070.png similarity index 100% rename from RotationSolver/Logos/0070.png rename to Images/0070.png diff --git a/RotationSolver/Logos/0071.png b/Images/0071.png similarity index 100% rename from RotationSolver/Logos/0071.png rename to Images/0071.png diff --git a/RotationSolver/Logos/0072.png b/Images/0072.png similarity index 100% rename from RotationSolver/Logos/0072.png rename to Images/0072.png diff --git a/RotationSolver/Logos/0073.png b/Images/0073.png similarity index 100% rename from RotationSolver/Logos/0073.png rename to Images/0073.png diff --git a/RotationSolver/Logos/0074.png b/Images/0074.png similarity index 100% rename from RotationSolver/Logos/0074.png rename to Images/0074.png diff --git a/RotationSolver/Logos/0075.png b/Images/0075.png similarity index 100% rename from RotationSolver/Logos/0075.png rename to Images/0075.png diff --git a/RotationSolver/Logos/0076.png b/Images/0076.png similarity index 100% rename from RotationSolver/Logos/0076.png rename to Images/0076.png diff --git a/RotationSolver/Logos/0077.png b/Images/0077.png similarity index 100% rename from RotationSolver/Logos/0077.png rename to Images/0077.png diff --git a/RotationSolver/Logos/0078.png b/Images/0078.png similarity index 100% rename from RotationSolver/Logos/0078.png rename to Images/0078.png diff --git a/RotationSolver/Logos/0079.png b/Images/0079.png similarity index 100% rename from RotationSolver/Logos/0079.png rename to Images/0079.png diff --git a/RotationSolver/Logos/0080.png b/Images/0080.png similarity index 100% rename from RotationSolver/Logos/0080.png rename to Images/0080.png diff --git a/RotationSolver/Logos/0081.png b/Images/0081.png similarity index 100% rename from RotationSolver/Logos/0081.png rename to Images/0081.png diff --git a/RotationSolver/Logos/0082.png b/Images/0082.png similarity index 100% rename from RotationSolver/Logos/0082.png rename to Images/0082.png diff --git a/RotationSolver/Logos/0083.png b/Images/0083.png similarity index 100% rename from RotationSolver/Logos/0083.png rename to Images/0083.png diff --git a/RotationSolver/Logos/0084.png b/Images/0084.png similarity index 100% rename from RotationSolver/Logos/0084.png rename to Images/0084.png diff --git a/RotationSolver/Logos/0085.png b/Images/0085.png similarity index 100% rename from RotationSolver/Logos/0085.png rename to Images/0085.png diff --git a/RotationSolver/Logos/0086.png b/Images/0086.png similarity index 100% rename from RotationSolver/Logos/0086.png rename to Images/0086.png diff --git a/RotationSolver/Logos/0087.png b/Images/0087.png similarity index 100% rename from RotationSolver/Logos/0087.png rename to Images/0087.png diff --git a/RotationSolver/Logos/0088.png b/Images/0088.png similarity index 100% rename from RotationSolver/Logos/0088.png rename to Images/0088.png diff --git a/RotationSolver/Logos/0089.png b/Images/0089.png similarity index 100% rename from RotationSolver/Logos/0089.png rename to Images/0089.png diff --git a/RotationSolver/Logos/0090.png b/Images/0090.png similarity index 100% rename from RotationSolver/Logos/0090.png rename to Images/0090.png diff --git a/RotationSolver/Logos/0091.png b/Images/0091.png similarity index 100% rename from RotationSolver/Logos/0091.png rename to Images/0091.png diff --git a/RotationSolver/Logos/0092.png b/Images/0092.png similarity index 100% rename from RotationSolver/Logos/0092.png rename to Images/0092.png diff --git a/RotationSolver/Logos/0093.png b/Images/0093.png similarity index 100% rename from RotationSolver/Logos/0093.png rename to Images/0093.png diff --git a/RotationSolver/Logos/0094.png b/Images/0094.png similarity index 100% rename from RotationSolver/Logos/0094.png rename to Images/0094.png diff --git a/RotationSolver/Logos/0095.png b/Images/0095.png similarity index 100% rename from RotationSolver/Logos/0095.png rename to Images/0095.png diff --git a/RotationSolver/Logos/0096.png b/Images/0096.png similarity index 100% rename from RotationSolver/Logos/0096.png rename to Images/0096.png diff --git a/RotationSolver/Logos/0097.png b/Images/0097.png similarity index 100% rename from RotationSolver/Logos/0097.png rename to Images/0097.png diff --git a/RotationSolver/Logos/0098.png b/Images/0098.png similarity index 100% rename from RotationSolver/Logos/0098.png rename to Images/0098.png diff --git a/RotationSolver/Logos/0099.png b/Images/0099.png similarity index 100% rename from RotationSolver/Logos/0099.png rename to Images/0099.png diff --git a/RotationSolver/Logos/0100.png b/Images/0100.png similarity index 100% rename from RotationSolver/Logos/0100.png rename to Images/0100.png diff --git a/RotationSolver/Logos/0101.png b/Images/0101.png similarity index 100% rename from RotationSolver/Logos/0101.png rename to Images/0101.png diff --git a/RotationSolver/Logos/0102.png b/Images/0102.png similarity index 100% rename from RotationSolver/Logos/0102.png rename to Images/0102.png diff --git a/RotationSolver/Logos/0103.png b/Images/0103.png similarity index 100% rename from RotationSolver/Logos/0103.png rename to Images/0103.png diff --git a/RotationSolver/Logos/0104.png b/Images/0104.png similarity index 100% rename from RotationSolver/Logos/0104.png rename to Images/0104.png diff --git a/RotationSolver/Logos/0105.png b/Images/0105.png similarity index 100% rename from RotationSolver/Logos/0105.png rename to Images/0105.png diff --git a/RotationSolver/Logos/0106.png b/Images/0106.png similarity index 100% rename from RotationSolver/Logos/0106.png rename to Images/0106.png diff --git a/RotationSolver/Logos/0107.png b/Images/0107.png similarity index 100% rename from RotationSolver/Logos/0107.png rename to Images/0107.png diff --git a/RotationSolver/Logos/0108.png b/Images/0108.png similarity index 100% rename from RotationSolver/Logos/0108.png rename to Images/0108.png diff --git a/RotationSolver/Logos/0109.png b/Images/0109.png similarity index 100% rename from RotationSolver/Logos/0109.png rename to Images/0109.png diff --git a/RotationSolver/Logos/0110.png b/Images/0110.png similarity index 100% rename from RotationSolver/Logos/0110.png rename to Images/0110.png diff --git a/RotationSolver/Logos/0111.png b/Images/0111.png similarity index 100% rename from RotationSolver/Logos/0111.png rename to Images/0111.png diff --git a/RotationSolver/Logos/0112.png b/Images/0112.png similarity index 100% rename from RotationSolver/Logos/0112.png rename to Images/0112.png diff --git a/RotationSolver/Logos/0113.png b/Images/0113.png similarity index 100% rename from RotationSolver/Logos/0113.png rename to Images/0113.png diff --git a/RotationSolver/Logos/0114.png b/Images/0114.png similarity index 100% rename from RotationSolver/Logos/0114.png rename to Images/0114.png diff --git a/RotationSolver/Logos/0115.png b/Images/0115.png similarity index 100% rename from RotationSolver/Logos/0115.png rename to Images/0115.png diff --git a/RotationSolver/Logos/0116.png b/Images/0116.png similarity index 100% rename from RotationSolver/Logos/0116.png rename to Images/0116.png diff --git a/RotationSolver/Logos/0117.png b/Images/0117.png similarity index 100% rename from RotationSolver/Logos/0117.png rename to Images/0117.png diff --git a/RotationSolver/Logos/0118.png b/Images/0118.png similarity index 100% rename from RotationSolver/Logos/0118.png rename to Images/0118.png diff --git a/RotationSolver/Logos/0119.png b/Images/0119.png similarity index 100% rename from RotationSolver/Logos/0119.png rename to Images/0119.png diff --git a/RotationSolver/Logos/0120.png b/Images/0120.png similarity index 100% rename from RotationSolver/Logos/0120.png rename to Images/0120.png diff --git a/RotationSolver/Logos/0121.png b/Images/0121.png similarity index 100% rename from RotationSolver/Logos/0121.png rename to Images/0121.png diff --git a/RotationSolver/Logos/0122.png b/Images/0122.png similarity index 100% rename from RotationSolver/Logos/0122.png rename to Images/0122.png diff --git a/RotationSolver/Logos/0123.png b/Images/0123.png similarity index 100% rename from RotationSolver/Logos/0123.png rename to Images/0123.png diff --git a/RotationSolver/Logos/0124.png b/Images/0124.png similarity index 100% rename from RotationSolver/Logos/0124.png rename to Images/0124.png diff --git a/RotationSolver/Logos/0125.png b/Images/0125.png similarity index 100% rename from RotationSolver/Logos/0125.png rename to Images/0125.png diff --git a/RotationSolver/Logos/0126.png b/Images/0126.png similarity index 100% rename from RotationSolver/Logos/0126.png rename to Images/0126.png diff --git a/RotationSolver/Logos/0127.png b/Images/0127.png similarity index 100% rename from RotationSolver/Logos/0127.png rename to Images/0127.png diff --git a/RotationSolver/Logos/0128.png b/Images/0128.png similarity index 100% rename from RotationSolver/Logos/0128.png rename to Images/0128.png diff --git a/RotationSolver/Logos/0129.png b/Images/0129.png similarity index 100% rename from RotationSolver/Logos/0129.png rename to Images/0129.png diff --git a/RotationSolver/Logos/0130.png b/Images/0130.png similarity index 100% rename from RotationSolver/Logos/0130.png rename to Images/0130.png diff --git a/RotationSolver/Logos/0131.png b/Images/0131.png similarity index 100% rename from RotationSolver/Logos/0131.png rename to Images/0131.png diff --git a/RotationSolver/Logos/0132.png b/Images/0132.png similarity index 100% rename from RotationSolver/Logos/0132.png rename to Images/0132.png diff --git a/RotationSolver/Logos/0133.png b/Images/0133.png similarity index 100% rename from RotationSolver/Logos/0133.png rename to Images/0133.png diff --git a/RotationSolver/Logos/0134.png b/Images/0134.png similarity index 100% rename from RotationSolver/Logos/0134.png rename to Images/0134.png diff --git a/RotationSolver/Logos/0135.png b/Images/0135.png similarity index 100% rename from RotationSolver/Logos/0135.png rename to Images/0135.png diff --git a/RotationSolver/Logos/0136.png b/Images/0136.png similarity index 100% rename from RotationSolver/Logos/0136.png rename to Images/0136.png diff --git a/RotationSolver/Logos/0137.png b/Images/0137.png similarity index 100% rename from RotationSolver/Logos/0137.png rename to Images/0137.png diff --git a/RotationSolver/Logos/0138.png b/Images/0138.png similarity index 100% rename from RotationSolver/Logos/0138.png rename to Images/0138.png diff --git a/RotationSolver/Logos/0139.png b/Images/0139.png similarity index 100% rename from RotationSolver/Logos/0139.png rename to Images/0139.png diff --git a/RotationSolver/Logos/0140.png b/Images/0140.png similarity index 100% rename from RotationSolver/Logos/0140.png rename to Images/0140.png diff --git a/RotationSolver/Logos/0141.png b/Images/0141.png similarity index 100% rename from RotationSolver/Logos/0141.png rename to Images/0141.png diff --git a/RotationSolver/Logos/0142.png b/Images/0142.png similarity index 100% rename from RotationSolver/Logos/0142.png rename to Images/0142.png diff --git a/RotationSolver/Logos/0143.png b/Images/0143.png similarity index 100% rename from RotationSolver/Logos/0143.png rename to Images/0143.png diff --git a/RotationSolver/Logos/0144.png b/Images/0144.png similarity index 100% rename from RotationSolver/Logos/0144.png rename to Images/0144.png diff --git a/RotationSolver/Logos/0145.png b/Images/0145.png similarity index 100% rename from RotationSolver/Logos/0145.png rename to Images/0145.png diff --git a/RotationSolver/Logos/0146.png b/Images/0146.png similarity index 100% rename from RotationSolver/Logos/0146.png rename to Images/0146.png diff --git a/RotationSolver/Logos/0147.png b/Images/0147.png similarity index 100% rename from RotationSolver/Logos/0147.png rename to Images/0147.png diff --git a/RotationSolver/Logos/0148.png b/Images/0148.png similarity index 100% rename from RotationSolver/Logos/0148.png rename to Images/0148.png diff --git a/RotationSolver/Logos/0149.png b/Images/0149.png similarity index 100% rename from RotationSolver/Logos/0149.png rename to Images/0149.png diff --git a/RotationSolver/Logos/0150.png b/Images/0150.png similarity index 100% rename from RotationSolver/Logos/0150.png rename to Images/0150.png diff --git a/RotationSolver/Logos/0151.png b/Images/0151.png similarity index 100% rename from RotationSolver/Logos/0151.png rename to Images/0151.png diff --git a/RotationSolver/Logos/0152.png b/Images/0152.png similarity index 100% rename from RotationSolver/Logos/0152.png rename to Images/0152.png diff --git a/RotationSolver/Logos/0153.png b/Images/0153.png similarity index 100% rename from RotationSolver/Logos/0153.png rename to Images/0153.png diff --git a/RotationSolver/Logos/0154.png b/Images/0154.png similarity index 100% rename from RotationSolver/Logos/0154.png rename to Images/0154.png diff --git a/RotationSolver/Logos/0155.png b/Images/0155.png similarity index 100% rename from RotationSolver/Logos/0155.png rename to Images/0155.png diff --git a/RotationSolver/Logos/0156.png b/Images/0156.png similarity index 100% rename from RotationSolver/Logos/0156.png rename to Images/0156.png diff --git a/RotationSolver/Logos/0157.png b/Images/0157.png similarity index 100% rename from RotationSolver/Logos/0157.png rename to Images/0157.png diff --git a/RotationSolver/Logos/0158.png b/Images/0158.png similarity index 100% rename from RotationSolver/Logos/0158.png rename to Images/0158.png diff --git a/RotationSolver/Logos/0159.png b/Images/0159.png similarity index 100% rename from RotationSolver/Logos/0159.png rename to Images/0159.png diff --git a/RotationSolver/Logos/0160.png b/Images/0160.png similarity index 100% rename from RotationSolver/Logos/0160.png rename to Images/0160.png diff --git a/RotationSolver/Logos/0161.png b/Images/0161.png similarity index 100% rename from RotationSolver/Logos/0161.png rename to Images/0161.png diff --git a/RotationSolver/Logos/0162.png b/Images/0162.png similarity index 100% rename from RotationSolver/Logos/0162.png rename to Images/0162.png diff --git a/RotationSolver/Logos/0163.png b/Images/0163.png similarity index 100% rename from RotationSolver/Logos/0163.png rename to Images/0163.png diff --git a/RotationSolver/Logos/0164.png b/Images/0164.png similarity index 100% rename from RotationSolver/Logos/0164.png rename to Images/0164.png diff --git a/RotationSolver/Logos/0165.png b/Images/0165.png similarity index 100% rename from RotationSolver/Logos/0165.png rename to Images/0165.png diff --git a/RotationSolver/Logos/0166.png b/Images/0166.png similarity index 100% rename from RotationSolver/Logos/0166.png rename to Images/0166.png diff --git a/RotationSolver/Logos/0167.png b/Images/0167.png similarity index 100% rename from RotationSolver/Logos/0167.png rename to Images/0167.png diff --git a/RotationSolver/Logos/0168.png b/Images/0168.png similarity index 100% rename from RotationSolver/Logos/0168.png rename to Images/0168.png diff --git a/RotationSolver/Logos/0169.png b/Images/0169.png similarity index 100% rename from RotationSolver/Logos/0169.png rename to Images/0169.png diff --git a/RotationSolver/Logos/0170.png b/Images/0170.png similarity index 100% rename from RotationSolver/Logos/0170.png rename to Images/0170.png diff --git a/RotationSolver/Logos/0171.png b/Images/0171.png similarity index 100% rename from RotationSolver/Logos/0171.png rename to Images/0171.png diff --git a/RotationSolver/Logos/0172.png b/Images/0172.png similarity index 100% rename from RotationSolver/Logos/0172.png rename to Images/0172.png diff --git a/RotationSolver/Logos/0173.png b/Images/0173.png similarity index 100% rename from RotationSolver/Logos/0173.png rename to Images/0173.png diff --git a/RotationSolver/Logos/0174.png b/Images/0174.png similarity index 100% rename from RotationSolver/Logos/0174.png rename to Images/0174.png diff --git a/RotationSolver/Logos/0175.png b/Images/0175.png similarity index 100% rename from RotationSolver/Logos/0175.png rename to Images/0175.png diff --git a/RotationSolver/Logos/0176.png b/Images/0176.png similarity index 100% rename from RotationSolver/Logos/0176.png rename to Images/0176.png diff --git a/RotationSolver/Logos/0177.png b/Images/0177.png similarity index 100% rename from RotationSolver/Logos/0177.png rename to Images/0177.png diff --git a/RotationSolver/Logos/0178.png b/Images/0178.png similarity index 100% rename from RotationSolver/Logos/0178.png rename to Images/0178.png diff --git a/RotationSolver/Logos/0179.png b/Images/0179.png similarity index 100% rename from RotationSolver/Logos/0179.png rename to Images/0179.png diff --git a/RotationSolver/Logos/0180.png b/Images/0180.png similarity index 100% rename from RotationSolver/Logos/0180.png rename to Images/0180.png diff --git a/Resources/HostileCastingArea.json b/Resources/HostileCastingArea.json index 6b213f0c6..3160eacdb 100644 --- a/Resources/HostileCastingArea.json +++ b/Resources/HostileCastingArea.json @@ -420,5 +420,15 @@ 35385, 36093, 35420, - 36091 + 36091, + 30981, + 30961, + 30974, + 35274, + 35268, + 35284, + 35279, + 35312, + 35280, + 35269 ] \ No newline at end of file diff --git a/Resources/RotationSolverRecord.json b/Resources/RotationSolverRecord.json index 2591d95a1..f0434ee9b 100644 --- a/Resources/RotationSolverRecord.json +++ b/Resources/RotationSolverRecord.json @@ -1,4 +1,4 @@ { - "ClickingCount": 12212, + "ClickingCount": 17599, "SaidUsers": [] } \ No newline at end of file diff --git a/RotationSolver.Basic/Configuration/Conditions/ActionCondition.cs b/RotationSolver.Basic/Configuration/Conditions/ActionCondition.cs new file mode 100644 index 000000000..404077b71 --- /dev/null +++ b/RotationSolver.Basic/Configuration/Conditions/ActionCondition.cs @@ -0,0 +1,80 @@ +namespace RotationSolver.Basic.Configuration.Conditions; + +internal class ActionCondition : DelayCondition +{ + internal IBaseAction _action; + + public ActionID ID { get; set; } = ActionID.None; + + public ActionConditionType ActionConditionType = ActionConditionType.Elapsed; + + public bool Condition { get; set; } + + public int Param1; + public int Param2; + public float Time; + + public override bool CheckBefore(ICustomRotation rotation) + { + return CheckBaseAction(rotation, ID, ref _action) && base.CheckBefore(rotation); + } + + public override bool IsTrueInside(ICustomRotation rotation) + { + var result = false; + + switch (ActionConditionType) + { + case ActionConditionType.Elapsed: + result = _action.ElapsedOneChargeAfter(Time); // Bigger + break; + + case ActionConditionType.ElapsedGCD: + result = _action.ElapsedOneChargeAfterGCD((uint)Param1, Param2); // Bigger + break; + + case ActionConditionType.Remain: + result = !_action.WillHaveOneCharge(Time); //Smaller + break; + + case ActionConditionType.RemainGCD: + result = !_action.WillHaveOneChargeGCD((uint)Param1, Param2); // Smaller + break; + + case ActionConditionType.CanUse: + result = _action.CanUse(out _, (CanUseOption)Param1, (byte)Param2); + break; + + case ActionConditionType.EnoughLevel: + result = _action.EnoughLevel; + break; + + case ActionConditionType.IsCoolDown: + result = _action.IsCoolingDown; + break; + + case ActionConditionType.CurrentCharges: + result = _action.CurrentCharges > Param1; + break; + + case ActionConditionType.MaxCharges: + result = _action.MaxCharges > Param1; + break; + } + + return Condition ? !result : result; + } +} + +internal enum ActionConditionType : byte +{ + Elapsed, + ElapsedGCD, + Remain, + RemainGCD, + CanUse, + EnoughLevel, + IsCoolDown, + CurrentCharges, + MaxCharges, +} diff --git a/RotationSolver.Basic/Configuration/Conditions/ConditionSet.cs b/RotationSolver.Basic/Configuration/Conditions/ConditionSet.cs new file mode 100644 index 000000000..78e18ff1c --- /dev/null +++ b/RotationSolver.Basic/Configuration/Conditions/ConditionSet.cs @@ -0,0 +1,30 @@ +namespace RotationSolver.Basic.Configuration.Conditions; + +internal class ConditionSet : DelayCondition +{ + public List Conditions { get; set; } = new List(); + + public LogicalType Type; + + public override bool IsTrueInside(ICustomRotation rotation) + { + if (Conditions.Count == 0) return false; + + return Type switch + { + LogicalType.And => Conditions.All(c => c.IsTrue(rotation)), + LogicalType.Or => Conditions.Any(c => c.IsTrue(rotation)), + LogicalType.NotAnd => !Conditions.All(c => c.IsTrue(rotation)), + LogicalType.NotOr => !Conditions.Any(c => c.IsTrue(rotation)), + _ => false, + }; + } +} + +internal enum LogicalType : byte +{ + And, + Or, + NotAnd, + NotOr, +} diff --git a/RotationSolver.Basic/Configuration/Conditions/DelayCondition.cs b/RotationSolver.Basic/Configuration/Conditions/DelayCondition.cs new file mode 100644 index 000000000..1d1a5ad75 --- /dev/null +++ b/RotationSolver.Basic/Configuration/Conditions/DelayCondition.cs @@ -0,0 +1,63 @@ +using ECommons.GameHelpers; + +namespace RotationSolver.Basic.Configuration.Conditions; + +internal abstract class DelayCondition : ICondition +{ + public float DelayMin = 0; + public float DelayMax = 0; + + RandomDelay _delay = default; + + public bool IsTrue(ICustomRotation rotation) + { + if (_delay.GetRange == null) + { + _delay = new(() => (DelayMin, DelayMax)); + } + + return _delay.Delay(CheckBefore(rotation) && IsTrueInside(rotation)); + } + + public abstract bool IsTrueInside(ICustomRotation rotation); + + public virtual bool CheckBefore(ICustomRotation rotation) + { + return Player.Available; + } + + internal static bool CheckBaseAction(ICustomRotation rotation, ActionID id, ref IBaseAction action) + { + if (id != ActionID.None && (action == null || (ActionID)action.ID != id)) + { + action = rotation.AllBaseActions.FirstOrDefault(a => (ActionID)a.ID == id); + } + if (action == null) return false; + return true; + } + + internal static bool CheckMemberInfo(ICustomRotation rotation, ref string name, ref T value) where T : MemberInfo + { + if (!string.IsNullOrEmpty(name) && (value == null || value.Name != name)) + { + var memberName = name; + if (typeof(T).IsAssignableFrom(typeof(PropertyInfo))) + { + value = (T)GetAllMethods(rotation.GetType(), RuntimeReflectionExtensions.GetRuntimeProperties).FirstOrDefault(m => m.Name == memberName); + } + else if (typeof(T).IsAssignableFrom(typeof(MethodInfo))) + { + value = (T)GetAllMethods(rotation.GetType(), RuntimeReflectionExtensions.GetRuntimeMethods).FirstOrDefault(m => m.Name == memberName); + } + } + return true; + } + + private static IEnumerable GetAllMethods(Type type, Func> getFunc) + { + if (type == null || getFunc == null) return Array.Empty(); + + var methods = getFunc(type); + return methods.Union(GetAllMethods(type.BaseType, getFunc)); + } +} diff --git a/RotationSolver.Basic/Configuration/Conditions/ICondition.cs b/RotationSolver.Basic/Configuration/Conditions/ICondition.cs new file mode 100644 index 000000000..9de2d682f --- /dev/null +++ b/RotationSolver.Basic/Configuration/Conditions/ICondition.cs @@ -0,0 +1,7 @@ +namespace RotationSolver.Basic.Configuration.Conditions; + +internal interface ICondition +{ + bool IsTrue(ICustomRotation rotation); + bool CheckBefore(ICustomRotation rotation); +} \ No newline at end of file diff --git a/RotationSolver/ActionSequencer/IConditionConverter.cs b/RotationSolver.Basic/Configuration/Conditions/IConditionConverter.cs similarity index 93% rename from RotationSolver/ActionSequencer/IConditionConverter.cs rename to RotationSolver.Basic/Configuration/Conditions/IConditionConverter.cs index 84aa2c105..4b1400771 100644 --- a/RotationSolver/ActionSequencer/IConditionConverter.cs +++ b/RotationSolver.Basic/Configuration/Conditions/IConditionConverter.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json.Linq; -namespace RotationSolver.ActionSequencer; +namespace RotationSolver.Basic.Configuration.Conditions; internal class IConditionConverter : JsonCreationConverter { @@ -38,7 +38,7 @@ private static bool FieldExists(string fieldName, JObject jObject) } } -public abstract class JsonCreationConverter : JsonConverter +internal abstract class JsonCreationConverter : JsonConverter { protected abstract T Create(JObject jObject); diff --git a/RotationSolver.Basic/Configuration/Conditions/MajorConditionSet.cs b/RotationSolver.Basic/Configuration/Conditions/MajorConditionSet.cs new file mode 100644 index 000000000..79f109da2 --- /dev/null +++ b/RotationSolver.Basic/Configuration/Conditions/MajorConditionSet.cs @@ -0,0 +1,135 @@ +using ECommons.DalamudServices; +using ECommons.ExcelServices; + +namespace RotationSolver.Basic.Configuration.Conditions; + +internal class MajorConditionSet +{ + const string conditionName = "Unnamed"; + + [JsonIgnore] + public bool IsUnnamed => Name == conditionName; + + /// + /// Key for action id. + /// + public Dictionary> Conditions { get; } = new(); + + [JsonIgnore] + public Dictionary ConditionDict + { + get + { + if (!Conditions.TryGetValue(DataCenter.Job, out var dict)) + { + dict = Conditions[DataCenter.Job] = new(); + } + return dict; + } + } + + public Dictionary> DisabledConditions { get; } = new(); + + [JsonIgnore] + public Dictionary DisableConditionDict + { + get + { + if (!DisabledConditions.TryGetValue(DataCenter.Job, out var dict)) + { + dict = DisabledConditions[DataCenter.Job] = new(); + } + return dict; + } + } + + public Dictionary ForceEnableConditions { get; private set; } + = new(); + + public Dictionary ForceDisableConditions { get; private set; } + = new(); + + public ConditionSet HealAreaConditionSet { get; set; } = new ConditionSet(); + public ConditionSet HealSingleConditionSet { get; set; } = new ConditionSet(); + public ConditionSet DefenseAreaConditionSet { get; set; } = new ConditionSet(); + public ConditionSet DefenseSingleConditionSet { get; set; } = new ConditionSet(); + public ConditionSet EsunaStanceNorthConditionSet { get; set; } = new ConditionSet(); + public ConditionSet RaiseShirkConditionSet { get; set; } = new ConditionSet(); + public ConditionSet MoveForwardConditionSet { get; set; } = new ConditionSet(); + public ConditionSet MoveBackConditionSet { get; set; } = new ConditionSet(); + public ConditionSet AntiKnockbackConditionSet { get; set; } = new ConditionSet(); + public ConditionSet BurstConditionSet { get; set; } = new ConditionSet(); + public ConditionSet SpeedConditionSet { get; set; } = new ConditionSet(); + + public string Name; + + public ConditionSet GetCondition(uint id) + { + if (!ConditionDict.TryGetValue(id, out var conditionSet)) + { + conditionSet = ConditionDict[id] = new ConditionSet(); + } + return conditionSet; + } + + public ConditionSet GetDisabledCondition(uint id) + { + if (!DisableConditionDict.TryGetValue(id, out var conditionSet)) + { + conditionSet = DisableConditionDict[id] = new ConditionSet(); + } + return conditionSet; + } + + public ConditionSet GetEnableCondition(PluginConfigBool config) + { + if (!ForceEnableConditions.TryGetValue(config, out var conditionSet)) + { + conditionSet = ForceEnableConditions[config] = new ConditionSet(); + } + return conditionSet; + } + + public ConditionSet GetDisableCondition(PluginConfigBool config) + { + if (!ForceDisableConditions.TryGetValue(config, out var conditionSet)) + { + conditionSet = ForceDisableConditions[config] = new ConditionSet(); + } + return conditionSet; + } + + public MajorConditionSet(string name = conditionName) + { + Name = name; + } + + public void Save(string folder) + { + if (!Directory.Exists(folder)) return; + var path = Path.Combine(folder, Name + ".json"); + + var str = JsonConvert.SerializeObject(this, Formatting.Indented); + File.WriteAllText(path, str); + } + + public static MajorConditionSet[] Read(string folder) + { + if (!Directory.Exists(folder)) return Array.Empty(); + + return Directory.EnumerateFiles(folder, "*.json").Select(p => + { + var str = File.ReadAllText(p); + + try + { + return JsonConvert.DeserializeObject(str, new IConditionConverter()); + } + catch + { + Svc.Chat.Print($"Failed to load the conditionSet from {p}"); + return null; + } + }).Where(set => set != null && !string.IsNullOrEmpty(set.Name)).ToArray(); + } +} diff --git a/RotationSolver.Basic/Configuration/Conditions/RotationCondition.cs b/RotationSolver.Basic/Configuration/Conditions/RotationCondition.cs new file mode 100644 index 000000000..9ef4752a1 --- /dev/null +++ b/RotationSolver.Basic/Configuration/Conditions/RotationCondition.cs @@ -0,0 +1,112 @@ +namespace RotationSolver.Basic.Configuration.Conditions; + +internal class RotationCondition : DelayCondition +{ + public ComboConditionType ComboConditionType = ComboConditionType.Float; + internal PropertyInfo _prop; + public string PropertyName = nameof(CustomRotation.CombatTime); + + MethodInfo _method; + public string MethodName = string.Empty; + + internal IBaseAction _action; + public ActionID ID { get; set; } = ActionID.None; + + public int Condition; + + public int Param1; + public float Param2; + + + public override bool CheckBefore(ICustomRotation rotation) + { + return CheckBaseAction(rotation, ID, ref _action) + && CheckMemberInfo(rotation, ref PropertyName, ref _prop) + && CheckMemberInfo(rotation, ref MethodName, ref _method) + && base.CheckBefore(rotation); + } + + public override bool IsTrueInside(ICustomRotation rotation) + { + switch (ComboConditionType) + { + case ComboConditionType.Bool: + if (_prop == null) return false; + if (_prop.GetValue(rotation) is bool b) + { + return Condition > 0 ? !b : b; + } + return false; + + case ComboConditionType.Integer: + if (_prop == null) return false; + + var value = _prop.GetValue(rotation); + if (value is byte by) + { + switch (Condition) + { + case 0: + return by > Param1; + case 1: + return by < Param1; + case 2: + return by == Param1; + } + } + else if (value is int i) + { + switch (Condition) + { + case 0: + return i > Param1; + case 1: + return i < Param1; + case 2: + return i == Param1; + } + } + return false; + + case ComboConditionType.Float: + if (_prop == null) return false; + if (_prop.GetValue(rotation) is float fl) + { + switch (Condition) + { + case 0: + return fl > Param2; + case 1: + return fl < Param2; + case 2: + return fl == Param2; + } + } + return false; + + case ComboConditionType.Last: + try + { + if (_method?.Invoke(rotation, new object[] { Param1 > 0, new IAction[] { _action } }) is bool boo) + { + return Condition > 0 ? !boo : boo; + } + return false; + } + catch + { + return false; + } + } + + return false; + } +} + +internal enum ComboConditionType : byte +{ + Bool, + Integer, + Float, + Last, +} diff --git a/RotationSolver.Basic/Configuration/Conditions/TargetCondition.cs b/RotationSolver.Basic/Configuration/Conditions/TargetCondition.cs new file mode 100644 index 000000000..fb1c0b299 --- /dev/null +++ b/RotationSolver.Basic/Configuration/Conditions/TargetCondition.cs @@ -0,0 +1,128 @@ +using ECommons.DalamudServices; +using ECommons.GameHelpers; +using Lumina.Excel.GeneratedSheets; + +namespace RotationSolver.Basic.Configuration.Conditions; + +internal class TargetCondition : DelayCondition +{ + internal IBaseAction _action; + public ActionID ID { get; set; } = ActionID.None; + + public bool Condition; + public bool FromSelf; + internal Status Status; + public StatusID StatusId { get; set; } + public bool IsTarget; + public TargetConditionType TargetConditionType; + + public float DistanceOrTime; + public int GCD; + + public string CastingActionName = string.Empty; + + public override bool IsTrueInside(ICustomRotation rotation) + { + BattleChara tar; + if (_action != null) + { + _action.CanUse(out _, CanUseOption.EmptyOrSkipCombo | CanUseOption.MustUse + | CanUseOption.IgnoreTarget); + tar = _action.Target; + } + else + { + tar = IsTarget ? Svc.Targets.Target as BattleChara : Player.Object; + tar ??= Player.Object; + } + + if (tar == null) return false; + + var result = false; + + switch (TargetConditionType) + { + case TargetConditionType.HasStatus: + result = tar.HasStatus(FromSelf, StatusId); + break; + + case TargetConditionType.IsBoss: + result = tar.IsBoss(); + break; + + case TargetConditionType.IsDying: + result = tar.IsDying(); + break; + + case TargetConditionType.InCombat: + result = tar.InCombat(); + break; + + case TargetConditionType.Distance: + result = tar.DistanceToPlayer() > DistanceOrTime; + break; + + case TargetConditionType.StatusEnd: + result = !tar.WillStatusEnd(DistanceOrTime, FromSelf, StatusId); + break; + + case TargetConditionType.StatusEndGCD: + result = !tar.WillStatusEndGCD((uint)GCD, DistanceOrTime, FromSelf, StatusId); + break; + + case TargetConditionType.TimeToKill: + result = tar.GetTimeToKill() > DistanceOrTime; + break; + + case TargetConditionType.CastingAction: + if (string.IsNullOrEmpty(CastingActionName) || tar.CastActionId == 0) + { + result = false; + break; + } + + var castName = Service.GetSheet().GetRow(tar.CastActionId)?.Name.ToString(); + + result = CastingActionName == castName; + break; + + case TargetConditionType.CastingActionTimeUntil: + + if (!tar.IsCasting || tar.CastActionId == 0) + { + result = false; + break; + } + + float castTime = tar.TotalCastTime - tar.CurrentCastTime; + result = castTime > DistanceOrTime + DataCenter.WeaponRemain; + break; + + case TargetConditionType.HP: + result = tar.CurrentHp > GCD; + break; + + case TargetConditionType.MP: + result = tar.CurrentMp > GCD; + break; + } + + return Condition ? !result : result; + } +} + +internal enum TargetConditionType : byte +{ + HasStatus, + IsDying, + IsBoss, + InCombat, + Distance, + StatusEnd, + StatusEndGCD, + CastingAction, + CastingActionTimeUntil, + TimeToKill, + HP, + MP, +} \ No newline at end of file diff --git a/RotationSolver.Basic/Configuration/Conditions/TraitCondition.cs b/RotationSolver.Basic/Configuration/Conditions/TraitCondition.cs new file mode 100644 index 000000000..4e0e1ca2e --- /dev/null +++ b/RotationSolver.Basic/Configuration/Conditions/TraitCondition.cs @@ -0,0 +1,28 @@ +using ECommons.GameHelpers; +using RotationSolver.Basic.Traits; + +namespace RotationSolver.Basic.Configuration.Conditions; + +internal class TraitCondition : DelayCondition +{ + public uint TraitID { get; set; } = 0; + internal IBaseTrait _trait; + public bool Condition { get; set; } + + public override bool CheckBefore(ICustomRotation rotation) + { + if (TraitID != 0 && (_trait == null || _trait.ID != TraitID)) + { + _trait = rotation.AllTraits.FirstOrDefault(a => a.ID == TraitID); + } + return base.CheckBefore(rotation); + } + + public override bool IsTrueInside(ICustomRotation rotation) + { + if (_trait == null || !Player.Available) return false; + + var result = _trait.EnoughLevel; + return Condition ? !result : result; + } +} diff --git a/RotationSolver.Basic/Configuration/Configs.cs b/RotationSolver.Basic/Configuration/Configs.cs index 4d21d47d3..1899fa440 100644 --- a/RotationSolver.Basic/Configuration/Configs.cs +++ b/RotationSolver.Basic/Configuration/Configs.cs @@ -2,6 +2,9 @@ using Dalamud.Utility; using ECommons.DalamudServices; using ECommons.ExcelServices; +using FFXIVClientStructs.STD; +using RotationSolver.Basic.Configuration.Conditions; +using System; namespace RotationSolver.Basic.Configuration; @@ -20,7 +23,7 @@ public static PluginConfig Create() } [JsonProperty] - private Dictionary _jobsConfig = new(); + private readonly Dictionary _jobsConfig = new(); public GlobalConfig GlobalConfig { get; private set; } = new(); public int Version { get; set; } = 7; @@ -34,8 +37,26 @@ public int GetValue(PluginConfigInt config) => GlobalConfig.Ints.GetValue(config); public bool GetValue(PluginConfigBool config) + { + var rotation = DataCenter.RightNowRotation; + var set = DataCenter.RightSet; + if (rotation != null && set != null) + { + if (GetEnableBoolRaw(config) && set.GetEnableCondition(config).IsTrue(rotation)) return true; + if (GetDisableBoolRaw(config) && set.GetDisableCondition(config).IsTrue(rotation)) return false; + } + + return GetBoolRaw(config); + } + + public bool GetBoolRaw(PluginConfigBool config) => GlobalConfig.Bools.GetValue(config); + public bool GetDisableBoolRaw(PluginConfigBool config) + => GlobalConfig.ForcedDisableBools.GetValue(config); + public bool GetEnableBoolRaw(PluginConfigBool config) + => GlobalConfig.ForcedEnableBools.GetValue(config); + public float GetValue(PluginConfigFloat config) => GlobalConfig.Floats.GetValue(config); @@ -51,7 +72,7 @@ public float GetDefault(Job job, JobConfigFloat config) public int GetDefault(PluginConfigInt config) => GlobalConfig.Ints.GetDefault(config); - public bool GetDefault(PluginConfigBool config) + public bool GetBoolRawDefault(PluginConfigBool config) => GlobalConfig.Bools.GetDefault(config); public float GetDefault(PluginConfigFloat config) @@ -101,9 +122,12 @@ public void SetValue(PluginConfigInt config, int value) } GlobalConfig.Ints.SetValue(config, value); } - public void SetValue(PluginConfigBool config, bool value) + public void SetBoolRaw(PluginConfigBool config, bool value) => GlobalConfig.Bools.SetValue(config, value); - + public void SetDisableBoolRaw(PluginConfigBool config, bool value) + => GlobalConfig.ForcedDisableBools.SetValue(config, value); + public void SetEnableBoolRaw(PluginConfigBool config, bool value) + => GlobalConfig.ForcedEnableBools.SetValue(config, value); public void SetValue(PluginConfigFloat config, float value) { var attr = config.GetAttribute(); @@ -177,6 +201,9 @@ [Serializable] public class GlobalConfig { public DictionConfig Ints { get; private set; } = new(); public DictionConfig Bools { get; private set; } = new(); + public DictionConfig ForcedEnableBools { get; private set; } = new(defaultGetter: cmd => false); + public DictionConfig ForcedDisableBools { get; private set; } = new(defaultGetter: cmd => false); + public DictionConfig Floats { get; private set; } = new(); public DictionConfig Vectors { get; private set; } = new(new() { @@ -456,13 +483,19 @@ public DefaultAttribute(object @default, object min = null, object max = null) [Serializable] public class DictionConfig where TConfig : struct, Enum { [JsonProperty] - private Dictionary configs = new (); + private readonly Dictionary configs = new (); private readonly SortedList _defaults; - public DictionConfig(SortedList @default = null) + private readonly Func _defaultGetter; + + public DictionConfig(SortedList @default = null, Func defaultGetter = null) { _defaults = @default; + _defaultGetter = defaultGetter ?? ((command) => + { + return (TValue)command.GetAttribute()?.Default ?? default; + }); } public TValue GetValue(TConfig command) @@ -471,7 +504,20 @@ public TValue GetValue(TConfig command) public TValue GetDefault(TConfig command) => _defaults?.TryGetValue(command, out var value) ?? false ? value - : (TValue)command.GetAttribute()?.Default ?? default; + : Get_Default(command); + + private TValue Get_Default(TConfig command) + { + try + { + return _defaultGetter(command); + } + catch (Exception ex) + { + Svc.Log.Warning(ex, "Failed to load the default value."); + return default; + } + } public void SetValue(TConfig command, TValue value) => configs[command] = value; diff --git a/RotationSolver.Basic/Configuration/OtherConfiguration.cs b/RotationSolver.Basic/Configuration/OtherConfiguration.cs index 29778d7cd..b1bc6fd5e 100644 --- a/RotationSolver.Basic/Configuration/OtherConfiguration.cs +++ b/RotationSolver.Basic/Configuration/OtherConfiguration.cs @@ -3,6 +3,7 @@ namespace RotationSolver.Basic.Configuration; #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CA2211 public class OtherConfiguration { public static HashSet HostileCastingArea = new(); @@ -98,78 +99,78 @@ public static void Init() Task.Run(() => InitOne(ref RotationSolverRecord, nameof(RotationSolverRecord), false)); } - public static void Save() + public static async Task Save() { - SaveDangerousStatus(); - SaveInvincibleStatus(); - SaveNoHostileNames(); - SaveAnimationLockTime(); - SaveHostileCastingArea(); - SaveHostileCastingTank(); - SaveBeneficialPositions(); - SaveRotationSolverRecord(); - SaveNoProvokeNames(); - SaveActionAOECounts(); - SaveActionTTK(); - SaveActionHealRatio(); + await SaveDangerousStatus(); + await SaveInvincibleStatus(); + await SaveNoHostileNames(); + await SaveAnimationLockTime(); + await SaveHostileCastingArea(); + await SaveHostileCastingTank(); + await SaveBeneficialPositions(); + await SaveRotationSolverRecord(); + await SaveNoProvokeNames(); + await SaveActionAOECounts(); + await SaveActionTTK(); + await SaveActionHealRatio(); } - public static void SaveActionHealRatio() + public static Task SaveActionHealRatio() { - Task.Run(() => Save(ActionHealRatio, nameof(ActionHealRatio))); + return Task.Run(() => Save(ActionHealRatio, nameof(ActionHealRatio))); } - public static void SaveActionTTK() + public static Task SaveActionTTK() { - Task.Run(() => Save(ActionTTK, nameof(ActionTTK))); + return Task.Run(() => Save(ActionTTK, nameof(ActionTTK))); } - public static void SaveActionAOECounts() + public static Task SaveActionAOECounts() { - Task.Run(() => Save(ActionAOECounts, nameof(ActionAOECounts))); + return Task.Run(() => Save(ActionAOECounts, nameof(ActionAOECounts))); } - public static void SaveRotationSolverRecord() + public static Task SaveRotationSolverRecord() { - Task.Run(() => Save(RotationSolverRecord, nameof(RotationSolverRecord))); + return Task.Run(() => Save(RotationSolverRecord, nameof(RotationSolverRecord))); } - public static void SaveNoProvokeNames() + public static Task SaveNoProvokeNames() { - Task.Run(() => Save(NoProvokeNames, nameof(NoProvokeNames))); + return Task.Run(() => Save(NoProvokeNames, nameof(NoProvokeNames))); } - public static void SaveBeneficialPositions() + public static Task SaveBeneficialPositions() { - Task.Run(() => Save(BeneficialPositions, nameof(BeneficialPositions))); + return Task.Run(() => Save(BeneficialPositions, nameof(BeneficialPositions))); } - public static void SaveHostileCastingArea() + public static Task SaveHostileCastingArea() { - Task.Run(() => Save(HostileCastingArea, nameof(HostileCastingArea))); + return Task.Run(() => Save(HostileCastingArea, nameof(HostileCastingArea))); } - public static void SaveHostileCastingTank() + public static Task SaveHostileCastingTank() { - Task.Run(() => Save(HostileCastingTank, nameof(HostileCastingTank))); + return Task.Run(() => Save(HostileCastingTank, nameof(HostileCastingTank))); } - public static void SaveDangerousStatus() + public static Task SaveDangerousStatus() { - Task.Run(() => Save(DangerousStatus, nameof(DangerousStatus))); + return Task.Run(() => Save(DangerousStatus, nameof(DangerousStatus))); } - public static void SaveInvincibleStatus() + public static Task SaveInvincibleStatus() { - Task.Run(() => Save(InvincibleStatus, nameof(InvincibleStatus))); + return Task.Run(() => Save(InvincibleStatus, nameof(InvincibleStatus))); } - public static void SaveNoHostileNames() + public static Task SaveNoHostileNames() { - Task.Run(() => Save(NoHostileNames, nameof(NoHostileNames))); + return Task.Run(() => Save(NoHostileNames, nameof(NoHostileNames))); } - public static void SaveAnimationLockTime() + public static Task SaveAnimationLockTime() { - Task.Run(() => Save(AnimationLockTime, nameof(AnimationLockTime))); + return Task.Run(() => Save(AnimationLockTime, nameof(AnimationLockTime))); } private static string GetFilePath(string name) @@ -220,7 +221,7 @@ private static void InitOne(ref T value, string name, bool download = true) { try { - var client = new HttpClient(); + using var client = new HttpClient(); var str = client.GetStringAsync($"https://raw.githubusercontent.com/{Service.USERNAME}/{Service.REPO}/main/Resources/{name}.json").Result; File.WriteAllText(path, str); @@ -244,4 +245,5 @@ private static void InitOne(ref T value, string name, bool download = true) } } } +#pragma warning restore CA2211 #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member \ No newline at end of file diff --git a/RotationSolver.Basic/Data/IconSet.cs b/RotationSolver.Basic/Data/IconSet.cs index 94517823c..f70786c61 100644 --- a/RotationSolver.Basic/Data/IconSet.cs +++ b/RotationSolver.Basic/Data/IconSet.cs @@ -124,11 +124,12 @@ public static bool GetTexture(uint id, out IDalamudTextureWrap texture, uint @de /// /// /// + /// /// - public static bool GetTexture(string path, out IDalamudTextureWrap texture) + public static bool GetTexture(string path, out IDalamudTextureWrap texture, bool loadingIcon = false) => ThreadLoadImageHandler.TryGetTextureWrap(path, out texture) - || (path.StartsWith("http:", StringComparison.OrdinalIgnoreCase) || path.StartsWith("https:", StringComparison.OrdinalIgnoreCase)) - && GetTexture("ui/uld/image2.tex", out texture); // loading pics. + || loadingIcon && ThreadLoadImageHandler.TryGetTextureWrap("ui/uld/image2.tex", out texture) + || ThreadLoadImageHandler.TryGetIconTextureWrap(0, false, out texture); // loading pics. private static readonly Dictionary _actionIcons = new(); diff --git a/RotationSolver.Basic/Data/StatusID.cs b/RotationSolver.Basic/Data/StatusID.cs index 071be6b1e..5b0a0263e 100644 --- a/RotationSolver.Basic/Data/StatusID.cs +++ b/RotationSolver.Basic/Data/StatusID.cs @@ -1432,4 +1432,28 @@ public enum StatusID : ushort /// LostSeraphStrike = 2484, + /// + /// + /// + Gobskin = 2114, + + /// + /// + /// + ToadOil = 1737, + + /// + /// + /// + Poison = 18, + + /// + /// + /// + BreathOfMagic = 3712, + + /// + /// + /// + MortalFlame = 3643, } diff --git a/RotationSolver.Basic/DataCenter.cs b/RotationSolver.Basic/DataCenter.cs index 072592272..c890a33e9 100644 --- a/RotationSolver.Basic/DataCenter.cs +++ b/RotationSolver.Basic/DataCenter.cs @@ -1,11 +1,12 @@ using Dalamud.Game.ClientState.Conditions; using Dalamud.Game.ClientState.Objects.SubKinds; -using Dalamud.Logging; using ECommons.DalamudServices; using ECommons.ExcelServices; using ECommons.GameHelpers; using FFXIVClientStructs.FFXIV.Client.Game; using FFXIVClientStructs.FFXIV.Client.Game.Fate; +using RotationSolver.Basic.Configuration; +using RotationSolver.Basic.Configuration.Conditions; using Action = Lumina.Excel.GeneratedSheets.Action; using CharacterManager = FFXIVClientStructs.FFXIV.Client.Game.Character.CharacterManager; @@ -13,14 +14,42 @@ namespace RotationSolver.Basic; internal static class DataCenter { + /// + /// This one never be null. + /// + public static MajorConditionSet RightSet + { + get + { + if (ConditionSets == null || !ConditionSets.Any()) + { + ConditionSets = new MajorConditionSet[] { new MajorConditionSet() }; + } + + var index = Service.Config.GetValue(PluginConfigInt.ActionSequencerIndex); + if(index < 0 || index >= ConditionSets.Count()) + { + index = 0; + Service.Config.SetValue(PluginConfigInt.ActionSequencerIndex, index); + } + + return ConditionSets[index]; + } + } + + internal static MajorConditionSet[] ConditionSets { get; set; } = Array.Empty(); + /// /// Only recorded 15s hps. /// public const int HP_RECORD_TIME = 240; internal static Queue<(DateTime time, SortedList hpRatios)> RecordedHP { get; } = new(HP_RECORD_TIME + 1); + public static ICustomRotation RightNowRotation { get; internal set; } + + internal static bool NoPoslock => Svc.Condition[ConditionFlag.OccupiedInEvent] - || !Service.Config.GetValue(Configuration.PluginConfigBool.PoslockCasting) + || !Service.Config.GetValue(PluginConfigBool.PoslockCasting) //Key cancel. || Svc.KeyState[ConfigurationHelper.Keys[Service.Config.GetValue(Configuration.PluginConfigInt.PoslockModifier) % ConfigurationHelper.Keys.Length]] //Gamepad cancel. @@ -179,12 +208,25 @@ public static float AbilityRemain static DateTime _specialStateStartTime = DateTime.MinValue; private static double SpecialTimeElapsed => (DateTime.Now - _specialStateStartTime).TotalSeconds; - public static double SpecialTimeLeft => WeaponTotal == 0 || WeaponElapsed == 0 ? Service.Config.GetValue(Configuration.PluginConfigFloat.SpecialDuration) - SpecialTimeElapsed : - Math.Ceiling((Service.Config.GetValue(Configuration.PluginConfigFloat.SpecialDuration) + WeaponElapsed - SpecialTimeElapsed) / WeaponTotal) * WeaponTotal - WeaponElapsed; + public static double SpecialTimeLeft => WeaponTotal == 0 || WeaponElapsed == 0 ? Service.Config.GetValue(PluginConfigFloat.SpecialDuration) - SpecialTimeElapsed : + Math.Ceiling((Service.Config.GetValue(PluginConfigFloat.SpecialDuration) + WeaponElapsed - SpecialTimeElapsed) / WeaponTotal) * WeaponTotal - WeaponElapsed; static SpecialCommandType _specialType = SpecialCommandType.EndSpecial; - public static SpecialCommandType SpecialType => + internal static SpecialCommandType SpecialType => SpecialTimeLeft < 0 ? SpecialCommandType.EndSpecial : _specialType; + + public static bool IsHealArea => SpecialType == SpecialCommandType.HealArea || RightSet.HealAreaConditionSet.IsTrue(RightNowRotation); + public static bool IsHealSingle => SpecialType == SpecialCommandType.HealSingle || RightSet.HealSingleConditionSet.IsTrue(RightNowRotation); + public static bool IsDefenseArea => SpecialType == SpecialCommandType.DefenseArea || RightSet.DefenseAreaConditionSet.IsTrue(RightNowRotation); + public static bool IsDefenseSingle => SpecialType == SpecialCommandType.DefenseSingle || RightSet.DefenseSingleConditionSet.IsTrue(RightNowRotation); + public static bool IsEsunaStanceNorth => SpecialType == SpecialCommandType.EsunaStanceNorth || RightSet.EsunaStanceNorthConditionSet.IsTrue(RightNowRotation); + public static bool IsRaiseShirk => SpecialType == SpecialCommandType.RaiseShirk || RightSet.RaiseShirkConditionSet.IsTrue(RightNowRotation); + public static bool IsMoveForward => SpecialType == SpecialCommandType.MoveForward || RightSet.MoveForwardConditionSet.IsTrue(RightNowRotation); + public static bool IsMoveBack => SpecialType == SpecialCommandType.MoveBack || RightSet.MoveBackConditionSet.IsTrue(RightNowRotation); + public static bool IsAntiKnockback => SpecialType == SpecialCommandType.AntiKnockback || RightSet.AntiKnockbackConditionSet.IsTrue(RightNowRotation); + public static bool IsBurst => SpecialType == SpecialCommandType.Burst || RightSet.BurstConditionSet.IsTrue(RightNowRotation); + public static bool IsSpeed => SpecialType == SpecialCommandType.Speed || RightSet.SpeedConditionSet.IsTrue(RightNowRotation); + public static bool State { get; set; } = false; public static bool IsManual { get; set; } = false; diff --git a/RotationSolver.Basic/Rotations/Basic/BLU_Base.cs b/RotationSolver.Basic/Rotations/Basic/BLU_Base.cs index 0f5f2880c..df117514b 100644 --- a/RotationSolver.Basic/Rotations/Basic/BLU_Base.cs +++ b/RotationSolver.Basic/Rotations/Basic/BLU_Base.cs @@ -996,7 +996,7 @@ protected override bool EmergencyGCD(out IAction act) if (BlueId == BLUID.Healer) { //Esuna - if (DataCenter.SpecialType == SpecialCommandType.EsunaStanceNorth && DataCenter.WeakenPeople.Any() || DataCenter.DyingPeople.Any()) + if (DataCenter.IsEsunaStanceNorth && DataCenter.WeakenPeople.Any() || DataCenter.DyingPeople.Any()) { if (Exuviation.CanUse(out act, CanUseOption.MustUse)) return true; } diff --git a/RotationSolver.Basic/Rotations/Basic/BRD_Base.cs b/RotationSolver.Basic/Rotations/Basic/BRD_Base.cs index 5c7924a46..6eb1812b7 100644 --- a/RotationSolver.Basic/Rotations/Basic/BRD_Base.cs +++ b/RotationSolver.Basic/Rotations/Basic/BRD_Base.cs @@ -344,7 +344,7 @@ protected static bool SongEndAfterGCD(uint gctCount = 0, float offset = 0) protected override bool EmergencyAbility(IAction nextGCD, out IAction act) { //Esuna - if (DataCenter.SpecialType == SpecialCommandType.EsunaStanceNorth && DataCenter.WeakenPeople.Any() || DataCenter.DyingPeople.Any()) + if (DataCenter.IsEsunaStanceNorth && DataCenter.WeakenPeople.Any() || DataCenter.DyingPeople.Any()) { if (WardensPaean.CanUse(out act, CanUseOption.MustUse)) return true; } diff --git a/RotationSolver.Basic/Rotations/Basic/SGE_Base.cs b/RotationSolver.Basic/Rotations/Basic/SGE_Base.cs index 644b249e9..739cb2127 100644 --- a/RotationSolver.Basic/Rotations/Basic/SGE_Base.cs +++ b/RotationSolver.Basic/Rotations/Basic/SGE_Base.cs @@ -149,9 +149,8 @@ protected static bool AddersgallEndAfterGCD(uint gctCount = 0, float offset = 0) return TargetFilter.FindAttackedTarget(targets, mustUse); }, - ActionCheck = (b, m) => Svc.Objects.OfType() - .Where(o => o.CurrentHp > 0) - .All(o => !o.HasStatus(true, StatusID.Kardion)), + + TargetStatus = new StatusID[] { StatusID.Kardion }, }; /// diff --git a/RotationSolver.Basic/Rotations/CustomRotation_Ability.cs b/RotationSolver.Basic/Rotations/CustomRotation_Ability.cs index ac8ad82eb..28a300da9 100644 --- a/RotationSolver.Basic/Rotations/CustomRotation_Ability.cs +++ b/RotationSolver.Basic/Rotations/CustomRotation_Ability.cs @@ -27,30 +27,28 @@ private bool Ability(IAction nextGCD, out IAction act, bool helpDefenseAOE, bool if (InterruptAbility(role, out act)) return true; - var specialType = DataCenter.SpecialType; + if (ShirkOrShield(role, out act)) return true; + if (DataCenter.IsAntiKnockback && AntiKnockback(role, out act)) return true; - if (ShirkOrShield(role, specialType, out act)) return true; - if (AntiKnockback(role, specialType, out act)) return true; - - if (specialType == SpecialCommandType.EsunaStanceNorth && role == JobRole.Melee) + if (DataCenter.IsEsunaStanceNorth && role == JobRole.Melee) { if (TrueNorth.CanUse(out act)) return true; } - if (GeneralHealAbility(specialType, out act)) return true; - if(specialType == SpecialCommandType.Speed && SpeedAbility(out act)) return true; + if (GeneralHealAbility(out act)) return true; + if (DataCenter.IsSpeed && SpeedAbility(out act)) return true; if (AutoDefense(role, helpDefenseAOE, helpDefenseSingle, out act)) return true; BaseAction.OtherOption |= CanUseOption.EmptyOrSkipCombo; - if (MovingAbility(specialType, out act)) return true; + if (MovingAbility(out act)) return true; BaseAction.OtherOption &= ~CanUseOption.EmptyOrSkipCombo; if (GeneralUsingAbility(role, out act)) return true; if (DataCenter.HPNotFull && InCombat) { - if (DataCenter.SpecialType == SpecialCommandType.HealSingle || CanHealSingleAbility) + if (DataCenter.IsHealSingle || CanHealSingleAbility) { if (UseHealPotion(out act)) return true; } @@ -90,7 +88,7 @@ private static bool InterruptAbility(JobRole role, out IAction act) return false; } - private bool ShirkOrShield(JobRole role, SpecialCommandType specialType, out IAction act) + private bool ShirkOrShield(JobRole role, out IAction act) { act = null; if (role != JobRole.Tank) @@ -98,16 +96,8 @@ private bool ShirkOrShield(JobRole role, SpecialCommandType specialType, out IAc return DataCenter.SetAutoStatus(AutoStatus.TankStance, false); } - switch (specialType) - { - case SpecialCommandType.RaiseShirk: - if (Shirk.CanUse(out act)) return true; - break; - - case SpecialCommandType.EsunaStanceNorth: - if (TankStance.CanUse(out act)) return true; - break; - } + if (DataCenter.IsRaiseShirk && Shirk.CanUse(out act)) return true; + if (DataCenter.IsEsunaStanceNorth && TankStance.CanUse(out act)) return true; if (DataCenter.SetAutoStatus(AutoStatus.TankStance, Service.Config.GetValue(PluginConfigBool.AutoTankStance) && !DataCenter.AllianceTanks.Any(t => t.CurrentHp != 0 && t.HasStatus(false, StatusHelper.TankStanceStatus)) @@ -119,12 +109,9 @@ private bool ShirkOrShield(JobRole role, SpecialCommandType specialType, out IAc return false; } - private static bool AntiKnockback(JobRole role, SpecialCommandType specialType, out IAction act) + private static bool AntiKnockback(JobRole role, out IAction act) { act = null; - - if (specialType != SpecialCommandType.AntiKnockback) return false; - switch (role) { case JobRole.Tank: @@ -145,26 +132,19 @@ private static bool AntiKnockback(JobRole role, SpecialCommandType specialType, return false; } - private bool GeneralHealAbility(SpecialCommandType specialType, out IAction act) + private bool GeneralHealAbility(out IAction act) { act = null; BaseAction.OtherOption |= CanUseOption.MustUse; - switch (specialType) - { - case SpecialCommandType.DefenseArea: - if (DefenseAreaAbility(out act)) return true; - break; + if (DataCenter.IsDefenseArea && DefenseAreaAbility(out act)) return true; + if (DataCenter.IsDefenseSingle && DefenseSingleAbility(out act)) return true; - case SpecialCommandType.DefenseSingle: - if (DefenseSingleAbility(out act)) return true; - break; - } BaseAction.OtherOption &= ~CanUseOption.MustUse; if ((DataCenter.HPNotFull || ClassJob.GetJobRole() != JobRole.Healer) && InCombat) { - if (DataCenter.SpecialType == SpecialCommandType.HealArea) + if (DataCenter.IsHealArea) { if (HealAreaAbility(out act)) return true; } @@ -174,7 +154,7 @@ private bool GeneralHealAbility(SpecialCommandType specialType, out IAction act) if (HealAreaAbility(out act)) return true; BaseAction.AutoHealCheck = false; } - if (DataCenter.SpecialType == SpecialCommandType.HealSingle) + if (DataCenter.IsHealSingle) { if (HealSingleAbility(out act)) return true; } @@ -250,11 +230,11 @@ private bool AutoDefense(JobRole role, bool helpDefenseAOE, bool helpDefenseSing return false; } - private bool MovingAbility(SpecialCommandType specialType, out IAction act) + private bool MovingAbility(out IAction act) { act = null; - if (specialType == SpecialCommandType.MoveForward && MoveForwardAbility(out act)) return true; - else if (specialType == SpecialCommandType.MoveBack && MoveBackAbility(out act)) return true; + if (DataCenter.IsMoveForward && MoveForwardAbility(out act)) return true; + else if (DataCenter.IsMoveBack && MoveBackAbility(out act)) return true; return false; } diff --git a/RotationSolver.Basic/Rotations/CustomRotation_GCD.cs b/RotationSolver.Basic/Rotations/CustomRotation_GCD.cs index 1c0cef86c..1df942973 100644 --- a/RotationSolver.Basic/Rotations/CustomRotation_GCD.cs +++ b/RotationSolver.Basic/Rotations/CustomRotation_GCD.cs @@ -15,11 +15,9 @@ private IAction GCD(bool helpDefenseAOE, bool helpDefenseSingle) if (EmergencyGCD(out act)) return act; - var specialType = DataCenter.SpecialType; + if (RaiseSpell(out act, false)) return act; - if (RaiseSpell(specialType, out act, false)) return act; - - if (specialType == SpecialCommandType.MoveForward && MoveForwardGCD(out act)) + if (DataCenter.IsMoveForward && MoveForwardGCD(out act)) { if (act is IBaseAction b && ObjectHelper.DistanceToPlayer(b.Target) > 5) return act; } @@ -28,7 +26,7 @@ private IAction GCD(bool helpDefenseAOE, bool helpDefenseSingle) if ((DataCenter.HPNotFull || ClassJob.GetJobRole() != JobRole.Healer) && (DataCenter.InCombat || Service.Config.GetValue(PluginConfigBool.HealOutOfCombat))) { - if (specialType == SpecialCommandType.HealArea) + if (DataCenter.IsHealArea) { if( HealAreaGCD(out act)) return act; } @@ -38,7 +36,7 @@ private IAction GCD(bool helpDefenseAOE, bool helpDefenseSingle) if (HealAreaGCD(out act)) return act; BaseAction.AutoHealCheck = false; } - if (specialType == SpecialCommandType.HealSingle) + if (DataCenter.IsHealSingle) { if (HealSingleGCD(out act)) return act; } @@ -49,15 +47,15 @@ private IAction GCD(bool helpDefenseAOE, bool helpDefenseSingle) BaseAction.AutoHealCheck = false; } } - if (specialType == SpecialCommandType.DefenseArea && DefenseAreaGCD(out act)) return act; - if (specialType == SpecialCommandType.DefenseSingle && DefenseSingleGCD(out act)) return act; + if (DataCenter.IsDefenseArea && DefenseAreaGCD(out act)) return act; + if (DataCenter.IsDefenseSingle && DefenseSingleGCD(out act)) return act; //Auto Defense if (DataCenter.SetAutoStatus(AutoStatus.DefenseArea, helpDefenseAOE) && DefenseAreaGCD(out act)) return act; if (DataCenter.SetAutoStatus(AutoStatus.DefenseSingle, helpDefenseSingle) && DefenseSingleGCD(out act)) return act; //Esuna - if (DataCenter.SetAutoStatus(AutoStatus.Esuna, (specialType == SpecialCommandType.EsunaStanceNorth + if (DataCenter.SetAutoStatus(AutoStatus.Esuna, (DataCenter.IsEsunaStanceNorth || !HasHostilesInRange || Service.Config.GetValue(PluginConfigBool.EsunaAll)) && DataCenter.WeakenPeople.Any() || DataCenter.DyingPeople.Any())) { @@ -87,15 +85,15 @@ private IAction GCD(bool helpDefenseAOE, bool helpDefenseSingle) } } - if (Service.Config.GetValue(PluginConfigBool.RaisePlayerByCasting) && RaiseSpell(specialType, out act, true)) return act; + if (Service.Config.GetValue(PluginConfigBool.RaisePlayerByCasting) && RaiseSpell(out act, true)) return act; return null; } - private bool RaiseSpell(SpecialCommandType specialType, out IAction act, bool mustUse) + private bool RaiseSpell(out IAction act, bool mustUse) { act = null; - if (specialType == SpecialCommandType.RaiseShirk && DataCenter.DeathPeopleAll.Any()) + if (DataCenter.IsRaiseShirk && DataCenter.DeathPeopleAll.Any()) { if (RaiseAction(out act)) return true; } diff --git a/RotationSolver.Basic/Rotations/CustomRotation_Invoke.cs b/RotationSolver.Basic/Rotations/CustomRotation_Invoke.cs index 03f457288..90397b036 100644 --- a/RotationSolver.Basic/Rotations/CustomRotation_Invoke.cs +++ b/RotationSolver.Basic/Rotations/CustomRotation_Invoke.cs @@ -108,7 +108,7 @@ private void UpdateActions(JobRole role) JobRole.Tank => Shirk.CanUse(out act) ? act : null, _ => null, }; - AntiKnockbackAbility = AntiKnockback(role, SpecialCommandType.AntiKnockback, out act) ? act : null; + AntiKnockbackAbility = AntiKnockback(role, out act) ? act : null; BaseAction.OtherOption |= CanUseOption.EmptyOrSkipCombo; diff --git a/RotationSolver.Basic/Rotations/CustomRotation_OtherInfo.cs b/RotationSolver.Basic/Rotations/CustomRotation_OtherInfo.cs index ab74ee467..9f2352cd9 100644 --- a/RotationSolver.Basic/Rotations/CustomRotation_OtherInfo.cs +++ b/RotationSolver.Basic/Rotations/CustomRotation_OtherInfo.cs @@ -197,13 +197,68 @@ public static bool IsLongerThan(float time) #endregion #region Command + /// + /// Is in burst right now? Usually it used with team support actions. Please use instead. + /// + [Obsolete("It will be removed in the future version", true)] + public static bool InBurst => IsBurst; /// /// Is in burst right now? Usually it used with team support actions. /// - public static bool InBurst => DataCenter.SpecialType == SpecialCommandType.Burst || Service.Config.GetValue(Configuration.PluginConfigBool.AutoBurst); + public static bool IsBurst => DataCenter.IsBurst || Service.Config.GetValue(Configuration.PluginConfigBool.AutoBurst); + + /// + /// Is in the command heal area. + /// + public static bool IsHealArea => DataCenter.IsHealArea; + + /// + /// Is in the command heal single. + /// + public static bool IsHealSingle => DataCenter.IsHealSingle; + + /// + /// Is in the command defense area. + /// + public static bool IsDefenseArea => DataCenter.IsDefenseArea; + + /// + /// Is in the command defense single. + /// + public static bool IsDefenseSingle => DataCenter.IsDefenseSingle; + + /// + /// Is in the command Esuna Stance North. + /// + public static bool IsEsunaStanceNorth => DataCenter.IsEsunaStanceNorth; + + /// + /// Is in the command Raise Shirk. + /// + public static bool IsRaiseShirk => DataCenter.IsRaiseShirk; - bool _canUseHealAction => + /// + /// Is in the command move forward. + /// + public static bool IsMoveForward => DataCenter.IsMoveForward; + + /// + /// Is in the command move back. + /// + public static bool IsMoveBack => DataCenter.IsMoveBack; + + /// + /// Is in the command anti knockback. + /// + public static bool IsAntiKnockback => DataCenter.IsAntiKnockback; + + /// + /// Is in the command speed. + /// + public static bool IsSpeed => DataCenter.IsSpeed; + + private bool CanUseHealAction => //Job (ClassJob.GetJobRole() == JobRole.Healer || Service.Config.GetValue(Configuration.PluginConfigBool.UseHealWhenNotAHealer)) && Service.Config.GetValue(Configuration.PluginConfigBool.AutoHeal) @@ -212,27 +267,22 @@ public static bool IsLongerThan(float time) /// /// /// - public virtual bool CanHealAreaAbility => DataCenter.CanHealAreaAbility && _canUseHealAction; + public virtual bool CanHealAreaAbility => DataCenter.CanHealAreaAbility && CanUseHealAction; /// /// /// - public virtual bool CanHealAreaSpell => DataCenter.CanHealAreaSpell && _canUseHealAction; + public virtual bool CanHealAreaSpell => DataCenter.CanHealAreaSpell && CanUseHealAction; /// /// /// - public virtual bool CanHealSingleAbility => DataCenter.CanHealSingleAbility && _canUseHealAction; + public virtual bool CanHealSingleAbility => DataCenter.CanHealSingleAbility && CanUseHealAction; /// /// /// - public virtual bool CanHealSingleSpell => DataCenter.CanHealSingleSpell && _canUseHealAction; - - /// - /// - /// - protected static SpecialCommandType SpecialType => DataCenter.SpecialType; + public virtual bool CanHealSingleSpell => DataCenter.CanHealSingleSpell && CanUseHealAction; /// /// True for On, false for off. @@ -278,6 +328,11 @@ public static bool IsLongerThan(float time) /// public static bool IsInHighEndDuty => DataCenter.IsInHighEndDuty; + /// + /// Is player in duty. + /// + public static bool IsInDuty => Svc.Condition[ConditionFlag.BoundByDuty]; + /// /// /// diff --git a/RotationSolver/ActionSequencer/ActionCondition.cs b/RotationSolver/ActionSequencer/ActionCondition.cs deleted file mode 100644 index e1cc02ab4..000000000 --- a/RotationSolver/ActionSequencer/ActionCondition.cs +++ /dev/null @@ -1,211 +0,0 @@ -using Dalamud.Utility; -using RotationSolver.Localization; -using RotationSolver.UI; - -namespace RotationSolver.ActionSequencer; - -internal class ActionCondition : BaseCondition -{ - private IBaseAction _action; - - public ActionID ID { get; set; } = ActionID.None; - - public ActionConditionType ActionConditionType = ActionConditionType.Elapsed; - - public bool Condition { get; set; } - - public int Param1; - public int Param2; - public float Time; - - public override bool IsTrueInside(ICustomRotation rotation) - { - if (!ConditionHelper.CheckBaseAction(rotation, ID, ref _action)) return false; - - var result = false; - - switch (ActionConditionType) - { - case ActionConditionType.Elapsed: - result = _action.ElapsedOneChargeAfter(Time); // Bigger - break; - - case ActionConditionType.ElapsedGCD: - result = _action.ElapsedOneChargeAfterGCD((uint)Param1, Param2); // Bigger - break; - - case ActionConditionType.Remain: - result = !_action.WillHaveOneCharge(Time); //Smaller - break; - - case ActionConditionType.RemainGCD: - result = !_action.WillHaveOneChargeGCD((uint)Param1, Param2); // Smaller - break; - - case ActionConditionType.CanUse: - result = _action.CanUse(out _, (CanUseOption)Param1, (byte)Param2); - break; - - case ActionConditionType.EnoughLevel: - result = _action.EnoughLevel; - break; - - case ActionConditionType.IsCoolDown: - result = _action.IsCoolingDown; - break; - - case ActionConditionType.CurrentCharges: - result = _action.CurrentCharges > Param1; - break; - - case ActionConditionType.MaxCharges: - result = _action.MaxCharges > Param1; - break; - } - - return Condition ? !result : result; - } - - private readonly CollapsingHeaderGroup _actionsList = new() - { - HeaderSize = 12, - }; - - public override void DrawInside(ICustomRotation rotation) - { - ConditionHelper.CheckBaseAction(rotation, ID, ref _action); - - var name = _action?.Name ?? string.Empty; - - var popUpKey = "Action Condition Pop Up" + GetHashCode().ToString(); - - ConditionHelper.ActionSelectorPopUp(popUpKey, _actionsList, rotation, item => ID = (ActionID)item.ID); - - if (_action?.GetTexture(out var icon) ?? false || IconSet.GetTexture(4, out icon)) - { - var cursor = ImGui.GetCursorPos(); - if (ImGuiHelper.NoPaddingNoColorImageButton(icon.ImGuiHandle, Vector2.One * ConditionHelper.IconSize, GetHashCode().ToString())) - { - if(!ImGui.IsPopupOpen(popUpKey)) ImGui.OpenPopup(popUpKey); - } - ImGuiHelper.DrawActionOverlay(cursor, ConditionHelper.IconSize, 1); - ImguiTooltips.HoveredTooltip(name); - } - - ImGui.SameLine(); - - ConditionHelper.DrawByteEnum($"##Category{GetHashCode()}", ref ActionConditionType, EnumTranslations.ToName); - - var condition = Condition ? 1 : 0; - var combos = Array.Empty(); - switch (ActionConditionType) - { - case ActionConditionType.ElapsedGCD: - case ActionConditionType.RemainGCD: - case ActionConditionType.Elapsed: - case ActionConditionType.Remain: - case ActionConditionType.CurrentCharges: - case ActionConditionType.MaxCharges: - combos = new string[] { ">", "<=" }; - break; - - case ActionConditionType.CanUse: - combos = new string[] - { - LocalizationManager.RightLang.ActionSequencer_Can, - LocalizationManager.RightLang.ActionSequencer_Cannot, - }; - break; - - case ActionConditionType.EnoughLevel: - case ActionConditionType.IsCoolDown: - combos = new string[] - { - LocalizationManager.RightLang.ActionSequencer_Is, - LocalizationManager.RightLang.ActionSequencer_Isnot, - }; - break; - } - ImGui.SameLine(); - - if(ImGuiHelper.SelectableCombo($"##Comparation{GetHashCode()}", combos, ref condition)) - { - Condition = condition > 0; - } - - - switch (ActionConditionType) - { - case ActionConditionType.Elapsed: - case ActionConditionType.Remain: - ConditionHelper.DrawDragFloat($"s##Seconds{GetHashCode()}", ref Time); - break; - - case ActionConditionType.ElapsedGCD: - case ActionConditionType.RemainGCD: - if (ConditionHelper.DrawDragInt($"GCD##GCD{GetHashCode()}", ref Param1)) - { - Param1 = Math.Max(0, Param1); - } - if (ConditionHelper.DrawDragInt($"{LocalizationManager.RightLang.ActionSequencer_TimeOffset}##Ability{GetHashCode()}", ref Param2)) - { - Param2 = Math.Max(0, Param2); - } - break; - - case ActionConditionType.CanUse: - var popUpId = "Can Use Id" + GetHashCode().ToString(); - var option = (CanUseOption)Param1; - - if (ImGui.Selectable($"{option}##CanUse{GetHashCode()}")) - { - if (!ImGui.IsPopupOpen(popUpId)) ImGui.OpenPopup(popUpId); - } - - if (ImGui.BeginPopup(popUpId)) - { - var showedValues = Enum.GetValues().Where(i => i.GetAttribute() == null); - - foreach (var value in showedValues) - { - var b = option.HasFlag(value); - if(ImGui.Checkbox(value.ToString(), ref b)) - { - option ^= value; - Param1 = (int)option; - } - } - - ImGui.EndPopup(); - } - - if (ConditionHelper.DrawDragInt($"{LocalizationManager.RightLang.ActionSequencer_AOECount}##AOECount{GetHashCode()}", ref Param2)) - { - Param2 = Math.Max(0, Param2); - } - break; - - case ActionConditionType.CurrentCharges: - case ActionConditionType.MaxCharges: - if (ConditionHelper.DrawDragInt($"{LocalizationManager.RightLang.ActionSequencer_Charges}##Charges{GetHashCode()}", ref Param1)) - { - Param1 = Math.Max(0, Param1); - } - break; - } - } - -} - -public enum ActionConditionType : byte -{ - Elapsed, - ElapsedGCD, - Remain, - RemainGCD, - CanUse, - EnoughLevel, - IsCoolDown, - CurrentCharges, - MaxCharges, -} diff --git a/RotationSolver/ActionSequencer/ActionSequencer.cd b/RotationSolver/ActionSequencer/ActionSequencer.cd deleted file mode 100644 index 2bd5f0b5c..000000000 --- a/RotationSolver/ActionSequencer/ActionSequencer.cd +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAACAAAAAAAAAA= - Timeline\IConditionConverter.cs - - - - - - AAAAAAAAAQQAAAAAEAAAAAAAAAAAAEAAAAAAAAAACAA= - Timeline\IConditionConverter.cs - - - - - - AAAAAAIABACAgggAAAAAAAAAAAAAAAAAAIAAgAAAAQA= - Timeline\ActionCondition.cs - - - - - - - CAAAAAAABAAAAggAABAAEAAAAAAAAAAAAAAAAIAAAAA= - Timeline\ConditionSet.cs - - - - - - - AAAAAIAAAAAAAAAAABAAAAQgAAAAAAAAAAAAAAAAAAA= - Timeline\MajorConditionSet.cs - - - - - - AAAAAAIABECAwggAAABAAAAAAAAAAAAAAAACggBAAQA= - Timeline\RotationCondition.cs - - - - - - - AEAAAAAAAAAggAgAAAEAAAQAAAAAAAAAAAAAAAAAAAA= - Timeline\BaseStatus.cs - - - - - - - AEAAAQQkJACAkggAAQAABAAAAAAAAAAAAAAAgAAAAAA= - Timeline\TargetCondition.cs - - - - - - - AAAAAAAABAAAAggAAAAAAAAAAAAAAAAAAAAAAAAIAAA= - Timeline\ICondition.cs - - - - - - AAAgAAIAAAAABIAgAAAAAAAAACAAAAAAAAABAAAAgIA= - Timeline\ActionCondition.cs - - - - - - AAAAAAAAAAAAAAAgAAAAAAAABAAAAAAAAAACAAAAAQI= - Timeline\RotationCondition.cs - - - - - - AAAAAAAAAAAAAAAAACCAAAAAAAAQAAhAAAEAAIAAAAA= - Timeline\TargetCondition.cs - - - - \ No newline at end of file diff --git a/RotationSolver/ActionSequencer/BaseCondition.cs b/RotationSolver/ActionSequencer/BaseCondition.cs deleted file mode 100644 index d1dd51210..000000000 --- a/RotationSolver/ActionSequencer/BaseCondition.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Dalamud.Interface.Utility; -using RotationSolver.Localization; -using RotationSolver.UI; - -namespace RotationSolver.ActionSequencer; - -internal abstract class BaseCondition : ICondition -{ - public float DelayMin = 0; - public float DelayMax = 0; - - RandomDelay _delay = default; - - [JsonIgnore] - private const float MIN = 0, MAX = 60; - - public bool IsTrue(ICustomRotation rotation) - { - if(_delay.GetRange == null) - { - _delay = new(() => (DelayMin, DelayMax)); - } - return _delay.Delay(IsTrueInside(rotation)); - } - - public abstract bool IsTrueInside(ICustomRotation rotation); - - public void Draw(ICustomRotation rotation) - { - BeforeDraw(); - ImGui.SetNextItemWidth(80 * ImGuiHelpers.GlobalScale); - if(ImGui.DragFloatRange2($"##Random Delay {GetHashCode()}", ref DelayMin, ref DelayMax, 0.1f, MIN, MAX)) - { - DelayMin = Math.Max(Math.Min(DelayMin, DelayMax), MIN); - DelayMax = Math.Min(Math.Max(DelayMin, DelayMax), MAX); - } - ImguiTooltips.HoveredTooltip(LocalizationManager.RightLang.ActionSequencer_Delay_Description); - - ImGui.SameLine(); - DrawInside(rotation); - } - - public virtual void BeforeDraw() - { - - } - public abstract void DrawInside(ICustomRotation rotation); -} diff --git a/RotationSolver/ActionSequencer/ConditionHelper.cs b/RotationSolver/ActionSequencer/ConditionHelper.cs deleted file mode 100644 index 71a289b7f..000000000 --- a/RotationSolver/ActionSequencer/ConditionHelper.cs +++ /dev/null @@ -1,165 +0,0 @@ -using Dalamud.Interface.Utility; -using Dalamud.Logging; -using ECommons.GameHelpers; -using RotationSolver.Localization; -using RotationSolver.UI; -using RotationSolver.Updaters; - -namespace RotationSolver.ActionSequencer; - -internal static class ConditionHelper -{ - public static bool CheckBaseAction(ICustomRotation rotation, ActionID id, ref IBaseAction action) - { - if (id != ActionID.None && (action == null || (ActionID)action.ID != id)) - { - action = rotation.AllBaseActions.FirstOrDefault(a => (ActionID)a.ID == id); - } - if (action == null || !Player.Available) return false; - return true; - } - - public static void CheckMemberInfo(ICustomRotation rotation, ref string name, ref T value) where T : MemberInfo - { - if (!string.IsNullOrEmpty(name) && (value == null || value.Name != name)) - { - var memberName = name; - if (typeof(T).IsAssignableFrom(typeof(PropertyInfo))) - { - value = (T)rotation.GetType().GetAllMethods(RuntimeReflectionExtensions.GetRuntimeProperties).FirstOrDefault(m => m.Name == memberName); - } - else if (typeof(T).IsAssignableFrom(typeof(MethodInfo))) - { - value = (T)rotation.GetType().GetAllMethods(RuntimeReflectionExtensions.GetRuntimeMethods).FirstOrDefault(m => m.Name == memberName); - } - } - } - - private static IEnumerable GetAllMethods(this Type type, Func> getFunc) - { - if (type == null || getFunc == null) return Array.Empty(); - - var methods = getFunc(type); - return methods.Union(GetAllMethods(type.BaseType, getFunc)); - } - - public static void DrawByteEnum(string name, ref T value, Func function) where T : struct, Enum - { - var values = Enum.GetValues(); - var index = Array.IndexOf(values, value); - var names = values.Select(function).ToArray(); - - if(ImGuiHelper.SelectableCombo(name, names, ref index)) - { - value = values[index]; - } - } - - public static bool DrawDragFloat(string name, ref float value) - { - ImGui.SameLine(); - ImGui.SetNextItemWidth(50); - return ImGui.DragFloat(name, ref value); - } - - public static bool DrawDragInt(string name, ref int value) - { - ImGui.SameLine(); - ImGui.SetNextItemWidth(50); - return ImGui.DragInt(name, ref value); - } - - public static bool DrawCheckBox(string name, ref int value, string desc = "") - { - ImGui.SameLine(); - - var @bool = value != 0; - - var result = false; - if (ImGui.Checkbox(name, ref @bool)) - { - value = @bool ? 1 : 0; - result = true; - } - - ImguiTooltips.HoveredTooltip(desc); - - return result; - } - - internal static void SearchItemsReflection(string popId, string name, ref string searchTxt, T[] actions, Action selectAction) where T : MemberInfo - { - if (ImGuiHelper.SelectableButton(name + "##" + popId)) - { - if (!ImGui.IsPopupOpen(popId)) ImGui.OpenPopup(popId); - } - - if (ImGui.BeginPopup(popId)) - { - var searchingKey = searchTxt; - - var members = actions.Select(m => (m, m.GetMemberName())) - .OrderByDescending(s => RotationConfigWindow.Similarity(s.Item2, searchingKey)); - - ImGui.SetNextItemWidth(Math.Max(50 * ImGuiHelpers.GlobalScale, members.Max(i => ImGuiHelpers.GetButtonSize(i.Item2).X))); - ImGui.InputTextWithHint("##Searching the member", LocalizationManager.RightLang.ConfigWindow_Actions_MemberName, ref searchTxt, 128); - - ImGui.Spacing(); - - foreach (var member in members) - { - if (ImGui.Selectable(member.Item2)) - { - selectAction?.Invoke(member.m); - ImGui.CloseCurrentPopup(); - } - } - - ImGui.EndPopup(); - } - } - - public static float IconSizeRaw => ImGuiHelpers.GetButtonSize("H").Y; - public static float IconSize => IconSizeRaw * ImGuiHelpers.GlobalScale; - private const int count = 8; - public static void ActionSelectorPopUp(string popUpId, CollapsingHeaderGroup group, ICustomRotation rotation, Action action, Action others = null) - { - if (group != null && ImGui.BeginPopup(popUpId)) - { - others?.Invoke(); - - group.ClearCollapsingHeader(); - - foreach (var pair in RotationUpdater.GroupActions(rotation.AllBaseActions)) - { - group.AddCollapsingHeader(() => pair.Key, () => - { - var index = 0; - foreach (var item in pair.OrderBy(t => t.ID)) - { - if (!item.GetTexture(out var icon)) continue; - - if (index++ % count != 0) - { - ImGui.SameLine(); - } - - ImGui.BeginGroup(); - var cursor = ImGui.GetCursorPos(); - if (ImGuiHelper.NoPaddingNoColorImageButton(icon.ImGuiHandle, Vector2.One * IconSize, group.GetHashCode().ToString())) - { - action?.Invoke(item); - ImGui.CloseCurrentPopup(); - } - ImGuiHelper.DrawActionOverlay(cursor, IconSize, 1); - ImGui.EndGroup(); - var name = item.Name; - if (!string.IsNullOrEmpty(name)) ImguiTooltips.HoveredTooltip(name); - } - }); - } - group.Draw(); - ImGui.EndPopup(); - } - } -} diff --git a/RotationSolver/ActionSequencer/ConditionSet.cs b/RotationSolver/ActionSequencer/ConditionSet.cs deleted file mode 100644 index ff669901e..000000000 --- a/RotationSolver/ActionSequencer/ConditionSet.cs +++ /dev/null @@ -1,150 +0,0 @@ -using Dalamud.Game.ClientState.Keys; -using ECommons.ImGuiMethods; -using RotationSolver.Localization; -using RotationSolver.UI; - -namespace RotationSolver.ActionSequencer; - -internal class ConditionSet : BaseCondition -{ - public override bool IsTrueInside(ICustomRotation rotation) - { - if (Conditions.Count == 0) return false; - switch (Type) - { - case LogicalType.And: - return Conditions.All(c => c.IsTrue(rotation)); - case LogicalType.Or: - return Conditions.Any(c => c.IsTrue(rotation)); - case LogicalType.NotAnd: - return !Conditions.All(c => c.IsTrue(rotation)); - case LogicalType.NotOr: - return !Conditions.Any(c => c.IsTrue(rotation)); - } - return false; - } - public List Conditions { get; set; } = new List(); - public LogicalType Type; - - public override void BeforeDraw() - { - ImGui.BeginGroup(); - } - - public override void DrawInside(ICustomRotation rotation) - { - AddButton(); - - ImGui.SameLine(); - - ConditionHelper.DrawByteEnum($"##Rule{GetHashCode()}", ref Type, t => t switch - { - LogicalType.And => "&&", - LogicalType.Or => " | | ", - LogicalType.NotAnd => "! &&", - LogicalType.NotOr => "! | | ", - _ => string.Empty, - }); - - ImGui.Spacing(); - - for(int i = 0; i < Conditions.Count; i++) - { - ICondition condition = Conditions[i]; - - void Delete() - { - Conditions.RemoveAt(i); - }; - - void Up() - { - Conditions.RemoveAt(i); - Conditions.Insert(Math.Max(0, i - 1), condition); - }; - void Down() - { - Conditions.RemoveAt(i); - Conditions.Insert(Math.Min(Conditions.Count, i + 1), condition); - } - - var key = $"Condition Pop Up: {condition.GetHashCode()}"; - - ImGuiHelper.DrawHotKeysPopup(key, string.Empty, - (LocalizationManager.RightLang.ConfigWindow_List_Remove, Delete, new string[] { "Delete" }), - (LocalizationManager.RightLang.ConfigWindow_Actions_MoveUp, Up, new string[] { "↑" }), - (LocalizationManager.RightLang.ConfigWindow_Actions_MoveDown, Down, new string[] { "↓" })); - - DrawCondition(condition.IsTrue(rotation)); - - ImGuiHelper.ExecuteHotKeysPopup(key, string.Empty, string.Empty, true, - (Delete, new VirtualKey[] { VirtualKey.DELETE }), - (Up, new VirtualKey[] { VirtualKey.UP }), - (Down, new VirtualKey[] { VirtualKey.DOWN })); - - ImGui.SameLine(); - - condition.Draw(rotation); - } - - ImGui.EndGroup(); - } - - private void AddButton() - { - if (ImGuiEx.IconButton(FontAwesomeIcon.Plus, "AddButton" + GetHashCode().ToString())) - { - ImGui.OpenPopup("Popup" + GetHashCode().ToString()); - } - - if (ImGui.BeginPopup("Popup" + GetHashCode().ToString())) - { - AddOneCondition(LocalizationManager.RightLang.ActionSequencer_ConditionSet); - AddOneCondition(LocalizationManager.RightLang.ActionSequencer_ActionCondition); - AddOneCondition(LocalizationManager.RightLang.ActionSequencer_TraitCondition); - AddOneCondition(LocalizationManager.RightLang.ActionSequencer_TargetCondition); - AddOneCondition(LocalizationManager.RightLang.ActionSequencer_RotationCondition); - - ImGui.EndPopup(); - } - } - - private void AddOneCondition(string name) where T : ICondition - { - if (ImGui.Selectable(name)) - { - Conditions.Add(Activator.CreateInstance()); - ImGui.CloseCurrentPopup(); - } - } - - internal static void DrawCondition(bool? tag) - { - float size = ConditionHelper.IconSize * (1 + 8 / 82); - - if (!tag.HasValue) - { - if (IconSet.GetTexture("ui/uld/image2.tex", out var texture) || IconSet.GetTexture(0u, out texture)) - { - ImGui.Image(texture.ImGuiHandle, Vector2.One * size); - } - } - else - { - if (IconSet.GetTexture("ui/uld/readycheck_hr1.tex", out var texture)) - { - ImGui.Image(texture.ImGuiHandle, Vector2.One * size, - new Vector2(tag.Value ? 0 : 0.5f, 0), - new Vector2(tag.Value ? 0.5f : 1, 1)); - } - } - } -} - -public enum LogicalType: byte -{ - And, - Or, - NotAnd, - NotOr, -} diff --git a/RotationSolver/ActionSequencer/ICondition.cs b/RotationSolver/ActionSequencer/ICondition.cs deleted file mode 100644 index 53ae37cf8..000000000 --- a/RotationSolver/ActionSequencer/ICondition.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace RotationSolver.ActionSequencer; - -internal interface ICondition -{ - bool IsTrue(ICustomRotation rotation); - void Draw(ICustomRotation rotation); -} \ No newline at end of file diff --git a/RotationSolver/ActionSequencer/MajorConditionSet.cs b/RotationSolver/ActionSequencer/MajorConditionSet.cs deleted file mode 100644 index 3a28dce88..000000000 --- a/RotationSolver/ActionSequencer/MajorConditionSet.cs +++ /dev/null @@ -1,78 +0,0 @@ -using ECommons.DalamudServices; -using Lumina.Data.Parsing; -using static FFXIVClientStructs.FFXIV.Client.UI.AddonAOZNotebook; - -namespace RotationSolver.ActionSequencer; - -internal class MajorConditionSet -{ - /// - /// Key for action id. - /// - public Dictionary Conditions { get; } = new (); - - public Dictionary DiabledConditions { get; } = new(); - - public string Name; - public void DrawCondition(uint id, ICustomRotation rotation) - { - - if (!Conditions.TryGetValue(id, out var conditionSet)) - { - conditionSet = Conditions[id] = new ConditionSet(); - } - - if (conditionSet == null) return; - - ConditionSet.DrawCondition(conditionSet.IsTrue(rotation)); - ImGui.SameLine(); - conditionSet?.Draw(rotation); - } - - public void DrawDisabledCondition(uint id, ICustomRotation rotation) - { - if (!DiabledConditions.TryGetValue(id, out var conditionSet)) - { - conditionSet = DiabledConditions[id] = new ConditionSet(); - } - if (conditionSet == null) return; - - ConditionSet.DrawCondition(conditionSet.IsTrue(rotation)); - ImGui.SameLine(); - conditionSet?.Draw(rotation); - } - - public MajorConditionSet(string name) - { - Name = name; - } - - public void Save(string folder) - { - if (!Directory.Exists(folder)) return; - var path = Path.Combine(folder, Name + ".json"); - - var str = JsonConvert.SerializeObject(this, Formatting.Indented); - File.WriteAllText(path, str); - } - - public static MajorConditionSet[] Read(string folder) - { - if (!Directory.Exists(folder)) return Array.Empty(); - - return Directory.EnumerateFiles(folder, "*.json").Select(p => - { - var str = File.ReadAllText(p); - - try - { - return JsonConvert.DeserializeObject(str, new IConditionConverter()); - } - catch - { - Svc.Chat.Print($"Failed to load the conditionSet from {p}"); - return null; - } - }).Where(set => set != null && !string.IsNullOrEmpty(set.Name)).ToArray(); - } -} diff --git a/RotationSolver/ActionSequencer/RotationCondition.cs b/RotationSolver/ActionSequencer/RotationCondition.cs deleted file mode 100644 index 6a4e41119..000000000 --- a/RotationSolver/ActionSequencer/RotationCondition.cs +++ /dev/null @@ -1,236 +0,0 @@ -using Dalamud.Logging; -using ECommons.GameHelpers; -using RotationSolver.Localization; -using RotationSolver.UI; - -namespace RotationSolver.ActionSequencer; - -internal class RotationCondition : BaseCondition -{ - public ComboConditionType ComboConditionType = ComboConditionType.Float; - PropertyInfo _prop; - public string PropertyName = nameof(CustomRotation.CombatTime); - - MethodInfo _method; - public string MethodName = string.Empty; - - IBaseAction _action; - public ActionID ID { get; set; } = ActionID.None; - - public int Condition; - - public int Param1; - public float Param2; - - private void UpdateInfo(ICustomRotation rotation) - { - ConditionHelper.CheckBaseAction(rotation, ID, ref _action); - ConditionHelper.CheckMemberInfo(rotation, ref PropertyName, ref _prop); - ConditionHelper.CheckMemberInfo(rotation, ref MethodName, ref _method); - } - - public override bool IsTrueInside(ICustomRotation rotation) - { - if (!Player.Available) return false; - UpdateInfo(rotation); - - switch (ComboConditionType) - { - case ComboConditionType.Bool: - if (_prop == null) return false; - if (_prop.GetValue(rotation) is bool b) - { - return Condition > 0 ? !b : b; - } - return false; - - case ComboConditionType.Integer: - if (_prop == null) return false; - - var value = _prop.GetValue(rotation); - if (value is byte by) - { - switch (Condition) - { - case 0: - return by > Param1; - case 1: - return by < Param1; - case 2: - return by == Param1; - } - } - else if (value is int i) - { - switch (Condition) - { - case 0: - return i > Param1; - case 1: - return i < Param1; - case 2: - return i == Param1; - } - } - return false; - - case ComboConditionType.Float: - if (_prop == null) return false; - if (_prop.GetValue(rotation) is float fl) - { - switch (Condition) - { - case 0: - return fl > Param2; - case 1: - return fl < Param2; - case 2: - return fl == Param2; - } - } - return false; - - case ComboConditionType.Last: - try - { - if (_method?.Invoke(rotation, new object[] { Param1 > 0, new IAction[] { _action } }) is bool boo) - { - return Condition > 0 ? !boo : boo; - } - return false; - } - catch - { - return false; - } - } - - return false; - } - - string searchTxt = string.Empty; - - private readonly CollapsingHeaderGroup _actionsList = new() - { - HeaderSize = 12, - }; - public override void DrawInside(ICustomRotation rotation) - { - UpdateInfo(rotation); - - ConditionHelper.DrawByteEnum($"##Category{GetHashCode()}", ref ComboConditionType, EnumTranslations.ToName); - - switch (ComboConditionType) - { - case ComboConditionType.Bool: - ImGui.SameLine(); - ConditionHelper.SearchItemsReflection($"##Comparation{GetHashCode()}", _prop?.GetMemberName(), ref searchTxt, rotation.AllBools, i => - { - _prop = i; - PropertyName = i.Name; - }); - ImGui.SameLine(); - - ImGuiHelper.SelectableCombo($"##IsOrNot{GetHashCode()}", new string[] - { - LocalizationManager.RightLang.ActionSequencer_Is, - LocalizationManager.RightLang.ActionSequencer_Isnot, - }, ref Condition); - - break; - - case ComboConditionType.Integer: - ImGui.SameLine(); - ConditionHelper.SearchItemsReflection($"##ByteChoice{GetHashCode()}", _prop?.GetMemberName(), ref searchTxt, rotation.AllBytesOrInt, i => - { - _prop = i; - PropertyName = i.Name; - }); - - ImGui.SameLine(); - - ImGuiHelper.SelectableCombo($"##Comparation{GetHashCode()}", new string[] { ">", "<", "=" }, ref Condition); - - ImGui.SameLine(); - ImGui.SetNextItemWidth(50); - - ImGui.DragInt($"##Value{GetHashCode()}", ref Param1); - - break; - case ComboConditionType.Float: - ImGui.SameLine(); - ConditionHelper.SearchItemsReflection($"##FloatChoice{GetHashCode()}", _prop?.GetMemberName(), ref searchTxt, rotation.AllFloats, i => - { - _prop = i; - PropertyName = i.Name; - }); - - ImGui.SameLine(); - ImGuiHelper.SelectableCombo($"##Comparation{GetHashCode()}", new string[] { ">", "<", "=" }, ref Condition); - - ImGui.SameLine(); - ImGui.SetNextItemWidth(50); - - ImGui.DragFloat($"##Value{GetHashCode()}", ref Param2); - - break; - - case ComboConditionType.Last: - ImGui.SameLine(); - - var names = new string[] - { - nameof(CustomRotation.IsLastGCD), - nameof(CustomRotation.IsLastAction), - nameof(CustomRotation.IsLastAbility), - }; - var index = Math.Max(0, Array.IndexOf(names, MethodName)); - if(ImGuiHelper.SelectableCombo($"##Last{GetHashCode()}", names, ref index)) - { - MethodName = names[index]; - } - - ImGui.SameLine(); - - ImGuiHelper.SelectableCombo($"##IsNot{GetHashCode()}", new string[] - { - LocalizationManager.RightLang.ActionSequencer_Is, - LocalizationManager.RightLang.ActionSequencer_Isnot, - }, ref Condition); - - ImGui.SameLine(); - - var name = _action?.Name ?? string.Empty; - - var popUpKey = "Rotation Condition Pop Up" + GetHashCode().ToString(); - - ConditionHelper.ActionSelectorPopUp(popUpKey, _actionsList, rotation, item => ID = (ActionID)item.ID); - - if (_action?.GetTexture(out var icon) ?? false || IconSet.GetTexture(4, out icon)) - { - var cursor = ImGui.GetCursorPos(); - if (ImGuiHelper.NoPaddingNoColorImageButton(icon.ImGuiHandle, Vector2.One * ConditionHelper.IconSize, GetHashCode().ToString())) - { - if (!ImGui.IsPopupOpen(popUpKey)) ImGui.OpenPopup(popUpKey); - } - ImGuiHelper.DrawActionOverlay(cursor, ConditionHelper.IconSize, 1); - } - - ImGui.SameLine(); - ImGuiHelper.SelectableCombo($"##Adjust{GetHashCode()}", new string[] - { - LocalizationManager.RightLang.ActionSequencer_Original, - LocalizationManager.RightLang.ActionSequencer_Adjusted, - }, ref Param1); - break; - } - } -} - -public enum ComboConditionType : byte -{ - Bool, - Integer, - Float, - Last, -} diff --git a/RotationSolver/ActionSequencer/TargetCondition.cs b/RotationSolver/ActionSequencer/TargetCondition.cs deleted file mode 100644 index 0b5155881..000000000 --- a/RotationSolver/ActionSequencer/TargetCondition.cs +++ /dev/null @@ -1,344 +0,0 @@ -using Dalamud.Interface.Utility; -using ECommons.DalamudServices; -using ECommons.GameHelpers; -using Lumina.Excel.GeneratedSheets; -using RotationSolver.Localization; -using RotationSolver.UI; - -namespace RotationSolver.ActionSequencer; - -internal class TargetCondition : BaseCondition -{ - private static Status[] _allStatus = null; - private static Status[] AllStatus - { - get - { - _allStatus ??= Enum.GetValues().Select(id => Service.GetSheet().GetRow((uint)id)).ToArray(); - return _allStatus; - } - } - - private IBaseAction _action; - public ActionID ID { get; set; } = ActionID.None; - - public bool Condition; - public bool FromSelf; - private Status Status { get; set; } - public StatusID StatusId { get; set; } - public bool IsTarget; - public TargetConditionType TargetConditionType; - - public float DistanceOrTime; - public int GCD; - - public string CastingActionName = string.Empty; - - public override bool IsTrueInside(ICustomRotation rotation) - { - if (!Player.Available) return false; - - BattleChara tar; - if (_action != null) - { - _action.CanUse(out _, CanUseOption.EmptyOrSkipCombo | CanUseOption.MustUse - | CanUseOption.IgnoreTarget); - tar = _action.Target; - } - else - { - tar = IsTarget ? Svc.Targets.Target as BattleChara : Player.Object; - tar ??= Player.Object; - } - - if (tar == null) return false; - - var result = false; - - switch (TargetConditionType) - { - case TargetConditionType.HasStatus: - result = tar.HasStatus(FromSelf, StatusId); - break; - - case TargetConditionType.IsBoss: - result = tar.IsBoss(); - break; - - case TargetConditionType.IsDying: - result = tar.IsDying(); - break; - - case TargetConditionType.InCombat: - result = tar.InCombat(); - break; - - case TargetConditionType.Distance: - result = tar.DistanceToPlayer() > DistanceOrTime; - break; - - case TargetConditionType.StatusEnd: - result = !tar.WillStatusEnd(DistanceOrTime, FromSelf, StatusId); - break; - - case TargetConditionType.StatusEndGCD: - result = !tar.WillStatusEndGCD((uint)GCD, DistanceOrTime, FromSelf, StatusId); - break; - - case TargetConditionType.TimeToKill: - result = tar.GetTimeToKill() > DistanceOrTime; - break; - - case TargetConditionType.CastingAction: - if (string.IsNullOrEmpty(CastingActionName) || tar.CastActionId == 0) - { - result = false; - break; - } - - var castName = Service.GetSheet().GetRow(tar.CastActionId)?.Name.ToString(); - - result = CastingActionName == castName; - break; - - case TargetConditionType.CastingActionTimeUntil: - - if (!tar.IsCasting || tar.CastActionId == 0) - { - result = false; - break; - } - - float castTime = tar.TotalCastTime - tar.CurrentCastTime; - result = castTime > DistanceOrTime + DataCenter.WeaponRemain; - break; - - case TargetConditionType.HP: - result = tar.CurrentHp > GCD; - break; - - case TargetConditionType.MP: - result = tar.CurrentMp > GCD; - break; - } - - return Condition ? !result : result; - } - - string searchTxt = string.Empty; - private readonly CollapsingHeaderGroup _actionsList = new() - { - HeaderSize = 12, - }; - - public override void DrawInside(ICustomRotation rotation) - { - ConditionHelper.CheckBaseAction(rotation, ID, ref _action); - - if (StatusId != StatusID.None && (Status == null || Status.RowId != (uint)StatusId)) - { - Status = AllStatus.FirstOrDefault(a => a.RowId == (uint) StatusId); - } - - var popUpKey = "Target Condition Pop Up" + GetHashCode().ToString(); - - ConditionHelper.ActionSelectorPopUp(popUpKey, _actionsList, rotation, item => ID = (ActionID)item.ID, ()=> - { - if (ImGui.Selectable(LocalizationManager.RightLang.ActionSequencer_Target)) - { - _action = null; - ID = ActionID.None; - IsTarget = true; - } - - if (ImGui.Selectable(LocalizationManager.RightLang.ActionSequencer_Player)) - { - _action = null; - ID = ActionID.None; - IsTarget = false; - } - }); - - if (_action != null ? ( _action.GetTexture(out var icon) || IconSet.GetTexture(4, out icon)) - : IconSet.GetTexture(IsTarget ? 16u : 18u, out icon)) - { - var cursor = ImGui.GetCursorPos(); - if (ImGuiHelper.NoPaddingNoColorImageButton(icon.ImGuiHandle, Vector2.One * ConditionHelper.IconSize, GetHashCode().ToString())) - { - if (!ImGui.IsPopupOpen(popUpKey)) ImGui.OpenPopup(popUpKey); - } - ImGuiHelper.DrawActionOverlay(cursor, ConditionHelper.IconSize, 1); - - var description = _action != null ? string.Format(LocalizationManager.RightLang.ActionSequencer_ActionTarget, _action.Name) - : IsTarget - ? LocalizationManager.RightLang.ActionSequencer_Target - : LocalizationManager.RightLang.ActionSequencer_Player; - ImguiTooltips.HoveredTooltip(description); - } - - ImGui.SameLine(); - ConditionHelper.DrawByteEnum($"##Category{GetHashCode()}", ref TargetConditionType, EnumTranslations.ToName); - - var condition = Condition ? 1 : 0; - var combos = Array.Empty(); - switch (TargetConditionType) - { - case TargetConditionType.HasStatus: - combos = new string[] - { - LocalizationManager.RightLang.ActionSequencer_Has, - LocalizationManager.RightLang.ActionSequencer_HasNot, - }; - break; - case TargetConditionType.IsDying: - case TargetConditionType.IsBoss: - case TargetConditionType.InCombat: - case TargetConditionType.CastingAction: - combos = new string[] - { - LocalizationManager.RightLang.ActionSequencer_Is, - LocalizationManager.RightLang.ActionSequencer_Isnot, - }; - break; - - case TargetConditionType.CastingActionTimeUntil: - case TargetConditionType.Distance: - case TargetConditionType.StatusEnd: - case TargetConditionType.TimeToKill: - case TargetConditionType.HP: - case TargetConditionType.MP: - combos = new string[] { ">", "<=" }; - break; - } - - ImGui.SameLine(); - - if(ImGuiHelper.SelectableCombo($"##Comparation{GetHashCode()}", combos, ref condition)) - { - Condition = condition > 0; - } - - var popupId = "Status Finding Popup" + GetHashCode().ToString(); - - RotationConfigWindow.StatusPopUp(popupId, AllStatus, ref searchTxt, status => - { - Status = status; - StatusId = (StatusID)Status.RowId; - }, size: ConditionHelper.IconSizeRaw); - - void DrawStatusIcon() - { - if (IconSet.GetTexture(Status?.Icon ?? 16220, out var icon) - || IconSet.GetTexture(16220, out icon)) - { - if (ImGuiHelper.NoPaddingNoColorImageButton(icon.ImGuiHandle, new Vector2(ConditionHelper.IconSize * 3 / 4, ConditionHelper.IconSize) * ImGuiHelpers.GlobalScale, GetHashCode().ToString())) - { - if (!ImGui.IsPopupOpen(popupId)) ImGui.OpenPopup(popupId); - } - ImguiTooltips.HoveredTooltip(Status?.Name ?? string.Empty); - } - } - - switch (TargetConditionType) - { - case TargetConditionType.HasStatus: - ImGui.SameLine(); - DrawStatusIcon(); - - ImGui.SameLine(); - - var check = FromSelf ? 1 : 0; - if(ImGuiHelper.SelectableCombo($"From Self {GetHashCode()}", new string[] - { - LocalizationManager.RightLang.ActionSequencer_StatusAll, - LocalizationManager.RightLang.ActionSequencer_StatusSelf, - }, ref check)) - { - FromSelf = check != 0; - } - break; - - case TargetConditionType.StatusEnd: - ImGui.SameLine(); - DrawStatusIcon(); - - ImGui.SameLine(); - - check = FromSelf ? 1 : 0; - if(ImGuiHelper.SelectableCombo($"From Self {GetHashCode()}", new string[] - { - LocalizationManager.RightLang.ActionSequencer_StatusAll, - LocalizationManager.RightLang.ActionSequencer_StatusSelf, - }, ref check)) - { - FromSelf = check != 0; - } - - ConditionHelper.DrawDragFloat($"s##Seconds{GetHashCode()}", ref DistanceOrTime); - break; - - - case TargetConditionType.StatusEndGCD: - ImGui.SameLine(); - DrawStatusIcon(); - - ImGui.SameLine(); - - check = FromSelf ? 1 : 0; - if(ImGuiHelper.SelectableCombo($"From Self {GetHashCode()}", new string[] - { - LocalizationManager.RightLang.ActionSequencer_StatusAll, - LocalizationManager.RightLang.ActionSequencer_StatusSelf, - }, ref check)) - { - FromSelf = check != 0; - } - - ConditionHelper.DrawDragInt($"GCD##GCD{GetHashCode()}", ref GCD); - ConditionHelper.DrawDragFloat($"{LocalizationManager.RightLang.ActionSequencer_TimeOffset}##Ability{GetHashCode()}", ref DistanceOrTime); - break; - - case TargetConditionType.Distance: - if (ConditionHelper.DrawDragFloat($"yalm##yalm{GetHashCode()}", ref DistanceOrTime)) - { - DistanceOrTime = Math.Max(0, DistanceOrTime); - } - break; - - case TargetConditionType.CastingAction: - ImGui.SameLine(); - ImGuiHelper.SetNextWidthWithName(CastingActionName); - ImGui.InputText($"Ability name##CastingActionName{GetHashCode()}", ref CastingActionName, 128); - break; - - case TargetConditionType.CastingActionTimeUntil: - ImGui.SameLine(); - ImGui.SetNextItemWidth(Math.Max(150 * ImGuiHelpers.GlobalScale, ImGui.CalcTextSize(DistanceOrTime.ToString()).X)); - ImGui.DragFloat($"s##CastingActionTimeUntil{GetHashCode()}", ref DistanceOrTime, .1f); - break; - - case TargetConditionType.MP: - case TargetConditionType.HP: - ImGui.SameLine(); - ImGui.SetNextItemWidth(Math.Max(150 * ImGuiHelpers.GlobalScale, ImGui.CalcTextSize(GCD.ToString()).X)); - ImGui.DragInt($"##HPorMP{GetHashCode()}", ref GCD, .1f); - break; - } - } -} - -public enum TargetConditionType : byte -{ - HasStatus, - IsDying, - IsBoss, - InCombat, - Distance, - StatusEnd, - StatusEndGCD, - CastingAction, - CastingActionTimeUntil, - TimeToKill, - HP, - MP, -} \ No newline at end of file diff --git a/RotationSolver/ActionSequencer/TraitCondition.cs b/RotationSolver/ActionSequencer/TraitCondition.cs deleted file mode 100644 index a941082c1..000000000 --- a/RotationSolver/ActionSequencer/TraitCondition.cs +++ /dev/null @@ -1,97 +0,0 @@ -using ECommons.GameHelpers; -using RotationSolver.Basic.Traits; -using RotationSolver.Localization; -using RotationSolver.UI; - -namespace RotationSolver.ActionSequencer; - -internal class TraitCondition : BaseCondition -{ - public uint TraitID { get; set; } = 0; - private IBaseTrait _trait; - public bool Condition { get; set; } - - public override bool IsTrueInside(ICustomRotation rotation) - { - CheckBaseTrait(rotation); - if (_trait == null || !Player.Available) return false; - - var result = _trait.EnoughLevel; - return Condition ? !result : result; - } - - private const int count = 8; - public override void DrawInside(ICustomRotation rotation) - { - CheckBaseTrait(rotation); - - var name = _trait?.Name ?? string.Empty; - var popUpKey = "Trait Condition Pop Up" + GetHashCode().ToString(); - - if (ImGui.BeginPopup(popUpKey)) - { - var index = 0; - foreach (var trait in rotation.AllTraits) - { - if (!trait.GetTexture(out var traitIcon)) continue; - - if (index++ % count != 0) - { - ImGui.SameLine(); - } - - ImGui.BeginGroup(); - var cursor = ImGui.GetCursorPos(); - if (ImGuiHelper.NoPaddingNoColorImageButton(traitIcon.ImGuiHandle, Vector2.One * ConditionHelper.IconSize, trait.GetHashCode().ToString())) - { - TraitID = trait.ID; - ImGui.CloseCurrentPopup(); - } - ImGuiHelper.DrawActionOverlay(cursor, ConditionHelper.IconSize, -1); - ImGui.EndGroup(); - - var tooltip = trait.Name; - if (!string.IsNullOrEmpty(tooltip)) ImguiTooltips.HoveredTooltip(tooltip); - - } - ImGui.EndPopup(); - } - - if (_trait?.GetTexture(out var icon) ?? false || IconSet.GetTexture(4, out icon)) - { - var cursor = ImGui.GetCursorPos(); - if (ImGuiHelper.NoPaddingNoColorImageButton(icon.ImGuiHandle, Vector2.One * ConditionHelper.IconSize, GetHashCode().ToString())) - { - if (!ImGui.IsPopupOpen(popUpKey)) ImGui.OpenPopup(popUpKey); - } - ImGuiHelper.DrawActionOverlay(cursor, ConditionHelper.IconSize, -1); - ImguiTooltips.HoveredTooltip(name); - } - - ImGui.SameLine(); - var i = 0; - ImGuiHelper.SelectableCombo($"##Category{GetHashCode()}", new string[] - { - LocalizationManager.RightLang.ActionConditionType_EnoughLevel - }, ref i); - ImGui.SameLine(); - - var condition = Condition ? 1 : 0; - if (ImGuiHelper.SelectableCombo($"##Comparation{GetHashCode()}", new string[] - { - LocalizationManager.RightLang.ActionSequencer_Is, - LocalizationManager.RightLang.ActionSequencer_Isnot, - }, ref condition)) - { - Condition = condition > 0; - } - } - - private void CheckBaseTrait(ICustomRotation rotation) - { - if (TraitID != 0 && (_trait == null || _trait.ID != TraitID)) - { - _trait = rotation.AllTraits.FirstOrDefault(a => a.ID == TraitID); - } - } -} diff --git a/RotationSolver/Commands/RSCommands_OtherCommand.cs b/RotationSolver/Commands/RSCommands_OtherCommand.cs index e3df95581..bfc1660a0 100644 --- a/RotationSolver/Commands/RSCommands_OtherCommand.cs +++ b/RotationSolver/Commands/RSCommands_OtherCommand.cs @@ -3,145 +3,144 @@ using RotationSolver.Localization; using RotationSolver.Updaters; -namespace RotationSolver.Commands +namespace RotationSolver.Commands; + +public static partial class RSCommands { - public static partial class RSCommands + private static void DoOtherCommand(OtherCommandType otherType, string str) { - private static void DoOtherCommand(OtherCommandType otherType, string str) + switch (otherType) { - switch (otherType) - { - case OtherCommandType.Rotations: - var customCombo = RotationUpdater.RightNowRotation; - if (customCombo == null) return; + case OtherCommandType.Rotations: + var customCombo = DataCenter.RightNowRotation; + if (customCombo == null) return; - DoRotationCommand(customCombo, str); - break; + DoRotationCommand(customCombo, str); + break; - case OtherCommandType.DoActions: - DoActionCommand(str); - break; + case OtherCommandType.DoActions: + DoActionCommand(str); + break; - case OtherCommandType.ToggleActions: - ToggleActionCommand(str); - break; + case OtherCommandType.ToggleActions: + ToggleActionCommand(str); + break; - case OtherCommandType.Settings: - DoSettingCommand(str); - break; + case OtherCommandType.Settings: + DoSettingCommand(str); + break; - case OtherCommandType.NextAction: - DoAction(); - break; - } + case OtherCommandType.NextAction: + DoAction(); + break; } + } - private static void DoSettingCommand(string str) + private static void DoSettingCommand(string str) + { + var job = DataCenter.Job; + var strs = str.Split(' '); + var value = strs.LastOrDefault(); + if(TryGetOneEnum(str, out var b)) { - var job = DataCenter.Job; - var strs = str.Split(' '); - var value = strs.LastOrDefault(); - if(TryGetOneEnum(str, out var b)) - { - var v = !Service.Config.GetValue(b); - Service.Config.SetValue(b, v); - value = Service.Config.GetValue(b).ToString(); - } - else if (TryGetOneEnum(str, out var f) && float.TryParse(value, out var f1)) - { - Service.Config.SetValue(f, f1); - value = Service.Config.GetValue(f).ToString(); - } - else if (TryGetOneEnum(str, out var i) && int.TryParse(value, out var i1)) - { - Service.Config.SetValue(i, i1); - value = Service.Config.GetValue(i).ToString(); - - } - else if (TryGetOneEnum(str, out var f2) && float.TryParse(value, out f1)) - { - Service.Config.SetValue(job, f2, f1); - value = Service.Config.GetValue(job, f2).ToString(); + var v = !Service.Config.GetValue(b); + Service.Config.SetBoolRaw(b, v); + value = Service.Config.GetValue(b).ToString(); + } + else if (TryGetOneEnum(str, out var f) && float.TryParse(value, out var f1)) + { + Service.Config.SetValue(f, f1); + value = Service.Config.GetValue(f).ToString(); + } + else if (TryGetOneEnum(str, out var i) && int.TryParse(value, out var i1)) + { + Service.Config.SetValue(i, i1); + value = Service.Config.GetValue(i).ToString(); - } - else if (TryGetOneEnum(str, out var i2) && int.TryParse(value, out i1)) - { - Service.Config.SetValue(job, i2, i1); - value = Service.Config.GetValue(job, i2).ToString(); - } - else - { - Svc.Chat.PrintError(LocalizationManager.RightLang.Commands_CannotFindConfig); - return; - } + } + else if (TryGetOneEnum(str, out var f2) && float.TryParse(value, out f1)) + { + Service.Config.SetValue(job, f2, f1); + value = Service.Config.GetValue(job, f2).ToString(); - //Say out. - Svc.Chat.Print(string.Format(LocalizationManager.RightLang.Commands_ChangeSettingsValue, - strs.FirstOrDefault(), value)); + } + else if (TryGetOneEnum(str, out var i2) && int.TryParse(value, out i1)) + { + Service.Config.SetValue(job, i2, i1); + value = Service.Config.GetValue(job, i2).ToString(); + } + else + { + Svc.Chat.PrintError(LocalizationManager.RightLang.Commands_CannotFindConfig); + return; } - private static void ToggleActionCommand(string str) + //Say out. + Svc.Chat.Print(string.Format(LocalizationManager.RightLang.Commands_ChangeSettingsValue, + strs.FirstOrDefault(), value)); + } + + private static void ToggleActionCommand(string str) + { + foreach (var act in RotationUpdater.RightRotationActions) { - foreach (var act in RotationUpdater.RightRotationActions) + if (str.StartsWith(act.Name)) { - if (str.StartsWith(act.Name)) - { - var flag = str.Substring(act.Name.Length).Trim(); + var flag = str[act.Name.Length..].Trim(); - act.IsEnabled = bool.TryParse(flag, out var parse) ? parse : !act.IsEnabled; + act.IsEnabled = bool.TryParse(flag, out var parse) ? parse : !act.IsEnabled; - return; - } + return; } } + } - private static void DoActionCommand(string str) - { - var strs = str.Split('-'); + private static void DoActionCommand(string str) + { + var strs = str.Split('-'); - if (strs != null && strs.Length == 2 && double.TryParse(strs[1], out var time)) + if (strs != null && strs.Length == 2 && double.TryParse(strs[1], out var time)) + { + var actName = strs[0]; + foreach (var iAct in RotationUpdater.RightRotationActions) { - var actName = strs[0]; - foreach (var iAct in RotationUpdater.RightRotationActions) + if (actName == iAct.Name) { - if (actName == iAct.Name) + DataCenter.AddCommandAction(iAct, time); + + if (Service.Config.GetValue(PluginConfigBool.ShowToastsAboutDoAction)) { - DataCenter.AddCommandAction(iAct, time); - - if (Service.Config.GetValue(PluginConfigBool.ShowToastsAboutDoAction)) - { - Svc.Toasts.ShowQuest(string.Format(LocalizationManager.RightLang.Commands_InsertAction, time), - new Dalamud.Game.Gui.Toast.QuestToastOptions() - { - IconId = iAct.IconID, - }); - } - - return; + Svc.Toasts.ShowQuest(string.Format(LocalizationManager.RightLang.Commands_InsertAction, time), + new Dalamud.Game.Gui.Toast.QuestToastOptions() + { + IconId = iAct.IconID, + }); } + + return; } } - - Svc.Chat.PrintError(LocalizationManager.RightLang.Commands_InsertActionFailure); } + Svc.Chat.PrintError(LocalizationManager.RightLang.Commands_InsertActionFailure); + } + - private static void DoRotationCommand(ICustomRotation customCombo, string str) + private static void DoRotationCommand(ICustomRotation customCombo, string str) + { + var configs = customCombo.Configs; + foreach (var config in configs) { - var configs = customCombo.Configs; - foreach (var config in configs) + if (config.DoCommand(configs, str)) { - if (config.DoCommand(configs, str)) - { - Svc.Chat.Print(config.GetType().FullName); - Svc.Chat.Print(str); - Svc.Chat.Print(string.Format(LocalizationManager.RightLang.Commands_ChangeRotationConfig, - config.DisplayName, configs.GetDisplayString(config.Name))); + Svc.Chat.Print(config.GetType().FullName); + Svc.Chat.Print(str); + Svc.Chat.Print(string.Format(LocalizationManager.RightLang.Commands_ChangeRotationConfig, + config.DisplayName, configs.GetDisplayString(config.Name))); - return; - } + return; } - Svc.Chat.PrintError(LocalizationManager.RightLang.Commands_CannotFindRotationConfig); } + Svc.Chat.PrintError(LocalizationManager.RightLang.Commands_CannotFindRotationConfig); } } diff --git a/RotationSolver/Localization/ConfigTranslation.cs b/RotationSolver/Localization/ConfigTranslation.cs index 45e600873..3e207f55c 100644 --- a/RotationSolver/Localization/ConfigTranslation.cs +++ b/RotationSolver/Localization/ConfigTranslation.cs @@ -302,14 +302,14 @@ private static string ToCommandStr(object obj, string extra = "") public static LinkDescription[] ToAction(this PluginConfigFloat config) => config switch { - PluginConfigFloat.ActionAhead => new LinkDescription[] - { - //new LinkDescription() - //{ - // Url = $"https://raw.githubusercontent.com/{Service.USERNAME}/{Service.REPO}/main/Images/HowAndWhenToClick.svg", - // Description = "This plugin helps you to use the right action during the combat. Here is a guide about the different options.", - //}, - }, + //PluginConfigFloat.ActionAhead => new LinkDescription[] + //{ + // //new LinkDescription() + // //{ + // // Url = $"https://raw.githubusercontent.com/{Service.USERNAME}/{Service.REPO}/main/Images/HowAndWhenToClick.svg", + // // Description = "This plugin helps you to use the right action during the combat. Here is a guide about the different options.", + // //}, + //}, //PluginConfigFloat.MinLastAbilityAdvanced => new LinkDescription[] //{ //}, diff --git a/RotationSolver/Localization/EnumTranslations.cs b/RotationSolver/Localization/EnumTranslations.cs index 3eee17b75..fcf203d49 100644 --- a/RotationSolver/Localization/EnumTranslations.cs +++ b/RotationSolver/Localization/EnumTranslations.cs @@ -1,5 +1,5 @@ using Dalamud.Game.ClientState.Keys; -using RotationSolver.ActionSequencer; +using RotationSolver.Basic.Configuration.Conditions; namespace RotationSolver.Localization; diff --git a/RotationSolver/Localization/Localization.json b/RotationSolver/Localization/Localization.json index 5f5e4f363..0cc1c0c02 100644 --- a/RotationSolver/Localization/Localization.json +++ b/RotationSolver/Localization/Localization.json @@ -302,7 +302,17 @@ "NumberOfHostilesInMaxRange": "The number of hostiles in max Range", "NumberOfAllHostilesInRange": "The number of all hostiles in Range", "NumberOfAllHostilesInMaxRange": "The number of all hostiles in max Range", - "InBurst": "In burst.", + "IsBurst": "Is burst", + "IsHealArea": "Is Heal Area", + "IsHealSingle": "Is Heal Single", + "IsDefenseArea": "Is Defense Area", + "IsDefenseSingle": "Is Defense Single", + "IsEsunaStanceNorth": "Is Esuna Stance North", + "IsRaiseShirk": "Is Raise Shirk", + "IsMoveForward": "Is Move Forward", + "IsMoveBack": "Is Move Back", + "IsAntiKnockback": "Is Anti Knockback", + "IsSpeed": "Is Speed", "CanHealAreaAbility": "Can heal area ability", "CanHealAreaSpell": "Can heal area spell", "CanHealSingleAbility": "Can heal single ability", @@ -310,6 +320,7 @@ "AutoState": "The state of auto. True for on.", "IsManual": "The state of manual. True for manual.", "IsInHighEndDuty": "Is in the high-end duty", + "IsInDuty": "Is player in duty", "Ping": "Your ping", "NextAbilityToNextGCD": "Time from next ability to next GCD", "IsLastGCD": "Just used GCD", @@ -476,6 +487,7 @@ "ConfigWindow_Extra_Description": "Rotation Solver focuses on the rotation itself. These are side features. If there are some other plugins can do that, these features will be deleted.", "ConfigWindow_Auto_Description": "Change the way that RS atomatically uses actions.", "ConfigWindow_Auto_ActionCondition": "Action Condition", + "ConfigWindow_Auto_StateCondition": "State Condition", "ConfigWindow_Auto_ActionCondition_Description": "This will change the way that Rotation Solver uses actions.", "ConfigWindow_Target_Config": "Configuration", "ConfigWindow_Search_Result": "Search Result", @@ -533,5 +545,21 @@ "ConfigWindow_About_Clicking500k": "You're tiring RS out, give it a break!", "ConfigWindow_About_ThanksToSupporters": "Many thanks to the sponsors.", "ConfigWindow_Rotations_Download": "Download Rotations", - "ConfigWindow_Rotations_Links": "Links of the rotations online" + "ConfigWindow_Rotations_Links": "Links of the rotations online", + "ConfigWindow_Options_ForcedEnableCondition": "Use Forced Enable Condition", + "ConfigWindow_Options_ForcedEnableConditionDesc": "The conditions of forced to make it true.", + "ConfigWindow_Options_ForcedDisableCondition": "Use Forced Disable Condition", + "ConfigWindow_Options_ForcedDisableConditionDesc": "The conditions of forced to make it false.", + "ConfigWindow_Auto_HealAreaConditionSet": "Heal Area Forced Condition", + "ConfigWindow_Auto_HealSingleConditionSet": "Heal Single Forced Condition", + "ConfigWindow_Auto_DefenseAreaConditionSet": "Defense Area Forced Condition", + "ConfigWindow_Auto_DefenseSingleConditionSet": "Defense Single Forced Condition", + "ConfigWindow_Auto_EsunaStanceNorthConditionSet": "Esuna Stance North Forced Condition", + "ConfigWindow_Auto_RaiseShirkConditionSet": "Raise Shirk Forced Condition", + "ConfigWindow_Auto_MoveForwardConditionSet": "Move Forward Forced Condition", + "ConfigWindow_Auto_MoveBackConditionSet": "Move Back Forced Condition", + "ConfigWindow_Auto_AntiKnockbackConditionSet": "Anti Knockback Forced Condition", + "ConfigWindow_Auto_BurstConditionSet": "Burst Forced Condition", + "ConfigWindow_Auto_SpeedConditionSet": "Speed Forced Condition", + "ConfigWindow_ConditionSetDesc": "The Condition set you chose, click to modify." } \ No newline at end of file diff --git a/RotationSolver/Localization/Strings.cs b/RotationSolver/Localization/Strings.cs index a09ae8500..1d18d556c 100644 --- a/RotationSolver/Localization/Strings.cs +++ b/RotationSolver/Localization/Strings.cs @@ -427,7 +427,17 @@ internal class Strings { nameof(CustomRotation.NumberOfHostilesInMaxRange), "The number of hostiles in max Range"}, { nameof(CustomRotation.NumberOfAllHostilesInRange), "The number of all hostiles in Range"}, { nameof(CustomRotation.NumberOfAllHostilesInMaxRange), "The number of all hostiles in max Range"}, - { nameof(CustomRotation.InBurst), "In burst."}, + { nameof(CustomRotation.IsBurst), "Is burst"}, + { nameof(CustomRotation.IsHealArea), "Is Heal Area"}, + { nameof(CustomRotation.IsHealSingle), "Is Heal Single"}, + { nameof(CustomRotation.IsDefenseArea), "Is Defense Area"}, + { nameof(CustomRotation.IsDefenseSingle), "Is Defense Single"}, + { nameof(CustomRotation.IsEsunaStanceNorth), "Is Esuna Stance North"}, + { nameof(CustomRotation.IsRaiseShirk), "Is Raise Shirk"}, + { nameof(CustomRotation.IsMoveForward), "Is Move Forward"}, + { nameof(CustomRotation.IsMoveBack), "Is Move Back"}, + { nameof(CustomRotation.IsAntiKnockback), "Is Anti Knockback"}, + { nameof(CustomRotation.IsSpeed), "Is Speed"}, { nameof(CustomRotation.CanHealAreaAbility), "Can heal area ability"}, { nameof(CustomRotation.CanHealAreaSpell), "Can heal area spell"}, @@ -438,6 +448,7 @@ internal class Strings { nameof(CustomRotation.IsManual), "The state of manual. True for manual."}, { nameof(CustomRotation.IsInHighEndDuty), "Is in the high-end duty"}, + { nameof(CustomRotation.IsInDuty), "Is player in duty"}, { nameof(CustomRotation.Ping), "Your ping"}, { nameof(CustomRotation.NextAbilityToNextGCD), "Time from next ability to next GCD"}, @@ -685,6 +696,7 @@ internal class Strings public string ConfigWindow_Extra_Description { get; set; } = "Rotation Solver focuses on the rotation itself. These are side features. If there are some other plugins can do that, these features will be deleted."; public string ConfigWindow_Auto_Description { get; set; } = "Change the way that RS atomatically uses actions."; public string ConfigWindow_Auto_ActionCondition { get; set; } = "Action Condition"; + public string ConfigWindow_Auto_StateCondition { get; set; } = "State Condition"; public string ConfigWindow_Auto_ActionCondition_Description { get; set; } = "This will change the way that Rotation Solver uses actions."; public string ConfigWindow_Target_Config { get; set; } = "Configuration"; public string ConfigWindow_Search_Result { get; set; } = "Search Result"; @@ -754,4 +766,23 @@ internal class Strings public string ConfigWindow_About_ThanksToSupporters { get; set; } = "Many thanks to the sponsors."; public string ConfigWindow_Rotations_Download { get; set; } = "Download Rotations"; public string ConfigWindow_Rotations_Links { get; set; } = "Links of the rotations online"; + public string ConfigWindow_Options_ForcedEnableCondition { get; set; } = "Use Forced Enable Condition"; + public string ConfigWindow_Options_ForcedEnableConditionDesc { get; set; } = "The conditions of forced to make it true."; + + public string ConfigWindow_Options_ForcedDisableCondition { get; set; } = "Use Forced Disable Condition"; + public string ConfigWindow_Options_ForcedDisableConditionDesc { get; set; } = "The conditions of forced to make it false."; + + public string ConfigWindow_Auto_HealAreaConditionSet { get; set; } = "Heal Area Forced Condition"; + public string ConfigWindow_Auto_HealSingleConditionSet { get; set; } = "Heal Single Forced Condition"; + public string ConfigWindow_Auto_DefenseAreaConditionSet { get; set; } = "Defense Area Forced Condition"; + public string ConfigWindow_Auto_DefenseSingleConditionSet { get; set; } = "Defense Single Forced Condition"; + public string ConfigWindow_Auto_EsunaStanceNorthConditionSet { get; set; } = "Esuna Stance North Forced Condition"; + public string ConfigWindow_Auto_RaiseShirkConditionSet { get; set; } = "Raise Shirk Forced Condition"; + public string ConfigWindow_Auto_MoveForwardConditionSet { get; set; } = "Move Forward Forced Condition"; + public string ConfigWindow_Auto_MoveBackConditionSet { get; set; } = "Move Back Forced Condition"; + public string ConfigWindow_Auto_AntiKnockbackConditionSet { get; set; } = "Anti Knockback Forced Condition"; + public string ConfigWindow_Auto_BurstConditionSet { get; set; } = "Burst Forced Condition"; + public string ConfigWindow_Auto_SpeedConditionSet { get; set; } = "Speed Forced Condition"; + public string ConfigWindow_ConditionSetDesc { get; set; } = "The Condition set you chose, click to modify."; + } \ No newline at end of file diff --git a/RotationSolver/Localization/de.json b/RotationSolver/Localization/de.json index cf0caef6c..a18a1d105 100644 --- a/RotationSolver/Localization/de.json +++ b/RotationSolver/Localization/de.json @@ -414,6 +414,7 @@ }, "HighEndWarning": "Please separately keybind damage reduction / shield cooldowns in case RS fails at a crucial moment in {0}!", "TextToTalkWarning": "You didn't install TextToTalk, please install it to make Rotation Solver say something for you!", + "AvariceWarning": "It seems that you didn't installed Avarice. If you want to get the positional indicator from Rotation Solver, please install it.", "ClickingMistakeMessage": "OOOps! RS clicked the wrong action ({0})!", "ConfigWindow_About_Punchline": "Analyses PvE combat information every frame and finds the best action.", "ConfigWindow_About_Description": "This means almost all the information available in one frame in combat, including the status of all players in the party, the status of any hostile targets, skill cooldowns, the MP and HP of characters, the location of characters, casting status of the hostile target, combo, combat duration, player level, etc.\n\nThen, it will highlight the best action on the hot bar, or help you to click on it.", @@ -495,7 +496,7 @@ "ConfigWindow_Actions_MoveDown": "Move Down", "ConfigWindow_NotInJob": "This option is unavailable while using your current job\n \nRoles or jobs needed:\n{0}", "ConfigWindow_Searching": "Search...", - "ConfigWindow_UI_HideWarning": "Hide warning when entering High-end Duty", + "ConfigWindow_UI_HideWarning": "Hide all warnings", "ConfigWindow_Auto_BeneficialAreaStrategy": "Beneficial AoE strategy", "ConfigWindow_About_OpenConfigFolder": "Open Config Folder", "ConfigWindow_Basic_AnimationLockTime": "The Animation lock time from individual actions. Here is 0.6s for example.", diff --git a/RotationSolver/Localization/es.json b/RotationSolver/Localization/es.json index 25f14e265..40b703851 100644 --- a/RotationSolver/Localization/es.json +++ b/RotationSolver/Localization/es.json @@ -414,6 +414,7 @@ }, "HighEndWarning": "Please separately keybind damage reduction / shield cooldowns in case RS fails at a crucial moment in {0}!", "TextToTalkWarning": "You didn't install TextToTalk, please install it to make Rotation Solver say something for you!", + "AvariceWarning": "It seems that you didn't installed Avarice. If you want to get the positional indicator from Rotation Solver, please install it.", "ClickingMistakeMessage": "OOOps! RS clicked the wrong action ({0})!", "ConfigWindow_About_Punchline": "Analyses PvE combat information every frame and finds the best action.", "ConfigWindow_About_Description": "This means almost all the information available in one frame in combat, including the status of all players in the party, the status of any hostile targets, skill cooldowns, the MP and HP of characters, the location of characters, casting status of the hostile target, combo, combat duration, player level, etc.\n\nThen, it will highlight the best action on the hot bar, or help you to click on it.", @@ -495,7 +496,7 @@ "ConfigWindow_Actions_MoveDown": "Move Down", "ConfigWindow_NotInJob": "This option is unavailable while using your current job\n \nRoles or jobs needed:\n{0}", "ConfigWindow_Searching": "Search...", - "ConfigWindow_UI_HideWarning": "Hide warning when entering High-end Duty", + "ConfigWindow_UI_HideWarning": "Hide all warnings", "ConfigWindow_Auto_BeneficialAreaStrategy": "Beneficial AoE strategy", "ConfigWindow_About_OpenConfigFolder": "Open Config Folder", "ConfigWindow_Basic_AnimationLockTime": "The Animation lock time from individual actions. Here is 0.6s for example.", diff --git a/RotationSolver/Localization/fr.json b/RotationSolver/Localization/fr.json index 5cb628b8a..0269321f3 100644 --- a/RotationSolver/Localization/fr.json +++ b/RotationSolver/Localization/fr.json @@ -414,6 +414,7 @@ }, "HighEndWarning": "Please separately keybind damage reduction / shield cooldowns in case RS fails at a crucial moment in {0}!", "TextToTalkWarning": "You didn't install TextToTalk, please install it to make Rotation Solver say something for you!", + "AvariceWarning": "It seems that you didn't installed Avarice. If you want to get the positional indicator from Rotation Solver, please install it.", "ClickingMistakeMessage": "OOOps! RS clicked the wrong action ({0})!", "ConfigWindow_About_Punchline": "Analyses PvE combat information every frame and finds the best action.", "ConfigWindow_About_Description": "This means almost all the information available in one frame in combat, including the status of all players in the party, the status of any hostile targets, skill cooldowns, the MP and HP of characters, the location of characters, casting status of the hostile target, combo, combat duration, player level, etc.\n\nThen, it will highlight the best action on the hot bar, or help you to click on it.", @@ -495,7 +496,7 @@ "ConfigWindow_Actions_MoveDown": "Move Down", "ConfigWindow_NotInJob": "This option is unavailable while using your current job\n \nRoles or jobs needed:\n{0}", "ConfigWindow_Searching": "Search...", - "ConfigWindow_UI_HideWarning": "Hide warning when entering High-end Duty", + "ConfigWindow_UI_HideWarning": "Hide all warnings", "ConfigWindow_Auto_BeneficialAreaStrategy": "Beneficial AoE strategy", "ConfigWindow_About_OpenConfigFolder": "Open Config Folder", "ConfigWindow_Basic_AnimationLockTime": "The Animation lock time from individual actions. Here is 0.6s for example.", diff --git a/RotationSolver/Localization/ja.json b/RotationSolver/Localization/ja.json index 9c1bb1cfa..9a437d26c 100644 --- a/RotationSolver/Localization/ja.json +++ b/RotationSolver/Localization/ja.json @@ -8,10 +8,10 @@ "Commands_InsertActionFailure": "アクションを見つけることができません。アクション名を確認してください。", "ConfigWindow_Header": "Rotation Solver Settings v", "ConfigWindow_EventItem": "イベント", - "ConfigWindow_HelpItem_AttackAuto": "Start the addon in Auto mode. When out of combat or when combat starts, switches the target according to the set condition.", - "ConfigWindow_HelpItem_AttackManual": "Start the addon in Manual mode. You need to choose the target manually. This will bypass any engage settings that you have set up and will start attacking immediately once something is targeted.", + "ConfigWindow_HelpItem_AttackAuto": "Auto mode を開始します。戦闘終了時、または戦闘開始時、設定した条件に応じてターゲットを切替えます。", + "ConfigWindow_HelpItem_AttackManual": "Manual mode を開始します。 これは、ターゲットを手動で選択する必要があります。ターゲット状態になることで、すぐに攻撃が開始されます。", "ConfigWindow_HelpItem_NextAction": "次のアクションを実行", - "ConfigWindow_HelpItem_AttackCancel": "Stop the addon. Always remember to turn it off when it is not in use!", + "ConfigWindow_HelpItem_AttackCancel": "動作を停止します。使用しない場合はこのモードにしてください!", "ConfigWindow_HelpItem_HealArea": "1つ以上のAoEヒーリングを使用するウィンドウを開きます。", "ConfigWindow_HelpItem_HealSingle": "1つまたは複数の単体ヒールを使用するウィンドウを開きます。", "ConfigWindow_HelpItem_DefenseArea": "1つ以上のAoE軽減を使用するウィンドウを開きます。", @@ -108,8 +108,8 @@ "ConfigWindow_Param_RaisePlayerByCasting": "Raise player while swiftcast is on cooldown", "ConfigWindow_Param_UseHealWhenNotAHealer": "Use healing abilities when playing a non-healer role", "ConfigWindow_Param_LessMPNoRaise": "Never raise player if MP is less than the set value", - "ConfigWindow_Param_UseTinctures": "Use Tinctures", - "ConfigWindow_Param_UseHealPotions": "Use Heal Potions", + "ConfigWindow_Param_UseTinctures": "幻薬を使用", + "ConfigWindow_Param_UseHealPotions": "ポーションを使用", "ConfigWindow_Param_StartOnCountdown": "Auto mode activation delay on countdown start", "ConfigWindow_Param_StartOnAttackedBySomeone": "Automatically turn on manual mode and target enemy when being attacked", "ConfigWindow_Param_EsunaAll": "Cleanse all dispellable debuffs.", @@ -180,8 +180,8 @@ "ConfigWindow_Control_CooldownWindowIconSize": "Cooldown icon size", "ConfigWindow_Control_ControlWindowNextSizeRatio": "Next Action Size Ratio", "ConfigWindow_Rotation_BetaRotation": "Beta Rotation!", - "ConfigWindow_Rotation_DownloadRotations": "Auto Download Rotations", - "ConfigWindow_Rotation_AutoUpdateRotations": "Auto Update Rotations", + "ConfigWindow_Rotation_DownloadRotations": "ローテーションの自動ダウンロード", + "ConfigWindow_Rotation_AutoUpdateRotations": "ローテーションの自動アップデート", "ConfigWindow_Rotation_InvalidRotation": "Invalid Rotation! \nPlease update to the latest version or contact to the {0}!", "ConfigWindow_List_Description": "In this window, you can set the parameters that can be customised using lists.", "ConfigWindow_List_Hostile": "Hostile", @@ -414,16 +414,17 @@ }, "HighEndWarning": "Please separately keybind damage reduction / shield cooldowns in case RS fails at a crucial moment in {0}!", "TextToTalkWarning": "You didn't install TextToTalk, please install it to make Rotation Solver say something for you!", + "AvariceWarning": "It seems that you didn't installed Avarice. If you want to get the positional indicator from Rotation Solver, please install it.", "ClickingMistakeMessage": "OOOps! RS clicked the wrong action ({0})!", - "ConfigWindow_About_Punchline": "Analyses PvE combat information every frame and finds the best action.", - "ConfigWindow_About_Description": "This means almost all the information available in one frame in combat, including the status of all players in the party, the status of any hostile targets, skill cooldowns, the MP and HP of characters, the location of characters, casting status of the hostile target, combo, combat duration, player level, etc.\n\nThen, it will highlight the best action on the hot bar, or help you to click on it.", - "ConfigWindow_About_Warning": "It is designed for GENERAL COMBAT, not for savage or ultimate. Use it carefully.", + "ConfigWindow_About_Punchline": "PvEの戦闘情報を各フレームごとに分析し、最適なアクションを見つけます。", + "ConfigWindow_About_Description": "これは、パーティ内の全プレイヤーのステータス、スキルのクールダウン、キャラクターのHPとMP、キャラクターの位置、敵ターゲットのキャスト状態、コンボ、戦闘時間、プレイヤーレベルなどの戦闘で使用可能なほぼすべての情報を意味します。\n\nそれらは、ホットバー上の最適なアクションを強調表示したり、クリックするのに役立ちます。", + "ConfigWindow_About_Warning": "注意:零式や絶のためではなく、一般的な戦闘のために設計されています。", "ConfigWindow_About_Macros": "Macros", "ConfigWindow_About_Links": "Links", "ConfigWindow_About_Compatibility": "Compatibility", "ConfigWindow_About_Supporters": "Supporters", - "ConfigWindow_About_Compatibility_Description": "Literally, Rotation Solver helps you to choose the target and then click the action. So any plugin that changes these will affect its decision.\n\nHere is a list of known incompatible plugins:", - "ConfigWindow_About_Compatibility_Others": "Please don't relog without closing the game. Crashes may occur.", + "ConfigWindow_About_Compatibility_Description": "文字通り、Rotation Solverはターゲットを選択してからアクションをクリックするのに役立ちます。他のプラグインはRotation Solverに影響を及ぼす可能性があります。\n\n下記は、影響を及ぼす可能性があると認知しているのプラグインの一覧です。", + "ConfigWindow_About_Compatibility_Others": "ゲームを終了せずに再ログインしないでください。クラッシュが発生する可能性があります。", "ConfigWindow_About_Compatibility_Mistake": "Can't properly execute the behavior that RS wants to do.", "ConfigWindow_About_Compatibility_Mislead": "Misleading RS to make the right decision.", "ConfigWindow_About_Compatibility_Crash": "Causes the game to crash.", @@ -435,7 +436,7 @@ "ConfigWindow_Rotation_Rating_Description": "Here are some rating methods to analysis this rotation. Most of these methods need your engagement.", "ConfigWindow_Rotation_Rating_CountOfLastUsing": "This is the count of using last action checking in this rotation. First is average one, second is maximum one. The less the better.\nLast used action is not a part of information from the game, it is recorded by player or author. \nIt can't accurately describe the current state of combat, which may make this rotation not general. \nFor example, clipping the gcd, death, take some status that grated by some action off manually, etc.", "ConfigWindow_Rotation_Rating_CountOfCombatTimeUsing": "This is the count of using combat time in this rotation. First is average one, second is maximum one. The less the better.\nCombat time is not a part of information from the game, it is recorded by player or author. \nIt can't accurately describe the current state of combat, which may make this rotation not general.\nFor example, engaged by others in the party, different gcd time, etc.", - "ConfigWindow_Actions_Description": "To customize when Rotation Solver uses specific actions automatically, click on an action's icon in the left list. Below, you may set the conditions for when that specific action is used. Each action can have a different set of conditions to override the default rotation behavior.", + "ConfigWindow_Actions_Description": "Rotation Solver が特定のアクションを自動的に使用するタイミングをカスタマイズするには、左側のリストを展開し、アクションのアイコンをクリックします。クリックした後、右側で特定のアクションが使用される場合の条件を設定できます。 Each action can have a different set of conditions to override the default rotation behavior.", "ConfigWindow_Actions_ForcedConditionSet": "Forced Condition", "ConfigWindow_Actions_ForcedConditionSet_Description": "Conditions for forced automatic use of action.", "ConfigWindow_Actions_DisabledConditionSet": "Disabled Condition", @@ -446,7 +447,7 @@ "ConfigWindow_Rotations_Loaded": "Loaded", "ConfigWindow_Rotations_GitHub": "GitHub", "ConfigWindow_Rotations_Libraries": "Libraries", - "ConfigWindow_Rotations_AutoLoadCustomRotations": "Auto load rotations", + "ConfigWindow_Rotations_AutoLoadCustomRotations": "ローテーションの自動読み込み", "ConfigWindow_Rotations_UserName": "User Name", "ConfigWindow_Rotations_Repository": "Repository", "ConfigWindow_Rotations_FileName": "File Name", @@ -495,16 +496,16 @@ "ConfigWindow_Actions_MoveDown": "Move Down", "ConfigWindow_NotInJob": "This option is unavailable while using your current job\n \nRoles or jobs needed:\n{0}", "ConfigWindow_Searching": "Search...", - "ConfigWindow_UI_HideWarning": "Hide warning when entering High-end Duty", + "ConfigWindow_UI_HideWarning": "Hide all warnings", "ConfigWindow_Auto_BeneficialAreaStrategy": "Beneficial AoE strategy", - "ConfigWindow_About_OpenConfigFolder": "Open Config Folder", + "ConfigWindow_About_OpenConfigFolder": "設定フォルダを開く", "ConfigWindow_Basic_AnimationLockTime": "The Animation lock time from individual actions. Here is 0.6s for example.", "ConfigWindow_Basic_Ping": "The ping time.\nIn RS, it means the time from sending the action request to receiving the using success message from the server.", "ConfigWindow_Basic_IdealClickingTime": "The ideal click time.", "ConfigWindow_Basic_RealClickingTime": "The real click time.", "ConfigWindow_Basic_ClickingDuration": "The clicking duration, RS will try to click at this moment.", "ConfigWindow_Basic_WeaponDelay": "This is the clipping time.\nGCD is over. However, RS forgets to click the next action.", - "ConfigWindow_About_ClickingCount": "Rotation Solver helped you by clicking actions {0:N0} times.", + "ConfigWindow_About_ClickingCount": "Rotation Solverは、アクションにおいて {0:N0} 回あなたを助けました。", "ConfigWindow_Auto_AutoHealTimeToKill": "Stop healing when time to kill is lower then...", "ConfigWindow_UI_ShowHostiles": "Show the hostile target icon", "ConfigWindow_UI_HostileIconHeight": "Hostile Icon height from position", @@ -531,6 +532,6 @@ "ConfigWindow_About_Clicking100k": "Well, you must be a lazy player!", "ConfigWindow_About_Clicking500k": "You're tiring RS out, give it a break!", "ConfigWindow_About_ThanksToSupporters": "Many thanks to the sponsors.", - "ConfigWindow_Rotations_Download": "Download Rotations", + "ConfigWindow_Rotations_Download": "ローテーションをダウンロード", "ConfigWindow_Rotations_Links": "Links of the rotations online" } \ No newline at end of file diff --git a/RotationSolver/Localization/zh.json b/RotationSolver/Localization/zh.json index 2752b69a6..f231b891d 100644 --- a/RotationSolver/Localization/zh.json +++ b/RotationSolver/Localization/zh.json @@ -414,6 +414,7 @@ }, "HighEndWarning": "当在{0} 时, 请单独绑定减伤/护盾的冷却时间, 以防RS在关键时刻失效!", "TextToTalkWarning": "您没有安装 TextToTalk,请安装它让RS为您说些什么!", + "AvariceWarning": "It seems that you didn't installed Avarice. If you want to get the positional indicator from Rotation Solver, please install it.", "ClickingMistakeMessage": "哎呀!RS点击了错误的操作 ({0}) !", "ConfigWindow_About_Punchline": "分析PvE战斗信息的每一帧并找到最佳技能。", "ConfigWindow_About_Description": "这意味着在战斗中几乎所有可用的信息都集中在一个帧中,包括团队中所有玩家的状态、敌对目标的状态、技能冷却时间、角色的MP和HP、角色的位置、敌对目标的施法状态、连击、战斗持续时间、玩家等级等。\n\n然后,它会在热栏上突出显示最佳技能,或者帮助您点击它。", @@ -495,7 +496,7 @@ "ConfigWindow_Actions_MoveDown": "下移", "ConfigWindow_NotInJob": "此选项对你当前职业不可用\n \n角色或职业需要:\n{0}", "ConfigWindow_Searching": "Search...", - "ConfigWindow_UI_HideWarning": "Hide warning when entering High-end Duty", + "ConfigWindow_UI_HideWarning": "Hide all warnings", "ConfigWindow_Auto_BeneficialAreaStrategy": "Beneficial AoE strategy", "ConfigWindow_About_OpenConfigFolder": "打开配置文件夹", "ConfigWindow_Basic_AnimationLockTime": "单个技能的动画锁时间。例如,这里为 0.6s 。", diff --git a/RotationSolver/RotationSolver.csproj b/RotationSolver/RotationSolver.csproj index a154fe3fc..ec8ed7075 100644 --- a/RotationSolver/RotationSolver.csproj +++ b/RotationSolver/RotationSolver.csproj @@ -13,7 +13,6 @@ - diff --git a/RotationSolver/RotationSolverPlugin.cs b/RotationSolver/RotationSolverPlugin.cs index d94ae6c74..79cd2fb4d 100644 --- a/RotationSolver/RotationSolverPlugin.cs +++ b/RotationSolver/RotationSolverPlugin.cs @@ -27,7 +27,7 @@ public sealed class RotationSolverPlugin : IDalamudPlugin, IDisposable static CooldownWindow _cooldownWindow; static readonly List _dis = new(); - public string Name => "Rotation Solver"; + public static string Name => "Rotation Solver"; public static DalamudLinkPayload OpenLinkPayload { get; private set; } public static DalamudLinkPayload HideWarningLinkPayload { get; private set; } @@ -89,7 +89,7 @@ public RotationSolverPlugin(DalamudPluginInterface pluginInterface) { if (id == 1) { - Service.Config.SetValue(PluginConfigBool.HideWarning, true); + Service.Config.SetBoolRaw(PluginConfigBool.HideWarning, true); Svc.Chat.Print("Warning has been hidden."); } }); @@ -109,7 +109,7 @@ internal static void ChangeUITranslation() RSCommands.Enable(); } - public void Dispose() + public async void Dispose() { RSCommands.Disable(); Watcher.Disable(); @@ -125,7 +125,7 @@ public void Dispose() MajorUpdater.Dispose(); PainterManager.Dispose(); - OtherConfiguration.Save(); + await OtherConfiguration.Save(); ECommonsMain.Dispose(); @@ -147,7 +147,7 @@ internal static void OpenConfigWindow() internal static void UpdateDisplayWindow() { var isValid = validDelay.Delay(MajorUpdater.IsValid - && RotationUpdater.RightNowRotation != null + && DataCenter.RightNowRotation != null && !Svc.Condition[ConditionFlag.OccupiedInCutSceneEvent] && !Svc.Condition[ConditionFlag.Occupied38] //Treasure hunt. && !Svc.Condition[ConditionFlag.WaitingForDuty] diff --git a/RotationSolver/UI/ConditionDrawer.cs b/RotationSolver/UI/ConditionDrawer.cs new file mode 100644 index 000000000..9c4297a71 --- /dev/null +++ b/RotationSolver/UI/ConditionDrawer.cs @@ -0,0 +1,846 @@ +using Dalamud.Game.ClientState.Keys; +using Dalamud.Interface.Utility; +using Dalamud.Utility; +using ECommons.ImGuiMethods; +using Lumina.Excel.GeneratedSheets; +using RotationSolver.Basic.Configuration.Conditions; +using RotationSolver.Localization; +using RotationSolver.Updaters; +using Action = System.Action; + +namespace RotationSolver.UI; + +internal static class ConditionDrawer +{ + internal static void DrawMain(this ConditionSet conditionSet, ICustomRotation rotation) + { + if (conditionSet == null) return; + + DrawCondition(conditionSet.IsTrue(rotation)); + ImGui.SameLine(); + conditionSet.Draw(rotation); + } + + internal static void DrawCondition(bool? tag) + { + float size = IconSize * (1 + 8 / 82); + + if (!tag.HasValue) + { + if (IconSet.GetTexture("ui/uld/image2.tex", out var texture, true) || IconSet.GetTexture(0u, out texture)) + { + ImGui.Image(texture.ImGuiHandle, Vector2.One * size); + } + } + else + { + if (IconSet.GetTexture("ui/uld/readycheck_hr1.tex", out var texture, true)) + { + ImGui.Image(texture.ImGuiHandle, Vector2.One * size, + new Vector2(tag.Value ? 0 : 0.5f, 0), + new Vector2(tag.Value ? 0.5f : 1, 1)); + } + } + } + + public static void CheckMemberInfo(ICustomRotation rotation, ref string name, ref T value) where T : MemberInfo + { + if (!string.IsNullOrEmpty(name) && (value == null || value.Name != name)) + { + var memberName = name; + if (typeof(T).IsAssignableFrom(typeof(PropertyInfo))) + { + value = (T)rotation.GetType().GetAllMethods(RuntimeReflectionExtensions.GetRuntimeProperties).FirstOrDefault(m => m.Name == memberName); + } + else if (typeof(T).IsAssignableFrom(typeof(MethodInfo))) + { + value = (T)rotation.GetType().GetAllMethods(RuntimeReflectionExtensions.GetRuntimeMethods).FirstOrDefault(m => m.Name == memberName); + } + } + } + + private static IEnumerable GetAllMethods(this Type type, Func> getFunc) + { + if (type == null || getFunc == null) return Array.Empty(); + + var methods = getFunc(type); + return methods.Union(type.BaseType.GetAllMethods(getFunc)); + } + + public static void DrawByteEnum(string name, ref T value, Func function) where T : struct, Enum + { + var values = Enum.GetValues(); + var index = Array.IndexOf(values, value); + var names = values.Select(function).ToArray(); + + if (ImGuiHelper.SelectableCombo(name, names, ref index)) + { + value = values[index]; + } + } + + public static bool DrawDragFloat(string name, ref float value) + { + ImGui.SameLine(); + ImGui.SetNextItemWidth(50); + return ImGui.DragFloat(name, ref value); + } + + public static bool DrawDragInt(string name, ref int value) + { + ImGui.SameLine(); + ImGui.SetNextItemWidth(50); + return ImGui.DragInt(name, ref value); + } + + public static bool DrawCheckBox(string name, ref int value, string desc = "") + { + ImGui.SameLine(); + + var @bool = value != 0; + + var result = false; + if (ImGui.Checkbox(name, ref @bool)) + { + value = @bool ? 1 : 0; + result = true; + } + + ImguiTooltips.HoveredTooltip(desc); + + return result; + } + + internal static void SearchItemsReflection(string popId, string name, ref string searchTxt, T[] actions, Action selectAction) where T : MemberInfo + { + if (ImGuiHelper.SelectableButton(name + "##" + popId)) + { + if (!ImGui.IsPopupOpen(popId)) ImGui.OpenPopup(popId); + } + + if (ImGui.BeginPopup(popId)) + { + var searchingKey = searchTxt; + + var members = actions.Select(m => (m, m.GetMemberName())) + .OrderByDescending(s => RotationConfigWindow.Similarity(s.Item2, searchingKey)); + + ImGui.SetNextItemWidth(Math.Max(50 * ImGuiHelpers.GlobalScale, members.Max(i => ImGuiHelpers.GetButtonSize(i.Item2).X))); + ImGui.InputTextWithHint("##Searching the member", LocalizationManager.RightLang.ConfigWindow_Actions_MemberName, ref searchTxt, 128); + + ImGui.Spacing(); + + foreach (var member in members) + { + if (ImGui.Selectable(member.Item2)) + { + selectAction?.Invoke(member.m); + ImGui.CloseCurrentPopup(); + } + } + + ImGui.EndPopup(); + } + } + + public static float IconSizeRaw => ImGuiHelpers.GetButtonSize("H").Y; + public static float IconSize => IconSizeRaw * ImGuiHelpers.GlobalScale; + private const int count = 8; + public static void ActionSelectorPopUp(string popUpId, CollapsingHeaderGroup group, ICustomRotation rotation, Action action, Action others = null) + { + if (group != null && ImGui.BeginPopup(popUpId)) + { + others?.Invoke(); + + group.ClearCollapsingHeader(); + + foreach (var pair in RotationUpdater.GroupActions(rotation.AllBaseActions)) + { + group.AddCollapsingHeader(() => pair.Key, () => + { + var index = 0; + foreach (var item in pair.OrderBy(t => t.ID)) + { + if (!item.GetTexture(out var icon)) continue; + + if (index++ % count != 0) + { + ImGui.SameLine(); + } + + ImGui.BeginGroup(); + var cursor = ImGui.GetCursorPos(); + if (ImGuiHelper.NoPaddingNoColorImageButton(icon.ImGuiHandle, Vector2.One * IconSize, group.GetHashCode().ToString())) + { + action?.Invoke(item); + ImGui.CloseCurrentPopup(); + } + ImGuiHelper.DrawActionOverlay(cursor, IconSize, 1); + ImGui.EndGroup(); + var name = item.Name; + if (!string.IsNullOrEmpty(name)) ImguiTooltips.HoveredTooltip(name); + } + }); + } + group.Draw(); + ImGui.EndPopup(); + } + } + + #region Draw + public static void Draw(this ICondition condition, ICustomRotation rotation) + { + condition.CheckBefore(rotation); + + condition.DrawBefore(); + + if (condition is DelayCondition delay) delay.DrawDelay(); + + ImGui.SameLine(); + + condition.DrawAfter(rotation); + } + + private static void DrawDelay(this DelayCondition condition) + { + const float MIN = 0, MAX = 60; + + ImGui.SetNextItemWidth(80 * ImGuiHelpers.GlobalScale); + if (ImGui.DragFloatRange2($"##Random Delay {condition.GetHashCode()}", ref condition.DelayMin, ref condition.DelayMax, 0.1f, MIN, MAX)) + { + condition.DelayMin = Math.Max(Math.Min(condition.DelayMin, condition.DelayMax), MIN); + condition.DelayMax = Math.Min(Math.Max(condition.DelayMin, condition.DelayMax), MAX); + } + ImguiTooltips.HoveredTooltip(LocalizationManager.RightLang.ActionSequencer_Delay_Description); + } + + private static void DrawBefore(this ICondition condition) + { + if (condition is ConditionSet) + { + ImGui.BeginGroup(); + } + } + + private static void DrawAfter(this ICondition condition, ICustomRotation rotation) + { + switch (condition) + { + case TraitCondition traitCondition: + traitCondition.DrawAfter(rotation); + break; + + case ActionCondition actionCondition: + actionCondition.DrawAfter(rotation); + break; + + case ConditionSet conditionSet: + conditionSet.DrawAfter(rotation); + break; + + case RotationCondition rotationCondition: + rotationCondition.DrawAfter(rotation); + break; + + case TargetCondition targetCondition: + targetCondition.DrawAfter(rotation); + break; + } + } + + private static void DrawAfter(this TraitCondition traitCondition, ICustomRotation rotation) + { + var name = traitCondition._trait?.Name ?? string.Empty; + var popUpKey = "Trait Condition Pop Up" + traitCondition.GetHashCode().ToString(); + + if (ImGui.BeginPopup(popUpKey)) + { + var index = 0; + foreach (var trait in rotation.AllTraits) + { + if (!trait.GetTexture(out var traitIcon)) continue; + + if (index++ % count != 0) + { + ImGui.SameLine(); + } + + ImGui.BeginGroup(); + var cursor = ImGui.GetCursorPos(); + if (ImGuiHelper.NoPaddingNoColorImageButton(traitIcon.ImGuiHandle, Vector2.One * IconSize, trait.GetHashCode().ToString())) + { + traitCondition.TraitID = trait.ID; + ImGui.CloseCurrentPopup(); + } + ImGuiHelper.DrawActionOverlay(cursor, IconSize, -1); + ImGui.EndGroup(); + + var tooltip = trait.Name; + if (!string.IsNullOrEmpty(tooltip)) ImguiTooltips.HoveredTooltip(tooltip); + + } + ImGui.EndPopup(); + } + + if (traitCondition._trait?.GetTexture(out var icon) ?? false || IconSet.GetTexture(4, out icon)) + { + var cursor = ImGui.GetCursorPos(); + if (ImGuiHelper.NoPaddingNoColorImageButton(icon.ImGuiHandle, Vector2.One * IconSize, traitCondition.GetHashCode().ToString())) + { + if (!ImGui.IsPopupOpen(popUpKey)) ImGui.OpenPopup(popUpKey); + } + ImGuiHelper.DrawActionOverlay(cursor, IconSize, -1); + ImguiTooltips.HoveredTooltip(name); + } + + ImGui.SameLine(); + var i = 0; + ImGuiHelper.SelectableCombo($"##Category{traitCondition.GetHashCode()}", new string[] + { + LocalizationManager.RightLang.ActionConditionType_EnoughLevel + }, ref i); + ImGui.SameLine(); + + var condition = traitCondition.Condition ? 1 : 0; + if (ImGuiHelper.SelectableCombo($"##Comparation{traitCondition.GetHashCode()}", new string[] + { + LocalizationManager.RightLang.ActionSequencer_Is, + LocalizationManager.RightLang.ActionSequencer_Isnot, + }, ref condition)) + { + traitCondition.Condition = condition > 0; + } + + } + + private static readonly CollapsingHeaderGroup _actionsList = new() + { + HeaderSize = 12, + }; + static string searchTxt = string.Empty; + + private static void DrawAfter(this ActionCondition actionCondition, ICustomRotation rotation) + { + var name = actionCondition._action?.Name ?? string.Empty; + var popUpKey = "Action Condition Pop Up" + actionCondition.GetHashCode().ToString(); + + ActionSelectorPopUp(popUpKey, _actionsList, rotation, item => actionCondition.ID = (ActionID)item.ID); + + if (actionCondition._action?.GetTexture(out var icon) ?? false || IconSet.GetTexture(4, out icon)) + { + var cursor = ImGui.GetCursorPos(); + if (ImGuiHelper.NoPaddingNoColorImageButton(icon.ImGuiHandle, Vector2.One * IconSize, actionCondition.GetHashCode().ToString())) + { + if (!ImGui.IsPopupOpen(popUpKey)) ImGui.OpenPopup(popUpKey); + } + ImGuiHelper.DrawActionOverlay(cursor, IconSize, 1); + ImguiTooltips.HoveredTooltip(name); + } + + ImGui.SameLine(); + + DrawByteEnum($"##Category{actionCondition.GetHashCode()}", ref actionCondition.ActionConditionType, EnumTranslations.ToName); + + var condition = actionCondition.Condition ? 1 : 0; + var combos = Array.Empty(); + switch (actionCondition.ActionConditionType) + { + case ActionConditionType.ElapsedGCD: + case ActionConditionType.RemainGCD: + case ActionConditionType.Elapsed: + case ActionConditionType.Remain: + case ActionConditionType.CurrentCharges: + case ActionConditionType.MaxCharges: + combos = new string[] { ">", "<=" }; + break; + + case ActionConditionType.CanUse: + combos = new string[] + { + LocalizationManager.RightLang.ActionSequencer_Can, + LocalizationManager.RightLang.ActionSequencer_Cannot, + }; + break; + + case ActionConditionType.EnoughLevel: + case ActionConditionType.IsCoolDown: + combos = new string[] + { + LocalizationManager.RightLang.ActionSequencer_Is, + LocalizationManager.RightLang.ActionSequencer_Isnot, + }; + break; + } + ImGui.SameLine(); + + if (ImGuiHelper.SelectableCombo($"##Comparation{actionCondition.GetHashCode()}", combos, ref condition)) + { + actionCondition.Condition = condition > 0; + } + + + switch (actionCondition.ActionConditionType) + { + case ActionConditionType.Elapsed: + case ActionConditionType.Remain: + DrawDragFloat($"s##Seconds{actionCondition.GetHashCode()}", ref actionCondition.Time); + break; + + case ActionConditionType.ElapsedGCD: + case ActionConditionType.RemainGCD: + if (DrawDragInt($"GCD##GCD{actionCondition.GetHashCode()}", ref actionCondition.Param1)) + { + actionCondition.Param1 = Math.Max(0, actionCondition.Param1); + } + if (DrawDragInt($"{LocalizationManager.RightLang.ActionSequencer_TimeOffset}##Ability{actionCondition.GetHashCode()}", ref actionCondition.Param2)) + { + actionCondition.Param2 = Math.Max(0, actionCondition.Param2); + } + break; + + case ActionConditionType.CanUse: + var popUpId = "Can Use Id" + actionCondition.GetHashCode().ToString(); + var option = (CanUseOption)actionCondition.Param1; + + if (ImGui.Selectable($"{option}##CanUse{actionCondition.GetHashCode()}")) + { + if (!ImGui.IsPopupOpen(popUpId)) ImGui.OpenPopup(popUpId); + } + + if (ImGui.BeginPopup(popUpId)) + { + var showedValues = Enum.GetValues().Where(i => i.GetAttribute() == null); + + foreach (var value in showedValues) + { + var b = option.HasFlag(value); + if (ImGui.Checkbox(value.ToString(), ref b)) + { + option ^= value; + actionCondition.Param1 = (int)option; + } + } + + ImGui.EndPopup(); + } + + if (DrawDragInt($"{LocalizationManager.RightLang.ActionSequencer_AOECount}##AOECount{actionCondition.GetHashCode()}", ref actionCondition.Param2)) + { + actionCondition.Param2 = Math.Max(0, actionCondition.Param2); + } + break; + + case ActionConditionType.CurrentCharges: + case ActionConditionType.MaxCharges: + if (DrawDragInt($"{LocalizationManager.RightLang.ActionSequencer_Charges}##Charges{actionCondition.GetHashCode()}", ref actionCondition.Param1)) + { + actionCondition.Param1 = Math.Max(0, actionCondition.Param1); + } + break; + } + + } + + private static void DrawAfter(this ConditionSet conditionSet, ICustomRotation rotation) + { + AddButton(); + + ImGui.SameLine(); + + DrawByteEnum($"##Rule{conditionSet.GetHashCode()}", ref conditionSet.Type, t => t switch + { + LogicalType.And => "&&", + LogicalType.Or => " | | ", + LogicalType.NotAnd => "! &&", + LogicalType.NotOr => "! | | ", + _ => string.Empty, + }); + + ImGui.Spacing(); + + for (int i = 0; i < conditionSet.Conditions.Count; i++) + { + ICondition condition = conditionSet.Conditions[i]; + + void Delete() + { + conditionSet.Conditions.RemoveAt(i); + }; + + void Up() + { + conditionSet.Conditions.RemoveAt(i); + conditionSet.Conditions.Insert(Math.Max(0, i - 1), condition); + }; + void Down() + { + conditionSet.Conditions.RemoveAt(i); + conditionSet.Conditions.Insert(Math.Min(conditionSet.Conditions.Count, i + 1), condition); + } + + var key = $"Condition Pop Up: {condition.GetHashCode()}"; + + ImGuiHelper.DrawHotKeysPopup(key, string.Empty, + (LocalizationManager.RightLang.ConfigWindow_List_Remove, Delete, new string[] { "Delete" }), + (LocalizationManager.RightLang.ConfigWindow_Actions_MoveUp, Up, new string[] { "↑" }), + (LocalizationManager.RightLang.ConfigWindow_Actions_MoveDown, Down, new string[] { "↓" })); + + DrawCondition(condition.IsTrue(rotation)); + + ImGuiHelper.ExecuteHotKeysPopup(key, string.Empty, string.Empty, true, + (Delete, new VirtualKey[] { VirtualKey.DELETE }), + (Up, new VirtualKey[] { VirtualKey.UP }), + (Down, new VirtualKey[] { VirtualKey.DOWN })); + + ImGui.SameLine(); + + condition.Draw(rotation); + } + + ImGui.EndGroup(); + + void AddButton() + { + if (ImGuiEx.IconButton(FontAwesomeIcon.Plus, "AddButton" + conditionSet.GetHashCode().ToString())) + { + ImGui.OpenPopup("Popup" + conditionSet.GetHashCode().ToString()); + } + + if (ImGui.BeginPopup("Popup" + conditionSet.GetHashCode().ToString())) + { + AddOneCondition(LocalizationManager.RightLang.ActionSequencer_ConditionSet); + AddOneCondition(LocalizationManager.RightLang.ActionSequencer_ActionCondition); + AddOneCondition(LocalizationManager.RightLang.ActionSequencer_TraitCondition); + AddOneCondition(LocalizationManager.RightLang.ActionSequencer_TargetCondition); + AddOneCondition(LocalizationManager.RightLang.ActionSequencer_RotationCondition); + + ImGui.EndPopup(); + } + + void AddOneCondition(string name) where T : ICondition + { + if (ImGui.Selectable(name)) + { + conditionSet.Conditions.Add(Activator.CreateInstance()); + ImGui.CloseCurrentPopup(); + } + } + } + } + + private static void DrawAfter(this RotationCondition rotationCondition, ICustomRotation rotation) + { + DrawByteEnum($"##Category{rotationCondition.GetHashCode()}", ref rotationCondition.ComboConditionType, EnumTranslations.ToName); + + switch (rotationCondition.ComboConditionType) + { + case ComboConditionType.Bool: + ImGui.SameLine(); + SearchItemsReflection($"##Comparation{rotationCondition.GetHashCode()}", rotationCondition._prop?.GetMemberName(), ref searchTxt, rotation.AllBools, i => + { + rotationCondition._prop = i; + rotationCondition.PropertyName = i.Name; + }); + ImGui.SameLine(); + + ImGuiHelper.SelectableCombo($"##IsOrNot{rotationCondition.GetHashCode()}", new string[] + { + LocalizationManager.RightLang.ActionSequencer_Is, + LocalizationManager.RightLang.ActionSequencer_Isnot, + }, ref rotationCondition.Condition); + + break; + + case ComboConditionType.Integer: + ImGui.SameLine(); + SearchItemsReflection($"##ByteChoice{rotationCondition.GetHashCode()}", rotationCondition._prop?.GetMemberName(), ref searchTxt, rotation.AllBytesOrInt, i => + { + rotationCondition._prop = i; + rotationCondition.PropertyName = i.Name; + }); + + ImGui.SameLine(); + + ImGuiHelper.SelectableCombo($"##Comparation{rotationCondition.GetHashCode()}", new string[] { ">", "<", "=" }, ref rotationCondition.Condition); + + ImGui.SameLine(); + ImGui.SetNextItemWidth(50); + + ImGui.DragInt($"##Value{rotationCondition.GetHashCode()}", ref rotationCondition.Param1); + + break; + case ComboConditionType.Float: + ImGui.SameLine(); + SearchItemsReflection($"##FloatChoice{rotationCondition.GetHashCode()}", rotationCondition._prop?.GetMemberName(), ref searchTxt, rotation.AllFloats, i => + { + rotationCondition._prop = i; + rotationCondition.PropertyName = i.Name; + }); + + ImGui.SameLine(); + ImGuiHelper.SelectableCombo($"##Comparation{rotationCondition.GetHashCode()}", new string[] { ">", "<", "=" }, ref rotationCondition.Condition); + + ImGui.SameLine(); + ImGui.SetNextItemWidth(50); + + ImGui.DragFloat($"##Value{rotationCondition.GetHashCode()}", ref rotationCondition.Param2); + + break; + + case ComboConditionType.Last: + ImGui.SameLine(); + + var names = new string[] + { + nameof(CustomRotation.IsLastGCD), + nameof(CustomRotation.IsLastAction), + nameof(CustomRotation.IsLastAbility), + }; + var index = Math.Max(0, Array.IndexOf(names, rotationCondition.MethodName)); + if (ImGuiHelper.SelectableCombo($"##Last{rotationCondition.GetHashCode()}", names, ref index)) + { + rotationCondition.MethodName = names[index]; + } + + ImGui.SameLine(); + + ImGuiHelper.SelectableCombo($"##IsNot{rotationCondition.GetHashCode()}", new string[] + { + LocalizationManager.RightLang.ActionSequencer_Is, + LocalizationManager.RightLang.ActionSequencer_Isnot, + }, ref rotationCondition.Condition); + + ImGui.SameLine(); + + var name = rotationCondition._action?.Name ?? string.Empty; + + var popUpKey = "Rotation Condition Pop Up" + rotationCondition.GetHashCode().ToString(); + + ActionSelectorPopUp(popUpKey, _actionsList, rotation, item => rotationCondition.ID = (ActionID)item.ID); + + if (rotationCondition._action?.GetTexture(out var icon) ?? false || IconSet.GetTexture(4, out icon)) + { + var cursor = ImGui.GetCursorPos(); + if (ImGuiHelper.NoPaddingNoColorImageButton(icon.ImGuiHandle, Vector2.One * IconSize, rotationCondition.GetHashCode().ToString())) + { + if (!ImGui.IsPopupOpen(popUpKey)) ImGui.OpenPopup(popUpKey); + } + ImGuiHelper.DrawActionOverlay(cursor, IconSize, 1); + } + + ImGui.SameLine(); + ImGuiHelper.SelectableCombo($"##Adjust{rotationCondition.GetHashCode()}", new string[] + { + LocalizationManager.RightLang.ActionSequencer_Original, + LocalizationManager.RightLang.ActionSequencer_Adjusted, + }, ref rotationCondition.Param1); + break; + } + } + + private static Status[] _allStatus = null; + private static Status[] AllStatus + { + get + { + _allStatus ??= Enum.GetValues().Select(id => Service.GetSheet().GetRow((uint)id)).ToArray(); + return _allStatus; + } + } + private static void DrawAfter(this TargetCondition targetCondition, ICustomRotation rotation) + { + DelayCondition.CheckBaseAction(rotation, targetCondition.ID, ref targetCondition._action); + + if (targetCondition.StatusId != StatusID.None && + (targetCondition.Status == null || targetCondition.Status.RowId != (uint)targetCondition.StatusId)) + { + targetCondition.Status = AllStatus.FirstOrDefault(a => a.RowId == (uint)targetCondition.StatusId); + } + + var popUpKey = "Target Condition Pop Up" + targetCondition.GetHashCode().ToString(); + + ActionSelectorPopUp(popUpKey, _actionsList, rotation, item => targetCondition.ID = (ActionID)item.ID, () => + { + if (ImGui.Selectable(LocalizationManager.RightLang.ActionSequencer_Target)) + { + targetCondition._action = null; + targetCondition.ID = ActionID.None; + targetCondition.IsTarget = true; + } + + if (ImGui.Selectable(LocalizationManager.RightLang.ActionSequencer_Player)) + { + targetCondition._action = null; + targetCondition.ID = ActionID.None; + targetCondition.IsTarget = false; + } + }); + + if (targetCondition._action != null ? targetCondition._action.GetTexture(out var icon) || IconSet.GetTexture(4, out icon) + : IconSet.GetTexture(targetCondition.IsTarget ? 16u : 18u, out icon)) + { + var cursor = ImGui.GetCursorPos(); + if (ImGuiHelper.NoPaddingNoColorImageButton(icon.ImGuiHandle, Vector2.One * IconSize, targetCondition.GetHashCode().ToString())) + { + if (!ImGui.IsPopupOpen(popUpKey)) ImGui.OpenPopup(popUpKey); + } + ImGuiHelper.DrawActionOverlay(cursor, IconSize, 1); + + var description = targetCondition._action != null ? string.Format(LocalizationManager.RightLang.ActionSequencer_ActionTarget, targetCondition._action.Name) + : targetCondition.IsTarget + ? LocalizationManager.RightLang.ActionSequencer_Target + : LocalizationManager.RightLang.ActionSequencer_Player; + ImguiTooltips.HoveredTooltip(description); + } + + ImGui.SameLine(); + DrawByteEnum($"##Category{targetCondition.GetHashCode()}", ref targetCondition.TargetConditionType, EnumTranslations.ToName); + + var condition = targetCondition.Condition ? 1 : 0; + var combos = Array.Empty(); + switch (targetCondition.TargetConditionType) + { + case TargetConditionType.HasStatus: + combos = new string[] + { + LocalizationManager.RightLang.ActionSequencer_Has, + LocalizationManager.RightLang.ActionSequencer_HasNot, + }; + break; + case TargetConditionType.IsDying: + case TargetConditionType.IsBoss: + case TargetConditionType.InCombat: + case TargetConditionType.CastingAction: + combos = new string[] + { + LocalizationManager.RightLang.ActionSequencer_Is, + LocalizationManager.RightLang.ActionSequencer_Isnot, + }; + break; + + case TargetConditionType.CastingActionTimeUntil: + case TargetConditionType.Distance: + case TargetConditionType.StatusEnd: + case TargetConditionType.TimeToKill: + case TargetConditionType.HP: + case TargetConditionType.MP: + combos = new string[] { ">", "<=" }; + break; + } + + ImGui.SameLine(); + + if (ImGuiHelper.SelectableCombo($"##Comparation{targetCondition.GetHashCode()}", combos, ref condition)) + { + targetCondition.Condition = condition > 0; + } + + var popupId = "Status Finding Popup" + targetCondition.GetHashCode().ToString(); + + RotationConfigWindow.StatusPopUp(popupId, AllStatus, ref searchTxt, status => + { + targetCondition.Status = status; + targetCondition.StatusId = (StatusID)targetCondition.Status.RowId; + }, size: IconSizeRaw); + + void DrawStatusIcon() + { + if (IconSet.GetTexture(targetCondition.Status?.Icon ?? 16220, out var icon) + || IconSet.GetTexture(16220, out icon)) + { + if (ImGuiHelper.NoPaddingNoColorImageButton(icon.ImGuiHandle, new Vector2(IconSize * 3 / 4, IconSize) * ImGuiHelpers.GlobalScale, targetCondition.GetHashCode().ToString())) + { + if (!ImGui.IsPopupOpen(popupId)) ImGui.OpenPopup(popupId); + } + ImguiTooltips.HoveredTooltip(targetCondition.Status?.Name ?? string.Empty); + } + } + + switch (targetCondition.TargetConditionType) + { + case TargetConditionType.HasStatus: + ImGui.SameLine(); + DrawStatusIcon(); + + ImGui.SameLine(); + + var check = targetCondition.FromSelf ? 1 : 0; + if (ImGuiHelper.SelectableCombo($"From Self {targetCondition.GetHashCode()}", new string[] + { + LocalizationManager.RightLang.ActionSequencer_StatusAll, + LocalizationManager.RightLang.ActionSequencer_StatusSelf, + }, ref check)) + { + targetCondition.FromSelf = check != 0; + } + break; + + case TargetConditionType.StatusEnd: + ImGui.SameLine(); + DrawStatusIcon(); + + ImGui.SameLine(); + + check = targetCondition.FromSelf ? 1 : 0; + if (ImGuiHelper.SelectableCombo($"From Self {targetCondition.GetHashCode()}", new string[] + { + LocalizationManager.RightLang.ActionSequencer_StatusAll, + LocalizationManager.RightLang.ActionSequencer_StatusSelf, + }, ref check)) + { + targetCondition.FromSelf = check != 0; + } + + DrawDragFloat($"s##Seconds{targetCondition.GetHashCode()}", ref targetCondition.DistanceOrTime); + break; + + + case TargetConditionType.StatusEndGCD: + ImGui.SameLine(); + DrawStatusIcon(); + + ImGui.SameLine(); + + check = targetCondition.FromSelf ? 1 : 0; + if (ImGuiHelper.SelectableCombo($"From Self {targetCondition.GetHashCode()}", new string[] + { + LocalizationManager.RightLang.ActionSequencer_StatusAll, + LocalizationManager.RightLang.ActionSequencer_StatusSelf, + }, ref check)) + { + targetCondition.FromSelf = check != 0; + } + + DrawDragInt($"GCD##GCD{targetCondition.GetHashCode()}", ref targetCondition.GCD); + DrawDragFloat($"{LocalizationManager.RightLang.ActionSequencer_TimeOffset}##Ability{targetCondition.GetHashCode()}", ref targetCondition.DistanceOrTime); + break; + + case TargetConditionType.Distance: + if (DrawDragFloat($"yalm##yalm{targetCondition.GetHashCode()}", ref targetCondition.DistanceOrTime)) + { + targetCondition.DistanceOrTime = Math.Max(0, targetCondition.DistanceOrTime); + } + break; + + case TargetConditionType.CastingAction: + ImGui.SameLine(); + ImGuiHelper.SetNextWidthWithName(targetCondition.CastingActionName); + ImGui.InputText($"Ability name##CastingActionName{targetCondition.GetHashCode()}", ref targetCondition.CastingActionName, 128); + break; + + case TargetConditionType.CastingActionTimeUntil: + ImGui.SameLine(); + ImGui.SetNextItemWidth(Math.Max(150 * ImGuiHelpers.GlobalScale, ImGui.CalcTextSize(targetCondition.DistanceOrTime.ToString()).X)); + ImGui.DragFloat($"s##CastingActionTimeUntil{targetCondition.GetHashCode()}", ref targetCondition.DistanceOrTime, .1f); + break; + + case TargetConditionType.MP: + case TargetConditionType.HP: + ImGui.SameLine(); + ImGui.SetNextItemWidth(Math.Max(150 * ImGuiHelpers.GlobalScale, ImGui.CalcTextSize(targetCondition.GCD.ToString()).X)); + ImGui.DragInt($"##HPorMP{targetCondition.GetHashCode()}", ref targetCondition.GCD, .1f); + break; + } + } + #endregion +} diff --git a/RotationSolver/UI/ControlWindow.cs b/RotationSolver/UI/ControlWindow.cs index fea61541a..34886263d 100644 --- a/RotationSolver/UI/ControlWindow.cs +++ b/RotationSolver/UI/ControlWindow.cs @@ -64,7 +64,7 @@ public override unsafe void Draw() LocalizationManager.RightLang.ConfigWindow_Control_IsInfoWindowMove, }, ref value)) { - Service.Config.SetValue(PluginConfigBool.IsControlWindowLock, value == 0); + Service.Config.SetBoolRaw(PluginConfigBool.IsControlWindowLock, value == 0); } ImGui.EndGroup(); @@ -82,8 +82,8 @@ public override unsafe void Draw() if (!isAoe) ImGui.PushStyleColor( ImGuiCol.Text, color); if (ImGuiHelper.SelectableButton("AOE")) { - Service.Config.SetValue(PluginConfigBool.UseAOEAction, !isAoe); - Service.Config.SetValue(PluginConfigBool.UseAOEWhenManual, !isAoe); + Service.Config.SetBoolRaw(PluginConfigBool.UseAOEAction, !isAoe); + Service.Config.SetBoolRaw(PluginConfigBool.UseAOEWhenManual, !isAoe); } if(!isAoe) ImGui.PopStyleColor(); @@ -93,7 +93,7 @@ public override unsafe void Draw() if (!isBurst) ImGui.PushStyleColor(ImGuiCol.Text, color); if (ImGuiHelper.SelectableButton("Burst")) { - Service.Config.SetValue(PluginConfigBool.AutoBurst, !isBurst); + Service.Config.SetBoolRaw(PluginConfigBool.AutoBurst, !isBurst); } if (!isBurst) ImGui.PopStyleColor(); ImGui.SameLine(); @@ -112,7 +112,7 @@ public override unsafe void Draw() private static void DrawSpecials() { - var rotation = RotationUpdater.RightNowRotation; + var rotation = DataCenter.RightNowRotation; DrawCommandAction(rotation?.ActionHealAreaGCD, rotation?.ActionHealAreaAbility, SpecialCommandType.HealArea, ImGuiColors.HealerGreen); diff --git a/RotationSolver/UI/CooldownWindow.cs b/RotationSolver/UI/CooldownWindow.cs index c5b8f1b84..131423eb1 100644 --- a/RotationSolver/UI/CooldownWindow.cs +++ b/RotationSolver/UI/CooldownWindow.cs @@ -16,7 +16,7 @@ public CooldownWindow() public override void Draw() { - if (RotationUpdater.RightNowRotation != null) + if (DataCenter.RightNowRotation != null) { var width = Service.Config.GetValue(PluginConfigFloat.CooldownWindowIconSize); var count = Math.Max(1, (int)MathF.Floor(ImGui.GetColumnWidth() / (width * (1 + 6 / 82) + ImGui.GetStyle().ItemSpacing.X))); diff --git a/RotationSolver/UI/ImGuiHelper.cs b/RotationSolver/UI/ImGuiHelper.cs index 63996a9cf..23f39664c 100644 --- a/RotationSolver/UI/ImGuiHelper.cs +++ b/RotationSolver/UI/ImGuiHelper.cs @@ -4,7 +4,6 @@ using Dalamud.Interface.Utility.Raii; using ECommons.DalamudServices; using ECommons.ImGuiMethods; -using ImGuiScene; using RotationSolver.Basic.Configuration; using RotationSolver.Commands; using RotationSolver.Localization; @@ -14,7 +13,6 @@ namespace RotationSolver.UI; internal static class ImGuiHelper { - internal static void SetNextWidthWithName(string name) { ImGui.SetNextItemWidth(Math.Max(80 * ImGuiHelpers.GlobalScale, ImGui.CalcTextSize(name).X + 30 * ImGuiHelpers.GlobalScale)); @@ -233,7 +231,7 @@ internal static void DrawActionOverlay(Vector2 cursor, float width, float percen { ImGui.SetCursorPos(cursor - new Vector2(pixPerUnit * 3, pixPerUnit * 4)); - var step = new Vector2(88f / cover.Width, 96f / cover.Height); + //var step = new Vector2(88f / cover.Width, 96f / cover.Height); var start = new Vector2((96f * 0 + 4f) / cover.Width, (96f * 2) / cover.Height); //Out Size is 88, 96 diff --git a/RotationSolver/UI/RotationConfigWindow.cs b/RotationSolver/UI/RotationConfigWindow.cs index 323c61ae1..4f87c1cb4 100644 --- a/RotationSolver/UI/RotationConfigWindow.cs +++ b/RotationSolver/UI/RotationConfigWindow.cs @@ -21,6 +21,7 @@ using RotationSolver.UI.SearchableConfigs; using RotationSolver.UI.SearchableSettings; using RotationSolver.Updaters; +using System.Collections.Generic; using System.Diagnostics; using GAction = Lumina.Excel.GeneratedSheets.Action; @@ -28,7 +29,7 @@ namespace RotationSolver.UI; public partial class RotationConfigWindow : Window { - private static float _scale => ImGuiHelpers.GlobalScale; + private static float Scale => ImGuiHelpers.GlobalScale; private static Job Job => DataCenter.Job; private RotationConfigWindowTab _activeTab; @@ -82,7 +83,7 @@ public override void Draw() using var table = ImRaii.Table("Rotation Config Table", 2, ImGuiTableFlags.Resizable); if (table) { - ImGui.TableSetupColumn("Rotation Config Side Bar", ImGuiTableColumnFlags.WidthFixed, 100 * _scale); + ImGui.TableSetupColumn("Rotation Config Side Bar", ImGuiTableColumnFlags.WidthFixed, 100 * Scale); ImGui.TableNextColumn(); try @@ -113,6 +114,70 @@ public override void Draw() } } + private void DrawConditionSet() + { + var set = DataCenter.RightSet; + + const string popUpId = "Right Set Popup"; + if (ImGui.Selectable(set.Name, false, ImGuiSelectableFlags.None, new Vector2(0, 20))) + { + ImGui.OpenPopup(popUpId); + } + ImguiTooltips.HoveredTooltip(LocalizationManager.RightLang.ConfigWindow_ConditionSetDesc); + + using (var popup = ImRaii.Popup(popUpId)) + { + if (popup.Success) + { + var combos = DataCenter.ConditionSets; + for (int i = 0; i < combos.Length; i++) + { + void DeleteFile() + { + ActionSequencerUpdater.Delete(combos[i].Name); + } + + if (combos[i].Name == set.Name) + { + ImGuiHelper.SetNextWidthWithName(set.Name); + ImGui.InputText("##MajorConditionSet", ref set.Name, 100); + } + else + { + var key = "Condition Set At " + i.ToString(); + ImGuiHelper.DrawHotKeysPopup(key, string.Empty, (LocalizationManager.RightLang.ConfigWindow_List_Remove, DeleteFile, new string[] { "Delete" })); + + + if (ImGui.Selectable(combos[i].Name)) + { + Service.Config.SetValue(PluginConfigInt.ActionSequencerIndex, i); + } + + ImGuiHelper.ExecuteHotKeysPopup(key, string.Empty, string.Empty, false, + (DeleteFile, new Dalamud.Game.ClientState.Keys.VirtualKey[] { Dalamud.Game.ClientState.Keys.VirtualKey.DELETE })); + } + } + + ImGui.PushFont(UiBuilder.IconFont); + + ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.HealerGreen); + if (ImGui.Selectable(FontAwesomeIcon.Plus.ToIconString())) + { + ActionSequencerUpdater.AddNew(); + } + ImGui.PopStyleColor(); + + if (ImGui.Selectable(FontAwesomeIcon.FileDownload.ToIconString())) + { + ActionSequencerUpdater.LoadFiles(); + } + + ImGui.PopFont(); + ImguiTooltips.HoveredTooltip(LocalizationManager.RightLang.ActionSequencer_Load); + } + } + } + private void DrawSideBar() { using var child = ImRaii.Child("Rotation Solver Side bar", -Vector2.One, false, ImGuiWindowFlags.NoScrollbar); @@ -126,10 +191,15 @@ private void DrawSideBar() ImGui.Separator(); ImGui.Spacing(); - var iconSize = Math.Max(_scale * MIN_COLUMN_WIDTH, Math.Min(wholeWidth, _scale * JOB_ICON_WIDTH)) * 0.6f; + var iconSize = Math.Max(Scale * MIN_COLUMN_WIDTH, Math.Min(wholeWidth, Scale * JOB_ICON_WIDTH)) * 0.6f; - if (wholeWidth > JOB_ICON_WIDTH * _scale) + if (wholeWidth > JOB_ICON_WIDTH * Scale) { + DrawConditionSet(); + + ImGui.Separator(); + ImGui.Spacing(); + ImGui.SetNextItemWidth(wholeWidth); SearchingBox(); @@ -144,7 +214,7 @@ private void DrawSideBar() using var popup = ImRaii.Popup("Searching Popup"); if (popup) { - ImGui.SetNextItemWidth(200 * _scale); + ImGui.SetNextItemWidth(200 * Scale); SearchingBox(); if (ImGui.IsKeyDown(ImGuiKey.Enter)) { @@ -160,7 +230,7 @@ private void DrawSideBar() ImGuiHelper.DrawActionOverlay(cursor, iconSize, -1); ImguiTooltips.HoveredTooltip("Search"); - }, Math.Max(_scale * MIN_COLUMN_WIDTH, wholeWidth), iconSize); + }, Math.Max(Scale * MIN_COLUMN_WIDTH, wholeWidth), iconSize); } } @@ -168,7 +238,7 @@ private void DrawSideBar() { if (item.GetAttribute() != null) continue; - if(IconSet.GetTexture(item.GetAttribute()?.Icon ?? 0, out var icon) && wholeWidth <= JOB_ICON_WIDTH * _scale) + if(IconSet.GetTexture(item.GetAttribute()?.Icon ?? 0, out var icon) && wholeWidth <= JOB_ICON_WIDTH * Scale) { ImGuiHelper.DrawItemMiddle(() => { @@ -179,7 +249,7 @@ private void DrawSideBar() _searchResults = Array.Empty(); } ImGuiHelper.DrawActionOverlay(cursor, iconSize, _activeTab == item ? 1 : 0); - }, Math.Max(_scale * MIN_COLUMN_WIDTH, wholeWidth), iconSize); + }, Math.Max(Scale * MIN_COLUMN_WIDTH, wholeWidth), iconSize); var desc = item.ToString(); var addition = item.ToDescription(); @@ -202,13 +272,13 @@ private void DrawSideBar() } } - if (wholeWidth <= 60 * _scale + if (wholeWidth <= 60 * Scale ? IconSet.GetTexture("https://storage.ko-fi.com/cdn/brandasset/kofi_s_logo_nolabel.png", out var texture) : IconSet.GetTexture("https://storage.ko-fi.com/cdn/brandasset/kofi_bg_tag_dark.png", out texture)) { - var width = Math.Min(150 * _scale, Math.Max(_scale * MIN_COLUMN_WIDTH, Math.Min(wholeWidth, texture.Width))); + var width = Math.Min(150 * Scale, Math.Max(Scale * MIN_COLUMN_WIDTH, Math.Min(wholeWidth, texture.Width))); var size = new Vector2(width, width * texture.Height / texture.Width); - size *= MathF.Max(_scale * MIN_COLUMN_WIDTH / size.Y, 1); + size *= MathF.Max(Scale * MIN_COLUMN_WIDTH / size.Y, 1); var result = false; ImGuiHelper.DrawItemMiddle(() => { @@ -225,36 +295,54 @@ private void DrawSideBar() } private const int FRAME_COUNT = 180; - private static SortedList _textureWrapList = new SortedList(FRAME_COUNT); + private static readonly List _loadingList = new(FRAME_COUNT); + private static readonly Dictionary _logosWrap = new(FRAME_COUNT + 1); private static bool GetLocalImage(string name, out IDalamudTextureWrap texture) { - var url = $"RotationSolver.Logos.{name}.png"; - if (_textureWrapList.TryGetValue(name, out texture)) return texture != null; + var dir = $"{Svc.PluginInterface.ConfigDirectory.FullName}\\Images"; + + if(!Directory.Exists(dir)) Directory.CreateDirectory(dir); - using var stream = typeof(RotationConfigWindow).Assembly.GetManifestResourceStream(url); - if (stream == null) + var file = dir + $"\\{name}.png"; + + if (File.Exists(file)) { - Svc.Log.Warning($"Failed to load the pic: {url} when getting the stream from assembly."); - _textureWrapList[url] = null; - return false; + if (!_logosWrap.ContainsKey(file)) + { + _logosWrap[name] = Svc.PluginInterface.UiBuilder.LoadImage(file); + } } - - using var memory = new MemoryStream(); - stream.CopyTo(memory); - texture = Svc.PluginInterface.UiBuilder.LoadImage(memory.ToArray()); - if(texture == null) + else if (!_loadingList.Contains(name)) { - Svc.Log.Warning($"Failed to load the pic: {url} when convert bytes to image."); - _textureWrapList[url] = null; - return false; + _loadingList.Add(name); + + Task.Run(async () => + { + if (!File.Exists(file)) + { + var url = $"https://raw.githubusercontent.com/{Service.USERNAME}/{Service.REPO}/main/Images/{name}.png"; + + using var client = new HttpClient(); + var stream = await client.GetStreamAsync(url); + + using var fs = new FileStream(file, FileMode.CreateNew); + + await stream.CopyToAsync(fs); + } + + + _loadingList.Remove(name); + }); } - _textureWrapList[url] = texture; - return true; + + return _logosWrap.TryGetValue(name, out texture); } + + private void DrawHeader(float wholeWidth) { - var size = MathF.Max(MathF.Min(wholeWidth, _scale * 128), _scale * MIN_COLUMN_WIDTH); + var size = MathF.Max(MathF.Min(wholeWidth, Scale * 128), Scale * MIN_COLUMN_WIDTH); if (IconSet.GetTexture((uint)0, out var overlay)) { @@ -271,9 +359,8 @@ private void DrawHeader(float wholeWidth) var frame = Environment.TickCount / 34 % FRAME_COUNT; if (frame <= 0) frame += FRAME_COUNT; - if (Service.Config.GetValue(PluginConfigBool.DrawIconAnimation) - ? GetLocalImage(frame.ToString("D4"), out var logo) - : IconSet.GetTexture($"https://raw.githubusercontent.com/{Service.USERNAME}/{Service.REPO}/main/Images/Logo.png", out logo)) + if ( GetLocalImage(Service.Config.GetValue(PluginConfigBool.DrawIconAnimation) + ? frame.ToString("D4") : "Logo", out var logo)) { ImGui.SetCursorPos(cursor); ImGui.Image(logo.ImGuiHandle, Vector2.One * size); @@ -283,12 +370,12 @@ private void DrawHeader(float wholeWidth) ImGui.Spacing(); } - var rotation = RotationUpdater.RightNowRotation; + var rotation = DataCenter.RightNowRotation; if (rotation != null) { var rotations = RotationUpdater.CustomRotations.FirstOrDefault(i => i.ClassJobIds.Contains((Job)(Player.Object?.ClassJob.Id ?? 0)))?.Rotations ?? Array.Empty(); - var iconSize = Math.Max(_scale * MIN_COLUMN_WIDTH, Math.Min(wholeWidth, _scale * JOB_ICON_WIDTH)); + var iconSize = Math.Max(Scale * MIN_COLUMN_WIDTH, Math.Min(wholeWidth, Scale * JOB_ICON_WIDTH)); var comboSize = ImGui.CalcTextSize(rotation.RotationName).X; const string slash = " - "; @@ -306,7 +393,7 @@ private void DrawHeader(float wholeWidth) DrawRotationIcon(rotation, iconSize); }, wholeWidth, iconSize); - if (_scale * JOB_ICON_WIDTH < wholeWidth) + if (Scale * JOB_ICON_WIDTH < wholeWidth) { DrawRotationCombo(comboSize, rotations, rotation, gameVersion); } @@ -393,7 +480,7 @@ private static void DrawRotationCombo(float comboSize, ICustomRotation[] rotatio private void DrawBody() { - ImGui.SetCursorPos(ImGui.GetCursorPos() + Vector2.One * 8 * _scale); + ImGui.SetCursorPos(ImGui.GetCursorPos() + Vector2.One * 8 * Scale); using var child = ImRaii.Child("Rotation Solver Body", -Vector2.One); if (child) { @@ -466,7 +553,7 @@ private void DrawBody() #region About - private static readonly SortedList CountStringPair = new SortedList() + private static readonly SortedList CountStringPair = new() { { 100_000, LocalizationManager.RightLang.ConfigWindow_About_Clicking100k }, { 500_000, LocalizationManager.RightLang.ConfigWindow_About_Clicking500k }, @@ -579,7 +666,7 @@ private static void DrawAboutCompatibility() ImGui.Spacing(); - var iconSize = 40 * _scale; + var iconSize = 40 * Scale; using var table = ImRaii.Table("Incompatible plugin", 4, ImGuiTableFlags.BordersInner | ImGuiTableFlags.Resizable @@ -649,17 +736,15 @@ private static void DrawAboutSupporters() ImGui.TextWrapped(LocalizationManager.RightLang.ConfigWindow_About_ThanksToSupporters); var width = ImGui.GetWindowWidth(); - using (var font = ImRaii.PushFont(ImGuiHelper.GetFont(12))) - { - using var color = ImRaii.PushColor(ImGuiCol.Text, ImGui.ColorConvertFloat4ToU32(ImGuiColors.DalamudYellow)); + using var font = ImRaii.PushFont(ImGuiHelper.GetFont(12)); + using var color = ImRaii.PushColor(ImGuiCol.Text, ImGui.ColorConvertFloat4ToU32(ImGuiColors.DalamudYellow)); - foreach (var name in DownloadHelper.Supporters) + foreach (var name in DownloadHelper.Supporters) + { + ImGuiHelper.DrawItemMiddle(() => { - ImGuiHelper.DrawItemMiddle(() => - { - ImGui.TextWrapped(name); - }, width, ImGui.CalcTextSize(name).X); - } + ImGui.TextWrapped(name); + }, width, ImGui.CalcTextSize(name).X); } } @@ -703,7 +788,7 @@ private static void DrawAboutLinks() #region Rotation private static void DrawRotation() { - var rotation = RotationUpdater.RightNowRotation; + var rotation = DataCenter.RightNowRotation; if (rotation == null) return; var desc = rotation.Description; @@ -728,7 +813,7 @@ private static void DrawRotation() if (!string.IsNullOrEmpty(info.DonateLink)) { - if (IconSet.GetTexture("https://storage.ko-fi.com/cdn/brandasset/kofi_button_red.png", out var icon) && ImGuiHelper.TextureButton(icon, wholeWidth, 250 * _scale, "Ko-fi link")) + if (IconSet.GetTexture("https://storage.ko-fi.com/cdn/brandasset/kofi_button_red.png", out var icon) && ImGuiHelper.TextureButton(icon, wholeWidth, 250 * Scale, "Ko-fi link")) { Util.OpenLink(info.DonateLink); } @@ -837,7 +922,7 @@ private static bool DrawRating(float value1, int value2, float max) private static void DrawRotationRating() { - var rotation = RotationUpdater.RightNowRotation; + var rotation = DataCenter.RightNowRotation; if (rotation == null) return; ImGui.TextWrapped(LocalizationManager.RightLang.ConfigWindow_Rotation_Rating_Description); @@ -855,7 +940,7 @@ private static void DrawRotationRating() private const float DESC_SIZE = 24; private static void DrawRotationDescription() { - var rotation = RotationUpdater.RightNowRotation; + var rotation = DataCenter.RightNowRotation; if (rotation == null) return; var wholeWidth = ImGui.GetWindowWidth(); @@ -890,7 +975,7 @@ private static void DrawRotationDescription() ImGui.TableNextRow(); ImGui.TableNextColumn(); - if (IconSet.GetTexture(attr.IconID, out var image)) ImGui.Image(image.ImGuiHandle, Vector2.One * DESC_SIZE * _scale); + if (IconSet.GetTexture(attr.IconID, out var image)) ImGui.Image(image.ImGuiHandle, Vector2.One * DESC_SIZE * Scale); ImGui.SameLine(); var isOnCommand = attr.IsOnCommand; @@ -906,7 +991,7 @@ private static void DrawRotationDescription() } bool notStart = false; - var size = DESC_SIZE * _scale; + var size = DESC_SIZE * Scale; var y = ImGui.GetCursorPosY() + size * 4 / 82; foreach (var item in allActions) { @@ -961,14 +1046,14 @@ internal static void DrawLinkDescription(LinkDescription link, float wholeWidth, private static string GetRotationStatusHead() { - var rotation = RotationUpdater.RightNowRotation; + var rotation = DataCenter.RightNowRotation; if (rotation == null || !rotation.ShowStatus) return string.Empty; return LocalizationManager.RightLang.ConfigWindow_Rotation_Status; } private static void DrawRotationStatus() { - RotationUpdater.RightNowRotation?.DisplayStatus(); + DataCenter.RightNowRotation?.DisplayStatus(); } private static string ToCommandStr(OtherCommandType type, string str, string extra = "") @@ -979,7 +1064,7 @@ private static string ToCommandStr(OtherCommandType type, string str, string ext } private static void DrawRotationConfiguration() { - var rotation = RotationUpdater.RightNowRotation; + var rotation = DataCenter.RightNowRotation; if (rotation == null) return; var enable = rotation.IsEnabled; @@ -1005,7 +1090,7 @@ private static void DrawRotationConfiguration() if (config is RotationConfigCombo c) { var val = set.GetCombo(c.Name); - ImGui.SetNextItemWidth(ImGui.CalcTextSize(c.Items[val]).X + 50 * _scale); + ImGui.SetNextItemWidth(ImGui.CalcTextSize(c.Items[val]).X + 50 * Scale); var openCombo = ImGui.BeginCombo(name, c.Items[val]); ImGuiHelper.ReactPopup(key, command, Reset); if (openCombo) @@ -1033,7 +1118,7 @@ private static void DrawRotationConfiguration() else if (config is RotationConfigFloat f) { float val = set.GetFloat(config.Name); - ImGui.SetNextItemWidth(_scale * Searchable.DRAG_WIDTH); + ImGui.SetNextItemWidth(Scale * Searchable.DRAG_WIDTH); if (ImGui.DragFloat(name, ref val, f.Speed, f.Min, f.Max)) { set.SetValue(config.Name, val.ToString()); @@ -1055,7 +1140,7 @@ private static void DrawRotationConfiguration() else if (config is RotationConfigInt i) { int val = set.GetInt(config.Name); - ImGui.SetNextItemWidth(_scale * Searchable.DRAG_WIDTH); + ImGui.SetNextItemWidth(Scale * Searchable.DRAG_WIDTH); if (ImGui.DragInt(name, ref val, i.Speed, i.Min, i.Max)) { set.SetValue(config.Name, val.ToString()); @@ -1072,7 +1157,7 @@ private static void DrawRotationConfiguration() private static void DrawRotationInformation() { - var rotation = RotationUpdater.RightNowRotation; + var rotation = DataCenter.RightNowRotation; if (rotation == null) return; var youtubeLink = rotation.GetType().GetCustomAttribute()?.ID; @@ -1081,7 +1166,7 @@ private static void DrawRotationInformation() if (!string.IsNullOrEmpty(youtubeLink)) { ImGui.NewLine(); - if (IconSet.GetTexture("https://www.gstatic.com/youtube/img/branding/youtubelogo/svg/youtubelogo.svg", out var icon) && ImGuiHelper.TextureButton(icon, wholeWidth, 250 * _scale, "Youtube Link")) + if (IconSet.GetTexture("https://www.gstatic.com/youtube/img/branding/youtubelogo/svg/youtubelogo.svg", out var icon) && ImGuiHelper.TextureButton(icon, wholeWidth, 250 * Scale, "Youtube Link")) { Util.OpenLink("https://www.youtube.com/watch?v=" + youtubeLink); } @@ -1146,9 +1231,9 @@ private static unsafe void DrawActions() { _actionsList.ClearCollapsingHeader(); - if (RotationUpdater.RightNowRotation != null) + if (DataCenter.RightNowRotation != null) { - var size = 30 * _scale; + var size = 30 * Scale; var count = Math.Max(1, (int)MathF.Floor(ImGui.GetColumnWidth() / (size * 1.1f + ImGui.GetStyle().ItemSpacing.X))); foreach (var pair in RotationUpdater.AllGroupedActions) { @@ -1252,7 +1337,6 @@ private static unsafe void DrawActions() } } - if (_activeAction != null) { var enable = _activeAction.IsEnabled; @@ -1277,7 +1361,7 @@ private static unsafe void DrawActions() ImGui.Separator(); var ttk = action.TimeToKill; - ImGui.SetNextItemWidth(_scale * 150); + ImGui.SetNextItemWidth(Scale * 150); if (ImGui.DragFloat($"{LocalizationManager.RightLang.ConfigWindow_Actions_TTK}##{action}", ref ttk, 0.1f, 0, 120)) { @@ -1287,7 +1371,7 @@ private static unsafe void DrawActions() if (!action.IsSingleTarget) { var aoeCount = (int)action.AOECount; - ImGui.SetNextItemWidth(_scale * 150); + ImGui.SetNextItemWidth(Scale * 150); if (ImGui.DragInt($"{LocalizationManager.RightLang.ConfigWindow_Actions_AOECount}##{action}", ref aoeCount, 0.05f, 1, 10)) { @@ -1298,7 +1382,7 @@ private static unsafe void DrawActions() if (action.IsHeal) { var ratio = action.AutoHealRatio; - ImGui.SetNextItemWidth(_scale * 150); + ImGui.SetNextItemWidth(Scale * 150); if (ImGui.DragFloat($"{LocalizationManager.RightLang.ConfigWindow_Actions_HealRatio}##{action}", ref ratio, 0.002f, 0, 1)) { @@ -1310,11 +1394,8 @@ private static unsafe void DrawActions() ImGui.Separator(); } - ActionSequencerUpdater.DrawHeader(30 * _scale); - if (_sequencerList != null) - { - _sequencerList.Draw(); - } + ImGui.TextWrapped(LocalizationManager.RightLang.ConfigWindow_Actions_ConditionDescription); + _sequencerList?.Draw(); } } @@ -1331,22 +1412,22 @@ private static unsafe void DrawActions() { ImGui.TextWrapped(LocalizationManager.RightLang.ConfigWindow_Actions_ForcedConditionSet_Description); - var rotation = RotationUpdater.RightNowRotation; - var set = ActionSequencerUpdater.RightSet; + var rotation = DataCenter.RightNowRotation; + var set = DataCenter.RightSet; if (set == null || _activeAction == null || rotation == null) return; - set.DrawCondition(_activeAction.ID, rotation); + set.GetCondition(_activeAction.ID)?.DrawMain(rotation); } }, { () => LocalizationManager.RightLang.ConfigWindow_Actions_DisabledConditionSet, () => { ImGui.TextWrapped(LocalizationManager.RightLang.ConfigWindow_Actions_DisabledConditionSet_Description); - var rotation = RotationUpdater.RightNowRotation; - var set = ActionSequencerUpdater.RightSet; + var rotation = DataCenter.RightNowRotation; + var set = DataCenter.RightSet; if (set == null || _activeAction == null || rotation == null) return; - set.DrawDisabledCondition(_activeAction.ID, rotation); + set.GetDisabledCondition(_activeAction.ID)?.DrawMain(rotation); } }, }) { @@ -1462,7 +1543,7 @@ private static void DrawRotationsLoaded() lastRole = role; if(IconSet.GetTexture(IconSet.GetJobIcon(jobs.First(), IconType.Framed), out var texture, 62574)) - ImGui.Image(texture.ImGuiHandle, Vector2.One * 30 * _scale); + ImGui.Image(texture.ImGuiHandle, Vector2.One * 30 * Scale); ImguiTooltips.HoveredTooltip(string.Join('\n', jobs)); } @@ -1473,7 +1554,7 @@ private static void DrawRotationsLoaded() if (!string.IsNullOrEmpty(info.DonateLink) && IconSet.GetTexture("https://storage.ko-fi.com/cdn/brandasset/kofi_button_red.png", out var icon) - && ImGuiHelper.NoPaddingNoColorImageButton(icon.ImGuiHandle, new Vector2(1, (float)icon.Height/ icon.Width) * MathF.Min(250, icon.Width) * _scale, info.FilePath)) + && ImGuiHelper.NoPaddingNoColorImageButton(icon.ImGuiHandle, new Vector2(1, (float)icon.Height/ icon.Width) * MathF.Min(250, icon.Width) * Scale, info.FilePath)) { Util.OpenLink(info.DonateLink); } @@ -1570,7 +1651,7 @@ private static void DrawRotationsGitHub() var changed = false; - var width = ImGui.GetWindowWidth() - ImGuiEx.CalcIconSize(FontAwesomeIcon.Ban).X - ImGui.GetStyle().ItemSpacing.X * 3 - 10 * _scale; + var width = ImGui.GetWindowWidth() - ImGuiEx.CalcIconSize(FontAwesomeIcon.Ban).X - ImGui.GetStyle().ItemSpacing.X * 3 - 10 * Scale; width /= 3; ImGui.SetNextItemWidth(width); @@ -1612,7 +1693,7 @@ private static void DrawRotationsLibraries() ImGui.Spacing(); - var width = ImGui.GetWindowWidth() - ImGuiEx.CalcIconSize(FontAwesomeIcon.Ban).X - ImGui.GetStyle().ItemSpacing.X - 10 * _scale; + var width = ImGui.GetWindowWidth() - ImGuiEx.CalcIconSize(FontAwesomeIcon.Ban).X - ImGui.GetStyle().ItemSpacing.X - 10 * Scale; int removeIndex = -1; for (int i = 0; i < Service.Config.GlobalConfig.OtherLibs.Length; i++) @@ -1732,20 +1813,20 @@ private static void DrawActionsStatuses() } static string _statusSearching = string.Empty; - private static void DrawStatusList(string name, HashSet statuses, Status[] allStatus) + private static async void DrawStatusList(string name, HashSet statuses, Status[] allStatus) { uint removeId = 0; uint notLoadId = 10100; var popupId = "Rotation Solver Popup" + name; - StatusPopUp(popupId, allStatus, ref _statusSearching, status => + StatusPopUp(popupId, allStatus, ref _statusSearching, async status => { statuses.Add(status.RowId); - OtherConfiguration.Save(); + await OtherConfiguration.Save(); }, notLoadId); - var count = Math.Max(1, (int)MathF.Floor(ImGui.GetColumnWidth() / (24 * _scale + ImGui.GetStyle().ItemSpacing.X))); + var count = Math.Max(1, (int)MathF.Floor(ImGui.GetColumnWidth() / (24 * Scale + ImGui.GetStyle().ItemSpacing.X))); var index = 0; if (IconSet.GetTexture(16220, out var text)) @@ -1754,7 +1835,7 @@ private static void DrawStatusList(string name, HashSet statuses, Status[] { ImGui.SameLine(); } - if (ImGuiHelper.NoPaddingNoColorImageButton(text.ImGuiHandle, new Vector2(24, 32) * _scale, name)) + if (ImGuiHelper.NoPaddingNoColorImageButton(text.ImGuiHandle, new Vector2(24, 32) * Scale, name)) { if (!ImGui.IsPopupOpen(popupId)) ImGui.OpenPopup(popupId); } @@ -1777,7 +1858,7 @@ private static void DrawStatusList(string name, HashSet statuses, Status[] { ImGui.SameLine(); } - ImGuiHelper.NoPaddingNoColorImageButton(texture.ImGuiHandle, new Vector2(24, 32) * _scale, "Status" + status.RowId.ToString()); + ImGuiHelper.NoPaddingNoColorImageButton(texture.ImGuiHandle, new Vector2(24, 32) * Scale, "Status" + status.RowId.ToString()); ImGuiHelper.ExecuteHotKeysPopup(key, string.Empty, $"{status.Name} ({status.RowId})", false, (Delete, new Dalamud.Game.ClientState.Keys.VirtualKey[] { Dalamud.Game.ClientState.Keys.VirtualKey.DELETE })); @@ -1787,7 +1868,7 @@ private static void DrawStatusList(string name, HashSet statuses, Status[] if (removeId != 0) { statuses.Remove(removeId); - OtherConfiguration.Save(); + await OtherConfiguration.Save(); } } @@ -1796,15 +1877,15 @@ internal static void StatusPopUp(string popupId, Status[] allStatus, ref string using var popup = ImRaii.Popup(popupId); if (popup) { - ImGui.SetNextItemWidth(200 * _scale); + ImGui.SetNextItemWidth(200 * Scale); ImGui.InputTextWithHint("##Searching the status", LocalizationManager.RightLang.ConfigWindow_List_StatusNameOrId, ref searching, 128); ImGui.Spacing(); - using var child = ImRaii.Child("Rotation Solver Add Status", new Vector2(-1, 400 * _scale)); + using var child = ImRaii.Child("Rotation Solver Add Status", new Vector2(-1, 400 * Scale)); if (child) { - var count = Math.Max(1, (int)MathF.Floor(ImGui.GetWindowWidth() / (size * 3 / 4 * _scale + ImGui.GetStyle().ItemSpacing.X))); + var count = Math.Max(1, (int)MathF.Floor(ImGui.GetWindowWidth() / (size * 3 / 4 * Scale + ImGui.GetStyle().ItemSpacing.X))); var index = 0; var searchingKey = searching; @@ -1816,7 +1897,7 @@ internal static void StatusPopUp(string popupId, Status[] allStatus, ref string { ImGui.SameLine(); } - if (ImGuiHelper.NoPaddingNoColorImageButton(texture.ImGuiHandle, new Vector2(size * 3 / 4, size) * _scale, "Adding" + status.RowId.ToString())) + if (ImGuiHelper.NoPaddingNoColorImageButton(texture.ImGuiHandle, new Vector2(size * 3 / 4, size) * Scale, "Adding" + status.RowId.ToString())) { clicked?.Invoke(status); ImGui.CloseCurrentPopup(); @@ -1868,7 +1949,7 @@ private static void DrawListActions() } private static string _actionSearching = string.Empty; - private static void DrawActionsList(string name, HashSet actions) + private static async void DrawActionsList(string name, HashSet actions) { uint removeId = 0; @@ -1877,12 +1958,12 @@ private static void DrawActionsList(string name, HashSet actions) using var popup = ImRaii.Popup(popupId); if (popup) { - ImGui.SetNextItemWidth(200 * _scale); + ImGui.SetNextItemWidth(200 * Scale); ImGui.InputTextWithHint("##Searching the action pop up", LocalizationManager.RightLang.ConfigWindow_List_ActionNameOrId, ref _actionSearching, 128); ImGui.Spacing(); - using var child = ImRaii.Child("Rotation Solver Add action", new Vector2(-1, 400 * _scale)); + using var child = ImRaii.Child("Rotation Solver Add action", new Vector2(-1, 400 * Scale)); if (child) { foreach (var action in AllActions.OrderByDescending(s =>Similarity(s.Name + " " + s.RowId.ToString(), _actionSearching))) @@ -1894,7 +1975,7 @@ private static void DrawActionsList(string name, HashSet actions) if(selected) { actions.Add(action.RowId); - OtherConfiguration.Save(); + await OtherConfiguration.Save(); ImGui.CloseCurrentPopup(); } } @@ -1928,11 +2009,10 @@ private static void DrawActionsList(string name, HashSet actions) if (removeId != 0) { actions.Remove(removeId); - OtherConfiguration.Save(); + await OtherConfiguration.Save(); } } - private static string _territorySearching = string.Empty; public static Vector3 HoveredPosition { get; private set; } = Vector3.Zero; private static void DrawListTerritories() { @@ -1960,7 +2040,7 @@ private static void DrawListTerritories() { if (getIcon) { - ImGui.Image(texture.ImGuiHandle, Vector2.One * 28 * _scale); + ImGui.Image(texture.ImGuiHandle, Vector2.One * 28 * Scale); ImGui.SameLine(); } ImGui.Text(territoryName); @@ -1988,7 +2068,7 @@ private static void DrawListTerritories() ImGui.TextWrapped(LocalizationManager.RightLang.ConfigWindow_List_NoHostileDesc); - var width = ImGui.GetColumnWidth() - ImGuiEx.CalcIconSize(FontAwesomeIcon.Ban).X - ImGui.GetStyle().ItemSpacing.X - 10 * _scale; + var width = ImGui.GetColumnWidth() - ImGuiEx.CalcIconSize(FontAwesomeIcon.Ban).X - ImGui.GetStyle().ItemSpacing.X - 10 * Scale; if(!OtherConfiguration.NoHostileNames.TryGetValue(territoryId, out var libs)) { @@ -2028,7 +2108,7 @@ private static void DrawListTerritories() ImGui.TextWrapped(LocalizationManager.RightLang.ConfigWindow_List_NoProvokeDesc); - width = ImGui.GetColumnWidth() - ImGuiEx.CalcIconSize(FontAwesomeIcon.Ban).X - ImGui.GetStyle().ItemSpacing.X - 10 * _scale; + width = ImGui.GetColumnWidth() - ImGuiEx.CalcIconSize(FontAwesomeIcon.Ban).X - ImGui.GetStyle().ItemSpacing.X - 10 * Scale; if (!OtherConfiguration.NoProvokeNames.TryGetValue(territoryId, out libs)) { @@ -2133,7 +2213,7 @@ private static void DrawDebug() private static readonly CollapsingHeaderGroup _debugHeader = new(new() { - {() => RotationUpdater.RightNowRotation != null ? "Rotation" : string.Empty, DrawDebugRotationStatus}, + {() => DataCenter.RightNowRotation != null ? "Rotation" : string.Empty, DrawDebugRotationStatus}, {() =>"Status", DrawStatus }, {() =>"Party", DrawParty }, {() =>"Target Data", DrawTargetData }, @@ -2150,7 +2230,7 @@ private static void DrawDebug() private static void DrawDebugRotationStatus() { - RotationUpdater.RightNowRotation?.DisplayStatus(); + DataCenter.RightNowRotation?.DisplayStatus(); } private static unsafe void DrawStatus() @@ -2259,7 +2339,7 @@ private static unsafe void DrawTargetData() private static void DrawNextAction() { - ImGui.Text(RotationUpdater.RightNowRotation.RotationName); + ImGui.Text(DataCenter.RightNowRotation.RotationName); ImGui.Text(DataCenter.SpecialType.ToString()); ImGui.Text("Ability Remain: " + DataCenter.AbilityRemain.ToString()); diff --git a/RotationSolver/UI/RotationConfigWindow_Config.cs b/RotationSolver/UI/RotationConfigWindow_Config.cs index 10be80577..523741ed5 100644 --- a/RotationSolver/UI/RotationConfigWindow_Config.cs +++ b/RotationSolver/UI/RotationConfigWindow_Config.cs @@ -17,6 +17,8 @@ public partial class RotationConfigWindow private static char[] _splitChar = new char[] { ' ', ',', '、', '.', '。' }; internal static float Similarity(string text, string key) { + if (string.IsNullOrEmpty(text)) return 0; + var chars = text.Split(_splitChar, StringSplitOptions.RemoveEmptyEntries); var keys = key.Split(_splitChar, StringSplitOptions.RemoveEmptyEntries); @@ -494,8 +496,48 @@ private static void DrawAuto() } }, { () => LocalizationManager.RightLang.ConfigWindow_Auto_ActionCondition, DrawAutoActionCondition }, + { () => LocalizationManager.RightLang.ConfigWindow_Auto_StateCondition, () => _autoState?.Draw() }, }); + private static readonly CollapsingHeaderGroup _autoState = new(new() + { + { () => LocalizationManager.RightLang.ConfigWindow_Auto_HealAreaConditionSet, + () => DataCenter.RightSet.HealAreaConditionSet?.DrawMain(DataCenter.RightNowRotation) }, + + { () => LocalizationManager.RightLang.ConfigWindow_Auto_HealSingleConditionSet, + () => DataCenter.RightSet.HealSingleConditionSet?.DrawMain(DataCenter.RightNowRotation) }, + + { () => LocalizationManager.RightLang.ConfigWindow_Auto_DefenseAreaConditionSet, + () => DataCenter.RightSet.DefenseAreaConditionSet?.DrawMain(DataCenter.RightNowRotation) }, + + { () => LocalizationManager.RightLang.ConfigWindow_Auto_DefenseSingleConditionSet, + () => DataCenter.RightSet.DefenseSingleConditionSet?.DrawMain(DataCenter.RightNowRotation) }, + + { () => LocalizationManager.RightLang.ConfigWindow_Auto_EsunaStanceNorthConditionSet, + () => DataCenter.RightSet.EsunaStanceNorthConditionSet?.DrawMain(DataCenter.RightNowRotation) }, + + { () => LocalizationManager.RightLang.ConfigWindow_Auto_RaiseShirkConditionSet, + () => DataCenter.RightSet.RaiseShirkConditionSet?.DrawMain(DataCenter.RightNowRotation) }, + + { () => LocalizationManager.RightLang.ConfigWindow_Auto_MoveForwardConditionSet, + () => DataCenter.RightSet.MoveForwardConditionSet?.DrawMain(DataCenter.RightNowRotation) }, + + { () => LocalizationManager.RightLang.ConfigWindow_Auto_MoveBackConditionSet, + () => DataCenter.RightSet.MoveBackConditionSet?.DrawMain(DataCenter.RightNowRotation) }, + + { () => LocalizationManager.RightLang.ConfigWindow_Auto_AntiKnockbackConditionSet, + () => DataCenter.RightSet.AntiKnockbackConditionSet?.DrawMain(DataCenter.RightNowRotation) }, + + { () => LocalizationManager.RightLang.ConfigWindow_Auto_BurstConditionSet, + () => DataCenter.RightSet.BurstConditionSet?.DrawMain(DataCenter.RightNowRotation) }, + + { () => LocalizationManager.RightLang.ConfigWindow_Auto_SpeedConditionSet, + () => DataCenter.RightSet.SpeedConditionSet?.DrawMain(DataCenter.RightNowRotation) }, + }) + { + HeaderSize = 18, + }; + private static void DrawAutoActionCondition() { ImGui.TextWrapped(LocalizationManager.RightLang.ConfigWindow_Auto_ActionCondition_Description); @@ -904,7 +946,7 @@ void Down() var names = Enum.GetNames(typeof(TargetingType)); var targingType = (int)Service.Config.GlobalConfig.TargetingTypes[i]; var text = LocalizationManager.RightLang.ConfigWindow_Param_HostileCondition; - ImGui.SetNextItemWidth(ImGui.CalcTextSize(text).X + 30 * _scale); + ImGui.SetNextItemWidth(ImGui.CalcTextSize(text).X + 30 * Scale); if (ImGui.Combo(text + "##HostileCondition" + i.ToString(), ref targingType, names, names.Length)) { Service.Config.GlobalConfig.TargetingTypes[i] = (TargetingType)targingType; diff --git a/RotationSolver/UI/SearchableConfigs/CheckBoxSearch.cs b/RotationSolver/UI/SearchableConfigs/CheckBoxSearch.cs index 3b6f603c2..704259aec 100644 --- a/RotationSolver/UI/SearchableConfigs/CheckBoxSearch.cs +++ b/RotationSolver/UI/SearchableConfigs/CheckBoxSearch.cs @@ -1,16 +1,105 @@ using Dalamud.Interface.Internal; using Dalamud.Interface.Utility; +using ECommons.DalamudServices; using ECommons.ExcelServices; -using ImGuiScene; using RotationSolver.Basic.Configuration; +using RotationSolver.Basic.Configuration.Conditions; using RotationSolver.Localization; using RotationSolver.UI.SearchableConfigs; +using RotationSolver.Updaters; namespace RotationSolver.UI.SearchableSettings; internal class CheckBoxSearchPlugin : CheckBoxSearch { - private PluginConfigBool _config; + private abstract class CheckBoxConditionAbstract : CheckBoxSearch + { + protected readonly PluginConfigBool _config; + + public override string SearchingKeys => string.Empty; + + public override string Command => string.Empty; + + public override LinkDescription[] Tooltips => null; + + public override string ID => _config.ToString() + Name; + + public CheckBoxConditionAbstract(PluginConfigBool config) : base() + { + _config = config; + AdditionalDraw = () => + { + GetCondition(DataCenter.Job)?.DrawMain(DataCenter.RightNowRotation); + ImGui.Separator(); + }; + } + + protected abstract ConditionSet GetCondition(Job job); + } + + private class CheckBoxDisable : CheckBoxConditionAbstract + { + public override string Name => LocalizationManager.RightLang.ConfigWindow_Options_ForcedDisableCondition; + + public override string Description => LocalizationManager.RightLang.ConfigWindow_Options_ForcedDisableConditionDesc; + + public CheckBoxDisable(PluginConfigBool config) : base(config) + { + } + public override void ResetToDefault(Job job) + { + Service.Config.SetDisableBoolRaw(_config, false); + } + + protected override bool GetValue(Job job) + { + return Service.Config.GetDisableBoolRaw(_config); + } + + protected override void SetValue(Job job, bool value) + { + Service.Config.SetDisableBoolRaw(_config, value); + } + + protected override ConditionSet GetCondition(Job job) + { + return DataCenter.RightSet.GetDisableCondition(_config); + } + } + + private class CheckBoxEnable : CheckBoxConditionAbstract + { + public override string Name => LocalizationManager.RightLang.ConfigWindow_Options_ForcedEnableCondition; + + public override string Description => LocalizationManager.RightLang.ConfigWindow_Options_ForcedEnableConditionDesc; + + public CheckBoxEnable(PluginConfigBool config) : base(config) + { + } + + public override void ResetToDefault(Job job) + { + Service.Config.SetEnableBoolRaw(_config, false); + } + + protected override bool GetValue(Job job) + { + return Service.Config.GetEnableBoolRaw(_config); + } + + protected override void SetValue(Job job, bool value) + { + Service.Config.SetEnableBoolRaw(_config, value); + } + + protected override ConditionSet GetCondition(Job job) + { + return DataCenter.RightSet.GetEnableCondition(_config); + } + } + + + private readonly PluginConfigBool _config; public override string ID => _config.ToString(); public override string Name => _config.ToName(); @@ -21,25 +110,30 @@ internal class CheckBoxSearchPlugin : CheckBoxSearch public override string Command => _config.ToCommand(); + private static readonly Action _emptyAction = () => { }; public CheckBoxSearchPlugin(PluginConfigBool config, params ISearchable[] children) - :base(children) + :base(new ISearchable[] + { + new CheckBoxEnable(config), new CheckBoxDisable(config), + }.Concat(children).ToArray()) { _config = config; + AdditionalDraw = _emptyAction; } protected override bool GetValue(Job job) { - return Service.Config.GetValue(_config); + return Service.Config.GetBoolRaw(_config); } protected override void SetValue(Job job, bool value) { - Service.Config.SetValue(_config, value); + Service.Config.SetBoolRaw(_config, value); } public override void ResetToDefault(Job job) { - Service.Config.SetValue(_config, Service.Config.GetDefault(_config)); + Service.Config.SetBoolRaw(_config, Service.Config.GetBoolRawDefault(_config)); } } @@ -49,6 +143,8 @@ internal abstract class CheckBoxSearch : Searchable public ActionID Action { get; init; } = ActionID.None; + public Action AdditionalDraw { get; set; } = null; + public CheckBoxSearch(params ISearchable[] children) { Children = children; @@ -80,6 +176,8 @@ protected virtual void DrawChildren(Job job) protected override void DrawMain(Job job) { var hasChild = Children != null && Children.Length > 0; + var hasAdditional = AdditionalDraw != null; + var hasSub = hasChild || hasAdditional; IDalamudTextureWrap texture = null; var hasIcon = Action != ActionID.None && IconSet.GetTexture(Action, out texture); @@ -107,9 +205,9 @@ protected override void DrawMain(Job job) if (ImGui.IsItemHovered()) ShowTooltip(job); } - else if (hasChild) + else if (hasSub) { - if (enable) + if (enable && hasChild || hasAdditional) { var x = ImGui.GetCursorPosX(); var drawBody = ImGui.TreeNode(name); @@ -119,7 +217,11 @@ protected override void DrawMain(Job job) { ImGui.SetCursorPosX(x); ImGui.BeginGroup(); - DrawChildren(job); + AdditionalDraw?.Invoke(); + if (hasChild) + { + DrawChildren(job); + } ImGui.EndGroup(); ImGui.TreePop(); } diff --git a/RotationSolver/UI/SearchableConfigs/Searchable.cs b/RotationSolver/UI/SearchableConfigs/Searchable.cs index eee7d7a36..dd8948b25 100644 --- a/RotationSolver/UI/SearchableConfigs/Searchable.cs +++ b/RotationSolver/UI/SearchableConfigs/Searchable.cs @@ -14,7 +14,7 @@ internal abstract class Searchable : ISearchable protected static float Scale => ImGuiHelpers.GlobalScale; public CheckBoxSearch Parent { get; set; } - public string SearchingKeys => Name + " " + Description; + public virtual string SearchingKeys => Name + " " + Description; public abstract string Name { get; } public abstract string Description { get; } public abstract string Command { get; } @@ -40,7 +40,7 @@ public unsafe void Draw(Job job) if (JobRoles != null) { - var role = RotationUpdater.RightNowRotation?.ClassJob?.GetJobRole(); + var role = DataCenter.RightNowRotation?.ClassJob?.GetJobRole(); if (role.HasValue) { canDraw = JobRoles.Contains(role.Value); diff --git a/RotationSolver/Updaters/ActionSequencerUpdater.cs b/RotationSolver/Updaters/ActionSequencerUpdater.cs index 4d9d2e323..86e009ee1 100644 --- a/RotationSolver/Updaters/ActionSequencerUpdater.cs +++ b/RotationSolver/Updaters/ActionSequencerUpdater.cs @@ -1,12 +1,4 @@ -using Dalamud.Interface.Colors; -using ECommons.DalamudServices; -using ECommons.ImGuiMethods; -using RotationSolver.ActionSequencer; -using RotationSolver.Basic.Configuration; -using RotationSolver.Localization; -using RotationSolver.UI; -using System.Diagnostics; -using System.Windows.Forms; +using RotationSolver.Basic.Configuration.Conditions; namespace RotationSolver.Updaters; @@ -14,38 +6,38 @@ internal class ActionSequencerUpdater { static string _actionSequencerFolder; - static IEnumerable _conditionSet; - public static MajorConditionSet RightSet => _conditionSet? - .ElementAtOrDefault(Service.Config.GetValue(PluginConfigInt.ActionSequencerIndex)); - - public static string[] ConditionSetsName => _conditionSet?.Select(s => s.Name).ToArray() ?? Array.Empty(); - public static void UpdateActionSequencerAction() { - if (_conditionSet == null) return; - var customRotation = RotationUpdater.RightNowRotation; + if (DataCenter.ConditionSets == null) return; + var customRotation = DataCenter.RightNowRotation; if (customRotation == null) return; var allActions = RotationUpdater.RightRotationActions; - var set = RightSet; + var set = DataCenter.RightSet; if (set == null) return; - DataCenter.DisabledActionSequencer = new HashSet(set.DiabledConditions.Where(pair => pair.Value.IsTrue(customRotation)) - .Select(pair => pair.Key)); + DataCenter.DisabledActionSequencer = new HashSet(set.DisableConditionDict + .Where(pair => pair.Value.IsTrue(customRotation)) + .Select(pair => pair.Key)); bool find = false; - foreach (var conditionPair in set.Conditions) + var conditions = set.ConditionDict; + if (conditions != null) { - var nextAct = allActions.FirstOrDefault(a => a.ID == conditionPair.Key); - if (nextAct == null) continue; + foreach (var conditionPair in conditions) + { + var nextAct = allActions.FirstOrDefault(a => a.ID == conditionPair.Key); + if (nextAct == null) continue; - if (!conditionPair.Value.IsTrue(customRotation)) continue; + if (!conditionPair.Value.IsTrue(customRotation)) continue; - DataCenter.ActionSequencerAction = nextAct; - find = true; - break; + DataCenter.ActionSequencerAction = nextAct; + find = true; + break; + } } + if (!find) { DataCenter.ActionSequencerAction = null; @@ -57,7 +49,7 @@ public static void Enable(string folder) _actionSequencerFolder = folder; if (!Directory.Exists(_actionSequencerFolder)) Directory.CreateDirectory(_actionSequencerFolder); - _conditionSet = MajorConditionSet.Read(_actionSequencerFolder); + LoadFiles(); } public static void SaveFiles() @@ -71,7 +63,7 @@ public static void SaveFiles() { } - foreach (var set in _conditionSet) + foreach (var set in DataCenter.ConditionSets) { set.Save(_actionSequencerFolder); } @@ -79,81 +71,20 @@ public static void SaveFiles() public static void LoadFiles() { - _conditionSet = MajorConditionSet.Read(_actionSequencerFolder); + DataCenter.ConditionSets = MajorConditionSet.Read(_actionSequencerFolder); } - private static void AddNew() + public static void AddNew() { - const string conditionName = "Unnamed"; - if (!_conditionSet.Any(c => c.Name == conditionName)) + if (!DataCenter.ConditionSets.Any(c => c.IsUnnamed)) { - _conditionSet = _conditionSet.Union(new[] { new MajorConditionSet(conditionName) }); + DataCenter.ConditionSets = DataCenter.ConditionSets.Append(new MajorConditionSet()).ToArray(); } } - private static void Delete(string name) + public static void Delete(string name) { - _conditionSet = _conditionSet.Where(c => c.Name != name); + DataCenter.ConditionSets = DataCenter.ConditionSets.Where(c => c.Name != name).ToArray(); File.Delete(_actionSequencerFolder + $"\\{name}.json"); } - - public static void DrawHeader(float width) - { - var set = RightSet; - bool hasSet = set != null; - - if (hasSet) - { - ImGuiHelper.SetNextWidthWithName(set.Name); - ImGui.InputText("##MajorConditionSet", ref set.Name, 100); - - ImGui.SameLine(); - } - - var combos = ConditionSetsName; - ImGui.SetNextItemWidth(width); - - if(ImGui.BeginCombo("##MajorConditionCombo", "")) - { - for (int i = 0; i < combos.Length; i++) - { - void DeleteFile() - { - Delete(combos[i]); - } - - var key = "Condition Set At " + i.ToString(); - - ImGuiHelper.DrawHotKeysPopup(key, string.Empty, (LocalizationManager.RightLang.ConfigWindow_List_Remove, DeleteFile, new string[] { "Delete" })); - - - if (ImGui.Selectable(combos[i])) - { - Service.Config.SetValue(PluginConfigInt.ActionSequencerIndex, i); - } - - ImGuiHelper.ExecuteHotKeysPopup(key, string.Empty, string.Empty, false, - (DeleteFile, new Dalamud.Game.ClientState.Keys.VirtualKey[] { Dalamud.Game.ClientState.Keys.VirtualKey.DELETE })); - } - - ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.HealerGreen); - ImGui.PushFont(UiBuilder.IconFont); - if (ImGui.Selectable(FontAwesomeIcon.Plus.ToIconString())) - { - AddNew(); - } - ImGui.PopFont(); - ImGui.PopStyleColor(); - ImGui.EndCombo(); - } - - ImGui.SameLine(); - if (ImGuiEx.IconButton(FontAwesomeIcon.FileDownload, "##LoadTheConditions")) - { - LoadFiles(); - } - ImguiTooltips.HoveredTooltip(LocalizationManager.RightLang.ActionSequencer_Load); - - ImGui.TextWrapped(LocalizationManager.RightLang.ConfigWindow_Actions_ConditionDescription); - } } diff --git a/RotationSolver/Updaters/ActionUpdater.cs b/RotationSolver/Updaters/ActionUpdater.cs index f0129a5c1..240a8e8ed 100644 --- a/RotationSolver/Updaters/ActionUpdater.cs +++ b/RotationSolver/Updaters/ActionUpdater.cs @@ -1,6 +1,5 @@ using Dalamud.Game.ClientState.Conditions; using Dalamud.Game.ClientState.Objects.SubKinds; -using Dalamud.Logging; using ECommons.DalamudServices; using ECommons.GameHelpers; using FFXIVClientStructs.FFXIV.Client.Game; @@ -21,7 +20,7 @@ internal static class ActionUpdater internal static IAction NextAction { get; set; } internal static IBaseAction NextGCDAction { get; set; } internal static IAction WrongAction { get; set; } - static Random _wrongRandom = new(); + static readonly Random _wrongRandom = new(); internal static void ClearNextAction() { @@ -32,7 +31,7 @@ internal static void ClearNextAction() internal static void UpdateNextAction() { PlayerCharacter localPlayer = Player.Object; - var customRotation = RotationUpdater.RightNowRotation; + var customRotation = DataCenter.RightNowRotation; try { diff --git a/RotationSolver/Updaters/RotationUpdater.cs b/RotationSolver/Updaters/RotationUpdater.cs index 578a006a6..d37e6fc20 100644 --- a/RotationSolver/Updaters/RotationUpdater.cs +++ b/RotationSolver/Updaters/RotationUpdater.cs @@ -17,7 +17,6 @@ internal static class RotationUpdater internal static SortedList AuthorHashes { get; private set; } = new SortedList(); internal static CustomRotationGroup[] CustomRotations { get; set; } = Array.Empty(); - public static ICustomRotation RightNowRotation { get; private set; } public static IAction[] RightRotationActions { get; private set; } = Array.Empty(); private static DateTime LastRunTime; @@ -383,7 +382,7 @@ private static ICustomRotation[] CreateRotationSet(ICustomRotation[] combos) } public static IEnumerable> AllGroupedActions - => GroupActions(RightNowRotation?.AllActions); + => GroupActions(DataCenter.RightNowRotation?.AllActions); public static IEnumerable> GroupActions(IEnumerable actions) => actions?.GroupBy(a => @@ -442,20 +441,20 @@ public static void UpdateRotation() if (!group.ClassJobIds.Contains(nowJob)) continue; var rotation = GetChosenRotation(group); - if (rotation != RightNowRotation) + if (rotation != DataCenter.RightNowRotation) { rotation?.OnTerritoryChanged(); } - RightNowRotation = rotation; - RightRotationActions = RightNowRotation.AllActions; - DataCenter.Job = RightNowRotation?.Jobs[0] ?? Job.ADV; + DataCenter.RightNowRotation = rotation; + RightRotationActions = DataCenter.RightNowRotation.AllActions; + DataCenter.Job = DataCenter.RightNowRotation?.Jobs[0] ?? Job.ADV; return; } CustomRotation.MoveTarget = null; - RightNowRotation = null; + DataCenter.RightNowRotation = null; RightRotationActions = Array.Empty(); - DataCenter.Job = RightNowRotation?.Jobs[0] ?? Job.ADV; + DataCenter.Job = DataCenter.RightNowRotation?.Jobs[0] ?? Job.ADV; } internal static ICustomRotation GetChosenRotation(CustomRotationGroup group) diff --git a/RotationSolver/Updaters/SocialUpdater.cs b/RotationSolver/Updaters/SocialUpdater.cs index 993d458dd..3f90f179e 100644 --- a/RotationSolver/Updaters/SocialUpdater.cs +++ b/RotationSolver/Updaters/SocialUpdater.cs @@ -96,7 +96,7 @@ static void ClientState_TerritoryChanged(ushort id) try { - RotationUpdater.RightNowRotation?.OnTerritoryChanged(); + DataCenter.RightNowRotation?.OnTerritoryChanged(); } catch(Exception ex) { @@ -147,7 +147,7 @@ internal static async void UpdateSocial() } } - private static readonly ChatEntityComparer _comparer = new ChatEntityComparer(); + private static readonly ChatEntityComparer _comparer = new (); private static async void SayHelloToUsers() { var players = DataCenter.AllianceMembers.OfType() @@ -244,12 +244,12 @@ public bool CanTarget public virtual BitmapFontIcon Icon => BitmapFontIcon.Mentor; - protected SeString Character => new SeString(new IconPayload(Icon), + protected SeString Character => new (new IconPayload(Icon), new UIForegroundPayload(31), new PlayerPayload(player.Name.TextValue, player.HomeWorld.Id), UIForegroundPayload.UIForegroundOff); - protected SeString RotationSolver => new SeString(new IconPayload(BitmapFontIcon.DPS), + protected static SeString RotationSolver => new (new IconPayload(BitmapFontIcon.DPS), RotationSolverPlugin.OpenLinkPayload, new UIForegroundPayload(31), new TextPayload("Rotation Solver"), diff --git a/XIVPainter b/XIVPainter index 23c9832e4..9fdc2b58f 160000 --- a/XIVPainter +++ b/XIVPainter @@ -1 +1 @@ -Subproject commit 23c9832e4d3b24b9fc542002fcf3744c2156b78b +Subproject commit 9fdc2b58f82302ddd0f4185bbf357a3d6e861681