/TGame/TCommon/Move/Move.cpp

http://awoe.googlecode.com/ · C++ · 662 lines · 481 code · 126 blank · 55 comment · 94 complexity · ae719be65105e4cbcdaae26c8620a678 MD5 · raw file

  1. #include "stdafx.h"
  2. #include "MoveController.h"
  3. Move::Move()
  4. :m_nCurMoveType(MT_WALK),
  5. m_nPrevMoveState(UnitBase::ums_Idle),
  6. m_bWalkOnly(false),
  7. m_MaxSpeed(MAX_SPEED),
  8. m_MaxTurn ( MAX_TURN ),
  9. m_AngularSpeed (ANGULAR_SPEED)
  10. {
  11. }
  12. Move::~Move()
  13. {
  14. }
  15. bool
  16. Move::OnCreate(StaticUnitGene* pGSData, IGeneData* pGDData)
  17. {
  18. if (__super::OnCreate(pGSData, pGDData))
  19. {
  20. int nData;
  21. nData = m_pStaticData->GetArg(AT_MaxSpeed);
  22. if (nData!=0)
  23. {
  24. m_MaxSpeed = float(nData) / 1000;
  25. }
  26. nData = m_pStaticData->GetArg(AT_MaxTurn);
  27. if (nData!=0)
  28. {
  29. m_MaxTurn = float(nData) / 1000;
  30. }
  31. nData = m_pStaticData->GetArg(AT_ArgularSpeed);
  32. if (nData!=0)
  33. {
  34. m_AngularSpeed = float(nData) / 1000;
  35. }
  36. }
  37. return true;
  38. }
  39. bool
  40. Move::OnAttach()
  41. {
  42. m_pUnit->RegGeneEvt( UGE_Move, this);
  43. m_pUnit->RegGeneEvt( UGE_Stop, this );
  44. if (m_pUnit->IsMonster())
  45. {
  46. m_bWalkOnly = true;
  47. }
  48. return true;
  49. }
  50. bool
  51. Move::OnDetach()
  52. {
  53. m_vctPath.clear();
  54. m_nPathIndex = 0;
  55. OnMoveStop();
  56. m_pUnit->UnregGeneEvt( UGE_Move, this);
  57. m_pUnit->UnregGeneEvt( UGE_Stop, this );
  58. return true;
  59. }
  60. bool
  61. Move::OnUpdate(int nElapse)
  62. {
  63. if (m_nPrevMoveState!=m_pUnit->GetMoveState())
  64. {
  65. //
  66. // someone else change the unit move state
  67. if (m_nPrevMoveState==UnitBase::ums_Moving &&
  68. m_pUnit->GetMoveState()!=UnitBase::ums_OutOfControl)
  69. {
  70. OnMoveStop(false, false);
  71. }
  72. //
  73. // keep state in sync with unit move state
  74. m_nPrevMoveState = m_pUnit->GetMoveState();
  75. }
  76. if (m_nPrevMoveState==UnitBase::ums_Idle ||
  77. m_nPrevMoveState==UnitBase::ums_Freeze)
  78. {
  79. return true;
  80. }
  81. Vector3 vct3Current = ToVector3(m_pUnit->GetPosition());
  82. Vector3 vct3Advance = ToVector3(m_pUnit->GetDirection());
  83. Vector3 vct3Position;
  84. Vector3 vct3DiffToNextPt;
  85. Vector3 vct3CurrentDiff;
  86. Real nCurrDiff;
  87. Real nNewDiff;
  88. Scene* pScene;
  89. if (m_vctPath.size() == 0)
  90. {
  91. return true;
  92. }
  93. // Always go into idle to allow blending
  94. pScene = m_pUnit->GetScene();
  95. if (pScene == NULL)
  96. {
  97. return true;
  98. }
  99. //m_MaxSpeed = pScene->GetMaxSpeed();
  100. //start to move
  101. if (m_pUnit->GetVelocity() == 0.0f)
  102. {
  103. m_pUnit->SetVelocity(0.01f); // Just so Idle stops
  104. m_nAcceleration = 1.0f;
  105. }
  106. else
  107. {
  108. // Check to make sure the desired and actual directions match so the unit doesn't make a wide turn on startup which can cause collision issues, remove check if that is ok
  109. // if (m_pUnit->GetVelocity() < m_pu3dMoveAnimation->m_nMaxRange) // && m_pUnit->m_lmUnit.GetDirectionsMatch() == true)
  110. if (m_nAcceleration != 0.0f)//moving
  111. {
  112. float nVelocity;
  113. nVelocity = m_pUnit->GetVelocity() * m_MaxSpeed/* * 0.75*/;
  114. nVelocity += (m_MaxSpeed * (float(nElapse)) / 1000 * m_nAcceleration) / 0.5;
  115. // Check ranges and stop
  116. if (nVelocity >= m_MaxSpeed)//to max speed
  117. {
  118. m_pUnit->SetVelocity(1.0);
  119. m_nAcceleration = 0.0f;
  120. }
  121. else if (nVelocity <= 0.0f)//stop moving
  122. {
  123. m_pUnit->SetVelocity(0.0f);
  124. m_nAcceleration = 0.0f;
  125. OnMoveStop();
  126. m_vctPath.clear();
  127. }
  128. else//
  129. {
  130. if (nVelocity > 0.0f)
  131. m_pUnit->SetVelocity(nVelocity/m_MaxSpeed);
  132. // TRACE("Move Weight %f\n", nWeight);
  133. }
  134. }
  135. // If the unit is turning, make them turn
  136. if (m_pUnit->m_lmUnit.GetDirectionsMatch() == false)
  137. {
  138. Matrix3 mtx3AngularMo;
  139. Vector3 vct3NewDirection;
  140. Vector3 vct3Base(0.0f, 0.0f, -1.0f);
  141. float nVectorAngle;
  142. float nOrigVectorAngle;
  143. float nNewVectorAngle;
  144. Vector2Ex vct2Direction(vct3Advance.x, -vct3Advance.z);
  145. if(!m_vctPath.empty() && 0 <= m_nPathIndex && m_nPathIndex < (int)m_vctPath.size())
  146. {
  147. m_pUnit->m_lmUnit.SetDesiredDirection(m_vctPath[m_nPathIndex] - ToAD_Vector3(vct3Current));
  148. }
  149. Vector2Ex vct2DesiredDirection(m_pUnit->m_lmUnit.m_vct3DesiredDirection.x, -m_pUnit->m_lmUnit.m_vct3DesiredDirection.z);
  150. float nAngularInc = 0;
  151. nAngularInc = (float(nElapse)) / 1000 * m_AngularSpeed;
  152. // Setup the vectors and normalize them
  153. vct2Direction.normalise();
  154. vct2DesiredDirection.normalise();
  155. // Get the angle between the two vectors
  156. nOrigVectorAngle = vct2DesiredDirection.GetAngleBetween(vct2Direction);
  157. // If the desired direction is clockwise to the current direction spin counter clockwise to rotate along shortest angle
  158. if (vct2Direction.GetIsClockwise(vct2DesiredDirection) == true)
  159. nOrigVectorAngle = -nOrigVectorAngle;
  160. // TRACE("Pre: nIndex %d Angle %f ", m_nPathIndex, nOrigVectorAngle);
  161. // Cap the maximum turn amount
  162. nVectorAngle = max(-m_MaxTurn, min(m_MaxTurn, nOrigVectorAngle * nAngularInc));
  163. // TRACE("Pst: nIndex %d Angle %f ", m_nPathIndex, nVectorAngle);
  164. // Setup the rotation
  165. mtx3AngularMo.FromAxisAngle(Vector3(0, 1, 0), (Radian)nVectorAngle);
  166. Matrix4 mtx4AngularMo(mtx3AngularMo);
  167. // Rotate the current direction
  168. vct3NewDirection = mtx4AngularMo * vct3Advance;
  169. vct2Direction.x = vct3NewDirection.x;
  170. vct2Direction.y = -vct3NewDirection.z;
  171. vct2Direction.normalise();
  172. // Test out the new angle to see if it is farther away to signify the rotation is complete
  173. nNewVectorAngle = vct2DesiredDirection.GetAngleBetween(vct2Direction);
  174. if (vct2Direction.GetIsClockwise(vct2DesiredDirection) == true)
  175. nNewVectorAngle = -nNewVectorAngle;
  176. // TRACE("Angle: Pre %f Post %f\n", nOrigVectorAngle, nNewVectorAngle);
  177. // if (nNewVectorAngle > nOrigVectorAngle)
  178. // Crossed zero, done turning
  179. if (fabsf(nOrigVectorAngle - nNewVectorAngle) > fabsf(nOrigVectorAngle))
  180. {
  181. vct3NewDirection = ToVector3(m_pUnit->m_lmUnit.m_vct3DesiredDirection);
  182. nNewVectorAngle = 0.0f;
  183. // TRACE("Cmp: %d\n", m_nPathIndex);
  184. }
  185. if(!m_vctPath.empty() && 0 <= m_nPathIndex && m_nPathIndex < (int)m_vctPath.size())
  186. {
  187. AD_Vector3 vec3Tmp = m_vctPath[m_nPathIndex] - ToAD_Vector3(vct3Current);
  188. if (ToVector3(vec3Tmp).length() < 10) //
  189. {
  190. vct3NewDirection = ToVector3(vec3Tmp);
  191. }
  192. }
  193. // Set the current direction
  194. m_pUnit->SetDirection(ToAD_Vector3(vct3NewDirection));
  195. // Stop if turn is completed (ie we turned less than the max)
  196. if (nNewVectorAngle == 0.0f)
  197. {
  198. m_pUnit->m_lmUnit.SetDirectionsMatch(false);
  199. }
  200. }
  201. // Find out why statement below is needed, needed for when a scene is switched
  202. if (m_pUnit->GetVelocity() > 0 && m_nPathIndex + 1 <= (int)m_vctPath.size())
  203. {
  204. Real nInc = (float(nElapse)) / 1000 * (m_pUnit->GetVelocity() * m_MaxSpeed);
  205. // TRACE("TimePos: %f\n", pAnimationState->getTimePosition());
  206. vct3Position = ToVector3(m_pUnit->GetPosition());
  207. // Get Current distance to next waypoint
  208. vct3CurrentDiff.x = m_vctPath[m_nPathIndex].x - vct3Position.x;
  209. vct3CurrentDiff.y = m_vctPath[m_nPathIndex].y - vct3Position.y;
  210. vct3CurrentDiff.z = m_vctPath[m_nPathIndex].z - vct3Position.z;
  211. nCurrDiff = vct3CurrentDiff.squaredLength();
  212. // Advance the character
  213. vct3Position = vct3Current + vct3Advance * nInc;
  214. if (!pScene->GetTilingGrid().GetIsBlockPosition(ToAD_Vector3(vct3Position)))
  215. {
  216. m_pUnit->SetPosition(ToAD_Vector3(vct3Position));
  217. }
  218. else if (!pScene->GetIsValidPosition(ToAD_Vector3(vct3Position)))
  219. {
  220. TilingGrid & tg = pScene->GetTilingGrid();
  221. int width = tg.GetGridWidth();
  222. int depth = tg.GetGridDepth();
  223. const float diff = 0.1f;
  224. if (vct3Position.x <= 0.0)
  225. {
  226. vct3Position.x = 0.0 + diff;
  227. }
  228. else if (vct3Position.x >= width)
  229. {
  230. vct3Position.x = width - diff;
  231. }
  232. if (vct3Position.z <= 0.0)
  233. {
  234. vct3Position.z = 0.0 + diff;
  235. }
  236. else if (vct3Position.z >= depth)
  237. {
  238. vct3Position.z = depth - diff;
  239. }
  240. }
  241. else if (pScene->GetTilingGrid().GetIsBlockPosition(ToAD_Vector3(vct3Position)))
  242. {
  243. TilingGrid & tg = pScene->GetTilingGrid();
  244. float width = tg.GetTileWidth();
  245. float depth = tg.GetTileDepth();
  246. TilePos nTileX_old;
  247. TilePos nTileZ_old;
  248. tg.GridPixelsToTilePosition(m_pUnit->GetPosition(), nTileX_old, nTileZ_old);
  249. TilePos nTileX_new;
  250. TilePos nTileZ_new;
  251. tg.GridPixelsToTilePosition(ToAD_Vector3(vct3Position), nTileX_new, nTileZ_new);
  252. if ((int)nTileX_old-(int)nTileX_new > 1 ||
  253. (int)nTileX_old-(int)nTileX_new < -1 ||
  254. (int)nTileZ_old-(int)nTileZ_new > 1 ||
  255. (int)nTileZ_old-(int)nTileZ_new < -1)
  256. {
  257. AD_WARN("ERROR!! Move over 1 tile next frame\n");
  258. }
  259. else
  260. {
  261. Vector3 adjust = vct3Position;
  262. if (tg.GetIsBlockPt((int)nTileX_new,(int)nTileZ_old))
  263. {
  264. int x = (int)nTileX_old>(int)nTileX_new?(int)nTileX_old:(int)nTileX_new;
  265. adjust.x = x*tg.GetTileWidth();
  266. adjust.x += (int)nTileX_old>(int)nTileX_new?0.1:-0.1;
  267. }
  268. if (tg.GetIsBlockPt((int)nTileX_old,(int)nTileZ_new))
  269. {
  270. int z = (int)nTileZ_old>(int)nTileZ_new?(int)nTileZ_old:(int)nTileZ_new;
  271. adjust.z = z*tg.GetTileDepth();
  272. adjust.z += (int)nTileZ_old>(int)nTileZ_new?0.1:-0.1;
  273. }
  274. vct3Position = adjust;
  275. }
  276. }
  277. if (pScene->GetIsValidPosition(ToAD_Vector3(vct3Position)) &&
  278. !pScene->GetTilingGrid().GetIsBlockPosition(ToAD_Vector3(vct3Position)))
  279. {
  280. m_pUnit->SetPosition(ToAD_Vector3(vct3Position));
  281. }
  282. //Move chat bubble.
  283. MoveChatBubble();
  284. // m_pScene->GetTilingGrid().GetGridYPositionInPixels(vct3Position.x, vct3Position.z, vct3Position.y);
  285. // Get new distance to way
  286. vct3DiffToNextPt.x = m_vctPath[m_nPathIndex].x - vct3Position.x;
  287. vct3DiffToNextPt.y = m_vctPath[m_nPathIndex].y - vct3Position.y;
  288. vct3DiffToNextPt.z = m_vctPath[m_nPathIndex].z - vct3Position.z;
  289. nNewDiff = vct3DiffToNextPt.squaredLength();
  290. // TRACE("Index %d/%d Curr %f Diff %f\n", m_nPathIndex, m_vctPath.size(), nCurrDiff, nNewDiff);
  291. // TRACE(" CX %f CY %f CZ %f NX %f NY %f NZ %f\n", vct3Position.x, vct3Position.y, vct3Position.z, m_vctPath[m_nPathIndex].x, m_vctPath[m_nPathIndex].y, m_vctPath[m_nPathIndex].z);
  292. Vector3 vct3ToEnd;
  293. int vectorSize = m_vctPath.size();
  294. vct3ToEnd.x = m_vctPath[vectorSize-1].x - vct3Position.x;
  295. vct3ToEnd.y = m_vctPath[vectorSize-1].y - vct3Position.y;
  296. vct3ToEnd.z = m_vctPath[vectorSize-1].z - vct3Position.z;
  297. Real nToEndDiff = vct3ToEnd.squaredLength();
  298. Real SlowDownLength = 1*pScene->GetTileDepth();
  299. if (nToEndDiff < SlowDownLength*SlowDownLength)
  300. {
  301. m_pUnit->SetVelocity(0.5);
  302. }
  303. // Get ready to stop
  304. if (nNewDiff < 1.40f || (vct3CurrentDiff.dotProduct(vct3DiffToNextPt) < 0.0f)) // && nNewDiff < 1000.0f))
  305. {
  306. // If at the end, stop
  307. if (m_nPathIndex + 1 >= (int)m_vctPath.size())
  308. {
  309. m_pUnit->SetVelocity(0.0f);
  310. m_nAcceleration = 0.0f;
  311. OnMoveStop(true);
  312. m_vctPath.clear();
  313. }
  314. else
  315. {
  316. if (m_nPathIndex + 1 < (int)m_vctPath.size())
  317. {
  318. m_nPathIndex++;
  319. SetDesiredUnitOrientation(ToVector3(m_pUnit->GetPosition()), ToVector3(m_vctPath[m_nPathIndex]));
  320. }
  321. }
  322. }
  323. }
  324. }
  325. return true;
  326. }
  327. void Move::OnHook(GeneEvt& evt)
  328. {
  329. if (m_pUnit->GetMoveState()!=UnitBase::ums_Freeze)
  330. {
  331. if (evt.GetID()==UGE_Move)
  332. {
  333. TilePos fX = evt.GetArgX()/1000;
  334. TilePos fY = evt.GetArgY()/1000;
  335. if (!m_bWalkOnly && m_nCurMoveType != evt.GetArgZ())
  336. {
  337. m_nCurMoveType = evt.GetArgZ();
  338. int nNewID = m_pStaticData->GetArg(AT_LinkToMove+m_nCurMoveType);
  339. static IStaticDataLoader* s_geneLoader = NULL;
  340. if (s_geneLoader==NULL)
  341. {
  342. s_geneLoader = g_StaticDataFactory->GetLoader(StaticUnitGene::category);
  343. }
  344. if (s_geneLoader)
  345. {
  346. StaticUnitGene* pNewSD = dynamic_cast<StaticUnitGene*>(s_geneLoader->Get(nNewID));
  347. if (pNewSD)
  348. {
  349. OnCreate(pNewSD);
  350. }
  351. }
  352. }
  353. DeterminePath(fX, fY);
  354. }
  355. }
  356. if ( UGE_Stop == evt.GetID() )
  357. {
  358. m_vctPath.clear();
  359. m_nPathIndex = 0;
  360. if (evt.GetArgX()!=0)
  361. {
  362. //
  363. // this is a stop that will freeze current unit
  364. // unit in freeze mode can't move to other place
  365. //
  366. OnMoveStop(true, true);
  367. }
  368. else
  369. {
  370. OnMoveStop();
  371. }
  372. }
  373. }
  374. bool Move::DeterminePath(TilePos nXDest, TilePos nZDest)//Scene* pScene, TilePos nXDest, TilePos nZDest, DWORD nTick)
  375. {
  376. if(NULL == m_pUnit)
  377. return false;
  378. Scene * pScene = m_pUnit->GetScene();
  379. m_nPathIndex = 0;
  380. bool ret = false;
  381. if (m_pUnit && pScene != NULL)
  382. {
  383. //ScenePath spUnit(pScene);
  384. TilePos nXStart;
  385. TilePos nZStart;
  386. Vector3 vct3Grid;
  387. Vector3 vctPrevious;
  388. CPoint ptGrid;
  389. m_pUnit->GetTilePosition(nXStart, nZStart);
  390. if ((int)nXStart == (int)nXDest &&
  391. (int)nZStart == (int)nZDest)
  392. {
  393. return false;
  394. }
  395. m_nAcceleration = 1.0f;
  396. m_vctPath.clear();
  397. AStartPath AstartPath(pScene);
  398. AstartPath.GetPath(m_vctPath, CPoint(nXStart, nZStart), CPoint(nXDest, nZDest));
  399. m_nPathIndex = 1;
  400. // If a path convert to real pixels
  401. if (m_vctPath.size() > 0)
  402. {
  403. if (m_vctPath.size() >= 2)
  404. {
  405. SetDesiredUnitOrientation(ToVector3(m_vctPath[0]), ToVector3(m_vctPath[1]));
  406. }
  407. if (m_Target.x > 0.0 && m_Target.z > 0.0)//m_Target has been set
  408. {
  409. vctPrevious = ToVector3(m_vctPath[m_vctPath.size()-1]);
  410. pScene->GetTilingGrid().GridToPixels(m_Target.x, m_Target.z, ToAD_Vector3(vct3Grid));
  411. float dx = vct3Grid.x - vctPrevious.x;
  412. float dz = vct3Grid.z - vctPrevious.z;
  413. if (dx<pScene->GetTileWidth() && dx>0.0 && dz<pScene->GetTileDepth() && dz>0.0)
  414. {
  415. m_vctPath[m_vctPath.size()-1] = ToAD_Vector3(vct3Grid);
  416. }
  417. }
  418. m_pUnit->m_lmUnit.SetDirectionsMatch(false);
  419. ret = true;
  420. OnMoveStart();
  421. }
  422. else
  423. {
  424. OnMoveStop();
  425. }
  426. }
  427. else
  428. {
  429. ret = false;
  430. }
  431. return ret;
  432. }
  433. /**
  434. * Sets the orientation so the unit faces the next position
  435. *
  436. * @param vct3Position Reference or current position
  437. * @param vct3NextPosition Next position
  438. */
  439. bool Move::SetDesiredUnitOrientation(const Vector3& vct3Position, const Vector3& vct3NextPosition)
  440. {
  441. Vector3 vct3DesiredDir(vct3NextPosition.x - vct3Position.x, vct3NextPosition.y - vct3Position.y, vct3NextPosition.z - vct3Position.z);
  442. Vector3 vct3Dir;
  443. m_pUnit->m_lmUnit.SetDesiredDirection(ToAD_Vector3(vct3DesiredDir));
  444. // Get current direction and see if they match
  445. vct3Dir = ToVector3(m_pUnit->m_lmUnit.m_vct3Direction);
  446. vct3DesiredDir.normalise();
  447. vct3Dir.normalise();
  448. // find angle between
  449. float nAngle = vct3DesiredDir.dotProduct(vct3Dir);
  450. // 1 is parallel, so give some play
  451. if (vct3DesiredDir.dotProduct(vct3Dir) < ALLOW_ANGLE_PLAY)
  452. m_pUnit->m_lmUnit.SetDirectionsMatch(false);
  453. else
  454. m_pUnit->m_lmUnit.SetDirectionsMatch(false);
  455. return m_pUnit->m_lmUnit.GetDirectionsMatch();
  456. }
  457. void Move::MoveChatBubble()
  458. {
  459. UnitRole* pRole = dynamic_cast<UnitRole*>(m_pUnit);
  460. if(NULL == pRole)
  461. {
  462. return ;
  463. }
  464. Scene* pScene = pRole->GetScene();
  465. //Change the position to screen from world.
  466. ControlWorld2Screen w2s;
  467. ObsEvtDefault evt(Ob_Evt_Control_GetCeilingCenter, &w2s.vctWorld);
  468. pRole->Changed(evt);
  469. ObsEvtDefault evtX(Ob_Evt_Control_World2Screen, &w2s);
  470. pScene->Changed(evtX);
  471. //Move chat bubble.
  472. ChatBubbleInfo infoData(ChatBubbleInfo::BubbleType_NormalPlayer);
  473. infoData.m_uiRoleId = pRole->GetRoleID();
  474. infoData.m_nX = WINDOW_WIDTH_NORMAL*(w2s.vctScreen.x);
  475. infoData.m_nY = WINDOW_HEIGHT_NORMAL*(w2s.vctScreen.y);
  476. CMsgMoveChatBubble msgMove;
  477. msgMove.m_pChatInfo = &infoData;
  478. pScene->GetInputDevice()->Send(&msgMove);
  479. }
  480. void Move::SetMaxSpeed(float maxSpeed)
  481. {
  482. m_MaxSpeed = maxSpeed;
  483. }
  484. float Move::GetMaxSpeed()
  485. {
  486. return m_MaxSpeed;
  487. }
  488. void Move::OnMoveStart()
  489. {
  490. m_nPrevMoveState = UnitBase::ums_Moving;
  491. m_pUnit->SetMoveState(m_nPrevMoveState);
  492. ObsEvtUSC evt(m_pStaticData->GetArg(AT_MoveState, 2));
  493. m_pUnit->Changed(evt);
  494. }
  495. void Move::OnMoveStop(bool bEndPathing /* = false */, bool bIsFreeze /* = false */)
  496. {
  497. if( NULL == m_pUnit ) return;
  498. m_Target.x = -1.0;
  499. m_Target.y = -1.0;
  500. m_Target.z = -1.0;
  501. m_pUnit->SetVelocity(0.0f);
  502. if (bEndPathing)
  503. {
  504. CMsgMoveUnit mumBeginPathing((UnitBase*)m_pUnit);
  505. mumBeginPathing.m_eMoveStateType = CMsgMoveUnit::MST_ENDPATHING;
  506. m_pUnit->GetScene()->GetInputDevice()->Send(&mumBeginPathing);
  507. }
  508. if (!bIsFreeze)
  509. {
  510. m_nPrevMoveState = UnitBase::ums_Idle;
  511. m_pUnit->SetMoveState(m_nPrevMoveState);
  512. }
  513. else
  514. {
  515. m_nPrevMoveState = UnitBase::ums_Freeze;
  516. m_pUnit->SetMoveState(m_nPrevMoveState);
  517. }
  518. ObsEvtUSC evt(m_pStaticData->GetArg(AT_StopState, 1));
  519. m_pUnit->Changed(evt);
  520. }
  521. void Move::SetMaxTurn(float maxTurn)
  522. {
  523. m_MaxTurn = maxTurn;
  524. }
  525. float Move::GetMaxTurn()
  526. {
  527. return m_MaxTurn;
  528. }
  529. void Move::SetAngularSpeed(float angularSpeed)
  530. {
  531. m_AngularSpeed = angularSpeed;
  532. }
  533. float Move::GetAngularSpeed()
  534. {
  535. return m_AngularSpeed;
  536. }