public static ISound PlayToPlayer(Player player, string name, PPos pos) { return Play(player, name, false, pos, 1); }
public static PPos Lerp(PPos a, PPos b, int mul, int div) { return a + ((PVecInt)(b - a) * mul / div); }
public static ISound Play(string name, PPos pos) { return Play(null, name, false, pos, 1); }
public byte ProjectedHeight(PPos puv) { return projectedHeight[(MPos)puv]; }
public List<MPos> Unproject(PPos puv) { var uv = (MPos)puv; if (!initializedCellProjection) InitializeCellProjection(); if (!inverseCellProjection.Contains(uv)) return new List<MPos>(); return inverseCellProjection[uv]; }
public MPos ChooseClosestEdgeCell(MPos uv) { var allProjected = ProjectedCellsCovering(uv); PPos edge; if (allProjected.Any()) { var puv = allProjected.First(); var horizontalBound = ((puv.U - Bounds.Left) < Bounds.Width / 2) ? Bounds.Left : Bounds.Right; var verticalBound = ((puv.V - Bounds.Top) < Bounds.Height / 2) ? Bounds.Top : Bounds.Bottom; var du = Math.Abs(horizontalBound - puv.U); var dv = Math.Abs(verticalBound - puv.V); edge = du < dv ? new PPos(horizontalBound, puv.V) : new PPos(puv.U, verticalBound); } else edge = new PPos(Bounds.Left, Bounds.Top); var unProjected = Unproject(edge); if (!unProjected.Any()) { // Adjust V until we find a cell that works for (var x = 2; x <= 2 * Grid.MaximumTerrainHeight; x++) { var dv = ((x & 1) == 1 ? 1 : -1) * x / 2; var test = new PPos(edge.U, edge.V + dv); if (!Contains(test)) continue; unProjected = Unproject(test); if (unProjected.Any()) break; } // This shouldn't happen. But if it does, return the original value and hope the caller doesn't explode. if (!unProjected.Any()) { Log.Write("debug", "Failed to find closest edge for map cell {0}", uv); return uv; } } return edge.V == Bounds.Bottom ? unProjected.MaxBy(x => x.V) : unProjected.MinBy(x => x.V); }
public PPos Clamp(PPos puv) { var bounds = new Rectangle(Bounds.X, Bounds.Y, Bounds.Width - 1, Bounds.Height - 1); return puv.Clamp(bounds); }
public static PPos Lerp(PPos a, PPos b, int mul, int div) { return(a + ((PVecInt)(b - a) * mul / div)); }
void PostInit() { rules = Exts.Lazy(() => { try { return Game.ModData.RulesetCache.Load(this); } catch (Exception e) { InvalidCustomRules = true; Log.Write("debug", "Failed to load rules for {0} with error {1}", Title, e.Message); } return Game.ModData.DefaultRules; }); cachedTileSet = Exts.Lazy(() => Rules.TileSets[Tileset]); var tl = new MPos(0, 0).ToCPos(this); var br = new MPos(MapSize.X - 1, MapSize.Y - 1).ToCPos(this); AllCells = new CellRegion(Grid.Type, tl, br); var btl = new PPos(Bounds.Left, Bounds.Top); var bbr = new PPos(Bounds.Right - 1, Bounds.Bottom - 1); SetBounds(btl, bbr); CustomTerrain = new CellLayer<byte>(this); foreach (var uv in AllCells.MapCoords) CustomTerrain[uv] = byte.MaxValue; var leftDelta = Grid.Type == MapGridType.RectangularIsometric ? new WVec(-512, 0, 0) : new WVec(-512, -512, 0); var topDelta = Grid.Type == MapGridType.RectangularIsometric ? new WVec(0, -512, 0) : new WVec(512, -512, 0); var rightDelta = Grid.Type == MapGridType.RectangularIsometric ? new WVec(512, 0, 0) : new WVec(512, 512, 0); var bottomDelta = Grid.Type == MapGridType.RectangularIsometric ? new WVec(0, 512, 0) : new WVec(-512, 512, 0); CellCorners = CellCornerHalfHeights.Select(ramp => new WVec[] { leftDelta + new WVec(0, 0, 512 * ramp[0]), topDelta + new WVec(0, 0, 512 * ramp[1]), rightDelta + new WVec(0, 0, 512 * ramp[2]), bottomDelta + new WVec(0, 0, 512 * ramp[3]) }).ToArray(); }
public static ISound Play(string name, PPos pos) { return(Play(null, name, false, pos, 1)); }
public static PPos Min(PPos a, PPos b) { return(new PPos(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y))); }
public static ISound PlayToPlayer(Player player, string name, PPos pos) { return(Play(player, name, false, pos, 1)); }
public static ISound Play(string name, PPos pos, float volumeModifier) { return(Play(null, name, false, pos, volumeModifier)); }
// Resolve an array index from map coordinates. public int Index(PPos uv) { return(uv.V * Size.Width + uv.U); }
public bool Contains(PPos uv) { return(bounds.Contains(uv.U, uv.V)); }
public NewMapLogic(Action onExit, Action<string> onSelect, Ruleset modRules, Widget widget, World world) { panel = widget; panel.Get<ButtonWidget>("CANCEL_BUTTON").OnClick = () => { Ui.CloseWindow(); onExit(); }; var tilesetDropDown = panel.Get<DropDownButtonWidget>("TILESET"); var tilesets = modRules.TileSets.Select(t => t.Key).ToList(); Func<string, ScrollItemWidget, ScrollItemWidget> setupItem = (option, template) => { var item = ScrollItemWidget.Setup(template, () => tilesetDropDown.Text == option, () => { tilesetDropDown.Text = option; }); item.Get<LabelWidget>("LABEL").GetText = () => option; return item; }; tilesetDropDown.Text = tilesets.First(); tilesetDropDown.OnClick = () => tilesetDropDown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 210, tilesets, setupItem); var widthTextField = panel.Get<TextFieldWidget>("WIDTH"); var heightTextField = panel.Get<TextFieldWidget>("HEIGHT"); panel.Get<ButtonWidget>("CREATE_BUTTON").OnClick = () => { int width, height; int.TryParse(widthTextField.Text, out width); int.TryParse(heightTextField.Text, out height); // Require at least a 2x2 playable area so that the // ground is visible through the edge shroud width = Math.Max(2, width); height = Math.Max(2, height); var maxTerrainHeight = world.Map.Grid.MaximumTerrainHeight; var tileset = modRules.TileSets[tilesetDropDown.Text]; var map = new Map(tileset, width + 2, height + maxTerrainHeight + 2); var tl = new PPos(1, 1); var br = new PPos(width, height + maxTerrainHeight); map.SetBounds(tl, br); map.PlayerDefinitions = new MapPlayers(map.Rules, map.SpawnPoints.Value.Length).ToMiniYaml(); map.FixOpenAreas(modRules); Action<string> afterSave = uid => { // HACK: Work around a synced-code change check. // It's not clear why this is needed here, but not in the other places that load maps. Game.RunAfterTick(() => { ConnectionLogic.Connect(System.Net.IPAddress.Loopback.ToString(), Game.CreateLocalServer(uid), "", () => Game.LoadEditor(uid), () => { Game.CloseServer(); onExit(); }); }); Ui.CloseWindow(); onSelect(uid); }; Ui.OpenWindow("SAVE_MAP_PANEL", new WidgetArgs() { { "onSave", afterSave }, { "onExit", () => { Ui.CloseWindow(); onExit(); } }, { "map", map }, { "playerDefinitions", map.PlayerDefinitions }, { "actorDefinitions", map.ActorDefinitions } }); }; }
byte ProjectedCellHeightInner(PPos puv) { while (inverseCellProjection.Contains((MPos)puv)) { var inverse = inverseCellProjection[(MPos)puv]; if (inverse.Any()) { // The original games treat the top of cliffs the same way as the bottom // This information isn't stored in the map data, so query the offset from the tileset var temp = inverse.MaxBy(uv => uv.V); var terrain = Tiles[temp]; return (byte)(Height[temp] - Rules.TileSet.Templates[terrain.Type][terrain.Index].Height); } // Try the next cell down if this is a cliff face puv = new PPos(puv.U, puv.V + 1); } return 0; }
public byte ProjectedHeight(PPos puv) { return(projectedHeight[(MPos)puv]); }
public MPos Clamp(MPos uv) { if (Grid.MaximumTerrainHeight == 0) return (MPos)Clamp((PPos)uv); // Already in bounds, so don't need to do anything. if (ContainsAllProjectedCellsCovering(uv)) return uv; // Clamping map coordinates is trickier than it might first look! // This needs to handle three nasty cases: // * The requested cell is well outside the map region // * The requested cell is near the top edge inside the map but outside the projected layer // * The clamped projected cell lands on a cliff face with no associated map cell // // Handling these cases properly requires abuse of our knowledge of the projection transform. // // The U coordinate doesn't change significantly in the projection, so clamp this // straight away and ensure the point is somewhere inside the map uv = cellProjection.Clamp(new MPos(uv.U.Clamp(Bounds.Left, Bounds.Right), uv.V)); // Project this guessed cell and take the first available cell // If it is projected outside the layer, then make another guess. var allProjected = ProjectedCellsCovering(uv); var projected = allProjected.Any() ? allProjected.First() : new PPos(uv.U, uv.V.Clamp(Bounds.Top, Bounds.Bottom)); // Clamp the projected cell to the map area projected = Clamp(projected); // Project the cell back into map coordinates. // This may fail if the projected cell covered a cliff or another feature // where there is a large change in terrain height. var unProjected = Unproject(projected); if (!unProjected.Any()) { // Adjust V until we find a cell that works for (var x = 2; x <= 2 * Grid.MaximumTerrainHeight; x++) { var dv = ((x & 1) == 1 ? 1 : -1) * x / 2; var test = new PPos(projected.U, projected.V + dv); if (!Contains(test)) continue; unProjected = Unproject(test); if (unProjected.Any()) break; } // This shouldn't happen. But if it does, return the original value and hope the caller doesn't explode. if (!unProjected.Any()) { Log.Write("debug", "Failed to clamp map cell {0} to map bounds", uv); return uv; } } return projected.V == Bounds.Bottom ? unProjected.MaxBy(x => x.V) : unProjected.MinBy(x => x.V); }
public MPos Clamp(MPos uv) { if (Grid.MaximumTerrainHeight == 0) { return((MPos)Clamp((PPos)uv)); } // Already in bounds, so don't need to do anything. if (ContainsAllProjectedCellsCovering(uv)) { return(uv); } // Clamping map coordinates is trickier than it might first look! // This needs to handle three nasty cases: // * The requested cell is well outside the map region // * The requested cell is near the top edge inside the map but outside the projected layer // * The clamped projected cell lands on a cliff face with no associated map cell // // Handling these cases properly requires abuse of our knowledge of the projection transform. // // The U coordinate doesn't change significantly in the projection, so clamp this // straight away and ensure the point is somewhere inside the map uv = cellProjection.Clamp(new MPos(uv.U.Clamp(Bounds.Left, Bounds.Right), uv.V)); // Project this guessed cell and take the first available cell // If it is projected outside the layer, then make another guess. var allProjected = ProjectedCellsCovering(uv); var projected = allProjected.Any() ? allProjected.First() : new PPos(uv.U, uv.V.Clamp(Bounds.Top, Bounds.Bottom)); // Clamp the projected cell to the map area projected = Clamp(projected); // Project the cell back into map coordinates. // This may fail if the projected cell covered a cliff or another feature // where there is a large change in terrain height. var unProjected = Unproject(projected); if (!unProjected.Any()) { // Adjust V until we find a cell that works for (var x = 2; x <= 2 * Grid.MaximumTerrainHeight; x++) { var dv = ((x & 1) == 1 ? 1 : -1) * x / 2; var test = new PPos(projected.U, projected.V + dv); if (!Contains(test)) { continue; } unProjected = Unproject(test); if (unProjected.Any()) { break; } } // This shouldn't happen. But if it does, return the original value and hope the caller doesn't explode. if (!unProjected.Any()) { Log.Write("debug", "Failed to clamp map cell {0} to map bounds", uv); return(uv); } } return(projected.V == Bounds.Bottom ? unProjected.MaxBy(x => x.V) : unProjected.MinBy(x => x.V)); }
public bool Contains(PPos puv) { return Bounds.Contains(puv.U, puv.V); }
public PPos Clamp(PPos puv) { var bounds = new Rectangle(Bounds.X, Bounds.Y, Bounds.Width - 1, Bounds.Height - 1); return(puv.Clamp(bounds)); }
public void SetBounds(PPos tl, PPos br) { // The tl and br coordinates are inclusive, but the Rectangle // is exclusive. Pad the right and bottom edges to match. Bounds = Rectangle.FromLTRB(tl.U, tl.V, br.U + 1, br.V + 1); // Directly calculate the projected map corners in world units avoiding unnecessary // conversions. This abuses the definition that the width of the cell is always // 1024 units, and that the height of two rows is 2048 for classic cells and 1024 // for isometric cells. var wtop = tl.V * 1024; var wbottom = (br.V + 1) * 1024; if (Grid.Type == MapGridType.RectangularIsometric) { wtop /= 2; wbottom /= 2; } ProjectedTopLeft = new WPos(tl.U * 1024, wtop, 0); ProjectedBottomRight = new WPos(br.U * 1024 - 1, wbottom - 1, 0); ProjectedCellBounds = new ProjectedCellRegion(this, tl, br); }
public bool Contains(PPos puv) { return(Bounds.Contains(puv.U, puv.V)); }
public static int hash_PPos(PPos i2) { return(((i2.X * 5) ^ (i2.Y * 3)) / 4); }
public bool ShroudObscures(PPos uv) { return(RenderPlayer != null && !RenderPlayer.Shroud.IsExplored(uv)); }
public static PPos Min(PPos a, PPos b) { return new PPos(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y)); }
void InitializeCellProjection() { if (initializedCellProjection) return; initializedCellProjection = true; cellProjection = new CellLayer<PPos[]>(this); inverseCellProjection = new CellLayer<List<MPos>>(this); projectedHeight = new CellLayer<byte>(this); // Initialize collections foreach (var cell in AllCells) { var uv = cell.ToMPos(Grid.Type); cellProjection[uv] = new PPos[0]; inverseCellProjection[uv] = new List<MPos>(); } // Initialize projections foreach (var cell in AllCells) UpdateProjection(cell); }
public static ISound Play(string name, PPos pos, float volumeModifier) { return Play(null, name, false, pos, volumeModifier); }
void PostInit() { try { Rules = Ruleset.Load(modData, this, Tileset, RuleDefinitions, WeaponDefinitions, VoiceDefinitions, NotificationDefinitions, MusicDefinitions, SequenceDefinitions); } catch (Exception e) { InvalidCustomRules = true; Rules = Ruleset.LoadDefaultsForTileSet(modData, Tileset); Log.Write("debug", "Failed to load rules for {0} with error {1}", Title, e.Message); } Rules.Sequences.Preload(); var tl = new MPos(0, 0).ToCPos(this); var br = new MPos(MapSize.X - 1, MapSize.Y - 1).ToCPos(this); AllCells = new CellRegion(Grid.Type, tl, br); var btl = new PPos(Bounds.Left, Bounds.Top); var bbr = new PPos(Bounds.Right - 1, Bounds.Bottom - 1); SetBounds(btl, bbr); CustomTerrain = new CellLayer<byte>(this); foreach (var uv in AllCells.MapCoords) CustomTerrain[uv] = byte.MaxValue; AllEdgeCells = UpdateEdgeCells(); }
static ISound Play(Player player, string name, bool headRelative, PPos pos, float volumeModifier) { if (player != null && player != player.World.LocalPlayer) return null; if (name == "" || name == null) return null; return soundEngine.Play2D(sounds[name], false, headRelative, pos.ToFloat2(), InternalSoundVolume * volumeModifier); }
public static Actor ClosestTo(this IEnumerable <Actor> actors, PPos px) { return(actors.OrderBy(a => (a.CenterLocation - px).LengthSquared).FirstOrDefault()); }