InstanceSpell.cs 59 KB

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