public void Connect(uint UID, VMEntity invoker, VMEntity obj, VMAvatar avatar, bool joinable, VM vm) { if (InvokerToEOD.ContainsKey(invoker.ObjectID)) return; //uh, what? VMEODServer server = null; if (avatar != null && AvatarToEOD.ContainsKey(avatar.PersistID)) { //avatar already using an EOD... quickly abort this attempt with the stub EOD. joinable = false; UID = 0; avatar = null; } if (joinable) { if (!JoinableEODs.TryGetValue(obj.ObjectID, out server)) { server = new VMEODServer(UID, obj, joinable, vm); JoinableEODs[obj.ObjectID] = server; Servers.Add(server); } } else { server = new VMEODServer(UID, obj, joinable, vm); Servers.Add(server); } if (avatar != null) RegisterAvatar(avatar, server); RegisterInvoker(invoker, server); server.Connect(new VMEODClient(invoker, avatar, vm, UID)); }
public void AddObject(VMEntity obj) { AddDynamicObject(obj, new LotTilePos((short)((sbyte)(((ushort)obj.Object.OBJ.SubIndex) >> 8) * 16), (short)((sbyte)(((ushort)obj.Object.OBJ.SubIndex) & 0xFF) * 16), (sbyte)obj.Object.OBJ.LevelOffset)); }
public VMRuntimeHeadline(VMSetBalloonHeadlineOperand op, VMEntity targ, VMEntity icon, sbyte index) { Operand = op; Target = targ; IconTarget = icon; Index = index; Duration = (op.DurationInLoops && op.Duration != -1) ? op.Duration * 15 : op.Duration; }
public VMThread(VMContext context, VMEntity entity, int stackSize) { this.Context = context; this.Entity = entity; this.Stack = new List<VMStackFrame>(stackSize); this.Queue = new List<VMQueuedAction>(); }
//type 2 will be function callback. public void Run(VMEntity cbOwner) { if (type == 1) { BHAV bhav; GameObject CodeOwner = null; ushort ActionID; TTABFlags ActionFlags; string ActionName = ""; if (IsTree) { ActionFlags = TTABFlags.Leapfrog; ActionID = (ushort)Interaction; } else { var Action = Target.TreeTable.InteractionByIndex[(byte)Interaction]; ActionID = Action.ActionFunction; ActionFlags = Action.Flags; ActionName = Target.TreeTableStrings.GetString((int)Action.TTAIndex); } if (ActionID < 4096) { //global bhav = null; //unimp as it has to access the context to get this. } else if (ActionID < 8192) { //local bhav = Target.Object.Resource.Get<BHAV>(ActionID); } else { //semi-global bhav = Target.SemiGlobal.Get<BHAV>(ActionID); } if (bhav == null) return; //??? if (IsTree) ActionName = bhav.ChunkLabel; CodeOwner = Target.Object; var routine = vm.Assemble(bhav); var args = new short[4]; if (SetParam) args[0] = cbOwner.ObjectID; Caller.Thread.EnqueueAction( new FSO.SimAntics.Engine.VMQueuedAction { Callee = Target, CodeOwner = CodeOwner, ActionRoutine = routine, Name = ActionName, StackObject = this.StackObject, Args = args, InteractionNumber = Interaction, Priority = (short)VMQueuePriority.Maximum, //not sure if this is meant to be the case! Flags = ActionFlags } ); } }
public void Load(VMFindLocationResultMarshal input, VMContext context) { RadianDirection = input.RadianDirection; Position = input.Position; Score = input.Score; FaceAnywhere = input.FaceAnywhere; Chair = context.VM.GetObjectById(input.Chair); RouteEntryFlags = input.RouteEntryFlags; }
public VMRuntimeHeadline(VMRuntimeHeadlineMarshal input, VMContext context) { Operand = input.Operand; Target = context.VM.GetObjectById(input.Target); IconTarget = context.VM.GetObjectById(input.IconTarget); Index = input.Index; Duration = input.Duration; Anim = input.Anim; }
public void Load(VMActionCallbackMarshal input, VMContext context) { type = input.Type; Target = context.VM.GetObjectById(input.Target); Interaction = input.Interaction; SetParam = input.SetParam; StackObject = context.VM.GetObjectById(input.StackObject); Caller = context.VM.GetObjectById(input.Caller); }
//type 1: interaction callback public VMActionCallback(VM vm, byte interactionNumber, VMEntity target, VMEntity stackObj, VMEntity caller, bool paramAsObjectID) { this.type = 1; this.Target = target; this.Interaction = interactionNumber; this.SetParam = paramAsObjectID; this.StackObject = stackObj; this.vm = vm; this.Caller = caller; }
private short StackPointer; /** -1 means idle **/ #endregion Fields #region Constructors public VMThread(VMContext context, VMEntity entity, int stackSize) { this.Context = context; this.Entity = entity; this.Stack = new VMStackFrame[stackSize]; this.StackPointer = -1; this.Queue = new List<VMQueuedAction>(); Context.ThreadIdle(this); }
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; }
public static VMPrimitiveExitCode EvaluateCheck(VMContext context, VMEntity entity, VMQueuedAction action) { var temp = new VMThread(context, entity, 5); temp.EnqueueAction(action); while (temp.Queue.Count > 0) //keep going till we're done! idling is for losers! { temp.Tick(); } context.ThreadRemove(temp); //hopefully this thread should be completely dereferenced... return temp.LastStackExitCode; }
public void RemoveObject(VMEntity obj) { var guid = obj.Object.OBJ.GUID; List<VMEntity> list = null; ObjectsByGUID.TryGetValue(guid, out list); if (list != null) { list.Remove(obj); if (list.Count == 0) ObjectsByGUID.Remove(guid); } if (obj is VMAvatar) Avatars.Remove(obj); }
public void RegisterObjectPos(VMEntity ent) { var off = GetOffest(ent.Position); List<VMEntity> tile = null; TileToObjects.TryGetValue(off, out tile); if (tile == null) { tile = new List<VMEntity>(); TileToObjects.Add(off, tile); } if (!tile.Contains(ent)) VM.AddToObjList(tile, ent); //shouldn't be a problem any more, but just in case check first. else { } }
public void NewObject(VMEntity obj) { var guid = obj.Object.OBJ.GUID; List<VMEntity> list = null; ObjectsByGUID.TryGetValue(guid, out list); if (list == null) { list = new List<VMEntity>(); ObjectsByGUID.Add(guid, list); } VM.AddToObjList(list, obj); if (obj is VMAvatar) VM.AddToObjList(Avatars, obj); }
public static bool FindLocationVector(VMEntity obj, VMEntity refObj, VMContext context, int dir) { LotTilePos step = DirectionVectors[dir]; for (int i = 0; i < 32; i++) { if (obj.SetPosition(new LotTilePos(refObj.Position) + step * i, (Direction)(1 << (dir)), context).Status == VMPlacementError.Success) return true; if (i != 0) { if (obj.SetPosition(new LotTilePos(refObj.Position) - step * i, (Direction)(1 << (dir)), context).Status == VMPlacementError.Success) return true; } } return false; }
//type 2 will be function callback. public void Run(VMEntity cbOwner) { if (type == 1) { BHAV bhav; GameObject CodeOwner = null; var Action = Target.TreeTable.InteractionByIndex[Interaction]; ushort ActionID = Action.ActionFunction; if (ActionID < 4096) { //global bhav = null; //unimp as it has to access the context to get this. } else if (ActionID < 8192) { //local bhav = Target.Object.Resource.Get<BHAV>(ActionID); } else { //semi-global bhav = Target.SemiGlobal.Resource.Get<BHAV>(ActionID); //CodeOwner = Target.SemiGlobal.Resource; } CodeOwner = Target.Object; var routine = vm.Assemble(bhav); var args = new short[4]; if (SetParam) args[0] = cbOwner.ObjectID; Caller.Thread.EnqueueAction( new FSO.SimAntics.Engine.VMQueuedAction { Callee = Target, CodeOwner = CodeOwner, Routine = routine, Name = Target.TreeTableStrings.GetString((int)Action.TTAIndex), StackObject = this.StackObject, Args = args, InteractionNumber = Interaction, Priority = VMQueuePriority.Maximum //not sure if this is meant to be the case! } ); } }
public static VMPrimitiveExitCode EvaluateCheck(VMContext context, VMEntity entity, 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.EnqueueAction(action); while (temp.Queue.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 void ProcessQTRDay(VM vm, VMEntity owner) { if (((VMGameObject)owner).Disabled > 0) { return; } if (ObjectFlags.HasFlag(VMTSOObjectFlags.FSODonated)) { Wear = 0; QtrDaysSinceLastRepair = 0; return; } Wear += 1; if (Wear > 90 * 4) { Wear = 90 * 4; } if (QtrDaysSinceLastRepair <= 7 * 4) { QtrDaysSinceLastRepair++; } //can break if the object has a repair interaction. if (QtrDaysSinceLastRepair > 7 * 4 && Wear > 50 * 4 && owner.TreeTable?.Interactions?.Any(x => (x.Flags & TTABFlags.TSOIsRepair) > 0) == true) { //object can break. calculate probability var rand = (int)vm.Context.NextRandom(10000); //lerp //1% at 50%, 4% at 90% var prob = 100 + ((Wear - (50 * 4)) * 75) / 40; if (rand < prob && owner.MultitileGroup.BaseObject == owner) { //break the object QtrDaysSinceLastRepair = 255; //apply the broken object particle to all parts foreach (var item in owner.MultitileGroup.Objects) { ((VMGameObject)item).EnableParticle(256); } } } }
public void RegisterObjectPos(VMEntity ent) { var off = GetOffest(ent.Position); List <VMEntity> tile = null; TileToObjects.TryGetValue(off, out tile); if (tile == null) { tile = new List <VMEntity>(); TileToObjects.Add(off, tile); } if (!tile.Contains(ent)) { VM.AddToObjList(tile, ent); //shouldn't be a problem any more, but just in case check first. } else { } }
public static bool FindLocationVector(VMEntity obj, VMEntity refObj, VMContext context, int dir, VMPlaceRequestFlags flags, bool preferNonEmpty = false) { LotTilePos step = DirectionVectors[dir]; var dirf = (Direction)(1 << (dir)); var deferred = new List <LotTilePos>(); Func <LotTilePos, bool> evaluate = (LotTilePos pos) => { if (preferNonEmpty && TileOccupied(context, pos)) { deferred.Add(pos); return(false); } else { return(obj.SetPosition(pos, dirf, context, flags).Status == VMPlacementError.Success); } }; for (int i = 0; i < 32; i++) { if (evaluate(new LotTilePos(refObj.Position) + step * (i / 2))) { return(true); } if (i % 2 != 0) { if (evaluate(new LotTilePos(refObj.Position) - step * (i / 2))) { return(true); } } } foreach (var tile in deferred) { if (obj.SetPosition(tile, dirf, context, flags).Status == VMPlacementError.Success) { return(true); } } return(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 RecursiveUnhide(VMEntity fake, VMEntity real) { var rgrp = real.MultitileGroup; for (int i = 0; i < rgrp.Objects.Count; i++) { rgrp.Objects[i].SetValue(VMStackObjectVariable.Hidden, fake.MultitileGroup.Objects[i].GetValue(VMStackObjectVariable.Hidden)); var slots = rgrp.Objects[i].TotalSlots(); for (int j = 0; j < slots; j++) { var slot = rgrp.Objects[i].GetSlot(j); var slot2 = fake.GetSlot(j); if (slot != null && slot2 != null && slot.GetValue(VMStackObjectVariable.Hidden) != slot2.GetValue(VMStackObjectVariable.Hidden)) { RecursiveUnhide(slot2, slot); } } } }
public override bool Execute(VM vm) { VMEntity obj = vm.GetObjectById(ObjectID); if (obj == null || (obj is VMAvatar)) { return(false); } if (obj.PersistID > 0) { vm.Context.ObjectQueries.RemoveMultitilePersist(vm, obj.PersistID); //in case persist is reassigned somehow } foreach (var e in obj.MultitileGroup.Objects) { e.PersistID = PersistID; } vm.Context.ObjectQueries.RegisterMultitilePersist(obj.MultitileGroup, obj.PersistID); return(true); }
private uint GetOwnerID(VMEntity obj, VMStackFrame context) { if (obj is VMAvatar) { return(0); } else { var objState = (obj.TSOState as VMTSOObjectState); if (objState.ObjectFlags.HasFlag(VMTSOObjectFlags.FSODonated) && context.VM.TSOState.CommunityLot) { return(context.VM.TSOState.OwnerID); } else { return(objState.OwnerID); } } }
public override bool Execute(VM vm, VMAvatar caller) { VMEntity callee = vm.GetObjectById(CalleeID); if (callee == null || caller == null) { return(false); } if (callee is VMGameObject && ((VMGameObject)callee).Disabled > 0) { return(false); } if (caller.Thread.Queue.Count >= VMThread.MAX_USER_ACTIONS) { return(false); } callee.PushUserInteraction(Interaction, caller, vm.Context, Global, new short[] { Param0, 0, 0, 0 }); return(true); }
public void RemoveObject(VMEntity obj) { var guid = obj.Object.OBJ.GUID; List <VMEntity> list = null; ObjectsByGUID.TryGetValue(guid, out list); if (list != null) { list.Remove(obj); if (list.Count == 0) { ObjectsByGUID.Remove(guid); } } if (obj is VMAvatar) { Avatars.Remove(obj); } }
public void IDEBreakpointHit(VM vm, VMEntity targetEnt) { new Thread(() => { if (MainWindow.Instance == null) { return; } try { MainWindow.Instance.Invoke(new MainWindowDelegate(() => { MainWindow.Instance.BHAVManager.OpenTracer(vm, targetEnt); }), null); } catch (Exception) { //oops? } }).Start(); }
private void RecursiveDelete(VMContext context, VMEntity real) { var rgrp = real.MultitileGroup; for (int i = 0; i < rgrp.Objects.Count; i++) { var slots = rgrp.Objects[i].TotalSlots(); var objs = new List<VMEntity>(); for (int j = 0; j < slots; j++) { var slot = rgrp.Objects[i].GetSlot(j); if (slot != null) { objs.Add(slot); } } foreach (var obj in objs) RecursiveDelete(context, obj); } rgrp.Delete(context); }
public void RunAction(VMEntity entity) { bool PetAction = entity.Object.GUID == VMAvatar.DOG_TEMPLATE ? true : false; if (Objects.Count > 0) { Random rand = new Random(); int n = rand.Next(0, Objects.Count - 1); Target = Objects[n]; Objects.RemoveAt(n); SetSelected(Target, PetAction); if (entity != Target) { ExecuteAction(entity, Target); } } }
public override bool Execute(VM vm) { VMEntity obj = vm.GetObjectById(ObjectID); if (obj == null || (obj is VMAvatar)) { return(false); } var result = obj.SetPosition(new LotTilePos(x, y, level), dir, vm.Context); if (result.Status == VMPlacementError.Success) { obj.MultitileGroup.ExecuteEntryPoint(11, vm.Context); //User Placement return(true); } else { return(false); } }
public override bool Execute(VM vm, VMAvatar caller) { if (caller == null || ((VMTSOAvatarState)caller.TSOState).Permissions < VMTSOAvatarPermissions.Roommate) { return(false); } VMEntity obj = vm.GetObjectByPersist(ObjectPID); //object must not be in use to set it for sale (will be disabled). if (obj == null || (obj is VMAvatar) || (NewPrice > 0 && obj.IsUserMovable(vm.Context, true) != VMPlacementError.Success)) { return(false); } if ((((VMGameObject)obj).Disabled & VMGameObjectDisableFlags.TransactionIncomplete) > 0) { return(false); //can't change price mid trasaction... } //must own the object to set it for sale if (obj.PersistID == 0 || ((VMTSOObjectState)obj.TSOState).OwnerID != caller.PersistID) { return(false); } if (NewPrice >= 0) { foreach (var o in obj.MultitileGroup.Objects) { ((VMGameObject)o).Disabled |= VMGameObjectDisableFlags.ForSale; } obj.MultitileGroup.SalePrice = NewPrice; } else { foreach (var o in obj.MultitileGroup.Objects) { ((VMGameObject)o).Disabled &= ~VMGameObjectDisableFlags.ForSale; } obj.MultitileGroup.SalePrice = -1; } return(true); }
public void SetSelected(VMMultitileGroup Group) { if (Holding != null) { ClearSelected(); } Holding = new UIObjectSelection(); Holding.Group = Group; Holding.PreviousTile = Holding.Group.BaseObject.Position; Holding.Dir = Group.Objects[0].Direction; VMEntity[] CursorTiles = new VMEntity[Group.Objects.Count]; for (int i = 0; i < Group.Objects.Count; i++) { var target = Group.Objects[i]; target.SetRoom(65534); if (target is VMGameObject) { ((ObjectComponent)target.WorldUI).ForceDynamic = true; } CursorTiles[i] = vm.Context.CreateObjectInstance(0x00000437, new LotTilePos(target.Position), FSO.LotView.Model.Direction.NORTH, true).Objects[0]; CursorTiles[i].SetPosition(new LotTilePos(0, 0, 1), Direction.NORTH, vm.Context); ((ObjectComponent)CursorTiles[i].WorldUI).ForceDynamic = true; } Holding.TilePosOffset = new Vector2(0, 0); Holding.CursorTiles = CursorTiles; uint guid; var bobj = Group.BaseObject; guid = bobj.Object.OBJ.GUID; if (bobj.MasterDefinition != null) { guid = bobj.MasterDefinition.GUID; } var catalogItem = Content.Content.Get().WorldCatalog.GetItemByGUID(guid); if (catalogItem != null) { Holding.Price = (int)catalogItem.Price; } }
public override VMPrimitiveExitCode Execute(VMStackFrame context, VMPrimitiveOperand args) { var operand = (VMRefreshOperand)args; VMEntity target = null; switch (operand.TargetObject) { case 0: target = context.Caller; break; case 1: target = context.StackObject; break; } switch (operand.RefreshType) { case 0: //graphic if (target is VMGameObject) { var TargObj = (VMGameObject)target; TargObj.RefreshGraphic(); } break; case 1: //light context.VM.Context.RefreshLighting(context.VM.Context.GetObjectRoom(target), true, new HashSet <ushort>()); if (target is VMGameObject) { ((VMGameObject)target).RefreshLight(); } break; case 2: //area contribution context.VM.Context.RefreshRoomScore(context.VM.Context.GetObjectRoom(target)); break; } return(VMPrimitiveExitCode.GOTO_TRUE); }
public void SetInfo(Texture2D thumb, string name, string description, int price) { ActiveEntity = null; DescriptionText.CurrentText = name + "\r\n" + description; ObjectNameText.Caption = name; StringBuilder motivesString = new StringBuilder(); motivesString.AppendFormat(GameFacade.Strings.GetString("206", "19") + "${0}\r\n", price); MotivesText.CurrentText = motivesString.ToString(); SpecificTabButton.Disabled = true; SellBackButton.Disabled = true; if (Thumbnail.Texture != null) { Thumbnail.Texture.Dispose(); } Thumbnail.Texture = thumb; UpdateImagePosition(); }
public void InitBHAV(BHAV bhav, EditorScope scope, VMEntity debugEnt, VMStackFrame debugFrame, BHAVPrimSelect callback) { if (FSOUI == null) { var mainCont = new UIExternalContainer(1024, 768); Editor = new UIBHAVEditor(bhav, scope, debugEnt); mainCont.Add(Editor); GameFacade.Screens.AddExternal(mainCont); SetUI(mainCont); Editor.BHAVView.OnSelectedChanged += callback; } else { //reuse existing lock (FSOUI) { Editor.QueueCommand(new ChangeBHAVCommand(bhav, scope, debugFrame, callback)); } } }
public override bool Execute(VM vm, VMAvatar caller) { VMEntity obj = vm.GetObjectById(ObjectID); if (!vm.TS1) { if (obj == null || caller == null || (obj is VMAvatar) || (caller.AvatarState.Permissions < VMTSOAvatarPermissions.Owner && obj.IsUserMovable(vm.Context, false) != VMPlacementError.Success)) { return(false); } if (caller.AvatarState.Permissions < VMTSOAvatarPermissions.Roommate) { return(false); } } else if (obj == null) { return(false); } var result = obj.SetPosition(new LotTilePos(x, y, level), dir, vm.Context, VMPlaceRequestFlags.UserPlacement); if (result.Status == VMPlacementError.Success) { obj.MultitileGroup.ExecuteEntryPoint(11, vm.Context); //User Placement vm.SignalChatEvent(new VMChatEvent(caller, VMChatEventType.Arch, caller?.Name ?? "Unknown", vm.GetUserIP(caller?.PersistID ?? 0), "moved " + obj.ToString() + " to (" + x / 16f + ", " + y / 16f + ", " + level + ")" )); return(true); } else { return(false); } }
public override bool Execute(VM vm) { if (ResponseText.Length > 32) { ResponseText = ResponseText.Substring(0, 32); } VMEntity caller = vm.Entities.FirstOrDefault(x => x.PersistID == ActorUID); //TODO: check if net user owns caller! if (caller == null || caller is VMGameObject || caller.Thread.BlockingState == null || !(caller.Thread.BlockingState is VMDialogResult)) { return(false); } var state = (VMDialogResult)caller.Thread.BlockingState; state.Responded = true; state.ResponseCode = ResponseCode; state.ResponseText = ResponseText; return(true); }
public void NewObject(VMEntity obj) { var guid = obj.Object.OBJ.GUID; List <VMEntity> list = null; ObjectsByGUID.TryGetValue(guid, out list); if (list == null) { list = new List <VMEntity>(); ObjectsByGUID.Add(guid, list); } VM.AddToObjList(list, obj); if (obj is VMAvatar) { VM.AddToObjList(Avatars, obj); if (obj.PersistID != 0) { AvatarsByPersist[obj.PersistID] = (VMAvatar)obj; } } }
public void RemoveObject(VMEntity obj) { var guid = obj.Object.OBJ.GUID; List <VMEntity> list = null; ObjectsByGUID.TryGetValue(guid, out list); if (list != null) { VM.DeleteFromObjList(list, obj); if (list.Count == 0) { ObjectsByGUID.Remove(guid); } } RemoveCategory(obj, obj.GetValue(VMStackObjectVariable.Category)); if (obj is VMAvatar) { Avatars.Remove(obj); AvatarsByPersist.Remove(obj.PersistID); } else if (obj.PersistID > 0 && obj.MultitileGroup.Objects.Count == 1) { MultitileByPersist.Remove(obj.PersistID); if (obj.Thread != null) { var vm = obj.Thread.Context.VM; if (vm.PlatformState.LimitExceeded) { VMBuildableAreaInfo.UpdateOverbudgetObjects(vm); } } } if (obj.TreeTable != null && obj.TreeTable.AutoInteractions.Length > 0) { WithAutonomy.Remove(obj); } }
public static bool FindLocationVector(VMEntity obj, VMEntity refObj, VMContext context, int dir, VMPlaceRequestFlags flags) { LotTilePos step = DirectionVectors[dir]; for (int i = 0; i < 32; i++) { if (obj.SetPosition(new LotTilePos(refObj.Position) + step * (i / 2), (Direction)(1 << (dir)), context, flags).Status == VMPlacementError.Success) { return(true); } if (i % 2 != 0) { if (obj.SetPosition(new LotTilePos(refObj.Position) - step * (i / 2), (Direction)(1 << (dir)), context, flags).Status == VMPlacementError.Success) { return(true); } } } return(false); }
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 SetSelected(VMEntity entity) { SelectedEntity = entity; propertyGrid.SelectedObject = entity; bhavList.Items.Clear(); var resource = entity.Object; var bhavs = resource.Resource.List <BHAV>(); if (bhavs != null) { foreach (var bhav in bhavs) { bhavList.Items.Add(bhav); } } if (entity.SemiGlobal != null) { var sglobbhavs = entity.SemiGlobal.List <BHAV>(); if (bhavs != null) { foreach (var bhav in sglobbhavs) { bhavList.Items.Add(bhav); } } } interactionList.Items.Clear(); if (entity.TreeTable != null) { TreeTableSel = entity.TreeTable; foreach (var interaction in entity.TreeTable.Interactions) { interactionList.Items.Add(entity.TreeTableStrings.GetString((int)interaction.TTAIndex)); } } }
public void NewObject(VMEntity obj) { var guid = obj.Object.OBJ.GUID; ObjectsByGUID.TryGetValue(guid, out var list); if (list == null) { list = new List <VMEntity>(); ObjectsByGUID.Add(guid, list); } VM.AddToObjList(list, obj); RegisterCategory(obj, obj.GetValue(VMStackObjectVariable.Category)); if (obj is VMAvatar) { VM.AddToObjList(Avatars, obj); if (obj.PersistID != 0) { AvatarsByPersist[obj.PersistID] = (VMAvatar)obj; } } }
public override bool Execute(VM vm) { var type = State.GetType(); //if ID is 0, there is no thread to unblock, and we just have to do the extra functionality below. if (ID != 0) { VMEntity obj = vm.GetObjectById(ID); //we can only update an object's blocking state if it exists and is of the same type exactly. if (obj == null || obj.Thread.BlockingState == null || obj.Thread.BlockingState.GetType() != type) { return(false); } obj.Thread.BlockingState = State; } if (type == typeof(VMTransferFundsState)) { //special handling. update visual budgets of involved elements. //note: if we are the server and the reference budget IS the visual, do not update. if (vm.GlobalLink == null || !(vm.GlobalLink is VMTSOGlobalLinkStub)) { var state = (VMTransferFundsState)State; var obj1 = vm.GetObjectByPersist(state.UID1); if (obj1 != null) { obj1.TSOState.Budget.Value = state.Budget1; } var obj2 = vm.GetObjectByPersist(state.UID2); if (obj2 != null) { obj2.TSOState.Budget.Value = state.Budget2; } } } return(true); }
public void SetSelected(VMMultitileGroup Group) { if (Holding != null) ClearSelected(); Holding = new UIObjectSelection(); Holding.Group = Group; Holding.PreviousTile = Holding.Group.BaseObject.Position; Holding.Dir = Group.Objects[0].Direction; VMEntity[] CursorTiles = new VMEntity[Group.Objects.Count]; for (int i = 0; i < Group.Objects.Count; i++) { var target = Group.Objects[i]; target.ExecuteEntryPoint(10, vm.Context, true, target); target.SetRoom(65534); if (target is VMGameObject) ((ObjectComponent)target.WorldUI).ForceDynamic = true; CursorTiles[i] = vm.Context.CreateObjectInstance(0x00000437, new LotTilePos(target.Position), FSO.LotView.Model.Direction.NORTH, true).Objects[0]; CursorTiles[i].SetPosition(new LotTilePos(0,0,1), Direction.NORTH, vm.Context); CursorTiles[i].SetRoom(65535); ((ObjectComponent)CursorTiles[i].WorldUI).ForceDynamic = true; } Holding.TilePosOffset = new Vector2(0, 0); Holding.CursorTiles = CursorTiles; uint guid; var bobj = Group.BaseObject; guid = bobj.Object.OBJ.GUID; if (bobj.MasterDefinition != null) guid = bobj.MasterDefinition.GUID; var catalogItem = Content.Content.Get().WorldCatalog.GetItemByGUID(guid); if (catalogItem != null) { var price = Group.InitialPrice; //(int)catalogItem.Value.Price; var dcPercent = VMBuildableAreaInfo.GetDiscountFor(catalogItem.Value, vm); var finalPrice = (price * (100 - dcPercent)) / 100; if (DonateMode) finalPrice -= (finalPrice * 2) / 3; Holding.Price = finalPrice; Group.InitialPrice = finalPrice; Group.BeforeDCPrice = price; } }
public static short MultitilePart(VMStackFrame context, VMEntity pointer, short targetValue) { if (pointer == null || (!pointer.MultitileGroup.MultiTile)) { return(0); //single part } else { var group = pointer.MultitileGroup.Objects; bool found = false; short bestID = 0; short smallestID = 0; for (int i = 0; i < group.Count; i++) { var temp = group[i]; if (temp.ObjectID < smallestID || smallestID == 0) { smallestID = temp.ObjectID; } if (temp.ObjectID > targetValue) { if ((!found) || (temp.ObjectID < bestID)) { found = true; bestID = temp.ObjectID; } } } if (found) { return(bestID); } else { return(smallestID); } } }
public static bool FindLocationFor(VMEntity obj, VMEntity refObj, VMContext context) { for (int i = 0; i < 10; i++) { if (i == 0) { for (int j = 0; j < 4; j++) { if (obj.SetPosition(new LotTilePos(refObj.Position), (Direction)(1 << (j * 2)), context).Status == VMPlacementError.Success) return true; } } else { LotTilePos bPos = refObj.Position; for (int x = -i; x <= i; x++) { for (int j = 0; j < 8; j++) { if (obj.SetPosition(LotTilePos.FromBigTile((short)(bPos.TileX + x), (short)(bPos.TileY + ((j % 2) * 2 - 1) * i), bPos.Level), (Direction)(1 << ((j / 2) * 2)), context).Status == VMPlacementError.Success) return true; } } for (int y = 1 - i; y < i; y++) { for (int j = 0; j < 8; j++) { if (obj.SetPosition(LotTilePos.FromBigTile((short)(bPos.TileX + ((j % 2) * 2 - 1) * i), (short)(bPos.TileY + y), bPos.Level), (Direction)(1 << ((j / 2) * 2)), context).Status == VMPlacementError.Success) return true; } } } } return false; }
public void Connect(uint UID, VMEntity invoker, VMEntity obj, VMAvatar avatar, bool joinable, VM vm) { if (InvokerToEOD.ContainsKey(invoker.ObjectID)) { return; //uh, what? } VMEODServer server = null; if (avatar != null && AvatarToEOD.ContainsKey(avatar.PersistID)) { //avatar already using an EOD... quickly abort this attempt with the stub EOD. joinable = false; UID = 0; avatar = null; } if (joinable) { if (!JoinableEODs.TryGetValue(obj.ObjectID, out server)) { server = new VMEODServer(UID, obj, joinable, vm); JoinableEODs[obj.ObjectID] = server; Servers.Add(server); } } else { server = new VMEODServer(UID, obj, joinable, vm); Servers.Add(server); } if (avatar != null) { RegisterAvatar(avatar, server); } RegisterInvoker(invoker, server); server.Connect(new VMEODClient(invoker, avatar, vm, UID)); }
public void ForceDisconnectObj(VMEntity invoker) { VMEODServer server = null; if (InvokerToEOD.TryGetValue(invoker.ObjectID, out server)) { var invokerClient = server.Clients.FirstOrDefault(x => x.Invoker == invoker); if (invokerClient != null) { server.Disconnect(invokerClient); } } }
public static VMPrimitiveExitCode EvaluateCheck(VMContext context, VMEntity entity, VMStackFrame initFrame) { return EvaluateCheck(context, entity, initFrame, null, null); }
public static VMPrimitiveExitCode EvaluateCheck(VMContext context, VMEntity entity, VMStackFrame initFrame, VMQueuedAction action) { return EvaluateCheck(context, entity, initFrame, action, null); }
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) { //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; }
// TODO: float values may desync if devices are not both x86 or using a different C# library. // Might need to replace with fixed point library for position and rotation /// <summary> /// This method will find all the avaliable locations within the criteria ordered by proximity to the optimal proximity /// External functions can then decide which is most desirable. E.g. the nearest slot to the object may be the longest route if /// its in another room. /// </summary> /// <param name="obj"></param> /// <param name="slot"></param> /// <param name="context"></param> /// <returns></returns> public List<VMFindLocationResult> FindAvaliableLocations(VMEntity obj, VMContext context, VMEntity caller) { /** * Start at min proximity and circle around the object to find the avaliable locations. * Then pick the one nearest to the optimal value */ /** * ------ MAJOR TODO: ------ * Avoid vector math at all costs! Small differences in hardware could cause desyncs. * This really goes for all areas of the SimAntics engine, but here it's particularly bad. */ Vector2 center; if (OnlySit) FailCode = VMRouteFailCode.NoChair; // if we need to use the average location of an object group, it needs to be calculated. if (((Flags & SLOTFlags.UseAverageObjectLocation) > 0) && (obj.MultitileGroup.MultiTile)) { center = new Vector2(0, 0); var objs = obj.MultitileGroup.Objects; for (int i = 0; i < objs.Count; i++) { center += new Vector2(objs[i].Position.x/16f, objs[i].Position.y/16f); } center /= objs.Count; } else center = new Vector2(obj.Position.x/16f, obj.Position.y/16f); //add offset of slot if it exists. must be rotated to be relative to object var rotOff = Vector3.Transform(Slot.Offset, Matrix.CreateRotationZ(obj.RadianDirection)); var circleCtr = new Vector2(center.X + rotOff.X / 16, center.Y + rotOff.Y / 16); ushort room = context.VM.Context.GetRoomAt(obj.Position); Results = new List<VMFindLocationResult>(); if ((Flags & SLOTFlags.SnapToDirection) > 0) { //snap to the specified direction, on the specified point. double baseRot; if (Slot.Facing > SLOTFacing.FaceAwayFromObject) { // bit of a legacy thing here. Facing field did not use to exist, // which is why SnapToDirection was hacked to use the directional flags. // now that it exists, it is used instead, to encode the same information... // just transform back into old format. Flags |= (SLOTFlags)(1 << (int)Slot.Facing); } else { if (((int)Flags & 255) == 0) Flags |= SLOTFlags.NORTH; } var flagRot = DirectionUtils.PosMod(obj.RadianDirection+FlagsAsRad(Flags), Math.PI*2); if (flagRot > Math.PI) flagRot -= Math.PI * 2; VerifyAndAddLocation(obj, circleCtr, center, Flags, Double.MaxValue, context, caller, (float)flagRot); return Results; } else { if (((int)Flags & 255) == 0 || Slot.Offset != new Vector3()) { //exact position //Flags |= (SLOTFlags)255; // special case, walk directly to point. VerifyAndAddLocation(obj, circleCtr, center, Flags, Double.MaxValue, context, caller, float.NaN); return Results; } var maxScore = Math.Max(DesiredProximity - MinProximity, MaxProximity - DesiredProximity) + (LotTilePos.Distance(obj.Position, caller.Position)+MaxProximity)/3 + 2; var ignoreRooms = (Flags & SLOTFlags.IgnoreRooms) > 0; var resolutionBound = (MaxProximity / Slot.Resolution) * Slot.Resolution; for (int x = -resolutionBound; x <= resolutionBound; x += Slot.Resolution) { for (int y = -resolutionBound; y <= resolutionBound; y += Slot.Resolution) { var pos = new Vector2(circleCtr.X + x / 16.0f, circleCtr.Y + y / 16.0f); double distance = Math.Sqrt(x * x + y * y); if (distance >= MinProximity - 0.01 && distance <= MaxProximity + 0.01 && (ignoreRooms || context.VM.Context.GetRoomAt(new LotTilePos((short)Math.Round(pos.X * 16), (short)Math.Round(pos.Y * 16), obj.Position.Level)) == room)) //slot is within proximity { var routeEntryFlags = (GetSearchDirection(circleCtr, pos, obj.RadianDirection) & Flags); //the route needs to know what conditions it fulfilled if (routeEntryFlags > 0) //within search location { double baseScore = ((maxScore - Math.Abs(DesiredProximity - distance)) + context.VM.Context.NextRandom(1024) / 1024.0f); VerifyAndAddLocation(obj, pos, center, routeEntryFlags, baseScore, context, caller, float.NaN); } } } } } /** Sort by how close they are to desired proximity **/ if (Results.Count > 1) Results = Results.OrderBy(x => -x.Score).ToList(); //avoid sort because it acts incredibly unusually if (Results.Count > 0) FailCode = VMRouteFailCode.Success; return Results; }
private void SetFail(VMRouteFailCode code, VMEntity blocker) { if (Array.IndexOf(FailPrio, code) > Array.IndexOf(FailPrio, FailCode)) { FailCode = code; Blocker = blocker; } }
private void VerifyAndAddLocation(VMEntity obj, Vector2 pos, Vector2 center, SLOTFlags entryFlags, double score, VMContext context, VMEntity caller, float facingDir) { //note: verification is not performed if snap target slot is enabled. var tpos = new LotTilePos((short)Math.Round(pos.X * 16), (short)Math.Round(pos.Y * 16), obj.Position.Level); if (context.IsOutOfBounds(tpos)) return; score -= LotTilePos.Distance(tpos, caller.Position)/3.0; if (Slot.SnapTargetSlot < 0 && context.Architecture.RaycastWall(new Point((int)pos.X, (int)pos.Y), new Point(obj.Position.TileX, obj.Position.TileY), obj.Position.Level)) { SetFail(VMRouteFailCode.WallInWay, null); return; } bool faceAnywhere = false; if (float.IsNaN(facingDir)) { var obj3P = obj.Position.ToVector3(); var objP = new Vector2(obj3P.X, obj3P.Y); switch (Slot.Facing) { case SLOTFacing.FaceTowardsObject: facingDir = (float)GetDirectionTo(pos, objP); break; case SLOTFacing.FaceAwayFromObject: facingDir = (float)GetDirectionTo(objP, pos); break; case SLOTFacing.FaceAnywhere: faceAnywhere = true; facingDir = 0.0f; break; default: int intDir = (int)Math.Round(Math.Log((double)obj.Direction, 2)); var rotatedF = ((int)Slot.Facing + intDir) % 8; facingDir = (float)(((int)rotatedF > 4) ? ((double)rotatedF * Math.PI / 4.0) : (((double)rotatedF - 8.0) * Math.PI / 4.0)); break; } } VMEntity chair = null; if (Slot.SnapTargetSlot < 0) { var solid = caller.PositionValid(tpos, Direction.NORTH, context); if (solid.Status != Model.VMPlacementError.Success) { if (solid.Object != null && solid.Object is VMGameObject) { if (Slot.Sitting > 0 && solid.Object.EntryPoints[26].ActionFunction != 0) { chair = solid.Object; } else { SetFail(VMRouteFailCode.DestTileOccupied, solid.Object); return; } } } if (chair != null && (Math.Abs(DirectionUtils.Difference(chair.RadianDirection, facingDir)) > Math.PI / 4)) return; //not a valid goal. if (chair == null && OnlySit) return; } Results.Add(new VMFindLocationResult { Position = new LotTilePos((short)Math.Round(pos.X * 16), (short)Math.Round(pos.Y * 16), obj.Position.Level), Score = score * ((chair != null) ? Slot.Sitting : Slot.Standing), //todo: prefer closer? RadianDirection = facingDir, Chair = chair, FaceAnywhere = faceAnywhere, RouteEntryFlags = entryFlags }); }
public VMPlacementResult ChangePosition(LotTilePos pos, Direction direction, VMContext context) { if (pos.Level > context.Architecture.Stories) return new VMPlacementResult(VMPlacementError.NotAllowedOnFloor); VMEntity[] OldContainers = new VMEntity[Objects.Count]; short[] OldSlotNum = new short[Objects.Count]; for (int i = 0; i < Objects.Count(); i++) { OldContainers[i] = Objects[i].Container; OldSlotNum[i] = Objects[i].ContainerSlot; Objects[i].PrePositionChange(context); } int Dir = 0; switch (direction) { case Direction.NORTH: Dir = 0; break; case Direction.EAST: Dir = 2; break; case Direction.SOUTH: Dir = 4; break; case Direction.WEST: Dir = 6; break; } Matrix rotMat = Matrix.CreateRotationZ((float)(Dir * Math.PI / 4.0)); VMPlacementResult[] places = new VMPlacementResult[Objects.Count]; var bObj = BaseObject; var leadOff = new Vector3(((sbyte)(((ushort)bObj.Object.OBJ.SubIndex) >> 8) * 16), ((sbyte)(((ushort)bObj.Object.OBJ.SubIndex) & 0xFF) * 16), 0); //TODO: optimize so we don't have to recalculate all of this if (pos != LotTilePos.OUT_OF_WORLD) { for (int i = 0; i < Objects.Count(); i++) { var sub = Objects[i]; var off = new Vector3((sbyte)(((ushort)sub.Object.OBJ.SubIndex) >> 8) * 16, (sbyte)(((ushort)sub.Object.OBJ.SubIndex) & 0xFF) * 16, 0); off = Vector3.Transform(off-leadOff, rotMat); var offPos = new LotTilePos((short)Math.Round(pos.x + off.X), (short)Math.Round(pos.y + off.Y), (sbyte)(pos.Level + sub.Object.OBJ.LevelOffset)); places[i] = sub.PositionValid(offPos, direction, context); if (places[i].Status != VMPlacementError.Success) { //go back to where we started: we're no longer out of world. for (int j = 0; j < Objects.Count(); j++) { //need to restore slot we were in if (OldContainers[j] != null) { OldContainers[j].PlaceInSlot(Objects[j], OldSlotNum[j], false, context); } Objects[j].PositionChange(context, false); } return places[i]; } } } //verification success for (int i = 0; i < Objects.Count(); i++) { var sub = Objects[i]; var off = new Vector3((sbyte)(((ushort)sub.Object.OBJ.SubIndex) >> 8) * 16, (sbyte)(((ushort)sub.Object.OBJ.SubIndex) & 0xFF)*16, 0); off = Vector3.Transform(off-leadOff, rotMat); var offPos = (pos==LotTilePos.OUT_OF_WORLD)? LotTilePos.OUT_OF_WORLD : new LotTilePos((short)Math.Round(pos.x + off.X), (short)Math.Round(pos.y + off.Y), (sbyte)(pos.Level+sub.Object.OBJ.LevelOffset)); sub.SetIndivPosition(offPos, direction, context, places[i]); } for (int i = 0; i < Objects.Count(); i++) Objects[i].PositionChange(context, false); return new VMPlacementResult(VMPlacementError.Success); }
public void UnregisterInvoker(VMEntity invoker) { if (invoker == null) return; InvokerToEOD.Remove(invoker.ObjectID); }
public bool RunInMyStack(BHAV bhav, GameObject CodeOwner, short[] passVars, VMEntity stackObj) { var OldStack = Stack; var OldQueue = Queue; 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>(); } if (Queue.Count > 0) { Queue = new List<VMQueuedAction>() { Queue[0] }; } else { Queue = new List<VMQueuedAction>(); } 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; while (Stack.Count > 0) { NextInstruction(); } //copy child stack things to parent stack //prevFrame.Args = frame.Args; //prevFrame.StackObject = frame.StackObject; Stack = OldStack; Queue = OldQueue; return (LastStackExitCode == VMPrimitiveExitCode.RETURN_TRUE) ? true : false; }
public VMThread(VMThreadMarshal input, VMContext context, VMEntity entity) { Context = context; Entity = entity; Load(input, context); }