XmdsInstancePlayer.cs 67 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063
  1. #define OPNE_JSG_AI_TOOLS
  2. using CommonAI.Zone;
  3. using CommonAI.Zone.Helper;
  4. using CommonAI.Zone.Instance;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. using System.Text;
  9. using XmdsCommon.Plugin;
  10. using CommonAI.Zone.Formula;
  11. using XmdsCommon.Message;
  12. using CommonLang;
  13. using XmdsCommonServer.Message;
  14. using CommonLang.Vector;
  15. using XmdsCommon.EditorData;
  16. using CommonAI.Zone.ZoneEditor;
  17. using CommonLang.Concurrent;
  18. using static CommonAI.Zone.Instance.InstanceUnit;
  19. using XmdsCommon.ZoneClient.XmdsClientVirtual;
  20. using XmdsCommonServer.Plugin.Scene;
  21. using static CommonAI.XmdsConstConfig;
  22. using System.Collections;
  23. using CommonLang.Log;
  24. using CommonAI.Data;
  25. using static XmdsCommonServer.Plugin.Units.XmdsInstanceUnitStateMachine;
  26. using CommonAI;
  27. namespace XmdsCommonServer.Plugin.Units
  28. {
  29. public class XmdsInstancePlayer : InstancePlayer
  30. {
  31. public enum GuardMode
  32. {
  33. Mode_Point,
  34. Mode_Map,
  35. }
  36. private static HashMap<int, AtomicInteger> CreateInfoMap = new HashMap<int, AtomicInteger>();
  37. //嘲讽状态
  38. protected XmdsInstanceUnitStateMock mMockTarget;
  39. private TimeInterval<int> mFindItemTimeInterval;
  40. private long mNextAutoFindPickItemTime;
  41. private GuardMode mCurGuardMode = GuardMode.Mode_Point;
  42. private Vector2 mGuardPos = new Vector2();
  43. private bool mDoStopSkill = false;
  44. private static int DEFAULT_CROSS_SERVER_ID = -999;
  45. private const char SPLIT = ':';
  46. private List<int> mAutoGuardTargetList = new List<int>();
  47. private int mAutoGuardTargetTimes = 0;
  48. private const int MAX_AUTO_GUARD_TARGET_TIMES = 500;
  49. private bool mIsReady = false;
  50. private XmdsInstanceUnitStateMachine.XmdsStateFollowAndAttack mXmdsFocusTarget;
  51. private bool mBotTestAutoFight = false;
  52. private int zoneID;
  53. //解决部分情况下未上发(或者上发时机不对)idle,导致别人看到自己在move,唯独自己看到自己是正常的
  54. private int mNotMoveTimes;
  55. private Vector2 mLastMovePos = new Vector2();
  56. //定点自动战斗情况下,玩家不能像怪物一样回原地,所以需要定时检测一下,重置定点的位置
  57. private long mLastAutoAttackTime = 0;
  58. //private Vector2 mLastAutoFightPos = new Vector2();
  59. //下一次通知背包已满时间
  60. //private long mNextNotifyBagFullTime = 0;
  61. public XmdsInstancePlayer(InstanceZone zone, UnitInfo info, string name, int force, int alliesForce, int level)
  62. : base(zone, info, name, force, level, alliesForce)
  63. {
  64. mFindItemTimeInterval = new TimeInterval<int>(XmdsConfig.Instance.GUARD_FIND_ITEM_CYCLE_TIME);
  65. mCheckGuard.FirstTimeEnable = true;
  66. if (TemplateManager.IsEditor)
  67. {
  68. mIsReady = true;
  69. mBotTestAutoFight = true;
  70. }
  71. else if ((Info.Properties as XmdsUnitProperties).BotTestTemplate)
  72. {
  73. mIsReady = true;
  74. }
  75. OnPlayerCreate();
  76. this.OnHandleAction += OnActionHandle;
  77. }
  78. static void OnActionHandle(InstanceUnit unit, ObjectAction act)
  79. {
  80. if (act is PlayerDramaEndAction && unit.AoiStatus != null)
  81. {
  82. var dramaId = (act as PlayerDramaEndAction).dramaId;
  83. if (unit.AoiStatus is XmdsPlayerAOI)
  84. {
  85. if ((unit.AoiStatus as XmdsPlayerAOI).QuestId == dramaId)
  86. {
  87. unit.setAoiStatus(null);
  88. }
  89. return;
  90. }
  91. if (unit.AoiStatus is DarmaAOI)
  92. {
  93. if ((unit.AoiStatus as DarmaAOI).darmaId == dramaId)
  94. {
  95. unit.setAoiStatus(null);
  96. }
  97. return;
  98. }
  99. }
  100. }
  101. private void clearAutoGuardTargetList()
  102. {
  103. if (mAutoGuardTargetList != null)
  104. {
  105. mAutoGuardTargetList.Clear();
  106. }
  107. mAutoGuardTargetTimes = 0;
  108. }
  109. protected override void Disposing()
  110. {
  111. foreach (var item in mQuestScript)
  112. {
  113. item.Value.Dispose();
  114. }
  115. clearAutoGuardTargetList();
  116. mXmdsFocusTarget = null;
  117. lastAttackUnit = null;
  118. base.Disposing();
  119. }
  120. private System.Action readyAction;
  121. public void PlayerReady()
  122. {
  123. mIsReady = true;
  124. if (readyAction != null)
  125. {
  126. readyAction.Invoke();
  127. }
  128. }
  129. public bool IsPlayerReady()
  130. {
  131. return mIsReady;
  132. }
  133. //--------------------------------------------------------------------------------------
  134. public override bool IsVisible
  135. {
  136. get { return base.IsVisible && mIsReady; }
  137. }
  138. public override bool IsInvincible
  139. {
  140. get { return (!mIsReady || base.IsInvincible); }
  141. }
  142. public XmdsVirtual_Player VirtualPlayer
  143. {
  144. get { return base.Virtual as XmdsVirtual_Player; }
  145. }
  146. public bool CanPickDropableItem
  147. {
  148. get { return VirtualPlayer.VirtualInventorySize >= 1; }
  149. }
  150. /// <summary>
  151. /// 是否是机器人
  152. /// </summary>
  153. //public bool IsBotTest { get; private set; }
  154. //--------------------------------------------------------------------------------------
  155. #region 任务相关
  156. private HashMap<string, Quest.QuestScript> mQuestScript = new HashMap<string, Quest.QuestScript>();
  157. public Quest.QuestScript GetQuestScript(string quest_id)
  158. {
  159. return mQuestScript.Get(quest_id);
  160. }
  161. public IList<Quest.QuestScript> GetAllQuestScript()
  162. {
  163. return new List<Quest.QuestScript>(mQuestScript.Values);
  164. }
  165. public void SetQuestScript(string quest_id, int questType, Quest.QuestScript script)
  166. {
  167. if (mQuestScript.ContainsKey(quest_id))
  168. {
  169. XmdsVirtual.FormatLog(CommonLang.Log.LoggerLevel.ERROR, "SetQuestScript Error : ContainsKey" + quest_id);
  170. RemoveQuestScript(quest_id);
  171. }
  172. mQuestScript.Add(quest_id, script);
  173. script.Init(quest_id, questType, this);
  174. script.Start();
  175. }
  176. public void RemoveQuestScript(string quest_id)
  177. {
  178. Quest.QuestScript qs = mQuestScript.Get(quest_id);
  179. if (qs != null)
  180. {
  181. qs.Dispose();
  182. mQuestScript.Remove(quest_id);
  183. }
  184. }
  185. public List<CommonAI.Zone.Helper.QuestData> GetQuests()
  186. {
  187. return new List<CommonAI.Zone.Helper.QuestData>(mQuests.Values);
  188. }
  189. #endregion
  190. //--------------------------------------------------------------------------------------
  191. #region 作弊惩罚
  192. private TimeExpire<int> mLockTime;
  193. public bool IsLock { get { return mLockTime != null; } }
  194. //索敌范围.
  195. private int mGuardSearchRange = XmdsConfig.Instance.NORMALSCENE_AUTO_GUARD_RANGE;
  196. /// <summary>
  197. /// 设置自动战斗索敌范围.
  198. /// </summary>
  199. /// <param name="v"></param>
  200. public void SetGuardSearchRange(int v)
  201. {
  202. mGuardSearchRange = v;
  203. }
  204. /// <summary>
  205. /// 检测到作弊,禁止一切操作一段时间
  206. /// </summary>
  207. /// <param name="timeMS"></param>
  208. public void Lock(int timeMS)
  209. {
  210. this.startIdle();
  211. if (mLockTime != null && mLockTime.ExpireTimeMS >= timeMS)
  212. {
  213. return;
  214. }
  215. else
  216. {
  217. mLockTime = new TimeExpire<int>(timeMS);
  218. }
  219. }
  220. private void upateLock()
  221. {
  222. if (mLockTime != null && mLockTime.Update(Parent.UpdateIntervalMS))
  223. {
  224. mLockTime = null;
  225. }
  226. }
  227. #endregion
  228. //--------------------------------------------------------------------------------------
  229. #region BUFF特殊状态锁定移动.
  230. private TimeExpire<int> mBuffLockMoveTime;
  231. public bool IsBuffLockMove { get { return mBuffLockMoveTime != null; } }
  232. public void BuffMoveLock(int timeMS)
  233. {
  234. this.startIdle();
  235. if (mBuffLockMoveTime != null && mBuffLockMoveTime.ExpireTimeMS >= timeMS)
  236. {
  237. return;
  238. }
  239. else
  240. {
  241. mBuffLockMoveTime = new TimeExpire<int>(timeMS);
  242. }
  243. }
  244. private void UpdateBuffMoveLock()
  245. {
  246. if (mBuffLockMoveTime != null && mBuffLockMoveTime.Update(Parent.UpdateIntervalMS))
  247. {
  248. mBuffLockMoveTime = null;
  249. }
  250. }
  251. #endregion
  252. //--------------------------------------------------------------------------------------
  253. protected override void onUpdate(bool slowRefresh)
  254. {
  255. base.onUpdate(slowRefresh);
  256. this.upateLock();
  257. this.UpdateBuffMoveLock();
  258. this.UpdateDoStopSkill();
  259. this.updateFollowTeam();
  260. this.UpdateAndModifyErrorData();
  261. }
  262. //--------------------------------------------------------------------------------------
  263. protected override void onAction(ObjectAction act)
  264. {
  265. if (IsLock) return;
  266. if (act is UnitAxisAction || act is UnitMoveAction)
  267. {
  268. //BUFF锁定客户端移动.
  269. if (IsBuffLockMove == true)
  270. {
  271. return;
  272. }
  273. }
  274. base.onAction(act);
  275. if (this.IsDead() == true)
  276. {
  277. //单位遗言更改.
  278. if (act is PlayerTestamentChangeEventAction)
  279. {
  280. PlayerTestamentChangeEventAction evt = act as PlayerTestamentChangeEventAction;
  281. ChangeTestament(evt.TestamentID);
  282. }
  283. }
  284. //自动战斗状态变更通知.
  285. if (act is PlayerAutoGuardEventC2B)
  286. {
  287. var evt = act as PlayerAutoGuardEventC2B;
  288. if (evt.Flag == false)
  289. {
  290. if (this.CurrentState is StateSkill)
  291. {
  292. mDoStopSkill = true;
  293. }
  294. }
  295. return;
  296. }
  297. else if (act is PlayerEnterCrossServerRequestC2B)
  298. {
  299. //战斗服判断单位是否在PVPV状态,如果不是发送切换场景请求.
  300. if ((this.Virtual as XmdsVirtual).CombatState != BattleStatus.PVP)
  301. {
  302. //发送协议.
  303. TransUnitEventB2R evt = new TransUnitEventB2R();
  304. //约定跨服场景ID.
  305. evt.SceneID = DEFAULT_CROSS_SERVER_ID;
  306. evt.playerId = this.PlayerUUID;
  307. evt.TargetX = 0;
  308. evt.TargetY = 0;
  309. this.queueEvent(evt);
  310. }
  311. else
  312. {
  313. (this.Virtual as XmdsVirtual).SendMsgToClient(CommonAI.XmdsConstConfig.TIPS_CAN_NOT_ENTER_SCENE);
  314. }
  315. }
  316. else if (act is GetMonsterSufferDamageInfoC2B)
  317. {
  318. var ret = act as GetMonsterSufferDamageInfoC2B;
  319. OnReceiveGetMonsterSufferDamageInfoC2B(ret);
  320. }
  321. foreach (var q in mQuestScript)
  322. {
  323. if (q.Value.TryDoAction(act))
  324. {
  325. break;
  326. }
  327. }
  328. }
  329. protected override bool doLaunchSkill(UnitLaunchSkillAction sk)
  330. {
  331. //Console.WriteLine(" ------------------------------doLaunchSkill - " + sk.SkillID + ", " + this.ID + ", targetID: " + sk.TargetObjID + ", XY:" + this.X + ", " + this.Y + ", direction : " + this.Direction);
  332. //if(sk.SkillID == 110160)
  333. // sk.SkillID = 110360;
  334. //如果在采集中,不让放技能,并通知客户端.
  335. if (CurrentActionStatus == UnitActionStatus.Pick)
  336. {
  337. this.VirtualPlayer.SendMsgToClient(CommonAI.XmdsConstConfig.TIPS_BE_BUSY);
  338. return false;
  339. }
  340. var skill = this.getSkillState(sk.SkillID);
  341. if (skill == null)
  342. {
  343. return false;
  344. }
  345. return base.doLaunchSkill(sk);
  346. }
  347. public bool PlayerChangeSkill(int oldSkillID, int newSkillID, SkillLevelData levelData)
  348. {
  349. return this.Virtual.ChangeSkill(oldSkillID, newSkillID, levelData);
  350. }
  351. // 获取队伍的天命属性加成
  352. public override int GetTeamFateValue(UnitFateType fateType)
  353. {
  354. if(this.TeamVirtual == null)
  355. {
  356. return this.Virtual.GetPetTalentAddition(fateType);
  357. }
  358. return this.TeamVirtual.GetTeamFateValue(fateType);
  359. }
  360. //查找自动拾取的物品
  361. public override InstanceItem findGuardPickItem()
  362. {
  363. if (CanPickDropableItem)
  364. {
  365. return base.findGuardPickItem();
  366. }
  367. return null;
  368. }
  369. //查找自动战斗等一切情况下的物品拾取
  370. public InstanceItem findAutoGuardPickItem()
  371. {
  372. if (CanPickDropableItem)
  373. {
  374. InstanceItem min = null;
  375. float min_len = float.MaxValue;
  376. float searchValue = this.mAutoPickRange * this.mAutoPickRange;
  377. Parent.ForEachNearObjects(this.X, this.Y, this.mAutoPickRange, (InstanceItem u, ref bool cancel) =>
  378. {
  379. if (!u.Info.Pickable && u.IsPickable(this))
  380. {
  381. float len = MathVector.getDistanceSquare(u.X, u.Y, this.X, this.Y);
  382. if (min_len > len && len <= searchValue)
  383. {
  384. min_len = len;
  385. min = u;
  386. }
  387. }
  388. });
  389. return min;
  390. }
  391. return null;
  392. }
  393. protected override void doPickObject(UnitPickObjectAction pick)
  394. {
  395. InstanceZoneObject obj = Parent.getObject<InstanceZoneObject>(pick.PickableObjectID);
  396. if (obj is InstanceItem)
  397. {
  398. InstanceItem item = obj as InstanceItem;
  399. var zip = (item.Info.Properties as XmdsItemProperties);
  400. switch (zip.ItemType)
  401. {
  402. case XmdsItemProperties.XmdsItemType.Equip:
  403. //if (CanPickDropableItem) XmdsDropableInstanceItem.IsPickable已经检查
  404. {
  405. item.DirectPickItem(this, () =>
  406. {
  407. RemoveDropItemB2C rd = new RemoveDropItemB2C(item.ID, this.ID);
  408. this.queueEvent(rd);
  409. });
  410. }
  411. break;
  412. default:
  413. {
  414. if (item.PickItem(this) && item.mFrom == 1)
  415. {
  416. RemoveDropItemB2C rd = new RemoveDropItemB2C(item.ID, this.ID);
  417. this.queueEvent(rd);
  418. }
  419. }
  420. break;
  421. }
  422. }
  423. else if (obj is InstanceUnit)
  424. {
  425. InstanceUnit unit = obj as InstanceUnit;
  426. this.PickUnit(unit);
  427. }
  428. }
  429. protected void TryDirectPickNearItems()
  430. {
  431. int size = this.VirtualPlayer.VirtualInventorySize;
  432. if (size == 0) { return; }
  433. Parent.ForEachNearObjects(this.X, this.Y, this.mAutoPickRange, (InstanceItem u, ref bool cancel) =>
  434. {
  435. if (size > 0)
  436. {
  437. var itemProp = u.Info.Properties as XmdsItemProperties;
  438. if (itemProp.AllowAutoGuardPick == true && u.PassTimeMS > 1000)
  439. {
  440. //自己可以捡的装备再扣除背包数量.
  441. if (u.DirectPickItem(this, () =>
  442. {
  443. RemoveDropItemB2C rd = new RemoveDropItemB2C(u.ID, this.ID);
  444. this.queueEvent(rd);
  445. }))
  446. {
  447. size--;
  448. }
  449. }
  450. }
  451. else
  452. {
  453. cancel = true;
  454. }
  455. });
  456. //this.VirtualPlayer.VirtualInventorySize = size;
  457. }
  458. public void setMocking(InstanceUnit unit)
  459. {
  460. if(unit == null)
  461. {
  462. if(mMockTarget != null)
  463. {
  464. mMockTarget.mMarkRemove = true;
  465. }
  466. mMockTarget = null;
  467. }
  468. else
  469. {
  470. mMockTarget = new XmdsInstanceUnitStateMock(this, unit);
  471. DoMockingAttack();
  472. }
  473. }
  474. protected override void updateGuard()
  475. {
  476. if (mMockTarget != null)
  477. {
  478. DoMockingAttack();
  479. }
  480. else if(this.mFocusPickItem != null && this.mFocusPickItem.IsActive)
  481. {
  482. return;
  483. }
  484. else if (IsGuard == true && (mXmdsFocusTarget == null || (mXmdsFocusTarget != null && !mXmdsFocusTarget.IsActive)))
  485. {
  486. mXmdsFocusTarget = null;
  487. InstanceUnit enemy = null;
  488. if (lastAttackUnit != null && lastAttackUnit.IsActive == true)//上一次攻击的单位如果没死且能攻击,继续攻击他.
  489. {
  490. //上次攻击的单位如果超过了一屏范围,取消攻击.
  491. if (CMath.getDistance(this.X, this.Y, lastAttackUnit.X, lastAttackUnit.Y) > this.mGuardSearchRange)
  492. {
  493. lastAttackUnit = null;
  494. }
  495. else
  496. {
  497. enemy = lastAttackUnit;
  498. }
  499. }
  500. else
  501. {
  502. lastAttackUnit = null;
  503. }
  504. if (enemy == null)//如果无效再找一次.
  505. {
  506. enemy = findGuardTarget(SkillTemplate.CastTarget.Enemy, AttackReason.Look);
  507. }
  508. if (enemy != null)
  509. {
  510. doXmdsFocusAttack(enemy, SkillTemplate.CastTarget.Enemy);
  511. return;
  512. }
  513. //UpdateXmdsGuard();
  514. }
  515. //自动拾取检测
  516. if(this.DoAutoPick())
  517. {
  518. return;
  519. }
  520. if (mFocusPickItem != null && !mFocusPickItem.IsActive)
  521. {
  522. mFocusPickItem = null;
  523. }
  524. if (mFindItemTimeInterval.Update(Parent.UpdateIntervalMS))
  525. {
  526. TryDirectPickNearItems();
  527. }
  528. if (IsGuard)
  529. {
  530. // 旋风斩贴近目标 //
  531. var state = CurrentState as StateSkill;
  532. if (state != null)
  533. {
  534. Vector2 movePos = (mXmdsFocusTarget == null) ? state.GetMoveToPos() : new Vector2(mXmdsFocusTarget.Target.X, mXmdsFocusTarget.Target.Y);
  535. if (movePos != null && state.IsControlMoveable && !state.unit.IsCannotMove && state.SkillData.AutoFightFollower)
  536. {
  537. if(state.setMoveTo(movePos.X, movePos.Y))
  538. {
  539. // 移动结束
  540. if((this.CurrentActionSubstate & (byte)UnitActionSubStatus.ChargeAtkMove) > 0)
  541. {
  542. this.RemoveActionSubState(UnitActionSubStatus.ChargeAtkMove);
  543. this.AddActionSubState(UnitActionSubStatus.ChargeAtkIdle);
  544. }
  545. }
  546. else
  547. {
  548. // 移动
  549. if ((this.CurrentActionSubstate & (byte)UnitActionSubStatus.ChargeAtkIdle) > 0)
  550. {
  551. this.RemoveActionSubState(UnitActionSubStatus.ChargeAtkIdle);
  552. this.AddActionSubState(UnitActionSubStatus.ChargeAtkMove);
  553. }
  554. }
  555. return;
  556. }
  557. }
  558. // 没目标定期检测目标 //
  559. if ((mXmdsFocusTarget == null) && (mFocusPickItem == null))
  560. {
  561. if (mCheckGuard.Update(Parent.UpdateIntervalMS))
  562. {
  563. var enemy = findGuardTarget(SkillTemplate.CastTarget.Enemy, AttackReason.Look);
  564. if (enemy != null)
  565. {
  566. doXmdsFocusAttack(enemy, SkillTemplate.CastTarget.Enemy);
  567. return;
  568. }
  569. var alias = findGuardTarget(SkillTemplate.CastTarget.AlliesIncludeSelf, AttackReason.Look);
  570. if (alias != null)
  571. {
  572. doXmdsFocusAttack(alias, SkillTemplate.CastTarget.AlliesIncludeSelf);
  573. return;
  574. }
  575. if (CommonLang.CUtils.localTimeMS - this.mLastAutoAttackTime > 3000/* && this.X == this.mLastAutoFightPos.X && this.Y == this.mLastAutoFightPos.Y*/)
  576. {
  577. this.mLastAutoAttackTime = CommonLang.CUtils.localTimeMS;
  578. this.mGuardPos.SetX(this.X);
  579. this.mGuardPos.SetY(this.Y);
  580. }
  581. }
  582. }
  583. }
  584. }
  585. //是否可以自动拾取
  586. public override bool DoAutoPick(bool ignoreInterval = false)
  587. {
  588. //非自动战斗或者非跟随,退出
  589. if (!this.IsGuard && (this.leadingMan == null || (this.leadingMan != null && !this.canFollowTeam)))
  590. {
  591. return false;
  592. }
  593. if(this.VirtualPlayer.VirtualInventorySize <= 0)
  594. {
  595. //只要自动战斗就提示这个,不合理,客户端自己加
  596. //if(mNextNotifyBagFullTime < CommonLang.CUtils.localTimeMS)
  597. //{
  598. // mNextNotifyBagFullTime = CommonLang.CUtils.localTimeMS + 6000;
  599. // this.Virtual.SendMsgToClient(CommonAI.XmdsConstConfig.TIPS_BAG_FULL);
  600. //}
  601. return false;
  602. }
  603. if (!this.Parent.CheckAutoDropItem() || !IsBattleCanPick())
  604. {
  605. return false;
  606. }
  607. if (mFocusPickItem == null || !mFocusPickItem.IsActive)
  608. {
  609. bool leaderInView = false;
  610. if (this.mTeamVirtual != null && this.canFollowTeam && this.leadingMan != null && this.leadingMan.Enable)
  611. {
  612. // 如果正在跟随图中,取消拾取
  613. if(this.CurrentState is StateFollowLeader)
  614. {
  615. StateFollowLeader folloLeader = this.CurrentState as StateFollowLeader;
  616. if(folloLeader != null && folloLeader.FollowState == StateFollow.MoveState.Move)
  617. {
  618. return false;
  619. }
  620. }
  621. if (!CMath.includeRoundPoint(X, Y, this.mAutoPickRange, leadingMan.X, leadingMan.Y))
  622. {
  623. return false;
  624. }
  625. else
  626. {
  627. leaderInView = true;
  628. }
  629. }
  630. bool canAutoPick = IsGuard || this.CurrentState is StateFollowAndPickItem || leaderInView;
  631. if (canAutoPick && (ignoreInterval || mNextAutoFindPickItemTime < CommonLang.CUtils.localTimeMS))
  632. {
  633. var item = findAutoGuardPickItem();
  634. if (item != null)
  635. {
  636. mNextAutoFindPickItemTime = CommonLang.CUtils.localTimeMS + XmdsConfig.Instance.GUARD_FIND_ITEM_CYCLE_TIME;
  637. doFocusPickItem(item, false);
  638. return true;
  639. }
  640. }
  641. }
  642. else
  643. {
  644. return true;
  645. }
  646. return false;
  647. }
  648. //是否跟随队长
  649. public override bool IsFollowMaster()
  650. {
  651. if(this.leadingMan != null && this.canFollowTeam)
  652. {
  653. return true;
  654. }
  655. return false;
  656. }
  657. private bool IsBattleCanPick()
  658. {
  659. if(this.Virtual.GetBattleStatus() != BattleStatus.None)
  660. {
  661. // 不主动开战
  662. if(this.mXmdsFocusTarget != null && this.mXmdsFocusTarget.TargetUnit.IsActive && !this.mXmdsFocusTarget.TargetUnit.IsFullHP())
  663. {
  664. return false;
  665. }
  666. }
  667. return true;
  668. }
  669. //通知拾取消息
  670. public override void NotifyRemoveDropItemB2C(InstanceItem item)
  671. {
  672. RemoveDropItemB2C rd = new RemoveDropItemB2C(item.ID, this.ID);
  673. this.queueEvent(rd);
  674. }
  675. private void DoMockingAttack()
  676. {
  677. //doXmdsFocusAttack(mMockTarget.GetTargetUnit(), SkillTemplate.CastTarget.Enemy, false, this.DefaultSkillStatus());
  678. if (!(this.CurrentState is XmdsInstanceUnitStateMock) || !(this.CurrentState is StateSkill))
  679. {
  680. changeState(mMockTarget);
  681. queueEvent(new PlayerFocuseTargetEvent(this.ID, mMockTarget.GetTargetUnit().ID, SkillTemplate.CastTarget.Enemy)); ;
  682. }
  683. }
  684. public override BuffState AddBuff(BuffTemplate buff, InstanceUnit sender, int pointMaxOverLayer = 0, bool forever = false, bool bMaxOverlayer = false,
  685. int buffExt = 0, bool isControlBuf = false, bool maxReset = false, int addLayers = 0)
  686. {
  687. XmdsBuffProperties prop = buff.Properties as XmdsBuffProperties;
  688. if (prop.BuffAbilityList != null)
  689. {
  690. int count = prop.BuffAbilityList.Count;
  691. for (int i = 0; i < count; i++)
  692. {
  693. if (XmdsInstanceUtils.IsDebuff(prop.BuffAbilityList[i].ability))
  694. {
  695. isControlBuf = true;
  696. break;
  697. }
  698. }
  699. }
  700. return base.AddBuff(buff, sender, pointMaxOverLayer, forever, bMaxOverlayer, buffExt, isControlBuf, maxReset, addLayers);
  701. }
  702. protected override void doHitAttack(InstanceUnit attacker, AttackSource source)
  703. {
  704. if (this.IsDead())
  705. {
  706. //XmdsAttackProperties zap = (source.Attack.Properties as XmdsAttackProperties);
  707. if (attacker.CurrentState is StateSkill)
  708. {
  709. var skilltemplate = (attacker.CurrentState as StateSkill).SkillData;
  710. if ((skilltemplate.Properties as XmdsSkillProperties).TargetType
  711. == XmdsSkillProperties.XmdsSkillTargetType.AllianceDead)
  712. {
  713. TemplateManager.Formula.OnHit(attacker, source, this);
  714. }
  715. }
  716. }
  717. base.doHitAttack(attacker, source);
  718. }
  719. /// <summary>
  720. /// 更改遗言.
  721. /// </summary>
  722. /// <param name="testamentID"></param>
  723. private void ChangeTestament(byte testamentID)
  724. {
  725. (this.Virtual as XmdsVirtual_Player).SyncTestament(testamentID);
  726. }
  727. public override void InitSkills(LaunchSkill baseSkill, params LaunchSkill[] skills)
  728. {
  729. if (this.Virtual == null ||
  730. (this.Virtual as XmdsVirtual).IsFinishSkillInit() == false)
  731. {
  732. return;
  733. }
  734. base.InitSkills(baseSkill, skills);
  735. }
  736. public override bool tryLaunchRandomSkillAndCancelCurrentSkill(InstanceUnit target, bool autoFocusNearTarget = false)
  737. {
  738. //自动战斗不允许中断当前技能施放.
  739. return false;
  740. }
  741. private void UpdateDoStopSkill()
  742. {
  743. if (this.CurrentState is StateSkill)
  744. {
  745. if (mDoStopSkill)
  746. {
  747. var ss = (this.CurrentState as StateSkill);
  748. if (ss.IsCancelableByMove || ss.IsCancelableBySkill)
  749. {
  750. ss.block();
  751. mDoStopSkill = false;
  752. }
  753. }
  754. }
  755. else
  756. {
  757. mDoStopSkill = false;
  758. }
  759. }
  760. protected override void doGuard(UnitGuardAction act)
  761. {
  762. //没有通关不能自动战斗.
  763. if (act.guard == true && this.Virtual != null && (this.Virtual as XmdsVirtual_Player).AllowUseAutoGuard() == false)
  764. {
  765. // 机器人除外.
  766. if (IsRobot)
  767. {
  768. return;
  769. }
  770. }
  771. cleanFocus();
  772. lastAttackUnit = null;
  773. XmdsVirtual.FormatLog(CommonLang.Log.LoggerLevel.DEBUG, "act.reason:" + act.reason);
  774. if (act.guard == false)
  775. {
  776. // mAutoGuardTargetList.Clear();
  777. }
  778. else
  779. {
  780. try
  781. {
  782. ParseGuardActionReason(act.reason);
  783. }
  784. catch (Exception error)
  785. {
  786. XmdsVirtual.FormatLog(CommonLang.Log.LoggerLevel.ERROR, "ParseGuardActionReason Error : " + act.reason + " error : " + error.ToString());
  787. }
  788. }
  789. base.doGuard(act);
  790. }
  791. /// <summary>
  792. /// 解析挂机指令,新增指令头,告知是定点挂机还是全图游走.
  793. /// 第0位 map/point:
  794. /// 第1位 怪物模板ID:
  795. /// EG: map:怪物模板ID:怪物模板ID
  796. /// </summary>
  797. /// <param name="reason"></param>
  798. private void ParseGuardActionReason(string reason)
  799. {
  800. if (mCurGuardMode == GuardMode.Mode_Point)
  801. {
  802. mGuardPos.SetX(this.X);
  803. mGuardPos.SetY(this.Y);
  804. }
  805. # if OPNE_JSG_AI_TOOLS
  806. if (this.IsRobot)
  807. {
  808. this.mGuardSearchRange = 100;
  809. reason = CommonAI.XmdsConstConfig.AUTO_GUARD_MODE_MAP;
  810. }
  811. #endif
  812. if (string.IsNullOrEmpty(reason))
  813. {
  814. return;
  815. }
  816. string[] array = reason.Split(SPLIT);
  817. if (array != null && array.Length > 0)
  818. {
  819. string head = array[0];
  820. if (head == CommonAI.XmdsConstConfig.AUTO_GUARD_MODE_MAP) //全图模式.
  821. {
  822. mCurGuardMode = GuardMode.Mode_Map;
  823. }
  824. else if (head == CommonAI.XmdsConstConfig.AUTO_GUARD_MODE_POINT)//定点模式.
  825. {
  826. mCurGuardMode = GuardMode.Mode_Point;
  827. mGuardPos.SetX(this.X);
  828. mGuardPos.SetY(this.Y);
  829. }
  830. //array可能是point: point:0 point:taskId:targetId
  831. if (array.Length >= 3)
  832. {
  833. clearAutoGuardTargetList();
  834. if (!string.IsNullOrEmpty(array[1]))
  835. {
  836. int taskId = int.Parse(array[1]);
  837. for (int i = 2; i < array.Length; i++)
  838. {
  839. if (!string.IsNullOrEmpty(array[i]))
  840. {
  841. int targetId = int.Parse(array[i]);
  842. if (targetId > 0)
  843. {
  844. mAutoGuardTargetList.Add(targetId);
  845. log.Debug("--------------addTarget id: " + targetId);
  846. }
  847. }
  848. }
  849. }
  850. }
  851. }
  852. }
  853. private float GetGuardPosX()
  854. {
  855. switch (mCurGuardMode)
  856. {
  857. case GuardMode.Mode_Map:
  858. return this.X;
  859. case GuardMode.Mode_Point:
  860. return mGuardPos.X;
  861. default:
  862. return this.X;
  863. }
  864. }
  865. private float GetGuardPosY()
  866. {
  867. switch (mCurGuardMode)
  868. {
  869. case GuardMode.Mode_Map:
  870. return this.Y;
  871. case GuardMode.Mode_Point:
  872. return mGuardPos.Y;
  873. default:
  874. return this.Y;
  875. }
  876. }
  877. //查找自动攻击单位.
  878. public override InstanceUnit findGuardTarget(SkillTemplate.CastTarget expect = SkillTemplate.CastTarget.Enemy, AttackReason reason = AttackReason.Look)
  879. {
  880. InstanceUnit min = null;
  881. if (getAvailableAutoLaunchSkill(expect) != null)
  882. {
  883. //有优先目标取优先目标攻击.
  884. if (mAutoGuardTargetList.Count > 0)
  885. {
  886. //using (var list = ListObjectPool<InstanceUnit>.AllocAutoRelease())
  887. List<InstanceUnit> list = new List<InstanceUnit>();
  888. {
  889. Parent.ForEachNearObjects(GetGuardPosX(), GetGuardPosY(), mGuardSearchRange, (InstanceUnit u, ref bool cancel) =>
  890. {
  891. if (Parent.IsAttackable(this, u, expect, reason, Info))
  892. {
  893. XmdsVirtual zv = u.Virtual as XmdsVirtual;
  894. if (zv != null)
  895. {
  896. if (mAutoGuardTargetList.Contains(zv.GetVirtualTemplateID()))
  897. {
  898. list.Add(u);
  899. }
  900. }
  901. }
  902. });
  903. if (list.Count > 0)
  904. {
  905. list.Sort((a, b) =>
  906. {
  907. float da = CMath.getDistanceSquare(a.X, a.Y, this.X, this.Y);
  908. float db = CMath.getDistanceSquare(b.X, b.Y, this.X, this.Y);
  909. return (int)(da - db);
  910. });
  911. min = list[0];
  912. if (min != null)
  913. {
  914. mAutoGuardTargetTimes = 0;
  915. }
  916. }
  917. log.Debug("findGuardTarget times: " + mAutoGuardTargetTimes + " count:" + mAutoGuardTargetList.Count + " min:" + (min == null ? "null" : "finded"));
  918. //找不到目标怪就直接返回null等下一次查找,直到等待MAX_AUTO_GUARD_TARGET_TIMES次数
  919. if (mAutoGuardTargetList.Count > 0 && min == null)
  920. {
  921. mAutoGuardTargetTimes += 1;
  922. if (mAutoGuardTargetTimes >= MAX_AUTO_GUARD_TARGET_TIMES)
  923. {
  924. clearAutoGuardTargetList();
  925. }
  926. else
  927. {
  928. return null;
  929. }
  930. }
  931. }
  932. }
  933. //没有优先目标,按照默认逻辑走.
  934. //原本是走父类逻辑,但是现在要分挂机模式,要分索敌范围.
  935. //base.findGuardTarget(expect, reason);
  936. if (min == null)
  937. {
  938. if (getAvailableSkill(expect) != null)
  939. {
  940. bool isMeSteah = this.IsHasSubState(UnitActionSubStatus.Stealth);
  941. float min_len = float.MaxValue;
  942. Parent.ForEachNearObjects(GetGuardPosX(), GetGuardPosY(), mGuardSearchRange, (InstanceUnit u, ref bool cancel) =>
  943. {
  944. // 别人隐身了,自己没有隐身,自动攻击不到
  945. if(u.Virtual.GetBattleStatus() == BattleStatus.None && u.IsHasSubState(UnitActionSubStatus.Stealth) && !isMeSteah)
  946. {
  947. return;
  948. }
  949. if (Parent.IsAttackable(this, u, expect, reason, Info))
  950. {
  951. #if OPNE_JSG_AI_TOOLS
  952. //降低机器人之间的互相PK概率
  953. if (this.IsRobot && u.IsPlayer)
  954. {
  955. XmdsInstancePlayer uPlayer = u as XmdsInstancePlayer;
  956. if (uPlayer.IsRobot && this.RandomN.Next() % 100 < 95)
  957. {
  958. return;
  959. }
  960. }
  961. //AI随机攻击目标
  962. if (this.IsRobot && this.RandomN.Next() % 100 < 15)
  963. {
  964. min = u;
  965. cancel = true;
  966. return;
  967. }
  968. #endif
  969. float len = MathVector.getDistanceSquare(u.X, u.Y, this.X, this.Y);
  970. if (min_len > len)
  971. {
  972. min_len = len;
  973. min = u;
  974. }
  975. }
  976. });
  977. }
  978. return min;
  979. }
  980. }
  981. return min;
  982. }
  983. /// <summary>
  984. /// 当任务完成时
  985. /// </summary>
  986. /// <param name="qd"></param>
  987. protected override void onQuestCommitted(QuestData qd)
  988. {
  989. int targetId = XmdsQuestData.GetTargetID(qd);
  990. if (this.mAutoGuardTargetList.Contains(targetId))
  991. {
  992. clearAutoGuardTargetList();
  993. }
  994. }
  995. public override void OnReconnected(UnitInfo temp, int force, int level, Vector2 enterPos)
  996. {
  997. (this.Virtual as XmdsVirtual_Player).OnUnitReEnter(temp, force, level, enterPos);
  998. base.OnReconnected(temp, force, level, enterPos);
  999. }
  1000. public override void OnDisconnected()
  1001. {
  1002. base.OnDisconnected();
  1003. var act = new UnitGuardAction();
  1004. act.guard = false;
  1005. doGuard(act);
  1006. var actFollow = new UnitFollowAction();
  1007. actFollow.follow = false;
  1008. doFollow(actFollow);
  1009. }
  1010. protected override void doFollow(UnitFollowAction act)
  1011. {
  1012. base.doFollow(act);
  1013. if (act.follow == true)
  1014. {
  1015. if (this.TeamVirtual != null && this.stateFollow != null)
  1016. {
  1017. if (this.TeamVirtual.TeamLeader != null && this.TeamVirtual.TeamLeader.Enable)
  1018. {
  1019. if (this.TeamVirtual.acceptAutoFollow(this))
  1020. {
  1021. this.TeamVirtual.changeMemberAutoFollow();
  1022. this.stateFollow.Distance = this.TeamVirtual.TeamLeader.RadiusSize + (this.BodyBlockSize * (this.FollowIndex + 1)) * 2;
  1023. //this.changeState(this.stateFollow);
  1024. }
  1025. else
  1026. {
  1027. this.TeamVirtual.cancelAutoFollow(this);
  1028. this.TeamVirtual.changeMemberAutoFollow();
  1029. }
  1030. }
  1031. else if (this.TeamVirtual.TeamLeader == null)
  1032. {
  1033. this.TeamVirtual.cancelAutoFollow(this);
  1034. this.TeamVirtual.changeMemberAutoFollow();
  1035. }
  1036. }
  1037. }
  1038. else
  1039. {
  1040. if (this.TeamVirtual != null)
  1041. {
  1042. this.TeamVirtual.cancelAutoFollow(this);
  1043. this.TeamVirtual.changeMemberAutoFollow();
  1044. }
  1045. }
  1046. }
  1047. public void SendBotTestAutoFight()
  1048. {
  1049. if (mBotTestAutoFight == true)
  1050. {
  1051. var act = new UnitGuardAction();
  1052. act.guard = true;
  1053. doGuard(act);
  1054. }
  1055. }
  1056. #region 自动释放技能.
  1057. /// <summary>
  1058. /// 获得当前能够使用的技能.
  1059. /// </summary>
  1060. /// <returns></returns>
  1061. protected SkillState GetAvailableAutoLaunchSkill(ref InstanceUnit enemy)
  1062. {
  1063. SkillState ret = null;
  1064. do
  1065. {
  1066. //没蓝直接转普攻.
  1067. if (mXmdsFocusTarget == null) { break; }
  1068. List<SkillState> list = SkillStatus as List<SkillState>;
  1069. XmdsStateFollowAndAttack current = CurrentState as XmdsStateFollowAndAttack;
  1070. //优先多段攻击技能
  1071. if (current != null)
  1072. {
  1073. for (int si = list.Count - 1; si >= 0; --si)
  1074. {
  1075. SkillState sst = list[si];
  1076. if (sst == null || (DefaultSkill != null && DefaultSkill.ID == sst.Data.ID))
  1077. {
  1078. continue;
  1079. }
  1080. if (sst.LaunchSkill.AutoLaunch && sst.IsActive && sst.IsMutilAction() && sst.IsHasNext()
  1081. && sst.IsCD && sst.IsDone && this.VirtualPlayer.SkillAutoLaunchTest(sst))
  1082. {
  1083. //System.Console.WriteLine(" - GetAvailableAutoLaunchSkill - " + sst.ID + ", " + sst.ActionIndex);
  1084. ret = sst;
  1085. break;
  1086. }
  1087. }
  1088. }
  1089. //其次技能.
  1090. if (ret != null) { break; }
  1091. for (int si = list.Count - 1; si >= 0; --si)
  1092. {
  1093. SkillState sst = list[si];
  1094. //非PVP, PVE状态下不允许释放技能
  1095. if (DefaultSkill != null && sst.Data.ID != DefaultSkill.ID &&
  1096. sst.LaunchSkill.AutoLaunch && (Virtual.IsInPVP() || Virtual.IsInPVE()))
  1097. {
  1098. if (!sst.IsCD && sst.IsActive && sst.IsDone && sst.LaunchSkill.AutoLaunch && sst.CanAutoLaunch() &&
  1099. this.VirtualPlayer.SkillAutoLaunchTest(sst))
  1100. {
  1101. //判断需要能量值
  1102. if (!this.Virtual.LaunchSkillCheckTalentInfo(sst))
  1103. {
  1104. continue;
  1105. }
  1106. //切换作用不同的技能,这时需要切换技能目标,会导致丢失原目标.
  1107. if (mXmdsFocusTarget.ExpectTarget != sst.Data.ExpectTarget)
  1108. {
  1109. enemy = findGuardTarget(sst.Data.ExpectTarget, AttackReason.Look);
  1110. }
  1111. if (enemy != null)
  1112. {
  1113. ret = sst;
  1114. }
  1115. break;
  1116. }
  1117. }
  1118. }
  1119. } while (false);
  1120. //没有技能时施放普攻.
  1121. if (ret == null && DefaultSkill != null)
  1122. {
  1123. if (enemy != null)
  1124. {
  1125. ret = getSkillState(DefaultSkill.ID);
  1126. }
  1127. }
  1128. return ret;
  1129. }
  1130. /// <summary>
  1131. /// 判断目标技能是否可以自动释放.
  1132. /// </summary>
  1133. /// <param name="skillid"></param>
  1134. /// <returns></returns>
  1135. //private bool CanAutoLaunchSkill(int skillid)
  1136. //{
  1137. // bool ret = false;
  1138. // var v = (this.Virtual as XmdsVirtual);
  1139. // if (v != null)
  1140. // {
  1141. // ret = v.AllowAutoLaunch(skillid);
  1142. // }
  1143. // return ret;
  1144. //}
  1145. public override SkillState getRandomLaunchableExpectSkill(InstanceUnit target, SkillTemplate.CastTarget expectTarget, AttackReason reason = AttackReason.Tracing, bool checkRange = false)
  1146. {
  1147. var ss = GetAvailableAutoLaunchSkill(ref target);
  1148. if (mXmdsFocusTarget != null && target != null && ss != null)
  1149. {
  1150. //mXmdsFocusTarget.TargetUnit = target;
  1151. //mXmdsFocusTarget.ExpectSkillState = ss;
  1152. //mXmdsFocusTarget.ChangeMoveTarget(target);
  1153. mXmdsFocusTarget.ChangeAttackTarget(ss, target);
  1154. }
  1155. return ss;
  1156. }
  1157. private InstanceUnit lastAttackUnit = null;
  1158. public override SkillState getRandomLaunchableExpectSkill(SkillTemplate.CastTarget expectTarget)
  1159. {
  1160. InstanceUnit unit = null;
  1161. if (mXmdsFocusTarget != null)
  1162. {
  1163. unit = mXmdsFocusTarget.TargetUnit;
  1164. }
  1165. var ss = GetAvailableAutoLaunchSkill(ref unit);
  1166. if (mXmdsFocusTarget != null && unit != null && ss != null)
  1167. {
  1168. //mXmdsFocusTarget.TargetUnit = unit;
  1169. //mXmdsFocusTarget.ExpectSkillState = ss;
  1170. //mXmdsFocusTarget.ChangeMoveTarget(unit);
  1171. if (ss.Data.ExpectTarget != mXmdsFocusTarget.ExpectTarget)
  1172. {
  1173. if (mXmdsFocusTarget.ExpectTarget == SkillTemplate.CastTarget.Enemy)
  1174. {
  1175. lastAttackUnit = mXmdsFocusTarget.TargetUnit;
  1176. }
  1177. }
  1178. mXmdsFocusTarget.ChangeAttackTarget(ss, unit);
  1179. }
  1180. return ss;
  1181. }
  1182. public void OnReceiveGetMonsterSufferDamageInfoC2B(GetMonsterSufferDamageInfoC2B evt)
  1183. {
  1184. var ret = evt as GetMonsterSufferDamageInfoC2B;
  1185. //找到指定的怪物单位,获取伤害信息并排序.
  1186. InstanceUnit iu = this.Parent.getUnit(ret.MonsterID);
  1187. if (iu != null && iu is XmdsInstanceMonster)
  1188. {
  1189. XmdsVirtual_Monster zvm = (iu as XmdsInstanceMonster).Virtual as XmdsVirtual_Monster;
  1190. if (zvm != null)
  1191. {
  1192. HashMap<string, PlayerDamageInfo> map = zvm.GetSufferDamage();
  1193. if (map != null)
  1194. {
  1195. MonsterSufferDamageInfoB2C msg = new MonsterSufferDamageInfoB2C();
  1196. List<PlayerDamageInfo> infoList = new List<PlayerDamageInfo>();
  1197. int playerRank = 0;
  1198. int playerDamage = 0;
  1199. //获取数据并排序.
  1200. foreach (var kvp in map)
  1201. {
  1202. infoList.Add(kvp.Value);
  1203. }
  1204. //伤害从大到小排序.
  1205. infoList.Sort((a, b) =>
  1206. {
  1207. return b.Damage - a.Damage;
  1208. });
  1209. //找到自己的排名和伤害.
  1210. for (int i = 0; i < infoList.Count; i++)
  1211. {
  1212. var temp = infoList[i];
  1213. if (this.PlayerUUID == temp.PlayerUUID)
  1214. {
  1215. playerRank = i + 1;
  1216. playerDamage = temp.Damage;
  1217. break;
  1218. }
  1219. }
  1220. //只取10条详细信息发送.
  1221. if (infoList.Count > 10)
  1222. {
  1223. infoList.RemoveRange(10, infoList.Count - 10);
  1224. }
  1225. msg.PlayerDamage = playerDamage;
  1226. msg.PlayerRank = playerRank;
  1227. msg.InfoList = infoList;
  1228. this.queueEvent(msg);
  1229. }
  1230. }
  1231. }
  1232. }
  1233. #endregion
  1234. #region 绕开底层重新实现自动战斗AI.
  1235. private XmdsInstanceUnitStateMachine.XmdsStateFollowAndAttack doXmdsFocusAttack(InstanceUnit target,
  1236. SkillTemplate.CastTarget expect_target = SkillTemplate.CastTarget.Enemy,
  1237. bool autoFocusNearTarget = true, InstanceUnit.SkillState lanuchSkill = null)
  1238. {
  1239. if ((mAttackTo == null || mAttackTo.IsAttack) && Parent.IsAttackable(this, target, expect_target, AttackReason.Tracing, Info))
  1240. {
  1241. this.mLastAutoAttackTime = CommonLang.CUtils.localTimeMS;
  1242. if (mXmdsFocusTarget != null)
  1243. {
  1244. if (mXmdsFocusTarget.TargetUnit != target)
  1245. {
  1246. mXmdsFocusTarget = new XmdsInstanceUnitStateMachine.XmdsStateFollowAndAttack(this, target, expect_target, autoFocusNearTarget, lanuchSkill);
  1247. if (changeState(mXmdsFocusTarget))
  1248. {
  1249. queueEvent(new PlayerFocuseTargetEvent(this.ID, target.ID, expect_target));
  1250. }
  1251. }
  1252. }
  1253. else
  1254. {
  1255. mXmdsFocusTarget = new XmdsInstanceUnitStateMachine.XmdsStateFollowAndAttack(this, target, expect_target, autoFocusNearTarget, lanuchSkill);
  1256. if (changeState(mXmdsFocusTarget))
  1257. {
  1258. queueEvent(new PlayerFocuseTargetEvent(this.ID, target.ID, expect_target));
  1259. }
  1260. }
  1261. }
  1262. else
  1263. {
  1264. mXmdsFocusTarget = null;
  1265. }
  1266. return mXmdsFocusTarget;
  1267. }
  1268. private void doXmdsFocusAttack(InstanceUnit target, SkillState state)
  1269. {
  1270. SkillTemplate.CastTarget expect_target = state.Data.ExpectTarget;
  1271. if ((mAttackTo == null || mAttackTo.IsAttack) && Parent.IsAttackable(this, target, expect_target, AttackReason.Tracing, Info))
  1272. {
  1273. if (mXmdsFocusTarget != null)
  1274. {
  1275. if (mXmdsFocusTarget.TargetUnit != target)
  1276. {
  1277. mXmdsFocusTarget = new XmdsInstanceUnitStateMachine.XmdsStateFollowAndAttack(this, target, expect_target, true);
  1278. mXmdsFocusTarget.ExpectSkillState = state;
  1279. if (changeState(mXmdsFocusTarget))
  1280. {
  1281. queueEvent(new PlayerFocuseTargetEvent(this.ID, target.ID, expect_target));
  1282. }
  1283. }
  1284. }
  1285. else
  1286. {
  1287. mXmdsFocusTarget = new XmdsInstanceUnitStateMachine.XmdsStateFollowAndAttack(this, target, expect_target, true);
  1288. mXmdsFocusTarget.ExpectSkillState = state;
  1289. if (changeState(mXmdsFocusTarget))
  1290. {
  1291. queueEvent(new PlayerFocuseTargetEvent(this.ID, target.ID, expect_target));
  1292. }
  1293. }
  1294. }
  1295. else
  1296. {
  1297. mXmdsFocusTarget = null;
  1298. }
  1299. }
  1300. protected override void cleanFocus()
  1301. {
  1302. mFocusTarget = null;
  1303. mXmdsFocusTarget = null;
  1304. base.cleanFocus();
  1305. }
  1306. protected override void doFocusTarget(UnitFocuseTargetAction focus)
  1307. {
  1308. if (IsGuard)
  1309. {
  1310. mAttackTo = null;
  1311. InstanceZoneObject src = Parent.getObject<InstanceZoneObject>(focus.targetUnitID);
  1312. //目标不能是宠物
  1313. if ((src is InstanceUnit) && !(src is InstancePet))
  1314. {
  1315. if (!IsNoneSkill && ((src as InstanceUnit).IsActive))
  1316. {
  1317. doXmdsFocusAttack(src as InstanceUnit);
  1318. }
  1319. }
  1320. else if ((src is InstanceItem))
  1321. {
  1322. if (src.Enable)
  1323. {
  1324. doFocusPickItem(src as InstanceItem);
  1325. }
  1326. }
  1327. else
  1328. {
  1329. cleanFocus();
  1330. }
  1331. }
  1332. }
  1333. public override void OnUnitDead()
  1334. {
  1335. this.cleanFocus();
  1336. // 死亡取消自动战斗
  1337. if (this.IsGuard)
  1338. {
  1339. this.IsGuard = false;
  1340. this.Virtual.doEvent(JSGCustomOpType.UpdateAutoBattleFlag);
  1341. }
  1342. }
  1343. public override void doSomething()
  1344. {
  1345. if (mWaitingSkill != null && CurrentState is StateSkill)
  1346. {
  1347. if (doLaunchSkill(mWaitingSkill))
  1348. {
  1349. return;
  1350. }
  1351. }
  1352. else if(this.DoAutoPick())
  1353. {
  1354. return;
  1355. }
  1356. else if (IsGuard)
  1357. {
  1358. if (this.canFollowTeam && leadingMan != null)
  1359. {
  1360. if (leadingMan.AoiStatus != null)
  1361. {
  1362. //若队长进入位面
  1363. UnitGuardAction action = new UnitGuardAction();
  1364. action.guard = false;
  1365. action.reason = "guard to follow";
  1366. doGuard(action);
  1367. startIdle();
  1368. return;
  1369. }
  1370. else if (leadingMan.Virtual.GetBattleStatus() == BattleStatus.None)
  1371. {
  1372. UnitGuardAction action = new UnitGuardAction();
  1373. action.guard = false;
  1374. action.reason = "guard to follow";
  1375. doGuard(action);
  1376. updateStateToFollowTeam();
  1377. mXmdsFocusTarget = null;
  1378. return;
  1379. }
  1380. this.stateFollow.Distance = this.leadingMan.RadiusSize + (this.BodyBlockSize * (this.FollowIndex + 1)) * 2;
  1381. //var distance = leadingMan.RadiusSize + this.BodyBlockSize * 2;
  1382. if (!CMath.includeRoundPoint(X, Y, this.GetFollowDistance(true), leadingMan.X, leadingMan.Y))
  1383. {
  1384. UnitGuardAction action = new UnitGuardAction();
  1385. action.guard = false;
  1386. action.reason = "guard to follow";
  1387. doGuard(action);
  1388. updateStateToFollowTeam();
  1389. mXmdsFocusTarget = null;
  1390. return;
  1391. }
  1392. }
  1393. if (mFocusPickItem != null && mFocusPickItem.IsActive)
  1394. {
  1395. changeState(mFocusPickItem);
  1396. return;
  1397. }
  1398. else
  1399. {
  1400. mFocusPickItem = null;
  1401. }
  1402. if (mXmdsFocusTarget != null && mXmdsFocusTarget.IsActive)
  1403. {
  1404. if (Parent.IsAttackable(this, mXmdsFocusTarget.TargetUnit, SkillTemplate.CastTarget.AlliesIncludeSelf, AttackReason.Attack, Info))
  1405. {
  1406. mXmdsFocusTarget = null;
  1407. }
  1408. else
  1409. {
  1410. changeState(mXmdsFocusTarget);
  1411. return;
  1412. }
  1413. }
  1414. else
  1415. {
  1416. mXmdsFocusTarget = null;
  1417. }
  1418. if (mAttackTo != null && !mAttackTo.IsDone)
  1419. {
  1420. changeState(mAttackTo);
  1421. return;
  1422. }
  1423. }
  1424. else if (this.canFollowTeam && leadingMan != null)
  1425. {
  1426. if (leadingMan.Enable)
  1427. {
  1428. if (this.CurrentState != this.stateFollow)
  1429. {
  1430. if (leadingMan.AoiStatus != null)
  1431. {
  1432. //若队长进入位面
  1433. return;
  1434. }
  1435. this.stateFollow.Distance = this.leadingMan.RadiusSize + (this.BodyBlockSize * (this.FollowIndex + 1)) * 2;
  1436. if (!CMath.includeRoundPoint(X, Y, this.GetFollowDistance(false), leadingMan.X, leadingMan.Y))
  1437. {
  1438. this.updateStateToFollowTeam();
  1439. mXmdsFocusTarget = null;
  1440. }
  1441. else
  1442. {//组队切场景后,如果队长不移动,队员状态不改变
  1443. this.updateStateToFollowTeam();
  1444. mXmdsFocusTarget = null;
  1445. }
  1446. }
  1447. else
  1448. {
  1449. //发生寻路卡死
  1450. //transportToTeamLeader();
  1451. }
  1452. //var distance = leadingMan.RadiusSize + this.BodyBlockSize * 2;
  1453. //if (!CMath.includeRoundPoint(X, Y, distance, leadingMan.X, leadingMan.Y))
  1454. //{
  1455. // this.updateStateToFollowTeam();
  1456. // mXmdsFocusTarget = null;
  1457. // return;
  1458. //}
  1459. return;
  1460. }
  1461. else
  1462. {
  1463. //leadingMan忙,切换leadingMan
  1464. //mTeamVirtual.changeMemberAutoFollow();
  1465. }
  1466. }
  1467. else if (CurrentState is StateChuanGongA || CurrentState is StateChuanGongB || CurrentState is StateClearYaoQi)
  1468. {
  1469. if (CommonLang.CUtils.localTimeMS < chuangongTime)
  1470. {
  1471. return;
  1472. }
  1473. }
  1474. else if(CurrentState is StateDaZuo)
  1475. {
  1476. return;
  1477. }
  1478. else if (CurrentState is StateDaZuoRecoveryAttr)
  1479. {
  1480. return;
  1481. }
  1482. startIdle();
  1483. }
  1484. #endregion
  1485. private float GetFollowDistance(bool isGuard)
  1486. {
  1487. if (isGuard)
  1488. {
  1489. return Templates.CFG.PET_FOLLOW_DISTANCE_MAX;
  1490. }
  1491. return this.stateFollow.Distance;
  1492. }
  1493. private void OnPlayerCreate()
  1494. {
  1495. lock (CreateInfoMap)
  1496. {
  1497. AtomicInteger c = null;
  1498. zoneID = (this.Parent as EditorScene).Data.ID;
  1499. if (CreateInfoMap.TryGetValue(zoneID, out c))
  1500. {
  1501. c++;
  1502. }
  1503. else
  1504. {
  1505. c = new AtomicInteger(1);
  1506. CreateInfoMap.Add(zoneID, c);
  1507. }
  1508. }
  1509. }
  1510. ~XmdsInstancePlayer()
  1511. {
  1512. lock (CreateInfoMap)
  1513. {
  1514. AtomicInteger c = null;
  1515. if (CreateInfoMap.TryGetValue(zoneID, out c))
  1516. {
  1517. c--;
  1518. }
  1519. }
  1520. }
  1521. //组队跟随
  1522. private XmdsTeamVirtual mTeamVirtual;
  1523. public XmdsTeamVirtual TeamVirtual
  1524. {
  1525. set
  1526. {
  1527. mTeamVirtual = value;
  1528. }
  1529. get
  1530. {
  1531. return mTeamVirtual;
  1532. }
  1533. }
  1534. private byte mFollowIndex;
  1535. public byte FollowIndex
  1536. {
  1537. set
  1538. {
  1539. mFollowIndex = value;
  1540. }
  1541. get
  1542. {
  1543. return mFollowIndex;
  1544. }
  1545. }
  1546. protected XmdsInstancePlayer leadingMan;
  1547. public XmdsInstancePlayer Leader
  1548. {
  1549. get
  1550. {
  1551. return leadingMan;
  1552. }
  1553. set
  1554. {
  1555. if (leadingMan != value)
  1556. {
  1557. leadingMan = value;
  1558. if (leadingMan == null)
  1559. {
  1560. this.stateFollow = null;
  1561. }
  1562. else
  1563. {
  1564. if (this.stateFollow == null)
  1565. {
  1566. this.stateFollow = new StateFollowLeader(this, leadingMan, 30);
  1567. }
  1568. else
  1569. {
  1570. this.stateFollow.Follower = leadingMan;
  1571. }
  1572. //this.stateFollow = StateFollowTeam.createStateFollowTeam(this, leadingMan);
  1573. }
  1574. }
  1575. }
  1576. }
  1577. public bool canFollowTeam = false;
  1578. public StateFollowLeader stateFollow;
  1579. override public bool isTeamMemberAndFollow()
  1580. {
  1581. return canFollowTeam;
  1582. }
  1583. //切换至跟随状态
  1584. public void updateStateToFollowTeam()
  1585. {
  1586. if (this.mIsReady)
  1587. {
  1588. if (this.canFollowTeam)
  1589. {
  1590. if (this.stateFollow != null && this.CurrentState != this.stateFollow)
  1591. {
  1592. this.changeState(this.stateFollow);
  1593. }
  1594. else if (this.stateFollow == null)
  1595. {
  1596. mTeamVirtual.changeMemberAutoFollow();
  1597. }
  1598. }
  1599. }
  1600. }
  1601. public void cancelGuard()
  1602. {
  1603. if (IsGuard)
  1604. {
  1605. log.Debug("------guardCanceled: " + this.Name);
  1606. UnitGuardAction action = new UnitGuardAction();
  1607. action.guard = false;
  1608. action.reason = "sdfsdfsdfs";
  1609. doGuard(action);
  1610. SetAutoBattleB2C evt = new SetAutoBattleB2C();
  1611. evt.isAutoBattle = 0;
  1612. this.queueEvent(evt);
  1613. }
  1614. }
  1615. /// <summary>
  1616. ///
  1617. /// </summary>
  1618. private void updateFollowTeam()
  1619. {
  1620. if (this.CurrentState == this.stateFollow && this.mTeamVirtual != null && this.canFollowTeam && this.leadingMan != null && this.leadingMan.Enable)
  1621. {
  1622. // 当前如果正在拾取状态,先捡完再说
  1623. if(this.CurrentState is StateFollowAndPickItem)
  1624. {
  1625. return;
  1626. }
  1627. if (CMath.includeRoundPoint(X, Y, this.GetFollowDistance(true), leadingMan.X, leadingMan.Y))
  1628. {
  1629. //在范围内
  1630. var leader = this.leadingMan;
  1631. if (leader.AoiStatus != null)
  1632. {
  1633. //队长在位面中
  1634. UnitGuardAction action = new UnitGuardAction();
  1635. action.guard = false;
  1636. action.reason = "sdfsdfsdfs";
  1637. doGuard(action);
  1638. startIdle();
  1639. //updateStateToFollowTeam();
  1640. return;
  1641. }
  1642. var vir = leader.Virtual as XmdsVirtual;
  1643. if (vir.CombatState == BattleStatus.PVE)
  1644. {
  1645. if (IsGuard == false)
  1646. {
  1647. //队长在PVE状态
  1648. UnitGuardAction action = new UnitGuardAction();
  1649. action.guard = true;
  1650. action.reason = CommonAI.XmdsConstConfig.AUTO_GUARD_MODE_POINT;
  1651. doGuard(action);
  1652. }
  1653. }
  1654. else if (vir.CombatState == BattleStatus.PVP)
  1655. {
  1656. //队长在PVP状态
  1657. //检查玩家Pk状态在“自由”,“队伍”攻击模式下,则跟随队长攻击目标,否则无视
  1658. var myVir = this.Virtual as XmdsVirtual;
  1659. if (IsGuard == false/* &&( myVir.GetCurPKMode() == PKInfo.PKMode.Team
  1660. || myVir.GetCurPKMode() == PKInfo.PKMode.All)*/)
  1661. {
  1662. UnitGuardAction action = new UnitGuardAction();
  1663. action.guard = true;
  1664. action.reason = CommonAI.XmdsConstConfig.AUTO_GUARD_MODE_POINT;
  1665. doGuard(action);
  1666. }
  1667. }
  1668. }
  1669. else
  1670. {
  1671. UnitGuardAction action = new UnitGuardAction();
  1672. action.guard = false;
  1673. action.reason = "sdfsdfsdfs";
  1674. doGuard(action);
  1675. updateStateToFollowTeam();
  1676. }
  1677. }
  1678. }
  1679. //检测修正部分异常数据
  1680. private void UpdateAndModifyErrorData()
  1681. {
  1682. if(this.CurrentActionStatus == UnitActionStatus.Move)
  1683. {
  1684. if(this.mNotMoveTimes == 0)
  1685. {
  1686. this.mNotMoveTimes = 1;
  1687. this.mLastMovePos.SetX(this.X);
  1688. this.mLastMovePos.SetY(this.Y);
  1689. }
  1690. else if(this.mLastMovePos.X == this.X && this.mLastMovePos.Y == this.Y)
  1691. {
  1692. this.mNotMoveTimes++;
  1693. }
  1694. else
  1695. {
  1696. this.mNotMoveTimes = 0;
  1697. }
  1698. if(this.mNotMoveTimes > 10)
  1699. {
  1700. this.mNotMoveTimes = 0;
  1701. this.doSomething();
  1702. }
  1703. }
  1704. else
  1705. {
  1706. this.mNotMoveTimes = 0;
  1707. }
  1708. }
  1709. //移动到队长旁
  1710. public void moveToLeader()
  1711. {
  1712. if (!this.mIsReady)
  1713. {
  1714. this.readyAction = moveToLeader;
  1715. return;
  1716. }
  1717. if (this.leadingMan != null)
  1718. {
  1719. if (this.CurrentState != this.stateFollow)
  1720. {
  1721. this.changeState(this.stateFollow);
  1722. var virt = this.Virtual as XmdsVirtual;
  1723. if (!virt.IsMounted && !virt.IsInDebuffStatus() && !CMath.includeRoundPoint(this.X, this.Y, this.Templates.CFG.TEAMER_FOLLOW_DISTANCE_LIMIT, this.leadingMan.X, this.leadingMan.Y))
  1724. {
  1725. PlayerSummonMountEventR2B r2b = new PlayerSummonMountEventR2B();
  1726. r2b.TimeMS = 0;
  1727. r2b.IsSummonMount = true;
  1728. (this.Virtual as XmdsVirtual).ReceiveMsgR2B(r2b);
  1729. }
  1730. }
  1731. //float dx, dy;
  1732. //var distance = this.leadingMan.RadiusSize + (this.BodyBlockSize * (this.FollowIndex + 1)) * 2;
  1733. //CMath.RandomPosInRound(Parent.RandomN, this.leadingMan.X, this.leadingMan.Y,
  1734. // distance, out dx, out dy);
  1735. //if (CMath.includeRoundPoint(
  1736. // this.X, this.Y,
  1737. // distance,
  1738. // dx, dy))
  1739. //{
  1740. // this.changeState(this.stateFollow);
  1741. // return;
  1742. //}
  1743. //this.changeState(new StateIdle(this));
  1744. ////StateFollowTeam stateMove = StateFollowTeam.createStateFollowTeam(this, leadingMan);
  1745. //StateMove stateMove = new StateMove(this, dx, dy);
  1746. //stateMove.EndMoveAction = (m) =>
  1747. //{
  1748. // this.changeState(this.stateFollow);
  1749. // return false;
  1750. //};
  1751. //var virt = this.Virtual as XmdsVirtual;
  1752. //if (!virt.IsMounted && !CMath.includeRoundPoint(this.X, this.Y, this.Templates.CFG.TEAMER_FOLLOW_DISTANCE_LIMIT, this.leadingMan.X, this.leadingMan.Y))
  1753. //{
  1754. // PlayerSummonMountEventR2B r2b = new PlayerSummonMountEventR2B();
  1755. // r2b.TimeMS = 0;
  1756. // r2b.IsSummonMount = true;
  1757. // (this.Virtual as XmdsVirtual).ReceiveMsgR2B(r2b);
  1758. //}
  1759. //this.changeState(stateMove);
  1760. }
  1761. }
  1762. protected override void onAdded(bool pointLv)
  1763. {
  1764. base.onAdded(pointLv);
  1765. //吴永辉:进入PVP地图清除技能CD bugId:2797
  1766. XmdsServerScene scene = this.Parent as XmdsServerScene;
  1767. SceneType sceneType = this.VirtualPlayer.mUnit.GetSceneType();
  1768. if (sceneType == SceneType.DanTiao || sceneType == SceneType.JJC || sceneType == SceneType.CrossServer || sceneType == SceneType.MengZhan
  1769. || sceneType == SceneType.FiveVFive || sceneType == SceneType.SourceDungeon
  1770. || sceneType == SceneType.GuildBoss || sceneType == SceneType.SecretDungeon)
  1771. {
  1772. this.ClearAllSkillCD();
  1773. }
  1774. }
  1775. }
  1776. //队伍跟随
  1777. public class StateFollowLeader : VStateFollowLeader
  1778. {
  1779. private InstanceZoneObject follower;
  1780. public InstanceZoneObject Follower
  1781. {
  1782. get
  1783. {
  1784. return follower;
  1785. }
  1786. set
  1787. {
  1788. follower = value;
  1789. this.target = follower;
  1790. }
  1791. }
  1792. public StateFollowLeader(InstanceUnit unit, InstanceZoneObject target, int holdTime = 0) : base(unit, target, holdTime)
  1793. {
  1794. follower = target;
  1795. }
  1796. protected override void onStart()
  1797. {
  1798. if (follower != null)
  1799. {
  1800. unit.SetActionStatus(UnitActionStatus.Move);
  1801. MoveAI.FindPath(follower);
  1802. }
  1803. }
  1804. protected override void onUpdate()
  1805. {
  1806. base.onUpdate();
  1807. switch (FollowState)
  1808. {
  1809. case MoveState.Move:
  1810. var virt = unit.Virtual as XmdsVirtual;
  1811. if (!virt.IsMounted && !virt.IsInDebuffStatus() && !CMath.includeRoundPoint(unit.X, unit.Y, unit.Templates.CFG.TEAMER_FOLLOW_DISTANCE_LIMIT, follower.X, follower.Y))
  1812. {
  1813. //Console.WriteLine("请求上马");
  1814. PlayerSummonMountEventR2B r2b = new PlayerSummonMountEventR2B();
  1815. r2b.TimeMS = 0;
  1816. r2b.IsSummonMount = true;
  1817. (unit.Virtual as XmdsVirtual).ReceiveMsgR2B(r2b);
  1818. }
  1819. break;
  1820. }
  1821. }
  1822. protected override void onUpdateFollowed(IPositionObject target)
  1823. {
  1824. unit.doSomething();
  1825. }
  1826. protected override void onChangedToMove(IPositionObject target)
  1827. {
  1828. var virt = unit.Virtual as XmdsVirtual;
  1829. if (!virt.IsMounted && !virt.IsInDebuffStatus() && !CMath.includeRoundPoint(unit.X, unit.Y, unit.Templates.CFG.TEAMER_FOLLOW_DISTANCE_LIMIT, follower.X, follower.Y))
  1830. {
  1831. PlayerSummonMountEventR2B r2b = new PlayerSummonMountEventR2B();
  1832. r2b.TimeMS = 0;
  1833. r2b.IsSummonMount = true;
  1834. (unit.Virtual as XmdsVirtual).ReceiveMsgR2B(r2b);
  1835. }
  1836. }
  1837. }
  1838. }