1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
#!/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
import TurnPassive
import TurnBuff
 
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):
        ## ÅжÏÊÇ·ñ´æÔÚijÖÖÉËѪÀàÐÍ
        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 Effect():
    
    def __init__(self, effID, values):
        self._effID = effID
        self._values = values
        return
    
    def GetEffectID(self): return self._effID
    def GetEffectValue(self, index): return self._values[index] if len(self._values) > index else 0
    def GetEffectValueCount(self): return len(self._values)
    
class SklllData():
    
    def __init__(self, ipyData):
        self._ipyData = ipyData
        self._effList = [] # [Effect, ...]
        for num in range(1, 1 + 3):
            effID = getattr(ipyData, "GetEffectID%s" % num)()
            values = getattr(ipyData, "GetEffectValues%s" % num)()
            self._effList.append(ObjPool.GetPoolMgr().acquire(Effect, effID, values))
        return
    
    def GetSkillID(self): return self._ipyData.GetSkillID()
    def GetSkillTypeID(self): return self._ipyData.GetSkillTypeID()
    def GetSkillMaxLV(self): return self._ipyData.GetSkillMaxLV()
    def GetSkillName(self): return self._ipyData.GetSkillName()
    def GetFuncType(self): return self._ipyData.GetFuncType()
    def GetSkillType(self): return self._ipyData.GetSkillType()
    def GetHurtType(self): return self._ipyData.GetHurtType()
    def GetAtkType(self): return self._ipyData.GetAtkType()
    def GetTagAim(self): return self._ipyData.GetTagAim() # Ãé׼λÖÃ
    def GetTagFriendly(self): return self._ipyData.GetTagFriendly() # µÐÎÒÄ¿±ê
    def GetTagSelf(self): return self._ipyData.GetTagSelf() # ÊÇ·ñº¬×Ô¼º
    def GetTagAffect(self): return self._ipyData.GetTagAffect() # Ä¿±êϸ·Ö
    def GetTagCount(self): return self._ipyData.GetTagCount() # Ä¿±ê¸öÊý
    def GetHappenRate(self): return self._ipyData.GetHappenRate() # ÊÍ·Å»òÌí¼Ó¼¸ÂÊ
    def GetLastTime(self): return self._ipyData.GetLastTime() # ³ÖÐøÊ±¼ä
    def GetCoolDownTime(self): return self._ipyData.GetCoolDownTime()
    def GetEffect(self, index): return self._effList[index] if len(self._effList) > index else 0
    def GetEffectCount(self): return len(self._effList)
    def GetConnSkill(self): return self._ipyData.GetConnSkill() # ¹ØÁª¼¼ÄÜ
    def GetEnhanceSkillList(self): return self._ipyData.GetEnhanceSkillList() # ¶îÍâ´¥·¢µÄ¼¼ÄÜIDÁбí
    def GetFightPower(self): return self._ipyData.GetFightPower()
    
class PyBuff():
    
    def __init__(self, ipyData):
        self._skillData = ObjPool.GetPoolMgr().acquire(SklllData, ipyData)
        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._buffStateDict = {} # buffÓ°ÏìµÄ״̬ {state:[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
        ipyData = IpyGameDataPY.GetIpyGameData("Skill", skillID)
        if not ipyData:
            return buff
        skillTypeID = ipyData.GetSkillTypeID()
        self._buffID += 1
        
        buff = ObjPool.GetPoolMgr().acquire(PyBuff, ipyData)
        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 DelBuff(self, buffID):
        if buffID not in self._buffIDDict:
            return
        buff = self._buffIDDict.pop(buffID)
        if buff in self._buffList:
            self._buffList.remove(buff)
        for skillTypeID, buffIDList in self._skillTypeIDBuffIDs.items():
            if buffID not in buffIDList:
                continue
            buffIDList.remove(buffID)
            if not buffIDList:
                self._skillTypeIDBuffIDs.pop(skillTypeID)
            break
        return
    
    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
    
    def AddBuffState(self, state, buffID):
        ## Ìí¼ÓbuffÓ°ÏìµÄ״̬£¬ChConfig.BatObjStateList
        if state not in self._buffStateDict:
            self._buffStateDict[state] = []
        buffIDList = self._buffStateDict[state]
        if buffID not in buffIDList:
            buffIDList.append(buffID)
        GameWorld.DebugLog("    AddBuffState state=%s,buffID=%s,%s" % (state, buffID, self._buffStateDict))
        return
    
    def DelBuffState(self, state, buffID):
        ## É¾³ýbuffÓ°ÏìµÄ״̬
        if state not in self._buffStateDict: return
        buffIDList = self._buffStateDict[state]
        if buffID not in buffIDList:
            return
        buffIDList.remove(buffID)
        if not len(buffIDList):
            self._buffStateDict.pop(state)
        GameWorld.DebugLog("    DelBuffState state=%s,buffID=%s,%s" % (state, buffID, self._buffStateDict))
        return
    
    def IsInBuffState(self, state):
        ## ÊÇ·ñ´¦ÓÚijÖÖ״̬ÏÂ
        return state in self._buffStateDict and len(self._buffStateDict[state]) > 0
    
class PySkill():
    
    def __init__(self, ipyData):
        self._skillData = ObjPool.GetPoolMgr().acquire(SklllData, ipyData)
        self._remainTime = 0
        self._batType = 0 # Õ½¶·ÀàÐÍ£¬ÆÕͨ¡¢Á¬»÷¡¢·´»÷¡¢×·»÷µÈ
        self._tagObjList = [] # ±¾´Î¼¼ÄÜÄ¿±êÁбí [BatObj, ...]
        self._hurtList = [] # ±¾´ÎÉËѪÁÐ±í£¬¿ÉÄÜͬһ¸ö¶ÔÏóÓжà¸öÉ˺¦£¬È絯ÉäµÈ [HurtObj, ...]
        self._bySkill = None # ÓÉÄĸö¼¼ÄÜ´¥·¢µÄ
        self._isEnhanceSkill = False # ÊÇ·ñÓÉÖ÷¼¼ÄܶîÍâ´¥·¢µÄ£¨·Ç±»¶¯´¥·¢£¬¼´Ö÷¼¼ÄܵÄEnhanceSkillList×Ö¶ÎÖеļ¼ÄÜ£©
        return
    
    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 GetEffect(self, index): return self._skillData.GetEffect(index)
    def GetEffectCount(self): return self._skillData.GetEffectCount()
    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 GetIsEnhanceSkill(self): return self._isEnhanceSkill
    def SetIsEnhanceSkill(self, isEnhanceSkill): self._isEnhanceSkill = isEnhanceSkill
    def GetBySkill(self): return self._bySkill
    def SetBySkill(self, bySkill): self._bySkill = bySkill
    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):
        ## Ìí¼Óij¸öÉËѪ
        hurtObj = ObjPool.GetPoolMgr().acquire(HurtObj)
        hurtObj.SetObjID(tagID)
        self._hurtList.append(hurtObj)
        return hurtObj
    def GetHurtObjList(self): return self._hurtList
    
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): return self._skillList[index]
    def FindSkillByID(self, skillID): return self._skillDict.get(skillID, None)
    def FindSkillByTypeID(self, skillTypeID):
        skill = None
        for s in self._skillList:
            if s.GetSkillTypeID() == skillTypeID:
                skill = s
                break
        return skill
    
    def LearnSkillByID(self, skillID):
        ipyData = IpyGameDataPY.GetIpyGameData("Skill", skillID)
        if not ipyData:
            return
        if skillID in self._skillDict:
            return
        skillTypeID = ipyData.GetSkillTypeID()
        curSkill = self.FindSkillByTypeID(skillTypeID)
        if curSkill:
            if curSkill.GetSkillID() >= skillID:
                return
            self.__deleteSkill(curSkill)
            
        # Ñ§Ð¼¼ÄÜ
        curSkill = ObjPool.GetPoolMgr().acquire(PySkill, ipyData)
        self._skillDict[skillID] = curSkill
        self._skillList.append(curSkill)
        return curSkill
    
    def __deleteSkill(self, curSkill):
        skillID = curSkill.GetSkillID()
        self._skillDict.pop(skillID, None)
        if curSkill in self._skillList:
            self._skillList.remove(curSkill)
        ObjPool.GetPoolMgr().release(curSkill)
        return
    
class BatObj():
    ## Õ½¶·ÊµÌå¶ÔÏóÊý¾Ý£¬Ä¿Ç°Óëij¸öNPCObj°ó¶¨
    
    def __init__(self):
        self.tfGUID = "" # ËùÊôµÄij³¡»ØºÏÕ½¶·µÄ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._hp = 0 # µ±Ç°ÉúÃüÖµ
        self._xp = 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):
        '''³õʼ»¯Õ½¶·ÊôÐÔ
        @param initAttrDict: ÒѾ­ËãºÃµÄÔÚÕóÈÝÖеÄÊôÐÔ£¬°üº¬î¿°í¡¢ÕóÈÝÊôÐԵȣ¬Õ½¶·ÖÐÖ»Òª¼ÆËãbuffÊôÐÔ¼´¿É
        @param initXP: ³õʼ»¯µÄÅ­ÆøÖµ
        '''
        self._initAttrDict = initAttrDict
        self._batAttrDict = {}
        self._batAttrDict.update(initAttrDict)
        self._skillTempAttrDict = {}
        self._xp = initXP
        self._hp = initAttrDict.get(ChConfig.AttrID_MaxHP, 1)
        TurnBuff.RefreshBuffAttr(self)
        TurnPassive.RefreshPassive(self)
        return
    
    def UpdInitBatAttr(self, initAttrDict):
        ## ¸üÐÂÕ½¶·ÊôÐÔ£¬Ò»°ãÖ»ÓÐÖ÷ÕóÈÝÐèÒª¸üУ¬Õ½¶·ÖÐÑø³É¡¢×°±¸±ä»¯µÈÒýÆðµÄÖ÷ÕóÈÝÊôÐÔ±ä¸üʱÐèҪʵʱ¸üÐÂ
        self._initAttrDict = initAttrDict
        TurnBuff.RefreshBuffAttr(self)
        return
    
    def ResetBattleEffect(self):
        self._batAttrDict = {}
        self._batAttrDict.update(self._initAttrDict)
        return self._batAttrDict
    
    def GetTFGUID(self): return self.tfGUID # ËùÊôµÄij³¡Õ½¶·
    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.skinID # ½öÍæ¼ÒÓÐÖµ£¬Î佫Ƥ·ô
    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 IsInState(self, state):
        ## ÊÇ·ñ´¦ÓÚijÖÖ״̬ÏÂ
        return self._buffMgr.IsInBuffState(state)
    
    # Õ½¶·ÊôÐÔ
    def GetMaxHP(self): return self._batAttrDict.get(ChConfig.AttrID_MaxHP, 0)
    def SetMaxHP(self, maxHP, isNotify=False):
        self._batAttrDict[ChConfig.AttrID_MaxHP] = maxHP
        if isNotify:
            NotifyObjInfoRefresh(self, ChConfig.AttrID_MaxHP, maxHP)
        return
    def GetHP(self): return self._hp
    def SetHP(self, hp, isNotify=False):
        self._hp = hp
        if isNotify:
            NotifyObjInfoRefresh(self, ChConfig.AttrID_HP, hp)
        return
    def SetHPFull(self, isNotify=True): self.SetHP(self.GetMaxHP(), isNotify)
    def GetXP(self): return self._xp
    def SetXP(self, xp, isNotify=True):
        self._xp = xp
        if isNotify:
            NotifyObjInfoRefresh(self, ChConfig.AttrID_XP, xp)
        return
    def GetAtk(self): return self.GetBatAttrValue(ChConfig.AttrID_Atk)
    def GetDef(self): return self.GetBatAttrValue(ChConfig.AttrID_Def)
    
    def GetBatAttrValue(self, attrID, includeTemp=True):
        #ChConfig.AttrID_HP ChConfig.AttrID_XP
        value = self._batAttrDict.get(attrID, 0)
        if includeTemp and attrID in self._skillTempAttrDict:
            value += self._skillTempAttrDict[attrID] # Ö§³ÖÕý¸ºÖµ
            value = max(1, value)
        return value
    def SetBatAttrValue(self, attrID, value): self._batAttrDict[attrID] = 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 = {}
    
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