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.

729 lines
17 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. //=============================================================================
  4. #include "fgdlib/fgdlib.h"
  5. #include "fgdlib/GameData.h"
  6. #include "fgdlib/WCKeyValues.h"
  7. #include "fgdlib/gdvar.h"
  8. // memdbgon must be the last include file in a .cpp file!!!
  9. #include <tier0/memdbgon.h>
  10. typedef struct
  11. {
  12. GDIV_TYPE eType; // The enumeration of this type.
  13. char *pszName; // The name of this type.
  14. trtoken_t eStoreAs; // How this type is stored (STRING, INTEGER, etc).
  15. } TypeMap_t;
  16. //-----------------------------------------------------------------------------
  17. // Maps type names to type enums and parsing logic for values.
  18. //-----------------------------------------------------------------------------
  19. static TypeMap_t TypeMap[] =
  20. {
  21. { ivAngle, "angle", STRING },
  22. { ivChoices, "choices", STRING },
  23. { ivColor1, "color1", STRING },
  24. { ivColor255, "color255", STRING },
  25. { ivDecal, "decal", STRING },
  26. { ivFlags, "flags", INTEGER },
  27. { ivInteger, "integer", INTEGER },
  28. { ivSound, "sound", STRING },
  29. { ivSprite, "sprite", STRING },
  30. { ivString, "string", STRING },
  31. { ivStudioModel, "studio", STRING },
  32. { ivTargetDest, "target_destination", STRING },
  33. { ivTargetSrc, "target_source", STRING },
  34. { ivTargetNameOrClass, "target_name_or_class", STRING }, // Another version of target_destination that accepts class names
  35. { ivVector, "vector", STRING },
  36. { ivNPCClass, "npcclass", STRING },
  37. { ivFilterClass, "filterclass", STRING },
  38. { ivFloat, "float", STRING },
  39. { ivMaterial, "material", STRING },
  40. { ivScene, "scene", STRING },
  41. { ivSide, "side", STRING },
  42. { ivSideList, "sidelist", STRING },
  43. { ivOrigin, "origin", STRING },
  44. { ivAxis, "axis", STRING },
  45. { ivVecLine, "vecline", STRING },
  46. { ivPointEntityClass, "pointentityclass", STRING },
  47. { ivNodeDest, "node_dest", INTEGER },
  48. { ivInstanceFile, "instance_file", STRING },
  49. { ivAngleNegativePitch, "angle_negative_pitch", STRING },
  50. { ivInstanceVariable, "instance_variable", STRING },
  51. { ivInstanceParm, "instance_parm", STRING },
  52. };
  53. char *GDinputvariable::m_pszEmpty = "";
  54. //-----------------------------------------------------------------------------
  55. //-----------------------------------------------------------------------------
  56. GDinputvariable::GDinputvariable(void)
  57. {
  58. m_szDefault[0] = 0;
  59. m_nDefault = 0;
  60. m_szValue[0] = 0;
  61. m_bReportable = FALSE;
  62. m_bReadOnly = false;
  63. m_pszDescription = NULL;
  64. }
  65. //-----------------------------------------------------------------------------
  66. // Purpose: construct generally used for creating a temp instance parm type
  67. // Input : szType - the textual type of this variable
  68. // szName - the name description of this variable
  69. //-----------------------------------------------------------------------------
  70. GDinputvariable::GDinputvariable( const char *szType, const char *szName )
  71. {
  72. m_szDefault[0] = 0;
  73. m_nDefault = 0;
  74. m_szValue[0] = 0;
  75. m_bReportable = FALSE;
  76. m_bReadOnly = false;
  77. m_pszDescription = NULL;
  78. m_eType = GetTypeFromToken( szType );
  79. strcpy( m_szName, szName );
  80. }
  81. //-----------------------------------------------------------------------------
  82. // Purpose: Destructor.
  83. //-----------------------------------------------------------------------------
  84. GDinputvariable::~GDinputvariable(void)
  85. {
  86. delete [] m_pszDescription;
  87. m_Items.RemoveAll();
  88. }
  89. //-----------------------------------------------------------------------------
  90. // Purpose: Implements the copy operator.
  91. //-----------------------------------------------------------------------------
  92. GDinputvariable &GDinputvariable::operator =(GDinputvariable &Other)
  93. {
  94. m_eType = Other.GetType();
  95. strcpy(m_szName, Other.m_szName);
  96. strcpy(m_szLongName, Other.m_szLongName);
  97. strcpy(m_szDefault, Other.m_szDefault);
  98. //
  99. // Copy the description.
  100. //
  101. delete [] m_pszDescription;
  102. if (Other.m_pszDescription != NULL)
  103. {
  104. m_pszDescription = new char[strlen(Other.m_pszDescription) + 1];
  105. strcpy(m_pszDescription, Other.m_pszDescription);
  106. }
  107. else
  108. {
  109. m_pszDescription = NULL;
  110. }
  111. m_nDefault = Other.m_nDefault;
  112. m_bReportable = Other.m_bReportable;
  113. m_bReadOnly = Other.m_bReadOnly;
  114. m_Items.RemoveAll();
  115. int nCount = Other.m_Items.Count();
  116. for (int i = 0; i < nCount; i++)
  117. {
  118. m_Items.AddToTail(Other.m_Items.Element(i));
  119. }
  120. return(*this);
  121. }
  122. //-----------------------------------------------------------------------------
  123. // Purpose: Returns the storage format of a given variable type.
  124. // Input : pszToken - Sting containing the token.
  125. // Output : GDIV_TYPE corresponding to the token in the string, ivBadType if the
  126. // string does not correspond to a valid type.
  127. //-----------------------------------------------------------------------------
  128. trtoken_t GDinputvariable::GetStoreAsFromType(GDIV_TYPE eType)
  129. {
  130. for (int i = 0; i < sizeof(TypeMap) / sizeof(TypeMap[0]); i++)
  131. {
  132. if (TypeMap[i].eType == eType)
  133. {
  134. return(TypeMap[i].eStoreAs);
  135. }
  136. }
  137. Assert(FALSE);
  138. return(STRING);
  139. }
  140. //-----------------------------------------------------------------------------
  141. // Purpose: Returns the enumerated type of a string token.
  142. // Input : pszToken - Sting containing the token.
  143. // Output : GDIV_TYPE corresponding to the token in the string, ivBadType if the
  144. // string does not correspond to a valid type.
  145. //-----------------------------------------------------------------------------
  146. GDIV_TYPE GDinputvariable::GetTypeFromToken(const char *pszToken)
  147. {
  148. for (int i = 0; i < sizeof(TypeMap) / sizeof(TypeMap[0]); i++)
  149. {
  150. if (IsToken(pszToken, TypeMap[i].pszName))
  151. {
  152. return(TypeMap[i].eType);
  153. }
  154. }
  155. return(ivBadType);
  156. }
  157. //-----------------------------------------------------------------------------
  158. // Purpose: Returns a string representing the type of this variable, eg. "integer".
  159. //-----------------------------------------------------------------------------
  160. const char *GDinputvariable::GetTypeText(void)
  161. {
  162. for (int i = 0; i < sizeof(TypeMap) / sizeof(TypeMap[0]); i++)
  163. {
  164. if (TypeMap[i].eType == m_eType)
  165. {
  166. return(TypeMap[i].pszName);
  167. }
  168. }
  169. return("unknown");
  170. }
  171. //-----------------------------------------------------------------------------
  172. // Purpose:
  173. // Input : tr -
  174. // Output : Returns TRUE on success, FALSE on failure.
  175. //-----------------------------------------------------------------------------
  176. BOOL GDinputvariable::InitFromTokens(TokenReader& tr)
  177. {
  178. char szToken[128];
  179. if (!GDGetToken(tr, m_szName, sizeof(m_szName), IDENT))
  180. {
  181. return FALSE;
  182. }
  183. if (!GDSkipToken(tr, OPERATOR, "("))
  184. {
  185. return FALSE;
  186. }
  187. // check for "reportable" marker
  188. trtoken_t ttype = tr.NextToken(szToken, sizeof(szToken));
  189. if (ttype == OPERATOR)
  190. {
  191. if (!strcmp(szToken, "*"))
  192. {
  193. m_bReportable = true;
  194. }
  195. }
  196. else
  197. {
  198. tr.Stuff(ttype, szToken);
  199. }
  200. // get type
  201. if (!GDGetToken(tr, szToken, sizeof(szToken), IDENT))
  202. {
  203. return FALSE;
  204. }
  205. if (!GDSkipToken(tr, OPERATOR, ")"))
  206. {
  207. return FALSE;
  208. }
  209. //
  210. // Check for known variable types.
  211. //
  212. m_eType = GetTypeFromToken(szToken);
  213. if (m_eType == ivBadType)
  214. {
  215. GDError(tr, "'%s' is not a valid variable type", szToken);
  216. return FALSE;
  217. }
  218. //
  219. // Look ahead at the next token.
  220. //
  221. ttype = tr.PeekTokenType(szToken,sizeof(szToken));
  222. //
  223. // Check for the "readonly" specifier.
  224. //
  225. if ((ttype == IDENT) && IsToken(szToken, "readonly"))
  226. {
  227. tr.NextToken(szToken, sizeof(szToken));
  228. m_bReadOnly = true;
  229. //
  230. // Look ahead at the next token.
  231. //
  232. ttype = tr.PeekTokenType(szToken,sizeof(szToken));
  233. }
  234. //
  235. // Check for the ':' indicating a long name.
  236. //
  237. if (ttype == OPERATOR && IsToken(szToken, ":"))
  238. {
  239. //
  240. // Eat the ':'.
  241. //
  242. tr.NextToken(szToken, sizeof(szToken));
  243. if (m_eType == ivFlags)
  244. {
  245. GDError(tr, "flag sets do not have long names");
  246. return FALSE;
  247. }
  248. //
  249. // Get the long name.
  250. //
  251. if (!GDGetToken(tr, m_szLongName, sizeof(m_szLongName), STRING))
  252. {
  253. return(FALSE);
  254. }
  255. //
  256. // Look ahead at the next token.
  257. //
  258. ttype = tr.PeekTokenType(szToken,sizeof(szToken));
  259. //
  260. // Check for the ':' indicating a default value.
  261. //
  262. if (ttype == OPERATOR && IsToken(szToken, ":"))
  263. {
  264. //
  265. // Eat the ':'.
  266. //
  267. tr.NextToken(szToken, sizeof(szToken));
  268. //
  269. // Look ahead at the next token.
  270. //
  271. ttype = tr.PeekTokenType(szToken,sizeof(szToken));
  272. if (ttype == OPERATOR && IsToken(szToken, ":"))
  273. {
  274. //
  275. // No default value provided, skip to the description.
  276. //
  277. }
  278. else
  279. {
  280. //
  281. // Determine how to parse the default value. If this is a choices field, the
  282. // default could either be a string or an integer, so we must look ahead and
  283. // use whichever is there.
  284. //
  285. trtoken_t eStoreAs = GetStoreAsFromType(m_eType);
  286. if (eStoreAs == STRING)
  287. {
  288. if (!GDGetToken(tr, m_szDefault, sizeof(m_szDefault), STRING))
  289. {
  290. return(FALSE);
  291. }
  292. }
  293. else if (eStoreAs == INTEGER)
  294. {
  295. if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER))
  296. {
  297. return(FALSE);
  298. }
  299. m_nDefault = atoi(szToken);
  300. }
  301. //
  302. // Look ahead at the next token.
  303. //
  304. ttype = tr.PeekTokenType(szToken,sizeof(szToken));
  305. }
  306. }
  307. //
  308. // Check for the ':' indicating a description.
  309. //
  310. if (ttype == OPERATOR && IsToken(szToken, ":"))
  311. {
  312. //
  313. // Eat the ':'.
  314. //
  315. tr.NextToken(szToken, sizeof(szToken));
  316. //
  317. // Read the description.
  318. //
  319. // If we've already read a description then free it to avoid memory leaks.
  320. if ( m_pszDescription )
  321. {
  322. delete [] m_pszDescription;
  323. m_pszDescription = NULL;
  324. }
  325. if (!GDGetTokenDynamic(tr, &m_pszDescription, STRING))
  326. {
  327. return(FALSE);
  328. }
  329. //
  330. // Look ahead at the next token.
  331. //
  332. ttype = tr.PeekTokenType(szToken,sizeof(szToken));
  333. }
  334. }
  335. else
  336. {
  337. //
  338. // Default long name is short name.
  339. //
  340. strcpy(m_szLongName, m_szName);
  341. }
  342. //
  343. // Check for the ']' indicating the end of the class definition.
  344. //
  345. if ((ttype == OPERATOR && IsToken(szToken, "]")) || ttype != OPERATOR)
  346. {
  347. if (m_eType == ivFlags || m_eType == ivChoices)
  348. {
  349. //
  350. // Can't define a flags or choices variable without providing any flags or choices.
  351. //
  352. GDError(tr, "no %s specified", m_eType == ivFlags ? "flags" : "choices");
  353. return(FALSE);
  354. }
  355. return(TRUE);
  356. }
  357. if (!GDSkipToken(tr, OPERATOR, "="))
  358. {
  359. return(FALSE);
  360. }
  361. if (m_eType != ivFlags && m_eType != ivChoices)
  362. {
  363. GDError(tr, "didn't expect '=' here");
  364. return(FALSE);
  365. }
  366. // should be '[' to start flags/choices
  367. if (!GDSkipToken(tr, OPERATOR, "["))
  368. {
  369. return(FALSE);
  370. }
  371. // get flags?
  372. if (m_eType == ivFlags)
  373. {
  374. GDIVITEM ivi;
  375. while (1)
  376. {
  377. ttype = tr.PeekTokenType();
  378. if (ttype != INTEGER)
  379. {
  380. break;
  381. }
  382. // store bitflag value
  383. GDGetToken(tr, szToken, sizeof(szToken), INTEGER);
  384. sscanf( szToken, "%lu", &ivi.iValue );
  385. // colon..
  386. if (!GDSkipToken(tr, OPERATOR, ":"))
  387. {
  388. return FALSE;
  389. }
  390. // get description
  391. if (!GDGetToken(tr, szToken, sizeof(szToken), STRING))
  392. {
  393. return FALSE;
  394. }
  395. strcpy(ivi.szCaption, szToken);
  396. // colon..
  397. if (!GDSkipToken(tr, OPERATOR, ":"))
  398. {
  399. return FALSE;
  400. }
  401. // get default setting
  402. if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER))
  403. {
  404. return FALSE;
  405. }
  406. ivi.bDefault = atoi(szToken) ? TRUE : FALSE;
  407. // add item to array of items
  408. m_Items.AddToTail(ivi);
  409. }
  410. // Set the default value.
  411. unsigned long nDefault = 0;
  412. for (int i = 0; i < m_Items.Count(); i++)
  413. {
  414. if (m_Items[i].bDefault)
  415. nDefault |= m_Items[i].iValue;
  416. }
  417. m_nDefault = (int)nDefault;
  418. Q_snprintf( m_szDefault, sizeof( m_szDefault ), "%d", m_nDefault );
  419. }
  420. else if (m_eType == ivChoices)
  421. {
  422. GDIVITEM ivi;
  423. while (1)
  424. {
  425. ttype = tr.PeekTokenType();
  426. if ((ttype != INTEGER) && (ttype != STRING))
  427. {
  428. break;
  429. }
  430. // store choice value
  431. GDGetToken(tr, szToken, sizeof(szToken), ttype);
  432. ivi.iValue = 0;
  433. strcpy(ivi.szValue, szToken);
  434. // colon
  435. if (!GDSkipToken(tr, OPERATOR, ":"))
  436. {
  437. return FALSE;
  438. }
  439. // get description
  440. if (!GDGetToken(tr, szToken, sizeof(szToken), STRING))
  441. {
  442. return FALSE;
  443. }
  444. strcpy(ivi.szCaption, szToken);
  445. m_Items.AddToTail(ivi);
  446. }
  447. }
  448. if (!GDSkipToken(tr, OPERATOR, "]"))
  449. {
  450. return FALSE;
  451. }
  452. return TRUE;
  453. }
  454. //-----------------------------------------------------------------------------
  455. // Purpose: Decodes a key value from a string.
  456. // Input : pkv - Pointer to the key value object containing string encoded value.
  457. //-----------------------------------------------------------------------------
  458. void GDinputvariable::FromKeyValue(MDkeyvalue *pkv)
  459. {
  460. trtoken_t eStoreAs = GetStoreAsFromType(m_eType);
  461. if (eStoreAs == STRING)
  462. {
  463. strcpy(m_szValue, pkv->szValue);
  464. }
  465. else if (eStoreAs == INTEGER)
  466. {
  467. m_nValue = atoi(pkv->szValue);
  468. }
  469. }
  470. //-----------------------------------------------------------------------------
  471. // Purpose: Determines whether the given flag is set (assuming this is an ivFlags).
  472. // Input : uCheck - Flag to check.
  473. // Output : Returns TRUE if flag is set, FALSE if not.
  474. //-----------------------------------------------------------------------------
  475. BOOL GDinputvariable::IsFlagSet(unsigned int uCheck)
  476. {
  477. Assert(m_eType == ivFlags);
  478. return (((unsigned int)m_nValue & uCheck) == uCheck) ? TRUE : FALSE;
  479. }
  480. //-----------------------------------------------------------------------------
  481. // Purpose: Combines the flags or choices items from another variable into our
  482. // list of flags or choices. Ours take priority if collisions occur.
  483. // Input : Other - The variable whose items are being merged with ours.
  484. //-----------------------------------------------------------------------------
  485. void GDinputvariable::Merge(GDinputvariable &Other)
  486. {
  487. //
  488. // Only valid if we are of the same type.
  489. //
  490. if (Other.GetType() != GetType())
  491. {
  492. return;
  493. }
  494. //
  495. // Add Other's items to this ONLY if there is no same-value entry
  496. // for a specific item.
  497. //
  498. bool bFound = false;
  499. int nOurItems = m_Items.Count();
  500. for (int i = 0; i < Other.m_Items.Count(); i++)
  501. {
  502. GDIVITEM &TheirItem = Other.m_Items[i];
  503. for (int j = 0; j < nOurItems; j++)
  504. {
  505. GDIVITEM &OurItem = m_Items[j];
  506. if (TheirItem.iValue == OurItem.iValue)
  507. {
  508. bFound = true;
  509. break;
  510. }
  511. }
  512. if (!bFound)
  513. {
  514. //
  515. // Not found in our list - add their item to our list.
  516. //
  517. m_Items.AddToTail(TheirItem);
  518. }
  519. }
  520. }
  521. //-----------------------------------------------------------------------------
  522. // Purpose: Determines whether the given flag is set (assuming this is an ivFlags).
  523. // Input : uFlags - Flags to set.
  524. // bSet - TRUE to set the flags, FALSE to clear them.
  525. //-----------------------------------------------------------------------------
  526. void GDinputvariable::SetFlag(unsigned int uFlags, BOOL bSet)
  527. {
  528. Assert(m_eType == ivFlags);
  529. if (bSet)
  530. {
  531. m_nValue |= uFlags;
  532. }
  533. else
  534. {
  535. m_nValue &= ~uFlags;
  536. }
  537. }
  538. //-----------------------------------------------------------------------------
  539. // Purpose: Sets this keyvalue to its default value.
  540. //-----------------------------------------------------------------------------
  541. void GDinputvariable::ResetDefaults(void)
  542. {
  543. if (m_eType == ivFlags)
  544. {
  545. m_nValue = 0;
  546. //
  547. // Run thru flags and set any default flags.
  548. //
  549. int nCount = m_Items.Count();
  550. for (int i = 0; i < nCount; i++)
  551. {
  552. if (m_Items[i].bDefault)
  553. {
  554. m_nValue |= GetFlagMask(i);
  555. }
  556. }
  557. }
  558. else
  559. {
  560. m_nValue = m_nDefault;
  561. strcpy(m_szValue, m_szDefault);
  562. }
  563. }
  564. //-----------------------------------------------------------------------------
  565. // Purpose: Encodes a key value as a string.
  566. // Input : pkv - Pointer to the key value object to receive the encoded string.
  567. //-----------------------------------------------------------------------------
  568. void GDinputvariable::ToKeyValue(MDkeyvalue *pkv)
  569. {
  570. strcpy(pkv->szKey, m_szName);
  571. trtoken_t eStoreAs = GetStoreAsFromType(m_eType);
  572. if (eStoreAs == STRING)
  573. {
  574. strcpy(pkv->szValue, m_szValue);
  575. }
  576. else if (eStoreAs == INTEGER)
  577. {
  578. itoa(m_nValue, pkv->szValue, 10);
  579. }
  580. }
  581. //-----------------------------------------------------------------------------
  582. // Purpose: Returns the description string that corresponds to a value string
  583. // for a choices list.
  584. // Input : pszString - The choices value string.
  585. // Output : Returns the description string.
  586. //-----------------------------------------------------------------------------
  587. const char *GDinputvariable::ItemStringForValue(const char *szValue)
  588. {
  589. int nCount = m_Items.Count();
  590. for (int i = 0; i < nCount; i++)
  591. {
  592. if (!stricmp(m_Items[i].szValue, szValue))
  593. {
  594. return(m_Items[i].szCaption);
  595. }
  596. }
  597. return(NULL);
  598. }
  599. //-----------------------------------------------------------------------------
  600. // Purpose: Returns the value string that corresponds to a description string
  601. // for a choices list.
  602. // Input : pszString - The choices description string.
  603. // Output : Returns the value string.
  604. //-----------------------------------------------------------------------------
  605. const char *GDinputvariable::ItemValueForString(const char *szString)
  606. {
  607. int nCount = m_Items.Count();
  608. for (int i = 0; i < nCount; i++)
  609. {
  610. if (!strcmpi(m_Items[i].szCaption, szString))
  611. {
  612. return(m_Items[i].szValue);
  613. }
  614. }
  615. return(NULL);
  616. }
  617. //-----------------------------------------------------------------------------
  618. // Purpose: this function will let you iterate through the text names of the variable types
  619. // Input : eType - the type to get the text of
  620. // Output : returns the textual name
  621. //-----------------------------------------------------------------------------
  622. const char *GDinputvariable::GetVarTypeName( GDIV_TYPE eType )
  623. {
  624. return TypeMap[ eType ].pszName;
  625. }