diff --git a/Inferno/Inferno.csproj b/Inferno/Inferno.csproj index 6ab14839..fc051172 100644 --- a/Inferno/Inferno.csproj +++ b/Inferno/Inferno.csproj @@ -168,6 +168,7 @@ + diff --git a/Inferno/InfernoScripts/InfernoCore/CoroutineSystem.cs b/Inferno/InfernoScripts/InfernoCore/CoroutineSystem.cs index 465dd20d..e3a35e0f 100644 --- a/Inferno/InfernoScripts/InfernoCore/CoroutineSystem.cs +++ b/Inferno/InfernoScripts/InfernoCore/CoroutineSystem.cs @@ -2,6 +2,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; +using System.Windows.Markup.Localizer; namespace Inferno { @@ -57,6 +58,17 @@ public void RemoveCoroutine(uint id) } } + /// + /// 全てのコルーチンを停止する + /// + public void RemoveAllCoroutine() + { + lock (_lockObject) + { + _coroutines.Clear(); + } + } + /// /// コルーチンが存在するかどうかチェックする /// diff --git a/Inferno/InfernoScripts/InfernoCore/InfernoScript.cs b/Inferno/InfernoScripts/InfernoCore/InfernoScript.cs index 95cdf7cd..42428fbf 100644 --- a/Inferno/InfernoScripts/InfernoCore/InfernoScript.cs +++ b/Inferno/InfernoScripts/InfernoCore/InfernoScript.cs @@ -158,10 +158,12 @@ protected uint StartCoroutine(IEnumerable coroutine) protected void StopCoroutine(uint id) { - if (coroutineSystem != null) - { - coroutineSystem.RemoveCoroutine(id); - } + coroutineSystem?.RemoveCoroutine(id); + } + + protected void StopAllCoroutine() + { + coroutineSystem?.RemoveAllCoroutine(); } protected bool IsCoroutineActive(uint id) diff --git a/Inferno/InfernoScripts/Parupunte/Scripts/Isono.cs b/Inferno/InfernoScripts/Parupunte/Scripts/Isono.cs index 43dad16b..381b415b 100644 --- a/Inferno/InfernoScripts/Parupunte/Scripts/Isono.cs +++ b/Inferno/InfernoScripts/Parupunte/Scripts/Isono.cs @@ -6,6 +6,7 @@ namespace Inferno.InfernoScripts.Parupunte.Scripts { + internal class Isono : ParupunteScript { public Isono(ParupunteCore core) : base(core) diff --git a/Inferno/InfernoScripts/Parupunte/Scripts/PerfectFreeze.cs b/Inferno/InfernoScripts/Parupunte/Scripts/PerfectFreeze.cs index 5b45ea2e..b7e886b3 100644 --- a/Inferno/InfernoScripts/Parupunte/Scripts/PerfectFreeze.cs +++ b/Inferno/InfernoScripts/Parupunte/Scripts/PerfectFreeze.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using GTA; using UniRx; @@ -15,11 +16,11 @@ public PerfectFreeze(ParupunteCore core) : base(core) public override string Name { get; } = "パーフェクトフリーズ"; public override string EndMessage { get; } = "おわり"; - private readonly float FreezeRange = 30; + private readonly float FreezeRange = 60; public override void OnStart() { - ReduceCounter = new ReduceCounter(20 * 1000); + ReduceCounter = new ReduceCounter(15 * 1000); AddProgressBar(ReduceCounter); ReduceCounter.OnFinishedAsync.Subscribe(_ => { @@ -32,42 +33,33 @@ public override void OnStart() var playerPos = core.PlayerPed.Position; var playerVehicle = core.GetPlayerVehicle(); - #region Vehicle - foreach (var v in core.CachedVehicles.Where( + + #region Ped + foreach (var p in core.CachedPeds.Where( x => x.IsSafeExist() && !freezedEntities.Contains(x) && x.IsInRangeOf(playerPos, FreezeRange) && x.IsAlive && x != playerVehicle)) { - v.FreezePosition = true; - freezedEntities.Add(v); + p.FreezePosition = true; + freezedEntities.Add(p); } #endregion - #region props - var props = GTA.World.GetAllProps(); - foreach (var prop in props.Where(x => - x.IsSafeExist() + #region Vehicle + foreach (var v in core.CachedVehicles.Where( + x => x.IsSafeExist() && !freezedEntities.Contains(x) && x.IsInRangeOf(playerPos, FreezeRange) - )) + && x.IsAlive + && x != playerVehicle)) { - prop.FreezePosition = true; - freezedEntities.Add(prop); + v.FreezePosition = true; + freezedEntities.Add(v); } #endregion - //離れていたら解除 - var deleteTargets = freezedEntities.FirstOrDefault(x => - x.IsSafeExist() && !x.IsInRangeOf(playerPos, FreezeRange + 5)); - - if (deleteTargets != null) - { - deleteTargets.FreezePosition = false; - freezedEntities.Remove(deleteTargets); - } - }); //プレイヤ車両は除外 diff --git a/Inferno/InfernoScripts/Player/ArmorAndHealthSupplier.cs b/Inferno/InfernoScripts/Player/ArmorAndHealthSupplier.cs index 06fdc5c8..9e44fc5e 100644 --- a/Inferno/InfernoScripts/Player/ArmorAndHealthSupplier.cs +++ b/Inferno/InfernoScripts/Player/ArmorAndHealthSupplier.cs @@ -1,49 +1,49 @@ using GTA; -using UniRx; - -namespace Inferno -{ - internal class ArmorAndHealthSupplier : InfernoScript +using UniRx; + +namespace Inferno +{ + internal class ArmorAndHealthSupplier : InfernoScript { - protected override void Setup() + protected override void Setup() { - CreateInputKeywordAsObservable("armor") - .Subscribe(_ => - { - IsActive = !IsActive; - DrawText("SupplyArmorAndHealth:" + IsActive, 3.0f); - }); - - OnAllOnCommandObservable.Subscribe(_ => IsActive = true); - - //ミッションが始まった時 - OnTickAsObservable - .Where(_ => IsActive) - .Select(_ => Game.MissionFlag) - .DistinctUntilChanged() - .Where(x => x) - .Subscribe(_ => SupplyArmorAndHealth()); - - //プレイヤが復活した時 - OnTickAsObservable - .Where(_ => IsActive && PlayerPed.IsSafeExist()) - .Select(_ => PlayerPed.IsAlive) - .DistinctUntilChanged() - .Skip(1) //ONにした直後の判定結果は無視 - .Where(x => x) - .Subscribe(_ => SupplyArmorAndHealth()); + CreateInputKeywordAsObservable("armor") + .Subscribe(_ => + { + IsActive = !IsActive; + DrawText("SupplyArmorAndHealth:" + IsActive, 3.0f); + }); + + OnAllOnCommandObservable.Subscribe(_ => IsActive = true); + + //ミッションが始まった時 + OnTickAsObservable + .Where(_ => IsActive) + .Select(_ => Game.MissionFlag) + .DistinctUntilChanged() + .Where(x => x) + .Subscribe(_ => SupplyArmorAndHealth()); + + //プレイヤが復活した時 + OnTickAsObservable + .Where(_ => IsActive && PlayerPed.IsSafeExist()) + .Select(_ => PlayerPed.IsAlive) + .DistinctUntilChanged() + .Skip(1) //ONにした直後の判定結果は無視 + .Where(x => x) + .Subscribe(_ => SupplyArmorAndHealth()); } - /// - /// 体力とアーマー回復 - /// - private void SupplyArmorAndHealth() - { - var player = PlayerPed; - var maxHealth = player.MaxHealth; - var maxArmor = Game.Player.GetPlayerMaxArmor(); - player.Health = maxHealth; - player.Armor = maxArmor; - } - } -} + /// + /// 体力とアーマー回復 + /// + private void SupplyArmorAndHealth() + { + var player = PlayerPed; + var maxHealth = player.MaxHealth; + var maxArmor = Game.Player.GetPlayerMaxArmor(); + player.Health = maxHealth; + player.Armor = maxArmor; + } + } +} diff --git a/Inferno/InfernoScripts/World/SpeedMax.cs b/Inferno/InfernoScripts/World/SpeedMax.cs new file mode 100644 index 00000000..374bfa54 --- /dev/null +++ b/Inferno/InfernoScripts/World/SpeedMax.cs @@ -0,0 +1,180 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using GTA; +using GTA.Math; +using UniRx; +namespace Inferno.InfernoScripts.World +{ + class SpeedMax : InfernoScript + { + HashSet vehicleHashSet = new HashSet(); + + enum SpeedType + { + Original, + Low, + Middle, + High, + Random + } + + SpeedType currentSpeedType = SpeedType.Original; + + private bool excludeMissionVehicle = false; + + protected override void Setup() + { + CreateInputKeywordAsObservable("snax") + .Subscribe(_ => IsActive = !IsActive); + + IsActiveAsObservable + .Where(x => x) + .Subscribe(x => + { + DrawText($"SpeedMax:{IsActive}[Type:{(currentSpeedType)}][Exclude:{excludeMissionVehicle}]"); + vehicleHashSet.Clear(); + }); + + IsActiveAsObservable + .Where(x => !x) + .Subscribe(x => + { + DrawText($"SpeedMax:{IsActive}"); + vehicleHashSet.Clear(); + }); + + //ミッション開始直後に一瞬動作を止めるフラグ + var suspednFlag = false; + + OnTickAsObservable + .Where(_ => IsActive && !suspednFlag) + .Subscribe(_ => + { + foreach (var v in CachedVehicles + .Where(x => + x.IsSafeExist() + && x.IsInRangeOf(PlayerPed.Position, 100.0f) + && !vehicleHashSet.Contains(x.Handle) + && !(excludeMissionVehicle && x.IsPersistent) + )) + { + vehicleHashSet.Add(v.Handle); + if (currentSpeedType == SpeedType.Original) + { + StartCoroutine(OriginalSpeedMaxCoroutine(v)); + } + else + { + StartCoroutine(VehicleSpeedMaxCorutine(v)); + } + + } + }); + var nextType = currentSpeedType; + OnKeyDownAsObservable + .Where(x => IsActive && x.KeyCode == Keys.F6) + .Do(_ => + { + nextType = GetNextSpeedType(nextType); + DrawText($"SpeedMax:[Type:{nextType}]", 1.0f); + }) + .Throttle(TimeSpan.FromSeconds(1)) + .Subscribe(_ => + { + currentSpeedType = nextType; + DrawText($"SpeedMax:[Type:{(currentSpeedType)}][OK]", 2.0f); + StopAllCoroutine(); + vehicleHashSet.Clear(); + }); + + OnKeyDownAsObservable + .Where(x => IsActive && x.KeyCode == Keys.F5) + .Subscribe(_ => + { + excludeMissionVehicle = !excludeMissionVehicle; + vehicleHashSet.Clear(); + StopAllCoroutine(); + DrawText($"SpeedMax:ExcludeMissionVehicles[{excludeMissionVehicle}]"); + }); + + OnTickAsObservable + .Where(_ => IsActive) + .Select(_ => PlayerPed.IsAlive) + .DistinctUntilChanged() + .Where(x => x) + .Subscribe(_ => vehicleHashSet.Clear()); + + //ミッションが始まった時にしばらく動作を止める + OnTickAsObservable + .Where(_ => IsActive) + .Select(_ => Game.MissionFlag) + .DistinctUntilChanged() + .Where(x => x) + .Do(_ => suspednFlag = true) + .Delay(TimeSpan.FromSeconds(3)) + .Subscribe(_ => suspednFlag = false); + } + + /// + /// オリジナルに近い挙動 + /// + private IEnumerable OriginalSpeedMaxCoroutine(Vehicle v) + { + var maxSpeed = Random.Next(100, 300); + while (IsActive && v.IsSafeExist()) + { + if (!v.IsInRangeOf(PlayerPed.Position, 1000)) yield break; + if (PlayerVehicle.Value == v) yield break; + v.Speed = maxSpeed; + yield return null; + } + } + + /// + /// カスタム版 + /// + private IEnumerable VehicleSpeedMaxCorutine(Vehicle v) + { + //たまに後ろに飛ぶ + var dir = (v.Handle % 10 == 0) ? -1 : 1; + var maxSpeed = GetVehicleSpeed() * dir; + if (Math.Abs(maxSpeed) > 20) + { + v.Speed = 100 * dir; + } + while (IsActive && v.IsSafeExist()) + { + if (!v.IsInRangeOf(PlayerPed.Position, 1000)) yield break; + if (PlayerVehicle.Value == v) yield break; + v.ApplyForce(maxSpeed * v.ForwardVector); + yield return null; + } + } + + private SpeedType GetNextSpeedType(SpeedType current) + { + return (SpeedType)(((int)current + 1) % Enum.GetNames(typeof(SpeedType)).Length); + } + + private float GetVehicleSpeed() + { + switch (currentSpeedType) + { + case SpeedType.Low: + return Random.Next(5, 10); + case SpeedType.Middle: + return Random.Next(10, 15); + case SpeedType.High: + return Random.Next(20, 30); + case SpeedType.Random: + return Random.Next(5, 30); + default: + return 0; + } + } + } +}