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); }