private void DoExecute() // MAIN thread only.. { executing = true; System.Diagnostics.Stopwatch timetaken = new System.Diagnostics.Stopwatch(); timetaken.Start(); while (true) { if (progcurrent != null) { if (progcurrent.GetErrorList != null) // any errors pending, handle { actioncontroller.LogLine("Error at " + progcurrent.Location + ": Line " + progcurrent.GetLastStep().LineNumber + ": " + progcurrent.GetLastStep().Name + Environment.NewLine + progcurrent.GetErrorList); TerminateCurrent(); } else if (progcurrent.IsProgramFinished) // if current program ran out, cancel it { // this catches a LOOP without a statement at the end.. or a DO without a WHILE at the end.. if (progcurrent.ExecLevel > 0 && progcurrent.LevelUp(progcurrent.ExecLevel, null)) // see if we have any pending LOOP (or a DO without a while) and continue.. { continue; // errors or movement causes it to go back.. errors will be picked up above } TerminateCurrent(); } } while (progcurrent == null && progqueue.Count > 0) // if no program,but something in queue { progcurrent = progqueue[0]; progqueue.RemoveAt(0); if (progcurrent.variables != null) // if not null, its because its just been restarted after a call.. reset globals { progcurrent.Add(actioncontroller.Globals); // in case they have been updated... } else { progcurrent.PrepareToRun(new ConditionVariables(progcurrent.inputvariables, actioncontroller.Globals), new ConditionFileHandles(), new Dictionary <string, Forms.ConfigurableForm>(), true); // with new file handles and close at end.. } if (progcurrent.IsProgramFinished) // reject empty programs.. { TerminateCurrent(); continue; // and try again } } if (progcurrent == null) // Still nothing, game over { break; } Action ac = progcurrent.GetNextStep(); // get the step. move PC on. if (ac.LevelUp > 0 && progcurrent.LevelUp(ac.LevelUp, ac)) // level up.. { System.Diagnostics.Debug.WriteLine((Environment.TickCount % 10000).ToString("00000") + " Abort Lv" + progcurrent.ExecLevel + " e " + (progcurrent.IsExecuteOn ? "1" : "0") + " up " + ac.LevelUp + ": " + progcurrent.StepNumber + " " + ac.Name + " " + ac.DisplayedUserData); continue; } System.Diagnostics.Debug.WriteLine((Environment.TickCount % 10000).ToString("00000") + " Exec Lv" + progcurrent.ExecLevel + " e " + (progcurrent.IsExecuteOn ? "1" : "0") + " up " + ac.LevelUp + ": " + progcurrent.StepNumber + " " + ac.Name + " " + ac.DisplayedUserData); if (progcurrent.DoExecute(ac)) // execute is on.. { if (ac.Type == Action.ActionType.Call) // Call needs to pass info back up thru to us, need a different call { ActionCall acall = ac as ActionCall; string prog; ConditionVariables paravars; if (acall.ExecuteCallAction(progcurrent, out prog, out paravars)) // if execute ok { //System.Diagnostics.Debug.WriteLine("Call " + prog + " with " + paravars.ToString()); Tuple <ActionFile, ActionProgram> ap = actionfilelist.FindProgram(prog, progcurrent.actionfile); // find program using this name, prefer this action file first if (ap != null) { Run(true, ap.Item1, ap.Item2, paravars, progcurrent.functions.handles, progcurrent.dialogs, false); // run now with these para vars } else { progcurrent.ReportError("Call cannot find " + prog); } } } else if (ac.Type == Action.ActionType.Return) // Return needs to pass info back up thru to us, need a different call { ActionReturn ar = ac as ActionReturn; string retstr; if (ar.ExecuteActionReturn(progcurrent, out retstr)) { TerminateCurrent(); if (progqueue.Count > 0) // pass return value if program is there.. { progqueue[0]["ReturnValue"] = retstr; } continue; // back to top, next action from returned function. } } else if (!ac.ExecuteAction(progcurrent)) // if execute says, stop, i'm waiting for something { return; // exit, with executing set true. ResumeAfterPause will restart it. } } if (async && timetaken.ElapsedMilliseconds > 100) // no more than 100ms per go to stop the main thread being blocked { System.Diagnostics.Debug.WriteLine((Environment.TickCount % 10000).ToString("00000") + " *** SUSPEND"); restarttick.Start(); break; } } executing = false; }