using System; using System.IO; using System.Text; using System.Collections.Generic; using System.Runtime.Serialization; using CommonAI.RTS.Manhattan; using CommonAI.RTS; using CommonLang.Vector; using CommonLang; using CommonLang.ByteOrder; using CommonLang.IO; using CommonLang.IO.Attribute; using CommonLang.Property; using CommonAI.Zone.Attributes; using CommonAI.Zone.UnitTriggers; using CommonAI.Zone.Instance; using CommonAI.Zone.ZoneEditor; using CommonAI.Zone.Helper; using CommonLang.Xml; using static CommonAI.Zone.AttackProp; using CommonLang.Log; using CommonAI.Data; namespace CommonAI.Zone { //---------------------------------------------------------------------------------// [MessageType(0x4000)] public class Config { [DescAttribute("系统帧率(服务端)", "系统")] public int SYSTEM_FPS = 30; [DescAttribute("全局重力", "全局")] public float GLOBAL_GRAVITY = 9.8f; [DescAttribute("全局挤开移动最大递归深度", "全局")] public uint GLOBAL_MOVE_IMPACT_DEPTH = 10; [DescAttribute("超出此同步范围,立即将坐标修正", "客户端")] public float CLIENT_UNIT_MOVE_MODIFY_MAX_RANGE = 20f; [DescAttribute("单位移动最慢速度(低于最慢速度表示不能移动)", "移动")] public float OBJECT_MOVE_TO_MIN_STEP_SEC = 0.3f; [DescAttribute("单位攻击范围是否包含身体半径", "战斗")] public bool OBJECT_ATTACK_RANGE_INCLUDE_BODYSIZE = false; [DescAttribute("单位间无碰撞总开关", "战斗")] public bool OBJECT_NONE_TOUCH = false; [DescAttribute("玩家无碰撞", "战斗")] public bool PLAYER_NONE_TOUCH = false; [DescAttribute("宠物跟随距离(靠近主人多少停止)", "战斗")] public float PET_FOLLOW_DISTANCE_MIN = 1.5f; [DescAttribute("宠物跟随距离(离主人多远时跟随)", "战斗")] public float PET_FOLLOW_DISTANCE_MAX = 2.5f; [DescAttribute("宠物强制跟随距离(距离太远,直接瞬移到主人)", "战斗")] public float PET_FOLLOW_DISTANCE_LIMIT = 12f; [DescAttribute("队员跟随距离(靠近主人多少停止)", "战斗")] public float TEAMER_FOLLOW_DISTANCE_MIN = 2f; [DescAttribute("队员跟随距离(离主人多远时跟随)", "战斗")] public float TEAMER_FOLLOW_DISTANCE_MAX = 4f; [DescAttribute("队员强制跟随距离(距离太远,直接瞬移到主人)", "战斗")] public float TEAMER_FOLLOW_DISTANCE_LIMIT = 8f; [DescAttribute("单位默认转身速度(弧度/秒)", "战斗")] public float UNIT_TURN_SPEED_SEC = 3.14f; [DescAttribute("单位允许被鞭尸", "战斗")] public bool UNIT_CAN_WHIPLASH_BODY = false; [DescAttribute("单位被击飞向上速度", "受击")] public float OBJECT_DAMAGE_FLY_ZSPEED_SEC = 10.0f; [DescAttribute("单位被击飞速度(距离/秒)", "受击")] public float OBJECT_DAMAGE_FLY_SPEED_SEC = 10.0f; [DescAttribute("单位被击飞加速度(距离/秒) => (速度=速度+加速度)", "受击")] public float OBJECT_DAMAGE_FLY_SPEED_ADD = 0f; [DescAttribute("单位被击飞阻力(每秒递减速度百分比)", "受击")] public float OBJECT_DAMAGE_FLY_SPEED_ACC = 0f; [DescAttribute("单位被击飞各项参数浮动值百分比", "受击")] public float OBJECT_DAMAGE_FLY_ARGS_FACTOR_PCT = 0f; [DescAttribute("单位受击时间(毫秒)", "受击")] public int OBJECT_DAMAGE_TIME_MS = 1000; [DescAttribute("每隔一段时间检测一下是否要追(防止抖动)", "AI")] public int AI_FOLLOW_AND_ATTACK_HOLD_TIME_MS = 1000; [DescAttribute("尝试追击过程中,调整射击范围(逃离)的比率", "AI")] public float AI_FOLLOW_AND_ATTACK_ADJUST_ESCAPE_PCT = 50; [DescAttribute("观察一定范围的触发器,固定时间固定检测周围变化", "AI")] public int AI_VIEW_TRIGGER_CHECK_TIME_MS = 1000; [DescAttribute("移动过程中每次AI变化的停顿时间", "AI")] public int AI_MOVE_AI_HOLD_TIME_MS = 1000; [DescAttribute("NPC每隔多长毫秒检测一次最大警戒距离", "AI")] public int AI_NPC_CHECK_IN_GUARD_LIMIT_TIME_MS = 500; [DescAttribute("NPC攻击间歇时,有多少几率检测旁边有人,并散开,防止堆积在一个点。(百分比)", "AI")] public float AI_NPC_ATTACK_IDLE_SCATTER_PCT = 300; [DescAttribute("NPC散开检测间隔", "AI")] public int AI_NPC_ATTACK_IDLE_INTERVAL = 3000; [DescAttribute("仇恨列表上限", "AI")] public int AI_HATE_SYSTEM_CAPACITY_MS = 50; } [MessageType(0x410B)] [DescAttribute("地块定义信息")] [Expandable] public class TerrainDefinitionMap : IExternalizable, ICloneable { [DescAttribute("地块定义")] [Expandable] public class MapBlockBrush : ICloneable { [ColorValueAttribute] [Desc("颜色值ARGB", "Key")] public int Value = ColorValueAttribute.COLOR_GREEN; [Desc("是否阻挡", "Key")] public bool IsBlock = true; [Desc("名字")] public string Name = ""; [Desc("注释")] public string Desc = ""; [Desc("Tag")] public string Tag = ""; public MapBlockBrush() { } public MapBlockBrush(int value, bool is_block, string name) { this.Value = value; this.IsBlock = is_block; this.Name = name; } public object Clone() { MapBlockBrush ret = new MapBlockBrush(); ret.Value = this.Value; ret.IsBlock = this.IsBlock; ret.Name = this.Name; ret.Desc = this.Desc; ret.Tag = this.Tag; return ret; } public override string ToString() { return string.Format("[{1}] {2} : {0}", Value.ToString("X8"), IsBlock ? "Block" : "Cross", Name); } } [NotNull] [ListAttribute(typeof(MapBlockBrush))] [Desc("地块定义列表")] public List Brushes = new List(); public TerrainDefinitionMap() { Brushes.Add(new MapBlockBrush(0, false, "NULL")); Brushes.Add(new MapBlockBrush(ColorValueAttribute.COLOR_GREEN, true, "Block")); Brushes.Add(new MapBlockBrush(ColorValueAttribute.COLOR_DARK_GRAY, false, "Safe")); } /// /// 去从 /// public bool ContainsValue(int value) { foreach (var b in Brushes) { if (b.Value == value) { return true; } } return false; } public MapBlockBrush GetMapBlockBrush(int value) { foreach (var b in Brushes) { if (b.Value == value) { return b; } } return null; } public object Clone() { TerrainDefinitionMap ret = new TerrainDefinitionMap(); ret.Brushes = CUtils.CloneList(this.Brushes); return ret; } public void WriteExternal(IOutputStream output) { output.PutS32(Brushes.Count); foreach (var v in this.Brushes) { output.PutS32(v.Value); output.PutBool(v.IsBlock); output.PutUTF(v.Name); output.PutUTF(v.Desc); output.PutUTF(v.Tag); } } public void ReadExternal(IInputStream input) { Brushes.Clear(); int count = input.GetS32(); for (int i = 0; i < count; i++) { var v = new MapBlockBrush(); v.Value = input.GetS32(); v.IsBlock = input.GetBool(); v.Name = input.GetUTF(); v.Desc = input.GetUTF(); v.Tag = input.GetUTF(); Brushes.Add(v); } } } [MessageType(0x410C)] [DescAttribute("动作定义信息")] [Expandable] public class UnitActionDefinitionMap : IExternalizable, ICloneable { [DescAttribute("动作定义")] [Expandable] public class UnitAction : ICloneable, IExternalizable { [DescAttribute("动作", "动作")] public UnitActionStatus Action = UnitActionStatus.Idle; [ListAttribute(typeof(UnitActionKeyFrame))] [DescAttribute("动作序列", "动作")] public List ActionQueue = new List(); public void WriteExternal(IOutputStream output) { output.PutEnum8(this.Action); output.PutStructList(this.ActionQueue); } public void ReadExternal(IInputStream input) { this.Action = input.GetEnum8(); this.ActionQueue = input.GetStructList(); } public object Clone() { UnitAction ret = new UnitAction(); ret.Action = this.Action; ret.ActionQueue = CUtils.CloneList(this.ActionQueue); return ret; } public override string ToString() { return string.Format("{0} : {1}", Action, CUtils.ListToString(ActionQueue)); } } [DescAttribute("动作帧定义")] [Expandable] public class UnitActionKeyFrame : ICloneable, IExternalizable { [DescAttribute("动作名")] public string ActionName = "f_idle"; [DescAttribute("播放时间(如果多段动作,则需要指定每段时间)")] public int TimeMS = 0; [DescAttribute("是否循环")] public bool Cycle = false; [DescAttribute("是否淡出")] public bool CrossFade = false; [DescAttribute("播放速度")] public float Speed = 1f; [DescAttribute("Tag")] public string Tag = ""; public override string ToString() { return ActionName; } public void WriteExternal(IOutputStream output) { output.PutUTF(this.ActionName); output.PutS32(this.TimeMS); output.PutBool(this.Cycle); output.PutBool(this.CrossFade); output.PutF32(this.Speed); output.PutUTF(this.Tag); } public void ReadExternal(IInputStream input) { this.ActionName = input.GetUTF(); this.TimeMS = input.GetS32(); this.Cycle = input.GetBool(); this.CrossFade = input.GetBool(); this.Speed = input.GetF32(); this.Tag = input.GetUTF(); } public object Clone() { UnitActionKeyFrame ret = new UnitActionKeyFrame(); ret.ActionName = this.ActionName; ret.TimeMS = this.TimeMS; ret.Cycle = this.Cycle; ret.CrossFade = this.CrossFade; ret.Speed = this.Speed; ret.Tag = this.Tag; return ret; } } [ListAttribute(typeof(UnitAction))] [DescAttribute("动作集合")] public List ActionMap = new List(); public void WriteExternal(IOutputStream output) { output.PutStructList(this.ActionMap); } public void ReadExternal(IInputStream input) { this.ActionMap = input.GetStructList(); } public object Clone() { UnitActionDefinitionMap ret = new UnitActionDefinitionMap(); ret.ActionMap = CUtils.CloneList(this.ActionMap); return ret; } } //---------------------------------------------------------------------------------// /// /// 场景基础数据 /// [MessageType(0x4001)] public class ZoneInfo : IExternalizable, ICloneable { public int TemplateID { get { return ID; } } [DescAttribute("ID", "", false)] public int ID; /// /// 地图总宽 /// public int TotalWidth { get { return mXCount * mGridCellW; } } /// /// 地图总高 /// public int TotalHeight { get { return mYCount * mGridCellH; } } /// /// 所有地图碰撞块信息 /// public int[,] TerrainMatrix { get { return mTerrainMatrix; } } /// /// 地图碰撞格宽 /// public int GridCellW { get { return mGridCellW; } } /// /// 地图碰撞格高 /// public int GridCellH { get { return mGridCellH; } } /// /// 地图横向格子数 /// public int XCount { get { return mXCount; } } /// /// 地图纵向格子数 /// public int YCount { get { return mYCount; } } //------------------------------------------------------------ [DescAttribute("", "", false)] public int[,] mTerrainMatrix; [DescAttribute("", "", false)] public int mXCount; [DescAttribute("", "", false)] public int mYCount; [DescAttribute("", "", false)] public int mGridCellW; [DescAttribute("", "", false)] public int mGridCellH; //------------------------------------------------------------ public ZoneInfo(int xcount, int ycount, int gridW, int gridH) { this.mXCount = xcount; this.mYCount = ycount; this.mGridCellW = gridW; this.mGridCellH = gridH; this.mTerrainMatrix = new int[xcount, ycount]; } public ZoneInfo() { } public int GetID() { return ID; } public object Clone() { ZoneInfo ret = new ZoneInfo(); ret.ID = this.ID; ret.mXCount = this.mXCount; ret.mYCount = this.mYCount; ret.mGridCellW = this.mGridCellW; ret.mGridCellH = this.mGridCellH; ret.mTerrainMatrix = new int[mXCount, mYCount]; for (int x = 0; x < mXCount; x++) { for (int y = 0; y < mYCount; y++) { ret.mTerrainMatrix[x, y] = this.mTerrainMatrix[x, y]; } } return ret; } public bool TryGetFlag(int bx, int by, out int flag) { if (bx < mXCount && bx >= 0 && by < mYCount && by >= 0) { flag = mTerrainMatrix[bx, by]; return true; } flag = 0; return false; } public void WriteExternal(IOutputStream output) { output.PutS32(ID); output.PutS32(mXCount); output.PutS32(mYCount); output.PutS32(mGridCellW); output.PutS32(mGridCellH); for (int x = 0; x < mXCount; x++) { for (int y = 0; y < mYCount; y++) { output.PutS32(mTerrainMatrix[x, y]); } } } public void ReadExternal(IInputStream input) { this.ID = input.GetS32(); this.mXCount = input.GetS32(); this.mYCount = input.GetS32(); this.mGridCellW = input.GetS32(); this.mGridCellH = input.GetS32(); this.mTerrainMatrix = new int[mXCount, mYCount]; for (int x = 0; x < mXCount; x++) { for (int y = 0; y < mYCount; y++) { this.mTerrainMatrix[x, y] = input.GetS32(); } } } } //---------------------------------------------------------------------------------// #region __Templates_Data__ //---------------------------------------------------------------------------------// /// /// 单位模板数据 /// [MessageType(0x4002)] [DescAttribute("单位模板数据")] [TableClassAttribute("ID")] public class UnitInfo : ICloneable, ITemplateData, IExternalizable { protected static readonly Logger log = LoggerFactory.GetDefLogger(); public int TemplateID { get { return ID; } } [XmlSerializable()] public string EditorPath { get; set; } /// /// 单位类型 /// public enum UnitType : byte { [DescAttribute("玩家")] TYPE_PLAYER = 1, [DescAttribute("NPC")] TYPE_NPC = 2, [DescAttribute("怪物")] TYPE_MONSTER = 3, [DescAttribute("宠物")] TYPE_PET = 4, [DescAttribute("召唤物")] TYPE_SUMMON = 5, [DescAttribute("建筑")] TYPE_BUILDING = 6, [DescAttribute("脚本控制")] TYPE_MANUAL = 7, [DescAttribute("触发机关")] TYPE_TRIGGER = 8, [DescAttribute("中立无敌意")] TYPE_NEUTRALITY = 9, } //------------------------------------ /// /// 单位类型 /// [DescAttribute("单位类型", "基础")] public UnitType UType = UnitType.TYPE_MONSTER; [DescAttribute( "单位类型" + "\n PLAYER=1" + "\n NPC=2" + "\n MONSTER=3" + "\n PET=4" + "\n SUMMON=5" + "\n BUILDING=6" + "\n MANUAL=7" + "\n TRIGGER=8" + "\n NEUTRALITY=9", "基础")] public int UTypeAsInt { get { return (int)UType; } } public bool IsSummon { get { return UType == UnitType.TYPE_SUMMON; } } [DescAttribute("召唤类型", "基础")] [DependOnProperty("IsSummon")] public SummonType SumType = SummonType.none; /// /// 模板ID /// [DescAttribute("ID", "", false)] public int ID; /// /// 单位名字 /// [LocalizationTextAttribute] [DescAttribute("单位名字", "基础")] public string Name; [DescAttribute("是否为精英怪", "基础")] public bool IsElite; //------------------------------------ /// /// 对应的模型文件名 /// [DescAttribute("对应的模型文件名", "资源")] [ResourceIDAttribute] public string FileName; [DescAttribute("怪物产生时触发的特效", "资源")] public LaunchEffect SpawnEffect; [DescAttribute("怪物脚底的特效", "资源")] public LaunchEffect FootCircleEffect; [DescAttribute("怪物死亡时触发的特效", "资源")] public LaunchEffect DeadEffect; [DescAttribute("怪物死亡动作播放结束后触发的特效", "资源")] public LaunchEffect DeadActionEffect; [DescAttribute("怪物烂掉时触发的特效", "资源")] public LaunchEffect RemovedEffect; [DescAttribute("怪物击碎时触发的特效", "资源")] public LaunchEffect CrushEffect; [DescAttribute("怪物受击时触发的特效", "资源")] public LaunchEffect DamageEffect; [DescAttribute("缩放比率", "资源")] public float BodyScale = 1; [DescAttribute("死亡的音效文件", "资源")] [ResourceIDAttribute] public string DeadAudioName; [DescAttribute("切换阵营特效", "资源-切阵营")] public LaunchEffect ChangeForceEffect; [DescAttribute("切换阵营音效文件", "资源-切阵营")] [ResourceIDAttribute] public string ChangeForceAudioName; [DescAttribute("破碎比例", "资源-破碎")] public int HitBreakPrecent; [DescAttribute("破碎特效", "资源-破碎")] public LaunchEffect HitBreakEffect; [DescAttribute("破碎音效文件", "资源-破碎")] [ResourceIDAttribute] public string HitBreakAudioName; //------------------------------------ /// /// 身体高度 /// [DescAttribute("身体高度", "战斗")] public float BodyHeight; /// /// 身体尺寸(半径) /// [DescAttribute("身体尺寸(半径)", "战斗")] public float BodySize = 1; /// /// 警戒距离范围 /// [DescAttribute("身体受攻击尺寸(半径)", "战斗")] public float BodyHitSize = 1; //------------------------------------ /// /// 警戒距离范围 /// [DescAttribute("警戒距离范围", "战斗 - 警戒")] public float GuardRange = 5; [DescAttribute("最大警戒范围,超过此范围不追击,0表示无限", "战斗 - 警戒")] public float GuardRangeLimit = 20; [DescAttribute("分组警戒范围,如果此单位进入战斗,则传给相邻单位Add,0表示不传递", "战斗 - 警戒")] public float GuardRangeGroup = 5; public bool IdleRecover { get { return RecoveryIntervalMS > 0; } } [DescAttribute("恢复间隔(毫秒),脱离战斗后回血间隔时间", "战斗 - 恢复")] public int RecoveryIntervalMS = 10000; [DescAttribute("血量恢复/秒", "战斗 - 恢复")] [DependOnProperty("IdleRecover")] public int HealthRecoveryPoint = 0; [DescAttribute("法力恢复/秒", "战斗 - 恢复")] [DependOnProperty("IdleRecover")] public int ManaRecoveryPoint = 0; //------------------------------------ [DescAttribute("体重(>=100不能被击飞)", "战斗")] public int Weight = 1; [DescAttribute("是否可移动", "战斗")] public bool IsMoveable = true; [DescAttribute("是否可转向", "战斗")] public bool IsTurnable = true; //------------------------------------ /// /// 移动距离,像素或者码 /// [DescAttribute("移动速度(距离/每秒)", "战斗")] public float MoveSpeedSEC = 6f; [DescAttribute("转身速度(弧度/秒)", "战斗")] public float TurnSpeedSEC = float.NaN; [DescAttribute("受击时间(毫秒)", "战斗")] public int DamageTimeMS = 10; //------------------------------------ /// /// 此单位普通攻击技能 /// [DescAttribute("此单位普通攻击技能", "技能")] public LaunchSkill BaseSkillID = new LaunchSkill(); /// /// 此单位绑定的所有技能ID /// [ListAttribute(typeof(LaunchSkill))] [DescAttribute("此单位绑定的所有技能ID", "技能")] public List Skills = new List(); /// /// 触发类特效 /// [ListAttribute(typeof(LaunchTrigger))] [DescAttribute("触发类", "技能")] public List Triggers = new List(); //------------------------------------ //------------------------------------ [DescAttribute("法术发射高度(炮口高度)", "炮口")] public float LaunchSpellHeight; [DescAttribute("法术发射半径(炮口半径)", "炮口")] public float LaunchSpellRadius = 0; //------------------------------------ [DescAttribute("死亡时释放法术(自爆)", "战斗")] public LaunchSpell DeadLaunchSpell = null; [DescAttribute("死亡时释放法术(灵魂出窍)", "战斗")] public LaunchSpell DeadDelayLaunchSpell = null; //------------------------------------ [DescAttribute("血量", "战斗")] public int HealthPoint = 100; [DescAttribute("法力值", "战斗")] public int ManaPoint = 100; [DescAttribute("耐力值", "战斗")] public int StaminaPoint = 100; [DescAttribute("产生经验", "战斗")] public int GenExp; //------------------------------------ /// /// 掉落道具列表 /// [ListAttribute(typeof(DropItemList))] [DescAttribute("掉落道具", "掉落")] public List DropItemsSet = new List(); [DescAttribute("被杀死直接获得金币", "掉落")] public int DropMoney; //------------------------------------ [DescAttribute("单位背包数量", "背包")] public int InventorySize = 1; [ListAttribute(typeof(InventoryItem))] [DescAttribute("进入战斗携带的道具列表(比如血瓶)", "背包")] public List InventoryList = new List(); //------------------------------------ /// /// 若是召唤类,则表示存活时间 /// [DescAttribute("若是召唤类,则表示存活时间(毫秒)", "战斗")] public int LifeTimeMS; /// /// 单位出生延时时间,通常播放出生动画 /// [DescAttribute("单位出生延时时间,通常播放出生动画(毫秒)", "战斗")] public int SpawnTimeMS; /// /// 持续时间 /// [DescAttribute("单位死亡持续时间,即死亡后多长时间内可继续鞭尸(毫秒)", "战斗")] public int DeadTimeMS; /// /// /// [DescAttribute("单位死亡之后延迟时间(毫秒),播放 DeadDelayLaunchSpell 特效", "战斗")] public int DeadDelayTimeMS; /// /// /// [DescAttribute("播放 DeadDelayLaunchSpell 特效的数量", "战斗")] public int DeadDelaySpellNumber; public bool HasNumbers { get { return DeadDelaySpellNumber > 1; } } /// /// /// [DescAttribute("播放每一个 DeadDelayLaunchSpell 间隔的时间(单位:毫秒)", "战斗")] [DependOnProperty("HasNumbers")] public int DeadDelaySpellIntervalMS; /// /// 复活时间 /// [DescAttribute("死亡后多久复活,0表示不能复活(毫秒)", "战斗")] public int RebirthTimeMS; //------------------------------------ [DescAttribute("用户自定义标志", "脚本")] public string UserTag; //------------------------------------ [DescAttribute("是否为动态创建单位,比如PVP或者根据玩家等级创建的单位", "扩展")] public bool IsDynamic = false; [DescAttribute("是否随机名字", "扩展")] public bool IsRandomName = false; //------------------------------------ [DescAttribute("单位绑定触发事件ID", "事件")] [TemplatesIDAttribute(typeof(UnitEventTemplate))] public List Events = new List(); //------------------------------------ /// /// 用户自定义扩展属性 /// [DescAttribute("扩展属性", "扩展")] [Expandable] [NotNull] public IUnitProperties Properties; //------------------------------------ [DescAttribute("自定义字段", "属性", true)] public string[] Attributes; //------------------------------------ public UnitInfo() { Properties = TemplateManager.Factory.CreateUnitProperties(); } public int GetID() { return ID; } public override string ToString() { return Name + "(" + ID + ")"; } public object Clone() { UnitInfo ret = new UnitInfo(); ret.EditorPath = this.EditorPath; ret.UType = this.UType; ret.ID = this.ID; ret.Name = this.Name; ret.IsElite = this.IsElite; ret.FileName = this.FileName; ret.SpawnEffect = CUtils.TryClone(this.SpawnEffect); ret.FootCircleEffect = CUtils.TryClone(this.FootCircleEffect); ret.DeadEffect = CUtils.TryClone(this.DeadEffect); ret.RemovedEffect = CUtils.TryClone(this.RemovedEffect); ret.DeadActionEffect = CUtils.TryClone(this.DeadActionEffect); ret.CrushEffect = CUtils.TryClone(this.CrushEffect); ret.DamageEffect = CUtils.TryClone(this.DamageEffect); ret.BodyScale = this.BodyScale; ret.DeadAudioName = this.DeadAudioName; ret.BodyHeight = this.BodyHeight; ret.BodySize = this.BodySize; ret.BodyHitSize = this.BodyHitSize; ret.GuardRange = this.GuardRange; ret.GuardRangeLimit = this.GuardRangeLimit; ret.GuardRangeGroup = this.GuardRangeGroup; ret.HealthRecoveryPoint = this.HealthRecoveryPoint; ret.ManaRecoveryPoint = this.ManaRecoveryPoint; ret.RecoveryIntervalMS = this.RecoveryIntervalMS; ret.Weight = this.Weight; ret.MoveSpeedSEC = this.MoveSpeedSEC; ret.TurnSpeedSEC = this.TurnSpeedSEC; ret.DamageTimeMS = this.DamageTimeMS; ret.IsMoveable = this.IsMoveable; ret.IsTurnable = this.IsTurnable; ret.BaseSkillID = CUtils.TryClone(this.BaseSkillID); ret.Skills = CUtils.CloneList(this.Skills); ret.Triggers = CUtils.CloneList(this.Triggers); ret.LaunchSpellHeight = this.LaunchSpellHeight; ret.LaunchSpellRadius = this.LaunchSpellRadius; ret.DeadLaunchSpell = this.DeadLaunchSpell; ret.DeadDelayLaunchSpell = this.DeadDelayLaunchSpell; ret.HealthPoint = this.HealthPoint; ret.ManaPoint = this.ManaPoint; ret.StaminaPoint = this.StaminaPoint; ret.GenExp = this.GenExp; ret.DropItemsSet = CUtils.CloneList(this.DropItemsSet); ret.DropMoney = this.DropMoney; ret.InventorySize = this.InventorySize; ret.InventoryList = CUtils.CloneList(this.InventoryList); ret.LifeTimeMS = this.LifeTimeMS; ret.SpawnTimeMS = this.SpawnTimeMS; ret.DeadTimeMS = this.DeadTimeMS; ret.DeadDelayTimeMS = this.DeadDelayTimeMS; ret.DeadDelaySpellNumber = this.DeadDelaySpellNumber; ret.DeadDelaySpellIntervalMS = this.DeadDelaySpellIntervalMS; ret.RebirthTimeMS = this.RebirthTimeMS; ret.UserTag = this.UserTag; ret.IsDynamic = this.IsDynamic; ret.Events = new List(this.Events); ret.Properties = CUtils.TryClone(this.Properties);// (IUnitProperties)this.Properties.Clone(); ret.Attributes = CUtils.CloneArray(this.Attributes); ret.HitBreakPrecent = this.HitBreakPrecent; ret.HitBreakEffect = CUtils.TryClone(this.HitBreakEffect); ret.ChangeForceEffect = CUtils.TryClone(this.ChangeForceEffect); ret.ChangeForceAudioName = this.ChangeForceAudioName; ret.HitBreakPrecent = this.HitBreakPrecent; ret.HitBreakEffect = this.HitBreakEffect; ret.HitBreakAudioName = this.HitBreakAudioName; ret.IsRandomName = this.IsRandomName; ret.SumType = this.SumType; return ret; } public void WriteExternal(IOutputStream output) { output.PutUTF(this.EditorPath); output.PutEnum8(this.UType); output.PutS32(this.ID); output.PutUTF(this.Name); output.PutBool(this.IsElite); output.PutUTF(this.FileName); output.PutExt(this.SpawnEffect); output.PutExt(this.FootCircleEffect); output.PutExt(this.DeadEffect); output.PutExt(this.RemovedEffect); output.PutExt(this.DeadActionEffect); output.PutExt(this.CrushEffect); output.PutExt(this.DamageEffect); output.PutF32(this.BodyScale); output.PutUTF(this.DeadAudioName); output.PutF32(this.BodyHeight); output.PutF32(this.BodySize); output.PutF32(this.BodyHitSize); output.PutF32(this.GuardRange); output.PutF32(this.GuardRangeLimit); output.PutF32(this.GuardRangeGroup); output.PutS32(this.RecoveryIntervalMS); output.PutS32(this.HealthRecoveryPoint); output.PutS32(this.ManaRecoveryPoint); output.PutS32(this.Weight); output.PutF32(this.MoveSpeedSEC); output.PutF32(this.TurnSpeedSEC); output.PutS32(this.DamageTimeMS); output.PutBool(this.IsMoveable); output.PutBool(this.IsTurnable); output.PutExt(this.BaseSkillID); output.PutList(this.Skills, output.PutExt); output.PutList(this.Triggers, output.PutExt); output.PutF32(this.LaunchSpellHeight); output.PutF32(this.LaunchSpellRadius); output.PutExt(this.DeadLaunchSpell); output.PutExt(this.DeadDelayLaunchSpell); output.PutS32(this.HealthPoint); output.PutS32(this.ManaPoint); output.PutS32(this.StaminaPoint); output.PutS32(this.GenExp); output.PutList(this.DropItemsSet, output.PutExt); output.PutS32(this.DropMoney); output.PutS32(this.InventorySize); output.PutList(this.InventoryList, output.PutExt); output.PutS32(this.LifeTimeMS); output.PutS32(this.SpawnTimeMS); output.PutS32(this.DeadTimeMS); output.PutS32(this.DeadDelayTimeMS); output.PutS32(this.DeadDelaySpellNumber); output.PutS32(this.DeadDelaySpellIntervalMS); output.PutS32(this.RebirthTimeMS); output.PutUTF(this.UserTag); output.PutBool(this.IsDynamic); output.PutList(this.Events, output.PutS32); output.PutArray(this.Attributes, output.PutUTF); output.PutExt(this.Properties); //破碎,切阵营 output.PutExt(this.ChangeForceEffect); output.PutUTF(this.ChangeForceAudioName); output.PutS32(this.HitBreakPrecent); output.PutExt(this.HitBreakEffect); output.PutUTF(this.HitBreakAudioName); // 随机名字 output.PutBool(this.IsRandomName); output.PutEnum8(this.SumType); } public void ReadExternal(IInputStream input) { this.EditorPath = input.GetUTF(); this.UType = input.GetEnum8(); this.ID = input.GetS32(); this.Name = input.GetUTF(); this.IsElite = input.GetBool(); this.FileName = input.GetUTF(); this.SpawnEffect = input.GetExt(); this.FootCircleEffect = input.GetExt(); this.DeadEffect = input.GetExt(); this.RemovedEffect = input.GetExt(); this.DeadActionEffect = input.GetExt(); this.CrushEffect = input.GetExt(); this.DamageEffect = input.GetExt(); this.BodyScale = input.GetF32(); this.DeadAudioName = input.GetUTF(); this.BodyHeight = input.GetF32(); this.BodySize = input.GetF32(); this.BodyHitSize = input.GetF32(); this.GuardRange = input.GetF32(); this.GuardRangeLimit = input.GetF32(); this.GuardRangeGroup = input.GetF32(); this.RecoveryIntervalMS = input.GetS32(); this.HealthRecoveryPoint = input.GetS32(); this.ManaRecoveryPoint = input.GetS32(); this.Weight = input.GetS32(); this.MoveSpeedSEC = input.GetF32(); this.TurnSpeedSEC = input.GetF32(); this.DamageTimeMS = input.GetS32(); this.IsMoveable = input.GetBool(); this.IsTurnable = input.GetBool(); this.BaseSkillID = input.GetExt(); this.Skills = input.GetList(input.GetExt); this.Triggers = input.GetList(input.GetExt); this.LaunchSpellHeight = input.GetF32(); this.LaunchSpellRadius = input.GetF32(); this.DeadLaunchSpell = input.GetExt(); this.DeadDelayLaunchSpell = input.GetExt(); this.HealthPoint = input.GetS32(); this.ManaPoint = input.GetS32(); this.StaminaPoint = input.GetS32(); this.GenExp = input.GetS32(); this.DropItemsSet = input.GetList(input.GetExt); this.DropMoney = input.GetS32(); this.InventorySize = input.GetS32(); this.InventoryList = input.GetList(input.GetExt); this.LifeTimeMS = input.GetS32(); this.SpawnTimeMS = input.GetS32(); this.DeadTimeMS = input.GetS32(); this.DeadDelayTimeMS = input.GetS32(); this.DeadDelaySpellNumber = input.GetS32(); this.DeadDelaySpellIntervalMS = input.GetS32(); this.RebirthTimeMS = input.GetS32(); this.UserTag = input.GetUTF(); this.IsDynamic = input.GetBool(); this.Events = input.GetList(input.GetS32); this.Attributes = input.GetUTFArray(); this.Properties = input.GetExt(this.Properties); this.ChangeForceEffect = input.GetExt(); this.ChangeForceAudioName = input.GetUTF(); this.HitBreakPrecent = input.GetS32(); this.HitBreakEffect = input.GetExt(); this.HitBreakAudioName = input.GetUTF(); this.IsRandomName = input.GetBool(); this.SumType = input.GetEnum8(); if (UType == UnitType.TYPE_NPC && this.RecoveryIntervalMS > 0) { log.Debug("NPC配置了恢复时间, 强行重置" + this.ID); this.RecoveryIntervalMS = 0; } } public LaunchSkill GetSkillByID(int skillID) { if (BaseSkillID != null && skillID == BaseSkillID.SkillID) { return BaseSkillID; } if (Skills != null) { for (int i = 0; i < Skills.Count; i++) { if (Skills[i].SkillID == skillID) { return Skills[i]; } } } return null; } } //---------------------------------------------------------------------------------// /// /// 技能模板 /// [MessageType(0x4003)] [DescAttribute("技能模板")] [TableClassAttribute("ID")] public class SkillTemplate : ICloneable, ITemplateData, IExternalizable { public int TemplateID { get { return ID; } } [XmlSerializable()] public string EditorPath { get; set; } // 技能ID [DescAttribute("ID", "", false)] public int ID; /// /// 技能名字 /// [LocalizationTextAttribute] [DescAttribute("技能名字", "基础")] public string Name; [DescAttribute("技能冷却时间(毫秒)", "基础")] [DependOnProperty("IsCoolDownWithAction", false)] public int CoolDownMS = 6000; //------------------------------------ [DescAttribute("技能图标", "资源")] public string IconName; //------------------------------------ /// /// 攻击动作序列 /// [DescAttribute("攻击动作序列", "动作")] [ListAttribute(typeof(UnitActionData))] public List ActionQueue = new List(); [DescAttribute("以动作时间作为冷却时间, 普攻使用", "动作")] //只能普攻使用 public bool IsCoolDownWithAction = false; [DescAttribute("可以打断其他技能和受击状态,受身技能", "动作")] public bool IsCounter = false; [DescAttribute("技能优先级,高优先级可打断低优先级", "动作")] public int ActionPriority = 0; [DescAttribute("动作播放速率", "动作")] public float ActionSpeedRate = 1f; [DescAttribute("技能释放期间,模型缩放(仅客户端有效)", "动作")] public float BodyScale = 1f; [DescAttribute("技能释放期间,可手动撤销", "动作")] public bool IsManuallyCancelable = false; [DescAttribute("忽略本技能释放中不可打断的时间段(只用作客户端显示用)", "动作")] public bool IgnoreMyUncancelable = false; //------------------------------------ [DescAttribute("每次释放只做一个动作,多段攻击", "多段攻击")] public bool IsSingleAction = false; [DependOnProperty("IsSingleAction")] [DescAttribute("多段攻击间隔有效时间", "多段攻击")] public int SingleActionCoolDownMS = 500; //------------------------------------ [DescAttribute("攻击距离", "攻击范围")] public float AttackRange = 3; [DescAttribute("攻击角度范围(弧度)\n如果角度为0,则为单体攻击", "攻击范围")] public float AttackAngle = 0; [DescAttribute("单体攻击,只在目标处于攻击范围才产生伤害", "攻击范围")] public bool AttackMustBeInRange = true; [DescAttribute("保持攻击距离(NPC会保持一段距离再攻击)大于0启效", "攻击范围")] public float AttackKeepRange = 0; [DescAttribute("自动战斗,跟随目标", "攻击范围")] public bool AutoFightFollower = false; //------------------------------------ [DescAttribute("技能当前储存次数")] public short CurUseTimes = -1; [DescAttribute("法术是否从自己身上发出", "释放")] public bool IsLaunchBody = true; [DescAttribute("吟唱时间(毫秒)大于0启效", "释放")] public int ChantTimeMS = 0; //------------------------------------ public enum CastTarget : byte { [DescAttribute("敌人")] Enemy = 0, [DescAttribute("友军")] Alias = 1, [DescAttribute("自己")] Self = 2, [DescAttribute("宠物为主人")] PetForMaster = 3, [DescAttribute("任何单位")] EveryOne = 4, [DescAttribute("无类型")] NA = 5, [DescAttribute("除自己之外友军")] AlliesExcludeSelf = 6, [DescAttribute("包括自己友军")] AlliesIncludeSelf = 7, [DescAttribute("除自己之外所有")] EveryOneExcludeSelf = 8, [DescAttribute("自己和敌人")] EnemyAndSelf = 9, } [DescAttribute("技能期望作用目标", "释放")] public CastTarget ExpectTarget = CastTarget.Enemy; //------------------------------------ public enum SelectRange : byte { [DescAttribute("无")] NA, [DescAttribute("圆形区域")] Round, [DescAttribute("直线")] Line, [DescAttribute("矩形区域")] Rect, [DescAttribute("扇形区域")] Fan, } //------------------------------------ [DescAttribute("释放时是否选择方向", "释放范围")] public bool IsSelectRange = false; [DependOnProperty("IsSelectRange")] [DescAttribute("选择方向类型", "释放范围")] public SelectRange SelectRangeType = SelectRange.NA; [DependOnProperty("IsSelectRange")] [DescAttribute("选择方向尺寸", "释放范围")] public float SelectRangeSize; //------------------------------------ [DescAttribute("释放消耗血量", "消耗")] public int CostHP; [DescAttribute("释放消耗法力", "消耗")] public int CostMP; //------------------------------------ /// /// 用户自定义扩展属性 /// [DescAttribute("扩展属性", "扩展")] [Expandable] [NotNull] public ISkillProperties Properties = TemplateManager.Factory.CreateSkillProperties(); //------------------------------------ public SkillTemplate() { } public SkillTemplate(int id) { this.ID = id; } public int GetID() { return ID; } public override string ToString() { return Name + "(" + ID + ")"; } public UnitActionData GetActionByName(string name) { foreach (UnitActionData act in ActionQueue) { if (name.Equals(act.ActionName)) { return act; } } return null; } public int ToUnitSkillTotalTime(float fastCastRate) { return (int)(this.CoolDownMS * Math.Max(0, 1f - fastCastRate)); } public int ActionQueueTimeMS { get { int ret = 0; for (int i = 0; i < ActionQueue.Count; i++) { ret += ActionQueue[i].TotalTimeMS; } return ret; } } public int[] ActionQueueTimeArray { get { int[] ret = new int[ActionQueue.Count]; for (int i = ret.Length - 1; i >= 0; --i) { ret[i] = ActionQueue[i].TotalTimeMS; } return ret; } } public object Clone() { SkillTemplate ret = new SkillTemplate(); ret.EditorPath = this.EditorPath; ret.ID = this.ID; ret.Name = this.Name; ret.IconName = this.IconName; ret.ActionQueue = CUtils.CloneList(this.ActionQueue); ret.IsSingleAction = this.IsSingleAction; ret.SingleActionCoolDownMS = this.SingleActionCoolDownMS; ret.IsCoolDownWithAction = this.IsCoolDownWithAction; ret.IsCounter = this.IsCounter; ret.ActionPriority = this.ActionPriority; ret.CoolDownMS = this.CoolDownMS; ret.ActionSpeedRate = this.ActionSpeedRate; ret.IsManuallyCancelable = this.IsManuallyCancelable; ret.IgnoreMyUncancelable = this.IgnoreMyUncancelable; ret.BodyScale = this.BodyScale; ret.AttackRange = this.AttackRange; ret.AttackAngle = this.AttackAngle; ret.AttackMustBeInRange = this.AttackMustBeInRange; ret.AttackKeepRange = this.AttackKeepRange; ret.AutoFightFollower = this.AutoFightFollower; ret.IsLaunchBody = this.IsLaunchBody; ret.ChantTimeMS = this.ChantTimeMS; ret.IsSelectRange = this.IsSelectRange; ret.SelectRangeType = this.SelectRangeType; ret.SelectRangeSize = this.SelectRangeSize; ret.CostHP = this.CostHP; ret.CostMP = this.CostMP; ret.ExpectTarget = this.ExpectTarget; //ret.CurUseTimes = this.CurUseTimes; ret.Properties = CUtils.TryClone(this.Properties); return ret; } public void WriteExternal(IOutputStream output) { output.PutUTF(this.EditorPath); output.PutS32(this.ID); output.PutUTF(this.Name); output.PutUTF(this.IconName); output.PutList(this.ActionQueue, output.PutExt); output.PutBool(this.IsSingleAction); output.PutS32(this.SingleActionCoolDownMS); output.PutBool(this.IsCoolDownWithAction); output.PutBool(this.IsCounter); output.PutS32(this.ActionPriority); output.PutS32(this.CoolDownMS); output.PutF32(this.ActionSpeedRate); output.PutBool(this.IsManuallyCancelable); output.PutBool(this.IgnoreMyUncancelable); output.PutF32(this.BodyScale); output.PutF32(this.AttackRange); output.PutF32(this.AttackAngle); output.PutBool(this.AttackMustBeInRange); output.PutF32(this.AttackKeepRange); output.PutBool(this.AutoFightFollower); output.PutBool(this.IsLaunchBody); output.PutS32(this.ChantTimeMS); output.PutBool(this.IsSelectRange); output.PutEnum8(this.SelectRangeType); output.PutF32(this.SelectRangeSize); output.PutS32(this.CostHP); output.PutS32(this.CostMP); output.PutEnum8(this.ExpectTarget); output.PutS16(this.CurUseTimes); output.PutExt(this.Properties); } public void ReadExternal(IInputStream input) { this.EditorPath = input.GetUTF(); this.ID = input.GetS32(); this.Name = input.GetUTF(); this.IconName = input.GetUTF(); this.ActionQueue = input.GetList(input.GetExt); this.IsSingleAction = input.GetBool(); this.SingleActionCoolDownMS = input.GetS32(); this.IsCoolDownWithAction = input.GetBool(); this.IsCounter = input.GetBool(); this.ActionPriority = input.GetS32(); this.CoolDownMS = input.GetS32(); this.ActionSpeedRate = input.GetF32(); this.IsManuallyCancelable = input.GetBool(); this.IgnoreMyUncancelable = input.GetBool(); this.BodyScale = input.GetF32(); this.AttackRange = input.GetF32(); this.AttackAngle = input.GetF32(); this.AttackMustBeInRange = input.GetBool(); this.AttackKeepRange = input.GetF32(); this.AutoFightFollower = input.GetBool(); this.IsLaunchBody = input.GetBool(); this.ChantTimeMS = input.GetS32(); this.IsSelectRange = input.GetBool(); this.SelectRangeType = input.GetEnum8(); this.SelectRangeSize = input.GetF32(); this.CostHP = input.GetS32(); this.CostMP = input.GetS32(); this.ExpectTarget = input.GetEnum8(); this.CurUseTimes = input.GetS16(); this.Properties = input.GetExt(this.Properties); } } //---------------------------------------------------------------------------------// /// /// 单位动作模板 /// [MessageType(0x4004)] [DescAttribute("单位动作")] [Expandable] public class UnitActionData : ICloneable, IExternalizable { [DescAttribute("总动作时间(毫秒)", "Action")] public int TotalTimeMS; [DescAttribute("动作播放速率增加(加法)", "动作")] public float ActionSpeedRate = 0.0f; [DescAttribute("单一动作类型,0-普通, 1,蓄力动作,2-多段式动作", "Action")] //蓄力动作,显示倒计时圈 //多段式动作,显示倒计时圈 + 倒计时 public ActionEnum SigleActionType; [DescAttribute("动作名字, IsSingleAction=false才有效", "Action")] public string ActionName; [DependOnProperty("IsControlMoveable", true)] [DescAttribute("移动动作名字", "Action")] public string MoveActionName; [DescAttribute("动作对应的特效,通常用作刀光", "Action")] [ResourceIDAttribute] public string ActionEffectFileName; [DescAttribute("动作是否循环", "Action")] public bool IsCycAction; [DescAttribute("显示蓄力倒计时条时间(毫秒)", "Action")] public int ShowChargeTimeMS = 0; [DescAttribute("移动可取消动作", "状态")] public bool IsCancelable = false; [DescAttribute("技能可取消动作", "状态")] public bool IsCancelableBySkill = false; [DescAttribute("技能能否被下一段替代", "状态")] public bool IsCancelBySkillNext = false; [DescAttribute("是否进入霸体状态,不会被打断", "状态")] public bool IsNoneBlock = false; [DescAttribute("动作期间是否无碰撞", "状态")] public bool IsNoneTouch = false; [DescAttribute("动作中是否面向目标", "状态")] public bool IsFaceToTarget = true; [DescAttribute("动作是否隐身", "状态")] public bool IsInvisible = false; [DescAttribute("动作中是否可以控制移动", "状态")] public bool IsControlMoveable = false; [DescAttribute("动作中可以控制转向", "状态")] public bool IsControlFaceable = false; //新增动作对应Icon [DescAttribute("是否换图", "资源")] public bool IsChangeIcon = false; [DescAttribute("图片名字", "资源")] [DependOnProperty("IsChangeIcon", true)] public string IconName; [DescAttribute("攻击范围改变", "攻击范围")] public AttackShape OverrideAttackShape; /// /// 所有关键帧 /// [ListAttribute(typeof(KeyFrame))] [DescAttribute("所有关键帧", "关键帧")] public List KeyFrames = new List(); public bool IsBodyHit { get { if (IsMoveToTarget) return false; if (IsJumpToTarget) return false; return BodyHit != null; } } /// /// 身体攻击判定 /// [DependOnProperty("IsMoveToTarget", false)] [DependOnProperty("IsJumpToTarget", false)] [DescAttribute("身体攻击判定", "身体攻击")] public AttackProp BodyHit; [DependOnProperty("IsBodyHit")] [DescAttribute("身体攻击判定范围", "身体攻击")] public float BodyHitSize; [DependOnProperty("IsBodyHit")] [DescAttribute("身体攻击后立即切换动作", "身体攻击")] public bool BodyHitNextAction; [DescAttribute("移动到目标", "位移 - 冲锋")] public bool IsMoveToTarget = false; [DescAttribute("移动到目标速度", "位移 - 冲锋")] [DependOnProperty("IsMoveToTarget")] public float MoveToTargetSpeedSEC = 10; [DescAttribute("移动到目标根据(距离/动作时间)来算速度,如果目标在原地,则原地跳跃。", "位移 - 跳跃")] [DependOnProperty("IsMoveToTarget", false)] public bool IsJumpToTarget = false; [DescAttribute("跳跃高度", "位移 - 跳跃")] [DependOnProperty("IsJumpToTarget")] public float JumpToTargetHeightZ = 1; [DescAttribute("在攻击范围内,如果位移则挤开目标", "碰撞")] [DependOnProperty("IsMoveToTarget", false)] [DependOnProperty("IsJumpToTarget", false)] public bool BodyBlockOnAttackRange = false; [DescAttribute("显示技能引导光圈(必须先打开扩展属性中的ShowLaunchGuide)", "控制")] public bool IsShowSkillGuide = false; [DescAttribute("增加技能按钮遮罩", "资源")] public bool IsAddSkillBtnBlock = false; [DescAttribute("动作的音效文件名", "资源")] public string ActionAudioName; [DescAttribute("动作的音效文件是否循环播放", "资源")] public bool IsAudioLoop; public UnitActionData() { } public override string ToString() { return "动作: " + ActionName + " (" + TotalTimeMS + "(毫秒))"; } public object Clone() { UnitActionData ret = new UnitActionData(); ret.ShowChargeTimeMS = this.ShowChargeTimeMS; ret.TotalTimeMS = this.TotalTimeMS; ret.ActionName = this.ActionName; ret.ActionEffectFileName = this.ActionEffectFileName; ret.IsCycAction = this.IsCycAction; ret.IsCancelable = this.IsCancelable; ret.IsCancelableBySkill = this.IsCancelableBySkill; ret.IsCancelBySkillNext = this.IsCancelBySkillNext; ret.IsNoneBlock = this.IsNoneBlock; ret.IsNoneTouch = this.IsNoneTouch; ret.IsFaceToTarget = this.IsFaceToTarget; ret.IsInvisible = this.IsInvisible; ret.IsControlMoveable = this.IsControlMoveable; ret.IsControlFaceable = this.IsControlFaceable; ret.IsChangeIcon = this.IsChangeIcon; ret.IconName = this.IconName; ret.OverrideAttackShape = CUtils.TryClone(this.OverrideAttackShape); ret.KeyFrames = CUtils.CloneList(this.KeyFrames); ret.BodyHit = CUtils.TryClone(this.BodyHit); ret.BodyHitSize = this.BodyHitSize; ret.BodyHitNextAction = this.BodyHitNextAction; ret.IsMoveToTarget = this.IsMoveToTarget; ret.MoveToTargetSpeedSEC = this.MoveToTargetSpeedSEC; ret.IsJumpToTarget = this.IsJumpToTarget; ret.JumpToTargetHeightZ = this.JumpToTargetHeightZ; ret.BodyBlockOnAttackRange = this.BodyBlockOnAttackRange; ret.IsShowSkillGuide = this.IsShowSkillGuide; ret.SigleActionType = this.SigleActionType; ret.MoveActionName = this.MoveActionName; ret.ActionSpeedRate = this.ActionSpeedRate; ret.IsAddSkillBtnBlock = this.IsAddSkillBtnBlock; ret.ActionAudioName = this.ActionAudioName; ret.IsAudioLoop = this.IsAudioLoop; return ret; } public void WriteExternal(IOutputStream output) { output.PutS32(this.TotalTimeMS); output.PutS32(this.ShowChargeTimeMS); output.PutUTF(this.ActionName); output.PutUTF(this.ActionEffectFileName); output.PutBool(this.IsCycAction); output.PutBool(this.IsCancelable); output.PutBool(this.IsCancelableBySkill); output.PutBool(this.IsCancelBySkillNext); output.PutBool(this.IsNoneBlock); output.PutBool(this.IsNoneTouch); output.PutBool(this.IsFaceToTarget); output.PutBool(this.IsInvisible); output.PutBool(this.IsControlMoveable); output.PutBool(this.IsControlFaceable); output.PutBool(this.IsChangeIcon); output.PutUTF(this.IconName); output.PutExt(this.OverrideAttackShape); output.PutList(this.KeyFrames, output.PutExt); output.PutExt(this.BodyHit); output.PutF32(this.BodyHitSize); output.PutBool(this.BodyHitNextAction); output.PutBool(this.IsMoveToTarget); output.PutF32(this.MoveToTargetSpeedSEC); output.PutBool(this.IsJumpToTarget); output.PutF32(this.JumpToTargetHeightZ); output.PutBool(this.BodyBlockOnAttackRange); output.PutBool(this.IsShowSkillGuide); output.PutEnum8(this.SigleActionType); output.PutUTF(this.MoveActionName); output.PutF32(this.ActionSpeedRate); output.PutBool(this.IsAddSkillBtnBlock); output.PutUTF(this.ActionAudioName); output.PutBool(this.IsAudioLoop); } public void ReadExternal(IInputStream input) { this.TotalTimeMS = input.GetS32(); this.ShowChargeTimeMS = input.GetS32(); this.ActionName = input.GetUTF(); this.ActionEffectFileName = input.GetUTF(); this.IsCycAction = input.GetBool(); this.IsCancelable = input.GetBool(); this.IsCancelableBySkill = input.GetBool(); this.IsCancelBySkillNext = input.GetBool(); this.IsNoneBlock = input.GetBool(); this.IsNoneTouch = input.GetBool(); this.IsFaceToTarget = input.GetBool(); this.IsInvisible = input.GetBool(); this.IsControlMoveable = input.GetBool(); this.IsControlFaceable = input.GetBool(); this.IsChangeIcon = input.GetBool(); this.IconName = input.GetUTF(); this.OverrideAttackShape = input.GetExt(); this.KeyFrames = input.GetList(input.GetExt); this.BodyHit = input.GetExt(); this.BodyHitSize = input.GetF32(); this.BodyHitNextAction = input.GetBool(); this.IsMoveToTarget = input.GetBool(); this.MoveToTargetSpeedSEC = input.GetF32(); this.IsJumpToTarget = input.GetBool(); this.JumpToTargetHeightZ = input.GetF32(); this.BodyBlockOnAttackRange = input.GetBool(); this.IsShowSkillGuide = input.GetBool(); this.SigleActionType = input.GetEnum8(); this.MoveActionName = input.GetUTF(); this.ActionSpeedRate = input.GetF32(); this.IsAddSkillBtnBlock = input.GetBool(); this.ActionAudioName = input.GetUTF(); this.IsAudioLoop = input.GetBool(); } //------------------------------------------------------------ /// /// 动作状态数据 /// [MessageType(0x4107)] [DescAttribute("动作关键帧数据")] [Expandable] public class StatusChange : ICloneable, IExternalizable { [DescAttribute("移动可取消动作", "状态")] public bool IsCancelable = false; [DescAttribute("技能可取消动作", "状态")] public bool IsCancelableBySkill = false; [DescAttribute("是否进入霸体状态,不会被打断", "状态")] public bool IsNoneBlock = false; [DescAttribute("动作期间是否无碰撞", "状态")] public bool IsNoneTouch = false; [DescAttribute("动作中是否面向目标", "状态")] public bool IsFaceToTarget = false; [DescAttribute("动作是否隐身", "状态")] public bool IsInvisible = false; [DescAttribute("动作中是否可以控制移动", "状态")] public bool IsControlMoveable = false; [DescAttribute("动作中可以控制转向", "状态")] public bool IsControlFaceable = false; public override string ToString() { return string.Format("{0}{1}{2}{3}{4}{5}{6}{7}", IsCancelable ? "移动可取消," : "", IsCancelableBySkill ? "技能可取消," : "", IsNoneBlock ? "霸体," : "", IsNoneTouch ? "无碰撞," : "", IsFaceToTarget ? "面向目标," : "", IsInvisible ? "隐身," : "", IsControlMoveable ? "可控制移动," : "", IsControlFaceable ? "可控制转向," : ""); } public object Clone() { StatusChange ret = new StatusChange(); ret.IsCancelable = this.IsCancelable; ret.IsCancelableBySkill = this.IsCancelableBySkill; ret.IsNoneBlock = this.IsNoneBlock; ret.IsNoneTouch = this.IsNoneTouch; ret.IsFaceToTarget = this.IsFaceToTarget; ret.IsInvisible = this.IsInvisible; ret.IsControlMoveable = this.IsControlMoveable; ret.IsControlFaceable = this.IsControlFaceable; return ret; } public void WriteExternal(IOutputStream output) { output.PutBool(this.IsCancelable); output.PutBool(this.IsCancelableBySkill); output.PutBool(this.IsNoneBlock); output.PutBool(this.IsNoneTouch); output.PutBool(this.IsFaceToTarget); output.PutBool(this.IsInvisible); output.PutBool(this.IsControlMoveable); output.PutBool(this.IsControlFaceable); } public void ReadExternal(IInputStream input) { this.IsCancelable = input.GetBool(); this.IsCancelableBySkill = input.GetBool(); this.IsNoneBlock = input.GetBool(); this.IsNoneTouch = input.GetBool(); this.IsFaceToTarget = input.GetBool(); this.IsInvisible = input.GetBool(); this.IsControlMoveable = input.GetBool(); this.IsControlFaceable = input.GetBool(); } } //------------------------------------------------------------ [MessageType(0x4108)] [DescAttribute("动作攻击范围")] [Expandable] public class AttackShape : ICloneable, IExternalizable { public enum Shape : byte { [DescAttribute("单体")] Single = CommonAI.Zone.Helper.AttackShape.Single, [DescAttribute("圆形")] Round = CommonAI.Zone.Helper.AttackShape.Round, [DescAttribute("扇形")] Fan = CommonAI.Zone.Helper.AttackShape.Fan, [DescAttribute("胶囊条状")] Strip = CommonAI.Zone.Helper.AttackShape.Strip, [DescAttribute("胶囊射线(以原点出去)")] StripRay = CommonAI.Zone.Helper.AttackShape.StripRay, [DescAttribute("胶囊射线,接触到最近")] StripRayTouchEnd = CommonAI.Zone.Helper.AttackShape.StripRayTouchEnd, [DescAttribute("方形条状")] RectStrip = CommonAI.Zone.Helper.AttackShape.RectStrip, [DescAttribute("方形射线(以原点出去)")] RectStripRay = CommonAI.Zone.Helper.AttackShape.RectStripRay, [DescAttribute("横向胶囊条状")] WideStrip = CommonAI.Zone.Helper.AttackShape.WideStrip, [DescAttribute("圆环,中间是空的")] Circle = CommonAI.Zone.Helper.AttackShape.Circle, } [DescAttribute("攻击范围类型", "攻击范围")] public Shape AShape = Shape.Round; [DescAttribute("半径(Round, Fan, Circle)长度(Strip, StripRay,StripRayTouchEnd, RectStrip, RectStripRay, LineToTarget, WideStrip)", "攻击范围")] public float AttackRange = 1; [DescAttribute("角度(Fan)", "攻击范围")] [DependOnProperty("IsShapeFan")] public float AttackAngle = 1; [DescAttribute("宽度,粗度(Strip, StripRay,StripRayTouchEnd,RectStrip, RectStripRay, WideStrip),环粗度(Circle)", "攻击范围")] [DependOnProperty("IsShapeStrip")] public float StripWide = 1; [DescAttribute("初始点偏移", "身体")] public float OffsetRadius = 0; public bool IsSingle { get { return AShape == Shape.Single; } } public bool IsShapeFan { get { return AShape == Shape.Fan; } } public bool IsShapeStrip { get { switch (AShape) { case Shape.Strip: case Shape.StripRay: case Shape.StripRayTouchEnd: case Shape.Circle: case Shape.RectStrip: case Shape.RectStripRay: case Shape.WideStrip: return true; } return false; } } public override string ToString() { return string.Format("重定向攻击范围:{0}", AShape); } public object Clone() { AttackShape ret = new AttackShape(); ret.AShape = this.AShape; ret.AttackRange = this.AttackRange; ret.AttackAngle = this.AttackAngle; ret.StripWide = this.StripWide; ret.OffsetRadius = this.OffsetRadius; return ret; } public void WriteExternal(IOutputStream output) { output.PutEnum8(this.AShape); output.PutF32(this.AttackRange); output.PutF32(this.AttackAngle); output.PutF32(this.StripWide); output.PutF32(this.OffsetRadius); } public void ReadExternal(IInputStream input) { this.AShape = input.GetEnum8(); this.AttackRange = input.GetF32(); this.AttackAngle = input.GetF32(); this.StripWide = input.GetF32(); this.OffsetRadius = input.GetF32(); } } //------------------------------------------------------------------------------------- //------------------------------------------------------------ [MessageType(0x4109)] [DescAttribute("动作攻击范围")] [Expandable] public class ThrowTarget : ICloneable, IExternalizable { public override string ToString() { return string.Format("重定向攻击范"); } public object Clone() { ThrowTarget ret = new ThrowTarget(); return ret; } public void WriteExternal(IOutputStream output) { } public void ReadExternal(IInputStream input) { } } //------------------------------------------------------------------------------------- //------------------------------------------------------------ /// /// 动作关键帧数据 /// [MessageType(0x4104)] [DescAttribute("动作关键帧数据")] [Expandable] public class KeyFrame : BaseKeyFrame, ICloneable, IExternalizable { /// /// 关键帧产生的法术或远程道具单位模板ID /// [DescAttribute("关键帧产生的法术或远程道具单位模板ID")] public LaunchSpell Spell; /// /// 当前关键帧特效 /// [DescAttribute("当前关键帧特效ID")] public LaunchEffect Effect; /// /// 攻击属性 /// [DescAttribute("攻击属性ID")] public AttackProp Attack; /// /// 对自己产生BUFF /// [DescAttribute("对自己产生BUFF")] public LaunchBuff SelfBuff; /// /// 此动作关键帧产生的位移 /// [DescAttribute("此动作关键帧产生的位移")] public StartMove Move; [DescAttribute("位移在有打击目标时是否生效")] public bool hitTargetMoveEnable = true; [DescAttribute("闪现位移")] public BlinkMove Blink; [DescAttribute("动作状态改变")] public StatusChange ChangeStatus; public KeyFrame() { } public override string ToString() { return "Frame: @" + FrameMS; } public object Clone() { KeyFrame ret = new KeyFrame(); ret.FrameMS = base.FrameMS; ret.Spell = CUtils.TryClone(this.Spell); ret.Effect = CUtils.TryClone(this.Effect); ret.Attack = CUtils.TryClone(this.Attack); ret.SelfBuff = CUtils.TryClone(this.SelfBuff); ret.Move = CUtils.TryClone(this.Move); ret.hitTargetMoveEnable = this.hitTargetMoveEnable; ret.Blink = CUtils.TryClone(this.Blink); ret.ChangeStatus = CUtils.TryClone(this.ChangeStatus); return ret; } public void WriteExternal(IOutputStream output) { output.PutS32(base.FrameMS); output.PutExt(this.Spell); output.PutExt(this.Effect); output.PutExt(this.Attack); output.PutExt(this.SelfBuff); output.PutExt(this.Move); output.PutBool(this.hitTargetMoveEnable); output.PutExt(this.Blink); output.PutExt(this.ChangeStatus); } public void ReadExternal(IInputStream input) { base.FrameMS = input.GetS32(); this.Spell = input.GetExt(); this.Effect = input.GetExt(); this.Attack = input.GetExt(); this.SelfBuff = input.GetExt(); this.Move = input.GetExt(); this.hitTargetMoveEnable = input.GetBool(); this.Blink = input.GetExt(); this.ChangeStatus = input.GetExt(); } } } //---------------------------------------------------------------------------------// /// /// 单位行为触发器 /// [MessageType(0x4010)] [DescAttribute("单位行为触发器")] [TableClassAttribute("ID")] public class UnitTriggerTemplate : ICloneable, ITemplateData, IExternalizable { public int TemplateID { get { return ID; } } [XmlSerializable()] public string EditorPath { get; set; } [DescAttribute("ID", "基础", false)] public int ID; [LocalizationTextAttribute] [DescAttribute("触发器名字", "基础")] public string Name; [DescAttribute("触发器冷却时间", "基础")] public int CoolDownTimeMS = 10000; [DescAttribute("事件触发条件(所有的关系为与)", "条件")] [ListAttribute(typeof(UnitTriggers.BaseTriggerEvent))] public List Triggers = new List(); [DescAttribute("释放技能", "动作")] public LaunchSkill DoSkill; [DescAttribute("产生Buff", "动作")] public LaunchBuff DoBuff; [DescAttribute("产生法术", "动作")] public LaunchSpell DoSpell; [DescAttribute("产生特效(图形)", "动作")] public LaunchEffect DoEffect; /// /// 召唤小弟 /// [DescAttribute("召唤小弟", "动作")] public SummonUnit DoSummon; //------------------------------------ /// /// 用户自定义扩展属性 /// [DescAttribute("扩展属性", "扩展")] [Expandable] [NotNull] public IUnitTriggerProperties Properties = TemplateManager.Factory.CreateTriggerProperties(); public override string ToString() { return Name + "(" + ID + ")"; } public string FunctionText() { StringBuilder sb = new StringBuilder(); if (Triggers.Count > 0) { foreach (UnitTriggers.BaseTriggerEvent e in Triggers) { sb.Append(string.Format("{0}", e)); if (e != Triggers[Triggers.Count - 1]) { sb.Append(" 并且 "); } } if (DoSkill != null) sb.Append("," + DoSkill); if (DoBuff != null) sb.Append("," + DoBuff); if (DoSpell != null) sb.Append("," + DoSpell); if (DoEffect != null) sb.Append("," + DoEffect); } return sb.ToString(); } public object Clone() { UnitTriggerTemplate ret = new UnitTriggerTemplate(); ret.EditorPath = this.EditorPath; ret.ID = this.ID; ret.Name = this.Name; ret.CoolDownTimeMS = this.CoolDownTimeMS; ret.Triggers = CUtils.CloneList(this.Triggers); ret.DoSkill = CUtils.TryClone(this.DoSkill); ret.DoBuff = CUtils.TryClone(this.DoBuff); ret.DoSpell = CUtils.TryClone(this.DoSpell); ret.DoEffect = CUtils.TryClone(this.DoEffect); ret.DoSummon = CUtils.TryClone(this.DoSummon); return ret; } public void WriteExternal(IOutputStream output) { output.PutUTF(this.EditorPath); output.PutS32(this.ID); output.PutUTF(this.Name); output.PutS32(this.CoolDownTimeMS); output.PutList(this.Triggers, output.PutExt); output.PutExt(this.DoSkill); output.PutExt(this.DoBuff); output.PutExt(this.DoSpell); output.PutExt(this.DoEffect); output.PutExt(this.DoSummon); } public void ReadExternal(IInputStream input) { this.EditorPath = input.GetUTF(); this.ID = input.GetS32(); this.Name = input.GetUTF(); this.CoolDownTimeMS = input.GetS32(); this.Triggers = input.GetListAny(); this.DoSkill = input.GetExt(); this.DoBuff = input.GetExt(); this.DoSpell = input.GetExt(); this.DoEffect = input.GetExt(); this.DoSummon = input.GetExt(); } } //---------------------------------------------------------------------------------// /// /// 法术/飞行道具模板 /// [MessageType(0x4005)] [DescAttribute("法术/飞行道具模板")] [TableClassAttribute("ID")] public class SpellTemplate : ICloneable, ITemplateData, IExternalizable { public int TemplateID { get { return ID; } } [XmlSerializable()] public string EditorPath { get; set; } public enum MotionType : byte { [DescAttribute("在原地不动")] Immovability = 1, [DescAttribute("按直线运动")] Straight = 2, [DescAttribute("跟随目标,直到击中")] Missile = 3, [DescAttribute("向周围扩散")] AOE = 4, [DescAttribute("绑定发射者")] Binding = 6, [DescAttribute("绑定被攻击者")] BindingTarget = 7, [DescAttribute("炮弹类")] Cannon = 8, [DescAttribute("直接在目标坐标生效")] SelectTarget = 9, [DescAttribute("先按直线运动,过程中锁定目标")] SeekerMissile = 10, [DescAttribute("向周围扩散,绑定发射者")] AOE_Binding = 11, [DescAttribute("向周围扩散,绑定被攻击者")] AOE_BindingTarget = 12, [DescAttribute("锁定并命中目标,和SeekerMissile区别是没有过程,直接命中。")] SeekerSelectTarget = 13, [DescAttribute("发射者和目标绑定(Distance必须在范围内)")] Chain = 14, [DescAttribute("直接在自身坐标生效")] SelectLauncher = 15, [DescAttribute("回旋镖路径1(最终返回到发射者)")] Boomerang1 = 16, [DescAttribute("回旋镖路径2(最终返回到发射点)")] Boomerang2 = 17, [DescAttribute("狐火路径")] Foxfire = 18, [DescAttribute("先直线,后停留")] StraightAndStop = 19, [DescAttribute("追踪,可击中路径上的敌人")] MissileAttackRoute = 20, [DescAttribute("曲线追踪")] CurveMissile = 21, } /// /// 往客户端推送,是否包含坐标 /// public bool IsLaunchSpellEventSyncPos { get { // 脱离运动类型的一些特殊字段 if(this.IsBindingOrbit) { return true; } switch (MType) { case SpellTemplate.MotionType.AOE_Binding: case SpellTemplate.MotionType.AOE_BindingTarget: case SpellTemplate.MotionType.Binding: case SpellTemplate.MotionType.BindingTarget: case SpellTemplate.MotionType.Chain: return false; case SpellTemplate.MotionType.SelectLauncher: case SpellTemplate.MotionType.SelectTarget: case SpellTemplate.MotionType.Immovability: case SpellTemplate.MotionType.Cannon: case SpellTemplate.MotionType.AOE: case SpellTemplate.MotionType.Straight: case SpellTemplate.MotionType.Missile: case SpellTemplate.MotionType.Boomerang1: case SpellTemplate.MotionType.Boomerang2: case SpellTemplate.MotionType.SeekerMissile: case SpellTemplate.MotionType.SeekerSelectTarget: case SpellTemplate.MotionType.StraightAndStop: case SpellTemplate.MotionType.MissileAttackRoute: case SpellTemplate.MotionType.CurveMissile: default: return true; } } } [DescAttribute("ID", "", false)] public int ID; /// /// 法术名字 /// [DescAttribute("法术名字")] [LocalizationTextAttribute] public string Name; /// /// 生命周期,帧 /// [DescAttribute("生命周期(毫秒)")] public int LifeTimeMS = 1000; [DescAttribute("客户端是否可见")] public bool ClientVisible = true; //-------------------------------------------- public enum Shape : byte { [DescAttribute("圆形(BodySize=半径尺寸)")] Round = AttackShape.Round, [DescAttribute("扇形(BodySize=半径尺寸;FanAngle=角度)")] Fan = AttackShape.Fan, [DescAttribute("胶囊条状(Distance=长度;RectWide=宽度)")] Strip = AttackShape.Strip, [DescAttribute("胶囊射线,以原点出去(Distance=长度;RectWide=宽度)")] StripRay = AttackShape.StripRay, [DescAttribute("胶囊射线,接触到最近(Distance=最大长度;RectWide=宽度)")] StripRayTouchEnd = AttackShape.StripRayTouchEnd, [DescAttribute("方形条状")] RectStrip = CommonAI.Zone.Helper.AttackShape.RectStrip, [DescAttribute("方形射线(以原点出去)")] RectStripRay = CommonAI.Zone.Helper.AttackShape.RectStripRay, [DescAttribute("横向胶囊条状")] WideStrip = CommonAI.Zone.Helper.AttackShape.WideStrip, [DescAttribute("连线类型(单体攻击),比如激光塔(Distance=判定距离)")] LineToTarget = AttackShape.LineToTarget, [DescAttribute("连线类型(单体攻击),比如伸出去的钩子(Distance=判定距离)")] LineToStart = AttackShape.LineToStart, [DescAttribute("圆环,中间是空的(BodySize=外环半径;BodySize-RectWide=内环半径)")] Circle = CommonAI.Zone.Helper.AttackShape.Circle, } public bool IsShapeFan { get { return BodyShape == Shape.Fan; } } public bool IsShapeStrip { get { switch (BodyShape) { case Shape.Strip: case Shape.StripRay: case Shape.StripRayTouchEnd: case Shape.Circle: case Shape.RectStrip: case Shape.RectStripRay: case Shape.WideStrip: return true; } return false; } } public bool IsShapeDistance { get { switch (BodyShape) { case Shape.Strip: case Shape.StripRay: case Shape.StripRayTouchEnd: case Shape.LineToTarget: case Shape.LineToStart: case Shape.RectStrip: case Shape.RectStripRay: case Shape.WideStrip: return true; default: return false; } } } //-------------------------------------------- [DescAttribute("攻击范围类型", "攻击范围")] public Shape BodyShape = Shape.Round; [DescAttribute("尺寸,半径(Round, Fan, Circle)", "攻击范围")] public float BodySize = 1; [DescAttribute("角度(Fan)", "攻击范围")] [DependOnProperty("IsShapeFan")] public float FanAngle; [DescAttribute("宽度,粗度(Strip, StripRay,StripRayTouchEnd,RectStrip, RectStripRay,Circle, WideStrip)", "攻击范围")] [DependOnProperty("IsShapeStrip")] public float RectWide = 1; [DescAttribute("长度(Strip, StripRay,StripRayTouchEnd, RectStrip, RectStripRay,LineToTarget, LineToStart, WideStrip)", "攻击范围")] [DependOnProperty("IsShapeDistance")] public float Distance = 10; //-------------------------------------------- [DescAttribute("法术自身高度", "攻击范围")] public float BodyHeight = 0; //-------------------------------------------- /// /// 运动类型 /// [DescAttribute("运动类型", "运动")] public MotionType MType = MotionType.Straight; public bool IsMoveable { get { switch (MType) { case MotionType.Cannon: case MotionType.Missile: case MotionType.SeekerMissile: case MotionType.Straight: case MotionType.AOE: case MotionType.AOE_Binding: case MotionType.AOE_BindingTarget: case MotionType.Boomerang1: case MotionType.Boomerang2: case MotionType.Foxfire: case MotionType.StraightAndStop: case MotionType.MissileAttackRoute: case MotionType.CurveMissile: return true; } return false; } } public bool IsBinding { get { switch (MType) { case MotionType.Binding: case MotionType.BindingTarget: case MotionType.AOE_Binding: case MotionType.AOE_BindingTarget: return true; } return false; } } public bool IsSeekingTarget { get { switch (MType) { case MotionType.SeekerMissile: case MotionType.SeekerSelectTarget: case MotionType.Foxfire: case MotionType.MissileAttackRoute: case MotionType.CurveMissile: return true; } return false; } } public bool IsAOE { get { switch (MType) { case MotionType.AOE: case MotionType.AOE_Binding: case MotionType.AOE_BindingTarget: return true; } return false; } } /// /// 运动速度,AOE或者扩散类,缩放速度 /// [DescAttribute("运动速度,AOE或者扩散类,缩放速度(距离 / 每秒)", "运动")] [DependOnProperty("IsMoveable")] public float MSpeedSEC = 15f; [DescAttribute("加速度(距离/每秒)(最终速度=速度+加速度)", "运动")] [DependOnProperty("IsMoveable")] public float MSpeedAdd = 0f; [DescAttribute("阻力(每秒递减速度百分比)", "运动")] [DependOnProperty("IsMoveable")] public float MSpeedAcc = 0f; [DescAttribute("最大移动距离", "运动")] public float MaxMoveDistance = 0f; [DescAttribute("最大限速", "运动")] [DependOnProperty("IsMoveable")] public float MSpeed_MAX = 100f; [DescAttribute("最小限速", "运动")] [DependOnProperty("IsMoveable")] public float MSpeed_MIN = -100f; //-------------------------------------------- public enum AoeMotionType : byte { [DescAttribute("线性,递增或递减")] Linear = 0, [DescAttribute("正弦,单次周期为PI,象限0~1")] Sine = 1, } [DescAttribute("AOE方式", "运动")] [DependOnProperty("IsAOE")] public AoeMotionType AOEMType = AoeMotionType.Linear; //-------------------------------------------- /// /// 转动速度 /// [DescAttribute("自转转动速度(距离/每秒)", "运动")] public float RotateSpeedSEC; [DescAttribute("抛物线高度", "运动")] public float ParabolaHeight = 0; /// /// /// [DescAttribute("暂时只给灵魂出窍的技能使用", "运动")] public bool HeightUpdate; //-------------------------------------------- public enum SeekingExpect : byte { [DescAttribute("搜索随机单位")] Random, [DescAttribute("搜索最近单位")] Nearest, [DescAttribute("搜索最远单位")] Farthest, [DescAttribute("搜索随机单位(忽略链中)")] RandomIgnoreInChain, [DescAttribute("搜索最近单位(忽略链中)")] NearestIgnoreInChain, [DescAttribute("搜索最远单位(忽略链中)")] FarthestIgnoreInChain, } //-------------------------------------------- [DescAttribute("如果是自动搜敌导弹SeekerMissile,则表示搜索范围,如果是LineToTarget则表示伤害距离", "运动-自动跟踪")] [DependOnProperty("IsSeekingTarget")] public float SeekingRange = 10; [DescAttribute("自动锁敌冷却时间(毫秒)", "运动-自动跟踪")] [DependOnProperty("IsSeekingTarget")] public int SeekingCooldownMS = 1000; [DescAttribute("自动锁敌运动时,转角距离", "运动-自动跟踪")] [DependOnProperty("IsSeekingTarget")] public float SeekingTurningAngleSEC = 3f; [DescAttribute("自动锁敌检测方式", "运动-自动跟踪")] [DependOnProperty("IsSeekingTarget")] public SeekingExpect SeekingExpectTarget = SeekingExpect.Random; //-------------------------------------------- [DescAttribute("如果是绑定则围绕绑定者公转", "运动-绑定")] [DependOnProperty("IsBinding")] public bool IsBindingOrbit = false; [DescAttribute("绑定公转距离", "运动-绑定")] [DependOnProperty("IsBinding")] public float OrbitDistance; [DescAttribute("如果为绑定,是否绑定方向", "运动-绑定")] [DependOnProperty("IsBinding")] public bool IsBindingDirection = false; //-------------------------------------------- //-------------------------------------------- [DescAttribute("最大影响(受击)单位,0表示无限制")] public int MaxAffectUnit = 0; //-------------------------------------------- /// /// 击中就消失 /// [DescAttribute("击中就消失(爆炸),和HitIntervalMS冲突", "关键帧")] public bool HitOnExplosion; [DescAttribute("击中就消失(爆炸)关键帧,适用于打到就爆和Cannon类法术", "关键帧")] [DependOnProperty("HitOnExplosion")] public KeyFrame HitOnExplosionKeyFrame; /// /// 每间隔多少帧就触发一次,0代表只造成一次伤害或效果 /// [DescAttribute("每间隔多少时间就触发一次,0 适用于穿透性,但只对单位造成一次伤害(毫秒)", "关键帧")] public int HitIntervalMS; [DescAttribute("只造成一次触发的关键帧 or 每隔一段时间触发的关键帧", "关键帧")] public KeyFrame HitIntervalKeyFrame; /// /// 按顺序触发的所有关键帧 /// [ListAttribute(typeof(KeyFrame))] [DescAttribute("按顺序触发的所有关键帧", "关键帧")] public List KeyFrames = new List(); //-------------------------------------------- /// /// 模型名字或者Perfab名字 /// [DescAttribute("模型名字或者Perfab名字", "资源")] [ResourceIDAttribute] public string FileName; [DescAttribute("模型名字或者Perfab名字(起始)", "资源")] [ResourceIDAttribute] public string FileNameSpawn; [DescAttribute("模型名字或者Perfab名字(结束)", "资源")] [ResourceIDAttribute] public string FileNameDestory; [DescAttribute("是否循环播放动画", "资源")] public bool IsCycAnim = true; [DescAttribute("缩放比率", "资源")] public float FileBodyScale = 1; [DescAttribute("法术释放时,在目标点释放特效,可作为技能提示", "特效")] public LaunchEffect TargetEffect; [DescAttribute("法术期望作用目标", "目标")] public SkillTemplate.CastTarget ExpectTarget = SkillTemplate.CastTarget.Enemy; //------------------------------------ [DescAttribute("绑定目标不可操控时移除自己", "移除条件")] public bool RemoveOnBindingUncontrollable = false; [DescAttribute("绑定目标非技能状态时移除自己", "移除条件")] public bool RemoveOnBindingSkillOver = false; [DescAttribute("当Spell被移除停止释放它的技能", "移除条件")] public bool StopBindingSkillOnRemoved = false; //------------------------------------ //-------------------------------------------- public enum SpecialAdditionalEffect : byte { [DescAttribute("无")] None = 0, [DescAttribute("黑洞效果,牵引碰到的怪物")] DarkHole = 1, [DescAttribute("路径牵引效果")] DragPath = 2, } public bool IsCanAddSpecialEffect { get { switch (MType) { case MotionType.Missile: case MotionType.SeekerMissile: case MotionType.Cannon: case MotionType.Chain: case MotionType.Boomerang1: case MotionType.Boomerang2: case MotionType.MissileAttackRoute: case MotionType.CurveMissile: return false; } return true; } } [DescAttribute("法术的特殊效果", "特殊效果")] [DependOnProperty("IsCanAddSpecialEffect")] public SpecialAdditionalEffect SpecialEffect = SpecialAdditionalEffect.None; [DescAttribute("特殊效果参数(黑洞的牵引速度)", "特殊效果")] [DependOnProperty("IsCanAddSpecialEffect")] public float SpecialEffectParam = 0; // -- [DescAttribute("飞行时间(毫秒)", "运动(回旋路径, 滞空)")] //[DependOnProperty("IsBoomerang")] public int BoomerangFlyTime = 1000; [DescAttribute("滞空时间(毫秒)", "运动(回旋路径, 滞空)")] //[DependOnProperty("IsBoomerang")] public int BoomerangHangtime = 1000; public bool IsBoomerang { get { return MType == MotionType.Boomerang1 || MType == MotionType.Boomerang2; } } /// /// 用户自定义扩展属性 /// [DescAttribute("扩展属性", "扩展")] [Expandable] [NotNull] public ISpellProperties Properties = TemplateManager.Factory.CreateSpellProperties(); //------------------------------------ [DescAttribute("速度(原始动画/特效速度 * 速度)", "特效加速")] public float EffectAddSpeed = 1; [DescAttribute("特效中存在的动画,动画的名字", "特效加速")] public string AnimtionName; [DescAttribute("音效文件名", "音效")] public string AudioName; [DescAttribute("音效文件是否循环", "音效")] public bool IsAudioLoop; public SpellTemplate() { } public int GetID() { return ID; } public override string ToString() { return Name + "(" + ID + ")"; } public object Clone() { SpellTemplate ret = new SpellTemplate(); ret.EditorPath = this.EditorPath; ret.ID = this.ID; ret.Name = this.Name; ret.LifeTimeMS = this.LifeTimeMS; ret.ClientVisible = this.ClientVisible; ret.BodyShape = this.BodyShape; ret.BodySize = this.BodySize; ret.FanAngle = this.FanAngle; ret.RectWide = this.RectWide; ret.BodyHeight = this.BodyHeight; ret.Distance = this.Distance; ret.MType = this.MType; ret.MSpeedSEC = this.MSpeedSEC; ret.MSpeedAdd = this.MSpeedAdd; ret.MSpeedAcc = this.MSpeedAcc; ret.MaxMoveDistance = this.MaxMoveDistance; ret.MSpeed_MAX = this.MSpeed_MAX; ret.MSpeed_MIN = this.MSpeed_MIN; ret.RotateSpeedSEC = this.RotateSpeedSEC; ret.ParabolaHeight = this.ParabolaHeight; ret.HeightUpdate = this.HeightUpdate; ret.AOEMType = this.AOEMType; ret.SeekingRange = this.SeekingRange; ret.SeekingCooldownMS = this.SeekingCooldownMS; ret.SeekingTurningAngleSEC = this.SeekingTurningAngleSEC; ret.SeekingExpectTarget = this.SeekingExpectTarget; ret.MaxAffectUnit = this.MaxAffectUnit; ret.IsBindingOrbit = this.IsBindingOrbit; ret.OrbitDistance = this.OrbitDistance; ret.IsBindingDirection = this.IsBindingDirection; ret.HitOnExplosion = this.HitOnExplosion; ret.HitOnExplosionKeyFrame = CUtils.TryClone(this.HitOnExplosionKeyFrame); ret.HitIntervalMS = this.HitIntervalMS; ret.HitIntervalKeyFrame = CUtils.TryClone(this.HitIntervalKeyFrame); ret.KeyFrames = CUtils.CloneList(this.KeyFrames); ret.FileName = this.FileName; ret.FileNameSpawn = this.FileNameSpawn; ret.FileNameDestory = this.FileNameDestory; ret.IsCycAnim = this.IsCycAnim; ret.FileBodyScale = this.FileBodyScale; ret.TargetEffect = CUtils.TryClone(this.TargetEffect); ret.ExpectTarget = this.ExpectTarget; ret.RemoveOnBindingUncontrollable = this.RemoveOnBindingUncontrollable; ret.RemoveOnBindingSkillOver = this.RemoveOnBindingSkillOver; ret.StopBindingSkillOnRemoved = this.StopBindingSkillOnRemoved; ret.Properties = CUtils.TryClone(this.Properties); ret.SpecialEffect = this.SpecialEffect; ret.SpecialEffectParam = this.SpecialEffectParam; ret.BoomerangFlyTime = this.BoomerangFlyTime; ret.BoomerangHangtime = this.BoomerangHangtime; ret.EffectAddSpeed = this.EffectAddSpeed; ret.AnimtionName = this.AnimtionName; ret.AudioName = this.AudioName; ret.IsAudioLoop = this.IsAudioLoop; return ret; } public void WriteExternal(IOutputStream output) { output.PutUTF(this.EditorPath); output.PutS32(this.ID); output.PutUTF(this.Name); output.PutS32(this.LifeTimeMS); output.PutBool(this.ClientVisible); output.PutEnum8(this.BodyShape); output.PutF32(this.BodySize); output.PutF32(this.FanAngle); output.PutF32(this.RectWide); output.PutF32(this.BodyHeight); output.PutF32(this.Distance); output.PutEnum8(this.MType); output.PutF32(this.MSpeedSEC); output.PutF32(this.MSpeedAdd); output.PutF32(this.MSpeedAcc); output.PutF32(this.MaxMoveDistance); output.PutF32(this.MSpeed_MAX); output.PutF32(this.MSpeed_MIN); output.PutF32(this.RotateSpeedSEC); output.PutF32(this.ParabolaHeight); output.PutBool(this.HeightUpdate); output.PutEnum8(this.AOEMType); output.PutF32(this.SeekingRange); output.PutS32(this.SeekingCooldownMS); output.PutF32(this.SeekingTurningAngleSEC); output.PutEnum8(this.SeekingExpectTarget); output.PutS32(this.MaxAffectUnit); output.PutBool(this.IsBindingOrbit); output.PutF32(this.OrbitDistance); output.PutBool(this.IsBindingDirection); output.PutBool(this.HitOnExplosion); output.PutExt(this.HitOnExplosionKeyFrame); output.PutS32(this.HitIntervalMS); output.PutExt(this.HitIntervalKeyFrame); output.PutList(this.KeyFrames, output.PutExt); output.PutUTF(this.FileName); output.PutUTF(this.FileNameSpawn); output.PutUTF(this.FileNameDestory); output.PutBool(this.IsCycAnim); output.PutF32(this.FileBodyScale); output.PutExt(this.TargetEffect); output.PutEnum8(this.ExpectTarget); output.PutBool(this.RemoveOnBindingUncontrollable); output.PutBool(this.RemoveOnBindingSkillOver); output.PutBool(this.StopBindingSkillOnRemoved); output.PutExt(this.Properties); output.PutEnum8(this.SpecialEffect); output.PutF32(this.SpecialEffectParam); output.PutS32(this.BoomerangFlyTime); output.PutS32(this.BoomerangHangtime); output.PutF32(this.EffectAddSpeed); output.PutUTF(this.AnimtionName); output.PutUTF(this.AudioName); output.PutBool(this.IsAudioLoop); } public void ReadExternal(IInputStream input) { this.EditorPath = input.GetUTF(); this.ID = input.GetS32(); this.Name = input.GetUTF(); this.LifeTimeMS = input.GetS32(); this.ClientVisible = input.GetBool(); this.BodyShape = input.GetEnum8(); this.BodySize = input.GetF32(); this.FanAngle = input.GetF32(); this.RectWide = input.GetF32(); this.BodyHeight = input.GetF32(); this.Distance = input.GetF32(); this.MType = input.GetEnum8(); this.MSpeedSEC = input.GetF32(); this.MSpeedAdd = input.GetF32(); this.MSpeedAcc = input.GetF32(); this.MaxMoveDistance = input.GetF32(); this.MSpeed_MAX = input.GetF32(); this.MSpeed_MIN = input.GetF32(); this.RotateSpeedSEC = input.GetF32(); this.ParabolaHeight = input.GetF32(); this.HeightUpdate = input.GetBool(); this.AOEMType = input.GetEnum8(); this.SeekingRange = input.GetF32(); this.SeekingCooldownMS = input.GetS32(); this.SeekingTurningAngleSEC = input.GetF32(); this.SeekingExpectTarget = input.GetEnum8(); this.MaxAffectUnit = input.GetS32(); this.IsBindingOrbit = input.GetBool(); this.OrbitDistance = input.GetF32(); this.IsBindingDirection = input.GetBool(); this.HitOnExplosion = input.GetBool(); this.HitOnExplosionKeyFrame = input.GetExt(); this.HitIntervalMS = input.GetS32(); this.HitIntervalKeyFrame = input.GetExt(); this.KeyFrames = input.GetList(input.GetExt); this.FileName = input.GetUTF(); this.FileNameSpawn = input.GetUTF(); this.FileNameDestory = input.GetUTF(); this.IsCycAnim = input.GetBool(); this.FileBodyScale = input.GetF32(); this.TargetEffect = input.GetExt(); this.ExpectTarget = input.GetEnum8(); this.RemoveOnBindingUncontrollable = input.GetBool(); this.RemoveOnBindingSkillOver = input.GetBool(); this.StopBindingSkillOnRemoved = input.GetBool(); this.Properties = input.GetExt(this.Properties); this.SpecialEffect = input.GetEnum8(); this.SpecialEffectParam = input.GetF32(); this.BoomerangFlyTime = input.GetS32(); this.BoomerangHangtime = input.GetS32(); this.EffectAddSpeed = input.GetF32(); this.AnimtionName = input.GetUTF(); this.AudioName = input.GetUTF(); this.IsAudioLoop = input.GetBool(); } //------------------------------------------------------------ //------------------------------------------------------------ /// /// 法术伤害或特效关键帧 /// [MessageType(0x4105)] [DescAttribute("法术伤害或特效关键帧")] [Expandable] public class KeyFrame : BaseKeyFrame, ICloneable, IExternalizable { /// /// 触发的特效 /// [DescAttribute("触发的特效")] public LaunchEffect Effect; /// /// 触发新的法术 /// [DescAttribute("触发新的法术")] public LaunchSpell Spell; /// /// 攻击伤害 /// [DescAttribute("攻击伤害")] public AttackProp Attack; /// /// 召唤小弟 /// [DescAttribute("召唤小弟")] public SummonUnit Summon; public KeyFrame() { } public override string ToString() { if (Spell == null) { return "Frame: @" + FrameMS; } return "Frame: @" + FrameMS + ", " + Spell.ToString(); } public object Clone() { KeyFrame ret = new KeyFrame(); ret.FrameMS = this.FrameMS; ret.Spell = CUtils.TryClone(this.Spell); ret.Effect = CUtils.TryClone(this.Effect); ret.Attack = CUtils.TryClone(this.Attack); ret.Summon = CUtils.TryClone(this.Summon); return ret; } public void WriteExternal(IOutputStream output) { output.PutS32(base.FrameMS); output.PutExt(this.Spell); output.PutExt(this.Effect); output.PutExt(this.Attack); output.PutExt(this.Summon); } public void ReadExternal(IInputStream input) { base.FrameMS = input.GetS32(); this.Spell = input.GetExt(); this.Effect = input.GetExt(); this.Attack = input.GetExt(); this.Summon = input.GetExt(); } } } //---------------------------------------------------------------------------------// /// /// BUFF类数据结构 /// [MessageType(0x4006)] [DescAttribute("BUFF类数据结构")] [TableClassAttribute("ID")] public class BuffTemplate : ICloneable, ITemplateData, IExternalizable { public int TemplateID { get { return ID; } } [XmlSerializable()] public string EditorPath { get; set; } [DescAttribute("ID", "", false)] public int ID; [LocalizationTextAttribute] [DescAttribute("Buff名字")] public string Name; [DescAttribute("技能图标", "资源")] public string IconName; [DescAttribute("需要同步客户端")] public bool ClientVisible = true; [DescAttribute("生命周期(毫秒)")] public int LifeTimeMS; //-------------------------------------------------------------- [DescAttribute("每间隔多少毫秒就触发一次", "关键帧")] public int HitIntervalMS; [DescAttribute("第0帧是否有效", "关键帧")] public bool FirstTimeEnable = true; [DescAttribute("每间隔时间触发一次的时候起效", "关键帧")] public KeyFrame HitKeyFrame; [ListAttribute(typeof(KeyFrame))] [DescAttribute("所有关键帧", "关键帧")] public List KeyFrames = new List(); [DescAttribute("Buff结束关键帧", "关键帧")] public KeyFrame EndKeyFrame; //-------------------------------------------------------------- [DescAttribute("是否有害(Debuff),否则为有益(Buff)", "BUFF")] public bool IsHarmful = false; [DescAttribute("Buff是否可以主动取消", "BUFF")] public bool IsCancelBySelf = false; [DescAttribute("Buff是否允许多个实例", "BUFF")] public bool IsDuplicating = false; [DescAttribute("Buff施放者死亡立即移除", "BUFF")] public bool IsRemoveOnSenderRemoved = true; [DescAttribute("死亡立即移除", "BUFF")] public bool IsRemoveOnDead = false; //-------------------------------------------------------------- [DescAttribute("BUFF期间,强制单位进入BUFF特殊动作(即不会被其他动作打断)", "状态")] public string LockStateAction; [DescAttribute("是否隐身", "状态")] public bool IsInvisible = false; [DescAttribute("是否无敌", "状态")] public bool IsInvincible = false; [DescAttribute("是否沉默(只能释放BaseSkill)", "状态")] public bool IsSilent = false; [DescAttribute("是否沉默允许移动", "状态")] public bool IsCanMove = true; [DescAttribute("产生眩晕", "状态")] public bool MakeStun = false; [DescAttribute("免疫控制", "状态")] public bool IgnoreControl = false; [DescAttribute("单位被动触发系,一直绑定关系", "状态")] public LaunchTrigger UnitTrigger; //-------------------------------------------------------------- [DescAttribute("允许变身", "变身 - 造型")] public bool MakeAvatar = false; [DescAttribute("单位变身的模型文件名", "变身 - 造型")] [ResourceIDAttribute] [DependOnProperty("MakeAvatar")] public string UnitFileName; //-------------------------------------------------------------- [DescAttribute("允许改变技能", "变身 - 技能")] public bool UnitChangeSkills = false; [DescAttribute("此单位变身普通攻击技能", "变身 - 技能")] [DependOnProperty("UnitChangeSkills")] public LaunchSkill UnitBaseSkillID; [ListAttribute(typeof(LaunchSkill))] [DescAttribute("此单位变身绑定的所有技能ID", "变身 - 技能")] [DependOnProperty("UnitChangeSkills")] public List UnitSkills = new List(); [DescAttribute("变身改变技能时,保留的技能ID", "变身 - 技能")] [TemplatesIDAttribute(typeof(SkillTemplate))] [DependOnProperty("UnitChangeSkills")] public List UnitKeepSkillsID = new List(); //-------------------------------------------------------------- //-------------------------------------------------------------- [DescAttribute("是否可堆叠层数", "堆叠")] public bool IsOverlay = false; [DescAttribute("最高可堆叠层数", "堆叠")] [DependOnProperty("IsOverlay")] public byte MaxOverlay = 1; [DescAttribute("是否为被动系,则不显示在面板")] public bool IsPassive = false; public enum BindingPlayType : byte { [DescAttribute("一次性全部播放,配置多少,播放多少")] All = 0, [DescAttribute("根据层数去播放,那一层播放那一个")] AppointOverLayer = 1, [DescAttribute("包含层数,如果层数是2,会同时播放1和2的特效")] IncludeOverLayer = 2, } [DescAttribute("BindingEffectList的播放模式(客户端用)", "特效")] public BindingPlayType PlayType = BindingPlayType.All; [DescAttribute("BUFF期间绑定特效(客户端用)", "特效")] public LaunchEffect BindingEffect; [ListAttribute(typeof(LaunchEffect))] [DescAttribute("BUFF期间绑定特效集合(客户端用)", "特效")] public List BindingEffectList = new List(); [ListAttribute(typeof(LaunchEffect))] [DescAttribute("BUFF期间每层绑定特效(每层对应一个特效,客户端用)", "特效")] [DependOnProperty("IsOverlay")] public List OverlayBindingEffect = new List(); //-------------------------------------------------------------- [DescAttribute("互斥类型,同类型不能出现两个(非0有效)", "互斥")] public int ExclusiveCatgory; [DescAttribute("互斥优先级,如果优先级相等,则替换", "互斥")] public int ExclusivePriority; //-------------------------------------------------------------- [DescAttribute("Buff用户自定义扩展属性", "扩展")] [Expandable] [NotNull] public IBuffProperties Properties; [DescAttribute("自定义字段", "属性", true)] public string[] Attributes; //内部使用的一些字段, [DescAttribute("强制加,跳过boss免控限制", "属性", true)] public bool forceAdd; public BuffTemplate() { this.Properties = TemplateManager.Factory.CreateBuffProperties(); } public int GetID() { return ID; } public override string ToString() { return Name + "(" + ID + ")"; } public object Clone() { BuffTemplate ret = new BuffTemplate(); ret.EditorPath = this.EditorPath; ret.ID = this.ID; ret.Name = this.Name; ret.IconName = this.IconName; ret.ClientVisible = this.ClientVisible; ret.LifeTimeMS = this.LifeTimeMS; ret.HitIntervalMS = this.HitIntervalMS; ret.FirstTimeEnable = this.FirstTimeEnable; ret.HitKeyFrame = CUtils.TryClone(this.HitKeyFrame); ret.KeyFrames = CUtils.CloneList(this.KeyFrames); ret.IsHarmful = this.IsHarmful; ret.IsCancelBySelf = this.IsCancelBySelf; ret.IsDuplicating = this.IsDuplicating; ret.EndKeyFrame = CUtils.TryClone(this.EndKeyFrame); ret.IsInvisible = this.IsInvisible; ret.IsInvincible = this.IsInvincible; ret.IsSilent = this.IsSilent; ret.IsCanMove = this.IsCanMove; ret.MakeStun = this.MakeStun; ret.IgnoreControl = this.IgnoreControl; ret.IsRemoveOnSenderRemoved = this.IsRemoveOnSenderRemoved; ret.IsRemoveOnDead = this.IsRemoveOnDead; ret.LockStateAction = this.LockStateAction; ret.UnitTrigger = CUtils.TryClone(this.UnitTrigger); ret.MakeAvatar = this.MakeAvatar; ret.UnitFileName = this.UnitFileName; ret.UnitChangeSkills = this.UnitChangeSkills; ret.UnitBaseSkillID = CUtils.TryClone(this.UnitBaseSkillID); ret.UnitSkills = CUtils.CloneList(this.UnitSkills); ret.UnitKeepSkillsID = new List(this.UnitKeepSkillsID); ret.IsOverlay = this.IsOverlay; ret.MaxOverlay = this.MaxOverlay; ret.IsPassive = this.IsPassive; ret.BindingEffect = CUtils.TryClone(this.BindingEffect); ret.PlayType = this.PlayType; ret.BindingEffectList = CUtils.CloneList(this.BindingEffectList); ret.OverlayBindingEffect = CUtils.CloneList(this.OverlayBindingEffect); ret.ExclusiveCatgory = this.ExclusiveCatgory; ret.ExclusivePriority = this.ExclusivePriority; ret.Properties = CUtils.TryClone(this.Properties); ret.Attributes = CUtils.CloneArray(this.Attributes); ret.forceAdd = this.forceAdd; return ret; } public void WriteExternal(IOutputStream output) { output.PutUTF(this.EditorPath); output.PutS32(this.ID); output.PutUTF(this.Name); output.PutUTF(this.IconName); output.PutS32(this.LifeTimeMS); output.PutBool(this.ClientVisible); output.PutS32(this.HitIntervalMS); output.PutBool(this.FirstTimeEnable); output.PutExt(this.HitKeyFrame); output.PutList(this.KeyFrames, output.PutExt); output.PutExt(this.EndKeyFrame); output.PutBool(this.IsHarmful); output.PutBool(this.IsCancelBySelf); output.PutBool(this.IsDuplicating); output.PutBool(this.IsInvisible); output.PutBool(this.IsInvincible); output.PutBool(this.IsSilent); output.PutBool(this.IsCanMove); output.PutBool(this.MakeStun); output.PutBool(this.IgnoreControl); output.PutBool(this.IsRemoveOnSenderRemoved); output.PutBool(this.IsRemoveOnDead); output.PutUTF(this.LockStateAction); output.PutExt(this.UnitTrigger); output.PutBool(this.MakeAvatar); output.PutUTF(this.UnitFileName); output.PutBool(this.UnitChangeSkills); output.PutExt(this.UnitBaseSkillID); output.PutList(this.UnitSkills, output.PutExt); output.PutList(this.UnitKeepSkillsID, output.PutS32); output.PutBool(this.IsOverlay); output.PutU8(this.MaxOverlay); output.PutBool(this.IsPassive); output.PutExt(this.BindingEffect); output.PutEnum8(this.PlayType); output.PutList(this.BindingEffectList, output.PutExt); output.PutList(this.OverlayBindingEffect, output.PutExt); output.PutS32(this.ExclusiveCatgory); output.PutS32(this.ExclusivePriority); output.PutExt(this.Properties); output.PutArray(this.Attributes, output.PutUTF); output.PutBool(this.forceAdd); } public void ReadExternal(IInputStream input) { this.EditorPath = input.GetUTF(); this.ID = input.GetS32(); this.Name = input.GetUTF(); this.IconName = input.GetUTF(); this.LifeTimeMS = input.GetS32(); this.ClientVisible = input.GetBool(); this.HitIntervalMS = input.GetS32(); this.FirstTimeEnable = input.GetBool(); this.HitKeyFrame = input.GetExt(); this.KeyFrames = input.GetList(input.GetExt); this.EndKeyFrame = input.GetExt(); this.IsHarmful = input.GetBool(); this.IsCancelBySelf = input.GetBool(); this.IsDuplicating = input.GetBool(); this.IsInvisible = input.GetBool(); this.IsInvincible = input.GetBool(); this.IsSilent = input.GetBool(); this.IsCanMove = input.GetBool(); this.MakeStun = input.GetBool(); this.IgnoreControl = input.GetBool(); this.IsRemoveOnSenderRemoved = input.GetBool(); this.IsRemoveOnDead = input.GetBool(); this.LockStateAction = input.GetUTF(); this.UnitTrigger = input.GetExt(); this.MakeAvatar = input.GetBool(); this.UnitFileName = input.GetUTF(); this.UnitChangeSkills = input.GetBool(); this.UnitBaseSkillID = input.GetExt(); this.UnitSkills = input.GetList(input.GetExt); this.UnitKeepSkillsID = input.GetList(input.GetS32); this.IsOverlay = input.GetBool(); this.MaxOverlay = input.GetU8(); this.IsPassive = input.GetBool(); this.BindingEffect = input.GetExt(); this.PlayType = input.GetEnum8(); this.BindingEffectList = input.GetList(input.GetExt); this.OverlayBindingEffect = input.GetList(input.GetExt); this.ExclusiveCatgory = input.GetS32(); this.ExclusivePriority = input.GetS32(); this.Properties = input.GetExt(this.Properties); this.Attributes = input.GetUTFArray(); this.forceAdd = input.GetBool(); } //-------------------------------------------- //-------------------------------------------- /// /// BUFF伤害或特效关键帧 /// [MessageType(0x4106)] [DescAttribute("BUFF伤害或特效关键帧")] [Expandable] public class KeyFrame : BaseKeyFrame, ICloneable, IExternalizable { /// /// 触发的特效 /// [DescAttribute("触发的特效")] public LaunchEffect Effect; /// /// 触发新的法术 /// [DescAttribute("触发新的法术")] public LaunchSpell Spell; /// /// 攻击伤害 /// [DescAttribute("攻击伤害")] public AttackProp Attack; /// /// 直接使用道具 /// [DescAttribute("直接使用道具")] public UseItem Item; /// /// 直接使用道具 /// [DescAttribute("场景添加道具")] public BuffAddItem addItem; public KeyFrame() { } public override string ToString() { return "Frame: @" + FrameMS; } public object Clone() { KeyFrame ret = new KeyFrame(); ret.FrameMS = this.FrameMS; ret.Spell = CUtils.TryClone(this.Spell); ret.Effect = CUtils.TryClone(this.Effect); ret.Attack = CUtils.TryClone(this.Attack); ret.Item = CUtils.TryClone(this.Item); ret.addItem = CUtils.TryClone(this.addItem); return ret; } public void WriteExternal(IOutputStream output) { output.PutS32(base.FrameMS); output.PutExt(this.Spell); output.PutExt(this.Effect); output.PutExt(this.Attack); output.PutExt(this.Item); output.PutExt(this.addItem); } public void ReadExternal(IInputStream input) { base.FrameMS = input.GetS32(); this.Spell = input.GetExt(); this.Effect = input.GetExt(); this.Attack = input.GetExt(); this.Item = input.GetExt(); this.addItem = input.GetExt(); } } } //---------------------------------------------------------------------------------// //---------------------------------------------------------------------------------// /// /// 掉落道具类数据结构 /// [MessageType(0x4007)] [DescAttribute("掉落道具类数据结构")] [TableClassAttribute("ID")] public class ItemTemplate : ICloneable, ITemplateData, IExternalizable { public int TemplateID { get { return ID; } } [XmlSerializable()] public string EditorPath { get; set; } [DescAttribute("ID", "", false)] public int ID; [LocalizationTextAttribute] [DescAttribute("掉落道具名字", "道具")] public string Name; [DescAttribute("掉落道具名字", "道具")] public string IconName; [DescAttribute("使用间隔时间(毫秒)", "道具")] public int UseCoolDownTimeMS = 0; [DescAttribute("场景显示的名字", "道具")] public string DisplayName; [DescAttribute("道具是否可被手动检取(如果手动检取,则不能直接走上去获得)", "捡取")] public bool Pickable = false; [DescAttribute("手动检取读条时间(毫秒)", "捡取")] [DependOnProperty("Pickable")] public int PickTimeMS = 2000; [DescAttribute("拾取后删除", "捡取")] public bool RemoveOnFinishPick = true; [DescAttribute("最大拾取人数", "捡取")] public byte maxPickPlayers = 0; [DescAttribute("单人最大拾取次数", "捡取")] public short maxPickTimes = 0; [DescAttribute("掉落后多久可以获得(毫秒)", "掉落")] public int GotCoolDownTimeMS = 500; [DescAttribute("掉落道具全阵营有效", "掉落")] public bool DropForAll; [DescAttribute("掉落道具仅玩家有效", "掉落")] public bool PlayerOnly = true; [DescAttribute("获得即使用", "掉落")] public bool GotOnUse = true; [DescAttribute("掉落金币最小值", "掉落")] public int DropMoneyMin = 0; [DescAttribute("掉落金币最大值", "掉落")] public int DropMoneyMax = 0; [DescAttribute("获得后的特效(检取者)", "特效")] public LaunchEffect GotEffect; [DescAttribute("获得后的特效(自身)", "特效")] public LaunchEffect GotEffectSelf; [DescAttribute("掉落时的特效", "特效")] public LaunchEffect DropEffect; [ResourceIDAttribute] [DescAttribute("资源模型名字", "资源")] public string FileName; [DescAttribute("拾取范围,半径", "资源")] public float BodySize = 1f; [DescAttribute("客户端可见", "资源")] public bool ClientVisible = true; [DescAttribute("道具产生后,持续时间(毫秒)", "掉落")] public int LifeTimeMS = 10000; [DescAttribute("道具产生后,显示截止时间戳(秒)", "掉落")] public int LifeEndTime = 0; [DescAttribute("道具飞到拾取者身上的插值(仅客户端表现用)", "掉落")] public float FlyLerp = 0.1f; [DescAttribute("是否显示持续时间 ", "掉落")] public bool showLifeTime = false; [DescAttribute("物品掉落的动画时长(毫秒)", "掉落")] public float AnimatorTime = -1.0f; [DescAttribute("仅做显示用", "掉落")] public bool OnlyForShow = false; [DescAttribute("模型上是否显示品质光柱", "掉落")] public bool ShowQualityEffect = true; [DescAttribute("使用后的特效", "特效")] public LaunchEffect UseEffect; [DescAttribute("使用后释放一个法术", "使用")] public LaunchSpell UseSpell; [DescAttribute("使用后召唤单位", "使用")] public SummonUnit UseSummon; [DescAttribute("使用后增加BUFF列表", "使用")] [ListAttribute(typeof(LaunchBuff))] public List UseBuffs = new List(); [DescAttribute("装备后增加BUFF列表", "装备")] [ListAttribute(typeof(LaunchBuff))] public List EquipBuffs = new List(); [DescAttribute("在背包内最大堆叠数量", "背包")] public int MaxStackCount = 100; [DescAttribute("最大持有数量,0表示无上限", "背包")] public int HoldingLimit = 0; [DescAttribute("是否在背包内可使用", "背包")] public bool IsInventoryUseable = true; [DescAttribute("是否可携带多个(包括堆叠)", "背包")] public bool IsDuplicateInventory = true; [DescAttribute("同步到服务器(可持久化保存的道具)", "背包")] public bool SyncToServer = false; [DescAttribute("背包道具使用读条(毫秒)", "背包")] public int UseInProgressTimeMS = 0; [DescAttribute("购买花费金币", "购买")] public bool BuyCostMoney; [DescAttribute("出售花费金币", "购买")] public bool SellGotMoney; [DescAttribute("是否弹出非物品类的二级面板", "显示")] public bool IsPopPanel = false; [ListAttribute(typeof(FlyEffect))] [DescAttribute("飞行特效", "妖气修为")] public List Fly; /// /// 道具扩展属性 /// [DescAttribute("道具扩展属性", "扩展")] [Expandable] [NotNull] public IItemProperties Properties; public ItemTemplate() { this.Properties = TemplateManager.Factory.CreateItemProperties(); } public ItemTemplate(int id) { this.ID = id; this.Properties = TemplateManager.Factory.CreateItemProperties(); } public int GetID() { return ID; } public override string ToString() { return Name + "(" + ID + ")"; } public object Clone() { ItemTemplate ret = new ItemTemplate(); ret.EditorPath = this.EditorPath; ret.ID = this.ID; ret.Name = this.Name; ret.IconName = this.IconName; ret.Pickable = this.Pickable; ret.PickTimeMS = this.PickTimeMS; ret.RemoveOnFinishPick = this.RemoveOnFinishPick; ret.GotCoolDownTimeMS = this.GotCoolDownTimeMS; ret.DropForAll = this.DropForAll; ret.PlayerOnly = this.PlayerOnly; ret.GotOnUse = this.GotOnUse; ret.DropMoneyMin = this.DropMoneyMin; ret.DropMoneyMax = this.DropMoneyMax; ret.GotEffect = CUtils.TryClone(this.GotEffect); ret.GotEffectSelf = CUtils.TryClone(this.GotEffectSelf); ret.DropEffect = CUtils.TryClone(this.DropEffect); ret.FileName = this.FileName; ret.BodySize = this.BodySize; ret.ClientVisible = this.ClientVisible; ret.LifeTimeMS = this.LifeTimeMS; ret.UseEffect = CUtils.TryClone(this.UseEffect); ret.UseSpell = CUtils.TryClone(this.UseSpell); ret.UseSummon = CUtils.TryClone(this.UseSummon); ret.UseBuffs = CUtils.CloneList(this.UseBuffs); ret.EquipBuffs = CUtils.CloneList(this.EquipBuffs); ret.MaxStackCount = this.MaxStackCount; ret.HoldingLimit = this.HoldingLimit; ret.IsInventoryUseable = this.IsInventoryUseable; ret.UseCoolDownTimeMS = this.UseCoolDownTimeMS; ret.IsDuplicateInventory = this.IsDuplicateInventory; ret.SyncToServer = this.SyncToServer; ret.UseInProgressTimeMS = this.UseInProgressTimeMS; ret.FlyLerp = this.FlyLerp; ret.showLifeTime = this.showLifeTime; ret.AnimatorTime = this.AnimatorTime; ret.LifeEndTime = this.LifeEndTime; ret.IsPopPanel = this.IsPopPanel; ret.Fly = CUtils.CloneList(this.Fly); ret.Properties = CUtils.TryClone(this.Properties); ret.maxPickPlayers = this.maxPickPlayers; ret.maxPickTimes = this.maxPickTimes; ret.OnlyForShow = this.OnlyForShow; ret.DisplayName = this.DisplayName; ret.ShowQualityEffect = this.ShowQualityEffect; return ret; } public void WriteExternal(IOutputStream output) { output.PutUTF(this.EditorPath); output.PutS32(this.ID); output.PutUTF(this.Name); output.PutUTF(this.IconName); output.PutBool(this.Pickable); output.PutS32(this.PickTimeMS); output.PutBool(this.RemoveOnFinishPick); output.PutS32(this.GotCoolDownTimeMS); output.PutBool(this.DropForAll); output.PutBool(this.PlayerOnly); output.PutBool(this.GotOnUse); output.PutS32(this.DropMoneyMin); output.PutS32(this.DropMoneyMax); output.PutExt(this.GotEffect); output.PutExt(this.GotEffectSelf); output.PutExt(this.DropEffect); output.PutUTF(this.FileName); output.PutF32(this.BodySize); output.PutBool(this.ClientVisible); output.PutS32(this.LifeTimeMS); output.PutExt(this.UseEffect); output.PutExt(this.UseSpell); output.PutExt(this.UseSummon); output.PutList(this.UseBuffs, output.PutExt); output.PutList(this.EquipBuffs, output.PutExt); output.PutS32(this.MaxStackCount); output.PutS32(this.HoldingLimit); output.PutBool(this.IsInventoryUseable); output.PutS32(this.UseCoolDownTimeMS); output.PutBool(this.IsDuplicateInventory); output.PutBool(this.SyncToServer); output.PutS32(this.UseInProgressTimeMS); output.PutExt(this.Properties); output.PutBool(this.showLifeTime); output.PutF32(this.FlyLerp); if (this.showLifeTime) { output.PutS32(this.LifeEndTime); } output.PutF32(this.AnimatorTime); output.PutBool(this.IsPopPanel); output.PutList(this.Fly, output.PutExt); output.PutS16(this.maxPickTimes); output.PutU8(this.maxPickPlayers); output.PutBool(this.OnlyForShow); output.PutUTF(this.DisplayName); output.PutBool(this.ShowQualityEffect); } public void ReadExternal(IInputStream input) { this.EditorPath = input.GetUTF(); this.ID = input.GetS32(); this.Name = input.GetUTF(); this.IconName = input.GetUTF(); this.Pickable = input.GetBool(); this.PickTimeMS = input.GetS32(); this.RemoveOnFinishPick = input.GetBool(); this.GotCoolDownTimeMS = input.GetS32(); this.DropForAll = input.GetBool(); this.PlayerOnly = input.GetBool(); this.GotOnUse = input.GetBool(); this.DropMoneyMin = input.GetS32(); this.DropMoneyMax = input.GetS32(); this.GotEffect = input.GetExt(); this.GotEffectSelf = input.GetExt(); this.DropEffect = input.GetExt(); this.FileName = input.GetUTF(); this.BodySize = input.GetF32(); this.ClientVisible = input.GetBool(); this.LifeTimeMS = input.GetS32(); this.UseEffect = input.GetExt(); this.UseSpell = input.GetExt(); this.UseSummon = input.GetExt(); this.UseBuffs = input.GetList(input.GetExt); this.EquipBuffs = input.GetList(input.GetExt); this.MaxStackCount = input.GetS32(); this.HoldingLimit = input.GetS32(); this.IsInventoryUseable = input.GetBool(); this.UseCoolDownTimeMS = input.GetS32(); this.IsDuplicateInventory = input.GetBool(); this.SyncToServer = input.GetBool(); this.UseInProgressTimeMS = input.GetS32(); this.Properties = input.GetExt(this.Properties); this.showLifeTime = input.GetBool(); this.FlyLerp = input.GetF32(); if (this.showLifeTime) { this.LifeEndTime = input.GetS32(); } this.AnimatorTime = input.GetF32(); this.IsPopPanel = input.GetBool(); this.Fly = input.GetList(input.GetExt); this.maxPickTimes = input.GetS16(); this.maxPickPlayers = input.GetU8(); this.OnlyForShow = input.GetBool(); this.DisplayName = input.GetUTF(); this.ShowQualityEffect = input.GetBool(); } } [MessageType(0x4018)] [DescAttribute("物品飞行特效")] [Expandable] public class FlyEffect : ICloneable, IExternalizable { [DescAttribute("特效名字")] public string Name; [DescAttribute("特效时长(秒数)")] public float Time; [DescAttribute("以玩家为目标点")] public bool isActorPos; [DescAttribute("是否绑定在节点上")] public bool isBindPart; [DescAttribute("特效飞至的部位")] public string PartName; [DescAttribute("特效拉升的高度")] public float Height; [DescAttribute("特效速度")] public float Speed; [DescAttribute("运行方向 0:原点 1:上 2:下 3:左 4:右 5:前 6:后")] public byte RunDirection = 0; [DescAttribute("音效文件名")] public string AudioName; [DescAttribute("是否到达玩家位置就删除特效")] public bool IsGoToActorPosAndRemove; [DescAttribute("特效和玩家之间的最小距离,小于等于这个距离,这个特效将会移除")] [DependOnProperty("IsGoToActorPosAndRemove")] public float MinDistance = 0.05f; [DescAttribute("基于此节点激活间隔时长")] public bool IsBeginActiveIntervalTime = false; [DescAttribute("间隔时长,基于激活后的时间间隔")] public float IntervalTime = -1; [DescAttribute("此特效移除后,关联下一个特效的index")] public int NextEffectIndex = -1; [DescAttribute("此特效生成时,基于那个index特效的坐标")] public int PosIndex = -1; public object Clone() { FlyEffect ret = new FlyEffect(); ret.Name = this.Name; ret.Time = this.Time; ret.PartName = this.PartName; ret.Height = this.Height; ret.isActorPos = this.isActorPos; ret.isBindPart = this.isBindPart; ret.Speed = this.Speed; ret.RunDirection = this.RunDirection; ret.AudioName = this.AudioName; ret.IsGoToActorPosAndRemove = this.IsGoToActorPosAndRemove; ret.IsBeginActiveIntervalTime = this.IsBeginActiveIntervalTime; ret.IntervalTime = this.IntervalTime; ret.NextEffectIndex = this.NextEffectIndex; ret.PosIndex = this.PosIndex; return ret; } public void ReadExternal(IInputStream input) { this.Name = input.GetUTF(); this.Time = input.GetF32(); this.PartName = input.GetUTF(); this.Height = input.GetF32(); this.isActorPos = input.GetBool(); this.isBindPart = input.GetBool(); this.Speed = input.GetF32(); this.RunDirection = input.GetU8(); this.AudioName = input.GetUTF(); this.IsGoToActorPosAndRemove = input.GetBool(); this.IsBeginActiveIntervalTime = input.GetBool(); this.IntervalTime = input.GetF32(); this.NextEffectIndex = input.GetS32(); this.PosIndex = input.GetS32(); } public void WriteExternal(IOutputStream output) { output.PutUTF(this.Name); output.PutF32(this.Time); output.PutUTF(this.PartName); output.PutF32(this.Height); output.PutBool(this.isActorPos); output.PutBool(this.isBindPart); output.PutF32(this.Speed); output.PutU8(this.RunDirection); output.PutUTF(this.AudioName); output.PutBool(this.IsGoToActorPosAndRemove); output.PutBool(this.IsBeginActiveIntervalTime); output.PutF32(this.IntervalTime); output.PutS32(this.NextEffectIndex); output.PutS32(this.PosIndex); } } //---------------------------------------------------------------------------------// [MessageType(0x4015)] [DescAttribute("单位事件触发")] [TableClassAttribute("ID")] public class UnitEventTemplate : ICloneable, ITemplateData, IExternalizable { public int TemplateID { get { return ID; } } [XmlSerializable()] public string EditorPath { get; set; } [DescAttribute("ID", "", false)] public int ID; [LocalizationTextAttribute] [DescAttribute("单位事件触发名字", "基础")] public string Name; [ListAttribute(typeof(UnitEvent))] [DescAttribute("所有事件", "基础", false)] public List Events = new List(); public override string ToString() { return Name + "(" + ID + ")"; } public object Clone() { UnitEventTemplate ret = new UnitEventTemplate(); ret.EditorPath = this.EditorPath; ret.ID = this.ID; ret.Name = this.Name; ret.Events = CUtils.CloneList(this.Events); return ret; } public void WriteExternal(IOutputStream output) { output.PutUTF(this.EditorPath); output.PutS32(this.ID); output.PutUTF(this.Name); output.PutList(this.Events, output.PutExt); } public void ReadExternal(IInputStream input) { this.EditorPath = input.GetUTF(); this.ID = input.GetS32(); this.Name = input.GetUTF(); this.Events = input.GetList(input.GetExt); } public UnitEvent GetEvent(string name) { foreach (var e in Events) { if (e.Name == name) { return e; } } return null; } } #endregion //---------------------------------------------------------------------------------// #region __Launch_Objects__ public abstract class BaseKeyFrame { [DescAttribute("关键帧时间(毫秒)")] public int FrameMS; } /// /// 技能或者法术产生的攻击属性 /// [MessageType(0x4008)] [DescAttribute("技能或者法术产生的攻击属性")] [Expandable] public class AttackProp : ISNData, ICloneable { /// /// 攻击力 /// [DescAttribute("攻击力")] public int Attack; [DescAttribute("产生受击", "Mask")] public bool MaskDamage = false; [DescAttribute("产生击飞", "Mask")] [DependOnProperty("MaskDamage")] public bool MaskHitFly = false; [DescAttribute("产生击倒", "Mask")] [DependOnProperty("MaskDamage")] public bool MaskKnockDown = false; [DescAttribute("此次攻击必命中,即使命中为0", "Mask")] public bool MaskMustHit = false; [DescAttribute("此次攻击必暴击,即使暴击为0", "Mask")] public bool MaskMustCritical = false; [DescAttribute("击中力度(大于目标体重才会产生受击)", "受击")] [DependOnProperty("MaskDamage")] public int Weight = 1; [DescAttribute("单位被(受击、击倒、眩晕、混乱)持续时间(毫秒)" + "\n * 此时间如果为0,首先选用单位DamageTimeMS,否则然后采用Config环境参数OBJECT_DAMAGE_TIME_MS替代之。" + "\n * HitMove运动时间不计算在KnockOutTimeMS内。", "受击")] [DependOnProperty("MaskDamage")] public int KnockOutTimeMS = 0; [DescAttribute("受击动作名", "受击")] [DependOnProperty("MaskDamage")] public string DamageActionName = null; [DescAttribute("受击时,不再遭受其他攻击", "受击")] [DependOnProperty("MaskDamage")] public bool IsDamageProtect = false; public bool IsHitMove { get { return MaskDamage && HitMove != null; } } [DescAttribute("被击中后向后移动距离(包括击飞控制)", "受击")] [DependOnProperty("MaskDamage")] public StartMove HitMove; public enum HitMoveType : byte { [DescAttribute("根据攻击者位置(台球碰撞)")] BySenderPosition, [DescAttribute("根据攻击者朝向(单向)")] BySenderDirection, [DescAttribute("根据攻击者朝向的左右边(摩西分海)")] BySenderLeftRight, [DescAttribute("位移至攻击者中心(向里吸)")] ToSenderCenter, [DescAttribute("位移至攻击者身边(向里吸)")] ToSenderBodySize, [DescAttribute("位移至攻击固定范围外")] BySenderRange, } [DescAttribute("受击位移计算方式", "受击")] [DependOnProperty("IsHitMove")] public HitMoveType HitMoveMType = HitMoveType.BySenderPosition; [DescAttribute("受击位移时对其他单位产生伤害", "受击")] [DependOnProperty("IsHitMove")] public AttackProp HitMoveBodyAttack; [DescAttribute("基于被攻击者身体范围的增加范围", "受击")] [DependOnProperty("IsHitMove")] public float HitMoveBodyAttackSize = 1; [DescAttribute("被击飞落地后产生伤害,或者位移结束产生伤害", "受击")] [DependOnProperty("MaskDamage")] [DependOnProperty("MaskHitFly")] public AttackProp FlyFallenDownAttack; [DescAttribute("被击中特效", "被击中")] public LaunchEffect Effect; [DescAttribute("被击中触发一个BUFF", "被击中")] public LaunchBuff Buff; [DescAttribute("被击中触发一个Spell", "被击中")] public LaunchSpell Spell; [DescAttribute("百分比概率击碎目标", "击碎")] public float CrushPercent = 0; [DescAttribute("击碎目标效果", "击碎")] public LaunchEffect CrushEffect; [DescAttribute("定帧时长", "客户端")] public int StopFrameMS = 0; [DescAttribute("定帧类型", "客户端")] public string StopFrameAction; /// /// 用户自定义扩展属性 /// [DescAttribute("用户自定义扩展属性", "扩展")] [Expandable] [NotNull] public IAttackProperties Properties; [DescAttribute("打死小怪是否击退", "受击")] public KillHitMove killHitMove; public AttackProp() { Properties = TemplateManager.Factory.CreateAttackProperties(); } /// /// 是否产生受击 /// /// public bool IsDamage() { return MaskDamage || MaskHitFly || MaskKnockDown; } public override string ToString() { return "攻击"; } public object Clone() { AttackProp ret = new AttackProp(); ret.SerialNumber = this.SerialNumber; ret.Attack = this.Attack; ret.MaskDamage = this.MaskDamage; ret.MaskHitFly = this.MaskHitFly; ret.MaskKnockDown = this.MaskKnockDown; ret.MaskMustHit = this.MaskMustHit; ret.MaskMustCritical = this.MaskMustCritical; ret.Weight = this.Weight; ret.KnockOutTimeMS = this.KnockOutTimeMS; ret.IsDamageProtect = this.IsDamageProtect; ret.DamageActionName = this.DamageActionName; ret.Effect = CUtils.TryClone(this.Effect); ret.Buff = CUtils.TryClone(this.Buff); ret.Spell = CUtils.TryClone(this.Spell); ret.HitMove = CUtils.TryClone(this.HitMove); ret.HitMoveMType = this.HitMoveMType; ret.HitMoveBodyAttack = CUtils.TryClone(this.HitMoveBodyAttack); ret.HitMoveBodyAttackSize = this.HitMoveBodyAttackSize; ret.FlyFallenDownAttack = CUtils.TryClone(this.FlyFallenDownAttack); ret.StopFrameMS = this.StopFrameMS; ret.StopFrameAction = this.StopFrameAction; ret.CrushPercent = this.CrushPercent; ret.CrushEffect = CUtils.TryClone(this.CrushEffect); ret.Properties = CUtils.TryClone(this.Properties); ret.killHitMove = CUtils.TryClone(this.killHitMove); return ret; } public override void WriteExternal(IOutputStream output) { base.WriteExternal(output); output.PutS32(this.Attack); output.PutBool(this.MaskDamage); output.PutBool(this.MaskHitFly); output.PutBool(this.MaskKnockDown); output.PutBool(this.MaskMustHit); output.PutBool(this.MaskMustCritical); output.PutS32(this.Weight); output.PutS32(this.KnockOutTimeMS); output.PutBool(this.IsDamageProtect); output.PutUTF(this.DamageActionName); output.PutExt(this.Effect); output.PutExt(this.Buff); output.PutExt(this.Spell); output.PutExt(this.HitMove); output.PutEnum8(this.HitMoveMType); output.PutExt(this.HitMoveBodyAttack); output.PutF32(this.HitMoveBodyAttackSize); output.PutExt(this.FlyFallenDownAttack); output.PutS32(this.StopFrameMS); output.PutUTF(this.StopFrameAction); output.PutF32(this.CrushPercent); output.PutExt(this.CrushEffect); output.PutExt(this.Properties); output.PutExt(this.killHitMove); } public override void ReadExternal(IInputStream input) { base.ReadExternal(input); this.Attack = input.GetS32(); this.MaskDamage = input.GetBool(); this.MaskHitFly = input.GetBool(); this.MaskKnockDown = input.GetBool(); this.MaskMustHit = input.GetBool(); this.MaskMustCritical = input.GetBool(); this.Weight = input.GetS32(); this.KnockOutTimeMS = input.GetS32(); this.IsDamageProtect = input.GetBool(); this.DamageActionName = input.GetUTF(); this.Effect = input.GetExt(); this.Buff = input.GetExt(); this.Spell = input.GetExt(); this.HitMove = input.GetExt(); this.HitMoveMType = input.GetEnum8(); this.HitMoveBodyAttack = input.GetExt(); this.HitMoveBodyAttackSize = input.GetF32(); this.FlyFallenDownAttack = input.GetExt(); this.StopFrameMS = input.GetS32(); this.StopFrameAction = input.GetUTF(); this.CrushPercent = input.GetF32(); this.CrushEffect = input.GetExt(); this.Properties = input.GetExt(this.Properties); this.killHitMove = input.GetExt(); } } //---------------------------------------------------------------------------------// /// /// 触发特效,一般只用于显示 /// [MessageType(0x4009)] [DescAttribute("触发特效,一般只用于显示")] [Expandable] public class LaunchEffect : ISNData, ICloneable { public enum RunType : byte { [DescAttribute("默认,沒有運行")] None = 0, [DescAttribute("圓形,以綁定點未中心")] Cycle_BindName = 1, } [DescAttribute("触发的特效名字")] [ResourceIDAttribute] public string Name; [DescAttribute("触发特效是否绑定在特定单位")] public bool BindBody = true; [DescAttribute("绑定挂载点位置")] public string BindPartName; [DescAttribute("如果不为0,则特效以该尺寸缩放")] public float ScaleToBodySize; [DescAttribute("特效高度的偏移量")] public float EffectHight = 0; [DescAttribute("特效水平方向的偏移量x")] public float EffectOffsetX = 0; [DescAttribute("特效水平方向的偏移量x")] public float EffectOffsetY = 0; [DescAttribute("音效")] [ResourceIDAttribute] public string SoundName; [DescAttribute("震屏时长(毫秒)", "震屏")] public int EarthQuakeMS; [DescAttribute("震屏幅度", "震屏")] public float EarthQuakeXYZ; [DescAttribute("自定义字段", "特效扩展")] public string Tag; [DescAttribute("摄像机动画名字")] public string CameraAnimation; [DescAttribute("特效持续时间,0表示只播放一次")] public int EffectTimeMS = 0; [DescAttribute("是否循环")] public bool IsLoop = false; [DescAttribute("是否同步施法者的Rotation")] public bool IsSyncSenderRotation = false; [DescAttribute("速度(原始动画/特效速度 * 速度)", "特效加速")] public float EffectAddSpeed = 1; [DescAttribute("特效中存在的动画,动画的名字", "特效加速")] public string AnimtionName; [DescAttribute("Buff運行方式")] public RunType RType = RunType.None; [DescAttribute("圆形运行参数设置")] public CricleSpeedMode CricleMode; public override string ToString() { return "触发特效:" + Name; } public object Clone() { LaunchEffect ret = new LaunchEffect(); ret.SerialNumber = this.SerialNumber; ret.Name = this.Name; ret.BindBody = this.BindBody; ret.BindPartName = this.BindPartName; ret.ScaleToBodySize = this.ScaleToBodySize; ret.EffectHight = this.EffectHight; ret.SoundName = this.SoundName; ret.EarthQuakeMS = this.EarthQuakeMS; ret.EarthQuakeXYZ = this.EarthQuakeXYZ; ret.Tag = this.Tag; ret.CameraAnimation = this.CameraAnimation; ret.EffectTimeMS = this.EffectTimeMS; ret.IsLoop = this.IsLoop; ret.IsSyncSenderRotation = this.IsSyncSenderRotation; ret.EffectAddSpeed = this.EffectAddSpeed; ret.AnimtionName = this.AnimtionName; ret.RType = this.RType; ret.CricleMode = CUtils.TryClone(this.CricleMode); return ret; } public override void WriteExternal(IOutputStream output) { base.WriteExternal(output); output.PutUTF(this.Name); output.PutBool(this.BindBody); output.PutUTF(this.BindPartName); output.PutF32(this.ScaleToBodySize); output.PutF32(this.EffectHight); output.PutUTF(this.SoundName); output.PutS32(this.EarthQuakeMS); output.PutF32(this.EarthQuakeXYZ); output.PutUTF(this.Tag); output.PutUTF(this.CameraAnimation); output.PutS32(this.EffectTimeMS); output.PutBool(this.IsLoop); output.PutBool(this.IsSyncSenderRotation); output.PutF32(this.EffectAddSpeed); output.PutUTF(this.AnimtionName); output.PutEnum8(this.RType); output.PutExt(this.CricleMode); } public override void ReadExternal(IInputStream input) { base.ReadExternal(input); this.Name = input.GetUTF(); this.BindBody = input.GetBool(); this.BindPartName = input.GetUTF(); this.ScaleToBodySize = input.GetF32(); this.EffectHight = input.GetF32(); this.SoundName = input.GetUTF(); this.EarthQuakeMS = input.GetS32(); this.EarthQuakeXYZ = input.GetF32(); this.Tag = input.GetUTF(); this.CameraAnimation = input.GetUTF(); this.EffectTimeMS = input.GetS32(); this.IsLoop = input.GetBool(); this.IsSyncSenderRotation = input.GetBool(); this.EffectAddSpeed = input.GetF32(); this.AnimtionName = input.GetUTF(); this.RType = input.GetEnum8(); this.CricleMode = input.GetExt(); } } [MessageType(0x4017)] [DescAttribute("围绕中心点圆形运行(美术工程有testpos脚本,方便快速调试)")] [Expandable] public class CricleSpeedMode : ISNData, ICloneable { [DescAttribute("挂节点的半径")] public string[] EffectName; [DescAttribute("挂节点的半径")] public float Radius = 0; [DescAttribute("点间距")] public float Gap = 0; [DescAttribute("弧度")] public float Radian = 0; [DescAttribute("圆点距离")] public float CircleCenterDis = 0; [DescAttribute("圆点距离2")] public float CircleCenterDis2 = 0; [DescAttribute("互斥度")] public float Mutual = 0; [DescAttribute("高度")] public float Height = 0; [DescAttribute("x轴弧度")] public float X_Direction = 0; [DescAttribute("y轴弧度")] public float Y_Direction = 0; [DescAttribute("z轴弧度")] public float Z_Direction = 0; [DescAttribute("旋转速度")] public float RotationSpeed = 0; public object Clone() { CricleSpeedMode ret = new CricleSpeedMode(); ret.SerialNumber = this.SerialNumber; ret.EffectName = CUtils.CloneArray(this.EffectName); ret.Radius = this.Radius; ret.Gap = this.Gap; ret.Radian = this.Radian; ret.CircleCenterDis = this.CircleCenterDis; ret.CircleCenterDis2 = this.CircleCenterDis2; ret.Mutual = this.Mutual; ret.Height = this.Height; ret.X_Direction = this.X_Direction; ret.Y_Direction = this.Y_Direction; ret.Z_Direction = this.Z_Direction; ret.RotationSpeed = this.RotationSpeed; return ret; } public override void WriteExternal(IOutputStream output) { base.WriteExternal(output); output.PutArray(this.EffectName, output.PutUTF); output.PutF32(this.Radius); output.PutF32(this.Gap); output.PutF32(this.Radian); output.PutF32(this.CircleCenterDis); output.PutF32(this.CircleCenterDis2); output.PutF32(this.Mutual); output.PutF32(this.Height); output.PutF32(this.X_Direction); output.PutF32(this.Y_Direction); output.PutF32(this.Z_Direction); output.PutF32(this.RotationSpeed); } public override void ReadExternal(IInputStream input) { base.ReadExternal(input); this.EffectName = input.GetUTFArray(); this.Radius = input.GetF32(); this.Gap = input.GetF32(); this.Radian = input.GetF32(); this.CircleCenterDis = input.GetF32(); this.CircleCenterDis2 = input.GetF32(); this.Mutual = input.GetF32(); this.Height = input.GetF32(); this.X_Direction = input.GetF32(); this.Y_Direction = input.GetF32(); this.Z_Direction = input.GetF32(); this.RotationSpeed = input.GetF32(); } } //---------------------------------------------------------------------------------// /// /// 发起法术或者飞行道具 /// [MessageType(0x400A)] [DescAttribute("释技能")] [Expandable] public class LaunchSkill : ISNData, ICloneable { [DescAttribute("SkillID")] [TemplateIDAttribute(typeof(SkillTemplate))] public int SkillID; [DescAttribute("释放技能权值-弃用")] public int Priority; [DescAttribute("AI自动释放技能-内部使用,不能设置")] public bool AutoLaunch = true; public LaunchSkill() { } public LaunchSkill(int skillID, bool autoLaunch = true) { this.SkillID = skillID; this.AutoLaunch = autoLaunch; } public override string ToString() { return "触发技能:" + SkillID; } public object Clone() { LaunchSkill ret = new LaunchSkill(); ret.SerialNumber = this.SerialNumber; ret.SkillID = this.SkillID; ret.Priority = this.Priority; ret.AutoLaunch = this.AutoLaunch; return ret; } public override void WriteExternal(IOutputStream output) { base.WriteExternal(output); output.PutS32(SkillID); output.PutS32(Priority); output.PutBool(AutoLaunch); } public override void ReadExternal(IInputStream input) { base.ReadExternal(input); this.SkillID = input.GetS32(); this.Priority = input.GetS32(); this.AutoLaunch = input.GetBool(); } } //---------------------------------------------------------------------------------// /// /// 发起法术或者飞行道具 /// [MessageType(0x400B)] [DescAttribute("释放法术或者飞行道具")] [Expandable] public class LaunchSpell : ISNData, ICloneable { public enum PosType : byte { /// /// 默认释放一个法术 /// POS_TYPE_DEFAULT_SINGLE = 0, /// /// 随机范围内目标施放法术 /// POS_TYPE_RANDOM_FOR_SPELL = 1, /// /// 打出圆环多个法术 /// POS_TYPE_CYCLE = 2, /// /// 打出扇形多个法术 /// POS_TYPE_FAN = 3, /// /// 随机方向 /// POS_TYPE_RANDOM_DIRECTION = 4, /// /// 范围 /// POS_TYPE_AREA = 5, /// /// 向同一个目标发射三个锁定法术 /// POS_TYPE_TOSAMETARGET = 6, /// /// X型法术 /// POS_TYPE_X = 7, /// /// 随机范围内施放法术 /// POS_TYPE_RANDOM_POS = 8, /// /// 火箭飞弹 /// /// POS_TYPE_MANY_CANNON = 9, } /// /// 触发新的法术 /// [DescAttribute("触发新的法术")] [TemplateIDAttribute(typeof(SpellTemplate))] public int SpellID; [DescAttribute("触发百分比")] public float LaunchPercent = 100f; /// /// 触发新的法术运行方式 /// [DescAttribute("触发新的法术运行方式")] public PosType PType = PosType.POS_TYPE_DEFAULT_SINGLE; /// /// 触发新的法术数量 /// [DescAttribute("法术范围")] [DependOnProperty("HasSpellRange")] public int SpellRange = 1; public bool MultiLaunch { get { return PType != PosType.POS_TYPE_DEFAULT_SINGLE; } } public bool HasSpellRange { get { return PType == PosType.POS_TYPE_RANDOM_FOR_SPELL || PType == PosType.POS_TYPE_RANDOM_POS; } } /// /// 触发新的法术数量 /// [DescAttribute("触发新的法术数量")] [DependOnProperty("MultiLaunch")] public int Count = 1; /// /// 如果触发为扇形,则定义扇形范围 /// [DescAttribute("扇形:扇形范围;X型:小角值")] [DependOnProperty("MultiLaunch")] public float Angle = 0; [DescAttribute("发射初始角度")] [DependOnProperty("MultiLaunch")] public float StartAngle = 0; public enum LaunchSpllSenderUnit : byte { [DescAttribute("默认")] Sender = 0, [DescAttribute("强制为施法者")] Launcher = 1, [DescAttribute("强制为被攻击者(只在Attack Launch Spell有效)")] DamagedUnit = 2, [DescAttribute("攻击者(在Buff中,buff的释加者)")] AttackerUnit = 3, } [DescAttribute("发射者", "发射者")] public LaunchSpllSenderUnit SenderUnit = LaunchSpllSenderUnit.Sender; [DescAttribute("填True,下面无效,发射口是否以单位炮口作为参考", "炮口")] public bool FromUnitBody = true; [DescAttribute("法术发射高度(炮口高度)", "炮口")] [DependOnProperty("FromUnitBody", false)] public float LaunchSpellHeight; [DescAttribute("法术发射半径(炮口半径)", "炮口")] [DependOnProperty("FromUnitBody", false)] public float LaunchSpellRadius = 0; [DescAttribute("位置偏移类型")] public XYModifyType xyModifyType = XYModifyType.Relative; [DescAttribute("位置偏移X")] public float xModify; [DescAttribute("位置偏移Y")] public float yModify; [DescAttribute("连锁等级,只在技能中LaunchSpell有效(闪电链类数量,如果Spell launch spell ID一致,则传递此值)", "连锁")] public int ChainLevel = 0; [DescAttribute("自动锁定范围内目标", "自动锁定")] public bool IsAutoSeekingTarget = false; [DescAttribute("自动锁定范围内目标(范围)", "自动锁定")] [DependOnProperty("IsAutoSeekingTarget")] public float SeekingTargetRange = 10f; [DescAttribute("自动锁定范围内目标(方式)", "自动锁定")] [DependOnProperty("IsAutoSeekingTarget")] public SpellTemplate.SeekingExpect SeekingTargetExpect = SpellTemplate.SeekingExpect.Random; //是否是程序创建的法师 private bool mIsCodeCreate = false; public LaunchSpell() { } public LaunchSpell(bool codeCreate) { this.mIsCodeCreate = codeCreate; } public bool IsCodeCreate() { return this.mIsCodeCreate; } public override string ToString() { //return "( " + SpellID + ", " + Count + " )"; return "法术:" + this.SpellID + " 数量:" + Count; } public object Clone() { LaunchSpell ret = new LaunchSpell(); ret.SerialNumber = this.SerialNumber; ret.SpellID = this.SpellID; ret.LaunchPercent = this.LaunchPercent; ret.PType = this.PType; ret.Count = this.Count; ret.Angle = this.Angle; ret.StartAngle = this.StartAngle; ret.FromUnitBody = this.FromUnitBody; ret.LaunchSpellHeight = this.LaunchSpellHeight; ret.LaunchSpellRadius = this.LaunchSpellRadius; ret.ChainLevel = this.ChainLevel; ret.SenderUnit = this.SenderUnit; ret.IsAutoSeekingTarget = this.IsAutoSeekingTarget; ret.SeekingTargetRange = this.SeekingTargetRange; ret.SeekingTargetExpect = this.SeekingTargetExpect; ret.SpellRange = this.SpellRange; ret.xModify = this.xModify; ret.yModify = this.yModify; ret.xyModifyType = this.xyModifyType; ret.mIsCodeCreate = this.mIsCodeCreate; return ret; } public override void WriteExternal(IOutputStream output) { base.WriteExternal(output); output.PutS32(this.SpellID); output.PutF32(this.LaunchPercent); output.PutEnum8(this.PType); output.PutS32(this.Count); output.PutF32(this.Angle); output.PutF32(this.StartAngle); output.PutBool(this.FromUnitBody); output.PutF32(this.LaunchSpellHeight); output.PutF32(this.LaunchSpellRadius); output.PutS32(this.ChainLevel); output.PutEnum8(this.SenderUnit); output.PutBool(this.IsAutoSeekingTarget); output.PutF32(this.SeekingTargetRange); output.PutEnum8(this.SeekingTargetExpect); output.PutS32(this.SpellRange); output.PutF32(this.xModify); output.PutF32(this.yModify); output.PutEnum8(this.xyModifyType); } public override void ReadExternal(IInputStream input) { base.ReadExternal(input); this.SpellID = input.GetS32(); this.LaunchPercent = input.GetF32(); this.PType = input.GetEnum8(); this.Count = input.GetS32(); this.Angle = input.GetF32(); this.StartAngle = input.GetF32(); this.FromUnitBody = input.GetBool(); this.LaunchSpellHeight = input.GetF32(); this.LaunchSpellRadius = input.GetF32(); this.ChainLevel = input.GetS32(); this.SenderUnit = input.GetEnum8(); this.IsAutoSeekingTarget = input.GetBool(); this.SeekingTargetRange = input.GetF32(); this.SeekingTargetExpect = input.GetEnum8(); this.SpellRange = input.GetS32(); this.xModify = input.GetF32(); this.yModify = input.GetF32(); this.xyModifyType = input.GetEnum8(); } public void GetXModify(InstanceUnit launcher, out float xChange, out float yChange) { if ((this.xModify != 0 || this.yModify != 0) && this.xyModifyType == Data.XYModifyType.Relative && launcher != null) { float degree = MathVector.getDegree(this.xModify, this.yModify); float distance = (float)Math.Sqrt(this.xModify * this.xModify + this.yModify * this.yModify); xChange = (float)(distance * Math.Cos(degree + launcher.Direction)); yChange = (float)(distance * Math.Sin(degree + launcher.Direction)); return; } else if (this.xyModifyType == Data.XYModifyType.Absolutely) { //不做处理 } xChange = this.xModify; yChange = this.yModify; } } //---------------------------------------------------------------------------------// /// /// 发起BUFF /// [MessageType(0x400C)] [DescAttribute("发起BUFF")] [Expandable] public class LaunchBuff : ISNData, ICloneable { /// /// Buff模板ID /// [DescAttribute("Buff模板ID, 一般用BindEventID")] [TemplateIDAttribute(typeof(BuffTemplate))] public int BuffID; [DescAttribute("触发百分比-废弃")] public float LaunchPercent = 100f; [DescAttribute("绑定事件id:有则去读事件表,忽视BuffID")] [DependOnProperty("IsBindEventID")] public int BindEventID; public bool IsBindEventID { get { return this.BuffID == 0; } } public LaunchBuff() { } public LaunchBuff(int buffID) { this.BuffID = buffID; } public override string ToString() { return "BUFF:" + BuffID + "_@_" + BindEventID; } public object Clone() { LaunchBuff ret = new LaunchBuff(); ret.SerialNumber = this.SerialNumber; ret.BuffID = this.BuffID; ret.BindEventID = this.BindEventID; ret.LaunchPercent = this.LaunchPercent; return ret; } public override void WriteExternal(IOutputStream output) { base.WriteExternal(output); output.PutS32(BuffID); output.PutF32(LaunchPercent); output.PutS32(BindEventID); } public override void ReadExternal(IInputStream input) { base.ReadExternal(input); this.BuffID = input.GetS32(); this.LaunchPercent = input.GetF32(); this.BindEventID = input.GetS32(); } } /// /// 召唤单位 /// [MessageType(0x400D)] [DescAttribute("召唤单位")] [Expandable] public class SummonUnit : ISNData, ICloneable { [DescAttribute("召唤单位模板")] [TemplateIDAttribute(typeof(UnitInfo))] public int UnitTemplateID; [DescAttribute("召唤单位等级")] [TemplateLevelAttribute] public int UnitLevel = 0; [DescAttribute("召唤处产生数量")] public int Count = 1; [DescAttribute("召唤处产生特效")] public LaunchEffect Effect; public SummonUnit() { } public SummonUnit(int templateID) { this.UnitTemplateID = templateID; } public override string ToString() { return "召唤单位:" + UnitTemplateID + " 数量:" + Count; } public object Clone() { SummonUnit ret = new SummonUnit(); ret.SerialNumber = this.SerialNumber; ret.UnitTemplateID = this.UnitTemplateID; ret.UnitLevel = this.UnitLevel; ret.Count = this.Count; ret.Effect = CUtils.TryClone(this.Effect); return ret; } public override void WriteExternal(IOutputStream output) { base.WriteExternal(output); output.PutS32(UnitTemplateID); output.PutS32(UnitLevel); output.PutS32(Count); output.PutExt(Effect); } public override void ReadExternal(IInputStream input) { base.ReadExternal(input); this.UnitTemplateID = input.GetS32(); this.UnitLevel = input.GetS32(); this.Count = input.GetS32(); this.Effect = input.GetExt(); } } [MessageType(0x4016)] [DescAttribute("闪现移动")] [Expandable] public class BlinkMove : ICloneable, IExternalizable { [DescAttribute("移动距离", "移动")] public float Distance = 5; [DescAttribute("角度偏移", "移动")] public float DirectionOffset; [DescAttribute("移动方式", "移动")] public BlinkMoveType MType = BlinkMoveType.MoveToForward; [DescAttribute("忽略地形", "碰撞")] public bool NoneTouchMap = false; [DescAttribute("忽略单位", "碰撞")] public bool NoneTouchObj = true; [DescAttribute("闪现起始点特效", "特效")] public LaunchEffect BeginEffect; [DescAttribute("闪现目标点特效", "特效")] public LaunchEffect TargetEffect; public enum BlinkMoveType : byte { [DescAttribute("向身前移动")] MoveToForward, [DescAttribute("向身后移动")] MoveToBackward, [DescAttribute("向技能释放目标点移动")] MoveToTargetPos, [DescAttribute("向技能释放目标单位移动(面前)")] MoveToTargetUnitFace, [DescAttribute("向技能释放目标单位移动(背后)")] MoveToTargetUnitBack, } public object Clone() { BlinkMove ret = new BlinkMove(); ret.Distance = this.Distance; ret.DirectionOffset = this.DirectionOffset; ret.MType = this.MType; ret.NoneTouchMap = this.NoneTouchMap; ret.NoneTouchObj = this.NoneTouchObj; ret.BeginEffect = CUtils.TryClone(this.BeginEffect); ret.TargetEffect = CUtils.TryClone(this.TargetEffect); return ret; } public void WriteExternal(IOutputStream output) { output.PutF32(this.Distance); output.PutF32(this.DirectionOffset); output.PutEnum8(this.MType); output.PutBool(this.NoneTouchMap); output.PutBool(this.NoneTouchObj); output.PutExt(this.BeginEffect); output.PutExt(this.TargetEffect); } public void ReadExternal(IInputStream input) { this.Distance = input.GetF32(); this.DirectionOffset = input.GetF32(); this.MType = input.GetEnum8(); this.NoneTouchMap = input.GetBool(); this.NoneTouchObj = input.GetBool(); this.BeginEffect = input.GetExt(); this.TargetEffect = input.GetExt(); } public override string ToString() { return "闪现移动"; } } /// /// 移动距离 /// [MessageType(0x400E)] [DescAttribute("移动距离")] [Expandable] public class StartMove : ISNData, ICloneable { [DescAttribute("速度(距离/每秒)", "位移")] public float SpeedSEC = 10f; [DescAttribute("加速度(距离/每秒)(最终速度=速度+加速度)", "位移")] public float SpeedAdd = 0f; [DescAttribute("阻力(每秒递减速度百分比)", "位移")] public float SpeedAcc = 0f; [DescAttribute("被击飞的向上速度(距离/每秒)", "位移")] public float ZSpeedSEC = 0f; [DescAttribute("被击飞的向上移动最大距离(天花板高度)", "位移")] [DependOnProperty("HasFly")] public float ZLimit = 0f; [DescAttribute("重设重力(非0有效)", "位移")] [DependOnProperty("HasFly")] public float OverrideGravity = 0f; [DescAttribute("起始移动方向修正", "位移")] public float Direction; [DescAttribute("移动过程中是否忽略碰撞", "位移")] public bool IsNoneTouch = false; [DescAttribute("自身转动速度(距离/每秒)", "旋转")] public float RotateSpeedSEC; [DescAttribute("持续时间(毫秒),如果是击飞此处无效,击飞时间按落地时间计算,运动时间不计算在DamageTime内", "时间")] [DependOnProperty("HasFly", false)] public int KeepTimeMS = 500; [DescAttribute("", "", false)] public float ArgsFactor = 0; public bool HasFly { get { return ZSpeedSEC != 0; } } public StartMove() { } public override string ToString() { return "移动速度:" + SpeedSEC + "(每秒) 持续:" + KeepTimeMS + "(毫秒)"; } public object Clone() { StartMove ret = new StartMove(); ret.SerialNumber = this.SerialNumber; ret.SpeedSEC = this.SpeedSEC; ret.SpeedAdd = this.SpeedAdd; ret.SpeedAcc = this.SpeedAcc; ret.ZSpeedSEC = this.ZSpeedSEC; ret.ZLimit = this.ZLimit; ret.OverrideGravity = this.OverrideGravity; ret.Direction = this.Direction; ret.IsNoneTouch = this.IsNoneTouch; ret.RotateSpeedSEC = this.RotateSpeedSEC; ret.KeepTimeMS = this.KeepTimeMS; ret.ArgsFactor = this.ArgsFactor; return ret; } public override void WriteExternal(IOutputStream output) { base.WriteExternal(output); output.PutF32(this.SpeedSEC); output.PutF32(this.SpeedAdd); output.PutF32(this.SpeedAcc); output.PutF32(this.ZSpeedSEC); output.PutF32(this.ZLimit); output.PutF32(this.OverrideGravity); output.PutF32(this.Direction); output.PutBool(this.IsNoneTouch); output.PutF32(this.RotateSpeedSEC); output.PutS32(this.KeepTimeMS); output.PutF32(this.ArgsFactor); } public override void ReadExternal(IInputStream input) { base.ReadExternal(input); this.SpeedSEC = input.GetF32(); this.SpeedAdd = input.GetF32(); this.SpeedAcc = input.GetF32(); this.ZSpeedSEC = input.GetF32(); this.ZLimit = input.GetF32(); this.OverrideGravity = input.GetF32(); this.Direction = input.GetF32(); this.IsNoneTouch = input.GetBool(); this.RotateSpeedSEC = input.GetF32(); this.KeepTimeMS = input.GetS32(); this.ArgsFactor = input.GetF32(); } } /// /// 道具掉落 /// [MessageType(0x400F)] [DescAttribute("道具掉落")] [Expandable] public class DropItem : ISNData, ICloneable { /// /// 掉落道具模板ID /// [DescAttribute("掉落道具模板ID")] [TemplateIDAttribute(typeof(ItemTemplate))] public int ItemTemplateID; /// /// 掉落数量 /// [DescAttribute("掉落数量")] public int DropCount = 1; /// /// 掉落道具百分比 /// [DescAttribute("掉落道具百分比")] public float DropPercent; [DescAttribute("掉落位置随机范围点")] public float DropPosRange = 0; public DropItem() { } public DropItem(int itemID, float percent) { this.ItemTemplateID = itemID; this.DropPercent = percent; } public override string ToString() { return "道具掉落:" + ItemTemplateID + " 掉率:" + DropPercent + "%"; } public object Clone() { DropItem ret = new DropItem(); ret.SerialNumber = this.SerialNumber; ret.ItemTemplateID = this.ItemTemplateID; ret.DropCount = this.DropCount; ret.DropPercent = this.DropPercent; ret.DropPosRange = this.DropPosRange; return ret; } public override void WriteExternal(IOutputStream output) { base.WriteExternal(output); output.PutS32(ItemTemplateID); output.PutS32(DropCount); output.PutF32(DropPercent); output.PutF32(DropPosRange); } public override void ReadExternal(IInputStream input) { base.ReadExternal(input); this.ItemTemplateID = input.GetS32(); this.DropCount = input.GetS32(); this.DropPercent = input.GetF32(); this.DropPosRange = input.GetF32(); } } /// /// 道具掉落 /// [MessageType(0x4013)] [DescAttribute("道具掉落列表")] [Expandable] public class DropItemList : ISNData, ICloneable { /// /// 掉落道具模板ID /// [ListAttribute(typeof(DropItem))] [DescAttribute("掉落道具模板列表")] public List DropItems = new List(); public DropItemList() { } public override string ToString() { return "道具掉落:" + DropItems.Count + "个物品中的一个"; } public object Clone() { DropItemList ret = new DropItemList(); ret.SerialNumber = this.SerialNumber; ret.DropItems = CUtils.CloneList(this.DropItems); return ret; } public override void WriteExternal(IOutputStream output) { base.WriteExternal(output); output.PutList(DropItems, output.PutExt); } public override void ReadExternal(IInputStream input) { base.ReadExternal(input); this.DropItems = input.GetList(input.GetExt); } } [MessageType(0x4012)] [DescAttribute("道具使用")] [Expandable] public class UseItem : ISNData, ICloneable { /// /// 掉落道具模板ID /// [DescAttribute("道具模板ID")] [TemplateIDAttribute(typeof(ItemTemplate))] public int ItemTemplateID; public UseItem() { } public UseItem(int itemID) { this.ItemTemplateID = itemID; } public override string ToString() { return "使用道具:" + ItemTemplateID; } public object Clone() { UseItem ret = new UseItem(); ret.SerialNumber = this.SerialNumber; ret.ItemTemplateID = this.ItemTemplateID; return ret; } public override void WriteExternal(IOutputStream output) { base.WriteExternal(output); output.PutS32(this.ItemTemplateID); } public override void ReadExternal(IInputStream input) { base.ReadExternal(input); this.ItemTemplateID = input.GetS32(); } } /// /// 击杀击退 /// [MessageType(0x4027)] [DescAttribute("击杀击退")] [Expandable] public class KillHitMove : ISNData, ICloneable { [DescAttribute("是否生效")] public bool enable = false; [DependOnProperty("enable")] [DescAttribute("受击位移计算方式", "受击")] public HitMoveType moveType = HitMoveType.BySenderDirection; public object Clone() { KillHitMove ret = new KillHitMove(); ret.enable = this.enable; ret.moveType = this.moveType; return ret; } public override string ToString() { return "是否生效:" + enable; } public override void WriteExternal(IOutputStream output) { base.WriteExternal(output); output.PutBool(this.enable); output.PutEnum8(this.moveType); //output.PutEnum32 } public override void ReadExternal(IInputStream input) { base.ReadExternal(input); this.enable = input.GetBool(); this.moveType = input.GetEnum8(); } } [MessageType(0x4028)] [DescAttribute("场景增加道具")] [Expandable] public class BuffAddItem : ISNData, ICloneable { public enum PosType : byte { [DescAttribute("buff触发位置")] HitBuffPos = 1, [DescAttribute("绑定者位置")] BindUnitPos = 2, [DescAttribute("指定位置")] PointPos = 3, } /// [DescAttribute("生成类型")] public PosType posType = PosType.HitBuffPos; /// /// 掉落道具模板ID /// [DescAttribute("道具模板ID")] [TemplateIDAttribute(typeof(ItemTemplate))] public int ItemTemplateID; public bool IsPointXY { get { return posType == PosType.PointPos; } } //记录位置信息 [DependOnProperty("IsPointXY")] [DescAttribute("指定位置X")] public float pointX; [DependOnProperty("IsPointXY")] [DescAttribute("指定位置Y")] public float pointY; public BuffAddItem() { } public override string ToString() { return "生成道具:" + ItemTemplateID; } public object Clone() { BuffAddItem ret = new BuffAddItem(); ret.SerialNumber = this.SerialNumber; ret.ItemTemplateID = this.ItemTemplateID; ret.pointX = this.pointX; ret.pointY = this.pointY; ret.posType = this.posType; return ret; } public override void WriteExternal(IOutputStream output) { base.WriteExternal(output); output.PutS32(this.ItemTemplateID); output.PutEnum8(this.posType); output.PutF32(this.pointX); output.PutF32(this.pointY); } public override void ReadExternal(IInputStream input) { base.ReadExternal(input); this.ItemTemplateID = input.GetS32(); this.posType = input.GetEnum8(); this.pointX = input.GetF32(); this.pointY = input.GetF32(); } } /// /// 单位被动触发 /// [MessageType(0x4011)] [DescAttribute("单位被动触发")] [Expandable] public class LaunchTrigger : ISNData, ICloneable { [DescAttribute("触发器ID")] [TemplateIDAttribute(typeof(UnitTriggerTemplate))] public int TriggerTemplateID; [DescAttribute("开启")] public bool Active = true; public LaunchTrigger() { } public LaunchTrigger(int id) { this.TriggerTemplateID = id; } public override string ToString() { return "单位触发:" + TriggerTemplateID; } public object Clone() { LaunchTrigger ret = new LaunchTrigger(); ret.SerialNumber = this.SerialNumber; ret.TriggerTemplateID = this.TriggerTemplateID; ret.Active = this.Active; return ret; } public override void WriteExternal(IOutputStream output) { base.WriteExternal(output); output.PutS32(TriggerTemplateID); output.PutBool(Active); } public override void ReadExternal(IInputStream input) { base.ReadExternal(input); this.TriggerTemplateID = input.GetS32(); this.Active = input.GetBool(); } } /// /// 携带道具 /// [MessageType(0x4014)] [DescAttribute("单位携带道具")] [Expandable] public class InventoryItem : IExternalizable, ICloneable { [TemplateIDAttribute(typeof(ItemTemplate))] [DescAttribute("道具模板ID")] public int ItemTemplateID; [DescAttribute("数量ID")] public int Count; public override string ToString() { return "携带道具:" + ItemTemplateID + "x" + Count; } public object Clone() { InventoryItem ret = new InventoryItem(); ret.ItemTemplateID = this.ItemTemplateID; ret.Count = this.Count; return ret; } public void WriteExternal(IOutputStream output) { output.PutS32(ItemTemplateID); output.PutS32(Count); } public void ReadExternal(IInputStream input) { this.ItemTemplateID = input.GetS32(); this.Count = input.GetS32(); } } [MessageType(0x410A)] [DescAttribute("单位组阵型")] [Expandable] public class TeamFormation : IExternalizable, ICloneable { public enum Formation : byte { [DescAttribute("随机")] Random = 0, [DescAttribute("方阵")] Square = 1, [DescAttribute("以中心点放射出去的圆阵")] Round = 2, [DescAttribute("圆环")] Cycle = 3, [DescAttribute("蜂窝阵")] Beehive = 4, [DescAttribute("直线")] Line = 5, } public bool IsSquare { get { return this.TFormation == Formation.Square; } } [DescAttribute("阵型")] public Formation TFormation = Formation.Random; [DescAttribute("单位间距,间距不计算身体半径,0表示按最大身体计算")] public float SpacingSize = 5; [DescAttribute("方阵: 每行固定人数,0表示行列相等")] [DependOnProperty("IsSquare")] public int SquareEachRowCount = 0; public object Clone() { TeamFormation ret = new TeamFormation(); ret.TFormation = this.TFormation; ret.SpacingSize = this.SpacingSize; ret.SquareEachRowCount = this.SquareEachRowCount; return ret; } public void WriteExternal(IOutputStream output) { output.PutEnum8(this.TFormation); output.PutF32(this.SpacingSize); output.PutS32(this.SquareEachRowCount); } public void ReadExternal(IInputStream input) { this.TFormation = input.GetEnum8(); this.SpacingSize = input.GetF32(); this.SquareEachRowCount = input.GetS32(); } public override string ToString() { return string.Format("阵型:{0}", TFormation); } } #endregion //---------------------------------------------------------------------------------// }