public void LocalTrainerSetup(Character trainer, string _) { // remove unwanted components DestroyImmediate(trainer.GetComponent <CharacterStats>()); DestroyImmediate(trainer.GetComponent <StartingEquipment>()); // add NPCLookFollow component trainer.gameObject.AddComponent <NPCLookFollow>(); // =========== setup Trainer DialogueTree from the template =========== var trainertemplate = Instantiate(Resources.Load("editor/templates/TrainerTemplate")) as GameObject; trainertemplate.transform.parent = trainer.transform; trainertemplate.transform.position = trainer.transform.position; // set Dialogue Actor name var necroActor = trainertemplate.GetComponentInChildren <DialogueActor>(); necroActor.SetName(trainerTemplate.Name); // get "Trainer" component, and set the SkillTreeUID to our custom tree UID Trainer trainerComp = trainertemplate.GetComponentInChildren <Trainer>(); At.SetValue(SkillManager.NecromancyTree.UID, typeof(Trainer), trainerComp, "m_skillTreeUID"); // setup dialogue tree var graphController = trainertemplate.GetComponentInChildren <DialogueTreeController>(); var graph = (graphController as GraphOwner <DialogueTreeExt>).graph; // the template comes with an empty ActorParameter, we can use that for our NPC actor. var actors = At.GetValue(typeof(DialogueTree), graph as DialogueTree, "_actorParameters") as List <DialogueTree.ActorParameter>; actors[0].actor = necroActor; actors[0].name = necroActor.name; // setup the actual dialogue now List <Node> nodes = At.GetValue(typeof(Graph), graph, "_nodes") as List <Node>; var rootStatement = graph.AddNode <StatementNodeExt>(); rootStatement.statement = new Statement("Do you seek to harness the power of Corruption, traveler?"); rootStatement.SetActorName(necroActor.name); var multiChoice1 = graph.AddNode <MultipleChoiceNodeExt>(); multiChoice1.availableChoices.Add(new MultipleChoiceNodeExt.Choice { statement = new Statement { text = "I'm interested, what can you teach me?" } }); multiChoice1.availableChoices.Add(new MultipleChoiceNodeExt.Choice { statement = new Statement { text = "Who are you?" } }); multiChoice1.availableChoices.Add(new MultipleChoiceNodeExt.Choice { statement = new Statement { text = "What is this place?" } }); // the template already has an action node for opening the Train menu. // Let's grab that and change the trainer to our custom Trainer component (setup above). var openTrainer = nodes[1] as ActionNode; (openTrainer.action as TrainDialogueAction).Trainer = new BBParameter <Trainer>(trainerComp); // create some custom dialogue var answer1 = graph.AddNode <StatementNodeExt>(); answer1.statement = new Statement("I wish I could remember..."); answer1.SetActorName(necroActor.name); var answer2 = graph.AddNode <StatementNodeExt>(); answer2.statement = new Statement("This is the fortress of the Plague Doctor, a powerful Lich. I've learned a lot about Corruption within these walls."); answer2.SetActorName(necroActor.name); // ===== finalize nodes ===== nodes.Clear(); // add the nodes we want to use nodes.Add(rootStatement); nodes.Add(multiChoice1); nodes.Add(openTrainer); nodes.Add(answer1); nodes.Add(answer2); graph.primeNode = rootStatement; graph.ConnectNodes(rootStatement, multiChoice1); // prime node triggers the multiple choice graph.ConnectNodes(multiChoice1, openTrainer, 0); // choice1: open trainer graph.ConnectNodes(multiChoice1, answer1, 1); // choice2: answer1 graph.ConnectNodes(answer1, rootStatement); // - choice2 goes back to root node graph.ConnectNodes(multiChoice1, answer2, 2); // choice3: answer2 graph.ConnectNodes(answer2, rootStatement); // - choice3 goes back to root node // set root node // set the trainer active trainer.gameObject.SetActive(true); }
// skill setup called from SkillManager #region Tendrils Skill Setup 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.SL.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.RequiredActivatedItemID = 8999050; auraCondition1.Invert = true; // create the Tendrils effect, a custom class derived from ShootProjectile ShootTendrils shootTendrils = effects.AddComponent <ShootTendrils>(); var orig = ResourcesPrefabManager.Instance.GetItemPrefab(8300292).transform.Find("Effects").GetComponent <ShootProjectile>(); At.InheritBaseValues(shootTendrils, orig); shootTendrils.SyncType = SyncTypes.Everyone; // disable clone target before cloning it var origProjectile = shootTendrils.BaseProjectile.gameObject; origProjectile.SetActive(false); var projectileObj = Instantiate(origProjectile); 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 = NecromancyBase.settings.ShootTendrils_Heal_NoPlagueAura; } // change damage and hit effects var hit = projectile.transform.Find("HitEffects").gameObject; hit.GetComponent <PunctualDamage>().Damages = NecromancyBase.settings.ShootTendrils_Damage_NoPlagueAura; hit.GetComponent <PunctualDamage>().Knockback = NecromancyBase.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.RequiredActivatedItemID = 8999050; auraCondition2.Invert = false; // add our custom ShootTendrils component ShootTendrils strongTendrils = plagueEffectsObj.AddComponent <ShootTendrils>(); At.InheritBaseValues(strongTendrils, orig); // clone the projectile origProjectile.SetActive(false); var strongProjObj = Instantiate(origProjectile); 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 = NecromancyBase.settings.ShootTendrils_Heal_InsideAura; } // change damage and hit effects. var strongHit = strongProj.transform.Find("HitEffects").gameObject; strongHit.GetComponent <PunctualDamage>().Damages = NecromancyBase.settings.ShootTendrils_Damage_InsideAura; strongHit.GetComponent <PunctualDamage>().Knockback = NecromancyBase.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); } }
// 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 <DetonateBlast>(); At.InheritBaseValues(detonateBlast, shootBlast); // 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 <DetonateCondition>(); 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 = new DamageType[] //{ // new DamageType(DamageType.Types.Decay, 40), // new DamageType(DamageType.Types.Ethereal, 20) //}; pDamage.Damages = NecromancyBase.settings.DeathRitual_WeakExplosionDamage; //pDamage.Knockback = 75; pDamage.Knockback = NecromancyBase.settings.DeathRitual_WeakKnockback; } var explosionFX = blast.transform.Find("ExplosionFX").gameObject; foreach (ParticleSystem 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 <DetonateBlast>(); At.InheritBaseValues(detonateBlast2, detonateBlast); // add condition. Required item on summon is Blue Ghost robes. var condition2 = effects2.AddComponent <DetonateCondition>(); 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 = new DamageType[] { new DamageType(DamageType.Types.Decay, 50), new DamageType(DamageType.Types.Ethereal, 20), new DamageType(DamageType.Types.Frost, 20) }; pDamage2.Knockback = 150; 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 } }