diff --git a/Framework/Intersect.Framework.Core/GameObjects/Events/Commands/EventCommands.cs b/Framework/Intersect.Framework.Core/GameObjects/Events/Commands/EventCommands.cs index b37a8a5c60..46dea0da30 100644 --- a/Framework/Intersect.Framework.Core/GameObjects/Events/Commands/EventCommands.cs +++ b/Framework/Intersect.Framework.Core/GameObjects/Events/Commands/EventCommands.cs @@ -331,6 +331,11 @@ public partial class GiveExperienceCommand : EventCommand /// The Variable Id to use. /// public Guid VariableId { get; set; } + + /// + /// If true, when a player have their experience reduced, they will be able to level down. + /// + public bool EnableLosingLevels { get; set; } = false; } public partial class ChangeLevelCommand : EventCommand diff --git a/Framework/Intersect.Framework.Core/GameObjects/Events/CommonEventTrigger.cs b/Framework/Intersect.Framework.Core/GameObjects/Events/CommonEventTrigger.cs index a8dae01c7a..245da480d9 100644 --- a/Framework/Intersect.Framework.Core/GameObjects/Events/CommonEventTrigger.cs +++ b/Framework/Intersect.Framework.Core/GameObjects/Events/CommonEventTrigger.cs @@ -39,4 +39,6 @@ public enum CommonEventTrigger MapChanged, UserVariableChange, + + LevelDown, } diff --git a/Intersect (Core)/CustomColors.cs b/Intersect (Core)/CustomColors.cs index aa5a7fdaff..e69adb0551 100644 --- a/Intersect (Core)/CustomColors.cs +++ b/Intersect (Core)/CustomColors.cs @@ -194,6 +194,8 @@ public sealed partial class CombatNamespace public Color LevelUp = Color.Cyan; + public Color LevelLost = Color.Red; + public Color MagicDamage = new Color(255, 255, 0, 255); public Color Missed = new Color(255, 255, 255, 255); diff --git a/Intersect.Editor/Forms/Editors/Events/Event Commands/EventCommand_GiveExperience.Designer.cs b/Intersect.Editor/Forms/Editors/Events/Event Commands/EventCommand_GiveExperience.Designer.cs index 9a34f01946..58ce93b184 100644 --- a/Intersect.Editor/Forms/Editors/Events/Event Commands/EventCommand_GiveExperience.Designer.cs +++ b/Intersect.Editor/Forms/Editors/Events/Event Commands/EventCommand_GiveExperience.Designer.cs @@ -1,4 +1,4 @@ -using DarkUI.Controls; +using DarkUI.Controls; namespace Intersect.Editor.Forms.Editors.Events.Event_Commands { @@ -30,242 +30,266 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - this.grpGiveExperience = new DarkUI.Controls.DarkGroupBox(); - this.grpManualAmount = new DarkUI.Controls.DarkGroupBox(); - this.nudExperience = new DarkUI.Controls.DarkNumericUpDown(); - this.lblExperience = new System.Windows.Forms.Label(); - this.grpVariableAmount = new DarkUI.Controls.DarkGroupBox(); - this.cmbVariable = new DarkUI.Controls.DarkComboBox(); - this.lblVariable = new System.Windows.Forms.Label(); - this.rdoGlobalVariable = new DarkUI.Controls.DarkRadioButton(); - this.rdoGuildVariable = new DarkUI.Controls.DarkRadioButton(); - this.rdoPlayerVariable = new DarkUI.Controls.DarkRadioButton(); - this.grpAmountType = new DarkUI.Controls.DarkGroupBox(); - this.rdoVariable = new DarkUI.Controls.DarkRadioButton(); - this.rdoManual = new DarkUI.Controls.DarkRadioButton(); - this.btnCancel = new DarkUI.Controls.DarkButton(); - this.btnSave = new DarkUI.Controls.DarkButton(); - this.grpGiveExperience.SuspendLayout(); - this.grpManualAmount.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.nudExperience)).BeginInit(); - this.grpVariableAmount.SuspendLayout(); - this.grpAmountType.SuspendLayout(); - this.SuspendLayout(); + grpGiveExperience = new DarkGroupBox(); + chkEnableLevelDown = new DarkCheckBox(); + grpVariableAmount = new DarkGroupBox(); + cmbVariable = new DarkComboBox(); + lblVariable = new Label(); + rdoGlobalVariable = new DarkRadioButton(); + rdoGuildVariable = new DarkRadioButton(); + rdoPlayerVariable = new DarkRadioButton(); + grpAmountType = new DarkGroupBox(); + rdoVariable = new DarkRadioButton(); + rdoManual = new DarkRadioButton(); + btnCancel = new DarkButton(); + btnSave = new DarkButton(); + grpManualAmount = new DarkGroupBox(); + nudExperience = new DarkNumericUpDown(); + lblExperience = new Label(); + grpGiveExperience.SuspendLayout(); + grpVariableAmount.SuspendLayout(); + grpAmountType.SuspendLayout(); + grpManualAmount.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)nudExperience).BeginInit(); + SuspendLayout(); // // grpGiveExperience // - this.grpGiveExperience.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(60)))), ((int)(((byte)(63)))), ((int)(((byte)(65))))); - this.grpGiveExperience.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(90)))), ((int)(((byte)(90)))), ((int)(((byte)(90))))); - this.grpGiveExperience.Controls.Add(this.grpVariableAmount); - this.grpGiveExperience.Controls.Add(this.grpAmountType); - this.grpGiveExperience.Controls.Add(this.btnCancel); - this.grpGiveExperience.Controls.Add(this.btnSave); - this.grpGiveExperience.Controls.Add(this.grpManualAmount); - this.grpGiveExperience.ForeColor = System.Drawing.Color.Gainsboro; - this.grpGiveExperience.Location = new System.Drawing.Point(3, 3); - this.grpGiveExperience.Name = "grpGiveExperience"; - this.grpGiveExperience.Size = new System.Drawing.Size(427, 157); - this.grpGiveExperience.TabIndex = 17; - this.grpGiveExperience.TabStop = false; - this.grpGiveExperience.Text = "Give Experience:"; - // - // grpManualAmount - // - this.grpManualAmount.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(60)))), ((int)(((byte)(63)))), ((int)(((byte)(65))))); - this.grpManualAmount.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(90)))), ((int)(((byte)(90)))), ((int)(((byte)(90))))); - this.grpManualAmount.Controls.Add(this.nudExperience); - this.grpManualAmount.Controls.Add(this.lblExperience); - this.grpManualAmount.ForeColor = System.Drawing.Color.Gainsboro; - this.grpManualAmount.Location = new System.Drawing.Point(6, 19); - this.grpManualAmount.Name = "grpManualAmount"; - this.grpManualAmount.Size = new System.Drawing.Size(292, 71); - this.grpManualAmount.TabIndex = 40; - this.grpManualAmount.TabStop = false; - this.grpManualAmount.Text = "Manual"; - this.grpManualAmount.Visible = false; - // - // nudExperience - // - this.nudExperience.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(69)))), ((int)(((byte)(73)))), ((int)(((byte)(74))))); - this.nudExperience.ForeColor = System.Drawing.Color.Gainsboro; - this.nudExperience.Location = new System.Drawing.Point(130, 25); - this.nudExperience.Maximum = new decimal(new int[] { - 100000000, - 0, - 0, - 0}); - this.nudExperience.Name = "nudExperience"; - this.nudExperience.Size = new System.Drawing.Size(141, 20); - this.nudExperience.TabIndex = 24; - this.nudExperience.Value = new decimal(new int[] { - 0, - 0, - 0, - 0}); - // - // lblExperience - // - this.lblExperience.AutoSize = true; - this.lblExperience.Location = new System.Drawing.Point(22, 27); - this.lblExperience.Name = "lblExperience"; - this.lblExperience.Size = new System.Drawing.Size(91, 13); - this.lblExperience.TabIndex = 23; - this.lblExperience.Text = "Give Experience: "; + grpGiveExperience.BackColor = System.Drawing.Color.FromArgb(60, 63, 65); + grpGiveExperience.BorderColor = System.Drawing.Color.FromArgb(90, 90, 90); + grpGiveExperience.Controls.Add(chkEnableLevelDown); + grpGiveExperience.Controls.Add(grpVariableAmount); + grpGiveExperience.Controls.Add(grpAmountType); + grpGiveExperience.Controls.Add(btnCancel); + grpGiveExperience.Controls.Add(btnSave); + grpGiveExperience.Controls.Add(grpManualAmount); + grpGiveExperience.ForeColor = System.Drawing.Color.Gainsboro; + grpGiveExperience.Location = new System.Drawing.Point(4, 3); + grpGiveExperience.Margin = new Padding(4, 3, 4, 3); + grpGiveExperience.Name = "grpGiveExperience"; + grpGiveExperience.Padding = new Padding(4, 3, 4, 3); + grpGiveExperience.Size = new Size(498, 181); + grpGiveExperience.TabIndex = 17; + grpGiveExperience.TabStop = false; + grpGiveExperience.Text = "Give Experience:"; + // + // chkEnableLevelDown + // + chkEnableLevelDown.AutoSize = true; + chkEnableLevelDown.Location = new System.Drawing.Point(356, 110); + chkEnableLevelDown.Margin = new Padding(4, 3, 4, 3); + chkEnableLevelDown.Name = "chkEnableLevelDown"; + chkEnableLevelDown.Size = new Size(130, 19); + chkEnableLevelDown.TabIndex = 41; + chkEnableLevelDown.Text = "Enable Level Down?"; // // grpVariableAmount // - this.grpVariableAmount.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(60)))), ((int)(((byte)(63)))), ((int)(((byte)(65))))); - this.grpVariableAmount.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(90)))), ((int)(((byte)(90)))), ((int)(((byte)(90))))); - this.grpVariableAmount.Controls.Add(this.cmbVariable); - this.grpVariableAmount.Controls.Add(this.lblVariable); - this.grpVariableAmount.Controls.Add(this.rdoGlobalVariable); - this.grpVariableAmount.Controls.Add(this.rdoGuildVariable); - this.grpVariableAmount.Controls.Add(this.rdoPlayerVariable); - this.grpVariableAmount.ForeColor = System.Drawing.Color.Gainsboro; - this.grpVariableAmount.Location = new System.Drawing.Point(6, 19); - this.grpVariableAmount.Name = "grpVariableAmount"; - this.grpVariableAmount.Size = new System.Drawing.Size(292, 103); - this.grpVariableAmount.TabIndex = 39; - this.grpVariableAmount.TabStop = false; - this.grpVariableAmount.Text = "Variable"; - this.grpVariableAmount.Visible = false; + grpVariableAmount.BackColor = System.Drawing.Color.FromArgb(60, 63, 65); + grpVariableAmount.BorderColor = System.Drawing.Color.FromArgb(90, 90, 90); + grpVariableAmount.Controls.Add(cmbVariable); + grpVariableAmount.Controls.Add(lblVariable); + grpVariableAmount.Controls.Add(rdoGlobalVariable); + grpVariableAmount.Controls.Add(rdoGuildVariable); + grpVariableAmount.Controls.Add(rdoPlayerVariable); + grpVariableAmount.ForeColor = System.Drawing.Color.Gainsboro; + grpVariableAmount.Location = new System.Drawing.Point(7, 22); + grpVariableAmount.Margin = new Padding(4, 3, 4, 3); + grpVariableAmount.Name = "grpVariableAmount"; + grpVariableAmount.Padding = new Padding(4, 3, 4, 3); + grpVariableAmount.Size = new Size(341, 119); + grpVariableAmount.TabIndex = 39; + grpVariableAmount.TabStop = false; + grpVariableAmount.Text = "Variable"; + grpVariableAmount.Visible = false; // // cmbVariable // - this.cmbVariable.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(69)))), ((int)(((byte)(73)))), ((int)(((byte)(74))))); - this.cmbVariable.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(90)))), ((int)(((byte)(90)))), ((int)(((byte)(90))))); - this.cmbVariable.BorderStyle = System.Windows.Forms.ButtonBorderStyle.Solid; - this.cmbVariable.ButtonColor = System.Drawing.Color.FromArgb(((int)(((byte)(43)))), ((int)(((byte)(43)))), ((int)(((byte)(43))))); - this.cmbVariable.DrawDropdownHoverOutline = false; - this.cmbVariable.DrawFocusRectangle = false; - this.cmbVariable.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed; - this.cmbVariable.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.cmbVariable.FlatStyle = System.Windows.Forms.FlatStyle.Flat; - this.cmbVariable.ForeColor = System.Drawing.Color.Gainsboro; - this.cmbVariable.FormattingEnabled = true; - this.cmbVariable.Location = new System.Drawing.Point(67, 72); - this.cmbVariable.Name = "cmbVariable"; - this.cmbVariable.Size = new System.Drawing.Size(219, 21); - this.cmbVariable.TabIndex = 39; - this.cmbVariable.Text = null; - this.cmbVariable.TextPadding = new System.Windows.Forms.Padding(2); + cmbVariable.BackColor = System.Drawing.Color.FromArgb(69, 73, 74); + cmbVariable.BorderColor = System.Drawing.Color.FromArgb(90, 90, 90); + cmbVariable.BorderStyle = ButtonBorderStyle.Solid; + cmbVariable.ButtonColor = System.Drawing.Color.FromArgb(43, 43, 43); + cmbVariable.DrawDropdownHoverOutline = false; + cmbVariable.DrawFocusRectangle = false; + cmbVariable.DrawMode = DrawMode.OwnerDrawFixed; + cmbVariable.DropDownStyle = ComboBoxStyle.DropDownList; + cmbVariable.FlatStyle = FlatStyle.Flat; + cmbVariable.ForeColor = System.Drawing.Color.Gainsboro; + cmbVariable.FormattingEnabled = true; + cmbVariable.Location = new System.Drawing.Point(78, 83); + cmbVariable.Margin = new Padding(4, 3, 4, 3); + cmbVariable.Name = "cmbVariable"; + cmbVariable.Size = new Size(255, 24); + cmbVariable.TabIndex = 39; + cmbVariable.Text = null; + cmbVariable.TextPadding = new Padding(2); // // lblVariable // - this.lblVariable.AutoSize = true; - this.lblVariable.Location = new System.Drawing.Point(8, 74); - this.lblVariable.Name = "lblVariable"; - this.lblVariable.Size = new System.Drawing.Size(45, 13); - this.lblVariable.TabIndex = 38; - this.lblVariable.Text = "Variable"; + lblVariable.AutoSize = true; + lblVariable.Location = new System.Drawing.Point(9, 85); + lblVariable.Margin = new Padding(4, 0, 4, 0); + lblVariable.Name = "lblVariable"; + lblVariable.Size = new Size(48, 15); + lblVariable.TabIndex = 38; + lblVariable.Text = "Variable"; // // rdoGlobalVariable // - this.rdoGlobalVariable.AutoSize = true; - this.rdoGlobalVariable.Location = new System.Drawing.Point(165, 19); - this.rdoGlobalVariable.Name = "rdoGlobalVariable"; - this.rdoGlobalVariable.Size = new System.Drawing.Size(96, 17); - this.rdoGlobalVariable.TabIndex = 37; - this.rdoGlobalVariable.Text = "Global Variable"; - this.rdoGlobalVariable.CheckedChanged += new System.EventHandler(this.rdoGlobalVariable_CheckedChanged); + rdoGlobalVariable.AutoSize = true; + rdoGlobalVariable.Location = new System.Drawing.Point(192, 22); + rdoGlobalVariable.Margin = new Padding(4, 3, 4, 3); + rdoGlobalVariable.Name = "rdoGlobalVariable"; + rdoGlobalVariable.Size = new Size(103, 19); + rdoGlobalVariable.TabIndex = 37; + rdoGlobalVariable.Text = "Global Variable"; + rdoGlobalVariable.CheckedChanged += SetupAmountInput; // // rdoGuildVariable // - this.rdoGuildVariable.AutoSize = true; - this.rdoGuildVariable.Location = new System.Drawing.Point(6, 42); - this.rdoGuildVariable.Name = "rdoGuildVariable"; - this.rdoGuildVariable.Size = new System.Drawing.Size(90, 17); - this.rdoGuildVariable.TabIndex = 37; - this.rdoGuildVariable.Text = "Guild Variable"; - this.rdoGuildVariable.CheckedChanged += new System.EventHandler(this.rdoGuildVariable_CheckedChanged); + rdoGuildVariable.AutoSize = true; + rdoGuildVariable.Location = new System.Drawing.Point(7, 48); + rdoGuildVariable.Margin = new Padding(4, 3, 4, 3); + rdoGuildVariable.Name = "rdoGuildVariable"; + rdoGuildVariable.Size = new Size(97, 19); + rdoGuildVariable.TabIndex = 37; + rdoGuildVariable.Text = "Guild Variable"; + rdoGuildVariable.CheckedChanged += SetupAmountInput; // // rdoPlayerVariable // - this.rdoPlayerVariable.AutoSize = true; - this.rdoPlayerVariable.Checked = true; - this.rdoPlayerVariable.Location = new System.Drawing.Point(6, 19); - this.rdoPlayerVariable.Name = "rdoPlayerVariable"; - this.rdoPlayerVariable.Size = new System.Drawing.Size(95, 17); - this.rdoPlayerVariable.TabIndex = 36; - this.rdoPlayerVariable.TabStop = true; - this.rdoPlayerVariable.Text = "Player Variable"; - this.rdoPlayerVariable.CheckedChanged += new System.EventHandler(this.rdoPlayerVariable_CheckedChanged); + rdoPlayerVariable.AutoSize = true; + rdoPlayerVariable.Checked = true; + rdoPlayerVariable.Location = new System.Drawing.Point(7, 22); + rdoPlayerVariable.Margin = new Padding(4, 3, 4, 3); + rdoPlayerVariable.Name = "rdoPlayerVariable"; + rdoPlayerVariable.Size = new Size(101, 19); + rdoPlayerVariable.TabIndex = 36; + rdoPlayerVariable.TabStop = true; + rdoPlayerVariable.Text = "Player Variable"; + rdoPlayerVariable.CheckedChanged += SetupAmountInput; // // grpAmountType // - this.grpAmountType.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(60)))), ((int)(((byte)(63)))), ((int)(((byte)(65))))); - this.grpAmountType.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(90)))), ((int)(((byte)(90)))), ((int)(((byte)(90))))); - this.grpAmountType.Controls.Add(this.rdoVariable); - this.grpAmountType.Controls.Add(this.rdoManual); - this.grpAmountType.ForeColor = System.Drawing.Color.Gainsboro; - this.grpAmountType.Location = new System.Drawing.Point(305, 19); - this.grpAmountType.Name = "grpAmountType"; - this.grpAmountType.Size = new System.Drawing.Size(115, 71); - this.grpAmountType.TabIndex = 37; - this.grpAmountType.TabStop = false; - this.grpAmountType.Text = "Amount Type:"; + grpAmountType.BackColor = System.Drawing.Color.FromArgb(60, 63, 65); + grpAmountType.BorderColor = System.Drawing.Color.FromArgb(90, 90, 90); + grpAmountType.Controls.Add(rdoVariable); + grpAmountType.Controls.Add(rdoManual); + grpAmountType.ForeColor = System.Drawing.Color.Gainsboro; + grpAmountType.Location = new System.Drawing.Point(356, 22); + grpAmountType.Margin = new Padding(4, 3, 4, 3); + grpAmountType.Name = "grpAmountType"; + grpAmountType.Padding = new Padding(4, 3, 4, 3); + grpAmountType.Size = new Size(134, 82); + grpAmountType.TabIndex = 37; + grpAmountType.TabStop = false; + grpAmountType.Text = "Amount Type:"; // // rdoVariable // - this.rdoVariable.AutoSize = true; - this.rdoVariable.Location = new System.Drawing.Point(9, 42); - this.rdoVariable.Name = "rdoVariable"; - this.rdoVariable.Size = new System.Drawing.Size(63, 17); - this.rdoVariable.TabIndex = 36; - this.rdoVariable.Text = "Variable"; - this.rdoVariable.CheckedChanged += new System.EventHandler(this.rdoVariable_CheckedChanged); + rdoVariable.AutoSize = true; + rdoVariable.Location = new System.Drawing.Point(10, 48); + rdoVariable.Margin = new Padding(4, 3, 4, 3); + rdoVariable.Name = "rdoVariable"; + rdoVariable.Size = new Size(66, 19); + rdoVariable.TabIndex = 36; + rdoVariable.Text = "Variable"; + rdoVariable.CheckedChanged += SetupAmountInput; // // rdoManual // - this.rdoManual.AutoSize = true; - this.rdoManual.Checked = true; - this.rdoManual.Location = new System.Drawing.Point(9, 19); - this.rdoManual.Name = "rdoManual"; - this.rdoManual.Size = new System.Drawing.Size(60, 17); - this.rdoManual.TabIndex = 35; - this.rdoManual.TabStop = true; - this.rdoManual.Text = "Manual"; - this.rdoManual.CheckedChanged += new System.EventHandler(this.rdoManual_CheckedChanged); + rdoManual.AutoSize = true; + rdoManual.Checked = true; + rdoManual.Location = new System.Drawing.Point(10, 22); + rdoManual.Margin = new Padding(4, 3, 4, 3); + rdoManual.Name = "rdoManual"; + rdoManual.Size = new Size(65, 19); + rdoManual.TabIndex = 35; + rdoManual.TabStop = true; + rdoManual.Text = "Manual"; + rdoManual.CheckedChanged += SetupAmountInput; // // btnCancel // - this.btnCancel.Location = new System.Drawing.Point(223, 128); - this.btnCancel.Name = "btnCancel"; - this.btnCancel.Padding = new System.Windows.Forms.Padding(5); - this.btnCancel.Size = new System.Drawing.Size(75, 23); - this.btnCancel.TabIndex = 20; - this.btnCancel.Text = "Cancel"; - this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); + btnCancel.Location = new System.Drawing.Point(260, 148); + btnCancel.Margin = new Padding(4, 3, 4, 3); + btnCancel.Name = "btnCancel"; + btnCancel.Padding = new Padding(6); + btnCancel.Size = new Size(88, 27); + btnCancel.TabIndex = 20; + btnCancel.Text = "Cancel"; + btnCancel.Click += btnCancel_Click; // // btnSave // - this.btnSave.Location = new System.Drawing.Point(6, 128); - this.btnSave.Name = "btnSave"; - this.btnSave.Padding = new System.Windows.Forms.Padding(5); - this.btnSave.Size = new System.Drawing.Size(75, 23); - this.btnSave.TabIndex = 19; - this.btnSave.Text = "Ok"; - this.btnSave.Click += new System.EventHandler(this.btnSave_Click); + btnSave.Location = new System.Drawing.Point(7, 148); + btnSave.Margin = new Padding(4, 3, 4, 3); + btnSave.Name = "btnSave"; + btnSave.Padding = new Padding(6); + btnSave.Size = new Size(88, 27); + btnSave.TabIndex = 19; + btnSave.Text = "Ok"; + btnSave.Click += btnSave_Click; + // + // grpManualAmount + // + grpManualAmount.BackColor = System.Drawing.Color.FromArgb(60, 63, 65); + grpManualAmount.BorderColor = System.Drawing.Color.FromArgb(90, 90, 90); + grpManualAmount.Controls.Add(nudExperience); + grpManualAmount.Controls.Add(lblExperience); + grpManualAmount.ForeColor = System.Drawing.Color.Gainsboro; + grpManualAmount.Location = new System.Drawing.Point(7, 22); + grpManualAmount.Margin = new Padding(4, 3, 4, 3); + grpManualAmount.Name = "grpManualAmount"; + grpManualAmount.Padding = new Padding(4, 3, 4, 3); + grpManualAmount.Size = new Size(341, 82); + grpManualAmount.TabIndex = 40; + grpManualAmount.TabStop = false; + grpManualAmount.Text = "Manual"; + grpManualAmount.Visible = false; + // + // nudExperience + // + nudExperience.BackColor = System.Drawing.Color.FromArgb(69, 73, 74); + nudExperience.ForeColor = System.Drawing.Color.Gainsboro; + nudExperience.Location = new System.Drawing.Point(152, 29); + nudExperience.Margin = new Padding(4, 3, 4, 3); + nudExperience.Maximum = new decimal(new int[] { 100000000, 0, 0, 0 }); + nudExperience.Name = "nudExperience"; + nudExperience.Size = new Size(164, 23); + nudExperience.TabIndex = 24; + nudExperience.Value = new decimal(new int[] { 0, 0, 0, 0 }); + // + // lblExperience + // + lblExperience.AutoSize = true; + lblExperience.Location = new System.Drawing.Point(26, 31); + lblExperience.Margin = new Padding(4, 0, 4, 0); + lblExperience.Name = "lblExperience"; + lblExperience.Size = new Size(96, 15); + lblExperience.TabIndex = 23; + lblExperience.Text = "Give Experience: "; // // EventCommandGiveExperience // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.AutoSize = true; - this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(45)))), ((int)(((byte)(45)))), ((int)(((byte)(48))))); - this.Controls.Add(this.grpGiveExperience); - this.Name = "EventCommandGiveExperience"; - this.Size = new System.Drawing.Size(436, 163); - this.grpGiveExperience.ResumeLayout(false); - this.grpManualAmount.ResumeLayout(false); - this.grpManualAmount.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.nudExperience)).EndInit(); - this.grpVariableAmount.ResumeLayout(false); - this.grpVariableAmount.PerformLayout(); - this.grpAmountType.ResumeLayout(false); - this.grpAmountType.PerformLayout(); - this.ResumeLayout(false); - + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + AutoSize = true; + BackColor = System.Drawing.Color.FromArgb(45, 45, 48); + Controls.Add(grpGiveExperience); + Margin = new Padding(4, 3, 4, 3); + Name = "EventCommandGiveExperience"; + Size = new Size(509, 188); + grpGiveExperience.ResumeLayout(false); + grpGiveExperience.PerformLayout(); + grpVariableAmount.ResumeLayout(false); + grpVariableAmount.PerformLayout(); + grpAmountType.ResumeLayout(false); + grpAmountType.PerformLayout(); + grpManualAmount.ResumeLayout(false); + grpManualAmount.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)nudExperience).EndInit(); + ResumeLayout(false); } #endregion @@ -285,5 +309,6 @@ private void InitializeComponent() private DarkRadioButton rdoGlobalVariable; private DarkRadioButton rdoGuildVariable; private DarkRadioButton rdoPlayerVariable; + private DarkCheckBox chkEnableLevelDown; } } diff --git a/Intersect.Editor/Forms/Editors/Events/Event Commands/EventCommand_GiveExperience.cs b/Intersect.Editor/Forms/Editors/Events/Event Commands/EventCommand_GiveExperience.cs index 4ae8abf5d6..22d5e5de1c 100644 --- a/Intersect.Editor/Forms/Editors/Events/Event Commands/EventCommand_GiveExperience.cs +++ b/Intersect.Editor/Forms/Editors/Events/Event Commands/EventCommand_GiveExperience.cs @@ -5,32 +5,35 @@ namespace Intersect.Editor.Forms.Editors.Events.Event_Commands; - public partial class EventCommandGiveExperience : UserControl { + private readonly FrmEvent _eventEditor; - private readonly FrmEvent mEventEditor; - - private GiveExperienceCommand mMyCommand; + private readonly GiveExperienceCommand _command; public EventCommandGiveExperience(GiveExperienceCommand refCommand, FrmEvent editor) { InitializeComponent(); - mMyCommand = refCommand; - mEventEditor = editor; + _command = refCommand; + _eventEditor = editor; InitLocalization(); - rdoVariable.Checked = mMyCommand.UseVariable; - rdoGlobalVariable.Checked = mMyCommand.VariableType == VariableType.ServerVariable; - rdoGuildVariable.Checked = mMyCommand.VariableType == VariableType.GuildVariable; + rdoVariable.Checked = _command.UseVariable; + rdoGlobalVariable.Checked = _command.VariableType == VariableType.ServerVariable; + rdoGuildVariable.Checked = _command.VariableType == VariableType.GuildVariable; + + nudExperience.Minimum = -long.MaxValue; + nudExperience.Maximum = long.MaxValue; - SetupAmountInput(); + chkEnableLevelDown.Checked = _command.EnableLosingLevels; + + SetupAmountInput(default, default); } private void InitLocalization() { - grpGiveExperience.Text = Strings.EventGiveExperience.title; - lblExperience.Text = Strings.EventGiveExperience.label; + grpGiveExperience.Text = Strings.EventGiveExperience.Title; + lblExperience.Text = Strings.EventGiveExperience.Label; lblVariable.Text = Strings.EventGiveExperience.Variable; @@ -45,60 +48,40 @@ private void InitLocalization() rdoGlobalVariable.Text = Strings.EventGiveExperience.ServerVariable; rdoGuildVariable.Text = Strings.EventGiveExperience.GuildVariable; - btnSave.Text = Strings.EventGiveExperience.okay; - btnCancel.Text = Strings.EventGiveExperience.cancel; + chkEnableLevelDown.Text = Strings.EventGiveExperience.EnableLosingLevels; + + btnSave.Text = Strings.General.Okay; + btnCancel.Text = Strings.General.Cancel; } private void btnSave_Click(object sender, EventArgs e) { - mMyCommand.Exp = (long) nudExperience.Value; + _command.Exp = (long)nudExperience.Value; + if (rdoPlayerVariable.Checked) { - mMyCommand.VariableType = VariableType.PlayerVariable; - mMyCommand.VariableId = PlayerVariableDescriptor.IdFromList(cmbVariable.SelectedIndex, VariableDataType.Integer); + _command.VariableType = VariableType.PlayerVariable; + _command.VariableId = PlayerVariableDescriptor.IdFromList(cmbVariable.SelectedIndex, VariableDataType.Integer); } else if (rdoGlobalVariable.Checked) { - mMyCommand.VariableType = VariableType.ServerVariable; - mMyCommand.VariableId = ServerVariableDescriptor.IdFromList(cmbVariable.SelectedIndex, VariableDataType.Integer); + _command.VariableType = VariableType.ServerVariable; + _command.VariableId = ServerVariableDescriptor.IdFromList(cmbVariable.SelectedIndex, VariableDataType.Integer); } else if (rdoGuildVariable.Checked) { - mMyCommand.VariableType = VariableType.GuildVariable; - mMyCommand.VariableId = GuildVariableDescriptor.IdFromList(cmbVariable.SelectedIndex, VariableDataType.Integer); + _command.VariableType = VariableType.GuildVariable; + _command.VariableId = GuildVariableDescriptor.IdFromList(cmbVariable.SelectedIndex, VariableDataType.Integer); } - mMyCommand.UseVariable = !rdoManual.Checked; - mEventEditor.FinishCommandEdit(); - } - - private void btnCancel_Click(object sender, EventArgs e) - { - mEventEditor.CancelCommandEdit(); - } - private void rdoManual_CheckedChanged(object sender, EventArgs e) - { - SetupAmountInput(); - } - - private void rdoVariable_CheckedChanged(object sender, EventArgs e) - { - SetupAmountInput(); + _command.UseVariable = !rdoManual.Checked; + _command.EnableLosingLevels = chkEnableLevelDown.Checked; + _eventEditor.FinishCommandEdit(); } - private void rdoPlayerVariable_CheckedChanged(object sender, EventArgs e) - { - SetupAmountInput(); - } - - private void rdoGlobalVariable_CheckedChanged(object sender, EventArgs e) - { - SetupAmountInput(); - } - - private void rdoGuildVariable_CheckedChanged(object sender, EventArgs e) + private void btnCancel_Click(object sender, EventArgs e) { - SetupAmountInput(); + _eventEditor.CancelCommandEdit(); } private void VariableBlank() @@ -114,7 +97,7 @@ private void VariableBlank() } } - private void SetupAmountInput() + private void SetupAmountInput(object? sender, EventArgs? e) { grpManualAmount.Visible = rdoManual.Checked; grpVariableAmount.Visible = !rdoManual.Checked; @@ -124,9 +107,9 @@ private void SetupAmountInput() { cmbVariable.Items.AddRange(PlayerVariableDescriptor.GetNamesByType(VariableDataType.Integer)); // Do not update if the wrong type of variable is saved - if (mMyCommand.VariableType == VariableType.PlayerVariable) + if (_command.VariableType == VariableType.PlayerVariable) { - var index = PlayerVariableDescriptor.ListIndex(mMyCommand.VariableId, VariableDataType.Integer); + var index = PlayerVariableDescriptor.ListIndex(_command.VariableId, VariableDataType.Integer); if (index > -1) { cmbVariable.SelectedIndex = index; @@ -145,9 +128,9 @@ private void SetupAmountInput() { cmbVariable.Items.AddRange(ServerVariableDescriptor.GetNamesByType(VariableDataType.Integer)); // Do not update if the wrong type of variable is saved - if (mMyCommand.VariableType == VariableType.ServerVariable) + if (_command.VariableType == VariableType.ServerVariable) { - var index = ServerVariableDescriptor.ListIndex(mMyCommand.VariableId, VariableDataType.Integer); + var index = ServerVariableDescriptor.ListIndex(_command.VariableId, VariableDataType.Integer); if (index > -1) { cmbVariable.SelectedIndex = index; @@ -166,9 +149,9 @@ private void SetupAmountInput() { cmbVariable.Items.AddRange(GuildVariableDescriptor.GetNamesByType(VariableDataType.Integer)); // Do not update if the wrong type of variable is saved - if (mMyCommand.VariableType == VariableType.GuildVariable) + if (_command.VariableType == VariableType.GuildVariable) { - var index = GuildVariableDescriptor.ListIndex(mMyCommand.VariableId, VariableDataType.Integer); + var index = GuildVariableDescriptor.ListIndex(_command.VariableId, VariableDataType.Integer); if (index > -1) { cmbVariable.SelectedIndex = index; @@ -184,6 +167,6 @@ private void SetupAmountInput() } } - nudExperience.Value = Math.Max(1, mMyCommand.Exp); + nudExperience.Value = _command.Exp; } } diff --git a/Intersect.Editor/Forms/Editors/Events/Event Commands/EventCommand_GiveExperience.resx b/Intersect.Editor/Forms/Editors/Events/Event Commands/EventCommand_GiveExperience.resx index 1af7de150c..af32865ec1 100644 --- a/Intersect.Editor/Forms/Editors/Events/Event Commands/EventCommand_GiveExperience.resx +++ b/Intersect.Editor/Forms/Editors/Events/Event Commands/EventCommand_GiveExperience.resx @@ -1,17 +1,17 @@  - diff --git a/Intersect.Editor/Localization/Strings.cs b/Intersect.Editor/Localization/Strings.cs index 535274c067..a8c23180a7 100644 --- a/Intersect.Editor/Localization/Strings.cs +++ b/Intersect.Editor/Localization/Strings.cs @@ -2800,6 +2800,7 @@ public partial struct EventEditor {16, @"Inventory Changed"}, {17, @"Map Changed"}, {18, @"User Variable Changed"}, + {19, @"Level Down"}, }; public static LocalizedString conditions = @"Conditions"; @@ -2947,20 +2948,17 @@ public partial struct EventEndQuest public partial struct EventGiveExperience { + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public static LocalizedString AmountType = @"Amount Type"; - public static LocalizedString cancel = @"Cancel"; - - public static LocalizedString label = @"Give Experience:"; - - public static LocalizedString okay = @"Ok"; - - public static LocalizedString title = @"Give Experience"; + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public static LocalizedString EnableLosingLevels = @"Enable losing levels?"; [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public static LocalizedString AmountType = @"Amount Type"; + public static LocalizedString GuildVariable = @"Guild Variable"; [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public static LocalizedString Variable = @"Variable"; + public static LocalizedString Label = @"Give Experience:"; [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public static LocalizedString Manual = @"Manual"; @@ -2972,8 +2970,10 @@ public partial struct EventGiveExperience public static LocalizedString ServerVariable = @"Global Variable"; [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public static LocalizedString GuildVariable = @"Guild Variable"; + public static LocalizedString Title = @"Give Experience"; + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public static LocalizedString Variable = @"Variable"; } public partial struct EventGotoLabel diff --git a/Intersect.Server.Core/Entities/Events/CommandProcessing.cs b/Intersect.Server.Core/Entities/Events/CommandProcessing.cs index a566f45293..8a1c48fbe3 100644 --- a/Intersect.Server.Core/Entities/Events/CommandProcessing.cs +++ b/Intersect.Server.Core/Entities/Events/CommandProcessing.cs @@ -421,7 +421,7 @@ private static void ProcessCommand( Stack callStack ) { - player.LevelUp(); + player.AddLevels(); } //Give Experience Command @@ -454,7 +454,14 @@ Stack callStack } } - player.GiveExperience(quantity); + if(quantity > 0) + { + player.GiveExperience(quantity); + } + else if (quantity < 0) + { + player.TakeExperience(Math.Abs(quantity), command.EnableLosingLevels, force: true); + } } //Change Level Command diff --git a/Intersect.Server.Core/Entities/Player.cs b/Intersect.Server.Core/Entities/Player.cs index 798703d8bc..87b14836bf 100644 --- a/Intersect.Server.Core/Entities/Player.cs +++ b/Intersect.Server.Core/Entities/Player.cs @@ -1151,16 +1151,10 @@ public override void Die(bool dropItems = true, Entity killer = null) { if (Options.Instance.Player.ExpLossOnDeathPercent > 0) { - if (Options.Instance.Player.ExpLossFromCurrentExp) - { - var ExpLoss = (this.Exp * (Options.Instance.Player.ExpLossOnDeathPercent / 100.0)); - TakeExperience((long)ExpLoss); - } - else - { - var ExpLoss = (GetExperienceToNextLevel(this.Level) * (Options.Instance.Player.ExpLossOnDeathPercent / 100.0)); - TakeExperience((long)ExpLoss); - } + var baseExp = Options.Instance.Player.ExpLossFromCurrentExp ? Exp : GetExperienceToNextLevel(Level); + var expRatioLost = Options.Instance.Player.ExpLossOnDeathPercent / 100.0; + var expLost = (long)(baseExp * expRatioLost); + TakeExperience(expLost); } } PacketSender.SendEntityDie(this); @@ -1255,7 +1249,8 @@ public void FixVitals() SetVital(Vital.Mana, GetVital(Vital.Mana)); } - //Leveling + #region Leveling + public void SetLevel(int level, bool resetExperience = false) { if (level < 1) @@ -1275,87 +1270,106 @@ public void SetLevel(int level, bool resetExperience = false) PacketSender.SendExperience(this); } - public void LevelUp(bool resetExperience = true, int levels = 1) + public void AddLevels(int levels = 1, bool resetExperience = true) { - var messages = new List(); - - var maxLevel = Options.Instance.Player.MaxLevel; + ClassBase? classDescriptor = null; + List<(string, Color)> messageList = []; + + var targetLevel = Math.Clamp(Level + levels, 1, Options.Instance.Player.MaxLevel); if (levels > 0) { - while (Level < maxLevel) + while (Level < targetLevel) { SetLevel(Level + 1, resetExperience); + messageList.Add((Strings.Player.LevelUp.ToString(Level), CustomColors.Combat.LevelUp)); - // level up logic (like spells) - } - } - else if (levels < 0) - { - while (1 < Level) - { - SetLevel(Level - 1, resetExperience); + if ((classDescriptor?.Id == ClassId || ClassBase.TryGet(ClassId, out classDescriptor)) && classDescriptor?.Spells != default) + { + foreach (var spell in classDescriptor.Spells) + { + if (spell.Level != Level) + { + continue; + } - // level down logic (like spells) + var spellInstance = new Spell(spell.Id); + _ = TryTeachSpell(spellInstance, false); + messageList.Add( + (Strings.Player.LearnedSpell.ToString(spellInstance.SpellName), CustomColors.Alerts.Info) + ); + } + } + + StartCommonEventsWithTrigger(CommonEventTrigger.LevelUp); + PacketSender.SendActionMsg(this, Strings.Combat.LevelUp, CustomColors.Combat.LevelUp); } } - - if (Level < Options.Instance.Player.MaxLevel) + else if (levels < 0) { - for (var i = 0; i < levels; i++) + while (targetLevel < Level) { - SetLevel(Level + 1, resetExperience); - - //Let's pull up class - leveling info - var classDescriptor = ClassBase.Get(ClassId); - if (classDescriptor?.Spells == null) - { - continue; - } + SetLevel(Level - 1); + messageList.Add((Strings.Player.LevelLost.ToString(Level), CustomColors.Combat.LevelLost)); - foreach (var spell in classDescriptor.Spells) + if ((classDescriptor?.Id == ClassId || ClassBase.TryGet(ClassId, out classDescriptor)) && classDescriptor?.Spells != default) { - if (spell.Level != Level) + foreach (var spell in classDescriptor.Spells) { - continue; - } + if (spell.Level != Level + 1) + { + continue; + } - var spellInstance = new Spell(spell.Id); - if (TryTeachSpell(spellInstance, true)) - { - messages.Add( - Strings.Player.SpellTaughtLevelUp.ToString(SpellBase.GetName(spellInstance.SpellId)) + ForgetSpell(FindSpell(spell.Id), true); + messageList.Add( + (Strings.Player.ForgotSpell.ToString(SpellBase.GetName(spell.Id)), CustomColors.Alerts.Info) ); } } + + StartCommonEventsWithTrigger(CommonEventTrigger.LevelDown); + PacketSender.SendActionMsg(this, Strings.Combat.LevelDown, CustomColors.Combat.LevelLost); } } - PacketSender.SendChatMsg(this, Strings.Player.LevelUp.ToString(Level), ChatMessageType.Experience, CustomColors.Combat.LevelUp, Name); - PacketSender.SendActionMsg(this, Strings.Combat.LevelUp, CustomColors.Combat.LevelUp); - foreach (var message in messages) + RecalculateStatsAndPoints(); + UnequipInvalidItems(); + PacketSender.SendExperience(this); + PacketSender.SendPointsTo(this); + PacketSender.SendPlayerSpells(this); + PacketSender.SendEntityDataToProximity(this); + + if (StatPoints > 0) { - PacketSender.SendChatMsg(this, message, ChatMessageType.Experience, CustomColors.Alerts.Info, Name); + messageList.Add((Strings.Player.StatPoints.ToString(StatPoints), CustomColors.Combat.StatPoints)); } - if (StatPoints > 0) + foreach (var (message, color) in messageList) { PacketSender.SendChatMsg( - this, Strings.Player.StatPoints.ToString(StatPoints), ChatMessageType.Experience, CustomColors.Combat.StatPoints, Name + this, + message, + ChatMessageType.Experience, + color, + Name ); } - - RecalculateStatsAndPoints(); - UnequipInvalidItems(); - PacketSender.SendExperience(this); - PacketSender.SendPointsTo(this); - PacketSender.SendEntityDataToProximity(this); - - //Search for level up activated events and run them - StartCommonEventsWithTrigger(CommonEventTrigger.LevelUp); } public void GiveExperience(long amount) { + // ReSharper disable once ConvertIfStatementToSwitchStatement + if (amount == 0) + { + return; + } + + if (amount < 0) + { + TakeExperience(-amount); + return; + } + Exp += (int)Math.Round(amount + (amount * (GetEquipmentBonusEffect(ItemEffect.EXP) / 100f))); if (Exp < 0) { @@ -1368,9 +1382,21 @@ public void GiveExperience(long amount) } } - public void TakeExperience(long amount) + public void TakeExperience(long amount, bool enableLosingLevels = false, bool force = false) { - if (this is Player && Options.Instance.Map.DisableExpLossInArenaMaps && Map.ZoneType == MapZone.Arena) + // ReSharper disable once ConvertIfStatementToSwitchStatement + if (amount == 0) + { + return; + } + + if (amount < 0) + { + GiveExperience(-amount); + return; + } + + if (!force && Options.Instance.Map.DisableExpLossInArenaMaps && Map.ZoneType == MapZone.Arena) { return; } @@ -1378,10 +1404,29 @@ public void TakeExperience(long amount) Exp -= amount; if (Exp < 0) { - Exp = 0; - } + if (!enableLosingLevels || Level == 1) + { + Exp = 0; + PacketSender.SendExperience(this); + } + else + { + var levelCount = 0; + while (Exp < 0 && Level + levelCount > 1) + { + --levelCount; + Exp += GetExperienceToNextLevel(Level + levelCount); + } - PacketSender.SendExperience(this); + AddLevels(levelCount); + + if (Exp < 0) + { + Exp = 0; + PacketSender.SendExperience(this); + } + } + } } private bool CheckLevelUp() @@ -1399,11 +1444,12 @@ private bool CheckLevelUp() return false; } - LevelUp(false, levelCount); - + AddLevels(levelCount, false); return true; } + #endregion + //Combat public override void KilledEntity(Entity entity) { @@ -5382,7 +5428,7 @@ public bool TryTeachSpell(Spell spell, bool sendUpdate = true) { PacketSender.SendPlayerSpellUpdate(this, i); PacketSender.SendChatMsg(this, - Strings.Player.SpellTaughtLevelUp.ToString(SpellBase.GetName(spell.SpellId)), + Strings.Player.LearnedSpell.ToString(SpellBase.GetName(spell.SpellId)), ChatMessageType.Experience, CustomColors.Alerts.Info, Name); } @@ -5428,17 +5474,24 @@ public void SwapSpells(int spell1, int spell2) PacketSender.SendPlayerSpellUpdate(this, spell2); } - public void ForgetSpell(int spellSlot, bool removeBoundSpell = false) + public bool ForgetSpell(int spellSlot, bool removeBoundSpell = false) { + if (spellSlot < 0 || Spells.Count <= spellSlot) + { + return false; + } + if (!SpellBase.Get(Spells[spellSlot].SpellId).Bound || removeBoundSpell) { Spells[spellSlot].Set(Spell.None); PacketSender.SendPlayerSpellUpdate(this, spellSlot); UnequipInvalidItems(); + return true; } else { PacketSender.SendChatMsg(this, Strings.Combat.TryForgetBoundSpell, ChatMessageType.Spells); + return false; } } diff --git a/Intersect.Server.Core/Localization/Strings.cs b/Intersect.Server.Core/Localization/Strings.cs index e595929947..bf0b8a7099 100644 --- a/Intersect.Server.Core/Localization/Strings.cs +++ b/Intersect.Server.Core/Localization/Strings.cs @@ -281,6 +281,9 @@ public sealed partial class CombatNamespace : LocaleNamespace [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public readonly LocalizedString ImmuneToEffect = @"IMMUNE!"; + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public readonly LocalizedString LevelDown = @"LEVEL DOWN!"; + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public readonly LocalizedString LevelUp = @"LEVEL UP!"; @@ -1097,6 +1100,9 @@ public sealed partial class PlayerNamespace : LocaleNamespace [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public readonly LocalizedString Left = @"{00} has left {01}."; + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public readonly LocalizedString LevelLost = @"You have lost a level! You are now level {00}!"; + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public readonly LocalizedString LevelUp = @"You have leveled up! You are now level {00}!"; @@ -1128,7 +1134,10 @@ public sealed partial class PlayerNamespace : LocaleNamespace public readonly LocalizedString ServerKilled = @"{00} has been killed by the server!"; [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public readonly LocalizedString SpellTaughtLevelUp = @"You've learned the {00} spell!"; + public readonly LocalizedString LearnedSpell = @"You've learned the {00} spell!"; + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public readonly LocalizedString ForgotSpell = @"You've forgotten the {00} spell!"; [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public readonly LocalizedString StatPoints = @"You have {00} stat points available to be spent!";