private bool ExecuteAction(VMQueuedAction action) { var frame = action.ToStackFrame(Entity); frame.DiscardResult = true; return(Push(frame)); }
private void ExecuteAction(VMQueuedAction action) { var frame = action.ToStackFrame(Entity); frame.DiscardResult = true; Push(frame); }
public static VMPrimitiveExitCode EvaluateCheck(VMContext context, VMEntity entity, VMQueuedAction action) { var temp = new VMThread(context, entity, 5); temp.IsCheck = true; temp.EnqueueAction(action); while (temp.Queue.Count > 0 && temp.DialogCooldown == 0) //keep going till we're done! idling is for losers! { temp.Tick(); } return (temp.DialogCooldown > 0) ? VMPrimitiveExitCode.ERROR:temp.LastStackExitCode; }
/// <summary> /// Add an item to the action queue /// </summary> /// <param name="invocation"></param> public void EnqueueAction(VMQueuedAction invocation) { invocation.UID = ActionUID++; QueueDirty = true; if (!IsCheck && (invocation.Flags & TTABFlags.RunImmediately) > 0) { // shove this action in the queue to try run it next tick. // interaction can be run normally if we actually hit it using allow push. (unlikely) // otherwise next tick will detect the "run immediately" interaction's prescence. // and it will be pushed to the stack immediately. // TODO: check if any interactions of this kind clobber the temps. // this doesnt ""run immediately"", but is good enough. invocation.Mode = VMQueueMode.Idle; //hide invocation.Priority = short.MinValue; this.Queue.Add(invocation); return; } if (Queue.Count == 0) //if empty, just queue right at the front { this.Queue.Add(invocation); } else if ((invocation.Flags & TTABFlags.Leapfrog) > 0) { //place right after active interaction, ignoring all priorities. this.Queue.Insert(ActiveQueueBlock + 1, invocation); } else //we've got an even harder job! find a place for this interaction based on its priority { bool hitParentEnd = (invocation.Mode != VMQueueMode.ParentIdle); for (int i = Queue.Count - 1; i > ActiveQueueBlock; i--) { if (hitParentEnd && (invocation.Priority <= Queue[i].Priority || Queue[i].Mode == VMQueueMode.ParentExit)) //skip until we find a parent exit or something with the same or higher priority. { this.Queue.Insert(i + 1, invocation); EvaluateQueuePriorities(); return; } if (Queue[i].Mode == VMQueueMode.ParentExit) { hitParentEnd = true; } } this.Queue.Insert(ActiveQueueBlock + 1, invocation); //this is more important than all other queued items that are not running, so stick this to run next. } EvaluateQueuePriorities(); }
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 ExecuteAction(VMQueuedAction action) { var frame = new VMStackFrame { Caller = Entity, Callee = action.Callee, CodeOwner = action.CodeOwner, Routine = action.Routine, StackObject = action.StackObject }; if (action.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 = action.Args; //WARNING - if you use this, the args array MUST have the same number of elements the routine is expecting! } Push(frame); }
/// <summary> /// Add an item to the action queue /// </summary> /// <param name="invocation"></param> public void EnqueueAction(VMQueuedAction invocation) { invocation.UID = ActionUID++; if (Queue.Count == 0) //if empty, just queue right at the front (or end, if you're like that!) { this.Queue.Add(invocation); } else //we've got an even harder job! find a place for this interaction based on its priority { for (int i = Queue.Count - 1; i > 0; i--) { if (invocation.Priority >= Queue[i].Priority) //if the next queue element we need to skip over is of the same or a higher priority we'll stay right here, otherwise skip over it! { this.Queue.Insert(i+1, invocation); return; } } this.Queue.Insert(1, invocation); //this is more important than all other queued items that are not running, so stick this to run next. } EvaluateQueuePriorities(); }
/// <summary> /// Add an item to the action queue /// </summary> /// <param name="invocation"></param> public void EnqueueAction(VMQueuedAction invocation) { if (!IsCheck && (invocation.Flags & TTABFlags.RunImmediately) > 0) { EvaluateCheck(Context, Entity, invocation); return; } invocation.UID = ActionUID++; if (Queue.Count == 0) //if empty, just queue right at the front { this.Queue.Add(invocation); } else if ((invocation.Flags & TTABFlags.Leapfrog) > 0) { //place right after active interaction, ignoring all priorities. this.Queue.Insert(1, invocation); } else //we've got an even harder job! find a place for this interaction based on its priority { bool hitParentEnd = (invocation.Mode != VMQueueMode.ParentIdle); for (int i = Queue.Count - 1; i > 0; i--) { if (hitParentEnd && (invocation.Priority <= Queue[i].Priority || Queue[i].Mode == VMQueueMode.ParentExit)) //skip until we find a parent exit or something with the same or higher priority. { this.Queue.Insert(i + 1, invocation); EvaluateQueuePriorities(); return; } if (Queue[i].Mode == VMQueueMode.ParentExit) { hitParentEnd = true; } } this.Queue.Insert(1, invocation); //this is more important than all other queued items that are not running, so stick this to run next. } EvaluateQueuePriorities(); }
private void ExecuteAction(VMQueuedAction action) { var frame = action.ToStackFrame(Entity); Push(frame); }
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 ExecuteAction(VMQueuedAction action) { var frame = new VMStackFrame { Caller = Entity, Callee = action.Callee, CodeOwner = action.CodeOwner, Routine = action.Routine, StackObject = action.StackObject }; if (action.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 = action.Args; //WARNING - if you use this, the args array MUST have the same number of elements the routine is expecting! Push(frame); }
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); }
public List <VMPieMenuInteraction> CheckTS1Action(VMQueuedAction action) { var result = new List <VMPieMenuInteraction>(); if (Entity is VMAvatar) //just let everyone use the CSR interactions { var avatar = (VMAvatar)Entity; if ((action.Flags & (TTABFlags.TS1AllowCats | TTABFlags.TS1AllowDogs)) > 0) { //interaction can only be performed by cats or dogs //if (!avatar.IsPet) return null; //check we're the correct type if (avatar.IsCat && (action.Flags & TTABFlags.TS1AllowCats) == 0) { return(null); } if (avatar.IsDog && (action.Flags & TTABFlags.TS1AllowDogs) == 0) { return(null); } } else if (avatar.IsPet) { return(null); //not allowed } var isVisitor = avatar.GetPersonData(VMPersonDataVariable.PersonType) == 1 && avatar.GetPersonData(VMPersonDataVariable.TS1FamilyNumber) != Context.VM.CurrentFamily?.ChunkID; //avatar.ObjectID != Context.VM.GetGlobalValue(3); TTABFlags ts1State = ((isVisitor) ? TTABFlags.AllowVisitors : 0) | ((avatar.GetPersonData(VMPersonDataVariable.PersonsAge) < 18) ? TTABFlags.TS1NoChild : 0) | ((avatar.GetPersonData(VMPersonDataVariable.PersonsAge) >= 18 && !avatar.IsPet) ? TTABFlags.TS1NoAdult : 0); //DEBUG: enable debug interction for all CSRs. if ((action.Flags & TTABFlags.Debug) > 0) { if (!isVisitor) { return(result); //do not bother running check } else { return(null); //disable debug for everyone else. } } //NEGATIVE EFFECTS: var pos = ts1State & (TTABFlags.TS1NoChild | TTABFlags.TS1NoAdult); var ts1Compare = action.Flags; if ((pos & ts1Compare) > 0) { return(null); } var negMask = (TTABFlags.AllowVisitors); var negatedFlags = (~ts1Compare) & negMask; if ((negatedFlags & ts1State) > 0) { return(null); //we are disallowed } } if (action.CheckRoutine != null && EvaluateCheck(Context, Entity, new VMStackFrame() { Caller = Entity, Callee = action.Callee, CodeOwner = action.CodeOwner, StackObject = action.StackObject, Routine = action.CheckRoutine, Args = new short[4] }, null, result) != VMPrimitiveExitCode.RETURN_TRUE) { return(null); } return(result); }
public static VMPrimitiveExitCode EvaluateCheck(VMContext context, VMEntity entity, VMStackFrame initFrame, VMQueuedAction action) { return EvaluateCheck(context, entity, initFrame, action, null); }
public List<VMPieMenuInteraction> CheckAction(VMQueuedAction action) { // 1. check action flags for permissions (if we are avatar) // 2. run check tree // rules: // Dogs/Cats means people CANNOT use these interactions. (DogsFlag|CatsFlag & IsDog|IsCat) // When Allow Object Owner is OFF it disallows the object owner, otherwise no effect // Visitors, Roommates, Ghosts have this same negative effect. // Friends apprars to override Owner, Visitors, Roommates // Allow CSRs:positive effect. if (action == null) return null; var result = new List<VMPieMenuInteraction>(); if (((action.Flags & TTABFlags.MustRun) == 0) && Entity is VMAvatar && ((action.Flags2 & TSOFlags.AllowCSRs) == 0)) //just let everyone use the CSR interactions { var avatar = (VMAvatar)Entity; if (avatar.GetSlot(0) != null && (action.Flags | TTABFlags.TSOAvailableCarrying) == 0) return null; if ((action.Flags & (TTABFlags.AllowCats | TTABFlags.AllowDogs)) > 0) { //interaction can only be performed by cats or dogs if (!avatar.IsPet) return null; //check we're the correct type if (avatar.IsCat && (action.Flags & TTABFlags.AllowCats) == 0) return null; if (avatar.IsDog && (action.Flags & TTABFlags.AllowDogs) == 0) return null; } else if (avatar.IsPet) return null; //not allowed if ((action.Flags & TTABFlags.TSOIsRepair) > 0) return null; TSOFlags tsoState = ((!(action.Callee is VMGameObject) || avatar.PersistID == ((VMTSOObjectState)action.Callee.TSOState).OwnerID) ? TSOFlags.AllowObjectOwner : 0) | ((((VMTSOAvatarState)avatar.TSOState).Permissions == VMTSOAvatarPermissions.Visitor) ? TSOFlags.AllowVisitors : 0) | ((((VMTSOAvatarState)avatar.TSOState).Permissions >= VMTSOAvatarPermissions.Roommate) ? TSOFlags.AllowRoommates : 0) | ((((VMTSOAvatarState)avatar.TSOState).Permissions == VMTSOAvatarPermissions.Admin) ? TSOFlags.AllowCSRs : 0) | ((avatar.GetPersonData(VMPersonDataVariable.IsGhost) > 0) ? TSOFlags.AllowGhost : 0) | TSOFlags.AllowFriends; TSOFlags tsoCompare = action.Flags2; //if flags are empty apart from "Non-Empty", force everything but visitor. (a kind of default state) if (tsoCompare == TSOFlags.NonEmpty) tsoCompare |= TSOFlags.AllowFriends | TSOFlags.AllowRoommates | TSOFlags.AllowObjectOwner; //DEBUG: enable debug interction for all roommates. change to only CSRs for production! if ((action.Flags & TTABFlags.Debug) > 0) { if ((tsoState & TSOFlags.AllowRoommates) > 0) return result; //do not bother running check else return null; //disable debug for everyone else. } if ((action.Flags & TTABFlags.TSOAvailableWhenDead) > 0) tsoCompare |= TSOFlags.AllowGhost; if ((action.Flags & TTABFlags.AllowVisitors) > 0) tsoCompare |= TSOFlags.AllowVisitors; //wrong??????? var posMask = (TSOFlags.AllowObjectOwner); if (((tsoState & posMask) & (tsoCompare & posMask)) == 0) { //NEGATIVE EFFECTS: var negMask = (TSOFlags.AllowVisitors | TSOFlags.AllowRoommates | TSOFlags.AllowGhost); var negatedFlags = (~tsoCompare) & negMask; if ((negatedFlags & tsoState) > 0) return null; //we are disallowed //if ((tsoCompare & TSOFlags.AllowCSRs) > 0) return null; // && (tsoState & TSOFlags.AllowCSRs) == 0 } } if (((action.Flags & TTABFlags.MustRun) == 0 || ((action.Flags & TTABFlags.TSORunCheckAlways) > 0)) && action.CheckRoutine != null && EvaluateCheck(Context, Entity, new VMStackFrame() { Caller = Entity, Callee = action.Callee, CodeOwner = action.CodeOwner, StackObject = action.StackObject, Routine = action.CheckRoutine, Args = new short[4] }, null, result) != VMPrimitiveExitCode.RETURN_TRUE) return null; return result; }
/// <summary> /// Add an item to the action queue /// </summary> /// <param name="invocation"></param> public void EnqueueAction(VMQueuedAction invocation) { invocation.UID = ActionUID++; QueueDirty = true; if (!IsCheck && (invocation.Flags & TTABFlags.RunImmediately) > 0) { // shove this action in the queue to try run it next tick. // interaction can be run normally if we actually hit it using allow push. (unlikely) // otherwise next tick will detect the "run immediately" interaction's prescence. // and it will be pushed to the stack immediately. // TODO: check if any interactions of this kind clobber the temps. // this doesnt ""run immediately"", but is good enough. invocation.Mode = VMQueueMode.Idle; //hide invocation.Priority = short.MinValue; this.Queue.Add(invocation); return; } if (Queue.Count == 0) //if empty, just queue right at the front this.Queue.Add(invocation); else if ((invocation.Flags & TTABFlags.Leapfrog) > 0) //place right after active interaction, ignoring all priorities. this.Queue.Insert(ActiveQueueBlock+1, invocation); else //we've got an even harder job! find a place for this interaction based on its priority { bool hitParentEnd = (invocation.Mode != VMQueueMode.ParentIdle); for (int i = Queue.Count - 1; i > ActiveQueueBlock; i--) { if (hitParentEnd && (invocation.Priority <= Queue[i].Priority || Queue[i].Mode == VMQueueMode.ParentExit)) //skip until we find a parent exit or something with the same or higher priority. { this.Queue.Insert(i+1, invocation); EvaluateQueuePriorities(); return; } if (Queue[i].Mode == VMQueueMode.ParentExit) hitParentEnd = true; } this.Queue.Insert(ActiveQueueBlock+1, invocation); //this is more important than all other queued items that are not running, so stick this to run next. } EvaluateQueuePriorities(); }
public List <VMPieMenuInteraction> CheckAction(VMQueuedAction action) { // 1. check action flags for permissions (if we are avatar) // 2. run check tree // rules: // Dogs/Cats means people CANNOT use these interactions. (DogsFlag|CatsFlag & IsDog|IsCat) // When Allow Object Owner is OFF it disallows the object owner, otherwise no effect // Visitors, Roommates, Ghosts have this same negative effect. // Friends apprars to override Owner, Visitors, Roommates // Allow CSRs:positive effect. if (action == null) { return(null); } if (Context.VM.TS1) { return(CheckTS1Action(action)); } var result = new List <VMPieMenuInteraction>(); if (((action.Flags & TTABFlags.MustRun) == 0) && Entity is VMAvatar) //just let everyone use the CSR interactions { var avatar = (VMAvatar)Entity; if (avatar.GetSlot(0) != null && (action.Flags & TTABFlags.TSOAvailableCarrying) == 0) { return(null); } if ((action.Flags & (TTABFlags.AllowCats | TTABFlags.AllowDogs)) > 0) { //interaction can only be performed by cats or dogs if (!avatar.IsPet) { return(null); } //check we're the correct type if (avatar.IsCat && (action.Flags & TTABFlags.AllowCats) == 0) { return(null); } if (avatar.IsDog && (action.Flags & TTABFlags.AllowDogs) == 0) { return(null); } } else if (avatar.IsPet) { return(null); //not allowed } if ((action.Flags & TTABFlags.TSOIsRepair) > 0 != ((action.Callee.MultitileGroup.BaseObject.TSOState as VMTSOObjectState)?.Broken ?? false)) { return(null); } TSOFlags tsoState = ((!(action.Callee is VMGameObject) || avatar.PersistID == ((VMTSOObjectState)action.Callee.TSOState).OwnerID) ? TSOFlags.AllowObjectOwner : 0) | ((((VMTSOAvatarState)avatar.TSOState).Permissions == VMTSOAvatarPermissions.Visitor) ? TSOFlags.AllowVisitors : 0) | ((((VMTSOAvatarState)avatar.TSOState).Permissions >= VMTSOAvatarPermissions.Roommate) ? TSOFlags.AllowRoommates : 0) | ((((VMTSOAvatarState)avatar.TSOState).Permissions == VMTSOAvatarPermissions.Admin) ? TSOFlags.AllowCSRs : 0) | ((avatar.GetPersonData(VMPersonDataVariable.IsGhost) > 0) ? TSOFlags.AllowGhost : 0) | TSOFlags.AllowFriends; TSOFlags tsoCompare = action.Flags2; //if flags are empty apart from "Non-Empty", force everything but visitor. (a kind of default state) if (tsoCompare == TSOFlags.NonEmpty) { tsoCompare |= TSOFlags.AllowFriends | TSOFlags.AllowRoommates | TSOFlags.AllowObjectOwner; } //DEBUG: enable debug interction for all CSRs. if ((action.Flags & TTABFlags.Debug) > 0) { if ((tsoState & TSOFlags.AllowCSRs) > 0) { return(result); //do not bother running check } else { return(null); //disable debug for everyone else. } } if ((action.Flags & TTABFlags.TSOAvailableWhenDead) > 0) { tsoCompare |= TSOFlags.AllowGhost; } if ((action.Flags & TTABFlags.AllowVisitors) > 0) { tsoCompare |= TSOFlags.AllowVisitors; //wrong??????? } var posMask = (TSOFlags.AllowObjectOwner); if (((tsoState & posMask) & (tsoCompare & posMask)) == 0) { //NEGATIVE EFFECTS: var negMask = (TSOFlags.AllowVisitors | TSOFlags.AllowRoommates | TSOFlags.AllowGhost); var negatedFlags = (~tsoCompare) & negMask; if ((negatedFlags & tsoState) > 0) { return(null); //we are disallowed } if ((tsoCompare & TSOFlags.AllowCSRs) > 0 && (tsoState & TSOFlags.AllowCSRs) == 0) { return(null); // only admins can run csr. } } } if (((action.Flags & TTABFlags.MustRun) == 0 || ((action.Flags & TTABFlags.TSORunCheckAlways) > 0)) && action.CheckRoutine != null && EvaluateCheck(Context, Entity, new VMStackFrame() { Caller = Entity, Callee = action.Callee, CodeOwner = action.CodeOwner, StackObject = action.StackObject, Routine = action.CheckRoutine, Args = new short[4] }, null, result) != VMPrimitiveExitCode.RETURN_TRUE) { return(null); } return(result); }
public bool ExecuteEntryPoint(int entry, VMContext context, bool runImmediately, VMEntity stackOBJ, short[] args) { if (entry == 11) { //user placement, hack to do auto floor removal/placement for stairs if (Object.OBJ.LevelOffset > 0 && Position != LotTilePos.OUT_OF_WORLD) { var floor = context.Architecture.GetFloor(Position.TileX, Position.TileY, Position.Level); var placeFlags = (VMPlacementFlags)ObjectData[(int)VMStackObjectVariable.PlacementFlags]; if ((placeFlags & VMPlacementFlags.InAir) > 0) context.Architecture.SetFloor(Position.TileX, Position.TileY, Position.Level, new FloorTile(), true); if ((placeFlags & VMPlacementFlags.OnFloor) > 0 && (floor.Pattern == 0)) context.Architecture.SetFloor(Position.TileX, Position.TileY, Position.Level, new FloorTile { Pattern = 1 } , true); } } bool result = false; if (EntryPoints[entry].ActionFunction > 255) { VMSandboxRestoreState SandboxState = null; if (GhostImage && runImmediately) { SandboxState = context.VM.Sandbox(); for (int i = 0; i < MultitileGroup.Objects.Count; i++) { var obj = MultitileGroup.Objects[i]; context.VM.AddEntity(obj); } } BHAV bhav; GameObject CodeOwner; ushort ActionID = EntryPoints[entry].ActionFunction; if (ActionID < 4096) { //global bhav = context.Globals.Resource.Get<BHAV>(ActionID); } else if (ActionID < 8192) { //local bhav = Object.Resource.Get<BHAV>(ActionID); } else { //semi-global bhav = SemiGlobal.Resource.Get<BHAV>(ActionID); } CodeOwner = Object; if (bhav != null) { var routine = context.VM.Assemble(bhav); var action = new VMQueuedAction { Callee = this, CodeOwner = CodeOwner, /** Main function **/ StackObject = stackOBJ, Routine = routine, Args = args }; if (runImmediately) { var checkResult = VMThread.EvaluateCheck(context, this, action); //if (checkResult == VMPrimitiveExitCode.ERROR) Delete(true, context); result = (checkResult == VMPrimitiveExitCode.RETURN_TRUE); } else this.Thread.EnqueueAction(action); } if (GhostImage && runImmediately) { //restore state context.VM.SandboxRestore(SandboxState); } return result; } else { return false; } }