129 【战斗】战斗系统-服务端(NPC、技能使用新表N.NPC表卡牌、J.技能表卡牌;重构战斗系统;优化战利品掉落;)
20个文件已修改
17个文件已删除
4个文件已添加
| | |
| | | BYTE OPLimitInAct; //活动期间限制队伍操作
|
| | | };
|
| | |
|
| | | //NPC表
|
| | |
|
| | | struct NPC
|
| | | {
|
| | | DWORD _NPCID; //NPCID
|
| | | char NPCName; //名称
|
| | | BYTE Country; //国家
|
| | | BYTE AtkDistType; //远近类型;1-近战;2-远程
|
| | | WORD LV; //等级
|
| | | DWORD Atk; //攻击力
|
| | | DWORD Def; //防御值
|
| | | DWORD MaxHP; //最大生命值,可超过20E
|
| | | list SkillIDList; //技能ID列表
|
| | | DWORD FinalDamPer; //最终增伤
|
| | | DWORD FinalDamPerDef; //最终减伤
|
| | | DWORD MissRate; //闪避概率
|
| | | DWORD MissRateDef; //抗闪避概率
|
| | | DWORD SuperHitRate; //暴击概率
|
| | | DWORD SuperHitRateDef; //抗暴击概率
|
| | | DWORD StunRate; //击晕概率
|
| | | DWORD StunRateDef; //抗击晕概率
|
| | | DWORD ComboRate; //连击概率
|
| | | DWORD ComboRateDef; //抗连击概率
|
| | | DWORD ParryRate; //格挡概率
|
| | | DWORD ParryRateDef; //抗格挡概率
|
| | | DWORD SuckHPPer; //吸血比率
|
| | | DWORD SuckHPPerDef; //抗吸血比率
|
| | | dict SpecAttrInfo; //特殊属性信息 {"属性ID":值, ...}
|
| | | };
|
| | |
|
| | | //技能表
|
| | | struct Skill
|
| | | {
|
| | | DWORD _SkillID; //技能ID
|
| | | DWORD SkillTypeID; //技能TypeID
|
| | | WORD SkillMaxLV; //最高等级
|
| | | char SkillName; //技能名
|
| | | BYTE FuncType; //功能分类
|
| | | BYTE SkillType; //技能类型
|
| | | BYTE HurtType; //伤害类型
|
| | | BYTE AtkType; //释放方式
|
| | | BYTE TagAim; //瞄准位置
|
| | | BYTE TagFriendly; //敌我目标
|
| | | BYTE TagAffect; //目标细分
|
| | | BYTE TagCount; //目标个数
|
| | | WORD HappenRate; //释放或添加几率
|
| | | WORD LastTime; //持续时间
|
| | | WORD CoolDownTime; //冷却时间
|
| | | WORD Priority; //优先级
|
| | | DWORD EffectID1; //效果ID1
|
| | | list EffectValues1; //效果值列表1
|
| | | DWORD EffectID2; //效果ID2
|
| | | list EffectValues2; //效果值列表2
|
| | | DWORD EffectID3; //效果ID3
|
| | | list EffectValues3; //效果值列表3
|
| | | DWORD ConnSkill; //关联技能
|
| | | list EnhanceSkillList; //触发技能ID列表
|
| | | DWORD FightPower; //技能战斗力
|
| | | };
|
| | |
|
| | | //武将表
|
| | | struct Hero
|
| | | {
|
| | | DWORD _HeroID; //英雄ID
|
| | | char Name; //名称
|
| | | BYTE Country; // 国家
|
| | | BYTE Quality; // 品质
|
| | | BYTE AtkDistType; //远近类型;1-近战;2-远程
|
| | |
| | | {
|
| | | BYTE _ChapterID; //章节ID
|
| | | list DailyBootyUpperList; // 每日战利品掉落上限,[[物品ID,每日上限], ...]
|
| | | list BootyWeightList; // 战利品掉落权重,[[权重,物品ID,掉落个数下限, 上限], ...]
|
| | | };
|
| | |
|
| | | //主线关卡表
|
| | |
| | | float AttrPer; //对应等级表中的比例
|
| | | dict AttrSpecDict; //特殊属性值字典 {attrKey:value, ...}
|
| | | dict AttrExDict; //特殊属性值字典 {attrKey:value, ...}
|
| | | };
|
| | |
|
| | | //NPC表扩展
|
| | |
|
| | | struct tagNPCEx
|
| | | {
|
| | | DWORD _NPCID; //NPCID
|
| | | BYTE FightPowerLackAtkLimit; //战力不足限制攻击
|
| | | DWORD SuppressFightPower; //推荐/压制战力
|
| | | BYTE AtkDistType; //远近类型;1-近战;2-远程
|
| | | DWORD Atk; //攻击力
|
| | | DWORD Def; //防御值
|
| | | DWORD MaxHP; //最大生命值,可超过20E
|
| | | list SkillIDList; //技能ID列表
|
| | | DWORD FinalHurtPer; //最终增伤
|
| | | DWORD FinalHurtReducePer; //最终减伤
|
| | | DWORD MissRate; //闪避概率
|
| | | DWORD MissDefRate; //抗闪避概率
|
| | | DWORD SuperHitRate; //暴击概率
|
| | | DWORD SuperHitRateReduce; //抗暴击概率
|
| | | DWORD FaintRate; //击晕概率
|
| | | DWORD FaintDefRate; //抗击晕概率
|
| | | DWORD ComboRate; //连击概率
|
| | | DWORD ComboDefRate; //抗连击概率
|
| | | DWORD ParryRate; //格挡概率
|
| | | DWORD ParryDefRate; //抗格挡概率
|
| | | DWORD ParryDamPer; //格挡减伤比率
|
| | | DWORD SuckHPPer; //吸血比率
|
| | | DWORD SuckHPDefPer; //抗吸血比率
|
| | | dict SpecAttrInfo; //特殊属性信息 {"属性ID":值, ...}
|
| | | };
|
| | |
|
| | | //成长型境界怪物表
|
| | |
| | | return heroIpyData.GetAtkDistType()
|
| | |
|
| | | npcID = curObj.GetNPCID()
|
| | | npcDataEx = NPCCommon.GetNPCDataEx(npcID)
|
| | | npcDataEx = NPCCommon.GetNPCDataPy(npcID)
|
| | | if npcDataEx:
|
| | | return npcDataEx.GetAtkDistType()
|
| | |
|
| | |
| | | PlayerControl.NotifyCode(atkPlayer, sysMark)
|
| | | return False
|
| | |
|
| | | npcDataEx = NPCCommon.GetNPCDataEx(npcID)
|
| | | if npcDataEx and npcDataEx.GetFightPowerLackAtkLimit():
|
| | | if npcDataEx.GetSuppressFightPower() > PlayerControl.GetFightPower(atkPlayer):
|
| | | if isNotify:
|
| | | PlayerControl.NotifyCode(atkPlayer, "BossFightPowerHint") |
| | | #GameWorld.DebugLog("战力不足,无法攻击boss! npcID=%s,SuppressFightPower=%s > playerFightPower=%s" |
| | | # % (npcID, npcDataEx.GetSuppressFightPower(), PlayerControl.GetFightPower(atkPlayer))) |
| | | return False
|
| | | #npcDataEx = NPCCommon.GetNPCDataPy(npcID)
|
| | | #if npcDataEx and npcDataEx.GetFightPowerLackAtkLimit():
|
| | | # if npcDataEx.GetSuppressFightPower() > PlayerControl.GetFightPower(atkPlayer):
|
| | | # if isNotify:
|
| | | # PlayerControl.NotifyCode(atkPlayer, "BossFightPowerHint") |
| | | # #GameWorld.DebugLog("战力不足,无法攻击boss! npcID=%s,SuppressFightPower=%s > playerFightPower=%s" |
| | | # # % (npcID, npcDataEx.GetSuppressFightPower(), PlayerControl.GetFightPower(atkPlayer))) |
| | | # return False
|
| | |
|
| | | return True
|
| | |
|
| | |
| | | aBurnValue = atkwargs.get('burnValue', 0)
|
| | | aBurnPer = atkwargs.get('burnPer', 0)
|
| | | hurtFormulaKey = atkwargs.get('hurtFormulaKey', None)
|
| | | #if hurtFormulaKey == "Burn":
|
| | | # pass
|
| | | #else:
|
| | | hurtValue = eval(IpyGameDataPY.GetFuncCompileCfg("DOTFormula", 1))
|
| | | elif not curSkill:
|
| | | hurtValue = eval(IpyGameDataPY.GetFuncCompileCfg("HurtFormula", 3))
|
| | |
| | | else:
|
| | | defObj.SetDict(ChConfig.Def_PlayerKey_LastAttackerObjID, atkObj.GetID())
|
| | |
|
| | | TurnAttack.AddTurnObjHurtValue(atkObj, defObj, resultHurtType.HurtType, resultHurtType.RealHurtHP, resultHurtType.LostHP, curSkill)
|
| | | #TurnAttack.AddTurnObjHurtValue(atkObj, defObj, resultHurtType.HurtType, resultHurtType.RealHurtHP, resultHurtType.LostHP, curSkill)
|
| | |
|
| | | #if resultHurtType.RealHurtHP:
|
| | | # PassiveBuffEffMng.OnPassiveSkillTrigger(defObj, atkObj, None, ChConfig.TriggerType_BeHurt, tick)
|
| | |
| | | if GameObj.GetHP(curObjDetel) > 0:
|
| | | return
|
| | |
|
| | | if TurnAttack.SetTurnObjKilled(curObjDetel, atkObj):
|
| | | return
|
| | | #if TurnAttack.SetTurnObjKilled(curObjDetel, atkObj):
|
| | | # return
|
| | |
|
| | | #---玩家处理---
|
| | | if curObjDetel.GetGameObjType() == IPY_GameWorld.gotPlayer:
|
| | |
| | | srcID, srcType = 0, 0
|
| | | if srcObj:
|
| | | srcID, srcType = srcObj.GetID(), srcObj.GetGameObjType()
|
| | | turnFight = TurnAttack.GetTurnFightMgr().getNPCTurnFight(curObj.GetID())
|
| | | turnFight = TurnAttack.GetTurnFightMgr().getTurnFight(curObj.GetTFGUID())
|
| | | if turnFight:
|
| | | clientPack = ChNetSendPack.tagObjPropertyRefreshView()
|
| | | clientPack.ObjID = curObj.GetID()
|
| | |
| | |
|
| | | DoLogic_AttackResult(attacker, defender, useSkill, tick)
|
| | |
|
| | | TurnAttack.OnTurnfightAttackResult(attacker, defender, useSkill)
|
| | | #TurnAttack.OnTurnfightAttackResult(attacker, defender, useSkill)
|
| | | return True
|
| | |
|
| | | #---------------------------------------------------------------------
|
| | |
| | |
|
| | | OnHurtTypeTriggerPassiveSkill(attacker, defender, curSkill, tick)
|
| | | DoLogic_AttackResult(attacker, defender, curSkill, tick)
|
| | | TurnAttack.OnTurnfightAttackResult(attacker, defender, curSkill)
|
| | | #TurnAttack.OnTurnfightAttackResult(attacker, defender, curSkill)
|
| | | return True
|
| | |
|
| | |
|
| | |
| | |
|
| | | DoLogic_AttackResult(attacker, defObj, curSkill, tick)
|
| | |
|
| | | TurnAttack.OnTurnfightAttackResult(attacker, defender, curSkill)
|
| | | #TurnAttack.OnTurnfightAttackResult(attacker, defender, curSkill)
|
| | | return
|
| | |
|
| | | ## 执行群攻攻击
|
| | |
| | | #通知客户端攻击结果
|
| | | __Sync_AttackResult(curNPC, target, curSkill)
|
| | |
|
| | | TurnAttack.OnTurnfightAttackSuccess(curNPC, target, curSkill)
|
| | | #TurnAttack.OnTurnfightAttackSuccess(curNPC, target, curSkill)
|
| | |
|
| | | #技能使用成功
|
| | | if curSkill:
|
| | |
| | |
|
| | | DoLogic_AttackResult(attacker, defObj, curSkill, tick)
|
| | |
|
| | | TurnAttack.OnTurnfightAttackResult(attacker, None, curSkill)
|
| | | #TurnAttack.OnTurnfightAttackResult(attacker, None, curSkill)
|
| | | return True
|
| | |
|
| | |
|
| | |
| | | sendPack.ValueEx = curHurt.GetHurtHPEx()
|
| | | sendPack.RemainHP = curHurt.GetCurHP()
|
| | | sendPack.RemainHPEx = curHurt.GetCurHPEx()
|
| | | turnFight = TurnAttack.GetTurnFightMgr().getNPCTurnFight(attacker.GetID())
|
| | | turnFight = TurnAttack.GetTurnFightMgr().getTurnFight(attacker.GetTFGUID())
|
| | | if turnFight:
|
| | | turnFight.addBatPack(sendPack)
|
| | | return
|
| | |
| | | # m_LastBattleTick = GetGameWorldManager()->GetTick();
|
| | | #===========================================================================
|
| | |
|
| | | turnFight = TurnAttack.GetTurnFightMgr().getNPCTurnFight(attacker.GetID())
|
| | | turnFight = TurnAttack.GetTurnFightMgr().getTurnFight(attacker.GetTFGUID())
|
| | | if turnFight:
|
| | | sendPack = ChNetSendPack.tagUseSkillAttack()
|
| | | sendPack.ObjID = attacker.GetID()
|
New file |
| | |
| | | #!/usr/bin/python
|
| | | # -*- coding: GBK -*-
|
| | | #-------------------------------------------------------------------------------
|
| | | #
|
| | | ##@package BattleObj
|
| | | #
|
| | | # @todo:战斗对象
|
| | | # @author hxp
|
| | | # @date 2025-08-06
|
| | | # @version 1.0
|
| | | #
|
| | | # 详细描述: py自定义的战斗对象,可以是玩家、NPC通用的,废弃原c++的Player及NPC,完全由py自行处理
|
| | | # MMO项目可以curPlayer绑定一个战斗对象,curPlayer仅做为玩家的数据对象,战斗相关统一使用战斗对象
|
| | | #
|
| | | #-------------------------------------------------------------------------------
|
| | | #"""Version = 2025-08-06 18:30"""
|
| | | #-------------------------------------------------------------------------------
|
| | |
|
| | | import GameWorld
|
| | | import PyGameData
|
| | | import TurnAttack
|
| | | import IpyGameDataPY
|
| | | import ChNetSendPack
|
| | | import ShareDefine
|
| | | import ChConfig
|
| | | import ObjPool
|
| | |
|
| | | class HurtObj():
|
| | | ## 伤血统计
|
| | | |
| | | def __init__(self):
|
| | | self.Clear()
|
| | | return
|
| | | |
| | | def Clear(self):
|
| | | self._objID = 0
|
| | | self._hurtTypes = 0 # 本次伤血类型,如闪避、暴击、格挡等,通过二进制或运算得到最终值,支持多种同时出现,如暴击的同时被格挡
|
| | | self._hurtHP = 0 # 伤血值
|
| | | self._lostHP = 0 # 实际掉血值
|
| | | self._curHP = 0 # 更新血量
|
| | | self._suckHP = 0 # 吸血量
|
| | | self._bounceHP = 0 # 反弹血量
|
| | | return
|
| | | |
| | | def GetObjID(self): return self._objID
|
| | | def SetObjID(self, objID): self._objID = objID
|
| | | def GetHurtTypes(self): return self._hurtTypes
|
| | | def SetHurtTypes(self, hurtTypes): self._hurtTypes = hurtTypes
|
| | | def AddHurtType(self, hurtType):
|
| | | ## 添加伤血类型,单次伤害支持多种类型同时出现
|
| | | self._hurtTypes |= pow(2, hurtType)
|
| | | return
|
| | | def HaveHurtType(self, hurtType):
|
| | | ## 判断是否存在某种伤血类型
|
| | | return self._hurtTypes&pow(2, hurtType) |
| | | def GetHurtHP(self): return self._hurtHP
|
| | | def SetHurtHP(self, hurtHP): self._hurtHP = hurtHP
|
| | | def GetLostHP(self): return self._lostHP
|
| | | def SetLostHP(self, lostHP): self._lostHP = lostHP
|
| | | def GetCurHP(self): return self._curHP
|
| | | def SetCurHP(self, curHP): self._curHP = curHP
|
| | | def GetSuckHP(self): return self._suckHP
|
| | | def SetSuckHP(self, suckHP): self._suckHP = suckHP
|
| | | def GetBounceHP(self): return self._bounceHP
|
| | | def SetBounceHP(self, bounceHP): self._bounceHP = bounceHP
|
| | | |
| | | class PyBuff():
|
| | | |
| | | def __init__(self, skillData):
|
| | | self._skillData = skillData
|
| | | self._buffID = 0
|
| | | self._ownerID = 0
|
| | | self._layer = 0
|
| | | self._remainTime = 0
|
| | | self._valueList = []
|
| | | return
|
| | | |
| | | def GetSkillData(self): return self._skillData
|
| | | def GetSkillID(self): return self._skillData.GetSkillID()
|
| | | def GetBuffID(self): return self._buffID
|
| | | def SetBuffID(self, buffID): self._buffID = buffID
|
| | | def GetOwnerID(self): return self._ownerID
|
| | | def SetOwnerID(self, ownerID): self._ownerID = ownerID
|
| | | def GetLayer(self): return self._layer
|
| | | def SetLayer(self, layer): self._layer = layer
|
| | | def GetRemainTime(self): return self._remainTime
|
| | | def SetRemainTime(self, remainTime): self._remainTime = remainTime
|
| | | def SetValueList(self, valueList): self._valueList = valueList
|
| | | def GetValue(self, index):
|
| | | return self._valueList[index] if len(self._valueList) > index else 0
|
| | |
|
| | | class BuffManager():
|
| | | ## 战斗对象buff管理器
|
| | | |
| | | def __init__(self):
|
| | | self._buffList = [] # [PyBuff, ...]
|
| | | self._buffIDDict = {} # {buffID:PyBuff, ...}
|
| | | self._skillTypeIDBuffIDs = {} # 技能TypeID对应的buff {skillTypeID:[buffID, ...], ...}
|
| | | self._buffID = 0 # 该对象的唯一buffID,递增,不同对象buffID可重复,buffID非skillID,不同buffID的skillID可能一样
|
| | | # 该项目设定同一个对象可能同时存在多个相同skillID的buff,独立算CD
|
| | | return
|
| | | |
| | | def ClearBuff(self):
|
| | | poolMgr = ObjPool.GetPoolMgr()
|
| | | for buff in self._buffList:
|
| | | poolMgr.release(buff)
|
| | | self._buffList = []
|
| | | self._buffIDDict = {}
|
| | | self._skillTypeIDBuffIDs = {}
|
| | | self._buffID = 0
|
| | | return
|
| | | |
| | | def GetBuffCount(self): return len(self._buffList)
|
| | | def GetBuffByIndex(self, index):
|
| | | buff = self._buffList[index]
|
| | | #if False:
|
| | | # buff = PyBuff()
|
| | | return buff
|
| | | |
| | | def AddBuff(self, skillID):
|
| | | buff = None
|
| | | skillData = IpyGameDataPY.GetIpyGameData("Skill", skillID)
|
| | | if not skillData:
|
| | | return buff
|
| | | skillTypeID = skillData.GetSkillTypeID()
|
| | | self._buffID += 1
|
| | | |
| | | buff = ObjPool.GetPoolMgr().acquire(PyBuff, skillData)
|
| | | buff.SetBuffID(self._buffID)
|
| | | |
| | | self._buffList.append(buff)
|
| | | self._buffIDDict[self._buffID] = buff
|
| | | if skillTypeID not in self._skillTypeIDBuffIDs:
|
| | | self._skillTypeIDBuffIDs[skillTypeID] = []
|
| | | buffIDs = self._skillTypeIDBuffIDs[skillTypeID]
|
| | | if self._buffID not in buffIDs:
|
| | | buffIDs.append(self._buffID)
|
| | | |
| | | #if False:
|
| | | # buff = PyBuff()
|
| | | return buff
|
| | | |
| | | def GetBuff(self, buffID):
|
| | | buff = None
|
| | | if buffID in self._buffIDDict:
|
| | | buff = self._buffIDDict[buffID]
|
| | | #if False:
|
| | | # buff = PyBuff()
|
| | | return buff
|
| | | |
| | | def FindBuffIDBySkillID(self, skillID):
|
| | | ## 返回该技能ID的所有buffID列表
|
| | | skillData = IpyGameDataPY.GetIpyGameData("Skill", skillID)
|
| | | if not skillData:
|
| | | return []
|
| | | return self.FindBuffIDBySkillTypeID(skillData.GetSkillTypeID())
|
| | | def FindBuffIDBySkillTypeID(self, skillTypeID):
|
| | | ## 返回该技能TypeID的所有buffID列表
|
| | | if skillTypeID not in self._skillTypeIDBuffIDs:
|
| | | return []
|
| | | buffs = []
|
| | | for buffID in self._skillTypeIDBuffIDs[skillTypeID]:
|
| | | if buffID not in self._buffIDDict:
|
| | | continue
|
| | | buffs.append(self._buffIDDict[buffID])
|
| | | return buffs
|
| | | |
| | | class PySkill():
|
| | | |
| | | def __init__(self, skillData):
|
| | | self._skillData = skillData
|
| | | self._remainTime = 0
|
| | | self._batType = 0 # 战斗类型,普通、连击、反击、追击等
|
| | | self._enhanceBySkill = None # 由哪个主技能触发的
|
| | | self._tagObjList = [] # 本次技能目标列表 [BatObj, ...]
|
| | | self._hurtList = [] # 本次伤血列表 [HurtObj, ...]
|
| | | return
|
| | | |
| | | def SetSkillData(self, skillData): self._skillData = skillData
|
| | | def GetSkillID(self): return self._skillData.GetSkillID()
|
| | | def GetSkillTypeID(self): return self._skillData.GetSkillTypeID()
|
| | | def GetSkillMaxLV(self): return self._skillData.GetSkillMaxLV()
|
| | | def GetSkillName(self): return self._skillData.GetSkillName()
|
| | | def GetFuncType(self): return self._skillData.GetFuncType()
|
| | | def GetSkillType(self): return self._skillData.GetSkillType()
|
| | | def GetHurtType(self): return self._skillData.GetHurtType()
|
| | | def GetAtkType(self): return self._skillData.GetAtkType()
|
| | | def GetTagAim(self): return self._skillData.GetTagAim() # 瞄准位置
|
| | | def GetTagFriendly(self): return self._skillData.GetTagFriendly() # 敌我目标
|
| | | def GetTagSelf(self): return self._skillData.GetTagSelf() # 是否含自己
|
| | | def GetTagAffect(self): return self._skillData.GetTagAffect() # 目标细分
|
| | | def GetTagCount(self): return self._skillData.GetTagCount() # 目标个数
|
| | | def GetHappenRate(self): return self._skillData.GetHappenRate() # 释放或添加几率
|
| | | def GetLastTime(self): return self._skillData.GetLastTime() # 持续时间
|
| | | def GetCoolDownTime(self): return self._skillData.GetCoolDownTime()
|
| | | def FindEffectID(self, effID):
|
| | | ## 查找是否有某个效果ID
|
| | | # @return: 大于0该ID所在的效果ID编号; 0-不存在该效果ID
|
| | | for idNum in range(1, 1 + 3):
|
| | | if self.GetEffectID(idNum) == effID:
|
| | | return idNum
|
| | | return 0
|
| | | def GetEffectID(self, idNum):
|
| | | ## 获取效果ID
|
| | | # @param idNum: 效果ID编号,从1开始
|
| | | if idNum == 1:
|
| | | return self._skillData.GetEffectID1()
|
| | | if idNum == 2:
|
| | | return self._skillData.GetEffectID2()
|
| | | if idNum == 3:
|
| | | return self._skillData.GetEffectID3()
|
| | | return 0
|
| | | def GetEffectValue(self, idNum, index):
|
| | | ## 获取效果对应值
|
| | | # @param idNum: 效果ID编号,从1开始
|
| | | # @param index: 值索引,从0开始代表第1个值
|
| | | if idNum <= 0:
|
| | | return 0
|
| | | if idNum == 1:
|
| | | values = self._skillData.GetEffectValues1()
|
| | | elif idNum == 2:
|
| | | values = self._skillData.GetEffectValues2()
|
| | | elif idNum == 3:
|
| | | values = self._skillData.GetEffectValues3()
|
| | | else:
|
| | | return 0
|
| | | return values[index] if len(values) > index else 0
|
| | | def GetConnSkill(self): return self._skillData.GetConnSkill() # 关联技能
|
| | | def GetEnhanceSkillList(self): return self._skillData.GetEnhanceSkillList() # 额外触发的技能ID列表
|
| | | def GetFightPower(self): return self._skillData.GetFightPower()
|
| | | |
| | | ## ---------------------------------- 非技能表内容 ----------------------------------
|
| | | def GetRemainTime(self): return self._remainTime
|
| | | def SetRemainTime(self, remainTime): self._remainTime = remainTime
|
| | | def GetBatType(self): return self._batType
|
| | | def SetBatType(self, batType): self._batType = batType
|
| | | def GetEnhanceBySkill(self): return self._enhanceBySkill
|
| | | def SetEnhanceBySkill(self, enhanceBySkill): self._enhanceBySkill = enhanceBySkill
|
| | | def GetTagObjList(self): return self._tagObjList # 技能目标列表
|
| | | def SetTagObjList(self, tagObjList): self._tagObjList = tagObjList
|
| | | def ClearHurtObj(self):
|
| | | ## 清空伤血统计
|
| | | poolMgr = ObjPool.GetPoolMgr()
|
| | | for hurtObj in self._hurtList:
|
| | | poolMgr.release(hurtObj)
|
| | | self._hurtList = []
|
| | | return
|
| | | def AddHurtObj(self, tagID):
|
| | | ## 添加某个伤血
|
| | | hurtObj = ObjPool.GetPoolMgr().acquire(HurtObj)
|
| | | hurtObj.SetObjID(tagID)
|
| | | self._hurtList.append(hurtObj)
|
| | | return hurtObj
|
| | | def GetHurtObjList(self): return self._hurtList
|
| | | def GetHurtObj(self, tagID):
|
| | | ## 获取某个伤血,如果目标没有在伤血列表里则返回None
|
| | | for hurtObj in self._hurtList:
|
| | | if hurtObj.GetObjID() == tagID:
|
| | | return hurtObj
|
| | | return
|
| | | |
| | | class SkillManager():
|
| | | ## 战斗对象技能管理器
|
| | | |
| | | def __init__(self):
|
| | | self._skillList = [] # 技能列表 [PySkill, ...]
|
| | | self._skillDict = {} # {skillID:PySkill, ...}
|
| | | return
|
| | | |
| | | def SkillReset(self):
|
| | | poolMgr = ObjPool.GetPoolMgr()
|
| | | for skill in self._skillList:
|
| | | poolMgr.release(skill)
|
| | | self._skillList = []
|
| | | self._skillDict = {}
|
| | | return
|
| | | |
| | | def GetSkillCount(self): return len(self._skillList)
|
| | | def GetSkillByIndex(self, index):
|
| | | skill = self._skillList[index]
|
| | | #if False:
|
| | | # skill = PySkill()
|
| | | return skill
|
| | | def FindSkillByID(self, skillID):
|
| | | skill = self._skillDict.get(skillID, None)
|
| | | #if False:
|
| | | # skill = PySkill()
|
| | | return skill
|
| | | def FindSkillByTypeID(self, skillTypeID):
|
| | | skill = None
|
| | | for s in self._skillList:
|
| | | if s.GetSkillTypeID() == skillTypeID:
|
| | | skill = s
|
| | | break
|
| | | #if False:
|
| | | # skill = PySkill()
|
| | | return skill
|
| | | |
| | | def LearnSkillByID(self, skillID):
|
| | | skillData = IpyGameDataPY.GetIpyGameData("Skill", skillID)
|
| | | if not skillData:
|
| | | return
|
| | | if skillID in self._skillDict:
|
| | | return
|
| | | skillTypeID = skillData.GetSkillTypeID()
|
| | | curSkill = self.FindSkillByTypeID(skillTypeID)
|
| | | if curSkill:
|
| | | if curSkill.GetSkillID() >= skillID:
|
| | | return
|
| | | # 升级技能
|
| | | curSkill.SetSkillData(skillData)
|
| | | else:
|
| | | # 学新技能
|
| | | curSkill = ObjPool.GetPoolMgr().acquire(PySkill, skillData)
|
| | | self._skillDict[skillID] = curSkill
|
| | | self._skillList.append(curSkill)
|
| | | return curSkill
|
| | | |
| | | class BatObj():
|
| | | ## 战斗实体对象数据,目前与某个NPCObj绑定
|
| | | |
| | | def __init__(self):
|
| | | self.tfGUID = "" # 所属的某场回合战斗的guid
|
| | | self.objID = 0
|
| | | self.objName = ""
|
| | | self.npcID = 0
|
| | | self.ownerID = 0 # 所属玩家ID,可能为0,0代表非玩家的战斗实体
|
| | | self.heroID = 0
|
| | | self.skinID = 0
|
| | | self.lv = 1
|
| | | self.fightPower = 0
|
| | | self.faction = 0 # 所属阵营,一般只有双方阵营, 1 或 2,发起方默认1
|
| | | self.lineupNum = 1 # 阵容位置编号,一般多V多时有用,通常默认1
|
| | | self.posNum = 0 # 所在阵容站位
|
| | | self._initAttrDict = {} # 初始化时的属性,固定不变,初始化时已经算好的属性 {attrID:value, ...}
|
| | | self._batAttrDict = {} # 实际战斗属性,包含buff层级的实际属性
|
| | | self._skillTempAttrDict = {} # 某次技能释放中临时的属性增减 {attrID:+-value, ...}
|
| | | self._kvDict = {} # 自定义kv字典
|
| | | self._skillUseCntDict = {} # 技能累计使用次数 {skillID:useCnt, ...}
|
| | | self._skillTurnUseCntDict = {} # 技能单回合累计使用次数 {skillID:useCnt, ...}
|
| | | self._skillMgr = ObjPool.GetPoolMgr().acquire(SkillManager)
|
| | | self._buffMgr = ObjPool.GetPoolMgr().acquire(BuffManager)
|
| | | |
| | | # 统计
|
| | | self.hurtStat = 0 # 输出统计
|
| | | self.defStat = 0 # 承伤统计
|
| | | self.cureStat = 0 # 治疗统计
|
| | | return
|
| | | |
| | | def InitBatAttr(self, initAttrDict, initXP=0):
|
| | | ## 初始化战斗属性
|
| | | self._initAttrDict = initAttrDict
|
| | | self._batAttrDict = {}
|
| | | self._batAttrDict.update(initAttrDict)
|
| | | self._batAttrDict[ChConfig.AttrID_XP] = initXP
|
| | | self._batAttrDict[ChConfig.AttrID_HP] = initAttrDict.get(ChConfig.AttrID_MaxHP, 1)
|
| | | self._skillTempAttrDict = {}
|
| | | return
|
| | | def GetTFGUID(self): return self.tfGUID # 所属的某场战斗
|
| | | def SetTFGUID(self, tfGUID): self.tfGUID = tfGUID
|
| | | def GetTurnFight(self): return TurnAttack.GetTurnFightMgr().getTurnFight(self.tfGUID)
|
| | | def GetID(self): return self.objID
|
| | | def GetName(self): return self.objName
|
| | | def SetName(self, name): self.objName = name
|
| | | def GetNPCID(self): return self.npcID # 如果是NPC战斗单位,则该值非0
|
| | | def SetNPCID(self, npcID): self.npcID = npcID # 设置所属的NPCID
|
| | | def GetOwnerID(self): return self.ownerID # 如果是玩家战斗单位,则该值非0,为所属玩家ID
|
| | | def GetHeroID(self): return self.heroID # 仅玩家有值,某个武将ID
|
| | | def GetSkinID(self): return self.heroID # 仅玩家有值,武将皮肤
|
| | | def SetOwnerHero(self, ownerID, heroID, skinID): # 设置所属的玩家及武将
|
| | | self.ownerID = ownerID
|
| | | self.heroID = heroID
|
| | | self.skinID = skinID
|
| | | def SetLineupPos(self, posNum, lineupNum=1):
|
| | | ## 设置阵容所在位置
|
| | | # @param posNum: 在本阵容中的站位
|
| | | # @param lineupNum: 本阵容在本阵营中的站位,一般多V多时有用,默认1
|
| | | self.posNum = posNum
|
| | | self.lineupNum = lineupNum
|
| | | def GetLineupNum(self): return self.lineupNum
|
| | | def GetPosNum(self): return self.posNum
|
| | | def GetFaction(self): return self.faction
|
| | | def SetFaction(self, faction): self.faction = faction
|
| | | def GetFightPower(self): return self.fightPower
|
| | | def SetFightPower(self, fightPower): self.fightPower = fightPower
|
| | | def GetLV(self): return self.lv
|
| | | def SetLV(self, lv): self.lv = lv
|
| | | def GetDictByKey(self, key): return self._kvDict.get(key, 0)
|
| | | def SetDict(self, key, value): self._kvDict[key] = value
|
| | | |
| | | def GetSkillManager(self): return self._skillMgr
|
| | | def GetBuffManager(self):return self._buffMgr
|
| | | |
| | | def GetCanAttack(self):
|
| | | ## 可否被攻击
|
| | | # 无敌buff
|
| | | #if 无敌:
|
| | | # return False
|
| | | return True
|
| | | |
| | | # 战斗属性
|
| | | def GetMaxHP(self): return self._batAttrDict.get(ChConfig.AttrID_MaxHP, 0)
|
| | | def SetMaxHP(self, maxHP): self._batAttrDict[ChConfig.AttrID_MaxHP] = maxHP
|
| | | def GetHP(self): return self._batAttrDict.get(ChConfig.AttrID_HP, 0)
|
| | | def SetHP(self, hp, isNotify=False):
|
| | | self._batAttrDict[ChConfig.AttrID_HP] = hp
|
| | | if isNotify:
|
| | | NotifyObjInfoRefresh(self, ChConfig.AttrID_HP, hp)
|
| | | return
|
| | | def SetHPFull(self, isNotify=True): self.SetHP(self.GetMaxHP())
|
| | | def GetXP(self): return self._batAttrDict.get(ChConfig.AttrID_XP, 0)
|
| | | def SetXP(self, xp, isNotify=True):
|
| | | self._batAttrDict[ChConfig.AttrID_XP] = xp
|
| | | if isNotify:
|
| | | NotifyObjInfoRefresh(self, ChConfig.AttrID_XP, xp)
|
| | | return
|
| | | def GetAtk(self): return self.GetAttrValue(ChConfig.AttrID_Atk)
|
| | | def GetDef(self): return self.GetAttrValue(ChConfig.AttrID_Def)
|
| | | |
| | | def GetAttrValue(self, attrID):
|
| | | value = self._batAttrDict.get(attrID, 0)
|
| | | if attrID in self._skillTempAttrDict:
|
| | | value += self._skillTempAttrDict[attrID] # 支持正负值
|
| | | value = max(1, value)
|
| | | return value
|
| | | def AddSkillTempAttr(self, attrID, value):
|
| | | ## 增加技能临时属性,支持正负值
|
| | | # @param value: 正值-加属性;负值-减属性
|
| | | self._skillTempAttrDict[attrID] = self._skillTempAttrDict.get(attrID, 0) + value
|
| | | def ClearSkillTempAttr(self): self._skillTempAttrDict = {}
|
| | | |
| | | def GetSkillUseCnt(self, skillID): return self._skillUseCntDict.get(skillID, 0)
|
| | | def GetSkillTurnUseCnt(self, skillID): return self._skillTurnUseCntDict.get(skillID, 0)
|
| | | def AddSkillUseCnt(self, skillID):
|
| | | self._skillUseCntDict[skillID] = self._skillUseCntDict.get(skillID, 0) + 1
|
| | | self._skillTurnUseCntDict[skillID] = self._skillTurnUseCntDict.get(skillID, 0) + 1
|
| | | |
| | | def StatHurtValue(self, hurtValue):
|
| | | ## 统计输出
|
| | | self.hurtStat += hurtValue
|
| | | return self.hurtStat
|
| | | |
| | | def StatDefValue(self, lostHP):
|
| | | ## 统计承伤
|
| | | self.defStat += lostHP
|
| | | return self.defStat
|
| | | |
| | | def StatCureValue(self, cureValue):
|
| | | ## 统计治疗
|
| | | self.cureStat += cureValue
|
| | | return self.cureStat
|
| | | |
| | | def TurnReset(self):
|
| | | ## 回合重置
|
| | | self._skillTurnUseCntDict = {}
|
| | | |
| | | def ResetBatObj(self, isReborn=True):
|
| | | ## 重置战斗相关
|
| | | # @param isReborn: 死亡的是否复活
|
| | | |
| | | # 重置统计
|
| | | self.hurtStat = 0
|
| | | self.defStat = 0
|
| | | self.cureStat = 0
|
| | | |
| | | if self.GetHP() <= 0 and not isReborn:
|
| | | return
|
| | | |
| | | # 清除buff
|
| | | |
| | | # 回满血
|
| | | self.SetHPFull()
|
| | | |
| | | # 重置怒气
|
| | | initXP = IpyGameDataPY.GetFuncCfg("AngerXP", 1)
|
| | | self.SetXP(initXP)
|
| | | return
|
| | | |
| | | |
| | | class BattleObjMgr():
|
| | | ## 战斗对象管理器
|
| | | |
| | | def __init__(self):
|
| | | self._newID = 0 # 管理创建新的实例ID
|
| | | self._freeIDList = []
|
| | | self.batObjDict = {} # 战斗单位 {objID:BatObj, ...}
|
| | | return
|
| | | |
| | | def __getNewObjID(self):
|
| | | while self._freeIDList:
|
| | | objID = self._freeIDList.pop(0)
|
| | | if objID not in self.batObjDict:
|
| | | return objID
|
| | | |
| | | maxID = 100000
|
| | | if self._newID >= maxID:
|
| | | self._newID = 0
|
| | | while self._newID < maxID:
|
| | | self._newID += 1
|
| | | if self._newID not in self.batObjDict:
|
| | | return self._newID
|
| | | GameWorld.ErrLog("__getNewObjID error.")
|
| | | return 0
|
| | | |
| | | def addBatObj(self):
|
| | | ## 添加战斗单位
|
| | | newBatObj = None
|
| | | newObjID = self.__getNewObjID()
|
| | | if not newObjID:
|
| | | return newBatObj
|
| | | newBatObj = ObjPool.GetPoolMgr().acquire(BatObj)
|
| | | newBatObj.objID = newObjID
|
| | | self.batObjDict[newObjID] = newBatObj
|
| | | GameWorld.DebugLog("添加战斗单位: objID=%s" % (newObjID))
|
| | | if False:
|
| | | newBatObj = BatObj(None, 0)
|
| | | return newBatObj
|
| | | |
| | | def getBatObj(self, objID):
|
| | | batObj = None
|
| | | if objID in self.batObjDict:
|
| | | batObj = self.batObjDict[objID]
|
| | | elif False:
|
| | | batObj = BatObj(None, 0)
|
| | | return batObj
|
| | | |
| | | def delBatObj(self, objID):
|
| | | if objID not in self.batObjDict:
|
| | | return
|
| | | batObj = self.batObjDict.pop(objID)
|
| | | if not batObj:
|
| | | return
|
| | | objID = batObj.objID
|
| | | GameWorld.DebugLog("回收战斗单位: objID=%s" % (objID))
|
| | | turnFight = batObj.GetTurnFight()
|
| | | if turnFight:
|
| | | # //04 07 NPC消失#tagNPCDisappear 此处通知消失,与回合制死亡区分
|
| | | clientPack = ChNetSendPack.tagNPCDisappear()
|
| | | clientPack.NPCID = [objID]
|
| | | clientPack.Count = len(clientPack.NPCID)
|
| | | turnFight.addBatPack(clientPack)
|
| | | |
| | | # 最后回收对象
|
| | | ObjPool.GetPoolMgr().release(batObj)
|
| | | if objID not in self._freeIDList: # 回收ID,重复利用
|
| | | self._freeIDList.append(objID)
|
| | | return
|
| | | |
| | | def GetBatObjMgr():
|
| | | batObjMgr = PyGameData.g_batObjMgr
|
| | | if not batObjMgr:
|
| | | batObjMgr = BattleObjMgr()
|
| | | PyGameData.g_batObjMgr = batObjMgr
|
| | | return batObjMgr
|
| | |
|
| | | def OnMinute():
|
| | | GameWorld.Log("战斗单位数量: %s" % len(GetBatObjMgr().batObjDict))
|
| | | return
|
| | |
|
| | | def NotifyObjInfoRefresh(batObj, attrID, value):
|
| | | ##0418通知对象属性刷新
|
| | | if attrID not in ChConfig.CDBRefresh_AttrIDDict:
|
| | | return
|
| | | refreshType, isBig = ChConfig.CDBRefresh_AttrIDDict[attrID]
|
| | | turnFight = TurnAttack.GetTurnFightMgr().getTurnFight(batObj.GetTFGUID())
|
| | | if not turnFight:
|
| | | return
|
| | | clientPack = ObjPool.GetPoolMgr().acquire(ChNetSendPack.tagObjInfoRefresh)
|
| | | clientPack.ObjID = batObj.GetID()
|
| | | clientPack.RefreshType = refreshType
|
| | | if isBig:
|
| | | clientPack.Value = value % ShareDefine.Def_PerPointValue
|
| | | clientPack.ValueEx = value / ShareDefine.Def_PerPointValue
|
| | | else:
|
| | | clientPack.Value = value
|
| | | clientPack.ValueEx = 0
|
| | | turnFight.addBatPack(clientPack)
|
| | | return
|
| | |
| | | import NPCCommon
|
| | | import ShareDefine
|
| | | import PyGameData
|
| | | import IPY_GameWorld
|
| | | import ItemControler
|
| | | import SkillCommon
|
| | | import SkillShell
|
| | | import AttackCommon
|
| | | import FBLogic
|
| | | import BattleObj
|
| | | import TurnSkill
|
| | | import TurnBuff
|
| | | import ObjPool
|
| | |
|
| | | import random
|
| | | import time
|
| | |
| | | FightState_Award, # 4 结算奖励
|
| | | FightState_Over, # 5 结束状态,无特殊意义,仅代表所有处理结束了,与Start对应
|
| | | ) = range(6)
|
| | |
|
| | | Def_FactionA = 1
|
| | | Def_FactionB = 2
|
| | |
|
| | | |
| | | class BatLineup():
|
| | | ## 战斗阵容
|
| | |
|
| | | def __init__(self, faction, num, fightMgr):
|
| | | self.fightMgr = fightMgr
|
| | | def __init__(self, faction, num, turnFight):
|
| | | self.turnFight = turnFight # TurnFight
|
| | | self.faction = faction # 所属阵营
|
| | | self.num = num # 该阵容所在阵营中的编号,不同阵营可重复,多V多
|
| | | self.ownerID = 0 # 阵容所属玩家ID,可能为0,0代表非玩家阵容
|
| | | self.npcPosDict = {} # 阵容NPC {站位编号:curNPC, ...}, 站位编号小于0为非主战单位,如主公、红颜等
|
| | | self.npcObjIDDict = {} # NPC实例ID字典 {objID:curNPC, ...}
|
| | | self.shapeType = 0 # 阵型
|
| | | self.actionNum = ActionNumStart # 行动位置,从1开始
|
| | | self.lordAttrDict = {} # 主公属性
|
| | | self.npcAttrDict = {} # 阵容NPC属性 {npcID:{attrID:value, ...}, ...}
|
| | | self.fightPower = 0 # 阵容总战力
|
| | | |
| | | # 战斗统计
|
| | | self.hurtStatDict = {} # 输出统计 {objID:totalValue, ...}
|
| | | self.defStatDict = {} # 承伤统计 {objID:totalValue, ...}
|
| | | self.cureStatDict = {} # 治疗统计 {objID:totalValue, ...}
|
| | | self.posObjIDDict = {} # 站位对应战斗实体 {站位编号:batObjID, ...}, 站位编号小于0为非主战单位,如主公、红颜等
|
| | | self.actionNum = ActionNumStart # 行动位置,从1开始
|
| | | return
|
| | |
|
| | | def getGUID(self): return self.fightMgr.guid
|
| | | def getPlayerID(self): return self.fightMgr.playerID # 发起的玩家ID
|
| | | def getPlayerID(self): return self.turnFight.playerID # 发起的玩家ID
|
| | |
|
| | | def isEmpty(self): return not self.npcPosDict
|
| | | def isEmpty(self): return not self.posObjIDDict
|
| | |
|
| | | def setLineup(self, lineupInfo):
|
| | | ## 设置阵容
|
| | | # @param lineupInfo: 阵容信息
|
| | | self.clearLineup()
|
| | | self.ownerID = lineupInfo.get("PlayerID", 0) # 阵容所属的玩家ID
|
| | | self.shapeType = lineupInfo.get("Shape", 0)
|
| | | self.lordAttrDict = lineupInfo.get("LordAttrDict", {})
|
| | | self.shapeType = lineupInfo.get("ShapeType", 0)
|
| | | self.fightPower = lineupInfo.get("FightPower", 0)
|
| | | SummonLineupObjs(self, self.faction, self.num, lineupInfo, self.getPlayerID())
|
| | | return
|
| | | |
| | | def refreshFightPower(self):
|
| | | ## 刷新阵容总战力
|
| | | if self.fightPower:
|
| | | return self.fightPower
|
| | | |
| | | return self.fightPower
|
| | | |
| | | def __resetStat(self):
|
| | | ## 重置战斗统计
|
| | | self.actionNum = ActionNumStart
|
| | | self.hurtStatDict = {}
|
| | | self.defStatDict = {}
|
| | | self.cureStatDict = {}
|
| | | return
|
| | | |
| | | def __resetAttrState(self, isReborn=True):
|
| | | ## 重置属性状态
|
| | | # @param isReborn: 是否复活
|
| | | initXP = IpyGameDataPY.GetFuncCfg("AngerXP", 1)
|
| | | for curNPC in self.npcPosDict.values():
|
| | | if not curNPC:
|
| | | continue
|
| | | if GameObj.GetHP(curNPC) <= 0 and not isReborn:
|
| | | continue
|
| | | # 回满血,清除buff
|
| | | GameObj.SetHPFull(curNPC, False)
|
| | | # 重置怒气
|
| | | GameObj.SetXP(curNPC, initXP, False)
|
| | | # ...
|
| | | |
| | | return
|
| | |
|
| | | def resetLineup(self, isReborn=True):
|
| | | ## 重置阵容
|
| | | self.__resetAttrState(isReborn)
|
| | | self.__resetStat()
|
| | | batObjMgr = BattleObj.GetBatObjMgr()
|
| | | for objID in self.posObjIDDict.values():
|
| | | batObj = batObjMgr.getBatObj(objID)
|
| | | if not batObj:
|
| | | continue
|
| | | batObj.ResetBatObj(isReborn)
|
| | | return
|
| | |
|
| | | def clearLineup(self):
|
| | | ## 清除阵容
|
| | | if not self.npcPosDict:
|
| | | if not self.posObjIDDict:
|
| | | return
|
| | | for curNPC in self.npcPosDict.values():
|
| | | if not curNPC:
|
| | | continue
|
| | | NPCCommon.SetDeadEx(curNPC)
|
| | | self.npcPosDict = {}
|
| | | self.npcObjIDDict = {}
|
| | | self.npcAttrDict = {}
|
| | | batObjMgr = BattleObj.GetBatObjMgr()
|
| | | for objID in self.posObjIDDict.values():
|
| | | batObjMgr.delBatObj(objID)
|
| | | self.posObjIDDict = {}
|
| | | self.fightPower = 0
|
| | | self.__resetStat()
|
| | | return
|
| | | |
| | | def statHurtValue(self, objID, hurtValue):
|
| | | ## 统计输出
|
| | | if objID not in self.npcObjIDDict:
|
| | | return
|
| | | updValue = self.hurtStatDict.get(objID, 0) + hurtValue
|
| | | self.hurtStatDict[objID] = updValue
|
| | | return updValue
|
| | | |
| | | def statDefValue(self, objID, lostHP):
|
| | | ## 统计承伤
|
| | | if objID not in self.npcObjIDDict:
|
| | | return
|
| | | updValue = self.defStatDict.get(objID, 0) + lostHP
|
| | | self.defStatDict[objID] = updValue
|
| | | return updValue
|
| | | |
| | | def statCureValue(self, objID, cureValue):
|
| | | ## 统计治疗
|
| | | if objID not in self.npcObjIDDict:
|
| | | return
|
| | | updValue = self.cureStatDict.get(objID, 0) + cureValue
|
| | | self.cureStatDict[objID] = updValue
|
| | | return updValue
|
| | |
|
| | | class BatFaction():
|
| | | ## 战斗阵营
|
| | |
|
| | | def __init__(self, faction, fightMgr):
|
| | | self.fightMgr = fightMgr
|
| | | def __init__(self, faction, turnFight):
|
| | | self.turnFight = turnFight # TurnFight
|
| | | self.faction = faction
|
| | | self.lineupDict = {} # 该阵营所有阵容信息 {编号:BatLineup, ...}
|
| | | return
|
| | |
| | | if num in self.lineupDict:
|
| | | lineup = self.lineupDict[num]
|
| | | else:
|
| | | lineup = BatLineup(self.faction, num, self.fightMgr)
|
| | | lineup = BatLineup(self.faction, num, self.turnFight)
|
| | | self.lineupDict[num] = lineup
|
| | | return lineup
|
| | |
|
| | |
| | |
|
| | | self.startTime = 0 # 开始时间戳,支持毫秒小数
|
| | | self.costTime = 0 # 单场战斗总耗时,支持毫秒小数
|
| | | |
| | | #玩家武将行动后击杀目标
|
| | | self.playerKillObjIDList = [] # [objID, ...]
|
| | | return
|
| | |
|
| | | def setTurn(self, mapID, funcLineID, turnMax, isNeedReport=False, msgDict={}):
|
| | |
| | | if not lineupInfo:
|
| | | continue
|
| | | batLineup.setLineup(lineupInfo)
|
| | | batLineup.refreshFightPower()
|
| | | return
|
| | |
|
| | | def sortActionQueue(self):
|
| | |
| | | for batFaction in self.factionDict.values():
|
| | | faction = batFaction.faction
|
| | | for num, batLineup in batFaction.lineupDict.items():
|
| | | fightPower = batLineup.refreshFightPower()
|
| | | fightPower = batLineup.fightPower
|
| | | sortValue = -(faction * 10 + num)
|
| | | sortList.append([fightPower, sortValue, faction, num])
|
| | | sortList.sort(reverse=True) # 战力高的先手
|
| | |
| | | GameWorld.DebugLog("阵容行动顺序[f, n]: %s" % self.actionSortList)
|
| | | return
|
| | |
|
| | | def getBatFaction(self, faction=Def_FactionA):
|
| | | def getBatFaction(self, faction=ChConfig.Def_FactionA):
|
| | | ## 默认阵营1
|
| | | batFaction = None
|
| | | if faction in self.factionDict:
|
| | |
| | | if self.winFaction:
|
| | | return self.winFaction
|
| | |
|
| | | batObjMgr = BattleObj.GetBatObjMgr()
|
| | | for faction, batFaction in self.factionDict.items():
|
| | | allKilled = True
|
| | | for batLineup in batFaction.lineupDict.values():
|
| | | if not allKilled:
|
| | | break
|
| | | for posNum, curNPC in batLineup.npcPosDict.items():
|
| | | for posNum, objID in batLineup.posObjIDDict.items():
|
| | | if posNum <= 0:
|
| | | # 非主战位置不判断
|
| | | continue
|
| | | if GameObj.GetHP(curNPC) > 0:
|
| | | batObj = batObjMgr.getBatObj(objID)
|
| | | if not batObj:
|
| | | continue
|
| | | if batObj.GetHP() > 0:
|
| | | allKilled = False
|
| | | break
|
| | |
|
| | | if allKilled:
|
| | | self.winFaction = Def_FactionA if faction == Def_FactionB else Def_FactionA
|
| | | self.winFaction = ChConfig.Def_FactionA if faction == ChConfig.Def_FactionB else ChConfig.Def_FactionA
|
| | | DoTurnFightOver(self.guid)
|
| | | return self.winFaction
|
| | |
|
| | |
| | | clientPack.Msg = msg
|
| | | clientPack.Len = len(clientPack.Msg)
|
| | | clientPack.FactionList = []
|
| | | |
| | | batObjMgr = BattleObj.GetBatObjMgr()
|
| | | for faction in self.factionDict.keys():
|
| | | batFaction = self.getBatFaction(faction)
|
| | | tfFaction = ChPyNetSendPack.tagSCTurnFightFaction()
|
| | |
| | | tfLineup.OwnerID = batLineup.ownerID
|
| | | tfLineup.ShapeType = batLineup.shapeType
|
| | | tfLineup.ObjList = []
|
| | | for posNum, curNPC in batLineup.npcPosDict.items():
|
| | | for posNum, objID in batLineup.posObjIDDict.items():
|
| | | batObj = batObjMgr.getBatObj(objID)
|
| | | if not batObj:
|
| | | continue
|
| | | tfObj = ChPyNetSendPack.tagSCTurnFightObj()
|
| | | tfObj.ObjID = curNPC.GetID()
|
| | | tfObj.NPCID = curNPC.GetNPCID()
|
| | | tfObj.HeroID = curNPC.GetDictByKey(ChConfig.Def_Obj_Dict_HeroID)
|
| | | tfObj.SkinID = curNPC.GetDictByKey(ChConfig.Def_Obj_Dict_SkinID)
|
| | | tfObj.HP = curNPC.GetHP()
|
| | | tfObj.HPEx = curNPC.GetHPEx()
|
| | | tfObj.MaxHP = curNPC.GetMaxHP()
|
| | | tfObj.MaxHPEx = curNPC.GetMaxHPEx()
|
| | | tfObj.LV = NPCCommon.GetNPCLV(curNPC)
|
| | | tfObj.ObjID = batObj.GetID()
|
| | | tfObj.NPCID = batObj.GetNPCID()
|
| | | tfObj.HeroID = batObj.GetHeroID()
|
| | | tfObj.SkinID = batObj.GetSkinID()
|
| | | tfObj.HP = batObj.GetHP() % ChConfig.Def_PerPointValue
|
| | | tfObj.HPEx = batObj.GetHP() / ChConfig.Def_PerPointValue
|
| | | tfObj.MaxHP = batObj.GetMaxHP() % ChConfig.Def_PerPointValue
|
| | | tfObj.MaxHPEx = batObj.GetMaxHP() / ChConfig.Def_PerPointValue
|
| | | tfObj.LV = batObj.GetLV()
|
| | | tfObj.PosNum = posNum
|
| | | tfObj.AngreXP = GameObj.GetXP(curNPC)
|
| | | tfObj.AngreXP = batObj.GetXP()
|
| | | tfLineup.ObjList.append(tfObj)
|
| | | tfLineup.ObjCnt = len(tfLineup.ObjList)
|
| | | tfFaction.LineupList.append(tfLineup)
|
| | |
| | | self.addBatPack(clientPack)
|
| | | return
|
| | |
|
| | | def syncObjAction(self, turnNum, objType, objID):
|
| | | def syncObjAction(self, turnNum, objID):
|
| | | clientPack = ChPyNetSendPack.tagMCTurnFightObjAction()
|
| | | clientPack.Clear()
|
| | | clientPack.TurnNum = turnNum
|
| | |
| | | # 有玩家的统一每个包单独发送,同样也支持战报统计
|
| | | if self.curPlayer:
|
| | | NetPackCommon.SendFakePack(self.curPlayer, clientPack)
|
| | | else:
|
| | | ObjPool.GetPoolMgr().release(clientPack)
|
| | | return
|
| | |
|
| | | class TurnFightMgr():
|
| | |
| | |
|
| | | def __init__(self):
|
| | | self.turnFightDict = {} # {guid:TurnFight, ...}
|
| | | self.npcGUIDDict = {} # npc所属的某场战斗guid {objID:guid, ...}
|
| | | return
|
| | |
|
| | | def addTurnFight(self, mapID, funcLineID=0, playerID=0):
|
| | |
| | | elif False:
|
| | | tf = TurnFight()
|
| | | return tf
|
| | | |
| | | def getNPCTurnFight(self, objID):
|
| | | ## 获取NPC所在的回合战斗,如果该npc不属于某场回合战斗则返回None
|
| | | tf = None
|
| | | if objID in self.npcGUIDDict:
|
| | | guid = self.npcGUIDDict[objID]
|
| | | if guid in self.turnFightDict:
|
| | | tf = self.turnFightDict[guid]
|
| | | if not tf and False:
|
| | | tf = TurnFight()
|
| | | return tf
|
| | | |
| | | def setNPCGUID(self, objID, guid):
|
| | | ## 设置NPC所属回合战斗guid
|
| | | self.npcGUIDDict[objID] = guid
|
| | | GameWorld.DebugLog("设置NPC所属回合战斗guid: %s,%s" % (objID, guid))
|
| | | return
|
| | | def delNPCGUID(self, objID):
|
| | | guid = self.npcGUIDDict.pop(objID, None)
|
| | | GameWorld.DebugLog("删除NPC所属回合战斗guid: %s,%s" % (objID, guid))
|
| | | return
|
| | |
|
| | | def GetTurnFightMgr():
|
| | | tfMgr = None
|
| | |
| | | ## 当前战斗是否关卡boss
|
| | | return self.turnFight.mapID == ChConfig.Def_FBMapID_MainBoss
|
| | |
|
| | | def clear(self):
|
| | | self.turnFight.clearFight()
|
| | | return
|
| | | |
| | | def GetMainFightMgr(curPlayer):
|
| | | ## 获取主线战斗管理
|
| | | olPlayer = PlayerOnline.GetOnlineMgr().GetOnlinePlayer(curPlayer)
|
| | |
| | | % (chapterID, levelNum, nowChapterID, fixNowValue), curPlayer.GetPlayerID())
|
| | | return
|
| | |
|
| | | def GetPlayerLineupByCache(playerID, lineupID):
|
| | | def GetPlayerLineupInfoByCache(playerID, lineupID):
|
| | | ## 获取玩家阵容信息 - 根据玩家查看缓存
|
| | | return {}
|
| | | lineupInfo = {}
|
| | | return lineupInfo
|
| | |
|
| | | def GetPlayerLineup(curPlayer, lineupID):
|
| | | ## 获取玩家阵容信息
|
| | | def GetPlayerLineupInfo(curPlayer, lineupID):
|
| | | ## 获取玩家阵容信息,可用于战斗或查看缓存,因为可能取玩家的缓存进行对战,所以统一使用json格式,前端通用
|
| | | # @param lineupID: 阵容ID
|
| | | # @return: 阵容全部信息json字典,前端通用格式
|
| | |
|
| | | playerID = curPlayer.GetPlayerID()
|
| | | lineup = PlayerOnline.GetOnlinePlayer(curPlayer).GetLineup(lineupID)
|
| | |
|
| | | # 武将
|
| | | lineupInfo = {"PlayerID":playerID, "FightPower":lineup.fightPower, "ShapeType":lineup.shapeType}
|
| | | heroDict = {}
|
| | | heroCount = 0
|
| | | curPack = curPlayer.GetItemManager().GetPack(ShareDefine.rptHero)
|
| | | for index in range(curPack.GetCount()):
|
| | | heroItem = curPack.GetAt(index)
|
| | | if not heroItem or heroItem.IsEmpty():
|
| | | continue
|
| | | lineupCount = heroItem.GetUserAttrCount(ShareDefine.Def_IudetHeroLineup)
|
| | | if not lineupCount:
|
| | | continue
|
| | | posNum = 0 # վλ
|
| | | for lpIndex in range(lineupCount):
|
| | | lineupValue = heroItem.GetUserAttrByIndex(ShareDefine.Def_IudetHeroLineup, lpIndex)
|
| | | #阵容类型*10000+阵型类型*100+位置编号
|
| | | if lineupValue / 10000 != lineupID:
|
| | | continue
|
| | | posNum = lineupValue % 100
|
| | | break
|
| | | |
| | | if not posNum:
|
| | | continue
|
| | | |
| | | heroID = heroItem.GetItemTypeID()
|
| | | heroIpyData = IpyGameDataPY.GetIpyGameData("Hero", heroID)
|
| | | if not heroIpyData:
|
| | | continue
|
| | | skinIDList = heroIpyData.GetSkinIDList()
|
| | | skinIndex = heroItem.GetUserAttr(ShareDefine.Def_IudetHeroSkin)
|
| | | if skinIndex < 0 or skinIndex >= len(skinIDList):
|
| | | continue
|
| | | skinID = skinIDList[skinIndex]
|
| | | for posNum in lineup.lineupHeroDict.keys():
|
| | | hero = lineup.GetLineupHero(posNum)
|
| | | heroID = hero.heroID
|
| | | itemIndex = hero.itemIndex
|
| | | userData = ""
|
| | | heroLV = 1
|
| | | if itemIndex >= 0 and itemIndex < curPack.GetCount():
|
| | | heroItem = curPack.GetAt(itemIndex)
|
| | | if heroItem and not heroItem.IsEmpty():
|
| | | userData = heroItem.GetUserData()
|
| | | heroLV = heroItem.GetUserAttr(ShareDefine.Def_IudetHeroLV)
|
| | | |
| | | skillIDlist = []
|
| | | skillIDlist += hero.heroSkillIDList
|
| | | heroDict[str(posNum)] = {
|
| | | "HeroID":heroID,
|
| | | "SkinID":skinID,
|
| | | "Data":heroItem.GetUserData(),
|
| | | "SkinID":hero.skinID,
|
| | | "LV":heroLV,
|
| | | "Data":userData,
|
| | | "FightPower":hero.fightPower,
|
| | | "AttrDict":{str(k):v for k, v in hero.heroBatAttrDict.items() if v > 0},
|
| | | "SkillIDList":skillIDlist,
|
| | | }
|
| | | |
| | | heroCount += 1
|
| | | if heroCount >= ShareDefine.LineupObjMax:
|
| | | break
|
| | | |
| | | if not heroDict:
|
| | | return {}
|
| | | lineupInfo.update({"Hero":heroDict})
|
| | |
|
| | | # 主公属性
|
| | | lordAttrDict = PlayerControl.GetLordAttr(curPlayer)
|
| | | |
| | | # 其他
|
| | | |
| | | lineupInfo = {"PlayerID":playerID, "LordAttrDict":lordAttrDict, "Hero":heroDict}
|
| | | return lineupInfo
|
| | |
|
| | | def GetNPCLineup(lineupID):
|
| | | def GetNPCLineupInfo(lineupID):
|
| | | ## 获取NPC阵容信息
|
| | | # @param lineupID: 阵容ID
|
| | | # @return: 阵容全部信息json字典,前端通用格式
|
| | |
| | | npcID = getattr(ipyData, "GetPosNPCID%s" % posNum)()
|
| | | if not npcID:
|
| | | continue
|
| | | npcData = NPCCommon.GetNPCDataPy(npcID)
|
| | | if not npcData:
|
| | | continue
|
| | | batAttrDict = {ChConfig.AttrID_Atk:npcData.GetAtk(), ChConfig.AttrID_Def:npcData.GetDef(), ChConfig.AttrID_MaxHP:npcData.GetMaxHP(), |
| | | ChConfig.AttrID_FinalDamPer:npcData.GetFinalDamPer(), ChConfig.AttrID_FinalDamPerDef:npcData.GetFinalDamPerDef(), |
| | | ChConfig.AttrID_MissRate:npcData.GetMissRate(), ChConfig.AttrID_MissRateDef:npcData.GetMissRateDef(), |
| | | ChConfig.AttrID_SuperHitRate:npcData.GetSuperHitRate(), ChConfig.AttrID_SuperHitRateDef:npcData.GetSuperHitRateDef(), |
| | | ChConfig.AttrID_StunRate:npcData.GetStunRate(), ChConfig.AttrID_StunRateDef:npcData.GetStunRateDef(), |
| | | ChConfig.AttrID_ComboRate:npcData.GetComboRate(), ChConfig.AttrID_ComboRateDef:npcData.GetComboRateDef(), |
| | | ChConfig.AttrID_ParryRate:npcData.GetParryRate(), ChConfig.AttrID_ParryRateDef:npcData.GetParryRateDef(), |
| | | ChConfig.AttrID_SuckHPPer:npcData.GetSuckHPPer(), ChConfig.AttrID_SuckHPPerDef:npcData.GetSuckHPPerDef(), |
| | | }
|
| | | batAttrDict.update(npcData.GetSpecAttrInfo())
|
| | | skillIDList = [] + npcData.GetSkillIDList()
|
| | | heroDict[str(posNum)] = {"NPCID":npcID, |
| | | "AttrDict":{str(k):v for k, v in batAttrDict.items() if v > 0},
|
| | | "SkillIDList":skillIDList
|
| | | }
|
| | |
|
| | | heroDict[str(posNum)] = {"NPCID":npcID}
|
| | | |
| | | lineupInfo = {"Hero":heroDict}
|
| | | lineupInfo = {"NPCLineupID":lineupID, "Hero":heroDict}
|
| | | return lineupInfo
|
| | |
|
| | | def SummonLineupObjs(batLineup, faction, num, lineupInfo, playerID=0):
|
| | |
| | | @param lineupInfo: 阵容信息
|
| | | @param playerID: 发起的玩家ID,系统场次为0
|
| | | '''
|
| | | |
| | | '''关于视野层级说明 sightLevel
|
| | | 玩家发起的战斗视野层级只能用玩家ID,才能达到只通知该玩家的效果
|
| | | 但是由于同个玩家可能同时存在多场战斗,如主线战斗 + 其他战斗,所以视野层级只能用作仅通知该玩家的作用,
|
| | | 不能用于处理NPC视野来遍历伤害对象等,因为不同战场的NPC视野层级可能相同,对于同场战斗NPC的遍历处理只能用 turnFight 管理遍历
|
| | | 鉴于视野层级仅用于通知的作用,故系统场次理论上可以只用一个视野层级,但是为了减少不必要的问题,系统场次的视野层级还是尽量区分开来
|
| | | 这里暂时用时间戳的后4位来做短时间内的理论上唯一视野层级
|
| | | '''
|
| | | GameWorld.DebugLog("SummonLineupObjs faction:%s,num:%s,lineupInfo=%s" % (faction, num, lineupInfo), playerID)
|
| | | if playerID:
|
| | | curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
|
| | | if not curPlayer:
|
| | | return
|
| | | posX, posY = curPlayer.GetPosX(), curPlayer.GetPosY()
|
| | | sightLevel = playerID
|
| | |
|
| | | # 开发过程中可以先开启视野层级及视野,方便检查战斗相关是否有遗漏
|
| | | if curPlayer.GetSightLevel() != sightLevel:
|
| | | PlayerControl.SetPlayerSightLevel(curPlayer, sightLevel)
|
| | | sight = ChConfig.Def_PlayerSight_Default * 5
|
| | | if curPlayer.GetSight() != sight:
|
| | | PlayerControl.SetSight(curPlayer, sight)
|
| | | else:
|
| | | gameMap = GameWorld.GetMap()
|
| | | posX, posY = gameMap.GetRebornMapX(), gameMap.GetRebornMapY() # 系统战斗默认取当前地图的复活点,需要优化
|
| | | sightLevel = 2000000000 + int(time.time()) % 10000
|
| | | |
| | | GameWorld.DebugLog("sightLevel=%s,pos=(%s,%s)" % (sightLevel, posX, posY), playerID)
|
| | | |
| | | tfGUID = batLineup.turnFight.guid
|
| | | lineupPlayerID = lineupInfo.get("PlayerID", 0) # 阵容所属玩家ID
|
| | | heroDict = lineupInfo.get("Hero", {})
|
| | | tick = GameWorld.GetGameWorld().GetTick()
|
| | |
|
| | | batObjMgr = BattleObj.GetBatObjMgr()
|
| | | initXP = IpyGameDataPY.GetFuncCfg("AngerXP", 1)
|
| | | baseAtkSkillIDList = IpyGameDataPY.GetFuncEvalCfg("ParryCfg", 3)
|
| | | tfMgr = GetTurnFightMgr()
|
| | | space = 3
|
| | | atkBackSkillIDList = IpyGameDataPY.GetFuncEvalCfg("ParryCfg", 3)
|
| | | for posNumKey, heroInfo in heroDict.items():
|
| | | posNum = int(posNumKey)
|
| | |
|
| | | heroID, skinID = 0, 0
|
| | | baseAtkSkillID = 0 # 基础普攻ID
|
| | | skillIDList = []
|
| | | npcID, heroID, skinID = 0, 0, 0
|
| | | atkBackSkillID = 0 # 反击技能ID
|
| | | fightPower = 0
|
| | | skillIDList = [] # 战斗对象可能改变属性或技能,重新创建,防止误修改来源值
|
| | | attrDict = {}
|
| | | skillIDList += heroInfo.get("SkillIDList", [])
|
| | | attrDict.update(heroInfo.get("AttrDict", {}))
|
| | | objName = ""
|
| | | if lineupPlayerID:
|
| | | heroID = heroInfo.get("HeroID", 0)
|
| | | skinID = heroInfo.get("SkinID", 0)
|
| | | npcID = FighterNPCID
|
| | | lv = heroInfo.get("LV", 1)
|
| | | fightPower = heroInfo.get("FightPower", 0)
|
| | | heroIpyData = IpyGameDataPY.GetIpyGameData("Hero", heroID)
|
| | | if not heroIpyData:
|
| | | continue
|
| | | normalSkillID = heroIpyData.GetNormalSkillID()
|
| | | angerSkillID = heroIpyData.GetAngerSkillID()
|
| | | skillIDList += [normalSkillID, angerSkillID]
|
| | | atkDistType = heroIpyData.GetAtkDistType()
|
| | | objName = heroIpyData.GetName()
|
| | | else:
|
| | | npcID = heroInfo.get("NPCID", 0)
|
| | | npcDataEx = NPCCommon.GetNPCDataEx(npcID)
|
| | | npcDataEx = NPCCommon.GetNPCDataPy(npcID)
|
| | | if not npcDataEx:
|
| | | continue
|
| | | skillIDList += npcDataEx.GetSkillIDList()
|
| | | objName = npcDataEx.GetNPCName()
|
| | | atkDistType = npcDataEx.GetAtkDistType()
|
| | | lv = npcDataEx.GetLV()
|
| | |
|
| | | if not npcID:
|
| | | continue
|
| | | |
| | | npcData = GameWorld.GetGameData().FindNPCDataByID(npcID)
|
| | | if not npcData:
|
| | | continue
|
| | | curSummon = GameWorld.GetNPCManager().AddPlayerSummonNPC()
|
| | | if not curSummon:
|
| | | continue
|
| | | objID = curSummon.GetID()
|
| | | batLineup.npcPosDict[posNum] = curSummon
|
| | | batLineup.npcObjIDDict[objID] = curSummon
|
| | | tfMgr.setNPCGUID(objID, batLineup.getGUID())
|
| | | |
| | | curSummon.SetNPCTypeID(npcID)
|
| | | curSummon.SetBornTime(tick)
|
| | | curSummon.SetAIType(0)
|
| | | curSummon.SetSightLevel(sightLevel)
|
| | | curSummon.SetIsNeedProcess(False)
|
| | | curSummon.SetCanAttack(True)
|
| | | curSummon.SetVisible(True)
|
| | | curSummon.SetDict(ChConfig.Def_Obj_Dict_TurnFightPosInfo, num * 100 + posNum)
|
| | | curSummon.SetDict(ChConfig.Def_Obj_Dict_LineupPlayerID, lineupPlayerID)
|
| | | curSummon.SetDict(ChConfig.Def_Obj_Dict_HeroID, heroID)
|
| | | curSummon.SetDict(ChConfig.Def_Obj_Dict_SkinID, skinID)
|
| | | GameObj.SetFaction(curSummon, faction)
|
| | | GameObj.SetXP(curSummon, initXP, False)
|
| | | batObj = batObjMgr.addBatObj()
|
| | | if not batObj:
|
| | | break
|
| | | objID = batObj.GetID()
|
| | | batObj.SetTFGUID(tfGUID)
|
| | | batObj.SetName(objName)
|
| | | batObj.SetFaction(faction)
|
| | | batObj.SetLineupPos(posNum, num)
|
| | | batObj.SetFightPower(fightPower)
|
| | | batObj.SetLV(lv)
|
| | | if npcID:
|
| | | batObj.SetNPCID(npcID)
|
| | | elif lineupPlayerID:
|
| | | batObj.SetOwnerHero(lineupPlayerID, heroID, skinID)
|
| | | batObj.InitBatAttr({int(k):v for k, v in attrDict.items()}, initXP)
|
| | |
|
| | | if atkDistType == ChConfig.AtkDistType_Short:
|
| | | baseAtkSkillID = baseAtkSkillIDList[0] if len(baseAtkSkillIDList) > 0 else 0
|
| | | atkBackSkillID = atkBackSkillIDList[0] if len(atkBackSkillIDList) > 0 else 0
|
| | | elif atkDistType == ChConfig.AtkDistType_Long:
|
| | | baseAtkSkillID = baseAtkSkillIDList[1] if len(baseAtkSkillIDList) > 1 else 0
|
| | | atkBackSkillID = atkBackSkillIDList[1] if len(atkBackSkillIDList) > 1 else 0
|
| | | if atkBackSkillID:
|
| | | skillIDList.append(atkBackSkillID)
|
| | | skillManager = batObj.GetSkillManager()
|
| | | skillManager.SkillReset()
|
| | | for skillID in skillIDList:
|
| | | skillManager.LearnSkillByID(skillID)
|
| | |
|
| | | skillManager = curSummon.GetSkillManager()
|
| | | #有指定的技能,重新学习
|
| | | if skillIDList:
|
| | | skillManager.ResetSkill()
|
| | | for skillID in skillIDList:
|
| | | skillManager.LVUPSkillByID(skillID)
|
| | | if baseAtkSkillID:
|
| | | skillManager.LVUPSkillByID(baseAtkSkillID)
|
| | | |
| | | rebornX = posX - space + (faction - 1) * space * 3 + ((posNum - 1) / 3 * space * 2 * (-1 if faction == 1 else 1))
|
| | | rebornY = posY + (posNum - 1) % 3 * space
|
| | | GameWorld.DebugLog("SummonNPC ID:%s,faction:%s,num=%s,posNum=%s,baseAtkSkillID=%s,%s" % (curSummon.GetID(), faction, num, posNum, baseAtkSkillID, skillIDList))
|
| | | curSummon.Reborn(rebornX, rebornY, False)
|
| | | NPCCommon.NPCControl(curSummon).DoNPCRebornCommLogic(tick)
|
| | | batLineup.posObjIDDict[posNum] = objID
|
| | | GameWorld.DebugLog("AddBatObj ID:%s,faction:%s,num=%s,posNum=%s,skill=%s,atk=%s,def=%s,hp=%s" |
| | | % (objID, faction, num, posNum, skillIDList, batObj.GetAtk(), batObj.GetDef(), batObj.GetHP()))
|
| | |
|
| | | return
|
| | |
|
| | |
| | | teamNum = 1
|
| | | lineupID = waveLineupList[teamNum - 1] # NPC阵容ID
|
| | |
|
| | | lineupMainInfo = GetPlayerLineup(curPlayer, ShareDefine.Lineup_Main)
|
| | | lineupMainInfo = GetPlayerLineupInfo(curPlayer, ShareDefine.Lineup_Main)
|
| | | if not lineupMainInfo:
|
| | | GameWorld.DebugLog("没有设置主阵容!", playerID)
|
| | | return
|
| | |
| | |
|
| | | turnFight = mainFightMgr.turnFight
|
| | | turnFight.setTurn(mapID, funcLineID, turnMax, False, {"teamNum":teamNum, "teamMax":teamMax})
|
| | | turnFight.setFactionLineup(Def_FactionA, {1:lineupMainInfo}, True)
|
| | | turnFight.setFactionLineup(Def_FactionB, {1:GetNPCLineup(lineupID)})
|
| | | turnFight.setFactionLineup(ChConfig.Def_FactionA, {1:lineupMainInfo}, True)
|
| | | turnFight.setFactionLineup(ChConfig.Def_FactionB, {1:GetNPCLineupInfo(lineupID)})
|
| | | turnFight.sortActionQueue()
|
| | | turnFight.syncInit()
|
| | | return
|
| | |
| | |
|
| | | wave = waveMax = 1 # 关卡boss固定只有一波
|
| | |
|
| | | lineupMainInfo = GetPlayerLineup(curPlayer, ShareDefine.Lineup_Main)
|
| | | lineupMainInfo = GetPlayerLineupInfo(curPlayer, ShareDefine.Lineup_Main)
|
| | | if not lineupMainInfo:
|
| | | GameWorld.DebugLog("没有设置主阵容!", playerID)
|
| | | return
|
| | |
| | |
|
| | | turnFight = mainFightMgr.turnFight
|
| | | turnFight.setTurn(mapID, funcLineID, turnMax, False, {"teamNum":teamNum, "teamMax":teamMax})
|
| | | turnFight.setFactionLineup(Def_FactionA, {1:lineupMainInfo}, True)
|
| | | turnFight.setFactionLineup(Def_FactionB, {1:GetNPCLineup(lineupID)})
|
| | | turnFight.setFactionLineup(ChConfig.Def_FactionA, {1:lineupMainInfo}, True)
|
| | | turnFight.setFactionLineup(ChConfig.Def_FactionB, {1:GetNPCLineupInfo(lineupID)})
|
| | | turnFight.sortActionQueue()
|
| | | turnFight.syncInit()
|
| | |
|
| | |
| | | mainFightMgr.nextTeam = False
|
| | | turnFight.resetTurn({"teamNum":teamNum})
|
| | | # 切换小队时,玩家阵容不需要处理,保留状态
|
| | | turnFight.setFactionLineup(Def_FactionB, {1:GetNPCLineup(lineupID)})
|
| | | turnFight.setFactionLineup(ChConfig.Def_FactionB, {1:GetNPCLineupInfo(lineupID)})
|
| | | turnFight.sortActionQueue()
|
| | | turnFight.syncInit()
|
| | |
|
| | |
| | | doMax = (PosNumMax + 2) * len(turnFight.actionSortList) # 防止死循环,做最大循环次数限制 = (最大位置数 + 主公、红颜位置)*行动阵容数
|
| | | overLineupList = [] # 本回合已经结束行动的阵容列表 [(faction, num), ...], 所有阵容全部结束代表本回合结束
|
| | |
|
| | | batObjMgr = BattleObj.GetBatObjMgr()
|
| | | turnNum = turnFight.turnNum
|
| | | GameWorld.DebugLog("turnNum=%s,doMax=%s,actionIndex=%s,%s" % (turnNum, doMax, turnFight.actionIndex, turnFight.actionSortList))
|
| | | while doCnt < doMax and len(overLineupList) < len(turnFight.actionSortList):
|
| | |
| | | batFaction = turnFight.getBatFaction(faction)
|
| | | batLineup = batFaction.getBatlineup(num)
|
| | | batLineup.actionNum = ActionNumStart
|
| | | for curNPC in batLineup.npcPosDict.values():
|
| | | TurnFightObjPerTurnStart(curNPC, None, turnNum, tick)
|
| | | for objID in batLineup.posObjIDDict.values():
|
| | | batObj = batObjMgr.getBatObj(objID)
|
| | | TurnFightObjPerTurnStart(turnFight, batObj, turnNum)
|
| | |
|
| | | if turnFight.actionIndex >= len(turnFight.actionSortList):
|
| | | turnFight.actionIndex = 0
|
| | |
| | | faction, num = turnFight.actionSortList[turnFight.actionIndex]
|
| | | batFaction = turnFight.getBatFaction(faction)
|
| | | batLineup = batFaction.getBatlineup(num)
|
| | | if batLineup.actionNum > max(batLineup.npcPosDict):
|
| | | if batLineup.actionNum > max(batLineup.posObjIDDict):
|
| | | if (faction, num) not in overLineupList:
|
| | | overLineupList.append((faction, num))
|
| | |
|
| | | turnFight.actionIndex += 1
|
| | | continue
|
| | |
|
| | | if faction == Def_FactionA:
|
| | | if faction == ChConfig.Def_FactionA:
|
| | | if not PlayerControl.HaveMoney(curPlayer, ShareDefine.TYPE_Price_Xiantao, fightPoint):
|
| | | GameWorld.DebugLog("战锤不足!")
|
| | | return
|
| | |
| | | elif batLineup.actionNum > 0:
|
| | | for posNum in range(batLineup.actionNum, PosNumMax + 1):
|
| | | batLineup.actionNum = posNum
|
| | | if posNum not in batLineup.npcPosDict:
|
| | | if posNum not in batLineup.posObjIDDict:
|
| | | continue
|
| | | curNPC = batLineup.npcPosDict[posNum]
|
| | | if not curNPC or GameObj.GetHP(curNPC) <= 0:
|
| | | continue
|
| | | objType = curNPC.GetGameObjType()
|
| | | objID = curNPC.GetID()
|
| | | turnFight.syncObjAction(turnNum, objType, objID)
|
| | | |
| | | objName = GetObjName(curNPC)
|
| | | curHP = GameObj.GetHP(curNPC)
|
| | | |
| | | GameWorld.DebugLog("★回合%s %s 行动 : curHP=%s" % (turnNum, objName, curHP))
|
| | | if not DoAttack(curNPC, None, tick):
|
| | | GameWorld.DebugLog(" 攻击失败")
|
| | | objID = batLineup.posObjIDDict[posNum]
|
| | | batObj = batObjMgr.getBatObj(objID)
|
| | | if not OnObjAction(turnFight, batObj):
|
| | | continue
|
| | |
|
| | | if faction == Def_FactionA:
|
| | | if faction == ChConfig.Def_FactionA:
|
| | | playerHeroAtk = True
|
| | |
|
| | | break
|
| | |
|
| | | turnFight.actionIndex += 1
|
| | | batLineup.actionNum += 1
|
| | | if batLineup.actionNum > max(batLineup.npcPosDict):
|
| | | if batLineup.actionNum > max(batLineup.posObjIDDict):
|
| | | GameWorld.DebugLog("该阵容本回合已经全部行动完了: turnNum=%s,faction=%s,num=%s,actionNum=%s" % (turnFight.turnNum, faction, num, batLineup.actionNum))
|
| | | if (faction, num) not in overLineupList:
|
| | | overLineupList.append((faction, num))
|
| | |
| | | for faction, num in turnFight.actionSortList:
|
| | | batFaction = turnFight.getBatFaction(faction)
|
| | | batLineup = batFaction.getBatlineup(num)
|
| | | for curNPC in batLineup.npcPosDict.values():
|
| | | for objID in batLineup.posObjIDDict.values():
|
| | | pass
|
| | |
|
| | | if turnFight.checkOverByKilled():
|
| | |
| | | curPlayer = turnFight.curPlayer
|
| | | turnMax = turnFight.turnMax
|
| | | EntryLogic(turnFight)
|
| | | batObjMgr = BattleObj.GetBatObjMgr()
|
| | | for turnNum in range(1, turnMax + 1):
|
| | | turnFight.turnNum = turnNum
|
| | | GameWorld.DebugLog("【----- 回合制战斗轮次: %s -----】" % turnNum)
|
| | |
| | | batFaction = turnFight.getBatFaction(faction)
|
| | | batLineup = batFaction.getBatlineup(num)
|
| | | batLineup.actionNum = 1
|
| | | for curNPC in batLineup.npcPosDict.values():
|
| | | TurnFightObjPerTurnStart(curNPC, None, turnNum, tick)
|
| | | for objID in batLineup.posObjIDDict.values():
|
| | | batObj = batObjMgr.getBatObj(objID)
|
| | | TurnFightObjPerTurnStart(turnFight, batObj, turnNum)
|
| | |
|
| | | # 主公
|
| | | for faction, num in turnFight.actionSortList:
|
| | |
| | | batLineup = batFaction.getBatlineup(num)
|
| | | for posNum in range(batLineup.actionNum, PosNumMax + 1):
|
| | | batLineup.actionNum = posNum + 1
|
| | | if posNum not in batLineup.npcPosDict:
|
| | | if posNum not in batLineup.posObjIDDict:
|
| | | continue
|
| | | curNPC = batLineup.npcPosDict[posNum]
|
| | | if not curNPC or GameObj.GetHP(curNPC) <= 0:
|
| | | continue
|
| | | objType = curNPC.GetGameObjType()
|
| | | objID = curNPC.GetID()
|
| | | turnFight.syncObjAction(turnNum, objType, objID)
|
| | | |
| | | objName = GetObjName(curNPC)
|
| | | curHP = GameObj.GetHP(curNPC)
|
| | | |
| | | GameWorld.DebugLog("★回合%s %s 行动 : curHP=%s" % (turnNum, objName, curHP))
|
| | | if not DoAttack(curNPC, None, tick):
|
| | | objID = batLineup.posObjIDDict[posNum]
|
| | | batObj = batObjMgr.getBatObj(objID)
|
| | | if not OnObjAction(turnFight, batObj):
|
| | | continue
|
| | |
|
| | | break
|
| | |
| | | GameWorld.DebugLog("回合结束逻辑: turnNum=%s,faction=%s, num=%s" % (turnNum, faction, num))
|
| | | batFaction = turnFight.getBatFaction(faction)
|
| | | batLineup = batFaction.getBatlineup(num)
|
| | | for curNPC in batLineup.npcPosDict.values():
|
| | | for objID in batLineup.posObjIDDict.values():
|
| | | pass
|
| | |
|
| | | if turnFight.checkOverByKilled():
|
| | |
| | | #funcLineID = clientData.FuncLineID
|
| | | return
|
| | |
|
| | | def GetObjName(gameObj):
|
| | | objName = gameObj.GetName()
|
| | | faction = GameObj.GetFaction(gameObj)
|
| | | posInfo = gameObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnFightPosInfo)
|
| | | heroID = gameObj.GetDictByKey(ChConfig.Def_Obj_Dict_HeroID)
|
| | | def GetObjName(batObj):
|
| | | faction = batObj.faction
|
| | | num = batObj.lineupNum
|
| | | posNum = batObj.posNum
|
| | | heroID = batObj.heroID
|
| | | if not heroID:
|
| | | heroID = gameObj.GetNPCID()
|
| | | return "%s%s %s[%s-%s]" % ("A" if faction == Def_FactionA else "B", posInfo, objName, gameObj.GetID(), heroID)
|
| | | heroID = batObj.npcID
|
| | | objName = GameWorld.CodeToGbk(batObj.GetName())
|
| | | return "%s%s-%s [%s-%s] %s" % ("A" if faction == ChConfig.Def_FactionA else "B", num, posNum, batObj.GetID(), heroID, objName)
|
| | |
|
| | | def EntryLogic(turnFight):
|
| | | ## 执行进场逻辑
|
| | |
| | | turnFight.enterLogic = True
|
| | | return
|
| | |
|
| | | def TurnFightObjPerTurnStart(gameObj, tagObj, turnNum, tick):
|
| | | def TurnFightObjPerTurnStart(turnFight, batObj, turnNum):
|
| | | ## 回合制战斗实例 - 每回合开始时处理
|
| | | if not gameObj:
|
| | | if not batObj:
|
| | | return
|
| | |
|
| | | if batObj.GetHP() <= 0:
|
| | | return
|
| | | |
| | | curID = batObj.GetID()
|
| | | buffMgr = batObj.GetBuffManager()
|
| | | GameWorld.DebugLog("更新buff: curID=%s,buffCount=%s" % (curID, buffMgr.GetBuffCount()))
|
| | | for index in range(buffMgr.GetBuffCount()):
|
| | | buff = buffMgr.GetBuffByIndex(index)
|
| | | curRemainTime = buff.GetRemainTime()
|
| | | if not curRemainTime:
|
| | | # 永久buff不处理
|
| | | continue
|
| | | buffID = buff.GetBuffID()
|
| | | updRemainTime = curRemainTime - 1
|
| | | GameWorld.DebugLog(" 更新buff剩余回合数: buffID=%s,updRemainTime=%s" % (buffID, updRemainTime))
|
| | | if updRemainTime > 0:
|
| | | buff.SetRemainTime(curRemainTime - 1)
|
| | | TurnBuff.SyncBuffRefresh(turnFight, batObj, buff)
|
| | | else:
|
| | | TurnBuff.SyncBuffDel(turnFight, batObj, buffID)
|
| | | |
| | | # SetTimeline(gameObj, turnNum, 0)
|
| | | # # 重置连击、反击数
|
| | | # gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnComboNum, 0)
|
| | |
| | |
|
| | | def AddTurnObjCureHP(curObj, srcObj, addValue, cureHP, skillID=0):
|
| | | ## 回合对象添加治疗值
|
| | | if not curObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnFightPosInfo):
|
| | | # @param curObj: 获得治疗的对象
|
| | | # @param srcObj: 来自谁的治疗
|
| | | # @param addValue: 治疗值
|
| | | # @param cureHP: 实际回血量
|
| | | if not srcObj:
|
| | | return
|
| | | |
| | | curFaction = GameObj.GetFaction(curObj)
|
| | | if not srcObj or curFaction != GameObj.GetFaction(srcObj):
|
| | | # 同阵营的治疗才统计
|
| | | return
|
| | | |
| | | curID = curObj.GetID()
|
| | | srcID = srcObj.GetID()
|
| | | turnFight = GetTurnFightMgr().getNPCTurnFight(curID)
|
| | | if not turnFight:
|
| | | return
|
| | | |
| | | curBatFaction = turnFight.getBatFaction(curFaction)
|
| | | for num in curBatFaction.lineupDict.keys():
|
| | | batLineup = curBatFaction.getBatlineup(num)
|
| | | updStatValue = batLineup.statCureValue(srcID, cureHP)
|
| | | if updStatValue == None:
|
| | | continue
|
| | | GameWorld.DebugLog(" 统计治疗: curTD=%s,srcID=%s,skillID=%s,addValue=%s,cureHP=%s,updStatValue=%s" |
| | | % (curID, srcID, skillID, addValue, cureHP, updStatValue))
|
| | | break
|
| | | |
| | | updStatValue = srcObj.StatCureValue(cureHP)
|
| | | GameWorld.DebugLog(" 统计治疗: curID=%s,srcID=%s,skillID=%s,addValue=%s,cureHP=%s,updStatValue=%s" |
| | | % (curID, srcID, skillID, addValue, cureHP, updStatValue))
|
| | | |
| | | return
|
| | |
|
| | | def AddTurnObjHurtValue(curObj, tagObj, hurtType, hurtValue, lostHP, curSkill=None):
|
| | | def AddTurnObjHurtValue(curBatObj, tagBatObj, hurtValue, lostHP, curSkill=None, isBounce=False):
|
| | | ## 回合对象添加伤害值
|
| | | if not curObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnFightPosInfo):
|
| | | return
|
| | | curID = curObj.GetID()
|
| | | tagID = tagObj.GetID()
|
| | | # @param isBounce: 是否反弹伤害
|
| | | curID = curBatObj.GetID()
|
| | | tagID = tagBatObj.GetID()
|
| | | skillID = curSkill.GetSkillID() if curSkill else 0
|
| | | turnFight = GetTurnFightMgr().getNPCTurnFight(curID)
|
| | | if not turnFight:
|
| | | return
|
| | | |
| | | if curID != tagID:
|
| | | curBatFaction = turnFight.getBatFaction(GameObj.GetFaction(curObj))
|
| | | for num in curBatFaction.lineupDict.keys():
|
| | | batLineup = curBatFaction.getBatlineup(num)
|
| | | updStatValue = batLineup.statHurtValue(curID, lostHP)
|
| | | if updStatValue == None:
|
| | | continue
|
| | | GameWorld.DebugLog(" 统计伤血: curTD=%s,tagID=%s,skillID=%s,hurtType=%s,hurtValue=%s,lostHP=%s,updStatValue=%s,tagHP=%s" |
| | | % (curID, tagID, skillID, hurtType, hurtValue, lostHP, updStatValue, GameObj.GetHP(tagObj)))
|
| | | break
|
| | | updStatValue = curBatObj.StatHurtValue(hurtValue)
|
| | | GameWorld.DebugLog(" 统计伤血: curID=%s,tagID=%s,skillID=%s,hurtValue=%s,lostHP=%s,updStatValue=%s,tagHP=%s,isBounce=%s" |
| | | % (curID, tagID, skillID, hurtValue, lostHP, updStatValue, tagBatObj.GetHP(), isBounce))
|
| | |
|
| | | tagBatFaction = turnFight.getBatFaction(GameObj.GetFaction(tagObj))
|
| | | for num in tagBatFaction.lineupDict.keys():
|
| | | batLineup = tagBatFaction.getBatlineup(num)
|
| | | updStatValue = batLineup.statDefValue(tagID, lostHP)
|
| | | if updStatValue == None:
|
| | | continue
|
| | | GameWorld.DebugLog(" 统计承伤: curTD=%s,tagID=%s,skillID=%s,hurtType=%s,hurtValue=%s,lostHP=%s,updStatValue=%s,curHP=%s" |
| | | % (tagID, curID, skillID, hurtType, hurtValue, lostHP, updStatValue, GameObj.GetHP(tagObj)))
|
| | | break
|
| | | |
| | | if tagBatObj:
|
| | | updStatValue = tagBatObj.StatDefValue(lostHP)
|
| | | GameWorld.DebugLog(" 统计承伤: curID=%s,tagID=%s,skillID=%s,hurtValue=%s,lostHP=%s,updStatValue=%s,curHP=%s,isBounce=%s" |
| | | % (tagID, curID, skillID, hurtValue, lostHP, updStatValue, tagBatObj.GetHP(), isBounce))
|
| | | |
| | | else:
|
| | | # 如换血类技能,自残的伤害不算输出
|
| | | GameWorld.DebugLog(" 自残: curTD=%s,tagID=%s,skillID=%s,hurtType=%s,hurtValue=%s,lostHP=%s,curHP=%s" |
| | | % (curID, tagID, skillID, hurtType, hurtValue, lostHP, GameObj.GetHP(curObj)))
|
| | | |
| | | if lostHP > 0 and curID != tagID:
|
| | | addXP = IpyGameDataPY.GetFuncCfg("AngerXP", 4)
|
| | | AddTurnFightXP(tagObj, addXP, "skillID:%s" % skillID)
|
| | | GameWorld.DebugLog(" 自残: curID=%s,tagID=%s,skillID=%s,hurtValue=%s,lostHP=%s,curHP=%s" |
| | | % (curID, tagID, skillID, hurtValue, lostHP, curBatObj.GetHP()))
|
| | | return
|
| | |
|
| | | def AddTurnFightXP(gameObj, addXP, reason=""):
|
| | | ## 回合战斗增加XP
|
| | | if addXP <= 0 or not addXP:
|
| | | #GameWorld.DebugLog(" 没有增加XP! curID=%s" % (gameObj.GetID()))
|
| | | def OnObjAction(turnFight, curBatObj):
|
| | | ## 战斗单位行动
|
| | | if not curBatObj:
|
| | | return
|
| | | posNum = gameObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnFightPosInfo) % 10
|
| | | if posNum <= 0:
|
| | | #非主战单位不加
|
| | | |
| | | curHP = curBatObj.GetHP()
|
| | | objID = curBatObj.GetID()
|
| | | if curHP <= 0:
|
| | | return
|
| | | curXP = GameObj.GetXP(gameObj)
|
| | | updXP = curXP + addXP
|
| | | GameObj.SetXP(gameObj, updXP)
|
| | | GameWorld.DebugLog(" 更新XP: curID=%s,curXP=%s,addXP=%s,updXP=%s,reason=%s" % (gameObj.GetID(), curXP, addXP, updXP, reason))
|
| | | |
| | | turnNum = turnFight.turnNum
|
| | | objName = GetObjName(curBatObj)
|
| | | |
| | | # 是否可行动状态判断
|
| | | canAction = True
|
| | | |
| | | if not canAction:
|
| | | GameWorld.DebugLog("★回合%s %s 当前状态不可行动!" % (turnNum, objName))
|
| | | return
|
| | | |
| | | GameWorld.DebugLog("★回合%s %s 行动 : curHP=%s" % (turnNum, objName, curHP))
|
| | | turnFight.syncObjAction(turnNum, objID)
|
| | | |
| | | curXP = curBatObj.GetXP()
|
| | | xpMax = IpyGameDataPY.GetFuncCfg("AngerXP", 2) |
| | | skillManager = curBatObj.GetSkillManager()
|
| | | useSkillList = []
|
| | | #GameWorld.DebugLog('skillCount=%s' % skillManager.GetSkillCount(), npcID)
|
| | | for index in range(0, skillManager.GetSkillCount()):
|
| | | useSkill = skillManager.GetSkillByIndex(index)
|
| | | if not useSkill:
|
| | | continue
|
| | | if useSkill.GetFuncType() in [ChConfig.Def_SkillFuncType_AtkbackSkill]:
|
| | | #基础普攻不能主动释放,目前仅用于反击
|
| | | continue
|
| | | #被动技能无法使用
|
| | | if SkillCommon.isPassiveSkill(useSkill):
|
| | | continue
|
| | | #还在冷却时间内无法释放
|
| | | if useSkill.GetRemainTime():
|
| | | continue
|
| | | skillID = useSkill.GetSkillID()
|
| | | # 常规攻击优先xp
|
| | | if SkillCommon.isAngerSkill(useSkill):
|
| | | if curXP < xpMax:
|
| | | continue
|
| | | useCnt = -1 # xp技能优先释放
|
| | | else:
|
| | | useCnt = curBatObj.GetSkillUseCnt(skillID)
|
| | | useSkillList.append([useCnt, skillID, useSkill])
|
| | | |
| | | useSkillList.sort() # 按使用次数优先升序排,使用次数低的优先判断使用
|
| | | #GameWorld.DebugLog(' 技能使用顺序 = useSkillList%s' % str(useSkillList), npcID)
|
| | | |
| | | for useInfo in useSkillList:
|
| | | useSkill = useInfo[-1]
|
| | | if TurnSkill.OnUseSkill(turnFight, curBatObj, useSkill):
|
| | | return True
|
| | | |
| | | return
|
| | |
|
| | | def DoAttack(curNPC, tagNPC, tick, turnBattleType=ChConfig.TurnBattleType_Normal, useSkill=None):
|
| | | curID = curNPC.GetID()
|
| | | npcID = curNPC.GetNPCID()
|
| | | objName = GetObjName(curNPC)
|
| | | GameWorld.DebugLog(" ● %s DoAttack: curID=%s,,turnBattleType=%s" % (objName, curID, turnBattleType))
|
| | | |
| | | atkOK = False
|
| | | tagObj = tagNPC
|
| | | curNPC.SetDict(ChConfig.Def_Obj_Dict_TurnBattleType, turnBattleType)
|
| | | |
| | | if turnBattleType == ChConfig.TurnBattleType_AtkBack:
|
| | | if not tagObj:
|
| | | return
|
| | | skillManager = curNPC.GetSkillManager()
|
| | | for index in range(0, skillManager.GetSkillCount()):
|
| | | skill = skillManager.GetSkillByIndex(index)
|
| | | #已经到尾部了
|
| | | if not skill or skill.GetSkillTypeID() == 0:
|
| | | break
|
| | | if skill.GetFuncType() == ChConfig.Def_SkillFuncType_NormalAttack:
|
| | | useSkill = skill
|
| | | break
|
| | | atkOK = SkillShell.DoLogic_UseSkill(curNPC, tagObj, useSkill, tick)
|
| | | elif turnBattleType == ChConfig.TurnBattleType_Combo:
|
| | | if not tagObj:
|
| | | return
|
| | | atkOK = SkillShell.DoLogic_UseSkill(curNPC, tagObj, useSkill, tick)
|
| | | else:
|
| | | curXP = GameObj.GetXP(curNPC)
|
| | | xpMax = IpyGameDataPY.GetFuncCfg("AngerXP", 2) |
| | | skillManager = curNPC.GetSkillManager()
|
| | | useSkillList = []
|
| | | #GameWorld.DebugLog('skillCount=%s' % skillManager.GetSkillCount(), npcID)
|
| | | for index in range(0, skillManager.GetSkillCount()):
|
| | | useSkill = skillManager.GetSkillByIndex(index)
|
| | | #已经到尾部了
|
| | | if not useSkill or useSkill.GetSkillTypeID() == 0:
|
| | | break
|
| | | if useSkill.GetFuncType() in [ChConfig.Def_SkillFuncType_NormalAttack]:
|
| | | #基础普攻不能主动释放,目前仅用于反击
|
| | | continue
|
| | | #被动技能无法使用
|
| | | if SkillCommon.isPassiveSkill(useSkill):
|
| | | continue
|
| | | #还在冷却时间内无法释放
|
| | | if SkillCommon.RefreshSkillRemainTime(useSkill, tick) != 0:
|
| | | continue
|
| | | skillTypeID = useSkill.GetSkillTypeID()
|
| | | # 常规攻击优先xp
|
| | | if SkillCommon.isAngerSkill(useSkill) and turnBattleType == ChConfig.TurnBattleType_Normal:
|
| | | if curXP < xpMax:
|
| | | continue
|
| | | useCnt = -1 # xp技能优先释放
|
| | | else:
|
| | | useCnt = curNPC.GetDictByKey(ChConfig.Def_NPC_Dict_SkillUseCnt % skillTypeID) # 该技能已使用次数
|
| | | useSkillList.append([useCnt, index, skillTypeID, useSkill])
|
| | | |
| | | useSkillList.sort() # 按使用次数优先升序排,使用次数低的优先判断使用
|
| | | #GameWorld.DebugLog(' 技能使用顺序 = useSkillList%s' % str(useSkillList), npcID)
|
| | | |
| | | for useInfo in useSkillList:
|
| | | useSkill = useInfo[-1]
|
| | | #skillID = useSkill.GetSkillID()
|
| | | atkOK, tagObj = DoNPCUseSkill(curNPC, useSkill, tick)
|
| | | if atkOK:
|
| | | break
|
| | | |
| | | curNPC.SetDict(ChConfig.Def_Obj_Dict_TurnBattleType, 0) # 无论攻击成功与否都重置战斗类型
|
| | | |
| | | tagID = 0
|
| | | tagHP = 0
|
| | | if tagObj:
|
| | | tagID = tagObj.GetID()
|
| | | tagHP = GameObj.GetHP(tagObj)
|
| | | GameWorld.DebugLog(' atkOK=%s,tagID=%s,tagHP=%s' % (atkOK, tagID, tagHP), npcID)
|
| | | if not atkOK:
|
| | | return
|
| | | |
| | | if not tagObj:
|
| | | return
|
| | | |
| | | if GameObj.GetFaction(curNPC) == GameObj.GetFaction(tagObj):
|
| | | # 同阵营直接返回,不处理连击、反击
|
| | | return True
|
| | | |
| | | curHP = GameObj.GetHP(curNPC)
|
| | | tagHP = GameObj.GetHP(tagObj)
|
| | | tagID = tagObj.GetID()
|
| | | GameWorld.DebugLog(" curID-HP=(%s-%s),tagID-HP=(%s-%s)" % (curID, curHP, tagID, tagHP))
|
| | | if tagHP <= 0 or curHP <= 0:
|
| | | return True
|
| | | |
| | | # 反击,反击可打断连击,所以优先判断
|
| | | if CanAtkBack(curNPC, tagObj):
|
| | | DoAttack(tagObj, curNPC, tick, ChConfig.TurnBattleType_AtkBack)
|
| | | return True
|
| | | |
| | | # 连击
|
| | | if CanCombo(curNPC, tagObj):
|
| | | DoAttack(curNPC, tagObj, tick, ChConfig.TurnBattleType_Combo, useSkill)
|
| | | |
| | | def DoAttack(curBatObj, tagBatObj, tick, turnBattleType=ChConfig.TurnBattleType_Normal, useSkill=None):
|
| | | # curID = curBatObj.GetID()
|
| | | # npcID = curBatObj.GetNPCID()
|
| | | # objName = GetObjName(curBatObj)
|
| | | # GameWorld.DebugLog(" ● %s DoAttack: curID=%s,,turnBattleType=%s" % (objName, curID, turnBattleType))
|
| | | # |
| | | # atkOK = False
|
| | | # curBatObj.SetDict(ChConfig.Def_Obj_Dict_TurnBattleType, turnBattleType)
|
| | | # |
| | | # if turnBattleType == ChConfig.TurnBattleType_AtkBack:
|
| | | # if not tagBatObj:
|
| | | # return
|
| | | # skillManager = curBatObj.GetSkillManager()
|
| | | # for index in range(0, skillManager.GetSkillCount()):
|
| | | # skill = skillManager.GetSkillByIndex(index)
|
| | | # if not skill:
|
| | | # continue
|
| | | # if skill.GetFuncType() == ChConfig.Def_SkillFuncType_AtkbackSkill:
|
| | | # useSkill = skill
|
| | | # break
|
| | | # atkOK = SkillShell.DoLogic_UseSkill(curBatObj, tagBatObj, useSkill, tick)
|
| | | # elif turnBattleType == ChConfig.TurnBattleType_Combo:
|
| | | # if not tagBatObj:
|
| | | # return
|
| | | # atkOK = SkillShell.DoLogic_UseSkill(curBatObj, tagBatObj, useSkill, tick)
|
| | | # else:
|
| | | # curXP = GameObj.GetXP(curBatObj)
|
| | | # xpMax = IpyGameDataPY.GetFuncCfg("AngerXP", 2) |
| | | # skillManager = curBatObj.GetSkillManager()
|
| | | # useSkillList = []
|
| | | # #GameWorld.DebugLog('skillCount=%s' % skillManager.GetSkillCount(), npcID)
|
| | | # for index in range(0, skillManager.GetSkillCount()):
|
| | | # useSkill = skillManager.GetSkillByIndex(index)
|
| | | # if not useSkill:
|
| | | # continue
|
| | | # if useSkill.GetFuncType() in [ChConfig.Def_SkillFuncType_AtkbackSkill]:
|
| | | # #基础普攻不能主动释放,目前仅用于反击
|
| | | # continue
|
| | | # #被动技能无法使用
|
| | | # if SkillCommon.isPassiveSkill(useSkill):
|
| | | # continue
|
| | | # #还在冷却时间内无法释放
|
| | | # if useSkill.GetRemainTime():
|
| | | # continue
|
| | | # skillID = useSkill.GetSkillID()
|
| | | # # 常规攻击优先xp
|
| | | # if SkillCommon.isAngerSkill(useSkill) and turnBattleType == ChConfig.TurnBattleType_Normal:
|
| | | # if curXP < xpMax:
|
| | | # continue
|
| | | # useCnt = -1 # xp技能优先释放
|
| | | # else:
|
| | | # useCnt = curBatObj.GetDictByKey(ChConfig.Def_NPC_Dict_SkillUseCnt % skillID) # 该技能已使用次数
|
| | | # useSkillList.append([useCnt, index, skillID, useSkill])
|
| | | # |
| | | # useSkillList.sort() # 按使用次数优先升序排,使用次数低的优先判断使用
|
| | | # #GameWorld.DebugLog(' 技能使用顺序 = useSkillList%s' % str(useSkillList), npcID)
|
| | | # |
| | | # for useInfo in useSkillList:
|
| | | # useSkill = useInfo[-1]
|
| | | # #skillID = useSkill.GetSkillID()
|
| | | # atkOK, tagBatObj = OnUseSkill(curBatObj, useSkill, tick)
|
| | | # if atkOK:
|
| | | # break
|
| | | # |
| | | # curBatObj.SetDict(ChConfig.Def_Obj_Dict_TurnBattleType, 0) # 无论攻击成功与否都重置战斗类型
|
| | | # |
| | | # tagID = 0
|
| | | # tagHP = 0
|
| | | # if tagObj:
|
| | | # tagID = tagObj.GetID()
|
| | | # tagHP = GameObj.GetHP(tagObj)
|
| | | # GameWorld.DebugLog(' atkOK=%s,tagID=%s,tagHP=%s' % (atkOK, tagID, tagHP), npcID)
|
| | | # if not atkOK:
|
| | | # return
|
| | | # |
| | | # if not tagObj:
|
| | | # return
|
| | | # |
| | | # if GameObj.GetFaction(curNPC) == GameObj.GetFaction(tagObj):
|
| | | # # 同阵营直接返回,不处理连击、反击
|
| | | # return True
|
| | | # |
| | | # curHP = GameObj.GetHP(curNPC)
|
| | | # tagHP = GameObj.GetHP(tagObj)
|
| | | # tagID = tagObj.GetID()
|
| | | # GameWorld.DebugLog(" curID-HP=(%s-%s),tagID-HP=(%s-%s)" % (curID, curHP, tagID, tagHP))
|
| | | # if tagHP <= 0 or curHP <= 0:
|
| | | # return True
|
| | | # |
| | | # # 反击,反击可打断连击,所以优先判断
|
| | | # if CanAtkBack(curNPC, tagObj):
|
| | | # DoAttack(tagObj, curNPC, tick, ChConfig.TurnBattleType_AtkBack)
|
| | | # return True
|
| | | # |
| | | # # 连击
|
| | | # if CanCombo(curNPC, tagObj):
|
| | | # DoAttack(curNPC, tagObj, tick, ChConfig.TurnBattleType_Combo, useSkill)
|
| | | # |
| | | return True
|
| | |
|
| | | def CanAtkBack(atkObj, defObj):
|
| | |
| | | % (atkObj.GetID(), comboNum, comboRate, atkComboRate, defComboReduce))
|
| | | return True
|
| | |
|
| | | def DoNPCUseSkill(curNPC, useSkill, tick):
|
| | | '''NPC使用技能
|
| | | @return: 是否成功, tagObj
|
| | | '''
|
| | | if not useSkill or useSkill.GetSkillTypeID() == 0:
|
| | | return False, None
|
| | | |
| | | #检查是否几率触发
|
| | | rate = useSkill.GetHappenRate()
|
| | | if rate != ChConfig.Def_MaxRateValue and not GameWorld.CanHappen(rate, ChConfig.Def_MaxRateValue):
|
| | | #GameWorld.Log('检查是否几率触发 = %s失败 = %s'%(rate, useSkill.GetSkillName()))
|
| | | return False, None
|
| | | |
| | | tagObj = None
|
| | | skillTag = SkillShell.GetSkillAffectTag(useSkill)
|
| | | skillAim = SkillShell.GetSkillFireAim(useSkill)
|
| | | |
| | | # 注: 多V多的情况友好目标仅针对本阵容、敌对目标可针对任意敌对阵容
|
| | | |
| | | #---对自己释放,或者无目标技能---
|
| | | if skillTag in ChConfig.Def_ST_CanNPCUseSkill or skillAim == ChConfig.Def_UseSkillAim_None:
|
| | | #释放自身类技能
|
| | | tagObj = curNPC
|
| | | isOK = SkillShell.DoLogic_UseSkill(curNPC, tagObj, useSkill, tick)
|
| | | return isOK, tagObj
|
| | | |
| | | # 召唤兽对主人释放技能
|
| | | elif skillTag == ChConfig.Def_UseSkillTag_SummonMaster:
|
| | | if not NPCCommon.IsSummonNPC(curNPC):
|
| | | GameWorld.ErrLog("该NPC非召唤兽,无法获得主人释放技能")
|
| | | return False, None
|
| | | |
| | | curSummonOwner = NPCCommon.GetSummonNPCOwner(IPY_GameWorld.gotPlayer, curNPC) |
| | | if curSummonOwner == None:
|
| | | curSummonOwner = NPCCommon.GetSummonNPCOwner(IPY_GameWorld.gotNPC, curNPC)
|
| | | |
| | | if curSummonOwner == None:
|
| | | GameWorld.ErrLog("召唤兽(%s)对主人释放技能,找不到主人" % curNPC.GetNPCID())
|
| | | return False, None
|
| | | |
| | | tagObj = curSummonOwner
|
| | | |
| | | # 友好死亡目标,一般是复活技能
|
| | | elif skillTag == ChConfig.Def_UseSkillTag_FriendDeath:
|
| | | deathList = GetFriendDeathList(curNPC)
|
| | | if not deathList:
|
| | | return False, None
|
| | | tagObj = random.choice(deathList) # 随机选一个
|
| | | |
| | | # 友好目标
|
| | | elif skillTag in ChConfig.Def_ST_CanNPCUseSkillFriend:
|
| | | friendList = GetFriendObjList(curNPC)
|
| | | if not friendList:
|
| | | return False, None
|
| | | tagObj = random.choice(friendList) # 随机选一个,可扩展其他选择规则
|
| | | |
| | | # 敌方目标
|
| | | else:
|
| | | tagObj = GetEnemyObj(curNPC)
|
| | | |
| | | if not tagObj:
|
| | | return False, None
|
| | | |
| | | GameWorld.DebugLog(" 技能释放: skillID=%s,atkID=%s,def=%s,HP:%s/%s" |
| | | % (useSkill.GetSkillID(), curNPC.GetID(), GetObjName(tagObj), GameObj.GetHP(tagObj), GameObj.GetMaxHP(tagObj)))
|
| | | isOK = SkillShell.DoLogic_UseSkill(curNPC, tagObj, useSkill, tick)
|
| | | return isOK, tagObj
|
| | | #def GetEnemyObj(curNPC, ruleType=0):
|
| | | # ## 获取一个敌对单位,针对所有敌对阵容主战单位,优先选择对位阵容单位,仅限活着的单位
|
| | | # # @param ruleType: 选择规则,默认0任意,1-最低血量;2-最高血量
|
| | | # objID = curNPC.GetID()
|
| | | # faction = GameObj.GetFaction(curNPC)
|
| | | # posInfo = curNPC.GetDictByKey(ChConfig.Def_Obj_Dict_TurnFightPosInfo)
|
| | | # num = posInfo / 100 # 阵容编号
|
| | | # posNum = posInfo % 100 # 所在阵容站位
|
| | | # turnFight = GetTurnFightMgr().getTurnFight(curNPC.GetTFGUID())
|
| | | # if not turnFight:
|
| | | # return
|
| | | # |
| | | # tagBatFaction = turnFight.getBatFaction(Def_FactionB if faction == Def_FactionA else Def_FactionA)
|
| | | # |
| | | # tagLineupNumList = [num] # 目标阵容选择顺序,优先对位阵容,再其他阵容
|
| | | # if num in tagBatFaction.lineupDict:
|
| | | # tagLineupNumList = [num]
|
| | | # for tagNum in tagBatFaction.lineupDict.keys():
|
| | | # if tagNum not in tagLineupNumList:
|
| | | # tagLineupNumList.append(tagNum)
|
| | | # |
| | | # batObjMgr = BattleObj.GetBatObjMgr()
|
| | | # for tagNum in tagLineupNumList:
|
| | | # tagLineup = tagBatFaction.getBatlineup(tagNum)
|
| | | # tagPosNumList = [posNum] # 优先对位位置,再其他位置按顺序遍历
|
| | | # pNumList = tagLineup.posObjIDDict.keys()
|
| | | # pNumList.sort()
|
| | | # for pNum in pNumList:
|
| | | # if pNum > 0 and pNum not in tagPosNumList:
|
| | | # tagPosNumList.append(pNum)
|
| | | # for pNum in tagPosNumList:
|
| | | # batObj = batObjMgr.getBatObj(objID)
|
| | | # if not batObj:
|
| | | # continue
|
| | | # if batObj.GetHP( )<= 0:
|
| | | # continue
|
| | | # return batObj
|
| | | # return
|
| | |
|
| | | def GetFriendDeathList(curNPC):
|
| | | ## 获取友方死亡单位,仅针对本阵容主战单位
|
| | | objID = curNPC.GetID()
|
| | | turnFight = GetTurnFightMgr().getNPCTurnFight(objID)
|
| | | if not turnFight:
|
| | | return []
|
| | | batFaction = turnFight.getBatFaction(GameObj.GetFaction(curNPC))
|
| | | num = curNPC.GetDictByKey(ChConfig.Def_Obj_Dict_TurnFightPosInfo) / 100
|
| | | batLineup = batFaction.getBatlineup(num)
|
| | | deathList = []
|
| | | for posNum, tagNPC in batLineup.npcPosDict.items():
|
| | | if posNum <= 0 or not tagNPC:
|
| | | continue
|
| | | if GameObj.GetHP(tagNPC) > 0:
|
| | | continue
|
| | | deathList.append(tagNPC)
|
| | | |
| | | return deathList
|
| | |
|
| | | def GetFriendObjList(curNPC):
|
| | | ## 获取友方单位,仅针对本阵容主战单位
|
| | | objID = curNPC.GetID()
|
| | | turnFight = GetTurnFightMgr().getNPCTurnFight(objID)
|
| | | if not turnFight:
|
| | | return []
|
| | | batFaction = turnFight.getBatFaction(GameObj.GetFaction(curNPC))
|
| | | num = curNPC.GetDictByKey(ChConfig.Def_Obj_Dict_TurnFightPosInfo) / 100
|
| | | batLineup = batFaction.getBatlineup(num)
|
| | | friendList = []
|
| | | for posNum, tagNPC in batLineup.npcPosDict.items():
|
| | | if posNum <= 0 or not tagNPC:
|
| | | continue
|
| | | if GameObj.GetHP(tagNPC) <= 0:
|
| | | continue
|
| | | friendList.append(tagNPC)
|
| | | return friendList
|
| | |
|
| | | def GetEnemyObj(curNPC, ruleType=0):
|
| | | ## 获取一个敌对单位,针对所有敌对阵容主战单位,优先选择对位阵容单位,仅限活着的单位
|
| | | # @param ruleType: 选择规则,默认0任意,1-最低血量;2-最高血量
|
| | | objID = curNPC.GetID()
|
| | | faction = GameObj.GetFaction(curNPC)
|
| | | posInfo = curNPC.GetDictByKey(ChConfig.Def_Obj_Dict_TurnFightPosInfo)
|
| | | num = posInfo / 100 # 阵容编号
|
| | | posNum = posInfo % 100 # 所在阵容站位
|
| | | turnFight = GetTurnFightMgr().getNPCTurnFight(objID)
|
| | | if not turnFight:
|
| | | return
|
| | | |
| | | tagBatFaction = turnFight.getBatFaction(Def_FactionB if faction == Def_FactionA else Def_FactionA)
|
| | | |
| | | tagLineupNumList = [num] # 目标阵容选择顺序,优先对位阵容,再其他阵容
|
| | | if num in tagBatFaction.lineupDict:
|
| | | tagLineupNumList = [num]
|
| | | for tagNum in tagBatFaction.lineupDict.keys():
|
| | | if tagNum not in tagLineupNumList:
|
| | | tagLineupNumList.append(tagNum)
|
| | | |
| | | for tagNum in tagLineupNumList:
|
| | | tagLineup = tagBatFaction.getBatlineup(tagNum)
|
| | | tagPosNumList = [posNum] # 优先对位位置,再其他位置按顺序遍历
|
| | | pNumList = tagLineup.npcPosDict.keys()
|
| | | pNumList.sort()
|
| | | for pNum in pNumList:
|
| | | if pNum > 0 and pNum not in tagPosNumList:
|
| | | tagPosNumList.append(pNum)
|
| | | for pNum in tagPosNumList:
|
| | | tagNPC = tagLineup.npcPosDict.get(pNum)
|
| | | if not tagNPC:
|
| | | continue
|
| | | if GameObj.GetHP(tagNPC) <= 0:
|
| | | continue
|
| | | return tagNPC
|
| | | return
|
| | |
|
| | | def SetTurnObjKilled(gameObj, killer=None):
|
| | | if not gameObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnFightPosInfo):
|
| | | #GameWorld.DebugLog("非回合战斗主体被击杀: curID=%s" % gameObj.GetID())
|
| | | return
|
| | | |
| | | def SetObjKilled(turnFight, gameObj, killer=None, useSkill=None):
|
| | | objID = gameObj.GetID()
|
| | | GameWorld.DebugLog(" %s 回合战斗主体被击杀: curID=%s" % (GetObjName(gameObj), objID))
|
| | | gameObj.SetCurAction(IPY_GameWorld.laNPCDie)
|
| | | if GameObj.GetHP(gameObj) != 0:
|
| | | GameObj.SetHP(gameObj, 0) # 回合制死亡仅设置为0,实例暂时不回收
|
| | | gameObj.SetVisible(False)
|
| | | gameObj.SetHP(0)
|
| | | killerObjID = killer.GetID() if killer else 0
|
| | | skillID = useSkill.GetSkillID() if useSkill else 0
|
| | |
|
| | | turnFight = GetTurnFightMgr().getNPCTurnFight(objID)
|
| | | if not turnFight:
|
| | | return True
|
| | | clientPack = ChPyNetSendPack.tagMCTurnFightObjDead()
|
| | | clientPack = ObjPool.GetPoolMgr().acquire(ChPyNetSendPack.tagMCTurnFightObjDead)
|
| | | clientPack.ObjID = objID
|
| | | turnFight.addBatPack(clientPack)
|
| | | |
| | | # 记录主动发起的玩家阵营击杀
|
| | | curPlayer = turnFight.curPlayer
|
| | | if killer and curPlayer and killer.GetDictByKey(ChConfig.Def_Obj_Dict_LineupPlayerID) == curPlayer.GetPlayerID():
|
| | | if objID not in turnFight.playerKillObjIDList:
|
| | | turnFight.playerKillObjIDList.append(objID)
|
| | | GameWorld.DebugLog("玩家单次击杀统计: %s" % turnFight.playerKillObjIDList)
|
| | | |
| | | clientPack.KillerObjID = killerObjID
|
| | | clientPack.SkillID = skillID
|
| | | turnFight.addBatPack(clientPack) |
| | | return True
|
| | |
|
| | | def OnTurnfightAttackSuccess(curObj, tagObj, curSkill):
|
| | | ## 回合战斗攻击成功额外处理,AttackResult之前,一般处理技能相关
|
| | | if curObj.GetGameObjType() != IPY_GameWorld.gotNPC:
|
| | | return
|
| | | if not curObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnFightPosInfo):
|
| | | return
|
| | | |
| | | objID = curObj.GetID()
|
| | | turnFight = GetTurnFightMgr().getNPCTurnFight(objID)
|
| | | if not turnFight:
|
| | | return
|
| | | |
| | | skillID = curSkill.GetSkillID() if curSkill else 0
|
| | | isXP = SkillCommon.isAngerSkill(curSkill)
|
| | | if isXP:
|
| | | GameObj.SetXP(curObj, 0)
|
| | | elif curSkill:
|
| | | if SkillCommon.isTurnNormalSkill(curSkill):
|
| | | addXP = IpyGameDataPY.GetFuncCfg("AngerXP", 3)
|
| | | AddTurnFightXP(curObj, addXP, "skillID:%s" % skillID)
|
| | | |
| | | curPlayer = turnFight.curPlayer
|
| | | # 仅主动发起玩家阵容触发
|
| | | if curPlayer and curObj.GetDictByKey(ChConfig.Def_Obj_Dict_LineupPlayerID) == curPlayer.GetPlayerID():
|
| | | FBLogic.OnPlayerLineupAttackSuccess(curPlayer, curObj, tagObj, curSkill, turnFight.mapID, turnFight.funcLineID)
|
| | | |
| | | return
|
| | |
|
| | | def OnTurnfightAttackResult(curObj, tagObj, curSkill):
|
| | | ## 回合战斗攻击结果额外处理,AttackResult 之后,一般处理击杀结算相关
|
| | | if curObj.GetGameObjType() != IPY_GameWorld.gotNPC:
|
| | | return
|
| | | if not curObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnFightPosInfo):
|
| | | return
|
| | | |
| | | objID = curObj.GetID()
|
| | | turnFight = GetTurnFightMgr().getNPCTurnFight(objID)
|
| | | if not turnFight:
|
| | | return
|
| | | |
| | | curPlayer = turnFight.curPlayer
|
| | | # 仅主动发起玩家阵容触发
|
| | | if curPlayer and curObj.GetDictByKey(ChConfig.Def_Obj_Dict_LineupPlayerID) == curPlayer.GetPlayerID():
|
| | | FBLogic.OnPlayerLineupAttackResult(curPlayer, curObj, tagObj, curSkill, turnFight.mapID, turnFight.funcLineID)
|
| | | |
| | | turnFight.playerKillObjIDList = []
|
| | | return
|
| | |
|
| | | def OnTurnAllOver(guid):
|
| | | ## 所有回合已经全部执行完毕
|
| | |
| | |
|
| | | if turnFight.playerID:
|
| | | # 玩家发起的,未击杀对方,算玩家输
|
| | | turnFight.winFaction = Def_FactionB
|
| | | turnFight.winFaction = ChConfig.Def_FactionB
|
| | | else:
|
| | | # 系统场次,按一定规则来,这里先随机
|
| | | turnFight.winFaction = random.choice([Def_FactionA, Def_FactionB])
|
| | | turnFight.winFaction = random.choice([ChConfig.Def_FactionA, ChConfig.Def_FactionB])
|
| | |
|
| | | DoTurnFightOver(guid)
|
| | | return
|
| | |
| | | GameWorld.DebugLog("--- 战斗结束处理 --- %s, winFaction=%s, costTime=%ss" % (guid, winFaction, turnFight.costTime))
|
| | |
|
| | | # 统计明细
|
| | | batObjMgr = BattleObj.GetBatObjMgr()
|
| | | statInfo = {}
|
| | | for faction in turnFight.factionDict.keys():
|
| | | if str(faction) not in statInfo:
|
| | |
| | | facStatInfo[str(num)] = {}
|
| | | lineupStatInfo = facStatInfo[str(num)]
|
| | | batLineup = batFaction.getBatlineup(num)
|
| | | hurtStatDict = batLineup.hurtStatDict
|
| | | defStatDict = batLineup.defStatDict
|
| | | cureStatDict = batLineup.cureStatDict
|
| | | GameWorld.DebugLog("阵容明细: faction=%s,num=%s" % (faction, num))
|
| | | for posNum, curNPC in batLineup.npcPosDict.items():
|
| | | objID = curNPC.GetID()
|
| | | npcID = curNPC.GetNPCID()
|
| | | heroID = curNPC.GetDictByKey(ChConfig.Def_Obj_Dict_HeroID)
|
| | | atkHurt = hurtStatDict.get(objID, 0)
|
| | | defHurt = defStatDict.get(objID, 0)
|
| | | cureHP = cureStatDict.get(objID, 0)
|
| | | for posNum, objID in batLineup.posObjIDDict.items():
|
| | | batObj = batObjMgr.getBatObj(objID)
|
| | | if not batObj:
|
| | | continue
|
| | | objID = batObj.GetID()
|
| | | npcID = batObj.GetNPCID()
|
| | | heroID = batObj.GetHeroID()
|
| | | atkHurt = batObj.hurtStat
|
| | | defHurt = batObj.defStat
|
| | | cureHP = batObj.cureStat
|
| | | GameWorld.DebugLog(" Pos:%s ID=%s-%s-%s,,HP=%s/%s, 输出=%s,承伤=%s,治疗=%s"
|
| | | % (posNum, objID, npcID, heroID, GameObj.GetHP(curNPC), GameObj.GetMaxHP(curNPC), atkHurt, defHurt, cureHP))
|
| | | % (posNum, objID, npcID, heroID, batObj.GetHP(), batObj.GetMaxHP(), atkHurt, defHurt, cureHP))
|
| | | lineupStatInfo[str(posNum)] = {"ObjID":objID, "HeroID":heroID, "NPCID":npcID, "AtkHurt":atkHurt, "DefHurt":defHurt, "CureHP":cureHP}
|
| | |
|
| | | awardItemList = []
|
| | | playerID = turnFight.playerID
|
| | | if playerID:
|
| | | curPlayer = turnFight.curPlayer
|
| | | isWin = (winFaction == Def_FactionA)
|
| | | isWin = (winFaction == ChConfig.Def_FactionA)
|
| | | # 主线小怪
|
| | | if turnFight.mapID == ChConfig.Def_FBMapID_Main:
|
| | | OnOver_MainLevel(curPlayer, isWin, awardItemList)
|
| | |
| | | }
|
| | |
|
| | | # 属性ID对应0418刷新类型 {属性ID:[刷新同步类型, 是否支持超20亿的大数值], ...}
|
| | | # 卡牌项目玩家/主公属性仅为中间层属性,并非最终属性,最终属性体现在卡牌上,暂定全部前端自己算
|
| | | # 所以仅配置战斗场景需要同步的属性即可
|
| | | CDBRefresh_AttrIDDict = {
|
| | | AttrID_MaxHP:[IPY_PlayerDefine.CDBPlayerRefresh_MaxHP, 1],
|
| | | AttrID_HP:[IPY_PlayerDefine.CDBPlayerRefresh_HP, 1],
|
| | |
| | | Def_Skill_Effect_BoomSeedHurt = 804 # BUFF种子单层伤害
|
| | | Def_Skill_Effect_StoreBlood = 809 # 将期间受到的伤害总值,用于最后回血,不影响伤害
|
| | | Def_Skill_Effect_AttackReplace = 1009 #攻击计算,野外小怪伤害替换1010 (2018-03-07增加精英怪)
|
| | | Def_Skill_Effect_Cure = 1000 #治疗
|
| | | Def_Skill_Effect_Anger = 1001 #怒气增减偷
|
| | | Def_Skill_Effect_Attack = 1010 #攻击计算
|
| | | Def_Skill_Effect_LayerCnt = 1011 # BUFF层级数量 A值层数;B值:10位-是否非叠加属性,个位-层数处理方式0递增1递减;C值: 是否攻击减层
|
| | | Def_Skill_Effect_MasterBuff = 1012 # 主从技能(同步buff持续时间)
|
| | |
| | |
|
| | | #伤害类型
|
| | | (
|
| | | HurtType_Fail, # 失败 - 如概率没有触发 0
|
| | | HurtType_Normal, # 普通伤害 1
|
| | | HurtTYpe_Recovery, # 回血 2
|
| | | HurtType_3,
|
| | | HurtType_4,
|
| | | HurtType_Parry, # 格挡 5
|
| | | HurtType_IgnoreDef, # 无视防御 6
|
| | | HurtType_SuperHit, # 暴击 7
|
| | | HurtType_8,
|
| | | HurtType_Miss, # 闪避 9
|
| | | ) = range(10)
|
| | |
|
| | | #伤害类型
|
| | | (
|
| | | Def_HurtType_Normal, # 普通伤害 1
|
| | | Def_HurtTYpe_Recovery, # 回复 2
|
| | | Def_HurtType_BounceHurt, # 反弹伤害 3
|
| | |
| | | Def_HurtType_ThumpHit, # 重击 16
|
| | | Def_HurtType_Yinji, # 印记 17
|
| | | Def_HurtType_Burn, # 灼烧 18
|
| | | ) = range(1, 19)
|
| | | ) = range(1001, 1001 + 18)
|
| | | #Def_HurtType_SuckBlood, # 吸血
|
| | |
|
| | | (
|
| | |
| | | Def_Skill_HappenState_LuckyHit = 0x0004 # 必会心一击
|
| | | Def_Skill_HappenState_ThumpHit = 0x0008 # 必重击
|
| | |
|
| | | # 技能目标 - 瞄准范围
|
| | | (
|
| | | SkillTagAim_All, # 全部 0
|
| | | SkillTagAim_Relative, # 对位位置 1
|
| | | SkillTagAim_FrontRow, # 前排 2
|
| | | SkillTagAim_BackRow, # 后排 3
|
| | | SkillTagAim_Vertical, # 竖排/纵排 4
|
| | | SkillTagAim_Self, # 自己 5
|
| | | SkillTagAim_MainSkill, # 继承主技能目标 6
|
| | | ) = range(7)
|
| | |
|
| | | # 技能目标 - 细分
|
| | | (
|
| | | SkillTagAffect_None, # 无 0
|
| | | SkillTagAffect_HPLowest, # 血量最低 1
|
| | | SkillTagAffect_HPHighest, # 血量最高 2
|
| | | SkillTagAffect_Death, # 死亡单位 3
|
| | | ) = range(4)
|
| | |
|
| | | #技能施法目标
|
| | | Def_UseSkillAim_Type = 3
|
| | |
| | | Def_NstNull, Def_NstMoving, Def_NstDead, Def_NstAttack = range(4)
|
| | |
|
| | | #-------------------------------#副本相关#------------------------
|
| | | # 主线小怪
|
| | | Def_FBMapID_Main = 1
|
| | | # 主线Boss
|
| | | Def_FBMapID_MainBoss = 2
|
| | |
|
| | | Def_FBMapID_Main = 1 # 主线小怪
|
| | | Def_FBMapID_MainBoss = 2 # 主线Boss
|
| | |
|
| | | #创角新手村地图ID列表
|
| | | Def_CreatRoleMapIDList = [10000]
|
| | |
| | | DropOwnerType_Contend, # 争夺 8 第一个攻击的获得归属,击杀当前归属者的玩家成为新归属者
|
| | | DropOwnerType_RankHurtPlayer, # 个人伤血排行奖励归属 9 根据玩家个人伤血排行给奖励,伤血不重置
|
| | | ) = range(10)
|
| | |
|
| | | #阵营
|
| | | Def_FactionA = 1
|
| | | Def_FactionB = 2
|
| | |
|
| | | #------------------------------------------------
|
| | | #技能类型
|
| | |
| | | TurnBattleType_Normal, # 常规攻击
|
| | | TurnBattleType_Combo, # 连击
|
| | | TurnBattleType_AtkBack, # 反击
|
| | | ) = range(3)
|
| | | TurnBattleType_Pursue , # 追击
|
| | | ) = range(4)
|
| | |
|
| | | Def_PerTurnTick = 1000 # 每回合等同于常规tick时长
|
| | |
|
| | |
| | |
|
| | | #主线
|
| | | Def_PDict_UnXiantaoCntExp = "UnXiantaoCntExp" # 累计未结算经验的战锤数
|
| | | Def_PDict_UnXiantaoCntEquip = "UnXiantaoCntEquip" # 累计未结算掉落的战锤数
|
| | | Def_PDict_UnXiantaoCntEquip = "UnXiantaoCntEquip" # 累计未结算装备掉落的战锤数
|
| | | Def_PDict_UnXiantaoCntBooty = "UnXiantaoCntBooty_%s" # 累计未结算战利品掉落的战锤数,参数(itemID)
|
| | | Def_PDict_BootyDropToday = "BootyDropToday_%s" # 今日已累计掉落战利品数量,参数(itemID)
|
| | |
|
| | | #-------------------------------------------------------------------------------
|
| | |
| | | ) = range(27)
|
| | |
|
| | |
|
| | | # 回合卡牌
|
| | | (
|
| | | Def_SkillFuncType_Common, #0为通用技能
|
| | | Def_SkillFuncType_TurnNormaSkill, #1 普攻技能
|
| | | Def_SkillFuncType_AngerSkill, #2 怒气技能
|
| | | Def_SkillFuncType_PotentialSkill, #3 潜能技能
|
| | | Def_SkillFuncType_AtkbackSkill, #4 反击技能
|
| | | ) = range(5)
|
| | |
|
| | | # MMO项目 - 先保留,重新定义从1000开始,后续可陆续删除
|
| | | (Def_SkillFuncType_Common, #0为通用技能
|
| | | Def_SkillFuncType_FbSkill, #1为法宝功能获得的主动技能
|
| | | Def_SkillFuncType_FbPassiveSkill, #2为法宝功能获得的被动技能
|
| | |
| | | Def_SkillFuncType_ShentongSkill, #20 神通技能
|
| | | Def_SkillFuncType_ElfSkill, #21 精怪技能
|
| | | Def_SkillFuncType_GatherTheSoul, #22 聚魂技能
|
| | | Def_SkillFuncType_TurnNormaSkill, #23 回合普攻技能
|
| | | ) = range(24)
|
| | | ) = range(1000, 1000 + 23)
|
| | |
|
| | | # 受技能效果完全影响的怪, 对应 Def_BattleRelationType_CommNoBoss
|
| | | Def_SkillAttack_NPCIsBoss = [ Def_NPCType_Ogre_Normal , #平凡小怪 0 # c++ 定义为普通NPC视野刷新
|
| | |
| | | ExpRateLimitType_Recover, # 资源找回
|
| | | ExpRateLimitType_Sweep, # 扫荡
|
| | | ) = range(2)
|
| | |
|
| | | # 技能功能类对应战斗力模块
|
| | | Def_SkillFuncType_MFPType={
|
| | | Def_SkillFuncType_FbSkill:ShareDefine.Def_MFPType_MagicWeapon1,
|
| | | Def_SkillFuncType_FbPassiveSkill:ShareDefine.Def_MFPType_MagicWeapon2,
|
| | | Def_SkillFuncType_FbSPSkill:ShareDefine.Def_MFPType_MagicWeapon1,
|
| | | Def_SkillFuncType_GiftSkill:ShareDefine.Def_MFPType_Role,
|
| | | |
| | | Def_SkillFuncType_HorseSkill:ShareDefine.Def_MFPType_Horse,
|
| | | Def_SkillFuncType_PetSkill:ShareDefine.Def_MFPType_Pet,
|
| | | Def_SkillFuncType_PetOwnerSkill:ShareDefine.Def_MFPType_Pet,
|
| | | Def_SkillFuncType_GWSkill:ShareDefine.Def_MFPType_Prestige,
|
| | | Def_SkillFuncType_SuiteSkill:ShareDefine.Def_MFPType_Equip,
|
| | | Def_SkillFuncType_TitleSkill:ShareDefine.Def_MFPType_Dienstgrad,
|
| | | Def_SkillFuncType_LianTiSkill:ShareDefine.Def_MFPType_LianTi,
|
| | | Def_SkillFuncType_ShentongSkill:ShareDefine.Def_MFPType_Shentong,
|
| | | }
|
| | |
|
| | |
|
| | | # 投资理财类型,和前端对应,从7开始
|
| | | InvestTypeList = (
|
| | |
| | |
|
| | |
|
| | | #------------------------------------------------------
|
| | | # B4 29 Buff消失 #tagSCBuffDel
|
| | |
|
| | | class tagSCBuffDel(Structure):
|
| | | _pack_ = 1
|
| | | _fields_ = [
|
| | | ("Cmd", c_ubyte),
|
| | | ("SubCmd", c_ubyte),
|
| | | ("ObjID", c_int), |
| | | ("BuffID", c_int), |
| | | ("RelatedSkillID", c_int), # 关联的技能ID,一般是主技能ID或由于某个技能释放引起的buff变更
|
| | | ]
|
| | |
|
| | | def __init__(self):
|
| | | self.Clear()
|
| | | self.Cmd = 0xB4
|
| | | self.SubCmd = 0x29
|
| | | return
|
| | |
|
| | | def ReadData(self, stringData, _pos=0, _len=0):
|
| | | self.Clear()
|
| | | memmove(addressof(self), stringData[_pos:], self.GetLength())
|
| | | return _pos + self.GetLength()
|
| | |
|
| | | def Clear(self):
|
| | | self.Cmd = 0xB4
|
| | | self.SubCmd = 0x29
|
| | | self.ObjID = 0
|
| | | self.BuffID = 0
|
| | | self.RelatedSkillID = 0
|
| | | return
|
| | |
|
| | | def GetLength(self):
|
| | | return sizeof(tagSCBuffDel)
|
| | |
|
| | | def GetBuffer(self):
|
| | | return string_at(addressof(self), self.GetLength())
|
| | |
|
| | | def OutputString(self):
|
| | | DumpString = '''// B4 29 Buff消失 //tagSCBuffDel:
|
| | | Cmd:%s,
|
| | | SubCmd:%s,
|
| | | ObjID:%d,
|
| | | BuffID:%d,
|
| | | RelatedSkillID:%d
|
| | | '''\
|
| | | %(
|
| | | self.Cmd,
|
| | | self.SubCmd,
|
| | | self.ObjID,
|
| | | self.BuffID,
|
| | | self.RelatedSkillID
|
| | | )
|
| | | return DumpString
|
| | |
|
| | |
|
| | | m_NAtagSCBuffDel=tagSCBuffDel()
|
| | | ChNetPackDict[eval("0x%02x%02x"%(m_NAtagSCBuffDel.Cmd,m_NAtagSCBuffDel.SubCmd))] = m_NAtagSCBuffDel
|
| | |
|
| | |
|
| | | #------------------------------------------------------
|
| | | # B4 28 Buff刷新 #tagSCBuffRefresh
|
| | |
|
| | | class tagSCBuffRefresh(Structure):
|
| | | _pack_ = 1
|
| | | _fields_ = [
|
| | | ("Cmd", c_ubyte),
|
| | | ("SubCmd", c_ubyte),
|
| | | ("ObjID", c_int), # 谁身上的buff
|
| | | ("BuffID", c_int), # buffID,某个obj上的唯一buffID,不同的buffID可能skillID相同
|
| | | ("SkillID", c_int), # 该buff对应技能表ID
|
| | | ("RelatedSkillID", c_int), # 关联的技能ID,一般是主技能ID或由于某个技能释放引起的buff变更
|
| | | ("LastTime", c_int), # 剩余时长毫秒/回合数
|
| | | ("Layer", c_ushort), # 层数,不需要默认0
|
| | | ("OwnerID", c_int), # buff来源者,即施法方
|
| | | ]
|
| | |
|
| | | def __init__(self):
|
| | | self.Clear()
|
| | | self.Cmd = 0xB4
|
| | | self.SubCmd = 0x28
|
| | | return
|
| | |
|
| | | def ReadData(self, stringData, _pos=0, _len=0):
|
| | | self.Clear()
|
| | | memmove(addressof(self), stringData[_pos:], self.GetLength())
|
| | | return _pos + self.GetLength()
|
| | |
|
| | | def Clear(self):
|
| | | self.Cmd = 0xB4
|
| | | self.SubCmd = 0x28
|
| | | self.ObjID = 0
|
| | | self.BuffID = 0
|
| | | self.SkillID = 0
|
| | | self.RelatedSkillID = 0
|
| | | self.LastTime = 0
|
| | | self.Layer = 0
|
| | | self.OwnerID = 0
|
| | | return
|
| | |
|
| | | def GetLength(self):
|
| | | return sizeof(tagSCBuffRefresh)
|
| | |
|
| | | def GetBuffer(self):
|
| | | return string_at(addressof(self), self.GetLength())
|
| | |
|
| | | def OutputString(self):
|
| | | DumpString = '''// B4 28 Buff刷新 //tagSCBuffRefresh:
|
| | | Cmd:%s,
|
| | | SubCmd:%s,
|
| | | ObjID:%d,
|
| | | BuffID:%d,
|
| | | SkillID:%d,
|
| | | RelatedSkillID:%d,
|
| | | LastTime:%d,
|
| | | Layer:%d,
|
| | | OwnerID:%d
|
| | | '''\
|
| | | %(
|
| | | self.Cmd,
|
| | | self.SubCmd,
|
| | | self.ObjID,
|
| | | self.BuffID,
|
| | | self.SkillID,
|
| | | self.RelatedSkillID,
|
| | | self.LastTime,
|
| | | self.Layer,
|
| | | self.OwnerID
|
| | | )
|
| | | return DumpString
|
| | |
|
| | |
|
| | | m_NAtagSCBuffRefresh=tagSCBuffRefresh()
|
| | | ChNetPackDict[eval("0x%02x%02x"%(m_NAtagSCBuffRefresh.Cmd,m_NAtagSCBuffRefresh.SubCmd))] = m_NAtagSCBuffRefresh
|
| | |
|
| | |
|
| | | #------------------------------------------------------
|
| | | # B4 12 删除恶意攻击玩家 #tagMCDelMaliciousAtkPlayer
|
| | |
|
| | | class tagMCDelMaliciousAtkPlayer(Structure):
|
| | |
| | |
|
| | | m_NAtagMCNPCSkillWarn=tagMCNPCSkillWarn()
|
| | | ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCNPCSkillWarn.Head.Cmd,m_NAtagMCNPCSkillWarn.Head.SubCmd))] = m_NAtagMCNPCSkillWarn
|
| | |
|
| | |
|
| | | #------------------------------------------------------
|
| | | # B4 18 对象属性刷新展示 #tagSCObjPropertyRefreshView
|
| | |
|
| | | class tagSCObjPropertyRefreshView(Structure):
|
| | | _pack_ = 1
|
| | | _fields_ = [
|
| | | ("Cmd", c_ubyte),
|
| | | ("SubCmd", c_ubyte),
|
| | | ("ObjID", c_int), |
| | | ("RefreshType", c_ushort), # 同0418刷新类型,如血量、怒气
|
| | | ("Value", c_int), # 更新值
|
| | | ("ValueEx", c_int), # 更新值,如果是大数值的此值为整除亿部分
|
| | | ("DiffType", c_ubyte), # 变化类型,0-减少;1-增加
|
| | | ("DiffValue", c_int), # 变化值
|
| | | ("DiffValueEx", c_int), # 变化值,如果是大数值的此值为整除亿部分
|
| | | ("SkillID", c_int), # 使用的技能表ID
|
| | | ("RelatedSkillID", c_int), # 关联的技能ID,一般是主技能ID,非主技能额外触发的为0
|
| | | ]
|
| | |
|
| | | def __init__(self):
|
| | | self.Clear()
|
| | | self.Cmd = 0xB4
|
| | | self.SubCmd = 0x18
|
| | | return
|
| | |
|
| | | def ReadData(self, stringData, _pos=0, _len=0):
|
| | | self.Clear()
|
| | | memmove(addressof(self), stringData[_pos:], self.GetLength())
|
| | | return _pos + self.GetLength()
|
| | |
|
| | | def Clear(self):
|
| | | self.Cmd = 0xB4
|
| | | self.SubCmd = 0x18
|
| | | self.ObjID = 0
|
| | | self.RefreshType = 0
|
| | | self.Value = 0
|
| | | self.ValueEx = 0
|
| | | self.DiffType = 0
|
| | | self.DiffValue = 0
|
| | | self.DiffValueEx = 0
|
| | | self.SkillID = 0
|
| | | self.RelatedSkillID = 0
|
| | | return
|
| | |
|
| | | def GetLength(self):
|
| | | return sizeof(tagSCObjPropertyRefreshView)
|
| | |
|
| | | def GetBuffer(self):
|
| | | return string_at(addressof(self), self.GetLength())
|
| | |
|
| | | def OutputString(self):
|
| | | DumpString = '''// B4 18 对象属性刷新展示 //tagSCObjPropertyRefreshView:
|
| | | Cmd:%s,
|
| | | SubCmd:%s,
|
| | | ObjID:%d,
|
| | | RefreshType:%d,
|
| | | Value:%d,
|
| | | ValueEx:%d,
|
| | | DiffType:%d,
|
| | | DiffValue:%d,
|
| | | DiffValueEx:%d,
|
| | | SkillID:%d,
|
| | | RelatedSkillID:%d
|
| | | '''\
|
| | | %(
|
| | | self.Cmd,
|
| | | self.SubCmd,
|
| | | self.ObjID,
|
| | | self.RefreshType,
|
| | | self.Value,
|
| | | self.ValueEx,
|
| | | self.DiffType,
|
| | | self.DiffValue,
|
| | | self.DiffValueEx,
|
| | | self.SkillID,
|
| | | self.RelatedSkillID
|
| | | )
|
| | | return DumpString
|
| | |
|
| | |
|
| | | m_NAtagSCObjPropertyRefreshView=tagSCObjPropertyRefreshView()
|
| | | ChNetPackDict[eval("0x%02x%02x"%(m_NAtagSCObjPropertyRefreshView.Cmd,m_NAtagSCObjPropertyRefreshView.SubCmd))] = m_NAtagSCObjPropertyRefreshView
|
| | |
|
| | |
|
| | | #------------------------------------------------------
|
| | |
| | | ("Cmd", c_ubyte),
|
| | | ("SubCmd", c_ubyte),
|
| | | ("ObjID", c_int),
|
| | | ("KillerObjID", c_int), # 被谁击杀的,可能为0 |
| | | ("SkillID", c_int), # 被什么技能击杀,可能为0 |
| | | ]
|
| | |
|
| | | def __init__(self):
|
| | |
| | | self.Cmd = 0xB4
|
| | | self.SubCmd = 0x22
|
| | | self.ObjID = 0
|
| | | self.KillerObjID = 0
|
| | | self.SkillID = 0
|
| | | return
|
| | |
|
| | | def GetLength(self):
|
| | |
| | | DumpString = '''// B4 22 回合战斗对象死亡 //tagMCTurnFightObjDead:
|
| | | Cmd:%s,
|
| | | SubCmd:%s,
|
| | | ObjID:%d
|
| | | ObjID:%d,
|
| | | KillerObjID:%d,
|
| | | SkillID:%d
|
| | | '''\
|
| | | %(
|
| | | self.Cmd,
|
| | | self.SubCmd,
|
| | | self.ObjID
|
| | | self.ObjID,
|
| | | self.KillerObjID,
|
| | | self.SkillID
|
| | | )
|
| | | return DumpString
|
| | |
|
| | |
| | |
|
| | |
|
| | | #------------------------------------------------------
|
| | | # B4 26 回合战斗标签 #tagSCTurnFightTag
|
| | |
|
| | | class tagSCTurnFightTag(Structure):
|
| | | Head = tagHead()
|
| | | Len = 0 #(BYTE Len)
|
| | | Tag = "" #(String Tag)// 标签,释放技能的标签格式: Skill_objID_skillID,其他标签格式可再扩展
|
| | | Sign = 0 #(BYTE Sign)// 0-标签头;1-标签尾;
|
| | | data = None
|
| | |
|
| | | def __init__(self):
|
| | | self.Clear()
|
| | | self.Head.Cmd = 0xB4
|
| | | self.Head.SubCmd = 0x26
|
| | | return
|
| | |
|
| | | def ReadData(self, _lpData, _pos=0, _Len=0):
|
| | | self.Clear()
|
| | | _pos = self.Head.ReadData(_lpData, _pos)
|
| | | self.Len,_pos = CommFunc.ReadBYTE(_lpData, _pos)
|
| | | self.Tag,_pos = CommFunc.ReadString(_lpData, _pos,self.Len)
|
| | | self.Sign,_pos = CommFunc.ReadBYTE(_lpData, _pos)
|
| | | return _pos
|
| | |
|
| | | def Clear(self):
|
| | | self.Head = tagHead()
|
| | | self.Head.Clear()
|
| | | self.Head.Cmd = 0xB4
|
| | | self.Head.SubCmd = 0x26
|
| | | self.Len = 0
|
| | | self.Tag = ""
|
| | | self.Sign = 0
|
| | | return
|
| | |
|
| | | def GetLength(self):
|
| | | length = 0
|
| | | length += self.Head.GetLength()
|
| | | length += 1
|
| | | length += len(self.Tag)
|
| | | length += 1
|
| | |
|
| | | return length
|
| | |
|
| | | def GetBuffer(self):
|
| | | data = ''
|
| | | data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
|
| | | data = CommFunc.WriteBYTE(data, self.Len)
|
| | | data = CommFunc.WriteString(data, self.Len, self.Tag)
|
| | | data = CommFunc.WriteBYTE(data, self.Sign)
|
| | | return data
|
| | |
|
| | | def OutputString(self):
|
| | | DumpString = '''
|
| | | Head:%s,
|
| | | Len:%d,
|
| | | Tag:%s,
|
| | | Sign:%d
|
| | | '''\
|
| | | %(
|
| | | self.Head.OutputString(),
|
| | | self.Len,
|
| | | self.Tag,
|
| | | self.Sign
|
| | | )
|
| | | return DumpString
|
| | |
|
| | |
|
| | | m_NAtagSCTurnFightTag=tagSCTurnFightTag()
|
| | | ChNetPackDict[eval("0x%02x%02x"%(m_NAtagSCTurnFightTag.Head.Cmd,m_NAtagSCTurnFightTag.Head.SubCmd))] = m_NAtagSCTurnFightTag
|
| | |
|
| | |
|
| | | #------------------------------------------------------
|
| | | # B4 27 使用技能 #tagSCUseSkill
|
| | |
|
| | | class tagSCUseSkillHurt(Structure):
|
| | | _pack_ = 1
|
| | | _fields_ = [
|
| | | ("ObjID", c_int), |
| | | ("AttackTypes", c_int), # 飘血类型汇总,支持多种类型并存,如无视防御且暴击同时被格挡,二进制或运算最终值;0-失败;1-普通;2-回血;5-格挡;6-无视防御;7-暴击;9-闪避
|
| | | ("HurtHP", c_int), # 飘血值,求余亿部分
|
| | | ("HurtHPEx", c_int), # 飘血值,整除亿部分
|
| | | ("CurHP", c_int), # 更新剩余血量,求余亿部分
|
| | | ("CurHPEx", c_int), # 更新剩余血量,整除亿部分
|
| | | ("SuckHP", c_int), # 本次伤害转化的吸血量
|
| | | ("BounceHP", c_int), # 本次伤害反弹的伤害量
|
| | | ]
|
| | |
|
| | | def __init__(self):
|
| | | self.Clear()
|
| | | return
|
| | |
|
| | | def ReadData(self, stringData, _pos=0, _len=0):
|
| | | self.Clear()
|
| | | memmove(addressof(self), stringData[_pos:], self.GetLength())
|
| | | return _pos + self.GetLength()
|
| | |
|
| | | def Clear(self):
|
| | | self.ObjID = 0
|
| | | self.AttackTypes = 0
|
| | | self.HurtHP = 0
|
| | | self.HurtHPEx = 0
|
| | | self.CurHP = 0
|
| | | self.CurHPEx = 0
|
| | | self.SuckHP = 0
|
| | | self.BounceHP = 0
|
| | | return
|
| | |
|
| | | def GetLength(self):
|
| | | return sizeof(tagSCUseSkillHurt)
|
| | |
|
| | | def GetBuffer(self):
|
| | | return string_at(addressof(self), self.GetLength())
|
| | |
|
| | | def OutputString(self):
|
| | | DumpString = '''// B4 27 使用技能 //tagSCUseSkill:
|
| | | ObjID:%d,
|
| | | AttackTypes:%d,
|
| | | HurtHP:%d,
|
| | | HurtHPEx:%d,
|
| | | CurHP:%d,
|
| | | CurHPEx:%d,
|
| | | SuckHP:%d,
|
| | | BounceHP:%d
|
| | | '''\
|
| | | %(
|
| | | self.ObjID,
|
| | | self.AttackTypes,
|
| | | self.HurtHP,
|
| | | self.HurtHPEx,
|
| | | self.CurHP,
|
| | | self.CurHPEx,
|
| | | self.SuckHP,
|
| | | self.BounceHP
|
| | | )
|
| | | return DumpString
|
| | |
|
| | |
|
| | | class tagSCUseSkill(Structure):
|
| | | Head = tagHead()
|
| | | ObjID = 0 #(DWORD ObjID)
|
| | | PMType = 0 #(BYTE PMType)// 物法类型 0或1-物理;2-法术
|
| | | BattleType = 0 #(BYTE BattleType)// 战斗类型 0-常规;1-连击;2-反击;3-追击
|
| | | CurHP = 0 #(DWORD CurHP)// 释放技能后剩余血量,吸血、反弹可能引起变化,求余亿部分
|
| | | CurHPEx = 0 #(DWORD CurHPEx)// 释放技能后剩余血量,吸血、反弹可能引起变化,整除亿部分
|
| | | SkillID = 0 #(DWORD SkillID)
|
| | | HurtCount = 0 #(BYTE HurtCount)//伤害数目
|
| | | HurtList = list() #(vector<tagSCUseSkillHurt> HurtList)//size = HurtCount
|
| | | data = None
|
| | |
|
| | | def __init__(self):
|
| | | self.Clear()
|
| | | self.Head.Cmd = 0xB4
|
| | | self.Head.SubCmd = 0x27
|
| | | return
|
| | |
|
| | | def ReadData(self, _lpData, _pos=0, _Len=0):
|
| | | self.Clear()
|
| | | _pos = self.Head.ReadData(_lpData, _pos)
|
| | | self.ObjID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
|
| | | self.PMType,_pos = CommFunc.ReadBYTE(_lpData, _pos)
|
| | | self.BattleType,_pos = CommFunc.ReadBYTE(_lpData, _pos)
|
| | | self.CurHP,_pos = CommFunc.ReadDWORD(_lpData, _pos)
|
| | | self.CurHPEx,_pos = CommFunc.ReadDWORD(_lpData, _pos)
|
| | | self.SkillID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
|
| | | self.HurtCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
|
| | | for i in range(self.HurtCount):
|
| | | temHurtList = tagSCUseSkillHurt()
|
| | | _pos = temHurtList.ReadData(_lpData, _pos)
|
| | | self.HurtList.append(temHurtList)
|
| | | return _pos
|
| | |
|
| | | def Clear(self):
|
| | | self.Head = tagHead()
|
| | | self.Head.Clear()
|
| | | self.Head.Cmd = 0xB4
|
| | | self.Head.SubCmd = 0x27
|
| | | self.ObjID = 0
|
| | | self.PMType = 0
|
| | | self.BattleType = 0
|
| | | self.CurHP = 0
|
| | | self.CurHPEx = 0
|
| | | self.SkillID = 0
|
| | | self.HurtCount = 0
|
| | | self.HurtList = list()
|
| | | return
|
| | |
|
| | | def GetLength(self):
|
| | | length = 0
|
| | | length += self.Head.GetLength()
|
| | | length += 4
|
| | | length += 1
|
| | | length += 1
|
| | | length += 4
|
| | | length += 4
|
| | | length += 4
|
| | | length += 1
|
| | | for i in range(self.HurtCount):
|
| | | length += self.HurtList[i].GetLength()
|
| | |
|
| | | return length
|
| | |
|
| | | def GetBuffer(self):
|
| | | data = ''
|
| | | data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
|
| | | data = CommFunc.WriteDWORD(data, self.ObjID)
|
| | | data = CommFunc.WriteBYTE(data, self.PMType)
|
| | | data = CommFunc.WriteBYTE(data, self.BattleType)
|
| | | data = CommFunc.WriteDWORD(data, self.CurHP)
|
| | | data = CommFunc.WriteDWORD(data, self.CurHPEx)
|
| | | data = CommFunc.WriteDWORD(data, self.SkillID)
|
| | | data = CommFunc.WriteBYTE(data, self.HurtCount)
|
| | | for i in range(self.HurtCount):
|
| | | data = CommFunc.WriteString(data, self.HurtList[i].GetLength(), self.HurtList[i].GetBuffer())
|
| | | return data
|
| | |
|
| | | def OutputString(self):
|
| | | DumpString = '''
|
| | | Head:%s,
|
| | | ObjID:%d,
|
| | | PMType:%d,
|
| | | BattleType:%d,
|
| | | CurHP:%d,
|
| | | CurHPEx:%d,
|
| | | SkillID:%d,
|
| | | HurtCount:%d,
|
| | | HurtList:%s
|
| | | '''\
|
| | | %(
|
| | | self.Head.OutputString(),
|
| | | self.ObjID,
|
| | | self.PMType,
|
| | | self.BattleType,
|
| | | self.CurHP,
|
| | | self.CurHPEx,
|
| | | self.SkillID,
|
| | | self.HurtCount,
|
| | | "..."
|
| | | )
|
| | | return DumpString
|
| | |
|
| | |
|
| | | m_NAtagSCUseSkill=tagSCUseSkill()
|
| | | ChNetPackDict[eval("0x%02x%02x"%(m_NAtagSCUseSkill.Head.Cmd,m_NAtagSCUseSkill.Head.SubCmd))] = m_NAtagSCUseSkill
|
| | |
|
| | |
|
| | | #------------------------------------------------------
|
| | | # B5 04 拍卖行新上架拍品 #tagGCAddAuctionItemInfo
|
| | |
|
| | | class tagGCAddAuctionItem(Structure):
|
| | |
| | | def __oneKeyLineup(curPlayer, msgList):
|
| | | ## 阵容上阵: Hero f 阵容ID [武将ID ...]
|
| | | lineupID = msgList[1] if len(msgList) > 1 else 0
|
| | | heroIDList = list(set(msgList[2:])) # 去重,单阵容武将ID不能重复
|
| | | |
| | | heroIDList = []
|
| | | for heroID in msgList[2:]: # 去重,单阵容武将ID不能重复
|
| | | if heroID not in heroIDList:
|
| | | heroIDList.append(heroID)
|
| | | if lineupID not in ShareDefine.LineupList:
|
| | | GameWorld.DebugAnswer(curPlayer, "不存在该阵容: %s" % lineupID)
|
| | | return
|
| | |
| | | if not gmList:
|
| | | GameWorld.DebugAnswer(curPlayer, "重置主线: MainLevel 0")
|
| | | GameWorld.DebugAnswer(curPlayer, "设置主线: MainLevel 章节 关卡 波")
|
| | | GameWorld.DebugAnswer(curPlayer, "测试掉落: MainLevel d 击杀数")
|
| | | GameWorld.DebugAnswer(curPlayer, "测试掉落: MainLevel d 战锤数")
|
| | | GameWorld.DebugAnswer(curPlayer, "重置战利: MainLevel b 0")
|
| | | GameWorld.DebugAnswer(curPlayer, "设置战利: MainLevel b 战利品ID 已掉落个数")
|
| | | return
|
| | |
| | | value = gmList[0]
|
| | |
|
| | | if value == "d":
|
| | | killCnt = gmList[1] if len(gmList) > 1 else 1
|
| | | GameLogic_MainLevel.GMTestKillDrop(curPlayer, killCnt)
|
| | | unXiantao = gmList[1] if len(gmList) > 1 else 1
|
| | | GameLogic_MainLevel.GMTestKillDrop(curPlayer, unXiantao)
|
| | | return
|
| | |
|
| | | if value == "b":
|
| | |
| | | else:
|
| | | sendPack.Value = value
|
| | | sendPack.ValueEx = 0
|
| | | turnFight = TurnAttack.GetTurnFightMgr().getNPCTurnFight(gameObj.GetID())
|
| | | if turnFight:
|
| | | turnFight.addBatPack(sendPack)
|
| | | return
|
| | | #turnFight = TurnAttack.GetTurnFightMgr().getTurnFight(gameObj.GetTFGUID())
|
| | | #if turnFight:
|
| | | # turnFight.addBatPack(sendPack)
|
| | | # return
|
| | | gameObj.NotifyAll(sendPack.GetBuffer(), sendPack.GetLength())
|
| | | return
|
| | |
| | |
|
| | | return callFunc(curPlayer, mapID, funcLineID, tagType, tagID, valueList)
|
| | |
|
| | | def OnPlayerLineupAttackSuccess(curPlayer, atkObj, defObj, curSkill, mapID, funcLineID):
|
| | | ## 回合战斗主动发起的玩家阵容释放技能成功
|
| | | do_FBLogic_ID = __GetFBLogic_MapID(mapID)
|
| | | |
| | | callFunc = GameWorld.GetExecFunc(FBProcess, "GameLogic_%s.%s" % (do_FBLogic_ID, "OnPlayerLineupAttackSuccess"))
|
| | | |
| | | if callFunc:
|
| | | callFunc(curPlayer, atkObj, defObj, curSkill, mapID, funcLineID)
|
| | | |
| | | return
|
| | |
|
| | | def OnPlayerLineupAttackResult(curPlayer, atkObj, defObj, curSkill, mapID, funcLineID):
|
| | | ## 回合战斗主动发起的玩家阵容攻击结果额外处理
|
| | | def OnPlayerLineupAttackResult(curPlayer, atkObj, killObjIDList, useSkill, mapID, funcLineID):
|
| | | ## 回合战斗主动发起的玩家阵容攻击结果额外处理 ,一般处理副本相关的掉落、奖励等
|
| | | do_FBLogic_ID = __GetFBLogic_MapID(mapID)
|
| | |
|
| | | callFunc = GameWorld.GetExecFunc(FBProcess, "GameLogic_%s.%s" % (do_FBLogic_ID, "OnPlayerLineupAttackResult"))
|
| | |
|
| | | if callFunc:
|
| | | callFunc(curPlayer, atkObj, defObj, curSkill, mapID, funcLineID)
|
| | | callFunc(curPlayer, atkObj, killObjIDList, useSkill, mapID, funcLineID)
|
| | |
|
| | | return
|
| | |
|
| | |
| | | import ChConfig
|
| | | import GameWorld
|
| | | import ShareDefine
|
| | | import SkillCommon
|
| | | import IpyGameDataPY
|
| | | import PlayerControl
|
| | | import ChPyNetSendPack
|
| | | import ItemControler
|
| | | import IPY_GameWorld
|
| | | import NetPackCommon
|
| | | import TurnAttack
|
| | | import ItemCommon
|
| | | import NPCCommon
|
| | | import ChEquip
|
| | | import ObjPool
|
| | |
|
| | | import random
|
| | |
|
| | |
| | | def ResetBootyDropToday(curPlayer):
|
| | | bootyItemIDList = GetBootyItemIDList()
|
| | | for itemID in bootyItemIDList:
|
| | | PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_UnXiantaoCntBooty % itemID, 0)
|
| | | if curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_BootyDropToday % itemID):
|
| | | PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_BootyDropToday % itemID, 0)
|
| | | SyncDropBootyInfo(curPlayer)
|
| | |
| | | ipyData = ipyDataMgr.GetMainChapterByIndex(chapterCount - 1)
|
| | | return [booty[0] for booty in ipyData.GetDailyBootyUpperList()]
|
| | |
|
| | | def OnPlayerLineupAttackSuccess(curPlayer, atkObj, defObj, curSkill, mapID, funcLineID):
|
| | | ## 回合战斗主动发起的玩家阵容释放技能成功
|
| | | def OnPlayerLineupAttackResult(curPlayer, atkObj, killObjIDList, useSkill, mapID, funcLineID):
|
| | | ## 回合战斗主动发起的玩家阵容攻击结果额外处理 ,一般处理副本相关的掉落、奖励等
|
| | |
|
| | | if mapID == ChConfig.Def_FBMapID_Main:
|
| | | __doCostZhanchui(curPlayer, atkObj, curSkill)
|
| | | __doKillAward(curPlayer, atkObj, killObjIDList)
|
| | |
|
| | | return
|
| | |
|
| | | def __doCostZhanchui(curPlayer, atkObj, curSkill):
|
| | | ## 扣除战锤消耗
|
| | | costZhanchui = 0
|
| | | isXP = SkillCommon.isAngerSkill(curSkill)
|
| | | turnBattleType = atkObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnBattleType)
|
| | | if isXP:
|
| | | costZhanchui = IpyGameDataPY.GetFuncCfg("ZhanchuiCost", 2)
|
| | | elif turnBattleType == ChConfig.TurnBattleType_Combo:
|
| | | costZhanchui = IpyGameDataPY.GetFuncCfg("ZhanchuiCost", 3)
|
| | | elif turnBattleType == ChConfig.TurnBattleType_AtkBack:
|
| | | costZhanchui = IpyGameDataPY.GetFuncCfg("ZhanchuiCost", 4)
|
| | | elif SkillCommon.isTurnNormalSkill(curSkill):
|
| | | costZhanchui = IpyGameDataPY.GetFuncCfg("ZhanchuiCost", 1)
|
| | | |
| | | if costZhanchui <= 0:
|
| | | return
|
| | | |
| | | fightPoint = max(curPlayer.GetFightPoint(), 1) # 主线战斗消耗倍值,默认1
|
| | | costZhanchuiTotal = costZhanchui * fightPoint
|
| | | if not PlayerControl.PayMoney(curPlayer, ShareDefine.TYPE_Price_Xiantao, costZhanchuiTotal, isNotify=False):
|
| | | # 不足时,有多少扣多少
|
| | | nowMoney = PlayerControl.GetMoney(curPlayer, ShareDefine.TYPE_Price_Xiantao)
|
| | | PlayerControl.PayMoney(curPlayer, ShareDefine.TYPE_Price_Xiantao, min(nowMoney, costZhanchuiTotal), isNotify=False)
|
| | | |
| | | return
|
| | |
|
| | | def OnPlayerLineupAttackResult(curPlayer, atkObj, defObj, curSkill, mapID, funcLineID):
|
| | | |
| | | if mapID == ChConfig.Def_FBMapID_Main:
|
| | | __doKillAward(curPlayer, atkObj, mapID, funcLineID)
|
| | | |
| | | return
|
| | |
|
| | | def __doKillAward(curPlayer, atkObj, mapID, funcLineID):
|
| | | def __doKillAward(curPlayer, atkObj, killObjIDList):
|
| | | ## 计算击杀奖励
|
| | | turnFight = TurnAttack.GetTurnFightMgr().getNPCTurnFight(atkObj.GetID())
|
| | | if not turnFight:
|
| | | if not killObjIDList:
|
| | | GameWorld.DebugLog("没有击杀不需要处理!")
|
| | | return
|
| | | |
| | | unXiantaoCntExp = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_UnXiantaoCntExp)
|
| | | if not turnFight.playerKillObjIDList:
|
| | | unXiantaoCntEquip = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_UnXiantaoCntEquip)
|
| | | GameWorld.DebugLog("没有击杀不需要处理! unXiantaoCntExp=%s,unXiantaoCntEquip=%s" % (unXiantaoCntExp, unXiantaoCntEquip))
|
| | | return
|
| | | killCnt = len(turnFight.playerKillObjIDList)
|
| | | # 直接重置,防止异常时重复结算
|
| | | turnFight.playerKillObjIDList = []
|
| | | |
| | | # 结算经验
|
| | | unXiantaoCntExp = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_UnXiantaoCntExp)
|
| | | if unXiantaoCntExp:
|
| | | PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_UnXiantaoCntExp, 0)
|
| | | perExp = IpyGameDataPY.GetFuncCfg("Mainline", 1) # 每个战锤增加经验
|
| | |
| | | GameWorld.DebugLog("增加经验: totalExp=%s,unXiantaoCntExp=%s" % (totalExp, unXiantaoCntExp))
|
| | | PlayerControl.PlayerControl(curPlayer).AddExp(totalExp, ShareDefine.Def_ViewExpType_KillNPC)
|
| | |
|
| | | __doMainDrop(curPlayer, killCnt)
|
| | | __doMainDrop(curPlayer)
|
| | | return
|
| | |
|
| | | def __doMainDrop(curPlayer, killCnt):
|
| | | def __doMainDrop(curPlayer):
|
| | | # 装备掉落
|
| | | __doDropEquip(curPlayer)
|
| | |
|
| | | playerID = curPlayer.GetPlayerID()
|
| | | DailyBootyUpperList, BootyWeightList = [], []
|
| | | DailyBootyUpperList = []
|
| | | chapterID = PlayerControl.GetMainLevelNowInfo(curPlayer)[0]
|
| | | chapterIpyData = IpyGameDataPY.GetIpyGameData("MainChapter", chapterID)
|
| | | if chapterIpyData:
|
| | | DailyBootyUpperList = chapterIpyData.GetDailyBootyUpperList()
|
| | | BootyWeightList = chapterIpyData.GetBootyWeightList()
|
| | | |
| | | bootyDropUpperDict = {k:v for k, v in DailyBootyUpperList} |
| | | GameWorld.DebugLog("可掉落战利品上限: chapterID=%s,%s,killCnt=%s" % (chapterID, bootyDropUpperDict, killCnt), playerID)
|
| | | |
| | | GameWorld.DebugLog("可掉落战利品上限: chapterID=%s, %s" % (chapterID, DailyBootyUpperList), playerID)
|
| | |
|
| | | # 其他战利品掉落
|
| | | for _ in range(killCnt):
|
| | | dropInfo = GameWorld.GetResultByWeightList(BootyWeightList)
|
| | | if not dropInfo:
|
| | | continue
|
| | | itemID = dropInfo[0]
|
| | | if not itemID:
|
| | | GameWorld.DebugLog("本次不掉落战利品!", playerID)
|
| | | continue
|
| | | if itemID not in bootyDropUpperDict:
|
| | | GameWorld.DebugLog("该战利品未解锁! itemID=%s" % itemID, playerID)
|
| | | bootyDropNeedDict = IpyGameDataPY.GetFuncEvalCfg("MainBootyDrop", 1, {})
|
| | | bootyDropCntDict = IpyGameDataPY.GetFuncEvalCfg("MainBootyDrop", 2, {})
|
| | | for itemID, dropUpper in DailyBootyUpperList:
|
| | | if dropUpper <= 0:
|
| | | continue
|
| | | todyDropCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_BootyDropToday % itemID)
|
| | | dropUpper = bootyDropUpperDict.get(itemID, 0)
|
| | | if todyDropCnt >= dropUpper:
|
| | | GameWorld.DebugLog("战利品已达今日掉落上限! itemID=%s,todyDropCnt=%s >= %s" % (itemID, todyDropCnt, dropUpper), playerID)
|
| | | continue
|
| | | if itemID not in bootyDropNeedDict or itemID not in bootyDropCntDict:
|
| | | continue
|
| | | dropOneNeed = bootyDropNeedDict[itemID]
|
| | | unXiantaoCntBooty = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_UnXiantaoCntBooty % itemID)
|
| | | dropBootyCnt = unXiantaoCntBooty / dropOneNeed
|
| | | if dropBootyCnt <= 0:
|
| | | continue
|
| | |
|
| | | dropMin = dropInfo[1] if len(dropInfo) > 1 else 1
|
| | | dropMax = dropInfo[2] if len(dropInfo) > 2 else 1
|
| | | dropCntRange = bootyDropCntDict[itemID]
|
| | | if not isinstance(dropCntRange, (list, tuple)) or len(dropCntRange) != 2:
|
| | | continue
|
| | | dropMin = dropCntRange[0]
|
| | | dropMax = dropCntRange[1]
|
| | |
|
| | | if dropMin == dropMax:
|
| | | dropCnt = dropMin
|
| | | else:
|
| | | dropCnt = random.randint(dropMin, dropMax)
|
| | | dropCnt = min(dropCnt, dropUpper - todyDropCnt)
|
| | | dropCntTotal = 0
|
| | | for _ in range(dropBootyCnt):
|
| | | if dropMin == dropMax:
|
| | | dropCnt = dropMin
|
| | | else:
|
| | | dropCnt = random.randint(dropMin, dropMax)
|
| | | dropCntTotal += dropCnt
|
| | | dropCntTotal = min(dropCntTotal, dropUpper - todyDropCnt)
|
| | | if dropCntTotal <= 0:
|
| | | continue
|
| | |
|
| | | GameWorld.DebugLog("掉落战利品! itemID=%s,dropCnt=%s" % (itemID, dropCnt), playerID)
|
| | | curItem = ItemControler.GetOutPutItemObj(itemID, dropCnt, False, curPlayer=curPlayer)
|
| | | GameWorld.DebugLog("掉落战利品! itemID=%s,unXiantaoCntBooty=%s,次数=%s,dropCntTotal=%s" % (itemID, unXiantaoCntBooty, dropBootyCnt, dropCntTotal), playerID)
|
| | | curItem = ItemControler.GetOutPutItemObj(itemID, dropCntTotal, False, curPlayer=curPlayer)
|
| | | if curItem == None:
|
| | | continue
|
| | | curItem.SetIsBind(1) # 为1时代表是掉落
|
| | | if not ItemControler.DoLogic_PutItemInPack(curPlayer, curItem, packIndexList=[IPY_GameWorld.rptIdentify]):
|
| | | continue
|
| | | SetBootyDropToday(curPlayer, itemID, todyDropCnt + dropCnt)
|
| | | |
| | | unXiantaoCntBooty = unXiantaoCntBooty % dropOneNeed
|
| | | PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_UnXiantaoCntBooty % itemID, unXiantaoCntBooty)
|
| | | SetBootyDropToday(curPlayer, itemID, todyDropCnt + dropCntTotal)
|
| | | |
| | | return
|
| | |
|
| | | def __doDropEquip(curPlayer):
|
| | |
| | |
|
| | | return
|
| | |
|
| | | def GMTestKillDrop(curPlayer, killCnt):
|
| | | def GMTestKillDrop(curPlayer, unXiantao):
|
| | | ## GM测试掉落
|
| | | unXiantaoCntEquip = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_UnXiantaoCntEquip) + killCnt
|
| | | unXiantaoCntEquip = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_UnXiantaoCntEquip) + unXiantao
|
| | | PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_UnXiantaoCntEquip, unXiantaoCntEquip)
|
| | | __doMainDrop(curPlayer, killCnt)
|
| | | |
| | | unXiantaoCntEquip = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_UnXiantaoCntEquip)
|
| | | GameWorld.DebugAnswer(curPlayer, "剩余未结算装备掉落战锤数:%s" % unXiantaoCntEquip)
|
| | | GameWorld.DebugAnswer(curPlayer, "未结算装备战锤数: %s" % unXiantaoCntEquip)
|
| | | chapterID = PlayerControl.GetMainLevelNowInfo(curPlayer)[0]
|
| | | chapterIpyData = IpyGameDataPY.GetIpyGameData("MainChapter", chapterID)
|
| | | if chapterIpyData:
|
| | | DailyBootyUpperList = chapterIpyData.GetDailyBootyUpperList()
|
| | | for itemID, upperCnt in DailyBootyUpperList:
|
| | | if upperCnt <= 0:
|
| | | continue
|
| | | unXiantaoCntBooty = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_UnXiantaoCntBooty % itemID) + unXiantao
|
| | | PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_UnXiantaoCntBooty % itemID, unXiantaoCntBooty)
|
| | | GameWorld.DebugAnswer(curPlayer, "未结算战利品(%s)战锤数: %s" % (itemID, unXiantaoCntBooty))
|
| | | |
| | | __doMainDrop(curPlayer)
|
| | | return
|
| | |
|
| | | #// B4 15 主线掉落物品操作 #tagCSMainDropItemOP
|
| | |
| | | syncItemIDList = GetBootyItemIDList()
|
| | | else:
|
| | | syncItemIDList = [itemID]
|
| | | clientPack = ChPyNetSendPack.tagSCDropBootyInfo()
|
| | | poolMgr = ObjPool.GetPoolMgr()
|
| | | clientPack = poolMgr.acquire(ChPyNetSendPack.tagSCDropBootyInfo)
|
| | | clientPack.DropBootyList = []
|
| | | for itemID in syncItemIDList:
|
| | | dropBooty = ChPyNetSendPack.tagSCDropBooty()
|
| | | dropBooty = poolMgr.acquire(ChPyNetSendPack.tagSCDropBooty)
|
| | | dropBooty.ItemID = itemID
|
| | | dropBooty.TodayDropCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_BootyDropToday % itemID)
|
| | | clientPack.DropBootyList.append(dropBooty)
|
| | |
| | | import ShareDefine
|
| | | import PlayerTeam
|
| | | import PyGameData
|
| | | import BattleObj
|
| | | import ObjPool
|
| | |
|
| | | import datetime
|
| | | import time
|
| | |
| | | #GameWorldActionControl.Dispose_DailyActionState()
|
| | | #GameWorldActionControl.Dispose_FBStateTime()
|
| | | PlayerOnline.OnMinute()
|
| | | BattleObj.OnMinute()
|
| | | ObjPool.OnMinute()
|
| | |
|
| | | PlayerTeam.OnCheckTeamPlayerDisconnectTimeout(tick)
|
| | | __CheckIpyDataRecycle(curTime)
|
| | |
| | | ("BYTE", "OPLimitInAct", 0),
|
| | | ),
|
| | |
|
| | | "NPC":(
|
| | | ("DWORD", "NPCID", 1),
|
| | | ("char", "NPCName", 0),
|
| | | ("BYTE", "Country", 0),
|
| | | ("BYTE", "AtkDistType", 0),
|
| | | ("WORD", "LV", 0),
|
| | | ("DWORD", "Atk", 0),
|
| | | ("DWORD", "Def", 0),
|
| | | ("DWORD", "MaxHP", 0),
|
| | | ("list", "SkillIDList", 0),
|
| | | ("DWORD", "FinalDamPer", 0),
|
| | | ("DWORD", "FinalDamPerDef", 0),
|
| | | ("DWORD", "MissRate", 0),
|
| | | ("DWORD", "MissRateDef", 0),
|
| | | ("DWORD", "SuperHitRate", 0),
|
| | | ("DWORD", "SuperHitRateDef", 0),
|
| | | ("DWORD", "StunRate", 0),
|
| | | ("DWORD", "StunRateDef", 0),
|
| | | ("DWORD", "ComboRate", 0),
|
| | | ("DWORD", "ComboRateDef", 0),
|
| | | ("DWORD", "ParryRate", 0),
|
| | | ("DWORD", "ParryRateDef", 0),
|
| | | ("DWORD", "SuckHPPer", 0),
|
| | | ("DWORD", "SuckHPPerDef", 0),
|
| | | ("dict", "SpecAttrInfo", 0),
|
| | | ),
|
| | |
|
| | | "Skill":(
|
| | | ("DWORD", "SkillID", 1),
|
| | | ("DWORD", "SkillTypeID", 0),
|
| | | ("WORD", "SkillMaxLV", 0),
|
| | | ("char", "SkillName", 0),
|
| | | ("BYTE", "FuncType", 0),
|
| | | ("BYTE", "SkillType", 0),
|
| | | ("BYTE", "HurtType", 0),
|
| | | ("BYTE", "AtkType", 0),
|
| | | ("BYTE", "TagAim", 0),
|
| | | ("BYTE", "TagFriendly", 0),
|
| | | ("BYTE", "TagAffect", 0),
|
| | | ("BYTE", "TagCount", 0),
|
| | | ("WORD", "HappenRate", 0),
|
| | | ("WORD", "LastTime", 0),
|
| | | ("WORD", "CoolDownTime", 0),
|
| | | ("WORD", "Priority", 0),
|
| | | ("DWORD", "EffectID1", 0),
|
| | | ("list", "EffectValues1", 0),
|
| | | ("DWORD", "EffectID2", 0),
|
| | | ("list", "EffectValues2", 0),
|
| | | ("DWORD", "EffectID3", 0),
|
| | | ("list", "EffectValues3", 0),
|
| | | ("DWORD", "ConnSkill", 0),
|
| | | ("list", "EnhanceSkillList", 0),
|
| | | ("DWORD", "FightPower", 0),
|
| | | ),
|
| | |
|
| | | "Hero":(
|
| | | ("DWORD", "HeroID", 1),
|
| | | ("char", "Name", 0),
|
| | | ("BYTE", "Country", 0),
|
| | | ("BYTE", "Quality", 0),
|
| | | ("BYTE", "AtkDistType", 0),
|
| | |
| | | "MainChapter":(
|
| | | ("BYTE", "ChapterID", 1),
|
| | | ("list", "DailyBootyUpperList", 0),
|
| | | ("list", "BootyWeightList", 0),
|
| | | ),
|
| | |
|
| | | "MainLevel":(
|
| | |
| | | ("float", "AttrPer", 0),
|
| | | ("dict", "AttrSpecDict", 0),
|
| | | ("dict", "AttrExDict", 0),
|
| | | ),
|
| | |
|
| | | "NPCEx":(
|
| | | ("DWORD", "NPCID", 1),
|
| | | ("BYTE", "FightPowerLackAtkLimit", 0),
|
| | | ("DWORD", "SuppressFightPower", 0),
|
| | | ("BYTE", "AtkDistType", 0),
|
| | | ("DWORD", "Atk", 0),
|
| | | ("DWORD", "Def", 0),
|
| | | ("DWORD", "MaxHP", 0),
|
| | | ("list", "SkillIDList", 0),
|
| | | ("DWORD", "FinalHurtPer", 0),
|
| | | ("DWORD", "FinalHurtReducePer", 0),
|
| | | ("DWORD", "MissRate", 0),
|
| | | ("DWORD", "MissDefRate", 0),
|
| | | ("DWORD", "SuperHitRate", 0),
|
| | | ("DWORD", "SuperHitRateReduce", 0),
|
| | | ("DWORD", "FaintRate", 0),
|
| | | ("DWORD", "FaintDefRate", 0),
|
| | | ("DWORD", "ComboRate", 0),
|
| | | ("DWORD", "ComboDefRate", 0),
|
| | | ("DWORD", "ParryRate", 0),
|
| | | ("DWORD", "ParryDefRate", 0),
|
| | | ("DWORD", "ParryDamPer", 0),
|
| | | ("DWORD", "SuckHPPer", 0),
|
| | | ("DWORD", "SuckHPDefPer", 0),
|
| | | ("dict", "SpecAttrInfo", 0),
|
| | | ),
|
| | |
|
| | | "NPCRealmStrengthen":(
|
| | |
| | | def GetSortReverse(self): return self.attrTuple[6] # 是否倒序 BYTE
|
| | | def GetOPLimitInAct(self): return self.attrTuple[7] # 活动期间限制队伍操作 BYTE |
| | | |
| | | # NPC表 |
| | | class IPY_NPC(): |
| | | |
| | | def __init__(self): |
| | | self.attrTuple = None |
| | | return |
| | | |
| | | def GetNPCID(self): return self.attrTuple[0] # NPCID DWORD
|
| | | def GetNPCName(self): return self.attrTuple[1] # 名称 char
|
| | | def GetCountry(self): return self.attrTuple[2] # 国家 BYTE
|
| | | def GetAtkDistType(self): return self.attrTuple[3] # 远近类型;1-近战;2-远程 BYTE
|
| | | def GetLV(self): return self.attrTuple[4] # 等级 WORD
|
| | | def GetAtk(self): return self.attrTuple[5] # 攻击力 DWORD
|
| | | def GetDef(self): return self.attrTuple[6] # 防御值 DWORD
|
| | | def GetMaxHP(self): return self.attrTuple[7] # 最大生命值,可超过20E DWORD
|
| | | def GetSkillIDList(self): return self.attrTuple[8] # 技能ID列表 list
|
| | | def GetFinalDamPer(self): return self.attrTuple[9] # 最终增伤 DWORD
|
| | | def GetFinalDamPerDef(self): return self.attrTuple[10] # 最终减伤 DWORD
|
| | | def GetMissRate(self): return self.attrTuple[11] # 闪避概率 DWORD
|
| | | def GetMissRateDef(self): return self.attrTuple[12] # 抗闪避概率 DWORD
|
| | | def GetSuperHitRate(self): return self.attrTuple[13] # 暴击概率 DWORD
|
| | | def GetSuperHitRateDef(self): return self.attrTuple[14] # 抗暴击概率 DWORD
|
| | | def GetStunRate(self): return self.attrTuple[15] # 击晕概率 DWORD
|
| | | def GetStunRateDef(self): return self.attrTuple[16] # 抗击晕概率 DWORD
|
| | | def GetComboRate(self): return self.attrTuple[17] # 连击概率 DWORD
|
| | | def GetComboRateDef(self): return self.attrTuple[18] # 抗连击概率 DWORD
|
| | | def GetParryRate(self): return self.attrTuple[19] # 格挡概率 DWORD
|
| | | def GetParryRateDef(self): return self.attrTuple[20] # 抗格挡概率 DWORD
|
| | | def GetSuckHPPer(self): return self.attrTuple[21] # 吸血比率 DWORD
|
| | | def GetSuckHPPerDef(self): return self.attrTuple[22] # 抗吸血比率 DWORD
|
| | | def GetSpecAttrInfo(self): return self.attrTuple[23] # 特殊属性信息 {"属性ID":值, ...} dict |
| | | |
| | | # 技能表 |
| | | class IPY_Skill(): |
| | | |
| | | def __init__(self): |
| | | self.attrTuple = None |
| | | return |
| | | |
| | | def GetSkillID(self): return self.attrTuple[0] # 技能ID DWORD
|
| | | def GetSkillTypeID(self): return self.attrTuple[1] # 技能TypeID DWORD
|
| | | def GetSkillMaxLV(self): return self.attrTuple[2] # 最高等级 WORD
|
| | | def GetSkillName(self): return self.attrTuple[3] # 技能名 char
|
| | | def GetFuncType(self): return self.attrTuple[4] # 功能分类 BYTE
|
| | | def GetSkillType(self): return self.attrTuple[5] # 技能类型 BYTE
|
| | | def GetHurtType(self): return self.attrTuple[6] # 伤害类型 BYTE
|
| | | def GetAtkType(self): return self.attrTuple[7] # 释放方式 BYTE
|
| | | def GetTagAim(self): return self.attrTuple[8] # 瞄准位置 BYTE
|
| | | def GetTagFriendly(self): return self.attrTuple[9] # 敌我目标 BYTE
|
| | | def GetTagAffect(self): return self.attrTuple[10] # 目标细分 BYTE
|
| | | def GetTagCount(self): return self.attrTuple[11] # 目标个数 BYTE
|
| | | def GetHappenRate(self): return self.attrTuple[12] # 释放或添加几率 WORD
|
| | | def GetLastTime(self): return self.attrTuple[13] # 持续时间 WORD
|
| | | def GetCoolDownTime(self): return self.attrTuple[14] # 冷却时间 WORD
|
| | | def GetPriority(self): return self.attrTuple[15] # 优先级 WORD
|
| | | def GetEffectID1(self): return self.attrTuple[16] # 效果ID1 DWORD
|
| | | def GetEffectValues1(self): return self.attrTuple[17] # 效果值列表1 list
|
| | | def GetEffectID2(self): return self.attrTuple[18] # 效果ID2 DWORD
|
| | | def GetEffectValues2(self): return self.attrTuple[19] # 效果值列表2 list
|
| | | def GetEffectID3(self): return self.attrTuple[20] # 效果ID3 DWORD
|
| | | def GetEffectValues3(self): return self.attrTuple[21] # 效果值列表3 list
|
| | | def GetConnSkill(self): return self.attrTuple[22] # 关联技能 DWORD
|
| | | def GetEnhanceSkillList(self): return self.attrTuple[23] # 触发技能ID列表 list
|
| | | def GetFightPower(self): return self.attrTuple[24] # 技能战斗力 DWORD |
| | | |
| | | # 武将表 |
| | | class IPY_Hero(): |
| | | |
| | |
| | | return |
| | | |
| | | def GetHeroID(self): return self.attrTuple[0] # 英雄ID DWORD
|
| | | def GetCountry(self): return self.attrTuple[1] # 国家 BYTE
|
| | | def GetQuality(self): return self.attrTuple[2] # 品质 BYTE
|
| | | def GetAtkDistType(self): return self.attrTuple[3] # 远近类型;1-近战;2-远程 BYTE
|
| | | def GetSkinIDList(self): return self.attrTuple[4] # 皮肤ID列表 list
|
| | | def GetNormalSkillID(self): return self.attrTuple[5] # 普攻技能ID DWORD
|
| | | def GetAngerSkillID(self): return self.attrTuple[6] # 怒气技能ID DWORD
|
| | | def GetAtkInheritPer(self): return self.attrTuple[7] # 攻击继承 WORD
|
| | | def GetDefInheritPer(self): return self.attrTuple[8] # 防御继承 WORD
|
| | | def GetHPInheritPer(self): return self.attrTuple[9] # 生命继承 WORD
|
| | | def GetBatAttrDict(self): return self.attrTuple[10] # 其他战斗属性字典 {"属性ID":值, ...} dict
|
| | | def GetFetterIDList(self): return self.attrTuple[11] # 羁绊ID列表 list |
| | | def GetName(self): return self.attrTuple[1] # 名称 char
|
| | | def GetCountry(self): return self.attrTuple[2] # 国家 BYTE
|
| | | def GetQuality(self): return self.attrTuple[3] # 品质 BYTE
|
| | | def GetAtkDistType(self): return self.attrTuple[4] # 远近类型;1-近战;2-远程 BYTE
|
| | | def GetSkinIDList(self): return self.attrTuple[5] # 皮肤ID列表 list
|
| | | def GetNormalSkillID(self): return self.attrTuple[6] # 普攻技能ID DWORD
|
| | | def GetAngerSkillID(self): return self.attrTuple[7] # 怒气技能ID DWORD
|
| | | def GetAtkInheritPer(self): return self.attrTuple[8] # 攻击继承 WORD
|
| | | def GetDefInheritPer(self): return self.attrTuple[9] # 防御继承 WORD
|
| | | def GetHPInheritPer(self): return self.attrTuple[10] # 生命继承 WORD
|
| | | def GetBatAttrDict(self): return self.attrTuple[11] # 其他战斗属性字典 {"属性ID":值, ...} dict
|
| | | def GetFetterIDList(self): return self.attrTuple[12] # 羁绊ID列表 list |
| | | |
| | | # 武将星级天赋表 |
| | | class IPY_HeroTalent(): |
| | |
| | | return |
| | | |
| | | def GetChapterID(self): return self.attrTuple[0] # 章节ID BYTE
|
| | | def GetDailyBootyUpperList(self): return self.attrTuple[1] # 每日战利品掉落上限,[[物品ID,每日上限], ...] list
|
| | | def GetBootyWeightList(self): return self.attrTuple[2] # 战利品掉落权重,[[权重,物品ID,掉落个数下限, 上限], ...] list |
| | | def GetDailyBootyUpperList(self): return self.attrTuple[1] # 每日战利品掉落上限,[[物品ID,每日上限], ...] list |
| | | |
| | | # 主线关卡表 |
| | | class IPY_MainLevel(): |
| | |
| | | def GetAttrPer(self): return self.attrTuple[5] # 对应等级表中的比例 float
|
| | | def GetAttrSpecDict(self): return self.attrTuple[6] # 特殊属性值字典 {attrKey:value, ...} dict
|
| | | def GetAttrExDict(self): return self.attrTuple[7] # 特殊属性值字典 {attrKey:value, ...} dict |
| | | |
| | | # NPC表扩展 |
| | | class IPY_NPCEx(): |
| | | |
| | | def __init__(self): |
| | | self.attrTuple = None |
| | | return |
| | | |
| | | def GetNPCID(self): return self.attrTuple[0] # NPCID DWORD
|
| | | def GetFightPowerLackAtkLimit(self): return self.attrTuple[1] # 战力不足限制攻击 BYTE
|
| | | def GetSuppressFightPower(self): return self.attrTuple[2] # 推荐/压制战力 DWORD
|
| | | def GetAtkDistType(self): return self.attrTuple[3] # 远近类型;1-近战;2-远程 BYTE
|
| | | def GetAtk(self): return self.attrTuple[4] # 攻击力 DWORD
|
| | | def GetDef(self): return self.attrTuple[5] # 防御值 DWORD
|
| | | def GetMaxHP(self): return self.attrTuple[6] # 最大生命值,可超过20E DWORD
|
| | | def GetSkillIDList(self): return self.attrTuple[7] # 技能ID列表 list
|
| | | def GetFinalHurtPer(self): return self.attrTuple[8] # 最终增伤 DWORD
|
| | | def GetFinalHurtReducePer(self): return self.attrTuple[9] # 最终减伤 DWORD
|
| | | def GetMissRate(self): return self.attrTuple[10] # 闪避概率 DWORD
|
| | | def GetMissDefRate(self): return self.attrTuple[11] # 抗闪避概率 DWORD
|
| | | def GetSuperHitRate(self): return self.attrTuple[12] # 暴击概率 DWORD
|
| | | def GetSuperHitRateReduce(self): return self.attrTuple[13] # 抗暴击概率 DWORD
|
| | | def GetFaintRate(self): return self.attrTuple[14] # 击晕概率 DWORD
|
| | | def GetFaintDefRate(self): return self.attrTuple[15] # 抗击晕概率 DWORD
|
| | | def GetComboRate(self): return self.attrTuple[16] # 连击概率 DWORD
|
| | | def GetComboDefRate(self): return self.attrTuple[17] # 抗连击概率 DWORD
|
| | | def GetParryRate(self): return self.attrTuple[18] # 格挡概率 DWORD
|
| | | def GetParryDefRate(self): return self.attrTuple[19] # 抗格挡概率 DWORD
|
| | | def GetParryDamPer(self): return self.attrTuple[20] # 格挡减伤比率 DWORD
|
| | | def GetSuckHPPer(self): return self.attrTuple[21] # 吸血比率 DWORD
|
| | | def GetSuckHPDefPer(self): return self.attrTuple[22] # 抗吸血比率 DWORD
|
| | | def GetSpecAttrInfo(self): return self.attrTuple[23] # 特殊属性信息 {"属性ID":值, ...} dict |
| | | |
| | | # 成长型境界怪物表 |
| | | class IPY_NPCRealmStrengthen(): |
| | |
| | | self.__LoadFileData("DirtyList", onlyCheck)
|
| | | self.__LoadFileData("DirtyName", onlyCheck)
|
| | | self.__LoadFileData("FuncTeamSet", onlyCheck)
|
| | | self.__LoadFileData("NPC", onlyCheck)
|
| | | self.__LoadFileData("Skill", onlyCheck)
|
| | | self.__LoadFileData("Hero", onlyCheck)
|
| | | self.__LoadFileData("HeroTalent", onlyCheck)
|
| | | self.__LoadFileData("HeroBreak", onlyCheck)
|
| | |
| | | self.__LoadFileData("PlayerLV", onlyCheck)
|
| | | self.__LoadFileData("SpecMapPlayerAttrFormat", onlyCheck)
|
| | | self.__LoadFileData("GMAttr", onlyCheck)
|
| | | self.__LoadFileData("NPCEx", onlyCheck)
|
| | | self.__LoadFileData("NPCRealmStrengthen", onlyCheck)
|
| | | self.__LoadFileData("NPCStrengthen", onlyCheck)
|
| | | self.__LoadFileData("NPCTimeLostHP", onlyCheck)
|
| | |
| | | def GetFuncTeamSetByIndex(self, index): |
| | | self.CheckLoadData("FuncTeamSet") |
| | | return self.ipyFuncTeamSetCache[index]
|
| | | |
| | | def GetNPCCount(self): |
| | | self.CheckLoadData("NPC") |
| | | return self.ipyNPCLen
|
| | | def GetNPCByIndex(self, index): |
| | | self.CheckLoadData("NPC") |
| | | return self.ipyNPCCache[index]
|
| | | |
| | | def GetSkillCount(self): |
| | | self.CheckLoadData("Skill") |
| | | return self.ipySkillLen
|
| | | def GetSkillByIndex(self, index): |
| | | self.CheckLoadData("Skill") |
| | | return self.ipySkillCache[index]
|
| | | |
| | | def GetHeroCount(self): |
| | | self.CheckLoadData("Hero") |
| | |
| | | def GetGMAttrByIndex(self, index): |
| | | self.CheckLoadData("GMAttr") |
| | | return self.ipyGMAttrCache[index]
|
| | | |
| | | def GetNPCExCount(self): |
| | | self.CheckLoadData("NPCEx") |
| | | return self.ipyNPCExLen
|
| | | def GetNPCExByIndex(self, index): |
| | | self.CheckLoadData("NPCEx") |
| | | return self.ipyNPCExCache[index]
|
| | | |
| | | def GetNPCRealmStrengthenCount(self): |
| | | self.CheckLoadData("NPCRealmStrengthen") |
| | |
| | | return realmNPCIpyData.GetLV()
|
| | | return curNPC.GetLV()
|
| | |
|
| | | def GetNPCDataEx(npcID):
|
| | | ## 获取NPC扩展数据表,可热更
|
| | | npcDataEx = IpyGameDataPY.GetIpyGameDataNotLog("NPCEx", npcID)
|
| | | def GetNPCDataPy(npcID):
|
| | | ## 获取NPC数据表,py自定义的表,可热更
|
| | | npcDataEx = IpyGameDataPY.GetIpyGameDataNotLog("NPC", npcID)
|
| | | if not npcDataEx:
|
| | | if False: # 不可能成立的条件,只为了 . 出代码提示
|
| | | npcDataEx = IpyGameDataPY.IPY_NPCEx()
|
| | | npcDataEx = IpyGameDataPY.IPY_NPC()
|
| | | return npcDataEx
|
| | | return npcDataEx
|
| | |
|
| | |
| | | def SetRealmLV(curNPC, realmLV): return curNPC.SetMAtkMin(realmLV) # NPC表中此字段含义改成境界等级
|
| | | def GetIsLVSuppress(curNPC): return curNPC.GetWindDef() # 风防代表是否等级压制
|
| | | def GetFightPowerLackAtkLimit(curNPC): # 战力不足限制攻击,默认不限制
|
| | | npcDataEx = GetNPCDataEx(curNPC.GetNPCID())
|
| | | return npcDataEx.GetFightPowerLackAtkLimit() if npcDataEx else 0
|
| | | def GetSuppressFightPower(curNPC):
|
| | | npcDataEx = GetNPCDataEx(curNPC.GetNPCID())
|
| | | return npcDataEx.GetSuppressFightPower() if npcDataEx else curNPC.GetThunderDef() # 雷防代表压制战力
|
| | | return 0
|
| | | def GetSuppressFightPower(curNPC): # 压制战力
|
| | | return 0
|
| | | def SetSuppressFightPower(curNPC, value): return curNPC.SetThunderDef(min(value, ShareDefine.Def_UpperLimit_DWord))
|
| | | def GetCommendFightPower(curNPC): return curNPC.GetFireDef() # 火防代表推荐战力
|
| | | def GetDropOwnerType(curNPC): return curNPC.GetThunderAtk() # 雷攻代表掉落归属类型
|
| | |
| | |
|
| | | # C++设置npc死亡
|
| | | notifyClient = True
|
| | | tfMgr = TurnAttack.GetTurnFightMgr()
|
| | | turnFight = tfMgr.getNPCTurnFight(objID)
|
| | | if turnFight:
|
| | | notifyClient = False # 回合制战斗的由py自己通知
|
| | | # //04 07 NPC消失#tagNPCDisappear 此处通知消失,与回合制死亡区分
|
| | | clientPack = ChNetSendPack.tagNPCDisappear()
|
| | | clientPack.NPCID = [objID]
|
| | | clientPack.Count = len(clientPack.NPCID)
|
| | | turnFight.addBatPack(clientPack)
|
| | | #tfMgr = TurnAttack.GetTurnFightMgr()
|
| | | #turnFight = tfMgr.getNPCTurnFight(objID)
|
| | | #if turnFight:
|
| | | # notifyClient = False # 回合制战斗的由py自己通知
|
| | | # # //04 07 NPC消失#tagNPCDisappear 此处通知消失,与回合制死亡区分
|
| | | # clientPack = ChNetSendPack.tagNPCDisappear()
|
| | | # clientPack.NPCID = [objID]
|
| | | # clientPack.Count = len(clientPack.NPCID)
|
| | | # turnFight.addBatPack(clientPack)
|
| | | curNPC.SetDead(curNPC.GetDictByKey(ChConfig.Def_NPCDead_Reason),
|
| | | curNPC.GetDictByKey(ChConfig.Def_NPCDead_KillerType),
|
| | | curNPC.GetDictByKey(ChConfig.Def_NPCDead_KillerID), notifyClient)
|
| | | tfMgr.delNPCGUID(objID)
|
| | | return
|
| | |
|
| | | def GameServer_KillGameWorldBoss(bossID, killPlayerName, hurtValue, isNotify=True, killerIDList=[]):
|
| | |
| | |
|
| | | def __notifyAppear(self):
|
| | | ## //04 06 NPC出现#tagNPCAppear,可能也有 04 08 玩家召唤NPC出现#tagPlayerSummonNPCAppear,卡牌先简化,只使用0406
|
| | | curNPC = self.__Instance
|
| | | objID = curNPC.GetID()
|
| | | turnFight = TurnAttack.GetTurnFightMgr().getNPCTurnFight(objID)
|
| | | if not turnFight:
|
| | | # 非回合制怪保留原通知
|
| | | curNPC.NotifyAppear()
|
| | | return
|
| | | #curNPC = self.__Instance
|
| | | #objID = curNPC.GetID()
|
| | | #turnFight = TurnAttack.GetTurnFightMgr().getNPCTurnFight(objID)
|
| | | #if not turnFight:
|
| | | # # 非回合制怪保留原通知
|
| | | # curNPC.NotifyAppear()
|
| | | # return
|
| | |
|
| | | # 回合制怪不通知,统一由 // B4 24 回合战斗初始化 #tagSCTurnFightInit
|
| | | return
|
| | |
| | | ChConfig.AttrID_MaxHP:3000000000,
|
| | | })
|
| | | else:
|
| | | npcDataEx = GetNPCDataEx(curNPC.GetNPCID())
|
| | | npcDataEx = GetNPCDataPy(curNPC.GetNPCID())
|
| | | if not npcDataEx:
|
| | | return
|
| | | heroAttrDict.update({
|
| | |
| | | import traceback
|
| | | import ChGameToMapPyPack
|
| | | from PyMongoDB.DBCommon import CommonDefine
|
| | | import ObjPool
|
| | | #-------------------------------------------------------------------------------
|
| | | #---全局变量---
|
| | |
|
| | |
| | | Log("SendFakePack: clientPack Len = %s > %s"%(clientPack.GetLength(), len(innerPackData)))
|
| | | #curPlayer.SendFakePack(innerPackData, len(innerPackData))
|
| | | curPlayer.SendFakePack(clientPack.GetBuffer(), clientPack.GetLength())
|
| | | ObjPool.GetPoolMgr().release(clientPack)
|
| | | return
|
| | |
|
| | | def SendFackPackOnline(clientPack, parseFunc=None, *args):
|
| | | ## 发送给全服在线玩家
|
New file |
| | |
| | | #!/usr/bin/python
|
| | | # -*- coding: GBK -*-
|
| | | #-------------------------------------------------------------------------------
|
| | | #
|
| | | ##@package ObjPool
|
| | | #
|
| | | # @todo:对象池管理
|
| | | # @author hxp
|
| | | # @date 2025-08-06
|
| | | # @version 1.0
|
| | | #
|
| | | # 详细描述: 对象池管理,建议对频繁创建的类使用对象池,如封包相关、战斗相关
|
| | | #
|
| | | #-------------------------------------------------------------------------------
|
| | | #"""Version = 2025-08-06 18:30"""
|
| | | #-------------------------------------------------------------------------------
|
| | |
|
| | | import GameWorld
|
| | | import PyGameData
|
| | | import collections
|
| | | import types
|
| | | #import sys
|
| | | #import ctypes
|
| | |
|
| | | class RecursiveObjectPoolManager(object):
|
| | | |
| | | def __init__(self):
|
| | | self._pools = {} # 存储各类的对象池 {class: pool}
|
| | | # 使用对象ID作为键的映射:{id(obj): obj_class}
|
| | | self._obj_id_to_pool = {}
|
| | | self._releasing = set() # 正在释放的对象ID集合
|
| | | |
| | | def create_pool(self, obj_class, max_size=10):
|
| | | """为指定类创建对象池
|
| | | :param obj_class: 要管理的对象类
|
| | | :param max_size: 对象池最大容量
|
| | | """
|
| | | if obj_class in self._pools:
|
| | | GameWorld.Log("Pool for %s already exists" % obj_class.__name__)
|
| | | return
|
| | | GameWorld.Log("create_pool %s, max_size=%s" % ( obj_class.__name__, max_size))
|
| | | |
| | | self._pools[obj_class] = {
|
| | | 'max_size': max_size,
|
| | | 'free_list': [], # 空闲对象列表
|
| | | 'active_list': [], # 使用中对象列表
|
| | | 'created_count': 0 # 已创建对象计数
|
| | | }
|
| | | return self
|
| | | |
| | | def acquire(self, obj_class, *args, **kwargs):
|
| | | """获取对象并记录其所属池"""
|
| | | if obj_class not in self._pools:
|
| | | # 如果池不存在,自动创建大小为0的无限制池
|
| | | self.create_pool(obj_class, 0)
|
| | | |
| | | pool = self._pools[obj_class]
|
| | | |
| | | if pool['free_list']:
|
| | | # 复用空闲对象
|
| | | obj = pool['free_list'].pop()
|
| | | # 重新初始化对象
|
| | | obj.__init__(*args, **kwargs)
|
| | | else:
|
| | | # 创建新对象
|
| | | if pool['max_size'] <= 0 or pool['created_count'] < pool['max_size']:
|
| | | obj = obj_class(*args, **kwargs)
|
| | | pool['created_count'] += 1
|
| | | # 记录对象到池的映射
|
| | | obj_id = id(obj)
|
| | | self._obj_id_to_pool[obj_id] = obj_class
|
| | | else:
|
| | | GameWorld.ErrLog("%s pool exhausted" % obj_class.__name__)
|
| | | return None # 返回None表示获取失败
|
| | | |
| | | pool['active_list'].append(obj)
|
| | | return obj
|
| | | |
| | | def release(self, obj):
|
| | | """释放对象并递归释放其嵌套对象池对象"""
|
| | | obj_id = id(obj)
|
| | | |
| | | # 检查是否正在递归释放中
|
| | | if obj_id in self._releasing:
|
| | | return
|
| | | |
| | | # 只处理对象池管理的对象
|
| | | if obj_id not in self._obj_id_to_pool:
|
| | | return
|
| | | |
| | | # 标记为正在释放
|
| | | self._releasing.add(obj_id)
|
| | | visited = set([obj_id]) # 初始化已访问集合
|
| | | |
| | | try:
|
| | | # 1. 递归释放嵌套对象池对象
|
| | | self._recursive_release(obj, visited)
|
| | | # 2. 释放当前对象
|
| | | self._return_to_pool(obj)
|
| | | finally:
|
| | | # 移除释放标记
|
| | | self._releasing.discard(obj_id)
|
| | | |
| | | def _recursive_release(self, obj, visited):
|
| | | """递归释放嵌套对象池对象(深度优先)"""
|
| | | # 获取对象的所有引用(不包含基础类型)
|
| | | for ref in self._get_references(obj):
|
| | | try:
|
| | | ref_id = id(ref)
|
| | | except TypeError:
|
| | | # 如果对象不可哈希,跳过
|
| | | continue
|
| | | |
| | | if ref_id in visited:
|
| | | continue
|
| | | visited.add(ref_id)
|
| | | |
| | | # 只处理对象池管理的对象
|
| | | if ref_id in self._obj_id_to_pool:
|
| | | # 先递归释放嵌套对象
|
| | | self._recursive_release(ref, visited)
|
| | | # 再释放当前引用对象
|
| | | self._return_to_pool(ref)
|
| | | else:
|
| | | # 对于非对象池管理的对象,继续递归查找其中的对象池对象
|
| | | self._recursive_release(ref, visited)
|
| | | |
| | | def _get_references(self, obj):
|
| | | """安全获取对象的所有直接引用,支持复杂数据结构"""
|
| | | refs = []
|
| | | obj_type = type(obj)
|
| | | |
| | | # 处理自定义对象的属性
|
| | | try:
|
| | | # 首先尝试__dict__属性
|
| | | if hasattr(obj, '__dict__'):
|
| | | for attr in dir(obj):
|
| | | if attr.startswith('__'):
|
| | | continue
|
| | | |
| | | try:
|
| | | attr_value = getattr(obj, attr)
|
| | | except Exception:
|
| | | continue
|
| | | |
| | | # 过滤基础类型
|
| | | if not self._is_basic_type(attr_value):
|
| | | refs.append(attr_value)
|
| | | except Exception:
|
| | | pass
|
| | | |
| | | # 处理常见容器类型
|
| | | if obj_type in (list, tuple, set, collections.deque):
|
| | | for item in obj:
|
| | | if not self._is_basic_type(item):
|
| | | refs.append(item)
|
| | | elif obj_type is dict:
|
| | | for key, value in obj.iteritems():
|
| | | if not self._is_basic_type(key):
|
| | | refs.append(key)
|
| | | if not self._is_basic_type(value):
|
| | | refs.append(value)
|
| | | |
| | | # 处理特殊属性(如__slots__定义的对象)
|
| | | try:
|
| | | if hasattr(obj, '__slots__'):
|
| | | for slot_name in obj.__slots__:
|
| | | if hasattr(obj, slot_name):
|
| | | slot_value = getattr(obj, slot_name)
|
| | | if not self._is_basic_type(slot_value):
|
| | | refs.append(slot_value)
|
| | | except Exception:
|
| | | pass
|
| | | |
| | | return refs
|
| | | |
| | | def _is_basic_type(self, value):
|
| | | """判断值是否为基本类型,不需要递归处理"""
|
| | | if value is None:
|
| | | return True
|
| | | if isinstance(value, (int, long, float, bool, str, unicode)):
|
| | | return True
|
| | | if isinstance(value, (types.FunctionType, types.MethodType, types.ModuleType)):
|
| | | return True
|
| | | if isinstance(value, (types.BuiltinFunctionType, type)):
|
| | | return True
|
| | | return False
|
| | | |
| | | def _return_to_pool(self, obj):
|
| | | """将对象归还到其所属池"""
|
| | | obj_id = id(obj)
|
| | | |
| | | # 获取对象所属类
|
| | | if obj_id not in self._obj_id_to_pool:
|
| | | return # 如果不在池中,忽略
|
| | | |
| | | obj_class = self._obj_id_to_pool[obj_id]
|
| | | |
| | | if obj_class not in self._pools:
|
| | | return # 如果池不存在,忽略
|
| | | |
| | | pool = self._pools[obj_class]
|
| | | |
| | | # 确保对象在活跃列表中
|
| | | if obj in pool['active_list']:
|
| | | # 从活跃列表移除
|
| | | try:
|
| | | pool['active_list'].remove(obj)
|
| | | except ValueError:
|
| | | # 如果对象不在列表中,忽略
|
| | | return
|
| | | |
| | | # 执行对象清理方法
|
| | | #if hasattr(obj, 'cleanup'):
|
| | | # try:
|
| | | # obj.cleanup()
|
| | | # except Exception:
|
| | | # pass
|
| | | |
| | | # 添加到空闲列表
|
| | | pool['free_list'].append(obj)
|
| | | else:
|
| | | # 如果在空闲列表中,跳过
|
| | | pass
|
| | | |
| | | def destroy_pool(self, obj_class):
|
| | | """销毁指定类的对象池"""
|
| | | if obj_class not in self._pools:
|
| | | return
|
| | | |
| | | pool = self._pools[obj_class]
|
| | | |
| | | # 清理所有对象
|
| | | for obj in list(pool['free_list'] + pool['active_list']):
|
| | | # 清理对象属性
|
| | | #if hasattr(obj, 'cleanup'):
|
| | | # try:
|
| | | # obj.cleanup()
|
| | | # except Exception:
|
| | | # pass
|
| | | |
| | | # 从映射中移除
|
| | | obj_id = id(obj)
|
| | | if obj_id in self._obj_id_to_pool:
|
| | | del self._obj_id_to_pool[obj_id]
|
| | | |
| | | del self._pools[obj_class]
|
| | | |
| | | def pool_status(self):
|
| | | """输出所有对象池的状态信息"""
|
| | | statusList = []
|
| | | max_name_len = 0
|
| | | max_created_len = 0
|
| | | max_free_len = 0
|
| | | max_active_len = 0
|
| | | |
| | | # 收集状态并计算最大长度
|
| | | for obj_class, pool in self._pools.items():
|
| | | # 获取类名
|
| | | class_name = getattr(obj_class, '__name__', str(obj_class))
|
| | | created = pool['created_count']
|
| | | free = len(pool['free_list'])
|
| | | active = len(pool['active_list'])
|
| | | |
| | | statusList.append({
|
| | | 'obj_class': class_name,
|
| | | 'created': created,
|
| | | 'free': free,
|
| | | 'active': active
|
| | | })
|
| | | |
| | | # 计算最大长度
|
| | | max_name_len = max(max_name_len, len(class_name))
|
| | | max_created_len = max(max_created_len, len(str(created)))
|
| | | max_free_len = max(max_free_len, len(str(free)))
|
| | | max_active_len = max(max_active_len, len(str(active)))
|
| | | |
| | | # 添加表头长度
|
| | | max_name_len = max(max_name_len, 8) # "对象池名称"的长度
|
| | | max_created_len = max(max_created_len, 4) # "总数"的长度
|
| | | max_free_len = max(max_free_len, 4) # "空闲"的长度
|
| | | max_active_len = max(max_active_len, 4) # "活跃"的长度
|
| | | |
| | | # 按活跃对象数量排序
|
| | | statusList.sort(key=lambda s: (s['created'], s['active']), reverse=True)
|
| | | |
| | | # 创建格式字符串
|
| | | header_format = "| {:<{name_width}} | {:>{created_width}} | {:>{free_width}} | {:>{active_width}} |"
|
| | | row_format = "| {:<{name_width}} | {:>{created_width}} | {:>{free_width}} | {:>{active_width}} |"
|
| | | |
| | | # 输出表头
|
| | | GameWorld.Log("----- 对象池状态 -----")
|
| | | GameWorld.Log(header_format.format(
|
| | | "对象池名称", "总数", "空闲", "活跃",
|
| | | name_width=max_name_len,
|
| | | created_width=max_created_len,
|
| | | free_width=max_free_len,
|
| | | active_width=max_active_len
|
| | | ))
|
| | | |
| | | # 输出分隔线
|
| | | separator = "+-{}-+-{}-+-{}-+-{}-+".format(
|
| | | "-" * max_name_len,
|
| | | "-" * max_created_len,
|
| | | "-" * max_free_len,
|
| | | "-" * max_active_len
|
| | | )
|
| | | GameWorld.Log(separator)
|
| | | |
| | | # 输出数据行
|
| | | for s in statusList:
|
| | | GameWorld.Log(row_format.format(
|
| | | s['obj_class'], s['created'], s['free'], s['active'],
|
| | | name_width=max_name_len,
|
| | | created_width=max_created_len,
|
| | | free_width=max_free_len,
|
| | | active_width=max_active_len
|
| | | ))
|
| | | |
| | | return
|
| | | |
| | | def GetPoolMgr():
|
| | | """获取指定类创建对象池"""
|
| | | poolMgr = PyGameData.g_objPoolMgr
|
| | | if not poolMgr:
|
| | | poolMgr = RecursiveObjectPoolManager()
|
| | | PyGameData.g_objPoolMgr = poolMgr
|
| | | return poolMgr
|
| | |
|
| | | def OnMinute():
|
| | | """每分钟执行,输出对象池状态"""
|
| | | GetPoolMgr().pool_status()
|
| | | return
|
| | |
|
| | | ## 使用示例
|
| | | #if __name__ == "__main__":
|
| | | # |
| | | # # 定义一个嵌套的Structure类
|
| | | # class SubStructure(ctypes.Structure):
|
| | | # _fields_ = [("z", ctypes.c_int)]
|
| | | # |
| | | # def __init__(self, name):
|
| | | # self.name = name
|
| | | # print "初始化SubStructure: name=%s" % (self.name)
|
| | | # return
|
| | | # |
| | | # def cleanup(self):
|
| | | # """清理方法"""
|
| | | # print "清理SubStructure: name=%s" % (self.name)
|
| | | # self.name = None
|
| | | # |
| | | # # 定义一个继承自Structure的类
|
| | | # class MyStructure(ctypes.Structure):
|
| | | # _fields_ = [("x", ctypes.c_int), ("y", ctypes.c_int)]
|
| | | # |
| | | # def __init__(self, name):
|
| | | # self.name = name
|
| | | # # 嵌套的Structure对象
|
| | | # self.sub = GetPoolMgr().acquire(SubStructure, "%s_sub" % name)
|
| | | # print "初始化MyStructure: name=%s" % (self.name)
|
| | | # return
|
| | | # |
| | | # def cleanup(self):
|
| | | # """清理方法"""
|
| | | # print "清理MyStructure: name=%s" % (self.name)
|
| | | # self.name = None
|
| | | # # 不需要手动释放sub,递归释放会处理
|
| | | # self.sub = None
|
| | | # |
| | | # class ClassE():
|
| | | # |
| | | # def __init__(self, name):
|
| | | # self.name = name
|
| | | # print "初始化对象 ClassE: name=%s" % (self.name)
|
| | | # self.ed1 = GetPoolMgr().acquire(ClassD, "%s_ed_1" % name)
|
| | | # return
|
| | | # |
| | | # class ClassD():
|
| | | # |
| | | # def __init__(self, name):
|
| | | # self.name = name
|
| | | # print "初始化对象 ClassD: name=%s" % (self.name)
|
| | | # return
|
| | | # |
| | | # def cleanup(self):
|
| | | # """清理方法"""
|
| | | # print "清理ClassD: name=%s" % (self.name)
|
| | | # self.name = None
|
| | | # |
| | | # class ClassC():
|
| | | # |
| | | # def __init__(self, name, bb):
|
| | | # self.name = name
|
| | | # print "初始化对象 ClassC: name=%s" % (self.name)
|
| | | # self.bb = bb
|
| | | # self.cd1 = GetPoolMgr().acquire(ClassD, "%s_cd_1" % name)
|
| | | # self.cd2 = GetPoolMgr().acquire(ClassD, "%s_cd_2" % name)
|
| | | # return
|
| | | # |
| | | # class ClassB():
|
| | | # |
| | | # def __init__(self, name):
|
| | | # self.name = name
|
| | | # print "初始化对象 ClassB: name=%s" % (self.name)
|
| | | # bc1 = GetPoolMgr().acquire(ClassC, "%s_c_1" % name, self)
|
| | | # bc2 = GetPoolMgr().acquire(ClassC, "%s_c_2" % name, self)
|
| | | # self.cList = [bc1, bc2]
|
| | | # self.dDict = {1:GetPoolMgr().acquire(ClassD, "%s_d_1" % name), GetPoolMgr().acquire(ClassD, "%s_d_2" % name):2, "bc1":bc1, "bc2":bc2}
|
| | | # return
|
| | | # |
| | | # def do(self, doStr):
|
| | | # print "ClassB.do name=%s, %s" % (self.name, doStr)
|
| | | # return
|
| | | # |
| | | # class ClassA():
|
| | | # |
| | | # def __init__(self, objID, name):
|
| | | # self.objID = objID
|
| | | # self.name = name
|
| | | # self.b = GetPoolMgr().acquire(ClassB, "%s_b" % name)
|
| | | # self.e = ClassE("%s_e" % name)
|
| | | # self.struct = GetPoolMgr().acquire(MyStructure, "%s_struct" % name) # Structure对象
|
| | | # self.dDict = {1:GetPoolMgr().acquire(ClassD, "%s_d_1" % name), GetPoolMgr().acquire(ClassD, "%s_d_2" % name):2}
|
| | | # print "初始化对象 ClassA: objID=%s,name=%s" % (self.objID, self.name)
|
| | | # |
| | | # def do(self, doStr):
|
| | | # print "ClassA.do objID=%s,name=%s, %s" % (self.objID, self.name, doStr)
|
| | | # return
|
| | | # |
| | | # def cleanup(self):
|
| | | # """清理方法"""
|
| | | # print "清理ClassA: objID=%s,name=%s" % (self.objID, self.name)
|
| | | # self.b = None
|
| | | # self.e = None
|
| | | # self.struct = None
|
| | | # self.dDict = None
|
| | | # self.name = None
|
| | | # self.objID = None
|
| | | #
|
| | | # |
| | | # # 创建对象池管理器
|
| | | # poolMgr = GetPoolMgr()
|
| | | # |
| | | # # 为所有类创建对象池,max_size=0 表示无限制
|
| | | # poolMgr.create_pool(ClassA, max_size=0)
|
| | | # poolMgr.create_pool(ClassB, max_size=0)
|
| | | # poolMgr.create_pool(ClassC, max_size=0)
|
| | | # poolMgr.create_pool(ClassD, max_size=0)
|
| | | # poolMgr.create_pool(MyStructure, max_size=0)
|
| | | # poolMgr.create_pool(SubStructure, max_size=0) # 嵌套的Structure类
|
| | | # |
| | | # # 创建测试对象
|
| | | # a1 = poolMgr.acquire(ClassA, 1000, "hanmeimei")
|
| | | # if a1 is None:
|
| | | # GameWorld.ErrLog("Failed to acquire ClassA instance for hanmeimei")
|
| | | # else:
|
| | | # a1.do("hello 1ilei")
|
| | | # |
| | | # a2 = poolMgr.acquire(ClassA, 1001, "lilei")
|
| | | # if a2 is None:
|
| | | # GameWorld.ErrLog("Failed to acquire ClassA instance for lilei")
|
| | | # else:
|
| | | # a2.do("hello hanmeimei")
|
| | | # |
| | | # # 输出状态
|
| | | # print("\n释放前状态")
|
| | | # poolMgr.pool_status()
|
| | | # |
| | | # # 释放对象
|
| | | # if a1:
|
| | | # poolMgr.release(a1)
|
| | | # if a2:
|
| | | # poolMgr.release(a2)
|
| | | # |
| | | # # 输出状态
|
| | | # print("\n释放后状态")
|
| | | # poolMgr.pool_status()
|
| | | # |
| | | # # 再次获取应复用对象
|
| | | # a3 = poolMgr.acquire(ClassA, 1002, "lihua")
|
| | | # if a3 is None:
|
| | | # GameWorld.ErrLog("Failed to acquire ClassA instance for lihua")
|
| | | # else:
|
| | | # a3.do("fuck you")
|
| | | # |
| | | # # 输出状态
|
| | | # print("\n再次获取后状态")
|
| | | # poolMgr.pool_status()
|
| | | # |
| | | # # 清理
|
| | | # if a3:
|
| | | # poolMgr.release(a3)
|
| | | # poolMgr.destroy_pool(ClassA)
|
| | | # poolMgr.destroy_pool(ClassB)
|
| | | # poolMgr.destroy_pool(ClassC)
|
| | | # poolMgr.destroy_pool(ClassD)
|
| | | # poolMgr.destroy_pool(MyStructure)
|
| | | # poolMgr.destroy_pool(SubStructure) |
| | |
| | | # @return 返回值无意义
|
| | | def ClearPyPlayerAction(curPlayer):
|
| | | #清除py自定义状态
|
| | | PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_PyPlayerAction, 0) |
| | | NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_PyPlayerAction, 0) |
| | | return
|
| | |
|
| | | #---------------------------------------------------------------------
|
| | |
| | | #轮回殿
|
| | | PlayerActLunhuidian.AddLunhuidianValue(curPlayer, PlayerActLunhuidian.AwardType_PayMoney, type_Price, price)
|
| | | if type_Price == ShareDefine.TYPE_Price_Xiantao:
|
| | | # 累加未结算战锤 - 经验
|
| | | unXiantaoCntExp = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_UnXiantaoCntExp)
|
| | | NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_UnXiantaoCntExp, unXiantaoCntExp + price)
|
| | | # 累加未结算战锤 - 装备
|
| | | unXiantaoCntEquip = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_UnXiantaoCntEquip)
|
| | | NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_UnXiantaoCntEquip, unXiantaoCntEquip + price)
|
| | | # 累加未结算战锤 - 战利品
|
| | | chapterID = GetMainLevelNowInfo(curPlayer)[0]
|
| | | chapterIpyData = IpyGameDataPY.GetIpyGameData("MainChapter", chapterID)
|
| | | if chapterIpyData:
|
| | | DailyBootyUpperList = chapterIpyData.GetDailyBootyUpperList()
|
| | | for itemID, upperCnt in DailyBootyUpperList:
|
| | | if upperCnt <= 0:
|
| | | continue
|
| | | if curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_BootyDropToday % itemID) >= upperCnt:
|
| | | continue
|
| | | unXiantaoCntBooty = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_UnXiantaoCntBooty % itemID)
|
| | | NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_UnXiantaoCntBooty % itemID, unXiantaoCntBooty + price)
|
| | | |
| | | PlayerPrestigeSys.AddRealmTaskValue(curPlayer, PlayerPrestigeSys.RealmTaskType_UseXiantao, price)
|
| | | unitPrice = price if quantity == 1 else int(math.ceil(price * 1.0 / quantity)) # 单价
|
| | | #reason_name = "Unknown" if not costType else costType
|
| | |
| | |
|
| | | # 杀怪
|
| | | if expViewType == ShareDefine.Def_ViewExpType_KillNPC:
|
| | | exp_rate = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_TotalExpRate)
|
| | | #exp_rate = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_TotalExpRate)
|
| | | exp_rate = 10000
|
| | | elif expViewType in [ShareDefine.Def_ViewExpType_GameEvent, ShareDefine.Def_ViewExpType_Sit]:
|
| | | exp_rate = curPlayer.GetGameEventExpRate()
|
| | | #exp_rate += GetFamilySitExpPer(curPlayer)
|
| | |
| | | insidePerAttrDict = {}
|
| | | customAttrDict = {}
|
| | | return attrList, insidePerAttrDict, customAttrDict
|
| | |
|
| | | def GetLordAttr(curPlayer):
|
| | | ## 获取主公属性汇总
|
| | | lordAttrDict = {"Atk":curPlayer.GetMaxAtk(), "Def":curPlayer.GetDef(), "MaxHP":GameObj.GetMaxHP(curPlayer), |
| | | "Hit":curPlayer.GetHit(), "Miss":curPlayer.GetMiss()}
|
| | | return lordAttrDict
|
| | |
|
| | | #-------------------------------------------------------------------------------
|
| | | ## 设置玩家字典值, 存库
|
| | |
| | | import time
|
| | |
|
| | | class LineupHero():
|
| | | ## 阵容战斗武将,注意:同一个武将在不同阵容中可能属性不一样
|
| | | ## 阵容武将,注意:同一个武将在不同阵容中可能属性不一样
|
| | |
|
| | | def __init__(self):
|
| | | self.Clear()
|
| | |
| | | def Clear(self):
|
| | | self.itemIndex = 0
|
| | | self.heroID = 0
|
| | | self.skinID = 0
|
| | | self.posNum = 0
|
| | | self.heroBatAttrDict = {} # 武将的最终战斗属性字典, {attrID:value, ...}
|
| | | self.heroSkillIDList = [] # 武将拥有的技能ID列表 [skillID, ...]
|
| | |
| | | return
|
| | |
|
| | | def OnClear(self):
|
| | | self.mainFight.clear()
|
| | | self.mainFight.turnFight.clearFight()
|
| | | return
|
| | |
|
| | | def SetPlayer(self, curPlayer):
|
| | |
| | | star = heroItem.GetUserAttr(ShareDefine.Def_IudetHeroStar)
|
| | | breakLV = heroItem.GetUserAttr(ShareDefine.Def_IudetHeroBreakLV)
|
| | | awakeLV = heroItem.GetUserAttr(ShareDefine.Def_IudetHeroAwakeLV)
|
| | | skinIndex = heroItem.GetUserAttr(ShareDefine.Def_IudetHeroSkin)
|
| | |
|
| | | skinID = 0
|
| | | skinIDList = heroIpyData.GetSkinIDList()
|
| | | if skinIndex < 0 or skinIndex >= len(skinIDList):
|
| | | skinID = skinIDList[skinIndex]
|
| | | elif skinIDList:
|
| | | skinID = skinIDList[0]
|
| | | |
| | | InitAddPer += qualityIpyData.GetInitAddPer()
|
| | | LVAddPer += qualityIpyData.GetLVAddPer() * heroLV
|
| | | BreakLVAddPer += qualityIpyData.GetBreakLVAddPer() * breakLV
|
| | |
| | | lineupHero.itemIndex = itemIndex
|
| | | lineupHero.posNum = posNum
|
| | | lineupHero.heroID = heroID
|
| | | lineupHero.skinID = skinID
|
| | | lineupHero.heroBatAttrDict = {}
|
| | | lineupHero.heroSkillIDList = []
|
| | | lineupHero.fightPower = 0
|
| | |
| | | GameWorld.DebugLog(" fightPower=%s,heroSkillIDList=%s" % (fightPower, lineupHero.heroSkillIDList))
|
| | | skillTypeIDDict = {}
|
| | | for skillID in lineupHero.heroSkillIDList:
|
| | | skillData = GameWorld.GetGameData().GetSkillBySkillID(skillID)
|
| | | skillData = IpyGameDataPY.GetIpyGameData("Skill", skillID)
|
| | | if not skillData:
|
| | | continue
|
| | | skillTypeID = skillData.GetSkillTypeID()
|
| | |
| | | g_serverClosing = 0 # 是否关服中 0-非关服中;1-关服中;2-关服结束
|
| | | g_closeSaveDataOK = False # 关服数据入库是否成功
|
| | |
|
| | | g_objPoolMgr = None # 对象池管理器
|
| | | g_batObjMgr = None # 战斗对象管理
|
| | |
|
| | | g_pyGameDataManager = None
|
| | |
|
| | | g_dbPlayerIDMap = {} # 本服DBPlayer玩家表ID映射关系 {playerID:accID, ...}
|
| | |
| | | elif curObjType == IPY_GameWorld.gotNPC:
|
| | | AttackCommon.NPCAddObjInHurtList(attackerOwner, curObj, curObjHP_BeforeAttack, lostValue)
|
| | |
|
| | | TurnAttack.AddTurnObjHurtValue(buffOwner, curObj, hurtType, lostValue, lostHP, curSkill)
|
| | | #TurnAttack.AddTurnObjHurtValue(buffOwner, curObj, lostValue, lostHP, curSkill)
|
| | |
|
| | | #统一调用攻击结束动作
|
| | | if isDoAttackResult:
|
| | | BaseAttack.DoLogic_AttackResult(buffOwner, curObj, None, tick)
|
| | |
|
| | | TurnAttack.OnTurnfightAttackResult(buffOwner, curObj, curSkill)
|
| | | #TurnAttack.OnTurnfightAttackResult(buffOwner, curObj, curSkill)
|
| | | return lostHP
|
| | |
|
| | | ## 检查增加淬毒buff
|
| | |
| | |
|
| | | def isAngerSkill(curSkill):
|
| | | ## 是否怒气技能
|
| | | return curSkill and curSkill.GetXP() > 0
|
| | | return curSkill and curSkill.GetFuncType() == ChConfig.Def_SkillFuncType_AngerSkill
|
| | |
|
| | | def isTurnNormalSkill(curSkill):
|
| | | ## 是否回合普攻技能,区别与无技能的普通A一下,该普攻同样可以有各种技能效果,只是他属于普攻
|
| | | return curSkill and curSkill.GetFuncType() == ChConfig.Def_SkillFuncType_TurnNormaSkill
|
| | |
|
| | | def isAtkbackSkill(curSkill):
|
| | | ## 是否反击技能
|
| | | return curSkill and curSkill.GetFuncType() == ChConfig.Def_SkillFuncType_AtkbackSkill
|
| | |
|
| | | ## 检查技能是否为被动技能, 用于控制不可释放技能
|
| | | def isPassiveSkill(curSkill):
|
| | | return curSkill.GetSkillType() in [ChConfig.Def_SkillType_Passive,
|
| | |
| | |
|
| | | #调用攻击惩罚逻辑
|
| | | BaseAttack.DoLogic_AttackResult(attacker, defender, None, tick)
|
| | | TurnAttack.OnTurnfightAttackResult(attacker, defender, curSkill)
|
| | | #TurnAttack.OnTurnfightAttackResult(attacker, defender, curSkill)
|
| | |
|
| | | return
|
| | | #---------------------------------------------------------------------
|
New file |
| | |
| | | #!/usr/bin/python
|
| | | # -*- coding: GBK -*-
|
| | | #-------------------------------------------------------------------------------
|
| | | #
|
| | | ##@package Skill.TurnBuff
|
| | | #
|
| | | # @todo:回合战斗buff
|
| | | # @author hxp
|
| | | # @date 2025-08-06
|
| | | # @version 1.0
|
| | | #
|
| | | # 详细描述: 回合战斗buff
|
| | | #
|
| | | #-------------------------------------------------------------------------------
|
| | | #"""Version = 2025-08-06 18:30"""
|
| | | #-------------------------------------------------------------------------------
|
| | |
|
| | | import ChConfig
|
| | | import GameWorld
|
| | | import ChPyNetSendPack
|
| | | import ObjPool
|
| | |
|
| | | def OnAddBuff(turnFight, batObj, curSkill, buffOwner=None):
|
| | | skillID = curSkill.GetSkillID()
|
| | | enhanceBySkill = curSkill.GetEnhanceBySkill()
|
| | | relatedSkillID = enhanceBySkill.GetSkillID() if enhanceBySkill else 0
|
| | | curID = batObj.GetID()
|
| | | ownerID = buffOwner.GetID() if buffOwner else curID
|
| | | GameWorld.DebugLog("OnAddBuff: curID=%s,skillID=%s,ownerID=%s,relatedSkillID=%s" % (curID, skillID, ownerID, relatedSkillID))
|
| | | #检查是否几率触发
|
| | | if not enhanceBySkill:
|
| | | rate = curSkill.GetHappenRate()
|
| | | if rate and rate != ChConfig.Def_MaxRateValue and not GameWorld.CanHappen(rate, ChConfig.Def_MaxRateValue):
|
| | | GameWorld.DebugLog(" 概率不触发buff!")
|
| | | return
|
| | | |
| | | skillTypeID = curSkill.GetSkillTypeID()
|
| | | # 先简单做下能加上即可
|
| | | buffMgr = batObj.GetBuffManager()
|
| | | buffIDList = buffMgr.FindBuffIDBySkillTypeID(skillTypeID)
|
| | | if buffIDList:
|
| | | GameWorld.DebugLog(" 已经存在该buff: skillTypeID=%s,buffIDList=%s" % (skillTypeID, buffIDList))
|
| | | return True
|
| | | |
| | | buff = buffMgr.AddBuff(skillID)
|
| | | if not buff:
|
| | | GameWorld.DebugLog(" 添加buff失败! skillID=%s" % skillID)
|
| | | return False
|
| | | GameWorld.DebugLog(" AddBuffOK. buffID=%s" % buff.GetBuffID())
|
| | | buff.SetOwnerID(ownerID)
|
| | | buff.SetRemainTime(curSkill.GetLastTime())
|
| | | #buff.SetLayer()
|
| | | SyncBuffRefresh(turnFight, batObj, buff, relatedSkillID)
|
| | | return True
|
| | |
|
| | | def SyncBuffRefresh(turnFight, curBatObj, curBuff, relatedSkillID=0):
|
| | | clientPack = ObjPool.GetPoolMgr().acquire(ChPyNetSendPack.tagSCBuffRefresh)
|
| | | clientPack.ObjID = curBatObj.GetID()
|
| | | clientPack.BuffID = curBuff.GetBuffID()
|
| | | clientPack.SkillID = curBuff.GetSkillID()
|
| | | clientPack.RelatedSkillID = relatedSkillID
|
| | | clientPack.LastTime = curBuff.GetRemainTime()
|
| | | clientPack.Layer = curBuff.GetLayer()
|
| | | clientPack.OwnerID = curBuff.GetOwnerID()
|
| | | turnFight.addBatPack(clientPack)
|
| | | return
|
| | |
|
| | | def SyncBuffDel(turnFight, curBatObj, buffID, relatedSkillID=0):
|
| | | clientPack = ObjPool.GetPoolMgr().acquire(ChPyNetSendPack.tagSCBuffDel)
|
| | | clientPack.ObjID = curBatObj.GetID()
|
| | | clientPack.BuffID = buffID
|
| | | clientPack.RelatedSkillID = relatedSkillID
|
| | | turnFight.addBatPack(clientPack)
|
| | | return
|
New file |
| | |
| | | #!/usr/bin/python
|
| | | # -*- coding: GBK -*-
|
| | | #-------------------------------------------------------------------------------
|
| | | #
|
| | | ##@package Skill.TurnSkill
|
| | | #
|
| | | # @todo:回合战斗技能
|
| | | # @author hxp
|
| | | # @date 2025-08-06
|
| | | # @version 1.0
|
| | | #
|
| | | # 详细描述: 回合战斗技能
|
| | | #
|
| | | #-------------------------------------------------------------------------------
|
| | | #"""Version = 2025-08-06 18:30"""
|
| | | #-------------------------------------------------------------------------------
|
| | |
|
| | | import ChConfig
|
| | | import GameWorld
|
| | | import BattleObj
|
| | | import SkillCommon
|
| | | import IpyGameDataPY
|
| | | import IPY_GameWorld
|
| | | import ChPyNetSendPack
|
| | | import PlayerControl
|
| | | import ShareDefine
|
| | | import TurnAttack
|
| | | import TurnBuff
|
| | | import ObjPool
|
| | | import FBLogic
|
| | |
|
| | | import random
|
| | |
|
| | | def GetPMType(batObj, useSkill):
|
| | | ## 获取物法伤害类型
|
| | | # GetHurtType 个位数用法改成 pvp pve标识,十位数-物攻法攻 IPY_GameWorld.ghtPhy = 1
|
| | | #---技能攻击, 读表获取攻击类型---
|
| | | ght = useSkill.GetHurtType() % 10
|
| | | if ght == IPY_GameWorld.ghtMag: # 做配置兼容用,优先验证法伤,否则默认物伤
|
| | | return IPY_GameWorld.ghtMag
|
| | | return IPY_GameWorld.ghtPhy
|
| | |
|
| | | def IsIgnoreDef(useSkill):
|
| | | ## 是否无视防御
|
| | | return useSkill.GetHurtType() / 10 == 1 # 2为真伤,待扩展
|
| | |
|
| | | def OnUseSkill(turnFight, curBatObj, useSkill, tagObjList=None, batType=ChConfig.TurnBattleType_Normal, enhanceBySkill=None):
|
| | | '''使用技能通用入口
|
| | | @param useSkill: 使用的技能,注意并不一定是身上的技能,可能只是 SkillData 表数据
|
| | | @param enhanceBySkill: 由哪个主技能额外触发的
|
| | | @return: 是否成功
|
| | | '''
|
| | | if not useSkill:
|
| | | return
|
| | | |
| | | skillID = useSkill.GetSkillID()
|
| | | if not skillID:
|
| | | return
|
| | | |
| | | #没有指定目标,则按技能自身的目标逻辑
|
| | | if not tagObjList:
|
| | | tagAim = useSkill.GetTagAim()
|
| | | tagFriendly = useSkill.GetTagFriendly()
|
| | | tagAffect = useSkill.GetTagAffect()
|
| | | tagCount = useSkill.GetTagCount()
|
| | | tagObjList = GetSkillTags(turnFight, curBatObj, tagAim, tagFriendly, tagAffect, tagCount)
|
| | | |
| | | enhanceBySkillID = enhanceBySkill.GetSkillID() if enhanceBySkill else 0
|
| | | GameWorld.DebugLog("使用技能: curID=%s,skillID=%s,tagCnt=%s,batType=%s,enhanceBySkill=%s" |
| | | % (curBatObj.GetID(), skillID, len(tagObjList), batType, enhanceBySkillID))
|
| | | if not tagObjList:
|
| | | # 可扩展其他目标选择,如复活技能没有死亡单位时则使用另外的效果
|
| | | return
|
| | | |
| | | # 以下为技能可以使用的处理,之后的逻辑默认技能使用成功
|
| | | |
| | | poolMgr = ObjPool.GetPoolMgr()
|
| | | usePoolSkill = False
|
| | | if isinstance(useSkill, IpyGameDataPY.IPY_Skill):
|
| | | usePoolSkill = True
|
| | | # 统一使用 BattleObj.PySkill
|
| | | useSkill = poolMgr.acquire(BattleObj.PySkill, useSkill)
|
| | | |
| | | useSkill.SetTagObjList(tagObjList)
|
| | | useSkill.SetBatType(batType)
|
| | | useSkill.SetEnhanceBySkill(enhanceBySkill)
|
| | | useSkill.ClearHurtObj()
|
| | | |
| | | curBatObj.ClearSkillTempAttr()
|
| | | for tagObj in tagObjList:
|
| | | tagObj.ClearSkillTempAttr()
|
| | | |
| | | objID = curBatObj.GetID()
|
| | | useTag = ""
|
| | | if not enhanceBySkill:
|
| | | # 因为可能触发连击,所以标记需带上累计使用技能次数,确保唯一
|
| | | useTag = "Skill_%s_%s_%s" % (objID, skillID, curBatObj.GetSkillUseCnt(skillID) + 1)
|
| | | clientPack = poolMgr.acquire(ChPyNetSendPack.tagSCTurnFightTag)
|
| | | clientPack.Tag = useTag
|
| | | clientPack.Len = len(clientPack.Tag)
|
| | | clientPack.Sign = 0
|
| | | turnFight.addBatPack(clientPack)
|
| | | |
| | | #这个技能是Buff
|
| | | if SkillCommon.IsBuff(useSkill):
|
| | | __doAddBuff(turnFight, curBatObj, useSkill)
|
| | | else:
|
| | | __doUseSkill(turnFight, curBatObj, useSkill)
|
| | | |
| | | if useTag:
|
| | | clientPack = poolMgr.acquire(ChPyNetSendPack.tagSCTurnFightTag)
|
| | | clientPack.Tag = useTag
|
| | | clientPack.Len = len(clientPack.Tag)
|
| | | clientPack.Sign = 1
|
| | | turnFight.addBatPack(clientPack)
|
| | | |
| | | # 最后重置、清空回收对象池
|
| | | useSkill.SetTagObjList([])
|
| | | useSkill.SetEnhanceBySkill(None) # 需重置,防止主技能被误回收
|
| | | useSkill.ClearHurtObj()
|
| | | if usePoolSkill:
|
| | | poolMgr.release(useSkill)
|
| | | return True
|
| | |
|
| | | def GetSkillTags(turnFight, curBatObj, tagAim, tagFriendly, tagAffect, tagCount):
|
| | | ## 获取技能目标 |
| | | curFaction = curBatObj.GetFaction()
|
| | | |
| | | # 自己,直接返回
|
| | | if tagAim == ChConfig.SkillTagAim_Self:
|
| | | return [curBatObj]
|
| | | |
| | | if tagFriendly:
|
| | | tagFaction = curFaction
|
| | | else:
|
| | | tagFaction = ChConfig.Def_FactionB if curFaction == ChConfig.Def_FactionA else ChConfig.Def_FactionA
|
| | | |
| | | batObjMgr = BattleObj.GetBatObjMgr()
|
| | | lineupNum = curBatObj.GetLineupNum()
|
| | | posNum = curBatObj.GetPosNum()
|
| | | |
| | | batFaction = turnFight.getBatFaction(tagFaction)
|
| | | if tagFaction == curFaction:
|
| | | lineupNumList = [lineupNum] # 友方暂时仅限制自己阵容
|
| | | else:
|
| | | lineupNumList = [lineupNum] # 敌方优先对位阵容,再其他阵容
|
| | | for tagNum in batFaction.lineupDict.keys():
|
| | | if tagNum not in lineupNumList:
|
| | | lineupNumList.append(tagNum)
|
| | | |
| | | aimObjList = [] # 先筛选出范围目标
|
| | | for num in lineupNumList:
|
| | | batLineup = batFaction.getBatlineup(num)
|
| | | |
| | | # 对位
|
| | | if tagAim == ChConfig.SkillTagAim_Relative:
|
| | | posNumList = [posNum] # 优先对位位置,再其他位置按顺序遍历
|
| | | pNumList = batLineup.posObjIDDict.keys()
|
| | | pNumList.sort()
|
| | | for pNum in pNumList:
|
| | | if pNum > 0 and pNum not in posNumList:
|
| | | posNumList.append(pNum)
|
| | | for pNum in posNumList:
|
| | | if pNum not in batLineup.posObjIDDict:
|
| | | continue
|
| | | tagObjID = batLineup.posObjIDDict[pNum]
|
| | | tagBatObj = batObjMgr.getBatObj(tagObjID)
|
| | | if not __skillTagFilter(tagBatObj, tagAffect):
|
| | | continue
|
| | | aimObjList.append(tagBatObj) # 对位的默认只选1个
|
| | | break
|
| | | |
| | | # 前排
|
| | | elif tagAim == ChConfig.SkillTagAim_FrontRow:
|
| | | # 优先前排,如果没有则后排亦是前排
|
| | | for pNumList in [[1, 2, 3], [4, 5, 6]]:
|
| | | hasObj = False
|
| | | for pNum in pNumList:
|
| | | if pNum not in batLineup.posObjIDDict:
|
| | | continue
|
| | | tagObjID = batLineup.posObjIDDict[pNum]
|
| | | tagBatObj = batObjMgr.getBatObj(tagObjID)
|
| | | if not __skillTagFilter(tagBatObj, tagAffect):
|
| | | continue
|
| | | hasObj = True
|
| | | aimObjList.append(tagBatObj)
|
| | | if hasObj:
|
| | | break
|
| | | |
| | | # 后排
|
| | | elif tagAim == ChConfig.SkillTagAim_BackRow:
|
| | | # 优先后排,如果没有则前排亦是后排
|
| | | for pNumList in [[4, 5, 6], [1, 2, 3]]:
|
| | | hasObj = False
|
| | | for pNum in pNumList:
|
| | | if pNum not in batLineup.posObjIDDict:
|
| | | continue
|
| | | tagObjID = batLineup.posObjIDDict[pNum]
|
| | | tagBatObj = batObjMgr.getBatObj(tagObjID)
|
| | | if not __skillTagFilter(tagBatObj, tagAffect):
|
| | | continue
|
| | | hasObj = True
|
| | | aimObjList.append(tagBatObj)
|
| | | if hasObj:
|
| | | break
|
| | | |
| | | # 竖排/纵排
|
| | | elif tagAim == ChConfig.SkillTagAim_Vertical:
|
| | | verticalNumList = [[1, 4], [2, 5], [3, 6]]
|
| | | for pNumList in verticalNumList:
|
| | | # 优先对位排
|
| | | if posNum in pNumList:
|
| | | verticalNumList.remove(pNumList)
|
| | | verticalNumList.insert(0, pNumList)
|
| | | break
|
| | | for pNumList in verticalNumList:
|
| | | hasObj = False
|
| | | for pNum in pNumList:
|
| | | if pNum not in batLineup.posObjIDDict:
|
| | | continue
|
| | | tagObjID = batLineup.posObjIDDict[pNum]
|
| | | tagBatObj = batObjMgr.getBatObj(tagObjID)
|
| | | if not __skillTagFilter(tagBatObj, tagAffect):
|
| | | continue
|
| | | hasObj = True
|
| | | aimObjList.append(tagBatObj)
|
| | | if hasObj:
|
| | | break
|
| | | |
| | | # 其他,默认全部
|
| | | else:
|
| | | pNumList = batLineup.posObjIDDict.keys()
|
| | | for pNum in pNumList:
|
| | | if pNum <= 0:
|
| | | continue
|
| | | tagObjID = batLineup.posObjIDDict[pNum]
|
| | | tagBatObj = batObjMgr.getBatObj(tagObjID)
|
| | | if not __skillTagFilter(tagBatObj, tagAffect):
|
| | | continue
|
| | | aimObjList.append(tagBatObj)
|
| | | |
| | | # 目标细分
|
| | | # 血量最低
|
| | | if tagAffect == ChConfig.SkillTagAffect_HPLowest:
|
| | | aimObjList.sort(key=lambda o:(o.GetHP()), reverse=False)
|
| | | aimObjList = aimObjList[:tagCount]
|
| | | |
| | | # 血量最高
|
| | | elif tagAffect == ChConfig.SkillTagAffect_HPHighest:
|
| | | aimObjList.sort(key=lambda o:(o.GetHP()), reverse=True)
|
| | | aimObjList = aimObjList[:tagCount]
|
| | | |
| | | else:
|
| | | # 范围目标超过个数,则随机取
|
| | | if tagCount and len(aimObjList) > tagCount:
|
| | | random.shuffle(aimObjList)
|
| | | aimObjList = aimObjList[:tagCount]
|
| | | |
| | | return aimObjList
|
| | |
|
| | | def __skillTagFilter(tagBatObj, tagAffect):
|
| | | ## 技能目标过滤器
|
| | | # @return: 是否允许添加该单位
|
| | | if not tagBatObj:
|
| | | return False
|
| | | if tagAffect != ChConfig.SkillTagAffect_Death and tagBatObj.GetHP() <= 0:
|
| | | return False
|
| | | if tagAffect == ChConfig.SkillTagAffect_Death and tagBatObj.GetHP() > 0:
|
| | | return False
|
| | | if not tagBatObj.GetCanAttack():
|
| | | return False
|
| | | return True
|
| | |
|
| | | def __doAddBuff(turnFight, curBatObj, useSkill):
|
| | | #执行添加buff
|
| | | |
| | | for tagBatObj in useSkill.GetTagObjList():
|
| | | TurnBuff.OnAddBuff(turnFight, tagBatObj, useSkill, buffOwner=curBatObj)
|
| | | |
| | | DoAttackResult(turnFight, curBatObj, useSkill)
|
| | | return
|
| | |
|
| | | def __doUseSkill(turnFight, curBatObj, useSkill):
|
| | | |
| | | atkType = useSkill.GetAtkType()
|
| | | GameWorld.DebugLog("__doUseSkill: curID=%s,skillID=%s,atkType=%s" % (curBatObj.GetID(), useSkill.GetSkillID(), atkType))
|
| | | # 通用攻击
|
| | | if atkType == 1:
|
| | | SkillModule_1(turnFight, curBatObj, useSkill)
|
| | | return
|
| | | |
| | | # 治疗
|
| | | if atkType == 2:
|
| | | SkillModule_2(turnFight, curBatObj, useSkill)
|
| | | return
|
| | | |
| | | # 复活
|
| | | if atkType == 3:
|
| | | return
|
| | | |
| | | # 多次攻击(锁目标多次伤害,非前端的多段飘血)
|
| | | if atkType == 4:
|
| | | return
|
| | | |
| | | # 弹射(多次攻击,切换目标)
|
| | | if atkType == 5:
|
| | | return
|
| | | |
| | | # 6 怒气增减偷
|
| | | if atkType == 6:
|
| | | SkillModule_6(turnFight, curBatObj, useSkill)
|
| | | return
|
| | | |
| | | return
|
| | |
|
| | | def SkillModule_1(turnFight, curBatObj, useSkill):
|
| | | ## 通用攻击,单攻、群攻
|
| | | |
| | | #执行攻击结果
|
| | | for tagBatObj in useSkill.GetTagObjList():
|
| | | __doSkillHurtHP(curBatObj, tagBatObj, useSkill)
|
| | | |
| | | DoAttackResult(turnFight, curBatObj, useSkill)
|
| | | return
|
| | |
|
| | | def SkillModule_2(turnFight, curBatObj, useSkill):
|
| | | ## 治疗
|
| | | |
| | | skillID = useSkill.GetSkillID()
|
| | | for tagBatObj in useSkill.GetTagObjList():
|
| | | cureHP = CalcCureHP(curBatObj, tagBatObj, useSkill, largeNum=True)
|
| | | if cureHP <= 0:
|
| | | continue
|
| | | |
| | | dHP = tagBatObj.GetHP()
|
| | | dMapHP = tagBatObj.GetMaxHP()
|
| | | |
| | | remainHP = min(dHP + cureHP, dMapHP)
|
| | | realCureHP = max(remainHP - dHP, 0)
|
| | | tagBatObj.SetHP(remainHP)
|
| | | |
| | | dID = tagBatObj.GetID()
|
| | | hurtObj = useSkill.AddHurtObj(dID)
|
| | | hurtObj.AddHurtType(ChConfig.HurtTYpe_Recovery)
|
| | | hurtObj.SetHurtHP(cureHP)
|
| | | hurtObj.SetLostHP(realCureHP)
|
| | | hurtObj.SetCurHP(tagBatObj.GetHP())
|
| | | GameWorld.DebugLog(" 治疗: dID=%s,cureHP=%s,realCureHP=%s,%s/%s" % (dID, cureHP, realCureHP, tagBatObj.GetHP(), dMapHP))
|
| | | |
| | | TurnAttack.AddTurnObjCureHP(tagBatObj, curBatObj, cureHP, realCureHP, skillID)
|
| | | |
| | | DoAttackResult(turnFight, curBatObj, useSkill)
|
| | | return
|
| | |
|
| | | def SkillModule_6(turnFight, curBatObj, useSkill):
|
| | | ## 怒气增减偷
|
| | | |
| | | curID = curBatObj.GetID()
|
| | | skillID = useSkill.GetSkillID()
|
| | | enhanceBySkill = useSkill.GetEnhanceBySkill()
|
| | | relatedSkillID = enhanceBySkill.GetSkillID() if enhanceBySkill else 0
|
| | | |
| | | effIDNum = useSkill.FindEffectID(ChConfig.Def_Skill_Effect_Anger)
|
| | | angerPer = useSkill.GetEffectValue(effIDNum, 0) # 最大值的百分比,万分率
|
| | | angerValue = useSkill.GetEffectValue(effIDNum, 1) # 固定值
|
| | | calcType = useSkill.GetEffectValue(effIDNum, 2) # 计算方式(1增 2减 3偷)
|
| | | xpMax = IpyGameDataPY.GetFuncCfg("AngerXP", 2)
|
| | | calcValue = int(xpMax * angerPer / 10000.0 + angerValue)
|
| | | attrID = ChConfig.AttrID_XP
|
| | | |
| | | GameWorld.DebugLog("怒气增减偷: curID=%s,calcValue=%s,skillID=%s,angerPer=%s,angerValue=%s,calcType=%s,relatedSkillID=%s" |
| | | % (curID, calcValue, skillID, angerPer, angerValue, calcType, relatedSkillID))
|
| | | curStealTotal = 0
|
| | | for tagBatObj in useSkill.GetTagObjList():
|
| | | |
| | | tagID = tagBatObj.GetID()
|
| | | # 减
|
| | | if calcType == 2:
|
| | | diffType = 0
|
| | | tagXP = tagBatObj.GetXP()
|
| | | diffValue = min(tagXP, calcValue) # 取较小值,不足时剩多少减多少
|
| | | updValue = tagXP - diffValue
|
| | | tagBatObj.SetXP(updValue, False)
|
| | | GameWorld.DebugLog(" 减怒气: tagID=%s,diffValue=%s,tagXP=%s,updXP=%s" % (tagID, diffValue, tagXP, updValue))
|
| | | Sync_PropertyRefreshView(turnFight, tagBatObj, attrID, updValue, diffValue, diffType, skillID, relatedSkillID)
|
| | | |
| | | # ͵
|
| | | elif calcType == 3:
|
| | | diffType = 0
|
| | | tagXP = tagBatObj.GetXP()
|
| | | diffValue = min(tagXP, calcValue) # 取较小值,不足时剩多少减多少
|
| | | updValue = tagXP - diffValue
|
| | | tagBatObj.SetXP(updValue, False)
|
| | | GameWorld.DebugLog(" 偷怒气: tagID=%s,diffValue=%s,tagXP=%s,updXP=%s" % (tagID, diffValue, tagXP, updValue))
|
| | | Sync_PropertyRefreshView(turnFight, tagBatObj, attrID, updValue, diffValue, diffType, skillID, relatedSkillID)
|
| | | |
| | | curStealTotal += diffValue
|
| | | |
| | | # 其他默认加
|
| | | else:
|
| | | diffType = 1
|
| | | tagXP = tagBatObj.GetXP()
|
| | | diffValue = calcValue
|
| | | updValue = tagXP + diffValue
|
| | | tagBatObj.SetXP(updValue, False)
|
| | | GameWorld.DebugLog(" 加怒气: tagID=%s,diffValue=%s,tagXP=%s,updXP=%s" % (tagID, diffValue, tagXP, updValue))
|
| | | Sync_PropertyRefreshView(turnFight, tagBatObj, attrID, updValue, diffValue, diffType, skillID, relatedSkillID)
|
| | | |
| | | if curStealTotal > 0:
|
| | | diffType = 1
|
| | | curXP = curBatObj.GetXP()
|
| | | diffValue = curStealTotal
|
| | | updValue = curXP + diffValue
|
| | | curBatObj.SetXP(updValue, False)
|
| | | GameWorld.DebugLog(" 偷总怒气: curID=%s,curStealTotal=%s,curXP=%s,updXP=%s" % (curID, curStealTotal, curXP, updValue))
|
| | | Sync_PropertyRefreshView(turnFight, curBatObj, attrID, updValue, diffValue, diffType, skillID, relatedSkillID)
|
| | | |
| | | DoAttackResult(turnFight, curBatObj, useSkill)
|
| | | return
|
| | |
|
| | | def DoAttackResult(turnFight, curBatObj, useSkill):
|
| | | '''执行攻击结果,技能、buff通用
|
| | | @param curBatObj: 施法方或buff归属方
|
| | | '''
|
| | | |
| | | if curBatObj:
|
| | | # 反弹、吸血 的原因,需要统一处理后结算,可能导致HP为负值,修正为0
|
| | | if curBatObj.GetHP() < 0:
|
| | | curBatObj.SetHP(0)
|
| | | |
| | | skillID = useSkill.GetSkillID()
|
| | | curBatObj.AddSkillUseCnt(skillID)
|
| | | |
| | | # 需先通知伤血 - 前端按顺序优先表现主技能内容,
|
| | | enhanceBySkill = useSkill.GetEnhanceBySkill()
|
| | | if not enhanceBySkill:
|
| | | Sync_UseSkill(turnFight, curBatObj, useSkill)
|
| | | __doCostZhanchui(turnFight, curBatObj, useSkill)
|
| | | __doSkillUserAnger(turnFight, curBatObj, useSkill)
|
| | | |
| | | # 统计死亡
|
| | | killObjIDList = [] # 击杀的目标ID列表
|
| | | for tagObj in useSkill.GetTagObjList():
|
| | | tagID = tagObj.GetID()
|
| | | hurtObj = useSkill.GetHurtObj(tagID)
|
| | | if hurtObj and not hurtObj.HaveHurtType(ChConfig.HurtTYpe_Recovery):
|
| | | __doSkillHurtAnger(tagObj, hurtObj.GetLostHP(), useSkill)
|
| | | if tagObj.GetHP() <= 0:
|
| | | killObjIDList.append(tagID)
|
| | | TurnAttack.SetObjKilled(turnFight, tagObj, curBatObj, useSkill)
|
| | | if curBatObj.GetHP() <= 0:
|
| | | TurnAttack.SetObjKilled(turnFight, curBatObj)
|
| | | |
| | | # 结算副本相关的攻击结果,仅主动发起玩家阵容武将触发
|
| | | curPlayer = turnFight.curPlayer
|
| | | if curPlayer and curBatObj.GetOwnerID() == curPlayer.GetPlayerID():
|
| | | FBLogic.OnPlayerLineupAttackResult(curPlayer, curBatObj, killObjIDList, useSkill, turnFight.mapID, turnFight.funcLineID)
|
| | | |
| | | # 额外触发技能
|
| | | __doUseEnhanceSkill(turnFight, curBatObj, useSkill)
|
| | | |
| | | # 循环触发被动,待扩展
|
| | | |
| | | # 最后处理反击 或 连击
|
| | | |
| | | return
|
| | |
|
| | | def __doCostZhanchui(turnFight, curBatObj, useSkill):
|
| | |
|
| | | turnFight.mapID
|
| | | if turnFight.mapID != ChConfig.Def_FBMapID_Main:
|
| | | ## 仅主线战斗需要
|
| | | return
|
| | | |
| | | curPlayer = turnFight.curPlayer
|
| | | if not curPlayer:
|
| | | return
|
| | | # 仅主动发起玩家阵容武将释放技能需要消耗
|
| | | if curBatObj.GetOwnerID() != curPlayer.GetPlayerID():
|
| | | return
|
| | | |
| | | costZhanchui = 0
|
| | | batType = useSkill.GetBatType()
|
| | | if SkillCommon.isAngerSkill(useSkill):
|
| | | costZhanchui = IpyGameDataPY.GetFuncCfg("ZhanchuiCost", 2)
|
| | | elif batType == ChConfig.TurnBattleType_Combo:
|
| | | costZhanchui = IpyGameDataPY.GetFuncCfg("ZhanchuiCost", 3)
|
| | | elif batType == ChConfig.TurnBattleType_AtkBack:
|
| | | costZhanchui = IpyGameDataPY.GetFuncCfg("ZhanchuiCost", 4)
|
| | | elif SkillCommon.isTurnNormalSkill(useSkill):
|
| | | costZhanchui = IpyGameDataPY.GetFuncCfg("ZhanchuiCost", 1)
|
| | | |
| | | if costZhanchui <= 0:
|
| | | return
|
| | | |
| | | fightPoint = max(curPlayer.GetFightPoint(), 1) # 主线战斗消耗倍值,默认1
|
| | | costZhanchuiTotal = costZhanchui * fightPoint
|
| | | if not PlayerControl.PayMoney(curPlayer, ShareDefine.TYPE_Price_Xiantao, costZhanchuiTotal, isNotify=False):
|
| | | # 不足时,有多少扣多少
|
| | | nowMoney = PlayerControl.GetMoney(curPlayer, ShareDefine.TYPE_Price_Xiantao)
|
| | | PlayerControl.PayMoney(curPlayer, ShareDefine.TYPE_Price_Xiantao, min(nowMoney, costZhanchuiTotal), isNotify=False)
|
| | | |
| | | return
|
| | |
|
| | | def __doSkillUserAnger(turnFight, curBatObj, useSkill):
|
| | | ## 技能释放者怒气相关
|
| | | if SkillCommon.isAngerSkill(useSkill):
|
| | | curBatObj.SetXP(0)
|
| | | elif SkillCommon.isTurnNormalSkill(useSkill):
|
| | | addXP = IpyGameDataPY.GetFuncCfg("AngerXP", 3)
|
| | | AddTurnFightXP(curBatObj, addXP, "skillID:%s" % useSkill.GetSkillID())
|
| | | return
|
| | |
|
| | | def __doSkillHurtAnger(batObj, lostHP, useSkill):
|
| | | ## 结算受伤者怒气
|
| | | if lostHP <= 0:
|
| | | return
|
| | | addXP = IpyGameDataPY.GetFuncCfg("AngerXP", 4)
|
| | | if addXP <= 0:
|
| | | return
|
| | | AddTurnFightXP(batObj, addXP, "skillID:%s" % useSkill.GetSkillID())
|
| | | return
|
| | |
|
| | | def AddTurnFightXP(gameObj, addXP, reason=""):
|
| | | ## 回合战斗增加XP
|
| | | if addXP <= 0 or not addXP:
|
| | | #GameWorld.DebugLog(" 没有增加XP! curID=%s" % (gameObj.GetID()))
|
| | | return
|
| | | posNum = gameObj.GetPosNum()
|
| | | if posNum <= 0:
|
| | | #非主战单位不加
|
| | | return
|
| | | curXP = gameObj.GetXP()
|
| | | updXP = curXP + addXP
|
| | | gameObj.SetXP(updXP)
|
| | | GameWorld.DebugLog(" 更新XP: curID=%s,curXP=%s,addXP=%s,updXP=%s,reason=%s" % (gameObj.GetID(), curXP, addXP, updXP, reason))
|
| | | return
|
| | |
|
| | | def __doUseEnhanceSkill(turnFight, curBatObj, useSkill):
|
| | | if useSkill.GetEnhanceBySkill():
|
| | | GameWorld.DebugLog("自身为额外触发的技能不再触发额外技能! skillID=%s" % useSkill.GetSkillID())
|
| | | return
|
| | | enhanceSkillIDList = useSkill.GetEnhanceSkillList()
|
| | | if not enhanceSkillIDList:
|
| | | return
|
| | | GameWorld.DebugLog("额外触发的技能! skillID=%s,enhanceSkillIDList=%s" % (useSkill.GetSkillID(), enhanceSkillIDList))
|
| | | # 根据触发技能的特点决定是触发一次还是 触发多次
|
| | | # 群体BUFF的请参考 IsPlayerUseSkill 客户端决定对象,一样可以实现同样效果
|
| | | tagObjList = useSkill.GetTagObjList()
|
| | | for enhanceSkillID in enhanceSkillIDList:
|
| | | enhanceSkillData = IpyGameDataPY.GetIpyGameData("Skill", enhanceSkillID)
|
| | | if not enhanceSkillData:
|
| | | continue
|
| | | # 继承主技能目标
|
| | | if enhanceSkillData.GetTagAim() == ChConfig.SkillTagAim_MainSkill:
|
| | | GameWorld.DebugLog(" 额外触发技能,继承主技能目标! enhanceSkillID=%s" % enhanceSkillID)
|
| | | # 额外触发的技能直接在外层检查概率,如果都没有触发则不需要再处理
|
| | | enhanceRate = enhanceSkillData.GetHappenRate() |
| | | enchanceTagObjList = []
|
| | | for tagObj in tagObjList:
|
| | | tagID = tagObj.GetID()
|
| | | if tagObj.GetHP() <= 0:
|
| | | GameWorld.DebugLog(" 已被击杀不触发: tagID=%s" % (tagID))
|
| | | continue
|
| | | hurtObj = useSkill.GetHurtObj(tagID)
|
| | | if not hurtObj:
|
| | | GameWorld.DebugLog(" 没有伤血不触发: tagID=%s" % (tagID))
|
| | | continue
|
| | | if hurtObj.HaveHurtType(ChConfig.HurtType_Miss):
|
| | | GameWorld.DebugLog(" 闪避的对象不再触发技能: tagID=%s,enhanceSkillID=%s" % (tagID, enhanceSkillID))
|
| | | continue
|
| | | if enhanceRate and enhanceRate != ChConfig.Def_MaxRateValue and not GameWorld.CanHappen(enhanceRate, ChConfig.Def_MaxRateValue):
|
| | | GameWorld.DebugLog(" 概率不触发: tagID=%s,enhanceRate=%s" % (tagID, enhanceRate))
|
| | | continue
|
| | | |
| | | enchanceTagObjList.append(tagObj)
|
| | | |
| | | if enchanceTagObjList:
|
| | | OnUseSkill(turnFight, curBatObj, enhanceSkillData, enchanceTagObjList, enhanceBySkill=useSkill)
|
| | | |
| | | continue
|
| | | |
| | | GameWorld.DebugLog(" 额外触发技能,重新锁定目标! enhanceSkillID=%s" % enhanceSkillID)
|
| | | OnUseSkill(turnFight, curBatObj, enhanceSkillData, enhanceBySkill=useSkill)
|
| | | |
| | | return
|
| | |
|
| | | def __doSkillHurtHP(attacker, defObj, curSkill):
|
| | | ## 执行技能伤血,只计算伤血,其他逻辑等技能同步后再处理
|
| | | # @return: None - 没有执行成功,即忽略该目标
|
| | | |
| | | atkObj = attacker
|
| | | atkID = atkObj.GetID()
|
| | | defID = defObj.GetID()
|
| | | hurtObj = curSkill.AddHurtObj(defID)
|
| | | |
| | | #检查是否几率触发
|
| | | if not curSkill.GetEnhanceBySkill(): # 额外触发的技能概率在触发时判断
|
| | | rate = curSkill.GetHappenRate()
|
| | | if rate and rate != ChConfig.Def_MaxRateValue and not GameWorld.CanHappen(rate, ChConfig.Def_MaxRateValue):
|
| | | #GameWorld.Log('检查是否几率触发 = %s失败 = %s'%(rate, useSkill.GetSkillName()))
|
| | | #放这里,兼容群攻时如果该技能是有概率的,则每个目标单独判断
|
| | | hurtObj.AddHurtType(ChConfig.HurtType_Fail)
|
| | | hurtObj.SetCurHP(defObj.GetHP())
|
| | | return hurtObj
|
| | | |
| | | atkEffIDNum = curSkill.FindEffectID(ChConfig.Def_Skill_Effect_Attack)
|
| | | atkSkillValue = 0
|
| | | atkSkillPer = curSkill.GetEffectValue(atkEffIDNum, 0)
|
| | | |
| | | dHP = defObj.GetHP() # 防守方当前血量
|
| | | dMaxHP = defObj.GetMaxHP() # 防守方最大血量
|
| | | |
| | | zhansha = False # 斩杀特殊处理
|
| | | # նɱ
|
| | | if zhansha:
|
| | | pass
|
| | | |
| | | else:
|
| | | hurtValue, hurtTypes = CalcHurtHP(atkObj, defObj, curSkill, atkSkillValue, atkSkillPer)
|
| | | |
| | | # 各种减伤 吸收盾处理
|
| | | #hurtValue = CalcHurtHPWithBuff(atkObj, defObj, hurtValue, curSkill, tick)
|
| | | |
| | | #伤害结构体
|
| | | hurtObj.SetHurtTypes(hurtTypes)
|
| | | hurtObj.SetHurtHP(hurtValue)
|
| | | remainHP = min(dMaxHP, max(0, dHP - hurtValue)) # 剩余血量
|
| | | |
| | | remainHP = int(remainHP) #防范
|
| | | lostHP = dHP - remainHP # 实际掉血量
|
| | | hurtObj.SetLostHP(lostHP)
|
| | | hurtObj.SetCurHP(remainHP)
|
| | | defObj.SetHP(remainHP)
|
| | | GameWorld.DebugLog(" 伤血: atkID=%s,defID=%s,hurtValue=%s,lostHP=%s,%s/%s" % (atkID, defID, hurtValue, lostHP, defObj.GetHP(), defObj.GetMaxHP()))
|
| | | |
| | | #反弹伤害
|
| | | CalcBounceHP(atkObj, defObj, hurtObj, curSkill)
|
| | | |
| | | #吸血
|
| | | CalcSuckBlood(atkObj, defObj, hurtObj, curSkill)
|
| | | |
| | | TurnAttack.AddTurnObjHurtValue(atkObj, defObj, hurtValue, lostHP, curSkill)
|
| | | return hurtObj
|
| | |
|
| | | def CalcHurtHP(atkObj, defObj, curSkill, atkSkillValue, atkSkillPer, **atkwargs):
|
| | | '''计算伤害
|
| | | '''
|
| | | pmType = GetPMType(atkObj, curSkill)
|
| | | ignoreDef = IsIgnoreDef(curSkill)
|
| | | |
| | | atkID = atkObj.GetID()
|
| | | defID = defObj.GetID()
|
| | | |
| | | skillID = curSkill.GetSkillID()
|
| | | isTurnNormalSkill = SkillCommon.isTurnNormalSkill(curSkill)
|
| | | isAngerSkill = SkillCommon.isAngerSkill(curSkill)
|
| | | isAtkbackSkill = SkillCommon.isAtkbackSkill(curSkill)
|
| | | |
| | | angerOverflow = 0 # 怒气溢出值
|
| | | |
| | | mustHit = False
|
| | | if isAngerSkill:
|
| | | mustHit = True
|
| | | GameWorld.DebugLog(" XP必命中")
|
| | | angerOverflow = max(atkObj.GetXP() - IpyGameDataPY.GetFuncCfg("AngerXP", 2), 0)
|
| | | |
| | | #命中公式 攻击方类型不同,公式不同
|
| | | if not mustHit:
|
| | | aMissRateDef = atkObj.GetAttrValue(ChConfig.AttrID_MissRateDef) #atkObj.GetHit() # 抗闪避率 - 命中
|
| | | dMissRate = defObj.GetAttrValue(ChConfig.AttrID_MissRate) # 闪避率
|
| | | missNum = defObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnMissNum)
|
| | | missRate = eval(IpyGameDataPY.GetFuncCompileCfg("MissCfg", 1))
|
| | | if GameWorld.CanHappen(missRate):
|
| | | return 0, pow(2, ChConfig.HurtType_Miss)
|
| | | |
| | | hurtTypes = pow(2, ChConfig.HurtType_Normal)
|
| | | |
| | | isSuperHit = False # 是否暴击
|
| | | if isSuperHit:
|
| | | hurtTypes |= pow(2, ChConfig.HurtType_SuperHit)
|
| | | |
| | | isParry = False # 是否格挡
|
| | | if isParry:
|
| | | hurtTypes |= pow(2, ChConfig.HurtType_Parry)
|
| | | |
| | | if ignoreDef:
|
| | | hurtTypes |= pow(2, ChConfig.HurtType_IgnoreDef)
|
| | | |
| | | #参与运算的数值
|
| | | rand = random.random() #种子数 0~1
|
| | | |
| | | aAtk = atkObj.GetAttrValue(ChConfig.AttrID_Atk) # 攻击方最大攻击
|
| | | |
| | | dHP = defObj.GetHP()
|
| | | dDef = 0 if ignoreDef else defObj.GetAttrValue(ChConfig.AttrID_Def) # 防守方防御力
|
| | | |
| | | aFinalDamPer = atkObj.GetAttrValue(ChConfig.AttrID_FinalDamPer) # 最终加成
|
| | | dFinalDamPerDef = defObj.GetAttrValue(ChConfig.AttrID_FinalDamPerDef) # 最终减伤
|
| | | |
| | | aNormalSkillPer, dNormalSkillPerDef = 0, 0
|
| | | if isTurnNormalSkill:
|
| | | aNormalSkillPer = atkObj.GetAttrValue(ChConfig.AttrID_NormalSkillPer) # 普技增伤
|
| | | dNormalSkillPerDef = defObj.GetAttrValue(ChConfig.AttrID_NormalSkillPerDef) # 普技减伤
|
| | | |
| | | aAngerSkillPer, dAngerSkillPerDef = 0, 0
|
| | | if isAngerSkill:
|
| | | aAngerSkillPer = atkObj.GetAttrValue(ChConfig.AttrID_AngerSkillPer) # 普技增伤
|
| | | dAngerSkillPerDef = defObj.GetAttrValue(ChConfig.AttrID_AngerSkillPerDef) # 普技减伤
|
| | | |
| | | # 物法增减伤
|
| | | if pmType == IPY_GameWorld.ghtMag: # 法伤
|
| | | aPMDamPer = atkObj.GetAttrValue(ChConfig.AttrID_MagDamPer)
|
| | | dPMDamPerDef = defObj.GetAttrValue(ChConfig.AttrID_MagDamPerDef)
|
| | | else: # 物伤
|
| | | aPMDamPer = atkObj.GetAttrValue(ChConfig.AttrID_PhyDamPer) |
| | | dPMDamPerDef = defObj.GetAttrValue(ChConfig.AttrID_PhyDamPerDef)
|
| | | |
| | | # 所有万分率参数统一除10000.0
|
| | | atkSkillPer /= 10000.0
|
| | | aNormalSkillPer /= 10000.0
|
| | | dNormalSkillPerDef /= 10000.0
|
| | | aAngerSkillPer /= 10000.0
|
| | | dAngerSkillPerDef /= 10000.0
|
| | | aPMDamPer /= 10000.0
|
| | | dPMDamPerDef /= 10000.0
|
| | | aFinalDamPer /= 10000.0
|
| | | dFinalDamPerDef /= 10000.0
|
| | | |
| | | |
| | | GameWorld.DebugLog("伤血计算: atkID=%s,defID=%s,skillID=%s,atkSkillPer=%s,aAtk=%s,dDef=%s,dHP=%s,hurtTypes=%s" |
| | | % (atkID, defID, skillID, atkSkillPer, aAtk, dDef, dHP, hurtTypes))
|
| | | |
| | | if "hurtFormulaKey" in atkwargs:
|
| | | aBurnValue = atkwargs.get('burnValue', 0)
|
| | | aBurnPer = atkwargs.get('burnPer', 0)
|
| | | hurtFormulaKey = atkwargs.get('hurtFormulaKey', None)
|
| | | hurtValue = eval(IpyGameDataPY.GetFuncCompileCfg("DOTFormula", 1))
|
| | | elif isTurnNormalSkill:
|
| | | hurtValue = eval(IpyGameDataPY.GetFuncCompileCfg("HurtFormula", 1))
|
| | | GameWorld.DebugLog(" 普攻技能伤害=%s" % (hurtValue))
|
| | | elif isAngerSkill:
|
| | | hurtValue = eval(IpyGameDataPY.GetFuncCompileCfg("HurtFormula", 2))
|
| | | GameWorld.DebugLog(" 怒气技能伤害=%s" % (hurtValue))
|
| | | elif isAtkbackSkill:
|
| | | hurtValue = eval(IpyGameDataPY.GetFuncCompileCfg("HurtFormula", 3))
|
| | | GameWorld.DebugLog(" 反击伤害=%s" % (hurtValue))
|
| | | else:
|
| | | hurtValue = eval(IpyGameDataPY.GetFuncCompileCfg("HurtFormula", 4))
|
| | | GameWorld.DebugLog(" 其他伤害=%s" % (hurtValue))
|
| | | |
| | | hurtValue = max(1, int(hurtValue)) # 负值、保底防范
|
| | | |
| | | return hurtValue, hurtTypes
|
| | |
|
| | | def CalcBounceHP(atkObj, defObj, hurtObj, curSkill):
|
| | | '''计算反弹反弹伤害
|
| | | '''
|
| | | if not atkObj.GetCanAttack():
|
| | | return
|
| | | |
| | | bounceHP = int(hurtObj.GetHurtHP() * random.uniform(0.1, 0.2))
|
| | | |
| | | if bounceHP <= 0:
|
| | | return
|
| | | |
| | | remainHP = atkObj.GetHP() - bounceHP # 反弹允许弹到负值,如果最终吸血没有吸到正值则算死亡
|
| | | hurtObj.SetBounceHP(bounceHP)
|
| | | atkObj.SetHP(remainHP)
|
| | | GameWorld.DebugLog(" 反弹伤害=%s,remainHP=%s" % (bounceHP, remainHP))
|
| | | |
| | | TurnAttack.AddTurnObjHurtValue(defObj, atkObj, bounceHP, bounceHP, isBounce=True)
|
| | | return
|
| | |
|
| | | def CalcSuckBlood(atkObj, defObj, hurtObj, curSkill):
|
| | | '''计算吸血
|
| | | '''
|
| | | |
| | | suckHP = int(hurtObj.GetHurtHP() * random.uniform(0.1, 0.2))
|
| | | |
| | | if suckHP <= 0:
|
| | | return
|
| | | |
| | | curHP = atkObj.GetHP()
|
| | | maxHP = atkObj.GetMaxHP()
|
| | | remainHP = min(curHP + suckHP, maxHP)
|
| | | cureHP = remainHP - curHP # 实际治疗量
|
| | | |
| | | hurtObj.SetSuckHP(suckHP)
|
| | | atkObj.SetHP(remainHP)
|
| | | GameWorld.DebugLog(" 吸血=%s,remainHP=%s/%s" % (suckHP, remainHP, maxHP))
|
| | | |
| | | # 吸血暂定算治疗
|
| | | TurnAttack.AddTurnObjCureHP(atkObj, atkObj, suckHP, cureHP)
|
| | | return
|
| | |
|
| | | def CalcCureHP(userObj, tagObj, curSkill, largeNum=False):
|
| | | ''' 计算治疗值
|
| | | '''
|
| | | cureBaseValue = 0 #治疗基础值
|
| | | effIDNum = curSkill.FindEffectID(ChConfig.Def_Skill_Effect_Cure)
|
| | | skillPer = curSkill.GetEffectValue(effIDNum, 0)
|
| | | cureType = curSkill.GetEffectValue(effIDNum, 1)
|
| | | |
| | | #获得基础治疗值
|
| | | if cureType == ChConfig.Def_Cure_Attack:
|
| | | cureBaseValue = userObj.GetAtk()
|
| | | elif cureType == ChConfig.Def_Cure_MaxHP:
|
| | | cureBaseValue = userObj.GetMaxHP()
|
| | | #elif cureType == ChConfig.Def_Cure_HurtValue:
|
| | | # cureBaseValue = GameObj.GetLastHurtValue(userObj)
|
| | | elif cureType == ChConfig.Def_Cure_TagMaxHP:
|
| | | cureBaseValue = 0 if not tagObj else tagObj.GetMaxHP()
|
| | | |
| | | #skillPer += PassiveBuffEffMng.GetPassiveSkillValueByTriggerType(userObj, None, curSkill, ChConfig.TriggerType_AddHP)
|
| | | |
| | | # 回合制
|
| | | curePer = 0 # 治疗加成
|
| | | cureDefPer = 0 # 敌方的弱化治疗
|
| | | angerOverflow = 0 # 怒气溢出值
|
| | | if SkillCommon.isAngerSkill(curSkill):
|
| | | angerOverflow = max(userObj.GetXP() - IpyGameDataPY.GetFuncCfg("AngerXP", 2), 0)
|
| | | #enemyObj = TurnAttack.GetEnemyObj(userObj)
|
| | | #curePer += GameObj.GetCurePer(userObj)
|
| | | #if enemyObj:
|
| | | # cureDefPer += GameObj.GetCureDefPer(enemyObj)
|
| | | |
| | | skillPer /= float(ChConfig.Def_MaxRateValue)
|
| | | curePer /= float(ChConfig.Def_MaxRateValue)
|
| | | cureDefPer /= float(ChConfig.Def_MaxRateValue)
|
| | | |
| | | baseValue = max(0, cureBaseValue) # 防止基值被弱化为负值,在恢复比例也是负值的情况下负负得正导致可以恢复血量
|
| | | |
| | | #公式计算治疗值 |
| | | cureHP = eval(IpyGameDataPY.GetFuncCompileCfg("CureFormula", 1))
|
| | | if not largeNum:
|
| | | cureHP = min(cureHP, ChConfig.Def_UpperLimit_DWord)
|
| | | cureHP = max(1, int(cureHP)) # 保底1点
|
| | | |
| | | GameWorld.DebugLog("计算治疗值(%s):skillID=%s,cureType=%s,baseValue=%s,skillPer=%s,curePer=%s,cureDefPer=%s,angerOverflow=%s" |
| | | % (cureHP, curSkill.GetSkillID(), cureType, baseValue, skillPer, curePer, cureDefPer, angerOverflow))
|
| | | return cureHP
|
| | |
|
| | | def Sync_UseSkill(turnFight, curBatObj, useSkill):
|
| | | ## 通知释放技能
|
| | | poolMgr = ObjPool.GetPoolMgr()
|
| | | clientPack = poolMgr.acquire(ChPyNetSendPack.tagSCUseSkill)
|
| | | clientPack.ObjID = curBatObj.GetID()
|
| | | clientPack.PMType = GetPMType(curBatObj, useSkill)
|
| | | clientPack.BattleType = useSkill.GetBatType()
|
| | | clientPack.CurHP = curBatObj.GetHP() % ChConfig.Def_PerPointValue
|
| | | clientPack.CurHPEx = curBatObj.GetHP() / ChConfig.Def_PerPointValue
|
| | | clientPack.SkillID = useSkill.GetSkillID()
|
| | | clientPack.HurtList = []
|
| | | for hurtObj in useSkill.GetHurtObjList():
|
| | | hurt = poolMgr.acquire(ChPyNetSendPack.tagSCUseSkillHurt)
|
| | | hurt.ObjID = hurtObj.GetObjID()
|
| | | hurt.AttackTypes = hurtObj.GetHurtTypes()
|
| | | hurt.HurtHP = hurtObj.GetHurtHP() % ChConfig.Def_PerPointValue
|
| | | hurt.HurtHPEx = hurtObj.GetHurtHP() / ChConfig.Def_PerPointValue
|
| | | hurt.CurHP = hurtObj.GetCurHP() % ChConfig.Def_PerPointValue
|
| | | hurt.CurHPEx = hurtObj.GetCurHP() / ChConfig.Def_PerPointValue
|
| | | hurt.SuckHP = min(hurtObj.GetSuckHP(), ChConfig.Def_UpperLimit_DWord)
|
| | | hurt.BounceHP = min(hurtObj.GetBounceHP(), ChConfig.Def_UpperLimit_DWord)
|
| | | clientPack.HurtList.append(hurt)
|
| | | clientPack.HurtCount = len(clientPack.HurtList)
|
| | | turnFight.addBatPack(clientPack)
|
| | | return
|
| | |
|
| | | def Sync_PropertyRefreshView(turnFight, curBatObj, attrID, value, diffValue, diffType=0, skillID=0, relatedSkillID=0):
|
| | | '''通知对象属性刷新展示B418
|
| | | @param attrID: 通知变化的属性ID
|
| | | @param diffValue: 变化值
|
| | | @param diffType: 变化类型,0-减少;1-增加
|
| | | @param skillID: 使用的技能表ID,即哪个技能的效果
|
| | | @param relatedSkillID: 关联的技能ID,一般是主技能ID,非主技能额外触发的为0
|
| | | '''
|
| | | if attrID not in ChConfig.CDBRefresh_AttrIDDict:
|
| | | return
|
| | | refreshType, isBig = ChConfig.CDBRefresh_AttrIDDict[attrID]
|
| | | poolMgr = ObjPool.GetPoolMgr()
|
| | | clientPack = poolMgr.acquire(ChPyNetSendPack.tagSCObjPropertyRefreshView)
|
| | | clientPack.ObjID = curBatObj.GetID()
|
| | | clientPack.RefreshType = refreshType
|
| | | if isBig:
|
| | | clientPack.Value = value % ShareDefine.Def_PerPointValue
|
| | | clientPack.ValueEx = value / ShareDefine.Def_PerPointValue
|
| | | clientPack.DiffValue = diffValue % ShareDefine.Def_PerPointValue
|
| | | clientPack.DiffValueEx = diffValue / ShareDefine.Def_PerPointValue
|
| | | else:
|
| | | clientPack.Value = value
|
| | | clientPack.ValueEx = 0
|
| | | clientPack.DiffValue = diffValue
|
| | | clientPack.DiffValueEx = 0
|
| | | clientPack.DiffType = diffType
|
| | | clientPack.SkillID = skillID
|
| | | clientPack.RelatedSkillID = relatedSkillID
|
| | | turnFight.addBatPack(clientPack)
|
| | | return
|