# coding: utf-8 # 灵气系统 by DreamCityToger import random import pyspigot as ps from org.bukkit import Material, Sound, Particle from org.bukkit.util import Vector from org.bukkit.entity import Player from org.bukkit.Bukkit import getServer from org.bukkit.inventory import ItemStack, EquipmentSlot from org.bukkit.enchantments import Enchantment from org.bukkit.event.player import PlayerInteractEvent from org.bukkit.potion import PotionEffect, PotionEffectType from util2.develop.gui.builder import initializeItemStack from util2.develop.gui.builder import getGUIValue WORLD_NAME = u"Old_World" MIN_TODAY_PRO = 0.0 #天时最小值 MAX_TODAY_PRO = 10.0 #天时最大值 MIN_REIKI_PRO = 0.0 #地利最小值 MAX_REIKI_PRO = 10.0 #地利最大值 class WorldManager: #世界管理 def __init__(self): self.world = getServer().getWorld(WORLD_NAME) def getWorld(self): #获取世界对象 return self.world worldManager = WorldManager() class ItemsManager: def __init__(self): self.itemsData = ps.config.loadConfig("reiki/items.yml") self.itemsData.save() self.initialElementItems() def initialElementItems(self): self.grassItems = [] self.fireItems = [] self.waterItems = [] self.earthItems = [] self.thunderItems = [] self.iceItems = [] self.windItems = [] items = self.itemsData.getKeys(False) for itemId in items: element = self.itemsData.getString("{}.element".format(itemId), None) if element is None: continue if element == u"GRASS": self.grassItems.append(itemId) elif element == u"FIRE": self.fireItems.append(itemId) elif element == u"WATER": self.waterItems.append(itemId) elif element == u"EARTH": self.earthItems.append(itemId) elif element == u"THUNDER": self.thunderItems.append(itemId) elif element == u"ICE": self.iceItems.append(itemId) elif element == u"WIND": self.windItems.append(itemId) def getItemstack(self, itemId=0): if str(itemId) not in self.itemsData.getKeys(False): #若不存在该Id道具 return None material = self.itemsData.getString("{}.material".format(itemId), u"DANDELION") itemstack = ItemStack(Material.valueOf(material), 1) itemMeta = itemstack.getItemMeta() enchantmentsSection = self.itemsData.get("{}.enchantments".format(itemId)) if enchantmentsSection is not None: enchantments = enchantmentsSection.getKeys(False) for enchantment in enchantments: enchant = Enchantment.getByName(enchantment) if enchant is not None: level = enchantmentsSection.getInt(enchantment, 1) itemMeta.addEnchant(enchant, level, True) itemstack.setItemMeta(itemMeta) display = self.itemsData.getString("{}.display".format(itemId), u"§f未命名道具") lores = self.itemsData.get("{}.lores".format(itemId), []) key = self.itemsData.getString("{}.key".format(itemId), None) if key is None: key = u"ITEM" #默认关键字 item = initializeItemStack(itemstack, display, *lores, data=u"reiki:{}".format(key)) return item def getItemDisplay(self, itemId=0): if str(itemId) not in self.itemsData.getKeys(False): return None display = self.itemsData.getString("{}.display".format(itemId), u"§f未命名道具") return display itemManager = ItemsManager() class BlockManager: def __init__(self): self.blockData = ps.config.loadConfig("reiki/block.yml") self.blockData.save() self.todayPro = 5.0 #每日运势 self.randomTodayPro() #存储不同灵气台的内容 self.taskIds = {} self.offY = {} self.keys = {} self.mutation = {} self.working = {} self.element = {} self.itemId = {} self.players= {} #灵气台管理-------------------------------- def getLocTable(self, loc): #获取对应位置的灵气台 x = loc.getBlockX() y = loc.getBlockY() z = loc.getBlockZ() for blockId in self.blockData.getKeys(False): if self.blockData.getInt("{}.x".format(blockId)) == x: if self.blockData.getInt("{}.y".format(blockId)) == y: if self.blockData.getInt("{}.z".format(blockId)) == z: return blockId return None def createReikiTable(self, loc): #创造一个灵气台 if self.getLocTable(loc): #若已经存在 return False blockId = str(self.getNewTableID()) self.blockData.set("{}.x".format(blockId), loc.getBlockX()) self.blockData.set("{}.y".format(blockId), loc.getBlockY()) self.blockData.set("{}.z".format(blockId), loc.getBlockZ()) self.blockData.set("{}.world".format(blockId), loc.getWorld().getName()) self.blockData.set("{}.name".format(blockId), u"普通灵气台") self.blockData.set("{}.grass".format(blockId), 11) self.blockData.set("{}.fire".format(blockId), 11) self.blockData.set("{}.water".format(blockId), 11) self.blockData.set("{}.earth".format(blockId), 11) self.blockData.set("{}.thunder".format(blockId), 11) self.blockData.set("{}.ice".format(blockId), 11) self.blockData.set("{}.wind".format(blockId), 11) self.blockData.set("{}.timesOfUse".format(blockId), 0) #使用过的次数 self.blockData.set("{}.timesOfMutation".format(blockId), 0) #突变召唤次数 self.blockData.save() return blockId def delReikiTable(self, blockId): #删除对应Id的灵气台 if str(blockId) not in self.blockData.getKeys(False): return False self.blockData.set(blockId, None) self.blockData.save() return True def getTableLoc(self, blockId): #获取灵气台的位置 if str(blockId) not in self.blockData.getKeys(False): return None x = self.blockData.getInt("{}.x".format(blockId)) y = self.blockData.getInt("{}.y".format(blockId)) z = self.blockData.getInt("{}.z".format(blockId)) world = worldManager.getWorld() return world.getBlockAt(x, y, z).getLocation() def getNewTableID(self): #获取一个新的灵气台ID currentID = 1 keys = self.blockData.getKeys(False) while True: if self.blockData.get(str(currentID)) is None: return currentID if str(currentID) not in keys: return currentID else: currentID += 1 def getTableElement(self, blockId, element=u"GRASS"): #获取灵气台的元素 if str(blockId) not in self.blockData.getKeys(False): #若不存在 return None if element.lower() not in ["grass", "fire", "water", "earth", "thunder", "ice", "wind"]: #若元素不存在 return None value = self.blockData.getInt("{}.{}".format(blockId, element.lower()), 0) #获取 return value def getTableName(self, blockId): #获取灵气台的名称 if str(blockId) not in self.blockData.getKeys(False): #若不存在 return None name = self.blockData.getString("{}.name".format(blockId), u"§f普通灵气台") #获取 return name def setTableElement(self, blockId, element=u"GRASS", value=11): if str(blockId) not in self.blockData.getKeys(False): #若不存在 return False if element.lower() not in ["grass", "fire", "water", "earth", "thunder", "ice", "wind"]: #若元素不存在 return False self.blockData.set("{}.{}".format(blockId, element.lower()), value) #设置 self.blockData.save() #保存 return True def setTableName(self, blockId, name): #设置灵气台的名称 if str(blockId) not in self.blockData.getKeys(False): #若不存在 return False self.blockData.set("{}.name".format(blockId), name) #设置 self.blockData.save() #保存 return True def addTableTimesOfUse(self, blockId): #增加灵气台使用次数 if str(blockId) not in self.blockData.getKeys(False): #若不存在 return False timesOfUse = self.blockData.getInt("{}.timesOfUse".format(blockId), 0) #获取 self.blockData.set("{}.timesOfUse".format(blockId), timesOfUse + 1) #设置 self.blockData.save() #保存 return True def addTableTimesOfMutation(self, blockId): #增加灵气台使用次数 if str(blockId) not in self.blockData.getKeys(False): #若不存在 return False timesOfMutation = self.blockData.getInt("{}.timesOfMutation".format(blockId), 0) #获取 self.blockData.set("{}.timesOfMutation".format(blockId), timesOfMutation + 1) #设置 self.blockData.save() #保存 return True #灵气召唤-------------------------------- def reikiCall(self, player, blockId, key=u"DANDELION", mutation=False): #灵气召唤 if str(blockId) not in self.blockData.getKeys(False): #若不存在 return False if blockId not in self.working: self.working[blockId] = False #设置为未工作 if self.working[blockId]: #若正在工作 return False #效果 loc = self.getTableLoc(blockId) world = loc.getWorld() world.playSound(loc, Sound.BLOCK_BELL_RESONATE, 1.0, 1.0) #播放声音 world.spawnParticle(Particle.ENCHANT, loc.add(Vector(0.5,1.5,0.5)), 300, 0.3, 0.4, 0.3, 0) element, itemId = self.selectElementAndItem(blockId) #抽取元素和物品 self.working[blockId] = True #设置正在工作 self.offY[blockId] = 2.0 #重置Y偏移 self.keys[blockId] = key #设置关键字 self.mutation[blockId] = mutation #设置是否为突变 self.element[blockId] = element #设置元素 self.itemId[blockId] = itemId #设置物品 self.players[blockId] = player #设置玩家 self.taskIds[blockId] = ps.scheduler.scheduleRepeatingTask(lambda s=self, b=blockId, m=mutation, : s.spawnParticles(b, m), 0, 1) return True def reikiCallEnd(self, blockId): key = self.keys[blockId] #获取关键字 mutation = self.mutation[blockId] #获取是否为突变 loc = self.getTableLoc(blockId) world = loc.getWorld() blockManager.addTableTimesOfUse(blockId) #增加使用次数 if key == u"DANDELION": #如果是蒲公英 if mutation: #如果是突变 blockManager.addTableTimesOfMutation(blockId) #增加突变次数 world.spawnParticle(Particle.REVERSE_PORTAL, loc.add(Vector(0.5,0.9,0.5)), 100, 0.25, 0.06, 0.25, 0) #播放粒子 world.playSound(loc, Sound.ENTITY_PLAYER_LEVELUP, 0.5, 2.0) #播放声音 player = self.players[blockId] #获取玩家 message = u"§d[灵气] §e{} §a在{}§a成功召唤出 {} !".format(player.getName(), self.getTableName(blockId), itemManager.getItemDisplay(self.itemId[blockId])) #消息 playerManager = PlayerManager(player) #获取玩家管理器 playerManager.upgradeLuck() getServer().broadcastMessage(message) self.dropItem(blockId, self.itemId[blockId]) #掉落 else: #如果不是 self.dropItem(blockId, 1) #掉落 def spawnParticles(self, blockId, mutation=False): if str(blockId) not in self.blockData.getKeys(False): return False loc = self.getTableLoc(blockId) world = loc.getWorld() if mutation: element = self.element[blockId] world.playSound(loc, Sound.BLOCK_AMETHYST_BLOCK_CHIME, 1.0, 1.0) #播放声音 if element == u"grass": world.spawnParticle(Particle.SPORE_BLOSSOM_AIR, loc.add(Vector(0.5,self.offY[blockId]+0.8,0.5)), 1, 0, 0, 0, 0) elif element == u"fire": world.spawnParticle(Particle.FLAME, loc.add(Vector(0.5,self.offY[blockId]+0.8,0.5)), 1, 0, 0, 0, 0.05) elif element == u"water": world.spawnParticle(Particle.DOLPHIN, loc.add(Vector(0.5,self.offY[blockId]+0.8,0.5)), 10, 0.05, 0, 0.05, 0) elif element == u"earth": world.spawnParticle(Particle.WAX_ON, loc.add(Vector(0.5,self.offY[blockId]+0.8,0.5)), 1, 0.2, 0, 0.2, 0) elif element == u"thunder": world.spawnParticle(Particle.FLASH, loc.add(Vector(0.5,self.offY[blockId]+0.8,0.5)), 1, 0, 0, 0, 0) elif element == u"ice": world.spawnParticle(Particle.SNOWFLAKE, loc.add(Vector(0.5,self.offY[blockId]+0.8,0.5)), 1, 0, 0, 0, 0) elif element == u"wind": world.spawnParticle(Particle.CLOUD, loc.add(Vector(0.5,self.offY[blockId]+0.8,0.5)), 1, 0, 0, 0, 0.02) else: world.spawnParticle(Particle.DRAGON_BREATH, loc.add(Vector(0.5,self.offY[blockId]+0.8,0.5)), 1, 0.02, 0, 0.02, 0) else: world.spawnParticle(Particle.HAPPY_VILLAGER, loc.add(Vector(0.5,self.offY[blockId]+0.8,0.5)), 1, 0.1, 0, 0.1, 0) self.offY[blockId] -= 0.05 #增加Y偏移 if self.offY[blockId] <= 0: #若Y偏移小于等于0 self.stopTask(blockId) #停止任务 self.reikiCallEnd(blockId) #灵气台反馈 self.working[blockId] = False #设置为未工作 def selectElementAndItem(self, blockId): if str(blockId) not in self.blockData.getKeys(False): return None, None # 加权抽取元素 elements = ['grass', 'fire', 'water', 'earth', 'thunder', 'ice', 'wind'] elementWeights = {element: self.blockData.getInt(u"{}.{}".format(blockId, element)) for element in elements} selectedElement = self.weightedRandomSelection(elementWeights) # 根据元素获取对应物品列表 if selectedElement == 'grass': itemList = itemManager.grassItems elif selectedElement == 'fire': itemList = itemManager.fireItems elif selectedElement == 'water': itemList = itemManager.waterItems elif selectedElement == 'earth': itemList = itemManager.earthItems elif selectedElement == 'thunder': itemList = itemManager.thunderItems elif selectedElement == 'ice': itemList = itemManager.iceItems elif selectedElement == 'wind': itemList = itemManager.windItems else: return None, None # 加权抽取物品 itemWeights = {} for itemId in itemList: weight = itemManager.itemsData.getInt(u"{}.weight".format(itemId), 1) itemWeights[str(itemId)] = weight selectedItem = self.weightedRandomSelection(itemWeights) return selectedElement, selectedItem def weightedRandomSelection(self, weights): totalWeight = sum(weights.values()) randomNum = random.uniform(0, totalWeight) cumulativeWeight = 0 for item, weight in weights.items(): cumulativeWeight += weight if randomNum <= cumulativeWeight: return item def stopTask(self, blockId): if blockId in self.taskIds: taskId = self.taskIds[blockId] if taskId is not None: ps.scheduler.stopTask(taskId) self.taskIds[blockId] = None def dropItem(self, blockId, itemId=1): if str(blockId) not in self.blockData.getKeys(False): return False item = itemManager.getItemstack(itemId) if item is None: return False loc = self.getTableLoc(blockId) world = loc.getWorld() droppedItem = world.dropItem(loc.add(Vector(0.5,1,0.5)), item) droppedItem.setVelocity(Vector(0, 0, 0)) world.playSound(loc, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1.0, 1.0) return True #运势管理 def setTodayPro(self, pro=5.0): #设置当日概率 self.todayPro = pro def randomTodayPro(self): rand = random.uniform(MIN_TODAY_PRO,MAX_TODAY_PRO) self.setTodayPro(rand) def getTodayPro(self): #获取今日运势概率 return self.todayPro def getReikiTablePro(self, blockId): #获取灵气台概率 if str(blockId) not in self.blockData.getKeys(False): #若不存在该灵气台 return None timesOfUse = self.blockData.getInt("{}.timesOfUse".format(blockId), 0) #获取 timesOfMutation = self.blockData.getInt("{}.timesOfMutation".format(blockId), 0) #获取 pro = (float(timesOfUse - timesOfMutation + 50) / float(timesOfUse + 100)) * 10 #计算 return pro def getPlayerPro(self, player): #获取玩家概率 luck = player.getPotionEffect(PotionEffectType.LUCK) unluck = player.getPotionEffect(PotionEffectType.UNLUCK) pro = 0.0 if luck is not None: luckLevel = luck.getAmplifier() + 1 # 效果等级从 0 开始,所以加 1 luckBonus = min(luckLevel * 5, 50) # 幸运影响最多 +5 pro += luckBonus if unluck is not None: unluckLevel = unluck.getAmplifier() + 1 # 效果等级从 0 开始,所以加 1 unluckPenalty = min(unluckLevel * 5, 50) # 霉运影响最多 -5 pro -= unluckPenalty return pro def getPro(self, player, blockId): #获取概率 pro = self.getPlayerPro(player) + self.getReikiTablePro(blockId) + self.getTodayPro() pro = max(0.0, min(pro, 100.0)) #限制概率范围 return pro blockManager = BlockManager() class PlayerManager: def __init__(self, player): self.player = player def getTargetFrameLocation(self): targetBlock = self.player.getTargetBlockExact(5) if targetBlock is not None: if targetBlock.getType() == Material.END_PORTAL_FRAME: loc = targetBlock.getLocation() if loc.getWorld().getName() == WORLD_NAME: return loc return None def drawPro(self, pro=5.0): #按概率判断成功 pro = max(0.0, min(pro, 100.0)) randomValue = random.uniform(0.0, 100.0) return randomValue <= pro def reikiCall(self, blockId, key=u"DANDELION"): #灵气召唤 pro = blockManager.getPro(self.player, blockId) #获取概率 mutation = self.drawPro(pro) #抽奖 if mutation: result = blockManager.reikiCall(self.player, blockId, key, mutation=True) else: result = blockManager.reikiCall(self.player, blockId, key, mutation=False) if result: return True else: return False def upgradeLuck(self): luck = self.player.getPotionEffect(PotionEffectType.LUCK) if luck is not None: luckLevel = luck.getAmplifier() + 1 # 效果等级从 0 开始,所以加 1 luckLevel = min(luckLevel, 6) # 最大等级为 7 self.player.addPotionEffect(PotionEffect(PotionEffectType.LUCK, 72000, luckLevel, True, False)) else: self.player.addPotionEffect(PotionEffect(PotionEffectType.LUCK, 72000, 0, True, False)) def reikiCommand(sender, label, args): if isinstance(sender, Player): if sender.isOp(): if sender.getWorld().getName() != WORLD_NAME: sender.sendMessage(u"§d[灵气]§f请在世界 §e{} §f中使用此命令".format(WORLD_NAME)) return False playerManager = PlayerManager(sender) if len(args) < 1: sender.sendMessage(u"§d[灵气]§f请输入参数") return False elif args[0] == u"add": blockLoc = playerManager.getTargetFrameLocation() if blockLoc is not None: blockId = blockManager.createReikiTable(blockLoc) if blockId is False: sender.sendMessage(u"§d[灵气]§f该位置已经有灵气台了") return False else: sender.sendMessage(u"§d[灵气]§f成功创建ID为{}的灵气台".format(blockId)) return True else: sender.sendMessage(u"§d[灵气]§f请看着一个末地传送门框架") return False elif args[0] == u"del": blockLoc = playerManager.getTargetFrameLocation() if blockLoc is not None: blockId = blockManager.getLocTable(blockLoc) if blockId is None: sender.sendMessage(u"§d[灵气]§f该位置没有灵气台") return False result = blockManager.delReikiTable(blockId) if result is False: sender.sendMessage(u"§d[灵气]§f未找到该灵气台") return False else: sender.sendMessage(u"§d[灵气]§f成功删除灵气台") return True else: sender.sendMessage(u"§d[灵气]§f请看着一个末地传送门框架") return False elif args[0] == u"list": try: page = int(args[1]) if len(args) > 1 else 1 except ValueError: sender.sendMessage(u"§d[灵气]§f页数参数必须是整数") return True pageSize = 10 blockIds = list(blockManager.blockData.getKeys(False)) startIndex = (page - 1) * pageSize endIndex = startIndex + pageSize totalPages = (len(blockIds) + pageSize - 1) // pageSize if startIndex >= len(blockIds): sender.sendMessage(u"§d[灵气]§f指定的页数不存在") return True sender.sendMessage(u"§d[灵气]§f当前灵气台列表 (第 {} 页,共 {} 页):".format(page, totalPages)) for blockId in blockIds[startIndex:endIndex]: blockLoc = blockManager.getTableLoc(blockId) blockX = blockLoc.getBlockX() blockY = blockLoc.getBlockY() blockZ = blockLoc.getBlockZ() blockName = blockManager.getTableName(blockId) # 获取元素值 elements = ["grass", "fire", "water", "earth", "thunder", "ice", "wind"] elementValues = {} for element in elements: value = blockManager.getTableElement(blockId, element) if value is None: value = 0 elementValues[element] = value elementStr = " ".join([u"{}:{}".format(elem, val) for elem, val in elementValues.items()]) sender.sendMessage(u"§d[灵气]§fID: §e{} §f位置: §e({},{},{}) §f名称: §e{} \n§f元素值: §e{}".format(blockId, blockX, blockY, blockZ, blockName, elementStr)) return True elif args[0] == u"getitem": if len(args) > 1: itemId = args[1] if str(itemId) not in itemManager.itemsData.getKeys(False): sender.sendMessage(u"§d[灵气]§f未找到该道具") return False itemstack = itemManager.getItemstack(itemId) sender.getInventory().addItem(itemstack) sender.sendMessage(u"§d[灵气]§f成功获取道具") return True elif args[0] == u"set": if len(args) > 2: blockLoc = playerManager.getTargetFrameLocation() if blockLoc is not None: blockId = blockManager.getLocTable(blockLoc) if blockId is None: sender.sendMessage(u"§d[灵气]§f该位置没有灵气台") return False setType = args[1] if setType == u"element": element = args[2] if element.lower() not in ["grass", "fire", "water", "earth", "thunder", "ice", "wind"]: sender.sendMessage(u"§d[灵气]§f元素不存在") return False value = args[3] try: value = int(value) except ValueError: sender.sendMessage(u"§d[灵气]§f数值必须为整数") return False result = blockManager.setTableElement(blockId, element, value) if result is False: sender.sendMessage(u"§d[灵气]§f设置失败") return False else: sender.sendMessage(u"§d[灵气]§f成功设置元素值") return True elif setType == u"name": name = u" ".join(args[2:]) result = blockManager.setTableName(blockId, name) if result is False: sender.sendMessage(u"§d[灵气]§f设置失败") return False else: sender.sendMessage(u"§d[灵气]§f成功设置名称") return True else: sender.sendMessage(u"§d[灵气]§f无效的参数") else: sender.sendMessage(u"§d[灵气]§f请看着一个末地传送门框架") else: sender.sendMessage(u"§d[灵气]§f请输入参数") return False else: sender.sendMessage(u"§d[灵气]§f无效的参数") return False return False ps.command.registerCommand(reikiCommand, "reiki") def onPlayerInteract(event): player = event.getPlayer() worldName = player.getWorld().getName() if worldName != WORLD_NAME: return False if event.getHand() == EquipmentSlot.OFF_HAND: #禁止副手触发 return False clickedBlock = event.getClickedBlock() if clickedBlock is None: #防止空指针 return False if clickedBlock.getType() != Material.END_PORTAL_FRAME: #判断是否是灵气台 return False blockLoc = clickedBlock.getLocation() blockX = blockLoc.getBlockX() blockY = blockLoc.getBlockY() blockZ = blockLoc.getBlockZ() blockId = None for id in blockManager.blockData.getKeys(False): x = blockManager.blockData.getInt("{}.x".format(id)) if blockX == x: y = blockManager.blockData.getInt("{}.y".format(id)) if blockY == y: z = blockManager.blockData.getInt("{}.z".format(id)) if blockZ == z: blockId = id break if blockId is None: return False playerManager = PlayerManager(player) item = event.getItem() guiValue = getGUIValue(item) if guiValue is not None: reiki, key = guiValue.split(':') if reiki == u"reiki": if key == u"DANDELION": result = playerManager.reikiCall(blockId, key) if result: item.setAmount(item.getAmount()-1) return name = blockManager.getTableName(blockId) if player.isOp(): elements = ["grass", "fire", "water", "earth", "thunder", "ice", "wind"] weights = {} for element in elements: value = blockManager.getTableElement(blockId, element) if value is None: value = 0 weights[element] = value player.sendMessage(u"§d[灵气]§a{}元素值:§a草{} §c火{} §3水{} §6土{} §e雷{} §b冰{} §f风{}".format(name, weights["grass"], weights["fire"], weights["water"], weights["earth"], weights["thunder"], weights["ice"], weights["wind"])) pro = blockManager.getPro(player, blockId) todayPro = blockManager.getTodayPro() playerPro = blockManager.getPlayerPro(player) reikiPro = blockManager.getReikiTablePro(blockId) player.sendMessage(u"§d[灵气]§a{}运势:§f{:.2f}%§7[天时{:.2f}|地利{:.2f}|人和{:.2f}]".format(name, pro, todayPro, reikiPro, playerPro)) ps.listener.registerListener(onPlayerInteract, PlayerInteractEvent)