private static void modDeathSound(ILContext il) { ILCursor cursor = new ILCursor(il); FieldReference refToThis = HookHelper.FindReferenceToThisInCoroutine(cursor); if (cursor.TryGotoNext(MoveType.After, instr => instr.MatchLdstr("event:/new_content/char/madeline/death_golden"))) { Logger.Log("CollabUtils2/StrawberryHooks", $"Modding golden death sound at {cursor.Index} in IL for PlayerDeadBody.DeathRoutine"); // we want to replace the vanilla death sound with the silver berry one if carrying a silver berry. cursor.Emit(OpCodes.Ldarg_0); cursor.Emit(OpCodes.Ldfld, refToThis); cursor.EmitDelegate <Func <string, PlayerDeadBody, string> >((orig, self) => { DynData <PlayerDeadBody> data = new DynData <PlayerDeadBody>(self); bool hasSilver = data.Get <bool>("hasSilver"); bool hasSpeedBerry = data.Get <bool>("hasSpeedBerry"); if (hasSilver && hasSpeedBerry) { return("event:/SC2020_silverTimedBerry_death"); } if (hasSilver) { return("event:/SC2020_silverBerry_death"); } if (hasSpeedBerry) { return("event:/SC2020_timedBerry_death"); } return(orig); }); } }
private static void modStrawberrySound(ILContext il) { ILCursor cursor = new ILCursor(il); FieldReference refToThis = HookHelper.FindReferenceToThisInCoroutine(cursor); if (cursor.TryGotoNext(MoveType.After, instr => instr.MatchLdstr("event:/game/general/strawberry_get"))) { Logger.Log("CollabUtils2/StrawberryHooks", $"Modding golden sound at {cursor.Index} in IL for Strawberry.CollectRoutine"); // we want to replace the vanilla collect sound with the silver berry one if the current berry is a silver one. cursor.Emit(OpCodes.Ldarg_0); cursor.Emit(OpCodes.Ldfld, refToThis); cursor.EmitDelegate <Func <string, Strawberry, string> >((orig, self) => { if (self is SilverBerry) { return("event:/SC2020_silverBerry_get"); } if (self is RainbowBerry) { return("event:/SC2020_rainbowBerry_get"); } if (self is SpeedBerry) { return("event:/SC2020_timedBerry_get"); } return(orig); }); } }
private static void modDoorRoutine(ILContext il) { ILCursor cursor = new ILCursor(il); FieldReference refToThis = HookHelper.FindReferenceToThisInCoroutine(cursor); // find the "player is on the left side of the door" check // FNA version bool hookPointFound = cursor.TryGotoNext(MoveType.After, instr => instr.MatchLdarg(0), instr => instr.OpCode == OpCodes.Ldfld && (instr.Operand as FieldReference).Name.Contains("player"), instr => instr.MatchCallvirt <Entity>("get_X"), instr => instr.MatchLdarg(0), instr => instr.OpCode == OpCodes.Ldfld && (instr.Operand as FieldReference).Name == "<>4__this", instr => instr.MatchCallvirt <Entity>("get_X")); if (!hookPointFound) { cursor.Index = 0; // XNA version hookPointFound = cursor.TryGotoNext(MoveType.After, instr => instr.OpCode == OpCodes.Ldloc_S, instr => instr.MatchCallvirt <Entity>("get_X"), instr => instr.OpCode == OpCodes.Ldloc_1, instr => instr.MatchCallvirt <Entity>("get_X")); } if (hookPointFound) { Logger.Log("CollabUtils2/MiniHeartDoor", $"Making mini heart door approachable from both sides at {cursor.Index} in IL for HeartGemDoor.Routine"); cursor.Index--; cursor.Emit(OpCodes.Dup); cursor.Index++; cursor.EmitDelegate <Func <HeartGemDoor, float, float> >((self, orig) => { if (self is MiniHeartDoor door) { // actually check the Y poition of the player instead. Player player = self.Scene.Tracker.GetEntity <Player>(); if (door.ForceTrigger || (player != null && player.Center.Y > door.Y - door.height && player.Center.Y < door.Y + door.height)) { // player has same height as door => ok (return MaxValue so that the door is further right than the player) return(float.MaxValue); } else { // player has not same height as door => ko (return MinValue so that the door is further left than the player) return(float.MinValue); } } return(orig); }); } cursor.Index = 0; if (refToThis != null && cursor.TryGotoNext(MoveType.After, instr => instr.MatchLdcR4(80f))) { Logger.Log("CollabUtils2/MiniHeartDoor", $"Making mini heart door open on command at {cursor.Index} in IL for HeartGemDoor.Routine"); cursor.Emit(OpCodes.Ldarg_0); cursor.Emit(OpCodes.Ldfld, refToThis); cursor.EmitDelegate <Func <float, HeartGemDoor, float> >((orig, self) => { if (self is MiniHeartDoor door && door.ForceTrigger) { // force trigger the door by replacing the approach distance by... basically positive infinity. return(float.MaxValue); } return(orig); }); } // add a patch at the place where the vanilla opened_heartgem_door_[heartcount] gets set. if (refToThis != null && cursor.TryGotoNext(MoveType.After, instr => instr.MatchLdstr("opened_heartgem_door_"))) { Logger.Log("CollabUtils2/MiniHeartDoor", $"Making mini heart door save its session flag at {cursor.Index} in IL for HeartGemDoor.Routine"); cursor.Emit(OpCodes.Ldarg_0); cursor.Emit(OpCodes.Ldfld, refToThis); cursor.EmitDelegate <Action <HeartGemDoor> >(self => { if (self is MiniHeartDoor door) { // mini heart doors use their own flags, that allow better differenciation between themselves by using entity ID. (door.Scene as Level).Session.SetFlag("opened_mini_heart_door_" + door.entityID, true); } }); } }