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.

1041 lines
22 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "fgdlib/GameData.h" // FGDLIB: eliminate dependency
  7. #include "fgdlib/GDClass.h"
  8. // memdbgon must be the last include file in a .cpp file!!!
  9. #include <tier0/memdbgon.h>
  10. //-----------------------------------------------------------------------------
  11. // Purpose: Constructor.
  12. //-----------------------------------------------------------------------------
  13. GDclass::GDclass(void)
  14. {
  15. m_nVariables = 0;
  16. m_bBase = false;
  17. m_bSolid = false;
  18. m_bBase = false;
  19. m_bSolid = false;
  20. m_bModel = false;
  21. m_bMove = false;
  22. m_bKeyFrame = false;
  23. m_bPoint = false;
  24. m_bNPC = false;
  25. m_bFilter = false;
  26. m_bHalfGridSnap = false;
  27. m_bGotSize = false;
  28. m_bGotColor = false;
  29. m_rgbColor.r = 220;
  30. m_rgbColor.g = 30;
  31. m_rgbColor.b = 220;
  32. m_rgbColor.a = 0;
  33. m_pszDescription = NULL;
  34. for (int i = 0; i < 3; i++)
  35. {
  36. m_bmins[i] = -8;
  37. m_bmaxs[i] = 8;
  38. }
  39. }
  40. //-----------------------------------------------------------------------------
  41. // Purpose: Destructor. Frees variable and helper lists.
  42. //-----------------------------------------------------------------------------
  43. GDclass::~GDclass(void)
  44. {
  45. //
  46. // Free variables.
  47. //
  48. int nCount = m_Variables.Count();
  49. for (int i = 0; i < nCount; i++)
  50. {
  51. GDinputvariable *pvi = m_Variables.Element(i);
  52. delete pvi;
  53. }
  54. m_Variables.RemoveAll();
  55. //
  56. // Free helpers.
  57. //
  58. nCount = m_Helpers.Count();
  59. for (int i = 0; i < nCount; i++)
  60. {
  61. CHelperInfo *pHelper = m_Helpers.Element(i);
  62. delete pHelper;
  63. }
  64. m_Helpers.RemoveAll();
  65. //
  66. // Free inputs.
  67. //
  68. nCount = m_Inputs.Count();
  69. for (int i = 0; i < nCount; i++)
  70. {
  71. CClassInput *pInput = m_Inputs.Element(i);
  72. delete pInput;
  73. }
  74. m_Inputs.RemoveAll();
  75. //
  76. // Free outputs.
  77. //
  78. nCount = m_Outputs.Count();
  79. for (int i = 0; i < nCount; i++)
  80. {
  81. CClassOutput *pOutput = m_Outputs.Element(i);
  82. delete pOutput;
  83. }
  84. m_Outputs.RemoveAll();
  85. delete m_pszDescription;
  86. }
  87. //-----------------------------------------------------------------------------
  88. // Purpose: Adds the base class's variables to our variable list. Acquires the
  89. // base class's bounding box and color, if any.
  90. // Input : pszBase - Name of base class to add.
  91. //-----------------------------------------------------------------------------
  92. void GDclass::AddBase(GDclass *pBase)
  93. {
  94. int iBaseIndex;
  95. Parent->ClassForName(pBase->GetName(), &iBaseIndex);
  96. //
  97. // Add variables from base - update variable table
  98. //
  99. for (int i = 0; i < pBase->GetVariableCount(); i++)
  100. {
  101. GDinputvariable *pVar = pBase->GetVariableAt(i);
  102. AddVariable(pVar, pBase, iBaseIndex, i);
  103. }
  104. //
  105. // Add inputs from the base.
  106. // UNDONE: need to use references to inputs & outputs to conserve memory
  107. //
  108. int nCount = pBase->GetInputCount();
  109. for (int i = 0; i < nCount; i++)
  110. {
  111. CClassInput *pInput = pBase->GetInput(i);
  112. CClassInput *pNew = new CClassInput;
  113. *pNew = *pInput;
  114. AddInput(pNew);
  115. }
  116. //
  117. // Add outputs from the base.
  118. //
  119. nCount = pBase->GetOutputCount();
  120. for (int i = 0; i < nCount; i++)
  121. {
  122. CClassOutput *pOutput = pBase->GetOutput(i);
  123. CClassOutput *pNew = new CClassOutput;
  124. *pNew = *pOutput;
  125. AddOutput(pNew);
  126. }
  127. //
  128. // If we don't have a bounding box, try to get the base's box.
  129. //
  130. if (!m_bGotSize)
  131. {
  132. if (pBase->GetBoundBox(m_bmins, m_bmaxs))
  133. {
  134. m_bGotSize = true;
  135. }
  136. }
  137. //
  138. // If we don't have a color, use the base's color.
  139. //
  140. if (!m_bGotColor)
  141. {
  142. m_rgbColor = pBase->GetColor();
  143. m_bGotColor = true;
  144. }
  145. }
  146. //-----------------------------------------------------------------------------
  147. // Purpose: Adds the given GDInputVariable to this GDClass's list of variables.
  148. // Input : pVar -
  149. // pBase -
  150. // iBaseIndex -
  151. // iVarIndex -
  152. // Output : Returns TRUE if the pVar pointer was copied directly into this GDClass,
  153. // FALSE if not. If this function returns TRUE, pVar should not be
  154. // deleted by the caller.
  155. //-----------------------------------------------------------------------------
  156. BOOL GDclass::AddVariable(GDinputvariable *pVar, GDclass *pBase, int iBaseIndex, int iVarIndex)
  157. {
  158. int iThisIndex;
  159. GDinputvariable *pThisVar = VarForName(pVar->GetName(), &iThisIndex);
  160. //
  161. // Check to see if we are overriding an existing variable definition.
  162. //
  163. if (pThisVar != NULL)
  164. {
  165. //
  166. // Same name, different type. Flag this as an error.
  167. //
  168. if (pThisVar->GetType() != pVar->GetType())
  169. {
  170. return(false);
  171. }
  172. GDinputvariable *pAddVar;
  173. bool bReturn;
  174. //
  175. // Check to see if we need to combine a choices/flags array.
  176. //
  177. if (pVar->GetType() == ivFlags || pVar->GetType() == ivChoices)
  178. {
  179. //
  180. // Combine two variables' flags into a new variable. Add the new
  181. // variable to the local variable list and modify the old variable's
  182. // position in our variable map to reflect the new local variable.
  183. // This way, we can have multiple inheritance.
  184. //
  185. GDinputvariable *pNewVar = new GDinputvariable;
  186. *pNewVar = *pVar;
  187. pNewVar->Merge(*pThisVar);
  188. pAddVar = pNewVar;
  189. bReturn = false;
  190. }
  191. else
  192. {
  193. pAddVar = pVar;
  194. bReturn = true;
  195. }
  196. if (m_VariableMap[iThisIndex][0] == -1)
  197. {
  198. //
  199. // "pThisVar" is a leaf variable - we can remove since it is overridden.
  200. //
  201. int nIndex = m_Variables.Find(pThisVar);
  202. Assert(nIndex != -1);
  203. delete pThisVar;
  204. m_Variables.Element(nIndex) = pAddVar;
  205. //
  206. // No need to modify variable map - we just replaced
  207. // the pointer in the local variable list.
  208. //
  209. }
  210. else
  211. {
  212. //
  213. // "pThisVar" was declared in a base class - we can replace the reference in
  214. // our variable map with the new variable.
  215. //
  216. m_VariableMap[iThisIndex][0] = iBaseIndex;
  217. if (iBaseIndex == -1)
  218. {
  219. m_Variables.AddToTail(pAddVar);
  220. m_VariableMap[iThisIndex][1] = m_Variables.Count() - 1;
  221. }
  222. else
  223. {
  224. m_VariableMap[iThisIndex][1] = iVarIndex;
  225. }
  226. }
  227. return(bReturn);
  228. }
  229. //
  230. // New variable.
  231. //
  232. if (iBaseIndex == -1)
  233. {
  234. //
  235. // Variable declared in the leaf class definition - add it to the list.
  236. //
  237. m_Variables.AddToTail(pVar);
  238. }
  239. //
  240. // Too many variables already declared in this class definition - abort.
  241. //
  242. if (m_nVariables == GD_MAX_VARIABLES)
  243. {
  244. //CUtlString str;
  245. //str.Format("Too many gamedata variables for class \"%s\"", m_szName);
  246. //AfxMessageBox(str);
  247. return(false);
  248. }
  249. //
  250. // Add the variable to our list.
  251. //
  252. m_VariableMap[m_nVariables][0] = iBaseIndex;
  253. m_VariableMap[m_nVariables][1] = iVarIndex;
  254. ++m_nVariables;
  255. //
  256. // We added the pointer to our list of items (see Variables.AddToTail, above) so
  257. // we must return true here.
  258. //
  259. return(true);
  260. }
  261. //-----------------------------------------------------------------------------
  262. // Finds an input by name.
  263. //-----------------------------------------------------------------------------
  264. CClassInput *GDclass::FindInput(const char *szName)
  265. {
  266. int nCount = GetInputCount();
  267. for (int i = 0; i < nCount; i++)
  268. {
  269. CClassInput *pInput = GetInput(i);
  270. if (!stricmp(pInput->GetName(), szName))
  271. {
  272. return(pInput);
  273. }
  274. }
  275. return(NULL);
  276. }
  277. //-----------------------------------------------------------------------------
  278. // Finds an output by name.
  279. //-----------------------------------------------------------------------------
  280. CClassOutput *GDclass::FindOutput(const char *szName)
  281. {
  282. int nCount = GetOutputCount();
  283. for (int i = 0; i < nCount; i++)
  284. {
  285. CClassOutput *pOutput = GetOutput(i);
  286. if (!stricmp(pOutput->GetName(), szName))
  287. {
  288. return(pOutput);
  289. }
  290. }
  291. return(NULL);
  292. }
  293. //-----------------------------------------------------------------------------
  294. // Purpose: Gets the mins and maxs of the class's bounding box as read from the
  295. // FGD file. This controls the onscreen representation of any entities
  296. // derived from this class.
  297. // Input : pfMins - Receives minimum X, Y, and Z coordinates for the class.
  298. // pfMaxs - Receives maximum X, Y, and Z coordinates for the class.
  299. // Output : Returns TRUE if this class has a specified bounding box, FALSE if not.
  300. //-----------------------------------------------------------------------------
  301. BOOL GDclass::GetBoundBox(Vector& pfMins, Vector& pfMaxs)
  302. {
  303. if (m_bGotSize)
  304. {
  305. pfMins[0] = m_bmins[0];
  306. pfMins[1] = m_bmins[1];
  307. pfMins[2] = m_bmins[2];
  308. pfMaxs[0] = m_bmaxs[0];
  309. pfMaxs[1] = m_bmaxs[1];
  310. pfMaxs[2] = m_bmaxs[2];
  311. }
  312. return(m_bGotSize);
  313. }
  314. //-----------------------------------------------------------------------------
  315. //-----------------------------------------------------------------------------
  316. CHelperInfo *GDclass::GetHelper(int nIndex)
  317. {
  318. return m_Helpers.Element(nIndex);
  319. }
  320. //-----------------------------------------------------------------------------
  321. //-----------------------------------------------------------------------------
  322. CClassInput *GDclass::GetInput(int nIndex)
  323. {
  324. return m_Inputs.Element(nIndex);
  325. }
  326. //-----------------------------------------------------------------------------
  327. //-----------------------------------------------------------------------------
  328. CClassOutput *GDclass::GetOutput(int nIndex)
  329. {
  330. return m_Outputs.Element(nIndex);
  331. }
  332. //-----------------------------------------------------------------------------
  333. // Purpose:
  334. // Input : tr -
  335. // pGD -
  336. // Output : Returns TRUE if worth continuing, FALSE otherwise.
  337. //-----------------------------------------------------------------------------
  338. BOOL GDclass::InitFromTokens(TokenReader& tr, GameData *pGD)
  339. {
  340. Parent = pGD;
  341. //
  342. // Initialize VariableMap
  343. //
  344. for (int i = 0; i < GD_MAX_VARIABLES; i++)
  345. {
  346. m_VariableMap[i][0] = -1;
  347. m_VariableMap[i][1] = -1;
  348. }
  349. //
  350. // Parse all specifiers (base, size, color, etc.)
  351. //
  352. if (!ParseSpecifiers(tr))
  353. {
  354. return(FALSE);
  355. }
  356. //
  357. // Specifiers should be followed by an "="
  358. //
  359. if (!GDSkipToken(tr, OPERATOR, "="))
  360. {
  361. return(FALSE);
  362. }
  363. //
  364. // Parse the class name.
  365. //
  366. if (!GDGetToken(tr, m_szName, sizeof(m_szName), IDENT))
  367. {
  368. return(FALSE);
  369. }
  370. //
  371. // Check next operator - if ":", we have a description - if "[",
  372. // we have no description.
  373. //
  374. char szToken[MAX_TOKEN];
  375. if ((tr.PeekTokenType(szToken,sizeof(szToken)) == OPERATOR) && IsToken(szToken, ":"))
  376. {
  377. // Skip ":"
  378. tr.NextToken(szToken, sizeof(szToken));
  379. //
  380. // Free any existing description and set the pointer to NULL so that GDGetToken
  381. // allocates memory for us.
  382. //
  383. delete m_pszDescription;
  384. m_pszDescription = NULL;
  385. // Load description
  386. if (!GDGetTokenDynamic(tr, &m_pszDescription, STRING))
  387. {
  388. return(FALSE);
  389. }
  390. }
  391. //
  392. // Opening square brace.
  393. //
  394. if (!GDSkipToken(tr, OPERATOR, "["))
  395. {
  396. return(FALSE);
  397. }
  398. //
  399. // Get class variables.
  400. //
  401. if (!ParseVariables(tr))
  402. {
  403. return(FALSE);
  404. }
  405. //
  406. // Closing square brace.
  407. //
  408. if (!GDSkipToken(tr, OPERATOR, "]"))
  409. {
  410. return(FALSE);
  411. }
  412. return(TRUE);
  413. }
  414. //-----------------------------------------------------------------------------
  415. // Purpose:
  416. // Input : &tr -
  417. // Output : Returns true on success, false on failure.
  418. //-----------------------------------------------------------------------------
  419. bool GDclass::ParseBase(TokenReader &tr)
  420. {
  421. char szToken[MAX_TOKEN];
  422. while (1)
  423. {
  424. if (!GDGetToken(tr, szToken, sizeof(szToken), IDENT))
  425. {
  426. return(false);
  427. }
  428. //
  429. // Find base class in list of classes.
  430. //
  431. GDclass *pBase = Parent->ClassForName(szToken);
  432. if (pBase == NULL)
  433. {
  434. GDError(tr, "undefined base class '%s", szToken);
  435. return(false);
  436. }
  437. AddBase(pBase);
  438. if (!GDGetToken(tr, szToken, sizeof(szToken), OPERATOR))
  439. {
  440. return(false);
  441. }
  442. if (IsToken(szToken, ")"))
  443. {
  444. break;
  445. }
  446. else if (!IsToken(szToken, ","))
  447. {
  448. GDError(tr, "expecting ',' or ')', but found %s", szToken);
  449. return(false);
  450. }
  451. }
  452. return(true);
  453. }
  454. //-----------------------------------------------------------------------------
  455. // Purpose:
  456. // Input : &tr -
  457. // Output : Returns true on success, false on failure.
  458. //-----------------------------------------------------------------------------
  459. bool GDclass::ParseColor(TokenReader &tr)
  460. {
  461. char szToken[MAX_TOKEN];
  462. //
  463. // Red.
  464. //
  465. if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER))
  466. {
  467. return(false);
  468. }
  469. BYTE r = atoi(szToken);
  470. //
  471. // Green.
  472. //
  473. if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER))
  474. {
  475. return(false);
  476. }
  477. BYTE g = atoi(szToken);
  478. //
  479. // Blue.
  480. //
  481. if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER))
  482. {
  483. return(false);
  484. }
  485. BYTE b = atoi(szToken);
  486. m_rgbColor.r = r;
  487. m_rgbColor.g = g;
  488. m_rgbColor.b = b;
  489. m_rgbColor.a = 0;
  490. m_bGotColor = true;
  491. if (!GDGetToken(tr, szToken, sizeof(szToken), OPERATOR, ")"))
  492. {
  493. return(false);
  494. }
  495. return(true);
  496. }
  497. //-----------------------------------------------------------------------------
  498. // Purpose: Parses a helper from the FGD file. Helpers are of the following format:
  499. //
  500. // <helpername>(<parameter 0> <parameter 1> ... <parameter n>)
  501. //
  502. // When this function is called, the helper name has already been parsed.
  503. // Input : tr - Tokenreader to use for parsing.
  504. // pszHelperName - Name of the helper being declared.
  505. // Output : Returns true on success, false on failure.
  506. //-----------------------------------------------------------------------------
  507. bool GDclass::ParseHelper(TokenReader &tr, char *pszHelperName)
  508. {
  509. char szToken[MAX_TOKEN];
  510. CHelperInfo *pHelper = new CHelperInfo;
  511. pHelper->SetName(pszHelperName);
  512. bool bCloseParen = false;
  513. while (!bCloseParen)
  514. {
  515. trtoken_t eType = tr.PeekTokenType(szToken,sizeof(szToken));
  516. if (eType == OPERATOR)
  517. {
  518. if (!GDGetToken(tr, szToken, sizeof(szToken), OPERATOR))
  519. {
  520. delete pHelper;
  521. return(false);
  522. }
  523. if (IsToken(szToken, ")"))
  524. {
  525. bCloseParen = true;
  526. }
  527. else if (IsToken(szToken, "="))
  528. {
  529. delete pHelper;
  530. return(false);
  531. }
  532. }
  533. else
  534. {
  535. if (!GDGetToken(tr, szToken, sizeof(szToken), eType))
  536. {
  537. delete pHelper;
  538. return(false);
  539. }
  540. else
  541. {
  542. pHelper->AddParameter(szToken);
  543. }
  544. }
  545. }
  546. m_Helpers.AddToTail(pHelper);
  547. return(true);
  548. }
  549. //-----------------------------------------------------------------------------
  550. // Purpose:
  551. // Input : &tr -
  552. // Output : Returns true on success, false on failure.
  553. //-----------------------------------------------------------------------------
  554. bool GDclass::ParseSize(TokenReader &tr)
  555. {
  556. char szToken[MAX_TOKEN];
  557. //
  558. // Mins.
  559. //
  560. for (int i = 0; i < 3; i++)
  561. {
  562. if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER))
  563. {
  564. return(false);
  565. }
  566. m_bmins[i] = (float)atof(szToken);
  567. }
  568. if (tr.PeekTokenType(szToken,sizeof(szToken)) == OPERATOR && IsToken(szToken, ","))
  569. {
  570. //
  571. // Skip ","
  572. //
  573. tr.NextToken(szToken, sizeof(szToken));
  574. //
  575. // Get maxes.
  576. //
  577. for (int i = 0; i < 3; i++)
  578. {
  579. if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER))
  580. {
  581. return(false);
  582. }
  583. m_bmaxs[i] = (float)atof(szToken);
  584. }
  585. }
  586. else
  587. {
  588. //
  589. // Split mins across origin.
  590. //
  591. for (int i = 0; i < 3; i++)
  592. {
  593. float div2 = m_bmins[i] / 2;
  594. m_bmaxs[i] = div2;
  595. m_bmins[i] = -div2;
  596. }
  597. }
  598. m_bGotSize = true;
  599. if (!GDGetToken(tr, szToken, sizeof(szToken), OPERATOR, ")"))
  600. {
  601. return(false);
  602. }
  603. return(true);
  604. }
  605. //-----------------------------------------------------------------------------
  606. // Purpose:
  607. // Input : &tr -
  608. // Output : Returns true on success, false on failure.
  609. //-----------------------------------------------------------------------------
  610. bool GDclass::ParseSpecifiers(TokenReader &tr)
  611. {
  612. char szToken[MAX_TOKEN];
  613. while (tr.PeekTokenType() == IDENT)
  614. {
  615. tr.NextToken(szToken, sizeof(szToken));
  616. //
  617. // Handle specifiers that don't have any parens after them.
  618. //
  619. if (IsToken(szToken, "halfgridsnap"))
  620. {
  621. m_bHalfGridSnap = true;
  622. }
  623. else
  624. {
  625. //
  626. // Handle specifiers require parens after them.
  627. //
  628. if (!GDSkipToken(tr, OPERATOR, "("))
  629. {
  630. return(false);
  631. }
  632. if (IsToken(szToken, "base"))
  633. {
  634. if (!ParseBase(tr))
  635. {
  636. return(false);
  637. }
  638. }
  639. else if (IsToken(szToken, "size"))
  640. {
  641. if (!ParseSize(tr))
  642. {
  643. return(false);
  644. }
  645. }
  646. else if (IsToken(szToken, "color"))
  647. {
  648. if (!ParseColor(tr))
  649. {
  650. return(false);
  651. }
  652. }
  653. else if (!ParseHelper(tr, szToken))
  654. {
  655. return(false);
  656. }
  657. }
  658. }
  659. return(true);
  660. }
  661. //-----------------------------------------------------------------------------
  662. // Purpose: Reads an input using a given token reader. If the input is
  663. // read successfully, the input is added to this class. If not, a
  664. // parsing failure is returned.
  665. // Input : tr - Token reader to use for parsing.
  666. // Output : Returns true on success, false on failure.
  667. //-----------------------------------------------------------------------------
  668. bool GDclass::ParseInput(TokenReader &tr)
  669. {
  670. char szToken[MAX_TOKEN];
  671. if (!GDGetToken(tr, szToken, sizeof(szToken), IDENT, "input"))
  672. {
  673. return(false);
  674. }
  675. CClassInput *pInput = new CClassInput;
  676. bool bReturn = ParseInputOutput(tr, pInput);
  677. if (bReturn)
  678. {
  679. AddInput(pInput);
  680. }
  681. else
  682. {
  683. delete pInput;
  684. }
  685. return(bReturn);
  686. }
  687. //-----------------------------------------------------------------------------
  688. // Purpose: Reads an input or output using a given token reader.
  689. // Input : tr - Token reader to use for parsing.
  690. // pInputOutput - Input or output to fill out.
  691. // Output : Returns true on success, false on failure.
  692. //-----------------------------------------------------------------------------
  693. bool GDclass::ParseInputOutput(TokenReader &tr, CClassInputOutputBase *pInputOutput)
  694. {
  695. char szToken[MAX_TOKEN];
  696. //
  697. // Read the name.
  698. //
  699. if (!GDGetToken(tr, szToken, sizeof(szToken), IDENT))
  700. {
  701. return(false);
  702. }
  703. pInputOutput->SetName(szToken);
  704. //
  705. // Read the type.
  706. //
  707. if (!GDGetToken(tr, szToken, sizeof(szToken), OPERATOR, "("))
  708. {
  709. return(false);
  710. }
  711. if (!GDGetToken(tr, szToken, sizeof(szToken), IDENT))
  712. {
  713. return(false);
  714. }
  715. InputOutputType_t eType = pInputOutput->SetType(szToken);
  716. if (eType == iotInvalid)
  717. {
  718. GDError(tr, "bad input/output type '%s'", szToken);
  719. return(false);
  720. }
  721. if (!GDGetToken(tr, szToken, sizeof(szToken), OPERATOR, ")"))
  722. {
  723. return(false);
  724. }
  725. //
  726. // Check the next operator - if ':', we have a description.
  727. //
  728. if ((tr.PeekTokenType(szToken,sizeof(szToken)) == OPERATOR) && (IsToken(szToken, ":")))
  729. {
  730. //
  731. // Skip the ":".
  732. //
  733. tr.NextToken(szToken, sizeof(szToken));
  734. //
  735. // Read the description.
  736. //
  737. char *pszDescription;
  738. if (!GDGetTokenDynamic(tr, &pszDescription, STRING))
  739. {
  740. return(false);
  741. }
  742. pInputOutput->SetDescription(pszDescription);
  743. }
  744. return(true);
  745. }
  746. //-----------------------------------------------------------------------------
  747. // Purpose: Reads an output using a given token reader. If the output is
  748. // read successfully, the output is added to this class. If not, a
  749. // parsing failure is returned.
  750. // Input : tr - Token reader to use for parsing.
  751. // Output : Returns true on success, false on failure.
  752. //-----------------------------------------------------------------------------
  753. bool GDclass::ParseOutput(TokenReader &tr)
  754. {
  755. char szToken[MAX_TOKEN];
  756. if (!GDGetToken(tr, szToken, sizeof(szToken), IDENT, "output"))
  757. {
  758. return(false);
  759. }
  760. CClassOutput *pOutput = new CClassOutput;
  761. bool bReturn = ParseInputOutput(tr, pOutput);
  762. if (bReturn)
  763. {
  764. AddOutput(pOutput);
  765. }
  766. else
  767. {
  768. delete pOutput;
  769. }
  770. return(bReturn);
  771. }
  772. //-----------------------------------------------------------------------------
  773. // Purpose:
  774. // Input : &tr -
  775. // Output : Returns true on success, false on failure.
  776. //-----------------------------------------------------------------------------
  777. bool GDclass::ParseVariables(TokenReader &tr)
  778. {
  779. while (1)
  780. {
  781. char szToken[MAX_TOKEN];
  782. if (tr.PeekTokenType(szToken,sizeof(szToken)) == OPERATOR)
  783. {
  784. break;
  785. }
  786. if (!stricmp(szToken, "input"))
  787. {
  788. if (!ParseInput(tr))
  789. {
  790. return(false);
  791. }
  792. continue;
  793. }
  794. if (!stricmp(szToken, "output"))
  795. {
  796. if (!ParseOutput(tr))
  797. {
  798. return(false);
  799. }
  800. continue;
  801. }
  802. if (!stricmp(szToken, "key"))
  803. {
  804. GDGetToken(tr, szToken, sizeof(szToken));
  805. }
  806. GDinputvariable * var = new GDinputvariable;
  807. if (!var->InitFromTokens(tr))
  808. {
  809. delete var;
  810. return(false);
  811. }
  812. int nDupIndex;
  813. GDinputvariable *pDupVar = VarForName(var->GetName(), &nDupIndex);
  814. // check for duplicate variable definitions
  815. if (pDupVar)
  816. {
  817. // Same name, different type.
  818. if (pDupVar->GetType() != var->GetType())
  819. {
  820. char szError[_MAX_PATH];
  821. sprintf(szError, "%s: Variable '%s' is multiply defined with different types.", GetName(), var->GetName());
  822. GDError(tr, szError);
  823. }
  824. }
  825. if (!AddVariable(var, this, -1, m_Variables.Count()))
  826. {
  827. delete var;
  828. }
  829. }
  830. return(true);
  831. }
  832. //-----------------------------------------------------------------------------
  833. // Purpose:
  834. // Input : iIndex -
  835. // Output : GDinputvariable *
  836. //-----------------------------------------------------------------------------
  837. GDinputvariable *GDclass::GetVariableAt(int iIndex)
  838. {
  839. if ( iIndex < 0 || iIndex >= m_nVariables )
  840. return NULL;
  841. if (m_VariableMap[iIndex][0] == -1)
  842. {
  843. return m_Variables.Element(m_VariableMap[iIndex][1]);
  844. }
  845. // find var's owner
  846. GDclass *pVarClass = Parent->GetClass(m_VariableMap[iIndex][0]);
  847. // find var in pVarClass
  848. return pVarClass->GetVariableAt(m_VariableMap[iIndex][1]);
  849. }
  850. //-----------------------------------------------------------------------------
  851. //-----------------------------------------------------------------------------
  852. GDinputvariable *GDclass::VarForName(const char *pszName, int *piIndex)
  853. {
  854. for(int i = 0; i < GetVariableCount(); i++)
  855. {
  856. GDinputvariable *pVar = GetVariableAt(i);
  857. if(!strcmpi(pVar->GetName(), pszName))
  858. {
  859. if(piIndex)
  860. piIndex[0] = i;
  861. return pVar;
  862. }
  863. }
  864. return NULL;
  865. }
  866. void GDclass::GetHelperForGDVar( GDinputvariable *pVar, CUtlVector<const char *> *pszHelperName )
  867. {
  868. const char *pszName = pVar->GetName();
  869. for( int i = 0; i < GetHelperCount(); i++ )
  870. {
  871. CHelperInfo *pHelper = GetHelper( i );
  872. int nParamCount = pHelper->GetParameterCount();
  873. for ( int j = 0; j < nParamCount; j++ )
  874. {
  875. if ( !strcmpi( pszName, pHelper->GetParameter( j ) ) )
  876. {
  877. pszHelperName->AddToTail(pHelper->GetName());
  878. }
  879. }
  880. }
  881. }