InstanceSpell.cs 59 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using CommonAI.RTS;
  5. using CommonLang.Vector;
  6. using CommonAI.ZoneClient;
  7. using CommonLang;
  8. using CommonAI.Zone.Formula;
  9. using CommonAI.Zone.Helper;
  10. using static CommonAI.Zone.Instance.InstanceUnit;
  11. using CommonAI.ZoneServer.JSGModule;
  12. using CommonAI.Data;
  13. namespace CommonAI.Zone.Instance
  14. {
  15. public class InstanceSpell : InstanceZoneObject
  16. {
  17. readonly protected SpellTemplate mInfo;
  18. readonly protected SyncSpellInfo mSyncInfo;
  19. readonly protected LaunchSpell mLaunchData;
  20. // 释放者
  21. readonly protected InstanceUnit mLauncherUnit;
  22. // 发出者
  23. readonly protected InstanceZoneObject mSender;
  24. protected AttackRangeHelper AttackRange;
  25. protected Vector2 mStartPos;
  26. protected float mLaunchDirection;
  27. // 被跟踪目标
  28. protected InstanceUnit mTarget;
  29. protected Vector2 mTargetPos;
  30. protected TimeExpire<int> mSeekingCooldownTime;
  31. protected SpellChainLevelInfo mChainInfo;
  32. /// <summary>
  33. /// 如果是技能产生的伤害,就是该技能的类型(就算是法术,也要追根到技能)
  34. /// </summary>
  35. public readonly XmdsSkillType FromSkillType = XmdsSkillType.none;
  36. private float mBaseSize;
  37. private float mDistance;
  38. private float mSpeed;
  39. private PopupKeyFrames<SpellTemplate.KeyFrame> mKeyFrames;
  40. private Dictionary<uint, InstanceUnit> mHittedUnits;
  41. private bool Finish = false;
  42. private TimeInterval<SpellTemplate.KeyFrame> mHitIntervalTicker;
  43. private InstanceUnit.StateSkill mBindingSkill;
  44. private bool mClientVisible;
  45. private bool mSyncPos;
  46. private float mMoveDistance;
  47. //服务器专用的扩展字段
  48. private int actionIndex;
  49. private int mMaxAffectUnit;
  50. //法术创建时,玩家的AOI状态
  51. private byte aoiFlag = 0;
  52. //每隔N秒触发,触发次数
  53. private int mHitTotalTimes;
  54. //法术总时长
  55. private readonly int mSpellTotalTime; //法术的总时长
  56. // 飞弹各种奇葩数据记录, 法术数量可控
  57. private JSGCreateSpellData mCreateSpellData; //法术创建信息(可变的,由技能数据确定)
  58. // 飞弹不同的法术id
  59. public List<LaunchSpell> mCurveSpellList;
  60. //连续飞弹
  61. private byte mCurveSpellIndex;
  62. private TVector2 mPrvePos = new TVector2();
  63. public InstanceSpell(
  64. InstanceZone zone,
  65. SpellTemplate data,
  66. LaunchSpell launch,
  67. InstanceUnit launcher,
  68. InstanceZoneObject sender,
  69. Dictionary<uint, InstanceUnit> damageList,
  70. XmdsSkillType fromSkillType = XmdsSkillType.none,
  71. int spellIndex = 0,
  72. JSGCreateSpellData createData = null)
  73. : base(zone, false)
  74. {
  75. this.mSpellTotalTime = data.LifeTimeMS;
  76. this.mCurveSpellIndex = (byte)spellIndex;
  77. SenderID = 0;
  78. if (sender != null)
  79. {
  80. if (sender is InstanceUnit)
  81. SenderID = sender.ID;
  82. else if (sender is InstanceSpell)
  83. SenderID = (sender as InstanceSpell).SenderID;
  84. }
  85. //记录AOI状态
  86. if (sender.AoiStatus != null)
  87. {
  88. this.aoiFlag = 1;
  89. }
  90. this.FromSkillType = fromSkillType;
  91. this.mLaunchData = launch;
  92. if (createData == null)
  93. {
  94. this.mCreateSpellData = new JSGCreateSpellData();
  95. this.mCreateSpellData.mMaxSpellCount = launch.Count;
  96. }
  97. else
  98. {
  99. this.mCreateSpellData = createData;
  100. }
  101. this.mKeyFrames = new PopupKeyFrames<SpellTemplate.KeyFrame>();
  102. this.mKeyFrames.AddRange(data.KeyFrames);
  103. this.mInfo = data;
  104. this.mLauncherUnit = launcher;
  105. this.mSender = sender;
  106. this.mBaseSize = data.BodySize;
  107. this.mDistance = data.Distance;
  108. this.faceTo(launcher.Direction);
  109. this.IsAffectNearChange = false;
  110. this.mSyncInfo = new SyncSpellInfo(zone.IsHalfSync);
  111. this.mSyncInfo.TemplateID = mInfo.ID;
  112. this.mSyncInfo.Force = launcher.Force;
  113. if (mInfo.HitIntervalMS <= 0)
  114. {
  115. this.mHittedUnits = (damageList == null ? new Dictionary<uint, InstanceUnit>() : damageList);
  116. }
  117. this.mClientVisible = mInfo.ClientVisible;
  118. this.mSyncPos = zone.SyncPos;
  119. this.mHitIntervalTicker = new TimeInterval<SpellTemplate.KeyFrame>(data.HitIntervalMS);
  120. this.mHitIntervalTicker.Tag = data.HitIntervalKeyFrame;
  121. this.mHitTotalTimes = 0;
  122. this.AttackRange = new AttackRangeHelper(launcher);
  123. this.mSpeed = mInfo.MSpeedSEC;
  124. this.mMoveDistance = 0;
  125. if (launcher.AoiStatus != null)
  126. {
  127. this.setAoiStatus(launcher.AoiStatus);
  128. }
  129. }
  130. public SpellTemplate Info { get { return mInfo; } }
  131. public LaunchSpell LaunchData { get { return mLaunchData; } }
  132. /// <summary>
  133. /// 最先技能的发起者
  134. /// </summary>
  135. public InstanceUnit Launcher { get { return mLauncherUnit; } }
  136. public uint LauncherID { get { return mLauncherUnit.ID; } }
  137. /// <summary>
  138. /// 技能的出口,比如技能触发技能,则Sender就是一个Spell
  139. /// </summary>
  140. public InstanceZoneObject Sender { get { return mSender; } }
  141. public InstanceUnit Target { get { return mTarget; } }
  142. public override bool IntersectMap { get { return false; } }
  143. public override bool IntersectObj { get { return false; } }
  144. public override bool Moveable { get { return true; } }
  145. public override float BodyBlockSize { get { return mBaseSize; } }
  146. public override float BodyHitSize { get { return mBaseSize; } }
  147. public override float BodyHeight { get { return mInfo.BodySize; } }
  148. public override float Weight { get { return 0; } }
  149. public override bool ClientVisible { get { return mClientVisible; } }
  150. public override bool SyncPos { get { return mSyncPos; } }
  151. public int BindActionIndex { get { return actionIndex; } set { this.actionIndex = value; } }
  152. public int MaxAffectUnit { get { return mMaxAffectUnit; } set { this.mMaxAffectUnit = value; } }
  153. /** 获取触发次数 */
  154. public int GetHitTimes()
  155. {
  156. return this.mHitTotalTimes;
  157. }
  158. /// <summary>
  159. /// 连锁等级
  160. /// </summary>
  161. public int ChainLevel { get { return (mChainInfo != null) ? mChainInfo.Level : 0; } }
  162. public SpellChainLevelInfo ChainInfo { get { return mChainInfo; } }
  163. public uint SenderID;
  164. public uint TargetID { get { return (mTarget != null) ? mTarget.ID : 0; } }
  165. public Vector2 TargetPos { get { return mTargetPos; } }
  166. public float LaunchHeightZ
  167. {
  168. get
  169. {
  170. if (mSender != null && mSender is InstanceSpell)
  171. {
  172. var obj = mSender as InstanceSpell;
  173. if (obj.mInfo.MType == SpellTemplate.MotionType.Cannon)
  174. {
  175. return 0;
  176. }
  177. else
  178. {
  179. return mSender.Z;
  180. }
  181. }
  182. float h = mLaunchData.LaunchSpellHeight;
  183. if (mLaunchData.FromUnitBody)
  184. {
  185. h = Launcher.Info.LaunchSpellHeight;
  186. }
  187. return h;
  188. }
  189. }
  190. public override SyncObjectInfo GenSyncInfo(bool net)
  191. {
  192. return GenSyncSpellInfo(net);
  193. }
  194. public SyncSpellInfo GenSyncSpellInfo(bool net = false)
  195. {
  196. mSyncInfo.x = X;
  197. mSyncInfo.y = Y;
  198. mSyncInfo.direction = this.Direction;
  199. mSyncInfo.HasSpeed = mInfo.IsMoveable && mSpeed != mInfo.MSpeedSEC;
  200. mSyncInfo.CurSpeed = mSpeed;
  201. return mSyncInfo;
  202. }
  203. // 如果是导弹类型,则需要目标
  204. public void setTarget(InstanceUnit target)
  205. {
  206. this.mTarget = target;
  207. }
  208. public void setTargetPos(Vector2 targetPos)
  209. {
  210. this.mTargetPos = targetPos;
  211. }
  212. public void setChainInfo(SpellChainLevelInfo c)
  213. {
  214. this.mChainInfo = c;
  215. }
  216. protected override void onAdded(bool pointLv)
  217. {
  218. if (mLaunchData.IsAutoSeekingTarget && mLaunchData.PType != LaunchSpell.PosType.POS_TYPE_AREA)
  219. {
  220. //目标不存在,或者已死亡才重新寻找, 不能打开,弹射逻辑
  221. //if(mTarget == null || mTarget.IsDead())
  222. {
  223. mTarget = Parent.SeekSpellAttackable(this.Launcher, this.Info, this.Launcher.AoiStatus,
  224. X, Y, mLaunchData.SeekingTargetRange, Info.ExpectTarget, mLaunchData.SeekingTargetExpect, mChainInfo);
  225. //Console.WriteLine("重新索敌:" + mTarget.ID);
  226. }
  227. }
  228. this.mSyncInfo.ObjectID = base.ID;
  229. this.mLaunchDirection = this.Direction;
  230. float radius = mLaunchData.LaunchSpellRadius;
  231. if (mLaunchData.FromUnitBody && (Sender is InstanceUnit))
  232. {
  233. radius = (Sender as InstanceUnit).Info.LaunchSpellRadius;
  234. }
  235. mStartPos = new Vector2(X, Y);
  236. switch (mInfo.MType)
  237. {
  238. case SpellTemplate.MotionType.SelectTarget:
  239. if (mTarget != null)
  240. {
  241. mStartPos.SetX(mTarget.X);
  242. mStartPos.SetY(mTarget.Y);
  243. }
  244. MathVector.movePolar(mStartPos, mLaunchDirection, radius);
  245. break;
  246. case SpellTemplate.MotionType.SelectLauncher:
  247. if (mLauncherUnit != null)
  248. {
  249. mStartPos.SetX(mLauncherUnit.X);
  250. mStartPos.SetY(mLauncherUnit.Y);
  251. }
  252. MathVector.movePolar(mStartPos, mLaunchDirection, radius);
  253. break;
  254. case SpellTemplate.MotionType.Immovability:
  255. MathVector.movePolar(mStartPos, mLaunchDirection, radius);
  256. break;
  257. case SpellTemplate.MotionType.Cannon:
  258. if (mTargetPos != null)
  259. {
  260. MathVector.moveTo(mStartPos, mTargetPos.X, mTargetPos.Y, radius);
  261. }
  262. else if (mTarget != null)
  263. {
  264. mTargetPos = new Vector2(mTarget.X, mTarget.Y);
  265. MathVector.moveTo(mStartPos, mTargetPos.X, mTargetPos.Y, radius);
  266. }
  267. break;
  268. case SpellTemplate.MotionType.AOE:
  269. MathVector.movePolar(mStartPos, mLaunchDirection, radius);
  270. break;
  271. case SpellTemplate.MotionType.AOE_Binding:
  272. break;
  273. case SpellTemplate.MotionType.AOE_BindingTarget:
  274. break;
  275. case SpellTemplate.MotionType.Straight:
  276. MathVector.movePolar(mStartPos, mLaunchDirection, radius);
  277. break;
  278. case SpellTemplate.MotionType.Binding:
  279. break;
  280. case SpellTemplate.MotionType.BindingTarget:
  281. break;
  282. case SpellTemplate.MotionType.Missile:
  283. if (mTarget != null)
  284. {
  285. MathVector.moveTo(mStartPos, mTarget.X, mTarget.Y, radius);
  286. }
  287. else
  288. {
  289. MathVector.movePolar(mStartPos, mLaunchDirection, radius);
  290. }
  291. break;
  292. case SpellTemplate.MotionType.MissileAttackRoute:
  293. if (mTarget != null)
  294. {
  295. MathVector.moveTo(mStartPos, mTarget.X, mTarget.Y, radius);
  296. }
  297. else
  298. {
  299. MathVector.movePolar(mStartPos, mLaunchDirection, radius);
  300. }
  301. //设置索敌间隔
  302. if (this.Info.SeekingCooldownMS > XmdsConstConfig.GAME_UPDATE_INTERVAL_MS)
  303. {
  304. this.mSeekingCooldownTime = new TimeExpire<int>(mInfo.SeekingCooldownMS);
  305. }
  306. else
  307. {
  308. log.Error("法术:" + this.Info.ID + ", 索敌间隔配置异常!");
  309. }
  310. break;
  311. case SpellTemplate.MotionType.SeekerMissile:
  312. if (mTarget != null)
  313. {
  314. MathVector.moveTo(mStartPos, mTarget.X, mTarget.Y, radius);
  315. }
  316. else
  317. {
  318. MathVector.movePolar(mStartPos, mLaunchDirection, radius);
  319. if (mInfo.SeekingCooldownMS == 0)
  320. {
  321. mTarget = seekAttackable(mInfo.SeekingRange);
  322. }
  323. else
  324. {
  325. this.mSeekingCooldownTime = new TimeExpire<int>(mInfo.SeekingCooldownMS);
  326. }
  327. }
  328. break;
  329. case SpellTemplate.MotionType.SeekerSelectTarget:
  330. if (mTarget == null)
  331. {
  332. if (mInfo.SeekingCooldownMS == 0)
  333. {
  334. mTarget = seekAttackable(mInfo.SeekingRange);
  335. if (mTarget != null)
  336. {
  337. mStartPos.SetX(mTarget.X);
  338. mStartPos.SetY(mTarget.Y);
  339. }
  340. }
  341. else
  342. {
  343. this.mSeekingCooldownTime = new TimeExpire<int>(mInfo.SeekingCooldownMS);
  344. }
  345. }
  346. break;
  347. case SpellTemplate.MotionType.Chain:
  348. if (mSender != null)
  349. {
  350. mStartPos.SetX(mSender.X);
  351. mStartPos.SetY(mSender.Y);
  352. }
  353. break;
  354. case SpellTemplate.MotionType.Boomerang1:
  355. case SpellTemplate.MotionType.Boomerang2:
  356. MathVector.movePolar(mStartPos, mLaunchDirection, radius);
  357. break;
  358. case SpellTemplate.MotionType.CurveMissile:
  359. MathVector.movePolar(mStartPos, mLaunchDirection, radius);
  360. if (mInfo.SeekingCooldownMS > 0)
  361. {
  362. this.mSeekingCooldownTime = new TimeExpire<int>(mInfo.SeekingCooldownMS);
  363. }
  364. break;
  365. case SpellTemplate.MotionType.Foxfire:
  366. MathVector.movePolar(mStartPos, mLaunchDirection, radius);
  367. mTarget = null;
  368. foxfireSeekWait = 0;
  369. break;
  370. case SpellTemplate.MotionType.StraightAndStop:
  371. MathVector.movePolar(mStartPos, mLaunchDirection, radius);
  372. break;
  373. }
  374. setPos(mStartPos.X, mStartPos.Y, this.LaunchHeightZ);
  375. }
  376. //public long mDisPosingTime = 0;
  377. //public long mDisPosingTime1 = 0;
  378. protected override void Disposing()
  379. {
  380. this.mSeekingCooldownTime = null;
  381. this.mKeyFrames = null;
  382. //mDisPosingTime = CommonLang.CUtils.localTimeMS;
  383. //mDisPosingTime1 = System.DateTime.Now.Ticks;
  384. if (this.mHittedUnits != null)
  385. {
  386. this.mHittedUnits.Clear();
  387. this.mHittedUnits = null;
  388. }
  389. this.mHitIntervalTicker = null;
  390. this.mCreateSpellData = null;
  391. if (this.mCurveSpellList != null)
  392. {
  393. this.mCurveSpellList.Clear();
  394. this.mCurveSpellList = null;
  395. }
  396. if (brothers != null)
  397. {
  398. for (int i = 0; i < brothers.Length; i++)
  399. {
  400. if (this == brothers[i])
  401. {
  402. brothers[i] = null;
  403. break;
  404. }
  405. }
  406. }
  407. this.AttackRange = null;
  408. base.Disposing();
  409. }
  410. protected override void onRemoved()
  411. {
  412. if (mInfo.StopBindingSkillOnRemoved)
  413. {
  414. if (this.Launcher != null && this.Launcher.CurrentState is InstanceUnit.StateSkill)
  415. {
  416. (this.Launcher.CurrentState as InstanceUnit.StateSkill).block();
  417. this.Launcher.doSomething();
  418. }
  419. }
  420. }
  421. override protected void onUpdate(bool slowRefresh)
  422. {
  423. if (IsPaused) { return; }
  424. if (Info.MaxMoveDistance == 0 || mMoveDistance < Info.MaxMoveDistance)
  425. {
  426. updateMotion();
  427. if (mInfo.IsMoveable)
  428. {
  429. MoveHelper.UpdateSpeed(Parent.UpdateIntervalMS, ref mSpeed, mInfo.MSpeedAdd, mInfo.MSpeedAcc, mInfo.MSpeed_MIN, mInfo.MSpeed_MAX);
  430. MoveHelper.UpdateMoveDistance(Parent.UpdateIntervalMS, ref mMoveDistance, mSpeed);
  431. }
  432. }
  433. if (this.mKeyFrames != null)
  434. {
  435. updateKeyFrames(slowRefresh);
  436. }
  437. if (mInfo.MType == SpellTemplate.MotionType.Foxfire && mTarget != null)
  438. {
  439. }
  440. else if (mInfo.MType == SpellTemplate.MotionType.CurveMissile && mTarget != null)
  441. {
  442. }
  443. else if (mInfo.MType == SpellTemplate.MotionType.Boomerang1 || mInfo.MType == SpellTemplate.MotionType.Boomerang2)
  444. {
  445. }
  446. else if (mInfo.MType == SpellTemplate.MotionType.Binding)//绑定自身的spell才在自己死亡时移除
  447. {
  448. if (!Sender.Enable || Sender.IsDead())
  449. {
  450. Parent.RemoveObject(this);
  451. }
  452. else if ((Sender.AoiStatus == null && this.aoiFlag == 1) || (Sender.AoiStatus != null && this.aoiFlag == 0))
  453. {
  454. //玩家AOI状态改变了,也要清一下
  455. Parent.RemoveObject(this);
  456. }
  457. StateSkill skill = this.mLauncherUnit.CurrentState as StateSkill;
  458. if (skill != null && skill.Skill != null && skill.SkillData.ActionQueue.Count > 1)
  459. {
  460. //UnitActionData curSkillAction = skill.Skill.GetCurAction();
  461. if (skill.CurrentActionIndex != this.actionIndex
  462. && (0 <= this.actionIndex && this.actionIndex < skill.SkillData.ActionQueue.Count)
  463. && skill.SkillData.ActionQueue[this.actionIndex].IsCancelBySkillNext)
  464. {
  465. Parent.RemoveObject(this);
  466. }
  467. }
  468. }
  469. if (PassTimeMS >= this.mSpellTotalTime)
  470. {
  471. Parent.RemoveObject(this);//Parent.RemoveObjectByID(ID);
  472. }
  473. }
  474. /// <summary>
  475. /// 更新移动行为
  476. /// </summary>
  477. private void updateMotion()
  478. {
  479. this.mPrvePos.SetX(X);
  480. this.mPrvePos.SetY(Y);
  481. switch (mInfo.MType)
  482. {
  483. case SpellTemplate.MotionType.Immovability:
  484. case SpellTemplate.MotionType.SelectTarget:
  485. case SpellTemplate.MotionType.SelectLauncher:
  486. break;
  487. case SpellTemplate.MotionType.Cannon:
  488. if (mTargetPos != null)
  489. {
  490. if (flyToTarget(mTargetPos.X, mTargetPos.Y, mSpeed, Parent.UpdateIntervalMS))
  491. {
  492. this.Finish = true;
  493. }
  494. }
  495. else if (PassTimeMS + Parent.UpdateIntervalMS >= this.mSpellTotalTime)//没有目标,结束时触发下
  496. {
  497. if (Parent.UpdateIntervalMS > 0)
  498. {
  499. this.Finish = true;
  500. }
  501. }
  502. break;
  503. case SpellTemplate.MotionType.Straight:
  504. flyTo(mLaunchDirection, mSpeed, Parent.UpdateIntervalMS);
  505. break;
  506. case SpellTemplate.MotionType.AOE:
  507. updateAOE();
  508. break;
  509. case SpellTemplate.MotionType.AOE_Binding:
  510. updateAOE();
  511. if (mSender != null && mSender.Enable)
  512. {
  513. updateBinding(mSender);
  514. }
  515. else
  516. {
  517. Parent.RemoveObject(this);
  518. }
  519. break;
  520. case SpellTemplate.MotionType.AOE_BindingTarget:
  521. updateAOE();
  522. if (mTarget != null && mTarget.IsActive)
  523. {
  524. updateBinding(mTarget);
  525. }
  526. else
  527. {
  528. Parent.RemoveObject(this);
  529. }
  530. break;
  531. case SpellTemplate.MotionType.Binding:
  532. if (mSender != null && mSender.Enable)
  533. {
  534. updateBinding(mSender);
  535. }
  536. else
  537. {
  538. Parent.RemoveObject(this);
  539. }
  540. break;
  541. case SpellTemplate.MotionType.BindingTarget:
  542. if (mTarget != null && mTarget.IsActive)
  543. {
  544. updateBinding(mTarget);
  545. }
  546. else
  547. {
  548. Parent.RemoveObject(this);
  549. }
  550. break;
  551. case SpellTemplate.MotionType.Missile:
  552. case SpellTemplate.MotionType.MissileAttackRoute:
  553. if (mTarget != null)
  554. {
  555. if (mInfo.RotateSpeedSEC == 0)
  556. {
  557. faceTo(mTarget.X, mTarget.Y);
  558. }
  559. flyToTarget(mTarget.X, mTarget.Y, mSpeed, Parent.UpdateIntervalMS);
  560. }
  561. else
  562. {
  563. flyTo(mLaunchDirection, mSpeed, Parent.UpdateIntervalMS);
  564. }
  565. break;
  566. case SpellTemplate.MotionType.SeekerMissile:
  567. if (mTarget != null)
  568. {
  569. if (mInfo.SeekingTurningAngleSEC != 0)
  570. {
  571. flyToTargetTunning(mTarget.X, mTarget.Y, mSpeed, mInfo.SeekingTurningAngleSEC, Parent.UpdateIntervalMS);
  572. }
  573. else
  574. {
  575. faceTo(mTarget.X, mTarget.Y);
  576. flyToTarget(mTarget.X, mTarget.Y, mSpeed, Parent.UpdateIntervalMS);
  577. }
  578. }
  579. else
  580. {
  581. flyTo(mLaunchDirection, mSpeed, Parent.UpdateIntervalMS);
  582. if (mSeekingCooldownTime == null || mSeekingCooldownTime.Update(Parent.UpdateIntervalMS))
  583. {
  584. mTarget = seekAttackable(mInfo.SeekingRange);
  585. if (mTarget != null)
  586. {
  587. Parent.queueObjectEvent(this, new SpellLockTargetEvent(ID, mTarget.ID, X, Y));
  588. }
  589. }
  590. }
  591. break;
  592. case SpellTemplate.MotionType.SeekerSelectTarget:
  593. if (mTarget == null)
  594. {
  595. if (mSeekingCooldownTime == null || mSeekingCooldownTime.Update(Parent.UpdateIntervalMS))
  596. {
  597. mTarget = seekAttackable(mInfo.SeekingRange);
  598. if (mTarget != null)
  599. {
  600. this.setPos(mTarget.X, mTarget.Y);
  601. Parent.queueObjectEvent(this, new SpellLockTargetEvent(ID, mTarget.ID, X, Y));
  602. }
  603. }
  604. }
  605. break;
  606. case SpellTemplate.MotionType.Chain:
  607. if (mSender != null && mSender.Enable && mTarget != null && mTarget.IsActive)
  608. {
  609. setPos(mSender.X, mSender.Y);
  610. faceTo(mTarget.X, mTarget.Y);
  611. updateBinding(mTarget);
  612. }
  613. else
  614. {
  615. Parent.RemoveObject(this);
  616. }
  617. break;
  618. case SpellTemplate.MotionType.Boomerang1:
  619. if (PassTimeMS < mInfo.BoomerangFlyTime)
  620. {
  621. flyTo(mLaunchDirection, mSpeed, Parent.UpdateIntervalMS);
  622. }
  623. else if (PassTimeMS > mInfo.BoomerangFlyTime + mInfo.BoomerangHangtime)
  624. {
  625. if (flyToTarget(mLauncherUnit.X, mLauncherUnit.Y, mSpeed * 1.4f, Parent.UpdateIntervalMS))
  626. {
  627. this.Finish = true;
  628. }
  629. }
  630. break;
  631. case SpellTemplate.MotionType.Boomerang2:
  632. if (PassTimeMS < mInfo.BoomerangFlyTime)
  633. {
  634. flyTo(mLaunchDirection, mSpeed, Parent.UpdateIntervalMS);
  635. }
  636. else if (PassTimeMS > mInfo.BoomerangFlyTime + mInfo.BoomerangHangtime)
  637. {
  638. if (flyToTarget(mStartPos.X, mStartPos.Y, mSpeed * 1.4f, Parent.UpdateIntervalMS))
  639. {
  640. this.Finish = true;
  641. }
  642. }
  643. break;
  644. case SpellTemplate.MotionType.CurveMissile:
  645. //IPosBase targetPos = mTargetPos;
  646. IPosBase targetPos = (mTarget != null) ? (IPosBase)mTarget : (IPosBase)mTargetPos;
  647. if (targetPos == null)
  648. {
  649. flyTo(mLaunchDirection, mSpeed, Parent.UpdateIntervalMS);
  650. }
  651. else if (mInfo.SeekingTurningAngleSEC != 0)
  652. {
  653. flyToTargetTunning(targetPos.X, targetPos.Y, mSpeed, mInfo.SeekingTurningAngleSEC, Parent.UpdateIntervalMS);
  654. }
  655. else
  656. {
  657. faceTo(targetPos.X, targetPos.Y);
  658. flyToTarget(targetPos.X, targetPos.Y, mSpeed, Parent.UpdateIntervalMS);
  659. }
  660. if (mTarget == null && (mSeekingCooldownTime == null || mSeekingCooldownTime.Update(Parent.UpdateIntervalMS)))
  661. {
  662. mTarget = seekAttackable(mInfo.SeekingRange);
  663. if (mTarget != null)
  664. {
  665. Parent.queueObjectEvent(this, new SpellLockTargetEvent(ID, mTarget.ID, X, Y));
  666. }
  667. }
  668. this.checkAndLaunchCurveSpell();
  669. break;
  670. case SpellTemplate.MotionType.Foxfire:
  671. if (mTarget == null)
  672. {
  673. foxfireRoundAngle = mLaunchDirection + PassTimeMS * 0.001f * 3;
  674. var x = mLauncherUnit.X + (float)(Math.Cos(foxfireRoundAngle + 0.3f) * mLaunchData.LaunchSpellRadius);
  675. var y = mLauncherUnit.Y + (float)(Math.Sin(foxfireRoundAngle + 0.3f) * mLaunchData.LaunchSpellRadius);
  676. flyToTarget(x, y, mSpeed, Parent.UpdateIntervalMS);
  677. if (mInfo.RotateSpeedSEC == 0)
  678. {
  679. faceTo(foxfireRoundAngle + (float)Math.PI * 0.25f);
  680. }
  681. if (foxfireSeekWait >= this.Info.SeekingCooldownMS && PassTimeMS < this.mSpellTotalTime - 500)
  682. {
  683. var tar = seekAttackable(mInfo.SeekingRange);
  684. if (tar != null && tar != mLauncherUnit)
  685. {
  686. changeBrotherSeekWait(-250);
  687. Parent.queueObjectEvent(this, new SpellLockTargetEvent(ID, tar.ID, X, Y));
  688. mTarget = tar;
  689. }
  690. }
  691. foxfireSeekWait += Parent.UpdateIntervalMS;
  692. }
  693. else
  694. {
  695. if (mInfo.SeekingTurningAngleSEC != 0)
  696. {
  697. flyToTargetTunning(mTarget.X, mTarget.Y, mSpeed, mInfo.SeekingTurningAngleSEC, Parent.UpdateIntervalMS);
  698. }
  699. else
  700. {
  701. faceTo(mTarget.X, mTarget.Y);
  702. flyToTarget(mTarget.X, mTarget.Y, mSpeed, Parent.UpdateIntervalMS);
  703. }
  704. }
  705. break;
  706. case SpellTemplate.MotionType.StraightAndStop:
  707. if (PassTimeMS < mInfo.BoomerangFlyTime)
  708. {
  709. flyTo(mLaunchDirection, mSpeed, Parent.UpdateIntervalMS);
  710. }
  711. //else if (PassTimeMS > mInfo.BoomerangFlyTime + mInfo.BoomerangHangtime)
  712. //{
  713. // if (flyToTarget(mLauncherUnit.X, mLauncherUnit.Y, mSpeed * 1.8f, Parent.UpdateIntervalMS))
  714. // {
  715. // this.Finish = true;
  716. // }
  717. //}
  718. break;
  719. }
  720. if (mInfo.BodyShape == SpellTemplate.Shape.LineToTarget)
  721. {
  722. if (mTarget != null)
  723. {
  724. this.faceTo(mTarget.X, mTarget.Y);
  725. }
  726. }
  727. else if (mInfo.BodyShape == SpellTemplate.Shape.LineToStart)
  728. {
  729. this.faceTo(mStartPos.X, mStartPos.Y);
  730. }
  731. else if (mInfo.RotateSpeedSEC != 0 && mInfo.MType != SpellTemplate.MotionType.SeekerMissile)
  732. {
  733. this.turn(MoveHelper.GetDistance(Parent.UpdateIntervalMS, mInfo.RotateSpeedSEC));
  734. }
  735. }
  736. /** 检测释放后续飞弹 */
  737. private void checkAndLaunchCurveSpell(bool force = false)
  738. {
  739. //////创建后续个飞弹
  740. if ((force || PassTimeMS >= XmdsConstConfig.GAME_UPDATE_INTERVAL_MS) && mCurveSpellIndex > 0 && this.Launcher.IsActive)
  741. {
  742. int nextSpellIndex = Math.Max(0, mCurveSpellIndex - 1);
  743. int flag = (this.mCreateSpellData.mMaxSpellCount - mCurveSpellIndex) % 2 == 0 ? 2 : -2;
  744. //float angleOffset = (this.Target == null ? this.LaunchData.StartAngle / 3 : this.LaunchData.StartAngle);
  745. float angleOffset = JSGModule.GetCurveStartAngleOffect(mLauncherUnit, this.mTarget, this.LaunchData.StartAngle, this.Info.SeekingRange);
  746. float startDirection = this.mLaunchDirection + angleOffset * flag;
  747. float launchX = this.Launcher.X - (float)(1.0f * Math.Cos(this.Launcher.Direction));
  748. float launchY = this.Launcher.Y - (float)(1.0f * Math.Sin(this.Launcher.Direction));
  749. LaunchSpell launchSpell = this.LaunchData;
  750. if (mCurveSpellList != null && mCurveSpellList.Count > mCurveSpellIndex)
  751. {
  752. launchSpell = mCurveSpellList[mCurveSpellIndex];
  753. }
  754. InstanceSpell addSpell = this.Parent.AddSpell(this.FromSkillType, this.Info, launchSpell, this.Sender, this.mLauncherUnit, (this.mTarget == null ? 0 : this.mTarget.ID),
  755. JSGModule.GetCurveDefaultTargetPos(mLauncherUnit, this.Info.SeekingRange), launchX, launchY, startDirection, null, -1, 0, null, nextSpellIndex);
  756. addSpell.mCurveSpellList = this.mCurveSpellList;
  757. mCurveSpellIndex = 0;
  758. }
  759. }
  760. public static double AngleBetween(Vector2 vector1, Vector2 vector2)
  761. {
  762. double sin = vector1.X * vector2.Y - vector2.X * vector1.Y;
  763. double cos = vector1.X * vector2.X + vector1.Y * vector2.Y;
  764. return Math.Atan2(sin, cos);
  765. }
  766. private void updateAOE()
  767. {
  768. switch (Info.BodyShape)
  769. {
  770. case SpellTemplate.Shape.LineToTarget:
  771. case SpellTemplate.Shape.LineToStart:
  772. case SpellTemplate.Shape.Strip:
  773. case SpellTemplate.Shape.StripRay:
  774. case SpellTemplate.Shape.StripRayTouchEnd:
  775. case SpellTemplate.Shape.RectStrip:
  776. case SpellTemplate.Shape.RectStripRay:
  777. updateAoeMotion(Info.Distance, ref mDistance);
  778. break;
  779. default:
  780. updateAoeMotion(Info.BodySize, ref mBaseSize);
  781. break;
  782. }
  783. }
  784. private void updateAoeMotion(float base_value, ref float value)
  785. {
  786. switch (Info.AOEMType)
  787. {
  788. case SpellTemplate.AoeMotionType.Sine:
  789. value = (float)Math.Sin(CMath.PI_F * PassTimeMS / (float)this.mSpellTotalTime) * base_value;
  790. break;
  791. case SpellTemplate.AoeMotionType.Linear:
  792. default:
  793. value += MoveHelper.GetDistance(Parent.UpdateIntervalMS, mSpeed);
  794. break;
  795. }
  796. }
  797. private void updateBinding(InstanceZoneObject target)
  798. {
  799. if ((target is InstanceUnit))
  800. {
  801. var target_unit = target as InstanceUnit;
  802. if (mInfo.RemoveOnBindingUncontrollable)
  803. {
  804. // 目标不可操控,停止法术 //
  805. if (target_unit.IsControllable == false)
  806. {
  807. Parent.RemoveObject(this);
  808. return;
  809. }
  810. }
  811. if (mInfo.RemoveOnBindingSkillOver)
  812. {
  813. // 目标非技能状态,停止法术 //
  814. if (target_unit.CurrentState is InstanceUnit.StateSkill)
  815. {
  816. if (mBindingSkill == null)
  817. {
  818. mBindingSkill = target_unit.CurrentState as InstanceUnit.StateSkill;
  819. }
  820. else if (mBindingSkill != target_unit.CurrentState)
  821. {
  822. Parent.RemoveObject(this);
  823. return;
  824. }
  825. }
  826. else
  827. {
  828. Parent.RemoveObject(this);
  829. return;
  830. }
  831. }
  832. }
  833. if (mInfo.IsBinding)
  834. {
  835. if (mInfo.IsBindingDirection)
  836. {
  837. this.faceTo(target.Direction);
  838. }
  839. if (mInfo.IsBindingOrbit)
  840. {
  841. float dadd = mInfo.OrbitDistance;
  842. float ox = (float)Math.Cos(Direction) * dadd;
  843. float oy = (float)Math.Sin(Direction) * dadd;
  844. this.setPos(target.X + ox, target.Y + oy);
  845. }
  846. else
  847. {
  848. float xChanage, yChange;
  849. this.LaunchData.GetXModify(this.Launcher, out xChanage, out yChange);
  850. this.setPos(target.X + xChanage, target.Y + yChange);
  851. }
  852. }
  853. }
  854. private void affectToSingle(InstanceUnit target, SpellTemplate.KeyFrame kf)
  855. {
  856. if (kf == null) return;
  857. if (kf.Effect != null)
  858. {
  859. Parent.queueObjectEvent(this, new UnitEffectEvent(this.ID, kf.Effect));
  860. }
  861. // 法术造成伤害
  862. if (kf.Attack != null)
  863. {
  864. Parent.unitAttackSingle(mLauncherUnit, new AttackSource(this, kf.Attack), target, mInfo.ExpectTarget);
  865. }
  866. // 法术产生法术
  867. if (kf.Spell != null)
  868. {
  869. Parent.spellLaunchSpell(this.FromSkillType, this, kf.Spell, this.X, this.Y, target.ID);
  870. //Parent.spellLaunchSpell(this, kf.Spell, mLauncherUnit.X + 5, mLauncherUnit.Y + 5, target.ID);
  871. }
  872. // 召唤
  873. if (kf.Summon != null)
  874. {
  875. Parent.spellSummonUnit(this, kf.Summon);
  876. }
  877. }
  878. private void affectToMulti(List<InstanceUnit> list, SpellTemplate.KeyFrame kf, bool effect)
  879. {
  880. if (kf == null) return;
  881. if (effect && kf.Effect != null)
  882. {
  883. Parent.queueObjectEvent(this, new UnitEffectEvent(this.ID, kf.Effect));
  884. }
  885. uint targetUnitID = 0;
  886. if (list.Count > 0)
  887. {
  888. targetUnitID = list[0].ID;
  889. // 法术造成伤害
  890. if (kf.Attack != null)
  891. {
  892. Parent.unitAttackDirect(mLauncherUnit, new AttackSource(this, kf.Attack), list);
  893. }
  894. }
  895. // 法术产生法术
  896. if (kf.Spell != null)
  897. {
  898. Parent.spellLaunchSpell(this.FromSkillType, this, kf.Spell, this.X, this.Y, targetUnitID);
  899. //System.Console.WriteLine("------法术产生法术: " + kf.Spell.SpellID + ", " + this.X + ", " + this.Y);
  900. }
  901. // 召唤
  902. if (kf.Summon != null)
  903. {
  904. Parent.spellSummonUnit(this, kf.Summon);
  905. }
  906. }
  907. #region __检测范围内目标__
  908. // 跟踪导弹查找附近单位 //
  909. public InstanceUnit seekAttackable(float range)
  910. {
  911. return Parent.SeekSpellAttackable(this.Launcher, this.Info, this.AoiStatus,
  912. X, Y, range, mInfo.ExpectTarget, mInfo.SeekingExpectTarget, mChainInfo);
  913. }
  914. // 范围伤害,碰撞检测 //
  915. private void getShapeAttackable(List<InstanceUnit> ret, AttackReason reason, bool slowRefresh)
  916. {
  917. AttackRange.Shape = (AttackShape)mInfo.BodyShape;
  918. AttackRange.BodySize = this.mBaseSize;
  919. AttackRange.Direction = this.Direction;
  920. AttackRange.Distance = this.mDistance;
  921. AttackRange.ExpectTarget = mInfo.ExpectTarget;
  922. AttackRange.FanAngle = this.mInfo.FanAngle;
  923. AttackRange.StripWide = this.mInfo.RectWide;
  924. float prv_x = this.X;
  925. float prv_y = this.Y;
  926. if (mInfo.MType == SpellTemplate.MotionType.Straight || mInfo.MType == SpellTemplate.MotionType.StraightAndStop)
  927. {
  928. prv_x = mPrvePos.X;
  929. prv_y = mPrvePos.Y;
  930. }
  931. AttackRange.GetShapeAttackable(ret, reason, this.Info, X, Y, prv_x, prv_y, mInfo.MaxAffectUnit, AoiStatus);
  932. }
  933. #endregion
  934. float foxfireRoundAngle = 0f;
  935. int foxfireSeekWait = 0;
  936. public InstanceSpell[] brothers = null;
  937. void changeBrotherSeekWait(int timeValue)
  938. {
  939. if (brothers == null)
  940. {
  941. return;
  942. }
  943. foreach (var b in brothers)
  944. {
  945. if(b != null)
  946. {
  947. b.foxfireSeekWait += timeValue;
  948. }
  949. }
  950. }
  951. /// <summary>
  952. /// 更新范围检测以及关键帧
  953. /// </summary>
  954. private void updateKeyFrames(bool slowRefresh)
  955. {
  956. switch (Info.MType)
  957. {
  958. case SpellTemplate.MotionType.Missile:
  959. case SpellTemplate.MotionType.SeekerMissile:
  960. //【战斗】Missile类技能,在目标消失后失效//
  961. if (mTarget != null && CMath.includeRoundPoint(mTarget.X, mTarget.Y, mTarget.BodyHitSize, this.X, this.Y))
  962. {
  963. if (mTarget.IsActive)
  964. {
  965. affectToSingle(mTarget, mInfo.HitOnExplosionKeyFrame);
  966. }
  967. Parent.RemoveObject(this);
  968. }
  969. break;
  970. case SpellTemplate.MotionType.CurveMissile:
  971. //【战斗】Missile类技能,在目标消失后失效//
  972. if (mTarget != null && CMath.includeRoundPoint(mTarget.X, mTarget.Y, mTarget.BodyHitSize + this.BodyHitSize, this.X, this.Y))
  973. {
  974. if (mTarget.IsActive)
  975. {
  976. affectToSingle(mTarget, mInfo.HitOnExplosionKeyFrame);
  977. }
  978. this.checkAndLaunchCurveSpell(true);
  979. Parent.RemoveObject(this);
  980. }
  981. break;
  982. case SpellTemplate.MotionType.MissileAttackRoute:
  983. if (mTarget != null && CMath.includeRoundPoint(mTarget.X, mTarget.Y, mTarget.BodyHitSize, this.X, this.Y))
  984. {
  985. if (mTarget.IsActive)
  986. {
  987. affectToSingle(mTarget, mInfo.HitOnExplosionKeyFrame);
  988. }
  989. Parent.RemoveObject(this);
  990. }
  991. else if (mSeekingCooldownTime.Update(Parent.UpdateIntervalMS))
  992. {
  993. using (var enemy_list = ListObjectPool<InstanceUnit>.AllocAutoRelease())
  994. {
  995. getShapeAttackable(enemy_list, AttackReason.Attack, slowRefresh);
  996. if (enemy_list.Count > 0)
  997. {
  998. InstanceUnit target = enemy_list[0];
  999. if (target.IsActive)
  1000. {
  1001. affectToSingle(target, mInfo.HitOnExplosionKeyFrame);
  1002. }
  1003. mSeekingCooldownTime.Reset();
  1004. }
  1005. }
  1006. }
  1007. break;
  1008. case SpellTemplate.MotionType.Cannon:
  1009. if (Finish)
  1010. {
  1011. SpellTemplate.KeyFrame kf = mInfo.HitOnExplosionKeyFrame;
  1012. if (kf != null)
  1013. {
  1014. using (var list = ListObjectPool<InstanceUnit>.AllocAutoRelease())
  1015. {
  1016. getShapeAttackable(list, AttackReason.Attack, slowRefresh);
  1017. affectToMulti(list, kf, true);
  1018. }
  1019. }
  1020. Parent.RemoveObject(this);
  1021. }
  1022. break;
  1023. case SpellTemplate.MotionType.Chain:
  1024. if (mTarget != null)
  1025. {
  1026. if (Collider.Object_Pos_IncludeInRound(mTarget, this.X, this.Y, this.mDistance))
  1027. {
  1028. updateKeyFrameSingleTarget(mTarget, true);
  1029. }
  1030. else
  1031. {
  1032. Parent.RemoveObject(this);
  1033. }
  1034. }
  1035. break;
  1036. case SpellTemplate.MotionType.Boomerang1:
  1037. case SpellTemplate.MotionType.Boomerang2:
  1038. if (Info.SpecialEffect == SpellTemplate.SpecialAdditionalEffect.DragPath && Info.SpecialEffectParam != 0f)
  1039. {
  1040. updateDragPathKeyFramesRanged(slowRefresh);
  1041. }
  1042. else if (Info.SpecialEffect == SpellTemplate.SpecialAdditionalEffect.DarkHole && Info.SpecialEffectParam != 0f)
  1043. {
  1044. updateDarkHoleKeyFramesRanged(slowRefresh);
  1045. }
  1046. else
  1047. {
  1048. updateKeyFramesRanged(slowRefresh);
  1049. }
  1050. if (Finish)
  1051. {
  1052. Parent.RemoveObject(this);
  1053. }
  1054. break;
  1055. case SpellTemplate.MotionType.Foxfire:
  1056. if (mTarget != null && CMath.includeRoundPoint(mTarget.X, mTarget.Y, mTarget.BodyHitSize, this.X, this.Y))
  1057. {
  1058. if (mTarget.IsActive)
  1059. {
  1060. affectToSingle(mTarget, mInfo.HitOnExplosionKeyFrame);
  1061. }
  1062. Parent.RemoveObject(this);
  1063. }
  1064. break;
  1065. default:
  1066. if (Info.BodyShape == SpellTemplate.Shape.LineToTarget || Info.BodyShape == SpellTemplate.Shape.LineToStart)
  1067. {
  1068. if (mTarget != null && Collider.Object_Pos_IncludeInRound(mTarget, this.X, this.Y, this.mDistance))
  1069. {
  1070. updateKeyFrameSingleTarget(mTarget, true);
  1071. }
  1072. else
  1073. {
  1074. updateKeyFrameSingleTarget(mTarget, false);
  1075. }
  1076. }
  1077. else
  1078. {
  1079. if (Info.SpecialEffect == SpellTemplate.SpecialAdditionalEffect.DragPath && Info.SpecialEffectParam != 0f)
  1080. {
  1081. updateDragPathKeyFramesRanged(slowRefresh);
  1082. }
  1083. else if (Info.SpecialEffect == SpellTemplate.SpecialAdditionalEffect.DarkHole && Info.SpecialEffectParam != 0f)
  1084. {
  1085. updateDarkHoleKeyFramesRanged(slowRefresh);
  1086. }
  1087. else
  1088. {
  1089. updateKeyFramesRanged(slowRefresh);
  1090. }
  1091. }
  1092. break;
  1093. }
  1094. }
  1095. private void updateKeyFrameSingleTarget(InstanceUnit enemy, bool affect)
  1096. {
  1097. using (var kfs = ListObjectPool<SpellTemplate.KeyFrame>.AllocAutoRelease())
  1098. {
  1099. int kfs_count = mKeyFrames.PopKeyFrames(PassTimeMS, kfs);
  1100. bool is_interval_test = mHitIntervalTicker.Update(Parent.UpdateIntervalMS);
  1101. if (affect)
  1102. {
  1103. if (kfs_count > 0 || is_interval_test || mInfo.HitIntervalMS == 0)
  1104. {
  1105. if (kfs_count > 0)
  1106. {
  1107. for (int i = 0; i < kfs.Count; i++)
  1108. {
  1109. affectToSingle(enemy, kfs[i]);
  1110. }
  1111. }
  1112. if (mInfo.HitOnExplosion)
  1113. {
  1114. // 击中后爆炸
  1115. affectToSingle(enemy, mInfo.HitOnExplosionKeyFrame);
  1116. Parent.RemoveObject(this);
  1117. }
  1118. else if (mInfo.HitIntervalKeyFrame != null)
  1119. {
  1120. if (mInfo.HitIntervalMS == 0)
  1121. {
  1122. // 只在接触后第一次产生效果
  1123. if (!mHittedUnits.ContainsKey(enemy.ID))
  1124. {
  1125. affectToSingle(enemy, mInfo.HitIntervalKeyFrame);
  1126. mHittedUnits.Add(enemy.ID, enemy);
  1127. }
  1128. }
  1129. else if (is_interval_test)
  1130. {
  1131. // 间隔产生效果
  1132. affectToSingle(enemy, mInfo.HitIntervalKeyFrame);
  1133. }
  1134. }
  1135. }
  1136. }
  1137. }
  1138. }
  1139. private void updateKeyFramesRanged(bool slowRefresh)
  1140. {
  1141. using (var kfs = ListObjectPool<SpellTemplate.KeyFrame>.AllocAutoRelease())
  1142. {
  1143. //if(mKeyFrames == null)
  1144. //{
  1145. // long ltime1 = CommonLang.CUtils.localTimeMS - mDisPosingTime;
  1146. // long ltime2 = System.DateTime.Now.Ticks - mDisPosingTime1;
  1147. //}
  1148. int kfs_count = mKeyFrames.PopKeyFrames(PassTimeMS, kfs);
  1149. bool is_interval_test = mHitIntervalTicker.Update(Parent.UpdateIntervalMS);
  1150. //此处修正 加入触发次数上限检测
  1151. if (is_interval_test && mInfo.HitIntervalMS > 0 && mHitIntervalTicker.TotalTickCount > (this.mSpellTotalTime / mInfo.HitIntervalMS))
  1152. {
  1153. is_interval_test = false;
  1154. }
  1155. if (kfs_count > 0 || is_interval_test || mInfo.HitIntervalMS == 0)
  1156. {
  1157. this.mHitTotalTimes++;
  1158. using (var enemy_list = ListObjectPool<InstanceUnit>.AllocAutoRelease())
  1159. {
  1160. getShapeAttackable(enemy_list, AttackReason.Attack, slowRefresh);
  1161. if (kfs_count > 0)
  1162. {
  1163. // 单Frame情况下,如果是Attack。进行唯一敌人判定(X型拼接法术, 需要伤害只生效一次)
  1164. //if (kfs_count == 1 && mInfo.HitIntervalMS == 0 && this.mInfo.KeyFrames.Count == 1 && kfs[0].Attack != null && this.mInfo.HitIntervalKeyFrame == null)
  1165. if(this.LaunchData.PType == LaunchSpell.PosType.POS_TYPE_X)
  1166. {
  1167. if(this.refreshHitUnit(enemy_list))
  1168. {
  1169. for (int i = 0; i < kfs.Count; i++)
  1170. {
  1171. affectToMulti(enemy_list, kfs[i], true);
  1172. }
  1173. }
  1174. }
  1175. else
  1176. {
  1177. for (int i = 0; i < kfs.Count; i++)
  1178. {
  1179. affectToMulti(enemy_list, kfs[i], true);
  1180. }
  1181. }
  1182. }
  1183. if (mInfo.HitOnExplosion)
  1184. {
  1185. if (enemy_list.Count > 0)
  1186. {
  1187. // 击中后爆炸
  1188. affectToMulti(enemy_list, mInfo.HitOnExplosionKeyFrame, true);
  1189. Parent.RemoveObject(this);
  1190. }
  1191. }
  1192. else if(mInfo.HitIntervalKeyFrame != null)
  1193. {
  1194. if (mInfo.HitIntervalMS == 0)
  1195. {
  1196. // 只在接触后第一次产生效果
  1197. if (enemy_list.Count > 0 && this.refreshHitUnit(enemy_list))
  1198. {
  1199. affectToMulti(enemy_list, mInfo.HitIntervalKeyFrame, true);
  1200. }
  1201. }
  1202. else if (is_interval_test)
  1203. {
  1204. // 间隔产生效果
  1205. affectToMulti(enemy_list, mInfo.HitIntervalKeyFrame, false);
  1206. }
  1207. }
  1208. }
  1209. }
  1210. }
  1211. }
  1212. private void updateDarkHoleKeyFramesRanged(bool slowRefresh)
  1213. {
  1214. using (var kfs = ListObjectPool<SpellTemplate.KeyFrame>.AllocAutoRelease())
  1215. {
  1216. using (var enemy_list = ListObjectPool<InstanceUnit>.AllocAutoRelease())
  1217. {
  1218. getShapeAttackable(enemy_list, AttackReason.Attack, slowRefresh);
  1219. for (int i = enemy_list.Count - 1; i >= 0; --i)
  1220. {
  1221. if(enemy_list[i].IsIgnoreControl)
  1222. {
  1223. continue;
  1224. }
  1225. float angle, distance, offset, dx, dy;
  1226. if (enemy_list[i].Weight < XmdsConstConfig.DEFAULT_WEIGHT)
  1227. {
  1228. offset = MoveHelper.GetDistance(Parent.UpdateIntervalMS, Info.SpecialEffectParam);
  1229. dx = this.X - enemy_list[i].X;
  1230. dy = this.Y - enemy_list[i].Y;
  1231. distance = dx * dx + dy * dy;
  1232. if (offset * offset < distance)
  1233. {
  1234. angle = MathVector.getDegree(dx, dy);
  1235. enemy_list[i].moveLinearMap(offset, angle);
  1236. }
  1237. else
  1238. {
  1239. enemy_list[i].moveLinearMap2(dx, dy);
  1240. }
  1241. enemy_list[i].SetStunTimeMS(100);
  1242. }
  1243. }
  1244. int kfs_count = mKeyFrames.PopKeyFrames(PassTimeMS, kfs);
  1245. bool is_interval_test = mHitIntervalTicker.Update(Parent.UpdateIntervalMS);
  1246. #region <<关键帧逻辑>>
  1247. if (kfs_count > 0 || is_interval_test || mInfo.HitIntervalMS == 0)
  1248. {
  1249. //getShapeAttackable(enemy_list, AttackReason.Attack);
  1250. if (kfs_count > 0)
  1251. {
  1252. for (int i = 0; i < kfs.Count; i++)
  1253. {
  1254. affectToMulti(enemy_list, kfs[i], false);
  1255. }
  1256. }
  1257. if (mInfo.HitOnExplosion)
  1258. {
  1259. if (enemy_list.Count > 0)
  1260. {
  1261. // 击中后爆炸
  1262. affectToMulti(enemy_list, mInfo.HitOnExplosionKeyFrame, true);
  1263. Parent.RemoveObject(this);
  1264. }
  1265. }
  1266. else if(mInfo.HitIntervalKeyFrame != null)
  1267. {
  1268. if (mInfo.HitIntervalMS == 0)
  1269. {
  1270. // 只在接触后第一次产生效果
  1271. if (enemy_list.Count > 0 && this.refreshHitUnit(enemy_list))
  1272. {
  1273. affectToMulti(enemy_list, mInfo.HitIntervalKeyFrame, true);
  1274. }
  1275. }
  1276. else if (is_interval_test)
  1277. {
  1278. // 间隔产生效果
  1279. affectToMulti(enemy_list, mInfo.HitIntervalKeyFrame, false);
  1280. }
  1281. }
  1282. }
  1283. #endregion
  1284. }
  1285. }
  1286. }
  1287. public override String GetTemplateData()
  1288. {
  1289. return "Spell:" + this.Info.ID;
  1290. }
  1291. private bool refreshHitUnit(CommonLang.ListObjectPool<InstanceUnit>.AutoReleaseList<InstanceUnit> enemy_list)
  1292. {
  1293. if(enemy_list.Count <= 0)
  1294. {
  1295. return true;
  1296. }
  1297. foreach (InstanceUnit u in mHittedUnits.Values)
  1298. {
  1299. enemy_list.Remove(u);
  1300. }
  1301. if (enemy_list.Count > 0)
  1302. {
  1303. for (int i = enemy_list.Count - 1; i >= 0; --i)
  1304. {
  1305. InstanceUnit u = enemy_list[i];
  1306. mHittedUnits.Add(u.ID, u);
  1307. }
  1308. return true;
  1309. }
  1310. return false;
  1311. }
  1312. public const float Pi = (float)Math.PI;
  1313. public const float PiOver2 = (float)(Math.PI / 2.0);
  1314. public const float PiOver36 = (float)(Math.PI / 36.0);
  1315. public const float TwoPi = (float)(Math.PI * 2.0);
  1316. private void updateDragPathKeyFramesRanged(bool slowRefresh)
  1317. {
  1318. using (var kfs = ListObjectPool<SpellTemplate.KeyFrame>.AllocAutoRelease())
  1319. {
  1320. using (var enemy_list = ListObjectPool<InstanceUnit>.AllocAutoRelease())
  1321. {
  1322. getShapeAttackable(enemy_list, AttackReason.Attack, slowRefresh);
  1323. float _a, _b, _angle, offset, dx, dy , dis;
  1324. for (int i = enemy_list.Count - 1; i >= 0; --i)
  1325. {
  1326. if (enemy_list[i].IsIgnoreControl)
  1327. {
  1328. continue;
  1329. }
  1330. if (enemy_list[i].Weight < XmdsConstConfig.DEFAULT_WEIGHT)
  1331. {
  1332. dx = enemy_list[i].X - this.X;
  1333. dy = enemy_list[i].Y - this.Y;
  1334. _a = MathVector.getDegree(dx, dy);
  1335. _b = this.Direction - _a;
  1336. if (_b < -Pi)
  1337. {
  1338. _b += TwoPi;
  1339. }
  1340. else if(_b > Pi)
  1341. {
  1342. _b -= TwoPi;
  1343. }
  1344. if (Math.Abs(_b) < PiOver36)
  1345. {
  1346. continue;
  1347. }
  1348. if(_b > 0)
  1349. {
  1350. if(_b > PiOver2)
  1351. {
  1352. continue;
  1353. }
  1354. _angle = this.Direction + PiOver2;
  1355. }
  1356. else
  1357. {
  1358. if (_b < -PiOver2)
  1359. {
  1360. continue;
  1361. }
  1362. _angle = this.Direction - PiOver2;
  1363. }
  1364. dis = Math.Abs((float)(dy * Math.Sin(_angle) / Math.Sin(_a)));
  1365. offset = MoveHelper.GetDistance(Parent.UpdateIntervalMS, Info.SpecialEffectParam);
  1366. if(offset > dis)
  1367. {
  1368. offset = dis;
  1369. }
  1370. enemy_list[i].moveLinearMap(offset, _angle);
  1371. enemy_list[i].SetStunTimeMS(100);
  1372. }
  1373. }
  1374. int kfs_count = mKeyFrames.PopKeyFrames(PassTimeMS, kfs);
  1375. bool is_interval_test = mHitIntervalTicker.Update(Parent.UpdateIntervalMS);
  1376. #region <<关键帧逻辑>>
  1377. if (kfs_count > 0 || is_interval_test || mInfo.HitIntervalMS == 0)
  1378. {
  1379. //getShapeAttackable(enemy_list, AttackReason.Attack);
  1380. if (kfs_count > 0)
  1381. {
  1382. for (int i = 0; i < kfs.Count; i++)
  1383. {
  1384. affectToMulti(enemy_list, kfs[i], false);
  1385. }
  1386. }
  1387. if (mInfo.HitOnExplosion)
  1388. {
  1389. if (enemy_list.Count > 0)
  1390. {
  1391. // 击中后爆炸
  1392. affectToMulti(enemy_list, mInfo.HitOnExplosionKeyFrame, true);
  1393. Parent.RemoveObject(this);
  1394. }
  1395. }
  1396. else if (mInfo.HitIntervalKeyFrame != null)
  1397. {
  1398. if (mInfo.HitIntervalMS == 0)
  1399. {
  1400. // 只在接触后第一次产生效果
  1401. if (enemy_list.Count > 0 && this.refreshHitUnit(enemy_list))
  1402. {
  1403. affectToMulti(enemy_list, mInfo.HitIntervalKeyFrame, true);
  1404. }
  1405. }
  1406. else if (is_interval_test)
  1407. {
  1408. // 间隔产生效果
  1409. affectToMulti(enemy_list, mInfo.HitIntervalKeyFrame, false);
  1410. }
  1411. }
  1412. }
  1413. #endregion
  1414. }
  1415. }
  1416. }
  1417. }
  1418. }