📄 user.cpp
字号:
// 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 + -