public unsafe ushort[] ReadStaticArt(ushort graphic, out short width, out short height, out Rectangle imageRectangle) { imageRectangle.X = 0; imageRectangle.Y = 0; imageRectangle.Width = 0; imageRectangle.Height = 0; (int length, int extra, bool patcher) = _file.SeekByEntryIndex(graphic + 0x4000); if (length == 0) { width = height = 0; return(_empty); } _file.Skip(4); width = _file.ReadShort(); height = _file.ReadShort(); if (width == 0 || height == 0) { return(_empty); } ushort[] pixels = new ushort[width * height]; ushort * ptr = (ushort *)_file.PositionAddress; ushort * lineoffsets = ptr; byte * datastart = (byte *)ptr + height * 2; int x = 0; int y = 0; ptr = (ushort *)(datastart + lineoffsets[0] * 2); int minX = width, minY = height, maxX = 0, maxY = 0; while (y < height) { ushort xoffs = *ptr++; ushort run = *ptr++; if (xoffs + run >= 2048) { pixels = new ushort[width * height]; return(pixels); } if (xoffs + run != 0) { x += xoffs; int pos = y * width + x; for (int j = 0; j < run; j++) { ushort val = *ptr++; if (val != 0) { val = (ushort)(0x8000 | val); } pixels[pos++] = val; } x += run; } else { x = 0; y++; ptr = (ushort *)(datastart + lineoffsets[y] * 2); } } if (graphic >= 0x2053 && graphic <= 0x2062 || graphic >= 0x206A && graphic <= 0x2079) { for (int i = 0; i < width; i++) { pixels[i] = 0; pixels[(height - 1) * width + i] = 0; } for (int i = 0; i < height; i++) { pixels[i * width] = 0; pixels[i * width + width - 1] = 0; } } else if (StaticFilters.IsCave(graphic) && Engine.Profile.Current != null && Engine.Profile.Current.EnableCaveBorder) { for (int yy = 0; yy < height; yy++) { int startY = yy != 0 ? -1 : 0; int endY = yy + 1 < height ? 2 : 1; for (int xx = 0; xx < width; xx++) { ref var pixel = ref pixels[yy * width + xx]; if (pixel == 0) { continue; } int startX = xx != 0 ? -1 : 0; int endX = xx + 1 < width ? 2 : 1; for (int i = startY; i < endY; i++) { int currentY = yy + i; for (int j = startX; j < endX; j++) { int currentX = xx + j; ref var currentPixel = ref pixels[currentY * width + currentX]; if (currentPixel == 0u) { pixel = 0x8000; } } } } }
private void AddTileToRenderList(GameObject obj, int worldX, int worldY, bool useObjectHandles, int maxZ) { for (; obj != null; obj = obj.Right) { if (obj.CurrentRenderIndex == _renderIndex || obj.IsDisposed) { continue; } if (_updateDrawPosition && obj.CurrentRenderIndex != _renderIndex || obj.IsPositionChanged) { obj.UpdateRealScreenPosition(_offset); } //obj.UseInRender = 0xFF; float drawX = obj.RealScreenPosition.X; float drawY = obj.RealScreenPosition.Y; if (drawX < _minPixel.X || drawX > _maxPixel.X) { break; } int z = obj.Z; int maxObjectZ = obj.PriorityZ; bool mounted = false; bool ismobile = false; StaticTiles itemData = default; bool changinAlpha = false; switch (obj) { case Mobile mob: maxObjectZ += Constants.DEFAULT_CHARACTER_HEIGHT; ismobile = true; mounted = mob.IsMounted; break; default: if (GameObjectHelper.TryGetStaticData(obj, out itemData)) { if (obj is Static st) { if (StaticFilters.IsCave(st.OriginalGraphic)) { if (Engine.Profile.Current.EnableCaveBorder && !st.IsBordered()) { st.SetBorder(true); } else if (!Engine.Profile.Current.EnableCaveBorder && st.IsBordered()) { st.SetBorder(false); } } else if (StaticFilters.IsTree(st.OriginalGraphic)) { if (Engine.Profile.Current.TreeToStumps && st.Graphic != Constants.TREE_REPLACE_GRAPHIC) { st.SetGraphic(Constants.TREE_REPLACE_GRAPHIC); } else if (st.OriginalGraphic != st.Graphic && !Engine.Profile.Current.TreeToStumps) { st.RestoreOriginalGraphic(); } } } if (_noDrawRoofs && itemData.IsRoof) { if (_alphaChanged) { changinAlpha = obj.ProcessAlpha(0); } else { changinAlpha = obj.AlphaHue != 0; } if (!changinAlpha) { continue; } } if ((Engine.Profile.Current.TreeToStumps && itemData.IsFoliage) || (Engine.Profile.Current.HideVegetation && StaticFilters.IsVegetation(obj.Graphic))) { continue; } maxObjectZ += itemData.Height; } break; } if (maxObjectZ > maxZ) { break; } obj.CurrentRenderIndex = _renderIndex; bool iscorpse = !ismobile && obj is Item item && item.IsCorpse; if (!ismobile && !iscorpse && itemData.IsInternal) { continue; } bool island = !ismobile && !iscorpse && obj is Land; if (!island && z >= _maxZ) { if (!changinAlpha) { if (_alphaChanged) { changinAlpha = obj.ProcessAlpha(0); } else { changinAlpha = obj.AlphaHue != 0; } if (!changinAlpha) { continue; } } } int testMinZ = (int)drawY + z * 4; int testMaxZ = (int)drawY; if (island) { Land t = obj as Land; if (t.IsStretched) { testMinZ -= t.MinZ * 4; } else { testMinZ = testMaxZ; } } else { testMinZ = testMaxZ; } if (testMinZ < _minPixel.Y || testMaxZ > _maxPixel.Y) { continue; } if (obj.Overheads != null && obj.Overheads.Count != 0) { int offY; if (ismobile && !mounted || iscorpse) { offY = -22; } else { switch (obj) { case Multi _: case Static _: offY = -44; break; //case Item _: // offY = 44; //break; default: offY = 0; break; } } for (int i = 0; i < obj.Overheads.Count; i++) { TextOverhead v = obj.Overheads[i]; v.Bounds.X = (v.Texture.Width >> 1) - 22; v.Bounds.Y = offY + v.Texture.Height; v.Bounds.Width = v.Texture.Width; v.Bounds.Height = v.Texture.Height; Overheads.AddOverhead(v); offY += v.Texture.Height; if (_alphaChanged) { if (v.TimeToLive > 0 && v.TimeToLive <= Constants.TIME_FADEOUT_TEXT) { if (!v.IsOverlapped) { v.ProcessAlpha(0); } } else if (!v.IsOverlapped && v.AlphaHue != 0xFF) { v.ProcessAlpha(0xFF); } } } } if (ismobile || iscorpse) { AddOffsetCharacterTileToRenderList(obj, useObjectHandles); } else if (itemData.IsFoliage) { if (obj is Static st) { bool check = World.Player.X <= worldX && World.Player.Y <= worldY; if (!check) { check = World.Player.Y <= worldY && World.Player.Position.X <= worldX + 1; if (!check) { check = World.Player.X <= worldX && World.Player.Y <= worldY + 1; } } if (check) { Rectangle rect = new Rectangle((int)drawX - st.FrameInfo.X, (int)drawY - st.FrameInfo.Y, st.FrameInfo.Width, st.FrameInfo.Height); check = rect.InRect(World.Player.GetOnScreenRectangle()); } st.CharacterIsBehindFoliage = check; } else if (obj is Multi m) { bool check = World.Player.X <= worldX && World.Player.Y <= worldY; if (!check) { check = World.Player.Y <= worldY && World.Player.Position.X <= worldX + 1; if (!check) { check = World.Player.X <= worldX && World.Player.Y <= worldY + 1; } } if (check) { Rectangle rect = new Rectangle((int)drawX - m.FrameInfo.X, (int)drawY - m.FrameInfo.Y, m.FrameInfo.Width, m.FrameInfo.Height); check = rect.InRect(World.Player.GetOnScreenRectangle()); } m.CharacterIsBehindFoliage = check; } } if (_alphaChanged && !changinAlpha) { if (itemData.IsTranslucent) { obj.ProcessAlpha(178); } else if (!itemData.IsFoliage && obj.AlphaHue != 0xFF) { obj.ProcessAlpha(0xFF); } } if (_renderListCount >= _renderList.Length) { int newsize = _renderList.Length + 1000; Array.Resize(ref _renderList, newsize); } if (useObjectHandles) { obj.UseObjectHandles = (ismobile || iscorpse || obj is Item it && !it.IsLocked && !it.IsMulti) && !obj.ClosedObjectHandles; _objectHandlesCount++; } else if (obj.ClosedObjectHandles) { obj.ClosedObjectHandles = false; obj.ObjectHandlesOpened = false; } else if (obj.UseObjectHandles) { obj.ObjectHandlesOpened = false; obj.UseObjectHandles = false; } _renderList[_renderListCount] = obj; //obj.UseInRender = (byte) _renderIndex; _renderListCount++; } }
private void AddTileToRenderList(GameObject obj, int worldX, int worldY, bool useObjectHandles, int maxZ) { for (; obj != null; obj = obj.Right) { if (obj.CurrentRenderIndex == _renderIndex || obj.IsDestroyed || !obj.AllowedToDraw) { continue; } if (_updateDrawPosition && obj.CurrentRenderIndex != _renderIndex || obj.IsPositionChanged) { obj.UpdateRealScreenPosition(_offset); } //obj.UseInRender = 0xFF; float drawX = obj.RealScreenPosition.X; float drawY = obj.RealScreenPosition.Y; if (drawX < _minPixel.X || drawX > _maxPixel.X) { break; } int z = obj.Z; int maxObjectZ = obj.PriorityZ; bool ismobile = false; StaticTiles itemData = default; bool changinAlpha = false; switch (obj) { case Mobile _: maxObjectZ += Constants.DEFAULT_CHARACTER_HEIGHT; ismobile = true; break; default: if (GameObjectHelper.TryGetStaticData(obj, out itemData)) { if (obj is Static st) { if (StaticFilters.IsCave(st.OriginalGraphic)) { if (Engine.Profile.Current.EnableCaveBorder && !st.IsBordered()) { st.SetBorder(true); } else if (!Engine.Profile.Current.EnableCaveBorder && st.IsBordered()) { st.SetBorder(false); } } else if (StaticFilters.IsTree(st.OriginalGraphic)) { if (Engine.Profile.Current.TreeToStumps && st.Graphic != Constants.TREE_REPLACE_GRAPHIC) { st.SetGraphic(Constants.TREE_REPLACE_GRAPHIC); } else if (st.OriginalGraphic != st.Graphic && !Engine.Profile.Current.TreeToStumps) { st.RestoreOriginalGraphic(); } } } if (_noDrawRoofs && itemData.IsRoof) { if (_alphaChanged) { changinAlpha = obj.ProcessAlpha(0); } else { changinAlpha = obj.AlphaHue != 0; } if (!changinAlpha) { continue; } } if ((Engine.Profile.Current.TreeToStumps && itemData.IsFoliage) || (Engine.Profile.Current.HideVegetation && StaticFilters.IsVegetation(obj.Graphic))) { continue; } maxObjectZ += itemData.Height; } break; } if (maxObjectZ > maxZ) { break; } obj.CurrentRenderIndex = _renderIndex; bool iscorpse = !ismobile && obj is Item item && item.IsCorpse; if (!ismobile && !iscorpse && itemData.IsInternal) { continue; } bool island = !ismobile && !iscorpse && obj is Land; if (!island && z >= _maxZ) { if (!changinAlpha) { if (_alphaChanged) { changinAlpha = obj.ProcessAlpha(0); } else { changinAlpha = obj.AlphaHue != 0; } if (!changinAlpha) { continue; } } } int testMinZ = (int)drawY + z * 4; int testMaxZ = (int)drawY; if (island) { Land t = obj as Land; if (t.IsStretched) { testMinZ -= t.MinZ * 4; } else { testMinZ = testMaxZ; } } else { testMinZ = testMaxZ; } if (testMinZ < _minPixel.Y || testMaxZ > _maxPixel.Y) { continue; } if (obj.OverheadMessageContainer != null && !obj.OverheadMessageContainer.IsEmpty) { _overheadManager.AddOverhead(obj.OverheadMessageContainer); } if (ismobile || iscorpse) { AddOffsetCharacterTileToRenderList(obj, useObjectHandles); } else if (itemData.IsFoliage) { bool check = World.Player.X <= worldX && World.Player.Y <= worldY; if (!check) { check = World.Player.Y <= worldY && World.Player.Position.X <= worldX + 1; if (!check) { check = World.Player.X <= worldX && World.Player.Y <= worldY + 1; } } if (check) { Rectangle rect = new Rectangle((int)drawX - obj.FrameInfo.X, (int)drawY - obj.FrameInfo.Y, obj.FrameInfo.Width, obj.FrameInfo.Height); Rectangle r = World.Player.GetOnScreenRectangle(); check = Exstentions.InRect(ref rect, ref r); } if (obj is Static st) { st.CharacterIsBehindFoliage = check; } else if (obj is Multi m) { m.CharacterIsBehindFoliage = check; } else if (obj is Item it) { it.CharacterIsBehindFoliage = check; } } if (_alphaChanged && !changinAlpha) { if (itemData.IsTranslucent) { obj.ProcessAlpha(178); } else if (!itemData.IsFoliage && obj.AlphaHue != 0xFF) { obj.ProcessAlpha(0xFF); } } if (_renderListCount >= _renderList.Length) { int newsize = _renderList.Length + 1000; //_renderList.Resize(newsize); Array.Resize(ref _renderList, newsize); } if (useObjectHandles) { obj.UseObjectHandles = (ismobile || iscorpse || obj is Item it && !it.IsLocked && !it.IsMulti) && !obj.ClosedObjectHandles; _objectHandlesCount++; } else if (obj.ClosedObjectHandles) { obj.ClosedObjectHandles = false; obj.ObjectHandlesOpened = false; } else if (obj.UseObjectHandles) { obj.ObjectHandlesOpened = false; obj.UseObjectHandles = false; } //ref var weak = ref _renderList[_renderListCount]; //if (weak == null) // weak = new WeakReference<GameObject>(obj); //else // weak.SetTarget(obj); _renderList[_renderListCount] = obj; //_renderList.Enqueue(obj); //obj.UseInRender = (byte) _renderIndex; _renderListCount++; } }