Files
mir_server/server/LogicServer/store/GameStore.cpp
aixianling 5c9f1dae4a init
2025-01-09 17:45:40 +08:00

790 lines
20 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "StdAfx.h"
#include "GameStore.h"
#include "../base/Container.hpp"
using namespace wylib::stream;
CGameStore::CGameStore()
:Inherited()
{
}
CGameStore::~CGameStore()
{
m_Merchands.empty();
m_refreshConfig.empty();
}
bool CGameStore::LoadGameStore(LPCTSTR sFilePath)
{
bool result = false;
CMemoryStream ms;
CCustomLuaPreProcessor pp;
//定义一个临时的商品表,将商品读取到此临时表。如果最终读取完成则拷贝到商品表中
CVector<Merchandise> merchandList;
try
{
//加载商城配置文件
if (ms.loadFromFile(sFilePath) <= 0)
{
showErrorFormat(_T("unable to load GameStore config %s "), sFilePath);
return false;
}
//对配置文件进行预处理
GetLogicServer()->GetVSPDefine().RegisteToPreprocessor(pp);
LPCTSTR sText = pp.parse((LPCTSTR)ms.getMemory(), sFilePath);
//设置配置脚本
if ( !sText || !setScript(sText) )
{
showError(_T("parse config error"));
return false;
}
//读取配置
result = ReadShopConfig();//ReadConfig(merchandList);
}
catch (RefString &s)
{
OutputMsg(rmError, s.rawStr());
}
catch (...)
{
OutputMsg(rmError, _T("unexpected error on load GameStore config"));
}
//如果读取配置成功则将临时商品表中的商品添加到我的商品列表中
if (result)
{
m_Merchands.clear();
m_Merchands.addList(merchandList);
merchandList.empty();
}
//清空脚本内存
setScript(NULL);
return result;
}
bool CGameStore::LoadGameRefresh(LPCTSTR sFilePath)
{
bool result = false;
CMemoryStream ms;
CCustomLuaPreProcessor pp;
//定义一个临时的商品表,将商品读取到此临时表。如果最终读取完成则拷贝到商品表中
CVector<MerchanRefresh> refreshList; //商品的刷新
try
{
//加载商城配置文件
if (ms.loadFromFile(sFilePath) <= 0)
{
showErrorFormat(_T("unable to load GameRfreshStore config %s "), sFilePath);
return false;
}
//对配置文件进行预处理
GetLogicServer()->GetVSPDefine().RegisteToPreprocessor(pp);
LPCTSTR sText = pp.parse((LPCTSTR)ms.getMemory(), sFilePath);
//设置配置脚本
if ( !sText || !setScript(sText) )
{
showError(_T("parse config error"));
return false;
}
//读取配置
result = ReadRefreshConfig(refreshList);
}
catch (RefString &s)
{
OutputMsg(rmError, s.rawStr());
}
catch (...)
{
OutputMsg(rmError, _T("unexpected error on load GameRefresh config"));
}
//如果读取配置成功则将临时商品表中的商品添加到我的商品列表中
if (result)
{
m_refreshConfig.clear();
m_refreshConfig.addList(refreshList);
refreshList.empty();
}
//清空脚本内存
setScript(NULL);
return result;
}
bool CGameStore::ReadRefreshConfig(CBaseList<MerchanRefresh> &refreshList)
{
if (!openGlobalTable("RefreshStore"))
return false;
//遍历刷新的列表
m_labelCount.clear();
INT_PTR nLabelId=0;
if ( enumTableFirst() )
{
MerchanRefresh md;
int nDef =-1;
do
{
nLabelId ++;
int nCountLimit = getFieldInt("count");
m_labelCount.add(nCountLimit);
if ( openFieldTable("items") )
{
if ( enumTableFirst() )
{
do
{
md.nMerchandiseId = getFieldInt("id");
if(GetMerchandise(md.nMerchandiseId) ==NULL)
{
OutputMsg(rmError,_T("store refresh data, id=%d is invalid"),md.nMerchandiseId );
continue;
}
md.nCount = getFieldInt("count");
nDef =-1;
md.nWeekDay = (BYTE)getFieldInt("weekDay",&nDef);
md.bMonth = (BYTE)getFieldInt("month",&nDef);
md.bDay = (BYTE)getFieldInt("day",&nDef);
nDef = 0;
md.nPercent = getFieldInt("percent",&nDef);
md.nOpenServerDay = (BYTE)getFieldInt("openServerDay",&nDef);
md.nMergeServerDay= (BYTE)getFieldInt("mergeServerDay",&nDef);
md.nBeforeMergeDay= (BYTE)getFieldInt("beforeMergeDay",&nDef);
md.nLabelId = (BYTE)nLabelId;
refreshList.add(md);
}
while (enumTableNext());
}
closeTable();
}
} while (enumTableNext());
}
closeTable();
return true;
}
const CGameStore::PMERCHANDISE CGameStore::GetMerchandise(const INT_PTR nId)const
{
INT_PTR i;
for (i=m_Merchands.count()-1; i>-1; --i)
{
if (m_Merchands[i].nId == nId)
{
return &m_Merchands[i];
}
}
return NULL;
}
const CGameStore::PMERCHANDISE CGameStore::GetShopItem( WORD wItemId) const
{
INT_PTR i;
for (i=m_Merchands.count()-1; i>-1; --i)
{
if (m_Merchands[i].wItemId == wItemId)
{
return &m_Merchands[i];
}
}
return NULL;
}
bool CGameStore::ReadConfig(CBaseList<Merchandise> &merchandList)
{
//打开商城配置表
if( !openGlobalTable("GameStore") )
{
return false;
}
LPCSTR sSPID = GetLogicServer()->GetVSPDefine().GetDefinition(CVSPDefinition::SPID);
//遍历商城分类表
if( enumTableFirst() )
{
Merchandise md;
//获取当前的SPID
int nDefault=0;
m_Merchands.clear();
int nDef =0;
int nCountDef = 1; //缺省每次购买1个物品
int nJobDef = 0; //无职业要求
int nSexDef = -1; //无性别要求
do
{
//标签的id
int labelId = getFieldInt("labelId",&nDefault); //分类的id
int nTotalCount = getFieldInt("totalBuyLimit",&nDefault); //最大能够购买的数目
bool bDefault = false;
//是否是动态添加的
bool bDynamicAdd = getFieldBoolean("dynamicAdd",&bDefault);
//打开商品分类中的商品表
if ( openFieldTable("items") )
{
//遍历单个商品分类中的所有商品
if ( enumTableFirst() )
{
do
{
nDef =0;
md.nId = getFieldInt("id"); //销售ID商城中的任意商品必须都不一样
md.wItemId = getFieldInt("item");
md.wItemCount = getFieldInt("count", &nCountDef);
md.bQuality = (BYTE)getFieldInt("quality",&nDef);
md.wQualityDataIndex = (WORD)getFieldInt("qualityDataIndex",&nDef);
md.bStrong = (BYTE)getFieldInt("strong",&nDef);
md.bLabelId = (BYTE) labelId; //分类的ID
md.wLabelBuyLimit = (WORD) nTotalCount; //整个分类能买多少个
md.bSaleLevel = (BYTE)getFieldInt("saleLevel",&nDef);
md.nJob = (int)getFieldInt("job",&nJobDef); //职业要求
md.nSex = (int)getFieldInt("sex",&nSexDef); //性别要求
md.bUse = (BYTE)getFieldInt("use",&nDef); // 立即使用要求
md.bDynamicAdd = bDynamicAdd; //是否是动态添加的
int nSingleBuyLimit = getFieldInt("singleBuyLimit",&nDefault); //单个商品每天购买的数目
md.bSingleBuyLimit = (WORD)nSingleBuyLimit; //单个商品的数目限制
md.dFreshBuyLimit = (WORD)getFieldInt("freshBuyLimit",&nDefault);
//读取物品的价格,如果价格有效则添加到商品表中
if( ReadMerchandisePrice(sSPID, md) && md.dwPrice >= 0 )
{
//如果已经存在同ID的物品则报错
for(int i=0; i < merchandList.count(); ++i)
{
if( merchandList[i].nId == md.nId )
{
showErrorFormat(_T("store id %d already exists"), md.nId);
break;
}
}
merchandList.add(md);
}
else
{
OutputMsg(rmError,_T("store id =%d, price error"),md.nId );
}
}
while (enumTableNext());
}
closeTable();
}
}
while (enumTableNext());
}
closeTable();
return true;
}
bool CGameStore::ReadMerchandisePrice(LPCSTR sCurrSPID, Merchandise &merchandise)
{
//如果价格配置表不存在则返回false
if ( !feildTableExists("price") )
return false;
//打开价格配置表
if ( openFieldTable("price") )
{
LPCSTR sSPID;
UINT dwPrice; //原价
//遍历价格配置表
if (enumTableFirst())
{
merchandise.dwPrice = 0; //将价格标记为0以便不出售
do
{
sSPID = getFieldString("spid"); //运营商ID不同的运营商可能商品价格不同
if ( *(PWORD)sSPID == '*' || !strcmp(sSPID, sCurrSPID) )
{
merchandise.btDealGoldType = getFieldInt("type"); //货币类型0-金币2-绑定元宝3-元宝)
//验证交易币种类型配置是否有效,如果无效则报错(这里从原货币类型改为奖励类型)
if( merchandise.btDealGoldType < qatEquipment || merchandise.btDealGoldType >= qatAwardTypeCount )
showErrorFormat(_T("invalid dealType value %d of merchandise %d"), merchandise.btDealGoldType, merchandise.nId);
dwPrice = getFieldInt("price"); //原价
if( *(PWORD)sSPID != '*' || merchandise.dwPrice == 0 )
{
merchandise.dwPrice = dwPrice;
merchandise.boBind = getFieldBoolean("bind");
}
}
}
while (enumTableNext());
}
closeTable();
}
return true;
}
void CGameStore::showError(LPCTSTR sError)
{
m_sLastErrDesc = sError;
RefString s = _T("[GameStore]");
s += sError;
throw s;
}
bool CGameStore::LoadDynamicData()
{
m_dynamicMerchands.LoadFromFile("./data/runtime/store/dynamicMerchans.rtd"); //动态的商品
m_consumerMerchands.LoadFromFile("./data/runtime/store/consumeMerchans.rtd"); //玩家消耗的商品
m_refreshTime.LoadFromFile("./data/runtime/store/refreshTime.rtd"); //刷新时间
m_YBConsumeRank.LoadTodayConsumeRankFile();
m_YBConsumeRank.LoadYesterdayConsumeRank();
//如果保存的时间过期了,那么就需要刷新
unsigned int nCurrentTime = CMiniDateTime::now();
for(INT i=1;i <= m_labelCount.count(); i++)
{
unsigned int nLastRefTime=(unsigned int) GetRefreshTime(i);
if(nLastRefTime + REFRESH_TIME_INTERVAL <= nCurrentTime ) //这里表示已经过期,可以继续刷新了
{
ResetDynamicMerchadise(i);
}
}
return true;
}
bool CGameStore::SaveDynamicData()
{
OutputMsg(rmTip,_T("Saving Store dynamic data"));
m_dynamicMerchands.SaveToFile("./data/runtime/store/dynamicMerchans.rtd"); //动态的商品
m_consumerMerchands.SaveToFile("./data/runtime/store/consumeMerchans.rtd"); //玩家消耗的商品
m_refreshTime.SaveToFile("./data/runtime/store/refreshTime.rtd"); //刷新时间
//m_YBConsumeRank.SaveTodayConsumeRankToFile();
//m_YBConsumeRank.SaveYesterdayConsumeRankToFile();
OutputMsg(rmTip,_T("Save Store dynamic data finish"));
return true;
}
void CGameStore::ResetLabelConfigData(INT nLabelID)
{
if(nLabelID <=0 || nLabelID > m_labelCount.count())
{
OutputMsg(rmError,_T("%s,invalid labelid=%d"),__FUNCTION__,nLabelID);
return;
}
INT_PTR nCountLimit = m_labelCount[nLabelID-1]; //该分类的数目的限制
if(nCountLimit <=0 ) return ;
//这里首先判断是开服以来的第几天
int nDays= GetLogicServer()->GetDaysSinceOpenServer(); //开服以来的第几天
if(nDays ==0 )
{
nDays =1;
}
//是合服以来的第几天
int nMergeServerDay =GetLogicServer()->GetDaysSinceCombineServer();
//是合服前第几天
int nBeforeMergeDay = GetGlobalLogicEngine()->GetMiscMgr().GetDaysBeforeCombineServer();
if(nBeforeMergeDay <=0)
{
nBeforeMergeDay =-2;
}
SYSTEMTIME sysTime;
GetLocalTime(&sysTime); //获取当前的时间
BYTE nCurrentMonth=(BYTE) sysTime.wMonth ; //月份
BYTE nCurrentDay = (BYTE) sysTime.wDay ; //天
INT_PTR nFindCount=0; //已经找到的数目
CVector<MerchanRefresh> data;
INT_PTR nOpenServerCount=0; // 开服第几天的数目为0
//优先满足开服,然后满足日期,最后按星期筛选
for( INT_PTR i=0; i < m_refreshConfig.count() ; i++)
{
if( m_refreshConfig[i].nLabelId == nLabelID) //如果称号
{
//openServerDay 开服的第几天 ,1表示开服第1天2第2天0表示不做开服的限制
BYTE bValue= m_refreshConfig[i].nOpenServerDay; //开服以来的第几天
if( bValue != (BYTE)0) //这里优先开服的天数
{
if( bValue == nDays )
{
data.insert(0,m_refreshConfig[i]);
nOpenServerCount ++;
}
continue;
}
BYTE bMonth = m_refreshConfig[i].bMonth; //月
BYTE bDay = m_refreshConfig[i].bDay;//日
//有月份或者日的的限制的
if( bMonth != BYTE(-1) || bDay != (BYTE)-1 )
{
//满足了日期了
if( (bMonth == nCurrentMonth || bMonth == BYTE(-1)) &&
(bDay == nCurrentDay || bDay == BYTE(-1))
)
{
data.insert(nOpenServerCount,m_refreshConfig[i]); //在后面添加
continue;
}
}
else
{
//weekDay表示星期几, -1表示不限制星期几0表示周日1表示周1 ,...6表示周6
if(m_refreshConfig[i].nMergeServerDay !=0)
{
if(nMergeServerDay == m_refreshConfig[i].nMergeServerDay)
{
data.add(m_refreshConfig[i]); //在后面添加
continue;
}
}
else
{
if( m_refreshConfig[i].nBeforeMergeDay !=0)
{
if (nBeforeMergeDay > 0 && (m_refreshConfig[i].nBeforeMergeDay == BYTE(-1) || nBeforeMergeDay == m_refreshConfig[i].nBeforeMergeDay))
{
data.add(m_refreshConfig[i]); //在后面添加
continue;
}
}
else
{
bValue = m_refreshConfig[i].nWeekDay ;
if(bValue == BYTE(-1) || bValue == sysTime.wDayOfWeek)
{
data.add(m_refreshConfig[i]); //在后面添加
}
}
}
}
}
}
INT_PTR nCount =0;
for(INT_PTR i=0; i < data.count(); i ++ )
{
unsigned int nRandom = GetGlobalLogicEngine()->GetRandValue(10000) + 1;
if (((unsigned)data[i].nPercent) == 0 || nRandom <= ((unsigned)data[i].nPercent))
{
AddDynamicMerchadise(data[i].nMerchandiseId, data[i].nCount);//添加道具进去
OutputMsg(rmTip,_T("Store add dynamic merchandise,id=%d,count=%d"),data[i].nMerchandiseId,data[i].nCount);
nCount++;
if(nCount >= nCountLimit)
{
break;
}
}
}
}
void CGameStore::ResetDynamicMerchadise(INT nLabel,bool bNeedBroadcast)
{
CGameStore& store= GetLogicServer()->GetDataProvider()->GetGameStore();
CGameStore::PMERCHANDISE pMerchandise ;
INT_PTR nCount = m_dynamicMerchands.RankCount();
//将动态物品列表里该分类的数据全部删除
for( INT_PTR i= nCount-1; i >=0; i--)
{
CGameStoreRank::PSALADATA pData = &m_dynamicMerchands[i];
//获得商品的指针
pMerchandise= store.GetMerchandise(pData->nId);
if(pMerchandise)
{
if(pMerchandise->bLabelId == (BYTE)nLabel )
{
m_dynamicMerchands.RemoveIndex(i);
m_dynamicMerchands.SetDataChange();
}
}
else //如果这个道具已经失效了,直接删除
{
m_dynamicMerchands.RemoveIndex(i);
m_dynamicMerchands.SetDataChange();
}
}
//删除玩家购买列表里这个分类的数据
nCount = m_consumerMerchands.RankCount();
for( INT_PTR i= nCount-1; i >=0; i--)
{
CGameStoreRank::PSALADATA pData = &m_consumerMerchands[i];
pMerchandise= store.GetMerchandise(pData->nId);
if(pMerchandise)
{
if(pMerchandise->bLabelId == (BYTE)nLabel )
{
m_consumerMerchands.RemoveIndex(i);
m_consumerMerchands.SetDataChange();
}
}
else //如果这个道具已经失效了,直接删除
{
m_consumerMerchands.RemoveIndex(i);
m_consumerMerchands.SetDataChange();
}
}
//更新刷新的时间
UpdateRefreshTime(nLabel);
//重置该分类的数据
ResetLabelConfigData (nLabel);
// //如果需要广播的话,广播一个分类的数据发生了改变
// if(bNeedBroadcast)
// {
// CGameStoreBuySystem::BroadLabelRefresh(nLabel);
// }
}
void CGameStore::UpdateRefreshTime(INT nLabelId)
{
bool isExist;
UINT nTime=(UINT) m_refreshTime.GetIdCount(nLabelId,isExist); //时间
unsigned int nCurrentTime= CMiniDateTime::now();
if(isExist) //存在这个分类
{
m_refreshTime.UpdateSelaCount(nLabelId,(INT)nCurrentTime);
}
else
{
if(nTime > nCurrentTime)
{
m_refreshTime.UpdateSelaCount(nLabelId,(INT)(nTime - nCurrentTime));
}
else if(nTime <= nCurrentTime)
{
m_refreshTime.UpdateSelaCount(nLabelId,(INT)(nCurrentTime - nTime));
}
}
}
unsigned int CGameStore::GetRefreshTime(INT nLableId)
{
bool isExist;
INT nValue= m_refreshTime.GetIdCount(nLableId,isExist);
if(isExist)
{
return (unsigned int)nValue;
}
else
{
return 0;
}
}
//获取角色的消费数据
CVector<CGameStoreRank::SaleData>& CGameStore::GetActcorConsumeData(INT nActorId)
{
m_actorConsumeList.clear();
for(INT_PTR i=0;i < m_consumerMerchands.RankCount(); i++)
{
CGameStoreRank::SaleData * pSale =& m_consumerMerchands[i];
if(pSale->nActorId ==nActorId)
{
m_actorConsumeList.add(*pSale);
}
}
return m_actorConsumeList;
}
bool CGameStore::ReadShopConfig()
{
//打开商城配置表
m_shops.clear();
if( !openGlobalTable("ShopConfig") )
{
return false;
}
//遍历商城分类表
if( enumTableFirst() )
{
int nDef =0;
do
{
if( enumTableFirst() )
{
do
{
if( enumTableFirst() )
{
do
{
//标签的id
int shoptype = getFieldInt("shoptype"); //分类的id
int nTabshop = getFieldInt("Tabshop",&nDef); //
ShopConfig shop;
shop.nShopId= getFieldInt("shopid",&nDef); //
shop.nLimitLv= getFieldInt("levellimit",&nDef); //
shop.nReincarnationlimit= getFieldInt("reincarnationlimit",&nDef); //
shop.nFlag= getFieldInt("flag",&nDef); //
shop.nDaylimit= getFieldInt("daylimit",&nDef); //
shop.nStaticType= getFieldInt("statictype",&nDef); //
shop.nGuildLevelLimit = getFieldInt("guildLevel",&nDef);
// 购买商品广播消息
if(isExistString("tips"))
{
getFieldStringBuffer("tips", shop.tips, ArrayCount(shop.tips) );
} else {
ZeroMemory( shop.tips, sizeof(shop.tips) );
}
//打开商品分类中的商品表
if ( feildTableExists("shop") && openFieldTable("shop"))
{
shop.shop.nType = getFieldInt("type", &nDef);
shop.shop.nItemId = getFieldInt("id", &nDef);
shop.shop.nCount = getFieldInt("count", &nDef);
closeTable();
}
//打开商品分类中的商品表
if ( feildTableExists("npc") && openFieldTable("npc"))
{
if ( enumTableFirst() )
{
do
{
int npcId = (int)getFieldInt(NULL);
shop.nNpc.push_back(npcId);
}while(enumTableNext());
}
closeTable();
}
if( feildTableExists("price") && openFieldTable("price"))
{
shop.price.nType = getFieldInt("type", &nDef);
shop.price.nId = getFieldInt("id", &nDef);
shop.price.nCount = getFieldInt("count", &nDef);
closeTable();
}
shop.buyLimit.clear();
if( feildTableExists("buytype") && openFieldTable("buytype"))
{
if ( enumTableFirst() )
{
do
{
ShopBuyType buyCfg;
buyCfg.nType = getFieldInt("type", &nDef);
buyCfg.limits.clear();
if(feildTableExists("limit") && openFieldTable("limit"))
{
if(enumTableFirst())
{
do
{
int nValue = getFieldInt("value",&nDef );
int nTimes = getFieldInt("times",&nDef );
buyCfg.limits[nValue] = nTimes;
}while(enumTableNext());
}
closeTable();
}
shop.buyLimit.push_back(buyCfg);
}while(enumTableNext());
}
closeTable();
}
m_shops[shoptype][nTabshop].push_back(shop);
}while(enumTableNext());
}
}while(enumTableNext());
}
}while(enumTableNext());
}
closeTable();
return true;
}
int CGameStore::getLimitTimes(std::vector<ShopBuyType>&buyLimit, CActor* pActor, int nOpenDay)
{
int times = -1;
if(buyLimit.size() <= 0)
return 0;
std::vector<ShopBuyType>::iterator it = buyLimit.begin();
for(;it != buyLimit.end(); it++)
{
ShopBuyType& infoCfg = *it;
int nValue = 0;
switch (infoCfg.nType)
{
case BuyShopLimitLevel:
if(pActor)
{
nValue = pActor->GetLevel();
}
/* code */
break;
case BuyShopLimitCircle:
if(pActor)
{
nValue = pActor->GetCircleLevel();
}
/* code */
break;
case BuyShopLimitOpenServerDay:
nValue = nOpenDay;
/* code */
break;
default:
break;
}
if(infoCfg.limits.size() <= 0)
continue;
std::map<int, int>::iterator ot = infoCfg.limits.begin();
for(; ot != infoCfg.limits.end(); ot++)
{
if(nValue >= ot->first /*&& ot->second > times */)
{
times = ot->second;
}
}
}
return times;
}