// Constructor internal ActorStructure(DecorateParser parser) { // Initialize flags = new Dictionary <string, bool>(); props = new Dictionary <string, List <string> >(); states = new Dictionary <string, StateStructure>(); // Always define a game property, but default to 0 values props["game"] = new List <string>(); inheritclass = "actor"; replaceclass = null; baseclass = null; skipsuper = false; // First next token is the class name parser.SkipWhitespace(true); classname = parser.StripTokenQuotes(parser.ReadToken()); if (string.IsNullOrEmpty(classname)) { parser.ReportError("Expected actor class name"); return; } // Parse tokens before entering the actor scope while (parser.SkipWhitespace(true)) { string token = parser.ReadToken(); if (!string.IsNullOrEmpty(token)) { token = token.ToLowerInvariant(); if (token == ":") { // The next token must be the class to inherit from parser.SkipWhitespace(true); inheritclass = parser.StripTokenQuotes(parser.ReadToken()); if (string.IsNullOrEmpty(inheritclass) || parser.IsSpecialToken(inheritclass)) { parser.ReportError("Expected class name to inherit from"); return; } else { // Find the actor to inherit from baseclass = parser.GetArchivedActorByName(inheritclass); if (baseclass == null) { General.ErrorLogger.Add(ErrorType.Warning, "Unable to find the DECORATE class '" + inheritclass + "' to inherit from, while parsing '" + classname + "'"); } } } else if (token == "replaces") { // The next token must be the class to replace parser.SkipWhitespace(true); replaceclass = parser.StripTokenQuotes(parser.ReadToken()); if (string.IsNullOrEmpty(replaceclass) || parser.IsSpecialToken(replaceclass)) { parser.ReportError("Expected class name to replace"); return; } } else if (token == "native") { // Igore this token } else if (token == "{") { // Actor scope begins here, // break out of this parse loop break; } else if (token == "-") { // This could be a negative doomednum (but our parser sees the - as separate token) // So read whatever is after this token and ignore it (negative doomednum indicates no doomednum) parser.ReadToken(); } else { // Check if numeric if (!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out doomednum)) { // Not numeric! parser.ReportError("Expected numeric editor thing number or start of actor scope"); return; } } } else { parser.ReportError("Unexpected end of structure"); return; } } // Now parse the contents of actor structure string previoustoken = ""; while (parser.SkipWhitespace(true)) { string token = parser.ReadToken(); token = token.ToLowerInvariant(); if ((token == "+") || (token == "-")) { // Next token is a flag (option) to set or remove bool flagvalue = (token == "+"); parser.SkipWhitespace(true); string flagname = parser.ReadToken(); if (!string.IsNullOrEmpty(flagname)) { // Add the flag with its value flagname = flagname.ToLowerInvariant(); flags[flagname] = flagvalue; } else { parser.ReportError("Expected flag name"); return; } } else if ((token == "action") || (token == "native")) { // We don't need this, ignore up to the first next ; while (parser.SkipWhitespace(true)) { string t = parser.ReadToken(); if ((t == ";") || (t == null)) { break; } } } else if (token == "skip_super") { skipsuper = true; } else if (token == "states") { // Now parse actor states until we reach the end of the states structure while (parser.SkipWhitespace(true)) { string statetoken = parser.ReadToken(); if (!string.IsNullOrEmpty(statetoken)) { // Start of scope? if (statetoken == "{") { // This is fine } // End of scope? else if (statetoken == "}") { // Done with the states, // break out of this parse loop break; } // State label? else if (statetoken == ":") { if (!string.IsNullOrEmpty(previoustoken)) { // Parse actor state StateStructure st = new StateStructure(this, parser, previoustoken); if (parser.HasError) { return; } states[previoustoken.ToLowerInvariant()] = st; } else { parser.ReportError("Unexpected end of structure"); return; } } else { // Keep token previoustoken = statetoken; } } else { parser.ReportError("Unexpected end of structure"); return; } } } else if (token == "}") { // Actor scope ends here, // break out of this parse loop break; } // Monster property? else if (token == "monster") { // This sets certain flags we are interested in flags["shootable"] = true; flags["countkill"] = true; flags["solid"] = true; flags["canpushwalls"] = true; flags["canusewalls"] = true; flags["activatemcross"] = true; flags["canpass"] = true; flags["ismonster"] = true; } // Projectile property? else if (token == "projectile") { // This sets certain flags we are interested in flags["noblockmap"] = true; flags["nogravity"] = true; flags["dropoff"] = true; flags["missile"] = true; flags["activateimpact"] = true; flags["activatepcross"] = true; flags["noteleport"] = true; } // Clearflags property? else if (token == "clearflags") { // Clear all flags flags.Clear(); } // Game property? else if (token == "game") { // Include all tokens on the same line List <string> games = new List <string>(); while (parser.SkipWhitespace(false)) { string v = parser.ReadToken(); if (v == null) { parser.ReportError("Unexpected end of structure"); return; } if (v == "\n") { break; } if (v != ",") { games.Add(v.ToLowerInvariant()); } } props[token] = games; } // Property else { // Property begins with $? Then the whole line is a single value if (token.StartsWith("$")) { // This is for editor-only properties such as $sprite and $category List <string> values = new List <string>(); if (parser.SkipWhitespace(false)) { values.Add(parser.ReadLine()); } else { values.Add(""); } props[token] = values; } else { // Next tokens up until the next newline are values List <string> values = new List <string>(); while (parser.SkipWhitespace(false)) { string v = parser.ReadToken(); if (v == null) { parser.ReportError("Unexpected end of structure"); return; } if (v == "\n") { break; } if (v != ",") { values.Add(v); } } props[token] = values; } } // Keep token previoustoken = token; } }