/// <summary> /// Spawns treasure chests in treasure room. /// </summary> private void SpawnTreasureChests() { var region = this.Regions.Last(); var rnd = RandomProvider.Get(); for (int i = 0; i < _treasureChests.Count; ++i) { var pos = new Generation.Position(this.Generator.Floors.Last().MazeGenerator.EndPos); pos.X *= Dungeon.TileSize; pos.Y *= Dungeon.TileSize; pos.X += Dungeon.TileSize / 2; pos.Y += (int)(Dungeon.TileSize * 2.5f); var placement = _treasurePlacementProvider.GetPosition(); pos.X += placement[0]; pos.Y += placement[1]; var rotation = MabiMath.DegreeToRadian(placement[2]); var prop = _treasureChests[i]; prop.RegionId = region.Id; prop.Info.X = pos.X; prop.Info.Y = pos.Y; prop.Info.Direction = rotation; region.AddProp(prop); } }
public void InCone() { var centerPos = new Position(0, 0); var topPos = new Position(0, 500); var bottomPos = new Position(0, -500); var leftPos = new Position(-500, 0); var rightPos = new Position(500, 0); var up = MabiMath.DegreeToRadian(90); var down = MabiMath.DegreeToRadian(270); var left = MabiMath.DegreeToRadian(180); var right = MabiMath.DegreeToRadian(0); Assert.Equal(true, topPos.InCone(centerPos, up, 600, MabiMath.DegreeToRadian(10))); Assert.Equal(true, bottomPos.InCone(centerPos, down, 600, MabiMath.DegreeToRadian(10))); Assert.Equal(true, leftPos.InCone(centerPos, left, 600, MabiMath.DegreeToRadian(10))); Assert.Equal(true, rightPos.InCone(centerPos, right, 600, MabiMath.DegreeToRadian(10))); Assert.Equal(true, topPos.InCone(centerPos, up, 500, MabiMath.DegreeToRadian(10))); Assert.Equal(false, topPos.InCone(centerPos, up, 500, MabiMath.DegreeToRadian(180))); Assert.Equal(true, topPos.InCone(centerPos, up, 600, MabiMath.DegreeToRadian(180))); Assert.Equal(true, topPos.InCone(centerPos, up, 1000, MabiMath.DegreeToRadian(180))); Assert.Equal(true, topPos.InCone(centerPos, up, 1000, MabiMath.DegreeToRadian(190))); Assert.Equal(true, topPos.InCone(centerPos, up, 1000, MabiMath.DegreeToRadian(-190))); Assert.Equal(true, topPos.InCone(centerPos, up, 1000, MabiMath.DegreeToRadian(9999))); Assert.Equal(true, topPos.InCone(centerPos, up, 1000, MabiMath.DegreeToRadian(-9999))); Assert.Equal(false, topPos.InCone(centerPos, MabiMath.DegreeToRadian(45), 2000, MabiMath.DegreeToRadian(45))); Assert.Equal(true, topPos.InCone(centerPos, MabiMath.DegreeToRadian(68), 2000, MabiMath.DegreeToRadian(45))); }
public void GetRelative() { var pos1 = new Position(100, 100); var pos2 = new Position(100, 200); Assert.Equal(new Position(100, 250), pos1.GetRelative(pos2, 50)); Assert.Equal(new Position(100, 150), pos1.GetRelative(pos2, -50)); Assert.Equal(new Position(100, -50), pos1.GetRelative(pos2, -250)); var pos3 = new Position(50, 100); Assert.Equal(new Position(0, 100), pos1.GetRelative(pos3, 50)); Assert.Equal(new Position(100, 100), pos1.GetRelative(pos3, -50)); Assert.Equal(new Position(300, 100), pos1.GetRelative(pos3, -250)); var up = MabiMath.DegreeToRadian(90); var down = MabiMath.DegreeToRadian(270); var left = MabiMath.DegreeToRadian(180); var right = MabiMath.DegreeToRadian(0); Assert.Equal(new Position(100, 200), pos1.GetRelative(up, 100)); Assert.Equal(new Position(100, 0), pos1.GetRelative(down, 100)); Assert.Equal(new Position(0, 100), pos1.GetRelative(left, 100)); Assert.Equal(new Position(200, 100), pos1.GetRelative(right, 100)); }
public override void OnPuzzleCreate(Puzzle puzzle) { var lockedPlace = puzzle.GetPlace("LockedPlace"); var key = puzzle.LockPlace(lockedPlace, "Boss"); var chest = new Chest(puzzle, "KeyChest"); lockedPlace.AddProp(chest, Placement.Center); chest.Info.Direction = MabiMath.DegreeToRadian(90); chest.Add(Item.Create(GoddessPass)); chest.Add(key); }
public void GetDirection() { var up = MabiMath.DegreeToRadian(90); var down = MabiMath.DegreeToRadian(270); var left = MabiMath.DegreeToRadian(180); var right = MabiMath.DegreeToRadian(0); var pos = new Position(100, 100); Assert.Equal(up, pos.GetDirection(new Position(100, 200))); Assert.Equal(down, pos.GetDirection(new Position(100, 0))); Assert.Equal(left, pos.GetDirection(new Position(0, 100))); Assert.Equal(right, pos.GetDirection(new Position(200, 100))); }
/// <summary> /// Adds prop to puzzle in place. /// </summary> /// <param name="place"></param> /// <param name="prop"></param> /// <param name="positionType"></param> public void AddProp(PuzzlePlace place, DungeonProp prop, Placement positionType) { if (this.Region == null) { throw new PuzzleException("AddProp outside of OnPuzzleCreate."); } var pos = place.GetPosition(positionType); prop.RegionId = this.Region.Id; prop.Info.X = pos[0]; prop.Info.Y = pos[1]; prop.UpdateShapes(); prop.Info.Direction = MabiMath.DegreeToRadian(pos[2]); prop.Behavior += PuzzleEvent; this.Region.AddProp(prop); this.Props[prop.Name] = prop; }
/// <summary> /// Creates new door prop. /// </summary> /// <param name="propId"></param> /// <param name="regionId"></param> /// <param name="x"></param> /// <param name="y"></param> /// <param name="direction">Direction the door faces in, in degree.</param> /// <param name="doorType"></param> /// <param name="name"></param> /// <param name="state"></param> public Door(int propId, int regionId, int x, int y, int direction, DungeonBlockType doorType, string name, string state = "open") : base(propId, regionId, x, y, direction, 1, 0, state, "", "") { this.Name = name; this.DoorType = doorType; this.BlockBoss = false; this.Behavior = this.DefaultBehavior; _isSwitchDoor = false; _closedFrom = new Position(x / Dungeon.TileSize, y / Dungeon.TileSize); // Set direction and adjust Y for boss doors if (doorType == DungeonBlockType.BossDoor) { this.Info.Direction = MabiMath.DirectionToRadian(0, 1); this.Info.Y += Dungeon.TileSize + Dungeon.TileSize / 2; } else { this.Info.Direction = MabiMath.DegreeToRadian(direction); } }
/// <summary> /// Initiates floor, creating puzzles and props. /// </summary> /// <param name="iRegion"></param> public void InitFloorRegion(int iRegion) { this.CreatePuzzles(iRegion); var region = this.Regions[iRegion]; var floor = this.Generator.Floors[iRegion - 1]; var gen = floor.MazeGenerator; var floorData = this.Data.Floors[iRegion - 1]; var iPrevRegion = iRegion - 1; var iNextRegion = iRegion + 1; var startTile = gen.StartPos; var startPos = new Generation.Position(startTile.X * Dungeon.TileSize + Dungeon.TileSize / 2, startTile.Y * Dungeon.TileSize + Dungeon.TileSize / 2); var startRoomTrait = floor.GetRoom(startTile); var startRoomIncomingDirection = startRoomTrait.GetIncomingDirection(); var endTile = gen.EndPos; var endPos = new Generation.Position(endTile.X * Dungeon.TileSize + Dungeon.TileSize / 2, endTile.Y * Dungeon.TileSize + Dungeon.TileSize / 2); var endRoomTrait = floor.GetRoom(endTile); var endRoomDirection = 0; for (int dir = 0; dir < 4; ++dir) { if (endRoomTrait.Links[dir] == LinkType.To) { endRoomDirection = dir; break; } } // Create upstairs prop var stairsBlock = this.Data.Style.Get(DungeonBlockType.StairsUp, startRoomIncomingDirection); var stairs = new Prop(stairsBlock.PropId, region.Id, startPos.X, startPos.Y, MabiMath.DegreeToRadian(stairsBlock.Rotation), 1, 0, "single"); stairs.Info.Color1 = floorData.Color1; stairs.Info.Color2 = floorData.Color1; stairs.Info.Color3 = floorData.Color3; region.AddProp(stairs); // Create portal prop leading to prev floor var portalBlock = this.Data.Style.Get(DungeonBlockType.PortalUp, startRoomIncomingDirection); var portal = new Prop(portalBlock.PropId, region.Id, startPos.X, startPos.Y, MabiMath.DegreeToRadian(portalBlock.Rotation), 1, 0, "single", "_upstairs", Localization.Get("<mini>TO</mini> Upstairs")); portal.Info.Color1 = floorData.Color1; portal.Info.Color2 = floorData.Color1; portal.Info.Color3 = floorData.Color3; portal.Behavior = (cr, pr) => { // Indoor_RDungeon_EB marks the end position on the prev floor. var clientEvent = this.Regions[iPrevRegion].GetClientEvent("Indoor_RDungeon_EB"); if (clientEvent == null) { Log.Error("Event 'Indoor_RDungeon_EB' not found while trying to warp to '{0}'.", this.Regions[iPrevRegion].Name); return; } // Warp to prev region var regionId = this.Regions[iPrevRegion].Id; var x = (int)clientEvent.Data.X; var y = (int)clientEvent.Data.Y; cr.Warp(regionId, x, y); }; region.AddProp(portal); // Create save statue if (floorData.Statue) { var saveStatue = new Prop(this.Data.SaveStatuePropId, region.Id, startPos.X, startPos.Y, MabiMath.DegreeToRadian(stairsBlock.Rotation + 180), 1, 0, "single"); saveStatue.Info.Color1 = floorData.Color1; saveStatue.Info.Color2 = floorData.Color1; saveStatue.Info.Color3 = floorData.Color3; saveStatue.Behavior = (cr, pr) => { cr.DungeonSaveLocation = cr.GetLocation(); Send.Notice(cr, Localization.Get("You have memorized this location.")); // Scroll message var msg = string.Format("You're currently on Floor {0} of {1}. ", iRegion, this.Data.EngName); Send.Notice(cr, NoticeType.Top, ScrollMessageDuration, msg + this.GetPlayerListScrollMessage()); }; region.AddProp(saveStatue); } // Spawn boss or downstair props // TODO: There is one dungeon that has two boss rooms. if (floor.IsLastFloor) { // Create door to treasure room _bossExitDoor = new Prop(this.Data.BossExitDoorId, region.Id, endPos.X, endPos.Y + Dungeon.TileSize / 2, Rotation(Direction.Up), 1, 0, "closed"); _bossExitDoor.Info.Color1 = floorData.Color1; _bossExitDoor.Info.Color2 = floorData.Color1; _bossExitDoor.Info.Color3 = floorData.Color3; region.AddProp(_bossExitDoor); // Get or create boss door if (endRoomTrait.PuzzleDoors[Direction.Down] == null) { Log.Warning("Dungeon.InitFloorRegion: No locked place in last section of '{0}'.", this.Name); _bossDoor = new Door(this.Data.BossDoorId, region.Id, endPos.X, endPos.Y - Dungeon.TileSize, Direction.Up, DungeonBlockType.BossDoor, "", "closed"); _bossDoor.Info.Color1 = floorData.Color1; _bossDoor.Info.Color2 = floorData.Color1; _bossDoor.Info.Color3 = floorData.Color3; _bossDoor.Behavior = (cr, pr) => { _bossDoor.Open(); }; _bossDoor.Behavior += this.BossDoorBehavior; _bossDoor.UpdateShapes(); endRoomTrait.SetPuzzleDoor(_bossDoor, Direction.Down); // making sure another open dummy door won't be added here region.AddProp(_bossDoor); } else { _bossDoor = endRoomTrait.PuzzleDoors[Direction.Down]; if (_bossDoor.State == "open") { Log.Warning("Dungeon.InitFloorRegion: Boss door was left open, closing. Dungeon: '{0}'.", this.Name); _bossDoor.Close(endRoomTrait.X, endRoomTrait.Y); } } // Create exit statue var exitStatue = new Prop(this.Data.LastStatuePropId, region.Id, endPos.X, endPos.Y + Dungeon.TileSize * 2, Rotation(Direction.Up), 1, 0, "single"); exitStatue.Info.Color1 = floorData.Color1; exitStatue.Info.Color2 = floorData.Color1; exitStatue.Info.Color3 = floorData.Color3; exitStatue.Extensions.AddSilent(new ConfirmationPropExtension("GotoLobby", "_LT[code.standard.msg.dungeon_exit_notice_msg]", "_LT[code.standard.msg.dungeon_exit_notice_title]", "haskey(chest)")); exitStatue.Behavior = (cr, pr) => { ChannelServer.Instance.Events.OnPlayerClearedDungeon(cr, this); cr.Warp(this.Data.Exit); }; region.AddProp(exitStatue); } else { // Create downstairs prop var stairsDownBlock = this.Data.Style.Get(DungeonBlockType.StairsDown, endRoomDirection); var stairsDown = new Prop(stairsDownBlock.PropId, region.Id, endPos.X, endPos.Y, MabiMath.DegreeToRadian(stairsDownBlock.Rotation), 1, 0, "single"); stairsDown.Info.Color1 = floorData.Color1; stairsDown.Info.Color2 = floorData.Color1; stairsDown.Info.Color3 = floorData.Color3; region.AddProp(stairsDown); // Create portal leading to the next floor var portalDownBlock = this.Data.Style.Get(DungeonBlockType.PortalDown, endRoomDirection); var portalDown = new Prop(portalDownBlock.PropId, region.Id, endPos.X, endPos.Y, MabiMath.DegreeToRadian(portalDownBlock.Rotation), 1, 0, "single", "_downstairs", Localization.Get("<mini>TO</mini> Downstairs")); portalDown.Info.Color1 = floorData.Color1; portalDown.Info.Color2 = floorData.Color1; portalDown.Info.Color3 = floorData.Color3; portalDown.Behavior = (cr, pr) => { // Indoor_RDungeon_SB marks the start position on the next floor. var clientEvent = this.Regions[iNextRegion].GetClientEvent("Indoor_RDungeon_SB"); if (clientEvent == null) { Log.Error("Event 'Indoor_RDungeon_SB' not found while trying to warp to '{0}'.", this.Regions[iNextRegion].Name); return; } // Warp to next floor var regionId = this.Regions[iNextRegion].Id; var x = (int)clientEvent.Data.X; var y = (int)clientEvent.Data.Y; cr.Warp(regionId, x, y); }; region.AddProp(portalDown); } // Place dummy doors for (int x = 0; x < floor.MazeGenerator.Width; ++x) { for (int y = 0; y < floor.MazeGenerator.Height; ++y) { var room = floor.MazeGenerator.GetRoom(x, y); var roomTrait = floor.GetRoom(x, y); var isRoom = (roomTrait.RoomType >= RoomType.Start); if (!room.Visited || !isRoom) { continue; } for (var dir = 0; dir < 4; ++dir) { // Skip stairs if (roomTrait.RoomType == RoomType.Start && dir == startRoomIncomingDirection) { continue; } if (roomTrait.RoomType == RoomType.End && dir == endRoomDirection) { continue; } if (roomTrait.Links[dir] == LinkType.None) { continue; } if (roomTrait.PuzzleDoors[dir] == null) { var doorX = x * Dungeon.TileSize + Dungeon.TileSize / 2; var doorY = y * Dungeon.TileSize + Dungeon.TileSize / 2; var doorBlock = this.Data.Style.Get(DungeonBlockType.Door, dir); var doorProp = new Prop(doorBlock.PropId, region.Id, doorX, doorY, MabiMath.DegreeToRadian(doorBlock.Rotation), state: "open"); doorProp.Info.Color1 = floorData.Color1; doorProp.Info.Color2 = floorData.Color2; doorProp.Info.Color3 = floorData.Color3; region.AddProp(doorProp); } else if (roomTrait.PuzzleDoors[dir].EntityId == 0) { // Add doors from failed puzzles roomTrait.PuzzleDoors[dir].Info.Region = region.Id; region.AddProp(roomTrait.PuzzleDoors[dir]); } } } } }
/// <summary> /// Generates areas, incl (client) props and events. /// </summary> private void GenerateAreas() { this.Data = new RegionInfoData(); var areaId = 2; var floor = this.Floor; for (int x = 0; x < floor.MazeGenerator.Width; ++x) { for (int y = 0; y < floor.MazeGenerator.Height; ++y) { var room = floor.MazeGenerator.GetRoom(x, y); var roomTrait = floor.GetRoom(x, y); if (!room.Visited) { continue; } var isStart = (roomTrait.RoomType == RoomType.Start); var isEnd = (roomTrait.RoomType == RoomType.End); var isRoom = (roomTrait.RoomType >= RoomType.Start); var isBossRoom = (floor.HasBossRoom && isEnd); var eventId = 0L; if (!isBossRoom) { var areaData = new AreaData(); areaData.Id = areaId++; areaData.Name = "Tile" + areaData.Id; areaData.X1 = x * Dungeon.TileSize; areaData.Y1 = y * Dungeon.TileSize; areaData.X2 = x * Dungeon.TileSize + Dungeon.TileSize; areaData.Y2 = y * Dungeon.TileSize + Dungeon.TileSize; this.Data.Areas.Add(areaData); var type = (isRoom ? DungeonBlockType.Room : DungeonBlockType.Alley); var propEntityId = MabiId.ClientProps | ((long)this.Id << 32) | ((long)areaData.Id << 16) | 1; var block = this.Dungeon.Data.Style.Get(type, room.Directions); var tileCenter = new Point(x * Dungeon.TileSize + Dungeon.TileSize / 2, y * Dungeon.TileSize + Dungeon.TileSize / 2); var prop = new Prop(propEntityId, block.PropId, this.Id, tileCenter.X, tileCenter.Y, MabiMath.DegreeToRadian(block.Rotation), 1, 0, "", "", ""); this.AddProp(prop); // Debug //foreach (var points in prop.Shapes) //{ // foreach (var point in points) // { // var pole = new Prop(30, this.Id, point.X, point.Y, 0, 1, 0, "", "", ""); // pole.Shapes.Clear(); // this.AddProp(pole); // } //} // TODO: This region/data stuff is a mess... create // proper classes, put them in the regions and be // done with it. if (isStart || isEnd) { var xp = tileCenter.X; var yp = tileCenter.Y; if (roomTrait.DoorType[Direction.Up] >= 3000) { yp += 400; } else if (roomTrait.DoorType[Direction.Right] >= 3000) { xp += 400; } else if (roomTrait.DoorType[Direction.Down] >= 3000) { yp -= 400; } else if (roomTrait.DoorType[Direction.Left] >= 3000) { xp -= 400; } var eventData = new EventData(); eventData.Id = MabiId.AreaEvents | ((long)this.Id << 32) | ((long)areaData.Id << 16) | eventId++; eventData.Name = (isStart ? "Indoor_RDungeon_SB" : "Indoor_RDungeon_EB"); eventData.X = xp; eventData.Y = yp; var shape = new ShapeData(); shape.DirX1 = 1; shape.DirY2 = 1; shape.LenX = 100; shape.LenY = 100; shape.PosX = xp; shape.PosY = yp; eventData.Shapes.Add(shape); areaData.Events.Add(eventData.Id, eventData); _clientEvents.Add(eventData.Id, new ClientEvent(eventData, this.Data.Name, areaData.Name)); } } else { // Big main room var areaData = new AreaData(); areaData.Id = areaId++; areaData.Name = "Tile" + areaData.Id; areaData.X1 = x * Dungeon.TileSize - Dungeon.TileSize; areaData.Y1 = y * Dungeon.TileSize; areaData.X2 = x * Dungeon.TileSize + Dungeon.TileSize * 2; areaData.Y2 = y * Dungeon.TileSize + Dungeon.TileSize * 2; this.Data.Areas.Add(areaData); var block = this.Dungeon.Data.Style.Get(DungeonBlockType.BossRoom); var propEntityId = MabiId.ClientProps | ((long)this.Id << 32) | ((long)areaData.Id << 16) | 1; var tileCenter = new Point(x * Dungeon.TileSize + Dungeon.TileSize / 2, y * Dungeon.TileSize + Dungeon.TileSize); var prop = new Prop(propEntityId, block.PropId, this.Id, tileCenter.X, tileCenter.Y, MabiMath.DegreeToRadian(block.Rotation), 1, 0, "", "", ""); this.AddProp(prop); // Debug //foreach (var points in prop.Shapes) //{ // foreach (var point in points) // { // var pole = new Prop(30, this.Id, point.X, point.Y, 0, 1, 0, "", "", ""); // pole.Shapes.Clear(); // this.AddProp(pole); // } //} // Treasure room areaData = new AreaData(); areaData.Id = areaId++; areaData.Name = "Tile" + areaData.Id; areaData.X1 = x * Dungeon.TileSize; areaData.Y1 = y * Dungeon.TileSize + Dungeon.TileSize * 2; areaData.X2 = x * Dungeon.TileSize + Dungeon.TileSize; areaData.Y2 = y * Dungeon.TileSize + Dungeon.TileSize * 2 + Dungeon.TileSize; this.Data.Areas.Add(areaData); } } } }
public override void OnCreation(Dungeon dungeon) { var region = dungeon.Regions.Last(); var bossLocation = dungeon.GetBossRoomCenter(); // Gargoyles region.AddProp(new Prop(29001, bossLocation.RegionId, bossLocation.X, bossLocation.Y, 0)); region.AddProp(new Prop(29002, bossLocation.RegionId, bossLocation.X, bossLocation.Y, 0)); region.AddProp(new Prop(29003, bossLocation.RegionId, bossLocation.X, bossLocation.Y, MabiMath.DegreeToRadian(90))); region.AddProp(new Prop(29004, bossLocation.RegionId, bossLocation.X, bossLocation.Y, MabiMath.DegreeToRadian(90))); region.AddProp(new Prop(29005, bossLocation.RegionId, bossLocation.X, bossLocation.Y, 0)); region.AddProp(new Prop(29006, bossLocation.RegionId, bossLocation.X, bossLocation.Y, 0)); }