public static void SetupPlagueTendrils(GameObject effects) { var plagueTendrils = effects.gameObject.AddComponent <PlagueAuraTendrils>(); var orig = ResourcesPrefabManager.Instance.GetItemPrefab(8300180).GetComponentInChildren <ShootBlast>(); At.CopyFields(plagueTendrils, orig, null, true); plagueTendrils.InstanstiatedAmount = 2; plagueTendrils.NoTargetForwardMultiplier = 0f; // disable clone target before cloning it var origBlast = plagueTendrils.BaseBlast.gameObject; origBlast.SetActive(false); var newBlast = GameObject.Instantiate(origBlast); GameObject.DontDestroyOnLoad(newBlast); //newBlast.SetActive(true); newBlast.name = "PlagueTendrils"; var blast = newBlast.GetComponent <BlastGround>(); plagueTendrils.BaseBlast = blast; newBlast.transform.Find("mdl_Fx@LichDarkTendril_c").localScale = new Vector3(0.5f, 0.5f, 0.5f); // change damage and hit effects var hit = blast.transform.Find("Effects").gameObject; hit.GetComponent <PunctualDamage>().Damages = NecromancerMod.settings.PlagueAura_TendrilDamage; hit.GetComponent <PunctualDamage>().Knockback = NecromancerMod.settings.PlagueAura_TendrilKnockback; var comp = hit.AddComponent <AddStatusEffectBuildUp>(); comp.Status = ResourcesPrefabManager.Instance.GetStatusEffectPrefab("Cripple"); comp.BuildUpValue = 100; }
//public static float LifeSpan = 40f; #region Plague Aura Skill Setup // this also sets up the PlagueTendrils effect. public static void SetupPlagueAura() { // 8890107 var plagueSkill = ResourcesPrefabManager.Instance.GetItemPrefab(8890107) as Skill; // destroy wind altar condition Destroy(plagueSkill.transform.Find("AdditionalActivationConditions").gameObject); // setup skill plagueSkill.CastSheathRequired = -1; plagueSkill.RequiredItems = new Skill.ItemRequired[0]; // get the Summon component, change to custom activation fx var effects = plagueSkill.transform.Find("Effects").gameObject; var origSummon = effects.GetComponent <Summon>(); var plagueAuraComp = effects.AddComponent <PlagueAura>(); At.CopyFields(plagueAuraComp, origSummon, null, true); Destroy(origSummon); // ======== set summoned prefab to our custom activated item (loaded with sideloader) ======== var plagueStone = ResourcesPrefabManager.Instance.GetItemPrefab(8999050); plagueAuraComp.SummonedPrefab = plagueStone.transform; var ephemeral = plagueStone.GetComponent <Ephemeral>(); ephemeral.LifeSpan = NecromancerBase.settings.PlagueAura_SigilLifespan; //// setup custom visuals //var origVisuals = plagueStone.GetComponent<Item>().VisualPrefab; //origVisuals.gameObject.SetActive(false); //var newVisuals = Instantiate(origVisuals.gameObject); //DontDestroyOnLoad(newVisuals); //origVisuals.gameObject.SetActive(true); var newVisuals = CustomItemVisuals.GetOrAddVisualLink(plagueStone).ItemVisuals; var magiccircle = newVisuals.transform.Find("mdl_fx_magicCircle"); // destroy rotating bolt fx Destroy(magiccircle.transform.Find("FX_Bolt").gameObject); // setup the clouds if (newVisuals.transform.Find("mdl_itm_firestone") is Transform t) { t.parent = magiccircle; Destroy(t.Find("FX_Bolt").gameObject); var ps = t.Find("smoke_desu").GetComponent <ParticleSystem>(); var m = ps.main; m.startColor = Color.green; t.Find("smoke_desu").position += Vector3.down * 3.2f; } // setup the Plague Tendrils effect (from inside that class) PlagueAuraTendrils.SetupPlagueTendrils(effects); }
/// <summary> /// Gets a copy of Component and adds it to the transform provided. /// </summary> /// <typeparam name="T">The Type of Component which will be added to the transform.</typeparam> /// <param name="component">The existing component to copy from (and the T if not directly supplied)</param> /// <param name="transform">The Transform to add to</param> /// <returns></returns> public static T GetCopyOf <T>(T component, Transform transform) where T : Component { var comp = transform.gameObject.AddComponent <T>(); At.CopyProperties(comp, component, null, true); At.CopyFields(comp, component, null, true); return(comp as T); }
internal override void CopyValuesFrom(object data) { var origPack = RefPack.Name; var origSub = this.Template.SerializedSubfolderName; var origFile = this.Template.SerializedFilename; At.CopyFields(Target, data, null, true); UpdateValues(); //base.CopyValuesFrom(data); Template = Target as ContentTemplate; Template.SerializedFilename = origFile; Template.SerializedSubfolderName = origSub; Template.SerializedSLPackName = origPack; }
/// <summary> /// Replaces existingComponent type with desiredType ONLY if desiredType is not assignable from the existingComponent type. /// That means if desiredType is Item and existingComponent type is Weapon, this will do nothing. /// If both types are the same, this will do nothing. /// Otherwise, this will replace existingComponent with a desiredType component and inherit all possible values. /// </summary> /// <param name="desiredType">The desired class type (the game type, not the SL type)</param> /// <param name="existingComponent">The existing component</param> /// <returns>The component left on the transform after the method runs.</returns> public static Component FixComponentType(Type desiredType, Component existingComponent) { if (!existingComponent || !existingComponent.transform || desiredType == null || desiredType.IsAbstract) { return(existingComponent); } var currentType = existingComponent.GetType(); // If currentType derives from desiredType (or they are the same type), do nothing // This is to allow using basic SL_Item (or whatever) templates on more complex types without replacing them. if (desiredType.IsAssignableFrom(currentType)) { return(existingComponent); } var newComp = existingComponent.gameObject.AddComponent(desiredType); while (!currentType.IsAssignableFrom(desiredType) && currentType.BaseType != null && currentType.BaseType != typeof(MonoBehaviour)) { // Desired type does not derive from current type. // We need to recursively dive through currentType's BaseTypes until we find a type we can assign from. // Eg, current is MeleeWeapon and we want a ProjectileWeapon. We need to get the common base class (Weapon, in that case). // When currentType reaches Weapon, Weapon.IsAssignableFrom(ProjectileWeapon) will return true. // We also want to make sure we didnt reach MonoBehaviour, and at least got a game class. currentType = currentType.BaseType; } // Final check if the value copying is valid, after operations above. if (currentType.IsAssignableFrom(desiredType)) { // recursively get all the values At.CopyProperties(newComp, existingComponent, currentType, true); At.CopyFields(newComp, existingComponent, currentType, true); } else { SL.Log($"FixComponentTypeIfNeeded - could not find a compatible type of {currentType.Name} which is assignable to desired type: {desiredType.Name}!"); } // remove the old component GameObject.DestroyImmediate(existingComponent); return(newComp); }
// skill setup called by Skillmanager init #region Detonate Skill public static void SetupDetonate() { var detonateSkill = ResourcesPrefabManager.Instance.GetItemPrefab(8890106) as AttackSkill; // setup skill detonateSkill.CastSheathRequired = -1; detonateSkill.RequiredOffHandTypes.Clear(); detonateSkill.RequiredTags = new TagSourceSelector[0]; detonateSkill.StartVFX = null; // destroy these existing effects Destroy(detonateSkill.transform.Find("RunicRay").gameObject); DestroyImmediate(detonateSkill.transform.Find("Effects").gameObject); // hang onto the ShootBlast, we want to use this var shootBlast = detonateSkill.transform.Find("RunicBlast").GetChild(0).GetComponent <ShootBlast>(); // ======== setup weak blast ============ // create new Effects object var effects = new GameObject("Effects"); effects.transform.parent = detonateSkill.transform; var detonateBlast = effects.AddComponent <DeathRitual>(); At.CopyFields(detonateBlast, shootBlast, null, true); // destroy the old RunicBlast now that we stole the blast component Destroy(detonateSkill.transform.Find("RunicBlast").gameObject); // add condition. Required item on summon is Mertons Bones. var condition = effects.AddComponent <DeathRitualCondition>(); condition.RequiredSummonEquipment = 3200030; condition.Invert = false; // disable clone target before cloning it var origBlast = detonateBlast.BaseBlast.gameObject; origBlast.SetActive(false); var blastObj = Instantiate(origBlast); DontDestroyOnLoad(blastObj); blastObj.name = "DetonateBlast"; var blast = blastObj.GetComponentInChildren <CircularBlast>(); detonateBlast.BaseBlast = blast; if (blast.GetComponentInChildren <PunctualDamage>() is PunctualDamage pDamage) { pDamage.Damages = NecromancerBase.settings.DeathRitual_WeakExplosionDamage; pDamage.Knockback = NecromancerBase.settings.DeathRitual_WeakKnockback; } var explosionFX = blast.transform.Find("ExplosionFX").gameObject; foreach (var particles in explosionFX.GetComponentsInChildren <ParticleSystem>()) { var m = particles.main; m.startColor = Color.green; } // =========== STRONG DETONATION (blue ghost) ================= // var effects2 = new GameObject("Effects"); effects2.transform.parent = detonateSkill.transform; var detonateBlast2 = effects2.AddComponent <DeathRitual>(); At.CopyFields(detonateBlast2, detonateBlast, null, true); // add condition. Required item on summon is Blue Ghost robes. var condition2 = effects2.AddComponent <DeathRitualCondition>(); condition2.RequiredSummonEquipment = 3200040; condition2.Invert = false; origBlast.SetActive(false); var blastObj2 = Instantiate(origBlast); origBlast.SetActive(false); DontDestroyOnLoad(blastObj2); blastObj2.name = "StrongDetonateBlast"; var blast2 = blastObj2.GetComponent <CircularBlast>(); detonateBlast2.BaseBlast = blast2; if (blast2.GetComponentInChildren <PunctualDamage>() is PunctualDamage pDamage2) { pDamage2.Damages = NecromancerBase.settings.DeathRitual_StrongExplosionDamage; pDamage2.Knockback = NecromancerBase.settings.DeathRitual_StrongKnockback; var comp = pDamage2.gameObject.AddComponent <AddStatusEffect>(); comp.Status = ResourcesPrefabManager.Instance.GetStatusEffectPrefab("Slow Down"); } var explosionFX2 = blast2.transform.Find("ExplosionFX").gameObject; foreach (ParticleSystem particles in explosionFX2.GetComponentsInChildren <ParticleSystem>()) { var m = particles.main; m.startColor = new Color() { r = 0.2f, g = 0.4f, b = 1, a = 1 }; // cyan-ish } }
public static void SetupTendrils() { // ============== setup base skill ============== var tendrils = ResourcesPrefabManager.Instance.GetItemPrefab(8890100) as AttackSkill; // setup skill tendrils.CastModifier = Character.SpellCastModifier.Mobile; // can move while casting but movement speed is 0.3x tendrils.MobileCastMovementMult = 0.3f; // clear existing effects SideLoader.Helpers.UnityHelpers.DestroyChildren(tendrils.transform); // ============= normal effects =============== // // create new effects var effects = new GameObject("Effects"); effects.transform.parent = tendrils.transform; // add our custom PlagueAura proximity condition component (INVERT = TRUE, we DONT want the aura on these effects). var auraCondition1 = effects.AddComponent <PlagueAuraProximityCondition>(); auraCondition1.ProximityDist = 2.5f; auraCondition1.Invert = true; // create the Tendrils effect, a custom class derived from ShootProjectile NoxiousTendrils shootTendrils = effects.AddComponent <NoxiousTendrils>(); var orig = ResourcesPrefabManager.Instance.GetItemPrefab(8300292).transform.Find("Effects").GetComponent <ShootProjectile>(); At.CopyFields(shootTendrils, orig, null, true); shootTendrils.SyncType = Effect.SyncTypes.Everyone; // disable clone target before cloning it var origProjectile = shootTendrils.BaseProjectile.gameObject; origProjectile.SetActive(false); var projectileObj = GameObject.Instantiate(origProjectile); GameObject.DontDestroyOnLoad(projectileObj); //projectileObj.SetActive(true); projectileObj.name = "NoxiousTendrils"; // get the actual Projectile component from our new Projectile Object, and set our "BaseProjectile" to this component var projectile = projectileObj.GetComponent <RaycastProjectile>(); shootTendrils.BaseProjectile = projectile; shootTendrils.IntanstiatedAmount = 8; // 2 per character, potential 3 summoned skeletons, so 8 total subeffects needed. projectile.Lifespan = 0.75f; projectile.DisableOnHit = false; projectile.EndMode = Projectile.EndLifeMode.LifetimeOnly; projectile.HitEnemiesOnly = true; // sound play if (projectileObj.GetComponentInChildren <SoundPlayer>() is SoundPlayer lightPlayer) { lightPlayer.Sounds = new List <GlobalAudioManager.Sounds> { GlobalAudioManager.Sounds.SFX_FireThrowLight }; } // heal on hit if (projectile.GetComponentInChildren <AffectHealthParentOwner>() is AffectHealthParentOwner heal) { heal.AffectQuantity = NecromancerMod.settings.ShootTendrils_Heal_NoPlagueAura; } // change damage and hit effects var hit = projectile.transform.Find("HitEffects").gameObject; hit.GetComponent <PunctualDamage>().Damages = NecromancerMod.settings.ShootTendrils_Damage_NoPlagueAura; hit.GetComponent <PunctualDamage>().Knockback = NecromancerMod.settings.ShootTendrils_Knockback_NoPlagueAura; var comp = hit.AddComponent <AddStatusEffectBuildUp>(); comp.Status = ResourcesPrefabManager.Instance.GetStatusEffectPrefab("Curse"); comp.BuildUpValue = 25; // adjust visuals foreach (ParticleSystem ps in projectileObj.GetComponentsInChildren <ParticleSystem>()) { var m = ps.main; m.startColor = Color.green; m.startSize = new ParticleSystem.MinMaxCurve(0.05f, 0.09f); } // ================= plague aura interaction effects =============== var plagueEffectsObj = new GameObject("Effects"); plagueEffectsObj.transform.parent = tendrils.transform; // add our custom PlagueAura proximity condition component var auraCondition2 = plagueEffectsObj.AddComponent <PlagueAuraProximityCondition>(); auraCondition2.ProximityDist = 2.5f; auraCondition2.Invert = false; // add our custom ShootTendrils component NoxiousTendrils strongTendrils = plagueEffectsObj.AddComponent <NoxiousTendrils>(); At.CopyFields(strongTendrils, orig, null, true); // clone the projectile origProjectile.SetActive(false); var strongProjObj = GameObject.Instantiate(origProjectile); GameObject.DontDestroyOnLoad(strongProjObj); origProjectile.SetActive(true); strongProjObj.name = "StrongNoxiousTendrils"; var strongProj = strongProjObj.GetComponent <RaycastProjectile>(); strongTendrils.BaseProjectile = strongProj; strongTendrils.IntanstiatedAmount = 8; strongProj.Lifespan = 0.75f; strongProj.DisableOnHit = false; strongProj.EndMode = Projectile.EndLifeMode.LifetimeOnly; strongProj.HitEnemiesOnly = true; // sound play if (strongProjObj.GetComponentsInChildren <SoundPlayer>() is SoundPlayer[] strongPlayers && strongPlayers.Count() > 0) { foreach (SoundPlayer player in strongPlayers) { player.Sounds = new List <GlobalAudioManager.Sounds> { GlobalAudioManager.Sounds.SFX_SKILL_ElemantalProjectileWind_Shot }; } } // heal on hit if (strongProj.GetComponentInChildren <AffectHealthParentOwner>() is AffectHealthParentOwner strongHeal) { //DestroyImmediate(heal); strongHeal.AffectQuantity = NecromancerMod.settings.ShootTendrils_Heal_InsideAura; } // change damage and hit effects. var strongHit = strongProj.transform.Find("HitEffects").gameObject; strongHit.GetComponent <PunctualDamage>().Damages = NecromancerMod.settings.ShootTendrils_Damage_InsideAura; strongHit.GetComponent <PunctualDamage>().Knockback = NecromancerMod.settings.ShootTendrils_Knockback_InsideAura; comp = strongHit.AddComponent <AddStatusEffectBuildUp>(); comp.Status = ResourcesPrefabManager.Instance.GetStatusEffectPrefab("Curse"); comp.BuildUpValue = 60; // adjust visuals foreach (ParticleSystem ps in strongProjObj.GetComponentsInChildren <ParticleSystem>()) { var m = ps.main; m.startColor = Color.green; m.startSize = new ParticleSystem.MinMaxCurve(0.12f, 0.20f); } }