ソースを参照

Merge branch 'stuffed' into 'master'

Stuffed

See merge request Bepsi/NTERA!6
Bepsi 6 年 前
コミット
1c2b81d273

+ 4 - 3
NTERA.Core/IConsole.cs

@@ -1,5 +1,6 @@
 using System.Drawing;
 using NTERA.Core.Interop;
+using NTERA.Core;
 
 namespace NTERA.Core
 {
@@ -25,7 +26,7 @@ namespace NTERA.Core
 		bool noOutputLog { get; set; }
 		void ThrowTitleError(bool something);
 		void PrintBar();
-		void PrintSingleLine(string line, bool temporary = false);
+		void PrintSingleLine(string line, bool temporary = false); // This means to not word-wrap
 		void NewLine();
 		void RefreshStrings(bool something);
 		void SetWindowTitle(string title);
@@ -33,7 +34,7 @@ namespace NTERA.Core
 		bool Enabled { get; }
 		void ThrowError(bool playSound);
 		void PrintErrorButton(string message);
-		void Write(string message);
+		void Write(string message, PrintFlags? flags = null);
 		bool UseSetColorStyle { get; set; }
 		void PrintC(string message, bool something);
 		DisplayLineAlignment Alignment { get; set; }
@@ -80,4 +81,4 @@ namespace NTERA.Core
 		string getDefStBar();
 		bool IsTimeOut { get; }
 	}
-}
+}

+ 2 - 1
NTERA.Core/NTERA.Core.csproj

@@ -46,9 +46,10 @@
     <Compile Include="Interop\DataStructs.cs" />
     <Compile Include="GameInstance.cs" />
     <Compile Include="IConsole.cs" />
+    <Compile Include="PrintFlags.cs" />
     <Compile Include="IMainWindow.cs" />
     <Compile Include="IScriptEngine.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-</Project>
+</Project>

+ 10 - 0
NTERA.Core/PrintFlags.cs

@@ -0,0 +1,10 @@
+namespace NTERA.Core
+{
+    public struct PrintFlags {
+        public bool NewLine;
+        public bool Wait;
+        public bool ForceKana;
+        public bool NoColor;
+        public bool SingleLine; // No word wrap
+    }
+}

+ 49 - 25
NTERA.Engine/Runtime/Base/Keywords.cs

@@ -3,6 +3,7 @@ using System.Collections.Generic;
 using System.Drawing;
 using System.Linq;
 using System.Reflection;
+using NTERA.Core;
 using NTERA.Core.Interop;
 using NTERA.Engine.Compiler;
 
@@ -228,30 +229,60 @@ namespace NTERA.Engine.Runtime.Base
 
 			runtime.Console.PrintHtml(htmlValue.String, false);
 		}
-		[Keyword("PRINT", true, false)]
+
+		private static PrintFlags ParsePrintFlags(string opts)
+		{
+			return new PrintFlags {
+				NewLine = opts.Contains("L") || opts.Contains("W"),
+				Wait = opts.Contains("W"),
+				ForceKana = opts.Contains("K"),
+				NoColor = opts.Contains("D")
+			};
+		}
+
 		[Keyword("PRINTFORM", true, true)]
-		public static void Print(EraRuntime runtime, StackFrame context, ExecutionNode node)
+		[Keyword("PRINTFORMK", true, true)]
+		[Keyword("PRINTFORMD", true, true)]
+		[Keyword("PRINTFORML", true, true)]
+		[Keyword("PRINTFORMW", true, true)]
+		[Keyword("PRINTFORMK", true, true)]
+		[Keyword("PRINTFORMKL", true, true)]
+		[Keyword("PRINTFORMKW", true, true)]
+		[Keyword("PRINTFORMD", true, true)]
+		[Keyword("PRINTFORMDL", true, true)]
+		[Keyword("PRINTFORMDW", true, true)]
+		public static void PrintForm(EraRuntime runtime, StackFrame context, ExecutionNode node)
 		{
+			var flags = ParsePrintFlags(node["name"].Substring(9));
 			var value = runtime.ComputeExpression(context, node.Single());
-
-			runtime.Console.Write(value.ToString());
+			runtime.Console.Write(value.ToString(), flags);
+			if (flags.Wait) {
+				runtime.InputResetEvent.WaitOne();
+			}
 		}
 
-		[Keyword("PRINTFORML", true, true)]
+		[Keyword("PRINT", true, false)]
 		[Keyword("PRINTL", true, false)]
-		public static void PrintLine(EraRuntime runtime, StackFrame context, ExecutionNode node)
+		[Keyword("PRINTW", true, false)]
+		[Keyword("PRINTK", true, false)]
+		[Keyword("PRINTKL", true, false)]
+		[Keyword("PRINTKW", true, false)]
+		[Keyword("PRINTD", true, false)]
+		[Keyword("PRINTDL", true, false)]
+		[Keyword("PRINTDW", true, false)]
+		public static void Print(EraRuntime runtime, StackFrame context, ExecutionNode node)
 		{
+			var flags = ParsePrintFlags(node["name"].Substring(5));
 			var value = runtime.ComputeExpression(context, node.Single());
-
-			runtime.Console.PrintSingleLine(value.ToString());
+			runtime.Console.Write(value.ToString(), flags);
+			if (flags.Wait) {
+				runtime.InputResetEvent.WaitOne();
+			}
 		}
 
 		private class PrintDataOptions
 		{
-			public bool PrintLine = false;
-			public bool Wait = false;
-			public bool ForceKana = false;
-			public bool NoColor = false;
+			public PrintFlags Flags = new PrintFlags();
 			public int Count = 0;
 			public ExecutionNode ChosenNode;
 		}
@@ -272,15 +303,7 @@ namespace NTERA.Engine.Runtime.Base
 			   DATAFORMs followed by a ENDDATA and it picks one at random and prints that.
 			 */
 			CurrentPrintDataOptions = new PrintDataOptions();
-			var opts = node["name"].Substring(9);
-			if (opts.Contains("L"))
-				CurrentPrintDataOptions.PrintLine = true;
-			if (opts.Contains("W"))
-				CurrentPrintDataOptions.Wait = true;
-			if (opts.Contains("K"))
-				CurrentPrintDataOptions.ForceKana = true;
-			if (opts.Contains("D"))
-				CurrentPrintDataOptions.NoColor = true;
+			CurrentPrintDataOptions.Flags = ParsePrintFlags(node["name"].Substring(9));
 		}
 
 		[Keyword("DATA", true, true)]
@@ -299,10 +322,11 @@ namespace NTERA.Engine.Runtime.Base
 				throw new ArgumentException("No DATAFORM found before ENDDATA");
 			}
 			var value = runtime.ComputeExpression(context, CurrentPrintDataOptions.ChosenNode);
-			if (CurrentPrintDataOptions.PrintLine)
-				runtime.Console.PrintSingleLine(value.ToString());
-			else
-				runtime.Console.Write(value.ToString());
+			var flags = CurrentPrintDataOptions.Flags;
+			runtime.Console.Write(value.ToString(), flags);
+			if (flags.Wait) {
+				runtime.InputResetEvent.WaitOne();
+			}
 		}
 	}
 }

+ 35 - 4
NTERA.Engine/Runtime/EraRuntime.cs

@@ -58,6 +58,17 @@ namespace NTERA.Engine.Runtime
 				GlobalVariables.Add(variable.Name, globalVariable);
 			}
 
+			foreach (var variable in ExecutionProvider.DefinedConstants)
+			{
+				var globalVariable = new Variable(variable.Name, variable.ValueType)
+				{
+					[0] = variable.CalculatedValue
+				};
+
+				GlobalVariables.Add(variable.Name, globalVariable);
+			}
+
+
 			foreach (var kv in Variables.StaticVariables)
 			{
 				GlobalVariables[kv.Key.Name] = new DynamicVariable(kv.Key.Name, kv.Key.Type, this, kv.Value);
@@ -66,14 +77,20 @@ namespace NTERA.Engine.Runtime
 			return true;
 		}
 
-		private void PrintStackTrace()
+		private void PrintStackTrace(bool toSystemConsoleOnly)
 		{
-			Console.PrintError("Stack trace:");
+			if (!toSystemConsoleOnly)
+				Console.PrintError("Stack trace:");
 
 			foreach (var stackMember in ExecutionStack)
 			{
 				string name = stackMember.IsAnonymous ? "<anonymous>" : $"@{stackMember.SelfDefinition.Name}";
-				Console.PrintError($"  - {name} ({stackMember.SelfDefinition.Position} > {stackMember.SelfDefinition.Filename})");
+				string msg = $"  - {name} ({stackMember.SelfDefinition.Position} > {stackMember.SelfDefinition.Filename})";
+				if (toSystemConsoleOnly) {
+					System.Console.Write(msg + "\n");
+				} else {
+					Console.PrintError(msg);
+				}
 			}
 		}
 
@@ -94,7 +111,7 @@ namespace NTERA.Engine.Runtime
 			catch (Exception ex)
 			{
 				Console.PrintError($"Unhandled exception: {ex.Message}");
-				PrintStackTrace();
+				PrintStackTrace(false);
 
 				throw;
 			}
@@ -261,6 +278,7 @@ namespace NTERA.Engine.Runtime
 				}
 				else {
 					System.Console.Write($"Error: {ex.Message}\n");
+					PrintStackTrace(true);
 				}
 			}
 		}
@@ -358,6 +376,15 @@ namespace NTERA.Engine.Runtime
 
 				case "call":
 					string functionName = expressionNode["target"];
+					if (functionName == "__INLINEIF") {
+						// For syntax like \@THIRD_PERSON?Third Person#Second Person\@
+						var node = expressionNode.GetSubtype("parameters");
+						bool condition = ComputeExpression(context, node[0]).Real != 0;
+						if (condition)
+							return ComputeExpression(context, node[1]);
+						else
+							return ComputeExpression(context, node[2]);
+					}
 					var function = TotalProcedureDefinitions.FirstOrDefault(func => func.IsReturnFunction && func.Name.Equals(functionName, StringComparison.OrdinalIgnoreCase));
 
 					if (function == null)
@@ -394,6 +421,9 @@ namespace NTERA.Engine.Runtime
 						case "multiply":
 							operatorToken = Token.Asterisk;
 							break;
+						case "Not":
+							operatorToken = Token.Not;
+							break;
 						default: throw new EraRuntimeException($"Unknown operation type: '{operationType}'");
 					}
 
@@ -405,6 +435,7 @@ namespace NTERA.Engine.Runtime
 						{
 							case Token.Plus: return innerValue;
 							case Token.Minus: return innerValue * -1;
+							case Token.Not: return !innerValue;
 							default: throw new EraRuntimeException($"Unsupported unary operation type: '{operationType}'");
 						}
 					}

+ 16 - 18
NTERA/Console/ConsoleRenderer.cs

@@ -33,36 +33,34 @@ namespace NTERA.Console
 			LineHeight = (int)(new Font("MS UI Gothic", 12)).GetHeight();
 		}
 
-		public void WriteItem(IRenderItem item)
+		private void WriteTextItem(TextRenderItem item)
 		{
 			var list = Items[Items.Count - 1];
 
-			var lastItem = list.LastOrDefault();
+			var lastItem = list.LastOrDefault() as TextRenderItem;
 
-			if (lastItem != null)
+			if (lastItem != null && lastItem.TextBrush.Color == item.TextBrush.Color)
 			{
-				if (lastItem is TextRenderItem lastTextItem && item is TextRenderItem newTextItem)
-				{
-					if (lastTextItem.TextBrush.Color == newTextItem.TextBrush.Color)
-					{
-						lastTextItem.Text += newTextItem.Text;
-						
-						AddedItem?.Invoke(item);
-						return;
-					}
-				}
+				lastItem.Text += item.Text;
+			} else {
+				list.Add(item);
+			}
+			// Add a new line if the newline flag is set, or if this isn't text
+			if (item.Flags.NewLine) {
+				Items.Add(new List<IRenderItem>());
 			}
-
-			Items[Items.Count - 1].Add(item);
 
 			AddedItem?.Invoke(item);
 		}
-
-		public void PrintItem(IRenderItem item)
+		public void WriteItem(IRenderItem item)
 		{
+			if (item is TextRenderItem textItem) {
+				WriteTextItem(textItem);
+				return;
+			}
+			// if it isn't text, just add it and always add a new line after it
 			Items[Items.Count - 1].Add(item);
 			Items.Add(new List<IRenderItem>());
-
 			AddedItem?.Invoke(item);
 		}
 

+ 15 - 16
NTERA/Console/EraConsoleInstance.cs

@@ -14,23 +14,22 @@ namespace NTERA.Console
 
 		public AutoResetEvent InputResetEvent { get; protected set; } = new AutoResetEvent(false);
 
+		public Color DefaultForeColor = Color.White;
 		public Color ForeColor = Color.White;
 
-		public void AddText(string text, Color? color = null, bool print = true)
+		public void AddText(string text, PrintFlags? flags = null, Color? color = null)
 		{
+			var flags_ = flags ?? new PrintFlags { NewLine = true };
 			var item = new TextRenderItem(text)
 			{
-				TextBrush = new SolidBrush(color ?? ForeColor),
-				Alignment = Alignment
+				TextBrush = new SolidBrush(color ?? (flags_.NoColor ? DefaultForeColor : ForeColor)),
+				Alignment = Alignment,
+				Flags = flags_
 			};
 
-
-			if (print)
-				Renderer.PrintItem(item);
-			else
-				Renderer.WriteItem(item);
+			Renderer.WriteItem(item);
 		}
-        
+
 
 		public bool IsRunning { get; set; } = true;
 		public bool Enabled { get; set; } = true;
@@ -63,13 +62,13 @@ namespace NTERA.Console
 		public void PrintError(string message)
 		{
 			System.Console.Write("ERROR: " + message + "\n");
-			AddText(message, Color.Red);
+			AddText(message, color: Color.Red );
 		}
 
 		public void PrintSystemLine(string message)
 		{
 			System.Console.Write("INFO: " + message + "\n");
-			AddText(message, Color.Gray);
+			AddText(message, color: Color.Gray);
 		}
 
 		public void DebugClearTraceLog()
@@ -88,7 +87,7 @@ namespace NTERA.Console
 		public void PrintWarning(string message, int level)
 		{
 			System.Console.Write("WARNING: " + message + "\n");
-			AddText(message, Color.Yellow);
+			AddText(message, color: Color.Yellow);
 		}
 
 		public void setStBar(string bar)
@@ -134,7 +133,7 @@ namespace NTERA.Console
 
 		public void PrintSingleLine(string line, bool temporary = false)
 		{
-			AddText(line, print: true);
+			AddText(line, new PrintFlags { SingleLine = true });
 		}
 
 		public void RefreshStrings(bool something)
@@ -155,11 +154,11 @@ namespace NTERA.Console
 
 		protected StringBuilder bodyBuilder = new StringBuilder();
 
-		public void Write(string message)
+		public void Write(string message, PrintFlags? flags = null)
 		{
 			//message.Replace(' ', ' ');
 			//bodyBuilder.Append(message);
-			AddText(message, print: false);
+			AddText(message, flags);
 		}
 
 		public void NewLine()
@@ -243,7 +242,7 @@ namespace NTERA.Console
 		public void PrintHtml(string html, bool newline)
 		{
 			foreach (var item in HtmlParser.ParseHtml(html, ScriptEngine.GetImage))
-				Renderer.PrintItem(item);
+				Renderer.WriteItem(item);
 		}
 
 		public void PrintImg(string img)

+ 12 - 1
NTERA/Console/RenderItem/TextRenderItem.cs

@@ -3,6 +3,7 @@ using System.Collections.Generic;
 using System.Drawing;
 using System.Linq;
 using System.Windows.Forms;
+using NTERA.Core;
 using NTERA.Core.Interop;
 
 namespace NTERA.Console.RenderItem
@@ -17,6 +18,8 @@ namespace NTERA.Console.RenderItem
 
 		public DisplayLineAlignment Alignment { get; set; }
 
+		public PrintFlags Flags { get; set; }
+
 		private static readonly string[] FullwidthCharacters = "0123456789。".ToCharArray().Select(x => x.ToString()).ToArray();
 
 		private static string AlignText(string input)
@@ -66,7 +69,15 @@ namespace NTERA.Console.RenderItem
 
 			var point = new Point(x, renderArea.Y);
 
-			TextRenderer.DrawText(graphics, Text, Font, point, TextBrush.Color, TextFormatFlags.ExpandTabs);
+			var textFormatFlags = TextFormatFlags.ExpandTabs;
+			if (!Flags.SingleLine) {
+				// We want word wrapping
+				textFormatFlags |= TextFormatFlags.WordBreak;
+				// FIXME: We will need to make a rectangle, not a point,
+				// to draw the text in
+			}
+
+			TextRenderer.DrawText(graphics, Text, Font, point, TextBrush.Color, textFormatFlags);
 
 			return TextRenderer.MeasureText(graphics, Text, Font).Width + renderArea.X;
 		}