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