游戏服务器之技能

来源:互联网 发布:数据挖掘的就业前景 编辑:程序博客网 时间:2024/04/28 15:08

技能是游戏里的重要组成部分。本文说的是实时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;        //技能idchar  job[MAX_JOB_LEN];//职业限制char name[MAX_NAME_LEN];//技能名称uint32  target;//1组队   2友方 3 敌方    4 城墙    5 自己uint32 cd;//技能cduint16 range;// 1单  2自己圆    3鼠标点圆 4 扇  5  线uint16  distance;//技能攻击距离uint16 angle;//角度uint16 radius;//半径uint16 mp;//消耗mpuint16 sp;//消耗spstring   stateid;uint16   type;//默认类型[出身]  0 需要学习  1   需要装备的 2uint32   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 技能当前等级 */uint16level;/** * \brief 技能熟练点数 */uint32points;    /**     * \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 uint16getProfessionPoints(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;}//消耗   cdif(!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;//给队友加技能状态BUFFif(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优则返回trueif(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优则返回trueif(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;/**停止时间*/uint32starttime;/**开始时间*/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;//策划配置动态参数1uint16  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));}uint16id;/**状态编号*/uint16level;/**状态等级*/uint16num;/**当前叠加的次数*/uint32time;/**持续时间*/uint8step; /**状态执行的步骤*/uint32attacker;/**状态投送者编号*/uint8type;     /**状态投送者类型*/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 几何范围搜索

0 0
原创粉丝点击