Created
December 9, 2023 06:49
-
-
Save spajus/f3cc31ad883f4182f0e8e133ffbcb298 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using Game.Audio; | |
using Game.Commands; | |
using Game.Components; | |
using Game.Constants; | |
using Game.Data; | |
using Game.Utils; | |
using Game.Visuals; | |
using KL.Clock; | |
using KL.Grid; | |
using KL.Randomness; | |
using KL.Utils; | |
using Unity.Mathematics; | |
using UnityEngine; | |
namespace Game.Story.Events { | |
public sealed class MicroMeteorStrikeStoryEvent : StoryEvent { | |
public const string Id = "MicroMeteorStrike"; | |
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType | |
.SubsystemRegistration)] | |
private static void Register() { | |
Register(meta); | |
} | |
private static readonly StoryEventMeta meta = new() { | |
Id = Id, | |
Create = () => new MicroMeteorStrikeStoryEvent(), | |
}; | |
public override StoryEventMeta Meta => meta; | |
public override EventLogEntry LogEntry => BuildLogEntry(); | |
public override float TensionToAddOnStart => 0.5f; | |
private EventLogEntry logEntry; | |
private Facing.Type directionFrom; | |
private EventLogEntry BuildLogEntry() => logEntry ??= EventLogEntry.CreateFor(this, | |
T.EvtMicroMeteorsTitle, T.EvtMicroMeteorsDesc, IconId.CWarning); | |
public override void AfterEnqueue() { | |
var rng = S.Rng; | |
directionFrom = rng.From(Facing.Types); | |
} | |
private long nextHitTick; | |
private int hitCount; | |
public override void OnTick(long ticks) { | |
if (ticks > nextHitTick) { | |
EnsureWarningEvent(); | |
Hit(ticks); | |
} | |
} | |
private readonly HashSet<int> hitObjects = new(); | |
private void Hit(long ticks) { | |
hitObjects.Clear(); | |
var count = Pos.GridW / 32; | |
var posF = EntityUtils.MeteorVector(directionFrom, 10f, count, Rng.Unseeded, | |
out var strikeV); | |
var startPos = posF(Mathf.RoundToInt(S.Rng.Range(count * 0.33f, count * 0.66f))); | |
var wt = WantedTension; | |
Vector2 curPos = startPos; | |
var stepV = strikeV.normalized; | |
if (stepV.sqrMagnitude < 0.001f) { | |
D.Err("stepV is zero!"); | |
} else { | |
var healthLeft = S.Rng.Range(200f, 300f) * wt / 5f; | |
healthLeft = math.clamp(healthLeft, 200f, 1000f); | |
bool hit = false; | |
var stepsLeft = Pos.GridW * 2f; | |
var a = S.Sys.Areas; | |
while (healthLeft > 0 && stepsLeft-- > 0) { | |
curPos += stepV; | |
var p = EntityUtils.ToPos(curPos); | |
if (Pos.IsOOB(p)) { continue; } | |
if (S.Sys.Sec.IsInForceFieldRange(curPos)) { | |
hit = true; | |
CmdCreateExplosion.CreateExplosionFX(S, curPos, 2f, 200f); | |
break; | |
} | |
if (S.Beings.ByPos.TryGetValue(p, out var hitBeings)) { | |
for (int i = hitBeings.Count - 1; i >= 0; i--) { | |
Being b = hitBeings[i]; | |
var beingDmg = Mathf.Min(healthLeft, b.Health.Health); | |
b.Health.TakeDamage(beingDmg, DamageType.Physical); | |
healthLeft -= beingDmg * 0.5f; | |
hit = true; | |
} | |
} | |
var wall = EntityUtils.WallAt(p); | |
if (wall?.IsConstructed == true) { | |
var wallH = wall.Damageable.Health; | |
if (S.Rng.Chance(0.7f)) { | |
wallH *= S.Rng.Range(0.85f, 0.99f); | |
} | |
var dmgAmt = Mathf.Min(healthLeft, wallH); | |
wall.Damageable.TakeDamage(dmgAmt, DamageType.Physical); | |
healthLeft -= dmgAmt; | |
hit = true; | |
CmdCreateExplosion.CreateExplosionFX(S, curPos, 2f, dmgAmt); | |
} | |
var obj = EntityUtils.ParentObjAt(p); | |
if (obj?.IsConstructed == true && hitObjects.Add(obj.PosIdx) | |
&& !obj.IsImmutable) { | |
// We hit the multi-tile object for the first time | |
var objH = obj.Damageable.Health; | |
if (S.Rng.Chance(0.7f)) { | |
objH *= S.Rng.Range(0.85f, 0.99f); | |
} | |
var dmgAmt = Mathf.Min(healthLeft, obj.Damageable.Health); | |
obj.Damageable.TakeDamage(dmgAmt, DamageType.Physical); | |
healthLeft -= dmgAmt; | |
CmdCreateExplosion.CreateExplosionFX(S, curPos, 2f, dmgAmt); | |
hit = true; | |
} | |
} | |
if (hit) { | |
S.Situation.AddTension(0.33f, "Micro Meteor: Hit"); | |
hitCount++; | |
} else { | |
S.Situation.AddTension(0.15f, "Micro Meteor: Miss"); | |
} | |
} | |
Coroutines.Start(ShowLine(ticks, Consts.TicksPer5Minutes, | |
startPos, curPos), this, "ShowLine"); | |
if (hitCount >= 5 && wt < 0.1f | |
|| S.Rng.Chance(Mathf.Clamp(0.01f, 0.1f, 1f / wt))) { | |
EndEvent(); | |
} else { | |
nextHitTick = ticks + Rng.URange(Consts.TicksPer3Minutes, | |
Consts.TicksPer15Minutes); | |
} | |
} | |
private IEnumerator ShowLine(long start, int durationInTicks, | |
Vector2 startPos, Vector2 endPos) { | |
var line = Lines.Create("BulletTrailLineFX", startPos, endPos); | |
var alphaStart = 0.25f; | |
var alphaEnd = 0.75f; | |
var endTick = start + durationInTicks; | |
while (S.Ticks < endTick) { | |
var alphaAmount = Mathf.InverseLerp(endTick, start, S.Ticks); | |
line.SetAlpha(alphaStart * alphaAmount, alphaEnd * alphaAmount); | |
yield return null; | |
if (!GameState.IsCurrent(S)) { yield break; } | |
} | |
line.Destroy(); | |
} | |
private EventNotification warningEvent; | |
public override void OnStart(long ticks) { | |
new CmdRestrictClock( | |
ClockSpeed.Normal, Consts.TicksPer10Minutes).Execute(S); | |
Sounds.PlayMusic(SoundtrackMood.Danger, true); | |
} | |
private void EnsureWarningEvent() { | |
if (warningEvent == null) { | |
var evt = UDB.Create( | |
"story", UDBT.IEventSticky, | |
IconId.CWarning, T.EvtMicroMeteorsTitle) | |
.WithIconClickFunction(LogEntry.ShowDetails); | |
warningEvent = EventNotification.Create(S.Ticks, | |
evt, Priority.Critical, true) | |
.WithUniqueId("micrometeors") | |
.AsEmergency(false, true); | |
S.Sig.AddEvent.Send(warningEvent); | |
} | |
} | |
protected override void OnLoad(ComponentData data) { | |
nextHitTick = data.GetLong("NextHit", 0); | |
directionFrom = (Facing.Type) data.GetInt("Direction", 0); | |
} | |
protected override void OnSave(ComponentData data) { | |
data.SetLong("NextHit", nextHitTick); | |
data.SetInt("Direction", (int) directionFrom); | |
} | |
public override void OnEnd(long ticks) { | |
if (warningEvent != null) { | |
S.Sig.RemoveEvent.Send(warningEvent); | |
warningEvent = null; | |
} | |
S.Sig.ShowFanfare.Send(Texts.Green(T.EvtMicroMeteorsEnded)); | |
S.Sys.Log.AddLine(T.EvtMicroMeteorsEnded, Consts.ColorTextGreen); | |
Sounds.PlayMusic(SoundtrackMood.Calm, false); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment