Counter Strike : Global Offensive Source Code
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.

779 lines
19 KiB

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