diff --git a/Iceboat.py b/Iceboat.py index b7498e8..56428bc 100644 --- a/Iceboat.py +++ b/Iceboat.py @@ -2,14 +2,14 @@ # 冰船系统 by DreamCityToger import time import pyspigot as ps -from org.bukkit import Bukkit, Sound, Location, Material, Particle, SoundCategory, GameMode +from org.bukkit import Bukkit, Sound, Location, Material, Particle, SoundCategory, GameMode, ChatColor from org.bukkit.util import Vector from org.bukkit.block import BlockFace -from org.bukkit.entity import Player, EntityType, Boat, ArmorStand +from org.bukkit.entity import Player, EntityType, Boat, ArmorStand, ItemDisplay from org.bukkit.Bukkit import getServer from org.bukkit.inventory import ItemStack from org.bukkit.inventory.EquipmentSlot import HAND -from org.bukkit.scoreboard import Criteria +from org.bukkit.scoreboard import Criteria, DisplaySlot, Team from org.bukkit.event.block import Action from org.bukkit.event.vehicle import VehicleExitEvent from org.bukkit.event.world import EntitiesLoadEvent @@ -29,8 +29,11 @@ from org.bukkit.event.player import PlayerArmorStandManipulateEvent from org.bukkit.potion import PotionEffect, PotionEffectType from org.bukkit.NamespacedKey import fromString -#from com.destroystokyo.paper.event.player import PlayerStopSpectatingEntityEvent +from io.papermc.paper.scoreboard.numbers import NumberFormat + +from com.destroystokyo.paper.event.player import PlayerStopSpectatingEntityEvent from net.milkbowl.vault.economy import Economy +from net.kyori.adventure.text import Component from net.md_5.bungee.api.chat import TextComponent from net.md_5.bungee.api.ChatMessageType import ACTION_BAR @@ -66,6 +69,7 @@ playerHeadsAPI = PlayerHeadsAPI() # 初始化Player Heads # 全局常量变量 ------------------------------------------------------------------- MAX_PLAYERS = 8 #单房间最多可以加入的玩家数量 +MIN_COMPETITION_PLAYERS = 1 #比赛最少需要的玩家数量 AVAILABLE_MAPNUM = 39 #可用地图数量 WORLD_NAME = u'iceboat' #世界名 LEAVE_INTERVAL = 12 #玩家离开房间操作要求(刻) @@ -74,9 +78,12 @@ ROOMS_CONFIG_PATH = u'iceboat/rooms.yml' #房间配置文件路径 HOLOGRAME_CONFIG_PATH = u'iceboat/hologram.yml' START_LINE_MATERIAL = Material.GLASS #启动线材料(默认玻璃) ENDING_INTERVAL = 60 #结束时间间隔(刻) +ENDING_COUNTDOWN = 600 #结束倒计时(刻) 至少为200 ARMOR_STAND_INTERVAL = 0.26 #盔甲架间距 LOBBY_POSITION = 0, 64, 0 #大厅位置 LOBBY_RADIUS = 300 #大厅半径 +BOAT_PITCH = 27 +PLAYER_RADIUS = 48 #玩家渲染距离 DEFAULT_BOAT_MATERIAL = u'OAK_BOAT' #默认船类型 DEFAULT_BOAT_DISPLAY = u'橡木船' #默认船展示名 DEFAULT_PARTICLE_MATERIAL = u'END_ROD' #默认粒子材质 @@ -85,6 +92,8 @@ DEFAULT_PARTICLE_DISPLAY = u'烛光' #默认粒子展示名 DEFAULT_TITLE_DISPLAY = u'新手' #默认称号展示名 DEFAULT_TITLE_MATERIAL = u'NAME_TAG' #默认称号材质 REWARD_AMOUNT = 100 #默认奖励金额基准 +ADVERTISEMENT_TEXT_1 = u"§e● DC商业梦想城官网" +ADVERTISEMENT_TEXT_2 = u"§f○ https://mcrail.top/" SIGNS = [ #告示牌类型 Material.OAK_SIGN, Material.OAK_WALL_SIGN, Material.SPRUCE_SIGN, Material.SPRUCE_WALL_SIGN, @@ -100,6 +109,7 @@ SIGNS = [ #告示牌类型 Material.PALE_OAK_SIGN, Material.PALE_OAK_WALL_SIGN ] + singleGames = {} #单人游戏房间 multiGames = {} #多人游戏房间 playersInParticlePreview = {} #预览玩家 @@ -135,6 +145,10 @@ class PlayerManager: #玩家管理 return True if self.leaveMultiRoom(): return True + if self.leaveSpectateRoom(): + return True + if self.leaveCompetition(): + return True self.player.sendTitle(u"§f", u"§c你不在任何游戏房间中", 5, 60, 10) self.player.playSound(self.player, Sound.ENTITY_VILLAGER_NO, 1.0, 1.0) return False @@ -142,7 +156,6 @@ class PlayerManager: #玩家管理 singleRoom = self.inSingleRoom() if singleRoom: #如果在单人房间内 singleRoom.closeRoom() - self.player.sendTitle(u"§f", u"§6离开成功", 5, 60, 10) self.player.playSound(self.player, Sound.BLOCK_NOTE_BLOCK_BASS, 1.0, 1.0) return True return False @@ -150,10 +163,22 @@ class PlayerManager: #玩家管理 multiRoom = self.inMultiRoom() if multiRoom: #如果在多人房间内 multiRoom.delPlayer(self.playerName) - self.player.sendTitle(u"§f", u"§6离开成功", 5, 60, 10) self.player.playSound(self.player, Sound.BLOCK_NOTE_BLOCK_BASS, 1.0, 1.0) return True return False + def leaveSpectateRoom(self): + spectateRoom = self.inSpectateRoom() + if spectateRoom: #如果在旁观者房间内 + spectateRoom.leave() + self.player.playSound(self.player, Sound.BLOCK_NOTE_BLOCK_BASS, 1.0, 1.0) + return True + def leaveCompetition(self): + competition = self.inCompetition() + if competition: #如果在比赛房间内 + competition.delPlayer(self.playerName) + competition.delPlayer(self.playerName) + self.player.playSound(self.player, Sound.BLOCK_NOTE_BLOCK_BASS, 1.0, 1.0) + return True def delayExit(self): #延迟离开载具判定 objective = getScoreboardObjective(u'IBLeaveAction') playerScore = objective.getScore(self.playerName) #获取玩家 @@ -178,24 +203,25 @@ class PlayerManager: #玩家管理 inv.clear() def getItemstacks(): #异步获取物品 itemstacks = {} - itemstacks[3] = initializeItemStack(Material.SLIME_BALL, u"§e>> §a单人模式 §e<<") - itemstacks[5] = initializeItemStack(Material.MAGMA_CREAM, u"§6>> §c快速离开 §6<<") - itemstacks[19] = initializeItemStack(Material.SPYGLASS, u"§6>> §b打开粒子预览页面 §6<<", u"§7仅在大厅可预览粒子效果") - itemstacks[21] = initializeItemStack(Material.CHEST, u"§6>> §b打开收集品菜单 §6<<", u'§7设置船/粒子/称号等') - itemstacks[23] = initializeItemStack(Material.PAPER, u"§6>> §b打开驾照等级页面 §6<<", u"§7查看驾照等级要求和升级") - itemstacks[25] = initializeItemStack(Material.SKULL_BANNER_PATTERN, u"§6>> §b打开排名查询页面 §6<<", u'§7查询全服玩家各数据排名') - itemstacks[27] = initializeItemStack(Material.BEACON, u"§6>> §e切换成绩广播模式 §6<<", u'§7将成绩广播给同世界玩家') - itemstacks[29] = initializeItemStack(Material.FIREWORK_STAR, u"§6>> §e切换粒子模式 §6<<", u'§7使用自定义粒子效果') - itemstacks[31] = initializeItemStack(Material.OAK_HANGING_SIGN, u"§6>> §e切换详细播报模式 §6<<", u'§7在聊天框播报详细信息') - itemstacks[33] = initializeItemStack(Material.NOTE_BLOCK, u"§6>> §e切换音乐模式 §6<<", u'§7需安装冰船音乐资源包') - itemstacks[35] = initializeItemStack(Material.JUKEBOX, u"§6>> §c关闭当前音乐 §6<<", u'§7需安装冰船音乐资源包') + itemstacks[4] = initializeItemStack(Material.SLIME_BALL, u"§e>> §a单人模式 §e<<") + itemstacks[6] = initializeItemStack(Material.MUSIC_DISC_RELIC, u"§6>> §c关闭当前音乐 §6<<", u'§7需安装冰船音乐资源包') + itemstacks[2] = initializeItemStack(Material.MAGMA_CREAM, u"§6>> §c离开房间 §6<<") + itemstacks[9] = initializeItemStack(Material.CHEST, u"§6>> §b打开收集品菜单 §6<<", u'§7设置船/粒子/称号等') + itemstacks[11] = initializeItemStack(Material.SPYGLASS, u"§6>> §b打开粒子预览页面 §6<<", u"§7仅在大厅可预览粒子效果") + itemstacks[13] = initializeItemStack(Material.ENDER_EYE, u"§6>> §b打开旁观选择页面 §6<<", u'§7选择旁观玩家') + itemstacks[15] = initializeItemStack(Material.PAPER, u"§6>> §b打开驾照等级页面 §6<<", u"§7查看驾照等级要求和升级") + itemstacks[17] = initializeItemStack(Material.SKULL_BANNER_PATTERN, u"§6>> §b打开排名查询页面 §6<<", u'§7查询全服玩家各数据排名') return itemstacks def setItemstacks(itemstacks): #同步设置物品 for slot, itemstack in itemstacks.items(): inv.setItem(slot, itemstack) ps.scheduler.runSyncCallbackTask(getItemstacks, setItemstacks) #同步回调 - self.updateInventoryPlayerInfo() #更新玩家背包玩家信息显示 + ps.scheduler.runTaskLater(lambda s=self: self.updateInventoryPlayerInfo(), 1) #更新玩家背包玩家信息显示 self.updateInventoryPlayAgain() #更新玩家背包再来一把显示 + self.updateInventoryMode(mode=u"detail") + self.updateInventoryMode(mode=u"broadcast") + self.updateInventoryMode(mode=u"music") + self.updateInventoryMode(mode=u"particle") def updateInventoryPlayerInfo(self): #更新玩家背包玩家信息显示 worldName = self.player.getWorld().getName() if worldName != WORLD_NAME: #只修改冰船世界的玩家背包 @@ -204,7 +230,7 @@ class PlayerManager: #玩家管理 def getItemstackPlayerInfo(): #异步获取物品 playerName = self.player.getName() playerData = PlayerDataManager(playerName) - itemstack = initializeItemStack(playerHeadsAPI.getPlayerHead(playerName), u"§6〓 §a玩家信息 §6〓", + itemstack = initializeItemStack(playerHeadsAPI.getPlayerHead(playerName), u"§6〓 §a{} §6〓".format(self.playerName), u'§eDC币余额: §f{}'.format(playerData.getBalance()), u'§e完成次数: §f{}'.format(playerData.getTotalMapTimes()), u'§e当季分数: §f{}'.format(playerData.getSeasonScore()), @@ -214,7 +240,7 @@ class PlayerManager: #玩家管理 ) return itemstack def setItemstackPlayerInfo(itemstack): #同步设置物品 - inv.setItem(13, itemstack) + inv.setItem(8, itemstack) ps.scheduler.runSyncCallbackTask(getItemstackPlayerInfo, setItemstackPlayerInfo) def updateInventoryPlayAgain(self): worldName = self.player.getWorld().getName() @@ -228,15 +254,67 @@ class PlayerManager: #玩家管理 itemstack = initializeItemStack(Material.NETHER_STAR, u"§6>> §a再来一把 §e{} §6<<".format(mapDisplay), u"§7快速进入上次游玩的地图(单人模式)", data=str(lastMap)) return itemstack def setItemstackPlayAgain(itemstack): #同步设置物品 - inv.setItem(1, itemstack) + inv.setItem(0, itemstack) ps.scheduler.runSyncCallbackTask(getItemstackPlayAgain, setItemstackPlayAgain) + def updateInventoryMode(self, mode=u"detail"): + #类型有detail/music/broadcast/particle + worldName = self.player.getWorld().getName() + if worldName != WORLD_NAME: #只修改冰船世界的玩家背包 + return + inv = self.player.getInventory() + def getItemstackMode(): #异步获取物品 + playerData = PlayerDataManager(self.playerName) + isOn = False + place = 28 + display = u"§f未命名" + material = Material.BARRIER + if mode == u"broadcast": + isOn = playerData.getBroadcastMode() + display = u"§6>> §e切换成绩广播模式 §6<<" + description = u'§7将成绩广播给同世界玩家' + material = Material.BEACON + place = 28 + elif mode == u"music": + isOn = playerData.getMusicMode() + display = u"§6>> §e切换音乐模式 §6<<" + description = u'§7需安装冰船音乐资源包' + material = Material.NOTE_BLOCK + place = 34 + elif mode == u"particle": + isOn = playerData.getParticleMode() + display = u"§6>> §e切换粒子模式 §6<<" + description = u'§7使用自定义粒子效果' + material = Material.FIREWORK_STAR + place = 30 + else: + isOn = playerData.getDetailMode() + display = u"§6>> §e切换详细播报模式 §6<<" + description = u'§7在聊天框播报详细信息' + material = Material.OAK_HANGING_SIGN + place = 32 + lores = [u'§e当前状态: {}'.format(u"§f启用中" if isOn else u"§7未启用"), description] + itemstack = initializeItemStack(material, display, *lores) + return itemstack, place + def setItemstackMode(result): #同步设置物品 + itemstack, place = result + inv.setItem(place, itemstack) + ps.scheduler.runSyncCallbackTask(getItemstackMode, setItemstackMode) def removePlayerFromRoom(self): #将玩家从任一房间移除 for roomId, room in multiGames.items(): if self.playerName in room.playerList: room.delPlayer(self.playerName) if self.playerName in singleGames: - del singleGames[self.playerName] + singleGames[self.playerName].closeRoom() + if self.playerName in playersInSpectate: + playersInSpectate[self.playerName].leave() + if self.playerName in competitionGame.playerList: + competitionGame.delPlayer(self.playerName) + competitionGame.delPlayer(self.playerName) def joinSingleRoom(self, mapNum): + if (self.inAnyRoom()) or (not self.inLobby()): #房间内禁止其它操作 + self.player.sendMessage(u"§c你已经在某房间中了") + self.player.playSound(self.player, Sound.ENTITY_VILLAGER_NO, 1.0, 1.0) + return False available = roomsManager.getAvailableRoomCount(mapNum) if available > 0: mapNum = int(mapNum) @@ -258,9 +336,32 @@ class PlayerManager: #玩家管理 self.player.playSound(self.player, Sound.ENTITY_VILLAGER_NO, 1.0, 1.0) self.player.sendMessage(u"§c该地图暂无空房,请稍后再试") return False + def actionCooldown(self): + objective = getScoreboardObjective(u'IBActionCooldown') + playerScore = objective.getScore(self.playerName) + lastAction = playerScore.getScore() + timestamp = time.time() + currentTime = int(timestamp * 10) % 10000000 + if lastAction != 0: + cooldown = currentTime - lastAction + if cooldown < 3: #0.5秒 + return True + else: + playerScore.setScore(currentTime) + return False + else: + playerScore.setScore(currentTime) + return False + def joinCompetitionTeam(self): + team = getScoreboardTeam(u"Competition") + team.addEntry(self.playerName) + def leaveCompetitionTeam(self): + team = getScoreboardTeam(u"Competition") + if team.hasEntry(self.playerName): + team.removeEntry(self.playerName) #玩家判定 def inAnyRoom(self): #检查玩家是否在任一房间内 - if self.inMultiRoom() or self.inSingleRoom(): + if self.inMultiRoom() or self.inSingleRoom() or self.inSpectateRoom() or self.inCompetition(): return True return False def inSingleRoom(self): @@ -272,6 +373,14 @@ class PlayerManager: #玩家管理 if room.isPlayerInRoom(self.playerName): return room #返回房间实例 return False + def inSpectateRoom(self): + if self.playerName in playersInSpectate: + return playersInSpectate[self.playerName] + return False + def inCompetition(self): + if self.playerName in competitionGame.playerList: + return competitionGame + return False def inLobby(self): #检查玩家是否在大厅内 playerLocation = self.player.getLocation() playerX = playerLocation.getX() @@ -516,7 +625,10 @@ class PlayerDataManager: #玩家数据管理 def toggleModeBoolean(self, mode='detailMode'): #切换模式布尔值 if mode not in ['particleMode', 'musicMode', 'detailMode', 'broadcastMode']: return False - currentValue = self.playerData.getBoolean(u"setting.{}".format(mode), False) + if mode in ['broadcastMode', 'particleMode']: + currentValue = self.playerData.getBoolean(u"setting.{}".format(mode), True) + else: + currentValue = self.playerData.getBoolean(u"setting.{}".format(mode), False) newValue = not currentValue self.playerData.set(u"setting.{}".format(mode), newValue) self.playerData.save() @@ -632,10 +744,6 @@ class CollectionManager: #收集品管理 if level is not None: return ["level", level] - totalTimes = iteminfo.get("totalTimes", None) - if totalTimes is not None: - return ["totalTimes", totalTimes] - record = iteminfo.get("record", None) if record is not None: maps = list(record.getKeys(False)) @@ -709,6 +817,12 @@ class SeasonManager: #季节管理 def getSeasonMaps(self): #获取当前季节地图列表 self.seasonMaps = list(self.seasonData.get("maps").getKeys(False)) return self.seasonMaps + def getSeasonFirstMap(self): #获取当前季节第一图 + self.seasonMaps = self.getSeasonMaps() #获取当前季节地图列表 + self.seasonFirstMap = self.seasonMaps[0] #获取当前季节第一图 + if self.seasonFirstMap: + return self.seasonFirstMap + return int(1) def inSeasonMaps(self, mapNum): #判断地图是否存在于当前季节 seasonMaps = self.getSeasonMaps() #获取当前季节地图列表 if str(mapNum) in seasonMaps: #如果地图已存在于当前季节 @@ -731,8 +845,6 @@ class SeasonManager: #季节管理 maps = list(recordSection.getKeys(False)) else: maps = list(recordSection.keys()) - print(playerName) - print(maps) for mapNum in maps: mapSection = recordSection.get(mapNum) if mapSection is not None: @@ -1240,681 +1352,88 @@ guiManager = GUIManager() #菜单管理 # 房间相关 ------------------------------------------------------------------- -class MultiGameRoom: #多人游戏房间类 - def __init__(self, roomId): - self.roomId = roomId - self.mapNum = 1 #默认1号地图 - self.roomNum = 1 #默认1号房 - self.map = None - self.playerCount = 0 # 房间内玩家数量 - self.finishCount = 0 # 完成玩家数量 - - self.playerList = {} # PlayerInGame对象的字典,键为玩家名称 - self.activeTasks = {} # 统一管理所有任务 - - self.rankList = [] #实时排名 - self.finishList = [] #完成列表 - self.mapDisplayArmorStands = [] # 存储该房间的盔甲架实体 - self.mapDisplayItemFrame = None # 存储该房间的展示框实体 - - self.isRunning = False #运行状态 包含Preparing和Gaming - self.isPreparing = False #准备状态 - self.isGaming = False #游戏状态 包含Starting和Ending - self.isStarting = False #开始状态 - self.isEnding = False #结束状态 - self.isClosed = False #是否关闭 - self.allFinished = False #是否所有玩家都完成 - - self.playerMapTimes = {} - self.playerTotalMapTimes = {} - # 房间管理 ---------------------------------------------- - def isEmpty(self): #判断房间是否为空 - return self.playerCount == 0 - def setIceboatMap(self, mapNum, roomNum): #设置房间地图对象 - self.mapNum = mapNum - self.roomNum = roomNum - self.map = IceboatMap(self.mapNum, self.roomNum) - def setMapNum(self, mapNum): #设置房间地图编号 +class IceboatMap: #地图类 + def __init__(self, mapNum, maproomNum): + self.mapNum = int(mapNum) - def setRoomNum(self, roomNum): #设置房间房号 - self.roomNum = roomNum - def save(self): # 更新房间对象 - multiGames[self.roomId] = self - # 玩家管理 ---------------------------------------------- - def addPlayer(self, playerName): #玩家进入房间 - if self.isRunning: #若房间已开启 - return False, u"房间已启动,无法加入" + self.maproomNum = int(maproomNum) + self.world = getServer().getWorld(WORLD_NAME) + #地图配置数据 + self.mapData = MapManager(self.mapNum) + self.yaw = self.mapData.getYaw() + self.lap = self.mapData.getLap() + self.point = self.mapData.getPoint() + self.display = self.mapData.getDisplay() + self.difficulty = self.mapData.getDifficulty() + #地图坐标字典集 + self.pointPositionDict = {} + points = self.mapData.getPoints() + #计算坐标 join + dimensions = [] + for axis in ['x', 'y', 'z']: + a = points.getInt('join.{}'.format(axis)) + if axis == 'x': + a = a + (self.mapNum * 10000) + if axis == 'z': + a = a + (self.maproomNum * 10000) + dimensions.append(a) + self.pointPositionDict['join'] = list(dimensions) + self.pointPositionDict['join'].append(self.yaw) + self.pointPositionDict['join'].append(0) #pitch 0 - if self.playerCount >= MAX_PLAYERS: #若房间已满 - return False, u"房间已满,无法加入" - - if playerName in self.playerList: #若玩家已经在房间内 - return False, u"你已在该房间内" - - initial = False - if self.playerCount == 0: #若房间为空的时候进行初始化 - initial = True - - self.playerList[playerName] = PlayerInGame(playerName) #创建玩家对象 - if initial: - mapNum = self.playerList[playerName].playerData.getLastMap() #获取玩家上一次玩的地图 - self.setMapNum(mapNum) #设置房间地图编号 - self.map = IceboatMap(self.mapNum, self.roomNum) #设置地图 - self.createMapDisplayItemFrame() # 地图显示功能 - - self.playerCount += 1 #玩家数量+1 - - self.createMapDisplayArmorStands() # 更新全息显示 - self.save() # 保存房间状态 - - return True, u"成功加入房间" - def delPlayer(self, playerName): #玩家在游戏中离开房间 - if playerName in self.playerList: #若玩家在房间内 - # 清理玩家关联的循环任务 - if playerName in self.activeTasks: - for taskId in self.activeTasks[playerName]: - if taskId is not None: - ps.scheduler.stopTask(taskId) - del self.activeTasks[playerName] - #玩家设置 - playerObj = self.playerList[playerName] #获取玩家对象 - if self.isRunning: #启动后才执行的内容 - playerObj.teleportToJoinLoc() #传送回进入房间前的位置 - self.broadcastMessage( - u"§b[§e{}§b] {}[{}]§f{} §a离开了房间".format( - self.map.display, playerObj.playerData.getLevelColor(), - playerObj.playerData.getTitleDisplay() ,playerObj.name - ) - ) #游戏内播报退出 - if self.isPreparing: #准备中才执行的内容 - playerObj.stopReadyParticle() #停止准备粒子效果 - playerObj.unsetInvisible() #取消隐身 - if self.isStarting: #游戏开始中才执行的内容 - playerObj.stopActionBarUpdates() #停止ActionBar更新 - playerObj.stopParticle() #停止粒子效果 - if self.isGaming: #游戏中才执行的内容 - playerObj.clearBoat() #离开时清理绑定的船 - del self.playerList[playerName] #删除玩家对象 - if not self.isClosed: # 房间未关闭时执行的内容 - self.createMapDisplayArmorStands() # 更新全息显示 - #房间设置 - self.playerCount -= 1 #玩家数量-1 - self.save() #保存房间状态 - if self.isEmpty(): #最后一个玩家离开 - self.closeRoom() #关闭房间 - def rankPlayerInGame(self): #更新房间内玩家排名 - players = list(self.playerList.values()) # 获取所有玩家对象 - # 多级排序:圈数(降) -> 检查点(降) -> 单圈时间戳() -> 名字(升) - players.sort(key=lambda p: ( - -p.lap, - -p.point, - p.passMoment, - p.name.lower() - )) - players = list(filter(lambda x: x not in self.finishList, players)) #过滤掉完成的玩家 - self.rankList = players # 存储排名好的对象列表 - for rank, player in enumerate(players, start=self.finishCount+1): # 更新未完成的玩家排名 - player.updateRank(rank) - def isPlayerInRoom(self, playerName): #判断玩家是否在房间内 - if playerName in self.playerList: - return True - return False - def settleFinishedPlayer(self, playerObj): #完成玩家结算 - self.finishCount += 1 - self.finishList.append(playerObj) - finishTime = playerObj.timer #完成时间戳 - playerObj.finishTime = finishTime - # 为所有玩家广播消息 - message = u"§b[§e{}§b] §a第 §e{} §a名 {}[{}]§f{} §a总用时 §e{:.2f} §a秒".format( - self.map.display, playerObj.rank, playerObj.playerData.getLevelColor(), - playerObj.playerData.getTitleDisplay() ,playerObj.name, finishTime) - if playerObj.broadcastMode: #如果开启了成绩广播模式 - broadcast(message) - else: - self.broadcastMessage(message) - playerObj.hasFinished = True # 标记玩家已完成 - playerObj.playSound(Sound.ENTITY_FIREWORK_ROCKET_LAUNCH, 1.0, 1.0) - playerObj.playSound(Sound.ENTITY_FIREWORK_ROCKET_TWINKLE, 1.0, 1.0) - playerObj.stopActionBarUpdates() - playerObj.stopParticle() - playerObj.finishAddVault() - record = playerObj.checkMultiRecord(self.map.mapNum) - if record: #纪录更新 - record = float(record) - playerObj.playSound(Sound.ENTITY_PLAYER_LEVELUP, 1.0, 1.0) - self.broadcastMessage( - u"§b[§e{}§b] {}[{}]§f{} §a刷新了多人纪录!§7(旧纪录:{:.2f})".format( - self.map.display, playerObj.playerData.getLevelColor(), - playerObj.playerData.getTitleDisplay() ,playerObj.name, record - ) - ) - if playerObj.detailMode: #如果玩家启用了详细模式 - playerObj.sendMessage(u"§b[§e{}§b] §a最佳纪录 §e{:.2f} §a秒 | 第 §e{} §a次完成该地图".format( - self.map.display, - playerObj.playerData.getMultiBestMapRecord(self.mapNum), - self.playerMapTimes[playerObj.name] + 1)) - if seasonManager.inSeasonMaps(self.mapNum): #如果是赛季地图 - playerObj.sendMessage(u"§b[§e{}§b] §a该地图当季分数 §e{:.2f} §a| 当季总分 §e{:.2f}".format( - self.map.display, - playerObj.playerData.getSeasonMapScore(self.mapNum), - playerObj.playerData.getSeasonScore())) + #计算区间 glass ready points + for key in ['glass', 'ready'] + list(range(1, int(self.point) + 1)): + mins, maxs = [], [] + for axis in ['x', 'y', 'z']: + a, b = sorted([ + points.getInt('{}.pos1.{}'.format(key, axis)), + points.getInt('{}.pos2.{}'.format(key, axis)) + ]) + if axis == 'x': + a += self.mapNum * 10000 + b += self.mapNum * 10000 + if axis == 'z': + a += self.maproomNum * 10000 + b += self.maproomNum * 10000 + mins.append(a) + maxs.append(b) + self.pointPositionDict['{}'.format(key)] = tuple(mins + maxs) + def initialSpecialMap(self): #初始化特殊地图 + if self.mapNum == 9: #西南克克十字城 + world = getServer().getWorld(WORLD_NAME) + x = 95000 + y = 54 + z = 5000 + (self.maproomNum * 10000) + block = world.getBlockAt(x, y, z) + blockType = block.getType() + if blockType != Material.REDSTONE_BLOCK: + ps.scheduler.runTaskLater(lambda: block.setType(Material.REDSTONE_BLOCK), 20) else: - playerObj.sendMessage(u"§b[§e{}§b] §a该地图不是当季地图".format(self.map.display)) - def bindPlayerInPreparingArea(self, playerObj): #绑定玩家在准备区域 - def checkTask(): - #print('Looping') - if not playerObj.inArea(self.map.getPreparingArea()): - actionBar(playerObj.player, u'§c请勿离开起点区域') - playerObj.teleport(self.map.getJoinPosition()) - taskId = ps.scheduler.scheduleRepeatingTask(checkTask, 0, 20) - self.trackTask(playerObj.name, taskId) - def updatePlayerInfo(self, playerName): #更新玩家信息 - if playerName in self.playerList: - self.playerList[playerName].updatePlayerData() #更新玩家对象数据 - self.save() #保存房间状态 - # 信息显示 ---------------------------------------------- - def createHologram(self): #创建/更新全息显示 - self.createMapDisplayArmorStands() - self.createMapDisplayItemFrame() - self.save() #保存房间状态 - def createMapDisplayArmorStands(self): #创造盔甲架显示 - config = ps.config.loadConfig(HOLOGRAME_CONFIG_PATH) - hologramLoc = config.get(str(self.roomId)) - if hologramLoc is not None: - x = hologramLoc.get("x") - y = hologramLoc.get("y") - z = hologramLoc.get("z") - if x is not None and y is not None and z is not None: - world = getServer().getWorld(WORLD_NAME) - self.clearMapDisplayArmorStands() # 清除旧的盔甲架 - sortedPlayers = sorted(self.playerList.keys(), reverse=True) # 按玩家名字首字母排序 - - # 设置名字之间的垂直偏移量 - xOffset = 2 - yOffset = 0.13 - (ARMOR_STAND_INTERVAL / 2) * (len(sortedPlayers) + 2) - zOffset = - 1.1 - - bottomLoc = Location(world, x, world.getMinHeight(), z) #预处理位置 - - # 为每个玩家创建盔甲架显示名字 - for playerName in sortedPlayers: - # 加载玩家数据 - playerData = PlayerDataManager(playerName) - customName = u"{}[{}]§f{}".format(playerData.getLevelColor(), playerData.getTitleDisplay(), playerName) - self.createArmorStand(world, bottomLoc, x + xOffset, y + yOffset, z + zOffset, customName) - yOffset += ARMOR_STAND_INTERVAL - - # 地图信息盔甲架 - customName = u"§a难度 §e{} §a圈数 §e{}".format(self.map.difficulty, self.map.lap) - self.createArmorStand(world, bottomLoc, x + xOffset, y + yOffset, z + zOffset, customName) - yOffset += ARMOR_STAND_INTERVAL - - # 地图名称盔甲架 - if self.isRunning: #房间状态判定 - roomStatus = u"§c[启动]" - else: - roomStatus = u"§a[等待]" - customName = u"§b§l【§e§l{}§b§l】{}".format(self.map.display, roomStatus) - self.createArmorStand(world, bottomLoc, x + xOffset, y + yOffset, z + zOffset, customName) - yOffset += ARMOR_STAND_INTERVAL - def createMapDisplayItemFrame(self): #创造展示框显示 - config = ps.config.loadConfig(HOLOGRAME_CONFIG_PATH) - hologramLoc = config.get(str(self.roomId)) - if hologramLoc is not None: - x = hologramLoc.get("x") - y = hologramLoc.get("y") - z = hologramLoc.get("z") - if x is not None and y is not None and z is not None: - world = getServer().getWorld(WORLD_NAME) - if self.mapDisplayItemFrame: # 删除并覆盖已有展示框 - self.mapDisplayItemFrame.remove() - displayLoc = Location(world, x - 1, y + 1, z) #最终展示框位置,偏移可修改 - bottomLoc = Location(world, x, world.getMinHeight(), z) # 预处理位置 - itemFrame = bottomLoc.getWorld().spawnEntity(bottomLoc, EntityType.ITEM_FRAME)#生成展示框 - mapItem = ItemStack(Material.MAP) - meta = mapItem.getItemMeta() - if int(self.mapNum) > int(AVAILABLE_MAPNUM): - num = 0 - else: - num = self.mapNum - customModelKey = fromString("template:map{}".format(int(num))) - meta.setItemModel(customModelKey) - mapItem.setItemMeta(meta) - itemFrame.setItem(mapItem) - itemFrame.setVisible(False) - self.mapDisplayItemFrame = itemFrame # 存储展示框实体 - - ps.scheduler.runTaskLater(lambda: itemFrame.teleport(displayLoc), 1) #延迟传送 - ps.scheduler.runTaskLater(lambda: itemFrame.setFacingDirection(BlockFace.SOUTH), 1) #调整面朝方向 - def clearHologram(self): #清理全息显示 - self.clearMapDisplayArmorStands() - self.clearMapDisplayItemFrame() - def clearMapDisplayArmorStands(self): #清理盔甲架显示 - for armorStand in self.mapDisplayArmorStands: - if armorStand and not armorStand.isDead(): - armorStand.remove() - self.mapDisplayArmorStands = [] - def clearMapDisplayItemFrame(self): #清理展示框显示 - if self.mapDisplayItemFrame: - self.mapDisplayItemFrame.remove() - self.mapDisplayItemFrame = None - # 流程管理 ---------------------------------------------- - def enterRunning(self): #尝试运行 - # 运行前检查是否有可用副本 - roomNum = roomsManager.getAvailableRoom(self.mapNum) - if roomNum is None: #无可用房间 - for playerObj in self.playerList.values(): - player = playerObj.player - if player: - player.sendTitle(u"", u"§c剩余空房不足", 5, 50, 20) - player.playSound(player, Sound.BLOCK_NOTE_BLOCK_BASS, 1, 1) - return False - - # 运行成功设置 - self.isRunning = True # 开启成功 - self.roomNum = roomNum # 更新房间号 - roomsManager.setAvailableRoom(self.mapNum, self.roomNum, True) #更新房间状态 - self.map = IceboatMap(self.mapNum, self.roomNum) # 更新地图 - self.map.initialSpecialMap() #初始化特殊地图 - self.createMapDisplayArmorStands() # 更新全息显示 - # 为房间内每个玩家对象执行 - for playerObj in self.playerList.values(): - if playerObj.player.isInsideVehicle(): #如果玩家在船内则删除船 - playerObj.player.getVehicle().remove() - playerObj.updatePlayerData() #更新玩家数据 - playerObj.updateJoinLoc() #更新玩家进入房间前的位置 - joinPos = self.map.getJoinPosition() #获取玩家进入房间的位置 - playerObj.teleport(joinPos) #传送玩家到房间内 - playerObj.updateLastMap(self.mapNum) #更新玩家上一次游玩的地图 - playerObj.setInvisible() #设置玩家隐身 - playerObj.startReadyParticle() #开始准备粒子效果 - - if playerObj.musicMode: #如果玩家启用了音乐模式 - playerObj.stopRecordSounds() #停止可能在播放的音乐 - playerObj.playIceboatMapSound(self.mapNum) - - self.playerMapTimes[playerObj.name] = playerObj.playerData.getMapTimes(self.mapNum) #获取每个玩家的完成次数 - self.playerTotalMapTimes[playerObj.name] = playerObj.playerData.getTotalMapTimes() #获取每个玩家的总完成次数 - if playerObj.detailMode: #如果玩家启用了详细模式 - self.mapManager = MapManager(self.mapNum) - playerObj.sendMessage(u"§b[§e{}§b] §a本地图由 §f{} §a等人参与制作".format(self.map.display, self.mapManager.getCreator())) - self.bindPlayerInPreparingArea(playerObj) #为玩家绑定检查点任务 - - self.enterPrepaing() #进入准备阶段 - def enterPrepaing(self): - self.isPreparing = True #进入准备阶段 - # 准备阶段设置 - self.map.replaceBlock(START_LINE_MATERIAL) # 启动线设置 - # 准备阶段流程 - def countdownTask1(): - if self.isEmpty(): # 检查房间内是否还有玩家 - self.closeRoom() #没有玩家则关闭房间 - return - self.countdownToAll(u'§f〓 5 〓', u'§7●●●●●', 1.0) - ps.scheduler.runTaskLater(countdownTask2, 20) - def countdownTask2(): - if self.isEmpty(): - self.closeRoom() - return - self.countdownToAll(u'§a〓 4 〓', u'§c●§7●●●●', 1.0) - ps.scheduler.runTaskLater(countdownTask3, 20) - def countdownTask3(): - if self.isEmpty(): - self.closeRoom() - return - self.countdownToAll(u'§b〓 3 〓', u'§c●●§7●●●', 1.0) - ps.scheduler.runTaskLater(countdownTask4, 20) - def countdownTask4(): - if self.isEmpty(): - self.closeRoom() - return - self.countdownToAll(u'§d〓 2 〓', u'§c●●●§7●●', 1.0) - ps.scheduler.runTaskLater(countdownTask5, 20) - def countdownTask5(): - if self.isEmpty(): - self.closeRoom() - return - self.countdownToAll(u'§e〓 1 〓', u'§c●●●●§7●', 1.0) - ps.scheduler.runTaskLater(countdownTask6, 20) - def countdownTask6(): - if self.isEmpty(): - self.closeRoom() - return - self.countdownToAll(u'§c§l〓 GO 〓', u'§a●●●●●', 2.0) - self.isPreparing = False #准备阶段结束 - for playerObj in self.playerList.values(): #获取玩家对象 - playerObj.stopReadyParticle() #结束准备粒子展示 - - self.enterStarting() - # 准备阶段开始 - ps.scheduler.runTaskLater(countdownTask1, 1) - def enterStarting(self): # 进入开始阶段 包括Starting和Gaming - self.isStarting = True # 进入开始阶段 - # 开始阶段设置 - for key in list(self.activeTasks.keys()): #清理非系统任务 - if key != 'system': - self.clearTasks(key) - # 各玩家设置 - for playerObj in self.playerList.values(): #获取玩家对象 - playerObj.spawnAndRideBoat() #生成船并绑定 - playerObj.setStartMoment() #设置开始时间戳 - playerObj.startActionBarUpdates(False) - playerObj.startParticle() #开始粒子展示 - # 开始阶段设置 - self.map.replaceBlock(Material.TRIPWIRE) # 启动线移除 - self.isGaming = True # 进入游戏阶段 - self.rankPlayerInGame() # 更新排名 - self.trackTask('system', ps.scheduler.scheduleRepeatingTask(lambda: self.updateGamingState(), 0, 1)) - def updateGamingState(self): # 游戏阶段每游戏刻更新状态 - #print('Looping') # 调试启用,用于检测循环任务是否停止 - if self.isEmpty(): #如果房间为空则关闭房间 - self.closeRoom() - return - - # 循环检测玩家状态 - self.allFinished = True #默认所有玩家都完成 - for playerObj in self.playerList.values(): - if not playerObj.inVehicle(): #如果玩家不在载具内 - self.delPlayer(playerObj.name) #移出玩家 - if self.isEnding: #若进入结束阶段则跳过 - return - - # 检查点位进度 - if not playerObj.hasFinished: #玩家还没完成 - self.allFinished = False #存在未完成玩家 - mapNum = self.map.mapNum #获取地图编号 - pointArea = self.map.getPointArea(playerObj.point) #获取玩家当前检查点区域 - if playerObj.arrivePoint(pointArea): #玩家到达检查点 - self.rankPlayerInGame() #通过检查点时更新全局排名 - playerObj.updateTimer() #更新玩家时间戳 - if playerObj.point >= self.map.point: #完成一圈 - playerObj.addLap() #圈数增加 - playerObj.resetPoint() #重置检查点 - if playerObj.lap <= self.map.lap: #未完成所有圈的情况 - playerObj.addLapTitle() - playerObj.addLapSound() - else: - self.settleFinishedPlayer(playerObj) #对完成玩家的结算 - playerObj.setPointsTimer() #设置玩家检查点时间戳 - playerObj.updateMultiBestMapRecordPointTimer(mapNum, playerObj.lap, playerObj.point) #更新玩家多人最好成绩点位 - playerObj.updateDValueText() - playerObj.showMultiTimerInActionBar() #更新玩家动态栏显示 - if playerObj.detailMode: #详细模式 - if playerObj.lap <= self.map.lap: - playerObj.showTimerByMessage(self.map.display) #显示详细信息 - - if self.allFinished: #所有玩家完成则在3秒后关闭房间 - self.isStarting = False #结束启动状态 - self.enterEnding() #进入结束阶段 - def enterEnding(self): #游戏结束阶段 - self.isEnding = True - ps.scheduler.runTaskLater(lambda: self.closeRoom(), ENDING_INTERVAL) #阶段 - def closeRoom(self): #关闭房间操作 - if self.isClosed: #不重复关闭 - return - self.isClosed = True - roomId = self.roomId - players = list(self.playerList.keys()) - - self.clearHologram() #清理全息显示 - roomsManager.setAvailableRoom(self.mapNum, self.roomNum, False) #房间可用 - for playerObj in self.playerList.values(): - self.delPlayer(playerObj.name) #执行玩家退出 - - for playerName, info in playerPage.items(): #关闭打开中的房间地图选择菜单 #待更新 - if "roomId" in info and info["roomId"] == self.roomId: - player = getServer().getPlayer(playerName) - if player and player.getOpenInventory().getTitle().startswith(u"§0多人模式地图选择 - 房间 {} - ".format(self.roomId)): - player.closeInventory() - - self.clearTasks('system')# 清理系统任务 - self.isRunning = False - self.isGaming = False - self.isEnding = False - - del multiGames[roomId] #删除房间 - - multiGames[roomId] = MultiGameRoom(roomId) #重新创建房间 - for playerName in players: #将玩家重新添加 - multiGames[roomId].addPlayer(playerName) - # 任务管理 -------------------------------- - def trackTask(self, owner, taskId): #仅循环任务需要任务管理 - if owner not in self.activeTasks: - self.activeTasks[owner] = [] - self.activeTasks[owner].append(taskId) - def clearTasks(self, owner): #停止指定循环任务 - if owner in self.activeTasks: - taskIds = list(self.activeTasks[owner]) - for taskId in taskIds: - if taskId is not None: - ps.scheduler.stopTask(taskId) - del self.activeTasks[owner] - # 辅助方法 -------------------------------- - def countdownToAll(self, title, subtitle, pitch): #为所有人播放倒计时反馈 - for playerObj in self.playerList.values(): - playerObj.sendTitle(title, subtitle, 0, 20, 10) - playerObj.playSound(Sound.BLOCK_NOTE_BLOCK_PLING, 1.0, pitch) - def broadcastMessage(self, message): #游戏内广播信息 - for playerObj in self.playerList.values(): - playerObj.player.sendMessage(message) - def createArmorStand(self, world, bottomLoc, x, y, z, customName): #生成盔甲架 - armorStand = world.spawn(bottomLoc, ArmorStand) #先在底部创造 - armorStand.setGravity(False) #设置无重力 - armorStand.setVisible(False) #设置不可见 - armorStand.setCollidable(False) #设置无碰撞箱 - armorStand.setCustomName(customName) #设置显示名 - armorStand.setCustomNameVisible(True) #设置显示名可见 - displayLoc = Location(world, x, y, z) #设置展示位置 - armorStand.teleport(displayLoc) #传送展示框 - self.mapDisplayArmorStands.append(armorStand) #将展示框添加到房间 -class SingleGameRoom: #单人游戏房间类 - def __init__(self, playerName, mapNum, roomNum): #玩家名:单人房间实例 - self.playerName = playerName - self.player = getServer().getPlayer(playerName) - self.playerObj = PlayerInGame(playerName) - - self.activeTasks = {} - - self.mapNum = mapNum - self.roomNum = roomNum - self.map = IceboatMap(self.mapNum, self.roomNum) - self.map.initialSpecialMap() #初始化特殊地图 - - self.isRunning = False - self.isPreparing = False - self.isStarting = False - self.isClosed = False - - self.mapManager = MapManager(self.mapNum) - # 房间管理 -------------------------------------------------- - def save(self): #更新状态 - singleGames[self.playerName] = self - # 玩家管理 -------------------------------------------------- - def playerLeave(self): #玩家离开 - # 清理玩家任务 - if hasattr(self, 'activeTasks') and self.playerName in self.activeTasks: - for taskId in self.activeTasks[self.playerName]: - if taskId is not None: - ps.scheduler.stopTask(taskId) - del self.activeTasks[self.playerName] - # 清理玩家自身状态并执行操作 - playerObj = self.playerObj - if self.isRunning: - playerObj.teleportToJoinLoc() #传送回进入房间前的位置 - if self.isStarting: - playerObj.clearBoat() #离开时清理绑定的船 - playerObj.stopActionBarUpdates() - playerObj.stopParticle() - self.save() - # 流程管理 -------------------------------------------------- - def enterRunning(self): #游戏初始化阶段 - self.isRunning = True - if self.player.isInsideVehicle(): #如果玩家在船内则删除船 - self.player.getVehicle().remove() - self.playerObj.updatePlayerData() #更新玩家数据 - self.playerObj.updateJoinLoc() #更新玩家进入房间前的位置 - joinPos = self.map.getJoinPosition() #获取玩家进入房间的位置 - self.playerObj.teleport(joinPos) #传送玩家到房间内 - - self.playerObj.updateLastMap(self.map.mapNum) #更新玩家上一次游玩的地图 - if self.playerObj.musicMode: #如果玩家启用了音乐模式 - self.playerObj.stopRecordSounds() #停止可能在播放的音乐 - self.playerObj.playIceboatMapSound(self.map.mapNum) - - if self.playerObj.detailMode: #如果玩家启用了详细模式 - self.playerObj.sendMessage(u"§b[§e{}§b] §a本地图由 §f{} §a等人参与制作".format(self.map.display, self.mapManager.getCreator())) - self.bindPlayerInPreparingArea() #为玩家绑定检查点任务 - - self.enterPreparing() #进入准备阶段 - def enterPreparing(self): - self.isPreparing = True #进入准备阶段 - # 准备阶段设置 - self.map.replaceBlock(START_LINE_MATERIAL) # 启动线设置 - # 准备阶段流程 - def countdownTask1(): - if self.playerName in singleGames: - self.countdownToPlayer(u'§f〓 5 〓', u'§7●●●●●', 1.0) - ps.scheduler.runTaskLater(countdownTask2, 20) - def countdownTask2(): - if self.playerName in singleGames: - self.countdownToPlayer(u'§a〓 4 〓', u'§c●§7●●●●',1.0) - ps.scheduler.runTaskLater(countdownTask3, 20) - def countdownTask3(): - if self.playerName in singleGames: - self.countdownToPlayer(u'§b〓 3 〓', u'§c●●§7●●●', 1.0) - ps.scheduler.runTaskLater(countdownTask4, 20) - def countdownTask4(): - if self.playerName in singleGames: - self.countdownToPlayer(u'§d〓 2 〓', u'§c●●●§7●●', 1.0) - ps.scheduler.runTaskLater(countdownTask5, 20) - def countdownTask5(): - if self.playerName in singleGames: - self.countdownToPlayer(u'§e〓 1 〓', u'§c●●●●§7●', 1.0) - ps.scheduler.runTaskLater(countdownTask6, 20) - def countdownTask6(): - if self.playerName in singleGames: - self.countdownToPlayer(u'§c§lGO', u'§a●●●●●', 2.0) - self.isPreparing = False - self.enterStarting() - # 准备阶段开始 - ps.scheduler.runTaskLater(countdownTask1, 1) # 待更新 - def enterStarting(self): #开始阶段 - self.isStarting = True - # 开始阶段设置 - self.clearTasks(self.playerObj.name) #清理玩家任务:循环检测区域 - self.playerObj.spawnAndRideBoat() #生成船并绑定 - self.playerObj.setStartMoment() #设置开始时间戳 - self.playerObj.startActionBarUpdates(True) - self.playerObj.startParticle() #开始粒子展示 - self.map.replaceBlock(Material.TRIPWIRE) #启动线移除 - self.trackTask('system', ps.scheduler.scheduleRepeatingTask(lambda: self.updateGamingState(), 0, 1)) - def updateGamingState(self): - #print('Looping') - if not self.playerObj.isOnline(): #玩家不在线则关闭房间 - self.closeRoom() - return - if not self.playerObj.inVehicle(): #玩家不在载具内则关闭房间 - self.closeRoom() - return - mapNum = self.map.mapNum - pointArea = self.map.getPointArea(self.playerObj.point) - if self.playerObj.arrivePoint(pointArea): - self.playerObj.updateTimer() - if self.playerObj.point >= self.map.point: - self.playerObj.addLap() - self.playerObj.resetPoint() - if self.playerObj.lap <= self.map.lap: - self.playerObj.addLapTitle() #没有到最后一圈则展现标题 - self.playerObj.addLapSound() #没有到最后一圈则播放音效 - else: - self.enterEnding() - self.playerObj.setPointsTimer() - self.playerObj.updateSingleBestMapRecordPointTimer(mapNum, self.playerObj.lap, self.playerObj.point) #更新玩家单人最好成绩点位 - self.playerObj.updateDValueText() #更新D值文本 - self.playerObj.showSingleTimerInActionBar() - if self.playerObj.detailMode: #详细模式下显示详细信息 - if self.playerObj.lap <= self.map.lap: #仅在未完成前播报 - self.playerObj.showTimerByMessage(self.map.display) - def enterEnding(self): - finishTime = self.playerObj.timer - self.playerObj.finishTime = finishTime - message = u"§b[§e{}§b] {}[{}]§f{} §a总用时 §e{:.2f} §a秒".format( - self.map.display, self.playerObj.playerData.getLevelColor(), self.playerObj.playerData.getTitleDisplay(), self.playerObj.name, finishTime) - if self.playerObj.broadcastMode: #如果开启了成绩广播模式 - broadcast(message) + ps.scheduler.runTaskLater(lambda: block.setType(Material.AIR), 10) + ps.scheduler.runTaskLater(lambda: block.setType(Material.REDSTONE_BLOCK), 20) + def getJoinPosition(self): #获取进入点坐标 + return self.pointPositionDict['join'] + def getPreparingArea(self): #获取准备区域 + return self.pointPositionDict['ready'] + def getPointArea(self, point): #获取检查点区域 + return self.pointPositionDict[str(point + 1)] + def replaceBlock(self, targetType): #开始区域线替换为目标材质 + if targetType == START_LINE_MATERIAL: + type = Material.TRIPWIRE else: - self.playerObj.sendMessage(message) - self.playerObj.hasFinished = True # 标记玩家已完成 - self.playerObj.playSound(Sound.ENTITY_FIREWORK_ROCKET_LAUNCH, 1.0, 1.0) - self.playerObj.playSound(Sound.ENTITY_FIREWORK_ROCKET_TWINKLE, 1.0, 1.0) - self.playerObj.stopActionBarUpdates() - self.playerObj.stopParticle() - self.playerObj.finishAddVault() - record = self.playerObj.checkSingleRecord(self.map.mapNum) - if record: #纪录更新 - record = float(record) - self.playerObj.playSound(Sound.ENTITY_PLAYER_LEVELUP, 1.0, 1.0) - self.playerObj.sendMessage( - u"§b[§e{}§b] {}[{}]§f{} §a刷新了个人纪录!§7(旧纪录:{:.2f})".format( - self.map.display, self.playerObj.playerData.getLevelColor(), self.playerObj.playerData.getTitleDisplay(), self.playerObj.name, record - ) - ) - if self.playerObj.detailMode: #如果玩家启用了详细模式 - self.playerObj.sendMessage(u"§b[§e{}§b] §a最佳纪录 §e{:.2f} §a秒 | 第 §e{} §a次完成该地图".format( - self.map.display, - self.playerObj.playerData.getSingleBestMapRecord(self.mapNum), - self.playerObj.playerData.getMapTimes(self.mapNum))) - if seasonManager.inSeasonMaps(self.mapNum): #如果是赛季地图 - self.playerObj.sendMessage(u"§b[§e{}§b] §a该地图当季分数 §e{:.2f} §a| 当季总分 §e{:.2f}".format( - self.map.display, - self.playerObj.playerData.getSeasonMapScore(self.mapNum), - self.playerObj.playerData.getSeasonScore())) - else: - self.playerObj.sendMessage(u"§b[§e{}§b] §a该地图不是当季地图".format(self.map.display)) - self.closeRoom() - def closeRoom(self): #游戏结束 - if self.isClosed: #不重复关闭 - return - self.isClosed = True - roomsManager.setAvailableRoom(self.mapNum, self.roomNum, False) - self.playerLeave() - self.clearTasks('system') # 清理系统任务 - self.isStarting = False - self.isRunning = False - del singleGames[self.playerName] - # 任务管理 -------------------------------- - def trackTask(self, owner, taskId): - if not hasattr(self, 'activeTasks'): - self.activeTasks = {} - if owner not in self.activeTasks: - self.activeTasks[owner] = [] - self.activeTasks[owner].append(taskId) - def clearTasks(self, owner): - if hasattr(self, 'activeTasks') and owner in self.activeTasks: - taskIds = list(self.activeTasks[owner]) - for taskId in taskIds: - if taskId is not None: - ps.scheduler.stopTask(taskId) - del self.activeTasks[owner] - # 辅助方法 -------------------------------- - def countdownToPlayer(self, title, subtitle, pitch): - player = self.playerObj.player - player.sendTitle(title, subtitle, 0, 20, 10) - player.playSound(player, Sound.BLOCK_NOTE_BLOCK_PLING, 1.0, pitch) - def bindPlayerInPreparingArea(self): #准备阶段循环检测 - def checkTask(): - #print('Looping') - if not self.playerObj.inArea(self.map.getPreparingArea()): - actionBar(self.playerObj.player, u'§c请勿离开起点区域') - self.playerObj.teleport(self.map.getJoinPosition()) - - taskId = ps.scheduler.scheduleRepeatingTask(checkTask, 0, 20) - self.trackTask(self.playerObj.name, taskId) + type = START_LINE_MATERIAL + x1, y1, z1, x2, y2, z2 = self.pointPositionDict['glass'] + for x in range(int(x1), int(x2) + 1): + for y in range(int(y1), int(y2) + 1): + for z in range(int(z1), int(z2) + 1): + block = self.world.getBlockAt(x, y, z) + if block.type == type: + block.setType(targetType) class PlayerInGame: #游戏内玩家类 def __init__(self, playerName): self.name = playerName self.player = Bukkit.getPlayer(playerName) - self.world = getServer().getWorld(WORLD_NAME) + self.world = worldManager.getWorld() self.boat = None #玩家绑定的船实体 # 计时相关 self.point = 0 # 当前通过检查点 @@ -1925,6 +1444,7 @@ class PlayerInGame: #游戏内玩家类 self.passMoment = 0 # 通过点位时间戳 self.lastMoment = 0 # 上一点位时间戳 self.hasFinished = False + self.dnf = False self.pointsTimer = {} #圈数对应记录点 [lap] point : Timer self.bestMapRecordPointTimer = 0 #点位最佳用时 self.dValueText = '' @@ -1935,6 +1455,8 @@ class PlayerInGame: #游戏内玩家类 # 玩家配置文件 self.playerData = PlayerDataManager(playerName) self.updatePlayerData() + # 初始化设置 + self.player.setFireTicks(0) #灭火 # 信息反馈 -------------------------------- def playSound(self, sound, volume, pitch): #为自己播放音效 self.player.playSound(self.player, sound, volume, pitch) @@ -1947,7 +1469,6 @@ class PlayerInGame: #游戏内玩家类 def addLapTitle(self): #完成一圈后显示标题 self.sendTitle(u'§f', u'§a进入第 §e{} §a圈'.format(self.lap), 0, 30, 10) def spawnBoatParticles(self): #生成船的粒子 - #print('Looping') if self.particleMode: #自定义粒子模式 leftLoc = self.getRelativeOffset(0.5, -1.0) rightLoc = self.getRelativeOffset(-0.5, -1.0) @@ -1984,7 +1505,7 @@ class PlayerInGame: #游戏内玩家类 True # force模式 ) def spawnPlayerParticles(self): #生成玩家开局展示粒子 - #print('Looping') + self.player.getWorld().spawnParticle( Particle.valueOf(DEFAULT_PARTICLE_TYPE), self.player.getLocation().add(Vector(0, 0.1, 0)), @@ -2002,12 +1523,12 @@ class PlayerInGame: #游戏内玩家类 def stopRecordSounds(self): #停止自定义音乐播放 self.player.stopSound(SoundCategory.RECORDS) def showSingleTimerInActionBar(self): #在动态栏为自己显示单人时间信息 - #print('Looping') + text = u"§fPoint {}-{} {} §f| 用时 §e§l{:.2f} §f秒".format( self.lap, self.point, self.dValueText, self.timer) actionBar(self.player, text) def showMultiTimerInActionBar(self): #在动态栏为自己显示多人时间信息 - #print('Looping') + text = u"§fPoint {}-{} {} §f| 排名 §b§l{} §f| 用时 §e§l{:.2f} §f秒".format( self.lap, self.point, self.dValueText, self.rank, self.timer) actionBar(self.player, text) @@ -2022,6 +1543,9 @@ class PlayerInGame: #游戏内玩家类 return False def isOnline(self): #判断玩家是否在线 return self.player.isOnline() + def inLobby(self): + playerManager = PlayerManager(self.player) + return playerManager.inLobby() def inArea(self, area): #判断玩家是否在指定区域 loc = self.player.getLocation() x = loc.getX() @@ -2033,6 +1557,12 @@ class PlayerInGame: #游戏内玩家类 z1 <= z <= z2): return True return False + def getSpectate(self): #判断是否有玩家在旁观正在游戏中的玩家 + spectators = [] + for name, spectator in playersInSpectate.items(): + if self.name == spectator.targetPlayerName: + spectators.append(spectator.playerName) + return spectators # 信息更新 -------------------------------- def arrivePoint(self, pointArea): #通过检查点 if self.inArea(pointArea): #是否在点位区域 @@ -2197,6 +1727,7 @@ class PlayerInGame: #游戏内玩家类 self.setInGame(0) #标记离开游戏 def spawnAndRideBoat(self): #根据玩家自己的船的类型自动上船 loc = self.player.getLocation() + loc.setPitch(BOAT_PITCH) boat = self.world.spawnEntity(loc, EntityType.valueOf(self.boatMaterial.upper())) #生成船 boat.addPassenger(self.player) #自动骑乘 self.boat = boat @@ -2205,10 +1736,10 @@ class PlayerInGame: #游戏内玩家类 if not self.boat.isDead(): #如果船还存在 self.boat.remove() #清除船 self.boat = None - def setInvisible(self): #让自己隐身(5秒) + def setInvisible(self): #让自己隐身 self.player.addPotionEffect(PotionEffect( PotionEffectType.INVISIBILITY, - 100, + 600, 0, False, #显示粒子 False #显示图标 @@ -2221,9 +1752,26 @@ class PlayerInGame: #游戏内玩家类 vault = round(vault * (self.timer / 180), 1) vault = round(vault * mag, 1) vaultEconomy.depositPlayer(self.player, vault) - self.player.sendTitle(u'§a§l完成', u'§f获得 §e{:.1f} §fDC币'.format(vault), 0, 50, 10) + self.player.sendTitle(u'§a§l第 §e§l{} §a§l名'.format(self.rank), u'§6用时 §e{:.2f} §6| §6获得 §e{:.1f} §6DC币'.format(self.timer, vault), 0, 80, 20) else: - self.player.sendTitle(u'§a§l完成', u'§f', 0, 50, 10) + self.player.sendTitle(u'§a§l第 §e§l{} §a§l名'.format(self.rank), u'§6用时 §e{:.2f}'.format(self.timer), 0, 80, 20) + return vault + def leaveAddVault(self, lap, point, vault=REWARD_AMOUNT): #离开游戏并扣除Vault,默认惩罚金额 + if vaultEconomy: + mag = 0.1 + if point > 0: + mag = float(self.point) / float(point) + if lap > 1: + mag = (float(self.lap) - 1.0 + mag) / float(lap) + if mag < 0: + mag = 0.0 + elif mag > 1.0: + mag = 1.0 + if self.timer <= 180: #如果小于180秒则百分比减少 + vault = round(vault * (self.timer / 180), 1) + vault = round(vault * mag, 1) + vaultEconomy.depositPlayer(self.player, vault) + return vault # 时间操作 -------------------------------- def setStartMoment(self): #设置游戏开始时间戳 self.startMoment = time.time() @@ -2314,41 +1862,32 @@ class PlayerInParticlePreview: #粒子预览类 def startPreviewing(self): #开始预览 self.particleTaskId = ps.scheduler.scheduleRepeatingTask(lambda: self.previewing(),0,1) def previewing(self): #生成船的粒子 - #print('Looping') - if self.particleMode: #自定义粒子模式 - leftLoc = self.getRelativeOffset(0.5, -1.0) - rightLoc = self.getRelativeOffset(-0.5, -1.0) - # 直接生成左右两边的粒子(完全对应原版命令) - worldManager.getWorld().spawnParticle( - Particle.valueOf(self.particleType), # 粒子类型 - leftLoc.add(Vector(0, self.particleInfo[5], 0)), # 相对坐标 - self.particleInfo[0], # 粒子数量 - self.particleInfo[1], # 偏移量x - self.particleInfo[2], # 偏移量y - self.particleInfo[3], # 偏移量z - self.particleInfo[4], # 速度 - None, # 数据 - True # force模式 - ) - worldManager.getWorld().spawnParticle( - Particle.valueOf(self.particleType), - rightLoc.add(Vector(0, self.particleInfo[5], 0)), # 相对坐标 - self.particleInfo[0], # 粒子数量 - self.particleInfo[1], # 偏移量x - self.particleInfo[2], # 偏移量y - self.particleInfo[3], # 偏移量z - self.particleInfo[4], # 速度 - None, # 数据 - True - ) - else: #单粒子模式 - worldManager.getWorld().spawnParticle( - Particle.DRAGON_BREATH, - self.boat.getLocation().add(Vector(0, 0.1, 0)), - 0,0,0,0,0, - None, # 数据 - True # force模式 - ) + + leftLoc = self.getRelativeOffset(0.5, -1.0) + rightLoc = self.getRelativeOffset(-0.5, -1.0) + # 直接生成左右两边的粒子(完全对应原版命令) + worldManager.getWorld().spawnParticle( + Particle.valueOf(self.particleType), # 粒子类型 + leftLoc.add(Vector(0, self.particleInfo[5], 0)), # 相对坐标 + self.particleInfo[0], # 粒子数量 + self.particleInfo[1], # 偏移量x + self.particleInfo[2], # 偏移量y + self.particleInfo[3], # 偏移量z + self.particleInfo[4], # 速度 + None, # 数据 + True # force模式 + ) + worldManager.getWorld().spawnParticle( + Particle.valueOf(self.particleType), + rightLoc.add(Vector(0, self.particleInfo[5], 0)), # 相对坐标 + self.particleInfo[0], # 粒子数量 + self.particleInfo[1], # 偏移量x + self.particleInfo[2], # 偏移量y + self.particleInfo[3], # 偏移量z + self.particleInfo[4], # 速度 + None, # 数据 + True + ) if not self.player.isInsideVehicle(): #如果不在载具里 self.stopPreviewing() #停止预览 def stopPreviewing(self): #停止预览 @@ -2361,87 +1900,1708 @@ class PlayerInParticlePreview: #粒子预览类 del playersInParticlePreview[self.name] def spawnAndRideBoat(self): #根据玩家自己的船的类型自动上船 loc = self.player.getLocation() + loc.setPitch(BOAT_PITCH) boat = worldManager.getWorld().spawnEntity(loc, EntityType.valueOf(self.boatMaterial.upper())) #生成船 boat.addPassenger(self.player) #自动骑乘 self.boat = boat -class IceboatMap: #地图类 - def __init__(self, mapNum, maproomNum): - - self.mapNum = int(mapNum) - self.maproomNum = int(maproomNum) - self.world = getServer().getWorld(WORLD_NAME) - #地图配置数据 - self.mapData = MapManager(self.mapNum) - self.yaw = self.mapData.getYaw() - self.lap = self.mapData.getLap() - self.point = self.mapData.getPoint() - self.display = self.mapData.getDisplay() - self.difficulty = self.mapData.getDifficulty() - #地图坐标字典集 - self.pointPositionDict = {} - points = self.mapData.getPoints() - #计算坐标 join - dimensions = [] - for axis in ['x', 'y', 'z']: - a = points.getInt('join.{}'.format(axis)) - if axis == 'x': - a = a + (self.mapNum * 10000) - if axis == 'z': - a = a + (self.maproomNum * 10000) - dimensions.append(a) - self.pointPositionDict['join'] = list(dimensions) - self.pointPositionDict['join'].append(self.yaw) - self.pointPositionDict['join'].append(0) #pitch 0 +class PlayerInSpectate: #旁观玩家 + def __init__(self, player): + self.player = player + self.playerName = player.getName() + self.playerManager = PlayerManager(player) + self.playerData = PlayerDataManager(self.playerName) - #计算区间 glass ready points - for key in ['glass', 'ready'] + list(range(1, int(self.point) + 1)): - mins, maxs = [], [] - for axis in ['x', 'y', 'z']: - a, b = sorted([ - points.getInt('{}.pos1.{}'.format(key, axis)), - points.getInt('{}.pos2.{}'.format(key, axis)) - ]) - if axis == 'x': - a += self.mapNum * 10000 - b += self.mapNum * 10000 - if axis == 'z': - a += self.maproomNum * 10000 - b += self.maproomNum * 10000 - mins.append(a) - maxs.append(b) - self.pointPositionDict['{}'.format(key)] = tuple(mins + maxs) - def initialSpecialMap(self): #初始化特殊地图 - if self.mapNum == 9: #西南克克十字城 - world = getServer().getWorld(WORLD_NAME) - x = 95000 - y = 54 - z = 5000 + (self.maproomNum * 10000) - block = world.getBlockAt(x, y, z) - blockType = block.getType() - if blockType != Material.REDSTONE_BLOCK: - ps.scheduler.runTaskLater(lambda: block.setType(Material.REDSTONE_BLOCK), 20) - else: - ps.scheduler.runTaskLater(lambda: block.setType(Material.AIR), 10) - ps.scheduler.runTaskLater(lambda: block.setType(Material.REDSTONE_BLOCK), 20) - def getJoinPosition(self): #获取进入点坐标 - return self.pointPositionDict['join'] - def getPreparingArea(self): #获取准备区域 - return self.pointPositionDict['ready'] - def getPointArea(self, point): #获取检查点区域 - return self.pointPositionDict[str(point + 1)] - def replaceBlock(self, targetType): #开始区域线替换为目标材质 - if targetType == START_LINE_MATERIAL: - type = Material.TRIPWIRE + self.boat = None + self.display = None + self.targetPlayer = None + self.targetPlayerName = None + self.teleportTaskID = None + + self.roomId = 0 + self.ticks = 0 + self.leaving = False + + def attachBoat(self, target): + boat = target.getVehicle() + if boat and isinstance(boat, Boat): + self.targetPlayer = target + self.targetPlayerName = self.targetPlayer.getName() + self.roomId = 0 + for roomId, room in multiGames.items(): + if room.isPlayerInRoom(self.targetPlayerName): + self.roomId = roomId #如果目标是某个多人房间内的玩家 + self.boat = boat + + self.spec() + boatLoc = self.boat.getLocation() + playerLoc = self.player.getLocation() + distance = playerLoc.distance(boatLoc) + if self.playerManager.inLobby(): #传送前,若在大厅旁观船则记录进入房间与位置 + self.updateJoinLoc() + self.setInGame(1) #标记进入游戏 + + if distance < PLAYER_RADIUS: #在渲染距离内直接附身 + self.player.setSpectatorTarget(self.boat) + else: #不在渲染距离内则循环传送后附身 + self.player.teleport(boatLoc) + self.display = worldManager.getWorld().spawn(self.player.getLocation(), ItemDisplay) + self.player.setSpectatorTarget(self.display) + self.ticks = 0 + self.teleportTaskID = ps.scheduler.scheduleRepeatingTask(lambda s=self: s.forceSpec(), 0, 1) + return True else: - type = START_LINE_MATERIAL - x1, y1, z1, x2, y2, z2 = self.pointPositionDict['glass'] - for x in range(int(x1), int(x2) + 1): - for y in range(int(y1), int(y2) + 1): - for z in range(int(z1), int(z2) + 1): - block = self.world.getBlockAt(x, y, z) - if block.type == type: - block.setType(targetType) + self.player.sendMessage(u"§c目标玩家已离开房间") + if self.playerManager.inLobby(): + del playersInSpectate[self.playerManager.playerName] + return False + def changeTarget(self): + if self.roomId > 0: #如果是多人房间 + playerList = list(multiGames[self.roomId].playerList) + if playerList: + anotherTargetName = playerList[0] + anotherTarget = getServer().getPlayer(anotherTargetName) + self.attachBoat(anotherTarget) + return True + return False + def forceSpec(self): + if self.boat.isDead(): #如果船在强制旁观过程中消失 + self.stopTPTask() #停止本次传送 + if not self.changeTarget(): #如果没有成功切换目标 + self.leave() #玩家离开旁观 + self.ticks += 1 + if self.ticks <= 7: + if self.display: + self.display.teleport(self.boat.getLocation().add(Vector(0, 0.5, 0))) + else: + self.stopTPTask() + self.player.setSpectatorTarget(self.boat) + self.ticks = 0 + def spec(self): + if self.player.getGameMode() != GameMode.SPECTATOR: + self.player.setGameMode(GameMode.SPECTATOR) + def updateJoinLoc(self): #更新玩家进入房间前位置到配置和实例 + loc = self.player.getLocation() + x = loc.getX() + y = loc.getY() + z = loc.getZ() + self.joinLoc = x, y, z + self.playerData.setJoinLoc(x, y, z) + def setInGame(self, score=1): #在记分板中标记玩家在游戏中,1为在,0为不在 + objective = getScoreboardObjective(u'InGame') + playerScore = objective.getScore(self.playerManager.playerName) #获取玩家分数 + playerScore.setScore(score) #设置玩家分数 + def stopTPTask(self): + if self.teleportTaskID is not None: + ps.scheduler.stopTask(self.teleportTaskID) #停止循环任务 + self.teleportTaskID = None + if self.display: #清除传送中介 + self.display.remove() + self.display = None + def leave(self): + self.leaving = True #标记允许离开 + if not self.playerManager.inLobby(): + self.playerManager.teleportToJoinLoc() + self.setInGame(0) #标记离开游戏 + self.stopTPTask() + if self.player.getGameMode()== GameMode.SPECTATOR: + self.player.setGameMode(GameMode.ADVENTURE) + self.player.sendTitle(u"§f", u"§6离开成功", 5, 60, 10) + del playersInSpectate[self.playerManager.playerName] +class CompetitionGameRoom: #比赛房间类 + def __init__(self): + self.initRoom() + # 流程管理 ---------------------------------------------- + def initRoom(self): + self.mapNum = seasonManager.getSeasonFirstMap() #默认赛季首图 + self.roomNum = 1 #默认1号房 + self.map = IceboatMap(self.mapNum, self.roomNum) #地图对象 + + self.playerCount = 0 # 房间内玩家数量 + self.finishCount = 0 # 完成玩家数量 + self.playingCount = 0 # 正在游戏中的玩家数量 + self.round = 1 # 当前轮次 + self.targetScore = 100 #目标分数 + self.playerList = {} #玩家列表 + self.scoreList = {} #分数列表 + self.rankList = [] #实时排名 + self.finishList = [] #完成列表 + self.playingList = [] #游戏中列表 + self.resetMaps() #重置比赛房间可选地图 + + self.isCompeting = False #是否正在比赛 + self.isReady = False #开局准备完成阶段 + self.isRunning = False #运行状态 包含Preparing和Gaming + self.isPreparing = False #准备状态 + self.isGaming = False #游戏状态 包含Starting和Ending + self.isStarting = False #开始状态 + self.isEnding = False #结束状态 + self.isHalftime = False #是否半场休息 + + self.allFinished = False #是否所有玩家都完成 + self.hasFinished = False #是否有玩家完成 + self.firstPlayerName = None #第一名玩家 + #非流程类存储 + self.activeTasks = {} + self.playerMapTimes = {} + self.playerTotalMapTimes = {} + self.mapDisplayArmorStands = [] # 存储该房间的盔甲架实体 + self.mapDisplayItemFrame = None # 存储该房间的展示框实体 + self.countdownTaskId = None + self.playerScoreboardObj = None + def enterReady(self): + if len(self.playerList) < MIN_COMPETITION_PLAYERS: + for playerObj in self.playerList.values(): + player = playerObj.player + if player: + player.sendTitle(u"", u"§c比赛需要至少{}人参与".format(MIN_COMPETITION_PLAYERS), 5, 50, 20) + player.playSound(player, Sound.BLOCK_NOTE_BLOCK_BASS, 1, 1) + return False + + self.isCompeting = True + if not self.isReady: + #准备阶段过程 + self.isReady = True + self.enterRunning() + def enterRunning(self): + # 运行前检查是否有可用副本 + roomNum = roomsManager.getAvailableRoom(self.mapNum) + if roomNum is None: #无可用房间 + for playerObj in self.playerList.values(): + player = playerObj.player + if player: + player.sendTitle(u"", u"§c剩余空房不足,请稍后再试", 5, 50, 20) + player.playSound(player, Sound.BLOCK_NOTE_BLOCK_BASS, 1, 1) + return False + self.isHalftime = False + self.isRunning = True # 开启成功 + self.roomNum = roomNum # 更新房间号 + roomsManager.setAvailableRoom(self.mapNum, self.roomNum, True) #更新房间状态 + self.map = IceboatMap(self.mapNum, self.roomNum) # 更新地图 + self.map.initialSpecialMap() #初始化特殊地图 + self.mapsList.remove(self.mapNum) #从可选地图列表中移除 + self.createMapDisplayArmorStands() # 更新全息显示 + mapManager = MapManager(self.mapNum) + mapDisplay = mapManager.getDisplay() + self.broadcastTitle(u"§a{}".format(mapDisplay), u"§eRound {}".format(self.round), 0, 90, 10) + + # 为房间内每个玩家对象执行 + for playerObj in self.playerList.values(): + if playerObj.player.isInsideVehicle(): #如果玩家在船内则删除船 + playerObj.player.getVehicle().remove() + self.playingList.append(playerObj.name) #添加到游戏中列表 + playerObj.updatePlayerData() #更新玩家数据 + playerObj.updateJoinLoc() #更新玩家进入房间前的位置 + joinPos = self.map.getJoinPosition() #获取玩家进入房间的位置 + playerObj.teleport(joinPos) #传送玩家到房间内 + playerObj.updateLastMap(self.mapNum) #更新玩家上一次游玩的地图 + playerObj.setInvisible() #设置玩家隐身 + playerObj.startReadyParticle() #开始准备粒子效果 + + if playerObj.musicMode: #如果玩家启用了音乐模式 + playerObj.stopRecordSounds() #停止可能在播放的音乐 + playerObj.playIceboatMapSound(self.mapNum) + + self.playerMapTimes[playerObj.name] = playerObj.playerData.getMapTimes(self.mapNum) #获取每个玩家的完成次数 + self.playerTotalMapTimes[playerObj.name] = playerObj.playerData.getTotalMapTimes() #获取每个玩家的总完成次数 + if playerObj.detailMode: #如果玩家启用了详细模式 + self.mapManager = MapManager(self.mapNum) + playerObj.sendMessage(u"§b[§e{}§b] §a本地图由 §f{} §a等人参与制作".format(self.map.display, self.mapManager.getCreator())) + self.bindPlayerInPreparingArea(playerObj) #为玩家绑定检查点任务 + self.playingCount = self.playerCount #更新正在游戏中的玩家数量 + self.enterPrepaing() #进入准备阶段 + def enterPrepaing(self): #待更新,更改进入阶段的时长并加入OB旁观机制 + self.isPreparing = True #进入准备阶段 + # 准备阶段设置 + self.map.replaceBlock(START_LINE_MATERIAL) # 启动线设置 + # 准备阶段流程 + def countdownTask1(): + self.countdownTaskId = None + if self.isEmpty(): # 检查房间内是否还有玩家 + self.closeRoom() #没有玩家则关闭房间 + return + self.countdownToAll(u'§f〓 5 〓', u'§7●●●●●', 1.0) + self.countdownTaskId = ps.scheduler.runTaskLater(countdownTask2, 20) + def countdownTask2(): + self.countdownTaskId = None + if self.isEmpty(): + self.closeRoom() + return + self.countdownToAll(u'§a〓 4 〓', u'§c●§7●●●●', 1.0) + self.countdownTaskId = ps.scheduler.runTaskLater(countdownTask3, 20) + def countdownTask3(): + self.countdownTaskId = None + if self.isEmpty(): + self.closeRoom() + return + self.countdownToAll(u'§b〓 3 〓', u'§c●●§7●●●', 1.0) + self.countdownTaskId = ps.scheduler.runTaskLater(countdownTask4, 20) + def countdownTask4(): + self.countdownTaskId = None + if self.isEmpty(): + self.closeRoom() + return + self.countdownToAll(u'§d〓 2 〓', u'§c●●●§7●●', 1.0) + self.countdownTaskId = ps.scheduler.runTaskLater(countdownTask5, 20) + def countdownTask5(): + self.countdownTaskId = None + if self.isEmpty(): + self.closeRoom() + return + self.countdownToAll(u'§e〓 1 〓', u'§c●●●●§7●', 1.0) + self.countdownTaskId = ps.scheduler.runTaskLater(countdownTask6, 20) + def countdownTask6(): + self.countdownTaskId = None + if self.isEmpty(): + self.closeRoom() + return + self.countdownToAll(u'§c§l〓 GO 〓', u'§a●●●●●', 2.0) + self.isPreparing = False #准备阶段结束 + for playerObj in self.playerList.values(): #获取玩家对象 + playerObj.stopReadyParticle() #结束准备粒子展示 + self.enterStarting() + # 准备阶段开始 + self.countdownTaskId = ps.scheduler.runTaskLater(countdownTask1, 101) + def enterStarting(self): + self.isStarting = True # 进入开始阶段 + # 开始阶段设置 + for key in list(self.activeTasks.keys()): #清理非系统任务 + if key != 'system': + self.clearTasks(key) + + removeScoreboardObjective(u"IBScoreList") + self.createScoreboardRanking() #初始化计分板 + # 各玩家设置 + for playerObj in self.playerList.values(): #获取玩家对象 + playerObj.unsetInvisible() #解除玩家隐身 + playerObj.spawnAndRideBoat() #生成船并绑定 + playerObj.setStartMoment() #设置开始时间戳 + playerObj.startActionBarUpdates(False) + playerObj.startParticle() #开始粒子展示 + #command = u'minecraft:scoreboard players display numberformat {playerName} IBPlayerRank blank'.format(playerName=playerObj.name) + #getServer().dispatchCommand(playerObj.player, command) + # 开始阶段设置 + self.map.replaceBlock(Material.TRIPWIRE) # 启动线移除 + self.isGaming = True # 进入游戏阶段 + self.rankPlayerInGame() # 更新排名 + self.trackTask('system', ps.scheduler.scheduleRepeatingTask(lambda: self.updateGamingState(), 0, 1)) + def updateGamingState(self): + # 调试启用,用于检测循环任务是否停止 + if self.isEmpty(): #如果房间为空则关闭房间 + self.closeRoom() + return + + # 循环检测玩家状态 + self.allFinished = True #默认所有玩家都完成 + for playerObj in self.playerList.values(): + if playerObj.name not in self.playingList: #如果玩家不在游戏中列表 + continue + if not playerObj.inVehicle(): #如果玩家不在载具内 + if playerObj.name in self.playingList: #如果玩家还在游戏中 + self.dnfPlayer(playerObj.name) #移出玩家 + if self.isEnding: #若进入结束阶段则跳过 + return + + # 检查点位进度 + if not playerObj.hasFinished: #玩家还没完成 + self.allFinished = False #存在未完成玩家 + mapNum = self.map.mapNum #获取地图编号 + pointArea = self.map.getPointArea(playerObj.point) #获取玩家当前检查点区域 + if playerObj.arrivePoint(pointArea): #玩家到达检查点 + self.rankPlayerInGame() #通过检查点时更新全局排名 + playerObj.updateTimer() #更新玩家时间戳 + if playerObj.point >= self.map.point: #完成一圈 + playerObj.addLap() #圈数增加 + playerObj.resetPoint() #重置检查点 + if playerObj.lap <= self.map.lap: #未完成所有圈的情况 + playerObj.addLapTitle() + playerObj.addLapSound() + else: + if not self.hasFinished: #如果此前没有完成的玩家 + self.enterEndCountdown() #进入结束倒计时 + self.settleFinishedPlayer(playerObj) #对完成玩家的结算 + + playerObj.setPointsTimer() #设置玩家检查点时间戳 + playerObj.updateMultiBestMapRecordPointTimer(mapNum, playerObj.lap, playerObj.point) #更新玩家多人最好成绩点位 + playerObj.updateDValueText() + playerObj.showMultiTimerInActionBar() #更新玩家动态栏显示 + if playerObj.detailMode: #详细模式 + if playerObj.lap <= self.map.lap: + playerObj.showTimerByMessage(self.map.display) #显示详细信息 + + if self.allFinished: #所有玩家完成则在3秒后关闭房间 + self.isStarting = False #结束启动状态 + self.enterEnding() #进入结束阶段 + def enterEndCountdown(self): + countdown = int(ENDING_COUNTDOWN) if ENDING_COUNTDOWN >= 200 else 200 + countdownSecond = int(countdown / 20) + self.broadcastTitle(u"§f", u"§c有玩家完成,进入{}秒结束倒计时".format(countdownSecond), 0, 15, 5) + self.broadcastSound(Sound.BLOCK_NOTE_BLOCK_BASS, 1, 1) + + def countdownTask1(): + self.countdownTaskId = None + if self.isEmpty(): + self.closeRoom() + return + if self.allFinished: #如果全部完成则不继续倒计时 + return + self.broadcastTitle(u"§f", u"§c还剩5秒", 0, 15, 5) + self.broadcastSound(Sound.BLOCK_NOTE_BLOCK_BASS, 1, 1) + self.countdownTaskId = ps.scheduler.runTaskLater(countdownTask2, 20) + def countdownTask2(): + self.countdownTaskId = None + if self.isEmpty(): + self.closeRoom() + return + if self.allFinished: #如果全部完成则不继续倒计时 + return + self.broadcastSound(Sound.BLOCK_NOTE_BLOCK_BASS, 1, 1) + self.countdownTaskId = ps.scheduler.runTaskLater(countdownTask3, 20) + def countdownTask3(): + self.countdownTaskId = None + if self.isEmpty(): + self.closeRoom() + return + if self.allFinished: #如果全部完成则不继续倒计时 + return + self.broadcastSound(Sound.BLOCK_NOTE_BLOCK_BASS, 1, 1) + self.countdownTaskId = ps.scheduler.runTaskLater(countdownTask4, 20) + def countdownTask4(): + self.countdownTaskId = None + if self.isEmpty(): + self.closeRoom() + return + if self.allFinished: #如果全部完成则不继续倒计时 + return + self.broadcastSound(Sound.BLOCK_NOTE_BLOCK_BASS, 1, 1) + self.countdownTaskId = ps.scheduler.runTaskLater(countdownTask5, 20) + def countdownTask5(): + self.countdownTaskId = None + if self.isEmpty(): + self.closeRoom() + return + if self.allFinished: #如果全部完成则不继续倒计时 + return + self.broadcastSound(Sound.BLOCK_NOTE_BLOCK_BASS, 1, 1) + self.countdownTaskId = ps.scheduler.runTaskLater(countdownTask6, 20) + def countdownTask6(): + self.countdownTaskId = None + if self.isEmpty(): + self.closeRoom() + return + if self.allFinished: #如果全部完成则不继续倒计时 + return + self.broadcastSound(Sound.BLOCK_NOTE_BLOCK_BASS, 1, 2) + self.broadcastTitle(u"§f", u"§c本局结束", 0, 15, 5) + self.enterHalfTime() + + self.countdownTaskId = ps.scheduler.runTaskLater(countdownTask1, countdown-100) + def enterEnding(self): + self.isEnding = True + ps.scheduler.runTaskLater(lambda: self.enterHalfTime(), ENDING_INTERVAL) #阶段 + def enterHalfTime(self): #待更新,进入中场环节 + if self.isHalftime: + return #不重复进入中场休息 + if self.isEmpty(): + self.closeRoom() + return + + self.isHalftime = True + + self.stopCountdownTask() # 停止倒计时任务 + playingList = list(self.playingList) #获取游戏中列表 + for index, playerName in enumerate(playingList): + self.dnfPlayer(playerName) #执行玩家退出 + roomsManager.setAvailableRoom(self.mapNum, self.roomNum, False) #房间可用 + self.round += 1 #增加轮次 + + if not self.mapsList: #如果没有可选地图 + self.resetMaps() #重置可选地图 + self.mapNum = seasonManager.getSeasonFirstMap() #默认赛季首图 + else: + self.mapNum = self.mapsList[0] + self.roomNum = 1 #默认1号房 + self.map = IceboatMap(self.mapNum, self.roomNum) + self.createHologram() + + removeScoreboardObjective(u"IBPlayerRank") + self.createScoreboardScoreList() + self.updateScoreboardScoreList() + + self.resetRoom() + #判断游戏结束 + for playerName, score in self.scoreList.items(): + if score >= self.targetScore: + self.settleRoom() + return + def settleRoom(self): #结算房间 + broadcast(u"§f") + broadcast(u"§a[比赛房间] §a比赛结束 | 回合数 §e{}".format(self.round-1)) + sortedList = sorted(self.scoreList.items(), key=lambda x: x[1], reverse=True) + rank = 0 + tempRank = 0 + lastScore = 0 + for playerName, score in sortedList: + if score == lastScore: + tempRank += 1 + else: + if tempRank > 0: + rank += tempRank + 1 + tempRank = 0 + else: + rank += 1 + if playerName not in self.playerList: + continue + playerObj = self.playerList[playerName] + if playerObj: + vault = self.addVaultByScore(playerObj, score) #结算Vault + message = u"§a[比赛房间] §eNo.{rank} {score} §a分 {levelColor}[{titleDisplay}]§f{playerName} §a| 获得 §e{vault} §aDC币".format( + levelColor=playerObj.playerData.getLevelColor(), rank=rank, + titleDisplay=playerObj.playerData.getTitleDisplay() ,playerName=playerObj.name, score=score, vault=vault) + broadcast(message) + lastScore = score + broadcast(u"§f") + self.closeRoom() + def resetRoom(self): + for playerObj in self.playerList.values(): + playerName = playerObj.name + self.playerList[playerName] = PlayerInGame(playerName) #重置玩家对象 + self.stopCountdownTask() # 停止倒计时任务 + self.clearTasks('system')# 清理系统任务 + self.rankList = [] #实时排名 + self.finishList = [] #完成列表 + self.playingList = [] #游戏中列表 + self.finishCount = 0 # 完成玩家数量 + self.playingCount = 0 # 正在游戏中的玩家数量 + self.isRunning = False + self.isPreparing = False + self.isGaming = False + self.isStarting = False + self.isEnding = False + self.hasFinished = False + self.createMapDisplayArmorStands() + def closeRoom(self): #在任意节点关闭房间 + self.clearHologram() # 清理全息显示 + if not self.isCompeting: #不重复关闭 + return + self.isCompeting = False + self.stopCountdownTask() # 停止倒计时任务 + removeScoreboardObjective(u"IBPlayerRank") + removeScoreboardObjective(u"IBScoreList") + + if self.isRunning: #在地图中则重置房间可用 + roomsManager.setAvailableRoom(self.mapNum, self.roomNum, False) + + for playerObj in self.playerList.values(): + self.delPlayer(playerObj.name) + self.delPlayer(playerObj.name) + self.clearTasks('system')# 清理系统任务 + self.initRoom() #重置房间 + # 玩家管理 ---------------------------------------------- + def addPlayer(self, playerName): + if self.isRunning: #若房间已开启 + return False, u"比赛启动中,无法加入" + if self.playerCount >= MAX_PLAYERS: #若房间已满 + return False, u"比赛房间已满,无法加入" + if len(self.scoreList) >= MAX_PLAYERS: #若房间已满 + if playerName not in self.scoreList: #若玩家不在计分中 + return False, u"计分中玩家数已达上限,无法加入" + if playerName in self.playerList: #若玩家已经在房间内 + return False, u"你已在该比赛房间内" + + initial = False + if self.isEmpty(): #若房间为空的时候进行初始化 + initial = True + if initial: + self.createMapDisplayItemFrame() # 地图显示功能 + self.createScoreboardScoreList() + + self.playerList[playerName] = PlayerInGame(playerName) #创建玩家对象 + if playerName not in self.scoreList: #若玩家不在分数列表中 + self.scoreList[playerName] = 0 #初始化分数 + self.updateScoreboardScoreList() + self.playerCount += 1 #玩家数量+1 + + player = getServer().getPlayer(playerName) + playerManager = PlayerManager(player) + playerManager.joinCompetitionTeam() + + + self.createMapDisplayArmorStands() # 更新全息显示 + self.save() # 保存房间状态 + return True, u"成功加入比赛" + def delPlayer(self, playerName): #玩家退出房间 + if playerName in self.playerList: #若玩家在房间内 + objective = getScoreboardObjective(u'InGame') + playerScore = objective.getScore(playerName) #获取玩家分数 + score = playerScore.getScore() #获取分数 + if score == 1: #1为玩家在游戏中 + self.dnfPlayer(playerName) #执行玩家退出 + else: #0为玩家不在游戏中 + self.removePlayer(playerName) #执行玩家移除 + def dnfPlayer(self, playerName): + if playerName in self.playerList: #若玩家在房间内 + self.clearTasks(playerName) # 清理玩家关联的循环任务 + playerObj = self.playerList[playerName] #获取玩家对象 + if not playerObj.hasFinished: #玩家未完成时离开 + self.playingCount -= 1 #正在游戏中的玩家数量-1 + self.scoreList[playerName] -= 2 #分数-2 + playerObj.sendTitle(u'§a§lDNF', u'§c-2分', 0, 80, 20) + playerObj.dnf = True + self.updateScoreboardRanking() + if self.isRunning: #启动后才执行的内容 + playerObj.teleportToJoinLoc() #传送回进入房间前的位置 + if not playerObj.hasFinished: + self.broadcastMessage( + u"§b[§e{}§b] {}[{}]§f{} §aDNF".format( + self.map.display, playerObj.playerData.getLevelColor(), + playerObj.playerData.getTitleDisplay() ,playerObj.name + ) + ) #游戏内播报退出 + if self.isPreparing: #准备中才执行的内容 + playerObj.stopReadyParticle() #停止准备粒子效果 + playerObj.unsetInvisible() #取消隐身 + if self.isStarting: #游戏开始中才执行的内容 + playerObj.stopActionBarUpdates() #停止ActionBar更新 + playerObj.stopParticle() #停止粒子效果 + if self.isGaming: #游戏中才执行的内容 + playerObj.clearBoat() #离开时清理绑定的船 + if playerObj.name in self.playingList: + self.playingList.remove(playerObj.name) #从游戏中列表中移除 + if not self.isAnyoneInGame(): + if not self.hasFinished: #若没有一个玩家完成比赛 + self.firstPlayerName = playerName #记录第一名玩家 + self.enterHalfTime() + self.save() #保存房间状态 + def removePlayer(self, playerName): + if playerName in self.playerList: #若玩家在房间内 + self.clearTasks(playerName) # 清理玩家关联的循环任务 + playerObj = self.playerList[playerName] #获取玩家对象 + if self.isCompeting: + self.broadcastMessage( + u"§b[§e{}§b] {}[{}]§f{} §a离开了比赛房间".format( + self.map.display, playerObj.playerData.getLevelColor(), + playerObj.playerData.getTitleDisplay() ,playerObj.name + ) + ) #游戏内播报退出 + player = playerObj.player + playerManager = PlayerManager(player) + playerManager.leaveCompetitionTeam() + + if playerName == self.firstPlayerName: #如果是第一名玩家 + self.firstPlayerName = None #删除第一名玩家 + + del self.playerList[playerName] #删除玩家对象 + + self.createMapDisplayArmorStands() # 更新全息显示 + #房间设置 + self.playerCount -= 1 #玩家数量-1 + + self.save() #保存房间状态 + if self.isEmpty(): #最后一个玩家离开 + self.closeRoom() #关闭房间 + def rankPlayerInGame(self): + players = list(self.playerList.values()) # 获取所有玩家对象 + # 多级排序:圈数(降) -> 检查点(降) -> 单圈时间戳() -> 名字(升) + players.sort(key=lambda p: ( + -p.lap, + -p.point, + p.passMoment, + p.name.lower() + )) + players = list(filter(lambda x: x not in self.finishList, players)) #过滤掉完成的玩家 + self.rankList = players # 存储排名好的对象列表 + for rank, player in enumerate(players, start=self.finishCount+1): # 更新未完成的玩家排名 + player.updateRank(rank) + self.updateScoreboardRanking() + def isPlayerInRoom(self, playerName): + if playerName in self.playerList: + return True + return False + def settleFinishedPlayer(self, playerObj): + self.finishCount += 1 + self.playingCount -= 1 + self.finishList.append(playerObj) + self.hasFinished = True #存在完成玩家 + finishTime = playerObj.timer #完成时间戳 + playerObj.finishTime = finishTime + # 为所有玩家广播消息 + message = u"§b[§e{}§b] §a第 §e{} §a名 {}[{}]§f{} §a总用时 §e{:.2f} §a秒".format( + self.map.display, playerObj.rank, playerObj.playerData.getLevelColor(), + playerObj.playerData.getTitleDisplay() ,playerObj.name, finishTime) + broadcast(message) + playerObj.hasFinished = True # 标记玩家已完成 + playerObj.playSound(Sound.ENTITY_FIREWORK_ROCKET_LAUNCH, 1.0, 1.0) + playerObj.playSound(Sound.ENTITY_FIREWORK_ROCKET_TWINKLE, 1.0, 1.0) + playerObj.stopActionBarUpdates() + playerObj.stopParticle() + + playerObj.sendTitle(u'§a§l第 §e§l{} §a§l名'.format(playerObj.rank), u'§6用时 §e{:.2f} §6| 获得 §e{} §6分'.format(playerObj.timer, self.getRankScore(playerObj.rank)), 0, 80, 20) + rankScore = self.getRankScore(playerObj.rank) + if playerObj.rank == 1: + self.firstPlayerName = playerObj.name #更新第一名玩家 + + self.scoreList[playerObj.name] += rankScore + record = playerObj.checkMultiRecord(self.map.mapNum) + + self.updateScoreboardRanking() + if record: #纪录更新 + record = float(record) + playerObj.playSound(Sound.ENTITY_PLAYER_LEVELUP, 1.0, 1.0) + self.broadcastMessage( + u"§b[§e{}§b] {}[{}]§f{} §a刷新了多人纪录!§7(旧纪录:{:.2f})".format( + self.map.display, playerObj.playerData.getLevelColor(), + playerObj.playerData.getTitleDisplay() ,playerObj.name, record + ) + ) + if playerObj.detailMode: #如果玩家启用了详细模式 + playerObj.sendMessage(u"§b[§e{}§b] §a最佳纪录 §e{:.2f} §a秒 | 第 §e{} §a次完成该地图".format( + self.map.display, + playerObj.playerData.getMultiBestMapRecord(self.mapNum), + self.playerMapTimes[playerObj.name] + 1)) + if seasonManager.inSeasonMaps(self.mapNum): #如果是赛季地图 + playerObj.sendMessage(u"§b[§e{}§b] §a该地图当季分数 §e{:.2f} §a| 当季总分 §e{:.2f}".format( + self.map.display, + playerObj.playerData.getSeasonMapScore(self.mapNum), + playerObj.playerData.getSeasonScore())) + else: + playerObj.sendMessage(u"§b[§e{}§b] §a该地图不是当季地图".format(self.map.display)) + def bindPlayerInPreparingArea(self, playerObj): + def checkTask(): + + if not playerObj.inArea(self.map.getPreparingArea()): + actionBar(playerObj.player, u'§c请勿离开起点区域') + playerObj.teleport(self.map.getJoinPosition()) + taskId = ps.scheduler.scheduleRepeatingTask(checkTask, 0, 20) + self.trackTask(playerObj.name, taskId) + def updatePlayerInfo(self, playerName): + if playerName in self.playerList: + self.playerList[playerName].updatePlayerData() #更新玩家对象数据 + self.save() #保存房间状态 + # 房间管理 ---------------------------------------------- + def isEmpty(self): + return self.playerCount == 0 + def isAnyoneInGame(self): + if self.playingList: + return True + return False + def setIceboatMap(self, mapNum, roomNum): + self.mapNum = mapNum + self.roomNum = roomNum + self.map = IceboatMap(self.mapNum, self.roomNum) + def setMapNum(self, mapNum): + self.mapNum = int(mapNum) + def setRoomNum(self, roomNum): + self.roomNum = roomNum + def setTargetScore(self, score): + score = int(score) + for playerName, playerScore in self.scoreList.items(): + if int(playerScore) >= score: #若有玩家已经超过设定分数则设定失败 + return False + self.targetScore = score + self.updateScoreboardScoreListDisplay() + return True + def resetMaps(self): + self.mapsList = list(seasonManager.getSeasonMaps()) + def save(self): + global competitionGame + competitionGame = self + # 任务管理 -------------------------------- + def trackTask(self, owner, taskId): + if owner not in self.activeTasks: + self.activeTasks[owner] = [] + self.activeTasks[owner].append(taskId) + def clearTasks(self, owner): + if owner in self.activeTasks: + taskIds = list(self.activeTasks[owner]) + for taskId in taskIds: + if taskId is not None: + ps.scheduler.stopTask(taskId) + del self.activeTasks[owner] + def stopCountdownTask(self): + if self.countdownTaskId is not None: + ps.scheduler.stopTask(self.countdownTaskId) + self.countdownTaskId = None + # 信息显示 ---------------------------------------------- + def createHologram(self): + self.createMapDisplayArmorStands() + self.createMapDisplayItemFrame() + self.save() #保存房间状态 + def createMapDisplayArmorStands(self): + config = ps.config.loadConfig(HOLOGRAME_CONFIG_PATH) + hologramLoc = config.get("8") #比赛房间为8号 + if hologramLoc is not None: + x = hologramLoc.get("x") + y = hologramLoc.get("y") + z = hologramLoc.get("z") + if x is not None and y is not None and z is not None: + world = worldManager.getWorld() + self.clearMapDisplayArmorStands() # 清除旧的盔甲架 + sortedPlayers = sorted(self.playerList.keys(), key=lambda playerName: PlayerDataManager(playerName).getSeasonScore()) #按玩家当季总分排序 + # 设置名字之间的垂直偏移量 + xOffset = 2 + yOffset = 0.13 - (ARMOR_STAND_INTERVAL / 2) * (len(sortedPlayers) + 2) + zOffset = - 1.1 + + bottomLoc = Location(world, x, world.getMinHeight(), z) #预处理位置 + + # 为每个玩家创建盔甲架显示名字 + for playerName in sortedPlayers: + # 加载玩家数据 + playerData = PlayerDataManager(playerName) + if playerName == self.firstPlayerName: + nameColor = u"§e" + else: + nameColor = u"§f" + score = self.scoreList[playerName] + newScore = score + 10 + scoreColor = self.getScoreColor(newScore) + customName = u"{}[{}]{}{}{}[{}]".format(playerData.getLevelColor(), playerData.getTitleDisplay(), + nameColor, playerName, scoreColor, score) + self.createArmorStand(world, bottomLoc, x + xOffset, y + yOffset, z + zOffset, customName) + yOffset += ARMOR_STAND_INTERVAL + + # 地图信息盔甲架 + customName = u"§a圈数 §e{} §a回合 §e{} §a抢 §e{}".format(self.map.lap, self.round, self.targetScore) + self.createArmorStand(world, bottomLoc, x + xOffset, y + yOffset, z + zOffset, customName) + yOffset += ARMOR_STAND_INTERVAL + + # 地图名称盔甲架 + if self.isRunning: #房间状态判定 + roomStatus = u"§c[启动]" + else: + roomStatus = u"§a[等待]" + customName = u"§b§l【§e§l{}§b§l】{}".format(self.map.display, roomStatus) + self.createArmorStand(world, bottomLoc, x + xOffset, y + yOffset, z + zOffset, customName) + yOffset += ARMOR_STAND_INTERVAL + def createMapDisplayItemFrame(self): + config = ps.config.loadConfig(HOLOGRAME_CONFIG_PATH) + hologramLoc = config.get("8") #比赛房间为8号 + if hologramLoc is not None: + x = hologramLoc.get("x") + y = hologramLoc.get("y") + z = hologramLoc.get("z") + if x is not None and y is not None and z is not None: + world = getServer().getWorld(WORLD_NAME) + if self.mapDisplayItemFrame: # 删除并覆盖已有展示框 + self.mapDisplayItemFrame.remove() + displayLoc = Location(world, x - 1, y + 1, z) #最终展示框位置,偏移可修改 + bottomLoc = Location(world, x, world.getMinHeight(), z) # 预处理位置 + itemFrame = bottomLoc.getWorld().spawnEntity(bottomLoc, EntityType.ITEM_FRAME)#生成展示框 + mapItem = ItemStack(Material.MAP) + meta = mapItem.getItemMeta() + if int(self.mapNum) > int(AVAILABLE_MAPNUM): + num = 0 + else: + num = self.mapNum + customModelKey = fromString("template:map{}".format(int(num))) + meta.setItemModel(customModelKey) + mapItem.setItemMeta(meta) + itemFrame.setItem(mapItem) + itemFrame.setVisible(False) + self.mapDisplayItemFrame = itemFrame # 存储展示框实体 + + ps.scheduler.runTaskLater(lambda: itemFrame.teleport(displayLoc), 1) #延迟传送 + ps.scheduler.runTaskLater(lambda: itemFrame.setFacingDirection(BlockFace.SOUTH), 1) #调整面朝方向 + def clearHologram(self): + self.clearMapDisplayArmorStands() + self.clearMapDisplayItemFrame() + def clearMapDisplayArmorStands(self): + for armorStand in self.mapDisplayArmorStands: + if armorStand and not armorStand.isDead(): + armorStand.remove() + self.mapDisplayArmorStands = [] + def clearMapDisplayItemFrame(self): + if self.mapDisplayItemFrame: + self.mapDisplayItemFrame.remove() + self.mapDisplayItemFrame = None + def createScoreboardRanking(self): + removeScoreboardObjective(u"IBPlayerRank") #重置已有对应计分板 + self.playerScoreboardObj = getScoreboardObjective(u"IBPlayerRank") + self.playerScoreboardObj.setDisplaySlot(DisplaySlot.SIDEBAR_TEAM_AQUA) + self.playerScoreboardObj.setDisplayName(u"§b§l【§e§l实时排名§b§l】") + + displayScore = self.playerScoreboardObj.getScore(u"第一行空行") + displayScore.setScore(0) + displayScore.numberFormat(NumberFormat.blank()) + displayScore.customName(Component.text(u"§f")) + + displayScore = self.playerScoreboardObj.getScore(u"最后一行空行") + displayScore.setScore(-9) + displayScore.numberFormat(NumberFormat.blank()) + displayScore.customName(Component.text(u"§f")) + + displayScore = self.playerScoreboardObj.getScore(u"广告行1") + displayScore.setScore(-10) + displayScore.numberFormat(NumberFormat.blank()) + displayScore.customName(Component.text(ADVERTISEMENT_TEXT_1)) + displayScore = self.playerScoreboardObj.getScore(u"广告行2") + displayScore.setScore(-11) + displayScore.numberFormat(NumberFormat.blank()) + displayScore.customName(Component.text(ADVERTISEMENT_TEXT_2)) + def updateScoreboardRanking(self): + if self.playerScoreboardObj: + for playerObj in self.rankList: + rank = playerObj.rank + playerScore = self.playerScoreboardObj.getScore(playerObj.name) + playerScore.setScore(-rank) + playerScore.numberFormat(NumberFormat.blank()) + color = u"§e" + namecolor = u"§f" + if playerObj.hasFinished: + color = u"§a" + namecolor = u"§a" + if playerObj.dnf: + color = u"§c" + namecolor = u"§c" + score = self.scoreList[playerObj.name] + addScore = self.getRankScore(rank) + newScore = score + addScore + scoreColor = self.getScoreColor(newScore) + playerScore.customName(Component.text(u" {color}§lNo.{} {namecolor}{} {scoreColor}[{}] ".format(rank, playerObj.name, score, color=color, namecolor=namecolor, scoreColor=scoreColor))) + def createScoreboardScoreList(self): + removeScoreboardObjective(u"IBScoreList") #重置已有对应计分板 + self.playerScoreboardObj = getScoreboardObjective(u"IBScoreList") + self.playerScoreboardObj.setDisplaySlot(DisplaySlot.SIDEBAR_TEAM_AQUA) + self.updateScoreboardScoreListDisplay() + + displayScore = self.playerScoreboardObj.getScore(u"第一行空行") + displayScore.setScore(9999) + displayScore.numberFormat(NumberFormat.blank()) + displayScore.customName(Component.text(u"§f")) + + displayScore = self.playerScoreboardObj.getScore(u"最后一行空行") + displayScore.setScore(-9999) + displayScore.numberFormat(NumberFormat.blank()) + displayScore.customName(Component.text(u"§f")) + + displayScore = self.playerScoreboardObj.getScore(u"广告行1") + displayScore.setScore(-10000) + displayScore.numberFormat(NumberFormat.blank()) + displayScore.customName(Component.text(ADVERTISEMENT_TEXT_1)) + + displayScore = self.playerScoreboardObj.getScore(u"广告行2") + displayScore.setScore(-10001) + displayScore.numberFormat(NumberFormat.blank()) + displayScore.customName(Component.text(ADVERTISEMENT_TEXT_2)) + def updateScoreboardScoreListDisplay(self): + self.playerScoreboardObj.setDisplayName(u"§b§l【§e§l积分排名 抢{}§b§l】".format(self.targetScore)) + def updateScoreboardScoreList(self): + if self.playerScoreboardObj: + sortedList = sorted(self.scoreList.items(), key=lambda x: x[1], reverse=True) + rank = 0 + tempRank = 0 + lastScore = 0 + for playerName, score in sortedList: + if score == lastScore: + tempRank += 1 + else: + if tempRank > 0: + rank += tempRank + 1 + tempRank = 0 + else: + rank += 1 + playerScore = self.playerScoreboardObj.getScore(playerName) + playerScore.setScore(score) + playerScore.numberFormat(NumberFormat.blank()) + if rank <= 3: #前三名金色 + color = u"§e" + else: + color = u"§f" + score = self.scoreList[playerName] + newScore = score + 10 + scoreColor = self.getScoreColor(newScore) + playerScore.customName(Component.text(u" {color}§lNo.{} {color}{} {scoreColor}[{}] ".format(rank, playerName, score, color=color, scoreColor=scoreColor))) + lastScore = score + # 辅助方法 -------------------------------- + def addVaultByScore(self, playerObj, score): + if playerObj.name in self.playerList: + if vaultEconomy: + vault = 5 * score * len(self.playerList) + if vault < 0: + vault = 0 + vaultEconomy.depositPlayer(playerObj.player, vault) + return vault + def getRankScore(self, rank): + score = 0 + if rank == 1: + score = 10 + elif rank == 2: + score = 7 + elif rank == 3: + score = 5 + elif rank == 4: + score = 4 + elif rank == 5: + score = 3 + elif rank == 6: + score = 1 + elif rank == 7: + score = 0 + elif rank == 8: + score = -1 + else: + score = -2 + return score + def getScoreColor(self, score): + color = u"§b" + dvalue = int(self.targetScore) - int(score) + if dvalue <= 0: + color = u"§c§l" + return color + def countdownToAll(self, title, subtitle, pitch): + self.broadcastTitle(title, subtitle, 0, 20, 10) + self.broadcastSound(Sound.BLOCK_NOTE_BLOCK_PLING, 1.0, pitch) + def broadcastMessage(self, message): + for playerObj in self.playerList.values(): + playerObj.player.sendMessage(message) + def broadcastTitle(self, title=u"§f", subtitle=u"§f", fadeIn=0, stay=90, fadeOut=10): + for playerObj in self.playerList.values(): + playerObj.player.sendTitle(title, subtitle, fadeIn, stay, fadeOut) + def broadcastSound(self, sound=Sound.BLOCK_NOTE_BLOCK_PLING, volume=1.0, pitch=1.0): + for playerObj in self.playerList.values(): + playerObj.player.playSound(playerObj.player, sound, volume, pitch) + def createArmorStand(self, world, bottomLoc, x, y, z, customName): + armorStand = world.spawn(bottomLoc, ArmorStand) #先在底部创造 + armorStand.setGravity(False) #设置无重力 + armorStand.setVisible(False) #设置不可见 + armorStand.setCollidable(False) #设置无碰撞箱 + armorStand.setCustomName(customName) #设置显示名 + armorStand.setCustomNameVisible(True) #设置显示名可见 + displayLoc = Location(world, x, y, z) #设置展示位置 + armorStand.teleport(displayLoc) #传送展示框 + self.mapDisplayArmorStands.append(armorStand) #将展示框添加到房间 +class MultiGameRoom: #多人游戏房间类 + def __init__(self, roomId): + self.roomId = roomId + self.mapNum = 1 #默认1号地图 + self.roomNum = 1 #默认1号房 + self.map = None + self.playerCount = 0 # 房间内玩家数量 + self.finishCount = 0 # 完成玩家数量 + self.playingCount = 0 # 正在游戏中的玩家数量 + + self.playerList = {} # PlayerInGame对象的字典,键为玩家名称 + self.activeTasks = {} + self.countdownTaskId = None + + self.rankList = [] #实时排名 + self.finishList = [] #完成列表 + self.mapDisplayArmorStands = [] # 存储该房间的盔甲架实体 + self.mapDisplayItemFrame = None # 存储该房间的展示框实体 + + self.isRunning = False #运行状态 包含Preparing和Gaming + self.isPreparing = False #准备状态 + self.isGaming = False #游戏状态 包含Starting和Ending + self.isStarting = False #开始状态 + self.isEnding = False #结束状态 + self.isClosed = False #是否关闭 + self.allFinished = False #是否所有玩家都完成 + + self.playerMapTimes = {} + self.playerTotalMapTimes = {} + # 房间管理 ---------------------------------------------- + def isEmpty(self): #判断房间是否为空 + return self.playerCount == 0 + def setIceboatMap(self, mapNum, roomNum): #设置房间地图对象 + self.mapNum = mapNum + self.roomNum = roomNum + self.map = IceboatMap(self.mapNum, self.roomNum) + def setMapNum(self, mapNum): #设置房间地图编号 + self.mapNum = int(mapNum) + def setRoomNum(self, roomNum): #设置房间房号 + self.roomNum = roomNum + def save(self): # 更新房间对象 + multiGames[self.roomId] = self + # 玩家管理 ---------------------------------------------- + def addPlayer(self, playerName): #玩家进入房间 + if self.isRunning: #若房间已开启 + return False, u"房间已启动,无法加入" + + if self.playerCount >= MAX_PLAYERS: #若房间已满 + return False, u"房间已满,无法加入" + + if playerName in self.playerList: #若玩家已经在房间内 + return False, u"你已在该房间内" + + initial = False + if self.isEmpty(): #若房间为空的时候进行初始化 + initial = True + + self.playerList[playerName] = PlayerInGame(playerName) #创建玩家对象 + if initial: + mapNum = self.playerList[playerName].playerData.getLastMap() #获取玩家上一次玩的地图 + self.setMapNum(mapNum) #设置房间地图编号 + self.map = IceboatMap(self.mapNum, self.roomNum) #设置地图 + self.createMapDisplayItemFrame() # 地图显示功能 + + self.playerCount += 1 #玩家数量+1 + + self.createMapDisplayArmorStands() # 更新全息显示 + self.save() # 保存房间状态 + + return True, u"成功加入房间" + def delPlayer(self, playerName): #玩家在游戏中离开房间 + if playerName in self.playerList: #若玩家在房间内 + # 清理玩家关联的循环任务 + if playerName in self.activeTasks: + for taskId in self.activeTasks[playerName]: + if taskId is not None: + ps.scheduler.stopTask(taskId) + del self.activeTasks[playerName] + #玩家设置 + playerObj = self.playerList[playerName] #获取玩家对象 + if not playerObj.hasFinished: #玩家未完成时离开 + self.playingCount -= 1 #正在游戏中的玩家数量-1 + if self.isRunning: #启动后才执行的内容 + playerObj.teleportToJoinLoc() #传送回进入房间前的位置 + self.broadcastMessage( + u"§b[§e{}§b] {}[{}]§f{} §a离开了房间".format( + self.map.display, playerObj.playerData.getLevelColor(), + playerObj.playerData.getTitleDisplay() ,playerObj.name + ) + ) #游戏内播报退出 + if self.isPreparing: #准备中才执行的内容 + playerObj.stopReadyParticle() #停止准备粒子效果 + playerObj.unsetInvisible() #取消隐身 + if self.isPreparing or playerObj.hasFinished or not self.isRunning: #准备中或已完成才执行的内容 + if not self.isClosed: + playerObj.sendTitle(u"§f", u"§6离开成功", 5, 60, 10) + else: + if self.map: + lap = self.map.lap + point = self.map.point + vault = playerObj.leaveAddVault(lap, point) + playerObj.sendTitle(u"§f", u"§6离开成功 | 获得 §e{:.1f} §6DC币".format(vault), 5, 60, 10) + + if self.isStarting: #游戏开始中才执行的内容 + playerObj.stopActionBarUpdates() #停止ActionBar更新 + playerObj.stopParticle() #停止粒子效果 + if self.isGaming: #游戏中才执行的内容 + playerObj.clearBoat() #离开时清理绑定的船 + + spectators = playerObj.getSpectate() + del self.playerList[playerName] #删除玩家对象 + if not self.isClosed: # 房间未关闭时执行的内容 + self.createMapDisplayArmorStands() # 更新全息显示 + #房间设置 + self.playerCount -= 1 #玩家数量-1 + self.save() #保存房间状态 + + for spectatorName in spectators: + spectatorObj = playersInSpectate[spectatorName] + if not spectatorObj.changeTarget(): + spectatorObj.leave() + if self.isEmpty(): #最后一个玩家离开 + self.closeRoom() #关闭房间 + def rankPlayerInGame(self): #更新房间内玩家排名 + players = list(self.playerList.values()) # 获取所有玩家对象 + # 多级排序:圈数(降) -> 检查点(降) -> 单圈时间戳() -> 名字(升) + players.sort(key=lambda p: ( + -p.lap, + -p.point, + p.passMoment, + p.name.lower() + )) + players = list(filter(lambda x: x not in self.finishList, players)) #过滤掉完成的玩家 + self.rankList = players # 存储排名好的对象列表 + for rank, player in enumerate(players, start=self.finishCount+1): # 更新未完成的玩家排名 + player.updateRank(rank) + def isPlayerInRoom(self, playerName): #判断玩家是否在房间内 + if playerName in self.playerList: + return True + return False + def settleFinishedPlayer(self, playerObj): #完成玩家结算 + self.finishCount += 1 + self.playingCount -= 1 + self.finishList.append(playerObj) + finishTime = playerObj.timer #完成时间戳 + playerObj.finishTime = finishTime + # 为所有玩家广播消息 + message = u"§b[§e{}§b] §a第 §e{} §a名 {}[{}]§f{} §a总用时 §e{:.2f} §a秒".format( + self.map.display, playerObj.rank, playerObj.playerData.getLevelColor(), + playerObj.playerData.getTitleDisplay() ,playerObj.name, finishTime) + if playerObj.broadcastMode: #如果开启了成绩广播模式 + broadcast(message) + else: + self.broadcastMessage(message) + playerObj.hasFinished = True # 标记玩家已完成 + playerObj.playSound(Sound.ENTITY_FIREWORK_ROCKET_LAUNCH, 1.0, 1.0) + playerObj.playSound(Sound.ENTITY_FIREWORK_ROCKET_TWINKLE, 1.0, 1.0) + playerObj.stopActionBarUpdates() + playerObj.stopParticle() + mag = 0.75 + (self.playingCount + self.finishCount) * 0.25 + vault = playerObj.finishAddVault(mag=mag) + record = playerObj.checkMultiRecord(self.map.mapNum) + if record: #纪录更新 + record = float(record) + playerObj.playSound(Sound.ENTITY_PLAYER_LEVELUP, 1.0, 1.0) + self.broadcastMessage( + u"§b[§e{}§b] {}[{}]§f{} §a刷新了多人纪录!§7(旧纪录:{:.2f})".format( + self.map.display, playerObj.playerData.getLevelColor(), + playerObj.playerData.getTitleDisplay() ,playerObj.name, record + ) + ) + if playerObj.detailMode: #如果玩家启用了详细模式 + playerObj.sendMessage(u"§b[§e{}§b] §a最佳纪录 §e{:.2f} §a秒 | 第 §e{} §a次完成该地图 | 获得 §e{:.1f} §aDC币".format( + self.map.display, + playerObj.playerData.getMultiBestMapRecord(self.mapNum), + self.playerMapTimes[playerObj.name] + 1, + vault)) + if seasonManager.inSeasonMaps(self.mapNum): #如果是赛季地图 + playerObj.sendMessage(u"§b[§e{}§b] §a该地图当季分数 §e{:.2f} §a| 当季总分 §e{:.2f}".format( + self.map.display, + playerObj.playerData.getSeasonMapScore(self.mapNum), + playerObj.playerData.getSeasonScore())) + else: + playerObj.sendMessage(u"§b[§e{}§b] §a该地图不是当季地图".format(self.map.display)) + def bindPlayerInPreparingArea(self, playerObj): #绑定玩家在准备区域 + def checkTask(): + + if not playerObj.inArea(self.map.getPreparingArea()): + actionBar(playerObj.player, u'§c请勿离开起点区域') + playerObj.teleport(self.map.getJoinPosition()) + taskId = ps.scheduler.scheduleRepeatingTask(checkTask, 0, 20) + self.trackTask(playerObj.name, taskId) + def updatePlayerInfo(self, playerName): #更新玩家信息 + if playerName in self.playerList: + self.playerList[playerName].updatePlayerData() #更新玩家对象数据 + self.save() #保存房间状态 + # 信息显示 ---------------------------------------------- + def createHologram(self): #创建/更新全息显示 + self.createMapDisplayArmorStands() + self.createMapDisplayItemFrame() + self.save() #保存房间状态 + def createMapDisplayArmorStands(self): #创造盔甲架显示 + config = ps.config.loadConfig(HOLOGRAME_CONFIG_PATH) + hologramLoc = config.get(str(self.roomId)) + if hologramLoc is not None: + x = hologramLoc.get("x") + y = hologramLoc.get("y") + z = hologramLoc.get("z") + if x is not None and y is not None and z is not None: + world = getServer().getWorld(WORLD_NAME) + self.clearMapDisplayArmorStands() # 清除旧的盔甲架 + sortedPlayers = sorted(self.playerList.keys(), reverse=True) # 按玩家名字首字母排序 + + # 设置名字之间的垂直偏移量 + xOffset = 2 + yOffset = 0.13 - (ARMOR_STAND_INTERVAL / 2) * (len(sortedPlayers) + 2) + zOffset = - 1.1 + + bottomLoc = Location(world, x, world.getMinHeight(), z) #预处理位置 + + # 为每个玩家创建盔甲架显示名字 + for playerName in sortedPlayers: + # 加载玩家数据 + playerData = PlayerDataManager(playerName) + customName = u"{}[{}]§f{}".format(playerData.getLevelColor(), playerData.getTitleDisplay(), playerName) + self.createArmorStand(world, bottomLoc, x + xOffset, y + yOffset, z + zOffset, customName) + yOffset += ARMOR_STAND_INTERVAL + + # 地图信息盔甲架 + customName = u"§a难度 §e{} §a圈数 §e{}".format(self.map.difficulty, self.map.lap) + self.createArmorStand(world, bottomLoc, x + xOffset, y + yOffset, z + zOffset, customName) + yOffset += ARMOR_STAND_INTERVAL + + # 地图名称盔甲架 + if self.isRunning: #房间状态判定 + roomStatus = u"§c[启动]" + else: + roomStatus = u"§a[等待]" + customName = u"§b§l【§e§l{}§b§l】{}".format(self.map.display, roomStatus) + self.createArmorStand(world, bottomLoc, x + xOffset, y + yOffset, z + zOffset, customName) + yOffset += ARMOR_STAND_INTERVAL + def createMapDisplayItemFrame(self): #创造展示框显示 + config = ps.config.loadConfig(HOLOGRAME_CONFIG_PATH) + hologramLoc = config.get(str(self.roomId)) + if hologramLoc is not None: + x = hologramLoc.get("x") + y = hologramLoc.get("y") + z = hologramLoc.get("z") + if x is not None and y is not None and z is not None: + world = getServer().getWorld(WORLD_NAME) + if self.mapDisplayItemFrame: # 删除并覆盖已有展示框 + self.mapDisplayItemFrame.remove() + displayLoc = Location(world, x - 1, y + 1, z) #最终展示框位置,偏移可修改 + bottomLoc = Location(world, x, world.getMinHeight(), z) # 预处理位置 + itemFrame = bottomLoc.getWorld().spawnEntity(bottomLoc, EntityType.ITEM_FRAME)#生成展示框 + mapItem = ItemStack(Material.MAP) + meta = mapItem.getItemMeta() + if int(self.mapNum) > int(AVAILABLE_MAPNUM): + num = 0 + else: + num = self.mapNum + customModelKey = fromString("template:map{}".format(int(num))) + meta.setItemModel(customModelKey) + mapItem.setItemMeta(meta) + itemFrame.setItem(mapItem) + itemFrame.setVisible(False) + self.mapDisplayItemFrame = itemFrame # 存储展示框实体 + + ps.scheduler.runTaskLater(lambda: itemFrame.teleport(displayLoc), 1) #延迟传送 + ps.scheduler.runTaskLater(lambda: itemFrame.setFacingDirection(BlockFace.SOUTH), 1) #调整面朝方向 + def clearHologram(self): #清理全息显示 + self.clearMapDisplayArmorStands() + self.clearMapDisplayItemFrame() + def clearMapDisplayArmorStands(self): #清理盔甲架显示 + for armorStand in self.mapDisplayArmorStands: + if armorStand and not armorStand.isDead(): + armorStand.remove() + self.mapDisplayArmorStands = [] + def clearMapDisplayItemFrame(self): #清理展示框显示 + if self.mapDisplayItemFrame: + self.mapDisplayItemFrame.remove() + self.mapDisplayItemFrame = None + # 流程管理 ---------------------------------------------- + def enterRunning(self): #尝试运行 + # 运行前检查是否有可用副本 + roomNum = roomsManager.getAvailableRoom(self.mapNum) + if roomNum is None: #无可用房间 + for playerObj in self.playerList.values(): + player = playerObj.player + if player: + player.sendTitle(u"", u"§c剩余空房不足", 5, 50, 20) + player.playSound(player, Sound.BLOCK_NOTE_BLOCK_BASS, 1, 1) + return False + + # 运行成功设置 + self.isRunning = True # 开启成功 + self.roomNum = roomNum # 更新房间号 + roomsManager.setAvailableRoom(self.mapNum, self.roomNum, True) #更新房间状态 + self.map = IceboatMap(self.mapNum, self.roomNum) # 更新地图 + self.map.initialSpecialMap() #初始化特殊地图 + self.createMapDisplayArmorStands() # 更新全息显示 + # 为房间内每个玩家对象执行 + for playerObj in self.playerList.values(): + if playerObj.player.isInsideVehicle(): #如果玩家在船内则删除船 + playerObj.player.getVehicle().remove() + playerObj.updatePlayerData() #更新玩家数据 + playerObj.updateJoinLoc() #更新玩家进入房间前的位置 + joinPos = self.map.getJoinPosition() #获取玩家进入房间的位置 + playerObj.teleport(joinPos) #传送玩家到房间内 + playerObj.updateLastMap(self.mapNum) #更新玩家上一次游玩的地图 + playerObj.setInvisible() #设置玩家隐身 + playerObj.startReadyParticle() #开始准备粒子效果 + + if playerObj.musicMode: #如果玩家启用了音乐模式 + playerObj.stopRecordSounds() #停止可能在播放的音乐 + playerObj.playIceboatMapSound(self.mapNum) + + self.playerMapTimes[playerObj.name] = playerObj.playerData.getMapTimes(self.mapNum) #获取每个玩家的完成次数 + self.playerTotalMapTimes[playerObj.name] = playerObj.playerData.getTotalMapTimes() #获取每个玩家的总完成次数 + if playerObj.detailMode: #如果玩家启用了详细模式 + self.mapManager = MapManager(self.mapNum) + playerObj.sendMessage(u"§b[§e{}§b] §a本地图由 §f{} §a等人参与制作".format(self.map.display, self.mapManager.getCreator())) + self.bindPlayerInPreparingArea(playerObj) #为玩家绑定检查点任务 + self.playingCount = self.playerCount #更新正在游戏中的玩家数量 + self.enterPrepaing() #进入准备阶段 + def enterPrepaing(self): + self.isPreparing = True #进入准备阶段 + # 准备阶段设置 + self.map.replaceBlock(START_LINE_MATERIAL) # 启动线设置 + # 准备阶段流程 + def countdownTask1(): + self.countdownTaskId = None + if self.isEmpty(): # 检查房间内是否还有玩家 + self.closeRoom() #没有玩家则关闭房间 + return + self.countdownToAll(u'§f〓 5 〓', u'§7●●●●●', 1.0) + self.countdownTaskId = ps.scheduler.runTaskLater(countdownTask2, 20) + def countdownTask2(): + self.countdownTaskId = None + if self.isEmpty(): + self.closeRoom() + return + self.countdownToAll(u'§a〓 4 〓', u'§c●§7●●●●', 1.0) + self.countdownTaskId = ps.scheduler.runTaskLater(countdownTask3, 20) + def countdownTask3(): + self.countdownTaskId = None + if self.isEmpty(): + self.closeRoom() + return + self.countdownToAll(u'§b〓 3 〓', u'§c●●§7●●●', 1.0) + self.countdownTaskId = ps.scheduler.runTaskLater(countdownTask4, 20) + def countdownTask4(): + self.countdownTaskId = None + if self.isEmpty(): + self.closeRoom() + return + self.countdownToAll(u'§d〓 2 〓', u'§c●●●§7●●', 1.0) + self.countdownTaskId = ps.scheduler.runTaskLater(countdownTask5, 20) + def countdownTask5(): + self.countdownTaskId = None + if self.isEmpty(): + self.closeRoom() + return + self.countdownToAll(u'§e〓 1 〓', u'§c●●●●§7●', 1.0) + self.countdownTaskId = ps.scheduler.runTaskLater(countdownTask6, 20) + def countdownTask6(): + self.countdownTaskId = None + if self.isEmpty(): + self.closeRoom() + return + self.countdownToAll(u'§c§l〓 GO 〓', u'§a●●●●●', 2.0) + self.isPreparing = False #准备阶段结束 + for playerObj in self.playerList.values(): #获取玩家对象 + playerObj.stopReadyParticle() #结束准备粒子展示 + self.enterStarting() + # 准备阶段开始 + self.countdownTaskId = ps.scheduler.runTaskLater(countdownTask1, 1) + def enterStarting(self): # 进入开始阶段 包括Starting和Gaming + self.isStarting = True # 进入开始阶段 + # 开始阶段设置 + for key in list(self.activeTasks.keys()): #清理非系统任务 + if key != 'system': + self.clearTasks(key) + # 各玩家设置 + for playerObj in self.playerList.values(): #获取玩家对象 + playerObj.unsetInvisible() #取消隐身 + playerObj.spawnAndRideBoat() #生成船并绑定 + playerObj.setStartMoment() #设置开始时间戳 + playerObj.startActionBarUpdates(False) + playerObj.startParticle() #开始粒子展示 + # 开始阶段设置 + self.map.replaceBlock(Material.TRIPWIRE) # 启动线移除 + self.isGaming = True # 进入游戏阶段 + self.rankPlayerInGame() # 更新排名 + self.trackTask('system', ps.scheduler.scheduleRepeatingTask(lambda: self.updateGamingState(), 0, 1)) + def updateGamingState(self): # 游戏阶段每游戏刻更新状态 + # 调试启用,用于检测循环任务是否停止 + if self.isEmpty(): #如果房间为空则关闭房间 + self.closeRoom() + return + + # 循环检测玩家状态 + self.allFinished = True #默认所有玩家都完成 + for playerObj in self.playerList.values(): + if not playerObj.inVehicle(): #如果玩家不在载具内 + self.delPlayer(playerObj.name) #移出玩家 + if self.isEnding: #若进入结束阶段则跳过 + return + + # 检查点位进度 + if not playerObj.hasFinished: #玩家还没完成 + self.allFinished = False #存在未完成玩家 + mapNum = self.map.mapNum #获取地图编号 + pointArea = self.map.getPointArea(playerObj.point) #获取玩家当前检查点区域 + if playerObj.arrivePoint(pointArea): #玩家到达检查点 + self.rankPlayerInGame() #通过检查点时更新全局排名 + playerObj.updateTimer() #更新玩家时间戳 + if playerObj.point >= self.map.point: #完成一圈 + playerObj.addLap() #圈数增加 + playerObj.resetPoint() #重置检查点 + if playerObj.lap <= self.map.lap: #未完成所有圈的情况 + playerObj.addLapTitle() + playerObj.addLapSound() + else: + self.settleFinishedPlayer(playerObj) #对完成玩家的结算 + playerObj.setPointsTimer() #设置玩家检查点时间戳 + playerObj.updateMultiBestMapRecordPointTimer(mapNum, playerObj.lap, playerObj.point) #更新玩家多人最好成绩点位 + playerObj.updateDValueText() + playerObj.showMultiTimerInActionBar() #更新玩家动态栏显示 + if playerObj.detailMode: #详细模式 + if playerObj.lap <= self.map.lap: + playerObj.showTimerByMessage(self.map.display) #显示详细信息 + + if self.allFinished: #所有玩家完成则在3秒后关闭房间 + self.isStarting = False #结束启动状态 + self.enterEnding() #进入结束阶段 + def enterEnding(self): #游戏结束阶段 + self.isEnding = True + ps.scheduler.runTaskLater(lambda: self.closeRoom(), ENDING_INTERVAL) #阶段 + def closeRoom(self): #关闭房间操作 + if self.isClosed: #不重复关闭 + return + self.isClosed = True + + # 停止倒计时任务 + if self.countdownTaskId is not None: + ps.scheduler.stopTask(self.countdownTaskId) + self.countdownTaskId = None + + roomId = self.roomId + players = list(self.playerList.keys()) + + self.clearHologram() #清理全息显示 + roomsManager.setAvailableRoom(self.mapNum, self.roomNum, False) #房间可用 + for playerObj in self.playerList.values(): + self.delPlayer(playerObj.name) #执行玩家退出 + self.clearTasks('system')# 清理系统任务 + self.isRunning = False + self.isGaming = False + self.isEnding = False + + del multiGames[roomId] #删除房间 + + multiGames[roomId] = MultiGameRoom(roomId) #重新创建房间 + for playerName in players: #将玩家重新添加 + multiGames[roomId].addPlayer(playerName) + # 任务管理 -------------------------------- + def trackTask(self, owner, taskId): #仅循环任务需要任务管理 + if owner not in self.activeTasks: + self.activeTasks[owner] = [] + self.activeTasks[owner].append(taskId) + def clearTasks(self, owner): #停止指定循环任务 + if owner in self.activeTasks: + taskIds = list(self.activeTasks[owner]) + for taskId in taskIds: + if taskId is not None: + ps.scheduler.stopTask(taskId) + del self.activeTasks[owner] + # 辅助方法 -------------------------------- + def countdownToAll(self, title, subtitle, pitch): #为所有人播放倒计时反馈 + self.broadcastTitle(title, subtitle, 0, 20, 10) + self.broadcastSound(Sound.BLOCK_NOTE_BLOCK_PLING, 1.0, pitch) + def broadcastMessage(self, message): #游戏内广播信息 + for playerObj in self.playerList.values(): + playerObj.player.sendMessage(message) + def broadcastTitle(self, title=u"§f", subtitle=u"§f", fadeIn=0, stay=90, fadeOut=10): #游戏内广播标题 + for playerObj in self.playerList.values(): + playerObj.player.sendTitle(title, subtitle, fadeIn, stay, fadeOut) + def broadcastSound(self, sound=Sound.BLOCK_NOTE_BLOCK_PLING, volume=1.0, pitch=1.0): #游戏内广播声音 + for playerObj in self.playerList.values(): + playerObj.player.playSound(playerObj.player, sound, volume, pitch) + def createArmorStand(self, world, bottomLoc, x, y, z, customName): #生成盔甲架 + armorStand = world.spawn(bottomLoc, ArmorStand) #先在底部创造 + armorStand.setGravity(False) #设置无重力 + armorStand.setVisible(False) #设置不可见 + armorStand.setCollidable(False) #设置无碰撞箱 + armorStand.setCustomName(customName) #设置显示名 + armorStand.setCustomNameVisible(True) #设置显示名可见 + displayLoc = Location(world, x, y, z) #设置展示位置 + armorStand.teleport(displayLoc) #传送展示框 + self.mapDisplayArmorStands.append(armorStand) #将展示框添加到房间 +class SingleGameRoom: #单人游戏房间类 + def __init__(self, playerName, mapNum, roomNum): #玩家名:单人房间实例 + self.playerName = playerName + self.player = getServer().getPlayer(playerName) + self.playerObj = PlayerInGame(playerName) + + self.activeTasks = {} + self.countdownTaskId = None + + self.mapNum = mapNum + self.roomNum = roomNum + self.map = IceboatMap(self.mapNum, self.roomNum) + self.map.initialSpecialMap() #初始化特殊地图 + + self.isRunning = False + self.isPreparing = False + self.isStarting = False + self.isClosed = False + + self.mapManager = MapManager(self.mapNum) + # 房间管理 -------------------------------------------------- + def save(self): #更新状态 + singleGames[self.playerName] = self + # 玩家管理 -------------------------------------------------- + def playerLeave(self): #玩家离开 + # 清理玩家任务 + if hasattr(self, 'activeTasks') and self.playerName in self.activeTasks: + for taskId in self.activeTasks[self.playerName]: + if taskId is not None: + ps.scheduler.stopTask(taskId) + del self.activeTasks[self.playerName] + # 清理玩家自身状态并执行操作 + playerObj = self.playerObj + if self.isRunning: + playerObj.teleportToJoinLoc() #传送回进入房间前的位置 + if self.isStarting: + playerObj.clearBoat() #离开时清理绑定的船 + playerObj.stopActionBarUpdates() + playerObj.stopParticle() + if self.map and not playerObj.hasFinished: + lap = self.map.lap + point = self.map.point + vault = playerObj.leaveAddVault(lap, point) + playerObj.sendTitle(u"§f", u"§6离开成功 | 获得 §e{:.1f} §6DC币".format(vault), 5, 60, 10) + elif not playerObj.hasFinished: + playerObj.sendTitle(u"§f", u"§6离开成功", 5, 60, 10) + self.save() + # 流程管理 -------------------------------------------------- + def enterRunning(self): #游戏初始化阶段 + self.isRunning = True + if self.player.isInsideVehicle(): #如果玩家在船内则删除船 + self.player.getVehicle().remove() + self.playerObj.updatePlayerData() #更新玩家数据 + self.playerObj.updateJoinLoc() #更新玩家进入房间前的位置 + joinPos = self.map.getJoinPosition() #获取玩家进入房间的位置 + self.playerObj.teleport(joinPos) #传送玩家到房间内 + + self.playerObj.updateLastMap(self.map.mapNum) #更新玩家上一次游玩的地图 + if self.playerObj.musicMode: #如果玩家启用了音乐模式 + self.playerObj.stopRecordSounds() #停止可能在播放的音乐 + self.playerObj.playIceboatMapSound(self.map.mapNum) + + if self.playerObj.detailMode: #如果玩家启用了详细模式 + self.playerObj.sendMessage(u"§b[§e{}§b] §a本地图由 §f{} §a等人参与制作".format(self.map.display, self.mapManager.getCreator())) + self.bindPlayerInPreparingArea() #为玩家绑定检查点任务 + + self.enterPreparing() #进入准备阶段 + def enterPreparing(self): + self.isPreparing = True #进入准备阶段 + # 准备阶段设置 + self.map.replaceBlock(START_LINE_MATERIAL) # 启动线设置 + # 准备阶段流程 + def countdownTask1(): + self.countdownTaskId = None + if self.playerName in singleGames: + self.countdownToPlayer(u'§f〓 5 〓', u'§7●●●●●', 1.0) + self.countdownTaskId = ps.scheduler.runTaskLater(countdownTask2, 20) + def countdownTask2(): + self.countdownTaskId = None + if self.playerName in singleGames: + self.countdownToPlayer(u'§a〓 4 〓', u'§c●§7●●●●',1.0) + self.countdownTaskId = ps.scheduler.runTaskLater(countdownTask3, 20) + def countdownTask3(): + self.countdownTaskId = None + if self.playerName in singleGames: + self.countdownToPlayer(u'§b〓 3 〓', u'§c●●§7●●●', 1.0) + self.countdownTaskId = ps.scheduler.runTaskLater(countdownTask4, 20) + def countdownTask4(): + self.countdownTaskId = None + if self.playerName in singleGames: + self.countdownToPlayer(u'§d〓 2 〓', u'§c●●●§7●●', 1.0) + self.countdownTaskId = ps.scheduler.runTaskLater(countdownTask5, 20) + def countdownTask5(): + self.countdownTaskId = None + if self.playerName in singleGames: + self.countdownToPlayer(u'§e〓 1 〓', u'§c●●●●§7●', 1.0) + self.countdownTaskId = ps.scheduler.runTaskLater(countdownTask6, 20) + def countdownTask6(): + self.countdownTaskId = None + if self.playerName in singleGames: + self.countdownToPlayer(u'§c§lGO', u'§a●●●●●', 2.0) + self.isPreparing = False + self.enterStarting() + # 准备阶段开始 + self.countdownTaskId = ps.scheduler.runTaskLater(countdownTask1, 1) + def enterStarting(self): #开始阶段 + self.isStarting = True + # 开始阶段设置 + self.clearTasks(self.playerObj.name) #清理玩家任务:循环检测区域 + self.playerObj.spawnAndRideBoat() #生成船并绑定 + self.playerObj.setStartMoment() #设置开始时间戳 + self.playerObj.startActionBarUpdates(True) + self.playerObj.startParticle() #开始粒子展示 + self.map.replaceBlock(Material.TRIPWIRE) #启动线移除 + self.trackTask('system', ps.scheduler.scheduleRepeatingTask(lambda: self.updateGamingState(), 0, 1)) + def updateGamingState(self): + + if not self.playerObj.isOnline(): #玩家不在线则关闭房间 + self.closeRoom() + return + if not self.playerObj.inVehicle(): #玩家不在载具内则关闭房间 + self.closeRoom() + return + mapNum = self.map.mapNum + pointArea = self.map.getPointArea(self.playerObj.point) + if self.playerObj.arrivePoint(pointArea): + self.playerObj.updateTimer() + if self.playerObj.point >= self.map.point: + self.playerObj.addLap() + self.playerObj.resetPoint() + if self.playerObj.lap <= self.map.lap: + self.playerObj.addLapTitle() #没有到最后一圈则展现标题 + self.playerObj.addLapSound() #没有到最后一圈则播放音效 + else: + self.enterEnding() + self.playerObj.setPointsTimer() + self.playerObj.updateSingleBestMapRecordPointTimer(mapNum, self.playerObj.lap, self.playerObj.point) #更新玩家单人最好成绩点位 + self.playerObj.updateDValueText() #更新D值文本 + self.playerObj.showSingleTimerInActionBar() + if self.playerObj.detailMode: #详细模式下显示详细信息 + if self.playerObj.lap <= self.map.lap: #仅在未完成前播报 + self.playerObj.showTimerByMessage(self.map.display) + def enterEnding(self): + finishTime = self.playerObj.timer + self.playerObj.finishTime = finishTime + message = u"§b[§e{}§b] {}[{}]§f{} §a总用时 §e{:.2f} §a秒".format( + self.map.display, self.playerObj.playerData.getLevelColor(), self.playerObj.playerData.getTitleDisplay(), self.playerObj.name, finishTime) + if self.playerObj.broadcastMode: #如果开启了成绩广播模式 + broadcast(message) + else: + self.playerObj.sendMessage(message) + self.playerObj.hasFinished = True # 标记玩家已完成 + self.playerObj.playSound(Sound.ENTITY_FIREWORK_ROCKET_LAUNCH, 1.0, 1.0) + self.playerObj.playSound(Sound.ENTITY_FIREWORK_ROCKET_TWINKLE, 1.0, 1.0) + self.playerObj.stopActionBarUpdates() + self.playerObj.stopParticle() + vault = self.playerObj.finishAddVault() + record = self.playerObj.checkSingleRecord(self.map.mapNum) + if record: #纪录更新 + record = float(record) + self.playerObj.playSound(Sound.ENTITY_PLAYER_LEVELUP, 1.0, 1.0) + self.playerObj.sendMessage( + u"§b[§e{}§b] {}[{}]§f{} §a刷新了个人纪录!§7(旧纪录:{:.2f})".format( + self.map.display, self.playerObj.playerData.getLevelColor(), self.playerObj.playerData.getTitleDisplay(), self.playerObj.name, record + ) + ) + if self.playerObj.detailMode: #如果玩家启用了详细模式 + self.playerObj.sendMessage(u"§b[§e{}§b] §a最佳纪录 §e{:.2f} §a秒 | 第 §e{} §a次完成该地图 | 获得 §e{:.1f} §aDC币".format( + self.map.display, + self.playerObj.playerData.getSingleBestMapRecord(self.mapNum), + self.playerObj.playerData.getMapTimes(self.mapNum), + vault)) + if seasonManager.inSeasonMaps(self.mapNum): #如果是赛季地图 + self.playerObj.sendMessage(u"§b[§e{}§b] §a该地图当季分数 §e{:.2f} §a| 当季总分 §e{:.2f}".format( + self.map.display, + self.playerObj.playerData.getSeasonMapScore(self.mapNum), + self.playerObj.playerData.getSeasonScore())) + else: + self.playerObj.sendMessage(u"§b[§e{}§b] §a该地图不是当季地图".format(self.map.display)) + self.closeRoom() + def closeRoom(self): #游戏结束 + if self.isClosed: #不重复关闭 + return + self.isClosed = True + # 停止倒计时任务 + if self.countdownTaskId is not None: + ps.scheduler.stopTask(self.countdownTaskId) + self.countdownTaskId = None + + roomsManager.setAvailableRoom(self.mapNum, self.roomNum, False) + spectators = self.playerObj.getSpectate() + self.playerLeave() + self.clearTasks('system') # 清理系统任务 + self.isStarting = False + self.isRunning = False + del singleGames[self.playerName] + + for spectatorName in spectators: + spectatorObj = playersInSpectate[spectatorName] + if not spectatorObj.changeTarget(): + spectatorObj.leave() + # 任务管理 -------------------------------- + def trackTask(self, owner, taskId): + if not hasattr(self, 'activeTasks'): + self.activeTasks = {} + if owner not in self.activeTasks: + self.activeTasks[owner] = [] + self.activeTasks[owner].append(taskId) + def clearTasks(self, owner): + if hasattr(self, 'activeTasks') and owner in self.activeTasks: + taskIds = list(self.activeTasks[owner]) + for taskId in taskIds: + if taskId is not None: + ps.scheduler.stopTask(taskId) + del self.activeTasks[owner] + # 辅助方法 -------------------------------- + def countdownToPlayer(self, title, subtitle, pitch): + player = self.playerObj.player + player.sendTitle(title, subtitle, 0, 20, 10) + player.playSound(player, Sound.BLOCK_NOTE_BLOCK_PLING, 1.0, pitch) + def bindPlayerInPreparingArea(self): #准备阶段循环检测 + def checkTask(): + + if not self.playerObj.inArea(self.map.getPreparingArea()): + actionBar(self.playerObj.player, u'§c请勿离开起点区域') + self.playerObj.teleport(self.map.getJoinPosition()) + + taskId = ps.scheduler.scheduleRepeatingTask(checkTask, 0, 20) + self.trackTask(self.playerObj.name, taskId) +competitionGame = CompetitionGameRoom() # 通用函数 ------------------------------------------------------------------- def actionBar(player, text): #为玩家设置动态栏 @@ -2458,6 +3618,24 @@ def getScoreboardObjective(scoreboardName): createScoreboardObjective(scoreboardName) objective = scoreboard.getObjective(scoreboardName) return objective +def removeScoreboardObjective(scoreboardName): + scoreboard = getServer().getScoreboardManager().getMainScoreboard() + if scoreboard.getObjective(scoreboardName): #初始化计分板 + scoreboard.getObjective(scoreboardName).unregister() +def getScoreboardTeam(teamName): + scoreboard = getServer().getScoreboardManager().getMainScoreboard() + if not scoreboard.getTeam(teamName): #初始化计分板 + scoreboard.registerNewTeam(teamName) + team = scoreboard.getTeam(teamName) + team.setColor(ChatColor.AQUA) + team.setOption(Team.Option.COLLISION_RULE, Team.OptionStatus.NEVER) + team.setCanSeeFriendlyInvisibles(False) + return team +def removeScoreboardTeam(teamName): + scoreboard = getServer().getScoreboardManager().getMainScoreboard() + team = scoreboard.getTeam(teamName) + if team: #初始化计分板 + team.unregister() def broadcast(message): #世界广播内容 for player in worldManager.getWorld().getPlayers(): player.sendMessage(message) @@ -2488,6 +3666,26 @@ def iceboatCommand(sender, label, args): # 房间命令 sender.sendTitle(u"§f", u"§c房间未被创建,请先进入房间", 5, 60, 10) sender.playSound(sender, Sound.ENTITY_VILLAGER_NO, 1.0, 1.0) return False + elif command == u'cstart': + if isinstance(sender, Player): + playerName = sender.getName() + player = sender + if not competitionGame.isPlayerInRoom(playerName): + player.sendTitle(u"§f", u"§c你不在该房间内,无法启动房间", 5, 60, 10) + player.playSound(player, Sound.ENTITY_VILLAGER_NO, 1.0, 1.0) + return False + if competitionGame.isRunning: + player.sendTitle(u"§f", u"§c比赛房间已启动", 5, 60, 10) + player.playSound(player, Sound.ENTITY_VILLAGER_NO, 1.0, 1.0) + return False + if competitionGame.firstPlayerName is not None: + if playerName != competitionGame.firstPlayerName: + player.sendTitle(u"§f", u"§c仅上局第一可开始游戏", 5, 60, 10) + player.playSound(player, Sound.ENTITY_VILLAGER_NO, 1.0, 1.0) + return False + competitionGame.enterReady() + return True + elif command == u'seasonreset': if isinstance(sender, Player): if sender.isOp(): @@ -2498,6 +3696,27 @@ def iceboatCommand(sender, label, args): # 房间命令 ps.scheduler.runSyncCallbackTask(lambda sm=seasonManager: sm.resetSeasonRecords(), resetOver()) if len(args) < 2: return False + if command == 'compete': + targetPlayerName = args[1] + targetPlayer = Bukkit.getPlayer(targetPlayerName) + if targetPlayer is None: + return False + playerManager = PlayerManager(targetPlayer) + if playerManager.inAnyRoom(): #判断玩家是否在房间内 + targetPlayer.sendTitle(u"§f", u"§c你已经在某房间内", 5, 60, 10) + targetPlayer.playSound(targetPlayer, Sound.ENTITY_VILLAGER_NO, 1.0, 1.0) + return False + result = competitionGame.addPlayer(targetPlayerName) + if isinstance(result, tuple) and len(result) == 2: + success, message = result + if success: + targetPlayer.sendTitle(u"§f", u"§a{}".format(message), 5, 60, 10) + targetPlayer.playSound(targetPlayer, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1.0, 1.0) + else: + targetPlayer.sendTitle(u"§f", u"§c{}".format(message), 5, 60, 10) + targetPlayer.playSound(targetPlayer, Sound.ENTITY_VILLAGER_NO, 1.0, 1.0) + else: + targetPlayer.sendMessage(u"§c发生未知错误,请稍后重试。") if command == 'multi': # 命令格式 /ib multi if len(args) < 3: return False @@ -2508,7 +3727,7 @@ def iceboatCommand(sender, label, args): # 房间命令 return False playerManager = PlayerManager(targetPlayer) if playerManager.inAnyRoom(): #判断玩家是否在房间内 - targetPlayer.sendTitle(u"§f", u"§c你已经在其它房间内", 5, 60, 10) + targetPlayer.sendTitle(u"§f", u"§c你已经在某房间内", 5, 60, 10) targetPlayer.playSound(targetPlayer, Sound.ENTITY_VILLAGER_NO, 1.0, 1.0) return False if roomId not in multiGames: # 若该ID的房间未开启 则新增一个实例 @@ -2553,6 +3772,24 @@ def iceboatMenuCommand(sender, label, args): # 菜单命令 MenuSingle(player).openWithRender() # 打开单人地图选择页面 player.playSound(player, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1.0, 1.0) return True + elif args[0].lower() == "competition": + playerName = player.getName() + if not competitionGame.isPlayerInRoom(playerName): + player.sendTitle(u"§f", u"§c你不在比赛中", 5, 60, 10) + player.playSound(player, Sound.ENTITY_VILLAGER_NO, 1.0, 1.0) + return False + if competitionGame.isRunning: + player.sendTitle(u"§f", u"§c比赛房间启动中", 5, 60, 10) + player.playSound(player, Sound.ENTITY_VILLAGER_NO, 1.0, 1.0) + return False + if competitionGame.firstPlayerName is not None: + if playerName != competitionGame.firstPlayerName: + player.sendTitle(u"§f", u"§c仅上局第一可修改设置", 5, 60, 10) + player.playSound(player, Sound.ENTITY_VILLAGER_NO, 1.0, 1.0) + return False + MenuCompetition(player).openWithRender() # 打开比赛地图选择页面 + player.playSound(player, Sound.ITEM_BOOK_PAGE_TURN, 1.0, 1.0) + return True elif args[0].lower() == "multi" and len(args) > 1: roomId = args[1] if roomId not in multiGames: @@ -2564,7 +3801,7 @@ def iceboatMenuCommand(sender, label, args): # 菜单命令 if not room.isPlayerInRoom(playerName): player.sendTitle(u"§f", u"§c你不在该房间,请先进入房间", 5, 60, 10) player.playSound(player, Sound.ENTITY_VILLAGER_NO, 1.0, 1.0) - return + return False MenuMulti(player, roomId).openWithRender() # 打开多人地图选择页面 player.playSound(player, Sound.ITEM_BOOK_PAGE_TURN, 1.0, 1.0) return True @@ -2865,7 +4102,9 @@ class MenuMulti(GUIController): return multiGames[str(self.roomId)].setIceboatMap(mapNum, roomNum) multiGames[str(self.roomId)].createHologram() #更新全息显示 - player.playSound(player, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1.0, 1.0) + mapManager = MapManager(mapNum) + multiGames[str(self.roomId)].broadcastTitle(u"§f", u"§e{} §a将地图设置为 §e{}".format(player.getName(), mapManager.getDisplay())) + multiGames[str(self.roomId)].broadcastSound(Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1.0, 1.0) else: player.playSound(player, Sound.ENTITY_VILLAGER_NO, 1.0, 1.0) player.sendMessage(u"§c该地图暂无空房,请稍后再试") @@ -2904,6 +4143,7 @@ class MenuCollection(GUIController): owned = False #默认未拥有 available = False #默认不可用 notForSale = False #默认可卖 + goToMap = 0 #默认不跳转到地图 lore = [] if itemNumber in ownedItems: @@ -2935,20 +4175,24 @@ class MenuCollection(GUIController): available = True color = u"§f" lore.append(u"§e驾照等级要求: {}{}".format(color, level)) - elif conditions[0] == u"totalTimes": - totalTimes = conditions[1] - playerTotalMapTimes = playerData.getTotalMapTimes() - if playerTotalMapTimes >= totalTimes: - available = True - color = u"§f" - lore.append(u"§e总完成次数要求: {}{}".format(color, totalTimes)) elif conditions[0] == u"record": - lore.append(u"§e单人纪录要求:") + lore.append(u"§e单人/多人纪录要求:") recordDict = conditions[1] satisfied = True for mapNum, record in recordDict.items(): mapDisplay = MapManager(mapNum).getDisplay() - playerRecord = playerData.getSingleBestMapRecord(mapNum) + playerRecord = 0 + playerSingleRecord = playerData.getSingleBestMapRecord(mapNum) + if playerSingleRecord > 0: + playerRecord = playerSingleRecord + playerMultiRecord = playerData.getMultiBestMapRecord(mapNum) + if playerMultiRecord > 0: + if playerRecord > 0: + if playerMultiRecord < playerRecord: + playerRecord = playerMultiRecord + else: + playerRecord = playerMultiRecord + color = u"§c" if playerRecord > 0: if playerRecord <= record: @@ -2960,6 +4204,8 @@ class MenuCollection(GUIController): satisfied = False playerRecord = u"暂无成绩" lore.append(u"§7- {}{} {} <= {:.2f}".format(color, mapDisplay, playerRecord, record)) + if not satisfied and goToMap == 0: + goToMap = int(mapNum) #设置第一个不满足条件的地图为跳转地图 if satisfied: available = True elif conditions[0] == u"times": @@ -2975,6 +4221,8 @@ class MenuCollection(GUIController): else: satisfied = False lore.append(u"§7- {}{} {} >= {}".format(color, mapDisplay, int(playerTimes), int(times))) + if not satisfied and goToMap == 0: + goToMap = int(mapNum) #设置第一个不满足条件的地图为跳转地图 if satisfied: available = True @@ -2982,15 +4230,21 @@ class MenuCollection(GUIController): if owned: lore.append(u"§6>> §a点击使用 §6<<") + goToMap = 0 #拥有则不跳转地图 elif available: lore.append(u"§6>> §e点击获取 §6<<") + goToMap = 0 #可获得则不跳转地图 elif notForSale: lore.append(u"§6>> §c非卖品 §6<<") + goToMap = 0 #非卖品则不跳转地图 else: - lore.append(u"§6<< §c未达要求 §6>>") + if conditions[0] in [u"times", u"record"]: + lore.append(u"§6<< §c未达要求,点击挑战 §6>>") + else: + lore.append(u"§6<< §c未达要求 §6>>") self.set(index, material, u"§b§l【§e§l{}§b§l】§f".format(display), *lore, - data="{}:{}:{}:{}".format(owned, available, self.itemType, itemNumber)) + data="{}:{}:{}:{}:{}".format(owned, available, self.itemType, itemNumber, goToMap)) self.spawnSeparators(45, 53) # 填充最后一行默认黑色染色玻璃板 if self.page > 1: @@ -3054,7 +4308,7 @@ class MenuCollection(GUIController): if item is not None: guiValue = getGUIValue(item) if guiValue: - owned, available, itemType, itemNumber = guiValue.split(':') + owned, available, itemType, itemNumber, goToMap = guiValue.split(':') playerData = PlayerDataManager(playerName) owned = int(owned) available = int(available) @@ -3086,7 +4340,11 @@ class MenuCollection(GUIController): player.sendMessage(u"§a获取成功!") player.playSound(player, Sound.ENTITY_VILLAGER_YES, 1.0, 1.0) else: #如果该收藏品不可用 - player.playSound(player, Sound.ENTITY_VILLAGER_NO, 1.0, 1.0) + if int(goToMap) != 0: + playerManager = PlayerManager(player) + playerManager.joinSingleRoom(goToMap) + else: + player.playSound(player, Sound.ENTITY_VILLAGER_NO, 1.0, 1.0) return if itemType == "boats": @@ -3218,7 +4476,6 @@ class MenuLevel(GUIController): for mapNum, record in recordDict.items(): mapManager = MapManager(mapNum) mapDisplay = mapManager.getDisplay() - goToMap = int(mapNum) #最后一张地图作为跳转地图 playerRecord = playerData.getSingleBestMapRecord(mapNum) color = u"§c" if playerRecord > 0: @@ -3231,10 +4488,11 @@ class MenuLevel(GUIController): satisfied = False playerRecord = u"暂无成绩" lore.append(u"§7- {}{} {} <= {:.2f}".format(color, mapDisplay, playerRecord, record)) + if not satisfied and goToMap == 0: + goToMap = int(mapNum) #设置第一个不满足条件的地图为跳转地图 if satisfied and levelEnough and not finished: available = True #满足条件,标记可用 - - + lore.append(u"§f") if not levelEnough: lore.append(u"§6<< §c未达等级 §6>>") @@ -3641,6 +4899,253 @@ class MenuRankingMapSelect(GUIController):# 单人房间菜单 if mapNumber is not None: MenuRanking(player, mapNum=int(mapNumber), rankingType=u"single").openWithRender() player.playSound(player, Sound.ITEM_BOOK_PAGE_TURN, 1.0, 1.0) +class MenuSpectate(GUIController): # 旁观菜单 + def __init__(self, player, page=1, sortMode=u"default"): + super(MenuSpectate, self).__init__(player) + self.page = page + self.sortMode = sortMode + self.setInfo("iceboat.spectate", u"§0旁观玩家选择 - 第 {} 页".format(page)) + self.setGUIManager(guiManager) + def render(self): + player = self.getPlayer() + playerName = player.getName() + itemsPerPage = 45 # 每页显示 45 个物品,最后一行用于控制 + + singlePlayers = [] + for playerName in singleGames: + if singleGames[playerName].isPreparing: + continue + singlePlayers.append(playerName) + + multiPlayers = [] + for roomId, room in multiGames.items(): + if room.isRunning: + if room.isPreparing: + continue + for playerName in room.playerList: + multiPlayers.append(playerName) + if self.sortMode == "single": + players = singlePlayers + elif self.sortMode == "multi": + players = multiPlayers + else: + players = list(singlePlayers + multiPlayers) + players.sort(key=lambda x: str(x)) + + self.totalPages = (len(players) + itemsPerPage - 1) // itemsPerPage + startIndex = (self.page - 1) * itemsPerPage + endIndex = startIndex + itemsPerPage + currentPagePlayers = players[startIndex:endIndex] + + for index, name in enumerate(currentPagePlayers): + lores = [] + if name in singlePlayers: + mapDisplay = singleGames[name].map.display + lores.append(u"§e单人模式: §f{}".format(mapDisplay)) + elif name in multiPlayers: + for roomId, room in multiGames.items(): + if name in room.playerList: + mapDisplay = room.map.display + lores.append(u"§e多人模式[{}]: §f{}".format(roomId, mapDisplay)) + break + try: + material = playerHeadsAPI.getPlayerHead(name) + except Exception: + material = Material.PLAYER_HEAD + self.set(index, material, u"§b§l【§e§l{}§b§l】§f".format(name), *lores, data=str(name)) + self.spawnSeparators(45, 53) # 填充最后一行默认黑色染色玻璃板 + if self.page > 1: + self.set(45, Material.WHITE_STAINED_GLASS_PANE, u"§a上一页") # 上一页按钮 + if self.page < self.totalPages: + self.set(53, Material.WHITE_STAINED_GLASS_PANE, u"§a下一页") # 下一页按钮 + self.set(48, Material.LIME_STAINED_GLASS_PANE, u"§a查看单人游戏中玩家") + self.set(49, Material.ORANGE_STAINED_GLASS_PANE, u"§a查看多人游戏中玩家") + self.set(50, Material.YELLOW_STAINED_GLASS_PANE, u"§e查看所有游戏中玩家") + playerPage[playerName] = { + "page": self.page, + "sortMode": self.sortMode + } + def onClick(self, e): + e.setCancelled(True) + clickInt = e.getSlot() + player = self.getPlayer() + playerName = player.getName() + playerPageInfo = playerPage.get(playerName, {"page": 1, "sortMode": u"default"}) + currentPage = playerPageInfo["page"] if hasattr(playerPageInfo, "page") else 1 + sortMode = playerPageInfo["sortMode"] if hasattr(playerPageInfo, "sortMode") else u"default" + if clickInt == 45 and currentPage > 1: + MenuSpectate(player, page=currentPage - 1, sortMode=sortMode).openWithRender() + player.playSound(player, Sound.ITEM_BOOK_PAGE_TURN, 1.0, 1.0) + elif clickInt == 53 and currentPage < self.totalPages: + MenuSpectate(player, page=currentPage + 1, sortMode=sortMode).openWithRender() + player.playSound(player, Sound.ITEM_BOOK_PAGE_TURN, 1.0, 1.0) + elif clickInt == 48: + MenuSpectate(player, sortMode=u"single").openWithRender() + player.playSound(player, Sound.ITEM_BOOK_PAGE_TURN, 1.0, 1.0) + elif clickInt == 49: + MenuSpectate(player, sortMode=u"multi").openWithRender() + player.playSound(player, Sound.ITEM_BOOK_PAGE_TURN, 1.0, 1.0) + elif clickInt == 50: + MenuSpectate(player, sortMode=u"default").openWithRender() + player.playSound(player, Sound.ITEM_BOOK_PAGE_TURN, 1.0, 1.0) + else: + item = e.getCurrentItem() + name = getGUIValue(item) + if name is not None: + target = getServer().getPlayer(name) + playersInSpectate[playerName] = PlayerInSpectate(player) + result = playersInSpectate[playerName].attachBoat(target) + if result is True: + player.playSound(player, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1.0, 1.0) + player.closeInventory() + else: + player.playSound(player, Sound.BLOCK_NOTE_BLOCK_BASS, 1.0, 1.0) + MenuSpectate(player, page=currentPage, sortMode=sortMode).openWithRender() +class MenuCompetition(GUIController): + def __init__(self, player, page=1, setTargetScore=False): + super(MenuCompetition, self).__init__(player) + self.page = page + self.setTargetScore = setTargetScore + if self.setTargetScore: + self.setInfo("iceboat.competition", u"§0比赛抢分设置 - 第 {} 页".format(page)) + else: + self.setInfo("iceboat.competition", u"§0比赛房间地图选择 - 第 {} 页".format(page)) + self.setGUIManager(guiManager) + def render(self): + player = self.getPlayer() + playerName = player.getName() + + if self.setTargetScore: + mapNumbers = [10,20,30,40,50,60,70,80,90,100,110,120,130,140,150,160,170,180,190,200] + else: + if competitionGame.mapsList: + mapNumbers = list(competitionGame.mapsList) + mapNumbers.sort(key=lambda num: int(num)) + else: + mapNumbers = [] + + itemsPerPage = 18 + self.totalPages = (len(mapNumbers) + itemsPerPage - 1) // itemsPerPage + + startIndex = (self.page - 1) * itemsPerPage + endIndex = startIndex + itemsPerPage + currentPageItems = mapNumbers[startIndex:endIndex] + + if self.setTargetScore: + for index, targetScore in enumerate(currentPageItems): + material = Material.GOLD_INGOT + amount = int(targetScore/10) + displayName = u"§6>> §e{}分 §6<<".format(targetScore) + lores = [ + u"§7点击设置抢分目标" + ] + self.set(index, material, displayName, *lores, data=str(targetScore), amount=amount) + else: + playerDataManager = PlayerDataManager(playerName) + for index, mapNumber in enumerate(currentPageItems): + mapFilePath = u"iceboat/maps/{}.yml".format(mapNumber) + mapConfig = ps.config.loadConfig(mapFilePath) + displayName = mapConfig.get("display", u"§b§l【§e§l地图 {}§b§l】§f".format(mapNumber)) + material = mapConfig.get("material", "PAPER") + lap = mapConfig.get("lap", "未知") + + mapManager = MapManager(mapNumber) + difficulty = mapManager.getDifficulty() + difficultySuffix = mapManager.getDifficultySuffix() + + available = roomsManager.getAvailableRoomCount(mapNumber) + total = roomsManager.getTotalRoomCount(mapNumber) + seasonMapBestRecord = playerDataManager.getSeasonBestMapRecord(mapNumber) + + try: + material = getattr(Material, material) + except AttributeError: + material = Material.PAPER + + lores = [ + u"§e序号: §f{}".format(mapNumber), + u"§e难度: §f{} {}".format(difficulty, difficultySuffix), + u"§e圈数: §f{}".format(lap), + "", + u"§e剩余空房: §f{}/{}".format(available, total), + u"§e当季纪录: §f{:.2f}".format(seasonMapBestRecord) if seasonMapBestRecord else u"§e当季纪录: §f暂无", + u"§e当季标准: §f{:.2f}".format(seasonManager.getSeasonStandard(mapNumber)), + u"§e当季分数: §f{:.2f}".format(playerDataManager.getSeasonMapScore(mapNumber)) + ] + self.set(index, material, u"§b§l【§e§l{}§b§l】§f".format(displayName), + *lores, + data=str(mapNumber) + ) + + self.spawnSeparators(18, 26) + if self.page > 1: + self.set(18, Material.WHITE_STAINED_GLASS_PANE, u"§a上一页") + buttonText = u"§e设置抢分目标" if self.setTargetScore else u"§e设置比赛地图" + self.set(22, Material.YELLOW_STAINED_GLASS_PANE, buttonText) + if self.page < self.totalPages: + self.set(26, Material.WHITE_STAINED_GLASS_PANE, u"§a下一页") + playerPage[playerName] = { + "page": self.page, + "setTargetScore": self.setTargetScore + } + def onClick(self, e): + e.setCancelled(True) + clickInt = e.getSlot() + player = self.getPlayer() + playerName = player.getName() + if not competitionGame.isPlayerInRoom(playerName): + player.closeInventory() + return + if clickInt == 18 and self.page > 1: + MenuCompetition(player, page=self.page - 1, setTargetScore=self.setTargetScore).openWithRender() + player.playSound(player, Sound.ITEM_BOOK_PAGE_TURN, 1.0, 1.0) + elif clickInt == 22: + MenuCompetition(player, page=self.page, setTargetScore=not self.setTargetScore).openWithRender() + player.playSound(player, Sound.ITEM_BOOK_PAGE_TURN, 1.0, 1.0) + elif clickInt == 26 and self.page < self.totalPages: + MenuCompetition(player, page=self.page + 1, setTargetScore=self.setTargetScore).openWithRender() + player.playSound(player, Sound.ITEM_BOOK_PAGE_TURN, 1.0, 1.0) + elif clickInt < 45: + item = e.getCurrentItem() + if self.setTargetScore: + targetScore = getGUIValue(item) + if targetScore is not None: + result = competitionGame.setTargetScore(targetScore) + if result: + competitionGame.broadcastTitle(u"§f", u"§e{} §a将比赛目标设置为 §e{}".format(player.getName(), targetScore)) + competitionGame.broadcastSound(Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1.0, 1.0) + competitionGame.createHologram() #更新全息显示 + player.closeInventory() + else: + player.playSound(player, Sound.ENTITY_VILLAGER_NO, 1.0, 1.0) + player.sendTitle(u"§f", u"§c已有达到该分数的玩家,设置失败", 5, 60, 10) + player.closeInventory() + else: + mapNumber = getGUIValue(item) + if mapNumber is not None: + if competitionGame.round == 1: + player.sendTitle(u"§f", u"§c首局地图不可更改", 5, 60, 10) + player.playSound(player, Sound.ENTITY_VILLAGER_NO, 1.0, 1.0) + return False + available = roomsManager.getAvailableRoomCount(mapNumber) + if available > 0: + mapNum = str(mapNumber) + roomNum = roomsManager.getAvailableRoom(mapNum) + if roomNum is None: + player.sendTitle(u"§f", u"§c暂无空房", 5, 60, 10) + player.playSound(player, Sound.ENTITY_VILLAGER_NO, 1.0, 1.0) + return + + competitionGame.setIceboatMap(mapNum, roomNum) + competitionGame.createHologram() #更新全息显示 + mapManager = MapManager(mapNum) + competitionGame.broadcastTitle(u"§f", u"§e{} §a将地图设置为 §e{}".format(player.getName(), mapManager.getDisplay())) + competitionGame.broadcastSound(Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1.0, 1.0) + else: + player.playSound(player, Sound.ENTITY_VILLAGER_NO, 1.0, 1.0) + player.sendMessage(u"§c该地图暂无空房,请稍后再试") + MenuCompetition(player, self.page, self.setTargetScore).openWithRender() + def onInventoryClick(e): # 菜单点击 player = e.getWhoClicked() worldName = player.getWorld().getName() @@ -3668,11 +5173,15 @@ def onInventoryClick(e): # 菜单点击 if itemType == Material.MAGMA_CREAM: #无论何时都可以尝试退出 iceboatCommand(player, "ib", ["leave", playerManager.playerName]) return - elif itemType == Material.JUKEBOX: #无论何时都可以关闭音乐 + elif itemType == Material.MUSIC_DISC_RELIC: #无论何时都可以关闭音乐 player.stopSound(SoundCategory.RECORDS) player.sendMessage(u"§a当前音乐已关闭") player.playSound(player, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1.0, 1.0) return + elif itemType == Material.ENDER_EYE and (playerManager.inSpectateRoom() or playerManager.inLobby()): #旁观菜单 + MenuSpectate(player).openWithRender() + player.playSound(player, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1.0, 1.0) + return elif playerManager.inAnyRoom() and not playerManager.inLobby(): #房间内禁止其它操作 player.sendMessage(u"§c游戏内禁止该操作") player.playSound(player, Sound.ENTITY_VILLAGER_NO, 1.0, 1.0) @@ -3708,6 +5217,7 @@ def onInventoryClick(e): # 菜单点击 playerData = PlayerDataManager(playerManager.playerName) #玩家设置修改 if itemType == Material.FIREWORK_STAR: #粒子模式 result = playerData.toggleModeBoolean("particleMode") + playerManager.updateInventoryMode(mode=u"particle") if result: player.sendMessage(u"§a自定义粒子模式已开启") player.playSound(player, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1.0, 1.0) @@ -3716,6 +5226,7 @@ def onInventoryClick(e): # 菜单点击 player.playSound(player, Sound.BLOCK_NOTE_BLOCK_BASS, 1.0, 1.0) elif itemType == Material.OAK_HANGING_SIGN: #详细播报模式 result = playerData.toggleModeBoolean("detailMode") + playerManager.updateInventoryMode(mode=u"detail") if result: player.sendMessage(u"§a详细播报模式已开启") player.playSound(player, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1.0, 1.0) @@ -3724,6 +5235,7 @@ def onInventoryClick(e): # 菜单点击 player.playSound(player, Sound.BLOCK_NOTE_BLOCK_BASS, 1.0, 1.0) elif itemType == Material.BEACON: #广播模式 result = playerData.toggleModeBoolean("broadcastMode") + playerManager.updateInventoryMode(mode=u"broadcast") if result: player.sendMessage(u"§a成绩广播模式已开启") player.playSound(player, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1.0, 1.0) @@ -3732,6 +5244,7 @@ def onInventoryClick(e): # 菜单点击 player.playSound(player, Sound.BLOCK_NOTE_BLOCK_BASS, 1.0, 1.0) elif itemType == Material.NOTE_BLOCK: #音乐模式 result = playerData.toggleModeBoolean("musicMode") + playerManager.updateInventoryMode(mode=u"music") if result: player.sendMessage(u"§a音乐模式已开启") player.playSound(player, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1.0, 1.0) @@ -3808,15 +5321,23 @@ def onPlayerInteract(event): # 玩家交互处理:禁止修改告示牌、物 #处理物品栏右键 playerManager = PlayerManager(player) if itemType == Material.SLIME_BALL: #打开单人模式菜单 + if playerManager.actionCooldown(): + return iceboatMenuCommand(playerManager.player, "", ["single"]) elif itemType == Material.NETHER_STAR: #快速进入上次游玩地图的单人模式 - if playerManager.inAnyRoom() and not playerManager.inLobby(): #房间内禁止其它操作 + if (playerManager.inAnyRoom()) or (not playerManager.inLobby()): #房间内禁止其它操作 return mapNumber = int(getGUIValue(item)) if mapNumber is not None: playerManager.joinSingleRoom(mapNumber) elif itemType == Material.MAGMA_CREAM: #离开房间 + if playerManager.actionCooldown(): + return iceboatCommand(playerManager.player, "ib", ["leave", playerManager.playerName]) + elif itemType == Material.MUSIC_DISC_RELIC: + player.stopSound(SoundCategory.RECORDS) + player.sendMessage(u"§a当前音乐已关闭") + player.playSound(player, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1.0, 1.0) else: return event.setCancelled(True) @@ -3851,8 +5372,8 @@ def onPlayerJoin(event): # 玩家加入处理 playerManager = PlayerManager(player) playerManager.removeBoat() playerManager.outGame() - playersManager.addPlayerAsync() - ps.scheduler.runTaskLater(lambda : playerManager.updateInventory(), 1) #延迟设置玩家背包 + playersManager.addPlayerAsync(playerManager.playerName) + ps.scheduler.runTaskLater(lambda pm=playerManager : pm.updateInventory(), 1) #延迟设置玩家背包 def onPlayerTeleportEvent(event): # 玩家进入冰船世界处理 toWorldName = event.getTo().getWorld().getName() fromWorldName = event.getFrom().getWorld().getName() @@ -3861,8 +5382,8 @@ def onPlayerTeleportEvent(event): # 玩家进入冰船世界处理 return player = event.getPlayer() playerManager = PlayerManager(player) - playersManager.addPlayerAsync() - ps.scheduler.runTaskLater(lambda : playerManager.updateInventory(), 1) #延迟设置玩家背包 + playersManager.addPlayerAsync(playerManager.playerName) + ps.scheduler.runTaskLater(lambda pm=playerManager : pm.updateInventory(), 1) #延迟设置玩家背包 if fromWorldName == WORLD_NAME: #离开冰船世界 if toWorldName == WORLD_NAME: #仅处理玩家从冰船世界离开冰船世界的情况 return @@ -3876,6 +5397,17 @@ def onArmorStandManipulate(event): #取消盔甲架交互 worldName = armorStand.getWorld().getName() if worldName == WORLD_NAME: #仅作用于冰船世界 event.setCancelled(True) +def onPlayerStopSPectating(event): #玩家离开观察者附身 + player = event.getPlayer() + worldName = player.getWorld().getName() + if worldName == WORLD_NAME: #仅作用于冰船世界 + playerName = player.getName() + if playerName in playersInSpectate: + playerManager = PlayerManager(player) + if playerManager.inSpectateRoom(): + if not playersInSpectate[playerName].leaving: + event.setCancelled(True) + ps.listener.registerListener(onPlayerInteract, PlayerInteractEvent) ps.listener.registerListener(onPlayerDropItem, PlayerDropItemEvent) @@ -3889,10 +5421,14 @@ ps.listener.registerListener(onPlayerJoin, PlayerJoinEvent) ps.listener.registerListener(onPlayerQuit, PlayerQuitEvent) ps.listener.registerListener(onPlayerTeleportEvent, PlayerTeleportEvent) ps.listener.registerListener(onArmorStandManipulate, PlayerArmorStandManipulateEvent) - +ps.listener.registerListener(onPlayerStopSPectating, PlayerStopSpectatingEntityEvent) # 取消所有物品栏拖动 # 重载处理 ----------------------------------------------------------------------------------------- def reloadAll(): + removeScoreboardObjective(u"IBPlayerRank") + removeScoreboardObjective(u"IBScoreList") + removeScoreboardTeam(u"Competition") + world = worldManager.getWorld() #仅修改冰船世界 roomsManager.resetAvailableRooms() #重置可用房间 players = world.getPlayers() @@ -3905,6 +5441,7 @@ def reloadAll(): playerX = playerLoc.getX() playerZ = playerLoc.getZ() playerManager = PlayerManager(player) + playerManager.outGame() #重置玩家状态 playerManager.updateInventory() #重置玩家背包 if not (-LOBBY_RADIUS < playerX < LOBBY_RADIUS) and not (-LOBBY_RADIUS < playerZ < LOBBY_RADIUS): #如果玩家在大厅内 playerManager.removeBoat() diff --git a/iceboat/collection.yml b/iceboat/collection.yml new file mode 100644 index 0000000..3912aa5 --- /dev/null +++ b/iceboat/collection.yml @@ -0,0 +1,692 @@ +#conditions: +# '1': +# cost: 0 +# level: 1.0 +# totalTimes: 10 +# record: +# '1': +# record: 100.00 +# times: +# '1': +# times: 10 + +boats: + '1': + display: '橡木船' + material: OAK_BOAT + cost: 0 + '2': + display: '云杉木船' + material: SPRUCE_BOAT + cost: 9999 + '3': + display: '白桦木船' + material: BIRCH_BOAT + cost: 9999 + '4': + display: '丛林木船' + material: JUNGLE_BOAT + cost: 9999 + '5': + display: '金合欢木船' + material: ACACIA_BOAT + cost: 9999 + '6': + display: '深色橡木船' + material: DARK_OAK_BOAT + cost: 9999 + '7': + display: '红树木船' + material: MANGROVE_BOAT + cost: 9999 + '8': + display: '樱花木船' + material: CHERRY_BOAT + cost: 9999 + '9': + display: '竹筏' + material: BAMBOO_RAFT + cost: 9999 + '10': + display: '苍白木船' + material: PALE_OAK_BOAT + cost: 9999 +particles: + '1': + display: '烛光' + material: END_ROD + type: END_ROD + cost: 0 + '2': + display: '青墨' + material: GLOW_INK_SAC + type: GLOW_SQUID_INK + cost: 450 + '3': + display: '墨' + material: INK_SAC + type: SQUID_INK + cost: 450 + '4': + display: '肥' + material: COCOA_BEANS + type: LANDING_HONEY + count: 10 + rx: 0.05 + ry: 0.05 + rz: 0.05 + cost: 450 + '5': + display: '魔爪' + material: ENCHANTED_BOOK + type: ENCHANTED_HIT + count: 5 + rx: 0.05 + rz: 0.05 + oy: 0.1 + cost: 1350 + '6': + display: '生命' + material: RED_DYE + type: HEART + oy: -0.1 + cost: 1350 + '7': + display: '哑光' + material: RAW_COPPER + type: WAX_OFF + count: 3 + rx: 0.02 + ry: 0.02 + rz: 0.02 + cost: 1350 + '8': + display: '胶' + material: HONEYCOMB + type: WAX_ON + cost: 1350 + '9': + display: '炽焰' + material: BLAZE_ROD + type: FLAME + speed: 0.01 #速度 + cost: 3150 + '10': + display: '菌丝' + material: BROWN_MUSHROOM + type: MYCELIUM + count: 20 + rx: 0.05 + ry: 0.05 + rz: 0.05 + cost: 3150 + '11': + display: '葡萄' + material: PURPLE_DYE + type: FALLING_OBSIDIAN_TEAR + count: 10 + rx: 0.05 + ry: 0.05 + rz: 0.05 + oy: 0.05 + cost: 3150 + '12': + display: '恩惠' + material: DOLPHIN_SPAWN_EGG + type: DOLPHIN + count: 50 #数量 + rx: 0.05 #x随机 + ry: 0.05 #y随机 + rz: 0.05 #z随机 + oy: 0.13 + cost: 6300 + '13': + display: '血迹' + material: REDSTONE + type: FALLING_LAVA + count: 10 + rx: 0.05 + ry: 0.05 + rz: 0.05 + oy: 0.1 + cost: 6300 + '14': + display: '火影' + material: BLAZE_POWDER + type: SMALL_FLAME + count: 8 + rx: 0.12 + rz: 0.12 + cost: 8700 + '15': + display: '削除' + material: LIME_DYE + type: SCRAPE + count: 5 + rx: 0.05 + ry: 0.05 + rz: 0.05 + cost: 8700 + '16': + display: '龙息' + material: DRAGON_BREATH + type: DRAGON_BREATH + level: 1.0 + '17': + display: '碳' + material: COAL + type: CAMPFIRE_COSY_SMOKE + oy: -0.08 + level: 2.0 + '18': + display: '烟花' + material: FIREWORK_STAR + type: FIREWORK + count: 5 + rx: 0.05 + rz: 0.05 + level: 3.0 + '19': + display: '唾沫' + material: LIGHT_GRAY_DYE + type: SPIT + count: 2 + rx: 0.05 + rz: 0.05 + oy: -0.05 + level: 4.0 + '20': + display: '云' + material: WHITE_DYE + type: CLOUD + oy: 0.15 + level: 5.0 + '21': + display: '渔者' + material: FISHING_ROD + type: FISHING + count: 20 + rx: 0.05 + ry: 0.05 + rz: 0.05 + record: + '20': + record: 130.00 + '22': + display: '灵魂' + material: SOUL_LANTERN + type: SCULK_SOUL + record: + '12': + record: 130.00 + '23': + display: '烟' + material: CAMPFIRE + type: CAMPFIRE_SIGNAL_SMOKE + oy: -0.08 + record: + '26': + record: 150.00 + '24': + display: '沉溺' + material: SEAGRASS + type: UNDERWATER + count: 100 + rx: 0.15 + ry: 0.08 + rz: 0.15 + oy: 0.2 + record: + '33': + record: 100.00 + '25': + display: '地狱火' + material: SOUL_CAMPFIRE + type: SOUL_FIRE_FLAME + speed: 0.01 + record: + '29': + record: 160.00 + '26': + display: '苍木' + material: PALE_OAK_SAPLING + type: PALE_OAK_LEAVES + record: + '3': + record: 100.00 + '27': + display: '灰烬' + material: GUNPOWDER + type: ASH + count: 80 #数量 + rx: 0.005 #x随机 + ry: 0.005 #y随机 + rz: 0.005 #z随机 + oy: 0.15 + record: + '28': + record: 110.00 + '28': + display: '水花' + material: BLUE_DYE + type: FALLING_WATER + count: 10 + rx: 0.05 + rz: 0.05 + oy: -0.05 + record: + '39': + record: 150.00 + '29': + display: '袭击' + material: BELL + type: OMINOUS_SPAWNING + count: 30 + rx: 0.2 + rz: 0.2 + record: + '1': + record: 100.00 + '30': + display: '启示录' + material: TOTEM_OF_UNDYING + type: TOTEM_OF_UNDYING + count: 3 + rx: 0.25 + rz: 0.25 + times: + '22': + times: 7 + '27': + times: 7 + '30': + times: 7 + '31': + display: '微光' + material: SPECTRAL_ARROW + type: GLOW + count: 3 + rx: 0.02 + ry: 0.02 + rz: 0.02 + oy: -0.08 + times: + '6': + times: 7 + '38': + times: 7 + '19': + times: 7 + '32': + display: '阵风' + material: WIND_CHARGE + type: SMALL_GUST + count: 20 + rx: 0.05 + ry: 0.05 + rz: 0.05 + times: + '5': + times: 7 + '11': + times: 7 + '32': + times: 7 + '33': + display: '雪花' + material: SNOWBALL + type: SNOWFLAKE + count: 10 + rx: 0.05 + ry: 0.05 + rz: 0.05 + times: + '13': + times: 7 + '31': + times: 7 + '37': + times: 7 + '34': + display: '落叶' + material: SPRUCE_SAPLING + type: FALLING_SPORE_BLOSSOM + count: 10 + rx: 0.05 + ry: 0.05 + rz: 0.05 + oy: 0.05 + times: + '34': + times: 7 + '35': + times: 7 + '14': + times: 7 + '35': + display: '樱花' + material: PINK_PETALS + type: CHERRY_LEAVES + count: 7 + rx: 0.07 + ry: 0.03 + rz: 0.07 + times: + '2': + times: 7 + '16': + times: 7 + '18': + times: 7 + '36': + display: '折跃' + material: SHULKER_SHELL + type: REVERSE_PORTAL + count: 20 + rx: 0.15 + rz: 0.15 + times: + '21': + times: 10 + '23': + times: 10 + '37': + display: '绿宝石' + material: EMERALD + type: HAPPY_VILLAGER + times: + '9': + times: 10 + '36': + times: 10 + '38': + display: '潮涌' + material: HEART_OF_THE_SEA + type: NAUTILUS + count: 20 + rx: 0.05 + ry: 0.05 + rz: 0.05 + times: + '15': + times: 10 + '24': + times: 10 + '39': + display: '热寂' + material: COMPASS + type: SOUL + times: + '4': + times: 10 + '10': + times: 10 +titles: + '1': + display: '新手' + material: NAME_TAG + cost: 0 + '2': + display: '车神' + material: OAK_BOAT + notForSale: True + lore: + - '§7DCIPL冠军专属' + '3': + display: '海岸冰场' + material: OAK_WOOD + times: + '1': + times: 57 + '4': + display: '元素化身' + material: CHEST + times: + '2': + times: 14 + '5': + display: '时间旅人' + material: BROWN_BANNER + times: + '3': + times: 42 + '6': + display: '巫妖王' + material: DARK_PRISMARINE_STAIRS + times: + '4': + times: 48 + '7': + display: '琳琅天上' + material: YELLOW_CONCRETE + times: + '5': + times: 26 + '8': + display: '方程式车手' + material: IRON_INGOT + times: + '6': + times: 29 + '9': + display: '神之一手' + material: LIGHT_BLUE_DYE + times: + '7': + times: 31 + '10': + display: '饺子' + material: COMMAND_BLOCK + times: + '8': + times: 44 + '11': + display: '大展宏图' + material: EMERALD + times: + '9': + times: 27 + '12': + display: '禁欲系' + material: COD + times: + '10': + times: 33 + '13': + display: '钻石泪' + material: GOLDEN_PICKAXE + times: + '11': + times: 46 + '14': + display: '考古学家' + material: CHISELED_SANDSTONE + times: + '12': + times: 33 + '15': + display: '冰封绿洲' + material: POWDER_SNOW_BUCKET + times: + '13': + times: 35 + '16': + display: '扭曲丛林' + material: OAK_FENCE + times: + '14': + times: 35 + '17': + display: '冰刺撞我' + material: SNOW + times: + '15': + times: 27 + '18': + display: '去春游' + material: WHEAT + times: + '16': + times: 27 + '19': + display: '碧溪轮影' + material: SWEET_BERRIES + times: + '17': + times: 25 + '20': + display: '流水人家' + material: DARK_OAK_FENCE + times: + '18': + times: 13 + '21': + display: '宇宙滑行士' + material: BEACON + times: + '19': + times: 34 + '22': + display: '江南渔火' + material: SPRUCE_BOAT + times: + '20': + times: 43 + '23': + display: '女巫姐姐❤' + material: CAKE + times: + '21': + times: 39 + '24': + display: '小黑子' + material: EGG + times: + '22': + times: 35 + '25': + display: '我重生了' + material: ENDER_EYE + times: + '23': + times: 41 + '26': + display: 'AT立场' + material: NETHERITE_BLOCK + times: + '24': + times: 35 + '27': + display: '繁荣车手' + material: POLISHED_GRANITE_SLAB + times: + '25': + times: 34 + '28': + display: '我❤荃角' + material: OAK_LEAVES + times: + '26': + times: 37 + '29': + display: '初号机' + material: SLIME_BALL + times: + '27': + times: 39 + '30': + display: '梦之伊始' + material: SPONGE + times: + '28': + times: 36 + '31': + display: '炼狱游者' + material: BLAZE_POWDER + times: + '29': + times: 54 + '32': + display: '启示录' + material: TOTEM_OF_UNDYING + times: + '30': + times: 19 + '33': + display: '雪殒' + material: SNOWBALL + times: + '31': + times: 54 + '34': + display: '陶瓦镇' + material: TERRACOTTA + times: + '32': + times: 26 + '35': + display: '星星比' + material: TROPICAL_FISH + times: + '33': + times: 35 + '36': + display: '冷钢狙击枪' + material: IRON_HORSE_ARMOR + cost: 8700 + lore: + - '§7DCIPL 冠军定制' + - '§7S1 DreamCityToger' + - '§f' + '37': + display: '魔法少女☆' + material: DIAMOND_HOE + cost: 8700 + lore: + - '§7DCIPL 冠军定制' + - '§7S2 BreakGraze' + - '§f' + '38': + display: '碧水良湖' + material: AXOLOTL_BUCKET + times: + '34': + times: 35 + '39': + display: '红枫小镇' + material: ACACIA_PLANKS + times: + '35': + times: 30 + '40': + display: '终局之城' + material: OXEYE_DAISY + times: + '36': + times: 27 + '41': + display: '你好冰船' + material: SNOW_BLOCK + times: + '37': + times: 10 + '42': + display: '那就我来' + material: IRON_BARS + times: + '38': + times: 42 + '43': + display: '落叶归根' + material: BAMBOO_HANGING_SIGN + times: + '39': + times: 45 + '44': + display: '马猴烧酒★' + material: BOW + cost: 8700 + lore: + - '§7DCIPL 冠军定制' + - '§7S3 BreakGraze' + - '§f' \ No newline at end of file diff --git a/iceboat/fame.yml b/iceboat/fame.yml new file mode 100644 index 0000000..492b311 --- /dev/null +++ b/iceboat/fame.yml @@ -0,0 +1,96 @@ +'1': + x: 4.5 + y: 64 + z: 6.5 + yaw: 90 + pitch: 0 +'2': + x: -3.5 + y: 64 + z: 6.5 + yaw: -90 + pitch: 0 +'3': + x: 4.5 + y: 64 + z: 12.5 + yaw: 90 + pitch: 0 +'4': + x: -3.5 + y: 64 + z: 12.5 + yaw: -90 + pitch: 0 +'5': + x: 4.5 + y: 64 + z: 18.5 + yaw: 90 + pitch: 0 +'6': + x: -3.5 + y: 64 + z: 18.5 + yaw: -90 + pitch: 0 +'7': + x: 4.5 + y: 64 + z: 24.5 + yaw: 90 + pitch: 0 +'8': + x: -3.5 + y: 64 + z: 24.5 + yaw: -90 + pitch: 0 +'9': + x: 4.5 + y: 64 + z: 30.5 + yaw: 90 + pitch: 0 +'10': + x: -3.5 + y: 64 + z: 30.5 + yaw: -90 + pitch: 0 +'11': + x: 4.5 + y: 64 + z: 36.5 + yaw: 90 + pitch: 0 +'12': + x: -3.5 + y: 64 + z: 36.5 + yaw: -90 + pitch: 0 +'13': + x: 4.5 + y: 64 + z: 42.5 + yaw: 90 + pitch: 0 +'14': + x: -3.5 + y: 64 + z: 42.5 + yaw: -90 + pitch: 0 +'15': + x: 4.5 + y: 64 + z: 48.5 + yaw: 90 + pitch: 0 +'16': + x: -3.5 + y: 64 + z: 48.5 + yaw: -90 + pitch: 0 \ No newline at end of file diff --git a/iceboat/hologram.yml b/iceboat/hologram.yml new file mode 100644 index 0000000..16e0d74 --- /dev/null +++ b/iceboat/hologram.yml @@ -0,0 +1,33 @@ + +1: + x: -30 + y: 64 + z: -2 +2: + x: -20 + y: 64 + z: -2 +3: + x: -10 + y: 64 + z: -2 +4: + x: 0 + y: 64 + z: -2 +5: + x: 10 + y: 64 + z: -2 +6: + x: 20 + y: 64 + z: -2 +7: + x: 30 + y: 64 + z: -2 +8: + x: 0 + y: 65 + z: -14 \ No newline at end of file diff --git a/iceboat/level.yml b/iceboat/level.yml new file mode 100644 index 0000000..3a6490a --- /dev/null +++ b/iceboat/level.yml @@ -0,0 +1,420 @@ +#conditions: +# '1': +# level: 1.0 +# target: 1.5 +# record: +# '1': +# record: 100.00 +'1': + display: 'L5-1 直线行驶' + material: PAPER + need: 0.0 + target: 0.1 + record: + '2999': + record: 4.00 +'2': + display: 'L5-2 方块速度' + material: PAPER + need: 0.1 + target: 0.2 + record: + '2998': + record: 7.0 +'3': + display: 'L5-3 左右转向' + material: PAPER + need: 0.2 + target: 0.3 + record: + '2997': + record: 10.00 +'4': + display: 'L5-4 提前入弯' + material: PAPER + need: 0.3 + target: 0.4 + record: + '2996': + record: 7.00 +'5': + display: '路考:极地雪堡' + material: PAPER + need: 0.4 + target: 0.6 + record: + '37': + record: 60.00 +'6': + display: 'L5-5 撞墙过弯' + material: PAPER + need: 0.6 + target: 0.8 + record: + '2995': + record: 5.00 +'7': + display: '路考:村镇木桥' + material: PAPER + need: 0.8 + target: 1.0 + record: + '18': + record: 125.00 +'8': + display: 'L4-1 捷径' + material: PAPER + need: 1.0 + target: 1.1 + record: + '2994': + record: 6.00 +'9': + display: '路考:极地狂飙' + material: PAPER + need: 1.1 + target: 1.3 + record: + '15': + record: 120.00 +'10': + display: 'L4-2 方块互动' + material: PAPER + need: 1.3 + target: 1.4 + record: + '2993': + record: 8.00 +'11': + display: 'L4-3 空中速度' + material: PAPER + need: 1.4 + target: 1.5 + record: + '2992': + record: 10.00 +'12': + display: '路考:秋名山' + material: PAPER + need: 1.5 + target: 1.7 + record: + '5': + record: 180.00 +'13': + display: 'L4-4 赛车线' + material: PAPER + need: 1.7 + target: 1.8 + record: + '2991': + record: 10.00 +'14': + display: '路考:特若柯特环' + material: PAPER + need: 1.8 + target: 2.0 + record: + '32': + record: 180.00 +'15': + display: 'L3-1 水流' + material: PAPER + need: 2.0 + target: 2.1 + record: + '2990': + record: 20.00 +'16': + display: '路考:沙漠金字塔' + material: PAPER + need: 2.1 + target: 2.3 + record: + '12': + record: 115.00 +'17': + display: '路考:滑稽游乐园' + material: PAPER + need: 2.1 + target: 2.3 + record: + '22': + record: 120.00 +'18': + display: 'L3-2 假弯' + material: PAPER + need: 2.3 + target: 2.4 + record: + '2989': + record: 9.00 +'19': + display: 'L3-3 急停' + material: PAPER + need: 2.4 + target: 2.5 + record: + '2988': + record: 5.50 +'20': + display: '路考:极地金鱼路' + material: PAPER + need: 2.5 + target: 2.7 + record: + '10': + record: 130.00 +'21': + display: '路考:村镇良枫' + material: PAPER + need: 2.5 + target: 2.7 + record: + '35': + record: 120.00 +'22': + display: 'L3-4 飞跃' + material: PAPER + need: 2.7 + target: 2.8 + record: + '2987': + record: 15.00 +'23': + display: '路考:极地惊险落崖' + material: PAPER + need: 2.8 + target: 3.0 + record: + '13': + record: 105.00 +'24': + display: '路考:甜点星球' + material: PAPER + need: 2.8 + target: 3.0 + record: + '21': + record: 120.00 +'25': + display: 'L2-1 蓝冰' + material: PAPER + need: 3.0 + target: 3.1 + record: + '2986': + record: 15.00 +'26': + display: '路考:环山森岭高速' + material: PAPER + need: 3.1 + target: 3.3 + record: + '26': + record: 130.00 +'27': + display: 'L2-2 空中控制' + material: PAPER + need: 3.3 + target: 3.4 + record: + '2985': + record: 11.50 +'28': + display: 'L2-3 对抗' + material: PAPER + need: 3.4 + target: 3.5 + record: + '2984': + record: 10.00 +'29': + display: 'L2-4 路线选择' + material: PAPER + need: 3.5 + target: 3.6 + record: + '2983': + record: 8.00 +'30': + display: '路考:宇宙城监狱岛' + material: PAPER + need: 3.6 + target: 3.8 + record: + '38': + record: 145.00 +'31': + display: '路考:异世界之旅' + material: PAPER + need: 3.6 + target: 3.8 + record: + '23': + record: 120.00 +'32': + display: '路考:箱根归路' + material: PAPER + need: 3.8 + target: 4.0 + record: + '39': + record: 160.00 +'33': + display: '路考:恶地矿山采集场' + material: PAPER + need: 3.8 + target: 4.0 + record: + '11': + record: 130.00 +'34': + display: 'L1-1 精确控制' + material: PAPER + need: 4.0 + target: 4.1 + record: + '2982': + record: 10.00 +'35': + display: '路考:极地破碎雪原' + material: PAPER + need: 4.1 + target: 4.3 + record: + '31': + record: 130.00 +'36': + display: 'L1-2 单格冰' + material: PAPER + need: 4.3 + target: 4.4 + record: + '2981': + record: 5.00 +'37': + display: 'L1-3 拖漂' + material: PAPER + need: 4.4 + target: 4.5 + record: + '2980': + record: 15.00 +'38': + display: '路考:炼狱祭坛' + material: PAPER + need: 4.5 + target: 4.7 + record: + '29': + record: 138.00 +'39': + display: 'L1-4 反拉双键' + material: PAPER + need: 4.7 + target: 4.8 + record: + '2979': + record: 4.00 +'40': + display: '路考:海岸冰场' + material: PAPER + need: 4.8 + target: 5.0 + record: + '1': + record: 105.00 + + + + + +'41': + display: 'S4赛季:极地雪堡' + material: PAPER + need: 5.0 + target: 5.1 + record: + '37': + record: 50.00 +'42': + display: 'S4赛季:村镇露营营地' + material: PAPER + need: 5.0 + target: 5.2 + record: + '16': + record: 102.00 +'43': + display: 'S4赛季:忠菊之城' + material: PAPER + need: 5.1 + target: 5.3 + record: + '36': + record: 94.00 +'44': + display: 'S4赛季:村镇良枫' + material: PAPER + need: 5.2 + target: 5.4 + record: + '35': + record: 108.00 +'45': + display: 'S4赛季:村镇良湖' + material: PAPER + need: 5.3 + target: 5.5 + record: + '34': + record: 123.00 +'46': + display: 'S4赛季:极地惊险落崖' + material: PAPER + need: 5.4 + target: 5.6 + record: + '13': + record: 92.00 +'47': + display: 'S4赛季:甜点星球' + material: PAPER + need: 5.5 + target: 5.7 + record: + '21': + record: 104.00 +'48': + display: 'S4赛季:异世界之旅' + material: PAPER + need: 5.6 + target: 5.8 + record: + '23': + record: 107.00 +'49': + display: 'S4赛季:极地冰封王座' + material: PAPER + need: 5.7 + target: 5.9 + record: + '4': + record: 129.00 +'50': + display: 'S4赛季:炼狱祭坛' + material: PAPER + need: 5.8 + target: 6.0 + record: + '29': + record: 132.00 +'51': + display: 'S4赛季:极地破碎雪原' + material: PAPER + need: 5.9 + target: 6.0 + record: + '31': + record: 124.00 \ No newline at end of file diff --git a/iceboat/maps/1.yml b/iceboat/maps/1.yml new file mode 100644 index 0000000..6fd5426 --- /dev/null +++ b/iceboat/maps/1.yml @@ -0,0 +1,120 @@ +display: '海岸冰场' +difficulty: '5.7' +material: OAK_WOOD +creator: "DreamCityToger" +yaw: 180 +lap: 2 +point: 10 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4996 + y: 63 + z: 4998 + pos2: + x: 5004 + y: 66 + z: 5005 + glass: + pos1: + x: 5003 + y: 64 + z: 4997 + pos2: + x: 4997 + y: 64 + z: 4997 + 1: + pos1: + x: 4991 + y: 63 + z: 4960 + pos2: + x: 4978 + y: 54 + z: 4981 + 2: + pos1: + x: 4980 + y: 56 + z: 4944 + pos2: + x: 5003 + y: 51 + z: 4954 + 3: + pos1: + x: 4991 + y: 60 + z: 5005 + pos2: + x: 4960 + y: 49 + z: 5027 + 4: + pos1: + x: 4960 + y: 57 + z: 5001 + pos2: + x: 4948 + y: 60 + z: 4975 + 5: + pos1: + x: 4944 + y: 62 + z: 4980 + pos2: + x: 4924 + y: 46 + z: 5020 + 6: + pos1: + x: 4929 + y: 46 + z: 5030 + pos2: + x: 4944 + y: 73 + z: 5051 + 7: + pos1: + x: 4934 + y: 72 + z: 5087 + pos2: + x: 4886 + y: 68 + z: 5101 + 8: + pos1: + x: 4886 + y: 70 + z: 5041 + pos2: + x: 44918 + y: 58 + z: 5008 + 9: + pos1: + x: 4984 + y: 65 + z: 5012 + pos2: + x: 4923 + y: 70 + z: 4999 + 10: + pos1: + x: 4995 + y: 63 + z: 4997 + pos2: + x: 5004 + y: 66 + z: 4977 \ No newline at end of file diff --git a/iceboat/maps/10.yml b/iceboat/maps/10.yml new file mode 100644 index 0000000..f8efea8 --- /dev/null +++ b/iceboat/maps/10.yml @@ -0,0 +1,147 @@ +display: '极地金鱼路' +difficulty: '3.3' +material: COD +creator: DreamCityToger +yaw: 0 +lap: 1 +point: 13 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4982 + y: 63 + z: 5003 + pos2: + x: 5014 + y: 67 + z: 4987 + glass: + pos1: + x: 5010 + y: 64 + z: 5003 + pos2: + x: 4983 + y: 64 + z: 5003 + 1: + pos1: + x: 4984 + y: 63 + z: 5150 + pos2: + x: 4945 + y: 67 + z: 5106 + 2: + pos1: + x: 4940 + y: 63 + z: 5119 + pos2: + x: 4918 + y: 67 + z: 5169 + 3: + pos1: + x: 4849 + y: 63 + z: 5179 + pos2: + x: 4914 + y: 67 + z: 5093 + 4: + pos1: + x: 4828 + y: 63 + z: 5053 + pos2: + x: 4859 + y: 67 + z: 5009 + 5: + pos1: + x: 4873 + y: 63 + z: 4939 + pos2: + x: 4832 + y: 67 + z: 4903 + 6: + pos1: + x: 4828 + y: 63 + z: 4892 + pos2: + x: 4912 + y: 67 + z: 4834 + 7: + pos1: + x: 4992 + y: 63 + z: 4864 + pos2: + x: 5024 + y: 67 + z: 4895 + 8: + pos1: + x: 5078 + y: 63 + z: 4917 + pos2: + x: 5162 + y: 67 + z: 4964 + 9: + pos1: + x: 5224 + y: 63 + z: 5095 + pos2: + x: 5169 + y: 67 + z: 5133 + 10: + pos1: + x: 5195 + y: 63 + z: 5226 + pos2: + x: 5130 + y: 67 + z: 5270 + 11: + pos1: + x: 5075 + y: 63 + z: 5189 + pos2: + x: 5119 + y: 67 + z: 5143 + 12: + pos1: + x: 5083 + y: 63 + z: 5066 + pos2: + x: 5148 + y: 67 + z: 5030 + 13: + pos1: + x: 5016 + y: 63 + z: 5003 + pos2: + x: 4973 + y: 67 + z: 5050 \ No newline at end of file diff --git a/iceboat/maps/11.yml b/iceboat/maps/11.yml new file mode 100644 index 0000000..e2f9efa --- /dev/null +++ b/iceboat/maps/11.yml @@ -0,0 +1,192 @@ +display: '恶地矿山采集场' +difficulty: '4.6' +material: GOLDEN_PICKAXE +creator: BreakGraze +yaw: -90 +lap: 1 +point: 18 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 5003 + y: 63 + z: 4992 + pos2: + x: 4959 + y: 67 + z: 5008 + glass: + pos1: + x: 5003 + y: 64 + z: 4993 + pos2: + x: 5003 + y: 64 + z: 5007 + 1: + pos1: + x: 5154 + y: 63 + z: 5017 + pos2: + x: 5205 + y: 67 + z: 4964 + 2: + pos1: + x: 5220 + y: 50 + z: 5046 + pos2: + x: 5199 + y: 67 + z: 5066 + 3: + pos1: + x: 5191 + y: 50 + z: 5114 + pos2: + x: 5177 + y: 67 + z: 5074 + 4: + pos1: + x: 5138 + y: 50 + z: 5130 + pos2: + x: 5116 + y: 67 + z: 5091 + 5: + pos1: + x: 5091 + y: 50 + z: 5092 + pos2: + x: 5054 + y: 67 + z: 5050 + 6: + pos1: + x: 5014 + y: 50 + z: 5081 + pos2: + x: 5037 + y: 67 + z: 5118 + 7: + pos1: + x: 5096 + y: 50 + z: 5162 + pos2: + x: 5146 + y: 67 + z: 5172 + 8: + pos1: + x: 5087 + y: 50 + z: 5214 + pos2: + x: 5136 + y: 67 + z: 5200 + 9: + pos1: + x: 5111 + y: 50 + z: 5227 + pos2: + x: 5162 + y: 67 + z: 5247 + 10: + pos1: + x: 5168 + y: 50 + z: 5280 + pos2: + x: 5201 + y: 67 + z: 5260 + 11: + pos1: + x: 5223 + y: 50 + z: 5204 + pos2: + x: 5212 + y: 67 + z: 5174 + 12: + pos1: + x: 5263 + y: 50 + z: 5229 + pos2: + x: 5299 + y: 67 + z: 5210 + 13: + pos1: + x: 5233 + y: 50 + z: 5267 + pos2: + x: 5257 + y: 67 + z: 5293 + 14: + pos1: + x: 5321 + y: 50 + z: 5342 + pos2: + x: 5258 + y: 67 + z: 5313 + 15: + pos1: + x: 5280 + y: 50 + z: 5351 + pos2: + x: 5323 + y: 67 + z: 5382 + 16: + pos1: + x: 5339 + y: 50 + z: 5437 + pos2: + x: 5370 + y: 67 + z: 5464 + 17: + pos1: + x: 5404 + y: 50 + z: 5468 + pos2: + x: 5356 + y: 67 + z: 5486 + 18: + pos1: + x: 5237 + y: 50 + z: 5462 + pos2: + x: 5215 + y: 67 + z: 5491 \ No newline at end of file diff --git a/iceboat/maps/12.yml b/iceboat/maps/12.yml new file mode 100644 index 0000000..5dcd5aa --- /dev/null +++ b/iceboat/maps/12.yml @@ -0,0 +1,147 @@ +display: '沙漠金字塔' +difficulty: '3.3' +material: CHISELED_SANDSTONE +creator: BreakGraze +yaw: -90 +lap: 1 +point: 13 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 5003 + y: 63 + z: 5014 + pos2: + x: 4968 + y: 67 + z: 4988 + glass: + pos1: + x: 5003 + y: 64 + z: 4989 + pos2: + x: 5003 + y: 64 + z: 5013 + 1: + pos1: + x: 5166 + y: 50 + z: 5032 + pos2: + x: 5132 + y: 100 + z: 5080 + 2: + pos1: + x: 5061 + y: 50 + z: 5094 + pos2: + x: 5121 + y: 100 + z: 5134 + 3: + pos1: + x: 5110 + y: 50 + z: 5157 + pos2: + x: 5150 + y: 100 + z: 5202 + 4: + pos1: + x: 5186 + y: 50 + z: 5213 + pos2: + x: 5171 + y: 100 + z: 5268 + 5: + pos1: + x: 5118 + y: 50 + z: 5365 + pos2: + x: 5085 + y: 100 + z: 5335 + 6: + pos1: + x: 5048 + y: 50 + z: 5362 + pos2: + x: 4980 + y: 100 + z: 5347 + 7: + pos1: + x: 4999 + y: 50 + z: 5319 + pos2: + x: 4965 + y: 100 + z: 5293 + 8: + pos1: + x: 4977 + y: 50 + z: 5271 + pos2: + x: 5000 + y: 100 + z: 5232 + 9: + pos1: + x: 4874 + y: 50 + z: 5205 + pos2: + x: 4895 + y: 100 + z: 5130 + 10: + pos1: + x: 4912 + y: 50 + z: 5030 + pos2: + x: 4924 + y: 73 + z: 4960 + 11: + pos1: + x: 4888 + y: 73 + z: 4996 + pos2: + x: 4910 + y: 77 + z: 5030 + 12: + pos1: + x: 4885 + y: 82 + z: 4974 + pos2: + x: 4906 + y: 100 + z: 5007 + 13: + pos1: + x: 5003 + y: 50 + z: 4985 + pos2: + x: 5079 + y: 100 + z: 5017 \ No newline at end of file diff --git a/iceboat/maps/13.yml b/iceboat/maps/13.yml new file mode 100644 index 0000000..92ae0d1 --- /dev/null +++ b/iceboat/maps/13.yml @@ -0,0 +1,129 @@ +display: '极地惊险落崖' +difficulty: '3.5' +material: POWDER_SNOW_BUCKET +creator: BreakGraze +yaw: 90 +lap: 1 +point: 11 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4998 + y: 63 + z: 5007 + pos2: + x: 5044 + y: 67 + z: 4991 + glass: + pos1: + x: 4997 + y: 64 + z: 5006 + pos2: + x: 4997 + y: 64 + z: 4992 + 1: + pos1: + x: 4879 + y: 63 + z: 4946 + pos2: + x: 4835 + y: 67 + z: 4975 + 2: + pos1: + x: 4773 + y: 50 + z: 5017 + pos2: + x: 4726 + y: 100 + z: 4974 + 3: + pos1: + x: 4752 + y: 50 + z: 5039 + pos2: + x: 4799 + y: 100 + z: 5070 + 4: + pos1: + x: 4782 + y: 50 + z: 5113 + pos2: + x: 4747 + y: 100 + z: 5078 + 5: + pos1: + x: 4728 + y: 50 + z: 5243 + pos2: + x: 4706 + y: 100 + z: 5273 + 6: + pos1: + x: 4824 + y: 50 + z: 5370 + pos2: + x: 4789 + y: 100 + z: 5336 + 7: + pos1: + x: 4755 + y: 50 + z: 5364 + pos2: + x: 4795 + y: 100 + z: 5393 + 8: + pos1: + x: 4918 + y: 50 + z: 5350 + pos2: + x: 5028 + y: 100 + z: 5299 + 9: + pos1: + x: 4959 + y: 50 + z: 5250 + pos2: + x: 5037 + y: 100 + z: 5206 + 10: + pos1: + x: 5027 + y: 50 + z: 5088 + pos2: + x: 5096 + y: 100 + z: 5037 + 11: + pos1: + x: 4997 + y: 50 + z: 5009 + pos2: + x: 4938 + y: 100 + z: 4990 \ No newline at end of file diff --git a/iceboat/maps/14.yml b/iceboat/maps/14.yml new file mode 100644 index 0000000..755f3ee --- /dev/null +++ b/iceboat/maps/14.yml @@ -0,0 +1,156 @@ +display: '村镇失修曲径' +difficulty: '3.5' +material: OAK_FENCE +creator: BreakGraze +yaw: 180 +lap: 1 +point: 14 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4994 + y: 63 + z: 4998 + pos2: + x: 5006 + y: 67 + z: 5025 + glass: + pos1: + x: 4995 + y: 64 + z: 4997 + pos2: + x: 5005 + y: 64 + z: 4997 + 1: + pos1: + x: 5029 + y: 63 + z: 4921 + pos2: + x: 5074 + y: 67 + z: 4944 + 2: + pos1: + x: 5036 + y: 63 + z: 4885 + pos2: + x: 5007 + y: 67 + z: 4864 + 3: + pos1: + x: 5032 + y: 63 + z: 4818 + pos2: + x: 5089 + y: 67 + z: 4844 + 4: + pos1: + x: 5110 + y: 63 + z: 4951 + pos2: + x: 5160 + y: 67 + z: 4896 + 5: + pos1: + x: 5168 + y: 63 + z: 4813 + pos2: + x: 5123 + y: 67 + z: 4755 + 6: + pos1: + x: 5041 + y: 63 + z: 4728 + pos2: + x: 4985 + y: 67 + z: 4805 + 7: + pos1: + x: 4958 + y: 63 + z: 4738 + pos2: + x: 5001 + y: 67 + z: 4694 + 8: + pos1: + x: 5166 + y: 63 + z: 4702 + pos2: + x: 5205 + y: 67 + z: 4762 + 9: + pos1: + x: 5232 + y: 63 + z: 4840 + pos2: + x: 5258 + y: 67 + z: 4895 + 10: + pos1: + x: 5284 + y: 63 + z: 4939 + pos2: + x: 5316 + y: 67 + z: 4897 + 11: + pos1: + x: 5278 + y: 63 + z: 4786 + pos2: + x: 5250 + y: 67 + z: 4769 + 12: + pos1: + x: 5285 + y: 63 + z: 4726 + pos2: + x: 5257 + y: 67 + z: 4693 + 13: + pos1: + x: 5270 + y: 63 + z: 4678 + pos2: + x: 5308 + y: 67 + z: 4660 + 14: + pos1: + x: 5357 + y: 63 + z: 4619 + pos2: + x: 5377 + y: 67 + z: 4585 \ No newline at end of file diff --git a/iceboat/maps/15.yml b/iceboat/maps/15.yml new file mode 100644 index 0000000..9acbd8d --- /dev/null +++ b/iceboat/maps/15.yml @@ -0,0 +1,102 @@ +display: '极地狂飙' +difficulty: '2.7' +material: SNOW +creator: BreakGraze +yaw: 90 +lap: 2 +point: 8 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4998 + y: 63 + z: 5007 + pos2: + x: 5036 + y: 67 + z: 4989 + glass: + pos1: + x: 4997 + y: 64 + z: 5006 + pos2: + x: 4997 + y: 64 + z: 4992 + 1: + pos1: + x: 4939 + y: 63 + z: 5072 + pos2: + x: 4987 + y: 67 + z: 5101 + 2: + pos1: + x: 4975 + y: 63 + z: 5162 + pos2: + x: 4919 + y: 67 + z: 5199 + 3: + pos1: + x: 4992 + y: 63 + z: 5261 + pos2: + x: 5021 + y: 67 + z: 5194 + 4: + pos1: + x: 5083 + y: 63 + z: 5227 + pos2: + x: 5119 + y: 67 + z: 5184 + 5: + pos1: + x: 5167 + y: 63 + z: 5139 + pos2: + x: 5129 + y: 67 + z: 5117 + 6: + pos1: + x: 5132 + y: 63 + z: 5085 + pos2: + x: 5173 + y: 67 + z: 5042 + 7: + pos1: + x: 5117 + y: 63 + z: 5031 + pos2: + x: 5084 + y: 67 + z: 5000 + 8: + pos1: + x: 4997 + y: 63 + z: 5009 + pos2: + x: 4956 + y: 67 + z: 4982 \ No newline at end of file diff --git a/iceboat/maps/16.yml b/iceboat/maps/16.yml new file mode 100644 index 0000000..df686c9 --- /dev/null +++ b/iceboat/maps/16.yml @@ -0,0 +1,93 @@ +display: '村镇露营营地' +difficulty: '2.7' +material: WHEAT +creator: BreakGraze +yaw: -90 +lap: 2 +point: 7 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 5003 + y: 63 + z: 4987 + pos2: + x: 4959 + y: 67 + z: 5014 + glass: + pos1: + x: 5003 + y: 64 + z: 4988 + pos2: + x: 5003 + y: 64 + z: 5012 + 1: + pos1: + x: 5210 + y: 63 + z: 5039 + pos2: + x: 5147 + y: 67 + z: 5106 + 2: + pos1: + x: 5078 + y: 63 + z: 5120 + pos2: + x: 5136 + y: 67 + z: 5147 + 3: + pos1: + x: 5174 + y: 63 + z: 5208 + pos2: + x: 5118 + y: 67 + z: 5260 + 4: + pos1: + x: 5063 + y: 63 + z: 5203 + pos2: + x: 5034 + y: 67 + z: 5248 + 5: + pos1: + x: 5008 + y: 63 + z: 5181 + pos2: + x: 4953 + y: 67 + z: 5138 + 6: + pos1: + x: 4912 + y: 63 + z: 5074 + pos2: + x: 4868 + y: 67 + z: 5002 + 7: + pos1: + x: 5003 + y: 63 + z: 4985 + pos2: + x: 5089 + y: 67 + z: 5018 \ No newline at end of file diff --git a/iceboat/maps/17.yml b/iceboat/maps/17.yml new file mode 100644 index 0000000..84bd499 --- /dev/null +++ b/iceboat/maps/17.yml @@ -0,0 +1,93 @@ +display: '村镇环道' +difficulty: '2.5' +material: SWEET_BERRIES +creator: BreakGraze +yaw: 0 +lap: 3 +point: 7 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 5009 + y: 63 + z: 5003 + pos2: + x: 4991 + y: 67 + z: 4974 + glass: + pos1: + x: 5007 + y: 64 + z: 5003 + pos2: + x: 4992 + y: 64 + z: 5003 + 1: + pos1: + x: 4970 + y: 63 + z: 5043 + pos2: + x: 4904 + y: 67 + z: 5064 + 2: + pos1: + x: 4921 + y: 63 + z: 5011 + pos2: + x: 4905 + y: 67 + z: 5048 + 3: + pos1: + x: 4868 + y: 63 + z: 5006 + pos2: + x: 4883 + y: 67 + z: 4974 + 4: + pos1: + x: 4914 + y: 63 + z: 4931 + pos2: + x: 4929 + y: 67 + z: 4954 + 5: + pos1: + x: 4910 + y: 63 + z: 4982 + pos2: + x: 4939 + y: 67 + z: 4997 + 6: + pos1: + x: 4956 + y: 63 + z: 4912 + pos2: + x: 4985 + y: 67 + z: 4945 + 7: + pos1: + x: 5008 + y: 63 + z: 5003 + pos2: + x: 4988 + y: 67 + z: 5033 \ No newline at end of file diff --git a/iceboat/maps/18.yml b/iceboat/maps/18.yml new file mode 100644 index 0000000..f00a683 --- /dev/null +++ b/iceboat/maps/18.yml @@ -0,0 +1,75 @@ +display: '村镇木桥' +difficulty: '1.3' +material: DARK_OAK_FENCE +creator: BreakGraze +yaw: 0 +lap: 5 +point: 5 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 5008 + y: 63 + z: 5003 + pos2: + x: 4993 + y: 67 + z: 4979 + glass: + pos1: + x: 5006 + y: 64 + z: 5003 + pos2: + x: 4994 + y: 64 + z: 5003 + 1: + pos1: + x: 5043 + y: 63 + z: 5065 + pos2: + x: 5094 + y: 67 + z: 5079 + 2: + pos1: + x: 5115 + y: 63 + z: 5048 + pos2: + x: 5093 + y: 67 + z: 4997 + 3: + pos1: + x: 5054 + y: 63 + z: 4982 + pos2: + x: 5070 + y: 67 + z: 4949 + 4: + pos1: + x: 5026 + y: 63 + z: 4937 + pos2: + x: 4993 + y: 67 + z: 4973 + 5: + pos1: + x: 4993 + y: 63 + z: 5003 + pos2: + x: 5034 + y: 67 + z: 5052 \ No newline at end of file diff --git a/iceboat/maps/19.yml b/iceboat/maps/19.yml new file mode 100644 index 0000000..dd82920 --- /dev/null +++ b/iceboat/maps/19.yml @@ -0,0 +1,156 @@ +display: '神舟遨游' +difficulty: '3.4' +material: BEACON +creator: BreakGraze、ZuiLiu_aaaaab、iceflyingAND、Harry10124V、WWWMrNobody、KaMuMom +yaw: -90 +lap: 1 +point: 14 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 5003 + y: 63 + z: 4988 + pos2: + x: 4956 + y: 67 + z: 5012 + glass: + pos1: + x: 5003 + y: 64 + z: 5011 + pos2: + x: 5003 + y: 64 + z: 4989 + 1: + pos1: + x: 5056 + y: 0 + z: 5012 + pos2: + x: 5107 + y: 255 + z: 4988 + 2: + pos1: + x: 5187 + y: 0 + z: 4988 + pos2: + x: 5162 + y: 255 + z: 4942 + 3: + pos1: + x: 5091 + y: 0 + z: 5000 + pos2: + x: 5114 + y: 255 + z: 4930 + 4: + pos1: + x: 5054 + y: 0 + z: 4935 + pos2: + x: 5041 + y: 255 + z: 4884 + 5: + pos1: + x: 5142 + y: 0 + z: 4832 + pos2: + x: 5127 + y: 255 + z: 4748 + 6: + pos1: + x: 5081 + y: 0 + z: 4683 + pos2: + x: 5046 + y: 255 + z: 4770 + 7: + pos1: + x: 4927 + y: 0 + z: 4822 + pos2: + x: 4839 + y: 255 + z: 4796 + 8: + pos1: + x: 4826 + y: 0 + z: 4677 + pos2: + x: 4868 + y: 255 + z: 4728 + 9: + pos1: + x: 4929 + y: 0 + z: 4770 + pos2: + x: 4988 + y: 255 + z: 4728 + 10: + pos1: + x: 4975 + y: 0 + z: 4677 + pos2: + x: 4928 + y: 255 + z: 4715 + 11: + pos1: + x: 4928 + y: 0 + z: 4621 + pos2: + x: 4881 + y: 255 + z: 4668 + 12: + pos1: + x: 4898 + y: 0 + z: 4677 + pos2: + x: 4913 + y: 255 + z: 4714 + 13: + pos1: + x: 4899 + y: 0 + z: 4881 + pos2: + x: 4910 + y: 255 + z: 4960 + 14: + pos1: + x: 5003 + y: 0 + z: 4988 + pos2: + x: 5056 + y: 255 + z: 5012 \ No newline at end of file diff --git a/iceboat/maps/2.yml b/iceboat/maps/2.yml new file mode 100644 index 0000000..bed0c96 --- /dev/null +++ b/iceboat/maps/2.yml @@ -0,0 +1,75 @@ +display: '村镇东篱' +difficulty: '1.4' +material: CHEST +creator: "DreamCityToger" +yaw: 0 +lap: 4 +point: 5 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 5008 + y: 67 + z: 4990 + pos2: + x: 4991 + y: 63 + z: 5002 + glass: + pos1: + x: 4992 + y: 64 + z: 5002 + pos2: + x: 5007 + y: 64 + z: 5002 + 1: + pos1: + x: 5021 + y: 66 + z: 5081 + pos2: + x: 5057 + y: 63 + z: 5100 + 2: + pos1: + x: 5078 + y: 66 + z: 5071 + pos2: + x: 5048 + y: 63 + z: 5038 + 3: + pos1: + x: 5030 + y: 63 + z: 5018 + pos2: + x: 5064 + y: 66 + z: 4994 + 4: + pos1: + x: 5075 + y: 63 + z: 4952 + pos2: + x: 5044 + y: 66 + z: 4928 + 5: + pos1: + x: 4985 + y: 66 + z: 5034 + pos2: + x: 5009 + y: 63 + z: 5002 \ No newline at end of file diff --git a/iceboat/maps/20.yml b/iceboat/maps/20.yml new file mode 100644 index 0000000..d8c40a4 --- /dev/null +++ b/iceboat/maps/20.yml @@ -0,0 +1,111 @@ +display: '烟雨行舟' +difficulty: '4.3' +material: SPRUCE_BOAT +creator: BreakGraze、ZuiLiu_aaaaab、iceflyingAND、Harry10124V、WWWMrNobody、KaMuMom +yaw: 90 +lap: 2 +point: 9 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4998 + y: 63 + z: 4993 + pos2: + x: 5017 + y: 67 + z: 5007 + glass: + pos1: + x: 4997 + y: 64 + z: 5006 + pos2: + x: 4997 + y: 64 + z: 4994 + 1: + pos1: + x: 4924 + y: 63 + z: 4990 + pos2: + x: 4974 + y: 67 + z: 4977 + 2: + pos1: + x: 4973 + y: 63 + z: 4900 + pos2: + x: 5022 + y: 67 + z: 4878 + 3: + pos1: + x: 5059 + y: 63 + z: 4932 + pos2: + x: 5099 + y: 67 + z: 4949 + 4: + pos1: + x: 5168 + y: 63 + z: 4970 + pos2: + x: 5129 + y: 67 + z: 4997 + 5: + pos1: + x: 5150 + y: 63 + z: 5022 + pos2: + x: 5129 + y: 67 + z: 5061 + 6: + pos1: + x: 5102 + y: 63 + z: 5033 + pos2: + x: 5080 + y: 67 + z: 5085 + 7: + pos1: + x: 5041 + y: 63 + z: 5098 + pos2: + x: 5029 + y: 67 + z: 5056 + 8: + pos1: + x: 4975 + y: 63 + z: 5040 + pos2: + x: 5022 + y: 67 + z: 5020 + 9: + pos1: + x: 4997 + y: 63 + z: 5007 + pos2: + x: 4950 + y: 67 + z: 4991 \ No newline at end of file diff --git a/iceboat/maps/21.yml b/iceboat/maps/21.yml new file mode 100644 index 0000000..816d098 --- /dev/null +++ b/iceboat/maps/21.yml @@ -0,0 +1,165 @@ +display: '甜点星球' +difficulty: '3.9' +material: CAKE +creator: BreakGraze、ZuiLiu_aaaaab、iceflyingAND、Harry10124V、WWWMrNobody、KaMuMom +yaw: -90 +lap: 1 +point: 15 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 5003 + y: 63 + z: 5010 + pos2: + x: 4955 + y: 67 + z: 4990 + glass: + pos1: + x: 5003 + y: 64 + z: 4991 + pos2: + x: 5003 + y: 64 + z: 5009 + 1: + pos1: + x: 5158 + y: 0 + z: 5000 + pos2: + x: 5114 + y: 255 + z: 5036 + 2: + pos1: + x: 5058 + y: 0 + z: 5054 + pos2: + x: 4997 + y: 255 + z: 5076 + 3: + pos1: + x: 4915 + y: 0 + z: 5064 + pos2: + x: 4892 + y: 255 + z: 5091 + 4: + pos1: + x: 4990 + y: 0 + z: 5122 + pos2: + x: 5029 + y: 255 + z: 5166 + 5: + pos1: + x: 5026 + y: 0 + z: 5349 + pos2: + x: 4999 + y: 255 + z: 5333 + 6: + pos1: + x: 4936 + y: 0 + z: 5351 + pos2: + x: 4966 + y: 255 + z: 5393 + 7: + pos1: + x: 5076 + y: 0 + z: 5427 + pos2: + x: 5116 + y: 255 + z: 5413 + 8: + pos1: + x: 5199 + y: 0 + z: 5393 + pos2: + x: 5243 + y: 255 + z: 5373 + 9: + pos1: + x: 5271 + y: 0 + z: 5313 + pos2: + x: 5243 + y: 255 + z: 5279 + 10: + pos1: + x: 5208 + y: 0 + z: 5211 + pos2: + x: 5230 + y: 255 + z: 5166 + 11: + pos1: + x: 5160 + y: 0 + z: 5157 + pos2: + x: 5133 + y: 255 + z: 5177 + 12: + pos1: + x: 5080 + y: 0 + z: 5190 + pos2: + x: 5110 + y: 255 + z: 5230 + 13: + pos1: + x: 5017 + y: 0 + z: 5233 + pos2: + x: 4979 + y: 255 + z: 5264 + 14: + pos1: + x: 4908 + y: 0 + z: 5220 + pos2: + x: 4851 + y: 255 + z: 5251 + 15: + pos1: + x: 4812 + y: 0 + z: 5150 + pos2: + x: 4824 + y: 255 + z: 5127 \ No newline at end of file diff --git a/iceboat/maps/22.yml b/iceboat/maps/22.yml new file mode 100644 index 0000000..96345ea --- /dev/null +++ b/iceboat/maps/22.yml @@ -0,0 +1,93 @@ +display: '滑稽游乐园' +difficulty: '3.5' +material: EGG +creator: BreakGraze、ZuiLiu_aaaaab、iceflyingAND、Harry10124V、WWWMrNobody、KaMuMom +yaw: 180 +lap: 2 +point: 7 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 5016 + y: 63 + z: 4999 + pos2: + x: 4971 + y: 67 + z: 5021 + glass: + pos1: + x: 4994 + y: 64 + z: 4998 + pos2: + x: 5007 + y: 64 + z: 4998 + 1: + pos1: + x: 5120 + y: 50 + z: 4941 + pos2: + x: 5131 + y: 70 + z: 4892 + 2: + pos1: + x: 5091 + y: 50 + z: 4961 + pos2: + x: 5113 + y: 70 + z: 5007 + 3: + pos1: + x: 5066 + y: 50 + z: 5108 + pos2: + x: 5049 + y: 70 + z: 5156 + 4: + pos1: + x: 5032 + y: 50 + z: 5148 + pos2: + x: 5004 + y: 70 + z: 5107 + 5: + pos1: + x: 4960 + y: 50 + z: 5102 + pos2: + x: 5004 + y: 70 + z: 5080 + 6: + pos1: + x: 4886 + y: 50 + z: 5064 + pos2: + x: 4931 + y: 70 + z: 5046 + 7: + pos1: + x: 4990 + y: 50 + z: 4998 + pos2: + x: 5032 + y: 70 + z: 4947 \ No newline at end of file diff --git a/iceboat/maps/23.yml b/iceboat/maps/23.yml new file mode 100644 index 0000000..3707e96 --- /dev/null +++ b/iceboat/maps/23.yml @@ -0,0 +1,147 @@ +display: '异世界之旅' +difficulty: '4.1' +material: ENDER_EYE +creator: BreakGraze、ZuiLiu_aaaaab、iceflyingAND、Harry10124V、WWWMrNobody、KaMuMom +yaw: 90 +lap: 1 +point: 13 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4998 + y: 63 + z: 5009 + pos2: + x: 5050 + y: 67 + z: 4991 + glass: + pos1: + x: 4997 + y: 64 + z: 5008 + pos2: + x: 4997 + y: 64 + z: 4992 + 1: + pos1: + x: 4812 + y: 0 + z: 5133 + pos2: + x: 4745 + y: 150 + z: 5225 + 2: + pos1: + x: 4715 + y: 0 + z: 5044 + pos2: + x: 4700 + y: 150 + z: 5107 + 3: + pos1: + x: 4723 + y: 0 + z: 4929 + pos2: + x: 4794 + y: 150 + z: 4952 + 4: + pos1: + x: 4885 + y: 0 + z: 4939 + pos2: + x: 4901 + y: 150 + z: 5028 + 5: + pos1: + x: 4892 + y: 0 + z: 5237 + pos2: + x: 4805 + y: 150 + z: 5259 + 6: + pos1: + x: 4795 + y: 0 + z: 5319 + pos2: + x: 4839 + y: 150 + z: 5284 + 7: + pos1: + x: 4912 + y: 0 + z: 5290 + pos2: + x: 4948 + y: 150 + z: 5254 + 8: + pos1: + x: 5053 + y: 0 + z: 5268 + pos2: + x: 5102 + y: 150 + z: 5225 + 9: + pos1: + x: 5078 + y: 0 + z: 5169 + pos2: + x: 5146 + y: 150 + z: 5131 + 10: + pos1: + x: 5101 + y: 0 + z: 5094 + pos2: + x: 5076 + y: 150 + z: 5109 + 11: + pos1: + x: 5175 + y: 0 + z: 5026 + pos2: + x: 5162 + y: 150 + z: 4965 + 12: + pos1: + x: 5130 + y: 0 + z: 4962 + pos2: + x: 5111 + y: 150 + z: 4930 + 13: + pos1: + x: 4997 + y: 0 + z: 5010 + pos2: + x: 4933 + y: 150 + z: 4982 \ No newline at end of file diff --git a/iceboat/maps/24.yml b/iceboat/maps/24.yml new file mode 100644 index 0000000..f4d9dc7 --- /dev/null +++ b/iceboat/maps/24.yml @@ -0,0 +1,147 @@ +display: '极地兵工厂' +difficulty: '3.5' +material: NETHERITE_BLOCK +creator: BreakGraze、ZuiLiu_aaaaab、iceflyingAND、Harry10124V、WWWMrNobody、KaMuMom +yaw: -90 +lap: 1 +point: 13 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 5003 + y: 63 + z: 4990 + pos2: + x: 4965 + y: 67 + z: 5012 + glass: + pos1: + x: 5003 + y: 64 + z: 4991 + pos2: + x: 5003 + y: 64 + z: 5011 + 1: + pos1: + x: 5122 + y: 0 + z: 5026 + pos2: + x: 5152 + y: 200 + z: 5082 + 2: + pos1: + x: 5196 + y: 0 + z: 5043 + pos2: + x: 5221 + y: 200 + z: 5119 + 3: + pos1: + x: 5271 + y: 0 + z: 5083 + pos2: + x: 5291 + y: 200 + z: 5144 + 4: + pos1: + x: 5201 + y: 0 + z: 5186 + pos2: + x: 5222 + y: 200 + z: 5241 + 5: + pos1: + x: 5181 + y: 0 + z: 5291 + pos2: + x: 5246 + y: 200 + z: 5340 + 6: + pos1: + x: 5220 + y: 0 + z: 5418 + pos2: + x: 5205 + y: 200 + z: 5448 + 7: + pos1: + x: 5171 + y: 0 + z: 5448 + pos2: + x: 5121 + y: 200 + z: 5385 + 8: + pos1: + x: 5047 + y: 0 + z: 5331 + pos2: + x: 4994 + y: 200 + z: 5315 + 9: + pos1: + x: 4912 + y: 0 + z: 5292 + pos2: + x: 5004 + y: 200 + z: 5253 + 10: + pos1: + x: 5001 + y: 0 + z: 5136 + pos2: + x: 4973 + y: 200 + z: 5073 + 11: + pos1: + x: 4924 + y: 0 + z: 5068 + pos2: + x: 4961 + y: 200 + z: 5119 + 12: + pos1: + x: 4873 + y: 0 + z: 5141 + pos2: + x: 4847 + y: 200 + z: 5117 + 13: + pos1: + x: 5003 + y: 0 + z: 4990 + pos2: + x: 5081 + y: 200 + z: 5012 \ No newline at end of file diff --git a/iceboat/maps/25.yml b/iceboat/maps/25.yml new file mode 100644 index 0000000..9429553 --- /dev/null +++ b/iceboat/maps/25.yml @@ -0,0 +1,102 @@ +display: '反向高速公路' +difficulty: '3.4' +material: POLISHED_GRANITE_SLAB +creator: DreamCityToger、_xuxu_ +yaw: 90 +lap: 2 +point: 8 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4998 + y: 63 + z: 4993 + pos2: + x: 5021 + y: 67 + z: 5007 + glass: + pos1: + x: 4997 + y: 64 + z: 5005 + pos2: + x: 4997 + y: 64 + z: 4994 + 1: + pos1: + x: 4799 + y: 0 + z: 5028 + pos2: + x: 4776 + y: 200 + z: 5084 + 2: + pos1: + x: 4835 + y: 0 + z: 5107 + pos2: + x: 4818 + y: 200 + z: 5136 + 3: + pos1: + x: 4847 + y: 0 + z: 5136 + pos2: + x: 4888 + y: 200 + z: 5108 + 4: + pos1: + x: 4908 + y: 0 + z: 5179 + pos2: + x: 4953 + y: 200 + z: 5192 + 5: + pos1: + x: 5014 + y: 0 + z: 5189 + pos2: + x: 5029 + y: 200 + z: 5161 + 6: + pos1: + x: 5030 + y: 0 + z: 5125 + pos2: + x: 5061 + y: 200 + z: 5144 + 7: + pos1: + x: 5050 + y: 0 + z: 5096 + pos2: + x: 5034 + y: 200 + z: 5070 + 8: + pos1: + x: 4997 + y: 0 + z: 5007 + pos2: + x: 4953 + y: 200 + z: 4991 \ No newline at end of file diff --git a/iceboat/maps/26.yml b/iceboat/maps/26.yml new file mode 100644 index 0000000..8831727 --- /dev/null +++ b/iceboat/maps/26.yml @@ -0,0 +1,93 @@ +display: '环山森岭高速' +difficulty: '3.7' +material: OAK_LEAVES +creator: ZuiLiu_aaaaab +yaw: 0 +lap: 3 +point: 7 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4990 + y: 63 + z: 5003 + pos2: + x: 5012 + y: 67 + z: 4977 + glass: + pos1: + x: 5011 + y: 64 + z: 5003 + pos2: + x: 4991 + y: 64 + z: 5003 + 1: + pos1: + x: 5062 + y: 63 + z: 5173 + pos2: + x: 5115 + y: 67 + z: 5252 + 2: + pos1: + x: 5147 + y: 0 + z: 5305 + pos2: + x: 5171 + y: 200 + z: 5330 + 3: + pos1: + x: 5240 + y: 0 + z: 5236 + pos2: + x: 5292 + y: 200 + z: 5180 + 4: + pos1: + x: 5322 + y: 0 + z: 5178 + pos2: + x: 5364 + y: 200 + z: 5146 + 5: + pos1: + x: 5405 + y: 0 + z: 5132 + pos2: + x: 5365 + y: 200 + z: 5102 + 6: + pos1: + x: 5251 + y: 0 + z: 4960 + pos2: + x: 5215 + y: 200 + z: 4926 + 7: + pos1: + x: 4989 + y: 0 + z: 5003 + pos2: + x: 5029 + y: 200 + z: 5093 \ No newline at end of file diff --git a/iceboat/maps/27.yml b/iceboat/maps/27.yml new file mode 100644 index 0000000..4a2afe5 --- /dev/null +++ b/iceboat/maps/27.yml @@ -0,0 +1,102 @@ +display: '宇宙城科技区' +difficulty: '3.9' +material: SLIME_BALL +creator: DreamCityToger、BreakGraze、ZuiLiu_aaaaab +yaw: 90 +lap: 2 +point: 8 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4998 + y: 63 + z: 5007 + pos2: + x: 5005 + y: 67 + z: 4992 + glass: + pos1: + x: 4997 + y: 64 + z: 4993 + pos2: + x: 4997 + y: 64 + z: 5006 + 1: + pos1: + x: 4935 + y: 63 + z: 5056 + pos2: + x: 4861 + y: 68 + z: 5025 + 2: + pos1: + x: 4963 + y: 65 + z: 5027 + pos2: + x: 4956 + y: 80 + z: 4992 + 3: + pos1: + x: 4964 + y: 67 + z: 4991 + pos2: + x: 4975 + y: 80 + z: 5014 + 4: + pos1: + x: 4996 + y: 0 + z: 5036 + pos2: + x: 5031 + y: 200 + z: 5026 + 5: + pos1: + x: 5033 + y: 0 + z: 5038 + pos2: + x: 5021 + y: 200 + z: 5049 + 6: + pos1: + x: 4992 + y: 0 + z: 5055 + pos2: + x: 4976 + y: 64 + z: 5031 + 7: + pos1: + x: 4994 + y: 0 + z: 4992 + pos2: + x: 5041 + y: 200 + z: 4941 + 8: + pos1: + x: 4997 + y: 0 + z: 4992 + pos2: + x: 4971 + y: 200 + z: 5007 \ No newline at end of file diff --git a/iceboat/maps/28.yml b/iceboat/maps/28.yml new file mode 100644 index 0000000..a792d34 --- /dev/null +++ b/iceboat/maps/28.yml @@ -0,0 +1,120 @@ +display: '层级教学关卡' +difficulty: '3.6' +material: SPONGE +creator: ZuiLiu_aaaaab +yaw: 90 +lap: 2 +point: 10 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4998 + y: 63 + z: 4994 + pos2: + x: 5021 + y: 67 + z: 5005 + glass: + pos1: + x: 4997 + y: 64 + z: 4995 + pos2: + x: 4997 + y: 64 + z: 5004 + 1: + pos1: + x: 4903 + y: 63 + z: 5025 + pos2: + x: 4892 + y: 67 + z: 5070 + 2: + pos1: + x: 4892 + y: 0 + z: 5128 + pos2: + x: 4902 + y: 200 + z: 5163 + 3: + pos1: + x: 4903 + y: 0 + z: 5179 + pos2: + x: 4931 + y: 200 + z: 5190 + 4: + pos1: + x: 4963 + y: 0 + z: 5150 + pos2: + x: 4991 + y: 200 + z: 5139 + 5: + pos1: + x: 5011 + y: 0 + z: 5173 + pos2: + x: 5022 + y: 200 + z: 5200 + 6: + pos1: + x: 5066 + y: 0 + z: 5193 + pos2: + x: 5055 + y: 200 + z: 5168 + 7: + pos1: + x: 5056 + y: 0 + z: 5144 + pos2: + x: 5076 + y: 200 + z: 5132 + 8: + pos1: + x: 5101 + y: 0 + z: 5155 + pos2: + x: 5112 + y: 200 + z: 5137 + 9: + pos1: + x: 5140 + y: 0 + z: 5126 + pos2: + x: 5129 + y: 200 + z: 5093 + 10: + pos1: + x: 4997 + y: 0 + z: 4994 + pos2: + x: 4927 + y: 200 + z: 5005 \ No newline at end of file diff --git a/iceboat/maps/29.yml b/iceboat/maps/29.yml new file mode 100644 index 0000000..f0ab8d3 --- /dev/null +++ b/iceboat/maps/29.yml @@ -0,0 +1,201 @@ +display: '炼狱祭坛' +difficulty: '5.4' +material: BLAZE_POWDER +creator: ZuiLiu_aaaaab、DreamCityToger +yaw: -90 +lap: 1 +point: 19 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 5003 + y: 63 + z: 5012 + pos2: + x: 4990 + y: 67 + z: 4991 + glass: + pos1: + x: 5003 + y: 64 + z: 4992 + pos2: + x: 5003 + y: 64 + z: 5010 + 1: + pos1: + x: 5179 + y: 0 + z: 5011 + pos2: + x: 5224 + y: 255 + z: 5026 + 2: + pos1: + x: 5231 + y: 0 + z: 5025 + pos2: + x: 5280 + y: 255 + z: 5047 + 3: + pos1: + x: 5402 + y: 0 + z: 4997 + pos2: + x: 5348 + y: 255 + z: 5024 + 4: + pos1: + x: 5359 + y: 0 + z: 5027 + pos2: + x: 5399 + y: 255 + z: 5063 + 5: + pos1: + x: 5474 + y: 0 + z: 5033 + pos2: + x: 5519 + y: 255 + z: 5068 + 6: + pos1: + x: 5430 + y: 0 + z: 5130 + pos2: + x: 5471 + y: 255 + z: 5171 + 7: + pos1: + x: 5456 + y: 0 + z: 5193 + pos2: + x: 5510 + y: 255 + z: 5221 + 8: + pos1: + x: 5403 + y: 0 + z: 5255 + pos2: + x: 5348 + y: 255 + z: 5294 + 9: + pos1: + x: 5317 + y: 0 + z: 5309 + pos2: + x: 5372 + y: 255 + z: 5333 + 10: + pos1: + x: 5443 + y: 0 + z: 5363 + pos2: + x: 5404 + y: 255 + z: 5388 + 11: + pos1: + x: 5338 + y: 0 + z: 5382 + pos2: + x: 5297 + y: 255 + z: 5439 + 12: + pos1: + x: 5219 + y: 0 + z: 5482 + pos2: + x: 5188 + y: 255 + z: 5449 + 13: + pos1: + x: 5119 + y: 0 + z: 5428 + pos2: + x: 5074 + y: 255 + z: 5453 + 14: + pos1: + x: 5067 + y: 0 + z: 5382 + pos2: + x: 5120 + y: 255 + z: 5318 + 15: + pos1: + x: 5197 + y: 0 + z: 5294 + pos2: + x: 5069 + y: 255 + z: 5226 + 16: + pos1: + x: 5220 + y: 0 + z: 5232 + pos2: + x: 5068 + y: 255 + z: 5165 + 17: + pos1: + x: 5115 + y: 0 + z: 5138 + pos2: + x: 5239 + y: 255 + z: 5050 + 18: + pos1: + x: 5179 + y: 0 + z: 5040 + pos2: + x: 5122 + y: 255 + z: 5070 + 19: + pos1: + x: 5017 + y: 0 + z: 5174 + pos2: + x: 4997 + y: 255 + z: 5149 \ No newline at end of file diff --git a/iceboat/maps/2979.yml b/iceboat/maps/2979.yml new file mode 100644 index 0000000..bcef947 --- /dev/null +++ b/iceboat/maps/2979.yml @@ -0,0 +1,39 @@ +display: '驾校:反拉双键' +difficulty: '2.1' +material: PAPER +creator: DreamCityToger、NoodleDada +yaw: 180 +lap: 1 +point: 1 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4996 + y: 63 + z: 4998 + pos2: + x: 5004 + y: 67 + z: 5005 + glass: + pos1: + x: 4997 + y: 64 + z: 4997 + pos2: + x: 5003 + y: 64 + z: 4997 + 1: + pos1: + x: 4996 + y: 63 + z: 4936 + pos2: + x: 5004 + y: 67 + z: 4931 \ No newline at end of file diff --git a/iceboat/maps/2980.yml b/iceboat/maps/2980.yml new file mode 100644 index 0000000..49f6916 --- /dev/null +++ b/iceboat/maps/2980.yml @@ -0,0 +1,39 @@ +display: '驾校:拖漂' +difficulty: '2.0' +material: PAPER +creator: DreamCityToger、BreakGraze +yaw: 180 +lap: 1 +point: 1 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4996 + y: 63 + z: 4998 + pos2: + x: 5004 + y: 67 + z: 5005 + glass: + pos1: + x: 4997 + y: 64 + z: 4997 + pos2: + x: 5003 + y: 64 + z: 4997 + 1: + pos1: + x: 4990 + y: 63 + z: 4898 + pos2: + x: 4998 + y: 67 + z: 4893 \ No newline at end of file diff --git a/iceboat/maps/2981.yml b/iceboat/maps/2981.yml new file mode 100644 index 0000000..424a6c8 --- /dev/null +++ b/iceboat/maps/2981.yml @@ -0,0 +1,39 @@ +display: '驾校:单格冰' +difficulty: '1.9' +material: PAPER +creator: DreamCityToger +yaw: 180 +lap: 1 +point: 1 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4996 + y: 63 + z: 4998 + pos2: + x: 5004 + y: 67 + z: 5005 + glass: + pos1: + x: 4997 + y: 64 + z: 4997 + pos2: + x: 5003 + y: 64 + z: 4997 + 1: + pos1: + x: 4926 + y: 63 + z: 4958 + pos2: + x: 4921 + y: 67 + z: 4966 \ No newline at end of file diff --git a/iceboat/maps/2982.yml b/iceboat/maps/2982.yml new file mode 100644 index 0000000..0f46af1 --- /dev/null +++ b/iceboat/maps/2982.yml @@ -0,0 +1,39 @@ +display: '驾校:精确控制' +difficulty: '1.8' +material: PAPER +creator: DreamCityToger +yaw: 180 +lap: 1 +point: 1 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4996 + y: 63 + z: 4998 + pos2: + x: 5004 + y: 67 + z: 5005 + glass: + pos1: + x: 4997 + y: 64 + z: 4997 + pos2: + x: 5003 + y: 64 + z: 4997 + 1: + pos1: + x: 5023 + y: 63 + z: 4849 + pos2: + x: 5028 + y: 67 + z: 4841 \ No newline at end of file diff --git a/iceboat/maps/2983.yml b/iceboat/maps/2983.yml new file mode 100644 index 0000000..18e039e --- /dev/null +++ b/iceboat/maps/2983.yml @@ -0,0 +1,39 @@ +display: '驾校:路线选择' +difficulty: '1.7' +material: PAPER +creator: DreamCityToger +yaw: 180 +lap: 1 +point: 1 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4996 + y: 63 + z: 4998 + pos2: + x: 5004 + y: 67 + z: 5005 + glass: + pos1: + x: 4997 + y: 64 + z: 4997 + pos2: + x: 5003 + y: 64 + z: 4997 + 1: + pos1: + x: 5022 + y: 50 + z: 4953 + pos2: + x: 5028 + y: 67 + z: 4966 \ No newline at end of file diff --git a/iceboat/maps/2984.yml b/iceboat/maps/2984.yml new file mode 100644 index 0000000..209fb39 --- /dev/null +++ b/iceboat/maps/2984.yml @@ -0,0 +1,39 @@ +display: '驾校:对抗' +difficulty: '1.6' +material: PAPER +creator: DreamCityToger +yaw: 180 +lap: 1 +point: 1 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4996 + y: 63 + z: 4998 + pos2: + x: 5004 + y: 67 + z: 5005 + glass: + pos1: + x: 4997 + y: 64 + z: 4997 + pos2: + x: 5003 + y: 64 + z: 4997 + 1: + pos1: + x: 5028 + y: 63 + z: 4759 + pos2: + x: 5023 + y: 67 + z: 4767 \ No newline at end of file diff --git a/iceboat/maps/2985.yml b/iceboat/maps/2985.yml new file mode 100644 index 0000000..1f506e3 --- /dev/null +++ b/iceboat/maps/2985.yml @@ -0,0 +1,39 @@ +display: '驾校:空中控制' +difficulty: '1.5' +material: PAPER +creator: DreamCityToger +yaw: 180 +lap: 1 +point: 1 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 5004 + y: 63 + z: 4998 + pos2: + x: 4996 + y: 67 + z: 5002 + glass: + pos1: + x: 4997 + y: 64 + z: 4997 + pos2: + x: 5003 + y: 64 + z: 4997 + 1: + pos1: + x: 4995 + y: 26 + z: 4900 + pos2: + x: 4991 + y: 22 + z: 4904 \ No newline at end of file diff --git a/iceboat/maps/2986.yml b/iceboat/maps/2986.yml new file mode 100644 index 0000000..72b2dd4 --- /dev/null +++ b/iceboat/maps/2986.yml @@ -0,0 +1,39 @@ +display: '驾校:蓝冰' +difficulty: '1.4' +material: PAPER +creator: DreamCityToger +yaw: 180 +lap: 1 +point: 1 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4993 + y: 63 + z: 4998 + pos2: + x: 5007 + y: 67 + z: 5004 + glass: + pos1: + x: 4994 + y: 64 + z: 4997 + pos2: + x: 5006 + y: 64 + z: 4997 + 1: + pos1: + x: 5027 + y: 63 + z: 4919 + pos2: + x: 5041 + y: 67 + z: 4913 \ No newline at end of file diff --git a/iceboat/maps/2987.yml b/iceboat/maps/2987.yml new file mode 100644 index 0000000..bba9a84 --- /dev/null +++ b/iceboat/maps/2987.yml @@ -0,0 +1,39 @@ +display: '驾校:飞跃' +difficulty: '1.3' +material: PAPER +creator: DreamCityToger +yaw: 180 +lap: 1 +point: 1 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 5006 + y: 63 + z: 5003 + pos2: + x: 4994 + y: 67 + z: 4997 + glass: + pos1: + x: 5005 + y: 64 + z: 5003 + pos2: + x: 4995 + y: 64 + z: 5003 + 1: + pos1: + x: 5061 + y: 46 + z: 5028 + pos2: + x: 5065 + y: 55 + z: 5038 \ No newline at end of file diff --git a/iceboat/maps/2988.yml b/iceboat/maps/2988.yml new file mode 100644 index 0000000..0ca9ed7 --- /dev/null +++ b/iceboat/maps/2988.yml @@ -0,0 +1,39 @@ +display: '驾校:急停' +difficulty: '1.2' +material: PAPER +creator: DreamCityToger +yaw: 180 +lap: 1 +point: 1 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4996 + y: 63 + z: 4998 + pos2: + x: 5004 + y: 67 + z: 5005 + glass: + pos1: + x: 4997 + y: 64 + z: 4997 + pos2: + x: 5003 + y: 64 + z: 4997 + 1: + pos1: + x: 5004 + y: 63 + z: 4971 + pos2: + x: 5012 + y: 67 + z: 4966 \ No newline at end of file diff --git a/iceboat/maps/2989.yml b/iceboat/maps/2989.yml new file mode 100644 index 0000000..1255bf9 --- /dev/null +++ b/iceboat/maps/2989.yml @@ -0,0 +1,39 @@ +display: '驾校:假弯' +difficulty: '1.1' +material: PAPER +creator: DreamCityToger +yaw: 180 +lap: 1 +point: 1 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4996 + y: 63 + z: 4998 + pos2: + x: 5004 + y: 67 + z: 5005 + glass: + pos1: + x: 4997 + y: 64 + z: 4997 + pos2: + x: 5003 + y: 64 + z: 4997 + 1: + pos1: + x: 5103 + y: 63 + z: 4919 + pos2: + x: 5116 + y: 67 + z: 4913 \ No newline at end of file diff --git a/iceboat/maps/2990.yml b/iceboat/maps/2990.yml new file mode 100644 index 0000000..914547c --- /dev/null +++ b/iceboat/maps/2990.yml @@ -0,0 +1,39 @@ +display: '驾校:水流' +difficulty: '1.0' +material: PAPER +creator: DreamCityToger +yaw: 180 +lap: 1 +point: 1 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4996 + y: 63 + z: 4998 + pos2: + x: 5004 + y: 67 + z: 5005 + glass: + pos1: + x: 4997 + y: 64 + z: 4997 + pos2: + x: 5003 + y: 64 + z: 4997 + 1: + pos1: + x: 5008 + y: 63 + z: 4894 + pos2: + x: 5013 + y: 67 + z: 4886 \ No newline at end of file diff --git a/iceboat/maps/2991.yml b/iceboat/maps/2991.yml new file mode 100644 index 0000000..edd44d9 --- /dev/null +++ b/iceboat/maps/2991.yml @@ -0,0 +1,39 @@ +display: '驾校:赛车线' +difficulty: '0.9' +material: PAPER +creator: DreamCityToger +yaw: -90 +lap: 1 +point: 1 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 5003 + y: 63 + z: 4990 + pos2: + x: 4995 + y: 67 + z: 5010 + glass: + pos1: + x: 5003 + y: 64 + z: 4991 + pos2: + x: 5003 + y: 64 + z: 5009 + 1: + pos1: + x: 5034 + y: 63 + z: 4933 + pos2: + x: 5014 + y: 67 + z: 4939 \ No newline at end of file diff --git a/iceboat/maps/2992.yml b/iceboat/maps/2992.yml new file mode 100644 index 0000000..cb11c75 --- /dev/null +++ b/iceboat/maps/2992.yml @@ -0,0 +1,39 @@ +display: '驾校:空中速度' +difficulty: '0.8' +material: PAPER +creator: DreamCityToger +yaw: 180 +lap: 1 +point: 1 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4996 + y: 63 + z: 4998 + pos2: + x: 5004 + y: 67 + z: 5017 + glass: + pos1: + x: 4997 + y: 64 + z: 4997 + pos2: + x: 5003 + y: 64 + z: 4997 + 1: + pos1: + x: 4996 + y: 56 + z: 4954 + pos2: + x: 5004 + y: 67 + z: 4949 \ No newline at end of file diff --git a/iceboat/maps/2993.yml b/iceboat/maps/2993.yml new file mode 100644 index 0000000..1fad654 --- /dev/null +++ b/iceboat/maps/2993.yml @@ -0,0 +1,39 @@ +display: '驾校:方块互动' +difficulty: '0.6' +material: PAPER +creator: DreamCityToger +yaw: 180 +lap: 1 +point: 1 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4996 + y: 63 + z: 4998 + pos2: + x: 5004 + y: 67 + z: 5005 + glass: + pos1: + x: 4997 + y: 64 + z: 4997 + pos2: + x: 5003 + y: 64 + z: 4997 + 1: + pos1: + x: 4996 + y: 63 + z: 4936 + pos2: + x: 5004 + y: 67 + z: 4931 \ No newline at end of file diff --git a/iceboat/maps/2994.yml b/iceboat/maps/2994.yml new file mode 100644 index 0000000..ad320d4 --- /dev/null +++ b/iceboat/maps/2994.yml @@ -0,0 +1,48 @@ +display: '驾校:捷径' +difficulty: '0.7' +material: PAPER +creator: DreamCityToger +yaw: 180 +lap: 1 +point: 2 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4996 + y: 63 + z: 4998 + pos2: + x: 5004 + y: 67 + z: 5005 + glass: + pos1: + x: 4997 + y: 64 + z: 4997 + pos2: + x: 5003 + y: 64 + z: 4997 + 1: + pos1: + x: 4996 + y: 63 + z: 4973 + pos2: + x: 5012 + y: 67 + z: 4940 + 2: + pos1: + x: 5004 + y: 63 + z: 4996 + pos2: + x: 5012 + y: 67 + z: 5001 \ No newline at end of file diff --git a/iceboat/maps/2995.yml b/iceboat/maps/2995.yml new file mode 100644 index 0000000..25a0b76 --- /dev/null +++ b/iceboat/maps/2995.yml @@ -0,0 +1,39 @@ +display: '驾校:撞墙过弯' +difficulty: '0.5' +material: PAPER +creator: DreamCityToger +yaw: 180 +lap: 1 +point: 1 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4996 + y: 63 + z: 4998 + pos2: + x: 5004 + y: 67 + z: 5005 + glass: + pos1: + x: 4997 + y: 64 + z: 4997 + pos2: + x: 5003 + y: 64 + z: 4997 + 1: + pos1: + x: 5023 + y: 63 + z: 4932 + pos2: + x: 5028 + y: 67 + z: 4940 \ No newline at end of file diff --git a/iceboat/maps/2996.yml b/iceboat/maps/2996.yml new file mode 100644 index 0000000..e88f4ea --- /dev/null +++ b/iceboat/maps/2996.yml @@ -0,0 +1,39 @@ +display: '驾校:提前入弯' +difficulty: '0.4' +material: PAPER +creator: DreamCityToger +yaw: 180 +lap: 1 +point: 1 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4995 + y: 63 + z: 5005 + pos2: + x: 5005 + y: 67 + z: 4998 + glass: + pos1: + x: 4996 + y: 64 + z: 4997 + pos2: + x: 5004 + y: 64 + z: 4997 + 1: + pos1: + x: 5045 + y: 62 + z: 4996 + pos2: + x: 5037 + y: 67 + z: 5001 \ No newline at end of file diff --git a/iceboat/maps/2997.yml b/iceboat/maps/2997.yml new file mode 100644 index 0000000..75036b1 --- /dev/null +++ b/iceboat/maps/2997.yml @@ -0,0 +1,39 @@ +display: '驾校:左右转向' +difficulty: '0.3' +material: PAPER +creator: DreamCityToger +yaw: 180 +lap: 1 +point: 1 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4996 + y: 63 + z: 4998 + pos2: + x: 5004 + y: 67 + z: 5005 + glass: + pos1: + x: 4997 + y: 64 + z: 4997 + pos2: + x: 5003 + y: 64 + z: 4997 + 1: + pos1: + x: 5057 + y: 62 + z: 4973 + pos2: + x: 5065 + y: 67 + z: 4968 \ No newline at end of file diff --git a/iceboat/maps/2998.yml b/iceboat/maps/2998.yml new file mode 100644 index 0000000..afb4954 --- /dev/null +++ b/iceboat/maps/2998.yml @@ -0,0 +1,39 @@ +display: '驾校:方块速度' +difficulty: '0.2' +material: PAPER +creator: DreamCityToger +yaw: 180 +lap: 1 +point: 1 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4996 + y: 63 + z: 4998 + pos2: + x: 5004 + y: 67 + z: 5005 + glass: + pos1: + x: 4997 + y: 64 + z: 4997 + pos2: + x: 5003 + y: 64 + z: 4997 + 1: + pos1: + x: 4996 + y: 62 + z: 4936 + pos2: + x: 5004 + y: 67 + z: 4931 \ No newline at end of file diff --git a/iceboat/maps/2999.yml b/iceboat/maps/2999.yml new file mode 100644 index 0000000..7858b3f --- /dev/null +++ b/iceboat/maps/2999.yml @@ -0,0 +1,39 @@ +display: '驾校:直线行驶' +difficulty: '0.1' +material: PAPER +creator: DreamCityToger +yaw: 180 +lap: 1 +point: 1 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4996 + y: 63 + z: 4998 + pos2: + x: 5004 + y: 67 + z: 5005 + glass: + pos1: + x: 4997 + y: 64 + z: 4997 + pos2: + x: 5003 + y: 64 + z: 4997 + 1: + pos1: + x: 4996 + y: 63 + z: 4936 + pos2: + x: 5004 + y: 67 + z: 4931 \ No newline at end of file diff --git a/iceboat/maps/3.yml b/iceboat/maps/3.yml new file mode 100644 index 0000000..75d88e7 --- /dev/null +++ b/iceboat/maps/3.yml @@ -0,0 +1,84 @@ +display: '村镇矢口京' +difficulty: '4.2' +material: BROWN_BANNER +creator: "DreamCityToger" +yaw: 90 +lap: 3 +point: 6 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4998 + y: 63 + z: 5006 + pos2: + x: 5005 + y: 67 + z: 4993 + glass: + pos1: + x: 4997 + y: 64 + z: 5005 + pos2: + x: 4997 + y: 64 + z: 4994 + 1: + pos1: + x: 4931 + y: 62 + z: 5008 + pos2: + x: 4908 + y: 67 + z: 5036 + 2: + pos1: + x: 4931 + y: 64 + z: 5038 + pos2: + x: 4951 + y: 67 + z: 5050 + 3: + pos1: + x: 4925 + y: 64 + z: 5082 + pos2: + x: 4952 + y: 67 + z: 5093 + 4: + pos1: + x: 4992 + y: 68 + z: 5091 + pos2: + x: 4976 + y: 62 + z: 5068 + 5: + pos1: + x: 4965 + y: 64 + z: 5035 + pos2: + x: 5016 + y: 67 + z: 5019 + 6: + pos1: + x: 4997 + y: 63 + z: 5006 + pos2: + x: 4978 + y: 66 + z: 4993 \ No newline at end of file diff --git a/iceboat/maps/30.yml b/iceboat/maps/30.yml new file mode 100644 index 0000000..86db409 --- /dev/null +++ b/iceboat/maps/30.yml @@ -0,0 +1,84 @@ +display: '宇宙城启示录' +difficulty: '1.9' +material: TOTEM_OF_UNDYING +creator: DreamCityToger +yaw: 90 +lap: 3 +point: 6 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4998 + y: 63 + z: 5008 + pos2: + x: 5009 + y: 67 + z: 4993 + glass: + pos1: + x: 4997 + y: 64 + z: 5007 + pos2: + x: 4997 + y: 64 + z: 4994 + 1: + pos1: + x: 4821 + y: 63 + z: 4985 + pos2: + x: 4793 + y: 67 + z: 4962 + 2: + pos1: + x: 4749 + y: 63 + z: 4912 + pos2: + x: 4732 + y: 67 + z: 4918 + 3: + pos1: + x: 4793 + y: 63 + z: 4962 + pos2: + x: 4823 + y: 67 + z: 4986 + 4: + pos1: + x: 4909 + y: 63 + z: 5010 + pos2: + x: 4937 + y: 67 + z: 4991 + 5: + pos1: + x: 5033 + y: 63 + z: 4997 + pos2: + x: 5048 + y: 67 + z: 5004 + 6: + pos1: + x: 4997 + y: 63 + z: 5008 + pos2: + x: 4956 + y: 67 + z: 4991 \ No newline at end of file diff --git a/iceboat/maps/31.yml b/iceboat/maps/31.yml new file mode 100644 index 0000000..ee7181d --- /dev/null +++ b/iceboat/maps/31.yml @@ -0,0 +1,129 @@ +display: '极地破碎雪原' +difficulty: '5.4' +material: SNOWBALL +creator: DreamCityToger、wenzn、YingYingAD、ZuiLiu_aaaaab +yaw: 90 +lap: 2 +point: 11 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4998 + y: 63 + z: 5006 + pos2: + x: 5019 + y: 67 + z: 4978 + glass: + pos1: + x: 4997 + y: 64 + z: 4984 + pos2: + x: 4997 + y: 64 + z: 5005 + 1: + pos1: + x: 4902 + y: 30 + z: 4988 + pos2: + x: 4975 + y: 90 + z: 4938 + 2: + pos1: + x: 4927 + y: 30 + z: 4935 + pos2: + x: 4888 + y: 90 + z: 4905 + 3: + pos1: + x: 4831 + y: 30 + z: 4910 + pos2: + x: 4841 + y: 90 + z: 4920 + 4: + pos1: + x: 4898 + y: 64 + z: 4906 + pos2: + x: 4939 + y: 50 + z: 4865 + 5: + pos1: + x: 4996 + y: 30 + z: 4875 + pos2: + x: 5033 + y: 90 + z: 4896 + 6: + pos1: + x: 5036 + y: 30 + z: 4897 + pos2: + x: 5016 + y: 90 + z: 4913 + 7: + pos1: + x: 5104 + y: 30 + z: 4931 + pos2: + x: 5120 + y: 90 + z: 4952 + 8: + pos1: + x: 5139 + y: 30 + z: 4992 + pos2: + x: 5113 + y: 90 + z: 5023 + 9: + pos1: + x: 5061 + y: 30 + z: 4966 + pos2: + x: 5042 + y: 90 + z: 4996 + 10: + pos1: + x: 5043 + y: 30 + z: 5044 + pos2: + x: 5015 + y: 90 + z: 5011 + 11: + pos1: + x: 4997 + y: 63 + z: 4982 + pos2: + x: 4972 + y: 90 + z: 5007 \ No newline at end of file diff --git a/iceboat/maps/32.yml b/iceboat/maps/32.yml new file mode 100644 index 0000000..c3d4c8f --- /dev/null +++ b/iceboat/maps/32.yml @@ -0,0 +1,156 @@ +display: '特若柯特环' +difficulty: '2.6' +material: TERRACOTTA +creator: BreakGraze +yaw: 90 +lap: 2 +point: 14 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4998 + y: 63 + z: 4993 + pos2: + x: 5014 + y: 67 + z: 5007 + glass: + pos1: + x: 4997 + y: 64 + z: 5007 + pos2: + x: 4997 + y: 64 + z: 4993 + 1: + pos1: + x: 4880 + y: 63 + z: 5058 + pos2: + x: 4844 + y: 67 + z: 5022 + 2: + pos1: + x: 4800 + y: 63 + z: 4996 + pos2: + x: 4844 + y: 67 + z: 4957 + 3: + pos1: + x: 4870 + y: 63 + z: 4852 + pos2: + x: 4888 + y: 67 + z: 4806 + 4: + pos1: + x: 4853 + y: 63 + z: 4741 + pos2: + x: 4827 + y: 67 + z: 4780 + 5: + pos1: + x: 4794 + y: 63 + z: 4830 + pos2: + x: 4768 + y: 67 + z: 4780 + 6: + pos1: + x: 4747 + y: 63 + z: 4741 + pos2: + x: 4732 + y: 67 + z: 4784 + 7: + pos1: + x: 4732 + y: 63 + z: 4953 + pos2: + x: 4759 + y: 67 + z: 4992 + 8: + pos1: + x: 4719 + y: 63 + z: 5050 + pos2: + x: 4698 + y: 67 + z: 5021 + 9: + pos1: + x: 4650 + y: 63 + z: 5019 + pos2: + x: 4618 + y: 67 + z: 5059 + 10: + pos1: + x: 4662 + y: 63 + z: 5189 + pos2: + x: 4684 + y: 67 + z: 5203 + 11: + pos1: + x: 4795 + y: 63 + z: 5142 + pos2: + x: 4863 + y: 67 + z: 5125 + 12: + pos1: + x: 4963 + y: 63 + z: 5117 + pos2: + x: 5002 + y: 67 + z: 5102 + 13: + pos1: + x: 5099 + y: 63 + z: 5056 + pos2: + x: 5064 + y: 67 + z: 5015 + 14: + pos1: + x: 4997 + y: 63 + z: 4987 + pos2: + x: 4948 + y: 67 + z: 5008 \ No newline at end of file diff --git a/iceboat/maps/33.yml b/iceboat/maps/33.yml new file mode 100644 index 0000000..d7b151e --- /dev/null +++ b/iceboat/maps/33.yml @@ -0,0 +1,138 @@ +display: '海百合海底谭' +difficulty: '3.5' +material: TROPICAL_FISH +creator: ZuiLiu_aaaaab +yaw: -90 +lap: 1 +point: 12 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 5003 + y: 63 + z: 5009 + pos2: + x: 4971 + y: 69 + z: 4976 + glass: + pos1: + x: 5003 + y: 64 + z: 4993 + pos2: + x: 5003 + y: 64 + z: 5007 + 1: + pos1: + x: 5199 + y: 63 + z: 5010 + pos2: + x: 5314 + y: 67 + z: 4990 + 2: + pos1: + x: 5376 + y: 63 + z: 4989 + pos2: + x: 5343 + y: 67 + z: 4959 + 3: + pos1: + x: 5284 + y: 63 + z: 4905 + pos2: + x: 5247 + y: 67 + z: 4869 + 4: + pos1: + x: 5029 + y: 63 + z: 4822 + pos2: + x: 4980 + y: 67 + z: 4873 + 5: + pos1: + x: 4884 + y: 63 + z: 4874 + pos2: + x: 4835 + y: 67 + z: 4835 + 6: + pos1: + x: 4735 + y: 63 + z: 4773 + pos2: + x: 4759 + y: 67 + z: 4824 + 7: + pos1: + x: 4687 + y: 63 + z: 4896 + pos2: + x: 4633 + y: 67 + z: 4842 + 8: + pos1: + x: 4618 + y: 63 + z: 4744 + pos2: + x: 4568 + y: 67 + z: 4713 + 9: + pos1: + x: 4531 + y: 63 + z: 4833 + pos2: + x: 4594 + y: 67 + z: 4882 + 10: + pos1: + x: 4704 + y: 63 + z: 4974 + pos2: + x: 4734 + y: 67 + z: 4920 + 11: + pos1: + x: 4882 + y: 63 + z: 4970 + pos2: + x: 4826 + y: 67 + z: 4992 + 12: + pos1: + x: 5003 + y: 63 + z: 4976 + pos2: + x: 5060 + y: 67 + z: 5015 \ No newline at end of file diff --git a/iceboat/maps/34.yml b/iceboat/maps/34.yml new file mode 100644 index 0000000..7c2648b --- /dev/null +++ b/iceboat/maps/34.yml @@ -0,0 +1,111 @@ +display: '村镇良湖' +difficulty: '3.5' +material: AXOLOTL_BUCKET +creator: Nikilewis7508、ZuiLiu_aaaaab、MorainCarium +yaw: 90 +lap: 2 +point: 9 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4998 + y: 63 + z: 5016 + pos2: + x: 5022 + y: 67 + z: 4992 + glass: + pos1: + x: 4997 + y: 64 + z: 5007 + pos2: + x: 4997 + y: 64 + z: 4993 + 1: + pos1: + x: 4849 + y: 63 + z: 5008 + pos2: + x: 4811 + y: 67 + z: 5059 + 2: + pos1: + x: 4710 + y: 63 + z: 5113 + pos2: + x: 4743 + y: 67 + z: 5061 + 3: + pos1: + x: 4787 + y: 63 + z: 4986 + pos2: + x: 4816 + y: 67 + z: 4940 + 4: + pos1: + x: 4873 + y: 63 + z: 4940 + pos2: + x: 4897 + y: 67 + z: 4922 + 5: + pos1: + x: 5035 + y: 63 + z: 4888 + pos2: + x: 5067 + y: 67 + z: 4852 + 6: + pos1: + x: 5198 + y: 63 + z: 4873 + pos2: + x: 5162 + y: 67 + z: 4907 + 7: + pos1: + x: 5081 + y: 63 + z: 4914 + pos2: + x: 5112 + y: 67 + z: 4949 + 8: + pos1: + x: 5152 + y: 63 + z: 5039 + pos2: + x: 5121 + y: 67 + z: 5016 + 9: + pos1: + x: 4997 + y: 63 + z: 4992 + pos2: + x: 4968 + y: 67 + z: 5017 \ No newline at end of file diff --git a/iceboat/maps/35.yml b/iceboat/maps/35.yml new file mode 100644 index 0000000..709a658 --- /dev/null +++ b/iceboat/maps/35.yml @@ -0,0 +1,111 @@ +display: '村镇良枫' +difficulty: '3.0' +material: ACACIA_PLANKS +creator: Nikilewis7508、ZuiLiu_aaaaab、iceflyingADN +yaw: 90 +lap: 2 +point: 9 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4998 + y: 63 + z: 5009 + pos2: + x: 5040 + y: 67 + z: 4991 + glass: + pos1: + x: 4997 + y: 64 + z: 5007 + pos2: + x: 4997 + y: 64 + z: 4993 + 1: + pos1: + x: 4820 + y: 63 + z: 4969 + pos2: + x: 4853 + y: 67 + z: 4939 + 2: + pos1: + x: 4901 + y: 63 + z: 4929 + pos2: + x: 4869 + y: 67 + z: 4878 + 3: + pos1: + x: 4930 + y: 63 + z: 4810 + pos2: + x: 4953 + y: 67 + z: 4835 + 4: + pos1: + x: 4982 + y: 63 + z: 4865 + pos2: + x: 4959 + y: 67 + z: 4900 + 5: + pos1: + x: 4921 + y: 63 + z: 4909 + pos2: + x: 4952 + y: 67 + z: 4937 + 6: + pos1: + x: 5038 + y: 63 + z: 4906 + pos2: + x: 5076 + y: 67 + z: 4875 + 7: + pos1: + x: 5213 + y: 63 + z: 4885 + pos2: + x: 5167 + y: 67 + z: 4939 + 8: + pos1: + x: 5162 + y: 63 + z: 4963 + pos2: + x: 5111 + y: 67 + z: 4983 + 9: + pos1: + x: 4997 + y: 63 + z: 5012 + pos2: + x: 4942 + y: 67 + z: 4973 \ No newline at end of file diff --git a/iceboat/maps/36.yml b/iceboat/maps/36.yml new file mode 100644 index 0000000..f2c90bd --- /dev/null +++ b/iceboat/maps/36.yml @@ -0,0 +1,84 @@ +display: '忠菊之城' +difficulty: '2.7' +material: OXEYE_DAISY +creator: ZuiLiu_aaaaab +yaw: 180 +lap: 3 +point: 6 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4994 + y: 63 + z: 4998 + pos2: + x: 5007 + y: 67 + z: 5024 + glass: + pos1: + x: 5006 + y: 64 + z: 4997 + pos2: + x: 4995 + y: 64 + z: 4997 + 1: + pos1: + x: 5046 + y: 63 + z: 4899 + pos2: + x: 5095 + y: 67 + z: 4913 + 2: + pos1: + x: 5160 + y: 63 + z: 4925 + pos2: + x: 5145 + y: 67 + z: 4949 + 3: + pos1: + x: 5112 + y: 63 + z: 4963 + pos2: + x: 5089 + y: 67 + z: 4939 + 4: + pos1: + x: 5027 + y: 63 + z: 4969 + pos2: + x: 5048 + y: 67 + z: 5001 + 5: + pos1: + x: 5103 + y: 63 + z: 5047 + pos2: + x: 5079 + y: 67 + z: 5030 + 6: + pos1: + x: 4994 + y: 63 + z: 4997 + pos2: + x: 5007 + y: 67 + z: 4958 \ No newline at end of file diff --git a/iceboat/maps/37.yml b/iceboat/maps/37.yml new file mode 100644 index 0000000..6ecab48 --- /dev/null +++ b/iceboat/maps/37.yml @@ -0,0 +1,102 @@ +display: '极地雪堡' +difficulty: '1.0' +material: SNOW_BLOCK +creator: ZuiLiu_aaaaab +yaw: -90 +lap: 1 +point: 8 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 5003 + y: 63 + z: 4994 + pos2: + x: 4967 + y: 67 + z: 5007 + glass: + pos1: + x: 5003 + y: 64 + z: 4995 + pos2: + x: 5003 + y: 64 + z: 5006 + 1: + pos1: + x: 5205 + y: 63 + z: 4992 + pos2: + x: 5294 + y: 67 + z: 5026 + 2: + pos1: + x: 5357 + y: 63 + z: 5127 + pos2: + x: 5328 + y: 67 + z: 5191 + 3: + pos1: + x: 5193 + y: 63 + z: 5282 + pos2: + x: 5117 + y: 67 + z: 5264 + 4: + pos1: + x: 5050 + y: 63 + z: 5282 + pos2: + x: 4959 + y: 67 + z: 5269 + 5: + pos1: + x: 4856 + y: 63 + z: 5283 + pos2: + x: 4790 + y: 67 + z: 5250 + 6: + pos1: + x: 4691 + y: 63 + z: 5148 + pos2: + x: 4721 + y: 67 + z: 5087 + 7: + pos1: + x: 4824 + y: 63 + z: 5011 + pos2: + x: 4893 + y: 67 + z: 4986 + 8: + pos1: + x: 5003 + y: 63 + z: 4994 + pos2: + x: 5062 + y: 67 + z: 5007 \ No newline at end of file diff --git a/iceboat/maps/38.yml b/iceboat/maps/38.yml new file mode 100644 index 0000000..aad7a48 --- /dev/null +++ b/iceboat/maps/38.yml @@ -0,0 +1,129 @@ +display: '宇宙城监狱岛' +difficulty: '4.2' +material: IRON_BARS +creator: DreamCityToger、WatercleanRZSQ、Chen_peipei +yaw: -90 +lap: 2 +point: 11 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 5003 + y: 63 + z: 4991 + pos2: + x: 4973 + y: 67 + z: 5024 + glass: + pos1: + x: 5003 + y: 64 + z: 5010 + pos2: + x: 5003 + y: 64 + z: 4992 + 1: + pos1: + x: 5173 + y: 63 + z: 4984 + pos2: + x: 5259 + y: 67 + z: 4902 + 2: + pos1: + x: 5298 + y: 63 + z: 4833 + pos2: + x: 5264 + y: 67 + z: 4785 + 3: + pos1: + x: 5376 + y: 63 + z: 4804 + pos2: + x: 5410 + y: 90 + z: 4788 + 4: + pos1: + x: 5477 + y: 63 + z: 4855 + pos2: + x: 5436 + y: 90 + z: 4907 + 5: + pos1: + x: 5327 + y: 63 + z: 4949 + pos2: + x: 5257 + y: 90 + z: 4890 + 6: + pos1: + x: 5249 + y: 63 + z: 4844 + pos2: + x: 5201 + y: 90 + z: 4751 + 7: + pos1: + x: 5111 + y: 63 + z: 4835 + pos2: + x: 5168 + y: 90 + z: 4892 + 8: + pos1: + x: 5230 + y: 63 + z: 5022 + pos2: + x: 5140 + y: 90 + z: 5067 + 9: + pos1: + x: 5073 + y: 63 + z: 5030 + pos2: + x: 5034 + y: 90 + z: 5080 + 10: + pos1: + x: 5028 + y: 63 + z: 5120 + pos2: + x: 4996 + y: 90 + z: 5063 + 11: + pos1: + x: 5003 + y: 63 + z: 5011 + pos2: + x: 5079 + y: 90 + z: 4988 \ No newline at end of file diff --git a/iceboat/maps/39.yml b/iceboat/maps/39.yml new file mode 100644 index 0000000..70c208b --- /dev/null +++ b/iceboat/maps/39.yml @@ -0,0 +1,210 @@ +display: '箱根归路' +difficulty: '4.5' +material: BAMBOO_HANGING_SIGN +creator: DreamCityToger、_William0v0_、WatercleanRZSQ +yaw: 0 +lap: 1 +point: 20 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4992 + y: 63 + z: 5003 + pos2: + x: 5007 + y: 67 + z: 4980 + glass: + pos1: + x: 5006 + y: 64 + z: 5003 + pos2: + x: 4993 + y: 64 + z: 5003 + 1: + pos1: + x: 4916 + y: 63 + z: 5153 + pos2: + x: 4996 + y: 67 + z: 5258 + 2: + pos1: + x: 5081 + y: 63 + z: 5326 + pos2: + x: 5042 + y: 67 + z: 5468 + 3: + pos1: + x: 5076 + y: 63 + z: 5556 + pos2: + x: 5221 + y: 67 + z: 5593 + 4: + pos1: + x: 5080 + y: 63 + z: 5670 + pos2: + x: 5060 + y: 67 + z: 5756 + 5: + pos1: + x: 4798 + y: 63 + z: 5989 + pos2: + x: 4832 + y: 67 + z: 6042 + 6: + pos1: + x: 4725 + y: 63 + z: 6149 + pos2: + x: 4797 + y: 67 + z: 6212 + 7: + pos1: + x: 4882 + y: 63 + z: 6369 + pos2: + x: 4962 + y: 67 + z: 6452 + 8: + pos1: + x: 4951 + y: 63 + z: 6490 + pos2: + x: 4897 + y: 67 + z: 6568 + 9: + pos1: + x: 4826 + y: 63 + z: 6689 + pos2: + x: 4739 + y: 67 + z: 6645 + 10: + pos1: + x: 4667 + y: 63 + z: 6779 + pos2: + x: 4615 + y: 67 + z: 6733 + 11: + pos1: + x: 4443 + y: 63 + z: 6861 + pos2: + x: 4486 + y: 67 + z: 6918 + 12: + pos1: + x: 4422 + y: 63 + z: 7005 + pos2: + x: 4474 + y: 67 + z: 7067 + 13: + pos1: + x: 4456 + y: 63 + z: 7113 + pos2: + x: 4404 + y: 67 + z: 7152 + 14: + pos1: + x: 4436 + y: 63 + z: 7277 + pos2: + x: 4381 + y: 67 + z: 7356 + 15: + pos1: + x: 4441 + y: 63 + z: 7483 + pos2: + x: 4477 + y: 67 + z: 7560 + 16: + pos1: + x: 4533 + y: 63 + z: 7663 + pos2: + x: 4491 + y: 67 + z: 7698 + 17: + pos1: + x: 4379 + y: 63 + z: 7763 + pos2: + x: 4319 + y: 67 + z: 7704 + 18: + pos1: + x: 4239 + y: 63 + z: 7747 + pos2: + x: 4192 + y: 67 + z: 7711 + 19: + pos1: + x: 4103 + y: 63 + z: 7746 + pos2: + x: 4063 + y: 67 + z: 7722 + 20: + pos1: + x: 4022 + y: 63 + z: 7861 + pos2: + x: 3998 + y: 67 + z: 7880 \ No newline at end of file diff --git a/iceboat/maps/4.yml b/iceboat/maps/4.yml new file mode 100644 index 0000000..6537bbb --- /dev/null +++ b/iceboat/maps/4.yml @@ -0,0 +1,210 @@ +display: '极地冰封王座' +difficulty: '4.8' +material: DARK_PRISMARINE_STAIRS +creator: "DreamCityToger" +yaw: 90 +lap: 1 +point: 20 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4998 + y: 63 + z: 5017 + pos2: + x: 5010 + y: 67 + z: 4984 + glass: + pos1: + x: 4997 + y: 67 + z: 4985 + pos2: + x: 4997 + y: 64 + z: 5014 + 1: + pos1: + x: 4876 + y: 63 + z: 5055 + pos2: + x: 4932 + y: 66 + z: 5125 + 2: + pos1: + x: 4910 + y: 63 + z: 5146 + pos2: + x: 4882 + y: 67 + z: 5168 + 3: + pos1: + x: 4920 + y: 63 + z: 5169 + pos2: + x: 4958 + y: 67 + z: 5183 + 4: + pos1: + x: 5036 + y: 63 + z: 5168 + pos2: + x: 5083 + y: 68 + z: 5205 + 5: + pos1: + x: 5066 + y: 63 + z: 5118 + pos2: + x: 5102 + y: 68 + z: 5140 + 6: + pos1: + x: 5111 + y: 63 + z: 5127 + pos2: + x: 5172 + y: 67 + z: 5142 + 7: + pos1: + x: 5182 + y: 63 + z: 5037 + pos2: + x: 5219 + y: 67 + z: 5101 + 8: + pos1: + x: 5252 + y: 63 + z: 5114 + pos2: + x: 5267 + y: 67 + z: 5192 + 9: + pos1: + x: 5244 + y: 63 + z: 5209 + pos2: + x: 5219 + y: 67 + z: 5184 + 10: + pos1: + x: 5145 + y: 63 + z: 5237 + pos2: + x: 5120 + y: 67 + z: 5300 + 11: + pos1: + x: 5110 + y: 60 + z: 5335 + pos2: + x: 5051 + y: 70 + z: 5296 + 12: + pos1: + x: 5022 + y: 60 + z: 5302 + pos2: + x: 4990 + y: 70 + z: 5225 + 13: + pos1: + x: 4992 + y: 63 + z: 5160 + pos2: + x: 4981 + y: 75 + z: 5111 + 14: + pos1: + x: 4955 + y: 63 + z: 5096 + pos2: + x: 4941 + y: 67 + z: 5055 + 15: + pos1: + x: 5000 + y: 63 + z: 5069 + pos2: + x: 5042 + y: 67 + z: 5085 + 16: + pos1: + x: 5070 + y: 63 + z: 5044 + pos2: + x: 5098 + y: 67 + z: 5065 + 17: + pos1: + x: 5103 + y: 62 + z: 5036 + pos2: + x: 5137 + y: 67 + z: 5009 + 18: + pos1: + x: 5168 + y: 62 + z: 4983 + pos2: + x: 5124 + y: 67 + z: 4951 + 19: + pos1: + x: 5095 + y: 62 + z: 4989 + pos2: + x: 5053 + y: 67 + z: 5019 + 20: + pos1: + x: 4998 + y: 64 + z: 4984 + pos2: + x: 4855 + y: 67 + z: 5028 \ No newline at end of file diff --git a/iceboat/maps/5.yml b/iceboat/maps/5.yml new file mode 100644 index 0000000..7853e1c --- /dev/null +++ b/iceboat/maps/5.yml @@ -0,0 +1,255 @@ +display: '秋名山' +difficulty: '2.6' +material: YELLOW_CONCRETE +creator: "DreamCityToger、ka_fei_coffee、Yeer_" +yaw: -135 +lap: 1 +point: 25 +points: + join: + x: 5000 + y: 140 + z: 5000 + ready: + pos1: + x: 5008 + y: 139 + z: 4993 + pos2: + x: 4983 + y: 145 + z: 5013 + glass: + pos1: + x: 5007 + y: 139 + z: 5002 + pos2: + x: 4999 + y: 145 + z: 4994 + 1: + pos1: + x: 5104 + y: 135 + z: 4951 + pos2: + x: 5083 + y: 129 + z: 4973 + 2: + pos1: + x: 5021 + y: 140 + z: 5022 + pos2: + x: 5066 + y: 120 + z: 5058 + 3: + pos1: + x: 5075 + y: 124 + z: 5067 + pos2: + x: 5089 + y: 118 + z: 5039 + 4: + pos1: + x: 5079 + y: 121 + z: 5024 + pos2: + x: 5119 + y: 116 + z: 5050 + 5: + pos1: + x: 5129 + y: 118 + z: 5056 + pos2: + x: 5165 + y: 112 + z: 5010 + 6: + pos1: + x: 5165 + y: 113 + z: 5015 + pos2: + x: 5181 + y: 109 + z: 5062 + 7: + pos1: + x: 5104 + y: 104 + z: 5137 + pos2: + x: 5054 + y: 98 + z: 5109 + 8: + pos1: + x: 5058 + y: 99 + z: 5129 + pos2: + x: 5103 + y: 96 + z: 5160 + 9: + pos1: + x: 5113 + y: 98 + z: 5178 + pos2: + x: 5090 + y: 92 + z: 5223 + 10: + pos1: + x: 5093 + y: 92 + z: 5281 + pos2: + x: 5125 + y: 88 + z: 5242 + 11: + pos1: + x: 5131 + y: 90 + z: 5250 + pos2: + x: 5154 + y: 82 + z: 5286 + 12: + pos1: + x: 5174 + y: 83 + z: 5301 + pos2: + x: 5204 + y: 77 + z: 5257 + 13: + pos1: + x: 5208 + y: 77 + z: 5249 + pos2: + x: 5220 + y: 72 + z: 5291 + 14: + pos1: + x: 5262 + y: 71 + z: 5334 + pos2: + x: 5282 + y: 62 + z: 5303 + 15: + pos1: + x: 5325 + y: 69 + z: 5246 + pos2: + x: 5358 + y: 61 + z: 5212 + 16: + pos1: + x: 5368 + y: 62 + z: 5225 + pos2: + x: 5381 + y: 57 + z: 5271 + 17: + pos1: + x: 5384 + y: 58 + z: 5272 + pos2: + x: 5405 + y: 53 + z: 5205 + 18: + pos1: + x: 5408 + y: 54 + z: 5206 + pos2: + x: 5467 + y: 48 + z: 5231 + 19: + pos1: + x: 5449 + y: 50 + z: 5242 + pos2: + x: 5470 + y: 44 + z: 5306 + 20: + pos1: + x: 5393 + y: 46 + z: 5363 + pos2: + x: 5347 + y: 39 + z: 5379 + 21: + pos1: + x: 5361 + y: 40 + z: 5393 + pos2: + x: 5433 + y: 34 + z: 5353 + 22: + pos1: + x: 5516 + y: 35 + z: 5381 + pos2: + x: 5488 + y: 30 + z: 5365 + 23: + pos1: + x: 5463 + y: 32 + z: 5374 + pos2: + x: 5435 + y: 24 + z: 5416 + 24: + pos1: + x: 5475 + y: 20 + z: 5469 + pos2: + x: 5523 + y: 16 + z: 5448 + 25: + pos1: + x: 5613 + y: 12 + z: 5437 + pos2: + x: 5637 + y: 18 + z: 5427 \ No newline at end of file diff --git a/iceboat/maps/6.yml b/iceboat/maps/6.yml new file mode 100644 index 0000000..92cdced --- /dev/null +++ b/iceboat/maps/6.yml @@ -0,0 +1,94 @@ +display: '宇宙城国际赛道' +difficulty: '2.9' +material: IRON_INGOT +creator: "DreamCityToger、BreakGraze、ZuiLiu_aaaaab、WatercleanRZSQ" +yaw: -90 +lap: 2 +point: 7 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4967 + y: 63 + z: 4992 + pos2: + x: 5003 + y: 67 + z: 5008 + glass: + pos1: + x: 5003 + y: 64 + z: 5008 + pos2: + x: 5003 + y: 64 + z: 4992 + 1: + pos1: + x: 5064 + y: 63 + z: 5010 + pos2: + x: 5138 + y: 67 + z: 4982 + 2: + pos1: + x: 5112 + y: 63 + z: 4955 + pos2: + x: 5056 + y: 67 + z: 4945 + 3: + pos1: + x: 5110 + y: 63 + z: 4833 + pos2: + x: 5090 + y: 67 + z: 4890 + 4: + pos1: + x: 5143 + y: 63 + z: 4837 + pos2: + x: 5117 + y: 67 + z: 4818 + 5: + pos1: + x: 5067 + y: 63 + z: 4800 + pos2: + x: 5050 + y: 67 + z: 4824 + 6: + pos1: + x: 4979 + y: 63 + z: 4977 + pos2: + x: 4948 + y: 67 + z: 5010 + 7: + pos1: + x: 5003 + y: 63 + z: 4992 + pos2: + x: 5017 + y: 67 + z: 5027 + diff --git a/iceboat/maps/7.yml b/iceboat/maps/7.yml new file mode 100644 index 0000000..a13a526 --- /dev/null +++ b/iceboat/maps/7.yml @@ -0,0 +1,111 @@ +display: '极地手指' +difficulty: '3.1' +material: LIGHT_BLUE_DYE +creator: "DreamCityToger" +yaw: 90 +lap: 3 +point: 9 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 4998 + y: 67 + z: 5006 + pos2: + x: 5018 + y: 63 + z: 4993 + glass: + pos1: + x: 4997 + y: 64 + z: 5004 + pos2: + x: 4997 + y: 64 + z: 4995 + 1: + pos1: + x: 4933 + y: 68 + z: 4989 + pos2: + x: 4971 + y: 63 + z: 4980 + 2: + pos1: + x: 4959 + y: 63 + z: 4978 + pos2: + x: 4925 + y: 66 + z: 4966 + 3: + pos1: + x: 4929 + y: 63 + z: 4961 + pos2: + x: 4974 + y: 66 + z: 4951 + 4: + pos1: + x: 4965 + y: 66 + z: 4947 + pos2: + x: 4917 + y: 63 + z: 4938 + 5: + pos1: + x: 4907 + y: 66 + z: 4934 + pos2: + x: 4974 + y: 63 + z: 4923 + 6: + pos1: + x: 4981 + y: 63 + z: 4919 + pos2: + x: 4927 + y: 67 + z: 4910 + 7: + pos1: + x: 4950 + y: 63 + z: 4906 + pos2: + x: 5010 + y: 66 + z: 4893 + 8: + pos1: + x: 5022 + y: 66 + z: 4924 + pos2: + x: 5036 + y: 63 + z: 4985 + 9: + pos1: + x: 4997 + y: 66 + z: 5005 + pos2: + x: 4940 + y: 63 + z: 4992 \ No newline at end of file diff --git a/iceboat/maps/8.yml b/iceboat/maps/8.yml new file mode 100644 index 0000000..70b62a8 --- /dev/null +++ b/iceboat/maps/8.yml @@ -0,0 +1,138 @@ +display: '层级彩虹瀑布' +difficulty: '4.4' +material: COMMAND_BLOCK +creator: "DreamCityToger" +yaw: -90 +lap: 2 +point: 12 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 5003 + y: 63 + z: 5012 + pos2: + x: 4979 + y: 66 + z: 4989 + glass: + pos1: + x: 5003 + y: 64 + z: 5011 + pos2: + x: 5003 + y: 64 + z: 4989 + 1: + pos1: + x: 5046 + y: 66 + z: 4969 + pos2: + x: 5063 + y: 62 + z: 5030 + 2: + pos1: + x: 5094 + y: 66 + z: 5004 + pos2: + x: 5126 + y: 63 + z: 4985 + 3: + pos1: + x: 5138 + y: 62 + z: 4901 + pos2: + x: 5202 + y: 58 + z: 4947 + 4: + pos1: + x: 5119 + y: 49 + z: 4946 + pos2: + x: 5083 + y: 45 + z: 4960 + 5: + pos1: + x: 5068 + y: 49 + z: 4907 + pos2: + x: 5035 + y: 38 + z: 4920 + 6: + pos1: + x: 5078 + y: 41 + z: 4934 + pos2: + x: 5048 + y: 37 + z: 4952 + 7: + pos1: + x: 5007 + y: 41 + z: 4942 + pos2: + x: 4979 + y: 32 + z: 4917 + 8: + pos1: + x: 5006 + y: 34 + z: 4930 + pos2: + x: 4999 + y: 26 + z: 4898 + 9: + pos1: + x: 4958 + y: 26 + z: 4898 + pos2: + x: 4946 + y: 51 + z: 4873 + 10: + pos1: + x: 4930 + y: 66 + z: 4873 + pos2: + x: 4899 + y: 63 + z: 4914 + 11: + pos1: + x: 4894 + y: 63 + z: 4936 + pos2: + x: 4939 + y: 67 + z: 4950 + 12: + pos1: + x: 5003 + y: 63 + z: 4989 + pos2: + x: 5047 + y: 66 + z: 5014 \ No newline at end of file diff --git a/iceboat/maps/9.yml b/iceboat/maps/9.yml new file mode 100644 index 0000000..ddc820f --- /dev/null +++ b/iceboat/maps/9.yml @@ -0,0 +1,84 @@ +display: '西南克克十字城' +difficulty: '2.7' +material: EMERALD +creator: DreamCityToger、ka_fei_coffee +yaw: 90 +lap: 3 +point: 6 +points: + join: + x: 5000 + y: 64 + z: 5000 + ready: + pos1: + x: 5022 + y: 63 + z: 4984 + pos2: + x: 4999 + y: 67 + z: 5016 + glass: + pos1: + x: 4998 + y: 64 + z: 5015 + pos2: + x: 4998 + y: 64 + z: 4985 + 1: + pos1: + x: 4914 + y: 63 + z: 4954 + pos2: + x: 4927 + y: 67 + z: 5046 + 2: + pos1: + x: 4908 + y: 63 + z: 5046 + pos2: + x: 4895 + y: 67 + z: 4954 + 3: + pos1: + x: 4863 + y: 63 + z: 4996 + pos2: + x: 4799 + y: 67 + z: 5005 + 4: + pos1: + x: 4908 + y: 63 + z: 5046 + pos2: + x: 4895 + y: 67 + z: 4954 + 5: + pos1: + x: 4914 + y: 63 + z: 4954 + pos2: + x: 4927 + y: 67 + z: 5046 + 6: + pos1: + x: 5022 + y: 63 + z: 4984 + pos2: + x: 4998 + y: 67 + z: 5016 \ No newline at end of file diff --git a/iceboat/players.yml b/iceboat/players.yml new file mode 100644 index 0000000..e69de29 diff --git a/iceboat/rooms.yml b/iceboat/rooms.yml new file mode 100644 index 0000000..3eca009 --- /dev/null +++ b/iceboat/rooms.yml @@ -0,0 +1,387 @@ +'1': + '1': false + '2': false + '3': false +'2': + '1': false + '2': false + '3': false +'3': + '1': false + '2': false + '3': false +'4': + '1': false + '2': false + '3': false +'5': + '1': false + '2': false + '3': false +'6': + '1': false + '2': false + '3': false +'7': + '1': false + '2': false + '3': false +'8': + '1': false + '2': false + '3': false +'9': + '1': false + '2': false + '3': false +'10': + '1': false + '2': false + '3': false +'11': + '1': false + '2': false + '3': false +'12': + '1': false + '2': false + '3': false +'13': + '1': false + '2': false + '3': false +'14': + '1': false + '2': false + '3': false +'15': + '1': false + '2': false + '3': false +'16': + '1': false + '2': false + '3': false +'17': + '1': false + '2': false + '3': false +'18': + '1': false + '2': false + '3': false +'19': + '1': false + '2': false + '3': false +'20': + '1': false + '2': false + '3': false +'21': + '1': false + '2': false + '3': false +'22': + '1': false + '2': false + '3': false +'23': + '1': false + '2': false + '3': false +'24': + '1': false + '2': false + '3': false +'25': + '1': false + '2': false + '3': false +'26': + '1': false + '2': false + '3': false +'27': + '1': false + '2': false + '3': false +'28': + '1': false + '2': false + '3': false +'29': + '1': false + '2': false + '3': false +'30': + '1': false + '2': false + '3': false +'31': + '1': false + '2': false + '3': false +'32': + '1': false + '2': false + '3': false +'33': + '1': false + '2': false + '3': false +'34': + '1': false + '2': false + '3': false +'35': + '1': false + '2': false + '3': false +'36': + '1': false + '2': false + '3': false +'37': + '1': false + '2': false + '3': false +'38': + '1': false + '2': false + '3': false +'39': + '1': false + '2': false + '3': false +'2979': + '1': false + '2': false + '3': false + '4': false + '5': false + '6': false + '7': false + '8': false + '9': false + '10': false +'2980': + '1': false + '2': false + '3': false + '4': false + '5': false + '6': false + '7': false + '8': false + '9': false + '10': false +'2981': + '1': false + '2': false + '3': false + '4': false + '5': false + '6': false + '7': false + '8': false + '9': false + '10': false +'2982': + '1': false + '2': false + '3': false + '4': false + '5': false + '6': false + '7': false + '8': false + '9': false + '10': false +'2983': + '1': false + '2': false + '3': false + '4': false + '5': false + '6': false + '7': false + '8': false + '9': false + '10': false +'2984': + '1': false + '2': false + '3': false + '4': false + '5': false + '6': false + '7': false + '8': false + '9': false + '10': false +'2985': + '1': false + '2': false + '3': false + '4': false + '5': false + '6': false + '7': false + '8': false + '9': false + '10': false +'2986': + '1': false + '2': false + '3': false + '4': false + '5': false + '6': false + '7': false + '8': false + '9': false + '10': false +'2987': + '1': false + '2': false + '3': false + '4': false + '5': false + '6': false + '7': false + '8': false + '9': false + '10': false +'2988': + '1': false + '2': false + '3': false + '4': false + '5': false + '6': false + '7': false + '8': false + '9': false + '10': false +'2989': + '1': false + '2': false + '3': false + '4': false + '5': false + '6': false + '7': false + '8': false + '9': false + '10': false +'2990': + '1': false + '2': false + '3': false + '4': false + '5': false + '6': false + '7': false + '8': false + '9': false + '10': false +'2991': + '1': false + '2': false + '3': false + '4': false + '5': false + '6': false + '7': false + '8': false + '9': false + '10': false +'2992': + '1': false + '2': false + '3': false + '4': false + '5': false + '6': false + '7': false + '8': false + '9': false + '10': false +'2993': + '1': false + '2': false + '3': false + '4': false + '5': false + '6': false + '7': false + '8': false + '9': false + '10': false +'2994': + '1': false + '2': false + '3': false + '4': false + '5': false + '6': false + '7': false + '8': false + '9': false + '10': false +'2995': + '1': false + '2': false + '3': false + '4': false + '5': false + '6': false + '7': false + '8': false + '9': false + '10': false +'2996': + '1': false + '2': false + '3': false + '4': false + '5': false + '6': false + '7': false + '8': false + '9': false + '10': false +'2997': + '1': false + '2': false + '3': false + '4': false + '5': false + '6': false + '7': false + '8': false + '9': false + '10': false +'2998': + '1': false + '2': false + '3': false + '4': false + '5': false + '6': false + '7': false + '8': false + '9': false + '10': false +'2999': + '1': false + '2': false + '3': false + '4': false + '5': false + '6': false + '7': false + '8': false + '9': false + '10': false diff --git a/iceboat/season.yml b/iceboat/season.yml new file mode 100644 index 0000000..f48b251 --- /dev/null +++ b/iceboat/season.yml @@ -0,0 +1,12 @@ +maps: + '37': 46.00 + '34': 118.00 + '35': 103.00 + '36': 88.00 + '31': 119.00 + '13': 88.00 + '4': 125.00 + '21': 101.00 + '23': 103.00 + '29': 129.00 + '16': 96.00 \ No newline at end of file