public override void WriteNewHooks() { bool runStockScaling = FireboltAttackSpeedStockScaling.Value && FireboltAttackSpeedStockScalingCoefficient.IsNotDefault(); bool runCooldownScaling = FireboltAttackSpeedCooldownScaling.Value && FireboltAttackSpeedCooldownScalingCoefficient.IsNotDefault(); float cooldownCoeff = FireboltAttackSpeedCooldownScalingCoefficient.FloatValue; float stockCoeff = FireboltAttackSpeedStockScalingCoefficient.FloatValue; if (runStockScaling || runCooldownScaling) { IL.RoR2.CharacterBody.RecalculateStats += il => { ILCursor c = new ILCursor(il); c.GotoNext(x => x.MatchRet() ); c.Emit(OpCodes.Ldarg_0); c.Emit <CharacterBody>(OpCodes.Ldfld, "skillLocator"); c.Emit(OpCodes.Ldloc_S, (byte)45); c.Emit(OpCodes.Ldloc_S, (byte)42); c.EmitDelegate <Action <SkillLocator, float, float> >( (skillLocator, cooldownScale, attackSpeed) => { GenericSkill primary = skillLocator != null ? skillLocator.primary : null; if (primary != null && primary.skillName == "FireFirebolt") { if (runCooldownScaling) { float val = cooldownScale * (1 / (1 + cooldownCoeff * (attackSpeed - 1))); primary.cooldownScale = val; } if (runStockScaling) { primary.SetBonusStockFromBody( (int)((attackSpeed - 1) * stockCoeff * primary.baseMaxStock)); } } }); }; } On.EntityStates.Mage.Weapon.Flamethrower.OnEnter += (orig, self) => { Type flamethrowerType = self.GetType(); GameObject go = typeof(EntityState) .GetProperty("gameObject", BindingFlags.NonPublic | BindingFlags.Instance) ?.GetValue(self) as GameObject; CharacterBody body = go.GetComponent <CharacterBody>(); if (FlamethrowerTickFrequencyScaleWithAttackSpeed.Value && FlamethrowerTickFrequencyScaleCoefficient.IsNotDefault()) { float baseVal = FlamethrowerTickFrequency.ValueConfigWrapper.IsNotDefault() ? FlamethrowerTickFrequency.ValueConfigWrapper.FloatValue : VanillaFlamethrowerTickFrequency; float val = baseVal + (body.attackSpeed - 1) * FlamethrowerTickFrequencyScaleCoefficient.FloatValue * baseVal ; flamethrowerType.SetFieldValue("tickFrequency", val ); } if (FlamethrowerDurationScaleDownWithAttackSpeed.Value && FlamethrowerDurationScaleCoefficient.IsNotDefault()) { float baseVal = FlamethrowerDuration.ValueConfigWrapper.IsNotDefault() ? FlamethrowerDuration.ValueConfigWrapper.FloatValue : VanillaFlamethrowerDuration; float val = baseVal - (body.attackSpeed - 1) * FlamethrowerDurationScaleCoefficient.FloatValue * baseVal; if (val < FlamethrowerMinimalDuration.FloatValue) { val = FlamethrowerMinimalDuration.FloatValue; } flamethrowerType.SetFieldValue("baseFlamethrowerDuration", val ); } orig(self); }; }
public override void OverrideGameValues() { MineMaxDeployCount.SetDefaultValue(10); TurretMaxDeployCount.SetDefaultValue(2); ShieldMaxDeployCount.SetDefaultValue(1); if (MineMaxDeployCount.IsNotDefault() || TurretMaxDeployCount.IsNotDefault() || ShieldMaxDeployCount.IsNotDefault()) { IL.RoR2.CharacterMaster.AddDeployable += il => { var c = new ILCursor(il).Goto(0); c.GotoNext( x => x.MatchStloc(1), x => x.MatchLdarg(0) ); c.Index += 1; c.Next.OpCode = OpCodes.Nop; c.Index += 1; c.Emit(OpCodes.Ldloc_1); c.Emit(OpCodes.Ldarg_0); c.Emit(OpCodes.Ldarg_2); c.EmitDelegate <Func <int, CharacterMaster, DeployableSlot, int> >((maxDeploy, self, slot) => { switch (slot) { case DeployableSlot.EngiMine: if (MineMaxDeployCount.IsNotDefault()) { maxDeploy = MineMaxDeployCount.Value; } break; case DeployableSlot.EngiTurret: if (TurretMaxDeployCount.IsNotDefault()) { maxDeploy = TurretMaxDeployCount.Value; } break; case DeployableSlot.EngiBubbleShield: if (ShieldMaxDeployCount.IsNotDefault()) { maxDeploy = ShieldMaxDeployCount.Value; } break; } return(maxDeploy); }); c.Emit(OpCodes.Stloc_1); c.Emit(OpCodes.Ldarg_0); }; } // Workaround for more than 8 max grenades if (GrenadeMinFireAmount.ValueConfigWrapper.Value >= 8 || GrenadeMaxFireAmount.ValueConfigWrapper.Value >= 8) { On.EntityStates.Engi.EngiWeapon.FireGrenades.OnEnter += (orig, self) => { Assembly assembly = self.GetType().Assembly; Type fireGrenades = assembly.GetClass("EntityStates.Engi.EngiWeapon", "FireGrenades"); orig(self); self.SetFieldValue("duration", fireGrenades.GetFieldValue <float>("baseDuration") * self.GetFieldValue <int>("grenadeCountMax") / 8f / self.GetFieldValue <float>("attackSpeedStat") ); }; } // typeof(RoR2Application).Assembly doesn't seem to work On.RoR2.RoR2Application.Start += (orig, self) => { orig(self); Assembly assembly = self.GetType().Assembly; Type shieldDeployed = typeof(EntityStates.Engi.EngiBubbleShield.Deployed); ShieldDeployedFields.ForEach(changer => changer.Apply(shieldDeployed)); if (ShieldEndlessDuration.Value) { EntityStates.Engi.EngiBubbleShield.Deployed.lifetime = float.PositiveInfinity; } Type chargeGrenades = assembly.GetClass("EntityStates.Engi.EngiWeapon", "ChargeGrenades"); ChargeGrenadesFields.ForEach(changer => changer.Apply(chargeGrenades)); if (GrenadeSetChargeCountToFireAmount.Value && GrenadeMaxFireAmount.ValueConfigWrapper.IsNotDefault()) { chargeGrenades.SetFieldValue("maxCharges", GrenadeMaxFireAmount.ValueConfigWrapper.Value); } }; }
public override void WriteNewHooks() { if (BarrageScalesWithAttackSpeed.Value && BarrageScaleModifier.IsNotDefault()) { On.EntityStates.Commando.CommandoWeapon.FireBarrage.OnEnter += (orig, self) => { orig(self); Assembly assembly = self.GetType().Assembly; Type fireBarr = assembly.GetClass("EntityStates.Commando.CommandoWeapon", "FireBarrage"); FieldInfo attackSpeed = typeof(BaseState).GetField("attackSpeedStat", BindingFlags.NonPublic | BindingFlags.Instance); FieldInfo durationBetweenShots = fireBarr.GetField("durationBetweenShots", BindingFlags.NonPublic | BindingFlags.Instance); float attackSpeedF = (float)attackSpeed?.GetValue(self); int baseShot = BarrageBaseShotAmount.ValueConfigWrapper.IsDefault() ? VanillaBarrageBaseShotAmount : BarrageBaseShotAmount.ValueConfigWrapper.Value; durationBetweenShots?.SetValue(self, (BarrageBaseDurationBetweenShots.ValueConfigWrapper.IsDefault() ? VanillaBarrageBaseDurationBetweenShots : BarrageBaseDurationBetweenShots.ValueConfigWrapper.FloatValue) / attackSpeedF / BarrageScaleModifier.FloatValue); fireBarr.SetFieldValue("bulletCount", baseShot + (int)((attackSpeedF - 1) * BarrageScaleModifier.FloatValue * baseShot)); }; } On.EntityStates.Commando.DodgeState.OnEnter += (orig, self) => { orig(self); if (DashResetsSecondCooldown.Value) { Assembly assembly = self.GetType().Assembly; Type entityState = assembly.GetClass("EntityStates", "EntityState"); SkillLocator locator = (SkillLocator)entityState .GetProperty("skillLocator", BindingFlags.NonPublic | BindingFlags.Instance) ?.GetValue(self, null); GenericSkill skill2 = locator.GetSkill(SkillSlot.Secondary); skill2.Reset(); } if (DashInvulnerability.Value) { if (DashInvulnerabilityTimer.IsDefault()) { Transform transform = self.InvokeMethod <Transform>("GetModelTransform"); HurtBoxGroup hurtBoxGroup = transform.GetComponent <HurtBoxGroup>(); ++hurtBoxGroup.hurtBoxesDeactivatorCounter; } else { self.outer.commonComponents.characterBody.AddTimedBuff(BuffIndex.HiddenInvincibility, DashInvulnerabilityTimer.FloatValue); } } }; On.EntityStates.Commando.DodgeState.OnExit += (orig, self) => { if (DashInvulnerability.Value && DashInvulnerabilityTimer.IsDefault()) { Transform transform = self.InvokeMethod <Transform>("GetModelTransform"); HurtBoxGroup hurtBoxGroup = transform.GetComponent <HurtBoxGroup>(); --hurtBoxGroup.hurtBoxesDeactivatorCounter; } orig(self); }; if (PistolHitLowerBarrageCooldown.Value && PistolHitLowerBarrageCooldownPercent.IsNotDefault()) { Type gsType = typeof(GenericSkill); FieldInfo rechargeStopwatch = gsType.GetField("rechargeStopwatch", BindingFlags.NonPublic | BindingFlags.Instance); FieldInfo finalRechargeInterval = gsType.GetField("finalRechargeInterval", BindingFlags.NonPublic | BindingFlags.Instance); IL.EntityStates.Commando.CommandoWeapon.FirePistol2.FireBullet += il => { ILCursor c = new ILCursor(il); c.GotoNext(x => x.MatchCallvirt(typeof(RoR2.BulletAttack).FullName, "Fire")); c.EmitDelegate <Func <BulletAttack, BulletAttack> >((BulletAttack ba) => { ba.hitCallback = (ref BulletAttack.BulletHit info) => { bool result = ba.DefaultHitCallback(ref info); if (info.entityObject?.GetComponent <HealthComponent>()) { SkillLocator skillLocator = ba.owner.GetComponent <SkillLocator>(); GenericSkill special = skillLocator.special; rechargeStopwatch.SetValue(special, (float)rechargeStopwatch.GetValue(special) + (float)finalRechargeInterval.GetValue(special) * PistolHitLowerBarrageCooldownPercent.FloatValue); } return(result); }; return(ba); }); }; } }