Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Timpanist v0.3.2
BepInEx/plugins/Rodanius-Timpanist/Rodanius.Timpanist.dll
Decompiled 20 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Text; using System.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using EntityStates; using HG; using HG.BlendableTypes; using KinematicCharacterController; using R2API; using R2API.Utils; using RoR2; using RoR2.CharacterAI; using RoR2.ContentManagement; using RoR2.Skills; using UnityEngine; using UnityEngine.Networking; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyVersion("0.0.0.0")] namespace Timpanist; public static class Combat { private static readonly Collider[] overlaps = (Collider[])(object)new Collider[512]; public static Ray Aim(CharacterBody body) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) Ray val = default(Ray); ((Ray)(ref val))..ctor(body.inputBank.aimOrigin, body.inputBank.aimDirection); float num = default(float); val = CameraRigController.ModifyAimRayIfApplicable(val, ((Component)body).gameObject, ref num); Vector3 point = ((Ray)(ref val)).GetPoint(1000f); GameObject gameObject = ((Component)body).gameObject; Ray val2 = val; LayerIndex val3 = LayerIndex.world; int num2 = LayerMask.op_Implicit(((LayerIndex)(ref val3)).mask); val3 = LayerIndex.entityPrecise; RaycastHit val4 = default(RaycastHit); if (Util.CharacterRaycast(gameObject, val2, ref val4, 1000f, LayerMask.op_Implicit(num2 | LayerMask.op_Implicit(((LayerIndex)(ref val3)).mask)), (QueryTriggerInteraction)1)) { point = ((RaycastHit)(ref val4)).point; } Vector3 aimOrigin = body.aimOrigin; Vector3 val5 = point - body.aimOrigin; return new Ray(aimOrigin, ((Vector3)(ref val5)).normalized); } public static DamageTypeCombo Type(DamageSource source, bool stun = false) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) return new DamageTypeCombo(DamageTypeCombo.op_Implicit((DamageType)(stun ? 32 : 0)), (DamageTypeExtended)0, source); } public unsafe static bool Hit(CharacterBody body, HealthComponent health, Vector3 point, float coefficient, float proc, DamageSource source, bool crit, bool stun, Vector3 force, ProcChainMask mask, GameObject inflictor = null, HurtBox hurtBox = null) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected O, but got Unknown //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Invalid comparison between Unknown and I4 //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Invalid comparison between Unknown and I4 if (!NetworkServer.active || !Object.op_Implicit((Object)(object)health) || (Object)(object)health == (Object)(object)body.healthComponent || !health.alive) { return false; } DamageInfo val = new DamageInfo { attacker = ((Component)body).gameObject, inflictor = (Object.op_Implicit((Object)(object)inflictor) ? inflictor : ((Component)body).gameObject), damage = body.damage * coefficient, crit = crit, position = point, force = force, procCoefficient = proc, procChainMask = mask, damageType = Type(source, stun), damageColorIndex = (DamageColorIndex)0 }; if (Object.op_Implicit((Object)(object)hurtBox)) { val.inflictedHurtbox = hurtBox; if (hurtBox.AttackHitRejectsHurtbox(new HurtBoxAttackHitProcessorArgs(val, body.aimOrigin))) { return false; } val.ModifyDamageInfo(hurtBox.damageModifier); } health.TakeDamage(val); GlobalEventManager.instance.OnHitEnemy(val, ((Component)health).gameObject); GlobalEventManager.instance.OnHitAll(val, ((Component)health).gameObject); TimpanistController component = ((Component)body).GetComponent<TimpanistController>(); if (Object.op_Implicit((Object)(object)component)) { component.Trace("direct-hit", ((object)(*(DamageSource*)(&source))/*cast due to .constrained prefix*/).ToString(), ((int)source == 1) ? body.skillLocator.primary : (((int)source == 4) ? body.skillLocator.utility : body.skillLocator.secondary), 0f, coefficient, proc, crit, ((Object)health).GetInstanceID()); } return true; } public unsafe static void Area(CharacterBody body, Vector3 origin, Vector3 aim, float radius, float halfAngle, float coefficient, float proc, DamageSource source, bool crit, bool stun, HashSet<HealthComponent> seen, float knockback = 10f) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) float num = radius; Collider[] array = overlaps; LayerIndex val = LayerIndex.entityPrecise; int num2 = Physics.OverlapSphereNonAlloc(origin, num, array, LayerMask.op_Implicit(((LayerIndex)(ref val)).mask), (QueryTriggerInteraction)2); int count = seen.Count; Collider[] array2 = overlaps; if (num2 == overlaps.Length) { float num3 = radius; val = LayerIndex.entityPrecise; array2 = Physics.OverlapSphere(origin, num3, LayerMask.op_Implicit(((LayerIndex)(ref val)).mask), (QueryTriggerInteraction)2); num2 = array2.Length; } for (int i = 0; i < num2; i++) { HurtBox component = ((Component)array2[i]).GetComponent<HurtBox>(); if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)component.healthComponent)) { continue; } HealthComponent healthComponent = component.healthComponent; if (seen.Contains(healthComponent) || (Object)(object)healthComponent == (Object)(object)body.healthComponent || !FriendlyFireManager.ShouldSplashHitProceed(healthComponent, body.teamComponent.teamIndex)) { continue; } Vector3 val2 = array2[i].ClosestPoint(origin); Vector3 val3 = val2 - origin; if (halfAngle < 180f && Vector3.Angle(aim, val3) > halfAngle) { continue; } val = LayerIndex.world; if (!Physics.Linecast(origin, val2, LayerMask.op_Implicit(((LayerIndex)(ref val)).mask), (QueryTriggerInteraction)1)) { Vector3 force = (stun ? (((Vector3)(ref val3)).normalized * 800f + Vector3.up * 250f) : (((Vector3)(ref val3)).normalized * knockback)); if (Hit(body, healthComponent, val2, coefficient, proc, source, crit, stun, force, default(ProcChainMask), null, component)) { seen.Add(healthComponent); } } } if (Plugin.Diagnostics.Value && proc >= 1f) { Plugin.Log("strike-query source=" + ((object)(*(DamageSource*)(&source))/*cast due to .constrained prefix*/).ToString() + " candidates=" + num2 + " selected=" + (seen.Count - count) + " radius=" + radius + " angle=" + halfAngle); } } public static void Sweep(CharacterBody body, Vector3 from, Vector3 to, float radius, float coefficient, float proc, bool crit, HashSet<HealthComponent> seen, HashSet<HealthComponent> afterbeatHits) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) Vector3 val = to - from; int num = Mathf.Max(1, Mathf.CeilToInt(((Vector3)(ref val)).magnitude / 0.4f)); for (int i = 0; i <= num; i++) { Vector3 val2 = Vector3.Lerp(from, to, (float)i / (float)num); Vector3 val3 = val2 - Vector3.up * 0.45f; Vector3 val4 = val2 + Vector3.up * 0.45f; Collider[] array = overlaps; LayerIndex val5 = LayerIndex.entityPrecise; int num2 = Physics.OverlapCapsuleNonAlloc(val3, val4, radius, array, LayerMask.op_Implicit(((LayerIndex)(ref val5)).mask), (QueryTriggerInteraction)2); Collider[] array2 = overlaps; if (num2 == overlaps.Length) { val5 = LayerIndex.entityPrecise; array2 = Physics.OverlapCapsule(val3, val4, radius, LayerMask.op_Implicit(((LayerIndex)(ref val5)).mask), (QueryTriggerInteraction)2); num2 = array2.Length; } for (int j = 0; j < num2; j++) { HurtBox component = ((Component)array2[j]).GetComponent<HurtBox>(); if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)component.healthComponent) || seen.Contains(component.healthComponent) || (Object)(object)component.healthComponent == (Object)(object)body.healthComponent || !FriendlyFireManager.ShouldSplashHitProceed(component.healthComponent, body.teamComponent.teamIndex)) { continue; } Vector3 val6 = array2[j].ClosestPoint(val2); val5 = LayerIndex.world; if (!Physics.Linecast(val2, val6, LayerMask.op_Implicit(((LayerIndex)(ref val5)).mask), (QueryTriggerInteraction)1)) { Vector3 corePosition = body.corePosition; val5 = LayerIndex.world; if (!Physics.Linecast(corePosition, val6, LayerMask.op_Implicit(((LayerIndex)(ref val5)).mask), (QueryTriggerInteraction)1) && Hit(body, component.healthComponent, val6, coefficient, proc, (DamageSource)4, crit, stun: false, ((Vector3)(ref val)).normalized * 150f, default(ProcChainMask), null, component)) { seen.Add(component.healthComponent); ((Component)body).GetComponent<TimpanistController>().QueueAfterbeat(component.healthComponent, val6, crit, afterbeatHits); } } } } } public static void Strike(CharacterBody body, Tuning mode, bool right) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) Ray val = Aim(body); HashSet<HealthComponent> hashSet = new HashSet<HealthComponent>(); Area(body, ((Ray)(ref val)).origin, ((Ray)(ref val)).direction, 22f, 38f, 4f, 1f, (DamageSource)1, body.RollCrit(), stun: false, hashSet, 100f); int num = 0; foreach (HealthComponent item in hashSet) { if (Object.op_Implicit((Object)(object)item) && Object.op_Implicit((Object)(object)item.body) && num++ < 12) { ImpactVisual.Emit(body, item.body.corePosition, ((Ray)(ref val)).direction, 0.8f, ImpactKind.HeavyContact); } } } public static void Roll(CharacterBody body) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) Ray val = Aim(body); HashSet<HealthComponent> hashSet = new HashSet<HealthComponent>(); Area(body, ((Ray)(ref val)).origin, ((Ray)(ref val)).direction, 14f, 50f, CavalryRules.RollDamage(body.attackSpeed), 0.12f, (DamageSource)2, body.RollCrit(), stun: false, hashSet, 130f); foreach (HealthComponent item in hashSet) { if (Object.op_Implicit((Object)(object)item) && Object.op_Implicit((Object)(object)item.body)) { item.body.AddTimedBuff(Content.MidFull, 0.35f); } } } } public static class Content { public static DrumSkillDef Left; public static RollSkillDef Right; public static SkillDef Charge; public static SkillDef Retune; public static BuffDef Poise; public static BuffDef LowFull; public static BuffDef LowHalf; public static BuffDef MidFull; public static BuffDef MidHalf; public static BuffDef LowResonant; public static BuffDef MidResonant; private static void Field(object target, string name, object value) { FieldInfo? field = target.GetType().GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { throw new MissingFieldException(target.GetType().FullName, name); } field.SetValue(target, value); } public static void Build(ContentPack pack) { //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_0292: Unknown result type (might be due to invalid IL or missing references) //IL_0297: Unknown result type (might be due to invalid IL or missing references) //IL_0303: Unknown result type (might be due to invalid IL or missing references) //IL_0308: Unknown result type (might be due to invalid IL or missing references) //IL_0309: Unknown result type (might be due to invalid IL or missing references) //IL_030b: Unknown result type (might be due to invalid IL or missing references) //IL_0310: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Unknown result type (might be due to invalid IL or missing references) //IL_0352: Unknown result type (might be due to invalid IL or missing references) //IL_0357: Unknown result type (might be due to invalid IL or missing references) //IL_0358: Unknown result type (might be due to invalid IL or missing references) //IL_035a: Unknown result type (might be due to invalid IL or missing references) //IL_035f: Unknown result type (might be due to invalid IL or missing references) //IL_0361: Unknown result type (might be due to invalid IL or missing references) //IL_0455: Unknown result type (might be due to invalid IL or missing references) //IL_045a: Unknown result type (might be due to invalid IL or missing references) //IL_0463: Unknown result type (might be due to invalid IL or missing references) //IL_0468: Unknown result type (might be due to invalid IL or missing references) //IL_0489: Unknown result type (might be due to invalid IL or missing references) //IL_048e: Unknown result type (might be due to invalid IL or missing references) //IL_0493: Unknown result type (might be due to invalid IL or missing references) //IL_049d: Unknown result type (might be due to invalid IL or missing references) //IL_049f: Unknown result type (might be due to invalid IL or missing references) //IL_054b: Unknown result type (might be due to invalid IL or missing references) //IL_05ca: Unknown result type (might be due to invalid IL or missing references) //IL_064f: Unknown result type (might be due to invalid IL or missing references) //IL_0654: Unknown result type (might be due to invalid IL or missing references) //IL_065e: Unknown result type (might be due to invalid IL or missing references) //IL_0682: Unknown result type (might be due to invalid IL or missing references) //IL_06a6: Unknown result type (might be due to invalid IL or missing references) //IL_06ca: Unknown result type (might be due to invalid IL or missing references) //IL_06ee: Unknown result type (might be due to invalid IL or missing references) //IL_0712: Unknown result type (might be due to invalid IL or missing references) //IL_0736: Unknown result type (might be due to invalid IL or missing references) //IL_074a: Unknown result type (might be due to invalid IL or missing references) //IL_0751: Expected O, but got Unknown //IL_07f2: Unknown result type (might be due to invalid IL or missing references) //IL_07f7: Unknown result type (might be due to invalid IL or missing references) SurvivorIdentity.RegisterLanguage(); LanguageAPI.Add("TIMPANIST_NAME", "The Timpanist"); LanguageAPI.Add("TIMPANIST_SUBTITLE", "Cavalry Percussionist"); LanguageAPI.Add("TIMPANIST_DESCRIPTION", "A mounted percussionist who breaks enemy lines with heavy sound waves. Strike hard, control crowds with a roll, and charge through them for a delayed Afterbeat."); LanguageAPI.Add("TIMPANIST_OUTRO", "...and so they left, the last note still ringing."); LanguageAPI.Add("TIMPANIST_FAILURE", "...and so they vanished, an unfinished cadence."); LanguageAPI.Add("TIMPANIST_DEFAULT", "Cavalry Percussionist"); GameObject obj = LegacyResourcesAPI.Load<GameObject>("Prefabs/CharacterBodies/CommandoBody"); if (!Object.op_Implicit((Object)(object)obj)) { throw new InvalidOperationException("CommandoBody runtime reference unavailable"); } GameObject val = PrefabAPI.InstantiateClone(obj, "RodaniusTimpanistBody", true); CharacterBody component = val.GetComponent<CharacterBody>(); component.baseNameToken = "TIMPANIST_NAME"; component.subtitleNameToken = "TIMPANIST_SUBTITLE"; component.baseMaxHealth = 130f; component.levelMaxHealth = 39f; component.baseRegen = 1f; component.levelRegen = 0.2f; component.baseDamage = 12f; component.levelDamage = 2.4f; component.baseCrit = 1f; component.levelCrit = 0f; component.baseArmor = 0f; component.levelArmor = 0f; component.baseMoveSpeed = 8.5f; component.levelMoveSpeed = 0f; component.baseAcceleration = 110f; component.baseJumpPower = 15f; component.levelJumpPower = 0f; component.baseJumpCount = 1; component.sprintingSpeedMultiplier = 1.6f; component.baseAttackSpeed = 1f; component.levelAttackSpeed = 0f; component.autoCalculateLevelStats = false; component.bodyColor = Graybox.Green; val.GetComponent<CharacterMotor>().mass = 100f; Rigidbody component2 = val.GetComponent<Rigidbody>(); if (Object.op_Implicit((Object)(object)component2)) { component2.mass = 100f; } KinematicCharacterMotor component3 = val.GetComponent<KinematicCharacterMotor>(); component3.Capsule = val.GetComponent<CapsuleCollider>(); component3.SetCapsuleDimensions(0.48f, 2.2f, 0f); val.GetComponent<ModelLocator>().modelTransform.parent.localPosition = new Vector3(0f, -1.1f, 0f); component.aimOriginTransform = Anchor(val.transform, "TimpanistAim", new Vector3(0f, 0.65f, 0f)); component.overrideCoreTransform = Anchor(val.transform, "TimpanistCore", Vector3.zero); List<EntityStateMachine> list = new List<EntityStateMachine>(val.GetComponents<EntityStateMachine>()); EntityStateMachine val2 = null; EntityStateMachine bodyMachine = null; foreach (EntityStateMachine item in list) { if (item.customName == "Body") { item.mainStateType = new SerializableEntityStateType(typeof(TimpanistMain)); bodyMachine = item; } if (item.customName == "Weapon") { val2 = item; } } if (!Object.op_Implicit((Object)(object)val2) || !Object.op_Implicit((Object)(object)bodyMachine)) { throw new InvalidOperationException("Template state-machine contract changed"); } val2.initialStateType = (val2.mainStateType = new SerializableEntityStateType(typeof(Idle))); string[] array = new string[1] { "Cavalry" }; foreach (string customName in array) { EntityStateMachine val3 = val.AddComponent<EntityStateMachine>(); val3.customName = customName; val3.initialStateType = (val3.mainStateType = new SerializableEntityStateType(typeof(Idle))); list.Add(val3); } Field(val.GetComponent<NetworkStateMachine>(), "stateMachines", list.ToArray()); SetStateOnHurt component4 = val.GetComponent<SetStateOnHurt>(); if (Object.op_Implicit((Object)(object)component4)) { component4.idleStateMachine = list.FindAll((EntityStateMachine x) => (Object)(object)x != (Object)(object)bodyMachine && x.customName != "Tuning").ToArray(); } CharacterDeathBehavior component5 = val.GetComponent<CharacterDeathBehavior>(); if (Object.op_Implicit((Object)(object)component5)) { component5.idleStateMachine = list.FindAll((EntityStateMachine x) => (Object)(object)x != (Object)(object)bodyMachine).ToArray(); } Transform modelTransform = val.GetComponent<ModelLocator>().modelTransform; Material template = (PressureVisual.Template = ((Component)modelTransform).GetComponent<CharacterModel>().baseRendererInfos[0].defaultMaterial); ImpactVisual.Build(pack); Graybox.BuildModel(val, modelTransform, template); val.AddComponent<TimpanistController>(); CameraTargetParams component6 = val.GetComponent<CameraTargetParams>(); component6.cameraParams = Object.Instantiate<CharacterCameraParams>(component6.cameraParams); CharacterCameraParamsData data = component6.cameraParams.data; data.pivotVerticalOffset = BlendableFloat.op_Implicit(1.65f); data.idealLocalCameraPos = BlendableVector3.op_Implicit(new Vector3(Plugin.CameraOffset.Value, 0f, 0f - Plugin.CameraDistance.Value)); component6.cameraParams.data = data; SkillLocator component7 = val.GetComponent<SkillLocator>(); GenericSkill[] components = val.GetComponents<GenericSkill>(); for (int i = 0; i < components.Length; i++) { Object.DestroyImmediate((Object)(object)components[i]); } Left = Make<DrumSkillDef>("LEFT", "Hammerstroke", "Strike a broad sound wave for <style=cIsDamage>400% damage</style>. Hold to repeat.", "Weapon", typeof(StrokeState), 0f, 0, end: false); Right = Make<RollSkillDef>("RIGHT", "Pressure Roll", "Hold for up to <style=cIsUtility>2s</style>: deal <style=cIsDamage>120% damage per second</style>, slow enemies by <style=cIsUtility>30%</style>, and push them back.", "Weapon", typeof(RollState), 6f, 1, end: true); ((SkillDef)Right).mustKeyPress = true; ((SkillDef)Right).autoHandleLuminousShot = true; ((SkillDef)Right).interruptPriority = (InterruptPriority)2; Charge = Make<SkillDef>("CHARGE", "Thunderous Charge", "Charge forward for <style=cIsDamage>350% damage</style>. Hits erupt in an <style=cIsDamage>180% Afterbeat</style>. Primary ends the charge early.", "Cavalry", typeof(ChargeState), 7f, 1, end: false); Charge.mustKeyPress = true; Retune = Make<SkillDef>("RETUNE", "Grand Accent", "Strike both drums for a staggering <style=cIsDamage>900% damage</style> wave.", "Weapon", typeof(GrandAccentState), 10f, 1, end: false); Retune.mustKeyPress = true; Retune.interruptPriority = (InterruptPriority)2; component7.primary = Slot(val, (SkillDef)(object)Left, pack); component7.secondary = Slot(val, (SkillDef)(object)Right, pack); component7.utility = Slot(val, Charge, pack); component7.special = Slot(val, Retune, pack); Poise = ScriptableObject.CreateInstance<BuffDef>(); ((Object)Poise).name = "RodaniusMountedPoise"; Poise.canStack = false; Poise.isDebuff = false; Poise.buffColor = Graybox.Green; Poise.iconSprite = Graybox.Icon(Graybox.Green); LowFull = Buff("TimpanistLowFull", debuff: false, new Color(0.35f, 0.95f, 0.85f)); LowResonant = Buff("TimpanistLowResonant", debuff: false, new Color(0.3f, 1f, 1f)); MidResonant = Buff("TimpanistMidResonant", debuff: true, new Color(1f, 0.9f, 0.4f)); LowHalf = Buff("TimpanistLowHalf", debuff: false, new Color(0.35f, 0.7f, 0.65f)); MidFull = Buff("TimpanistMidFull", debuff: true, new Color(1f, 0.75f, 0.25f)); MidHalf = Buff("TimpanistMidHalf", debuff: true, new Color(0.8f, 0.6f, 0.25f)); GameObject val4 = new GameObject("RodaniusTimpanistDisplay"); val4.SetActive(false); if (!Presentation.TryBuild(val4.transform, template)) { Graybox.BuildVisual(val4.transform, template); } Object.DontDestroyOnLoad((Object)(object)val4); GameObject val5 = PrefabAPI.InstantiateClone(val4, "RodaniusTimpanistDisplayPrefab", false); val5.SetActive(true); Object.Destroy((Object)(object)val4); SurvivorDef val6 = ScriptableObject.CreateInstance<SurvivorDef>(); ((Object)val6).name = "RodaniusTimpanist"; val6.bodyPrefab = val; val6.displayPrefab = val5; val6.displayNameToken = "TIMPANIST_NAME"; val6.descriptionToken = "TIMPANIST_DESCRIPTION"; val6.outroFlavorToken = "TIMPANIST_OUTRO"; val6.mainEndingEscapeFailureFlavorToken = "TIMPANIST_FAILURE"; val6.primaryColor = Graybox.Green; val6.desiredSortPosition = 100f; val6.hidden = false; component.portraitIcon = (Texture)(object)SurvivorIdentity.LoadPortrait(); GameObject val7 = PrefabAPI.InstantiateClone(LegacyResourcesAPI.Load<GameObject>("Prefabs/CharacterMasters/CommandoMonsterMaster"), "RodaniusTimpanistMonsterMaster", true); val7.GetComponent<CharacterMaster>().bodyPrefab = val; AISkillDriver[] components2 = val7.GetComponents<AISkillDriver>(); for (int i = 0; i < components2.Length; i++) { Object.DestroyImmediate((Object)(object)components2[i]); } Driver(val7, "Crowd control", (SkillSlot)1, 0f, 10f); Driver(val7, "Hammerstroke", (SkillSlot)0, 0f, 22f); Driver(val7, "Charge", (SkillSlot)2, 22f, 40f); Driver(val7, "Approach", (SkillSlot)(-1), 22f, float.PositiveInfinity); pack.bodyPrefabs.Add((GameObject[])(object)new GameObject[1] { val }); pack.masterPrefabs.Add((GameObject[])(object)new GameObject[1] { val7 }); pack.survivorDefs.Add((SurvivorDef[])(object)new SurvivorDef[1] { val6 }); pack.buffDefs.Add((BuffDef[])(object)new BuffDef[7] { Poise, LowFull, LowHalf, MidFull, MidHalf, LowResonant, MidResonant }); pack.skillDefs.Add((SkillDef[])(object)new SkillDef[4] { Left, Right, Charge, Retune }); pack.entityStateTypes.Add(new Type[5] { typeof(TimpanistMain), typeof(StrokeState), typeof(RollState), typeof(ChargeState), typeof(GrandAccentState) }); Plugin.Log("Registered Timpanist content; runtime acceptance NOT yet established."); } private static T Make<T>(string id, string title, string description, string machine, Type state, float recharge, int consume, bool end) where T : SkillDef { //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) T val = ScriptableObject.CreateInstance<T>(); ((Object)(object)val).name = "RodaniusTimpanist" + id; ((SkillDef)val).skillName = "TIMPANIST_" + id; ((SkillDef)val).skillNameToken = ((SkillDef)val).skillName + "_NAME"; ((SkillDef)val).skillDescriptionToken = ((SkillDef)val).skillName + "_DESCRIPTION"; LanguageAPI.Add(((SkillDef)val).skillNameToken, title); LanguageAPI.Add(((SkillDef)val).skillDescriptionToken, description); ((SkillDef)val).activationStateMachineName = machine; ((SkillDef)val).activationState = new SerializableEntityStateType(state); ((SkillDef)val).baseMaxStock = 1; ((SkillDef)val).baseRechargeInterval = recharge; ((SkillDef)val).rechargeStock = 1; ((SkillDef)val).requiredStock = consume; ((SkillDef)val).stockToConsume = consume; ((SkillDef)val).fullRestockOnAssign = true; ((SkillDef)val).resetCooldownTimerOnUse = false; ((SkillDef)val).beginSkillCooldownOnSkillEnd = end; ((SkillDef)val).isCombatSkill = true; ((SkillDef)val).cancelSprintingOnActivation = false; ((SkillDef)val).canceledFromSprinting = false; ((SkillDef)val).interruptPriority = (InterruptPriority)1; ((SkillDef)val).icon = SkillIcons.Load(id); return val; } private static GenericSkill Slot(GameObject body, SkillDef def, ContentPack pack) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) GenericSkill val = body.AddComponent<GenericSkill>(); val.skillName = def.skillName; SkillFamily val2 = ScriptableObject.CreateInstance<SkillFamily>(); ((Object)val2).name = def.skillName + "Family"; Variant[] array = new Variant[1]; Variant val3 = new Variant { skillDef = def }; ((Variant)(ref val3)).viewableNode = new Node(def.skillNameToken, false, (Node)null); array[0] = val3; val2.variants = (Variant[])(object)array; Field(val, "_skillFamily", val2); pack.skillFamilies.Add((SkillFamily[])(object)new SkillFamily[1] { val2 }); return val; } private static void Driver(GameObject master, string name, SkillSlot slot, float min, float max) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) AISkillDriver obj = master.AddComponent<AISkillDriver>(); obj.customName = name; obj.skillSlot = slot; obj.requireSkillReady = (int)slot != -1; obj.minDistance = min; obj.maxDistance = max; obj.selectionRequiresTargetLoS = true; obj.activationRequiresTargetLoS = true; obj.moveTargetType = (TargetType)0; obj.movementType = (MovementType)1; obj.aimType = (AimType)2; obj.shouldSprint = true; obj.moveInputScale = 1f; obj.driverUpdateTimerOverride = 0.2f; } public static Transform Anchor(Transform parent, string name, Vector3 position) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) Transform transform = new GameObject(name).transform; transform.SetParent(parent, false); transform.localPosition = position; return transform; } private static BuffDef Buff(string name, bool debuff, Color color) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) BuffDef obj = ScriptableObject.CreateInstance<BuffDef>(); ((Object)obj).name = name; obj.isDebuff = debuff; obj.canStack = false; obj.buffColor = color; obj.iconSprite = Graybox.Icon(color); return obj; } } public sealed class TimpanistController : MonoBehaviour { private sealed class PendingBeat { public HealthComponent target; public Vector3 point; public float at; public bool crit; public HashSet<HealthComponent> hit; } public CharacterBody Body; public EntityStateMachine Weapon; public EntityStateMachine Cavalry; public EntityStateMachine BodyMachine; public Tuning LeftMode = Tuning.Mid; public Tuning RightMode = Tuning.Mid; public byte VisualMask; public float LeftFlash = -100f; public float RightFlash = -100f; public float TuneFlash = -100f; public float StrokeSpeed = 1f; public float ImpactSoundAt = -100f; public float RollClock; public float NextEffectTick; public float ChargeFlash = -100f; public float GrandFlash = -100f; public bool LastTuneRight; public bool NextRight; public bool PrimaryPressed; public int Cast; public string LastCancellation = ""; private bool oldPrimary; private bool focus = true; private float chargeUntil; private readonly List<PendingBeat> pending = new List<PendingBeat>(); public bool VisualRolling => VisualMask != 0; private void Awake() { Body = ((Component)this).GetComponent<CharacterBody>(); EntityStateMachine[] components = ((Component)this).GetComponents<EntityStateMachine>(); foreach (EntityStateMachine val in components) { if (val.customName == "Weapon") { Weapon = val; } if (val.customName == "Cavalry") { Cavalry = val; } if (val.customName == "Body") { BodyMachine = val; } } } private void Start() { CharacterBody body = Body; body.OnBodyDeath = (Action<CharacterBody>)Delegate.Combine(body.OnBodyDeath, new Action<CharacterBody>(Died)); if (Plugin.Diagnostics.Value) { ((Component)this).gameObject.AddComponent<DevelopmentHarness>(); } } public Tuning Pitch(bool right) { if (!right) { return LeftMode; } return RightMode; } private void Died(CharacterBody b) { PresentationRagdoll.Release(b); pending.Clear(); CancelRoll("death"); CancelCharge(); } public int NextCast() { return ++Cast; } public bool InputAllowed() { if (!Object.op_Implicit((Object)(object)Body) || Body.allSkillsDisabled || !Object.op_Implicit((Object)(object)Body.healthComponent) || !Body.healthComponent.alive || !Object.op_Implicit((Object)(object)BodyMachine) || !(BodyMachine.state is TimpanistMain)) { return false; } if (Body.isPlayerControlled) { foreach (LocalUser readOnlyLocalUsers in LocalUserManager.readOnlyLocalUsersList) { if ((Object)(object)readOnlyLocalUsers.cachedBody == (Object)(object)Body) { return focus && !readOnlyLocalUsers.isUIFocused; } } } return true; } private void OnApplicationFocus(bool value) { focus = value; if (!value && Object.op_Implicit((Object)(object)Body) && Body.hasEffectiveAuthority) { CancelRoll("application focus"); CancelCharge(); } } private void Update() { if (Object.op_Implicit((Object)(object)Body) && Body.hasEffectiveAuthority && Object.op_Implicit((Object)(object)Body.inputBank)) { bool down = Body.inputBank.skill1.down; PrimaryPressed |= down && !oldPrimary; oldPrimary = down; if (!InputAllowed()) { PrimaryPressed = false; } } } private void FixedUpdate() { //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)Body) || !Object.op_Implicit((Object)(object)Body.skillLocator)) { return; } if (NetworkServer.active && chargeUntil > 0f && Time.fixedTime >= chargeUntil) { EndChargePoise(); } if (!InputAllowed()) { CancelRoll("body interruption"); CancelCharge(); } if ((Object)(object)Body.skillLocator.utility.skillDef != (Object)(object)Content.Charge) { CancelCharge(); } if (!NetworkServer.active) { return; } if (!Body.healthComponent.alive) { pending.Clear(); return; } for (int num = pending.Count - 1; num >= 0; num--) { PendingBeat pendingBeat = pending[num]; if (!(Time.fixedTime < pendingBeat.at)) { pending.RemoveAt(num); Vector3 origin = ((Object.op_Implicit((Object)(object)pendingBeat.target) && Object.op_Implicit((Object)(object)pendingBeat.target.body)) ? pendingBeat.target.body.corePosition : pendingBeat.point); Combat.Area(Body, origin, Vector3.forward, 5f, 180f, 1.8f, 0.35f, (DamageSource)4, pendingBeat.crit, stun: false, pendingBeat.hit, 100f); ImpactVisual.Emit(Body, origin, Vector3.forward, 5f, ImpactKind.Afterbeat); } } } public void QueueAfterbeat(HealthComponent target, Vector3 point, bool crit, HashSet<HealthComponent> shared) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) if (NetworkServer.active && pending.Count < 64) { pending.Add(new PendingBeat { target = target, point = point, crit = crit, at = Time.fixedTime + 0.32f, hit = shared }); ImpactVisual.Emit(Body, point, Vector3.forward, 1.5f, ImpactKind.ChargeContact); } } public void GrantPoise(float duration, bool charge = false) { if (NetworkServer.active) { chargeUntil = Time.fixedTime + duration; if (!Body.HasBuff(Content.Poise)) { Body.AddBuff(Content.Poise); } } } public void EndChargePoise() { if (NetworkServer.active && Object.op_Implicit((Object)(object)Body) && Object.op_Implicit((Object)(object)Content.Poise) && Body.HasBuff(Content.Poise)) { Body.RemoveBuff(Content.Poise); } chargeUntil = 0f; } public void CancelCharge() { if (Object.op_Implicit((Object)(object)Cavalry) && Cavalry.state is ChargeState && Body.hasEffectiveAuthority) { Cavalry.SetNextStateToMain(); } } public void CancelRoll(string why) { LastCancellation = why; if (Object.op_Implicit((Object)(object)Body) && Body.hasEffectiveAuthority && Object.op_Implicit((Object)(object)Weapon) && Weapon.state is RollState) { Weapon.SetNextStateToMain(); } VisualMask = 0; } public void Trace(string evt, string action, GenericSkill slot, float q, float coefficient, float proc, bool crit, int target = 0) { if (Plugin.Diagnostics.Value) { Plugin.Log($"TIMP event={evt} action={action} damage={coefficient:R} proc={proc:R} target={target}"); } } private void OnDestroy() { if (Object.op_Implicit((Object)(object)Body)) { CharacterBody body = Body; body.OnBodyDeath = (Action<CharacterBody>)Delegate.Remove(body.OnBodyDeath, new Action<CharacterBody>(Died)); } pending.Clear(); EndChargePoise(); } } public enum Tuning : byte { Low, Mid, High } public enum ActionKind : byte { None, Left, Right, Roll, Stop, TuneLeft, TuneRight } public static class Rules { public static float Speed(float a) { return Math.Max(0.1f, a); } public static float StrokeTime(float a) { return Math.Max(0.1f, 0.42f / Speed(a)); } public static Tuning Next(Tuning value) { return (Tuning)((int)(value + 1) % 3); } public static float Range(Tuning value) { return value switch { Tuning.Mid => 22, Tuning.Low => 10, _ => 40, }; } public static float Angle(Tuning value) { return value switch { Tuning.Mid => 40, Tuning.Low => 100, _ => 12, }; } public static float Damage(Tuning value) { return value switch { Tuning.Mid => 2.4f, Tuning.Low => 1.8f, _ => 3.2f, }; } public static bool Resonant(Tuning left, Tuning right) { if (left != Tuning.Mid || right != Tuning.Low) { if (left == Tuning.High) { return right == Tuning.Mid; } return false; } return true; } public static float RollBonus(byte mask, Tuning left, Tuning right) { if (mask != 3 || !Resonant(left, right)) { return 1f; } return 1.2f; } public static string Note(bool right, Tuning pitch) { if (!right) { return pitch switch { Tuning.Mid => "B", Tuning.Low => "G", _ => "D", }; } return pitch switch { Tuning.Mid => "D", Tuning.Low => "B", _ => "F", }; } public static float Contribution(byte mask, int side) { if ((mask & (1 << side)) != 0) { if (mask != 3) { return 1f; } return 0.5f; } return 0f; } } public static class CavalryRules { public const float StrikeDamage = 4f; public const float StrikeRange = 22f; public const float StrikeAngle = 38f; public const float RollDuration = 2f; public const float RollTick = 0.2f; public const float RollRange = 14f; public const float RollAngle = 50f; public const float ChargeDuration = 1f; public const float ChargeDamage = 3.5f; public const float AfterbeatDamage = 1.8f; public const float AfterbeatDelay = 0.32f; public const float AfterbeatRadius = 5f; public const float GrandDamage = 9f; public const float GrandRange = 25f; public const float GrandAngle = 55f; public static float StrikeDuration(float speed) { return Math.Max(0.16f, 0.62f / Rules.Speed(speed)); } public static float ContactTime(float speed) { return 0.12f / Rules.Speed(speed); } public static float ChargeSpeed(float walk, float age) { return Math.Max(1f, walk) * (2.5f + 0.5f * Math.Min(1f, Math.Max(0f, age) / 0.15f)); } public static float RollDamage(float speed) { return 0.24f * Rules.Speed(speed); } public static bool ChargeCancel(bool pressed, float age) { if (pressed) { return age >= 0.1f; } return false; } } public sealed class CustomPcmOutput : IDisposable { private sealed class LoopVoice { public Sample Sample; public Sample Wanted; public int Position; public float Envelope; public float Level; } private sealed class ClientState { public bool Active = true; public bool Audible; public bool PairWarning; public float TargetL; public float TargetR; public float CurrentL; public float CurrentR; public readonly int[,] Variant = new int[2, 3]; public readonly LoopVoice[] Loops = new LoopVoice[3] { new LoopVoice(), new LoopVoice(), new LoopVoice() }; } private sealed class StrikeVoice { public ClientState Owner; public Sample Sample; public int Position; public float Envelope; public float Level; public bool Stopping; } private sealed class Sample { public readonly float[] Data; public Sample(float[] data) { Data = data; } } private sealed class StrikeSet { public readonly Sample[] Variants; public StrikeSet(Sample[] variants) { Variants = variants; } } private sealed class Library { public readonly StrikeSet[,] Strikes = new StrikeSet[2, 3]; public readonly Sample[,] Rolls = new Sample[2, 3]; public readonly Sample[,] Pairs = new Sample[3, 3]; public long SourceBytes; public int DecodedSourceFrames; public int StrikeCount; public int IndividualRollCount; public int PairCount; private static readonly string[] tuning = new string[3] { "low", "mid", "high" }; public static Library Load(string directory) { Library library = new Library(); long sourceBytes = 0L; int decodedFrames = 0; int num = 0; int num2 = 0; for (int i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) { string text = ((i == 0) ? "left" : "right") + "-" + tuning[j]; library.Strikes[i, j] = new StrikeSet(new Sample[1] { Read(Path.Combine(directory, text + "-strike.wav"), loop: false, ref sourceBytes, ref decodedFrames) }); library.Rolls[i, j] = Read(Path.Combine(directory, text + "-roll.wav"), loop: true, ref sourceBytes, ref decodedFrames); } } for (int k = 0; k < 2; k++) { for (int l = 0; l < 3; l++) { string text2 = ((k == 0) ? "left" : "right") + "-" + tuning[l]; List<Sample> list = new List<Sample>(library.Strikes[k, l].Variants); for (int m = 2; m <= 6; m++) { Sample sample = Optional(Path.Combine(directory, text2 + "-strike-" + m.ToString("00") + ".wav"), loop: false, ref sourceBytes, ref decodedFrames); if (sample != null) { list.Add(sample); } } library.Strikes[k, l] = new StrikeSet(list.ToArray()); num2 += list.Count; } } for (int n = 0; n < 3; n++) { for (int num3 = 0; num3 < 3; num3++) { library.Pairs[n, num3] = Optional(Path.Combine(directory, "split-" + n + "-" + num3 + "-roll.wav"), loop: true, ref sourceBytes, ref decodedFrames); if (library.Pairs[n, num3] != null) { num++; } } } library.SourceBytes = sourceBytes; library.DecodedSourceFrames = decodedFrames; library.StrikeCount = num2; library.IndividualRollCount = 6; library.PairCount = num; Message("Loaded timpani PCM library once: " + num2 + " strike takes, 6 individual rolls, " + num + " paired rolls; " + sourceBytes + " WAV bytes."); return library; } private static Sample Optional(string path, bool loop, ref long sourceBytes, ref int decodedFrames) { if (!File.Exists(path)) { return null; } long num = sourceBytes; int num2 = decodedFrames; try { return Read(path, loop, ref sourceBytes, ref decodedFrames); } catch (Exception ex) { sourceBytes = num; decodedFrames = num2; Message("Optional timpani WAV skipped: " + Path.GetFileName(path) + ": " + ex.Message); return null; } } private static Sample Read(string path, bool loop, ref long sourceBytes, ref int decodedFrames) { FileInfo fileInfo = new FileInfo(path); if (!fileInfo.Exists) { throw new FileNotFoundException("Required timpani WAV missing", path); } if (fileInfo.Length < 44 || fileInfo.Length > 5242880 || (sourceBytes += fileInfo.Length) > 100663296) { throw new InvalidDataException("Audio library/file byte limit"); } int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; byte[] array = null; using (BinaryReader binaryReader = new BinaryReader(File.OpenRead(path))) { if (new string(binaryReader.ReadChars(4)) != "RIFF") { throw new InvalidDataException("Expected RIFF WAV: " + path); } uint num5 = binaryReader.ReadUInt32(); if (new string(binaryReader.ReadChars(4)) != "WAVE" || (long)num5 + 8L > binaryReader.BaseStream.Length) { throw new InvalidDataException("Invalid WAVE length"); } long num6 = (long)num5 + 8L; while (binaryReader.BaseStream.Position + 8 <= num6) { string text = new string(binaryReader.ReadChars(4)); uint num7 = binaryReader.ReadUInt32(); long num8 = binaryReader.BaseStream.Position + num7; if (num8 > num6 || num7 > 5242880) { throw new InvalidDataException("Invalid WAVE chunk"); } if (text == "fmt ") { if (num7 < 16) { throw new InvalidDataException("Short WAVE format"); } num4 = binaryReader.ReadUInt16(); num2 = binaryReader.ReadUInt16(); num = binaryReader.ReadInt32(); binaryReader.ReadInt32(); ushort num9 = binaryReader.ReadUInt16(); num3 = binaryReader.ReadUInt16(); if (num9 != num2 * 2) { throw new InvalidDataException("WAVE PCM block alignment"); } } else if (text == "data") { if (array != null) { throw new InvalidDataException("Multiple WAVE data chunks unsupported"); } array = binaryReader.ReadBytes((int)num7); if (array.Length != (int)num7) { throw new EndOfStreamException(); } } binaryReader.BaseStream.Position = num8 + (num7 & 1); } } if (num4 != 1 || (num2 != 1 && num2 != 2) || num3 != 16 || num < 8000 || num > 96000 || array == null || array.Length % (num2 * 2) != 0) { throw new InvalidDataException("Expected mono/stereo PCM16 WAV, 8-96kHz: " + path); } int num10 = array.Length / (num2 * 2); int num11 = (int)Math.Round((double)num10 * 48000.0 / (double)num); if (num11 < 2400 || num11 > 1152000 || (decodedFrames += num11) > 24000000) { throw new InvalidDataException("Audio duration/decoded-memory limit"); } float[] array2 = new float[num11]; for (int i = 0; i < num11; i++) { double num12 = (double)i * (double)num / 48000.0; int num13 = Math.Min(num10 - 1, (int)num12); int num14 = Math.Min(num10 - 1, num13 + 1); float num15 = (float)(num12 - (double)num13); float num16 = 0f; float num17 = 0f; for (int j = 0; j < num2; j++) { num16 += (float)BitConverter.ToInt16(array, (num13 * num2 + j) * 2) / 32768f; num17 += (float)BitConverter.ToInt16(array, (num14 * num2 + j) * 2) / 32768f; } array2[i] = (num16 + (num17 - num16) * num15) / (float)num2; } if (loop) { int num18 = Math.Min(240, num11 / 8); float[] array3 = new float[num11 - num18]; for (int k = 0; k < array3.Length; k++) { float num19 = ((k < num18) ? ((float)(0.5 - 0.5 * Math.Cos(Math.PI * (double)(k + 1) / (double)num18))) : 1f); array3[k] = ((k < num18) ? (array2[num11 - num18 + k] * (1f - num19) + array2[k] * num19) : array2[k]); } array2 = array3; } return new Sample(array2); } } private sealed class Engine { public readonly object Gate = new object(); public readonly Library Bank; public readonly StrikeVoice[] Strikes = new StrikeVoice[16]; private readonly ClientState[] clients = new ClientState[8]; private readonly NativeBuffer[] buffers = new NativeBuffer[3]; private readonly short[] output = new short[960]; public volatile bool Ready; public volatile bool Failed; public volatile bool Closing; public int ClientCount; public int CloseAfter; private Thread worker; private IntPtr device; public Engine(Library bank) { Bank = bank; for (int i = 0; i < Strikes.Length; i++) { Strikes[i] = new StrikeVoice(); } } public ClientState Add() { lock (Gate) { if (Closing || Failed) { return null; } for (int i = 0; i < clients.Length; i++) { if (clients[i] == null) { ClientState clientState = new ClientState(); clients[i] = clientState; ClientCount++; return clientState; } } return null; } } public void Start() { worker = new Thread(Work) { IsBackground = true, Name = "Timpanist PCM output" }; worker.Start(); } private void Work() { try { WaveFormat format = new WaveFormat { Format = 1, Channels = 2, SamplesPerSecond = 48000u, BytesPerSecond = 192000u, BlockAlign = 4, Bits = 16, ExtraSize = 0 }; Check(Native.waveOutOpen(out var intPtr, uint.MaxValue, ref format, UIntPtr.Zero, UIntPtr.Zero, 0u), "open"); device = intPtr; for (int i = 0; i < buffers.Length; i++) { buffers[i] = new NativeBuffer(); buffers[i].Prepare(device); } Ready = true; Message("Custom timpani WinMM PCM ready: 48 kHz stereo, three 10 ms buffers; owned volume/pan, independent of Wwise SFX bus."); int num = 0; while (true) { lock (Gate) { if (ClientCount == 0 && Environment.TickCount - CloseAfter >= 60) { Closing = true; break; } } NativeBuffer nativeBuffer = buffers[num]; if (!nativeBuffer.Submitted || nativeBuffer.Done) { lock (Gate) { Render(); } Marshal.Copy(output, 0, nativeBuffer.Data, output.Length); Check(Native.waveOutWrite(device, nativeBuffer.Header, (uint)NativeBuffer.HeaderSize), "write"); nativeBuffer.Submitted = true; num = (num + 1) % buffers.Length; } else { Thread.Sleep(2); } } } catch (Exception ex) { Failed = true; Closing = true; Message("Custom timpani PCM stopped: " + ex.GetType().Name + ": " + ex.Message); } finally { Ready = false; Closing = true; int num2 = 0; while (!Cleanup()) { if (num2 == 0) { Message("PCM cleanup retained native resources for retry; new output waits for successful cleanup."); } num2 = Math.Min(19, num2 + 1); Thread.Sleep(100 + num2 * 100); } lock (global) { if (shared == this) { shared = null; } } Message("Custom timpani PCM device and all native buffers closed."); } } private bool Cleanup() { NativeBuffer[] array; if (device != IntPtr.Zero) { uint num; try { num = Native.waveOutReset(device); } catch { return false; } if (num != 0) { return false; } array = buffers; foreach (NativeBuffer nativeBuffer in array) { if (nativeBuffer != null && !nativeBuffer.Unprepare(device)) { return false; } } try { if (Native.waveOutClose(device) != 0) { return false; } } catch { return false; } device = IntPtr.Zero; } array = buffers; for (int i = 0; i < array.Length; i++) { array[i]?.Free(); } return true; } private static float Move(float x, float target, float step) { if (!(x < target)) { return Math.Max(target, x - step); } return Math.Min(target, x + step); } private void Render() { for (int i = 0; i < 480; i++) { float num = 0f; float num2 = 0f; ClientState[] array = clients; foreach (ClientState clientState in array) { if (clientState == null) { continue; } clientState.CurrentL = Move(clientState.CurrentL, clientState.TargetL, 0.0013888889f); clientState.CurrentR = Move(clientState.CurrentR, clientState.TargetR, 0.0013888889f); LoopVoice[] loops = clientState.Loops; foreach (LoopVoice loopVoice in loops) { if (loopVoice.Sample == null && loopVoice.Wanted != null) { loopVoice.Sample = loopVoice.Wanted; loopVoice.Position = 0; } loopVoice.Envelope = Move(loopVoice.Envelope, (loopVoice.Sample != null && loopVoice.Sample == loopVoice.Wanted) ? loopVoice.Level : 0f, 0.0010416667f); if (loopVoice.Sample != null) { float num3 = loopVoice.Sample.Data[loopVoice.Position++] * loopVoice.Envelope; if (loopVoice.Position >= loopVoice.Sample.Data.Length) { loopVoice.Position = 0; } num += num3 * clientState.CurrentL; num2 += num3 * clientState.CurrentR; if (loopVoice.Envelope <= 0f && loopVoice.Sample != loopVoice.Wanted) { loopVoice.Sample = null; loopVoice.Position = 0; } } } } StrikeVoice[] strikes = Strikes; foreach (StrikeVoice strikeVoice in strikes) { ClientState owner = strikeVoice.Owner; if (owner != null) { strikeVoice.Envelope = Move(strikeVoice.Envelope, (!strikeVoice.Stopping) ? 1 : 0, 1f / (48000f * (strikeVoice.Stopping ? 0.01f : 0.002f))); int num4 = strikeVoice.Sample.Data.Length - strikeVoice.Position; float num5 = Math.Min(1f, (float)num4 / 240f); float num6 = strikeVoice.Sample.Data[strikeVoice.Position++] * strikeVoice.Level * strikeVoice.Envelope * num5; num += num6 * owner.CurrentL; num2 += num6 * owner.CurrentR; if (strikeVoice.Position >= strikeVoice.Sample.Data.Length || (strikeVoice.Stopping && strikeVoice.Envelope <= 0f)) { strikeVoice.Owner = null; strikeVoice.Sample = null; } } } output[i * 2] = (short)(Math.Tanh(num * 0.75f) * 32760.0); output[i * 2 + 1] = (short)(Math.Tanh(num2 * 0.75f) * 32760.0); } for (int l = 0; l < clients.Length; l++) { ClientState clientState2 = clients[l]; if (clientState2 == null || clientState2.Active || clientState2.CurrentL > 0f || clientState2.CurrentR > 0f) { continue; } bool flag = false; LoopVoice[] loops = clientState2.Loops; for (int j = 0; j < loops.Length; j++) { if (loops[j].Sample != null) { flag = true; break; } } if (!flag) { clients[l] = null; } } } private static void Check(uint result, string operation) { if (result != 0) { throw new InvalidOperationException("waveOut " + operation + " MMRESULT=" + result); } } } private struct WaveHeader { public IntPtr Data; public uint Length; public uint Recorded; public UIntPtr User; public uint Flags; public uint Loops; public IntPtr Next; public UIntPtr Reserved; } [StructLayout(LayoutKind.Sequential, Pack = 2)] private struct WaveFormat { public ushort Format; public ushort Channels; public uint SamplesPerSecond; public uint BytesPerSecond; public ushort BlockAlign; public ushort Bits; public ushort ExtraSize; } private sealed class NativeBuffer { public static readonly int HeaderSize = Marshal.SizeOf(typeof(WaveHeader)); private static readonly int FlagsOffset = (int)Marshal.OffsetOf(typeof(WaveHeader), "Flags"); public IntPtr Header; public IntPtr Data; public bool Submitted; private bool prepared; public bool Done => (Marshal.ReadInt32(Header, FlagsOffset) & 1) != 0; public void Prepare(IntPtr device) { Data = Marshal.AllocHGlobal(1920); Header = Marshal.AllocHGlobal(HeaderSize); Marshal.StructureToPtr(new WaveHeader { Data = Data, Length = 1920u }, Header, fDeleteOld: false); uint num = Native.waveOutPrepareHeader(device, Header, (uint)HeaderSize); if (num != 0) { throw new InvalidOperationException("waveOut prepare MMRESULT=" + num); } prepared = true; } public bool Unprepare(IntPtr device) { if (!prepared) { return true; } uint num; try { num = Native.waveOutUnprepareHeader(device, Header, (uint)HeaderSize); } catch { return false; } if (num != 0) { return false; } prepared = false; return true; } public void Free() { if (Header != IntPtr.Zero) { Marshal.FreeHGlobal(Header); Header = IntPtr.Zero; } if (Data != IntPtr.Zero) { Marshal.FreeHGlobal(Data); Data = IntPtr.Zero; } } } private static class Native { [DllImport("winmm.dll", ExactSpelling = true)] internal static extern uint waveOutOpen(out IntPtr output, uint device, ref WaveFormat format, UIntPtr callback, UIntPtr instance, uint flags); [DllImport("winmm.dll", ExactSpelling = true)] internal static extern uint waveOutPrepareHeader(IntPtr output, IntPtr header, uint bytes); [DllImport("winmm.dll", ExactSpelling = true)] internal static extern uint waveOutWrite(IntPtr output, IntPtr header, uint bytes); [DllImport("winmm.dll", ExactSpelling = true)] internal static extern uint waveOutReset(IntPtr output); [DllImport("winmm.dll", ExactSpelling = true)] internal static extern uint waveOutUnprepareHeader(IntPtr output, IntPtr header, uint bytes); [DllImport("winmm.dll", ExactSpelling = true)] internal static extern uint waveOutClose(IntPtr output); } private const int Rate = 48000; private const int Frames = 480; private const int BufferCount = 3; private const int MaxClients = 8; private const int MaxStrikes = 16; private const int MaxFileBytes = 5242880; private const int MaxLibraryBytes = 100663296; private const int MaxDecodedFrames = 24000000; private const int MaxSampleFrames = 1152000; private static readonly object global = new object(); private static readonly object messageGate = new object(); private static readonly Queue<string> messages = new Queue<string>(); private static Library library; private static Engine shared; private static bool unsupportedReported; private static long nextLibraryTry; private static string lastLibraryError; private readonly Engine engine; private readonly ClientState state; private readonly Action<string> logger; private bool disposed; public bool Available { get { if (!disposed && engine.Ready) { return !engine.Failed; } return false; } } private CustomPcmOutput(Engine e, ClientState s, Action<string> log) { engine = e; state = s; logger = log; } public static CustomPcmOutput TryCreate(string directory, Action<string> logger) { PumpMessages(logger); if (Environment.OSVersion.Platform != PlatformID.Win32NT) { if (!unsupportedReported) { unsupportedReported = true; Message("Custom timpani PCM requires Windows; no native explosion fallback."); PumpMessages(logger); } return null; } lock (global) { try { if (library == null) { if (DateTime.UtcNow.Ticks < nextLibraryTry) { return null; } try { library = Library.Load(directory); lastLibraryError = null; } catch (Exception ex) { nextLibraryTry = DateTime.UtcNow.AddSeconds(5.0).Ticks; string text = ex.GetType().Name + ": " + ex.Message; if (text != lastLibraryError) { Message("Custom timpani WAV library unavailable: " + text); lastLibraryError = text; } return null; } } if (shared != null && (shared.Closing || shared.Failed)) { return null; } bool flag = shared == null; if (flag) { shared = new Engine(library); } ClientState clientState = shared.Add(); if (clientState == null) { Message("Custom timpani client limit reached (8); this body remains silent."); return null; } CustomPcmOutput result = new CustomPcmOutput(shared, clientState, logger); if (flag) { try { shared.Start(); } catch { shared = null; throw; } } return result; } catch (Exception ex2) { Message("Custom timpani audio unavailable: " + ex2.GetType().Name + ": " + ex2.Message); return null; } } } public void PumpLogs() { PumpMessages(logger); } public static void PumpMessages(Action<string> logger) { if (logger == null) { return; } for (int i = 0; i < 16; i++) { string obj; lock (messageGate) { if (messages.Count == 0) { break; } obj = messages.Dequeue(); } try { logger(obj); } catch { } } } private static void Message(string text) { lock (messageGate) { if (messages.Count < 32) { messages.Enqueue(text); } } } private static float Clamp(float x, float a, float b) { if (!float.IsNaN(x) && !float.IsInfinity(x)) { return Math.Max(a, Math.Min(b, x)); } return a; } public void SetMix(float gain, float pan, bool audible, bool leftRoll, int leftTuning, bool rightRoll, int rightTuning, float rollGain) { if (disposed) { return; } lock (engine.Gate) { if (!state.Active) { return; } state.Audible = audible; gain = (audible ? Clamp(gain, 0f, 1f) : 0f); pan = Clamp(pan, -1f, 1f); state.TargetL = gain * (float)Math.Sqrt((double)(1f - pan) * 0.5); state.TargetR = gain * (float)Math.Sqrt((double)(1f + pan) * 0.5); int num = Math.Max(0, Math.Min(2, leftTuning)); int num2 = Math.Max(0, Math.Min(2, rightTuning)); Sample sample = ((leftRoll && rightRoll) ? engine.Bank.Pairs[num, num2] : null); if (audible && leftRoll && rightRoll && sample == null && !state.PairWarning) { state.PairWarning = true; Message("Paired roll WAV missing; mixing the two individual continuous roll recordings."); } state.Loops[0].Wanted = ((audible && leftRoll && sample == null) ? engine.Bank.Rolls[0, num] : null); state.Loops[1].Wanted = ((audible && rightRoll && sample == null) ? engine.Bank.Rolls[1, num2] : null); state.Loops[2].Wanted = (audible ? sample : null); LoopVoice[] loops = state.Loops; for (int i = 0; i < loops.Length; i++) { loops[i].Level = Clamp(rollGain, 0f, 1f); } if (audible) { return; } StrikeVoice[] strikes = engine.Strikes; foreach (StrikeVoice strikeVoice in strikes) { if (strikeVoice.Owner == state) { strikeVoice.Stopping = true; } } } } public void Strike(bool right, int tuning, float gain) { if (disposed) { return; } lock (engine.Gate) { if (!state.Active || !state.Audible || engine.Failed || engine.Closing) { return; } StrikeVoice strikeVoice = null; StrikeVoice[] strikes = engine.Strikes; foreach (StrikeVoice strikeVoice2 in strikes) { if (strikeVoice2.Owner == null) { strikeVoice = strikeVoice2; break; } } if (strikeVoice != null) { int num = (right ? 1 : 0); int num2 = Math.Max(0, Math.Min(2, tuning)); Sample[] variants = engine.Bank.Strikes[num, num2].Variants; int num3 = state.Variant[num, num2]; state.Variant[num, num2] = (num3 + 1) % variants.Length; strikeVoice.Owner = state; strikeVoice.Sample = variants[num3]; strikeVoice.Position = 0; strikeVoice.Level = Clamp(gain, 0f, 1f); strikeVoice.Envelope = 0f; strikeVoice.Stopping = false; } } } public void Dispose() { if (disposed) { return; } disposed = true; lock (engine.Gate) { if (!state.Active) { return; } state.Active = false; state.Audible = false; state.TargetL = (state.TargetR = 0f); LoopVoice[] loops = state.Loops; for (int i = 0; i < loops.Length; i++) { loops[i].Wanted = null; } StrikeVoice[] strikes = engine.Strikes; foreach (StrikeVoice strikeVoice in strikes) { if (strikeVoice.Owner == state) { strikeVoice.Stopping = true; } } engine.ClientCount--; if (engine.ClientCount == 0) { engine.CloseAfter = Environment.TickCount; } } } } public sealed class DevelopmentHarness : MonoBehaviour { [ConCommand(/*Could not decode attribute arguments.*/)] private static void Probe(ConCommandArgs args) { //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) CharacterBody senderBody = ((ConCommandArgs)(ref args)).senderBody; TimpanistController timpanistController = (Object.op_Implicit((Object)(object)senderBody) ? ((Component)senderBody).GetComponent<TimpanistController>() : null); if (!Object.op_Implicit((Object)(object)timpanistController)) { Plugin.Log("No Timpanist sender body"); return; } Plugin.Log($"TIMP 0.3.2 authority={senderBody.hasEffectiveAuthority} secondaryStock={senderBody.skillLocator.secondary.stock} rollMask={timpanistController.VisualMask} bodyState={((object)timpanistController.BodyMachine.state).GetType().Name} grounded={senderBody.characterMotor.isGrounded} position={((Component)senderBody).transform.position} foot={senderBody.footPosition}"); } } public static class DisplayRules { public static ItemDisplayRuleSet Mounted(ItemDisplayRuleSet source) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) ItemDisplayRuleSet val = ScriptableObject.CreateInstance<ItemDisplayRuleSet>(); ((Object)val).name = "TimpanistMountedDisplayRules"; if (!Object.op_Implicit((Object)(object)source) || source.keyAssetRuleGroups == null) { val.keyAssetRuleGroups = Array.Empty<KeyAssetRuleGroup>(); return val; } KeyAssetRuleGroup[] array = (KeyAssetRuleGroup[])source.keyAssetRuleGroups.Clone(); for (int i = 0; i < array.Length; i++) { DisplayRuleGroup displayRuleGroup = array[i].displayRuleGroup; if (displayRuleGroup.rules != null) { ItemDisplayRule[] array2 = (ItemDisplayRule[])displayRuleGroup.rules.Clone(); for (int j = 0; j < array2.Length; j++) { string text = (array2[j].childName ?? "").ToLowerInvariant(); bool flag = text.EndsWith("l") || text.Contains("left"); array2[j].childName = (text.Contains("head") ? "Head" : (text.Contains("chest") ? "Chest" : (text.Contains("neck") ? "Neck" : ((!text.Contains("upperarm") && !text.Contains("shoulder")) ? ((!text.Contains("arm") && !text.Contains("hand")) ? ((!text.Contains("thigh") && !text.Contains("calf") && !text.Contains("foot")) ? (text.Contains("pelvis") ? (flag ? "HipL" : "HipR") : "SaddleBack") : (flag ? "HorseFlankL" : "HorseFlankR")) : (flag ? "ForearmL" : "ForearmR")) : (flag ? "ShoulderL" : "ShoulderR"))))); array2[j].localPos = Vector3.ClampMagnitude(array2[j].localPos, 0.23f); } displayRuleGroup.rules = array2; array[i].displayRuleGroup = displayRuleGroup; } } val.keyAssetRuleGroups = array; return val; } } public sealed class DrumSurfaceVisual : MonoBehaviour { private CharacterModel model; private TimpanistController c; private readonly Material[] materials = (Material[])(object)new Material[2]; private readonly LineRenderer[] rings = (LineRenderer[])(object)new LineRenderer[2]; private readonly TrailRenderer[] trails = (TrailRenderer[])(object)new TrailRenderer[2]; private void Start() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) model = ((Component)this).GetComponentInParent<CharacterModel>(); if (!Object.op_Implicit((Object)(object)PressureVisual.Template)) { return; } Transform[] componentsInChildren = ((Component)this).GetComponentsInChildren<Transform>(); for (int i = 0; i < 2; i++) { materials[i] = PressureVisual.CreateMaterial(PressureVisual.ColorFor((i != 0) ? Tuning.High : Tuning.Low)); string text = ((i == 0) ? "L" : "R"); Transform val = null; Transform val2 = null; Transform[] array = componentsInChildren; foreach (Transform val3 in array) { if (((Object)val3).name == "Drum" + text) { val = val3; } if (((Object)val3).name == "Hand" + text) { val2 = val3; } } if (Object.op_Implicit((Object)(object)val)) { GameObject val4 = new GameObject("PitchRing" + text); val4.transform.SetParent(val, false); val4.transform.localPosition = Vector3.up * 0.012f; LineRenderer val5 = val4.AddComponent<LineRenderer>(); ((Renderer)val5).sharedMaterial = materials[i]; val5.useWorldSpace = false; val5.positionCount = 33; val5.widthMultiplier = 0.018f; float num = ((i == 0) ? 0.342f : 0.305f); for (int k = 0; k < 33; k++) { float num2 = (float)k * (float)Math.PI * 2f / 32f; val5.SetPosition(k, new Vector3(Mathf.Cos(num2) * num, 0f, Mathf.Sin(num2) * num)); } rings[i] = val5; } if (Object.op_Implicit((Object)(object)val2)) { GameObject val6 = new GameObject("MalletTrail" + text); val6.transform.SetParent(val2, false); val6.transform.localPosition = new Vector3((i == 0) ? (-0.04f) : 0.04f, -0.1f, 0.295f); TrailRenderer val7 = val6.AddComponent<TrailRenderer>(); ((Renderer)val7).sharedMaterial = materials[i]; val7.time = 0.1f; val7.startWidth = 0.028f; val7.endWidth = 0f; val7.minVertexDistance = 0.025f; val7.emitting = false; trails[i] = val7; } } } private void LateUpdate() { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)c) && Object.op_Implicit((Object)(object)model) && Object.op_Implicit((Object)(object)model.body)) { c = ((Component)model.body).GetComponent<TimpanistController>(); } for (int i = 0; i < 2; i++) { Color val = PressureVisual.ColorFor(Object.op_Implicit((Object)(object)c) ? c.Pitch(i == 1) : ((i != 0) ? Tuning.High : Tuning.Low)); bool flag = Object.op_Implicit((Object)(object)c) && c.Body.healthComponent.alive; float num = (Object.op_Implicit((Object)(object)c) ? Mathf.Clamp01(1f - (Time.time - ((i == 0) ? c.LeftFlash : c.RightFlash)) / 0.35f) : 0f); float num2 = ((flag && (c.VisualMask & (1 << i)) != 0) ? (0.65f + 0.2f * Mathf.Sin(Time.time * 24f)) : (0.12f + num * 0.8f)); val.a = (flag ? num2 : 0.12f); bool flag2 = Object.op_Implicit((Object)(object)c) && Time.time - c.GrandFlash < 0.55f; if (flag2) { val = Color.Lerp(val, Color.white, 0.35f + 0.2f * Mathf.Sin(Time.time * 7f)); } Material val2 = materials[i]; if (Object.op_Implicit((Object)(object)val2)) { if (val2.HasProperty("_Color")) { val2.SetColor("_Color", val); } if (val2.HasProperty("_EmColor")) { val2.SetColor("_EmColor", val); } if (val2.HasProperty("_EmPower")) { val2.SetFloat("_EmPower", flag2 ? 3f : (1f + num * 3f)); } } if (Object.op_Implicit((Object)(object)rings[i])) { LineRenderer obj = rings[i]; Color startColor = (rings[i].endColor = val); obj.startColor = startColor; rings[i].widthMultiplier = 0.035f + num * 0.06f; } if (Object.op_Implicit((Object)(object)trails[i])) { trails[i].emitting = flag && (c.VisualRolling || num > 0.1f); val.a = 0.65f; trails[i].startColor = val; val.a = 0f; trails[i].endColor = val; } } } private void OnDestroy() { Material[] array = materials; foreach (Material val in array) { if (Object.op_Implicit((Object)(object)val)) { Object.Destroy((Object)(object)val); } } } } public static class Graybox { public static readonly Color Green = Color32.op_Implicit(new Color32((byte)50, (byte)145, (byte)114, byte.MaxValue)); public static readonly Color Copper = Color32.op_Implicit(new Color32((byte)232, (byte)157, (byte)88, byte.MaxValue)); public static readonly Color Ivory = Color32.op_Implicit(new Color32(byte.MaxValue, (byte)238, (byte)200, byte.MaxValue)); public static readonly Color Metal = Color32.op_Implicit(new Color32((byte)142, (byte)173, (byte)186, byte.MaxValue)); public static readonly Color Bay = Color32.op_Implicit(new Color32((byte)124, (byte)78, (byte)51, byte.MaxValue)); public static readonly Color Black = Color32.op_Implicit(new Color32((byte)41, (byte)49, (byte)56, byte.MaxValue)); public static Material Material(Material template, Color color) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) Material val = (Object.op_Implicit((Object)(object)template) ? new Material(template) : new Material(Shader.Find("Standard"))); ((Object)val).name = "TimpanistGraybox_" + ColorUtility.ToHtmlStringRGB(color); if (val.HasProperty("_Color")) { val.SetColor("_Color", color); } if (val.HasProperty("_MainTex")) { val.SetTexture("_MainTex", (Texture)(object)Texture2D.whiteTexture); } if (val.HasProperty("_NormalTex")) { val.SetTexture("_NormalTex", (Texture)null); } if (val.HasProperty("_EmColor")) { val.SetColor("_EmColor", color * 0.3f); } if (val.HasProperty("_EmTex")) { val.SetTexture("_EmTex", (Texture)(object)Texture2D.whiteTexture); } if (val.HasProperty("_EmPower")) { val.SetFloat("_EmPower", 0.4f); } if (val.HasProperty("_SpecularStrength")) { val.SetFloat("_SpecularStrength", 0.3f); } if (val.HasProperty("_NormalStrength")) { val.SetFloat("_NormalStrength", 0f); } return val; } public static Transform Part(Transform parent, string name, PrimitiveType type, Vector3 position, Vector3 scale, Material mat) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) GameObject obj = GameObject.CreatePrimitive(type); ((Object)obj).name = name; obj.transform.SetParent(parent, false); obj.transform.localPosition = position; obj.transform.localScale = scale; Object.DestroyImmediate((Object)(object)obj.GetComponent<Collider>()); obj.GetComponent<Renderer>().sharedMaterial = mat; return obj.transform; } public static Sprite Icon(Color color) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false); for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { float num = Vector2.Distance(new Vector2((float)j, (float)i), new Vector2(31.5f, 31.5f)); val.SetPixel(j, i, (num > 29f) ? Color.clear : ((num > 23f) ? color : Ivory)); } } val.Apply(); return Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f)); } public static void BuildModel(GameObject body, Transform model, Material template) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Unknown result type (might be due to invalid IL or missing references) //IL_0322: Unknown result type (might be due to invalid IL or missing references) CharacterModel component = ((Component)model).GetComponent<CharacterModel>(); Renderer[] componentsInChildren = ((Component)model).GetComponentsInChildren<Renderer>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren[i]); } LODGroup[] componentsInChildren2 = ((Component)model).GetComponentsInChildren<LODGroup>(true); for (int i = 0; i < componentsInChildren2.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren2[i]); } HurtBox[] componentsInChildren3 = ((Component)model).GetComponentsInChildren<HurtBox>(true); for (int i = 0; i < componentsInChildren3.Length; i++) { ((Component)componentsInChildren3[i]).gameObject.SetActive(false); } model.localPosition = Vector3.zero; model.localScale = Vector3.one; Transform val = Content.Anchor(model, "TimpanistGraybox", Vector3.zero); bool flag = Presentation.TryBuild(val, template); if (!flag) { BuildVisual(val, template); } Renderer[] componentsInChildren4 = ((Component)val).GetComponentsInChildren<Renderer>(true); RendererInfo[] array = (RendererInfo[])(object)new RendererInfo[componentsInChildren4.Length]; for (int j = 0; j < array.Length; j++) { array[j] = new RendererInfo { renderer = componentsInChildren4[j], defaultMaterial = componentsInChildren4[j].sharedMaterial, defaultShadowCastingMode = (ShadowCastingMode)1, hideOnDeath = true }; } component.baseRendererInfos = array; component.baseLightInfos = Array.Empty<LightInfo>(); component.itemDisplayRuleSet = DisplayRules.Mounted(component.itemDisplayRuleSet); HurtBoxGroup component2 = ((Component)model).GetComponent<HurtBoxGroup>(); Transform obj = Content.Anchor(model, "TimpanistHurtCapsule", new Vector3(0f, 1.1f, 0f)); ((Component)obj).gameObject.layer = LayerIndex.entityPrecise.intVal; CapsuleCollider obj2 = ((Component)obj).gameObject.AddComponent<CapsuleCollider>(); obj2.radius = 0.48f; obj2.height = 2.2f; ((Collider)obj2).isTrigger = false; HurtBox val2 = ((Component)obj).gameObject.AddComponent<HurtBox>(); val2.healthComponent = body.GetComponent<HealthComponent>(); val2.isBullseye = true; val2.hurtBoxGroup = component2; val2.indexInGroup = 0; component2.hurtBoxes = (HurtBox[])(object)new HurtBox[1] { val2 }; component2.mainHurtBox = val2; component2.bullseyeCount = 1; SkinDef val3 = ScriptableObject.CreateInstance<SkinDef>(); ((Object)val3).name = "RodaniusTimpanistDefault"; val3.nameToken = "TIMPANIST_DEFAULT"; val3.rootObject = ((Component)model).gameObject; val3.icon = Icon(Copper); val3.baseSkins = Array.Empty<SkinDef>(); SkinDefParams val4 = ScriptableObject.CreateInstance<SkinDefParams>(); ((Object)val4).name = "RodaniusTimpanistDefaultParams"; val4.rendererInfos = array; val4.gameObjectActivations = Array.Empty<GameObjectActivation>(); val4.meshReplacements = Array.Empty<MeshReplacement>(); val4.projectileGhostReplacements = Array.Empty<ProjectileGhostReplacement>(); val4.minionSkinReplacements = Array.Empty<MinionSkinReplacement>(); val4.lightReplacements = Array.Empty<LightInfo>(); val3.skinDefParams = val4; val3.optimizedSkinDefParams = val4; (((Component)model).GetComponent<ModelSkinController>() ?? ((Component)model).gameObject.AddComponent<ModelSkinController>()).skins = (SkinDef[])(object)new SkinDef[1] { val3 }; if (!flag) { ((Component)val).gameObject.AddComponent<GrayboxMotion>(); } ChildLocator component3 = ((Component)model).GetComponent<ChildLocator>(); List<NameTransformPair> list = new List<NameTransformPair>(); Transform[] componentsInChildren5 = ((Component)val).GetComponentsInChildren<Transform>(); foreach (Transform val5 in componentsInChildren5) { list.Add(new NameTransformPair { name = ((Object)val5).name, transform = val5 }); } typeof(ChildLocator).GetField("transformPairs", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(component3, list.ToArray()); } public static void BuildVisual(Transform root, Material template) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_031f: Unknown result type (might be due to invalid IL or missing references) //IL_0333: Unknown result type (might be due to invalid IL or missing references) //IL_0355: Unknown result type (might be due to invalid IL or missing references) //IL_0369: Unknown result type (might be due to invalid IL or missing references) //IL_0383: Unknown result type (might be due to invalid IL or missing references) //IL_03a3: Unknown result type (might be due to invalid IL or missing references) //IL_03b7: Unknown result type (might be due to invalid IL or missing references) //IL_03da: Unknown result type (might be due to invalid IL or missing references) //IL_03ee: Unknown result type (might be due to invalid IL or missing references) //IL_0410: Unknown result type (might be due to invalid IL or missing references) //IL_0424: Unknown result type (might be due to invalid IL or missing references) //IL_0446: Unknown result type (might be due to invalid IL or missing references) //IL_045a: Unknown result type (might be due to invalid IL or missing references) //IL_047c: Unknown result type (might be due to invalid IL or missing references) //IL_0490: Unknown result type (might be due to invalid IL or missing references) //IL_04b3: Unknown result type (might be due to invalid IL or missing references) //IL_04c7: Unknown result type (might be due to invalid IL or missing references) //IL_04e9: Unknown result type (might be due to invalid IL or missing references) //IL_04fd: Unknown result type (might be due to invalid IL or missing references) //IL_051f: Unknown result type (might be due to invalid IL or missing references) //IL_0533: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02e1: Unknown result type (might be due to invalid IL or missing references) //IL_057b: Unknown result type (might be due to invalid IL or missing references) //IL_058f: Unknown result type (might be due to invalid IL or missing references) //IL_05aa: Unknown result type (might be due to invalid IL or missing references) //IL_05d5: Unknown result type (might be due to invalid IL or missing references) //IL_05e9: Unknown result type (might be due to invalid IL or missing references) //IL_0616: Unknown result type (might be due to invalid IL or missing references) //IL_062a: Unknown result type (might be due to invalid IL or missing references) //IL_0657: Unknown result type (might be due to invalid IL or missing references) //IL_066b: Unknown result type (might be due to invalid IL or missing references) //IL_0698: Unknown result type (might be due to invalid IL or missing references) //IL_06b2: Unknown result type (might be due to invalid IL or missing references) //IL_0a82: Unknown result type (might be due to invalid IL or missing references) //IL_0a6c: Unknown result type (might be due to invalid IL or missing references) //IL_0a56: Unknown result type (might be due to invalid IL or missing references) //IL_06f7: Unknown result type (might be due to invalid IL or missing references) //IL_0705: Unknown result type (might be due to invalid IL or missing references) //IL_072e: Unknown result type (might be due to invalid IL or missing references) //IL_0748: Unknown result type (might be due to invalid IL or missing references) //IL_0775: Unknown result type (might be due to invalid IL or missing references) //IL_0789: Unknown result type (might be due to invalid IL or missing references) //IL_07b6: Unknown result type (might be due to invalid IL or missing references) //IL_07ca: Unknown result type (might be due to invalid IL or missing references) //IL_07f6: Unknown result type (might be due to invalid IL or missing references) //IL_081a: Unknown result type (might be due to invalid IL or missing references) //IL_082e: Unknown result type (might be due to invalid IL or missing references) //IL_0853: Unknown result type (might be due to invalid IL or missing references) //IL_0867: Unknown result type (might be due to invalid IL or missing references) //IL_0893: Unknown result type (might be due to invalid IL or missing references) //IL_08a4: Unknown result type (might be due to invalid IL or missing references) //IL_08b8: Unknown result type (might be due to invalid IL or missing references) //IL_08e1: Unknown result type (might be due to invalid IL or missing references) //IL_08f5: Unknown result type (might be due to invalid IL or missing references) //IL_090f: Unknown result type (might be due to invalid IL or missing references) //IL_0935: Unknown result type (might be due to invalid IL or missing references) //IL_093a: Unknown result type (might be due to invalid IL or missing references) //IL_0944: Unknown result type (might be due to invalid IL or missing references) Material mat = Material(template, Bay); Material mat2 = Material(template, Black); Material mat3 = Material(template, Metal); Material mat4 = Material(template, Copper); Material mat5 = Material(template, Ivory); Material mat6 = Material(template, Green); Part(root, "HorseTorso", (PrimitiveT