public void Awake() { On.RoR2.Console.Awake += (orig, self) => { CommandHelper.RegisterCommands(self); orig(self); }; confScalar = Config.Wrap("Scalars", "printerScalar", "1.0 = Reduces spawn-rate of printers for each extra player over 4. 16 players results in 25% of the normal spawns, 8 players results in 50% of the normal. Using a scalar value of 4.0 with 16 players results in no change to the spawnrate.", 1.0 ); /// Credits to Fluffatron for getting an effective hook working. On.RoR2.DirectorCardCategorySelection.SumAllWeightsInCategory += (orig, self, category) => { var numberOfPlayers = RoR2.Run.instance.participatingPlayerCount; if (numberOfPlayers > 4) //only make changes if > 4 players { AddInfoLog($"Making changes based on {numberOfPlayers} players"); var cardsToBeAdjusted = new List <string> { CardNames.Duplicator, CardNames.DuplicatorLarge, CardNames.DuplicatorMilitary, CardNames.LunarChest }; foreach (var card in cardsToBeAdjusted) { AddDebugLog($"Player count is > 4. Adjusting value for {card}"); AdjustSelectionWeight(category, card, numberOfPlayers); } } else { AddDebugLog("No changes made to weighting."); } float num = 0.0f; for (int index = 0; index < category.cards.Length; ++index) { var name = category.cards[index].spawnCard.name; int weight = category.cards[index].selectionWeight; num += (float)category.cards[index].selectionWeight; } return(num); }; }
/*private static ConfigWrapper<float> MyConfig; * private float myConfig * { * get { return GetValue(MyConfig.Value, 10.0f, 20.0f); } * } * private float GetValue(float value, float min, float max) * { * if(value < min) { return min; } * if(value > max) { return max; } * return value; * }*/ public void Awake() { On.RoR2.Console.Awake += (orig, self) => { CommandHelper.RegisterCommands(self); orig(self); }; cStickyMultiplier = Config.Wrap("Multipliers", "StickybombMultiplier", $"Modifies the damage multiplier of the stickybomb: >{_stickyMin}f, 1.8f vanilla, {_stickyMultiplier}f default, <={_stickyMax}f", _stickyMultiplier); cBleedMultiplier = Config.Wrap("Multipliers", "BleedDamageMultiplier", $"Modifies the damage multiplier value of tri-tip: >{_bleedDamageMin}f, 1.0f vanilla, {_bleedDamageMultiplier}f default <={_bleedDamageMax}f", _bleedDamageMultiplier); cBleedChancePerStack = Config.Wrap("Multipliers", "BleedChancePerStack", $"Modifies the chance of inflicting bleed with tri-tip: >{_bleedChanceMin}f, 15f vanilla, {_bleedChancePerStack}f default, <={_bleedChanceMax}f", _bleedChancePerStack); cBleedProcChain = Config.Wrap("Multipliers", "BleedProcChainEnabled", $"Enables proc-chain triggered bleeds", true); cIceRingMultiplier = Config.Wrap("Multipliers", "IceRingMultiplier", $"Modifies the damage multiplier of the Ice Band: >{_iceRingMin}f, 1.25f vanilla, {_iceRingMultiplier}f default, <={_iceRingMax}f", _iceRingMultiplier); cUkuleleMultiplier = Config.Wrap("Multipliers", "UkeleleMultiplier", $"Modifies the damage multiplier of the Ukulele: >{_ukuleleMin}f, 0.8f vanilla, {_ukuleleMultiplier}f default, <={_ukuleleMax}f", _ukuleleMultiplier); _stickyMultiplier = (cStickyMultiplier.Value > _stickyMin && cStickyMultiplier.Value <= _stickyMax) ? cStickyMultiplier.Value : _stickyMultiplier; _bleedDamageMultiplier = (cBleedMultiplier.Value > _bleedDamageMin && cBleedMultiplier.Value <= _bleedDamageMax) ? cBleedMultiplier.Value : _bleedDamageMultiplier; _bleedChancePerStack = (cBleedChancePerStack.Value > _bleedChanceMin && cBleedChancePerStack.Value <= _bleedChanceMax) ? cBleedChancePerStack.Value : _bleedChancePerStack; _iceRingMultiplier = (cIceRingMultiplier.Value > _iceRingMin && cIceRingMultiplier.Value <= _iceRingMax) ? cIceRingMultiplier.Value : _iceRingMultiplier; _ukuleleMultiplier = (cUkuleleMultiplier.Value > _ukuleleMin && cUkuleleMultiplier.Value <= _ukuleleMax) ? cUkuleleMultiplier.Value : _ukuleleMultiplier; cCrowbarDeminishingThreshold = Config.Wrap("Crowbar", "CrowbarDeminishingThresholdEnabled", "Enables a variable threshold for Crowbars which scales with deminishing returns, similar to a teddy.", true); cCrowbarScalar = Config.Wrap("Crowbar", "CrowbarScalar", $"Modifies the per stack scalar with deminishing returns: >{_crowbarScalarMin}f, {_crowbarScalar}f default, <={_crowbarScalarMax}f", _crowbarScalar); cCrowbarCap = Config.Wrap("Crowbar", "CrowbarCap", $"Modifies the cap of the maximum health for which the crowbars effect is applied, as a % of fullHP: >{_crowbarCapMin}f, {_crowbarCap}f default, <={_crowbarCapMax}f", _crowbarCap); _crowbarScalar = (cCrowbarScalar.Value > _crowbarScalarMin && cCrowbarScalar.Value <= _crowbarScalarMax) ? cCrowbarScalar.Value : _crowbarScalar; _crowbarCap = (cCrowbarCap.Value > _crowbarCapMin && cCrowbarCap.Value <= _crowbarCapMax) ? cCrowbarCap.Value : _crowbarCap; cGuillotineDeminishingThreshold = Config.Wrap("Guillotine", "GuillotineThresholdEnabled", "Enables a variable threshold for Guillotine which scales with deminishing returns, similar to a teddy.", true); cGuillotineScalar = Config.Wrap("Guillotine", "GuillotineScalar", $"Modifies the per stack scalar with deminishing returns: >{_guilotineScalarMin}f, {_guilotineScalar}f default, <={_guilotineScalarMax}f", _guilotineScalar); cGuillotineCap = Config.Wrap("Guillotine", "GuillotineCap", $"Modifies the cap of the minimum health for which the crowbars effect is applied, as a % of fullHP: >{_guilotineCapMin}f, {_guilotineCap}f default, <={_guilotineCapMax}f", _guilotineCap); _guilotineScalar = (cGuillotineScalar.Value > _guilotineScalarMin && cGuillotineScalar.Value <= _guilotineScalarMax) ? cGuillotineScalar.Value : _guilotineScalar; _guilotineCap = (cGuillotineCap.Value > _guilotineCapMin && cGuillotineCap.Value <= _guilotineCapMax) ? cGuillotineCap.Value : _guilotineCap; cPredatoryEnabled = Config.Wrap("Predatory", "PredatoryEnabled", "Enables linear predatory scaling: 3,6,9...", true); cPredatoryBuffsPerStack = Config.Wrap("Predatory", "PredatoryBuffsPerStack", $"Alters the scaling of predatory isntincts to scale linearly instead of 3+2xStacks: >{_predatoryMin}i, {_predatoryBuffsPerStack}i default, <={_predatoryMax}", _predatoryBuffsPerStack); _predatoryBuffsPerStack = (cPredatoryBuffsPerStack.Value > _predatoryMin && cPredatoryBuffsPerStack.Value <= _predatoryMax) ? cPredatoryBuffsPerStack.Value : _predatoryBuffsPerStack; cAPElites = Config.Wrap("APRounds", "APElitesEnabled", "Alters the AP rounds to be inclusive of elite mobs", true); cAPDamage = Config.Wrap("APRounds", "APDamageScalar", $"Alters the AP damage scalar to be lower than default due to increased effectiveness: >{_APMin}f, {_APScalar}f default, <={_APMax}f", _APScalar); _APScalar = (cAPDamage.Value > _APMin && cAPDamage.Value <= _APMax) ? cAPDamage.Value : _APScalar; cCursedOSP = Config.Wrap("OSP", "CursedOSPDisabled", "Disables One Shot Protection for Cursed characters(read as shaped glass, lunar potion curse)", true); cAegisDecay = Config.Wrap("Barrier", "DisableAegisDecay", "Barrier given by Aegis does not decay", true); cAegisBuff = Config.Wrap("Barrier", "BuffAegis", "Aegis provides 33% instead of 20% of FullCombinedHealth as barrier", true); cBrooch = Config.Wrap("Barrier", "BroochBarrierVal", $"The value of barrier restored per kill: >{_broochMin}f, {_brooch}f default, <={_broochMax}f", _brooch); _brooch = (cBrooch.Value > _broochMin && cBrooch.Value <= _broochMax) ? cBrooch.Value : _brooch; cChronoFix = Config.Wrap("ChronoBauble", "ChronoReworkEnabled", "Reworks the chronobauble to apply slow stacks to enemies onHit", true); cChronoChance = Config.Wrap("ChronoBauble", "ChronoProcChance", "The chance per hit per item to apply a single slow stack", _chronoChance); _chronoChance = (cChronoChance.Value > _chronoMin && cChronoChance.Value <= _chronoMax) ? cChronoChance.Value : _chronoChance; IL.RoR2.GlobalEventManager.OnHitEnemy += (il) => { var c = new ILCursor(il); c.Index = 0; //Bleed procchain if (cBleedProcChain.Value) { c.GotoNext( x => x.MatchLdarg(1), x => x.MatchLdflda <DamageInfo>("procChainMask"), x => x.MatchLdcI4(5), x => x.MatchCall <ProcChainMask>("HasProc") ); c.Next.OpCode = OpCodes.Nop; c.Index++; c.RemoveRange(3); c.Emit(OpCodes.Ldc_I4_0); } //BleedChance c.GotoNext( x => x.MatchLdcR4(15f), x => x.MatchLdloc(19), x => x.MatchConvR4() ); c.Remove(); c.Emit(OpCodes.Ldc_R4, _bleedChancePerStack); //BleedDmg c.GotoNext( x => x.MatchLdarg(1), x => x.MatchLdfld <DamageInfo>("procCoefficient"), x => x.MatchMul(), x => x.MatchLdcR4(1f) ); //BleedProcChain if (cBleedProcChain.Value) { c.RemoveRange(2); c.Emit(OpCodes.Ldloc_0); c.Emit(OpCodes.Ldarg_1); c.EmitDelegate <Func <CharacterBody, DamageInfo, float> >((attacker, damageInfo) => { if (attacker.teamComponent.teamIndex == TeamIndex.Player) { return(1f); } return(damageInfo.procCoefficient); }); c.Index += 1; c.Remove(); } else { c.Index += 3; c.Remove(); } c.Emit(OpCodes.Ldloc_0); c.Emit(OpCodes.Ldarg_1); c.EmitDelegate <Func <CharacterBody, DamageInfo, float> >((attacker, damageInfo) => { if (attacker.teamComponent.teamIndex == TeamIndex.Player) { return(_bleedDamageMultiplier); } return(1f); }); //c.Emit(OpCodes.Ldc_R4, _bleedDamageMultiplier); //Chrono if (cChronoFix.Value) { int arg1, icount; c.GotoNext( x => x.MatchLdloc(out arg1), x => x.MatchLdcI4(26), x => x.MatchLdcR4(2f), x => x.MatchLdloc(out icount), x => x.MatchConvR4(), x => x.MatchMul(), x => x.MatchCallvirt <CharacterBody>("AddTimedBuff") ); c.RemoveRange(7); } //Ukulele c.GotoNext( x => x.MatchLdcR4(0.8f), x => x.MatchStloc(24) ); c.Remove(); c.Emit(OpCodes.Ldc_R4, _ukuleleMultiplier); //StickyDmg c.GotoNext( x => x.MatchLdcR4(1.8f), x => x.MatchStloc(37)// (OpCodes.Stloc_S, (byte)37) ); c.Remove(); c.Emit(OpCodes.Ldc_R4, _stickyMultiplier); //IceBand c.GotoNext( x => x.MatchLdcR4(1.25f), x => x.MatchLdcR4(1.25f), x => x.MatchLdloc(39) ); c.RemoveRange(2); c.Emit(OpCodes.Ldc_R4, _iceRingMultiplier); c.Emit(OpCodes.Ldc_R4, 2.5f); }; //Brooch IL.RoR2.GlobalEventManager.OnCharacterDeath += (il) => { ILCursor c = new ILCursor(il); int val, val2; c.GotoNext( x => x.MatchLdloc(out val), x => x.MatchCallvirt <CharacterBody>("get_healthComponent"), x => x.MatchLdcR4(20f), x => x.MatchLdloc(out val2), x => x.MatchConvR4() ); c.Index += 2; c.Next.Operand = _brooch; }; //Predatory Stacks IL.RoR2.CharacterBody.AddTimedBuff += (il) => { var c = new ILCursor(il); if (cPredatoryEnabled.Value) { c.GotoNext( x => x.MatchLdloc(2), x => x.MatchLdcI4(1), x => x.MatchLdloc(1), x => x.MatchLdcI4(2) ); c.Index += 1; c.Remove(); c.Index += 1; c.Remove(); c.Emit(OpCodes.Ldc_I4, _predatoryBuffsPerStack); c.Index += 1; c.Remove(); } }; //cBar, AP, OSP IL.RoR2.HealthComponent.TakeDamage += (il) => { ILCursor c = new ILCursor(il); #region Crowbar if (cCrowbarDeminishingThreshold.Value) { c.GotoNext( x => x.MatchLdarg(0), x => x.MatchCallvirt <HealthComponent>("get_combinedHealth"), x => x.MatchLdarg(0), x => x.MatchCallvirt <HealthComponent>("get_fullCombinedHealth"), x => x.MatchLdcR4(0.9f) ); c.Index += 4; c.Remove(); c.Emit(OpCodes.Ldloc_1); c.EmitDelegate <Func <CharacterBody, float> >((cb) => { if (cb.master.inventory) { int bars = cb.master.inventory.GetItemCount(ItemIndex.Crowbar); if (bars > 0) { return(1f - ((1f - 1f / (_crowbarScalar * (float)bars + 1f)) * _crowbarCap)); } } return(0.9f); }); } #endregion #region AP if (cAPElites.Value) { //Debug.Log(il); ILLabel lab1 = il.DefineLabel(); ILLabel lab2 = il.DefineLabel(); c.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld <HealthComponent>("body"), x => x.MatchCallvirt <CharacterBody>("get_isBoss") ); c.Index += 3; c.Remove(); c.Emit(OpCodes.Brtrue_S, lab1); c.Emit(OpCodes.Ldarg_0); c.Emit(OpCodes.Ldfld, typeof(HealthComponent).GetFieldCached("body")); c.Emit(OpCodes.Callvirt, typeof(CharacterBody).GetMethodCached("get_isElite")); c.Emit(OpCodes.Brfalse_S, lab2); //c.Index = 1; c.MarkLabel(lab1); //AP Multiplier c.GotoNext( x => x.MatchLdloc(4), x => x.MatchLdcR4(1.0f), x => x.MatchLdcR4(0.2f) ); //Debug.Log(c); c.Index += 2; c.Remove(); c.Emit(OpCodes.Ldc_R4, _APScalar); //Return label c.GotoNext( x => x.MatchLdarg(1), x => x.MatchLdfld <DamageInfo>("crit") ); c.MarkLabel(lab2); //Debug.Log(il); } #endregion #region OSP if (cCursedOSP.Value) { c.GotoNext( x => x.MatchLdloc(4), x => x.MatchLdarg(0), x => x.MatchCallvirt <HealthComponent>("get_fullCombinedHealth"), x => x.MatchLdcR4(0.9f), x => x.MatchMul() ); c.Index += 5; c.Emit(OpCodes.Ldarg_0); c.Emit(OpCodes.Ldfld, typeof(HealthComponent).GetFieldCached("body")); c.Emit(OpCodes.Callvirt, typeof(CharacterBody).GetMethodCached("get_cursePenalty")); c.Emit(OpCodes.Mul); } #endregion #region Guilotine if (cGuillotineDeminishingThreshold.Value) { c.GotoNext( x => x.MatchLdloc(1), x => x.MatchCallvirt <CharacterBody>("get_executeEliteHealthFraction"), x => x.MatchStloc(29) ); c.Index++; c.Remove(); c.EmitDelegate <Func <CharacterBody, float> >((cb) => { if (cb.inventory && cb.inventory.GetItemCount(ItemIndex.ExecuteLowHealthElite) > 0) { return((1f - 1f / (_guilotineScalar * (float)cb.inventory.GetItemCount(ItemIndex.ExecuteLowHealthElite) + 1f)) * _guilotineCap); } return(cb.executeEliteHealthFraction); }); } //Debug.Log(il); #endregion }; //Aegis IL.RoR2.HealthComponent.Heal += (il) => { ILCursor c = new ILCursor(il); c.GotoNext(MoveType.After, x => x.MatchLdfld <HealthComponent>("barrierOnOverHealCount"), x => x.MatchConvR4(), x => x.MatchMul(), x => x.MatchLdcR4(0.2f) ); if (cAegisBuff.Value) { c.Prev.Operand = _aegisMultiplier; } }; //AegisDecay & multiplier IL.RoR2.HealthComponent.ServerFixedUpdate += (il) => { ILCursor c = new ILCursor(il); c.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld <HealthComponent>("barrier"), x => x.MatchLdcR4(0) ); c.Index += 2; //Debug.Log(c); c.Remove(); //Debug.Log(c); c.Emit(OpCodes.Ldarg_0); c.EmitDelegate <Func <HealthComponent, float> >((hc) => { if (hc.body && hc.body.inventory && cAegisDecay.Value) { return(hc.fullCombinedHealth * (hc.body.inventory.GetItemCount(ItemIndex.BarrierOnOverHeal) * (cAegisBuff.Value ? _aegisMultiplier : 0.2f))); } return(0f); }); Debug.Log(c); }; if (cChronoFix.Value) { On.RoR2.GlobalEventManager.OnHitEnemy += GlobalEventManager_OnHitEnemy; } }
public static List <EquipmentIndex> eblackList = new List <EquipmentIndex>(); //EquipmentBlacklist public void Awake() { //Setup banned items & equipment initConf(); //Don't know what this does but we need it. On.RoR2.Console.Awake += (orig, self) => { CommandHelper.RegisterCommands(self); orig(self); }; /* * We are completely rewriting BuildDropTable to avoid using IL. During various tests it was discovered that * modifying the tierDropTables directly resulted in client sync issues, which would make clients unable to join * the lobby, although the changes were working fine in singleplayer. Similarly amonst other tests we found that * using a standard eventhook didn't really work as we would modify the droplist before it was created, this * removing non-existant entries from the droplist; or we would modify it too late and the list would be readOnly * and changes would not be effective. The following solution appears to allow clients to join a lobby without * having the mod installed. * Massive thanks to Atlas_ and the entire modding discord for their help and support. Without Atlas_ this hook * would not have been possible. */ On.RoR2.Run.BuildDropTable += (On.RoR2.Run.orig_BuildDropTable orig, Run self) => { self.availableTier1DropList.Clear(); self.availableTier2DropList.Clear(); self.availableTier3DropList.Clear(); self.availableLunarDropList.Clear(); self.availableEquipmentDropList.Clear(); List <ItemIndex> itemList = new List <ItemIndex>(); List <EquipmentIndex> equipList = new List <EquipmentIndex>(); /* * Loop through ItemsIndex and omit adding banned items to the itemDropList. */ for (ItemIndex itemIndex = ItemIndex.Syringe; itemIndex < ItemIndex.Count; itemIndex++) { if (iblackList.IndexOf(itemIndex) < 0) { itemList.Add(itemIndex); } } foreach (ItemIndex itemIndex in itemList) { if (self.availableItems.HasItem(itemIndex)) { ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex); List <PickupIndex> list = null; switch (itemDef.tier) { case ItemTier.Tier1: list = self.availableTier1DropList; break; case ItemTier.Tier2: list = self.availableTier2DropList; break; case ItemTier.Tier3: list = self.availableTier3DropList; break; case ItemTier.Lunar: list = self.availableLunarDropList; break; } if (list != null) { list.Add(new PickupIndex(itemIndex)); } } } /* * Loop through EquipmentIndex and omit adding banned equipment to the eqipmentDropList. */ for (EquipmentIndex equipIndex = EquipmentIndex.CommandMissile; equipIndex < EquipmentIndex.Count; equipIndex++) { if (eblackList.IndexOf(equipIndex) < 0) { equipList.Add(equipIndex); } } foreach (EquipmentIndex equipmentIndex in equipList) { if (self.availableEquipment.HasEquipment(equipmentIndex)) { EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(equipmentIndex); if (equipmentDef.canDrop) { if (!equipmentDef.isLunar) { self.availableEquipmentDropList.Add(new PickupIndex(equipmentIndex)); } else { self.availableLunarDropList.Add(new PickupIndex(equipmentIndex)); } } } } self.smallChestDropTierSelector.Clear(); self.smallChestDropTierSelector.AddChoice(self.availableTier1DropList, 0.8f); self.smallChestDropTierSelector.AddChoice(self.availableTier2DropList, 0.2f); self.smallChestDropTierSelector.AddChoice(self.availableTier3DropList, 0.01f); self.mediumChestDropTierSelector.Clear(); self.mediumChestDropTierSelector.AddChoice(self.availableTier2DropList, 0.8f); self.mediumChestDropTierSelector.AddChoice(self.availableTier3DropList, 0.2f); self.largeChestDropTierSelector.Clear(); }; }