using System; using System.Collections.Generic; using System.Text; using NTERA.EmuEra.Game.EraEmu.GameData.Expression; using NTERA.EmuEra.Game.EraEmu.GameData.Function; using NTERA.EmuEra.Game.EraEmu.GameData.Variable; using NTERA.EmuEra.Game.EraEmu.Sub; using NTERA.EmuEra.Game.EraEmu._Library; namespace NTERA.EmuEra.Game.EraEmu.GameData { internal sealed class StrForm { private StrForm() { } string[] strs;//terms.Length + 1 IOperandTerm[] terms; #region static static FormattedStringMethod formatCurlyBrace; static FormattedStringMethod formatPercent; static FormattedStringMethod formatYenAt; static FunctionMethodTerm NameTarget;// "***" static FunctionMethodTerm CallnameMaster;// "+++" static FunctionMethodTerm CallnamePlayer;// "===" static FunctionMethodTerm NameAssi;// "///" static FunctionMethodTerm CallnameTarget;// "$$$" public static void Initialize() { formatCurlyBrace = new FormatCurlyBrace(); formatPercent = new FormatPercent(); formatYenAt = new FormatYenAt(); VariableToken nameID = GlobalStatic.VariableData.GetSystemVariableToken("NAME"); VariableToken callnameID = GlobalStatic.VariableData.GetSystemVariableToken("CALLNAME"); IOperandTerm[] zeroArg = { new SingleTerm(0) }; VariableTerm target = new VariableTerm(GlobalStatic.VariableData.GetSystemVariableToken("TARGET"), zeroArg); VariableTerm master = new VariableTerm(GlobalStatic.VariableData.GetSystemVariableToken("MASTER"), zeroArg); VariableTerm player = new VariableTerm(GlobalStatic.VariableData.GetSystemVariableToken("PLAYER"), zeroArg); VariableTerm assi = new VariableTerm(GlobalStatic.VariableData.GetSystemVariableToken("ASSI"), zeroArg); VariableTerm nametarget = new VariableTerm(nameID, new IOperandTerm[] { target }); VariableTerm callnamemaster = new VariableTerm(callnameID, new IOperandTerm[] { master }); VariableTerm callnameplayer = new VariableTerm(callnameID, new IOperandTerm[] { player }); VariableTerm nameassi = new VariableTerm(nameID, new IOperandTerm[] { assi }); VariableTerm callnametarget = new VariableTerm(callnameID, new IOperandTerm[] { target }); NameTarget = new FunctionMethodTerm(formatPercent, new IOperandTerm[] { nametarget, null, null }); CallnameMaster = new FunctionMethodTerm(formatPercent, new IOperandTerm[] { callnamemaster, null, null }); CallnamePlayer = new FunctionMethodTerm(formatPercent, new IOperandTerm[] { callnameplayer, null, null }); NameAssi = new FunctionMethodTerm(formatPercent, new IOperandTerm[] { nameassi, null, null }); CallnameTarget = new FunctionMethodTerm(formatPercent, new IOperandTerm[] { callnametarget, null, null }); } public static StrForm FromWordToken(StrFormWord wt) { StrForm ret = new StrForm(); ret.strs = wt.Strs; IOperandTerm[] termArray = new IOperandTerm[wt.SubWords.Length]; for (int i = 0; i < wt.SubWords.Length; i++) { SubWord SWT = wt.SubWords[i]; TripleSymbolSubWord tSymbol = SWT as TripleSymbolSubWord; if (tSymbol != null) { switch (tSymbol.Code) { case '*': termArray[i] = NameTarget; continue; case '+': termArray[i] = CallnameMaster; continue; case '=': termArray[i] = CallnamePlayer; continue; case '/': termArray[i] = NameAssi; continue; case '$': termArray[i] = CallnameTarget; continue; } throw new ExeEE("何かおかしい"); } WordCollection wc = null; IOperandTerm operand = null; YenAtSubWord yenat = SWT as YenAtSubWord; if (yenat != null) { wc = yenat.Words; if (wc != null) { operand = ExpressionParser.ReduceIntegerTerm(wc, TermEndWith.EoL); if (!wc.EOL) throw new CodeEE("三項演算子\\@の第一オペランドが異常です"); } else operand = new SingleTerm(0); IOperandTerm left = new StrFormTerm(FromWordToken(yenat.Left)); IOperandTerm right = null; if (yenat.Right == null) right = new SingleTerm(""); else right = new StrFormTerm(FromWordToken(yenat.Right)); termArray[i] = new FunctionMethodTerm(formatYenAt, new[] { operand, left, right }); continue; } wc = SWT.Words; operand = ExpressionParser.ReduceExpressionTerm(wc, TermEndWith.Comma); if (operand == null) { if (SWT is CurlyBraceSubWord) throw new CodeEE("{}の中に式が存在しません"); throw new CodeEE("%%の中に式が存在しません"); } IOperandTerm second = null; SingleTerm third = null; wc.ShiftNext(); if (!wc.EOL) { second = ExpressionParser.ReduceIntegerTerm(wc, TermEndWith.Comma); wc.ShiftNext(); if (!wc.EOL) { IdentifierWord id = wc.Current as IdentifierWord; if (id == null) throw new CodeEE("','の後にRIGHT又はLEFTがありません"); if (string.Equals(id.Code, "LEFT", Config.Config.SCVariable))//標準RIGHT third = new SingleTerm(1); else if (!string.Equals(id.Code, "RIGHT", Config.Config.SCVariable)) throw new CodeEE("','の後にRIGHT又はLEFT以外の単語があります"); wc.ShiftNext(); } if (!wc.EOL) throw new CodeEE("RIGHT又はLEFTの後に余分な文字があります"); } if (SWT is CurlyBraceSubWord) { if (operand.GetOperandType() != typeof(Int64)) throw new CodeEE("{}の中の式が数式ではありません"); termArray[i] = new FunctionMethodTerm(formatCurlyBrace, new[] { operand, second, third }); continue; } if (operand.GetOperandType() != typeof(string)) throw new CodeEE("%%の中の式が文字列式ではありません"); termArray[i] = new FunctionMethodTerm(formatPercent, new[] { operand, second, third }); } ret.terms = termArray; return ret; } #endregion public bool IsConst => (strs.Length == 1); public IOperandTerm GetIOperandTerm() { if((strs.Length == 2) && (strs[0].Length == 0) && (strs[1].Length == 0)) return terms[0]; return null; } public void Restructure(ExpressionMediator exm, bool tryTranslate=false) { if (strs.Length == 1) return; bool canRestructure = false; for (int i = 0; i < terms.Length; i++) { terms[i] = terms[i].Restructure(exm); if (terms[i] is SingleTerm) { canRestructure = true; } } if (!canRestructure) return; List strList = new List(); List termList = new List(); strList.AddRange(strs); termList.AddRange(terms); for (int i = 0; i < termList.Count; i++) { if (termList[i] is SingleTerm) { string str = termList[i].GetStrValue(exm, tryTranslate); strList[i] = strList[i] + str + strList[i + 1]; termList.RemoveAt(i); strList.RemoveAt(i + 1); i--; } } strs = new string[strList.Count]; terms = new IOperandTerm[termList.Count]; strList.CopyTo(strs); termList.CopyTo(terms); } public string GetString(ExpressionMediator exm, bool tryTranslate = false) { if (strs.Length == 1) return strs[0]; StringBuilder builder = new StringBuilder(100); for (int i = 0; i < strs.Length - 1; i++) { builder.Append(strs[i]); //builder.Append(Translation.translate(terms[i].GetStrValue(exm))); //If the tryTranslate is true we'll try to translate it //HERE builder.Append(terms[i].GetStrValue(exm, tryTranslate)); } builder.Append(strs[strs.Length - 1]); return builder.ToString(); } #region FormattedStringMethod 書式付文字列の内部 private abstract class FormattedStringMethod : FunctionMethod { public FormattedStringMethod() { CanRestructure = true; ReturnType = typeof(string); argumentTypeArray = null; } public override string CheckArgumentType(string name, IOperandTerm[] arguments) { throw new ExeEE("型チェックは呼び出し元が行うこと"); } public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments) { throw new ExeEE("戻り値の型が違う"); } public override SingleTerm GetReturnValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate) { return new SingleTerm(GetStrValue(exm, arguments, tryTranslate)); } } private sealed class FormatCurlyBrace : FormattedStringMethod { public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false) { int nbrPad = 0; string ret = arguments[0].GetIntValue(exm).ToString(); if (arguments[1] == null) return ret; //Bartoum: Engine bug fix, a negative value will make PadRight && PadLeft left. nbrPad = (int)arguments[1].GetIntValue(exm); if(nbrPad < 0) nbrPad = 0; if (arguments[2] != null) ret = ret.PadRight(nbrPad, ' ');//LEFT else ret = ret.PadLeft(nbrPad, ' ');//RIGHT return ret; } } private sealed class FormatPercent : FormattedStringMethod { public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false) { if (arguments[1] != null) tryTranslate = true; //Changes by Bartoum string ret = arguments[0].GetStrValue(exm, tryTranslate); string original = ret; //We try to translate the entire string. If the name of a csv variable was put alone in a variable like ARGS this will work. //At this point we can't know where the name came from so we need to use ALL. if(exm.Process.getCurrentLine != null && exm.Process.getCurrentLine.ToString().Contains("RETURNF")) tryTranslate = false; if (tryTranslate){ ret = Translation.translate(ret, "ALL", tryTranslate); //If it didn't work we strip everything after a number and all those characters - [ ] 【 】and ( if ) is not present. if(original == ret){ ret = Translation.translateALL(ret, "ALL"); } } if (arguments[1] == null) return ret; int totalLength = (int)arguments[1].GetIntValue(exm); int currentLength = LangManager.GetStrlenLang(ret); totalLength -= currentLength - ret.Length;//全角文字の数だけマイナス。タブ文字?ゼロ幅文字?知るか! if (totalLength < ret.Length) return ret;//PadLeftは0未満を送ると例外を投げる if (arguments[2] != null) ret = ret.PadRight(totalLength, ' ');//LEFT else ret = ret.PadLeft(totalLength, ' ');//RIGHT return ret; } } private sealed class FormatYenAt : FormattedStringMethod {//Operator のTernaryIntStrStrとやってることは同じ public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false) { return (arguments[0].GetIntValue(exm) != 0) ? arguments[1].GetStrValue(exm) : arguments[2].GetStrValue(exm); } } #endregion } }