public VMPrimitiveExitCode ExecuteSubRoutine(VMStackFrame frame, ushort opcode, VMSubRoutineOperand operand) { VMRoutine bhav = null; GameObject CodeOwner; if (opcode >= 8192) { // Semi-Global sub-routine call bhav = (VMRoutine)frame.ScopeResource.SemiGlobal.GetRoutine(opcode); } else if (opcode >= 4096) { // Private sub-routine call bhav = (VMRoutine)frame.ScopeResource.GetRoutine(opcode); } else { // Global sub-routine call //CodeOwner = frame.Global.Resource; bhav = (VMRoutine)frame.Global.Resource.GetRoutine(opcode); } CodeOwner = frame.CodeOwner; ExecuteSubRoutine(frame, bhav, CodeOwner, operand); #if IDE_COMPAT if (Stack.LastOrDefault().GetCurrentInstruction().Breakpoint || ThreadBreak == VMThreadBreakMode.StepIn) { Breakpoint(frame, "Stepped in."); ContinueExecution = false; } else #endif { ContinueExecution = true; } return(VMPrimitiveExitCode.CONTINUE); }
public ushort ResultCheckCounter = 0; //how many times the interaction result has been checked. used for timeout. public VMStackFrame ToStackFrame(VMEntity caller) { var frame = new VMStackFrame { Caller = caller, Callee = Callee, CodeOwner = CodeOwner, Routine = ActionRoutine, StackObject = StackObject, ActionTree = true }; if (Args == null) { frame.Args = new short[4]; //always 4? i got crashes when i used the value provided by the routine, when for that same routine edith displayed 4 in the properties... } else { frame.Args = Args; //WARNING - if you use this, the args array MUST have the same number of elements the routine is expecting! } return(frame); }
private void MoveToInstruction(VMStackFrame frame, byte instruction, bool continueExecution) { if (frame is VMRoutingFrame) { //TODO: Handle returning false into the pathfinder (indicates failure) return; } switch (instruction) { case 255: Pop(VMPrimitiveExitCode.RETURN_FALSE); break; case 254: Pop(VMPrimitiveExitCode.RETURN_TRUE); break; case 253: Pop(VMPrimitiveExitCode.ERROR); break; default: frame.InstructionPointer = instruction; if (frame.GetCurrentInstruction().Breakpoint || (ThreadBreak != VMThreadBreakMode.Active && ( ThreadBreak == VMThreadBreakMode.StepIn || (ThreadBreak == VMThreadBreakMode.StepOver && Stack.Count - 1 <= BreakFrame) || (ThreadBreak == VMThreadBreakMode.StepOut && Stack.Count <= BreakFrame) ))) { Breakpoint(frame); } break; } ContinueExecution = (ThreadBreak != VMThreadBreakMode.Pause) && continueExecution; }
public static object GetSuit(VMStackFrame context, VMSuitScope scope, ushort id) { STR suitTable = null; var avatar = (VMAvatar)context.Caller; switch (scope) { case VMSuitScope.Object: suitTable = context.CodeOwner.Resource.Get <STR>(304); break; case VMSuitScope.Global: suitTable = context.Global.Resource.Get <STR>(304); break; case VMSuitScope.Person: //get outfit from person if (context.VM.TS1) { return(GetPersonSuitTS1((VMAvatar)context.Caller, id)); } var type = (VMPersonSuits)id; bool male = (avatar.GetPersonData(VMPersonDataVariable.Gender) == 0); switch (type) { //todo: (tail etc), cockroach head case VMPersonSuits.DefaultDaywear: return(avatar.DefaultSuits.Daywear.ID); case VMPersonSuits.Naked: return((ulong)(male ? 0x24E0000000D : 0x10000000D)); case VMPersonSuits.DefaultSwimwear: return(avatar.DefaultSuits.Swimwear.ID); case VMPersonSuits.JobOutfit: if (context.VM.TS1) { return(null); } var job = avatar.GetPersonData(VMPersonDataVariable.OnlineJobID); if (job < 1 || job > 5) { return(null); } var level = Math.Max(0, Math.Min(3, (avatar.GetPersonData(VMPersonDataVariable.OnlineJobGrade) - 1) / 4)); return((ulong)(JobOutfits[male?0:1][job - 1][level])); case VMPersonSuits.DefaultSleepwear: return(avatar.DefaultSuits.Sleepwear.ID); case VMPersonSuits.SkeletonPlus: return((ulong)(0x5750000000D)); case VMPersonSuits.SkeletonMinus: return((ulong)(0x5740000000D)); case VMPersonSuits.TeleporterMishap: return((ulong)(male ? 0x2900000000D : 0x4A0000000D)); case VMPersonSuits.DynamicDaywear: return(avatar.DynamicSuits.Daywear); case VMPersonSuits.DynamicSleepwear: return(avatar.DynamicSuits.Sleepwear); case VMPersonSuits.DynamicSwimwear: return(avatar.DynamicSuits.Swimwear); case VMPersonSuits.DynamicCostume: return(avatar.DynamicSuits.Costume); case VMPersonSuits.DecorationHead: return(avatar.Decoration.Head); case VMPersonSuits.DecorationBack: return(avatar.Decoration.Back); case VMPersonSuits.DecorationShoes: return(avatar.Decoration.Shoes); case VMPersonSuits.DecorationTail: return(avatar.Decoration.Tail); } return(null); } if (suitTable != null) { var suitFile = suitTable.GetString(id) + ".apr"; return(suitFile); //var apr = FSO.Content.Content.Get().AvatarAppearances.Get(suitFile); //return apr; } return(null); }
public static string ParseDialogString(VMStackFrame context, string input, STR source, int depth) { if (depth > 10) { return(input); } int state = 0; StringBuilder command = new StringBuilder(); StringBuilder output = new StringBuilder(); if (input == null) { return("Missing String!!!"); } for (int i = 0; i < input.Length; i++) { if (state == 0) { if (input[i] == '$') { state = 1; //start parsing string command.Clear(); } else { output.Append(input[i]); } } else { command.Append(input[i]); if (i == input.Length - 1 || !CommandSubstrValid(command.ToString())) { if (i != input.Length - 1 || char.IsDigit(input[i])) { command.Remove(command.Length - 1, 1); i--; } var cmdString = command.ToString(); short[] values = new short[3]; if (cmdString.Length > 1 && cmdString[cmdString.Length - 1] == ':') { try { if (cmdString == "DynamicStringLocal:" || cmdString == "TimeLocal:" || cmdString == "JobOffer:" || cmdString == "Job:" || cmdString == "JobDesc:" || cmdString == "DateLocal:") { values[1] = -1; values[2] = -1; for (int j = 0; j < 3; j++) { char next = input[++i]; string num = ""; while (char.IsDigit(next)) { num += next; next = (++i == input.Length) ? '!': input[i]; } if (num == "") { values[j] = -1; if (j == 1) { values[2] = -1; } break; } values[j] = short.Parse(num); if (i == input.Length || next != ':') { break; } } } else { char next = input[++i]; string num = ""; while (char.IsDigit(next)) { num += next; next = (++i == input.Length) ? '!' : input[i]; } values[0] = short.Parse(num); } i--; } catch (FormatException) { } } try { switch (cmdString) { case "Object": case "DynamicObjectName": //hack: if stack object doesn't exist and should contain owner's id, //try output the callee's owner id instead for tip jar. //special id for this is -1. if (context.StackObjectID == -1 && !context.VM.TS1) { //StackObjectOwnerID call sets the id to -1 if no owner found. (null is usually 0) output.Append(context.VM.TSOState.Names.GetNameForID( context.VM, (context.Callee.TSOState as VMTSOObjectState)?.OwnerID ?? 0 )); } else { output.Append(context.StackObject.ToString()); } break; case "Me": output.Append(context.Caller.ToString()); break; case "TempXL:": output.Append(VMMemory.GetBigVariable(context, Scopes.VMVariableScope.TempXL, values[0]).ToString()); break; case "MoneyXL:": output.Append("$" + VMMemory.GetBigVariable(context, Scopes.VMVariableScope.TempXL, values[0]).ToString("##,#0")); break; case "Temp:": output.Append(VMMemory.GetBigVariable(context, Scopes.VMVariableScope.Temps, values[0]).ToString()); break; case "$": output.Append("$"); i--; break; case "Attribute:": output.Append(VMMemory.GetBigVariable(context, Scopes.VMVariableScope.MyObjectAttributes, values[0]).ToString()); break; case "DynamicStringLocal:": STR res = null; if (values[2] != -1 && values[1] != -1) { VMEntity obj = context.VM.GetObjectById((short)context.Locals[values[2]]); if (obj == null) { break; } ushort tableID = (ushort)context.Locals[values[1]]; { //local if (obj.SemiGlobal != null) { res = obj.SemiGlobal.Get <STR>(tableID); } if (res == null) { res = obj.Object.Resource.Get <STR>(tableID); } if (res == null) { res = context.Global.Resource.Get <STR>(tableID); } } } else if (values[1] != -1) { //global table ushort tableID = (ushort)context.Locals[values[1]]; res = context.Global.Resource.Get <STR>(tableID); } else { res = source; } ushort index = (ushort)context.Locals[values[0]]; if (res != null) { var str = res.GetString(index); output.Append(ParseDialogString(context, str, res, depth++)); // recursive command parsing! // this is needed for the crafting table. // though it is also, completely insane? } break; case "Local:": output.Append(VMMemory.GetBigVariable(context, Scopes.VMVariableScope.Local, values[0]).ToString()); break; case "FixedLocal:": output.Append((VMMemory.GetBigVariable(context, Scopes.VMVariableScope.Local, values[0]) / 100f).ToString("F2")); break; case "TimeLocal:": var hours = VMMemory.GetBigVariable(context, Scopes.VMVariableScope.Local, values[0]); var mins = (values[1] == -1)?0:VMMemory.GetBigVariable(context, Scopes.VMVariableScope.Local, values[1]); var suffix = (hours > 11) ? "pm" : "am"; if (hours > 12) { hours -= 12; } output.Append(hours.ToString()); output.Append(":"); output.Append(mins.ToString().PadLeft(2, '0')); output.Append(suffix); break; case "JobOffer:": output.Append(Content.Content.Get().Jobs.JobOffer( (short)VMMemory.GetBigVariable(context, Scopes.VMVariableScope.Local, values[0]), VMMemory.GetBigVariable(context, Scopes.VMVariableScope.Local, values[1]))); break; case "Job:": case "JobDesc:": var level = VMMemory.GetBigVariable(context, Scopes.VMVariableScope.Local, values[1]); var jobStr = Content.Content.Get().Jobs.JobStrings( (short)VMMemory.GetBigVariable(context, Scopes.VMVariableScope.Local, values[0])); if (jobStr != null) { output.Append(jobStr.GetString(level * 3 + ((cmdString == "JobDesc:")?3:4))); } break; case "Param:": output.Append(VMMemory.GetBigVariable(context, Scopes.VMVariableScope.Parameters, values[0]).ToString()); break; case "NameLocal:": output.Append(context.VM.GetObjectById(VMMemory.GetVariable(context, Scopes.VMVariableScope.Local, values[0])).ToString()); break; case "Neighbor": //neighbour in stack object id if (!context.VM.TS1) { break; } var guid = Content.Content.Get().Neighborhood.GetNeighborByID(context.StackObjectID)?.GUID ?? 0; var gobj = Content.Content.Get().WorldObjects.Get(guid); if (gobj == null) { output.Append("Unknown"); } else { output.Append(gobj.Resource.Get <FSO.Files.Formats.IFF.Chunks.CTSS>(gobj.OBJ.CatalogStringsID)?.GetString(0) ?? "Unknown"); } break; case "ListObject": output.Append(new string(context.StackObject.MyList.Select(x => (char)x).ToArray())); break; case "CatalogLocal:": var catObj = context.VM.GetObjectById(VMMemory.GetVariable(context, Scopes.VMVariableScope.Local, values[0])); var cat = catObj.Object.Resource.Get <CTSS>(catObj.Object.OBJ.CatalogStringsID)?.GetString(1); output.Append(cat ?? ""); break; case "DateLocal:": var date = new DateTime(context.Locals[values[2]], context.Locals[values[1]], context.Locals[values[0]]); output.Append(date.ToLongDateString()); break; case "\\n": output.Append("\n"); break; default: output.Append(cmdString); break; } } catch (Exception) { //something went wrong. just skip command } state = 0; } } } output.Replace("\r\n", "\r\n\r\n"); return(output.ToString()); }
public static string ParseDialogString(VMStackFrame context, string input, STR source) { return(ParseDialogString(context, input, source, 0)); }
public static VMPrimitiveExitCode EvaluateCheck(VMContext context, VMEntity entity, VMStackFrame initFrame, VMQueuedAction action, List <VMPieMenuInteraction> actionStrings) { var temp = new VMThread(context, entity, 5); var forceClone = !context.VM.Scheduler.RunningNow; //temps should only persist on check trees running within the vm tick to avoid desyncs. if (entity.Thread != null) { temp.TempRegisters = forceClone?(short[])entity.Thread.TempRegisters.Clone() : entity.Thread.TempRegisters; temp.TempXL = forceClone ? (int[])entity.Thread.TempXL.Clone() : entity.Thread.TempXL; } temp.IsCheck = true; temp.ActionStrings = actionStrings; //generate and place action strings in here temp.Push(initFrame); if (action != null) { temp.Queue.Add(action); //this check runs an action. We may need its interaction number, etc. } while (temp.Stack.Count > 0 && temp.DialogCooldown == 0) //keep going till we're done! idling is for losers! { temp.Tick(); temp.ThreadBreak = VMThreadBreakMode.Active; //cannot breakpoint in check trees } if (context.VM.Aborting) { return(VMPrimitiveExitCode.ERROR); } return((temp.DialogCooldown > 0) ? VMPrimitiveExitCode.RETURN_FALSE : temp.LastStackExitCode); }
public static VMPrimitiveExitCode EvaluateCheck(VMContext context, VMEntity entity, VMStackFrame initFrame, VMQueuedAction action) { return(EvaluateCheck(context, entity, initFrame, action, null)); }
private void HandleResult(VMStackFrame frame, VMInstruction instruction, VMPrimitiveExitCode result) { switch (result) { // Don't advance the instruction pointer, this primitive isnt finished yet case VMPrimitiveExitCode.CONTINUE_NEXT_TICK: ScheduleIdleStart = Context.VM.Scheduler.CurrentTickID; Context.VM.Scheduler.ScheduleTickIn(Entity, 1); ContinueExecution = false; break; case VMPrimitiveExitCode.CONTINUE_FUTURE_TICK: ContinueExecution = false; break; case VMPrimitiveExitCode.ERROR: ContinueExecution = false; Pop(result); break; case VMPrimitiveExitCode.RETURN_TRUE: case VMPrimitiveExitCode.RETURN_FALSE: /** pop stack and return false **/ Pop(result); break; case VMPrimitiveExitCode.GOTO_TRUE: MoveToInstruction(frame, instruction.TruePointer, true); break; case VMPrimitiveExitCode.GOTO_FALSE: MoveToInstruction(frame, instruction.FalsePointer, true); break; case VMPrimitiveExitCode.GOTO_TRUE_NEXT_TICK: MoveToInstruction(frame, instruction.TruePointer, false); ScheduleIdleStart = Context.VM.Scheduler.CurrentTickID; Context.VM.Scheduler.ScheduleTickIn(Entity, 1); ContinueExecution = false; break; case VMPrimitiveExitCode.GOTO_FALSE_NEXT_TICK: MoveToInstruction(frame, instruction.FalsePointer, false); ScheduleIdleStart = Context.VM.Scheduler.CurrentTickID; Context.VM.Scheduler.ScheduleTickIn(Entity, 1); ContinueExecution = false; break; case VMPrimitiveExitCode.CONTINUE: ContinueExecution = true; break; case VMPrimitiveExitCode.INTERRUPT: Stack.Clear(); QueueDirty = true; if (Queue.Count > 0) { Queue.RemoveAt(0); } LastStackExitCode = result; break; } }
public bool RunInMyStack(BHAV bhav, GameObject CodeOwner, short[] passVars, VMEntity stackObj) { //a little bit hacky. We may not need to do as serious a context switch as this. var OldStack = Stack; var OldQueue = Queue; var OldCheck = IsCheck; var OldQueueBlock = ActiveQueueBlock; VMStackFrame prevFrame = new VMStackFrame() { Caller = Entity, Callee = Entity }; if (Stack.Count > 0) { prevFrame = Stack[Stack.Count - 1]; Stack = new List <VMStackFrame>() { prevFrame }; } else { Stack = new List <VMStackFrame>(); } Queue = new List <VMQueuedAction>(); if (Queue.Count > 0) { Queue.Add(Queue[0]); } IsCheck = true; ExecuteSubRoutine(prevFrame, bhav, CodeOwner, new VMSubRoutineOperand(passVars)); Stack.RemoveAt(0); if (Stack.Count == 0) { Stack = OldStack; Queue = OldQueue; return(false); //bhav was invalid/empty } var frame = Stack[Stack.Count - 1]; frame.StackObject = stackObj; try { while (Stack.Count > 0) { NextInstruction(); } } catch (Exception e) { if (e is ThreadAbortException) { throw e; } //we need to catch these so that the parent can be restored. } //copy child stack things to parent stack Stack = OldStack; Queue = OldQueue; IsCheck = OldCheck; ActiveQueueBlock = OldQueueBlock; return((LastStackExitCode == VMPrimitiveExitCode.RETURN_TRUE) ? true : false); }
public static VMPrimitiveExitCode EvaluateCheck(VMContext context, VMEntity entity, VMStackFrame initFrame, VMQueuedAction action, List <VMPieMenuInteraction> actionStrings) { var temp = new VMThread(context, entity, 5); if (entity.Thread != null) { temp.TempRegisters = entity.Thread.TempRegisters; temp.TempXL = entity.Thread.TempXL; } temp.IsCheck = true; temp.ActionStrings = actionStrings; //generate and place action strings in here temp.Push(initFrame); if (action != null) { temp.Queue.Add(action); //this check runs an action. We may need its interaction number, etc. } while (temp.Stack.Count > 0 && temp.DialogCooldown == 0) //keep going till we're done! idling is for losers! { temp.Tick(); temp.ThreadBreak = VMThreadBreakMode.Active; //cannot breakpoint in check trees } return((temp.DialogCooldown > 0) ? VMPrimitiveExitCode.ERROR:temp.LastStackExitCode); }
private void ExecuteInstruction(VMStackFrame frame) { var instruction = frame.GetCurrentInstruction(); var opcode = instruction.Opcode; if (opcode >= 256) { BHAV bhav = null; GameObject CodeOwner; if (opcode >= 8192) { // Semi-Global sub-routine call bhav = frame.ScopeResource.SemiGlobal.Get <BHAV>(opcode); } else if (opcode >= 4096) { // Private sub-routine call bhav = frame.ScopeResource.Get <BHAV>(opcode); } else { // Global sub-routine call //CodeOwner = frame.Global.Resource; bhav = frame.Global.Resource.Get <BHAV>(opcode); } CodeOwner = frame.CodeOwner; var operand = (VMSubRoutineOperand)instruction.Operand; ExecuteSubRoutine(frame, bhav, CodeOwner, operand); #if IDE_COMPAT if (Stack.LastOrDefault().GetCurrentInstruction().Breakpoint || ThreadBreak == VMThreadBreakMode.StepIn) { Breakpoint(frame); ContinueExecution = false; } else #endif { ContinueExecution = true; } return; } var primitive = Context.Primitives[opcode]; if (primitive == null) { HandleResult(frame, instruction, VMPrimitiveExitCode.GOTO_TRUE); return; } VMPrimitiveHandler handler = primitive.GetHandler(); var result = handler.Execute(frame, instruction.Operand); if (result != null) { HandleResult(frame, instruction, result); } }
public static string ParseDialogString(VMStackFrame context, string input, STR source) { int state = 0; StringBuilder command = new StringBuilder(); StringBuilder output = new StringBuilder(); if (input == null) { return("Missing String!!!"); } for (int i = 0; i < input.Length; i++) { if (state == 0) { if (input[i] == '$') { state = 1; //start parsing string command.Clear(); } else { output.Append(input[i]); } } else { command.Append(input[i]); if (i == input.Length - 1 || !CommandSubstrValid(command.ToString())) { if (i != input.Length - 1 || char.IsDigit(input[i])) { command.Remove(command.Length - 1, 1); i--; } var cmdString = command.ToString(); short[] values = new short[3]; if (cmdString.Length > 1 && cmdString[cmdString.Length - 1] == ':') { try { if (cmdString == "DynamicStringLocal:") { values[1] = -1; values[2] = -1; for (int j = 0; j < 3; j++) { char next = input[++i]; string num = ""; while (char.IsDigit(next)) { num += next; next = (++i == input.Length) ? '!': input[i]; } if (num == "") { values[j] = -1; if (j == 1) { values[2] = -1; } break; } values[j] = short.Parse(num); if (i == input.Length || next != ':') { break; } } } else { char next = input[++i]; string num = ""; while (char.IsDigit(next)) { num += next; next = (++i == input.Length) ? '!' : input[i]; } values[0] = short.Parse(num); } i--; } catch (FormatException) { } } try { switch (cmdString) { case "Object": case "DynamicObjectName": output.Append(context.StackObject.ToString()); break; case "Me": output.Append(context.Caller.ToString()); break; case "TempXL:": output.Append(VMMemory.GetBigVariable(context, Scopes.VMVariableScope.TempXL, values[0]).ToString()); break; case "MoneyXL:": output.Append("$" + VMMemory.GetBigVariable(context, Scopes.VMVariableScope.TempXL, values[0]).ToString("##,#0")); break; case "Temp:": output.Append(VMMemory.GetBigVariable(context, Scopes.VMVariableScope.Temps, values[0]).ToString()); break; case "$": output.Append("$"); i--; break; case "Attribute:": output.Append(VMMemory.GetBigVariable(context, Scopes.VMVariableScope.MyObjectAttributes, values[0]).ToString()); break; case "DynamicStringLocal:": STR res = null; if (values[2] != -1 && values[1] != -1) { VMEntity obj = context.VM.GetObjectById((short)context.Locals[values[2]]); if (obj == null) { break; } ushort tableID = (ushort)context.Locals[values[1]]; { //local if (obj.SemiGlobal != null) { res = obj.SemiGlobal.Get <STR>(tableID); } if (res == null) { res = obj.Object.Resource.Get <STR>(tableID); } if (res == null) { res = context.Global.Resource.Get <STR>(tableID); } } } else if (values[1] != -1) { //global table ushort tableID = (ushort)context.Locals[values[1]]; res = context.Global.Resource.Get <STR>(tableID); } else { res = source; } ushort index = (ushort)context.Locals[values[0]]; if (res != null) { var str = res.GetString(index); output.Append(ParseDialogString(context, str, res)); // recursive command parsing! // this is needed for the crafting table. // though it is also, completely insane? } break; case "Local:": output.Append(VMMemory.GetBigVariable(context, Scopes.VMVariableScope.Local, values[0]).ToString()); break; case "Param:": output.Append(VMMemory.GetBigVariable(context, Scopes.VMVariableScope.Parameters, values[0]).ToString()); break; case "NameLocal:": output.Append("(NameLocal)"); break; default: output.Append(cmdString); break; } } catch (Exception) { //something went wrong. just skip command } state = 0; } } } output.Replace("\r\n", "\r\n\r\n"); return(output.ToString()); }
public VMSimanticsException(string message, VMStackFrame context) : base(message) { this.context = context; this.message = message; }
public abstract VMPrimitiveExitCode Execute(VMStackFrame context, VMPrimitiveOperand operand);