public MyCueBank(XAudio2 audioEngine, MyObjectBuilder_CueDefinitions cues) { m_audioEngine = audioEngine; if (cues.Cues.Length > 0) { InitTransitionCues(); InitMusicCategories(); m_cues = new Dictionary <int, MyObjectBuilder_CueDefinition>(cues.Cues.Length); InitCues(cues); InitCategories(); InitWaveBank(); InitVoicePools(); #if DEBUG ValidateCues(); #endif //DEBUG InitNonLoopableCuesLimitRemoveHelper(); Reverb reverb = new Reverb(); m_effectDescriptor = new EffectDescriptor(reverb); } }
/**********************************************************************************/ // функция получения урона юнитом // /**********************************************************************************/ override public void ApplyDamage(DamageData damage) { if (m_state == UNIT_STATE.ACTIVE) { // объект получает урон m_armor.TakeDamage(damage); // накладываем визуальный эффект EffectDescriptor dE = new EffectDescriptor(); if (damage.DamageType == DamageData.DAMAGE_TYPE.ACID) { dE.Type = UnitEffect.EFFECT_TYPE.DAMAGE_ACID; } else { dE.Type = UnitEffect.EFFECT_TYPE.DAMAGE; } dE.Responsibility = EffectDescriptor.EffectResponsibility.REQUIRED; ApplyEffect(dE); // если есть возможность нанести ответный урон - делаем это if (damage.ExpectResponce == DamageData.RESPONSE.EXPECTED) { m_weaponMaster.UseCloseWeapon(damage.Damager, true); } } }
private void DirectSound_Start(object sender, EventArgs e) { soundStream = new SoundStream(File.OpenRead(loadFilePath)); WaveFormat format = soundStream.Format; AudioBuffer buffer = new AudioBuffer { Stream = soundStream.ToDataStream(), AudioBytes = (int)soundStream.Length, Flags = BufferFlags.EndOfStream }; soundStream.Close(); sourceVoice = new SourceVoice(xAudio2, format, true); sourceVoice.SubmitSourceBuffer(buffer, soundStream.DecodedPacketsInfo); sourceVoice.Start(); if (directSoundEffect == 0) { SharpDX.XAPO.Fx.Echo effectEcho = new SharpDX.XAPO.Fx.Echo(xAudio2); EffectDescriptor effectDescriptor = new EffectDescriptor(effectEcho); sourceVoice.SetEffectChain(effectDescriptor); sourceVoice.EnableEffect(0); } else if (directSoundEffect == 1) { SharpDX.XAPO.Fx.Reverb effectReverb = new SharpDX.XAPO.Fx.Reverb(xAudio2); EffectDescriptor effectDescriptor = new EffectDescriptor(effectReverb); sourceVoice.SetEffectChain(effectDescriptor); sourceVoice.EnableEffect(0); } }
/**********************************************************************************/ // функция применения эффектов // /**********************************************************************************/ public void ApplyEffect(EffectDescriptor effect) { if (!m_isActive) { return; } UnitEffect.EFFECT_TYPE eType = effect.Type; bool weHaveEffect = m_effects.ContainsKey(eType); bool effectWasApplied = false; if (weHaveEffect) { if (m_effects[eType] != null) { m_effects[eType].EffectProducer = effect.EffectProducer; m_effects[eType].Activate(effect.Value); effectWasApplied = true; } } if (effectWasApplied == false && effect.Responsibility == EffectDescriptor.EffectResponsibility.REQUIRED) { Debug.LogError("We cann't apply effect: " + eType + " !"); } }
public void TestCanConstructViaDelegate() { EffectDescriptor td = new EffectDescriptor(); td.Delegate = new EffectConstructionDelegate(Effect.TestFactory); Effect t = td.CreateEffect(3, null); Assert.AreEqual(typeof(Effect), t.GetType()); }
public void TestConstructsGenericEffect() { EffectDescriptor td = new EffectDescriptor(); GenericEffect gt = td.CreateEffect(3, new XmlNodeInformation(new CommonNamespaces(OpenXmlFormat.Transitional))) as GenericEffect; Assert.IsNotNull(gt); Assert.IsTrue(td == gt.Descriptor); Assert.AreEqual(3, gt.Depth); }
public void TestAdditionalLevelsToInclude() { EffectDescriptor td = new EffectDescriptor(); td.AdditionalLevels = 2; GenericEffect gt = td.CreateEffect(3, new XmlNodeInformation(new CommonNamespaces(OpenXmlFormat.Transitional))) as GenericEffect; Assert.IsNotNull(gt); Assert.IsTrue(td == gt.Descriptor); Assert.AreEqual(1, gt.Depth); }
public void AddEffect(EffectDescriptor effect) { List <EffectDescriptor> effectList = new List <EffectDescriptor>(); if (effects != null) { effectList.AddRange(effects); } effectList.Add(effect); SetEffects(effectList); }
/**********************************************************************************/ // функция применения эффектов // /**********************************************************************************/ public override void ApplyEffect(EffectDescriptor effect) { UnitEffect.EFFECT_TYPE eType = effect.Type; bool weHaveEffect = m_effects.ContainsKey(eType); if (weHaveEffect) { m_effects[eType].EffectProducer = effect.EffectProducer; m_effects[eType].Activate(effect.Value); } else if (effect.Responsibility == EffectDescriptor.EffectResponsibility.REQUIRED) { Debug.LogError("We cann't apply effect: " + eType + " !"); } }
/// <summary> /// Adds the effect. /// </summary> /// <param name="effectName">Effect name.</param> /// <param name="modifier">Modifier.</param> /// <param name="duration">Duration (if == MaxValue - this is constant effect).</param> /// <param name="fxPrefab">Fx prefab.</param> public void AddEffect(string effectName, float modifier, float duration, GameObject fxPrefab) { // Get effect handler from effect name MethodInfo methodInfo = GetType().GetMethod(effectName, BindingFlags.Instance | BindingFlags.NonPublic); if (methodInfo != null) { EffectDescriptor hit = null; // Serch if same effect already active foreach (EffectDescriptor sem in effectList) { if (effectName == sem.name) { hit = sem; break; } } if (hit == null) // Have no such active effect { EffectDescriptor newSem = new EffectDescriptor(); newSem.name = effectName; // Create effect newSem.effects.Add(modifier, Time.time + duration); // Add it to list effectList.Add(newSem); // Play visual effect if (fxPrefab != null) { newSem.fx = Instantiate(fxPrefab, transform); } // Effect added methodInfo.Invoke(this, new object[] { EffectTrigger.Added, modifier }); } else // Already have same effect { // Add it to current list hit.effects.Add(modifier, Time.time + duration); // One more modifier added to existing effect methodInfo.Invoke(this, new object[] { EffectTrigger.NewModifier, modifier }); } } else { Debug.LogError("Unknown effect - " + effectName); } }
public PlayForm() { InitializeComponent(); // Initalize XAudio2 xaudio2 = new XAudio2(XAudio2Flags.None, ProcessorSpecifier.DefaultProcessor); masteringVoice = new MasteringVoice(xaudio2); var waveFormat = new WaveFormat(44100, 32, 2); sourceVoice = new SourceVoice(xaudio2, waveFormat); int bufferSize = waveFormat.ConvertLatencyToByteSize(60000); DataStream dataStream = new DataStream(bufferSize, true, true); // Prepare the initial sound to modulate int numberOfSamples = bufferSize / waveFormat.BlockAlign; for (int i = 0; i < numberOfSamples; i++) { float value = (float)(Math.Cos(2 * Math.PI * 220.0 * i / waveFormat.SampleRate) * 0.5); dataStream.Write(value); dataStream.Write(value); } dataStream.Position = 0; audioBuffer = new AudioBuffer { Stream = dataStream, Flags = BufferFlags.EndOfStream, AudioBytes = bufferSize, LoopBegin = 0, LoopLength = numberOfSamples, LoopCount = AudioBuffer.LoopInfinite }; // Set the effect on the source ModulatorEffect = new ModulatorEffect(); modulatorDescriptor = new EffectDescriptor(ModulatorEffect); reverb = new Reverb(); effectDescriptor = new EffectDescriptor(reverb); //sourceVoice.SetEffectChain(modulatorDescriptor, effectDescriptor); sourceVoice.SetEffectChain(modulatorDescriptor); //sourceVoice.EnableEffect(0); this.Closed += new EventHandler(PlayForm_Closed); }
public MyCueBank(XAudio2 audioEngine, ListReader <MySoundData> cues) { m_audioEngine = audioEngine; if (cues.Count > 0) { m_cues = new Dictionary <MyCueId, MySoundData>(cues.Count, MyCueId.Comparer); InitTransitionCues(); InitCues(cues); InitCategories(); InitWaveBank(); InitVoicePools(); m_reverb = new Reverb(); m_effectDescriptor = new EffectDescriptor(m_reverb); } }
/// <summary> /// SharpDX XAudio2 sample. Plays a generated sound with some reverb. /// </summary> static void Main(string[] args) { var xaudio2 = new XAudio2(); var masteringVoice = new MasteringVoice(xaudio2); var waveFormat = new WaveFormat(44100, 32, 2); var sourceVoice = new SourceVoice(xaudio2, waveFormat); int bufferSize = waveFormat.ConvertLatencyToByteSize(60000); var dataStream = new DataStream(bufferSize, true, true); int numberOfSamples = bufferSize / waveFormat.BlockAlign; for (int i = 0; i < numberOfSamples; i++) { // cos(2 * PI * (220 + 4 * cos(2 * PI * 10 * t)) * t) * 0.5 double vibrato = Math.Cos(2 * Math.PI * 10.0 * i / waveFormat.SampleRate); float value = (float)(Math.Cos(2 * Math.PI * (220.0 + 4.0 * vibrato) * i / waveFormat.SampleRate) * 0.5); dataStream.Write(value); dataStream.Write(value); } dataStream.Position = 0; var audioBuffer = new AudioBuffer { Stream = dataStream, Flags = BufferFlags.EndOfStream, AudioBytes = bufferSize }; var reverb = new Reverb(xaudio2); var effectDescriptor = new EffectDescriptor(reverb); sourceVoice.SetEffectChain(effectDescriptor); sourceVoice.EnableEffect(0); sourceVoice.SubmitSourceBuffer(audioBuffer, null); sourceVoice.Start(); Console.WriteLine("Play sound"); for (int i = 0; i < 60; i++) { Console.Write("."); Console.Out.Flush(); Thread.Sleep(1000); } }
private bool RenderEffectFieldWithDelete(EffectDescriptor effect) { Expression expression = new Expression(effect.effectExpression, validVariables); expression.Parse(); string expressionError = string.Empty; if (!expression.isValid) { expressionError = expression.LastError; } effect.effectExpression = EditorGUI.TextField(new Rect(170, mainControlRectY, 400, 15), effectDisplayNames[effect.effectType], effect.effectExpression); bool result = GUI.Button(new Rect(600, mainControlRectY, 20, 15), "X"); if (!expression.isValid) { mainControlRectY += 20; EditorGUI.LabelField(new Rect(170, mainControlRectY, 700, 15), expressionError); } mainControlRectY += 20; return(result); }
public Track(XAudio2 xAudio2, Z2Sound baa, Dictionary <Tuple <byte, byte>, Instrument> instrumentTable, Dictionary <int, Sample> sampleTable) { engine = xAudio2; soundData = baa; this.instrumentTable = instrumentTable; this.sampleTable = sampleTable; voiceTable = new Dictionary <byte, NoteData>(); submix = new SubmixVoice(engine); Echo effect = new Echo(); EffectDescriptor effectDescriptor = new EffectDescriptor(effect) { InitialState = true, OutputChannelCount = 2 }; submix.SetEffectChain(effectDescriptor); EchoParameters effectParameter = new EchoParameters { Delay = 160f, Feedback = 0f, WetDryMix = 0f }; submix.SetEffectParameters(0, effectParameter); submix.EnableEffect(0); outputMatrix = new float[2]; Volume = 127; Pitch = 0; Pan = 63; panChanged = false; Bank = 0; Echo = 0; echoChanged = false; Instrument = 0; outputMatrix[0] = (outputMatrix[1] = 0.5f); }
private TriggeringNodeDefinition BuildMockTriggerNodeThing() { EffectDescriptor td = new EffectDescriptor(); td.AdditionalLevels = 2; td.ContentType = ContentType.SmallText; TriggeringNodeDefinition result = new TriggeringNodeDefinition(NamespaceId.w, "vanish", null, null, td); return result; }
/**********************************************************************************/ // функция применения эффектов // эффекты не применяются // /**********************************************************************************/ public override void ApplyEffect(EffectDescriptor effect) { }
/**********************************************************************************/ // функция применения эффектов // /**********************************************************************************/ abstract public void ApplyEffect(EffectDescriptor effect);
/**********************************************************************************/ // эффекты // /**********************************************************************************/ public override void ApplyEffect(EffectDescriptor effect) { // эффекты не применяются }
/**********************************************************************************/ // применяем эффеккт кислоты // /**********************************************************************************/ protected override void ApplyBilletEffect(Collision2D coll) { EffectDescriptor effectDescr = new EffectDescriptor(UnitEffect.EFFECT_TYPE.ACID, damage, this, EffectDescriptor.EffectResponsibility.TRY_TO_APPLY); coll.gameObject.SendMessage("ApplyEffect", effectDescr, SendMessageOptions.DontRequireReceiver); }
/**********************************************************************************/ // функция применения эффектов // /**********************************************************************************/ public override void ApplyEffect(EffectDescriptor effect) { m_effectMaster.ApplyEffect(effect); }
public void TestIntegerToStringLookupEffect() { Dictionary<string, string> lookup = new Dictionary<string, string>(); lookup.Add("0", "Nobody We Know"); lookup.Add("1", "Henry McAlpine"); lookup.Add("2", "Bicycle Repair Man"); EffectDescriptor td = new EffectDescriptor(); td.ContentType = ContentType.Comment; td.BlockType = Effect.BlockType.Structure; AttributeFilter filter = new NullAttributeFilter(); td.AddAdditionalInfoDescriptor(new AdditionalInfoDescriptor("Author", "authorID", AdditionalInfoDescriptor.MappingType.StringToStringLookup)); { XmlNodeInformation xni = new XmlNodeInformation(new CommonNamespaces(OpenXmlFormat.Transitional)); List<AttribDetails> lad = xni.GetAttributes() as List<AttribDetails>; lad.Add(new AttribDetails("p", "authorId", @"http://schemas.openxmlformats.org/presentationml/2006/main", "7")); GenericEffect ge = td.CreateEffect(2, xni) as GenericEffect; List<NodeInfo> geai = ge.GetAdditionalInfo(); NodeInfo ni = geai[0]; Assert.AreEqual("Author", ni.name); Assert.AreEqual("Unknown", ni.value); } td.DictStringToStringLookup = lookup; { XmlNodeInformation xni = new XmlNodeInformation(new CommonNamespaces(OpenXmlFormat.Transitional)); List<AttribDetails> lad = xni.GetAttributes() as List<AttribDetails>; lad.Add(new AttribDetails("p", "authorId", @"http://schemas.openxmlformats.org/presentationml/2006/main", "1")); GenericEffect ge = td.CreateEffect(2, xni) as GenericEffect; List<NodeInfo> geai = ge.GetAdditionalInfo(); NodeInfo ni = geai[0]; Assert.AreEqual("Author", ni.name); Assert.AreEqual("Henry McAlpine", ni.value); } { XmlNodeInformation xni = new XmlNodeInformation(new CommonNamespaces(OpenXmlFormat.Transitional)); List<AttribDetails> lad = xni.GetAttributes() as List<AttribDetails>; lad.Add(new AttribDetails("p", "authorId", @"http://schemas.openxmlformats.org/presentationml/2006/main", "2")); GenericEffect ge = td.CreateEffect(2, xni) as GenericEffect; List<NodeInfo> geai = ge.GetAdditionalInfo(); NodeInfo ni = geai[0]; Assert.AreEqual("Author", ni.name); Assert.AreEqual("Bicycle Repair Man", ni.value); } { XmlNodeInformation xni = new XmlNodeInformation(new CommonNamespaces(OpenXmlFormat.Transitional)); List<AttribDetails> lad = xni.GetAttributes() as List<AttribDetails>; lad.Add(new AttribDetails("p", "authorId", @"http://schemas.openxmlformats.org/presentationml/2006/main", "7")); GenericEffect ge = td.CreateEffect(2, xni) as GenericEffect; List<NodeInfo> geai = ge.GetAdditionalInfo(); NodeInfo ni = geai[0]; Assert.AreEqual("Author", ni.name); Assert.AreEqual("Unknown", ni.value); } }
public async void RenderProject(StorageFileEx saveToFile) { //second rendering not allowed if (IsRendering) { return; } RenderProgress = "Initiate rendering ..."; IsRendering = true; StopIsChecked = true; var tempWaveFileStream = await saveToFile.OpenStreamForWriteAsync(); await Task.Run(() => { ExecuteStop(); var waveFileWriter = new WaveFileWriterEffect(); var descriptor = new EffectDescriptor(waveFileWriter); AudioDefines.MasteringVoice.SetEffectChain(descriptor); AudioDefines.MasteringVoice.EnableEffect(0); var silenceSamplePlayer = new SilenceSamplePlayer(); silenceSamplePlayer.WithXAudio(AudioDefines.XAudio) .WithWaveFormat(AudioDefines.WaveFormat) .WithVoicePool(AudioDefines.VoicePool); silenceSamplePlayer.BuildAsync().Wait(); silenceSamplePlayer.Play(); RenderProgress = string.Format("rendering"); Task.Delay(500).Wait(); var previousVolume = MasterVolume; MasterVolume = 0.0; waveFileWriter.Start(); PlayIsChecked = true; MasterVolume = previousVolume; Task.Delay(30000).Wait(); MasterVolume = 0.0; waveFileWriter.Stop(tempWaveFileStream); StopIsChecked = true; silenceSamplePlayer.Dispose(); AudioDefines.MasteringVoice.DisableEffect(0); AudioDefines.MasteringVoice.SetEffectChain(null); waveFileWriter.Dispose(); MasterVolume = previousVolume; }); tempWaveFileStream.Dispose(); IsRendering = false; }
public void TestFilterOutNodesWithContentByName() { using (Stream from = File.Open(TESTFILE_DIR + "Comments3.xml", FileMode.Open)) { if (File.Exists(TESTFILE_DIR + "Comments3_result.xml")) File.Delete(TESTFILE_DIR + "Comments3_result.xml"); using (Stream to = File.Open(TESTFILE_DIR + "Comments3_result.xml", FileMode.CreateNew)) { StateMachineBasedXmlFilter xfb = new StateMachineBasedXmlFilter(new CommonNamespaces(OpenXmlFormat.Transitional)); xfb.ConnectToInputStream(from); xfb.ConnectToOutputStream(to); EffectDescriptor td = new EffectDescriptor(); td.BlockType = Effect.BlockType.Content; TriggeringNodeDefinition tnd = new TriggeringNodeDefinition(NamespaceId.w, "t", null, null, td); xfb.AddNodeToTriggerList(tnd); xfb.Execute(); } } Assert.IsTrue(XmlDocumentComparison.AreEquivalent(TESTFILE_DIR + "Comments3_wanted.xml", TESTFILE_DIR + "Comments3_result.xml")); }
public static Effect Factory(int iDepth, XmlNodeInformation ni, EffectDescriptor ed) { return new EndNodeRememberingEffect(iDepth); }
private void OnGUI() { // Display items /* * "Skills" label at top left * Search text box * Results box with selectable items, vertical scrolling * Right panel * "Name" label and text box * "Display" label and text box * "Delay" label and text box * "Targets" label and enumeration multi-select * "Start Target" label and enumeration single-select * "Retargetable" label and checkbox * "Effects" label * Vertical scrolling area with effect controls * New Effect button * Create button, creates a new skill * When a change has been made, a Save and Revert button are shown as enabled */ listItemStyle.normal.background = Texture2D.blackTexture; // Not that it shows up, awesome listItemStyle.normal.textColor = Color.white; selectedItemStyle.normal.background = Texture2D.whiteTexture; selectedItemStyle.normal.textColor = Color.blue; bool newSkillClicked = false; string newSkillName = string.Empty; if (GUI.Button(new Rect(30, 370, 100, 20), "New Skill")) { SkillDescriptor newSkill = new SkillDescriptor(); newSkillName = newSkill.name; SkillDatabase.UpdateSkill(newSkill); newSkillClicked = true; } GUI.Box(new Rect(10, 50, 140, 300), string.Empty); GUI.Label(new Rect(10, 10, 40, 15), "Skills"); GUI.SetNextControlName("txtSearch"); if (newSkillClicked) { searchText = string.Empty; } searchText = GUI.TextField(new Rect(10, 30, 90, 15), searchText); if (GUI.GetNameOfFocusedControl() != "txtSearch" && searchText.Length == 0) { GUI.Label(new Rect(10, 30, 90, 15), "(Search)"); } List <string> skillNames = SkillDatabase.FindSkills(searchText); skillListScrollPosition = GUI.BeginScrollView(new Rect(10, 50, 140, 300), skillListScrollPosition, new Rect(0, 0, 120, skillNames.Count * 20)); if (newSkillClicked) { selectedSkillName = newSkillName; } string startSelectionName = selectedSkillName; int yButton = 10, skillIndex = 0; foreach (string skillName in skillNames) { if (GUI.Button(new Rect(5, yButton, 130, 15), skillName, selectedSkillName == skillName ? selectedItemStyle : listItemStyle)) { selectedSkillName = skillName; } yButton += 20; skillIndex++; } if (startSelectionName != selectedSkillName) { EditorGUI.FocusTextInControl(null); Repaint(); } selectedSkill = SkillDatabase.GetSkill(selectedSkillName); GUI.EndScrollView(); GUI.Box(new Rect(160, 10, 700, 400), string.Empty); if (selectedSkill != null) { mainControlRectY = 20; // TODO: Set up the skill display itself, and wire up components to variables. // Then, create the save/load function. Going to be cool! string originalName = selectedSkill.name; selectedSkill.name = EditorGUI.TextField(MainControlRect(), "Name", selectedSkill.name); if (originalName != selectedSkill.name) { SkillDatabase.RenameSkill(originalName, selectedSkill); selectedSkillName = selectedSkill.name; } selectedSkill.displayText = EditorGUI.TextField(MainControlRect(), "Display Text", selectedSkill.displayText); selectedSkill.delay = EditorGUI.FloatField(MainControlRect(), "Action Delay", selectedSkill.delay); //EditorGUI.LabelField(new Rect(130, y, 100, 15), "Targets"); // The dance of the target options. // First, figure out what our default selection is - because it might forcibly change right after this. // Get the list of currently available flags, and use the selectedDefaultIndex value to figure out // which one is selected in the editor. List <CommandBase.Target> flags = new List <CommandBase.Target>(); foreach (CommandBase.Target target in (CommandBase.Target[])System.Enum.GetValues(typeof(CommandBase.Target))) { if ((selectedSkill.targets & target) > 0) { flags.Add(target); } } CommandBase.Target selectedDefaultTarget = CommandBase.Target.NONE; if (selectedDefaultIndex < flags.Count) { selectedDefaultTarget = flags[selectedDefaultIndex]; } // Now show the targets enum flags field to pick up changes. selectedSkill.targets = (CommandBase.Target)(EditorGUI.EnumFlagsField(MainControlRect(), "Targets", selectedSkill.targets)); // Now, re-fetch the list of available targets. flags.Clear(); foreach (CommandBase.Target target in (CommandBase.Target[])System.Enum.GetValues(typeof(CommandBase.Target))) { if ((selectedSkill.targets & target) > 0) { flags.Add(target); } } if (flags.Count > 0) { // Is our selected default value still in here? If so, make sure we're still pointing at it; otherwise, point at the first item in the list. if (flags.Contains(selectedDefaultTarget)) { selectedDefaultIndex = flags.IndexOf(selectedDefaultTarget); } else { selectedDefaultIndex = 0; } // Now convert the flags to strings so we can display them in a popup. List <string> flagStrings = new List <string>(); foreach (CommandBase.Target flag in flags) { flagStrings.Add(flag.ToString()); } selectedDefaultIndex = EditorGUI.Popup(MainControlRect(), "Default target", selectedDefaultIndex, flagStrings.ToArray()); if (selectedDefaultIndex < flags.Count) { selectedDefaultTarget = flags[selectedDefaultIndex]; } } selectedSkill.isRetargetable = EditorGUI.Toggle(MainControlRect(), "Retargetable", selectedSkill.isRetargetable); mainControlRectY += 40; EditorGUI.LabelField(MainControlRect(), "Effects"); EffectDescriptor killed = null; if (selectedSkill.effects != null) { foreach (EffectDescriptor effect in selectedSkill.effects) { if (RenderEffectFieldWithDelete(effect)) { // Deleted killed = effect; } } if (killed != null) { selectedSkill.RemoveEffect(killed); } } EditorGUI.LabelField(new Rect(170, mainControlRectY, 100, 15), "Add effect type"); List <string> effectNames = new List <string>(); foreach (string key in effectsByName.Keys) { effectNames.Add(key); } selectedNewEffectType = EditorGUI.Popup(new Rect(280, mainControlRectY, 100, 15), selectedNewEffectType, effectNames.ToArray()); if (GUI.Button(new Rect(390, mainControlRectY, 70, 15), "Add")) { EffectDescriptor newDescriptor = new EffectDescriptor(); newDescriptor.effectType = effectsByName[effectNames[selectedNewEffectType]]; newDescriptor.effectExpression = string.Empty; selectedSkill.AddEffect(newDescriptor); } SkillDatabase.SaveSkills(); } }