RM_Mission.cpp 58 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931
  1. /************************************************************************************************
  2. *
  3. * RM_Mission.cpp
  4. *
  5. * implements the CRMMission class. The CRMMission class loads and manages an arioche mission
  6. *
  7. ************************************************************************************************/
  8. #include "../server/exe_headers.h"
  9. #include "rm_headers.h"
  10. #define ARIOCHE_CLIPBRUSH_SIZE 300
  11. #define CVAR_OBJECTIVE 0
  12. /************************************************************************************************
  13. * CRMMission::CRMMission
  14. * constructor
  15. *
  16. * inputs:
  17. * none
  18. *
  19. * return:
  20. * none
  21. *
  22. ************************************************************************************************/
  23. CRMMission::CRMMission ( CRandomTerrain* landscape )
  24. {
  25. mCurrentObjective = NULL;
  26. mValidPaths = false;
  27. mValidRivers = false;
  28. mValidNodes = false;
  29. mValidWeapons = false;
  30. mValidAmmo = false;
  31. mValidObjectives = false;
  32. mValidInstances = false;
  33. mTimeLimit = 0;
  34. mMaxInstancePosition = 1;
  35. mAccuracyMultiplier = 1.0f;
  36. mHealthMultiplier = 1.0f;
  37. mPickupHealth = 1.0f;
  38. mPickupArmor = 1.0f;
  39. mPickupAmmo = 1.0f;
  40. mPickupWeapon = 1.0f;
  41. mPickupEquipment = 1.0f;
  42. mDefaultPadding = 0;
  43. mSymmetric = SYMMETRY_NONE;
  44. // mCheckedEnts.clear();
  45. mLandScape = landscape;
  46. // cut down the possible area that is 'legal' for area manager to use by 20%
  47. vec3_t land_min, land_max;
  48. land_min[0] = mLandScape->GetBounds ( )[0][0] + (mLandScape->GetBounds ( )[1][0]-mLandScape->GetBounds ( )[0][0]) * 0.1f;
  49. land_min[1] = mLandScape->GetBounds ( )[0][1] + (mLandScape->GetBounds ( )[1][1]-mLandScape->GetBounds ( )[0][1]) * 0.1f;
  50. land_min[2] = mLandScape->GetBounds ( )[0][2] + (mLandScape->GetBounds ( )[1][2]-mLandScape->GetBounds ( )[0][2]) * 0.1f;
  51. land_max[0] = mLandScape->GetBounds ( )[1][0] - (mLandScape->GetBounds ( )[1][0]-mLandScape->GetBounds ( )[0][0]) * 0.1f;
  52. land_max[1] = mLandScape->GetBounds ( )[1][1] - (mLandScape->GetBounds ( )[1][1]-mLandScape->GetBounds ( )[0][1]) * 0.1f;
  53. land_max[2] = mLandScape->GetBounds ( )[1][2] - (mLandScape->GetBounds ( )[1][2]-mLandScape->GetBounds ( )[0][2]) * 0.1f;
  54. // Create a new area manager for the landscape
  55. mAreaManager = new CRMAreaManager ( land_min,
  56. land_max );
  57. // Create a new path manager
  58. mPathManager = new CRMPathManager ( mLandScape );
  59. }
  60. /************************************************************************************************
  61. * CRMMission::~CRMMission
  62. * destructor
  63. *
  64. * inputs:
  65. * none
  66. *
  67. * return:
  68. * none
  69. *
  70. ************************************************************************************************/
  71. CRMMission::~CRMMission ( )
  72. {
  73. rmObjectiveIter_t oit;
  74. rmInstanceIter_t iit;
  75. // mCheckedEnts.clear();
  76. // Cleanup the objectives
  77. for (oit = mObjectives.begin(); oit != mObjectives.end(); oit++)
  78. {
  79. delete (*oit);
  80. }
  81. // Cleanup the instances
  82. for (iit = mInstances.begin(); iit != mInstances.end(); iit++)
  83. {
  84. delete (*iit);
  85. }
  86. if (mPathManager)
  87. {
  88. delete mPathManager;
  89. mPathManager = 0;
  90. }
  91. if (mAreaManager)
  92. {
  93. delete mAreaManager;
  94. mAreaManager = 0;
  95. }
  96. }
  97. /************************************************************************************************
  98. * CRMMission::FindObjective
  99. * searches through the missions objectives for the one with the given name
  100. *
  101. * inputs:
  102. * name: name of objective to find
  103. *
  104. * return:
  105. * objective: objective matching the given name or NULL if it couldnt be found
  106. *
  107. ************************************************************************************************/
  108. CRMObjective* CRMMission::FindObjective ( const char* name )
  109. {
  110. rmObjectiveIter_t it;
  111. for (it = mObjectives.begin(); it != mObjectives.end(); it++)
  112. {
  113. // Does it match?
  114. if (!stricmp ((*it)->GetName(), name ))
  115. {
  116. return (*it);
  117. }
  118. }
  119. // Not found
  120. return NULL;
  121. }
  122. void CRMMission::MirrorPos(vec3_t pos)
  123. {
  124. pos[0] = 1.0f - pos[0];
  125. pos[1] = 1.0f - pos[1];
  126. }
  127. /************************************************************************************************
  128. * CRMMission::ParseOrigin
  129. * parses an origin block which includes linking to a node and absolute origins
  130. *
  131. * inputs:
  132. * group: parser group containing the node or origin
  133. *
  134. * return:
  135. * true: parsed successfully
  136. * false: failed to parse
  137. *
  138. ************************************************************************************************/
  139. bool CRMMission::ParseOrigin ( CGPGroup* originGroup, vec3_t origin, vec3_t lookat, int* flattenHeight )
  140. {
  141. const char* szNodeName;
  142. vec3_t mins;
  143. vec3_t maxs;
  144. if ( flattenHeight )
  145. {
  146. *flattenHeight = 66;
  147. }
  148. // If no group was given then use 0,0,0
  149. if ( NULL == originGroup )
  150. {
  151. VectorCopy ( vec3_origin, origin );
  152. return false;
  153. }
  154. // See if attaching to a named node
  155. szNodeName = originGroup->FindPairValue ( "node", "" );
  156. if ( *szNodeName )
  157. {
  158. CRMNode* node;
  159. // Find the node being attached to
  160. node = mPathManager->FindNodeByName ( szNodeName );
  161. if ( node )
  162. {
  163. if ( flattenHeight )
  164. {
  165. if ( node->GetFlattenHeight ( ) == -1 )
  166. {
  167. node->SetFlattenHeight ( 40 + mLandScape->irand(0,40) );
  168. }
  169. *flattenHeight = node->GetFlattenHeight ( );
  170. }
  171. VectorCopy(node->GetPos(), origin);
  172. VectorCopy ( origin, lookat );
  173. int dir;
  174. int rnd_offset = mLandScape->irand(0, DIR_MAX-1);
  175. for (dir=0; dir<DIR_MAX; dir++)
  176. {
  177. int d = (dir + rnd_offset) % DIR_MAX;
  178. if (node->PathExist(d))
  179. {
  180. vec4_t tmp_pt, tmp_dir;
  181. int pathID = node->GetPath(d);
  182. mLandScape->GetPathInfo(pathID, 0.1f, tmp_pt, tmp_dir );
  183. lookat[0] = tmp_pt[0];
  184. lookat[1] = tmp_pt[1];
  185. lookat[2] = 0;
  186. return true;
  187. }
  188. }
  189. return true;
  190. }
  191. }
  192. mins[0] = atof( originGroup->FindPairValue ( "left", ".1" ) );
  193. mins[1] = atof( originGroup->FindPairValue ( "top", ".1" ) );
  194. maxs[0] = atof( originGroup->FindPairValue ( "right", ".9" ) );
  195. maxs[1] = atof( originGroup->FindPairValue ( "bottom", ".9" ) );
  196. lookat[0] = origin[0] = mLandScape->flrand(mins[0],maxs[0]);
  197. lookat[1] = origin[1] = mLandScape->flrand(mins[1],maxs[1]);
  198. lookat[2] = origin[2] = 0;
  199. return true;
  200. }
  201. /************************************************************************************************
  202. * CRMMission::ParseNodes
  203. * parses all the named nodes in the file
  204. *
  205. * inputs:
  206. * group: parser group containing the named nodes
  207. *
  208. * return:
  209. * true: parsed successfully
  210. * false: failed to parse
  211. *
  212. ************************************************************************************************/
  213. bool CRMMission::ParseNodes ( CGPGroup* group )
  214. {
  215. // If NULL that means this particular difficulty level has no named nodes
  216. if ( NULL == group || mValidNodes)
  217. {
  218. return true;
  219. }
  220. // how many nodes spaced over map?
  221. int x_cells;
  222. int y_cells;
  223. x_cells = atoi ( group->FindPairValue ( "x_cells", "3" ) );
  224. y_cells = atoi ( group->FindPairValue ( "y_cells", "3" ) );
  225. mPathManager->CreateArray(x_cells, y_cells);
  226. // Loop through all the nodes and generate each as specified
  227. for ( group = group->GetSubGroups();
  228. group;
  229. group=group->GetNext() )
  230. {
  231. int min_depth = atof( group->FindPairValue ( "min_depth", "0" ) );
  232. int max_depth = atof( group->FindPairValue ( "max_depth", "5" ) );
  233. int min_paths = atoi( group->FindPairValue ( "min_paths", "1" ) );
  234. int max_paths = atoi( group->FindPairValue ( "max_paths", "1" ) );
  235. mPathManager->CreateLocation( group->GetName(), min_depth, max_depth, min_paths, max_paths );
  236. }
  237. mValidNodes = true;
  238. return true;
  239. }
  240. /************************************************************************************************
  241. * CRMMission::ParsePaths
  242. * parses all path styles in the file and then generates paths
  243. *
  244. * inputs:
  245. * group: parser group containing the list of path styles
  246. *
  247. * return:
  248. * true: parsed successfully
  249. * false: failed to parse
  250. *
  251. ************************************************************************************************/
  252. bool CRMMission::ParsePaths ( CGPGroup* group )
  253. {
  254. // If NULL that means this particular difficulty level has no paths
  255. if ( NULL == group || mValidPaths)
  256. {
  257. return true;
  258. }
  259. // path style info
  260. float depth;
  261. float deviation;
  262. float breadth;
  263. float minwidth;
  264. float maxwidth;
  265. int points;
  266. points = atoi ( group->FindPairValue ( "points", "10" ) );
  267. depth = atof ( group->FindPairValue ( "depth", ".31" ) );
  268. deviation = atof ( group->FindPairValue ( "deviation", ".025" ) );
  269. breadth = atof ( group->FindPairValue ( "breadth", "5" ) );
  270. minwidth = atof ( group->FindPairValue ( "minwidth", ".03" ) );
  271. maxwidth = atof ( group->FindPairValue ( "maxwidth", ".05" ) );
  272. mPathManager->SetPathStyle( points, minwidth, maxwidth, depth, deviation, breadth);
  273. if (!mValidPaths)
  274. { // we must create paths
  275. mPathManager->GeneratePaths( mSymmetric );
  276. mValidPaths = true;
  277. }
  278. return true;
  279. }
  280. /************************************************************************************************
  281. * CRMMission::ParseRivers
  282. * parses all river styles in the file and then generates rivers
  283. *
  284. * inputs:
  285. * group: parser group containing the list of path styles
  286. *
  287. * return:
  288. * true: parsed successfully
  289. * false: failed to parse
  290. *
  291. ************************************************************************************************/
  292. bool CRMMission::ParseRivers ( CGPGroup* group )
  293. {
  294. // If NULL that means this particular difficulty level has no rivers
  295. if ( NULL == group || mValidRivers)
  296. {
  297. return true;
  298. }
  299. // river style info
  300. int maxdepth;
  301. float beddepth;
  302. float deviation;
  303. float breadth;
  304. float minwidth;
  305. float maxwidth;
  306. int points;
  307. string bridge_name;
  308. maxdepth = atoi ( group->FindPairValue ( "maxpathdepth", "5" ) );
  309. points = atoi ( group->FindPairValue ( "points", "10" ) );
  310. beddepth = atof ( group->FindPairValue ( "depth", "1" ) );
  311. deviation = atof ( group->FindPairValue ( "deviation", ".03" ) );
  312. breadth = atof ( group->FindPairValue ( "breadth", "7" ) );
  313. minwidth = atof ( group->FindPairValue ( "minwidth", ".01" ) );
  314. maxwidth = atof ( group->FindPairValue ( "maxwidth", ".03" ) );
  315. bridge_name= group->FindPairValue ( "bridge", "" ) ;
  316. mPathManager->SetRiverStyle( maxdepth, points, minwidth, maxwidth, beddepth, deviation, breadth, bridge_name);
  317. if (!mValidRivers &&
  318. beddepth < 1) // use a depth of 1 if we don't want any rivers
  319. { // we must create rivers
  320. mPathManager->GenerateRivers();
  321. mValidRivers = true;
  322. }
  323. return true;
  324. }
  325. void CRMMission::PlaceBridges()
  326. {
  327. if (!mValidRivers || strlen(mPathManager->GetBridgeName()) < 1)
  328. return;
  329. int max_bridges = 0;
  330. int path;
  331. float t;
  332. float river_depth = mLandScape->GetLandScape()->GetWaterHeight();
  333. vec3_t pos, lastpos;
  334. vec3pair_t bounds;
  335. VectorSet(bounds[0], 0,0,0);
  336. VectorSet(bounds[1], 0,0,0);
  337. // walk along paths looking for dips
  338. for (path = 0; path < mPathManager->GetPathCount(); path++)
  339. {
  340. vec4_t tmp_pt, tmp_dir;
  341. bool new_water = true;
  342. mLandScape->GetPathInfo(path, 0, tmp_pt, tmp_dir );
  343. lastpos[0] = mLandScape->GetBounds ( )[0][0] + (mLandScape->GetBounds ( )[1][0]-mLandScape->GetBounds ( )[0][0]) * tmp_pt[0];
  344. lastpos[1] = mLandScape->GetBounds ( )[0][1] + (mLandScape->GetBounds ( )[1][1]-mLandScape->GetBounds ( )[0][1]) * tmp_pt[1];
  345. lastpos[2] = mLandScape->GetBounds ( )[0][2] + (mLandScape->GetBounds ( )[1][2]-mLandScape->GetBounds ( )[0][2]) * tmp_pt[2];
  346. mLandScape->GetLandScape()->GetWorldHeight ( lastpos, bounds, true );
  347. const float delta = 0.05f;
  348. for (t= delta; t < 1.0f; t += delta)
  349. {
  350. mLandScape->GetPathInfo(path, t, tmp_pt, tmp_dir );
  351. pos[0] = mLandScape->GetBounds ( )[0][0] + (mLandScape->GetBounds ( )[1][0]-mLandScape->GetBounds ( )[0][0]) * tmp_pt[0];
  352. pos[1] = mLandScape->GetBounds ( )[0][1] + (mLandScape->GetBounds ( )[1][1]-mLandScape->GetBounds ( )[0][1]) * tmp_pt[1];
  353. pos[2] = mLandScape->GetBounds ( )[0][2] + (mLandScape->GetBounds ( )[1][2]-mLandScape->GetBounds ( )[0][2]) * tmp_pt[2];
  354. mLandScape->GetLandScape()->GetWorldHeight ( pos, bounds, true );
  355. if (new_water &&
  356. lastpos[2] < river_depth &&
  357. pos[2] < river_depth &&
  358. pos[2] > lastpos[2])
  359. { // add a bridge
  360. if (max_bridges < 3)
  361. {
  362. CRMArea* area;
  363. CRMInstance* instance;
  364. max_bridges++;
  365. // create a single bridge
  366. lastpos[2] = mLandScape->GetBounds ( )[0][2] + (mLandScape->GetBounds ( )[1][2]-mLandScape->GetBounds ( )[0][2]) * mPathManager->GetPathDepth();
  367. instance = mInstanceFile.CreateInstance ( mPathManager->GetBridgeName() );
  368. if ( NULL != instance )
  369. { // Set the area
  370. vec3_t zerodvec;
  371. VectorClear(zerodvec);
  372. area = mAreaManager->CreateArea ( lastpos, instance->GetSpacingRadius(), instance->GetSpacingLine(), GetDefaultPadding(), 0, zerodvec, pos, instance->GetFlattenRadius()?true:false, false, instance->GetLockOrigin() );
  373. area->EnableLookAt(false);
  374. instance->SetArea ( mAreaManager, area );
  375. mInstances.push_back ( instance );
  376. new_water = false;
  377. }
  378. }
  379. }
  380. else if (pos[2] > river_depth)
  381. { // hit land again
  382. new_water = true;
  383. }
  384. VectorCopy ( pos, lastpos );
  385. }
  386. }
  387. }
  388. void CRMMission::PlaceWallInstance(CRMInstance* instance, float xpos, float ypos, float zpos, int x, int y, float angle)
  389. {
  390. if (NULL == instance)
  391. return;
  392. float spacing = instance->GetSpacingRadius();
  393. CRMArea* area;
  394. vec3_t origin;
  395. vec3_t zerodvec;
  396. VectorClear(zerodvec);
  397. origin[0] = xpos + spacing * x;
  398. origin[1] = ypos + spacing * y;
  399. origin[2] = zpos;
  400. // Set the area of position
  401. area = mAreaManager->CreateArea ( origin, (spacing / 2.1f), 0, GetDefaultPadding(), 0, zerodvec, origin, instance->GetFlattenRadius()?true:false, false, instance->GetLockOrigin() );
  402. area->EnableLookAt(false);
  403. area->SetAngle(angle);
  404. instance->SetArea ( mAreaManager, area );
  405. mInstances.push_back ( instance );
  406. }
  407. /************************************************************************************************
  408. * CRMMission::ParseWallRect
  409. * creates instances for walled rectangle at this node (fence)
  410. *
  411. * inputs:
  412. * group: parser group containing the wall rect info
  413. *
  414. * return:
  415. * true: parsed successfully
  416. * false: failed to parse
  417. *
  418. ************************************************************************************************/
  419. bool CRMMission::ParseWallRect(CGPGroup* group , int side)
  420. {
  421. #ifndef PRE_RELEASE_DEMO
  422. CGPGroup* wallGroup = group->FindSubGroup ( "wallrect" ) ;
  423. // If NULL that means this particular instance has no wall rect
  424. if ( NULL == group || NULL == wallGroup)
  425. {
  426. return true;
  427. }
  428. const char* wallName = wallGroup->FindPairValue ( "wall_instance", "" );
  429. const char* cornerName = wallGroup->FindPairValue ( "corner_instance", "" );
  430. const char* towerName = wallGroup->FindPairValue ( "tower_instance", "" );
  431. const char* gateName = wallGroup->FindPairValue ( "gate_instance", "" );
  432. const char* ripName = wallGroup->FindPairValue ( "rip_instance", "" );
  433. if ( NULL != wallName )
  434. {
  435. int xcount = atoi( wallGroup->FindPairValue ( "xcount", "0" ) );
  436. int ycount = atoi( wallGroup->FindPairValue ( "ycount", "0" ) );
  437. int gateCount = atoi( wallGroup->FindPairValue ( "gate_count", "1" ) );
  438. int gateMin = atoi( wallGroup->FindPairValue ( "gate_min", "0" ) );
  439. int gateMax = atoi( wallGroup->FindPairValue ( "gate_max", "0" ) );
  440. int ripCount = atoi( wallGroup->FindPairValue ( "rip_count", "0" ) );
  441. int ripMin = atoi( wallGroup->FindPairValue ( "rip_min", "0" ) );
  442. int ripMax = atoi( wallGroup->FindPairValue ( "rip_max", "0" ) );
  443. int towerCount = atoi( wallGroup->FindPairValue ( "tower_count", "0" ) );
  444. int towerMin = atoi( wallGroup->FindPairValue ( "tower_min", "0" ) );
  445. int towerMax = atoi( wallGroup->FindPairValue ( "tower_max", "0" ) );
  446. if (gateMin != gateMax)
  447. gateCount = mLandScape->irand(gateMin,gateMax);
  448. if (ripMin != ripMax)
  449. ripCount = mLandScape->irand(ripMin,ripMax);
  450. if (towerMin != towerMax)
  451. towerCount = mLandScape->irand(towerMin,towerMax);
  452. if (NULL == gateName)
  453. gateCount = 0;
  454. if (NULL == towerName)
  455. towerCount = 0;
  456. if (NULL == ripName)
  457. ripCount = 0;
  458. const char* nodename;
  459. CGPGroup* originGroup = group->FindSubGroup ( "origin" );
  460. if (originGroup)
  461. {
  462. nodename = originGroup->FindPairValue ( "node", "" );
  463. if (*nodename)
  464. {
  465. CRMNode* node;
  466. // Find the node being attached to
  467. node = mPathManager->FindNodeByName ( nodename );
  468. if ( node )
  469. {
  470. CRMInstance* instance;
  471. int x,y;
  472. int halfx = xcount/2;
  473. int halfy = ycount/2;
  474. float xpos = mLandScape->GetBounds ( )[0][0] + (mLandScape->GetBounds ( )[1][0]-mLandScape->GetBounds ( )[0][0]) * node->GetPos()[0];
  475. float ypos = mLandScape->GetBounds ( )[0][1] + (mLandScape->GetBounds ( )[1][1]-mLandScape->GetBounds ( )[0][1]) * node->GetPos()[1];
  476. float zpos = mLandScape->GetBounds ( )[1][2] + 100;
  477. float angle = 0;
  478. int lastGate = 0;
  479. int lastRip = 0;
  480. // corners
  481. x = -halfx;
  482. y = -halfy;
  483. if (towerCount > 3 ||
  484. (towerCount > 0 && mLandScape->irand(1,2) == 1) )
  485. {
  486. towerCount--;
  487. instance = mInstanceFile.CreateInstance ( towerName );
  488. }
  489. else
  490. instance = mInstanceFile.CreateInstance ( cornerName );
  491. angle = (float)DEG2RAD(90);
  492. instance->SetSide(side);
  493. PlaceWallInstance(instance, xpos, ypos, zpos, x, y, angle);
  494. x = halfx;
  495. y = -halfy;
  496. if (towerCount > 3 ||
  497. (towerCount > 0 && mLandScape->irand(1,2) == 1) )
  498. {
  499. towerCount--;
  500. instance = mInstanceFile.CreateInstance ( towerName );
  501. }
  502. else
  503. instance = mInstanceFile.CreateInstance ( cornerName );
  504. angle = (float)DEG2RAD(180);
  505. instance->SetSide(side);
  506. PlaceWallInstance(instance, xpos, ypos, zpos, x, y, angle);
  507. x = halfx;
  508. y = halfy;
  509. if (towerCount > 3 ||
  510. (towerCount > 0 && mLandScape->irand(1,2) == 1) )
  511. {
  512. towerCount--;
  513. instance = mInstanceFile.CreateInstance ( towerName );
  514. }
  515. else
  516. instance = mInstanceFile.CreateInstance ( cornerName );
  517. angle = (float)DEG2RAD(270);
  518. instance->SetSide(side);
  519. PlaceWallInstance(instance, xpos, ypos, zpos, x, y, angle);
  520. x = -halfx;
  521. y = halfy;
  522. if (towerCount > 3 ||
  523. (towerCount > 0 && mLandScape->irand(1,2) == 1) )
  524. {
  525. towerCount--;
  526. instance = mInstanceFile.CreateInstance ( towerName );
  527. }
  528. else
  529. instance = mInstanceFile.CreateInstance ( cornerName );
  530. angle = DEG2RAD(0);
  531. instance->SetSide(side);
  532. PlaceWallInstance(instance, xpos, ypos, zpos, x, y, angle);
  533. // walls
  534. angle = DEG2RAD(0);
  535. for (x = -halfx+1; x <= halfx-1; x++)
  536. {
  537. if (lastGate<1 && gateCount > 0 && mLandScape->irand(1,(halfx+halfy)/gateCount) == 1)
  538. { // gate
  539. gateCount--;
  540. lastGate = 3;
  541. instance = mInstanceFile.CreateInstance ( gateName );
  542. }
  543. else if (lastRip<1 && ripCount > 0 && mLandScape->irand(1,(halfx+halfy)/ripCount) == 1)
  544. { // damaged fence
  545. ripCount--;
  546. lastRip = 3;
  547. instance = mInstanceFile.CreateInstance ( ripName );
  548. }
  549. else
  550. { // just a wall
  551. instance = mInstanceFile.CreateInstance ( wallName );
  552. lastRip--;
  553. lastGate--;
  554. }
  555. instance->SetSide(side);
  556. PlaceWallInstance(instance, xpos, ypos, zpos, x, -halfy, angle);
  557. }
  558. for (x = -halfx+1; x <= halfx-1; x++)
  559. {
  560. if (lastGate<1 && gateCount > 0 && mLandScape->irand(1,(halfx+halfy)/gateCount) == 1)
  561. { // gate
  562. gateCount--;
  563. lastGate = 3;
  564. instance = mInstanceFile.CreateInstance ( gateName );
  565. }
  566. else if (lastRip<1 && ripCount > 0 && mLandScape->irand(1,(halfx+halfy)/ripCount) == 1)
  567. { // damaged fence
  568. ripCount--;
  569. lastRip = 3;
  570. instance = mInstanceFile.CreateInstance ( ripName );
  571. }
  572. else
  573. { // just a wall
  574. instance = mInstanceFile.CreateInstance ( wallName );
  575. lastRip--;
  576. lastGate--;
  577. }
  578. instance->SetSide(side);
  579. PlaceWallInstance(instance, xpos, ypos, zpos, x, halfy, angle);
  580. }
  581. angle = (float)DEG2RAD(90);
  582. for (y = -halfy+1; y <= halfy-1; y++)
  583. {
  584. if (lastGate<1 && gateCount > 0 && mLandScape->irand(1,(halfx+halfy)/gateCount) == 1)
  585. { // gate
  586. gateCount--;
  587. lastGate = 3;
  588. instance = mInstanceFile.CreateInstance ( gateName );
  589. }
  590. else if (lastRip<1 && ripCount > 0 && mLandScape->irand(1,(halfx+halfy)/ripCount) == 1)
  591. { // damaged fence
  592. ripCount--;
  593. lastRip = 3;
  594. instance = mInstanceFile.CreateInstance ( ripName );
  595. }
  596. else
  597. { // just a wall
  598. instance = mInstanceFile.CreateInstance ( wallName );
  599. lastRip--;
  600. lastGate--;
  601. }
  602. instance->SetSide(side);
  603. PlaceWallInstance(instance, xpos, ypos, zpos, -halfx, y, angle);
  604. }
  605. for (y = -halfy+1; y <= halfy-1; y++)
  606. {
  607. if (lastGate<1 && gateCount > 0 && mLandScape->irand(1,(halfx+halfy)/gateCount) == 1)
  608. { // gate
  609. gateCount--;
  610. lastGate = 3;
  611. instance = mInstanceFile.CreateInstance ( gateName );
  612. }
  613. else if (lastRip<1 && ripCount > 0 && mLandScape->irand(1,(halfx+halfy)/ripCount) == 1)
  614. { // damaged fence
  615. ripCount--;
  616. lastRip = 3;
  617. instance = mInstanceFile.CreateInstance ( ripName );
  618. }
  619. else
  620. { // just a wall
  621. instance = mInstanceFile.CreateInstance ( wallName );
  622. lastRip--;
  623. lastGate--;
  624. }
  625. instance->SetSide(side);
  626. PlaceWallInstance(instance, xpos, ypos, zpos, halfx, y, angle);
  627. }
  628. }
  629. }
  630. }
  631. }
  632. else
  633. return false;
  634. #endif // #ifndef PRE_RELEASE_DEMO
  635. return true;
  636. }
  637. /************************************************************************************************
  638. * CRMMission::ParseInstancesOnPath
  639. * creates instances on path between nodes
  640. *
  641. * inputs:
  642. * group: parser group containing the defenses, other instances on the path between nodes
  643. *
  644. * return:
  645. * true: parsed successfully
  646. * false: failed to parse
  647. *
  648. ************************************************************************************************/
  649. bool CRMMission::ParseInstancesOnPath ( CGPGroup* group )
  650. {
  651. #ifndef PRE_RELEASE_DEMO
  652. CGPGroup* defenseGroup;
  653. for ( defenseGroup = group->GetSubGroups();
  654. defenseGroup;
  655. defenseGroup=defenseGroup->GetNext() )
  656. if (stricmp ( defenseGroup->GetName ( ), "defenses" )==0 ||
  657. stricmp ( defenseGroup->GetName(), "instanceonpath")==0)
  658. {
  659. const char* defName = defenseGroup->FindPairValue ( "instance", "" );
  660. if ( *defName )
  661. {
  662. float minpos;
  663. float maxpos;
  664. int mincount;
  665. int maxcount;
  666. // how far along path does this get placed?
  667. minpos = atof( defenseGroup->FindPairValue ( "minposition", "0.5" ) );
  668. maxpos = atof( defenseGroup->FindPairValue ( "maxposition", "0.5" ) );
  669. mincount = atoi( defenseGroup->FindPairValue ( "mincount", "1" ) );
  670. maxcount = atoi( defenseGroup->FindPairValue ( "maxcount", "1" ) );
  671. const char* nodename;
  672. CGPGroup* originGroup = group->FindSubGroup ( "origin" );
  673. if (originGroup)
  674. {
  675. nodename = originGroup->FindPairValue ( "node", "" );
  676. if (*nodename)
  677. {
  678. CRMNode* node;
  679. // Find the node being attached to
  680. node = mPathManager->FindNodeByName ( nodename );
  681. if ( node )
  682. {
  683. int dir;
  684. // look at each connection from this node to others, if there is a path, create a defense
  685. for (dir=0; dir<DIR_MAX; dir++)
  686. {
  687. if (node->PathExist(dir))
  688. { // path leads out of this node
  689. CRMArea* area;
  690. CRMInstance* instance;
  691. float spacing;
  692. vec3_t origin;
  693. vec3_t lookat;
  694. vec4_t tmp_pt, tmp_dir;
  695. int n,num_insts = mLandScape->irand(mincount,maxcount);
  696. int pathID = node->GetPath(dir);
  697. if (0 == num_insts)
  698. continue;
  699. float posdelta = (maxpos - minpos) / num_insts;
  700. for (n=0; n<num_insts; n++)
  701. {
  702. instance = mInstanceFile.CreateInstance ( defName );
  703. // Failed to create, not good
  704. if ( NULL == instance )
  705. {
  706. continue;
  707. }
  708. // If a spacing radius was specified then override the one thats
  709. // in the instance
  710. spacing = atof( defenseGroup->FindPairValue ( "spacing", "0" ) );
  711. if ( spacing )
  712. {
  713. instance->SetSpacingRadius ( spacing );
  714. }
  715. instance->SetFilter(group->FindPairValue("filter", ""));
  716. instance->SetTeamFilter(group->FindPairValue("teamfilter", ""));
  717. if (strstr(instance->GetTeamFilter(),"red"))
  718. instance->SetSide(SIDE_RED);
  719. else if (strstr(instance->GetTeamFilter(),"blue"))
  720. instance->SetSide(SIDE_BLUE);
  721. float pos_along_path = mLandScape->flrand(minpos + posdelta*n, minpos + posdelta*(n+1));
  722. float look_along_path = atof( defenseGroup->FindPairValue ( "pathalign", "1" ) ) ;
  723. mLandScape->GetPathInfo (pathID, pos_along_path, tmp_pt, tmp_dir );
  724. origin[0] = tmp_pt[0];
  725. origin[1] = tmp_pt[1];
  726. mLandScape->GetPathInfo (pathID, look_along_path, tmp_dir, tmp_pt );
  727. lookat[0] = tmp_pt[0];
  728. lookat[1] = tmp_pt[1];
  729. origin[0] = mLandScape->GetBounds ( )[0][0] + (mLandScape->GetBounds ( )[1][0]-mLandScape->GetBounds ( )[0][0]) * origin[0];
  730. origin[1] = mLandScape->GetBounds ( )[0][1] + (mLandScape->GetBounds ( )[1][1]-mLandScape->GetBounds ( )[0][1]) * origin[1];
  731. origin[2] = mLandScape->GetBounds ( )[0][2] ;
  732. // look at a point along the path at this location
  733. lookat[0] = mLandScape->GetBounds ( )[0][0] + (mLandScape->GetBounds ( )[1][0]-mLandScape->GetBounds ( )[0][0]) * lookat[0];
  734. lookat[1] = mLandScape->GetBounds ( )[0][1] + (mLandScape->GetBounds ( )[1][1]-mLandScape->GetBounds ( )[0][1]) * lookat[1];
  735. lookat[2] = 0;
  736. // Fixed height? (used for bridges)
  737. if ( !atoi(group->FindPairValue ( "nodrop", "0" )) )
  738. {
  739. origin[2] = mLandScape->GetBounds ( )[1][2] + 100;
  740. }
  741. // Set the area of position
  742. area = mAreaManager->CreateArea ( origin, instance->GetSpacingRadius(), instance->GetSpacingLine(), GetDefaultPadding(), 0, origin, lookat, instance->GetFlattenRadius()?true:false, true, instance->GetLockOrigin(), mSymmetric );
  743. area->EnableLookAt(false);
  744. if ( node->GetFlattenHeight ( ) == -1 )
  745. {
  746. node->SetFlattenHeight ( 66 + mLandScape->irand(0,40) );
  747. }
  748. instance->SetFlattenHeight ( node->GetFlattenHeight ( ) );
  749. instance->SetArea ( mAreaManager, area );
  750. mInstances.push_back ( instance );
  751. }
  752. }
  753. }
  754. }
  755. }
  756. }
  757. else
  758. return false;
  759. }
  760. else
  761. return false;
  762. }
  763. #endif // #ifndef PRE_RELEASE_DEMO
  764. return true;
  765. }
  766. /************************************************************************************************
  767. * CRMMission::ParseInstance
  768. * Parses an individual instance
  769. *
  770. * inputs:
  771. * group: parser group containing the list of instances
  772. *
  773. * return:
  774. * true: instances parsed successfully
  775. * false: instances failed to parse
  776. *
  777. ************************************************************************************************/
  778. bool CRMMission::ParseInstance ( CGPGroup* group )
  779. {
  780. CRMArea* area;
  781. CRMInstance* instance;
  782. float spacing;
  783. vec3_t origin;
  784. vec3_t lookat;
  785. int flattenHeight;
  786. vec3_t zerodvec;
  787. VectorClear(zerodvec);
  788. // create fences / walls
  789. // Create the instance using the instance file helper class
  790. instance = mInstanceFile.CreateInstance ( group->GetName ( ) );
  791. // Failed to create, not good
  792. if ( NULL == instance )
  793. {
  794. return false;
  795. }
  796. // If a spacing radius was specified then override the one thats
  797. // in the instance
  798. spacing = atof( group->FindPairValue ( "spacing", "0" ) );
  799. if ( spacing )
  800. {
  801. instance->SetSpacingRadius ( spacing );
  802. }
  803. instance->SetFilter(group->FindPairValue("filter", ""));
  804. instance->SetTeamFilter(group->FindPairValue("teamfilter", ""));
  805. if (strstr(instance->GetTeamFilter(),"red"))
  806. instance->SetSide( SIDE_RED);
  807. else if (strstr(instance->GetTeamFilter(),"blue"))
  808. instance->SetSide( SIDE_BLUE );
  809. // ParseWallRect(group, instance->GetSide());
  810. // Get its origin now
  811. ParseOrigin ( group->FindSubGroup ( "origin" ), origin, lookat, &flattenHeight );
  812. origin[0] = mLandScape->GetBounds ( )[0][0] + (mLandScape->GetBounds ( )[1][0]-mLandScape->GetBounds ( )[0][0]) * origin[0];
  813. origin[1] = mLandScape->GetBounds ( )[0][1] + (mLandScape->GetBounds ( )[1][1]-mLandScape->GetBounds ( )[0][1]) * origin[1];
  814. origin[2] = mLandScape->GetBounds ( )[0][2] + (mLandScape->GetBounds ( )[1][2]-mLandScape->GetBounds ( )[0][2]) * origin[2];
  815. lookat[0] = mLandScape->GetBounds ( )[0][0] + (mLandScape->GetBounds ( )[1][0]-mLandScape->GetBounds ( )[0][0]) * lookat[0];
  816. lookat[1] = mLandScape->GetBounds ( )[0][1] + (mLandScape->GetBounds ( )[1][1]-mLandScape->GetBounds ( )[0][1]) * lookat[1];
  817. lookat[2] = mLandScape->GetBounds ( )[0][2] + (mLandScape->GetBounds ( )[1][2]-mLandScape->GetBounds ( )[0][2]) * lookat[2];
  818. // Fixed height? (used for bridges)
  819. if ( !atoi(group->FindPairValue ( "nodrop", "0" )) )
  820. {
  821. origin[2] = mLandScape->GetBounds ( )[1][2] + 100;
  822. }
  823. // Set the area of position
  824. area = mAreaManager->CreateArea ( origin, instance->GetSpacingRadius(), instance->GetSpacingLine(), GetDefaultPadding(), 0, zerodvec, lookat, instance->GetFlattenRadius()?true:false, true, instance->GetLockOrigin(), mSymmetric );
  825. instance->SetArea ( mAreaManager, area );
  826. instance->SetFlattenHeight ( flattenHeight );
  827. mInstances.push_back ( instance );
  828. // create defenses?
  829. ParseInstancesOnPath(group );
  830. return true;
  831. }
  832. /************************************************************************************************
  833. * CRMMission::ParseInstances
  834. * parses all instances within the mission and populates the instance list
  835. *
  836. * inputs:
  837. * group: parser group containing the list of instances
  838. *
  839. * return:
  840. * true: instances parsed successfully
  841. * false: instances failed to parse
  842. *
  843. ************************************************************************************************/
  844. bool CRMMission::ParseInstances ( CGPGroup* group )
  845. {
  846. #ifndef PRE_RELEASE_DEMO
  847. // If NULL that means this particular difficulty level has no instances
  848. if ( NULL == group )
  849. {
  850. return true;
  851. }
  852. // Loop through all the instances in the mission and add each
  853. // to the master list of instances
  854. for ( group = group->GetSubGroups();
  855. group;
  856. group=group->GetNext() )
  857. {
  858. ParseInstance ( group );
  859. }
  860. #endif // #ifndef PRE_RELEASE_DEMO
  861. return true;
  862. }
  863. /************************************************************************************************
  864. * CRMMission::ParseObjectives
  865. * parses all objectives within the mission and populates the objective list
  866. *
  867. * inputs:
  868. * group: parser group containing the list of objectives
  869. *
  870. * return:
  871. * true: objectives parsed successfully
  872. * false: objectives failed to parse
  873. *
  874. ************************************************************************************************/
  875. bool CRMMission::ParseObjectives ( CGPGroup* group )
  876. {
  877. // If NULL that means this particular difficulty level has no objectives
  878. if ( NULL == group )
  879. {
  880. return true;
  881. }
  882. // Loop through all the objectives in the mission and add each
  883. // to the master list of objectives
  884. for ( group = group->GetSubGroups();
  885. group;
  886. group=group->GetNext() )
  887. {
  888. CRMObjective* objective;
  889. // Create the new objective
  890. objective = new CRMObjective ( group );
  891. mObjectives.push_back ( objective );
  892. }
  893. mValidObjectives = true;
  894. return true;
  895. }
  896. /************************************************************************************************
  897. * CRMMission::ParseAmmo
  898. * parses the given ammo list and sets the necessary ammo cvars to grant those
  899. * weapons to the players
  900. *
  901. * inputs:
  902. * ammos: parser group containing the ammo list
  903. *
  904. * return:
  905. * true: ammo parsed successfully
  906. * false: ammo failed to parse
  907. *
  908. ************************************************************************************************/
  909. bool CRMMission::ParseAmmo ( CGPGroup* ammos )
  910. {
  911. /* CGPValue* ammo;
  912. // No weapons, no success
  913. if ( NULL == ammos )
  914. {
  915. return false;
  916. }
  917. if (0 == gi.Cvar_VariableIntegerValue("ar_wpnselect"))
  918. {
  919. // Make sure the ammo cvars are all reset so ammo from the last map or
  920. // another difficulty level wont carry over
  921. CWeaponSystem::ClearAmmoCvars (TheWpnSysHelper());
  922. ammo = ammos->GetPairs ( );
  923. // Loop through the weapons listed and grant them to the player
  924. while ( ammo )
  925. {
  926. // Grab the weapons ID
  927. AmmoID id = CWeaponSystem::GetAmmoID ( ammo->GetName ( ) );
  928. // Now set the weapon cvar with the given data
  929. TheWpnSysHelper().CvarSet ( CWeaponSystem::GetAmmoCvar ( id ), ammo->GetTopValue ( ), CVAR_AMMO );
  930. // Move on to the next weapon
  931. ammo = (CGPValue*)ammo->GetNext();
  932. }
  933. }
  934. */
  935. mValidAmmo = true;
  936. return true;
  937. }
  938. /************************************************************************************************
  939. * CRMMission::ParseWeapons
  940. * parses the given weapon list and sets the necessary weapon cvars to grant those
  941. * weapons to the players
  942. *
  943. * inputs:
  944. * weapons: parser group containing the weapons list
  945. *
  946. * return:
  947. * true: weapons parsed successfully
  948. * false: weapons failed to parse
  949. *
  950. ************************************************************************************************/
  951. bool CRMMission::ParseWeapons ( CGPGroup* weapons )
  952. {
  953. /* CGPValue* weapon;
  954. WpnID id;
  955. // No weapons, no success
  956. if ( NULL == weapons )
  957. {
  958. return false;
  959. }
  960. if (0 == gi.Cvar_VariableIntegerValue("ar_wpnselect"))
  961. {
  962. // Make sure the weapon cvars are all reset so weapons from the last map or
  963. // another difficulty level wont carry over
  964. CWeaponSystem::ClearWpnCvars (TheWpnSysHelper());
  965. id = NULL_WpnID;
  966. weapon = weapons->GetPairs ( );
  967. // Loop through the weapons listed and grant them to the player
  968. while ( weapon )
  969. {
  970. // Grab the weapons ID
  971. id = CWeaponSystem::GetWpnID ( weapon->GetName ( ) );
  972. // Now set the weapon cvar with the given data
  973. TheWpnSysHelper().CvarSet ( CWeaponSystem::GetWpnCvar ( id ), weapon->GetTopValue ( ) );
  974. // Move on to the next weapon
  975. weapon = (CGPValue*)weapon->GetNext();
  976. }
  977. // If we found at least one weapon then ready the last one in the list
  978. if ( NULL_WpnID != id )
  979. {
  980. TheWpnSysHelper().CvarSet("wp_righthand", va("%i/%i/0/0",id,CWeaponSystem::GetClipSize ( id )), CVAR_MISC );
  981. }
  982. }
  983. */
  984. mValidWeapons = true;
  985. return true;
  986. }
  987. /************************************************************************************************
  988. * CRMMission::ParseOutfit
  989. * parses the outfit (weapons and ammo)
  990. *
  991. * inputs:
  992. * outfit: parser group containing the outfit
  993. *
  994. * return:
  995. * true: weapons and ammo parsed successfully
  996. * false: failed to parse
  997. *
  998. ************************************************************************************************/
  999. bool CRMMission::ParseOutfit ( CGPGroup* outfit )
  1000. {
  1001. if ( NULL == outfit )
  1002. {
  1003. return false;
  1004. }
  1005. /* // Its ok to fail parsing weapons as long as weapons have
  1006. // already been parsed at some point
  1007. if ( !ParseWeapons ( ParseRandom ( outfit->FindSubGroup ( "weapons" ) ) ) )
  1008. {
  1009. if ( !mValidWeapons )
  1010. {
  1011. return false;
  1012. }
  1013. }
  1014. // Its ok to fail parsing ammo as long as ammo have
  1015. // already been parsed at some point
  1016. if ( !ParseAmmo ( ParseRandom ( outfit->FindSubGroup ( "ammo" ) ) ) )
  1017. {
  1018. if ( !mValidAmmo)
  1019. {
  1020. return false;
  1021. }
  1022. }
  1023. */
  1024. return true;
  1025. }
  1026. /************************************************************************************************
  1027. * CRMMission::ParseRandom
  1028. * selects a random sub group with from all within this one
  1029. *
  1030. * inputs:
  1031. * random: parser group containing the various subgroups
  1032. *
  1033. * return:
  1034. * true: parsed successfuly
  1035. * false: failed to parse
  1036. *
  1037. ************************************************************************************************/
  1038. CGPGroup* CRMMission::ParseRandom ( CGPGroup* randomGroup )
  1039. {
  1040. if (NULL == randomGroup)
  1041. return NULL;
  1042. CGPGroup* group;
  1043. CGPGroup* groups[MAX_RANDOM_CHOICES];
  1044. int numGroups;
  1045. // Build a list of the groups one can be chosen
  1046. for ( numGroups = 0, group = randomGroup->GetSubGroups ( );
  1047. group;
  1048. group = group->GetNext ( ) )
  1049. {
  1050. if ( stricmp ( group->GetName ( ), "random_choice" ) )
  1051. {
  1052. continue;
  1053. }
  1054. int weight = atoi ( group->FindPairValue ( "random_weight", "1" ) );
  1055. while (weight-- > 0)
  1056. groups[numGroups++] = group;
  1057. assert (numGroups <= MAX_RANDOM_CHOICES);
  1058. }
  1059. // No groups!
  1060. if ( !numGroups )
  1061. {
  1062. return randomGroup;
  1063. }
  1064. // Now choose a group to parse
  1065. return groups[mLandScape->irand(0,numGroups-1)];
  1066. }
  1067. /************************************************************************************************
  1068. * CRMMission::ParseDifficulty
  1069. * parses the given difficulty and populates the mission with its data
  1070. *
  1071. * inputs:
  1072. * difficulty: parser group containing the difficulties info
  1073. *
  1074. * return:
  1075. * true: difficulty parsed successfully
  1076. * false: difficulty failed to parse
  1077. *
  1078. ************************************************************************************************/
  1079. bool CRMMission::ParseDifficulty ( CGPGroup* difficulty, CGPGroup *parent )
  1080. {
  1081. // If a null difficulty then stop the recursion. Make sure to
  1082. // return true here so the parsing doesnt fail
  1083. if ( NULL == difficulty )
  1084. {
  1085. return true;
  1086. }
  1087. if (difficulty->GetParent())
  1088. {
  1089. parent = difficulty->GetParent();
  1090. }
  1091. // is map supposed to be symmetric?
  1092. mSymmetric = (symmetry_t)atoi(parent->FindPairValue ( "symmetric", "0" ));
  1093. mBackUpPath = atoi(parent->FindPairValue ( "backuppath", "0" ));
  1094. if( mSymmetric )
  1095. {// pick between the 2 starting corners -- yes this is a hack
  1096. mSymmetric = SYMMETRY_TOPLEFT;
  1097. if( TheRandomMissionManager->GetLandScape()->irand(0, 1) )
  1098. {
  1099. mSymmetric = SYMMETRY_BOTTOMRIGHT;
  1100. }
  1101. }
  1102. mDefaultPadding = atoi(parent->FindPairValue ( "padding", "0" ));
  1103. // Parse the nodes
  1104. if ( !ParseNodes ( ParseRandom ( difficulty->FindSubGroup ( "nodes" ) ) ) )
  1105. {
  1106. return false;
  1107. }
  1108. // Parse the paths
  1109. if ( !ParsePaths ( ParseRandom ( difficulty->FindSubGroup ( "paths" ) ) ) )
  1110. {
  1111. return false;
  1112. }
  1113. // Parse the rivers
  1114. if ( !ParseRivers ( ParseRandom ( difficulty->FindSubGroup ( "rivers" ) ) ) )
  1115. {
  1116. return false;
  1117. }
  1118. // Handle inherited properties
  1119. if ( !ParseDifficulty ( parent->FindSubGroup ( difficulty->FindPairValue ( "inherit", "" ) ), parent ) )
  1120. {
  1121. return false;
  1122. }
  1123. // parse the player's outfit (weapons and ammo)
  1124. if ( !ParseOutfit( ParseRandom ( difficulty->FindSubGroup ( "outfit" ) ) ) )
  1125. {
  1126. // Its ok to fail parsing weapons as long as weapons have
  1127. // already been parsed at some point
  1128. if ( !ParseWeapons ( ParseRandom ( difficulty->FindSubGroup ( "weapons" ) ) ) )
  1129. {
  1130. if ( !mValidWeapons )
  1131. {
  1132. return false;
  1133. }
  1134. }
  1135. // Its ok to fail parsing ammo as long as ammo have
  1136. // already been parsed at some point
  1137. if ( !ParseAmmo ( ParseRandom ( difficulty->FindSubGroup ( "ammo" ) ) ) )
  1138. {
  1139. if ( !mValidAmmo)
  1140. {
  1141. return false;
  1142. }
  1143. }
  1144. }
  1145. // Its ok to fail parsing objectives as long as objectives have
  1146. // already been parsed at some point
  1147. if ( !ParseObjectives ( ParseRandom ( difficulty->FindSubGroup ( "objectives" ) ) ) )
  1148. {
  1149. if ( !mValidObjectives )
  1150. {
  1151. return false;
  1152. }
  1153. }
  1154. // Set the cvars with the available values
  1155. Cvar_Set ( "mi_health", difficulty->FindPairValue ( "health", "100" ) );
  1156. Cvar_Set ( "mi_armor", difficulty->FindPairValue ( "armor", "0" ) );
  1157. // Parse out the timelimit
  1158. mTimeLimit = atol(difficulty->FindPairValue("timelimit", "0"));
  1159. // NPC multipliers
  1160. mAccuracyMultiplier = atof(difficulty->FindPairValue("npcaccuracy", "1"));
  1161. mHealthMultiplier = atof(difficulty->FindPairValue("npchealth", "1"));
  1162. // keep only some of RMG pickups 1 = 100%
  1163. mPickupHealth = atof(difficulty->FindPairValue("pickup_health", "1"));
  1164. mPickupArmor = atof(difficulty->FindPairValue("pickup_armor", "1"));
  1165. mPickupAmmo = atof(difficulty->FindPairValue("pickup_ammo", "1"));
  1166. mPickupWeapon = atof(difficulty->FindPairValue("pickup_weapon", "1"));
  1167. mPickupEquipment = atof(difficulty->FindPairValue("pickup_equipment", "1"));
  1168. // Its ok to fail parsing instances as long as instances have
  1169. // already been parsed at some point
  1170. if ( !ParseInstances ( ParseRandom ( difficulty->FindSubGroup ( "instances" ) ) ) )
  1171. {
  1172. if ( !mValidInstances )
  1173. {
  1174. return false;
  1175. }
  1176. }
  1177. return true;
  1178. }
  1179. /************************************************************************************************
  1180. * CRMMission::Load
  1181. * Loads the given mission using the given difficulty level
  1182. *
  1183. * inputs:
  1184. * name: Name of the mission to load (should only be the name rather than the full path)
  1185. * difficulty: difficulty level to load
  1186. *
  1187. * return:
  1188. * true: mission successfully loaded
  1189. * false: mission failed to load
  1190. *
  1191. ************************************************************************************************/
  1192. bool CRMMission::Load ( const char* mission, const char* instances, const char* difficulty )
  1193. {
  1194. CGenericParser2 parser;
  1195. CGPGroup* root;
  1196. // Create the parser for the mission file
  1197. if(!Com_ParseTextFile(va("ext_data/rmg/%s.mission", mission), parser))
  1198. {
  1199. if(!Com_ParseTextFile(va("ext_data/arioche/%s.mission", mission), parser))
  1200. {
  1201. Com_Printf("ERROR: Failed to open mission file '%s'\n", mission);
  1202. return false;
  1203. }
  1204. }
  1205. // Grab the root parser groop and make sure its mission, otherwise this
  1206. // isnt a valid mission file
  1207. root = parser.GetBaseParseGroup()->GetSubGroups();
  1208. if(stricmp(root->GetName(), "mission"))
  1209. {
  1210. Com_Printf("ERROR: '%s' is not a valid mission file\n", mission );
  1211. parser.Clean();
  1212. return false;
  1213. }
  1214. // Grab the mission description and set the cvar for it
  1215. mDescription = root->FindPairValue ( "description", "<MISSION DESCRIPTION MISSING>" );
  1216. // Cvar_Set("ar_obj_main0",mDescription.c_str(), CVAR_OBJECTIVE);
  1217. // Cvar_Set("ar_obj_maincom0", "&OBJECTIVES_INPROGRESS&", CVAR_OBJECTIVE);
  1218. // Cvar_SetValue ("ar_cur_objective", 0, CVAR_OBJECTIVE);
  1219. string mInfo = root->FindPairValue ( "info", "<MISSION ADDITIONAL INFO MISSING>" );
  1220. // Cvar_Set("ar_obj_info0",mInfo.c_str(), CVAR_OBJECTIVE);
  1221. mExitScreen = root->FindPairValue ( "exitScreen", "<EXIT SCREEN MISSING>" );
  1222. mTimeExpiredScreen = root->FindPairValue ( "TimeExpiredScreen", "<TIME EXPIRED SCREEN MISSING>" );
  1223. // Open the instance file for the specified instances
  1224. if ( !mInstanceFile.Open ( instances) )
  1225. {
  1226. Com_Printf ( "ERROR: Could not open instance file '%s'\n", instances );
  1227. return false;
  1228. }
  1229. // Start at one and readjust each time we see and instance
  1230. // with a higher value
  1231. mMaxInstancePosition = 1;
  1232. // Now parse the specified difficulty level
  1233. CGPGroup* parserdif = root->FindSubGroup ( difficulty );
  1234. CGPGroup* parserpar = parserdif->GetParent();
  1235. if (!parserpar)
  1236. { //rww - expected to have a parent, but sometime doesn't get set.
  1237. //I take it JK2's generic parser is not quite the same as SOF2's. Or is out of date.
  1238. parserpar = root;
  1239. }
  1240. if ( !ParseDifficulty ( parserdif, parserpar ) )
  1241. {
  1242. return false;
  1243. }
  1244. // Generate the terrain now
  1245. mLandScape->Generate(mSymmetric);
  1246. // Cleanup
  1247. parser.Clean();
  1248. return true;
  1249. }
  1250. /************************************************************************************************
  1251. * CRMMission::Spawn
  1252. * Spawns all of the instances for the entire mission onto the given landscape
  1253. *
  1254. * inputs:
  1255. * landscape: landscape to spawn instances on
  1256. *
  1257. * return:
  1258. * true: instances spawned successfully
  1259. * false: instances failed to spawn
  1260. *
  1261. ************************************************************************************************/
  1262. bool CRMMission::Spawn ( CRandomTerrain* terrain, qboolean IsServer )
  1263. {
  1264. #ifndef PRE_RELEASE_DEMO
  1265. rmInstanceIter_t it;
  1266. int areaIndex;
  1267. CRMArea* area;
  1268. // Prespawn all instances, this is mainly for flattening
  1269. for(it = mInstances.begin(); it != mInstances.end(); it++)
  1270. {
  1271. CRMInstance* instance = *it;
  1272. // Pre-Spawn
  1273. instance->PreSpawn ( terrain, IsServer );
  1274. if (mSymmetric)
  1275. {
  1276. instance->SetMirror(1);
  1277. instance->PreSpawn ( terrain, IsServer );
  1278. instance->SetMirror(0);
  1279. }
  1280. }
  1281. mLandScape->Smooth ( );
  1282. // place bridges
  1283. PlaceBridges();
  1284. // create automap
  1285. // if (!com_dedicated->integer)
  1286. {
  1287. #ifndef DEDICATED
  1288. CM_TM_Create(mLandScape->GetLandScape());
  1289. #endif
  1290. }
  1291. mLandScape->GetLandScape()->UpdatePatches();
  1292. // Spawn all instances
  1293. for(it = mInstances.begin(); it != mInstances.end(); it++)
  1294. {
  1295. CRMInstance* instance = *it;
  1296. // Spawn
  1297. instance->Spawn ( terrain, IsServer );
  1298. instance->PostSpawn ( terrain, IsServer );
  1299. if (mSymmetric)
  1300. { // spawn the mirror version
  1301. instance->SetMirror(1);
  1302. instance->Spawn ( terrain, IsServer );
  1303. instance->PostSpawn ( terrain, IsServer );
  1304. instance->SetMirror(0);
  1305. }
  1306. }
  1307. #ifndef FINAL_BUILD
  1308. // make sure to write out after the mirror happens so red side is displayed on map
  1309. if (1 == Cvar_VariableIntegerValue("rmg_saveautomap"))
  1310. { // write out automap for test purposes
  1311. char seed[MAX_QPATH];
  1312. char terrainName[MAX_QPATH];
  1313. char missionName[MAX_QPATH];
  1314. Cvar_VariableStringBuffer("RMG_seed", seed, MAX_QPATH);
  1315. Cvar_VariableStringBuffer("RMG_terrain", terrainName, MAX_QPATH);
  1316. Cvar_VariableStringBuffer("RMG_mission", missionName, MAX_QPATH);
  1317. #ifndef DEDICATED
  1318. for(it = mInstances.begin(); it != mInstances.end(); it++)
  1319. {
  1320. (*it)->DrawAutomapSymbol();
  1321. }
  1322. //gi.CM_TM_SaveImageToDisk(terrainName, missionName, seed);
  1323. CM_TM_SaveImageToDisk(terrainName, missionName, seed);
  1324. #endif
  1325. Com_Error (ERR_DROP, "RMG Automap written.");
  1326. return false;
  1327. }
  1328. #endif
  1329. // // draw player start on automap
  1330. // CEntity *spot = NULL;
  1331. // spot = entitySystem->GetEntityFromClassname( spot, "info_player_start");
  1332. // if (spot)
  1333. // {
  1334. // gi.CM_TM_AddStart(spot->GetOrigin()[0], spot->GetOrigin()[1]);
  1335. // }
  1336. // Spawn NPC triggers now
  1337. // SpawnNPCTriggers ( mLandScape );
  1338. // Restory all the NPC's accuracies to the template accuracies times the
  1339. // multiplier
  1340. // INPCEnt::RestoreTemplate ( mAccuracyMultiplier, mHealthMultiplier );
  1341. // Little trick to set the current objective to the first in the list
  1342. CompleteObjective ( NULL );
  1343. // Iterate through the areas and add each to the landscapes list, this is sorta hacky
  1344. // but bridges the game / common gap
  1345. for ( areaIndex = 0; NULL != (area = mAreaManager->EnumArea ( areaIndex )); areaIndex ++ )
  1346. {
  1347. // Dont bother adding it to the list if collision isnt enabled
  1348. if ( !area->IsCollisionEnabled() )
  1349. {
  1350. continue;
  1351. }
  1352. CArea* newarea = new CArea ( );
  1353. newarea->Init ( area->GetOrigin(), area->GetSpacingRadius (), 0, area->IsFlattened()?AT_FLAT:AT_NONE );
  1354. mLandScape->GetLandScape()->SaveArea( newarea );
  1355. if (mSymmetric)
  1356. {
  1357. CArea* newarea = new CArea ( );
  1358. newarea->Init ( area->GetOrigin(), area->GetSpacingRadius (), 0, area->IsFlattened()?AT_FLAT:AT_NONE );
  1359. newarea->GetPosition()[0] = mLandScape->GetBounds ( )[0][0]+mLandScape->GetBounds ( )[1][0]-newarea->GetPosition()[0];
  1360. newarea->GetPosition()[1] = mLandScape->GetBounds ( )[0][1]+mLandScape->GetBounds ( )[1][1]-newarea->GetPosition()[1];
  1361. mLandScape->GetLandScape()->SaveArea( newarea );
  1362. }
  1363. }
  1364. mInstanceFile.Close ( );
  1365. #endif // PRE_RELEASE_DEMO
  1366. return true;
  1367. }
  1368. /************************************************************************************************
  1369. * CRMMission::CompleteMission
  1370. * Pauses the game, plays an end screen after a brief delay, which then returns the player to
  1371. * the RMG menu.
  1372. * *
  1373. * Input *
  1374. * <Variable>: <Description> *
  1375. * Output / Return *
  1376. * <Variable>: <Description> *
  1377. ************************************************************************************************/
  1378. void CRMMission::CompleteMission(void)
  1379. {
  1380. Cvar_Set ("cl_paused", "1");
  1381. // AddText(va("killserver; menu %s\n", mExitScreen.c_str()));
  1382. return;
  1383. }
  1384. /************************************************************************************************
  1385. * CRMMission::FailedMission
  1386. * Pauses the game, plays an end screen after a brief delay, which then returns the player to
  1387. * the RMG menu.
  1388. * *
  1389. * Input *
  1390. * TimeExpired: indicates if the reason failed was because of time
  1391. * Output / Return *
  1392. * <Variable>: <Description> *
  1393. ************************************************************************************************/
  1394. void CRMMission::FailedMission(bool TimeExpired)
  1395. {
  1396. Cvar_Set ("cl_paused", "1");
  1397. if (TimeExpired)
  1398. {
  1399. // AddText(va("killserver; menu %s\n", mTimeExpiredScreen.c_str()));
  1400. }
  1401. return;
  1402. }
  1403. /************************************************************************************************
  1404. * CRMMission::CompleteObjective
  1405. * Completes the given objective and advances the current objective accordingly
  1406. *
  1407. * inputs:
  1408. * objective: the objetive to mark complete
  1409. *
  1410. * return:
  1411. * none
  1412. *
  1413. ************************************************************************************************/
  1414. void CRMMission::CompleteObjective ( CRMObjective* objective )
  1415. {
  1416. rmObjectiveIter_t it;
  1417. // Set the object as completed
  1418. if ( objective )
  1419. {
  1420. objective->Complete ( true );
  1421. // Set the completed text for the objective
  1422. // gi.Cvar_Set( va("ar_obj_subcom0_%i", objective->GetOrderIndex ( )), "&OBJECTIVES_COMPLETE&", CVAR_OBJECTIVE) ;
  1423. /* CEntity *tent = G_TempEntity( vec3_origin, EV_SUB_PRINT );
  1424. tent->s.time2 = gi.SP_GetStringID ( objective->GetMessage ( ) );
  1425. tent->r.svFlags |= SVF_BROADCAST;
  1426. G_AddTempEntity(tent);
  1427. if (objective->CompleteSoundID())
  1428. G_SoundBroadcast( tent, objective->CompleteSoundID());
  1429. */
  1430. }
  1431. mCurrentObjective = NULL;
  1432. // Find the next objective
  1433. for (it = mObjectives.begin(); it != mObjectives.end(); it++)
  1434. {
  1435. objective = (*it);
  1436. // Skip completed objectives
  1437. if ( objective->IsCompleted ( ) )
  1438. {
  1439. continue;
  1440. }
  1441. // Find the objective with the lowest priority
  1442. if ( mCurrentObjective && objective->GetPriority ( ) > mCurrentObjective->GetPriority ( ) )
  1443. {
  1444. continue;
  1445. }
  1446. // Found one
  1447. mCurrentObjective = objective;
  1448. }
  1449. if ( NULL != mCurrentObjective )
  1450. {
  1451. // Cvar_SetValue ("ar_cur_objective", mCurrentObjective->GetOrderIndex ( ), CVAR_OBJECTIVE);
  1452. mCurrentObjective->Activate ( );
  1453. }
  1454. else
  1455. {
  1456. // Set the completed text for the objective
  1457. // Cvar_Set( "ar_obj_maincom0", "&OBJECTIVES_COMPLETE&", CVAR_OBJECTIVE) ;
  1458. }
  1459. }
  1460. /************************************************************************************************
  1461. * CRMMission::Preview
  1462. * Previews the instances within the mission
  1463. *
  1464. * inputs:
  1465. * from: the origin which the mission is being previewed from
  1466. *
  1467. * return:
  1468. * none
  1469. *
  1470. ************************************************************************************************/
  1471. void CRMMission::Preview ( const vec3_t from )
  1472. {
  1473. rmInstanceIter_t it;
  1474. // Look for settlements close to the player and put up some debug stuff
  1475. for(it = mInstances.begin(); it != mInstances.end(); it++)
  1476. {
  1477. CRMInstance* instance = *it;
  1478. vec3_t a;
  1479. vec3_t b;
  1480. VectorCopy ( from, a );
  1481. VectorCopy ( instance->GetOrigin(), b );
  1482. a[2] = 0;
  1483. b[2] = 0;
  1484. // Skip stuff thats too far away
  1485. if ( Distance ( a, b) > 2000 )
  1486. {
  1487. continue;
  1488. }
  1489. instance->Preview ( from );
  1490. }
  1491. }
  1492. /************************************************************************************************
  1493. * CRMMission::PurgeTrigger
  1494. * Purge the trigger and all its targets
  1495. *
  1496. * inputs:
  1497. * trigger: trigger to purge
  1498. *
  1499. * return:
  1500. * none
  1501. *
  1502. ************************************************************************************************/
  1503. /*void CRMMission::PurgeTrigger ( CEntity* trigger )
  1504. {
  1505. CEntity* target;
  1506. // Purge all targets
  1507. target = entitySystem->GetEntityFromTargetName ( NULL, trigger->GetTarget ( ) );
  1508. while ( target )
  1509. {
  1510. PurgeTrigger ( target );
  1511. target = entitySystem->GetEntityFromTargetName ( target, trigger->GetTarget ( ) );
  1512. }
  1513. // Get rid of the purge trigger
  1514. entitySystem->RemoveEntityWithServer ( trigger );
  1515. entitySystem->RemoveEntity ( trigger );
  1516. }
  1517. */
  1518. /************************************************************************************************
  1519. * CRMMission::PurgeUnlinkedTriggers
  1520. * Searches the entitySystem form a random arioche trigger that matches the objective name
  1521. *
  1522. * inputs:
  1523. * none
  1524. *
  1525. * return:
  1526. * trigger: a random trigger or NULL if one couldnt be found
  1527. *
  1528. ************************************************************************************************/
  1529. /*void CRMMission::PurgeUnlinkedTriggers ( )
  1530. {
  1531. CTriggerAriocheObjective* search;
  1532. // Start at the first match of the classname
  1533. search = (CTriggerAriocheObjective*) entitySystem->GetEntityFromClassname ( NULL, "trigger_arioche_objective" );
  1534. // Continue on as long as there are triggers
  1535. while ( search )
  1536. {
  1537. CTriggerAriocheObjective* purge = search;
  1538. // move on to the next trigger before deleting the entity
  1539. // just in case there are some state issues with the search
  1540. search = (CTriggerAriocheObjective*) entitySystem->GetEntityFromClassname ( search, "trigger_arioche_objective" );
  1541. // Dont purge linked triggers
  1542. if ( purge->GetObjective ( ) )
  1543. {
  1544. continue;
  1545. }
  1546. // Purge the trigger and all its targets
  1547. PurgeTrigger ( purge );
  1548. }
  1549. }
  1550. */
  1551. /************************************************************************************************
  1552. * CRMMission::SpawnNPCTriggers
  1553. * Spawn triggers across the map which will activate sleeping NPCs
  1554. *
  1555. * inputs:
  1556. * landscape: landscape to spawn the triggers relative to
  1557. *
  1558. * return:
  1559. * trigger: a random trigger or NULL if one couldnt be found
  1560. *
  1561. ************************************************************************************************/
  1562. /*void CRMMission::SpawnNPCTriggers ( CCMLandScape* landscape )
  1563. {
  1564. CEntity* ent;
  1565. int i;
  1566. int count;
  1567. float section;
  1568. // Determine how many NPC sections there are in the map
  1569. count = (landscape->GetBounds()[1][0] - landscape->GetBounds()[0][0]) / 5000.0f;
  1570. section = (landscape->GetBounds()[1][0] - landscape->GetBounds()[0][0]) / count;
  1571. // Drop a trigger down at each NPC section interval except for the first and last.
  1572. for ( i = 1; i < count - 1; i ++ )
  1573. {
  1574. vec3_t mins;
  1575. vec3_t maxs;
  1576. vec3_t origin;
  1577. VectorCopy ( landscape->GetBounds()[0], mins );
  1578. VectorCopy ( landscape->GetBounds()[1], maxs );
  1579. // Set up the mins and maxs for the trigger
  1580. mins[0] = mins[0] + (section * i) - 100;
  1581. maxs[0] = mins[0] + 100;
  1582. maxs[2] = maxs[2] + 100;
  1583. mins[2] = mins[2] - 100;
  1584. origin[0] = (maxs[0]-mins[0])/2 + mins[0];
  1585. origin[1] = (maxs[1]-mins[1])/2 + mins[1];
  1586. origin[2] = (maxs[2]-mins[2])/2 + mins[2];
  1587. spawnSystem->ClearSpawnFields();
  1588. spawnSystem->AddSpawnField("classname", "trigger_arioche_npcspawner" );
  1589. spawnSystem->AddSpawnField("origin", va("%f %f %f",origin[0],origin[1],origin[2]) );
  1590. spawnSystem->AddSpawnField("target", va("rmg_npc_%i", i + 1) );
  1591. // Spawn the inhabitant, if it fails then fail
  1592. ent = entitySystem->SpawnItem("trigger_arioche_npcspawner");
  1593. if ( !ent )
  1594. {
  1595. continue;
  1596. }
  1597. // Fail if we cant register the entity
  1598. if ( -1 == entitySystem->RegisterEntityWithServer( ent ) )
  1599. {
  1600. entitySystem->RemoveEntity ( ent );
  1601. continue;
  1602. }
  1603. // Normalize the mins and maxs for the X axis since they arent
  1604. // absolute mins and maxs
  1605. mins[0] = -100;
  1606. maxs[0] = 100;
  1607. // Adjust the absmin and absmax for the trigger now
  1608. VectorCopy ( mins, ent->r.mins[0] );
  1609. VectorCopy ( maxs, ent->r.maxs[0] );
  1610. Com_DPrintf( "NPC Trigger spawned at '%f %f %f' for targets 'rmg_npc_%i'\n", origin[0], origin[1], origin[2], i + 1 );
  1611. // Set the "ONLY_ONCE" spawn flag
  1612. ent->AddSpawnflags ( 2 );
  1613. #ifdef _GAME
  1614. // initial linking
  1615. gi.SV_LinkEntity( ent );
  1616. #endif
  1617. }
  1618. AttachNPCTriggers ( landscape );
  1619. }
  1620. */
  1621. /************************************************************************************************
  1622. * CRMMission::AttachNPCTriggers
  1623. * Attaches npc triggers to all unattached npcs
  1624. *
  1625. * inputs:
  1626. * landscape: landscape triggers were spawned on
  1627. *
  1628. * return:
  1629. * trigger: a random trigger or NULL if one couldnt be found
  1630. *
  1631. ************************************************************************************************/
  1632. /*void CRMMission::AttachNPCTriggers ( CCMLandScape* landscape )
  1633. {
  1634. TNPCList npcList;
  1635. TNPCFinder npcFinder;
  1636. CNPC* theNPC = 0;
  1637. int npcsegment;
  1638. GetCharacterManager().GetCharacterList(npcList);
  1639. // Loop through all npcs and reset their accuracy
  1640. for( npcFinder = npcList.begin(); npcFinder != npcList.end(); npcFinder++)
  1641. {
  1642. theNPC = (CNPC*) INPCEnt::GetEntity(*npcFinder);
  1643. if(!theNPC)
  1644. {
  1645. continue;
  1646. }
  1647. npcsegment = (theNPC->r.currentOrigin[0] - landscape->GetMins()[0]) / 5000.0f;
  1648. // All npcs in segment 0 and 1 are immediately spawned, all others wait for the
  1649. // trigger
  1650. if ( npcsegment > 1 )
  1651. {
  1652. entitySystem->RemoveFromTargetNameMap(theNPC);
  1653. theNPC->SetTargetName ( va("rmg_npc_%i", npcsegment ) );
  1654. entitySystem->AddToTargetNameMap(theNPC);
  1655. // Start the NPC in the off position
  1656. theNPC->SetSpawnflags(1);
  1657. theNPC->r.contents = 0;
  1658. theNPC->r.svFlags |= SVF_NOCLIENT;
  1659. theNPC->s.eFlags |= EF_NODRAW;
  1660. }
  1661. }
  1662. }
  1663. */