481 lines
14 KiB
C#
481 lines
14 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using EFT;
|
|
using EFT.Counters;
|
|
using EFT.Interactive;
|
|
using EFT.InventoryLogic;
|
|
using EFT.Quests;
|
|
using EFT.UI;
|
|
using stupid.solutions.Data;
|
|
using stupid.solutions.Features;
|
|
using stupid.solutions.Features.ESP;
|
|
using stupid.solutions.stupid.solutions.Data;
|
|
using stupid.solutions.Utils;
|
|
using UnityEngine;
|
|
|
|
namespace stupid.solutions;
|
|
|
|
public class QuestESP : MonoBehaviour
|
|
{
|
|
public struct QuestItemsSearched
|
|
{
|
|
public string ID { get; set; }
|
|
}
|
|
|
|
private List<PointOfInterest> poiList = new List<PointOfInterest>();
|
|
|
|
private List<dynamic> startedQuests = new List<object>();
|
|
|
|
private bool shouldRefreshData = true;
|
|
|
|
public static List<string> QuestItemIds = new List<string>();
|
|
|
|
private List<PlaceItemTrigger> placeItemTriggers = new List<PlaceItemTrigger>();
|
|
|
|
private List<ExperienceTrigger> experienceTrigger = new List<ExperienceTrigger>();
|
|
|
|
private bool gettriggers = true;
|
|
|
|
private bool getquestitems = true;
|
|
|
|
private float _nextQuestCacheTime;
|
|
|
|
private static readonly float _cacheQuestInterval = 5f;
|
|
|
|
public Color Color { get; set; } = Color.magenta;
|
|
|
|
private void Update()
|
|
{
|
|
if (Settings.QuestESP && Time.time >= _nextQuestCacheTime)
|
|
{
|
|
if (Main.GameWorld != null && Main.LocalPlayer != null && Main.MainCamera != null)
|
|
{
|
|
try
|
|
{
|
|
poiList.Clear();
|
|
RefreshData(poiList);
|
|
shouldRefreshData = false;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ConsoleScreen.Log("Error refreshing data: " + ex.Message);
|
|
}
|
|
}
|
|
_nextQuestCacheTime = Time.time + _cacheQuestInterval;
|
|
}
|
|
if (gettriggers && Main.GameWorld != null && Main.LocalPlayer != null && Main.MainCamera != null)
|
|
{
|
|
GetTriggers();
|
|
}
|
|
if (Main.GameWorld == null)
|
|
{
|
|
gettriggers = true;
|
|
getquestitems = true;
|
|
poiList.Clear();
|
|
QuestItemIds.Clear();
|
|
placeItemTriggers.Clear();
|
|
experienceTrigger.Clear();
|
|
}
|
|
}
|
|
|
|
public void GetTriggers()
|
|
{
|
|
if (placeItemTriggers == null)
|
|
{
|
|
placeItemTriggers = new List<PlaceItemTrigger>();
|
|
}
|
|
if (experienceTrigger == null)
|
|
{
|
|
experienceTrigger = new List<ExperienceTrigger>();
|
|
}
|
|
gettriggers = false;
|
|
placeItemTriggers.Clear();
|
|
experienceTrigger.Clear();
|
|
placeItemTriggers = UnityEngine.Object.FindObjectsOfType<PlaceItemTrigger>().ToList();
|
|
experienceTrigger = UnityEngine.Object.FindObjectsOfType<ExperienceTrigger>().ToList();
|
|
ConsoleScreen.Log($"Got Triggers + {experienceTrigger.Count + placeItemTriggers.Count}");
|
|
}
|
|
|
|
public void RefreshData(List<PointOfInterest> data)
|
|
{
|
|
GameWorld gameWorld = Main.GameWorld;
|
|
if (gameWorld == null)
|
|
{
|
|
return;
|
|
}
|
|
Player localPlayer = Main.LocalPlayer;
|
|
if (localPlayer == null || Main.MainCamera == null)
|
|
{
|
|
return;
|
|
}
|
|
Profile profile = localPlayer.Profile;
|
|
if (profile == null)
|
|
{
|
|
return;
|
|
}
|
|
try
|
|
{
|
|
List<_F286> questsData = profile.QuestsData;
|
|
startedQuests.Clear();
|
|
foreach (_F286 item in questsData)
|
|
{
|
|
if (item.Template != null && item.Template.Conditions != null && profile.Stats != null && profile.Stats.Eft != null && profile.Stats.Eft.OverallCounters != null && item.Status == EQuestStatus.Started)
|
|
{
|
|
startedQuests.Add(item);
|
|
}
|
|
}
|
|
if (startedQuests.Any())
|
|
{
|
|
RefreshVisitPlaceLocations(startedQuests, profile, data);
|
|
RefreshFindItemLocations(startedQuests, gameWorld, data);
|
|
RefreshPlaceOrRepairItemLocations(startedQuests, profile, data);
|
|
if (getquestitems)
|
|
{
|
|
RefreshNonStaticQuestItems(startedQuests, gameWorld, data);
|
|
getquestitems = false;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
}
|
|
|
|
private void RefreshVisitPlaceLocations(List<dynamic> startedQuests, Profile profile, List<PointOfInterest> records)
|
|
{
|
|
try
|
|
{
|
|
List<ExperienceTrigger> source = this.experienceTrigger.ToList();
|
|
foreach (dynamic startedQuest in startedQuests)
|
|
{
|
|
dynamic val = startedQuest.Template?.Conditions[EQuestStatus.AvailableForFinish];
|
|
if (val == null)
|
|
{
|
|
continue;
|
|
}
|
|
foreach (dynamic item in val)
|
|
{
|
|
try
|
|
{
|
|
if ((startedQuest.CompletedConditions.Contains(item.id)) || !(item is ConditionCounterCreator conditionCounterCreator))
|
|
{
|
|
continue;
|
|
}
|
|
foreach (Condition condition in conditionCounterCreator.Conditions)
|
|
{
|
|
if (condition is ConditionVisitPlace conditionVisitPlace)
|
|
{
|
|
string expectedTriggerId = conditionVisitPlace.target;
|
|
ExperienceTrigger experienceTrigger = source.FirstOrDefault((ExperienceTrigger t) => t.Id == expectedTriggerId);
|
|
if (!(experienceTrigger == null) && profile.Stats.Eft.OverallCounters.GetInt(CounterTag.TriggerVisited, experienceTrigger.Id) <= 0)
|
|
{
|
|
Vector3 position = experienceTrigger.transform.position;
|
|
AddQuestRecord(records, conditionCounterCreator, startedQuest, position, Color.cyan);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ConsoleScreen.Log($"Error processing condition {(object)item?.id}: {ex.Message}");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
}
|
|
|
|
private bool IsQuestConditionAvailableForFinish(dynamic quest)
|
|
{
|
|
dynamic val = quest.Template?.Conditions[EQuestStatus.AvailableForFinish];
|
|
return val != null && !quest.CompletedConditions.Contains(val.id);
|
|
}
|
|
|
|
private void RefreshFindItemLocations(List<dynamic> startedQuests, GameWorld world, List<PointOfInterest> records)
|
|
{
|
|
try
|
|
{
|
|
_E3D7<int, LootItem> lootItems = world.LootItems;
|
|
for (int i = 0; i < lootItems.Count; i++)
|
|
{
|
|
try
|
|
{
|
|
LootItem byIndex = lootItems.GetByIndex(i);
|
|
if (!GameUtils.IsLootItemValid(byIndex))
|
|
{
|
|
continue;
|
|
}
|
|
bool flag = false;
|
|
foreach (dynamic startedQuest in startedQuests)
|
|
{
|
|
dynamic val = startedQuest.Template?.Conditions[EQuestStatus.AvailableForFinish];
|
|
if (val == null)
|
|
{
|
|
continue;
|
|
}
|
|
foreach (object item in val)
|
|
{
|
|
if (!(item is ConditionFindItem conditionFindItem))
|
|
{
|
|
continue;
|
|
}
|
|
string text = conditionFindItem.target.FirstOrDefault()?.ToString();
|
|
bool flag2 = text == null || !text.Contains(byIndex.Item.TemplateId.ToString());
|
|
if (!flag2 && !((flag2 | startedQuest.CompletedConditions.Contains(conditionFindItem.id)) ? true : false))
|
|
{
|
|
if (!byIndex.Item.QuestItem && !flag)
|
|
{
|
|
QuestItemIds.Add(byIndex.Item.LocalizedName());
|
|
flag = true;
|
|
}
|
|
else
|
|
{
|
|
Vector3 position = byIndex.transform.position;
|
|
AddQuestRecord(records, conditionFindItem, startedQuest, position, Color.yellow);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
}
|
|
|
|
private void RefreshNonStaticQuestItems(List<dynamic> startedQuests, GameWorld world, List<PointOfInterest> records)
|
|
{
|
|
try
|
|
{
|
|
foreach (GameLootContainer gameLootContainer in LootableContainerESP._gameLootContainers)
|
|
{
|
|
if (!GameUtils.IsLootableContainerValid(gameLootContainer.LootableContainer))
|
|
{
|
|
continue;
|
|
}
|
|
foreach (Item allItem in gameLootContainer.LootableContainer.ItemOwner.RootItem.GetAllItems())
|
|
{
|
|
foreach (dynamic startedQuest in startedQuests)
|
|
{
|
|
dynamic val = startedQuest.Template?.Conditions[EQuestStatus.AvailableForFinish];
|
|
if (val == null)
|
|
{
|
|
continue;
|
|
}
|
|
bool flag = false;
|
|
foreach (object item in val)
|
|
{
|
|
if (item is ConditionFindItem conditionFindItem)
|
|
{
|
|
string text = conditionFindItem.target.FirstOrDefault()?.ToString();
|
|
bool flag2 = text == null || !text.Contains(allItem.TemplateId.ToString());
|
|
if (!flag2 && !((flag2 | startedQuest.CompletedConditions.Contains(conditionFindItem.id)) ? true : false) && !allItem.QuestItem && !flag)
|
|
{
|
|
QuestItemIds.Add(allItem.LocalizedName());
|
|
flag = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (Main.OnlineGamePlayers.Count > 0)
|
|
{
|
|
foreach (OnlineGamePlayer onlineGamePlayer in Main.OnlineGamePlayers)
|
|
{
|
|
IEnumerator<Item> enumerator6 = onlineGamePlayer.Player.ObservedPlayerController.EquipmentViewController.Equipment.GetAllItems().GetEnumerator();
|
|
while (enumerator6.MoveNext())
|
|
{
|
|
if (enumerator6.Current != null)
|
|
{
|
|
foreach (Item allItem2 in enumerator6.Current.GetAllItems())
|
|
{
|
|
foreach (dynamic startedQuest2 in startedQuests)
|
|
{
|
|
dynamic val2 = startedQuest2.Template?.Conditions[EQuestStatus.AvailableForFinish];
|
|
if (!((val2 == null) ? true : false))
|
|
{
|
|
bool flag3 = false;
|
|
foreach (object item2 in val2)
|
|
{
|
|
if (item2 is ConditionFindItem conditionFindItem2)
|
|
{
|
|
string text2 = conditionFindItem2.target.FirstOrDefault()?.ToString();
|
|
bool flag2 = text2 == null || !text2.Contains(allItem2.TemplateId.ToString());
|
|
if (!flag2 && !((flag2 | startedQuest2.CompletedConditions.Contains(conditionFindItem2.id)) ? true : false) && !allItem2.QuestItem && !flag3)
|
|
{
|
|
QuestItemIds.Add(allItem2.LocalizedName());
|
|
flag3 = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
foreach (GamePlayer gamePlayer in Main.GamePlayers)
|
|
{
|
|
IEnumerator<Item> enumerator8 = gamePlayer.Player.Profile.Inventory.Equipment.GetAllItems().GetEnumerator();
|
|
while (enumerator8.MoveNext())
|
|
{
|
|
if (enumerator8.Current == null)
|
|
{
|
|
continue;
|
|
}
|
|
foreach (Item allItem3 in enumerator8.Current.GetAllItems())
|
|
{
|
|
foreach (dynamic startedQuest3 in startedQuests)
|
|
{
|
|
dynamic val3 = startedQuest3.Template?.Conditions[EQuestStatus.AvailableForFinish];
|
|
if (val3 == null)
|
|
{
|
|
continue;
|
|
}
|
|
bool flag4 = false;
|
|
foreach (object item3 in val3)
|
|
{
|
|
if (item3 is ConditionFindItem conditionFindItem3)
|
|
{
|
|
string text3 = conditionFindItem3.target.FirstOrDefault()?.ToString();
|
|
bool flag2 = text3 == null || !text3.Contains(allItem3.TemplateId.ToString());
|
|
if (!flag2 && !((flag2 | startedQuest3.CompletedConditions.Contains(conditionFindItem3.id)) ? true : false) && !allItem3.QuestItem && !flag4)
|
|
{
|
|
QuestItemIds.Add(allItem3.LocalizedName());
|
|
flag4 = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
}
|
|
|
|
private void RefreshPlaceOrRepairItemLocations(List<dynamic> startedQuests, Profile profile, List<PointOfInterest> records)
|
|
{
|
|
try
|
|
{
|
|
Item[] source = profile.Inventory.GetPlayerItems()?.ToArray();
|
|
List<PlaceItemTrigger> source2 = placeItemTriggers;
|
|
foreach (dynamic startedQuest in startedQuests)
|
|
{
|
|
try
|
|
{
|
|
dynamic val = startedQuest.Template?.Conditions[EQuestStatus.AvailableForFinish];
|
|
if (val == null)
|
|
{
|
|
continue;
|
|
}
|
|
foreach (object item in val)
|
|
{
|
|
ConditionZone zoneCondition = item as ConditionZone;
|
|
if (zoneCondition == null)
|
|
{
|
|
continue;
|
|
}
|
|
if (startedQuest.CompletedConditions.Contains(zoneCondition.id))
|
|
{
|
|
continue;
|
|
}
|
|
string zoneconditionstring = zoneCondition.target.FirstOrDefault()?.ToString();
|
|
if (zoneconditionstring != null && source.FirstOrDefault((Item x) => zoneconditionstring.Contains(x.TemplateId.ToString())) != null)
|
|
{
|
|
PlaceItemTrigger placeItemTrigger = source2.FirstOrDefault((PlaceItemTrigger t) => t.Id == zoneCondition.zoneId);
|
|
if (!(placeItemTrigger == null))
|
|
{
|
|
Vector3 position = placeItemTrigger.transform.position;
|
|
AddQuestRecord(records, zoneCondition, startedQuest, position, Color);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
}
|
|
|
|
private void AddQuestRecord(List<PointOfInterest> records, dynamic condition, dynamic quest, Vector3 position, Color color)
|
|
{
|
|
PointOfInterest item = new PointOfInterest
|
|
{
|
|
Name = $" {(object)quest.Template.Name} ",
|
|
Description = $" {(object)condition.FormattedDescription} ",
|
|
Position = position,
|
|
Color = color,
|
|
Quest = quest
|
|
};
|
|
records.Add(item);
|
|
}
|
|
|
|
public void OnGUI()
|
|
{
|
|
if (!(Main.GameWorld != null) || !Settings.QuestESP)
|
|
{
|
|
return;
|
|
}
|
|
foreach (var item in (from poi in poiList
|
|
group poi by new { poi.Position, poi.Name }).ToDictionary(g => g.Key, g => g.ToList()))
|
|
{
|
|
List<PointOfInterest> value = item.Value;
|
|
Vector3 position = item.Key.Position;
|
|
Vector3 vector = GameUtils.WorldPointToScreenPoint(position);
|
|
float num = Vector3.Distance(Main.MainCamera.transform.position, position);
|
|
bool num2 = vector.z > 0f && vector.x > 0f && vector.x < (float)Screen.width && vector.y > 0f && vector.y < (float)Screen.height;
|
|
bool flag = Aimbot.CaulculateInFov2(position) <= Settings.SimpleStringsFOV;
|
|
if (!num2)
|
|
{
|
|
continue;
|
|
}
|
|
if (Settings.DrawSimpleStrings)
|
|
{
|
|
string label = (flag ? $"{item.Key.Name} [{num:F0}m]" : "[Q]");
|
|
Render.DrawString(new Vector2(vector.x - 50f, vector.y), label, value[0].Color);
|
|
if (!flag || !Settings.DrawDescription)
|
|
{
|
|
continue;
|
|
}
|
|
float num3 = 15f;
|
|
foreach (PointOfInterest item2 in value)
|
|
{
|
|
Render.DrawString(new Vector2(vector.x - 50f, vector.y + num3), item2.Description, Color.white);
|
|
num3 += 15f;
|
|
}
|
|
continue;
|
|
}
|
|
string label2 = $"{item.Key.Name} [{num:F0}m]";
|
|
Render.DrawString(new Vector2(vector.x - 50f, vector.y), label2, value[0].Color);
|
|
if (!Settings.DrawDescription)
|
|
{
|
|
continue;
|
|
}
|
|
float num4 = 15f;
|
|
foreach (PointOfInterest item3 in value)
|
|
{
|
|
Render.DrawString(new Vector2(vector.x - 50f, vector.y + num4), item3.Description, Color.white);
|
|
num4 += 15f;
|
|
}
|
|
}
|
|
}
|
|
}
|