Permalink
Cannot retrieve contributors at this time
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
2346 lines (2055 sloc)
87.2 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System.Collections; | |
| using System.Collections.Generic; | |
| //using System.Collections.Concurrent; | |
| using Microsoft.CSharp; | |
| using UnityEngine; | |
| using UnityEngine.EventSystems; | |
| using UnityEngine.UI; | |
| using System; | |
| using System.Linq; | |
| using System.Text; | |
| using System.Text.RegularExpressions; | |
| using System.CodeDom.Compiler; | |
| using System.Reflection; | |
| using DG.Tweening; | |
| public class Compiler : MonoBehaviour { | |
| //InputField ScriptInputField = null; | |
| TMPro.TMP_InputField ScriptInputField = null; | |
| Text_Editor ScriptEditor_My = null; | |
| //TMPro.TextMeshProUGUI ScriptTextField = null; | |
| public BOT_Param_struct BOT_Param = new BOT_Param_struct(); | |
| [Serializable] | |
| public struct BOT_Param_struct { | |
| public GameObject Shield_Prefab; | |
| } | |
| classes_dict classes_dictionary = new classes_dict(); | |
| class classes_dict | |
| { | |
| public Dictionary<string, classes_dict> dict = new Dictionary<string, classes_dict>(); | |
| } | |
| //BOT bot_inst; | |
| Action deleg = null; | |
| IAsyncResult res = null; | |
| public static bool dont_show_rebase_anim_next_time = false; | |
| Suggestion suggestion = null; | |
| public static classes_info cur_active_class = null; | |
| public static List<classes_info> classes = new List<classes_info>(); | |
| public static List<classes_info> functions = new List<classes_info>(); | |
| // Use this for initialization | |
| void Start () { | |
| gameObject.AddComponent<BOT>(); | |
| gameObject.AddComponent<BOT_Helpers.Platform>(); | |
| BOT.bot_shield = BOT_Param.Shield_Prefab; | |
| GameObject tmp = GameObject.Find("Script_InputField_TMPRO"); | |
| if (tmp != null) { | |
| ScriptInputField = tmp.GetComponent<TMPro.TMP_InputField>(); | |
| ScriptInputField.onValueChanged.AddListener(Suggestion); | |
| } else { | |
| ScriptEditor_My = GameObject.Find("Text_Editor").GetComponent<Text_Editor>(); | |
| BOT.script_editor = ScriptEditor_My; | |
| } | |
| cur_active_class = new classes_info(""); | |
| cur_active_class.id = 0; | |
| cur_active_class.changed = false; | |
| cur_active_class.active = true; cur_active_class.enabled = true; classes.Add(cur_active_class); | |
| GameObject suggestion_obj = GameObject.Find("Suggestion"); | |
| if (suggestion_obj != null) suggestion = suggestion_obj.GetComponent<Suggestion>(); | |
| bool WRITE_ASSEMBLIES_LIST_TO_FILE = false; | |
| bool READ_ASSEMBLIES_LIST_FROM_FILE = false; | |
| bool READ_ASSEMBLIES_LIST_FROM_REFLECTION = false; | |
| string assemblies_txt_file = "D:\\Unity 2018.1.0f2\\Projects\\Script-o-bot\\assemblies list.txt"; | |
| //test get all classes | |
| if (!READ_ASSEMBLIES_LIST_FROM_FILE && READ_ASSEMBLIES_LIST_FROM_REFLECTION) { | |
| //Get classes from reflection | |
| System.IO.StreamWriter sw = null; | |
| if (WRITE_ASSEMBLIES_LIST_TO_FILE) sw = System.IO.File.CreateText(assemblies_txt_file); | |
| foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) | |
| { | |
| //Debug.Log(asm.FullName); | |
| if (WRITE_ASSEMBLIES_LIST_TO_FILE) sw.WriteLine("Assembly full name: " + asm.FullName); | |
| if (WRITE_ASSEMBLIES_LIST_TO_FILE) sw.WriteLine("----------------------------------------------------------------------------------"); | |
| string t = asm.FullName.ToUpper(); | |
| if (true || t.Contains("CSHARP") || t.Contains("MSCORLIB") || t.Contains("SYSTEM") || t.Contains("UNITYENGINE")) | |
| { | |
| foreach (Type type in asm.GetTypes()) | |
| { | |
| //Debug.Log(type.FullName); | |
| //if (type.FullName.ToUpper().Contains("BOT")) Debug.Log(asm.FullName + " " + type.FullName); | |
| string ttt = (type.IsEnum ? " - ENUM" : ""); | |
| if (WRITE_ASSEMBLIES_LIST_TO_FILE) sw.WriteLine("Type: " + type.FullName + ttt); | |
| if (type.IsEnum) { | |
| foreach (string s in type.GetEnumNames()) { | |
| if (WRITE_ASSEMBLIES_LIST_TO_FILE) sw.WriteLine("Enum: " + s); | |
| } | |
| } | |
| string t_name = type.FullName; | |
| t_name = t_name.Replace("+", ".").Replace(">", "").Replace("<", ""); | |
| if (t_name.Contains("`")) t_name = t_name.Substring(0, t_name.IndexOf("`")); | |
| if (t_name.Contains("c__")) t_name = t_name.Substring(0, t_name.IndexOf("c__")); | |
| classes_dict current_level_dict = classes_dictionary; | |
| foreach (string n in t_name.Split(new char[]{'.'}, StringSplitOptions.RemoveEmptyEntries)) | |
| { | |
| if (!current_level_dict.dict.ContainsKey(n)) current_level_dict.dict.Add(n, new classes_dict()); | |
| current_level_dict = current_level_dict.dict[n]; | |
| } | |
| MethodInfo[] methodInfos = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static); | |
| foreach (var mi in methodInfos) { | |
| if (WRITE_ASSEMBLIES_LIST_TO_FILE) sw.WriteLine("Method: " + mi.Name); | |
| //if (WRITE_ASSEMBLIES_LIST_TO_FILE) sw.WriteLine("Method: " + mi.Name + " (" + mi.MemberType.ToString() + ")"); | |
| if (!current_level_dict.dict.ContainsKey(mi.Name)) current_level_dict.dict.Add(mi.Name, new classes_dict()); | |
| } | |
| } | |
| } | |
| if (WRITE_ASSEMBLIES_LIST_TO_FILE) { sw.WriteLine(""); sw.WriteLine(""); sw.WriteLine(""); } | |
| } | |
| if (WRITE_ASSEMBLIES_LIST_TO_FILE) sw.Close(); | |
| } else if (READ_ASSEMBLIES_LIST_FROM_FILE) { | |
| //Get classes from file | |
| var sr = System.IO.File.OpenText(assemblies_txt_file); | |
| classes_dict current_level_dict = classes_dictionary; | |
| while (!sr.EndOfStream) { | |
| string l = sr.ReadLine().Trim(); | |
| if (l == "") continue; | |
| if (l.ToUpper().StartsWith("-")) continue; | |
| if (l.ToUpper().StartsWith("TYPE:")) { | |
| current_level_dict = classes_dictionary; | |
| string t_name = l.Substring(5).Trim(); | |
| t_name = t_name.Replace("+", ".").Replace(">", "").Replace("<", ""); | |
| if (t_name.Contains("`")) t_name = t_name.Substring(0, t_name.IndexOf("`")); | |
| if (t_name.Contains("c__")) t_name = t_name.Substring(0, t_name.IndexOf("c__")); | |
| foreach (string n in t_name.Split(new char[]{'.'}, StringSplitOptions.RemoveEmptyEntries)) | |
| { | |
| if (!current_level_dict.dict.ContainsKey(n)) current_level_dict.dict.Add(n, new classes_dict()); | |
| current_level_dict = current_level_dict.dict[n]; | |
| } | |
| } | |
| if (l.ToUpper().StartsWith("METHOD:")) { | |
| string m_name = l.Substring(7).Trim(); | |
| if (!current_level_dict.dict.ContainsKey(m_name)) current_level_dict.dict.Add(m_name, new classes_dict()); | |
| } | |
| } | |
| } | |
| // Type thisType = this.GetType(); | |
| // MethodInfo theMethod = thisType.GetMethod("gameObject.transform.position.x"); | |
| // theMethod.Invoke(this, null); | |
| } | |
| // Update is called once per frame | |
| void Update () { | |
| BOT.Update(); | |
| if (res != null && res.IsCompleted) { | |
| bool there_is_suspended_loot = false; | |
| foreach (var g in Engine.Level_Spawnable) { | |
| Loot lt = g.GetComponent<Loot>(); | |
| if (lt != null && lt.isDeactivating() ) { there_is_suspended_loot = true; break; } | |
| } | |
| //If script error, ignore suspended_enemie. | |
| //Otherwise fighting bomb with 0HP will freeze script (it will throw error, but the bomb will suspend stopping) | |
| bool there_is_suspended_enemie = false; | |
| if (BOT.last_error == "") { | |
| foreach (var e in Engine.Level_Enemies) if (e.suspend) { there_is_suspended_enemie = true; break; } | |
| } | |
| if (!there_is_suspended_enemie && !there_is_suspended_loot && !BOT.dying_in_progress) { | |
| if (deleg != null){ | |
| try { | |
| deleg.EndInvoke(res); | |
| } catch (Exception e) { | |
| //need to skip "Thread was being aborted" because it's by design. | |
| //BUT need to show other errors if there are more then one | |
| //operation is not valid due to current state of object | |
| Error_Panel.ShowError(e.Message.Replace("`", "'")); | |
| } | |
| deleg = null; | |
| } | |
| res = null; | |
| BOT.script_thread = null; | |
| ResetBotState(); | |
| } | |
| } | |
| //Textmesh pro automatically reenable wrapping each time :( | |
| //Debug.Log(ScriptInputField.textComponent.enableWordWrapping.ToString()); | |
| if (ScriptInputField != null) { | |
| if (ScriptInputField.textComponent.enableWordWrapping) ScriptInputField.textComponent.enableWordWrapping = false; | |
| } | |
| TransformMy.Update(); | |
| } | |
| public void Play() | |
| { | |
| if (Control_UI.isInPauseState()){ | |
| Resume(); return; | |
| } | |
| if (res != null) { | |
| Error_Panel.ShowError("Script already running."); return; | |
| } | |
| res = null; | |
| deleg = null; | |
| string str = ""; | |
| if (ScriptInputField != null) str = ScriptInputField.text; else str = ScriptEditor_My.text; | |
| cur_active_class.content = str; | |
| //str = Regex.Replace(str, "<.*?>", string.Empty); //Remove HTML tags TODO: is it dangerous? Check "if (a < 1 && a > 5)". Don't need it with my script editor | |
| str = Regex.Replace(str, "(for)(.*?)(;)(.*?)(;)", "$1$2я$4я"); | |
| //Fill debug_info - each instruction start/end | |
| //Also assure if/else/for/while keywords has a {} after them | |
| //TODO: wrap if / for / foreach / while and lambda ()=> in {} block if there is no one present. do it before entering loop | |
| //TODO: если не парные фигурные скобки - ничего не делать, просто дать компилятору ругнутся | |
| //TODO: nested () i.e. if ((a < 10) && (b > 5)) | |
| //TODO: if with bracket if(){command;} - p() not added, need to put if/while/for detection outside of ';' | |
| //TODO: empty {} after if/while/for/else | |
| //TODO: "if (mail.Contains("1") || mail.Contains("2")) title = "3 " + title;" --> translates to "BOT.P(478, 510);if (mail.Contains("1") {BOT.P(511, 572);|| mail.Contains("2")) title = "3 " + title;}" | |
| //TODO: "if (char.IsDigit(mail[i])) n = n + mail[i]; else break;" translates to "BOT.P(1021, 1046);if (char.IsDigit(mail[i]){BOT.P(1046, 1063);) n = n + mail[i];} else {BOT.P(1070, 1075);break;}" | |
| //DONE: nested if/for | |
| //DONE: need to skip comments | |
| //DONE: need to skip text in "" and '' | |
| List<char> empties = new char[]{'\n', '\r', '\t', ' ', '\0'}.ToList(); | |
| List<int> insert_brackets = new List<int>(); | |
| BOT.DebugInfo_Instructions = new List<BOT.DebugInfoStruct>(); | |
| int first_bracket = str.IndexOf("{"); | |
| if (first_bracket < 0) {Error_Panel.ShowError("Script does not contain any functions."); return;} | |
| if (Regex.IsMatch(str.Substring(0, first_bracket + 1), "class\\s+\\w+\\s*{$")) first_bracket = str.IndexOf("{", first_bracket + 1); | |
| if (first_bracket < 0) {Error_Panel.ShowError("Script does not contain any functions."); return;} | |
| bool in_quotes_single = false; | |
| bool in_quotes_double = false; | |
| bool in_comment_singleLine = false; | |
| bool in_comment_multiLine = false; | |
| //local function to add entry to debugInfo | |
| void add_to_debugInfo(int start, int end) { | |
| BOT.DebugInfoStruct t = new BOT.DebugInfoStruct(); | |
| t.CommandCharStart = start; t.CommandCharEnd = end; | |
| t.Editor_Line_Index = ScriptEditor_My.Get_Line_By_Char_Index(start); | |
| BOT.DebugInfo_Instructions.Add(t); | |
| } | |
| int cmdStart = first_bracket + 1; | |
| for (int i = first_bracket; i < str.Length; i++) { | |
| //Handle quotes | |
| if (str[i] == '"' && !in_quotes_single) { | |
| if (in_quotes_double && i > 0 && str[i-1] != '\\') in_quotes_double = false; | |
| else in_quotes_double = true; | |
| } | |
| if (str[i] == '\'' && !in_quotes_double) { | |
| if (in_quotes_single && i > 0 && str[i-1] != '\\') in_quotes_single = false; | |
| else in_quotes_single = true; | |
| } | |
| if (in_quotes_single || in_quotes_double) { continue; } | |
| //Handle comments | |
| if (str.Length > i+1 && str[i] == '/' && str[i+1] == '/') in_comment_singleLine = true; | |
| if (str.Length > i+1 && str[i] == '/' && str[i+1] == '*') in_comment_multiLine = true; | |
| if (in_comment_singleLine) { | |
| if (str[i] == '\n') { in_comment_singleLine = false; } | |
| cmdStart = i + 1; continue; | |
| } | |
| if (in_comment_multiLine) { | |
| if (str.Length > i+1 && str[i] == '*' && str[i+1] == '/') in_comment_multiLine = false; | |
| cmdStart = i + 2; continue; | |
| } | |
| if (str[i] == '{') { | |
| //if there is no ';' inside {} code block, then skip it, because it's lambda or array init - new int[]{3,5,7}; | |
| int ind_close = str.IndexOf("}", i); | |
| int ind_semicolon = str.IndexOf(";", i); | |
| if (ind_close < ind_semicolon) { | |
| //Check if we have full enclosed block here, with the same number of '{' and '}' | |
| string block = str.Substring(i, ind_semicolon - i); | |
| //Debug.Log("block: " + block); | |
| if ( block.Count(c => c == '{') == block.Count(c => c == '}') ) | |
| i = ind_semicolon; | |
| else | |
| cmdStart = i + 1; | |
| //Debug.Log("cmdStart: " + cmdStart); | |
| } | |
| //If we'll want to count conditional and loop operators as command - comment this 'else' block | |
| //TODO: Uncommenting this will break function declarations as BOT.P will be injected before bracket of new func declaration | |
| else | |
| cmdStart = i + 1; | |
| } | |
| if (str[i] == '}') cmdStart = i + 1; | |
| if (str[i] == ';') { | |
| //Debug.Log("found ; - '" + str.Substring(i-5, 6) + "', cmdstart = " + cmdStart ); | |
| while (empties.Contains(str[cmdStart])) cmdStart++; | |
| string current_command_substr = ""; | |
| while (true) { | |
| int new_cmd_start = -1; | |
| current_command_substr = str.Substring(cmdStart).Trim(); | |
| if (current_command_substr.StartsWith("if")) { new_cmd_start = str.IndexOfBalancedEnd('(', ')', cmdStart) + 1; } | |
| else if (current_command_substr.StartsWith("while")) { new_cmd_start = str.IndexOfBalancedEnd('(', ')', cmdStart) + 1; } | |
| else if (current_command_substr.StartsWith("for")) { new_cmd_start = str.IndexOfBalancedEnd('(', ')', cmdStart) + 1; } | |
| else if (current_command_substr.StartsWith("else")) { new_cmd_start = str.IndexOf("else", cmdStart) + 5; } | |
| if(new_cmd_start > 0) { | |
| if (!current_command_substr.StartsWith("else")) { | |
| //If we'll want to count conditional and loop operators as command - uncomment this | |
| add_to_debugInfo(cmdStart, new_cmd_start); | |
| } | |
| cmdStart = new_cmd_start; | |
| while (empties.Contains(str[cmdStart])) cmdStart++; | |
| string new_substr = str.Substring(cmdStart).Trim(); | |
| if(!new_substr.StartsWith("{")) insert_brackets.Add(cmdStart); | |
| } | |
| //Debug.Log(current_command_substr.Substring(0, 20).Replace("\n", "") + ", OK = " + f.ToString() + ", new_substr = " + new_substr.Trim().Substring(0, 20).Replace("\n", "")); | |
| if (str.Substring(cmdStart).Trim().StartsWith("{")) { cmdStart = str.IndexOf("{", cmdStart) + 1; } | |
| else if (new_cmd_start <= 0) break; | |
| } | |
| add_to_debugInfo(cmdStart, i); | |
| cmdStart = i + 1; | |
| } | |
| } | |
| for (int i = BOT.DebugInfo_Instructions.Count - 1; i >=0; i--) | |
| { | |
| int st = BOT.DebugInfo_Instructions[i].CommandCharStart; | |
| str = str.Insert(st, "BOT.P(" + i.ToString() + ")я"); | |
| if (insert_brackets.Contains(st)) { | |
| int end = str.IndexOf(";", st) + 1; | |
| int end_block = str.IndexOf("}", st) + 1; | |
| if (end > 5 && end < end_block) { | |
| str = str.Insert(end, "}").Insert(st, "{"); | |
| } | |
| } | |
| } | |
| /* | |
| //Inject stuff to start method - BOT.P(n) call after each instruction | |
| str = str.Replace(";", ";BOT.P(1);"); | |
| str = str.Replace("{", "{BOT.P(1);"); | |
| //Replace all BOT.P(1) by BOT.P(n) | |
| int n = 0; | |
| str = System.Text.RegularExpressions.Regex.Replace(str, "BOT.P\\(1\\)", m => "BOT.P(" + n++ + ")"); | |
| //Remove last BOT.P call, because it is after last instruction | |
| str = str.Replace("BOT.P("+ (n-1).ToString() +");", ""); | |
| */ | |
| //Inject stuff to start method - using and class envelop | |
| // str = "using UnityEngine; \npublic class Compiled {" + str.Replace("void","public static void") + "}"; | |
| // int ind = str.IndexOf("Start"); | |
| // if (ind < 0) {Error_Panel.ShowError("Missing 'Start' function."); return;} | |
| // ind = str.IndexOf("{", ind); | |
| // if (ind < 0) {Error_Panel.ShowError("Missing 'Start' function."); return;} | |
| // str = str.Insert(ind + 1, "\nBOT.script_thread = System.Threading.Thread.CurrentThread;\n"); | |
| str = str.Replace("я", ";"); | |
| // str += "\n\nclass test_class {"; | |
| // str += " BOT_Shield g;"; | |
| // str += " public void ttt(float x, float y, float z) {"; | |
| // str += " Debug.Log(" + UnityEngine.Random.Range(0,9).ToString() + ");"; | |
| // str += " Vector3 pos = new Vector3(0f, 0f, 0f);"; | |
| // str += " g = BOT.CreateShield(pos);"; | |
| // str += " g.test_event += aaa;"; | |
| // str += " g.MoveTo(x, y, z);"; | |
| // str += " }"; | |
| // str += " public void aaa() {"; | |
| // str += " g.Release();"; | |
| // str += " }"; | |
| // str += "}"; | |
| //Compiling secondary classes | |
| //TODO: it should not be done everey time 'play' is pressed | |
| string str_to_compile = ""; | |
| foreach (classes_info cl in classes) { | |
| // if (cl.id != 0 && cl.enabled) { | |
| // str += "\n\n" + cl.content + "\n\n"; | |
| // } | |
| string class_content = cl.id == cur_active_class.id ? str : cl.content; | |
| if (cl.id == 0) { | |
| //class_content = "using UnityEngine; using BOT_Helpers; \npublic class Compiled {" + class_content.Replace("void","public static void") + "}"; | |
| class_content = "using UnityEngine; using BOT_Helpers; \npublic class Compiled {" + class_content.Replace("void","public void") + "}"; | |
| int ind = class_content.IndexOf("Start"); | |
| if (ind < 0) {Error_Panel.ShowError("Missing 'Start' function."); return;} | |
| ind = class_content.IndexOf("{", ind); | |
| if (ind < 0) {Error_Panel.ShowError("Missing 'Start' function."); return;} | |
| class_content = class_content.Insert(ind + 1, "\nBOT.script_thread = System.Threading.Thread.CurrentThread;\n"); | |
| } | |
| if (cl.enabled) { | |
| str_to_compile += "\n\n" + class_content + "\n\n"; | |
| } | |
| } | |
| //Debug - show final script | |
| BOT.DebugInfo_Instructions.Add(new BOT.DebugInfoStruct()); | |
| BOT.DebugInfo_Instructions.Add(new BOT.DebugInfoStruct()); | |
| string str1 = Regex.Replace(str_to_compile, "BOT.P\\((\\d+)\\)", m => "BOT.P(" + BOT.DebugInfo_Instructions[ int.Parse(m.Groups[1].Value) ].CommandCharStart.ToString() + ", " + BOT.DebugInfo_Instructions[ int.Parse(m.Groups[1].Value) ].CommandCharEnd.ToString() + ")" ); | |
| var o = GameObject.Find("Panel_Options").transform.Find("Tab6_Content"); | |
| o.GetChild(1).GetChild(0).GetChild(0).GetChild(0).GetComponent<Text>().text = str1; | |
| str_to_compile += "public class launcher { public static void launch() { var l = new Compiled(); l.Start(); } }"; | |
| var assembly = Compile(str_to_compile); | |
| if (assembly != null) | |
| { | |
| foreach (GameObject g in Engine.Level_Spawnable){ | |
| Loot lt = g.GetComponent<Loot>(); | |
| if (lt != null) lt.Set(); | |
| } | |
| foreach (var ISetable in Engine.Level_Setable) { | |
| ISetable.Set(); | |
| } | |
| var rr = Engine.Level_Readable.Where(x=> x.randomize_on_play).ToArray(); | |
| if (rr.Count() == 2) { | |
| string[] t = Phrase_Generator.Generate_Random_Phrase().Split(new char[]{' '}); | |
| rr[0].text = t[0]; rr[1].text = t[1]; | |
| } | |
| Engine.Loot_list.Clear(); | |
| Engine.commands_count = BOT.DebugInfo_Instructions.Count - 2; //Substract 2, because we added 2 empty entry above, to show debug script | |
| BOT.last_error = ""; | |
| BOT.suspend_script = 0; | |
| BOT.Set_Pause(BOT.Pause_States.Reset); | |
| //var methodStart = assembly.GetType("Compiled").GetMethod("Start"); | |
| var methodStart = assembly.GetType("launcher").GetMethod("launch"); | |
| deleg = (Action)Delegate.CreateDelegate(typeof(Action), methodStart); | |
| res = deleg.BeginInvoke(null, null); | |
| Control_UI.set_play_state(); | |
| } | |
| } | |
| public void Stop(bool noDissolveAnim = false) | |
| { | |
| if (BOT.script_thread != null && BOT.script_thread.IsAlive) | |
| { | |
| res = null; deleg = null; | |
| BOT.script_thread.Abort(); | |
| BOT.script_thread = null; | |
| BOT.events.Clear(); | |
| BOT.bot_instance.StopAllCoroutines(); | |
| if (BOT.dead || BOT.dying_in_progress) { | |
| BOT.bot_instance.StopAllCoroutines(); | |
| BOT.dead = false; BOT.dying_in_progress = false; | |
| //BOT.bot_animator.Play("Anim_Idle"); | |
| } | |
| } | |
| ResetBotState(noDissolveAnim); | |
| } | |
| public void Pause() | |
| { | |
| BOT.Set_Pause(BOT.Pause_States.Pause_Command); | |
| Control_UI.set_pause_state(); | |
| } | |
| public void Pause_Immediate() | |
| { | |
| BOT.Set_Pause(BOT.Pause_States.Pause_Immediate); | |
| Control_UI.set_pause_state(); | |
| Control_UI.enable_frame(); | |
| } | |
| public void Resume() | |
| { | |
| BOT.Set_Pause(BOT.Pause_States.Reset); | |
| Control_UI.set_play_state(); | |
| } | |
| public void AdvanceFrame() | |
| { | |
| Control_UI.disable_frame(); | |
| BOT.Set_Pause(BOT.Pause_States.Advance_Command); | |
| } | |
| public void ResetBotState(bool noAnim = false) | |
| { | |
| //Debug.Log("Reset bot state"); | |
| //In case we have highlighted text in script window, used by debugger | |
| GameObject ed_my = GameObject.Find("Text_Editor"); | |
| if (ed_my != null) ed_my.GetComponent<Text_Editor>().HighlightText(-1, -1); | |
| BOT.HP = 100; | |
| BOT.act = null; BOT.act_in_process = false; BOT.is_paused = false; | |
| BOT.Set_Pause(BOT.Pause_States.Reset); | |
| Robot.PlaySfx(-1); | |
| Control_UI.set_stop_state(); Engine.CheckRequirement(); Control_UI.disable_canvas(); | |
| Engine.commands_count = -1; | |
| //TODO: check if it's not another camera | |
| Camera.main.DOKill(); | |
| Camera.main.DOFieldOfView(30f, 2f); | |
| //Bot does not need rebase anim if he is at right place, and his props (like say-plane) are hidden | |
| bool bot_does_not_need_rebase_anim = isBotAlreadyInPlace(); | |
| if (bot_does_not_need_rebase_anim) Control_UI.enable_canvas(); | |
| //noanim - is used when stop is called from LoadNextScene | |
| //dont_show_rebase_anim_next_time - is set by Engine Step - i.e. after requirement met for level complete, but there are some additional step | |
| if (!bot_does_not_need_rebase_anim && !noAnim && !Camera_Controller.level_complete_shown && !dont_show_rebase_anim_next_time) { | |
| BOT.bot_obj.GetComponent<Robot>().Dissolve(); | |
| StartCoroutine("ResetBotState_Coroutine"); | |
| } | |
| dont_show_rebase_anim_next_time = false; | |
| //Reset talk plane & scanner | |
| BOT.tw_talk = null; | |
| BOT.talk_plane.transform.DOKill(); | |
| BOT.talk_plane.transform.localScale = new Vector3(0f, 0f, 0f); | |
| BOT.bot_obj.transform.GetChild(0).GetChild(8).GetChild(0).DOKill(); | |
| BOT.bot_obj.transform.GetChild(0).GetChild(8).GetChild(0).gameObject.SetActive(false); | |
| //Reset loot and collectors | |
| //Debug.Log("Spawnable count: " + Engine.Level_Spawnable.Count.ToString()); | |
| if (!Camera_Controller.level_complete_shown) { | |
| foreach (GameObject g in Engine.Level_Spawnable){ | |
| Loot lt = g.GetComponent<Loot>(); | |
| if (lt != null) lt.Reset(); | |
| } | |
| foreach (Collector cl in Engine.Level_Collectors){ | |
| cl.status = 0; | |
| } | |
| foreach (Enemy en in Engine.Level_Enemies) { | |
| en.Reset(false); | |
| } | |
| foreach (Projectile pr in Engine.Level_Projectiles) { | |
| Destroy(pr.gameObject); | |
| } | |
| foreach (Engine.IDestructible idstr in Engine.Level_Destructibles) { | |
| idstr.Destroy(); | |
| } | |
| foreach (Engine.IResetable r in Engine.Level_Resetable) { | |
| r.Reset(); | |
| } | |
| foreach (GameObject dstr in Engine.Objects_To_Destroy) { | |
| Destroy(dstr); | |
| } | |
| Engine.Objects_To_Destroy.Clear(); | |
| Engine.Level_Projectiles.Clear(); | |
| Engine.Level_Destructibles.Clear(); | |
| Hud.Log("Скрипт завершился, задание не выполнено."); | |
| if (Engine.requirement_additional_info != "") Hud.Log(Engine.requirement_additional_info); | |
| } | |
| //Need to reset death AFTER enemy reset, otherwise requirement is true even if bot is dead | |
| BOT.dead = false; | |
| } | |
| bool isBotAlreadyInPlace() { | |
| bool bot_does_not_need_rebase_anim = true; | |
| Vector2 pos_bot_2d = new Vector2(BOT.bot_obj.transform.position.x, BOT.bot_obj.transform.position.z); | |
| Vector2 pos_spawner_2d = new Vector2(Engine.spawner.transform.position.x, Engine.spawner.transform.position.z); | |
| // Debug.Log("float min: " + float.MinValue); | |
| // Debug.Log("pos dif: " + Vector3.Distance(BOT.bot_obj.transform.position, Engine.spawner.transform.position)); | |
| // Debug.Log("pos dif 2d: " + Vector2.Distance(pos_bot_2d, pos_spawner_2d)); | |
| // Debug.Log("pos dif height: " + Mathf.Abs(BOT.bot_obj.transform.position.y - Engine.spawner.transform.position.y)); | |
| // Debug.Log("ang dif: " + Quaternion.Angle(BOT.bot_obj.transform.rotation, Engine.spawner.transform.rotation)); | |
| // Debug.Log("size dif: " + Vector3.Distance(BOT.bot_obj.transform.lossyScale, new Vector3(3f, 3f, 3f))); | |
| bot_does_not_need_rebase_anim &= Vector2.Distance(pos_bot_2d, pos_spawner_2d) <= 0.001f; | |
| bot_does_not_need_rebase_anim &= Mathf.Abs(BOT.bot_obj.transform.position.y - Engine.spawner.transform.position.y) < 0.02f; | |
| bot_does_not_need_rebase_anim &= Quaternion.Angle(BOT.bot_obj.transform.rotation, Engine.spawner.transform.rotation) <= 0.001f; | |
| bot_does_not_need_rebase_anim &= Vector3.Distance(BOT.bot_obj.transform.lossyScale, new Vector3(3f, 3f, 3f)) <= 0.001; | |
| //Debug.Log("bot_does_not_need_rebase_anim = " + bot_does_not_need_rebase_anim.ToString()); | |
| if (bot_does_not_need_rebase_anim) { | |
| //Reset bot parts and arms | |
| Engine.bot_base.GetComponent<Robot_Base>().Appear(); | |
| } | |
| return bot_does_not_need_rebase_anim; | |
| } | |
| IEnumerator ResetBotState_Coroutine() { | |
| BOT.bot_obj.GetComponent<Rigidbody>().isKinematic = true; | |
| BOT.bot_obj.GetComponent<BoxCollider>().enabled = false; | |
| yield return new WaitForSeconds(0.75f); //Wait for bot to dissolve | |
| BOT.bot_animator.Play("Anim_Idle"); //If stopped while dead or picking up anim - reset animator | |
| if (Options_Global_Static.BOT_FastRebase.isOn) { | |
| BOT.bot_obj.transform.position = Engine.spawner.transform.position; | |
| BOT.bot_obj.transform.rotation = Engine.spawner.transform.rotation; | |
| BOT.bot_obj.transform.localScale = new Vector3(3f, 3f, 3f); | |
| Engine.bot_base.GetComponent<Robot_Base>().Appear(); //Reset arms and other bor parts | |
| BOT.bot_obj.GetComponent<Robot>().Appear(); | |
| BOT.bot_obj.GetComponent<BoxCollider>().enabled = true; | |
| BOT.bot_obj.GetComponent<Rigidbody>().isKinematic = false; | |
| yield return new WaitForSeconds(0.75f); //Wait for bot to appear | |
| Control_UI.enable_canvas(); | |
| yield break; | |
| } | |
| //Move base to spawner | |
| Vector3 spawn_pos = Engine.spawner.transform.position; | |
| Engine.bot_base.transform.position = new Vector3(spawn_pos.x, 0.1f, spawn_pos.z); | |
| Engine.bot_base.transform.rotation = Engine.spawner.transform.rotation; | |
| //Move bot to base and activate animation | |
| BOT.bot_obj.transform.parent = Engine.bot_base.transform.GetChild(2); | |
| BOT.bot_obj.transform.localPosition = Vector3.zero - Vector3.up * 0.6f; //0.4f; | |
| BOT.bot_obj.transform.localRotation = Quaternion.identity; | |
| BOT.bot_obj.transform.localScale = new Vector3(2f, 3f, 2f); | |
| BOT.bot_obj.GetComponent<Robot>().Appear_Immediate(); | |
| BOT.bot_obj.SetActive(false); | |
| Engine.bot_base.SetActive(true); | |
| Engine.bot_base.GetComponent<Animator>().SetTrigger("Trig"); | |
| //Reparanting and reactivating robot is done in Robot_Base script from animation events | |
| } | |
| public void Compile_Secondary_Classes() { | |
| string str = ""; | |
| foreach (classes_info cl in classes) { | |
| if (cl.id != 0 && cl.enabled) { | |
| str += cl.content + "\n\n"; | |
| } | |
| } | |
| var assembly = Compile(str); | |
| if (assembly != null) | |
| { | |
| Debug.Log("Compiled."); | |
| //Debug.Log("Compiled. Assembly location: " + assembly.Location); | |
| } | |
| } | |
| public static Assembly Compile(string source) { | |
| //var provider = new CSharpCodeProvider(); | |
| var provider2 = new CSharpCompiler.CodeCompiler(); | |
| var param = new CompilerParameters(); | |
| // Add ALL of the assembly references | |
| foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) | |
| { | |
| if (!(assembly.ManifestModule is System.Reflection.Emit.ModuleBuilder)) | |
| param.ReferencedAssemblies.Add(assembly.Location); | |
| } | |
| // Add specific assembly references | |
| //param.ReferencedAssemblies.Add("System.dll"); | |
| //param.ReferencedAssemblies.Add("CSharp.dll"); | |
| //param.ReferencedAssemblies.Add("UnityEngines.dll"); | |
| // Generate a dll in memory | |
| param.GenerateExecutable = false; | |
| param.GenerateInMemory = true; | |
| param.WarningLevel = 3; | |
| // Compile the source | |
| //var result = provider.CompileAssemblyFromSource(param, source); | |
| var result = provider2.CompileAssemblyFromSource(param, source); | |
| if (result.Errors.Count > 0) { | |
| var msg = new StringBuilder(); | |
| foreach (CompilerError error in result.Errors) { | |
| if (error.IsWarning) { Hud.Log("Compile warning: " + error.ErrorText.Replace("`", "'") ); continue; } | |
| msg.AppendFormat("Error ({0}): {1}\n", error.ErrorNumber, error.ErrorText.Replace("`", "'") ); | |
| } | |
| if (msg.Length > 0) Error_Panel.ShowError(msg.ToString()); | |
| } | |
| // Return the assembly | |
| return result.CompiledAssembly; | |
| } | |
| public void Suggestion (string str) | |
| { | |
| if (cur_active_class != null) { | |
| cur_active_class.changed = true; | |
| cur_active_class.content = str; | |
| } | |
| str = " " + str; | |
| //int pos = ScriptInputField.caretPosition + 1; | |
| int pos = ScriptInputField.stringPosition; | |
| if (pos >= str.Length) return; | |
| int pos2 = str.LastIndexOfAny(new char[]{';', ' ', '\n', '{', '}'}, pos); | |
| str = str.Substring(pos2 + 1, pos - pos2); | |
| //Debug.Log ("Str = '" + str + "', corrPos = "+ pos.ToString() + ", word bedin pos = " + pos2.ToString()); | |
| if (str == "") return; | |
| var current_namespace = classes_dictionary.dict; //Root | |
| var arr = str.Split(new char[]{'.'}, StringSplitOptions.None); | |
| for (int n = 0; n < arr.Length - 1; n++) { | |
| if (current_namespace.ContainsKey(arr[n])) { | |
| //Debug.Log("Switch namespace to: " + arr[n]); | |
| current_namespace = current_namespace[arr[n]].dict; | |
| } | |
| else { | |
| //Debug.Log("Namespace not found: " + arr[n]); | |
| return; | |
| } | |
| } | |
| int sugCount = 0; | |
| string sugStr = ""; | |
| List<string> sugList = new List<string>(); | |
| foreach (KeyValuePair<string, classes_dict> kv in current_namespace) | |
| { | |
| //Debug.Log(kv.Key); | |
| if (kv.Key.ToUpper().StartsWith(arr[arr.Length-1].ToUpper())) | |
| { | |
| sugList.Add(kv.Key); | |
| sugStr += kv.Key + "\n"; | |
| sugCount += 1; | |
| if (sugCount > 15) break; | |
| } | |
| } | |
| if (sugStr != "" && suggestion != null) suggestion.Suggest(sugStr); | |
| //Debug.Log(sugStr); | |
| } | |
| } | |
| public class classes_info { | |
| public int id = -1; | |
| public string content = ""; | |
| public string original_name = ""; | |
| public bool active = false; | |
| public bool changed = false; | |
| public bool saved = false; | |
| public string saved_fileName = ""; | |
| public bool enabled = false; | |
| const string EMPTY_CLASS_NAME = "Unnamed class"; | |
| const string MAIN_CLASS_NAME = "Main"; | |
| Regex func_regexp_name = new Regex(@"(((abstract|async|extern|override|partial|readonly|sealed|static|virtual|volatile|public|private|protected|internal)\s+)*[\w]+\s+[\w]+\s*\(.*?\))\s*{", RegexOptions.Compiled); | |
| //Regex func_regexp_content = new Regex(@"({(?>[^{}]+|(?1))*})", RegexOptions.Compiled); | |
| public classes_info(string class_content, string function_name = "") { | |
| content = class_content; | |
| if (function_name == "") | |
| original_name = GetClassName(); | |
| else | |
| original_name = function_name; | |
| } | |
| public string GetClassName() { | |
| Match m = Regex.Match(content, "class\\s+(\\w+)", RegexOptions.Compiled); | |
| if (m.Success && m.Groups.Count > 1) return m.Groups[1].Value; | |
| if (id == 0) return "Main"; | |
| return EMPTY_CLASS_NAME; | |
| } | |
| public static bool IsClass(string text = "") { | |
| return Regex.Match(text, "class\\s+(\\w+)", RegexOptions.Compiled).Success; | |
| } | |
| public string[] GetFuncSignatures() { | |
| int in_brackets = 0; | |
| string functions = ""; | |
| string name = GetClassName(); | |
| bool has_class_def = name != EMPTY_CLASS_NAME && name != MAIN_CLASS_NAME; | |
| foreach (char c in content) { | |
| if (c == '{') { in_brackets++; functions += "{"; continue; } | |
| if (c == '}') { in_brackets--; functions += "}"; continue; } | |
| if (has_class_def && in_brackets != 1) continue; | |
| else if (!has_class_def && in_brackets != 0) continue; | |
| if (c != '\r' && c != '\n' && c != '\t') functions += c; | |
| } | |
| functions = Regex.Replace(functions, @"\s+", " ", RegexOptions.Compiled); //Replace multiple spaces by single | |
| functions = functions.Replace(" (", "("); | |
| //Debug.Log(GetClassName() + "-> found " + func_regexp_name.Matches(functions).Count + " functions in: " + functions); | |
| return func_regexp_name.Matches(functions).Cast<Match>().Select(x=>x.Groups[1].Value).ToArray(); | |
| //functions = functions.Replace(")", ")|"); | |
| //return functions.Split(new char[]{'|'}, StringSplitOptions.RemoveEmptyEntries).Select((x)=>x.Trim()).Where((x)=>x != "").ToArray(); | |
| } | |
| public static string[] GetFuncNameAndParamFromSignature(string signature) { | |
| string name = signature.Substring(0, signature.LastIndexOf("(")).Trim(); | |
| name = name.Substring(name.LastIndexOf(" ") + 1).Trim(); | |
| return new string[]{ name, signature.Substring(signature.LastIndexOf("(")).Trim() }; | |
| } | |
| public string GetFuncBySignature(string signature) { | |
| int ind = content.IndexOf(signature); | |
| if (ind < 0) return ""; | |
| int ind_br = content.IndexOf("{", ind) + 1; | |
| int end = 0; | |
| int level = 0; | |
| bool in_str1 = false; | |
| bool in_str2 = false; | |
| for (int i = ind_br; i < content.Length; i++) { | |
| if (content[i] == '"') in_str1 = !in_str1; | |
| if (content[i] == '\'') in_str2 = !in_str2; | |
| if (in_str1 || in_str2) continue; | |
| if (content[i] == '{') level++; | |
| if (content[i] == '}') level--; | |
| if (level < 0) { end = i; break; } | |
| } | |
| //Debug.Log("start: " + ind + ", end: " + end + ", count: " + (end - ind) + ", content: " + content.Substring(ind, end - ind)); | |
| if (level >= 0) return ""; //not closed brackets | |
| //else return signature + " {\r\n" + content.Substring(ind, end - ind).Trim(); | |
| else return content.Substring(ind, end - ind + 1).Trim(); | |
| // Match m = func_regexp_content.Match(content, ind); | |
| // if (m.Success) return signature + m.Value.Trim(); else return ""; | |
| } | |
| } | |
| public struct EnemyInfo { | |
| public int HP; | |
| public int MP; | |
| public float pos_x; | |
| public float pos_y; | |
| } | |
| public class BOT : MonoBehaviour | |
| { | |
| //Stats | |
| public static int HP = 100; | |
| public static int MP = 7; | |
| public static int speed = 5; | |
| public static int qEnergy = 0; | |
| //Config | |
| public static float moving_speed = 0.025f; | |
| static float rotating_speed = 1f; | |
| //Obj reference | |
| public static GameObject bot_obj; | |
| public static GameObject talk_plane; | |
| public static GameObject bot_shield; | |
| static Text talk_text; | |
| public static BOT bot_instance; | |
| public static Text_Editor script_editor; | |
| //Controls | |
| public static Action act = null; | |
| public static List<Action> events = new List<Action>(); | |
| public static bool act_in_process = false; | |
| public static bool pause = false; | |
| public static bool pause_command = false; | |
| public static bool frame_advance = false; | |
| public static bool frame_advance_command = false; | |
| public static bool is_paused = false; | |
| public static System.Threading.Thread script_thread = null; | |
| public static int suspend_script = 0; | |
| public enum Pause_States { Reset, Pause_Command, Pause_Immediate, Advance_Command }; | |
| //Internals | |
| static int val_to_return_int = 0; | |
| static float val_to_return_float = 0f; | |
| static bool val_to_return_bool = false; | |
| static string val_to_return_string = ""; | |
| static Vector2 val_to_return_vector2; | |
| static Enemy val_to_return_enemy = null; | |
| static EnemyInfo val_to_return_enemy_info; | |
| static UnityEngine.Object val_to_return_object; | |
| static System.Object val_to_return_object_sys; | |
| public static List<KeyCode> key_downs = new List<KeyCode>(); | |
| Action bot_anim_pause = null; | |
| Action bot_anim_unpause = null; | |
| //public static | |
| public static bool dead = false; | |
| public static bool dying_in_progress = false; | |
| public static Animator bot_animator = null; | |
| public static List<Collider> cur_colliders = new List<Collider>(); | |
| public static Tweener tw_talk = null; | |
| public static string last_error = ""; | |
| public static string blocked = ""; | |
| //Debugger | |
| public static List<DebugInfoStruct> DebugInfo_Instructions = new List<DebugInfoStruct>(); | |
| public struct DebugInfoStruct { | |
| public int CommandCharStart; | |
| public int CommandCharEnd; | |
| public int Editor_Line_Index; | |
| } | |
| public enum Directions { left, right, forward, backward } | |
| void Start() | |
| { | |
| bot_instance = this; | |
| bot_obj = GameObject.Find("Robot"); | |
| bot_animator = bot_obj.transform.GetChild(0).GetComponent<Animator>(); | |
| talk_plane = bot_obj.transform.Find("TalkPlane").gameObject; | |
| talk_text = GameObject.Find("Talk_Text").GetComponent<Text>(); | |
| talk_plane.SetActive(false); | |
| bot_anim_pause = new Action(()=> bot_animator.speed = 0f ); | |
| bot_anim_unpause = new Action(()=> bot_animator.speed = 1f ); | |
| } | |
| //This functions are called async, from another thread | |
| public static void Say(string str, float duration = 1.2f) | |
| { | |
| if (blocked.ToLower().Contains("say(x)")) throw new Exception("I don't know about 'Say(x)' method yet."); | |
| act = () => bot_instance.SayShow(str, duration); Thread_Wait(); | |
| } | |
| public static void Say(float f, float duration = 1.2f) | |
| { | |
| if (blocked.ToLower().Contains("say(f)")) throw new Exception("I don't know about 'Say(f)' method yet."); | |
| act = () => bot_instance.SayShow(f.ToString("N8"), duration); Thread_Wait(); | |
| } | |
| public static void Move(int d = 999999) | |
| { | |
| if (d == 999999 && blocked.ToLower().Contains("move()")) throw new Exception("I don't know about 'Move()' method yet."); | |
| if (d != 999999 && blocked.ToLower().Contains("move(x)")) throw new Exception("I don't know about 'Move(x)' method yet."); | |
| act = () => bot_instance.StartCoroutine("MoveCoroutine", d); Thread_Wait(); | |
| } | |
| public static void Move(float f) | |
| { | |
| if (blocked.ToLower().Contains("move(x)")) throw new Exception("I don't know about 'Move(x)' method yet."); | |
| act = () => bot_instance.StartCoroutine("MoveCoroutineFloat", f); Thread_Wait(); | |
| } | |
| public static void Rotate(int d) | |
| { | |
| if (blocked.ToLower().Contains("rotate(x)")) throw new Exception("I don't know about 'Rotate(x)' method yet."); | |
| act = () => bot_instance.StartCoroutine("RotateCoroutine", d); Thread_Wait(); | |
| } | |
| public static void RotateTo(float x, float y, float step = 0f) | |
| { | |
| bool step_Is_0 = Mathf.Approximately(step, 0f); | |
| if (step_Is_0 && blocked.ToLower().Contains("rotateto(x,y)")) throw new Exception("I don't know about 'RotateTo(x, y)' method yet."); | |
| if (!step_Is_0 && blocked.ToLower().Contains("rotateto(x,y,f)")) throw new Exception("I don't know about 'RotateTo(x, y, s)' method yet."); | |
| act = () => bot_instance.StartCoroutine(bot_instance.RotateToCoroutine(x, y, step)); Thread_Wait(); | |
| } | |
| public static void Scale(float value) | |
| { | |
| if (blocked.ToLower().Contains("scale(v)")) throw new Exception("I don't know about 'Scale(v)' method yet."); | |
| act = () => bot_instance.ScaleSub(value); Thread_Wait(); | |
| } | |
| public static int PickUp() | |
| { | |
| if (blocked.ToLower().Contains("pickup()")) throw new Exception("I don't know about 'PickUp()' function yet."); | |
| act = () => bot_instance.StartCoroutine(bot_instance.PickupCoroutine("", false)); Thread_Wait(); | |
| return val_to_return_int; | |
| } | |
| public static int CheckContainerCapacity() | |
| { | |
| if (blocked.ToLower().Contains("checkcontainercapacity()")) throw new Exception("I don't know about 'CheckContainerCapacity()' function yet."); | |
| act = () => bot_instance.StartCoroutine(bot_instance.PickupCoroutine("check", false)); Thread_Wait(); | |
| return val_to_return_int; | |
| } | |
| public static void DestroyContainer() | |
| { | |
| if (blocked.ToLower().Contains("destroycontainer()")) throw new Exception("I don't know about 'DestroyContainer()' method yet."); | |
| act = () => bot_instance.StartCoroutine(bot_instance.PickupCoroutine("destroy", false)); Thread_Wait(); | |
| } | |
| public static void DestroyContainerWithAdditionalBrutality() | |
| { | |
| if (blocked.ToLower().Contains("destroycontainerwithadditionalbrutality()")) throw new Exception("I don't know about 'DestroyContainerWithAdditionalBrutality()' method yet."); | |
| act = () => bot_instance.StartCoroutine(bot_instance.PickupCoroutine("destroy", true)); Thread_Wait(); | |
| } | |
| public static void PutEnergy(int q) | |
| { | |
| //Debug.Log("PutEnergy - async"); | |
| if (blocked.ToLower().Contains("putenergy()")) throw new Exception("I don't know about 'PutEnergy()' method yet."); | |
| KeyValuePair<Loot.loot_type_enum, int> t; | |
| t = new KeyValuePair<Loot.loot_type_enum, int>(Loot.loot_type_enum.QuanticEnergy, q); | |
| act = () => bot_instance.StartCoroutine("PutCoroutine", t); Thread_Wait(); | |
| } | |
| public static void Fight() | |
| { | |
| if (blocked.ToLower().Contains("fight()")) throw new Exception("I don't know about 'Fight()' method yet."); | |
| act = () => bot_instance.StartCoroutine("Fight", ""); Thread_Wait(); | |
| } | |
| public static int CheckPotatoes() { | |
| if (blocked.ToLower().Contains("checkpotatoes()")) throw new Exception("I don't know about 'CheckPotatoes()' method yet."); | |
| act = () => bot_instance.CheckPotatesSub(); Thread_Wait(); | |
| return val_to_return_int; | |
| } | |
| public static Enemy GetClosestEnemy() | |
| { | |
| if (blocked.ToLower().Contains("getclosestenemy()")) throw new Exception("I don't know about 'GetClosestEnemy()' function yet."); | |
| act = () => bot_instance.GetClosestEnemySub(); Thread_Wait(); | |
| return val_to_return_enemy; | |
| } | |
| public static EnemyInfo GetClosestEnemyInfo() | |
| { | |
| if (blocked.ToLower().Contains("getclosestenemyinfo()")) throw new Exception("I don't know about 'GetClosestEnemyInfo()' function yet."); | |
| act = () => bot_instance.GetClosestEnemyInfoSub(); Thread_Wait(); | |
| return val_to_return_enemy_info; | |
| } | |
| public static Projectile GetClosestProjectile() | |
| { | |
| if (blocked.ToLower().Contains("getclosestprojectile()")) throw new Exception("I don't know about 'GetClosestProjectile()' function yet."); | |
| act = () => bot_instance.GetClosestProjectileSub(); Thread_Wait(); | |
| return ((Projectile)val_to_return_object); | |
| } | |
| public static string GetText() { | |
| if (blocked.ToLower().Contains("gettext()")) throw new Exception("I don't know about 'GetText()' function yet."); | |
| act = () => bot_instance.GetTextSub(); Thread_Wait(); | |
| return val_to_return_string; | |
| } | |
| public static bool GetIndicatorState() { | |
| if (blocked.ToLower().Contains("getsndicatorstate()")) throw new Exception("I don't know about 'GetIndicatorState()' function yet."); | |
| act = () => bot_instance.GetIndicatorStateSub(); Thread_Wait(); | |
| return val_to_return_bool; | |
| } | |
| public static void SetSwitchState(bool b) { | |
| if (blocked.ToLower().Contains("setswitchstate()")) throw new Exception("I don't know about 'SetSwitchState(bool b)' method yet."); | |
| act = () => bot_instance.SetSwitchStateSub(b); suspend_script++; Thread_Wait(); | |
| } | |
| public static Vector2 Position() | |
| { | |
| if (blocked.ToLower().Contains("position()")) throw new Exception("I don't know about 'Position()' function yet."); | |
| act = () => bot_instance.GetBotPosition(); Thread_Wait(); | |
| return val_to_return_vector2; | |
| } | |
| public static bool GetKey(KeyCode k) | |
| { | |
| if (blocked.ToLower().Contains("getkey()")) throw new Exception("I don't know about 'getkey()' function yet."); | |
| act = () => bot_instance.GetKeySub(k); Thread_Wait(); | |
| return val_to_return_bool; | |
| } | |
| public static bool GetKeyDown(KeyCode k) | |
| { | |
| if (blocked.ToLower().Contains("getkeydown()")) throw new Exception("I don't know about 'getkeydown()' function yet."); | |
| act = () => bot_instance.GetKeySub(k, true); Thread_Wait(); | |
| return val_to_return_bool; | |
| } | |
| public static bool CheckObstacle(Directions dir = Directions.forward) | |
| { | |
| if (blocked.ToLower().Contains("checkobstacle()")) throw new Exception("I don't know about 'CheckObstacle()' function yet."); | |
| act = () => bot_instance.CheckObstacleSub(dir); Thread_Wait(); | |
| return val_to_return_bool; | |
| } | |
| public static BOT_Shield CreateShield(Vector3 pos) | |
| { | |
| if (blocked.ToLower().Contains("createshield()")) throw new Exception("I don't know about 'CreateShield()' function yet."); | |
| act = () => bot_instance.CreateShieldSub(pos); Thread_Wait(); | |
| return ((BOT_Shield)val_to_return_object); | |
| } | |
| public static float GetFloorSquare() | |
| { | |
| if (blocked.ToLower().Contains("getfloorsquare()")) throw new Exception("I don't know about 'GetFloorSquare()' function yet."); | |
| act = () => bot_instance.GetFloorSquareSub(); Thread_Wait(); | |
| return val_to_return_float; | |
| } | |
| // public static Terminal.terminal_data Terminal_Read() { | |
| // if (blocked.ToLower().Contains("terminal_read()")) throw new Exception("I don't know about 'Terminal_Read()' function yet."); | |
| // act = () => bot_instance.StartCoroutine( bot_instance.Terminal_ReadSub() ); Thread_Wait(); | |
| // return (Terminal.terminal_data)val_to_return_object_sys; | |
| // } | |
| // public static void Terminal_Answer(bool responce) { | |
| // if (blocked.ToLower().Contains("terminal_answer()")) throw new Exception("I don't know about 'Terminal_Answer()' method yet."); | |
| // act = () => bot_instance.StartCoroutine ( bot_instance.Terminal_AnsewerSub(responce) ); Thread_Wait(); | |
| // } | |
| // public static void Terminal_Answer(string[] responce) { | |
| // if (blocked.ToLower().Contains("terminal_answer()")) throw new Exception("I don't know about 'Terminal_Answer()' method yet."); | |
| // act = () => bot_instance.StartCoroutine ( bot_instance.Terminal_AnsewerSub(false, true, responce) ); Thread_Wait(); | |
| // } | |
| public static Terminal_Universal.terminal_data Terminal_Read() { | |
| if (blocked.ToLower().Contains("terminal_read()")) throw new Exception("I don't know about 'Terminal_Read()' function yet."); | |
| act = () => bot_instance.StartCoroutine( bot_instance.TerminalU_ReadSub() ); Thread_Wait(); | |
| return (Terminal_Universal.terminal_data)val_to_return_object_sys; | |
| } | |
| public static void Terminal_Answer(bool responce) { | |
| if (blocked.ToLower().Contains("terminal_answer()")) throw new Exception("I don't know about 'Terminal_Answer()' method yet."); | |
| act = () => bot_instance.StartCoroutine ( bot_instance.TerminalU_AnsewerSub(responce) ); Thread_Wait(); | |
| } | |
| public static void Terminal_Answer(string[] responce) { | |
| if (blocked.ToLower().Contains("terminal_answer()")) throw new Exception("I don't know about 'Terminal_Answer()' method yet."); | |
| act = () => bot_instance.StartCoroutine ( bot_instance.TerminalU_AnsewerSub(false, true, responce) ); Thread_Wait(); | |
| } | |
| public static void Terminal_Answer(object responce) { | |
| if (blocked.ToLower().Contains("terminal_answer()")) throw new Exception("I don't know about 'Terminal_Answer()' method yet."); | |
| act = () => bot_instance.StartCoroutine ( bot_instance.TerminalU2_AnsewerSub(responce) ); Thread_Wait(); | |
| } | |
| public static void Die() | |
| { | |
| if (blocked.ToLower().Contains("die()")) throw new Exception("I don't know about 'die()' method yet."); | |
| HP = 0; Thread_Wait(); | |
| } | |
| public static void ProcessEvents() | |
| { | |
| lock (events) { | |
| foreach (var a in events) { | |
| a.Invoke(); | |
| if (last_error != "") { throw new Exception(last_error); } | |
| } | |
| events.Clear(); | |
| key_downs.Clear(); | |
| } | |
| } | |
| public static void WaitForEvents() | |
| { | |
| while (true) { | |
| System.Threading.Thread.Sleep(10); | |
| ProcessEvents(); | |
| } | |
| } | |
| public static void P(int n) | |
| { | |
| //This is called from user script by autogenerated calls between each user command | |
| if (script_editor.Have_breakpoint ( DebugInfo_Instructions[n].Editor_Line_Index )) { | |
| BOT.Set_Pause(BOT.Pause_States.Pause_Command); | |
| act = () => { Control_UI.set_pause_state(); act = null; act_in_process = false; }; Thread_Wait(); | |
| } | |
| if (pause_command) { | |
| act = () => bot_instance.StartCoroutine("Pause", n); Thread_Wait(); | |
| } | |
| } | |
| public static void Thread_Wait() | |
| { | |
| while (act != null || suspend_script > 0) { | |
| System.Threading.Thread.Sleep(10); | |
| if (last_error != "") { throw new Exception(last_error); } | |
| } | |
| if (last_error != "") { throw new Exception(last_error); } | |
| } | |
| //End async functions | |
| public void SayShow(string str, float duration = 1.2f) | |
| { | |
| //Debug.Log("Saying: " + str); | |
| tw_talk = null; | |
| talk_text.text = str; | |
| talk_plane.transform.DOKill(); | |
| talk_plane.transform.localScale = new Vector3(0f, 0f, 0f); | |
| talk_plane.SetActive(true); | |
| //Face to camera | |
| Vector3 lookPos = Camera.main.transform.position - talk_plane.transform.position; lookPos.y = 0f; | |
| talk_plane.transform.rotation = Quaternion.LookRotation(lookPos); | |
| talk_plane.transform.Rotate(90f, 0f, 0f); | |
| tw_talk = talk_plane.transform.DOScale(new Vector3(0.1f, 0.1f, 0.1f), 1f).SetEase(Ease.OutBounce).OnComplete(()=>{ | |
| foreach (var sl in Engine.Level_StringListiners) sl.OnSay(str); | |
| tw_talk = talk_plane.transform.DOScale(new Vector3(0f, 0f, 0f), 1f).SetEase(Ease.OutBounce).SetDelay(duration).OnComplete(()=>{ | |
| act_in_process = false; act = null; tw_talk = null; Engine.SetRequirement("SAY"); | |
| }); | |
| }); | |
| } | |
| IEnumerator MoveCoroutine(int d) | |
| { | |
| //Debug.Log(d); | |
| float speed = moving_speed; | |
| if (d < 0) speed *= -1; | |
| Vector3 cur_pos = bot_obj.transform.localPosition; | |
| Vector3 target_pos = bot_obj.transform.localPosition + (bot_obj.transform.forward * d); | |
| //bot_obj.GetComponent<AudioSource> | |
| Robot.PlaySfx(0); | |
| float bot_fall_threashold = (bot_obj.transform.lossyScale.y / 3f) * 0.5f; | |
| while (Vector3.Distance(cur_pos, target_pos) > (moving_speed * Time.timeScale)) | |
| { | |
| if (script_thread == null) break; | |
| if (!pause && bot_obj.transform.position.y > bot_fall_threashold) //This is needed to leave control when bot is falling | |
| { | |
| cur_pos = bot_obj.transform.localPosition; | |
| cur_pos += bot_obj.transform.forward * speed * Time.timeScale; | |
| //bot_obj.transform.localPosition = cur_pos; | |
| bot_obj.GetComponent<Rigidbody>().MovePosition(cur_pos); | |
| yield return new WaitForFixedUpdate(); | |
| } | |
| if (frame_advance) pause = true; | |
| yield return null; | |
| } | |
| Robot.PlaySfx(-1); | |
| if (!pause && bot_obj.transform.position.y > bot_fall_threashold) bot_obj.GetComponent<Rigidbody>().MovePosition(target_pos); | |
| //Debug.Log("Finish moving."); | |
| if (script_thread != null) bot_obj.transform.localPosition = target_pos; | |
| act_in_process = false; act = null; | |
| } | |
| IEnumerator MoveCoroutineFloat(float d) | |
| { | |
| float speed = moving_speed; | |
| if (d < 0) speed *= -1; | |
| Vector3 cur_pos = bot_obj.transform.localPosition; | |
| Vector3 target_pos = bot_obj.transform.localPosition + (bot_obj.transform.forward * d); | |
| while (Vector3.Distance(cur_pos, target_pos) > (moving_speed * Time.timeScale)) | |
| { | |
| if (script_thread == null) break; | |
| if (!pause && bot_obj.transform.position.y > 0.5f) //This is needed to leave control when bot is falling | |
| { | |
| cur_pos += bot_obj.transform.forward * speed * Time.timeScale; | |
| bot_obj.transform.localPosition = cur_pos; | |
| } | |
| if (frame_advance) pause = true; | |
| yield return null; | |
| } | |
| if (!pause && bot_obj.transform.position.y > 0.5f) bot_obj.GetComponent<Rigidbody>().MovePosition(target_pos); | |
| //Debug.Log("Finish moving."); | |
| if (script_thread != null) bot_obj.transform.localPosition = target_pos; | |
| act_in_process = false; act = null; | |
| } | |
| IEnumerator RotateCoroutine(int d) | |
| { | |
| float speed = rotating_speed; | |
| if (d < 0) speed *= -1; | |
| Vector3 old_pos = bot_obj.transform.position; | |
| Vector3 cur_rot = bot_obj.transform.rotation.eulerAngles; | |
| float cur_rot_y = cur_rot.y; | |
| float target_rot_y = cur_rot_y + d; | |
| Robot.PlaySfx(1); | |
| while (Mathf.Abs(Mathf.DeltaAngle(cur_rot_y, target_rot_y)) > (rotating_speed * Time.timeScale)) | |
| { | |
| if (script_thread == null) break; | |
| if (!pause) | |
| { | |
| cur_rot_y += speed * Time.timeScale; | |
| bot_obj.transform.rotation = Quaternion.Euler ( cur_rot.x, cur_rot_y, cur_rot.z ); | |
| } | |
| if (frame_advance) pause = true; | |
| yield return null; | |
| } | |
| Robot.PlaySfx(-1); | |
| old_pos.y = bot_obj.transform.position.y; | |
| bot_obj.transform.position = old_pos; | |
| if (script_thread != null) bot_obj.transform.rotation = Quaternion.Euler ( cur_rot.x, target_rot_y, cur_rot.z ); | |
| act_in_process = false; act = null; | |
| } | |
| IEnumerator RotateToCoroutine(float x, float y, float step = 0f) | |
| { | |
| Vector3 targetPos = new Vector3(x, 0f, y); | |
| Vector3 direction = (targetPos - bot_obj.transform.position).normalized; | |
| Quaternion target_rot = Quaternion.LookRotation( new Vector3(direction.x, 0f, direction.z)); | |
| Vector3 cur_rot = bot_obj.transform.rotation.eulerAngles; | |
| float cur_rot_y = cur_rot.y; | |
| float speed = rotating_speed; | |
| if (Mathf.DeltaAngle(cur_rot_y, target_rot.eulerAngles.y) < 0) speed *= -1; | |
| float total = 0f; | |
| while (Mathf.Abs(Mathf.DeltaAngle(cur_rot_y, target_rot.eulerAngles.y)) > (rotating_speed * Time.timeScale)) | |
| { | |
| if (script_thread == null) break; | |
| if (!pause) | |
| { | |
| cur_rot_y += speed * Time.timeScale; | |
| total += Mathf.Abs(speed * Time.timeScale); | |
| bot_obj.transform.rotation = Quaternion.Euler ( cur_rot.x, cur_rot_y, cur_rot.z ); | |
| if (step > 0f && total >= step) { | |
| act_in_process = false; act = null; yield break; | |
| } | |
| } | |
| if (frame_advance) pause = true; | |
| yield return null; | |
| } | |
| if (script_thread != null) bot_obj.transform.rotation = Quaternion.Euler ( cur_rot.x, target_rot.eulerAngles.y, cur_rot.z ); | |
| act_in_process = false; act = null; | |
| } | |
| IEnumerator PickupCoroutine(string str = "", bool brutality = false) { | |
| val_to_return_int = 0; | |
| List<Collider> colliders_to_remove = new List<Collider>(); | |
| //Version of pickup in front | |
| RaycastHit hit; | |
| Ray ray = new Ray(bot_obj.transform.position, bot_obj.transform.forward); | |
| if (!Physics.Raycast(ray, out hit, 1f)) { | |
| last_error = "There is no loot in front of me."; yield break; | |
| } | |
| Collider col = hit.collider; | |
| Loot loot = col.GetComponent<Loot>(); | |
| if (loot) { | |
| while (bot_animator.GetCurrentAnimatorStateInfo(0).IsName("Anim_PickUp_Front")) yield return null; | |
| //BOT Animation | |
| float l = 0f; | |
| if (str != "check") { | |
| if (str == "destroy" && loot.gameObject.name.StartsWith("toilet")) { | |
| //Custom destroy-toilet animation | |
| if (brutality) { | |
| //Sledgehammer | |
| bot_animator.SetTrigger("SledgeHammer"); | |
| yield return new WaitForSeconds_BOTPauseAware((1f / 60f) * 50f, bot_anim_pause, bot_anim_unpause); | |
| var broken_toilet = Instantiate(loot.additional_resources[0], loot.transform.position, loot.transform.rotation); | |
| Engine.Objects_To_Destroy.Add(broken_toilet); loot.gameObject.SetActive(false); | |
| yield return new WaitForSeconds_BOTPauseAware(1.5f, bot_anim_pause, bot_anim_unpause); | |
| Engine.Objects_To_Destroy.Remove(broken_toilet); Destroy(broken_toilet); loot.gameObject.SetActive(true); | |
| } else { | |
| //Petard | |
| //Test blink while throwing petard | |
| // BOT.bot_animator.SetTrigger("Blink"); | |
| // yield return new WaitForSeconds(0.2f); | |
| BOT.bot_animator.Play("New State", 1); //Reset eyes before playing timeline | |
| BOT.bot_animator.Play("New State", 2); //Reset tail before playing timeline | |
| yield return new WaitForEndOfFrame(); | |
| var pd = bot_obj.GetComponent<UnityEngine.Playables.PlayableDirector>(); | |
| pd.SetGenericBinding(pd.playableAsset.outputs.ElementAt(1).sourceObject, loot.gameObject); | |
| pd.Play(); | |
| yield return new WaitForSeconds_BOTPauseAware(Convert.ToSingle(pd.duration), bot_anim_pause, bot_anim_unpause); | |
| } | |
| } else { | |
| //Pickup/Destroy - bot arm animation | |
| foreach(AnimationClip a in bot_animator.runtimeAnimatorController.animationClips) | |
| if (a.name.ToUpper() == "Anim_PickUp_Front".ToUpper()) | |
| l = a.length - 0.5f; | |
| bot_animator.SetTrigger("Pickup"); | |
| yield return new WaitForSeconds_BOTPauseAware(l / 2, bot_anim_pause, bot_anim_unpause); | |
| } | |
| val_to_return_int = loot.quantity; //Because random containers requier to get quantity at the moment we pick it | |
| //Add loot to bot, after half animation, because it will be instantly logged | |
| if (str == "") { //Only if pickup | |
| if (loot.loot_type == Loot.loot_type_enum.HP) { HP += loot.quantity; } | |
| else if (loot.loot_type == Loot.loot_type_enum.MP) { MP += loot.quantity; } | |
| else if (loot.loot_type == Loot.loot_type_enum.QuanticEnergy) { qEnergy += loot.quantity; } | |
| Engine.Loot_list.Add(new KeyValuePair<Loot.loot_type_enum, int>(loot.loot_type, loot.quantity)); | |
| //Debug.Log("Loot list count: " + Engine.Loot_list.Count.ToString()); | |
| } | |
| } else { | |
| //Check - scanner animation | |
| Transform scanner = bot_obj.transform.GetChild(0).GetChild(8).GetChild(0); | |
| scanner.localRotation = Quaternion.Euler(-25f, 0f, 0f); | |
| scanner.gameObject.SetActive(true); | |
| Tweener scan_tween = scanner.DOLocalRotate(new Vector3(25f, 0f, 0f), 2f); | |
| yield return new WaitForSeconds_BOTPauseAware(2f, new Action(()=>scan_tween.Pause()), new Action(()=>scan_tween.Play())); | |
| scanner.gameObject.SetActive(false); | |
| val_to_return_int = loot.quantity; //Because random containers requier to get quantity at the moment we pick it | |
| Hud.Log("Scan result: container contains " + loot.quantity.ToString() + " " + loot.loot_type.ToString()); | |
| } | |
| //If it's pickup or destroy operation - hide continaer | |
| if (str != "check") { | |
| if (str != "destroy") { loot.PickUpAndDestroy(0); } | |
| else { loot.PickUpAndDestroy(1); } | |
| colliders_to_remove.Add(col); | |
| } | |
| yield return new WaitForSeconds_BOTPauseAware(l / 2, bot_anim_pause, bot_anim_unpause); | |
| if (str != "check") while (loot.gameObject.activeSelf) yield return null; | |
| if (str == "destroy") Hud.Log("Container destroyed"); | |
| } else { | |
| last_error = "There is no loot in front of me."; | |
| } | |
| for (int i = 0; i < colliders_to_remove.Count; i++){ | |
| cur_colliders.Remove(colliders_to_remove[i]); | |
| } | |
| if (frame_advance) pause = true; | |
| act_in_process = false; act = null; | |
| } | |
| IEnumerator PutCoroutine(KeyValuePair<Loot.loot_type_enum, int> s) { | |
| //Debug.Log("PutEnergy - main thread"); | |
| RaycastHit hit; | |
| Ray ray = new Ray(bot_obj.transform.position, bot_obj.transform.forward); | |
| if (!Physics.Raycast(ray, out hit, 1f)) { | |
| last_error = "There is no collector in front of me."; yield break; | |
| } | |
| Collider col = hit.collider; | |
| Collector clctr = col.GetComponent<Collector>(); | |
| if (clctr) { | |
| clctr.Put(s.Key, s.Value); | |
| clctr.GetComponent<Animator>().SetTrigger("Open"); | |
| //TODO: BOT Put Animation | |
| yield return new WaitForSeconds_BOTPauseAware(1f); | |
| } else { | |
| last_error = "There is no collector in front of me."; | |
| } | |
| if (frame_advance) pause = true; | |
| act_in_process = false; act = null; | |
| } | |
| IEnumerator Fight(string str) | |
| { | |
| RaycastHit hit; | |
| Ray ray = new Ray(bot_obj.transform.position, bot_obj.transform.forward); | |
| if (!Physics.Raycast(ray, out hit, 1f)) { | |
| last_error = "There is no enemy in front of me."; yield break; | |
| } | |
| Collider col = hit.collider; | |
| Enemy e = col.transform.parent.GetComponent<Enemy>(); | |
| if (e) { | |
| if (e.HP <= 0) {last_error = "The enemy is already dead."; yield break;} | |
| bot_animator.SetTrigger("Pickup"); | |
| float l = 0f; | |
| foreach(AnimationClip a in bot_animator.runtimeAnimatorController.animationClips) | |
| if (a.name.ToUpper() == "Anim_PickUp_Front".ToUpper()) | |
| l = a.length - 0.5f; | |
| yield return new WaitForSeconds_BOTPauseAware(l, bot_anim_pause, bot_anim_unpause); | |
| e.TakeDamage(1); | |
| yield return new WaitForSeconds_BOTPauseAware(0.5f, bot_anim_pause, bot_anim_unpause); | |
| } else { | |
| last_error = "There is no enemy in front of me."; | |
| } | |
| if (frame_advance) pause = true; | |
| act_in_process = false; act = null; | |
| } | |
| void GetKeySub(KeyCode k, bool down = false) | |
| { | |
| if (down) val_to_return_bool = key_downs.Contains(k); | |
| else val_to_return_bool = Input.GetKey(k); | |
| if (frame_advance) pause = true; | |
| act_in_process = false; act = null; | |
| } | |
| void GetClosestEnemySub() | |
| { | |
| Enemy enemy = null; | |
| float min_dist = 1000000000; | |
| foreach (Enemy e in Engine.Level_Enemies) { | |
| float cur_dist = Vector3.Distance(e.transform.GetChild(0).position, bot_obj.transform.position); | |
| if (cur_dist < min_dist) { | |
| enemy = e; | |
| min_dist = cur_dist; | |
| } | |
| } | |
| if (enemy == null) Hud.Log("There is no living enemies."); | |
| val_to_return_enemy = enemy; | |
| if (frame_advance) pause = true; | |
| act_in_process = false; act = null; | |
| } | |
| void GetClosestEnemyInfoSub() | |
| { | |
| Enemy enemy = null; | |
| float min_dist = 1000000000; | |
| foreach (Enemy e in Engine.Level_Enemies) { | |
| float cur_dist = Vector3.Distance(e.transform.GetChild(0).position, bot_obj.transform.position); | |
| if (cur_dist < min_dist) { | |
| enemy = e; | |
| min_dist = cur_dist; | |
| } | |
| } | |
| if (enemy == null) Hud.Log("There is no living enemies."); | |
| EnemyInfo ei = new EnemyInfo(); | |
| ei.HP = enemy.HP; | |
| ei.pos_x = enemy.transform.GetChild(0).position.x; | |
| ei.pos_y = enemy.transform.GetChild(0).position.z; | |
| val_to_return_enemy_info = ei; | |
| if (frame_advance) pause = true; | |
| act_in_process = false; act = null; | |
| } | |
| void GetClosestProjectileSub() | |
| { | |
| Projectile prj = null; | |
| float min_dist = 3; | |
| foreach (Projectile p in Engine.Level_Projectiles) { | |
| if (p.captured) continue; | |
| float cur_dist = Vector3.Distance(p.transform.position, bot_obj.transform.position); | |
| if (cur_dist < min_dist) { | |
| prj = p; | |
| min_dist = cur_dist; | |
| } | |
| } | |
| //if (prj == null) Hud.Log("There is no projectiles near me."); //This just spam to log if doing it in loop | |
| val_to_return_object = prj; | |
| if (frame_advance) pause = true; | |
| act_in_process = false; act = null; | |
| } | |
| void GetFloorSquareSub() | |
| { | |
| RaycastHit hit; | |
| if (Physics.Raycast(bot_obj.transform.position, -bot_obj.transform.up, out hit)) { | |
| Vector3 sz = hit.collider.bounds.size; | |
| val_to_return_float = sz.x * sz.z; | |
| } else { | |
| val_to_return_float = -1f; | |
| } | |
| if (frame_advance) pause = true; | |
| act_in_process = false; act = null; | |
| } | |
| void GetTextSub() { | |
| RaycastHit hit; | |
| Ray ray = new Ray(bot_obj.transform.position, bot_obj.transform.forward); | |
| if (!Physics.Raycast(ray, out hit, 1f)) { | |
| last_error = "There is no text in front of me."; return; | |
| } | |
| Collider col = hit.collider; | |
| Readable r = col.GetComponent<Readable>(); | |
| if (r) { | |
| val_to_return_string = r.text; | |
| } else { | |
| last_error = "There is no text in front of me."; | |
| } | |
| Hud.Log("Bot has read: \""+ val_to_return_string + "\""); | |
| if (frame_advance) pause = true; | |
| act_in_process = false; act = null; | |
| } | |
| void GetIndicatorStateSub() { | |
| RaycastHit[] hits = Physics.RaycastAll(bot_obj.transform.position, bot_obj.transform.forward, 1f); | |
| if (hits.Count() > 0) { | |
| var led = hits.Where(h=> h.transform.GetComponent<Indicator_Led>() != null).Select(h=> h.transform.GetComponent<Indicator_Led>() ).FirstOrDefault(); | |
| if (led != null) { | |
| val_to_return_bool = led.GetState(); | |
| if (val_to_return_bool) Hud.Log("Бот узнал что индикатор включён"); else Hud.Log("Бот узнал что индикатор выключен"); | |
| } else { | |
| last_error = "There is no indicators in front of me."; return; | |
| } | |
| } else { | |
| last_error = "There is no indicators in front of me."; return; | |
| } | |
| if (frame_advance) pause = true; | |
| act_in_process = false; act = null; | |
| } | |
| void SetSwitchStateSub(bool b) { | |
| RaycastHit[] hits = Physics.RaycastAll(bot_obj.transform.position, bot_obj.transform.forward, 1f); | |
| if (hits.Count() > 0) { | |
| var sw = hits.Where(h=> h.transform.GetComponent<Switch>() != null).Select(h=> h.transform.GetComponent<Switch>() ).FirstOrDefault(); | |
| if (sw != null) { | |
| sw.SetState(b, true); | |
| if (b) Hud.Log("Бот повернул переключатель в позицию вкл."); else Hud.Log("Бот повернул переключатель в позицию выкл."); | |
| } else { | |
| last_error = "There is no switches in front of me."; return; | |
| } | |
| } else { | |
| last_error = "There is no switches in front of me."; return; | |
| } | |
| if (frame_advance) pause = true; | |
| act_in_process = false; act = null; | |
| } | |
| void CheckPotatesSub() { | |
| val_to_return_int = 0; | |
| RaycastHit hit; | |
| Ray ray = new Ray(bot_obj.transform.position, -bot_obj.transform.up); | |
| if (Physics.Raycast(ray, out hit, 1f)) { | |
| Collider col = hit.collider; | |
| Floor_RandomPotatoes p = col.GetComponent<Floor_RandomPotatoes>(); | |
| if (p) { | |
| val_to_return_int = p.GetCellPotatoCount(); | |
| } | |
| } | |
| if (frame_advance) pause = true; | |
| act_in_process = false; act = null; | |
| } | |
| //Old Terminal --- obsolete | |
| // IEnumerator Terminal_ReadSub() { | |
| // RaycastHit hit; | |
| // Ray ray = new Ray(bot_obj.transform.position, bot_obj.transform.forward); | |
| // if (!Physics.Raycast(ray, out hit, 1f)) { | |
| // last_error = "There is no terminal in front of me."; | |
| // if (frame_advance) pause = true; | |
| // act_in_process = false; act = null; | |
| // yield break; | |
| // } | |
| // Collider col = hit.collider; | |
| // Terminal t = col.GetComponent<Terminal>(); | |
| // if (t) { | |
| // Terminal.terminal_data td = t.Read(); | |
| // while (!t.terminal_is_ready) { yield return null; } | |
| // val_to_return_object_sys = td; | |
| // } else { | |
| // //Try Terminal_Mail | |
| // Terminal_Mail tm = col.GetComponent<Terminal_Mail>(); | |
| // if (tm) { | |
| // Terminal.terminal_data td = tm.Read(); | |
| // while (!tm.terminal_is_ready) { yield return null; } | |
| // val_to_return_object_sys = td; | |
| // } else { | |
| // last_error = "There is no terminal in front of me."; | |
| // } | |
| // } | |
| // if (frame_advance) pause = true; | |
| // act_in_process = false; act = null; | |
| // } | |
| // IEnumerator Terminal_AnsewerSub(bool responce, bool is_mail_terminal = false, string[] responce_str = null) { | |
| // RaycastHit hit; | |
| // Ray ray = new Ray(bot_obj.transform.position, bot_obj.transform.forward); | |
| // if (!Physics.Raycast(ray, out hit, 1f)) { | |
| // last_error = "There is no terminal in front of me."; | |
| // if (frame_advance) pause = true; | |
| // act_in_process = false; act = null; | |
| // yield break; | |
| // } | |
| // Collider col = hit.collider; | |
| // if (!is_mail_terminal) { | |
| // Terminal t = col.GetComponent<Terminal>(); | |
| // if (t) { | |
| // t.Responce(responce); | |
| // while (!t.terminal_is_ready) { yield return null; } | |
| // } else { | |
| // last_error = "There is no terminal in front of me."; | |
| // } | |
| // } else { | |
| // Terminal_Mail t = col.GetComponent<Terminal_Mail>(); | |
| // if (t) { | |
| // t.Responce(responce_str); | |
| // while (!t.terminal_is_ready) { yield return null; } | |
| // } else { | |
| // last_error = "There is no terminal in front of me."; | |
| // } | |
| // } | |
| // if (frame_advance) pause = true; | |
| // act_in_process = false; act = null; | |
| // } | |
| IEnumerator TerminalU_ReadSub() { | |
| RaycastHit hit; | |
| Ray ray = new Ray(bot_obj.transform.position, bot_obj.transform.forward); | |
| if (!Physics.Raycast(ray, out hit, 1f)) { | |
| last_error = "There is no terminal in front of me."; | |
| if (frame_advance) pause = true; | |
| act_in_process = false; act = null; | |
| yield break; | |
| } | |
| Collider col = hit.collider; | |
| Terminal_Universal t = col.GetComponent<Terminal_Universal>(); | |
| if (t) { | |
| Terminal_Universal.terminal_data td = t.Read(); | |
| if (string.IsNullOrEmpty(t.terminal_error)) { | |
| while (!t.terminal_is_ready) { yield return null; } | |
| val_to_return_object_sys = td; | |
| } else { | |
| last_error = t.terminal_error; | |
| val_to_return_object_sys = null; | |
| } | |
| } else { | |
| last_error = "There is no terminal in front of me."; | |
| } | |
| if (frame_advance) pause = true; | |
| act_in_process = false; act = null; | |
| } | |
| IEnumerator TerminalU_AnsewerSub(bool responce, bool is_mail_terminal = false, string[] responce_str = null) { | |
| RaycastHit hit; | |
| Ray ray = new Ray(bot_obj.transform.position, bot_obj.transform.forward); | |
| if (!Physics.Raycast(ray, out hit, 1f)) { | |
| last_error = "There is no terminal in front of me."; | |
| if (frame_advance) pause = true; | |
| act_in_process = false; act = null; | |
| yield break; | |
| } | |
| Collider col = hit.collider; | |
| Terminal_Universal t = col.GetComponent<Terminal_Universal>(); | |
| if (t) { | |
| if (!is_mail_terminal) t.Responce(responce); | |
| else t.Responce(responce_str); | |
| if (string.IsNullOrEmpty(t.terminal_error)) { | |
| while (!t.terminal_is_ready) { yield return null; } | |
| } else { | |
| last_error = t.terminal_error; | |
| } | |
| } else { | |
| last_error = "There is no terminal in front of me."; | |
| } | |
| if (frame_advance) pause = true; | |
| act_in_process = false; act = null; | |
| } | |
| IEnumerator TerminalU2_AnsewerSub(object responce) { | |
| RaycastHit hit; | |
| Ray ray = new Ray(bot_obj.transform.position, bot_obj.transform.forward); | |
| if (!Physics.Raycast(ray, out hit, 1f)) { | |
| last_error = "There is no terminal in front of me."; | |
| if (frame_advance) pause = true; | |
| act_in_process = false; act = null; | |
| yield break; | |
| } | |
| Collider col = hit.collider; | |
| Terminal_Universal t = col.GetComponent<Terminal_Universal>(); | |
| if (t) { | |
| t.Responce(responce); | |
| if (string.IsNullOrEmpty(t.terminal_error)) { | |
| while (!t.terminal_is_ready) { yield return null; } | |
| } else { | |
| last_error = t.terminal_error; | |
| } | |
| } else { | |
| last_error = "There is no terminal in front of me."; | |
| } | |
| if (frame_advance) pause = true; | |
| act_in_process = false; act = null; | |
| } | |
| void GetBotPosition() | |
| { | |
| val_to_return_vector2 = new Vector2(bot_obj.transform.position.x, bot_obj.transform.position.z); | |
| if (frame_advance) pause = true; | |
| act_in_process = false; act = null; | |
| } | |
| void CheckObstacleSub(Directions dir) | |
| { | |
| Vector3 real_dir = Vector3.zero; | |
| if (dir == Directions.left) real_dir = -bot_obj.transform.right; | |
| if (dir == Directions.right) real_dir = bot_obj.transform.right; | |
| if (dir == Directions.forward) real_dir = bot_obj.transform.forward; | |
| if (dir == Directions.backward) real_dir = -bot_obj.transform.forward; | |
| val_to_return_bool = Physics.Raycast(bot_obj.transform.position, real_dir, 1f); | |
| if (frame_advance) pause = true; | |
| act_in_process = false; act = null; | |
| } | |
| void CreateShieldSub(Vector3 pos) | |
| { | |
| //GameObject shld = GameObject.CreatePrimitive(PrimitiveType.Cube); | |
| GameObject shld_outer = Instantiate(bot_shield); | |
| shld_outer.transform.position = pos; | |
| shld_outer.transform.localScale = new Vector3(0.8f, 0.8f, 0.8f); | |
| shld_outer.transform.GetChild(0).GetComponent<PSMeshRendererUpdater>().Color = new Color32(181, 80, 75, 255); | |
| GameObject shld_inner = Instantiate(bot_shield); | |
| shld_inner.transform.SetParent( shld_outer.transform ); | |
| shld_inner.transform.localPosition = Vector3.zero; | |
| shld_inner.transform.localRotation = Quaternion.Euler(0f, -90f, 0f); | |
| shld_inner.transform.localScale = new Vector3(0.875f, 0.875f, 0.875f); | |
| shld_inner.transform.GetChild(0).GetComponent<PSMeshRendererUpdater>().Color = new Color32(134, 232, 255, 255); | |
| var shld_cmp = shld_outer.AddComponent<BOT_Shield>(); | |
| val_to_return_object = shld_cmp; | |
| if (frame_advance) pause = true; | |
| act_in_process = false; act = null; | |
| } | |
| void ScaleSub (float value) | |
| { | |
| Vector3 bot_default_scale = new Vector3(3f, 3f, 3f); | |
| Camera.main.DOFieldOfView(30f * value, 3f); | |
| bot_obj.transform.DOScale( bot_default_scale * value, 1f ).SetEase(Ease.InBounce).OnComplete(()=>{ | |
| if (frame_advance) pause = true; | |
| act_in_process = false; act = null; | |
| }); | |
| } | |
| IEnumerator Pause(int n) | |
| { | |
| //Debug.Log("Start pause coroutine"); | |
| Control_UI.enable_frame(); | |
| //Highlight current instruction in script | |
| is_paused = true; | |
| int r1 = DebugInfo_Instructions[n].CommandCharStart; | |
| int r2 = DebugInfo_Instructions[n].CommandCharEnd; | |
| Text_Editor t = GameObject.Find("Text_Editor").GetComponent<Text_Editor>(); | |
| t.HighlightText(r1, r2); | |
| while (pause_command) { | |
| yield return null; | |
| } | |
| //Debug.Log("Start pause coroutine - unpause"); | |
| Control_UI.disable_frame(); | |
| //Reset highlight current instruction | |
| t.HighlightText(-1, -1); | |
| is_paused = false; | |
| if (frame_advance_command) pause_command = true; | |
| act_in_process = false; act = null; | |
| } | |
| public static void Set_Pause(Pause_States p) { | |
| switch (p) { | |
| case Pause_States.Reset: | |
| BOT.key_downs.Clear(); | |
| BOT.frame_advance = false; BOT.pause = false; | |
| BOT.frame_advance_command = false; BOT.pause_command = false; | |
| break; | |
| case Pause_States.Pause_Command: | |
| BOT.frame_advance = false; BOT.pause = false; | |
| BOT.frame_advance_command = false; BOT.pause_command = true; | |
| break; | |
| case Pause_States.Pause_Immediate: | |
| BOT.frame_advance = false; BOT.pause = true; | |
| BOT.frame_advance_command = false; BOT.pause_command = false; | |
| break; | |
| case Pause_States.Advance_Command: | |
| BOT.frame_advance_command = true; BOT.pause = false; | |
| if (is_paused) BOT.pause_command = false; else BOT.pause_command = true; | |
| break; | |
| } | |
| //Debug.Log("Set state: " + p.ToString() + ", variables: " + BOT.pause + "," + BOT.pause_command + "," + BOT.frame_advance + "," + BOT.frame_advance_command); | |
| } | |
| IEnumerator wait_and_die(float t) | |
| { | |
| yield return new WaitForSeconds(t); | |
| dying_in_progress = false; | |
| last_error = "BOT is dead. Long live the new BOT!"; | |
| } | |
| public static void Update() | |
| { | |
| //This is executed in MAIN thread | |
| if (HP <= 0) { | |
| if (!dead) { | |
| dead = true; | |
| dying_in_progress = true; | |
| bot_instance.StopAllCoroutines(); | |
| bot_instance.StartCoroutine("wait_and_die", 4f); | |
| } else | |
| return; | |
| } | |
| if (!act_in_process && act != null) | |
| { | |
| act_in_process = true; act.Invoke(); | |
| } | |
| if (pause && tw_talk != null && tw_talk.IsPlaying()) | |
| tw_talk.Pause(); | |
| if (!pause && tw_talk != null && !tw_talk.IsPlaying()) | |
| { | |
| tw_talk.Play(); | |
| if (frame_advance) pause = true; | |
| } | |
| } | |
| } | |
| public class BOT_Shield : MonoBehaviour, Engine.IDestructible { | |
| public Projectile captured = null; | |
| bool release_request = false; | |
| public delegate void test_deleg(); | |
| public event test_deleg test_event; | |
| System.Threading.Thread event_req_thread = null; | |
| Vector3 bounds_size; | |
| Vector3 target_dest = new Vector3(float.MinValue, float.MinValue, float.MinValue); | |
| TransformMy tm; | |
| //GameObject thread_safe_gameobject; | |
| void Start() { | |
| //thread_safe_gameobject = gameObject; | |
| tm = gameObject.transform2(); | |
| float radius = transform.GetChild(1).lossyScale.x; | |
| float bounds_offset = Mathf.Sin( Mathf.Deg2Rad * 45f ) * radius; | |
| bounds_size = new Vector3(bounds_offset, bounds_offset, bounds_offset); | |
| Engine.Level_Destructibles.Add(this); | |
| } | |
| void Update() { | |
| float radius = transform.lossyScale.y / 2; | |
| RaycastHit hit; | |
| Ray ray = new Ray(transform.position - new Vector3(0f, radius, 0f), transform.up); | |
| if (Physics.Raycast(ray, out hit, radius)) { | |
| Bounds my_bounds = new Bounds(transform.position, bounds_size); | |
| if (my_bounds.Contains(hit.collider.bounds.min) && my_bounds.Contains(hit.collider.bounds.max)) { | |
| //Debug.Log("Check inside shield INSIDE, found: " + hit.transform.name); | |
| var rb = hit.transform.GetComponent<Rigidbody>(); | |
| var pr = hit.transform.GetComponent<Projectile>(); | |
| if (rb != null && pr != null && captured == null) { | |
| if (rb.velocity.magnitude > 0.1f) { | |
| rb.velocity = rb.velocity / 4; | |
| } else { | |
| captured = pr; | |
| pr.captured = true; | |
| pr.speed = Vector3.zero; | |
| rb.isKinematic = true; | |
| hit.transform.SetParent(transform); | |
| hit.transform.DOLocalMove(Vector3.zero, 0.1f).OnComplete(()=> | |
| hit.transform.DOLocalMoveY(0.12f, 1f).SetLoops(-1, LoopType.Yoyo) | |
| ); | |
| } | |
| } | |
| if (rb == null && pr != null && captured == null) { | |
| captured = pr; | |
| pr.captured = true; | |
| pr.speed = Vector3.zero; | |
| hit.transform.SetParent(transform); | |
| hit.transform.DOLocalMove(Vector3.zero, 0.1f).OnComplete(()=> | |
| hit.transform.DOLocalMoveY(0.12f, 1f).SetLoops(-1, LoopType.Yoyo) | |
| ); | |
| } | |
| } | |
| } | |
| if (release_request) { | |
| if (captured != null) { | |
| captured.transform.SetParent(null, true); | |
| var rb = captured.GetComponent<Rigidbody>(); | |
| if (rb != null) { | |
| rb.DOKill(); | |
| } else { | |
| captured.transform.DOKill(); | |
| rb = captured.gameObject.AddComponent<Rigidbody>(); | |
| } | |
| var random_force = new Vector3(UnityEngine.Random.Range(-0.2f, 0.2f), 0f, UnityEngine.Random.Range(0.2f, 0.2f)); | |
| rb.AddForce(random_force, ForceMode.Impulse); | |
| } | |
| Engine.Level_Destructibles.Remove(this); | |
| Destroy(gameObject); | |
| } | |
| } | |
| public void MoveTo(float x, float y, float z) { | |
| while (tm == null) System.Threading.Thread.Sleep(10); | |
| tm.MoveTo(x, y, z); | |
| //target_dest = new Vector3(x, y, z); | |
| event_req_thread = BOT.script_thread; | |
| tm.on_move_dest_reached += () => { | |
| //Debug.Log("Event is working. Event thread id = " + System.Threading.Thread.CurrentThread.ManagedThreadId + ", BOT thread id = " + BOT.script_thread.ManagedThreadId); | |
| //Debug.Log("3"); | |
| BOT.events.Add( new Action(()=> { this.test_event(); }) ); | |
| //BOT.events.Add( new Action(()=> { Debug.Log("aaa"); }) ); | |
| //if (BOT.script_thread != null && BOT.script_thread == event_req_thread && test_event != null) test_event(); | |
| }; | |
| } | |
| public void Release(){ | |
| //This is called from user-script | |
| release_request = true; | |
| } | |
| public void Destroy(){ | |
| if (captured != null) { | |
| captured.transform.SetParent(null, true); | |
| captured.transform.DOKill(); | |
| var rb = captured.GetComponent<Rigidbody>(); | |
| if (rb != null) rb.DOKill(); | |
| } | |
| if (tm != null) tm.Reset_Event(); | |
| Destroy(gameObject); | |
| } | |
| // public TransformMy t{ | |
| // get { return thread_safe_gameobject.transform2(); } | |
| // } | |
| } | |
| namespace BOT_Helpers { | |
| public class Platform : MonoBehaviour { | |
| float platform_speed = 1f; | |
| public static bool wait = false; | |
| public static Vector3 target_pos = Vector3.zero; | |
| public static List<GameObject> spawn_gameobjects = new List<GameObject>(); | |
| public static List<ParticleSystem> spawn_particles = new List<ParticleSystem>(); | |
| public static Platform inst = null; | |
| void Start() { inst = this; } | |
| public static void MoveTo(int x, int y, int z) { | |
| BOT.act = new Action(()=> inst.StartCoroutine( inst.MoveTo_Coroutine(x,y,z) ) ); | |
| BOT.Thread_Wait(); | |
| } | |
| IEnumerator MoveTo_Coroutine(int x, int y, int z) { | |
| //BOT.bot_obj.GetComponent<Rigidbody>().isKinematic = true; | |
| //var cl1 = BOT.bot_obj.GetComponent<BoxCollider>(); cl1.enabled = false; | |
| //var cl2 = BOT.bot_obj.transform.GetChild(3).GetComponent<SphereCollider>(); cl2.enabled = false; | |
| //yield return new WaitForFixedUpdate(); | |
| RaycastHit hit; | |
| Ray ray = new Ray(BOT.bot_obj.transform.position, Vector3.down); | |
| if (!Physics.Raycast(ray, out hit, 1f)) { | |
| Debug.Log("Raycast - false. Pos-from: " + BOT.bot_obj.transform.position); | |
| //BOT.bot_obj.GetComponent<Rigidbody>().isKinematic = false; cl1.enabled = true; cl2.enabled = true; | |
| //Ray ray2 = new Ray(BOT.bot_obj.transform.position + (Vector3.down * 2f), Vector3.up); | |
| //bool test = Physics.Raycast(ray2, out hit, 3f); | |
| //Debug.Log("Raycast - from bottom = " + test); | |
| BOT.last_error = "Platform class can not be used if BOT is not standing on the platform"; yield break; | |
| } | |
| var pm = hit.transform.GetComponent<Platform_Mono>(); | |
| if (pm == null) { | |
| Debug.Log("Raycast - " + hit.transform.gameObject.name); | |
| //BOT.bot_obj.GetComponent<Rigidbody>().isKinematic = false; cl1.enabled = true; cl2.enabled = true; | |
| BOT.last_error = "Platform class can not be used if BOT is not standing on the platform"; yield break; | |
| } | |
| //cl1.enabled = true; cl2.enabled = true; | |
| if (x < pm.limit_X.x || x > pm.limit_X.y) { BOT.last_error = "Platform move range X is outside of the limits"; yield break; } | |
| if (y < pm.limit_Y.x || y > pm.limit_Y.y) { BOT.last_error = "Platform move range Y is outside of the limits"; yield break; } | |
| if (z < pm.limit_Z.x || z > pm.limit_Z.y) { BOT.last_error = "Platform move range Z is outside of the limits"; yield break; } | |
| var override_x = pm.override_X.Where(v=> v.x == x); if ( override_x.Count() > 0 ) x = override_x.ElementAt(0).y; | |
| var override_y = pm.override_Y.Where(v=> v.x == y); if ( override_y.Count() > 0 ) y = override_y.ElementAt(0).y; | |
| var override_z = pm.override_Z.Where(v=> v.x == z); if ( override_z.Count() > 0 ) z = override_z.ElementAt(0).y; | |
| target_pos = new Vector3(x,y,z); | |
| if (pm.OnMoveBegin != null) pm.OnMoveBegin.Invoke(); | |
| while (wait) yield return null; | |
| var pmt = pm.transform; | |
| if (pm.particles == null && pm.fx == null) { | |
| //No particle fx | |
| BOT.bot_obj.transform.SetParent(pmt, true); | |
| BOT.bot_obj.GetComponent<Rigidbody>().isKinematic = true; | |
| pmt.DOMoveX((float)x, platform_speed).SetSpeedBased(); | |
| while ( DOTween.IsTweening(pmt) ) { yield return null; } | |
| pmt.DOMoveY((float)y, platform_speed).SetSpeedBased(); | |
| while ( DOTween.IsTweening(pmt) ) { yield return null; } | |
| pmt.DOMoveZ((float)z, platform_speed).SetSpeedBased(); | |
| while ( DOTween.IsTweening(pmt) ) { yield return null; } | |
| Engine.spawner.transform.position = pmt.position + (Vector3.up * 0.6f); | |
| BOT.bot_obj.transform.SetParent(null, true); | |
| DontDestroyOnLoad(BOT.bot_obj); | |
| //BOT.bot_obj.GetComponent<Rigidbody>().isKinematic = false; | |
| } else { | |
| //Particle fx | |
| BOT.bot_obj.GetComponent<Rigidbody>().isKinematic = true; | |
| if (pm.anim_chain.Count() > 0) { | |
| List<GameObject> gameobjects_list = new List<GameObject>(); | |
| List<ParticleSystem> particles_list = new List<ParticleSystem>(); | |
| foreach (var anim in pm.anim_chain) { | |
| var param_pos = anim.param; | |
| if (anim.use_offset_of_bot_pos) param_pos += BOT.bot_obj.transform.position; | |
| switch (anim.animation) { | |
| case Platform_Mono.animation_info.spawn_particles : | |
| if (pm.particles != null) { | |
| var p_go = Instantiate(pm.particles.gameObject, param_pos, Quaternion.Euler(anim.rotation) ); | |
| p_go.SetActive(true); | |
| var p_ps = p_go.GetComponent<ParticleSystem>(); p_ps.Play(); | |
| spawn_particles.Add(p_ps); particles_list.Add(p_ps); | |
| } else { | |
| var go = Instantiate(pm.fx, param_pos, Quaternion.Euler(anim.rotation) ); | |
| go.SetActive(true); | |
| spawn_gameobjects.Add(go); gameobjects_list.Add(go); | |
| } | |
| break; | |
| case Platform_Mono.animation_info.translate_bot : | |
| break; | |
| case Platform_Mono.animation_info.scale_bot : | |
| if (anim.duration < 0.01f) | |
| BOT.bot_obj.transform.localScale = param_pos; | |
| else { | |
| BOT.bot_obj.transform.DOScale(param_pos, anim.duration).SetDelay(anim.delay); | |
| if (anim.wait) while ( DOTween.IsTweening(BOT.bot_obj.transform) ) { yield return null; } | |
| } | |
| break; | |
| case Platform_Mono.animation_info.rotate_bot : | |
| if (anim.duration < 0.01f) | |
| BOT.bot_obj.transform.rotation = Quaternion.Euler(anim.rotation); | |
| else { | |
| BOT.bot_obj.transform.DORotate(anim.rotation, anim.duration).SetDelay(anim.delay); | |
| if (anim.wait) while ( DOTween.IsTweening(BOT.bot_obj.transform) ) { yield return null; } | |
| } | |
| break; | |
| case Platform_Mono.animation_info.move_platform : | |
| pmt.transform.position = target_pos; | |
| BOT.bot_obj.transform.position = target_pos + anim.param; | |
| BOT.bot_obj.transform.rotation = Quaternion.Euler(anim.rotation); | |
| break; | |
| case Platform_Mono.animation_info.delay : | |
| if (anim.delay <= 0f) yield return null; | |
| else yield return new WaitForSeconds(anim.delay); | |
| break; | |
| } | |
| } | |
| foreach (var ps in particles_list) { spawn_particles.Remove(ps); Destroy(ps); } | |
| foreach (var go in gameobjects_list) { spawn_gameobjects.Remove(go); Destroy(go); } | |
| BOT.bot_obj.GetComponent<Rigidbody>().isKinematic = false; | |
| goto Finish; | |
| } | |
| //Spawn particles - disappear | |
| var particle_pos = BOT.bot_obj.transform.position + new Vector3(0f, 0.1f, 0f); // - new Vector3(0f, 0.6f, 0f); | |
| var particle_rot = Quaternion.Euler(-90f, 0f, 0f); | |
| var ps_new = Instantiate(pm.particles.gameObject, particle_pos, particle_rot ); | |
| ps_new.SetActive(true); | |
| var p = ps_new.GetComponent<ParticleSystem>(); spawn_particles.Add(p); | |
| //var m = p.main; m.simulationSpeed = 2f; | |
| p.Play(); | |
| //Scale bot - disappear | |
| BOT.bot_obj.transform.DOScale(new Vector3(3f, 0f, 3f), 0.5f).SetDelay(0.5f); | |
| while ( DOTween.IsTweening( BOT.bot_obj.transform ) ) { yield return null; } | |
| ////Scale bot - appear | |
| pmt.transform.position = target_pos; | |
| BOT.bot_obj.transform.position = new Vector3(x, y + 0.6f, z); | |
| BOT.bot_obj.transform.rotation = Quaternion.Euler(0f, 90f, 0f); | |
| //BOT.bot_obj.transform.DOScale(new Vector3(3f, 3f, 3f), 0.5f); | |
| BOT.bot_obj.transform.localScale = new Vector3(0f, 0f, 0f); | |
| BOT.bot_obj.transform.DOScale(new Vector3(3f, 0.01f, 3f), 0.5f).OnComplete(()=> { | |
| BOT.bot_obj.transform.DOScale(new Vector3(3f, 3f, 3f), 0.5f); | |
| }); | |
| ////Spawn particles - appear | |
| var particle_pos2 = BOT.bot_obj.transform.position + new Vector3(0f, 0.1f, 0f); // - new Vector3(0f, 0.6f, 0f); | |
| var ps_new2 = Instantiate(pm.particles.gameObject, particle_pos2, particle_rot ); | |
| ps_new2.SetActive(true); | |
| var p2 = ps_new2.GetComponent<ParticleSystem>(); spawn_particles.Add(p2); | |
| //var m2 = p2.main; m2.simulationSpeed = 2f; | |
| p2.Play(); | |
| //When scaling from 0, bot rotate to random direction | |
| yield return null; | |
| BOT.bot_obj.transform.rotation = Quaternion.Euler(0f, 90f, 0f); | |
| //while ( DOTween.IsTweening( BOT.bot_obj.transform ) ) { yield return null; } | |
| yield return new WaitForSeconds(1.5f); | |
| spawn_particles.Remove(p); spawn_particles.Remove(p2); | |
| Destroy(ps_new); Destroy(ps_new2); | |
| BOT.bot_obj.GetComponent<Rigidbody>().isKinematic = false; | |
| } | |
| Finish: | |
| if (pm.OnMoveEnd != null) pm.OnMoveEnd.Invoke(); | |
| while (wait) yield return null; | |
| if (BOT.frame_advance) BOT.pause = true; | |
| BOT.act_in_process = false; BOT.act = null; | |
| } | |
| } | |
| public class Console { | |
| public static void Log(string s) { | |
| BOT.act = new Action(()=> { | |
| Hud.Log(s); | |
| if (BOT.frame_advance) BOT.pause = true; | |
| BOT.act_in_process = false; BOT.act = null; | |
| }); | |
| BOT.Thread_Wait(); | |
| } | |
| } | |
| } | |
| public static class ExtensionMethods | |
| { | |
| // static Dictionary<GameObject, Vector3> moving = new Dictionary<GameObject, Vector3>(); | |
| // public static void Move(this Transform trans, Vector3 speed) | |
| // { | |
| // moving.Add(trans.gameObject, speed); | |
| // } | |
| // public static void Update() | |
| // { | |
| // foreach (KeyValuePair<GameObject, Vector3> kv in moving) { | |
| // //Debug.Log(kv.Key.name + " " +kv.Value.ToString()); | |
| // kv.Key.transform.Translate(kv.Value); | |
| // } | |
| // } | |
| public static TransformMy transform2(this GameObject g) { | |
| return new TransformMy(g); | |
| } | |
| public static void TextMeshProHighlight(TMPro.TMP_Text TMP, int first_char, int last_char, Color c) | |
| { | |
| //Debug.Log("Highlight r1 = " + first_char.ToString() + ", r2 = " + last_char.ToString()); | |
| TMPro.TMP_TextInfo ti = TMP.textInfo; | |
| if (last_char < 0) last_char = ti.characterCount - 1; | |
| for (int i = first_char; i <= last_char; i++){ | |
| if (!ti.characterInfo[i].isVisible) continue; | |
| int materialIndex = ti.characterInfo[i].materialReferenceIndex; | |
| var newVertexColors = ti.meshInfo[materialIndex].colors32; | |
| int vertexIndex = ti.characterInfo[i].vertexIndex; | |
| newVertexColors[vertexIndex + 0] = c; | |
| newVertexColors[vertexIndex + 1] = c; | |
| newVertexColors[vertexIndex + 2] = c; | |
| newVertexColors[vertexIndex + 3] = c; | |
| } | |
| // New function which pushes (all) updated vertex data to the appropriate meshes when using either the Mesh Renderer or CanvasRenderer. | |
| TMP.UpdateVertexData(TMPro.TMP_VertexDataUpdateFlags.Colors32); | |
| } | |
| public static GameObject[] ObjectsUnderPointer() { | |
| PointerEventData pointerData = new PointerEventData (EventSystem.current) { pointerId = -1, }; | |
| pointerData.position = Input.mousePosition; | |
| List<RaycastResult> results = new List<RaycastResult>(); | |
| EventSystem.current.RaycastAll(pointerData, results); | |
| return results.Select(rr=> rr.gameObject).ToArray(); | |
| } | |
| public static int IndexOfBalancedEnd (this string s, char open, char close, int start = 0) { | |
| int ind = s.IndexOf(open, start); | |
| if (ind < 0) return ind; | |
| int cur_level = 1; | |
| for (int i = ind + 1; i < s.Length; i++) { | |
| if (s[i] == open) { cur_level++; } | |
| if (s[i] == close) { cur_level--; } | |
| if (cur_level == 0) { ind = i; break; } | |
| } | |
| // var sw = System.IO.File.AppendText("D:/Unity 2018.1.0f2/Projects/Script-o-bot/IndexOfBalancedEnd.log"); | |
| // sw.WriteLine("cur level = " + cur_level.ToString() + ", ind = " + ind.ToString()); | |
| // sw.Close(); | |
| if (cur_level > 0) return -1; | |
| return ind; | |
| } | |
| } | |
| public class TransformMy | |
| { | |
| //Test: | |
| //Debug.Log(BOT.bot_obj.transform2().position.x.ToString()); | |
| //BOT.bot_obj.transform2().position = new Vector3(1f, 1f, 1f); | |
| public delegate void move_dest_reached_deleg(); | |
| public event move_dest_reached_deleg on_move_dest_reached; | |
| public GameObject obj = null; | |
| static List<TransformMy> inst = new List<TransformMy>(); | |
| static Dictionary<GameObject, Vector3> moving = new Dictionary<GameObject, Vector3>(); | |
| static bool in_pause_mode = false; | |
| List<Action> actions = new List<Action>(); | |
| static List<Tweener> tweeners = new List<Tweener>(); | |
| public TransformMy(GameObject g) { | |
| obj = g; inst.Add(this); | |
| } | |
| public Vector3 position { | |
| get { | |
| Vector3 v = Vector3.left; | |
| actions.Add ( new Action( ()=> v = obj.transform.position) ); | |
| while (actions.Count > 0) System.Threading.Thread.Sleep(10); | |
| return v; | |
| } | |
| set { | |
| actions.Add ( new Action( ()=> obj.transform.position = value) ); | |
| while (actions.Count > 0) System.Threading.Thread.Sleep(10); | |
| } | |
| } | |
| public void Move( Vector3 speed ) { | |
| moving.Add(obj, speed); | |
| } | |
| public Tweener MoveTo( float x, float y, float z ) { | |
| //Running in user script thread | |
| Vector3 dest = new Vector3(x, y, z); | |
| float distance = Vector3.Distance(position, dest); | |
| Tweener tw = null; | |
| actions.Add ( new Action( ()=> { | |
| tw = obj.transform.DOMove(dest, distance).SetEase(Ease.Linear).OnComplete(()=> { | |
| lock (tweeners) { tweeners.Remove(tw); } | |
| if (this.on_move_dest_reached != null) { this.on_move_dest_reached(); } | |
| }); | |
| tweeners.Add(tw); | |
| })); | |
| while (actions.Count > 0) System.Threading.Thread.Sleep(10); | |
| return tw; | |
| } | |
| public static void Update() { | |
| //Running in unity main thread | |
| lock (inst) { | |
| foreach (var i in inst.ToArray()) { | |
| lock (i.actions) { | |
| foreach (var a in i.actions) { a.Invoke(); } | |
| i.actions.Clear(); | |
| } | |
| } | |
| } | |
| //Move | |
| lock (moving) { | |
| foreach (KeyValuePair<GameObject, Vector3> kv in moving) { | |
| kv.Key.transform.Translate(kv.Value); | |
| } | |
| } | |
| //Handle pause | |
| if ((BOT.pause || BOT.is_paused) && !in_pause_mode) { | |
| in_pause_mode = true; | |
| lock (tweeners) { foreach (Tweener t in tweeners) t.Pause(); } | |
| } | |
| if (!(BOT.pause || BOT.is_paused) && in_pause_mode) { | |
| in_pause_mode = false; | |
| lock (tweeners) { foreach (Tweener t in tweeners) t.Play(); } | |
| } | |
| } | |
| public void Reset_Event() { | |
| obj.transform.DOKill(); | |
| this.on_move_dest_reached = null; | |
| } | |
| } |