游戏服务器之技能

技能是游戏里的重要组成部分。本文说的是实时rpg服务器的技能部分。


设计上:

技能攻击流程:

学习新的技能(到技能管理器)->技能释放->按某种范围攻击(羁绊范围或者几何范围搜索)->技能对象对防御者产生作用->添加技能状态到防御者技能状态管理器->技能状态管理器定时器运行->执行技能状态管理器中的技能状态对象->执行技能状态对象下的状态机->执行技能状态函数


数据结构

1、技能管理器:pk对象都含有技能管理器,技能管理器是自定义拓展的hashmap(sgi stl的拓展库下的__gnu_cxx::hash_multimap,需自定义哈希和等值比较函数),管理一个pk对象所有的技能对象(技能对象需要存档)。

2、技能状态管理器:pk对象都含有技能状态管理器,管理pk对象被施加的所有的技能状态对象(技能状态对象需要存档),一个技能状态含一个以上的技能状态函数(目前一个)。


技能处理主要分成两部分:技能攻击和技能状态处理。

技能攻击分为:

(1)状态技能。状态技能会加载技能状态到状态管理器。加载时运行且在技能状态定时器里运行技能状态对象(执行技能状态函数)。

(2)即时技能。


添加技能状态时会计算技能点。运行时会加载到角色属性上。

技能状态分为:

(1)可叠加状态。

(2)不可叠加状态。

 

对于技能攻击

技能释放时机:

(1)ai的攻击类型状态处理。

(2)客户端发来的角色施法协议处理。


范围搜索(pk对象施法按一定的规则来搜索范围)

(1)羁绊范围搜索:附近组队范围(队友或自己)

(2)技能几何范围搜索(1单2 自己圆3鼠标点圆4扇5线))

几何范围搜索参考:http://write.blog.csdn.net/postedit/26476517 


对于技能状态处理

技能状态处理时机:

(1)角色循环运行技能状态管理器定时器(运行所有有效技能状态对象里的函数)。

(2)npc循环运行技能状态管理器定时器(运行所有有效技能状态对象里的函数)。



本文目录

1、技能配置

2、技能对象

3、技能管理器

4、学习新的技能

5、技能作用

(1)技能释放

(2)技能形式

(2-1)羁绊范围技能攻击

(2-2)几何范围技能攻击

(3)技能对象对防御者产生作用

(4)添加技能状态到技能状态管理器


6、范围检查

(1)技能的组队范围检查

(2)技能释放几何范围搜索

(2-1)某点为中心的圆的范围

(2-2)搜索扇形范围

7、技能状态对象

8、技能状态管理器

9、技能状态管理器定时器

10、运行技能状态对象

11、技能状态函数


本文内容:

1、技能配置

 策划配置的技能配置表一行对应的一个技能配置。含技能基础属性数值。

struct SkillDataBase
{
	const uint32 getUniqueID() const
	{
		return id;
	}

	uint32 	id;			        //技能id
	char  	job[MAX_JOB_LEN];		//职业限制
	char name[MAX_NAME_LEN];		//技能名称
	uint32  target;				//1组队   2友方 3 敌方    4 城墙    5 自己
	uint32 	cd;				//技能cd
	uint16 	range;				// 1单  2自己圆    3鼠标点圆 4 扇  5  线
	uint16  distance;			//技能攻击距离
	uint16 	angle;				//角度
	uint16 	radius;				//半径
	uint16 	mp;				//消耗mp
	uint16 	sp;				//消耗sp
	string   stateid;
	uint16   type;				//默认类型[出身]  0 需要学习  1   需要装备的 2
	uint32   ms;				//角色施放该技能需要耗费的毫秒数
	uint32   speed;  			//角色的技能基础需求速度值
	uint32   attackmode;     <span style="white-space:pre">		</span>//
	uint16   normal;			//属性对抗计算流程
	uint16   combo;				//触发连击的技能
};

2、技能对象

技能对象作为出生、学习的对象,可以释放并存于角色对象的技能管理器。可用于技能释放检查和当前属性扣除。

class Skill :base_object{
public:
	friend class SkillManager;//技能管理器

	/**
	 * \brief 内存分配器
	 *
	 */
	friend void constructInPlace<Skill,uint32,uint16,uint32,uint32,uint64>(Skill *,uint32,uint16,uint32,uint32,uint64);
	friend void destructInPlace<Skill>(Skill *);
	/**
	 * \brief 构造函数
	 * \param id 技能编号
	 * \param level 技能等级
	 * \param points 技能熟练点数
	 * \param coldtime 冷却时间
         * \param lasttime 最后释放技能时间
	 */
	Skill(const uint32 _id,const uint16 _level,const uint32 _points,const uint32 _coldtime,const uint64 _lasttime);
	/**
	 * \brief 析构函数
	 */
	~Skill();
public :
	/**
	 * \brief 获取类名字
	 *
	 */
	const char *getClassName() const { return "技能"; }
	/**
	 * \brief 技能序列化
	 * \param out 输出参数,缓存地址
	 * \return 返回缓存大小
	 */
	const uint32 serialize(char *out,scene_pk_object *owner);
	/**
	 * \brief 检查攻击模式切换的时间的合法性
	 *
	 */
	bool checkAttackModeTime(scene_player *pUser,uint32 clienttime);
	/**
	 * \brief 检查技能攻击距离
	 * \param pos1 位置1
	 * \param pos2 位置2
	 * \return true表示在攻击范围内
	 */
	bool checkRange(const nPos &pos,const nPos &pos1,uint32 adjust=0);
	/**
	 * \brief 该技能是否需要走伤害流程
	 * \return 返回true需要计算伤害
	 */
	bool checkInjured();
	/**
	 * \brief 获取技能剩余冷却时间
	 * \return 剩余冷却时间
	 */
	const uint32 getColdTime(scene_pk_object *owner);
	/**
	 * \brief 检查技能需求的召唤兽
	 *
	 */
	bool checkSummon(scene_pk_object *owner);
	/**
	 * \brief 检查技能需求的条件状态
	 *
	 */
	bool checkState(scene_pk_object *owner);
	/**
	 * \brief 消耗技能需求的条件状态
	 *
	 */
	void consumeState(scene_pk_object *owner);
	/**
	 * \brief 释放技能检查生命值比例
	 *
	 */
	bool checkneedhppercent(scene_pk_object *owner);
	/**
	 * \brief 检查当前技能是否可以释放
	 * \return true可以释放
	 *
	 */
	bool checkColdTime(scene_pk_object *owner);
	/**
	 * \brief 通知客户端清空冷却时间
	 *
	 */
	void notifyClearColdTime(scene_pk_object *owner);
	/**
	 * \brief 设置冷却时间
	 *
	 */
	void setColdTime(uint32 coldtime);
        //通知技能cd时间
	void notifyColdTime(scene_pk_object *owner);
    /* *
     * \author 
     * \brief 获取该技能增加的效果值
     * */
    void getSkillValue(scene_pk_object *owner,uint32 &value,uint8 &hurtType);
	/**
	 * \brief 释放技能扣除魔法值
	 * \param owner 释放者
	 * \return 生命值扣除是否成功
	 */
	bool usemp(scene_pk_object *owner);
	/**
	 * \brief 释放技能扣除体力值
	 * \param owner 释放者
	 * \return 体力值扣除是否成功
	 *
	 */
	bool usesp(scene_pk_object *owner);
public :
	/**
	 * \brief 技能升级表基类指针
	 */
	const zSkillB	*base;
	
	/**
	 * \brief 技能当前等级
	 */
	uint16	level;
	/**
	 * \brief 技能熟练点数
	 */
	uint32	points;
    /**
     * \brief 冷却时间
     */
    uint32 coldtime;
    /**
	 * \brief 最后释放技能时间
	 */
	uint64 lasttime;
};


3、技能管理器

每个角色对象含一个技能管理器,包含技能的学习,升级,删除,及释放等操作。需要存档技能管理器内的技能对象。对防御者释加技能对象。

/**
 * \brief 技能管理器,包括技能的学习,升级,删除,及释放等操作
 */
class SkillManager : public base_manager<index_uint32>
{
public :

	typedef base_manager<index_uint32> super;
	/**
	 * \brief 构造函数
	 * \param obj 技能管理器拥有者
	 */
	SkillManager(scene_pk_object *obj);
	/**
	 * \brief 析构函数
	 */
	~SkillManager();
	/**
	 * \brief 学习升级技能
	 * \param id 技能编号
	 * \param byGold 钻石购买技能
	 * \return 学习升级是否成功
	 *
	 */
	bool studySkill(const uint32 id,bool byGold = false);
	/**
	 * \brief 技能的序列化
	 * \param out 输出参数,序列化缓存
	 * \return 返回序列化缓存大小
	 */
	const uint32 serialize(char *out);
	/**
	 * \brief 技能反序列化
	 * \param in 需要反序列化的缓存
	 * \param version 版本
	 *
	 */
	void unSerialize(const SerializeBinaryMember *in, uint32 version);
        /**
         * \brief 技能升级列表序列化
         * \param out 输出参数,序列化缓存
         * \return 返回序列化缓存大小
         */
        const uint32 serializeSkillUpdate(char* &out)const;
        /**
         * \brief 技能升级列表反序列化
         * \param in 需要反序列化的缓存
         * \param version 版本
         */
        const uint32 unserializeSkillUpdate(const char* &in);
	/**
	 * \brief 对对方作用技能
	 * \param skill 作用的技能
	 * \param pDef 防御者
	 *
	 */
	void putSkill(Skill *skill,scene_pk_object *pDef);
	/**
	 * \brief 得到一个技能
	 * \param id 技能编号
	 * \return 返回技能,失败返回NULL
	 *
	 */
	Skill *getSkillByID(const uint32 id);
	/**
	 * \brief 得到一个技能
	 * \param name 技能名字
	 * \return 返回技能,失败返回NULL
	 *
	 */
	Skill* getSkillByName(const char* name);
	/**
	 * \brief 添加一个技能给目标
	 * \param id 技能编号
	 * \param level 技能等级
	 * \return 添加是否成功
	 *
	 */
	bool loadSkill(const uint32 id,const uint16 level=1);
	/**
	 * \brief 创建一个技能
	 * \param base 技能基础数据
	 * \param points 花费技能点
	 * \param coldtime 冷却时间
	 * \return 成功,返回技能指针
	 * 		   失败,返回NULL
	 */
	Skill *creatorSkill(const uint32 skillid,const uint16 level = 1,const uint32 points=0 ,const uint32 coldtime=0);
	/**
	 * \brief 随机得到一个技能
	 * \return 返回一个技能指针
	 *
	 */
	Skill *randomGetSkill();
	/**
	 * \brief 卸载一个技能并通知客户端
	 * \param id 技能编号
	 *
	 */
	void unloadSkillNotify(const uint32 id);
	/**
	 * \brief 卸载一个技能不通知客户端
	 * \param id 技能编号
	 *
	 */
	void unloadSkill(const uint32 id);
	/**
	 * \brief 刷新所有技能给用户
	 *
	 */
	void sendAllToMe();
	/**
	 * \brief 获取某职业已学技能点
	 * \param profession 职业
	 * \return 该职业已学技能点
	 *
	 */
	const uint16	getProfessionPoints(const uint16 profession);
	/**
	 * \brief 获取职业
	 *
	 */
	inline const uint32 getProfession() { return _profession; }
	/**
	 * \brief 遍历
	 * \param e 回调
	 * \return 回调是否成功
	 */
	template <class YourSkillEntry>
	bool execEverySkill(callback<YourSkillEntry> &e)
	{
		return invoke_all<>(e);
	}
	/**
	 * \brief 遍历
	 * \param e 回调
	 */
	template <class DelSkillEntry>
	void delEverySkill(temp_remove<DelSkillEntry> &e)
	{
		delete_object_if<>(e);
	}
       
        /**
         * \author 
         * \brief 更新技能熟练点数
         * \param skillid 技能ID
         */
        bool updatePoints(const uint32 skillid);
        /**
         * \author 
         * \brief 升级技能
         */
        bool updateSkill(const uint32 id,const uint8 flag = 0);
        /**
         * \author hxh
         * \brief 技能升级GM命令
         */
        void skillUpdateGM();
        /**
         * \author 
         * \brief   获取技能限制属性
         */
        void getLimitedPoint(uint32 &strength,uint32 &agility,uint32 &power,uint32 &intell);
private :
	/**
	 * \brief 检查并扣除技能学习升级需要的东东
	 * \param id 技能编号
	 * \param needbook 学习技能是否需要技能书,默认为需要
	 * \return 成功可以学习升级
	 *
	 */
	bool checkLevel(const uint32 id, bool needbook = true);
	/**
	 * \brief 加载所有普通技能(不需要学习就会的技能)
	 *
	 */
	void loadRoleNormalSkill();
private :
	/**
	 * \brief 管理器主人
	 *
	 */
	scene_pk_object *owner;
	/**
	 * \brief 职业
	 *
	 */
	uint32 _profession;
   public:        
       typedef std::map<uint32,SkillUpdate> SkillUpdateMap;
       typedef SkillUpdateMap::const_iterator SkillUpdateConstIt;
       typedef SkillUpdateMap::iterator SkillUpdateIt;
       SkillUpdateMap skillUpdateMap;//技能升级属性存储列表
};



能pk的对象含有技能管理器

class scene_pk_object : public SceneEntry

{...

/*** \author
         * \description 技能管理器
         */
        SkillManager skillm;

};


4、学习新的技能

检查学习条件,根据技能的id来学习技能。

bool SkillManager::studySkill(const uint32 id,bool byGold)
{
   if(owner->getType() != SceneObject_Player)
   {
		return false;
   }
	scene_player *pUser = (scene_player *)owner;
	const zSkillB *base = NULL;
  const SkillStudyB *skillBase = NULL;
  if(byGold)
  {
      skillBase = (const SkillStudyB*)skillStudyBm::get_instance().getBySkillId(id);
  }
  else
  {
		skillBase =	(const SkillStudyB *)skillStudyBm::get_instance().get(id);
  }
 if(!skillBase)
 {
		g_log->error("[%u,%s]技能学习配表没有该技能id=%u",pUser->id,pUser->name,id);
		return false;
  }

  base = skillbm::get_instance().get(skillBase->skillId);
  if(!base)
 {
		g_log->error("[%u,%s]技能配表没有该技能id=%u",pUser->id,pUser->name,skillBase->skillId);
    return false;
 }

  Skill *skill = getSkillByID(skillBase->skillId);
  if(skill)
  {
		g_player_mgr.sendTipsToUser(pUser->roledata.id,TIPS_TYPE_EVENT,"%s技能已经学习了",skill->base->name);
		return false;
  }

  if(skillBase->job && !((1<<pUser->roledata.job) & skillBase->job))
  {
		g_player_mgr.sendTipsToUser(pUser->roledata.id,TIPS_TYPE_EVENT,"职业不对");
		return false;
  }
        
  if(skillBase->changeJob > pUser->roledata.changeJob)
  {
      g_player_mgr.sendTipsToUser(pUser->roledata.id,TIPS_TYPE_EVENT,"职业进阶小于%d",skillBase->changeJob);
      return false;
  }
	if(skillBase->level && pUser->roledata.level < skillBase->level)
	{
		g_player_mgr.sendTipsToUser(pUser->roledata.id,TIPS_TYPE_EVENT,"等级小于%d",skillBase->level);
		return false;
	}

	if(skillBase->strength && pUser->charstate.strength < skillBase->strength)
	{
		g_player_mgr.sendTipsToUser(pUser->roledata.id,TIPS_TYPE_EVENT,"力量小于%d",skillBase->strength);
		return false;
	}
	if(skillBase->agility && pUser->charstate.agility < skillBase->agility)
	{
		//scene_chat::send_sys(pUser, "敏捷小于%d", skillBase->agility);
		g_player_mgr.sendTipsToUser(pUser->roledata.id,TIPS_TYPE_EVENT,"敏捷小于%d",skillBase->agility);
		return false;
	}
	if(skillBase->power && pUser->charstate.power < skillBase->power)
	{
		//scene_chat::send_sys(pUser, "体力小于%d", skillBase->power);
		g_player_mgr.sendTipsToUser(pUser->roledata.id,TIPS_TYPE_EVENT,"体力小于%d",skillBase->power);
		return false;
	}
	if(skillBase->intell && pUser->charstate.intell < skillBase->intell)
	{
		//scene_chat::send_sys(pUser, "智力小于%d", skillBase->intell);
		g_player_mgr.sendTipsToUser(pUser->roledata.id,TIPS_TYPE_EVENT,"智力小于%d",skillBase->intell);
		return false;
	}
  if(byGold && !(pUser->packs.removeMoneyByType(MoneyType_Gold,skillBase->gold,pUser->id,pUser->name,"钻石学习技能",eMoneyOpType_SkillStudy)))
  {
      g_player_mgr.sendTipsToUser(pUser->roledata.id,TIPS_TYPE_EVENT,"钻石不足%u",skillBase->gold);
      return false;
  }
	skill = creatorSkill(base->id);
	if(skill == NULL)
	{
		//scene_chat::send_sys(pUser, "创建技能失败");
		g_player_mgr.sendTipsToUser(pUser->roledata.id,TIPS_TYPE_EVENT,"创建技能失败");
		return false;
	}
        pUser->set_save_tag(SAVE_OTHER);
	
	BUFFER_USERCMD(MSG::stAddSkillUserCmd,send);
	MSG::stSkillProperty *data = send->data;
	data->dwSkillID = skillBase->skillId;
	data->dwCooldownTime = 0;
	data->level = skill->level;
	data->points = skill->points;
	send->size++;
	pUser->sendmsgToMe(send, send->allsize());
	//scene_chat::send_sys(pUser, "创建技能成功");
	g_player_mgr.sendTipsToUser(pUser->roledata.id,TIPS_TYPE_EVENT,"创建技能成功");
        pUser->CheckTaskPre( 0,TASK_FINISH_SYS,5,skillBase->skillId,0 );    //完成类任务
	return true;
}

5、技能作用

(1)技能释放

释放技能

bool ScenePk::action(scene_pk_object *pAttack,const MSG::stAttackMagicUserCmd *rev, Skill *ptrskill)
{
	pAttack->hvalue->reset();//清空伤害
	BUFFER_USERCMD(MSG::stRetAttackMagicUserCmd,send);
	if(pAttack->getType() == SceneObject_Player)
	{
		send->dwAttackerID = pAttack->id;
	}
	else
	{
		send->dwAttackerID = pAttack->tempid;
	}

	send->byEntryType = pAttack->getType();
	send->wdSkillID = rev->skillID;
	send->byDirect = rev->direct;

	//魔法目标位置
	pAttack->_xpos = rev->x;
	pAttack->_ypos = rev->y;

	//检测是否满足释放技能
	if(!pAttack->checkSkillAction(ptrskill,rev,send->retCode))
	{
            pAttack->sendmsgToMe(send,send->getsize());
		return false;
	}
	//消耗   cd
	if(!pAttack->consumeSkill(ptrskill,send->retCode))
	{
	   //释放失败
            pAttack->sendmsgToMe(send,send->getsize());
	   return false;
	}

	//扣除耐久
	if(pAttack->getType() == SceneObject_Player)
	{
		scene_player *pUser = (scene_player *)pAttack;
		pUser->_cur_skill = ptrskill;
		pUser->packs.epack.attackCounter();
		if(ptrskill->base->id != 605201)
		{
			pUser->addCombo(ptrskill);
		}
	}
        //升级技能熟练点
       pAttack->skillm.updatePoints(ptrskill->base->id);
	//攻击类型(几何范围方式)
	switch(ptrskill->base->attackmode)
	{
		case MSG::SkillUseMethod_SelfUse: ///自身释放 属于没有伤害类型  只有加状态(<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;">只带状态 没有伤害</span>)
		{
			magicAttackSelf(pAttack,rev,send, ptrskill);
		}
		break;
		case MSG::SkillUseMethod_ToOne: //对单体释放,辅助技能,没有伤害,只加状态
		{
			skillStateToOne(pAttack,rev,send,ptrskill);
		}
		break;
		case MSG::SkillUseMethod_ToMulti://对多体释放,辅助技能,没有伤害,只加状态
		{
			skillStateToMulti(pAttack,rev,send,ptrskill);
		}
		break;
		case MSG::SkillUseMethod_PointAttack://对单体攻击(保存连击位置、更新分数、对防御者施加技能对象(添加技能状态)、<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;">计算伤害和sd防护、发送客户端、处理伤害和反伤、处理补血</span><span style="font-size: 12px; font-family: Arial, Helvetica, sans-serif;">)</span>
		{
			magicAttackSingle(pAttack,rev,send,ptrskill);
        	}
		break;
		case MSG::SkillUseMethod_MultiAttack: //对多体攻击(搜索范围、计算连击伤害和魔法伤害、发送客户端、处理战斗状态、处理攻击伤害、处理反伤、处理补血)
		{
			magicAttackMulti(pAttack,rev,send, ptrskill);
		}
		break;
		default:
		{
			send->retCode = MSG::RETURN_CODE_UNDEFINED_ATTACK_MODE;
            		pAttack->sendmsgToMe(send,send->getsize());
		}
		break;
	}

	return true;
}


(2)技能形式

(2-1)羁绊范围技能攻击

组队技能。 释放组队技能(一般是辅助技能)。

scene_pk_object *pAtt 施法对象
void ScenePk::magicAttackTeam(scene_pk_object *pAtt,const MSG::stAttackMagicUserCmd *rev,MSG::stRetAttackMagicUserCmd *send,Skill *ptrskill)
{
	scene_player* pAttack = pAtt->getMaster();
	if(!pAttack)
	{
		send->retCode = MSG::RETURN_CODE_PLAYER_NULL;//没有该玩家
	        pAtt->sendmsgToMe(send,send->getsize());
		return;
	}

	MSG::stRetDefenceList *rdlist =  NULL;
	uint8 hurtType = MSG::HURT_TYPE_NULL;

	//给队友加技能状态BUFF
	if(pAttack->team)
	{
		pAttack->team->checkTeamAttckRange(pAttack,ptrskill,send);//对技能范围内的队友施法,添加技能对象作用(技能范围需要在视野范围内)
	}
	else//对自己施法
	{
		pAttack->skillm.putSkill(ptrskill,pAttack);
		rdlist = (MSG::stRetDefenceList*)&send->data[send->size];
		rdlist->dwDefencerID = pAttack->id;
		rdlist->byEntryType = pAttack->getType();
		rdlist->dwHp = 0;
		rdlist->byState = 0;
		rdlist->hurtType = hurtType;
		send->size = 1;
	}
	send->retCode = MSG::RETURN_CODE_SUCCEED;

  if(send->size)
	{
		pAttack->sendmsgToNine(send,send->getsize());//通知九屏
	}else
	{
		pAttack->sendmsgToMe(send,send->getsize());
	}
}


(2-2)几何范围技能攻击

先计算伤害和防护值,返回给客户端,再对被施法者处理战后影响(添加被战斗技能状态(buff),增减属性,红名,掉经验,掉装备,扣耐久,转换战斗模式,npc增加仇恨对象)。

技能释放几何范围方式
  

 enum enumSkillUseMethod
    {
        SkillUseMethod_SelfUse			= 0,		/**对自己释放*/
        SkillUseMethod_MultiAttack	    = 1,        /**点对多攻击*/
        SkillUseMethod_PointAttack      = 2,        /**点对点攻击*/
        SkillUseMethod_ToOne            = 3,        /**点对点辅助*/
        SkillUseMethod_ToMulti          = 4,        /**点对多辅助*/
        SkillUseMethod_Num,
    };

点对点的攻击(SkillUseMethod_PointAttack)。单被施法对象的攻击计算。

void ScenePk::magicAttackSingle(scene_pk_object *pAttack, const MSG::stAttackMagicUserCmd *rev, MSG::stRetAttackMagicUserCmd *send, Skill *ptrskill)
{

	// 连击处理(<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;">保存连击座标</span>)
	if(ptrskill && pAttack && SceneObject_Player == pAttack->getType())
	{
		switch(ptrskill->base->range)
		{
		case MSG::SKILLRANGETYPE_SINGLE:/**< 单点 */
		case MSG::SKILLRANGETYPE_ONESELF:/**< 自己圆 r*/
		case MSG::SKILLRANGETYPE_LINE:/**< 线*/
		case MSG::SKILLRANGETYPE_SECTOR:/**< 扇*/
			{
				((scene_player*)pAttack)->addComboAttckPos(pAttack->getPos().x, pAttack->getPos().y, ptrskill->base->id);
			}
			break;
		case MSG::SKILLRANGETYPE_CURSOR:/**< 鼠标点圆 */
			{//保存连击座标
				((scene_player*)pAttack)->addComboAttckPos(rev->x, rev->y, ptrskill->base->id);
			}
			break;
		}
	}

        uint8 hurtType = MSG::HURT_TYPE_NULL;
	uint32 hurtSd = 0;//防御者SD伤害
	bool isMiss = false;
	scene_pk_object *pDefend = getPKObjectByEntryType(rev->defencerID,rev->defenderType);
	if(!pDefend)
	{
		send->retCode = MSG::RETURN_CODE_TARGET_NULL;//防御者为空
                pAttack->sendmsgToMe(send,send->getsize());
	}

	if(!pDefend->checkCanPKMe(pAttack))
	{
		return;
	}
	nPos comboPos;
       uint32 parm1 = 0;		
       parm1 = getCommonSkillHurt(ptrskill);
	hurtType = MSG::HURT_TYPE_NULL;
	hurtSd = 0;//防御者SD伤害
      pAttack->hvalue->hurt = 0;//初始化为0
      pDefend->hvalue->hurt = 0;//初始化为0
	//计算伤害
	pAttack->hvalue->calculate(pAttack, pDefend, hurtType, parm1, pDefend->hvalue->hurt, 0, 0);
	// 处理组队征服副本伤害统计
	if(pAttack && pDefend && pAttack->getType() == SceneObject_Player)
	{
		scene_player *pUser = ((scene_player*)pAttack);
		if(pUser->scene && CopySceneType_TeamConquer == pUser->scene->sceneType)
		{
			pUser->updateScore(pDefend->hvalue->hurt);
		}
	}
        
	pAttack->hvalue->defendHurtWithSd(pAttack, pDefend, pDefend->hvalue->hurt, hurtSd);
	if(hurtType == MSG::HURT_TYPE_MISS)//攻击怪物记录技能释放过程中是否闪避
	{
		isMiss = (pDefend->getType() == SceneObject_NPC)? true:false;//攻击怪物记录技能释放过程中是否闪避
	}
		
        if(ptrskill->base->normal)
	{
		send->srcx = pAttack->getPos().x;
		send->srcy = pAttack->getPos().y;
		if(hurtType != MSG::HURT_TYPE_MISS)
                {
                    pAttack->skillm.putSkill(ptrskill,pAttack);
                }
		send->x = pAttack->getPos().x;
		send->y = pAttack->getPos().y;
		comboPos = pAttack->getPos();
	}
	else
	{
		send->srcx = pDefend->getPos().x;
		send->srcy = pDefend->getPos().y;
                if(hurtType != MSG::HURT_TYPE_MISS)
                {
    		       pAttack->skillm.putSkill(ptrskill,pDefend);
                }
		send->x = pDefend->getPos().x;
		send->y = pDefend->getPos().y;
		comboPos = pAttack->getPos();
	}

	pAttack->full_t_DefenceList(pDefend, (MSG::stRetDefenceList *)&send->data[send->size], pDefend->hvalue->hurt,hurtSd,hurtType);
	send->size++;
        MSG::stRetDefenceList *retReflect = NULL;//就算反伤
	if(pDefend->hvalue->calculate_return_hurt(pAttack, pDefend, pDefend->hvalue->hurt, pAttack->hvalue->hurt))
	{
		uint32 returnHurtSd = 0;
		pAttack->hvalue->defendHurtWithSd(pDefend, pAttack, pAttack->hvalue->hurt, returnHurtSd,true);
		pAttack->full_t_DefenceList(pAttack, (MSG::stRetDefenceList *)&send->data[send->size], pAttack->hvalue->hurt,returnHurtSd,MSG::HURT_TYPE_REFLECT_DAMAGE);
                retReflect = (MSG::stRetDefenceList *)&send->data[send->size];
		send->size++;
	}
	if(send->size)
	{
		send->retCode = MSG::RETURN_CODE_SUCCEED;
                pAttack->sendmsgToNine(send,send->getsize());
		handleAttackHurt(send, pAttack);
			
                //处理反伤害
                if(retReflect)
                {
                  pDefend->handleFightHurt(pAttack,retReflect);
                }

                //玩家主动攻击有一定概率获得瞬间满血
               if(pAttack->getType() == SceneObject_Player && !isMiss)
               { 
		   ((scene_player*)pAttack)->randomFull();
	       }
        }
        else
       {
	   send->retCode = MSG::RETURN_CODE_TARGET_NULL;
           pAttack->sendmsgToMe(send,send->getsize());
       }
}

多被攻击者战斗 (SkillUseMethod_MultiAttack)。多被施法对象的战斗计算。

void ScenePk::magicAttackMulti(scene_pk_object *pAttack, const MSG::stAttackMagicUserCmd *rev, MSG::stRetAttackMagicUserCmd *send, Skill *ptrskill)
{
 	pAttack->reduceAttackDur();//减少装备耐久
	static DefenceTargetList targetList;//被攻击者列表
	targetList.clear();
	send->srcx = pAttack->getPos().x;
	send->srcy = pAttack->getPos().y;
	send->x = rev->x;
	send->y = rev->y;

	bool isMiss = false;
	addAttackTargetList(pAttack, rev, ptrskill,  targetList);//搜索技能范围目标到被攻击者列表
        ReflectorMap refMap;//反伤对象容器
        
        if(ptrskill->base->id == 605201)
	{
		if(pAttack->getType() == SceneObject_Player)
		{
			dealMagicComboHurt(pAttack, ptrskill,targetList,  send);//计算连击的伤害和防护值
		}
	}
        else
       {
          dealMagicMultiHurt(pAttack, ptrskill,targetList,  send, refMap, isMiss);//计算施法的伤害和防护值
       }
		
       send->retCode = MSG::RETURN_CODE_SUCCEED;

       pAttack->sendmsgToNine(send,send->getsize());

	if(send->size)
	{
		if(ptrskill->base->id != 605201)
		{
			handleFightState(send, pAttack, ptrskill,refMap);//加入技能状态
		}
		//处理伤害
		handleAttackHurt(send, pAttack);
		
		//处理反伤害
		handleReflectHurt(pAttack,send,refMap);
		
		//玩家主动攻击有一定概率获得瞬间满血
	   if(pAttack->getType() == SceneObject_Player && !isMiss)
	   {
		((scene_player*)pAttack)->randomFull();
	   }
	}
}


(3)技能对象对防御者产生作用

void SkillManager::putSkill(Skill *skill,scene_pk_object *pDefend)
{
	if(!skill)
	{
		return;
	}
	//在作用对象为死亡的状态下
	if(pDefend && pDefend->getEntryState() == SceneObject_Death)
	{
		return;
	}
	 if(pDefend->getType() != SceneObject_NPC && pDefend->getType() != SceneObject_Player)
	{
		return;
	}
	
	Touch_State_Vector::const_iterator biter1 = skill->base->statelist.begin();//技能携带的技能状态
	for(; biter1 != skill->base->statelist.end(); ++biter1)
	{
		const int &state = *biter1;
		const SkillStateB *base  = skillStateBm::get_instance().get(state);
		if(base)
		{
		  const Element_Value_Vector &elementlist = base->getElementListByLevel(skill->level);
			for(uint32 i = 0; i < elementlist.size(); i++)
			{
				const ElementValue& value = elementlist[i];
				if(value.id == StateValueType_AddPhysicsHurtValue ||value.id == StateValueType_AddMagicHurtValue)//技能状态的效果id
				{
					continue;//物理伤害和魔法伤害已经直接读取系数,这里不需状态
				}
				pDefend->statem->addState(value,owner,0,base->save_die,base->save_offline,base->run_offline,base->unlimited);//对防御者添加伤害状态
				 
			}
		}
	}
}

(4)添加技能状态到技能状态管理器

添加技能状态到技能状态管理器

bool StateManager::addState(const ElementValue& value, scene_pk_object *pAtt,uint32 ltime,bool save_die,bool save_offline,bool run_offline,bool unlimited)
{
	if(!pAtt)
	{
		return false;
	}
    if(pAtt->getType() != SceneObject_Player && pAtt->getType() != SceneObject_NPC)
    {
        return false;
    }
	uint32 rate = (uint32)nMisc::randBetween(0, 100);
	if(rate > value.effect)//按概率生效技能效果
	{
		return false;
	}
	StateObject *object = new StateObject(pAtt, value,save_die,save_offline,run_offline,unlimited);


	if(!object)
	{
		return false;
	}

	POINT_DEBUG_INFO(info,"NP--%s-技能状态%p",_owner->name,object);
	if(ltime)
	{
		object->run.time = ltime;
	}
    	//计算技能影响的属性值,计算出来的结果保存在ElementValue(技能状态元素信息)的parm3中.(在运行技能状态定时器时会运行该技能状态,这里只是计算增加点数)
	effectStateProperty(object);
	if(!addState(object))
	{
		return false;
	}


	return true;
}


添加技能状态对象到技能状态管理器

bool StateManager::addState(StateObject *object)
{
	uint32 notify = 0;
	StateObject_map::iterator it = _state_map.begin();
	for(;it != _state_map.end() ; ++it)
	{
		if((*it)->isMultiExpState())
		{
			continue;
		}
		if((*it)->run.id == object->run.id)
		{
			break;
		}
	}

	//如果没有相同技能效果id的新效果, 就加入新的技能效果
	if(it == _state_map.end())
	{
		notify |= runState(object);
		object->id = this->id++;
		_state_map.push_back(object);
		setStateToBuf(object);
		setNineStateToIndex(object);
		loadIco(object);
		StateManager::freshAll(_owner,notify);
		return true;
	}

	StateObject *old = *it;
	if(old->bDelete == true)
	{
		return true;
	}

	//处理技能效果id相同

        //可以叠加技能效果
	if(old->run.num < old->element.maxnum)//叠加次数小于最大叠加次数
	{
		//按照技能替换规则比较,如果newOjbect与oldObject效果id相同,且比oldObject优则返回true
		if(compareState(object,old))
		{
			//技能效果比较较优的情况下,删除旧的技能状态并加入新的技能状态
			old->run.step = MSG::STATESTEP_UNLOAD;
			runState(old);
			object->id = this->id++;
     			_state_map.push_back(object);
     			old->bDelete = true;
			notify |= runState(object);
			loadIco(object);
			freshAll(_owner,notify);
			return true;
		}
		//直接在老技能状态叠加上去 删除新的技能状态
        	old->run.step = MSG::STATESTEP_UNLOAD;
		notify |= runState(old);
		old->run.num += 1;
        	if(object->run.id == StateValueType_RecoveryHp || object->run.id == StateValueType_RecoveryMp)
        	{
            		old->run.time += object->run.time;//加载技能时间
            		old->run.num = 1;
        	}
        	else
        	{
            		old->element.parm3 += object->element.parm3;//叠加技能点
        	}
        	old->run.attacker = object->run.attacker;//施法者标识
		old->run.step = MSG::STATESTEP_LOAD;
		POINT_DEBUG_INFO(info,"DP--%s-技能状态%p", _owner->name,object);
		SAFE_DELETE(object);
		notify |= runState(old);
		loadIco(old);
		freshAll(_owner,notify);//刷新到前端
		return true;
	}
	else if(old->element.maxnum == 1)//最大叠加次数为1(不能叠加技能效果)
	{
		按照技能替换规则比较,如果newOjbect与oldObject效果id相同,且比oldObject优则返回true
		if(compareState(object,old))
		{
			//删除老的技能状态 加载新的技能状态
			old->run.step = MSG::STATESTEP_UNLOAD;
			runState(old);
			object->id = this->id++;
			_state_map.push_back(object);
			old->bDelete =  true;
			notify |= runState(object);
			loadIco(object);
			freshAll(_owner,notify);
			return true;
		}
	}
	return false;
}


6、范围检查
(1)技能的组队范围检查

void scene_team::checkTeamAttckRange( scene_player* pUser,Skill* pSkill, MSG::stRetAttackMagicUserCmd* pSend ,bool isFind)
{
	if(pUser->getState() == SceneObject_Death)
	{
		return;
	}
	for (std::set<uint32>::iterator it = playerIdSet.begin();
		it != playerIdSet.end();
		++it)
	{
		scene_player *pOhterUser = g_player_mgr.get_player_by_id(*it);
		if (pOhterUser)
		{
			if (pUser->scene == pOhterUser->scene)
			{
				if(pSkill->checkRange(pUser->getPos(), pOhterUser->getPos(), 3))
				{
					if (!isFind)//这个标志没有具体意义,只是为了区分ScenePk.cpp两个调用
					{
						MSG::stRetDefenceList *defendlist = NULL;
						defendlist = (MSG::stRetDefenceList*)&pSend->data[pSend->size];
						defendlist->dwDefencerID = pOhterUser->id;
						defendlist->byEntryType = pOhterUser->getType();
						defendlist->dwHp = 0;
						defendlist->byState = 0;
						defendlist->hurtType = 0;
						pSend->size++;
						pUser->skillm.putSkill(pSkill,pOhterUser);//对对方作用技能,添加技能状态到对方技能状态管理器
					}
					else
					{
						pUser->skillm.putSkill(pSkill,pOhterUser);

						MSG::stRetDefenceList *defendlist = NULL;
						defendlist = (MSG::stRetDefenceList*)&pSend->data[pSend->size];
						defendlist->dwDefencerID = pOhterUser->id;
						defendlist->byEntryType = pOhterUser->getType();
						pSkill->getSkillValue(pOhterUser,defendlist->dwHp,defendlist->hurtType);
						//defendlist->dwHp = 0;
						defendlist->dwSd = 0;
						defendlist->byState = 0;
						//defendlist->hurtType = 0;
						pSend->size++;
					}
				}
			}
		}
	}
}


(2)技能释放几何范围搜索

/**
 * \author 
 * \description 技能释放几何范围
 */
//1单2 自己圆3鼠标点圆4扇5线
enum SkillRangeType
{
    SKILLRANGETYPE_SINGLE = 1,  /**< 单 */
    SKILLRANGETYPE_ONESELF= 2, /**< 自己圆 r*/
    SKILLRANGETYPE_CURSOR = 3, /**< 鼠标点圆 */
    SKILLRANGETYPE_SECTOR = 4, /**< 扇*/
    SKILLRANGETYPE_LINE = 5, /**< 线*/
    SKILLRANGETYPE_MAX
};

检查被攻击者,搜索攻击范围

bool ScenePk::addAttackTargetList(scene_pk_object *pAttack, const MSG::stAttackMagicUserCmd *rev,Skill *skill, DefenceTargetList &defendList)
{
	// 保存连击座标
	if(skill && pAttack && SceneObject_Player == pAttack->getType())
	{

		switch(skill->base->range)
		{
		case MSG::SKILLRANGETYPE_SINGLE:
		case MSG::SKILLRANGETYPE_ONESELF:
		case MSG::SKILLRANGETYPE_LINE:
		case MSG::SKILLRANGETYPE_SECTOR:
			{//保存连击座标
				((scene_player*)pAttack)->addComboAttckPos(pAttack->getPos().x, pAttack->getPos().y, skill->base->id);
			}
			break;
		case MSG::SKILLRANGETYPE_CURSOR:
			{
				((scene_player*)pAttack)->addComboAttckPos(rev->x, rev->y, skill->base->id);
			}
			break;
		}
	}
  uint16 flags = 0;
  if(pAttack->getType() == SceneObject_Player)
  {
      scene_player* pAtt = (scene_player*)pAttack;
      if(pAtt->getPkMode() == MSG::PKMODE_NORMAL)//普通模式只攻击npc
      {
          SetBit(flags,SceneObject_NPC);
      }
      else//其他模式攻击角色和npc
      {
          SetBit(flags,SceneObject_Player);
          SetBit(flags,SceneObject_NPC);
      }
  }
  else if(pAttack->getType() == SceneObject_NPC)//优化怪物攻击,不再搜索怪物
  {
      SetBit(flags,SceneObject_Player);
  }
	
	switch(skill->base->range)//攻击范围
	{
		case MSG::SKILLRANGETYPE_SINGLE:   //单体攻击
		{
			scene_pk_object *pDefend = getPKObjectByEntryType(rev->defencerID,rev->defenderType);
			if(pDefend && skill->checkRange(pAttack->getPos(),pDefend->getPos(),skill->base->distance))
			{
				defendList.push_back(pDefend);
			}
			return true;
		}
		break;
		case MSG::SKILLRANGETYPE_ONESELF:  //自己圆
		{
			pAttack->scene->searchRoundScreenRange(nPos(pAttack->getPos().x, pAttack->getPos().y),skill->base->radius,defendList,flags);

			if(defendList.empty())
			{
				return false;
			}
			return true;
		}
		break;
		case MSG::SKILLRANGETYPE_CURSOR: //鼠标圆
		{
		//	pAttack->scene->searchEntryRound(nPos(rev->x, rev->y), skill->base->radius, pAttack->getCamp(), *defendList);
			pAttack->scene->searchRoundScreenRange(nPos(rev->x, rev->y),skill->base->radius,defendList,flags);
			if(defendList.empty())
			{
				return false;
			}
			return true;
		}
		break;
		case MSG::SKILLRANGETYPE_SECTOR://扇形
		{
			//pAttack->scene->searchEntrySector(pAttack->getPos(),rev->direct, skill->base->radius, skill->base->angle, pAttack->getCamp(), *defendList);
                        pAttack->scene->searchSectorScreenRange(pAttack->getPos(), skill->base->radius, skill->base->angle,rev->direct,  defendList,flags);
			if(defendList.empty())
			{
				return false;
			}
			return true;
		}
		break;
		case MSG::SKILLRANGETYPE_LINE://直线,鼠标点方
		{
			pAttack->scene->searchEntryLine(nPos(pAttack->getPos().x, pAttack->getPos().y), nPos(rev->x, rev->y),skill->base->distance, defendList,flags);
			if(defendList.empty())
			{
				return false;
			}
			return true;
		}
		break;
	default:
		break;
	}
	return true;
}

检查范围:
(2-1)某点为中心的圆的范围

void Scene::searchRoundScreenRange(const nPos& center,const uint16 r, DefenceTargetList &targetVec,const uint16 flags)
{
	SearchPlayerMonsterPosExec exec(center, r, targetVec);
	const screen_vector &pv = getScreenByRange(center, r + 5);

    	screen_vector::const_iterator iter = pv.begin();
    	screen_vector::const_iterator iter_end = pv.end();
	for(; iter != iter_end; ++iter)
	{
        if(GetBit(flags,SceneObject_Player))
        {
		    execAllOfScreen(SceneObject_Player, *iter, exec);//遍历屏上的所有的玩家
        }
        if(GetBit(flags,SceneObject_NPC))
        {
		    execAllOfScreen(SceneObject_NPC, *iter, exec);//遍历屏上的所有的npc
        }
	}
}

遍历屏上的对象,获取范围内对象

struct SearchPlayerMonsterPosExec : public callback<SceneEntry>
{
	const nPos& _center;
	const uint16& _range;
	DefenceTargetList &_targetVec;
	SearchPlayerMonsterPosExec(const nPos& center, const uint16& range, DefenceTargetList& targetVec)
		:_center(center), _range(range), _targetVec(targetVec)
	{
	//	_targetVec.reserve(9 * SCREEN_GRID_WIDTH * SCREEN_GRID_HEIGHT);
	}

	bool invoke(SceneEntry *entry)
	{
	if(entry == NULL)
	{
		return false;
	}
        scene_pk_object *pkEntry = NULL;
	if(entry->getType() == SceneObject_NPC)
	{
		pkEntry = getPKObjectByEntryType(entry->tempid, SceneObject_NPC);
	}
        else if(entry->getType() == SceneObject_Player)
	{
		pkEntry = getPKObjectByEntryType(entry->id, SceneObject_Player);
	}
        if(!pkEntry)
        {
            return false;
        }
        
        uint16 distance = nGraphAlgo::getDistance(_center, pkEntry->getPos());
        if(distance <= _range)
        {
            _targetVec.push_back(pkEntry);
            return true;
        }
		return false;
	}
};

(2-2)搜索扇形范围

void Scene::searchSectorScreenRange(const nPos& center, const uint16& range,const uint16& angle ,const uint16& dir, DefenceTargetList& targetVec, const uint16 flags)
{
   if(range < 1 || angle == 180)
  {
      return;
  }
  SearchSectorPosExec exec(center, range,angle,dir ,targetVec);//检查中心点,半径、角度、方向的回调
  
  const screen_vector &pv = getScreenByRange(center, range + 5);//获取九屏,条件是偏移5格子内

  screen_vector::const_iterator iter = pv.begin();
  screen_vector::const_iterator iter_end = pv.end();
  for(; iter != iter_end; ++iter)
 {
    if(GetBit(flags,SceneObject_Player))
    {
       execAllOfScreen(SceneObject_Player, *iter, exec);
    }
    if(GetBit(flags,SceneObject_NPC))
    {
       execAllOfScreen(SceneObject_NPC, *iter, exec);
    }
   }
}

在扇形区域搜索目标,先检查最大长度,再按客户端发来的方向角度上检查技能的范围上的npc或玩家

//在扇形区域搜索目标
struct SearchSectorPosExec : public callback<SceneEntry>
{
	const nPos& _center;
	const uint16& _range;
	const uint16& _angle;
	const uint16& _dir;
	DefenceTargetList &_targetVec;
	int abs_x;
	int abs_y;
	uint16 range_pow2;
 	double angle_tan;//dir = up,right,down,left时使用的tan(*)值
	double angle_tan_less;//dir = up_right,down_right,down_left,up_left && _angle <= 90度时使用的tan(*)
 	double angle_tan_more;//dir = up_right,down_right,down_left,up_left && _angle > 90度时使用的tan(*)
	scene_pk_object *_exinclude;
	SearchSectorPosExec(const nPos& center, const uint16& range,const uint16& angle ,const uint16& dir,DefenceTargetList& targetVec)
		:_center(center), _range(range),_angle(angle), _dir(dir),_targetVec(targetVec),abs_x(0),abs_y(0)
	{
           range_pow2 = _range * _range;
           angle_tan = tan(_angle * PI / 360);
           angle_tan_less = tan((45 - _angle/2)*PI/180);
           angle_tan_more = tan((_angle/2 - 45)*PI/180);
	}

	bool invoke(SceneEntry *entry)
	{
		if(entry == NULL)
		{
			return false;
		}
        	scene_pk_object *pkEntry = NULL;
		if(entry->getType() == SceneObject_NPC)
		{
			pkEntry = getPKObjectByEntryType(entry->tempid, SceneObject_NPC);
    }
    else if(entry->getType() == SceneObject_Player)
    {
        pkEntry = getPKObjectByEntryType(entry->id, SceneObject_Player);
    }
		if(! pkEntry)
		{
			return false;
		}

	  const nPos &pos = pkEntry->getPos();
	  //int abs_x = 0,abs_y = 0;
	  abs_x = abs(_center.x - pos.x);
	  abs_y = abs(_center.y - pos.y);
	
	  //uint16 distance = nGraphAlgo::getDistance(_center, pos);
		if((abs_x*abs_x+abs_y*abs_y) > range_pow2)
		{
			return false;
		}
	  else if (abs_x == 0 && abs_y == 0)
	  {
	      _targetVec.push_back(pkEntry);
	      return true;
	  }
	  
	  if(_dir % 2==0)//dir = up,right,down,left
		{
			//angle_tan = tan(_angle * PI / 360);
      if((_dir == _DIR_UP && pos.y <= _center.y) || (_dir == _DIR_DOWN && pos.y >= _center.y))
      {
    			if(angle_tan * abs_y - abs_x >= 0)
          {
              _targetVec.push_back(pkEntry);
              return true;
          }
      }
      else if((_dir == _DIR_RIGHT && pos.x >= _center.x) || (_dir == _DIR_LEFT && pos.x <= _center.x))
      {
          if(angle_tan * abs_x - abs_y >= 0)
          {
              _targetVec.push_back(pkEntry);
              return true;
          }
      }
		}
		else    //dir = up_right,down_right,down_left,up_left
		{
                   if(_angle/2 <= 45)
		   {
        //angle_tan = tan((45 - _angle/2)*PI/180);
        if(abs_x >= (abs_y * angle_tan_less) && abs_y >= (abs_y * angle_tan_less))
        {
            if(_dir == _DIR_DOWNRIGHT && pos.x >= _center.x && pos.y >= _center.y)
            {
                _targetVec.push_back(pkEntry);
                return true;
            }
            else if(_dir == _DIR_UPRIGHT && pos.x >= _center.x && pos.y <= _center.y)
            {
                _targetVec.push_back(pkEntry);
                return true;
            }
            else if(_dir == _DIR_UPLEFT && pos.x <= _center.x && pos.y <= _center.y)
            {
                _targetVec.push_back(pkEntry);
                return true;
            }
            else if(_dir == _DIR_DOWNLEFT && pos.x <= _center.x && pos.y >= _center.y)
            {
                _targetVec.push_back(pkEntry);
                return true;
            }
        }
    }
    else if(_angle/2 > 45)
    {
        //angle_tan = tan((_angle/2 - 45)*PI/180);
        if(_dir == _DIR_DOWNRIGHT)
        {
            if(pos.x >= _center.x && pos.y >= _center.y)
            {
                _targetVec.push_back(pkEntry);
                return true;
            }
            else if(pos.y > _center.y && abs_x <= (abs_y * angle_tan_more))
            {
                _targetVec.push_back(pkEntry);
                return true;
            }
            else if(pos.x > _center.x && abs_y <= (abs_y * angle_tan_more))
            {
                _targetVec.push_back(pkEntry);
                return true;
            }
        }
        else if(_dir == _DIR_UPRIGHT)
        {
            if(pos.x >= _center.x && pos.y <= _center.y)
            {
                _targetVec.push_back(pkEntry);
                return true;
            }
            else if(pos.y > _center.y && abs_y <= (abs_x * angle_tan_more))
            {
                _targetVec.push_back(pkEntry);
                return true;
            }
            else if(pos.x < _center.x && abs_x <= (abs_y * angle_tan_more))
            {
                _targetVec.push_back(pkEntry);
                return true;
            }
        }
        else if(_dir == _DIR_UPLEFT)
        {
            if(pos.x <= _center.x && pos.y <= _center.y)
            {
                _targetVec.push_back(pkEntry);
                return true;
            }
            else if(pos.x > _center.x && abs_x <= (abs_y * angle_tan_more))
            {
                _targetVec.push_back(pkEntry);
                return true;
            }
            else if(pos.y > _center.y && abs_y <= (abs_x * angle_tan_more))
            {
                _targetVec.push_back(pkEntry);
                return true;
            }
        }
        else if(_dir == _DIR_DOWNLEFT)
        {
            if(pos.x <= _center.x && pos.y >= _center.y)
            {
                _targetVec.push_back(pkEntry);
                return true;
            }
            else if(pos.x > _center.x && abs_x <= (abs_y * angle_tan_more))
            {
                _targetVec.push_back(pkEntry);
                return true;
            }
            else if(pos.y < _center.y && abs_x <= (abs_x * angle_tan_more))
            {
                _targetVec.push_back(pkEntry);
                return true;
            }
        }
    }
	}
  return false;
}

场景实体搜索可以参考:

http://blog.csdn.net/chenjiayi_yun/article/details/26476517



7、技能状态对象

技能状态对象

struct StateObject:public nMemoryAlloc//使用内存池
{
	StateRunAttr run;	/**状态属性*/
	uint32 	offline;	/**停止时间*/
	uint32	starttime;	/**开始时间*/

	ElementValue element;	/*技能状态元素信息 **/
	bool         bDelete;
	uint32       id;

	StateObject();

	StateObject(scene_pk_object *pAtt, const ElementValue& base,bool save_die,bool save_offline,bool run_offline,bool unlimited);

	StateObject(StateObject &object);

	~StateObject();

	scene_pk_object *getAttacker();
        /**
	 * \brief 判断需要序列化
	 */
	bool isNeedSerialize();
	/**
	 * \brief 判断是非卸载状态
	 */
	bool isValid()const;
	/**
	 * \brief 判断是否是卸载状态
	 */
	bool isWaitDel()const;
	/**
	 * \brief 判断是否是暂停状态
	 */
    	bool isPause()const;
	/**
	 * \brief 是多倍
	 */
    	bool isMultiExpState();
	/**
	 * \brief 序列化
	 */
	const uint32 serialize(char *out);
	/**
	 * \brief 反序列化
	 */
	const uint32 unSerialize(const char *in,const uint32 version);
};



技能状态元素

struct ElementValue
{
	uint16  id;
	uint32  lasttime;	//持续时间
	uint16  cd;			//cd间隔
        uint16  effect;     //效果号生效概率
	uint16  maxnum;		//最大叠加层数
	uint16  parm1;		//策划配置动态参数1
	uint16  parm2;		//策划配置动态参数2
        uint32  parm3;      //增加点数,这个参数在加载技能中使用到


	ElementValue():id(0),lasttime(0),cd(0),effect(0),maxnum(0),parm1(0),parm2(0),parm3(0)
	{
	}
    ElementValue(const ElementValue &value)
    {
        id = value.id;
        lasttime = value.lasttime;
        cd = value.cd;
        effect = value.effect;
        maxnum = value.maxnum;
        parm1 = value.parm1;
        parm2 = value.parm2;
        parm3 = value.parm3;
    }
    inline void copy(const ElementValue &value)
    {
        id = value.id;
        lasttime = value.lasttime;
        cd = value.cd;
        effect = value.effect;
        maxnum = value.maxnum;
        parm1 = value.parm1;
        parm2 = value.parm2;
        parm3 = value.parm3;
    }
};



状态属性

struct StateRunAttr
{
	StateRunAttr()
	{
		bzero(this,sizeof(*this));
	}
	uint16	id;		/**状态编号*/
	uint16	level;		/**状态等级*/
	uint16	num;		/**当前叠加的次数*/
	uint32	time;		/**持续时间*/
	uint8	step; 		/**状态执行的步骤*/
	uint32	attacker;	/**状态投送者编号*/
	uint8	type;     		/**状态投送者类型*/
	bool 	pause;    		/**状态暂停标志*/
	bool    save_die;   	/* *死亡保留状态*/
	bool    save_offline;  	/* *下线存档状态*/
	bool    run_offline;    	/* *下线后状态继续倒计时*/
	bool    unlimited; 	//不限时间
};



8、技能状态管理器

技能状态管理器管理作为pk对象的成员而存在,管理该pk对象的所有的技能状态的运行、删除、序列化、刷新到前端。

class StateManager
{
public :
	StateManager(scene_pk_object *owner);
	 
	~StateManager();
	 
	typedef vector<StateObject *> RemoveObject_vector;
public:
	//刷新角色属性到前端
	static void freshAll(scene_pk_object *_owner,const uint32 notify);
	//序列化
	const uint32 serialize(char *out);
	//反序列化
	void unSerialize(const SerializeBinaryMember *in,const uint32 version);
	//删除所有技能状态
	void deleteAll();
	//删除状态
	void deleteStateObject(StateObject * pObject);
	//获取技能状态
	StateObject *getState(const uint16 id);
	//运行状态函数(装载状态、重新装载状态、定时器状态、卸载状态)( 增减属性并同步到前端)
	uint32 runState(StateObject *object);
	//技能状态循环(删除技能状态删除列表里的技能状态对象)
	void loop();
	//定时运行所有状态对象(runState)
	void stateTimer();
	//发送所有技能状态到前端
	void loadAllIco();
	//发送新技能状态到前端
	void loadIco(const StateObject *object);
	//发送取消技能状态到前端
	void unloadIco(const StateObject *object);
	/* *
	* \brief 暂停状态
	* */
	void pauseState(StateObject *object);
	/* *
	* \brief 重启状态
	* */
	void restartState(StateObject *object);
	
        void execEveryState(callback<StateObject> &ee);
	/* *
	* \brief 人物死亡状态下把受死亡影响的状态设置为待删除状态
	* */
	void waitToDel();

	bool addState(StateObject *object);
        /* *
           * 添加技能状态
         * */
	bool addState(const ElementValue& value, scene_pk_object *pAtt, uint32 ltime=0,bool save_die=false,bool save_offline=false,bool run_offline=true,bool unlimited=false);

	bool issetState(const uint16 state) const;
 	//初始化技能状态管理器(状态函数)
	static void initall();
  /**
	 * \brief 比较两个StateObject,根据比较规则决定返回值,
	 * \object1和object2必须是同种类型的StateObject,即run.id相等,否则直接返回false
	 * \
	 * \return 若返回true则newObject点数较大,否则是oldObject,返回true则oldObject 可合并到newObject
	 */
	bool compareState(StateObject* newObject,StateObject* oldObject);
	/* *
	 * \brief 计算技能影响的属性值,计算出来的结果保存在ElementValue的parm3中
	 * */
	void effectStateProperty(StateObject* object);
private :
	//设置技能状态id按位设置到缓存(方便访问)
	void setStateToBuf(const StateObject *object);
	void clearStateToBuf(const StateObject *object);

	void setNineStateToIndex(const StateObject *object);

	void clearNineStateToIndex(const StateObject *object);
     
public :

	typedef const uint32 (* Func)(scene_pk_object *,StateObject *,ElementValue *);

	static std::vector<Func> funclist;

	scene_pk_object *_owner;

	typedef std::set<StateObject*> StateObjectDel_Set;
	typedef vector<StateObject*> StateObject_map;
	typedef StateObject_map::iterator StateObject_iterator;
	typedef StateObject_map::const_iterator StateObject_const_iterator;
	typedef std::list<uint16> zListNineState;

	typedef zListNineState::iterator zListNineState_iter;

	StateObject_map	_state_map;
	
	StateObjectDel_Set _state_del;

	uint8 _state_buf[(MSG::StateType_Max + 7) / 8];

	zListNineState _nine_state_index;
	RemoveObject_vector _remove_vector;

	uint32 _profession;
public:
  const StateObject_map& getStateObjectVec()const;
};

9、技能状态管理器定时器

在角色循环和npc循环里会定时运行技能状态机管理器定时器。

技能状态机管理器定时器,遍历所有技能状态对象,删除失效技能状态对象,运行技能状态对象,刷新角色属性到前端。

// 技能状态机管理器定时器
void StateManager::stateTimer() 
{
	uint32 notify = 0;
	StateObject_map::iterator iter = _state_map.begin();
	StateObject_map::iterator iter_end = _state_map.end();

	for(; iter != iter_end;)
       {
		StateObject_map::iterator ittemp = iter;
		++iter;
		StateObject *object = *ittemp;
		if(object == NULL)
		{
			continue;
		}

		if(object->run.pause)//暂停的不执行
		{
			continue;
		}

		if(object->isWaitDel()) //技能状态对象已失效
		{
			notify |= removeState(object);//移除技能状态对象
			continue;
		}

		if(object->run.num == 0)//技能状态对象的叠加数为0
		{
			notify |= removeState(object);
			continue;
		}

		if(object->run.time == 0)//技能状态对象时间到时
		{
			notify |= removeState(object);
			continue;
		}

		notify |= runState(object);//运行技能状态对象
		if(!object->run.unlimited)//无限时间的BUFF不参加倒计时
		{
			object->run.time--;//技能状态对象时间减少
		}
       }

	StateManager::freshAll(_owner,notify);//刷新属性到前端
	waitToDel();//修改死亡对象技能状态对象的状态为卸载
}


//清除技能状态对象
uint32 StateManager::removeState(StateObject *object)
{
	uint32 notify = 0;
	if(object)
	{
		if(!object->run.pause)//没有暂停的状态要通知前端卸载BUFF图标
		{
			clearStateToBuf(object);
			clearNineStateToIndex(object);
			unloadIco(object);
			object->run.step = MSG::STATESTEP_UNLOAD;
			notify = runState(object);//运行技能状态对象
		}
		object->bDelete =  true;//标记删除技能状态对象
	}

	return notify;
}


卸载死亡对象的技能状态对象

void StateManager::waitToDel()
{
	if(_owner->getEntryState() == SceneObject_Death)
	{
		StateObject_map::iterator iter = _state_map.begin();
		for(;iter != _state_map.end();)
		{
			StateObject *object = *iter;
			if(!object->run.save_die)//死亡保存状态(如果是不需要保存的就准备卸载)
			{
				object->run.step = MSG::STATESTEP_UNLOAD;
			}
			++iter;
		}
	}
}


广播清除九屏状态
void StateManager::clearNineStateToIndex(const StateObject *object)
{
	if(object)
	{
		for(zListNineState_iter iter = _nine_state_index.begin() ; iter != _nine_state_index.end(); ++iter)
		{
			if(*iter == object->run.id)
			{
				_nine_state_index.erase(iter); //需要广播九屏的技能状态id列表
				MSG::stClearStateMapScreenUserCmd send;
				if(_owner->getType() == SceneObject_Player)
				{
					send.dwTempID = _owner->id;
				}
				else if(_owner->getType() == SceneObject_NPC)
				{
					send.dwTempID = _owner->tempid;
				}
				send.type = _owner->getType();
				send.dwState = object->run.id;
				_owner->sendmsgToNine(&send,sizeof(send));//广播到九屏

				return;
			}
		}
	}
}

清除技能状态

void StateManager::clearStateToBuf(const StateObject *object)
{
	if(object)
	{
		clear_state(_state_buf,object->run.id);
	}
}


/// 清除某个技能状态(技能状态buff数组,技能状态id)
inline void clear_state(uint8 *state, uint32 stateid)
{
	state[stateid/ 8] &= (0xff & (~(1 << (stateid % 8))));//按位清除
}


技能状态buff

uint8 _state_buf[(MSG::StateType_Max + 7) / 8];//按位计算技能状态是否存在


角色循环运行技能状态定时器

//角色循环
bool scene_player::loop()
{
	...
	if(_one_sec(main_logic_thread::currentTime))
	{
		// 运行人物状态机
		{
			this->statem->loop();//技能状态管理器循环(删除技能状态删除列表的对象)
			this->statem->stateTimer();//运行技能状态管理器定时器
		}
		...
	}
	...
}

npc循环运行技能状态定时器
//npc循环
bool scene_npc::loop()
{
		const SceneObjectState &state = getEntryState();
		if(state == SceneObject_Normal)//npc正常状态
		{
			if (AIC)
			{
				if(this->base->npcType == MSG::NpcType_Gun)
				{
					gunAction();
				}
				else
				{
					AIC->processPhase();
					normalAction();
				}
			}

			if(_one_sec(main_logic_thread::currentTime))//1秒定时器
			{
					this->statem->loop();//技能状态管理器循环(删除技能状态删除列表的对象)
					this->statem->stateTimer();//运行技能状态管理器定时器
			}
...
}

10、运行技能状态对象

运行技能状态对象的运行,会执行运行技能状态对象的函数。


// 运行状态机 对一个技能 对应多个funclist [1:N]的关系
uint32 StateManager::runState(StateObject *object)
{
	uint32 notify = 0;
	if(!object)
	{
		return notify;
	}

	if(!_owner && object->run.pause)
	{
		return notify;
	}

	ElementValue& element =	object->element;
	//运行技能状态函数
	notify |= funclist.at(element.id > MAX_ELEMENT_ID ? 0 : element.id)(_owner,object,&element);

	if(object->run.step == MSG::STATESTEP_LOAD)//技能状态转换成定时器状态
	{
		object->run.step = MSG::STATESTEP_TIMER;
	}
	else if(object->run.step == MSG::STATESTEP_RELOAD)
	{
		object->run.step = MSG::STATESTEP_TIMER;
		loadIco(object);//通知前端重新加载了该技能状态
	}
	return notify;
}


根据技能状态的技能元素的id来索引技能状态函数(表驱动法),运行技能状态函数。


11、技能状态函数

技能状态函数的有多个状态(状态加载STATESTEP_LOAD、状态解档加载STATESTEP_RELOAD、状态轮训STATESTEP_TIMER、状态卸载   STATESTEP_UNLOAD),在不同状态下有不同功能。

技能状态函数数量较多,以下是其中一个

/**
 * \brief key = 3,add Hp
 */
const uint32 StateElementValue_3(scene_pk_object *owner,StateObject *object,ElementValue *evalue)
{
    switch(object->run.step)
    {
        case MSG::STATESTEP_LOAD:
            {
                if(owner && owner->getEntryState()!=SceneObject_Death)
                {
                    owner->addHp(evalue->parm1);
                    return MSG::NOTIFYTYPE_HPSD;
                }
            }
            break;
        case MSG::STATESTEP_RELOAD:     //状态解档加载
            {
。。。
            }
            break;
        case MSG::STATESTEP_UNLOAD://该状态卸载后
            {
                。。。
            }
            break;
    }
    return MSG::NOTIFYTYPE_NULL;
}




 
 
 

范围搜索(pk对象施法按一定的规则来搜索范围)

(1)羁绊范围搜索:附近组队范围(队友或自己)

(2)技能几何范围搜索(1单2 自己圆3鼠标点圆4扇5线))

参考:http://write.blog.csdn.net/postedit/26476517 几何范围搜索

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值