Advertisement
Guest User

Untitled

a guest
Sep 29th, 2010
253
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 50.95 KB | None | 0 0
  1. #include common_scripts\utility;
  2. #include maps\mp\_utility;
  3.  
  4. findBoxCenter( mins, maxs )
  5. {
  6. center = ( 0, 0, 0 );
  7. center = maxs - mins;
  8. center = ( center[0]/2, center[1]/2, center[2]/2 ) + mins;
  9. return center;
  10. }
  11.  
  12. expandMins( mins, point )
  13. {
  14. if ( mins[0] > point[0] )
  15. mins = ( point[0], mins[1], mins[2] );
  16. if ( mins[1] > point[1] )
  17. mins = ( mins[0], point[1], mins[2] );
  18. if ( mins[2] > point[2] )
  19. mins = ( mins[0], mins[1], point[2] );
  20. return mins;
  21. }
  22.  
  23. expandMaxs( maxs, point )
  24. {
  25. if ( maxs[0] < point[0] )
  26. maxs = ( point[0], maxs[1], maxs[2] );
  27. if ( maxs[1] < point[1] )
  28. maxs = ( maxs[0], point[1], maxs[2] );
  29. if ( maxs[2] < point[2] )
  30. maxs = ( maxs[0], maxs[1], point[2] );
  31. return maxs;
  32. }
  33.  
  34.  
  35. addSpawnPoints( team, spawnPointName, isSetOptional )
  36. {
  37. if ( !isDefined( isSetOptional ) )
  38. isSetOptional = false;
  39.  
  40. oldSpawnPoints = [];
  41. if ( level.teamSpawnPoints[team].size )
  42. oldSpawnPoints = level.teamSpawnPoints[team];
  43.  
  44. level.teamSpawnPoints[team] = getSpawnpointArray( spawnPointName );
  45.  
  46. if ( !level.teamSpawnPoints[team].size && !isSetOptional )
  47. {
  48. println( "^1Error: No " + spawnPointName + " spawnpoints found in level!" );
  49. maps\mp\gametypes\_callbacksetup::AbortLevel();
  50. wait 1; // so we don't try to abort more than once before the frame ends
  51. return;
  52. }
  53.  
  54. if ( !isDefined( level.spawnpoints ) )
  55. level.spawnpoints = [];
  56.  
  57. for ( index = 0; index < level.teamSpawnPoints[team].size; index++ )
  58. {
  59. spawnpoint = level.teamSpawnPoints[team][index];
  60.  
  61. if ( !isdefined( spawnpoint.inited ) )
  62. {
  63. spawnpoint spawnPointInit();
  64. level.spawnpoints[ level.spawnpoints.size ] = spawnpoint;
  65. }
  66. }
  67.  
  68. for ( index = 0; index < oldSpawnPoints.size; index++ )
  69. {
  70. origin = oldSpawnPoints[index].origin;
  71.  
  72. // are these 2 lines necessary? we already did it in spawnPointInit
  73. level.spawnMins = expandMins( level.spawnMins, origin );
  74. level.spawnMaxs = expandMaxs( level.spawnMaxs, origin );
  75.  
  76. level.teamSpawnPoints[team][ level.teamSpawnPoints[team].size ] = oldSpawnPoints[index];
  77. }
  78. }
  79.  
  80. placeSpawnPoints( spawnPointName )
  81. {
  82. spawnPoints = getSpawnpointArray( spawnPointName );
  83.  
  84. /#
  85. if ( !isDefined( level.extraspawnpointsused ) )
  86. level.extraspawnpointsused = [];
  87. #/
  88.  
  89. if ( !spawnPoints.size )
  90. {
  91. println( "^1Error: No " + spawnPointName + " spawnpoints found in level!" );
  92. maps\mp\gametypes\_callbacksetup::AbortLevel();
  93. wait 1; // so we don't try to abort more than once before the frame ends
  94. return;
  95. }
  96.  
  97. for( index = 0; index < spawnPoints.size; index++ )
  98. {
  99. spawnPoints[index] spawnPointInit();
  100. // don't add this spawnpoint to level.spawnpoints,
  101. // because it's an unimportant one that we don't want to do sight traces to
  102.  
  103. /#
  104. spawnPoints[index].fakeclassname = spawnPointName;
  105. level.extraspawnpointsused[ level.extraspawnpointsused.size ] = spawnPoints[index];
  106. #/
  107. }
  108. }
  109.  
  110. getSpawnpointArray( classname )
  111. {
  112. spawnPoints = getEntArray( classname, "classname" );
  113.  
  114. if ( !isdefined( level.extraspawnpoints ) || !isdefined( level.extraspawnpoints[classname] ) )
  115. return spawnPoints;
  116.  
  117. for ( i = 0; i < level.extraspawnpoints[classname].size; i++ )
  118. {
  119. spawnPoints[ spawnPoints.size ] = level.extraspawnpoints[classname][i];
  120. }
  121.  
  122. return spawnPoints;
  123. }
  124.  
  125. expandSpawnpointBounds( classname )
  126. {
  127. spawnPoints = getSpawnpointArray( classname );
  128. for( index = 0; index < spawnPoints.size; index++ )
  129. {
  130. level.spawnMins = expandMins( level.spawnMins, spawnPoints[index].origin );
  131. level.spawnMaxs = expandMaxs( level.spawnMaxs, spawnPoints[index].origin );
  132. }
  133. }
  134.  
  135. setMapCenterForReflections()
  136. {
  137. level.spawnMins = (0,0,0);
  138. level.spawnMaxs = (0,0,0);
  139.  
  140. maps\mp\gametypes\_spawnlogic::expandSpawnpointBounds( "mp_tdm_spawn_allies_start" );
  141. maps\mp\gametypes\_spawnlogic::expandSpawnpointBounds( "mp_tdm_spawn_axis_start" );
  142. level.mapCenter = maps\mp\gametypes\_spawnlogic::findBoxCenter( level.spawnMins, level.spawnMaxs );
  143. setMapCenter( level.mapCenter );
  144. }
  145.  
  146. // initspawnpoint()
  147. spawnPointInit()
  148. {
  149. spawnpoint = self;
  150. origin = spawnpoint.origin;
  151.  
  152. level.spawnMins = expandMins( level.spawnMins, origin );
  153. level.spawnMaxs = expandMaxs( level.spawnMaxs, origin );
  154.  
  155. spawnpoint placeSpawnpoint();
  156. spawnpoint.forward = anglesToForward( spawnpoint.angles );
  157. spawnpoint.sightTracePoint = spawnpoint.origin + (0,0,50);
  158.  
  159. spawnpoint.lastspawnedplayer = spawnpoint; // just want this to be any entity for which isalive() returns false
  160. spawnpoint.lastspawntime = gettime();
  161.  
  162. skyHeight = 1024;
  163. spawnpoint.outside = true;
  164. if ( !bullettracepassed( spawnpoint.sightTracePoint, spawnpoint.sightTracePoint + (0,0,skyHeight), false, undefined) )
  165. {
  166. startpoint = spawnpoint.sightTracePoint + spawnpoint.forward * 100;
  167. if ( !bullettracepassed( startpoint, startpoint + (0,0,skyHeight), false, undefined) )
  168. spawnpoint.outside = false;
  169. }
  170.  
  171. right = anglesToRight( spawnpoint.angles );
  172. spawnpoint.alternates = [];
  173. AddAlternateSpawnpoint( spawnpoint, spawnpoint.origin + right * 45 );
  174. AddAlternateSpawnpoint( spawnpoint, spawnpoint.origin - right * 45 );
  175. //AddAlternateSpawnpoint( spawnpoint, spawnpoint.origin + spawnpoint.forward * 45 );
  176.  
  177. /*
  178. spawnpoint.secondFloor = false;
  179. if ( isDefined( level.spawnSecondFloorTrig ) )
  180. {
  181. spawnpoint.secondFloor = (spawnpoint isTouching( level.spawnSecondFloorTrig ));
  182.  
  183. spawnpoint.floorTransitionDistances = [];
  184.  
  185. for ( pointIndex = 0; pointIndex < level.spawnFloorTransitions.size; pointIndex++ )
  186. {
  187. spawnpoint.floorTransitionDistances[ pointIndex ] = distance( level.spawnFloorTransitions[ pointIndex ], spawnpoint.origin );
  188. }
  189. }
  190. */
  191.  
  192. spawnPointUpdate( spawnpoint );
  193.  
  194. spawnpoint.inited = true;
  195. }
  196.  
  197. AddAlternateSpawnpoint( spawnpoint, alternatepos )
  198. {
  199. spawnpointposRaised = playerPhysicsTrace( spawnpoint.origin, spawnpoint.origin + (0,0,18), false, undefined );
  200. zdiff = spawnpointposRaised[2] - spawnpoint.origin[2];
  201.  
  202. alternateposRaised = (alternatepos[0], alternatepos[1], alternatepos[2] + zdiff );
  203.  
  204. traceResult = playerPhysicsTrace( spawnpointposRaised, alternateposRaised, false, undefined );
  205. if ( traceResult != alternateposRaised )
  206. return;
  207.  
  208. finalAlternatePos = playerPhysicsTrace( alternateposRaised, alternatepos );
  209.  
  210. spawnpoint.alternates[ spawnpoint.alternates.size ] = finalAlternatePos;
  211. }
  212.  
  213.  
  214. getTeamSpawnPoints( team )
  215. {
  216. return level.teamSpawnPoints[team];
  217. }
  218.  
  219. // selects a spawnpoint, preferring ones with heigher weights (or toward the beginning of the array if no weights).
  220. // also does final things like setting self.lastspawnpoint to the one chosen.
  221. // this takes care of avoiding telefragging, so it doesn't have to be considered by any other function.
  222. getSpawnpoint_Final( spawnpoints, useweights )
  223. {
  224. prof_begin( "spawn_final" );
  225.  
  226. bestspawnpoint = undefined;
  227.  
  228. if ( !isdefined( spawnpoints ) || spawnpoints.size == 0 )
  229. return undefined;
  230.  
  231. if ( !isdefined( useweights ) )
  232. useweights = true;
  233.  
  234. if ( useweights )
  235. {
  236. // choose spawnpoint with best weight
  237. // (if a tie, choose randomly from the best)
  238. bestspawnpoint = getBestWeightedSpawnpoint( spawnpoints );
  239. /#
  240. thread spawnWeightDebug( spawnpoints, bestspawnpoint );
  241. #/
  242. }
  243. else
  244. {
  245. carePackages = getEntArray( "care_package", "targetname" );
  246. // (only place we actually get here from is getSpawnpoint_Random() )
  247. // no weights. prefer spawnpoints toward beginning of array
  248. for ( i = 0; i < spawnpoints.size; i++ )
  249. {
  250. if( isdefined( self.lastspawnpoint ) && self.lastspawnpoint == spawnpoints[i] )
  251. continue;
  252.  
  253. if ( positionWouldTelefrag( spawnpoints[i].origin ) )
  254. continue;
  255.  
  256. if ( carePackages.size && !canSpawn( spawnpoints[i].origin ) )
  257. continue;
  258.  
  259. bestspawnpoint = spawnpoints[i];
  260. break;
  261. }
  262. if ( !isdefined( bestspawnpoint ) )
  263. {
  264. // Couldn't find a useable spawnpoint. All spawnpoints either telefragged or were our last spawnpoint
  265. // Our only hope is our last spawnpoint - unless it too will telefrag...
  266. if ( isdefined( self.lastspawnpoint ) && !positionWouldTelefrag( self.lastspawnpoint.origin ) )
  267. {
  268. // (make sure our last spawnpoint is in the valid array of spawnpoints to use)
  269. for ( i = 0; i < spawnpoints.size; i++ )
  270. {
  271. if ( spawnpoints[i] == self.lastspawnpoint )
  272. {
  273. bestspawnpoint = spawnpoints[i];
  274. break;
  275. }
  276. }
  277. }
  278. }
  279. }
  280.  
  281. if ( !isdefined( bestspawnpoint ) )
  282. {
  283. // couldn't find a useable spawnpoint! all will telefrag.
  284. if ( useweights )
  285. {
  286. // at this point, forget about weights. just take a random one.
  287. bestspawnpoint = spawnpoints[randomint(spawnpoints.size)];
  288. }
  289. else
  290. {
  291. bestspawnpoint = spawnpoints[0];
  292. }
  293. }
  294.  
  295. prof_end( "spawn_final" );
  296.  
  297. return bestspawnpoint;
  298. }
  299.  
  300. finalizeSpawnpointChoice( spawnpoint )
  301. {
  302. time = getTime();
  303.  
  304. self.lastspawnpoint = spawnpoint;
  305. self.lastspawntime = time;
  306. spawnpoint.lastspawnedplayer = self;
  307. spawnpoint.lastspawntime = time;
  308. }
  309.  
  310. maxSightTracedSpawnpoints = 3;
  311.  
  312. getBestWeightedSpawnpoint( spawnpoints )
  313. {
  314. otherteam = getOtherTeam( self.team );
  315.  
  316. assert( spawnpoints.size > 0 );
  317.  
  318. for ( try = 0; ; try++ )
  319. {
  320. bestspawnpoints = [];
  321. bestspawnpoints[0] = spawnpoints[0];
  322. bestweight = spawnpoints[0].weight;
  323. for ( i = 1; i < spawnpoints.size; i++ )
  324. {
  325. spawnpoint = spawnpoints[i];
  326. if ( spawnpoint.weight > bestweight )
  327. {
  328. bestspawnpoints = [];
  329. bestspawnpoints[0] = spawnpoint;
  330. bestweight = spawnpoint.weight;
  331. }
  332. else if ( spawnpoint.weight == bestweight )
  333. {
  334. bestspawnpoints[bestspawnpoints.size] = spawnpoint;
  335. }
  336. }
  337.  
  338. // pick randomly from the available spawnpoints with the best weight
  339. assert( bestspawnpoints.size > 0 );
  340. bestspawnpoint = bestspawnpoints[randomint( bestspawnpoints.size )];
  341.  
  342. if ( try >= maxSightTracedSpawnpoints )
  343. {
  344. println( "Spawning " + self.name + " at spawnpoint " + bestspawnpoint.origin + " because the " + maxSightTracedSpawnpoints + " best spawnpoints failed last minute sight trace tests." );
  345. /# DumpSpawnData( spawnpoints, bestspawnpoint ); #/
  346. return bestspawnpoint;
  347. }
  348.  
  349. // if we already know that this spawnpoint has sight lines to the enemy team, and it's still the best we've got, there's no point doing more traces.
  350. sights = 0;
  351. if ( level.teambased )
  352. sights = bestspawnpoint.sights[otherteam];
  353. else
  354. sights = bestspawnpoint.sights;
  355.  
  356. if ( sights > 0 )
  357. {
  358. println( "Spawning " + self.name + " at spawnpoint " + bestspawnpoint.origin + " even though " + sights + " lines of sight to the enemy exist." );
  359. /# DumpSpawnData( spawnpoints, bestspawnpoint ); #/
  360. return bestspawnpoint;
  361. }
  362.  
  363. if ( isdefined( bestspawnpoint.lastSightTraceTime ) && bestspawnpoint.lastSightTraceTime == gettime() )
  364. return bestspawnpoint;
  365.  
  366. sightValue = lastMinuteSightTraces( bestspawnpoint );
  367. if ( sightValue == 0 )
  368. return bestspawnpoint;
  369.  
  370. sightValue = adjustSightValue( sightvalue );
  371. if ( level.teambased )
  372. bestspawnpoint.sights[otherteam] += sightValue;
  373. else
  374. bestspawnpoint.sights += sightValue;
  375.  
  376. penalty = getLosPenalty() * sightValue;
  377. /#
  378. bestspawnpoint.spawnData[bestspawnpoint.spawnData.size] = "Last minute sight trace: -" + penalty;
  379. #/
  380. bestspawnpoint.weight -= penalty;
  381.  
  382. bestspawnpoint.lastSightTraceTime = gettime();
  383. }
  384. assertmsg( "can't get here" );
  385. }
  386.  
  387. /#
  388.  
  389. DumpSpawnData( spawnpoints, winnerspawnpoint )
  390. {
  391. if ( getSubStr( self.name, 0, 3 ) == "bot" )
  392. {
  393. if ( getdvarint("scr_spawnpointdebug") == 0 )
  394. return;
  395. }
  396.  
  397. println( "=================================" );
  398. println( "spawndata = spawnstruct();" );
  399. println( "spawndata.playername = \"" + self.name + "\";" );
  400. println( "spawndata.friends = [];" );
  401. println( "spawndata.enemies = [];" );
  402. foreach ( player in level.players )
  403. {
  404. if ( player.team == self.team )
  405. println( "spawndata.friends[ spawndata.friends.size ] = " + player.origin + ";" );
  406. else
  407. println( "spawndata.enemies[ spawndata.enemies.size ] = " + player.origin + ";" );
  408. }
  409. println( "spawndata.otherdata = [];" );
  410.  
  411. println( "spawndata.spawnpoints = [];" );
  412. index = 0;
  413. foreach ( spawnpoint in spawnpoints )
  414. {
  415. if ( spawnpoint == winnerspawnpoint )
  416. println( "spawndata.spawnpointwinner = " + index + ";" );
  417.  
  418. println( "spawnpoint = spawnstruct();" );
  419. println( "spawnpoint.weight = " + spawnpoint.weight + ";" );
  420. println( "spawnpoint.origin = " + spawnpoint.origin + ";" );
  421. println( "spawnpoint.spawndata = [];" );
  422. for ( i = 0; i < spawnpoint.spawndata.size; i++ )
  423. {
  424. println( "spawnpoint.spawndata[" + i + "] = \"" + spawnpoint.spawndata[i] + "\";" );
  425. }
  426.  
  427. println( "spawndata.spawnpoints[spawndata.spawnpoints.size] = spawnpoint;" );
  428. index++;
  429. }
  430. println( "=================================" );
  431. }
  432.  
  433. DrawRecordedSpawnData()
  434. {
  435. spawndata = undefined;
  436.  
  437. // to remove line beginnings from console log, use regexp: ^\[.*\]
  438. // ====================================
  439. // paste console log output in here
  440. // ====================================
  441.  
  442. if ( isDefined( spawndata ) )
  443. thread drawSpawnData( spawndata );
  444. }
  445.  
  446. checkBad( spawnpoint )
  447. {
  448. for ( i = 0; i < level.players.size; i++ )
  449. {
  450. player = level.players[i];
  451.  
  452. if ( !isAlive( player ) || player.sessionstate != "playing" )
  453. continue;
  454. if ( level.teambased && player.team == self.team )
  455. continue;
  456.  
  457. losExists = bullettracepassed(player.origin + (0,0,50), spawnpoint.sightTracePoint, false, undefined);
  458. if ( losExists )
  459. thread badSpawnLine( spawnpoint.sightTracePoint, player.origin + (0,0,50), self.name, player.name );
  460. }
  461. }
  462.  
  463. badSpawnLine( start, end, name1, name2 )
  464. {
  465. dist = distance(start,end);
  466. for ( i = 0; i < 20 * 10; i++ )
  467. {
  468. line( start, end, (1,0,0) );
  469. print3d( start, "Bad spawn! " + name1 + ", dist = " + dist );
  470. print3d( end, name2 );
  471.  
  472. wait .05;
  473. }
  474. }
  475.  
  476. drawSpawnData( spawndata )
  477. {
  478. level notify("drawing_spawn_data");
  479. level endon("drawing_spawn_data");
  480.  
  481. textoffset = (0,0,-12);
  482.  
  483. fakeplayer = spawnstruct();
  484. fakeplayer.name = spawndata.playername;
  485.  
  486. fakeplayer thread spawnWeightDebug( spawndata.spawnpoints, spawndata.spawnpoints[spawndata.spawnpointwinner] );
  487.  
  488. while(1)
  489. {
  490. for (i = 0; i < spawndata.friends.size; i++)
  491. {
  492. print3d(spawndata.friends[i], "=)", (.5,1,.5), 1, 5);
  493. }
  494. for (i = 0; i < spawndata.enemies.size; i++)
  495. {
  496. print3d(spawndata.enemies[i], "=(", (1,.5,.5), 1, 5);
  497. }
  498.  
  499. for (i = 0; i < spawndata.otherdata.size; i++)
  500. {
  501. print3d(spawndata.otherdata[i].origin, spawndata.otherdata[i].text, (.5,.75,1), 1, 2);
  502. }
  503.  
  504. wait .05;
  505. }
  506. }
  507.  
  508. #/
  509.  
  510. getSpawnpoint_Random(spawnpoints)
  511. {
  512. // level endon("game_ended");
  513.  
  514. // There are no valid spawnpoints in the map
  515. if(!isdefined(spawnpoints))
  516. return undefined;
  517.  
  518. // randomize order
  519. for ( i = 0; i < spawnpoints.size; i++ )
  520. {
  521. j = randomInt(spawnpoints.size);
  522. spawnpoint = spawnpoints[i];
  523. spawnpoints[i] = spawnpoints[j];
  524. spawnpoints[j] = spawnpoint;
  525. }
  526.  
  527. if ( isDefined( self.predictedSpawnPoint ) )
  528. {
  529. // if we predicted spawning at one of these spawnpoints already, favor that one.
  530. for ( i = 1; i < spawnpoints.size; i++ )
  531. {
  532. if ( spawnpoints[i] == self.predictedSpawnPoint )
  533. {
  534. temp = spawnpoints[0];
  535. spawnpoints[0] = spawnpoints[i];
  536. spawnpoints[i] = temp;
  537. break;
  538. }
  539. }
  540. }
  541.  
  542. return getSpawnpoint_Final(spawnpoints, false);
  543. }
  544.  
  545. getAllOtherPlayers()
  546. {
  547. aliveplayers = [];
  548.  
  549. // Make a list of fully connected, non-spectating, alive players
  550. for(i = 0; i < level.players.size; i++)
  551. {
  552. if ( !isdefined( level.players[i] ) )
  553. continue;
  554. player = level.players[i];
  555.  
  556. if ( player.sessionstate != "playing" || player == self )
  557. continue;
  558.  
  559. aliveplayers[aliveplayers.size] = player;
  560. }
  561. return aliveplayers;
  562. }
  563.  
  564.  
  565. // weight array manipulation code
  566. initWeights(spawnpoints)
  567. {
  568. for (i = 0; i < spawnpoints.size; i++)
  569. spawnpoints[i].weight = 0;
  570.  
  571. /#
  572. for (i = 0; i < spawnpoints.size; i++) {
  573. spawnpoints[i].spawnData = [];
  574. }
  575. #/
  576. }
  577.  
  578. // ================================================
  579.  
  580.  
  581. getSpawnpoint_NearTeam( spawnpoints, favoredspawnpoints )
  582. {
  583. // level endon("game_ended");
  584.  
  585. /*if ( self.wantSafeSpawn )
  586. {
  587. return getSpawnpoint_SafeSpawn( spawnpoints );
  588. }*/
  589.  
  590. // There are no valid spawnpoints in the map
  591. if(!isdefined(spawnpoints))
  592. return undefined;
  593.  
  594. /#
  595. setDevDvarIfUninitialized("scr_spawn_randomly", "0");
  596. if ( getdvarint("scr_spawn_randomly") == 1 )
  597. return getSpawnpoint_Random( spawnpoints );
  598. #/
  599.  
  600. prof_begin("spawn_basiclogic");
  601.  
  602. /#
  603. if ( getdvarint("scr_spawnsimple") > 0 )
  604. return getSpawnpoint_Random( spawnpoints );
  605. #/
  606.  
  607. Spawnlogic_Begin();
  608.  
  609. initWeights(spawnpoints);
  610.  
  611. obj = spawnstruct();
  612.  
  613. alliedDistanceWeight = 2;
  614.  
  615. //prof_begin(" spawn_basicsumdists");
  616. myTeam = self.team;
  617. enemyTeam = getOtherTeam( myTeam );
  618.  
  619. carePackages = getEntArray( "care_package", "targetname" );
  620. foreach ( spawnpoint in spawnpoints )
  621. {
  622. if ( spawnpoint.numPlayersAtLastUpdate > 0 )
  623. {
  624. allyDistSum = spawnpoint.weightedDistSum[ myTeam ]; // we weight the allied distSum to account for things like snipers and tactical insertion
  625. enemyDistSum = spawnpoint.distSum[ enemyTeam ];
  626.  
  627. // high enemy distance is good, high ally distance is bad
  628. spawnpoint.weight = (enemyDistSum - alliedDistanceWeight*allyDistSum) / spawnpoint.numPlayersAtLastUpdate;
  629.  
  630. /#
  631. spawnpoint.spawnData[spawnpoint.spawnData.size] = "Base weight: " + int(spawnpoint.weight) + " = (" + int(enemyDistSum) + " - " + alliedDistanceWeight + "*" + int(allyDistSum) + ") / " + spawnpoint.numPlayersAtLastUpdate;
  632. #/
  633. }
  634. else
  635. {
  636. spawnpoint.weight = 0;
  637.  
  638. /#
  639. spawnpoint.spawnData[spawnpoint.spawnData.size] = "Base weight: 0";
  640. #/
  641. }
  642.  
  643. if ( carePackages.size && !canSpawn( spawnpoint.origin ) )
  644. spawnpoint.weight -= 500000;
  645. }
  646. //prof_end(" spawn_basicsumdists");
  647.  
  648. if ( isdefined( favoredspawnpoints ) )
  649. {
  650. for (i = 0; i < favoredspawnpoints.size; i++)
  651. {
  652. favoredspawnpoints[i].weight += 50000;
  653. /#
  654. favoredspawnpoints[i].spawnData[favoredspawnpoints[i].spawnData.size] = "Favored: 50000";
  655. #/
  656. }
  657. }
  658.  
  659. if ( isDefined( self.predictedSpawnPoint ) && isDefined( self.predictedSpawnPoint.weight ) )
  660. {
  661. // add a tiebreaker in case we end up choosing between spawnpoints of similar weight
  662. self.predictedSpawnPoint.weight += 100;
  663. /#
  664. self.predictedSpawnPoint.spawnData[self.predictedSpawnPoint.spawnData.size] = "Predicted: 100";
  665. #/
  666. }
  667.  
  668. prof_end("spawn_basiclogic");
  669.  
  670. prof_begin("spawn_complexlogic");
  671.  
  672. avoidSameSpawn();
  673. // not avoiding spawn reuse because it doesn't do anything nearbyPenalty doesn't do
  674. //avoidSpawnReuse(spawnpoints, true);
  675. // not avoiding spawning near recent deaths for team-based modes. kills the fast pace.
  676. //avoidDangerousSpawns(spawnpoints, true);
  677. avoidWeaponDamage(spawnpoints);
  678. avoidVisibleEnemies(spawnpoints, true);
  679.  
  680. prof_end("spawn_complexlogic");
  681.  
  682. result = getSpawnpoint_Final(spawnpoints);
  683.  
  684. /#
  685. setdevdvarIfUninitialized("scr_spawn_showbad", "0");
  686. if ( getdvarint("scr_spawn_showbad") == 1 )
  687. checkBad( result );
  688. #/
  689.  
  690. return result;
  691. }
  692.  
  693. getSpawnpoint_SafeSpawn( spawnpoints )
  694. {
  695. // There are no valid spawnpoints in the map
  696. if ( !isdefined( spawnpoints ) )
  697. return undefined;
  698. assert( spawnpoints.size > 0 );
  699.  
  700. Spawnlogic_Begin();
  701.  
  702. safestSpawnpoint = undefined;
  703. safestDangerDist = undefined;
  704.  
  705. enemyTeam = getOtherTeam( self.team );
  706. if ( !level.teambased )
  707. enemyTeam = "all";
  708.  
  709. mingrenadedistsquared = 500 * 500;
  710.  
  711. foreach ( spawnpoint in spawnpoints )
  712. {
  713. dangerDist = spawnpoint.minDist[ enemyTeam ];
  714.  
  715. foreach ( grenade in level.grenades )
  716. {
  717. if ( !isdefined( grenade ) )
  718. continue;
  719.  
  720. if ( distancesquared( spawnpoint.origin, grenade.origin ) < mingrenadedistsquared )
  721. {
  722. grenadeDist = distance( spawnpoint.origin, grenade.origin ) - 220;
  723. if ( grenadeDist < dangerDist )
  724. {
  725. if ( grenadeDist < 0 )
  726. grenadeDist = 0;
  727. dangerDist = grenadeDist;
  728. }
  729. }
  730. }
  731.  
  732. if ( positionWouldTelefrag( spawnpoint.origin ) )
  733. dangerDist -= 200; // discourage telefragging but don't worry too much
  734.  
  735. if ( isDefined( level.artilleryDangerCenters ) )
  736. {
  737. airstrikeDanger = maps\mp\killstreaks\_airstrike::getAirstrikeDanger( spawnpoint.origin );
  738. if ( airstrikeDanger > 0 )
  739. dangerDist = 0;
  740. }
  741.  
  742. if ( level.teambased )
  743. {
  744. if ( spawnpoint.sights[enemyTeam] > 0 )
  745. dangerDist = 0;
  746. }
  747. else
  748. {
  749. if ( spawnpoint.sights > 0 )
  750. dangerDist = 0;
  751. }
  752.  
  753. if ( !isdefined( safestSpawnpoint ) || dangerDist > safestDangerDist )
  754. {
  755. safestSpawnpoint = spawnpoint;
  756. safestDangerDist = dangerDist;
  757. }
  758. }
  759.  
  760. assert( isdefined( safestSpawnpoint ) );
  761. if ( !isdefined( safestSpawnpoint ) )
  762. {
  763. safestSpawnpoint = spawnpoints[ randomint( spawnpoints.size ) ];
  764. safestSpawnpoint.safeSpawnDangerDist = 500;
  765. }
  766. else
  767. {
  768. safestSpawnpoint.safeSpawnDangerDist = safestDangerDist;
  769. }
  770.  
  771. return safestSpawnpoint;
  772. }
  773.  
  774. /////////////////////////////////////////////////////////////////////////
  775.  
  776. getSpawnpoint_DM(spawnpoints)
  777. {
  778. // level endon("game_ended");
  779.  
  780. /*if ( self.wantSafeSpawn )
  781. {
  782. return getSpawnpoint_SafeSpawn( spawnpoints );
  783. }*/
  784.  
  785. // There are no valid spawnpoints in the map
  786. if(!isdefined(spawnpoints))
  787. return undefined;
  788.  
  789. Spawnlogic_Begin();
  790.  
  791. initWeights(spawnpoints);
  792.  
  793. aliveplayers = getAllOtherPlayers();
  794.  
  795. // new logic: we want most players near idealDist units away.
  796. // players closer than badDist units will be considered negatively
  797. idealDist = 1600;
  798. badDist = 1200;
  799.  
  800. if (aliveplayers.size > 0 )
  801. {
  802. for (i = 0; i < spawnpoints.size; i++)
  803. {
  804. totalDistFromIdeal = 0;
  805. nearbyBadAmount = 0;
  806. for (j = 0; j < aliveplayers.size; j++)
  807. {
  808. dist = distance(spawnpoints[i].origin, aliveplayers[j].origin);
  809.  
  810. if (dist < badDist)
  811. nearbyBadAmount += (badDist - dist) / badDist;
  812.  
  813. distfromideal = abs(dist - idealDist);
  814. totalDistFromIdeal += distfromideal;
  815. }
  816. avgDistFromIdeal = totalDistFromIdeal / aliveplayers.size;
  817.  
  818. wellDistancedAmount = (idealDist - avgDistFromIdeal) / idealDist;
  819. // if (wellDistancedAmount < 0) wellDistancedAmount = 0;
  820.  
  821. // wellDistancedAmount is between -inf and 1, 1 being best (likely around 0 to 1)
  822. // nearbyBadAmount is between 0 and inf,
  823. // and it is very important that we get a bad weight if we have a high nearbyBadAmount.
  824.  
  825. spawnpoints[i].weight = wellDistancedAmount - nearbyBadAmount * 2 + randomfloat(.2);
  826. }
  827. }
  828.  
  829. carePackages = getEntArray( "care_package", "targetname" );
  830.  
  831. for (i = 0; i < spawnpoints.size; i++)
  832. {
  833. if ( carePackages.size && !canSpawn( spawnpoints[i].origin ) )
  834. spawnpoints[i].weight -= 500000;
  835. }
  836.  
  837. if ( isDefined( self.predictedSpawnPoint ) && isDefined( self.predictedSpawnPoint.weight ) )
  838. {
  839. // add a tiebreaker in case we end up choosing between spawnpoints of similar weight
  840. self.predictedSpawnPoint.weight += 100;
  841. /#
  842. self.predictedSpawnPoint.spawnData[self.predictedSpawnPoint.spawnData.size] = "Predicted: 100";
  843. #/
  844. }
  845.  
  846. avoidSameSpawn();
  847. //avoidSpawnReuse(spawnpoints, false);
  848. //avoidDangerousSpawns(spawnpoints, false);
  849. avoidWeaponDamage(spawnpoints);
  850. avoidVisibleEnemies(spawnpoints, false);
  851.  
  852. return getSpawnpoint_Final(spawnpoints);
  853. }
  854.  
  855. // =============================================
  856.  
  857. // called at the start of every spawn
  858. Spawnlogic_Begin()
  859. {
  860. //updateDeathInfo();
  861.  
  862. /#
  863. level.debugSpawning = (getdvarint("scr_spawnpointdebug") > 0);
  864. #/
  865. }
  866.  
  867. // called once at start of game
  868. init()
  869. {
  870. /#
  871. setDevDvarIfUninitialized("scr_spawnpointdebug", "0");
  872. setDevDvarIfUninitialized("scr_killbots", 0);
  873. setDevDvarIfUninitialized("scr_killbottimer", 0);
  874.  
  875. thread loopbotspawns();
  876. #/
  877.  
  878. // start keeping track of deaths
  879. level.spawnlogic_deaths = [];
  880. // DEBUG
  881. level.spawnlogic_spawnkills = [];
  882. level.players = [];
  883. level.grenades = [];
  884. level.pipebombs = [];
  885. level.turrets = [];
  886. level.helis = [];
  887. level.tanks = [];
  888.  
  889. level.teamSpawnPoints["axis"] = [];
  890. level.teamSpawnPoints["allies"] = [];
  891.  
  892. level thread trackGrenades();
  893.  
  894. level.spawnMins = (0,0,0);
  895. level.spawnMaxs = (0,0,0);
  896. if ( isdefined( level.safespawns ) )
  897. {
  898. for( i = 0; i < level.safespawns.size; i++ )
  899. {
  900. level.safespawns[i] spawnPointInit();
  901. }
  902. }
  903.  
  904. /*
  905. level.spawnSecondFloorTrig = getent( "spawn_second_floor", "targetname" );
  906. if ( isDefined( level.spawnSecondFloorTrig ) )
  907. {
  908. transitions = getentarray( level.spawnSecondFloorTrig.target, "targetname" );
  909. level.spawnFloorTransitions = [];
  910.  
  911. foreach ( org in transitions )
  912. {
  913. level.spawnFloorTransitions[ level.spawnFloorTransitions.size ] = org.origin;
  914. org delete();
  915. }
  916. }
  917. */
  918.  
  919. // DEBUG
  920. /#
  921. if (getdvarint("scr_spawnpointdebug") > 0)
  922. {
  923. thread profileDebug();
  924.  
  925. thread drawRecordedSpawnData();
  926. }
  927. thread watchSpawnProfile();
  928. thread spawnGraphCheck();
  929. thread sightCheckCost();
  930. #/
  931. }
  932. /#
  933.  
  934. sightCheckCost()
  935. {
  936. traceCount = 30;
  937.  
  938. for ( ;; )
  939. {
  940. prof_begin( "sight_check_cost" );
  941.  
  942. traceType = getDvar( "scr_debugcost" );
  943.  
  944. if ( traceType == "bullet" && isDefined( level.players[0] ) )
  945. {
  946. for ( i = 0; i < traceCount; i++ )
  947. bulletTracePassed( level.players[0].origin + (0,0,50), (0,0,0), false, undefined );
  948.  
  949. }
  950. else if ( traceType == "damagecone" && isDefined( level.players[0] ) )
  951. {
  952. for ( i = 0; i < traceCount; i++ )
  953. level.players[0] damageConeTrace( (0,0,0) );
  954. }
  955. else if ( traceType == "sightcone" && isDefined( level.players[0] ) )
  956. {
  957. for ( i = 0; i < traceCount; i++ )
  958. level.players[0] sightConeTrace( (0,0,0) );
  959. }
  960. else
  961. {
  962. wait ( 1.0 );
  963. }
  964.  
  965. prof_end( "sight_check_cost" );
  966.  
  967. wait ( 0.05 );
  968. }
  969. }
  970.  
  971. watchSpawnProfile()
  972. {
  973. while(1)
  974. {
  975. while( getDvar( "scr_spawnprofile" ) == "" || getDvar( "scr_spawnprofile" ) == "0" )
  976. wait ( 0.05 );
  977.  
  978. thread spawnProfile();
  979.  
  980. while( getDvar( "scr_spawnprofile" ) != "" && getDvar( "scr_spawnprofile" ) != "0" )
  981. wait ( 0.05 );
  982.  
  983. level notify("stop_spawn_profile");
  984. }
  985. }
  986.  
  987. spawnProfile()
  988. {
  989. level endon("stop_spawn_profile");
  990.  
  991. spawnObj = spawnStruct();
  992.  
  993. while(1)
  994. {
  995. /*
  996.  
  997. if ( level.players.size > 0 && level.spawnpoints.size > 0 )
  998. {
  999. playerNum = randomint(level.players.size);
  1000. player = level.players[playerNum];
  1001.  
  1002. if ( player.team != "allies" && player.team != "axis" )
  1003. continue;
  1004.  
  1005. if ( level.teamBased && (getDvar( "scr_spawnprofile" ) == "allies" || getDvar( "scr_spawnprofile" ) == "axis") && player.team != getDvar( "scr_spawnprofile" ) )
  1006. continue;
  1007.  
  1008. attempt = 1;
  1009. while ( !isdefined( player ) && attempt < level.players.size )
  1010. {
  1011. playerNum = ( playerNum + 1 ) % level.players.size;
  1012. attempt++;
  1013. player = level.players[playerNum];
  1014. }
  1015.  
  1016. player getSpawnpoint_NearTeam(level.spawnpoints);
  1017. }
  1018. */
  1019.  
  1020. dvarString = getDvar( "scr_spawnprofile" );
  1021.  
  1022. if ( dvarString != "allies" && dvarString != "axis" )
  1023. {
  1024. if ( cointoss() )
  1025. dvarString = "allies";
  1026. else
  1027. dvarString = "axis";
  1028. }
  1029.  
  1030. spawnObj.team = dvarString;
  1031. spawnObj.pers["team"] = dvarString;
  1032.  
  1033. spawnObj getSpawnpoint_NearTeam(level.spawnpoints);
  1034. wait ( 0.05 );
  1035. }
  1036. }
  1037.  
  1038. spawnGraphCheck()
  1039. {
  1040. while(1)
  1041. {
  1042. if ( getdvarint("scr_spawngraph") < 1 )
  1043. {
  1044. wait 3;
  1045. continue;
  1046. }
  1047. thread spawnGraph();
  1048. while ( getdvarint("scr_spawngraph") >= 1 )
  1049. {
  1050. wait .2;
  1051. continue;
  1052. }
  1053. level notify( "end_spawn_graph" );
  1054. level notify( "spawn_graph_stop_draw" );
  1055. }
  1056. }
  1057.  
  1058. spawnGraph()
  1059. {
  1060. level endon( "end_spawn_graph" );
  1061.  
  1062. w = 20;
  1063. h = 20;
  1064. weightscale = .1;
  1065. fakespawnpoints = [];
  1066.  
  1067. corners = getentarray("minimap_corner", "targetname");
  1068. if ( corners.size != 2 )
  1069. {
  1070. println("^1 can't spawn graph: no minimap corners");
  1071. return;
  1072. }
  1073. min = corners[0].origin;
  1074. max = corners[0].origin;
  1075. if ( corners[1].origin[0] > max[0] )
  1076. max = (corners[1].origin[0], max[1], max[2]);
  1077. else
  1078. min = (corners[1].origin[0], min[1], min[2]);
  1079. if ( corners[1].origin[1] > max[1] )
  1080. max = (max[0], corners[1].origin[1], max[2]);
  1081. else
  1082. min = (min[0], corners[1].origin[1], min[2]);
  1083.  
  1084. i = 0;
  1085. for ( y = 0; y < h; y++ )
  1086. {
  1087. yamnt = y / (h - 1);
  1088. for ( x = 0; x < w; x++ )
  1089. {
  1090. xamnt = x / (w - 1);
  1091. fakespawnpoints[i] = spawnstruct();
  1092. fakespawnpoints[i].origin = (min[0] * xamnt + max[0] * (1-xamnt), min[1] * yamnt + max[1] * (1-yamnt), min[2]);
  1093. fakespawnpoints[i].angles = (0,0,0);
  1094.  
  1095. fakespawnpoints[i].forward = anglesToForward( fakespawnpoints[i].angles );
  1096. fakespawnpoints[i].sightTracePoint = fakespawnpoints[i].origin;
  1097. fakespawnpoints[i].outside = true;
  1098. fakespawnpoints[i].secondfloor = false;
  1099. fakespawnpoints[i].fake = true;
  1100.  
  1101. i++;
  1102. }
  1103. }
  1104.  
  1105. didweights = false;
  1106.  
  1107. while(1)
  1108. {
  1109. spawni = 0;
  1110. numiters = 10;
  1111. for ( i = 0; i < numiters; i++ )
  1112. {
  1113. if ( !level.players.size || !isdefined( level.players[0].team ) || level.players[0].team == "spectator" || !isdefined( level.players[0].class ) )
  1114. break;
  1115.  
  1116. endspawni = spawni + fakespawnpoints.size / numiters;
  1117. if ( i == numiters - 1 )
  1118. endspawni = fakespawnpoints.size;
  1119.  
  1120. for ( ; spawni < endspawni; spawni++ )
  1121. {
  1122. spawnPointUpdate( fakespawnpoints[spawni] );
  1123. }
  1124.  
  1125. wait .05;
  1126. }
  1127.  
  1128. if ( !level.players.size || !isdefined( level.players[0].team ) || level.players[0].team == "spectator" || !isdefined( level.players[0].class ) )
  1129. {
  1130. wait 1;
  1131. continue;
  1132. }
  1133.  
  1134. level.players[0] getSpawnpoint_NearTeam( fakespawnpoints );
  1135.  
  1136. for ( i = 0; i < fakespawnpoints.size; i++ )
  1137. setupSpawnGraphPoint( fakespawnpoints[i], weightscale );
  1138.  
  1139. didweights = true;
  1140.  
  1141. level.players[0] drawSpawnGraph( fakespawnpoints, w, h, weightscale );
  1142.  
  1143. wait .05;
  1144. }
  1145. }
  1146.  
  1147. drawSpawnGraph( fakespawnpoints, w, h, weightscale )
  1148. {
  1149. level notify( "spawn_graph_stop_draw" );
  1150.  
  1151. i = 0;
  1152. for ( y = 0; y < h; y++ )
  1153. {
  1154. yamnt = y / (h - 1);
  1155. for ( x = 0; x < w; x++ )
  1156. {
  1157. xamnt = x / (w - 1);
  1158.  
  1159. if ( y > 0 )
  1160. {
  1161. thread spawnGraphLine( fakespawnpoints[i], fakespawnpoints[i-w], weightscale );
  1162. }
  1163. if ( x > 0 )
  1164. {
  1165. thread spawnGraphLine( fakespawnpoints[i], fakespawnpoints[i-1], weightscale );
  1166. }
  1167. i++;
  1168. }
  1169. }
  1170. }
  1171.  
  1172. setupSpawnGraphPoint( s1, weightscale )
  1173. {
  1174. s1.visible = true;
  1175. if ( s1.weight < -1000/weightscale )
  1176. {
  1177. s1.visible = false;
  1178. }
  1179. }
  1180.  
  1181. spawnGraphLine( s1, s2, weightscale )
  1182. {
  1183. if ( !s1.visible || !s2.visible )
  1184. return;
  1185.  
  1186. p1 = s1.origin + (0,0,s1.weight*weightscale + 100);
  1187. p2 = s2.origin + (0,0,s2.weight*weightscale + 100);
  1188.  
  1189. level endon( "spawn_graph_stop_draw" );
  1190.  
  1191. for ( ;; )
  1192. {
  1193. line( p1, p2, (1,1,1) );
  1194. wait .05;
  1195. waittillframeend;
  1196. }
  1197. }
  1198.  
  1199. loopbotspawns()
  1200. {
  1201. while(1)
  1202. {
  1203. if ( getdvarint("scr_killbots") < 1 )
  1204. {
  1205. wait 3;
  1206. continue;
  1207. }
  1208. if ( !isdefined( level.players ) )
  1209. {
  1210. wait .05;
  1211. continue;
  1212. }
  1213.  
  1214. bots = [];
  1215. for (i = 0; i < level.players.size; i++)
  1216. {
  1217. if ( !isdefined( level.players[i] ) )
  1218. continue;
  1219.  
  1220. if ( level.players[i].sessionstate == "playing" && issubstr(level.players[i].name, "bot") )
  1221. {
  1222. bots[bots.size] = level.players[i];
  1223. }
  1224. }
  1225. if ( bots.size > 0 )
  1226. {
  1227. if ( getdvarint( "scr_killbots" ) == 1 )
  1228. {
  1229. killer = bots[randomint(bots.size)];
  1230. victim = bots[randomint(bots.size)];
  1231.  
  1232. victim thread [[level.callbackPlayerDamage]] (
  1233. killer, // eInflictor The entity that causes the damage.(e.g. a turret)
  1234. killer, // eAttacker The entity that is attacking.
  1235. 1000, // iDamage Integer specifying the amount of damage done
  1236. 0, // iDFlags Integer specifying flags that are to be applied to the damage
  1237. "MOD_RIFLE_BULLET", // sMeansOfDeath Integer specifying the method of death
  1238. "none", // sWeapon The weapon number of the weapon used to inflict the damage
  1239. (0,0,0), // vPoint The point the damage is from?
  1240. (0,0,0), // vDir The direction of the damage
  1241. "none", // sHitLoc The location of the hit
  1242. 0 // psOffsetTime The time offset for the damage
  1243. );
  1244. }
  1245. else
  1246. {
  1247. numKills = getdvarint( "scr_killbots" );
  1248. lastVictim = undefined;
  1249. for ( index = 0; index < numKills; index++ )
  1250. {
  1251. killer = bots[randomint(bots.size)];
  1252. victim = bots[randomint(bots.size)];
  1253.  
  1254. while ( isDefined( lastVictim ) && victim == lastVictim )
  1255. victim = bots[randomint(bots.size)];
  1256.  
  1257. victim thread [[level.callbackPlayerDamage]] (
  1258. killer, // eInflictor The entity that causes the damage.(e.g. a turret)
  1259. killer, // eAttacker The entity that is attacking.
  1260. 1000, // iDamage Integer specifying the amount of damage done
  1261. 0, // iDFlags Integer specifying flags that are to be applied to the damage
  1262. "MOD_RIFLE_BULLET", // sMeansOfDeath Integer specifying the method of death
  1263. "none", // sWeapon The weapon number of the weapon used to inflict the damage
  1264. (0,0,0), // vPoint The point the damage is from?
  1265. (0,0,0), // vDir The direction of the damage
  1266. "none", // sHitLoc The location of the hit
  1267. 0 // psOffsetTime The time offset for the damage
  1268. );
  1269.  
  1270. lastVictim = victim;
  1271. }
  1272. }
  1273. }
  1274.  
  1275. if ( getdvarfloat( "scr_killbottimer" ) > .05 )
  1276. wait getdvarfloat( "scr_killbottimer" );
  1277. else
  1278. wait .05;
  1279. }
  1280. }
  1281.  
  1282. spawnWeightDebug(spawnpoints, winner)
  1283. {
  1284. level notify("stop_spawn_weight_debug");
  1285. level endon("stop_spawn_weight_debug");
  1286. while(1)
  1287. {
  1288. if ( getdvarint("scr_spawnpointdebug") == 0 )
  1289. {
  1290. wait(3);
  1291. continue;
  1292. }
  1293.  
  1294. textoffset = (0,0,-12);
  1295. for (i = 0; i < spawnpoints.size; i++)
  1296. {
  1297. amnt = 1 * (1 - spawnpoints[i].weight / (-100000));
  1298. if (amnt < 0) amnt = 0;
  1299. if (amnt > 1) amnt = 1;
  1300.  
  1301. orig = spawnpoints[i].origin + (0,0,80);
  1302.  
  1303. print3d(orig, int(spawnpoints[i].weight), (1,amnt,.5));
  1304. orig += textoffset;
  1305.  
  1306. if ( spawnpoints[i] == winner )
  1307. {
  1308. print3d(orig, "Spawned " + self.name + " here", (1,amnt,.5));
  1309. orig += textoffset;
  1310. }
  1311.  
  1312. if (isdefined(spawnpoints[i].spawnData))
  1313. {
  1314. for (j = 0; j < spawnpoints[i].spawnData.size; j++)
  1315. {
  1316. print3d(orig, spawnpoints[i].spawnData[j], (.5,.5,.5));
  1317. orig += textoffset;
  1318. }
  1319. }
  1320.  
  1321. // "bar graph"
  1322. height = 0;
  1323. if ( spawnpoints[i].weight > -1000 )
  1324. height = (spawnpoints[i].weight + 1000) / 10;
  1325.  
  1326. amnt = spawnpoints[i].weight / 2000;
  1327. if (amnt < 0) amnt = 0;
  1328. if (amnt > 1) amnt = 1;
  1329.  
  1330. color = (1 - amnt, 1, 0);
  1331.  
  1332. pt1 = spawnpoints[i].origin + (0,0,95);
  1333. pt2 = spawnpoints[i].origin + (30,0,95);
  1334. pt3 = pt1 + (0,0,height);
  1335. pt4 = pt2 + (0,0,height);
  1336. line( pt1, pt2, color );
  1337. line( pt1, pt3, color );
  1338. line( pt2, pt4, color );
  1339. line( pt3, pt4, color );
  1340.  
  1341. if ( spawnpoints[i] == winner )
  1342. {
  1343. // checkmark
  1344. checkpt1 = pt3 + (0,0,30);
  1345. checkpt2 = pt3 + (10,0,10);
  1346. checkpt3 = pt3 + (30,0,50);
  1347.  
  1348. line( checkpt1, checkpt2, color );
  1349. line( checkpt2, checkpt3, color );
  1350. }
  1351. }
  1352. wait(.05);
  1353. }
  1354. }
  1355.  
  1356. profileDebug()
  1357. {
  1358. while(1)
  1359. {
  1360. if (getdvar("scr_spawnpointprofile") != "1") {
  1361. wait(3);
  1362. continue;
  1363. }
  1364.  
  1365. for (i = 0; i < level.spawnpoints.size; i++)
  1366. level.spawnpoints[i].weight = randomint(10000);
  1367. if (level.players.size > 0)
  1368. level.players[randomint(level.players.size)] getSpawnpoint_NearTeam(level.spawnpoints);
  1369.  
  1370. wait(.05);
  1371. }
  1372. }
  1373.  
  1374. debugNearbyPlayers(players, origin)
  1375. {
  1376. if ( getdvarint("scr_spawnpointdebug") == 0 )
  1377. return;
  1378.  
  1379. starttime = gettime();
  1380. while(1)
  1381. {
  1382. for (i = 0; i < players.size; i++)
  1383. line(players[i].origin, origin, (.5,1,.5));
  1384. if (gettime() - starttime > 5000)
  1385. return;
  1386. wait .05;
  1387. }
  1388. }
  1389. #/
  1390.  
  1391.  
  1392. trackGrenades()
  1393. {
  1394. while ( 1 )
  1395. {
  1396. level.grenades = getentarray("grenade", "classname");
  1397. wait .05;
  1398. }
  1399. }
  1400.  
  1401.  
  1402. // used by spawning; needs to be fast.
  1403. isPointVulnerable(playerorigin)
  1404. {
  1405. pos = self.origin + level.claymoremodelcenteroffset;
  1406. playerpos = playerorigin + (0,0,32);
  1407. distsqrd = distancesquared(pos, playerpos);
  1408.  
  1409. forward = anglestoforward(self.angles);
  1410.  
  1411. if (distsqrd < level.claymoreDetectionRadius*level.claymoreDetectionRadius)
  1412. {
  1413. playerdir = vectornormalize(playerpos - pos);
  1414. angle = acos(vectordot(playerdir, forward));
  1415. if (angle < level.claymoreDetectionConeAngle) {
  1416. return true;
  1417. }
  1418. }
  1419. return false;
  1420. }
  1421.  
  1422.  
  1423. avoidWeaponDamage(spawnpoints)
  1424. {
  1425. //prof_begin(" spawn_complexgrenade");
  1426.  
  1427. weaponDamagePenalty = 100000;
  1428. if (getdvar("scr_spawnpointweaponpenalty") != "" && getdvar("scr_spawnpointweaponpenalty") != "0")
  1429. weaponDamagePenalty = getdvarfloat("scr_spawnpointweaponpenalty");
  1430.  
  1431. mingrenadedistsquared = 250*250; // (actual grenade radius is 220, 250 includes a safety area of 30 units)
  1432.  
  1433. for (i = 0; i < spawnpoints.size; i++)
  1434. {
  1435. for (j = 0; j < level.grenades.size; j++)
  1436. {
  1437. if ( !isdefined( level.grenades[j] ) )
  1438. continue;
  1439.  
  1440. // could also do a sight check to see if it's really dangerous.
  1441. if (distancesquared(spawnpoints[i].origin, level.grenades[j].origin) < mingrenadedistsquared)
  1442. {
  1443. spawnpoints[i].weight -= weaponDamagePenalty;
  1444. /#
  1445. spawnpoints[i].spawnData[spawnpoints[i].spawnData.size] = "Was near grenade: -" + int(weaponDamagePenalty);
  1446. #/
  1447. }
  1448. }
  1449.  
  1450. if ( !isDefined( level.artilleryDangerCenters ) )
  1451. continue;
  1452.  
  1453. airstrikeDanger = maps\mp\killstreaks\_airstrike::getAirstrikeDanger( spawnpoints[i].origin ); // 0 = none, 1 = full, might be > 1 for more than 1 airstrike
  1454.  
  1455. if ( airstrikeDanger > 0 )
  1456. {
  1457. worsen = airstrikeDanger * weaponDamagePenalty;
  1458. spawnpoints[i].weight -= worsen;
  1459. /#
  1460. spawnpoints[i].spawnData[spawnpoints[i].spawnData.size] = "Was near artillery (" + int(airstrikeDanger*100) + "% danger): -" + int(worsen);
  1461. #/
  1462. }
  1463. }
  1464.  
  1465. //prof_end(" spawn_complexgrenade");
  1466. }
  1467.  
  1468. spawnPerFrameUpdate()
  1469. {
  1470. spawnpointindex = 0;
  1471.  
  1472. // each frame, do sight checks against a spawnpoint
  1473.  
  1474. while(1)
  1475. {
  1476. wait .05;
  1477.  
  1478. prof_begin("spawn_update");
  1479.  
  1480. //time = gettime();
  1481.  
  1482. if ( !isDefined( level.spawnPoints ) )
  1483. return;
  1484.  
  1485. spawnpointindex = (spawnpointindex + 1) % level.spawnPoints.size;
  1486.  
  1487. if ( getdvar( "scr_spawnpoint_forceindex" ) != "" )
  1488. spawnpointindex = getdvarint( "scr_spawnpoint_forceindex" );
  1489.  
  1490. spawnpoint = level.spawnPoints[spawnpointindex];
  1491.  
  1492. spawnPointUpdate( spawnpoint );
  1493.  
  1494. prof_end("spawn_update");
  1495. }
  1496. }
  1497.  
  1498. adjustSightValue( sightValue )
  1499. {
  1500. assert( sightValue >= 0 );
  1501. assert( sightValue <= 1 );
  1502. if ( sightValue <= 0 )
  1503. return 0;
  1504. if ( sightValue >= 1 )
  1505. return 1;
  1506. return sightValue * 0.5 + 0.25;
  1507. }
  1508.  
  1509. spawnPointUpdate( spawnpoint )
  1510. {
  1511. prof_begin( " spawn_update_init" );
  1512.  
  1513. if ( level.teambased )
  1514. {
  1515. spawnpoint.sights["axis"] = 0;
  1516. spawnpoint.sights["allies"] = 0;
  1517. }
  1518. else
  1519. {
  1520. spawnpoint.sights = 0;
  1521. }
  1522.  
  1523. spawnpointdir = spawnpoint.forward;
  1524.  
  1525. debug = false;
  1526. /#
  1527. debug = (getdvarint("scr_spawnpointdebug") > 0);
  1528.  
  1529. spawnpoint notify( "debug_stop_LOS" );
  1530. #/
  1531.  
  1532. spawnpoint.distSum["all"] = 0;
  1533. spawnpoint.distSum["allies"] = 0;
  1534. spawnpoint.distSum["axis"] = 0;
  1535.  
  1536. spawnpoint.weightedDistSum["all"] = 0;
  1537. spawnpoint.weightedDistSum["allies"] = 0;
  1538. spawnpoint.weightedDistSum["axis"] = 0;
  1539.  
  1540. spawnpoint.minDist["all"] = 9999999;
  1541. spawnpoint.minDist["allies"] = 9999999;
  1542. spawnpoint.minDist["axis"] = 9999999;
  1543.  
  1544. spawnpoint.numPlayersAtLastUpdate = 0;
  1545.  
  1546. totalPlayers["all"] = 0;
  1547. totalPlayers["allies"] = 0;
  1548. totalPlayers["axis"] = 0;
  1549.  
  1550. weightSum["all"] = 0;
  1551. weightSum["allies"] = 0;
  1552. weightSum["axis"] = 0;
  1553.  
  1554. winner = undefined;
  1555.  
  1556. curTime = getTime();
  1557.  
  1558. team = "all";
  1559. teambased = level.teambased;
  1560.  
  1561. prof_end( " spawn_update_init" );
  1562.  
  1563. prof_begin( " spawn_update_ploop" );
  1564.  
  1565. foreach ( player in level.players )
  1566. {
  1567. //prof_begin( " spawn_update_player" );
  1568.  
  1569. if ( player.sessionstate != "playing" )
  1570. {
  1571. //prof_end( " spawn_update_player" );
  1572. continue;
  1573. }
  1574.  
  1575. /*
  1576. playerSecondFloor = false;
  1577. if ( isDefined( level.spawnSecondFloorTrig ) && player isTouching( level.spawnSecondFloorTrig ) )
  1578. playerSecondFloor = true;
  1579. */
  1580.  
  1581. //prof_begin( " spawn_update_diff" );
  1582.  
  1583. diff = player.origin - spawnpoint.origin;
  1584. diff = (diff[0], diff[1], 0);
  1585.  
  1586. weight = 1.0; // default weight for weightedDistSum
  1587.  
  1588. dist = length( diff ); // needs to be actual distance for distSum value
  1589.  
  1590. //prof_end( " spawn_update_diff" );
  1591.  
  1592. //prof_begin( " spawn_update_team" );
  1593.  
  1594. if ( teambased )
  1595. team = player.team;
  1596.  
  1597. //prof_end( " spawn_update_team" );
  1598.  
  1599. //prof_begin( " spawn_update_nearby" );
  1600. if ( dist < spawnpoint.minDist[team] )
  1601. spawnpoint.minDist[team] = dist;
  1602. //prof_end( " spawn_update_nearby" );
  1603.  
  1604. //prof_begin( " spawn_update_weight" );
  1605. // tactical insertion weighting; players should not spawn too close to recent TI spawns
  1606. if ( player.wasTI && curTime - player.spawnTime < 15000 )
  1607. weight *= 0.1;
  1608.  
  1609. // sniper weight check
  1610. // note: weaponClass() is slow!
  1611. if ( player.isSniper )
  1612. weight *= 0.5;
  1613. //prof_end( " spawn_update_weight" );
  1614.  
  1615. //prof_begin( " spawn_update_sums" );
  1616. weightSum[ team ] += weight;
  1617. spawnpoint.weightedDistSum[ team ] += dist * weight;
  1618.  
  1619. spawnpoint.distSum[ team ] += dist;
  1620. spawnpoint.numPlayersAtLastUpdate++;
  1621.  
  1622. totalPlayers[team]++;
  1623. //prof_end( " spawn_update_sums" );
  1624.  
  1625. //prof_begin( " spawn_update_dot" );
  1626. pdir = anglestoforward(player.angles);
  1627. if (vectordot(spawnpointdir, diff) < 0 && vectordot(pdir, diff) > 0)
  1628. {
  1629. //prof_end( " spawn_update_dot" );
  1630. //prof_end( " spawn_update_player" );
  1631. continue; // player and spawnpoint are looking in opposite directions
  1632. }
  1633. //prof_end( " spawn_update_dot" );
  1634.  
  1635. /#
  1636. if ( isDefined( spawnpoint.fake ) )
  1637. {
  1638. //prof_end( " spawn_update_player" );
  1639. continue;
  1640. }
  1641. #/
  1642.  
  1643. // do sight check
  1644. /*
  1645. prof_begin( " spawn_update_told" );
  1646. losExists = bullettracepassed(player.origin + (0,0,50), spawnpoint.sightTracePoint, false, undefined);
  1647. prof_end( " spawn_update_told" );
  1648. */
  1649.  
  1650. prof_begin( " spawn_update_trace" );
  1651. sightValue = SpawnSightTrace( spawnpoint, spawnpoint.sightTracePoint, player.origin + (0,0,50) );
  1652. prof_end( " spawn_update_trace" );
  1653.  
  1654. //prof_begin( " spawn_update_losexists" );
  1655. spawnpoint.lastSightTraceTime = gettime();
  1656.  
  1657. if ( sightValue > 0 )
  1658. {
  1659. sightValue = adjustSightValue( sightvalue );
  1660. if ( teamBased )
  1661. spawnpoint.sights[team] += sightValue;
  1662. else
  1663. spawnpoint.sights += sightValue;
  1664.  
  1665. /#
  1666. if ( debug )
  1667. spawnpoint thread spawnpointDebugLOS( player.origin + (0,0,50) );
  1668. #/
  1669. }
  1670. //else
  1671. // line(player.origin + (0,0,50), spawnpoint.sightTracePoint, (1,.5,.5));
  1672.  
  1673. //prof_end( " spawn_update_losexists" );
  1674.  
  1675. //prof_end( " spawn_update_player" );
  1676. }
  1677.  
  1678. prof_end( " spawn_update_ploop" );
  1679.  
  1680. prof_begin( " spawn_update_other" );
  1681.  
  1682. nearbyEnemyRange = getFloatProperty( "scr_spawn_enemyavoiddist", 1000 );
  1683. nearbyEnemyPenalty = 2000; // typical base weights tend to peak around 1500 or so. this is large enough to upset that while only locally dominating it.
  1684.  
  1685. foreach ( team, value in weightSum )
  1686. {
  1687. if ( weightSum[team] )
  1688. spawnpoint.weightedDistSum[team] = spawnpoint.weightedDistSum[team] / weightSum[team] * totalPlayers[team];
  1689.  
  1690. nearbyPenalty = 0;
  1691. if ( spawnpoint.mindist[team] < nearbyEnemyRange )
  1692. nearbyPenalty = nearbyEnemyPenalty * (1 - spawnpoint.mindist[team] / nearbyEnemyRange);
  1693. spawnpoint.nearbyPenalty[team] = nearbyPenalty;
  1694. }
  1695.  
  1696.  
  1697. foreach ( tank in level.tanks )
  1698. {
  1699. sightValue = SpawnSightTrace( spawnpoint, spawnpoint.sightTracePoint, tank.origin + (0,0,50) );
  1700. spawnpoint.lastSightTraceTime = gettime();
  1701.  
  1702. if ( sightValue <= 0 )
  1703. continue;
  1704.  
  1705. sightValue = adjustSightValue( sightvalue );
  1706. if ( teamBased )
  1707. spawnpoint.sights[tank.team] += sightValue;
  1708. else
  1709. spawnpoint.sights += sightValue;
  1710.  
  1711. /#
  1712. if ( debug )
  1713. spawnpoint thread spawnpointDebugLOS( tank.origin + (0,0,50) );
  1714. #/
  1715. }
  1716.  
  1717. foreach ( turret in level.turrets )
  1718. {
  1719. if ( !isDefined( turret ) )
  1720. continue;
  1721.  
  1722. sightValue = SpawnSightTrace( spawnpoint, spawnpoint.sightTracePoint, turret.origin + (0,0,50) );
  1723. spawnpoint.lastSightTraceTime = gettime();
  1724.  
  1725. if ( sightValue <= 0 )
  1726. continue;
  1727.  
  1728. sightValue = adjustSightValue( sightvalue );
  1729. if ( teamBased )
  1730. spawnpoint.sights[turret.team] += sightValue;
  1731. else
  1732. spawnpoint.sights += sightValue;
  1733.  
  1734. /#
  1735. if ( debug )
  1736. spawnpoint thread spawnpointDebugLOS( turret.origin + (0,0,50) );
  1737. #/
  1738. }
  1739.  
  1740. // Disabled to see if removal of the red boxes upon spawn is sufficient
  1741. // (helicopter traces also intentionally disabled)
  1742. /*
  1743. if ( spawnpoint.outside )
  1744. {
  1745. foreach ( heli in level.helis )
  1746. {
  1747. sightValue = SpawnSightTrace( spawnpoint, spawnpoint.sightTracePoint, heli.origin + (0,0,30) );
  1748. spawnpoint.lastSightTraceTime = gettime();
  1749.  
  1750. if ( sightValue <= 0 )
  1751. continue;
  1752.  
  1753. sightValue = adjustSightValue( sightvalue );
  1754. if ( teamBased )
  1755. spawnpoint.sights[heli.team] += sightValue;
  1756. else
  1757. spawnpoint.sights += sightValue;
  1758.  
  1759. /#
  1760. if ( debug )
  1761. spawnpoint thread spawnpointDebugLOS( heli.origin + (0,0,30) );
  1762. #/
  1763. }
  1764.  
  1765. foreach ( missile in level.missilesForSightTraces )
  1766. {
  1767. sightValue = SpawnSightTrace( spawnpoint, spawnpoint.sightTracePoint, missile.origin );
  1768. spawnpoint.lastSightTraceTime = gettime();
  1769.  
  1770. if ( sightValue <= 0 )
  1771. continue;
  1772.  
  1773. sightValue = adjustSightValue( sightvalue );
  1774. if ( teamBased )
  1775. spawnpoint.sights[missile.team] += sightValue;
  1776. else
  1777. spawnpoint.sights += sightValue;
  1778.  
  1779. /#
  1780. if ( debug )
  1781. spawnpoint thread spawnpointDebugLOS( missile.origin );
  1782. #/
  1783. }
  1784.  
  1785. if ( isDefined( level.ac130player ) && level.ac130player.team != "spectator" )
  1786. {
  1787. if ( teamBased )
  1788. spawnpoint.sights[level.ac130player.team]++;
  1789. else
  1790. spawnpoint.sights++;
  1791. }
  1792. }
  1793. */
  1794.  
  1795. prof_end( " spawn_update_other" );
  1796. }
  1797.  
  1798. /#
  1799. spawnpointDebugLOS( point )
  1800. {
  1801. // g_spawndebug is better for this
  1802. /*
  1803. self endon( "debug_stop_LOS" );
  1804. for ( ;; )
  1805. {
  1806. line( point, self.sightTracePoint, (1, .5, .5) );
  1807. wait .05;
  1808. }
  1809. */
  1810. }
  1811. #/
  1812.  
  1813. getLosPenalty()
  1814. {
  1815. if (getdvar("scr_spawnpointlospenalty") != "" && getdvar("scr_spawnpointlospenalty") != "0")
  1816. return getdvarfloat("scr_spawnpointlospenalty");
  1817. return 100000;
  1818. }
  1819.  
  1820. lastMinuteSightTraces( spawnpoint )
  1821. {
  1822. prof_begin(" spawn_final_lastminsc");
  1823.  
  1824. closest = undefined;
  1825. closestDistsq = 100000000.0;
  1826. secondClosest = undefined;
  1827. secondClosestDistsq = 100000000.0;
  1828. foreach ( player in level.players )
  1829. {
  1830. if ( player.team == self.team && level.teambased )
  1831. continue;
  1832. if ( player.sessionstate != "playing" )
  1833. continue;
  1834. if ( player == self )
  1835. continue;
  1836.  
  1837. distsq = distanceSquared( spawnpoint.origin, player.origin );
  1838. if ( distsq < closestDistsq )
  1839. {
  1840. secondClosest = closest;
  1841. secondClosestDistsq = closestDistsq;
  1842.  
  1843. closest = player;
  1844. closestDistSq = distsq;
  1845. }
  1846. else if ( distsq < secondClosestDistSq )
  1847. {
  1848. secondClosest = player;
  1849. secondClosestDistSq = distsq;
  1850. }
  1851. }
  1852.  
  1853. if ( isdefined( closest ) )
  1854. {
  1855. sightValue = SpawnSightTrace( spawnpoint, spawnpoint.sightTracePoint, closest.origin + (0,0,50) );
  1856. if ( sightValue > 0 )
  1857. {
  1858. sightValue = adjustSightValue( sightvalue );
  1859. prof_end(" spawn_final_lastminsc");
  1860. return sightValue;
  1861. }
  1862. }
  1863. if ( isdefined( secondClosest ) )
  1864. {
  1865. sightValue = SpawnSightTrace( spawnpoint, spawnpoint.sightTracePoint, secondClosest.origin + (0,0,50) );
  1866. if ( sightValue > 0 )
  1867. {
  1868. sightValue = adjustSightValue( sightvalue );
  1869. prof_end(" spawn_final_lastminsc");
  1870. return sightValue;
  1871. }
  1872. }
  1873.  
  1874. prof_end(" spawn_final_lastminsc");
  1875. return 0;
  1876. }
  1877.  
  1878.  
  1879. avoidVisibleEnemies(spawnpoints, teambased)
  1880. {
  1881. //prof_begin(" spawn_complexsc");
  1882.  
  1883. lospenalty = getLosPenalty();
  1884.  
  1885. otherteam = "axis";
  1886. if ( self.team == "axis" )
  1887. otherteam = "allies";
  1888.  
  1889. if ( teambased )
  1890. {
  1891. foreach ( spawnpoint in spawnpoints )
  1892. {
  1893. penalty = lospenalty * spawnpoint.sights[otherteam];
  1894. spawnpoint.weight -= penalty;
  1895.  
  1896. /#
  1897. if ( penalty > 0 )
  1898. spawnpoint.spawnData[spawnpoint.spawnData.size] = "Sight traces: -" + int(penalty);
  1899. #/
  1900. }
  1901. }
  1902. else
  1903. {
  1904. foreach ( spawnpoint in spawnpoints )
  1905. {
  1906. penalty = lospenalty * spawnpoint.sights;
  1907. spawnpoint.weight -= penalty;
  1908.  
  1909. /#
  1910. if ( penalty > 0 )
  1911. spawnpoint.spawnData[spawnpoint.spawnData.size] = "Sight traces: -" + int(penalty);
  1912. #/
  1913. }
  1914.  
  1915. otherteam = "all";
  1916. }
  1917.  
  1918. foreach ( spawnpoint in spawnpoints )
  1919. {
  1920. // penalty for nearby enemies
  1921. spawnpoint.weight -= spawnpoint.nearbyPenalty[otherteam];
  1922. /#
  1923. if ( spawnpoint.nearbyPenalty[otherteam] != 0 )
  1924. spawnpoint.spawnData[spawnpoint.spawnData.size] = "Nearest enemy at " + int(spawnpoint.minDist[otherteam]) + " units: -" + int(spawnpoint.nearbyPenalty[otherteam]);
  1925. #/
  1926.  
  1927. if ( positionWouldTelefrag( spawnpoint.origin ) )
  1928. {
  1929. telefragCount = 1;
  1930.  
  1931. foreach ( alternate in spawnpoint.alternates )
  1932. {
  1933. if ( positionWouldTelefrag( alternate ) )
  1934. telefragCount++;
  1935. else
  1936. break;
  1937. }
  1938.  
  1939. penalty = 100000;
  1940. if ( telefragCount < spawnpoint.alternates.size + 1 )
  1941. {
  1942. penalty = 1500 * telefragCount;
  1943. if ( isDefined( self.forceSpawnNearTeammates ) )
  1944. penalty = 0;
  1945. }
  1946.  
  1947. spawnpoint.weight -= penalty;
  1948. /#
  1949. spawnpoint.spawnData[spawnpoint.spawnData.size] = "Would telefrag " + telefragCount + " times: -" + penalty;
  1950. #/
  1951. }
  1952. }
  1953.  
  1954. // DEBUG
  1955. //prof_end(" spawn_complexsc");
  1956. }
  1957.  
  1958. avoidSpawnReuse(spawnpoints, teambased)
  1959. {
  1960. // DEBUG
  1961. //prof_begin(" spawn_complexreuse");
  1962.  
  1963. time = getTime();
  1964.  
  1965. maxtime = 10*1000;
  1966. maxdistSq = 1024 * 1024;
  1967.  
  1968. foreach ( spawnpoint in spawnpoints )
  1969. {
  1970. lastspawnedplayer = spawnpoint.lastspawnedplayer;
  1971.  
  1972. if ( !isalive( lastspawnedplayer ) )
  1973. continue;
  1974.  
  1975. if ( teambased && spawnpoint.lastspawnedplayer.team == self.team )
  1976. continue;
  1977. if ( spawnpoint.lastspawnedplayer == self )
  1978. continue;
  1979.  
  1980. timepassed = time - spawnpoint.lastspawntime;
  1981. if ( timepassed < maxtime )
  1982. {
  1983. distSq = distanceSquared( spawnpoint.lastspawnedplayer.origin, spawnpoint.origin );
  1984. if (distSq < maxdistSq)
  1985. {
  1986. worsen = 5000 * (1 - distSq/maxdistSq) * (1 - timepassed/maxtime);
  1987. spawnpoint.weight -= worsen;
  1988. /#
  1989. spawnpoint.spawnData[spawnpoint.spawnData.size] = "Recently spawned enemy: -" + worsen;
  1990. #/
  1991. }
  1992. else
  1993. spawnpoint.lastspawnedplayer = undefined; // don't worry any more about this spawnpoint
  1994. }
  1995. else
  1996. spawnpoint.lastspawnedplayer = undefined; // don't worry any more about this spawnpoint
  1997. }
  1998.  
  1999. //prof_end(" spawn_complexreuse");
  2000. }
  2001.  
  2002. avoidSameSpawn()
  2003. {
  2004. //prof_begin(" spawn_complexsamespwn");
  2005.  
  2006. spawnpoint = self.lastspawnpoint;
  2007.  
  2008. if ( !isdefined( spawnpoint ) || !isdefined( spawnpoint.weight ) )
  2009. {
  2010. //prof_end(" spawn_complexsamespwn");
  2011. return;
  2012. }
  2013.  
  2014. spawnpoint.weight -= 1000;
  2015. /#
  2016. spawnpoint.spawnData[spawnpoint.spawnData.size] = "Was last spawnpoint: -1000";
  2017. #/
  2018.  
  2019. //prof_end(" spawn_complexsamespwn");
  2020. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement