/* * now, it's shit from wow. */ #pragma once #include "Target.h" class CCharacter; class UpdateObj; class CEffectBase; ////////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////// typedef int SpellID; #define INVALID_SPELL_ID SpellID(-1) enum ESpellClass { SPELL_CLS_BASE = 0, SPELL_CLS_RUSH = 1, }; enum ESpellStep { LPAS_NONE = 0, LPAS_CAST, LPAS_ATTACK, LPAS_END, }; enum SpellTargetRelative { STR_UNKNOWN =0, STR_SELF, // 自身 STR_FRIENDLY, // 友好 STR_hostile, // 敌对 STR_neutrally, // 中立 }; // 0 : 不需要选择 1: 选择对象 2: 选择区域 enum SpellSelectMethod { STT_UNKNOW = -1, STT_NONE = 0, STT_UNIT, STT_DEST_LOCATION, }; #define STC_MAPPOSITION (TYPE_AREATRIGGER << 1) enum SpellEffectSlot { SES_HEAD01 = 0, SES_HEAD02, SES_BODY, SES_FOOT, SES_WEAPON, SES_TERRAIN, }; struct SpellEffectNode : public NiMemObject { SpellEffectNode(); virtual ~SpellEffectNode(); //int AttachNode; SpellEffectSlot Slot; int ForceClearAtStageEnd; float Offset; float MaxLife; // 生命期 char Media[MAX_PATH]; virtual int GetType() const { return -1;}; }; struct SpellEffectNifNode : public SpellEffectNode { virtual int GetType() const { return 0;} float AniStartTime; INT AniLoopCnt; }; struct SpellDecalEffectNode : public SpellEffectNode { virtual int GetType() const { return 1;} BOOL FollowOnwer; float Rotate; float fRadius; }; struct SpellTrailEffectNode : public SpellEffectNode { virtual int GetType() const { return 2;} }; struct SpellProjectileEffectNode : public SpellEffectNode { virtual int GetType() const { return 3;} char ExpMedia[MAX_PATH]; }; struct SpellTargetSelDesc { int SelMethod; // 0 : 不需要选择 1: 选择对象 2: 选择区域 float SelRadius; // 如果为选择区域,则这里为区域半径 char Brush[128]; // 如果SelMethod为选择对象, 这里表示的是光标 ;若为区域,则表示DECAL 纹理. }; struct SpellApperanceDesc { bool bHideWeapon; // 武器是否需要隐藏 SpellApperanceDesc() { bHideWeapon = false; } }; struct SpellStageDescBase : public NiMemObject { inline SpellStageDescBase() { Time = 0.0f; Sound[0] = 0; Animation[0] = 0; } virtual ~SpellStageDescBase(); float Time; char Sound[MAX_PATH]; char Animation[128]; std::vector Effects; }; struct SpellCastDesc: public SpellStageDescBase { }; struct SpellAttackDesc : public SpellStageDescBase { float DamageTime; }; struct SpellDamageDesc: public SpellStageDescBase { }; class SpellDesc : public NiMemObject { public: int m_SpellId; char m_Name[128]; // 技能名称 ESpellClass m_SpellCls; char m_Icon[MAX_PATH]; char* m_LongDesc; int m_LevelLimit; // 技能级别限制 int m_Profession; // 技能职业 -1: 表示所有职业 float m_AttackRange; // 攻击距离 SpellTargetRelative m_TargetRelative; // 目标社会关系 UINT m_TargetClass; // 目标类别 int m_MPRequest; int m_HPRequest; int m_LevelRequest; SpellTargetSelDesc m_SelectionDesc; SpellApperanceDesc m_ApperanceDesc; SpellCastDesc* m_CastDesc; SpellAttackDesc* m_AttackDesc; SpellDamageDesc* m_DamageDesc; }; class SpellInstance; class SpellTemplate : public SpellDesc { public: SpellTemplate(); ~SpellTemplate(); // 创建技能实例 SpellInstance* CreateInstance(); // 检查施法者条件是否满足 BOOL CheckOwnerRequest(CCharacter* pOwner) const; // 检查目标类型是否有效 BOOL IsTargetValid(UpdateObj* pTarget) const; // 检查目标关系是否有效 BOOL IsTargetRelativeValid(UpdateObj* pAttacker, UpdateObj* pAttackee) const; // 是否需要选择目标对象 BOOL IsNeedSelectTargetObject(CCharacter* pOwner) const; // 获取选择目标方法 int GetSelectMethod() const; // 选择目标 BOOL SelectTarget(CCharacter* Caller) const; void Damage(CCharacter* Caller, CCharacter* Target); inline BOOL IsNeedCast() const { return m_CastDesc != NULL;} CEffectBase* CreateEffect(SpellEffectNode* pEffectNode) const; CEffectBase* EmitStageEffect(SYObjID TargetId, SpellEffectNode* EffectNode); protected: CEffectBase* CreateNifEffect(SpellEffectNifNode* pEffectNode) const; CEffectBase* CreateDecalEffect(SpellDecalEffectNode* pEffectNode) const; CEffectBase* CreateTrailEffect(SpellTrailEffectNode* pEffectNode) const; CEffectBase* CreateProjectileEffect(SpellProjectileEffectNode* pEffectNode) const; }; class SpellInstance : public NiMemObject { public: SpellInstance(SpellTemplate* pTemplate); virtual ~SpellInstance(); inline void SetOwner(CCharacter* Owner) { m_pOwner = Owner; } virtual BOOL IsSpellAttack() const { return TRUE; } virtual BOOL Begin(); virtual BOOL Update(DWORD dwTime); virtual void End(BOOL bInterrupted = FALSE); inline const SpellTemplate* GetTemplate() const { return m_SpellTemplate;} virtual void Go(const Target& Targets); virtual void BeginAttack(const Target& Targets); virtual void DamageTargets(const Target& Targets); enum SpellStage { SS_Nothing = 0, SS_Cast, SS_Release, }; void BeginCast(float fCastTime); BOOL UpdateCast(float fTime); void EndCast(); void CastDelay(float fDelayTime); void CastFailure(); protected: BOOL UpdateAttack(float fTime); void EndAttack(); void EmitStageEffects(const std::vector& EffectNodes); CEffectBase* EmitStageEffect(SpellEffectNode* EffectNodes); void CreateCastEffects(); void ClearCastEffects(); void CreateAttackEffect(const Target& Targets); BOOL ChangeApperance(); void RestoreApperance(); protected: CCharacter* m_pOwner; SpellTemplate* m_SpellTemplate; ESpellStep m_AttackStep; DWORD m_AttackTime; float m_fAttackStartTime; float m_fCastStartTime; float m_fCastFullTime; Target m_Targets; std::vector m_CastEffects; int m_iLastStage; bool m_bHideWeapon[2]; }; ////////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////// #if 0 struct SKILL_INFO { UINT Identity; // 技能编号 CHAR SkillName[SKILL_NAME_MAX]; // 技能名称 CHAR SkillDesc[SKILL_DESC_MAX]; // 技能描述 WORD Profession; // 职业 WORD ProfessionSpellIndex; // 职业技能索引 WORD SkillFlags; // 技能类型. WORD DamageFlags; // 伤害类型. BYTE DamageCalcMethod; // 伤害计算方式 WORD AddtiveFlags; // 附加效果 是否有buffer debuffer float AddtiveOdds; // 附加几率. BYTE HaveSpecialEffect; // 是否有特殊攻击效果 float SpecialEffectOdds; // 特殊效果几率 BYTE TargetSelectionFlag; // 目标选中标记 BYTE TargetAreaFlag; // 目标区域标记 CHAR TargetAreaDesc[SKILL_TARGETAREA_DESC_MAX]; // 区域几何参数描述 CHAR TargetSelBrush[128]; BYTE AttackTargetFlag; // 伤害范围: 单体 或者 区域 BYTE AttackAreaFlag; // 伤害区域标记 CHAR AttackAreaDesc[SKILL_TARGETAREA_DESC_MAX]; // 区域几何参数描述 BYTE TargetObjectClass; // 伤害目标类型. 人, 怪物 BYTE TargetObjectRelative; // 伤害目标关系 . 敌 友 float MaxRange; // 最大施法距离 UINT HPCost; UINT MPCost; UINT XXCost; float PrepareTime; // 准备时间 S. WORD PrepareBrokenCondition; // 吟唱打断方式 float ReleaseFreezeTime; // 释放/攻击后的僵直时间 float FreezeTime; // 技能冷却时间. BYTE DiscontinuousAttacking; // 间断攻击(持续施法) WORD DiscontAttackBrokenCondition; // 间断攻击打断方式 WORD DiscontAttackLoopNum; // 间断攻击循环次数 DWORD DiscontAttackCycle; // 间断攻击周期 ms UINT Faction; // 派别 UINT LevelReq; // 等级 UINT Weapon; // 武器 CHAR Icon[128]; // 技能图标 CHAR PrepareAnim[128]; // 吟唱动作 CHAR PrepareEffect[128]; // 吟唱特效 CHAR ReleaseAnim[128]; // 释放/攻击动作 CHAR ReleaseEffect[128]; // 释放/攻击特效 float ReleaseEffectLife; // 释放特效播放时间 //BYTE NumReleaseSerial; CHAR TrackAnim[128]; // 轨迹动作 CHAR HitAnim[128]; // 被击动作 CHAR HitEffect[128]; // 被击特效 float ReleaseAngle; // 释放角度 BOOL Valid; // 是否有效 }; class SkillData : public NiMemObject { public: SkillData(){} virtual ~SkillData(){} }; // 我想还是用数据驱动好了, 尽量减少派生, 除非是特殊技能. class CSkill { public: CSkill(SpellID TypeID); virtual ~CSkill(void); // 是否为状态代理,如果是,则会完全代理SkillState来进行处理. Proxy** 方法会被调用。 否则,永不调用. virtual BOOL IsStateProxy() const { return FALSE; } // 处理本地玩家开始攻击的操作行为. virtual BOOL LocalBeginAttack(CPlayer* LocalPlayer); // 是否为目标对象技能, 否则为范围技能. //virtual BOOL IsTargetSkill() const; virtual SpellID GetType() const { return (SpellID)m_Info.Identity;} public: inline WORD GetProfession() const { return m_Info.Profession; } inline WORD GetProfessionIndex() const { return m_Info.ProfessionSpellIndex; } inline float GetAttackMaxRange() const { return m_Info.MaxRange; } inline const char* GetPrepareAnim() const { return m_Info.PrepareAnim;} inline DWORD GetPrepareTime() const { return m_PrepareTime;} inline UINT GetTargetType() const { return m_Info.TargetSelectionFlag;} BOOL CanMoveWhenPrepareing() const; BOOL CanMoveWhenAttacking() const; inline DWORD GetAttackFreezeTime() const { return (DWORD)(m_Info.ReleaseFreezeTime*1000);} inline const char* GetAttackAnim() const { return m_Info.ReleaseAnim; } // Data virtual BOOL IsNeedSelectTargetObject(CPlayer* LocalPlayer) const; // 技能是否需要准备,吟唱/蓄力. virtual BOOL IsNeedPrepareAttack() const; BOOL ReleaseAttack(CCharacter* Caller, DWORD TimeOffset); BOOL CheckCondition(CCharacter* Caller) const; virtual BOOL SelectTarget(CCharacter* Caller); virtual CEffectBase* CreatePrepareEffect(CCharacter* Caller); virtual CEffectBase* CreateReleaseEffect(CCharacter* Caller); virtual void ClearReleaseEffect(CCharacter* Caller) {} virtual void UpdateReleaseEffect(CCharacter* Caller, DWORD Tick) {} virtual CEffectBase* CreateProjectileReleaseEffect(CCharacter* Caller); virtual CEffectBase* CreateDamageEffect(CCharacter* Caller, CCharacter* Target); virtual void EndSkill(CCharacter* Caller){} public: virtual BOOL ProxyStart(IStateActor* Owner, DWORD CurTime){ return TRUE;} virtual EStateProcessResult ProxyProcess(IStateActor* Owner, DWORD dwTick){ return SPR_END;} virtual BOOL ProxyEnd(IStateActor* Owner, DWORD CurTime){return TRUE;} protected: SKILL_INFO m_Info; DWORD m_PrepareTime; DWORD m_ReleaseTime; float m_fTargetAreaParam0; float m_fTargetAreaParam1; BOOL m_bContinuingRelease; // 是否持续释放攻击 BOOL m_bResetSkillWhenEnd; // 是否重置技能ID. }; // 火球 class Skill_FireBall : public CSkill { virtual CEffectBase* CreateReleaseEffect(CCharacter* Caller); public: Skill_FireBall(SpellID TypeID):CSkill(TypeID) { } }; // 鬼斩 class Skill_CutOfHost : public CSkill { virtual CEffectBase* CreateReleaseEffect(CCharacter* Caller); virtual void ClearReleaseEffect(CCharacter* Caller); virtual void UpdateReleaseEffect(CCharacter* Caller, DWORD Tick); public: Skill_CutOfHost(SpellID TypeID):CSkill(TypeID) { } }; // 吸取MP class Skill_SuckMP : public CSkill { virtual CEffectBase* CreateReleaseEffect(CCharacter* Caller); virtual void ClearReleaseEffect(CCharacter* Caller); virtual void UpdateReleaseEffect(CCharacter* Caller, DWORD Tick); public: Skill_SuckMP(SpellID TypeID):CSkill(TypeID) { } }; // 单目标肉搏技能基类 class Skill_Melee_Single_Base : public CSkill { public: Skill_Melee_Single_Base(SpellID TypeID):CSkill(TypeID) { } }; // 多目标肉搏技能 class Skill_Melle_Multi_Base : public CSkill { public: Skill_Melle_Multi_Base(SpellID TypeID):CSkill(TypeID) { } }; // 远程技能 class Skill_Range_Base : public CSkill { virtual CEffectBase* CreateReleaseEffect(CCharacter* Caller); public: Skill_Range_Base(SpellID TypeID):CSkill(TypeID) { } }; // 魔法 class Skill_Magic_Base : public CSkill { public: Skill_Magic_Base(SpellID TypeID):CSkill(TypeID) { } }; // 震地一击 class Skill_Quake_Shock : public Skill_Melle_Multi_Base { class SKILL_DATA : public StateUserData { public: SKILL_DATA(IStateProxy* pState):StateUserData(pState) { } class DecalTerrain* Decal; float fTime; INT m_nFrameRate; INT m_nCurFrame; float m_fFrameTime; NiSourceTexturePtr spTextures[27]; }; //virtual BOOL IsStateProxy() const { return TRUE; } public: Skill_Quake_Shock() : Skill_Melle_Multi_Base(SKILL_TYPE_QUAKE_SHOCK) { } virtual CEffectBase* CreateReleaseEffect(CCharacter* Caller); virtual void UpdateReleaseEffect(CCharacter* Caller, DWORD Tick); virtual void EndSkill(CCharacter* Caller); }; class Skill_HANDY_HEW : public Skill_Melee_Single_Base { virtual CEffectBase* CreateReleaseEffect(CCharacter* Caller); virtual void UpdateReleaseEffect(CCharacter* Caller, DWORD Tick); virtual void EndSkill(CCharacter* Caller); public: Skill_HANDY_HEW():Skill_Melee_Single_Base(SKILL_TYPE_HANDY_HEW) { } }; class Skill_IMPALE_ACCURATELY : public Skill_Range_Base { class SkillStateData : public SkillData { }; virtual CEffectBase* CreateReleaseEffect(CCharacter* Caller); virtual EStateProcessResult ProxyProcess(IStateActor* Owner, DWORD dwTick); virtual BOOL ProxyStart(IStateActor* Owner, DWORD CurTime); virtual BOOL ProxyEnd(IStateActor* Owner, DWORD CurTime); void Attack(CCharacter* Attacker, INT TimeOffset); public: Skill_IMPALE_ACCURATELY(): Skill_Range_Base(SKILL_TYPE_IMPALE_ACCURATELY) { } virtual BOOL IsStateProxy() const { return TRUE; } }; #endif