public VMPlacementError ChangePosition(LotTilePos pos, Direction direction, VMContext context) { if (pos.Level > context.Architecture.Stories) return VMPlacementError.NotAllowedOnFloor; for (int i = 0; i < Objects.Count(); i++) 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++) Objects[j].PositionChange(context); return places[i].Status; } } } //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); return VMPlacementError.Success; }
public bool CheckFloorValid(LotTilePos pos, FloorTile floor) { if (pos.Level < 1 || pos.Level > ObjectsAt.Count || !ObjectsAt[pos.Level - 1].ContainsKey(pos.TileID)) return true; var objs = ObjectsAt[pos.Level - 1][pos.TileID]; foreach (var id in objs) { var obj = VM.GetObjectById(id); if (obj.FloorChangeValid(floor, pos.Level) != VMPlacementError.Success) return false; } return true; }
private bool SetPosition(VMEntity entity, LotTilePos pos, Direction dir, VMContext context) { return SetPosition(entity, pos, (float)(Math.Round(Math.Log((double)dir, 2))*(Math.PI/4)), context); }
public virtual VMPlacementError SetPosition(LotTilePos pos, Direction direction, VMContext context) { return MultitileGroup.ChangePosition(pos, direction, context); }
public ushort GetRoomAt(LotTilePos pos) { if (pos.TileX < 0 || pos.TileX >= _Arch.Width) return 0; else if (pos.TileY < 0 || pos.TileY >= _Arch.Height) return 0; else if (pos.Level < 1 || pos.Level > _Arch.Stories) return 0; else return Architecture.Rooms[pos.Level-1].Map[pos.TileX + pos.TileY * _Arch.Width]; }
public VMSolidResult SolidToAvatars(LotTilePos pos) { if (pos.Level < 1 || pos.Level > ObjectsAt.Count || !ObjectsAt[pos.Level - 1].ContainsKey(pos.TileID)) return new VMSolidResult(); var objs = ObjectsAt[pos.Level - 1][pos.TileID]; foreach (var id in objs) { var obj = VM.GetObjectById(id); if (obj == null) continue; var flags = (VMEntityFlags)obj.GetValue(VMStackObjectVariable.Flags); if (((flags & VMEntityFlags.DisallowPersonIntersection) > 0) || (flags & (VMEntityFlags.AllowPersonIntersection | VMEntityFlags.HasZeroExtent)) == 0) return new VMSolidResult { Solid = true, Chair = (obj.EntryPoints[26].ActionFunction != 0)?obj:null }; //solid to people } return new VMSolidResult(); }
public LotTilePos(LotTilePos pos) { x = pos.x; y = pos.y; Level = pos.Level; }
public VMMultitileGroup CreateObjectInstance(UInt32 GUID, LotTilePos pos, Direction direction, short MainStackOBJ, short MainParam) { VMMultitileGroup group = new VMMultitileGroup(); var objDefinition = TSO.Content.Content.Get().WorldObjects.Get(GUID); if (objDefinition == null) { return null; } var master = objDefinition.OBJ.MasterID; if (master != 0) { group.MultiTile = true; var objd = objDefinition.Resource.List<OBJD>(); for (int i = 0; i < objd.Count; i++) { if (objd[i].MasterID == master && objd[i].SubIndex != -1) //if sub-part of this object, make it! { var subObjDefinition = TSO.Content.Content.Get().WorldObjects.Get(objd[i].GUID); if (subObjDefinition != null) { var worldObject = new ObjectComponent(subObjDefinition); var vmObject = new VMGameObject(subObjDefinition, worldObject); vmObject.MasterDefinition = objDefinition.OBJ; vmObject.UseTreeTableOf(objDefinition); vmObject.MainParam = MainParam; vmObject.MainStackOBJ = MainStackOBJ; group.Objects.Add(vmObject); vmObject.MultitileGroup = group; VM.AddEntity(vmObject); } } } group.Init(this); VMPlacementError couldPlace = group.ChangePosition(pos, direction, this); if (couldPlace != VMPlacementError.Success); return group; } else { if (objDefinition.OBJ.ObjectType == OBJDType.Person) //person { var vmObject = new VMAvatar(objDefinition); vmObject.MultitileGroup = group; group.Objects.Add(vmObject); VM.AddEntity(vmObject); Blueprint.AddAvatar((AvatarComponent)vmObject.WorldUI); vmObject.MainParam = MainParam; vmObject.MainStackOBJ = MainStackOBJ; group.Init(this); vmObject.SetPosition(pos, direction, this); return group; } else { var worldObject = new ObjectComponent(objDefinition); var vmObject = new VMGameObject(objDefinition, worldObject); vmObject.MultitileGroup = group; group.Objects.Add(vmObject); VM.AddEntity(vmObject); vmObject.MainParam = MainParam; vmObject.MainStackOBJ = MainStackOBJ; group.Init(this); vmObject.SetPosition(pos, direction, this); return group; } } }
private double GetDirectionTo(LotTilePos pos1, LotTilePos pos2) { return Math.Atan2(pos2.x - pos1.x, -(pos2.y - pos1.y)); }
private static bool equals(LotTilePos c1, LotTilePos c2) { return c1.x == c2.x && c1.y == c2.y && c1.Level == c2.Level; }
public override VMPrimitiveExitCode Execute(VMStackFrame context) { var operand = context.GetCurrentOperand<VMGotoRelativePositionOperand>(); var obj = context.StackObject; var avatar = (VMAvatar)context.Caller; if (obj.Position == LotTilePos.OUT_OF_WORLD) return VMPrimitiveExitCode.GOTO_FALSE; var result = new VMFindLocationResult(); LotTilePos relative; int intDir = (int)Math.Round(Math.Log((double)obj.Direction, 2)); /** * Examples for reference * Fridge - Have Snack - In front of, facing */ if (operand.Location == VMGotoRelativeLocation.OnTopOf) { relative = new LotTilePos(0, 0, obj.Position.Level); result.Position = new LotTilePos(obj.Position); //result.Flags = (SLOTFlags)obj.Direction; } else { int dir; if (operand.Location == VMGotoRelativeLocation.AnywhereNear) dir = (int)context.VM.Context.NextRandom(8); else dir = ((int)operand.Location + intDir) % 8; relative = Positions[dir]; var location = obj.Position; location += relative; result.Position = location; } //throw new Exception("Unknown goto relative"); if (operand.Direction == VMGotoRelativeDirection.Facing) { result.RadianDirection = (float)GetDirectionTo(relative, new LotTilePos(0, 0, relative.Level)); result.Flags = RadianToFlags(result.RadianDirection); } else if (operand.Direction == VMGotoRelativeDirection.AnyDirection) { result.RadianDirection = 0; result.Flags = SLOTFlags.NORTH; } else { var dir = ((int)operand.Direction + intDir) % 8; result.RadianDirection = (float)dir*(float)(Math.PI/4.0); if (result.RadianDirection > Math.PI) result.RadianDirection -= (float)(Math.PI * 2.0); result.Flags = (SLOTFlags)(1<<(int)dir); } var pathFinder = context.Thread.PushNewPathFinder(context, new List<VMFindLocationResult>() { result }); if (pathFinder != null) return VMPrimitiveExitCode.CONTINUE; else return VMPrimitiveExitCode.GOTO_FALSE; }
private double GetDist(LotTilePos pos1, LotTilePos pos2) { return Math.Sqrt(Math.Pow(pos1.x - pos2.x, 2) + Math.Pow(pos1.y - pos2.y, 2))/16.0 + Math.Abs(pos1.Level-pos2.Level)*10; }
private bool AdvanceWaypoint() { if (WalkTo.Count == 0) return false; var point = WalkTo.First.Value; WalkTo.RemoveFirst(); if (WalkTo.Count > 0) { CurrentWaypoint = LotTilePos.FromBigTile((short)point.X, (short)point.Y, Caller.Position.Level); } else CurrentWaypoint = CurRoute.Position; //go directly to position at last WalkDirection = TargetDirection; TargetDirection = Math.Atan2(CurrentWaypoint.x - Caller.Position.x, Caller.Position.y - CurrentWaypoint.y); //y+ as north. x+ is -90 degrees. TurnFrames = 10; return true; }
public bool CheckWallValid(LotTilePos pos, WallTile wall) { if (pos.Level < 1 || pos.Level > ObjectsAt.Count || !ObjectsAt[pos.Level - 1].ContainsKey(pos.TileID)) return true; var objs = ObjectsAt[pos.Level - 1][pos.TileID]; foreach (var id in objs) { var obj = VM.GetObjectById(id); if (obj.WallChangeValid(wall, obj.Direction, false) != VMPlacementError.Success) return false; } return true; }
public static int Distance(LotTilePos a, LotTilePos b) { return (int)Math.Sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); //TODO: consider level? does anything need this? }
public VMMultitileGroup CreateObjectInstance(UInt32 GUID, LotTilePos pos, Direction direction) { return CreateObjectInstance(GUID, pos, direction, 0, 0); }
public override VMPrimitiveExitCode Execute(VMStackFrame context) { var operand = context.GetCurrentOperand<VMCreateObjectInstanceOperand>(); LotTilePos tpos = new LotTilePos(LotTilePos.OUT_OF_WORLD); Direction dir; switch (operand.Position) { case VMCreateObjectPosition.UnderneathMe: case VMCreateObjectPosition.OnTopOfMe: tpos = new LotTilePos(context.Caller.Position); dir = Direction.NORTH; break; case VMCreateObjectPosition.BelowObjectInLocal: tpos = new LotTilePos(context.VM.GetObjectById((short)context.Locals[operand.LocalToUse]).Position); dir = Direction.NORTH; break; case VMCreateObjectPosition.BelowObjectInStackParam0: tpos = new LotTilePos(context.VM.GetObjectById((short)context.Args[0]).Position); dir = Direction.NORTH; break; case VMCreateObjectPosition.OutOfWorld: dir = Direction.NORTH; break; case VMCreateObjectPosition.InSlot0OfStackObject: case VMCreateObjectPosition.InMyHand: dir = Direction.NORTH; //this object should start in slot 0 of the stack object! //we have to create it first tho so hold your horses break; case VMCreateObjectPosition.InFrontOfStackObject: case VMCreateObjectPosition.InFrontOfMe: var objp = (operand.Position == VMCreateObjectPosition.InFrontOfStackObject)?context.StackObject:context.Caller; tpos = new LotTilePos(objp.Position); switch (objp.Direction) { case tso.world.model.Direction.SOUTH: tpos.y += 16; break; case tso.world.model.Direction.WEST: tpos.x -= 16; break; case tso.world.model.Direction.EAST: tpos.x += 16; break; case tso.world.model.Direction.NORTH: tpos.y -= 16; break; } dir = objp.Direction; break; default: throw new VMSimanticsException("Where do I put this??", context); } var obj = context.VM.Context.CreateObjectInstance(operand.GUID, tpos, dir, (operand.PassObjectIds && context.StackObject != null) ? (context.StackObject.ObjectID) : (short)0, (operand.PassTemp0) ? (context.Thread.TempRegisters[0]) : (operand.PassObjectIds ? context.Caller.ObjectID : (short)0) ).Objects[0]; if (operand.Position == VMCreateObjectPosition.InSlot0OfStackObject) context.StackObject.PlaceInSlot(obj, 0); else if (operand.Position == VMCreateObjectPosition.InMyHand) context.Caller.PlaceInSlot(obj, 0); if ((operand.Flags & (1 << 6)) > 0) { var interaction = operand.InteractionCallback; if (interaction == 254) { var temp = context.Caller.Thread.Queue[0].InteractionNumber; if (temp == -1) throw new VMSimanticsException("Set callback as 'this interaction' when queue item has no interaction number!", context); interaction = (byte)temp; } var callback = new VMActionCallback(context.VM, interaction, context.Callee, context.StackObject, context.Caller, true); callback.Run(obj); } else context.StackObject = obj; return VMPrimitiveExitCode.GOTO_TRUE; }
public VMPlacementResult GetObjPlace(VMEntity target, LotTilePos pos) { //ok, this might be confusing... short allowedHeights = target.GetValue(VMStackObjectVariable.AllowedHeightFlags); short weight = target.GetValue(VMStackObjectVariable.Weight); var tflags = (VMEntityFlags)target.GetValue(VMStackObjectVariable.Flags); bool noFloor = (allowedHeights&1)==0; VMPlacementError status = (noFloor)?VMPlacementError.HeightNotAllowed:VMPlacementError.Success; if ((tflags & VMEntityFlags.HasZeroExtent) > 0 || pos.Level < 1 || pos.Level > ObjectsAt.Count || (!ObjectsAt[pos.Level - 1].ContainsKey(pos.TileID))) { return new VMPlacementResult { Status = status }; } var objs = ObjectsAt[pos.Level - 1][pos.TileID]; foreach (var id in objs) { var obj = VM.GetObjectById(id); if (obj == null || obj.MultitileGroup == target.MultitileGroup) continue; var flags = (VMEntityFlags)obj.GetValue(VMStackObjectVariable.Flags); if ((flags & VMEntityFlags.HasZeroExtent) == 0) { status = VMPlacementError.CantIntersectOtherObjects; //this object is technically solid. Check if we can place on top of it if (allowedHeights>1 && obj.TotalSlots() > 0 && (obj.GetSlot(0) == null || obj.GetSlot(0) == target)) { //first check if we have a slot 0, which is what we place onto. then check if it's empty, //then check if the object can support this one's weight. //we also need to make sure that the height of this specific slot is allowed. if (((1 << (obj.GetSlotHeight(0) - 1)) & allowedHeights) > 0) { if (weight < obj.GetValue(VMStackObjectVariable.SupportStrength)) { return new VMPlacementResult { Status = VMPlacementError.Success, Container = obj }; } else { status = VMPlacementError.CantSupportWeight; } } else { if (noFloor) { if ((allowedHeights & (1 << 3)) > 0) status = VMPlacementError.CounterHeight; else status = (obj.GetSlotHeight(0) == 8) ? VMPlacementError.CannotPlaceComputerOnEndTable : VMPlacementError.HeightNotAllowed; } } } } } return new VMPlacementResult { Status = status }; }
public VMPlacementResult PositionValid(LotTilePos pos, Direction direction, VMContext context) { if (pos == LotTilePos.OUT_OF_WORLD) return new VMPlacementResult(); else if (context.IsOutOfBounds(pos)) return new VMPlacementResult { Status = VMPlacementError.LocationOutOfBounds }; //TODO: speedup with exit early checks //TODO: corner checks (wtf uses this) var arch = context.Architecture; var wall = arch.GetWall(pos.TileX, pos.TileY, pos.Level); //todo: preprocess to check which walls are real solid walls. VMPlacementError wallValid = WallChangeValid(wall, direction, true); if (wallValid != VMPlacementError.Success) return new VMPlacementResult { Status = wallValid }; var floor = arch.GetFloor(pos.TileX, pos.TileY, pos.Level); //todo: preprocess to check which walls are real solid walls. VMPlacementError floorValid = FloorChangeValid(floor, pos.Level); if (floorValid != VMPlacementError.Success) return new VMPlacementResult { Status = floorValid }; //we've passed the wall test, now check if we intersect any objects. var valid = context.GetObjPlace(this, pos); return valid; }
public bool IsOutOfBounds(LotTilePos pos) { return (pos.x < 0 || pos.y < 0 || pos.TileX >= _Arch.Width || pos.TileY >= _Arch.Height); }
public virtual void SetIndivPosition(LotTilePos pos, Direction direction, VMContext context, VMPlacementResult info) { Direction = direction; //TODO: clean the f**k up out of OUT_OF_WORLD if (this is VMGameObject) context.Blueprint.ChangeObjectLocation((ObjectComponent)WorldUI, (pos==LotTilePos.OUT_OF_WORLD)?LotTilePos.FromBigTile(-1,-1,1):pos); Position = pos; if (info.Container != null) info.Container.PlaceInSlot(this, 0); }
public void ChangeObjectLocation(ObjectComponent component, LotTilePos pos) { short tileX = (pos.x < 0) ? (short)0 : pos.TileX; short tileY = (pos.y < 0) ? (short)0 : pos.TileY; sbyte level = pos.Level; /** It has never been placed before if tileX == -2 **/ if (component.TileX != -2){ var currentOffset = GetOffset(component.TileX, component.TileY); var currentList = Objects[currentOffset]; if (currentList != null){ currentList.RemoveObject(component); } } if (tileX != -2) { var newOffset = GetOffset(tileX, tileY); var newList = Objects[newOffset]; if (newList == null) { newList = Objects[newOffset] = new BlueprintObjectList(); } newList.AddObject(component); if (!All.Contains(component)) { All.Add(component); } } else if (All.Contains(component)) { All.Remove(component); } Damage.Add(new BlueprintDamage(BlueprintDamageType.OBJECT_MOVE, tileX, tileY, level) { Component = component }); OccupiedTilesDirty = true; component.blueprint = this; component.TileX = tileX; component.TileY = tileY; component.Level = level; component.Position = new Microsoft.Xna.Framework.Vector3(pos.x / 16.0f, pos.y / 16.0f, (level - 1) * 3.0f); }
private bool SetPosition(VMEntity entity, LotTilePos pos, float radDir, VMContext context) { if (entity is VMGameObject) { var posChange = entity.SetPosition(pos, (Direction)(1 << (int)(Math.Round(DirectionUtils.PosMod(radDir, (float)Math.PI * 2) / (Math.PI/4)) % 8)), context); if (posChange != VMPlacementError.Success) return false; } else { entity.Position = pos; entity.RadianDirection = radDir; } return true; }