From ffa8a645ed6a92a3c723bbf5c7f1eb4d5425c826 Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期三, 17 十一月 2021 15:15:34 +0800
Subject: [PATCH] 9341 【BT5】【主干】【后端】情缘系统(优化情缘系统)

---
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerBillboard.py                                |   50 +
 ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py                                         |   35 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventSrc/FunctionNPCCommon.py |    5 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py                      |   88 +
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerEventCounter.py                             |    5 
 ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py                                           |   88 +
 ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py                                             |   43 
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerLove.py                                     |  756 ++++++++++++----
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py                    |   33 
 ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py                                              |    8 
 PySysDB/PySysDBPY.h                                                                                     |   11 
 ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/BillboardData.py                             |    1 
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerTalk.py                                     |   13 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py             |   26 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerLove.py                |  253 +---
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerViewCacheTube.py       |    1 
 ServerPython/CoreServerGroup/GameServer/PyNetPack.ini                                                   |   11 
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py                                  |    4 
 ServerPython/CoreServerGroup/GameServer/Script/PyGameDataStruct.py                                      |  279 +++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTalk.py                |   10 
 ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py                                       |    3 
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerSocial.py                                   |  338 ++++--
 ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/Charm.py                                     |   74 +
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFriend.py                                   |   30 
 ServerPython/CoreServerGroup/GameServer/Script/PyDataManager.py                                         |   34 
 /dev/null                                                                                               |  100 --
 ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py                                            |    5 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini                              |    2 
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerCharm.py                                    |  299 ++++++
 ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/Couple.py                                    |  128 ++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py        |    5 
 PySysDB/PySysDBG.h                                                                                      |   13 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py                         |    6 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/LoveRing.py             |   49 +
 34 files changed, 2,121 insertions(+), 685 deletions(-)

diff --git a/PySysDB/PySysDBG.h b/PySysDB/PySysDBG.h
index ceff25c..9d6c4c2 100644
--- a/PySysDB/PySysDBG.h
+++ b/PySysDB/PySysDBG.h
@@ -862,11 +862,24 @@
 	dict		Award;	//奖励 {"职业":[[物品ID,个数,是否绑定],...], ...}
 };
 
+//情缘礼物表
+
+struct tagLoveGift
+{
+	BYTE		_GiftNum;	//聘礼ID
+	DWORD		AddCharmSelf;	//单个增加自身魅力
+	DWORD		AddCharmTag;	//单个增加对方魅力
+	DWORD		AddIntimacy;	//单个增加双方亲密度
+	char		WorldNotifyKey;	//广播key
+};
+
 //情缘提亲表
 
 struct tagMarry
 {
 	BYTE		_BridePriceID;	//聘礼ID
+	BYTE		CanBuyCount;	//可购买次数
+	BYTE		IsDayReset;	//是否每日重置
 	DWORD		Prosperity;	//初始繁荣度
 	WORD		CandyTimes;	//喜糖持续时间秒
 	list		CandyItemInfo;	//喜糖物品列表[[物品ID,个数,是否拍品], ...]
diff --git a/PySysDB/PySysDBPY.h b/PySysDB/PySysDBPY.h
index 4d16b02..e34c63d 100644
--- a/PySysDB/PySysDBPY.h
+++ b/PySysDB/PySysDBPY.h
@@ -2423,14 +2423,21 @@
 	BYTE		_QualityLV;	//品级
 };
 
+//情缘礼物表
+
+struct tagLoveGift
+{
+	BYTE		_GiftNum;	//聘礼ID
+	DWORD		GiftItemID;	//物品ID
+	BYTE		AllowBatch;	//是否允许批量赠送
+};
+
 //情缘提亲表
 
 struct tagMarry
 {
 	BYTE		_BridePriceID;	//聘礼ID
 	list		CostMoneyInfo;	//消耗货币类型|数值
-	BYTE		CanBuyCount;	//可购买次数
-	BYTE		IsDayReset;	//是否每日重置
 };
 
 //情缘情戒表
diff --git a/ServerPython/CoreServerGroup/GameServer/PyNetPack.ini b/ServerPython/CoreServerGroup/GameServer/PyNetPack.ini
index a5898de..c94691e 100644
--- a/ServerPython/CoreServerGroup/GameServer/PyNetPack.ini
+++ b/ServerPython/CoreServerGroup/GameServer/PyNetPack.ini
@@ -458,6 +458,17 @@
 PacketSubCMD_2=0x16
 PacketCallFunc_2=OnMarryBreakResponse
 
+[PlayerCharm]
+ScriptName = GameWorldLogic\PlayerCharm.py
+Writer = hxp
+Releaser = hxp
+RegType = 0
+RegisterPackCount = 1
+
+PacketCMD_1=0xB3
+PacketSubCMD_1=0x09
+PacketCallFunc_1=OnCharmOfferBillboardQuery
+
 [PlayerTalk]
 ScriptName = Player\PlayerTalk.py
 Writer = alee
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py b/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py
index 8449223..c1c901c 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py
@@ -592,7 +592,8 @@
             
             ShareDefine.Def_BT_Arena                    : 1000,          #竞技场榜
             ShareDefine.Def_BT_Environment              : 20,            #环保榜 (垃圾分类活动)
-            ShareDefine.Def_BT_Charm                    : 100,           #魅力总榜
+            ShareDefine.Def_BT_CharmTotal               : 100,           #魅力总榜
+            ShareDefine.Def_BT_CharmWeek                : 100,           #魅力周榜
             ShareDefine.Def_BT_CharmDay                 : 100,           #魅力日榜
             }
 
@@ -754,13 +755,14 @@
 Def_Online = 1
 Def_OnlineNoClient = 2
 
-# 分组 1 最近联系人 2 好友 3 仇人 4 黑名单
+# 分组 1 最近联系人 2 好友 3 仇人 4 黑名单 5 亲密
 (
 Def_SocialGroup_Contacts,
 Def_SocialGroup_Friend,
 Def_SocialGroup_Enemy,
 Def_SocialGroup_Black,
-) = range(1, 5)
+Def_SocialGroup_Intimacy,
+) = range(1, 6)
 
 Def_CDBPlayerRefresh_Online = "OnlineType"
 
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py b/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py
index 8822b65..2486b4e 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py
@@ -2330,6 +2330,66 @@
 
 
 #------------------------------------------------------
+# B3 09 魅力贡献榜查看 #tagCGCharmOfferBillboardQuery
+
+class  tagCGCharmOfferBillboardQuery(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("PlayerID", c_int),    # 魅力玩家ID
+                  ("QueryType", c_ubyte),    # 查看类型: 1-总榜,2-周榜,3-日榜
+                  ("QueryCount", c_ubyte),    # 查看名次数量,最大255
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xB3
+        self.SubCmd = 0x09
+        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 = 0x09
+        self.PlayerID = 0
+        self.QueryType = 0
+        self.QueryCount = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCGCharmOfferBillboardQuery)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// B3 09 魅力贡献榜查看 //tagCGCharmOfferBillboardQuery:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                PlayerID:%d,
+                                QueryType:%d,
+                                QueryCount:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.PlayerID,
+                                self.QueryType,
+                                self.QueryCount
+                                )
+        return DumpString
+
+
+m_NAtagCGCharmOfferBillboardQuery=tagCGCharmOfferBillboardQuery()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCGCharmOfferBillboardQuery.Cmd,m_NAtagCGCharmOfferBillboardQuery.SubCmd))] = m_NAtagCGCharmOfferBillboardQuery
+
+
+#------------------------------------------------------
 # B3 16 和平离婚回应 #tagGCMarryBreakResponse
 
 class  tagGCMarryBreakResponse(Structure):
@@ -4419,15 +4479,17 @@
 
 
 #------------------------------------------------------
-# B3 10 送花 #tagCMSendFlowers
+# B3 10 送礼物 #tagCMSendGifts
 
-class  tagCMSendFlowers(Structure):
+class  tagCMSendGifts(Structure):
     _pack_ = 1
     _fields_ = [
                   ("Cmd", c_ubyte),
                   ("SubCmd", c_ubyte),
                   ("TagPlayerID", c_int),    # 目标玩家ID
-                  ("FlowerCount", c_int),    # 赠送花数量
+                  ("GiftNum", c_ushort),    # 赠送礼物编号
+                  ("GiftCount", c_int),    # 赠送礼物数量
+                  ("IsAutoBuy", c_ubyte),    # 是否自动购买
                   ]
 
     def __init__(self):
@@ -4445,33 +4507,39 @@
         self.Cmd = 0xB3
         self.SubCmd = 0x10
         self.TagPlayerID = 0
-        self.FlowerCount = 0
+        self.GiftNum = 0
+        self.GiftCount = 0
+        self.IsAutoBuy = 0
         return
 
     def GetLength(self):
-        return sizeof(tagCMSendFlowers)
+        return sizeof(tagCMSendGifts)
 
     def GetBuffer(self):
         return string_at(addressof(self), self.GetLength())
 
     def OutputString(self):
-        DumpString = '''// B3 10 送花 //tagCMSendFlowers:
+        DumpString = '''// B3 10 送礼物 //tagCMSendGifts:
                                 Cmd:%s,
                                 SubCmd:%s,
                                 TagPlayerID:%d,
-                                FlowerCount:%d
+                                GiftNum:%d,
+                                GiftCount:%d,
+                                IsAutoBuy:%d
                                 '''\
                                 %(
                                 self.Cmd,
                                 self.SubCmd,
                                 self.TagPlayerID,
-                                self.FlowerCount
+                                self.GiftNum,
+                                self.GiftCount,
+                                self.IsAutoBuy
                                 )
         return DumpString
 
 
-m_NAtagCMSendFlowers=tagCMSendFlowers()
-ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMSendFlowers.Cmd,m_NAtagCMSendFlowers.SubCmd))] = m_NAtagCMSendFlowers
+m_NAtagCMSendGifts=tagCMSendGifts()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMSendGifts.Cmd,m_NAtagCMSendGifts.SubCmd))] = m_NAtagCMSendGifts
 
 
 #------------------------------------------------------
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/BillboardData.py b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/BillboardData.py
index 952bf23..00735e4 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/BillboardData.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/BillboardData.py
@@ -28,6 +28,7 @@
     GameWorld.DebugAnswer(curPlayer, "榜单类型:0-战力,1-龙魂,2-灵瑶,4-等级,5-坐骑,6-灵宠,7-符印,8-脱机,9-境界,19-助战")
     GameWorld.DebugAnswer(curPlayer, "开服活动榜类型:11-强化,12-坐骑,13-宝石,14-冲级,15-境界,16-战力,18-符印,20-神兵,21-充值,22-灵宠,24-灵根,25-升星")
     GameWorld.DebugAnswer(curPlayer, "运营活动榜类型:17-仙界盛典,23-仙界盛典2")
+    GameWorld.DebugAnswer(curPlayer, "魅力榜单类型:30-总榜,31-周榜,31-日榜")
     return
 
 ## 执行逻辑
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/Charm.py b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/Charm.py
new file mode 100644
index 0000000..cb3cbb3
--- /dev/null
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/Charm.py
@@ -0,0 +1,74 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package GM.Commands.Charm
+#
+# @todo:魅力
+# @author hxp
+# @date 2021-11-17
+# @version 1.0
+#
+# 详细描述: 魅力
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2021-11-17 15:00"""
+#-------------------------------------------------------------------------------
+
+import GameWorld
+import PlayerCharm
+
+def __Help(curPlayer):
+    GameWorld.DebugAnswer(curPlayer, "---------- %s" % GameWorld.GetCurrentDataTimeStr())
+    GameWorld.DebugAnswer(curPlayer, "清空魅力: Charm 0")
+    GameWorld.DebugAnswer(curPlayer, "随机魅力: Charm 1 人数  贡献人数 [选填 随机范围值A B]")
+    GameWorld.DebugAnswer(curPlayer, "随机范围值不填的话默认10~1000")
+    GameWorld.DebugAnswer(curPlayer, "增加魅力: Charm 2 数值 [选填 贡献玩家ID 获得玩家ID]")
+    GameWorld.DebugAnswer(curPlayer, "玩家ID不填的话均默认自己")
+    return
+
+#逻辑实现
+## 执行逻辑
+#  @param curPlayer 当前玩家
+#  @param gmList [cmdIndex gmAccID msg]
+#  @return None
+#  @remarks 函数详细说明.
+def OnExec(curPlayer, gmList):
+    
+    if not gmList:
+        __Help(curPlayer)
+        return
+    
+    value1 = gmList[0]
+    # 清空魅力
+    if value1 == 0:
+        PlayerCharm.GMClearCharm()
+    # 随机魅力
+    elif value1 == 1 and len(gmList) >= 3:
+        playerCount = gmList[1]
+        offerCount = gmList[2]
+        randA = gmList[3] if len(gmList) > 3 else 10
+        randB = gmList[4] if len(gmList) > 4 else 1000
+        PlayerCharm.GMRandCharm(curPlayer, playerCount, offerCount, randA, randB)
+    # 增加魅力
+    elif value1 == 2 and len(gmList) >= 2:
+        addValue = gmList[1]
+        offerPlayerID = gmList[2] if len(gmList) > 2 else curPlayer.GetPlayerID()
+        addPlayerID = gmList[3] if len(gmList) > 3 else curPlayer.GetPlayerID()
+        
+        addPlayer = None
+        if addPlayerID == curPlayer.GetPlayerID():
+            addPlayer = curPlayer
+        elif addPlayerID >= 10000:
+            addPlayer = GameWorld.GetPlayerManager().FindPlayerByID(addPlayerID)
+        PlayerCharm.AddCharm(addPlayer, addPlayerID, offerPlayerID, addValue)
+        GameWorld.DebugAnswer(curPlayer, "增加玩家[ %s ]魅力:%s, 贡献者[ %s ]" % (addPlayerID, addValue, offerPlayerID))
+    else:
+        __Help(curPlayer)
+        return
+    
+    return
+
+
+
+
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/Couple.py b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/Couple.py
new file mode 100644
index 0000000..f5164e8
--- /dev/null
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/Couple.py
@@ -0,0 +1,128 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package GM.Commands.Couple
+#
+# @todo:伴侣
+# @author hxp
+# @date 2021-11-17
+# @version 1.0
+#
+# 详细描述: 伴侣
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2021-11-17 15:00"""
+#-------------------------------------------------------------------------------
+
+import GameWorld
+import PyDataManager
+import PlayerLove
+import PyGameData
+
+import time
+
+def __Help(curPlayer):
+    GameWorld.DebugAnswer(curPlayer, "---------- %s" % GameWorld.GetCurrentDataTimeStr())
+    GameWorld.DebugAnswer(curPlayer, "清除伴侣: Couple 0")
+    GameWorld.DebugAnswer(curPlayer, "重置聘礼: Couple 0 1")
+    GameWorld.DebugAnswer(curPlayer, "设置伴侣: Couple 1 目标ID [可选聘礼ID]")
+    GameWorld.DebugAnswer(curPlayer, "设亲密度: Couple 2 目标ID 亲密度")
+    GameWorld.DebugAnswer(curPlayer, "增加密度: Couple 3 目标ID 亲密度")
+    return
+
+#逻辑实现
+## 执行逻辑
+#  @param curPlayer 当前玩家
+#  @param gmList [cmdIndex gmAccID msg]
+#  @return None
+#  @remarks 函数详细说明.
+def OnExec(curPlayer, gmList):
+    
+    if not gmList:
+        __Help(curPlayer)
+        return
+    
+    playerID = curPlayer.GetPlayerID()
+    coupleMgr = PyDataManager.GetDBPyCoupleManager()
+    couple = coupleMgr.GetCouple(playerID)
+    
+    value1 = gmList[0]
+    if value1 == 0:
+        # 离婚
+        if len(gmList) == 1:
+            PlayerLove.__DoMarryBreakLogic(couple, playerID)
+            GameWorld.DebugAnswer(curPlayer, "清除伴侣OK!")
+            return
+        
+        value2 = gmList[1]
+        # 重置聘礼
+        if value2 == 1:
+            if not couple:
+                GameWorld.DebugAnswer(curPlayer, "没有伴侣!")
+                return
+            couple.coupleData.BridePriceState = 0
+            PlayerLove.Sync_CoupleInfo(curPlayer)
+            GameWorld.DebugAnswer(curPlayer, "重置聘礼OK!")
+            
+        return
+    
+    # 设置伴侣
+    elif value1 == 1:
+        if couple:
+            GameWorld.DebugAnswer(curPlayer, "已有伴侣! coupleID=%s" % couple.GetCoupleID(playerID))
+            return
+        tagPlayerID = gmList[1] if len(gmList) > 1 else 0
+        if not tagPlayerID or tagPlayerID == playerID:
+            GameWorld.DebugAnswer(curPlayer, "非法伴侣玩家ID:%s,playerID=%s" % (tagPlayerID, playerID))
+            return
+        tagCouple = coupleMgr.GetCouple(tagPlayerID)
+        if tagCouple:
+            GameWorld.DebugAnswer(curPlayer, "对方已有伴侣! tagCoupleID=%s" % tagCouple.GetCoupleID(tagPlayerID))
+            return
+        
+        bridePriceID = gmList[2] if len(gmList) > 2 else 1
+        
+        reqData = PlayerLove.MarryReq()
+        reqData.playerIDA = tagPlayerID
+        reqData.playerIDB = playerID
+        reqData.bridePriceID = bridePriceID
+        reqData.reqTime = int(time.time())
+        PyGameData.g_marryReqInfo[tagPlayerID] = reqData
+        
+        reqPlayer = GameWorld.GetPlayerManager().FindPlayerByID(tagPlayerID)
+        isOK = PlayerLove.__DoMarryResponse(curPlayer, reqPlayer, tagPlayerID, 1)
+        GameWorld.DebugAnswer(curPlayer, "设置伴侣【%s】 %s" % (tagPlayerID, isOK))
+        return
+    
+    # 设置亲密度
+    elif value1 == 2 and len(gmList) >= 3:
+        tagPlayerID = gmList[1]
+        setValue = gmList[2]
+        if not tagPlayerID or tagPlayerID == playerID:
+            GameWorld.DebugAnswer(curPlayer, "玩家ID不能设置亲密度:%s,playerID=%s" % (tagPlayerID, playerID))
+            return
+        intimacys = PyDataManager.GetIntimacyManager().GetIntimacys(playerID)
+        updIntimacy = intimacys.SetIntimacy(curPlayer, tagPlayerID, setValue)
+        GameWorld.DebugAnswer(curPlayer, "设置目标【%s】亲密度: %s" % (tagPlayerID, updIntimacy))
+        
+    # 增加亲密度
+    elif value1 == 3 and len(gmList) >= 3:
+        tagPlayerID = gmList[1]
+        addValue = gmList[2]
+        if not tagPlayerID or tagPlayerID == playerID:
+            GameWorld.DebugAnswer(curPlayer, "玩家ID不能增加亲密度:%s,playerID=%s" % (tagPlayerID, playerID))
+            return
+        PyDataManager.GetIntimacyManager().AddIntimacyBoth(playerID, tagPlayerID, addValue)
+        intimacys = PyDataManager.GetIntimacyManager().GetIntimacys(playerID)
+        if intimacys:
+            GameWorld.DebugAnswer(curPlayer, "更新目标【%s】亲密度: %s" % (tagPlayerID, intimacys.GetTagIntimacy(tagPlayerID)))     
+    else:
+        __Help(curPlayer)
+        return
+    
+    return
+
+
+
+
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/Friend.py b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/Friend.py
deleted file mode 100644
index 5c0576d..0000000
--- a/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/Friend.py
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/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/GameWorld.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py
index 8fc20e4..40c7c07 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py
@@ -996,6 +996,49 @@
     rate = random.randint(1, randList[-1][0])
     return GetResultByRiseList(randList, rate)
 
+## 获得对应数位的值
+#  @param numValue 数值
+#  @param dataIndex 数位索引
+#  @return 获得的值 
+def GetDataByDigitPlace(numValue, dataIndex):
+    return (numValue/pow(10, dataIndex))%10
+    
+
+## 设置对应数位的值
+#  @param numValue 数值
+#  @param dataIndex 数位索引
+#  @param dataValue 当前修改数值
+#  @return 获得的值 
+def ChangeDataByDigitPlace(numValue, dataIndex, dataValue):
+    
+    if dataValue < 0 or dataValue > 9 or dataIndex > ShareDefine.Def_PDictDigitCnt:
+        return numValue
+    
+    # 获得对应数位的值
+    lastTagLV = GetDataByDigitPlace(numValue, dataIndex)
+    
+    numValue += pow(10, dataIndex)*(dataValue - lastTagLV)
+    return numValue
+
+def GetBitValue(dataValue, index):
+    """ 得到某个字节值中某一位(Bit)的值
+    @param dataValue: 待取值的字节值
+    @param index: 待读取位的序号,从右向左0开始,0-7为一个完整字节的8个位
+    @return: 返回读取该位的值,0或1
+    """
+    return 1 if dataValue & (1 << index) else 0
+
+def SetBitValue(dataValue, index, val):
+    """ 更改某个字节值中某一位(Bit)的值
+    @param dataValue: 准备更改的字节原值
+    @param index: 待更改位的序号,从右向左0开始,0-7为一个完整字节的8个位
+    @param val: 目标位预更改的值,0或1
+    @return: 返回更改后字节的值
+    """
+    if val:
+        return dataValue | (1 << index)
+    return dataValue & ~(1 << index)
+
 ## 根据字典key获取value值
 #  @return 
 def GetDictValueByKey(attrDict, findKey, defaultValue=None):
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py b/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py
index 4cde1f6..9972bfd 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py
@@ -708,8 +708,18 @@
                         ("dict", "Award", 0),
                         ),
 
+                "LoveGift":(
+                        ("BYTE", "GiftNum", 1),
+                        ("DWORD", "AddCharmSelf", 0),
+                        ("DWORD", "AddCharmTag", 0),
+                        ("DWORD", "AddIntimacy", 0),
+                        ("char", "WorldNotifyKey", 0),
+                        ),
+
                 "Marry":(
                         ("BYTE", "BridePriceID", 1),
+                        ("BYTE", "CanBuyCount", 0),
+                        ("BYTE", "IsDayReset", 0),
                         ("DWORD", "Prosperity", 0),
                         ("WORD", "CandyTimes", 0),
                         ("list", "CandyItemInfo", 0),
@@ -2195,11 +2205,30 @@
     def GetRank(self): return self.Rank # 排名
     def GetAward(self): return self.Award # 奖励 {"职业":[[物品ID,个数,是否绑定],...], ...}
 
+# 情缘礼物表
+class IPY_LoveGift():
+    
+    def __init__(self):
+        self.GiftNum = 0
+        self.AddCharmSelf = 0
+        self.AddCharmTag = 0
+        self.AddIntimacy = 0
+        self.WorldNotifyKey = ""
+        return
+        
+    def GetGiftNum(self): return self.GiftNum # 聘礼ID
+    def GetAddCharmSelf(self): return self.AddCharmSelf # 单个增加自身魅力
+    def GetAddCharmTag(self): return self.AddCharmTag # 单个增加对方魅力
+    def GetAddIntimacy(self): return self.AddIntimacy # 单个增加双方亲密度
+    def GetWorldNotifyKey(self): return self.WorldNotifyKey # 广播key
+
 # 情缘提亲表
 class IPY_Marry():
     
     def __init__(self):
         self.BridePriceID = 0
+        self.CanBuyCount = 0
+        self.IsDayReset = 0
         self.Prosperity = 0
         self.CandyTimes = 0
         self.CandyItemInfo = []
@@ -2208,6 +2237,8 @@
         return
         
     def GetBridePriceID(self): return self.BridePriceID # 聘礼ID
+    def GetCanBuyCount(self): return self.CanBuyCount # 可购买次数
+    def GetIsDayReset(self): return self.IsDayReset # 是否每日重置
     def GetProsperity(self): return self.Prosperity # 初始繁荣度
     def GetCandyTimes(self): return self.CandyTimes # 喜糖持续时间秒
     def GetCandyItemInfo(self): return self.CandyItemInfo # 喜糖物品列表[[物品ID,个数,是否拍品], ...]
@@ -2493,6 +2524,8 @@
         self.ipyActNewFairyCeremonyLen = len(self.ipyActNewFairyCeremonyCache)
         self.ipyNewUniquenessArriveCache = self.__LoadFileData("NewUniquenessArrive", IPY_NewUniquenessArrive)
         self.ipyNewUniquenessArriveLen = len(self.ipyNewUniquenessArriveCache)
+        self.ipyLoveGiftCache = self.__LoadFileData("LoveGift", IPY_LoveGift)
+        self.ipyLoveGiftLen = len(self.ipyLoveGiftCache)
         self.ipyMarryCache = self.__LoadFileData("Marry", IPY_Marry)
         self.ipyMarryLen = len(self.ipyMarryCache)
         self.ipyActLuckyTreasureCache = self.__LoadFileData("ActLuckyTreasure", IPY_ActLuckyTreasure)
@@ -2799,6 +2832,8 @@
     def GetActNewFairyCeremonyByIndex(self, index): return self.ipyActNewFairyCeremonyCache[index]
     def GetNewUniquenessArriveCount(self): return self.ipyNewUniquenessArriveLen
     def GetNewUniquenessArriveByIndex(self, index): return self.ipyNewUniquenessArriveCache[index]
+    def GetLoveGiftCount(self): return self.ipyLoveGiftLen
+    def GetLoveGiftByIndex(self, index): return self.ipyLoveGiftCache[index]
     def GetMarryCount(self): return self.ipyMarryLen
     def GetMarryByIndex(self, index): return self.ipyMarryCache[index]
     def GetActLuckyTreasureCount(self): return self.ipyActLuckyTreasureLen
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py
index 80ab4f7..1a784f9 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py
@@ -67,6 +67,7 @@
 import PlayerAssist
 import PlayerFB
 import PlayerLove
+import PlayerCharm
 #---------------------------------------------------------------------
 
 #---------------------------------------------------------------------
@@ -212,6 +213,8 @@
     if not PlayerControl.GetIsTJG(curPlayer):
         #家族副本boss状态通知
         PlayerFamilyBoss.OnLogin(curPlayer)
+        #魅力
+        PlayerCharm.OnPlayerLogin(curPlayer)
         #情缘
         PlayerLove.OnPlayerLogin(curPlayer)
         
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerBillboard.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerBillboard.py
index 586d56e..088920e 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerBillboard.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerBillboard.py
@@ -26,8 +26,11 @@
 import NetPackCommon
 import DataRecordPack
 import PlayerFamily
+import PyDataManager
+import PlayerViewCache
 
 import time
+import random
 
 Def_Key_BillboardSortTick = "BillboardSortTick_%s" # 排行榜是否排序tick,参数(排行榜类型)
 Def_Key_BillboardNeedSort = "BillboardNeedSort_%s" # 排行榜是否需要排序,参数(排行榜类型)
@@ -522,6 +525,53 @@
     #GameWorld.DebugLog("__UpdateBillboardSortState:bType=%s,autoSort=%s,isUpd=%s,needSort=%s" % (bType, autoSort, isUpd, gameWorld.GetDictByKey(key)))
     return
 
+def GetBillboardOperateInfo(curPlayer):
+    # 排行榜中所保存的运营商相关信息
+    platform = curPlayer.GetAccID()
+    if platform in ["tencent"]:
+        return curPlayer.GetOperateInfo()
+    return platform
+
+def UpdatePlayerBillboardEx(curPlayer, playerID, bType, cmpValue, cmpValue2=0, cmpValue3=0, value1=0, value2=0, autoSort=False):
+    ## 更新玩家排行榜
+    # @param curPlayer: 可能为None
+    
+    playerOpInfo = ""
+    playerJob = 0
+    playerName = ""
+    playerRealmLV = 0
+    
+    if curPlayer:
+        playerID = curPlayer.GetID()
+        playerJob = curPlayer.GetJob()
+        playerName = curPlayer.GetName()
+        playerRealmLV = curPlayer.GetOfficialRank()
+        playerOpInfo = GetBillboardOperateInfo(curPlayer)
+    else:
+        socialPlayer = PyDataManager.GetPersonalSocialManager().GetSocialPlayer(playerID)
+        if socialPlayer:
+            playerJob = socialPlayer.playerInfo.Job
+            playerName = socialPlayer.playerInfo.PlayerName
+            playerRealmLV = socialPlayer.playerInfo.RealmLV
+        else:
+            curCache = PlayerViewCache.FindViewCache(playerID)
+            if curCache:
+                cacheDict = PlayerViewCache.GetCachePropDataDict(curCache)
+                playerJob = cacheDict["Job"]
+                playerName = cacheDict["Name"]
+                playerRealmLV = cacheDict["RealmLV"]
+                
+    if not playerName and playerID < 10000:
+        playerJob = random.choice([1, 2])
+        playerName = "testName%s" % playerID
+        playerRealmLV = random.randint(1, 10)
+        
+    if bType in ShareDefine.BTValue1_OfficialRankList:
+        value1 = playerRealmLV
+            
+    UpdatePlayerBillboard(playerID, playerName, playerOpInfo, bType, playerJob, value1, value2, cmpValue, autoSort, cmpValue2, cmpValue3)
+    return
+
 #---------------------------------------------------------------------
 #===============================================================================
 #    void        SetType(int inputType);    //_I_KEY_INDEX_排行榜类型
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerCharm.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerCharm.py
new file mode 100644
index 0000000..0a8e7f9
--- /dev/null
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerCharm.py
@@ -0,0 +1,299 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package PlayerCharm
+#
+# @todo:魅力系统
+# @author hxp
+# @date 2021-11-17
+# @version 1.0
+#
+# 详细描述: 魅力系统
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2021-11-17 15:00"""
+#-------------------------------------------------------------------------------
+
+import CommFunc
+import ShareDefine
+import PlayerControl
+import ChPyNetSendPack
+import PyGameDataStruct
+import PlayerBillboard
+import NetPackCommon
+import PyDataManager
+import PlayerSocial
+import GameWorld
+
+import operator
+import random
+import time
+
+CharmValueRecTypeList = (
+CharmValueRecType_Total, # 总 - 1
+CharmValueRecType_Week, # 周 - 2
+CharmValueRecType_Day, # 日 - 3
+) = range(1, 1 + 3)
+    
+class DBPyCharmValueRecManager(object):
+    ## 魅力贡献记录管理
+    
+    def __init__(self):
+        self.charmValueRecDict = {} # 魅力贡献记录字典 {playerID:{recType:{offerPlayerID:PyGameDataStruct.tagDBPyCharmValueRec, ...}, ...}}
+        self.charmTotalDict = {} # 总魅力  {playerID:{recType:totalCharm, ...}, ...}
+        self.charmSortListDict = {} # 排序后的贡献记录 {playerID:{recType:[PyGameDataStruct.tagDBPyCharmValueRec, ...], ...}}
+        return
+    
+    def ClearCharmByType(self, recType):
+        for recTypeDict in self.charmValueRecDict.values():
+            recTypeDict.pop(recType, None)
+            
+        for recTypeDict in self.charmTotalDict.values():
+            recTypeDict.pop(recType, None)
+            
+        for recTypeDict in self.charmSortListDict.values():
+            recTypeDict.pop(recType, None)
+        return
+    
+    # 保存数据 存数据库和realtimebackup
+    def GetSaveData(self):
+        savaData = ""
+        cntData = ""
+        cnt = 0
+        
+        for recTypeDict in self.charmValueRecDict.values():
+            for offerPlayerDict in recTypeDict.values():
+                for recData in offerPlayerDict.values():
+                    cnt += 1
+                    savaData += recData.getBuffer()
+                
+        GameWorld.Log("Save DBPyCharmValueRec count :%s len=%s" % (cnt, len(savaData)))
+        return CommFunc.WriteDWORD(cntData, cnt) + savaData
+    
+    # 从数据库载入数据
+    def LoadPyGameData(self, datas, pos, dataslen):
+        cnt, pos = CommFunc.ReadDWORD(datas, pos)
+        GameWorld.Log("Load DBPyCharmValueRec count :%s" % cnt)
+        
+        for _ in xrange(cnt):
+            recData = PyGameDataStruct.tagDBPyCharmValueRec()
+            recData.clear()
+            pos += recData.readData(datas, pos, dataslen)
+            
+            playerID = recData.PlayerID
+            recType = recData.Type
+            offerPlayerID = recData.OfferPlayerID
+            
+            if playerID not in self.charmValueRecDict:
+                self.charmValueRecDict[playerID] = {}
+            recTypeDataDict = self.charmValueRecDict[playerID]
+            if recType not in recTypeDataDict:
+                recTypeDataDict[recType] = {}
+            offerPlayerDict = recTypeDataDict[recType]
+            offerPlayerDict[offerPlayerID] = recData
+            
+            if playerID not in self.charmTotalDict:
+                self.charmTotalDict[playerID] = {}
+            recTypeValueDict = self.charmTotalDict[playerID]
+            recTypeValueDict[recType] = recTypeValueDict.get(recType, 0) + recData.CharmValue
+            
+        return pos
+    
+def DoOnWeek():
+    PlayerBillboard.ClearBillboardByIndex(ShareDefine.Def_BT_CharmWeek)
+    PyDataManager.GetDBPyCharmValueRecManager().ClearCharmByType(CharmValueRecType_Week)
+    playerManager = GameWorld.GetPlayerManager()
+    for i in xrange(playerManager.GetActivePlayerCount()):
+        curPlayer = playerManager.GetActivePlayerAt(i)
+        if not curPlayer or PlayerControl.GetIsTJG(curPlayer):
+            continue
+        Sync_PlayerCharmInfo(curPlayer)
+    return
+
+def DoOnDay():
+    PlayerBillboard.ClearBillboardByIndex(ShareDefine.Def_BT_CharmDay)
+    PyDataManager.GetDBPyCharmValueRecManager().ClearCharmByType(CharmValueRecType_Day)
+    playerManager = GameWorld.GetPlayerManager()
+    for i in xrange(playerManager.GetActivePlayerCount()):
+        curPlayer = playerManager.GetActivePlayerAt(i)
+        if not curPlayer or PlayerControl.GetIsTJG(curPlayer):
+            continue
+        Sync_PlayerCharmInfo(curPlayer)
+    return
+
+def OnPlayerLogin(curPlayer):
+    Sync_PlayerCharmInfo(curPlayer)
+    return
+
+def GetPlayerCharmOfferSortList(playerID, recType):
+    ## 获取排序后的玩家魅力贡献榜
+    
+    charmValueRecMgr = PyDataManager.GetDBPyCharmValueRecManager()
+    if playerID not in charmValueRecMgr.charmValueRecDict:
+        return []
+    recTypeDataDict = charmValueRecMgr.charmValueRecDict[playerID]
+    if recType not in recTypeDataDict:
+        return []
+    offerPlayerDict = recTypeDataDict[recType]
+    
+    if playerID not in charmValueRecMgr.charmSortListDict:
+        charmValueRecMgr.charmSortListDict[playerID] = {}
+    recTypeSortListDict = charmValueRecMgr.charmSortListDict[playerID]
+    if recType not in recTypeSortListDict:
+        # 排序
+        recDataList = offerPlayerDict.values()
+        recDataList.sort(key=operator.attrgetter("CharmValue", "UpdTime"), reverse=True)
+        recTypeSortListDict[recType] = recDataList
+        
+    return recTypeSortListDict[recType]
+
+def AddCharm(curPlayer, playerID, offerPlayerID, addValue, isNotify=True):
+    ''' 添加魅力
+    @param curPlayer: 增加魅力的玩家实例,可能为None
+    @param offerPlayerID: 魅力贡献玩家ID
+    @param addValue: 增加魅力值
+    '''
+    
+    charmValueRecMgr = PyDataManager.GetDBPyCharmValueRecManager()
+    if playerID not in charmValueRecMgr.charmValueRecDict:
+        charmValueRecMgr.charmValueRecDict[playerID] = {}
+    recTypeDataDict = charmValueRecMgr.charmValueRecDict[playerID]
+    
+    if playerID not in charmValueRecMgr.charmTotalDict:
+        charmValueRecMgr.charmTotalDict[playerID] = {}
+    recTypeValueDict = charmValueRecMgr.charmTotalDict[playerID]
+    
+    updTime = max(0, GameWorld.ChangeTimeStrToNum("2090-01-01 00:00:00") - int(time.time())) # 用于倒序排序
+    for recType in CharmValueRecTypeList:
+        if recType not in recTypeDataDict:
+            recTypeDataDict[recType] = {}
+        offerPlayerDict = recTypeDataDict[recType]
+        
+        if offerPlayerID not in offerPlayerDict:
+            offerPlayerDict[offerPlayerID] = PyGameDataStruct.tagDBPyCharmValueRec()
+        recData = offerPlayerDict[offerPlayerID]
+        
+        curValue = recData.CharmValue
+        recData.PlayerID = playerID
+        recData.Type = recType
+        recData.OfferPlayerID = offerPlayerID
+        recData.CharmValue += addValue
+        recData.UpdTime = updTime
+        
+        typeTotalValue = recTypeValueDict.get(recType, 0)
+        recTypeValueDict[recType] = typeTotalValue + addValue
+        
+        GameWorld.DebugLog("增加魅力记录: playerID=%s,recType=%s,offerPlayerID=%s,addValue=%s,updValue=(%s-%s),updTime=%s,typeTotalValue=(%s-%s)" 
+                           % (playerID, recType, offerPlayerID, addValue, curValue, recData.CharmValue, updTime, typeTotalValue, recTypeValueDict[recType]), playerID)
+        
+    # 榜单
+    charmTotal = recTypeValueDict.get(CharmValueRecType_Total, 0)
+    charmWeek = recTypeValueDict.get(CharmValueRecType_Week, 0)
+    charmDay = recTypeValueDict.get(CharmValueRecType_Day, 0)
+    PlayerBillboard.UpdatePlayerBillboardEx(curPlayer, playerID, ShareDefine.Def_BT_CharmTotal, charmTotal)
+    PlayerBillboard.UpdatePlayerBillboardEx(curPlayer, playerID, ShareDefine.Def_BT_CharmWeek, charmWeek)
+    PlayerBillboard.UpdatePlayerBillboardEx(curPlayer, playerID, ShareDefine.Def_BT_CharmDay, charmDay)
+    
+    charmValueRecMgr.charmSortListDict.pop(playerID, None) # 数据变更时移除,下次用到时再重新排序生成
+    
+    if not curPlayer:
+        return
+    
+    if not isNotify:
+        return
+    
+    PlayerControl.NotifyCode(curPlayer, "AddCharm", [addValue])
+    Sync_PlayerCharmInfo(curPlayer)
+    return
+
+def Sync_PlayerCharmInfo(curPlayer, isForce=False):
+    ## 同步魅力信息
+    playerID = curPlayer.GetPlayerID()
+    charmValueRecMgr = PyDataManager.GetDBPyCharmValueRecManager()
+    if playerID not in charmValueRecMgr.charmTotalDict and not isForce:
+        return
+    recTypeValueDict = charmValueRecMgr.charmTotalDict.get(playerID, {})
+    clientPack = ChPyNetSendPack.tagGCPlayerCharmValueInfo()
+    clientPack.CharmValueTotal = recTypeValueDict.get(CharmValueRecType_Total, 0)
+    clientPack.CharmValueWeek = recTypeValueDict.get(CharmValueRecType_Week, 0)
+    clientPack.CharmValueDay = recTypeValueDict.get(CharmValueRecType_Day, 0)
+    NetPackCommon.SendFakePack(curPlayer, clientPack)
+    return
+
+#// B3 09 魅力贡献榜查看 #tagCGCharmOfferBillboardQuery
+#
+#struct    tagCGCharmOfferBillboardQuery
+#{
+#    tagHead        Head;
+#    DWORD        PlayerID;        // 魅力玩家ID
+#    BYTE        QueryType;    // 查看类型: 1-总榜,2-周榜,3-日榜
+#    BYTE        QueryCount;    // 查看名次数量,最大255
+#};
+def OnCharmOfferBillboardQuery(index, clientData, tick):
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    tagPlayerID = clientData.PlayerID
+    queryType = clientData.QueryType
+    queryCount = min(clientData.QueryCount, 255)
+    
+    sortList = GetPlayerCharmOfferSortList(tagPlayerID, queryType)
+    clientPack = ChPyNetSendPack.tagGCCharmOfferBillboardDataList()
+    clientPack.PlayerID = tagPlayerID
+    clientPack.QueryType = queryType
+    clientPack.OfferBillboardDataList = []
+    for i, recData in enumerate(sortList[:queryCount]):
+        billboardData = ChPyNetSendPack.tagGCCharmOfferBillboardData()
+        billboardData.OrderIndex = i
+        billboardData.PlayerID = recData.OfferPlayerID
+        billboardData.PlayerName = PlayerSocial.GetSocialPlayerName(billboardData.PlayerID)
+        billboardData.NameLen = len(billboardData.PlayerName)
+        billboardData.CharmValue = recData.CharmValue
+        clientPack.OfferBillboardDataList.append(billboardData)
+    clientPack.DataCount = len(clientPack.OfferBillboardDataList)
+    NetPackCommon.SendFakePack(curPlayer, clientPack)
+    return
+
+
+def GMClearCharm():
+    ## GM清空魅力
+    GameWorld.Log("GM清空魅力")
+    charmValueRecMgr = PyDataManager.GetDBPyCharmValueRecManager()
+    charmValueRecMgr.charmValueRecDict = {}
+    charmValueRecMgr.charmTotalDict = {}
+    charmValueRecMgr.charmSortListDict = {}
+    playerManager = GameWorld.GetPlayerManager()
+    for i in xrange(playerManager.GetActivePlayerCount()):
+        curPlayer = playerManager.GetActivePlayerAt(i)
+        if not curPlayer or PlayerControl.GetIsTJG(curPlayer):
+            continue
+        Sync_PlayerCharmInfo(curPlayer, True)
+    GameWorld.DebugAnswer(curPlayer, "GM清空魅力OK")
+    return
+
+def GMRandCharm(curPlayer, playerCount, offerCount, randA, randB):
+    ## GM随机增加魅力数据
+    GameWorld.Log("GM随机增加魅力数据: playerCount=%s,offerCount=%s,randA=%s,randB=%s" % (playerCount, offerCount, randA, randB))
+    playerDict = {}
+    playerManager = GameWorld.GetPlayerManager()
+    for i in xrange(playerManager.GetActivePlayerCount()):
+        player = playerManager.GetActivePlayerAt(i)
+        if not player or PlayerControl.GetIsTJG(player):
+            continue
+        playerDict[player.GetPlayerID()] = player
+        
+    playerCount = min(1000, playerCount)
+    if len(playerDict) < playerCount:
+        lackCount = playerCount - len(playerDict)
+        for testPlayerID in xrange(1000, 1000 + lackCount):
+            playerDict[testPlayerID] = None
+            
+    for playerID, player in playerDict.items():
+        for offerPlayerID in xrange(2000, 2000 + offerCount):
+            addValue = random.randint(randA, randB)
+            AddCharm(player, playerID, offerPlayerID, addValue, False)
+        if player:
+            Sync_PlayerCharmInfo(player)
+            
+    GameWorld.DebugAnswer(curPlayer, "GM随机增加魅力数据OK") 
+    return
+
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py
index 23577f7..47564b2 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py
@@ -247,10 +247,6 @@
 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/PlayerEventCounter.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerEventCounter.py
index 8390752..24c18df 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerEventCounter.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerEventCounter.py
@@ -31,6 +31,7 @@
 import GameWorldArena
 import NetPackCommon
 import PlayerDuJie
+import PlayerCharm
 #---------------------------------------------------------------------
 
 #---------------------------------------------------------------------
@@ -57,6 +58,8 @@
     if isMixServer:
         PlayerDBGSEvent.SetDBGSTrig_ServerTime(PlayerDBGSEvent.Def_MixServerDay)
     
+    #魅力
+    PlayerCharm.DoOnDay()
     #家族更新
     PlayerFamily.FamilyOnDay(tick)
     
@@ -103,6 +106,8 @@
     #设定服务器当前周事件
     PlayerDBGSEvent.SetDBGSTrig_ServerTime(PlayerDBGSEvent.Def_ServerWeek)
     
+    #魅力
+    PlayerCharm.DoOnWeek()
     #家族更新
     PlayerFamily.FamilyOnWeek(tick)
     
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFriend.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFriend.py
index c971cf3..f8cadde 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFriend.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFriend.py
@@ -214,9 +214,9 @@
         GameWorld.Log('DeleteFriend -> 封包异常 ->没有这个玩家', playerID)
         return
     
-    coupleID = PlayerControl.GetCoupleID(curPlayer)
-    if coupleID == friendID:
-        GameWorld.Log('DeleteFriend -> 封包异常 ->伴侣不能删除好友,coupleID=%s' % coupleID, playerID)
+    couple = PyDataManager.GetDBPyCoupleManager().GetCouple(playerID)
+    if couple and couple.GetCoupleID(playerID) == friendID:
+        GameWorld.Log('DeleteFriend -> 封包异常 ->伴侣不能删除好友.friendID=%s' % friendID, playerID)
         return
     
     #离线好友同时删除记录
@@ -229,6 +229,12 @@
     if tagPlayer != None:
         PlayerControl.NotifyCode(tagPlayer, 'Friend_DeleteFriend2', [curPlayer.GetName()])
     PlayerTeam.OnTeamMemFriendChange(curPlayer, friendID, False)
+    
+    # 亲密度减少
+    decIntimacyPer = IpyGameDataPY.GetFuncCfg("IntimacyReduce", 1)
+    if decIntimacyPer:
+        PyDataManager.GetIntimacyManager().DelIntimacyBothPer(playerID, friendID, decIntimacyPer)
+        
     return
 
 
@@ -394,7 +400,8 @@
     #    return
     #===========================================================================
     
-    if tagID == PlayerControl.GetCoupleID(curPlayer):
+    couple = PyDataManager.GetDBPyCoupleManager().GetCouple(curPlayer.GetID())
+    if couple and couple.GetCoupleID(curPlayer.GetID()) == tagID:
         GameWorld.DebugLog("伴侣不能加入黑名单! tagID=%s" % tagID, curPlayer.GetID())
         return
     
@@ -419,6 +426,11 @@
     
     PlayerControl.NotifyCode(curPlayer, 'AddBlackList', [playerName])
     
+    # 亲密度减少
+    decIntimacyPer = IpyGameDataPY.GetFuncCfg("IntimacyReduce", 2)
+    if decIntimacyPer:
+        PyDataManager.GetIntimacyManager().DelIntimacyBothPer(curPlayer.GetPlayerID(), tagID, decIntimacyPer)
+        
     return
 
 
@@ -482,6 +494,15 @@
     players.Sync_SocialsInfo(curPlayer)
     return
 
+#亲密
+def __OnPlayerLoginIntimacylist(curPlayer, tick):
+    intimacys = PyDataManager.GetIntimacyManager().GetIntimacys(curPlayer.GetID())
+    if intimacys == None:
+        return
+    
+    intimacys.Sync_SocialsInfo(curPlayer)
+    return
+
 ## 玩家登陆
 #  @param curPlayer 当前玩家
 #  @param tick 当前时间
@@ -495,6 +516,7 @@
     __OnPlayerLoginEnemy(curPlayer, tick)
     __OnPlayerLoginContacts(curPlayer, tick)
     __OnPlayerLoginBlacklist(curPlayer, tick)
+    __OnPlayerLoginIntimacylist(curPlayer, tick)
     
     # 向当前玩家通知相关联的所有玩家信息
     PlayerSocial.Sync_AllSocialsInfo(curPlayer)
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerLove.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerLove.py
index 01bc4aa..96c5995 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerLove.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerLove.py
@@ -21,12 +21,14 @@
 import ChPyNetSendPack
 import PlayerCompensation
 import PlayerFamilyRedPacket
-import PlayerBillboard
+import PyGameDataStruct
 import NetPackCommon
 import IpyGameDataPY
 import PlayerSocial
+import PlayerCharm
 import ShareDefine
 import PyGameData
+import CommFunc
 
 import operator
 import time
@@ -58,6 +60,227 @@
         self.playerFreeEatCountDict = {} # 玩家免费吃喜糖次数 {playerID:次数, ...}
         self.fireworksCountDict = {} # 烟花次数信息 {playerID:次数, ...}
         return
+    
+class PlayerCouple():
+    
+    def __init__(self, coupleData):
+        self.coupleData = coupleData # PyGameDataStruct.tagDBPyCouple()
+        
+        # 更新最大聘礼ID
+        self.BridePriceMaxID = 0
+        maxCount = IpyGameDataPY.IPY_Data().GetMarryCount()
+        for index in range(maxCount)[::-1]:
+            ipyData = IpyGameDataPY.IPY_Data().GetMarryByIndex(index)
+            priceID = ipyData.GetBridePriceID()
+            if self.GetBridePriceBuyCount(priceID):
+                self.BridePriceMaxID = priceID
+                break
+        return
+    
+    def GetCoupleID(self, playerID):
+        return self.coupleData.PlayerIDA if (playerID == self.coupleData.PlayerIDB) else self.coupleData.PlayerIDB
+    def GetCoupleName(self, playerID): return PlayerSocial.GetSocialPlayerName(self.GetCoupleID(playerID))
+    def GetCoupleJob(self, playerID): return PlayerSocial.GetSocialPlayerJob(self.GetCoupleID(playerID))
+    def GetNewMarryTime(self): return self.coupleData.NewMarryTime
+    def GetMarryTime(self): return self.coupleData.MarryTime
+    def GetBridePriceState(self): return self.coupleData.BridePriceState
+    def GetBridePriceBuyCount(self, priceID): return GameWorld.GetDataByDigitPlace(self.coupleData.BridePriceState, priceID - 1)
+    def SetBridePriceBuyCount(self, priceID, buyCount):
+        self.coupleData.BridePriceState = GameWorld.ChangeDataByDigitPlace(self.coupleData.BridePriceState, priceID - 1, min(buyCount, 9))
+        return self.coupleData.BridePriceState
+    def GetBreakRequestID(self): return self.coupleData.BreakRequestID
+    def GetBreakRequestTime(self): return self.coupleData.BreakRequestTime
+    def SetBreakRequestID(self, reqID):
+        self.coupleData.BreakRequestID = reqID
+        self.coupleData.BreakRequestTime = 0
+        if reqID > 0:
+            curTime = int(time.time())
+            self.coupleData.BreakRequestTime = curTime
+            if reqID == self.coupleData.PlayerIDA:
+                self.coupleData.BreakRequestTimeA = curTime
+            else:
+                self.coupleData.BreakRequestTimeB = curTime
+        return
+    def GetPlayerBreakRequestTime(self, playerID):
+        return self.coupleData.BreakRequestTimeA if (playerID == self.coupleData.PlayerIDA) else self.coupleData.BreakRequestTimeB
+    def GetSendMapServerCoupleInfo(self, playerID): 
+        coupleID = self.GetCoupleID(playerID)
+        coupleName = self.GetCoupleName(playerID)
+        coupleJob = self.GetCoupleJob(playerID)
+        bridePriceMaxID = self.BridePriceMaxID
+        return coupleID, coupleName, coupleJob, bridePriceMaxID
+    
+class DBPyCoupleManager(object):
+    ## 伴侣数据管理
+    
+    def __init__(self):
+        self.coupleDict = {} # {(playerIDA, playerIDB):PlayerCouple, ...}
+        self.coupleIDDict = {} # {playerID:(playerIDA, playerIDB), ...} # 伴侣对应关系
+        return
+    
+    def DelCouple(self, playerIDA, playerIDB):
+        ## 删除伴侣数据,如果已离婚且均已通知,则可直接删除
+        key = (playerIDA, playerIDB)
+        if key in self.coupleDict:
+            self.coupleDict.pop(key)
+        
+        if playerIDA in self.coupleIDDict and self.coupleIDDict[playerIDA] == key:
+            self.coupleIDDict.pop(playerIDA)
+            
+        if playerIDB in self.coupleIDDict and self.coupleIDDict[playerIDB] == key:
+            self.coupleIDDict.pop(playerIDB)
+        return
+    
+    def AddCouple(self, playerIDA, playerIDB, coupleData):
+        ## 添加新伴侣
+        coupleKey = (playerIDA, playerIDB)
+        couple = PlayerCouple(coupleData)
+        self.coupleDict[coupleKey] = couple
+        self.coupleIDDict[playerIDA] = coupleKey
+        self.coupleIDDict[playerIDB] = coupleKey
+        return couple
+    
+    def GetCouple(self, playerID):
+        ## 获取伴侣
+        coupleData = None
+        # 不可能成立的条件,只是为了. 能出代码提示指向 PlayerCouple 类
+        if False:
+            coupleData = PlayerCouple(None)
+        if playerID not in self.coupleIDDict:
+            return coupleData
+        coupleKey = self.coupleIDDict[playerID]
+        if coupleKey not in self.coupleDict:
+            return coupleData
+        coupleData = self.coupleDict[coupleKey]
+        return coupleData
+    
+    def SendMapServerCoupleInfo(self, syncPlayerIDList=None):
+        ## 同步地图伴侣信息
+        syncCoupleInfo = {}
+        if syncPlayerIDList == None:
+            syncPlayerIDList = self.coupleIDDict.keys()
+        for playerID in syncPlayerIDList:
+            couple = self.GetCouple(playerID)
+            if not couple:
+                syncCoupleInfo[playerID] = []
+            else:
+                syncCoupleInfo[playerID] = couple.GetSendMapServerCoupleInfo(playerID)
+        GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_CoupleInfo, syncCoupleInfo)
+        return
+    
+    # 保存数据 存数据库和realtimebackup
+    def GetSaveData(self):
+        savaData = ""
+        cntData = ""
+        cnt = 0
+        
+        for couple in self.coupleDict.values():
+            cnt += 1
+            savaData += couple.coupleData.getBuffer()
+                
+        GameWorld.Log("Save DBPyMarry count :%s len=%s" % (cnt, len(savaData)))
+        return CommFunc.WriteDWORD(cntData, cnt) + savaData
+    
+    # 从数据库载入数据
+    def LoadPyGameData(self, datas, pos, dataslen):
+        cnt, pos = CommFunc.ReadDWORD(datas, pos)
+        GameWorld.Log("Load DBPyMarry count :%s" % cnt)
+        
+        for _ in xrange(cnt):
+            coupleData = PyGameDataStruct.tagDBPyCouple()
+            coupleData.clear()
+            pos += coupleData.readData(datas, pos, dataslen)
+            
+            playerIDA = coupleData.PlayerIDA
+            playerIDB = coupleData.PlayerIDB
+            
+            couple = self.AddCouple(playerIDA, playerIDB, coupleData)
+            if couple.GetBreakRequestTime() > 0:
+                PyGameData.g_marryBreakInfo[(playerIDA, playerIDB)] = couple
+                
+        SortMarryBreak()
+        return pos
+    
+class DBPyUnNotifyLoveGiftRecManager(object):
+    ## 未通知的赠送礼物记录管理
+    
+    def __init__(self):
+        self.unNotifyLoveGiftDict = {} # {playerID:[PyGameDataStruct.tagDBPyUnNotifyLoveGiftRec, ...], ...}
+        return
+    
+    def AddUnNotifyGiftRec(self, receivePlayerID, givePlayerID, giftNum, giftCount, sendTime):
+        ''' 添加未通知的赠送礼物记录
+        @param receivePlayerID: 未通知的受赠方玩家ID
+        @param givePlayerID: 赠送方玩家ID
+        '''
+        recData = PyGameDataStruct.tagDBPyUnNotifyLoveGiftRec()
+        recData.PlayerID = receivePlayerID
+        recData.GivePlayerID = givePlayerID
+        recData.GiftNum = giftNum
+        recData.GiftCount = giftCount
+        recData.SendTime = sendTime
+        
+        if receivePlayerID not in self.unNotifyLoveGiftDict:
+            self.unNotifyLoveGiftDict[receivePlayerID] = []
+        giftList = self.unNotifyLoveGiftDict[receivePlayerID]
+        giftList.append(recData)
+        return
+    
+    def LoginNotify(self, curPlayer):
+        receivePlayerID = curPlayer.GetPlayerID()
+        if receivePlayerID not in self.unNotifyLoveGiftDict:
+            return
+        giftList = self.unNotifyLoveGiftDict.pop(receivePlayerID, [])
+        
+        sendGiftList = []
+        for recData in giftList:
+            giftOK = ChPyNetSendPack.tagGCSendGiftsOK()
+            giftOK.PlayerID = recData.GivePlayerID
+            giftOK.Name = PlayerSocial.GetSocialPlayerName(recData.GivePlayerID)
+            giftOK.NameLen = len(giftOK.Name)
+            giftOK.GiftNum = recData.GiftNum
+            giftOK.GiftCount = recData.GiftCount
+            giftOK.SendTime = recData.SendTime
+            sendGiftList.append(giftOK)
+            
+        clientPack = ChPyNetSendPack.tagGCSendGiftsOKList()
+        clientPack.SendGiftsOKList = sendGiftList
+        clientPack.Count = len(clientPack.SendGiftsOKList)
+        NetPackCommon.SendFakePack(curPlayer, clientPack)
+        return
+    
+    # 保存数据 存数据库和realtimebackup
+    def GetSaveData(self):
+        savaData = ""
+        cntData = ""
+        cnt = 0
+        
+        for recDataList in self.unNotifyLoveGiftDict.values():
+            for recData in recDataList:
+                cnt += 1
+                savaData += recData.getBuffer()
+                
+        GameWorld.Log("Save DBPyUnNotifyLoveGiftRec count :%s len=%s" % (cnt, len(savaData)))
+        return CommFunc.WriteDWORD(cntData, cnt) + savaData
+    
+    # 从数据库载入数据
+    def LoadPyGameData(self, datas, pos, dataslen):
+        cnt, pos = CommFunc.ReadDWORD(datas, pos)
+        GameWorld.Log("Load DBPyUnNotifyLoveGiftRec count :%s" % cnt)
+        
+        for _ in xrange(cnt):
+            recData = PyGameDataStruct.tagDBPyUnNotifyLoveGiftRec()
+            recData.clear()
+            pos += recData.readData(datas, pos, dataslen)
+            
+            playerID = recData.PlayerID
+            
+            if playerID not in self.unNotifyLoveGiftDict:
+                self.unNotifyLoveGiftDict[playerID] = []
+            recDataList = self.unNotifyLoveGiftDict[playerID]
+            recDataList.append(recData)
+            
+        return pos
     
 def AddProsperity(candyObj, addValue):
     candyObj.prosperity += addValue
@@ -100,11 +323,42 @@
     return
 
 def DoOnDay():
-    PlayerBillboard.ClearBillboardByIndex(ShareDefine.Def_BT_CharmDay)
+    
+    # 重置每日聘礼状态
+    syncPlayerIDList = []
+    coupleMgr = PyDataManager.GetDBPyCoupleManager()
+    ipyDataMgr = IpyGameDataPY.IPY_Data()
+    for index in range(ipyDataMgr.GetMarryCount()):
+        ipyData = ipyDataMgr.GetMarryByIndex(index)
+        if not ipyData.GetIsDayReset():
+            continue
+        bridePriceID = ipyData.GetBridePriceID()
+        
+        for couple in coupleMgr.coupleDict.values():
+            bridePriceState = couple.GetBridePriceState()
+            buyCount = couple.GetBridePriceBuyCount(bridePriceID)
+            if not buyCount:
+                continue
+            coupleIDInfo = [couple.coupleData.PlayerIDA, couple.coupleData.PlayerIDB]
+            updBridePriceState = couple.SetBridePriceBuyCount(bridePriceID, 0)
+            GameWorld.DebugLog("重置每日聘礼次数: coupleIDInfo=%s,bridePriceState=%s,bridePriceID=%s,updBridePriceState=%s" 
+                               % (coupleIDInfo, bridePriceState, bridePriceID, updBridePriceState))
+            syncPlayerIDList.extend(coupleIDInfo)
+            
+    if syncPlayerIDList:
+        playerMgr = GameWorld.GetPlayerManager()
+        syncPlayerIDList = list(set(syncPlayerIDList))
+        for playerID in syncPlayerIDList:
+            curPlayer = playerMgr.FindPlayerByID(playerID)
+            if not curPlayer or PlayerControl.GetIsTJG(curPlayer):
+                continue
+            Sync_CoupleInfo(curPlayer)
+            
     return
 
 def OnPlayerLogin(curPlayer):
-    __LoginCheckCouple(curPlayer)
+    PyDataManager.GetDBPyUnNotifyLoveGiftRecManager().LoginNotify(curPlayer)
+    Sync_CoupleInfo(curPlayer)
     Sync_CandyList(curPlayer)
     return
 
@@ -123,6 +377,22 @@
         PyGameData.g_marryCandyInfo.pop((candyObj.playerIDA, candyObj.playerIDB), None)
         
         __DoMarryCandyOver(candyObj)
+        
+    # 检查和离
+    breakWaitTimes = IpyGameDataPY.GetFuncCfg("LoveMarryBreak", 5)
+    doCount = len(PyGameData.g_marryBreakSortList)
+    while doCount > 0 and PyGameData.g_marryBreakSortList:
+        doCount -= 1
+        couple = PyGameData.g_marryBreakSortList[0]
+        if curTime <= (couple.GetBreakRequestTime() + breakWaitTimes):
+            break
+        playerIDA, playerIDB = couple.coupleData.PlayerIDA, couple.coupleData.PlayerIDB
+        PyGameData.g_marryBreakSortList.pop(0)
+        PyGameData.g_marryBreakInfo.pop((playerIDA, playerIDB), None)
+        
+        GameWorld.Log("和离提交请求到期,系统自动和离! playerIDA=%s,playerIDB=%s, len(g_marryBreakSortList)=%s" 
+                      % (playerIDA, playerIDB, len(PyGameData.g_marryBreakSortList)))
+        __DoMarryBreakLogic(couple, 0)
         
     return
 
@@ -167,7 +437,6 @@
         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")
@@ -180,21 +449,31 @@
         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:
+    if __CheckMarryReqTimeout(reqData):
         GameWorld.DebugLog("提亲请求已超时! reqPlayerID=%s" % reqPlayerID, playerID)
         PlayerControl.NotifyCode(curPlayer, "MarryReqInvalid")
+        PyGameData.g_marryReqInfo.pop(reqPlayerID, None)
         return
     
+    __DoMarryResponse(curPlayer, reqPlayer, reqPlayerID, isOK)
+    return
+
+def __DoMarryResponse(curPlayer, reqPlayer, reqPlayerID, isOK):
+    ''' 提亲回应
+    @param curPlayer: 回应玩家
+    @param reqPlayer: 提亲玩家
+    @param isOK: 是否统一
+    '''
+    reqData = PyGameData.g_marryReqInfo.pop(reqPlayerID, None)
+    if not reqData:
+        return
+    bridePriceID = reqData.bridePriceID
     ipyData = IpyGameDataPY.GetIpyGameData("Marry", bridePriceID)
     if not ipyData:
         return
     
-    reqPlayerName = reqPlayer.GetName()
+    playerID = curPlayer.GetPlayerID()
+    reqPlayerName = reqPlayer.GetName() if reqPlayer else PlayerSocial.GetSocialPlayerName(reqPlayerID)
     playerName = curPlayer.GetName()
     
     responsePack = ChPyNetSendPack.tagGCMarryResponseRet()
@@ -205,13 +484,17 @@
     responsePack.PlayerNameB = playerName
     responsePack.NameBLen = len(responsePack.PlayerNameB)
     responsePack.IsOK = isOK
-    NetPackCommon.SendFakePack(reqPlayer, responsePack) # 必回复提亲方
+    if reqPlayer:
+        NetPackCommon.SendFakePack(reqPlayer, responsePack) # 必回复提亲方
     # 拒绝
     if not isOK:
         return
     NetPackCommon.SendFakePack(curPlayer, responsePack) # 回应方仅同意时同步
     
     # ===================== 以下执行成亲逻辑 ===================== 
+    GameWorld.Log("执行成亲: reqPlayerID=%s,playerID=%s,bridePriceID=%s" % (reqPlayerID, playerID, bridePriceID), playerID)
+    
+    curTime = int(time.time())
     prosperity = ipyData.GetProsperity()
     candyTimes = ipyData.GetCandyTimes()
     brideGiftItemInfo = ipyData.GetBrideGiftItemInfo()
@@ -222,26 +505,49 @@
             paramList.extend([itemID, itemCount])
         PlayerControl.WorldNotify(0, worldNotifyKey, paramList)
         
-    for player, coupleID, coupleName in [[reqPlayer, playerID, playerName], [curPlayer, reqPlayerID, reqPlayerName]]:        
-        PlayerControl.SetCoupleID(player, coupleID)
+    coupleMgr = PyDataManager.GetDBPyCoupleManager()
+    couple = coupleMgr.GetCouple(playerID)
+    if not couple:
+        GameWorld.Log("    新婚: reqPlayerID=%s,playerID=%s,bridePriceID=%s" % (reqPlayerID, playerID, bridePriceID), playerID)
+        coupleData = PyGameDataStruct.tagDBPyCouple()
+        coupleData.PlayerIDA = reqPlayerID
+        coupleData.PlayerNameA = reqPlayerName
+        coupleData.PlayerIDB = playerID
+        coupleData.PlayerNameB = playerName
+        coupleData.NewMarryTime = curTime
+        couple = coupleMgr.AddCouple(reqPlayerID, playerID, coupleData)
         
-        # 更新社交关系
-        socialPlayer = PyDataManager.GetPersonalSocialManager().GetSocialPlayer(player.GetPlayerID())
-        if socialPlayer:
-            socialPlayer.SetCoupleInfo(coupleID, coupleName)
-            socialPlayer.CheckUpdCouplePriceMaxID(bridePriceID)
-            
-        # 通知地图玩家
-        dataMsg = [reqPlayerID, coupleID, curTime, bridePriceID]
+        # 通知给相关社交人员
+        PlayerSocial.NotifySocialCoupleChange(reqPlayerID, playerID)
+        PlayerSocial.NotifySocialCoupleChange(playerID, reqPlayerID)
+        
+        # 通知地图全局伴侣信息
+        PyDataManager.GetDBPyCoupleManager().SendMapServerCoupleInfo([playerID, reqPlayerID])
+    else:
+        GameWorld.Log("    已婚,再次提亲: PlayerIDA=%s,PlayerIDB=%s, cur reqPlayerID=%s,playerID=%s,bridePriceID=%s" 
+                      % (couple.coupleData.PlayerIDA, couple.coupleData.PlayerIDB, reqPlayerID, playerID, bridePriceID), playerID)
+        
+    couple.coupleData.MarryTime = curTime
+    updBuyCountValue = couple.SetBridePriceBuyCount(bridePriceID, couple.GetBridePriceBuyCount(bridePriceID) + 1)
+    GameWorld.Log("    updBuyCountValue=%s" % updBuyCountValue, playerID)
+    
+    if bridePriceID > couple.BridePriceMaxID:
+        couple.BridePriceMaxID = bridePriceID
+        GameWorld.Log("    update BridePriceMaxID=%s" % couple.BridePriceMaxID, playerID)
+        
+    # 通知玩家
+    for player in [reqPlayer, curPlayer]:
+        if not player:
+            continue   
+        mapServerCoupleInfo = couple.GetSendMapServerCoupleInfo(player.GetPlayerID())
+        dataMsg = [reqPlayerID, bridePriceID, mapServerCoupleInfo]
         MapServer_QueryPlayer_DoLogic_Love(player, "MarrySuccess", dataMsg, playerID)
+        Sync_CoupleInfo(player)
         
     # 聘礼奖励发邮件
     playerIDList = [reqPlayerID, playerID]
     paramList = [reqPlayerName, playerName]
     PlayerCompensation.SendMailByKey("MarrySuccess", playerIDList, brideGiftItemInfo, paramList)
-    
-    # 通知地图全局伴侣信息
-    PlayerSocial.SendMapServerCoupleInfo([playerID, reqPlayerID])
     
     # 新增喜糖
     candyObj = MarryCandy()
@@ -255,11 +561,27 @@
     AddProsperity(candyObj, prosperity)
     
     PyGameData.g_marryCandyInfo[(reqPlayerID, playerID)] = candyObj
+    __SortCandy()
+    Sync_CandyList(None, [candyObj])
+    return True
+
+def __SortCandy():
     PyGameData.g_marryCandySortList = PyGameData.g_marryCandyInfo.values()
     PyGameData.g_marryCandySortList.sort(key=operator.attrgetter("endTime"))
-    
-    Sync_CandyList(None, [candyObj])
     return
+
+def SortMarryBreak():
+    PyGameData.g_marryBreakSortList = PyGameData.g_marryBreakInfo.values()
+    PyGameData.g_marryBreakSortList.sort(key=operator.attrgetter("coupleData.BreakRequestTime"))
+    #GameWorld.DebugLog("SortMarryBreak count=%s" % len(PyGameData.g_marryBreakSortList))
+    return
+
+def __CheckMarryReqTimeout(reqData):
+    ## 检查提亲是否超时
+    curTime = int(time.time())
+    passSeconds = curTime - reqData.reqTime
+    reqSecondCD = IpyGameDataPY.GetFuncCfg("LoveMarry", 1)
+    return passSeconds > reqSecondCD
 
 #// B3 16 和平离婚回应 #tagGCMarryBreakResponse
 #
@@ -273,103 +595,89 @@
     isOK = clientData.IsOK
     
     playerID = curPlayer.GetPlayerID()
-    coupleID = PlayerControl.GetCoupleID(curPlayer)
-    if not coupleID:
+    couple = PyDataManager.GetDBPyCoupleManager().GetCouple(playerID)
+    if not couple:
+        GameWorld.Log("没有伴侣,无法回应和离! ", playerID)
+        return
+    coupleID = couple.GetCoupleID(playerID)
+    breakRequestID = couple.GetBreakRequestID()
+    if not breakRequestID or coupleID != breakRequestID:
+        GameWorld.Log("伴侣没有提出和离,无法回应和离! coupleID=%s,breakRequestID=%s" 
+                      % (coupleID, breakRequestID), playerID)
         return
     
-    if coupleID not in PyGameData.g_marryBreakReqInfo:
-        GameWorld.DebugLog("对方没有请求和离,回应无效! coupleID=%s" % coupleID, playerID)
-        return
+    playerIDA, playerIDB = couple.coupleData.PlayerIDA, couple.coupleData.PlayerIDB
+    if (playerIDA, playerIDB) in PyGameData.g_marryBreakInfo:
+        PyGameData.g_marryBreakInfo.pop((playerIDA, playerIDB), None)
+        SortMarryBreak()
         
-    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:
+        GameWorld.Log("拒绝和离! coupleID=%s" % coupleID, playerID)
+        couple.SetBreakRequestID(0) # 清除和离请求ID
+        
+        Sync_CoupleInfo(curPlayer)
+        tagPlayer = GameWorld.GetPlayerManager().FindPlayerByID(coupleID)
+        if tagPlayer and not PlayerControl.GetIsTJG(tagPlayer):
+            Sync_CoupleInfo(tagPlayer)
         PlayerCompensation.SendMailByKey("MarryBreakRefuse", [coupleID], [], [curPlayer.GetName()])
         return
     
     GameWorld.Log("同意和离: coupleID=%s" % coupleID, playerID)
     
-    __DoMarryBreak(curPlayer, coupleID)
+    __DoMarryBreakLogic(couple, playerID)
     return
 
-def __DoMarryBreak(curPlayer, coupleID):
+def __DoMarryBreakLogic(couple, playerID=0):
     ## 执行离婚 
     
-    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:
+    if not couple:
         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):
-    ## 清除伴侣社交关系
+    playerIDA = couple.coupleData.PlayerIDA
+    playerIDB = couple.coupleData.PlayerIDB
     
-    coupleID = PlayerControl.GetCoupleID(curPlayer)
-    coupleName = ""
+    coupleMgr = PyDataManager.GetDBPyCoupleManager()
     
-    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)
+    # 亲密度减少
+    decIntimacyPer = IpyGameDataPY.GetFuncCfg("LoveMarryBreak", 4)
+    if decIntimacyPer:
+        PyDataManager.GetIntimacyManager().DelIntimacyBothPer(playerIDA, playerIDB, decIntimacyPer)
         
     # 邮件通知离婚
-    playerIDList = [playerID]
-    paramList = [coupleName]
-    PlayerCompensation.SendMailByKey("MarryBreakOK", playerIDList, [], paramList)
-    return
+    for pid in [playerIDA, playerIDB]:
+        coupleName = couple.GetCoupleName(pid)
+        playerIDList = [pid]
+        paramList = [coupleName]
+        PlayerCompensation.SendMailByKey("MarryBreakOK", playerIDList, [], paramList)
+        
+    coupleMgr.DelCouple(playerIDA, playerIDB)
+    # 通知地图全局伴侣信息
+    PyDataManager.GetDBPyCoupleManager().SendMapServerCoupleInfo([playerIDA, playerIDB])
+    
+    # 通知玩家
+    dataMsg = []
+    for pid in [playerIDA, playerIDB]:
+        tagPlayer = GameWorld.GetPlayerManager().FindPlayerByID(pid)
+        if tagPlayer and not PlayerControl.GetIsTJG(tagPlayer):
+            MapServer_QueryPlayer_DoLogic_Love(tagPlayer, "ClearCoupleSocial", dataMsg, playerID)
+            Sync_CoupleInfo(tagPlayer)
+            
+    # 通知给相关社交人员
+    PlayerSocial.NotifySocialCoupleChange(playerIDA, 0)
+    PlayerSocial.NotifySocialCoupleChange(playerIDB, 0)
+    
+    if (playerIDA, playerIDB) in PyGameData.g_marryCandyInfo:
+        GameWorld.Log("离婚时同步清除喜糖宴会: playerIDA=%s, playerIDB=%s" % (playerIDA, playerIDB), playerID)
+        PyGameData.g_marryCandyInfo.pop((playerIDA, playerIDB))
+        __SortCandy()
+        Sync_CandyList(None)
+        
+    if (playerIDA, playerIDB) in PyGameData.g_marryBreakInfo:
+        GameWorld.Log("离婚时同步清除和离请求: playerIDA=%s, playerIDB=%s" % (playerIDA, playerIDB), playerID)
+        PyGameData.g_marryBreakInfo.pop((playerIDA, playerIDB), None)
+        SortMarryBreak()
+        
+    return True
 
 def MapServer_Love(curPlayer, msgList):
     mapID = curPlayer.GetRealMapID()
@@ -379,13 +687,13 @@
     
     msgType, dataMsg = msgList
     
-    # 送花请求
-    if msgType == "SendFlowersReq":
-        ret = __CheckSendFlowers(curPlayer, dataMsg)
+    # 送礼物请求
+    if msgType == "SendGiftsReq":
+        ret = __SendGiftsReq(curPlayer, dataMsg)
         
-    # 送花OK
-    elif msgType == "SendFlowersOK":
-        __DoSendFlowersOK(curPlayer, dataMsg)
+    # 送礼物
+    elif msgType == "SendGiftsOK":
+        __DoSendGiftsOK(curPlayer, dataMsg)
         return
     
     # 提亲
@@ -409,63 +717,70 @@
         return
     return msgList + [ret]
 
-def __CheckSendFlowers(curPlayer, dataMsg):
-    ## 在线好友可赠送
+def __SendGiftsReq(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")
+    # 黑名单检查
+    if PyDataManager.GetBlacklistManager().CheckBlacklistBoth(playerID, tagPlayerID, curPlayer):
         return
     
     return True
 
-def __DoSendFlowersOK(curPlayer, dataMsg):
-    ## 送花OK
+def __DoSendGiftsOK(curPlayer, dataMsg):
+    ## 送礼物
     
     playerID = curPlayer.GetPlayerID()
     playerName = curPlayer.GetName()
     
-    tagPlayerID, flowerID, flowerCount, addCharm, addCharmTag, addIntimacy, isWorldNotify = dataMsg
+    tagPlayerID, giftNum, giftItemID, giftCount, isAutoBuy = 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):
+    ipyData = IpyGameDataPY.GetIpyGameData("LoveGift", giftNum)
+    if not ipyData:
         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)
+    addCharmSelf = ipyData.GetAddCharmSelf() * giftCount
+    addCharmTag = ipyData.GetAddCharmTag() * giftCount
+    addIntimacy = ipyData.GetAddIntimacy() * giftCount
+    worldNotifyKey = ipyData.GetWorldNotifyKey()
+    
+    GameWorld.Log("赠送礼物: tagPlayerID=%s,giftNum=%s,giftItemID=%s,giftCount=%s,addCharmSelf=%s,addCharmTag=%s,addIntimacy=%s,isAutoBuy=%s" 
+                  % (tagPlayerID, giftNum, giftItemID, giftCount, addCharmSelf, addCharmTag, addIntimacy, isAutoBuy), playerID)
+    
+    tagPlayer = GameWorld.GetPlayerManager().FindPlayerByID(tagPlayerID)
+    
+    PyDataManager.GetIntimacyManager().AddIntimacyBoth(playerID, tagPlayerID, addIntimacy)
+    PlayerCharm.AddCharm(curPlayer, playerID, playerID, addCharmSelf)
+    PlayerCharm.AddCharm(tagPlayer, tagPlayerID, playerID, addCharmTag)
+    
+    tagPlayerName = ""
+    isOnline = tagPlayer and not PlayerControl.GetIsTJG(tagPlayer)
+    if isOnline:
+        tagPlayerName = tagPlayer.GetName()
+    else:
+        tagPlayerName = PlayerSocial.GetSocialPlayerName(tagPlayerID)
         
-    if isWorldNotify:
-        PlayerControl.WorldNotify(0, "SendFlowers%s" % flowerCount, [playerName, tagPlayerName, flowerCount, flowerID])
+    if worldNotifyKey:
+        PlayerControl.WorldNotify(0, worldNotifyKey, [playerName, tagPlayerName, giftItemID, giftCount])
         
-    dataMsg = [addCharmTag]
-    MapServer_QueryPlayer_DoLogic_Love(tagPlayer, "AddCharm", dataMsg, playerID)
-        
+    sendTime = int(time.time())
+    if not isOnline:
+        PyDataManager.GetDBPyUnNotifyLoveGiftRecManager().AddUnNotifyGiftRec(tagPlayerID, playerID, giftNum, giftCount, sendTime)
+        return
+    
     # 通知目标前端送花成功
-    clientPack = ChPyNetSendPack.tagGCSendFlowersOK()
-    clientPack.PlayerID = playerID
-    clientPack.Name = playerName
-    clientPack.NameLen = len(clientPack.Name)
-    clientPack.FlowerCount = flowerCount
+    giftOK = ChPyNetSendPack.tagGCSendGiftsOK()
+    giftOK.PlayerID = playerID
+    giftOK.Name = playerName
+    giftOK.NameLen = len(giftOK.Name)
+    giftOK.GiftNum = giftNum
+    giftOK.GiftCount = giftCount
+    giftOK.SendTime = sendTime
+    
+    clientPack = ChPyNetSendPack.tagGCSendGiftsOKList()
+    clientPack.SendGiftsOKList = [giftOK]
+    clientPack.Count = len(clientPack.SendGiftsOKList)
     NetPackCommon.SendFakePack(tagPlayer, clientPack)
     return
 
@@ -485,33 +800,30 @@
     ## 成亲通用检查
     
     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") # 非好友
+    
+    # 黑名单检查
+    if PyDataManager.GetBlacklistManager().CheckBlacklistBoth(playerID, tagPlayerID, curPlayer):
         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") # 已经有其他伴侣了
+    curCouple = PyDataManager.GetDBPyCoupleManager().GetCouple(playerID)
+    if curCouple and curCouple.GetCoupleID(playerID) != tagPlayerID:
+        PlayerControl.NotifyCode(curPlayer, "HaveCouple") # 已经有其他伴侣了
         return
     
-    tagCoupleID = PlayerControl.GetCoupleID(tagPlayer)
-    if tagCoupleID and tagCoupleID != playerID:
-        PlayerControl.NotifyCode(curPlayer, "TagHaveCouple") # 已经有其他伴侣了
+    tagCouple = PyDataManager.GetDBPyCoupleManager().GetCouple(tagPlayerID)
+    if tagCouple and tagCouple.GetCoupleID(tagPlayerID) != playerID:
+        PlayerControl.NotifyCode(curPlayer, "TagHaveCouple") # 对方已经有其他伴侣了
         return
     
     # 回应方可不检查亲密度
     if checkIntimacy:
         needIntimacy = IpyGameDataPY.GetFuncCfg("LoveMarry", 2)
-        if curFriend.Intimacy < needIntimacy:
+        curIntimacys = PyDataManager.GetIntimacyManager().GetIntimacys(playerID)
+        if not curIntimacys or curIntimacys.GetTagIntimacy(tagPlayerID) < needIntimacy:
             PlayerControl.NotifyCode(curPlayer, "IntimacyLack", [needIntimacy]) # 亲密度不足
             return
         
@@ -519,7 +831,7 @@
 
 def __DoMarryReq(curPlayer, dataMsg):
     ## 提亲
-        
+    
     tagPlayerID, bridePriceID = dataMsg
     
     tagPlayer = GameWorld.GetPlayerManager().FindPlayerByID(tagPlayerID)
@@ -533,6 +845,34 @@
         PlayerControl.NotifyCode(curPlayer, "MarryReqLimitByCandy") # 喜宴中无法操作
         return
     
+    couple = PyDataManager.GetDBPyCoupleManager().GetCouple(playerID)
+    if couple:
+        coupleID = couple.GetCoupleID(playerID)
+        if coupleID != tagPlayerID:
+            GameWorld.Log("已成亲伴侣ID不一致,无法提亲! tagPlayerID(%s) != coupleID(%s)" % (tagPlayerID, coupleID), playerID)
+            return
+        
+        ipyData = IpyGameDataPY.GetIpyGameData("Marry", bridePriceID)
+        if not ipyData:
+            return
+        
+        canBuyMax = ipyData.GetCanBuyCount()
+        buyCount = couple.GetBridePriceBuyCount(bridePriceID)
+        GameWorld.DebugLog("bridePriceID=%s,buyCount=%s,canBuyMax=%s %s" % (bridePriceID, buyCount, canBuyMax, couple.coupleData.BridePriceState))
+        if canBuyMax and buyCount >= canBuyMax:
+            GameWorld.Log("聘礼提亲次数不足,无法提亲! bridePriceID=%s,buyCount(%s) >= canBuyMax(%s)" 
+                          % (bridePriceID, buyCount, canBuyMax), playerID)
+            return
+        
+    if tagPlayerID in PyGameData.g_marryReqInfo:
+        tagReqData = PyGameData.g_marryReqInfo[tagPlayerID]
+        if playerID == tagReqData.playerIDB and not __CheckMarryReqTimeout(tagReqData):
+            GameWorld.Log("玩家提亲时,目标刚好已经先提过亲,且在有效期内,直接成亲!tagPlayerID=%s" % tagPlayerID, playerID)
+            if __DoMarryResponse(curPlayer, tagPlayer, tagPlayerID, 1):
+                return
+        else:
+            GameWorld.DebugLog("对方有提亲,但是对象不一样或已超时! tagPlayerID=%s, timeout=%s" % (tagReqData.playerIDB, __CheckMarryReqTimeout(tagReqData)), playerID)
+            
     curTime = int(time.time())
     if playerID not in PyGameData.g_marryReqInfo:
         reqData = MarryReq()
@@ -631,44 +971,82 @@
 
 def __DoMarryBreakReq(curPlayer, dataMsg):
     ## 离婚请求
-    playerID, coupleID, breakType, moneyType, moneyValue = dataMsg
+    playerID, breakType, moneyType, moneyValue = dataMsg
     
-    gameServerCoupleID = PlayerControl.GetCoupleID(curPlayer)
-    socialPlayer = PyDataManager.GetPersonalSocialManager().GetSocialPlayer(playerID)
-    socialCoupleID = 0 if not socialPlayer else socialPlayer.GetCoupleID()
+    couple = PyDataManager.GetDBPyCoupleManager().GetCouple(playerID)
+    if not couple:
+        GameWorld.Log("没有伴侣,不需要离婚! ", playerID)
+        return
+    coupleID = couple.GetCoupleID(playerID)
     
-    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])
+    curTime = int(time.time())
+    
+    # 公共CD
+    marryTime = couple.GetMarryTime()
+    passTime = curTime - marryTime
+    marryBreakCD = IpyGameDataPY.GetFuncCfg("LoveMarryBreak", 1)
+    if marryBreakCD and passTime < marryBreakCD:
+        GameWorld.Log("距离最近一次成亲离婚等待时间未到,无法请求离婚! marryTime=%s,passTime(%s) < %s" 
+                      % (GameWorld.ChangeTimeNumToStr(marryTime), passTime, marryBreakCD), playerID)
         return
     
-    if (playerID, coupleID) in PyGameData.g_marryCandyInfo or (coupleID, playerID) in PyGameData.g_marryCandyInfo:
-        PlayerControl.NotifyCode(curPlayer, "MarryReqLimitByCandy") # 喜宴中无法操作
+    # 和离额外限制个人CD
+    playerBreakRequestTime = couple.GetPlayerBreakRequestTime(playerID)
+    if breakType == 0 and playerBreakRequestTime:
+        passTime = curTime - playerBreakRequestTime
+        breakReqCD = IpyGameDataPY.GetFuncCfg("LoveMarryBreak", 2)
+        if breakReqCD and passTime < breakReqCD:
+            GameWorld.Log("距离最近一次请求和离等待时间未到,无法请求离婚! playerBreakRequestTime=%s,passTime(%s) < %s" 
+                          % (GameWorld.ChangeTimeNumToStr(playerBreakRequestTime), passTime, breakReqCD), playerID)
+            return
+        
+    if couple.GetBreakRequestID() == coupleID:
+        GameWorld.Log("请求离婚时对方已经提出和离了,直接离婚! coupleID=%s,breakRequestID=%s" 
+                      % (coupleID, couple.GetBreakRequestID()), playerID)        
+        __DoMarryBreakLogic(couple, playerID)
         return
     
     # 0-和平离婚;1-强制离婚
     if breakType == 0:
+        if couple.GetBreakRequestID() != playerID:
+            playerIDA, playerIDB = couple.coupleData.PlayerIDA, couple.coupleData.PlayerIDB
+            GameWorld.Log("新增提交和离! coupleID=%s" % coupleID, playerID)
+            couple.SetBreakRequestID(playerID)
+            PyGameData.g_marryBreakInfo[(playerIDA, playerIDB)] = couple
+            SortMarryBreak()
+            playerBreakRequestTime = couple.GetPlayerBreakRequestTime(playerID)
+        else:
+            GameWorld.Log("重复提交和离! coupleID=%s" % coupleID, playerID)
+            
+        Sync_CoupleInfo(curPlayer)
         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
+        if tagPlayer and not PlayerControl.GetIsTJG(tagPlayer):
+            Sync_CoupleInfo(tagPlayer)
         return
     
     GameWorld.Log("强制离婚: coupleID=%s" % coupleID, playerID)
-    __DoMarryBreak(curPlayer, coupleID)
+    __DoMarryBreakLogic(couple, playerID)
     
     return moneyType, moneyValue
 
+def Sync_CoupleInfo(curPlayer):
+    ## 同步伴侣信息
+    playerID = curPlayer.GetPlayerID()
+    clientPack = ChPyNetSendPack.tagGCCoupleInfo()
+    curCouple = PyDataManager.GetDBPyCoupleManager().GetCouple(playerID)
+    if curCouple:
+        clientPack.CoupleID = curCouple.GetCoupleID(playerID)
+        clientPack.CoupleName = curCouple.GetCoupleName(playerID)
+        clientPack.NameLen = len(clientPack.CoupleName)
+        clientPack.NewMarryTime = curCouple.GetNewMarryTime()
+        clientPack.MarryTime = curCouple.GetMarryTime()
+        clientPack.BridePriceState = curCouple.GetBridePriceState()
+        clientPack.BreakRequestID = curCouple.GetBreakRequestID()
+        clientPack.BreakRequestTime = curCouple.GetBreakRequestTime()
+        clientPack.PlayerBreakRequestTime = curCouple.GetPlayerBreakRequestTime(playerID)
+    NetPackCommon.SendFakePack(curPlayer, clientPack)
+    return
+
 def Sync_CandyList(curPlayer, syncCandyList=None):
     if syncCandyList == None:
         syncCandyList = PyGameData.g_marryCandySortList
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerSocial.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerSocial.py
index 3ed29f5..6b70901 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerSocial.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerSocial.py
@@ -139,8 +139,10 @@
             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
+            if hasattr(player, 'Intimacy'):
+                inPack.SortValue = player.Intimacy
+            else:
+                inPack.SortValue = player.Timestamp if hasattr(player, 'Timestamp') else 0
             pack.Players.append(inPack)
             
         pack.Count = len(pack.Players)
@@ -196,48 +198,7 @@
         self.Delete(delFriendID)
         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):
         return
@@ -334,6 +295,144 @@
             self.PlayerFriends[playerFriend.PlayerID].SocialDict[playerFriend.TagID] = playerFriend
             
             AddBeSocial(playerFriend.TagID, playerFriend.PlayerID)
+        return pos
+    
+#-------------------亲密------------------------------
+# 某个玩家的亲密组管理
+class Intimacys(SocialPlayers):
+    def __init__(self, PlayerID):
+        super(Intimacys, self).__init__(PlayerID, PyGameDataStruct.tagDBPyPlayerIntimacy, 
+                                        ChConfig.Def_SocialGroup_Intimacy)
+        
+    def GetIntimacyObj(self, tagID):
+        if tagID not in self.SocialDict:
+            self.Add(tagID)
+        return self.SocialDict.get(tagID)
+    
+    def GetTagIntimacy(self, tagID):
+        intimacyObj = self.Find(tagID)
+        return intimacyObj.Intimacy if intimacyObj else 0
+    
+    def AddIntimacy(self, curPlayer, tagID, addValue):
+        ## 增加亲密度 - 支持正负、支持离线, curPlayer 可能为None
+        intimacyObj = self.GetIntimacyObj(tagID)
+        if not intimacyObj:
+            return 0
+        if not intimacyObj.Intimacy and addValue < 0:
+            return 0
+        intimacyObj.Intimacy = min(max(0, intimacyObj.Intimacy + addValue), ShareDefine.Def_UpperLimit_DWord)
+        nowIntimacy = intimacyObj.Intimacy
+        
+        if nowIntimacy <= 0:
+            self.Delete(tagID)
+            
+        if not curPlayer:
+            return nowIntimacy
+        
+        tagName = ""
+        socialPlayer = PyDataManager.GetPersonalSocialManager().GetSocialPlayer(tagID)
+        if socialPlayer:
+            tagName = socialPlayer.playerInfo.PlayerName
+            
+        if addValue > 0:
+            PlayerControl.NotifyCode(curPlayer, "AddIntimacy", [tagName, addValue])
+        elif addValue < 0:
+            PlayerControl.NotifyCode(curPlayer, "DelIntimacy", [tagName, abs(addValue)])
+            
+        self.Sync_SocialsInfo(curPlayer, [tagID])
+        return nowIntimacy
+    
+    def SetIntimacy(self, curPlayer, tagID, setValue):
+        ## 直接设置亲密度 - 一般GM测试使用
+        intimacyObj = self.GetIntimacyObj(tagID)
+        if not intimacyObj:
+            return 0
+        intimacyObj.Intimacy = setValue
+        if curPlayer:
+            self.Sync_SocialsInfo(curPlayer, [tagID])
+        return intimacyObj.Intimacy
+    
+# 整个游戏的亲密管理
+class IntimacyManager(object):
+    def __init__(self):
+        self.PlayerIntimacys = {}     # PyGameDataStruct.tagDBPyPlayerIntimacy
+        return
+    
+    # 增加双方亲密度
+    def AddIntimacyBoth(self, aID, bID, addValue):
+        
+        for playerID, tagPlayerID in {aID:bID, bID:aID}.items():
+            intimacys = self.GetIntimacys(playerID)
+            if not intimacys:
+                continue
+            intimacyObj = intimacys.GetIntimacyObj(tagPlayerID)
+            if not intimacyObj:
+                continue
+            
+            curIntimacy = intimacyObj.Intimacy
+            curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
+            updIntimacy = intimacys.AddIntimacy(curPlayer, tagPlayerID, addValue)
+            
+            GameWorld.DebugLog("增加亲密度: playerID=%s,tagPlayerID=%s,curIntimacy=%s,addValue=%s,updIntimacy=%s" 
+                               % (playerID, tagPlayerID, curIntimacy, addValue, updIntimacy), playerID)
+        return
+    
+    # 扣除双方亲密度 - 按百分比
+    def DelIntimacyBothPer(self, aID, bID, delPer):
+        
+        for playerID, tagPlayerID in {aID:bID, bID:aID}.items():
+            intimacys = self.GetIntimacys(playerID)
+            if not intimacys:
+                continue
+            intimacyObj = intimacys.GetIntimacyObj(tagPlayerID)
+            if not intimacyObj:
+                continue
+            
+            curIntimacy = intimacyObj.Intimacy
+            delValue = -max(1, int(curIntimacy * delPer / 100.0))
+            curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
+            updIntimacy = intimacys.AddIntimacy(curPlayer, tagPlayerID, delValue)
+            GameWorld.DebugLog("扣除亲密度: playerID=%s,tagPlayerID=%s,curIntimacy=%s,delPer=%s,delValue=%s,updIntimacy=%s" 
+                               % (playerID, tagPlayerID, curIntimacy, delPer, delValue, updIntimacy), playerID)
+            
+        return
+    
+    # 获取亲密组
+    def GetIntimacys(self, playerID):
+        if playerID not in self.PlayerIntimacys:
+            self.PlayerIntimacys[playerID] = Intimacys(playerID)
+        return self.PlayerIntimacys[playerID]
+    
+    # 保存亲密数据 存数据库和realtimebackup
+    def GetSaveData(self):
+        savaData = ""
+        cntData = ""
+        cnt = 0
+        for intimacys in self.PlayerIntimacys.values():
+            for playerIntimacy in intimacys.SocialDict.values():
+                cnt += 1
+                savaData += playerIntimacy.getBuffer()
+        
+        GameWorld.Log("Save DBPyPlayerIntimacy cnt :%s len=%s" % (cnt, len(savaData)))
+        return CommFunc.WriteDWORD(cntData, cnt) + savaData
+
+    # 从数据库载入亲密数据
+    def LoadPyGameData(self, datas, pos, dataslen):
+        cnt, pos = CommFunc.ReadDWORD(datas, pos)
+        GameWorld.Log("Load DBPyPlayerIntimacy cnt :%s"%cnt)
+        
+        self.PlayerIntimacys = {}
+        
+        for i in xrange(cnt):
+            playerIntimacy = PyGameDataStruct.tagDBPyPlayerIntimacy()
+            playerIntimacy.clear()
+            pos += playerIntimacy.readData(datas, pos, dataslen)
+            playerID = playerIntimacy.PlayerID
+            if playerID not in self.PlayerIntimacys:
+                self.PlayerIntimacys[playerID] = Intimacys(playerID) 
+            self.PlayerIntimacys[playerID].SocialDict[playerIntimacy.TagID] = playerIntimacy
+            
+            AddBeSocial(playerIntimacy.TagID, playerIntimacy.PlayerID)
         return pos
     
 #-------------------仇人------------------------------
@@ -696,7 +795,6 @@
 class SocialPlayerData(object):
     def __init__(self, playerSocial = None, player = None):
         self.playerInfo = PyGameDataStruct.tagPersonalSocial()
-        self.syncMapCouple = 0 # 是否已经同步过地图全局伴侣信息
         
         if playerSocial:
             self.playerInfo = playerSocial
@@ -712,7 +810,6 @@
         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
@@ -725,38 +822,7 @@
         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):
@@ -803,7 +869,6 @@
             playerSocial.LV = 1
             playerSocial.RealmLV = 1
             playerSocial.OnlineType = ChConfig.Def_Offline
-            playerSocial.CoupleID = 0
         else:
             cacheDict = PlayerViewCache.GetCachePropDataDict(curCache)
     
@@ -814,7 +879,6 @@
             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]
@@ -831,11 +895,30 @@
         socialPlayer.SubSocialRef()
         if socialPlayer.GetRefCount() <= 0:
             self.SocialInfo.pop(delPlayerID)
-            
     
     def GetSocialPlayer(self, playerID):
         return self.SocialInfo.get(playerID, None)
     
+    def SyncSocialCoupleInfo(self, curPlayer):
+        coupleMgr = PyDataManager.GetDBPyCoupleManager()
+        coupleList = []
+        for playerID in self.SocialInfo.keys():
+            couple = coupleMgr.GetCouple(playerID)
+            if not couple:
+                continue
+            socialCouple = ChPyNetSendPack.tagGCSocialCouple()
+            socialCouple.PlayerID = playerID
+            socialCouple.CoupleID = couple.GetCoupleID(playerID)
+            coupleList.append(socialCouple)
+            
+        if not coupleList:
+            return
+        
+        clientPack = ChPyNetSendPack.tagGCSocialCouples()
+        clientPack.Player = coupleList
+        clientPack.Count = len(clientPack.Player)
+        NetPackCommon.SendFakePack(curPlayer, clientPack)
+        return
     
     # 保存有社交的玩家信息
     def GetSaveData(self):
@@ -864,6 +947,38 @@
                 
         return pos
 
+def GetSocialPlayerName(playerID):
+    ## 获取玩家社交昵称
+    socialPlayer = PyDataManager.GetPersonalSocialManager().GetSocialPlayer(playerID)
+    if socialPlayer:
+        return socialPlayer.playerInfo.PlayerName
+    
+    curCache = PlayerViewCache.FindViewCache(playerID)
+    if curCache:
+        cacheDict = PlayerViewCache.GetCachePropDataDict(curCache)
+        return cacheDict["Name"]
+    
+    if playerID < 10000:
+        return "testName%s" % playerID
+    
+    return ""
+
+def GetSocialPlayerJob(playerID):
+    ## 获取玩家社交职业
+    socialPlayer = PyDataManager.GetPersonalSocialManager().GetSocialPlayer(playerID)
+    if socialPlayer:
+        return socialPlayer.playerInfo.Job
+    
+    curCache = PlayerViewCache.FindViewCache(playerID)
+    if curCache:
+        cacheDict = PlayerViewCache.GetCachePropDataDict(curCache)
+        return cacheDict["Job"]
+    
+    if playerID < 10000:
+        job = 2 if playerID % 2 == 0 else 1
+        return job
+    
+    return 1
 
 # 向相关联的社交对象通知当前玩家信息
 # 最近联系人、仇人和黑名单存在单向情况, 向对方通知信息
@@ -893,8 +1008,32 @@
         if PlayerControl.GetIsTJG(player):
             continue
         NetPackCommon.SendFakePack(player, pack)
-        
+    return
 
+def NotifySocialCoupleChange(playerID, coupleID):
+    ## 通知伴侣变更给相关社交人员
+    if playerID not in PyGameData.g_BeSocialList:
+        return
+    
+    couple = ChPyNetSendPack.tagGCSocialCouple()
+    couple.PlayerID = playerID
+    couple.CoupleID = coupleID
+    
+    clientPack = ChPyNetSendPack.tagGCSocialCouples()
+    clientPack.Player.append(couple)
+    clientPack.Count = len(clientPack.Player)
+    
+    for tagID in PyGameData.g_BeSocialList[playerID]:
+        player = GameWorld.GetPlayerManager().FindPlayerByID(tagID)
+        if not player:
+            continue
+        
+        if PlayerControl.GetIsTJG(player):
+            continue
+        
+        NetPackCommon.SendFakePack(player, clientPack)
+    return
+    
 
 #更新玩家社交信息
 def UpdateSocialInfo(playerID, notifyType, value):
@@ -908,39 +1047,8 @@
         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 # 未指定时才检查,防止启动地图时同步过多(启动地图时,只同步本次已经同步过的)
-        
-    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
 
 # 向当前玩家通知相关联的所有玩家信息
@@ -954,9 +1062,11 @@
     list3 = contacts.SocialDict.keys() if contacts else []
     blacklists = PyDataManager.GetBlacklistManager().GetBlacklist(playerID)
     list4 = blacklists.SocialDict.keys() if blacklists else []
+    intimacys = PyDataManager.GetIntimacyManager().GetIntimacys(playerID)
+    list5 = intimacys.SocialDict.keys() if intimacys else []
 
     #信息并集后发送, 玩家ID
-    resultSet = set(list1)|set(list2)|set(list3)|set(list4)
+    resultSet = set(list1)|set(list2)|set(list3)|set(list4)|set(list5)
     
     sendPack = ChPyNetSendPack.tagGCSocialPlayers()
     sendPack.Clear()
@@ -971,6 +1081,8 @@
         
     sendPack.Count = len(sendPack.Player)
     NetPackCommon.SendFakePack(curPlayer, sendPack)
+    
+    socialManager.SyncSocialCoupleInfo(curPlayer)
     return
     
 
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerTalk.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerTalk.py
index 18a73a1..a1c8215 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerTalk.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerTalk.py
@@ -453,12 +453,13 @@
     # 等级
     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)
+    coupleName, coupleJob, bridePriceMaxID = "", 1, 0
+    couple = PyDataManager.GetDBPyCoupleManager().GetCouple(playerID)
+    if couple:
+        coupleName = couple.GetCoupleName(playerID)
+        coupleJob = couple.GetCoupleJob(playerID)
+        bridePriceMaxID = couple.BridePriceMaxID
+    extraValueStr = "%s|%s|%s|%s" % (extraValueStr, coupleName, coupleJob, bridePriceMaxID)
     return extraValueStr
 
 
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/PyDataManager.py b/ServerPython/CoreServerGroup/GameServer/Script/PyDataManager.py
index a4df3e7..70fb00a 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/PyDataManager.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/PyDataManager.py
@@ -28,6 +28,8 @@
 import PlayerAssist
 import PyGameDataStruct
 import IpyGameDataPY
+import PlayerCharm
+import PlayerLove
 import CommFunc
 import time
 
@@ -307,6 +309,10 @@
 
 class PyGameDataManager(object):
     def __init__(self):
+        self.DBPyCoupleManager = PlayerLove.DBPyCoupleManager()
+        self.DBPyUnNotifyLoveGiftRecManager = PlayerLove.DBPyUnNotifyLoveGiftRecManager()
+        self.DBPyCharmValueRecManager = PlayerCharm.DBPyCharmValueRecManager()
+        self.IntimacyManager = PlayerSocial.IntimacyManager()
         self.CrossPersonalCompensationManager = PlayerCompensation.CrossPersonalCompensationManager()
         self.CrossBillboardManager = CrossBillboard.CrossBillboardManager()
         self.PlayerAssistThanksPyManager = PlayerAssistThanksPyManager()
@@ -332,6 +338,10 @@
 
     def GetSaveData(self):
         buff = ""
+        buff += self.DBPyCoupleManager.GetSaveData()
+        buff += self.DBPyUnNotifyLoveGiftRecManager.GetSaveData()
+        buff += self.DBPyCharmValueRecManager.GetSaveData()
+        buff += self.IntimacyManager.GetSaveData()
         buff += self.CrossPersonalCompensationManager.GetSaveData()
         buff += self.CrossBillboardManager.GetSaveData()
         buff += self.PlayerAssistThanksPyManager.GetSaveData()
@@ -356,6 +366,10 @@
         return buff
     
     def LoadGameData(self, gameBuffer, pos):
+        pos = self.DBPyCoupleManager.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
+        pos = self.DBPyUnNotifyLoveGiftRecManager.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
+        pos = self.DBPyCharmValueRecManager.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
+        pos = self.IntimacyManager.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
         pos = self.CrossPersonalCompensationManager.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
         pos = self.CrossBillboardManager.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
         pos = self.PlayerAssistThanksPyManager.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
@@ -467,6 +481,26 @@
     pyGameDataMgr = GetPyGameDataManager()
     return pyGameDataMgr.familyStoreItemManager
 
+def GetDBPyCoupleManager():
+    # 伴侣管理
+    pyGameDataMgr = GetPyGameDataManager()
+    return pyGameDataMgr.DBPyCoupleManager
+
+def GetDBPyUnNotifyLoveGiftRecManager():
+    # 未通知的赠送礼物记录
+    pyGameDataMgr = GetPyGameDataManager()
+    return pyGameDataMgr.DBPyUnNotifyLoveGiftRecManager
+
+def GetDBPyCharmValueRecManager():
+    # 魅力管理
+    pyGameDataMgr = GetPyGameDataManager()
+    return pyGameDataMgr.DBPyCharmValueRecManager
+
+def GetIntimacyManager():
+    # 亲密管理
+    pyGameDataMgr = GetPyGameDataManager()
+    return pyGameDataMgr.IntimacyManager
+
 # 好友系统
 def GetFriendManager():
     pyGameDataMgr = GetPyGameDataManager()
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py b/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py
index 2bcdd79..d06282f 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py
@@ -89,8 +89,9 @@
 
 g_marryReqInfo = {} # 当前进行中的求亲信息 {请求玩家ID:MarryReq, ...}
 g_marryCandyInfo = {} # 进行中的喜糖信息 {(playerIDA, playerIDB):MarryCandy, ...}
-g_marryCandySortList = [] # 按结算时间排序后的喜糖列表
-g_marryBreakReqInfo = {} # 请求离婚信息 {reqPlayerID:tagPlayerID, ...}
+g_marryCandySortList = [] # 按结算时间排序后的喜糖列表,升序
+g_marryBreakInfo = {} # 进行中的离婚信息{(playerIDA, playerIDB):MarryCandy, ...}
+g_marryBreakSortList = [] # 按提交时间排序后的喜糖列表,升序
 
 g_arenaPlayerBattleRecDict = {} # 本服竞技场玩家挑战记录缓存 {playerID:[ArenaBattleRec, ...], ...}
 g_arenaPlayerMatchDict = {} # 本服竞技场玩家匹配记录缓存 {playerID:[ArenaMatchPlayer, ...], ...}
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/PyGameDataStruct.py b/ServerPython/CoreServerGroup/GameServer/Script/PyGameDataStruct.py
index a04b939..68a9d5b 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/PyGameDataStruct.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/PyGameDataStruct.py
@@ -2121,7 +2121,6 @@
     _fields_ = [
         ('PlayerID', ctypes.c_ulong),
         ('TagID', ctypes.c_ulong),
-        ('Intimacy', ctypes.c_ulong),
         ('ADOResult', ctypes.c_ulong),
     ]
 
@@ -2141,7 +2140,6 @@
         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()
 
 
@@ -2157,12 +2155,10 @@
         output = '''//玩家好友表#tagDBPyPlayerFriend:
             PlayerID = %s,
             TagID = %s,
-            Intimacy = %s,
             ADOResult = %s,
             '''%(
                 self.PlayerID,
                 self.TagID,
-                self.Intimacy,
                 self.ADOResult,
             )
         return output
@@ -2232,10 +2228,6 @@
         ('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),
     ]
 
@@ -2260,10 +2252,6 @@
         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()
 
 
@@ -2284,10 +2272,6 @@
             RealmLV = %s,
             OnlineType = %s,
             RefCount = %s,
-            CoupleID = %s,
-            CoupleName = %s,
-            CouplePriceMaxID = %s,
-            CoupleBreakOffline = %s,
             ADOResult = %s,
             '''%(
                 self.PlayerID,
@@ -2297,10 +2281,6 @@
                 self.RealmLV,
                 self.OnlineType,
                 self.RefCount,
-                self.CoupleID,
-                self.CoupleName,
-                self.CouplePriceMaxID,
-                self.CoupleBreakOffline,
                 self.ADOResult,
             )
         return output
@@ -2311,11 +2291,256 @@
             self.PlayerName = Str
         else:
             self.PlayerName = Str[:33]
-            
-    def SetCoupleName(self,Str):
-        if len(Str)<=33:
-            self.CoupleName = Str
-        else:
-            self.CoupleName = Str[:33]
-            
 
+
+# 玩家亲密表 #tagDBPyPlayerIntimacy
+class tagDBPyPlayerIntimacy(Structure):
+    _pack_ = 1
+    _fields_ = [
+        ('PlayerID', ctypes.c_ulong),
+        ('TagID', ctypes.c_ulong),
+        ('Intimacy', ctypes.c_ulong),
+        ('ADOResult', ctypes.c_ulong),
+    ]
+
+    def __init__(self):
+        Structure.__init__(self)
+        self.clear()
+
+
+    def clear(self):
+        memset(addressof(self), 0, self.getLength())
+
+    def readData(self, buf, pos = 0, length = 0):
+        if not pos <= length:
+            return -1
+        if len(buf) < pos + self.getLength():
+            return -1
+        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()
+
+
+    def getBuffer(self):
+        buf = create_string_buffer(self.getLength())
+        memmove(addressof(buf), addressof(self), self.getLength())
+        return string_at(addressof(buf), self.getLength())
+
+    def getLength(self):
+        return sizeof(tagDBPyPlayerIntimacy)
+
+    def outputString(self):
+        output = '''// 玩家亲密表 #tagDBPyPlayerIntimacy:
+            PlayerID = %s,
+            TagID = %s,
+            Intimacy = %s,
+            ADOResult = %s,
+            '''%(
+                self.PlayerID,
+                self.TagID,
+                self.Intimacy,
+                self.ADOResult,
+            )
+        return output
+
+
+# 魅力贡献值记录表 #tagDBPyCharmValueRec
+class tagDBPyCharmValueRec(Structure):
+    _pack_ = 1
+    _fields_ = [
+        ('PlayerID', ctypes.c_ulong),
+        ('Type', ctypes.c_ubyte),
+        ('OfferPlayerID', ctypes.c_ulong),
+        ('CharmValue', ctypes.c_ulong),
+        ('UpdTime', ctypes.c_ulong),
+        ('ADOResult', ctypes.c_ulong),
+    ]
+
+    def __init__(self):
+        Structure.__init__(self)
+        self.clear()
+
+
+    def clear(self):
+        memset(addressof(self), 0, self.getLength())
+
+    def readData(self, buf, pos = 0, length = 0):
+        if not pos <= length:
+            return -1
+        if len(buf) < pos + self.getLength():
+            return -1
+        self.clear()
+        self.PlayerID, pos = CommFunc.ReadDWORD(buf, pos)
+        self.Type, pos = CommFunc.ReadBYTE(buf, pos)
+        self.OfferPlayerID, pos = CommFunc.ReadDWORD(buf, pos)
+        self.CharmValue, pos = CommFunc.ReadDWORD(buf, pos)
+        self.UpdTime, pos = CommFunc.ReadDWORD(buf, pos)
+        return self.getLength()
+
+
+    def getBuffer(self):
+        buf = create_string_buffer(self.getLength())
+        memmove(addressof(buf), addressof(self), self.getLength())
+        return string_at(addressof(buf), self.getLength())
+
+    def getLength(self):
+        return sizeof(tagDBPyCharmValueRec)
+
+    def outputString(self):
+        output = '''// 魅力贡献值记录表 #tagDBPyCharmValueRec:
+            PlayerID = %s,
+            Type = %s,
+            OfferPlayerID = %s,
+            CharmValue = %s,
+            UpdTime = %s,
+            ADOResult = %s,
+            '''%(
+                self.PlayerID,
+                self.Type,
+                self.OfferPlayerID,
+                self.CharmValue,
+                self.UpdTime,
+                self.ADOResult,
+            )
+        return output
+
+
+# 未通知的情缘送礼记录 #tagDBPyUnNotifyLoveGiftRec
+class tagDBPyUnNotifyLoveGiftRec(Structure):
+    _pack_ = 1
+    _fields_ = [
+        ('PlayerID', ctypes.c_ulong),
+        ('GivePlayerID', ctypes.c_ulong),
+        ('GiftNum', ctypes.c_ushort),
+        ('GiftCount', ctypes.c_ulong),
+        ('SendTime', ctypes.c_ulong),
+        ('ADOResult', ctypes.c_ulong),
+    ]
+
+    def __init__(self):
+        Structure.__init__(self)
+        self.clear()
+
+
+    def clear(self):
+        memset(addressof(self), 0, self.getLength())
+
+    def readData(self, buf, pos = 0, length = 0):
+        if not pos <= length:
+            return -1
+        if len(buf) < pos + self.getLength():
+            return -1
+        self.clear()
+        self.PlayerID, pos = CommFunc.ReadDWORD(buf, pos)
+        self.GivePlayerID, pos = CommFunc.ReadDWORD(buf, pos)
+        self.GiftNum, pos = CommFunc.ReadWORD(buf, pos)
+        self.GiftCount, pos = CommFunc.ReadDWORD(buf, pos)
+        self.SendTime, pos = CommFunc.ReadDWORD(buf, pos)
+        return self.getLength()
+
+
+    def getBuffer(self):
+        buf = create_string_buffer(self.getLength())
+        memmove(addressof(buf), addressof(self), self.getLength())
+        return string_at(addressof(buf), self.getLength())
+
+    def getLength(self):
+        return sizeof(tagDBPyUnNotifyLoveGiftRec)
+
+    def outputString(self):
+        output = '''// 未通知的情缘送礼记录 #tagDBPyUnNotifyLoveGiftRec:
+            PlayerID = %s,
+            GivePlayerID = %s,
+            GiftNum = %s,
+            GiftCount = %s,
+            SendTime = %s,
+            ADOResult = %s,
+            '''%(
+                self.PlayerID,
+                self.GivePlayerID,
+                self.GiftNum,
+                self.GiftCount,
+                self.SendTime,
+                self.ADOResult,
+            )
+        return output
+
+
+# 伴侣表 #tagDBPyCouple
+class tagDBPyCouple(Structure):
+    _pack_ = 1
+    _fields_ = [
+        ('PlayerIDA', ctypes.c_ulong),
+        ('PlayerIDB', ctypes.c_ulong),
+        ('NewMarryTime', ctypes.c_ulong),
+        ('MarryTime', ctypes.c_ulong),
+        ('BridePriceState', ctypes.c_ulong),
+        ('BreakRequestID', ctypes.c_ulong),
+        ('BreakRequestTime', ctypes.c_ulong),
+        ('BreakRequestTimeA', ctypes.c_ulong),
+        ('BreakRequestTimeB', ctypes.c_ulong),
+        ('ADOResult', ctypes.c_ulong),
+    ]
+
+    def __init__(self):
+        Structure.__init__(self)
+        self.clear()
+
+
+    def clear(self):
+        memset(addressof(self), 0, self.getLength())
+
+    def readData(self, buf, pos = 0, length = 0):
+        if not pos <= length:
+            return -1
+        if len(buf) < pos + self.getLength():
+            return -1
+        self.clear()
+        self.PlayerIDA, pos = CommFunc.ReadDWORD(buf, pos)
+        self.PlayerIDB, pos = CommFunc.ReadDWORD(buf, pos)
+        self.NewMarryTime, pos = CommFunc.ReadDWORD(buf, pos)
+        self.MarryTime, pos = CommFunc.ReadDWORD(buf, pos)
+        self.BridePriceState, pos = CommFunc.ReadDWORD(buf, pos)
+        self.BreakRequestID, pos = CommFunc.ReadDWORD(buf, pos)
+        self.BreakRequestTime, pos = CommFunc.ReadDWORD(buf, pos)
+        self.BreakRequestTimeA, pos = CommFunc.ReadDWORD(buf, pos)
+        self.BreakRequestTimeB, pos = CommFunc.ReadDWORD(buf, pos)
+        return self.getLength()
+
+
+    def getBuffer(self):
+        buf = create_string_buffer(self.getLength())
+        memmove(addressof(buf), addressof(self), self.getLength())
+        return string_at(addressof(buf), self.getLength())
+
+    def getLength(self):
+        return sizeof(tagDBPyCouple)
+
+    def outputString(self):
+        output = '''// 伴侣表 #tagDBPyCouple:
+            PlayerIDA = %s,
+            PlayerIDB = %s,
+            NewMarryTime = %s,
+            MarryTime = %s,
+            BridePriceState = %s,
+            BreakRequestID = %s,
+            BreakRequestTime = %s,
+            BreakRequestTimeA = %s,
+            BreakRequestTimeB = %s,
+            ADOResult = %s,
+            '''%(
+                self.PlayerIDA,
+                self.PlayerIDB,
+                self.NewMarryTime,
+                self.MarryTime,
+                self.BridePriceState,
+                self.BreakRequestID,
+                self.BreakRequestTime,
+                self.BreakRequestTimeA,
+                self.BreakRequestTimeB,
+                self.ADOResult,
+            )
+        return output
+            
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
index ee2d293..0816ae1 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
@@ -1615,7 +1615,7 @@
 
 PacketCMD_1=0xB3
 PacketSubCMD_1=0x10
-PacketCallFunc_1=OnSendFlowers
+PacketCallFunc_1=OnSendGifts
 
 PacketCMD_2=0xB3
 PacketSubCMD_2=0x11
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
index a8e2831..0ad82b5 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -4170,12 +4170,6 @@
 Def_PDict_FuncSysPrivilegeAward = "FuncSysPrivilegeAward_%s" # 系统功能特权领奖记录,参数(系统功能ID)
 
 #情缘
-Def_PDict_LoveCharmTotal = "LoveCharmTotal" # 魅力值 - 总
-Def_PDict_LoveCharmToday = "LoveCharmToday" # 魅力值 - 今日
-Def_PDict_LoveNewMarryTime = "LoveNewMarryTime" # 成亲时间 - 新婚时间 
-Def_PDict_LoveMarryTime = "LoveMarryTime" # 成亲时间  - 最近一次提亲成功时间
-Def_PDict_LoveBridePriceState = "LoveBridePriceState" # 聘礼状态,按聘礼ID位存储每种聘礼已购买次数
-Def_PDict_LoveBridePriceMaxID = "LoveBridePriceMaxID" # 提亲最大聘礼ID,用于决定伴侣昵称颜色等
 Def_PDict_LoveRingClassLV = "LoveRingClassLV" # 情戒 - 阶级
 Def_PDict_LoveRingStarLV = "LoveRingStarLV" # 情戒 - 星级
 Def_PDict_LoveRingEatCount = "LoveRingEatCount" # 情戒 - 本星已淬炼道具数
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
index 8822b65..2486b4e 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
@@ -2330,6 +2330,66 @@
 
 
 #------------------------------------------------------
+# B3 09 魅力贡献榜查看 #tagCGCharmOfferBillboardQuery
+
+class  tagCGCharmOfferBillboardQuery(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("PlayerID", c_int),    # 魅力玩家ID
+                  ("QueryType", c_ubyte),    # 查看类型: 1-总榜,2-周榜,3-日榜
+                  ("QueryCount", c_ubyte),    # 查看名次数量,最大255
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xB3
+        self.SubCmd = 0x09
+        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 = 0x09
+        self.PlayerID = 0
+        self.QueryType = 0
+        self.QueryCount = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCGCharmOfferBillboardQuery)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// B3 09 魅力贡献榜查看 //tagCGCharmOfferBillboardQuery:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                PlayerID:%d,
+                                QueryType:%d,
+                                QueryCount:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.PlayerID,
+                                self.QueryType,
+                                self.QueryCount
+                                )
+        return DumpString
+
+
+m_NAtagCGCharmOfferBillboardQuery=tagCGCharmOfferBillboardQuery()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCGCharmOfferBillboardQuery.Cmd,m_NAtagCGCharmOfferBillboardQuery.SubCmd))] = m_NAtagCGCharmOfferBillboardQuery
+
+
+#------------------------------------------------------
 # B3 16 和平离婚回应 #tagGCMarryBreakResponse
 
 class  tagGCMarryBreakResponse(Structure):
@@ -4419,15 +4479,17 @@
 
 
 #------------------------------------------------------
-# B3 10 送花 #tagCMSendFlowers
+# B3 10 送礼物 #tagCMSendGifts
 
-class  tagCMSendFlowers(Structure):
+class  tagCMSendGifts(Structure):
     _pack_ = 1
     _fields_ = [
                   ("Cmd", c_ubyte),
                   ("SubCmd", c_ubyte),
                   ("TagPlayerID", c_int),    # 目标玩家ID
-                  ("FlowerCount", c_int),    # 赠送花数量
+                  ("GiftNum", c_ushort),    # 赠送礼物编号
+                  ("GiftCount", c_int),    # 赠送礼物数量
+                  ("IsAutoBuy", c_ubyte),    # 是否自动购买
                   ]
 
     def __init__(self):
@@ -4445,33 +4507,39 @@
         self.Cmd = 0xB3
         self.SubCmd = 0x10
         self.TagPlayerID = 0
-        self.FlowerCount = 0
+        self.GiftNum = 0
+        self.GiftCount = 0
+        self.IsAutoBuy = 0
         return
 
     def GetLength(self):
-        return sizeof(tagCMSendFlowers)
+        return sizeof(tagCMSendGifts)
 
     def GetBuffer(self):
         return string_at(addressof(self), self.GetLength())
 
     def OutputString(self):
-        DumpString = '''// B3 10 送花 //tagCMSendFlowers:
+        DumpString = '''// B3 10 送礼物 //tagCMSendGifts:
                                 Cmd:%s,
                                 SubCmd:%s,
                                 TagPlayerID:%d,
-                                FlowerCount:%d
+                                GiftNum:%d,
+                                GiftCount:%d,
+                                IsAutoBuy:%d
                                 '''\
                                 %(
                                 self.Cmd,
                                 self.SubCmd,
                                 self.TagPlayerID,
-                                self.FlowerCount
+                                self.GiftNum,
+                                self.GiftCount,
+                                self.IsAutoBuy
                                 )
         return DumpString
 
 
-m_NAtagCMSendFlowers=tagCMSendFlowers()
-ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMSendFlowers.Cmd,m_NAtagCMSendFlowers.SubCmd))] = m_NAtagCMSendFlowers
+m_NAtagCMSendGifts=tagCMSendGifts()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMSendGifts.Cmd,m_NAtagCMSendGifts.SubCmd))] = m_NAtagCMSendGifts
 
 
 #------------------------------------------------------
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventSrc/FunctionNPCCommon.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventSrc/FunctionNPCCommon.py
index 8221f83..ddcfb1c 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventSrc/FunctionNPCCommon.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventSrc/FunctionNPCCommon.py
@@ -531,7 +531,7 @@
     PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_DelPackIndex, int(itemIndexs))
     return
 
-def PayAutoBuyItem(curPlayer, lackItemDict, priceType, costType=ChConfig.Def_Cost_Unknown, infoDict={}):
+def PayAutoBuyItem(curPlayer, lackItemDict, priceType, costType=ChConfig.Def_Cost_Unknown, infoDict={}, isCheck=False):
     ''' 支付自动购买物品消耗,从商城中购买,直接扣钱,不产生物品
             一般用于基础商店自动购买物品,不考虑复杂的限购逻辑
     '''
@@ -570,6 +570,9 @@
     if totalMoney <= 0:
         return
     
+    if isCheck:
+        return PlayerControl.HaveMoney(curPlayer, priceType, totalMoney)
+    
     GameWorld.DebugLog("扣除自动购买消耗: lackItemDict=%s,priceType=%s,totalMoney=%s,costType=%s,addLimitCountInfo=%s" 
                        % (lackItemDict, priceType, totalMoney, costType, addLimitCountInfo), curPlayer.GetPlayerID())
     
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
deleted file mode 100644
index b3543d4..0000000
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Love.py
+++ /dev/null
@@ -1,100 +0,0 @@
-#!/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/LoveRing.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/LoveRing.py
new file mode 100644
index 0000000..aff06ab
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/LoveRing.py
@@ -0,0 +1,49 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package GM.Commands.LoveRing
+#
+# @todo:情戒
+# @author hxp
+# @date 2021-11-09
+# @version 1.0
+#
+# 详细描述: 情戒
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2021-11-09 20:00"""
+#-------------------------------------------------------------------------------
+
+import GameWorld
+import PlayerControl
+import PlayerLove
+import ChConfig
+
+## GM命令执行入口
+#  @param curPlayer 当前玩家
+#  @param msgList 参数列表 [addSkillID]
+#  @return None
+#  @remarks 函数详细说明.
+def OnExec(curPlayer, msgList):
+    
+    if not msgList:
+        GameWorld.DebugAnswer(curPlayer, "重置情戒: LoveRing 0")
+        GameWorld.DebugAnswer(curPlayer, "设置情戒: LoveRing 阶  [可选星  已吃个数]")
+        return
+    
+    classLV = msgList[0] if len(msgList) > 0 else 1
+    if classLV == 0:
+        starLV, eatCount = 0, 0
+    else:
+        starLV = msgList[1] if len(msgList) > 1 else 1
+        eatCount = msgList[2] if len(msgList) > 2 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
+
+
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
index 67bf73d..aa409b1 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
@@ -1876,11 +1876,15 @@
                         ("BYTE", "QualityLV", 1),
                         ),
 
+                "LoveGift":(
+                        ("BYTE", "GiftNum", 1),
+                        ("DWORD", "GiftItemID", 0),
+                        ("BYTE", "AllowBatch", 0),
+                        ),
+
                 "Marry":(
                         ("BYTE", "BridePriceID", 1),
                         ("list", "CostMoneyInfo", 0),
-                        ("BYTE", "CanBuyCount", 0),
-                        ("BYTE", "IsDayReset", 0),
                         ),
 
                 "LoveRing":(
@@ -5802,20 +5806,29 @@
     def GetPointID(self): return self.PointID # 灵根ID
     def GetQualityLV(self): return self.QualityLV # 品级
 
+# 情缘礼物表
+class IPY_LoveGift():
+    
+    def __init__(self):
+        self.GiftNum = 0
+        self.GiftItemID = 0
+        self.AllowBatch = 0
+        return
+        
+    def GetGiftNum(self): return self.GiftNum # 聘礼ID
+    def GetGiftItemID(self): return self.GiftItemID # 物品ID
+    def GetAllowBatch(self): return self.AllowBatch # 是否允许批量赠送
+
 # 情缘提亲表
 class IPY_Marry():
     
     def __init__(self):
         self.BridePriceID = 0
-        self.CostMoneyInfo = []
-        self.CanBuyCount = 0
-        self.IsDayReset = 0
+        self.CostMoneyInfo = []
         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 # 是否每日重置
+    def GetCostMoneyInfo(self): return self.CostMoneyInfo # 消耗货币类型|数值
 
 # 情缘情戒表
 class IPY_LoveRing():
@@ -6304,6 +6317,8 @@
         self.ipySkyTowerServerChallengeLen = len(self.ipySkyTowerServerChallengeCache)
         self.ipyLingGenEffectCache = self.__LoadFileData("LingGenEffect", IPY_LingGenEffect)
         self.ipyLingGenEffectLen = len(self.ipyLingGenEffectCache)
+        self.ipyLoveGiftCache = self.__LoadFileData("LoveGift", IPY_LoveGift)
+        self.ipyLoveGiftLen = len(self.ipyLoveGiftCache)
         self.ipyMarryCache = self.__LoadFileData("Marry", IPY_Marry)
         self.ipyMarryLen = len(self.ipyMarryCache)
         self.ipyLoveRingCache = self.__LoadFileData("LoveRing", IPY_LoveRing)
@@ -6860,6 +6875,8 @@
     def GetSkyTowerServerChallengeByIndex(self, index): return self.ipySkyTowerServerChallengeCache[index]
     def GetLingGenEffectCount(self): return self.ipyLingGenEffectLen
     def GetLingGenEffectByIndex(self, index): return self.ipyLingGenEffectCache[index]
+    def GetLoveGiftCount(self): return self.ipyLoveGiftLen
+    def GetLoveGiftByIndex(self, index): return self.ipyLoveGiftCache[index]
     def GetMarryCount(self): return self.ipyMarryLen
     def GetMarryByIndex(self, index): return self.ipyMarryCache[index]
     def GetLoveRingCount(self): return self.ipyLoveRingLen
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 aae8f25..b25c494 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
@@ -6200,9 +6200,29 @@
 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)
+##伴侣
+def GetCoupleID(curPlayer):
+    coupleInfo = GetCoupleInfo(curPlayer.GetPlayerID())
+    return coupleInfo[0] if coupleInfo else 0
+def GetCoupleName(curPlayer):
+    coupleInfo = GetCoupleInfo(curPlayer.GetPlayerID())
+    return coupleInfo[1] if coupleInfo else ""
+def GetCoupleJob(curPlayer):
+    coupleInfo = GetCoupleInfo(curPlayer.GetPlayerID())
+    return coupleInfo[2] if coupleInfo else 1
+def GetBridePriceMaxID(curPlayer):
+    coupleInfo = GetCoupleInfo(curPlayer.GetPlayerID())
+    return coupleInfo[3] if coupleInfo else 0
+def GetCoupleInfo(playerID):
+    if playerID not in PyGameData.g_coupleInfo:
+        return
+    return PyGameData.g_coupleInfo[playerID]
+def SetCoupleInfo(playerID, coupleInfo):
+    if not coupleInfo:
+        PyGameData.g_coupleInfo.pop(playerID, None)
+    else:
+        PyGameData.g_coupleInfo[playerID] = coupleInfo
+    return
 
 ## 玩家所属服务器组ID
 def GetPlayerServerGroupID(curPlayer): return curPlayer.GetExAttr13()
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
index 0b2cd6f..23cc1ca 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
@@ -1350,10 +1350,7 @@
         if key == ShareDefine.Def_Notify_WorldKey_CoupleInfo:
             syncCoupleInfo = eval(msgValue)
             for playerID, coupleInfo in syncCoupleInfo.items():
-                if not coupleInfo:
-                    PyGameData.g_coupleInfo.pop(playerID, None)
-                else:
-                    PyGameData.g_coupleInfo[playerID] = coupleInfo
+                PlayerControl.SetCoupleInfo(playerID, coupleInfo)
             return
         
         if key.startswith(ShareDefine.Def_Notify_WorldKey_OperationActionInfo[:-2]): 
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerLove.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerLove.py
index 33f4029..99570be 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerLove.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerLove.py
@@ -20,88 +20,66 @@
 import PlayerControl
 import IpyGameDataPY
 import ChPyNetSendPack
-import PlayerBillboard
+import FunctionNPCCommon
 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)
-            
+def DoPlayerOnDay(curPlayer):   
     return
 
 def DoPlayerLogin(curPlayer):
-    Sync_CharmInfo(curPlayer)
-    Sync_CoupleInfo(curPlayer)
     Sync_LoveRingInfo(curPlayer)
     return
 
-#// B3 10 送花 #tagCMSendFlowers
+#// B3 10 送礼物 #tagCMSendGifts
 #
-#struct    tagCMSendFlowers
+#struct    tagCMSendGifts
 #{
 #    tagHead        Head;
 #    DWORD        TagPlayerID;    // 目标玩家ID
-#    DWORD        FlowerCount;    // 赠送花数量
+#    WORD        GiftNum;        // 赠送礼物编号
+#    DWORD        GiftCount;    // 赠送礼物数量
+#    BYTE        IsAutoBuy;    // 是否自动购买
 #};
-def OnSendFlowers(index, clientData, tick):
+def OnSendGifts(index, clientData, tick):
     curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
     tagPlayerID = clientData.TagPlayerID
-    flowerCount = clientData.FlowerCount
+    giftNum = clientData.GiftNum
+    giftCount = clientData.GiftCount
+    isAutoBuy = clientData.IsAutoBuy
     
-    if flowerCount <= 0:
+    if giftNum <= 0 or giftCount <= 0:
         return
     
-    flowerCountInfoDict = IpyGameDataPY.GetFuncEvalCfg("LoveFlower", 2, {})
-    if str(flowerCount) not in flowerCountInfoDict:
+    ipyData = IpyGameDataPY.GetIpyGameData("LoveGift", giftNum)
+    if not ipyData:
         return
-    addCharm, addCharmTag, addIntimacy = flowerCountInfoDict[str(flowerCount)]
-    flowerID = IpyGameDataPY.GetFuncCfg("LoveFlower", 1)
     
-    _, bindCnt, unBindCnt = ItemCommon.GetPackItemBindStateIndexInfo(curPlayer, flowerID, flowerCount)
-    lackCnt = flowerCount - bindCnt - unBindCnt
+    giftItemID = ipyData.GetGiftItemID()
+    if not ipyData.GetAllowBatch():
+        giftCount = 1 # 不允许批量赠送的默认赠送1个
+        
+    _, bindCnt, unBindCnt = ItemCommon.GetPackItemBindStateIndexInfo(curPlayer, giftItemID, giftCount)
+    lackCnt = giftCount - 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 isAutoBuy:
+            GameWorld.DebugLog("礼物道具不足,无法赠送! giftItemID=%s,giftCount=%s,bindCnt=%s,unBindCnt=%s,lackCnt=%s" 
+                               % (giftItemID, giftCount, bindCnt, unBindCnt, lackCnt))
+            return
+        
+        moneyType = IpyGameDataPY.GetFuncCfg("LoveGift", 1)
+        infoDict = {ChConfig.Def_Cost_Reason_SonKey:giftItemID}
+        if not FunctionNPCCommon.PayAutoBuyItem(curPlayer, {giftItemID:lackCnt}, moneyType, ChConfig.Def_Cost_Love, infoDict, isCheck=True):
+            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)
+    dataMsg = [tagPlayerID, giftNum, giftItemID, giftCount, isAutoBuy]
+    SendToGameServer_Love(curPlayer, "SendGiftsReq", dataMsg)
     return
 
 #// B3 11 提亲 #tagCMMarryReq
@@ -117,26 +95,9 @@
     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
@@ -222,23 +183,9 @@
     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)
+        costMoneyInfo = IpyGameDataPY.GetFuncEvalCfg("LoveMarryBreak", 3)
         if len(costMoneyInfo) != 2:
             return
         moneyType, moneyValue = costMoneyInfo
@@ -250,7 +197,7 @@
         PlayerControl.NotifyCode(curPlayer, "RequestLater")
         return
     
-    dataMsg = [playerID, coupleID, breakType, moneyType, moneyValue]
+    dataMsg = [playerID, breakType, moneyType, moneyValue]
     SendToGameServer_Love(curPlayer, "MarryBreakReq", dataMsg)
     return
 
@@ -265,14 +212,8 @@
     
     msgType, dataMsg = msgData[:2]
     
-    ## 增加魅力值
-    if msgType == "AddCharm":
-        addCharmTag = dataMsg[0]
-        __DoAddCharm(curPlayer, addCharmTag)
-        return
-    
     ## 结婚成功
-    elif msgType == "MarrySuccess":
+    if msgType == "MarrySuccess":
         __DoMarrySuccess(curPlayer, dataMsg)
     
     ## 离婚成功
@@ -285,11 +226,11 @@
     
     msgType, dataMsg, ret = msgData
     
-    ## 送花请求返回
-    if msgType == "SendFlowersReq":
+    ## 送礼物请求返回
+    if msgType == "SendGiftsReq":
         if not ret:
             return
-        __DoSendFlowers(curPlayer, dataMsg)
+        __DoSendGiftsReq(curPlayer, dataMsg)
         
     ## 吃喜糖返回
     elif msgType == "MarryEatCandy":
@@ -311,27 +252,35 @@
         
     return
 
-def __DoSendFlowers(curPlayer, dataMsg):
-    ## 送花方处理
+def __DoSendGiftsReq(curPlayer, dataMsg):
+    ## 送礼物方处理
     
     playerID = curPlayer.GetPlayerID()
-    tagPlayerID, flowerID, flowerCount, addCharm = dataMsg[:4]
+    tagPlayerID, giftNum, giftItemID, giftCount, isAutoBuy = dataMsg
     
-    costItemIndexList, bindCnt, unBindCnt = ItemCommon.GetPackItemBindStateIndexInfo(curPlayer, flowerID, flowerCount)
-    lackCnt = flowerCount - bindCnt - unBindCnt
+    costItemIndexList, bindCnt, unBindCnt = ItemCommon.GetPackItemBindStateIndexInfo(curPlayer, giftItemID, giftCount)
+    lackCnt = giftCount - bindCnt - unBindCnt
+    delCnt = giftCount
     if lackCnt > 0:
-        GameWorld.ErrLog("地图鲜花道具不足,无法赠送! tagPlayerID=%s,flowerID=%s,flowerCount=%s,lackCnt=%s" 
-                         % (tagPlayerID, flowerID, flowerCount, lackCnt), playerID)
-        return
+        if not isAutoBuy:
+            GameWorld.ErrLog("礼物道具不足,无法赠送! giftItemID=%s,giftCount=%s,bindCnt=%s,unBindCnt=%s,lackCnt=%s" 
+                             % (giftItemID, giftCount, bindCnt, unBindCnt, lackCnt))
+            return
+        
+        moneyType = IpyGameDataPY.GetFuncCfg("LoveGift", 1)
+        infoDict = {ChConfig.Def_Cost_Reason_SonKey:giftItemID}
+        if not FunctionNPCCommon.PayAutoBuyItem(curPlayer, {giftItemID:lackCnt}, moneyType, ChConfig.Def_Cost_Love, infoDict):
+            return
+        delCnt -= lackCnt
+        
+    GameWorld.Log("赠送礼物: tagPlayerID=%s,giftNum=%s,giftItemID=%s,giftCount=%s,isAutoBuy=%s" 
+                  % (tagPlayerID, giftNum, giftItemID, giftCount, isAutoBuy), playerID)
     
-    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)
+    # 扣除消耗
+    if delCnt > 0:
+        ItemCommon.DelCostItemByBind(curPlayer, costItemIndexList, bindCnt, unBindCnt, delCnt, "Love")
+        
+    SendToGameServer_Love(curPlayer, "SendGiftsOK", dataMsg)
     return
 
 def __DoMarryEatCandy(curPlayer, retInfo):
@@ -369,57 +318,19 @@
     ## 离婚请求结果返回
     
     costMoneyType, costMoneyValue = retInfo
-    GameWorld.Log("执行离婚请求结果: costMoneyType=%s, costMoneyValue=%s" % (costMoneyType, costMoneyValue), curPlayer.GetPlayerID())
+    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) # 是否新婚
+    reqPlayerID, bridePriceID, mapServerCoupleInfo = dataMsg
     playerID = curPlayer.GetPlayerID()
+    PlayerControl.SetCoupleInfo(playerID, mapServerCoupleInfo)
     
-    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)
+    GameWorld.Log("执行成亲成功! reqPlayerID=%s,bridePriceID=%s" % (reqPlayerID, bridePriceID), playerID)
     
     if curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LoveRingClassLV) == 0:
         GameWorld.DebugLog("激活情戒!")
@@ -428,9 +339,6 @@
         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)
@@ -442,20 +350,13 @@
     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)
+    PlayerControl.SetCoupleInfo(playerID, None)
     
     GameWorld.Log("清除伴侣关系成功! coupleID=%s" % (coupleID), playerID)
     RefreshLoveAttr(curPlayer)
@@ -555,7 +456,7 @@
         
     # 扣除消耗
     if delCnt:
-        ItemCommon.DelCostItemByBind(curPlayer, costItemIndexList, bindCnt, unBindCnt, delCnt, "LoveRing")
+        ItemCommon.DelCostItemByBind(curPlayer, costItemIndexList, bindCnt, unBindCnt, delCnt, "Love")
         
     # 升星
     if ringUpType == "starUp":
@@ -631,24 +532,6 @@
     # 保存计算值
     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):
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 2c30c71..f90c0bb 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTalk.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTalk.py
@@ -381,12 +381,10 @@
     # 等级
     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)
+    coupleName = PlayerControl.GetCoupleName(objTalk)
+    coupleJob = PlayerControl.GetCoupleJob(objTalk)
+    bridePriceMaxID = PlayerControl.GetBridePriceMaxID(objTalk)
+    extraValueStr = "%s|%s|%s|%s" % (extraValueStr, coupleName, coupleJob, 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 fe51838..40ca12b 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerViewCacheTube.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerViewCacheTube.py
@@ -177,7 +177,6 @@
     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()

--
Gitblit v1.8.0