InstanceSpell.cs 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462
  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. readonly 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 readonly 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. protected override void onRemoved()
  377. {
  378. if (mInfo.StopBindingSkillOnRemoved)
  379. {
  380. if (this.Launcher != null && this.Launcher.CurrentState is InstanceUnit.StateSkill)
  381. {
  382. (this.Launcher.CurrentState as InstanceUnit.StateSkill).block();
  383. this.Launcher.doSomething();
  384. }
  385. }
  386. }
  387. override protected void onUpdate(bool slowRefresh)
  388. {
  389. if (IsPaused) { return; }
  390. if (Info.MaxMoveDistance == 0 || mMoveDistance < Info.MaxMoveDistance)
  391. {
  392. updateMotion();
  393. if (mInfo.IsMoveable)
  394. {
  395. MoveHelper.UpdateSpeed(Parent.UpdateIntervalMS, ref mSpeed, mInfo.MSpeedAdd, mInfo.MSpeedAcc, mInfo.MSpeed_MIN, mInfo.MSpeed_MAX);
  396. MoveHelper.UpdateMoveDistance(Parent.UpdateIntervalMS, ref mMoveDistance, mSpeed);
  397. }
  398. }
  399. updateKeyFrames();
  400. if (mInfo.MType == SpellTemplate.MotionType.Foxfire && mTarget != null)
  401. {
  402. }
  403. else if(mInfo.MType == SpellTemplate.MotionType.CurveMissile && mTarget != null)
  404. {
  405. }
  406. else if (mInfo.MType == SpellTemplate.MotionType.Boomerang1 || mInfo.MType == SpellTemplate.MotionType.Boomerang2)
  407. {
  408. }
  409. else if (mInfo.MType == SpellTemplate.MotionType.Binding)//绑定自身的spell才在自己死亡时移除
  410. {
  411. if (!Sender.Enable || Sender.IsDead())
  412. {
  413. Parent.RemoveObject(this);
  414. }
  415. else if((Sender.AoiStatus == null && this.aoiFlag == 1) || (Sender.AoiStatus != null && this.aoiFlag == 0))
  416. {
  417. //玩家AOI状态改变了,也要清一下
  418. Parent.RemoveObject(this);
  419. }
  420. StateSkill skill = this.mLauncherUnit.CurrentState as StateSkill;
  421. if (skill != null && skill.Skill != null && skill.SkillData.ActionQueue.Count > 1)
  422. {
  423. //UnitActionData curSkillAction = skill.Skill.GetCurAction();
  424. if (skill.CurrentActionIndex != this.actionIndex
  425. && (0 <= this.actionIndex && this.actionIndex < skill.SkillData.ActionQueue.Count)
  426. && skill.SkillData.ActionQueue[this.actionIndex].IsCancelBySkillNext)
  427. {
  428. Parent.RemoveObject(this);
  429. }
  430. }
  431. }
  432. if (PassTimeMS >= this.mSpellTotalTime)
  433. {
  434. Parent.RemoveObject(this);//Parent.RemoveObjectByID(ID);
  435. }
  436. }
  437. /// <summary>
  438. /// 更新移动行为
  439. /// </summary>
  440. private void updateMotion()
  441. {
  442. this.mPrvePos.SetX(X);
  443. this.mPrvePos.SetY(Y);
  444. switch (mInfo.MType)
  445. {
  446. case SpellTemplate.MotionType.Immovability:
  447. case SpellTemplate.MotionType.SelectTarget:
  448. case SpellTemplate.MotionType.SelectLauncher:
  449. break;
  450. case SpellTemplate.MotionType.Cannon:
  451. if (mTargetPos != null)
  452. {
  453. if(flyToTarget(mTargetPos.X, mTargetPos.Y, mSpeed, Parent.UpdateIntervalMS))
  454. {
  455. this.Finish = true;
  456. }
  457. }
  458. else if(PassTimeMS + Parent.UpdateIntervalMS >= this.mSpellTotalTime)//没有目标,结束时触发下
  459. {
  460. if(Parent.UpdateIntervalMS > 0)
  461. {
  462. this.Finish = true;
  463. }
  464. }
  465. break;
  466. case SpellTemplate.MotionType.Straight:
  467. flyTo(mLaunchDirection, mSpeed, Parent.UpdateIntervalMS);
  468. break;
  469. case SpellTemplate.MotionType.AOE:
  470. updateAOE();
  471. break;
  472. case SpellTemplate.MotionType.AOE_Binding:
  473. updateAOE();
  474. if (mSender != null && mSender.Enable)
  475. {
  476. updateBinding(mSender);
  477. }
  478. else
  479. {
  480. Parent.RemoveObject(this);
  481. }
  482. break;
  483. case SpellTemplate.MotionType.AOE_BindingTarget:
  484. updateAOE();
  485. if (mTarget != null && mTarget.IsActive)
  486. {
  487. updateBinding(mTarget);
  488. }
  489. else
  490. {
  491. Parent.RemoveObject(this);
  492. }
  493. break;
  494. case SpellTemplate.MotionType.Binding:
  495. if (mSender != null && mSender.Enable)
  496. {
  497. updateBinding(mSender);
  498. }
  499. else
  500. {
  501. Parent.RemoveObject(this);
  502. }
  503. break;
  504. case SpellTemplate.MotionType.BindingTarget:
  505. if (mTarget != null && mTarget.IsActive)
  506. {
  507. updateBinding(mTarget);
  508. }
  509. else
  510. {
  511. Parent.RemoveObject(this);
  512. }
  513. break;
  514. case SpellTemplate.MotionType.Missile:
  515. case SpellTemplate.MotionType.MissileAttackRoute:
  516. if (mTarget != null)
  517. {
  518. if (mInfo.RotateSpeedSEC == 0)
  519. {
  520. faceTo(mTarget.X, mTarget.Y);
  521. }
  522. flyToTarget(mTarget.X, mTarget.Y, mSpeed, Parent.UpdateIntervalMS);
  523. }
  524. else
  525. {
  526. flyTo(mLaunchDirection, mSpeed, Parent.UpdateIntervalMS);
  527. }
  528. break;
  529. case SpellTemplate.MotionType.SeekerMissile:
  530. if (mTarget != null)
  531. {
  532. if (mInfo.SeekingTurningAngleSEC != 0)
  533. {
  534. flyToTargetTunning(mTarget.X, mTarget.Y, mSpeed, mInfo.SeekingTurningAngleSEC, Parent.UpdateIntervalMS);
  535. }
  536. else
  537. {
  538. faceTo(mTarget.X, mTarget.Y);
  539. flyToTarget(mTarget.X, mTarget.Y, mSpeed, Parent.UpdateIntervalMS);
  540. }
  541. }
  542. else
  543. {
  544. flyTo(mLaunchDirection, mSpeed, Parent.UpdateIntervalMS);
  545. if (mSeekingCooldownTime == null || mSeekingCooldownTime.Update(Parent.UpdateIntervalMS))
  546. {
  547. mTarget = seekAttackable(mInfo.SeekingRange);
  548. if (mTarget != null)
  549. {
  550. Parent.queueObjectEvent(this, new SpellLockTargetEvent(ID, mTarget.ID, X, Y));
  551. }
  552. }
  553. }
  554. break;
  555. case SpellTemplate.MotionType.SeekerSelectTarget:
  556. if (mTarget == null)
  557. {
  558. if (mSeekingCooldownTime == null || mSeekingCooldownTime.Update(Parent.UpdateIntervalMS))
  559. {
  560. mTarget = seekAttackable(mInfo.SeekingRange);
  561. if (mTarget != null)
  562. {
  563. this.setPos(mTarget.X, mTarget.Y);
  564. Parent.queueObjectEvent(this, new SpellLockTargetEvent(ID, mTarget.ID, X, Y));
  565. }
  566. }
  567. }
  568. break;
  569. case SpellTemplate.MotionType.Chain:
  570. if (mSender != null && mSender.Enable && mTarget != null && mTarget.IsActive)
  571. {
  572. setPos(mSender.X, mSender.Y);
  573. faceTo(mTarget.X, mTarget.Y);
  574. updateBinding(mTarget);
  575. }
  576. else
  577. {
  578. Parent.RemoveObject(this);
  579. }
  580. break;
  581. case SpellTemplate.MotionType.Boomerang1:
  582. if (PassTimeMS < mInfo.BoomerangFlyTime)
  583. {
  584. flyTo(mLaunchDirection, mSpeed, Parent.UpdateIntervalMS);
  585. }
  586. else if (PassTimeMS > mInfo.BoomerangFlyTime + mInfo.BoomerangHangtime)
  587. {
  588. if (flyToTarget(mLauncherUnit.X, mLauncherUnit.Y, mSpeed * 1.4f, Parent.UpdateIntervalMS))
  589. {
  590. this.Finish = true;
  591. }
  592. }
  593. break;
  594. case SpellTemplate.MotionType.Boomerang2:
  595. if (PassTimeMS < mInfo.BoomerangFlyTime)
  596. {
  597. flyTo(mLaunchDirection, mSpeed, Parent.UpdateIntervalMS);
  598. }
  599. else if (PassTimeMS > mInfo.BoomerangFlyTime + mInfo.BoomerangHangtime)
  600. {
  601. if (flyToTarget(mStartPos.X, mStartPos.Y, mSpeed * 1.4f, Parent.UpdateIntervalMS))
  602. {
  603. this.Finish = true;
  604. }
  605. }
  606. break;
  607. case SpellTemplate.MotionType.CurveMissile:
  608. //IPosBase targetPos = mTargetPos;
  609. IPosBase targetPos = (mTarget != null) ? (IPosBase)mTarget : (IPosBase)mTargetPos;
  610. if (targetPos == null)
  611. {
  612. flyTo(mLaunchDirection, mSpeed, Parent.UpdateIntervalMS);
  613. }
  614. else if (mInfo.SeekingTurningAngleSEC != 0)
  615. {
  616. flyToTargetTunning(targetPos.X, targetPos.Y, mSpeed, mInfo.SeekingTurningAngleSEC, Parent.UpdateIntervalMS);
  617. }
  618. else
  619. {
  620. faceTo(targetPos.X, targetPos.Y);
  621. flyToTarget(targetPos.X, targetPos.Y, mSpeed, Parent.UpdateIntervalMS);
  622. }
  623. if (mTarget == null && (mSeekingCooldownTime == null || mSeekingCooldownTime.Update(Parent.UpdateIntervalMS)))
  624. {
  625. mTarget = seekAttackable(mInfo.SeekingRange);
  626. if (mTarget != null)
  627. {
  628. Parent.queueObjectEvent(this, new SpellLockTargetEvent(ID, mTarget.ID, X, Y));
  629. }
  630. }
  631. //////创建后续个飞弹
  632. if (PassTimeMS >= XmdsConstConfig.GAME_UPDATE_INTERVAL_MS && mCurveSpellIndex > 0 && this.Launcher.IsActive)
  633. {
  634. int nextSpellIndex = Math.Max(0, mCurveSpellIndex - 1);
  635. int flag = (this.mCreateSpellData.mMaxSpellCount - mCurveSpellIndex) % 2 == 0 ? 2 : -2;
  636. //float angleOffset = (this.Target == null ? this.LaunchData.StartAngle / 3 : this.LaunchData.StartAngle);
  637. float angleOffset = JSGModule.GetCurveStartAngleOffect(mLauncherUnit, this.mTarget, this.LaunchData.StartAngle, this.Info.SeekingRange);
  638. float startDirection = this.mLaunchDirection + angleOffset * flag;
  639. float launchX = this.Launcher.X - (float)(1.0f * Math.Cos(this.Launcher.Direction));
  640. float launchY = this.Launcher.Y - (float)(1.0f * Math.Sin(this.Launcher.Direction));
  641. LaunchSpell launchSpell = this.LaunchData;
  642. if (mCurveSpellList != null && mCurveSpellList.Count > mCurveSpellIndex)
  643. {
  644. launchSpell = mCurveSpellList[mCurveSpellIndex];
  645. }
  646. InstanceSpell addSpell = this.Parent.AddSpell(this.FromSkillType, this.Info, launchSpell, this.Sender, this.mLauncherUnit, (this.mTarget == null ? 0 : this.mTarget.ID),
  647. JSGModule.GetCurveDefaultTargetPos(mLauncherUnit, this.Info.SeekingRange), launchX, launchY, startDirection, null, -1, 0, null, nextSpellIndex);
  648. addSpell.mCurveSpellList = this.mCurveSpellList;
  649. mCurveSpellIndex = 0;
  650. }
  651. break;
  652. case SpellTemplate.MotionType.Foxfire:
  653. if (mTarget == null)
  654. {
  655. foxfireRoundAngle = mLaunchDirection + PassTimeMS * 0.001f * 3;
  656. var x = mLauncherUnit.X + (float)(Math.Cos(foxfireRoundAngle + 0.3f) * mLaunchData.LaunchSpellRadius);
  657. var y = mLauncherUnit.Y + (float)(Math.Sin(foxfireRoundAngle + 0.3f) * mLaunchData.LaunchSpellRadius);
  658. flyToTarget(x, y, mSpeed, Parent.UpdateIntervalMS);
  659. if (mInfo.RotateSpeedSEC == 0)
  660. {
  661. faceTo(foxfireRoundAngle + (float)Math.PI * 0.25f);
  662. }
  663. if (foxfireSeekWait >= this.Info.SeekingCooldownMS && PassTimeMS < this.mSpellTotalTime - 500)
  664. {
  665. var tar = seekAttackable(mInfo.SeekingRange);
  666. if (tar != null && tar != mLauncherUnit)
  667. {
  668. changeBrotherSeekWait(-250);
  669. Parent.queueObjectEvent(this, new SpellLockTargetEvent(ID, tar.ID, X, Y));
  670. mTarget = tar;
  671. }
  672. }
  673. foxfireSeekWait += Parent.UpdateIntervalMS;
  674. }
  675. else
  676. {
  677. if (mInfo.SeekingTurningAngleSEC != 0)
  678. {
  679. flyToTargetTunning(mTarget.X, mTarget.Y, mSpeed, mInfo.SeekingTurningAngleSEC, Parent.UpdateIntervalMS);
  680. }
  681. else
  682. {
  683. faceTo(mTarget.X, mTarget.Y);
  684. flyToTarget(mTarget.X, mTarget.Y, mSpeed, Parent.UpdateIntervalMS);
  685. }
  686. }
  687. break;
  688. case SpellTemplate.MotionType.StraightAndStop:
  689. if (PassTimeMS < mInfo.BoomerangFlyTime)
  690. {
  691. flyTo(mLaunchDirection, mSpeed, Parent.UpdateIntervalMS);
  692. }
  693. //else if (PassTimeMS > mInfo.BoomerangFlyTime + mInfo.BoomerangHangtime)
  694. //{
  695. // if (flyToTarget(mLauncherUnit.X, mLauncherUnit.Y, mSpeed * 1.8f, Parent.UpdateIntervalMS))
  696. // {
  697. // this.Finish = true;
  698. // }
  699. //}
  700. break;
  701. }
  702. if (mInfo.BodyShape == SpellTemplate.Shape.LineToTarget)
  703. {
  704. if (mTarget != null)
  705. {
  706. this.faceTo(mTarget.X, mTarget.Y);
  707. }
  708. }
  709. else if (mInfo.BodyShape == SpellTemplate.Shape.LineToStart)
  710. {
  711. this.faceTo(mStartPos.X, mStartPos.Y);
  712. }
  713. else if (mInfo.RotateSpeedSEC != 0 && mInfo.MType != SpellTemplate.MotionType.SeekerMissile)
  714. {
  715. this.turn(MoveHelper.GetDistance(Parent.UpdateIntervalMS, mInfo.RotateSpeedSEC));
  716. }
  717. }
  718. public static double AngleBetween(Vector2 vector1, Vector2 vector2)
  719. {
  720. double sin = vector1.X * vector2.Y - vector2.X * vector1.Y;
  721. double cos = vector1.X * vector2.X + vector1.Y * vector2.Y;
  722. return Math.Atan2(sin, cos);
  723. }
  724. private void updateAOE()
  725. {
  726. switch (Info.BodyShape)
  727. {
  728. case SpellTemplate.Shape.LineToTarget:
  729. case SpellTemplate.Shape.LineToStart:
  730. case SpellTemplate.Shape.Strip:
  731. case SpellTemplate.Shape.StripRay:
  732. case SpellTemplate.Shape.StripRayTouchEnd:
  733. case SpellTemplate.Shape.RectStrip:
  734. case SpellTemplate.Shape.RectStripRay:
  735. updateAoeMotion(Info.Distance, ref mDistance);
  736. break;
  737. default:
  738. updateAoeMotion(Info.BodySize, ref mBaseSize);
  739. break;
  740. }
  741. }
  742. private void updateAoeMotion(float base_value, ref float value)
  743. {
  744. switch (Info.AOEMType)
  745. {
  746. case SpellTemplate.AoeMotionType.Sine:
  747. value = (float)Math.Sin(CMath.PI_F * PassTimeMS / (float)this.mSpellTotalTime) * base_value;
  748. break;
  749. case SpellTemplate.AoeMotionType.Linear:
  750. default:
  751. value += MoveHelper.GetDistance(Parent.UpdateIntervalMS, mSpeed);
  752. break;
  753. }
  754. }
  755. private void updateBinding(InstanceZoneObject target)
  756. {
  757. if ((target is InstanceUnit))
  758. {
  759. var target_unit = target as InstanceUnit;
  760. if (mInfo.RemoveOnBindingUncontrollable)
  761. {
  762. // 目标不可操控,停止法术 //
  763. if (target_unit.IsControllable == false)
  764. {
  765. Parent.RemoveObject(this);
  766. return;
  767. }
  768. }
  769. if (mInfo.RemoveOnBindingSkillOver)
  770. {
  771. // 目标非技能状态,停止法术 //
  772. if (target_unit.CurrentState is InstanceUnit.StateSkill)
  773. {
  774. if (mBindingSkill == null)
  775. {
  776. mBindingSkill = target_unit.CurrentState as InstanceUnit.StateSkill;
  777. }
  778. else if (mBindingSkill != target_unit.CurrentState)
  779. {
  780. Parent.RemoveObject(this);
  781. return;
  782. }
  783. }
  784. else
  785. {
  786. Parent.RemoveObject(this);
  787. return;
  788. }
  789. }
  790. }
  791. if (mInfo.IsBinding)
  792. {
  793. if (mInfo.IsBindingDirection)
  794. {
  795. this.faceTo(target.Direction);
  796. }
  797. if (mInfo.IsBindingOrbit)
  798. {
  799. float dadd = mInfo.OrbitDistance;
  800. float ox = (float)Math.Cos(Direction) * dadd;
  801. float oy = (float)Math.Sin(Direction) * dadd;
  802. this.setPos(target.X + ox, target.Y + oy);
  803. }
  804. else
  805. {
  806. float xChanage, yChange;
  807. this.LaunchData.GetXModify(this.Launcher, out xChanage, out yChange);
  808. this.setPos(target.X + xChanage, target.Y + yChange);
  809. }
  810. }
  811. }
  812. private void affectToSingle(InstanceUnit target, SpellTemplate.KeyFrame kf)
  813. {
  814. if (kf == null) return;
  815. if (kf.Effect != null)
  816. {
  817. Parent.queueObjectEvent(this, new UnitEffectEvent(this.ID, kf.Effect));
  818. }
  819. // 法术造成伤害
  820. if (kf.Attack != null)
  821. {
  822. Parent.unitAttackSingle(mLauncherUnit, new AttackSource(this, kf.Attack), target, mInfo.ExpectTarget);
  823. }
  824. // 法术产生法术
  825. if (kf.Spell != null)
  826. {
  827. Parent.spellLaunchSpell(this.FromSkillType, this, kf.Spell, this.X, this.Y, target.ID);
  828. //Parent.spellLaunchSpell(this, kf.Spell, mLauncherUnit.X + 5, mLauncherUnit.Y + 5, target.ID);
  829. }
  830. // 召唤
  831. if (kf.Summon != null)
  832. {
  833. Parent.spellSummonUnit(this, kf.Summon);
  834. }
  835. }
  836. private void affectToMulti(List<InstanceUnit> list, SpellTemplate.KeyFrame kf, bool effect)
  837. {
  838. if (kf == null) return;
  839. if (effect && kf.Effect != null)
  840. {
  841. Parent.queueObjectEvent(this, new UnitEffectEvent(this.ID, kf.Effect));
  842. }
  843. uint targetUnitID = 0;
  844. if (list.Count > 0)
  845. {
  846. targetUnitID = list[0].ID;
  847. // 法术造成伤害
  848. if (kf.Attack != null)
  849. {
  850. Parent.unitAttackDirect(mLauncherUnit, new AttackSource(this, kf.Attack), list);
  851. }
  852. }
  853. // 法术产生法术
  854. if (kf.Spell != null)
  855. {
  856. Parent.spellLaunchSpell(this.FromSkillType, this, kf.Spell, this.X, this.Y, targetUnitID);
  857. //System.Console.WriteLine("------法术产生法术: " + kf.Spell.SpellID + ", " + this.X + ", " + this.Y);
  858. }
  859. // 召唤
  860. if (kf.Summon != null)
  861. {
  862. Parent.spellSummonUnit(this, kf.Summon);
  863. }
  864. }
  865. #region __检测范围内目标__
  866. // 跟踪导弹查找附近单位 //
  867. public InstanceUnit seekAttackable(float range)
  868. {
  869. return Parent.SeekSpellAttackable(this.Launcher, this.Info, this.AoiStatus,
  870. X, Y, range, mInfo.ExpectTarget, mInfo.SeekingExpectTarget, mChainInfo);
  871. }
  872. // 范围伤害,碰撞检测 //
  873. private void getShapeAttackable(List<InstanceUnit> ret, AttackReason reason)
  874. {
  875. AttackRange.Shape = (AttackShape)mInfo.BodyShape;
  876. AttackRange.BodySize = this.mBaseSize;
  877. AttackRange.Direction = this.Direction;
  878. AttackRange.Distance = this.mDistance;
  879. AttackRange.ExpectTarget = mInfo.ExpectTarget;
  880. AttackRange.FanAngle = this.mInfo.FanAngle;
  881. AttackRange.StripWide = this.mInfo.RectWide;
  882. float prv_x = this.X;
  883. float prv_y = this.Y;
  884. if (mInfo.MType == SpellTemplate.MotionType.Straight || mInfo.MType == SpellTemplate.MotionType.StraightAndStop)
  885. {
  886. prv_x = mPrvePos.X;
  887. prv_y = mPrvePos.Y;
  888. }
  889. AttackRange.GetShapeAttackable(ret, reason, this.Info, X, Y, prv_x, prv_y, mInfo.MaxAffectUnit, AoiStatus);
  890. }
  891. #endregion
  892. float foxfireRoundAngle = 0f;
  893. int foxfireSeekWait = 0;
  894. public InstanceSpell[] brothers = null;
  895. void changeBrotherSeekWait(int timeValue)
  896. {
  897. if (brothers == null)
  898. {
  899. return;
  900. }
  901. foreach (var b in brothers)
  902. {
  903. b.foxfireSeekWait += timeValue;
  904. }
  905. }
  906. /// <summary>
  907. /// 更新范围检测以及关键帧
  908. /// </summary>
  909. private void updateKeyFrames()
  910. {
  911. switch (Info.MType)
  912. {
  913. case SpellTemplate.MotionType.Missile:
  914. case SpellTemplate.MotionType.SeekerMissile:
  915. //【战斗】Missile类技能,在目标消失后失效//
  916. if (mTarget != null && CMath.includeRoundPoint(mTarget.X, mTarget.Y, mTarget.BodyHitSize, this.X, this.Y))
  917. {
  918. if (mTarget.IsActive)
  919. {
  920. affectToSingle(mTarget, mInfo.HitOnExplosionKeyFrame);
  921. }
  922. Parent.RemoveObject(this);
  923. }
  924. break;
  925. case SpellTemplate.MotionType.CurveMissile:
  926. //【战斗】Missile类技能,在目标消失后失效//
  927. if (mTarget != null && CMath.includeRoundPoint(mTarget.X, mTarget.Y, mTarget.BodyHitSize + this.BodyHitSize, this.X, this.Y))
  928. {
  929. if (mTarget.IsActive)
  930. {
  931. affectToSingle(mTarget, mInfo.HitOnExplosionKeyFrame);
  932. }
  933. Parent.RemoveObject(this);
  934. }
  935. break;
  936. case SpellTemplate.MotionType.MissileAttackRoute:
  937. if (mTarget != null && CMath.includeRoundPoint(mTarget.X, mTarget.Y, mTarget.BodyHitSize, this.X, this.Y))
  938. {
  939. if (mTarget.IsActive)
  940. {
  941. affectToSingle(mTarget, mInfo.HitOnExplosionKeyFrame);
  942. }
  943. Parent.RemoveObject(this);
  944. }
  945. else if (mSeekingCooldownTime.Update(Parent.UpdateIntervalMS))
  946. {
  947. using (var enemy_list = ListObjectPool<InstanceUnit>.AllocAutoRelease())
  948. {
  949. getShapeAttackable(enemy_list, AttackReason.Attack);
  950. if (enemy_list.Count > 0)
  951. {
  952. InstanceUnit target = enemy_list[0];
  953. if (target.IsActive)
  954. {
  955. affectToSingle(target, mInfo.HitOnExplosionKeyFrame);
  956. }
  957. mSeekingCooldownTime.Reset();
  958. }
  959. }
  960. }
  961. break;
  962. case SpellTemplate.MotionType.Cannon:
  963. if (Finish)
  964. {
  965. SpellTemplate.KeyFrame kf = mInfo.HitOnExplosionKeyFrame;
  966. if (kf != null)
  967. {
  968. using (var list = ListObjectPool<InstanceUnit>.AllocAutoRelease())
  969. {
  970. getShapeAttackable(list, AttackReason.Attack);
  971. affectToMulti(list, kf, true);
  972. }
  973. }
  974. Parent.RemoveObject(this);
  975. }
  976. break;
  977. case SpellTemplate.MotionType.Chain:
  978. if (mTarget != null)
  979. {
  980. if (Collider.Object_Pos_IncludeInRound(mTarget, this.X, this.Y, this.mDistance))
  981. {
  982. updateKeyFrameSingleTarget(mTarget, true);
  983. }
  984. else
  985. {
  986. Parent.RemoveObject(this);
  987. }
  988. }
  989. break;
  990. case SpellTemplate.MotionType.Boomerang1:
  991. case SpellTemplate.MotionType.Boomerang2:
  992. if (Finish)
  993. {
  994. Parent.RemoveObject(this);
  995. }
  996. if (Info.SpecialEffect == SpellTemplate.SpecialAdditionalEffect.DragPath && Info.SpecialEffectParam != 0f)
  997. {
  998. updateDragPathKeyFramesRanged();
  999. }
  1000. else if (Info.SpecialEffect == SpellTemplate.SpecialAdditionalEffect.DarkHole && Info.SpecialEffectParam != 0f)
  1001. {
  1002. updateDarkHoleKeyFramesRanged();
  1003. }
  1004. else
  1005. {
  1006. updateKeyFramesRanged();
  1007. }
  1008. break;
  1009. case SpellTemplate.MotionType.Foxfire:
  1010. if (mTarget != null && CMath.includeRoundPoint(mTarget.X, mTarget.Y, mTarget.BodyHitSize, this.X, this.Y))
  1011. {
  1012. if (mTarget.IsActive)
  1013. {
  1014. affectToSingle(mTarget, mInfo.HitOnExplosionKeyFrame);
  1015. }
  1016. Parent.RemoveObject(this);
  1017. }
  1018. break;
  1019. default:
  1020. if (Info.BodyShape == SpellTemplate.Shape.LineToTarget || Info.BodyShape == SpellTemplate.Shape.LineToStart)
  1021. {
  1022. if (mTarget != null && Collider.Object_Pos_IncludeInRound(mTarget, this.X, this.Y, this.mDistance))
  1023. {
  1024. updateKeyFrameSingleTarget(mTarget, true);
  1025. }
  1026. else
  1027. {
  1028. updateKeyFrameSingleTarget(mTarget, false);
  1029. }
  1030. }
  1031. else
  1032. {
  1033. if (Info.SpecialEffect == SpellTemplate.SpecialAdditionalEffect.DragPath && Info.SpecialEffectParam != 0f)
  1034. {
  1035. updateDragPathKeyFramesRanged();
  1036. }
  1037. else if (Info.SpecialEffect == SpellTemplate.SpecialAdditionalEffect.DarkHole && Info.SpecialEffectParam != 0f)
  1038. {
  1039. updateDarkHoleKeyFramesRanged();
  1040. }
  1041. else
  1042. {
  1043. updateKeyFramesRanged();
  1044. }
  1045. }
  1046. break;
  1047. }
  1048. }
  1049. private void updateKeyFrameSingleTarget(InstanceUnit enemy, bool affect)
  1050. {
  1051. using (var kfs = ListObjectPool<SpellTemplate.KeyFrame>.AllocAutoRelease())
  1052. {
  1053. int kfs_count = mKeyFrames.PopKeyFrames(PassTimeMS, kfs);
  1054. bool is_interval_test = mHitIntervalTicker.Update(Parent.UpdateIntervalMS);
  1055. if (affect)
  1056. {
  1057. if (kfs_count > 0 || is_interval_test || mInfo.HitIntervalMS == 0)
  1058. {
  1059. if (kfs_count > 0)
  1060. {
  1061. for (int i = 0; i < kfs.Count; i++)
  1062. {
  1063. affectToSingle(enemy, kfs[i]);
  1064. }
  1065. }
  1066. if (mInfo.HitOnExplosion)
  1067. {
  1068. // 击中后爆炸
  1069. affectToSingle(enemy, mInfo.HitOnExplosionKeyFrame);
  1070. Parent.RemoveObject(this);
  1071. }
  1072. else if (mInfo.HitIntervalKeyFrame != null)
  1073. {
  1074. if (mInfo.HitIntervalMS == 0)
  1075. {
  1076. // 只在接触后第一次产生效果
  1077. if (!mHittedUnits.ContainsKey(enemy.ID))
  1078. {
  1079. affectToSingle(enemy, mInfo.HitIntervalKeyFrame);
  1080. mHittedUnits.Add(enemy.ID, enemy);
  1081. }
  1082. }
  1083. else if (is_interval_test)
  1084. {
  1085. // 间隔产生效果
  1086. affectToSingle(enemy, mInfo.HitIntervalKeyFrame);
  1087. }
  1088. }
  1089. }
  1090. }
  1091. }
  1092. }
  1093. private void updateKeyFramesRanged()
  1094. {
  1095. using (var kfs = ListObjectPool<SpellTemplate.KeyFrame>.AllocAutoRelease())
  1096. {
  1097. int kfs_count = mKeyFrames.PopKeyFrames(PassTimeMS, kfs);
  1098. bool is_interval_test = mHitIntervalTicker.Update(Parent.UpdateIntervalMS);
  1099. //此处修正 加入触发次数上限检测
  1100. if (is_interval_test && mInfo.HitIntervalMS > 0 && mHitIntervalTicker.TotalTickCount > (this.mSpellTotalTime / mInfo.HitIntervalMS))
  1101. {
  1102. is_interval_test = false;
  1103. }
  1104. if (kfs_count > 0 || is_interval_test || mInfo.HitIntervalMS == 0)
  1105. {
  1106. this.mHitTotalTimes++;
  1107. using (var enemy_list = ListObjectPool<InstanceUnit>.AllocAutoRelease())
  1108. {
  1109. getShapeAttackable(enemy_list, AttackReason.Attack);
  1110. if (kfs_count > 0)
  1111. {
  1112. // 单Frame情况下,如果是Attack。进行唯一敌人判定(X型拼接法术, 需要伤害只生效一次)
  1113. //if (kfs_count == 1 && mInfo.HitIntervalMS == 0 && this.mInfo.KeyFrames.Count == 1 && kfs[0].Attack != null && this.mInfo.HitIntervalKeyFrame == null)
  1114. if(this.LaunchData.PType == LaunchSpell.PosType.POS_TYPE_X)
  1115. {
  1116. if(this.refreshHitUnit(enemy_list))
  1117. {
  1118. for (int i = 0; i < kfs.Count; i++)
  1119. {
  1120. affectToMulti(enemy_list, kfs[i], true);
  1121. }
  1122. }
  1123. }
  1124. else
  1125. {
  1126. for (int i = 0; i < kfs.Count; i++)
  1127. {
  1128. affectToMulti(enemy_list, kfs[i], true);
  1129. }
  1130. }
  1131. }
  1132. if (mInfo.HitOnExplosion)
  1133. {
  1134. if (enemy_list.Count > 0)
  1135. {
  1136. // 击中后爆炸
  1137. affectToMulti(enemy_list, mInfo.HitOnExplosionKeyFrame, true);
  1138. Parent.RemoveObject(this);
  1139. }
  1140. }
  1141. else if(mInfo.HitIntervalKeyFrame != null)
  1142. {
  1143. if (mInfo.HitIntervalMS == 0)
  1144. {
  1145. // 只在接触后第一次产生效果
  1146. if (enemy_list.Count > 0 && this.refreshHitUnit(enemy_list))
  1147. {
  1148. affectToMulti(enemy_list, mInfo.HitIntervalKeyFrame, true);
  1149. }
  1150. }
  1151. else if (is_interval_test)
  1152. {
  1153. // 间隔产生效果
  1154. affectToMulti(enemy_list, mInfo.HitIntervalKeyFrame, false);
  1155. }
  1156. }
  1157. }
  1158. }
  1159. }
  1160. }
  1161. private void updateDarkHoleKeyFramesRanged()
  1162. {
  1163. using (var kfs = ListObjectPool<SpellTemplate.KeyFrame>.AllocAutoRelease())
  1164. {
  1165. using (var enemy_list = ListObjectPool<InstanceUnit>.AllocAutoRelease())
  1166. {
  1167. getShapeAttackable(enemy_list, AttackReason.Attack);
  1168. for (int i = enemy_list.Count - 1; i >= 0; --i)
  1169. {
  1170. if(enemy_list[i].IsIgnoreControl)
  1171. {
  1172. continue;
  1173. }
  1174. float angle, distance, offset, dx, dy;
  1175. if (enemy_list[i].Weight < XmdsConstConfig.DEFAULT_WEIGHT)
  1176. {
  1177. offset = MoveHelper.GetDistance(Parent.UpdateIntervalMS, Info.SpecialEffectParam);
  1178. dx = this.X - enemy_list[i].X;
  1179. dy = this.Y - enemy_list[i].Y;
  1180. distance = dx * dx + dy * dy;
  1181. if (offset * offset < distance)
  1182. {
  1183. angle = MathVector.getDegree(dx, dy);
  1184. enemy_list[i].moveLinearMap(offset, angle);
  1185. }
  1186. else
  1187. {
  1188. enemy_list[i].moveLinearMap2(dx, dy);
  1189. }
  1190. enemy_list[i].SetStunTimeMS(100);
  1191. }
  1192. }
  1193. int kfs_count = mKeyFrames.PopKeyFrames(PassTimeMS, kfs);
  1194. bool is_interval_test = mHitIntervalTicker.Update(Parent.UpdateIntervalMS);
  1195. #region <<关键帧逻辑>>
  1196. if (kfs_count > 0 || is_interval_test || mInfo.HitIntervalMS == 0)
  1197. {
  1198. //getShapeAttackable(enemy_list, AttackReason.Attack);
  1199. if (kfs_count > 0)
  1200. {
  1201. for (int i = 0; i < kfs.Count; i++)
  1202. {
  1203. affectToMulti(enemy_list, kfs[i], false);
  1204. }
  1205. }
  1206. if (mInfo.HitOnExplosion)
  1207. {
  1208. if (enemy_list.Count > 0)
  1209. {
  1210. // 击中后爆炸
  1211. affectToMulti(enemy_list, mInfo.HitOnExplosionKeyFrame, true);
  1212. Parent.RemoveObject(this);
  1213. }
  1214. }
  1215. else if(mInfo.HitIntervalKeyFrame != null)
  1216. {
  1217. if (mInfo.HitIntervalMS == 0)
  1218. {
  1219. // 只在接触后第一次产生效果
  1220. if (enemy_list.Count > 0 && this.refreshHitUnit(enemy_list))
  1221. {
  1222. affectToMulti(enemy_list, mInfo.HitIntervalKeyFrame, true);
  1223. }
  1224. }
  1225. else if (is_interval_test)
  1226. {
  1227. // 间隔产生效果
  1228. affectToMulti(enemy_list, mInfo.HitIntervalKeyFrame, false);
  1229. }
  1230. }
  1231. }
  1232. #endregion
  1233. }
  1234. }
  1235. }
  1236. public override String GetTemplateData()
  1237. {
  1238. return "Spell:" + this.Info.ID;
  1239. }
  1240. private bool refreshHitUnit(CommonLang.ListObjectPool<InstanceUnit>.AutoReleaseList<InstanceUnit> enemy_list)
  1241. {
  1242. if(enemy_list.Count <= 0)
  1243. {
  1244. return true;
  1245. }
  1246. foreach (InstanceUnit u in mHittedUnits.Values)
  1247. {
  1248. enemy_list.Remove(u);
  1249. }
  1250. if (enemy_list.Count > 0)
  1251. {
  1252. for (int i = enemy_list.Count - 1; i >= 0; --i)
  1253. {
  1254. InstanceUnit u = enemy_list[i];
  1255. mHittedUnits.Add(u.ID, u);
  1256. }
  1257. return true;
  1258. }
  1259. return false;
  1260. }
  1261. public const float Pi = (float)Math.PI;
  1262. public const float PiOver2 = (float)(Math.PI / 2.0);
  1263. public const float PiOver36 = (float)(Math.PI / 36.0);
  1264. public const float TwoPi = (float)(Math.PI * 2.0);
  1265. private void updateDragPathKeyFramesRanged()
  1266. {
  1267. using (var kfs = ListObjectPool<SpellTemplate.KeyFrame>.AllocAutoRelease())
  1268. {
  1269. using (var enemy_list = ListObjectPool<InstanceUnit>.AllocAutoRelease())
  1270. {
  1271. getShapeAttackable(enemy_list, AttackReason.Attack);
  1272. float _a, _b, _angle, offset, dx, dy , dis;
  1273. for (int i = enemy_list.Count - 1; i >= 0; --i)
  1274. {
  1275. if (enemy_list[i].IsIgnoreControl)
  1276. {
  1277. continue;
  1278. }
  1279. if (enemy_list[i].Weight < XmdsConstConfig.DEFAULT_WEIGHT)
  1280. {
  1281. dx = enemy_list[i].X - this.X;
  1282. dy = enemy_list[i].Y - this.Y;
  1283. _a = MathVector.getDegree(dx, dy);
  1284. _b = this.Direction - _a;
  1285. if (_b < -Pi)
  1286. {
  1287. _b += TwoPi;
  1288. }
  1289. else if(_b > Pi)
  1290. {
  1291. _b -= TwoPi;
  1292. }
  1293. if (Math.Abs(_b) < PiOver36)
  1294. {
  1295. continue;
  1296. }
  1297. if(_b > 0)
  1298. {
  1299. if(_b > PiOver2)
  1300. {
  1301. continue;
  1302. }
  1303. _angle = this.Direction + PiOver2;
  1304. }
  1305. else
  1306. {
  1307. if (_b < -PiOver2)
  1308. {
  1309. continue;
  1310. }
  1311. _angle = this.Direction - PiOver2;
  1312. }
  1313. dis = Math.Abs((float)(dy * Math.Sin(_angle) / Math.Sin(_a)));
  1314. offset = MoveHelper.GetDistance(Parent.UpdateIntervalMS, Info.SpecialEffectParam);
  1315. if(offset > dis)
  1316. {
  1317. offset = dis;
  1318. }
  1319. enemy_list[i].moveLinearMap(offset, _angle);
  1320. enemy_list[i].SetStunTimeMS(100);
  1321. }
  1322. }
  1323. int kfs_count = mKeyFrames.PopKeyFrames(PassTimeMS, kfs);
  1324. bool is_interval_test = mHitIntervalTicker.Update(Parent.UpdateIntervalMS);
  1325. #region <<关键帧逻辑>>
  1326. if (kfs_count > 0 || is_interval_test || mInfo.HitIntervalMS == 0)
  1327. {
  1328. //getShapeAttackable(enemy_list, AttackReason.Attack);
  1329. if (kfs_count > 0)
  1330. {
  1331. for (int i = 0; i < kfs.Count; i++)
  1332. {
  1333. affectToMulti(enemy_list, kfs[i], false);
  1334. }
  1335. }
  1336. if (mInfo.HitOnExplosion)
  1337. {
  1338. if (enemy_list.Count > 0)
  1339. {
  1340. // 击中后爆炸
  1341. affectToMulti(enemy_list, mInfo.HitOnExplosionKeyFrame, true);
  1342. Parent.RemoveObject(this);
  1343. }
  1344. }
  1345. else if (mInfo.HitIntervalKeyFrame != null)
  1346. {
  1347. if (mInfo.HitIntervalMS == 0)
  1348. {
  1349. // 只在接触后第一次产生效果
  1350. if (enemy_list.Count > 0 && this.refreshHitUnit(enemy_list))
  1351. {
  1352. affectToMulti(enemy_list, mInfo.HitIntervalKeyFrame, true);
  1353. }
  1354. }
  1355. else if (is_interval_test)
  1356. {
  1357. // 间隔产生效果
  1358. affectToMulti(enemy_list, mInfo.HitIntervalKeyFrame, false);
  1359. }
  1360. }
  1361. }
  1362. #endregion
  1363. }
  1364. }
  1365. }
  1366. }
  1367. }