public static void DoFootstepSounds(Mobile mobile, double frame) { MobileSoundData data; if (!m_Data.TryGetValue(mobile.Serial, out data)) { data = new MobileSoundData(mobile); m_Data.Add(mobile.Serial, data); } bool play = (data.LastFootstep < 0.5d && frame >= 0.5d) || (data.LastFootstep > 0.5d && frame < 0.5d); if (mobile.IsMounted && !mobile.IsRunning && frame > 0.5d) play = false; if (play) { if (mobile.IsMounted && mobile.IsRunning) { int sfx = Utility.RandomValue(0, m_StepMountedSFX.Length - 1); m_Audio.PlaySound(m_StepMountedSFX[sfx]); } else { int sfx = Utility.RandomValue(0, m_StepSFX.Length - 1); m_Audio.PlaySound(m_StepSFX[sfx]); } } data.LastFootstep = frame; }
public MobileHealthTrackerGump(Mobile mobile) : base(mobile.Serial, 0) { while (UserInterface.GetControl<MobileHealthTrackerGump>(mobile.Serial) != null) { UserInterface.GetControl<MobileHealthTrackerGump>(mobile.Serial).Dispose(); } IsMoveable = true; HandlesMouseInput = true; Mobile = mobile; if (Mobile.IsClientEntity) { AddControl(m_Background = new GumpPic(this, 0, 0, 0x0803, 0)); m_BarBGs = new GumpPic[3]; AddControl(m_BarBGs[0] = new GumpPic(this, 34, 10, 0x0805, 0)); AddControl(m_BarBGs[1] = new GumpPic(this, 34, 24, 0x0805, 0)); AddControl(m_BarBGs[2] = new GumpPic(this, 34, 38, 0x0805, 0)); m_Bars = new GumpPicWithWidth[3]; AddControl(m_Bars[0] = new GumpPicWithWidth(this, 34, 10, 0x0806, 0, 1f)); AddControl(m_Bars[1] = new GumpPicWithWidth(this, 34, 24, 0x0806, 0, 1f)); AddControl(m_Bars[2] = new GumpPicWithWidth(this, 34, 38, 0x0806, 0, 1f)); } else { AddControl(m_Background = new GumpPic(this, 0, 0, 0x0804, 0)); m_BarBGs = new GumpPic[1]; AddControl(m_BarBGs[0] = new GumpPic(this, 34, 38, 0x0805, 0)); m_Bars = new GumpPicWithWidth[1]; AddControl(m_Bars[0] = new GumpPicWithWidth(this, 34, 38, 0x0806, 0, 1f)); AddControl(new HtmlGumpling(this, 17, 13, 120, 20, 0, 0, String.Format("<span color='#000' style='font-family:uni0;'>{0}", mobile.Name))); } }
public static int GetNextZ(Mobile m, Position3D loc, Direction d) { int newZ; if (CheckMovement(m, loc, d, out newZ, true)) return newZ; return loc.Z; }
public static void ResetFootstepSounds(Mobile mobile) { if (m_Data.ContainsKey(mobile.Serial)) { m_Data[mobile.Serial].LastFootstep = 1.0f; } }
public PaperDollInteractable(AControl parent, int x, int y, Mobile sourceEntity) : base(0, 0) { Parent = parent; Position = new Point(x, y); m_isFemale = sourceEntity.Flags.IsFemale; SourceEntity = sourceEntity; m_World = ServiceRegistry.GetService<WorldModel>(); }
public EquipmentSlot(AControl parent, int x, int y, Mobile entity, EquipLayer layer) : base(parent) { HandlesMouseInput = true; m_Entity = entity; m_EquipLayer = layer; Position = new Point(x, y); AddControl(new GumpPicTiled(this, 0, 0, 19, 20, 0x243A)); AddControl(new GumpPic(this, 0, 0, 0x2344, 0)); m_World = ServiceRegistry.GetService<WorldModel>(); }
public CrimeQueryGump(Mobile mobile) : base(0, 0) { Mobile = mobile; AddControl(new GumpPic(this, 0, 0, 0x0816, 0)); AddControl(new TextLabelAscii(this, 40, 30, 1, 118, "This may flag you criminal!", 120)); ((TextLabelAscii)LastControl).Hue = 997; AddControl(new Button(this, 40, 77, 0x817, 0x818, ButtonTypes.Activate, 0, 0)); AddControl(new Button(this, 100, 77, 0x81A, 0x81B, ButtonTypes.Activate, 1, 1)); IsMoveable = false; MetaData.IsModal = true; }
public MobileHealthTrackerGump(Mobile mobile) : base(mobile.Serial, 0) { while (UserInterface.GetControl<MobileHealthTrackerGump>(mobile.Serial) != null) { UserInterface.GetControl<MobileHealthTrackerGump>(mobile.Serial).Dispose(); } IsMoveable = true; Mobile = mobile; m_World = Service.Get<WorldModel>(); if (Mobile.IsClientEntity) { AddControl(m_Background = new GumpPic(this, 0, 0, 0x0803, 0)); m_Background.MouseDoubleClickEvent += Background_MouseDoubleClickEvent; m_BarBGs = new GumpPic[3]; AddControl(m_BarBGs[0] = new GumpPic(this, 34, 10, 0x0805, 0)); AddControl(m_BarBGs[1] = new GumpPic(this, 34, 24, 0x0805, 0)); AddControl(m_BarBGs[2] = new GumpPic(this, 34, 38, 0x0805, 0)); m_Bars = new GumpPicWithWidth[3]; AddControl(m_Bars[0] = new GumpPicWithWidth(this, 34, 10, 0x0806, 0, 1f)); AddControl(m_Bars[1] = new GumpPicWithWidth(this, 34, 24, 0x0806, 0, 1f)); AddControl(m_Bars[2] = new GumpPicWithWidth(this, 34, 38, 0x0806, 0, 1f)); } else { AddControl(m_Background = new GumpPic(this, 0, 0, 0x0804, 0)); m_Background.MouseDoubleClickEvent += Background_MouseDoubleClickEvent; m_BarBGs = new GumpPic[1]; AddControl(m_BarBGs[0] = new GumpPic(this, 34, 38, 0x0805, 0)); m_Bars = new GumpPicWithWidth[1]; AddControl(m_Bars[0] = new GumpPicWithWidth(this, 34, 38, 0x0806, 0, 1f)); AddControl(m_NameEntry = new TextEntry(this, 17, 16, 124, 20, 0, 0, 99, mobile.Name)); SetupMobileNameEntry(); } // bars should not handle mouse input, pass it to the background gump. for (int i = 0; i < m_BarBGs.Length; i++) { m_BarBGs[i].HandlesMouseInput = false; m_Bars[i].HandlesMouseInput = false; } }
public MobileHealthTrackerGump(Mobile mobile) : base(mobile.Serial, 0) { while (UserInterface.GetControl<MobileHealthTrackerGump>(mobile.Serial) != null) { UserInterface.GetControl<MobileHealthTrackerGump>(mobile.Serial).Dispose(); } IsMoveable = true; Mobile = mobile; if (Mobile.IsClientEntity) { AddControl(m_Background = new GumpPic(this, 0, 0, 0x0803, 0)); m_Background.MouseDoubleClickEvent += Background_MouseDoubleClickEvent; m_BarBGs = new GumpPic[3]; AddControl(m_BarBGs[0] = new GumpPic(this, 34, 10, 0x0805, 0)); AddControl(m_BarBGs[1] = new GumpPic(this, 34, 24, 0x0805, 0)); AddControl(m_BarBGs[2] = new GumpPic(this, 34, 38, 0x0805, 0)); m_Bars = new GumpPicWithWidth[3]; AddControl(m_Bars[0] = new GumpPicWithWidth(this, 34, 10, 0x0806, 0, 1f)); AddControl(m_Bars[1] = new GumpPicWithWidth(this, 34, 24, 0x0806, 0, 1f)); AddControl(m_Bars[2] = new GumpPicWithWidth(this, 34, 38, 0x0806, 0, 1f)); } else { AddControl(m_Background = new GumpPic(this, 0, 0, 0x0804, 0)); m_BarBGs = new GumpPic[1]; AddControl(m_BarBGs[0] = new GumpPic(this, 34, 38, 0x0805, 0)); m_Bars = new GumpPicWithWidth[1]; AddControl(m_Bars[0] = new GumpPicWithWidth(this, 34, 38, 0x0806, 0, 1f)); AddControl(new HtmlGumpling(this, 17, 13, 120, 20, 0, 0, String.Format("<span color='#000' style='font-family:uni0;'>{0}", mobile.Name))); } // bars should not handle mouse input, pass it to the background gump. for (int i = 0; i < m_BarBGs.Length; i++) { m_BarBGs[i].HandlesMouseInput = false; m_Bars[i].HandlesMouseInput = false; } }
public void AttackRequest(Mobile mobile) { // Do nothing on Invulnerable if (mobile.Notoriety == 0x7){ } // Attack Innocents, Reds and Greys else if (mobile.Notoriety == 0x1 || mobile.Notoriety == 0x3 || mobile.Notoriety == 0x4 || mobile.Notoriety == 0x5 || mobile.Notoriety == 0x6) { m_Network.Send(new AttackRequestPacket(mobile.Serial)); } // CrimeQuery is enabled, ask before attacking others else if (Settings.UserInterface.CrimeQuery) { m_UserInterface.AddControl(new CrimeQueryGump(mobile), 0, 0); } // CrimeQuery is disabled, so attack without asking else { m_Network.Send(new AttackRequestPacket(mobile.Serial)); } }
public static void DoFootstepSounds(Mobile mobile, double frame) { if (!mobile.Body.IsHumanoid || mobile.Flags.IsHidden) return; MobileSoundData data; if (!m_Data.TryGetValue(mobile.Serial, out data)) { data = new MobileSoundData(mobile); m_Data.Add(mobile.Serial, data); } bool play = (data.LastFrame < 0.5d && frame >= 0.5d) || (data.LastFrame > 0.5d && frame < 0.5d); if (mobile.IsMounted && !mobile.IsRunning && frame > 0.5d) play = false; if (play) { float volume = 1f; int distanceFromPlayer = Utility.DistanceBetweenTwoPoints(mobile.DestinationPosition.Tile, WorldModel.Entities.GetPlayerEntity().DestinationPosition.Tile); if (distanceFromPlayer > 4) volume = 1f - (distanceFromPlayer - 4) * 0.05f; if (mobile.IsMounted && mobile.IsRunning) { int sfx = Utility.RandomValue(0, m_StepMountedSFX.Length - 1); m_Audio.PlaySound(m_StepMountedSFX[sfx], Core.Audio.AudioEffects.PitchVariation, volume); } else { int sfx = Utility.RandomValue(0, m_StepSFX.Length - 1); m_Audio.PlaySound(m_StepSFX[sfx], Core.Audio.AudioEffects.PitchVariation, volume); } } data.LastFrame = frame; }
public MobileAnimation(Mobile parent) { Parent = parent; }
public override void Update(double totalMS, double frameMS) { if (Mobile != null && Mobile.IsDisposed) Mobile = null; if (Mobile == null) { Dispose(); return; } // switch the graphics on the peace/war btn if this is the player entity and warmode flag has changed. if (Mobile.IsClientEntity && m_IsWarMode != Mobile.Flags.IsWarMode) { m_IsWarMode = Mobile.Flags.IsWarMode; int[] btngumps = m_IsWarMode ? WarModeBtnGumps : PeaceModeBtnGumps; m_WarModeBtn.GumpUpID = btngumps[0]; m_WarModeBtn.GumpDownID = btngumps[1]; m_WarModeBtn.GumpOverID = btngumps[2]; } base.Update(totalMS, frameMS); }
public override bool RestoreGump(Dictionary<string, object> data) { int serial; if (data.ContainsKey("serial")) { serial = (int)data["serial"]; Mobile mobile = WorldModel.Entities.GetObject<Mobile>(serial, false); if (mobile != null) { Mobile = mobile; BuildGump(); return true; } } return false; }
public MobileView(Mobile mobile) : base(mobile) { m_Animation = new MobileAnimation(mobile); m_MobileLayers = new MobileViewLayer[(int)EquipLayer.LastUserValid]; PickType = PickType.PickObjects; }
public static bool CheckMovement(Mobile m, Position3D loc, Direction d, out int newZ, bool forceOK = false) { Map map = m.Map; if (map == null) { newZ = 0; return true; } int xStart = (int)loc.X; int yStart = (int)loc.Y; int xForward = xStart, yForward = yStart; int xRight = xStart, yRight = yStart; int xLeft = xStart, yLeft = yStart; bool checkDiagonals = ((int)d & 0x1) == 0x1; offsetXY(d, ref xForward, ref yForward); offsetXY((Direction)(((int)d - 1) & 0x7), ref xLeft, ref yLeft); offsetXY((Direction)(((int)d + 1) & 0x7), ref xRight, ref yRight); if (xForward < 0 || yForward < 0 || xForward >= map.TileWidth || yForward >= map.TileHeight) { newZ = 0; return false; } int startZ, startTop; List<Item> itemsStart = m_Pools[0]; List<Item> itemsForward = m_Pools[1]; List<Item> itemsLeft = m_Pools[2]; List<Item> itemsRight = m_Pools[3]; TileFlag reqFlags = ImpassableSurface; // if (m.CanSwim) // reqFlags |= TileFlag.Wet; if (checkDiagonals) { MapTile tileStart = map.GetMapTile(xStart, yStart); MapTile tileForward = map.GetMapTile(xForward, yForward); MapTile tileLeft = map.GetMapTile(xLeft, yLeft); MapTile tileRight = map.GetMapTile(xRight, yRight); if ((tileForward == null) || (tileStart == null) || (tileLeft == null) || (tileRight == null)) { newZ = (int)loc.Z; return false; } List<MapTile> tiles = new List<MapTile>(); //m_Sectors; tiles.Add(tileStart); tiles.Add(tileForward); tiles.Add(tileLeft); tiles.Add(tileRight); for (int i = 0; i < tiles.Count; ++i) { MapTile tile = tiles[i]; for (int j = 0; j < tile.Entities.Count; ++j) { AEntity entity = tile.Entities[j]; //Item item = sector.Items[j]; // if (ignoreMovableImpassables && item.Movable && item.ItemData.Impassable) // continue; if (entity is Item) { Item item = (Item)entity; if ((item.ItemData.Flags & reqFlags) == 0) continue; if (tile == tileStart && item.AtWorldPoint(xStart, yStart) && item.ItemID < 0x4000) itemsStart.Add(item); else if (tile == tileForward && item.AtWorldPoint(xForward, yForward) && item.ItemID < 0x4000) itemsForward.Add(item); else if (tile == tileLeft && item.AtWorldPoint(xLeft, yLeft) && item.ItemID < 0x4000) itemsLeft.Add(item); else if (tile == tileRight && item.AtWorldPoint(xRight, yRight) && item.ItemID < 0x4000) itemsRight.Add(item); } } } } else { MapTile tileStart = map.GetMapTile(xStart, yStart); MapTile tileForward = map.GetMapTile(xForward, yForward); if ((tileForward == null) || (tileStart == null)) { newZ = (int)loc.Z; return false; } if (tileStart == tileForward) { for (int i = 0; i < tileStart.Entities.Count; ++i) { AEntity entity = tileStart.Entities[i]; // Item item = sectorStart.Items[i]; if (entity is Item) { Item item = (Item)entity; // if (ignoreMovableImpassables && item.Movable && item.ItemData.Impassable) // continue; if ((item.ItemData.Flags & reqFlags) == 0) continue; if (item.AtWorldPoint(xStart, yStart) && item.ItemID < 0x4000) itemsStart.Add(item); else if (item.AtWorldPoint(xForward, yForward) && item.ItemID < 0x4000) itemsForward.Add(item); } } } else { for (int i = 0; i < tileForward.Entities.Count; ++i) { AEntity entity = tileForward.Entities[i]; // Item item = sectorForward.Items[i]; if (entity is Item) { Item item = (Item)entity; // if (ignoreMovableImpassables && item.Movable && item.ItemData.Impassable) // continue; if ((item.ItemData.Flags & reqFlags) == 0) continue; if (item.AtWorldPoint(xForward, yForward) && item.ItemID < 0x4000) itemsForward.Add(item); } } for (int i = 0; i < tileStart.Entities.Count; ++i) { AEntity entity = tileStart.Entities[i]; // Item item = sectorStart.Items[i]; if (entity is Item) { Item item = (Item)entity; // if (ignoreMovableImpassables && item.Movable && item.ItemData.Impassable) // continue; if ((item.ItemData.Flags & reqFlags) == 0) continue; if (item.AtWorldPoint(xStart, yStart) && item.ItemID < 0x4000) itemsStart.Add(item); } } } } getStartZ(m, map, loc, itemsStart, out startZ, out startTop); bool moveIsOk = check(map, m, itemsForward, xForward, yForward, startTop, startZ, out newZ) | forceOK; if (moveIsOk && checkDiagonals) { int hold; if (!check(map, m, itemsLeft, xLeft, yLeft, startTop, startZ, out hold) && !check(map, m, itemsRight, xRight, yRight, startTop, startZ, out hold)) moveIsOk = false; } for (int i = 0; i < (checkDiagonals ? 4 : 2); ++i) { if (m_Pools[i].Count > 0) m_Pools[i].Clear(); } if (!moveIsOk) newZ = startZ; return moveIsOk; }
public MobileView(Mobile mobile) : base(mobile) { Animation = new MobileAnimation(mobile); m_MobileLayers = new MobileViewLayer[(int)EquipLayer.LastUserValid]; PickType = PickType.PickObjects; IsShadowCastingView = true; }
private static bool check(Map map, Mobile m, List<Item> items, int x, int y, int startTop, int startZ, out int newZ) { newZ = 0; MapTile mapTile = map.GetMapTile(x, y); if (mapTile == null) return false; StaticItem[] tiles = mapTile.GetStatics().ToArray(); bool landBlocks = (mapTile.Ground.LandData.Flags & TileFlag.Impassable) != 0; bool considerLand = !mapTile.Ground.IsIgnored; //if (landBlocks && canSwim && (TileData.LandTable[landTile.ID & 0x3FFF].Flags & TileFlag.Wet) != 0) //Impassable, Can Swim, and Is water. Don't block it. // landBlocks = false; // else // if (cantWalk && (TileData.LandTable[landTile.ID & 0x3FFF].Flags & TileFlag.Wet) == 0) //Can't walk and it's not water // landBlocks = true; int landLow = 0, landCenter = 0, landTop = 0; landCenter = map.GetAverageZ(x, y, ref landLow, ref landTop); bool moveIsOk = false; int stepTop = startTop + StepHeight; int checkTop = startZ + PersonHeight; bool ignoreDoors = (!m.IsAlive || m.Body == 0x3DB); #region Tiles for (int i = 0; i < tiles.Length; ++i) { StaticItem tile = tiles[i]; if ((tile.ItemData.Flags & ImpassableSurface) == TileFlag.Surface) // || (canSwim && (flags & TileFlag.Wet) != 0) Surface && !Impassable { // if (cantWalk && (flags & TileFlag.Wet) == 0) // continue; int itemZ = (int)tile.Z; int itemTop = itemZ; int ourZ = itemZ + tile.ItemData.CalcHeight; int ourTop = ourZ + PersonHeight; int testTop = checkTop; if (moveIsOk) { int cmp = Math.Abs(ourZ - m.Z) - Math.Abs(newZ - m.Z); if (cmp > 0 || (cmp == 0 && ourZ > newZ)) continue; } if (ourZ + PersonHeight > testTop) testTop = ourZ + PersonHeight; if (!tile.ItemData.IsBridge) itemTop += tile.ItemData.Height; if (stepTop >= itemTop) { int landCheck = itemZ; if (tile.ItemData.Height >= StepHeight) landCheck += StepHeight; else landCheck += tile.ItemData.Height; if (considerLand && landCheck < landCenter && landCenter > ourZ && testTop > landLow) continue; if (IsOk(ignoreDoors, ourZ, testTop, tiles, items)) { newZ = ourZ; moveIsOk = true; } } } } #endregion #region Items for (int i = 0; i < items.Count; ++i) { Item item = items[i]; ItemData itemData = item.ItemData; TileFlag flags = itemData.Flags; if ((flags & ImpassableSurface) == TileFlag.Surface) // Surface && !Impassable && !Movable { // || (m.CanSwim && (flags & TileFlag.Wet) != 0)) // !item.Movable && // if (cantWalk && (flags & TileFlag.Wet) == 0) // continue; int itemZ = item.Z; int itemTop = itemZ; int ourZ = itemZ + itemData.CalcHeight; int ourTop = ourZ + PersonHeight; int testTop = checkTop; if (moveIsOk) { int cmp = Math.Abs(ourZ - m.Z) - Math.Abs(newZ - m.Z); if (cmp > 0 || (cmp == 0 && ourZ > newZ)) continue; } if (ourZ + PersonHeight > testTop) testTop = ourZ + PersonHeight; if (!itemData.IsBridge) itemTop += itemData.Height; if (stepTop >= itemTop) { int landCheck = itemZ; if (itemData.Height >= StepHeight) landCheck += StepHeight; else landCheck += itemData.Height; if (considerLand && landCheck < landCenter && landCenter > ourZ && testTop > landLow) continue; if (IsOk(ignoreDoors, ourZ, testTop, tiles, items)) { newZ = ourZ; moveIsOk = true; } } } } #endregion if (considerLand && !landBlocks && (stepTop) >= landLow) { int ourZ = landCenter; int ourTop = ourZ + PersonHeight; int testTop = checkTop; if (ourZ + PersonHeight > testTop) testTop = ourZ + PersonHeight; bool shouldCheck = true; if (moveIsOk) { int cmp = Math.Abs(ourZ - m.Z) - Math.Abs(newZ - m.Z); if (cmp > 0 || (cmp == 0 && ourZ > newZ)) shouldCheck = false; } if (shouldCheck && IsOk(ignoreDoors, ourZ, testTop, tiles, items)) { newZ = ourZ; moveIsOk = true; } } return moveIsOk; }
public MobileEquipment(Mobile parent) { m_Equipment = new Item[(int)EquipLayer.LastValid + 1]; m_Parent = parent; }
public MobileSoundData(Mobile mobile) { Mobile = mobile; }
public static bool CheckMovementForced(Mobile m, Position3D loc, Direction d, out int newZ) { return CheckMovement(m, loc, d,out newZ, true); }
public PaperDollGump(Mobile parent) : base(parent.Serial, 0) { Parent = parent; m_UserInterface = ServiceRegistry.GetService<UserInterfaceService>(); m_World = ServiceRegistry.GetService<WorldModel>(); m_Client = ServiceRegistry.GetService<INetworkClient>(); IsMovable = true; if (parent == (Mobile)WorldModel.Entities.GetPlayerObject()) { AddControl(new GumpPic(this, 0, 0, 0x07d0, 0)); // HELP AddControl(new Button(this, 185, 44 + 27*0, 0x07ef, 0x07f0, ButtonTypes.Activate, 0, (int) Buttons.Help)); ((Button) LastControl).GumpOverID = 0x07f1; // OPTIONS AddControl(new Button(this, 185, 44 + 27*1, 0x07d6, 0x07d7, ButtonTypes.Activate, 0, (int) Buttons.Options)); ((Button) LastControl).GumpOverID = 0x07d8; // LOG OUT AddControl(new Button(this, 185, 44 + 27*2, 0x07d9, 0x07da, ButtonTypes.Activate, 0, (int) Buttons.LogOut)); ((Button) LastControl).GumpOverID = 0x07db; // QUESTS AddControl(new Button(this, 185, 44 + 27*3, 0x57b5, 0x57b7, ButtonTypes.Activate, 0, (int) Buttons.Quests)); ((Button) LastControl).GumpOverID = 0x57b6; // SKILLS AddControl(new Button(this, 185, 44 + 27*4, 0x07df, 0x07e0, ButtonTypes.Activate, 0, (int) Buttons.Skills)); ((Button) LastControl).GumpOverID = 0x07e1; // GUILD AddControl(new Button(this, 185, 44 + 27*5, 0x57b2, 0x57b4, ButtonTypes.Activate, 0, (int) Buttons.Guild)); ((Button) LastControl).GumpOverID = 0x57b3; // PEACE / WAR AddControl(new Button(this, 185, 44 + 27*6, 0x07e5, 0x07e6, ButtonTypes.Activate, 0, (int) Buttons.PeaceWarToggle)); ((Button) LastControl).GumpOverID = 0x07e7; // STATUS AddControl(new Button(this, 185, 44 + 27*7, 0x07eb, 0x07ec, ButtonTypes.Activate, 0, (int) Buttons.Status)); ((Button) LastControl).GumpOverID = 0x07ed; // Paperdoll AddControl(new PaperDollInteractable(this, 8, 21) { SourceEntity = Parent }); } else { AddControl(new GumpPic(this, 0, 0, 0x07d1, 0)); // Paperdoll AddControl(new PaperDollInteractable(this, 8, 21) { SourceEntity = Parent }); } }