Files
test/EC_Player_clean.cpp
T
2026-03-24 12:28:56 +07:00

11617 lines
319 KiB
C++

/*
* FILE: EC_Player.cpp
*
* DESCRIPTION:
*
* CREATED BY: Duyuxin, 2004/9/1
*
* HISTORY:
*
* Copyright (c) 2004 Archosaur Studio, All Rights Reserved.
*/
#include "EC_Global.h"
#include "EC_Game.h"
#include "EC_Player.h"
#include "EC_Model.h"
#include "EC_Face.h"
#include "EC_IvtrTypes.h"
#include "EC_RTDebug.h"
#include "EC_IvtrItem.h"
#include "EC_IvtrScroll.h"
#include "EC_IvtrWeapon.h"
#include "EC_IvtrEquipMatter.h"
#include "EC_Resource.h"
#include "EC_Viewport.h"
#include "EC_Utility.h"
#include "EC_ManDecal.h"
#include "EC_Decal.h"
#include "EC_World.h"
#include "EC_GameRun.h"
#include "EC_ImageRes.h"
#include "EC_GFXCaster.h"
#include "EC_Resource.h"
#include "EC_FixedMsg.h"
#include "EC_ManAttacks.h"
#include "EC_ManPlayer.h"
#include "EC_HostPlayer.h"
#include "EC_ElsePlayer.h"
#include "EC_Team.h"
#include "EC_Faction.h"
#include "EC_Skill.h"
#include "ElementSkill.h"
#include "EC_PortraitRender.h"
#include "EC_PateText.h"
#include "EC_Configs.h"
#include "EC_GameSession.h"
#include "EC_CustomizeBound.h"
#include "EC_SceneLoader.h"
#include "FWAssemblySet.h"
#include "FWTemplate.h"
#include "EC_NPC.h"
#include "EC_ManNPC.h"
#include "EC_Sprite.h"
#include "EC_UIManager.h"
#include "EC_GameUIMan.h"
#include "EC_Goblin.h"
#include "EC_Pet.h"
#include "EC_ManMatter.h"
#include "EC_Matter.h"
#include "EC_ChangePill.h"
#include "EL_Precinct.h"
#include "EC_CountryConfig.h"
#include "EC_UIConfigs.h"
#include "EC_Optimize.h"
#include "EC_ProfConfigs.h"
#include "EC_PlayerActionController.h"
#include "EC_PlayerBodyController.h"
#include "EC_MemSimplify.h"
#include "EC_ElementDataHelper.h"
#include "DlgChariot.h"
#include "DlgReincarnationShow.h"
#include "DlgLevel2UpgradeShow.h"
#include "EC_TaoistRank.h"
#include "elementdataman.h"
#include "privilege.hxx"
#include "ids.hxx"
#include "A2DSprite.h"
#include "A2DSpriteItem.h"
#include "A3DSkin.h"
#include "A3DSkinMan.h"
#include "A3DShaderMan.h"
#include "A3DSkinMesh.h"
#include "A3DShader.h"
#include "A3DSkinModel.h"
#include "A3DSkinModelAct.h"
#include "A3DSkinModelAux.h"
#include "A3DTerrainWater.h"
#include "A3DCamera.h"
#include "A3DSkeleton.h"
#include "A3DBone.h"
#include "A3DFlatCollector.h"
#include "AAssist.h"
#include "AFile.h"
#include "A3DLight.h"
#include <A3DFont.h>
#include <AFI.h>
#include "A3DCombinedAction.h"
#include "A3DGFXFuncs.h"
#include <A3DSKinRender.h>
#define new A_DEBUG_NEW
#define FASHION_POWER 30.0f
#define FASHION_SPECULAR 0xff202020
#define ARMOR_POWER 20.0f
#define ARMOR_SPECULAR 0xffffffff
#define WEAPON_POWER 15.0f
#define WEAPON_SPECULAR 0xff000000//0xffffffff
#define PLAYERMODEL_GETTYPE(iShape) ((iShape & 0xff) >> 6)
#define PLAYERMODEL_GETID(iShape) (iShape & 0x3f)
///////////////////////////////////////////////////////////////////////////
//
// Define and Macro
//
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
//
// Reference to External variables and functions
//
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
//
// Local Types and Variables and Global variables
//
///////////////////////////////////////////////////////////////////////////
static const char* _left_hand_weapon = "LeftHand";
static const char* _right_hand_weapon = "RightHand";
static const char* _wing = "Wing";
static const char* _wing2 = "Wing2";
const char* _cc_ride = "CC_Ride";
static const char* _cc_ride2 = "CC_Ride2";
const char* _hh_ride = "HH_Ride";
const char* _hanger_ride = "Rider";
static const char* _hanger_ride2 = "Rider2";
static const char* _hanger_hug = "Hug";
static const char* _hh_bind = "HH_Bind";
static const char* _cc_bind = "CC_Bind";
const char* _cc_fenghuolun = "CC_feijian";
const char* _hh_left_foot = "HH_左脚";
const char* _hh_right_foot = "HH_右脚";
static const char* _hh_left_shoulder_weapon = "HH_leftsword"; // 人背上的武器挂点(左肩)
static const char* _hh_right_shoulder_weapon= "HH_rightsword"; // 人背上的武器挂点(右肩)
static const char* _hh_left_hand_weapon = "HH_lefthandweapon"; // 人手上的武器挂点(左手)
static const char* _hh_right_hand_weapon = "HH_righthandweapon"; // 人手上的武器挂点(右手)
static const char* _hh_qiu = "HH_qiu"; // 人手上的球挂点(右手)
static const char* _hh_right_hand_nickle_weapon = "HH_weapon"; // 人手上胧族月镰挂点(右手)
static const char* _cc_weapon = "CC_weapon"; // 武器上的挂点名称
static const char* _cc_qiu = "CC_qiu"; // 球上的挂点名称
static const char* _hh_qiu_base = "HH_base"; // 球上的特效挂点(右手)
const char* _multiobject_effect[] = {"绿色连线.gfx","红色连线.gfx","黑色连线.gfx",};
static const char* _head_skin[NUM_PROFESSION*NUM_GENDER] =
{
"Models\\Players\\形象\\武侠男\\\\武侠男头",
"Models\\Players\\形象\\武侠女\\\\武侠女头",
"Models\\Players\\形象\\法师男\\\\法师男头",
"Models\\Players\\形象\\法师女\\\\法师女头",
"Models\\Players\\形象\\巫师男\\\\巫师男头",
"Models\\Players\\形象\\巫师女\\\\巫师女头",
"",
"Models\\Players\\形象\\妖精\\\\妖精头",
"Models\\Players\\形象\\妖兽男\\\\妖兽男头",
"",
"Models\\Players\\形象\\刺客男\\\\刺客男头",
"Models\\Players\\形象\\刺客女\\\\刺客女头",
"Models\\Players\\形象\\羽芒男\\\\羽芒男头",
"Models\\Players\\形象\\羽芒女\\\\羽芒女头",
"Models\\Players\\形象\\羽灵男\\\\羽灵男头",
"Models\\Players\\形象\\羽灵女\\\\羽灵女头",
"Models\\Players\\形象\\剑灵男\\\\剑灵男头",
"Models\\Players\\形象\\剑灵女\\\\剑灵女头",
"Models\\Players\\形象\\魅灵男\\\\魅灵男头",
"Models\\Players\\形象\\魅灵女\\\\魅灵女头",
"Models\\Players\\形象\\夜影男\\\\夜影男头",
"Models\\Players\\形象\\夜影女\\\\夜影女头",
"Models\\Players\\形象\\月仙男\\\\月仙男头",
"Models\\Players\\形象\\月仙女\\\\月仙女头",
};
static const char* _body_skin[NUM_PROFESSION*NUM_GENDER] =
{
"Models\\Players\\形象\\武侠男\\躯干\\武侠男",
"Models\\Players\\形象\\武侠女\\躯干\\武侠女",
"Models\\Players\\形象\\法师男\\躯干\\法师男",
"Models\\Players\\形象\\法师女\\躯干\\法师女",
"Models\\Players\\形象\\巫师男\\躯干\\巫师男%d",
"Models\\Players\\形象\\巫师女\\躯干\\巫师女%d",
"",
"Models\\Players\\形象\\妖精\\躯干\\妖精%d",
"Models\\Players\\形象\\妖兽男\\躯干\\妖兽男%d",
"",
"Models\\Players\\形象\\刺客男\\躯干\\刺客男%d",
"Models\\Players\\形象\\刺客女\\躯干\\刺客女%d",
"Models\\Players\\形象\\羽芒男\\躯干\\羽芒男",
"Models\\Players\\形象\\羽芒女\\躯干\\羽芒女",
"Models\\Players\\形象\\羽灵男\\躯干\\羽灵男",
"Models\\Players\\形象\\羽灵女\\躯干\\羽灵女",
"Models\\Players\\形象\\剑灵男\\躯干\\剑灵男",
"Models\\Players\\形象\\剑灵女\\躯干\\剑灵女",
"Models\\Players\\形象\\魅灵男\\躯干\\魅灵男",
"Models\\Players\\形象\\魅灵女\\躯干\\魅灵女",
"Models\\Players\\形象\\夜影男\\躯干\\夜影男",
"Models\\Players\\形象\\夜影女\\躯干\\夜影女",
"Models\\Players\\形象\\月仙男\\躯干\\月仙男",
"Models\\Players\\形象\\月仙女\\躯干\\月仙女",
};
static const char* _simple_body_skin[NUM_PROFESSION*NUM_GENDER] =
{
"Models\\Players\\形象\\武侠男\\躯干\\武侠男简化",
"Models\\Players\\形象\\武侠女\\躯干\\武侠女简化",
"Models\\Players\\形象\\法师男\\躯干\\法师男简化",
"Models\\Players\\形象\\法师女\\躯干\\法师女简化",
"Models\\Players\\形象\\巫师男\\躯干\\巫师男简化",
"Models\\Players\\形象\\巫师女\\躯干\\巫师女简化",
"",
"Models\\Players\\形象\\妖精\\躯干\\妖精简化",
"Models\\Players\\形象\\妖兽男\\躯干\\妖兽男简化%d",
"",
"Models\\Players\\形象\\刺客男\\躯干\\刺客男简化",
"Models\\Players\\形象\\刺客女\\躯干\\刺客女简化",
"Models\\Players\\形象\\羽芒男\\躯干\\羽芒男简化",
"Models\\Players\\形象\\羽芒女\\躯干\\羽芒女简化",
"Models\\Players\\形象\\羽灵男\\躯干\\羽灵男简化",
"Models\\Players\\形象\\羽灵女\\躯干\\羽灵女简化",
"Models\\Players\\形象\\剑灵男\\躯干\\剑灵男简化",
"Models\\Players\\形象\\剑灵女\\躯干\\剑灵女简化",
"Models\\Players\\形象\\魅灵男\\躯干\\魅灵男简化",
"Models\\Players\\形象\\魅灵女\\躯干\\魅灵女简化",
"Models\\Players\\形象\\夜影男\\躯干\\夜影男简化",
"Models\\Players\\形象\\夜影女\\躯干\\夜影女简化",
"Models\\Players\\形象\\月仙男\\躯干\\月仙男简化",
"Models\\Players\\形象\\月仙女\\躯干\\月仙女简化",
};
static const char* _equipment_skin[NUM_PROFESSION*NUM_GENDER] =
{
"Models\\Players\\装备\\\\%s\\男通用%s",
"Models\\Players\\装备\\\\%s\\女通用%s",
"Models\\Players\\装备\\\\%s\\男通用%s",
"Models\\Players\\装备\\\\%s\\女通用%s",
"Models\\Players\\装备\\\\%s\\男通用%s",
"Models\\Players\\装备\\\\%s\\女通用%s",
"",
"Models\\Players\\装备\\\\%s\\妖精%s",
"Models\\Players\\装备\\\\%s\\妖兽%s",
"",
"Models\\Players\\装备\\\\%s\\男通用%s",
"Models\\Players\\装备\\\\%s\\女通用%s",
"Models\\Players\\装备\\\\%s\\男通用%s",
"Models\\Players\\装备\\\\%s\\女通用%s",
"Models\\Players\\装备\\\\%s\\男通用%s",
"Models\\Players\\装备\\\\%s\\女通用%s",
"Models\\Players\\装备\\\\%s\\男通用%s",
"Models\\Players\\装备\\\\%s\\女通用%s",
"Models\\Players\\装备\\\\%s\\男通用%s",
"Models\\Players\\装备\\\\%s\\女通用%s",
"Models\\Players\\装备\\\\%s\\男通用%s",
"Models\\Players\\装备\\\\%s\\女通用%s",
"Models\\Players\\装备\\\\%s\\男通用%s",
"Models\\Players\\装备\\\\%s\\女通用%s",
};
static const char* _equipment_default_skin[NUM_PROFESSION*NUM_GENDER] =
{
"Models\\Players\\装备\\\\%s\\武侠男%s",
"Models\\Players\\装备\\\\%s\\武侠女%s",
"Models\\Players\\装备\\\\%s\\法师男%s",
"Models\\Players\\装备\\\\%s\\法师女%s",
"Models\\Players\\装备\\\\%s\\巫师男%s",
"Models\\Players\\装备\\\\%s\\巫师女%s",
"",
"Models\\Players\\装备\\\\%s\\妖精%s",
"Models\\Players\\装备\\\\%s\\妖兽%s",
"",
"Models\\Players\\装备\\\\%s\\刺客男%s",
"Models\\Players\\装备\\\\%s\\刺客女%s",
"Models\\Players\\装备\\\\%s\\羽芒男%s",
"Models\\Players\\装备\\\\%s\\羽芒女%s",
"Models\\Players\\装备\\\\%s\\羽灵男%s",
"Models\\Players\\装备\\\\%s\\羽灵女%s",
"Models\\Players\\装备\\\\%s\\剑灵男%s",
"Models\\Players\\装备\\\\%s\\剑灵女%s",
"Models\\Players\\装备\\\\%s\\魅灵男%s",
"Models\\Players\\装备\\\\%s\\魅灵女%s",
"Models\\Players\\装备\\\\%s\\夜影男%s",
"Models\\Players\\装备\\\\%s\\夜影女%s",
"Models\\Players\\装备\\\\%s\\月仙男%s",
"Models\\Players\\装备\\\\%s\\月仙女%s",
};
static const int _skin_alpha_map[] =
{
SKIN_SORT_DEFAULT, // SKIN_BODY_INDEX
SKIN_SORT_UPPER, // SKIN_UPPER_BODY_INDEX
SKIN_SORT_WRIST, // SKIN_WRIST_INDEX
SKIN_SORT_LOWER, // SKIN_LOWER_INDEX
SKIN_SORT_FOOT, // SKIN_FOOT_INDEX
SKIN_SORT_DEFAULT, // SKIN_HEAD_INDEX
SKIN_SORT_UPPER, // SKIN_FASHION_UPPER_BODY_INDEX
SKIN_SORT_WRIST, // SKIN_FASHION_WRIST_INDEX
SKIN_SORT_LOWER, // SKIN_FASHION_LOWER_INDEX
SKIN_SORT_FOOT, // SKIN_FASHION_FOOT_INDEX
};
static char strWeaponActName[512]; // Weapon action name
static CRITICAL_SECTION l_csLoadPlayerSkin;
static CECPlayer::PLAYER_ACTION* _default_actions = NULL; // Static Action data table
static CECPlayer::PLAYER_ACTION* _turning_actions = NULL; // Static Action data table
static abase::hash_map<unsigned int, const PLAYER_ACTION_INFO_CONFIG *> _default_skill_actions; // skill actions
static PLAYER_LEVELEXP_CONFIG _player_levelup_exp; // Level up exp needed
static const int GAP_BETWEEN_NAME_TITLE = 7;
static const A3DVECTOR3 aExts[NUM_PROFESSION*NUM_GENDER] =
{
A3DVECTOR3(0.4f, 0.9f, 0.4f), // 武侠
A3DVECTOR3(0.3f, 0.85f, 0.3f),
A3DVECTOR3(0.3f, 0.9f, 0.3f), // 法师
A3DVECTOR3(0.3f, 0.85f, 0.3f),
A3DVECTOR3(0.3f, 0.9f, 0.3f), // 巫师
A3DVECTOR3(0.3f, 0.85f, 0.3f),
A3DVECTOR3(0.3f, 0.9f, 0.3f), // 妖精
A3DVECTOR3(0.3f, 0.85f, 0.3f),
A3DVECTOR3(0.5f, 1.05f, 0.5f), // 妖兽
A3DVECTOR3(0.3f, 0.9f, 0.3f),
A3DVECTOR3(0.3f, 0.9f, 0.3f), // 刺客
A3DVECTOR3(0.3f, 0.85f, 0.3f),
A3DVECTOR3(0.3f, 0.9f, 0.3f), // 羽芒
A3DVECTOR3(0.3f, 0.85f, 0.3f),
A3DVECTOR3(0.3f, 0.9f, 0.3f), // 羽灵
A3DVECTOR3(0.3f, 0.85f, 0.3f),
A3DVECTOR3(0.3f, 0.9f, 0.3f), // 剑灵
A3DVECTOR3(0.3f, 0.85f, 0.3f),
A3DVECTOR3(0.3f, 0.9f, 0.3f), // 魅灵
A3DVECTOR3(0.3f, 0.85f, 0.3f),
A3DVECTOR3(0.3f, 0.9f, 0.3f), // 夜影
A3DVECTOR3(0.3f, 0.85f, 0.3f),
A3DVECTOR3(0.3f, 0.9f, 0.3f), // 月仙
A3DVECTOR3(0.3f, 0.85f, 0.3f),
};
const int CECPlayer::m_sciStateIDForStateAction[1] = {117};
///////////////////////////////////////////////////////////////////////////
//
// Local functions
//
///////////////////////////////////////////////////////////////////////////
static void _GenSkinPath(char* szPath, int nProfession, int nGender, const char* szSkinName)
{
sprintf(szPath, _equipment_skin[nProfession * NUM_GENDER + nGender], szSkinName, szSkinName);
}
static void _GenDefaultSkinPath(char* szPath, int nProfession, int nGender, const char* szSkinName)
{
sprintf(szPath, _equipment_default_skin[nProfession * NUM_GENDER + nGender], szSkinName, szSkinName);
}
static const char* _GenWeaponActionName(char* szAct, int nGender)
{
sprintf(strWeaponActName, "%s_%s", szAct, (nGender==GENDER_MALE) ? "" : "");
return strWeaponActName;
}
static inline int _GetProfessionTransformModelID(int nChar, int nGender, int nModelID)
{
int result(0);
switch (nChar){
case PROF_HAG: // 妖精
result = (2 == nModelID) ? RES_MOD_ORC_FOX2 : RES_MOD_ORC_FOX;
break;
case PROF_ORC: // 妖兽
result = (2 == nModelID) ? RES_MOD_ORC_PANDER : RES_MOD_ORC_TIGER;
break;
case PROF_MONK: // 巫师
case PROF_GHOST: // 刺客
result = (GENDER_MALE == nGender) ? RES_MOD_SHADOW_FISH_M : RES_MOD_SHADOW_FISH_F;
break;
case PROF_YEYING: // 夜影
result = (GENDER_MALE == nGender) ? RES_MOD_YEYING_RESHAPE_M : RES_MOD_YEYING_RESHAPE_F;
break;
case PROF_YUEXIAN: // 月仙
result = (GENDER_MALE == nGender) ? RES_MOD_YUEXIAN_RESHAPE_M : RES_MOD_YUEXIAN_RESHAPE_F;
break;
}
return result;
}
static bool IsTransofrmModelLikeHuman(int nChar, int nGender, int nModelID){
bool result(false);
const int *likeHumanModelArray = NULL;
int likeHumanModelCount = 0;
switch (nChar)
{
case PROF_YEYING:
if (GENDER_MALE == nGender){
const int LIKE_HUMAN_MODEL_COUNT = 1;
static int s_LikeHumanModel[LIKE_HUMAN_MODEL_COUNT] = {RES_MOD_YEYING_RESHAPE_M};
likeHumanModelArray = s_LikeHumanModel;
likeHumanModelCount = LIKE_HUMAN_MODEL_COUNT;
}else{
const int LIKE_HUMAN_MODEL_COUNT = 1;
static int s_LikeHumanModel[LIKE_HUMAN_MODEL_COUNT] = {RES_MOD_YEYING_RESHAPE_F};
likeHumanModelArray = s_LikeHumanModel;
likeHumanModelCount = LIKE_HUMAN_MODEL_COUNT;
}
break;
case PROF_YUEXIAN:
if (GENDER_MALE == nGender){
const int LIKE_HUMAN_MODEL_COUNT = 1;
static int s_LikeHumanModel[LIKE_HUMAN_MODEL_COUNT] = {RES_MOD_YUEXIAN_RESHAPE_M};
likeHumanModelArray = s_LikeHumanModel;
likeHumanModelCount = LIKE_HUMAN_MODEL_COUNT;
}else{
const int LIKE_HUMAN_MODEL_COUNT = 1;
static int s_LikeHumanModel[LIKE_HUMAN_MODEL_COUNT] = {RES_MOD_YUEXIAN_RESHAPE_F};
likeHumanModelArray = s_LikeHumanModel;
likeHumanModelCount = LIKE_HUMAN_MODEL_COUNT;
}
break;
}
if (likeHumanModelCount > 0){
const int *begin = likeHumanModelArray;
const int *end = likeHumanModelArray + likeHumanModelCount;
if (std::find(begin, end, _GetProfessionTransformModelID(nChar, nGender, nModelID)) != end){
result = true;
}
}
return result;
}
inline void _ReleaseLoadModel(EC_PLAYERLOADRESULT& Ret)
{
if (Ret.pPlayerModel)
{
Ret.pPlayerModel->Release();
delete Ret.pPlayerModel;
}
if (Ret.pDummyModel)
{
Ret.pDummyModel->Release();
delete Ret.pDummyModel;
}
if (Ret.pFaceModel)
{
Ret.pFaceModel->Release();
delete Ret.pFaceModel;
}
if (Ret.pPetModel)
{
Ret.pPetModel->Release();
delete Ret.pPetModel;
}
for (int i = 0; i < NUM_SKIN_INDEX; i++)
{
g_pGame->ReleaseA3DSkin(Ret.EquipResult.aSkins[i][0]);
g_pGame->ReleaseA3DSkin(Ret.EquipResult.aSkins[i][1]);
g_pGame->ReleaseA3DSkin(Ret.EquipResult.aSkins[i][2]);
}
if (Ret.EquipResult.pLeftHandWeapon)
{
Ret.EquipResult.pLeftHandWeapon->Release();
delete Ret.EquipResult.pLeftHandWeapon;
}
if (Ret.EquipResult.pRightHandWeapon)
{
Ret.EquipResult.pRightHandWeapon->Release();
delete Ret.EquipResult.pRightHandWeapon;
}
if (Ret.EquipResult.pWing)
{
Ret.EquipResult.pWing->Release();
delete Ret.EquipResult.pWing;
}
}
// Build pate faction text
static void _BuildPateFactionText(int idFaction, int iRank, ACString& strText)
{
strText.Empty();
if (!idFaction)
return;
// Reset faction name
Faction_Info* pFaction = g_pGame->GetFactionMan()->GetFaction(idFaction);
if (!pFaction)
return;
strText = pFaction->GetName();
// Add faction rank
if (iRank >= _R_MASTER && iRank <= _R_POINEER)
{
strText += _AL(" ");
strText += g_pGame->GetFixedMsgTab()->GetWideString(FIXMSG_FCRANK_MASTER + iRank - _R_MASTER);
}
}
void GetFashionActionNameByID(int idEquipment, AString& strAction)
{
if (idEquipment)
{
DATA_TYPE dt = DT_INVALID;
const void* pEquip = g_pGame->GetElementDataMan()->get_data_ptr(
idEquipment,
ID_SPACE_ESSENCE,
dt);
if (pEquip && dt == DT_FASHION_ESSENCE)
{
const FASHION_ESSENCE *pEssence = (const FASHION_ESSENCE *)pEquip;
strAction = pEssence->wear_action;
}
}
}
bool CECPlayer::LoadPlayerEquips(
int iProf,
int iGender,
__int64 Mask,
const int* pEquips,
EquipsLoadResult& Ret,
bool bSimpleModel)
{
memset(&Ret, 0, sizeof(Ret));
ShowEquipments(
iProf,
iGender,
pEquips,
Mask,
&Ret,
bSimpleModel
);
return true;
}
// Load player model
bool CECPlayer::LoadPlayerModel(
int iProfession,
int iGender,
int iCustom,
const int* pEquips,
const char* szPetPath,
EC_PLAYERLOADRESULT& Ret,
bool bSimpleFace, bool bSimpleModel)
{
static const char* aModelFiles[NUM_PROFESSION*NUM_GENDER] =
{
res_ModelFile(RES_MOD_WARRIOR_M), // 武侠
res_ModelFile(RES_MOD_WARRIOR_F),
res_ModelFile(RES_MOD_MAGE_M), // 法师
res_ModelFile(RES_MOD_MAGE_F),
res_ModelFile(RES_MOD_MONK_M), // 巫师
res_ModelFile(RES_MOD_MONK_F),
res_ModelFile(RES_MOD_HAG_M), // 妖精
res_ModelFile(RES_MOD_HAG_F),
res_ModelFile(RES_MOD_ORC_M), // 妖兽
res_ModelFile(RES_MOD_ORC_F),
res_ModelFile(RES_MOD_GHOST_M), // 刺客
res_ModelFile(RES_MOD_GHOST_F),
res_ModelFile(RES_MOD_ARCHOR_M), // 羽芒
res_ModelFile(RES_MOD_ARCHOR_F),
res_ModelFile(RES_MOD_ANGEL_M), // 羽灵
res_ModelFile(RES_MOD_ANGEL_F),
res_ModelFile(RES_MOD_JIANLING_M), // 剑灵
res_ModelFile(RES_MOD_JIANLING_F),
res_ModelFile(RES_MOD_MEILING_M), // 魅灵
res_ModelFile(RES_MOD_MEILING_F),
res_ModelFile(RES_MOD_YEYING_M), // 夜影
res_ModelFile(RES_MOD_YEYING_F),
res_ModelFile(RES_MOD_YUEXIAN_M), // 月仙
res_ModelFile(RES_MOD_YUEXIAN_F),
};
int iChar = iProfession * NUM_GENDER + iGender;
memset(&Ret, 0, sizeof(Ret));
Ret.dwValidMask |= PLAYERLOADRESULT_PLAYERMODEL | PLAYERLOADRESULT_EQUIPMODEL | PLAYERLOADRESULT_PETMODEL;
// Load player model ----------------------------
if (!(Ret.pPlayerModel = new CECModel))
{
glb_ErrorOutput(ECERR_NOTENOUGHMEMORY, "CECPlayer::LoadPlayerModel", __LINE__);
_ReleaseLoadModel(Ret);
return false;
}
// Load skeleton without skins
const char* szFile = aModelFiles[iChar];
if (!Ret.pPlayerModel->Load(szFile, true, A3DSkinModel::LSF_NOSKIN, /*true*/false))
{
a_LogOutput(1, "CECPlayer::LoadPlayerModel, Failed to load player model %s", szFile);
_ReleaseLoadModel(Ret);
return false;
}
A3DSkinModel* pA3DModel = Ret.pPlayerModel->GetA3DSkinModel();
if (!pA3DModel)
{
_ReleaseLoadModel(Ret);
return false;
}
pA3DModel->AddSkin(NULL, false); // body skin
pA3DModel->AddSkin(NULL, false); // upper body skin
pA3DModel->AddSkin(NULL, false); // wrist skin
pA3DModel->AddSkin(NULL, false); // lower body skin
pA3DModel->AddSkin(NULL, false); // foot skin
pA3DModel->AddSkin(NULL, false); // head skin
pA3DModel->AddSkin(NULL, false); // fashion upper body skin
pA3DModel->AddSkin(NULL, false); // fashion wrist skin
pA3DModel->AddSkin(NULL, false); // fashion lower body skin
pA3DModel->AddSkin(NULL, false); // fashion foot skin
// load equips
__int64 EquipMask = 0;
if (pEquips)
{
for (__int64 i = 0; i < SIZE_ALL_EQUIPIVTR; i++)
EquipMask |= (pEquips[i] < 0) ? 0 : (1 << i);
}
if(EquipMask)
{
ShowEquipments(
iProfession,
iGender,
pEquips,
EquipMask,
&Ret.EquipResult,
bSimpleModel
);
}
if (!LoadBodySkin(iCustom, iProfession, iGender, Ret.EquipResult.aSkins, Ret.pBodyShaders, bSimpleModel))
{
_ReleaseLoadModel(Ret);
return false;
}
if( bSimpleFace )
{
Ret.pFaceModel = NULL;
}
else
{
Ret.pFaceModel = ThreadLoadFaceModel(iProfession, iGender, iCustom);
if (!Ret.pFaceModel)
{
_ReleaseLoadModel(Ret);
return false;
}
}
if (szPetPath && szPetPath[0] && !LoadPetModel(szPetPath, &Ret.pPetModel))
{
_ReleaseLoadModel(Ret);
return false;
}
return true;
}
bool CECPlayer::LoadPetModel(const char* szPetPath, CECModel** ppPetModel)
{
CECModel*& pPetModel = *ppPetModel;
pPetModel = new CECModel();
// g_pGame->GetA3DEngine()->GetA3DSkinMan()->SetReplaceShaderFile("armor.sdr", A3DSkinMan::SHADERREPLACE_REFLECTPREFIX);
g_pGame->GetA3DEngine()->GetA3DSkinMan()->SetReplaceShaderFile((const char*)glb_ArmorReplaceShader_ReflectPrefix, A3DSkinMan::SHADERREPLACE_USERDEFINE);
if (!pPetModel->Load(szPetPath, true, A3DSkinModel::LSF_NOSKIN, true))
{
delete pPetModel;
pPetModel = NULL;
g_pGame->GetA3DEngine()->GetA3DSkinMan()->SetReplaceShaderFile("", 0);
return false;
}
pPetModel->BuildWoundActionChannel();
char szSkin[MAX_PATH];
strncpy(szSkin, szPetPath, MAX_PATH);
glb_ChangeExtension(szSkin, "ski");
A3DSkin * pPetSkin = g_pGame->LoadA3DSkin(szSkin, false);
if( !pPetSkin )
{
pPetModel->Release();
delete pPetModel;
pPetModel = NULL;
g_pGame->GetA3DEngine()->GetA3DSkinMan()->SetReplaceShaderFile("", 0);
return false;
}
pPetModel->GetA3DSkinModel()->AddSkin(pPetSkin, true);
g_pGame->GetA3DEngine()->GetA3DSkinMan()->SetReplaceShaderFile("", 0);
return true;
}
bool CECPlayer::LoadDummyModel(int iShape, CECModel** ppDummyModel)
{
CECModel* pDummyModel = NULL;
int resID = PLAYERMODEL_GETID(iShape);
if(resID > 0) // == 0 means no model changed but logic transformed
{
pDummyModel = new CECModel;
if (!pDummyModel)
{
glb_ErrorOutput(ECERR_NOTENOUGHMEMORY, "CECPlayer::LoadDummyModel", __LINE__);
return false;
}
const char* szFile = NULL;
if (PLAYERMODEL_GETTYPE(iShape) == PLAYERMODEL_DUMMYTYPE2) // 小动物变身
szFile = res_ModelFileForChangeShape2(resID);
else
szFile = res_ModelFile(resID);
if (!pDummyModel->Load(szFile, true, 0, false))
{
delete pDummyModel;
a_LogOutput(1, "CECPlayer::LoadDummyModel, Failed to load dummy model %s", szFile);
return false;
}
}
*ppDummyModel = pDummyModel;
return true;
}
// Release player model
void CECPlayer::ReleasePlayerModel(EC_PLAYERLOADRESULT& Ret)
{
if (Ret.pPlayerModel)
{
QueueECModelForRelease(Ret.pPlayerModel);
Ret.pPlayerModel = NULL;
}
if (Ret.pDummyModel)
{
QueueECModelForRelease(Ret.pDummyModel);
Ret.pDummyModel = NULL;
}
A3DRELEASE(Ret.pFaceModel);
A3DRELEASE(Ret.pPetModel);
A3DRELEASE(Ret.EquipResult.pLeftHandWeapon);
A3DRELEASE(Ret.EquipResult.pRightHandWeapon);
A3DRELEASE(Ret.EquipResult.pWing);
A3DRELEASE(Ret.EquipResult.pWing2);
for (int i = 0; i < 3; i++)
{
g_pGame->ReleaseA3DSkin(Ret.EquipResult.aSkins[SKIN_BODY_INDEX][i]);
g_pGame->ReleaseA3DSkin(Ret.EquipResult.aSkins[SKIN_HEAD_INDEX][i]);
g_pGame->ReleaseA3DSkin(Ret.EquipResult.aSkins[SKIN_UPPER_BODY_INDEX][i]);
g_pGame->ReleaseA3DSkin(Ret.EquipResult.aSkins[SKIN_WRIST_INDEX][i]);
g_pGame->ReleaseA3DSkin(Ret.EquipResult.aSkins[SKIN_LOWER_INDEX][i]);
g_pGame->ReleaseA3DSkin(Ret.EquipResult.aSkins[SKIN_FOOT_INDEX][i]);
g_pGame->ReleaseA3DSkin(Ret.EquipResult.aSkins[SKIN_FASHION_UPPER_BODY_INDEX][i]);
g_pGame->ReleaseA3DSkin(Ret.EquipResult.aSkins[SKIN_FASHION_WRIST_INDEX][i]);
g_pGame->ReleaseA3DSkin(Ret.EquipResult.aSkins[SKIN_FASHION_LOWER_INDEX][i]);
g_pGame->ReleaseA3DSkin(Ret.EquipResult.aSkins[SKIN_FASHION_FOOT_INDEX][i]);
}
}
// Get exp of specified level
int CECPlayer::GetLevelUpExp(int iLevel)
{
return _player_levelup_exp.exp[iLevel - 1];
//return iLevel * iLevel * 500;
}
// Build riding pet file name
const char* CECPlayer::GetRidingPetFileName(int idPet)
{
static const char* szDef = "Models\\NPCs\\宠物\\骑宠\\骑宠马\\骑宠马白.ecm";
DATA_TYPE DataType;
const void* pDataPtr = g_pGame->GetElementDataMan()->get_data_ptr(idPet, ID_SPACE_ESSENCE, DataType);
if (DataType != DT_PET_ESSENCE)
return szDef;
const PET_ESSENCE* pData = (const PET_ESSENCE*)pDataPtr;
if (!pData->file_model[0])
return szDef;
return pData->file_model;
}
// Initialize static resources
bool CECPlayer::InitStaticRes()
{
// Element data man must has been initialized
elementdataman* pdb = g_pGame->GetElementDataMan();
if (!pdb)
{
ASSERT(pdb);
return false;
}
BuildActionList();
// Initialize level up exp table
DATA_TYPE dt;
_player_levelup_exp = *(PLAYER_LEVELEXP_CONFIG*)g_pGame->GetElementDataMan()->get_data_ptr(202, ID_SPACE_CONFIG, dt);
// Initialize a CRITICAL_SECTION for loading player skin
InitializeCriticalSection(&l_csLoadPlayerSkin);
return true;
}
// Release static resources
void CECPlayer::ReleaseStaticRes()
{
delete[] _default_actions;
_default_actions = NULL;
delete[] _turning_actions;
_turning_actions = NULL;
_default_skill_actions.clear();
DeleteCriticalSection(&l_csLoadPlayerSkin);
}
///////////////////////////////////////////////////////////////////////////
//
// Implement CECPlayer
//
///////////////////////////////////////////////////////////////////////////
CECPlayer::CECPlayer(CECPlayerMan* pPlayerMan)
{
m_iCID = OCID_PLAYER;
m_pPlayerMan = pPlayerMan;
m_pPlayerModel = NULL;
m_pFaceModel = NULL;
memset(m_pModels, 0, sizeof(m_pModels));
memset(m_aShapeID, 0, sizeof(m_aShapeID));
m_pLeftHandWeapon = NULL;
m_pRightHandWeapon = NULL;
m_bWeaponAttached = false;
m_pPetModel = NULL;
m_pActionController = NULL;
m_pBodyController = NULL;
m_pSprite = NULL;
m_pGoblin = NULL;
memset(m_pBodyShader, 0, sizeof(A3DShader *) * 3);
m_iMoveMode = MOVE_STAND;
m_iMoveEnv = MOVEENV_GROUND;
m_bCastShadow = false;
m_pLevelUpGFX = NULL;
m_pWaterWaveStill = NULL;
m_pWaterWaveMove = NULL;
m_pAirBubble = NULL;
m_pSwimBubble = NULL;
m_pTransformGfx = NULL;
m_pDuelStateGFX = NULL;
m_pPetCureGFX = NULL;
m_pPetCureGFXtate = -1;
memset(m_pMonsterSpiritGFX, 0, sizeof(m_pMonsterSpiritGFX));
m_iMonsterSpiritMineID = 0;
m_stateMonsterSpirit = BALL_STATE_NONE;
m_fTouchRad = 0.3f;
m_iMoneyCnt = 0;
m_iMaxMoney = 1000;
m_bWalkRun = 1;
m_pTeam = NULL;
m_iProfession = PROF_WARRIOR;
m_iGender = GENDER_MALE;
m_bRenderName = false;
m_bRenderBar = true;
m_dwStates = 0;
m_dwStates2 = 0;
m_dwResFlags = 0;
m_uAttackType = DEFAULT_ACTION_TYPE;
m_iFashionWeaponType= DEFAULT_ACTION_TYPE;
m_bAboutToDie = false;
memset(m_aExtStates, 0, sizeof(m_aExtStates));
memset(m_aExtStatesShown, 0, sizeof(m_aExtStatesShown));
m_pCurSkill = NULL;
m_idCurSkillTarget = 0;
m_bFight = false;
m_iReputation = 0;
m_iShape = 0;
m_bInSanctuary = false;
m_bPetInSanctuary = false;
m_iBoothState = 0;
m_crcBooth = 0;
m_bFashionMode = false;
m_factionPVPMask = 0;
m_idFaction = 0;
m_idFRole = GNET::_R_UNMEMBER;
m_idSpouse = 0;
m_byPariahLvl = 0;
m_bRushFly = false;
m_AttachMode = enumAttachNone;
m_bHangerOn = false;
m_iBuddyId = 0;
m_idCandBuddy = 0;
m_bCandHangerOn = false;
m_pFactionDecal = NULL;
m_iBattleCamp = GP_BATTLE_CAMP_NONE;
m_dwGMFlags = 0;
m_idCurPet = 0;
m_pBoothModel = NULL;
m_iBoothModelCertificateID = -1; // 默认值为-1,以处理默认摆摊模型为0时、也需要加载默认摆摊模型的情况
m_bBoothModelLoaded = false;
m_iBoothBarCertificateID = -1; // 默认值为-1,以处理默认摆摊模型为0时、也需要加载默认摆摊模型的情况
m_weaponHangerPos = WEAPON_HANGER_HAND;
m_vNamePos = A3DVECTOR3(0.0f);
m_i64EquipDisabled = 0;
m_idForce = 0;
m_idCountry = 0;
m_pCountryDecal = NULL;
m_pPateCountry = NULL;
m_PlayerActions = _default_actions; // bind to default actions
m_iMemUsage = CECMemSimplify::MEMUSAGE_NORMAL;
m_GoblinRenderCnt.SetPeriod(30000);
m_GoblinRenderCnt.Reset(true);
m_bRenderGoblin = true;
m_TransCnt.SetPeriod(500);
m_fDstTrans = 0.f;
m_fCurTrans = 0.f;
m_fTransDelta = 0.f;
m_fDistToCamera = 0.0f;
if ((m_pPateName = new CECPateText))
m_pPateName->EnableBorder(true);
if ((m_pPateMarry = new CECPateText))
m_pPateMarry->EnableBorder(true);
if ((m_pPateBooth = new CECPateText))
m_pPateBooth->EnableBorder(true);
if ((m_pPateFaction = new CECPateText))
m_pPateFaction->EnableBorder(true);
if ((m_pPateForce = new CECPateText))
m_pPateForce->EnableBorder(true);
if ((m_pPateTitle = new CECPateText))
m_pPateTitle->EnableBorder(true);
m_pPateLastWords1 = new CECPateText;
m_pPateLastWords2 = new CECPateText;
m_pPateTeamReq = new CECPateText;
m_pBubbleTexts = new CECBubbleDecalList;
m_nLowerEquipMethod = enumSkinShowNone;
m_nLowerFashionEquipMethod = enumSkinShowNone;
m_wingType = WINGTYPE_FLYSWORD;
m_aabb.Center = g_vOrigin;
m_aabb.Extents.Set(0.3f, 0.9f, 0.3f);
m_aabbServer = m_aabb;
m_MoveConst.fStepHei = 0.8f;
m_MoveConst.fMinAirHei = 1.6f;
m_MoveConst.fMinWaterHei = 0.3f;
m_MoveConst.fShoreDepth = 1.6f;
m_MoveConst.fWaterSurf = 0.6f;
memset(&m_CustomizeData, 0, sizeof(m_CustomizeData));
m_CustomizeData.bodyID = 0;
m_CustomizeData.dwVersion = CUSTOMIZE_DATA_VERSION;
m_CustomizeData.colorBody = 0xffffffff;
m_CustomizeData.headScale = 128;
m_CustomizeData.upScale = 128;
m_CustomizeData.waistScale = 128;
m_CustomizeData.armWidth = 128;
m_CustomizeData.legWidth = 128;
m_CustomizeData.breastScale = 128;
m_OldCustomizeData = m_CustomizeData;
m_ChgPllCustomizeData = m_CustomizeData;
m_vPortraitCamScale = 1.0f;
m_bIsChangingFace = false;
memset(&m_PlayerInfo, 0, sizeof (m_PlayerInfo));
memset(&m_BasicProps, 0, sizeof (m_BasicProps));
memset(&m_ExtProps, 0, sizeof (m_ExtProps));
memset(m_aEquips, 0xff, sizeof (m_aEquips));
memset(&m_TeamReq, 0, sizeof (m_TeamReq));
memset(m_aSkins, 0, sizeof (m_aSkins));
memset(m_aCurSkins, 0, sizeof (m_aCurSkins));
memset(&m_pvp, 0, sizeof (m_pvp));
memset(&m_meridiansProp, 0, sizeof (m_meridiansProp));
m_PlayerInfo.crc_c = -1;
m_PateContent.iVisible = 0;
m_bShowWeapon = true;
m_stoneUpperBody = 0;
m_stoneWrist = 0;
m_stoneLowerBody = 0;
m_stoneFoot = 0;
m_stoneWeapon = 0;
m_idFullSuite = 0;
m_stoneUpperBodyShown = 0;
m_stoneWristShown = 0;
m_stoneLowerBodyShown = 0;
m_stoneFootShown = 0;
m_stoneWeaponShown = 0;
m_idFullSuiteShown = 0;
m_TitleID = 0;
m_ReincarnationCount = 0;
m_RealmLevel = 0;
m_strLastSayCnt.SetPeriod(20000);
m_fScaleBySkill = 1.f;
m_SkillIDForStateAction = 0;
// Initialize Customize Factor
InitCustomizeFactor();
m_idSelTarget = 0;
//载入个性化限制
//m_pCustomizeBound = g_CustomizeBoundMgr.GetCustomizeBound("Configs\\CustomizeBound.ini");
//assert(m_pCustomizeBound);
}
CECPlayer::~CECPlayer()
{
}
//#define _DEBUG_OUTPUT_ACTIONS
void CECPlayer::BuildActionList()
{
#ifdef _DEBUG_OUTPUT_ACTIONS
FILE * fpActionList = fopen("actions.txt", "wt");
#endif
// Load action names from file
if (!_default_actions)
{
typedef abase::hashtab<PLAYER_ACTION_INFO_CONFIG *, AString, abase::_hash_function> PlayerActionMap;
typedef abase::hashtab<PLAYER_ACTION_INFO_CONFIG *, AWString, abase::_hash_function> PlayerSkillActionMap;
int i;
elementdataman * dataman = g_pGame->GetElementDataMan();
PLAYER_ACTION_INFO_CONFIG * data = NULL;
// 1. 建立动作名称到 PLAYER_ACTION_INFO_CONFIG 数据的映射,供后续快速查询
PlayerActionMap actionMap(100);
PlayerSkillActionMap skillActionMap(100);
{
int count = dataman->get_data_num(ID_SPACE_CONFIG);
DATA_TYPE dt;
int id(0);
for (i = 0; i < count; ++ i)
{
id = dataman->get_data_id(ID_SPACE_CONFIG, i, dt);
if (dt != DT_PLAYER_ACTION_INFO_CONFIG)
continue;
data = (PLAYER_ACTION_INFO_CONFIG *) dataman->get_data_ptr(id, ID_SPACE_CONFIG, dt);
// 建立通用动作名的映射表条目
if (data->action_name[0] && data->action_name[0] != '0')
{
if (!actionMap.put(data->action_name, data))
{
#ifdef _DEBUG
AString strTemp;
strTemp.Format("通用动作名重复: action_name = %s, 原id = %d, 新id = %d\n", data->action_name, (*(actionMap.find(data->action_name).value()))->id, data->id);
::OutputDebugStringA(strTemp);
#endif
}
}
// 建立技能动作名的映射表条目
if (data->name[0] && data->name[0] != '0')
{
if (!skillActionMap.put(data->name, data))
{
#ifdef _DEBUG
ACString strTemp;
strTemp.Format(_AL("技能动作名重复: name = %s, 原id = %d, 新id = %d\n"), data->name, (*(skillActionMap.find(data->name).value()))->id, data->id);
::OutputDebugString(strTemp);
#endif
}
}
#ifdef _DEBUG
if (!(data->action_name[0] && data->action_name[0] != '0') &&
!(data->name[0] && data->name[0] != '0'))
{
AString strTemp;
strTemp.Format("动作配置表错误,名称为空: id = %d\n", data->id);
::OutputDebugStringA(strTemp);
}
#endif
}
}
// 2.处理通用动作
CECStringTab actionNames;
actionNames.Init("Configs\\actions_player.txt", false);
_default_actions = new PLAYER_ACTION[ACT_MAX];
memset(_default_actions, 0, sizeof(PLAYER_ACTION) * ACT_MAX);
for(i=0; i<ACT_MAX; i++)
{
_default_actions[i].type = (PLAYER_ACTION_TYPE) i;
const char *szName = actionNames.GetANSIString(i);
if (szName && szName[0])
{
PlayerActionMap::iterator it = actionMap.find(szName);
if (it != actionMap.end())
{
_default_actions[i].data = data = *it.value();
#ifdef _DEBUG_OUTPUT_ACTIONS
if( i >= ACT_ATTACK_1 && i <= ACT_ATTACK_4 )
{
for(int n=0; n<NUM_WEAPON_TYPE; n++)
{
fprintf(fpActionList, "%s_%s起\n", data->action_prefix, data->action_weapon_suffix[n].suffix);
fprintf(fpActionList, "%s_%s落\n", data->action_prefix, data->action_weapon_suffix[n].suffix);
}
}
else
{
for(int n=0; n<NUM_WEAPON_TYPE; n++)
{
fprintf(fpActionList, "%s_%s\n", data->action_prefix, data->action_weapon_suffix[n].suffix);
}
}
#endif
continue;
}
}
// not found
// a_LogOutput(1, "CECPlayer::CECPlayer(), Failed to find action [%s]'s data", actionNames.GetANSIString(i));
}
// 建立特殊动作映射
if(_turning_actions) delete[] _turning_actions;
_turning_actions = new PLAYER_ACTION[ACT_MAX];
PlayerActionMap::iterator turning = actionMap.find("自身旋转"); // 查找特殊的动作
for(i=0; i<ACT_MAX; i++)
{
if( (i < ACT_GROUNDDIE || // 陆地死亡
i > ACT_REVIVE) && // 复活
turning != actionMap.end() )
{
// 用旋转动作替换通用动作
_turning_actions[i].type = (PLAYER_ACTION_TYPE) i;
_turning_actions[i].data = *turning.value();
}
else
{
// 使用通用动作
_turning_actions[i] = _default_actions[i];
}
}
// 3.处理技能动作
unsigned int idSkill = 0;
while(true)
{
idSkill = GNET::ElementSkill::NextSkill(idSkill);
if( idSkill == 0 )
break;
const wchar_t *wszName = GNET::ElementSkill::GetName(idSkill);
if (wszName && wszName[0])
{
PlayerSkillActionMap::iterator it = skillActionMap.find(wszName);
if (it != skillActionMap.end())
{
_default_skill_actions[idSkill] = data = *it.value();
#ifdef _DEBUG_OUTPUT_ACTIONS
for(int n=0; n<NUM_WEAPON_TYPE; n++)
{
if( data->action_weapon_suffix[n].suffix[0] )
{
fprintf(fpActionList, "%s_吟唱_%s\n", data->action_prefix, data->action_weapon_suffix[n].suffix);
fprintf(fpActionList, "%s_施放起_%s\n", data->action_prefix, data->action_weapon_suffix[n].suffix);
fprintf(fpActionList, "%s_施放落_%s\n", data->action_prefix, data->action_weapon_suffix[n].suffix);
}
}
#endif
continue;
}
}
// not found
// a_LogOutput(1, "CECPlayer::BuildActionList(), Failed to find skill action %d!", idSkill);
}
}
#ifdef _DEBUG_OUTPUT_ACTIONS
fclose(fpActionList);
#endif
}
// Release object
void CECPlayer::Release()
{
DetachBuddy();
// Clear extend states before model is released
ClearShowExtendStates();
::memset(m_aExtStates, 0, sizeof(m_aExtStates));
m_aIconStates.clear();
if (m_pPateName)
{
delete m_pPateName;
m_pPateName = NULL;
}
if (m_pPateMarry)
{
delete m_pPateMarry;
m_pPateMarry = NULL;
}
if (m_pPateForce)
{
delete m_pPateForce;
m_pPateForce = NULL;
}
if (m_pPateTitle)
{
delete m_pPateTitle;
m_pPateTitle = NULL;
}
if (m_pPateLastWords1)
{
delete m_pPateLastWords1;
m_pPateLastWords1 = NULL;
}
if (m_pPateLastWords2)
{
delete m_pPateLastWords2;
m_pPateLastWords2 = NULL;
}
if (m_pPateTeamReq)
{
delete m_pPateTeamReq;
m_pPateTeamReq = NULL;
}
if (m_pPateBooth)
{
delete m_pPateBooth;
m_pPateBooth = NULL;
}
if (m_pPateFaction)
{
delete m_pPateFaction;
m_pPateFaction = NULL;
}
if (m_pFactionDecal)
{
delete m_pFactionDecal;
m_pFactionDecal = NULL;
}
if (m_pPateCountry)
{
delete m_pPateCountry;
m_pPateCountry = NULL;
}
if (m_pCountryDecal)
{
delete m_pCountryDecal;
m_pCountryDecal = NULL;
}
if (m_pBubbleTexts)
{
delete m_pBubbleTexts;
m_pBubbleTexts = NULL;
}
if (m_pLevelUpGFX)
{
g_pGame->GetGFXCaster()->ReleaseGFXEx(m_pLevelUpGFX);
m_pLevelUpGFX = NULL;
}
if (m_pPetCureGFX)
{
A3DGFXExMan *pGFXExMan = g_pGame->GetA3DGFXExMan();
if (pGFXExMan)
pGFXExMan->CacheReleasedGfx(m_pPetCureGFX);
m_pPetCureGFX = NULL;
m_pPetCureGFXtate = -1;
}
for (int i = 0; i < sizeof(m_pMonsterSpiritGFX) / sizeof(m_pMonsterSpiritGFX[0]); ++i) {
A3DGFXExMan *pGFXExMan = g_pGame->GetA3DGFXExMan();
if (pGFXExMan)
pGFXExMan->CacheReleasedGfx(m_pMonsterSpiritGFX[i]);
m_pMonsterSpiritGFX[i] = NULL;
}
if (m_pWaterWaveStill)
{
g_pGame->GetGFXCaster()->ReleaseGFXEx(m_pWaterWaveStill);
m_pWaterWaveStill = NULL;
}
if (m_pWaterWaveMove)
{
g_pGame->GetGFXCaster()->ReleaseGFXEx(m_pWaterWaveMove);
m_pWaterWaveMove = NULL;
}
if (m_pAirBubble)
{
g_pGame->GetGFXCaster()->ReleaseGFXEx(m_pAirBubble);
m_pAirBubble = NULL;
}
if (m_pSwimBubble)
{
g_pGame->GetGFXCaster()->ReleaseGFXEx(m_pSwimBubble);
m_pSwimBubble = NULL;
}
if (m_pTransformGfx)
{
g_pGame->GetGFXCaster()->ReleaseGFXEx(m_pTransformGfx);
m_pTransformGfx = NULL;
}
if (m_pDuelStateGFX)
{
g_pGame->GetGFXCaster()->ReleaseGFXEx(m_pDuelStateGFX);
m_pDuelStateGFX = NULL;
}
if (m_pPetModel)
{
m_pPetModel->RemoveChildModel(_hanger_ride, false);
A3DRELEASE(m_pPetModel);
}
ClearBoothModel();
for (MOEffectMAP::iterator it = m_mapMOEffect.begin();it != m_mapMOEffect.end();++it)
{
A3DGFXExMan *pGFXExMan = g_pGame->GetA3DGFXExMan();
pGFXExMan->CacheReleasedGfx(it->second);
}
m_mapMOEffect.clear();
// Release face model
ReleaseFaceModel();
// Release player model
ReleasePlayerModel();
// Clear resource ready flags
SetResReadyFlag(RESFG_ALL, false);
m_bAboutToDie = false;
}
bool CECPlayer::LoadBodySkin(
int nBodyID,
int iProfession,
int iGender,
A3DSkin* aSkins[NUM_SKIN_INDEX][3],
A3DShader* pBodyShaders[3],
bool bSimpleModel)
{
// body skin will be customized later, so they counld't be sharedly loaded by
// A3DSkinMan
char szBodySkin[256];
// ensure the gender is valid
if(iGender != GENDER_MALE)
{
ASSERT(iGender == GENDER_FEMALE);
iGender = GENDER_FEMALE;
}
const int nMaxBodyID = CECProfConfig::Instance().GetMaxBodyID(iProfession);
if (nMaxBodyID > 0)
{
// use the max value instead of invalid value
if(nBodyID < 0 || nBodyID > nMaxBodyID)
{
#ifndef _PROFILE_MEMORY
ASSERT(false);
#endif
nBodyID = nMaxBodyID;
}
if( !bSimpleModel )
sprintf(szBodySkin, _body_skin[iProfession * NUM_GENDER + iGender], nBodyID + 1);
else
sprintf(szBodySkin, _simple_body_skin[iProfession * NUM_GENDER + iGender], nBodyID + 1);
}
else
{
if( !bSimpleModel )
strncpy(szBodySkin, _body_skin[iProfession * NUM_GENDER + iGender], 256);
else
strncpy(szBodySkin, _simple_body_skin[iProfession * NUM_GENDER + iGender], 256);
}
if (!LoadPlayerSkin(aSkins[SKIN_BODY_INDEX], SKIN_BODY_INDEX, szBodySkin))
{
a_LogOutput(1, "CECPlayer::LoadBodySkin, Falied to replace body skin");
return false;
}
int n;
for(n=0; n<3; n++)
{
A3DSkin* pBodySkin = aSkins[SKIN_BODY_INDEX][n];
int i;
// adjust skin's material to make it a little speculable
int nNumMaterial = pBodySkin->GetMaterialNum();
for(i=0; i<nNumMaterial; i++)
{
A3DMATERIALPARAM param = pBodySkin->GetMaterial(i)->GetMaterialParam();
param.Specular = 0xff3a3a3a;
param.Power = 10.0f;
pBodySkin->GetMaterial(i)->SetMaterialParam(param);
}
A3DSkinMesh* pMesh = NULL;
for(i=0; i<pBodySkin->GetSkinMeshNum(); i++)
{
if( pBodySkin->GetSkinMesh(i)->GetTextureIndex() == 0 )
{
// found body mesh
pMesh = pBodySkin->GetSkinMesh(i);
break;
}
}
if (!pMesh)
{
a_LogOutput(1, "CECPlayer::LoadBodySkin, Failed to set body shader");
return false;
}
int iTexIndex = pMesh->GetTextureIndex();
A3DTexture* pTex = pBodySkin->GetTexture(iTexIndex);
char szTextureMap[MAX_PATH];
strncpy(szTextureMap, pTex->GetMapFile(), MAX_PATH);
// now load body skin shader
pBodyShaders[n] = glb_LoadBodyShader(pBodySkin, szTextureMap);
if (!pBodyShaders[n])
a_LogOutput(1, "CECPlayer::LoadBodySkin, Failed to load body shader");
if (!pBodySkin->ChangeSkinTexturePtr(iTexIndex, pBodyShaders[n]))
{
a_LogOutput(1, "CECPlayer::LoadBodySkin, Failed to change skin texture");
return false;
}
}
// Record head skin file
char szHeadFile[256];
if( nMaxBodyID > 0 )
sprintf(szHeadFile, "%s%d", _head_skin[iProfession * NUM_GENDER + iGender], nBodyID + 1);
else
strcpy(szHeadFile, _head_skin[iProfession * NUM_GENDER + iGender]);
if (!LoadPlayerSkin(aSkins[SKIN_HEAD_INDEX], SKIN_HEAD_INDEX, szHeadFile))
{
a_LogOutput(1, "CECPlayer::LoadBodySkin, Falied to replace head skin");
return false;
}
return true;
}
bool CECPlayer::LoadBodySkin(int nBodyID, bool bSimpleModel)
{
A3DSkin* aSkins[NUM_SKIN_INDEX][3] = {0};
A3DShader* pBodyShaders[3];
if (!LoadBodySkin(nBodyID, m_iProfession, m_iGender, aSkins, pBodyShaders, bSimpleModel))
{
for (int i = 0; i < NUM_SKIN_INDEX; i++)
{
g_pGame->ReleaseA3DSkin(aSkins[i][0]);
g_pGame->ReleaseA3DSkin(aSkins[i][1]);
g_pGame->ReleaseA3DSkin(aSkins[i][2]);
}
return false;
}
// we must remove the skin from skin model before we can release it.
ReplaceCurSkin(SKIN_BODY_INDEX, NULL);
ReplaceCurSkin(SKIN_HEAD_INDEX, NULL);
for (int i = 0; i < 3; i++)
{
g_pGame->ReleaseA3DSkin(m_aSkins[SKIN_BODY_INDEX][i]);
g_pGame->ReleaseA3DSkin(m_aSkins[SKIN_HEAD_INDEX][i]);
m_aSkins[SKIN_BODY_INDEX][i] = aSkins[SKIN_BODY_INDEX][i];
m_aSkins[SKIN_HEAD_INDEX][i] = aSkins[SKIN_HEAD_INDEX][i];
m_pBodyShader[i] = pBodyShaders[i];
}
if (GetMajorModel() && !bSimpleModel)
{
GetMajorModel()->ShowSkin(SKIN_HEAD_INDEX, false);
}
return true;
}
bool CECPlayer::LoadPlayerSkin(
A3DSkin* aSkins[3],
int iIndex,
const char* szFile)
{
ASSERT(iIndex >= 0 && iIndex < NUM_SKIN_INDEX);
// #ifdef _DEBUG
// static int _reentrant = 0;
// assert(_reentrant++ == 0);
// #endif
ACSWrapper csa(&l_csLoadPlayerSkin);
memset(aSkins, 0, sizeof(A3DSkin*) * 3);
// now we make skinman replace skin's texture with a shader automatically
if( iIndex >= SKIN_UPPER_BODY_INDEX && iIndex <= SKIN_FOOT_INDEX )
{
#ifdef SKIN_BUMP_ENABLE
g_pGame->GetA3DEngine()->GetA3DSkinMan()->SetReplaceShaderFile("armornormalmap.sdr", A3DSkinMan::SHADERREPLACE_NORMALMAPNEEDED);
#else
// g_pGame->GetA3DEngine()->GetA3DSkinMan()->SetReplaceShaderFile("armor.sdr", 0);
g_pGame->GetA3DEngine()->GetA3DSkinMan()->SetReplaceShaderFile((const char*)glb_ArmorReplaceShader, A3DSkinMan::SHADERREPLACE_USERDEFINE);
#endif
}
else if( iIndex >= SKIN_FASHION_UPPER_BODY_INDEX && iIndex <= SKIN_FASHION_FOOT_INDEX )
{
// g_pGame->GetA3DEngine()->GetA3DSkinMan()->SetReplaceShaderFile("fashion.sdr", 0);
g_pGame->GetA3DEngine()->GetA3DSkinMan()->SetReplaceShaderFile((const char*)glb_FashionReplaceShader, A3DSkinMan::SHADERREPLACE_USERDEFINE);
}
if( szFile )
{
const char * suffix1[] = {"一级", "二级", "三级"};
const char * suffix2[] = {"", "二级", "三级"};
const char ** pSuffixes;
if( iIndex == SKIN_BODY_INDEX || iIndex == SKIN_HEAD_INDEX )
pSuffixes = suffix2;
else
pSuffixes = suffix1;
char strSkinPath[MAX_PATH];
for(int i=0; i<3; i++)
{
sprintf(strSkinPath, "%s%s.ski", szFile, pSuffixes[i]);
A3DSkin * pSkin = g_pGame->LoadA3DSkin(strSkinPath, true);
if (pSkin == NULL)
{
a_LogOutput(1, "CECPlayer::LoadPlayerSkin, Falied to load skin %s", strSkinPath);
g_pGame->GetA3DEngine()->GetA3DSkinMan()->SetReplaceShaderFile("", 0);
// #ifdef _DEBUG
// assert(--_reentrant == 0);
// #endif
return false;
}
// now set a specific material for armors
if( iIndex >= SKIN_UPPER_BODY_INDEX && iIndex <= SKIN_FOOT_INDEX )
{
A3DCOLOR specular = ARMOR_SPECULAR;
if( !g_pGame->GetA3DDevice()->TestPixelShaderVersion(1, 1) )
{
specular = 0xff606060;
}
int numMaterial = pSkin->GetMaterialNum();
for(int j=0; j<numMaterial; j++)
{
A3DMATERIALPARAM param = pSkin->GetMaterial(j)->GetMaterialParam();
param.Specular = specular;
param.Power = ARMOR_POWER;
pSkin->GetMaterial(j)->SetMaterialParam(param);
}
}
else if( iIndex >= SKIN_FASHION_UPPER_BODY_INDEX && iIndex <= SKIN_FASHION_FOOT_INDEX )
{
A3DCOLOR specular = FASHION_SPECULAR;
int numMaterial = pSkin->GetMaterialNum();
for(int j=0; j<numMaterial; j++)
{
A3DMATERIALPARAM param = pSkin->GetMaterial(j)->GetMaterialParam();
param.Specular = specular;
param.Power = FASHION_POWER;
pSkin->GetMaterial(j)->SetMaterialParam(param);
}
}
aSkins[i] = pSkin;
}
}
g_pGame->GetA3DEngine()->GetA3DSkinMan()->SetReplaceShaderFile("", 0);
// #ifdef _DEBUG
// assert(--_reentrant == 0);
// #endif
return true;
}
// Release player model
void CECPlayer::ReleasePlayerModel()
{
if( m_pSprite )
{
m_pSprite->Release();
delete m_pSprite;
m_pSprite = NULL;
}
if( m_pGoblin )
{
m_pGoblin->Release();
delete m_pGoblin;
m_pGoblin = NULL;
}
// Release player skins
int i(0);
for (i=0; i < NUM_SKIN_INDEX; i++)
{
g_pGame->ReleaseA3DSkin(m_aSkins[i][0]);
g_pGame->ReleaseA3DSkin(m_aSkins[i][1]);
g_pGame->ReleaseA3DSkin(m_aSkins[i][2]);
m_aSkins[i][0] = m_aSkins[i][1] = m_aSkins[i][2] = NULL;
m_aCurSkins[i] = NULL;
}
memset(m_pBodyShader, 0, sizeof(m_pBodyShader));
//memset(m_aEquips, 0xff, sizeof(m_aEquips));
ReleaseWeapon();
m_pPlayerModel = NULL;
//memset(m_aShapeID, 0, sizeof(m_aShapeID));
for(i = 0; i<PLAYERMODEL_MAX;i++)
{
if(!m_pModels[i]) continue;
if (IsLoadThreadReady())
{
QueueECModelForRelease(m_pModels[i]);
}
else
{
m_pModels[i]->Release();
delete m_pModels[i];
}
}
memset(m_pModels, 0, sizeof(m_pModels));
m_GfxRecords.clear();
if (m_pFaceModel)
m_pFaceModel->SetParent(NULL);
SetResReadyFlag(RESFG_SKELETON | RESFG_SKIN, false);
RecreateActionController();
RecreateBodyController();
}
CECFace* CECPlayer::ThreadLoadFaceModel(int nCurCharacter, int nCurGender, int nFaceID)
{
CECFace* pFaceModel;
if (!(pFaceModel = new CECFace))
{
glb_ErrorOutput(ECERR_NOTENOUGHMEMORY, "CECPlayer::ThreadLoadFaceModel", __LINE__);
return NULL;
}
// load different model's according to the character and gender
bool bval;
bval = pFaceModel->Init(nCurCharacter, nCurGender, nFaceID);
if( !bval )
{
a_LogOutput(1, "CECPlayer::ThreadLoadFaceModel(), Failed to init face model.");
delete pFaceModel;
return NULL;
}
return pFaceModel;
}
// Load player face model
bool CECPlayer::LoadFaceModel(int nCurCharacter, int nCurGender, int nFaceID)
{
// Release old face model
ReleaseFaceModel();
if (m_pFaceModel = ThreadLoadFaceModel(nCurCharacter, nCurGender, nFaceID)){
AttachFaceModel();
}
return m_pFaceModel != NULL;
}
// Release player face model
void CECPlayer::ReleaseFaceModel()
{
if (m_pFaceModel)
{
if (GetMajorModel()){
GetMajorModel()->RemoveComboModel(m_pFaceModel->GetECModel());
GetMajorModel()->ShowSkin(SKIN_HEAD_INDEX, true);
}
m_pFaceModel->Release();
delete m_pFaceModel;
m_pFaceModel = NULL;
}
// SetResReadyFlag(RESFG_CUSTOM, false);
}
void CECPlayer::TransformShape(int iShape, bool bLoadAtOnce/* =false */)
{
SetShape(iShape);
a_LogOutput(1, "CECPlayer::TransformShape(iShape=%d)(iShapeType=%d,iShapeID=%d)", iShape, PLAYERMODEL_GETTYPE(iShape), PLAYERMODEL_GETID(iShape));
if (!GetMajorModel()) return;
if (IsShapeChanged())
{
// change to a dummy model, may cause an asynchronous loading
QueueLoadDummyModel(m_iShape, bLoadAtOnce);
}
else
{
// back to major model is a synchronous operation
ApplyShapeModelChange(GetMajorModel());
}
}
void CECPlayer::ApplyShapeModelChange(CECModel* pModel)
{
// store and reset the attach state
int iBuddyId = m_iBuddyId;
bool bHangerOn = m_bHangerOn;
if (m_AttachMode != enumAttachNone) DetachBuddy(NULL, false);
// logic transform but no model changed
if(!pModel) pModel = GetMajorModel();
if(pModel && m_pPlayerModel && m_pPlayerModel != pModel)
{
// sync the position
pModel->SetPos(m_pPlayerModel->GetPos());
pModel->SetDirAndUp(m_pPlayerModel->GetDir(), m_pPlayerModel->GetUp());
// sync wing
CECModel* pWing = m_pPlayerModel->GetChildModel(_wing);
m_pPlayerModel->RemoveChildModel(_wing, false);
CECModel* pWing2 = m_pPlayerModel->GetChildModel(_wing2);
m_pPlayerModel->RemoveChildModel(_wing2, false);
if (m_wingType == WINGTYPE_FLYSWORD || m_wingType == WINGTYPE_WING) {
if (pWing) {
pModel->AddChildModel(
_wing,
false,
UsingWing() ? "HH_chibang" : "HH_feijian",
pWing,
UsingWing() ? "CC_chibang" : "CC_feijian");
}
} else if (m_wingType == WINGTYPE_DOUBLEWHEEL) {
if (pWing) {
pModel->AddChildModel(
_wing,
false,
_hh_left_foot,
pWing,
_cc_fenghuolun);
}
if (pWing2) {
pModel->AddChildModel(
_wing2,
false,
_hh_right_foot,
pWing2,
_cc_fenghuolun);
}
}
ShowWing(IsFlying());
// sync the effect
typedef abase::hash_map<AString, GFXRECORD>::iterator GFXIter;
for(GFXIter i=m_GfxRecords.begin();i!=m_GfxRecords.end();++i)
{
const GFXRECORD& rec = i->second;
m_pPlayerModel->RemoveGfx(rec.strPath, rec.strHook);
if (!pModel->GetGfx(rec.strPath, rec.strHook)){
pModel->PlayGfx(rec.strPath, rec.strHook, rec.fScale);
}
}
}
// change the target
if (m_pPlayerModel != pModel){
ClearShowExtendStates();
if (IsMajorModel(m_pPlayerModel)){
RemoveEquipGfx();
}
DetachWeapon();
m_pPlayerModel = pModel;
AttachWeapon();
if (pModel != NULL){
ShowExtendStates(0, m_aExtStates, OBJECT_EXT_STATE_COUNT);
}
if (IsMajorModel(m_pPlayerModel)){
AddEquipGfx();
}
RecreateActionController();
RecreateBodyController();
}
// different ground mode
SetUseGroundNormal( ShouldUseGroundNormalForCurrentShapeModel() );
PlayAction(GetMoveStandAction(false, IsFighting()), true);
// restore the attach state
if (iBuddyId)
{
if( !bHangerOn )
AttachBuddy(iBuddyId);
else
{
CECPlayer* pBuddy = m_pPlayerMan->GetPlayer(iBuddyId);
if( pBuddy ) pBuddy->AttachBuddy(m_PlayerInfo.cid);
}
}
ScaleBody(m_fScaleBySkill);
// 战车升级光效,此时模型已记载,gfx可播放。
CECHostPlayer* pHost = g_pGame->GetGameRun()->GetHostPlayer();
if (IsHostPlayer() && pHost && pHost->GetBattleInfo().IsChariotWar())
{
CChariot* pChariot = pHost->GetChariot();
if (pChariot && pChariot->IsUpdateState())
{
PlayGfx(res_GFXFile(RES_GFX_LEVELUP), NULL, 4.0, PLAYERMODEL_TYPEALL);
BubbleText(BUBBLE_LEVELUP, 0);
pChariot->UpdateState(0,0);// 恢复战车升级标志
}
}
}
void CECPlayer::AttachBuddy(int iBuddy)
{
if (!GetMajorModel())
return;
if (GetGender() != GENDER_MALE)
return;
CECPlayer* pBuddy = m_pPlayerMan->GetPlayer(iBuddy);
if (!pBuddy || pBuddy->GetGender() != GENDER_FEMALE)
return;
CECModel* pBuddyModel = pBuddy->GetPlayerModel();
if (!pBuddyModel) return;
if (m_pPetModel)
{
if (!m_pPetModel->AddChildModel(_hanger_ride2, false, _hh_ride, pBuddyModel, _cc_ride2))
return;
A3DSkinModelHanger* pHanger = m_pPetModel->GetA3DSkinModel()->GetSkinModelHanger(_hanger_ride2);
if (pHanger) pHanger->SetOffsetMat(a3d_Translate(0, 0, 0));
pHanger = m_pPetModel->GetA3DSkinModel()->GetSkinModelHanger(_hanger_ride);
if (pHanger) pHanger->SetOffsetMat(a3d_Translate(0, 0, -0.1f));
m_AttachMode = enumAttachRideOnPet;
m_bHangerOn = false;
m_iBuddyId = pBuddy->m_PlayerInfo.cid;
pBuddy->m_AttachMode = enumAttachRideOnPet;
pBuddy->m_bHangerOn = true;
pBuddy->m_iBuddyId = m_PlayerInfo.cid;
}
else if (IsShapeChanged())
{
if (!m_pPlayerModel || !m_pPlayerModel->AddChildModel(_hanger_ride, false, _hh_ride, pBuddyModel, _cc_ride2))
return;
A3DSkinModelHanger* pHanger = m_pPlayerModel->GetA3DSkinModel()->GetSkinModelHanger(_hanger_ride);
if (pHanger) pHanger->SetOffsetMat(a3d_Translate(0, 0, 0.0f));
m_AttachMode = enumAttachRideOnPlayer;
m_bHangerOn = false;
m_iBuddyId = pBuddy->m_PlayerInfo.cid;
pBuddy->m_AttachMode = enumAttachRideOnPlayer;
pBuddy->m_bHangerOn = true;
pBuddy->m_iBuddyId = m_PlayerInfo.cid;
}
else
{
if (!GetMajorModel()->AddChildModel(_hanger_hug, false, _hh_bind, pBuddyModel, _cc_bind))
return;
m_AttachMode = enumAttachHugPlayer;
m_bHangerOn = false;
m_iBuddyId = pBuddy->m_PlayerInfo.cid;
pBuddy->m_AttachMode = enumAttachHugPlayer;
pBuddy->m_bHangerOn = true;
pBuddy->m_iBuddyId = m_PlayerInfo.cid;
}
m_idCandBuddy = 0;
m_bCandHangerOn = false;
pBuddy->m_idCandBuddy = 0;
pBuddy->m_bCandHangerOn = false;
pBuddy->SetPos(GetPos());
PlayAction(GetMoveStandAction(false, IsFighting()), true);
}
void CECPlayer::DetachBuddy(CECPlayer* pBuddy, bool bResetData)
{
if (m_AttachMode == enumAttachNone)
return;
if (m_bHangerOn)
{
if (!pBuddy) pBuddy = m_pPlayerMan->GetPlayer(m_iBuddyId);
if (pBuddy)
pBuddy->DetachBuddy(this, bResetData);
else
{
assert(false);
if( bResetData )
{
m_AttachMode = enumAttachNone;
m_bHangerOn = false;
m_iBuddyId = 0;
}
}
}
else
{
if (!pBuddy) pBuddy = m_pPlayerMan->GetPlayer(m_iBuddyId);
if (m_AttachMode == enumAttachRideOnPlayer)
{
if(m_pPlayerModel) m_pPlayerModel->RemoveChildModel(_hanger_ride, false);
}
else if (m_AttachMode == enumAttachHugPlayer)
{
if(m_pPlayerModel) m_pPlayerModel->RemoveChildModel(_hanger_hug, false);
}
else if (m_AttachMode == enumAttachRideOnPet)
{
if (m_pPetModel)
{
A3DSkinModelHanger* pHanger = m_pPetModel->GetA3DSkinModel()->GetSkinModelHanger(_hanger_ride);
if (pHanger) pHanger->SetOffsetMat(a3d_IdentityMatrix());
m_pPetModel->RemoveChildModel(_hanger_ride2, false);
}
}
if( bResetData )
{
m_AttachMode = enumAttachNone;
m_bHangerOn = false;
m_iBuddyId = 0;
}
if (pBuddy)
{
if( bResetData )
{
pBuddy->m_AttachMode = enumAttachNone;
pBuddy->m_bHangerOn = false;
pBuddy->m_iBuddyId = 0;
}
pBuddy->SetPos(pBuddy->GetPos());
pBuddy->ChangeModelMoveDirAndUp(pBuddy->GetDir(), pBuddy->GetUp());
pBuddy->PlayAction(GetMoveStandAction(false, IsFighting()), true);
}
PlayAction(GetMoveStandAction(IsPlayingMoveAction(), IsFighting()), true);
}
}
// Load player's skeleton
bool CECPlayer::LoadPlayerSkeleton(bool bAtOnce)
{
// remove disabled equipments before loading
int aEnabledEquips[SIZE_ALL_EQUIPIVTR];
for (__int64 i=0; i < SIZE_ALL_EQUIPIVTR; i++)
{
aEnabledEquips[i] =
((1 << i) & m_i64EquipDisabled) == 1 ? 0 : m_aEquips[i];
}
const char* szPetPath = NULL;
if (m_RidingPet.id)
szPetPath = GetRidingPetFileName(m_RidingPet.id);
EC_PLAYERLOADRESULT Ret;
int aEquips[IVTRSIZE_EQUIPPACK];
__int64 EquipMask = 0;
if (aEnabledEquips[EQUIPIVTR_WEAPON] > 0)
EquipMask |= 1 << EQUIPIVTR_WEAPON;
if (aEnabledEquips[EQUIPIVTR_FASHION_WEAPON] > 0)
EquipMask |= 1 << EQUIPIVTR_FASHION_WEAPON;
memcpy(aEquips, aEnabledEquips, sizeof(aEquips));
DecideWeaponLoad(aEquips, EquipMask);
if (bAtOnce || !IsLoadThreadReady())
{
// Under normal circumstances, only HostPlayer can reach here
if (!LoadPlayerModel(m_iProfession, m_iGender, m_CustomizeData.bodyID, aEquips, szPetPath, Ret,false,false))
{
a_LogOutput(1, "CECPlayer::Init, failed to call LoadPlayerModel() !");
return false;
}
SetPlayerLoadedResult(Ret);
if(IsShapeChanged() && !QueueLoadDummyModel(m_iShape, true))
{
// ignore the dummy model loading failure
a_LogOutput(1, "CECPlayer::Init, failed to call QueueLoadDummyModel() !");
}
}
else
{
int iType = m_iCID == OCID_HOST_NAVIGATER ? MTL_ECM_HOST_NAVIGATER : MTL_ECM_PLAYER;
QueueECModelForLoad(
iType,
m_PlayerInfo.cid,
m_dwBornStamp,
GetPos(),
szPetPath,
m_iProfession,
m_iGender,
m_CustomizeData.bodyID,
aEquips);
if(IsShapeChanged())
QueueLoadDummyModel(m_iShape, false);
}
return true;
}
bool CECPlayer::QueueLoadEquips(const int* pEquips, __int64 Mask, bool bAtOnce)
{
if (bAtOnce || !IsLoadThreadReady())
{
EquipsLoadResult Ret;
if (!LoadPlayerEquips(m_iProfession, m_iGender, Mask, pEquips, Ret))
return false;
SetEquipsLoadedResult(Ret, true);
}
else
{
QueueECModelForLoad(
MTL_ECM_PLAYER_EQUIP,
m_PlayerInfo.cid,
m_dwBornStamp,
GetPos(),
NULL,
m_iProfession,
m_iGender,
Mask,
const_cast<int*>(pEquips));
}
return true;
}
bool CECPlayer::QueueLoadPetModel(const char* szPetPath, bool bAtOnce)
{
if (bAtOnce || !IsLoadThreadReady())
{
CECModel* pPetModel = NULL;
if (!LoadPetModel(szPetPath, &pPetModel) || !pPetModel)
return false;
if (!SetPetLoadResult(pPetModel))
{
A3DRELEASE(pPetModel);
return false;
}
}
else
{
QueueECModelForLoad(MTL_ECM_PET, m_PlayerInfo.cid, m_dwBornStamp, GetPos(), szPetPath);
}
return true;
}
bool CECPlayer::QueueLoadFace(bool bAtOnce)
{
if( bAtOnce || !IsLoadThreadReady() )
{
EC_PLAYERLOADRESULT Ret;
memset(&Ret, 0, sizeof(Ret));
Ret.dwValidMask |= PLAYERLOADRESULT_PLAYERFACE;
Ret.pFaceModel = ThreadLoadFaceModel(m_iProfession, m_iGender, m_CustomizeData.bodyID);
if( !Ret.pFaceModel )
return false;
if( !SetPlayerLoadedResult(Ret) )
{
A3DRELEASE(Ret.pFaceModel);
return false;
}
}
else
{
QueueECModelForLoad(MTL_ECM_PLAYER_FACE, m_PlayerInfo.cid, m_dwBornStamp, GetPos(), NULL,
m_iProfession, m_iGender, m_CustomizeData.bodyID);
}
return true;
}
bool CECPlayer::QueueLoadDummyModel(int iShape, bool bAtOnce)
{
int iShapeType = PLAYERMODEL_GETTYPE(iShape);
int iShapeID = PLAYERMODEL_GETID(iShape);
// ensure this function only used in dummy model loading
ASSERT(iShapeType != PLAYERMODEL_MAJOR && iShapeType < PLAYERMODEL_MAX);
// If model already loaded, use it directly.
if(m_aShapeID[iShapeType] == iShapeID && m_pModels[iShapeType])
{
ApplyShapeModelChange(m_pModels[iShapeType]);
return true;
}
// try to load a new dummy model
if (bAtOnce || !IsLoadThreadReady())
{
CECModel* pDummyModel = NULL;
if (!LoadDummyModel(iShape, &pDummyModel) || !pDummyModel)
return false;
if (!SetDummyLoadResult(iShape, pDummyModel))
{
A3DRELEASE(pDummyModel);
return false;
}
}
else
{
int iType = (m_iCID == OCID_HOST_NAVIGATER) ? MTL_ECM_HOST_NAVIGATER_DUMMY:MTL_ECM_PLAYER_DUMMY;
QueueECModelForLoad(
iType,
m_PlayerInfo.cid,
m_dwBornStamp,
GetPos(),
NULL,
iShape);
}
return true;
}
void CECPlayer::RideOnPet(int id, unsigned short color)
{
m_CandPet.id = id;
m_CandPet.color = color;
m_RidingPet.id = id;
m_RidingPet.color = color;
}
void CECPlayer::GetOffPet(bool bResetData)
{
int iBuddyId = 0;
m_CandPet.Reset();
SetNamePos(A3DVECTOR3(0.0f));
if (m_AttachMode != enumAttachNone)
{
iBuddyId = m_iBuddyId;
DetachBuddy(NULL, bResetData);
}
if (m_pPetModel)
{
m_pPetModel->RemoveChildModel(_hanger_ride, false);
A3DRELEASE(m_pPetModel);
}
if( bResetData )
m_RidingPet.Reset();
// Re-calculate player's AABB
CalcPlayerAABB();
SetUseGroundNormal(ShouldUseGroundNormalForCurrentShapeModel());
SetPos(GetPos());
if (iBuddyId)
AttachBuddy(iBuddyId);
else
PlayAction(GetMoveStandAction(false, IsFighting()), true);
}
#define SET_SKIN_SHOW_MASK(index, b) \
{ \
dwSkinShowMask |= (1 << (index)); \
if (b) \
dwSkinShowFlag |= (1 << (index)); \
else \
dwSkinShowFlag &= ~(1 << (index)); \
}
inline void _get_skin_show_mask(
DWORD& dwChangeMask,
int& nLowerMethod,
DWORD& dwSkinShowMask,
DWORD& dwSkinShowFlag,
bool bFashion)
{
for (int i = enumSkinShowUpperBody; i <= enumSkinShowUpperLowerAndWrist; i++)
{
if ((1 << i) & dwChangeMask)
{
switch (i)
{
case enumSkinShowUpperBody:
if (bFashion)
{
SET_SKIN_SHOW_MASK(SKIN_FASHION_WRIST_INDEX, true)
SET_SKIN_SHOW_MASK(SKIN_FASHION_LOWER_INDEX, true)
if (nLowerMethod == enumSkinShowLowerAndFoot)
SET_SKIN_SHOW_MASK(SKIN_FASHION_FOOT_INDEX, false)
else
SET_SKIN_SHOW_MASK(SKIN_FASHION_FOOT_INDEX, true)
}
else
{
SET_SKIN_SHOW_MASK(SKIN_WRIST_INDEX, true)
SET_SKIN_SHOW_MASK(SKIN_LOWER_INDEX, true)
if (nLowerMethod == enumSkinShowLowerAndFoot)
SET_SKIN_SHOW_MASK(SKIN_FOOT_INDEX, false)
else
SET_SKIN_SHOW_MASK(SKIN_FOOT_INDEX, true)
}
break;
case enumSkinShowWrist:
break;
case enumSkinShowLowerBody:
nLowerMethod = enumSkinShowLowerBody;
if (bFashion)
SET_SKIN_SHOW_MASK(SKIN_FASHION_FOOT_INDEX, true)
else
SET_SKIN_SHOW_MASK(SKIN_FOOT_INDEX, true)
break;
case enumSkinShowFoot:
break;
case enumSkinShowUpperAndLower:
if (bFashion)
{
SET_SKIN_SHOW_MASK(SKIN_FASHION_WRIST_INDEX, true)
SET_SKIN_SHOW_MASK(SKIN_FASHION_LOWER_INDEX, false)
SET_SKIN_SHOW_MASK(SKIN_FASHION_FOOT_INDEX, true)
}
else
{
SET_SKIN_SHOW_MASK(SKIN_WRIST_INDEX, true)
SET_SKIN_SHOW_MASK(SKIN_LOWER_INDEX, false)
SET_SKIN_SHOW_MASK(SKIN_FOOT_INDEX, true)
}
break;
case enumSkinShowUpperAndWrist:
if (bFashion)
{
SET_SKIN_SHOW_MASK(SKIN_FASHION_WRIST_INDEX, false)
SET_SKIN_SHOW_MASK(SKIN_FASHION_LOWER_INDEX, true)
if (nLowerMethod == enumSkinShowLowerAndFoot)
SET_SKIN_SHOW_MASK(SKIN_FASHION_FOOT_INDEX, false)
else
SET_SKIN_SHOW_MASK(SKIN_FASHION_FOOT_INDEX, true)
}
else
{
SET_SKIN_SHOW_MASK(SKIN_WRIST_INDEX, false)
SET_SKIN_SHOW_MASK(SKIN_LOWER_INDEX, true)
if (nLowerMethod == enumSkinShowLowerAndFoot)
SET_SKIN_SHOW_MASK(SKIN_FOOT_INDEX, false)
else
SET_SKIN_SHOW_MASK(SKIN_FOOT_INDEX, true)
}
break;
case enumSkinShowLowerAndFoot:
nLowerMethod = enumSkinShowLowerAndFoot;
if (bFashion)
SET_SKIN_SHOW_MASK(SKIN_FASHION_FOOT_INDEX, false)
else
SET_SKIN_SHOW_MASK(SKIN_FOOT_INDEX, false)
break;
case enumSkinShowUpperLowerAndWrist:
if (bFashion)
{
SET_SKIN_SHOW_MASK(SKIN_FASHION_WRIST_INDEX, false)
SET_SKIN_SHOW_MASK(SKIN_FASHION_LOWER_INDEX, false)
SET_SKIN_SHOW_MASK(SKIN_FASHION_FOOT_INDEX, true)
}
else
{
SET_SKIN_SHOW_MASK(SKIN_WRIST_INDEX, false)
SET_SKIN_SHOW_MASK(SKIN_LOWER_INDEX, false)
SET_SKIN_SHOW_MASK(SKIN_FOOT_INDEX, true)
}
break;
}
}
}
}
bool CECPlayer::SetEquipsLoadedResult(EquipsLoadResult& Result, bool bUpdateAtOnce)
{
if (!GetMajorModel())
return false;
A3DSkinModel* pA3DModel = GetMajorModel()->GetA3DSkinModel();
DWORD dwSkinShowMask = 0, dwSkinShowFlag = 0;
_get_skin_show_mask(Result.dwShowMask, m_nLowerEquipMethod, dwSkinShowMask, dwSkinShowFlag, false);
_get_skin_show_mask(Result.dwFashionShowMask, m_nLowerFashionEquipMethod, dwSkinShowMask, dwSkinShowFlag, true);
if( !ShouldUseClothedModel() )
{
for (int i = 0; i < NUM_SKIN_INDEX; i++)
{
if( i == SKIN_HEAD_INDEX || i == SKIN_BODY_INDEX )
continue;
if( Result.aSkins[i][0] ) g_pGame->ReleaseA3DSkin(Result.aSkins[i][0]);
if( Result.aSkins[i][1] ) g_pGame->ReleaseA3DSkin(Result.aSkins[i][1]);
if( Result.aSkins[i][2] ) g_pGame->ReleaseA3DSkin(Result.aSkins[i][2]);
Result.aSkins[i][0] = Result.aSkins[i][1] = Result.aSkins[i][2] = NULL;
}
}
else
{
for (int i = 0; i < NUM_SKIN_INDEX; i++)
{
DWORD dwMask = (1 << i);
if (dwMask & Result.dwSkinChangeMask)
{
ReplaceCurSkin(i, NULL);
g_pGame->ReleaseA3DSkin(m_aSkins[i][0]);
g_pGame->ReleaseA3DSkin(m_aSkins[i][1]);
g_pGame->ReleaseA3DSkin(m_aSkins[i][2]);
m_aSkins[i][0] = Result.aSkins[i][0];
m_aSkins[i][1] = Result.aSkins[i][1];
m_aSkins[i][2] = Result.aSkins[i][2];
for (int j = 0; j < 3; j++)
{
if (NULL != m_aSkins[i][j])
m_aSkins[i][j]->SetAlphaSortWeight(_skin_alpha_map[i]);
}
}
if (dwMask & dwSkinShowMask)
pA3DModel->ShowSkin(i, (dwMask & dwSkinShowFlag) != 0);
}
}
if (bUpdateAtOnce)
UpdateCurSkins();
if (Result.bWingChanged)
{
m_wingType = Result.wingType;
m_pPlayerModel->RemoveChildModel(_wing);
m_pPlayerModel->RemoveChildModel(_wing2);
if (m_wingType == WINGTYPE_FLYSWORD || m_wingType == WINGTYPE_WING) {
if (Result.pWing) {
m_pPlayerModel->AddChildModel(
_wing,
false,
UsingWing() ? "HH_chibang" : "HH_feijian",
Result.pWing,
UsingWing() ? "CC_chibang" : "CC_feijian");
}
} else if (m_wingType == WINGTYPE_DOUBLEWHEEL) {
if (Result.pWing) {
m_pPlayerModel->AddChildModel(
_wing,
false,
_hh_left_foot,
Result.pWing,
_cc_fenghuolun);
}
if (Result.pWing2) {
m_pPlayerModel->AddChildModel(
_wing2,
false,
_hh_right_foot,
Result.pWing2,
_cc_fenghuolun);
}
}
if (Result.pWing && Result.pWing->GetA3DSkinModel())
{
Result.pWing->GetA3DSkinModel()->SetAlphaSortID(m_PlayerInfo.cid);
Result.pWing->GetA3DSkinModel()->SetAlphaSortWeight(SKIN_SORT_WING);
}
if (Result.pWing2 && Result.pWing2->GetA3DSkinModel())
{
Result.pWing2->GetA3DSkinModel()->SetAlphaSortID(m_PlayerInfo.cid);
Result.pWing2->GetA3DSkinModel()->SetAlphaSortWeight(SKIN_SORT_WING);
}
if (Result.pWing || Result.pWing2)
{
// HACK: ensure weapon added after wings to avoid alpha sort bug
if(!Result.bWeaponChanged && !Result.bFashionWeaponChanged){
DetachWeapon();
}
}
}
ShowWing(IsFlying());
if (Result.bWeaponChanged || Result.bFashionWeaponChanged)
{
if (Result.bFashionWeaponChanged)
{
m_iFashionWeaponType = Result.uFashionAttackType;
m_strLeftFashionWeapon = Result.strLeftFashionWeapon;
m_strRightFashionWeapon = Result.strRightFashionWeapon;
}
if (Result.bWeaponChanged)
{
m_uAttackType = Result.uAttackType;
m_strLeftWeapon = Result.strLeftWeapon;
m_strRightWeapon = Result.strRightWeapon;
}
SetWeaponResult(Result);
}else if (Result.bWingChanged && (Result.pWing || Result.pWing2)){
AttachWeapon();
}
int idFullSuite = SearchFullSuite();
if( idFullSuite == 0 )
{
RemoveFullSuiteGFX();
m_idFullSuite = 0;
}
else if( idFullSuite != m_idFullSuite )
{
RemoveFullSuiteGFX();
m_idFullSuite = idFullSuite;
AddFullSuiteGFX();
}
if( Result.stoneUpperBody != 0xff && m_stoneUpperBody != Result.stoneUpperBody )
{
RemoveUpperBodyStones();
m_stoneUpperBody = Result.stoneUpperBody;
AddUpperBodyStones();
}
if( Result.stoneWrist != 0x00ff && m_stoneWrist != Result.stoneWrist )
{
RemoveWristStones();
m_stoneWrist = Result.stoneWrist;
AddWristStones();
}
if( Result.stoneLowerBody != 0x00ff && m_stoneLowerBody != Result.stoneLowerBody )
{
RemoveLowerBodyStones();
m_stoneLowerBody = Result.stoneLowerBody;
AddLowerBodyStones();
}
if( Result.stoneFoot != 0x00ff && m_stoneFoot != Result.stoneFoot )
{
RemoveFootStones();
m_stoneFoot = Result.stoneFoot;
AddFootStones();
}
if( Result.stoneWeapon != 0x00ff )
{
m_stoneWeaponShown = 0;
m_stoneWeapon = Result.stoneWeapon;
AddWeaponStones();
}else if (IsShowFashionWeapon()){
m_stoneWeapon = 0;
m_stoneWeaponShown = 0;
}
ScaleChildModel();
return true;
}
void CECPlayer::SetRidingPetColor(unsigned short clr)
{
m_RidingPet.color = clr;
A3DCOLOR clrModel;
if (!m_RidingPet.GetColor(clrModel))
clrModel = RIDINGPET::GetDefaultColor();
SetRidingPetColor(m_pPetModel, clrModel);
}
void CECPlayer::SetRidingPetColor(CECModel *pModel, A3DCOLOR clr)
{
// 设置修改模型上的颜色
while (true)
{
if (!pModel) break;
A3DSkinModel *pSkinModel = pModel->GetA3DSkinModel();
if (!pSkinModel) break;
for (int i = 0; i < pSkinModel->GetSkinNum(); ++ i)
{
A3DSkin *pSkin = pSkinModel->GetA3DSkin(i);
if (!pSkin) continue;
for(int idTex=0; idTex<pSkin->GetTextureNum(); idTex ++)
{
A3DTexture * pTex = pSkin->GetTexture(idTex);
if( pTex && pTex->IsShaderTexture() )
{
A3DShader * pShader = (A3DShader *) pTex;
if (strstr(pShader->GetMapFile(), "rewu.sdr"))
pShader->GetGeneralProps().dwTFactor = clr;
}
}
}
break;
}
}
bool CECPlayer::SetPetLoadResult(CECModel* pPetModel)
{
ASSERT(pPetModel);
if (!m_RidingPet.id || !GetMajorModel() || m_CandPet.id || !pPetModel)
return false;
if (m_pPetModel)
{
RIDINGPET pet = m_RidingPet;
GetOffPet();
m_RidingPet = pet;
}
const A3DVECTOR3 vCurPos = GetPos();
m_aabbServer.Center = vCurPos + A3DVECTOR3(0.0f, m_aabbServer.Extents.y, 0.0f);
m_aabbServer.CompleteMinsMaxs();
m_pPetModel = pPetModel;
// 将宠物颜色设置到模型上
SetRidingPetColor(m_RidingPet.color);
SetUseGroundNormal(true);
m_pPetModel->SetAffectedByParent(false);
m_pPetModel->SetPos(vCurPos);
m_pPetModel->SetDirAndUp(GetDir(), GetUp());
int iIndex;
A3DSkeletonHook* pHook = GetMajorModel()->GetA3DSkinModel()->GetSkeleton()->GetHook(_cc_ride, &iIndex);
if (pHook) pHook->SetFixDirFlag(true);
int iBuddyId = m_iBuddyId;
if (m_AttachMode != enumAttachNone)
DetachBuddy();
m_pPetModel->AddChildModel(_hanger_ride, false, _hh_ride, GetMajorModel(), _cc_ride);
m_pPetModel->GetA3DSkinModel()->Update(0);
if (iBuddyId)
AttachBuddy(iBuddyId);
else
PlayAction(GetMoveStandAction(false, IsFighting()), true);
return true;
}
// Set loaded model to player object, this function is used in multithread loading process
bool CECPlayer::SetPlayerLoadedResult(EC_PLAYERLOADRESULT& Ret)
{
int i;
if(!ShouldUseModel())
return false;
// model loading
if(Ret.dwValidMask & PLAYERLOADRESULT_PLAYERMODEL)
{
if (GetMajorModel())
return false;
// set the major model
m_pPlayerModel = Ret.pPlayerModel;
m_pPlayerModel->SetAffectedByParent(false);
m_pPlayerModel->GetA3DSkinModel()->SetInheritTransFlag(false);
m_pModels[PLAYERMODEL_MAJOR] = m_pPlayerModel;
m_GfxRecords.clear();
RecreateActionController();
RecreateBodyController();
}
// dummy model loading
if(Ret.dwValidMask & PLAYERLOADRESULT_DUMMYMODEL)
{
if( !SetDummyLoadResult(Ret.iShape, Ret.pDummyModel) )
A3DRELEASE(Ret.pDummyModel);
}
// pet model loading
if(Ret.dwValidMask & PLAYERLOADRESULT_PETMODEL)
{
if (Ret.pPetModel && !SetPetLoadResult(Ret.pPetModel))
A3DRELEASE(Ret.pPetModel);
}
// player model loading
if(Ret.dwValidMask & PLAYERLOADRESULT_PLAYERMODEL)
{
if (!m_pPetModel)
{
m_pPlayerModel->SetPos(GetPos());
m_pPlayerModel->SetDirAndUp(GetDir(), GetUp());
m_pPlayerModel->GetA3DSkinModel()->Update(0);
SetUseGroundNormal(ShouldUseGroundNormalForCurrentShapeModel());
// make the player stand at beginning
PlayAction(ACT_STAND, true, 0);
}
for (i = 0; i < SIZE_ALL_EQUIPIVTR; i++)
{
if (m_aEquips[i] > 0 && IsShownEquip(i) && GetMajorModel())
{
DWORD dwRealID = GetRealElementID(i, m_aEquips[i]);
GetMajorModel()->OnScriptChangeEquip(dwRealID, 1, false);
}
}
}
// equips model loading
if(Ret.dwValidMask & PLAYERLOADRESULT_EQUIPMODEL)
{
bool bOnlyEquip = (0 == (Ret.dwValidMask & (~PLAYERLOADRESULT_EQUIPMODEL)));
if(!SetEquipsLoadedResult(Ret.EquipResult, bOnlyEquip) && bOnlyEquip)
{
return false;
}
}
// player model loading
if(Ret.dwValidMask & PLAYERLOADRESULT_PLAYERMODEL)
{
ReplaceCurSkin(SKIN_BODY_INDEX, NULL);
ReplaceCurSkin(SKIN_HEAD_INDEX, NULL);
for (i = 0; i < 3; i++)
{
g_pGame->ReleaseA3DSkin(m_aSkins[SKIN_BODY_INDEX][i]);
g_pGame->ReleaseA3DSkin(m_aSkins[SKIN_HEAD_INDEX][i]);
m_aSkins[SKIN_BODY_INDEX][i] = Ret.EquipResult.aSkins[SKIN_BODY_INDEX][i];
m_aSkins[SKIN_HEAD_INDEX][i] = Ret.EquipResult.aSkins[SKIN_HEAD_INDEX][i];
m_pBodyShader[i] = Ret.pBodyShaders[i];
}
if (ShouldUseFaceModel()){
SetFaceModel(Ret.pFaceModel);
}else{
SetFaceModel(NULL);
A3DRELEASE(Ret.pFaceModel);
}
// Update some customized data
SetBodyColor(m_CustomizeData.colorBody);
UpdateBodyScales();
// Set model's position and orientation
m_pPlayerModel->SetPos(GetPos());
m_pPlayerModel->SetDirAndUp(GetDir(), GetUp());
// Update the transparent level
SetTransparent(GetTransparentLimit());
// Set skin model ID, so same ID can deal with the aphla sort in same space
if (NULL != m_pPlayerModel->GetA3DSkinModel())
{
m_pPlayerModel->GetA3DSkinModel()->SetAlphaSortID(m_PlayerInfo.cid);
m_pPlayerModel->GetA3DSkinModel()->SetAlphaSortWeight(SKIN_SORT_DEFAULT);
}
// Force to update model once completely to avoid rendering error
m_pPlayerModel->SetAutoUpdateFlag(false);
m_pPlayerModel->Tick(1);
m_pPlayerModel->SetAutoUpdateFlag(true);
if( m_pFaceModel ) m_pFaceModel->Tick(1);
m_dwResFlags = RESFG_ALL;
OnAllResourceReady();
UpdateCurSkins();
UpdateGodEvilSprite();
// 被CECMemSimplify重新加载模型时,通知男方重新绑定相依相偎
if( m_iBuddyId )
{
if( m_bHangerOn )
{
CECPlayer* pPlayer = m_pPlayerMan->GetPlayer(m_iBuddyId);
if( pPlayer )
pPlayer->m_idCandBuddy = m_PlayerInfo.cid;
}
else
m_idCandBuddy = m_iBuddyId;
}
}
// 加载玩家的自定义脸数据
if( Ret.dwValidMask & PLAYERLOADRESULT_PLAYERFACE ){
if( !ShouldUseFaceModel() || !GetMajorModel() ){
A3DRELEASE(Ret.pFaceModel);
}else{
SetFaceModel(Ret.pFaceModel);
}
}
return true;
}
void CECPlayer::SetFaceModel(CECFace *pFaceModel){
if (pFaceModel == m_pFaceModel){
return;
}
ReleaseFaceModel();
if (!pFaceModel){
return;
}
m_pFaceModel = pFaceModel;
if (m_bIsChangingFace){
m_pFaceModel->SetFaceData(m_CustomizeData.faceData);
}else{
if( m_CustomizeData.faceData.idFaceTex == 0 && (m_iProfession != PROF_ORC || m_iGender != GENDER_MALE) ){
m_CustomizeData.faceData = *m_pFaceModel->GetFaceData();
m_pFaceModel->UpdateAll();
}else{
m_pFaceModel->SetFaceData(m_CustomizeData.faceData);
}
if (InFashionMode()){
UpdateHairModel(true, m_aEquips[EQUIPIVTR_FASHION_HEAD]);
}else{
UpdateHairModel(true, m_aEquips[EQUIPIVTR_HEAD]);
}
}
AttachFaceModel();
}
void CECPlayer::AttachFaceModel(){
if (!m_pFaceModel){
return;
}
if (m_pFaceModel->GetA3DSkinModel()){
m_pFaceModel->GetA3DSkinModel()->SetAlphaSortID(m_PlayerInfo.cid);
m_pFaceModel->GetA3DSkinModel()->SetAlphaSortWeight(SKIN_SORT_HEAD);
}
if (GetMajorModel()){
m_pFaceModel->SetParent(GetMajorModel()->GetA3DSkinModel());
GetMajorModel()->ShowSkin(SKIN_HEAD_INDEX, false);
if (GetMajorModel()->FindComboModel(m_pFaceModel->GetECModel()) < 0){
GetMajorModel()->AddComboModel(m_pFaceModel->GetECModel());
}
}
}
bool CECPlayer::SetDummyLoadResult(int iShape, CECModel* pModel)
{
int iShapeType = PLAYERMODEL_GETTYPE(iShape);
int iShapeID = PLAYERMODEL_GETID(iShape);
a_LogOutput(1, "CECPlayer::SetDummyLoadResult(iShape=%d)(iShapeType=%d,iShapeID=%d)", iShape, iShapeType, iShapeID);
if (iShapeType == PLAYERMODEL_MAJOR ||
iShapeType < 0 || iShapeType >= PLAYERMODEL_MAX){
a_LogOutput(1, "ApplyShapeModelChange invalid(iShapeType=%d, iShapeID=%d)", iShapeType, iShapeID);
ASSERT(false);
return false;
}
if (iShape != m_iShape){ // 2014-8-4:频繁变身时,资源加载落后于m_iShape变化(后者在处理协议时即修改),此时,丢弃结果
a_LogOutput(1, "ApplyShapeModelChange ignored cause shape mismatch(m_iShape=%d, iShapeType=%d, iShapeID=%d)", m_iShape, iShapeType, iShapeID);
return false;
}
CECModel* pOldModel = m_pModels[iShapeType];
if(pOldModel != pModel)
{
m_pModels[iShapeType] = pModel;
m_aShapeID[iShapeType] = iShapeID;
if(pModel) pModel->SetAffectedByParent(false);
}
ApplyShapeModelChange(pModel);
if (pOldModel && pOldModel != pModel && pOldModel != GetPlayerModel()){
if (IsLoadThreadReady()){
QueueECModelForRelease(pOldModel);
}else{
pOldModel->Release();
delete pOldModel;
}
}
return true;
}
bool CECPlayer::UpdateGodEvilSprite()
{
// 简单模型不显示小精灵
if( !ShouldUseClothedModel())
return false;
// first determine new sprite id.
CECSprite::SPRITE_ID idSprite = CECSprite::SPRITE_NULL;
if( GetBasicProps().iLevel2 >= 20 )
{
switch(GetBasicProps().iLevel2)
{
case 20:
idSprite = CECSprite::SPRITE_GOD1;
break;
case 21:
idSprite = CECSprite::SPRITE_GOD2;
break;
case 22:
idSprite = CECSprite::SPRITE_GOD3;
break;
case 30:
idSprite = CECSprite::SPRITE_EVIL1;
break;
case 31:
idSprite = CECSprite::SPRITE_EVIL2;
break;
case 32:
idSprite = CECSprite::SPRITE_EVIL3;
break;
}
}
if( m_pSprite && idSprite != m_pSprite->GetSpriteID() )
{
// first try to release old ones.
if( m_pSprite )
{
m_pSprite->Release();
delete m_pSprite;
m_pSprite = NULL;
}
}
if( NULL == m_pSprite && idSprite != CECSprite::SPRITE_NULL )
{
m_pSprite = new CECSprite();
if( !m_pSprite->Init(idSprite, this) )
{
m_pSprite->Release();
delete m_pSprite;
m_pSprite = NULL;
a_LogOutput(1, "CECPlayer::UpdateGodEvilSprite(), failed to load sprite!");
}
else
m_pSprite->SetPos(GetPos() + A3DVECTOR3(0.0f, 2.5f, 0.0f));
}
return true;
}
bool CECPlayer::UpdateGoblin()
{
return true;
}
// Render goblin or sprite
void CECPlayer::RenderGoblinOrSprite(CECViewport* pViewport)
{
CECHostPlayer* pHost = g_pGame->GetGameRun()->GetHostPlayer();
if (pHost && pHost->GetBattleInfo().IsChariotWar()){
return; // 战车战场里不显示精灵
}
if(m_pGoblin && m_pSprite)
{
if( IsFighting())
{
m_pGoblin->SetTransparent(0.0f);
m_pGoblin->Render(pViewport);
}
else
{
if(m_bRenderGoblin)
m_pGoblin->Render(pViewport);
else
m_pSprite->Render(pViewport);
}
}
else if(m_pGoblin)
{
m_GoblinRenderCnt.Reset();
m_pGoblin->SetTransparent(0.0f);
m_pGoblin->Render(pViewport);
}
else if(m_pSprite)
{
m_GoblinRenderCnt.Reset();
m_pSprite->SetTransparent(0.0f);
m_pSprite->Render(pViewport);
}
}
inline void _fade_out_gfx(A3DGFXEx*& pGfx, float fDeltaTime)
{
if (!pGfx) return;
if (pGfx->GetState() != ST_STOP)
{
float fAlpha = pGfx->GetAlpha();
fAlpha -= fDeltaTime;
if (fAlpha <= 0)
{
pGfx->Stop();
// g_pGame->GetA3DGFXExMan()->CacheReleasedGfx(pGfx);
g_pGame->GetGFXCaster()->ReleaseGFXEx(pGfx);
pGfx = NULL;
}
else
pGfx->SetAlpha(fAlpha);
}
else
{
// g_pGame->GetA3DGFXExMan()->CacheReleasedGfx(pGfx);
g_pGame->GetGFXCaster()->ReleaseGFXEx(pGfx);
pGfx = NULL;
}
}
// Tick routine
bool CECPlayer::Tick(DWORD dwDeltaTime)
{
CECObject::Tick(dwDeltaTime);
if (m_pBodyController){
m_pBodyController->Tick(dwDeltaTime);
}
DWORD dwRealTime = g_pGame->GetRealTickTime();
UpdateCurSkins();
UpdateBoothModel();
UpdateBoothBar();
// Update last said words
if (m_pPateLastWords1 && m_pPateLastWords1->GetItemNum())
{
if (m_strLastSayCnt.IncCounter(dwDeltaTime))
{
// Clear string
m_strLastSayCnt.Reset();
m_pPateLastWords1->Clear();
m_pPateLastWords2->Clear();
}
else
{
m_pPateLastWords1->Tick(dwDeltaTime);
m_pPateLastWords2->Tick(dwDeltaTime);
}
}
A3DTerrainWater* pWater = g_pGame->GetGameRun()->GetWorld()->GetTerrainWater();
float fDeltaTime = dwDeltaTime / 1000.0f;
A3DVECTOR3 vPos = GetPos();
float fWaterHei = pWater->GetWaterHeight(vPos);
float fGrndHei = g_pGame->GetGameRun()->GetWorld()->GetTerrainHeight(vPos);
float fWaterOff = vPos.y - fWaterHei;
if (fWaterHei > fGrndHei + .3f &&
((fWaterOff > -10.f && fWaterOff <= 0) || (fWaterOff > 0 && fWaterOff < 10.0f && IsFlying())))
{
A3DMATRIX4 mat;
if (pWater->IsUnderWater(g_pGame->GetViewport()->GetA3DCamera()->GetPos()))
vPos.y = fWaterHei - .01f;
else
vPos.y = fWaterHei + .01f;
A3DVECTOR3 vDir = GetDir();
vDir.y = 0;
vDir.Normalize();
mat = a3d_TransformMatrix(vDir, g_vAxisY, vPos);
if (IsPlayerMoving())
{
if (!m_pWaterWaveMove)
m_pWaterWaveMove = g_pGame->GetGFXCaster()->LoadGFXEx(res_GFXFile(RES_GFX_WATER_WAVE_MOVE));
if (m_pWaterWaveMove)
{
if (m_pWaterWaveMove->GetState() == ST_STOP
|| m_pWaterWaveMove->GetAlpha() < 1.0f)
{
m_pWaterWaveMove->SetAlpha(1.0f);
float fSpeed = GetFlySpeed() / GetSwimSpeed();
if (fSpeed > 2.0f) fSpeed = 2.0f;
if (IsFlying()) m_pWaterWaveMove->SetPlaySpeed(fSpeed);
else m_pWaterWaveMove->SetPlaySpeed(1.0f);
m_pWaterWaveMove->Start(true);
}
m_pWaterWaveMove->SetParentTM(mat);
}
_fade_out_gfx(m_pWaterWaveStill, fDeltaTime);
}
else
{
if (!m_pWaterWaveStill)
m_pWaterWaveStill = g_pGame->GetGFXCaster()->LoadGFXEx(res_GFXFile(RES_GFX_WATER_WAVE_STILL));
if (m_pWaterWaveStill)
{
if (m_pWaterWaveStill->GetState() == ST_STOP
|| m_pWaterWaveStill->GetAlpha() < 1.0f)
{
m_pWaterWaveStill->SetAlpha(1.0f);
m_pWaterWaveStill->Start(true);
}
m_pWaterWaveStill->SetParentTM(mat);
}
_fade_out_gfx(m_pWaterWaveMove, fDeltaTime);
}
}
else
{
_fade_out_gfx(m_pWaterWaveStill, fDeltaTime);
_fade_out_gfx(m_pWaterWaveMove, fDeltaTime);
}
bool bFadeAirBubble = true;
bool bFadeSwimBubble = true;
if (!pWater->IsUnderWater(g_pGame->GetViewport()->GetA3DCamera()->GetPos()))
{
if (m_pAirBubble)
{
m_pAirBubble->Stop();
// g_pGame->GetA3DGFXExMan()->CacheReleasedGfx(m_pAirBubble);
g_pGame->GetGFXCaster()->ReleaseGFXEx(m_pAirBubble);
m_pAirBubble = NULL;
}
if (m_pSwimBubble)
{
m_pSwimBubble->Stop();
g_pGame->GetGFXCaster()->ReleaseGFXEx(m_pSwimBubble);
m_pSwimBubble = NULL;
}
bFadeAirBubble = false;
bFadeSwimBubble = false;
}
else if (m_iMoveEnv == MOVEENV_WATER)
{
if (IsPlayerMoving())
{
if (!m_pSwimBubble)
m_pSwimBubble = g_pGame->GetGFXCaster()->LoadGFXEx(res_GFXFile(RES_GFX_SWIM_BUBBLE));
if (m_pSwimBubble)
{
if (m_pSwimBubble->GetState() == ST_STOP
|| m_pSwimBubble->GetAlpha() < 1.0f)
{
m_pSwimBubble->SetAlpha(1.0f);
m_pSwimBubble->Start(true);
}
A3DMATRIX4 mat = GetAbsoluteTM();
A3DVECTOR3 vOff = GetPos() + GetDir() * .8f;
vOff.y += 1.1f;
mat.SetRow(3, vOff);
m_pSwimBubble->SetParentTM(mat);
}
bFadeSwimBubble = false;
}
else
{
if (!m_pAirBubble)
m_pAirBubble = g_pGame->GetGFXCaster()->LoadGFXEx(res_GFXFile(RES_GFX_AIR_BUBBLE));
if (m_pAirBubble)
{
if (m_pAirBubble->GetState() == ST_STOP
|| m_pAirBubble->GetAlpha() < 1.0f)
{
m_pAirBubble->SetAlpha(1.0f);
m_pAirBubble->Start(true);
}
A3DMATRIX4 mat = GetAbsoluteTM();
A3DVECTOR3 vOff = GetPos() + GetDir() * .1f;
vOff.y += 1.6f;
mat.SetRow(3, vOff);
m_pAirBubble->SetParentTM(mat);
}
bFadeAirBubble = false;
}
}
if (bFadeAirBubble) _fade_out_gfx(m_pAirBubble, fDeltaTime);
if (bFadeSwimBubble) _fade_out_gfx(m_pSwimBubble, fDeltaTime);
// Update bubble text
if (m_pBubbleTexts)
m_pBubbleTexts->Tick(dwDeltaTime);
if( m_pvp.iDuelState == DUEL_ST_INDUEL )
{
if (!m_pDuelStateGFX)
m_pDuelStateGFX = g_pGame->GetGFXCaster()->LoadGFXEx(res_GFXFile(RES_GFX_INDUEL));
if (m_pDuelStateGFX)
{
if (m_pDuelStateGFX->GetState() == ST_STOP || m_pDuelStateGFX->GetAlpha() < 1.0f)
{
m_pDuelStateGFX->SetAlpha(1.0f);
m_pDuelStateGFX->Start(true);
}
A3DMATRIX4 mat = GetAbsoluteTM();
m_pDuelStateGFX->SetParentTM(mat);
}
}
else
{
if (m_pDuelStateGFX)
{
m_pDuelStateGFX->Stop();
g_pGame->GetGFXCaster()->ReleaseGFXEx(m_pDuelStateGFX);
m_pDuelStateGFX = NULL;
}
}
if( m_pSprite )
m_pSprite->Tick(dwDeltaTime);
if( m_pGoblin )
m_pGoblin->Tick(dwDeltaTime);
if (m_idCandBuddy) AttachBuddy(m_idCandBuddy);
if (m_CandPet.id && GetMajorModel())
{
const char* szPetPath = GetRidingPetFileName(m_CandPet.id);
QueueLoadPetModel(szPetPath, false);
m_CandPet.Reset();
}
// Update render goblin counter
if(m_pGoblin && m_pSprite)
{
if(m_GoblinRenderCnt.IncCounter(dwDeltaTime))
{
m_GoblinRenderCnt.Reset();
if(m_bRenderGoblin)
m_pSprite->SetTransparent(1.0f);
else
m_pGoblin->SetTransparent(1.0f);
m_bRenderGoblin = !m_bRenderGoblin;
}
else
{
int iRenderCnt = (int)m_GoblinRenderCnt.GetCounter();
if(iRenderCnt < 5000 || iRenderCnt > 25000)
{
float fTransparent = iRenderCnt<5000 ? (1.0f - (float)iRenderCnt/5000.0f) : (float)(iRenderCnt - 25000)/5000.0f;
if(m_bRenderGoblin)
m_pGoblin->SetTransparent(fTransparent);
else
m_pSprite->SetTransparent(fTransparent);
}
}
}
DoSkillStateAction();
return true;
}
// Process message
bool CECPlayer::ProcessMessage(const ECMSG& Msg)
{
return true;
}
// Play a damaged effect
void CECPlayer::Damaged(int nDamage, DWORD dwModifier/* 0 */,int skill /* 0 */)
{
if (nDamage == -2)
{
// this message is caused by a help skill, so don't use a wounded action here
if (dwModifier & CECAttackEvent::MOD_IMMUNE)
BubbleText(BUBBLE_IMMUNE, 0);
else if (dwModifier & CECAttackEvent::MOD_NULLITY)
BubbleText(BUBBLE_INVALIDHIT, 0);
else if (dwModifier & CECAttackEvent::MOD_DODGE_DEBUFF)
BubbleText(BUBBLE_DODGE_DEBUFF, 0);
}
else if (nDamage == -1)
{
// when else player hit this player iDamage is -1,
// Just play a wounded action
if(!OnDamaged(skill)){
PlayAction(ACT_WOUNDED);
}
if (dwModifier & CECAttackEvent::MOD_IMMUNE)
BubbleText(BUBBLE_IMMUNE, 0);
else if (dwModifier & CECAttackEvent::MOD_NULLITY)
BubbleText(BUBBLE_INVALIDHIT, 0);
else if (dwModifier & CECAttackEvent::MOD_DODGE_DEBUFF)
BubbleText(BUBBLE_DODGE_DEBUFF, 0);
}
else
{
// Popup a damage decal
if (nDamage > 0)
{
int p1 = 0;
if (dwModifier & CECAttackEvent::MOD_CRITICAL_STRIKE)
p1 |= 0x0001;
if (dwModifier & CECAttackEvent::MOD_RETORT)
p1 |= 0x0002;
if(!OnDamaged(skill))
PlayAction(ACT_WOUNDED);
if (dwModifier & CECAttackEvent::MOD_IMMUNE)
BubbleText(BUBBLE_IMMUNE, 0);
else if (dwModifier & CECAttackEvent::MOD_REBOUND)
BubbleText(BUBBLE_REBOUND, nDamage);
else if (dwModifier & CECAttackEvent::MOD_BEAT_BACK)
BubbleText(BUBBLE_BEAT_BACK, nDamage);
else
BubbleText(BUBBLE_DAMAGE, nDamage, p1);
}
else if (dwModifier & CECAttackEvent::MOD_IMMUNE)
BubbleText(BUBBLE_IMMUNE, 0);
else if (dwModifier & CECAttackEvent::MOD_NULLITY)
BubbleText(BUBBLE_INVALIDHIT, 0);
else
BubbleText(BUBBLE_HITMISSED, 0);
}
}
bool CECPlayer::OnDamaged(int skill)
{
CECAttacksMan* pAtkMan = g_pGame->GetGameRun()->GetWorld()->GetAttacksMan();
AString name1,name2;
for (int i=0;i<sizeof(m_sciStateIDForStateAction)/sizeof(m_sciStateIDForStateAction[0]);i++)
{
if (pAtkMan && pAtkMan->GetSkillStateActionName(skill,m_sciStateIDForStateAction[i],name1,name2))
{
m_SkillIDForStateAction = skill;
return true;
}
}
return false;
}
// Play an attack effect
void CECPlayer::PlayAttackEffect(int idTarget, int idSkill, int skillLevel, int nDamage,
DWORD dwModifier, int nAttackSpeed, int* piAttackTime/* NULL */, int nSection)
{
if (!IsAllResReady())
return;
if( !idSkill )
{
int idWeapon = IsShapeChanged() ? 0 : GetWeaponID();
int nTimeFly = 10;
if( idWeapon )
{
// 看看是不是远程武器
DATA_TYPE dt;
WEAPON_ESSENCE * pWeapon = (WEAPON_ESSENCE *) g_pGame->GetElementDataMan()->get_data_ptr(idWeapon, ID_SPACE_ESSENCE, dt);
ASSERT(dt == DT_WEAPON_ESSENCE);
if( dt == DT_WEAPON_ESSENCE && pWeapon && pWeapon->require_projectile )
{
nTimeFly = 700;
if( m_aEquips[EQUIPIVTR_PROJECTILE] )
idWeapon = m_aEquips[EQUIPIVTR_PROJECTILE]; // set weapon to the projectile
}
}
if( g_pGame->GetGameRun()->GetWorld()->GetAttacksMan()->FindAttackByAttacker(GetPlayerInfo().cid) )
{
// signal early attack event
ClearComActFlagAllRankNodes(true);
}
// melee attack
CECAttackEvent *pAttack = g_pGame->GetGameRun()->GetWorld()->GetAttacksMan()->AddMeleeAttack(
GetPlayerInfo().cid, idTarget, idWeapon, dwModifier, nDamage, nTimeFly);
if (pAttack)
{
if( !IsDead() && (dwModifier & CECAttackEvent::MOD_RETORT) == 0
&& (dwModifier & CECAttackEvent::MOD_ATTACK_AURA) == 0
&& PlayAttackAction(nAttackSpeed, piAttackTime, &pAttack->m_bSignaled)
&& (dwModifier & CECAttackEvent::MOD_BEAT_BACK) == 0){
}else{
pAttack->m_bSignaled = true;
}
}
}
else
{
if( skillLevel == 0 )
{
if( m_pCurSkill )
skillLevel = m_pCurSkill->GetSkillLevel();
else
skillLevel = 1;
}
CECAttackEvent *pAttack = NULL;
// first try to find if there is already a skill attack event in attackman
CECAttackerEvents attackerEvents = g_pGame->GetGameRun()->GetWorld()->GetAttacksMan()->FindAttackByAttacker(GetPlayerInfo().cid);
if( attackerEvents )
{
if(CECAttackEvent *pAttack = attackerEvents.Find(idSkill, nSection))
{
// 面攻击的非第一次伤害消息
pAttack->AddTarget(idTarget, dwModifier, nDamage);
goto EXIT;
}
else
{
attackerEvents.Signal();
}
}
if(GNET::ElementSkill::IsGoblinSkill(idSkill) &&
GNET::ElementSkill::GetType(idSkill) == 2)
{
pAttack = g_pGame->GetGameRun()->GetWorld()->GetAttacksMan()->AddSkillAttack(
GetPlayerInfo().cid, GetPlayerInfo().cid, idTarget, GetWeaponID(), idSkill, skillLevel, dwModifier, nDamage);
}
else
{
// begin a skill attack
pAttack = g_pGame->GetGameRun()->GetWorld()->GetAttacksMan()->AddSkillAttack(
GetPlayerInfo().cid, m_idCurSkillTarget, idTarget, GetWeaponID(), idSkill, skillLevel, dwModifier, nDamage);
}
if (pAttack)
{
pAttack->SetSkillSection(nSection);
if( !IsDead() && (dwModifier & CECAttackEvent::MOD_RETORT) == 0
&& (dwModifier & CECAttackEvent::MOD_ATTACK_AURA) == 0
&& PlaySkillAttackAction(idSkill, nAttackSpeed,NULL,nSection,&pAttack->m_bSignaled)
&& (dwModifier & CECAttackEvent::MOD_BEAT_BACK) == 0){
}else{
pAttack->m_bSignaled = true;
}
}
EXIT:
// For skill attacking, time is always set to 0
if (piAttackTime)
*piAttackTime = 0;
}
}
// Set absolute position
void CECPlayer::SetPos(const A3DVECTOR3& vPos)
{
CECObject::SetPos(vPos);
m_aabb.Center = vPos + A3DVECTOR3(0.0f, m_aabb.Extents.y, 0.0f);
m_aabb.CompleteMinsMaxs();
m_aabbServer.Center = vPos + A3DVECTOR3(0.0f, m_aabbServer.Extents.y, 0.0f);
m_aabbServer.CompleteMinsMaxs();
if (m_pPetModel)
m_pPetModel->SetPos(vPos);
else if(m_pPlayerModel)
{
m_pPlayerModel->SetPos(vPos);
}
if (m_iBuddyId && !m_bHangerOn)
{
CECPlayer* pBuddy = m_pPlayerMan->GetPlayer(m_iBuddyId);
if (pBuddy)
{
pBuddy->SetPos(vPos);
// Buddy有可能在此之前就Tick了,这里设置Pos后应再TICK一次以确保变换矩阵的正确
if( !m_pPlayerModel && pBuddy->GetPlayerModel() )
pBuddy->GetPlayerModel()->Tick(0);
}
}
// test code ...
/*
if (g_pGame->GetGameRun()->GetGameState() == CECGameRun::GS_GAME)
{
float fHei = g_pGame->GetGameRun()->GetWorld()->GetTerrainHeight(vPos);
if (fHei > vPos.y + 0.001f)
{
g_pGame->RuntimeDebugInfo(0xffffffff, _AL("%f"), fHei - vPos.y);
}
}
*/
}
// Set absolute forward and up direction
void CECPlayer::SetDirAndUp(const A3DVECTOR3& vDir, const A3DVECTOR3& vUp)
{
CECObject::SetDirAndUp(vDir, vUp);
A3DVECTOR3 vNewDir = GetDir();
A3DVECTOR3 vNewUp = GetUp();
if (m_pPetModel)
m_pPetModel->SetDirAndUp(vNewDir, vNewUp);
else if(m_pPlayerModel)
{
m_pPlayerModel->SetDirAndUp(vNewDir, vNewUp);
}
}
bool CECPlayer::SupportCastSkillWhenMove()const{
return m_pActionController != NULL && m_pActionController->SupportCastSkillWhenMove();
}
bool CECPlayer::CanCombineWithMoveForSkill(int idSkill)const{
return m_pActionController != NULL && m_pActionController->CanCombineWithMoveForSkill(idSkill);
}
// 移动、停止移动时调用此函数,用于处理移动攻击中模型朝向和转向
void CECPlayer::StartModelMove(const A3DVECTOR3& vMoveDir, const A3DVECTOR3& vHeadUp, DWORD dwSwitchDirTime){
if (!m_pBodyController){
if (dwSwitchDirTime > 0){
SetDestDirAndUp(vMoveDir, vHeadUp, dwSwitchDirTime);
}else{
SetDirAndUp(vMoveDir, vHeadUp);
}
}else{
if (dwSwitchDirTime > 0){
m_pBodyController->Move(vMoveDir, vHeadUp);
}else{
m_pBodyController->MoveImmediatelyTo(vMoveDir, vHeadUp);
}
}
}
void CECPlayer::StopModelMove(const A3DVECTOR3& vMoveDir, const A3DVECTOR3& vHeadUp, DWORD dwSwitchDirTime){
if (!m_pBodyController){
if (dwSwitchDirTime > 0){
SetDestDirAndUp(vMoveDir, vHeadUp, dwSwitchDirTime);
}else{
SetDirAndUp(vMoveDir, vHeadUp);
}
}else{
m_pBodyController->StopMove(vMoveDir, vHeadUp);
}
}
void CECPlayer::StopModelMove(){
if (m_pBodyController){
m_pBodyController->StopMove();
}
}
void CECPlayer::ChangeModelMoveDirAndUp(const A3DVECTOR3& vMoveDir, const A3DVECTOR3& vHeadUp){
if (!m_pBodyController){
SetDirAndUp(vMoveDir, vHeadUp);
}else{
m_pBodyController->ChangeMoveDirAndUp(vMoveDir, vHeadUp); // 根据当前移动状态,调整移动方向或模型朝向
}
}
void CECPlayer::ChangeModelTargetDirAndUp(const A3DVECTOR3 &vDir, const A3DVECTOR3 &vUp){
if (!m_pBodyController){
SetDirAndUp(vDir, vUp);
}else{
m_pBodyController->ChangeModelTargetDirAndUp(vDir, vUp);
}
}
A3DVECTOR3 CECPlayer::GetModelMoveDir()const{ // 移动时、返回移动朝向,静止时、返回模型朝向
if (!m_pBodyController){
return GetDir();
}else{
return m_pBodyController->GetModelMoveDir();
}
}
bool CECPlayer::PlayNonSkillActionWithName(int iAction, const char* szActName, bool bRestart/* =true */, int nTransTime/* =200 */, bool bNoFx/* =false */, bool *pActFlag/* =NULL */, DWORD dwFlagMode/* =COMACT_FLAG_MODE_NONE */){
return m_pActionController
&& m_pActionController->PlayNonSkillActionWithName(iAction, szActName, bRestart, nTransTime, bNoFx, pActFlag, dwFlagMode);
}
bool CECPlayer::QueueNonSkillActionWithName(int iAction, const char* szActName, int nTransTime/* =200 */, bool bForceStopPrevAct/* =false */, bool bNoFx/* =false */, bool bResetSpeed/* =false */, bool bResetActFlag/* =false */, bool *pNewActFlag/* =NULL */, DWORD dwNewFlagMode/* =COMACT_FLAG_MODE_NONE */){
return m_pActionController
&& m_pActionController->QueueNonSkillActionWithName(iAction, szActName, nTransTime, bForceStopPrevAct, bNoFx, bResetSpeed, bResetActFlag, pNewActFlag, dwNewFlagMode);
}
bool CECPlayer::PlaySkillCastActionWithName(int idSkill, const char *szActName, bool bNoFX/* =false */){
return m_pActionController
&& m_pActionController->PlaySkillCastActionWithName(idSkill, szActName, bNoFX);
}
bool CECPlayer::PlaySkillAttackActionWithName(int idSkill, const char *szActName, bool bNoFX/* =false */, bool *pActFlag/* =NULL */, DWORD dwFlagMode/* =COMACT_FLAG_MODE_NONE */){
return m_pActionController
&& m_pActionController->PlaySkillAttackActionWithName(idSkill, szActName, bNoFX, pActFlag, dwFlagMode);
}
bool CECPlayer::QueueSkillAttackActionWithName(int idSkill, const char *szActName, int nTransTime/* =200 */, bool bNoFX/* =false */, bool bResetSpeed/* =false */, bool bResetActFlag/* =false */, bool *pNewActFlag/* =NULL */, DWORD dwNewFlagMode/* =COMACT_FLAG_MODE_NONE */){
return m_pActionController
&& m_pActionController->QueueSkillAttackActionWithName(idSkill, szActName, nTransTime, bNoFX, bResetSpeed, bResetActFlag, pNewActFlag, dwNewFlagMode);
}
bool CECPlayer::PlayWoundActionWithName(const char* szActName){
return m_pActionController
&& m_pActionController->PlayWoundActionWithName(szActName);
}
void CECPlayer::ClearComActFlagAllRankNodes(bool bSignalCurrent){
if (m_pActionController){
m_pActionController->ClearComActFlagAllRankNodes(bSignalCurrent);
}
}
void CECPlayer::StopChannelAction(){
if (m_pActionController){
m_pActionController->StopChannelAction();
}
}
void CECPlayer::StopSkillCastAction(){
if (m_pActionController){
m_pActionController->StopSkillCastAction();
}
}
void CECPlayer::StopSkillAttackAction(){
if (m_pActionController){
m_pActionController->StopSkillAttackAction();
}
}
bool CECPlayer::IsPlayingAction()const{
return GetLowerBodyAction() != -1;
}
bool CECPlayer::IsPlayingAction(int iAction)const{
return m_pActionController ? m_pActionController->IsPlayingAction(iAction) : false;
}
bool CECPlayer::IsPlayingCastingSkillAction()const{
return m_pActionController ? m_pActionController->IsPlayingCastingSkillAction() : false;
}
bool CECPlayer::IsPlayingMoveAction()const{
return m_pActionController ? m_pActionController->IsPlayingMoveAction() : false;
}
bool CECPlayer::IsPlayingCastingSkillAndMoveActions()const{
return IsPlayingCastingSkillAction() && IsPlayingMoveAction();
}
int CECPlayer::GetLowerBodyAction()const{
return m_pActionController ? m_pActionController->GetLowerBodyAction() : -1;
}
bool CECPlayer::PlayAction(int iAction, bool bRestart/* true */, int iTransTime/* 200 */, bool bQueue/* false */){
return PlayActionWithConfig(iAction, 0, bRestart, iTransTime, bQueue);
}
bool CECPlayer::PlayActionWithConfig(int iAction, int actionConfigID, bool bRestart/* =true */, int iTransTime/* =200 */, bool bQueue/* =false */){
if (iAction < 0 || iAction >= ACT_MAX){
ASSERT(false);
return false;
}
if (actionConfigID > 0){
DATA_TYPE dt(DT_INVALID);
const void *p = g_pGame->GetElementDataMan()->get_data_ptr(actionConfigID, ID_SPACE_CONFIG, dt);
if (dt == DT_PLAYER_ACTION_INFO_CONFIG){
PLAYER_ACTION actionConfig;
actionConfig.type = (PLAYER_ACTION_TYPE)iAction;
actionConfig.data = (PLAYER_ACTION_INFO_CONFIG *)p;
return PlayActionWithConfig(iAction, actionConfig, bRestart, iTransTime, bQueue);
}else{
ASSERT(false);
a_LogOutput(1, "CECPlayer::PlayActionWithConfig, invalid action config ID(%d)", actionConfigID);
}
}
return PlayActionWithConfig(iAction, m_PlayerActions[iAction], bRestart, iTransTime, bQueue);
}
// Play model action by weapon and relative action index
bool CECPlayer::PlayActionWithConfig(int iAction, const PLAYER_ACTION &actionConfig, bool bRestart/* true */, int iTransTime/* 200 */, bool bQueue/* false */)
{
if (m_pPlayerModel)
{
if (iAction != ACT_WOUNDED)
{
if (iAction == ACT_TAKEOFF){
ShowWing(true);
}else if (iAction == ACT_LANDON){
ShowWing(false);
}
PLAYER_ACTION action = actionConfig;
if( !action.data )
return false;
if( !bQueue )
{
// update show weapon states.
m_bShowWeapon = action.data->hide_weapon ? false : true;
}
char szAct[512];
int weapon_type = GetShowingWeaponType();
if( iAction >= ACT_ATTACK_1 && iAction <= ACT_ATTACK_4 )
{
// attack action should not be played by this function
return false;
}
else if( iAction == ACT_ATTACK_TOSS )
{
// we use toss second part action as a common action
sprintf(szAct, "%s_%s落", action.data->action_prefix, action.data->action_weapon_suffix[weapon_type].suffix);
if( !bQueue ){
PlayNonSkillActionWithName(iAction, szAct, bRestart, iTransTime);
}else{
QueueNonSkillActionWithName(iAction, szAct, iTransTime, bRestart, false, false, true, NULL, COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX);
}
}
else if( (iAction >= ACT_EXP_WAVE && iAction <= ACT_EXP_KISS_END) || (iAction >= ACT_EXP_FIGHT && iAction <= ACT_EXP_DANCE) )
{
// 表情动作
AString strFashionAction;
if (iAction == ACT_EXP_DANCE && InFashionMode())
strFashionAction = GetFashionActionName();
sprintf(szAct, "%s_%s"
, strFashionAction.IsEmpty() ? action.data->action_prefix : strFashionAction
, action.data->action_weapon_suffix[weapon_type].suffix);
if( !bQueue ){
PlayNonSkillActionWithName(iAction, szAct, bRestart, iTransTime);
}else{
QueueNonSkillActionWithName(iAction, szAct, iTransTime, false, false, false, true, NULL, COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX);
}
}
else if (iAction == ACT_EXP_FASHIONWEAPON)
{
if (CanShowFashionWeapon(m_uAttackType, m_iFashionWeaponType))
{
AString strAction;
int idEquipment = m_aEquips[EQUIPIVTR_FASHION_WEAPON] & 0x0000ffff;
GetFashionActionNameByID(idEquipment,strAction);
if (!strAction.IsEmpty())
{ //by2024 sprintf_s
sprintf(szAct, "%s_%s", strAction, action.data->action_weapon_suffix[weapon_type].suffix);
if( !bQueue ){
PlayNonSkillActionWithName(iAction, szAct, bRestart, iTransTime);
}else{
QueueNonSkillActionWithName(iAction, szAct, iTransTime, false, false, false, true, NULL, COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX);
}
}
}
}
else
{
// 通用动作
if (m_pPetModel)
{
if( iAction == ACT_FIGHTSTAND )
action = m_PlayerActions[ACT_STAND];
else if( iAction >= ACT_PICKUP && iAction <= ACT_PICKUP_MATTER )
action = m_PlayerActions[ACT_STAND];
if( iAction == ACT_TWO_KISS )
sprintf(szAct, "站立_亲吻_双骑_通用");
else
sprintf(szAct, "%s_%s", action.data->action_prefix, "骑乘_通用");
const char * szPetAct = NULL;
if (iAction == ACT_STAND || iAction == ACT_FIGHTSTAND)
szPetAct = CECNPC::GetBaseActionName(CECNPC::ACT_STAND);
else if (iAction == ACT_RUN)
szPetAct = CECNPC::GetBaseActionName(CECNPC::ACT_RUN);
else if (iAction == ACT_WALK)
szPetAct = CECNPC::GetBaseActionName(CECNPC::ACT_WALK);
else if (iAction == ACT_JUMP_START)
szPetAct = CECNPC::GetBaseActionName(CECNPC::ACT_JUMP_START);
else if (iAction == ACT_JUMP_LAND)
szPetAct = CECNPC::GetBaseActionName(CECNPC::ACT_JUMP_LAND);
else if (iAction == ACT_JUMP_LOOP)
szPetAct = CECNPC::GetBaseActionName(CECNPC::ACT_JUMP_LOOP);
if( !bQueue )
m_pPetModel->PlayActionByName(szPetAct, 1.0f, bRestart, iTransTime, true);
else
m_pPetModel->QueueAction(szPetAct, iTransTime);
// now weapon wanted.
m_bShowWeapon = false;
}
else if (m_bHangerOn)
{
if( iAction == ACT_FIGHTSTAND )
action = m_PlayerActions[ACT_STAND];
else if( iAction >= ACT_PICKUP && iAction <= ACT_PICKUP_MATTER )
action = m_PlayerActions[ACT_STAND];
if( iAction == ACT_TWO_KISS )
{
if (m_AttachMode == enumAttachRideOnPlayer)
sprintf(szAct, "抚摸_绑定_通用");
else if (m_AttachMode == enumAttachHugPlayer)
sprintf(szAct, "亲吻_绑定_通用");
else if (m_AttachMode == enumAttachRideOnPet)
sprintf(szAct, "亲吻_双骑_通用");
}
else
{
if (m_AttachMode == enumAttachRideOnPlayer)
sprintf(szAct, "%s_%s", action.data->action_prefix, "双骑_通用");
else if (m_AttachMode == enumAttachHugPlayer)
{
if( iAction != ACT_RUN )
sprintf(szAct, "%s", "站立_绑定_通用");
else
sprintf(szAct, "%s", "奔跑_绑定_通用");
}
else if (m_AttachMode == enumAttachRideOnPet)
sprintf(szAct, "%s_%s", action.data->action_prefix, "双骑_通用");
}
// now weapon wanted.
m_bShowWeapon = false;
}
else if (m_AttachMode == enumAttachHugPlayer || m_AttachMode == enumAttachRideOnPlayer)
{
if( iAction == ACT_FIGHTSTAND )
action = m_PlayerActions[ACT_STAND];
else if( iAction >= ACT_PICKUP && iAction <= ACT_PICKUP_MATTER )
action = m_PlayerActions[ACT_STAND];
if( iAction == ACT_TWO_KISS )
{
action = m_PlayerActions[GetMoveStandAction(false, false)];
if (m_AttachMode == enumAttachHugPlayer)
sprintf(szAct, "%s_%s", action.data->action_prefix, "亲吻_绑定_通用");
else
sprintf(szAct, "%s_%s", action.data->action_prefix, "抚摸_绑定_通用");
}
else
sprintf(szAct, "%s_%s", action.data->action_prefix, "绑定_通用");
// now weapon wanted.
m_bShowWeapon = false;
}
else
sprintf(szAct, "%s_%s", action.data->action_prefix, action.data->action_weapon_suffix[weapon_type].suffix);
CECModel* pRightHandWeapon = GetRightHandWeapon();
if( !bQueue )
{
PlayNonSkillActionWithName(iAction, szAct, bRestart, iTransTime);
if(pRightHandWeapon && IsUsingMagicWeapon())
pRightHandWeapon->PlayActionByName(_GenWeaponActionName(szAct, m_iGender), 1.0f, bRestart, iTransTime, true, iAction);
}
else
{
QueueNonSkillActionWithName(iAction, szAct, iTransTime, bRestart, false, false, true, NULL, COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX);
if(pRightHandWeapon && IsUsingMagicWeapon())
pRightHandWeapon->QueueAction(_GenWeaponActionName(szAct, m_iGender), iTransTime, iAction, bRestart ? true : false);
}
if (m_iBuddyId)
{
if( !m_bHangerOn )
{
CECPlayer* pBuddy = m_pPlayerMan->GetPlayer(m_iBuddyId);
if (pBuddy)
{
if( iAction == ACT_STAND || iAction == ACT_FIGHTSTAND ||
iAction == ACT_RUN || iAction == ACT_WALK || iAction == ACT_JUMP_START ||
iAction == ACT_JUMP_LOOP || iAction == ACT_JUMP_LAND || iAction == ACT_WOUNDED ||
iAction == ACT_TWO_KISS )
{
pBuddy->PlayAction(iAction, bRestart, iTransTime, bQueue);
}
else
pBuddy->PlayAction(ACT_STAND, bRestart, iTransTime, bQueue);
}
}
}
}
}
else // iAction == ACT_WOUNDED
{
PLAYER_ACTION action = m_PlayerActions[iAction];
PlayWoundActionWithName(action.data->action_name);
if (m_pPetModel)
{
A3DSkinModel *pSkinModel = m_pPetModel->GetA3DSkinModel();
const char* szPetAct = CECNPC::GetBaseActionName(CECNPC::ACT_WOUNDED);
if (!pSkinModel->GetAction(szPetAct))
{
szPetAct = CECNPC::GetBaseActionName(CECNPC::ACT_WOUNDED2);
if (!pSkinModel->GetAction(szPetAct))
szPetAct = NULL;
if (szPetAct)
pSkinModel->PlayActionByName(szPetAct, CECModel::ACTCHA_WOUND, 1, 0, false);
}
}
}
if( !bQueue )
{
if( !m_bShowWeapon )
ShowWeapon(false);
else
{
// 巫师跳跃时需要隐藏法宝
if(IsUsingMagicWeapon() && (iAction == ACT_JUMP_START || iAction == ACT_JUMP_LAND || iAction == ACT_JUMP_LOOP))
ShowWeapon(false);
else
ShowWeapon(true);
}
// 根据播放动作,更改武器悬挂位置
UpdateWeaponHangerPosByAction(iAction);
}
return true;
}
else
return false;
}
// Play skill cast action
bool CECPlayer::PlaySkillCastAction(int idSkill)
{
if( !m_pPlayerModel )
return false;
char szAct[512];
szAct[0] = '\0';
int weapon_type = GetShowingWeaponType();
const PLAYER_ACTION_INFO_CONFIG* data = _default_skill_actions[idSkill];
if( !data || !data->action_prefix[0] )
{
// Check if it's a target item skill
if(GNET::ElementSkill::GetCommonCoolDown(idSkill) > 1<<4)
{
data = m_PlayerActions[ACT_USING_TARGET_ITEM].data;
if( !data || !data->action_prefix[0] )
return false;
}
else
return false;
}
if( GetMoveEnv() == MOVEENV_GROUND )
{
sprintf(szAct, "%s_吟唱_%s", data->action_prefix, data->action_weapon_suffix[weapon_type].suffix);
}
else
{
if( (/*UsingWing()*/m_wingType == WINGTYPE_WING && IsFlying()) || (GetProfession() == PROF_ANGEL) || (GetProfession() == PROF_ARCHOR) || (GetProfession() == PROF_MONK) || (GetProfession() == PROF_GHOST) )
sprintf(szAct, "%s_空中翅膀_吟唱_%s", data->action_prefix, data->action_weapon_suffix[weapon_type].suffix);
else
sprintf(szAct, "%s_空中飞剑_吟唱_%s", data->action_prefix, data->action_weapon_suffix[weapon_type].suffix);
}
bool bHideFX = !CECOptimize::Instance().GetGFX().CanShowCast(GetCharacterID(), GetClassID());
if (!PlaySkillCastActionWithName(idSkill, szAct, bHideFX)){
return false;
}
ShowWeaponByConfig(data);
UpdateWeaponHangerPosBySkillAction(idSkill);// 根据技能播放的动作,更改武器悬挂位置(只能检查不排队动作)
return true;
}
// Set part extend properties
void CECPlayer::SetPartExtendProps(int iPropIdx, void* pData)
{
switch (iPropIdx)
{
case EXTPROPIDX_BASE:
m_ExtProps.bs = *(ROLEEXTPROP_BASE*)pData;
break;
case EXTPROPIDX_MOVE:
m_ExtProps.mv = *(ROLEEXTPROP_MOVE*)pData;
break;
case EXTPROPIDX_ATTACK:
m_ExtProps.ak = *(ROLEEXTPROP_ATK*)pData;
break;
case EXTPROPIDX_DEF:
m_ExtProps.df = *(ROLEEXTPROP_DEF*)pData;
break;
default:
ASSERT(0);
return;
}
}
/*
* Add By Zhangyu, 12.22.04
*/
void CECPlayer::ShowEquipments(
int nProf,
int nGender,
const int* pEquipmentID,
__int64 ChangeMask,
EquipsLoadResult* pResult,
bool bSimpleModel)
{
DATA_TYPE dt;
A3DCOLOR color;
// keep old things.
pResult->stoneWeapon = 0x00ff;
pResult->stoneUpperBody = 0x00ff;
pResult->stoneWrist = 0x00ff;
pResult->stoneLowerBody = 0x00ff;
pResult->stoneFoot = 0x00ff;
for (__int64 i = 0; i < SIZE_ALL_EQUIPIVTR; i++)
{
if (((1 << i) & ChangeMask))
{
int idEquipment = pEquipmentID[i];
if((i >= EQUIPIVTR_FASHION_BODY && i <= EQUIPIVTR_FASHION_WRIST ) ||
i == EQUIPIVTR_FASHION_HEAD || i == EQUIPIVTR_FASHION_WEAPON)
{
WORD wColor = (idEquipment & 0xffff0000) >> 16;
idEquipment &= 0x0000ffff;
color = FASHION_WORDCOLOR_TO_A3DCOLOR(wColor);
}
else
{
if( i == EQUIPIVTR_WEAPON )
{
pResult->stoneWeapon = (idEquipment & 0xffff0000) >> 16;
}
if( i == EQUIPIVTR_BODY )
{
pResult->stoneUpperBody = (idEquipment & 0xffff0000) >> 16;
}
if( i == EQUIPIVTR_WRIST )
{
pResult->stoneWrist = (idEquipment & 0xffff0000) >> 16;
}
if( i == EQUIPIVTR_LEG )
{
pResult->stoneLowerBody = (idEquipment & 0xffff0000) >> 16;
}
if( i == EQUIPIVTR_FOOT )
{
pResult->stoneFoot = (idEquipment & 0xffff0000) >> 16;
}
idEquipment &= 0x0000ffff;
}
if (idEquipment)
{
const void* pEquip = g_pGame->GetElementDataMan()->get_data_ptr(
idEquipment,
ID_SPACE_ESSENCE,
dt);
if (pEquip)
{
switch (dt)
{
case DT_WEAPON_ESSENCE:
ChangeWeapon(pResult, static_cast<const WEAPON_ESSENCE*>(pEquip));
continue;
case DT_ARMOR_ESSENCE:
if( !bSimpleModel )
{
ChangeArmor(
static_cast<const ARMOR_ESSENCE*>(pEquip),
pResult->dwShowMask,
pResult->dwSkinChangeMask,
nProf,
nGender,
pResult->aSkins);
}
continue;
case DT_WINGMANWING_ESSENCE:
pResult->wingType = WINGTYPE_WING;
ChangeWing(pResult, static_cast<const WINGMANWING_ESSENCE*>(pEquip)->file_model);
continue;
case DT_FLYSWORD_ESSENCE:
pResult->wingType = FlyMode2WingType(static_cast<const FLYSWORD_ESSENCE*>(pEquip)->fly_mode);
if (pResult->wingType != WINGTYPE_DOUBLEWHEEL) {
ChangeWing(pResult, static_cast<const FLYSWORD_ESSENCE*>(pEquip)->file_model);
} else {
ChangeWing(pResult, static_cast<const FLYSWORD_ESSENCE*>(pEquip)->file_model,
static_cast<const FLYSWORD_ESSENCE*>(pEquip)->file_model2);
}
continue;
case DT_FASHION_ESSENCE:
{
const FASHION_ESSENCE* pFashion = static_cast<const FASHION_ESSENCE*>(pEquip);
if (pFashion->equip_location == enumSkinShowHand)
{
pResult->uFashionAttackType = pFashion->action_type;
pResult->bFashionWeaponChanged = true;
pResult->strLeftFashionWeapon = pFashion->file_model_left;
pResult->strRightFashionWeapon = pFashion->file_model_right;
ChangeWeapon(pResult, pFashion->file_model_left, pFashion->file_model_right);
}
else
{
if( !bSimpleModel )
{
ChangeFashion(
pFashion,
pResult->dwFashionShowMask,
pResult->dwSkinChangeMask,
nProf,
nGender,
pResult->aSkins,
color
);
}
}
continue;
}
default:
continue;
}
}
else
a_LogOutput(1, "Equipment Invent: WrongEquipType: Id = %d", idEquipment);
}
if( bSimpleModel ) // 简单模型不加载默认装备
continue;
if (i == EQUIPIVTR_BODY)
{
pResult->dwShowMask |= (1 << enumSkinShowUpperBody);
pResult->dwSkinChangeMask |= (1 << SKIN_UPPER_BODY_INDEX);
pResult->stoneUpperBody = 0;
ChangeDefaultUpper(pResult->aSkins[SKIN_UPPER_BODY_INDEX], nProf, nGender);
}
else if (i == EQUIPIVTR_LEG)
{
pResult->dwShowMask |= (1 << enumSkinShowLowerBody);
pResult->dwSkinChangeMask |= (1 << SKIN_LOWER_INDEX);
pResult->stoneLowerBody = 0;
ChangeDefaultLower(pResult->aSkins[SKIN_LOWER_INDEX], nProf, nGender);
}
else if (i == EQUIPIVTR_WRIST)
{
pResult->dwShowMask |= (1 << enumSkinShowWrist);
pResult->dwSkinChangeMask |= (1 << SKIN_WRIST_INDEX);
pResult->stoneWrist = 0;
ChangeDefaultWrist(pResult->aSkins[SKIN_WRIST_INDEX], nProf, nGender);
}
else if (i == EQUIPIVTR_FOOT)
{
pResult->dwShowMask |= (1 << enumSkinShowFoot);
pResult->dwSkinChangeMask |= (1 << SKIN_FOOT_INDEX);
pResult->stoneFoot = 0;
ChangeDefaultFoot(pResult->aSkins[SKIN_FOOT_INDEX], nProf, nGender);
}
else if (i == EQUIPIVTR_WEAPON)
{
pResult->bWeaponChanged = true;
pResult->stoneWeapon = 0;
pResult->uAttackType = DEFAULT_ACTION_TYPE;
}
else if (i == EQUIPIVTR_FLYSWORD)
pResult->bWingChanged = true;
else if (i == EQUIPIVTR_FASHION_BODY)
{
pResult->dwFashionShowMask |= (1 << enumSkinShowUpperBody);
pResult->dwSkinChangeMask |= (1 << SKIN_FASHION_UPPER_BODY_INDEX);
ChangeDefaultFashionUpper(pResult->aSkins[SKIN_FASHION_UPPER_BODY_INDEX], nProf, nGender);
}
else if (i == EQUIPIVTR_FASHION_LEG)
{
pResult->dwFashionShowMask |= (1 << enumSkinShowLowerBody);
pResult->dwSkinChangeMask |= (1 << SKIN_FASHION_LOWER_INDEX);
ChangeDefaultFashionLower(pResult->aSkins[SKIN_FASHION_LOWER_INDEX], nProf, nGender);
}
else if (i == EQUIPIVTR_FASHION_WRIST)
{
pResult->dwFashionShowMask |= (1 << enumSkinShowWrist);
pResult->dwSkinChangeMask |= (1 << SKIN_FASHION_WRIST_INDEX);
ChangeDefaultFashionWrist(pResult->aSkins[SKIN_FASHION_WRIST_INDEX], nProf, nGender);
}
else if (i == EQUIPIVTR_FASHION_FOOT)
{
pResult->dwFashionShowMask |= (1 << enumSkinShowFoot);
pResult->dwSkinChangeMask |= (1 << SKIN_FASHION_FOOT_INDEX);
ChangeDefaultFashionFoot(pResult->aSkins[SKIN_FASHION_FOOT_INDEX], nProf, nGender);
}
else if (i == EQUIPIVTR_FASHION_HEAD)
{
int aaa = 1; // for test
}
else if (i == EQUIPIVTR_FASHION_WEAPON)
{
pResult->bFashionWeaponChanged = true;
pResult->uFashionAttackType = DEFAULT_ACTION_TYPE;
}
}
}
}
void CECPlayer::ShowEquipments(const int* pEquipmentID, bool bLoadAtOnce, bool bForceLoad)
{
if( !GetMajorModel() || !GetMajorModel()->GetA3DSkinModel())
return;
__int64 Mask = 0;
for (__int64 i = 0; i < SIZE_ALL_EQUIPIVTR; i++)
{
if( bForceLoad )
{
if( !((1 << i) & m_i64EquipDisabled) || pEquipmentID[i] == 0 )
Mask |= (1 << i);
}
else
{
if ( pEquipmentID[i] != m_aEquips[i] )
{
if (IsShownEquip(i))
{
if (m_aEquips[i] > 0 )
{
DWORD dwRealID = GetRealElementID(i, m_aEquips[i]);
GetMajorModel()->OnScriptChangeEquip(dwRealID, 0, false);
}
if (pEquipmentID[i] > 0)
{
DWORD dwRealID = GetRealElementID(i, pEquipmentID[i]);
GetMajorModel()->OnScriptChangeEquip(dwRealID, 1, false);
}
}
if( // not disable
!((1 << i) & m_i64EquipDisabled)
// remove equip
|| pEquipmentID[i] == 0 )
{
Mask |= (1 << i);
}
m_aEquips[i] = pEquipmentID[i];
}
}
}
int aEquips[IVTRSIZE_EQUIPPACK];
memcpy(aEquips, pEquipmentID, sizeof(aEquips));
DecideWeaponLoad(aEquips, Mask);
QueueLoadEquips(aEquips, Mask, bLoadAtOnce);
}
void CECPlayer::ChangeEquipDisableMask(__int64 Mask)
{
// equipment disable will affect the player animation
int aChangedEquip[SIZE_ALL_EQUIPIVTR];
int aRestoreEquip[SIZE_ALL_EQUIPIVTR];
// backup the equipments info
ASSERT(sizeof(aRestoreEquip) == sizeof(m_aEquips));
memcpy(aRestoreEquip, m_aEquips, sizeof(m_aEquips));
for (__int64 i = 0; i < SIZE_ALL_EQUIPIVTR; i++)
{
__int64 flagOld = (1 << i) & m_i64EquipDisabled;
__int64 flagCur = (1 << i) & Mask;
if(flagCur != flagOld)
{
if(flagCur)
{
// this equipment should be disabled
aChangedEquip[i] = 0;
}
else
{
// this equipment should be restored
aChangedEquip[i] = m_aEquips[i];
m_aEquips[i] = 0;
}
}
else
{
aChangedEquip[i] = m_aEquips[i];
}
}
m_i64EquipDisabled = Mask;
// remove disabled equipments
ShowEquipments(aChangedEquip, false);
// restore the equipments info
memcpy(m_aEquips, aRestoreEquip, sizeof(m_aEquips));
}
bool CECPlayer::ChangeWing(
EquipsLoadResult* pResult,
const char* szModeFile,
const char* szModeFile2)
{
if (!szModeFile[0]) return false;
pResult->bWingChanged = true;
g_pGame->GetA3DEngine()->GetA3DSkinMan()->SetReplaceShaderFile((const char*)glb_ArmorReplaceShader_ReflectPrefix, A3DSkinMan::SHADERREPLACE_USERDEFINE);
CECModel* pWing = new CECModel;
if (pWing->Load(szModeFile, true, A3DSkinModel::LSF_UNIQUESKIN))
{
pWing->Show(false);
pResult->pWing = pWing;
}
else
delete pWing;
if (szModeFile2 != NULL) {
CECModel* pRightFoot = new CECModel;
if (pRightFoot->Load(szModeFile2, true, A3DSkinModel::LSF_UNIQUESKIN))
{
pRightFoot->Show(false);
pResult->pWing2 = pRightFoot;
}
else
delete pRightFoot;
}
g_pGame->GetA3DEngine()->GetA3DSkinMan()->SetReplaceShaderFile("", 0);
return true;
}
inline void _SetWeaponMaterial(A3DSkinModel* pModel)
{
if (!pModel) return;
int nNumSkin = pModel->GetSkinNum();
A3DSkin * pSkin;
for (int i = 0; i < nNumSkin; i++)
{
pSkin = pModel->GetA3DSkin(i);
if( pSkin )
{
int nNumMaterial = pSkin->GetMaterialNum();
for (int i = 0; i < nNumMaterial; i++)
{
A3DMATERIALPARAM param = pSkin->GetMaterial(i)->GetMaterialParam();
param.Specular = WEAPON_SPECULAR;
param.Power = WEAPON_POWER;
pSkin->GetMaterial(i)->SetMaterialParam(param);
}
}
}
}
bool CECPlayer::ChangeWeapon(EquipsLoadResult* pResult, const char* szLeft, const char* szRight)
{
if (pResult->bFashionWeaponChanged)
g_pGame->GetA3DEngine()->GetA3DSkinMan()->SetReplaceShaderFile((const char*)glb_FashionReplaceShader, A3DSkinMan::SHADERREPLACE_USERDEFINE);
else
g_pGame->GetA3DEngine()->GetA3DSkinMan()->SetReplaceShaderFile((const char*)glb_ArmorReplaceShader_ReflectPrefix, A3DSkinMan::SHADERREPLACE_USERDEFINE);
if (szLeft[0])
{
CECModel* pWeapon = new CECModel;
if (pWeapon->Load(szLeft, true, A3DSkinModel::LSF_UNIQUESKIN))
{
_SetWeaponMaterial(pWeapon->GetA3DSkinModel());
pResult->pLeftHandWeapon = pWeapon;
}
else
delete pWeapon;
}
if (szRight[0])
{
CECModel* pWeapon = new CECModel;
if (pWeapon->Load(szRight, true, A3DSkinModel::LSF_UNIQUESKIN))
{
_SetWeaponMaterial(pWeapon->GetA3DSkinModel());
pResult->pRightHandWeapon = pWeapon;
}
else
delete pWeapon;
}
g_pGame->GetA3DEngine()->GetA3DSkinMan()->SetReplaceShaderFile("", 0);
return true;
}
void CECPlayer::ChangeWeapon(EquipsLoadResult* pResult, const WEAPON_ESSENCE* pWeapon)
{
DATA_TYPE dt;
const WEAPON_SUB_TYPE* pSubType =
(const WEAPON_SUB_TYPE*) g_pGame->GetElementDataMan()->get_data_ptr(
pWeapon->id_sub_type,
ID_SPACE_ESSENCE,
dt);
if (pSubType == NULL || dt != DT_WEAPON_SUB_TYPE)
{
a_LogOutput(1, "Equipment Invent: Wrong Weapon SubType, Essence Id = %d", pWeapon->id);
return;
}
pResult->uAttackType = pSubType->action_type;
pResult->strLeftWeapon = pWeapon->file_model_left;
pResult->strRightWeapon = pWeapon->file_model_right;
pResult->bWeaponChanged = true;
ChangeWeapon(
pResult,
pWeapon->file_model_left,
pWeapon->file_model_right);
}
void CECPlayer::ChangeArmor(
const ARMOR_ESSENCE* pArmor,
DWORD& dwShowMask,
DWORD& dwSkinChangeMask,
int nProf,
int nGender,
A3DSkin* pSkins[][3]
)
{
static const int _location_skin_map[] =
{
0, // none
SKIN_UPPER_BODY_INDEX, // enumSkinShowUpperBody
SKIN_WRIST_INDEX, // enumSkinShowWrist
SKIN_LOWER_INDEX, // enumSkinShowLowerBody
SKIN_FOOT_INDEX, // enumSkinShowFoot
SKIN_UPPER_BODY_INDEX, // enumSkinShowUpperAndLower
SKIN_UPPER_BODY_INDEX, // enumSkinShowUpperAndWrist
SKIN_LOWER_INDEX, // enumSkinShowLowerAndFoot
SKIN_UPPER_BODY_INDEX // enumSkinShowUpperLowerAndWrist
};
int nLocation = pArmor->equip_location;
if (nLocation < enumSkinShowUpperBody || nLocation > enumSkinShowUpperLowerAndWrist)
return;
char szPath[MAX_PATH];
_GenSkinPath(szPath, nProf, nGender, pArmor->realname);
int nSkinIndex = _location_skin_map[nLocation];
dwShowMask |= (1 << nLocation);
dwSkinChangeMask |= (1 << nSkinIndex);
ChangeArmor(
szPath,
pSkins[nSkinIndex],
nLocation,
false,
nProf,
nGender
);
}
bool CECPlayer::ChangeArmor(
const char* strSkinFile,
A3DSkin* aSkins[3],
int nLocation,
bool bDefault,
int nProf,
int nGender)
{
switch (nLocation)
{
case enumSkinShowUpperBody:
if (!LoadPlayerSkin(aSkins, SKIN_UPPER_BODY_INDEX, strSkinFile))
{
a_LogOutput(1, "Equipment Invent: Wrong Skin: %s", strSkinFile);
if (!bDefault) ChangeDefaultUpper(aSkins, nProf, nGender);
}
break;
case enumSkinShowWrist:
if (!LoadPlayerSkin(aSkins, SKIN_WRIST_INDEX, strSkinFile))
{
a_LogOutput(1, "Equipment Invent: Wrong Skin: %s", strSkinFile);
if (!bDefault) ChangeDefaultWrist(aSkins, nProf, nGender);
}
break;
case enumSkinShowLowerBody:
if (!LoadPlayerSkin(aSkins, SKIN_LOWER_INDEX, strSkinFile))
{
a_LogOutput(1, "Equipment Invent: Wrong Skin: %s", strSkinFile);
if (!bDefault) ChangeDefaultLower(aSkins, nProf, nGender);
}
break;
case enumSkinShowFoot:
if (!LoadPlayerSkin(aSkins, SKIN_FOOT_INDEX, strSkinFile))
{
a_LogOutput(1, "Equipment Invent: Wrong Skin: %s", strSkinFile);
if (!bDefault) ChangeDefaultFoot(aSkins, nProf, nGender);
}
break;
case enumSkinShowUpperAndLower:
if (!LoadPlayerSkin(aSkins, SKIN_UPPER_BODY_INDEX, strSkinFile))
{
a_LogOutput(1, "Equipment Invent: Wrong Skin: %s", strSkinFile);
if (!bDefault) ChangeDefaultUpper(aSkins, nProf, nGender);
}
break;
case enumSkinShowUpperAndWrist:
if (!LoadPlayerSkin(aSkins, SKIN_UPPER_BODY_INDEX, strSkinFile))
{
a_LogOutput(1, "Equipment Invent: Wrong Skin: %s", strSkinFile);
if (!bDefault) ChangeDefaultUpper(aSkins, nProf, nGender);
}
break;
case enumSkinShowLowerAndFoot:
if (!LoadPlayerSkin(aSkins, SKIN_LOWER_INDEX, strSkinFile))
{
a_LogOutput(1, "Equipment Invent: Wrong Skin: %s", strSkinFile);
if (!bDefault) ChangeDefaultLower(aSkins, nProf, nGender);
}
break;
case enumSkinShowUpperLowerAndWrist:
if (!LoadPlayerSkin(aSkins, SKIN_UPPER_BODY_INDEX, strSkinFile))
{
a_LogOutput(1, "Equipment Invent: Wrong Skin: %s", strSkinFile);
if (!bDefault) ChangeDefaultUpper(aSkins, nProf, nGender);
}
break;
case enumSkinShowNone:
break;
default:
a_LogOutput(1, "Equipment Invent: Wrong Location: %d", nLocation);
break;
}
return true;
}
void CECPlayer::ChangeFashion(
const FASHION_ESSENCE* pFashion,
DWORD& dwShowMask,
DWORD& dwSkinChangeMask,
int nProf,
int nGender,
A3DSkin* pSkins[][3],
A3DCOLOR color)
{
static const int _location_skin_map[] =
{
0, // none
SKIN_FASHION_UPPER_BODY_INDEX, // enumSkinShowUpperBody
SKIN_FASHION_WRIST_INDEX, // enumSkinShowWrist
SKIN_FASHION_LOWER_INDEX, // enumSkinShowLowerBody
SKIN_FASHION_FOOT_INDEX, // enumSkinShowFoot
SKIN_FASHION_UPPER_BODY_INDEX, // enumSkinShowUpperAndLower
SKIN_FASHION_UPPER_BODY_INDEX, // enumSkinShowUpperAndWrist
SKIN_FASHION_LOWER_INDEX, // enumSkinShowLowerAndFoot
SKIN_FASHION_UPPER_BODY_INDEX, // enumSkinShowUpperLowerAndWrist
};
int nLocation = pFashion->equip_location;
if (nLocation < enumSkinShowUpperBody || nLocation > enumSkinShowUpperLowerAndWrist)
return;
char szPath[MAX_PATH];
_GenSkinPath(szPath, nProf, nGender, pFashion->realname);
int nSkinIndex = _location_skin_map[nLocation];
dwShowMask |= (1 << nLocation);
dwSkinChangeMask |= (1 << nSkinIndex);
ChangeFashion(
szPath,
pSkins[nSkinIndex],
nLocation,
false,
nProf,
nGender,
color
);
}
bool CECPlayer::ChangeFashion(
const char* strSkinFile,
A3DSkin* aSkins[3],
int nLocation,
bool bDefault,
int nProf,
int nGender,
A3DCOLOR color)
{
switch (nLocation)
{
case enumSkinShowUpperBody:
if (!LoadPlayerSkin(aSkins, SKIN_FASHION_UPPER_BODY_INDEX, strSkinFile))
{
a_LogOutput(1, "Equipment Invent: Wrong Skin: %s", strSkinFile);
if (!bDefault) ChangeDefaultFashionUpper(aSkins, nProf, nGender);
}
break;
case enumSkinShowWrist:
if (!LoadPlayerSkin(aSkins, SKIN_FASHION_WRIST_INDEX, strSkinFile))
{
a_LogOutput(1, "Equipment Invent: Wrong Skin: %s", strSkinFile);
if (!bDefault) ChangeDefaultFashionWrist(aSkins, nProf, nGender);
}
break;
case enumSkinShowLowerBody:
if (!LoadPlayerSkin(aSkins, SKIN_FASHION_LOWER_INDEX, strSkinFile))
{
a_LogOutput(1, "Equipment Invent: Wrong Skin: %s", strSkinFile);
if (!bDefault) ChangeDefaultFashionLower(aSkins, nProf, nGender);
}
break;
case enumSkinShowFoot:
if (!LoadPlayerSkin(aSkins, SKIN_FASHION_FOOT_INDEX, strSkinFile))
{
a_LogOutput(1, "Equipment Invent: Wrong Skin: %s", strSkinFile);
if (!bDefault) ChangeDefaultFashionFoot(aSkins, nProf, nGender);
}
break;
case enumSkinShowUpperAndLower:
if (!LoadPlayerSkin(aSkins, SKIN_FASHION_UPPER_BODY_INDEX, strSkinFile))
{
a_LogOutput(1, "Equipment Invent: Wrong Skin: %s", strSkinFile);
if (!bDefault) ChangeDefaultFashionUpper(aSkins, nProf, nGender);
}
break;
case enumSkinShowUpperAndWrist:
if (!LoadPlayerSkin(aSkins, SKIN_FASHION_UPPER_BODY_INDEX, strSkinFile))
{
a_LogOutput(1, "Equipment Invent: Wrong Skin: %s", strSkinFile);
if (!bDefault) ChangeDefaultFashionUpper(aSkins, nProf, nGender);
}
break;
case enumSkinShowLowerAndFoot:
if (!LoadPlayerSkin(aSkins, SKIN_FASHION_LOWER_INDEX, strSkinFile))
{
a_LogOutput(1, "Equipment Invent: Wrong Skin: %s", strSkinFile);
if (!bDefault) ChangeDefaultFashionLower(aSkins, nProf, nGender);
}
break;
case enumSkinShowUpperLowerAndWrist:
if (!LoadPlayerSkin(aSkins, SKIN_FASHION_UPPER_BODY_INDEX, strSkinFile))
{
a_LogOutput(1, "Equipment Invent: Wrong Skin: %s", strSkinFile);
if (!bDefault) ChangeDefaultFashionUpper(aSkins, nProf, nGender);
}
break;
case enumSkinShowNone:
break;
default:
a_LogOutput(1, "Equipment Invent: Wrong Location: %d", nLocation);
break;
}
// now get the shader and set color to it.
for(int i=0; i<3; i++)
{
A3DSkin * pSkin = aSkins[i];
if (!pSkin) continue;
for(int idTex=0; idTex<pSkin->GetTextureNum(); idTex ++)
{
A3DTexture * pTex = pSkin->GetTexture(idTex);
if( pTex && pTex->IsShaderTexture() )
{
A3DShader * pShader = (A3DShader *) pTex;
pShader->GetGeneralProps().dwTFactor = color;
}
}
}
return true;
}
// play attack action
bool CECPlayer::PlayAttackAction(int nAttackSpeed, int* piAttackTime/* =NULL */, bool *pActFlag/* =NULL */)
{
if (!m_pPlayerModel)
return false;
int nRand = rand() % 4;
char szAct[512];
szAct[0] = '\0';
int weapon_type = GetShowingWeaponType();
int nTime1, nTime2, iAction = ACT_ATTACK_1 + nRand;
const PLAYER_ACTION& action = m_PlayerActions[iAction];
if( !action.data || !action.data->action_prefix[0] )
return false;
ShowWeaponByConfig(action.data);
CECModel* pRightHandWeapon = GetRightHandWeapon();
bool bHideFX = !CECOptimize::Instance().GetGFX().CanShowAttack(GetCharacterID(), GetClassID());
if( GetMoveEnv() == MOVEENV_GROUND )
{
sprintf(szAct, "%s_%s起", action.data->action_prefix, action.data->action_weapon_suffix[weapon_type].suffix);
PlayNonSkillActionWithName(iAction, szAct, true, 200, bHideFX, pActFlag, COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX);
if(pRightHandWeapon && IsUsingMagicWeapon())
pRightHandWeapon->PlayActionByName(_GenWeaponActionName(szAct, m_iGender), 1.0f, true, 200, true, iAction, bHideFX);
nTime1 = m_pPlayerModel->GetComActTimeSpanByName(szAct);
sprintf(szAct, "%s_%s落", action.data->action_prefix, action.data->action_weapon_suffix[weapon_type].suffix);
QueueNonSkillActionWithName(iAction, szAct, 0, false, bHideFX);
if(pRightHandWeapon && IsUsingMagicWeapon())
pRightHandWeapon->QueueAction(_GenWeaponActionName(szAct, m_iGender), 0, iAction, false, false, bHideFX);
nTime2 = m_pPlayerModel->GetComActTimeSpanByName(szAct);
}
else
{
const char *szActionMiddleName = NULL;
if( (/*UsingWing()*/m_wingType == WINGTYPE_WING && IsFlying()) || (GetProfession() == PROF_ANGEL) || (GetProfession() == PROF_ARCHOR) || (GetProfession() == PROF_MONK) || (GetProfession() == PROF_GHOST) )
{
szActionMiddleName = "空中翅膀";
}else{
szActionMiddleName = "空中飞剑";
}
sprintf(szAct, "%s_%s_%s起", action.data->action_prefix, szActionMiddleName, action.data->action_weapon_suffix[weapon_type].suffix);
PlayNonSkillActionWithName(iAction, szAct, true, 200, bHideFX, pActFlag, COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX);
if(pRightHandWeapon && IsUsingMagicWeapon())
pRightHandWeapon->PlayActionByName(_GenWeaponActionName(szAct, m_iGender), 1.0f, true, 200, true, iAction, bHideFX);
nTime1 = m_pPlayerModel->GetComActTimeSpanByName(szAct);
sprintf(szAct, "%s_%s_%s落", action.data->action_prefix, szActionMiddleName, action.data->action_weapon_suffix[weapon_type].suffix);
QueueNonSkillActionWithName(iAction, szAct, 0, false, bHideFX);
if(pRightHandWeapon && IsUsingMagicWeapon())
pRightHandWeapon->QueueAction(_GenWeaponActionName(szAct, m_iGender), 0, iAction, false, false, bHideFX);
nTime2 = m_pPlayerModel->GetComActTimeSpanByName(szAct);
}
// make attack action end up with a stand to eliminate the still animation if a long delay occurs.
const PLAYER_ACTION& stand_action = m_PlayerActions[ACT_FIGHTSTAND];
sprintf(szAct, "%s_%s", stand_action.data->action_prefix, stand_action.data->action_weapon_suffix[weapon_type].suffix);
QueueNonSkillActionWithName(ACT_FIGHTSTAND, szAct, 300, false, bHideFX, true); // 2012-1-31: 增加设置 bResetSpeed=true,避免 ACT_FIGHTSTAND 动作受攻击动作速度修改影响(m_pPlayerModel->SetPlaySpeed)而播放过快
if(pRightHandWeapon && IsUsingMagicWeapon())
pRightHandWeapon->QueueAction(_GenWeaponActionName(szAct, m_iGender), 300, iAction, false, false, bHideFX, true); // 2012-1-31: 同上
// now we try to adjust the player's animation to meet synchronize with attack speed
if( nAttackSpeed > 0 )
{
float vScale = (nTime1 + nTime2) / (float)nAttackSpeed;
if (vScale > 0.0f){
m_pPlayerModel->SetPlaySpeed(vScale);
if(pRightHandWeapon && IsUsingMagicWeapon())
pRightHandWeapon->SetPlaySpeed(vScale);
}
}
if (piAttackTime)
*piAttackTime = nTime1 + nTime2;
// 根据播放动作,更改武器悬挂位置
UpdateWeaponHangerPosByAction(iAction);
return true;
}
static void _GetSkillSectionActionName(char* szAct,int idSkill,int nSection)
{
if (nSection)
{
CECAttacksMan* pAtkMan = g_pGame->GetGameRun()->GetWorld()->GetAttacksMan();
AString suffix;
if(pAtkMan && pAtkMan->GetSkillSectionActionSuffix(idSkill,nSection,suffix))
{
strcat(szAct,"_");
strcat(szAct,suffix);
}
}
}
// play skill attack action
bool CECPlayer::PlaySkillAttackAction(int idSkill, int nAttackSpeed, int* piAttackTime/* =NULL */,int nSection /* = 0 */, bool *pActFlag/* =NULL */)
{
if (!m_pPlayerModel )
return false;
char szAct[512];
szAct[0] = '\0';
int weapon_type = GetShowingWeaponType();
const PLAYER_ACTION_INFO_CONFIG* data = _default_skill_actions[idSkill];
if( !data || !data->action_prefix[0] )
{
// Check if it's a target item skill
if(GNET::ElementSkill::GetCommonCoolDown(idSkill) > 1<<4)
{
data = m_PlayerActions[ACT_USING_TARGET_ITEM].data;
if( !data || !data->action_prefix[0] )
return false;
}
else
return false;
}
int nTime1, nTime2;
bool bInfinite = false;
A3DCombinedAction * pAct;
CECModel* pRightHandWeapon = GetRightHandWeapon();
bool bHideFX = !CECOptimize::Instance().GetGFX().CanShowAttack(GetCharacterID(), GetClassID());
CECAttacksMan* pAtkMan = g_pGame->GetGameRun()->GetWorld()->GetAttacksMan();
if( GetMoveEnv() == MOVEENV_GROUND )
{
sprintf(szAct, "%s_施放起_%s", data->action_prefix, data->action_weapon_suffix[weapon_type].suffix);
_GetSkillSectionActionName(szAct,idSkill,nSection);
if (!PlaySkillAttackActionWithName(idSkill, szAct, bHideFX, pActFlag, COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX)){
return false;
}
nTime1 = m_pPlayerModel->GetComActTimeSpanByName(szAct);
pAct = m_pPlayerModel->GetComActByName(szAct);
if( pAct ) bInfinite |= pAct->IsInfinite();
sprintf(szAct, "%s_施放落_%s", data->action_prefix, data->action_weapon_suffix[weapon_type].suffix);
_GetSkillSectionActionName(szAct,idSkill,nSection);
QueueSkillAttackActionWithName(idSkill, szAct, 0, bHideFX);
nTime2 = m_pPlayerModel->GetComActTimeSpanByName(szAct);
pAct = m_pPlayerModel->GetComActByName(szAct);
if( pAct ) bInfinite |= pAct->IsInfinite();
}
else
{
const char *szActionMiddleName = NULL;
if( (/*UsingWing()*/ m_wingType == WINGTYPE_WING && IsFlying()) || (GetProfession() == PROF_ANGEL) || (GetProfession() == PROF_ARCHOR) || (GetProfession() == PROF_MONK) || (GetProfession() == PROF_GHOST) )
{
szActionMiddleName = "空中翅膀";
}else{
szActionMiddleName = "空中飞剑";
}
sprintf(szAct, "%s_%s_施放起_%s", data->action_prefix, szActionMiddleName, data->action_weapon_suffix[weapon_type].suffix);
_GetSkillSectionActionName(szAct,idSkill,nSection);
if (!PlaySkillAttackActionWithName(idSkill, szAct, bHideFX, pActFlag, COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX)){
return false;
}
if(pRightHandWeapon && IsUsingMagicWeapon())
pRightHandWeapon->PlayActionByName(_GenWeaponActionName(szAct, m_iGender), 1.0f, true, 200, true, ACT_CASTSKILL, bHideFX);
nTime1 = m_pPlayerModel->GetComActTimeSpanByName(szAct);
pAct = m_pPlayerModel->GetComActByName(szAct);
if( pAct ) bInfinite |= pAct->IsInfinite();
sprintf(szAct, "%s_%s_施放落_%s", data->action_prefix, szActionMiddleName, data->action_weapon_suffix[weapon_type].suffix);
_GetSkillSectionActionName(szAct,idSkill,nSection);
QueueSkillAttackActionWithName(idSkill, szAct, 0, bHideFX);
if(pRightHandWeapon && IsUsingMagicWeapon())
pRightHandWeapon->QueueAction(_GenWeaponActionName(szAct, m_iGender), 0, ACT_CASTSKILL, false, false, bHideFX);
nTime2 = m_pPlayerModel->GetComActTimeSpanByName(szAct);
pAct = m_pPlayerModel->GetComActByName(szAct);
if( pAct ) bInfinite |= pAct->IsInfinite();
}
int nExecuteTime = GNET::ElementSkill::GetExecuteTime(idSkill, 0);
// now we try to adjust the player's animation to meet synchronize with attack speed
if( !bInfinite )
{
if( nExecuteTime > 0 )
{
float vScale = (nTime1 + nTime2) / (float)nExecuteTime;
m_pPlayerModel->SetPlaySpeed(vScale * 1.2f);
if(pRightHandWeapon && IsUsingMagicWeapon())
pRightHandWeapon->SetPlaySpeed(vScale * 1.2f);
}
if (piAttackTime)
*piAttackTime = nTime1 + nTime2;
}
else
{
// the action is looped, so we just return the execute determined by skill
if (piAttackTime)
*piAttackTime = nExecuteTime;
}
ShowWeaponByConfig(data);
UpdateWeaponHangerPosBySkillAction(idSkill);
return true;
}
// Change the color of body
void CECPlayer::SetBodyColor(A3DCOLOR color)
{
if( GetProfession() == PROF_ORC && GetGender() == GENDER_MALE ) // 妖兽男的皮肤不调色
m_CustomizeData.colorBody = 0xffffffff;
else
m_CustomizeData.colorBody = color;
for(int i=0; i<3; i++)
{
if (m_pBodyShader[i])
{
m_pBodyShader[i]->GetGeneralProps().dwTFactor = m_CustomizeData.colorBody;
}
}
}
void CECPlayer::SetBodyHeadScale(unsigned char vScale)
{
m_CustomizeData.headScale = vScale;
UpdateBodyScales();
}
void CECPlayer::SetBodyUpScale(unsigned char vScale)
{
m_CustomizeData.upScale = vScale;
UpdateBodyScales();
}
void CECPlayer::SetBodyWaistScale(unsigned char vScale)
{
m_CustomizeData.waistScale = vScale;
UpdateBodyScales();
}
void CECPlayer::SetBodyArmWidth(unsigned char vScale)
{
m_CustomizeData.armWidth = vScale;
UpdateBodyScales();
}
void CECPlayer::SetBodyLegWidth(unsigned char vScale)
{
m_CustomizeData.legWidth = vScale;
UpdateBodyScales();
}
void CECPlayer::SetBodyBreastScale(unsigned char vScale)
{
m_CustomizeData.breastScale = vScale;
UpdateBodyScales();
}
void CECPlayer::UpdateBodyScales()
{
if (!GetPlayerModel())
return;
A3DSkinModel * pSkinModel = GetPlayerModel()->GetA3DSkinModel();
if( pSkinModel )
{
A3DVECTOR3 vecScale;
A3DSkeleton * pSkeleton = pSkinModel->GetSkeleton();
// head adjust
vecScale.x = 1.0f;
float fHeadScaleYZ = 1.0f;
if (GetProfession() == PROF_YEYING || GetProfession() == PROF_YUEXIAN){
// 玩家使用大头时,Neck 不随头部缩放更易接受。老职业维持原状
fHeadScaleYZ = TransformScaleFromIntToFloat( m_CustomizeData.upScale, m_CustomizeFactor.fScaleUpFactor, SCALE_UP_FACTOR);
}else{
fHeadScaleYZ = TransformScaleFromIntToFloat(m_CustomizeData.headScale, m_CustomizeFactor.fScaleHeadFactor, SCALE_HEAD_FACTOR);
}
vecScale.y = vecScale.z = fHeadScaleYZ;
A3DBone * pBoneNeck = pSkeleton->GetBone("Bip01 Neck", NULL);
if( pBoneNeck )
{
pBoneNeck->SetScaleFactor(vecScale);
pBoneNeck->SetScaleType(A3DBone::SCALE_LOCAL_NOOFFSET);
}
vecScale.x = vecScale.y = vecScale.z = TransformScaleFromIntToFloat( m_CustomizeData.headScale, m_CustomizeFactor.fScaleHeadFactor, SCALE_HEAD_FACTOR);
A3DBone * pBoneHead = pSkeleton->GetBone("Bip01 Head", NULL);
if( pBoneHead )
{
pBoneHead->SetScaleFactor(vecScale);
pBoneHead->SetScaleType(A3DBone::SCALE_WHOLE);
}
if( m_iGender == GENDER_FEMALE )
{
// female's breast adjust
vecScale.x = TransformScaleFromIntToFloat( m_CustomizeData.breastScale, m_CustomizeFactor.fScaleBreastFactor, SCALE_BREAST_FACTOR);
vecScale.y = vecScale.z = TransformScaleFromIntToFloat( m_CustomizeData.breastScale,m_CustomizeFactor.fScaleBreastFactor, SCALE_BREAST_FACTOR);
A3DBone * pBoneFBreast = pSkeleton->GetBone("Bone01", NULL);
if( pBoneFBreast )
{
pBoneFBreast->SetScaleFactor(vecScale);
pBoneFBreast->SetScaleType(A3DBone::SCALE_LOCAL);
}
}
// first adjust clavicles
vecScale.x = TransformScaleFromIntToFloat( m_CustomizeData.upScale, m_CustomizeFactor.fScaleUpFactor, SCALE_UP_FACTOR);
vecScale.y = vecScale.z =TransformScaleFromIntToFloat( m_CustomizeData.upScale, m_CustomizeFactor.fScaleUpFactor, SCALE_UP_FACTOR);
A3DBone * pBoneLClavicle = pSkeleton->GetBone("Bip01 L Clavicle", NULL);
if( pBoneLClavicle )
{
pBoneLClavicle->SetScaleFactor(vecScale);
pBoneLClavicle->SetScaleType(A3DBone::SCALE_LOCAL);
}
A3DBone * pBoneRClavicle = pSkeleton->GetBone("Bip01 R Clavicle", NULL);
if( pBoneRClavicle )
{
pBoneRClavicle->SetScaleFactor(vecScale);
pBoneRClavicle->SetScaleType(A3DBone::SCALE_LOCAL);
}
// then breast
vecScale.x = 1.0f;
vecScale.y = vecScale.z = TransformScaleFromIntToFloat( m_CustomizeData.upScale,m_CustomizeFactor.fScaleUpFactor, SCALE_UP_FACTOR);
A3DBone * pBoneBreast = pSkeleton->GetBone("Bip01 Spine2", NULL);
if( pBoneBreast )
{
pBoneBreast->SetScaleFactor(vecScale);
pBoneBreast->SetScaleType(A3DBone::SCALE_LOCAL);
}
// chest
vecScale.x = 1.0f;
vecScale.y = vecScale.z = TransformScaleFromIntToFloat( m_CustomizeData.upScale,m_CustomizeFactor.fScaleUpFactor, SCALE_UP_FACTOR);
A3DBone * pBoneChest = pSkeleton->GetBone("Bip01 Spine1", NULL);
if( pBoneChest )
{
pBoneChest->SetScaleFactor(vecScale);
pBoneChest->SetScaleType(A3DBone::SCALE_LOCAL);
}
// waist
vecScale.x = 1.0f;
vecScale.y = vecScale.z = TransformScaleFromIntToFloat( m_CustomizeData.waistScale,m_CustomizeFactor.fScaleWaistFactor, SCALE_WAIST_FACTOR);
A3DBone * pBoneWaist = pSkeleton->GetBone("Bip01 Spine", NULL);
if( pBoneWaist )
{
pBoneWaist->SetScaleFactor(vecScale);
pBoneWaist->SetScaleType(A3DBone::SCALE_LOCAL_NOOFFSET);
}
// pelvis
vecScale.x = 1.0f;
vecScale.y = vecScale.z = TransformScaleFromIntToFloat( m_CustomizeData.waistScale,m_CustomizeFactor.fScaleWaistFactor, SCALE_WAIST_FACTOR);
A3DBone * pBonePelvis = pSkeleton->GetBone("Bip01 Pelvis", NULL);
if( pBonePelvis )
{
pBonePelvis->SetScaleFactor(vecScale);
pBonePelvis->SetScaleType(A3DBone::SCALE_LOCAL);
}
// arm
vecScale.x = 1.0f;
vecScale.y = vecScale.z = TransformScaleFromIntToFloat( m_CustomizeData.armWidth,m_CustomizeFactor.fWidthArmFactor, WIDTH_ARM_FACTOR);
A3DBone * pBoneLUpperArm = pSkeleton->GetBone("Bip01 L UpperArm", NULL);
if( pBoneLUpperArm )
{
pBoneLUpperArm->SetScaleFactor(vecScale);
pBoneLUpperArm->SetScaleType(A3DBone::SCALE_LOCAL);
}
A3DBone * pBoneRUpperArm = pSkeleton->GetBone("Bip01 R UpperArm", NULL);
if( pBoneRUpperArm )
{
pBoneRUpperArm->SetScaleFactor(vecScale);
pBoneRUpperArm->SetScaleType(A3DBone::SCALE_LOCAL);
}
A3DBone * pBoneLForeArm = pSkeleton->GetBone("Bip01 L Forearm", NULL);
if( pBoneLForeArm )
{
pBoneLForeArm->SetScaleFactor(vecScale);
pBoneLForeArm->SetScaleType(A3DBone::SCALE_LOCAL);
}
A3DBone * pBoneRForeArm = pSkeleton->GetBone("Bip01 R Forearm", NULL);
if( pBoneRForeArm )
{
pBoneRForeArm->SetScaleFactor(vecScale);
pBoneRForeArm->SetScaleType(A3DBone::SCALE_LOCAL);
}
// leg
vecScale.x = 1.0f;
vecScale.y = vecScale.z = TransformScaleFromIntToFloat( m_CustomizeData.legWidth, m_CustomizeFactor.fWidthLegFactor, WIDTH_ARM_FACTOR);
A3DBone * pBoneLThigh = pSkeleton->GetBone("Bip01 L Thigh", NULL);
if( pBoneLThigh )
{
pBoneLThigh->SetScaleFactor(vecScale);
pBoneLThigh->SetScaleType(A3DBone::SCALE_LOCAL);
}
A3DBone * pBoneRThigh = pSkeleton->GetBone("Bip01 R Thigh", NULL);
if( pBoneRThigh )
{
pBoneRThigh->SetScaleFactor(vecScale);
pBoneRThigh->SetScaleType(A3DBone::SCALE_LOCAL);
}
vecScale.x = 1.0f;
vecScale.y = vecScale.z = TransformScaleFromIntToFloat( m_CustomizeData.legWidth, m_CustomizeFactor.fWidthLegFactor, WIDTH_LEG_FACTOR);
A3DBone * pBoneLCalf = pSkeleton->GetBone("Bip01 L Calf", NULL);
if( pBoneLCalf )
{
pBoneLCalf->SetScaleFactor(vecScale);
pBoneLCalf->SetScaleType(A3DBone::SCALE_LOCAL);
}
A3DBone * pBoneRCalf = pSkeleton->GetBone("Bip01 R Calf", NULL);
if( pBoneRCalf )
{
pBoneRCalf->SetScaleFactor(vecScale);
pBoneRCalf->SetScaleType(A3DBone::SCALE_LOCAL);
}
ScaleBody(m_fScaleBySkill);
}
}
//更新头发模型及贴图(与头盔模型(或时装头饰)显示相关)
void CECPlayer::UpdateHairModel(bool bUpdateAll, int iArmetID)
{
if( (m_iProfession == PROF_ORC) ||
(!m_pFaceModel || !m_pFaceModel->GetFaceData()) ||
(iArmetID == -1))
return;
iArmetID &= 0xffff;
// iArmetID为0时,恢复形象的默认个性化数据
int idHairModel = m_CustomizeData.faceData.idHairModel;
int idHairTex = m_CustomizeData.faceData.idHairTex;
if(iArmetID != 0)
{
// 根据iArmetID找到相应头盔(或时装头饰),读取对应的idHairModel和idHairTex
DATA_TYPE dt;
ARMOR_ESSENCE * pArmorHead = (ARMOR_ESSENCE *) g_pGame->GetElementDataMan()->get_data_ptr(iArmetID, ID_SPACE_ESSENCE, dt);
if(dt != DT_ARMOR_ESSENCE) // 非头盔id,则为时装头饰id
{
FASHION_ESSENCE* pFashionHead = (FASHION_ESSENCE*)g_pGame->GetElementDataMan()->get_data_ptr(iArmetID, ID_SPACE_ESSENCE, dt);
ASSERT(dt == DT_FASHION_ESSENCE);
if(dt == DT_FASHION_ESSENCE && pFashionHead)
{
idHairModel = pFashionHead->id_hair;
idHairTex = pFashionHead->id_hair_texture;
}
}
else if( pArmorHead )
{
if(pArmorHead->id_hair != 0)
idHairModel = pArmorHead->id_hair;
if(pArmorHead->id_hair_texture != 0)
idHairTex = pArmorHead->id_hair_texture;
}
}
m_pFaceModel->GetFaceData()->idHairModel = idHairModel;
m_pFaceModel->GetFaceData()->idHairTex = idHairTex;
if (bUpdateAll)
m_pFaceModel->UpdateAll();
}
bool CECPlayer::ValidateCustomizeData(int nProf, int nGender, PLAYER_CUSTOMIZEDATA &data)
{
bool modified(false);
static const char *s_hairModel[NUM_PROFESSION][2] = {
{"facedata\\武侠男\\预定义\\01武侠男标准1.ini", "facedata\\法师女\\预定义\\武侠女标准1.ini"}, // 武侠
{"facedata\\武侠男\\预定义\\法师男标准1.ini", "facedata\\法师女\\预定义\\01法师女标准1.ini"}, // 法师
{"facedata\\影族男\\预定义\\巫师男标准01.ini", "facedata\\影族女\\预定义\\巫师女标准01.ini"}, // 巫师
{"", "facedata\\法师女\\预定义\\妖精女标准1.ini"}, // 妖精
{"facedata\\妖兽男\\预定义\\妖兽男标准.ini", ""}, // 妖兽
{"facedata\\影族男\\预定义\\刺客男标准01.ini", "facedata\\影族女\\预定义\\刺客女标准01.ini"}, // 刺客
{"facedata\\武侠男\\预定义\\羽灵男标准1.ini", "facedata\\法师女\\预定义\\羽芒女标准1.ini"}, // 羽芒
{"facedata\\武侠男\\预定义\\羽灵男标准1.ini", "facedata\\法师女\\预定义\\羽灵女标准1.ini"}, // 羽灵
{"facedata\\灵族男\\预定义\\剑灵男标准01.ini", "facedata\\灵族女\\预定义\\剑灵女标准01.ini"}, // 剑灵
{"facedata\\灵族男\\预定义\\魅灵男标准01.ini", "facedata\\灵族女\\预定义\\魅灵女标准01.ini"}, // 魅灵
{"facedata\\胧族男\\预定义\\夜影男标准01.ini", "facedata\\胧族女\\预定义\\夜影女标准01.ini"}, // 夜影
{"facedata\\胧族男\\预定义\\月仙男标准01.ini", "facedata\\胧族女\\预定义\\月仙女标准01.ini"}, // 月仙
};
static int s_idHairModel[NUM_PROFESSION][2] = {0};
static int s_idHairTex[NUM_PROFESSION][2] = {0};
static bool s_loaded[NUM_PROFESSION][2];
int &defaultHairModel = s_idHairModel[nProf][nGender];
int &defaultHairTex = s_idHairTex[nProf][nGender];
bool &loaded = s_loaded[nProf][nGender];
// Check and load default hair model and tex
if (!loaded)
{
defaultHairModel = 0;
defaultHairTex = 0;
loaded = true;
// Get from file
const char *szFile = s_hairModel[nProf][nGender];
if (szFile && strlen(szFile)>0)
{
AIniFile IniFile;
if(!IniFile.Open(szFile))
{
a_LogOutput(1, "CECPlayer::ValidateCustomizeData, Failed to open file %s", szFile);
}
else
{
AString strSection = "Hair";
defaultHairModel = IniFile.GetValueAsInt(strSection, "idHairModel", 0);
defaultHairTex = IniFile.GetValueAsInt(strSection, "idHairTex", 0);
IniFile.Close();
}
}
}
elementdataman* pElementDataMan = g_pGame->GetElementDataMan();
unsigned short &idHairModel = data.faceData.idHairModel;
unsigned short &idHairTex = data.faceData.idHairTex;
DATA_TYPE datatype;
if (defaultHairModel && idHairModel)
{
FACE_HAIR_ESSENCE* pEssence = (FACE_HAIR_ESSENCE*)pElementDataMan->get_data_ptr(idHairModel, ID_SPACE_FACE, datatype);
if (pEssence && datatype==DT_FACE_HAIR_ESSENCE && pEssence->fashion_head_only)
{
// Hair model is invalid
a_LogOutput(1, "CECPlayer::ValidateCustomizeData, idHairModel(%d) is invalid and set to default", idHairModel);
idHairModel = defaultHairModel;
modified = true;
}
}
if (defaultHairTex && idHairTex)
{
FACE_TEXTURE_ESSENCE* pEssence = (FACE_TEXTURE_ESSENCE*)pElementDataMan->get_data_ptr(idHairTex, ID_SPACE_FACE, datatype);
if (pEssence && datatype==DT_FACE_TEXTURE_ESSENCE && pEssence->fashion_head_only)
{
// Hair tex is invalid
a_LogOutput(1, "CECPlayer::ValidateCustomizeData, idHairTex(%d) is invalid and set to default", idHairTex);
idHairTex = defaultHairTex;
modified = true;
}
}
// only allowed the third eye in these professions
unsigned short &idThirdEye = data.faceData.idThirdEye;
if( nProf != PROF_MEILING &&
nProf != PROF_JIANLING &&
idThirdEye != 0)
{
a_LogOutput(1, "CECPlayer::ValidateCustomizeData, idThirdEye(%d) is invalid and set to default", idThirdEye);
idThirdEye = 0;
modified = true;
}
return modified;
}
// Change customize data
bool CECPlayer::ChangeCustomizeData(const PLAYER_CUSTOMIZEDATA& data, bool bApply/* true */)
{
if( data.dwVersion >= CUSTOMIZE_DATA_VERSION_1 &&
data.dwVersion <= CUSTOMIZE_DATA_VERSION &&
data.faceData.scaleUp > 0.0f )
{
if( !m_pFaceModel || !GetMajorModel() )
bApply = false;
if (bApply && m_CustomizeData.bodyID != data.bodyID)
{
ASSERT(ShouldUseClothedModel()); // 这里不可能是简单模型模式
// We should reload a new body
if (!LoadBodySkin(data.bodyID))
return false;
if (!LoadFaceModel(m_iProfession, m_iGender, data.bodyID))
{
a_LogOutput(1, "CECPlayer::ChangeCustomizeData, Failed to load face model");
return false;
}
}
m_CustomizeData = data;
// 某些不允许的个性化情况(如时装头巾被用来替换非时装状态下的默认头发)
ValidateCustomizeData(GetProfession(), GetGender(), m_CustomizeData);
if (bApply)
{
if (m_pFaceModel)
m_pFaceModel->SetFaceData(m_CustomizeData.faceData);
if(!InFashionMode())
UpdateHairModel(true);
SetBodyColor(data.colorBody);
UpdateBodyScales();
}
SetResReadyFlag(RESFG_CUSTOM, true);
return true;
}
else
{
if( m_pFaceModel )
m_CustomizeData.faceData = *m_pFaceModel->GetFaceData();
SetResReadyFlag(RESFG_CUSTOM, true);
return false;
}
}
// 更新形象的默认个性化数据
bool CECPlayer::SaveAsDefaultCustomizeData()
{
const CECFace::FACE_CUSTOMIZEDATA& faceData = m_CustomizeData.faceData;
AIniFile IniFile;
char szFile[256];
sprintf(szFile, "userdata\\character\\character%d%d.ini", m_iProfession, m_iGender);
IniFile.Open(szFile);
//3庭3
AString strSection = "3Parts";
IniFile.WriteIntValue(strSection, "scaleUp", faceData.scaleUp);
IniFile.WriteIntValue(strSection, "scaleMiddle", faceData.scaleMiddle);
IniFile.WriteIntValue(strSection, "scaleDown", faceData.scaleDown);
//脸型融合3
strSection = "BlendFace";
IniFile.WriteIntValue(strSection, "idFaceShape1", faceData.idFaceShape1);
IniFile.WriteIntValue(strSection, "idFaceShape2", faceData.idFaceShape2);
IniFile.WriteIntValue(strSection, "blendFaceShape", faceData.blendFaceShape);
//脸盘调整3
strSection = "Face";
IniFile.WriteIntValue(strSection, "scaleFaceH", faceData.scaleFaceH);
IniFile.WriteIntValue(strSection, "scaleFaceV", faceData.scaleFaceV);
IniFile.WriteIntValue(strSection, "idFaceTex", faceData.idFaceTex);
//法令
strSection = "Faling";
IniFile.WriteIntValue(strSection, "idFalingSkin", faceData.idFalingSkin);
IniFile.WriteIntValue(strSection, "idFalingTex", faceData.idFalingTex);
//额头5
strSection = "Forehead";
IniFile.WriteIntValue(strSection, "offsetForeheadH", faceData.offsetForeheadH);
IniFile.WriteIntValue(strSection, "offsetForeheadV", faceData.offsetForeheadV);
IniFile.WriteIntValue(strSection, "offsetForeheadZ", faceData.offsetForeheadZ);
IniFile.WriteIntValue(strSection, "rotateForehead", faceData.rotateForehead);
IniFile.WriteIntValue(strSection, "scaleForehead", faceData.scaleForehead);
//颧骨5
strSection = "YokeBone";
IniFile.WriteIntValue(strSection, "offsetYokeBoneH", faceData.offsetYokeBoneH);
IniFile.WriteIntValue(strSection, "offsetYokeBoneV", faceData.offsetYokeBoneV);
IniFile.WriteIntValue(strSection, "offsetYokeBoneZ", faceData.offsetYokeBoneZ);
IniFile.WriteIntValue(strSection, "rotateYokeBone", faceData.rotateYokeBone);
IniFile.WriteIntValue(strSection, "scaleYokeBone", faceData.scaleYokeBone);
//脸颊4
strSection = "Cheek";
IniFile.WriteIntValue(strSection, "offsetCheekH", faceData.offsetCheekH);
IniFile.WriteIntValue(strSection, "offsetCheekV", faceData.offsetCheekV);
IniFile.WriteIntValue(strSection, "offsetCheekZ", faceData.offsetCheekZ);
IniFile.WriteIntValue(strSection, "scaleCheek", faceData.scaleCheek);
//下巴4
strSection = "Chain";
IniFile.WriteIntValue(strSection, "offsetChainV", faceData.offsetChainV);
IniFile.WriteIntValue(strSection, "offsetChainZ", faceData.offsetChainZ);
IniFile.WriteIntValue(strSection, "rotateChain", faceData.rotateChain);
IniFile.WriteIntValue(strSection, "scaleChainH", faceData.scaleChainH);
//颌骨6
strSection = "Jaw";
IniFile.WriteIntValue(strSection, "offsetJawH", faceData.offsetJawH);
IniFile.WriteIntValue(strSection, "offsetJawV", faceData.offsetJawV);
IniFile.WriteIntValue(strSection, "offsetJawZ", faceData.offsetJawZ);
IniFile.WriteIntValue(strSection, "scaleJawSpecial", faceData.scaleJawSpecial);
IniFile.WriteIntValue(strSection, "scaleJawH", faceData.scaleJawH);
IniFile.WriteIntValue(strSection, "scaleJawV", faceData.scaleJawV);
//眼睛18
strSection = "Eye";
IniFile.WriteIntValue(strSection, "idThirdEye", faceData.idThirdEye);
IniFile.WriteIntValue(strSection, "idEyeBaseTex", faceData.idEyeBaseTex);
IniFile.WriteIntValue(strSection, "idEyeHighTex", faceData.idEyeHighTex);
IniFile.WriteIntValue(strSection, "idEyeBallTex", faceData.idEyeBallTex);
IniFile.WriteIntValue(strSection, "idEyeShape", faceData.idEyeShape);
IniFile.WriteIntValue(strSection, "scaleEyeH", faceData.scaleEyeH);
IniFile.WriteIntValue(strSection, "scaleEyeV", faceData.scaleEyeV);
IniFile.WriteIntValue(strSection, "rotateEye", faceData.rotateEye);
IniFile.WriteIntValue(strSection, "offsetEyeH", faceData.offsetEyeH);
IniFile.WriteIntValue(strSection, "offsetEyeV", faceData.offsetEyeV);
IniFile.WriteIntValue(strSection, "offseteyeZ", faceData.offsetEyeZ);
IniFile.WriteIntValue(strSection, "scaleEyeBall", faceData.scaleEyeBall);
IniFile.WriteIntValue(strSection, "scaleEyeH2", faceData.scaleEyeH2);
IniFile.WriteIntValue(strSection, "scaleEyeV2", faceData.scaleEyeV2);
IniFile.WriteIntValue(strSection, "rotateEye2", faceData.rotateEye2);
IniFile.WriteIntValue(strSection, "offsetEyeH2", faceData.offsetEyeH2);
IniFile.WriteIntValue(strSection, "offsetEyeV2", faceData.offsetEyeV2);
IniFile.WriteIntValue(strSection, "offseteyeZ2", faceData.offsetEyeZ2);
IniFile.WriteIntValue(strSection, "scaleEyeBall2", faceData.scaleEyeBall2);
//眉毛14
strSection = "Brow";
IniFile.WriteIntValue(strSection, "idBrowTex", faceData.idBrowTex);
IniFile.WriteIntValue(strSection, "idBrowShape", faceData.idBrowShape);
IniFile.WriteIntValue(strSection, "scaleBrowH", faceData.scaleBrowH);
IniFile.WriteIntValue(strSection, "scaleBrowV", faceData.scaleBrowV);
IniFile.WriteIntValue(strSection, "rotateBrow", faceData.rotateBrow);
IniFile.WriteIntValue(strSection, "offsetBrowH", faceData.offsetBrowH);
IniFile.WriteIntValue(strSection, "offsetBrowV", faceData.offsetBrowV);
IniFile.WriteIntValue(strSection, "offsetBrowZ", faceData.offsetBrowZ);
IniFile.WriteIntValue(strSection, "scaleBrowH2", faceData.scaleBrowH2);
IniFile.WriteIntValue(strSection, "scaleBrowV2", faceData.scaleBrowV2);
IniFile.WriteIntValue(strSection, "rotateBrow2", faceData.rotateBrow2);
IniFile.WriteIntValue(strSection, "offsetBrowH2", faceData.offsetBrowH2);
IniFile.WriteIntValue(strSection, "offsetBrowV2", faceData.offsetBrowV2);
IniFile.WriteIntValue(strSection, "offsetBrowZ2", faceData.offsetBrowZ2);
//鼻子8
strSection = "Nose";
IniFile.WriteIntValue(strSection, "idNoseTex", faceData.idNoseTex);
IniFile.WriteIntValue(strSection, "idNoseTipShape", faceData.idNoseTipShape);
IniFile.WriteIntValue(strSection, "scaleNoseTipH", faceData.scaleNoseTipH);
IniFile.WriteIntValue(strSection, "scaleNoseTipV", faceData.scaleNoseTipV);
IniFile.WriteIntValue(strSection, "scaleNoseTipZ", faceData.scaleNoseTipZ);
IniFile.WriteIntValue(strSection, "offsetNoseTipV", faceData.offsetNoseTipV);
IniFile.WriteIntValue(strSection, "idNoseBridgeShape", faceData.idNoseBridgeShape);
IniFile.WriteIntValue(strSection, "scaleBridgeTipH", faceData.scaleBridgeTipH);
IniFile.WriteIntValue(strSection, "offsetBridgeTipZ", faceData.offsetBridgeTipZ);
//嘴9
strSection = "Mouth";
IniFile.WriteIntValue (strSection, "idMouthUpLipLine", faceData.idMouthUpLipLine);
IniFile.WriteIntValue(strSection, "idMouthMidLipLine", faceData.idMouthMidLipLine);
IniFile.WriteIntValue(strSection, "idMouthDownLipLine", faceData.idMouthDownLipLine);
IniFile.WriteIntValue(strSection, "thickUpLip", faceData.thickUpLip);
IniFile.WriteIntValue(strSection, "thickDownLip", faceData.thickDownLip);
IniFile.WriteIntValue(strSection, "scaleMouthH", faceData.scaleMouthH);
IniFile.WriteIntValue(strSection, "offsetMouthV", faceData.offsetMouthV);
IniFile.WriteIntValue(strSection, "offsetMOuthZ", faceData.offsetMouthZ);
IniFile.WriteIntValue(strSection, "idMouthTex", faceData.idMouthTex);
IniFile.WriteIntValue(strSection, "offsetCornerOfMouthSpecial", faceData.offsetCornerOfMouthSpecial);
IniFile.WriteIntValue(strSection, "scaleMouthH2", faceData.scaleMouthH2);
IniFile.WriteIntValue(strSection, "offsetCornerOfMouthSpecial2", faceData.offsetCornerOfMouthSpecial2);
//耳朵3
strSection = "Ear";
IniFile.WriteIntValue(strSection, "idEarShape", faceData.idEarShape);
IniFile.WriteIntValue(strSection, "scaleEar", faceData.scaleEar);
IniFile.WriteIntValue(strSection, "offsetEarV", faceData.offsetEarV);
//头发1
strSection = "Hair";
IniFile.WriteIntValue(strSection, "idHairModel", faceData.idHairModel);
IniFile.WriteIntValue(strSection, "idHairTex", faceData.idHairTex);
//胡子2
strSection = "Moustache";
IniFile.WriteIntValue(strSection, "idMoustacheTex", faceData.idMoustacheTex);
IniFile.WriteIntValue(strSection, "idMoustacheSkin", faceData.idMoustacheSkin);
IniFile.WriteIntValue(strSection, "idGoateeTex", faceData.idGoateeTex);
//各部分颜色7
strSection = "Color";
IniFile.WriteIntValue(strSection, "colorHair", faceData.colorHair);
IniFile.WriteIntValue(strSection, "colorFace", faceData.colorFace);
IniFile.WriteIntValue(strSection, "colorEye", faceData.colorEye);
IniFile.WriteIntValue(strSection, "colorBrow", faceData.colorBrow);
IniFile.WriteIntValue(strSection, "colorMouth", faceData.colorMouth);
IniFile.WriteIntValue(strSection, "colorEyeBall", faceData.colorEyeBall);
IniFile.WriteIntValue(strSection, "colorMoustache", faceData.colorMoustache);
//身体参数
strSection = "Body";
IniFile.WriteIntValue(strSection, "bodyID", m_CustomizeData.bodyID);
IniFile.WriteIntValue(strSection, "colorBody", m_CustomizeData.colorBody);
IniFile.WriteIntValue(strSection, "headScale", m_CustomizeData.headScale);
IniFile.WriteIntValue(strSection, "upScale", m_CustomizeData.upScale);
IniFile.WriteIntValue(strSection, "waistScale", m_CustomizeData.waistScale);
IniFile.WriteIntValue(strSection, "armWidth", m_CustomizeData.armWidth);
IniFile.WriteIntValue(strSection, "legWidth", m_CustomizeData.legWidth);
IniFile.WriteIntValue(strSection, "breastScale", m_CustomizeData.breastScale);
IniFile.Save(szFile);
IniFile.Close();
return true;
}
// 载入形象的默认个性化数据
bool CECPlayer::LoadDefaultCustomizeData(int prof, int gender, PLAYER_CUSTOMIZEDATA &data)
{
memset(&data, 0, sizeof(data));
data.dwVersion = CUSTOMIZE_DATA_VERSION;
data.colorBody = 0xffffffff;
data.headScale = 128;
data.upScale = 128;
data.waistScale = 128;
data.armWidth = 128;
data.legWidth = 128;
data.breastScale = 128;
AIniFile IniFile;
char szFile[256];
sprintf(szFile, "userdata\\character\\character%d%d.ini", prof, gender);
if(!IniFile.Open(szFile))
{
a_LogOutput(1, "CECPlayer::LoadDefaultCustomizeData, Failed to open file %s", szFile);
return false;
}
//3庭3
AString strSection = "3Parts";
data.faceData.scaleUp = IniFile.GetValueAsInt(strSection, "scaleUp", data.faceData.scaleUp);
data.faceData.scaleMiddle = IniFile.GetValueAsInt(strSection, "scaleMiddle", data.faceData.scaleMiddle);
data.faceData.scaleDown = IniFile.GetValueAsInt(strSection, "scaleDown", data.faceData.scaleDown);
//脸型融合3
strSection = "BlendFace";
data.faceData.idFaceShape1 = IniFile.GetValueAsInt(strSection, "idFaceShape1", data.faceData.idFaceShape1);
data.faceData.idFaceShape2 = IniFile.GetValueAsInt(strSection, "idFaceShape2", data.faceData.idFaceShape2);
data.faceData.blendFaceShape = IniFile.GetValueAsInt(strSection, "blendFaceShape", data.faceData.blendFaceShape);
//脸盘调整3
strSection = "Face";
data.faceData.scaleFaceH = IniFile.GetValueAsInt(strSection, "scaleFaceH", data.faceData.scaleFaceH);
data.faceData.scaleFaceV = IniFile.GetValueAsInt(strSection, "scaleFaceV", data.faceData.scaleFaceV);
data.faceData.idFaceTex = IniFile.GetValueAsInt(strSection, "idFaceTex", data.faceData.idFaceTex);
//法令
strSection = "Faling";
data.faceData.idFalingSkin = IniFile.GetValueAsInt(strSection, "idFalingSkin", data.faceData.idFalingSkin);
data.faceData.idFalingTex = IniFile.GetValueAsInt(strSection, "idFalingTex", data.faceData.idFalingTex);
//额头5
strSection = "Forehead";
data.faceData.offsetForeheadH = IniFile.GetValueAsInt(strSection, "offsetForeheadH", data.faceData.offsetForeheadH);
data.faceData.offsetForeheadV = IniFile.GetValueAsInt(strSection, "offsetForeheadV", data.faceData.offsetForeheadV);
data.faceData.offsetForeheadZ = IniFile.GetValueAsInt(strSection, "offsetForeheadZ", data.faceData.offsetForeheadZ);
data.faceData.rotateForehead = IniFile.GetValueAsInt(strSection, "rotateForehead", data.faceData.rotateForehead);
data.faceData.scaleForehead = IniFile.GetValueAsInt(strSection, "scaleForehead", data.faceData.scaleForehead);
//颧骨5
strSection = "YokeBone";
data.faceData.offsetYokeBoneH = IniFile.GetValueAsInt(strSection, "offsetYokeBoneH", data.faceData.offsetYokeBoneH);
data.faceData.offsetYokeBoneV = IniFile.GetValueAsInt(strSection, "offsetYokeBoneV", data.faceData.offsetYokeBoneV);
data.faceData.offsetYokeBoneZ = IniFile.GetValueAsInt(strSection, "offsetYokeBoneZ", data.faceData.offsetYokeBoneZ);
data.faceData.rotateYokeBone = IniFile.GetValueAsInt(strSection, "rotateYokeBone", data.faceData.rotateYokeBone);
data.faceData.scaleYokeBone = IniFile.GetValueAsInt(strSection, "scaleYokeBone", data.faceData.scaleYokeBone);
//脸颊4
strSection = "Cheek";
data.faceData.offsetCheekH = IniFile.GetValueAsInt(strSection, "offsetCheekH", data.faceData.offsetCheekH);
data.faceData.offsetCheekV = IniFile.GetValueAsInt(strSection, "offsetCheekV", data.faceData.offsetCheekV);
data.faceData.offsetCheekZ = IniFile.GetValueAsInt(strSection, "offsetCheekZ", data.faceData.offsetCheekZ);
data.faceData.scaleCheek = IniFile.GetValueAsInt(strSection, "scaleCheek", data.faceData.scaleCheek);
//下巴4
strSection = "Chain";
data.faceData.offsetChainV = IniFile.GetValueAsInt(strSection, "offsetChainV", data.faceData.offsetChainV);
data.faceData.offsetChainZ = IniFile.GetValueAsInt(strSection, "offsetChainZ", data.faceData.offsetChainZ);
data.faceData.rotateChain = IniFile.GetValueAsInt(strSection, "rotateChain", data.faceData.rotateChain);
data.faceData.scaleChainH = IniFile.GetValueAsInt(strSection, "scaleChainH", data.faceData.scaleChainH);
//颌骨6
strSection = "Jaw";
data.faceData.offsetJawH = IniFile.GetValueAsInt(strSection, "offsetJawH", data.faceData.offsetJawH);
data.faceData.offsetJawV = IniFile.GetValueAsInt(strSection, "offsetJawV", data.faceData.offsetJawV);
data.faceData.offsetJawZ = IniFile.GetValueAsInt(strSection, "offsetJawZ", data.faceData.offsetJawZ);
data.faceData.scaleJawSpecial = IniFile.GetValueAsInt(strSection, "scaleJawSpecial", data.faceData.scaleJawSpecial);
data.faceData.scaleJawH = IniFile.GetValueAsInt(strSection, "scaleJawH", data.faceData.scaleJawH);
data.faceData.scaleJawV = IniFile.GetValueAsInt(strSection, "scaleJawV", data.faceData.scaleJawV);
//眼睛18
strSection = "Eye";
data.faceData.idThirdEye = IniFile.GetValueAsInt(strSection, "idThirdEye", data.faceData.idThirdEye);
data.faceData.idEyeBaseTex = IniFile.GetValueAsInt(strSection, "idEyeBaseTex", data.faceData.idEyeBaseTex);
data.faceData.idEyeHighTex = IniFile.GetValueAsInt(strSection, "idEyeHighTex", data.faceData.idEyeHighTex);
data.faceData.idEyeBallTex = IniFile.GetValueAsInt(strSection, "idEyeBallTex", data.faceData.idEyeBallTex);
data.faceData.idEyeShape = IniFile.GetValueAsInt(strSection, "idEyeShape", data.faceData.idEyeShape);
data.faceData.scaleEyeH = IniFile.GetValueAsInt(strSection, "scaleEyeH", data.faceData.scaleEyeH);
data.faceData.scaleEyeV = IniFile.GetValueAsInt(strSection, "scaleEyeV", data.faceData.scaleEyeV);
data.faceData.rotateEye = IniFile.GetValueAsInt(strSection, "rotateEye", data.faceData.rotateEye);
data.faceData.offsetEyeH = IniFile.GetValueAsInt(strSection, "offsetEyeH", data.faceData.offsetEyeH);
data.faceData.offsetEyeV = IniFile.GetValueAsInt(strSection, "offsetEyeV", data.faceData.offsetEyeV);
data.faceData.offsetEyeZ = IniFile.GetValueAsInt(strSection, "offseteyeZ", data.faceData.offsetEyeZ);
data.faceData.scaleEyeBall = IniFile.GetValueAsInt(strSection, "scaleEyeBall", data.faceData.scaleEyeBall);
data.faceData.scaleEyeH2 = IniFile.GetValueAsInt(strSection, "scaleEyeH2", data.faceData.scaleEyeH2);
data.faceData.scaleEyeV2 = IniFile.GetValueAsInt(strSection, "scaleEyeV2", data.faceData.scaleEyeV2);
data.faceData.rotateEye2= IniFile.GetValueAsInt(strSection, "rotateEye2", data.faceData.rotateEye2);
data.faceData.offsetEyeH2 = IniFile.GetValueAsInt(strSection, "offsetEyeH2", data.faceData.offsetEyeH2);
data.faceData.offsetEyeV2 = IniFile.GetValueAsInt(strSection, "offsetEyeV2", data.faceData.offsetEyeV2);
data.faceData.offsetEyeZ2 = IniFile.GetValueAsInt(strSection, "offseteyeZ2", data.faceData.offsetEyeZ2);
data.faceData.scaleEyeBall2 = IniFile.GetValueAsInt(strSection, "scaleEyeBall2", data.faceData.scaleEyeBall2);
//眉毛14
strSection = "Brow";
data.faceData.idBrowTex = IniFile.GetValueAsInt(strSection, "idBrowTex", data.faceData.idBrowTex);
data.faceData.idBrowShape = IniFile.GetValueAsInt(strSection, "idBrowShape", data.faceData.idBrowShape);
data.faceData.scaleBrowH = IniFile.GetValueAsInt(strSection, "scaleBrowH", data.faceData.scaleBrowH);
data.faceData.scaleBrowV = IniFile.GetValueAsInt(strSection, "scaleBrowV", data.faceData.scaleBrowV);
data.faceData.rotateBrow = IniFile.GetValueAsInt(strSection, "rotateBrow", data.faceData.rotateBrow);
data.faceData.offsetBrowH = IniFile.GetValueAsInt(strSection, "offsetBrowH", data.faceData.offsetBrowH);
data.faceData.offsetBrowV = IniFile.GetValueAsInt(strSection, "offsetBrowV", data.faceData.offsetBrowV);
data.faceData.offsetBrowZ = IniFile.GetValueAsInt(strSection, "offsetBrowZ", data.faceData.offsetBrowZ);
data.faceData.scaleBrowH2 = IniFile.GetValueAsInt(strSection, "scaleBrowH2", data.faceData.scaleBrowH2);
data.faceData.scaleBrowV2 = IniFile.GetValueAsInt(strSection, "scaleBrowV2", data.faceData.scaleBrowV2);
data.faceData.rotateBrow2 = IniFile.GetValueAsInt(strSection, "rotateBrow2", data.faceData.rotateBrow2);
data.faceData.offsetBrowH2 = IniFile.GetValueAsInt(strSection, "offsetBrowH2", data.faceData.offsetBrowH2);
data.faceData.offsetBrowV2 = IniFile.GetValueAsInt(strSection, "offsetBrowV2", data.faceData.offsetBrowV2);
data.faceData.offsetBrowZ2 = IniFile.GetValueAsInt(strSection, "offsetBrowZ2", data.faceData.offsetBrowZ2);
//鼻子9
strSection = "Nose";
data.faceData.idNoseTex = IniFile.GetValueAsInt(strSection, "idNoseTex", data.faceData.idNoseTex);
data.faceData.idNoseTipShape = IniFile.GetValueAsInt(strSection, "idNoseTipShape", data.faceData.idNoseTipShape);
data.faceData.scaleNoseTipH = IniFile.GetValueAsInt(strSection, "scaleNoseTipH", data.faceData.scaleNoseTipH);
data.faceData.scaleNoseTipV = IniFile.GetValueAsInt(strSection, "scaleNoseTipV", data.faceData.scaleNoseTipV);
data.faceData.scaleNoseTipZ = IniFile.GetValueAsInt(strSection, "scaleNoseTipZ", data.faceData.scaleNoseTipZ);
data.faceData.offsetNoseTipV = IniFile.GetValueAsInt(strSection, "offsetNoseTipV", data.faceData.offsetNoseTipV);
data.faceData.idNoseBridgeShape = IniFile.GetValueAsInt(strSection, "idNoseBridgeShape", data.faceData.idNoseBridgeShape);
data.faceData.scaleBridgeTipH = IniFile.GetValueAsInt(strSection, "scaleBridgeTipH", data.faceData.scaleBridgeTipH);
data.faceData.offsetBridgeTipZ = IniFile.GetValueAsInt(strSection, "OffsetBridgeTipZ", data.faceData.offsetBridgeTipZ);
//嘴9
strSection = "Mouth";
data.faceData.idMouthUpLipLine = IniFile.GetValueAsInt (strSection, "idMouthUpLipLine", data.faceData.idMouthUpLipLine);
data.faceData.idMouthMidLipLine = IniFile.GetValueAsInt(strSection, "idMouthMidLipLine", data.faceData.idMouthMidLipLine);
data.faceData.idMouthDownLipLine = IniFile.GetValueAsInt(strSection, "idMouthDownLipLine", data.faceData.idMouthDownLipLine);
data.faceData.thickUpLip = IniFile.GetValueAsInt(strSection, "thickUpLip", data.faceData.thickUpLip);
data.faceData.thickDownLip = IniFile.GetValueAsInt(strSection, "thickDownLip", data.faceData.thickDownLip);
data.faceData.scaleMouthH = IniFile.GetValueAsInt(strSection, "scaleMouthH", data.faceData.scaleMouthH);
data.faceData.offsetMouthV = IniFile.GetValueAsInt(strSection, "offsetMouthV", data.faceData.offsetMouthV);
data.faceData.offsetMouthZ = IniFile.GetValueAsInt(strSection, "offsetMOuthZ", data.faceData.offsetMouthZ);
data.faceData.idMouthTex = IniFile.GetValueAsInt(strSection, "idMouthTex", data.faceData.idMouthTex);
data.faceData.offsetCornerOfMouthSpecial = IniFile.GetValueAsInt(strSection, "offsetCornerOfMouthSpecial", data.faceData.offsetCornerOfMouthSpecial);
data.faceData.scaleMouthH2 = IniFile.GetValueAsInt(strSection, "scaleMouthH2", data.faceData.scaleMouthH2);
data.faceData.offsetCornerOfMouthSpecial2 = IniFile.GetValueAsInt(strSection, "offsetCornerOfMouthSpecial2", data.faceData.offsetCornerOfMouthSpecial2);
//耳朵3
strSection = "Ear";
data.faceData.idEarShape = IniFile.GetValueAsInt(strSection, "idEarShape", data.faceData.idEarShape);
data.faceData.scaleEar = IniFile.GetValueAsInt(strSection, "scaleEar", data.faceData.scaleEar);
data.faceData.offsetEarV = IniFile.GetValueAsInt(strSection, "offsetEarV", data.faceData.offsetEarV);
//头发1
strSection = "Hair";
data.faceData.idHairModel = IniFile.GetValueAsInt(strSection, "idHairModel", data.faceData.idHairModel);
data.faceData.idHairTex = IniFile.GetValueAsInt(strSection, "idHairTex", data.faceData.idHairTex);
//胡子2
strSection = "Moustache";
data.faceData.idMoustacheTex = IniFile.GetValueAsInt(strSection, "idMoustacheTex", data.faceData.idMoustacheTex);
data.faceData.idMoustacheSkin = IniFile.GetValueAsInt(strSection, "idMoustacheSkin", data.faceData.idMoustacheSkin);
data.faceData.idGoateeTex = IniFile.GetValueAsInt(strSection, "idGoateeTex", data.faceData.idGoateeTex);
//各部分颜色7
strSection = "Color";
data.faceData.colorHair = IniFile.GetValueAsInt(strSection, "colorHair", data.faceData.colorHair);
data.faceData.colorFace = IniFile.GetValueAsInt(strSection, "colorFace", data.faceData.colorFace);
data.faceData.colorEye = IniFile.GetValueAsInt(strSection, "colorEye", data.faceData.colorEye);
data.faceData.colorBrow = IniFile.GetValueAsInt(strSection, "colorBrow", data.faceData.colorBrow);
data.faceData.colorMouth = IniFile.GetValueAsInt(strSection, "colorMouth", data.faceData.colorMouth);
data.faceData.colorEyeBall = IniFile.GetValueAsInt(strSection, "colorEyeBall", data.faceData.colorEyeBall);
data.faceData.colorMoustache = IniFile.GetValueAsInt(strSection, "colorMoustache", data.faceData.colorMoustache);
// 身体参数
strSection = "Body";
data.bodyID = IniFile.GetValueAsInt(strSection, "bodyID", data.bodyID);
data.colorBody = IniFile.GetValueAsInt(strSection, "colorBody", data.colorBody);
data.headScale = IniFile.GetValueAsInt(strSection, "headScale", data.headScale);
data.upScale = IniFile.GetValueAsInt(strSection, "upScale", data.upScale);
data.waistScale = IniFile.GetValueAsInt(strSection, "waistScale", data.waistScale);
data.armWidth = IniFile.GetValueAsInt(strSection, "armWidth", data.armWidth);
data.legWidth = IniFile.GetValueAsInt(strSection, "legWidth", data.legWidth);
data.breastScale = IniFile.GetValueAsInt(strSection, "breastScale", data.breastScale);
IniFile.Close();
return true;
}
// Store player's customize data for later restore
void CECPlayer::StoreCustomizeData()
{
memcpy(&m_OldCustomizeData, &m_CustomizeData, sizeof(PLAYER_CUSTOMIZEDATA));
}
// Retore player's customize data
void CECPlayer::RestoreCustomizeData()
{
ChangeCustomizeData(m_OldCustomizeData);
}
// Show / hide wing
void CECPlayer::ShowWing(bool bShow)
{
if (m_pPlayerModel)
{
CECModel* pWing = m_pPlayerModel->GetChildModel(_wing);
if (pWing) pWing->Show(bShow);
CECModel* pWing2 = m_pPlayerModel->GetChildModel(_wing2);
if (pWing2) pWing2->Show(bShow);
}
}
enumWingType CECPlayer::FlyMode2WingType(unsigned int flymode) {
switch (flymode){
case 0:
return WINGTYPE_FLYSWORD;
case 1:
return WINGTYPE_WING;
case 2:
return WINGTYPE_DOUBLEWHEEL;
default:
ASSERT(false && AString().Format("unknow fly mode: %d", flymode));
return WINGTYPE_FLYSWORD;
}
}
// Show / hide wing
void CECPlayer::ShowWeapon(bool bShow)
{
if (m_pPlayerModel)
{
CECModel* pLeftHandWeapon = GetLeftHandWeapon();
if (pLeftHandWeapon)
pLeftHandWeapon->Show(bShow);
CECModel* pRightHandWeapon = GetRightHandWeapon();
if (pRightHandWeapon)
pRightHandWeapon->Show(bShow);
}
}
void CECPlayer::ShowWeaponByConfig(const PLAYER_ACTION_INFO_CONFIG *p){
m_bShowWeapon = p->hide_weapon ? false : true;
ShowWeapon(m_bShowWeapon);
}
// Add money amount
int CECPlayer::AddMoneyAmount(int iAmount)
{
m_iMoneyCnt += iAmount;
if (m_iMoneyCnt < 0)
{
g_pGame->RuntimeDebugInfo(RTDCOL_WARNING, _AL("Player money is negative"));
m_iMoneyCnt = 0;
}
return m_iMoneyCnt;
}
// Render titles / names / talks above player's header
bool CECPlayer::RenderName(CECViewport* pViewport, DWORD dwFlags)
{
if (!FillPateContent(pViewport))
return true;
AUIManager* pUIMan = g_pGame->GetGameRun()->GetUIManager()->GetCurrentUIManPtr();
float fScale = CECPateText::GetRenderScale();
CECImageRes* pImageRes = g_pGame->GetImageRes();
int x, y=int(m_PateContent.iCurY-20*fScale);
int cx, cy;
int title_cx(0), title_cy(0),name_cx(0), name_cy(0);
bool bTitleAfter(true);
// Decide name color
DWORD dwNameCol = GetNameColor();
bool bRenderName = GetShowName();
const TITLE_CONFIG* pTitle = GetTitleConfig(m_TitleID);
// get title size
if (pTitle) {
m_pPateTitle->GetExtent(&title_cx, &title_cy);
title_cx = int(title_cx * fScale);
title_cy = int(title_cy * fScale);
bTitleAfter = pTitle->after_name != 0;
}
// Draw name string
if (bRenderName && m_pPateName && (dwFlags & RNF_NAME))
{
if (g_pGame->GetPrivilege()->Has_Toggle_NameID())
{
ACString strText;
if (g_pGame->GetConfigs()->GetShowIDFlag())
strText.Format(_AL("%u"), m_PlayerInfo.cid);
else
strText = m_strName;
m_pPateName->SetText(strText, false);
}
m_pPateName->GetExtent(&cx, &cy);
name_cx = cx = int(cx * fScale);
name_cy = cy = int(cy * fScale);
x = m_PateContent.iBaseX - ((cx + title_cx + GAP_BETWEEN_NAME_TITLE) >> 1);
// m_pPateName->Render(pViewport, x, y+2, dwNameCol, m_PateContent.z);
m_pPateName->RegisterRender(bTitleAfter ? x : x + title_cx + GAP_BETWEEN_NAME_TITLE, y+2, dwNameCol, m_PateContent.z);
int tx = x + cx + title_cx + GAP_BETWEEN_NAME_TITLE + 4;
// Draw team leader icon
// TODO: It's better to use m_pTeam rather host's team object, but in
// current version, else player's m_pTeam is always NULL
CECTeam* pTeam = g_pGame->GetGameRun()->GetHostPlayer()->GetTeam();
if (pTeam)
{
int iIcon = -1;
if (pTeam->GetLeaderID() == m_PlayerInfo.cid)
iIcon = CECImageRes::IMG_TEAMLEADER;
else if (pTeam->GetMemberByID(m_PlayerInfo.cid))
iIcon = CECImageRes::IMG_TEAMMATE;
if (iIcon >= 0)
{
pImageRes->GetImageItemSize(iIcon, 0, &cx, &cy);
cx = int(cx * fScale);
cy = int(cy * fScale);
pImageRes->RegisterDraw(iIcon, tx, y, 0xffffffff, 0, m_PateContent.z);
tx += cx;
}
}
// Draw PK state flag
if (m_pvp.bInPVPCombat)
{
pImageRes->GetImageItemSize(CECImageRes::IMG_PKSTATE, 0, &cx, &cy);
cx = int(cx * fScale);
cy = int(cy * fScale);
pImageRes->RegisterDraw(CECImageRes::IMG_PKSTATE, tx, y, 0xffffffff, 0, m_PateContent.z);
tx += cx;
}
// Draw GM flag
if (IsGM())
{
pImageRes->GetImageItemSize(CECImageRes::IMG_GMFLAG, 0, &cx, &cy);
cx = int(cx * fScale);
cy = int(cy * fScale);
pImageRes->RegisterDraw(CECImageRes::IMG_GMFLAG, tx, y, 0xffffffff, 0, m_PateContent.z);
tx += cx;
}
}
// Draw title
if (bRenderName && m_pPateTitle && pTitle && (dwFlags & RNF_NAME))
{
m_pPateTitle->Clear();
m_pPateTitle->GetExtent(&cx, &cy);
cx = int(cx * fScale);
cy = int(cy * fScale);
if (bTitleAfter)
x = m_PateContent.iBaseX - ((cx + name_cx + GAP_BETWEEN_NAME_TITLE) >> 1) + name_cx + GAP_BETWEEN_NAME_TITLE;
else x = m_PateContent.iBaseX - ((cx + name_cx + GAP_BETWEEN_NAME_TITLE) >> 1);
m_pPateTitle->SetText(pTitle->name, false);
m_pPateTitle->RegisterRender(x, y + 2, pTitle->color ? pTitle->color : dwNameCol, m_PateContent.z);
}
// Does player join a faction ?
if (bRenderName && m_idFaction && m_pPateFaction && (dwFlags & RNF_NAME))
{
// Check faction name
if (!m_pPateFaction->GetItemNum())
{
ACString strText;
_BuildPateFactionText(m_idFaction, m_idFRole, strText);
m_pPateFaction->SetText(strText, false, false);
}
// Draw faction icon and name
if (m_pPateFaction->GetItemNum())
{
// Get text size
m_pPateFaction->GetExtent(&cx, &cy);
cx = int(cx * fScale);
cy = int(cy * fScale);
// Get icon size
int cx1=0, cy1=0;
if (m_pFactionDecal)
{
m_pFactionDecal->GetExtent(&cx1, &cy1);
cx1 = int(cx1 * fScale);
cy1 = int(cy1 * fScale);
}
// Reset line height
int ty, lh = a_Max(cy, cy1); // Line height
// Calculate start position
x = m_PateContent.iBaseX - ((cx + cx1) >> 1);
y -= lh + 2;
if (m_pFactionDecal)
{
// Draw faction icon
ty = y + ((lh - cy1) >> 1);
m_pFactionDecal->SetZValue(m_PateContent.z);
m_pFactionDecal->SetScreenPos(x, ty);
m_pFactionDecal->SetScaleX(fScale);
m_pFactionDecal->SetScaleY(fScale);
m_pFactionDecal->Render(pViewport);
x += cx1 + 2;
}
// Draw faction name
DWORD dwFactionCol = dwNameCol;
if (IsInFactionPVP()){
dwFactionCol = NAMECOL_FACTION_PVP;
}else{
CECFactionMan *pFMan = g_pGame->GetFactionMan();
if (pFMan->IsFactionAlliance(GetFactionID()))
dwFactionCol = NAMECOL_ALLIANCE;
else if (pFMan->IsFactionHostile(GetFactionID()))
dwFactionCol = NAMECOL_HOSTILE;
}
ty = y + ((lh - cy) >> 1);
m_pPateFaction->RegisterRender(x, ty, dwFactionCol, m_PateContent.z);
}
}
// Draw marry
if (bRenderName && m_pPateMarry && (dwFlags & RNF_TITLE) && GetSpouse())
{
m_pPateMarry->Clear();
if( GetGender() == 0 )
{
ACString strTitle;
const wchar_t * szSpouseName = g_pGame->GetGameRun()->GetPlayerName(GetSpouse(), false);
if( szSpouseName )
{
strTitle.Format(g_pGame->GetItemDesc()->GetWideString(ITEMDESC_SPOUSE_MALE), szSpouseName);
m_pPateMarry->SetText(strTitle, false, false);
}
}
else
{
ACString strTitle;
const wchar_t * szSpouseName = g_pGame->GetGameRun()->GetPlayerName(GetSpouse(), false);
if( szSpouseName )
{
strTitle.Format(g_pGame->GetItemDesc()->GetWideString(ITEMDESC_SPOUSE_FEMALE), szSpouseName);
m_pPateMarry->SetText(strTitle, false, false);
}
}
m_pPateMarry->GetExtent(&cx, &cy);
cx = int(cx * fScale);
cy = int(cy * fScale);
y -= cy + 2;
x = m_PateContent.iBaseX - (cx >> 1);
m_pPateMarry->RegisterRender(x, y, 0xffffffff, m_PateContent.z);
}
// Draw Force Name
if (bRenderName && GetForce() && m_pPateForce && (dwFlags & RNF_FORCE))
{
// search the data essence
DATA_TYPE DataType = DT_INVALID;
const FORCE_CONFIG* pConfig =
(const FORCE_CONFIG*)g_pGame->GetElementDataMan()->get_data_ptr(GetForce(), ID_SPACE_CONFIG, DataType);
if (DataType == DT_FORCE_CONFIG && pConfig)
{
m_pPateForce->SetText(pConfig->name, false, false);
m_pPateForce->GetExtent(&cx, &cy);
cx = int(cx * fScale);
cy = int(cy * fScale);
y -= cy + 2;
x = m_PateContent.iBaseX - (cx >> 1);
m_pPateForce->RegisterRender(x, y, 0xffff00ff, m_PateContent.z);
}
}
if (GetCountry() && m_pPateCountry)
{
if (m_pPateCountry->GetItemNum())
{
// Get text size
m_pPateCountry->GetExtent(&cx, &cy);
cx = int(cx * fScale);
cy = int(cy * fScale);
// Get icon size
int cx1=0, cy1=0;
if (m_pCountryDecal)
{
m_pCountryDecal->GetExtent(&cx1, &cy1);
cx1 = int(cx1 * fScale);
cy1 = int(cy1 * fScale);
}
// Reset line height
int ty, lh = a_Max(cy, cy1); // Line height
// Calculate start position
x = m_PateContent.iBaseX - ((cx + cx1) >> 1);
y -= lh + 2;
if (m_pCountryDecal)
{
// Draw faction icon
ty = y + ((lh - cy1) >> 1);
m_pCountryDecal->SetZValue(m_PateContent.z);
m_pCountryDecal->SetScreenPos(x, ty);
m_pCountryDecal->SetScaleX(fScale);
m_pCountryDecal->SetScaleY(fScale);
m_pCountryDecal->Render(pViewport);
x += cx1 + 2;
}
// Draw country name
ty = y + ((lh - cy) >> 1);
m_pPateCountry->RegisterRender(x, ty, IsInBattle() ? dwNameCol : NAMECOL_WHITE, m_PateContent.z);
}
}
if( IsKing() )
{
CECGameUIMan* pGameUI = g_pGame->GetGameRun()->GetUIManager()->GetInGameUIMan();
ACString strKing = pGameUI->GetStringFromTable(10303);
pImageRes->GetImageItemSize(CECImageRes::IMG_KING, 0, &cx, &cy);
cx = int(cx * fScale);
cy = int(cy * fScale);
int w, h;
A3DFont* pFont = g_pGame->GetFont(RES_FONT_TITLE);
if( pFont )
{
pFont->GetTextExtent(strKing, strKing.GetLength(), &w, &h);
w += cx;
y -= cy + 2;
x = m_PateContent.iBaseX - (w >> 1);
pImageRes->RegisterDraw(CECImageRes::IMG_KING, x, y, 0xffffffff, 0, m_PateContent.z);
pFont->TextOut(x + cx + 2, y + cy - h, strKing, 0xffff00ff, 0, m_PateContent.z, true);
}
}
if (dwFlags & RNF_WORDS)
{
// Draw last said words, line 2 first
if (m_pPateLastWords2 && m_pPateLastWords2->GetItemNum())
{
m_pPateLastWords1->GetExtent(&cx, &cy);
cx = int(cx * fScale);
cy = int(cy * fScale);
y -= cy + 2;
x = m_PateContent.iBaseX - (cx >> 1);
// m_pPateLastWords2->Render(pViewport, x, y, 0xffffffff, m_PateContent.z);
m_pPateLastWords2->RegisterRender(x, y, 0xffffffff, m_PateContent.z);
}
// Last said words, line 1
if (m_pPateLastWords1 && m_pPateLastWords1->GetItemNum())
{
m_pPateLastWords1->GetExtent(&cx, &cy);
cx = int(cx * fScale);
cy = int(cy * fScale);
y -= cy + 2;
x = m_PateContent.iBaseX - (cx >> 1);
// m_pPateLastWords1->Render(pViewport, x, y, 0xffffffff, m_PateContent.z);
m_pPateLastWords1->RegisterRender(x, y, 0xffffffff, m_PateContent.z);
}
}
// Draw trade words / team requirement
if (m_iBoothState == 2 && ((dwFlags & RNF_BUY) || (dwFlags & RNF_SELL)))
{
/*
if (m_pPateBooth && m_pPateBooth->GetItemNum())
y = RenderBoothName(pViewport, y);*/
if (m_pPateBooth && m_pPateBooth->GetItemNum())
{
m_pPateBooth->GetExtent(&cx, &cy);
cx = int(cx * fScale);
cy = int(cy * fScale);
y -= cy + 6;
x = m_PateContent.iBaseX - (cx >> 1);
// m_pPateBooth->Render(pViewport, x, y, A3DCOLORRGB(255, 156, 0), m_PateContent.z);
m_pPateBooth->RegisterRender(x, y, A3DCOLORRGB(255, 156, 0), m_PateContent.z);
}
}
else if (m_TeamReq.bShowReq && m_pPateTeamReq && m_pPateTeamReq->GetItemNum())
{
m_pPateTeamReq->GetExtent(&cx, &cy);
cx = int(cx * fScale);
cy = int(cy * fScale);
y -= cy + 2;
x = m_PateContent.iBaseX - (cx >> 1);
// m_pPateTeamReq->Render(pViewport, x, y, A3DCOLORRGB(255, 228, 0), m_PateContent.z);
m_pPateTeamReq->RegisterRender(x, y, A3DCOLORRGB(255, 228, 0), m_PateContent.z);
}
m_PateContent.iCurY = y;
return true;
}
// Render booth name
int CECPlayer::RenderBoothName(CECViewport* pViewport, int y)
{
AUIManager* pUIMan = g_pGame->GetGameRun()->GetUIManager()->GetCurrentUIManPtr();
float fScale = CECPateText::GetRenderScale();
int cx, cy, cx1, cy1;
m_pPateBooth->GetExtent(&cx, &cy);
cx = int(cx * fScale);
cy = int(cy * fScale);
// Draw background
cx1 = cx + 10;
cy1 = cy + 10;
y -= cy1 + 2;
int iNewY = y;
int x = m_PateContent.iBaseX - (cx1 >> 1);
float z = m_PateContent.z + 0.00001f;
CECImageRes* pImageRes = g_pGame->GetImageRes();
DWORD dwCol = 0xffffffff;
pImageRes->DrawImage(CECImageRes::IMG_BOOTHBAR, x, y, dwCol, 0, z, 5, 5);
pImageRes->DrawImage(CECImageRes::IMG_BOOTHBAR, x+5, y, dwCol, 1, z, cx, 5);
pImageRes->DrawImage(CECImageRes::IMG_BOOTHBAR, x+5+cx, y, dwCol, 2, z, 5, 5);
pImageRes->DrawImage(CECImageRes::IMG_BOOTHBAR, x, y+5, dwCol, 3, z, 5, cy);
pImageRes->DrawImage(CECImageRes::IMG_BOOTHBAR, x+5, y+5, dwCol, 4, z, cx, cy);
pImageRes->DrawImage(CECImageRes::IMG_BOOTHBAR, x+5+cx, y+5, dwCol, 5, z, 5, cy);
pImageRes->DrawImage(CECImageRes::IMG_BOOTHBAR, x, y+5+cy, dwCol, 6, z, 5, 5);
pImageRes->DrawImage(CECImageRes::IMG_BOOTHBAR, x+5, y+5+cy, dwCol, 7, z, cx, 5);
pImageRes->DrawImage(CECImageRes::IMG_BOOTHBAR, x+5+cx, y+5+cy, dwCol, 8, z, 5, 5);
// Draw text
y += 5;
x = m_PateContent.iBaseX - (cx >> 1);
// m_pPateBooth->Render(pViewport, x, y, A3DCOLORRGB(255, 203, 74), m_PateContent.z);
m_pPateBooth->RegisterRender(x, y, A3DCOLORRGB(255, 203, 74), m_PateContent.z);
return iNewY;
}
// Render bar above player's header
bool CECPlayer::RenderBars(CECViewport* pViewport)
{
if (!FillPateContent(pViewport))
return true;
int x, y, cx=100, cy=3;
A3DFlatCollector* pFlat = g_pGame->GetA3DEngine()->GetA3DFlatCollector();
CECConfigs* pConfigs = g_pGame->GetConfigs();
DWORD colEmpty = A3DCOLORRGB(234, 159, 90);
x = m_PateContent.iBaseX - (cx >> 1);
y = m_PateContent.iCurY - 3;
if (IsHostPlayer())
{
// Draw exp bar
if (false/*pConfigs->GetVideoSettings().bPlayerEXP*/)
{
if (m_BasicProps.iExp < 0)
pFlat->AddRect_2D(x, y, x+cx-1, y+cy-1, colEmpty);
else
{
int iLen = (int)ceil(cx * ((float)m_BasicProps.iExp / GetLevelUpExp(m_BasicProps.iLevel)));
pFlat->AddRect_2D(x, y, x+cx-1, y+cy-1, colEmpty);
pFlat->AddRect_2D(x, y, x+iLen-1, y+cy-1, A3DCOLORRGB(249, 44, 255));
}
y -= cy + 1;
}
// Draw MP bar
if (pConfigs->GetVideoSettings().bPlayerMP)
{
if (m_ExtProps.bs.max_mp && m_BasicProps.iCurMP)
{
int iLen = (int)ceil(cx * ((float)m_BasicProps.iCurMP / m_ExtProps.bs.max_mp));
a_Clamp(iLen, 1, cx);
pFlat->AddRect_2D(x, y, x+cx-1, y+cy-1, colEmpty);
pFlat->AddRect_2D(x, y, x+iLen-1, y+cy-1, A3DCOLORRGB(57, 151, 255));
}
y -= cy + 1;
}
}
// Draw HP bar
if (pConfigs->GetVideoSettings().bPlayerHP)
{
if (m_ExtProps.bs.max_hp && m_BasicProps.iCurHP)
{
int iLen = (int)ceil(cx * ((float)m_BasicProps.iCurHP / m_ExtProps.bs.max_hp));
a_Clamp(iLen, 1, cx);
pFlat->AddRect_2D(x, y, x+cx-1, y+cy-1, colEmpty);
pFlat->AddRect_2D(x, y, x+iLen-1, y+cy-1, A3DCOLORRGB(255, 57, 62));
}
y -= cy + 1;
}
m_PateContent.iCurY = y;
return true;
}
// Fill pate content
// Return false if pate content is un-visible
bool CECPlayer::FillPateContent(CECViewport* pViewport)
{
// If m_PateContent.iVisible != 0, pate content has been filled
// for this frame
if (m_PateContent.iVisible)
return m_PateContent.iVisible == 2 ? true : false;
A3DVIEWPORTPARAM* pViewPara = pViewport->GetA3DViewport()->GetParam();
// Calculate basic center position on screen
A3DVECTOR3 vPos;
if (m_iBoothState == 2 && GetBoothModel() && GetBoothModel()->HasCHAABB()){
vPos = m_aabb.Center + g_vAxisY * GetBoothModel()->GetCHAABB().Extents.y * 1.15f;
}else{
if (IsInChariot()){
vPos = m_aabb.Center + g_vAxisY * GetDummyModel(PLAYERMODEL_DUMMYTYPE2)->GetModelAABB().Extents.y * 2.f;
}else{
vPos = m_aabb.Center + g_vAxisY * m_aabb.Extents.y;
}
if (GetGender() == GENDER_MALE){ // 男模型比较高,拉近时名字容易嵌到身体里面
vPos.y += 0.1f;
}
}
if((IsRidingOnPet() && m_pPetModel))
{
const A3DAABB &aabb = GetPlayerPickAABB();
vPos = aabb.Center + A3DVECTOR3(0, aabb.Extents.y, 0);
}
// 打坐使用特殊模型时,名字需要抬高位置 by SunXuewei 2009-11-18
if(IsSitting() && (GetRace() == RACE_GHOST || GetRace() == RACE_OBORO))
{ //头像上的名字
static float scaleRatio[NUM_RACE][NUM_GENDER] =
{{0.0f, 0.0f}, // 人类
{0.0f, 0.0f}, // 妖族
{0.0f, 0.0f}, // 羽人
{1.0f, 0.5f}, // 汐族
{0.0f, 0.0f}, // 灵族
{1.0f, 1.0f}, // 胧族
};
vPos.y += m_aabb.Extents.y * scaleRatio[GetRace()][GetGender()];
}
// 胧族飞行时,名字需要抬高位置
if (IsFlying() && GetRace() == RACE_OBORO) {
vPos.y += m_aabb.Extents.y * 0.5f;
}
A3DVECTOR3 vScrPos;
pViewport->GetA3DViewport()->Transform(vPos, vScrPos);
if (vScrPos.z < pViewPara->MinZ || vScrPos.z > pViewPara->MaxZ)
{
m_PateContent.iVisible = 1; // In-visible
return false;
}
m_PateContent.iVisible = 2;
m_PateContent.iBaseX = (int)vScrPos.x;
m_PateContent.iBaseY = (int)vScrPos.y-10;
m_PateContent.iCurY = m_PateContent.iBaseY;
m_PateContent.z = vScrPos.z;
return true;
}
float CECPlayer::GetGroundSpeed()
{
// return m_bWalkRun ? g_pGame->GetConfigs()->GetHostRunSpeed() : m_ExtProps.mv.walk_speed;
return m_bWalkRun ? m_ExtProps.mv.run_speed : m_ExtProps.mv.walk_speed;
}
// Set resources ready flag
void CECPlayer::SetResReadyFlag(DWORD dwFlag, bool bSet)
{
if (bSet)
{
m_dwResFlags |= dwFlag;
}
else
m_dwResFlags &= ~dwFlag;
}
// When all resources are ready, this function will be called
void CECPlayer::OnAllResourceReady()
{
/* if (!m_pLevelUpGFX)
m_pLevelUpGFX = g_pGame->GetGFXCaster()->LoadGFXEx(res_GFXFile(RES_GFX_LEVELUP));
if (!m_pWaterWaveStill)
m_pWaterWaveStill = g_pGame->GetGFXCaster()->LoadGFXEx(res_GFXFile(RES_GFX_WATER_WAVE_STILL));
if (!m_pWaterWaveMove)
m_pWaterWaveMove = g_pGame->GetGFXCaster()->LoadGFXEx(res_GFXFile(RES_GFX_WATER_WAVE_MOVE));
if (!m_pAirBubble)
m_pAirBubble = g_pGame->GetGFXCaster()->LoadGFXEx(res_GFXFile(RES_GFX_AIR_BUBBLE));
if (!m_pTransformGfx)
m_pTransformGfx = g_pGame->GetGFXCaster()->LoadGFXEx(res_GFXFile(RES_GFX_AIR_TRANSFORM));
*/
if (m_iShape) TransformShape(GetShapeMask());
}
// Caculate player's AABB base on profession and gender
void CECPlayer::CalcPlayerAABB()
{
int iIndex = m_iProfession * NUM_GENDER + m_iGender;
m_aabb.Extents = aExts[iIndex] * m_fScaleBySkill;
m_aabbServer.Extents = aExts[iIndex];
static const MOVECONST aMoveConsts[NUM_PROFESSION*NUM_GENDER] =
{
// 武侠
// fStepHei fMinAirHei fMinWaterHei fShoreDepth fWaterSurf
{ 0.8f, 1.6f, 0.3f, 1.6f, 0.6f },
{ 0.8f, 1.6f, 0.3f, 1.5f, 0.55f },
// 法师
{ 0.8f, 1.6f, 0.3f, 1.6f, 0.6f },
{ 0.8f, 1.6f, 0.3f, 1.5f, 0.55f },
// 巫师
{ 0.8f, 1.6f, 0.3f, 1.6f, 0.6f },
{ 0.8f, 1.6f, 0.3f, 1.5f, 0.55f },
// 妖精
{ 0.8f, 1.6f, 0.3f, 1.6f, 0.6f },
{ 0.8f, 1.6f, 0.3f, 1.5f, 0.55f },
// 妖兽
{ 0.8f, 1.6f, 0.3f, 1.8f, 0.7f },
{ 0.8f, 1.6f, 0.3f, 1.6f, 0.6f },
// 刺客
{ 0.8f, 1.6f, 0.3f, 1.6f, 0.6f },
{ 0.8f, 1.6f, 0.3f, 1.5f, 0.55f },
// 羽芒
{ 0.8f, 1.6f, 0.3f, 1.6f, 0.6f },
{ 0.8f, 1.6f, 0.3f, 1.5f, 0.55f },
// 羽灵
{ 0.8f, 1.6f, 0.3f, 1.6f, 0.6f },
{ 0.8f, 1.6f, 0.3f, 1.5f, 0.55f },
// 剑灵
{ 0.8f, 1.6f, 0.3f, 1.6f, 0.6f },
{ 0.8f, 1.6f, 0.3f, 1.5f, 0.55f },
// 魅灵
{ 0.8f, 1.6f, 0.3f, 1.6f, 0.6f },
{ 0.8f, 1.6f, 0.3f, 1.5f, 0.55f },
// 夜影
{ 0.8f, 1.6f, 0.3f, 1.6f, 0.6f },
{ 0.8f, 1.6f, 0.3f, 1.5f, 0.55f },
// 月仙
{ 0.8f, 1.6f, 0.3f, 1.6f, 0.6f },
{ 0.8f, 1.6f, 0.3f, 1.5f, 0.55f },
};
m_MoveConst = aMoveConsts[iIndex];
}
// Get player's model aabb
const A3DAABB & CECPlayer::GetModelAABB()
{
return GetPlayerPickAABB();
}
// Get player's skin model
A3DSkinModel * CECPlayer::GetA3DSkinModel()
{
if( m_pPlayerModel )
return m_pPlayerModel->GetA3DSkinModel();
else
return NULL;
}
// Get player's pick AABB
const A3DAABB& CECPlayer::GetPlayerPickAABB()
{
if (m_pPlayerModel && m_pPlayerModel->GetA3DSkinModel())
return m_pPlayerModel->GetA3DSkinModel()->GetModelAABB();
else
return m_aabb;
}
// Get property move or stand action
int CECPlayer::GetMoveStandAction(bool bMove, bool bFight/* false */)const
{
int iMoveEnv = m_iMoveEnv;
if (m_AttachMode != enumAttachNone)
{
bFight = false;
if( m_bHangerOn )
iMoveEnv = MOVEENV_GROUND;
}
int iAction = ACT_STAND;
if (bMove)
{
// Play appropriate actions
if (iMoveEnv == MOVEENV_GROUND)
{
if (m_bWalkRun)
iAction = ACT_RUN;
else
iAction = ACT_WALK;
}
else if (iMoveEnv == MOVEENV_AIR)
{
if (/*UsingWing()*/ m_wingType == WINGTYPE_WING)
iAction = ACT_FLY;
else
iAction = ACT_FLY_SWORD;
}
else if (iMoveEnv == MOVEENV_WATER){
if (CanCombineWithMoveForSkill()){
iAction = ACT_SWIM_FOR_MOVESKILL;
}else{
iAction = ACT_SWIM;
}
}
}
else
{
// Play appropriate actions
if (iMoveEnv == MOVEENV_GROUND)
{
if (bFight)
iAction = ACT_FIGHTSTAND;
else
iAction = ACT_STAND;
}
else if (iMoveEnv == MOVEENV_AIR)
{
if (/*UsingWing()*/ m_wingType == WINGTYPE_WING)
iAction = ACT_HANGINAIR;
else
iAction = ACT_HANGINAIR_SWORD;
}
else if (iMoveEnv == MOVEENV_WATER)
iAction = ACT_HANGINWATER;
}
return iAction;
}
bool CECPlayer::IsMoveStandAction(int iAction){
const static int s_MoveStandAction[] = {
CECPlayer::ACT_RUN,
CECPlayer::ACT_WALK,
CECPlayer::ACT_FLY,
CECPlayer::ACT_FLY_SWORD,
CECPlayer::ACT_SWIM,
CECPlayer::ACT_SWIM_FOR_MOVESKILL,
CECPlayer::ACT_STAND,
CECPlayer::ACT_FIGHTSTAND,
CECPlayer::ACT_HANGINAIR,
CECPlayer::ACT_HANGINAIR_SWORD,
CECPlayer::ACT_HANGINWATER,
};
const int *begin = &s_MoveStandAction[0];
const int *end = &s_MoveStandAction[ARRAY_SIZE(s_MoveStandAction)-1];
return std::find(begin, end, iAction) != end;
}
// Check water moving environment
bool CECPlayer::CheckWaterMoveEnv(const A3DVECTOR3& vPos, float fWaterHei, float fGndHei)
{
bool bRet = false;
/* if (vPos.y < fWaterHei - m_MoveConst.fShoreDepth)
bRet = true;
else if (vPos.y < fWaterHei && fWaterHei - fGndHei > m_MoveConst.fShoreDepth)
bRet = true;
*/
// if (vPos.y < fWaterHei - m_MoveConst.fWaterSurf - m_aabb.Extents.y)
// if (vPos.y < fWaterHei - m_MoveConst.fWaterSurf + 0.01f)
/*
if (vPos.y < fWaterHei - m_MoveConst.fShoreDepth)
bRet = true;
else if (vPos.y < fWaterHei - m_MoveConst.fWaterSurf + 0.01f && fWaterHei - fGndHei > m_MoveConst.fShoreDepth)
bRet = true;
*/
//@note : modify the water test. By Kuiwu[12/10/2005]
if (vPos.y + m_aabbServer.Extents.y < fWaterHei - m_MoveConst.fWaterSurf - 0.001f)
{
bRet = true;
}
//else if (vPos.y + m_aabb.Extents.y < fWaterHei- m_MoveConst.fWaterSurf + 1E-4f && vPos.y - fGndHei >= 0.2f )
else if (vPos.y + m_aabbServer.Extents.y < fWaterHei- m_MoveConst.fWaterSurf + 1E-4f && vPos.y - fGndHei >= 0.01f )
{
bRet = true;
}
return bRet;
}
// Set last said words
void CECPlayer::SetLastSaidWords(const ACHAR* szWords, int nEmotionSet, CECIvtrItem *pItem)
{
if (!m_pPateLastWords1 || !m_pPateLastWords2)
return;
ACString str = FilterEmotionSet(szWords, nEmotionSet);
szWords = str;
m_pPateLastWords1->SetText(szWords, true, true, pItem);
m_pPateLastWords2->Clear();
m_strLastSayCnt.Reset();
}
void CECPlayer::SetFactionPVPMask(unsigned char mask)
{
m_factionPVPMask = mask;
}
bool CECPlayer::IsInFactionPVP()const
{
return (m_factionPVPMask & 0x01) != 0;
}
bool CECPlayer::CanAttackFactionPVPMineCar()const
{
return (m_factionPVPMask & 0x02) != 0;
}
bool CECPlayer::CanAttackFactionPVPMineBase()const
{
return (m_factionPVPMask & 0x04) != 0;
}
// Set faction ID
void CECPlayer::SetFactionID(int id)
{
m_idFaction = id;
if (!m_idFaction)
return;
// Clear pate faction text, it will be rebuilt in RenderName()
if (m_pPateFaction)
m_pPateFaction->Clear();
// Reset faction icon
if (!m_pFactionDecal)
m_pFactionDecal = new CECSpriteDecal;
AString strIcon;
strIcon.Format("%d_%d.dds", g_pGame->GetGameInit().iServerID, m_idFaction);
int iIndex;
CECGameUIMan* pGameUI = g_pGame->GetGameRun()->GetUIManager()->GetInGameUIMan();
A2DSprite* pIcon = pGameUI->GetGuildIcon(strIcon, &iIndex);
m_pFactionDecal->ChangeSpriteIcon(pIcon, iIndex);
}
void CECPlayer::OnFactionNameChange(){
if (m_pPateFaction){
m_pPateFaction->Clear();
}
}
// Set faction role
void CECPlayer::SetFRoleID(int role)
{
m_idFRole = role;
// Clear pate faction text, it will be rebuilt in RenderName()
if (m_pPateFaction)
m_pPateFaction->Clear();
}
// On start binding buddy
void CECPlayer::OnStartBinding(int idMule, int idRider)
{
m_bCandHangerOn = (idRider == GetCharacterID()) ? true : false;
m_idCandBuddy = m_bCandHangerOn ? idMule : idRider;
}
CECPlayer * CECPlayer::GetBuddy()const{
CECPlayer *result = NULL;
if (GetBuddyID() != 0){
result = m_pPlayerMan->GetPlayer(GetBuddyID());
}
return result;
}
bool CECPlayer::CanBindBuddy()const{
return GetBuddyState() == 0
&& !IsInvisible()
&& GetShapeType() != PLAYERMODEL_DUMMYTYPE2
&& (GetRace() != RACE_OBORO || GetShapeType() != PLAYERMODEL_PROFESSION);
}
// Set booth name
void CECPlayer::SetBoothName(const ACHAR* szName)
{
m_strBoothName = szName;
if (m_pPateBooth)
m_pPateBooth->SetBoothContent(szName);
}
// Is specified id a member of our team ?
bool CECPlayer::IsTeamMember(int idPlayer)
{
if (!m_pTeam)
return false;
return m_pTeam->GetMemberByID(idPlayer) ? true : false;
}
// Set new visible extend states
void CECPlayer::SetNewExtendStates(int start, const DWORD* pData, int count)
{
if(!pData || start + count > OBJECT_EXT_STATE_COUNT)
{
ASSERT(false);
a_LogOutput(1, "CECPlayer::SetNewExtendStates, invalid data(start=%d, count=%d)", start, count);
return;
}
ShowExtendStates(start, pData, count);
memcpy(m_aExtStates + start, pData, sizeof(DWORD) * count );
if(GetExtState(111))
{
// 武侠旋转技能 太虚·诛神诀
m_PlayerActions = _turning_actions;
}
else
{
m_PlayerActions = _default_actions;
}
}
void CECPlayer::ClearShowExtendStates()
{
DWORD aExtStates[OBJECT_EXT_STATE_COUNT] = {0};
ShowExtendStates(0, aExtStates, OBJECT_EXT_STATE_COUNT, true);
}
void CECPlayer::ShowExtendStates(int start, const DWORD* pData, int count, bool bIgnoreOptimize/* =false */)
{
if(!pData || start + count > OBJECT_EXT_STATE_COUNT)
{
ASSERT(false);
return;
}
if (!IsAllResReady() || !GetMajorModel())
return;
if (!bIgnoreOptimize &&
!CECOptimize::Instance().GetGFX().CanShowState(GetCharacterID(), GetClassID()))
return;
static const char* szBasePath = "策划联入\\状态效果\\";
const int bitSize = sizeof(DWORD) * 8;
for(int index = 0; index<count; index++)
{
int idState = index + start;
for (int i=0; i < bitSize; i++)
{
DWORD dwMask = 1 << i;
DWORD dwFlag1 = m_aExtStatesShown[idState] & dwMask;
DWORD dwFlag2 = pData[index] & dwMask;
if ((!dwFlag1 && !dwFlag2) || (dwFlag1 && dwFlag2))
continue;
const GNET::VisibleState* pvs = GNET::VisibleState::Query(m_iProfession, i + idState*bitSize);
if (!pvs)
continue;
AString strGFXFile = pvs->GetEffect();
if (!strGFXFile.GetLength())
continue;
strGFXFile = szBasePath + strGFXFile;
if (TestProcessPetCureGFX(strGFXFile, dwFlag2 != 0, i + idState*bitSize))
continue;
if (dwFlag1)
{
// Remove old state
CECModel *pWeapon = NULL;
bool bLeft (false);
if (IsWeaponHookPos(pvs->GetHH(), &bLeft, &pWeapon))
{
// 武器上特效
if (pWeapon)
{
const char * gfxHook = GetWeaponGFXHookPos(pWeapon, bLeft);
pWeapon->RemoveGfx(strGFXFile, gfxHook);
}
}
else
{
// 模型上特效
RemoveGfx(strGFXFile, pvs->GetHH(), PLAYERMODEL_TYPEALL);
}
}
else
{
// Add new state
const char* szHH = pvs->GetHH();
float fScale;
if (stricmp("HH_Head", szHH) == 0)
fScale = GetMajorModel()->GetOuterData()[0];
else if (stricmp("HH_Spine", szHH) == 0)
fScale = GetMajorModel()->GetOuterData()[1];
else
fScale = 1.0f;
CECModel *pWeapon = NULL;
bool bLeft (false);
if (IsWeaponHookPos(pvs->GetHH(), &bLeft, &pWeapon))
{
if (pWeapon)
{
const char *gfxHook = GetWeaponGFXHookPos(pWeapon, bLeft);
pWeapon->PlayGfx(strGFXFile, gfxHook, fScale);
}
}
else
{
PlayGfx(strGFXFile, pvs->GetHH(), fScale, PLAYERMODEL_TYPEALL, true);
}
}
}
}
memcpy(m_aExtStatesShown + start, pData, sizeof(DWORD) * count );
}
void CECPlayer::SetExtendStatesToWeapon()
{
// 根据玩家的当前状态,将相关特效等挂到当前武器上(当前武器可能刚更换,挂在原武器上的状态特效因删除而消失)
// 避免因武器更换等原因导致不能正确指示状态
//
static const char* szBasePath = "策划联入\\状态效果\\";
const int bitSize = sizeof(DWORD) * 8;
if (IsAllResReady() && GetMajorModel())
{
AString strGFXFile;
for(int idState = 0; idState<OBJECT_EXT_STATE_COUNT; idState++)
{
for (int i=0; i < bitSize; i++)
{
DWORD dwMask = 1 << i;
DWORD dwFlag1 = m_aExtStatesShown[idState] & dwMask;
if (!dwFlag1)
{
// 状态为0,不可能会给武器添加特效等
continue;
}
// 获取合法的光效路径名称
const GNET::VisibleState* pvs = GNET::VisibleState::Query(m_iProfession, i + idState*bitSize);
if (!pvs)
continue;
strGFXFile = pvs->GetEffect();
if (!strGFXFile.GetLength())
continue;
strGFXFile = szBasePath + strGFXFile;
if (IsPetCureGFX(strGFXFile))
{
// 是宠物治疗光效,与武器无关
continue;
}
CECModel *pWeapon = NULL;
bool bLeft (false);
if (!IsWeaponHookPos(pvs->GetHH(), &bLeft, &pWeapon))
{
// 不是放到武器上的光效,也忽略
continue;
}
if (!pWeapon)
{
// 对应的武器当前没有,也不需要处理
continue;
}
// 光效有了,武器有了,现在需要添加到当前的武器上
// 计算缩放
const char* szHH = pvs->GetHH();
float fScale;
if (stricmp("HH_Head", szHH) == 0)
fScale = GetMajorModel()->GetOuterData()[0];
else if (stricmp("HH_Spine", szHH) == 0)
fScale = GetMajorModel()->GetOuterData()[1];
else
fScale = 1.0f;
// 计算武器悬挂位置并播放特效
const char *gfxHook = GetWeaponGFXHookPos(pWeapon, bLeft);
pWeapon->PlayGfx(strGFXFile, gfxHook, fScale);
// 继续检查其它有效状态,可能有左/右手武器还需要继续添加
// 注意,有效状态应保证对同一武器只会播放一次光效
// 如果有多次,此处逻辑以最后一次处理到的为准
// 与服务器传来的可能不一致
}
}
}
}
void CECPlayer::SetTeamRequireText(const TEAMREQ& Req)
{
// Build pate string
CECStringTab* pFixStr = g_pGame->GetFixedMsgTab();
m_strTeamReq = _AL("");
if (Req.bShowLevel)
{
const ACHAR* szProf = g_pGame->GetGameRun()->GetProfName(Req.iProfession);
m_strTeamReq.Format(pFixStr->GetWideString(FIXMSG_LEVELANDPROF), Req.iLevel, szProf);
m_strTeamReq += _AL(" ");
}
if (!Req.iType)
m_strTeamReq += pFixStr->GetWideString(FIXMSG_SEARCHTEAM);
else
m_strTeamReq += pFixStr->GetWideString(FIXMSG_SEARCHTEAMMEM);
}
void CECPlayer::SetTeamRequire(const TEAMREQ& Req, bool bConfirm)
{
m_TeamReq = Req;
// Build pate string
SetTeamRequireText(Req);
if (m_pPateTeamReq)
{
if (m_strTeamReq.GetLength())
m_pPateTeamReq->SetText(m_strTeamReq, false, true);
else
m_pPateTeamReq->Clear();
}
// If this is host player, notify server
if (bConfirm && IsHostPlayer())
{
// Compress data
int iData1=0, iData2=0;
if (Req.bShowReq)
iData1 |= (1 << 31);
if (Req.bShowLevel)
{
iData1 |= (1 << 30);
iData1 |= (Req.iLevel << 8);
iData1 |= Req.iProfession;
}
iData1 |= (Req.iType << 16);
g_pGame->GetGameSession()->c2s_CmdSetAdvData(iData1, iData2);
}
}
// Decompress advertisement data
void CECPlayer::DecompAdvData(int iData1, int iData2)
{
TEAMREQ Req;
Req.bShowReq = (iData1 & (1 << 31)) ? true : false;
Req.bShowLevel = (iData1 & (1 << 30)) ? true : false;
Req.iType = (iData1 & 0x00ff0000) >> 16;
Req.iLevel = (iData1 & 0x0000ff00) >> 8;
Req.iProfession = iData1 & 0xff;
SetTeamRequire(Req, false);
}
// Message handlers
void CECPlayer::OnMsgPlayerExtState(const ECMSG& Msg)
{
using namespace S2C;
if (Msg.dwParam2 == UPDATE_EXT_STATE)
{
cmd_update_ext_state* pCmd = (cmd_update_ext_state*)Msg.dwParam1;
ASSERT(pCmd && pCmd->id == m_PlayerInfo.cid);
SetNewExtendStates(0, pCmd->states, OBJECT_EXT_STATE_COUNT);
}
else if (Msg.dwParam2 == ICON_STATE_NOTIFY)
{
cmd_icon_state_notify cmd;
if (!cmd.Initialize((const void *)Msg.dwParam1, Msg.dwParam3))
{
ASSERT(0);
return;
}
ASSERT(cmd.id == m_PlayerInfo.cid);
m_aIconStates = cmd.states;
if (m_aIconStates.size() > 1)
qsort(m_aIconStates.begin(), m_aIconStates.size(), sizeof (m_aIconStates[0]), glb_IconStateCompare);
}
}
void CECPlayer::OnMsgEnchantResult(const ECMSG& Msg)
{
using namespace S2C;
cmd_enchant_result* pCmd = (cmd_enchant_result*)Msg.dwParam1;
ASSERT(pCmd && pCmd->caster == m_PlayerInfo.cid);
DWORD mask = (DWORD)(-1);
// we should filter out these things that will cause bubble texts
if (pCmd->target != m_pPlayerMan->GetHostPlayer()->GetCharacterID() &&
!IsHostPlayer())
mask &= CECAttackEvent::MOD_PHYSIC_ATTACK_RUNE | CECAttackEvent::MOD_MAGIC_ATTACK_RUNE | CECAttackEvent::MOD_CRITICAL_STRIKE | CECAttackEvent::MOD_ENCHANT_FAILED;
// DWORD dwModifier = (((DWORD)pCmd->modifier2) << 8) | pCmd->modifier;
DWORD dwModifier = (DWORD)pCmd->attack_flag;
if( GNET::ElementSkill::GetType(pCmd->skill) == GNET::TYPE_ATTACK )
{
// only attack skill will cause wounded action, when damage is -1
PlayAttackEffect(pCmd->target, pCmd->skill, pCmd->level, -1, dwModifier & mask, 0,NULL,pCmd->section);
}
else
{
// other skills will not cause wounded action, so we set damage to -2 which will be discarded to play wounded action
PlayAttackEffect(pCmd->target, pCmd->skill, pCmd->level, -2, dwModifier & mask, 0,NULL,pCmd->section);
}
}
void CECPlayer::OnMsgPlayerAdvData(const ECMSG& Msg)
{
using namespace S2C;
if (Msg.dwParam2 == PLAYER_SET_ADV_DATA)
{
cmd_player_set_adv_data* pCmd = (cmd_player_set_adv_data*)Msg.dwParam1;
DecompAdvData(pCmd->data1, pCmd->data2);
}
else
{
ASSERT(Msg.dwParam2 == PLAYER_CLR_ADV_DATA);
cmd_player_clr_adv_data* pCmd = (cmd_player_clr_adv_data*)Msg.dwParam1;
m_TeamReq.bShowReq = false;
}
}
void CECPlayer::OnMsgPlayerPVP(const ECMSG& Msg)
{
using namespace S2C;
switch (Msg.dwParam2)
{
case PLAYER_ENABLE_PVP: m_pvp.bEnable = true; break;
case PLAYER_DISABLE_PVP: m_pvp.bEnable = false; break;
case PVP_COMBAT:
{
cmd_pvp_combat* pCmd = (cmd_pvp_combat*)Msg.dwParam1;
m_pvp.bInPVPCombat = pCmd->state ? true : false;
break;
}
}
}
void CECPlayer::RemoveEquipGfx()
{
// 移除显示武器、防具、套装特效
RemoveUpperBodyStones();
RemoveWristStones();
RemoveLowerBodyStones();
RemoveFootStones();
RemoveFullSuiteGFX();
}
void CECPlayer::AddEquipGfx()
{
// 显示武器、防具、套装特效
if (GetMajorModel() != NULL && !InFashionMode()){
AddUpperBodyStones();
AddWristStones();
AddLowerBodyStones();
AddFootStones();
AddFullSuiteGFX();
}
}
void CECPlayer::OnMsgSwitchFashionMode(const ECMSG& Msg)
{
using namespace S2C;
cmd_player_enable_fashion* pCmd = (cmd_player_enable_fashion*)Msg.dwParam1;
m_bFashionMode = pCmd->is_enabble ? true : false;
UpdateCurSkins();
OnSwitchFashionWeapon();
if (InFashionMode()){
RemoveEquipGfx();
}else{
AddEquipGfx();
}
for (int i = 0; i < SIZE_ALL_EQUIPIVTR; i++)
{
if (m_aEquips[i] <= 0)
continue;
int nEquipFlag = 0;
if (IsShownEquip(i))
{
nEquipFlag = 1;
}
if ( GetMajorModel() )
{
DWORD dwRealID = GetRealElementID(i, m_aEquips[i]);
GetMajorModel()->OnScriptChangeEquip(dwRealID, nEquipFlag, false);
}
}
if (InFashionMode())
UpdateHairModel(true, m_aEquips[EQUIPIVTR_FASHION_HEAD]);
else
UpdateHairModel(true, m_aEquips[EQUIPIVTR_HEAD]);
}
void CECPlayer::OnMsgPlayerEffect(const ECMSG& Msg)
{
using namespace S2C;
if (Msg.dwParam2 == PLAYER_ENABLE_EFFECT)
{
cmd_player_enable_effect* pCmd = (cmd_player_enable_effect*)Msg.dwParam1;
ApplyEffect(pCmd->effect, true);
}
else if (Msg.dwParam2 == PLAYER_DISABLE_EFFECT)
{
cmd_player_disable_effect* pCmd = (cmd_player_disable_effect*)Msg.dwParam1;
DiscardEffect(pCmd->effect);
}
}
void CECPlayer::OnMsgChangeNameColor(const ECMSG& Msg)
{
using namespace S2C;
switch (Msg.dwParam2)
{
case INVADER_RISE:
m_dwStates |= GP_STATE_INVADER;
break;
case PARIAH_RISE:
{
m_dwStates |= GP_STATE_PARIAH;
cmd_pariah_rise* pCmd = (cmd_pariah_rise*)Msg.dwParam1;
m_byPariahLvl = pCmd->pariah_lvl;
break;
}
case INVADER_FADE:
{
m_dwStates &= ~(GP_STATE_INVADER | GP_STATE_PARIAH);
if (IsHostPlayer() && PKLevelCheck())
{
CELPrecinct* p = g_pGame->GetGameRun()->GetWorld()->GetCurPrecinct();
if (p && p->IsPKProtect())
g_pGame->GetGameSession()->c2s_CmdSendEnterPKPrecinct();
}
break;
}
}
}
void CECPlayer::OnMsgPlayerMount(const ECMSG& Msg)
{
using namespace S2C;
const cmd_player_mounting* pCmd = (const cmd_player_mounting*)Msg.dwParam1;
if (pCmd->mount_id)
RideOnPet(pCmd->mount_id, pCmd->mount_color);
else
GetOffPet();
}
void CECPlayer::PlayTaoistEffect()
{
CECGameUIMan* pGameUI = g_pGame->GetGameRun()->GetUIManager()->GetInGameUIMan();
CDlgLevel2UpgradeShow *pDlg = dynamic_cast<CDlgLevel2UpgradeShow *>(pGameUI->GetDialog("Win_Level2UpgradeShow"));
pDlg->SetNewLevel2(GetBasicProps().iLevel2);
pDlg->Show(true);
}
bool CECPlayer::CanPlayTaoistEffect(int originalLevel2, int newLevel2, bool bFirstTime)
{
bool result(false);
if(!bFirstTime){
if (IsHostPlayer()){
if ( (!IsGodEvilConvert(originalLevel2, newLevel2)) && (originalLevel2 < newLevel2) ){
result =true;
}
}
}
return result;
}
void CECPlayer::SetLevel2(int level2, bool bFirstTime)
{
int lastLevel2 = m_BasicProps.iLevel2;
m_BasicProps.iLevel2 = level2;
if (CanPlayTaoistEffect(lastLevel2, level2, bFirstTime)){
PlayTaoistEffect();
}
}
bool CECPlayer::IsGodEvilConvert(int originalLevel2, int newLevel2)
{
const CECTaoistRank* originalTaoist = CECTaoistRank::GetTaoistRank(originalLevel2);
const CECTaoistRank* newTaoist = CECTaoistRank::GetTaoistRank(newLevel2);
return (originalTaoist->IsGodRank() && newTaoist->IsEvilRank()) || (originalTaoist->IsEvilRank() && newTaoist->IsGodRank());
}
void CECPlayer::OnMsgPlayerLevel2(const ECMSG& Msg)
{
using namespace S2C;
cmd_task_deliver_level2* pCmd = (cmd_task_deliver_level2*)Msg.dwParam1;
// 修真进阶时播放全屏特效
SetLevel2(pCmd->level2, false);
UpdateGodEvilSprite();
}
void CECPlayer::OnMsgKingChanged(const ECMSG &Msg)
{
using namespace S2C;
char is_king = 0;
if( Msg.dwParam2 == PLAYER_KING_CHANGED )
{
cmd_player_king_changed* pCmd = (cmd_player_king_changed*)Msg.dwParam1;
is_king = pCmd->is_king;
}
else if ( Msg.dwParam2 == SELF_KING_NOTIFY )
{
cmd_self_king_notify* pCmd = (cmd_self_king_notify*)Msg.dwParam1;
is_king = pCmd->is_king;
}
if( is_king )
m_dwStates2 |= GP_STATE2_ISKING;
else
m_dwStates2 &= ~GP_STATE2_ISKING;
}
static A3DSkinModel::LIGHTINFO MakePlayerModelLightInfoForAUI(const A3DVECTOR3 &vLightDir){
A3DSkinModel::LIGHTINFO result;
memset(&result, 0, sizeof(result));
const A3DLIGHTPARAM& lp = g_pGame->GetDirLight()->GetLightparam();
result.colDirDiff = lp.Diffuse;
result.colDirSpec = lp.Specular;
result.vLightDir = vLightDir;
result.colAmbient = A3DCOLORVALUE(0.5f, 0.5f, 0.5f, 1.0f) + g_pGame->GetA3DDevice()->GetAmbientValue();
result.colAmbient.r = min(result.colAmbient.r, 1.0f);
result.colAmbient.g = min(result.colAmbient.g, 1.0f);
result.colAmbient.b = min(result.colAmbient.b, 1.0f);
result.colAmbient.a = min(result.colAmbient.a, 1.0f);
result.colPtDiff = A3DCOLORVALUE(0.0f, 0.0f, 0.0f, 1.0f);
result.colPtAmb = A3DCOLORVALUE(0.0f, 0.0f, 0.0f, 1.0f);
result.fPtRange = 0.01f;
result.vPtAtten = A3DVECTOR3(0.0f);
result.vPtLightPos = A3DVECTOR3(0.0f);
result.bPtLight = true;
return result;
}
// player's render for shadow call back function
bool PlayerRenderForShadow(A3DViewport * pViewport, void * pArg)
{
CECPlayer * pPlayer = (CECPlayer *) pArg;
g_pGame->GetA3DDevice()->SetZTestEnable(true);
g_pGame->GetA3DDevice()->SetZWriteEnable(true);
g_pGame->GetA3DDevice()->SetAlphaTestEnable(true);
g_pGame->GetA3DDevice()->SetAlphaBlendEnable(false);
g_pGame->GetA3DDevice()->SetAlphaFunction(A3DCMP_GREATEREQUAL);
g_pGame->GetA3DDevice()->SetAlphaRef(84);
CECViewport viewport;
viewport.InitFromA3D(pViewport);
// if (pPlayer->GetBoothState() == 2)
// pPlayer->GetBoothModel()->RenderAtOnce(pViewport, A3DSkinModel::RAO_NOTEXTURE | A3DSkinModel::RAO_NOMATERIAL, false);
if (pPlayer->GetPetModel())
{
if (pPlayer->IsShapeModelChanged())
{
pPlayer->GetPetModel()->GetA3DSkinModel()->RenderAtOnce(pViewport, A3DSkinModel::RAO_NOMATERIAL, false);
}
else
{
bool bShowHeadOld = pPlayer->GetPlayerModel()->IsSkinShown(SKIN_HEAD_INDEX);
pPlayer->GetPlayerModel()->ShowSkin(SKIN_HEAD_INDEX, true);
pPlayer->GetPetModel()->GetA3DSkinModel()->RenderAtOnce(pViewport, A3DSkinModel::RAO_NOMATERIAL, false);
pPlayer->GetPlayerModel()->ShowSkin(SKIN_HEAD_INDEX, bShowHeadOld);
}
}
else if (pPlayer->IsShapeModelChanged())
pPlayer->GetPlayerModel()->GetA3DSkinModel()->RenderAtOnce(pViewport, A3DSkinModel::RAO_NOMATERIAL, false);
else
{
bool bShowHeadOld = pPlayer->GetPlayerModel()->IsSkinShown(SKIN_HEAD_INDEX);
pPlayer->GetPlayerModel()->ShowSkin(SKIN_HEAD_INDEX, true);
pPlayer->GetPlayerModel()->GetA3DSkinModel()->RenderAtOnce(pViewport, A3DSkinModel::RAO_NOMATERIAL, false);
pPlayer->GetPlayerModel()->ShowSkin(SKIN_HEAD_INDEX, bShowHeadOld);
}
g_pGame->GetA3DDevice()->SetAlphaBlendEnable(true);
g_pGame->GetA3DDevice()->SetAlphaTestEnable(false);
g_pGame->GetA3DDevice()->SetZTestEnable(true);
g_pGame->GetA3DDevice()->SetZWriteEnable(true);
return true;
}
typedef abase::vector<bool> SkinShowFlagArray;
static SkinShowFlagArray GetSkinShowFlag(A3DSkinModel *pModel){
SkinShowFlagArray result;
if (pModel){
result.reserve(pModel->GetSkinNum());
for (int i(0); i < pModel->GetSkinNum(); ++ i){
bool bShown(false);
if (A3DSkinModel::SKIN *pSkinItem = pModel->GetSkinItem(i)){
bShown = pSkinItem->bRender;
}
result.push_back(bShown);
}
}
return result;
}
static SkinShowFlagArray GetShowSomeSkinOnlyFlag(A3DSkinModel *pModel, int skinIndex){
SkinShowFlagArray result;
if (pModel){
result.reserve(pModel->GetSkinNum());
for (int i(0); i < pModel->GetSkinNum(); ++ i){
result.push_back(i == skinIndex ? true : false);
}
}
return result;
}
static SkinShowFlagArray GetShowHeadOnlyFlag(A3DSkinModel *pModel){
return GetShowSomeSkinOnlyFlag(pModel, SKIN_HEAD_INDEX);
}
static SkinShowFlagArray GetHideAllSkinFlag(A3DSkinModel *pModel){
return GetShowSomeSkinOnlyFlag(pModel, -1);
}
static void ShowSkin(A3DSkinModel *pModel, const SkinShowFlagArray &showSkinFlagArray){
if (pModel){
for (size_t i(0); i < showSkinFlagArray.size(); ++ i){
pModel->ShowSkin(i, showSkinFlagArray[i]);
}
}
}
typedef abase::vector<SkinShowFlagArray> ChildModelsSkinShowFlagArray;
static ChildModelsSkinShowFlagArray GetChildModelsSkinShowFlag(A3DSkinModel *pModel){
ChildModelsSkinShowFlagArray result;
if (pModel){
result.reserve(pModel->GetChildModelNum());
for (int i(0); i < pModel->GetChildModelNum(); ++ i){
result.push_back(GetSkinShowFlag(pModel->GetChildModel(i)));
}
}
return result;
}
static ChildModelsSkinShowFlagArray GetHideChildModelsSkinShowFlag(A3DSkinModel *pModel){
ChildModelsSkinShowFlagArray result;
if (pModel){
result.reserve(pModel->GetChildModelNum());
for (int i(0); i < pModel->GetChildModelNum(); ++ i){
result.push_back(GetHideAllSkinFlag(pModel->GetChildModel(i)));
}
}
return result;
}
static void ShowChildModelsSkin(A3DSkinModel *pModel, const ChildModelsSkinShowFlagArray &childModelsShowSkinFlagArray){
if (pModel){
for (size_t i(0); i < childModelsShowSkinFlagArray.size(); ++ i){
ShowSkin(pModel->GetChildModel(i), childModelsShowSkinFlagArray[i]);
}
}
}
void PlayerRenderPortraitNoFace(const A3DRECT &rc, DWORD param1, DWORD param2, DWORD param3)
{
static const float headsize[NUM_PROFESSION*NUM_GENDER] = {
0.221f, 0.200f, // 武侠
0.221f, 0.200f, // 法师
0.221f, 0.200f, // 巫师
0.221f, 0.200f, // 妖精
0.294f, 0.200f, // 妖兽
0.221f, 0.200f, // 刺客
0.221f, 0.200f, // 羽芒
0.221f, 0.200f, // 羽灵
0.221f, 0.200f, // 剑灵
0.221f, 0.200f, // 魅灵
0.221f, 0.200f, // 夜影
0.221f, 0.200f, // 月仙
};
static const float pose[NUM_PROFESSION*NUM_GENDER][2] = {
{1.1f, 0.02f}, {0.9f, 0.04f}, // 武侠
{1.1f, 0.02f}, {0.9f, 0.04f}, // 法师
{0.9f, 0.02f}, {0.9f, 0.04f}, // 巫师
{0.9f, 0.04f}, {0.8f, 0.04f}, // 妖精
{1.3f, 0.05f}, {0.8f, 0.04f}, // 妖兽
{0.9f, 0.02f}, {0.9f, 0.04f}, // 刺客
{0.8f, 0.02f}, {0.6f, 0.04f}, // 羽芒
{0.9f, 0.02f}, {0.7f, 0.04f}, // 羽灵
{1.0f, 0.02f}, {0.8f, 0.04f}, // 剑灵
{1.0f, 0.02f}, {0.8f, 0.04f}, // 魅灵
{1.0f, 0.02f}, {0.8f, 0.04f}, // 夜影
{1.0f, 0.02f}, {0.8f, 0.04f}, // 月仙
};
// CECFace的 "脖子对齐"骨头的初始相对矩阵,确定相机位置时会用到
// 由于此时没有CECFace, 故写死在这里
static const A3DMATRIX4 matNeck(
0.0f, 0.996917f, 0.0784576f, 0.0f,
-1.0f, 0.0f, 0.0f, 0.0f,
0.0f, -0.0784576f, 0.996917f, 0.0f,
0.0f, -0.0454048f, -0.00635493f, 1.0f
);
if( param1 == 0 )
return;
CECPlayer * pPlayer = (CECPlayer *) param1;
float vDeg = (int)param2 * 0.01f;
CECModel* pMajorModel = pPlayer->GetMajorModel();
if( !pMajorModel ) return;
A3DSkinModel* pModel = pMajorModel->GetA3DSkinModel();
if( !pModel ) return;
A3DSkin* pHeadSkin = pMajorModel->GetA3DSkin(SKIN_HEAD_INDEX);
if( !pHeadSkin ) return;
A3DViewport * pCurViewport = g_pGame->GetA3DEngine()->GetActiveViewport();
A3DViewport * pPortraitViewport = g_pGame->GetPortraitRender()->GetPortraitViewport();
A3DCameraBase * pCamera = pPortraitViewport->GetCamera();
A3DVIEWPORTPARAM viewParam = *pPortraitViewport->GetParam();
viewParam.X = rc.left;
viewParam.Y = rc.top;
viewParam.Width = rc.right - rc.left;
viewParam.Height = rc.bottom - rc.top;
pPortraitViewport->SetParam(&viewParam);
((A3DCamera *) pCamera)->SetProjectionParam(-1.0f, -1.0f, -1.0f, ((float)viewParam.Width) / viewParam.Height);
A3DBone* pHeadBone = pModel->GetSkeleton()->GetBone("Bip01 Head", NULL);
A3DMATRIX4 matHead = a3d_RotateY(vDeg) * (InverseTM(matNeck) * pHeadBone->GetAbsoluteTM());
A3DVECTOR3 vecPos = matHead.GetRow(3);
A3DVECTOR3 vecDir = Normalize(matHead.GetRow(2));
A3DVECTOR3 vecUp = Normalize(matHead.GetRow(1));
// 计算头部肖像的缩放
float vHeadScale = 1.0f;
int index = pPlayer->GetProfession() * NUM_GENDER + pPlayer->GetGender();
A3DVECTOR3 vHeadTop = A3DVECTOR3(0.0f, pHeadSkin->GetInitMeshAABB().Extents.y, 0.0f) * pHeadBone->GetAbsoluteTM();
A3DVECTOR3 vHeadBottom = A3DVECTOR3(0.0f, 0.0f, 0.0f) * pHeadBone->GetAbsoluteTM();
float fHeadHeight = (vHeadTop - vHeadBottom).Magnitude();
vHeadScale = fHeadHeight / headsize[index] * (pPlayer->IsChangingFace() ? 1.0f : pPlayer->GetPortraitCameraScale());
static float s_scalePos = 1.5f;
float *p = &s_scalePos;
static float s_scaleUp = 1.5f;
p = &s_scaleUp;
pCamera->SetPos(vecPos + vecDir * (pose[index][0] * vHeadScale * s_scalePos) + vecUp * pose[index][1] * vHeadScale * s_scaleUp);
pCamera->SetDirAndUp(-vecDir, vecUp);
pPortraitViewport->Active();
pPortraitViewport->ClearDevice();
CECViewport viewport;
viewport.InitFromA3D(pPortraitViewport);
g_pGame->GetA3DDevice()->SetAlphaBlendEnable(true);
g_pGame->GetA3DDevice()->SetAlphaTestEnable(true);
// 保存原有透明度(显示头像时需屏蔽透明度)
float fTransparent = pModel->GetTransparent();
// 重置透明度
pModel->SetTransparent(-1.0f);
// 设置专用光照,使不受场景光照影响
pModel->SetLightInfo(MakePlayerModelLightInfoForAUI(pCamera->GetDir()));
// 隐藏其它皮肤
SkinShowFlagArray savedSkinShowFlag = GetSkinShowFlag(pModel);
ChildModelsSkinShowFlagArray savedChildModelShowFlag = GetChildModelsSkinShowFlag(pModel);
ShowSkin(pModel, GetShowHeadOnlyFlag(pModel));
ShowChildModelsSkin(pModel, GetHideChildModelsSkinShowFlag(pModel));
// 打坐使用特殊模型时,需要对头像显示特殊处理 by SunXuewei 2009-11-18
if(pPlayer->IsSitting() && (pPlayer->GetRace() == RACE_GHOST || pPlayer->GetRace() == RACE_OBORO))
{
int iMaterialMethod = pModel->GetMaterialMethod();
pModel->SetMaterialMethod(A3DSkinModel::MTL_ORIGINAL);
pModel->RenderAtOnce(viewport.GetA3DViewport(), 0, false);
pModel->SetMaterialMethod(iMaterialMethod);
}
else
{
pModel->RenderAtOnce(viewport.GetA3DViewport(), 0, false);
}
// 恢复隐藏的皮肤
ShowSkin(pModel, savedSkinShowFlag);
ShowChildModelsSkin(pModel, savedChildModelShowFlag);
// 渲染脸部引用的GFX特效(如灵族的额饰特效)
// 需使用正确的 alpha 模式
g_pGame->GetA3DDevice()->SetAlphaBlendEnable(true);
g_pGame->GetA3DDevice()->SetAlphaTestEnable(false);
g_pGame->GetA3DGFXExMan()->RenderAllGfx(pPortraitViewport, true);
g_pGame->GetA3DDevice()->SetAlphaBlendEnable(true);
g_pGame->GetA3DDevice()->SetAlphaTestEnable(false);
// 恢复原有透明度
pModel->SetTransparent(fTransparent);
pCurViewport->Active();
}
void PlayerRenderPortrait(const A3DRECT &rc, DWORD param1, DWORD param2, DWORD param3)
{
static float headsize[NUM_PROFESSION*NUM_GENDER] = {
0.221f, 0.200f, // 武侠
0.221f, 0.200f, // 法师
0.221f, 0.200f, // 巫师
0.221f, 0.200f, // 妖精
0.294f, 0.200f, // 妖兽
0.221f, 0.200f, // 刺客
0.221f, 0.200f, // 羽芒
0.221f, 0.200f, // 羽灵
0.221f, 0.200f, // 剑灵
0.221f, 0.200f, // 魅灵
0.221f, 0.200f, // 夜影
0.221f, 0.200f, // 月仙
};
static float pose[NUM_PROFESSION*NUM_GENDER][2] = {
{0.7f, 0.04f}, {0.6f, 0.04f}, // 武侠
{0.7f, 0.04f}, {0.6f, 0.04f}, // 法师
{0.7f, 0.04f}, {0.6f, 0.04f}, // 巫师
{0.7f, 0.04f}, {0.7f, 0.05f}, // 妖精
{0.9f, 0.06f}, {0.6f, 0.04f}, // 妖兽
{0.7f, 0.04f}, {0.6f, 0.04f}, // 刺客
{0.7f, 0.04f}, {0.6f, 0.04f}, // 羽芒
{0.7f, 0.04f}, {0.6f, 0.04f}, // 羽灵
{0.7f, 0.04f}, {0.6f, 0.04f}, // 剑灵
{0.7f, 0.04f}, {0.6f, 0.04f}, // 魅灵
{0.7f, 0.04f}, {0.6f, 0.04f}, // 夜影
{0.7f, 0.04f}, {0.6f, 0.04f}, // 月仙
};
if( param1 == 0 )
return;
CECPlayer * pPlayer = (CECPlayer *) param1;
float vDeg = (int)param2 * 0.01f;
CECFace * pFace = pPlayer->GetFaceModel();
if (!pFace)
{
PlayerRenderPortraitNoFace(rc, param1, param2, param3);
return;
}
A3DViewport * pCurViewport = g_pGame->GetA3DEngine()->GetActiveViewport();
A3DViewport * pPortraitViewport = g_pGame->GetPortraitRender()->GetPortraitViewport();
A3DCameraBase * pCamera = pPortraitViewport->GetCamera();
A3DVIEWPORTPARAM viewParam = *pPortraitViewport->GetParam();
viewParam.X = rc.left;
viewParam.Y = rc.top;
viewParam.Width = rc.right - rc.left;
viewParam.Height = rc.bottom - rc.top;
pPortraitViewport->SetParam(&viewParam);
((A3DCamera *) pCamera)->SetProjectionParam(-1.0f, -1.0f, -1.0f, ((float)viewParam.Width) / viewParam.Height);
A3DMATRIX4 matHead = a3d_RotateY(vDeg) * pFace->GetFaceTM();
A3DVECTOR3 vecPos = matHead.GetRow(3);
A3DVECTOR3 vecDir = Normalize(matHead.GetRow(2));
A3DVECTOR3 vecUp = Normalize(matHead.GetRow(1));
int index = pPlayer->GetProfession() * NUM_GENDER + pPlayer->GetGender();
float vHeadScale = 1.0f;
A3DSkinModel * pFaceModel = pPlayer->GetFaceModel()->GetA3DSkinModel();
A3DBone * pBoneUp = pFaceModel->GetSkeleton()->GetBone("脸盘010", NULL);
A3DBone * pBoneLow = pFaceModel->GetSkeleton()->GetBone("脸盘120", NULL);
float vDis = Magnitude(pBoneUp->GetAbsoluteTM().GetRow(3) - pBoneLow->GetAbsoluteTM().GetRow(3));
vHeadScale = vDis / headsize[index] * pPlayer->GetPortraitCameraScale();
pCamera->SetPos(vecPos + vecDir * (pose[index][0] * vHeadScale * 1.3f) + vecUp * pose[index][1] * vHeadScale * 1.05f);
pCamera->SetDirAndUp(-vecDir, vecUp);
pPortraitViewport->Active();
pPortraitViewport->ClearDevice();
CECViewport viewport;
viewport.InitFromA3D(pPortraitViewport);
g_pGame->GetA3DDevice()->SetAlphaBlendEnable(true);
g_pGame->GetA3DDevice()->SetAlphaTestEnable(true);
// 保存原有透明度(显示头像时需屏蔽透明度)
float fTransparent = pFace->GetTransparent();
// 重置透明度
pFace->SetTransparent(-1.0f);
A3DSkinModel::LIGHTINFO light = MakePlayerModelLightInfoForAUI(pCamera->GetDir());
if(pPlayer->IsSitting() && (pPlayer->GetRace() == RACE_GHOST || pPlayer->GetRace() == RACE_OBORO))
{
// 打坐使用特殊模型时,需要对头像显示特殊处理 by SunXuewei 2009-11-18
int iMaterialMethod = pFaceModel->GetMaterialMethod();
pFaceModel->SetMaterialMethod(A3DSkinModel::MTL_ORIGINAL);
pFace->Render(&viewport, true, false, &light);
pFaceModel->SetMaterialMethod(iMaterialMethod);
}
else
{
pFace->Render(&viewport, true, false, &light);
}
// 渲染脸部引用的GFX特效(如灵族的额饰特效)
// 需使用正确的 alpha 模式
g_pGame->GetA3DDevice()->SetAlphaBlendEnable(true);
g_pGame->GetA3DDevice()->SetAlphaTestEnable(false);
g_pGame->GetA3DGFXExMan()->RenderAllGfx(pPortraitViewport, true);
g_pGame->GetA3DDevice()->SetAlphaBlendEnable(true);
g_pGame->GetA3DDevice()->SetAlphaTestEnable(false);
// 恢复原有透明度
pFace->SetTransparent(fTransparent);
pCurViewport->Active();
}
void PlayerRenderDemonstration(const A3DRECT &rc, DWORD param1, DWORD param2, DWORD param3)
{
static const float _dist[NUM_PROFESSION][2] =
{
{ -9.2f, -8.4f }, // 武侠
{ -9.2f, -8.4f }, // 法师
{ -9.2f, -8.4f }, // 僧侣
{ -9.2f, -8.4f }, // 妖精
{ -9.5f, -8.4f }, // 妖兽
{ -9.2f, -8.4f }, // 魅灵
{ -9.2f, -8.4f }, // 羽芒
{ -9.2f, -8.4f }, // 羽灵
{ -9.2f, -8.4f }, // 剑灵
{ -9.2f, -8.4f }, // 魅灵
{ -9.2f, -8.4f }, // 夜影
{ -9.2f, -8.4f }, // 月仙
};
static const float _height[NUM_PROFESSION][2] =
{
{ 0.95f, 0.85f }, // 武侠
{ 0.95f, 0.85f }, // 法师
{ 0.95f, 0.85f }, // 僧侣
{ 0.95f, 0.85f }, // 妖精
{ 1.0f, 0.85f }, // 妖兽
{ 0.95f, 0.85f }, // 魅灵
{ 0.95f, 0.85f }, // 羽芒
{ 0.95f, 0.85f }, // 羽灵
{ 0.95f, 0.85f }, // 剑灵
{ 0.95f, 0.85f }, // 魅灵
{ 0.95f, 0.85f }, // 夜影
{ 0.95f, 0.85f }, // 月仙
};
static const float _nearest_dist = -1.f;
static const float _x_max = 1.f;
if( param1 == 0 )
return;
CECPlayer * pPlayer = (CECPlayer *) param1;
float vDeg = DEG2RAD(param2);
char nDist = (param3 >> 8) & 0xff;
char nHeight = param3 & 0xff;
char nLeftRight = (param3 >> 16) & 0xff;
A3DViewport * pCurViewport = g_pGame->GetA3DEngine()->GetActiveViewport();
A3DViewport * pPortraitViewport = g_pGame->GetPortraitRender()->GetPortraitViewport();
A3DCameraBase * pCamera = pPortraitViewport->GetCamera();
A3DRECT rcClamped = rc;
if (rcClamped.left < (int)pCurViewport->GetParam()->X){
rcClamped.left = (int)pCurViewport->GetParam()->X;
}
if (rcClamped.top < (int)pCurViewport->GetParam()->Y){
rcClamped.top = (int)pCurViewport->GetParam()->Y;
}
if (rcClamped.right > (int)pCurViewport->GetParam()->X + (int)pCurViewport->GetParam()->Width){
rcClamped.right = (int)pCurViewport->GetParam()->X + (int)pCurViewport->GetParam()->Width;
}
if (rcClamped.bottom > (int)pCurViewport->GetParam()->Y + (int)pCurViewport->GetParam()->Height){
rcClamped.bottom = (int)pCurViewport->GetParam()->Y + (int)pCurViewport->GetParam()->Height;
}
A3DVIEWPORTPARAM viewParam = *pPortraitViewport->GetParam();
viewParam.X = rcClamped.left;
viewParam.Y = rcClamped.top;
viewParam.Width = rcClamped.right - rcClamped.left;
viewParam.Height = rcClamped.bottom - rcClamped.top;
pPortraitViewport->SetParam(&viewParam);
((A3DCamera *) pCamera)->SetProjectionParam(-1.0f, -1.0f, -1.0f, ((float)viewParam.Width) / viewParam.Height);
int nGender = pPlayer->GetGender();
int nProfession = pPlayer->GetProfession();
float fDist = nDist / 100.f * (_nearest_dist - _dist[nProfession][nGender]) + _dist[nProfession][nGender];
float fHeight = (nHeight + 100) / 100.f * _height[nProfession][nGender];
float fXpos = nLeftRight / 50.f * _x_max - _x_max;
A3DMATRIX4 mat = a3d_RotateY(vDeg);
A3DVECTOR3 vecPos = A3DVECTOR3(fXpos, fHeight + (/*pPlayer->UsingWing()*/pPlayer->GetWingType() == WINGTYPE_WING ? 0.3f : 0.0f), fDist) * mat;
A3DVECTOR3 vecDir = A3DVECTOR3(0, 0, 1.0f) * mat;
A3DVECTOR3 vecUp = A3DVECTOR3(0, 1.0f, 0);
pCamera->SetPos(vecPos);
pCamera->SetDirAndUp(vecDir, vecUp);
pPortraitViewport->Active();
pPortraitViewport->ClearDevice();
A3DSkinModel::LIGHTINFO light = MakePlayerModelLightInfoForAUI(pCamera->GetDir());
if (pPlayer->GetPlayerModel()->GetA3DSkinModel())
pPlayer->GetPlayerModel()->GetA3DSkinModel()->SetLightInfo(light);
// 开始渲染
// 设置图元收集对象
A3DEngine* pA3DEngine = g_pGame->GetA3DEngine();
A3DSkinRender* psr = g_pGame->GetSkinRender2();
A3DSkinRender* psrold = pA3DEngine->GetA3DSkinMan()->GetCurSkinRender();
pA3DEngine->GetA3DSkinMan()->SetCurSkinRender(psr);
// 渲染 非Alpha 物体
g_pGame->GetA3DDevice()->SetAlphaBlendEnable(false);
g_pGame->GetA3DDevice()->SetAlphaTestEnable(true);
g_pGame->GetA3DDevice()->SetAlphaFunction(A3DCMP_GREATER);
g_pGame->GetA3DDevice()->SetAlphaRef(84);
// CECModel::Render 中不更新光照参数,以免试衣模型受环境光影响
CECModel *pPlayerModel = pPlayer->GetPlayerModel();
bool bUpdateFlagOld = pPlayerModel->GetUpdateLightInfoFlag();
pPlayerModel->SetUpdateLightInfoFlag(false);
pPlayerModel->Render(pPortraitViewport);
pPlayerModel->SetUpdateLightInfoFlag(bUpdateFlagOld);
if (pPlayer->GetFaceModel())
{
CECViewport v;
v.InitFromA3D(pPortraitViewport);
pPlayer->GetFaceModel()->Render(&v, true, false, &light);
}
psr->Render(pPortraitViewport, false);
psr->ResetRenderInfo(false);
// 渲染 Alpha 物体
g_pGame->GetA3DDevice()->SetAlphaTestEnable(false);
g_pGame->GetA3DDevice()->SetAlphaBlendEnable(true);
psr->RenderAlpha(pPortraitViewport);
psr->ResetRenderInfo(true);
g_pGame->GetA3DGFXExMan()->RenderAllGfx(pPortraitViewport, true);
// 恢复原有设置
pA3DEngine->GetA3DSkinMan()->SetCurSkinRender(psrold);
pCurViewport->Active();
}
bool CECPlayer::HasWingModel()const
{
return m_pPlayerModel != NULL
&& (m_pPlayerModel->GetChildModel(_wing) || m_pPlayerModel->GetChildModel(_wing2));
}
//把比例从int 转换到float
float CECPlayer::TransformScaleFromIntToFloat(int nScale, float fScaleFactor, float fMax)
{
if(fScaleFactor >= 1.0)
fScaleFactor = 0.99f;
if(fScaleFactor >= fMax)
fScaleFactor = fMax;
else if ( fScaleFactor < 0.0f)
fScaleFactor = 0.0f;
float fScale = (nScale - 128.0f)/128.0f;
fScale = fScale * fScaleFactor + 1.0f;
return fScale;
}
void CECPlayer::InitCustomizeFactor(void)
{
m_CustomizeFactor.fScaleHeadFactor = SCALE_HEAD_FACTOR;
m_CustomizeFactor.fScaleUpFactor = SCALE_UP_FACTOR;
m_CustomizeFactor.fScaleWaistFactor = SCALE_WAIST_FACTOR;
m_CustomizeFactor.fWidthArmFactor = WIDTH_ARM_FACTOR;
m_CustomizeFactor.fWidthLegFactor = WIDTH_LEG_FACTOR;
m_CustomizeFactor.fScaleBreastFactor = SCALE_BREAST_FACTOR;
}
bool CECPlayer::LoadCustomizeFactorFromIni(void)
{
AIniFile IniFile;
if (!IniFile.Open("Configs\\CustomizeFactor.ini"))
{
a_LogOutput(1, "CECPlayer::LoadFaceShapeFactorFromINIFile, Failed to open file Configs\\CustomizeFactor.ini");
return false;
}
AString strSection = "Stature";
m_CustomizeFactor.fScaleHeadFactor = IniFile.GetValueAsFloat(strSection, "HeadScaleFactor",m_CustomizeFactor.fScaleHeadFactor);
m_CustomizeFactor.fScaleUpFactor = IniFile.GetValueAsFloat(strSection, "UpScaleFactor", m_CustomizeFactor.fScaleUpFactor);
m_CustomizeFactor.fScaleWaistFactor = IniFile.GetValueAsFloat(strSection, "WaistScaleFactor", m_CustomizeFactor.fScaleWaistFactor);
m_CustomizeFactor.fWidthArmFactor = IniFile.GetValueAsFloat(strSection, "ArmWidthFactor", m_CustomizeFactor.fWidthArmFactor);
m_CustomizeFactor.fWidthLegFactor = IniFile.GetValueAsFloat(strSection, "LegWidthFactor", m_CustomizeFactor.fWidthLegFactor);
m_CustomizeFactor.fScaleBreastFactor = IniFile.GetValueAsFloat(strSection, "BreastScaleFactor", m_CustomizeFactor.fScaleBreastFactor);
IniFile.Close();
return true;
}
// Print bubble text
void CECPlayer::BubbleText(int iIndex, DWORD dwNum, int p1/* 0 */)
{
if (!m_pBubbleTexts)
return;
bool bHost = IsHostPlayer();
// if (iIndex == BUBBLE_EXP || iIndex == BUBBLE_SP)
// bHost = false;
DWORD dwCol = A3DCOLORRGB(255, 205, 75);
// Print notify text into chat dialog
if(bHost)
{
CECHostPlayer* pHost = g_pGame->GetGameRun()->GetHostPlayer();
if (iIndex == BUBBLE_EXP)
{
g_pGame->GetGameRun()->AddFixedChannelMsg((int)dwNum > 0 ?
(pHost->GetReincarnationTome().tome_active ? FIXMSG_GOT_BOOKEXP : FIXMSG_GOTEXP)
: FIXMSG_LOSTEXP, GP_CHAT_FIGHT, (int)dwNum);
}
if (iIndex == BUBBLE_SP)
{
g_pGame->GetGameRun()->AddFixedChannelMsg(FIXMSG_GOTSP, GP_CHAT_FIGHT, (int)dwNum);
}
if (iIndex == BUBBLE_REALMEXP)
{
g_pGame->GetGameRun()->AddFixedChannelMsg(FIXMSG_GOT_REALMEXP, GP_CHAT_FIGHT, (int)dwNum);
}
}
A3DVECTOR3 vPos;
if (IsInChariot())
{
vPos = GetPos() + g_vAxisY * (GetDummyModel(PLAYERMODEL_DUMMYTYPE2)->GetModelAABB().Extents.y * 2.3f);
}
else
vPos = GetPos() + g_vAxisY * (m_aabb.Extents.y * 2.5f);
CECBubbleDecal* pBubbleDecal = m_pBubbleTexts->AddDecal(vPos, CECDecal::DCID_ICONDECAL);
CECIconDecal* pDecal = (CECIconDecal*)pBubbleDecal->GetDecal();
switch (iIndex)
{
case BUBBLE_DAMAGE:
if (!bHost)
dwCol = A3DCOLORRGB(237, 56, 0);
if (p1 & 0x0001)
pDecal->AddIcon(CECImageRes::IMG_DEADLYSTRIKE, 0, dwCol);
else if (p1 & 0x0002)
pDecal->AddIcon(CECImageRes::IMG_RETORT, 0, dwCol);
pDecal->AddNumIcons(CECImageRes::IMG_POPUPNUM, dwNum, dwCol);
break;
case BUBBLE_EXP:
pDecal->AddIcon(CECImageRes::IMG_GOTEXP, 0, dwCol);
pDecal->AddNumIcons(CECImageRes::IMG_POPUPNUM, dwNum, dwCol);
// pDecal->SetScreenPos(80, 70);
// pDecal->EnableScreenPos(true);
break;
case BUBBLE_SP:
pDecal->AddIcon(CECImageRes::IMG_GOTSP, 0, dwCol);
pDecal->AddNumIcons(CECImageRes::IMG_POPUPNUM, dwNum, dwCol);
// pDecal->SetScreenPos(80, 90);
// pDecal->EnableScreenPos(true);
break;
case BUBBLE_MONEY:
pDecal->AddIcon(CECImageRes::IMG_GOTMONEY, 0, dwCol);
pDecal->AddNumIcons(CECImageRes::IMG_POPUPNUM, dwNum, dwCol);
break;
case BUBBLE_LEVELUP:
pDecal->AddIcon(CECImageRes::IMG_LEVELUP, 0, dwCol);
break;
case BUBBLE_HITMISSED:
if (!bHost)
dwCol = A3DCOLORRGB(237, 56, 0);
pDecal->AddIcon(CECImageRes::IMG_HITMISSED, 0, dwCol);
break;
case BUBBLE_INVALIDHIT:
if (!bHost)
dwCol = A3DCOLORRGB(237, 56, 0);
pDecal->AddIcon(CECImageRes::IMG_INVALIDHIT, 0, dwCol);
break;
case BUBBLE_IMMUNE:
if (!bHost)
dwCol = A3DCOLORRGB(237, 56, 0);
pDecal->AddIcon(CECImageRes::IMG_IMMUNE, 0, dwCol);
break;
case BUBBLE_HPWARN:
dwCol = A3DCOLORRGB(255, 255, 255);
pDecal->AddIcon(CECImageRes::IMG_HPWARN, 0, dwCol);
break;
case BUBBLE_MPWARN:
dwCol = A3DCOLORRGB(255, 255, 255);
pDecal->AddIcon(CECImageRes::IMG_MPWARN, 0, dwCol);
break;
case BUBBLE_REBOUND:
pDecal->AddIcon(CECImageRes::IMG_REBOUND, 0, dwCol);
pDecal->AddNumIcons(CECImageRes::IMG_POPUPNUM, dwNum, dwCol);
break;
case BUBBLE_BEAT_BACK:
pDecal->AddIcon(CECImageRes::IMG_BEAT_BACK, 0, dwCol);
pDecal->AddNumIcons(CECImageRes::IMG_POPUPNUM, dwNum, dwCol);
break;
case BUBBLE_ADD:
dwCol = A3DCOLORRGB(126, 206, 244);
pDecal->AddIcon(CECImageRes::IMG_ADD, 0, dwCol);
pDecal->AddNumIcons(CECImageRes::IMG_POPUPNUM, dwNum, dwCol);
break;
case BUBBLE_DODGE_DEBUFF:
if (!bHost)
dwCol = A3DCOLORRGB(237, 56, 0);
pDecal->AddIcon(CECImageRes::IMG_DODGE_DEBUFF, 0, dwCol);
break;
default:
return;
}
}
bool CECPlayer::IsClothesOn()
{
if( m_bFashionMode )
{
if( m_iGender == GENDER_MALE )
{
if( !m_aCurSkins[SKIN_FASHION_LOWER_INDEX] )
return false;
}
else
{
if( !m_aCurSkins[SKIN_FASHION_UPPER_BODY_INDEX] ||
!m_aCurSkins[SKIN_FASHION_LOWER_INDEX] )
return false;
}
}
else
{
if( !m_aCurSkins[SKIN_UPPER_BODY_INDEX] ||
!m_aCurSkins[SKIN_LOWER_INDEX] )
return false;
}
return true;
}
bool CECPlayer::UpdateCurSkins()
{
if (GetMajorModel())
{
int i;
for(i=0; i<NUM_SKIN_INDEX; i++)
{
int lodLevel = 0;
// first of all update lod based skin
if( m_fDistToCamera > 20.0f )
lodLevel = 2;
else if( m_fDistToCamera > 10.0f )
lodLevel = 1;
if( m_bFashionMode )
{
if (i >= SKIN_UPPER_BODY_INDEX && i <= SKIN_FOOT_INDEX)
{
ReplaceCurSkin(i, NULL);
}
else
{
ReplaceCurSkin(i, m_aSkins[i][lodLevel]);
}
}
else
{
if (i >= SKIN_FASHION_UPPER_BODY_INDEX && i <= SKIN_FASHION_FOOT_INDEX)
{
ReplaceCurSkin(i, NULL);
}
else
{
ReplaceCurSkin(i, m_aSkins[i][lodLevel]);
}
}
}
}
return true;
}
//吃变形丸
bool CECPlayer::EatChgPill(const char* pszPillFile, float vCamScale)
{
if(!m_ChangePill.IsEmpty())
return false;
if(!m_ChangePill.Load(pszPillFile))
return false;
if( (m_ChangePill.GetCharacter() != m_iProfession) || (m_ChangePill.GetGender() != m_iGender))
return false;
if( m_ChangePill.IsEmpty())
return false;
//备份原有个性化数据
BackupCustomizeData();
//设置变形丸数据
for( int i = 0; i < m_ChangePill.GetChgPillDataCount(); i++)
{
SetChgPillData(m_ChangePill.GetChgPillData(i)->nKey, m_ChangePill.GetChgPillData(i)->nValue);
}
//变形
ChangeCustomizeData(m_CustomizeData);
m_vPortraitCamScale = vCamScale;
m_bIsChangingFace = true;
return true;
}
//设置变形丸数据
bool CECPlayer::SetChgPillData(int nID, int nData)
{
switch(nID)
{
case CUS_HEAD_SCALE:
m_CustomizeData.headScale = nData;
return true;
case CUS_UP_SCALE:
m_CustomizeData.upScale = nData;
return true;
case CUS_WAIST_SCALE:
m_CustomizeData.waistScale = nData;
return true;
case CUS_ARM_WIDTH:
m_CustomizeData.armWidth = nData;
return true;
case CUS_LEG_WIDTH:
m_CustomizeData.legWidth = nData;
return true;
case CUS_BREAST_SCALE:
m_CustomizeData.breastScale = nData;
return true;
case CUS_ID_FACE:
m_CustomizeData.faceData.idFaceShape1 = nData;
m_CustomizeData.faceData.idFaceShape2 = nData;
return true;
case CUS_ID_FALING:
m_CustomizeData.faceData.idFalingSkin = nData;
return true;
case CUS_SCALE_FACEH:
m_CustomizeData.faceData.scaleFaceH = nData;
return true;
case CUS_SCALE_FACEV:
m_CustomizeData.faceData.scaleFaceV = nData;
return true;
case CUS_SCALE_UP:
m_CustomizeData.faceData.scaleUp = nData;
return true;
case CUS_SCALE_MIDDLE:
m_CustomizeData.faceData.scaleMiddle = nData;
return true;
case CUS_SCALE_DOWN:
m_CustomizeData.faceData.scaleDown = nData;
return true;
case CUS_OFFSET_FOREHEADH:
m_CustomizeData.faceData.offsetForeheadH = nData;
return true;
case CUS_OFFSET_FOREHEADV:
m_CustomizeData.faceData.offsetForeheadV = nData;
return true;
case CUS_OFFSET_FOREHEADZ:
m_CustomizeData.faceData.offsetForeheadZ = nData;
return true;
case CUS_ROTATE_FOREHEAD:
m_CustomizeData.faceData.rotateForehead = nData;
return true;
case CUS_SCALE_FOREHEAD:
m_CustomizeData.faceData.scaleForehead = nData;
return true;
case CUS_OFFSET_YOKEBONEH:
m_CustomizeData.faceData.offsetYokeBoneH = nData;
return true;
case CUS_OFFSET_YOKEBONEV:
m_CustomizeData.faceData.offsetYokeBoneV = nData;
return true;
case CUS_OFFSET_YOKEBONEZ:
m_CustomizeData.faceData.offsetYokeBoneZ = nData;
return true;
case CUS_ROTATE_YOKEBONE:
m_CustomizeData.faceData.rotateYokeBone = nData;
return true;
case CUS_SCALE_YOKEBONE:
m_CustomizeData.faceData.scaleYokeBone = nData;
return true;
case CUS_OFFSET_CHEEKH:
m_CustomizeData.faceData.offsetCheekH = nData;
return true;
case CUS_OFFSET_CHEEKV:
m_CustomizeData.faceData.offsetCheekV = nData;
return true;
case CUS_OFFSET_CHEEKZ:
m_CustomizeData.faceData.offsetCheekZ = nData;
return true;
case CUS_SCALE_CHEEK:
m_CustomizeData.faceData.scaleCheek = nData;
return true;
case CUS_OFFSET_CHAINV:
m_CustomizeData.faceData.offsetChainV = nData;
return true;
case CUS_OFFSET_CHAINZ:
m_CustomizeData.faceData.offsetChainZ = nData;
return true;
case CUS_ROTATE_CHAIN:
m_CustomizeData.faceData.rotateChain = nData;
return true;
case CUS_SCALE_CHAINH:
m_CustomizeData.faceData.scaleChainH = nData;
return true;
case CUS_OFFSET_JAWH:
m_CustomizeData.faceData.offsetJawH = nData;
return true;
case CUS_OFFSET_JAWV:
m_CustomizeData.faceData.offsetJawV = nData;
return true;
case CUS_OFFSET_JAWZ:
m_CustomizeData.faceData.offsetJawZ = nData;
return true;
case CUS_SCALE_JAWSPECIAL:
m_CustomizeData.faceData.scaleJawSpecial = nData;
return true;
case CUS_SCALE_JAWH:
m_CustomizeData.faceData.scaleJawH = nData;
return true;
case CUS_SCALE_JAWV:
m_CustomizeData.faceData.scaleJawV = nData;
return true;
case CUS_ID_EYE_BASETEX:
m_CustomizeData.faceData.idEyeBaseTex = nData;
return true;
case CUS_ID_EYE_SHAPE:
m_CustomizeData.faceData.idEyeShape = nData;
return true;
case CUS_SCALE_EYEH:
m_CustomizeData.faceData.scaleEyeH = nData;
return true;
case CUS_SCALE_EYEV:
m_CustomizeData.faceData.scaleEyeV = nData;
return true;
case CUS_ROTATE_EYE:
m_CustomizeData.faceData.rotateEye = nData;
return true;
case CUS_OFFSET_EYEH:
m_CustomizeData.faceData.offsetEyeH = nData;
return true;
case CUS_OFFSET_EYEV:
m_CustomizeData.faceData.offsetEyeV = nData;
return true;
case CUS_OFFSET_EYEZ:
m_CustomizeData.faceData.offsetEyeZ = nData;
return true;
case CUS_SCALE_EYE_BALL:
m_CustomizeData.faceData.scaleEyeBall = nData;
return true;
case CUS_SCALE_EYEH2:
m_CustomizeData.faceData.scaleEyeH2 = nData;
return true;
case CUS_SCALE_EYEV2:
m_CustomizeData.faceData.scaleEyeV2 = nData;
return true;
case CUS_ROTATE_EYE2:
m_CustomizeData.faceData.rotateEye2 = nData;
return true;
case CUS_OFFSET_EYEH2:
m_CustomizeData.faceData.offsetEyeH2 = nData;
return true;
case CUS_OFFSET_EYEV2:
m_CustomizeData.faceData.offsetEyeV2 = nData;
return true;
case CUS_OFFSET_EYEZ2:
m_CustomizeData.faceData.offsetEyeZ2 = nData;
return true;
case CUS_SCALE_EYE_BALL2:
m_CustomizeData.faceData.scaleEyeBall2 = nData;
return true;
case CUS_ID_BROW_TEX:
m_CustomizeData.faceData.idBrowTex = nData;
return true;
case CUS_ID_BROW_SHAPE:
m_CustomizeData.faceData.idBrowShape = nData;
return true;
case CUS_SCALE_BROWH:
m_CustomizeData.faceData.scaleBrowH = nData;
return true;
case CUS_SCALE_BROWV:
m_CustomizeData.faceData.scaleBrowV = nData;
return true;
case CUS_ROTATE_BROW:
m_CustomizeData.faceData.rotateBrow = nData;
return true;
case CUS_OFFSET_BROWH:
m_CustomizeData.faceData.offsetBrowH = nData;
return true;
case CUS_OFFSET_BROWV:
m_CustomizeData.faceData.offsetBrowV = nData;
return true;
case CUS_OFFSET_BROWZ:
m_CustomizeData.faceData.offsetBrowZ = nData;
return true;
case CUS_SCALE_BROWH2:
m_CustomizeData.faceData.scaleBrowH2 = nData;
return true;
case CUS_SCALE_BROWV2:
m_CustomizeData.faceData.scaleBrowV2 = nData;
return true;
case CUS_ROTATE_BROW2:
m_CustomizeData.faceData.rotateBrow2 = nData;
return true;
case CUS_OFFSET_BROWH2:
m_CustomizeData.faceData.offsetBrowH2 = nData;
return true;
case CUS_OFFSET_BROWV2:
m_CustomizeData.faceData.offsetBrowV2 = nData;
return true;
case CUS_OFFSET_BROWZ2:
m_CustomizeData.faceData.offsetBrowZ2 = nData;
return true;
case CUS_ID_NOSE_TEX:
m_CustomizeData.faceData.idNoseTex = nData;
return true;
case CUS_ID_NOSETIP_SHAPE:
m_CustomizeData.faceData.idNoseTipShape = nData;
return true;
case CUS_ID_NOSEBRIDGE_SHAPE:
m_CustomizeData.faceData.idNoseBridgeShape = nData;
return true;
case CUS_SCALE_NOSETIPH:
m_CustomizeData.faceData.scaleNoseTipH = nData;
return true;
case CUS_SCALE_NOSETIPV:
m_CustomizeData.faceData.scaleNoseTipV = nData;
return true;
case CUS_OFFSET_NOSETIPV:
m_CustomizeData.faceData.offsetNoseTipV = nData;
return true;
case CUS_SCALE_NOSETIPZ:
m_CustomizeData.faceData.scaleNoseTipZ = nData;
return true;
case CUS_SCALE_BRIDGETIPH:
m_CustomizeData.faceData.scaleBridgeTipH = nData;
return true;
case CUS_OFFSET_BRIDGETIPZ:
m_CustomizeData.faceData.offsetBridgeTipZ = nData;
return true;
case CUS_ID_MOUTH_UPLIPLINE:
m_CustomizeData.faceData.idMouthUpLipLine = nData;
return true;
case CUS_ID_MOUTH_MIDLIPLINE:
m_CustomizeData.faceData.idMouthMidLipLine = nData;
return true;
case CUS_ID_MOUTH_DOWNLIPLINE:
m_CustomizeData.faceData.idMouthDownLipLine = nData;
return true;
case CUS_THICK_UPLIP:
m_CustomizeData.faceData.thickUpLip = nData;
return true;
case CUS_THICK_DOWNLIP:
m_CustomizeData.faceData.thickDownLip = nData;
return true;
case CUS_OFFSET_MOUTHV:
m_CustomizeData.faceData.offsetMouthV = nData;
return true;
case CUS_OFFSET_MOUTHZ:
m_CustomizeData.faceData.offsetMouthZ = nData;
return true;
case CUS_SCALE_MOUTHH:
m_CustomizeData.faceData.scaleMouthH = nData;
return true;
case CUS_SCALE_MOUTHH2:
m_CustomizeData.faceData.scaleMouthH2 = nData;
return true;
case CUS_OFFSET_CORNEROFMOUTHSPECIAL:
m_CustomizeData.faceData.offsetCornerOfMouthSpecial = nData;
return true;
case CUS_OFFSET_CORNEROFMOUTHSPECIAL2:
m_CustomizeData.faceData.offsetCornerOfMouthSpecial2 = nData;
return true;
case CUS_ID_EAR_SHAPE:
m_CustomizeData.faceData.idEarShape = nData;
return true;
case CUS_SCALE_EAR:
m_CustomizeData.faceData.scaleEar = nData;
return true;
case CUS_OFFSET_EARV:
m_CustomizeData.faceData.offsetEarV = nData;
return true;
case CUS_ID_HAIR_MODEL:
m_CustomizeData.faceData.idHairModel = nData;
return true;
case CUS_ID_HAIR_TEX:
m_CustomizeData.faceData.idHairTex = nData;
return true;
case CUS_ID_MOUSTACHE_TEX:
m_CustomizeData.faceData.idMoustacheTex = nData;
return true;
case CUS_ID_MOUSTACHE_SKIN:
m_CustomizeData.faceData.idMoustacheSkin = nData;
return true;
case CUS_ID_GOATEE_TEX:
m_CustomizeData.faceData.idGoateeTex = nData;
return true;
case CUS_ID_EYE_HIGHTEX:
m_CustomizeData.faceData.idEyeHighTex = nData;
return true;
case CUS_COLOR_FACE:
m_CustomizeData.faceData.colorFace = nData;
m_CustomizeData.colorBody = nData;
return true;
case CUS_COLOR_EYE:
m_CustomizeData.faceData.colorEye = nData;
return true;
case CUS_COLOR_BROW:
m_CustomizeData.faceData.colorBrow = nData;
return true;
case CUS_COLOR_MOUTH:
m_CustomizeData.faceData.colorMouth = nData;
return true;
case CUS_COLOR_HAIR:
m_CustomizeData.faceData.colorHair = nData;
return true;
case CUS_COLOR_EYEBALL:
m_CustomizeData.faceData.colorEyeBall = nData;
return true;
case CUS_COLOR_MOUSTACHE:
m_CustomizeData.faceData.colorMoustache = nData;
return true;
default:
return false;
}
}
//备份个性化数据(与变形丸相关)
void CECPlayer::BackupCustomizeData(void)
{
memcpy(&m_ChgPllCustomizeData, &m_CustomizeData, sizeof(PLAYER_CUSTOMIZEDATA));
}
//还原备份个性化数据(与变形丸相关)
bool CECPlayer::DiscardChgPill(void)
{
if( m_ChangePill.IsEmpty())
return false;
ChangeCustomizeData(m_ChgPllCustomizeData);
m_ChangePill.ClearChangePillData();
m_vPortraitCamScale = 1.0f;
m_bIsChangingFace = false;
return true;
}
// Apply effect on player
bool CECPlayer::ApplyEffect(int iEffect, bool bCheckArray)
{
if (bCheckArray)
{
// Check whether player has had this effect
for (int i=0; i < m_aCurEffects.GetSize(); i++)
{
if (m_aCurEffects[i] == iEffect)
return true;
}
m_aCurEffects.UniquelyAdd(iEffect);
}
CECIvtrItem* pItem = CECIvtrItem::CreateItem(iEffect, 0, 1);
if (!pItem)
return false;
switch (pItem->GetClassID())
{
case CECIvtrItem::ICID_FACEPILL:
{
const char* szFile = ((CECIvtrFacePill*)pItem)->GetPillFile(m_iProfession, m_iGender);
if (szFile)
EatChgPill(szFile, ((CECIvtrFacePill*)pItem)->GetDBEssence()->camera_scale);
break;
}
}
delete pItem;
return true;
}
// Discard effect from player
void CECPlayer::DiscardEffect(int iEffect)
{
// From from effect records
for (int i=0; i < m_aCurEffects.GetSize(); i++)
{
if (m_aCurEffects[i] == iEffect)
{
m_aCurEffects.RemoveAtQuickly(i);
break;
}
}
CECIvtrItem* pItem = CECIvtrItem::CreateItem(iEffect, 0, 1);
if (!pItem)
return;
switch (pItem->GetClassID())
{
case CECIvtrItem::ICID_FACEPILL:
DiscardChgPill();
break;
}
delete pItem;
}
// Check whether player has effect of specified type
bool CECPlayer::HasEffectType(int iEffType)
{
int i;
switch (iEffType)
{
case EFF_FACEPILL:
{
elementdataman* pDataMan = g_pGame->GetElementDataMan();
// Get item data type
for (i=0; i < m_aCurEffects.GetSize(); i++)
{
DATA_TYPE DataType = pDataMan->get_data_type(m_aCurEffects[i], ID_SPACE_ESSENCE);
if (DataType == DT_FACEPILL_ESSENCE)
return true;
}
break;
}
}
return false;
}
// Play start use item action
bool CECPlayer::PlayStartUseItemAction(int tid)
{
DATA_TYPE dt;
const void * pDBEssence = g_pGame->GetElementDataMan()->get_data_ptr(tid, ID_SPACE_ESSENCE, dt);
switch(dt)
{
case DT_MEDICINE_ESSENCE:
break;
case DT_TOWNSCROLL_ESSENCE:
case DT_UNIONSCROLL_ESSENCE:
PlayAction(ACT_USEITEM);
PlayAction(ACT_USEITMELOOP, true, 0, true);
break;
case DT_REVIVESCROLL_ESSENCE:
if( IsDead() )
break;
else
{
// play an action use revive scroll to revive somebody else
PlayAction(ACT_USEITEM);
PlayAction(ACT_USEITMELOOP, true, 0, true);
}
break;
case DT_WAR_TANKCALLIN_ESSENCE:
if( IsDead() )
break;
else
{
// play an action use revive scroll to revive somebody else
PlayAction(ACT_USEITEM);
PlayAction(ACT_USEITMELOOP, true, 0, true);
}
break;
case DT_FIREWORKS_ESSENCE:
if( IsDead() )
break;
else
{
PlayAction(ACT_EXP_ASSAULT);
}
break;
}
return true;
}
bool CECPlayer::PlayGatherMonsterSpiritAction()
{
PlayAction(ACT_USEITEM);
PlayAction(ACT_USEITMELOOP, true, 0, true);
return true;
}
// Play use item effect
bool CECPlayer::PlayUseItemEffect(int tid, const void* pData, size_t sz)
{
DATA_TYPE dt;
const void * pDBEssence = g_pGame->GetElementDataMan()->get_data_ptr(tid, ID_SPACE_ESSENCE, dt);
switch(dt)
{
case DT_MEDICINE_ESSENCE:
{
if( !GetPlayerModel() )
return true;
const MEDICINE_ESSENCE * pMedicine = (MEDICINE_ESSENCE *) pDBEssence;
switch(pMedicine->id_major_type)
{
case 1794: // 加生命
PlayGfx(res_GFXFile(RES_GFX_RED_MEDICINE), NULL, 1.0, PLAYERMODEL_TYPEALL);
break;
case 1802: // 加真气
PlayGfx(res_GFXFile(RES_GFX_BLUE_MEDICINE), NULL, 1.0, PLAYERMODEL_TYPEALL);
break;
case 1810: // 加生命和真气
PlayGfx(res_GFXFile(RES_GFX_PURPLE_MEDICINE), NULL, 1.0, PLAYERMODEL_TYPEALL);
break;
case 1815: // 解毒
case 2038: // 瞬间解毒
PlayGfx(res_GFXFile(RES_GFX_JIEDU_MEDICINE), NULL, 1.0, PLAYERMODEL_TYPEALL);
break;
}
break;
}
case DT_TOWNSCROLL_ESSENCE:
break;
case DT_ARMORRUNE_ESSENCE:
{
if( !GetPlayerModel() )
return true;
const ARMORRUNE_ESSENCE * pArmorRune = (ARMORRUNE_ESSENCE *) pDBEssence;
switch(pArmorRune->id_sub_type)
{
case 405: // 物防符
PlayGfx(res_GFXFile(RES_GFX_PHYSIC_ARMORRUNE), NULL, 1.0, PLAYERMODEL_TYPEALL);
break;
case 406: // 法防符
PlayGfx(res_GFXFile(RES_GFX_MAGIC_ARMORRUNE), NULL, 1.0, PLAYERMODEL_TYPEALL);
break;
}
break;
}
break;
case DT_FIREWORKS_ESSENCE:
{
const FIREWORKS_ESSENCE * pFireWorks = (FIREWORKS_ESSENCE *) pDBEssence;
if( pFireWorks->file_fw[0] )
{
g_pGame->GetGFXCaster()->PlayFW(pFireWorks->file_fw, pFireWorks->time_to_fire * 1000, GetPos() + GetDir() * 0.5f, GetDir());
}
DoEmote(ROLEEXP_FIREWORK);
}
break;
case DT_SKILLMATTER_ESSENCE:
{
const SKILLMATTER_ESSENCE * pSkillMatter = (SKILLMATTER_ESSENCE *) pDBEssence;
if( pSkillMatter->id_skill )
{
abase::vector<TARGET_DATA> targets;
g_pGame->GetGameRun()->GetWorld()->GetAttacksMan()->GetSkillGfxComposerMan()->Play(
pSkillMatter->id_skill, GetPlayerInfo().cid, GetPlayerInfo().cid, targets);
}
}
break;
}
return true;
}
float CECPlayer::GetEquipGfxScale()
{
float vScale = 1.0f;
if( m_iGender == GENDER_FEMALE )
vScale = 0.6f;
else if( m_iProfession == PROF_ORC )
vScale = 1.3f;
return vScale;
}
void CECPlayer::AddUpperBodyStones()
{
if (InFashionMode()){
RemoveUpperBodyStones();
return;
}
if (!CECOptimize::Instance().GetGFX().CanShowArmorStone(GetCharacterID(), GetClassID())){
return;
}
const WORD &stone = m_stoneUpperBody;
WORD &stoneShown = m_stoneUpperBodyShown;
if (stoneShown == stone){
return;
}
if (stoneShown != 0){
RemoveUpperBodyStones();
}
if (stone == 0){
return;
}
int nEquipIndex = EQUIPIVTR_BODY;
float vScale = GetEquipGfxScale();
AString strGFX = GetArmorStoneGfx(stone, nEquipIndex);
if (PlayGfx(strGFX, "HH_Spine", vScale)){
stoneShown = stone;
}
strGFX = GetArmorStoneGfx(stone, nEquipIndex, 1);
if (PlayGfx(strGFX, "HH_Shangshen02", vScale)){
stoneShown = stone;
}
if (PlayGfx(strGFX, "HH_Shangshen05", vScale)){
stoneShown = stone;
}
}
void CECPlayer::RemoveUpperBodyStones()
{
WORD &stoneShown = m_stoneUpperBodyShown;
if (stoneShown == 0) return;
int nEquipIndex = EQUIPIVTR_BODY;
AString strGFX = GetArmorStoneGfx(stoneShown, nEquipIndex);
RemoveGfx(strGFX, "HH_Spine");
strGFX = GetArmorStoneGfx(stoneShown, nEquipIndex, 1);
RemoveGfx(strGFX, "HH_Shangshen02");
RemoveGfx(strGFX, "HH_Shangshen05");
stoneShown = 0;
}
void CECPlayer::AddWristStones()
{
if (InFashionMode()){
RemoveWristStones();
return;
}
if (!CECOptimize::Instance().GetGFX().CanShowArmorStone(GetCharacterID(), GetClassID())){
return;
}
const WORD &stone = m_stoneWrist;
WORD &stoneShown = m_stoneWristShown;
if (stoneShown == stone){
return;
}
if (stoneShown != 0){
RemoveWristStones();
}
if (stone == 0){
return;
}
int nEquipIndex = EQUIPIVTR_WRIST;
float vScale = GetEquipGfxScale();
AString strGFX = GetArmorStoneGfx(stone, nEquipIndex);
if (PlayGfx(strGFX, "HH_shou03", vScale)){
stoneShown = stone;
}
if (PlayGfx(strGFX, "HH_shou04", vScale)){
stoneShown = stone;
}
}
void CECPlayer::RemoveWristStones()
{
WORD &stoneShown = m_stoneWristShown;
if (stoneShown == 0) return;
int nEquipIndex = EQUIPIVTR_WRIST;
AString strGFX = GetArmorStoneGfx(stoneShown, nEquipIndex);
RemoveGfx(strGFX, "HH_shou03");
RemoveGfx(strGFX, "HH_shou04");
stoneShown = 0;
}
void CECPlayer::AddLowerBodyStones()
{
if (InFashionMode()){
RemoveLowerBodyStones();
return;
}
if (!CECOptimize::Instance().GetGFX().CanShowArmorStone(GetCharacterID(), GetClassID())){
return;
}
const WORD &stone = m_stoneLowerBody;
WORD &stoneShown = m_stoneLowerBodyShown;
if (stoneShown == stone){
return;
}
if (stoneShown != 0){
RemoveLowerBodyStones();
}
if (stone == 0){
return;
}
int nEquipIndex = EQUIPIVTR_LEG;
float vScale = GetEquipGfxScale();
AString strGFX = GetArmorStoneGfx(stone, nEquipIndex);
if (PlayGfx(strGFX, "HH_xiashen02", vScale)){
stoneShown = stone;
}
if (PlayGfx(strGFX, "HH_xiashen04", vScale)){
stoneShown = stone;
}
}
void CECPlayer::RemoveLowerBodyStones()
{
WORD &stoneShown = m_stoneLowerBodyShown;
if (stoneShown == 0) return;
int nEquipIndex = EQUIPIVTR_LEG;
AString strGFX = GetArmorStoneGfx(stoneShown, nEquipIndex);
RemoveGfx(strGFX, "HH_xiashen02");
RemoveGfx(strGFX, "HH_xiashen04");
stoneShown = 0;
}
void CECPlayer::AddFootStones()
{
if (InFashionMode()){
RemoveFootStones();
return;
}
if (!CECOptimize::Instance().GetGFX().CanShowArmorStone(GetCharacterID(), GetClassID())){
return;
}
const WORD &stone = m_stoneFoot;
WORD &stoneShown = m_stoneFootShown;
if (stoneShown == stone){
return;
}
if (stoneShown != 0){
RemoveFootStones();
}
if (stone == 0){
return;
}
int nEquipIndex = EQUIPIVTR_FOOT;
float vScale = GetEquipGfxScale();
AString strGFX = GetArmorStoneGfx(stone, nEquipIndex);
if (PlayGfx(strGFX, "HH_xie02", vScale)){
stoneShown = stone;
}
if (PlayGfx(strGFX, "HH_xie04", vScale)){
stoneShown = stone;
}
}
void CECPlayer::RemoveFootStones()
{
WORD &stoneShown = m_stoneFootShown;
if (stoneShown == 0) return;
int nEquipIndex = EQUIPIVTR_FOOT;
AString strGFX = GetArmorStoneGfx(stoneShown, nEquipIndex);
RemoveGfx(strGFX, "HH_xie02");
RemoveGfx(strGFX, "HH_xie04");
stoneShown = 0;
}
AString CECPlayer::GetSharpenerGfx(WORD status)
{
// 计算被磨刀石磨过的装备应该显示的特效
// 若装备未被磨过,则返回空
//
AString strGfxFile;
BYTE idColor = (status>>8); // 高8位指示磨刀石控制的选项
if (idColor != 0)
{
static const char * szGFXFile[] =
{
"",
"物理攻击1级",
"物理攻击2级",
"物理攻击3级",
"法术攻击1级",
"法术攻击2级",
"法术攻击3级",
"生命增强1级",
"生命增强2级",
"生命增强3级",
"属性增强1级",
"属性增强2级",
"属性增强3级",
"特殊属性1级",
"特殊属性2级",
"特殊属性3级",
};
const int nGFXFile = sizeof(szGFXFile)/sizeof(szGFXFile[0]);
if (idColor >= nGFXFile)
idColor = nGFXFile-1;
strGfxFile.Format("程序联入\\磨刀石光效\\磨刀石光效%s.gfx", szGFXFile[idColor]);
}
return strGfxFile;
}
AString CECPlayer::GetArmorStoneGfx(WORD status, int nEquipIndex, int nEquipParam0)
{
// 根据防具类型、防具的GFX属性,查找对应的GFX路径
// status: 颜色参数
// nEquipIndex: 防具装备在装备包裹中的位置
// nEquipParam0: 附加参数
AString strGfxFile = GetSharpenerGfx(status);
if (strGfxFile.IsEmpty() && status != 0)
{
const char * szColors[] = {"", "红色", "白色", "金色", "蓝色", "紫色", "绿色", "混合"};
int idLevel = 1;
int idColor = status & 0x00ff;
if( idColor > 7 )
{
idColor %= 8;
idLevel = 2;
}
switch(nEquipIndex)
{
case EQUIPIVTR_BODY:
if (nEquipParam0 == 0)
{
strGfxFile.Format("程序联入\\装备宝石镶嵌\\%s%s%d级.gfx", szColors[idColor], "胸甲", idLevel);
}
else if (nEquipParam0 == 1)
{
strGfxFile.Format("程序联入\\装备宝石镶嵌\\%s%s%d级.gfx", szColors[idColor], "肩甲", idLevel);
}
break;
case EQUIPIVTR_WRIST:
strGfxFile.Format("程序联入\\装备宝石镶嵌\\%s%s%d级.gfx", szColors[idColor], "腕甲", idLevel);
break;
case EQUIPIVTR_LEG:
strGfxFile.Format("程序联入\\装备宝石镶嵌\\%s%s%d级.gfx", szColors[idColor], "腿甲", idLevel);
break;
case EQUIPIVTR_FOOT:
strGfxFile.Format("程序联入\\装备宝石镶嵌\\%s%s%d级.gfx", szColors[idColor], "靴甲", idLevel);
break;
}
}
return strGfxFile;
}
AString CECPlayer::GetWeaponStoneGfx(WORD status)
{
// 查找武器对应的GFX路径
// status: 颜色参数
AString strGfxFile = GetSharpenerGfx(status);
if (strGfxFile.IsEmpty() && status != 0)
{
const char * szColors[] = {"", "", "", "", "", "", "绿", ""};
int idColor1 = status & 0x7;
int idColor2 = (status >> 3) & 0x7;
if( idColor1 > idColor2 )
{
int temp = idColor1;
idColor1 = idColor2;
idColor2 = temp;
}
strGfxFile.Format("程序联入\\武器宝石镶嵌\\%s%s.gfx", szColors[idColor1], szColors[idColor2]);
}
return strGfxFile;
}
void CECPlayer::AddWeaponStones()
{
// 向当前武器模型(非时装武器)添加宝石特效
if (!CECOptimize::Instance().GetGFX().CanShowWeaponStone(GetCharacterID(), GetClassID())){
return;
}
if (!GetPlayerModel() || IsShowFashionWeapon()){
return; // 没显示武器模型
}
if (m_stoneWeaponShown == m_stoneWeapon){
return; // 特效没变化
}
if (m_stoneWeaponShown != 0){
RemoveWeaponStones();
}
if (m_stoneWeapon == 0){
return;
}
AString strGFX = GetWeaponStoneGfx(m_stoneWeapon);
if (strGFX.IsEmpty()){
return;
}
float vScale = GetEquipGfxScale();
if (CECModel* pLeftHandWeapon = GetLeftHandWeapon()){
const char * leftGFXHookPos = GetLeftWeaponGFXHookPos(pLeftHandWeapon);
pLeftHandWeapon->PlayGfx(strGFX, leftGFXHookPos, vScale);
m_stoneWeaponShown = m_stoneWeapon;
}
if (CECModel* pRightHandWeapon = GetRightHandWeapon()){
const char * rightGFXHookPos = GetRightWeaponGFXHookPos(pRightHandWeapon);
pRightHandWeapon->PlayGfx(strGFX, rightGFXHookPos, vScale);
m_stoneWeaponShown = m_stoneWeapon;
}
}
void CECPlayer::RemoveWeaponStones()
{
// 移除当前武器(非时装武器)上的特效(宝石镶嵌、磨刀石)
if (m_stoneWeaponShown == 0) return;
if (GetPlayerModel() && !IsShowFashionWeapon()){
AString strGFX = GetWeaponStoneGfx(m_stoneWeaponShown);
if (!strGFX.IsEmpty()){
if (CECModel* pLeftHandWeapon = GetLeftHandWeapon()){
const char * leftGFXHookPos = GetLeftWeaponGFXHookPos(pLeftHandWeapon);
pLeftHandWeapon->RemoveGfx(strGFX, leftGFXHookPos);
}
if (CECModel* pRightHandWeapon = GetRightHandWeapon()){
const char * rightGFXHookPos = GetRightWeaponGFXHookPos(pRightHandWeapon);
pRightHandWeapon->RemoveGfx(strGFX, rightGFXHookPos);
}
}
}
m_stoneWeaponShown = 0;
}
void CECPlayer::AddFullSuiteGFX()
{
if (InFashionMode()){
RemoveFullSuiteGFX();
return;
}
if (!CECOptimize::Instance().GetGFX().CanShowSuite(GetCharacterID(), GetClassID())){
return;
}
if (m_idFullSuiteShown == m_idFullSuite){
return;
}
if (m_idFullSuiteShown != 0){
RemoveFullSuiteGFX();
}
if (m_idFullSuite == 0){
return;
}
DATA_TYPE dt;
SUITE_ESSENCE * pSuite = (SUITE_ESSENCE *) g_pGame->GetElementDataMan()->get_data_ptr(m_idFullSuite, ID_SPACE_ESSENCE, dt);
if (dt == DT_SUITE_ESSENCE && pSuite->file_gfx[0]){
float vScale = GetEquipGfxScale();
if (PlayGfx(pSuite->file_gfx + 4, "HH_Spine", vScale)){
m_idFullSuiteShown = m_idFullSuite;
}
}
}
void CECPlayer::RemoveFullSuiteGFX()
{
if (m_idFullSuiteShown == 0) return;
DATA_TYPE dt;
SUITE_ESSENCE * pSuite = (SUITE_ESSENCE *) g_pGame->GetElementDataMan()->get_data_ptr(m_idFullSuiteShown, ID_SPACE_ESSENCE, dt);
if (dt == DT_SUITE_ESSENCE && pSuite->file_gfx[0] ){
RemoveGfx(pSuite->file_gfx + 4, "HH_Spine");
}
m_idFullSuiteShown = 0;
}
// Set player's transparence
void CECPlayer::SetTransparent(float fTrans)
{
if (m_pPlayerModel)
m_pPlayerModel->SetTransparent(fTrans);
if (m_pFaceModel)
{
m_pFaceModel->SetTransparent(fTrans);
m_pFaceModel->AutoHairTrans(fTrans >= 0.0f ? false : true);
}
}
// Get player name color
DWORD CECPlayer::GetNameColor()
{
DWORD dwNameCol = NAMECOL_MAUVE;
if (IsInBattle()) // Player is in battle
{
if (m_iBattleCamp == GP_BATTLE_CAMP_INVADER)
dwNameCol = NAMECOL_BC_RED;
else // (m_iBattleCamp == GP_BATTLE_CAMP_DEFENDER)
dwNameCol = NAMECOL_BC_BLUE;
}
else if (IsPariah())
{
switch (m_byPariahLvl)
{
case 0: dwNameCol = NAMECOL_RED0; break;
case 1: dwNameCol = NAMECOL_RED1; break;
default: dwNameCol = NAMECOL_RED2; break;
}
}
else if (IsInvader())
dwNameCol = NAMECOL_PINK;
else if (m_pvp.bEnable)
dwNameCol = NAMECOL_WHITE;
return dwNameCol;
}
// Check whether player in a same battle camp
bool CECPlayer::InSameBattleCamp(CECPlayer* pPlayer)
{
if (!pPlayer || m_iBattleCamp == GP_BATTLE_CAMP_NONE ||
m_iBattleCamp != pPlayer->GetBattleCamp())
return false;
return true;
}
// Check whether specified npc in a same battle camp
bool CECPlayer::InSameBattleCamp(CECNPC* pNPC)
{
if (!pNPC || m_iBattleCamp == GP_BATTLE_CAMP_NONE ||
(m_iBattleCamp == GP_BATTLE_CAMP_INVADER && !pNPC->IsInBattleInvaderCamp()) ||
(m_iBattleCamp == GP_BATTLE_CAMP_DEFENDER && !pNPC->IsInBattleDefenderCamp()))
return false;
return true;
}
// Change player's tank leader state
void CECPlayer::ChangeTankLeader(int idTank, bool bBecomeLeader)
{
if (!IsInBattle())
return;
static const char* szHeadHook = "HH_Head";
// Get effect file name base on player's battle camp
const char* szGFXFile;
if (m_iBattleCamp == GP_BATTLE_CAMP_INVADER)
szGFXFile = res_GFXFile(RES_GFX_TANKLEADER_RED);
else
szGFXFile = res_GFXFile(RES_GFX_TANKLEADER_BLUE);
// When player leave battle, idTank == 0
if (!idTank)
{
// Remove effect if there is one
RemoveGfx(szGFXFile, szHeadHook, PLAYERMODEL_TYPEALL);
m_aBattleTanks.RemoveAll(false);
return;
}
if (bBecomeLeader)
{
// No matter how many tanks are controlled by player, ensure only
// one effect is played
if (!m_aBattleTanks.GetSize())
{
PlayGfx(szGFXFile, szHeadHook, 1.0, PLAYERMODEL_TYPEALL);
}
int iIndex = m_aBattleTanks.Find(idTank);
if (iIndex < 0)
{
m_aBattleTanks.Add(idTank);
if (IsHostPlayer())
g_pGame->GetGameRun()->AddFixedMessage(FIXMSG_OBTAINTANK);
}
}
else
{
if (m_aBattleTanks.GetSize())
{
// Check whether tank has been controlled by us
int iIndex = m_aBattleTanks.Find(idTank);
if (iIndex >= 0)
{
m_aBattleTanks.RemoveAtQuickly(iIndex);
if (IsHostPlayer())
g_pGame->GetGameRun()->AddFixedMessage(FIXMSG_LOSETANK);
}
// Remove effect only when no tank is controlled by player
if (!m_aBattleTanks.GetSize())
{
RemoveGfx(szGFXFile, szHeadHook, PLAYERMODEL_TYPEALL);
}
}
}
}
// Update player's tank leader state
void CECPlayer::UpdateTankLeader()
{
if (!IsInBattle() || !m_aBattleTanks.GetSize())
return;
CECNPCMan* pNPCMan = g_pGame->GetGameRun()->GetWorld()->GetNPCMan();
for (int i=0; i < m_aBattleTanks.GetSize(); i++)
{
int id = m_aBattleTanks[i];
if (!pNPCMan->GetNPC(id))
{
// If tank has left player's eye shot, remove it
m_aBattleTanks.RemoveAtQuickly(i);
i--;
if (IsHostPlayer())
g_pGame->GetGameRun()->AddFixedMessage(FIXMSG_LOSETANK);
}
}
if (!m_aBattleTanks.GetSize())
{
// Remove effect if no tank is controlled by player
ChangeTankLeader(0, false);
}
}
void CECPlayer::SetSpouse(int idSpouse)
{
m_idSpouse = idSpouse;
}
void CECPlayer::SetGoblinRenderCnt(int iCnt)
{
m_GoblinRenderCnt.SetCounter(iCnt);
}
void CECPlayer::SetRenderGoblin(bool bRender)
{
m_bRenderGoblin = bRender;
if(m_pGoblin)
{
m_pGoblin->SetTransparent(0.0f);
}
}
// Does an equipment need to show
bool CECPlayer::IsShownEquip(int nEquipIndex)
{
if((nEquipIndex >= EQUIPIVTR_FASHION_BODY && nEquipIndex <= EQUIPIVTR_FASHION_WRIST) ||
nEquipIndex == EQUIPIVTR_FASHION_HEAD || nEquipIndex == EQUIPIVTR_FASHION_WEAPON)
return m_bFashionMode;
else
return !m_bFashionMode;
}
// Get real element id
DWORD CECPlayer::GetRealElementID(int nEquipIndex, DWORD dwEquipID)
{
// Some equipments use first 16 bits to store color info, so we need to clear color.
// DWORD dwRealID = dwEquipID;
// if (nEquipIndex >= EQUIPIVTR_FASHION_BODY && nEquipIndex <= EQUIPIVTR_FASHION_WRIST)
DWORD dwRealID = dwEquipID & 0x0000ffff;
return dwRealID;
}
bool CECPlayer::GetWeaponMajorType(unsigned int &id_major_type){
bool result(false);
int idWeapon = GetWeaponID();
if (idWeapon && idWeapon != 0xffff){
DATA_TYPE dt;
WEAPON_ESSENCE * pWeapon = (WEAPON_ESSENCE *) g_pGame->GetElementDataMan()->get_data_ptr(idWeapon, ID_SPACE_ESSENCE, dt);
ASSERT(dt == DT_WEAPON_ESSENCE);
if (dt == DT_WEAPON_ESSENCE && pWeapon){
id_major_type = pWeapon->id_major_type;
result = true;
}
}
return result;
}
// 是否正在使用法宝类武器
bool CECPlayer::IsUsingMagicWeapon()
{
if (GetProfession() == PROF_MONK){
unsigned int id_major_type(0);
if (GetWeaponMajorType(id_major_type) &&
id_major_type == 25333){ // 法宝
return true;
}
}
return false;
}
// 是否正在使用胧族武器(胧刀类、月镰类)
bool CECPlayer::IsUsingOboroWeapon(){
return IsUsingLongKnifeWeapon() || IsUsingSickleWeapon();
}
bool CECPlayer::IsUsingLongKnifeWeapon(){
if (GetProfession() == PROF_YEYING || GetProfession() == PROF_YUEXIAN){
unsigned int id_major_type(0);
if (GetWeaponMajorType(id_major_type)){
return id_major_type == 44878; // 胧刀
}
}
return false;
}
bool CECPlayer::IsUsingSickleWeapon(){
if (GetProfession() == PROF_YEYING || GetProfession() == PROF_YUEXIAN){
unsigned int id_major_type(0);
if (GetWeaponMajorType(id_major_type)){
return id_major_type == 44879; // 月镰
}
}
return false;
}
CECModel * CECPlayer::GetBoothModel()
{
return m_pBoothModel;
}
CECModel * CECPlayer::LoadBoothModel(const AString path)
{
CECModel *pBoothModel = NULL;
if (af_IsFileExist(path))
{
// 为减少不必要的错误信息输出,仅当文件存在时尝试加载
g_pGame->GetA3DEngine()->GetA3DSkinMan()->SetReplaceShaderFile(
(const char*)glb_BoothReplaceShader, A3DSkinMan::SHADERREPLACE_USERDEFINE);
pBoothModel = new CECModel;
if (!pBoothModel || !pBoothModel->Load(path))
{
a_LogOutput(1, "CECPlayerMan::LoadBoothModel, Failed to load default booth models %s", (const char *)path);
A3DRELEASE(pBoothModel);
pBoothModel = NULL;
}
else
{
A3DSkinModel *pBoothSkinModel = pBoothModel->GetA3DSkinModel();
if (pBoothSkinModel)
pBoothSkinModel->EnableSpecular(true);
}
g_pGame->GetA3DEngine()->GetA3DSkinMan()->SetReplaceShaderFile("", 0);
}
return pBoothModel;
}
void CECPlayer::SetBoothModel(const char *idBoothModel)
{
ClearBoothModel();
// 使用默认模型
if (!idBoothModel || !idBoothModel[0]){
AString defModelFile = res_ModelFile(GetGender()==GENDER_MALE?RES_MOD_DEFAULT_BOOTH_M:RES_MOD_DEFAULT_BOOTH_F);
m_pBoothModel = LoadBoothModel(defModelFile);
return;
}
// 尝试直接加载(一般用于不区分男女的模型)
if (m_pBoothModel = LoadBoothModel(idBoothModel)){
return;
}
// 按上述路径未查找到相应路径,尝试按照性别修改路径名
AString path = idBoothModel;
if (path.GetLength() <= 4){
return;
}
path.CutRight(4);
path += (GetGender()==GENDER_MALE ? "" : "");
path += ".ecm";
m_pBoothModel = LoadBoothModel(path);
}
void CECPlayer::ClearBoothModel(){
if (!m_bBoothModelLoaded){
return;
}
if (m_pBoothModel){
A3DRELEASE(m_pBoothModel);
}
m_iBoothModelCertificateID = -1;
m_bBoothModelLoaded = false;
}
void CECPlayer::UpdateBoothModel(){
if (m_iBoothState != 2){ // 不是摆摊状态不需要模型
ClearBoothModel();
return;
}
if (!ShouldUseBoothModel()){ // 不需要显示模型时不显示模型
ClearBoothModel();
return;
}
if (GetCertificateID() == m_iBoothModelCertificateID){
return;
}
const char *szBoothModel = "";
if (const SELL_CERTIFICATE_ESSENCE *pEssence = CECElementDataHelper::GetCertificate(GetCertificateID())){
szBoothModel = pEssence->show_model;
}
SetBoothModel(szBoothModel);
m_iBoothModelCertificateID = GetCertificateID();
m_bBoothModelLoaded = true;
}
void CECPlayer::SetBoothBar(const char* szFile)
{
if (!m_pPateBooth){
return;
}
if (!szFile || !szFile[0]){
m_pPateBooth->SetBarImage(NULL);
}else{
m_pPateBooth->SetBarImage(szFile);
}
}
void CECPlayer::ClearBoothBar(){
if (!m_iBoothBarCertificateID){
return;
}
SetBoothBar("");
m_iBoothBarCertificateID = -1;
}
void CECPlayer::UpdateBoothBar(){
if (m_iBoothState != 2){
ClearBoothBar();
return;
}
if (GetCertificateID() == m_iBoothBarCertificateID){
return;
}
const char *szBoothBar = "";
if (const SELL_CERTIFICATE_ESSENCE *pEssence = CECElementDataHelper::GetCertificate(GetCertificateID())){
if (*pEssence->name_image){
szBoothBar = pEssence->name_image + 9; // 跳过 surfaces/
}
}
SetBoothBar(szBoothBar);
m_iBoothBarCertificateID = GetCertificateID();
}
void CECPlayer::ReplaceCurSkin(int nSkinIndex, A3DSkin *pNewSkin)
{
if (GetMajorModel())
{
if (nSkinIndex>=0 && nSkinIndex<NUM_SKIN_INDEX)
{
const A3DSkin *pOldSkin = GetMajorModel()->GetA3DSkin(nSkinIndex);
if (pOldSkin != pNewSkin)
{
GetMajorModel()->ReplaceSkin(nSkinIndex, pNewSkin, false);
m_aCurSkins[nSkinIndex] = pNewSkin;
}
}
}
}
bool CECPlayer::IsFrog()
{
return GetShapeType() == PLAYERMODEL_DUMMYTYPE2 &&
GetShapeID() == RES_MOD_MONEYFROG;
}
bool CECPlayer::SetWeaponHangerPos(WeaponHangerPosition newWeaponHangerPos)
{
// 设置新的武器悬挂位置
//
bool bRet(false);
while (true)
{
if (m_weaponHangerPos == newWeaponHangerPos)
{
bRet = true;
break;
}
if (!GetPlayerModel())
break;
// 获取已有武器模型
CECModel *pLeftHandWeapon = GetLeftHandWeapon();
CECModel *pRightHandWeapon = GetRightHandWeapon();
// 获取模型的显示状态
bool bShowLeft = pLeftHandWeapon && pLeftHandWeapon->IsShown();
bool bShowRight = pRightHandWeapon && pRightHandWeapon->IsShown();
// 删除旧有模型的挂接状态,但保留模型自身
DetachWeapon();
// 挂接原有武器模型到新挂点
m_weaponHangerPos = newWeaponHangerPos;
AttachWeapon();
// 恢复显示状态
if (pLeftHandWeapon)
pLeftHandWeapon->Show(bShowLeft);
if (pRightHandWeapon)
pRightHandWeapon->Show(bShowRight);
bRet = true;
break;
}
return bRet;
}
// 根据当前武器、查询 Player 模型上的挂点
//
const char * CECPlayer::GetLeftWeaponHookPos(WeaponHangerPosition p)
{
const char *pRet = NULL;
switch(p)
{
case WEAPON_HANGER_HAND:
pRet = _hh_left_hand_weapon;
break;
case WEAPON_HANGER_SHOULDER:
pRet = _hh_left_shoulder_weapon;
break;
}
return pRet;
}
const char * CECPlayer::GetRightWeaponHookPos(WeaponHangerPosition p)
{
const char *pRet = NULL;
switch(p)
{
case WEAPON_HANGER_HAND:
if (IsUsingMagicWeapon()){
pRet = _hh_qiu;
}else if (IsUsingSickleWeapon()){
pRet = _hh_right_hand_nickle_weapon;
}else{
pRet = _hh_right_hand_weapon;
}
break;
case WEAPON_HANGER_SHOULDER:
pRet = _hh_right_shoulder_weapon;
break;
}
return pRet;
}
// 根据当前武器、查询武器自身上与玩家挂点位置对接的挂点名称
//
const char * CECPlayer::GetLeftWeaponOwnHookPos(CECModel *pModel)
{
A3DSkinModel *pSkinModel = pModel->GetA3DSkinModel();
return pSkinModel && (pSkinModel->GetSkeletonHook(_cc_weapon, true)!=NULL) ? _cc_weapon : NULL;
}
const char * CECPlayer::GetRightWeaponOwnHookPos(CECModel *pModel)
{
const char *pRet = NULL;
A3DSkinModel *pSkinModel = pModel->GetA3DSkinModel();
if (pSkinModel)
{
if (pSkinModel->GetSkeletonHook(_cc_weapon, true))
pRet = _cc_weapon;
else if (pSkinModel->GetSkeletonHook(_cc_qiu, true))
pRet = _cc_qiu;
}
return pRet;
}
const char * CECPlayer::GetWeaponOwnHookPos(CECModel *pModel, bool bLeft)
{
return bLeft
? GetLeftWeaponOwnHookPos(pModel)
: GetRightWeaponOwnHookPos(pModel);
}
// 获取武器上GFX的挂点
//
const char *CECPlayer::GetLeftWeaponGFXHookPos(CECModel *pModel)
{
return GetLeftWeaponOwnHookPos(pModel);
}
const char * CECPlayer::GetRightWeaponGFXHookPos(CECModel *pModel)
{
const char * rightHookPos = NULL;
if (IsMagicWeapon(pModel))
{
// 右手持法球时,不能使用武器上的 CC_qiu 挂点位置作为特效的悬挂点(因为处在人脚下)
rightHookPos = _hh_qiu_base;
}
else
{
rightHookPos = GetRightWeaponOwnHookPos(pModel);
}
return rightHookPos;
}
const char * CECPlayer::GetWeaponGFXHookPos(CECModel *pModel, bool bLeft)
{
return bLeft
? GetLeftWeaponGFXHookPos(pModel)
: GetRightWeaponGFXHookPos(pModel);
}
CECModel * CECPlayer::GetLeftHandWeapon()
{
return m_pLeftHandWeapon;
}
CECModel * CECPlayer::GetRightHandWeapon()
{
return m_pRightHandWeapon;
}
bool CECPlayer::IsWeaponHookPos(const char *szHH, bool *pbLeft /* = NULL */, CECModel **ppWeaponModel /* = NULL */)
{
// 判断给定的人身上的挂点是否为武器挂点,并返回对应武器模型和左右位置
//
bool bWeaponHook(false);
if (!stricmp(szHH, _hh_left_hand_weapon) ||
!stricmp(szHH, _hh_left_shoulder_weapon))
{
if (ppWeaponModel)
*ppWeaponModel = GetLeftHandWeapon();
if (pbLeft)
*pbLeft = true;
bWeaponHook = true;
}
else if (!stricmp(szHH, _hh_right_hand_weapon)
|| !stricmp(szHH, _hh_right_shoulder_weapon)
|| !stricmp(szHH, _hh_right_hand_nickle_weapon))
{
if (ppWeaponModel)
*ppWeaponModel = GetRightHandWeapon();
if (pbLeft)
*pbLeft = false;
bWeaponHook = true;
}
return bWeaponHook;
}
void CECPlayer::UpdateWeaponHangerPosBySkillAction(int idSkill)
{
if (GetProfession() == PROF_JIANLING)
{
WeaponHangerPosition weaponPos = m_weaponHangerPos;
int type = GNET::ElementSkill::GetType(idSkill);
if (type == TYPE_ATTACK ||
type == TYPE_CURSE ||
type == TYPE_BLESS)
{
// 攻击类技能,改为手持剑状态
weaponPos = WEAPON_HANGER_HAND;
}
else
{
// 其它技能改为背剑状态
weaponPos = WEAPON_HANGER_SHOULDER;
}
// 实施悬挂位置修改
SetWeaponHangerPos(weaponPos);
}
}
void CECPlayer::UpdateWeaponHangerPosByAction(int iAction)
{
if (GetProfession() == PROF_JIANLING)
{
WeaponHangerPosition weaponPos = m_weaponHangerPos;
int changeAction = 0; // 修改选项含义:0 维持原样,1 修改为背在背上,2 修改为握在手上
// 根据要播放的动作、确定武器悬挂位置如何修改
static byte s_WeaponChangeAction[ACT_MAX] =
{
1,// ACT_STAND = 0, // 站立
2,// ACT_FIGHTSTAND, // 战斗站立
0,// ACT_WALK, // 行走
0,// ACT_RUN, // 奔跑
0,// ACT_JUMP_START, // 起跳
// 5
0,// ACT_JUMP_LOOP, // 起跳空中循环
0,// ACT_JUMP_LAND, // 跳跃落地
1,// ACT_SWIM, // 游动
1,// ACT_HANGINWATER, // 水中漂浮
0,// ACT_TAKEOFF, // 翅膀起飞 should be ACT_TAKEOFF_WING
// 10
0,// ACT_HANGINAIR, // 翅膀悬停 should be ACT_HANGINAIR_WING
0,// ACT_FLY, // 翅膀前进 should be ACT_FLY_WING
0,// ACT_FLYDOWN, // 翅膀高空下降 should be ACT_FLYDOWN_WING_HIGH
0,// ACT_FLYDOWN_WING_LOW, // 翅膀低空下降 should be ACT_FLYDOWN_WING_LOW
0,// ACT_LANDON, // 翅膀落地 should be ACT_LAND_WING
// 15
0,// ACT_TAKEOFF_SWORD, // 飞剑起飞
0,// ACT_HANGINAIR_SWORD, // 飞剑悬停
0,// ACT_FLY_SWORD, // 飞剑前进
0,// ACT_FLYDOWN_SWORD_HIGH, // 飞剑高空下降
0,// ACT_FLYDOWN_SWORD_LOW, // 飞剑低空下降
// 20
0,// ACT_LANDON_SWORD, // 飞剑落地
1,// ACT_SITDOWN, // 打坐
1,// ACT_SITDOWN_LOOP, // 打坐循环
1,// ACT_STANDUP, // 打坐站起
0,// ACT_WOUNDED, // 受伤
// 25
0,// ACT_GROUNDDIE, // 陆地死亡
0,// ACT_GROUNDDIE_LOOP, // 死亡地面循环
0,// ACT_WATERDIE, // 水中死亡
0,// ACT_WATERDIE_LOOP, // 死亡水中循环
0,// ACT_AIRDIE_ST, // 空中死亡
// 30
0,// ACT_AIRDIE, // 空中死亡下落循环
0,// ACT_AIRDIE_ED, // 空中死亡落地
0,// ACT_AIRDIE_LAND_LOOP, // 死亡落地循环
0,// ACT_REVIVE, // 复活
1,// ACT_CUSTOMIZE, // 长休闲动作
// 35
0,// ACT_STRIKEBACK, // 被击退
0,// ACT_STRIKEDOWN, // 被击倒
0,// ACT_STRIKEDOWN_LOOP, // 被击倒倒地循环
0,// ACT_STRIKEDOWN_STANDUP, // 被击倒站起
1,// ACT_PICKUP, // 采摘
// 40
1,// ACT_PICKUP_LOOP, // 采摘植物循环
1,// ACT_PICKUP_STANDUP, // 采摘站起
0,// ACT_PICKUP_MATTER, // 捡东西
0,// ACT_GAPE, // 伸懒腰
0,// ACT_LOOKAROUND, // 四处张望
// 45
2,// ACT_PLAYWEAPON, // 转动兵器
0,// ACT_EXP_WAVE, // 招手
0,// ACT_EXP_NOD, // 点头
0,// ACT_EXP_SHAKEHEAD, // 摇头
0,// ACT_EXP_SHRUG, // 耸肩膀
// 50
0,// ACT_EXP_LAUGH, // 大笑
0,// ACT_EXP_ANGRY, // 生气
0,// ACT_EXP_STUN, // 晕倒
0,// ACT_EXP_DEPRESSED, // 沮丧
0,// ACT_EXP_KISSHAND, // 飞吻
// 55
0,// ACT_EXP_SHY, // 害羞
0,// ACT_EXP_SALUTE, // 抱拳
0,// ACT_EXP_SITDOWN, // 坐下
0,// ACT_EXP_SITDOWN_LOOP, // 坐下循环
0,// ACT_EXP_SITDOWN_STANDUP, // 坐下站起
// 60
0,// ACT_EXP_ASSAULT, // 冲锋
0,// ACT_EXP_THINK, // 思考
0,// ACT_EXP_DEFIANCE, // 挑衅
0,// ACT_EXP_VICTORY, // 胜利
0,// ACT_EXP_KISS, // 亲吻
// 65
0,// ACT_EXP_KISS_LOOP, // 亲吻循环
0,// ACT_EXP_KISS_END, // 亲吻结束
2,// ACT_ATTACK_1, // 普攻1
2,// ACT_ATTACK_2, // 普攻2
2,// ACT_ATTACK_3, // 普攻3
// 70
2,// ACT_ATTACK_4, // 普攻4
1,// ACT_ATTACK_TOSS, // 放暗器
0,// ACT_TRICK_RUN, // 跑动中的花招
0,// ACT_TRICK_JUMP, // 跳跃中的花招
0,// ACT_FLY_GLIDE, // 翅膀滑翔
// 75
0,// ACT_FLY_GLIDE_SWORD, // 飞剑滑翔
0,// ACT_EXP_FIGHT, // 战斗
0,// ACT_EXP_ATTACK1, // 攻击1
0,// ACT_EXP_ATTACK2, // 攻击2
0,// ACT_EXP_ATTACK3, // 攻击3
// 80
0,// ACT_EXP_ATTACK4, // 攻击4
0,// ACT_EXP_DEFENCE, // 防御
0,// ACT_EXP_FALL, // 摔倒
0,// ACT_EXP_FALLONGROUND, // 倒地
0,// ACT_EXP_LOOKAROUND, // 张望
// 85
0,// ACT_EXP_DANCE, // 舞蹈
2,// ACT_EXP_FASHIONWEAPON // 时装武器
1,// ACT_USEITEM, // 通用的使用物品动作
1,// ACT_USEITMELOOP, // 通用的使用物品循环动作
0,// ACT_TWO_KISS, // 双人亲吻
1,// ACT_USING_TARGET_ITEM, // 使用道具
};
if (iAction >= 0 && iAction < ACT_MAX)
changeAction = s_WeaponChangeAction[iAction];
switch(changeAction)
{
case 1:
weaponPos = WEAPON_HANGER_SHOULDER;
break;
case 2:
weaponPos = WEAPON_HANGER_HAND;
break;
}
// 实施悬挂位置修改
SetWeaponHangerPos(weaponPos);
}
}
void CECPlayer::UpdatePetCureGFX(DWORD dwDeltaTime)
{
if (!m_pPetCureGFX)
{
// 光效必须在“中状态”时加载
return;
}
A3DGFXExMan *pGFXExMan = g_pGame->GetA3DGFXExMan();
// 判断是否需要此光效
bool bNeedGFX(false);
CECPet *pPet = NULL;
while (true)
{
// 判断宠物是否存在
int idPet = GetCurPetID();
if (!idPet)
break;
CECNPCMan *pNPCMan = g_pGame->GetGameRun()->GetWorld()->GetNPCMan();
if (!pNPCMan)
break;
pPet = pNPCMan->GetPetByID(idPet);
if (!pPet)
break;
// 宠物存在
// 仍然需要光效
bNeedGFX = true;
break;
}
if (!bNeedGFX)
{
// 不需要光效了,释放已加载
pGFXExMan->CacheReleasedGfx(m_pPetCureGFX);
m_pPetCureGFX = NULL;
m_pPetCureGFXtate = -1;
return;
}
// 需要光效、且光效存在
// 判断是否适合显示光效
A3DVECTOR3 pos[2];
const A3DAABB &playerAABB = GetPlayerAABB();
pos[0] = playerAABB.Center;
const A3DAABB &petAABB = pPet->GetPickAABB();
pos[1] = petAABB.Center;
A3DVECTOR3 delta = pos[0]-pos[1];
float dist2 = delta.SquaredMagnitude();
if (dist2 > 625.0f)
{
// 两者距离过远(超过 25 米),隐藏光效
if (m_pPetCureGFX->IsVisible())
m_pPetCureGFX->SetVisible(false);
return;
}
// 需要显示光效果
if (m_pPetCureGFX->GetState() != ST_PLAY)
m_pPetCureGFX->Start(true);
if (!m_pPetCureGFX->IsVisible())
m_pPetCureGFX->SetVisible(true);
// 更新电弧光效的位置等
int nElement = m_pPetCureGFX->GetElementCount();
for (int i = 0; i < nElement; ++ i)
{
A3DGFXElement *pElement = m_pPetCureGFX->GetElement(i);
if (pElement)
GFX_UpdateLightingEdgePos(m_pPetCureGFX, pElement->GetName(), pos);
}
m_pPetCureGFX->TickAnimation(dwDeltaTime);
}
bool CECPlayer::IsPetCureGFX(const AString &strGFXFile)
{
// 判断指定光效是否为宠物治疗光效
//
bool bRet(false);
while (true)
{
AString strTitle;
if (!af_GetFileTitle(strGFXFile, strTitle) ||
strTitle.IsEmpty())
break;
const char *szTitle = (const char *)strTitle;
if (strstr(szTitle, "电弧") != szTitle)
break;
// 只要是电弧光效都返回 true
bRet = true;
break;
}
return bRet;
}
bool CECPlayer::TestProcessPetCureGFX(const AString &strGFXFile, bool bLoad, int iState)
{
bool bRet(false);
while (true)
{
if (!IsPetCureGFX(strGFXFile))
break;
// 只要是电弧光效都返回 true
bRet = true;
A3DGFXExMan *pGFXExMan = g_pGame->GetA3DGFXExMan();
if (!bLoad)
{
// 要消除旧有状态,判断是否加载过
if (m_pPetCureGFXtate == iState)
{
// 状态正确,判断是否已加载
if (m_pPetCureGFX)
{
// 曾经加载,现释放
pGFXExMan->CacheReleasedGfx(m_pPetCureGFX);
m_pPetCureGFX = NULL;
m_pPetCureGFXtate = -1;
}
}
// 处理完成
break;
}
// 加载新特效
// 先释放已经加载
if (m_pPetCureGFX)
{
// 释放已加载
pGFXExMan->CacheReleasedGfx(m_pPetCureGFX);
m_pPetCureGFX = NULL;
m_pPetCureGFXtate = -1;
}
// 加载新的特效
m_pPetCureGFX = pGFXExMan->LoadGfx(g_pGame->GetA3DDevice(), strGFXFile);
if (!m_pPetCureGFX)
break;
// 设置默认参数
m_pPetCureGFX->SetScale(1.0f);
// 初始为不可见
m_pPetCureGFX->SetVisible(false);
// 记录对应状态下标
m_pPetCureGFXtate = iState;
// 更新位置
UpdatePetCureGFX(0);
break;
}
return bRet;
}
void CECPlayer::UpdatePosRelatedGFX(DWORD dwDeltaTime)
{
// 位置相关 GFX 的更新,需要在玩家位置计算完成后执行,以减少延迟
//
UpdatePetCureGFX(dwDeltaTime);
UpdateMultiObjectEffect(dwDeltaTime);
}
void CECPlayer::RenderPetCureGFX()
{
if (m_pPetCureGFX && m_pPetCureGFX->IsVisible())
{
A3DGFXExMan *pGFXExMan = g_pGame->GetA3DGFXExMan();
pGFXExMan->RegisterGfx(m_pPetCureGFX);
}
}
bool CECPlayer::IsMagicWeapon(CECModel *pModel)
{
// 根据武器的挂点、判断是否为法宝类武器
//
bool bRet(false);
if (pModel)
{
A3DSkinModel *pSkinModel = pModel->GetA3DSkinModel();
if (pSkinModel)
{
// 同 GetRightWeaponOwnHookPos 保持一致
// 武器模板上无 _cc_weapon 挂点、但有 _cc_qiu 挂点时
// 认定为法宝武器
//
if (pSkinModel->GetSkeletonHook(_cc_weapon, true))
bRet = false;
else if (pSkinModel->GetSkeletonHook(_cc_qiu, true))
bRet = true;
}
}
return bRet;
}
AString CECPlayer::GetFashionActionName()
{
// 查找时装装备上携带的动作名称
//
AString strAction;
static int local_check_order[] =
{
EQUIPIVTR_FASHION_HEAD,
EQUIPIVTR_FASHION_BODY,
EQUIPIVTR_FASHION_WRIST,
EQUIPIVTR_FASHION_LEG,
EQUIPIVTR_FASHION_FOOT,
};
int idEquipment(0);
for (int i = 0; i < sizeof(local_check_order)/sizeof(local_check_order[0]); ++ i)
{
// 按顺序查找指定服装
idEquipment = m_aEquips[local_check_order[i]] & 0x0000ffff;
GetFashionActionNameByID(idEquipment, strAction);
if (!strAction.IsEmpty())
{
// 发现非空时装动作,即返回
break;
}
}
return strAction;
}
void CECPlayer::SetShape(int iShape)
{
// The shape id from the server is a 8-bit number
// The meaning of each bit:
// | 7 6 | 5 4 3 2 1 0 |
// |-TYPE-|-----Model ID-----|
int iNewShape = (iShape & 0xff); // only accept 8bit
// 对旧的Shape数据数据进行修正
FixOldShapeInfo(iNewShape);
// 职业变身,Model ID要经转化
if( PLAYERMODEL_GETTYPE(iNewShape) == PLAYERMODEL_PROFESSION )
{
int iRealID = _GetProfessionTransformModelID(
m_iProfession, m_iGender, PLAYERMODEL_GETID(iNewShape));
iNewShape = 0x40 | iRealID;
}
// 非职业变身,Model ID为EC_Resource.h里的值,故不做处理
else
{
}
// store the original data into 8~15 bit
m_iShape = iNewShape | ((iShape & 0xff) << 8);
}
void CECPlayer::FixOldShapeInfo(int& iShape)
{
// 那个时候shape为0代表没有变身,非0代表职业变身
if(iShape != 0 && PLAYERMODEL_GETTYPE(iShape) == 0)
iShape |= 0x40;
}
unsigned char CECPlayer::GetShapeMask() const
{
// restore the original data from 8~15 bit
return static_cast<unsigned char>((m_iShape & 0xff00) >> 8);
}
// Get player's current model type
int CECPlayer::GetShapeType() const
{
return PLAYERMODEL_GETTYPE(m_iShape);
}
// Get player's current model id
int CECPlayer::GetShapeID() const
{
return PLAYERMODEL_GETID(m_iShape);
}
// Play Gfx on Models
bool CECPlayer::PlayGfx(const char* szPath, const char* szHook, float fScale /*1.0f*/, unsigned int iShapeTypeMask /*(1<<PLAYERMODEL_MAJOR)*/, bool bForceNoRecord /*false*/)
{
bool bPlayed(false);
bool bSkipRecord = (iShapeTypeMask != PLAYERMODEL_TYPEALL) || bForceNoRecord;
for(int i=0;i<PLAYERMODEL_MAX;i++)
{
if (m_pModels[i] && (iShapeTypeMask & (1<<i)))
{
if (IsCurrentModel(m_pModels[i])){
m_pModels[i]->PlayGfx(szPath, szHook, fScale);
bPlayed = true;
}
if(bSkipRecord) continue;
A3DGFXEx* pGfx = m_pModels[i]->GetGfx(szPath, szHook);
if (pGfx && pGfx->IsInfinite()){
GFXRECORD rec;
rec.strPath = szPath;
rec.strHook = szHook;
rec.fScale = fScale;
AString key = rec.strPath + rec.strHook;
m_GfxRecords[key] = rec;
bSkipRecord = true;
}
}
}
return bPlayed;
}
void CECPlayer::RemoveGfx(const char* szPath, const char* szHook, unsigned int iShapeTypeMask /*(1<<PLAYERMODEL_MAJOR)*/)
{
bool bSkipRecord = false;
for(int i=0;i<PLAYERMODEL_MAX;i++)
{
if( m_pModels[i] && (iShapeTypeMask & (1<<i)) )
{
m_pModels[i]->RemoveGfx(szPath, szHook);
// remove the gfx info when it is unnecessary
if(!bSkipRecord)
{
bSkipRecord = true;
AString key = AString(szPath) + szHook;
m_GfxRecords.erase(key);
}
}
}
}
bool CECPlayer::IsShapeModelChanged() const
{
return m_pModels[PLAYERMODEL_MAJOR] != m_pPlayerModel;
}
bool CECPlayer::IsShapeModelReady() const
{
if(GetShapeID() == 0)
{
// logic transform only, no model changed
return m_pPlayerModel == m_pModels[PLAYERMODEL_MAJOR];
}
else
{
// whether the target model is set to current using model
return m_pPlayerModel == m_pModels[min(PLAYERMODEL_MAX-1, GetShapeType())];
}
}
bool CECPlayer::ShouldUseGroundNormalForCurrentShapeModel()const{
return IsShapeModelChanged() && !IsTransofrmModelLikeHuman(GetProfession(), GetGender(), GetShapeID());
}
bool CECPlayer::GetExtState(int n)
{
const int bitSize = sizeof(DWORD) * 8;
const int totalBitSize = bitSize * OBJECT_EXT_STATE_COUNT;
if(n < 0 || n >= totalBitSize)
return false;
int index = n / bitSize;
int bitOffset = n % bitSize;
return (m_aExtStates[index] & (1 << bitOffset)) ? true : false;
}
bool CECPlayer::StartAdjustTransparency(float fCur, float fDest, DWORD dwTime)
{
// use current value for starting
if(fCur < 0.f) fCur = m_fCurTrans;
if(fDest < 0.f) fDest = 0.f;
// ignore the invalid params
if(dwTime == 0 || fabs(fDest - m_fDstTrans) < 0.0001f || fabs(fDest - fCur) < 0.0001f)
{
return false;
}
// start the counter to change the transparency
m_fCurTrans = fCur;
m_fDstTrans = fDest;
m_fTransDelta = (fDest - m_fCurTrans) / dwTime;
m_TransCnt.SetPeriod(dwTime);
m_TransCnt.Reset();
return true;
}
float CECPlayer::UpdateTransparency(DWORD dwDeltaTime)
{
// Use this valid to change model's transparency
if (!m_TransCnt.IsFull() && m_fDstTrans != m_fCurTrans)
{
m_fCurTrans += m_fTransDelta * dwDeltaTime;
if (m_fTransDelta > 0.0f)
a_ClampRoof(m_fCurTrans, m_fDstTrans);
else
a_ClampFloor(m_fCurTrans, m_fDstTrans);
}
return (m_fCurTrans <= 0.f) ? -1.0f : m_fCurTrans;
}
float CECPlayer::GetTransparentLimit()
{
if(GetExtState(109))//无敌状态的光效ID
{
return 0.7f;//无敌
}
else if (m_dwStates & GP_STATE_INVISIBLE)
{
return 0.7f;//隐身
}
else if (!IsSelectable())
{
return 0.5f;//无法选中
}
else if(GetExtState(110))//雷神变状态光效ID
{
return 0.3f;//雷神变
}
return -1.f;
}
void CECPlayer::AddMultiObjectEffect(int idTarget,char cType)
{
if (cType < 0 || cType > 2)
return;
static const char* szBasePath = "策划联入\\状态效果\\";
MULTIOBJECT_EFFECT mo;
mo.cType = cType;
mo.iTarget = idTarget;
MOEffectMAP::iterator it = m_mapMOEffect.find(mo);
if (it == m_mapMOEffect.end())
{
AString strGfxFile(_multiobject_effect[cType]);
strGfxFile = szBasePath + strGfxFile;
A3DGFXExMan *pGFXExMan = g_pGame->GetA3DGFXExMan();
A3DGFXEx* pGfx = pGFXExMan->LoadGfx(g_pGame->GetA3DDevice(), strGfxFile);
if (!pGfx)
return;
pGfx->SetScale(1.0f);
pGfx->SetVisible(false);
if (IsAllResReady() && m_pPlayerModel)
UpdateOneMultiObjectEffect(idTarget,pGfx,0);
m_mapMOEffect[mo] = pGfx;
}
}
void CECPlayer::RemoveMultiObjectEffect(int idTarget,char cType)
{
MULTIOBJECT_EFFECT mo;
mo.cType = cType;
mo.iTarget = idTarget;
MOEffectMAP::iterator it = m_mapMOEffect.find(mo);
if (it != m_mapMOEffect.end())
{
A3DGFXExMan *pGFXExMan = g_pGame->GetA3DGFXExMan();
pGFXExMan->CacheReleasedGfx(it->second);
m_mapMOEffect.erase(mo);
}
}
void CECPlayer::UpdateOneMultiObjectEffect(int idTarget,A3DGFXEx* pGfx,DWORD dwDeltaTime)
{
if (idTarget == 0 || pGfx == NULL)
return;
CECObject* pObject = NULL;
if (ISNPCID(idTarget))
{
if (!(pObject = g_pGame->GetGameRun()->GetWorld()->GetNPCMan()->GetNPC(idTarget)))
return;
}
else if (ISPLAYERID(idTarget))
{
if (!(pObject = g_pGame->GetGameRun()->GetWorld()->GetPlayerMan()->GetPlayer(idTarget)))
return;
}
else
{
if (!(pObject = g_pGame->GetGameRun()->GetWorld()->GetMatterMan()->GetMatter(idTarget))) {
StopMonsterSpiritConnectGfx();
return;
}
}
A3DVECTOR3 pos[2];
const A3DAABB &playerAABB = GetPlayerAABB();
pos[0] = playerAABB.Center;
if (pObject->IsNPC()) {
const A3DAABB &targetAABB = ((CECNPC*)pObject)->GetPickAABB();
pos[1] = targetAABB.Center;
} else if (pObject->IsPlayer()) {
const A3DAABB &targetAABB = ((CECPlayer*)pObject)->GetPlayerAABB();
pos[1] = targetAABB.Center;
} else {
pos[1] = pos[0];
pos[1].y += .5f;
pos[0] = pObject->GetPos();
}
A3DVECTOR3 delta = pos[0]-pos[1];
float dist2 = delta.SquaredMagnitude();
if (dist2 > 2025.0f)
{
if (pGfx->IsVisible())
pGfx->SetVisible(false);
return;
}
if (pGfx->GetState() != ST_PLAY)
pGfx->Start(true);
if (!pGfx->IsVisible())
pGfx->SetVisible(true);
int nElement = pGfx->GetElementCount();
for (int i = 0; i < nElement; ++ i)
{
A3DGFXElement *pElement = pGfx->GetElement(i);
if (pElement)
GFX_UpdateLightingEdgePos(pGfx, pElement->GetName(), pos);
}
pGfx->TickAnimation(dwDeltaTime);
}
void CECPlayer::UpdateMultiObjectEffect(DWORD dwDeltaTime)
{
for (MOEffectMAP::iterator it = m_mapMOEffect.begin();it != m_mapMOEffect.end();++it)
{
UpdateOneMultiObjectEffect(it->first.iTarget,it->second,dwDeltaTime);
}
}
void CECPlayer::RenderMultiObjectGFX()
{
A3DGFXExMan *pGFXExMan = g_pGame->GetA3DGFXExMan();
for (MOEffectMAP::iterator it = m_mapMOEffect.begin();it != m_mapMOEffect.end();++it)
{
if (it->second && it->second->IsVisible())
{
pGFXExMan->RegisterGfx(it->second);
}
}
}
void CECPlayer::ClearBubbleText()
{
if (m_pBubbleTexts)
m_pBubbleTexts->ClearDecalList();
}
A3DAABB CECPlayer::GetShadowAABB()
{
A3DAABB shadowAABB;
shadowAABB.Clear();
shadowAABB.Merge(m_aabb);
if (IsRidingOnPet() && m_pPetModel && m_pPetModel->GetA3DSkinModel())
shadowAABB.Merge(m_pPetModel->GetModelAABB());
else if (GetPlayerModel() && GetPlayerModel()->GetA3DSkinModel())
shadowAABB.Merge(GetPlayerModel()->GetModelAABB());
return shadowAABB;
}
void CECPlayer::SetCountry(int id)
{
if (m_idCountry == id) return;
m_idCountry = id;
if (!m_idCountry)
{
delete m_pPateCountry;
m_pPateCountry = NULL;
delete m_pCountryDecal;
m_pCountryDecal = NULL;
return;
}
const ACString *pName = CECCountryConfig::Instance().GetName(id);
if (!pName || pName->IsEmpty())
{
delete m_pPateCountry;
m_pPateCountry = NULL;
}
else
{
if (!m_pPateCountry)
{
m_pPateCountry = new CECPateText;
m_pPateCountry->EnableBorder(true);
}
m_pPateCountry->SetText(*pName, false, false);
}
A2DSprite *pSprite = CECCountryConfig::Instance().GetIcon(id);
if (!pSprite)
{
delete m_pCountryDecal;
m_pCountryDecal = NULL;
}
else
{
if (!m_pCountryDecal)
m_pCountryDecal = new CECSpriteDecal;
m_pCountryDecal->ChangeSpriteIcon(pSprite, 0);
}
}
bool CECPlayer::GetShowName()const
{
// 正常显示人物名称时返回 true
bool bShow(true);
while (true)
{
if (CECUIConfig::Instance().GetGameUI().bShowNameInCountryWar)
break;
CECGameRun *pGameRun = g_pGame->GetGameRun();
if (!pGameRun->GetWorld()->IsCountryWarMap())
break;
if (IsHostPlayer())
break;
CECHostPlayer *pHost = pGameRun->GetHostPlayer();
if (pHost->GetCountry() == GetCountry())
break;
bShow = false;
break;
}
return bShow;
}
bool CECPlayer::GetShowNameInCountryWar()
{
// 需要以国战特有的方式显示名称时返回 true
return !GetShowName() && GetCountry();
}
ACString CECPlayer::GetNameInCountryWar()
{
// 以国家和职业代替角色名
ACString strName;
CECGameRun *pGameRun = g_pGame->GetGameRun();
strName.Format(
pGameRun->GetUIManager()->GetBaseUIMan()->GetStringFromTable(9924),
*CECCountryConfig::Instance().GetName(GetCountry()),
pGameRun->GetProfName(GetProfession()));
return strName;
}
const FASHION_WEAPON_CONFIG* CECPlayer::GetFashionConfig()
{
static FASHION_WEAPON_CONFIG* pFashionConfig = NULL;
if (NULL == pFashionConfig)
{
elementdataman *pDataMan = g_pGame->GetElementDataMan();
DATA_TYPE DataType;
unsigned int tid = pDataMan->get_first_data_id(ID_SPACE_CONFIG,DataType);
while(tid)
{
if(DataType == DT_FASHION_WEAPON_CONFIG)
{
pFashionConfig = (FASHION_WEAPON_CONFIG *)pDataMan->get_data_ptr(tid,ID_SPACE_CONFIG, DataType);
break;
}
tid = pDataMan->get_next_data_id(ID_SPACE_CONFIG, DataType);
}
}
return pFashionConfig;
}
bool CECPlayer::IsFashionWeaponTypeFit(int weapon_type, int fashion_weapon_type)
{
if (fashion_weapon_type < 0 || fashion_weapon_type >= NUM_WEAPON_TYPE) return false;
const FASHION_WEAPON_CONFIG* pConfig = GetFashionConfig();
if (NULL == pConfig)
{
ASSERT(!"Fashion weapon config load failed!");
a_LogOutput(1, "CECPlayer::GetFashionConfig, Failed to load fashion weapon config");
return false;
}
int fashion_weapon_mask = pConfig->action_mask[fashion_weapon_type];
return (fashion_weapon_mask & (1 << GetWeaponType(weapon_type))) != 0;
}
bool CECPlayer::CanShowFashionWeapon(int weapon_type, int fashion_weapon_type)
{
return IsFashionWeaponTypeFit(weapon_type, fashion_weapon_type) && InFashionMode();
}
#define CLEAR_WEAPON(index) \
{ \
Mask &= ~(1 << (__int64)index); \
pEquipmentID[index] = -1; \
}
#define SET_WEAPON(index, id) \
{ \
Mask |= (1 << (__int64)index); \
pEquipmentID[index] = id; \
}
#define RECORD_NORMAL_WEAPON(file_model_left, file_model_right, action_type) \
{ \
m_strLeftWeapon = file_model_left; \
m_strRightWeapon = file_model_right; \
m_uAttackType = action_type; \
}
#define RECORD_FASHION_WEAPON(file_model_left, file_model_right, index) \
{ \
m_strLeftFashionWeapon = file_model_left; \
m_strRightFashionWeapon = file_model_right; \
m_iFashionWeaponType = index; \
}
void CECPlayer::DecideWeaponLoad(int* pEquipmentID, __int64& Mask)
{
bool bNormalWeaponChanged = ((1 << EQUIPIVTR_WEAPON) & Mask) != 0;
bool bFashionWeaponChanged = ((1 << EQUIPIVTR_FASHION_WEAPON) & Mask) != 0;
const WEAPON_ESSENCE* pWeapon = NULL;
const FASHION_ESSENCE* pFashion = NULL;
const WEAPON_SUB_TYPE* pSubType = NULL;
int Index[2] = {EQUIPIVTR_WEAPON, EQUIPIVTR_FASHION_WEAPON};
for (int i = 0; i < 2; ++i)
{
int idEquipment = pEquipmentID[Index[i]];
idEquipment &= 0x0000ffff;
DATA_TYPE dt;
if (idEquipment)
{
const void* pEquip = g_pGame->GetElementDataMan()->get_data_ptr(
idEquipment,
ID_SPACE_ESSENCE,
dt);
if (dt == DT_WEAPON_ESSENCE)
{
pWeapon = (const WEAPON_ESSENCE*)pEquip;
pSubType =(const WEAPON_SUB_TYPE*) g_pGame->GetElementDataMan()->get_data_ptr(
pWeapon->id_sub_type,
ID_SPACE_ESSENCE,
dt);
if (dt != DT_WEAPON_SUB_TYPE) pSubType = NULL;
}
else if (dt == DT_FASHION_ESSENCE) pFashion = (const FASHION_ESSENCE*)pEquip;
}
}
bool bCanShowFashionWeaponBefore = CanShowFashionWeapon(m_uAttackType, m_iFashionWeaponType);
bool bCanShowFashionWeapon(false);
CECGameUIMan* pGameUI = g_pGame->GetGameRun()->GetUIManager()->GetInGameUIMan();
// 普通武器改变
if (bNormalWeaponChanged)
{
// 时装武器改变
if (bFashionWeaponChanged)
{
// 装备时装武器和普通武器
if (pSubType && pFashion)
{
if (CanShowFashionWeapon(pSubType->action_type, pFashion->action_type))
{
CLEAR_WEAPON(EQUIPIVTR_WEAPON);
}
else
{
CLEAR_WEAPON(EQUIPIVTR_FASHION_WEAPON);
}
}
// 装备普通武器
else if(pSubType && !pFashion)
{
}
// 装备时装武器
else if (!pSubType && pFashion)
{
if (CanShowFashionWeapon(m_uAttackType, pFashion->action_type))
{
CLEAR_WEAPON(EQUIPIVTR_WEAPON);
}
else
{
CLEAR_WEAPON(EQUIPIVTR_FASHION_WEAPON);
}
}
// 没有装备任务武器
else
{
}
if (pSubType) RECORD_NORMAL_WEAPON(
pWeapon->file_model_left, pWeapon->file_model_right, pSubType->action_type);
if (pFashion) RECORD_FASHION_WEAPON(
pFashion->file_model_left, pFashion->file_model_right, pFashion->action_type);
}
else
{
// 装备普通武器
if (pSubType)
{
bCanShowFashionWeapon = CanShowFashionWeapon(pSubType->action_type, m_iFashionWeaponType);
if (bCanShowFashionWeapon)
{
CLEAR_WEAPON(EQUIPIVTR_WEAPON);
if (!bCanShowFashionWeaponBefore)
SET_WEAPON(EQUIPIVTR_FASHION_WEAPON, m_aEquips[EQUIPIVTR_FASHION_WEAPON]);
}
RECORD_NORMAL_WEAPON(
pWeapon->file_model_left, pWeapon->file_model_right, pSubType->action_type);
}
// 脱下普通武器
else
{
bCanShowFashionWeapon = CanShowFashionWeapon(DEFAULT_ACTION_TYPE, m_iFashionWeaponType);
if (bCanShowFashionWeapon)
{
CLEAR_WEAPON(EQUIPIVTR_WEAPON);
if (!bCanShowFashionWeaponBefore)
SET_WEAPON(EQUIPIVTR_FASHION_WEAPON, m_aEquips[EQUIPIVTR_FASHION_WEAPON]);
}
RECORD_NORMAL_WEAPON((char*)NULL, (char*)NULL, DEFAULT_ACTION_TYPE);
}
}
}
else if (bFashionWeaponChanged)
{
// 装备时装武器
if (pFashion)
{
bCanShowFashionWeapon = CanShowFashionWeapon(m_uAttackType, pFashion->action_type);
if (!bCanShowFashionWeapon)
{
if (pGameUI && this == g_pGame->GetGameRun()->GetHostPlayer() && InFashionMode())
pGameUI->AddChatMessage(pGameUI->GetStringFromTable(906), GP_CHAT_SYSTEM);
CLEAR_WEAPON(EQUIPIVTR_FASHION_WEAPON);
if (bCanShowFashionWeaponBefore)
SET_WEAPON(EQUIPIVTR_WEAPON, m_aEquips[EQUIPIVTR_WEAPON]);
}
// 能显示时装武器,此处要把m_stoneWeapon清零
else CLEAR_WEAPON(EQUIPIVTR_WEAPON);
RECORD_FASHION_WEAPON(
pFashion->file_model_left, pFashion->file_model_right, pFashion->action_type);
}
// 脱下时装武器
else
{
if (0 != m_aEquips[EQUIPIVTR_WEAPON])
{
CLEAR_WEAPON(EQUIPIVTR_FASHION_WEAPON);
if (bCanShowFashionWeaponBefore)
SET_WEAPON(EQUIPIVTR_WEAPON, m_aEquips[EQUIPIVTR_WEAPON]);
}
RECORD_FASHION_WEAPON((char*)NULL, (char*)NULL, DEFAULT_ACTION_TYPE);
}
}
if (bCanShowFashionWeaponBefore && !bCanShowFashionWeapon
&& pGameUI && !bFashionWeaponChanged && bNormalWeaponChanged && this == g_pGame->GetGameRun()->GetHostPlayer())
pGameUI->AddChatMessage(pGameUI->GetStringFromTable(906), GP_CHAT_SYSTEM);
}
void CECPlayer::SetWeaponResult(EquipsLoadResult& Result)
{
ReleaseWeapon();
m_weaponHangerPos = WEAPON_HANGER_HAND;
if (GetProfession() == PROF_JIANLING && !IsFighting()){
// 剑灵非战斗状态下,武器挂在肩膀上
m_weaponHangerPos = WEAPON_HANGER_SHOULDER;
}
m_pLeftHandWeapon = Result.pLeftHandWeapon;
m_pRightHandWeapon = Result.pRightHandWeapon;
AttachWeapon();
if (Result.bFashionWeaponChanged){
if (m_pLeftHandWeapon){
m_pLeftHandWeapon->GetA3DSkinModel()->SetAlphaSortID(m_PlayerInfo.cid);
m_pLeftHandWeapon->GetA3DSkinModel()->SetAlphaSortWeight(SKIN_SORT_WEAPON);
}
if (m_pRightHandWeapon){
m_pRightHandWeapon->GetA3DSkinModel()->SetAlphaSortID(m_PlayerInfo.cid);
m_pRightHandWeapon->GetA3DSkinModel()->SetAlphaSortWeight(SKIN_SORT_WEAPON);
}
}
if (m_pLeftHandWeapon || m_pRightHandWeapon){
// 有武器存在,将当前还存在的状态特效,补充挂到新的武器上
// 避免因武器更换等原因导致不能正确指示状态
SetExtendStatesToWeapon();
}
// now show weapon according to old weapon states.
ShowWeapon(m_bShowWeapon);
}
void CECPlayer::OnSwitchFashionWeapon()
{
if (!GetMajorModel() || !IsFashionWeaponTypeFit(m_uAttackType, m_iFashionWeaponType))
return;
EquipsLoadResult Result;
memset(&Result, 0, sizeof(Result));
if (InFashionMode())
{
ChangeWeapon(&Result, m_strLeftFashionWeapon, m_strRightFashionWeapon);
}
else
{
ChangeWeapon(&Result, m_strLeftWeapon, m_strRightWeapon);
}
SetWeaponResult(Result);
m_stoneWeaponShown = 0;
if (InFashionMode()){
m_stoneWeapon = 0;
}else{
m_stoneWeapon = m_aEquips[EQUIPIVTR_WEAPON] >> 16;
AddWeaponStones();
}
}
int CECPlayer::GetShowingWeaponType()
{
int weapon_type = 0;
if (CanShowFashionWeapon(m_uAttackType, m_iFashionWeaponType) && m_aEquips[EQUIPIVTR_FASHION_WEAPON] != 0)
{
weapon_type = (m_iFashionWeaponType == DEFAULT_ACTION_TYPE || !IsWeaponAttached()) ?
10 : m_iFashionWeaponType;
}
else
{
weapon_type = (m_uAttackType == DEFAULT_ACTION_TYPE || !IsWeaponAttached()) ?
10 : m_uAttackType;
}
return weapon_type;
}
// 更新经脉属性
void CECPlayer::SetMeridiansProp(const MeridiansProp& meridianProp)
{
m_meridiansProp = meridianProp;
}
bool CECPlayer::IsShowFashionWeapon()
{
// 当前状态是否应该显示时装武器模型,返回 true 不保证模型已经加载完成并显示
//
return m_aEquips[EQUIPIVTR_FASHION_WEAPON] != 0
&& CanShowFashionWeapon(m_uAttackType, m_iFashionWeaponType);
}
void CECPlayer::OptimizeShowExtendStates()
{
if (CECOptimize::Instance().GetGFX().CanShowState(GetCharacterID(), GetClassID())){
ShowExtendStates(0, m_aExtStates, OBJECT_EXT_STATE_COUNT);
}else{
ClearShowExtendStates();
}
}
void CECPlayer::OptimizeWeaponStoneGfx()
{
if (CECOptimize::Instance().GetGFX().CanShowWeaponStone(GetCharacterID(), GetClassID())){
AddWeaponStones();
}else{
RemoveWeaponStones();
}
}
void CECPlayer::OptimizeArmorStoneGfx()
{
if (CECOptimize::Instance().GetGFX().CanShowArmorStone(GetCharacterID(), GetClassID())){
AddUpperBodyStones();
AddWristStones();
AddLowerBodyStones();
AddFootStones();
}else{
RemoveUpperBodyStones();
RemoveWristStones();
RemoveLowerBodyStones();
RemoveFootStones();
}
}
void CECPlayer::OptimizeSuiteGfx()
{
if (CECOptimize::Instance().GetGFX().CanShowSuite(GetCharacterID(), GetClassID())){
AddFullSuiteGFX();
}else{
RemoveFullSuiteGFX();
}
}
const TITLE_CONFIG* CECPlayer::GetTitleConfig(unsigned short id)
{
DATA_TYPE DataType = DT_INVALID;
const void* pDataPtr = g_pGame->GetElementDataMan()->get_data_ptr(id, ID_SPACE_CONFIG, DataType);
if (DataType != DT_TITLE_CONFIG && DataType != DT_COMPLEX_TITLE_CONFIG)
return NULL;
const TITLE_CONFIG* pData = (const TITLE_CONFIG*)pDataPtr;
return pData;
}
A3DBone* CECPlayer::ScaleRootBone(CECModel* pModel, float scale)
{
int num_bone, j, root_index;
A3DBone* pBone = NULL;
A3DSkeleton* pSkeleton = NULL;
if (pModel) {
pSkeleton = pModel->GetA3DSkinModel()->GetSkeleton();
if (pSkeleton) {
num_bone = pSkeleton->GetRootBoneNum();
for (j = 0; j < num_bone; ++j) {
root_index = pSkeleton->GetRootBone(j);
pBone = pSkeleton->GetBone(root_index);
if (pBone) {
pBone->SetScaleFactor(A3DVECTOR3(scale, scale, scale));
pBone->SetScaleType(A3DBone::SCALE_WHOLE);
break;
}
}
}
}
return pBone;
}
void CECPlayer::ScaleChildModel()
{
CECModel* pModel;
int num_child = m_pPlayerModel->GetChildCount();
int i;
AString strCCFeijian("CC_feijian");
for (i = 0; i < num_child; ++i) {
pModel = m_pPlayerModel->GetChildModel(i);
// 飞剑的CC_feijian挂点没有挂在骨骼上,跳过飞剑
if (pModel->GetCCName() == strCCFeijian)
continue;
ScaleRootBone(pModel, m_fScaleBySkill);
pModel->SetGfxScale(m_fScaleBySkill);
}
}
void CECPlayer::ScaleBody(float fScale)
{
m_fScaleBySkill = fScale;
if (!m_pPlayerModel) return;
A3DSkeleton * pSkeleton = m_pPlayerModel->GetA3DSkinModel()->GetSkeleton();
// 缩放root bone
A3DBone* pRootBone = ScaleRootBone(m_pPlayerModel, fScale);
// 脚底位移修正
if (pRootBone) {
float offset = pRootBone->GetOriginalMatrix().GetRow(3).y * (1.f - fScale);
pSkeleton->SetFootOffset(offset);
}
// 缩放武器、飞行器
ScaleChildModel();
// 缩放gfx
m_pPlayerModel->SetGfxScale(fScale);
// 缩放包围盒
CalcPlayerAABB();
A3DVECTOR3 vPos = GetPos();
m_aabb.Center = vPos + A3DVECTOR3(0.0f, m_aabb.Extents.y, 0.0f);
m_aabb.CompleteMinsMaxs();
m_aabbServer.Center = vPos + A3DVECTOR3(0.0f, m_aabbServer.Extents.y, 0.0f);
m_aabbServer.CompleteMinsMaxs();
}
void CECPlayer::LoadMonsterSpiritGFX(int index, int res_index)
{
int count = sizeof(m_pMonsterSpiritGFX) / sizeof(m_pMonsterSpiritGFX[0]);
if (index >= 0 && index < count) {
A3DGFXExMan *pGFXExMan = g_pGame->GetA3DGFXExMan();
if (m_pMonsterSpiritGFX[index] == NULL) {
m_pMonsterSpiritGFX[index] = pGFXExMan->LoadGfx(g_pGame->GetA3DDevice(), res_GFXFile(res_index));
if (!m_pMonsterSpiritGFX[index]) return;
m_pMonsterSpiritGFX[index]->SetScale(1.0f);
m_pMonsterSpiritGFX[index]->Start(true);
}
}
}
void CECPlayer::StartMonsterSpiritConnectGfx(int mine_id, A3DVECTOR3 pos)
{
LoadMonsterSpiritGFX(0, RES_GFX_MONSTER_SPIRIT_LINE);
m_iMonsterSpiritMineID = mine_id;
m_posMonsterSpirit = pos;
}
void CECPlayer::StopMonsterSpiritConnectGfx()
{
A3DGFXExMan *pGFXExMan = g_pGame->GetA3DGFXExMan();
if (pGFXExMan) pGFXExMan->CacheReleasedGfx(m_pMonsterSpiritGFX[0]);
m_pMonsterSpiritGFX[0] = NULL;
m_iMonsterSpiritMineID = 0;
}
void CECPlayer::StartMonsterSpiritBallGfx()
{
LoadMonsterSpiritGFX(1, RES_GFX_MONSTER_SPIRIT_BALL);
if (m_pMonsterSpiritGFX[1]) {
m_pMonsterSpiritGFX[1]->SetPos(m_posMonsterSpirit);
m_stateMonsterSpirit = BALL_STATE_RISING;
}
}
void CECPlayer::UpdateMonsterSpiritGfx(DWORD dwDeltaTime)
{
UpdateOneMultiObjectEffect(m_iMonsterSpiritMineID, m_pMonsterSpiritGFX[0], dwDeltaTime);
if (m_stateMonsterSpirit == BALL_STATE_NONE) {}
else if (m_stateMonsterSpirit == BALL_STATE_DISAPPER) {
A3DGFXExMan *pGFXExMan = g_pGame->GetA3DGFXExMan();
if (pGFXExMan) pGFXExMan->CacheReleasedGfx(m_pMonsterSpiritGFX[1]);
m_pMonsterSpiritGFX[1] = NULL;
m_stateMonsterSpirit = BALL_STATE_NONE;
} else {
A3DVECTOR3 targetPos = GetPos();
if (m_pPlayerModel){
int index;
if (A3DBone *pBone = m_pPlayerModel->GetA3DSkinModel()->GetSkeleton()->GetBone("Bip01 Head", &index)){
targetPos = pBone->GetAbsoluteTM().GetRow(3);
}
}
A3DVECTOR3 pos;
if (m_stateMonsterSpirit == BALL_STATE_RISING) {
float deltaY = 1.f * dwDeltaTime / 1000;
pos = m_pMonsterSpiritGFX[1]->GetPos();
pos.y += deltaY;
m_pMonsterSpiritGFX[1]->SetPos(pos);
if (pos.y > targetPos.y) m_stateMonsterSpirit = BALL_STATE_FOLLOW;
} else if (m_stateMonsterSpirit == BALL_STATE_FOLLOW) {
pos = m_pMonsterSpiritGFX[1]->GetPos();
A3DVECTOR3 direction = targetPos - pos;
if (direction.Magnitude() < 1.f) m_stateMonsterSpirit = BALL_STATE_DISAPPER;
direction.Normalize();
pos += (direction * (10.f * dwDeltaTime / 1000));
m_pMonsterSpiritGFX[1]->SetPos(pos);
}
m_pMonsterSpiritGFX[1]->TickAnimation(dwDeltaTime);
}
}
void CECPlayer::RenderMonsterSpiritGfx()
{
A3DGFXExMan *pGFXExMan = g_pGame->GetA3DGFXExMan();
unsigned int count = sizeof(m_pMonsterSpiritGFX) / sizeof(m_pMonsterSpiritGFX[0]);
for (unsigned int i = 0; i < count; ++i)
{
if (m_pMonsterSpiritGFX[i] && m_pMonsterSpiritGFX[i]->IsVisible())
pGFXExMan->RegisterGfx(m_pMonsterSpiritGFX[i]);
}
}
int CECPlayer::HasSkillStateForAction()
{
for (int i=0;i<sizeof(m_sciStateIDForStateAction)/sizeof(m_sciStateIDForStateAction[0]);i++)
{
if (GetExtState(m_sciStateIDForStateAction[i]))
return m_sciStateIDForStateAction[i];
}
return 0;
}
void CECPlayer::PlayEnterBattleGfx()
{
if (m_ReincarnationCount) {
AString strGfx;
strGfx.Format(res_GFXFile(RES_GFX_BATTLEFURY), m_ReincarnationCount);
PlayGfx(strGfx, NULL, 1.0, PLAYERMODEL_TYPEALL);
}
}
bool CECPlayer::IsInChariot()
{
CECGameRun* pRun = g_pGame->GetGameRun();
if(!pRun) return false;
CECHostPlayer* pHost = pRun->GetHostPlayer();
if (pHost && pHost->GetBattleInfo().IsChariotWar() && GetShapeType() == PLAYERMODEL_DUMMYTYPE2 && GetDummyModel(PLAYERMODEL_DUMMYTYPE2))
return true;
return false;
}
bool CECPlayer::ChangeFashionColor(int equipSlot, unsigned short newColor){
if (EQUIPIVTR_FASHION_BODY != equipSlot &&
EQUIPIVTR_FASHION_LEG != equipSlot &&
EQUIPIVTR_FASHION_FOOT != equipSlot &&
EQUIPIVTR_FASHION_WRIST != equipSlot){
return false; // 不是时装位置
}
if (!GetRealElementID(equipSlot, m_aEquips[equipSlot])){
return false; // 没有装备
}
int equipID = m_aEquips[equipSlot];
unsigned short currentColor = ((equipID >> 16) & 0x0000ffff);
if (currentColor == newColor){
return true; // 与已有颜色相同,下面就不用麻烦检查了
}
int skinIndex = -1;
switch (equipSlot){
case EQUIPIVTR_FASHION_BODY:
skinIndex = SKIN_FASHION_UPPER_BODY_INDEX;
break;
case EQUIPIVTR_FASHION_LEG:
skinIndex = SKIN_FASHION_LOWER_INDEX;
break;
case EQUIPIVTR_FASHION_FOOT:
skinIndex = SKIN_FASHION_FOOT_INDEX;
break;
case EQUIPIVTR_FASHION_WRIST:
skinIndex = SKIN_FASHION_WRIST_INDEX;
break;
}
A3DCOLOR a3dColor = FASHION_WORDCOLOR_TO_A3DCOLOR(newColor);
for (int i(0); i < sizeof(m_aSkins[0])/sizeof(m_aSkins[0][0]); ++ i){
if (A3DSkin *pSkin = m_aSkins[skinIndex][i]){
for(int idTex=0; idTex<pSkin->GetTextureNum(); idTex ++){
A3DTexture * pTex = pSkin->GetTexture(idTex);
if (pTex && pTex->IsShaderTexture()){
A3DShader * pShader = (A3DShader *) pTex;
pShader->GetGeneralProps().dwTFactor = a3dColor; // Loop 每件 Skin,直接设置到每个 Shader 中
}
}
}
}
int newEquipID = (m_aEquips[equipSlot] & 0x0000ffff) | (newColor << 16);
m_aEquips[equipSlot] = newEquipID;
return true;
}
void CECPlayer::RecreateActionController(){
if (!m_pPlayerModel){
delete m_pActionController;
m_pActionController = NULL;
return;
}
if (!m_pActionController){
m_pActionController = new CECPlayerActionController;
}
m_pActionController->Bind(this, m_pPlayerModel);
}
void CECPlayer::RecreateBodyController(){
if (!m_pPlayerModel){
delete m_pBodyController;
m_pBodyController = NULL;
return;
}
if (!SupportCastSkillWhenMove()){
return;
}
if (!m_pBodyController){
m_pBodyController = new CECPlayerBodyController;
}
if (!m_pBodyController->Bind(this, m_pPlayerModel)){
delete m_pBodyController;
m_pBodyController = NULL;
}
}
void CECPlayer::TurnFaceTo(int idTarget, DWORD dwTime){
if (idTarget){
if (idTarget == GetCharacterID()){
return;
}
if (IsWorkMoveRunning() && !IsPlayingCastingSkillAndMoveActions()){ // 移动时一般应面向移动方向、只在移动施法中才转向
return;
}
}
if (!m_pBodyController){
CECObject::TurnFaceTo(idTarget, dwTime);
return;
}
m_pBodyController->TurnFaceTo(idTarget);
}
void CECPlayer::SetName(const ACHAR *szName){
m_strName = szName;
if (m_pPateName){
m_pPateName->SetText(m_strName, false);
}
}
void CECPlayer::CloneSimplePropertyTo(CECPlayer *player)const{
// CECObject
player->SetPos(GetPos());
player->SetDirAndUp(GetDir(), GetUp());
player->SetGroundNormal(GetGroundNormal());
player->SetUseGroundNormal(GetUseGroundNormal());
// CECPlayer
player->m_PlayerInfo = GetPlayerInfo();
player->SetBornStamp(GetBornStamp());
player->SetName(GetName());
player->SetProps(&GetBasicProps(), &GetExtendProps());
player->m_iGender = GetGender();
player->m_iProfession = GetProfession();
player->m_pvp = GetPVPInfo();
player->m_aIconStates = GetIconStates();
player->SetMoneyAmount(GetMoneyAmount());
player->m_iMaxMoney = GetMaxMoneyAmount();
player->m_i64EquipDisabled = m_i64EquipDisabled;
player->SetBoothState(GetBoothState());
player->m_factionPVPMask= m_factionPVPMask;
player->m_RidingPet = GetRidingPetInfo();
player->m_iBattleCamp = GetBattleCamp();
player->m_dwGMFlags = m_dwGMFlags;
player->SetSpouse(GetSpouse());
player->m_idForce = GetForce();
player->SetCountry(GetCountry());
player->SetMoveMode(GetMoveMode());
player->SetMoveEnv(GetMoveEnv());
player->SetWalkRunFlag(GetWalkRunFlag());
player->m_MoveConst = m_MoveConst;
player->m_aabbServer = m_aabbServer;
player->m_aabb = m_aabb;
player->m_dwStates = m_dwStates;
player->m_dwStates2 = m_dwStates2;
player->m_fTouchRad = GetTouchRadius();
player->m_byPariahLvl = GetPariahLevel();
player->SetBoothName(GetBoothName());
player->m_CustomizeFactor = m_CustomizeFactor;
player->ChangeCustomizeData(m_CustomizeData);
for (int i=0; i < GetEffectCount(); i++)
player->ApplyEffect(GetEffect(i), true);
player->SetFactionID(GetFactionID());
player->SetCurPetID(GetCurPetID());
player->SetCurrentTitle(GetCurrentTitle());
player->SetReputation(GetReputation());
player->SetFashionMode(InFashionMode());
player->SetFRoleID(GetFRoleID());
player->SetMeridiansProp(GetMeridiansProp());
player->SetReincarnationCount(GetReincarnationCount());
player->SetRealmLevel(GetRealmLevel());
player->ScaleBody(GetScaleBySkill());
player->SetTeamRequire(GetTeamRequire(), false);
player->SetNewExtendStates(0, m_aExtStates, OBJECT_EXT_STATE_COUNT);
player->m_GoblinRenderCnt = m_GoblinRenderCnt;
player->m_bRenderGoblin = m_bRenderGoblin;
}
int CECPlayer::SearchFullSuite()
{
DATA_TYPE DataType = DT_INVALID;
elementdataman* pDataMan = g_pGame->GetElementDataMan();
CECGame::SuiteEquipTable& SuiteMapTab = g_pGame->GetSuiteEquipTable();
int i;
typedef abase::hashtab<int, int, abase::_hash_function> SuiteTable;
SuiteTable SuiteTab(32);
// Check how many suits of equipment host have dressed
for (i=0; i < SIZE_ALL_EQUIPIVTR; i++)
{
int idEquip = GetEquippedItem(i);
if (!idEquip)
continue;
CECGame::SuiteEquipTable::pair_type pair = SuiteMapTab.get(idEquip);
if (!pair.second)
continue;
int idSuite = *pair.first;
const void* pData = pDataMan->get_data_ptr(idSuite, ID_SPACE_ESSENCE, DataType);
if (DataType != DT_SUITE_ESSENCE)
continue;
const SUITE_ESSENCE* pSuiteEss = (const SUITE_ESSENCE*)pData;
if (pSuiteEss->file_gfx[0])
SuiteTab.put(idSuite, pSuiteEss->max_equips);
}
if (!SuiteTab.size())
return 0; // No suite was found
// Check whether suite is full
SuiteTable::iterator it = SuiteTab.begin();
for (; it != SuiteTab.end(); ++it)
{
int idSuite = *it.key();
int iMaxNum = *it.value();
if (iMaxNum == GetEquippedSuiteItem(idSuite))
return idSuite;
}
return 0;
}
int CECPlayer::GetEquippedSuiteItem(int idSuite, int* aItems/* NULL */)
{
CECGame::SuiteEquipTable& SuiteTab = g_pGame->GetSuiteEquipTable();
int i, iItemCnt = 0;
for (i=0; i < SIZE_ALL_EQUIPIVTR; i++)
{
int idEquip = GetEquippedItem(i);
if (!idEquip)
continue;
CECGame::SuiteEquipTable::pair_type pair = SuiteTab.get(idEquip);
if (!pair.second || idSuite != *pair.first)
continue;
if (aItems)
aItems[iItemCnt] = idEquip;
iItemCnt++;
}
return iItemCnt;
}
int CECPlayer::GetEquippedItem(int index)const{
if (index < 0 || index >= SIZE_ALL_EQUIPIVTR){
ASSERT(false);
return 0;
}
return m_aEquips[index] & 0xffff;
}
void CECPlayer::DetachWeapon(){
if (IsWeaponAttached()){
ASSERT(GetPlayerModel() != NULL);
if (GetLeftHandWeapon()){
GetPlayerModel()->RemoveChildModel(_left_hand_weapon, false);
}
if (GetRightHandWeapon()){
GetPlayerModel()->RemoveChildModel(_right_hand_weapon, false);
}
m_bWeaponAttached = false;
}
}
bool CECPlayer::AttachWeapon(){
bool result(false);
ASSERT(!IsWeaponAttached());
while (GetPlayerModel() && (GetLeftHandWeapon() || GetRightHandWeapon())){
A3DSkinModel *pSkinModel = GetPlayerModel()->GetA3DSkinModel();
if (!pSkinModel ||
!pSkinModel->GetSkeleton()){
break;
}
if (!pSkinModel->GetSkeletonHook(GetLeftWeaponHookPos(m_weaponHangerPos),true) ||
!pSkinModel->GetSkeletonHook(GetRightWeaponHookPos(m_weaponHangerPos),true)){
break;
}
if (GetLeftHandWeapon()){
GetPlayerModel()->AddChildModel(
_left_hand_weapon,
false,
GetLeftWeaponHookPos(m_weaponHangerPos),
GetLeftHandWeapon(),
GetLeftWeaponOwnHookPos(GetLeftHandWeapon()));
}
if (GetRightHandWeapon()){
GetPlayerModel()->AddChildModel(
_right_hand_weapon,
false,
GetRightWeaponHookPos(m_weaponHangerPos),
GetRightHandWeapon(),
GetRightWeaponOwnHookPos(GetRightHandWeapon()));
}
m_bWeaponAttached = true;
result = true;
break;
}
return result;
}
void CECPlayer::ReleaseWeapon(){
DetachWeapon();
if (m_pLeftHandWeapon){
A3DRELEASE(m_pLeftHandWeapon);
}
if (m_pRightHandWeapon){
A3DRELEASE(m_pRightHandWeapon);
}
}
bool CECPlayer::IsWeaponAttached()const{
return m_bWeaponAttached;
}
int CECPlayer::GetRace()const{
return CECProfConfig::Instance().GetRaceByProfession(GetProfession());
}
bool CECPlayer::ShouldUseFaceModel() const {
if (!IsElsePlayer()){
return true;
}
return m_iMemUsage < CECMemSimplify::MEMUSAGE_NOFACE;
}
bool CECPlayer::ShouldUseClothedModel() const {
if (!IsElsePlayer()){
return true;
}
return m_iMemUsage < CECMemSimplify::MEMUSAGE_SIMPLEMODEL;
}
bool CECPlayer::ShouldUseModel() const {
if (!IsElsePlayer()){
return true;
}
bool result(true);
switch (m_iMemUsage){
case CECMemSimplify::MEMUSAGE_NOMODEL:
result = g_pGame->GetGameRun()->GetMemSimplify()->IsMostImportant(this);
break;
case CECMemSimplify::MEMUSAGE_NOMODEL_UNIMPORTANT:
result = g_pGame->GetGameRun()->GetMemSimplify()->IsImportant(this);
break;
}
return result;
}
bool CECPlayer::ShouldUseBoothModel()const{
if (m_iBoothState != 2){ // 不是摆摊状态不需要模型
return false;
}
if (IsHostPlayer()){ // 主玩家始终显示
return true;
}
if (!IsElsePlayer()){ // 主玩家、周围玩家以外不显示
return false;
}
bool result(true);
switch (GetMemUsage()){
case CECMemSimplify::MEMUSAGE_NOMODEL:
result = g_pGame->GetGameRun()->GetMemSimplify()->IsMostImportant(this);
break;
}
return result;
}