From f4f907ae6ae2f22207859230e8fc88583fe3a723 Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期三, 10 十一月 2021 11:26:11 +0800
Subject: [PATCH] 9341 【BT5】【主干】【后端】情缘系统

---
 ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/Friend.py                                    |   68 +
 ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py                                         |   32 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py                      |  484 +++++++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Love.py                 |  100 ++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py                       |    2 
 ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py                                           |  484 +++++++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/PrintFightPower.py      |    3 
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerLove.py                                     |  723 ++++++++++++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py                    |   70 +
 ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py                                              |    2 
 PySysDB/PySysDBPY.h                                                                                     |   26 
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerTalk.py                                     |   10 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py             |    6 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerLove.py                |  662 +++++++++++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerViewCacheTube.py       |    2 
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py                                  |    4 
 ServerPython/CoreServerGroup/GameServer/Script/PyGameDataStruct.py                                      |   26 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTalk.py                |   10 
 ServerPython/CoreServerGroup/GameServer/Script/Player/UpdatePlayerName.py                               |    3 
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerSocial.py                                   |  129 ++
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFriend.py                                   |    9 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_Love.py |   55 +
 ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py                                            |    5 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini                              |   36 
 PySysDB/PySysDBG.h                                                                                      |   12 
 25 files changed, 2,952 insertions(+), 11 deletions(-)

diff --git a/PySysDB/PySysDBG.h b/PySysDB/PySysDBG.h
index 407da7a..ceff25c 100644
--- a/PySysDB/PySysDBG.h
+++ b/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
diff --git a/PySysDB/PySysDBPY.h b/PySysDB/PySysDBPY.h
index 198c70b..4d16b02 100644
--- a/PySysDB/PySysDBPY.h
+++ b/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
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py b/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py
index 802bc24..8449223 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py
+++ b/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匹配), 默认保存, 如果不保存,可配置进去
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py b/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py
index 557a689..8822b65 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py
+++ b/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):
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/Friend.py b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/Friend.py
new file mode 100644
index 0000000..5c0576d
--- /dev/null
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/Friend.py
@@ -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
+
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py b/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py
index 714c0ed..4cde1f6 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py
+++ b/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
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py
index 47564b2..23577f7 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py
+++ b/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)
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFriend.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFriend.py
index 96adcd2..c971cf3 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFriend.py
+++ b/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)
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerLove.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerLove.py
new file mode 100644
index 0000000..01bc4aa
--- /dev/null
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerLove.py
@@ -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
+
+
+
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerSocial.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerSocial.py
index 770c385..3ed29f5 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerSocial.py
+++ b/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):
@@ -208,7 +255,7 @@
         #    sendPack.Friends.append(playerFriend)
         # NetPackCommon.SendPyPackToMapServer(curPlayer.GetLineNO(), curPlayer.GetRealMapID(), sendPack) 
         #=======================================================================
-    
+        
 
 # 整个游戏的好友管理
 class FriendManager(object):
@@ -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(playerID, notifyType, value)
+    return
+
+def SendMapServerCoupleInfo(syncPlayerIDList=None):
+    checkState = False
+    syncCoupleInfo = {}
+    socialMgr = PyDataManager.GetPersonalSocialManager()
+    if syncPlayerIDList == None:
+        syncPlayerIDList = socialMgr.SocialInfo.keys()
+        checkState = True # 未指定时才检查,防止启动地图时同步过多(启动地图时,只同步本次已经同步过的)
         
-    Notify_All(curPlayer.GetID(), notifyType, value)
-
-
+    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):
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerTalk.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerTalk.py
index c7b1261..18a73a1 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerTalk.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerTalk.py
@@ -437,7 +437,8 @@
     vipLv = player.GetVIPLv()  # 玩家vip等级
     GMLevel = player.GetGMLevel()
     job = player.GetJob()
-
+    playerID = player.GetID()
+    
     extraValueStr = ""
     # vip等级
     extraValueStr += GetTalkExtraValueStar(ShareDefine.Def_TalkExtraValue_Bit_VipLv)%vipLv
@@ -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
 
 
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/UpdatePlayerName.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/UpdatePlayerName.py
index f8bc598..bb8be03 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/UpdatePlayerName.py
+++ b/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: 必须在纠正排行后, 因为纠正宠物排行榜有用到玩家改名前的旧名字
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py b/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py
index 142aca7..2bcdd79 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py
+++ b/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 = [] # 本服竞技场机器人等级列表
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/PyGameDataStruct.py b/ServerPython/CoreServerGroup/GameServer/Script/PyGameDataStruct.py
index bcb5cc3..a04b939 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/PyGameDataStruct.py
+++ b/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]
+            
 
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
index b3b8d2c..ee2d293 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
+++ b/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
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
index 557a689..8822b65 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
+++ b/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):
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Love.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Love.py
new file mode 100644
index 0000000..b3543d4
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Love.py
@@ -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
+
+
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/PrintFightPower.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/PrintFightPower.py
index e75d7a7..8407b24 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/PrintFightPower.py
+++ b/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 模块类型(可选)")
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
index 0b76ec9..67bf73d 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
+++ b/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
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
index b68f005..aae8f25 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
+++ b/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):
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerLove.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerLove.py
new file mode 100644
index 0000000..33f4029
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerLove.py
@@ -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
+
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTalk.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTalk.py
index 2e010dd..2c30c71 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTalk.py
+++ b/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
 
 
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerViewCacheTube.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerViewCacheTube.py
index a2a0595..fe51838 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerViewCacheTube.py
+++ b/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()
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_Love.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_Love.py
new file mode 100644
index 0000000..b0fe747
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_Love.py
@@ -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
+
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py
index b011cfd..8c0e8f2 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py
+++ b/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, ...], ...}

--
Gitblit v1.8.0