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.

761 lines
21 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Implements a class that encapsulates much of the functionality
  4. // of entities. CMapWorld and CMapEntity are both derived from this
  5. // class.
  6. //
  7. // CEditGameClass-derived objects have the following properties:
  8. //
  9. // Key/value pairs - A list of string pairs that hold data properties
  10. // of the object. Each property has a unique name.
  11. //
  12. // Connections - A list of outputs in this object that are connected to
  13. // inputs in another entity.
  14. //
  15. //=============================================================================//
  16. #include "stdafx.h"
  17. #include "ChunkFile.h"
  18. #include "fgdlib/GameData.h"
  19. #include "GameConfig.h"
  20. #include "EditGameClass.h"
  21. #include "MapEntity.h"
  22. #include "mathlib/Mathlib.h"
  23. // memdbgon must be the last include file in a .cpp file!!!
  24. #include <tier0/memdbgon.h>
  25. //
  26. // An empty string returned by GetComments when we have no comments set.
  27. //
  28. char *CEditGameClass::g_pszEmpty = "";
  29. //-----------------------------------------------------------------------------
  30. // Purpose: Constructor. Initializes data members.
  31. //-----------------------------------------------------------------------------
  32. CEditGameClass::CEditGameClass(void)
  33. {
  34. m_pClass = NULL;
  35. m_szClass[0] = '\0';
  36. m_pszComments = NULL;
  37. }
  38. //-----------------------------------------------------------------------------
  39. // Purpose: Destructor. Frees memory.
  40. //-----------------------------------------------------------------------------
  41. CEditGameClass::~CEditGameClass(void)
  42. {
  43. delete m_pszComments;
  44. Connections_RemoveAll();
  45. Upstream_RemoveAll();
  46. }
  47. //-----------------------------------------------------------------------------
  48. // Purpose:
  49. // Input : *pConnection -
  50. //-----------------------------------------------------------------------------
  51. void CEditGameClass::Connections_Add(CEntityConnection *pConnection)
  52. {
  53. #if defined(_DEBUG) && 0
  54. LPCTSTR pszTargetName = GetKeyValue("targetname");
  55. if ( pszTargetName && !strcmp(pszTargetName, "zapperpod7_rotator") )
  56. {
  57. // Set breakpoint here for debugging this entity's visiblity
  58. int foo = 0;
  59. }
  60. #endif
  61. if ( m_Connections.Find(pConnection) == -1 )
  62. m_Connections.AddToTail(pConnection);
  63. }
  64. //-----------------------------------------------------------------------------
  65. // Purpose:
  66. // Input : *pConnection -
  67. // Output : Returns true on success, false on failure.
  68. //-----------------------------------------------------------------------------
  69. bool CEditGameClass::Connections_Remove(CEntityConnection *pConnection)
  70. {
  71. int nIndex = m_Connections.Find(pConnection);
  72. if (nIndex != -1)
  73. {
  74. m_Connections.Remove(nIndex);
  75. return(true);
  76. }
  77. return(false);
  78. }
  79. //-----------------------------------------------------------------------------
  80. // NOTE: unlike Connections_Remove, this actually frees each connection!!
  81. //-----------------------------------------------------------------------------
  82. void CEditGameClass::Connections_RemoveAll()
  83. {
  84. //
  85. // Remove all our connections from their targets' upstream lists.
  86. //
  87. int nConnectionsCount = m_Connections.Count();
  88. for (int nConnection = 0; nConnection < nConnectionsCount; nConnection++)
  89. {
  90. CEntityConnection *pConnection = m_Connections.Element( nConnection );
  91. #if defined( ENTITY_MAINTAIN_UPSTREAM_LISTS )
  92. CMapEntityList *pTargetList = pConnection->GetTargetEntityList();
  93. if ( pTargetList )
  94. {
  95. FOR_EACH_OBJ( *pTargetList, pos )
  96. {
  97. CMapEntity *pEntity = pTargetList->Element( pos );
  98. // If you hit this assert it means that an entity was deleted but not removed
  99. // from this entity's list of targets.
  100. ASSERT( pEntity != NULL );
  101. if ( pEntity )
  102. {
  103. pEntity->Upstream_Remove( pConnection );
  104. }
  105. }
  106. }
  107. #endif
  108. delete pConnection;
  109. }
  110. m_Connections.RemoveAll();
  111. }
  112. //-----------------------------------------------------------------------------
  113. // Purpose:
  114. //-----------------------------------------------------------------------------
  115. void CEditGameClass::Connections_FixBad(bool bRelink)
  116. {
  117. int nConnectionsCount = m_Connections.Count();
  118. for (int nConnections = 0; nConnections < nConnectionsCount; nConnections++)
  119. {
  120. CEntityConnection *pConnection = m_Connections.Element(nConnections);
  121. CMapEntityList *pTargetEntities = pConnection->GetTargetEntityList();
  122. int nEntityCount = pTargetEntities->Count();
  123. for ( int nEntities = 0; nEntities < nEntityCount; nEntities++ )
  124. {
  125. CMapEntity *pEntity = pTargetEntities->Element(nEntities);
  126. // If you hit this assert it means that an entity was deleted but not removed
  127. // from this entity's list of targets.
  128. ASSERT( pEntity != NULL );
  129. if ( pEntity )
  130. {
  131. pEntity->Upstream_Remove( pConnection );
  132. }
  133. }
  134. if ( bRelink )
  135. {
  136. pConnection->LinkTargetEntities();
  137. }
  138. }
  139. }
  140. //-----------------------------------------------------------------------------
  141. // Purpose:
  142. // Input : *pConnection -
  143. //-----------------------------------------------------------------------------
  144. void CEditGameClass::Upstream_Add(CEntityConnection *pConnection)
  145. {
  146. #if defined(_DEBUG) && 0
  147. LPCTSTR pszTargetName = GetKeyValue("targetname");
  148. if ( pszTargetName && !strcmp(pszTargetName, "zapperpod7_rotator") )
  149. {
  150. // Set breakpoint here for debugging this entity's visiblity
  151. int foo = 0;
  152. }
  153. #endif
  154. #if defined( ENTITY_MAINTAIN_UPSTREAM_LISTS )
  155. if ( m_Upstream.Find(pConnection) == -1 )
  156. m_Upstream.AddToTail(pConnection);
  157. #endif
  158. }
  159. //-----------------------------------------------------------------------------
  160. // Purpose:
  161. // Input : *pConnection -
  162. // Output : Returns true on success, false on failure.
  163. //-----------------------------------------------------------------------------
  164. bool CEditGameClass::Upstream_Remove(CEntityConnection *pConnection)
  165. {
  166. int nIndex = m_Upstream.Find(pConnection);
  167. if (nIndex != -1)
  168. {
  169. m_Upstream.Remove(nIndex);
  170. return(true);
  171. }
  172. return(false);
  173. }
  174. //-----------------------------------------------------------------------------
  175. // Purpose:
  176. //-----------------------------------------------------------------------------
  177. void CEditGameClass::Upstream_RemoveAll(void)
  178. {
  179. #if defined( ENTITY_MAINTAIN_UPSTREAM_LISTS )
  180. //
  181. // Remove all our connections from their targets' upstream lists.
  182. //
  183. int nUpstreamCount = m_Upstream.Count();
  184. for (int nConnection = 0; nConnection < nUpstreamCount; nConnection++)
  185. {
  186. CEntityConnection *pConnection = m_Upstream.Element( nConnection );
  187. CMapEntityList *pSourceList = pConnection->GetSourceEntityList();
  188. if ( pSourceList )
  189. {
  190. FOR_EACH_OBJ( *pSourceList, pos )
  191. {
  192. CMapEntity *pEntity = pSourceList->Element( pos );
  193. pEntity->Connection_Remove( pConnection );
  194. }
  195. }
  196. }
  197. #endif
  198. m_Upstream.RemoveAll();
  199. }
  200. //-----------------------------------------------------------------------------
  201. // Purpose:
  202. //-----------------------------------------------------------------------------
  203. void CEditGameClass::Upstream_FixBad()
  204. {
  205. #if defined(_DEBUG) && 0
  206. LPCTSTR pszTargetName = GetKeyValue("targetname");
  207. if ( pszTargetName && !strcmp(pszTargetName, "cave_guard_seq1") )
  208. {
  209. // Set breakpoint here for debugging this entity
  210. int foo = 0;
  211. }
  212. #endif
  213. int nUpstreamCount = m_Upstream.Count();
  214. for (int nUpstream = 0; nUpstream < nUpstreamCount; nUpstream++)
  215. {
  216. CEntityConnection *pUpstream = m_Upstream.Element(nUpstream);
  217. pUpstream->LinkTargetEntities();
  218. }
  219. }
  220. //-----------------------------------------------------------------------------
  221. // Purpose:
  222. // Input : pszClass -
  223. // bLoading -
  224. //-----------------------------------------------------------------------------
  225. void CEditGameClass::SetClass(LPCTSTR pszClass, bool bLoading)
  226. {
  227. extern GameData *pGD;
  228. strcpy(m_szClass, pszClass);
  229. StripEdgeWhiteSpace(m_szClass);
  230. if (pGD)
  231. {
  232. m_pClass = pGD->ClassForName(m_szClass);
  233. }
  234. }
  235. //-----------------------------------------------------------------------------
  236. // Purpose: Copies the data from a given CEditGameClass object into this one.
  237. // Input : pFrom - Object to copy.
  238. // Output : Returns a pointer to this.
  239. //-----------------------------------------------------------------------------
  240. CEditGameClass *CEditGameClass::CopyFrom(CEditGameClass *pFrom)
  241. {
  242. m_pClass = pFrom->m_pClass;
  243. strcpy( m_szClass, pFrom->m_szClass );
  244. //
  245. // Copy all the keys.
  246. //
  247. m_KeyValues.RemoveAll();
  248. for ( int i=pFrom->GetFirstKeyValue(); i != pFrom->GetInvalidKeyValue(); i=pFrom->GetNextKeyValue( i ) )
  249. {
  250. m_KeyValues.SetValue(pFrom->GetKey(i), pFrom->GetKeyValue(i));
  251. }
  252. //
  253. // Copy all the connections objects
  254. //
  255. Connections_RemoveAll();
  256. int nConnCount = pFrom->Connections_GetCount();
  257. for (int i = 0; i < nConnCount; i++)
  258. {
  259. CEntityConnection *pConn = pFrom->Connections_Get(i);
  260. CEntityConnection *pNewConn = new CEntityConnection( *pConn );
  261. Connections_Add(pNewConn);
  262. }
  263. //
  264. // Copy the comments.
  265. //
  266. SetComments(pFrom->GetComments());
  267. return(this);
  268. }
  269. //-----------------------------------------------------------------------------
  270. // Purpose: Applies the default keys for this object's game class. Called when
  271. // the entity's class is changed.
  272. //-----------------------------------------------------------------------------
  273. void CEditGameClass::GetDefaultKeys( void )
  274. {
  275. if ( m_pClass != NULL )
  276. {
  277. //
  278. // For each variable from the base class...
  279. //
  280. int nVariableCount = m_pClass->GetVariableCount();
  281. for ( int i = 0; i < nVariableCount; i++ )
  282. {
  283. GDinputvariable *pVar = m_pClass->GetVariableAt(i);
  284. Assert(pVar != NULL);
  285. if (pVar != NULL)
  286. {
  287. int iIndex;
  288. LPCTSTR p = m_KeyValues.GetValue(pVar->GetName(), &iIndex);
  289. //
  290. // If the variable is not present in this object, set the default value.
  291. //
  292. if (p == NULL)
  293. {
  294. MDkeyvalue tmpkv;
  295. pVar->ResetDefaults();
  296. pVar->ToKeyValue(&tmpkv);
  297. //
  298. // Only set the key value if it is non-zero.
  299. //
  300. if ((tmpkv.szKey[0] != 0) && (tmpkv.szValue[0] != 0) && (stricmp(tmpkv.szValue, "0")))
  301. {
  302. SetKeyValue(tmpkv.szKey, tmpkv.szValue);
  303. }
  304. }
  305. }
  306. }
  307. }
  308. }
  309. //-----------------------------------------------------------------------------
  310. // Purpose: Returns this object's angles as a vector of the form:
  311. // [0] PITCH [1] YAW [2] ROLL
  312. //-----------------------------------------------------------------------------
  313. void CEditGameClass::GetAngles(QAngle &vecAngles)
  314. {
  315. vecAngles = vec3_angle;
  316. const char *pszAngles = GetKeyValue("angles");
  317. if (pszAngles != NULL)
  318. {
  319. sscanf(pszAngles, "%f %f %f", &vecAngles[PITCH], &vecAngles[YAW], &vecAngles[ROLL]);
  320. }
  321. }
  322. //-----------------------------------------------------------------------------
  323. // Purpose: Sets a new yaw, overriding any existing angles. Uses special values
  324. // for yaw to indicate pointing straight up or straight down.
  325. //
  326. // This method of representing orientation is obsolete; this code is
  327. // only for importing old RMF or MAP files.
  328. //
  329. // Input : a - Value for angle.
  330. //-----------------------------------------------------------------------------
  331. void CEditGameClass::ImportAngle(int nAngle)
  332. {
  333. QAngle vecAngles;
  334. vecAngles.Init();
  335. if (nAngle == -1) // UP
  336. {
  337. vecAngles[PITCH] = -90;
  338. }
  339. else if (nAngle == -2) // DOWN
  340. {
  341. vecAngles[PITCH] = 90;
  342. }
  343. else
  344. {
  345. vecAngles[YAW] = nAngle;
  346. }
  347. SetAngles(vecAngles);
  348. }
  349. //-----------------------------------------------------------------------------
  350. // Purpose: Sets this object's angles as a vector of the form:
  351. // [0] PITCH [1] YAW [2] ROLL
  352. //-----------------------------------------------------------------------------
  353. void CEditGameClass::SetAngles(const QAngle &vecAngles)
  354. {
  355. char szAngles[80];
  356. sprintf(szAngles, "%g %g %g", (double)vecAngles[PITCH], (double)vecAngles[YAW], (double)vecAngles[ROLL]);
  357. SetKeyValue("angles", szAngles);
  358. }
  359. //-----------------------------------------------------------------------------
  360. // Purpose:
  361. // Input : *pFile -
  362. // Output : ChunkFileResult_t
  363. //-----------------------------------------------------------------------------
  364. ChunkFileResult_t CEditGameClass::SaveVMF(CChunkFile *pFile, CSaveInfo *pSaveInfo)
  365. {
  366. ChunkFileResult_t eResult = pFile->WriteKeyValue("classname", m_szClass);
  367. if (eResult != ChunkFile_Ok)
  368. {
  369. return(eResult);
  370. }
  371. //
  372. // Determine whether we have a game data class. This will help us decide which keys
  373. // to write.
  374. //
  375. GDclass *pGameDataClass = NULL;
  376. if (pGD != NULL)
  377. {
  378. pGameDataClass = pGD->ClassForName(m_szClass);
  379. }
  380. //
  381. // Consider all the keyvalues in this object for serialization.
  382. //
  383. for ( int z=m_KeyValues.GetFirst(); z != m_KeyValues.GetInvalidIndex(); z=m_KeyValues.GetNext( z ) )
  384. {
  385. MDkeyvalue &KeyValue = m_KeyValues.GetKeyValue(z);
  386. //
  387. // Don't write keys that were already written above.
  388. //
  389. bool bAlreadyWritten = false;
  390. if (!stricmp(KeyValue.szKey, "classname"))
  391. {
  392. bAlreadyWritten = true;
  393. }
  394. //
  395. // If the variable wasn't already written above.
  396. //
  397. if (!bAlreadyWritten)
  398. {
  399. //
  400. // Write it to the MAP file.
  401. //
  402. eResult = pFile->WriteKeyValue(KeyValue.szKey, KeyValue.szValue);
  403. if (eResult != ChunkFile_Ok)
  404. {
  405. return(eResult);
  406. }
  407. }
  408. }
  409. //
  410. // If we have a game data class, for each keyvalue in the class definition, write out all keys
  411. // that are not present in the object and whose defaults are nonzero in the class definition.
  412. //
  413. if (pGameDataClass != NULL)
  414. {
  415. //
  416. // For each variable from the base class...
  417. //
  418. int nVariableCount = pGameDataClass->GetVariableCount();
  419. for (int i = 0; i < nVariableCount; i++)
  420. {
  421. GDinputvariable *pVar = pGameDataClass->GetVariableAt(i);
  422. Assert(pVar != NULL);
  423. if (pVar != NULL)
  424. {
  425. int iIndex;
  426. LPCTSTR p = m_KeyValues.GetValue(pVar->GetName(), &iIndex);
  427. //
  428. // If the variable is not present in this object, write out the default value.
  429. //
  430. if (p == NULL)
  431. {
  432. MDkeyvalue TempKey;
  433. pVar->ResetDefaults();
  434. pVar->ToKeyValue(&TempKey);
  435. //
  436. // Only write the key value if it is non-zero.
  437. //
  438. if ((TempKey.szKey[0] != 0) && (TempKey.szValue[0] != 0) && (stricmp(TempKey.szValue, "0")))
  439. {
  440. eResult = pFile->WriteKeyValue(TempKey.szKey, TempKey.szValue);
  441. if (eResult != ChunkFile_Ok)
  442. {
  443. return(eResult);
  444. }
  445. }
  446. }
  447. }
  448. }
  449. }
  450. //
  451. // Save all the connections.
  452. //
  453. if ((eResult == ChunkFile_Ok) && (Connections_GetCount() > 0))
  454. {
  455. eResult = pFile->BeginChunk("connections");
  456. if (eResult == ChunkFile_Ok)
  457. {
  458. int nConnCount = Connections_GetCount();
  459. for (int i = 0; i < nConnCount; i++)
  460. {
  461. CEntityConnection *pConnection = Connections_Get(i);
  462. if (pConnection != NULL)
  463. {
  464. char szTemp[512];
  465. sprintf(szTemp, "%s%c%s%c%s%c%g%c%d", pConnection->GetTargetName(), VMF_IOPARAM_STRING_DELIMITER,
  466. pConnection->GetInputName(), VMF_IOPARAM_STRING_DELIMITER, pConnection->GetParam(), VMF_IOPARAM_STRING_DELIMITER,
  467. pConnection->GetDelay(), VMF_IOPARAM_STRING_DELIMITER, pConnection->GetTimesToFire());
  468. eResult = pFile->WriteKeyValue(pConnection->GetOutputName(), szTemp);
  469. if (eResult != ChunkFile_Ok)
  470. {
  471. return(eResult);
  472. }
  473. }
  474. }
  475. eResult = pFile->EndChunk();
  476. }
  477. }
  478. return(eResult);
  479. }
  480. //-----------------------------------------------------------------------------
  481. // Purpose: Slightly modified strtok. Does not modify the input string. Does
  482. // not skip over more than one separator at a time. This allows parsing
  483. // strings where tokens between separators may or may not be present:
  484. //
  485. // Door01,,,0 would be parsed as "Door01" "" "" "0"
  486. // Door01,Open,,0 would be parsed as "Door01" "Open" "" "0"
  487. //
  488. // Input : token - Returns with a token, or zero length if the token was missing.
  489. // str - String to parse.
  490. // sep - Character to use as separator. UNDONE: allow multiple separator chars
  491. // Output : Returns a pointer to the next token to be parsed.
  492. //-----------------------------------------------------------------------------
  493. static const char *nexttoken_gameclass(char *token, const char *str, char sep)
  494. {
  495. if (*str == '\0')
  496. {
  497. return(NULL);
  498. }
  499. //
  500. // Find the first separator.
  501. //
  502. const char *ret = str;
  503. while ((*str != sep) && (*str != '\0'))
  504. {
  505. str++;
  506. }
  507. //
  508. // Copy everything up to the first separator into the return buffer.
  509. // Do not include separators in the return buffer.
  510. //
  511. while (ret < str)
  512. {
  513. *token++ = *ret++;
  514. }
  515. *token = '\0';
  516. //
  517. // Advance the pointer unless we hit the end of the input string.
  518. //
  519. if (*str == '\0')
  520. {
  521. return(str);
  522. }
  523. return(++str);
  524. }
  525. //-----------------------------------------------------------------------------
  526. // Purpose: Builds a connection from a keyvalue pair.
  527. // Input : szKey - Contains the name of the output.
  528. // szValue - Contains the target, input, delay, and parameter, comma delimited.
  529. // pEditGameClass - Entity to receive the connection.
  530. // Output : Returns ChunkFile_Ok if the data was well-formed, ChunkFile_Fail if not.
  531. //-----------------------------------------------------------------------------
  532. ChunkFileResult_t CEditGameClass::LoadKeyCallback(const char *szKey, const char *szValue, CEditGameClass *pEditGameClass)
  533. {
  534. CEntityConnection *pConnection = new CEntityConnection;
  535. // Set the "source" name to be the name of the pEditGameClass' targetname
  536. pConnection->SetSourceName( pEditGameClass->GetKeyValue("targetname") ); // Use the classname if no targetname is defined?
  537. // Set the "output" from the passed in parameter
  538. pConnection->SetOutputName(szKey);
  539. // Figure out what delimiter to use. We switched from commas to the nonprintable
  540. // character 0x07 when we added the ability to execute vscript code in an input.
  541. char chDelim = VMF_IOPARAM_STRING_DELIMITER;
  542. if (strchr(szValue, VMF_IOPARAM_STRING_DELIMITER) == NULL)
  543. {
  544. chDelim = ',';
  545. }
  546. char szToken[MAX_PATH];
  547. //
  548. // Parse the target name.
  549. //
  550. const char *psz = nexttoken_gameclass(szToken, szValue, chDelim);
  551. if (szToken[0] != '\0')
  552. {
  553. pConnection->SetTargetName(szToken);
  554. }
  555. //
  556. // Parse the input name.
  557. //
  558. psz = nexttoken_gameclass(szToken, psz, chDelim);
  559. if (szToken[0] != '\0')
  560. {
  561. pConnection->SetInputName(szToken);
  562. }
  563. //
  564. // Parse the parameter override.
  565. //
  566. psz = nexttoken_gameclass(szToken, psz, chDelim);
  567. if (szToken[0] != '\0')
  568. {
  569. pConnection->SetParam(szToken);
  570. }
  571. //
  572. // Parse the delay.
  573. //
  574. psz = nexttoken_gameclass(szToken, psz, chDelim);
  575. if (szToken[0] != '\0')
  576. {
  577. pConnection->SetDelay((float)atof(szToken));
  578. }
  579. //
  580. // Parse the number of times to fire the output.
  581. //
  582. nexttoken_gameclass(szToken, psz, chDelim);
  583. if (szToken[0] != '\0')
  584. {
  585. pConnection->SetTimesToFire(atoi(szToken));
  586. }
  587. pEditGameClass->Connections_Add(pConnection); // Does this belong here or SetSourceName or LinkSourceEntities??
  588. return(ChunkFile_Ok);
  589. }
  590. //-----------------------------------------------------------------------------
  591. // Purpose:
  592. // Input : *pFile -
  593. // *pEntity -
  594. // Output : ChunkFileResult_t
  595. //-----------------------------------------------------------------------------
  596. ChunkFileResult_t CEditGameClass::LoadConnectionsCallback(CChunkFile *pFile, CEditGameClass *pEditGameClass)
  597. {
  598. return(pFile->ReadChunk((KeyHandler_t)LoadKeyCallback, pEditGameClass));
  599. }
  600. //-----------------------------------------------------------------------------
  601. // Purpose: Returns all the spawnflags.
  602. //-----------------------------------------------------------------------------
  603. unsigned long CEditGameClass::GetSpawnFlags(void)
  604. {
  605. LPCTSTR pszVal = GetKeyValue("spawnflags");
  606. if (pszVal == NULL)
  607. {
  608. return(0);
  609. }
  610. unsigned long val = 0;
  611. sscanf( pszVal, "%lu", &val );
  612. return val;
  613. }
  614. //-----------------------------------------------------------------------------
  615. // Purpose: Returns true if a given spawnflag (or flags) is set, false if not.
  616. //-----------------------------------------------------------------------------
  617. bool CEditGameClass::GetSpawnFlag(unsigned long nFlags)
  618. {
  619. unsigned long nSpawnFlags = GetSpawnFlags();
  620. return((nSpawnFlags & nFlags) != 0);
  621. }
  622. //-----------------------------------------------------------------------------
  623. // Purpose: Sets the given spawnflag (or flags) to the given state.
  624. // Input : nFlag - Flag values to set or clear (ie 1, 2, 4, 8, 16, etc.)
  625. // bSet - True to set the flags, false to clear them.
  626. //-----------------------------------------------------------------------------
  627. void CEditGameClass::SetSpawnFlag(unsigned long nFlags, bool bSet)
  628. {
  629. unsigned long nSpawnFlags = GetSpawnFlags();
  630. if (bSet)
  631. {
  632. nSpawnFlags |= nFlags;
  633. }
  634. else
  635. {
  636. nSpawnFlags &= ~nFlags;
  637. }
  638. SetSpawnFlags(nSpawnFlags);
  639. }
  640. //-----------------------------------------------------------------------------
  641. // Purpose: Sets all the spawnflags at once.
  642. // Input : nSpawnFlags - New value for spawnflags.
  643. //-----------------------------------------------------------------------------
  644. void CEditGameClass::SetSpawnFlags(unsigned long nSpawnFlags)
  645. {
  646. char szValue[80];
  647. V_snprintf( szValue, sizeof( szValue ), "%lu", nSpawnFlags );
  648. SetKeyValue("spawnflags", nSpawnFlags);
  649. }