public void ChangePosition(short x, short y, sbyte level, Direction direction, VMContext 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; } for (int i = 0; i < Objects.Count(); i++) { var sub = Objects[i]; var off = new Vector3((sbyte)(((ushort)sub.Object.OBJ.SubIndex) >> 8), (sbyte)(((ushort)sub.Object.OBJ.SubIndex) & 0xFF), 0); off = Vector3.Transform(off, Matrix.CreateRotationZ((float)(Dir * Math.PI / 4.0))); sub.Direction = direction; context.Blueprint.ChangeObjectLocation((ObjectComponent)sub.WorldUI, (short)Math.Round(x + off.X), (short)Math.Round(y + off.Y), (sbyte)level); } for (int i = 0; i < Objects.Count(); i++) Objects[i].PositionChange(context); }
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>(); }
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 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); }
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; }
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 Tick(VMAvatar avatar, VMContext context) { if (context.Clock.Minutes == LastMinute) return; LastMinute = context.Clock.Minutes; string category = "Skills"; string sleepState = (avatar.GetMotiveData(VMMotive.SleepState) == 0)?"Awake":"Asleep"; int moodSum = 0; for (int i = 0; i < 7; i++) { if (avatar.IsPet && i == 5) return; float lotMul = LotMotives.GetNum(category + "_" + LotMotiveNames[i] + "Weight"); float frac = 0; var motive = avatar.GetMotiveData(DecrementMotives[i]); var r_Hunger = (SimMotives.GetNum("HungerDecrementRatio") * (100+avatar.GetMotiveData(VMMotive.Hunger))) * LotMotives.GetNum(category+"_HungerWeight"); switch (i) { case 0: frac = r_Hunger; break; case 1: frac = (SimMotives.GetNum("ComfortDecrementActive") * lotMul); break; case 2: frac = (SimMotives.GetNum("HygieneDecrement" + sleepState) * lotMul); break; case 3: frac = (SimMotives.GetNum("BladderDecrement" + sleepState) * lotMul) + (SimMotives.GetNum("HungerToBladderMultiplier") * r_Hunger); break; case 4: frac = (SimMotives.GetNum("EnergySpan") / (60 * SimMotives.GetNum("WakeHours"))); // TODO: wrong but appears to be close? need one which uses energy weight, which is about 2.4 on skills break; case 5: frac = (sleepState == "Asleep") ? 0 : (SimMotives.GetNum("EntDecrementAwake") * lotMul); break; case 6: frac = (SimMotives.GetNum("SocialDecrementBase") + (SimMotives.GetNum("SocialDecrementMultiplier") * (100+motive))) * lotMul; frac /= 2; //make this less harsh right now, til I can work out how multiplayer bonus is meant to work break; } MotiveFractions[i] += (short)(frac * 1000); if (MotiveFractions[i] >= 1000) { motive -= (short)(MotiveFractions[i] / 1000); MotiveFractions[i] %= 1000; if (motive < -100) motive = -100; avatar.SetMotiveData(DecrementMotives[i], motive); } moodSum += motive; } avatar.SetMotiveData(VMMotive.Mood, (short)(moodSum / 7)); }
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; }
/// <summary> /// Renders the macro using the context /// </summary> public override bool Render(IInternalContextAdapter context, TextWriter writer, INode node) { try { // it's possible the tree hasn't been parsed yet, so get // the VMManager to parse and init it if (nodeTree != null) { if (!init) { nodeTree.Init(context, rsvc); init = true; } // wrap the current context and add the VMProxyArg objects VMContext vmc = new VMContext(context, rsvc); for(int i = 1; i < argArray.Length; i++) { // we can do this as VMProxyArgs don't change state. They change // the context. VMProxyArg arg = (VMProxyArg) proxyArgHash[argArray[i]]; vmc.AddVMProxyArg(arg); } // now render the VM nodeTree.Render(vmc, writer); } else { rsvc.Error("VM error : " + macroName + ". Null AST"); } } catch(Exception e) { // if it's a MIE, it came from the render.... throw it... if (e is MethodInvocationException) throw; rsvc.Error("VelocimacroProxy.render() : exception VM = #" + macroName + "() : " + e); } return true; }
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 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 virtual void Load(VMMultitileGroupMarshal input, VMContext context) { MultiTile = input.MultiTile; Objects = new List<VMEntity>(); foreach (var id in input.Objects) { var obj = context.VM.GetObjectById(id); Objects.Add(obj); obj.MultitileGroup = this; } }
public void Delete(VMContext context) { for (int i = 0; i < Objects.Count(); i++) { var obj = Objects[i]; obj.PrePositionChange(context); context.RemoveObjectInstance(obj); } }
public void ExecuteEntryPoint(int num, VMContext context) { for (int i = 0; i < Objects.Count; i++) Objects[i].ExecuteEntryPoint(num, context, true); }
public virtual void Load(VMThreadMarshal input, VMContext context) { Stack = new List<VMStackFrame>(); foreach (var item in input.Stack) { Stack.Add((item is VMRoutingFrameMarshal)? new VMRoutingFrame(item, context, this) : new VMStackFrame(item, context, this)); } Queue = new List<VMQueuedAction>(); foreach (var item in input.Queue) Queue.Add(new VMQueuedAction(item, context)); TempRegisters = input.TempRegisters; TempXL = input.TempXL; LastStackExitCode = input.LastStackExitCode; BlockingDialog = input.BlockingDialog; Interrupt = input.Interrupt; ActionUID = input.ActionUID; DialogCooldown = input.DialogCooldown; }
public VMThread(VMThreadMarshal input, VMContext context, VMEntity entity) { Context = context; Entity = entity; Load(input, context); }
public static VMPrimitiveExitCode EvaluateCheck(VMContext context, VMEntity entity, VMStackFrame initFrame, VMQueuedAction action) { return(EvaluateCheck(context, entity, initFrame, action, null)); }
public VMActionCallback(VMActionCallbackMarshal input, VMContext context) { Load(input, context); }
// 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; SLOTEnumerationFunction((x, y, distance) => { var pos = new Vector2(circleCtr.X + x / 16.0f, circleCtr.Y + y / 16.0f); if (distance >= MinProximity - 0.5 && distance <= MaxProximity + 0.5 && (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 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 }); }
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)((rotatedF > 4) ? (rotatedF * Math.PI / 4.0) : ((rotatedF - 8.0) * Math.PI / 4.0)); break; } } VMFindLocationResult result = new VMFindLocationResult { Position = new LotTilePos((short)Math.Round(pos.X * 16), (short)Math.Round(pos.Y * 16), obj.Position.Level), RadianDirection = facingDir, FaceAnywhere = faceAnywhere, RouteEntryFlags = entryFlags }; var avatarInWay = false; if (Slot.SnapTargetSlot < 0) { var solid = caller.PositionValid(tpos, Direction.NORTH, context, VMPlaceRequestFlags.AcceptSlots | VMPlaceRequestFlags.AllAvatarsSolid); if (solid.Status != VMPlacementError.Success) { if (solid.Object != null) { if (solid.Object is VMGameObject) { if (Slot.Sitting > 0 && solid.Object.EntryPoints[26].ActionFunction != 0) { result.Chair = solid.Object; } else { SetFail(VMRouteFailCode.DestTileOccupied, solid.Object); return; } } else { avatarInWay = true; } } } if (context.ObjectQueries.GetObjectsAt(tpos)?.Any( x => ((VMEntityFlags2)x.GetValue(VMStackObjectVariable.FlagField2) & VMEntityFlags2.ArchitectualDoor) > 0) ?? false) { avatarInWay = true; //prefer not standing in front of a door. (todo: merge with above check?) } if (result.Chair != null && (Math.Abs(DirectionUtils.Difference(result.Chair.RadianDirection, facingDir)) > Math.PI / 4)) { return; //not a valid goal. } if (result.Chair == null && OnlySit) { return; } score = score * ((result.Chair != null) ? Slot.Sitting : Slot.Standing); //if an avatar is in or going to our destination positon, we this spot becomes low priority as getting into it will require a shoo. if (!avatarInWay) { foreach (var avatar in context.ObjectQueries.Avatars) { if (avatar == caller) { continue; } //search for routing frame. is its destination the same as ours? if (avatar.Thread != null) { var intersects = avatar.Thread.Stack.Any(x => x is VMRoutingFrame && ((VMRoutingFrame)x).IntersectsOurDestination(result)); if (intersects) { score = score / 100000; break; } } } } else { score = score / 100000; } } result.Score = score; Results.Add(result); }
public VMFindLocationResult(VMFindLocationResultMarshal input, VMContext context) { Load(input, context); }
public void Tick(VMAvatar avatar, VMContext context) { if (context.Clock.Minutes == LastMinute) { return; } LastMinute = context.Clock.Minutes; string category = "Skills"; string sleepState = (avatar.GetMotiveData(VMMotive.SleepState) == 0)?"Awake":"Asleep"; int moodSum = 0; for (int i = 0; i < 7; i++) { float lotMul = LotMotives.GetNum(category + "_" + LotMotiveNames[i] + "Weight"); float frac = 0; var motive = avatar.GetMotiveData(DecrementMotives[i]); var r_Hunger = (SimMotives.GetNum("HungerDecrementRatio") * (100 + avatar.GetMotiveData(VMMotive.Hunger))) * LotMotives.GetNum(category + "_HungerWeight"); switch (i) { case 0: frac = r_Hunger; break; case 1: frac = (SimMotives.GetNum("ComfortDecrementActive") * lotMul); break; case 2: frac = (SimMotives.GetNum("HygieneDecrement" + sleepState) * lotMul); break; case 3: frac = (SimMotives.GetNum("BladderDecrement" + sleepState) * lotMul) + (SimMotives.GetNum("HungerToBladderMultiplier") * r_Hunger); break; case 4: frac = (SimMotives.GetNum("EnergySpan") / (60 * SimMotives.GetNum("WakeHours"))); // TODO: wrong but appears to be close? need one which uses energy weight, which is about 2.4 on skills break; case 5: frac = (sleepState == "Asleep") ? 0 : (SimMotives.GetNum("EntDecrementAwake") * lotMul); break; case 6: frac = (SimMotives.GetNum("SocialDecrementBase") + (SimMotives.GetNum("SocialDecrementMultiplier") * (100 + motive))) * lotMul; frac /= 2; //make this less harsh right now, til I can work out how multiplayer bonus is meant to work break; } MotiveFractions[i] += (short)(frac * 1000); if (MotiveFractions[i] >= 1000) { motive -= (short)(MotiveFractions[i] / 1000); MotiveFractions[i] %= 1000; if (motive < -100) { motive = -100; } avatar.SetMotiveData(DecrementMotives[i], motive); } moodSum += motive; } avatar.SetMotiveData(VMMotive.Mood, (short)(moodSum / 7)); }
public VMQueuedAction(VMQueuedActionMarshal input, VMContext context) { Load(input, context); }
public VMMultitileGroup(VMMultitileGroupMarshal input, VMContext context) { Load(input, context); }
public override void Update(UpdateState state) { base.Update(state); if (TempVM == null && GUID != 0) { var world = new ExternalWorld(GameFacade.GraphicsDevice); world.Initialize(GameFacade.Scenes); var context = new VMContext(world); TempVM = new VM(context, new VMServerDriver(new VMTSOGlobalLinkStub()), new VMNullHeadlineProvider()); TempVM.Init(); var blueprint = new Blueprint(32, 32); blueprint.Light = new RoomLighting[] { new RoomLighting() { OutsideLight = 100 }, new RoomLighting() { OutsideLight = 100 }, new RoomLighting() { OutsideLight = 100 }, }; blueprint.OutsideColor = Color.White; blueprint.GenerateRoomLights(); blueprint.RoomColors[2].A /= 2; world.State.AmbientLight.SetData(blueprint.RoomColors); world.State.OutsidePx.SetData(new Color[] { Color.White }); world.InitBlueprint(blueprint); context.Blueprint = blueprint; context.Architecture = new VMArchitecture(1, 1, blueprint, TempVM.Context); } if (GUID != oldGUID) { SetGUIDLocal(GUID, TempVM); state.SharedData["ExternalDraw"] = true; } if (ForceRedraw) { state.SharedData["ExternalDraw"] = true; ForceRedraw = false; } if (TempVM != null) { var lcount = TempVM.Scheduler.CurrentTickID; TempVM.Update(); var count = TempVM.Scheduler.CurrentTickID; foreach (var ent in TempVM.Entities) { if (ent is VMAvatar) { for (uint i = lcount; i < count; i++) { ent.Tick(); } } } TempVM.PreDraw(); } }
private bool SetPosition(VMEntity entity, LotTilePos pos, float radDir, bool shooAva, VMContext context) { var posChange = entity.SetPosition(pos, (Direction)(1 << (int)(Math.Round(DirectionUtils.PosMod(radDir, (float)Math.PI * 2) / (Math.PI / 4)) % 8)), context); if (posChange.Status != VMPlacementError.Success) { if (shooAva && posChange.Object != null && posChange.Object is VMAvatar) { if (!posChange.Object.Thread.Queue.Any(x => x.Callee != null && x.Callee.Object.GUID == GOTO_GUID && x.InteractionNumber == SHOO_INTERACTION)) { //push shoo if not already being shooed VMEntity callee = context.VM.Context.CreateObjectInstance(GOTO_GUID, new LotTilePos(posChange.Object.Position), Direction.NORTH).Objects[0]; callee.PushUserInteraction(SHOO_INTERACTION, posChange.Object, context.VM.Context, false); } } if (posChange.Status == VMPlacementError.LocationOutOfBounds) { entity.SetValue(VMStackObjectVariable.PrimitiveResult, 2); } entity.SetValue(VMStackObjectVariable.PrimitiveResultID, (posChange.Object == null) ? (short)0 : posChange.Object.ObjectID); return(false); } if (entity is VMAvatar) { entity.RadianDirection = radDir; } return(true); }
private bool SetPosition(VMEntity entity, LotTilePos pos, Direction dir, bool shooAva, VMContext context) { return(SetPosition(entity, pos, (float)(Math.Round(Math.Log((double)dir, 2)) * (Math.PI / 4)), shooAva, context)); }
public VMStackFrame(VMStackFrameMarshal input, VMContext context, VMThread thread) { Thread = thread; Load(input, context); }
public List <VMObstacle> GenerateRoomObs(ushort room, sbyte level, Rectangle bounds, VMContext context) { var result = new List <VMObstacle>(); if (room == 0) { bounds = new Rectangle(1, 1, Width - 2, Height - 2); } var x1 = Math.Max(0, bounds.X - 1); var x2 = Math.Min(Width, bounds.Right + 1); var y1 = Math.Max(0, bounds.Y - 1); var y2 = Math.Min(Height, bounds.Bottom + 1); for (int y = y1; y < y2; y++) { VMObstacle next = null; for (int x = x1; x < x2; x++) { uint tRoom = Map[x + y * Width]; if ((ushort)tRoom != room && ((tRoom >> 16) & 0x7FFF) != room) { //is there a door on this tile? var door = (context.ObjectQueries.GetObjectsAt(LotTilePos.FromBigTile((short)x, (short)y, level))?.FirstOrDefault( o => ((VMEntityFlags2)(o.GetValue(VMStackObjectVariable.FlagField2)) & VMEntityFlags2.ArchitectualDoor) > 0) ); if (door != null) { //ok... is is a portal to this room? block all sides that are not a portal to this room var otherSide = door.MultitileGroup.Objects.FirstOrDefault(o => context.GetObjectRoom(o) == room && o.EntryPoints[15].ActionFunction != 0); if (otherSide != null) { //make a hole for this door if (next != null) { next = null; } // note: the sims 1 stops here. this creates issues where sims can walk through doors in some circumstance // eg. two doors back to back into the same room. The sim will not perform a room route to the middle room, they will just walk through the door. // like, through it. This also works for pools but some additional rules prevent you from doing anything too silly. // we want to create 1 unit thick walls blocking each non-portal side. // todo: fix for this continue; } } if (next != null) { next.x2 += 16; } else { next = new VMObstacle((x << 4) - 3, (y << 4) - 3, (x << 4) + 19, (y << 4) + 19); result.Add(next); } } else { if (next != null) { next = null; } } } } OptimizeObstacles(result); return(result); }
public void Run(VMContext ctx, out ExecutionState state) { state = ExecutionState.Exit; }
/// <summary> /// Generates the room map for the specified walls array. /// </summary> public void GenerateMap(WallTile[] Walls, FloorTile[] Floors, int width, int height, List <VMRoom> rooms, sbyte floor, VMContext context) //for first floor gen, curRoom should be 1. For floors above, it should be the last genmap result { Map = new uint[width * height]; //although 0 is the base of the array, room 1 is known to simantics as room 0. //values of 0 indicate the room has not been chosen in that location yet. bool noFloorBad = (rooms.Count > 1); this.Width = width; this.Height = height; //flood fill recursively. Each time choose find and choose the first "0" as the base. //The first recursion (outside) cannot fill into diagonals. bool remaining = true; bool outside = true; int i = 0; while (remaining) { var spread = new Stack <SpreadItem>(); remaining = false; while (i < Map.Length) { remaining = true; //get the wall on this tile. var wall = Walls[i]; var segs = wall.Segments; var room = (uint)rooms.Count; if (Map[i] == 0 && (segs & (WallSegments.AnyDiag)) == 0) { //normal tile - no diagonal ExpectedTile = Floors[i].Pattern; Map[i] = room | (room << 16); spread.Push(new SpreadItem(new Point(i % width, i / width), WallSegments.AnyAdj)); break; } else if ((Map[i] & 0xFFFF) == 0) { //start spreading from this side of the diagonal WallSegments validSpread; if ((segs & WallSegments.HorizontalDiag) > 0) { validSpread = WallSegments.TopLeft | WallSegments.TopRight; ExpectedTile = wall.TopLeftStyle; Map[i] |= 0x80000000; } else { validSpread = WallSegments.TopRight | WallSegments.BottomRight; ExpectedTile = wall.TopLeftPattern; } Map[i] |= room; spread.Push(new SpreadItem(new Point(i % width, i / width), validSpread)); break; } else if ((Map[i] & 0x7FFF0000) == 0) { //start spreading the other side WallSegments validSpread; if ((segs & WallSegments.HorizontalDiag) > 0) { validSpread = WallSegments.BottomLeft | WallSegments.BottomRight; ExpectedTile = wall.TopLeftPattern; Map[i] |= 0x80000000; } else { validSpread = WallSegments.TopLeft | WallSegments.BottomLeft; ExpectedTile = wall.TopLeftStyle; } Map[i] |= (room << 16); spread.Push(new SpreadItem(new Point(i % width, i / width), validSpread)); i++; break; } else { remaining = false; } i++; } if (remaining) { int rminX = spread.Peek().Pt.X; int rmaxX = rminX; int rminY = spread.Peek().Pt.Y; int rmaxY = rminY; var wallObs = new List <VMObstacle>(); var wallLines = (VM.UseWorld)?new VMWallLineBuilder():null; var fenceLines = (VM.UseWorld) ? new VMWallLineBuilder() : null; var wallDict = new Dictionary <uint, Vector2[]>(); var adjRooms = new HashSet <ushort>(); ushort area = 0; while (spread.Count > 0) { area++; var itemT = spread.Pop(); var item = itemT.Pt; if (item.X > rmaxX) { rmaxX = item.X; } if (item.X < rminX) { rminX = item.X; } if (item.Y > rmaxY) { rmaxY = item.Y; } if (item.Y < rminY) { rminY = item.Y; } var plusX = (item.X + 1) % width; var minX = (item.X + width - 1) % width; var plusY = (item.Y + 1) % height; var minY = (item.Y + height - 1) % height; var mainWalls = Walls[item.X + item.Y * width]; int obsX = item.X << 4; int obsY = item.Y << 4; if ((mainWalls.Segments & WallSegments.HorizontalDiag) > 0) { wallObs.Add(new VMObstacle(obsX + 11, obsY - 1, obsX + 17, obsY + 5)); wallObs.Add(new VMObstacle(obsX + 7, obsY + 3, obsX + 13, obsY + 9)); wallObs.Add(new VMObstacle(obsX + 3, obsY + 7, obsX + 9, obsY + 13)); wallObs.Add(new VMObstacle(obsX - 1, obsY + 11, obsX + 5, obsY + 17)); if (mainWalls.TopRightStyle == 1) { wallLines?.AddLine(obsX, obsY, 2); } else { fenceLines?.AddLine(obsX, obsY, 2); } } if ((mainWalls.Segments & WallSegments.VerticalDiag) > 0) { wallObs.Add(new VMObstacle(obsX - 1, obsY - 1, obsX + 5, obsY + 5)); wallObs.Add(new VMObstacle(obsX + 3, obsY + 3, obsX + 9, obsY + 9)); wallObs.Add(new VMObstacle(obsX + 7, obsY + 7, obsX + 13, obsY + 13)); wallObs.Add(new VMObstacle(obsX + 11, obsY + 11, obsX + 17, obsY + 17)); if (mainWalls.TopRightStyle == 1) { wallLines?.AddLine(obsX, obsY, 3); } else { fenceLines?.AddLine(obsX, obsY, 3); } } var PXWalls = Walls[plusX + item.Y * width]; var PYWalls = Walls[item.X + plusY * width]; if ((mainWalls.Segments & WallSegments.TopLeft) > 0) { if (!mainWalls.TopLeftDoor) { wallObs.Add(new VMObstacle(obsX - 3, obsY - 3, obsX + 6, obsY + 19)); } if (mainWalls.TopLeftThick) { wallLines?.AddLine(obsX, obsY, 0); } else { fenceLines?.AddLine(obsX, obsY, 0); } } if ((mainWalls.Segments & WallSegments.TopRight) > 0) { if (!mainWalls.TopRightDoor) { wallObs.Add(new VMObstacle(obsX - 3, obsY - 3, obsX + 19, obsY + 6)); } if (mainWalls.TopRightThick) { wallLines?.AddLine(obsX, obsY, 1); } else { fenceLines?.AddLine(obsX, obsY, 1); } } if ((mainWalls.Segments & WallSegments.BottomLeft) > 0) { if (!PYWalls.TopRightDoor) { wallObs.Add(new VMObstacle(obsX - 3, obsY + 13, obsX + 19, obsY + 19)); } if (PYWalls.TopRightThick) { wallLines?.AddLine(obsX, obsY + 16, 1); } else { fenceLines?.AddLine(obsX, obsY + 16, 1); } } if ((mainWalls.Segments & WallSegments.BottomRight) > 0) { if (!PXWalls.TopLeftDoor) { wallObs.Add(new VMObstacle(obsX + 13, obsY - 3, obsX + 19, obsY + 19)); } if (PXWalls.TopLeftThick) { wallLines?.AddLine(obsX + 16, obsY, 0); } else { fenceLines?.AddLine(obsX + 16, obsY, 0); } } bool segAllow = ((PXWalls.Segments & WallSegments.TopLeft) == 0); if ((segAllow || PXWalls.TopLeftStyle != 1) && ((itemT.Dir & WallSegments.BottomRight) > 0)) { SpreadOnto(Walls, Floors, plusX, item.Y, 0, Map, width, height, spread, (ushort)rooms.Count, ExpectedTile, noFloorBad, adjRooms, !segAllow); } segAllow = ((mainWalls.Segments & WallSegments.TopLeft) == 0); if ((segAllow || mainWalls.TopLeftStyle != 1) && ((itemT.Dir & WallSegments.TopLeft) > 0)) { SpreadOnto(Walls, Floors, minX, item.Y, 2, Map, width, height, spread, (ushort)rooms.Count, ExpectedTile, noFloorBad, adjRooms, !segAllow); } segAllow = ((PYWalls.Segments & WallSegments.TopRight) == 0); if ((segAllow || PYWalls.TopRightStyle != 1) && ((itemT.Dir & WallSegments.BottomLeft) > 0)) { SpreadOnto(Walls, Floors, item.X, plusY, 1, Map, width, height, spread, (ushort)rooms.Count, ExpectedTile, noFloorBad, adjRooms, !segAllow); } segAllow = ((mainWalls.Segments & WallSegments.TopRight) == 0); if ((segAllow || mainWalls.TopRightStyle != 1) && ((itemT.Dir & WallSegments.TopRight) > 0)) { SpreadOnto(Walls, Floors, item.X, minY, 3, Map, width, height, spread, (ushort)rooms.Count, ExpectedTile, noFloorBad, adjRooms, !segAllow); } } var bounds = new Rectangle(rminX, rminY, (rmaxX - rminX) + 1, (rmaxY - rminY) + 1); var roomObs = GenerateRoomObs((ushort)rooms.Count, (sbyte)(floor + 1), bounds, context); OptimizeObstacles(wallObs); OptimizeObstacles(roomObs); var supportRooms = new List <ushort>(); ushort myRoom = (ushort)rooms.Count; ushort minRoom = myRoom; bool deferredLit = false; foreach (var roomN in adjRooms) { var room = rooms[roomN]; if (minRoom > room.LightBaseRoom) { deferredLit = true; minRoom = room.LightBaseRoom; } room.AdjRooms.Add(myRoom); if (outside) { MakeOutside(rooms, room); } else if (room.IsOutside) { outside = true; } } if (deferredLit) { rooms[minRoom].SupportRooms.Add(myRoom); } else { supportRooms.Add(myRoom); } if (VM.UseWorld && minRoom != rooms.Count) { rooms[minRoom].WallLines.AddRange(wallLines.Lines); rooms[minRoom].FenceLines.AddRange(fenceLines.Lines); } rooms.Add(new VMRoom { IsOutside = outside, IsPool = ExpectedTile > 65533, Bounds = bounds, WallObs = wallObs, RoomObs = roomObs, WallLines = (deferredLit) ? null : wallLines?.Lines, FenceLines = (deferredLit) ? null : fenceLines?.Lines, AdjRooms = adjRooms, RoomID = myRoom, LightBaseRoom = minRoom, Area = area, Floor = floor, SupportRooms = supportRooms }); foreach (var roomN in adjRooms) { var room = rooms[roomN]; TrySwitchBaseRoom(rooms, room, minRoom); } outside = false; } } }
public void Load(VMQueuedActionMarshal input, VMContext context) { CodeOwner = FSO.Content.Content.Get().WorldObjects.Get(input.CodeOwnerGUID); BHAV bhav = null; if (input.RoutineID >= 8192) bhav = CodeOwner.Resource.SemiGlobal.Get<BHAV>(input.RoutineID); else if (input.RoutineID >= 4096) bhav = CodeOwner.Resource.Get<BHAV>(input.RoutineID); else bhav = context.Globals.Resource.Get<BHAV>(input.RoutineID); ActionRoutine = context.VM.Assemble(bhav); if (input.CheckRoutineID != 0) { if (input.CheckRoutineID >= 8192) bhav = CodeOwner.Resource.SemiGlobal.Get<BHAV>(input.CheckRoutineID); else if (input.CheckRoutineID >= 4096) bhav = CodeOwner.Resource.Get<BHAV>(input.CheckRoutineID); else bhav = context.Globals.Resource.Get<BHAV>(input.CheckRoutineID); CheckRoutine = context.VM.Assemble(bhav); } Callee = context.VM.GetObjectById(input.Callee); StackObject = context.VM.GetObjectById(input.StackObject); IconOwner = context.VM.GetObjectById(input.IconOwner); Name = input.Name; Args = input.Args; InteractionNumber = input.InteractionNumber; Cancelled = input.Cancelled; Priority = input.Priority; Mode = input.Mode; Flags = input.Flags; Flags2 = input.Flags2; UID = input.UID; Callback = (input.Callback == null)?null:new VMActionCallback(input.Callback, context); }
public VMObjectQueries(VMContext context) { Context = context; }
static void Main(string[] args) { FSO.Windows.Program.InitWindows(); TimedReferenceController.SetMode(CacheType.PERMANENT); Console.WriteLine("Loading Config..."); try { var configString = File.ReadAllText("facadeconfig.json"); Config = Newtonsoft.Json.JsonConvert.DeserializeObject <FacadeConfig>(configString); } catch (Exception e) { Console.WriteLine("Could not find configuration file 'facadeconfig.json'. Please ensure it is valid and present in the same folder as this executable."); return; } Console.WriteLine("Locating The Sims Online..."); string baseDir = AppDomain.CurrentDomain.BaseDirectory; Directory.SetCurrentDirectory(baseDir); //Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException); OperatingSystem os = Environment.OSVersion; PlatformID pid = os.Platform; ILocator gameLocator; bool linux = pid == PlatformID.MacOSX || pid == PlatformID.Unix; if (linux && Directory.Exists("/Users")) { gameLocator = new MacOSLocator(); } else if (linux) { gameLocator = new LinuxLocator(); } else { gameLocator = new WindowsLocator(); } bool useDX = true; FSOEnvironment.Enable3D = true; GraphicsModeControl.ChangeMode(FSO.LotView.Model.GlobalGraphicsMode.Full3D); GameThread.NoGame = true; GameThread.UpdateExecuting = true; var path = gameLocator.FindTheSimsOnline(); if (path != null) { FSOEnvironment.ContentDir = "Content/"; FSOEnvironment.GFXContentDir = "Content/" + (useDX ? "DX/" : "OGL/"); FSOEnvironment.Linux = linux; FSOEnvironment.DirectX = useDX; FSOEnvironment.TexCompress = FSOEnvironment.TexCompressSupport; FSOEnvironment.GameThread = Thread.CurrentThread; FSO.HIT.HITVM.Init(); FSO.HIT.HITVM.Get().SetMasterVolume(FSO.HIT.Model.HITVolumeGroup.AMBIENCE, 0); FSO.HIT.HITVM.Get().SetMasterVolume(FSO.HIT.Model.HITVolumeGroup.FX, 0); FSO.HIT.HITVM.Get().SetMasterVolume(FSO.HIT.Model.HITVolumeGroup.MUSIC, 0); FSO.HIT.HITVM.Get().SetMasterVolume(FSO.HIT.Model.HITVolumeGroup.VOX, 0); FSO.Files.Formats.IFF.Chunks.STR.DefaultLangCode = FSO.Files.Formats.IFF.Chunks.STRLangCode.EnglishUS; } Console.WriteLine("Creating Graphics Device..."); var gds = new GraphicsDeviceServiceMock(); var gd = gds.GraphicsDevice; //set up some extra stuff like the content manager var services = new GameServiceContainer(); var content = new ContentManager(services); content.RootDirectory = FSOEnvironment.GFXContentDir; services.AddService <IGraphicsDeviceService>(gds); var vitaboyEffect = content.Load <Effect>("Effects/Vitaboy"); FSO.Vitaboy.Avatar.setVitaboyEffect(vitaboyEffect); WorldConfig.Current = new WorldConfig() { LightingMode = 3, SmoothZoom = true, SurroundingLots = 0 }; DGRP3DMesh.Sync = true; Console.WriteLine("Looks like that worked. Loading FSO Content!"); VMContext.InitVMConfig(false); Content.Init(path, gd); WorldContent.Init(services, content.RootDirectory); VMAmbientSound.ForceDisable = true; Layer = new _3DLayer(); Layer.Initialize(gd); GD = gd; if (args.FirstOrDefault() == "debug") { DebugLot = uint.Parse(args[1]); } Console.WriteLine("Starting Worker Loop!"); WorkerLoop(); Console.WriteLine("Exiting."); GameThread.SetKilled(); gds.Release(); }
public int Run() { LOG.Info("Starting server"); TimedReferenceController.SetMode(CacheType.PERMANENT); if (Config.Services == null) { LOG.Warn("No services found in the configuration file, exiting"); return(1); } if (!Directory.Exists(Config.GameLocation)) { LOG.Fatal("The directory specified as gameLocation in config.json does not exist"); return(1); } Directory.CreateDirectory(Config.SimNFS); Directory.CreateDirectory(Path.Combine(Config.SimNFS, "Lots/")); Directory.CreateDirectory(Path.Combine(Config.SimNFS, "Objects/")); Content.Model.AbstractTextureRef.ImageFetchFunction = Utils.SoftwareImageLoader.SoftImageFetch; //TODO: Some content preloading LOG.Info("Scanning content"); Content.GameContent.Init(Config.GameLocation, Content.ContentMode.SERVER); Kernel.Bind <Content.GameContent>().ToConstant(Content.GameContent.Get); VMContext.InitVMConfig(); Kernel.Bind <MemoryCache>().ToConstant(new MemoryCache("fso_server")); LOG.Info("Loading domain logic"); Kernel.Load <ServerDomainModule>(); Servers = new List <AbstractServer>(); CityServers = new List <CityServer>(); Kernel.Bind <IServerNFSProvider>().ToConstant(new ServerNFSProvider(Config.SimNFS)); if (Config.Services.UserApi != null && Config.Services.UserApi.Enabled) { var childKernel = new ChildKernel( Kernel ); var api = new UserApi(Config, childKernel); ActiveUApiServer = api; Servers.Add(api); api.OnRequestShutdown += RequestedShutdown; api.OnBroadcastMessage += BroadcastMessage; api.OnRequestUserDisconnect += RequestedUserDisconnect; api.OnRequestMailNotify += RequestedMailNotify; } foreach (var cityServer in Config.Services.Cities) { /** * Need to create a kernel for each city server as there is some data they do not share */ var childKernel = new ChildKernel( Kernel, new ShardDataServiceModule(Config.SimNFS), new CityServerModule() ); var city = childKernel.Get <CityServer>(new ConstructorArgument("config", cityServer)); CityServers.Add(city); Servers.Add(city); } foreach (var lotServer in Config.Services.Lots) { if (lotServer.SimNFS == null) { lotServer.SimNFS = Config.SimNFS; } var childKernel = new ChildKernel( Kernel, new LotServerModule() ); Servers.Add( childKernel.Get <LotServer>(new ConstructorArgument("config", lotServer)) ); } if (Config.Services.Tasks != null && Config.Services.Tasks.Enabled) { var childKernel = new ChildKernel( Kernel, new TaskEngineModule() ); childKernel.Bind <TaskServerConfiguration>().ToConstant(Config.Services.Tasks); childKernel.Bind <TaskTuning>().ToConstant(Config.Services.Tasks.Tuning); var tasks = childKernel.Get <TaskServer>(new ConstructorArgument("config", Config.Services.Tasks)); Servers.Add(tasks); ActiveTaskServer = tasks; Server.Servers.Tasks.Domain.ShutdownTask.ShutdownHook = RequestedShutdown; } foreach (var server in Servers) { server.OnInternalShutdown += ServerInternalShutdown; } Running = true; AppDomain.CurrentDomain.DomainUnload += CurrentDomain_DomainUnload; AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit; /* * NetworkDebugger debugInterface = null; * * if (Options.Debug) * { * debugInterface = new NetworkDebugger(Kernel); * foreach (AbstractServer server in Servers) * { * server.AttachDebugger(debugInterface); * } * } */ LOG.Info("Starting services"); foreach (var server in Servers) { server.Start(); } HostPool.Start(); //Hacky reference to maek sure the assembly is included FSO.Common.DatabaseService.Model.LoadAvatarByIDRequest x; /*if (debugInterface != null) * { * Application.EnableVisualStyles(); * Application.Run(debugInterface); * } * else*/ { while (Running) { Thread.Sleep(1000); lock (Servers) { if (Servers.Count == 0) { LOG.Info("All servers shut down, shutting down program..."); Kernel.Get <IGluonHostPool>().Stop(); /*var domain = AppDomain.CreateDomain("RebootApp"); * * var assembly = "FSO.Server.Updater, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"; * var type = "FSO.Server.Updater.Program"; * * var updater = typeof(FSO.Server.Updater.Program); * * domain.CreateInstance(assembly, type); * AppDomain.Unload(AppDomain.CurrentDomain);*/ return(2 + (int)ShutdownMode); } } } } return(1); }
public void Delete(VMContext context) { while (Objects.Count > 0) { var obj = Objects[0]; obj.Delete(false, context); } }
public void Tick(VMAvatar avatar, VMContext context) { var roomScore = context.GetRoomScore(context.GetRoomAt(avatar.Position)); avatar.SetMotiveData(VMMotive.Room, roomScore); if (context.Clock.Minutes == LastMinute) { return; } if (avatar.GetPersonData(VMPersonDataVariable.Cheats) > 0) { return; } LastMinute = context.Clock.Minutes; UpdateCategory(context); int sleepState = (avatar.GetMotiveData(VMMotive.SleepState) == 0)?1:0; int moodSum = 0; for (int i = 0; i < 7; i++) { int lotMul = LotMuls[i]; int frac = 0; var motive = avatar.GetMotiveData(DecrementMotives[i]); var r_Hunger = FracMul(FlatSimMotives[0] * (100 + avatar.GetMotiveData(VMMotive.Hunger)), LotMuls[0]); switch (i) { case 0: frac = r_Hunger; break; case 1: frac = FracMul(FlatSimMotives[1], lotMul); break; case 2: frac = FracMul(FlatSimMotives[2 + sleepState], lotMul); break; case 3: frac = FracMul(FlatSimMotives[4 + sleepState], lotMul) + FracMul(r_Hunger, FlatSimMotives[6]); break; case 4: frac = (FlatSimMotives[7] / (60 * FlatSimMotives[8])); // TODO: wrong but appears to be close? need one which uses energy weight, which is about 2.4 on skills break; case 5: frac = (sleepState == 0) ? 0 : FracMul(FlatSimMotives[9], lotMul); break; case 6: frac = FlatSimMotives[10] + FracMul((FlatSimMotives[11] * (100 + motive)), lotMul); frac /= 2; //make this less harsh right now, til I can work out how multiplayer bonus is meant to work break; } MotiveFractions[i] += (short)frac; if (MotiveFractions[i] >= 1000) { motive -= (short)(MotiveFractions[i] / 1000); MotiveFractions[i] %= 1000; if (motive < -100) { motive = -100; } avatar.SetMotiveData(DecrementMotives[i], motive); } moodSum += motive; } moodSum += roomScore; avatar.SetMotiveData(VMMotive.Mood, (short)(moodSum / 8)); }
public void Init(VMContext context) { for (int i = 0; i < Objects.Count(); i++) { Objects[i].Init(context); } }
public static VMPrimitiveExitCode EvaluateCheck(VMContext context, VMEntity entity, VMStackFrame initFrame) { return EvaluateCheck(context, entity, initFrame, null, null); }
public void SetVisualPosition(Vector3 pos, Direction direction, VMContext 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)); var bObj = BaseObject; var leadOff = new Vector3((sbyte)(((ushort)bObj.Object.OBJ.SubIndex) >> 8), (sbyte)(((ushort)bObj.Object.OBJ.SubIndex) & 0xFF), 0); for (int i = 0; i < Objects.Count(); i++) { var sub = Objects[i]; var off = new Vector3((sbyte)(((ushort)sub.Object.OBJ.SubIndex) >> 8), (sbyte)(((ushort)sub.Object.OBJ.SubIndex) & 0xFF), sub.Object.OBJ.LevelOffset*2.95f); off = Vector3.Transform(off-leadOff, rotMat); sub.Direction = direction; sub.VisualPosition = pos + off; } }
public static VMPrimitiveExitCode EvaluateCheck(VMContext context, VMEntity entity, VMStackFrame initFrame, VMQueuedAction action) { return EvaluateCheck(context, entity, initFrame, action, null); }
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); }
// 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 vTree_NodeMouseUp(object sender, vTreeViewMouseEventArgs e) { switch (e.Node.Depth) { case 0: ClearDateCallback(); break; case 1: ClearDateCallback(); if (e.Node.Nodes.Count != 0) { break; } using (VMContext VMContext = new VMContext()) { IQueryable <DataFile> source = VMContext.DataFiles.Where(dataFile => dataFile.AccountId == AccountID); Expression <Func <DataFile, int> > selector = dataFile => dataFile.FileAddedTimestamp.Value.Year; using (List <int> .Enumerator enumerator = source.Select(selector).Distinct().ToList().GetEnumerator()) { while (enumerator.MoveNext()) { int current = enumerator.Current; e.Node.Nodes.Add(new vTreeNode(string.Format("{0}", current)) { ImageIndex = 2, Tag = current }); } break; } } case 2: ClearDateCallback(); if (e.Node.Nodes.Count != 0) { break; } AccountID = (Guid)e.Node.Parent.Tag; YEAR = (int)e.Node.Tag; using (VMContext VMContext = new VMContext()) { IQueryable <DataFile> source = VMContext.DataFiles.Where(dataFile => dataFile.AccountId == AccountID && dataFile.FileAddedTimestamp.Value.Year == YEAR && dataFile.IsPurged == false); Expression <Func <DataFile, int> > selector = dataFile => dataFile.FileAddedTimestamp.Value.Month; using (List <int> .Enumerator enumerator = source.Select(selector).Distinct().ToList().GetEnumerator()) { while (enumerator.MoveNext()) { int current = enumerator.Current; e.Node.Nodes.Add(new vTreeNode(string.Format("{0}", Months[current - 1])) { ImageIndex = 3, Tag = current }); } break; } } case 3: ClearDateCallback(); if (e.Node.Nodes.Count != 0) { break; } vTreeNode parent1 = e.Node.Parent; YEAR = (int)parent1.Tag; AccountID = (Guid)parent1.Parent.Tag; MONTH = (int)e.Node.Tag; using (VMContext VMContext = new VMContext()) { IQueryable <DataFile> source = VMContext.DataFiles.Where(dataFile => dataFile.AccountId == AccountID && dataFile.FileAddedTimestamp.Value.Year == YEAR && dataFile.FileAddedTimestamp.Value.Month == MONTH && dataFile.IsPurged == false); Expression <Func <DataFile, int> > selector = dataFile => dataFile.FileAddedTimestamp.Value.Day; using (List <int> .Enumerator enumerator = source.Select(selector).Distinct().ToList().GetEnumerator()) { while (enumerator.MoveNext()) { int current = enumerator.Current; DayOfWeek dayOfWeek = new DateTime(YEAR, MONTH, current).DayOfWeek; e.Node.Nodes.Add(new vTreeNode(string.Format("{0} • {1}", current, dayOfWeek)) { ImageIndex = 4, Tag = current }); } break; } } case 4: vTreeNode parent2 = e.Node.Parent; MONTH = (int)parent2.Tag; vTreeNode parent3 = parent2.Parent; YEAR = (int)parent3.Tag; AccountID = (Guid)parent3.Parent.Tag; int tag = (int)e.Node.Tag; if (tag <= 0 || tag > 31) { break; } Callback(new DateTime(YEAR, MONTH, tag, 0, 0, 0)); break; } }
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 void ChangePosition(short x, short y, sbyte level, Direction direction, VMContext 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; } for (int i = 0; i < Objects.Count(); i++) { var sub = Objects[i]; var off = new Vector3((sbyte)(((ushort)sub.Object.OBJ.SubIndex) >> 8), (sbyte)(((ushort)sub.Object.OBJ.SubIndex) & 0xFF), 0); off = Vector3.Transform(off, Matrix.CreateRotationZ((float)(Dir * Math.PI / 4.0))); sub.Direction = direction; context.Blueprint.ChangeObjectLocation((ObjectComponent)sub.WorldUI, (short)Math.Round(x + off.X), (short)Math.Round(y + off.Y), (sbyte)level); } for (int i = 0; i < Objects.Count(); i++) { Objects[i].PositionChange(context); } }
public void Tick(VMAvatar avatar, VMContext context) { var roomScore = context.GetRoomScore(context.GetRoomAt(avatar.Position)); avatar.SetMotiveData(VMMotive.Room, roomScore); if (context.Clock.Minutes / 2 == LastMinute || avatar.GetValue(VMStackObjectVariable.Hidden) > 0) { return; } LastMinute = context.Clock.Minutes / 2; var sleeping = (avatar.GetMotiveData(VMMotive.SleepState) != 0); int moodSum = 0; for (int i = 0; i < 7; i++) { int frac = 0; var dm = DecrementMotives[i]; if (avatar.HasMotiveChange(dm) && dm != VMMotive.Energy) { continue; } var motive = avatar.GetMotiveData(dm); var r_Hunger = ToFixed1000(Constants[5]) * (100 + avatar.GetMotiveData(VMMotive.Hunger)); switch (i) { case 0: frac = r_Hunger; break; case 1: var active = avatar.GetPersonData(VMPersonDataVariable.ActivePersonality); if (active > 666) { frac = ToFixed1000(Constants[14]); } else if (active < 666) { frac = ToFixed1000(Constants[15]); } else { frac = ToFixed1000(Constants[16]); } break; case 2: frac = ToFixed1000(Constants[sleeping ? 11 : 10]); break; case 3: frac = ToFixed1000(Constants[sleeping ? 13 : 12]) + FracMul(r_Hunger, ToFixed1000(Constants[4])); break; case 4: if (sleeping) { frac = (context.Clock.Hours >= Constants[2]) ? ToFixed1000(Constants[3]) : 0; } else { frac = (ToFixed1000(Constants[0]) / (30 * (int)Constants[1])); } //energy span over wake hours. small energy drift applied if asleep during the day. break; case 5: frac = (sleeping)?0:ToFixed1000(Constants[8]); break; case 6: frac = ToFixed1000(Constants[6]) + ToFixed1000(Constants[7]) * avatar.GetPersonData(VMPersonDataVariable.OutgoingPersonality); break; } MotiveFractions[i] += (short)frac; if (MotiveFractions[i] >= 1000) { motive -= (short)(MotiveFractions[i] / 1000); MotiveFractions[i] %= 1000; if (motive < -100) { motive = -100; } avatar.SetMotiveData(DecrementMotives[i], motive); } moodSum += motive; } moodSum += roomScore; avatar.SetMotiveData(VMMotive.Mood, (short)(moodSum / 8)); }