Advertisement
Guest User

Untitled

a guest
Sep 29th, 2010
166
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 23.31 KB | None | 0 0
  1. init()
  2. {
  3. level.coptermodel = "vehicle_cobra_helicopter_fly";
  4. precacheModel(level.coptermodel);
  5.  
  6. level.copter_maxaccel = 200;
  7. level.copter_maxvel = 700;
  8. level.copter_rotspeed = 90; // degrees per second
  9. level.copter_accellookahead = 2; // seconds
  10.  
  11. level.copterCenterOffset = (0,0,72);
  12. level.copterTargetOffset = (0,0,45);
  13.  
  14. level.copterexplosion = loadfx("explosions/default_explosion");
  15. level.copterfinalexplosion = loadfx("explosions/large_vehicle_explosion");
  16. }
  17.  
  18. getAboveBuildingsLocation(location)
  19. {
  20. trace = bullettrace(location + (0,0,10000), location, false, undefined);
  21. startorigin = trace["position"] + (0,0,-514);
  22.  
  23. zpos = 0;
  24.  
  25. maxxpos = 13; maxypos = 13;
  26. for (xpos = 0; xpos < maxxpos; xpos++) {
  27. for (ypos = 0; ypos < maxypos; ypos++) {
  28. thisstartorigin = startorigin + ((xpos/(maxxpos-1) - .5) * 1024, (ypos/(maxypos-1) - .5) * 1024, 0);
  29. thisorigin = bullettrace(thisstartorigin, thisstartorigin + (0,0,-10000), false, undefined);
  30. zpos += thisorigin["position"][2];
  31. }
  32. }
  33. zpos = zpos / (maxxpos*maxypos);
  34.  
  35. zpos = zpos + 850;
  36.  
  37. return (location[0], location[1], zpos);
  38. }
  39.  
  40. vectorAngle(v1, v2)
  41. {
  42. dot = vectordot(v1, v2);
  43. if (dot >= 1)
  44. return 0;
  45. else if (dot <= -1)
  46. return 180;
  47. return acos(dot);
  48. }
  49. vectorTowardsOtherVector(v1, v2, angle)
  50. {
  51. dot = vectordot(v1, v2);
  52. if (dot <= -1)
  53. {
  54. return v1; // eh
  55. }
  56. v3 = vectornormalize(v2 - vecscale(v1, dot));
  57.  
  58. return vecscale(v1, cos(angle)) + vecscale(v3, sin(angle));
  59. }
  60. veclength(v)
  61. {
  62. return distance((0,0,0), v);
  63. }
  64.  
  65. createCopter(location, team, damagetrig)
  66. {
  67. location = getAboveBuildingsLocation(location);
  68.  
  69. scriptorigin = spawn("script_origin", location);
  70. scriptorigin.angles = vectorToAngles((1, 0, 0));
  71.  
  72. copter = spawn("script_model", location);
  73. copter.angles = vectorToAngles((0, 1, 0));
  74.  
  75. copter linkto(scriptorigin);
  76. scriptorigin.copter = copter;
  77. copter setModel(level.coptermodel);
  78. copter playLoopSound("mp_copter_ambience");
  79.  
  80. damagetrig.origin = scriptorigin.origin;
  81. damagetrig thread mylinkto(scriptorigin);
  82. scriptorigin.damagetrig = damagetrig;
  83.  
  84. scriptorigin.finalDest = location;
  85. scriptorigin.finalZDest = location[2];
  86. scriptorigin.desiredDir = (1,0,0);
  87. scriptorigin.desiredDirEntity = undefined;
  88. scriptorigin.desiredDirEntityOffset = (0,0,0);
  89. scriptorigin.vel = (0,0,0);
  90. scriptorigin.dontascend = false;
  91.  
  92. scriptorigin.health = 2000;
  93. if (getdvar("scr_copter_health") != "")
  94. scriptorigin.health = getdvarfloat("scr_copter_health");
  95.  
  96. scriptorigin.team = team;
  97.  
  98. scriptorigin thread copterAI();
  99. scriptorigin thread copterDamage(damagetrig);
  100.  
  101. return scriptorigin;
  102. }
  103.  
  104. makeCopterPassive()
  105. {
  106. self.damagetrig notify("unlink");
  107. self.damagetrig = undefined;
  108.  
  109. self notify("passive");
  110.  
  111. self.desiredDirEntity = undefined;
  112. self.desiredDir = undefined;
  113. }
  114. makeCopterActive(damagetrig)
  115. {
  116. damagetrig.origin = self.origin;
  117. damagetrig thread mylinkto(self);
  118. self.damagetrig = damagetrig;
  119.  
  120. self thread copterAI();
  121. self thread copterDamage(damagetrig);
  122. }
  123.  
  124. mylinkto(obj)
  125. {
  126. self endon("unlink");
  127. while(1)
  128. {
  129. self.angles = obj.angles;
  130. self.origin = obj.origin;
  131. wait .1;
  132. }
  133. }
  134.  
  135. setCopterDefenseArea(areaEnt)
  136. {
  137. self.areaEnt = areaEnt;
  138. self.areaDescentPoints = [];
  139. if (isdefined(areaEnt.target)) {
  140. self.areaDescentPoints = getentarray(areaEnt.target, "targetname");
  141. }
  142. for (i = 0; i < self.areaDescentPoints.size; i++)
  143. {
  144. self.areaDescentPoints[i].targetEnt = getent(self.areaDescentPoints[i].target, "targetname");
  145. }
  146. }
  147.  
  148. copterAI()
  149. {
  150. self thread copterMove();
  151. self thread copterShoot();
  152.  
  153. self endon("death");
  154. self endon("passive");
  155.  
  156. flying = true;
  157. descendingEnt = undefined;
  158. reachedDescendingEnt = false;
  159. returningToArea = false;
  160.  
  161. while(1)
  162. {
  163. if (!isdefined(self.areaEnt)) {
  164. wait(1);
  165. continue;
  166. }
  167.  
  168. players = level.players;
  169. enemyTargets = [];
  170. if (self.team != "neutral") {
  171. for (i = 0; i < players.size; i++) {
  172. if (isalive(players[i]) && isdefined(players[i].pers["team"]) && players[i].pers["team"] != self.team && !isdefined(players[i].usingObj)) {
  173. playerorigin = players[i].origin;
  174. playerorigin = (playerorigin[0], playerorigin[1], self.areaEnt.origin[2]);
  175. if (distance(playerorigin, self.areaEnt.origin) < self.areaEnt.radius)
  176. enemyTargets[enemyTargets.size] = players[i];
  177. }
  178. }
  179. }
  180.  
  181. insideTargets = [];
  182. outsideTargets = [];
  183.  
  184. skyheight = bullettrace(self.origin, self.origin + (0,0,10000), false, undefined)["position"][2] - 10;
  185.  
  186. bestTarget = undefined;
  187. bestWeight = 0;
  188. for (i = 0; i < enemyTargets.size; i++) {
  189. inside = false;
  190. trace = bulletTrace(enemyTargets[i].origin + (0,0,10), enemyTargets[i].origin + (0,0,10000), false, undefined);
  191. if (trace["position"][2] >= skyheight)
  192. // outside.
  193. outsideTargets[outsideTargets.size] = enemyTargets[i];
  194. else
  195. // inside.
  196. insideTargets[insideTargets.size] = enemyTargets[i];
  197. }
  198.  
  199. goToPos = undefined;
  200. calcedGoToPos = false;
  201.  
  202. oldDescendingEnt = undefined;
  203.  
  204. // determine if we should change states
  205. if (flying) {
  206. if (outsideTargets.size == 0 && insideTargets.size > 0 && self.areaDescentPoints.size > 0) {
  207. flying = false;
  208.  
  209. result = determineBestEnt(insideTargets, self.areaDescentPoints, self.origin);
  210. descendingEnt = result["descendEnt"];
  211. if (isdefined(descendingEnt))
  212. goToPos = result["position"];
  213. else
  214. flying = true;
  215. }
  216. }
  217. else {
  218. oldDescendingEnt = descendingEnt;
  219. if (insideTargets.size == 0) {
  220. flying = true;
  221. }
  222. else {
  223. // if we can't get a good target, and there are outside targets, give up and fly
  224. if (outsideTargets.size > 0) {
  225. if (!isdefined(descendingEnt))
  226. flying = true;
  227. else
  228. {
  229. calcedGoToPos = true;
  230. goToPos = determineBestPos(insideTargets, descendingEnt, self.origin);
  231. if (!isdefined(goToPos))
  232. flying = true;
  233. }
  234. }
  235. // determine where to go.
  236. if (isdefined(descendingEnt)) {
  237. // we're already descended. try to find a good place to shoot into the door/window from.
  238. if (!calcedGoToPos)
  239. goToPos = determineBestPos(insideTargets, descendingEnt, self.origin);
  240. }
  241. if (!isdefined(goToPos)) {
  242. result = determineBestEnt(insideTargets, self.areaDescentPoints, self.origin);
  243. if (isdefined(result["descendEnt"])) {
  244. descendingEnt = result["descendEnt"];
  245. goToPos = result["position"];
  246. reachedDescendingEnt = false;
  247. }
  248. else {
  249. if (isdefined(descendingEnt)) {
  250. if (isdefined(self.finalDest))
  251. goToPos = self.finalDest;
  252. else
  253. goToPos = descendingEnt.origin;
  254. }
  255. else
  256. goToPos = undefined;
  257. }
  258. }
  259. // couldn't find a place to descend?
  260. if (!isdefined(goToPos))
  261. flying = true;
  262. }
  263. }
  264.  
  265. if (flying)
  266. {
  267. // determine best target to shoot outside.
  268.  
  269. desireddist = 1024*2.5;
  270.  
  271. distToArea = distance((self.origin[0], self.origin[1], self.areaEnt.origin[2]), self.areaEnt.origin);
  272. if (outsideTargets.size == 0 && distToArea > self.areaEnt.radius + desireddist*.25)
  273. returningToArea = true;
  274. else if (distToArea < self.areaEnt.radius*.5)
  275. returningToArea = false;
  276. if (outsideTargets.size == 0 && !returningToArea)
  277. {
  278. // no outside targets? look again for any enemies outside the radius we're defending - just so
  279. // we don't look stupid when we could be making ourself useful.
  280. if (self.team != "neutral") {
  281. for (i = 0; i < players.size; i++) {
  282. if (isalive(players[i]) && isdefined(players[i].pers["team"]) && players[i].pers["team"] != self.team && !isdefined(players[i].usingObj)) {
  283. playerorigin = players[i].origin;
  284. playerorigin = (playerorigin[0], playerorigin[1], self.areaEnt.origin[2]);
  285. if (distance(players[i].origin, self.areaEnt.origin) > self.areaEnt.radius)
  286. outsideTargets[outsideTargets.size] = players[i];
  287. }
  288. }
  289. }
  290. }
  291.  
  292. best = undefined;
  293. bestdist = 0;
  294. for (i = 0; i < outsideTargets.size; i++)
  295. {
  296. dist = abs(distance(outsideTargets[i].origin, self.origin) - desireddist);
  297. if (!isdefined(best) || dist < bestdist) {
  298. best = outsideTargets[i];
  299. bestdist = dist;
  300. }
  301. }
  302.  
  303. if (isdefined(best)) {
  304. // determine best position to go to to get target.
  305. attackpos = best.origin + level.copterTargetOffset;
  306. goToPos = determineBestAttackPos(attackpos, self.origin, desireddist);
  307.  
  308. //iprintln("going to flying attack pos");
  309.  
  310. self setCopterDest(goToPos, false);
  311.  
  312. self.desiredDir = vectornormalize(attackpos - goToPos);
  313. self.desiredDirEntity = best;
  314. self.desiredDirEntityOffset = level.copterTargetOffset;
  315.  
  316. wait(1);
  317. }
  318. else {
  319. goToPos = getRandomPos(self.areaEnt.origin, self.areaEnt.radius);
  320. self setCopterDest(goToPos, false);
  321.  
  322. //iprintln("going to random pos");
  323.  
  324. self.desiredDir = undefined;
  325. self.desiredDirEntity = undefined;
  326.  
  327. wait(1);
  328. }
  329. }
  330. else
  331. {
  332. if (distance(self.origin, descendingEnt.origin) < descendingEnt.radius)
  333. reachedDescendingEnt = true;
  334.  
  335. //iprintln("going to descent pos");
  336.  
  337. goDirectly = (isdefined(oldDescendingEnt) && oldDescendingEnt == descendingEnt);
  338. goDirectly = goDirectly && reachedDescendingEnt;
  339.  
  340. self.desiredDir = vectornormalize(descendingEnt.targetEnt.origin - (goToPos - level.copterCenterOffset));
  341. self.desiredDirEntity = descendingEnt.targetEnt;
  342. self.desiredDirEntityOffset = (0,0,0);
  343.  
  344. if (goToPos != self.origin) {
  345. self setCopterDest(goToPos - level.copterCenterOffset, true, goDirectly);
  346. wait(.3);
  347. }
  348. else
  349. wait(.3);
  350. }
  351. }
  352. }
  353.  
  354. // determines the best position to go to within descendEnt
  355. // from where a target is visible. if no such positions,
  356. // returns undefined.
  357. determineBestPos(targets, descendEnt, startorigin)
  358. {
  359. targetpos = descendEnt.targetEnt.origin;
  360. circleradius = distance(targetpos, descendEnt.origin);
  361.  
  362.  
  363. bestpoint = undefined;
  364. bestdist = 0;
  365. for (i = 0; i < targets.size; i++)
  366. {
  367. enemypos = targets[i].origin + level.copterTargetOffset;
  368. passed = bullettracepassed(enemypos, targetpos, false, undefined);
  369. if (passed) {
  370. dir = targetpos - enemypos;
  371. dir = (dir[0], dir[1], 0);
  372. isect = vecscale(vectornormalize(dir),circleradius) + targetpos;
  373. isect = (isect[0], isect[1], descendEnt.origin[2]);
  374.  
  375. dist = distance(isect, descendEnt.origin);
  376. if (dist <= descendEnt.radius) {
  377. dist = distance(isect, startorigin);
  378. if (!isdefined(bestpoint) || dist < bestdist) {
  379. bestdist = dist;
  380. bestpoint = isect;
  381. }
  382. }
  383. }
  384. }
  385. return bestpoint;
  386. }
  387. // determines the best entity out of descendEnts to go to
  388. // in order to get at one of targets.
  389. // result["descendEnt"] is the winning entity,
  390. // result["position"] is the position to go to.
  391. determineBestEnt(targets, descendEnts, startorigin)
  392. {
  393. result = [];
  394.  
  395. bestpos = undefined;
  396. bestent = 0;
  397. bestdist = 0;
  398. for (i = 0; i < descendEnts.size; i++)
  399. {
  400. thispos = determineBestPos(targets, descendEnts[i], startorigin);
  401. if (isdefined(thispos)) {
  402. thisdist = distance(thispos, startorigin);
  403. if (!isdefined(bestpos) || thisdist < bestdist) {
  404. bestpos = thispos;
  405. bestent = i;
  406. bestdist = thisdist;
  407. }
  408. }
  409. }
  410.  
  411. if (isdefined(bestpos)) {
  412. result["descendEnt"] = descendEnts[bestent];
  413. result["position"] = bestpos;
  414. return result;
  415. }
  416.  
  417. result["descendEnt"] = undefined;
  418. return result;
  419. }
  420.  
  421. determineBestAttackPos(targetpos, curpos, desireddist)
  422. {
  423. targetposcopterheight = (targetpos[0], targetpos[1], curpos[2]);
  424. attackdirx = curpos - targetposcopterheight;
  425. attackdirx = vectornormalize(attackdirx);
  426. attackdiry = (0-attackdirx[1], attackdirx[0], 0);
  427.  
  428. bestpos = undefined;
  429. bestdist = 0;
  430. for (i = 0; i < 8; i++) {
  431. theta = (i/8.0) * 360;
  432. thisdir = vecscale(attackdirx, cos(theta)) + vecscale(attackdiry, sin(theta));
  433. traceend = targetposcopterheight + vecscale(thisdir, desireddist);
  434.  
  435. losexists = bullettracepassed(targetpos, traceend, false, undefined);
  436. if (losexists) {
  437. thisdist = distance(traceend, curpos);
  438. if (!isdefined(bestpos) || thisdist < bestdist) {
  439. bestpos = traceend;
  440. bestdist = thisdist;
  441. }
  442. }
  443. }
  444.  
  445. goToPos = undefined;
  446. if (isdefined(bestpos)) {
  447. goToPos = bestpos;
  448. }
  449. else {
  450. dist = distance(targetposcopterheight, curpos);
  451. if (dist > desireddist)
  452. goToPos = self.origin + vecscale(vectornormalize(attackdirx), 0-(dist - desireddist));
  453. else
  454. goToPos = self.origin;
  455. }
  456. return goToPos;
  457. }
  458.  
  459. getRandomPos(origin, radius)
  460. {
  461. // no sqrt so have to do this the guess and check way.
  462.  
  463. pos = origin + ((randomfloat(2)-1)*radius, (randomfloat(2)-1)*radius, 0);
  464. while(distanceSquared(pos, origin) > radius*radius)
  465. pos = origin + ((randomfloat(2)-1)*radius, (randomfloat(2)-1)*radius, 0);
  466.  
  467. return pos;
  468. }
  469.  
  470. copterShoot()
  471. {
  472. self endon("death");
  473. self endon("passive");
  474.  
  475. cosThreshold = cos(10);
  476. while(1)
  477. {
  478. if (isdefined(self.desiredDirEntity) && isdefined(self.desiredDirEntity.origin)) {
  479. mypos = self.origin + level.copterCenterOffset;
  480. enemypos = self.desiredDirEntity.origin + self.desiredDirEntityOffset;
  481. curdir = anglesToForward(self.angles);
  482. enemydirraw = enemypos - mypos;
  483. enemydir = vectornormalize(enemydirraw);
  484.  
  485. if (vectordot(curdir, enemydir) > cosThreshold)
  486. {
  487. canseetarget = bullettracepassed(mypos, enemypos, false, undefined);
  488. if (!canseetarget && isplayer(self.desiredDirEntity) && isalive(self.desiredDirEntity))
  489. canseetarget = bullettracepassed(mypos, self.desiredDirEntity getEye(), false, undefined);
  490. if (canseetarget) {
  491. // shoot.
  492. self playSound("mp_copter_shoot");
  493. numshots = 20;
  494. for (i = 0; i < numshots; i++)
  495. {
  496. mypos = self.origin + level.copterCenterOffset;
  497. /*if (isdefined(self.desiredDirEntity)) {
  498. enemypos = self.desiredDirEntity.origin + self.desiredDirEntityOffset;
  499. enemydirraw = enemypos - mypos;
  500. enemydir = vectornormalize(enemydirraw);
  501. dir = enemydir;
  502. }
  503. else*/
  504. dir = anglesToForward(self.angles);
  505.  
  506. dir = dir + ((randomfloat(2)-1)*.015, (randomfloat(2)-1)*.015, (randomfloat(2)-1)*.015);
  507. dir = vectornormalize(dir);
  508. self myMagicBullet(mypos, dir);
  509. wait(.075);
  510. }
  511. wait(.25);
  512. }
  513. //else
  514. //iprintln("can't see");
  515. }
  516. //else
  517. //iprintln("below cosThreshold: ", vectordot(curdir, enemydir), " < ", cosThreshold);
  518. }
  519. //else
  520. //iprintln("no target");
  521. wait(.25);
  522. }
  523. }
  524. myMagicBullet(pos, dir)
  525. {
  526. damage = 20;
  527. if (getdvar("scr_copter_damage") != "")
  528. damage = getdvarint("scr_copter_damage");
  529.  
  530. // for now just shoot from origin
  531. trace = bullettrace(pos, pos + vecscale(dir, 10000), true, undefined);
  532. if (isdefined(trace["entity"]) && isplayer(trace["entity"]) && isalive(trace["entity"])) {
  533. // hurt entity shot at
  534. trace["entity"] thread [[level.callbackPlayerDamage]](
  535. self, // eInflictor The entity that causes the damage.(e.g. a turret)
  536. self, // eAttacker The entity that is attacking.
  537. damage, // iDamage Integer specifying the amount of damage done
  538. 0, // iDFlags Integer specifying flags that are to be applied to the damage
  539. "MOD_RIFLE_BULLET", // sMeansOfDeath Integer specifying the method of death
  540. "copter", // sWeapon The weapon number of the weapon used to inflict the damage
  541. self.origin, // vPoint The point the damage is from?
  542. dir, // vDir The direction of the damage
  543. "none", // sHitLoc The location of the hit
  544. 0 // psOffsetTime The time offset for the damage
  545. );
  546. }
  547. //line(pos, trace["position"], (1,1,1));
  548. }
  549.  
  550. setCopterDest(newlocation, descend, dontascend)
  551. {
  552. self.finalDest = getAboveBuildingsLocation(newlocation);
  553. if (isdefined(descend) && descend)
  554. self.finalZDest = newlocation[2];
  555. else
  556. self.finalZDest = self.finalDest[2];
  557.  
  558. self.intransit = true;
  559. self.dontascend = false;
  560. if (isdefined(dontascend))
  561. self.dontascend = dontascend;
  562. }
  563. notifyArrived()
  564. {
  565. wait .05;
  566. self notify("arrived");
  567. }
  568.  
  569. vecscale(vec, scalar)
  570. {
  571. return (vec[0]*scalar, vec[1]*scalar, vec[2]*scalar);
  572. }
  573.  
  574. abs(x)
  575. {
  576. if (x < 0)
  577. return 0-x;
  578. return x;
  579. }
  580.  
  581. copterMove()
  582. {
  583. self endon("death");
  584.  
  585. if (isdefined(self.copterMoveRunning))
  586. return;
  587. self.copterMoveRunning = true;
  588.  
  589. self.intransit = false;
  590. interval = .15;
  591. zinterp = .1;
  592. tiltamnt = 0;
  593. while(1)
  594. {
  595. horizDistSquared = distanceSquared((self.origin[0], self.origin[1], 0), (self.finalDest[0], self.finalDest[1], 0));
  596.  
  597. doneMoving = horizDistSquared < 10*10;
  598.  
  599. //if (!doneMoving)
  600. {
  601. nearDest = (horizDistSquared < 256*256);
  602.  
  603. self.intransit = true;
  604.  
  605. desiredZ = 0;
  606.  
  607. // movement
  608. movingHorizontally = true;
  609. movingVertically = false;
  610. if (self.dontascend)
  611. movingVertically = true;
  612. else {
  613. // if we're not near our horizontal goal position
  614. if (!nearDest) {
  615. // get the z position we *want* to have before moving horizontally
  616. desiredZ = getAboveBuildingsLocation(self.origin)[2];
  617. movingHorizontally = (abs(self.origin[2] - desiredZ) <= 256); // we're moving horizontally if we're up high enough to do so
  618. movingVertically = !movingHorizontally; // we're moving vertically if we aren't
  619. }
  620. // if we are near our horizontal goal position
  621. else
  622. movingVertically = true;
  623. }
  624.  
  625. // determine our destination
  626. if (movingHorizontally) {
  627. if (movingVertically)
  628. thisDest = (self.finalDest[0], self.finalDest[1], self.finalZDest);
  629. else
  630. thisDest = self.finalDest;
  631. }
  632. else {
  633. assert(movingVertically);
  634. thisDest = (self.origin[0], self.origin[1], desiredZ);
  635. }
  636.  
  637. movevec = thisDest - self.origin;
  638.  
  639. idealAccel = vecscale(thisDest - (self.origin + vecscale(self.vel, level.copter_accellookahead)), interval);
  640. vlen = veclength(idealAccel);
  641. if (vlen > level.copter_maxaccel) {
  642. idealAccel = vecscale(idealAccel, level.copter_maxaccel / vlen);
  643. }
  644.  
  645. self.vel = self.vel + idealAccel;
  646. vlen = veclength(self.vel);
  647. if (vlen > level.copter_maxvel) {
  648. self.vel = vecscale(self.vel, level.copter_maxvel / vlen);
  649. }
  650.  
  651. thisDest = self.origin + vecscale(self.vel, interval);
  652.  
  653. self moveto(thisDest, interval*.999);
  654.  
  655. speed = veclength(self.vel);
  656.  
  657. if (isdefined(self.desiredDirEntity) && isdefined(self.desiredDirEntity.origin)) {
  658. self.destDir = vectornormalize((self.desiredDirEntity.origin + self.desiredDirEntityOffset) - (self.origin + level.copterCenterOffset));
  659. }
  660. else if (isdefined(self.desiredDir)) {
  661. self.destDir = self.desiredDir;
  662. }
  663. else if (movingVertically) {
  664. self.destDir = anglesToForward(self.angles);
  665. self.destDir = vectornormalize((self.destDir[0], self.destDir[1], 0));
  666. }
  667. else {
  668. tiltamnt = speed / level.copter_maxvel;
  669. tiltamnt = (tiltamnt - .1) / .9; if (tiltamnt < 0) tiltamnt = 0;
  670.  
  671. self.destDir = movevec;
  672. self.destDir = vectornormalize((self.destDir[0], self.destDir[1], 0)); // remove z component
  673. tiltamnt = tiltamnt * (1 - (vectorAngle(anglesToForward(self.angles), self.destDir) / 180));
  674. self.destDir = vectornormalize((self.destDir[0], self.destDir[1], tiltamnt * -.4)); // tilt forward while moving
  675. }
  676. }
  677. /*else {
  678. if (self.intransit) {
  679. self.intransit = false;
  680. self.dontascend = false;
  681.  
  682. // if we descended to get to this point, we'll be ascending to get out
  683. if (self.finalZDest != self.finalDest[2])
  684. self.ascending = true;
  685.  
  686. self notify("arrived");
  687. }
  688.  
  689. if (isdefined(self.desiredDir))
  690. self.destDir = self.desiredDir;
  691. else {
  692. self.destDir = anglesToForward(self.angles);
  693. self.destDir = vectornormalize((self.destDir[0], self.destDir[1], 0));
  694. }
  695. }*/
  696.  
  697. // rotation
  698. newdir = self.destDir;
  699. //line(self.origin + level.copterCenterOffset, self.origin + level.copterCenterOffset + vecscale(self.destDir,10000), (1,0,0));
  700. if (newdir[2] < -.4) {// *never* look too far down
  701. newdir = vectornormalize((newdir[0], newdir[1], -.4));
  702. }
  703. //line(self.origin + level.copterCenterOffset, self.origin + level.copterCenterOffset + vecscale(newdir,10000), (1,1,0));
  704.  
  705. copterangles = self.angles;
  706. copterangles = combineangles(copterangles, (0,90,0));
  707. olddir = anglesToForward(copterangles);
  708.  
  709. thisRotSpeed = level.copter_rotspeed;
  710. //if (movelen < 256)
  711. // thisRotSpeed = thisRotSpeed * movelen / 256;
  712.  
  713. olddir2d = vectornormalize((olddir[0], olddir[1], 0));
  714. newdir2d = vectornormalize((newdir[0], newdir[1], 0));
  715.  
  716. angle = vectorAngle(olddir2d, newdir2d);
  717. angle3d = vectorAngle(olddir, newdir);
  718.  
  719. if (angle > .001 && thisRotSpeed > .001) {
  720. thisangle = thisRotSpeed * interval;
  721. if (thisangle > angle)
  722. thisangle = angle;
  723.  
  724. newdir2d = vectorTowardsOtherVector(olddir2d, newdir2d, thisangle);
  725. oldz = olddir[2]/veclength((olddir[0], olddir[1], 0));
  726. newz = newdir[2]/veclength((newdir[0], newdir[1], 0));
  727. interpz = oldz + (newz - oldz) * (thisangle / angle);
  728. newdir = vectornormalize((newdir2d[0], newdir2d[1], interpz));
  729.  
  730. copterangles = vectorToAngles(newdir);
  731. copterangles = combineangles(copterangles, (0,-90,0));
  732. self rotateto(copterangles, interval*.999);
  733. }
  734. else if (angle3d > .001 && thisRotSpeed > .001) {
  735. // need to rotate vertically
  736. thisangle = thisRotSpeed * interval;
  737. if (thisangle > angle3d)
  738. thisangle = angle3d;
  739.  
  740. newdir = vectorTowardsOtherVector(olddir, newdir, thisangle);
  741. newdir = vectornormalize(newdir);
  742.  
  743. copterangles = vectorToAngles(newdir);
  744. copterangles = combineangles(copterangles, (0,-90,0));
  745. self rotateto(copterangles, interval*.999);
  746. }
  747.  
  748. wait interval;
  749. }
  750. }
  751.  
  752. copterDamage(damagetrig)
  753. {
  754. self endon("passive");
  755.  
  756. while(1)
  757. {
  758. damagetrig waittill("damage", amount, attacker);
  759.  
  760. // disallow friendly fire
  761. if (isdefined(attacker) && isplayer(attacker) && isdefined(attacker.pers["team"]) && attacker.pers["team"] == self.team)
  762. continue;
  763.  
  764. self.health -= amount;
  765. if (self.health <= 0) {
  766. self thread copterDie();
  767. return;
  768. }
  769. //iprintln("OW ", amount);
  770. }
  771. }
  772.  
  773. copterDie()
  774. {
  775. self endon("passive");
  776.  
  777. self notify("death");
  778. self.dead = true;
  779.  
  780. self thread copterExplodeFX();
  781.  
  782. // crash.
  783. interval = .2;
  784. rottime = 15;
  785. self rotateyaw(360 + randomfloat(360), rottime);
  786. self rotatepitch(360 + randomfloat(360), rottime);
  787. self rotateroll(360 + randomfloat(360), rottime);
  788. while(1)
  789. {
  790. self.vel = self.vel + vecscale((0,0,-200), interval);
  791. newpos = self.origin + vecscale(self.vel, interval);
  792.  
  793. // check for collision with ground
  794. pathclear = bullettracepassed(self.origin, newpos, false, undefined);
  795. if (!pathclear)
  796. break;
  797.  
  798. self moveto(newpos, interval*.999);
  799.  
  800. wait (interval);
  801. }
  802.  
  803. playfx (level.copterfinalexplosion, self.origin);
  804. playsoundatpos( self.origin, "mp_copter_explosion" );
  805. self notify("finaldeath");
  806.  
  807. deleteCopter();
  808. }
  809. deleteCopter()
  810. {
  811. if (isdefined(self.damagetrig)) {
  812. self.damagetrig notify("unlink");
  813. self.damagetrig = undefined;
  814. }
  815. self.copter delete();
  816. self delete();
  817. }
  818. copterExplodeFX()
  819. {
  820. self endon("finaldeath");
  821.  
  822. while(1)
  823. {
  824. playfx (level.copterexplosion, self.origin);
  825. self playsound("mp_copter_explosion");
  826. wait .5 + randomfloat(1);
  827. }
  828. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement