protected virtual void WriteActor(Actor actor) { this.WriteActorHeader(actor); this.writer.WriteLine("{"); this.WriteActorCombos(actor); this.WriteActorFlags(actor); this.WriteActorProperties(actor); this.writer.WriteLine("States{"); this.WriteActorStateMachine(actor); this.writer.WriteLine("}"); this.writer.WriteLine("}"); }
protected virtual void WriteActorCombos(Actor actor) { if (actor.HasMonsterCombo) { this.writer.WriteLine("MONSTER"); } if (actor.HasProjectileCombo) { this.writer.WriteLine("PROJECTILE"); } }
protected virtual void WriteActorProperties(Actor actor) { var keyValPairs = from property in actor.Properties from value in actor.Properties[property.Key] select new { Key = property.Key, Value = value }; foreach (var pair in keyValPairs) { this.writer.WriteLine(pair.Key + " " + pair.Value); } }
protected virtual void WriteActorStateMachine(Actor actor) { Random r = new Random(); var jumpTargetLabelsByState = actor.StateMachine.States.OfType<GoToState>().ToDictionary(p => p, p => "__j" + r.Next(0, int.MaxValue)); var labelsFromJumpTargets = jumpTargetLabelsByState.ToLookup(p => p.Key.Target, p => p.Value); ILookup<State, string> labelsByState = actor.StateMachine.Labels.ToLookup(p => p.Value, p => p.Key).Union(labelsFromJumpTargets); foreach (State state in actor.StateMachine.States) { if (labelsByState.Contains(state)) { foreach (string label in labelsByState[state].Where(p => !p.Contains(':'))) { this.writer.WriteLine(label + ":"); } } if (state is FrameState) { FrameState frameState = state as FrameState; this.writer.WriteLine(frameState.Sprite + " " + frameState.Frame + " " + frameState.Duration + (frameState.IsBright ? " BRIGHT " : " ") + frameState.CodePointer); } else if (state is GoToState) { this.writer.WriteLine("goto " + jumpTargetLabelsByState[state as GoToState]); } else if (state is FailState) { this.writer.WriteLine("fail"); } else if (state is StopState) { this.writer.WriteLine("stop"); } } }
protected virtual void WriteActorHeader(Actor actor) { this.writer.WriteLine("actor \"" + actor.Name + "\" : \"" + actor.Parent + "\" "); if (actor.ReplacesName != string.Empty) { this.writer.WriteLine("replaces \"" + actor.ReplacesName + "\" "); } if (actor.IsNative) { this.writer.WriteLine("native "); } if (actor.DoomEdNum != 0) { this.writer.WriteLine(actor.DoomEdNum.ToString() + " "); } }
protected virtual void WriteActorFlags(Actor actor) { foreach (string flag in actor.EnabledFlags) { this.writer.WriteLine("+" + flag); } foreach (string flag in actor.DisabledFlags) { this.writer.WriteLine("-" + flag); } }
public static int Main(string[] args) { DateTime startTime = DateTime.Now; try { // parse command line options List<string> decoratePaths = new List<string>(); List<string> acsFiles = new List<string>(); string otputDecorateFile = "decorate.txt"; string otputAcsFile = "acs.txt"; string libraryName = "DEFAULTLIB"; string mode = "zdoom"; OptionSet options = new OptionSet() { { "a|acs=", "ACS source files.", p => acsFiles.Add(p) }, { "d|decorate=", "Directory with user DECORATE files.", p => decoratePaths.Add(p) }, { "o|acsOut=", "Output ACS file. acs.txt is default.", p => otputAcsFile = p }, { "p|decorateOut=", "Output DECORATE file. decorate.txt is default.", p => otputDecorateFile = p }, { "m|mode=", "Mode (ZDoom or Skulltag), ZDoom is default.", p => mode = p }, { "l|library=", "Name of the ACS library.", p => libraryName = p } }; options.Parse(args); if (decoratePaths.Count == 0) { throw new ArgumentException("No input decorate path specified."); } if (acsFiles.Count == 0) { throw new ArgumentException("No input ACS file specified."); } DecorateParser parser = new DecorateParser(); // add native decorate files string applicationDirectory = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "/"; if (mode.Equals("ZDoom", StringComparison.OrdinalIgnoreCase)) { parser.AddFiles(new DirectoryInfo(applicationDirectory + "decorate/zdoom").GetFilesRecursive(), DecorateFileType.Native); } else { parser.AddFiles(new DirectoryInfo(applicationDirectory + "decorate/skulltag").GetFilesRecursive(), DecorateFileType.Native); } // add user decorate files var files = from path in decoratePaths from file in new DirectoryInfo(path).GetFilesRecursive() select file; parser.AddFiles(files, DecorateFileType.User); Console.WriteLine("Parsing DECORATE files..."); // parse the files var actors = parser.GetActors(); // print some stats var localActors = from actor in actors where !actor.IsFromNativeFile select actor; Console.WriteLine("Found " + actors.Count() + " actors (" + localActors.Count() + " user + " + (actors.Count() - localActors.Count()) + " native)"); // add the classId actor to each monster Actor classIdActor = new Actor() { Name = "__classId", Parent = actors.OfName("inventory").First() }; actors = actors.Append(classIdActor); var monsters = from actor in actors where actor.HasFlagEnabled("ISMONSTER") select actor; foreach (var monster in monsters) { monster.StateMachine.InsertStatesBeforeState( new List<State> { new FrameState() { }, new FrameState() { CodePointer = "A_TakeInventory(\"__classId\", 9999)" }, new FrameState() { CodePointer = "A_GiveInventory(\"__classId\", " + monster.ID + ")" } }, monster.StateMachine.Labels["spawn"]); } // generate ACS Console.WriteLine("Generating output ACS..."); using (var textWriter = new StreamWriter(otputAcsFile)) { var writer = new AcsWriter(textWriter, libraryName); writer.WriteCheckActorClass2(actors); writer.WriteGetWeapon(actors); writer.WriteGetCustomProperty(actors); writer.WriteGetWeaponCustomProperty(actors); writer.WriteOriginalContent(File.ReadAllText(acsFiles[0])); } // generate DECORATE Console.WriteLine("Generating output DECORATE..."); using (var textWriter = new StreamWriter(otputDecorateFile)) { var writer = new DecorateWriter(textWriter); writer.WriteActors(actors); } // print time stat TimeSpan timeDelta = DateTime.Now - startTime; Console.WriteLine("Done after " + Math.Round((double)timeDelta.TotalMilliseconds / 1000d, 2) + " seconds!"); return 0; } catch (IOException e) { Console.WriteLine(e.GetType().Name + ": " + e.Message); Console.WriteLine(string.Empty); Console.WriteLine("Stack trace:"); Console.WriteLine(e.StackTrace); return -1; } }
protected StateMachine ParseStateMachine(Actor actor) { string[] lines = actor.StatesText.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None); var states = new List<State>(); var labels = new Dictionary<string, State>(); // non-root actors inheirit state machine from their parents if (actor.Parent != null) { StateMachine parentMachine = actor.Parent.StateMachine.CloneForChild(actor.Parent.Name); states = parentMachine.States.ToList(); labels = parentMachine.Labels.ToDictionary(p => p.Key, p => p.Value); } var openGoTos = new Dictionary<GoToState, KeyValuePair<string, int>>(); List<string> openLabels = new List<string>(); string lastLabel = string.Empty; foreach (string line in lines) { string trimmed = line.Trim(); if (trimmed == string.Empty) { continue; } string framePattern = @" ([A-Za-z0-9_\-""#]{4,6}) # sprite name \s+ ([A-Za-z\[\]\\""#]+) # frame list \s+ (-?\d+) # duration (\s+bright\s+) # bright yes/no ?(.*) # code pointer "; Match labelMatch = Regex.Match(line, "([A-Za-z0-9_.]+):", RegexOptions.IgnoreCase); Match gotoMatch = Regex.Match(line, @"goto\s+([A-Za-z0-9_:.]+)?(\s*\+\s*(\d+))?", RegexOptions.IgnoreCase); Match frameMatch = Regex.Match(line, framePattern, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); List<State> currentLineStates = new List<State>(); if (trimmed.Equals("fail", StringComparison.OrdinalIgnoreCase)) { currentLineStates.Add(new FailState()); } else if (trimmed.Equals("stop", StringComparison.OrdinalIgnoreCase)) { currentLineStates.Add(new StopState()); } else if (trimmed.Equals("loop", StringComparison.OrdinalIgnoreCase)) { GoToState state = new GoToState(); openGoTos.Add(state, new KeyValuePair<string, int>(lastLabel, 0)); currentLineStates.Add(state); } else if (trimmed.Equals("wait", StringComparison.OrdinalIgnoreCase)) { GoToState state = new GoToState(); state.Target = states.Last(); currentLineStates.Add(state); } else if (gotoMatch.Success) { int offset = 0; int.TryParse(gotoMatch.Groups[3].Value, out offset); State state = new GoToState(); openGoTos.Add(state as GoToState, new KeyValuePair<string, int>(gotoMatch.Groups[1].Value.ToLower(), offset)); currentLineStates.Add(state); } else if (labelMatch.Success) { openLabels.Add(labelMatch.Groups[1].Value.ToLower()); lastLabel = labelMatch.Groups[1].Value.ToLower(); } else if (frameMatch.Success) { foreach (char frame in frameMatch.Groups[2].Value.TrimQuotes()) { FrameState newState = new FrameState() { Sprite = frameMatch.Groups[1].Value, Frame = frame, Duration = int.Parse(frameMatch.Groups[3].Value), IsBright = frameMatch.Groups[4].Value != string.Empty, CodePointer = frameMatch.Groups[5].Value }; currentLineStates.Add(newState); } } else { throw new Exception("Could not parse state line \"" + trimmed + "\" in actor \"" + actor.Name + "\" in file \"" + actor.File.FullName + "\"."); } if (currentLineStates.Count > 0) { foreach (string label in openLabels) { labels[label] = currentLineStates[0]; } openLabels.Clear(); } states.AddRange(currentLineStates); } foreach (var openGoTo in openGoTos) { GoToState state = openGoTo.Key; string targetLabel = openGoTo.Value.Key; int offset = openGoTo.Value.Value; State targetState = null; if (targetLabel == string.Empty) { targetState = state; } else { if (!labels.ContainsKey(targetLabel)) { throw new Exception("Jump target \"" + targetLabel + "\" not found in actor \"" + actor.Name + "\" in file \"" + actor.File.FullName + "\"."); } targetState = labels[targetLabel]; } int stateIndex = states.IndexOf(targetState); Debug.Assert(stateIndex >= 0, "Goto target state not found!"); state.Target = states[stateIndex + offset]; // only FrameStates count towards the offset int numStatesToSkip = offset; int i = stateIndex; state.Target = states[i]; while (numStatesToSkip >= 1) { i++; state.Target = states[i]; if (state.Target.CountsAsState) { numStatesToSkip--; } } } return new StateMachine(states, labels); }
protected IEnumerable<Actor> GetActorsFromFile(DecorateFileInfo file) { Console.WriteLine(" Parsing file " + file.FileInfo.FullName); //// if(cached && cacheValid){ //// load from cache //// } //// else //// { string text = string.Empty; using (var reader = file.FileInfo.OpenText()) { text = reader.ReadToEnd(); } // remove comments text = Regex.Replace(text, "//(.*?)\\n", Environment.NewLine, RegexOptions.Singleline | RegexOptions.IgnoreCase); text = Regex.Replace(text, "/\\*(.*?)\\*/", string.Empty, RegexOptions.Singleline | RegexOptions.IgnoreCase); // remove action and const definitions if (file.Origin == DecorateFileType.Native) { text = Regex.Replace(text, "(action)?\\s*(native|const)?(.*?);", string.Empty, RegexOptions.IgnoreCase); } string actorPattern = @" actor\s+ ([A-Za-z0-9_]+|"".*?"") # actor name (with or without quotes) \s* (:\s*([A-Za-z0-9_]+|"".*?"")\s*)? # parent name (with or without quotes) (replaces\s*([A-Za-z0-9_]+|"".*?"")\s*)? # replaced actor name (with or without quotes) (\d*\s*)? # doomEdNum (native\s*)? # native yes/no { (.*?) # properties and flags (states\s*{(.*?)}\s*)? # state machine } "; var matches = Regex.Matches(text, actorPattern, RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); foreach (Match match in matches) { string fullText = match.Groups[0].Value; string name = match.Groups[1].Value; string parent = match.Groups[3].Value; string replaces = match.Groups[5].Value; string doomednum = match.Groups[6].Value; string native = match.Groups[7].Value; string content = match.Groups[8].Value; string statesContent = match.Groups[10].Value; Actor actor = null; actor = new Actor() { File = file.FileInfo, Name = name, ParentName = parent == string.Empty ? (name.ToLower() == "actor" ? string.Empty : "actor") : parent, ReplacesName = replaces, IsNative = native != string.Empty, IsFromNativeFile = file.Origin == DecorateFileType.Native, DoomEdNum = doomednum != string.Empty ? Int32.Parse(doomednum) : 0, PropertiesAndFlagsText = content, StatesText = statesContent, OriginalText = fullText }; yield return actor; } }