diff --git a/Attributes/InternalCEEvent.cs b/Attributes/InternalCEEventAttribute.cs similarity index 81% rename from Attributes/InternalCEEvent.cs rename to Attributes/InternalCEEventAttribute.cs index 6de686b..8d3bf4a 100644 --- a/Attributes/InternalCEEvent.cs +++ b/Attributes/InternalCEEventAttribute.cs @@ -9,7 +9,7 @@ namespace RainWorldCE.Attributes /// These events should never be randomly rolled /// [AttributeUsage(AttributeTargets.Class)] - internal class InternalCEEvent : System.Attribute + internal class InternalCEEventAttribute : System.Attribute { } } diff --git a/Attributes/MSCEvent.cs b/Attributes/MSCEventAttribute.cs similarity index 84% rename from Attributes/MSCEvent.cs rename to Attributes/MSCEventAttribute.cs index bfbd403..9eafb31 100644 --- a/Attributes/MSCEvent.cs +++ b/Attributes/MSCEventAttribute.cs @@ -10,7 +10,7 @@ namespace RainWorldCE.Attributes /// These events only work with MSC enabled /// [AttributeUsage(AttributeTargets.Class)] - internal class MSCEvent : System.Attribute + internal class MSCEventAttribute : System.Attribute { } } diff --git a/Docs/CustomChaos.md b/Docs/CustomChaos.md index 051c45e..a15bcff 100644 --- a/Docs/CustomChaos.md +++ b/Docs/CustomChaos.md @@ -16,9 +16,10 @@ In the Remix options one of the lines shows up as ERROR: You have entered an invalid command in that line (WAIT without time, Non existing event name etc.) This line will do nothing and you should fix it Internal event names to be used in scripts: +Challenger - Challenger CreatureMigration - Coming through CreatureRandomizer - DNA Mutations -Darkness - Darkness / Shaded Region +Darkness - Darkness / Shaded Region FlipCamera - Camera issues FoodLevel - Digestive reordering Friend - The Friend @@ -30,13 +31,16 @@ InvertControls - Directional confusion KarmaLevel - Karma shuffle LiftOff - Lift off LizardPack - The pack +LooseGrasp - Hot Potatoes LowGravity - Low gravity +Melting - Extreme Heat MovementTime - Super Slugcat NoodleInvasion - Noodle invasion PaletteRandomizer - Too many mushrooms +Pixelize - Retro RainbowCat - Rainbow Cat RainyDay - Rainy day -RandomLorePearl - A piece of history +RandomLorePearl - A piece of history RandomSong - Jukebox Hero Rifle - Free gun RoomConnectionShuffle - Geographic issues diff --git a/Events/Challenger.cs b/Events/Challenger.cs new file mode 100644 index 0000000..b138d8f --- /dev/null +++ b/Events/Challenger.cs @@ -0,0 +1,192 @@ +using BepInEx.Logging; +using IL.LizardCosmetics; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace RainWorldCE.Events +{ + internal class Challenger : CEEvent + { + /// + /// Spawns a random enemy + /// + public Challenger() + { + _name = "Challenger"; + _description = "A new foe has appeared"; + } + + public override void StartupTrigger() + { + CreatureTemplate.Type creatureType = RandomCreature(EventHelpers.CurrentRoom.AnySkyAccess); + WriteLog(LogLevel.Debug, $"Spawning: {creatureType}"); + List adjacendRooms = EventHelpers.GetConnectedRooms(EventHelpers.CurrentRoom); + AbstractRoom sourceRoom = adjacendRooms[rnd.Next(adjacendRooms.Count)]; + int destRoomNodeId = EventHelpers.GetNodeIdOfRoomConnection(sourceRoom, EventHelpers.CurrentRoom); + if (creatureType == CreatureTemplate.Type.Vulture || creatureType == MoreSlugcats.MoreSlugcatsEnums.CreatureTemplateType.MirosVulture) + { + sourceRoom = game.world.offScreenDen; + for (int i = 0; i < EventHelpers.CurrentRoom.realizedRoom.borderExits.Length; i++) + { + if (!(EventHelpers.CurrentRoom.realizedRoom.borderExits[i].type == AbstractRoomNode.Type.SkyExit)) + { + continue; + } + destRoomNodeId = i + EventHelpers.CurrentRoom.realizedRoom.exitAndDenIndex.Length; + } + } + int amt = 1; + if (creatureType == CreatureTemplate.Type.Spider) + amt = 16; + for (int i = 0; i < amt; i++) + { + AbstractCreature creature = new AbstractCreature(game.world, StaticWorld.GetCreatureTemplate(creatureType), null, new WorldCoordinate(sourceRoom.index, -1, -1, 0), game.GetNewID()); + if (creatureType == CreatureTemplate.Type.Centipede) + { + creature.spawnData = $"{{{UnityEngine.Random.Range(0.6f, 1.0f)}}}"; + } + EventHelpers.MakeCreatureAttackCreature(creature, EventHelpers.MainPlayer); + creature.ChangeRooms(new WorldCoordinate(EventHelpers.CurrentRoom.index, -1, -1, destRoomNodeId)); + WriteLog(LogLevel.Debug, $"Spawned: {creature}"); + if (creatureType == MoreSlugcats.MoreSlugcatsEnums.CreatureTemplateType.Inspector) + { + creature.abstractAI.RealAI.preyTracker.AddPrey(creature.abstractAI.RealAI.tracker.RepresentationForCreature(EventHelpers.MainPlayer, true)); + (creature.realizedCreature as MoreSlugcats.Inspector).anger = 1.0f; + } + } + } + + public static CreatureTemplate.Type RandomCreature(bool allowFlying = false) + { + int ran = rnd.Next(111); + if (rnd.Next(100) > 50) + { + if (ModManager.MSC) + { + switch (ran) + { + case < 10: + return CreatureTemplate.Type.GreenLizard; + case < 20: + return MoreSlugcats.MoreSlugcatsEnums.CreatureTemplateType.EelLizard; + case < 30: + return CreatureTemplate.Type.PinkLizard; + case < 40: + return MoreSlugcats.MoreSlugcatsEnums.CreatureTemplateType.SpitLizard; + case < 50: + return MoreSlugcats.MoreSlugcatsEnums.CreatureTemplateType.ZoopLizard; + case < 60: + return CreatureTemplate.Type.BlueLizard; + case < 70: + return CreatureTemplate.Type.WhiteLizard; + case < 80: + return CreatureTemplate.Type.YellowLizard; + case < 90: + return CreatureTemplate.Type.Salamander; + case < 99: + return CreatureTemplate.Type.BlackLizard; + case < 105: + return CreatureTemplate.Type.CyanLizard; + case < 198: + return CreatureTemplate.Type.RedLizard; + case >= 109: + return MoreSlugcats.MoreSlugcatsEnums.CreatureTemplateType.TrainLizard; + + } + } + else + { + switch (ran) + { + case < 20: + return CreatureTemplate.Type.GreenLizard; + case < 40: + return CreatureTemplate.Type.PinkLizard; + case < 60: + return CreatureTemplate.Type.BlueLizard; + case < 70: + return CreatureTemplate.Type.WhiteLizard; + case < 80: + return CreatureTemplate.Type.YellowLizard; + case < 90: + return CreatureTemplate.Type.Salamander; + case < 99: + return CreatureTemplate.Type.BlackLizard; + case < 107: + return CreatureTemplate.Type.CyanLizard; + case >= 107: + return CreatureTemplate.Type.RedLizard; + } + } + + } + else + { + ran = rnd.Next(120); + if (ModManager.MSC) + { + switch (ran) + { + case < 15: + return CreatureTemplate.Type.Centipede; + case < 30: + return CreatureTemplate.Type.BigSpider; + case < 40: + return MoreSlugcats.MoreSlugcatsEnums.CreatureTemplateType.MotherSpider; + case < 50: + if (allowFlying) return CreatureTemplate.Type.Vulture; + else return RandomCreature(); + case < 60: + return CreatureTemplate.Type.Spider; + case < 70: + return CreatureTemplate.Type.SpitterSpider; + case < 80: + return CreatureTemplate.Type.Centiwing; + case < 87: + return MoreSlugcats.MoreSlugcatsEnums.CreatureTemplateType.ScavengerElite; + case < 95: + return MoreSlugcats.MoreSlugcatsEnums.CreatureTemplateType.FireBug; + case < 101: + return MoreSlugcats.MoreSlugcatsEnums.CreatureTemplateType.Inspector; + case < 108: + return CreatureTemplate.Type.MirosBird; + case < 114: + if (allowFlying) return MoreSlugcats.MoreSlugcatsEnums.CreatureTemplateType.MirosVulture; + else return RandomCreature(); + case >= 114: + return CreatureTemplate.Type.RedCentipede; + + } + } + else + { + switch (ran) + { + case < 20: + return CreatureTemplate.Type.Centipede; + case < 40: + return CreatureTemplate.Type.BigSpider; + case < 55: + if (allowFlying) return CreatureTemplate.Type.Vulture; + else return RandomCreature(); + case < 70: + return CreatureTemplate.Type.Spider; + case < 86: + return CreatureTemplate.Type.SpitterSpider; + case < 100: + return CreatureTemplate.Type.Centiwing; + case < 110: + return CreatureTemplate.Type.MirosBird; + case >= 110: + return CreatureTemplate.Type.RedCentipede; + } + } + } + } + } +} + + diff --git a/Events/EventHelpers.cs b/Events/EventHelpers.cs index 1f35a65..437c115 100644 --- a/Events/EventHelpers.cs +++ b/Events/EventHelpers.cs @@ -121,12 +121,18 @@ internal static int GetNodeIdOfRoomConnection(AbstractRoom source, AbstractRoom internal static void MakeCreatureAttackCreature(AbstractCreature attacker, AbstractCreature target) { - attacker.state.socialMemory.GetOrInitiateRelationship(target.ID).like = -1f; - attacker.state.socialMemory.GetOrInitiateRelationship(target.ID).tempLike = -1f; + if (attacker.state?.socialMemory is not null) + { + attacker.state.socialMemory.GetOrInitiateRelationship(target.ID).like = -1f; + attacker.state.socialMemory.GetOrInitiateRelationship(target.ID).tempLike = -1f; + } attacker.personality.aggression = 1f; attacker.personality.dominance = 1f; attacker.personality.bravery = 1f; - attacker.abstractAI.followCreature = target; + if (attacker.abstractAI is not null) + { + attacker.abstractAI.followCreature = target; + } } internal static void MakeCreatureLikeAndFollowCreature(AbstractCreature friend, AbstractCreature target) diff --git a/Events/FlipCamera.cs b/Events/FlipCamera.cs index 096879c..e82cd87 100644 --- a/Events/FlipCamera.cs +++ b/Events/FlipCamera.cs @@ -10,7 +10,7 @@ namespace RainWorldCE.Events { /// - /// Flips the camera either by y + /// Flips the camera vertically /// internal class FlipCamera : CEEvent { diff --git a/Events/Friend.cs b/Events/Friend.cs index f2d0a11..ec7bded 100644 --- a/Events/Friend.cs +++ b/Events/Friend.cs @@ -38,7 +38,7 @@ static CreatureTemplate.Type PickLizardType case < 10: return CreatureTemplate.Type.GreenLizard; case < 20: - return MoreSlugcats.MoreSlugcatsEnums.CreatureTemplateType.SpitLizard; + return MoreSlugcats.MoreSlugcatsEnums.CreatureTemplateType.EelLizard; case < 30: return CreatureTemplate.Type.PinkLizard; case < 40: diff --git a/Events/LiftOff.cs b/Events/LiftOff.cs index 4cda510..f0082b7 100644 --- a/Events/LiftOff.cs +++ b/Events/LiftOff.cs @@ -5,6 +5,7 @@ using static SlugcatStats; using UnityEngine; using BepInEx.Logging; +using System.Drawing; namespace RainWorldCE.Events { @@ -23,6 +24,16 @@ public LiftOff() public override void RecurringTrigger() { + if (ModManager.MSC) + { + VirtualMicrophone virtMic = game.cameras[0].virtualMicrophone; + SoundLoader.SoundData soundData = virtMic.GetSoundData(MoreSlugcats.MoreSlugcatsEnums.MSCSoundID.Inv_Hit, 2); + if (virtMic.SoundClipReady(soundData)) + { + virtMic.soundObjects.Add(new VirtualMicrophone.DisembodiedSound(virtMic, soundData, 0f, 1f, 1f, startAtRandomTime: false, 0)); + } + } + foreach (AbstractCreature player in EventHelpers.AllPlayers) { player.realizedCreature.mainBodyChunk.vel.y += 100f; diff --git a/Events/LooseGrasp.cs b/Events/LooseGrasp.cs new file mode 100644 index 0000000..98cec06 --- /dev/null +++ b/Events/LooseGrasp.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace RainWorldCE.Events +{ + /// + /// Makes the player loose grasp of an item after about 7 seconds if they don't switch hands/replace/drop it + /// + internal class LooseGrasp : CEEvent + { + public LooseGrasp() + { + _name = "Hot Potatoes"; + _description = "Why is everything suddenly hot to the touch?\n Holding stuff for too long might burn you"; + _repeatEverySec = 1; + _activeTime = (int)(60 * RainWorldCE.eventDurationMult); + } + + Tuple[] graspCounter = new Tuple[16]; //4 players should be max but just in case? + public override void RecurringTrigger() + { + for (int playerIndex = 0; playerIndex < EventHelpers.AllPlayers.Count; playerIndex++) + { + AbstractCreature playerA = EventHelpers.AllPlayers[playerIndex]; + Creature player = playerA.realizedCreature; + if (graspCounter[playerIndex] is null) + { + graspCounter[playerIndex] = new (player.grasps, (Creature.Grasp[])player.grasps.Clone(), new int[player.grasps.Length]); + } + for (int graspIndex = 0; graspIndex < graspCounter[playerIndex].Item1.Length; graspIndex++) + { + if (ReferenceEquals(graspCounter[playerIndex].Item1[graspIndex], graspCounter[playerIndex].Item2[graspIndex])) + { + graspCounter[playerIndex].Item3[graspIndex] += 1; + } + else + { + graspCounter[playerIndex].Item3[graspIndex] = 0; + graspCounter[playerIndex].Item2[graspIndex] = graspCounter[playerIndex].Item1[graspIndex]; + } + + if (graspCounter[playerIndex].Item3[graspIndex] > 6) + { + (player as Player).ReleaseGrasp(graspIndex); + } + } + } + } + } +} diff --git a/Events/Melting.cs b/Events/Melting.cs new file mode 100644 index 0000000..946c7a5 --- /dev/null +++ b/Events/Melting.cs @@ -0,0 +1,111 @@ +using RainWorldCE.PostProcessing; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace RainWorldCE.Events +{ + /// + /// Screen melting effect + /// + internal class Melting : CEEvent + { + public Melting() + { + _name = "Extreme Heat"; + _description = "Everything melts, even the nacho cheese"; + _repeatEverySec = 2; + _activeTime = 80; + } + + private Texture2D MeltText; + private Color[] meltPixels; + public override void StartupTrigger() + { + MeltText = new Texture2D(Screen.width, 1) + { + filterMode = FilterMode.Point + }; + meltPixels = new Color[Screen.width]; + for (int i = 0; i < meltPixels.Length; i++) + { + meltPixels[i] = new Color(0, 0, 0, 0); + } + MeltText.SetPixels(meltPixels); + MeltText.Apply(); + Shader.SetGlobalTexture("Gamer025_MeltTex", MeltText); + foreach (RoomCamera camera in game.cameras) + { + camera.AddPPEffect(new MeltEffect()); + } + } + + public override void ShutdownTrigger() + { + foreach (RoomCamera camera in game.cameras) + { + camera.RemovePPEffect(typeof(MeltEffect)); + } + } + + public override void RecurringTrigger() + { + for (int i = 0; i < meltPixels.Length; i++) + { + if (UnityEngine.Random.Range(1, 1000) > 985) //97 + { + float amt = UnityEngine.Random.Range(1, 7); //6 + meltPixels[i].r += amt / 255f; + for (int away = 1; away < amt; away++) + { + if (i + away < meltPixels.Length) + { + meltPixels[i + away].r += (amt - away) / 255f; + } + if (i - away >= 0) + { + meltPixels[i - away].r += (amt - away) / 255f; + } + } + } + } + MeltText.SetPixels(meltPixels); + MeltText.Apply(); + } + } + + public class MeltEffect : IDrawable + { + public void AddToContainer(RoomCamera.SpriteLeaser sLeaser, RoomCamera rCam, FContainer newContatiner) + { + rCam.ReturnFContainer("PostProcessing").AddChild(sLeaser.sprites[0]); + } + + public void ApplyPalette(RoomCamera.SpriteLeaser sLeaser, RoomCamera rCam, RoomPalette palette) + { + } + + public void DrawSprites(RoomCamera.SpriteLeaser sLeaser, RoomCamera rCam, float timeStacker, Vector2 camPos) + { + + } + + public void InitiateSprites(RoomCamera.SpriteLeaser sLeaser, RoomCamera rCam) + { + sLeaser.sprites = new FSprite[1]; + sLeaser.sprites[0] = new FSprite("Futile_White"); + sLeaser.sprites[0].shader = rCam.game.rainWorld.Shaders["MeltingPP"]; + sLeaser.sprites[0].scaleX = rCam.game.rainWorld.options.ScreenSize.x / 16f; + sLeaser.sprites[0].scaleY = 48f; + sLeaser.sprites[0].anchorX = 0f; + sLeaser.sprites[0].anchorY = 0f; + AddToContainer(sLeaser, rCam, null); + } + } +} + + diff --git a/Events/Pixelize.cs b/Events/Pixelize.cs new file mode 100644 index 0000000..bca23d7 --- /dev/null +++ b/Events/Pixelize.cs @@ -0,0 +1,81 @@ +using RainWorldCE.Config; +using RainWorldCE.PostProcessing; +using System.Collections.Generic; +using UnityEngine; + +namespace RainWorldCE.Events +{ + /// + /// Pixelizes the screen + /// + internal class Pixelize : CEEvent + { + public Pixelize() + { + _name = "Retro"; + _description = "Rain World finally arrived on the NES"; + _activeTime = (int)(60 * RainWorldCE.eventDurationMult); + } + + public override void StartupTrigger() + { + foreach (RoomCamera camera in game.cameras) + { + camera.AddPPEffect(new PixelizeEffect()); + } + int intensity = TryGetConfigAsInt("intensity"); + Shader.SetGlobalFloat("Gamer025_PixelizeIntens", Mathf.Lerp(1.5f, 10f, Mathf.InverseLerp(10, 100, intensity))); + } + + public override void ShutdownTrigger() + { + foreach (RoomCamera camera in game.cameras) + { + camera.RemovePPEffect(typeof(PixelizeEffect)); + } + } + public override List ConfigEntries + { + get + { + List options = new List + { + new IntegerConfigEntry("Intensity", "How badly the game will be retrofied", "intensity", new RWCustom.IntVector2(10, 100), 30, this) + }; + return options; + } + } + } + + + public class PixelizeEffect : IDrawable + { + public void AddToContainer(RoomCamera.SpriteLeaser sLeaser, RoomCamera rCam, FContainer newContatiner) + { + rCam.ReturnFContainer("PostProcessing").AddChild(sLeaser.sprites[0]); + } + + public void ApplyPalette(RoomCamera.SpriteLeaser sLeaser, RoomCamera rCam, RoomPalette palette) + { + } + + public void DrawSprites(RoomCamera.SpriteLeaser sLeaser, RoomCamera rCam, float timeStacker, Vector2 camPos) + { + + } + + public void InitiateSprites(RoomCamera.SpriteLeaser sLeaser, RoomCamera rCam) + { + sLeaser.sprites = new FSprite[1]; + sLeaser.sprites[0] = new FSprite("Futile_White"); + sLeaser.sprites[0].shader = rCam.game.rainWorld.Shaders["PixelizePP"]; + sLeaser.sprites[0].scaleX = rCam.game.rainWorld.options.ScreenSize.x / 16f; + sLeaser.sprites[0].scaleY = 48f; + sLeaser.sprites[0].anchorX = 0f; + sLeaser.sprites[0].anchorY = 0f; + AddToContainer(sLeaser, rCam, null); + } + } +} + + diff --git a/Events/Rifle.cs b/Events/Rifle.cs index 5701a63..0c5c9b4 100644 --- a/Events/Rifle.cs +++ b/Events/Rifle.cs @@ -6,9 +6,14 @@ using System.Threading.Tasks; using MoreSlugcats; using UnityEngine; +using RainWorldCE.Attributes; namespace RainWorldCE.Events { + /// + /// Gives every player a rifle and some random ammo + /// + [MSCEvent] internal class Rifle : CEEvent { public Rifle() diff --git a/Events/Speed.cs b/Events/Speed.cs index 905d932..2eac027 100644 --- a/Events/Speed.cs +++ b/Events/Speed.cs @@ -19,17 +19,42 @@ public Speed() public override void StartupTrigger() { - game.session.characterStats.runspeedFac += 1f; - game.session.characterStats.poleClimbSpeedFac += 1f; - game.session.characterStats.corridorClimbSpeedFac += 1f; + if (ModManager.CoopAvailable) + { + foreach (SlugcatStats stats in (game.session as StoryGameSession).characterStatsJollyplayer.Where(x => x is not null)) + { + stats.runspeedFac += 1f; + stats.poleClimbSpeedFac += 1f; + stats.corridorClimbSpeedFac += 1f; + } + } + else + { + game.session.characterStats.runspeedFac += 1f; + game.session.characterStats.poleClimbSpeedFac += 1f; + game.session.characterStats.corridorClimbSpeedFac += 1f; + } + } public override void ShutdownTrigger() { - game.session.characterStats.runspeedFac -= 1f; - game.session.characterStats.poleClimbSpeedFac -= 1f; - game.session.characterStats.corridorClimbSpeedFac -= 1f; + if (ModManager.CoopAvailable) + { + foreach (SlugcatStats stats in (game.session as StoryGameSession).characterStatsJollyplayer.Where(x => x is not null)) + { + stats.runspeedFac -= 1f; + stats.poleClimbSpeedFac -= 1f; + stats.corridorClimbSpeedFac -= 1f; + } + } + else + { + game.session.characterStats.runspeedFac -= 1f; + game.session.characterStats.poleClimbSpeedFac -= 1f; + game.session.characterStats.corridorClimbSpeedFac -= 1f; + } } } } diff --git a/Events/Thanksgiving.cs b/Events/Thanksgiving.cs index 02e1d71..51cc073 100644 --- a/Events/Thanksgiving.cs +++ b/Events/Thanksgiving.cs @@ -25,8 +25,19 @@ public override void StartupTrigger() //Resets itself when cycle ends (EventHelpers.MainPlayer.realizedCreature as Player).AddFood( (EventHelpers.MainPlayer.realizedCreature as Player).MaxFoodInStomach - (EventHelpers.MainPlayer.realizedCreature as Player).FoodInStomach); - game.session.characterStats.bodyWeightFac += 0.20f; - game.session.characterStats.runspeedFac -= 0.20f; + if (ModManager.CoopAvailable) + { + foreach (SlugcatStats stats in (game.session as StoryGameSession).characterStatsJollyplayer.Where(x => x is not null)) + { + stats.bodyWeightFac += 0.20f; + stats.runspeedFac -= 0.20f; + } + } + else + { + game.session.characterStats.bodyWeightFac += 0.20f; + game.session.characterStats.runspeedFac -= 0.20f; + } } } } diff --git a/RainWorldCE.cs b/RainWorldCE.cs index d27f8bc..64b84f8 100644 --- a/RainWorldCE.cs +++ b/RainWorldCE.cs @@ -18,7 +18,7 @@ namespace RainWorldCE; -[BepInPlugin(MOD_ID, "Rain World Chaos Edition", "2.3.9")] +[BepInPlugin(MOD_ID, "Rain World Chaos Edition", "2.4.0")] public class RainWorldCE : BaseUnityPlugin { public const string MOD_ID = "Gamer025.RainworldCE"; @@ -61,6 +61,10 @@ public class RainWorldCE : BaseUnityPlugin /// public static Type[] blockedEvents; /// + /// Current position in blockedEvents + /// + static int blockedEventCounter = 0; + /// /// Amount of events already triggered /// static int eventCounter = 0; @@ -118,14 +122,14 @@ public void OnEnable() void Update() { //Only tick if the game seems to be running and is in story mode - if (CEactive && game.IsStorySession && game.pauseMenu == null && game.AllowRainCounterToTick()) + if (CEactive && game is not null && game.IsStorySession && game.pauseMenu == null && game.AllowRainCounterToTick() && game.manager.currentMainLoop is RainWorldGame) { timepool += UnityEngine.Time.deltaTime; //We only need second precision, so lets only do stuff every full second if (timepool > 1) { timepool--; - RainWorldCE.ME.Logger_p.Log(LogLevel.Debug, $"{DateTime.Now:HH:mm:ss:fff} Calling SecondUpdate [{gameTimer}]"); + //RainWorldCE.ME.Logger_p.Log(LogLevel.Debug, $"{DateTime.Now:HH:mm:ss:fff} Calling SecondUpdate [{gameTimer}]"); SecondUpdate(); gameTimer++; } @@ -214,7 +218,8 @@ public static Type PickEvent() //Should fill up the array and then start overwriting the oldest blocked event if (blockedEvents.Length > 0) { - blockedEvents[eventCounter % blockedEvents.Length] = eventClass; + blockedEvents[blockedEventCounter] = eventClass; + blockedEventCounter = (blockedEventCounter + 1) % blockedEvents.Length; RainWorldCE.ME.Logger_p.Log(LogLevel.Debug, $"Blocked events: {String.Join(",", blockedEvents.OfType().Select(x => x.ToString()).ToArray())}"); } return eventClass; @@ -392,6 +397,7 @@ void RainWorldGameCtorHook(On.RainWorldGame.orig_ctor orig, RainWorldGame self, { ME.Logger_p.Log(LogLevel.Debug, $"Setting blockedEvents to {blockCount} from Remix"); blockedEvents = new Type[blockCount]; + blockedEventCounter = 0; } } else @@ -415,6 +421,16 @@ void RainWorldGameWinHook(On.RainWorldGame.orig_Win orig, RainWorldGame self, bo orig(self, malnourished); } + void ProcessManagerRequestMainProcessSwitchHook(On.ProcessManager.orig_RequestMainProcessSwitch_ProcessID orig, ProcessManager self, ProcessManager.ProcessID ID) + { + //Disable CE if game not in game mode + if (ID != ProcessManager.ProcessID.Game) + CEactive = false; + else + CEactive = true; + orig(self, ID); + } + void ShortcutHandlerSuckInCreatureHook(On.ShortcutHandler.orig_SuckInCreature orig, ShortcutHandler self, Creature creature, Room room, ShortcutData shortCut) { foreach (CEEvent activeEvent in activeEvents) @@ -446,7 +462,6 @@ void RoomCameraChangeRoomHook(On.RoomCamera.orig_ChangeRoom orig, RoomCamera sel { for (int j = 0; j < room.physicalObjects[i].Count; j++) { - ME.Logger_p.Log(LogLevel.Debug, room.physicalObjects[i][j]); if (room.physicalObjects[i][j] is Oracle) { CEactive = false; @@ -530,6 +545,8 @@ private void OnModsInitHook(On.RainWorld.orig_OnModsInit orig, RainWorld self) //Triggers for resetting CEs state On.RainWorldGame.ExitGame += RainWorldGameExitGameHook; On.RainWorldGame.Win += RainWorldGameWinHook; + //Used to pause CE on process switch (death screen ...) + On.ProcessManager.RequestMainProcessSwitch_ProcessID += ProcessManagerRequestMainProcessSwitchHook; //Add own HUD to the game On.HUD.HUD.InitSinglePlayerHud += HUDInitSinglePlayerHudHook; //Needed for fixing teleports @@ -543,7 +560,7 @@ private void OnModsInitHook(On.RainWorld.orig_OnModsInit orig, RainWorld self) On.ShortcutHandler.SuckInCreature += ShortcutHandlerSuckInCreatureHook; //Used as trigger for PlayerChangedRoomTrigger On.RoomCamera.ChangeRoom += RoomCameraChangeRoomHook; - + //Load asset bundle containing shaders, can only loaded once otherwise error try @@ -556,6 +573,8 @@ private void OnModsInitHook(On.RainWorld.orig_OnModsInit orig, RainWorld self) } ME.Logger_p.Log(LogLevel.Debug, $"Assetbundle content: {String.Join(", ", CEAssetBundle.GetAllAssetNames())}"); self.Shaders.Add("FlipScreenPP", FShader.CreateShader("FlipScreenPP", CEAssetBundle.LoadAsset("flipscreen.shader"))); + self.Shaders.Add("MeltingPP", FShader.CreateShader("MeltingPP", CEAssetBundle.LoadAsset("melt.shader"))); + self.Shaders.Add("PixelizePP", FShader.CreateShader("PixelizePP", CEAssetBundle.LoadAsset("pixelize.shader"))); } catch (Exception e) { @@ -587,9 +606,9 @@ public static IEnumerable GetEnumerableOfType() where T : class public static IEnumerable GetAllCEEventTypes() { IEnumerable eventTypes = - GetEnumerableOfType().Where(x => !x.IsDefined(typeof(InternalCEEvent), true)); + GetEnumerableOfType().Where(x => !x.IsDefined(typeof(InternalCEEventAttribute), true)); if (!ModManager.MSC) - eventTypes = eventTypes.Where(x => !x.IsDefined(typeof(MSCEvent), true)); + eventTypes = eventTypes.Where(x => !x.IsDefined(typeof(MSCEventAttribute), true)); return eventTypes; } } \ No newline at end of file diff --git a/RainWorldCE.csproj b/RainWorldCE.csproj index 08c8153..e071ce0 100644 --- a/RainWorldCE.csproj +++ b/RainWorldCE.csproj @@ -1,4 +1,4 @@ - + net48 @@ -7,7 +7,7 @@ latest True True - 2.3.9 + 2.4.0 diff --git a/Shaders/FlipScreen.shader b/Shaders/FlipScreen.shader new file mode 100644 index 0000000..ac62eb8 --- /dev/null +++ b/Shaders/FlipScreen.shader @@ -0,0 +1,75 @@ +Shader "Gamer025/FlipImage" +{ + Properties + { + _MainTex("Texture", 2D) = "white" {} + } + SubShader + { + // No culling or depth + Cull Off ZWrite Off ZTest Always + + GrabPass + { + "_ScreenTexture" + } + + Pass + { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma enable_d3d11_debug_symbols + #include "UnityCG.cginc" + + struct appdata + { + float4 vertex : POSITION; + float2 uv : TEXCOORD0; + }; + + struct v2f + { + float2 grabPos : TEXCOORD0; + float4 vertex : SV_POSITION; + }; + + float when_gt(float x, float y) { + return max(sign(x - y), 0.0); + } + + float when_lt(float x, float y) { + return max(sign(y - x), 0.0); + } + + v2f vert(appdata v) + { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + o.grabPos = ComputeGrabScreenPos(o.vertex); + return o; + } + + + sampler2D _MainTex; + sampler2D _ScreenTexture; + float Gamer025_YFlip; + + fixed4 frag(v2f i) : SV_Target + { + float closeToMid = 1 - 2 * abs(Gamer025_YFlip - 0.5f); + float flipYMidpoint = sign(Gamer025_YFlip - 0.5); + i.grabPos.y = abs((flipYMidpoint + 1) / 2 - i.grabPos.y); + float upperOrLower = sign(i.grabPos.y - 0.5); + + i.grabPos.y = i.grabPos.y + closeToMid / 2 * upperOrLower; + float outOfBounds = when_gt(i.grabPos.y, 1) + when_lt(i.grabPos.y, 0); + + fixed4 col = tex2D(_ScreenTexture, i.grabPos); + col.rgb = col.rgb - outOfBounds; + return col; + } + ENDCG + } + } +} diff --git a/Shaders/Melt.shader b/Shaders/Melt.shader new file mode 100644 index 0000000..2ef4a95 --- /dev/null +++ b/Shaders/Melt.shader @@ -0,0 +1,71 @@ +Shader "Gamer025/Melt" +{ + Properties + { + //Gamer025_MeltTex("MeltTexture", 2D) = "black" {} + } + SubShader + { + // No culling or depth + Cull Off ZWrite Off ZTest Always + + GrabPass + { + "_ScreenTexture" + } + + Pass + { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma enable_d3d11_debug_symbols + #include "UnityCG.cginc" + + struct appdata + { + float4 vertex : POSITION; + float2 uv : TEXCOORD0; + }; + + struct v2f + { + float2 grabPos : TEXCOORD0; + float4 vertex : SV_POSITION; + }; + + + float when_gt(float x, float y) { + return max(sign(x - y), 0.0); + } + + float when_lt(float x, float y) { + return max(sign(y - x), 0.0); + } + + v2f vert(appdata v) + { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + o.grabPos = ComputeGrabScreenPos(o.vertex); + return o; + } + + + sampler2D Gamer025_MeltTex; + sampler2D _ScreenTexture; + float4 _ScreenTexture_TexelSize; + + fixed4 frag(v2f i) : SV_Target + { + float meltAmt = tex2D(Gamer025_MeltTex, i.grabPos).r; + fixed4 above = tex2D(_ScreenTexture, i.grabPos - float2(0, _ScreenTexture_TexelSize.y * meltAmt * 255)); + fixed4 col = fixed4(0, 0, 0, 1); + if (above.r + above.g + above.b > 0) + col = above; + return col; + } + ENDCG + } + } +} diff --git a/Shaders/Pixelize.shader b/Shaders/Pixelize.shader new file mode 100644 index 0000000..1fcc39a --- /dev/null +++ b/Shaders/Pixelize.shader @@ -0,0 +1,69 @@ +Shader "Gamer025/Pixelize" +{ + Properties + { + } + SubShader + { + // No culling or depth + Cull Off ZWrite Off ZTest Always + + GrabPass + { + "_ScreenTexture" + } + + Pass + { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma enable_d3d11_debug_symbols + #include "UnityCG.cginc" + + struct appdata + { + float4 vertex : POSITION; + float2 uv : TEXCOORD0; + }; + + struct v2f + { + float2 grabPos : TEXCOORD0; + float4 vertex : SV_POSITION; + }; + + + float when_gt(float x, float y) { + return max(sign(x - y), 0.0); + } + + float when_lt(float x, float y) { + return max(sign(y - x), 0.0); + } + + v2f vert(appdata v) + { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + o.grabPos = ComputeGrabScreenPos(o.vertex); + return o; + } + + + sampler2D _ScreenTexture; + float4 _ScreenTexture_TexelSize; + float Gamer025_PixelizeIntens; + + //Inspired by https://luka712.github.io/2018/07/01/Pixelate-it-Shadertoy-Unity/ + fixed4 frag(v2f i) : SV_Target + { + float pixelX = 1 / _ScreenTexture_TexelSize / Gamer025_PixelizeIntens; + float pixelY = 1 / _ScreenTexture_TexelSize / Gamer025_PixelizeIntens; + + return tex2D(_ScreenTexture, float2(floor(pixelX * i.grabPos.x) / pixelX, floor(pixelY * i.grabPos.y) / pixelY)); + } + ENDCG + } + } +} diff --git a/modinfo.json b/modinfo.json index e04499d..4866285 100644 --- a/modinfo.json +++ b/modinfo.json @@ -1,7 +1,7 @@ { "id": "Gamer025.RainworldCE", "name": "Rain World: Chaos Edition", - "version": "2.3.9", + "version": "2.4.0", "target_game_version": "v1.9.07b", "authors": "Gamer025", "description": "Ever felt like Rain World didn't have enough randomness/chaos? Rain World: Chaos edition is here to help. With over 30 events and the ability to highly customize their generation no cycle will ever be the same.",