diff --git a/Content.Server/White/MeatyOre/MeatyOreStoreSystem.cs b/Content.Server/White/MeatyOre/MeatyOreStoreSystem.cs index 30dd13a9d3..91d58d559b 100644 --- a/Content.Server/White/MeatyOre/MeatyOreStoreSystem.cs +++ b/Content.Server/White/MeatyOre/MeatyOreStoreSystem.cs @@ -1,19 +1,31 @@ -using Content.Server.Chat.Managers; +using Content.Server.Chat.Managers; +using System.Linq; +using System.Net.Http; +using System.Net.Http.Json; +using System.Threading.Tasks; +using Content.Server.Chat.Managers; using Content.Server.GameTicking.Rules; using Content.Server.Mind; -using Content.Server.Roles; + using Content.Server.Popups; + using Content.Server.Roles; using Content.Server.Store.Components; using Content.Server.Store.Systems; using Content.Server.White.Sponsors; using Content.Shared.FixedPoint; using Content.Shared.GameTicking; using Content.Shared.Humanoid; -using Content.Shared.Mobs; + using Content.Shared.Mind.Components; + using Content.Shared.Mobs; using Content.Shared.Mobs.Components; using Content.Shared.Roles.Jobs; using Content.Shared.Verbs; using Content.Shared.White; using Content.Shared.White.MeatyOre; +using Content.Shared.Verbs; +using Content.Shared.White; +using Content.Shared.White.MeatyOre; +using Newtonsoft.Json.Linq; +using Robust.Server.GameObjects; using Robust.Server.GameStates; using Robust.Server.Player; using Robust.Shared.Configuration; @@ -21,7 +33,7 @@ using Robust.Shared.Map; using Robust.Shared.Network; using Robust.Shared.Player; -namespace Content.Server.White; +namespace Content.Server.White.MeatyOre; public sealed class MeatyOreStoreSystem : EntitySystem { @@ -36,19 +48,26 @@ public sealed class MeatyOreStoreSystem : EntitySystem [Dependency] private readonly RoleSystem _roleSystem = default!; [Dependency] private readonly MindSystem _mindSystem = default!; [Dependency] private readonly SharedJobSystem _jobSystem = default!; + [Dependency] private readonly PopupSystem _popupSystem = default!; + private HttpClient _httpClient = default!; + private string _apiUrl = default!; private static readonly string StorePresetPrototype = "StorePresetMeatyOre"; private static readonly string MeatyOreCurrencyPrototype = "MeatyOreCoin"; + private bool _meatyOrePanelEnabled; - private readonly Dictionary _meatyOreStores = new(); + public override void Initialize() { base.Initialize(); + _httpClient = new HttpClient(); + _configurationManager.OnValueChanged(WhiteCVars.MeatyOrePanelEnabled, OnPanelEnableChanged, true); + _configurationManager.OnValueChanged(WhiteCVars.OnlyInOhio, s => _apiUrl = s, true); SubscribeLocalEvent(OnPostRoundCleanup); SubscribeNetworkEvent(OnShopRequested); @@ -58,21 +77,28 @@ public sealed class MeatyOreStoreSystem : EntitySystem private void MeatyOreVerbs(GetVerbsEvent ev) { - if(!EntityManager.TryGetComponent(ev.User, out var actorComponent)) return; - if(!_sponsorsManager.TryGetInfo(actorComponent.PlayerSession.UserId, out _)) return; - if(!HasComp(ev.Target)) return; - if(!TryComp(ev.Target, out var state) || state?.CurrentState != MobState.Alive) return; - if(!TryGetStore(actorComponent.PlayerSession, out var store)) return; - - if(!_mindSystem.TryGetMind(ev.Target, out var mindId, out var mind)) return; - if (_roleSystem.MindIsAntagonist(mindId)) return; - - if(mind.Session == null) return; - if(!_jobSystem.CanBeAntag(mind.Session)) return; - - if (!store.Balance.TryGetValue("MeatyOreCoin", out var currency)) return; - - if(currency - 10 < 0) return; + if(!EntityManager.TryGetComponent(ev.User, out var actorComponent)) + return; + if(!_sponsorsManager.TryGetInfo(actorComponent.PlayerSession.UserId, out _)) + return; + if(!HasComp(ev.Target)) + return; + if(!TryComp(ev.Target, out var state) || state.CurrentState != MobState.Alive) + return; + if(!TryGetStore(actorComponent.PlayerSession, out var store)) + return; + if (!_mindSystem.TryGetMind(ev.Target, out var mindId, out var mind)) + return; + if (_roleSystem.MindIsAntagonist(mindId)) + return; + if (mind.Session == null) + return; + if (!_jobSystem.CanBeAntag(mind.Session)) + return; + if (!store.Balance.TryGetValue("MeatyOreCoin", out var currency)) + return; + if(currency - 10 < 0) + return; var verb = new Verb() { @@ -81,8 +107,7 @@ public sealed class MeatyOreStoreSystem : EntitySystem Message = $"Цена - {MeatyOreCurrencyPrototype}:10", Act = () => { - _storeSystem.TryAddCurrency(new Dictionary {{MeatyOreCurrencyPrototype, -10}}, store.Owner, store); - _traitorRuleSystem.MakeTraitor(mind.Session); + TryAddRole(ev.User, ev.Target, store); }, Category = VerbCategory.MeatyOre }; @@ -98,9 +123,11 @@ public sealed class MeatyOreStoreSystem : EntitySystem foreach (var meatyOreStoreData in _meatyOreStores) { var session = _playerManager.GetSessionByUserId(meatyOreStoreData.Key); - if(session == null) continue; + var playerEntity = session.AttachedEntity; - if(!playerEntity.HasValue) continue; + + if(!playerEntity.HasValue) + continue; _storeSystem.CloseUi(playerEntity.Value, meatyOreStoreData.Value); } @@ -121,9 +148,12 @@ public sealed class MeatyOreStoreSystem : EntitySystem var playerEntity = args.SenderSession.AttachedEntity; - if(!playerEntity.HasValue) return; - if(!HasComp(playerEntity.Value)) return; - if(!TryGetStore(playerSession!, out var storeComponent)) return; + if(!playerEntity.HasValue) + return; + if(!HasComp(playerEntity.Value)) + return; + if(!TryGetStore(playerSession!, out var storeComponent)) + return; _pvsOverrideSystem.AddSessionOverride(storeComponent.Owner, playerSession!); _storeSystem.ToggleUi(playerEntity.Value, storeComponent.Owner, storeComponent); @@ -134,12 +164,11 @@ public sealed class MeatyOreStoreSystem : EntitySystem store = null!; if (!_sponsorsManager.TryGetInfo(session.UserId, out var sponsorInfo)) - { return false; - } - - if (_meatyOreStores.TryGetValue(session.UserId, out store!)) return true; - if (sponsorInfo.MeatyOreCoin == 0) return false; + if (_meatyOreStores.TryGetValue(session.UserId, out store!)) + return true; + if (sponsorInfo.MeatyOreCoin == 0) + return false; store = CreateStore(session.UserId, sponsorInfo.MeatyOreCoin); return true; @@ -170,4 +199,107 @@ public sealed class MeatyOreStoreSystem : EntitySystem return storeComponent; } + + private async void TryAddRole(EntityUid user, EntityUid target, StoreComponent store) + { + if (!EntityManager.TryGetComponent(user, out var userActorComponent)) + return; + if (!EntityManager.TryGetComponent(target, out var targetActorComponent)) + return; + + var ckey = userActorComponent.PlayerSession.Name; + var grant = user == target; + var result = await GrantAntagonist(ckey, !grant); + + if (result) + { + _traitorRuleSystem.MakeTraitor(targetActorComponent.PlayerSession); + _storeSystem.TryAddCurrency(new Dictionary { { MeatyOreCurrencyPrototype, -10 } }, store.Owner, store); + } + else + { + var timeMessage = grant + ? $"Вы сможете выдать себе антага через: {await GetCooldownRemaining(ckey, false)}" + : $"Вы сможете выдать антага другу через: {await GetCooldownRemaining(ckey, true)}"; + + _popupSystem.PopupEntity(timeMessage, user, user); + } + } + + + private async Task GrantAntagonist(string ckey, bool isFriend) + { + var result = false; + + try + { + var url = $"{_apiUrl}/api/Antagonist/grantUser"; + + if (isFriend) + { + url = $"{_apiUrl}/api/Antagonist/grantFriend"; + } + + var requestData = new { UserId = ckey }; + + var response = await _httpClient.PostAsJsonAsync(url, requestData); + + if (response.IsSuccessStatusCode) + { + var responseContent = await response.Content.ReadAsStringAsync(); + result = bool.Parse(responseContent); + } + else + { + response.EnsureSuccessStatusCode(); + } + } + catch (Exception) + { + // ignored + } + + return result; + } + + private async Task GetCooldownRemaining(string ckey, bool isFriend) + { + try + { + var url = $"{_apiUrl}/api/Antagonist/cooldownUser?userId={ckey}"; + + if (isFriend) + { + url = $"{_apiUrl}/api/Antagonist/cooldownFriend?userId={ckey}"; + } + + HttpResponseMessage response; + + response = await _httpClient.GetAsync(url); + + if (response.IsSuccessStatusCode) + { + var responseData = await response.Content.ReadAsStringAsync(); + if (!string.IsNullOrEmpty(responseData)) + { + var jsonObject = JObject.Parse(responseData); + if (jsonObject.TryGetValue("remainingTime", out var remainingTimeToken) && TimeSpan.TryParse(remainingTimeToken.ToString(), out var remainingTime)) + { + var time = new TimeSpan(remainingTime.Hours, remainingTime.Minutes, 0); + return time; + } + } + } + else + { + response.EnsureSuccessStatusCode(); + } + } + catch (Exception) + { + // ignored + } + + return TimeSpan.Zero; + } } diff --git a/Content.Shared/White/WhiteCVars.cs b/Content.Shared/White/WhiteCVars.cs index 20bdf54bf2..16728c1b28 100644 --- a/Content.Shared/White/WhiteCVars.cs +++ b/Content.Shared/White/WhiteCVars.cs @@ -181,6 +181,13 @@ public sealed class WhiteCVars public static readonly CVarDef DefaultChatSize = CVarDef.Create("white.chat_size_default", "300;500", CVar.CLIENTONLY | CVar.ARCHIVE); + /* + * OnlyInOhio + */ + + public static readonly CVarDef OnlyInOhio = + CVarDef.Create("white.ohio_api_link", "", CVar.SERVERONLY | CVar.ARCHIVE | CVar.CONFIDENTIAL); + /* * Mark dead chat messages as admin */