From c35e176a3b05f745600c6e60f168313d2b9e7b30 Mon Sep 17 00:00:00 2001 From: hxp <ale99527@vip.qq.com> Date: 星期三, 17 九月 2025 12:00:19 +0800 Subject: [PATCH] 129 【战斗】战斗系统-服务端(司马懿技能;增加按层级结算持续buff效果5003;增加非按攻击力计算伤害支持;技能伤害增加可限制最大攻击力百分比上限配置;) --- ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_MainLevel.py | 331 +++++++++++++++++++++++++++++++++++++++++-------------- 1 files changed, 247 insertions(+), 84 deletions(-) diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_MainLevel.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_MainLevel.py index 6cb2c29..69d3df3 100644 --- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_MainLevel.py +++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_MainLevel.py @@ -17,6 +17,7 @@ import ChConfig import GameWorld +import TurnAttack import ShareDefine import IpyGameDataPY import PlayerControl @@ -24,8 +25,11 @@ import ItemControler import IPY_GameWorld import NetPackCommon +import PlayerArena import ItemCommon +import PlayerTask import NPCCommon +import BattleObj import ChEquip import ObjPool @@ -64,17 +68,17 @@ ipyData = ipyDataMgr.GetMainChapterByIndex(chapterCount - 1) return [booty[0] for booty in ipyData.GetDailyBootyUpperList()] -def OnPlayerLineupAttackResult(curPlayer, atkObj, killObjIDList, useSkill, mapID, funcLineID): +def OnPlayerLineupAttackResult(curPlayer, atkObj, killObjList, useSkill, mapID, funcLineID): ## 回合战斗主动发起的玩家阵容攻击结果额外处理 ,一般处理副本相关的掉落、奖励等 if mapID == ChConfig.Def_FBMapID_Main: - __doKillAward(curPlayer, atkObj, killObjIDList) + __doKillAward(curPlayer, atkObj, killObjList) return -def __doKillAward(curPlayer, atkObj, killObjIDList): +def __doKillAward(curPlayer, atkObj, killObjList): ## 计算击杀奖励 - if not killObjIDList: + if not killObjList: GameWorld.DebugLog("没有击杀不需要处理!") return # 结算经验 @@ -86,12 +90,13 @@ GameWorld.DebugLog("增加经验: totalExp=%s,unXiantaoCntExp=%s" % (totalExp, unXiantaoCntExp)) PlayerControl.PlayerControl(curPlayer).AddExp(totalExp, ShareDefine.Def_ViewExpType_KillNPC) - __doMainDrop(curPlayer) + __doMainDrop(curPlayer, killObjList) return -def __doMainDrop(curPlayer): +def __doMainDrop(curPlayer, killObjList): # 装备掉落 - __doDropEquip(curPlayer) + if __doDropEquip(curPlayer, killObjList) == -1: + return playerID = curPlayer.GetPlayerID() DailyBootyUpperList = [] @@ -102,10 +107,16 @@ GameWorld.DebugLog("可掉落战利品上限: chapterID=%s, %s" % (chapterID, DailyBootyUpperList), playerID) + # 战利品掉落默认不堆叠,故最多只能掉落剩余空格子个数的物品 + spaceCount = ItemCommon.GetItemPackSpace(curPlayer, IPY_GameWorld.rptIdentify) + # 其他战利品掉落 bootyDropNeedDict = IpyGameDataPY.GetFuncEvalCfg("MainBootyDrop", 1, {}) bootyDropCntDict = IpyGameDataPY.GetFuncEvalCfg("MainBootyDrop", 2, {}) for itemID, dropUpper in DailyBootyUpperList: + if spaceCount <= 0: + GameWorld.DebugLog("掉落背包已满!", playerID) + break if dropUpper <= 0: continue todyDropCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_BootyDropToday % itemID) @@ -120,6 +131,22 @@ if dropBootyCnt <= 0: continue + itemData = GameWorld.GetGameData().GetItemByTypeID(itemID) + if not itemData: + continue + + # 判断挑战券 + if itemData.GetType() == ChConfig.Def_ItemType_AutoUseMoney: + curEff = itemData.GetEffectByIndex(0) + effID = curEff.GetEffectID() + moneyType = curEff.GetEffectValue(1) + if effID == ChConfig.Def_Effect_ItemGiveMoney and moneyType == ShareDefine.TYPE_Price_ArenaTicket: + curMoney = PlayerControl.GetMoney(curPlayer, ShareDefine.TYPE_Price_ArenaTicket) + storeMax = PlayerArena.GetArenaTicketStoreMax(curPlayer) + if curMoney >= storeMax: + GameWorld.DebugLog("挑战券已达存储上限! itemID=%s,curMoney=%s >= %s" % (itemID, curMoney, storeMax), playerID) + continue + dropCntRange = bootyDropCntDict[itemID] if not isinstance(dropCntRange, (list, tuple)) or len(dropCntRange) != 2: continue @@ -137,7 +164,8 @@ if dropCntTotal <= 0: continue - GameWorld.DebugLog("掉落战利品! itemID=%s,unXiantaoCntBooty=%s,次数=%s,dropCntTotal=%s" % (itemID, unXiantaoCntBooty, dropBootyCnt, dropCntTotal), playerID) + GameWorld.DebugLog("掉落战利品! itemID=%s,unXiantaoCntBooty=%s,次数=%s,dropCntTotal=%s,spaceCount=%s" + % (itemID, unXiantaoCntBooty, dropBootyCnt, dropCntTotal, spaceCount), playerID) curItem = ItemControler.GetOutPutItemObj(itemID, dropCntTotal, False, curPlayer=curPlayer) if curItem == None: continue @@ -147,73 +175,144 @@ unXiantaoCntBooty = unXiantaoCntBooty % dropOneNeed PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_UnXiantaoCntBooty % itemID, unXiantaoCntBooty) SetBootyDropToday(curPlayer, itemID, todyDropCnt + dropCntTotal) + spaceCount -= 1 return -def __doDropEquip(curPlayer): +def __doDropEquip(curPlayer, killObjList): ## 主线掉落装备 - unXiantaoCntEquip = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_UnXiantaoCntEquip) - dropOneNeed = IpyGameDataPY.GetFuncCfg("MainEquipDrop", 1) # 每消耗X个战锤掉落一件装备 - dropEquipCnt = unXiantaoCntEquip / dropOneNeed + playerID = curPlayer.GetPlayerID() + unXiantaoCntEquip = PlayerControl.GetUnXiantaoCntEquip(curPlayer) + bossTypeDropInfo = IpyGameDataPY.GetFuncCfg("MainEquipDrop", 1) # 每消耗X个战锤掉落一件装备 + fightPoint = max(curPlayer.GetFightPoint(), 1) # 消耗倍率也是掉落倍率 + dropEquipCnt = 0 + objDropCntDict = {} + for tagObj in killObjList: + tagID = tagObj.GetID() + npcID = tagObj.GetNPCID() + if not npcID: + continue + npcData = NPCCommon.GetNPCDataPy(npcID) + if not npcData: + continue + bossType = npcData.GetBossType() + if bossType not in bossTypeDropInfo: + continue + dropCnt = GameWorld.GetResultByRandomList(bossTypeDropInfo[bossType]) + if not dropCnt: + continue + dropCnt *= fightPoint # 多倍掉落 + objDropCntDict[tagID] = [tagObj, dropCnt, bossType] + dropEquipCnt += dropCnt + if dropEquipCnt <= 0: - GameWorld.DebugLog("主线暂不能掉落! unXiantaoCntEquip=%s,dropOneNeed=%s,dropEquipCnt=%s" % (unXiantaoCntEquip, dropOneNeed, dropEquipCnt)) + GameWorld.DebugLog("主线暂不能掉落! unXiantaoCntEquip=%s,dropEquipCnt=%s" % (unXiantaoCntEquip, dropEquipCnt), playerID) return + # 根据掉落背包空间修正最终可掉落装备数 dropEquipCnt = ItemCommon.GetItemPackSpace(curPlayer, IPY_GameWorld.rptIdentify, dropEquipCnt) if not dropEquipCnt: - GameWorld.DebugLog("掉落鉴定背包没有空间!") - return + GameWorld.DebugLog("掉落背包已满!", playerID) + return -1 - playerID = curPlayer.GetPlayerID() treeLV = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreeLV) ipyData = IpyGameDataPY.GetIpyGameData("TreeLV", treeLV) if not ipyData: return - equipColorRateList = ipyData.GetEquipColorRateList() - GameWorld.DebugLog("主线掉落装备: unXiantaoCntEquip=%s,dropEquipCnt=%s,treeLV=%s,equipColorRateList=%s" % (unXiantaoCntEquip, dropEquipCnt, treeLV, equipColorRateList), playerID) + GameWorld.DebugLog("主线掉落装备: unXiantaoCntEquip=%s,dropEquipCnt=%s,treeLV=%s,objDropCntDict=%s" + % (unXiantaoCntEquip, dropEquipCnt, treeLV, objDropCntDict), playerID) - maxRate = 10000 - totalRate = 0 - colorRateList = [] - for equipColor, colorRate in enumerate(equipColorRateList, 1): - if not colorRate: - continue - totalRate += colorRate - colorRateList.append([totalRate, equipColor]) - - if totalRate != maxRate: - GameWorld.SendGameError("GameWarning", "CutTreeTotalRateError:%s!=%s,treeLV=%s" % (totalRate, maxRate, treeLV)) - if not colorRateList: - return - GameWorld.DebugLog(" colorRateList=%s,totalRate=%s" % (colorRateList, totalRate), playerID) - - for _ in range(dropEquipCnt): - itemColor = GameWorld.GetResultByRandomList(colorRateList) - if not itemColor: - continue - equipIDList = NPCCommon.__GetEquipIDList(0, color=itemColor, placeList=ChConfig.Def_MainEquipPlaces, findType="MainEquipDrop") - if not equipIDList: - continue - randEquipID = random.choice(equipIDList) - - curItem = ItemControler.GetOutPutItemObj(randEquipID, 1, False, curPlayer=curPlayer) - if curItem == None: - continue - curItem.SetIsBind(1) # 为1时代表是掉落 - - #GameWorld.DebugLog("掉落装备: randEquipID=%s,%s" % (randEquipID, curItem.GetGUID()), playerID) - if not ItemControler.DoLogic_PutItemInPack(curPlayer, curItem, packIndexList=[IPY_GameWorld.rptIdentify]): + for tagID, dropInfo in objDropCntDict.items(): + tagObj, dropCnt, bossType = dropInfo + if hasattr(ipyData, "GetEquipColorRateList%s" % bossType): + equipColorRateList = getattr(ipyData, "GetEquipColorRateList%s" % bossType)() + else: + equipColorRateList = ipyData.GetEquipColorRateList() + + GameWorld.DebugLog("tagID=%s,bossType=%s,dropCnt=%s,treeLV=%s,equipColorRateList=%s" + % (tagID, bossType, dropCnt, treeLV, equipColorRateList), playerID) + if not equipColorRateList: continue - unXiantaoCntEquip -= dropOneNeed - PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_UnXiantaoCntEquip, unXiantaoCntEquip) + totalRate = 0 + colorRateList = [] + for equipColor, colorRate in enumerate(equipColorRateList, 1): + if not colorRate: + continue + totalRate += colorRate + colorRateList.append([totalRate, equipColor]) + + #maxRate = 10000 + #if totalRate != maxRate: + # GameWorld.SendGameError("GameWarning", "CutTreeTotalRateError:%s!=%s,treeLV=%s" % (totalRate, maxRate, treeLV)) + if not colorRateList: + return + GameWorld.DebugLog(" colorRateList=%s,totalRate=%s" % (colorRateList, totalRate), playerID) + for _ in range(dropCnt): + if dropEquipCnt <= 0: + break + itemColor = GameWorld.GetResultByRandomList(colorRateList) + if not itemColor: + continue + equipIDList = NPCCommon.__GetEquipIDList(0, color=itemColor, placeList=ChConfig.Def_MainEquipPlaces, findType="MainEquipDrop") + if not equipIDList: + continue + randEquipID = random.choice(equipIDList) + + curItem = ItemControler.GetOutPutItemObj(randEquipID, 1, False, curPlayer=curPlayer) + if curItem == None: + continue + curItem.SetIsBind(1) # 为1时代表是掉落 + #GameWorld.DebugLog("掉落装备: randEquipID=%s,%s" % (randEquipID, curItem.GetGUID()), playerID) + if not ItemControler.DoLogic_PutItemInPack(curPlayer, curItem, packIndexList=[IPY_GameWorld.rptIdentify]): + continue + + dropEquipCnt -= 1 + return -def GMTestKillDrop(curPlayer, unXiantao): - ## GM测试掉落 - unXiantaoCntEquip = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_UnXiantaoCntEquip) + unXiantao - PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_UnXiantaoCntEquip, unXiantaoCntEquip) - GameWorld.DebugAnswer(curPlayer, "未结算装备战锤数: %s" % unXiantaoCntEquip) +def GMTestKill(curPlayer, useXiantao): + ## GM测试击杀 + + mainFightMgr = TurnAttack.GetMainFightMgr(curPlayer) + turnFight = mainFightMgr.turnFight + if not turnFight.isInFight(): + GameWorld.DebugAnswer(curPlayer, "非主线战斗中!") + return + + useSkill = None + batObjMgr = BattleObj.GetBatObjMgr() + + # 随便取一个武将击杀对方所有怪物即可 + atkObj = None + batFactionA = turnFight.getBatFaction(ChConfig.Def_FactionA) + batLineup = batFactionA.getBatlineup(1) + for objID in batLineup.posObjIDDict.values(): + atkObj = batObjMgr.getBatObj(objID) + if atkObj.IsAlive(): + break + + if not atkObj: + GameWorld.DebugAnswer(curPlayer, "主阵容没有存活武将!") + return + + clientPack = ChPyNetSendPack.tagSCTurnFightReportSign() + clientPack.Sign = 0 + NetPackCommon.SendFakePack(curPlayer, clientPack) # 标记开始 + + killObjList = [] + batFactionB = turnFight.getBatFaction(ChConfig.Def_FactionB) + batLineup = batFactionB.getBatlineup(1) + for objID in batLineup.posObjIDDict.values(): + tagObj = batObjMgr.getBatObj(objID) + if tagObj.IsAlive(): + killObjList.append(tagObj) + TurnAttack.SetObjKilled(turnFight, tagObj, atkObj, useSkill) + + unXiantaoCntExp = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_UnXiantaoCntExp) + useXiantao + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_UnXiantaoCntExp, unXiantaoCntExp) + GameWorld.DebugAnswer(curPlayer, "未结算经验战锤数: %s" % unXiantaoCntExp) + GameWorld.DebugAnswer(curPlayer, "未结算装备战锤数: %s" % PlayerControl.AddUnXiantaoCntEquip(curPlayer, useXiantao)) chapterID = PlayerControl.GetMainLevelNowInfo(curPlayer)[0] chapterIpyData = IpyGameDataPY.GetIpyGameData("MainChapter", chapterID) if chapterIpyData: @@ -221,11 +320,16 @@ for itemID, upperCnt in DailyBootyUpperList: if upperCnt <= 0: continue - unXiantaoCntBooty = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_UnXiantaoCntBooty % itemID) + unXiantao + unXiantaoCntBooty = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_UnXiantaoCntBooty % itemID) + useXiantao PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_UnXiantaoCntBooty % itemID, unXiantaoCntBooty) GameWorld.DebugAnswer(curPlayer, "未结算战利品(%s)战锤数: %s" % (itemID, unXiantaoCntBooty)) - __doMainDrop(curPlayer) + OnPlayerLineupAttackResult(curPlayer, atkObj, killObjList, useSkill, turnFight.mapID, turnFight.funcLineID) + turnFight.checkOverByKilled() + + # 标记结束 + clientPack.Sign = 1 + NetPackCommon.SendFakePack(curPlayer, clientPack) return #// B4 15 主线掉落物品操作 #tagCSMainDropItemOP @@ -251,6 +355,7 @@ else: __doPickupMainItem(curPlayer, itemIndexList) + ItemCommon.SyncMakeItemAnswer(curPlayer, ShareDefine.Def_mitMainDropItemOP, ChConfig.Def_ComposeState_Sucess, opType) return def __doEquipMainEquip(curPlayer, itemIndexList, isAutoDecompose): @@ -297,54 +402,67 @@ # 刷属性 ChEquip.RefreshRoleEquipAttr(curPlayer) + + PlayerTask.UpdTaskValue(curPlayer, ChConfig.TaskType_EquipColor) return def __doDecomposeMainEquip(curPlayer, itemIndexList): playerID = curPlayer.GetPlayerID() GameWorld.DebugLog("分解主线装备: itemIndexList=%s" % (itemIndexList), playerID) - IdentifyPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptIdentify) - - moneyType = IpyGameDataPY.GetFuncCfg("MainEquipDrop", 2) - if not moneyType: + moneyType, moneyBase = IpyGameDataPY.GetFuncEvalCfg("MainEquipDrop", 2) + if not moneyType or not moneyBase: return + + equipDict = {} + IdentifyPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptIdentify) + for index in range(IdentifyPack.GetCount()): + curEquip = IdentifyPack.GetAt(index) + if not ItemCommon.CheckItemCanUse(curEquip): + #GameWorld.DebugLog("物品为空或不可用: index=%s" % index, playerID) + continue + if not ItemCommon.GetIsMainEquip(curEquip): + #GameWorld.DebugLog("非主线装备: index=%s" % index, playerID) + continue + equipDict[index] = curEquip + + if not equipDict: + return + + equipCnt = len(equipDict) + unXiantaoCntEquip = PlayerControl.GetUnXiantaoCntEquip(curPlayer) + perEquipXiantao = unXiantaoCntEquip / float(equipCnt) if equipCnt > 1 else unXiantaoCntEquip + decomposeMoney = max(1, moneyBase * perEquipXiantao) # 至少1个 + GameWorld.DebugLog("unXiantaoCntEquip=%s,equipCnt=%s,perEquipXiantao=%s,equipIndexList=%s" + % (unXiantaoCntEquip, equipCnt, perEquipXiantao, equipDict.keys()), playerID) + GameWorld.DebugLog("moneyBase=%s,decomposeMoney=%s" % (moneyBase, decomposeMoney), playerID) moneyTotal = 0 + decomposeCnt = 0 decomposeIndexList = [] for itemIndex in itemIndexList: - if itemIndex < 0 or itemIndex >= IdentifyPack.GetCount(): + if itemIndex not in equipDict: continue - curEquip = IdentifyPack.GetAt(itemIndex) - if not ItemCommon.CheckItemCanUse(curEquip): - GameWorld.DebugLog("物品为空或不可用: itemIndex=%s" % itemIndex, playerID) - continue - - if not ItemCommon.GetIsMainEquip(curEquip): - GameWorld.DebugLog("非主线装备: itemIndex=%s" % itemIndex, playerID) - continue - itemColor = curEquip.GetItemColor() - - colorIpyData = IpyGameDataPY.GetIpyGameData("EquipColor", itemColor) - if not colorIpyData: - return - moneyBase = colorIpyData.GetMoneyBase() # 分解货币基础 - if not moneyBase: - return - # 可以处理一些加成 - - decomposeMoney = moneyBase + curEquip = equipDict[itemIndex] moneyTotal += decomposeMoney - GameWorld.DebugLog(" itemIndex=%s,itemColor=%s,moneyBase=%s,decomposeMoney=%s,%s" - % (itemIndex, itemColor, moneyBase, decomposeMoney, moneyTotal), playerID) + GameWorld.DebugLog(" itemIndex=%s,moneyBase=%s,perEquipXiantao=%s,decomposeMoney=%s,总:%s" + % (itemIndex, moneyBase, perEquipXiantao, decomposeMoney, moneyTotal), playerID) ItemCommon.DelItem(curPlayer, curEquip, curEquip.GetCount(), True, ChConfig.ItemDel_EquipDecompose) decomposeIndexList.append(itemIndex) + decomposeCnt += 1 + unXiantaoCntEquip -= perEquipXiantao if not moneyTotal: return + moneyTotal = int(round(moneyTotal)) # 四舍五入取整 + unXiantaoCntEquip = PlayerControl.SetUnXiantaoCntEquip(curPlayer, unXiantaoCntEquip) + GameWorld.DebugLog("moneyTotal=%s,unXiantaoCntEquip=%s" % (moneyTotal, unXiantaoCntEquip), playerID) + PlayerControl.GiveMoney(curPlayer, moneyType, moneyTotal, "DecomposeMainEquip", isSysHint=False) + PlayerTask.AddTaskValue(curPlayer, ChConfig.TaskType_EquipDecompose, decomposeCnt) return def __doPickupMainItem(curPlayer, itemIndexList): @@ -392,3 +510,48 @@ clientPack.Count = len(clientPack.DropBootyList) NetPackCommon.SendFakePack(curPlayer, clientPack) return + +def OnTurnFightOver(curPlayer, turnFight, mapID, funcLineID, overMsg): + ## 回合战斗结束 + + if not curPlayer: + return + + #winFaction = turnFight.winFaction + isWin = turnFight.isWin + + playerID = curPlayer.GetPlayerID() + mainFightMgr = TurnAttack.GetMainFightMgr(curPlayer) + chapterID, levelNum, wave = PlayerControl.GetMainLevelNowInfo(curPlayer) + + if not isWin: + nextWave = max(1, wave - 1) + nowValue = PlayerControl.SetMainLevelNowInfo(curPlayer, chapterID, levelNum, nextWave) + GameWorld.DebugLog("主线小怪战斗失败,降一波! chapterID=%s,levelNum=%s,wave=%s,nextWave=%s,nowValue=%s" + % (chapterID, levelNum, wave, nextWave, nowValue), playerID) + return + + if turnFight.haveNextLineup(): + GameWorld.DebugLog("主线小怪战斗胜利,有下一小队! chapterID=%s,levelNum=%s,wave=%s" % (chapterID, levelNum, wave), playerID) + return + + # 获胜过波 + if wave < mainFightMgr.waveMax: + nextWave = min(mainFightMgr.waveMax, wave + 1) + nowValue = PlayerControl.SetMainLevelNowInfo(curPlayer, chapterID, levelNum, nextWave) + GameWorld.DebugLog("主线小怪波战斗胜利,下一波! chapterID=%s,levelNum=%s,wave=%s,nextWave=%s,nowValue=%s" + % (chapterID, levelNum, wave, nextWave, nowValue), playerID) + else: + GameWorld.DebugLog("主线小怪波战斗胜利,最后一波循环刷! chapterID=%s,levelNum=%s,wave=%s" % (chapterID, levelNum, wave), playerID) + + # 小怪可能会退波,所以只在有超过已过关卡进度时才更新值 + hisPassValue = PlayerControl.GetMainLevelPassValue(curPlayer) + curPassValue = PlayerControl.ComMainLevelValue(chapterID, levelNum, wave) + if curPassValue > hisPassValue: + GameWorld.DebugLog("更新当前过关进度! curPassValue=%s,hisPassValue=%s" % (curPassValue, hisPassValue), playerID) + PlayerControl.SetMainLevelPassValue(curPlayer, curPassValue) + else: + GameWorld.DebugLog("未超过当前过关进度,不更新! curPassValue=%s <= hisPassValue=%s" % (curPassValue, hisPassValue), playerID) + + return + -- Gitblit v1.8.0