Jelajahi Sumber

Merge branch 'stuffed' into 'master'

Stuffed

See merge request Bepsi/NTERA!5
Bepsi 6 tahun lalu
induk
melakukan
89adda7a3a

+ 75 - 1
NTERA.Engine/Runtime/Base/Keywords.cs

@@ -10,6 +10,8 @@ namespace NTERA.Engine.Runtime.Base
 {
 	public static class Keywords
 	{
+		private static Random random = new Random();
+
 		[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
 		private class KeywordAttribute : Attribute
 		{
@@ -180,6 +182,20 @@ namespace NTERA.Engine.Runtime.Base
 			runtime.Console.PrintBar();
 		}
 
+		[Keyword("CUSTOMDRAWLINE", true)]
+		public static void CustomDrawLine(EraRuntime runtime, StackFrame context, ExecutionNode node)
+		{
+			if (node.SubNodes.Length == 1)
+			{
+				var value = runtime.ComputeExpression(context, node.Single());
+				runtime.Console.printCustomBar(value.ToString());
+			}
+			else {
+				throw new ArgumentException("Missing argument to CUSTOMDRAWLINE");
+			}
+
+		}
+
 		[Keyword("DRAWLINEFORM", true, true)]
 		public static void DrawLineForm(EraRuntime runtime, StackFrame context, ExecutionNode node)
 		{
@@ -212,7 +228,6 @@ namespace NTERA.Engine.Runtime.Base
 
 			runtime.Console.PrintHtml(htmlValue.String, false);
 		}
-
 		[Keyword("PRINT", true, false)]
 		[Keyword("PRINTFORM", true, true)]
 		public static void Print(EraRuntime runtime, StackFrame context, ExecutionNode node)
@@ -230,5 +245,64 @@ namespace NTERA.Engine.Runtime.Base
 
 			runtime.Console.PrintSingleLine(value.ToString());
 		}
+
+		private class PrintDataOptions
+		{
+			public bool PrintLine = false;
+			public bool Wait = false;
+			public bool ForceKana = false;
+			public bool NoColor = false;
+			public int Count = 0;
+			public ExecutionNode ChosenNode;
+		}
+		static private PrintDataOptions CurrentPrintDataOptions;
+
+		[Keyword("PRINTDATA")]
+		[Keyword("PRINTDATAL")]
+		[Keyword("PRINTDATAW")]
+		[Keyword("PRINTDATAK")]
+		[Keyword("PRINTDATAKL")]
+		[Keyword("PRINTDATAKW")]
+		[Keyword("PRINTDATAD")]
+		[Keyword("PRINTDATADL")]
+		[Keyword("PRINTDATADW")]
+		public static void PrintData(EraRuntime runtime, StackFrame context, ExecutionNode node)
+		{
+			/* This function doesn't do anything itself, but lets you specify a bunch of
+			   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;
+		}
+
+		[Keyword("DATA", true, true)]
+		[Keyword("DATAFORM", true, true)]
+		public static void DataForm(EraRuntime runtime, StackFrame context, ExecutionNode node)
+		{
+			CurrentPrintDataOptions.Count++;
+			if (random.Next(0, CurrentPrintDataOptions.Count) == 0)
+				CurrentPrintDataOptions.ChosenNode = node.Single();
+		}
+
+		[Keyword("ENDDATA")]
+		public static void EndData(EraRuntime runtime, StackFrame context, ExecutionNode node)
+		{
+			if (CurrentPrintDataOptions.ChosenNode == null) {
+				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());
+		}
 	}
 }

+ 37 - 17
NTERA.Engine/Runtime/EraRuntime.cs

@@ -26,9 +26,12 @@ namespace NTERA.Engine.Runtime
 		public Value LastInputValue { get; protected set; }
 		public AutoResetEvent InputResetEvent { get; } = new AutoResetEvent(false);
 
-		public EraRuntime(IExecutionProvider executionProvider)
+		public bool IgnoreErrors = false;
+
+		public EraRuntime(IExecutionProvider executionProvider, bool ignoreErrors)
 		{
 			ExecutionProvider = executionProvider;
+			IgnoreErrors = ignoreErrors;
 		}
 
 		public bool Initialize(IConsole console)
@@ -44,7 +47,7 @@ namespace NTERA.Engine.Runtime
 
 			TotalProcedureDefinitions.AddRange(ExecutionProvider.DefinedProcedures);
 			TotalProcedureDefinitions.AddRange(BaseDefinitions.DefaultGlobalFunctions);
-			
+
 			foreach (var variable in BaseDefinitions.DefaultGlobalVariables)
 			{
 				var globalVariable = new Variable(variable.Name, variable.ValueType)
@@ -63,6 +66,17 @@ namespace NTERA.Engine.Runtime
 			return true;
 		}
 
+		private void PrintStackTrace()
+		{
+			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})");
+			}
+		}
+
 		public void Start()
 		{
 			Console.PrintSystemLine("EraJIT x64 0.0.0.0");
@@ -79,14 +93,8 @@ namespace NTERA.Engine.Runtime
 			}
 			catch (Exception ex)
 			{
-				Console.PrintSystemLine($"Unhandled exception: {ex.Message}");
-				Console.PrintSystemLine("Stack trace:");
-
-				foreach (var stackMember in ExecutionStack)
-				{
-					string name = stackMember.IsAnonymous ? "<anonymous>" : $"@{stackMember.SelfDefinition.Name}";
-					Console.PrintSystemLine($"  - {name} ({stackMember.SelfDefinition.Position} > {stackMember.SelfDefinition.Filename})");
-				}
+				Console.PrintError($"Unhandled exception: {ex.Message}");
+				PrintStackTrace();
 
 				throw;
 			}
@@ -183,7 +191,7 @@ namespace NTERA.Engine.Runtime
 			}
 
 			ExecutionNode node = context.ExecutionNodes[context.ExecutionIndex++];
-			
+
 			if (node.Type == "for")
 			{
 				ExecutionNode forContext = node[0];
@@ -194,7 +202,7 @@ namespace NTERA.Engine.Runtime
 				var endNumber = ComputeExpression(context, forContext[2]);
 
 				iterationVariable[iterationIndex] = beginNumber;
-				
+
 				var newContext = context.Clone(node.Skip(1).ToList());
 
 				newContext.AnonymousExitCondition = frame =>
@@ -212,13 +220,13 @@ namespace NTERA.Engine.Runtime
 
 				return;
 			}
-			
+
 			if (node.Type == "do")
 			{
 				ExecutionNode loopContext = node[0];
-				
+
 				var loopVariable = ComputeVariable(context, loopContext[0], out var loopIndex);
-				
+
 				var newContext = context.Clone(node.Skip(1).ToList());
 
 				newContext.AnonymousExitCondition = frame =>
@@ -242,7 +250,19 @@ namespace NTERA.Engine.Runtime
 				return;
 			}
 
-			ExecuteNode(context, node);
+			try {
+				ExecuteNode(context, node);
+			}
+			catch (Exception ex)
+			{
+				if (!IgnoreErrors)
+				{
+					throw ex;
+				}
+				else {
+					System.Console.Write($"Error: {ex.Message}\n");
+				}
+			}
 		}
 
 		public void ExecuteNode(StackFrame context, ExecutionNode node)
@@ -417,4 +437,4 @@ namespace NTERA.Engine.Runtime
 			return new CroppedImage(name, bitmap, definition.Dimensions ?? new Rectangle(Point.Empty, bitmap.Size), false);
 		}
 	}
-}
+}

+ 1 - 0
NTERA/NTERA.csproj

@@ -68,6 +68,7 @@
     </Compile>
     <Compile Include="Console\HTMLParser.cs" />
     <Compile Include="Program.cs" />
+    <Compile Include="Options.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <EmbeddedResource Include="Console\ConsoleControl.resx">
       <DependentUpon>ConsoleControl.cs</DependentUpon>

+ 9 - 0
NTERA/Options.cs

@@ -0,0 +1,9 @@
+
+namespace NTERA
+{
+	public class Options
+	{
+        public bool IgnoreErrors = false;
+        public string EraFolder = null;
+    }
+}

+ 31 - 2
NTERA/Program.cs

@@ -9,11 +9,40 @@ namespace NTERA
 		/// The main entry point for the application.
 		/// </summary>
 		[STAThread]
-		static void Main()
+		static void Main(string[] args)
 		{
+			var options = new Options();
+			options.EraFolder = Environment.GetEnvironmentVariable("ERA");
+			if (options.EraFolder == null) {
+				options.EraFolder = Environment.CurrentDirectory;
+			}
+
+			foreach(var arg in args)
+			{
+				if (arg == "--ignoreerrors") {
+					options.IgnoreErrors = true;
+				}
+				else if (arg == "--help" || arg == "-h" || arg == "/?") {
+					System.Console.Write(@"
+NTERA - An ERA game engine, implemented in .net:
+	[path to era game]
+	--help           - This help message
+	--ignoreerrors   - Do not stop on missing function errors etc. (Will likely break the game!)
+					");
+					return;
+				}
+				else if (!arg.StartsWith("-")) {
+					options.EraFolder = arg;
+				}
+				else {
+					System.Console.Write($"Error: Argument '{arg}' not understood.  See --help\n");
+					return;
+				}
+			}
+
 			Application.EnableVisualStyles();
 			Application.SetCompatibleTextRenderingDefault(false);
-			Application.Run(new formMain());
+			Application.Run(new formMain(options));
 		}
 	}
 }

+ 3 - 6
NTERA/formMain.cs

@@ -1,6 +1,7 @@
 using System.Threading.Tasks;
 using System.Windows.Forms;
 using System;
+using NTERA;
 using NTERA.Console;
 using NTERA.Core;
 using NTERA.EmuEra;
@@ -13,17 +14,13 @@ namespace NTERA
 	{
 		private readonly GameInstance instance = new GameInstance();
 
-		public formMain()
+		public formMain(Options options)
 		{
 			InitializeComponent();
 
             //var scriptEngine = new EmuEraGameInstance();
             //var scriptEngine = new Engine();
-			var eraFolder = Environment.GetEnvironmentVariable("ERA");
-			if (eraFolder == null) {
-				eraFolder = Environment.CurrentDirectory;
-			}
-			var scriptEngine = new EraRuntime(new JITCompiler(eraFolder));
+			var scriptEngine = new EraRuntime(new JITCompiler(options.EraFolder), options.IgnoreErrors);
 
             //Task.Factory.StartNew(() => instance.Run(new EraConsoleInstance(consoleControl1.Renderer, scriptEngine), scriptEngine));
             Task.Factory.StartNew(() => instance.Run(new EraConsoleInstance(consoleControl1.Renderer, scriptEngine), scriptEngine));

+ 1 - 1
README.md

@@ -34,7 +34,7 @@ Build with:
 
 You can run with (note the MONO_IOMAP=all to make it treat files case insensitive):
 
-    ERA=/path/to/eragame MONO_IOMAP=all mono NTERA/bin/Debug/NTERA.exe
+    MONO_IOMAP=all mono NTERA/bin/Debug/NTERA.exe /path/to/eragame
 
 ## Development