Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

721 lines
16 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "stdafx.h"
  8. #include "MapPath.h"
  9. #include "hammer.h"
  10. #include "EditPathDlg.h"
  11. #include "MapEntity.h"
  12. // memdbgon must be the last include file in a .cpp file!!!
  13. #include <tier0/memdbgon.h>
  14. float GetFileVersion(void);
  15. //-----------------------------------------------------------------------------
  16. // Purpose:
  17. //-----------------------------------------------------------------------------
  18. CMapPath::CMapPath(void)
  19. {
  20. m_iDirection = dirOneway;
  21. SetName("");
  22. SetClass("path_corner");
  23. }
  24. //-----------------------------------------------------------------------------
  25. // Purpose:
  26. //-----------------------------------------------------------------------------
  27. CMapPath::~CMapPath(void)
  28. {
  29. }
  30. //-----------------------------------------------------------------------------
  31. // Purpose:
  32. //-----------------------------------------------------------------------------
  33. CMapPathNode::CMapPathNode(void)
  34. {
  35. bSelected = FALSE;
  36. szName[0] = 0;
  37. }
  38. CMapPathNode::CMapPathNode(const CMapPathNode& src)
  39. {
  40. *this = src;
  41. }
  42. //-----------------------------------------------------------------------------
  43. // Purpose:
  44. // Input : src -
  45. // Output : CMapPathNode
  46. //-----------------------------------------------------------------------------
  47. CMapPathNode &CMapPathNode::operator=(const CMapPathNode &src)
  48. {
  49. // we don't care.
  50. Q_strncpy( szName, src.szName, sizeof(szName) );
  51. bSelected = src.bSelected;
  52. kv.RemoveAll();
  53. for ( int i=src.kv.GetFirst(); i != src.kv.GetInvalidIndex(); i=src.kv.GetNext( i ) )
  54. {
  55. MDkeyvalue KeyValue = src.kv.GetKeyValue(i);
  56. kv.SetValue(KeyValue.szKey, KeyValue.szValue);
  57. }
  58. pos = src.pos;
  59. dwID = src.dwID;
  60. return *this;
  61. }
  62. //-----------------------------------------------------------------------------
  63. // Purpose:
  64. // Input : dwID -
  65. // piIndex -
  66. // Output : CMapPathNode *
  67. //-----------------------------------------------------------------------------
  68. CMapPathNode *CMapPath::NodeForID(DWORD dwID, int* piIndex)
  69. {
  70. for(int iNode = 0; iNode < m_Nodes.Count(); iNode++)
  71. {
  72. if(m_Nodes[iNode].dwID == dwID)
  73. {
  74. if(piIndex)
  75. piIndex[0] = iNode;
  76. return &m_Nodes[iNode];
  77. }
  78. }
  79. return NULL;
  80. }
  81. //-----------------------------------------------------------------------------
  82. // Purpose:
  83. // Output : DWORD
  84. //-----------------------------------------------------------------------------
  85. DWORD CMapPath::GetNewNodeID(void)
  86. {
  87. DWORD dwNewID = 1;
  88. while(true)
  89. {
  90. int iNode;
  91. for(iNode = 0; iNode < m_Nodes.Count(); iNode++)
  92. {
  93. if(m_Nodes[iNode].dwID == dwNewID)
  94. break;
  95. }
  96. if(iNode == m_Nodes.Count())
  97. return dwNewID;
  98. ++dwNewID;
  99. }
  100. }
  101. //-----------------------------------------------------------------------------
  102. // Purpose:
  103. // Input : dwAfterID -
  104. // vecPos -
  105. // Output :
  106. //-----------------------------------------------------------------------------
  107. DWORD CMapPath::AddNode(DWORD dwAfterID, const Vector &vecPos)
  108. {
  109. int iPos;
  110. if(dwAfterID == ADD_START)
  111. iPos = 0;
  112. else if(dwAfterID == ADD_END)
  113. iPos = m_Nodes.Count();
  114. else if(!NodeForID(dwAfterID, &iPos))
  115. return 0; // not found!
  116. CMapPathNode node;
  117. node.pos = vecPos;
  118. node.bSelected = FALSE;
  119. node.dwID = GetNewNodeID();
  120. if(iPos == m_Nodes.Count())
  121. {
  122. // add at tail
  123. m_Nodes.AddToTail(node);
  124. }
  125. else
  126. {
  127. m_Nodes.InsertBefore( iPos, node );
  128. }
  129. return node.dwID;
  130. }
  131. //-----------------------------------------------------------------------------
  132. // Purpose:
  133. // Input : dwID -
  134. // *pt -
  135. //-----------------------------------------------------------------------------
  136. void CMapPath::SetNodePosition(DWORD dwID, Vector& pt)
  137. {
  138. int iIndex;
  139. NodeForID(dwID, &iIndex);
  140. m_Nodes[iIndex].pos = pt;
  141. }
  142. //-----------------------------------------------------------------------------
  143. // Purpose:
  144. // Input : dwID -
  145. //-----------------------------------------------------------------------------
  146. void CMapPath::DeleteNode(DWORD dwID)
  147. {
  148. int iIndex;
  149. if ( NodeForID(dwID, &iIndex) )
  150. {
  151. m_Nodes.Remove(iIndex);
  152. }
  153. }
  154. //-----------------------------------------------------------------------------
  155. // Purpose:
  156. // Input : file -
  157. // fIsStoring -
  158. //-----------------------------------------------------------------------------
  159. void CMapPath::SerializeRMF(std::fstream& file, BOOL fIsStoring)
  160. {
  161. int iSize;
  162. if(fIsStoring)
  163. {
  164. // save!!
  165. file.write(m_szName, 128);
  166. file.write(m_szClass, 128);
  167. file.write((char*) &m_iDirection, sizeof(m_iDirection));
  168. iSize = m_Nodes.Count();
  169. file.write((char*) &iSize, sizeof iSize);
  170. for(int i = 0; i < m_Nodes.Count(); i++)
  171. {
  172. CMapPathNode& node = m_Nodes[i];
  173. // store each node
  174. file.write((char*) &node.pos[0], 3 * sizeof(float));
  175. file.write((char*) &node.dwID, sizeof(node.dwID));
  176. file.write((char*) &node.szName, sizeof(node.szName));
  177. //
  178. // Write keyvalue count.
  179. //
  180. WCKeyValues &kv = node.kv;
  181. iSize = 0;
  182. for ( int z=kv.GetFirst(); z != kv.GetInvalidIndex(); z=kv.GetNext( z ) )
  183. {
  184. ++iSize;
  185. }
  186. file.write((char*) &iSize, sizeof(iSize));
  187. //
  188. // Write keyvalues.
  189. //
  190. for (int k = kv.GetFirst(); k != kv.GetInvalidIndex(); k=kv.GetNext( k ) )
  191. {
  192. MDkeyvalue &KeyValue = kv.GetKeyValue(k);
  193. if (KeyValue.szKey[0] != '\0')
  194. {
  195. KeyValue.SerializeRMF(file, TRUE);
  196. }
  197. }
  198. }
  199. }
  200. else
  201. {
  202. // load!!
  203. file.read(m_szName, 128);
  204. file.read(m_szClass, 128);
  205. file.read((char*) &m_iDirection, sizeof m_iDirection);
  206. file.read((char*) &iSize, sizeof iSize);
  207. int nNodes = iSize;
  208. m_Nodes.RemoveAll();
  209. // read nodes
  210. for(int i = 0; i < nNodes; i++)
  211. {
  212. CMapPathNode node;
  213. // store each node
  214. file.read((char*) &node.pos[0], 3 * sizeof(float));
  215. file.read((char*) &node.dwID, sizeof(node.dwID));
  216. if(GetFileVersion() >= 1.6f)
  217. {
  218. file.read((char*) &node.szName, sizeof(node.szName));
  219. // read keyvalues
  220. file.read((char*) &iSize, sizeof(iSize));
  221. WCKeyValues &kv = node.kv;
  222. for (int k = 0; k < iSize; k++)
  223. {
  224. MDkeyvalue KeyValue;
  225. KeyValue.SerializeRMF(file, FALSE);
  226. kv.SetValue( KeyValue.szKey, KeyValue.szValue );
  227. }
  228. }
  229. m_Nodes.AddToTail(node);
  230. }
  231. }
  232. }
  233. //-----------------------------------------------------------------------------
  234. // Purpose:
  235. // Input : iIndex -
  236. // iName -
  237. // str -
  238. //-----------------------------------------------------------------------------
  239. void CMapPath::GetNodeName(int iIndex, int iName, CString& str)
  240. {
  241. if(m_Nodes[iIndex].szName[0])
  242. str = m_Nodes[iIndex].szName;
  243. else
  244. {
  245. if(iName)
  246. str.Format("%s%02d", m_szName, iName);
  247. else
  248. str = m_szName;
  249. }
  250. }
  251. //-----------------------------------------------------------------------------
  252. // Purpose:
  253. // Input : file -
  254. // fIsStoring -
  255. // *pIntersecting -
  256. //-----------------------------------------------------------------------------
  257. void CMapPath::SerializeMAP(std::fstream& file, BOOL fIsStoring, BoundBox *pIntersecting)
  258. {
  259. if( m_Nodes.Count() == 0)
  260. return;
  261. // if saving WITHIN a box, check all nodes to see if they all
  262. // fit within that box. if not, don't save ANY of the path.
  263. if(pIntersecting)
  264. {
  265. for(int i = 0; i < m_Nodes.Count(); i++)
  266. {
  267. if (!pIntersecting->ContainsPoint(m_Nodes[i].pos))
  268. {
  269. return; // doesn't intersect - don't save path
  270. }
  271. }
  272. }
  273. Assert(fIsStoring);
  274. CString strTemp;
  275. MDkeyvalue kvTemp;
  276. // initialize nodes for saving
  277. for(int i = 0; i < m_Nodes.Count(); i++)
  278. {
  279. m_Nodes[i].nTargets = 0;
  280. }
  281. int iDirec = 1;
  282. int iCurNode = 0;
  283. int iMax = m_Nodes.Count()-1;
  284. int iName = 0;
  285. // resolve targets
  286. int iLastNodeIndex = -1;
  287. BOOL bFirstPass = TRUE;
  288. ResolveNamesAgain:
  289. while(1)
  290. {
  291. // store targetname
  292. GetNodeName(iCurNode, iName, strTemp);
  293. // store our name in the previous node (if not -1)
  294. if(iLastNodeIndex != -1)
  295. {
  296. CMapPathNode &prevNode = m_Nodes[iLastNodeIndex];
  297. strcpy(prevNode.szTargets[prevNode.nTargets++], strTemp);
  298. }
  299. ++iName;
  300. iLastNodeIndex = iCurNode;
  301. if(iCurNode == iMax)
  302. break;
  303. iCurNode += iDirec;
  304. }
  305. if(bFirstPass && m_iDirection == dirPingpong && m_Nodes.Count() > 2)
  306. {
  307. // redo loop
  308. bFirstPass = FALSE;
  309. iDirec = -1;
  310. iCurNode = m_Nodes.Count()-2;
  311. iMax = 0;
  312. goto ResolveNamesAgain;
  313. }
  314. else if (m_iDirection == dirCircular)
  315. {
  316. //
  317. // Connect the last node to the first node.
  318. //
  319. CMapPathNode &LastNode = m_Nodes[iMax];
  320. GetNodeName(iCurNode, 0, strTemp);
  321. strcpy(LastNode.szTargets[LastNode.nTargets], strTemp);
  322. LastNode.nTargets++;
  323. }
  324. iDirec = 1;
  325. iCurNode = 0;
  326. iMax = m_Nodes.Count()-1;
  327. iName = 0;
  328. SaveAgain:
  329. while(1)
  330. {
  331. file << "{" << "\r\n";
  332. // store name
  333. kvTemp.Set("classname", m_szClass);
  334. kvTemp.SerializeMAP(file, TRUE);
  335. CMapPathNode &node = m_Nodes[iCurNode];
  336. // store location
  337. strTemp.Format("%.0f %.0f %.0f", node.pos[0], node.pos[1],
  338. node.pos[2]);
  339. kvTemp.Set("origin", strTemp);
  340. kvTemp.SerializeMAP(file, TRUE);
  341. // store targetname
  342. GetNodeName(iCurNode, iName, strTemp);
  343. kvTemp.Set("targetname", strTemp);
  344. kvTemp.SerializeMAP(file, TRUE);
  345. // store target (if not last)
  346. BOOL bStoreTarget = TRUE;
  347. if(iCurNode == iMax && m_iDirection == dirOneway)
  348. bStoreTarget = FALSE;
  349. if (bStoreTarget)
  350. {
  351. kvTemp.Set("target", (iDirec == 1) ? node.szTargets[0] : node.szTargets[1]);
  352. kvTemp.SerializeMAP(file, TRUE);
  353. }
  354. // other keyvalues
  355. WCKeyValues &kv = node.kv;
  356. for (int k = kv.GetFirst(); k != kv.GetInvalidIndex(); k=kv.GetNext( k ) )
  357. {
  358. MDkeyvalue &KeyValue = kv.GetKeyValue(k);
  359. if (KeyValue.szKey[0] != '\0')
  360. {
  361. KeyValue.SerializeMAP(file, TRUE);
  362. }
  363. }
  364. file << "}" << "\r\n";
  365. ++iName;
  366. iLastNodeIndex = iCurNode;
  367. if(iCurNode == iMax)
  368. break;
  369. iCurNode += iDirec;
  370. }
  371. if(iDirec == 1 && m_iDirection == dirPingpong && m_Nodes.Count() > 2)
  372. {
  373. // redo loop
  374. iDirec = -1;
  375. iCurNode = m_Nodes.Count()-2;
  376. iMax = 1;
  377. goto SaveAgain;
  378. }
  379. }
  380. // Edit
  381. void CMapPath::EditInfo()
  382. {
  383. CEditPathDlg dlg;
  384. dlg.m_strName = m_szName;
  385. dlg.m_strClass = m_szClass;
  386. dlg.m_iDirection = m_iDirection;
  387. if(dlg.DoModal() != IDOK)
  388. return;
  389. SetName(dlg.m_strName);
  390. SetClass(dlg.m_strClass);
  391. m_iDirection = dlg.m_iDirection;
  392. }
  393. //-----------------------------------------------------------------------------
  394. // Purpose:
  395. // Input : dwNodeID -
  396. // Output : CMapEntity *
  397. //-----------------------------------------------------------------------------
  398. CMapEntity *CMapPath::CreateEntityForNode(DWORD dwNodeID)
  399. {
  400. int iIndex;
  401. CMapPathNode *pNode = NodeForID(dwNodeID, &iIndex);
  402. if (pNode == NULL)
  403. {
  404. return NULL; // no node, no entity!
  405. }
  406. CMapEntity *pEntity = new CMapEntity;
  407. for (int k = pNode->kv.GetFirst(); k != pNode->kv.GetInvalidIndex(); k=pNode->kv.GetNext( k ) )
  408. {
  409. pEntity->SetKeyValue(pNode->kv.GetKey(k), pNode->kv.GetValue(k));
  410. }
  411. // store target/targetname properties:
  412. CString str;
  413. str.Format("%s%02d", m_szName, iIndex);
  414. pEntity->SetKeyValue("targetname", str);
  415. int iNext = iIndex + 1;
  416. if(iNext != -1)
  417. {
  418. str.Format("%s%02d", m_szName, iNext);
  419. pEntity->SetKeyValue("target", str);
  420. }
  421. pEntity->SetClass(m_szClass);
  422. return pEntity;
  423. }
  424. //-----------------------------------------------------------------------------
  425. // Purpose:
  426. // Input : dwNodeID -
  427. // *pEntity -
  428. //-----------------------------------------------------------------------------
  429. void CMapPath::CopyNodeFromEntity(DWORD dwNodeID, CMapEntity *pEntity)
  430. {
  431. CMapPathNode *pNode = NodeForID(dwNodeID);
  432. if (!pNode)
  433. {
  434. return; // no node, no copy!
  435. }
  436. pNode->kv.RemoveAll();
  437. //
  438. // Copy all the keys except target and targetname from the entity to the pathnode.
  439. //
  440. for ( int i=pEntity->GetFirstKeyValue(); i != pEntity->GetInvalidKeyValue(); i=pEntity->GetNextKeyValue( i ) )
  441. {
  442. if (!strcmp(pEntity->GetKey(i), "target") || !strcmp(pEntity->GetKey(i), "targetname"))
  443. {
  444. continue;
  445. }
  446. pNode->kv.SetValue(pEntity->GetKey(i), pEntity->GetKeyValue(i));
  447. }
  448. }
  449. /*
  450. //-----------------------------------------------------------------------------
  451. // Purpose:
  452. // Input : *szKey -
  453. // *szValue -
  454. // *pNode -
  455. // Output : CChunkFileResult_t
  456. //-----------------------------------------------------------------------------
  457. UNDONE: Nobody uses the path tool because the user interface is so poor.
  458. Path support has been pulled until the tool itself can be fixed or replaced.
  459. CChunkFileResult_t CMapPathNode::LoadKeyCallback(const char *szKey, const char *szValue, CMapPathNode *pNode)
  460. {
  461. if (!stricmp(szKey, "origin"))
  462. {
  463. CChunkFile::ReadKeyValueVector3(szValue, pNode->pos);
  464. }
  465. else if (!stricmp(szKey, "id"))
  466. {
  467. CChunkFile::ReadKeyValueInt(szValue, &pNode->dwID);
  468. }
  469. else if (!stricmp(szKey, "name"))
  470. {
  471. strcpy(pNode->szName, szValue);
  472. }
  473. }
  474. //-----------------------------------------------------------------------------
  475. // Purpose:
  476. // Input : *pFile -
  477. // Output : ChunkFileResult_t
  478. //-----------------------------------------------------------------------------
  479. ChunkFileResult_t CMapPathNode::SaveVMF(CChunkFile *pFile, CSaveInfo *pSaveInfo)
  480. {
  481. ChunkFileResult_t eResult = pFile->BeginChunk("node");
  482. if (eResult == ChunkFile_Ok)
  483. {
  484. eResult = pFile->WriteKeyValueVector3("origin", node.pos);
  485. }
  486. if (eResult == ChunkFile_Ok)
  487. {
  488. eResult = pFile->WriteKeyValueInt("id", node.dwID);
  489. }
  490. if (eResult == ChunkFile_Ok)
  491. {
  492. eResult = pFile->WriteKeyValue("name", node.szName);
  493. }
  494. if (eResult == ChunkFile_Ok)
  495. {
  496. eResult = pFile->BeginChunk("keys");
  497. }
  498. //
  499. // Write keyvalues.
  500. //
  501. if (eResult == ChunkFile_Ok)
  502. {
  503. iSize = kv.GetCount();
  504. for (int k = 0; k < iSize; k++)
  505. {
  506. MDkeyvalue &KeyValue = kv.GetKeyValue(k);
  507. if (eResult == ChunkFile_Ok)
  508. {
  509. eResult = pFile->WriteKeyValue(KeyValue.GetKey(), KeyValue.GetValue());
  510. }
  511. }
  512. }
  513. // End the keys chunk.
  514. if (eResult == ChunkFile_Ok)
  515. {
  516. eResult = pFile->EndChunk();
  517. }
  518. // End the node chunk.
  519. if (eResult == ChunkFile_Ok)
  520. {
  521. eResult = pFile->EndChunk();
  522. }
  523. return(eResult);
  524. }
  525. //-----------------------------------------------------------------------------
  526. // Purpose:
  527. // Input : *szKey -
  528. // *szValue -
  529. // *pPath -
  530. // Output : CChunkFileResult_t
  531. //-----------------------------------------------------------------------------
  532. CChunkFileResult_t CMapPath::LoadKeyCallback(const char *szKey, const char *szValue, CMapPath *pPath)
  533. {
  534. if (!stricmp(szKey, "name"))
  535. {
  536. pPath->SetName(szValue);
  537. }
  538. else if (!stricmp(szKey, "classname"))
  539. {
  540. pPath->SetClass(szValue);
  541. }
  542. else if (!stricmp(szKey, "direction"))
  543. {
  544. CChunkFile::ReadKeyValueInt(szValue, &pPath->m_iDirection);
  545. }
  546. }
  547. //-----------------------------------------------------------------------------
  548. // Purpose:
  549. // Input : *pFile -
  550. //-----------------------------------------------------------------------------
  551. void CMapPath::LoadVMF(CChunkFile *pFile)
  552. {
  553. file.read((char*) &iSize, sizeof iSize);
  554. m_nNodes = iSize;
  555. m_Nodes.SetSize(m_nNodes);
  556. // read nodes
  557. for (int i = 0; i < m_nNodes; i++)
  558. {
  559. CMapPathNode &node = m_Nodes[i];
  560. // read keyvalues
  561. file.read((char*) &iSize, sizeof(iSize));
  562. KeyValues &kv = node.kv;
  563. kv.SetSize(iSize);
  564. for (int k = 0; k < iSize; k++)
  565. {
  566. MDkeyvalue &KeyValue = kv.GetKeyValue(k);
  567. KeyValue.SerializeRMF(file, FALSE);
  568. }
  569. }
  570. }
  571. }
  572. //-----------------------------------------------------------------------------
  573. // Purpose:
  574. // Input : *pFile -
  575. //-----------------------------------------------------------------------------
  576. void CMapPath::SaveVMF(CChunkFile *pFile, CSaveInfo *pSaveInfo)
  577. {
  578. int iSize;
  579. ChunkFileResult_t eResult = pFile->BeginChunk("path");
  580. if (eResult == ChunkFile_Ok)
  581. {
  582. eResult = pFile-WriteKeyValue("name", m_szName);
  583. }
  584. if (eResult == ChunkFile_Ok)
  585. {
  586. eResult = pFile->WriteKeyValue("classname", m_szClass);
  587. }
  588. if (eResult == ChunkFile_Ok)
  589. {
  590. eResult = pFile->WriteKeyValueInt("direction", m_iDirection);
  591. }
  592. if (eResult == ChunkFile_Ok)
  593. {
  594. for (int i = 0; i < m_nNodes; i++)
  595. {
  596. CMapPathNode &node = m_Nodes[i];
  597. eResult = node.SaveVMF(pFile, pSaveInfo);
  598. }
  599. }
  600. if (eResult == ChunkFile_Ok)
  601. {
  602. eResult = pFile->EndChunk();
  603. }
  604. }
  605. */