hxp
2021-11-09 f4f907ae6ae2f22207859230e8fc88583fe3a723
9341 【BT5】【主干】【后端】情缘系统

# Conflicts:
# ServerPython/CoreServerGroup/GameServer/PyNetPack.ini
# ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py
# ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py
# ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py
# ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py
# ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py
# ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
# ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
# ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
# ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
# ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
20个文件已修改
5个文件已添加
2955 ■■■■■ 已修改文件
PySysDB/PySysDBG.h 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
PySysDB/PySysDBPY.h 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py 484 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/Friend.py 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFriend.py 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerLove.py 723 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerSocial.py 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerTalk.py 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/UpdatePlayerName.py 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/PyGameDataStruct.py 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py 484 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Love.py 100 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/PrintFightPower.py 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerLove.py 662 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTalk.py 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerViewCacheTube.py 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_Love.py 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
PySysDB/PySysDBG.h
@@ -862,6 +862,18 @@
    dict        Award;    //奖励 {"职业":[[物品ID,个数,是否绑定],...], ...}
};
//情缘提亲表
struct tagMarry
{
    BYTE        _BridePriceID;    //聘礼ID
    DWORD        Prosperity;    //初始繁荣度
    WORD        CandyTimes;    //喜糖持续时间秒
    list        CandyItemInfo;    //喜糖物品列表[[物品ID,个数,是否拍品], ...]
    list        BrideGiftItemInfo;    //聘礼物品列表[[物品ID,个数,是否拍品], ...]
    char        WorldNotifyKey;    //广播key
};
//幸运鉴宝活动时间表
struct tagActLuckyTreasure
PySysDB/PySysDBPY.h
@@ -2423,6 +2423,32 @@
    BYTE        _QualityLV;    //品级
};
//情缘提亲表
struct tagMarry
{
    BYTE        _BridePriceID;    //聘礼ID
    list        CostMoneyInfo;    //消耗货币类型|数值
    BYTE        CanBuyCount;    //可购买次数
    BYTE        IsDayReset;    //是否每日重置
};
//情缘情戒表
struct tagLoveRing
{
    BYTE        _RingClassLV;    //情戒阶级
    BYTE        _RingStarLV;    //情戒星级
    list        CoupleAttrType;    //仙侣属性类型(非累积)
    list        CoupleAttrValue;    //仙侣属性值(非累积)
    list        StarAttrType;    //星级额外属性类型(非累积)
    list        StarAttrValue;    //星级额外属性值(非累积)
    list        UpItemAttrType;    //每x个培养丹增加属性类型,x=UpEatItemPerCount
    list        UpItemAttrValue;    //每x个培养丹增加属性值,x=UpEatItemPerCount
    DWORD        NeedEatCount;    //升级所需个数(非累计)
    DWORD        UpEatItemPerCount;    //每次培养消耗x个
};
//骑宠幻化表
struct tagHorsePetSkin
ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py
@@ -592,6 +592,8 @@
            
            ShareDefine.Def_BT_Arena                    : 1000,          #竞技场榜
            ShareDefine.Def_BT_Environment              : 20,            #环保榜 (垃圾分类活动)
            ShareDefine.Def_BT_Charm                    : 100,           #魅力总榜
            ShareDefine.Def_BT_CharmDay                 : 100,           #魅力日榜
            }
#排行榜保存类型(和BillboardType匹配), 默认保存, 如果不保存,可配置进去
ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py
@@ -2330,6 +2330,114 @@
#------------------------------------------------------
# B3 16 和平离婚回应 #tagGCMarryBreakResponse
class  tagGCMarryBreakResponse(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("IsOK", c_ubyte),    # 是否同意,0-否,1-是
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xB3
        self.SubCmd = 0x16
        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 = 0xB3
        self.SubCmd = 0x16
        self.IsOK = 0
        return
    def GetLength(self):
        return sizeof(tagGCMarryBreakResponse)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B3 16 和平离婚回应 //tagGCMarryBreakResponse:
                                Cmd:%s,
                                SubCmd:%s,
                                IsOK:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.IsOK
                                )
        return DumpString
m_NAtagGCMarryBreakResponse=tagGCMarryBreakResponse()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCMarryBreakResponse.Cmd,m_NAtagGCMarryBreakResponse.SubCmd))] = m_NAtagGCMarryBreakResponse
#------------------------------------------------------
# B3 12 提亲回应 #tagCGMarryResponse
class  tagCGMarryResponse(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("ReqPlayerID", c_int),    # 提亲的玩家ID
                  ("IsOK", c_ubyte),    # 是否同意,0-否,1-是
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xB3
        self.SubCmd = 0x12
        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 = 0xB3
        self.SubCmd = 0x12
        self.ReqPlayerID = 0
        self.IsOK = 0
        return
    def GetLength(self):
        return sizeof(tagCGMarryResponse)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B3 12 提亲回应 //tagCGMarryResponse:
                                Cmd:%s,
                                SubCmd:%s,
                                ReqPlayerID:%d,
                                IsOK:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.ReqPlayerID,
                                self.IsOK
                                )
        return DumpString
m_NAtagCGMarryResponse=tagCGMarryResponse()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCGMarryResponse.Cmd,m_NAtagCGMarryResponse.SubCmd))] = m_NAtagCGMarryResponse
#------------------------------------------------------
#B3 04 加入黑名单 #tagCGAddBlackList
class  tagCGAddBlackList(Structure):
@@ -3991,6 +4099,382 @@
#------------------------------------------------------
# B3 17 情戒解锁 #tagCMLoveRingUnlock
class  tagCMLoveRingUnlock(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xB3
        self.SubCmd = 0x17
        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 = 0xB3
        self.SubCmd = 0x17
        return
    def GetLength(self):
        return sizeof(tagCMLoveRingUnlock)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B3 17 情戒解锁 //tagCMLoveRingUnlock:
                                Cmd:%s,
                                SubCmd:%s
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd
                                )
        return DumpString
m_NAtagCMLoveRingUnlock=tagCMLoveRingUnlock()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMLoveRingUnlock.Cmd,m_NAtagCMLoveRingUnlock.SubCmd))] = m_NAtagCMLoveRingUnlock
#------------------------------------------------------
# B3 18 情戒升级 #tagCMLoveRingUp
class  tagCMLoveRingUp(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("UseItemCnt", c_int),    #消耗材料个数
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xB3
        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 = 0xB3
        self.SubCmd = 0x18
        self.UseItemCnt = 0
        return
    def GetLength(self):
        return sizeof(tagCMLoveRingUp)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B3 18 情戒升级 //tagCMLoveRingUp:
                                Cmd:%s,
                                SubCmd:%s,
                                UseItemCnt:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.UseItemCnt
                                )
        return DumpString
m_NAtagCMLoveRingUp=tagCMLoveRingUp()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMLoveRingUp.Cmd,m_NAtagCMLoveRingUp.SubCmd))] = m_NAtagCMLoveRingUp
#------------------------------------------------------
# B3 15 离婚 #tagCMMarryBreak
class  tagCMMarryBreak(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("BreakType", c_ubyte),    # 0-和平离婚;1-强制离婚
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xB3
        self.SubCmd = 0x15
        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 = 0xB3
        self.SubCmd = 0x15
        self.BreakType = 0
        return
    def GetLength(self):
        return sizeof(tagCMMarryBreak)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B3 15 离婚 //tagCMMarryBreak:
                                Cmd:%s,
                                SubCmd:%s,
                                BreakType:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.BreakType
                                )
        return DumpString
m_NAtagCMMarryBreak=tagCMMarryBreak()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMMarryBreak.Cmd,m_NAtagCMMarryBreak.SubCmd))] = m_NAtagCMMarryBreak
#------------------------------------------------------
# B3 14 购买婚礼烟花 #tagCMMarryBuyFireworks
class  tagCMMarryBuyFireworks(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("PlayerIDA", c_int),    # 喜糖所属玩家IDA
                  ("PlayerIDB", c_int),    # 喜糖所属玩家IDB
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xB3
        self.SubCmd = 0x14
        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 = 0xB3
        self.SubCmd = 0x14
        self.PlayerIDA = 0
        self.PlayerIDB = 0
        return
    def GetLength(self):
        return sizeof(tagCMMarryBuyFireworks)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B3 14 购买婚礼烟花 //tagCMMarryBuyFireworks:
                                Cmd:%s,
                                SubCmd:%s,
                                PlayerIDA:%d,
                                PlayerIDB:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.PlayerIDA,
                                self.PlayerIDB
                                )
        return DumpString
m_NAtagCMMarryBuyFireworks=tagCMMarryBuyFireworks()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMMarryBuyFireworks.Cmd,m_NAtagCMMarryBuyFireworks.SubCmd))] = m_NAtagCMMarryBuyFireworks
#------------------------------------------------------
# B3 13 吃喜糖 #tagCMMarryEatCandy
class  tagCMMarryEatCandy(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("PlayerIDA", c_int),    # 喜糖所属玩家IDA
                  ("PlayerIDB", c_int),    # 喜糖所属玩家IDB
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xB3
        self.SubCmd = 0x13
        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 = 0xB3
        self.SubCmd = 0x13
        self.PlayerIDA = 0
        self.PlayerIDB = 0
        return
    def GetLength(self):
        return sizeof(tagCMMarryEatCandy)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B3 13 吃喜糖 //tagCMMarryEatCandy:
                                Cmd:%s,
                                SubCmd:%s,
                                PlayerIDA:%d,
                                PlayerIDB:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.PlayerIDA,
                                self.PlayerIDB
                                )
        return DumpString
m_NAtagCMMarryEatCandy=tagCMMarryEatCandy()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMMarryEatCandy.Cmd,m_NAtagCMMarryEatCandy.SubCmd))] = m_NAtagCMMarryEatCandy
#------------------------------------------------------
# B3 11 提亲 #tagCMMarryReq
class  tagCMMarryReq(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("TagPlayerID", c_int),    # 目标玩家ID
                  ("BridePriceID", c_ubyte),    # 聘礼ID
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xB3
        self.SubCmd = 0x11
        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 = 0xB3
        self.SubCmd = 0x11
        self.TagPlayerID = 0
        self.BridePriceID = 0
        return
    def GetLength(self):
        return sizeof(tagCMMarryReq)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B3 11 提亲 //tagCMMarryReq:
                                Cmd:%s,
                                SubCmd:%s,
                                TagPlayerID:%d,
                                BridePriceID:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.TagPlayerID,
                                self.BridePriceID
                                )
        return DumpString
m_NAtagCMMarryReq=tagCMMarryReq()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMMarryReq.Cmd,m_NAtagCMMarryReq.SubCmd))] = m_NAtagCMMarryReq
#------------------------------------------------------
# B3 10 送花 #tagCMSendFlowers
class  tagCMSendFlowers(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("TagPlayerID", c_int),    # 目标玩家ID
                  ("FlowerCount", c_int),    # 赠送花数量
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xB3
        self.SubCmd = 0x10
        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 = 0xB3
        self.SubCmd = 0x10
        self.TagPlayerID = 0
        self.FlowerCount = 0
        return
    def GetLength(self):
        return sizeof(tagCMSendFlowers)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B3 10 送花 //tagCMSendFlowers:
                                Cmd:%s,
                                SubCmd:%s,
                                TagPlayerID:%d,
                                FlowerCount:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.TagPlayerID,
                                self.FlowerCount
                                )
        return DumpString
m_NAtagCMSendFlowers=tagCMSendFlowers()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMSendFlowers.Cmd,m_NAtagCMSendFlowers.SubCmd))] = m_NAtagCMSendFlowers
#------------------------------------------------------
# A1 01 玩家电脑信息 #tagCMPCInfo
class  tagCMPCInfo(Structure):
ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/Friend.py
New file
@@ -0,0 +1,68 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package GM.Commands.Friend
#
# @todo:好友
# @author hxp
# @date 2021-11-09
# @version 1.0
#
# 详细描述: 好友
#
#-------------------------------------------------------------------------------
#"""Version = 2021-11-09 20:00"""
#-------------------------------------------------------------------------------
import GameWorld
import PyDataManager
#---------------------------------------------------------------------
#全局变量
#---------------------------------------------------------------------
#---------------------------------------------------------------------
#逻辑实现
## 执行逻辑
#  @param curPlayer 当前玩家
#  @param gmList [cmdIndex gmAccID msg]
#  @return None
#  @remarks 函数详细说明.
def OnExec(curPlayer, gmList):
    ## 本服处理
    if not gmList or len(gmList) != 2:
        GameWorld.DebugAnswer(curPlayer, "设置亲密: Friend 好友玩家ID 亲密度")
        curFriends = PyDataManager.GetFriendManager().GetFriends(curPlayer.GetPlayerID())
        if curFriends:
            GameWorld.DebugAnswer(curPlayer, "当前好友总数=%s" % len(curFriends.SocialDict))
            for friendID, friendObj in curFriends.SocialDict.items():
                GameWorld.DebugAnswer(curPlayer, "    friendID=%s,亲密度=%s" % (friendID, friendObj.Intimacy))
        return
    friendID = gmList[0]
    intimacyValue = gmList[1]
    playerID = curPlayer.GetPlayerID()
    curFriends = PyDataManager.GetFriendManager().GetFriends(playerID)
    if not curFriends:
        GameWorld.DebugAnswer(curPlayer, "没有好友!")
        return
    updIntimacy = curFriends.SetIntimacy(curPlayer, friendID, intimacyValue)
    if updIntimacy == None:
        GameWorld.DebugAnswer(curPlayer, "没有该好友!friendID=%s" % friendID)
        return
    GameWorld.DebugAnswer(curPlayer, "设置好友[ %s ]亲密度: %s" % (friendID, updIntimacy))
    tagFriends = PyDataManager.GetFriendManager().GetFriends(friendID)
    if tagFriends != None:
        tagPlayer = GameWorld.GetPlayerManager().FindPlayerByID(friendID)
        updIntimacy = tagFriends.SetIntimacy(tagPlayer, playerID, intimacyValue)
        if updIntimacy != None:
            GameWorld.DebugAnswer(curPlayer, "对方好友[ %s ]亲密度: %s" % (playerID, updIntimacy))
    return
ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py
@@ -708,6 +708,15 @@
                        ("dict", "Award", 0),
                        ),
                "Marry":(
                        ("BYTE", "BridePriceID", 1),
                        ("DWORD", "Prosperity", 0),
                        ("WORD", "CandyTimes", 0),
                        ("list", "CandyItemInfo", 0),
                        ("list", "BrideGiftItemInfo", 0),
                        ("char", "WorldNotifyKey", 0),
                        ),
                "ActLuckyTreasure":(
                        ("DWORD", "CfgID", 1),
                        ("char", "ActMark", 0),
@@ -2186,6 +2195,25 @@
    def GetRank(self): return self.Rank # 排名
    def GetAward(self): return self.Award # 奖励 {"职业":[[物品ID,个数,是否绑定],...], ...}
# 情缘提亲表
class IPY_Marry():
    def __init__(self):
        self.BridePriceID = 0
        self.Prosperity = 0
        self.CandyTimes = 0
        self.CandyItemInfo = []
        self.BrideGiftItemInfo = []
        self.WorldNotifyKey = ""
        return
    def GetBridePriceID(self): return self.BridePriceID # 聘礼ID
    def GetProsperity(self): return self.Prosperity # 初始繁荣度
    def GetCandyTimes(self): return self.CandyTimes # 喜糖持续时间秒
    def GetCandyItemInfo(self): return self.CandyItemInfo # 喜糖物品列表[[物品ID,个数,是否拍品], ...]
    def GetBrideGiftItemInfo(self): return self.BrideGiftItemInfo # 聘礼物品列表[[物品ID,个数,是否拍品], ...]
    def GetWorldNotifyKey(self): return self.WorldNotifyKey # 广播key
# 幸运鉴宝活动时间表
class IPY_ActLuckyTreasure():
    
@@ -2465,6 +2493,8 @@
        self.ipyActNewFairyCeremonyLen = len(self.ipyActNewFairyCeremonyCache)
        self.ipyNewUniquenessArriveCache = self.__LoadFileData("NewUniquenessArrive", IPY_NewUniquenessArrive)
        self.ipyNewUniquenessArriveLen = len(self.ipyNewUniquenessArriveCache)
        self.ipyMarryCache = self.__LoadFileData("Marry", IPY_Marry)
        self.ipyMarryLen = len(self.ipyMarryCache)
        self.ipyActLuckyTreasureCache = self.__LoadFileData("ActLuckyTreasure", IPY_ActLuckyTreasure)
        self.ipyActLuckyTreasureLen = len(self.ipyActLuckyTreasureCache)
        self.ipyCrossActCTGBillboardCache = self.__LoadFileData("CrossActCTGBillboard", IPY_CrossActCTGBillboard)
@@ -2769,6 +2799,8 @@
    def GetActNewFairyCeremonyByIndex(self, index): return self.ipyActNewFairyCeremonyCache[index]
    def GetNewUniquenessArriveCount(self): return self.ipyNewUniquenessArriveLen
    def GetNewUniquenessArriveByIndex(self, index): return self.ipyNewUniquenessArriveCache[index]
    def GetMarryCount(self): return self.ipyMarryLen
    def GetMarryByIndex(self, index): return self.ipyMarryCache[index]
    def GetActLuckyTreasureCount(self): return self.ipyActLuckyTreasureLen
    def GetActLuckyTreasureByIndex(self, index): return self.ipyActLuckyTreasureCache[index]
    def GetCrossActCTGBillboardCount(self): return self.ipyCrossActCTGBillboardLen
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py
@@ -247,6 +247,10 @@
def GetChatBubbleBox(curPlayer): return curPlayer.GetExAttr10()
def SetChatBubbleBox(curPlayer, value): return curPlayer.SetExAttr10(value)
##伴侣ID
def GetCoupleID(curPlayer): return curPlayer.GetExAttr11()
def SetCoupleID(curPlayer, coupleID): return curPlayer.SetExAttr11(coupleID)
##玩家主动退出仙盟时间(<100代表退出次数)
def SetLeaveFamilyTime(curPlayer, value, isSyncMap=True):
    curPlayer.SetExAttr12(value)
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFriend.py
@@ -214,6 +214,11 @@
        GameWorld.Log('DeleteFriend -> 封包异常 ->没有这个玩家', playerID)
        return
    
    coupleID = PlayerControl.GetCoupleID(curPlayer)
    if coupleID == friendID:
        GameWorld.Log('DeleteFriend -> 封包异常 ->伴侣不能删除好友,coupleID=%s' % coupleID, playerID)
        return
    #离线好友同时删除记录
    PyDataManager.GetFriendManager().DelFriendBoth(playerID, friendID)
    
@@ -389,6 +394,10 @@
    #    return
    #===========================================================================
    
    if tagID == PlayerControl.GetCoupleID(curPlayer):
        GameWorld.DebugLog("伴侣不能加入黑名单! tagID=%s" % tagID, curPlayer.GetID())
        return
    tagPlayer = GameWorld.GetPlayerManager().FindPlayerByID(tagID)
    if not tagPlayer:
        curCache = PlayerViewCache.FindViewCache(tagID)
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerLove.py
New file
@@ -0,0 +1,723 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package PlayerLove
#
# @todo:情缘系统
# @author hxp
# @date 2021-11-09
# @version 1.0
#
# 详细描述: 情缘系统
#
#-------------------------------------------------------------------------------
#"""Version = 2021-11-09 20:00"""
#-------------------------------------------------------------------------------
import GameWorld
import PyDataManager
import PlayerControl
import ChPyNetSendPack
import PlayerCompensation
import PlayerFamilyRedPacket
import PlayerBillboard
import NetPackCommon
import IpyGameDataPY
import PlayerSocial
import ShareDefine
import PyGameData
import operator
import time
import math
class MarryReq():
    ## 进行中的求亲,不存档,回应方上线也不通知,仅双方都在线时同步处理,服务器维护不存档,重新请求
    def __init__(self):
        self.playerIDA = 0 # 请求方
        self.playerIDB = 0 # 回应方
        self.bridePriceID = 0 # 聘礼ID
        self.reqTime = 0 # 请求时间戳
        return
class MarryCandy():
    ## 喜糖宴会,不存库,服务器关服时未结束的喜宴强制结算
    def __init__(self):
        self.playerIDA = 0
        self.playerNameA = ""
        self.playerIDB = 0
        self.playerNameB = ""
        self.bridePriceID = 0 # 聘礼ID
        self.marryTime = 0 # 成亲时间戳
        self.endTime = 0 # 结算时间戳
        self.prosperity = 0 # 总繁荣度
        self.prosperitySuccessList = [] # 繁荣度达标成就已处理值
        self.playerFreeEatCountDict = {} # 玩家免费吃喜糖次数 {playerID:次数, ...}
        self.fireworksCountDict = {} # 烟花次数信息 {playerID:次数, ...}
        return
def AddProsperity(candyObj, addValue):
    candyObj.prosperity += addValue
    succProsperityStrList = []
    # 繁荣度全服红包
    redpackDict = IpyGameDataPY.GetFuncEvalCfg("LoveCandyAward", 1, {})
    for prosperityStr, redPackID in redpackDict.items():
        if candyObj.prosperity < int(prosperityStr):
            continue
        if prosperityStr in candyObj.prosperitySuccessList:
            continue
        succProsperityStrList.append(prosperityStr)
        PlayerFamilyRedPacket.CreateSystemRedPacket(redPackID)
    # 繁荣度额外奖励
    itemInfoDict = IpyGameDataPY.GetFuncEvalCfg("LoveCandyAward", 2, {})
    for prosperityStr, itemList in itemInfoDict.items():
        if candyObj.prosperity < int(prosperityStr):
            continue
        if prosperityStr in candyObj.prosperitySuccessList:
            continue
        succProsperityStrList.append(prosperityStr)
        playerIDList = [candyObj.playerIDA, candyObj.playerIDB]
        paramList = [candyObj.playerNameA, candyObj.playerNameB, prosperityStr]
        PlayerCompensation.SendMailByKey("MarryCandyProsperity", playerIDList, itemList, paramList)
    for prosperityStr in succProsperityStrList:
        if prosperityStr not in candyObj.prosperitySuccessList:
            candyObj.prosperitySuccessList.append(prosperityStr)
    return
def OnServerClose():
    for candyObj in PyGameData.g_marryCandySortList:
        __DoMarryCandyOver(candyObj)
    return
def DoOnDay():
    PlayerBillboard.ClearBillboardByIndex(ShareDefine.Def_BT_CharmDay)
    return
def OnPlayerLogin(curPlayer):
    __LoginCheckCouple(curPlayer)
    Sync_CandyList(curPlayer)
    return
def OnTimeProcess(curTime, tick):
    ## 每秒触发一次
    # 检查结算喜糖
    doCount = len(PyGameData.g_marryCandySortList)
    while doCount > 0 and PyGameData.g_marryCandySortList:
        doCount -= 1
        candyObj = PyGameData.g_marryCandySortList[0]
        if curTime <= candyObj.endTime:
            break
        PyGameData.g_marryCandySortList.pop(0)
        PyGameData.g_marryCandyInfo.pop((candyObj.playerIDA, candyObj.playerIDB), None)
        __DoMarryCandyOver(candyObj)
    return
def __DoMarryCandyOver(candyObj):
    playerIDA, playerIDB, prosperity = candyObj.playerIDA, candyObj.playerIDB, candyObj.prosperity
    GameWorld.Log("结算婚礼喜糖宴会: playerIDA=%s,playerIDB=%s,prosperity=%s" % (playerIDA, playerIDB, prosperity))
    transformItemInfo = IpyGameDataPY.GetFuncEvalCfg("LoveCandyAward", 3)
    if len(transformItemInfo) != 2:
        return
    unitProsperity, itemID = transformItemInfo
    itemCount = int(math.ceil(prosperity / float(unitProsperity)))
    remainSeconds = candyObj.endTime - int(time.time())
    GameWorld.Log("喜宴繁荣度转化奖励: playerIDA=%s,playerIDB=%s,prosperity=%s,itemID=%s,itemCount=%s,marryTime=%s,endTime=%s,remainSeconds=%s"
                  % (playerIDA, playerIDB, prosperity, itemID, itemCount,
                     GameWorld.ChangeTimeNumToStr(candyObj.marryTime),
                     GameWorld.ChangeTimeNumToStr(candyObj.endTime), remainSeconds
                     ))
    if not itemID or not itemCount:
        return
    playerIDList = [playerIDA, playerIDB]
    itemList = [[itemID, itemCount, 0]]
    paramList = [candyObj.playerNameA, candyObj.playerNameB, prosperity]
    PlayerCompensation.SendMailByKey("MarryCandyOver", playerIDList, itemList, paramList)
    return
#// B3 12 提亲回应 #tagCGMarryResponse
#
#struct    tagCGMarryResponse
#{
#    tagHead        Head;
#    DWORD        ReqPlayerID;    // 提亲的玩家ID
#    BYTE        IsOK;    // 是否同意,0-否,1-是
#};
def OnMarryResponse(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    reqPlayerID = clientData.ReqPlayerID
    isOK = clientData.IsOK
    reqPlayer = GameWorld.GetPlayerManager().FindPlayerByID(reqPlayerID)
    if not __MarryCheckComm(curPlayer, reqPlayer, reqPlayerID, False):
        return
    playerID = curPlayer.GetPlayerID()
    curTime = int(time.time())
    if reqPlayerID not in PyGameData.g_marryReqInfo:
        GameWorld.DebugLog("提亲请求不存在! reqPlayerID=%s" % reqPlayerID, playerID)
        PlayerControl.NotifyCode(curPlayer, "MarryReqInvalid")
        return
    reqData = PyGameData.g_marryReqInfo[reqPlayerID]
    if reqData.playerIDB != playerID:
        GameWorld.DebugLog("非目前提亲对象! reqPlayerID=%s, playerIDB(%s) != playerID(%s)"
                           % (reqPlayerID, reqData.playerIDB, playerID), playerID)
        PlayerControl.NotifyCode(curPlayer, "MarryReqInvalid")
        return
    reqData = PyGameData.g_marryReqInfo.pop(reqPlayerID)
    bridePriceID = reqData.bridePriceID
    passSeconds = curTime - reqData.reqTime
    reqSecondCD = IpyGameDataPY.GetFuncCfg("LoveMarry", 1)
    if passSeconds > reqSecondCD:
        GameWorld.DebugLog("提亲请求已超时! reqPlayerID=%s" % reqPlayerID, playerID)
        PlayerControl.NotifyCode(curPlayer, "MarryReqInvalid")
        return
    ipyData = IpyGameDataPY.GetIpyGameData("Marry", bridePriceID)
    if not ipyData:
        return
    reqPlayerName = reqPlayer.GetName()
    playerName = curPlayer.GetName()
    responsePack = ChPyNetSendPack.tagGCMarryResponseRet()
    responsePack.PlayerIDA = reqPlayerID
    responsePack.PlayerNameA = reqPlayerName
    responsePack.NameALen = len(responsePack.PlayerNameA)
    responsePack.PlayerIDB = playerID
    responsePack.PlayerNameB = playerName
    responsePack.NameBLen = len(responsePack.PlayerNameB)
    responsePack.IsOK = isOK
    NetPackCommon.SendFakePack(reqPlayer, responsePack) # 必回复提亲方
    # 拒绝
    if not isOK:
        return
    NetPackCommon.SendFakePack(curPlayer, responsePack) # 回应方仅同意时同步
    # ===================== 以下执行成亲逻辑 =====================
    prosperity = ipyData.GetProsperity()
    candyTimes = ipyData.GetCandyTimes()
    brideGiftItemInfo = ipyData.GetBrideGiftItemInfo()
    worldNotifyKey = ipyData.GetWorldNotifyKey()
    if worldNotifyKey:
        paramList = [reqPlayerName, playerName]
        for itemID, itemCount, _ in brideGiftItemInfo:
            paramList.extend([itemID, itemCount])
        PlayerControl.WorldNotify(0, worldNotifyKey, paramList)
    for player, coupleID, coupleName in [[reqPlayer, playerID, playerName], [curPlayer, reqPlayerID, reqPlayerName]]:
        PlayerControl.SetCoupleID(player, coupleID)
        # 更新社交关系
        socialPlayer = PyDataManager.GetPersonalSocialManager().GetSocialPlayer(player.GetPlayerID())
        if socialPlayer:
            socialPlayer.SetCoupleInfo(coupleID, coupleName)
            socialPlayer.CheckUpdCouplePriceMaxID(bridePriceID)
        # 通知地图玩家
        dataMsg = [reqPlayerID, coupleID, curTime, bridePriceID]
        MapServer_QueryPlayer_DoLogic_Love(player, "MarrySuccess", dataMsg, playerID)
    # 聘礼奖励发邮件
    playerIDList = [reqPlayerID, playerID]
    paramList = [reqPlayerName, playerName]
    PlayerCompensation.SendMailByKey("MarrySuccess", playerIDList, brideGiftItemInfo, paramList)
    # 通知地图全局伴侣信息
    PlayerSocial.SendMapServerCoupleInfo([playerID, reqPlayerID])
    # 新增喜糖
    candyObj = MarryCandy()
    candyObj.playerIDA = reqPlayerID
    candyObj.playerNameA = reqPlayerName
    candyObj.playerIDB = playerID
    candyObj.playerNameB = playerName
    candyObj.bridePriceID = bridePriceID
    candyObj.marryTime = curTime
    candyObj.endTime = curTime + candyTimes
    AddProsperity(candyObj, prosperity)
    PyGameData.g_marryCandyInfo[(reqPlayerID, playerID)] = candyObj
    PyGameData.g_marryCandySortList = PyGameData.g_marryCandyInfo.values()
    PyGameData.g_marryCandySortList.sort(key=operator.attrgetter("endTime"))
    Sync_CandyList(None, [candyObj])
    return
#// B3 16 和平离婚回应 #tagGCMarryBreakResponse
#
#struct    tagGCMarryBreakResponse
#{
#    tagHead        Head;
#    BYTE        IsOK;    // 是否同意,0-否,1-是
#};
def OnMarryBreakResponse(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    isOK = clientData.IsOK
    playerID = curPlayer.GetPlayerID()
    coupleID = PlayerControl.GetCoupleID(curPlayer)
    if not coupleID:
        return
    if coupleID not in PyGameData.g_marryBreakReqInfo:
        GameWorld.DebugLog("对方没有请求和离,回应无效! coupleID=%s" % coupleID, playerID)
        return
    if playerID != PyGameData.g_marryBreakReqInfo[coupleID]:
        GameWorld.DebugLog("非对方没有请求和离对象,回应无效! reqPlayerID=%s,tagPlayerID=%s"
                           % (coupleID, PyGameData.g_marryBreakReqInfo[coupleID]), playerID)
        return
    PyGameData.g_marryBreakReqInfo.pop(coupleID, None)
    if not isOK:
        PlayerCompensation.SendMailByKey("MarryBreakRefuse", [coupleID], [], [curPlayer.GetName()])
        return
    GameWorld.Log("同意和离: coupleID=%s" % coupleID, playerID)
    __DoMarryBreak(curPlayer, coupleID)
    return
def __DoMarryBreak(curPlayer, coupleID):
    ## 执行离婚
    playerID = curPlayer.GetPlayerID()
    __ClearCoupleSocial(curPlayer)
    tagPlayer = GameWorld.GetPlayerManager().FindPlayerByID(coupleID)
    if tagPlayer:
        __ClearCoupleSocial(tagPlayer)
    # 未在线,标记离婚状态,等下次玩家上线处理
    else:
        socialPlayer = PyDataManager.GetPersonalSocialManager().GetSocialPlayer(coupleID)
        if socialPlayer:
            socialPlayer.SetCoupleBreakOffline()
            GameWorld.Log("离婚时伴侣不在线,标记伴侣社交关系已离婚!等下次上线处理! coupleID=%s" % coupleID, playerID)
    # 通知地图全局伴侣信息
    PlayerSocial.SendMapServerCoupleInfo([playerID, coupleID])
    return
def __LoginCheckCouple(curPlayer):
    ## 登录检查是否已被离婚
    playerID = curPlayer.GetPlayerID()
    coupleID = PlayerControl.GetCoupleID(curPlayer)
    if not coupleID:
        return
    socialPlayer = PyDataManager.GetPersonalSocialManager().GetSocialPlayer(playerID)
    if socialPlayer == None or socialPlayer.GetCoupleBreakOffline():
        GameWorld.Log("玩家上线检测到已被离婚,执行解除伴侣关系!coupleID=%s" % coupleID, playerID)
        __ClearCoupleSocial(curPlayer)
    # 上线未同步过地图全局伴侣信息的则同步
    if socialPlayer and not socialPlayer.syncMapCouple and socialPlayer.GetCoupleID():
        PlayerSocial.SendMapServerCoupleInfo([playerID])
    return
def __ClearCoupleSocial(curPlayer):
    ## 清除伴侣社交关系
    coupleID = PlayerControl.GetCoupleID(curPlayer)
    coupleName = ""
    playerID = curPlayer.GetPlayerID()
    GameWorld.Log("玩家执行解除伴侣关系! coupleID=%s" % coupleID, playerID)
    if coupleID:
        # 亲密度减少
        curFriends = PyDataManager.GetFriendManager().GetFriends(playerID)
        if curFriends != None:
            decIntimacyPer = IpyGameDataPY.GetFuncCfg("LoveMarryBreak", 3)
            updIntimacy = curFriends.AddIntimacyByPer(curPlayer, coupleID, -decIntimacyPer)
            GameWorld.Log("    更新自身与对方亲密度: tagPlayerID=%s,decIntimacyPer=%s,updIntimacy=%s" % (coupleID, decIntimacyPer, updIntimacy), playerID)
    # 通知地图
    dataMsg = []
    MapServer_QueryPlayer_DoLogic_Love(curPlayer, "ClearCoupleSocial", dataMsg, playerID)
    # 清社交关系 - 由地图清除后同步更新
    PlayerControl.SetCoupleID(curPlayer, 0)
    socialPlayer = PyDataManager.GetPersonalSocialManager().GetSocialPlayer(playerID)
    if socialPlayer:
        coupleName = socialPlayer.playerInfo.CoupleName
        socialPlayer.SetCoupleInfo(0, "")
        socialPlayer.CheckUpdCouplePriceMaxID(0)
    # 邮件通知离婚
    playerIDList = [playerID]
    paramList = [coupleName]
    PlayerCompensation.SendMailByKey("MarryBreakOK", playerIDList, [], paramList)
    return
def MapServer_Love(curPlayer, msgList):
    mapID = curPlayer.GetRealMapID()
    GameWorld.Log("MapServer_Love mapID=%s,msgList=%s" % (mapID, msgList), curPlayer.GetPlayerID())
    if not msgList:
        return
    msgType, dataMsg = msgList
    # 送花请求
    if msgType == "SendFlowersReq":
        ret = __CheckSendFlowers(curPlayer, dataMsg)
    # 送花OK
    elif msgType == "SendFlowersOK":
        __DoSendFlowersOK(curPlayer, dataMsg)
        return
    # 提亲
    elif msgType == "MarryReq":
        __DoMarryReq(curPlayer, dataMsg)
        return
    # 吃喜糖
    elif msgType == "MarryEatCandy":
        ret = __DoMarryEatCandy(curPlayer, dataMsg)
    # 购买喜糖烟花
    elif msgType == "MarryBuyFireworks":
        ret = __DoMarryBuyFireworks(curPlayer, dataMsg)
    # 离婚
    elif msgType == "MarryBreakReq":
        ret = __DoMarryBreakReq(curPlayer, dataMsg)
    if ret == None:
        return
    return msgList + [ret]
def __CheckSendFlowers(curPlayer, dataMsg):
    ## 在线好友可赠送
    tagPlayerID = dataMsg[0]
    playerID = curPlayer.GetPlayerID()
    curFriends = PyDataManager.GetFriendManager().GetFriends(playerID)
    if curFriends == None:
        return
    curFriend = curFriends.Find(tagPlayerID)
    if curFriend == None:
        PlayerControl.NotifyCode(curPlayer, "NotFriend")
        return
    tagPlayer = GameWorld.GetPlayerManager().FindPlayerByID(tagPlayerID)
    if not tagPlayer or PlayerControl.GetIsTJG(tagPlayer):
        PlayerControl.NotifyCode(curPlayer, "LoveOffline")
        return
    return True
def __DoSendFlowersOK(curPlayer, dataMsg):
    ## 送花OK
    playerID = curPlayer.GetPlayerID()
    playerName = curPlayer.GetName()
    tagPlayerID, flowerID, flowerCount, addCharm, addCharmTag, addIntimacy, isWorldNotify = dataMsg
    GameWorld.Log("赠送鲜花OK: tagPlayerID=%s,flowerCount=%s,addCharm=%s,addCharmTag=%s,addIntimacy=%s"
                  % (tagPlayerID, flowerCount, addCharm, addCharmTag, addIntimacy), playerID)
    curFriends = PyDataManager.GetFriendManager().GetFriends(playerID)
    if curFriends != None:
        updIntimacy = curFriends.AddIntimacy(curPlayer, tagPlayerID, addIntimacy)
        GameWorld.Log("    增加自身与对方亲密度: tagPlayerID=%s,updIntimacy=%s" % (tagPlayerID, updIntimacy), playerID)
    tagPlayer = GameWorld.GetPlayerManager().FindPlayerByID(tagPlayerID)
    if not tagPlayer or PlayerControl.GetIsTJG(tagPlayer):
        return
    tagPlayerName = tagPlayer.GetName()
    tagFriends = PyDataManager.GetFriendManager().GetFriends(tagPlayerID)
    if tagFriends != None:
        updIntimacy = tagFriends.AddIntimacy(tagPlayer, playerID, addIntimacy)
        GameWorld.Log("    增加对方与自身亲密度: tagPlayerID=%s,updIntimacy=%s" % (tagPlayerID, updIntimacy), playerID)
    if isWorldNotify:
        PlayerControl.WorldNotify(0, "SendFlowers%s" % flowerCount, [playerName, tagPlayerName, flowerCount, flowerID])
    dataMsg = [addCharmTag]
    MapServer_QueryPlayer_DoLogic_Love(tagPlayer, "AddCharm", dataMsg, playerID)
    # 通知目标前端送花成功
    clientPack = ChPyNetSendPack.tagGCSendFlowersOK()
    clientPack.PlayerID = playerID
    clientPack.Name = playerName
    clientPack.NameLen = len(clientPack.Name)
    clientPack.FlowerCount = flowerCount
    NetPackCommon.SendFakePack(tagPlayer, clientPack)
    return
def MapServer_QueryPlayer_DoLogic_Love(tagPlayer, msgType, dataMsg, playerID=0):
    ## 通知目标玩家地图执行 DoLogic
    tagPlayerID = tagPlayer.GetPlayerID()
    tagMapID = tagPlayer.GetRealMapID()
    if tagMapID:
        cmdStr = str([msgType, dataMsg])
        GameWorld.Log("MapServer_QueryPlayer_DoLogic_Love: msgType=%s,tagPlayerID=%s,tagMapID=%s,dataMsg=%s"
                      % (msgType, tagPlayerID, tagMapID, dataMsg), playerID)
        GameWorld.GetPlayerManager().MapServer_QueryPlayer(0, 0, tagPlayer.GetPlayerID(), tagMapID, "Love",
                                                           cmdStr, len(cmdStr), tagPlayer.GetRouteServerIndex())
    return
def __MarryCheckComm(curPlayer, tagPlayer, tagPlayerID, checkIntimacy):
    ## 成亲通用检查
    playerID = curPlayer.GetPlayerID()
    curFriends = PyDataManager.GetFriendManager().GetFriends(playerID)
    if curFriends == None:
        PlayerControl.NotifyCode(curPlayer, "NotFriend") # 非好友
        return
    curFriend = curFriends.Find(tagPlayerID)
    if curFriend == None:
        PlayerControl.NotifyCode(curPlayer, "NotFriend") # 非好友
        return
    if not tagPlayer or PlayerControl.GetIsTJG(tagPlayer):
        PlayerControl.NotifyCode(curPlayer, "LoveOffline") # 离线
        return
    coupleID = PlayerControl.GetCoupleID(curPlayer)
    if coupleID and coupleID != tagPlayerID:
        PlayerControl.NotifyCode(curPlayer, "TagHaveCouple") # 已经有其他伴侣了
        return
    tagCoupleID = PlayerControl.GetCoupleID(tagPlayer)
    if tagCoupleID and tagCoupleID != playerID:
        PlayerControl.NotifyCode(curPlayer, "TagHaveCouple") # 已经有其他伴侣了
        return
    # 回应方可不检查亲密度
    if checkIntimacy:
        needIntimacy = IpyGameDataPY.GetFuncCfg("LoveMarry", 2)
        if curFriend.Intimacy < needIntimacy:
            PlayerControl.NotifyCode(curPlayer, "IntimacyLack", [needIntimacy]) # 亲密度不足
            return
    return True
def __DoMarryReq(curPlayer, dataMsg):
    ## 提亲
    tagPlayerID, bridePriceID = dataMsg
    tagPlayer = GameWorld.GetPlayerManager().FindPlayerByID(tagPlayerID)
    if not __MarryCheckComm(curPlayer, tagPlayer, tagPlayerID, True):
        return
    playerID = curPlayer.GetPlayerID()
    if (playerID, tagPlayerID) in PyGameData.g_marryCandyInfo or (tagPlayerID, playerID) in PyGameData.g_marryCandyInfo:
        PlayerControl.NotifyCode(curPlayer, "MarryReqLimitByCandy") # 喜宴中无法操作
        return
    curTime = int(time.time())
    if playerID not in PyGameData.g_marryReqInfo:
        reqData = MarryReq()
        PyGameData.g_marryReqInfo[playerID] = reqData
    else:
        reqData = PyGameData.g_marryReqInfo[playerID]
    # 提前不验证,直接覆盖,放在回应中验证
    reqData.playerIDA = playerID
    reqData.playerIDB = tagPlayerID
    reqData.bridePriceID = bridePriceID
    reqData.reqTime = curTime
    # 通知自己请求成功
    NetPackCommon.SendFakePack(curPlayer, ChPyNetSendPack.tagGCMarryReqOK())
    # 通知对方
    clientPack = ChPyNetSendPack.tagGCMarryReqInfo()
    clientPack.PlayerID = playerID
    clientPack.PlayerName = curPlayer.GetName()
    clientPack.NameLen = len(clientPack.PlayerName)
    clientPack.BridePriceID = bridePriceID
    NetPackCommon.SendFakePack(tagPlayer, clientPack)
    return
def __DoMarryEatCandy(curPlayer, dataMsg):
    ## 吃喜糖
    playerIDA, playerIDB, playerID, costMoneyType, costMoneyValue, playerMoneyValue = dataMsg
    coupleIDInfo = (playerIDA, playerIDB)
    if coupleIDInfo not in PyGameData.g_marryCandyInfo:
        GameWorld.ErrLog("不存在该婚礼喜糖宴会! playerIDA=%s, playerIDB=%s" % (playerIDA, playerIDB))
        return
    candyObj = PyGameData.g_marryCandyInfo[coupleIDInfo]
    bridePriceID = candyObj.bridePriceID
    ipyData = IpyGameDataPY.GetIpyGameData("Marry", bridePriceID)
    if not ipyData:
        return
    candyItemInfo = ipyData.GetCandyItemInfo()
    playerFreeEatCount = candyObj.playerFreeEatCountDict.get(playerID, 0)
    playerFireworksCount = candyObj.fireworksCountDict.get(playerID, 0)
    candyFreeCount = IpyGameDataPY.GetFuncCfg("LoveCandy", 1) # 免费喜糖次数
    fireworksCandyCount = IpyGameDataPY.GetFuncCfg("LoveCandyFire", 3) # 购买一次烟花赠送喜糖次数
    totalFreeCount = candyFreeCount + fireworksCandyCount * playerFireworksCount
    isFree = (playerFreeEatCount < totalFreeCount)
    canBuy = isFree or (playerMoneyValue >= costMoneyValue)
    GameWorld.Log("吃喜糖: coupleIDInfo=%s,costMoneyType=%s,costMoneyValue=%s,playerMoneyValue=%s,playerFireworksCount=%s,playerFreeEatCount=%s,totalFreeCount=%s,isFree=%s,canBuy=%s"
                  % (coupleIDInfo, costMoneyType, costMoneyValue, playerMoneyValue, playerFireworksCount, playerFreeEatCount, totalFreeCount, isFree, canBuy), playerID)
    if canBuy:
        addProsperityValue = IpyGameDataPY.GetFuncCfg("LoveCandy", 3) # 喜糖每次增加繁荣度
        AddProsperity(candyObj, addProsperityValue)
        if isFree:
            candyObj.playerFreeEatCountDict[playerID] = playerFreeEatCount + 1
        Sync_CandyList(None, [candyObj])
        updProsperity = candyObj.prosperity
        updPlayerFreeEatCount = candyObj.playerFreeEatCountDict.get(playerID, 0)
        GameWorld.Log("更新喜糖宴会: updProsperity=%s,updPlayerFreeEatCount=%s" % (updProsperity, updPlayerFreeEatCount), playerID)
    return canBuy, isFree, costMoneyType, costMoneyValue, candyItemInfo
def __DoMarryBuyFireworks(curPlayer, dataMsg):
    ## 购买喜糖烟花
    playerIDA, playerIDB, playerID, costMoneyType, costMoneyValue, playerMoneyValue = dataMsg
    coupleIDInfo = (playerIDA, playerIDB)
    if coupleIDInfo not in PyGameData.g_marryCandyInfo:
        GameWorld.ErrLog("不存在该婚礼喜糖宴会烟花! playerIDA=%s, playerIDB=%s" % (playerIDA, playerIDB))
        return
    candyObj = PyGameData.g_marryCandyInfo[coupleIDInfo]
    fireworksTotalBuyCount = sum(candyObj.fireworksCountDict.values())
    totalBuyCountLimit = IpyGameDataPY.GetFuncCfg("LoveCandyFire", 1)
    if fireworksTotalBuyCount >= totalBuyCountLimit:
        PlayerControl.NotifyCode(curPlayer, "MarryFireworksSoldout")
        return
    addProsperityValue = IpyGameDataPY.GetFuncCfg("LoveCandyFire", 4) # 烟花喜糖赠送繁荣度
    GameWorld.Log("购买婚礼烟花: coupleIDInfo=%s,costMoneyType=%s,costMoneyValue=%s,playerMoneyValue=%s,fireworksCountDict=%s"
                  % (coupleIDInfo, costMoneyType, costMoneyValue, playerMoneyValue, candyObj.fireworksCountDict), playerID)
    AddProsperity(candyObj, addProsperityValue)
    candyObj.fireworksCountDict[playerID] = candyObj.fireworksCountDict.get(playerID, 0) + 1
    Sync_CandyList(None, [candyObj])
    GameWorld.Log("更新婚礼烟花: updProsperity=%s,fireworksCountDict=%s" % (candyObj.prosperity, candyObj.fireworksCountDict), playerID)
    return costMoneyType, costMoneyValue
def __DoMarryBreakReq(curPlayer, dataMsg):
    ## 离婚请求
    playerID, coupleID, breakType, moneyType, moneyValue = dataMsg
    gameServerCoupleID = PlayerControl.GetCoupleID(curPlayer)
    socialPlayer = PyDataManager.GetPersonalSocialManager().GetSocialPlayer(playerID)
    socialCoupleID = 0 if not socialPlayer else socialPlayer.GetCoupleID()
    if not gameServerCoupleID or coupleID != gameServerCoupleID or not socialCoupleID or coupleID != socialCoupleID:
        GameWorld.ErrLog("地图玩家伴侣数据与GameServer不一致,离婚请求时直接通过! gameServerCoupleID=%s,socialCoupleID=%s,mapCoupleID=%s"
                         % (gameServerCoupleID, socialCoupleID, coupleID), playerID)
        __ClearCoupleSocial(curPlayer)
        PlayerSocial.SendMapServerCoupleInfo([playerID])
        return
    if (playerID, coupleID) in PyGameData.g_marryCandyInfo or (coupleID, playerID) in PyGameData.g_marryCandyInfo:
        PlayerControl.NotifyCode(curPlayer, "MarryReqLimitByCandy") # 喜宴中无法操作
        return
    # 0-和平离婚;1-强制离婚
    if breakType == 0:
        tagPlayer = GameWorld.GetPlayerManager().FindPlayerByID(coupleID)
        if not tagPlayer or PlayerControl.GetIsTJG(tagPlayer):
            PlayerControl.NotifyCode(curPlayer, "LoveOffline") # 离线
            return
        clientPack = ChPyNetSendPack.tagGCMarryBreakInfo()
        clientPack.PlayerID = playerID
        clientPack.PlayerName = curPlayer.GetName()
        clientPack.NameLen = len(clientPack.PlayerName)
        NetPackCommon.SendFakePack(tagPlayer, clientPack)
        PyGameData.g_marryBreakReqInfo[playerID] = coupleID
        return
    GameWorld.Log("强制离婚: coupleID=%s" % coupleID, playerID)
    __DoMarryBreak(curPlayer, coupleID)
    return moneyType, moneyValue
def Sync_CandyList(curPlayer, syncCandyList=None):
    if syncCandyList == None:
        syncCandyList = PyGameData.g_marryCandySortList
    if not syncCandyList:
        return
    clientPack = ChPyNetSendPack.tagGCCandyList()
    clientPack.CandyInfoList = []
    for candyObj in PyGameData.g_marryCandySortList:
        candyInfo = ChPyNetSendPack.tagGCCandyInfo()
        candyInfo.PlayerIDA = candyObj.playerIDA
        candyInfo.PlayerNameA = candyObj.playerNameA
        candyInfo.NameALen = len(candyInfo.PlayerNameA)
        candyInfo.PlayerIDB = candyObj.playerIDB
        candyInfo.PlayerNameB = candyObj.playerNameB
        candyInfo.NameBLen = len(candyInfo.PlayerNameB)
        candyInfo.BridePriceID = candyObj.bridePriceID
        candyInfo.MarryTime = candyObj.marryTime
        candyInfo.EndTime = candyObj.endTime
        candyInfo.Prosperity = candyObj.prosperity
        candyInfo.FireworksTotalBuyCount = sum(candyObj.fireworksCountDict.values())
        if curPlayer:
            candyInfo.FireworksPlayerBuyCount = candyObj.fireworksCountDict.get(curPlayer.GetPlayerID(), 0)
            candyInfo.PlayerFreeEatCandyCount = candyObj.playerFreeEatCountDict.get(curPlayer.GetPlayerID(), 0)
        clientPack.CandyInfoList.append(candyInfo)
    clientPack.CandyCount = len(clientPack.CandyInfoList)
    if not curPlayer:
        playerManager = GameWorld.GetPlayerManager()
        for i in xrange(playerManager.GetActivePlayerCount()):
            curPlayer = playerManager.GetActivePlayerAt(i)
            if curPlayer == None:
                continue
            if PlayerControl.GetIsTJG(curPlayer):
                continue
            for candyInfo in clientPack.CandyInfoList:
                candyInfo.FireworksPlayerBuyCount = candyObj.fireworksCountDict.get(curPlayer.GetPlayerID(), 0)
                candyInfo.PlayerFreeEatCandyCount = candyObj.playerFreeEatCountDict.get(curPlayer.GetPlayerID(), 0)
            NetPackCommon.SendFakePack(curPlayer, clientPack)
    else:
        if PlayerControl.GetIsTJG(curPlayer):
            return
        NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerSocial.py
@@ -26,6 +26,7 @@
import IpyGameDataPY
import PlayerViewCache
import PyGameData
import ShareDefine
#--------------------社交圈基本结构-------------------
# 社交圈
class SocialPlayers(object):
@@ -123,20 +124,26 @@
    
    # 上线通知 
    def Sync_SocialsInfo(self, curPlayer):
    def Sync_SocialsInfo(self, curPlayer, playerIDList=None):
        if playerIDList == None:
            playerIDList = self.SocialDict.keys()
        pack = ChPyNetSendPack.tagGCGroupPlayers()
        pack.Clear()
        pack.GroupType = self.GroupType
        pack.Players = []
        pack.Count = self.GetCount()
        
        for player in self.SocialDict.values():
        for playerID in playerIDList:
            if playerID not in self.SocialDict:
                continue
            player = self.SocialDict[playerID]
            inPack = ChPyNetSendPack.tagGCGroupPlayer()
            inPack.PlayerID = player.TagID
            
            inPack.SortValue = player.Timestamp if hasattr(player, 'Timestamp') else 0
            inPack.Intimacy = player.Intimacy if hasattr(player, 'Intimacy') else 0
            pack.Players.append(inPack)
            
        pack.Count = len(pack.Players)
        NetPackCommon.SendFakePack(curPlayer, pack)
        return
@@ -190,6 +197,46 @@
        curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(self.PlayerID)
        self.MapServer_SyncFriendInfo(curPlayer)
    
    def AddIntimacy(self, curPlayer, friendID, addValue):
        ## 增加亲密度 - 支持正负
        if friendID not in self.SocialDict:
            return 0
        friendObj = self.SocialDict[friendID]
        friendObj.Intimacy += addValue
        friendObj.Intimacy = max(0, min(friendObj.Intimacy, ShareDefine.Def_UpperLimit_DWord))
        if not curPlayer:
            return friendObj.Intimacy
        friendName = ""
        socialPlayer = PyDataManager.GetPersonalSocialManager().GetSocialPlayer(friendID)
        if socialPlayer:
            friendName = socialPlayer.playerInfo.PlayerName
        if addValue > 0:
            PlayerControl.NotifyCode(curPlayer, "AddIntimacy", [friendName, addValue])
        self.Sync_SocialsInfo(curPlayer, [friendID])
        return friendObj.Intimacy
    def AddIntimacyByPer(self, curPlayer, friendID, addPer):
        ## 增加亲密度 - 根据百分比,支持正负
        if friendID not in self.SocialDict:
            return 0
        friendObj = self.SocialDict[friendID]
        addValue = int(friendObj.Intimacy * addPer / 100.0)
        return self.AddIntimacy(curPlayer, friendID, addValue)
    def SetIntimacy(self, curPlayer, friendID, setValue):
        ## 直接设置亲密度 - 一般GM测试使用
        if friendID not in self.SocialDict:
            return
        friendObj = self.SocialDict[friendID]
        friendObj.Intimacy = setValue
        if curPlayer:
            self.Sync_SocialsInfo(curPlayer, [friendID])
        return friendObj.Intimacy
    
    # 通知地图好友信息
    def MapServer_SyncFriendInfo(self, curPlayer):
@@ -649,6 +696,7 @@
class SocialPlayerData(object):
    def __init__(self, playerSocial = None, player = None):
        self.playerInfo = PyGameDataStruct.tagPersonalSocial()
        self.syncMapCouple = 0 # 是否已经同步过地图全局伴侣信息
        
        if playerSocial:
            self.playerInfo = playerSocial
@@ -664,6 +712,7 @@
        self.playerInfo.LV = curPlayer.GetLV()
        self.playerInfo.RealmLV = curPlayer.GetOfficialRank()
        self.playerInfo.OnlineType = 1      # 0 不在线  1 在线 2 脱机在线  
        self.playerInfo.CoupleID = PlayerControl.GetCoupleID(curPlayer)
        if not self.playerInfo.RefCount:
            self.playerInfo.RefCount = 1
        return
@@ -676,8 +725,38 @@
        packStruct.LV = self.playerInfo.LV
        packStruct.RealmLV = self.playerInfo.RealmLV
        packStruct.OnlineType = self.playerInfo.OnlineType
        packStruct.CoupleID = self.GetCoupleID()
        return packStruct
    
    def GetCoupleID(self): return 0 if self.GetCoupleBreakOffline() else self.playerInfo.CoupleID
    def GetCoupleName(self): return "" if not self.GetCoupleID() else self.playerInfo.CoupleName
    def SetCoupleInfo(self, coupleID, coupleName):
        self.playerInfo.CoupleBreakOffline = 0
        self.playerInfo.CoupleID = coupleID
        self.playerInfo.CoupleName = coupleName
        Notify_All(self.playerInfo.PlayerID, IPY_PlayerDefine.CDBPlayerRefresh_ExAttr11, coupleID)
        return
    def GetBridePriceMaxID(self): return self.playerInfo.CouplePriceMaxID
    def CheckUpdCouplePriceMaxID(self, bridePriceID):
        if bridePriceID > 0 and bridePriceID <= self.playerInfo.CouplePriceMaxID:
            GameWorld.Log("不更新社交最高聘礼ID: bridePriceID=%s,self.playerInfo.CouplePriceMaxID=%s"
                          % (bridePriceID, self.playerInfo.CouplePriceMaxID), self.playerInfo.PlayerID)
            return
        self.playerInfo.CouplePriceMaxID = bridePriceID
        GameWorld.Log("更新社交最高聘礼ID: bridePriceID=%s" % (bridePriceID), self.playerInfo.PlayerID)
        return
    def GetCoupleBreakOffline(self):
        ## 是否离线状态下被离婚,等待下次上线处理
        return self.playerInfo.CoupleBreakOffline == 1
    def SetCoupleBreakOffline(self):
        ## 设置离线状态下被离婚,是的话将在玩家下次上线后处理解除相关伴侣关系,因为离线状态下无法处理,故做个标记等待上线处理
        self.playerInfo.CoupleBreakOffline = 1
        GameWorld.Log("离线状态下被离婚,标记伴侣社交关系已离婚!等下次上线处理! coupleID=%s" % self.playerInfo.CoupleID, self.playerInfo.PlayerID)
        return
    
    # 更新玩家数据引用, 根据需求是否更新玩家数据
    def AddSocialRef(self, curPlayer = None):
@@ -724,6 +803,7 @@
            playerSocial.LV = 1
            playerSocial.RealmLV = 1
            playerSocial.OnlineType = ChConfig.Def_Offline
            playerSocial.CoupleID = 0
        else:
            cacheDict = PlayerViewCache.GetCachePropDataDict(curCache)
    
@@ -734,6 +814,7 @@
            playerSocial.LV = cacheDict["LV"]
            playerSocial.RealmLV = cacheDict["RealmLV"]
            playerSocial.OnlineType = ChConfig.Def_Offline
            playerSocial.CoupleID = cacheDict.get("CoupleID", 0)
            
        self.SocialInfo[playerID] = SocialPlayerData(playerSocial)
        socialPlayer = self.SocialInfo[playerID]
@@ -816,8 +897,8 @@
#更新玩家社交信息
def UpdateSocialInfo(curPlayer, notifyType, value):
    socialPlayer = PyDataManager.GetPersonalSocialManager().GetSocialPlayer(curPlayer.GetID())
def UpdateSocialInfo(playerID, notifyType, value):
    socialPlayer = PyDataManager.GetPersonalSocialManager().GetSocialPlayer(playerID)
    if socialPlayer == None:
        return
    
@@ -827,10 +908,40 @@
        socialPlayer.playerInfo.RealmLV = value
    elif notifyType == IPY_PlayerDefine.CDBPlayerRefresh_PlayerName:
        socialPlayer.playerInfo.PlayerName = value
        coupleID = socialPlayer.playerInfo.CoupleID
        if coupleID:
            coupleSocialPlayer = PyDataManager.GetPersonalSocialManager().GetSocialPlayer(coupleID)
            if coupleSocialPlayer:
                coupleSocialPlayer.playerInfo.CoupleName = value
                SendMapServerCoupleInfo([coupleID])
        
    Notify_All(curPlayer.GetID(), notifyType, value)
    Notify_All(playerID, notifyType, value)
    return
def SendMapServerCoupleInfo(syncPlayerIDList=None):
    checkState = False
    syncCoupleInfo = {}
    socialMgr = PyDataManager.GetPersonalSocialManager()
    if syncPlayerIDList == None:
        syncPlayerIDList = socialMgr.SocialInfo.keys()
        checkState = True # 未指定时才检查,防止启动地图时同步过多(启动地图时,只同步本次已经同步过的)
    for playerID in syncPlayerIDList:
        socialPlayer = socialMgr.GetSocialPlayer(playerID)
        if not socialPlayer:
            continue
        coupleID = socialPlayer.GetCoupleID()
        if checkState:
            if not socialPlayer.syncMapCouple:
                continue
            if not coupleID:
                continue
        socialPlayer.syncMapCouple = 1
        coupleName = socialPlayer.GetCoupleName()
        syncCoupleInfo[playerID] = [coupleID, coupleName] if coupleID else []
    GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_CoupleInfo, syncCoupleInfo)
    return
# 向当前玩家通知相关联的所有玩家信息
def Sync_AllSocialsInfo(curPlayer):
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerTalk.py
@@ -437,6 +437,7 @@
    vipLv = player.GetVIPLv()  # 玩家vip等级
    GMLevel = player.GetGMLevel()
    job = player.GetJob()
    playerID = player.GetID()
    extraValueStr = ""
    # vip等级
@@ -451,6 +452,13 @@
    extraValueStr += GetTalkExtraValueStar(ShareDefine.Def_TalkExtraValue_Bit_ServerGroupID) % PlayerControl.GetPlayerServerGroupID(player)
    # 等级
    extraValueStr += GetTalkExtraValueStar(ShareDefine.Def_TalkExtraValue_Bit_LV) % player.GetLV()
    # 伴侣信息
    coupleName, bridePriceMaxID = "", 0
    socialPlayer = PyDataManager.GetPersonalSocialManager().GetSocialPlayer(playerID)
    if socialPlayer and socialPlayer.GetCoupleID():
        coupleName = socialPlayer.GetCoupleName()
        bridePriceMaxID = socialPlayer.GetBridePriceMaxID()
    extraValueStr = "%s|%s|%s" % (extraValueStr, coupleName, bridePriceMaxID)
    return extraValueStr
ServerPython/CoreServerGroup/GameServer/Script/Player/UpdatePlayerName.py
@@ -156,7 +156,6 @@
    #改名成功
    UpdatePlayerNameResult(curPlayer, ShareDefine.Def_Rename_Result_Succeed)
    
    PlayerSocial.UpdateSocialInfo(curPlayer, IPY_GameServer.CDBPlayerRefresh_PlayerName, newName)
    #流向记录
    DataRecordPack.DR_UpdatePlayerName(curPlayer, oldPlayerName)
    
@@ -230,6 +229,8 @@
        #修改家族信息
        RedressFamily(curPlayer)
        
        #纠正社交中玩家名字
        PlayerSocial.UpdateSocialInfo(curPlayer.GetID(), IPY_GameServer.CDBPlayerRefresh_PlayerName, curPlayer.GetName())
        
    #删除通用表记录的改名信息
    #@warning: 必须在纠正排行后, 因为纠正宠物排行榜有用到玩家改名前的旧名字
ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py
@@ -87,6 +87,11 @@
g_fbHelpBattleCheckInPlayerDict = {} # 副本助战玩家登记缓存 {playerID:HelpBattlePlayer, ...}
g_marryReqInfo = {} # 当前进行中的求亲信息 {请求玩家ID:MarryReq, ...}
g_marryCandyInfo = {} # 进行中的喜糖信息 {(playerIDA, playerIDB):MarryCandy, ...}
g_marryCandySortList = [] # 按结算时间排序后的喜糖列表
g_marryBreakReqInfo = {} # 请求离婚信息 {reqPlayerID:tagPlayerID, ...}
g_arenaPlayerBattleRecDict = {} # 本服竞技场玩家挑战记录缓存 {playerID:[ArenaBattleRec, ...], ...}
g_arenaPlayerMatchDict = {} # 本服竞技场玩家匹配记录缓存 {playerID:[ArenaMatchPlayer, ...], ...}
g_arenaRobotLVList = [] # 本服竞技场机器人等级列表
ServerPython/CoreServerGroup/GameServer/Script/PyGameDataStruct.py
@@ -2121,6 +2121,7 @@
    _fields_ = [
        ('PlayerID', ctypes.c_ulong),
        ('TagID', ctypes.c_ulong),
        ('Intimacy', ctypes.c_ulong),
        ('ADOResult', ctypes.c_ulong),
    ]
@@ -2140,6 +2141,7 @@
        self.clear()
        self.PlayerID, pos = CommFunc.ReadDWORD(buf, pos)
        self.TagID, pos = CommFunc.ReadDWORD(buf, pos)
        self.Intimacy, pos = CommFunc.ReadDWORD(buf, pos)
        return self.getLength()
@@ -2155,10 +2157,12 @@
        output = '''//玩家好友表#tagDBPyPlayerFriend:
            PlayerID = %s,
            TagID = %s,
            Intimacy = %s,
            ADOResult = %s,
            '''%(
                self.PlayerID,
                self.TagID,
                self.Intimacy,
                self.ADOResult,
            )
        return output
@@ -2228,6 +2232,10 @@
        ('RealmLV', ctypes.c_ushort),
        ('OnlineType', ctypes.c_ubyte),
        ('RefCount', ctypes.c_ulong),
        ('CoupleID', ctypes.c_ulong),
        ('CoupleName', ctypes.c_char * 33),
        ('CouplePriceMaxID', ctypes.c_ubyte),
        ('CoupleBreakOffline', ctypes.c_ubyte),
        ('ADOResult', ctypes.c_ulong),
    ]
@@ -2252,6 +2260,10 @@
        self.RealmLV, pos = CommFunc.ReadWORD(buf, pos)
        self.OnlineType, pos = CommFunc.ReadBYTE(buf, pos)
        self.RefCount, pos = CommFunc.ReadDWORD(buf, pos)
        self.CoupleID, pos = CommFunc.ReadDWORD(buf, pos)
        self.CoupleName, pos = CommFunc.ReadString(buf, pos, 33)
        self.CouplePriceMaxID, pos = CommFunc.ReadBYTE(buf, pos)
        self.CoupleBreakOffline, pos = CommFunc.ReadBYTE(buf, pos)
        return self.getLength()
@@ -2272,6 +2284,10 @@
            RealmLV = %s,
            OnlineType = %s,
            RefCount = %s,
            CoupleID = %s,
            CoupleName = %s,
            CouplePriceMaxID = %s,
            CoupleBreakOffline = %s,
            ADOResult = %s,
            '''%(
                self.PlayerID,
@@ -2281,6 +2297,10 @@
                self.RealmLV,
                self.OnlineType,
                self.RefCount,
                self.CoupleID,
                self.CoupleName,
                self.CouplePriceMaxID,
                self.CoupleBreakOffline,
                self.ADOResult,
            )
        return output
@@ -2292,4 +2312,10 @@
        else:
            self.PlayerName = Str[:33]
            
    def SetCoupleName(self,Str):
        if len(Str)<=33:
            self.CoupleName = Str
        else:
            self.CoupleName = Str[:33]
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
@@ -1605,6 +1605,42 @@
PacketSubCMD_2=0x12
PacketCallFunc_2=OnGetFuncSysPrivilegeAward
;情缘
[PlayerLove]
ScriptName = Player\PlayerLove.py
Writer = hxp
Releaser = hxp
RegType = 0
RegisterPackCount = 7
PacketCMD_1=0xB3
PacketSubCMD_1=0x10
PacketCallFunc_1=OnSendFlowers
PacketCMD_2=0xB3
PacketSubCMD_2=0x11
PacketCallFunc_2=OnMarryReq
PacketCMD_3=0xB3
PacketSubCMD_3=0x13
PacketCallFunc_3=OnMarryEatCandy
PacketCMD_4=0xB3
PacketSubCMD_4=0x14
PacketCallFunc_4=OnMarryBuyFireworks
PacketCMD_5=0xB3
PacketSubCMD_5=0x15
PacketCallFunc_5=OnMarryBreak
PacketCMD_6=0xB3
PacketSubCMD_6=0x17
PacketCallFunc_6=OnLoveRingUnlock
PacketCMD_7=0xB3
PacketSubCMD_7=0x18
PacketCallFunc_7=OnLoveRingUp
;缥缈仙域
[PlayerFairyDomain]
ScriptName = Player\PlayerFairyDomain.py
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
@@ -2330,6 +2330,114 @@
#------------------------------------------------------
# B3 16 和平离婚回应 #tagGCMarryBreakResponse
class  tagGCMarryBreakResponse(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("IsOK", c_ubyte),    # 是否同意,0-否,1-是
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xB3
        self.SubCmd = 0x16
        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 = 0xB3
        self.SubCmd = 0x16
        self.IsOK = 0
        return
    def GetLength(self):
        return sizeof(tagGCMarryBreakResponse)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B3 16 和平离婚回应 //tagGCMarryBreakResponse:
                                Cmd:%s,
                                SubCmd:%s,
                                IsOK:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.IsOK
                                )
        return DumpString
m_NAtagGCMarryBreakResponse=tagGCMarryBreakResponse()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCMarryBreakResponse.Cmd,m_NAtagGCMarryBreakResponse.SubCmd))] = m_NAtagGCMarryBreakResponse
#------------------------------------------------------
# B3 12 提亲回应 #tagCGMarryResponse
class  tagCGMarryResponse(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("ReqPlayerID", c_int),    # 提亲的玩家ID
                  ("IsOK", c_ubyte),    # 是否同意,0-否,1-是
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xB3
        self.SubCmd = 0x12
        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 = 0xB3
        self.SubCmd = 0x12
        self.ReqPlayerID = 0
        self.IsOK = 0
        return
    def GetLength(self):
        return sizeof(tagCGMarryResponse)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B3 12 提亲回应 //tagCGMarryResponse:
                                Cmd:%s,
                                SubCmd:%s,
                                ReqPlayerID:%d,
                                IsOK:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.ReqPlayerID,
                                self.IsOK
                                )
        return DumpString
m_NAtagCGMarryResponse=tagCGMarryResponse()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCGMarryResponse.Cmd,m_NAtagCGMarryResponse.SubCmd))] = m_NAtagCGMarryResponse
#------------------------------------------------------
#B3 04 加入黑名单 #tagCGAddBlackList
class  tagCGAddBlackList(Structure):
@@ -3991,6 +4099,382 @@
#------------------------------------------------------
# B3 17 情戒解锁 #tagCMLoveRingUnlock
class  tagCMLoveRingUnlock(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xB3
        self.SubCmd = 0x17
        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 = 0xB3
        self.SubCmd = 0x17
        return
    def GetLength(self):
        return sizeof(tagCMLoveRingUnlock)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B3 17 情戒解锁 //tagCMLoveRingUnlock:
                                Cmd:%s,
                                SubCmd:%s
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd
                                )
        return DumpString
m_NAtagCMLoveRingUnlock=tagCMLoveRingUnlock()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMLoveRingUnlock.Cmd,m_NAtagCMLoveRingUnlock.SubCmd))] = m_NAtagCMLoveRingUnlock
#------------------------------------------------------
# B3 18 情戒升级 #tagCMLoveRingUp
class  tagCMLoveRingUp(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("UseItemCnt", c_int),    #消耗材料个数
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xB3
        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 = 0xB3
        self.SubCmd = 0x18
        self.UseItemCnt = 0
        return
    def GetLength(self):
        return sizeof(tagCMLoveRingUp)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B3 18 情戒升级 //tagCMLoveRingUp:
                                Cmd:%s,
                                SubCmd:%s,
                                UseItemCnt:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.UseItemCnt
                                )
        return DumpString
m_NAtagCMLoveRingUp=tagCMLoveRingUp()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMLoveRingUp.Cmd,m_NAtagCMLoveRingUp.SubCmd))] = m_NAtagCMLoveRingUp
#------------------------------------------------------
# B3 15 离婚 #tagCMMarryBreak
class  tagCMMarryBreak(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("BreakType", c_ubyte),    # 0-和平离婚;1-强制离婚
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xB3
        self.SubCmd = 0x15
        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 = 0xB3
        self.SubCmd = 0x15
        self.BreakType = 0
        return
    def GetLength(self):
        return sizeof(tagCMMarryBreak)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B3 15 离婚 //tagCMMarryBreak:
                                Cmd:%s,
                                SubCmd:%s,
                                BreakType:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.BreakType
                                )
        return DumpString
m_NAtagCMMarryBreak=tagCMMarryBreak()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMMarryBreak.Cmd,m_NAtagCMMarryBreak.SubCmd))] = m_NAtagCMMarryBreak
#------------------------------------------------------
# B3 14 购买婚礼烟花 #tagCMMarryBuyFireworks
class  tagCMMarryBuyFireworks(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("PlayerIDA", c_int),    # 喜糖所属玩家IDA
                  ("PlayerIDB", c_int),    # 喜糖所属玩家IDB
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xB3
        self.SubCmd = 0x14
        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 = 0xB3
        self.SubCmd = 0x14
        self.PlayerIDA = 0
        self.PlayerIDB = 0
        return
    def GetLength(self):
        return sizeof(tagCMMarryBuyFireworks)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B3 14 购买婚礼烟花 //tagCMMarryBuyFireworks:
                                Cmd:%s,
                                SubCmd:%s,
                                PlayerIDA:%d,
                                PlayerIDB:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.PlayerIDA,
                                self.PlayerIDB
                                )
        return DumpString
m_NAtagCMMarryBuyFireworks=tagCMMarryBuyFireworks()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMMarryBuyFireworks.Cmd,m_NAtagCMMarryBuyFireworks.SubCmd))] = m_NAtagCMMarryBuyFireworks
#------------------------------------------------------
# B3 13 吃喜糖 #tagCMMarryEatCandy
class  tagCMMarryEatCandy(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("PlayerIDA", c_int),    # 喜糖所属玩家IDA
                  ("PlayerIDB", c_int),    # 喜糖所属玩家IDB
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xB3
        self.SubCmd = 0x13
        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 = 0xB3
        self.SubCmd = 0x13
        self.PlayerIDA = 0
        self.PlayerIDB = 0
        return
    def GetLength(self):
        return sizeof(tagCMMarryEatCandy)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B3 13 吃喜糖 //tagCMMarryEatCandy:
                                Cmd:%s,
                                SubCmd:%s,
                                PlayerIDA:%d,
                                PlayerIDB:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.PlayerIDA,
                                self.PlayerIDB
                                )
        return DumpString
m_NAtagCMMarryEatCandy=tagCMMarryEatCandy()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMMarryEatCandy.Cmd,m_NAtagCMMarryEatCandy.SubCmd))] = m_NAtagCMMarryEatCandy
#------------------------------------------------------
# B3 11 提亲 #tagCMMarryReq
class  tagCMMarryReq(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("TagPlayerID", c_int),    # 目标玩家ID
                  ("BridePriceID", c_ubyte),    # 聘礼ID
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xB3
        self.SubCmd = 0x11
        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 = 0xB3
        self.SubCmd = 0x11
        self.TagPlayerID = 0
        self.BridePriceID = 0
        return
    def GetLength(self):
        return sizeof(tagCMMarryReq)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B3 11 提亲 //tagCMMarryReq:
                                Cmd:%s,
                                SubCmd:%s,
                                TagPlayerID:%d,
                                BridePriceID:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.TagPlayerID,
                                self.BridePriceID
                                )
        return DumpString
m_NAtagCMMarryReq=tagCMMarryReq()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMMarryReq.Cmd,m_NAtagCMMarryReq.SubCmd))] = m_NAtagCMMarryReq
#------------------------------------------------------
# B3 10 送花 #tagCMSendFlowers
class  tagCMSendFlowers(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("TagPlayerID", c_int),    # 目标玩家ID
                  ("FlowerCount", c_int),    # 赠送花数量
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xB3
        self.SubCmd = 0x10
        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 = 0xB3
        self.SubCmd = 0x10
        self.TagPlayerID = 0
        self.FlowerCount = 0
        return
    def GetLength(self):
        return sizeof(tagCMSendFlowers)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B3 10 送花 //tagCMSendFlowers:
                                Cmd:%s,
                                SubCmd:%s,
                                TagPlayerID:%d,
                                FlowerCount:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.TagPlayerID,
                                self.FlowerCount
                                )
        return DumpString
m_NAtagCMSendFlowers=tagCMSendFlowers()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMSendFlowers.Cmd,m_NAtagCMSendFlowers.SubCmd))] = m_NAtagCMSendFlowers
#------------------------------------------------------
# A1 01 玩家电脑信息 #tagCMPCInfo
class  tagCMPCInfo(Structure):
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Love.py
New file
@@ -0,0 +1,100 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package GM.Commands.Love
#
# @todo:情缘
# @author hxp
# @date 2021-11-09
# @version 1.0
#
# 详细描述: 情缘
#
#-------------------------------------------------------------------------------
#"""Version = 2021-11-09 20:00"""
#-------------------------------------------------------------------------------
import GameWorld
import PlayerControl
import PlayerBillboard
import ShareDefine
import PlayerLove
import ChConfig
## GM命令执行入口
#  @param curPlayer 当前玩家
#  @param msgList 参数列表 [addSkillID]
#  @return None
#  @remarks 函数详细说明.
def OnExec(curPlayer, msgList):
    if not msgList:
        GameWorld.DebugAnswer(curPlayer, "重置所有: Love 0")
        GameWorld.DebugAnswer(curPlayer, "重置聘礼: Love 0 1")
        GameWorld.DebugAnswer(curPlayer, "设置情戒: Love 1 阶  [可选星  已吃个数]")
        GameWorld.DebugAnswer(curPlayer, "设置魅力: Love 2 魅力值 [可选今日魅力值]")
        return
    isSendGameServer = False
    value1 = msgList[0]
    if value1 == 0:
        # 重置所有
        if len(msgList) == 1:
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveBridePriceState, 0)
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveBridePriceMaxID, 0)
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveRingClassLV, 0)
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveRingStarLV, 0)
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveRingEatCount, 0)
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveCharmTotal, 0)
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveCharmToday, 0)
            PlayerBillboard.UpdatePlayerBillboard(curPlayer, ShareDefine.Def_BT_Charm, 0)
            PlayerBillboard.UpdatePlayerBillboard(curPlayer, ShareDefine.Def_BT_CharmDay, 0)
            PlayerLove.Sync_CharmInfo(curPlayer)
            PlayerLove.Sync_CoupleInfo(curPlayer)
            PlayerLove.Sync_LoveRingInfo(curPlayer)
            PlayerLove.RefreshLoveAttr(curPlayer)
            GameWorld.DebugAnswer(curPlayer, "重置聘礼、情戒、魅力OK!")
        # 重置聘礼
        elif len(msgList) == 2 and msgList[1] == 1:
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveBridePriceState, 0)
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveBridePriceMaxID, 0)
            PlayerLove.Sync_CoupleInfo(curPlayer)
            GameWorld.DebugAnswer(curPlayer, "重置聘礼OK!")
        return
    # 设置情戒
    elif value1 == 1:
        classLV = msgList[1] if len(msgList) > 1 else 1
        starLV = msgList[2] if len(msgList) > 2 else 1
        eatCount = msgList[3] if len(msgList) > 3 else 0
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveRingClassLV, classLV)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveRingStarLV, starLV)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveRingEatCount, eatCount)
        PlayerLove.Sync_LoveRingInfo(curPlayer)
        PlayerLove.RefreshLoveAttr(curPlayer)
        GameWorld.DebugAnswer(curPlayer, "设置情戒: 阶:%s 星:%s 颗:%s" % (classLV, starLV, eatCount))
        return
    # 设置魅力
    elif value1 == 2:
        charmTotal = msgList[1] if len(msgList) > 1 else 1
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveCharmTotal, charmTotal)
        PlayerBillboard.UpdatePlayerBillboard(curPlayer, ShareDefine.Def_BT_Charm, charmTotal)
        GameWorld.DebugAnswer(curPlayer, "设置总魅力: %s" % charmTotal)
        if len(msgList) > 2:
            charmToday = msgList[2] if len(msgList) > 2 else 0
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveCharmToday, charmToday)
            PlayerBillboard.UpdatePlayerBillboard(curPlayer, ShareDefine.Def_BT_CharmDay, charmToday)
            GameWorld.DebugAnswer(curPlayer, "设置今日魅力: %s" % charmToday)
        PlayerLove.Sync_CharmInfo(curPlayer)
        return
    return isSendGameServer
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/PrintFightPower.py
@@ -53,6 +53,7 @@
                   ShareDefine.Def_MFPType_FaQi:"法器",
                   ShareDefine.Def_MFPType_Dogz:"神兽",
                   ShareDefine.Def_MFPType_Coat:"ʱװ",
                   ShareDefine.Def_MFPType_Love:"情缘",
                   ShareDefine.Def_MFPType_Other:"其他",
                   }
    
@@ -100,6 +101,8 @@
                     ChConfig.Def_CalcAttrFunc_PeerlessWeaponTrain:"灭世培养",
                     ChConfig.Def_CalcAttrFunc_PeerlessWeapon2Train:"噬魂培养",
                     ChConfig.Def_CalcAttrFunc_FaQi:"法器",
                     ChConfig.Def_CalcAttrFunc_LoveRing:"情戒基础",
                     ChConfig.Def_CalcAttrFunc_LoveRingCouple:"情戒仙侣",
                     }
    
    GameWorld.DebugAnswer(curPlayer, "PrintFightPower 模块类型(可选)")
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
@@ -1876,6 +1876,26 @@
                        ("BYTE", "QualityLV", 1),
                        ),
                "Marry":(
                        ("BYTE", "BridePriceID", 1),
                        ("list", "CostMoneyInfo", 0),
                        ("BYTE", "CanBuyCount", 0),
                        ("BYTE", "IsDayReset", 0),
                        ),
                "LoveRing":(
                        ("BYTE", "RingClassLV", 1),
                        ("BYTE", "RingStarLV", 1),
                        ("list", "CoupleAttrType", 0),
                        ("list", "CoupleAttrValue", 0),
                        ("list", "StarAttrType", 0),
                        ("list", "StarAttrValue", 0),
                        ("list", "UpItemAttrType", 0),
                        ("list", "UpItemAttrValue", 0),
                        ("DWORD", "NeedEatCount", 0),
                        ("DWORD", "UpEatItemPerCount", 0),
                        ),
                "HorsePetSkin":(
                        ("BYTE", "Type", 1),
                        ("DWORD", "ID", 1),
@@ -5782,6 +5802,48 @@
    def GetPointID(self): return self.PointID # 灵根ID
    def GetQualityLV(self): return self.QualityLV # 品级
# 情缘提亲表
class IPY_Marry():
    def __init__(self):
        self.BridePriceID = 0
        self.CostMoneyInfo = []
        self.CanBuyCount = 0
        self.IsDayReset = 0
        return
    def GetBridePriceID(self): return self.BridePriceID # 聘礼ID
    def GetCostMoneyInfo(self): return self.CostMoneyInfo # 消耗货币类型|数值
    def GetCanBuyCount(self): return self.CanBuyCount # 可购买次数
    def GetIsDayReset(self): return self.IsDayReset # 是否每日重置
# 情缘情戒表
class IPY_LoveRing():
    def __init__(self):
        self.RingClassLV = 0
        self.RingStarLV = 0
        self.CoupleAttrType = []
        self.CoupleAttrValue = []
        self.StarAttrType = []
        self.StarAttrValue = []
        self.UpItemAttrType = []
        self.UpItemAttrValue = []
        self.NeedEatCount = 0
        self.UpEatItemPerCount = 0
        return
    def GetRingClassLV(self): return self.RingClassLV # 情戒阶级
    def GetRingStarLV(self): return self.RingStarLV # 情戒星级
    def GetCoupleAttrType(self): return self.CoupleAttrType # 仙侣属性类型(非累积)
    def GetCoupleAttrValue(self): return self.CoupleAttrValue # 仙侣属性值(非累积)
    def GetStarAttrType(self): return self.StarAttrType # 星级额外属性类型(非累积)
    def GetStarAttrValue(self): return self.StarAttrValue # 星级额外属性值(非累积)
    def GetUpItemAttrType(self): return self.UpItemAttrType # 每x个培养丹增加属性类型,x=UpEatItemPerCount
    def GetUpItemAttrValue(self): return self.UpItemAttrValue # 每x个培养丹增加属性值,x=UpEatItemPerCount
    def GetNeedEatCount(self): return self.NeedEatCount # 升级所需个数(非累计)
    def GetUpEatItemPerCount(self): return self.UpEatItemPerCount # 每次培养消耗x个
# 骑宠幻化表
class IPY_HorsePetSkin():
    
@@ -6242,6 +6304,10 @@
        self.ipySkyTowerServerChallengeLen = len(self.ipySkyTowerServerChallengeCache)
        self.ipyLingGenEffectCache = self.__LoadFileData("LingGenEffect", IPY_LingGenEffect)
        self.ipyLingGenEffectLen = len(self.ipyLingGenEffectCache)
        self.ipyMarryCache = self.__LoadFileData("Marry", IPY_Marry)
        self.ipyMarryLen = len(self.ipyMarryCache)
        self.ipyLoveRingCache = self.__LoadFileData("LoveRing", IPY_LoveRing)
        self.ipyLoveRingLen = len(self.ipyLoveRingCache)
        self.ipyHorsePetSkinCache = self.__LoadFileData("HorsePetSkin", IPY_HorsePetSkin)
        self.ipyHorsePetSkinLen = len(self.ipyHorsePetSkinCache)
        self.ipyAssistThanksGiftCache = self.__LoadFileData("AssistThanksGift", IPY_AssistThanksGift)
@@ -6794,6 +6860,10 @@
    def GetSkyTowerServerChallengeByIndex(self, index): return self.ipySkyTowerServerChallengeCache[index]
    def GetLingGenEffectCount(self): return self.ipyLingGenEffectLen
    def GetLingGenEffectByIndex(self, index): return self.ipyLingGenEffectCache[index]
    def GetMarryCount(self): return self.ipyMarryLen
    def GetMarryByIndex(self, index): return self.ipyMarryCache[index]
    def GetLoveRingCount(self): return self.ipyLoveRingLen
    def GetLoveRingByIndex(self, index): return self.ipyLoveRingCache[index]
    def GetHorsePetSkinCount(self): return self.ipyHorsePetSkinLen
    def GetHorsePetSkinByIndex(self, index): return self.ipyHorsePetSkinCache[index]
    def GetAssistThanksGiftCount(self): return self.ipyAssistThanksGiftLen
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
@@ -95,6 +95,7 @@
import QuestCommon
import PlayerDogz
import PlayerFaQi
import PlayerLove
import ChPlayer
import GMShell
import GameObj
@@ -4514,6 +4515,7 @@
        PlayerGatherSoul.RefreshGatherSoulAttr(curPlayer)
        PlayerCoat.CalcClothesCoatSkinAttr(curPlayer)
        PlayerFaQi.CalcFaQiAttr(curPlayer)
        PlayerLove.CalcLoveAttr(curPlayer)
        self.RefreshAllState(isForce=True)
        GameWorld.DebugLog("End ReCalcAllState!!!")
        return
@@ -6198,6 +6200,10 @@
def GetChatBubbleBox(curPlayer): return curPlayer.GetExAttr10()
def SetChatBubbleBox(curPlayer, value): return curPlayer.SetExAttr10(value, False, True)
##伴侣ID
def GetCoupleID(curPlayer): return curPlayer.GetExAttr11()
def SetCoupleID(curPlayer, coupleID): return curPlayer.SetExAttr11(coupleID, False, False)
## 玩家所属服务器组ID
def GetPlayerServerGroupID(curPlayer): return curPlayer.GetExAttr13()
def UpdPlayerServerGroupID(curPlayer):
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerLove.py
New file
@@ -0,0 +1,662 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package Player.PlayerLove
#
# @todo:情缘系统
# @author hxp
# @date 2021-11-09
# @version 1.0
#
# 详细描述: 情缘系统
#
#-------------------------------------------------------------------------------
#"""Version = 2021-11-09 20:00"""
#-------------------------------------------------------------------------------
import GameWorld
import ItemCommon
import PlayerControl
import IpyGameDataPY
import ChPyNetSendPack
import PlayerBillboard
import IPY_GameWorld
import ItemControler
import NetPackCommon
import ShareDefine
import ChConfig
import time
def DoPlayerOnDay(curPlayer):
    # 重置每日魅力
    if curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveCharmToday):
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveCharmToday, 0)
        Sync_CharmInfo(curPlayer)
    # 重置每日聘礼
    bridePriceState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveBridePriceState)
    if bridePriceState:
        updBridePriceState = bridePriceState
        ipyDataMgr = IpyGameDataPY.IPY_Data()
        for index in range(ipyDataMgr.GetMarryCount()):
            ipyData = ipyDataMgr.GetMarryByIndex(index)
            if not ipyData.GetIsDayReset():
                continue
            bridePriceID = ipyData.GetBridePriceID()
            dataIndex = bridePriceID - 1
            buyCount = GameWorld.GetDataByDigitPlace(updBridePriceState, dataIndex)
            if not buyCount:
                continue
            updBridePriceState = GameWorld.ChangeDataByDigitPlace(updBridePriceState, dataIndex, 0)
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveBridePriceState, updBridePriceState)
            GameWorld.DebugLog("重置每日聘礼次数: bridePriceState=%s,bridePriceID=%s,updBridePriceState=%s"
                               % (bridePriceState, bridePriceID, updBridePriceState), curPlayer.GetPlayerID())
        if bridePriceState != updBridePriceState:
            Sync_CoupleInfo(curPlayer)
    return
def DoPlayerLogin(curPlayer):
    Sync_CharmInfo(curPlayer)
    Sync_CoupleInfo(curPlayer)
    Sync_LoveRingInfo(curPlayer)
    return
#// B3 10 送花 #tagCMSendFlowers
#
#struct    tagCMSendFlowers
#{
#    tagHead        Head;
#    DWORD        TagPlayerID;    // 目标玩家ID
#    DWORD        FlowerCount;    // 赠送花数量
#};
def OnSendFlowers(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    tagPlayerID = clientData.TagPlayerID
    flowerCount = clientData.FlowerCount
    if flowerCount <= 0:
        return
    flowerCountInfoDict = IpyGameDataPY.GetFuncEvalCfg("LoveFlower", 2, {})
    if str(flowerCount) not in flowerCountInfoDict:
        return
    addCharm, addCharmTag, addIntimacy = flowerCountInfoDict[str(flowerCount)]
    flowerID = IpyGameDataPY.GetFuncCfg("LoveFlower", 1)
    _, bindCnt, unBindCnt = ItemCommon.GetPackItemBindStateIndexInfo(curPlayer, flowerID, flowerCount)
    lackCnt = flowerCount - bindCnt - unBindCnt
    if lackCnt > 0:
        GameWorld.DebugLog("鲜花道具不足,无法赠送! flowerID=%s,flowerCount=%s,bindCnt=%s,unBindCnt=%s,lackCnt=%s"
                           % (flowerID, flowerCount, bindCnt, unBindCnt, lackCnt))
        return
    if not GameWorld.SetPlayerTickTime(curPlayer, ChConfig.TYPE_Player_Tick_Love, tick):
        PlayerControl.NotifyCode(curPlayer, "RequestLater")
        return
    isWorldNotify = (flowerCount in IpyGameDataPY.GetFuncEvalCfg("LoveFlower", 3))
    dataMsg = [tagPlayerID, flowerID, flowerCount, addCharm, addCharmTag, addIntimacy, isWorldNotify]
    SendToGameServer_Love(curPlayer, "SendFlowersReq", dataMsg)
    return
#// B3 11 提亲 #tagCMMarryReq
#
#struct    tagCMMarryReq
#{
#    tagHead        Head;
#    DWORD        TagPlayerID;    // 目标玩家ID
#    BYTE        BridePriceID;    // 聘礼ID
#};
def OnMarryReq(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    tagPlayerID = clientData.TagPlayerID
    bridePriceID = clientData.BridePriceID
    playerID = curPlayer.GetPlayerID()
    coupleID = PlayerControl.GetCoupleID(curPlayer)
    if coupleID and coupleID != tagPlayerID:
        GameWorld.DebugLog("已成亲伴侣ID不一致,无法提亲! tagPlayerID(%s) != coupleID(%s)" % (tagPlayerID, coupleID), playerID)
        return
    ipyData = IpyGameDataPY.GetIpyGameData("Marry", bridePriceID)
    if not ipyData:
        return
    canBuyMax = ipyData.GetCanBuyCount()
    dataIndex = bridePriceID - 1
    bridePriceState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveBridePriceState)
    buyCount = GameWorld.GetDataByDigitPlace(bridePriceState, dataIndex)
    if canBuyMax and buyCount >= canBuyMax:
        GameWorld.DebugLog("聘礼提亲次数不足,无法提亲! bridePriceID=%s,buyCount(%s) >= canBuyMax(%s)"
                           % (bridePriceID, buyCount, canBuyMax), playerID)
        return
    costMoneyInfo = ipyData.GetCostMoneyInfo()
    if len(costMoneyInfo) != 2:
        return
    moneyType, moneyValue = costMoneyInfo
    if not PlayerControl.HaveMoney(curPlayer, moneyType, moneyValue):
        return
    if not GameWorld.SetPlayerTickTime(curPlayer, ChConfig.TYPE_Player_Tick_Love, tick):
        PlayerControl.NotifyCode(curPlayer, "RequestLater")
        return
    dataMsg = [tagPlayerID, bridePriceID]
    SendToGameServer_Love(curPlayer, "MarryReq", dataMsg)
    return
#// B3 13 吃喜糖 #tagCMMarryEatCandy
#
#struct    tagCMMarryEatCandy
#{
#    tagHead        Head;
#    DWORD        PlayerIDA;    // 喜糖所属玩家IDA
#    DWORD        PlayerIDB;    // 喜糖所属玩家IDB
#};
def OnMarryEatCandy(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    playerIDA = clientData.PlayerIDA
    playerIDB = clientData.PlayerIDB
    playerID = curPlayer.GetPlayerID()
    if not GameWorld.SetPlayerTickTime(curPlayer, ChConfig.TYPE_Player_Tick_Love, tick):
        PlayerControl.NotifyCode(curPlayer, "RequestLater")
        return
    costMoneyType, costMoneyValue = IpyGameDataPY.GetFuncEvalCfg("LoveCandy", 2)
    playerMoneyValue = PlayerControl.GetMoney(curPlayer, costMoneyType)
    dataMsg = [playerIDA, playerIDB, playerID, costMoneyType, costMoneyValue, playerMoneyValue]
    SendToGameServer_Love(curPlayer, "MarryEatCandy", dataMsg)
    return
#// B3 14 购买婚礼烟花 #tagCMMarryBuyFireworks
#
#struct    tagCMMarryBuyFireworks
#{
#    tagHead        Head;
#    DWORD        PlayerIDA;    // 喜糖所属玩家IDA
#    DWORD        PlayerIDB;    // 喜糖所属玩家IDB
#};
def OnMarryBuyFireworks(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    playerIDA = clientData.PlayerIDA
    playerIDB = clientData.PlayerIDB
    playerID = curPlayer.GetPlayerID()
    costMoneyType, costMoneyValue = IpyGameDataPY.GetFuncEvalCfg("LoveCandyFire", 2)
    if not PlayerControl.HaveMoney(curPlayer, costMoneyType, costMoneyValue):
        return
    playerMoneyValue = PlayerControl.GetMoney(curPlayer, costMoneyType)
    if not GameWorld.SetPlayerTickTime(curPlayer, ChConfig.TYPE_Player_Tick_Love, tick):
        PlayerControl.NotifyCode(curPlayer, "RequestLater")
        return
    dataMsg = [playerIDA, playerIDB, playerID, costMoneyType, costMoneyValue, playerMoneyValue]
    SendToGameServer_Love(curPlayer, "MarryBuyFireworks", dataMsg)
    return
#// B3 15 离婚 #tagCMMarryBreak
#
#struct    tagCMMarryBreak
#{
#    tagHead        Head;
#    BYTE        BreakType;    // 0-和平离婚;1-强制离婚
#};
def OnMarryBreak(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    breakType = clientData.BreakType
    playerID = curPlayer.GetPlayerID()
    coupleID = PlayerControl.GetCoupleID(curPlayer)
    if not coupleID:
        GameWorld.DebugLog("没有伴侣,不需要离婚!", playerID)
        return
    curTime = int(time.time())
    marryTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveMarryTime)
    passTime = curTime - marryTime
    breakCD = IpyGameDataPY.GetFuncCfg("LoveMarryBreak", 1)
    if breakCD and passTime < breakCD:
        GameWorld.Log("离婚等待时间未到,无法离婚! marryTime=%s,passTime(%s) < %s"
                      % (GameWorld.ChangeTimeNumToStr(marryTime), passTime, breakCD), playerID)
        return
    moneyType, moneyValue = 0, 0
    if breakType == 1:
        costMoneyInfo = IpyGameDataPY.GetFuncEvalCfg("LoveMarryBreak", 2)
        if len(costMoneyInfo) != 2:
            return
        moneyType, moneyValue = costMoneyInfo
        if not PlayerControl.HaveMoney(curPlayer, moneyType, moneyValue):
            return
    if not GameWorld.SetPlayerTickTime(curPlayer, ChConfig.TYPE_Player_Tick_Love, tick):
        PlayerControl.NotifyCode(curPlayer, "RequestLater")
        return
    dataMsg = [playerID, coupleID, breakType, moneyType, moneyValue]
    SendToGameServer_Love(curPlayer, "MarryBreakReq", dataMsg)
    return
def SendToGameServer_Love(curPlayer, msgType, dataMsg):
    ## 发送信息到跨服服务器
    msgList = str([msgType, dataMsg])
    GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(curPlayer.GetPlayerID(), 0, 0, "Love", msgList, len(msgList))
    GameWorld.Log("情缘发送GameServer: %s, %s" % (msgType, dataMsg), curPlayer.GetPlayerID())
    return
def GameServer_Love_DoLogic(curPlayer, msgData):
    msgType, dataMsg = msgData[:2]
    ## 增加魅力值
    if msgType == "AddCharm":
        addCharmTag = dataMsg[0]
        __DoAddCharm(curPlayer, addCharmTag)
        return
    ## 结婚成功
    elif msgType == "MarrySuccess":
        __DoMarrySuccess(curPlayer, dataMsg)
    ## 离婚成功
    elif msgType == "ClearCoupleSocial":
        __ClearCoupleSocial(curPlayer, dataMsg)
    return
def GameServer_Love_DoResult(curPlayer, msgData):
    msgType, dataMsg, ret = msgData
    ## 送花请求返回
    if msgType == "SendFlowersReq":
        if not ret:
            return
        __DoSendFlowers(curPlayer, dataMsg)
    ## 吃喜糖返回
    elif msgType == "MarryEatCandy":
        if not ret:
            return
        __DoMarryEatCandy(curPlayer, ret)
    ## 购买婚礼烟花返回
    elif msgType == "MarryBuyFireworks":
        if not ret:
            return
        __DoMarryBuyFireworks(curPlayer, ret)
    ## 离婚请求返回
    elif msgType == "MarryBreakReq":
        if not ret:
            return
        __DoMarryBreakReq(curPlayer, ret)
    return
def __DoSendFlowers(curPlayer, dataMsg):
    ## 送花方处理
    playerID = curPlayer.GetPlayerID()
    tagPlayerID, flowerID, flowerCount, addCharm = dataMsg[:4]
    costItemIndexList, bindCnt, unBindCnt = ItemCommon.GetPackItemBindStateIndexInfo(curPlayer, flowerID, flowerCount)
    lackCnt = flowerCount - bindCnt - unBindCnt
    if lackCnt > 0:
        GameWorld.ErrLog("地图鲜花道具不足,无法赠送! tagPlayerID=%s,flowerID=%s,flowerCount=%s,lackCnt=%s"
                         % (tagPlayerID, flowerID, flowerCount, lackCnt), playerID)
        return
    GameWorld.Log("赠送鲜花: tagPlayerID=%s,flowerID=%s,flowerCount=%s,addCharm=%s" % (tagPlayerID, flowerID, flowerCount, addCharm), playerID)
    saveDataDict = {"tagPlayerID":tagPlayerID}
    ItemCommon.DelCostItemByBind(curPlayer, costItemIndexList, bindCnt, unBindCnt, flowerCount, "Love", saveDataDict)
    __DoAddCharm(curPlayer, addCharm)
    SendToGameServer_Love(curPlayer, "SendFlowersOK", dataMsg)
    return
def __DoMarryEatCandy(curPlayer, retInfo):
    ## 执行吃喜糖结果
    canBuy, isFree, costMoneyType, costMoneyValue, candyItemInfo = retInfo
    if not isFree:
        if not PlayerControl.HaveMoney(curPlayer, costMoneyType, costMoneyValue):
            return
    if not canBuy:
        return
    GameWorld.Log("吃喜糖结果: isFree=%s" % (isFree), curPlayer.GetPlayerID())
    if not isFree:
        infoDict = {ChConfig.Def_Cost_Reason_SonKey:"EatCandy"}
        PlayerControl.PayMoney(curPlayer, costMoneyType, costMoneyValue, ChConfig.Def_Cost_Love, infoDict, isMinus=True)
    ItemControler.GivePlayerItemOrMail(curPlayer, candyItemInfo)
    return
def __DoMarryBuyFireworks(curPlayer, retInfo):
    ## 执行购买婚礼烟花结果
    costMoneyType, costMoneyValue = retInfo
    GameWorld.Log("执行购买婚礼烟花结果: costMoneyType=%s, costMoneyValue=%s" % (costMoneyType, costMoneyValue), curPlayer.GetPlayerID())
    infoDict = {ChConfig.Def_Cost_Reason_SonKey:"MarryBuyFireworks"}
    PlayerControl.PayMoney(curPlayer, costMoneyType, costMoneyValue, ChConfig.Def_Cost_Love, infoDict, isMinus=True)
    return
def __DoMarryBreakReq(curPlayer, retInfo):
    ## 离婚请求结果返回
    costMoneyType, costMoneyValue = retInfo
    GameWorld.Log("执行离婚请求结果: costMoneyType=%s, costMoneyValue=%s" % (costMoneyType, costMoneyValue), curPlayer.GetPlayerID())
    infoDict = {ChConfig.Def_Cost_Reason_SonKey:"MarryBreak"}
    PlayerControl.PayMoney(curPlayer, costMoneyType, costMoneyValue, ChConfig.Def_Cost_Love, infoDict, isMinus=True)
    return
def __DoAddCharm(curPlayer, addValue):
    ## 增加魅力值
    charmTotal = min(curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveCharmTotal) + addValue, ShareDefine.Def_UpperLimit_DWord)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveCharmTotal, charmTotal)
    charmToday = min(curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveCharmToday) + addValue, ShareDefine.Def_UpperLimit_DWord)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveCharmToday, charmToday)
    GameWorld.Log("增加魅力: addValue=%s,charmTotal=%s,charmToday=%s" % (addValue, charmTotal, charmToday), curPlayer.GetPlayerID())
    PlayerControl.NotifyCode(curPlayer, "AddCharm", [addValue])
    PlayerBillboard.UpdatePlayerBillboard(curPlayer, ShareDefine.Def_BT_Charm, charmTotal)
    PlayerBillboard.UpdatePlayerBillboard(curPlayer, ShareDefine.Def_BT_CharmDay, charmToday)
    Sync_CharmInfo(curPlayer)
    return
def __DoMarrySuccess(curPlayer, dataMsg):
    ## 执行成亲成功
    reqPlayerID, coupleID, curTime, bridePriceID = dataMsg
    isNewlyMarried = (PlayerControl.GetCoupleID(curPlayer) != coupleID) # 是否新婚
    playerID = curPlayer.GetPlayerID()
    if isNewlyMarried:
        PlayerControl.SetCoupleID(curPlayer, coupleID)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveNewMarryTime, curTime)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveBridePriceState, 0)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveBridePriceMaxID, 0)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveMarryTime, curTime)
    dataIndex = bridePriceID - 1
    bridePriceState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveBridePriceState)
    buyCount = GameWorld.GetDataByDigitPlace(bridePriceState, dataIndex)
    updBuyCount = min(9, buyCount + 1)
    updBridePriceState = GameWorld.ChangeDataByDigitPlace(bridePriceState, dataIndex, updBuyCount)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveBridePriceState, updBridePriceState)
    bridePriceMaxID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveBridePriceMaxID)
    if bridePriceID > bridePriceMaxID:
        bridePriceMaxID = bridePriceID
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveBridePriceMaxID, bridePriceMaxID)
    Sync_CoupleInfo(curPlayer)
    if curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveRingClassLV) == 0:
        GameWorld.DebugLog("激活情戒!")
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveRingClassLV, 1)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveRingStarLV, 1)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveRingEatCount, 0)
        Sync_LoveRingInfo(curPlayer)
    GameWorld.Log("执行成亲成功! coupleID=%s,curTime=%s,bridePriceID=%s,isNewlyMarried=%s,bridePriceState=%s,buyCount=%s,updBuyCount=%s,updBridePriceState=%s,bridePriceMaxID=%s"
                  % (coupleID, curTime, bridePriceID, isNewlyMarried, bridePriceState, buyCount, updBuyCount, updBridePriceState, bridePriceMaxID), playerID)
    # 提亲的玩家扣除消耗
    if playerID == reqPlayerID:
        ipyData = IpyGameDataPY.GetIpyGameData("Marry", bridePriceID)
        if ipyData:
            moneyType, moneyValue = ipyData.GetCostMoneyInfo()
            infoDict = {ChConfig.Def_Cost_Reason_SonKey:"MarrySuccess", "bridePriceID":bridePriceID}
            PlayerControl.PayMoney(curPlayer, moneyType, moneyValue, ChConfig.Def_Cost_Love, infoDict, isMinus=True)
    RefreshLoveAttr(curPlayer)
    return
def GetBridePriceMaxID(curPlayer):
    ## 获取结婚聘礼的最高ID
    return curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveBridePriceMaxID)
def __ClearCoupleSocial(curPlayer, dataMsg):
    ## 离婚 - 清除伴侣关系
    playerID = curPlayer.GetPlayerID()
    coupleID = PlayerControl.GetCoupleID(curPlayer)
    PlayerControl.SetCoupleID(curPlayer, 0)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveBridePriceState, 0)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveBridePriceMaxID, 0)
    Sync_CoupleInfo(curPlayer)
    GameWorld.Log("清除伴侣关系成功! coupleID=%s" % (coupleID), playerID)
    RefreshLoveAttr(curPlayer)
    return
#// B3 17 情戒解锁 #tagCMLoveRingUnlock
#
#struct    tagCMLoveRingUnlock
#{
#    tagHead        Head;
#};
def OnLoveRingUnlock(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    playerID = curPlayer.GetPlayerID()
    unlockItemID = IpyGameDataPY.GetFuncCfg("LoveRing", 1)
    unlockItem = ItemCommon.FindItemInPackByItemID(curPlayer, unlockItemID, IPY_GameWorld.rptItem)
    if not ItemCommon.CheckItemCanUse(unlockItem):
        GameWorld.DebugLog("物品解锁情戒缺少道具! unlockItemID=%s" % unlockItemID, playerID)
        return
    ItemCommon.DelItem(curPlayer, unlockItem, 1)
    classLV = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveRingClassLV)
    if classLV < 1:
        GameWorld.DebugLog("物品解锁情戒!", playerID)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveRingClassLV, 1)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveRingStarLV, 1)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveRingEatCount, 0)
        Sync_LoveRingInfo(curPlayer)
        RefreshLoveAttr(curPlayer)
    NetPackCommon.SendFakePack(curPlayer, ChPyNetSendPack.tagMCLoveRingUnlockOK())
    return
#// B3 18 情戒升级 #tagCMLoveRingUp
#
#struct    tagCMLoveRingUp
#{
#    tagHead        Head;
#    DWORD        UseItemCnt;        //消耗材料个数
#};
def OnLoveRingUp(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    costItemCount = clientData.UseItemCnt # 消耗材料个数
    #isAutoBuy = False # 本功能暂不提供自动购买
    playerID = curPlayer.GetPlayerID()
    classLV = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveRingClassLV)
    if not classLV:
        GameWorld.DebugLog("情戒未解锁!", playerID)
        return
    starLV = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveRingStarLV)
    curEatItemCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveRingEatCount)
    ringIpyData = IpyGameDataPY.GetIpyGameData("LoveRing", classLV, starLV)
    if not ringIpyData:
        return
    needEatCount = ringIpyData.GetNeedEatCount()
    if not needEatCount:
        GameWorld.DebugLog("情戒已满级!classLV=%s,starLV=%s" % (classLV, starLV), playerID)
        return
    costItemID = IpyGameDataPY.GetFuncCfg("LoveRing", 2)
    if not costItemID or costItemCount <= 0:
        return
    costItemIndexList, bindCnt, unBindCnt = ItemCommon.GetPackItemBindStateIndexInfo(curPlayer, costItemID, costItemCount)
    lackCnt = costItemCount - bindCnt - unBindCnt
    if lackCnt > 0:
        GameWorld.DebugLog("消耗道具不足,无法升级情戒! costItemID=%s,costItemCount=%s,bindCnt=%s,unBindCnt=%s,lackCnt=%s"
                           % (costItemID, costItemCount, bindCnt, unBindCnt, lackCnt), playerID)
        return
    delCnt = costItemCount
    updClassLV, updStarLV = classLV, starLV
    updEatItemCount = curEatItemCount + costItemCount
    GameWorld.DebugLog("情戒升级: classLV=%s,starLV=%s,curEatItemCount=%s,costItemCount=%s,updEatItemCount=%s,needEatCount=%s"
                       % (classLV, starLV, curEatItemCount, costItemCount, updEatItemCount, needEatCount), playerID)
    ringUpType = ""
    if updEatItemCount >= needEatCount:
        ringUpType = "starUp"
        updStarLV += 1
        nextRingIpyData = IpyGameDataPY.GetIpyGameDataNotLog("LoveRing", updClassLV, updStarLV)
        if not nextRingIpyData:
            updClassLV += 1
            updStarLV = 1
            nextRingIpyData = IpyGameDataPY.GetIpyGameData("LoveRing", updClassLV, updStarLV)
            if not nextRingIpyData:
                GameWorld.ErrLog("情戒升级数据异常: classLV=%s,starLV=%s,curEatItemCount=%s,costItemCount=%s,updEatItemCount=%s,needEatCount=%s"
                       % (classLV, starLV, curEatItemCount, costItemCount, updEatItemCount, needEatCount), playerID)
                return
            ringUpType = "classUp"
        updEatItemCount -= needEatCount
    # 扣除消耗
    if delCnt:
        ItemCommon.DelCostItemByBind(curPlayer, costItemIndexList, bindCnt, unBindCnt, delCnt, "LoveRing")
    # 升星
    if ringUpType == "starUp":
        GameWorld.DebugLog("    升星: updClassLV=%s,updStarLV=%s,updEatItemCount=%s" % (updClassLV, updStarLV, updEatItemCount), playerID)
    # 升阶
    elif ringUpType == "classUp":
        GameWorld.DebugLog("    升阶: updClassLV=%s,updStarLV=%s,updEatItemCount=%s" % (updClassLV, updStarLV, updEatItemCount), playerID)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveRingClassLV, updClassLV)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveRingStarLV, updStarLV)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LoveRingEatCount, updEatItemCount)
    Sync_LoveRingInfo(curPlayer)
    RefreshLoveAttr(curPlayer)
    return
def RefreshLoveAttr(curPlayer):
    CalcLoveAttr(curPlayer)
    PlayerControl.PlayerControl(curPlayer).RefreshPlayerAttrState()
    return
def CalcLoveAttr(curPlayer):
    classLV = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveRingClassLV)
    starLV = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveRingStarLV)
    coupleID = PlayerControl.GetCoupleID(curPlayer)
    allAttrList = [{} for _ in range(4)]
    allAttrListCouple = [{} for _ in range(4)]
    ipyDataMgr = IpyGameDataPY.IPY_Data()
    for index in xrange(ipyDataMgr.GetLoveRingCount()):
        ringIpyData = ipyDataMgr.GetLoveRingByIndex(index)
        dataClassLV = ringIpyData.GetRingClassLV()
        dataStarLV = ringIpyData.GetRingStarLV()
        if dataClassLV > classLV or (dataClassLV == classLV and dataStarLV > starLV):
            break
        elif dataClassLV == classLV and dataStarLV == starLV:
            upItemCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveRingEatCount)
        else:
            upItemCount = ringIpyData.GetNeedEatCount()
        # 阶星属性
        starAttrTypeList = ringIpyData.GetStarAttrType()
        starAttrValueList = ringIpyData.GetStarAttrValue()
        for i, attrID in enumerate(starAttrTypeList):
            attrValue = starAttrValueList[i]
            PlayerControl.CalcAttrDict_Type(attrID, attrValue, allAttrList)
        # 升级个数属性
        upItemPerCount = ringIpyData.GetUpEatItemPerCount()
        if upItemCount and upItemPerCount:
            upItemAttrTypeList = ringIpyData.GetUpItemAttrType()
            upItemAttrValueList = ringIpyData.GetUpItemAttrValue()
            attrMultiple = upItemCount / upItemPerCount
            for i, attrID in enumerate(upItemAttrTypeList):
                attrValue = upItemAttrValueList[i]
                PlayerControl.CalcAttrDict_Type(attrID, attrValue * attrMultiple, allAttrList)
        # 仙侣属性
        if coupleID:
            coupleAttrTypeList = ringIpyData.GetCoupleAttrType()
            coupleAttrValueList = ringIpyData.GetCoupleAttrValue()
            for i, attrID in enumerate(coupleAttrTypeList):
                attrValue = coupleAttrValueList[i]
                PlayerControl.CalcAttrDict_Type(attrID, attrValue, allAttrListCouple)
    #GameWorld.DebugLog("情戒基础属性: classLV=%s,starLV=%s,allAttrList=%s" % (classLV, starLV, allAttrList))
    #GameWorld.DebugLog("情戒仙侣属性: classLV=%s,starLV=%s,allAttrListCouple=%s" % (classLV, starLV, allAttrListCouple))
    # 保存计算值
    PlayerControl.SetCalcAttrListValue(curPlayer, ChConfig.Def_CalcAttrFunc_LoveRing, allAttrList)
    PlayerControl.SetCalcAttrListValue(curPlayer, ChConfig.Def_CalcAttrFunc_LoveRingCouple, allAttrListCouple)
    return
def Sync_CharmInfo(curPlayer):
    ## 同步魅力信息
    clientPack = ChPyNetSendPack.tagMCCharmInfo()
    clientPack.CharmTotal = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveCharmTotal)
    clientPack.CharmToday = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveCharmToday)
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
def Sync_CoupleInfo(curPlayer):
    ## 同步伴侣信息
    clientPack = ChPyNetSendPack.tagMCCoupleInfo()
    clientPack.CoupleID = PlayerControl.GetCoupleID(curPlayer)
    clientPack.NewMarryTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveNewMarryTime)
    clientPack.MarryTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveMarryTime)
    clientPack.BridePriceState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveBridePriceState)
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
def Sync_LoveRingInfo(curPlayer):
    ## 同步情戒信息
    clientPack = ChPyNetSendPack.tagMCLoveRingInfo()
    clientPack.ClassLV = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveRingClassLV)
    clientPack.StarLV = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveRingStarLV)
    clientPack.EatCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveRingEatCount)
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTalk.py
@@ -29,6 +29,8 @@
import ChItem
import PlayerTJG
import EventShell
import PyGameData
import PlayerLove
#---------------------------------------------------------------------
@@ -363,6 +365,7 @@
    vipLv = objTalk.GetVIPLv()  # 玩家vip等级
    GMLevel = objTalk.GetGMLevel()
    job = objTalk.GetJob()
    playerID = objTalk.GetID()
    
    extraValueStr = ""
    # vip等级
@@ -377,6 +380,13 @@
    extraValueStr += GetTalkExtraValueStar(ShareDefine.Def_TalkExtraValue_Bit_ServerGroupID) % PlayerControl.GetPlayerServerGroupID(objTalk)
    # 等级
    extraValueStr += GetTalkExtraValueStar(ShareDefine.Def_TalkExtraValue_Bit_LV) % objTalk.GetLV()
    # 伴侣信息
    coupleName, bridePriceMaxID = "", 0
    coupleInfo = PyGameData.g_coupleInfo.get(playerID)
    if coupleInfo and len(coupleInfo) >= 2 and coupleInfo[0] == PlayerControl.GetCoupleID(objTalk):
        coupleName = coupleInfo[1]
        bridePriceMaxID = PlayerLove.GetBridePriceMaxID(objTalk)
    extraValueStr = "%s|%s|%s" % (extraValueStr, coupleName, bridePriceMaxID)
    return extraValueStr
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerViewCacheTube.py
@@ -177,6 +177,8 @@
    curPlayerPropDict["ServerGroupID"] = PlayerControl.GetPlayerServerGroupID(curPlayer)
    curPlayerPropDict["LingGenPoint"] = [PlayerControl.GetMetal(curPlayer), PlayerControl.GetWood(curPlayer), PlayerControl.GetWater(curPlayer), 
                                         PlayerControl.GetFire(curPlayer), PlayerControl.GetEarth(curPlayer)]
    curPlayerPropDict["CoupleID"] = PlayerControl.GetCoupleID(curPlayer)
    #战斗属性
    curPlayerPropDict["MinAtk"] = curPlayer.GetMinAtk()
    curPlayerPropDict["MaxAtk"] = curPlayer.GetMaxAtk()
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_Love.py
New file
@@ -0,0 +1,55 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package Player.RemoteQuery.GY_Query_Love
#
# @todo:情缘
# @author hxp
# @date 2021-11-09
# @version 1.0
#
# 详细描述: 情缘
#
#-------------------------------------------------------------------------------
#"""Version = 2021-11-09 20:00"""
#-------------------------------------------------------------------------------
import GameWorld
import PlayerLove
import ChConfig
#------------------------------------------------------------------------------
## 跨服赛报名调用接口
#  @param query_Type 请求类型
#  @param query_ID 请求的玩家ID
#  @param packCMDList 发包命令
#  @param tick 当前时间
#  @return "True" or "False" or ""
#  @remarks 函数详细说明.
def DoLogic(query_Type, query_ID, packCMDList, tick):
    curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(query_ID)
    if not curPlayer or curPlayer.IsEmpty():
        return
    GameWorld.Log("GameServer_Love_DoLogic msgData=%s" % (packCMDList), query_ID)
    PlayerLove.GameServer_Love_DoLogic(curPlayer, packCMDList)
    return
#------------------------------------------------------------------------------
## 执行结果
#  @param curPlayer 发出请求的玩家
#  @param callFunName 功能名称
#  @param funResult 查询的结果
#  @param tick 当前时间
#  @return None
#  @remarks 函数详细说明.
def DoResult(curPlayer, callFunName, funResult, tick):
    curPlayer.SetTickByType(ChConfig.TYPE_Player_Tick_Love, 0)
    msgData = eval(funResult)
    playerID = curPlayer.GetPlayerID()
    GameWorld.Log("GameServer_Love_DoResult msgData=%s" % (msgData), playerID)
    PlayerLove.GameServer_Love_DoResult(curPlayer, msgData)
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py
@@ -110,4 +110,6 @@
g_fairyDomainLimit = [] #全服已限制的缥缈仙域事件
g_elemntSkillDict = {} #{skillID:[attrID*100000+needValue,..]}
g_coupleInfo = {} # {playerID:[coupleID, coupleName], ...}
g_playerPriWoodPileNPCDict = {} # {playerID:[npcObj, ...], ...}