⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 user.cpp

📁 网络游戏魔域的服务端与客户端完整源代码 包括详细的说明文档与开发日志
💻 CPP
📖 第 1 页 / 共 5 页
字号:
// User.cpp: implementation of the CUser class.
//
//////////////////////////////////////////////////////////////////////

#include <math.h>
#include "AllMsg.h"
#include "MsgDataArray.h"
#include "Package.h"
#include "User.h"
#include "MapGroup.h"
#include "netmsg.h"
#include "ItemType.h"
#include "team.h"
#include "StatusOnce.h"
#include "Transformation.h"
#include "WantedList.h"
#include "PoliceWanted.h"
#include "MapTrap.h"
#include "I_MessagePort.h"
#include "DeadLoop.h"
#include "AutoPtr.h"
#include "I_Shell.h"
#include "MercenaryTaskData.h"
#include "MercenaryTask.h"
#include "math.h"
#include "TaskDetail.h"


//extern long	g_sKickoutCheat;
long	g_sKickoutCheat = 0;
//////////////////////////////////////////////////////////////////////
const int	ADD_ENERGY_STAND_SECS			= 5;			// 每多少秒增加一次
const int	ADD_ENERGY_STAND				= 50;			// 站着增加数量
const int	DEL_ENERGY_PELT_SECS			= 3;			// 疾行状态每3秒减一次
const int	DEL_ENERGY_PELT					= 2;			// 每次扣2点
const int	KEEP_STAND_MS					= 1500;			// 站稳需要的时间,站稳后能挡住玩家。
const int	CRUSH_ENERGY_NEED				= 100;			// 挤开需要多少点
const int	CRUSH_ENERGY_EXPEND				= 100;			// 挤开消耗多少点
const int	SYNWAR_PROFFER_PERCENT			= 1;			// 打柱子得经验值的百分比
const int	SYNWAR_MONEY_PERCENT			= 2;			// 打柱子得钱的百分比
const int	MIN_SUPERMAP_KILLS				= 25;			// 无双列表低限
//const int	NEWBIE_LEVEL					= 70;			// 新手的等级
const int	VETERAN_DIFF_LEVEL				= 20;			// 老手的等级差
//const int	_MIN_TUTOR_LEVEL				= 50;							// 导师最低等级
const int	HIGHEST_WATER_WIZARD_PROF		= 135;			// 水真人
const int	MOUNT_ADD_INTIMACY_SECS			= 3600;			// 
const int	INTIMACY_DEAD_DEC				= 20;			// 
const int	SLOWHEALLIFE_MS					= 1000;							// 吃药补血慢慢补上去的豪秒数。
const int	AUTOHEALLIFE_TIME				= 10;							// 每隔10秒自动补血1次。
const int	AUTOHEALLIFE_EACHPERIOD			= 6;							// 每次补血6。
const int	AUTOHEAL_MAXLIFE_TIME			= 60;							// 每隔60秒自动恢复maxlife
const int	AUTOHEAL_MAXLIFE_FLESH_WOUND	= 16;							// 轻伤状态下每次恢复maxlife的千分比
const int	AUTOHEAL_MAXLIFE_GBH			= 4;							// 重伤状态下每次恢复maxlife的千分比
const int	TICK_SECS						= 10;
const int	MAX_PKLIMIT						= 10000;						// PK值的最大最小限制(防回卷)  //change huang 2004.1.11
const int	PILEMONEY_CHANGE				= 5000;							// 大量现金变动(需要即时存盘)
const int	_ADDITIONALPOINT_NUM			= 3;							// 升1级加多少属性点
const int	PK_DEC_TIME						= 60;							// 每间隔60秒降低pk值     //change huang 2004.1.11   
const int   PKVALUE_DEC_ONCE                = 1;                            // 按时间减少PK值。        
const int	PKVALUE_DEC_ONCE_IN_PRISON		= 3;							// 按时间减少PK值——在监狱中的情况
const int	PKVALUE_DEC_PERDEATH			= 10;							// 被PK死一次减少的PK值
const int	TIME_TEAMPRC					= 5;							// 队伍信息处理的时间
const int	DURABILITY_DEC_TIME				= 12;							// 每12秒降低一次按时间消耗的装备耐久度
const int	USER_ATTACK_SPEED				= 800;							// 玩家徒手攻击频率
const int	POISONDAMAGE_INTERVAL			= 2;							// 中毒每2秒伤血一次
const int	WARGHOST_CHECK_INTERVAL			= 10;							// 每隔10秒检查一次战魂等级(武器经验)
const int	AUTO_REBORN_SECS				= 30;							// 复活宝石30秒后自动使用
const int	INC_POTENTIAL_SECS				= 6*60;							// 每隔6分钟增加一次潜能
const int	INC_POTENTIAL_NUM				= 1;							// 每次增加1点潜能
const int	ADD_POTENTIAL_RELATIONSHIP		= 6;							// 关系值之和每达到6增加1点潜力值

// add by zlong 2003-11-28
const int	SPRITE_ADD_EXP_SECS				= 60;			//元素精灵每分钟增加一次经验
const int	SPRITE_ADD_EXP					= 1;			//经验增加数量

const int	EUDEMON_ADD_FIDELITY_SECS		= 60*6;			// 幻兽每6分钟增加一次亲密度
const int	EUDEMON_ADD_FIDELITY			= 1;			// 每次增加的亲密度
const int	MAX_EUDEMON_FIDELITY			= 1000;			// 最大亲密度1000
const int	MAX_RETURN_BORN_POS_LEV			= 4;			// 死亡后返回初始出生点的最大等级
//////////////////////////////////////////////////////////////////////
MYHEAP_IMPLEMENTATION(CUser,s_heap)
char	szActionTable[]			= _TBL_ACTION;
char	szTaskTable[]			= _TBL_TASK;
//char	szMagicTypeTable[]		= _TBL_MAGICTYPE;
char	szTrackTable[]			= _TBL_TRACK;
char	szBonusTable[]			= _TBL_BONUS;
char	szAddPointTable[]		= _TBL_POINTALLOT;
char	szTrapTypeTable[]		= _TBL_TRAPTYPE;
char	szMonsterTypeTable[]	= _TBL_MONSTERTYPE;
char	szRebirthTable[]		= _TBL_REBIRTH;	

//////////////////////////////////////////////////////////////////////
// Construction/Destruction CHEAT
//////////////////////////////////////////////////////////////////////
bool CUser::SetCheatLevel(int nLevel)
{
#if	!defined(_DEBUG)
	if(IsGM() || GetLev() < LOGIN_FREE_LEVEL)
		return false;
#endif

	// init count
	if(m_nCheatLevel == 0)
		m_nCheatCount = UserManager()->GetCheatCount(GetID());


	// is max?
	if(nLevel <= m_nCheatLevel)
		return false;

	if(!IsCheater(_TYPE_MAGIC))
	{
		m_nCheatLevel	= nLevel;
		if(m_nCheatLevel + m_nCheatCount*10 >= 30)
		{
			SetCheatMark(_TYPE_MAGIC, 0);

			// add to manager
			int nAmount, nTimes;
			UserManager()->AddCheat(GetID(), &nAmount, &nTimes);
			LOGCHEAT("magic: user[%s], account[%u], type[zffy], level[%d], amount[%d], times[%d]", GetName(), GetAccountID(), nLevel, nAmount, nTimes);
			return true;
		}
	}
	else
	{
		m_nCheatLevel	= nLevel;
		LOGCHEAT("magic: user[%s], account[%u], type[zffy], level[%d]", GetName(), GetAccountID(), nLevel);
	}

	return false;
}

//////////////////////////////////////////////////////////////////////
bool CUser::IsCheater(OBJID idKind)
{
	CHECKF(idKind < 32);

	return (m_maskCheat & (1<<idKind)) != 0;
}

char* g_setName[] = { "_TYPE_MAGIC", "_TYPE_WS", "_TYPE_FY", "_TYPE_USE_LIFE", "_TYPE_USE_MANA", 
		"null", "null", "null", "null", "null", "null", "null", "null", "null", "null", 
		"null", "null", "null", "null", "null", "null", "null", "null", "null", "null", 
		"null", "null", "null", "null", "null", "null", "null", "null", "null", "null",  };
//////////////////////////////////////////////////////////////////////
void CUser::SetCheatMark(OBJID idCheatKind, DWORD dwCheatMark)
{
	CHECK(idCheatKind < 32);

	LOGCHEAT("client: user[%s], account[%u], type[%s], mark[%d]", GetName(), GetAccountID(), g_setName[idCheatKind], dwCheatMark);

	m_maskCheat = m_maskCheat | (1<<idCheatKind);
}

//////////////////////////////////////////////////////////////////////
void CUser::KickoutCheat(OBJID idKind)
{
	CHECK(idKind < 32);
	CHECK(IsCheater(idKind));

#if	!defined(_DEBUG)
//	if(UserManager()->GetCheatAmount() < 5)
//		return ;
#endif

	// kickout
	if(GetLev() >= LOGIN_FREE_LEVEL && (g_sKickoutCheat&(1<<idKind)) != 0 )
	{
#if	defined(_DEBUG)
		SendSysMsg("★CHEAT★");
#endif
		UserManager()->KickOutSocket(m_idSocket, "cheat");
	}
	else
	{
		LOGCHEAT("need kick: user[%s], account[%u], type[%s]", GetName(), GetAccountID(), g_setName[idKind]);
	}
}

//////////////////////////////////////////////////////////////////////
bool CUser::IsMagicAtkCheat (OBJID idTarget, int nTargetX, int nTargetY, DWORD dwTimeStamp)
{
	IRole* pRole = RoleManager()->QueryRole(idTarget);
	if (!pRole)
		return false;

	// action mode test
	{
		if (dwTimeStamp-m_dwLastJump < 100)
		{
			//::MyLogSave("gmlog/test", "---------suspect action found!");
			return true;
		}
	}

	// interval test
	CONST TEST_SIZE = 8;
	m_setActionTime.push_back(dwTimeStamp);

	if (m_setActionTime.size() > TEST_SIZE)
		m_setActionTime.pop_front();

	if (m_setActionTime.size() != TEST_SIZE)
		return false;

	{
		deque<int> setDeltaTime;
		for (int i=1; i<TEST_SIZE; i++)
			setDeltaTime.push_back(m_setActionTime[i]-m_setActionTime[i-1]);		

		CONST SUSPECT_TIME = 20;

		int nSuspectCount = 0;
		for (i=1; i<TEST_SIZE-1; i++)
		{
			if (abs(setDeltaTime[0] - setDeltaTime[i]) <= SUSPECT_TIME)
				nSuspectCount++;
		}

		if (nSuspectCount >= TEST_SIZE-2)
		{
			//::MyLogSave("gmlog/test", "---------repeat action found!");
			return true;
		}
	}

	// target pos test
	if (nTargetX == 0 && nTargetY == 0)
		return true;

	// dislocation test
	// ....
	return false;	
}

//////////////////////////////////////////////////////////////////////
void CUser::DoCheaterPunish	(int nData/* = 0*/)
{
	CONST OBJID idMapCheaterPrison = 6010;
	CONST int nPosX = 34, nPosY = 74;

	if (this->GetMapID() == idMapCheaterPrison)
		return;

	this->SetRecordPos(idMapCheaterPrison, nPosX, nPosY, true);
	this->FlyMap(idMapCheaterPrison, nPosX, nPosY);
}

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CUser::CUser()
{
	SetObjType(OBJ_USER);

	m_link.Init(this);
	m_nStep			= STEP_LOGIN;		// 地图组首先是进入地图

	// item ----------------------
	m_pWeaponR		= NULL;
	m_pWeaponL		= NULL;
	m_pHelmet		= NULL;
	m_pNecklace		= NULL;
	m_pArmor		= NULL;
	m_pRingR		= NULL;
	m_pRingL		= NULL;
	m_pShoes		= NULL;
	m_pMount		= NULL;
	m_pSprite		= NULL;
	m_pMantle		= NULL;

	m_bUpdateWeight	= true;			// true: 需要重新计算

	m_nPose			= 0;	//DEFAULT_LOGIN_POSE;
	m_nEmotin		= 0;	//DEFAULT_LOGIN_EMOTION;

	m_dwXP			= 0;
	m_pTeam			= NULL;

	// tick -----------
	m_dwFirstServerTick	= 0;
	m_dwLastServerTick	= 0;

	m_dwLastClientTick	= 0;
	m_dwFirstClientTick	= 0;
	m_dwLastCoolShow	= 0;

	m_dwLastRcvClientTick = 0;

	// interface
	m_ifaceSquareDeal.m_pParent	= this;

	m_pBattleSystem	= NULL;
	m_pStorage		= NULL;
	m_idTaskNpc		= ID_NONE;
	m_idTaskItem	= ID_NONE;
	m_idTaskItemAction	= ID_NONE;
	m_bDebugAction	= false;
	m_pPackage		= CUserPackage::CreateNew();

	m_pUserWeaponSkillSet	= CUserWeaponSkillSet::CreateNew(true);
	m_pMagic		= NULL;
	m_pSyn			= NULL;
	m_bGhost		= false;

	m_bHaveLeaveWord	= true;
	m_pTransformation	= NULL;

//	m_bSynchro		= true;
	m_pBooth		= NULL;
	m_idxLastArrow	= -1;		// error

	// foot print
	m_tFootPrint	= 0;
	m_posFootPrint.x	= 0;
	m_posFootPrint.y	= 0;

	// superman list
	m_nCurrSupermanKills	= 0;
	m_nTopSupermanKills		= 0;
	m_nSupermanOrder		= 0;

	// cheat test
	m_dwLastJump = 0;
	m_dwMsgCount = 0;

	// tutor
	m_pTutor	= NULL;
	m_dwExpToTutor	= 0;
	
	// mine
	m_pMineTarget	= NULL;

	//帮派服装的armor type;
	m_nSynDressArmorType = 0;
	m_pTaskDetail	= NULL;
	m_bIsEnableWarGhostExp = false;

	m_idLinkEudemonItem	= ID_NONE;
	m_idLinkEudemonType	= ID_NONE;
	m_nLinkValue		= 0;
}

//////////////////////////////////////////////////////////////////////
CUser::~CUser()
{
	LeaveMapGroup();
	if (m_pBattleSystem)
	{
		delete m_pBattleSystem;
		m_pBattleSystem	= NULL;
	}
	if(m_pStorage)
		m_pStorage->Release();

	if (m_pPackage)
		m_pPackage->Release();

	if (m_pUserWeaponSkillSet)
		m_pUserWeaponSkillSet->Release();

	if (m_pMagic)
		m_pMagic->ReleaseByOwner();
	if (m_pSyn)
		m_pSyn->ReleaseByOwner();

	SAFE_RELEASE (m_setStatus);
	
	if (m_pTeam)
		m_pTeam->ReleaseByOwner();
	if (m_pTransformation)
		m_pTransformation->Release();

	if(m_pTaskDetail)
		m_pTaskDetail->Release();

	DEBUG_TRY
	Announce()->DeleteAnnounceByUserID(this->GetID(),false);
    DEBUG_CATCH("Announce()->DeleteAnnounceByUserID(this->GetID()) ERROR!");

	this->DestroyBooth();
}

//////////////////////////////////////////////////////////////////////
CUser* CUser::CreateNewUser(PROCESS_ID idProcess, SOCKET_ID idSocket, UserInfoStruct* pInfo)	// join from other map_group
{
	CHECKF(CMapGroup::IsValidMapGroupProcessID(idProcess));
	CHECKF(pInfo);

	CUserPtr pUser = CUser::CreateNew();
	CHECKF(pUser);
	if(pUser)
	{
		pUser->m_idProcess	= idProcess;
		pUser->m_idSocket	= idSocket;
		memcpy(&pUser->m_data.m_Info, pInfo, sizeof(UserInfoStruct));
		pUser->m_data.m_pRes = MapGroup(idProcess)->QueryDataDefault()->GetUserData()->CreateNewRecord(pInfo->id);
		if(!pUser->m_data.m_pRes)
		{
			pUser->ReleaseByOwner();
			return NULL;
		}
	}

	pUser->Init();
	pUser->QueryEnemy()->Create(idProcess, pUser);
	pUser->m_pMap	= NULL;			//? 保证为空,用于控制连续切屏。

	// transformation
	if(pUser->m_data.m_Info.dwMonsterType && pUser->m_data.m_Info.dwMonsterSecs)
	{
		ASSERT(pUser->Transform(pUser->m_data.m_Info.dwMonsterType, pUser->m_data.m_Info.dwMonsterSecs));
	}

	return pUser;
}

//////////////////////////////////////////////////////////////////////
// login, return false: logout_user
bool CUser::EnterMap()
{
	if(m_nStep != STEP_LOGIN)
		return false;

	SendLight();

	CMapPtr pMap = GetMap();
	if(pMap)
	{
		UpdateBroadcastSet();

		pMap->EnterRoom(this->QueryMapThing(), WITH_BLOCK);
//		pMap->SendBlockInfo((IRole*)this);
		pMap->SendRegionInfo(this);
		pMap->SendMapInfo(this);

//		SendSelfToBlock();
	}

//	if(!GetMap()->IsWingEnable())
//		QueryStatusSet()->DelObj(STATUS_WING);

	// 进入市场地图解除XPFULL状态
	if (pMap && pMap->IsBoothEnable())
		DetachStatus((IRole*)this, STATUS_XPFULL);

	CRole::AttachStatus(this->QueryRole(), STATUS_PK_PROTECT, 0, CHGMAP_LOCK_SECS);
//	m_tLock.Startup(CHGMAP_LOCK_SECS);
	m_nStep = STEP_ENTERMAP;
	return true;
}

//////////////////////////////////////////////////////////////////////
bool CUser::SendSelfToBlock()
{
	// brocast my info
	CMsgPlayer msg;
	if (msg.Create((IRole*)this))
		this->BroadcastRoomMsg(&msg, EXCLUDE_SELF);

	return true;
}

//////////////////////////////////////////////////////////////////////
void CUser::SetMaxLifePercent(int nPercent, BOOL bUpdate /*= TRUE*/)
{
	bool bAboveHalfLife = this->GetLife()*2 >= this->GetMaxLife();
	m_data.SetMaxLifePercent(nPercent);		// 由SetMaxLifePercent保证不低于1/8
	bool bBelowHalfLife = this->GetLife()*2 < this->GetMaxLife();
	bool bSpeedChanged = (bAboveHalfLife && bBelowHalfLife) || (!bAboveHalfLife && !bBelowHalfLife);

	// 通知客户端
	CMsgUserAttrib	msg;
	if (msg.Create(GetID(), _USERATTRIB_MAXLIFE, GetMaxLife()))
	{
		// 是否影响到速度?
		IStatus* pStatus = this->QueryStatus(STATUS_SLOWDOWN2);
		if (pStatus && bSpeedChanged)
			msg.Append(_USERATTRIB_SPEED, AdjustSpeed(GetSpeed()));

		SendMsg(&msg);
	}
	const bool bMaxLife = true;
	this->BroadcastTeamLife(bMaxLife);	
}

//////////////////////////////////////////////////////////////////////
// modify attrib
//////////////////////////////////////////////////////////////////////
bool CUser::AddAttrib(int idxAttr, __int64 i64Data, int nSynchro)
{
	CMsgUserAttrib	msg;
	IF_NOT (msg.Create(GetID(), _USERATTRIB_NONE, 0))			// _USERATTRIB_NONE : 不添加
		return false;

	if(i64Data)
	{
		switch(idxAttr)
		{
		case	_USERATTRIB_LEV:
			{
				IF_NOT (i64Data >= 0)
					return false;

				int nOldLev = this->GetLev();
				int nNewLev = __min(MAX_USERLEV, nOldLev+i64Data);
				m_data.SetLev(nNewLev, true);
				IF_NOT (msg.Append(_USERATTRIB_LEV, this->GetLev()))
					return false;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -