Advertisement
Guest User

Wisps

a guest
Jan 17th, 2025
231
0
182 days
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.60 KB | Source Code | 0 0
  1. using ExileCore;
  2. using ExileCore.PoEMemory;
  3. using ExileCore.PoEMemory.Components;
  4. using ExileCore.PoEMemory.MemoryObjects;
  5. using ExileCore.Shared.Helpers;
  6. using SharpDX;
  7. using System.Collections.Generic;
  8. using System.Linq;
  9. using Vector3N = System.Numerics.Vector3;
  10. using Vector2N = System.Numerics.Vector2;
  11. using ExileCore.PoEMemory.Elements;
  12.  
  13. namespace WhereTheWispsAt;
  14.  
  15. public class WhereTheWispsAt : BaseSettingsPlugin<WhereTheWispsAtSettings>
  16. {
  17. public enum WispType
  18. {
  19. None,
  20. Yellow,
  21. YellowMed,
  22. YellowBig,
  23. Purple,
  24. PurpleMed,
  25. PurpleBig,
  26. Blue,
  27. BlueMed,
  28. BlueBig,
  29. Chests,
  30. LightBomb,
  31. Wells,
  32. FuelRefill,
  33. Altars,
  34. DustConverters,
  35. Dealer,
  36. Encounter
  37. }
  38.  
  39. public WispData Wisps = new([], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], []);
  40.  
  41. public WhereTheWispsAt()
  42. {
  43. Name = "Where The Wisps At";
  44. }
  45.  
  46. public override bool Initialise() => true;
  47.  
  48. public override Job Tick()
  49. {
  50. var wellsToRemove = Wisps.Wells.Where(
  51. well => well.TryGetComponent<StateMachine>(out var stateComp) &&
  52. stateComp?.States.Any(x => x.Name == "activated" && x.Value == 1) == true
  53. )
  54. .ToList();
  55.  
  56. wellsToRemove.ForEach(well => RemoveEntityFromList(well, Wisps.Wells));
  57.  
  58. var altarsToRemove = Wisps.Altars.Where(
  59. altar => altar.TryGetComponent<StateMachine>(out var stateComp) &&
  60. stateComp?.States.Any(x => x.Name == "activated" && x.Value == 1) == true
  61. )
  62. .ToList();
  63.  
  64. altarsToRemove.ForEach(altar => RemoveEntityFromList(altar, Wisps.Altars));
  65.  
  66. var dustConvertersToRemove = Wisps.DustConverters.Where(
  67. converter => converter.TryGetComponent<StateMachine>(out var stateComp) &&
  68. stateComp?.States.Any(
  69. x => x.Name == "activated" && x.Value == 1
  70. ) == true
  71. )
  72. .ToList();
  73.  
  74. dustConvertersToRemove.ForEach(altar => RemoveEntityFromList(altar, Wisps.DustConverters));
  75.  
  76. foreach (var chest in Wisps.Chests.Where(x => x.GetComponent<Chest>()?.IsOpened != false).ToList())
  77. RemoveEntityFromList(chest, Wisps.Chests);
  78.  
  79. return null;
  80. }
  81.  
  82. public override void EntityAdded(Entity entity)
  83. {
  84. var path = entity.TryGetComponent<Animated>(out var animatedComp) ? animatedComp?.BaseAnimatedObjectEntity?.Path
  85. : null;
  86.  
  87. var metadata = entity.Metadata;
  88.  
  89. switch (metadata)
  90. {
  91. case not null when metadata.StartsWith("Metadata/MiscellaneousObjects/Azmeri/AzmeriResource"):
  92. if (path != null)
  93. {
  94. if (path.Contains("_primal_sml"))
  95. {
  96. Wisps.Blue.Add(entity);
  97. }
  98. else if (path.Contains("_primal_med"))
  99. {
  100. Wisps.BlueMed.Add(entity);
  101. }
  102. else if (path.Contains("_primal_big"))
  103. {
  104. Wisps.BlueBig.Add(entity);
  105. }
  106. else if (path.Contains("_warden_sml"))
  107. {
  108. Wisps.Yellow.Add(entity);
  109. }
  110. else if (path.Contains("_warden_med"))
  111. {
  112. Wisps.YellowMed.Add(entity);
  113. }
  114. else if (path.Contains("_warden_big"))
  115. {
  116. Wisps.YellowBig.Add(entity);
  117. }
  118. else if (path.Contains("_vodoo_sml"))
  119. {
  120. Wisps.Purple.Add(entity);
  121. }
  122. else if (path.Contains("_vodoo_med"))
  123. {
  124. Wisps.PurpleMed.Add(entity);
  125. }
  126. else if (path.Contains("_vodoo_big"))
  127. {
  128. Wisps.PurpleBig.Add(entity);
  129. }
  130. }
  131.  
  132. break;
  133. case "Metadata/MiscellaneousObjects/Azmeri/AzmeriLightBomb":
  134. Wisps.LightBomb.Add(entity);
  135. break;
  136. case "Metadata/MiscellaneousObjects/Azmeri/AzmeriFuelResupply":
  137. Wisps.FuelRefill.Add(entity);
  138. break;
  139. case "Metadata/MiscellaneousObjects/Azmeri/AzmeriFlaskRefill":
  140. Wisps.Wells.Add(entity);
  141. break;
  142. case "Metadata/NPC/League/Affliction/GlyphsHarvestTree":
  143. Wisps.Encounters[entity] = "Harvest";
  144. break;
  145. case "Metadata/MiscellaneousObjects/Azmeri/AzmeriBuffEffigySmall":
  146. case "Metadata/MiscellaneousObjects/Azmeri/AzmeriBuffEffigyMedium":
  147. case "Metadata/MiscellaneousObjects/Azmeri/AzmeriBuffEffigyLarge":
  148. Wisps.Encounters[entity] = "Buff";
  149. break;
  150. case "Metadata/Monsters/LeagueAzmeri/VoodooKingBoss/VoodooKingBoss":
  151. case "Metadata/Monsters/LeagueAzmeri/VoodooKingBoss/VoodooKingBoss2":
  152. case "Metadata/Monsters/LeagueAzmeri/VoodooKingBoss/VoodooKingBoss3":
  153. case "Metadata/NPC/Ghostrider":
  154. case "Metadata/NPC/League/Affliction/GlyphsEtching01":
  155. case "Metadata/NPC/League/Affliction/GlyphsEtching02":
  156. case "Metadata/NPC/League/Affliction/GlyphsEtching03":
  157. case "Metadata/NPC/League/Affliction/GlyphsEtching04":
  158. case "Metadata/NPC/League/Affliction/GlyphsEtching05":
  159. case "Metadata/NPC/League/Affliction/GlyphsGoddessStatue":
  160. case "Metadata/NPC/League/Affliction/GlyphsGruthkulShrine":
  161. case "Metadata/NPC/League/Affliction/GlyphsKingGlyphOne":
  162. case "Metadata/NPC/League/Affliction/GlyphsKingGlyphTwo":
  163. case "Metadata/NPC/League/Affliction/GlyphsMajiProclamation01":
  164. case "Metadata/NPC/League/Affliction/GlyphsMajiProclamation02":
  165. case "Metadata/NPC/League/Affliction/GlyphsSingleStatue":
  166. case "Metadata/NPC/League/Affliction/GlyphsWarringSisters":
  167. Wisps.Encounters[entity] = metadata[(metadata.LastIndexOf('/') + 1)..];
  168. break;
  169. case "Metadata/Chests/LeagueAzmeri/OmenChest":
  170. Wisps.Encounters[entity] = "Omen Chest";
  171. break;
  172. case not null when metadata.Contains("Azmeri/SacrificeAltarObjects"):
  173. Wisps.Altars.Add(entity);
  174. break;
  175. case not null when metadata.Contains("Azmeri/AzmeriDustConverter"):
  176. Wisps.DustConverters.Add(entity);
  177. break;
  178. case not null when metadata.Contains("Azmeri/UniqueDealer"):
  179. Wisps.Dealer.Add(entity);
  180. break;
  181. case not null when metadata.StartsWith("Metadata/Chests/LeagueAzmeri/"):
  182. Wisps.Chests.Add(entity);
  183. break;
  184. }
  185. }
  186.  
  187. public override void EntityRemoved(Entity entity)
  188. {
  189. new[]
  190. {
  191. Wisps.Blue, Wisps.BlueMed, Wisps.BlueBig, Wisps.Purple, Wisps.PurpleMed, Wisps.PurpleBig, Wisps.Yellow, Wisps.YellowMed, Wisps.YellowBig, Wisps.LightBomb, Wisps.Wells, Wisps.FuelRefill
  192. }.ToList()
  193. .ForEach(list => RemoveEntityFromList(entity, list));
  194.  
  195. Wisps.Encounters.Remove(entity);
  196. }
  197.  
  198. private static void RemoveEntityFromList(Entity entity, List<Entity> list)
  199. {
  200. var entityToRemove = list.FirstOrDefault(wisp => wisp.Id == entity.Id);
  201.  
  202. if (entityToRemove != null)
  203. {
  204. list.Remove(entityToRemove);
  205. }
  206. }
  207.  
  208. public override void AreaChange(AreaInstance area) =>
  209. Wisps = new WispData([], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], []);
  210.  
  211. public override void Render()
  212. {
  213. if (!Settings.Enable.Value || !GameController.InGame)
  214. {
  215. return;
  216. }
  217.  
  218. var inGameUi = GameController.Game.IngameState.IngameUi;
  219.  
  220. if (!Settings.IgnoreFullscreenPanels && inGameUi.FullscreenPanels.Any(x => x.IsVisible))
  221. {
  222. return;
  223. }
  224.  
  225. if (!Settings.IgnoreLargePanels && inGameUi.LargePanels.Any(x => x.IsVisible))
  226. {
  227. return;
  228. }
  229.  
  230. foreach (var (list, color, size, text, type) in new[]
  231. {
  232. (Wisps.Yellow, Settings.YellowWisp, Settings.YellowSize.Value, null, WispType.Yellow),
  233. (Wisps.YellowMed, Settings.YellowWispMed, Settings.YellowSizeMed.Value, null, WispType.YellowMed),
  234. (Wisps.YellowBig, Settings.YellowWispBig, Settings.YellowSizeBig.Value, null, WispType.YellowBig),
  235. (Wisps.Purple, Settings.PurpleWisp, Settings.PurpleSize.Value, null, WispType.Purple),
  236. (Wisps.PurpleMed, Settings.PurpleWispMed, Settings.PurpleSizeMed.Value, null, WispType.PurpleMed),
  237. (Wisps.PurpleBig, Settings.PurpleWispBig, Settings.PurpleSizeBig.Value, null, WispType.PurpleBig),
  238. (Wisps.Blue, Settings.BlueWisp, Settings.BlueSize.Value, null, WispType.Blue),
  239. (Wisps.BlueMed, Settings.BlueWispMed, Settings.BlueSizeMed.Value, null, WispType.BlueMed),
  240. (Wisps.BlueBig, Settings.BlueWispBig, Settings.BlueSizeBig.Value, null, WispType.BlueBig),
  241. (Wisps.Chests, Settings.ChestColor, Settings.ChestSize.Value, null, WispType.Chests),
  242. (Wisps.LightBomb, Settings.LightBomb, 0, "Light Bomb", WispType.LightBomb),
  243. (Wisps.Wells, Settings.Wells, 0, "Well", WispType.Wells),
  244. (Wisps.FuelRefill, Settings.FuelRefill, 0, "Fuel Refill", WispType.FuelRefill),
  245. (Wisps.Altars, Settings.Altars, 0, "Altar", WispType.Altars),
  246. (Wisps.DustConverters, Settings.DustConverters, 0, "Dust Converter", WispType.DustConverters),
  247. (Wisps.Dealer, Settings.Dealer, 0, "! TRADER !", WispType.Dealer)
  248. })
  249. DrawWisps(list, color, size, text, type);
  250.  
  251. foreach (var (entity, text) in Wisps.Encounters)
  252. DrawWisps([entity], Settings.EncounterColor, 0, text, WispType.Encounter);
  253.  
  254. foreach (var chest in Wisps.Chests)
  255. if (chest.DistancePlayer < Settings.ChestScreenDisplayMaxDistance &&
  256. chest.TryGetComponent<Render>(out var render))
  257. {
  258. Graphics.DrawBoundingBoxInWorld(
  259. chest.PosNum,
  260. Settings.ChestColor.Value with
  261. {
  262. A = (byte)Settings.ChestAlpha
  263. },
  264. render.BoundsNum,
  265. render.RotationNum.X
  266. );
  267. }
  268. if (Settings.DrawRemainingFuel)
  269. {
  270. if (!GameController.IngameState.Data.IsInsideAzmeriZone)
  271. {
  272. return;
  273. }
  274. var fuelLeft = inGameUi.LeagueMechanicButtons.AzmeriElement.Data.RemainingFuelFraction;
  275. var fuelLeftText = $"{fuelLeft:P0}";
  276. var textPlacement = new Vector2(Settings.PositionX, Settings.PositionY);
  277. using (Graphics.SetTextScale(Settings.TextSize))
  278. {
  279. Graphics.DrawText(fuelLeftText, textPlacement, Settings.FuelColor);
  280. }
  281. }
  282. return;
  283.  
  284. void DrawWisps(List<Entity> entityList, Color color, int size, string text, WispType type = WispType.None)
  285. {
  286. // Just run this once, land looks flat.
  287. var groundZ = entityList.FirstOrDefault()?.GridPosNum is { } gridPosNum
  288. ? GameController.IngameState.Data.GetTerrainHeightAt(gridPosNum) : 0;
  289.  
  290. entityList = entityList.OrderBy(x => x.Id).ToList();
  291.  
  292. var screenSize = new RectangleF
  293. {
  294. X = 0,
  295. Y = 0,
  296. Width = GameController.Window.GetWindowRectangleTimeCache.Size.Width,
  297. Height = GameController.Window.GetWindowRectangleTimeCache.Size.Height
  298. };
  299.  
  300. for (var i = 0; i < entityList.Count; i++)
  301. {
  302. var specificWispTypes = new[]
  303. {
  304. WispType.Yellow, WispType.YellowMed, WispType.YellowBig, WispType.Purple, WispType.PurpleMed, WispType.PurpleBig, WispType.Blue, WispType.BlueMed, WispType.BlueBig, WispType.LightBomb, WispType.FuelRefill
  305. };
  306.  
  307. var entityCur = entityList[i];
  308.  
  309. if (Settings.DrawMap && GameController.IngameState.IngameUi.Map.LargeMap.IsVisibleLocal)
  310. {
  311. var mapPos = GameController.IngameState.Data.GetGridMapScreenPosition(
  312. entityCur.PosNum.WorldToGrid()
  313. );
  314.  
  315. if (text != null)
  316. {
  317. const int widthPadding = 3;
  318. var boxOffset = Graphics.MeasureText(text) / 2f;
  319. var textOffset = boxOffset;
  320. boxOffset.X += widthPadding;
  321. Graphics.DrawBox(mapPos - boxOffset, mapPos + boxOffset, Color.Black);
  322. Graphics.DrawText(text, mapPos - textOffset, color);
  323. }
  324. else
  325. {
  326. if (Settings.DrawMapLines && i < entityList.Count - 1 && type != WispType.Chests)
  327. {
  328. if (i < entityList.Count - 1 && specificWispTypes.Contains(type))
  329. {
  330. var entityNext = entityList[i + 1];
  331.  
  332. var mapPosTo
  333. = GameController.IngameState.Data.GetGridMapScreenPosition(
  334. entityNext.PosNum.WorldToGrid()
  335. );
  336.  
  337. if (entityNext.Id == entityCur.Id + 1 && entityCur.Distance(entityNext) < 30 &&
  338. IsEntityWithinScreen(mapPos, screenSize, 0) &&
  339. IsEntityWithinScreen(mapPosTo, screenSize, 0))
  340. {
  341. Graphics.DrawLine(mapPos, mapPosTo, Settings.MapLineSize, color);
  342. }
  343. }
  344. }
  345.  
  346. Graphics.DrawBox(
  347. new RectangleF(mapPos.X - size / 2, mapPos.Y - size / 2, size, size),
  348. color,
  349. 1f
  350. );
  351. }
  352. }
  353.  
  354. if (!Settings.DrawWispsOnGround || !specificWispTypes.Contains(type))
  355. {
  356. continue;
  357. }
  358.  
  359. var entityPos = entityCur.PosNum;
  360. var entityPosScreen = RemoteMemoryObject.pTheGame.IngameState.Camera.WorldToScreen(entityPos);
  361.  
  362. if (IsEntityWithinScreen(entityPosScreen, screenSize, 50))
  363. {
  364. Graphics.DrawBoundingBoxInWorld(
  365. entityPos with
  366. {
  367. Z = groundZ
  368. },
  369. color with
  370. {
  371. A = (byte)Settings.WispsOnGroundAlpha
  372. },
  373. new Vector3N(
  374. Settings.WispsOnGroundWidth,
  375. Settings.WispsOnGroundWidth,
  376. Settings.WispsOnGroundHeight
  377. ),
  378. 0f
  379. );
  380. }
  381. }
  382. }
  383. }
  384.  
  385. private static bool IsEntityWithinScreen(Vector2N entityPos, RectangleF screensize, float allowancePX)
  386. {
  387. // Check if the entity position is within the screen bounds with allowance
  388. var leftBound = screensize.Left - allowancePX;
  389. var rightBound = screensize.Right + allowancePX;
  390. var topBound = screensize.Top - allowancePX;
  391. var bottomBound = screensize.Bottom + allowancePX;
  392.  
  393. return entityPos.X >= leftBound && entityPos.X <= rightBound && entityPos.Y >= topBound &&
  394. entityPos.Y <= bottomBound;
  395. }
  396.  
  397. public record WispData(
  398. List<Entity> Purple,
  399. List<Entity> PurpleMed,
  400. List<Entity> PurpleBig,
  401. List<Entity> Yellow,
  402. List<Entity> YellowMed,
  403. List<Entity> YellowBig,
  404. List<Entity> Blue,
  405. List<Entity> BlueMed,
  406. List<Entity> BlueBig,
  407. List<Entity> LightBomb,
  408. List<Entity> Wells,
  409. List<Entity> FuelRefill,
  410. List<Entity> Altars,
  411. List<Entity> DustConverters,
  412. List<Entity> Dealer,
  413. List<Entity> Chests,
  414. Dictionary<Entity, string> Encounters);
  415. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement