diff --git a/cprev/Plugin.cs b/cprev/Plugin.cs index 9594592..f3a0544 100644 --- a/cprev/Plugin.cs +++ b/cprev/Plugin.cs @@ -18,6 +18,8 @@ void Start() { harmony = Harmony.CreateAndPatchAll(typeof(CpRev), "com.kirisoup.hff.cprev"); + if (onlyCoreModding) return; + if (timerLoaded) harmony.PatchAll(typeof(TimerInteg)); Cmds.RegCmds(); @@ -27,7 +29,7 @@ void Start() void OnGUI() { - if (!enabledCPR || !shouldWarnInvalid) return; + if (!enabledCPR || onlyCoreModding) return; if (!cpMissed) return; @@ -149,7 +151,7 @@ static class TimerInteg } public static bool enabledCPR = true; - public static bool shouldWarnInvalid = true; + public static bool onlyCoreModding = false; static bool cpMissed; static readonly bool timerLoaded = BepInEx.Bootstrap.Chainloader.PluginInfos.ContainsKey("com.plcc.hff.timer"); } diff --git a/reversed/Command.cs b/reversed/Command.cs index 8cef410..6adbf1d 100644 --- a/reversed/Command.cs +++ b/reversed/Command.cs @@ -19,7 +19,8 @@ public static void RegCmds() "Setting reversed% mode on/off", ""); - Soup.Regcmds.ToShell("rt", "", new Action(PlayerRt)); + Soup.Regcmds.ToShell("throw", "", new Action(ThrowPlayer)); + } @@ -33,7 +34,7 @@ public static bool SyntaxError(string error = null, bool badSyntax = true) { if (badSyntax) print("Command syntax error" + (error.IsNullOrWhiteSpace() ? null : ": " + error) + newline + - helpClr + Soup.Regcmds.description_["reversed"] + "" + helpClr + Soup.Regcmds.description_["reversedmode"] + "" ); return badSyntax; @@ -81,6 +82,11 @@ public static void Toggler(String param) case "query": case "q": break; + case "alwaysSpawnInside": case "asi": + alwaysSpawnInside = !alwaysSpawnInside; + print($"{helpClr}reversed% alwaysSpawnInside: " + alwaysSpawnInside + " <#ff0088>(Changed!)"); + break; + default: Cmds.SyntaxError("Unexpected parameters"); return; diff --git a/reversed/Plugin.cs b/reversed/Plugin.cs index d17b4a6..78d9cfb 100644 --- a/reversed/Plugin.cs +++ b/reversed/Plugin.cs @@ -1,10 +1,10 @@ using System; +using System.Reflection; using System.Collections.Generic; using BepInEx; using HarmonyLib; using HumanAPI; using Multiplayer; -using Timer; using UnityEngine; namespace reversed @@ -35,172 +35,419 @@ static void InvalidWarning(string warning, Vector2 pos) new() { fontSize = 30, normal = { textColor = Color.red } }); } - static LevelPassTrigger[] finishes; + static int hoverLayer = 8; + static int hoverLayerMask; + static readonly AccessTools.FieldRef velocities = AccessTools.FieldRefAccess(typeof(Human), "velocities"); - - static void PlayerRt() + void FixedUpdate() { - Ray.CollisionOverlapped(Human.Localplayer.GetComponent().bounds.center); - } + // if (Game.instance.currentCheckpointNumber != 0) return; - static class Ray - { - public static bool CollisionOverlapped(Vector2 pos) + foreach (NetPlayer player in NetGame.instance.players) { - RaycastHit[] hitsAbove = Physics.RaycastAll(pos, Vector3.up, float.MaxValue); + Vector3 pos = player.human.GetComponent().bounds.center; + float py = pos.y; + float vy = player.human.velocity.y; - bool hasCollisionAbove = false; - foreach (RaycastHit hit in hitsAbove) + if (Physics.Raycast(pos, Vector3.up, levelMaxY, hoverLayerMask)) { - if (hit.collider is null || hit.collider.isTrigger) continue; - hasCollisionAbove = true; break; - } + float acc = 0; - if (hasCollisionAbove) return true; + // stopping - RaycastHit[] hitsBellow = Physics.RaycastAll(pos, Vector3.down, float.MaxValue); + float h = Math.Abs(origFinishTopY - py); - bool hasCollisionBellow = false; + float tsqr = (float)Math.Pow(7.5, 2); - foreach (RaycastHit hit in hitsBellow) - { - if (hit.collider is null || hit.collider.isTrigger) continue; - hasCollisionBellow = true; break; - } + float dtsqr = (float)(h/tsqr); - return hasCollisionBellow; - } + float acc0 = (float)(dtsqr + Math.Sqrt(Math.Abs(Math.Pow(dtsqr, 2) - Math.Pow(vy, 2)/tsqr))); - // public static float FindUpLimit(Vector2 pos) - // { - - // } - } + // accent + float desiredVy = (float)Math.Sqrt(h * 19.62); + float acc1 = Math.Abs(vy)*2; + if (vy < -1) acc = acc0; + else acc = acc1; + // acc = acc0; + print($"d {h} vy {vy} desiredVy {desiredVy} vy < desiredVy {vy < desiredVy} acc {acc}"); - static void ModifyFinish(LevelPassTrigger finish) - { - if (finish is null || !finish.enabled) return; + if (vy < desiredVy) + + foreach (Rigidbody rigidbody in player.human.rigidbodies) + rigidbody.velocity += new Vector3(0, acc, 0); + + } - finish.gameObject.GetComponent().enabled = false; - Collider[] colliders = finish.gameObject.GetComponents(); - bool overlapped = Ray.CollisionOverlapped(finish.transform.position); - foreach (Collider collider in colliders) - { - if (!collider.enabled) continue; - - // collider.isTrigger = false; - if (overlapped) collider.enabled=false; } - if (overlapped) return; - WindEffector winde = finish.gameObject.AddComponent(); + + } - winde.ignoreParents = new Transform[] {finish.gameObject.transform}; + static void ThrowPlayer(string input = null) + { + if (!float.TryParse(input, out float height)) height = 100; - winde.humanFlyForce = 100; + float d = Mathf.Max(0, height - Human.Localplayer.GetComponent().bounds.center.y); - winde.applyAcceleration = false; + float b = 0.95f; + float g = Physics.gravity.y; - winde.cDamp = 0.02f; + // float wtf = (float)((4*Math.Pow(b,2) - 4*g*b + Math.Pow(g,2))/(b-0.5*g)); + float wtf = 1171/50; - winde.centerBend = 0; + // float desiredVy = (float)Math.Sqrt(-2 * Physics.gravity.y * d + 0.05 * Math.Pow(d, 2)); - winde.coefDrag = 0; + float desiredVy = (float)Math.Sqrt(d * wtf); - winde.distPower = 1; + // desiredVy * - winde.maxDist = 200; + SetHumanVY(desiredVy); - winde.respectArea = false; + } - winde.wind = new(0, 1, 0); + static void SetHumanVY(float vy) + { + Human human = NetGame.instance.players[0].human; - winde.enabled = true; + foreach (var item in Human.Localplayer.rigidbodies) + { + item.velocity = new(item.velocity.x, vy, item.velocity.z); + } + for (int i = 0; i < Human.Localplayer.rigidbodies.Length; i++ ) + { + velocities(human)[i] = new(velocities(human)[i].x, vy, velocities(human)[i].z); + } } static class Rev { + static WorkshopItemSource lvltype; + static int lvlnum; + + static bool redrock; + + static bool onLevelBegin = false; + [HarmonyPatch(typeof(Game), "AfterLoad")] [HarmonyPrefix] - static void AfterLoad() + static void PreAfterLoad() { - finishes = FindObjectsOfType(); + if (!enabledRev) return; - LevelPassTrigger finish = FindClosestFinish(finishes); + // init a list of endzones + origFinishes = FindObjectsOfType(); - if (finish is null) return; + if (origFinishes is null || origFinishes.Length == 0) return; - Vector3 finpos = finish.transform.position; - float finhight = finish.gameObject.transform.lossyScale.y/2; + // handles edge case where there are multiple endzones found from the level + origFinish = FindClosestFinish(origFinishes); + origFinishPos = origFinish.gameObject.GetComponent().bounds.center; + origSpawnPos = FindObjectOfType().checkpoints[0].position; + origFinish.gameObject.layer = hoverLayer; - CreateDummyFinish(FindObjectOfType().checkpoints[0].position, finish.gameObject); + hoverLayerMask = 1 << hoverLayer; - ModifyFinish(finish); + ReverseFinish(origSpawnPos); - ChangeSpawnTo(finpos, finhight); + ReverseSpawn(origFinishPos, origFinish.gameObject.GetComponent().bounds.extents.y); + + ModifyOldFinish(origFinish); + + onLevelBegin = true; + + lvltype = Game.instance.currentLevelType; + lvlnum = Game.instance.currentLevelNumber; } - } - static void CreateDummyFinish(Vector3 pos, GameObject src) - { - GameObject obj = GameObject.CreatePrimitive(PrimitiveType.Sphere); - obj.name = "revfinish"; - obj.SetActive(true); - obj.transform.SetParent(src.transform.parent, false); - obj.transform.localScale = Vector3.one * 8; - obj.transform.position = pos; - obj.GetComponent().isTrigger = true; - obj.AddComponent(); - obj.GetComponent().enabled = false; + [HarmonyPatch(typeof(Game), "AfterLoad")] + [HarmonyPostfix] + static void PostAfterLoad() => onLevelBegin = false; + + static bool executingSpawnAt = false; + + [HarmonyPatch(typeof(Human), "SpawnAt", new Type[] { typeof(Vector3) })] + [HarmonyPrefix] + static void PreSpawnAt(ref Vector3 pos) + { + spawnAtPos = pos; + executingSpawnAt = true; + } + + [HarmonyPatch(typeof(Human), "SpawnAt", new Type[] { typeof(Vector3) })] + [HarmonyPostfix] + static void PostSpawnAt() => executingSpawnAt = false; + + [HarmonyPatch(typeof(Human), "SetPosition")] + [HarmonyPrefix] + static void SetPosition(ref Vector3 spawnPos) + { + if (!enabledRev) return; + if (!executingSpawnAt) return; + if (Game.instance.currentCheckpointNumber != 0) return; + + redrock = lvltype == WorkshopItemSource.EditorPick && lvlnum == 7; + + bool alwaysSpawnInside = !redrock && Plugin.alwaysSpawnInside; + + if (!onLevelBegin && !alwaysSpawnInside) return; + + float? yCap = FindYCap() - uniRadius/2; + + if (yCap is null) return; + + if (spawnPos.y <= yCap) return; + + spawnPos.y = (float)yCap; + + float vcap = - (spawnPos.y - spawnAtPos.y)/2 - Physics.gravity.y; + float vori = Human.instance.velocity.y; + + print($"vcap {vcap}"); + + foreach (Rigidbody rigidbody in Human.instance.rigidbodies) + rigidbody.velocity += new Vector3(0, vcap - vori, 0); + + print($"Human.instance.velocity {Human.instance.velocity}"); + } } - static LevelPassTrigger FindClosestFinish(LevelPassTrigger[] finishes) + static LevelPassTrigger FindClosestFinish(LevelPassTrigger[] origFinishes) { Transform lastcp = Game.currentLevel.GetCheckpointTransform(Game.currentLevel.checkpoints.Length - 1); float closestDist = float.MaxValue; LevelPassTrigger closestFinish = null; - foreach (LevelPassTrigger finish in finishes) + foreach (LevelPassTrigger origFinish in origFinishes) { - print("found endzone"); - - float distance = Vector3.Distance(finish.transform.position, lastcp.position); + float distance = Vector3.Distance(origFinish.transform.position, lastcp.position); if (distance >= closestDist) continue; - print($"selected endzone with distance to endcp {distance}"); - closestDist = distance; - closestFinish = finish; + closestFinish = origFinish; } return closestFinish; } - static void ChangeSpawnTo(Vector3 finpos, float finhight) => FindObjectOfType().checkpoints[0].position = new(finpos.x, finpos.y + finhight, finpos.z); + static void ReverseFinish(Vector3 pos) + { + GameObject revFinish = GameObject.CreatePrimitive(PrimitiveType.Sphere); + revFinish.name = "revfinish"; + revFinish.SetActive(true); + revFinish.transform.SetParent(Game.currentLevel.gameObject.transform, false); + revFinish.transform.localScale = Vector3.one * uniRadius *2; + revFinish.GetComponent().isTrigger = true; + revFinish.AddComponent(); + if (debug) Soup.ObjMajic.ShadePureColor(revFinish.GetComponent(), new(0, 1, 0, 0.33f)); + else revFinish.GetComponent().enabled = false; + + Vector3? surfacingPos = Clipped(pos); + bool overlapped = surfacingPos is not null; + + Vector3? landingPos = Floating(pos); + bool floating = landingPos is not null; + + // Handles spawnpoint underground or floating in midair: + + // if upper half of the reversed spawn is clipping inside a collider, set its pos to the highest surface above it + if (overlapped) revFinish.transform.position = (Vector3)surfacingPos; + + // else, if the reversed spawn is floating (and there is no collider above it), set its pos to the surface + else if (floating) revFinish.transform.position = (Vector3)landingPos; + + else revFinish.transform.position = pos; + } + + static Vector3? Clipped(Vector3 point) + { + RaycastHit[] overlapped = FindClipped(point + Vector3.up * uniRadius/2, uniRadius/2); + + // only continue if any colliders overlaps with upper half of the reversed spawn + if (overlapped is null) return null; + + if (debug) Soup.ObjMajic.CreateDummySphere("Clipped", uniRadius, point, new Color(1, 0, 0, 0.33f)); + + + RaycastHit? hit = Soup.XrayHax.RayhitFirstSolid(OverrideY(point, levelMaxY), Vector3.down, float.PositiveInfinity, sels: overlapped); + + // return the highest point from overlapping colliders + return hit != null ? ((RaycastHit)hit).point : null; + } + + static RaycastHit[] FindClipped(Vector3 point, float radius = 0) + { + RaycastHit[] candidates = Soup.XrayHax.RayhitAllSolid(OverrideY(point, levelMaxY), Vector3.down, float.PositiveInfinity); + + if (debug) Soup.ObjMajic.CreateDummySphere("Clip Check", radius, point, Color.magenta); + + // only continue if any colliders found on the xz coord of the point + if (candidates is null || candidates.Length == 0) return null; + + List overlapped = new(); + + foreach (RaycastHit hit in candidates) + if (Vector3.Distance(hit.collider.ClosestPoint(point), point) < radius) overlapped.Add(hit); + + return overlapped.ToArray(); + } + + // assumes not overlapped + static Vector3? Floating(Vector3 point) + { + bool noColliderAbove = Soup.XrayHax.RayhitFirstSolid(point + Vector3.up * (uniRadius/2), Vector3.up, float.PositiveInfinity) is null; + + // only continue if no collider found from above + if (!noColliderAbove) return null; + + RaycastHit? hit = Soup.XrayHax.RayhitFirstSolid(point, Vector3.down, float.PositiveInfinity); + + // return first hit position downwards (null if nothing found) + return hit != null ? ((RaycastHit)hit).point : null; + } - static class Storage + static void ModifyOldFinish(LevelPassTrigger origFinish) { - class Endzone + if (origFinish is null || !origFinish.enabled) return; + + origFinish.gameObject.GetComponent().enabled = false; + + Collider[] colliders = origFinish.gameObject.GetComponents(); + + RaycastHit? hit = Soup.XrayHax.RayhitFirstSolid(origFinishPos, Vector3.down, float.PositiveInfinity); + + bool overlappedBellow = hit is not null; + + foreach (Collider collider in colliders) { + if (!collider.enabled) continue; + + collider.isTrigger = false; + // if (overlappedBellow) + // collider.enabled=false; + + // Bounds bounds = collider.bounds; + + // collider.transform.localScale = new Vector3(bounds.size.x + uniRadius, bounds.size.y + uniRadius, bounds.size.z + uniRadius); } } + static void ReverseSpawn(Vector3 finpos, float finhight) + { + Vector3 revSpawnPos = new(finpos.x, finpos.y + finhight, finpos.z); + + origFinishTopY = finpos.y + finhight; + + FindObjectOfType().checkpoints[0].position = revSpawnPos; + } + + static float? FindYCap() + { + if (debug) + { + Soup.ObjMajic.CreateDummySphere("dropStart", safeZone, spawnAtPos + Vector3.up * dropDist, new(0, 1, 1, 0.5f)); + + Soup.ObjMajic.CreateDummySphere("revspawn", 0.5f, spawnAtPos, new(1, 1, 0, 1f)); + + Soup.ObjMajic.DrawLine(OverrideY(spawnAtPos, levelMaxY), spawnAtPos, Color.black); + } + + // Ray above + Vector3 rayAStart = OverrideY(spawnAtPos, levelMaxY); + Vector3 rayAEnds = spawnAtPos + Vector3.up * (dropDist + safeZone); + + RaycastHit[] hitsA = Soup.XrayHax.RayhitAllSolid(rayAStart, rayAEnds); + + if (hitsA is null || hitsA.Length == 0) + { + if (debug) Soup.ObjMajic.DrawLine(rayAStart, rayAEnds, Color.yellow, Vector3.forward * 0.1f); + return null; + } + + if (debug) + { + Soup.ObjMajic.DrawBlockedLine(rayAStart, hitsA[0].point, rayAEnds, Color.yellow, Vector3.forward * 0.1f); + + foreach (RaycastHit hit in hitsA) Soup.ObjMajic.ShadePureColor(hit.transform.gameObject.GetComponent(), new Color(1, 0, 0.5f, 0.75f)); + } + + // ray ignore + Vector3 rayIStart = spawnAtPos + Vector3.up * (dropDist + safeZone); + Vector3 rayIEnds = spawnAtPos + Vector3.up * safeZone; + + RaycastHit[] hitsI = Soup.XrayHax.RayhitAllSolid(rayIStart, rayIEnds); + + if (hitsI is null || hitsI.Length == 0) + { + if (debug) Soup.ObjMajic.DrawLine(rayIStart, rayIEnds, new(1, 0, 0.5f), Vector3.forward * 0.2f); + hitsI = new RaycastHit[0]; + } + + else if (debug) + { + Soup.ObjMajic.DrawBlockedLine(rayIStart, hitsI[0].point, rayIEnds, new(1, 0, 0.5f), Vector3.forward * 0.2f); + + foreach (RaycastHit hit in hitsI) Soup.ObjMajic.ShadePureColor(hit.transform.gameObject.GetComponent(), new Color(1, 1, 1, 0.5f)); + } + + // ray below + Vector3 rayBStart = spawnAtPos + Vector3.up * safeZone; + Vector3 rayBEnds = OverrideY(spawnAtPos, levelMaxY); + + RaycastHit hitB; + RaycastHit? ihitB = Soup.XrayHax.RayhitFirstSolid(rayBStart, rayBEnds, igns: hitsI); + + if (ihitB is null) + { + if (debug) Soup.ObjMajic.DrawLine(rayBStart, rayBEnds, Color.cyan, Vector3.forward * 0.3f); + return null; + } + + hitB = (RaycastHit)ihitB; + + if (debug) Soup.ObjMajic.DrawBlockedLine(rayBStart, hitB.point, rayBEnds, Color.yellow, Vector3.forward * 0.3f); + + return hitB.point.y; + } + + static LevelPassTrigger[] origFinishes; + static LevelPassTrigger origFinish; + static Vector3 origFinishPos; + static float origFinishTopY; + static Vector3 origSpawnPos; + static Vector3 spawnAtPos; + + static Vector3 OverrideY(Vector3 original, float y) => new(original.x, y, original.z); + static Vector3 OverrideY(Vector3 original, Vector3 y) => new(original.x, y.y, original.z); + + static readonly float uniRadius = 1.5f; + + static readonly float levelMaxY = 4000; + + static readonly float safeZone = uniRadius; + + static readonly float dropDist = -Physics.gravity.y * 2; + public static bool enabledRev = true; + + public static bool alwaysSpawnInside = true; + + static readonly bool debug = true; + static readonly bool timerLoaded = BepInEx.Bootstrap.Chainloader.PluginInfos.ContainsKey("com.plcc.hff.timer"); } } \ No newline at end of file diff --git a/reversed/SouperPower/XrayHax.cs b/reversed/SouperPower/XrayHax.cs new file mode 100644 index 0000000..bf9925b --- /dev/null +++ b/reversed/SouperPower/XrayHax.cs @@ -0,0 +1,86 @@ +using System.Linq; +using System.Collections.Generic; +using UnityEngine; + + +public partial class Soup +{ + public static class XrayHax + { + public static RaycastHit? RayhitFirstSolid(Vector3 start, Vector3 end, RaycastHit[] sels = null, RaycastHit[] igns = null) => + RayhitFirstSolid(start, (end - start).normalized, Vector3.Distance(start, end), sels, igns); + + public static RaycastHit? RayhitFirstSolid(Vector3 pos, Vector3 dir, float dist, RaycastHit[] sels = null, RaycastHit[] igns = null) + { + sels ??= new RaycastHit[0]; + igns ??= new RaycastHit[0]; + + string[] selsName = new string[sels.Length]; + string[] ignsName = new string[igns.Length]; + + for (int i = 0; i < sels.Length; i++) + selsName[i] = sels[i].transform.gameObject.name; + + for (int i = 0; i < igns.Length; i++) + ignsName[i] = igns[i].transform.gameObject.name; + + RaycastHit[] hits = Xray(pos, dir, dist); + + if (hits is null) return null; + + foreach (RaycastHit hit in hits) + if(CandidateMatch(hit, selsName, ignsName)) return hit; + + return null; + } + + + public static RaycastHit[] RayhitAllSolid(Vector3 start, Vector3 end, RaycastHit[] sels = null, RaycastHit[] igns = null) => + RayhitAllSolid(start, (end - start).normalized, Vector3.Distance(start, end), sels, igns); + + public static RaycastHit[] RayhitAllSolid(Vector3 pos, Vector3 dir, float dist, RaycastHit[] sels = null, RaycastHit[] igns = null) + { + sels ??= new RaycastHit[0]; + igns ??= new RaycastHit[0]; + + string[] selsName = new string[sels.Length]; + string[] ignsName = new string[igns.Length]; + + for (int i = 0; i < sels.Length; i++) + selsName[i] = sels[i].transform.gameObject.name; + + for (int i = 0; i < igns.Length; i++) + ignsName[i] = igns[i].transform.gameObject.name; + + RaycastHit[] hits = Xray(pos, dir, dist); + + if (hits is null) return null; + + List validhits = new(); + + foreach (RaycastHit hit in hits) + if(CandidateMatch(hit, selsName, ignsName)) validhits.Add(hit); + + return validhits.ToArray(); + } + + public static bool CandidateMatch(RaycastHit hit, string[] selsName, string[] ignsName) + { + if (hit.collider.isTrigger) + return false; + if (hit.transform.GetComponentInParent()) + return false; + if (hit.rigidbody) + return false; + if (selsName.Length != 0 && !selsName.Contains(hit.transform.gameObject.name)) + return false; + if (ignsName.Length != 0 && ignsName.Contains(hit.transform.gameObject.name)) + return false; + + return true; + } + + public static RaycastHit[] Xray(Vector3 pos, Vector3 dir, float dist) => Physics.RaycastAll(pos, dir, dist, 0b111111111100011111111110101); + + } +} \ No newline at end of file diff --git a/reversed/SouperPower/objmagic.cs b/reversed/SouperPower/objmagic.cs new file mode 100644 index 0000000..3b39d86 --- /dev/null +++ b/reversed/SouperPower/objmagic.cs @@ -0,0 +1,64 @@ +using UnityEngine; +using UnityEngine.Rendering; + +public partial class Soup +{ + public class ObjMajic + { + public static void DrawBlockedLine(Vector3 start, Vector3 hit, Vector3 end, Color color, Vector3 disp = new(), float width = 0.02f) + { + DrawLine(start, hit, color, disp, width); + // Color blockedColor = new(1 - color.r, 1 - color.g, 1 - color.b, color.a/4); + Color blockedColor = Color.red; + DrawLine(hit, end, blockedColor, disp, width); + } + + public static void DrawLine(Vector3 start, Vector3 end, Color color, Vector3 disp = new(), float width = 0.02f) + { + GameObject line = new("ray"); + line.transform.SetParent(Game.currentLevel.gameObject.transform); + LineRenderer render = line.AddComponent(); + render.startWidth = width; + render.endWidth = width; + render.positionCount = 2; + render.SetPosition(0, start + disp); + render.SetPosition(1, end + disp); + Material material = render.material ?? new Material(Shader.Find("Standard")); + MakeTransluscent(material); + material.renderQueue = 3001; + render.material.color = color; + } + + public static void ShadePureColor(Renderer render, Color color) + { + Material material = render.material ?? new Material(Shader.Find("Standard")); + MakeTransluscent(material); + material.color = color; + } + + public static void CreateDummySphere(string name, float radius, Vector3 pos, Color color) + { + GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere); + sphere.name = name; + sphere.SetActive(true); + sphere.transform.SetParent(Game.currentLevel.gameObject.transform, false); + sphere.transform.localScale = Vector3.one * radius * 2; + sphere.transform.position = pos; + sphere.GetComponent().isTrigger = true; + ShadePureColor(sphere.GetComponent(), color); + } + + public static void MakeTransluscent(Material material) + { + material.shader = Shader.Find("Standard"); + material.SetFloat("_Mode", 2); + material.SetInt("_SrcBlend", (int)BlendMode.SrcAlpha); + material.SetInt("_DstBlend", (int)BlendMode.OneMinusSrcAlpha); + material.SetInt("_ZWrite", 0); + material.DisableKeyword("_ALPHATEST_ON"); + material.EnableKeyword("_ALPHABLEND_ON"); + material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); + material.renderQueue = 3000; + } + } +} \ No newline at end of file diff --git a/reversed/res/cprev.dll b/reversed/res/cprev.dll new file mode 100644 index 0000000..edb21b9 Binary files /dev/null and b/reversed/res/cprev.dll differ diff --git a/reversed/reversed.csproj b/reversed/reversed.csproj index 3aff82e..32360b3 100644 --- a/reversed/reversed.csproj +++ b/reversed/reversed.csproj @@ -26,6 +26,7 @@ ref\HumanMod.dll +