Advertisement
connyloathsome

pxlog again

Nov 12th, 2012
258
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 255.04 KB | None | 0 0
  1. Log started
  2. Project X! Version : 0.8.0.3104
  3. for WA 3.6.31.0
  4. WormKit Module
  5. Unlocked code region
  6. Unlocked data region
  7. Loading from : px3d.dll
  8. PX3D library loaded and binded
  9. Cleaning old render
  10. Cleaning old render VFT
  11. Precision : Double
  12. Round Mode : Nearest
  13. Making Single Player form scheme select..
  14. Making Single Player form scheme select resources..
  15. Result MWAB : 68160
  16. Loading level dat file : data\current.thm 0x0043BC6E
  17. Show of Single Player Match form..
  18. Scheme list saved
  19. Checking saved PX Scheme
  20. Loading scheme PX Normal.pxs
  21. Loading scheme file PXSchemes\PX Normal.pxs
  22. SchemeMan is being initializated..
  23. PXS : Loading pxdata.pxd
  24. PXS : Symbols loaded and linked
  25. PXFS has been initialized
  26. Processing scheme scripts.
  27. PXS : Making scheme scripts
  28. PXS : Library Code :
  29. //This unit allows to detect
  30. //weapon which missile belongs to
  31.  
  32. CWeapon* u_lweap;
  33.  
  34. int DistBetweenObjs(CGObject* ObA, CGObject* ObB)
  35. {
  36. int dx = ObA->PosX - ObB->PosX;
  37. int dy = ObA->PosY - ObB->PosY;
  38.  
  39. int r = sqrt(dx * dx + dy * dy);
  40.  
  41. return r;
  42. };
  43.  
  44. void MissileIndex::InitGraphic()
  45. {
  46. u_lweap = NullObj;
  47. };
  48.  
  49. override void CWorm::FireFinal(CWeapon* Weap, CShootDesc* Desc)
  50. {
  51. u_lweap = Weap;
  52. super;
  53. u_lweap = NullObj;
  54. };
  55.  
  56. override CMissile::CMissile(CObject* parent, CWeaponLaunch* ldata, CShootDesc* sdata)
  57. {
  58. weap = u_lweap;
  59. super;
  60. };
  61.  
  62.  
  63. override void CTurnGame::Message(CObject* sender,EMType Type,int MSize,CMessageData* MData)
  64. {
  65. if (Type == M_TURNBEGIN)
  66. {
  67. for (local i = 1; i < Env->Objs.Count; i++)
  68. {
  69. local mine = CMine(Env->Objs.Objs[i]);
  70. if (mine is CMine)
  71. {
  72. if (mine->autoTurnDestruct)
  73. {
  74. mine->Explosion();
  75. mine->Free(true);
  76. i--;
  77. }
  78. }
  79. }
  80. }
  81. super;
  82. }
  83.  
  84. override CMine::CMine(CObject* Parent,CMineParams* Params,CShootDesc* SDesc,bool Snap,int Unk)
  85. {
  86. autoTurnDestruct = false;
  87. autoDestroyTimer = -1;
  88. super;
  89. }
  90.  
  91. override void CMine::Message(CObject* sender,EMType Type,int MSize,CMessageData* MData)
  92. {
  93. if (Type == M_FRAME)
  94. {
  95. if (autoDestroyTimer > 0)
  96. {
  97. autoDestroyTimer--;
  98. } else if (autoDestroyTimer == 0) {
  99. Explosion();
  100. Free(true);
  101. return;
  102. }
  103. }
  104. super;
  105. }
  106. PXS : Library Code :
  107. float srandom_p()
  108. {
  109. int n = GS->GetRandom() % 10000;
  110. res = n / 10000.0;
  111. return res;
  112. };
  113.  
  114. float srandom_b()
  115. {
  116. int n = GS->GetRandom() % 10000;
  117. res = n / 5000.0 - 1.0;
  118. return res;
  119. };
  120.  
  121. int RandomInt(int min, int max)
  122. {
  123. return (GS->GetRandom()%(max - min + 1)) + min;
  124. }
  125.  
  126. float RandomFloat(float min, float max)
  127. {
  128. int n = (GS->GetRandom()%10000);
  129. float s = min + ((max - min) * n) / 10000.0;
  130. return s;
  131. }
  132. PXS : Library Code :
  133.  
  134. void SetTeamWon(int team)
  135. {
  136.  
  137. local w = GetCurrentWorm();
  138. if (w != NullObj && GetTeamColor(w->WormTeam) != GetTeamColor(team))
  139. {
  140. Root->DoExplosion(w->PosX, w->PosY, 100, 8, 1, 0);
  141. }
  142.  
  143. if (#RESPAWN_CONTROL)
  144. {
  145. if (rControl->enabled)
  146. {
  147. rControl->SetWinner(GetTeamColor(team));
  148. return;
  149. }
  150. }
  151. for (local i = 1; i <= 6; i++)
  152. {
  153. if (team == i) continue;
  154. for (local worm = 1; worm <= 8; worm++)
  155. {
  156. GS->Info.SetWormHealth(i, worm, 0);
  157. }
  158. }
  159. }
  160.  
  161. bool IsTeamAlive(int team)
  162. {
  163. if (Root->GetObject(TI_Team, team) == NullObj) return false;
  164. for (local i = 1; i <= 8; i++)
  165. {
  166. if (GS->Info.Teams[team-1].Worms[i-1].Health > 0) return true;
  167. }
  168. return false;
  169. }
  170.  
  171. CWorm* GetCurrentWorm()
  172. {
  173. local CurWorm = Root->CurWorm;
  174. local CurTeam = Root->CurTeam;
  175.  
  176. if (CurWorm <= 0 || CurWorm > 8) return NullObj;
  177. if (CurTeam <= 0 || CurTeam > 6) return NullObj;
  178. return Root->GetObject(2, CurWorm + 16 * CurTeam);
  179. };
  180.  
  181. int GetWormColor(CWorm* worm)
  182. {
  183. return GetTeamColor(worm->WormTeam) + 1;
  184. };
  185.  
  186. bool CGObject::IsInBox(fixed left, fixed top, fixed right, fixed bottom)
  187. {
  188. if (PosX > left && PosX < right)
  189. {
  190. if (PosY > top && PosY < bottom)
  191. {
  192. return true;
  193. }
  194. }
  195. return false;
  196. }
  197.  
  198. bool CGObject::IsValid()
  199. {
  200. if ((this is CGObject) == false) return false;
  201. for (local i = 1; i < Env->Objs.Count; i+= 1)
  202. {
  203. if (Env->Objs.Objs[i] == this)
  204. {
  205. return true;
  206. }
  207. }
  208. return false;
  209. }
  210.  
  211. int GetFreeWormIndex(int Team)
  212. {
  213. TNW = GS->Info.Teams[Team-1].NWorms;
  214. for (i = 1; i <= TNW; i+=1)
  215. {
  216. if (GS->Info.Teams[Team-1].Worms[i-1].State == 135) return i;
  217. };
  218. if (TNW < 8)
  219. {
  220. return TNW + 1;
  221. };
  222. return -1;
  223. };
  224.  
  225. void ExpandNWorms(int Team, int ExpTo)
  226. {
  227. local LIndex = GS->Info.Teams[Team-1].NWorms;
  228. GS->Info.Teams[Team-1].NWorms = ExpTo;
  229. for (i = LIndex + 1; i < ExpTo; i+=1)
  230. {
  231. GS->Info.Teams[Team-1].Worms[i-1].State = 135; //DEAD NAU
  232. };
  233. GS->Info.Teams[Team-1].Worms[ExpTo].State = 100;
  234. };
  235.  
  236. CWorm* RessurectWorm(int Index, int Team, fixed x, fixed y)
  237. {
  238. return RessurectWormEx(Index, Team, x, y, "New Worm", 100);
  239. }
  240.  
  241.  
  242. CWorm* RessurectWormEx(int Index, int Team, fixed x, fixed y, string wName, int Health)
  243. {
  244. T = Root->GetObject(TI_Team, Team);
  245. if (T == NullObj)
  246. {
  247. return T;
  248. };
  249. CWormParams wParam;
  250. zero(&wParam);
  251. wParam.SetName(wName);
  252. wParam.SetPosition(Health, x, y, true);
  253.  
  254. GS->Info.Teams[Team-1].Worms[Index-1].Health = Health;
  255. worm = new CWorm(T, Team, Index, &wParam);
  256. GS->Info.Teams[Team-1].Worms[Index-1].Health = Health;
  257.  
  258. if (Index > GS->Info.Teams[Team-1].NWorms)
  259. {
  260. ExpandNWorms(Team, Index);
  261. };
  262.  
  263.  
  264. return worm;
  265. };
  266. PXS : Library Code :
  267. float Lerp(float delta, float from, float to) {
  268. if (delta > 1) return to;
  269. if (delta < 0) return from;
  270. return from + (to - from) * delta;
  271. }
  272.  
  273. float NormalizeAngle(float a)
  274. {
  275. while(a > 3.141593) a -= 6.283186;
  276. while(a <= -3.141593) a += 6.283186;
  277. return a;
  278. }
  279.  
  280. float LerpAngle(float c, float a, float b)
  281. {
  282. a = NormalizeAngle(a);
  283. b = a + NormalizeAngle(b - a);
  284.  
  285. return NormalizeAngle(Lerp(c, a, b));
  286. }
  287.  
  288. int Sign(float n)
  289. {
  290. if(n<0) return -1;
  291. else if(n>0) return 1;
  292.  
  293. return 0;
  294. }
  295.  
  296. // t - time to shoot
  297. // d - delta
  298. // g - gravity or wind
  299.  
  300. float SolveBallistic(float d, float t, float g)
  301. {
  302. local a = (2 * d - g * t * t) / (2 * t);
  303. return a;
  304. };
  305. PXS : Library Code :
  306. CKeySync* keySync;
  307.  
  308. void sync_script::Init()
  309. {
  310. keySync = new CKeySync(RegisterPXMessage());
  311. };
  312.  
  313. override void CTurnGame::SetCurrentTeam(int Team)
  314. {
  315. super;
  316. for (local i = 0; i < 256; i+=1)
  317. {
  318. keySync->kRStates[i] = false;
  319. }
  320. }
  321.  
  322. CKeySync::CKeySync(int MType)
  323. {
  324. msgType = MType;
  325. kSync = new bool[256];
  326. kStates = new bool[256];
  327. kRStates = new bool[256];
  328. kPStates = new bool[256];
  329.  
  330. for (local i = 0; i < 256; i+=1)
  331. {
  332. kSync[i] = false;
  333. kStates[i] = false;
  334. kRStates[i] = false;
  335. kPStates[i] = false;
  336. };
  337. };
  338.  
  339. //adds key for syncronization
  340. void CKeySync::AddKey(int kIndex)
  341. {
  342. if (kIndex >= 0 && kIndex < 256) kSync[kIndex] = true;
  343. };
  344.  
  345. //is key still pressed
  346. bool CKeySync::KeyPressed(int kIndex)
  347. {
  348. return kRStates[kIndex];
  349. };
  350.  
  351. //is key JUST pressed
  352. bool CKeySync::KeyPressedNow(int kIndex)
  353. {
  354. return kPStates[kIndex];
  355. };
  356.  
  357. void CKeySync::ProcessInput()
  358. {
  359. for (local i = 0; i < 256; i++)
  360. {
  361. if (kSync[i] == false) continue;
  362. local kpr = IsKeyPressed(i);
  363. if (kpr != kStates[i])
  364. {
  365. if (kpr)
  366. {
  367. GG->queue2->AddPXMessage( msgType, i, 1);
  368. } else {
  369. GG->queue2->AddPXMessage( msgType, i, 0);
  370. }
  371. kStates[i] = kpr;
  372. }
  373. }
  374. }
  375.  
  376. void CKeySync::OnMessage(CMessageData* MData)
  377. {
  378. if (MData->GetParameter(0) == msgType)
  379. {
  380. local ki = MData->GetParameter(1);
  381. local kp = MData->GetParameter(2);
  382. if (kp)
  383. {
  384. if (kRStates[ki] == false) kPStates[ki] = true;
  385. kRStates[ki] = true;
  386. } else {
  387. kRStates[ki] = false;
  388. }
  389. }
  390. }
  391.  
  392. void CKeySync::OnFrame()
  393. {
  394. for (local i = 0; i < 256; i++)
  395. {
  396. kPStates[i] = false;
  397. }
  398. }
  399.  
  400. override void CTurnGame::Message(CObject* sender,EMType Type,int MSize,CMessageData* MData)
  401. {
  402. if (Type == M_INPUT)
  403. {
  404. keySync->ProcessInput();
  405. }
  406. if (Type == M_PXMESSAGE)
  407. {
  408. keySync->OnMessage(MData);
  409. }
  410. super;
  411. if (Type == M_FRAME)
  412. {
  413. keySync->OnFrame();
  414. }
  415. };
  416. PXS : Library Code : CGObject* Trace(CObject* parent, CColMask* colmask, fixed x, fixed y, float ang, float res, int maxlen, int flags, int* outL)
  417. {
  418. tx = float(x);
  419. ty = float(y);
  420.  
  421. dx = sin(ang) * res;
  422. dy = 0 - cos(ang) * res; //lol, TODO
  423.  
  424. nchecks = int(maxlen / res);
  425. for (i = 0; i < nchecks; i += 1)
  426. {
  427. obj = CheckMaskAt(parent, colmask, tx, ty, flags);
  428. if (obj != NullObj)
  429. {
  430. *outL = i * res;
  431. return obj;
  432. };
  433. tx += dx;
  434. ty += dy;
  435. };
  436. *outL = maxlen;
  437. return NullObj;
  438. };
  439.  
  440. CGObject* DTrace(CObject* parent, CColMask* colmask, fixed x, fixed y, fixed shx, fixed shy, int nchecks, int flags, int* outInter)
  441. {
  442. tx = float(x);
  443. ty = float(y);
  444.  
  445. dx = float(shx);
  446. dy = float(shy); //lol, TODO
  447.  
  448. for (i = 0; i < nchecks; i += 1)
  449. {
  450. obj = CheckMaskAt(parent, colmask, tx, ty, flags);
  451. if (obj != NullObj)
  452. {
  453. *outInter = i;
  454. return obj;
  455. };
  456. tx += dx;
  457. ty += dy;
  458. };
  459. *outInter = nchecks;
  460. return NullObj;
  461. };
  462.  
  463. CGObject* BTrace(CObject* parent, CColMask* colmask, fixed x, fixed y, float shx, float shy, fixed g, int nchecks, int flags, int* outInter)
  464. {
  465. tx = float(x);
  466. ty = float(y);
  467.  
  468. dx = shx;
  469. dy = shy; //lol, TODO
  470.  
  471. ddy = float(g);
  472.  
  473. for (i = 0; i < nchecks; i += 1)
  474. {
  475. obj = CheckMaskAt(parent, colmask, tx, ty, flags);
  476. if (obj != NullObj)
  477. {
  478. // parent->DoExplosion( 1, tx, ty, 100, 10, 0, 1);
  479. *outInter = i;
  480. return obj;
  481. };
  482. tx += dx;
  483. ty += dy;
  484. dy += ddy;
  485. };
  486. *outInter = nchecks;
  487. return NullObj;
  488. };
  489.  
  490.  
  491. CColMask *MASK_PIXEL;
  492.  
  493. void tracers::InitGraphic()
  494. {
  495. CBitmap1 *bmp = new CBitmap1(1, 1);
  496. bmp->SetPixel(0, 0, 1);
  497. MASK_PIXEL = new CColMask(1,1,bmp);
  498. }
  499.  
  500. CTraceRes::CTraceRes()
  501. {
  502. HitX = 0;
  503. HitY = 0;
  504. PreHitX = 0;
  505. PreHitY = 0;
  506. TangentX = 0.0;
  507. TangentY = 0.0;
  508. NormalX = 0.0;
  509. NormalY = 0.0;
  510. StartsSolid = false;
  511. LeftSolidX = 0;
  512. LeftSolidY = 0;
  513. HitObject = NullObj;
  514. Hit = false;
  515.  
  516. Point1X = 0;
  517. Point1Y = 0;
  518. Point2X = 0;
  519. Point2Y = 0;
  520. }
  521.  
  522. bool MatchCollisionGroup(CGObject *obj, int flags)
  523. {
  524. if(obj->ClType == OC_Landscape) { if(flags & 2 == 0) return false; } // Land
  525. else if(obj->ClType == OC_Worm)
  526. {
  527. if(flags & 4 == 0) // Standing worms
  528. {
  529. if(obj->ObjState == WS_IDLE) return false;
  530. if(obj->ObjState == WS_WALKING) return false;
  531. if(obj->ObjState == WS_AIMING) return false;
  532. if(obj->ObjState == WS_SETPOWER) return false;
  533. if(obj->ObjState == WS_JUMPPREPARE) return false;
  534. }
  535. if(flags & 8 == 0) // Worms with weapon
  536. {
  537. if(obj->ObjState == WS_FIRED) return false;
  538. if(obj->ObjState == WS_FIRECONT) return false;
  539. if(obj->ObjState == WS_DRILLING) return false;
  540. if(obj->ObjState == WS_TELEPORTING) return false;
  541. if(obj->ObjState == WS_CONTROL_WEAPON) return false;
  542. if(obj->ObjState == WS_BLOWTORCH) return false;
  543. }
  544. if(flags & 16 == 0) // Worms in mid-air
  545. {
  546. if(obj->ObjState == WS_POING) return false;
  547. if(obj->ObjState == WS_JUMP) return false;
  548. if(obj->ObjState == WS_PARACHUTE) return false;
  549. if(obj->ObjState == WS_SLIDING) return false;
  550. if(obj->ObjState == WS_POWERFLY) return false;
  551. if(obj->ObjState == WS_FLYING) return false;
  552. if(obj->ObjState == WS_FLYING2) return false;
  553. if(obj->ObjState == WS_JETPACK) return false;
  554. if(obj->ObjState == WS_AFTERROPE) return false;
  555. }
  556. if(flags & 32 == 0) // Worms on rope/bungee
  557. {
  558. if(obj->ObjState == WS_ROPING) return false;
  559. if(obj->ObjState == WS_BUNGEE) return false;
  560. }
  561. if(flags & 64 == 0) // Frozen worms
  562. {
  563. if(obj->ObjState == WS_FROZEN) return false;
  564. }
  565. if(flags & 256 == 0) // Suicide bomber/kamikaze
  566. {
  567. if(obj->ObjState == WS_FIREPUNCH) return false;
  568. if(obj->ObjState == WS_SUICIDEBOMBER) return false;
  569. }
  570. }
  571. else if(obj->ClType == OC_Mine) { if(flags & 1024 == 0) return false; } // Mines
  572. else if(obj->ClType == OC_Crate) { if(flags & 2048 == 0) return false; } // Crates
  573. else if(obj->ClType == OC_Cross) { if(flags & 8192 == 0) return false; } // Gravestones
  574. else if(obj->ClType == OC_Missile) { if(flags & 32768 == 0) return false; } // Weapons
  575. else if(obj->ClType == OC_Arrow) { if(flags & 65536 == 0) return false; } // Arrows
  576. else if(obj->ClType == OC_OilDrum) { if(flags & 131072 == 0) return false; } // Oil drums
  577. else { if(flags & (1 << obj->Layer) == 0) return false; } // Custom objects
  578.  
  579. return true;
  580. }
  581.  
  582. CGObject* FindInMask(CGObject* parent, CColMask* msk, int x, int y, int flags)
  583. {
  584. int i;
  585. CGObject *obj;
  586.  
  587. if(flags <= 0 && parent != NullObj) flags = parent->ColGroup;
  588.  
  589. for(i = 0; i < Env->Objs.Count; i += 1)
  590. {
  591. obj = CGObject(Env->Objs.Objs[i]);
  592. if(obj == parent) continue;
  593. if(obj == NullObj) continue;
  594. if(MatchCollisionGroup(obj, flags) == false) continue;
  595. if(msk->Check(x, y, obj->ColMask, obj->PosX, obj->PosY))
  596. {
  597. return obj;
  598. }
  599. }
  600. return NullObj;
  601. }
  602.  
  603. CGObject *_TraceMask(CObject *parent, CColMask *mask, int x1, int y1, int x2, int y2, int flags, int *xr, int *yr, int *xl, int *yl, int *ssolid, int *xls, int *yls)
  604. {
  605. int dx;
  606. int dy;
  607. int abs_dx;
  608. int abs_dy;
  609. int sx;
  610. int sy;
  611. int dir;
  612. int e;
  613. bool first = true;
  614. bool insolid = false;
  615.  
  616. CGObject *obj;
  617.  
  618. dx = x2 - x1;
  619. dy = y2 - y1;
  620.  
  621. if(dx == 0) { sx = 0; abs_dx = 0; }
  622. else if(dx > 0) { sx = 1; abs_dx = dx; }
  623. else { sx = 0-1; abs_dx = 0-dx; }
  624.  
  625. if(dy == 0) { sy = 0; abs_dy = 0; }
  626. else if(dy > 0) { sy = 1; abs_dy = dy; }
  627. else { sy = 0-1; abs_dy = 0-dy; }
  628.  
  629. if(abs_dx >= abs_dy) { e = abs_dx; dir = 0; }
  630. else { e = abs_dy; dir = 1; }
  631.  
  632. abs_dx = abs_dx * 2;
  633. abs_dy = abs_dy * 2;
  634. *xl = x1;
  635. *yl = y1;
  636. *xls = x1;
  637. *yls = y1;
  638. *ssolid = 0;
  639. while(true)
  640. {
  641. obj = FindInMask(parent, mask, x1, y1, flags);
  642. if(obj != NullObj)
  643. {
  644. if(first)
  645. {
  646. *ssolid = 1;
  647. insolid = true;
  648. }
  649. else
  650. {
  651. if(insolid == false)
  652. {
  653. *xr = x1; *yr = y1;
  654. return obj;
  655. }
  656. }
  657. }
  658. else
  659. {
  660. if(insolid)
  661. {
  662. insolid = false;
  663. *xls = x1;
  664. *yls = y1;
  665. }
  666. }
  667.  
  668. *xl = x1;
  669. *yl = y1;
  670.  
  671. if(dir == 0)
  672. {
  673. x1 += sx;
  674. if(x1 == x2) break;
  675.  
  676. if(sy != 0)
  677. {
  678. e -= abs_dy;
  679. if(e < 0)
  680. {
  681. y1 += sy;
  682. e += abs_dx;
  683. }
  684. }
  685. }
  686. else
  687. {
  688. y1 += sy;
  689. if(y1 == y2) break;
  690.  
  691. if(sx != 0)
  692. {
  693. e -= abs_dx;
  694. if(e <= 0)
  695. {
  696. x1 += sx;
  697. e += abs_dy;
  698. }
  699. }
  700. }
  701. first = false;
  702. }
  703.  
  704. *xr = x2;
  705. *yr = y2;
  706. return NullObj;
  707. }
  708.  
  709. CGObject *TraceMask(CObject *parent, CColMask *mask, int x1, int y1, int x2, int y2, int flags, int *xr, int *yr)
  710. {
  711. int t;
  712. return _TraceMask(parent, mask, x1, y1, x2, y2, flags, xr, yr, &t, &t, &t, &t, &t);
  713. }
  714.  
  715. CGObject *TraceLine(CObject *parent, int x1, int y1, int x2, int y2, int flags, int *xr, int *yr)
  716. {
  717. return TraceMask(parent, MASK_PIXEL, x1, y1, x2, y2, flags, xr, yr);
  718. }
  719.  
  720. bool TraceMaskEx(CObject *parent, CColMask *mask, int x1, int y1, int x2, int y2, int flags, CTraceRes *res)
  721. {
  722. int num_points = 6;
  723.  
  724. int x;
  725. int y;
  726. int xl;
  727. int yl;
  728. int ss;
  729. int xls;
  730. int yls;
  731.  
  732. CGObject *obj = _TraceMask(parent, mask, x1, y1, x2, y2, flags, &x, &y, &xl, &yl, &ss, &xls, &yls);
  733. CGObject *o;
  734.  
  735. res->HitX = x;
  736. res->HitY = y;
  737. res->HitObject = obj;
  738.  
  739. if(ss == 1) res->StartsSolid = true;
  740. else res->StartsSolid = false;
  741.  
  742. res->PreHitX = xl;
  743. res->PreHitY = yl;
  744. res->LeftSolidX = xls;
  745. res->LeftSolidY = yls;
  746.  
  747. if(obj == NullObj)
  748. {
  749. res->TangentX = 1.0;
  750. res->TangentY = 0.0;
  751. res->NormalX = 0.0;
  752. res->NormalY = -1.0;
  753. res->Point1X = 0;
  754. res->Point1Y = 0;
  755. res->Point2X = 0;
  756. res->Point2Y = 0;
  757. res->Hit = false;
  758. return false;
  759. }
  760.  
  761. int cx0;
  762. int cy0;
  763. int cx1 = x;
  764. int cy1 = y;
  765. int cx2 = x;
  766. int cy2 = y;
  767.  
  768. int dx;
  769. int dy;
  770. int t;
  771. int abs_dx;
  772. int abs_dy;
  773. int rx;
  774. int ry;
  775.  
  776. float tangx;
  777. float tangy;
  778. float normx;
  779. float normy;
  780. float dist;
  781.  
  782. bool changed;
  783.  
  784. dx = x2 - x1;
  785. dy = y2 - y1;
  786.  
  787. if(dx == 0) { rx = 0; abs_dx = 0; }
  788. else if(dx > 0) { rx = 1; abs_dx = dx; }
  789. else { rx = 0-1; abs_dx = 0-dx; }
  790.  
  791. if(dy == 0) { ry = 0; abs_dy = 0; }
  792. else if(dy > 0) { ry = 1; abs_dy = dy; }
  793. else { ry = 0-1; abs_dy = 0-dy; }
  794.  
  795. int n;
  796.  
  797. n = num_points;
  798. dx = rx;
  799. dy = 0;
  800. changed = false;
  801. while(true)
  802. {
  803. o = FindInMask(parent, mask, cx1, cy1, flags);
  804. if(o != NullObj)
  805. {
  806. n -= 1;
  807. t = dx;
  808. dx = dy;
  809. dy = 0-t;
  810. if(n<=0) break;
  811. }
  812. else
  813. {
  814. t = dx;
  815. dx = 0-dy;
  816. dy = t;
  817. }
  818. cx1 += dx;
  819. cy1 += dy;
  820.  
  821. if(cx1==x)
  822. {
  823. if(cy1==y)
  824. {
  825. if(changed)
  826. {
  827. break;
  828. }
  829. else
  830. {
  831. dx = 0;
  832. dy = ry;
  833. changed = true;
  834. }
  835. }
  836. }
  837. }
  838.  
  839. n = num_points;
  840. dx = rx;
  841. dy = 0;
  842. changed = false;
  843. while(true)
  844. {
  845. o = FindInMask(parent, mask, cx2, cy2, flags);
  846. if(o != NullObj)
  847. {
  848. n -= 1;
  849. t = dx;
  850. dx = 0-dy;
  851. dy = t;
  852. if(n<=0) break;
  853. }
  854. else
  855. {
  856. t = dx;
  857. dx = dy;
  858. dy = 0-t;
  859. }
  860. cx2 += dx;
  861. cy2 += dy;
  862.  
  863. if(cx2==x)
  864. {
  865. if(cy2==y)
  866. {
  867. if(changed)
  868. {
  869. break;
  870. }
  871. else
  872. {
  873. dx = 0;
  874. dy = ry;
  875. changed = true;
  876. }
  877. }
  878. }
  879. }
  880.  
  881. res->Point1X = cx1;
  882. res->Point1Y = cy1;
  883. res->Point2X = cx2;
  884. res->Point2Y = cy2;
  885. tangx = (cx2 - cx1);
  886. tangy = (cy2 - cy1);
  887. normx = (cy1 - cy2);
  888. normy = (cx2 - cx1);
  889. dist = sqrt(normx*normx + normy*normy);
  890.  
  891. if(dist > 0)
  892. {
  893. res->TangentX = tangx / dist;
  894. res->TangentY = tangy / dist;
  895. res->NormalX = normx / dist;
  896. res->NormalY = normy / dist;
  897. }
  898. else
  899. {
  900. res->TangentX = 1.0;
  901. res->TangentY = 0.0;
  902. res->NormalX = 0.0;
  903. res->NormalY = -1.0;
  904. }
  905.  
  906. res->Hit = true;
  907. return true;
  908. }
  909.  
  910. CGObject *TraceLineEx(CObject *parent, int x1, int y1, int x2, int y2, int flags, CTraceRes *res)
  911. {
  912. TraceMaskEx(parent, MASK_PIXEL, x1, y1, x2, y2, flags, res);
  913. return res->HitObject;
  914. }
  915. PXS : Library Code :
  916. bool GameStartedToDestroy; //true when game is ending
  917.  
  918. int g_tColorInd[6];
  919. int g_tColorInd2[7]; //reversed
  920.  
  921.  
  922. //rad is actually about 1/2 of actual diameter :D
  923. bool TeleportObject(CGObject* obj, int tX, int tY, int rad, bool onGround, int flags)
  924. {
  925. local dx = 0;
  926. local dy = -1;
  927. local iX = obj->PosX; local iY = obj->PosY;
  928.  
  929. obj->PosY = -1000;
  930.  
  931. l = 1;
  932. for (local nm = 0; nm <= rad; nm++)
  933. {
  934. for (local i = 0; i < l; i++)
  935. {
  936.  
  937. obj->PosY -= 1;
  938.  
  939. if (Env->CheckCollisionEx(obj, tX, tY, obj->ColMask, flags) == NullObj)
  940. {
  941. obj->PosY -= 1;
  942.  
  943. if (!onGround || (Env->CheckCollisionEx( obj, tX, tY + 1, obj->ColMask, flags) != NullObj))
  944. {
  945. obj->PosX = tX;
  946. obj->PosY = tY;
  947. return true;
  948. }
  949. }
  950.  
  951. tX += dx;
  952. tY += dy;
  953. }
  954. local t = dx;
  955. dx = -dy;
  956. dy = t;
  957.  
  958. if (nm % 2 == 1)
  959. {
  960. l++;
  961. }
  962. }
  963. obj->PosY = iY;
  964. return false;
  965. }
  966.  
  967. string MakeZeroedNumber(int n, int minLen)
  968. {
  969. string str = ItoA(n);
  970. while (StrLen(str) < minLen) str = StrCon("0", str);
  971. return str;
  972. }
  973.  
  974. void generateTColorInd()
  975. {
  976. tExists = new bool[7];
  977. sTeam = 1;
  978.  
  979. for (i = 0; i < 7; i++)
  980. {
  981. tExists[i] = false;
  982. g_tColorInd2[i] = -1;
  983. }
  984. for (i = 1; i <= 6; i++)
  985. {
  986. if (Root->GetObject(TI_Team, i) != NullObj)
  987. {
  988. tExists[GetTeamColor(i)] = true;
  989. }
  990. }
  991. for (i = 0; i <= 5; i++)
  992. {
  993. if (tExists[i])
  994. {
  995. g_tColorInd2[sTeam] = i;
  996. g_tColorInd[i] = sTeam++;
  997. }
  998. }
  999.  
  1000. }
  1001.  
  1002. override void CTurnGame::Free(bool FreeMem)
  1003. {
  1004. GameStartedToDestroy = true;
  1005. super;
  1006. GameStartedToDestroy = false;
  1007. }
  1008.  
  1009. CBitmap1* MakeCircleMask(int rad)
  1010. {
  1011. msk = new CBitmap1(rad * 2, rad * 2);
  1012. rsq = rad * rad;
  1013. drad = rad * 2;
  1014. // hrad = rad / 2;
  1015. for (int i = 0; i < drad; i+=1)
  1016. {
  1017. cwidth = int(sqrt(rsq - (i - rad) * (i - rad)));
  1018. lborder = rad - cwidth;
  1019. rborder = rad + cwidth;
  1020. if (rborder >= drad) rborder = drad - 1;
  1021. msk->HLine(lborder, rborder, i, 1);
  1022. };
  1023. return msk;
  1024. };
  1025.  
  1026. CBitmap1* MakeRectMask(int sx, int sy)
  1027. {
  1028. msk = new CBitmap1(sx, sy);
  1029. msk->Rect( 0, 0, sx, sy, 1);
  1030. return msk;
  1031. }
  1032.  
  1033. CBitmap1* MakePixelMask()
  1034. {
  1035. msk = new CBitmap1(1, 1);
  1036. msk->SetPixel(0, 0, 1);
  1037. return msk;
  1038. };
  1039.  
  1040. CGObject* CheckMaskAt(CGObject* Obj, CColMask* msk, fixed x, fixed y, int flags)
  1041. {
  1042. nObj = Env->Objs.Count;
  1043. for (i = 0; i < nObj; i += 1)
  1044. {
  1045. trg = CGObject(Env->Objs.Objs[i]);
  1046. if (trg == Obj) continue;
  1047. if (trg == NullObj) continue;
  1048. if (flags >= 0 && flags != trg->Layer) continue;
  1049. if (msk->Check(x, y, trg->ColMask, trg->PosX, trg->PosY))
  1050. {
  1051. return trg;
  1052. };
  1053. };
  1054.  
  1055. return NullObj;
  1056. };
  1057.  
  1058. void GetTeamColorRGB(int clr, int* r, int* g, int* b)
  1059. {
  1060. if (clr == 1)
  1061. {
  1062. *r = 255;
  1063. *g = 128;
  1064. *b = 128;
  1065. } else if (clr == 2)
  1066. {
  1067. *r = 0;
  1068. *g = 150;
  1069. *b = 255;
  1070. } else if (clr == 3)
  1071. {
  1072. *r = 0;
  1073. *g = 208;
  1074. *b = 0;
  1075. } else if (clr == 4)
  1076. {
  1077. *r = 255;
  1078. *g = 255;
  1079. *b = 64;
  1080. } else if (clr == 5)
  1081. {
  1082. *r = 232;
  1083. *g = 0;
  1084. *b = 232;
  1085. } else if (clr == 6)
  1086. {
  1087. *r = 80;
  1088. *g = 255;
  1089. *b = 255;
  1090. } else {
  1091. *r = 255;
  1092. *g = 255;
  1093. *b = 255;
  1094. }
  1095. }
  1096.  
  1097. int GetTeamColorRGB(int clr)
  1098. {
  1099. int r;
  1100. int g;
  1101. int b;
  1102. GetTeamColorRGB(clr, &r, &g, &b);
  1103. return RGB(r, g, b);
  1104. }
  1105. PXS : Library Code :
  1106. // Math constants
  1107. float MATH_TWO_PI;
  1108. float MATH_PI;
  1109. float MATH_HALF_PI;
  1110. float MATH_QUARTER_PI;
  1111.  
  1112. // Layer enums
  1113. int LAYER_UNUSED0 ;
  1114. int LAYER_TERRAIN ;
  1115. int LAYER_WORM_ON_TERRAIN ;
  1116. int LAYER_WORM_USING_WEAPON ;
  1117. int LAYER_WORM_IN_MIDAIR ;
  1118. int LAYER_WORM_ON_ROPE ;
  1119. int LAYER_WORM_FROZEN ;
  1120. int LAYER_UNUSED7 ;
  1121. int LAYER_KAMIKAZE ;
  1122. int LAYER_GASCANISTER ;
  1123. int LAYER_MINE ;
  1124. int LAYER_CRATE ;
  1125. int LAYER_DONORCARD ;
  1126. int LAYER_GRAVESTONE ;
  1127. int LAYER_UNUSED14 ;
  1128. int LAYER_OTHERWEAPON ;
  1129. int LAYER_ARROW ;
  1130. int LAYER_OILDRUM ;
  1131. int LAYER_UNUSED18 ;
  1132. int LAYER_UNUSED19 ;
  1133. int LAYER_UNUSED20 ;
  1134. int LAYER_UNUSED21 ;
  1135. int LAYER_SKIMMING ;
  1136. int LAYER_UNUSED23 ;
  1137. int LAYER_UNUSED24 ;
  1138. int LAYER_UNUSED25 ;
  1139. int LAYER_UNUSED26 ;
  1140. int LAYER_UNUSED27 ;
  1141. int LAYER_UNUSED28 ;
  1142. int LAYER_UNUSED29 ;
  1143. int LAYER_UNUSED30 ;
  1144.  
  1145. // Collision "group" enums (more like collision mask)
  1146. int CMASK_UNUSED0 ;
  1147. int CMASK_TERRAIN ;
  1148. int CMASK_WORM_ON_TERRAIN ;
  1149. int CMASK_WORM_USING_WEAPON ;
  1150. int CMASK_WORM_IN_MIDAIR ;
  1151. int CMASK_WORM_ON_ROPE ;
  1152. int CMASK_WORM_FROZEN ;
  1153. int CMASK_UNUSED7 ;
  1154. int CMASK_KAMIKAZE ;
  1155. int CMASK_GASCANISTER ;
  1156. int CMASK_MINE ;
  1157. int CMASK_CRATE ;
  1158. int CMASK_DONORCARD ;
  1159. int CMASK_GRAVESTONE ;
  1160. int CMASK_UNUSED14 ;
  1161. int CMASK_OTHERWEAPON ;
  1162. int CMASK_ARROW ;
  1163. int CMASK_OILDRUM ;
  1164. int CMASK_UNUSED18 ;
  1165. int CMASK_UNUSED19 ;
  1166. int CMASK_UNUSED20 ;
  1167. int CMASK_UNUSED21 ;
  1168. int CMASK_SKIMMING ;
  1169. int CMASK_UNUSED23 ;
  1170. int CMASK_UNUSED24 ;
  1171. int CMASK_UNUSED25 ;
  1172. int CMASK_UNUSED26 ;
  1173. int CMASK_UNUSED27 ;
  1174. int CMASK_UNUSED28 ;
  1175. int CMASK_UNUSED29 ;
  1176. int CMASK_UNUSED30 ;
  1177.  
  1178. // Preset CMASK enums
  1179. int CMASK_DEFAULT_COLLIDEABLE;
  1180.  
  1181. void px_enums::FirstFrame()
  1182. {
  1183. MATH_TWO_PI = 6.283186;
  1184. MATH_PI = 3.141593;
  1185. MATH_HALF_PI = 1.570796;
  1186. MATH_QUARTER_PI = 0.785398;
  1187.  
  1188. LAYER_UNUSED0 = 0;
  1189. LAYER_TERRAIN = 1;
  1190. LAYER_WORM_ON_TERRAIN = 2;
  1191. LAYER_WORM_USING_WEAPON = 3;
  1192. LAYER_WORM_IN_MIDAIR = 4;
  1193. LAYER_WORM_ON_ROPE = 5;
  1194. LAYER_WORM_FROZEN = 6;
  1195. LAYER_UNUSED7 = 7;
  1196. LAYER_KAMIKAZE = 8;
  1197. LAYER_GASCANISTER = 9;
  1198. LAYER_MINE = 10;
  1199. LAYER_CRATE = 11;
  1200. LAYER_DONORCARD = 12;
  1201. LAYER_GRAVESTONE = 13;
  1202. LAYER_UNUSED14 = 14;
  1203. LAYER_OTHERWEAPON = 15;
  1204. LAYER_ARROW = 16;
  1205. LAYER_OILDRUM = 17;
  1206. LAYER_UNUSED18 = 18;
  1207. LAYER_UNUSED19 = 19;
  1208. LAYER_UNUSED20 = 20;
  1209. LAYER_UNUSED21 = 21;
  1210. LAYER_SKIMMING = 22;
  1211. LAYER_UNUSED23 = 23;
  1212. LAYER_UNUSED24 = 24;
  1213. LAYER_UNUSED25 = 25;
  1214. LAYER_UNUSED26 = 26;
  1215. LAYER_UNUSED27 = 27;
  1216. LAYER_UNUSED28 = 28;
  1217. LAYER_UNUSED29 = 29;
  1218. LAYER_UNUSED30 = 30;
  1219.  
  1220. CMASK_UNUSED0 = 1;
  1221. CMASK_TERRAIN = 2;
  1222. CMASK_WORM_ON_TERRAIN = 4;
  1223. CMASK_WORM_USING_WEAPON = 8;
  1224. CMASK_WORM_IN_MIDAIR = 16;
  1225. CMASK_WORM_ON_ROPE = 32;
  1226. CMASK_WORM_FROZEN = 64;
  1227. CMASK_UNUSED7 = 128;
  1228. CMASK_KAMIKAZE = 256;
  1229. CMASK_GASCANISTER = 512;
  1230. CMASK_MINE = 1024;
  1231. CMASK_CRATE = 2048;
  1232. CMASK_DONORCARD = 4096;
  1233. CMASK_GRAVESTONE = 8192;
  1234. CMASK_UNUSED14 = 16384;
  1235. CMASK_OTHERWEAPON = 32768;
  1236. CMASK_ARROW = 65536;
  1237. CMASK_OILDRUM = 131072;
  1238. CMASK_UNUSED18 = 262144;
  1239. CMASK_UNUSED19 = 524288;
  1240. CMASK_UNUSED20 = 1048576;
  1241. CMASK_UNUSED21 = 2097152;
  1242. CMASK_SKIMMING = 4194304;
  1243. CMASK_UNUSED23 = 8388608;
  1244. CMASK_UNUSED24 = 16777216;
  1245. CMASK_UNUSED25 = 33554432;
  1246. CMASK_UNUSED26 = 67108864;
  1247. CMASK_UNUSED27 = 134217728;
  1248. CMASK_UNUSED28 = 268435456;
  1249. CMASK_UNUSED29 = 536870912;
  1250. CMASK_UNUSED30 = 1073741824;
  1251.  
  1252. CMASK_DEFAULT_COLLIDEABLE = CMASK_TERRAIN
  1253. | CMASK_WORM_ON_TERRAIN
  1254. | CMASK_WORM_USING_WEAPON
  1255. | CMASK_WORM_IN_MIDAIR
  1256. | CMASK_WORM_ON_ROPE
  1257. | CMASK_WORM_FROZEN
  1258. | CMASK_CRATE
  1259. | CMASK_DONORCARD
  1260. | CMASK_OILDRUM
  1261. | CMASK_SKIMMING;
  1262. }
  1263. PXS : Library Code :
  1264. int CGOBJECT_LAYER_OVERRIDE;
  1265. int CGOBJECT_MASKINDEX_OVERRIDE;
  1266.  
  1267. void layer_override::FirstFrame()
  1268. {
  1269. CGOBJECT_LAYER_OVERRIDE = -1;
  1270. CGOBJECT_MASKINDEX_OVERRIDE = -1;
  1271. }
  1272.  
  1273. void SetLayerOverride(int layer)
  1274. {
  1275. CGOBJECT_LAYER_OVERRIDE = layer;
  1276. }
  1277.  
  1278. void SetMaskIndexOverride(int maskIndex)
  1279. {
  1280. CGOBJECT_MASKINDEX_OVERRIDE = maskIndex;
  1281. }
  1282.  
  1283. override CGObject::CGObject(CObject *parent, int layer, int maskIndex)
  1284. {
  1285. if(CGOBJECT_LAYER_OVERRIDE > 0)
  1286. {
  1287. layer = CGOBJECT_LAYER_OVERRIDE;
  1288. CGOBJECT_LAYER_OVERRIDE = -1;
  1289. }
  1290.  
  1291. if(CGOBJECT_MASKINDEX_OVERRIDE > 0)
  1292. {
  1293. maskIndex = CGOBJECT_MASKINDEX_OVERRIDE;
  1294. CGOBJECT_MASKINDEX_OVERRIDE = -1;
  1295. }
  1296.  
  1297. super;
  1298. }
  1299. PXS : Library Code :
  1300.  
  1301. EMType M_TOUCHSENSOR;
  1302. EMType M_TOUCHSENSOR_COLLIDE;
  1303.  
  1304. CTouchSensor : CGObject;
  1305. CTouchSensorParent : CObject;
  1306.  
  1307. CTouchSensorParent * TSensorParent;
  1308. CColMask* terrainColMask;
  1309.  
  1310. void ldetector_script::Init()
  1311. {
  1312. M_TOUCHSENSOR = RegisterPXMessage();
  1313. M_TOUCHSENSOR_COLLIDE = RegisterPXMessage();
  1314. TSensorParent = new CTouchSensorParent;
  1315. terrainColMask = CColMask(NullObj);
  1316. }
  1317.  
  1318. CTouchSensorParent::CTouchSensorParent()
  1319. {
  1320. super(NullObj, GS); //GS is not initialized there.. but who cares
  1321. activatorObj = CGObject(NullObj);
  1322. isCheckCollision = false;
  1323. }
  1324. /*
  1325. int CTouchSensorParent::Check(int x,int y,CColMask* trg)
  1326. {
  1327. if (!isCheckCollision) return 0;
  1328. for (local i = 0;i < Childs.Count; i++)
  1329. {
  1330. local ts = CTouchSensor(Childs.Objs[i]);
  1331. if (trg->Check(x, y, ts->ColMask, ts->PosX, ts->PosY))
  1332. {
  1333. if (activatorObj != NullObj)
  1334. {
  1335. ts->activator = activatorObj;
  1336. ts->noCollide = false;
  1337. CMessageData mData;
  1338. ts->notify->Message( ts, M_TOUCHSENSOR, 1032, &mData);
  1339. if (ts->noCollide) return -1;
  1340. }
  1341. return 1;
  1342. }
  1343. }
  1344. return 0;
  1345. } */
  1346.  
  1347. CTouchSensor::CTouchSensor(CObject* notifyTo, int x, int y, int sx, int sy)
  1348. {
  1349. super(Root, 1, 9);
  1350.  
  1351. ClType = EObjectClass(4020);
  1352.  
  1353. terrain = CGObject( Env->Objs.Objs[0] );
  1354.  
  1355.  
  1356. Env->ObjsL[1].Remove(this); //some zhl for the win
  1357. Env->ObjsL[1].Remove(terrain);
  1358. Env->ObjsL[1].Compact();
  1359. Env->ObjsL[1].Add(this);
  1360. Env->ObjsL[1].Add(terrain);
  1361.  
  1362. terrainColMask = CGObject(Env->Objs.Objs[0])->ColMask;
  1363. noCollide = false;
  1364. if ( (x + sx) > GG->land->BitMask->SX ) sx = x - GG->land->BitMask->SX;
  1365. if ( (y + sy) > GG->land->BitMask->SY ) sy = y - GG->land->BitMask->SY;
  1366. if ( x < 0 )
  1367. {
  1368. sx += x;
  1369. x = 0;
  1370. }
  1371. if ( y < 0 )
  1372. {
  1373. sy += y;
  1374. y = 0;
  1375. }
  1376. if ( (sx <= 0) || (sy <= 0) )
  1377. {
  1378. PosX = -1000; PosY = -1000;
  1379. return;
  1380. }
  1381.  
  1382. bMask = new CBitmap1(sx, sy);
  1383.  
  1384. for (local cx = 0; cx < sx; cx++)
  1385. {
  1386. for (local cy = 0; cy < sy; cy++)
  1387. {
  1388. bMask->SetPixel(cx, cy, GG->land->BitMask->GetPixel( cx+x, cy+y));
  1389. }
  1390. }
  1391. // GG->land->BitMask->Rect(x, y, sx+x, sy+y, 0); // for ropez!
  1392.  
  1393. ColMask = new CColMask(0, 0, bMask);
  1394.  
  1395. notify = notifyTo;
  1396.  
  1397. PosX = x;
  1398. PosY = y;
  1399. Stopped = false;
  1400. // GravityFactor = 0;
  1401. IsMaterial = true;
  1402. IsStatic = true;
  1403.  
  1404. aObjs = new CGObject*[10];
  1405. aCObjs = new bool[10];
  1406. maxObjects = 10;
  1407. nObjects = 0;
  1408. }
  1409. /*
  1410. override bool CColMask::Check(int x,int y,CColMask* trg,int trgx,int trgy)
  1411. {
  1412. local ans = 0;
  1413. if (trg == terrainColMask)
  1414. {
  1415. ans = TSensorParent->Check(x, y, this);
  1416. } else if (this == terrainColMask)
  1417. {
  1418. ans = TSensorParent->Check(trgx, trgy, trg);
  1419. }
  1420. if (ans > 0)
  1421. {
  1422. return true;
  1423. } else if (ans < 0) return false;
  1424. return super;
  1425. } */
  1426.  
  1427. void CTouchSensor::Message(CObject* sender,EMType Type,int MSize,CMessageData* MData)
  1428. {
  1429. if (Type == M_FRAME)
  1430. {
  1431. if (nObjects > 0)
  1432. {
  1433. if (notify != NullObj)
  1434. {
  1435. CMessageData mData;
  1436. for (local i = 0; i < nObjects; i++)
  1437. {
  1438. activator = aObjs[i];
  1439. notify->Message( this, M_TOUCHSENSOR, 1032, &mData);
  1440. }
  1441. }
  1442. nObjects = 0;
  1443. }
  1444. }
  1445. }
  1446.  
  1447. override CGObject* CEnv::CheckCollisionEx(CGObject* obj,fixed x,fixed y,CColMask* mask,int colflags)
  1448. {
  1449. local res = super;
  1450.  
  1451. if (res != NullObj)
  1452. {
  1453. if (res->ClType == EObjectClass(4020))
  1454. {
  1455. local ts = CTouchSensor(res);
  1456. ts->activator = obj;
  1457.  
  1458. for (local i = 0; i < ts->nObjects; i++)
  1459. {
  1460. if (ts->aObjs[i] == obj)
  1461. {
  1462. if (ts->aCObjs[i])
  1463. {
  1464. return NullObj;
  1465. } else {
  1466. return ts->terrain;
  1467. }
  1468. }
  1469. }
  1470.  
  1471. CMessageData mData;
  1472. mData.params[0] = 0;
  1473. obj->Message( ts, M_TOUCHSENSOR_COLLIDE, 1032, &mData);
  1474.  
  1475. if (ts->nObjects < ts->maxObjects)
  1476. {
  1477. ts->aObjs[ts->nObjects] = obj;
  1478. ts->aCObjs[ts->nObjects] = mData.params[0] != 0;
  1479. ts->nObjects++;
  1480. }
  1481.  
  1482. if (mData.params[0] != 0) return NullObj;
  1483. return ts->terrain;
  1484. }
  1485. }
  1486.  
  1487. return res;
  1488. }
  1489.  
  1490.  
  1491.  
  1492. bool CTouchSensor::Reflect(CGObject* Obj,int type)
  1493. {
  1494. return false;
  1495. }
  1496. PXS : Library Code :
  1497.  
  1498. require utils;
  1499.  
  1500. CAntiGlitch* ggAg;
  1501.  
  1502. void antiglitch_s::Init()
  1503. {
  1504. ggAg = new CAntiGlitch;
  1505. }
  1506.  
  1507. CAntiGlitch::CAntiGlitch()
  1508. {
  1509. lTime = 0;
  1510. cState = 0;
  1511. gTime = 0;
  1512. rTime = 0;
  1513. }
  1514.  
  1515. void CAntiGlitch::Frame()
  1516. {
  1517.  
  1518. if ( (lTime == Root->Timer) && (rTime == Root->RetreatTimer) )
  1519. {
  1520. gTime += 20;
  1521. if (gTime > 20000)
  1522. {
  1523. if (cState == 0)
  1524. {
  1525. //shake all objects first
  1526. ShowMessage("Antiglitch Stage One");
  1527. for (local i = 1; i < Env->Objs.Count; i++)
  1528. {
  1529. local obj = CGObject(Env->Objs.Objs[i]);
  1530. if (obj == NullObj) continue;
  1531. local shake = obj->IsMoving();
  1532. if (!shake) continue;
  1533. if (obj is CMissile)
  1534. {
  1535. missile = CMissile(obj);
  1536. missile->ExplodeAt(missile->PosX, missile->PosY);
  1537. missile->Free(true);
  1538. continue;
  1539. }
  1540. obj->SpX = GS->GetRandom() % 200 - 100;
  1541. obj->SpY = GS->GetRandom() % 200 - 100;
  1542. }
  1543. cState = 1;
  1544. gTime = 10000;
  1545. } else if (cState == 1)
  1546. {
  1547. ShowMessage("Antiglitch Stage Two");
  1548. //delete objects to hell
  1549. for (local i = 1; i < Env->Objs.Count; i++)
  1550. {
  1551. local obj = CGObject(Env->Objs.Objs[i]);
  1552. if (obj == NullObj) continue;
  1553. if (obj->ClType == OC_Worm) continue;
  1554. if (!obj->IsMoving()) continue;
  1555. obj->Free(true);
  1556. }
  1557. cState = 2;
  1558. gTime = 10000;
  1559. } else if (cState == 2)
  1560. {
  1561. ShowMessage("Antiglitch Stage Three");
  1562. //shake everything
  1563. for (local i = 1; i < Env->Objs.Count; i++)
  1564. {
  1565. local obj = CGObject(Env->Objs.Objs[i]);
  1566. if (obj == NullObj) continue;
  1567. obj->SpX = GS->GetRandom() % 200 - 100;
  1568. obj->SpY = GS->GetRandom() % 200 - 100;
  1569. if (obj is CMissile)
  1570. {
  1571. missile = CMissile(obj);
  1572. missile->Free(true);
  1573. continue;
  1574. }
  1575. }
  1576. cState = 3;
  1577. gTime = 10000;
  1578. } else if (cState == 3)
  1579. {
  1580. cState = 4;
  1581. ShowMessage("Antiglitch Stage Four");
  1582. Root->Message( Root, M_SKIPTURN, 0, NullObj);
  1583. }
  1584. }
  1585. } else {
  1586. gTime = 0;
  1587. cState = 0;
  1588. lTime = Root->Timer;
  1589. rTime = Root->RetreatTimer;
  1590. }
  1591. }
  1592.  
  1593. override void CWorm::FireFinal(CWeapon* Weap,CShootDesc* Desc)
  1594. {
  1595. super;
  1596. ggAg->gTime = 0;
  1597. ggAg->cState = 0;
  1598. }
  1599.  
  1600. override void CWorm::SetState(EObjState State)
  1601. {
  1602. if (State == WS_DEAD)
  1603. {
  1604. ggAg->gTime = 0;
  1605. ggAg->cState = 0;
  1606. }
  1607. super;
  1608. }
  1609.  
  1610. override void CTurnGame::Message(CObject* sender,EMType Type,int MSize,CMessageData* MData)
  1611. {
  1612. super;
  1613. if (Type == M_FRAME)
  1614. {
  1615. ggAg->Frame();
  1616. }
  1617. }
  1618. PXS : Library Code :
  1619. require utils;
  1620.  
  1621.  
  1622. $editor
  1623. $object LightSource
  1624. $origin -15 -15
  1625. $image "edcross.png"
  1626. $radius 17
  1627. $func SpawnLightSource
  1628. $autoname LSource
  1629. $param Radius radius 50
  1630. $param FalloffRadius radius 75
  1631. $param Intensity int 100
  1632. $object_end
  1633.  
  1634. $object FoWControl
  1635. $origin -15 -15
  1636. $image "edfowcontrol.png"
  1637. $radius 17
  1638. $func SpawnFoWControl
  1639. $param Enable bool true
  1640. $param WormLightRadius int 50
  1641. $param WormLightFRadius int 110
  1642. $object_end
  1643. $end
  1644.  
  1645. CDarknessControl* darkControl;
  1646.  
  1647. #DARKNESS
  1648.  
  1649. enum DCLightType = (DCL_OMNI, DCL_DIRECT);
  1650.  
  1651. void darkness_script::Init()
  1652. {
  1653. darkControl = new CDarknessControl;
  1654. }
  1655.  
  1656. void SpawnLightSource(CEditorObject* obj)
  1657. {
  1658. darkControl->SetLight(obj->PosX, obj->PosY, obj->GetInt("Radius"),
  1659. obj->GetInt("FalloffRadius"), obj->GetInt("Intensity")/100.0);
  1660. darkControl->sSources = darkControl->nSources;
  1661. }
  1662.  
  1663. CDarknessControl::CDarknessControl()
  1664. {
  1665. enabled = false;
  1666. initialized = false;
  1667. seeAll = false;
  1668. lSource = new CLightSource[512];
  1669. sSources = 0;
  1670. wLightRadius = 50;
  1671. wLightFRadius = 110;
  1672. }
  1673.  
  1674. void DarknessControl_Render()
  1675. {
  1676. darkControl->Draw();
  1677. }
  1678.  
  1679. bool CDarknessControl::IsColorVisible(int clr)
  1680. {
  1681. if (IsReplay() || seeAll) return true;
  1682. if (IsMultiplayer())
  1683. {
  1684. if (GG->machColors[GetLocalMachine()] & (1 << clr))
  1685. {
  1686. return true;
  1687. }
  1688.  
  1689. } else {
  1690. if (clr == GetTeamColor(Root->CurTeam))
  1691. {
  1692. return true;
  1693. }
  1694. }
  1695. return false;
  1696. }
  1697.  
  1698. bool CDarknessControl::IsTeamVisible(int team)
  1699. {
  1700. return IsColorVisible(GetTeamColor(team));
  1701. }
  1702.  
  1703. bool CDarknessControl::DoIKnowHim(CWorm* worm)
  1704. {
  1705. if (!enabled) return true;
  1706. return IsTeamVisible(worm->WormTeam);
  1707. }
  1708.  
  1709.  
  1710. override void CWorm::RenderLabels()
  1711. {
  1712. if (darkControl->DoIKnowHim(this) || (DC_LightTimer > 0) ) super;
  1713. DC_LightTimer -= 1;
  1714. } /*
  1715. override void CWorm::RenderDmgLabel()
  1716. {
  1717. if (darkControl->DoIKnowHim(this)) super;
  1718. } */
  1719. override void CWorm::RenderCrosshair()
  1720. {
  1721. if (darkControl->DoIKnowHim(this)) super;
  1722. }
  1723.  
  1724. override void CDDQueue::AddSprite(fixed z,fixed x,fixed y,int unk,int sprite,fixed frame)
  1725. {
  1726. if (!darkControl->enabled || darkControl->seeAll || !IsMultiplayer())
  1727. {
  1728. super;
  1729. return;
  1730. }
  1731. local sIndex = sprite & 65535;
  1732. if (sIndex >= 20 && sIndex <= 25)
  1733. {
  1734. if (GG->machColors[GetLocalMachine()] & (1 << (sIndex - 20)) )
  1735. {
  1736. super;
  1737. }
  1738. return;
  1739. }
  1740. super;
  1741. }
  1742.  
  1743. override void CObject::ForceFocus(fixed x,fixed y)
  1744. {
  1745. if (!IsMultiplayer() || darkControl == NullObj || !darkControl->enabled)
  1746. {
  1747. super;
  1748. } else {
  1749. if (ClType == OC_Team)
  1750. {
  1751. local tm = CTeam(this);
  1752. if (GG->machColors[GetLocalMachine()] & (1 << GetTeamColor(tm->Index)))
  1753. {
  1754. super;
  1755. }
  1756. }
  1757. if (ClType == OC_Worm)
  1758. {
  1759. local wm = CWorm(this);
  1760. if (GG->machColors[GetLocalMachine()] & (1 << GetTeamColor(wm->WormTeam)))
  1761. {
  1762. super;
  1763. }
  1764. }
  1765. }
  1766. }
  1767. override void CGObject::LookAtMe(fixed x,fixed y,int priority)
  1768. {
  1769. if (!IsMultiplayer() || darkControl == NullObj || !darkControl->enabled)
  1770. {
  1771. super;
  1772. } else {
  1773. if (ClType == OC_Worm)
  1774. {
  1775. local wm = CWorm(this);
  1776. if (GG->machColors[GetLocalMachine()] & (1 << GetTeamColor(wm->WormTeam)))
  1777. {
  1778. super;
  1779. }
  1780. }
  1781. }
  1782. }
  1783.  
  1784. void CDarknessControl::Init()
  1785. {
  1786. bSize = 12;
  1787. nBlX = GS->Disp->xRes / bSize + 4;
  1788. nBlY = GS->Disp->yRes / bSize + 4;
  1789. lOutRGB = new int[nBlX*nBlY];
  1790. initialized = true;
  1791. if (IsMultiplayer())
  1792. {
  1793. if ((GG->machColors[GetLocalMachine()] & (1+2+4+8+16+32)) == 0) enabled = false;
  1794. }
  1795. }
  1796.  
  1797. void CDarknessControl::SetLight(float x, float y, float rad, float rad2, float intens)
  1798. {
  1799. if (nSources == 512) return;
  1800. lSource[nSources].x = x;
  1801. lSource[nSources].y = y;
  1802. lSource[nSources].rad = rad;
  1803. lSource[nSources].rad2 = rad2;
  1804. lSource[nSources].rads = rad * rad;
  1805. lSource[nSources].rad2s = rad2 * rad2;
  1806. lSource[nSources].intens = intens;
  1807. lSource[nSources].radds = rad2 * rad2 - rad * rad;
  1808. lSource[nSources].type = DCL_OMNI;
  1809. nSources++;
  1810. }
  1811.  
  1812. void CDarknessControl::SetDirectionalLight(float x1, float y1, float x2, float y2, float spread, float dSpread, float intens, float intensFall)
  1813. {
  1814. if (nSources == 512) return;
  1815.  
  1816. local ds = sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); //normalization factor
  1817. if (ds == 0) return;
  1818.  
  1819. lSource[nSources].a = (y1 - y2) / ds;
  1820. lSource[nSources].b = (x2 - x1) / ds;
  1821. lSource[nSources].c = -(x1 * (y1 - y2) + y1 * (x2 - x1)) / ds;
  1822. lSource[nSources].c2 = -(x1 * (x2 - x1) - y1 * (y1 - y2)) / ds;
  1823.  
  1824. lSource[nSources].x = x1;
  1825. lSource[nSources].y = y1;
  1826.  
  1827. lSource[nSources].rad = ds;
  1828. lSource[nSources].rad2 = spread;
  1829. lSource[nSources].rad2s = dSpread;
  1830. lSource[nSources].rads = (ds * dSpread + spread) / 3.0;
  1831. lSource[nSources].radsr = ds * dSpread + spread;
  1832.  
  1833.  
  1834. lSource[nSources].intens = intens;
  1835. lSource[nSources].intens2 = intensFall;
  1836.  
  1837.  
  1838. lSource[nSources].type = DCL_DIRECT;
  1839. nSources++;
  1840. }
  1841.  
  1842. void CDarknessControl::DoFlashlight(CGObject* fromObj, float x1, float y1, float dx, float dy, float maxDist)
  1843. {
  1844. local xr = 0; local yr = 0;
  1845. local cObj = TraceLine(fromObj, x1, y1, x1 + dx * maxDist, y1 + dy * maxDist, -1, &xr, &yr);
  1846. local ds = (xr - x1) * (xr - x1) + (yr - y1) * (yr - y1);
  1847. if (cObj != NullObj && ds < 40000)
  1848. {
  1849. if (cObj->ClType == OC_Worm)
  1850. {
  1851. local wm = CWorm(cObj);
  1852. wm->DC_LightTimer = 3;
  1853. }
  1854. }
  1855. SetDirectionalLight(x1, y1, xr, yr, 25, 0.35, 0.8, 0.7 / maxDist);
  1856. }
  1857.  
  1858. void CDarknessControl::GenerateLSources()
  1859. {
  1860. nSources = sSources;
  1861. for (local i = 1; i < Env->Objs.Count; i++)
  1862. {
  1863. local obj = CGObject(Env->Objs.Objs[i]);
  1864. if (obj == NullObj) continue;
  1865. if (obj->ClType == OC_Worm)
  1866. {
  1867. local wm = CWorm(obj);
  1868. local lit = DoIKnowHim(wm);
  1869. if (!lit) continue;
  1870. SetLight(obj->PosX, obj->PosY, wLightRadius, wLightFRadius, 0.9);
  1871. if (wm->ObjState == WS_AIMING || wm->ObjState == WS_SETPOWER || wm->ObjState == WS_FIRED || wm->ObjState == WS_FIRECONT)
  1872. {
  1873. local ang = (1 - wm->FireAngle) * 3.14159;
  1874. if (wm->TurnSide < 0)
  1875. {
  1876. ang = 6.28318 - ang;
  1877. }
  1878. DoFlashlight(wm, wm->PosX, wm->PosY, sin(ang), -cos(ang), 1000);
  1879. }
  1880. }
  1881. }
  1882. }
  1883.  
  1884. void CDarknessControl::GetLightIntensity(float x, float y, float* R, float* G, float* B)
  1885. {
  1886. local oR = 0.0; local oG = 0.0; local oB = 0.0;
  1887.  
  1888. for (local i = 0; i < nSources; i++)
  1889. {
  1890. local dx = x - lSource[i].x;
  1891. local dy = y - lSource[i].y;
  1892. local ds = dx * dx + dy * dy;
  1893. if (lSource[i].type == DCL_OMNI)
  1894. {
  1895. if (ds < lSource[i].rad2s)
  1896. {
  1897. if (ds < lSource[i].rads)
  1898. {
  1899. oR = oR + lSource[i].intens; oG = oG + lSource[i].intens; oB = oB + lSource[i].intens;
  1900. } else {
  1901. local coef = (1.0 - (ds - lSource[i].rads) / lSource[i].radds) * lSource[i].intens;
  1902. oR += coef; oG += coef; oB += coef;
  1903. }
  1904. }
  1905. } else {
  1906. local v1 = x * lSource[i].b - y * lSource[i].a + lSource[i].c2;
  1907. if (v1 >= 0)
  1908. {
  1909. local sp = 0.0; local coef2 = 1.0;
  1910. if (v1 <= lSource[i].rad)
  1911. {
  1912. sp = lSource[i].rad2 + v1 * lSource[i].rad2s;
  1913. } else {
  1914. if (v1 <= (lSource[i].rad + lSource[i].rads))
  1915. {
  1916. local coef2 = 1.0 - (v1 - lSource[i].rad) / lSource[i].rads;
  1917. sp = lSource[i].radsr * sqrt(coef2);
  1918. } else continue;
  1919. }
  1920.  
  1921. if (sp > 0.0)
  1922. {
  1923. sp = sp + 0.5;
  1924. local v2 = abs(x * lSource[i].a + y * lSource[i].b + lSource[i].c);
  1925. local coef = 1 - v2 / sp;
  1926. if (coef > 0.0)
  1927. {
  1928. local intens = lSource[i].intens - lSource[i].intens2 * v1;
  1929. if (intens > 0.0)
  1930. {
  1931. coef = coef * intens * coef2;
  1932. oR += coef; oG += coef; oB += coef;
  1933. }
  1934. }
  1935. }
  1936. }
  1937. }
  1938. }
  1939. *R = oR; *G = oG; *B = oB;
  1940. }
  1941.  
  1942. void CDarknessControl::Draw()
  1943. {
  1944. if (!initialized) Init();
  1945. GenerateLSources();
  1946. local i = 0; // i don't trust EAX to do typecasting :D
  1947. local offX = -float( int(int(GS->ActCameraX) % bSize) ) + GS->ActCameraX - GS->Disp->halfX - bSize;
  1948. local offY = -float( int(int(GS->ActCameraY) % bSize) ) + GS->ActCameraY - GS->Disp->halfY - bSize;
  1949. local IntensityR = 0.0;
  1950. local IntensityG = 0.0;
  1951. local IntensityB = 0.0;
  1952. for (local cy = 0; cy < nBlY; cy++)
  1953. {
  1954. local cOffX = offX;
  1955. local cOffY = cy * bSize + offY;
  1956. for (local cx = 0; cx < nBlX; cx++)
  1957. {
  1958. GetLightIntensity(cOffX, cOffY, &IntensityR, &IntensityG, &IntensityB);
  1959. local R = int(IntensityR * 255.0);
  1960. if (R > 255) R = 255;
  1961. local G = int(IntensityG * 255.0);
  1962. if (G > 255) G = 255;
  1963. local B = int(IntensityB * 255.0);
  1964. if (B > 255) B = 255;
  1965. lOutRGB[i] = RGB(R,G,B);
  1966. i++;
  1967. cOffX += bSize;
  1968. }
  1969. }
  1970.  
  1971. CQuad q;
  1972. i = 0;
  1973. q.tex = 0;
  1974. q.blend = 64; //color blending
  1975.  
  1976. for (local j = 0; j < 4; j++)
  1977. {
  1978. q.v[j].tx = 0; q.v[j].ty = 0;
  1979. }
  1980. for (local cy = 0; cy < (nBlY-1); cy++)
  1981. {
  1982. local cOffX = offX;
  1983. local cOffY = cy * bSize + offY;
  1984. for (local cx = 0; cx < (nBlX-1); cx++)
  1985. {
  1986. q.v[0].x = cOffX;
  1987. q.v[0].y = cOffY;
  1988. q.v[1].x = cOffX + bSize;
  1989. q.v[1].y = cOffY;
  1990. q.v[2].x = cOffX + bSize;
  1991. q.v[2].y = cOffY + bSize;
  1992. q.v[3].x = cOffX;
  1993. q.v[3].y = cOffY + bSize;
  1994.  
  1995. q.v[0].color = lOutRGB[i];
  1996. q.v[1].color = lOutRGB[i+1];
  1997. q.v[2].color = lOutRGB[i+nBlX+1];
  1998. q.v[3].color = lOutRGB[i+nBlX];
  1999. RenderQuad(&q, 0);
  2000.  
  2001.  
  2002. i++;
  2003. cOffX += bSize;
  2004. }
  2005. i++;
  2006. }
  2007. }
  2008.  
  2009. void CDarknessControl::UpdateStatus()
  2010. {
  2011. if (seeAll || !enabled || !initialized) return;
  2012. if (!IsMultiplayer()) return;
  2013.  
  2014. local hOther = false;
  2015. local hMy = false;
  2016. for (local i = 1; i < Env->Objs.Count; i++)
  2017. {
  2018. local wm = CWorm(Env->Objs.Objs[i]);
  2019. if (wm == NullObj) continue;
  2020. if (wm->ClType != OC_Worm) continue;
  2021. if (wm->ObjState == WS_DEATH) continue;
  2022. if (GG->machColors[GetLocalMachine()] & (1 << GetTeamColor(wm->WormTeam)))
  2023. {
  2024. hMy = true;
  2025. } else {
  2026. hOther = true;
  2027. }
  2028. }
  2029.  
  2030. if (!hMy) seeAll = true;
  2031. if (!hOther) seeAll = true;
  2032. }
  2033.  
  2034. void CDarknessControl::Queue()
  2035. {
  2036. if (!enabled) return;
  2037. Root->AddCustomRender(0.5, "DarknessControl_Render");
  2038. }
  2039.  
  2040. override void CTurnGame::Message(CObject* sender,EMType Type,int MSize,CMessageData* MData)
  2041. {
  2042. super;
  2043.  
  2044. if (Type == M_FRAME)
  2045. {
  2046. darkControl->UpdateStatus();
  2047. }
  2048. if (Type == M_DRAWQUEUE)
  2049. {
  2050. darkControl->Queue();
  2051. }
  2052. }
  2053.  
  2054. void SpawnFoWControl(CEditorObject* obj)
  2055. {
  2056. if (obj->GetBool("Enable"))
  2057. {
  2058. darkControl->enabled = true;
  2059. }
  2060. darkControl->wLightRadius = obj->GetInt("WormLightRadius");
  2061. darkControl->wLightFRadius = obj->GetInt("WormLightFRadius");
  2062.  
  2063. }
  2064. PXS : Library Code :
  2065. require Utils;
  2066.  
  2067. override CMine::CMine(CObject* Parent, CMineParams* Params, CShootDesc* Desc, bool Snap, int Unk)
  2068. {
  2069. if (Desc->Team >= 1)
  2070. {
  2071. Params->Radius = 1;
  2072.  
  2073. if (Params->Fuse >= 0) {
  2074. local AddFuse = GS->GetRandom() % 12 * 125;
  2075. Params->Fuse = 750 + AddFuse;
  2076. } else Params->Fuse = 0 - Params->Fuse;
  2077. };
  2078. super;
  2079. };
  2080.  
  2081. override void CMine::Message(CObject* sender, EMType Type, int MSize, CMessageData* MData)
  2082. {
  2083. if (Type != M_FRAME || InitParams.Radius != 1 || ClType != OC_Mine)
  2084. {
  2085. super;
  2086. return;
  2087. };
  2088. if (Active != 0 || Prefuse > 0)
  2089. {
  2090. super;
  2091. return;
  2092. };
  2093. for (local i = 1; i < Env->Objs.Count; i+=1)
  2094. {
  2095. local obj = Env->Objs.Objs[i];
  2096. if (obj == NullObj) continue;
  2097. if (obj->ClType != OC_Worm) continue;
  2098. local worm = CWorm(obj);
  2099. if (GetTeamColor(ShootData.Team) == GetTeamColor(worm->WormTeam)) continue;
  2100. if (DistBetweenObjs(obj, this) < 65)
  2101. {
  2102. Active = 1;
  2103. nPulses = Fuse / 250;
  2104. break;
  2105. };
  2106. };
  2107. super;
  2108. };
  2109.  
  2110. override void CMine::Render()
  2111. {
  2112. if (InitParams.Radius == -1) return;
  2113. if (InitParams.Radius == 1)
  2114. {
  2115. local Color = GetTeamColor(ShootData.Team);
  2116. if (Color == 0)
  2117. {
  2118. SetColorMod(RGB(180, 0, 0), 4); //4 - diffuse color goes to smooth addition
  2119. }
  2120. if (Color == 1)
  2121. {
  2122. SetColorMod(RGB(0, 0, 180), 4);
  2123. }
  2124. if (Color == 2)
  2125. {
  2126. SetColorMod(RGB(0, 180, 0), 4);
  2127. }
  2128. if (Color == 3)
  2129. {
  2130. SetColorMod(RGB(120, 120, 0), 4);
  2131. }
  2132. if (Color == 4)
  2133. {
  2134. SetColorMod(RGB(120, 0, 120), 4);
  2135. }
  2136. if (Color == 5)
  2137. {
  2138. SetColorMod(RGB(0, 120, 120), 4);
  2139. }
  2140. };
  2141. super;
  2142. ClearColorMod();
  2143. };
  2144. PXS : Library Code : require utils;
  2145. WindNade : CMissile;
  2146. GravityNade : CMissile;
  2147. StickyMine : CMine;
  2148. MovingOilDrum : COilDrum;
  2149.  
  2150.  
  2151. override void CWorm:: OnSink() { return; }
  2152.  
  2153. StickyMine::StickyMine(CObject* Parent,CMineParams* Params,CShootDesc* SDesc,bool Snap,int Unk, CWorm *launcher)
  2154. {
  2155. super(Parent, Params, SDesc, Snap, Unk);
  2156. stuck = false;
  2157. released = false;
  2158. launcher->stickyminedelete = false;
  2159. if ((PosX != SDesc->X) || (PosY != SDesc->Y)) {
  2160. launcher->nTotalShoots = 0;
  2161. //WORKAROUND FOR EAX BUG
  2162. launcher->stickyminedelete = true;
  2163. return;
  2164. }
  2165. }
  2166.  
  2167.  
  2168.  
  2169. void StickyMine::Collide(CGObject* Obj,int type)
  2170. {
  2171. super;
  2172. if (released == false){
  2173. if (stuck == false) {
  2174. SpX = 0;
  2175. SpY = 0;
  2176. GravityFactor=0;
  2177. stuck = true;
  2178. }
  2179. else {
  2180. GravityFactor=1;
  2181. released = true;
  2182. }
  2183. }
  2184. }
  2185.  
  2186.  
  2187.  
  2188. void StickyMine::Message(CObject* sender,EMType Type,int MSize,CMessageData* MData)
  2189. {
  2190. if (released == false){
  2191. if (Type == M_FRAME) {
  2192. if ( (stuck == true) && ((SpX != 0) || (SpY != 0)) ) {
  2193. GravityFactor = 1;
  2194. released = true;
  2195. }
  2196. }
  2197. }
  2198. super;
  2199. }
  2200.  
  2201. // WORKAROUND FOR WA BUG
  2202.  
  2203. override void CWorm::CWorm(CObject* Parent,int aTeam,int aIndex,CWormParams* params)
  2204. {
  2205. super;
  2206. stickyminefired = false;
  2207. }
  2208.  
  2209. // END OF WORKAROUND
  2210.  
  2211.  
  2212.  
  2213.  
  2214.  
  2215. MovingOilDrum::MovingOilDrum(CObject *parent, CShootDesc *Sdesc, CWorm *launcher)
  2216. {
  2217. FreeMe = false;
  2218. super(parent->GetObject(25, 0), Sdesc->X, Sdesc->Y, false);
  2219. SpX = Sdesc->SpX;
  2220. SpY = Sdesc->SpY;
  2221. if ((PosX != Sdesc->X) || (PosY != Sdesc->Y)) {
  2222. launcher->nAvalShoots = 1;
  2223. launcher->nTotalShoots = 0;
  2224. FreeMe = true;
  2225. return;
  2226. }
  2227. }
  2228.  
  2229. void MovingOilDrum::Message(CObject* sender,EMType Type,int MSize,CMessageData* MData)
  2230. {
  2231. if ((Type == M_FRAME) && FreeMe)
  2232. {
  2233. Free(true);
  2234. return;
  2235. }
  2236. super;
  2237. }
  2238.  
  2239.  
  2240.  
  2241.  
  2242. WindNade::WindNade(CObject* parent,CWeaponLaunch* ldata,CShootDesc* sdata)
  2243. {
  2244. super;
  2245. WindFactor = 1;
  2246. }
  2247.  
  2248. GravityNade::GravityNade(CObject* parent,CWeaponLaunch* ldata,CShootDesc* sdata)
  2249. {
  2250. super;
  2251. GravityFactor = 2;
  2252.  
  2253. }
  2254.  
  2255. override void CWorm::FireFinal(CWeapon* Weap,CShootDesc* Desc)
  2256. {
  2257. if (Weap->CheckName("GravNade"))
  2258. {
  2259. new GravityNade(Root->GetObject(25, 0),&Weap->launch, Desc);
  2260. return;
  2261. }
  2262. if (Weap->CheckName("WindNade"))
  2263. {
  2264. new WindNade(Root->GetObject(25, 0),&Weap->launch, Desc);
  2265. return;
  2266. }
  2267. if(Weap->CheckName("J"))
  2268. {
  2269. SpX = Desc->SpX;
  2270. SpY = Desc->SpY;
  2271. return;
  2272. }
  2273. if (Weap->CheckName("StickyMine"))
  2274. {
  2275. // WORKAROUND FOR WA BUG
  2276.  
  2277. // END OF WORKAROUND
  2278. CMineParams MParams;
  2279. zero(&MParams);
  2280. MParams.Prefuse = 2500; //time before ability to activate
  2281. MParams.Flags = 60; //flags of objects to react on
  2282. MParams.Bias = 0; //Y shift of explosion
  2283. MParams.Damage = 27; //damage
  2284. MParams.BlastPower = 100;
  2285. MParams.Fuse = 100;
  2286. MParams.Radius = 40;
  2287. local smine = new StickyMine(Root->GetObject(25, 0), &MParams, Desc, false, 0, this);
  2288. if (stickyminedelete) //workaround for EAX bug
  2289. {
  2290. smine->Free(true);
  2291. } else {
  2292. if (!stickyminefired) {
  2293. nTotalShoots = 0;
  2294. stickyminefired = true;
  2295. } else {
  2296. stickyminefired = false;
  2297. }
  2298. }
  2299. return;
  2300. }
  2301. if (Weap->CheckName("BarrelLauncher"))
  2302. {
  2303. new MovingOilDrum(Root->GetObject(25, 0), Desc, this);
  2304. return;
  2305. }
  2306. super;
  2307. }
  2308.  
  2309.  
  2310. override void CMissile::ExplodeAt(fixed x,fixed y)
  2311. {
  2312. if (weap->CheckName("TeleNade")){
  2313. currentworm = GetCurrentWorm();
  2314. if (currentworm != NullObj){
  2315. currentworm->PosX = x;
  2316. currentworm->PosY = y-6;
  2317. return;
  2318. }
  2319. return;
  2320. // weapon = GetWeaponByName("Teleport");
  2321. // shootdesc = new CShootDesc;
  2322. // currentworm = GetCurrentWorm();
  2323. // shootdesc->Team = currentworm->WormTeam;
  2324. // shootdesc->Worm = currentworm->WormNumber;
  2325. // shootdesc->AddX = x;
  2326. // shootdesc->AddY = y;
  2327. // shootdesc->X = currentworm->PosX;
  2328. // shootdesc->Y = currentworm->PosY;
  2329. // currentworm->FireFinal(weapon, shootdesc);
  2330. // return;
  2331. }
  2332.  
  2333. super;
  2334. }
  2335. PXS : Library Code :
  2336. require Utils;
  2337.  
  2338. CTurretBase : CGObject;
  2339.  
  2340. CSprite* turretSprite;
  2341. CSprite* turretSpriteB;
  2342.  
  2343. void turretbase::InitGraphic()
  2344. {
  2345. local f = GetAttachment("turretbase.png");
  2346. turretSprite = LoadSprite(f, 1, 0);
  2347. local f = GetAttachment("turrenttower.png");
  2348. turretSpriteB = LoadSprite(f, 1, 0);
  2349. };
  2350.  
  2351. void turretbase::FirstFrame()
  2352. {
  2353. local envfilter = CFilter(Root->GetObject(25, 0));
  2354. envfilter->Allow(M_TURNBEGIN);
  2355. };
  2356.  
  2357. CTurretBase::CTurretBase(CObject* parent, fixed x, fixed y)
  2358. {
  2359. super(parent, 17, 9); //barrel's collsion mask
  2360. PosX = x;
  2361. PosY = y;
  2362. SpX = 0;
  2363. SpY = 0;
  2364. ColGroup = 6190;
  2365. DumpingB = 0.5;
  2366. IsMaterial = true;
  2367. SpeedDivider = 1;
  2368. TargetObj = CGObject(NullObj);
  2369.  
  2370. baseSprite = turretSprite;
  2371. towerSprite = turretSpriteB;
  2372.  
  2373. ClType = EObjectClass(500);
  2374.  
  2375. gFactor = 1.0;
  2376.  
  2377. towerOffset = 25;
  2378. thinkingTime = 15;
  2379. curThink = 0;
  2380.  
  2381. dontShoot = false;
  2382.  
  2383. timeForShoot = 15.0; //time, need for ballistic solving
  2384.  
  2385. minimalRadius = 40;
  2386. sensorRadius = 350;
  2387. lostRadius = 450;
  2388.  
  2389. turretangle = 1.57;
  2390. angToShoot = 0.0;
  2391. turretdir = 1;
  2392.  
  2393. reloadState = 0;
  2394. reloadTime = 30;
  2395. initalRTime = 20;
  2396. stepRTime = 1.12;
  2397. shootPower = 0.0;
  2398.  
  2399. timeForShoot = 32.0;
  2400.  
  2401. turretTeam = -1;
  2402.  
  2403. ammoPerTurn = 5;
  2404.  
  2405. towerlen = 10;
  2406.  
  2407. local FourCheck = MakeCircleMask(3);
  2408. FourCheckMask = new CColMask(0, 0, FourCheck);
  2409.  
  2410. breakable = false;
  2411. health = 50;
  2412. maxHealth = health;
  2413. ExpDamage = 50;
  2414.  
  2415. speed = 0.08;
  2416. };
  2417.  
  2418. void CTurretBase::GetShootAngle()
  2419. {
  2420. local tm = timeForShoot;
  2421. local x = TargetObj->PosX - PosX;
  2422. local rx = x / timeForShoot;
  2423. local y = TargetObj->PosY - (PosY - towerOffset);
  2424. local ry = SolveBallistic(y, timeForShoot, Env->Gravity * gFactor);
  2425.  
  2426. angToShoot = 0.0;
  2427. if (rx > 0)
  2428. {
  2429. angToShoot = atan2(rx, 0 - ry);
  2430. turretdir = 1;
  2431. } else {
  2432. angToShoot = atan2(0 - rx, 0 - ry);
  2433. turretdir = -1;
  2434. };
  2435. shootPower = sqrt(rx * rx + ry * ry);
  2436.  
  2437. lrx = rx;
  2438. lry = ry;
  2439. };
  2440.  
  2441. bool CTurretBase::CheckTrace()
  2442. {
  2443. local trtime = timeForShoot;
  2444. local a = 0;
  2445. local HObj = BTrace(this, FourCheckMask, PosX, PosY - towerOffset, lrx, lry, Env->Gravity * gFactor, trtime - 1, 1, &a);
  2446. if (CObject(HObj) == Env->Objs.Objs[0]) return true;
  2447. return false;
  2448. };
  2449.  
  2450. bool CTurretBase::AimToEnemy()
  2451. {
  2452.  
  2453. DistToEnemy = DistBetweenObjs(this, TargetObj);
  2454. if (DistToEnemy > lostRadius)
  2455. {
  2456. TargetObj = NullObj;
  2457. return false;
  2458. };
  2459.  
  2460. local ang = 0.0;
  2461. //MY RULE FOR ARCTAN
  2462. //a = sin(ang)
  2463. //b = cos(ang)
  2464. //ang = atan2(a, b);
  2465.  
  2466. GetShootAngle();
  2467.  
  2468. local ang = angToShoot;
  2469.  
  2470. if (abs(ang - turretangle) > (speed * 2) )
  2471. // if (false)
  2472. {
  2473. if (ang > turretangle)
  2474. {
  2475. turretangle = turretangle + speed;
  2476. } else {
  2477. turretangle = turretangle - speed;
  2478. };
  2479. return false;
  2480. } else {
  2481. turretangle = ang;
  2482. if (dontShoot) return false;
  2483. return true;
  2484. };
  2485.  
  2486. };
  2487.  
  2488. void CTurretBase::UpdateTime()
  2489. {
  2490. timeForShoot += 10.0;
  2491. timeForShoot = timeForShoot * 1.1;
  2492. if (timeForShoot > 100.0) timeForShoot = 16.0;
  2493. };
  2494.  
  2495. void CTurretBase::FillShootingInfo()
  2496. {
  2497. ShootX = PosX + sin(turretangle) * turretdir * towerlen;
  2498. ShootY = (PosY - towerOffset) - cos(turretangle) * towerlen;
  2499. ShootSX = sin(turretangle) * turretdir;
  2500. ShootSY = 0.0 - cos(turretangle);
  2501. UpdateTime();
  2502. };
  2503.  
  2504. bool CTurretBase::ShootAtEnemy()
  2505. {
  2506. // PrintMessage(2);
  2507. return true;
  2508. };
  2509.  
  2510. void CTurretBase::FindTarget()
  2511. {
  2512. for (local i = 1; i < Env->Objs.Count; i+=1)
  2513. {
  2514. local Obj = Env->Objs.Objs[i];
  2515. if (Obj == NullObj) continue;
  2516. if (Obj->ClType != OC_Worm) continue;
  2517.  
  2518. local Worm = CWorm(Obj);
  2519.  
  2520. if (turretTeam >= 0)
  2521. {
  2522. local tColor = GetTeamColor(Worm->WormTeam);
  2523. if (tColor == GetTeamColor(turretTeam)) continue;
  2524. };
  2525.  
  2526. if (Worm->ObjState != WS_WALKING)
  2527. {
  2528. if ((Worm->SpX == 0) && (Worm->SpY == 0)) continue;
  2529. }
  2530.  
  2531. if (GS->Info.GetWormHealth(Worm->WormTeam,Worm->WormNumber) <= 0) continue;
  2532.  
  2533.  
  2534. local CatX = Worm->PosX - PosX;
  2535. local CatY = Worm->PosY - (PosY - towerOffset);
  2536. local Dist = sqrt(CatX * CatX + CatY * CatY);
  2537.  
  2538. if (Dist < minimalRadius) continue;
  2539. if (Dist < sensorRadius)
  2540. {
  2541. if (srandom_p() < 0.3)
  2542. {
  2543. if (Obj != TargetObj)
  2544. {
  2545. TargetObj = Obj;
  2546. PRegister(&TargetObj);
  2547. };
  2548. };
  2549. };
  2550. };
  2551. };
  2552.  
  2553. bool CTurretBase::ApplyDamage(int dmg)
  2554. {
  2555. if (breakable == false) return false;
  2556. health -= dmg;
  2557. if (health <= 0)
  2558. {
  2559. DoExplosion(PosX,PosY, 100, ExpDamage, 0, 0);
  2560. Free(true);
  2561. return true;
  2562. }
  2563. return false;
  2564. }
  2565.  
  2566. void CTurretBase::Message(CObject* sender, EMType Type, int MSize, CMessageData* MData)
  2567. {
  2568. if (breakable && (health <= 0)) return;
  2569. if (Type == M_FRAME)
  2570. {
  2571. if (reloadState > 0) reloadState -= 1;
  2572. if (Root->IsTimerActive() == false)
  2573. {
  2574. super;
  2575. return;
  2576. };
  2577. if (ammoCurrent <= 0)
  2578. {
  2579. super;
  2580. return;
  2581. }
  2582. if (TargetObj == NullObj)
  2583. {
  2584. FindTarget();
  2585. curThink = thinkingTime;
  2586. } else {
  2587. if (curThink > 0)
  2588. {
  2589. curThink = curThink - 1;
  2590. } else {
  2591. if (AimToEnemy())
  2592. {
  2593. if (reloadState == 0)
  2594. {
  2595. if (CheckTrace())
  2596. {
  2597. if (srandom_p() < 0.65)
  2598. {
  2599. UpdateTime();
  2600. curThink = 4;
  2601. } else {
  2602. TargetObj = NullObj;
  2603. curThink = 10;
  2604. return;
  2605. };
  2606. reloadState = reloadTime;
  2607. return;
  2608. };
  2609. FillShootingInfo();
  2610. if (ShootAtEnemy())
  2611. {
  2612. reloadState = reloadTime;
  2613. reloadTime = int(reloadTime * stepRTime);
  2614. ammoCurrent -= 1;
  2615. } else {
  2616. TargetObj = NullObj;
  2617. curThink = 10;
  2618. return;
  2619. }
  2620. };
  2621. };
  2622. };
  2623. };
  2624. };
  2625. if (Type == M_DRAWQUEUE)
  2626. {
  2627. local colorCoef = health / maxHealth * 0.75 + 0.25;
  2628. int r; int g; int b;
  2629. GetTeamColorRGB(GetTeamColor(turretTeam)+1, &r, &g, &b);
  2630. if (r < 128) r = 128;
  2631. if (g < 128) g = 128;
  2632. if (b < 128) b = 128;
  2633. SetColorMod(RGB(colorCoef * r, colorCoef * g, colorCoef * b), 0);
  2634.  
  2635. AddSprite(12, PosX, PosY, 0, baseSprite->Index, 0);
  2636. local spr = towerSprite->Index;
  2637. local ang = turretangle;
  2638. if (turretdir < 0)
  2639. {
  2640. spr = spr + 262144;
  2641. ang = 3.1415 - ang;
  2642. };
  2643.  
  2644. // local ang = turretangle;
  2645. // if (turretdir < 0) ang = ang + 1.5707;
  2646.  
  2647. AddSpriteEx(11, PosX, PosY - towerOffset, spr, 0, ang - 1.5707, 1);
  2648. ClearColorMod();
  2649. };
  2650.  
  2651. if (Type == M_TURNBEGIN)
  2652. {
  2653. reloadTime = initalRTime;
  2654. ammoCurrent = ammoPerTurn;
  2655. TargetObj = CGObject(NullObj);
  2656. }
  2657.  
  2658. if (breakable)
  2659. {
  2660. if (Type == M_EXPLOSION)
  2661. {
  2662. local dx = MData->fparams[1] - PosX;
  2663. local dy = MData->fparams[2] - PosY;
  2664.  
  2665. local dist = dx*dx + dy*dy;
  2666. local dmgcoef = 1 - dist / (MData->params[4] * MData->params[4] * 4);
  2667. if (dmgcoef > 0)
  2668. {
  2669. if (ApplyDamage(dmgcoef * MData->params[4])) return;
  2670. }
  2671.  
  2672. }
  2673.  
  2674. if (Type == M_GUNEXP)
  2675. {
  2676. if (sender is CArrow)
  2677. {
  2678. if (CArrow(sender)->TeamIndex == turretTeam)
  2679. {
  2680. return;
  2681. }
  2682. }
  2683. if (ApplyDamage(MData->params[5])) return;
  2684. }
  2685. }
  2686.  
  2687. super;
  2688. };
  2689. PXS : Library Code :
  2690. $editor
  2691. $object MineTurret
  2692. $origin -20 -25
  2693. $radius 28
  2694. $image "edturret.png"
  2695. $func SpawnTurret
  2696. $param Invincible bool false
  2697. $param Mounted bool false
  2698. $param ClearMines bool true
  2699. $param AmmoPerTurn int 9999
  2700. $object_end
  2701. $end
  2702.  
  2703. CSprite* mineturretBase;
  2704. CSprite* mineturretTower;
  2705.  
  2706. void mineturret::InitGraphic()
  2707. {
  2708. local f = GetAttachment("baseminez.png");
  2709. mineturretBase = LoadSprite(f, 1, 0);
  2710. local f = GetAttachment("towerminez.png");
  2711. mineturretTower = LoadSprite(f, 1, 0);
  2712. }
  2713.  
  2714. CMineTurret : CTurretBase;
  2715.  
  2716. void CMineTurret::CMineTurret(CObject* parent, fixed x, fixed y)
  2717. {
  2718. super;
  2719. breakable = true;
  2720. clearMines = false;
  2721. baseSprite = mineturretBase;
  2722. towerSprite = mineturretTower;
  2723. };
  2724.  
  2725. bool CMineTurret::ShootAtEnemy()
  2726. {
  2727. if (CheckMaskAt(this, FourCheckMask, ShootX, ShootY, -1) != NullObj) return false;
  2728. CMineParams MParams;
  2729. CShootDesc SDesc;
  2730. zero(&MParams);
  2731. zero(&SDesc);
  2732.  
  2733. local ForceVar = GS->GetRandom() % 64;
  2734. local BaseForce = shootPower - 0.1 + ForceVar / 96.0;
  2735.  
  2736. SDesc.Team = turretTeam;
  2737. SDesc.X = ShootX;
  2738. SDesc.Y = ShootY;
  2739.  
  2740. if (turretTeam < 0) SDesc.Team = 0;
  2741.  
  2742. SDesc.SpX = ShootSX * BaseForce;
  2743. SDesc.SpY = ShootSY * BaseForce;
  2744.  
  2745. MParams.Prefuse = 0;
  2746. MParams.Flags = 60;
  2747. MParams.Bias = 0;
  2748. MParams.Damage = 50;
  2749. MParams.BlastPower = 100;
  2750. MParams.Fuse = 400; //20 frames
  2751. MParams.Radius = 48;
  2752.  
  2753. local Mine = new CMine(Root->GetObject(25, 0), &MParams, &SDesc, false, 0);
  2754. Mine->autoTurnDestruct = clearMines;
  2755. return true;
  2756. };
  2757.  
  2758. override void CWorm::FireFinal(CWeapon* Weap, CShootDesc* Desc)
  2759. {
  2760. if (Weap->CheckName("Mine Turret"))
  2761. {
  2762. local sg = new CMineTurret(GetObject(25, 0), PosX + 15 * TurnSide, PosY - 50);
  2763. sg->turretTeam = WormTeam;
  2764. sg->ammoPerTurn = 6;
  2765. } else {
  2766. super;
  2767. };
  2768. };
  2769.  
  2770. void SpawnTurret(CEditorObject* eobj)
  2771. {
  2772. local sg = new CMineTurret(Root->GetObject(25, 0), eobj->PosX, eobj->PosY);
  2773. sg->turretTeam = -1;
  2774. sg->clearMines = eobj->GetBool("ClearMines");
  2775. sg->ammoPerTurn = eobj->GetInt("AmmoPerTurn");
  2776. if (eobj->GetBool("Invincible"))
  2777. {
  2778. sg->breakable = false;
  2779. }
  2780. if (eobj->GetBool("Mounted"))
  2781. {
  2782. sg->SpeedDivider = 32767;
  2783. for (local i = 0; i < 100; i++)
  2784. {
  2785. if (Env->CheckCollision(sg, sg->PosX, sg->PosY + 1) != NullObj) break;
  2786. sg->PosY += 1;
  2787. }
  2788. }
  2789. };
  2790. PXS : Library Code :
  2791. require utils;
  2792.  
  2793. CArrowTurret : CTurretBase;
  2794.  
  2795. bool AT_DontDrawLand;
  2796.  
  2797. CSprite* arrturretBase;
  2798. CSprite* arrturretTower;
  2799.  
  2800. void arrowturret::InitGraphic()
  2801. {
  2802. local f = GetAttachment("balbase.png");
  2803. arrturretBase = LoadSprite(f, 1, 0);
  2804. local f = GetAttachment("baltower.png");
  2805. arrturretTower = LoadSprite(f, 1, 0);
  2806. }
  2807.  
  2808. override void CLandscape::ApplyBitmap(int x,int y,int sx,int sy,CBitmap* bm,CBitmap* bm2,int srcX,int srcY)
  2809. {
  2810. if (AT_DontDrawLand) return;
  2811. super;
  2812. }
  2813.  
  2814. override CArrow::CArrow(CObject* Parent,int* damage,CShootDesc* desc)
  2815. {
  2816. DontStick = false;
  2817. super;
  2818. }
  2819.  
  2820. override void CArrow::Message(CObject* sender,EMType Type,int MSize,CMessageData* MData)
  2821. {
  2822. if (DontStick)
  2823. {
  2824. AT_DontDrawLand = true;
  2825. super;
  2826. AT_DontDrawLand = false;
  2827. } else {
  2828. super;
  2829. }
  2830. }
  2831.  
  2832. void CArrowTurret::CArrowTurret(CObject* parent, fixed x, fixed y)
  2833. {
  2834. super;
  2835. gFactor = 0.25;
  2836. ColGroup = ColGroup & (-65537); //remove Arrows flag
  2837. breakable = true;
  2838. towerlen = 16;
  2839. ammoPerTurn = 8;
  2840. baseSprite = arrturretBase;
  2841. towerSprite = arrturretTower;
  2842. };
  2843.  
  2844. bool CArrowTurret::AimToEnemy()
  2845. {
  2846. if (TargetObj != NullObj)
  2847. {
  2848. local l = DistBetweenObjs(TargetObj, this);
  2849. timeForShoot = l / 10 + 1; //500 pixels per sec, rait
  2850. }
  2851. return super;
  2852. }
  2853.  
  2854. bool CArrowTurret::ShootAtEnemy()
  2855. {
  2856. if (CheckMaskAt(Root, FourCheckMask, ShootX, ShootY, -65537) != NullObj) return false;
  2857.  
  2858.  
  2859. CShootDesc SDesc;
  2860. zero(&SDesc);
  2861.  
  2862. local ForceVar = GS->GetRandom() % 64;
  2863. local BaseForce = shootPower - 0.1 + ForceVar / 96.0;
  2864.  
  2865. SDesc.Team = turretTeam; //no more //fixin rare CArrow crash bug.
  2866. SDesc.Worm = 0;
  2867.  
  2868. SDesc.X = ShootX;
  2869. SDesc.Y = ShootY;
  2870. if (turretTeam < 0) SDesc.Team = 0; //wtf
  2871.  
  2872. SDesc.SpX = ShootSX * BaseForce;
  2873. SDesc.SpY = ShootSY * BaseForce;
  2874.  
  2875. local admg = 10;
  2876.  
  2877. local arrow = new CArrow(Root->GetObject(25, 0), &admg, &SDesc);
  2878. if (CGObject(arrow)->IsValid())
  2879. {
  2880. arrow->GravityFactor = 0.25;
  2881. arrow->DontStick = true;
  2882. }
  2883. return true;
  2884.  
  2885. };
  2886.  
  2887. override void CWorm::FireFinal(CWeapon* Weap, CShootDesc* Desc)
  2888. {
  2889. if (Weap->CheckName("Auto-ballista"))
  2890. {
  2891. local sg = new CArrowTurret(GetObject(25, 0), PosX + 15 * TurnSide, PosY - 50);
  2892. sg->turretTeam = WormTeam;
  2893. } else {
  2894. super;
  2895. };
  2896. };
  2897. PXS : Library Code :
  2898. require utils;
  2899.  
  2900. PxParticleManager : CObject
  2901. PxParticle : CObject
  2902.  
  2903. PxParticleManager *PM;
  2904.  
  2905. void particle::FirstFrame()
  2906. {
  2907. PM = new PxParticleManager();
  2908. }
  2909.  
  2910. PxParticleManager::PxParticleManager()
  2911. {
  2912. super(Root, GS);
  2913. }
  2914.  
  2915. void __DrawPxParticles()
  2916. {
  2917. PM->Draw();
  2918. }
  2919.  
  2920. void PxParticleManager::Draw()
  2921. {
  2922. for(int i=0 ; i<Childs.Count ; i+=1)
  2923. {
  2924. local p = PxParticle(Childs.Objs[i]);
  2925. if(p == PxParticle(NullObj)) continue;
  2926. p->Draw();
  2927. }
  2928. }
  2929.  
  2930. void PxParticleManager::Message(CObject* sender, EMType Type, int MSize, CMessageData* MData)
  2931. {
  2932. if(Type == M_FRAME)
  2933. {
  2934. super;
  2935. }
  2936. if(Type == M_DRAWQUEUE)
  2937. {
  2938. AddCustomRender(6, "__DrawPxParticles");
  2939. }
  2940.  
  2941. if(Type == M_FRAME)
  2942. {
  2943. for(int i=0 ; i<Childs.Count ; i+=1)
  2944. {
  2945. local p = PxParticle(Childs.Objs[i]);
  2946. if(p == PxParticle(NullObj)) continue;
  2947.  
  2948. if(p->Dead)
  2949. {
  2950. p->Free(true);
  2951. break;
  2952. }
  2953. }
  2954. }
  2955. }
  2956.  
  2957. PxParticle::PxParticle(int sprite, float x, float y)
  2958. {
  2959. super(PM, GS);
  2960.  
  2961. PosX = x;
  2962. PosY = y;
  2963. SpX = 0.0;
  2964. SpY = 0.0;
  2965. Sprite = sprite;
  2966.  
  2967. AirResistance = 0.0;
  2968. LifeTime = 50;
  2969. StartR = 255; StartG = 255; StartB = 255; StartA = 255;
  2970. EndR = 255; EndG = 255; EndB = 255; EndA = 0;
  2971. StartSizeX = 1.0;
  2972. StartSizeY = 1.0;
  2973. EndSizeX = 1.0;
  2974. EndSizeY = 1.0;
  2975. GravityFactor = 0.0;
  2976. WindFactor = 0.0;
  2977. AngleSpeed = 0.0;
  2978. BlendMode = 0;
  2979. Randomness = 0;
  2980.  
  2981. AnimSpeed = 0.0;
  2982. AnimCycle = 0.0;
  2983.  
  2984. //Collision = false;
  2985. //CollisionDamping = 1.0;
  2986.  
  2987. Rotation = 0.0;
  2988. CurFrame = 0.0;
  2989. Dead = false;
  2990.  
  2991. AirResistance = 1.0 / (AirResistance + 1.0);
  2992. }
  2993.  
  2994. void PxParticle::SetAirResistance(float a) { AirResistance = 1.0 / (a + 1.0); }
  2995. void PxParticle::SetLifeTime(int t) { CurFrame = 0; LifeTime = t; }
  2996. void PxParticle::SetStartColor(int r, int g, int b)
  2997. { StartR = r; StartG = g; StartB = b; }
  2998. void PxParticle::SetEndColor(int r, int g, int b)
  2999. { EndR = r; EndG = g; EndB = b; }
  3000. void PxParticle::SetColor(int r, int g, int b)
  3001. { StartR = r; StartG = g; StartB = b;
  3002. EndR = r; EndG = g; EndB = b; }
  3003. void PxParticle::SetStartAlpha(int a) { StartA = a; }
  3004. void PxParticle::SetEndAlpha(int a) { EndA = a; }
  3005. void PxParticle::SetAlpha(int a) { StartA = a; EndA = a; }
  3006. void PxParticle::SetStartSize(float x, float y) { StartSizeX = x ; StartSizeY = y; }
  3007. void PxParticle::SetEndSize(float x, float y) { EndSizeX = x ; EndSizeY = y; }
  3008. void PxParticle::SetSize(float x, float y) { StartSizeX = x ; StartSizeY = y;
  3009. EndSizeX = x ; EndSizeY = y; }
  3010. void PxParticle::GravityFactor(float g) { GravityFactor = g; }
  3011. void PxParticle::SetWindFactor(float f) { WindFactor = f; }
  3012. void PxParticle::SetAngleSpeed(float s) { AngleSpeed = s; }
  3013. void PxParticle::SetVelocity(float x, float y) { SpX = x; SpY = y; }
  3014.  
  3015. void PxParticle::SetBlendMode(int mode) { BlendMode = mode; }
  3016. void PxParticle::SetMotionRandomness(float r) { Randomness = r; }
  3017. //void PxParticle::SetWorldCollision(bool c) { Collision = c; }
  3018. //void PxParticle::SetBounce(float d) { CollisionDamping = d; }
  3019.  
  3020. void PxParticle::SetAnimSpeed(float s) { AnimSpeed = s; }
  3021.  
  3022. void PxParticle::SetRandomVelocity(float min, float max)
  3023. {
  3024. float s = RandomFloat(min, max);
  3025. float a = (RandomInt(0,360) * 3.141593) / 180.0;
  3026.  
  3027. SpX = s * cos(a);
  3028. SpY = s * sin(a);
  3029. }
  3030.  
  3031. void PxParticle::Draw()
  3032. {
  3033. if(Dead) return;
  3034.  
  3035. float cycle = CurFrame / LifeTime;
  3036. if(cycle >= 1.0) return;
  3037.  
  3038. float animcycle = cycle;
  3039.  
  3040. if(AnimSpeed > 0.0)
  3041. {
  3042. animcycle = AnimCycle;
  3043. }
  3044.  
  3045. float xsize = StartSizeX + cycle * (EndSizeX - StartSizeX);
  3046. float ysize = StartSizeY + cycle * (EndSizeY - StartSizeY);
  3047. float r = StartR + cycle * (EndR - StartR);
  3048. float g = StartG + cycle * (EndG - StartG);
  3049. float b = StartB + cycle * (EndB - StartB);
  3050. float a = StartA + cycle * (EndA - StartA);
  3051. int col = ARGB(a, r, g, b);
  3052.  
  3053. CQuad q;
  3054. FillSpriteQuad(&q, Sprite, animcycle, 0);
  3055. TransformQuad(&q, Rotation, xsize, ysize, PosX, PosY);
  3056. q.blend = BlendMode;
  3057. for(int i=0 ; i<4 ; i+=1) q.v[i].color = col;
  3058.  
  3059. RenderQuad(&q, 0);
  3060. }
  3061.  
  3062. void PxParticle::Message(CObject* sender, EMType Type, int MSize, CMessageData* MData)
  3063. {
  3064. if(Dead) return;
  3065.  
  3066. if(Type == M_FRAME)
  3067. {
  3068. if(CurFrame >= LifeTime)
  3069. {
  3070. Randomness = 0;
  3071. Dead = true;
  3072. return;
  3073. }
  3074. Rotation += AngleSpeed;
  3075. while(Rotation > 3.141593) Rotation -= 6.283186;
  3076. while(Rotation <= 0 - 3.141593) Rotation += 6.283186;
  3077.  
  3078. PosX = PosX + SpX;
  3079. PosY = PosY + SpY;
  3080. SpX = (SpX * AirResistance) + (WindFactor * Env->Wind);
  3081. SpY = (SpY * AirResistance) + (GravityFactor * Env->Gravity);
  3082.  
  3083. if(Randomness > 0)
  3084. {
  3085. float s = RandomFloat(0, Randomness);
  3086. float a = (RandomInt(0,360) * 3.141593) / 180.0;
  3087.  
  3088. SpX = SpX + s * cos(a);
  3089. SpY = SpY + s * sin(a);
  3090. }
  3091.  
  3092. CurFrame += 1.0;
  3093.  
  3094. if(AnimSpeed > 0.0)
  3095. {
  3096. AnimCycle = AnimCycle + AnimSpeed;
  3097. if(AnimCycle >= 1.0) AnimCycle -= 1.0;
  3098. }
  3099. }
  3100. }
  3101. PXS : Library Code :
  3102. PxAirstrikeParams::PxAirstrikeParams()
  3103. {
  3104. Sprite = 86;
  3105. Sound = 52;
  3106.  
  3107. NumBombs = 5;
  3108. BombDistance = 32;
  3109. FramesBetweenBombs = 1;
  3110. BombSpX = 0;
  3111. BombSpY = 0;
  3112.  
  3113. SpeedCompensation = 3.0;
  3114.  
  3115. PlaneAppearXOffset = 512;
  3116. PlaneAppearYOffset = -128;
  3117. }
  3118.  
  3119. ///////////////////////////////////////////////////
  3120. // PxAirstrike
  3121.  
  3122. PxAirstrike : CObject;
  3123.  
  3124. PxAirstrike::PxAirstrike(CObject* Parent, CShootDesc* Desc, PxAirstrikeParams* Params)
  3125. {
  3126. super(Parent, GS);
  3127. ClType = OC_AirStrike;
  3128.  
  3129. Sprite = Params->Sprite;
  3130. Sound = Params->Sound;
  3131. ShouldPlaySound = true;
  3132.  
  3133. //Direction = Params->Direction;
  3134. Direction = Desc->SpX;
  3135. Team = Desc->Team;
  3136. Worm = Desc->Worm;
  3137.  
  3138. NumBombs = Params->NumBombs;
  3139. BombDistance = Params->BombDistance;
  3140. FramesBetweenBombs = Params->FramesBetweenBombs;
  3141. PlaneAppearXOffset = Params->PlaneAppearXOffset;
  3142. PlaneAppearYOffset = Params->PlaneAppearYOffset;
  3143. SpeedCompensation = Params->SpeedCompensation;
  3144.  
  3145. BombSpX = Params->BombSpX;
  3146. BombSpY = Params->BombSpY;
  3147.  
  3148. PosX = 0.0;
  3149. PosY = 0.0;
  3150. SpY = 0.0;
  3151. BombDrop = 0;
  3152.  
  3153. if(Direction >= 0)
  3154. {
  3155. // Left to right
  3156. Direction = 1;
  3157. SpX = BombDistance / FramesBetweenBombs;
  3158. }
  3159. else
  3160. {
  3161. // Right to left
  3162. Direction = -1;
  3163. SpX = -BombDistance / FramesBetweenBombs;
  3164. BombSpX = -BombSpX;
  3165. }
  3166.  
  3167. // Position the airplane on the horizontal axis
  3168.  
  3169. PosX = Desc->AddX;
  3170. PosY = PlaneAppearYOffset;
  3171.  
  3172. // Speed compensation for directional strikes depending on AddY
  3173. int DiffY = Desc->AddY - PosY;
  3174. if(DiffY < 0) DiffY = 0;
  3175.  
  3176. float fPosX = SpeedCompensation * BombSpX * sqrt(DiffY);
  3177. fPosX = PosX - fPosX;
  3178.  
  3179. PosX = fPosX;
  3180.  
  3181. BombDrop = NumBombs / 2;
  3182.  
  3183. if(BombDrop * 2 == NumBombs)
  3184. {
  3185. // Even number of bombs
  3186. PosX = PosX - (Direction * BombDistance) / 2;
  3187. }
  3188. else
  3189. {
  3190. // Odd number of bombs
  3191. BombDrop = BombDrop + 1;
  3192. }
  3193.  
  3194. if(Direction == 1)
  3195. {
  3196. while(PosX > 0 - PlaneAppearXOffset)
  3197. {
  3198. PosX = PosX - FramesBetweenBombs * BombDistance;
  3199. BombDrop = BombDrop - 1;
  3200. }
  3201. }
  3202. else
  3203. {
  3204. while(PosX < GS->LevelSX + PlaneAppearXOffset)
  3205. {
  3206. PosX = PosX + FramesBetweenBombs * BombDistance;
  3207. BombDrop = BombDrop - 1;
  3208. }
  3209. }
  3210.  
  3211. FrameCounter = 0;
  3212. }
  3213.  
  3214. void PxAirstrike::DropBomb()
  3215. {
  3216. }
  3217.  
  3218. void PxAirstrike::RenderPlane()
  3219. {
  3220. if(Direction > 0)
  3221. {
  3222. AddSprite(10, PosX, PosY, 0, 262144 + Sprite, 0);
  3223. }
  3224. else
  3225. {
  3226. AddSprite(10, PosX, PosY, 0, Sprite, 0);
  3227. }
  3228. }
  3229.  
  3230. void PxAirstrike::Message(CObject* sender, EMType Type, int MSize, CMessageData* MData)
  3231. {
  3232. // Drawing operations are done here
  3233. if(Type == M_DRAWQUEUE)
  3234. {
  3235. RenderPlane();
  3236. return;
  3237. }
  3238.  
  3239. super;
  3240.  
  3241. // This is run every frame
  3242. if(Type == M_FRAME)
  3243. {
  3244. if(ShouldPlaySound)
  3245. {
  3246. ShouldPlaySound = false;
  3247. PlaySound(Sound, 1, 1, 0);
  3248. }
  3249.  
  3250. FrameCounter = FrameCounter + 1;
  3251. if(FrameCounter >= FramesBetweenBombs)
  3252. {
  3253. FrameCounter = 0;
  3254. if(BombDrop > 0 && BombDrop <= NumBombs)
  3255. {
  3256. DropBomb();
  3257. }
  3258.  
  3259. BombDrop = BombDrop + 1;
  3260. }
  3261.  
  3262. PosX = PosX + SpX;
  3263. PosY = PosY + SpY;
  3264.  
  3265. if(Direction > 0 && PosX > GS->LevelSX + PlaneAppearXOffset)
  3266. {
  3267. Free(true);
  3268. }
  3269. else if(Direction < 0 && PosX < 0 - PlaneAppearXOffset)
  3270. {
  3271. Free(true);
  3272. }
  3273. }
  3274. }
  3275. PXS : Library Code :
  3276. require utils, pxparticles;
  3277.  
  3278. #WEAPON_BOWLINGBALL
  3279.  
  3280. CColMask* MASK_CIRCLE;
  3281. CSprite* bowlingballSprite;
  3282. CSprite* bowlingballsparkSprite;
  3283. CSprite* bowlingballglowSprite;
  3284. CLogFile* blog;
  3285.  
  3286. void bowlingball::FirstFrame()
  3287. {
  3288. MASK_CIRCLE = new CColMask(16, 16, MakeCircleMask(16));
  3289. }
  3290.  
  3291. // Loading resources
  3292. void bowlingball::InitGraphic()
  3293. {
  3294. CFile *f;
  3295. f = GetAttachment("bowling.png"); bowlingballSprite = LoadSprite(f, 1, 0);
  3296. f = GetAttachment("bowlingspark.png"); bowlingballsparkSprite = LoadSprite(f, 10, 0);
  3297. f = GetAttachment("lightning_glow.png"); bowlingballglowSprite = LoadSprite(f, 1, 0);
  3298. blog = new CLogFile("blog.txt");
  3299. }
  3300.  
  3301. CBowlingBall : CMine;
  3302.  
  3303. CBowlingBall::CBowlingBall(CObject* Parent, CShootDesc* Desc)
  3304. {
  3305. CMineParams MParams;
  3306. zero(&MParams);
  3307. MParams.Prefuse = 0;
  3308. MParams.Radius = 0;
  3309. MParams.Fuse = 70;
  3310. MParams.Flags = 0;
  3311. MParams.Bias = 0;
  3312. MParams.Damage = 0;
  3313. MParams.BlastPower = 0;
  3314.  
  3315. SetLayerOverride(LAYER_OILDRUM);
  3316.  
  3317. super(Parent, &MParams, Desc, false, 0);
  3318.  
  3319. //Layer = LAYER_OILDRUM;
  3320. ColGroup = CMASK_SKIMMING;
  3321.  
  3322. //BounceColMask = MASK_CIRCLE_SMALL;
  3323. //BounceColMask2 = ColMask;
  3324. BounceColMask = ColMask;
  3325. // BounceColMask = MASK_CIRCLE;
  3326. BounceColMask2 = MASK_PIXEL;
  3327. ColMask = MASK_CIRCLE;
  3328.  
  3329. // How much the physics object should bounce when colliding
  3330. PhysBounciness = 0.03;
  3331. // How much speed should be decreased when colliding
  3332. PhysFriction = 0.02;
  3333. // How much acceleration should be added on the X and Y axis
  3334. PhysInertiaX = 0.8;
  3335. PhysInertiaY = 0.4;
  3336.  
  3337. // The object will be put into "low speed" state when its speed goes below this value for a long time
  3338. LowSpeedThreshold = 4.0;
  3339. // How many frames the physics object should hold a low speed to be put into "low speed" state
  3340. TimeForLowSpeed = 100;
  3341.  
  3342. // Regular physics parameters will be replaced by those ones when in "low speed" state
  3343. LowSpeedBounciness = 0.03;
  3344. LowSpeedFriction = 0.03;
  3345. LowSpeedInertiaX = 0.0;
  3346. LowSpeedInertiaY = 0.0;
  3347.  
  3348. // Special physics parameters applied when the ball is in "electrified" state
  3349. ZappedBounciness = 0.03;
  3350. ZappedFriction = -0.05;
  3351. ZappedInertiaX = 0.8;
  3352. ZappedInertiaY = 0.4;
  3353.  
  3354. SleepDistanceThreshold = 2;
  3355. SleepSamplePeriod = 80;
  3356.  
  3357. // Multiplier for incoming force from guns and melee
  3358. GunForceMultiplier = 0.7;
  3359. // Multiplier for incoming force from explosions
  3360. ExplosionForceMultiplier = 1.0;
  3361.  
  3362. // The minimum velocity for the ball to start emitting flame effects after being thrown by an explosion
  3363. SpeedFlamesStartThreshold = 12.0;
  3364. // If the ball goes below this speed for such an amount of time, it will stop emitting flames
  3365. SpeedFlamesStopThreshold = 5.0;
  3366. SpeedFlamesStopDuration = 100;
  3367. SpeedFlamesStopTimer = 100;
  3368. SpeedFlames = false;
  3369. ThrownByExplosionTimeout = 20;
  3370. ThrownByExplosionTimer = 0;
  3371. ThrownByExplosion = false;
  3372.  
  3373. DefaultColGroup = CMASK_TERRAIN | CMASK_WORM_ON_TERRAIN | CMASK_WORM_FROZEN |
  3374. CMASK_CRATE | CMASK_DONORCARD | CMASK_OILDRUM;
  3375.  
  3376. NoWormsColGroup = CMASK_TERRAIN | CMASK_CRATE | CMASK_DONORCARD | CMASK_OILDRUM;
  3377.  
  3378. DamageableColGroup = CMASK_WORM_ON_TERRAIN | CMASK_WORM_USING_WEAPON | CMASK_WORM_IN_MIDAIR |
  3379. CMASK_WORM_ON_ROPE | CMASK_WORM_FROZEN | CMASK_MINE |
  3380. CMASK_CRATE | CMASK_DONORCARD | CMASK_OILDRUM;
  3381.  
  3382. NextDie = GS->Tick + 500;
  3383. Wtfboom = false;
  3384.  
  3385. LastSpX = SpX;
  3386. LastSpY = SpY;
  3387. LastPosX = PosX;
  3388. LastPosY = PosY;
  3389. RealSpX = 0.0;
  3390. RealSpY = 0.0;
  3391.  
  3392. Rotation = 0.0;
  3393. SpinMultiplierX = 0.06;
  3394. SpinMultiplierY = 0.02;
  3395. MaxSpinSpeed = 0.6;
  3396.  
  3397. MinPushSpeed = 4.0;
  3398. MinDamageSpeed = 4.0;
  3399. MaxDamageSpeed = 15.0;
  3400. DamageForceMultiplier = 0.7;
  3401. MinDamage = 5.0;
  3402. MaxDamage = 60.0;
  3403.  
  3404. Res = new CTraceRes;
  3405. First = true;
  3406. EnteredSolid = false;
  3407.  
  3408. LastRecordPosX = PosX;
  3409. LastRecordPosY = PosY;
  3410. SleepSampleTimer = 200;
  3411. LowSpeedTimer = 200;
  3412. IsAsleep = false;
  3413. IsLowSpeed = false;
  3414.  
  3415. //float r = GS->GetRandom()%1000;
  3416. ZPlane = 5;
  3417. ShakeAmplitude = 0.0;
  3418. ShakeFadeRate = 0.2;
  3419. //ZPlane = ZPlane + (r * 0.001);
  3420.  
  3421. NextRecalcZPlane = 0;
  3422. ClType = EObjectClass(71);
  3423.  
  3424. SparkAnimSpeed = 0.02;
  3425. SparkPauseDuration = 0.4;
  3426. SparkCycle = 0.0;
  3427. SparkCycleDuration = 1.0 + SparkPauseDuration;
  3428.  
  3429. ZapTurnsRemaining = 0;
  3430. GlowSize = 0.0;
  3431. }
  3432.  
  3433. void CBowlingBall::Free(bool b)
  3434. {
  3435. delete Res;
  3436. super;
  3437. }
  3438.  
  3439. void CBowlingBall::Collide(CGObject* Obj, int type)
  3440. {
  3441. }
  3442.  
  3443. void CBowlingBall::Zap(int zaptype)
  3444. {
  3445. float mul;
  3446.  
  3447. if(zaptype == 0)
  3448. {
  3449. ZapTurnsRemaining = 1;
  3450. mul = 1.0;
  3451. }
  3452. else
  3453. {
  3454. mul = 0.8;
  3455. }
  3456.  
  3457. Wake();
  3458.  
  3459. float ang = RandomFloat(-0.1, 0.1);
  3460. float speed = RandomFloat(5.0, 10.0);
  3461. SpX = sin(ang) * speed * mul;
  3462. SpY = -cos(ang) * speed * mul;
  3463. }
  3464.  
  3465. void CBowlingBall::DoAnimation()
  3466. {
  3467. if(ZapTurnsRemaining > 0)
  3468. {
  3469. SparkCycle = SparkCycle + SparkAnimSpeed;
  3470. if(SparkCycle > SparkCycleDuration) SparkCycle = SparkCycle - SparkCycleDuration;
  3471. }
  3472. }
  3473. void CBowlingBall::UpdateZPlane()
  3474. {
  3475. // Recalculate Z plane periodically to make sure objects are drawn properly when overlapping each other
  3476. if(NextRecalcZPlane <= 0)
  3477. {
  3478. local matches = 0;
  3479.  
  3480. for(local i = 1; i < Env->Objs.Count; i+=1)
  3481. {
  3482. local obj = Env->Objs.Objs[i];
  3483.  
  3484. if(obj == NullObj) continue;
  3485. if(obj == this) continue;
  3486. if(obj->ClType == EObjectClass(71))
  3487. {
  3488. local ball = CBowlingBall(obj);
  3489.  
  3490. float dX = ball->PosX - PosX;
  3491. float dY = ball->PosY - PosY;
  3492. float r2 = dX*dX + dY*dY;
  3493.  
  3494. if(r2 < 900.0)
  3495. {
  3496. if(ball->ZPlane == ZPlane)
  3497. {
  3498. ball->ZPlane = ball->ZPlane + 1;
  3499. }
  3500. matches = matches + 1;
  3501. }
  3502. }
  3503. }
  3504.  
  3505. if(matches == 0) ZPlane = 5;
  3506.  
  3507. NextRecalcZPlane = 200;
  3508. }
  3509. else
  3510. {
  3511. NextRecalcZPlane = NextRecalcZPlane - 1;
  3512. }
  3513. }
  3514.  
  3515. void CBowlingBall::UpdateRotation()
  3516. {
  3517. float abs_speedX = RealSpX;
  3518. float abs_speedY = RealSpY;
  3519.  
  3520. if(abs_speedX < 0) abs_speedX = 0-abs_speedX;
  3521. if(abs_speedY < 0) abs_speedY = 0-abs_speedY;
  3522.  
  3523. float rot = SpinMultiplierX * abs_speedX + SpinMultiplierY * abs_speedY;
  3524.  
  3525. if(rot > MaxSpinSpeed) rot = MaxSpinSpeed;
  3526. if(RealSpX<0) rot = 0-rot;
  3527.  
  3528. ApplyRotation(rot);
  3529. }
  3530.  
  3531. void CBowlingBall::ApplyRotation(float r)
  3532. {
  3533. Rotation += r;
  3534. while(Rotation > 3.141593) Rotation -= 6.283186;
  3535. while(Rotation <= 0 - 3.141593) Rotation += 6.283186;
  3536. }
  3537.  
  3538. void CBowlingBall::TakeExplosionDamage(fixed x, fixed y, int dmg)
  3539. {
  3540. if(dmg == 0) return;
  3541.  
  3542. float fdmg = dmg;
  3543. float dx = PosX - x;
  3544. float dy = PosY - y;
  3545.  
  3546. float distsqr = dx*dx + dy*dy;
  3547. float fdmgsqr = fdmg*fdmg*1.25*1.25;
  3548.  
  3549. fdmg = (1.0-distsqr/fdmgsqr) * fdmg;
  3550. dmg = fdmg;
  3551.  
  3552. if(dmg > 0) TakeDamage(0, dmg);
  3553. }
  3554.  
  3555. void CBowlingBall::TakeDamage(int type, int dmg)
  3556. {
  3557. //if(type == 10)
  3558. //{
  3559. // fixed fdmg = dmg;
  3560. // fdmg = Health * fdmg / 100.0;
  3561. // dmg = fdmg;
  3562. //}
  3563.  
  3564. //Health -= dmg;
  3565. Wake();
  3566. }
  3567.  
  3568. void CBowlingBall::Sleep()
  3569. {
  3570. if(IsAsleep) return;
  3571. IsAsleep = true;
  3572. IsLowSpeed = false;
  3573. //IsMaterial = true;
  3574. SleepX = PosX;
  3575. SleepY = PosY;
  3576. SpeedDivider = 1000;
  3577. SpeedDividerB = 1000;
  3578. SpX = 0.0;
  3579. SpY = 0.0;
  3580. GravityFactor = 0.0;
  3581. Stopped = 1;
  3582. InMidAir = 0;
  3583. ThrownByExplosion = false;
  3584. SpeedFlames = false;
  3585. }
  3586.  
  3587. void CBowlingBall::Wake()
  3588. {
  3589. if(IsAsleep == false && IsLowSpeed == false) return;
  3590. IsAsleep = false;
  3591. IsLowSpeed = false;
  3592. //IsMaterial = false;
  3593. SleepX = 0;
  3594. SleepY = 0;
  3595. SpeedDivider = 1;
  3596. SpeedDividerB = 1;
  3597. GravityFactor = 1.0;
  3598. Stopped = 0;
  3599. InMidAir = 1;
  3600. SleepSampleTimer = 200;
  3601. LowSpeedTimer = 200;
  3602. }
  3603.  
  3604. void CBowlingBall::Render()
  3605. {
  3606. bool hascolormod = false;
  3607.  
  3608. if(Sinking)
  3609. {
  3610. hascolormod = true;
  3611. SetColorMod(RGB(90, 90, 240), 6);
  3612. }
  3613.  
  3614. //else if(IsAsleep)
  3615. //{
  3616. // hascolormod = true;
  3617. // SetColorMod(RGB(0, 255, 0), 6);
  3618. //}
  3619. //else if(IsLowSpeed)
  3620. //{
  3621. // hascolormod = true;
  3622. // SetColorMod(RGB(255, 180, 0), 6);
  3623. //}
  3624.  
  3625. AddSpriteEx(ZPlane+0.01, PosX, PosY, bowlingballSprite->Index, 0, Rotation, 1);
  3626.  
  3627. if(hascolormod) ClearColorMod();
  3628.  
  3629. if(Sinking == false && ZapTurnsRemaining > 0)
  3630. {
  3631. CQuad q;
  3632. int j;
  3633.  
  3634. // Glow effect
  3635. FillSpriteQuad(&q, bowlingballglowSprite->Index, 0, 0);
  3636. TransformQuad(&q, 0, GlowSize, GlowSize, PosX, PosY);
  3637. q.blend = 1;
  3638. for(j=0 ; j<4 ; j+=1) q.v[j].color = RGB(80,110,128);
  3639.  
  3640. for(j=0 ; j<3 ; j+=1)
  3641. AddSpriteQ(ZPlane+0.02, &q, bowlingballglowSprite->Index, 0, 64);
  3642.  
  3643. if(SparkCycle <= 1.0)
  3644. {
  3645. // Spark effect
  3646. FillSpriteQuad(&q, bowlingballsparkSprite->Index, 0, 0);
  3647. TransformQuad(&q, Rotation, 1, 1, PosX, PosY);
  3648. q.blend = 1;
  3649. for(j=0 ; j<4 ; j+=1) q.v[j].color = RGB(255,255,255);
  3650. AddSpriteQ(ZPlane, &q, bowlingballsparkSprite->Index, SparkCycle, 64);
  3651. }
  3652. }
  3653.  
  3654. if(EnteredSolid)
  3655. {
  3656. AddSpriteEx(9, PosX, PosY, 2, 0, 0, 1);
  3657. }
  3658. }
  3659.  
  3660. void CBowlingBall::ProcessBallOnBallCollision(float Speed)
  3661. {
  3662. CGObject *obj;
  3663.  
  3664. for(int i = 0; i < Env->Objs.Count; i += 1)
  3665. {
  3666. obj = CGObject(Env->Objs.Objs[i]);
  3667. if(obj == this) continue;
  3668. if(obj == NullObj) continue;
  3669.  
  3670.  
  3671. if(obj->ClType == ClType)
  3672. {
  3673. if(ColMask->Check(PosX, PosY, obj->ColMask, obj->PosX, obj->PosY))
  3674. {
  3675. float ForceX = obj->PosX - PosX;
  3676. float ForceY = obj->PosY - PosY;
  3677. float dist = sqrt(ForceX*ForceX + ForceY*ForceY);
  3678.  
  3679. if(dist > 0)
  3680. {
  3681. ForceX = 0.6*sqrt(Speed) * ForceX / dist;
  3682. ForceY = 0.6*sqrt(Speed) * ForceY / dist;
  3683.  
  3684. CMessageData msg;
  3685. msg.params[0] = 0;
  3686. msg.fparams[1] = PosX;
  3687. msg.fparams[2] = PosY;
  3688. msg.fparams[3] = ForceX;
  3689. msg.fparams[4] = ForceY;
  3690. msg.params[5] = 1;
  3691. msg.params[6] = 0;
  3692.  
  3693. obj->Message(this, M_GUNEXP, 1032, &msg);
  3694. }
  3695. }
  3696. }
  3697. }
  3698. }
  3699.  
  3700. void CBowlingBall::ProcessBallOnOtherCollision(float Speed)
  3701. {
  3702. CGObject *obj;
  3703. float dmg = Speed;
  3704.  
  3705. if(dmg>MaxDamageSpeed) dmg = MaxDamageSpeed;
  3706. dmg = MinDamage + (MaxDamage - MinDamage) * (dmg - MinDamageSpeed) / (MaxDamageSpeed - MinDamageSpeed);
  3707.  
  3708. for(int i = 0; i < Env->Objs.Count; i += 1)
  3709. {
  3710. obj = CGObject(Env->Objs.Objs[i]);
  3711. if(obj == this) continue;
  3712. if(obj == NullObj) continue;
  3713. if(obj->IsMaterial == false) continue;
  3714.  
  3715. if(ColMask->Check(PosX, PosY, obj->ColMask, obj->PosX, obj->PosY))
  3716. {
  3717. blog->Write("AAAD3");
  3718. float damage = 0;
  3719.  
  3720. if(obj->ClType == OC_Worm)
  3721. {
  3722. local worm = CWorm(obj);
  3723.  
  3724. if(worm->DamageRecoverTime <= 0)
  3725. {
  3726. if(obj->ObjState == WS_IDLE) damage = dmg;
  3727. if(obj->ObjState == WS_SLIDING) damage = dmg;
  3728. if(obj->ObjState == WS_WALKING) damage = dmg;
  3729. if(obj->ObjState == WS_AIMING) damage = dmg;
  3730. if(obj->ObjState == WS_FIRED) damage = dmg;
  3731. if(obj->ObjState == WS_FIRECONT) damage = dmg;
  3732. if(obj->ObjState == WS_DRILLING) damage = dmg;
  3733. if(obj->ObjState == WS_CONTROL_WEAPON) damage = dmg;
  3734. if(obj->ObjState == WS_SETPOWER) damage = dmg;
  3735. if(obj->ObjState == WS_JUMPPREPARE) damage = dmg;
  3736. if(obj->ObjState == WS_FROZEN) damage = dmg;
  3737. if(obj->ObjState == WS_POWERFLY) damage = dmg;
  3738. if(obj->ObjState == WS_FLYING) damage = dmg;
  3739. if(obj->ObjState == WS_FLYING2) damage = dmg;
  3740. if(obj->ObjState == WS_FLYING2) damage = dmg;
  3741. if(obj->ObjState == WS_JETPACK) damage = dmg;
  3742. if(obj->ObjState == WS_PARACHUTE) damage = dmg;
  3743. if(obj->ObjState == WS_JUMP) damage = dmg;
  3744. if(obj->ObjState == WS_ROPING) damage = dmg;
  3745. if(obj->ObjState == WS_BUNGEE) damage = dmg;
  3746.  
  3747. worm->DamageRecoverTime = 12;
  3748. }
  3749. }
  3750. else if(obj->ClType == OC_Mine)
  3751. {
  3752. damage = dmg;
  3753. }
  3754. else if(obj is CMagnet)
  3755. {
  3756. damage = dmg;
  3757. }
  3758. else if(obj->ClType == EObjectClass(73))
  3759. {
  3760. damage = dmg;
  3761. }
  3762. else if(obj->ClType == OC_OilDrum)
  3763. {
  3764. damage = 100;
  3765. }
  3766. else if(obj->ClType == OC_Crate)
  3767. {
  3768. damage = 100;
  3769. }
  3770.  
  3771. if(damage > 0)
  3772. {
  3773. float ForceX = RealSpX;
  3774. float ForceY = RealSpY;
  3775. float ForceXAbs = ForceX;
  3776. bool crushed = false;
  3777.  
  3778. if(ForceX < 0) ForceXAbs = 0-ForceXAbs;
  3779.  
  3780. if(obj->ClType == OC_Worm)
  3781. {
  3782. bool crushable = false;
  3783. if(obj->ObjState == WS_IDLE) crushable = true;
  3784. if(obj->ObjState == WS_WALKING) crushable = true;
  3785. if(obj->ObjState == WS_AIMING) crushable = true;
  3786. if(obj->ObjState == WS_FIRED) crushable = true;
  3787. if(obj->ObjState == WS_FIRECONT) crushable = true;
  3788. if(obj->ObjState == WS_CONTROL_WEAPON) crushable = true;
  3789. if(obj->ObjState == WS_SETPOWER) crushable = true;
  3790. if(obj->ObjState == WS_JUMPPREPARE) crushable = true;
  3791.  
  3792. if(crushable && ForceY > MinDamageSpeed)
  3793. {
  3794. if(ForceXAbs / ForceY < 0.2)
  3795. {
  3796. ForceX = 0;
  3797. ForceY = 10;
  3798. crushed = true;
  3799. }
  3800. }
  3801. }
  3802.  
  3803. if(crushed==false)
  3804. {
  3805. if(ForceY < 0)
  3806. {
  3807. ForceY = ForceY - ForceXAbs;
  3808. }
  3809. else
  3810. {
  3811. ForceY = ForceY - 2*ForceXAbs;
  3812. }
  3813. ForceX = ForceX * DamageForceMultiplier;
  3814. ForceY = ForceY * DamageForceMultiplier;
  3815. }
  3816.  
  3817. CMessageData msg;
  3818. msg.params[0] = 0;
  3819. msg.fparams[1] = PosX;
  3820. msg.fparams[2] = PosY;
  3821. msg.fparams[3] = ForceX;
  3822. msg.fparams[4] = ForceY;
  3823. msg.params[5] = damage;
  3824. msg.params[6] = 0;
  3825.  
  3826. obj->Message(this, M_GUNEXP, 1032, &msg);
  3827.  
  3828. local p = new PxParticle(81, PosX, PosY);
  3829. p->SetLifeTime(15);
  3830. p->SetVelocity(0,0);
  3831. p->SetStartAlpha(255);
  3832. p->SetEndAlpha(255);
  3833.  
  3834. if(crushed)
  3835. {
  3836. PlayLocalSound(33, 5, 1.0, 1.0);
  3837. }
  3838. else
  3839. {
  3840. PlayLocalSound(101, 5, 1.0, 1.0);
  3841. }
  3842. }
  3843. }
  3844. }
  3845. }
  3846.  
  3847. void CBowlingBall::PhysicsThink()
  3848. {
  3849. if(IsAsleep)
  3850. {
  3851. PosX = SleepX;
  3852. PosY = SleepY;
  3853. RealSpX = 0.0;
  3854. RealSpY = 0.0;
  3855. SpX = 0.0;
  3856. SpY = 0.0;
  3857. Stopped = 1;
  3858. InMidAir = 0;
  3859. }
  3860. else
  3861. {
  3862. float Speed = sqrt(RealSpX*RealSpX + RealSpY*RealSpY);
  3863.  
  3864. fixed SpX2 = SpX;
  3865. fixed SpY2 = SpY + Env->Gravity;
  3866.  
  3867. float bounciness;
  3868. float friction;
  3869. float inertiaX;
  3870. float inertiaY;
  3871.  
  3872. if(IsLowSpeed)
  3873. {
  3874. bounciness = LowSpeedBounciness;
  3875. friction = LowSpeedFriction;
  3876. inertiaX = LowSpeedInertiaX;
  3877. inertiaY = LowSpeedInertiaY;
  3878. }
  3879. else if(ZapTurnsRemaining > 0)
  3880. {
  3881. bounciness = ZappedBounciness;
  3882. friction = ZappedFriction;
  3883. inertiaX = ZappedInertiaX;
  3884. inertiaY = ZappedInertiaY;
  3885. }
  3886. else
  3887. {
  3888. bounciness = PhysBounciness;
  3889. friction = PhysFriction;
  3890. inertiaX = PhysInertiaX;
  3891. inertiaY = PhysInertiaY;
  3892. }
  3893.  
  3894. if(SpX2 == 0)
  3895. {
  3896. if(SpY2 == 0)
  3897. {
  3898. SpY2 = SpY + 0.1;
  3899. }
  3900. }
  3901.  
  3902. // Collision detection
  3903. if(Speed > MinDamageSpeed)
  3904. {
  3905. // Enough speed for knocking stuff out of the way, ignore worms
  3906. TraceMaskEx(this, BounceColMask, PosX, PosY, PosX + SpX2, PosY + SpY2, NoWormsColGroup, Res);
  3907. }
  3908. else
  3909. {
  3910. // Regular traces, takes anything solid into consideration
  3911. TraceMaskEx(this, BounceColMask, PosX, PosY, PosX + SpX2, PosY + SpY2, DefaultColGroup, Res);
  3912. }
  3913. if(Res->StartsSolid)
  3914. {
  3915. TraceMaskEx(this, BounceColMask, PosX, PosY, PosX + SpX2, PosY + SpY2, NoWormsColGroup, Res);
  3916. if(Res->StartsSolid)
  3917. {
  3918. // The object is stuck inside something solid, try to unblock it
  3919. TraceMaskEx(this, BounceColMask, PosX, PosY, PosX - 8 * SpX2, PosY - 8 * SpY2, NoWormsColGroup, Res);
  3920. TraceMaskEx(this, BounceColMask, Res->LeftSolidX, Res->LeftSolidY, Res->LeftSolidX + 8 * SpX2, Res->LeftSolidY + 8 * SpY2, NoWormsColGroup, Res);
  3921. }
  3922. }
  3923.  
  3924. // Couldn't unblock it :(
  3925. if(Res->StartsSolid)
  3926. {
  3927. TraceMaskEx(this, BounceColMask2, PosX, PosY, PosX - 8 * SpX2, PosY - 8 * SpY2, NoWormsColGroup, Res);
  3928. TraceMaskEx(this, BounceColMask2, Res->LeftSolidX, Res->LeftSolidY, Res->LeftSolidX + 8 * SpX2, Res->LeftSolidY + 8 * SpY2, NoWormsColGroup, Res);
  3929. if(Res->StartsSolid)
  3930. {
  3931. //EnteredSolid = true;
  3932. //SpY = SpY - 4.0;
  3933. Sleep();
  3934. }
  3935. }
  3936.  
  3937. // Collision processing
  3938. if(Res->Hit)
  3939. {
  3940. First = false;
  3941. // Calculating tangent and normal initial forces
  3942. float SpT = (SpX2 * Res->TangentX) + (SpY2 * Res->TangentY);
  3943. float SpN = (SpX2 * Res->NormalX ) + (SpY2 * Res->NormalY );
  3944.  
  3945. // Move the object 1 pixel away from the collision point
  3946. PosX = Res->PreHitX;
  3947. PosY = Res->PreHitY;
  3948.  
  3949. // Calculating bounciness and friction forces
  3950. float ForceX = 0 - SpN * Res->NormalX * (bounciness + 1.0) - SpT * Res->TangentX * friction;
  3951. float ForceY = 0 - SpN * Res->NormalY * (bounciness + 1.0) - SpT * Res->TangentY * friction;
  3952.  
  3953. // Calculating work of the resulting force relative to the current speed
  3954. float W = (ForceX * SpX2) + (ForceY * SpY2);
  3955. if(W < -10.0)
  3956. {
  3957. // Negative work, the object has been brutally stopped, shake the screen to give more intensity to the impact
  3958. float shake = 0 - W;
  3959. if(shake > 50.0) shake = 50.0;
  3960. shake = shake * 0.1;
  3961. if(shake > ShakeAmplitude)
  3962. {
  3963. GS->ShakeX = GS->ShakeX + (shake - ShakeAmplitude);
  3964. GS->ShakeY = GS->ShakeY + (shake - ShakeAmplitude);
  3965. ShakeAmplitude = shake;
  3966. }
  3967. }
  3968.  
  3969. SpX = SpX + ForceX;
  3970. SpY = SpY + ForceY;
  3971.  
  3972. float sp = Speed;
  3973. if(sp > 1.5)
  3974. {
  3975. for(int i=0 ; i<4 ; i+=1)
  3976. {
  3977. local p = new PxParticle(80, PosX, PosY);
  3978. p->SetLifeTime(30);
  3979. p->SetRandomVelocity(sp*0.5, sp*1.2);
  3980. p->SetAirResistance(0.5);
  3981. p->SetStartAlpha(255);
  3982. p->SetEndAlpha(255);
  3983. }
  3984. }
  3985. }
  3986.  
  3987. SpX = SpX + inertiaX * (SpX - LastSpX);
  3988. SpY = SpY + inertiaY * (SpY - LastSpY);
  3989. RealSpX = PosX - LastPosX;
  3990. RealSpY = PosY - LastPosY;
  3991.  
  3992. // Should solve an issue where the object keeps rolling on a perfectly horizontal surface,
  3993. // even though friction should prevent it from doing so
  3994. if(IsLowSpeed)
  3995. {
  3996. if(RealSpY > -1.0)
  3997. {
  3998. if(RealSpY < 1.0)
  3999. {
  4000. if(SpX > -1.0)
  4001. {
  4002. if(SpX < 0.0) SpX = 0;
  4003. }
  4004. }
  4005. }
  4006. }
  4007.  
  4008. LastPosX = PosX;
  4009. LastPosY = PosY;
  4010. LastSpX = SpX;
  4011. LastSpY = SpY;
  4012.  
  4013. if(ThrownByExplosion)
  4014. {
  4015. if(SpeedFlames)
  4016. {
  4017. if(Speed < SpeedFlamesStopThreshold)
  4018. {
  4019. SpeedFlamesStopTimer = SpeedFlamesStopTimer - 1;
  4020. if(SpeedFlamesStopTimer <= 0)
  4021. {
  4022. SpeedFlames = false;
  4023. }
  4024. }
  4025. else
  4026. {
  4027. SpeedFlamesStopTimer = SpeedFlamesStopDuration;
  4028. }
  4029. }
  4030. else
  4031. {
  4032. if(Speed > SpeedFlamesStartThreshold)
  4033. {
  4034. SpeedFlamesStopTimer = SpeedFlamesStopDuration;
  4035. SpeedFlames = true;
  4036. }
  4037. ThrownByExplosionTimer = ThrownByExplosionTimer - 1;
  4038. if(ThrownByExplosionTimer <= 0)
  4039. {
  4040. ThrownByExplosion = false;
  4041. }
  4042. }
  4043. }
  4044. if(Speed > MinPushSpeed)
  4045. {
  4046. ProcessBallOnBallCollision(Speed);
  4047. }
  4048.  
  4049. if(Speed > MinDamageSpeed)
  4050. {
  4051. ProcessBallOnOtherCollision(Speed);
  4052. }
  4053. if(Speed < LowSpeedThreshold)
  4054. {
  4055. LowSpeedTimer = LowSpeedTimer - 1;
  4056. if(LowSpeedTimer <= 0)
  4057. {
  4058. //local p = new PxParticle(81, PosX, PosY);
  4059. //p->SetLifeTime(30);
  4060. //p->SetVelocity(0,0);
  4061. //p->SetStartAlpha(255);
  4062. //p->SetEndAlpha(255);
  4063. IsLowSpeed = true;
  4064. LowSpeedTimer = TimeForLowSpeed;
  4065. }
  4066. }
  4067. else
  4068. {
  4069. LowSpeedTimer = TimeForLowSpeed;
  4070. IsLowSpeed = false;
  4071. }
  4072.  
  4073. SleepSampleTimer = SleepSampleTimer - 1;
  4074. if(SleepSampleTimer <= 0)
  4075. {
  4076. //local p = new PxParticle(79, PosX, PosY);
  4077. //p->SetLifeTime(30);
  4078. //p->SetVelocity(0,0);
  4079. //p->SetStartAlpha(255);
  4080. //p->SetEndAlpha(255);
  4081.  
  4082. float dx = PosX - LastRecordPosX;
  4083. float dy = PosY - LastRecordPosY;
  4084. float dist = sqrt(dx*dx+dy*dy);
  4085.  
  4086. if(dist < SleepDistanceThreshold) Sleep();
  4087.  
  4088. SleepSampleTimer = SleepSamplePeriod;
  4089. LastRecordPosX = PosX;
  4090. LastRecordPosY = PosY;
  4091. }
  4092. }
  4093. }
  4094.  
  4095. void CBowlingBall::DoTrailEffects()
  4096. {
  4097. local p0 = PxParticle(NullObj);
  4098. float s0;
  4099. float s1;
  4100.  
  4101. if(IsAsleep == false && IsLowSpeed == false)
  4102. {
  4103. // Regular trail
  4104. p0 = new PxParticle(bowlingballglowSprite->Index, PosX, PosY);
  4105. p0->SetBlendMode(1);
  4106. p0->SetStartColor(45,10,4);
  4107. p0->SetEndColor(0,0,0);
  4108. p0->SetLifeTime(15);
  4109. p0->SetRandomVelocity(0, 0);
  4110. p0->SetAirResistance(0);
  4111. p0->SetAlpha(255);
  4112. p0->SetStartSize(0.3,0.3);
  4113. p0->SetEndSize(0.35,0.35);
  4114. }
  4115.  
  4116. // Electrified ball
  4117. GlowSize = RandomFloat(0.5, 0.9);
  4118. if(ZapTurnsRemaining > 0 && (IsAsleep == false))
  4119. {
  4120. s0 = RandomFloat(0.2,0.3);
  4121. s1 = RandomFloat(0.4,0.5);
  4122.  
  4123. p0 = new PxParticle(bowlingballglowSprite->Index, PosX, PosY);
  4124. p0->SetBlendMode(1);
  4125. p0->SetStartColor(80,110,128);
  4126. p0->SetEndColor(0,0,0);
  4127. p0->SetLifeTime(30);
  4128. p0->SetRandomVelocity(0, 0.3);
  4129. p0->SetAirResistance(0.0);
  4130. p0->SetAlpha(255);
  4131. p0->SetStartSize(0.3,0.3);
  4132. p0->SetEndSize(0.5,0.5);
  4133. }
  4134. // Fire trail when the ball is thrown by an explosion
  4135. else if(ThrownByExplosion && (IsAsleep == false))
  4136. {
  4137. if(SpeedFlames)
  4138. {
  4139. s0 = RandomFloat(0.1, 0.2);
  4140. s1 = RandomFloat(0.05, 0.1);
  4141.  
  4142. p0 = new PxParticle(bowlingballglowSprite->Index, PosX, PosY);
  4143. p0->SetBlendMode(1);
  4144. p0->SetStartColor(160,RandomInt(30,160),10);
  4145. p0->SetEndColor(0,0,0);
  4146. p0->SetLifeTime(20);
  4147. p0->SetRandomVelocity(0, 0.3);
  4148. p0->SetAirResistance(0);
  4149. p0->SetAlpha(255);
  4150. p0->SetStartSize(s0,s0);
  4151. p0->SetEndSize(s1,s1);
  4152. }
  4153. }
  4154. }
  4155.  
  4156. void CBowlingBall::Message(CObject* sender, EMType Type, int MSize, CMessageData* MData)
  4157. {
  4158. if(Wtfboom) return;
  4159.  
  4160. if(Type == M_EXPLOSION)
  4161. {
  4162. TakeExplosionDamage(MData->fparams[1], MData->fparams[2], MData->params[4]);
  4163. ThrownByExplosion = true;
  4164. ThrownByExplosionTimer = ThrownByExplosionTimeout;
  4165. float force = MData->params[3];
  4166. force = force * ExplosionForceMultiplier;
  4167. MData->params[3] = force;
  4168. }
  4169. if(Type == M_GUNEXP)
  4170. {
  4171. TakeDamage(MData->params[0], MData->params[5]);
  4172. MData->params[3] = MData->params[3] * GunForceMultiplier;
  4173. MData->params[4] = MData->params[4] * GunForceMultiplier;
  4174. }
  4175.  
  4176. if(Type==M_FRAME)
  4177. {
  4178. if(ShakeAmplitude > 0)
  4179. {
  4180. ShakeAmplitude = ShakeAmplitude - ShakeFadeRate; if(ShakeAmplitude < 0) ShakeAmplitude = 0;
  4181. GS->ShakeX = GS->ShakeX - ShakeFadeRate; if(GS->ShakeX < 0) GS->ShakeX = 0;
  4182. GS->ShakeY = GS->ShakeY - ShakeFadeRate; if(GS->ShakeY < 0) GS->ShakeY = 0;
  4183. }
  4184.  
  4185. if(Sinking==false)
  4186. {
  4187. DoAnimation();
  4188. UpdateRotation();
  4189. PhysicsThink();
  4190. DoTrailEffects();
  4191. }
  4192. }
  4193.  
  4194. if(Type==M_DRAWQUEUE)
  4195. {
  4196. Render();
  4197. return;
  4198. }
  4199.  
  4200. super;
  4201.  
  4202. if(Type == M_FRAME)
  4203. {
  4204. if(Wtfboom) Free(true);
  4205. }
  4206. }
  4207.  
  4208. override CWorm::CWorm(CObject* Parent, int aTeam, int aIndex, CWormParams* params)
  4209. {
  4210. super;
  4211. DamageRecoverTime = 0;
  4212. }
  4213.  
  4214. override void CWorm::Message(CObject* sender, EMType Type, int MSize, CMessageData* MData)
  4215. {
  4216. if(Type == M_FRAME)
  4217. {
  4218. if(DamageRecoverTime > 0) DamageRecoverTime = DamageRecoverTime - 1;
  4219. }
  4220.  
  4221. super;
  4222. }
  4223.  
  4224. override void CWorm::FireFinal(CWeapon* Weap, CShootDesc* Desc)
  4225. {
  4226. if(Weap->CheckName("Bowling Ball"))
  4227. {
  4228. CShootDesc SDesc;
  4229. zero(&SDesc);
  4230.  
  4231. local BaseForceX = 0.4;
  4232. local BaseForceY = 0.8;
  4233.  
  4234. SDesc.Team = WormTeam;
  4235. SDesc.X = PosX;
  4236. SDesc.Y = PosY;
  4237. SDesc.SpX = (0.5 * SpX) + TurnSide * BaseForceX;
  4238. SDesc.SpY = (0.5 * SpY) - BaseForceY;
  4239.  
  4240. DamageRecoverTime = 50;
  4241. new CBowlingBall(GetObject(25, 0), &SDesc);
  4242. }
  4243. else if(Weap->CheckName("Earth Quake"))
  4244. {
  4245. CGObject *obj;
  4246. CBowlingBall *ball;
  4247. for(int i = 0; i < Env->Objs.Count; i += 1)
  4248. {
  4249. obj = CGObject(Env->Objs.Objs[i]);
  4250. if(obj == NullObj) continue;
  4251.  
  4252. if(obj->ClType == EObjectClass(71))
  4253. {
  4254. ball = CBowlingBall(obj);
  4255. ball->Wake();
  4256. }
  4257. }
  4258. super;
  4259. }
  4260. else
  4261. {
  4262. super;
  4263. }
  4264. }
  4265. PXS : Library Code :
  4266. require pxairstrike;
  4267.  
  4268. PxAirstrikeParams *BowlingBallStrikeParams;
  4269.  
  4270. void bbstrike::FirstFrame()
  4271. {
  4272. BowlingBallStrikeParams = new PxAirstrikeParams;
  4273. BowlingBallStrikeParams->SpeedCompensation = 2.5;
  4274. }
  4275.  
  4276. ///////////////////////////////////////////////////
  4277. // PxBowlingBallStrike
  4278.  
  4279. PxBowlingBallStrike : PxAirstrike
  4280.  
  4281. PxBowlingBallStrike::PxBowlingBallStrike(CObject* Parent, CShootDesc* Desc, PxAirstrikeParams* Params)
  4282. {
  4283. super;
  4284. }
  4285.  
  4286. void PxBowlingBallStrike::DropBomb()
  4287. {
  4288. CShootDesc SDesc;
  4289. zero(&SDesc);
  4290.  
  4291. SDesc.Team = Team;
  4292. SDesc.X = PosX;
  4293. SDesc.Y = PosY;
  4294.  
  4295. SDesc.SpX = BombSpX;
  4296. SDesc.SpY = BombSpY;
  4297.  
  4298. new CBowlingBall(GetObject(25, 0), &SDesc);
  4299. }
  4300.  
  4301. void PxBowlingBallStrike::RenderPlane()
  4302. {
  4303. super;
  4304. }
  4305.  
  4306. ///////////////////////////////////////////////////
  4307. // CWorm overrides
  4308.  
  4309. override void CWorm::FireFinal(CWeapon* Weap, CShootDesc* Desc)
  4310. {
  4311. if(Weap->CheckName("Bowling Ball Strike"))
  4312. {
  4313. BowlingBallStrikeParams->NumBombs = 3;
  4314. BowlingBallStrikeParams->BombDistance = 48;
  4315. BowlingBallStrikeParams->BombSpX = 5;
  4316. BowlingBallStrikeParams->BombSpY = 0;
  4317. new PxBowlingBallStrike(GetObject(25, 0), Desc, BowlingBallStrikeParams);
  4318. }
  4319. else
  4320. {
  4321. super;
  4322. }
  4323. }
  4324. PXS : Library Code :
  4325. require utils, pxparticles, wp_bowlingball;
  4326.  
  4327. #WEAPON_MAGNET
  4328.  
  4329. CSprite* magnetSprite;
  4330. CSprite* magnetSprite2;
  4331. CSprite* magnetDamagedSprite;
  4332. CSprite* magnetDamagedSprite2;
  4333.  
  4334. CSprite* magnetRingSprite;
  4335. CSprite* magnetRingSprite2;
  4336.  
  4337. CSprite* magnetSparks;
  4338.  
  4339. CSprite* magmissileSprite;
  4340. CSprite* magmissileSprite2;
  4341.  
  4342. CSprite* wmaglnk;
  4343. CSprite* wmaglnku;
  4344. CSprite* wmaglnkd;
  4345. CSprite* wmag2lnk;
  4346. CSprite* wmag2lnku;
  4347. CSprite* wmag2lnkd;
  4348.  
  4349. CMagnet : CMine;
  4350.  
  4351. CMagnetResult::CMagnetResult()
  4352. {
  4353. ForceX = float(0.0);
  4354. ForceY = float(0.0);
  4355. IsNull = true;
  4356. }
  4357.  
  4358. void CMagnetResult::Reset()
  4359. {
  4360. ForceX = float(0.0);
  4361. ForceY = float(0.0);
  4362. IsNull = true;
  4363. }
  4364.  
  4365. CMagnetResult *MagnetInternalResult;
  4366.  
  4367. //CBitmap32* AnimDebugBitmap;
  4368. //string AnimDebugText;
  4369.  
  4370. // Loading resources
  4371. void magnet::InitGraphic()
  4372. {
  4373. CFile *f;
  4374.  
  4375. f = GetAttachment("magnet.png"); magnetSprite = LoadSprite(f, 1, 0);
  4376. f = GetAttachment("magnet2.png"); magnetSprite2 = LoadSprite(f, 1, 0);
  4377. f = GetAttachment("magnet_damaged.png"); magnetDamagedSprite = LoadSprite(f, 1, 0);
  4378. f = GetAttachment("magnet2_damaged.png"); magnetDamagedSprite2 = LoadSprite(f, 1, 0);
  4379. f = GetAttachment("ring_in.png"); magnetRingSprite = LoadSprite(f, 1, 0);
  4380. f = GetAttachment("ring_out.png"); magnetRingSprite2 = LoadSprite(f, 1, 0);
  4381. f = GetAttachment("magnetsparks.png"); magnetSparks = LoadSprite(f, 10, 0);
  4382. f = GetAttachment("magmissile.png"); magmissileSprite = LoadSprite(f, 1, 0);
  4383. f = GetAttachment("magmissile2.png"); magmissileSprite2 = LoadSprite(f, 1, 0);
  4384.  
  4385. // note to entuser and self: the third parameter isn't actually flags, it's the framerate of the sprite
  4386. // also those deploy animation sprites need to be loaded in a precise order (normal, up, down)
  4387. f = GetAttachment("wmaglnk.png"); wmaglnk = LoadSprite(f, 10, 24);
  4388. f = GetAttachment("wmaglnku.png"); wmaglnku = LoadSprite(f, 10, 24);
  4389. f = GetAttachment("wmaglnkd.png"); wmaglnkd = LoadSprite(f, 10, 24);
  4390.  
  4391. f = GetAttachment("wmag2lnk.png"); wmag2lnk = LoadSprite(f, 10, 24);
  4392. f = GetAttachment("wmag2lnku.png"); wmag2lnku = LoadSprite(f, 10, 24);
  4393. f = GetAttachment("wmag2lnkd.png"); wmag2lnkd = LoadSprite(f, 10, 24);
  4394.  
  4395. //AnimDebugBitmap = MakeBitmap(300,36);
  4396. //AnimDebugText = "geez";
  4397. }
  4398.  
  4399. void magnet::FirstFrame()
  4400. {
  4401. local envfilter = CFilter(Root->GetObject(25, 0));
  4402. envfilter->Allow(M_TURNEND);
  4403.  
  4404. MagnetInternalResult = new CMagnetResult();
  4405. }
  4406.  
  4407. ///////////////////////////////////////////////////
  4408. // CMagnet class
  4409.  
  4410. CMagnet::CMagnet(CObject* Parent, CShootDesc* Desc, int WormDir, int Pol)
  4411. {
  4412. WormTurnSide = WormDir;
  4413.  
  4414. // Maximum distance in which objects can be affected by the magnet
  4415. MaxRange = 170.0;
  4416.  
  4417. // Maximum acceleration the magnet can apply
  4418. MaxForce = 12.0;
  4419.  
  4420. // How much the force applied by the magnet is multiplied
  4421. ForceCoefficient = 14000.0;
  4422.  
  4423. // This value is added to the squared distance to avoid divisions by zero, it also gives the magnet a less violent behaviour
  4424. // on objects which are near the center
  4425. AttractOffset = 10.0;
  4426. RepelOffset = 5.0;
  4427.  
  4428. // If set to true, magnets in attract mode will attempt to synchronize caught random mines
  4429. // so they explode at the same time, causing maximum damage
  4430. MineTriggerSync = true;
  4431.  
  4432. // How many cycles of turns before the magnet stops working
  4433. TurnsRemaining = 4;
  4434.  
  4435. // How much damage the magnet can take before breaking
  4436. Health = 80;
  4437. ExplosionDamage = 50;
  4438. ExplosionBlast = 100;
  4439.  
  4440. // Ignore any damage taken
  4441. IgnoreDamage = false;
  4442.  
  4443. // Offset between the projectile and the actual magnetic field
  4444. MagnetOffsetX = 0.0;
  4445. MagnetOffsetY = 0.0;
  4446. MagnetOffsetRelative = false;
  4447.  
  4448. // END OF MAGNET PARAMETERS
  4449.  
  4450. // Sprite parameters
  4451. Sprite1 = magnetSprite->Index;
  4452. Sprite2 = magnetSprite2->Index;
  4453. Sprite1Damaged = magnetDamagedSprite->Index;
  4454. Sprite2Damaged = magnetDamagedSprite2->Index;
  4455.  
  4456. // Animation parameters
  4457. SpinMultiplier = 0.04;
  4458. MaxSpinSpeed = 0.5;
  4459.  
  4460. OrientationOption = 0;
  4461.  
  4462. RingSpeed = 8;
  4463. RingPeriod = 65;
  4464. RingMinSize = 5;
  4465. RingMaxSize = 120;
  4466.  
  4467. SparkAnimSpeed = 0.02;
  4468. SparkPauseDuration = 0.4;
  4469.  
  4470. // Physics crap
  4471. DumpingA = 0.3;
  4472. DumpingB = 0.3;
  4473. DumpingC = 0.3;
  4474.  
  4475. // Private shit
  4476. Removed = false;
  4477.  
  4478. Rotation = float(0.0);
  4479. Mirrored = false;
  4480. Polarity = Pol;
  4481. LowHealth = 30;
  4482.  
  4483. NumRings = 0;
  4484. Rings = new int[5];
  4485. for(local i=0 ; i<5 ; i+=1) Rings[i] = 0;
  4486. NextRing = 0;
  4487.  
  4488. NextRecalcZPlane = 0;
  4489. ZPlane = 10;
  4490.  
  4491. SparkCycle = 0.0;
  4492.  
  4493. OwnerTeam = Desc->Team;
  4494. LastTeam = OwnerTeam;
  4495.  
  4496. CMineParams MParams;
  4497. zero(&MParams);
  4498.  
  4499. MParams.Prefuse = 0;
  4500. MParams.Flags = 0;
  4501. MParams.Bias = 0;
  4502. MParams.Radius = 1;
  4503. MParams.Fuse = 70;
  4504. MParams.Damage = 48;
  4505. MParams.BlastPower = 100;
  4506.  
  4507. super(Parent, &MParams, Desc, false, 0);
  4508.  
  4509. MagnetPosX = PosX;
  4510. MagnetPosY = PosY;
  4511.  
  4512. ClType = EObjectClass(70);
  4513. Initialized = false;
  4514.  
  4515. TurnEnded = false;
  4516. TurnEndTime = 0;
  4517. TurnsLifetime = 0;
  4518.  
  4519. DoMagneticField(false, true);
  4520. }
  4521.  
  4522. void CMagnetResult::CalculateMagneticForce(CMagnet *mag, fixed PosX, fixed PosY, float fmul)
  4523. {
  4524. if(mag->Removed || mag->TurnsRemaining <= 0) return;
  4525.  
  4526. float offset = mag->RepelOffset;
  4527. if(mag->Polarity < 0)
  4528. {
  4529. offset = mag->AttractOffset;
  4530. }
  4531.  
  4532. // Calculating distance from object to magnet
  4533. float fX = PosX - mag->MagnetPosX;
  4534. float fY = PosY - mag->MagnetPosY;
  4535. float r2 = fX*fX + fY*fY + offset;
  4536.  
  4537. // Too far away, don't do anything
  4538. if(r2>mag->MaxRange) return;
  4539.  
  4540. // Calculating force
  4541. float r = sqrt(r2);
  4542. float mul = mag->ForceCoefficient / r2;
  4543.  
  4544. if(mul > mag->MaxForce) mul = mag->MaxForce;
  4545.  
  4546. fX = (fX / r) * mul * mag->Polarity;
  4547. fY = (fY / r) * mul * mag->Polarity;
  4548.  
  4549. ForceX = fmul * fX;
  4550. ForceY = fmul * fY;
  4551. IsNull = false;
  4552. }
  4553.  
  4554. void CMagnetResult::CalculateGlobalMagneticForce(fixed PosX, fixed PosY, float fmul)
  4555. {
  4556. for(int i = 1; i < Env->Objs.Count; i+=1)
  4557. {
  4558. local obj = Env->Objs.Objs[i];
  4559.  
  4560. if(obj == NullObj) continue;
  4561. if(obj is CMagnet)
  4562. {
  4563. CMagnet *mag = CMagnet(obj);
  4564. CalculateMagneticForce(mag, PosX, PosY, fmul);
  4565. }
  4566. }
  4567. }
  4568.  
  4569. // Placeholder for CMagnetMissile
  4570. void CMagnet::Collide(CGObject* Obj, int type)
  4571. {
  4572. super;
  4573. }
  4574.  
  4575. // Initializations which require the initial parameters should be done there
  4576. void CMagnet::InitializeParameters()
  4577. {
  4578. if(Initialized) return;
  4579.  
  4580. MaxRange = MaxRange * MaxRange;
  4581. MaxSyncRange = MaxRange * 0.25;
  4582. AttractOffset = AttractOffset * AttractOffset;
  4583. RepelOffset = RepelOffset * RepelOffset;
  4584.  
  4585. RingMinSize = RingMinSize * 10;
  4586. RingMaxSize = RingMaxSize * 10;
  4587.  
  4588. SparkCycleDuration = 1.0 + SparkPauseDuration;
  4589.  
  4590. TurnsLifetime = TurnsRemaining;
  4591.  
  4592. Initialized = true;
  4593. }
  4594.  
  4595. // Recharges a discharged magnet
  4596. void CMagnet::Recharge()
  4597. {
  4598. if(Removed) return;
  4599.  
  4600. if(TurnsRemaining <= 0)
  4601. {
  4602. NextRing = 0;
  4603. }
  4604.  
  4605. TurnsRemaining = TurnsLifetime;
  4606.  
  4607. DoMagneticField(false, true);
  4608. }
  4609.  
  4610. // Update the position of the magnetic field relative to the actual projectile
  4611. void CMagnet::UpdateMagnetPosition()
  4612. {
  4613. if(MagnetOffsetRelative)
  4614. {
  4615. float s = sin(Rotation);
  4616. float c = cos(Rotation);
  4617. MagnetPosX = PosX - s * MagnetOffsetX - c * MagnetOffsetY;
  4618. MagnetPosY = PosY + c * MagnetOffsetX - s * MagnetOffsetY;
  4619. }
  4620. else
  4621. {
  4622. MagnetPosX = PosX + MagnetOffsetX;
  4623. MagnetPosY = PosY + MagnetOffsetY;
  4624. }
  4625. }
  4626.  
  4627. // Update the angle of the projectile
  4628. void CMagnet::UpdateRotation()
  4629. {
  4630. if(OrientationOption == 0)
  4631. {
  4632. float speed = sqrt(SpX*SpX + SpY*SpY);
  4633. float rot = SpinMultiplier * speed;
  4634.  
  4635. if(rot > MaxSpinSpeed) rot = MaxSpinSpeed;
  4636. if(SpX<0) rot = 0-rot;
  4637.  
  4638. ApplyRotation(rot);
  4639. }
  4640. else
  4641. {
  4642.  
  4643. if(SpX==0.0)
  4644. {
  4645. if(SpY>0.0)
  4646. {
  4647. if(WormTurnSide > 0)
  4648. {
  4649. // something weird is happening HERE //no moar (ent)
  4650. Rotation = 0;
  4651. }
  4652. else
  4653. {
  4654. Rotation = 3.141593;
  4655. }
  4656. }
  4657. else if(SpY<0.0)
  4658. {
  4659. if(WormTurnSide > 0)
  4660. {
  4661. Rotation = 3.141593;
  4662. }
  4663. else
  4664. {
  4665. Rotation = 0;
  4666. }
  4667. }
  4668. }
  4669. else
  4670. {
  4671. Rotation = 0-atan2(SpX, SpY);
  4672. }
  4673. ApplyRotation(0.0);
  4674. }
  4675. }
  4676.  
  4677. // Rotates the projectile by r radians, and normalizes the angle
  4678. void CMagnet::ApplyRotation(float r)
  4679. {
  4680. Rotation += r;
  4681. while(Rotation > 3.141593) Rotation -= 6.283186;
  4682. while(Rotation <= 0 - 3.141593) Rotation += 6.283186;
  4683. }
  4684.  
  4685. // Applies blast damage to the magnet
  4686. // x, y : origin of the explosion
  4687. // dmg : maximum damage the explosion should do
  4688. void CMagnet::TakeExplosionDamage(fixed x, fixed y, int dmg)
  4689. {
  4690. if(dmg == 0) return;
  4691.  
  4692. float fdmg = dmg;
  4693. float dx = PosX - x;
  4694. float dy = PosY - y;
  4695.  
  4696. float distsqr = dx*dx + dy*dy;
  4697. float fdmgsqr = fdmg*fdmg*4.0;
  4698.  
  4699. fdmg = (1.0-distsqr/fdmgsqr) * fdmg;
  4700. dmg = fdmg;
  4701.  
  4702. if(dmg > 0) TakeDamage(0, dmg);
  4703. }
  4704.  
  4705. // Applies direct damage to the magnet (without any further calculation)
  4706. // type should be always 0 (10 is for percentage-based damage and is reserved to the Battle Axe)
  4707. void CMagnet::TakeDamage(int type, int dmg)
  4708. {
  4709. if(type == 10)
  4710. {
  4711. fixed fdmg = dmg;
  4712. fdmg = Health * fdmg / 100.0;
  4713. dmg = fdmg;
  4714. }
  4715.  
  4716. Health -= dmg;
  4717. }
  4718.  
  4719. int CMagnet::GetRing(int i) { return Rings[i]; }
  4720. void CMagnet::SetRing(int i, int x) { Rings[i] = x; }
  4721.  
  4722. // Adds a ring effect to the magnetic field
  4723. void CMagnet::PushRing()
  4724. {
  4725. if(NumRings<5)
  4726. {
  4727. if(Polarity>0) SetRing(NumRings, RingMinSize);
  4728. else SetRing(NumRings, RingMaxSize);
  4729. NumRings = NumRings + 1;
  4730. }
  4731. }
  4732.  
  4733. // Removes a ring when it has disappeared
  4734. void CMagnet::PopRing()
  4735. {
  4736. if(NumRings>0)
  4737. {
  4738. for(local i = 1; i < NumRings; i+=1)
  4739. {
  4740. SetRing(i-1, GetRing(i));
  4741. }
  4742. NumRings = NumRings - 1;
  4743. }
  4744. }
  4745.  
  4746. // Triggers a mine and applies mine timer synchronization
  4747. void CMagnet::TriggerMine(CMine *mine)
  4748. {
  4749. // Not a special mine
  4750. if(mine->Radius > 1 && mine->Active == 0 && mine->Prefuse <= 0 && mine->Fuse < 0)
  4751. {
  4752. // Give it a random fuse time (between 1 and 5)
  4753. mine->Fuse = 1000 + (GS->GetRandom()%4000);
  4754.  
  4755. // Mine synchronisation mode is on
  4756. if(MineTriggerSync)
  4757. {
  4758. // Only applies to magnets in attract mode
  4759. if(Polarity<0)
  4760. {
  4761. // Search for an attracted mine with the highest fuse time
  4762. int maxFuse = 1000;
  4763. for(local i = 1; i < Env->Objs.Count; i+=1)
  4764. {
  4765. local obj2 = Env->Objs.Objs[i];
  4766.  
  4767. if(obj2 == NullObj) continue;
  4768.  
  4769. if(obj2->ClType == OC_Mine)
  4770. {
  4771. local mine2 = CMine(obj2);
  4772.  
  4773. if(mine2 == mine) continue;
  4774.  
  4775. // Calculate distance from mine to magnet
  4776. float mX = mine2->PosX - MagnetPosX;
  4777. float mY = mine2->PosY - MagnetPosY;
  4778. float rm2 = mX * mX + mY * mY;
  4779.  
  4780. // If it's close enough, we'll consider it's being attracted
  4781. if(rm2 < MaxSyncRange)
  4782. {
  4783. if(mine2->Fuse > maxFuse) maxFuse = mine2->Fuse;
  4784. }
  4785. }
  4786. }
  4787.  
  4788. // If another mine was found and its fuse is long enough
  4789. if(maxFuse > 1000)
  4790. {
  4791. // Synchronize the current mine with it
  4792. // and give it a slight random offset so it doesn't look too suspicious
  4793. mine->Fuse = maxFuse + (GS->GetRandom()%400) - 200;
  4794. }
  4795. }
  4796. }
  4797. }
  4798.  
  4799. // Trigger the mine
  4800. mine->Active = 1;
  4801. mine->nPulses = mine->Fuse / 250;
  4802. }
  4803.  
  4804. // Applies force to nearby objects
  4805. // It will also trigger mines to make sure the turn will not get stuck due to perpetual motion
  4806. void CMagnet::ApplyForce(CGObject *obj, float fmul, bool forceWake)
  4807. {
  4808. // Wake up nearby bowling balls
  4809. if(SpX != 0 || SpY != 0) forceWake = true;
  4810.  
  4811. if(forceWake == false)
  4812. {
  4813. if(#WEAPON_BOWLINGBALL)
  4814. {
  4815. if(obj is CBowlingBall)
  4816. {
  4817. local ball = CBowlingBall(obj);
  4818. if(ball->IsAsleep) return;
  4819. }
  4820. }
  4821. }
  4822.  
  4823. MagnetInternalResult->Reset();
  4824. MagnetInternalResult->CalculateMagneticForce(this, obj->PosX, obj->PosY, fmul);
  4825.  
  4826. if(MagnetInternalResult->IsNull) return;
  4827.  
  4828. // If the object is a mine, trigger it to make it explode
  4829. if(obj->ClType == OC_Mine)
  4830. {
  4831. local mine = CMine(obj);
  4832. TriggerMine(mine);
  4833. }
  4834.  
  4835. if(forceWake)
  4836. {
  4837. if(#WEAPON_BOWLINGBALL)
  4838. {
  4839. if(obj is CBowlingBall)
  4840. {
  4841. CBowlingBall *ball = CBowlingBall(obj);
  4842. ball->Wake();
  4843. }
  4844. }
  4845. }
  4846.  
  4847. // Applying force
  4848. obj->SpX += MagnetInternalResult->ForceX;
  4849. obj->SpY += MagnetInternalResult->ForceY;
  4850.  
  4851. obj->Stopped = 1;
  4852. obj->InMidAir = 0;
  4853.  
  4854. // End the turn if there are still moving missiles after 600 ticks
  4855. if(obj->ClType == OC_Missile)
  4856. {
  4857. if(TurnEnded)
  4858. {
  4859. if(GS->Tick - TurnEndTime > 300)
  4860. {
  4861. local missile = CMissile(obj);
  4862. missile->ExplodeAt(missile->PosX, missile->PosY);
  4863. }
  4864. }
  4865. }
  4866. }
  4867.  
  4868. void CMagnet::DoMagneticField(bool applyForce, bool forceWake)
  4869. {
  4870. float force = 0.0;
  4871. if(applyForce) force = 1.0;
  4872.  
  4873. for(int i = 1; i < Env->Objs.Count; i+=1)
  4874. {
  4875. local obj = Env->Objs.Objs[i];
  4876.  
  4877. if(obj == NullObj) continue;
  4878. if(obj->ClType == OC_Mine) ApplyForce(obj, force, forceWake);
  4879. if(obj->ClType == OC_Missile) ApplyForce(obj, force, forceWake);
  4880.  
  4881. // Support for bowling balls
  4882. if(#WEAPON_BOWLINGBALL)
  4883. {
  4884. if(obj is CBowlingBall) ApplyForce(obj, force * 0.25, forceWake);
  4885. }
  4886. }
  4887. }
  4888.  
  4889. // Draws the magnetic ring effect
  4890. void CMagnet::DrawMagnetRings()
  4891. {
  4892. if(NumRings>0)
  4893. {
  4894. CQuad q;
  4895. q.blend = 1;
  4896. for(local i = 0; i < NumRings; i+=1)
  4897. {
  4898. local size = GetRing(i) / 10;
  4899. local alpha = ((RingMaxSize - GetRing(i)) * 255) / RingMaxSize;
  4900.  
  4901. q.v[0].x = MagnetPosX - size; q.v[0].y = MagnetPosY - size;
  4902. q.v[0].color = ARGB(alpha,255,255,255);
  4903. q.v[1].x = MagnetPosX + size; q.v[1].y = MagnetPosY - size;
  4904. q.v[1].color = ARGB(alpha,255,255,255);
  4905. q.v[2].x = MagnetPosX + size; q.v[2].y = MagnetPosY + size;
  4906. q.v[2].color = ARGB(alpha,255,255,255);
  4907. q.v[3].x = MagnetPosX - size; q.v[3].y = MagnetPosY + size;
  4908. q.v[3].color = ARGB(alpha,255,255,255);
  4909.  
  4910. if(Polarity>0)
  4911. {
  4912. AddSpriteQ(ZPlane+1, &q, magnetRingSprite2->Index, 0, 64);
  4913. }
  4914. else
  4915. {
  4916. AddSpriteQ(ZPlane+1, &q, magnetRingSprite->Index, 0, 64);
  4917. }
  4918. }
  4919. }
  4920. }
  4921.  
  4922. // Takes care of the animations
  4923. void CMagnet::DoAnimation()
  4924. {
  4925. // Rings
  4926. if(NumRings>0)
  4927. {
  4928. for(local i = 0; i < NumRings; i+=1)
  4929. {
  4930. SetRing(i, GetRing(i) + RingSpeed * Polarity);
  4931. }
  4932. if(Polarity>0)
  4933. {
  4934. if(GetRing(0)>RingMaxSize) PopRing();
  4935. }
  4936. else
  4937. {
  4938. if(GetRing(0)<RingMinSize) PopRing();
  4939. }
  4940. }
  4941.  
  4942. if(TurnsRemaining>0 && Removed == false)
  4943. {
  4944. if(NextRing <= 0)
  4945. {
  4946. PushRing();
  4947. NextRing = RingPeriod;
  4948. }
  4949. else
  4950. {
  4951. NextRing = NextRing - 1;
  4952. }
  4953. }
  4954.  
  4955. // Sparks animation
  4956. if(TurnsRemaining>0)
  4957. {
  4958. SparkCycle = SparkCycle + SparkAnimSpeed;
  4959. if(SparkCycle > SparkCycleDuration) SparkCycle = SparkCycle - SparkCycleDuration;
  4960. }
  4961. }
  4962.  
  4963. // Draws the magnet's sprite
  4964. void CMagnet::DrawMagnet()
  4965. {
  4966. int sprite = Sprite1;
  4967.  
  4968. if(Polarity<0)
  4969. {
  4970. if(Health<=LowHealth) sprite = Sprite1Damaged;
  4971. else sprite = Sprite1;
  4972. }
  4973. else
  4974. {
  4975. if(Health<=LowHealth) sprite = Sprite2Damaged;
  4976. else sprite = Sprite2;
  4977. }
  4978.  
  4979. if(Mirrored) sprite += 262144;
  4980.  
  4981. AddSpriteEx(ZPlane, PosX, PosY, sprite, 0, Rotation + 3.14159, 1);
  4982. }
  4983.  
  4984. // Draws additional effects such as electrical sparks
  4985. void CMagnet::DrawMagnetEffects()
  4986. {
  4987. if(TurnsRemaining>0)
  4988. {
  4989. if(SparkCycle <= 1.0)
  4990. AddSpriteEx(ZPlane-1, PosX, PosY, magnetSparks->Index, SparkCycle, Rotation, 1);
  4991. }
  4992. }
  4993.  
  4994. // Called when a new turn begins (this is used to discharge the magnet after a given number of turn cycles)
  4995. void CMagnet::OnTurnBegin(int Team)
  4996. {
  4997. TurnEnded = false;
  4998. TurnEndTime = 0;
  4999. if(TurnsRemaining>0)
  5000. {
  5001. if(Team == OwnerTeam) TurnsRemaining = TurnsRemaining - 1;
  5002. if(TurnsRemaining <= 0)
  5003. {
  5004. // Wake all nearby objects without applying force to them
  5005. DoMagneticField(false, true);
  5006. }
  5007. }
  5008. }
  5009.  
  5010. void CMagnet::Message(CObject* sender, EMType Type, int MSize, CMessageData* MData)
  5011. {
  5012. if(Type == M_FRAME)
  5013. {
  5014. InitializeParameters();
  5015. }
  5016.  
  5017. if(Type == M_TURNEND)
  5018. {
  5019. TurnEnded = true;
  5020. TurnEndTime = GS->Tick;
  5021. }
  5022.  
  5023. // Drawing operations are done here
  5024. if(Type == M_DRAWQUEUE)
  5025. {
  5026. if(Initialized == false) return;
  5027.  
  5028. UpdateMagnetPosition();
  5029. DrawMagnetRings();
  5030.  
  5031. if(Removed==false)
  5032. {
  5033. if(Mirrored) SetColorMod(RGB(0, 255, 0), 6);
  5034. if(Sinking) SetColorMod(RGB(90, 90, 240), 6);
  5035.  
  5036. DrawMagnet();
  5037.  
  5038. if(Sinking) ClearColorMod();
  5039. if(Mirrored) ClearColorMod();
  5040.  
  5041. DrawMagnetEffects();
  5042.  
  5043. // Recalculate Z plane periodically to make sure magnets are drawn properly when overlapping each other
  5044. if(NextRecalcZPlane <= 0)
  5045. {
  5046. local matches = 0;
  5047.  
  5048. for(local i = 1; i < Env->Objs.Count; i+=1)
  5049. {
  5050. local obj = Env->Objs.Objs[i];
  5051.  
  5052. if(obj == NullObj) continue;
  5053. if(obj == this) continue;
  5054. if(obj->ClType == EObjectClass(70))
  5055. {
  5056. local mag = CMagnet(obj);
  5057.  
  5058. float dX = mag->PosX - PosX;
  5059. float dY = mag->PosY - PosY;
  5060. float r2 = dX*dX + dY*dY;
  5061.  
  5062. if(r2 < 900.0)
  5063. {
  5064. if(mag->ZPlane == ZPlane)
  5065. {
  5066. mag->ZPlane = mag->ZPlane + 2;
  5067. }
  5068. matches = matches + 1;
  5069. }
  5070. }
  5071. }
  5072.  
  5073. if(matches == 0) ZPlane = 10;
  5074.  
  5075. NextRecalcZPlane = 200;
  5076. }
  5077. else
  5078. {
  5079. NextRecalcZPlane = NextRecalcZPlane - 1;
  5080. }
  5081. }
  5082.  
  5083. return;
  5084. }
  5085.  
  5086. // Damage handling
  5087. if(Removed==false)
  5088. {
  5089. if(Type == M_EXPLOSION)
  5090. {
  5091. if(IgnoreDamage) return;
  5092. TakeExplosionDamage(MData->fparams[1], MData->fparams[2], MData->params[4]);
  5093. }
  5094. if(Type == M_GUNEXP)
  5095. {
  5096. if(IgnoreDamage) return;
  5097. TakeDamage(MData->params[0], MData->params[5]);
  5098. }
  5099. }
  5100.  
  5101. super;
  5102.  
  5103. // This is done every frame (derp)
  5104. if(Type == M_FRAME)
  5105. {
  5106. UpdateMagnetPosition();
  5107. DoAnimation();
  5108.  
  5109. if(Removed)
  5110. {
  5111. if(NumRings == 0) Free(true);
  5112. return;
  5113. }
  5114. else
  5115. {
  5116. if(Sinking)
  5117. {
  5118. TurnsRemaining = 0;
  5119. DoMagneticField(false, true);
  5120. }
  5121. else
  5122. {
  5123. UpdateRotation();
  5124. }
  5125.  
  5126. if(TurnsRemaining>0)
  5127. {
  5128. // Apply magnetic force to nearby objects but don't wake them if the magnet is standing still
  5129. DoMagneticField(true, false);
  5130. }
  5131.  
  5132. // No more health -> KA-BEWM!
  5133. if(Health <= 0)
  5134. {
  5135. // Wake all nearby objects without applying force to them
  5136. DoMagneticField(false, true);
  5137.  
  5138. DoExplosion(PosX,PosY-20, ExplosionBlast, ExplosionDamage, 0, 0);
  5139. Removed = true;
  5140. SpeedDivider = 1000;
  5141. SpX = 0.0;
  5142. SpY = 0.0;
  5143. GravityFactor = 0.0;
  5144. IsMaterial = false;
  5145. Stopped = 1;
  5146. }
  5147. }
  5148. }
  5149. }
  5150.  
  5151. ///////////////////////////////////////////////////
  5152. // CMagnetMissile class
  5153.  
  5154. CMagnetMissile : CMagnet;
  5155.  
  5156. CMagnetMissile::CMagnetMissile(CObject* Parent, CShootDesc* Desc, int WormDir, int Pol)
  5157. {
  5158. super;
  5159.  
  5160. // Maximum distance in which objects can be affected by the magnet
  5161. MaxRange = 120.0;
  5162.  
  5163. // Maximum acceleration the magnet can apply
  5164. MaxForce = 12.0;
  5165.  
  5166. // How much the force applied by the magnet is multiplied
  5167. ForceCoefficient = 12000.0;
  5168.  
  5169. // This value is added to the squared distance to avoid divisions by zero, it also gives the magnet a less violent behaviour
  5170. // on objects which are near the center
  5171. AttractOffset = 20.0;
  5172. RepelOffset = 10.0;
  5173.  
  5174. // If set to true, magnets in attract mode will attempt to synchronize caught random mines
  5175. // so they explode at the same time, causing maximum damage
  5176. MineTriggerSync = true;
  5177.  
  5178. // How many cycles of turns before the magnet stops working
  5179. TurnsRemaining = 2;
  5180.  
  5181. // How much damage the magnet can take before breaking
  5182. Health = 20;
  5183. ExplosionDamage = 40;
  5184. ExplosionBlast = 100;
  5185.  
  5186. // Ignore any damage taken
  5187. IgnoreDamage = true;
  5188.  
  5189. // Offset between the projectile and the actual magnetic field
  5190. MagnetOffsetX = -14.0;
  5191. MagnetOffsetY = 0.0;
  5192. MagnetOffsetRelative = true;
  5193.  
  5194. // END OF MAGNET PARAMETERS
  5195.  
  5196. // Sprite parameters
  5197. Sprite1 = magmissileSprite->Index;
  5198. Sprite2 = magmissileSprite2->Index;
  5199. Sprite1Damaged = magmissileSprite->Index;
  5200. Sprite2Damaged = magmissileSprite2->Index;
  5201.  
  5202. // Animation parameters
  5203. SpinMultiplier = 0.04;
  5204. MaxSpinSpeed = 0.5;
  5205.  
  5206. RingSpeed = 12;
  5207. RingPeriod = 30;
  5208. RingMinSize = 5;
  5209. RingMaxSize = 60;
  5210.  
  5211. OrientationOption = 1;
  5212.  
  5213. // Private
  5214. Phase = 0;
  5215. AttachX = 0.0;
  5216. AttachY = 0.0;
  5217.  
  5218. LastSpX = SpX;
  5219. LastSpY = SpY;
  5220. }
  5221.  
  5222. // Collisions derp
  5223. void CMagnetMissile::Collide(CGObject* Obj, int type)
  5224. {
  5225. if(Phase == 0)
  5226. {
  5227. float speed = sqrt(LastSpX * LastSpX + LastSpY * LastSpY);
  5228.  
  5229. // Collided with the world
  5230. if(Obj->ClType == OC_Landscape)
  5231. {
  5232. int hitx;
  5233. int hity;
  5234.  
  5235. float s = sin(Rotation);
  5236. float c = cos(Rotation);
  5237. float dx = 0 - (s * 8.0);
  5238. float dy = c * 8.0;
  5239.  
  5240. // Perform a trace 8 units forwards
  5241. CGObject *hit = TraceLine(this, PosX, PosY, PosX + dx, PosY + dy, 2, &hitx, &hity);
  5242.  
  5243. if(hit != NullObj)
  5244. {
  5245. // The trace hit the world, make the missile stick
  5246. if(hit->ClType == OC_Landscape)
  5247. {
  5248. AttachX = PosX;
  5249. AttachY = PosY;
  5250. SpeedDivider = 1000;
  5251. SpeedDividerB = 1000;
  5252. SpX = 0.0;
  5253. SpY = 0.0;
  5254. GravityFactor = 0.0;
  5255. Stopped = 1;
  5256. InMidAir = 0;
  5257. Phase = 1;
  5258.  
  5259. // Arrow impact sound
  5260. PlayLocalSound(28, 5, 1.0, 1.0);
  5261.  
  5262. IgnoreDamage = false;
  5263. OrientationOption = 0;
  5264.  
  5265. return;
  5266. }
  5267. }
  5268. else if(speed>5.0)
  5269. {
  5270. // Didn't hit the world at a suitable angle, reflect it if it has enough speed
  5271. super;
  5272. return;
  5273. }
  5274.  
  5275. // Not enough speed, make it roll away
  5276. IgnoreDamage = false;
  5277. OrientationOption = 0;
  5278. Phase = 2;
  5279. }
  5280. else // Collided with something else
  5281. {
  5282. bool nodamage = false;
  5283.  
  5284. // Bounce off oil drums and crates without dealing any damage
  5285. if(Obj->ClType == OC_OilDrum) nodamage = true;
  5286. if(Obj->ClType == OC_Crate) nodamage = true;
  5287.  
  5288. if(nodamage)
  5289. {
  5290. IgnoreDamage = false;
  5291. OrientationOption = 0;
  5292. Phase = 2;
  5293. super;
  5294. return;
  5295. }
  5296.  
  5297. // Knock colliding objects away
  5298. fixed forceX;
  5299. fixed forceY;
  5300.  
  5301. if(speed>0.5)
  5302. {
  5303. forceX = LastSpX * 0.3;
  5304. forceY = (LastSpY - speed) * 0.3;
  5305. // This will ensure the missile keeps going right through whatever it collided with
  5306. // (see CMagnetMissile::Message)
  5307. PostCollide = true;
  5308.  
  5309. CMessageData msg;
  5310. msg.params[0] = 0;
  5311. msg.fparams[1] = PosX;
  5312. msg.fparams[2] = PosY;
  5313. msg.fparams[3] = forceX;
  5314. msg.fparams[4] = forceY;
  5315. msg.params[5] = 5;
  5316. msg.params[6] = 0;
  5317.  
  5318. Obj->Message(this, M_GUNEXP, 1032, &msg);
  5319.  
  5320. // PUNCH!
  5321. PlayLocalSound(101, 5, 1.0, 1.0);
  5322. return;
  5323. }
  5324. else
  5325. {
  5326. IgnoreDamage = false;
  5327. OrientationOption = 0;
  5328. Phase = 2;
  5329. super;
  5330. return;
  5331. }
  5332. }
  5333. }
  5334. super;
  5335. }
  5336.  
  5337. void CMagnetMissile::Message(CObject* sender, EMType Type, int MSize, CMessageData* MData)
  5338. {
  5339. if(Phase == 1)
  5340. {
  5341. bool checkdetach = false;
  5342. bool detach = true;
  5343.  
  5344. // Took damage, see if it should detach or not
  5345. if(Type == M_EXPLOSION) { checkdetach = true; detach = false; }
  5346. else if(Type == M_GUNEXP)
  5347. {
  5348. // Detach it no matter what if melee damage has been received (aka type != 1 and 3)
  5349. checkdetach = true;
  5350. if(MData->params[0] == 1) detach = false;
  5351. if(MData->params[0] == 3) detach = false;
  5352. }
  5353.  
  5354. if(checkdetach)
  5355. {
  5356. if(detach == false)
  5357. {
  5358. // Damage has been dealt by fire, bullets or explosions, check if the missile still has an attachment point
  5359. int hitx;
  5360. int hity;
  5361.  
  5362. float s = sin(Rotation);
  5363. float c = cos(Rotation);
  5364. float dx = 0 - (s * 8.0);
  5365. float dy = c * 8.0;
  5366.  
  5367. // Perform a trace 8 units forwards
  5368. CGObject *hit = TraceLine(this, PosX, PosY, PosX + dx, PosY + dy, CMASK_TERRAIN, &hitx, &hity);
  5369.  
  5370. // Not attached to world anymore, detach it
  5371. if(hit == NullObj) detach = true;
  5372. else if(hit->ClType != OC_Landscape) detach = true;
  5373. }
  5374.  
  5375. // Detaching :(
  5376. if(detach)
  5377. {
  5378. AttachX = 0.0;
  5379. AttachY = 0.0;
  5380. SpeedDivider = 1;
  5381. SpeedDividerB = 1;
  5382. GravityFactor = 1.0;
  5383. Stopped = 0;
  5384. InMidAir = 1;
  5385. Phase = 2;
  5386. }
  5387. }
  5388. }
  5389.  
  5390. super;
  5391.  
  5392. if(Type == M_FRAME)
  5393. {
  5394. if(Phase == 0)
  5395. {
  5396. if(Sinking == false)
  5397. {
  5398. local p = new PxParticle(131, MagnetPosX, MagnetPosY);
  5399. p->SetLifeTime(30);
  5400. p->SetRandomVelocity(0.2, 0.6);
  5401. p->SetAirResistance(0.5);
  5402. p->SetAlpha(255);
  5403. if(Polarity==1)
  5404. {
  5405. p->SetColor(60,80,190);
  5406. }
  5407. else
  5408. {
  5409. p->SetColor(200,60,60);
  5410. }
  5411. }
  5412. }
  5413.  
  5414. if(Phase == 1)
  5415. {
  5416. PosX = AttachX;
  5417. PosY = AttachY;
  5418. SpX = 0.0;
  5419. SpY = 0.0;
  5420. Stopped = 1;
  5421. InMidAir = 0;
  5422. }
  5423.  
  5424. if(PostCollide)
  5425. {
  5426. // Collided with something it should go right through
  5427. // Set its velocity back to what it was before the collision
  5428. SpX = LastSpX;
  5429. SpY = LastSpY;
  5430. PostCollide = false;
  5431. }
  5432. LastSpX = SpX;
  5433. LastSpY = SpY;
  5434. }
  5435. }
  5436.  
  5437. ///////////////////////////////////////////////////
  5438. // CTurnGame overrides
  5439.  
  5440. override void CTurnGame::SetCurrentTeam(int Team)
  5441. {
  5442. super;
  5443.  
  5444. for(local i = 1; i < Env->Objs.Count; i+=1)
  5445. {
  5446. local obj = Env->Objs.Objs[i];
  5447.  
  5448. if(obj == NullObj) continue;
  5449. if(obj is CMagnet)
  5450. {
  5451. CMagnet *mag = CMagnet(obj);
  5452. mag->OnTurnBegin(Team);
  5453. }
  5454. }
  5455. }
  5456.  
  5457. ///////////////////////////////////////////////////
  5458. // CWorm overrides
  5459.  
  5460. override CWorm::CWorm(CObject* Parent, int aTeam, int aIndex, CWormParams* params)
  5461. {
  5462. super;
  5463. MagnetPolarity = 0;
  5464. AnimCanChangeMagnetType = false;
  5465. }
  5466.  
  5467. override void CWorm::FireFinal(CWeapon* Weap, CShootDesc* Desc)
  5468. {
  5469. if(Weap->CheckName("Electromagnet"))
  5470. {
  5471. local ang = (1 - FireAngle) * 3.14159;
  5472. if (TurnSide < 0)
  5473. {
  5474. ang = 6.28318 - ang;
  5475. }
  5476.  
  5477. CShootDesc SDesc;
  5478. zero(&SDesc);
  5479.  
  5480. local BaseForce = 0.3;
  5481.  
  5482. SDesc.Team = WormTeam;
  5483. SDesc.X = PosX;
  5484. SDesc.Y = PosY;
  5485. SDesc.SpX = SpX + TurnSide * BaseForce;
  5486. SDesc.SpY = SpY - 0.15;
  5487.  
  5488. int polarity = 1;
  5489. if(MagnetPolarity==1) polarity = -1;
  5490. new CMagnet(GetObject(25, 0), &SDesc, TurnSide, polarity);
  5491. }
  5492. else if(Weap->CheckName("Magnetic Missile"))
  5493. {
  5494. local ang = (1 - FireAngle) * 3.14159;
  5495. if (TurnSide < 0)
  5496. {
  5497. ang = 6.28318 - ang;
  5498. };
  5499.  
  5500. CShootDesc SDesc;
  5501. zero(&SDesc);
  5502.  
  5503. float BaseForce = FirePower * 20.0;
  5504.  
  5505. SDesc.Team = WormTeam;
  5506. SDesc.X = PosX;
  5507. SDesc.Y = PosY;
  5508. SDesc.SpX = SpX + sin(ang) * BaseForce;
  5509. SDesc.SpY = SpY - cos(ang) * BaseForce;
  5510.  
  5511. int polarity = 1;
  5512. if(MagnetPolarity==1) polarity = -1;
  5513. new CMagnetMissile(GetObject(25, 0), &SDesc, TurnSide, polarity);
  5514. }
  5515. else
  5516. {
  5517. super;
  5518. }
  5519. }
  5520.  
  5521. override void CWorm::Message(CObject* sender, EMType Type, int MSize, CMessageData* MData)
  5522. {
  5523. if(Type == M_FRAME)
  5524. {
  5525. if (CurWeapon->CheckName("Electromagnet"))
  5526. {
  5527. local Team = CTeam(GetObject(21, WormTeam));
  5528. Team->AllowSelectBounce = true;
  5529. //if(MagnetPolarity==1) CurWeapon->NameB = "Electromagnet, ATTRACT Mode";
  5530. //else CurWeapon->NameB = "Electromagnet, REPEL Mode";
  5531. }
  5532. else if (CurWeapon->CheckName("Magnetic Missile"))
  5533. {
  5534. local Team = CTeam(GetObject(21, WormTeam));
  5535. Team->AllowSelectBounce = true;
  5536. }
  5537. }
  5538. if (Type == M_SETBOUNCE)
  5539. {
  5540. if (CurWeapon->CheckName("Electromagnet"))
  5541. {
  5542. if (MData->GetParameter(1) != WormNumber) return;
  5543. local Dir = MData->GetParameter(2);
  5544.  
  5545. if(MagnetPolarity != Dir)
  5546. {
  5547. MagnetPolarity = Dir;
  5548.  
  5549. if(AnimCanChangeMagnetType) // Don't replay the deploy animation if we're not standing still
  5550. {
  5551. Anim->SetAnim(334); // Dynamite deploy animation
  5552. }
  5553. }
  5554.  
  5555. if(Dir==1) ShowMessage("Electromagnet, ATTRACT Mode");
  5556. else ShowMessage("Electromagnet, REPEL Mode");
  5557. return;
  5558. }
  5559. else if (CurWeapon->CheckName("Magnetic Missile"))
  5560. {
  5561. if (MData->GetParameter(1) != WormNumber) return;
  5562. local Dir = MData->GetParameter(2);
  5563. MagnetPolarity = Dir;
  5564. if(Dir==1) ShowMessage("Magnetic Missile, ATTRACT Mode");
  5565. else ShowMessage("Magnetic Missile, REPEL Mode");
  5566. return;
  5567. }
  5568. }
  5569. //if(Type == M_DRAWQUEUE)
  5570. //{
  5571. // int sx;
  5572. // int sy;
  5573. //
  5574. // AnimDebugBitmap->Rect(0,0,299,35,ARGB(255,0,0,0));
  5575. // GS->Disp->DrawText(1, AnimDebugBitmap, 5, 3, AnimDebugText, &sx, &sy);
  5576. //
  5577. // int RenderX = -GS->ResX / 2 + 165;
  5578. // int RenderY = -GS->ResY / 2 + 55;
  5579. // AddInterfaceBitmap(1, RenderX, RenderY, AnimDebugBitmap, 0, 0, 300, 100,0);
  5580. //}
  5581.  
  5582. super;
  5583. }
  5584.  
  5585. ///////////////////////////////////////////////////
  5586. // CSpriteAnim overrides
  5587.  
  5588. override void CSpriteAnim::SetAnimEx(int sindex, fixed frame)
  5589. {
  5590. // Make sure the game has actually started (otherwise GetCurrentWorm would crash the game due to Root not existing)
  5591. if(GS->Tick >= 1)
  5592. {
  5593. // If we belong to the current worm
  5594. CWorm *w = GetCurrentWorm();
  5595. if(w != NullObj && w->Anim == this)
  5596. {
  5597. //int f = int(frame * 1000.0);
  5598. //string temp = MakeNumberString(" Frame: ", f, "");
  5599. //AnimDebugText = MakeNumberString("Anim: ", sindex, temp);
  5600.  
  5601. if(sindex == 334 && w->CurWeapon->CheckName("Electromagnet")) // Dynamite deploy animation
  5602. {
  5603. if(w->MagnetPolarity == 1)
  5604. {
  5605. // Red magnet deploy animation
  5606. super(wmaglnk->Index, frame);
  5607. }
  5608. else
  5609. {
  5610. // Blue magnet deploy animation
  5611. super(wmag2lnk->Index, frame);
  5612. }
  5613.  
  5614. w->AnimCanChangeMagnetType = true;
  5615.  
  5616. return;
  5617. }
  5618. else
  5619. {
  5620. w->AnimCanChangeMagnetType = false;
  5621. }
  5622. }
  5623. }
  5624.  
  5625. super;
  5626. }
  5627. PXS : Library Code :
  5628. require pxairstrike, pxparticles, utils, wp_magnets, wpsounds;
  5629.  
  5630. PxAirstrikeParams *BunkerBusterParams;
  5631. CFireDesc *BunkerBusterFireDesc;
  5632.  
  5633. //CSprite* bunkerbusterSprite;
  5634. //CSprite* superbunkerbusterSprite;
  5635.  
  5636. CSprite *bbIdleSprite;
  5637. CSprite *bbDiggingSprite;
  5638. CSprite *sbbIdleSprite;
  5639. CSprite *sbbDiggingSprite;
  5640. CSprite *sbbGlowSprite;
  5641.  
  5642. CSoundFile* bunkerbusterDrillSound;
  5643. CSoundFile* bunkerbusterFallSound;
  5644. CColMask* MASK_BUNKERBUSTER;
  5645.  
  5646. CMagnetResult *BunkerBusterMagnetResult;
  5647.  
  5648.  
  5649. void bunkerbuster::FirstFrame()
  5650. {
  5651. BunkerBusterParams = new PxAirstrikeParams;
  5652. BunkerBusterFireDesc = new CFireDesc;
  5653.  
  5654. BunkerBusterFireDesc->Count = 10;
  5655. BunkerBusterFireDesc->UnkB = 1;
  5656. BunkerBusterFireDesc->Duration = 1000;
  5657. BunkerBusterFireDesc->UpPower = 15;
  5658. BunkerBusterFireDesc->Damage = 1;
  5659. BunkerBusterFireDesc->OwnerTeam = 0;
  5660.  
  5661. MASK_BUNKERBUSTER = new CColMask(8, 8, MakeCircleMask(8));
  5662.  
  5663. CFile *f;
  5664. f = GetAttachment("bunkbustdrill.wav");
  5665. bunkerbusterDrillSound = new CSoundFile(f);
  5666.  
  5667. f = GetAttachment("bunkbustfall.wav");
  5668. bunkerbusterFallSound = new CSoundFile(f);
  5669.  
  5670. BunkerBusterMagnetResult = new CMagnetResult();
  5671. }
  5672.  
  5673. // Loading resources
  5674. void bunkerbuster::InitGraphic()
  5675. {
  5676. CFile *f;
  5677.  
  5678. f = GetAttachment("bbuster_idle.png");
  5679. bbIdleSprite = LoadSprite(f, 3, 0);
  5680. f = GetAttachment("bbuster_digging.png");
  5681. bbDiggingSprite = LoadSprite(f, 3, 0);
  5682. f = GetAttachment("sbbuster_idle.png");
  5683. sbbIdleSprite = LoadSprite(f, 3, 0);
  5684. f = GetAttachment("sbbuster_digging.png");
  5685. sbbDiggingSprite = LoadSprite(f, 3, 0);
  5686. f = GetAttachment("sbbuster_glow.png");
  5687. sbbGlowSprite = LoadSprite(f, 1, 0);
  5688.  
  5689. //f = GetAttachment("bunkerbuster.png");
  5690. //bunkerbusterSprite = LoadSprite(f, 3, 0);
  5691.  
  5692. //f = GetAttachment("superbunkerbuster.png");
  5693. //superbunkerbusterSprite = LoadSprite(f, 3, 0);
  5694. }
  5695. ///////////////////////////////////////////////////
  5696. // PxBunkerBusterStrike
  5697.  
  5698. PxBunkerBusterStrike : PxAirstrike
  5699.  
  5700. PxBunkerBusterStrike::PxBunkerBusterStrike(CObject* Parent, CShootDesc* Desc, PxAirstrikeParams* Params, int type)
  5701. {
  5702. super(Parent, Desc, Params);
  5703. BusterType = type;
  5704. }
  5705.  
  5706. void PxBunkerBusterStrike::DropBomb()
  5707. {
  5708. CShootDesc SDesc;
  5709. zero(&SDesc);
  5710.  
  5711. SDesc.Team = Team;
  5712. SDesc.X = PosX;
  5713. SDesc.Y = PosY;
  5714.  
  5715. SDesc.SpX = 0;
  5716. SDesc.SpY = 0;
  5717.  
  5718. new PxBunkerBuster(Root->GetObject(25, 0), &SDesc, BusterType);
  5719. }
  5720.  
  5721. void PxBunkerBusterStrike::RenderPlane()
  5722. {
  5723. SetColorMod(RGB(255, 140, 0), 6); // orange plane!
  5724. super;
  5725. ClearColorMod();
  5726. }
  5727.  
  5728. ///////////////////////////////////////////////////
  5729. // PxBunkerBuster
  5730.  
  5731. PxBunkerBuster : CMine
  5732.  
  5733. PxBunkerBuster::PxBunkerBuster(CObject* Parent, CShootDesc* Desc, int type)
  5734. {
  5735. CMineParams MParams;
  5736. zero(&MParams);
  5737. MParams.Prefuse = 0;
  5738. MParams.Radius = 0;
  5739. MParams.Fuse = 1;
  5740. MParams.Flags = 0;
  5741. MParams.Bias = 0;
  5742. MParams.Damage = 0;
  5743. MParams.BlastPower = 0;
  5744.  
  5745. super(Parent, &MParams, Desc, false, 0);
  5746.  
  5747. // parameters
  5748.  
  5749. DrillFuelAmount = float(220.0);
  5750.  
  5751. DrillMinSpeed = float(1.0);
  5752. DrillMaxSpeed = float(4.0);
  5753. DiggingMagnetFactor = float(3.0);
  5754.  
  5755. DirX = float(0.0);
  5756. DirY = float(1.0);
  5757.  
  5758. AnimSpeed = 0.08;
  5759.  
  5760. ExplosionDeltaTime = 8;
  5761. ExplosionDistance = 40;
  5762. if(type == 0)
  5763. {
  5764. //Sprite = bunkerbusterSprite->Index;
  5765. SpriteIdle = bbIdleSprite->Index;
  5766. SpriteDigging = bbDiggingSprite->Index;
  5767. SpriteGlow = 0;
  5768.  
  5769. NumExplosions = 1;
  5770. ExplosionBlast = 100;
  5771. ExplosionDamage = 38;
  5772. }
  5773. else
  5774. {
  5775. //Sprite = superbunkerbusterSprite->Index;
  5776. SpriteIdle = sbbIdleSprite->Index;
  5777. SpriteDigging = sbbDiggingSprite->Index;
  5778. SpriteGlow = sbbGlowSprite->Index;
  5779.  
  5780. NumExplosions = 5;
  5781. ExplosionBlast = 80;
  5782. ExplosionDamage = 26;
  5783. }
  5784.  
  5785. DrillFireMinDelta = 15;
  5786. DrillFireMaxDelta = 60;
  5787.  
  5788. // internal - do not change
  5789. ClType = EObjectClass(72);
  5790. Dead = false;
  5791. Drilling = false;
  5792. DrillSpeed = DrillMinSpeed;
  5793. AnimCycle = 0.0;
  5794. AnimCycleDuration = 1.0;
  5795. ExhaustType = 0;
  5796. ColMask = MASK_BUNKERBUSTER;
  5797. Team = Desc->Team;
  5798. ChangeDrillSpeedTimer = 0;
  5799. DrillSoundTimer = 0;
  5800. BusterType = type;
  5801. ExplosionNum = 0;
  5802. ExplosionTimer = 0;
  5803. DrillFireTimer = 0;
  5804.  
  5805. Rotation = 0.0;
  5806.  
  5807. ColGroupDigging = CMASK_TERRAIN
  5808. | CMASK_WORM_ON_TERRAIN
  5809. | CMASK_WORM_USING_WEAPON
  5810. | CMASK_WORM_IN_MIDAIR
  5811. | CMASK_WORM_ON_ROPE
  5812. | CMASK_WORM_FROZEN
  5813. | CMASK_GASCANISTER
  5814. | CMASK_MINE
  5815. | CMASK_CRATE
  5816. | CMASK_DONORCARD
  5817. | CMASK_OILDRUM
  5818. | CMASK_SKIMMING;
  5819.  
  5820. ColGroupDefault = ColGroupDigging | CMASK_TERRAIN;
  5821. ColGroup = ColGroupDefault;
  5822.  
  5823. SoundObj = CSound(NullObj);
  5824. bunkerbusterFallSound->Play(1.0, 0.0, false);
  5825.  
  5826. MaxMagnetForce = 0.1;
  5827.  
  5828. LastPosX = PosX;
  5829. LastPosY = PosY;
  5830. }
  5831.  
  5832. void PxBunkerBuster::UpdateRotation()
  5833. {
  5834. if(SpX==0.0)
  5835. {
  5836. if(SpY>0.0)
  5837. {
  5838. Rotation = 0.0;
  5839. }
  5840. else if(SpY<0.0)
  5841. {
  5842. Rotation = 3.141593;
  5843. }
  5844. }
  5845. else
  5846. {
  5847. Rotation = -atan2(SpX, SpY);
  5848. }
  5849. }
  5850.  
  5851. void PxBunkerBuster::StartDigging()
  5852. {
  5853. Drilling = true;
  5854. ExhaustType = 1;
  5855.  
  5856. GravityFactor = 0.0;
  5857. SoundObj = bunkerbusterDrillSound->Play(1.0, 0.0, false);
  5858.  
  5859. LastPosX = PosX;
  5860. LastPosY = PosY;
  5861. } //seems like colgroup changing in Collide hook causes game freezing
  5862.  
  5863. void PxBunkerBuster::StopDigging()
  5864. {
  5865. Drilling = false;
  5866. GravityFactor = 1.0;
  5867. // ColGroup = ColGroupDefault;
  5868.  
  5869. if(SoundObj != CSound(NullObj))
  5870. {
  5871. // Mute the sound
  5872. SoundObj->Update(0.0, 0.0);
  5873. }
  5874. }
  5875.  
  5876. void PxBunkerBuster::Explode()
  5877. {
  5878. if(Dead) return;
  5879.  
  5880. SetDirection(SpX, SpY);
  5881. StopDigging();
  5882.  
  5883. //DoExplosion(1, PosX, PosY, ExplosionBlast, ExplosionDamage, 0, 0);
  5884. SpX = 0.0;
  5885. SpY = 0.0;
  5886. GravityFactor = 0.0;
  5887. IsMaterial = false;
  5888. Stopped = 1;
  5889.  
  5890. Dead = true;
  5891. }
  5892.  
  5893. void PxBunkerBuster::SetDirection(float dx, float dy)
  5894. {
  5895. if(Dead) return;
  5896.  
  5897. float d = sqrt(dx*dx+dy*dy);
  5898.  
  5899. if(d < 0.0001 && d > -0.0001)
  5900. {
  5901. DirX = 0;
  5902. DirY = 1;
  5903. }
  5904. else
  5905. {
  5906. DirX = dx / d;
  5907. DirY = dy / d;
  5908. }
  5909. }
  5910.  
  5911. void PxBunkerBuster::Collide(CGObject* Obj, int type)
  5912. {
  5913. if(Obj->ClType == OC_Landscape)
  5914. {
  5915. if(Drilling == false)
  5916. {
  5917. if(DrillFuelAmount <= 0)
  5918. {
  5919. Explode();
  5920. return;
  5921. }
  5922.  
  5923. StartDigging();
  5924. }
  5925. }
  5926. else
  5927. {
  5928. Explode();
  5929. }
  5930. }
  5931.  
  5932. void PxBunkerBuster::DoExplosion(fixed x, fixed y, int PushPower, int Damage, int unkB, int team)
  5933. {
  5934. super;
  5935.  
  5936. if(BusterType > 0)
  5937. {
  5938. BunkerBusterFireDesc->Count = 6;
  5939. BunkerBusterFireDesc->X = x;
  5940. BunkerBusterFireDesc->Y = y;
  5941. BunkerBusterFireDesc->SpX = 0;
  5942. BunkerBusterFireDesc->SpY = 0;
  5943.  
  5944. new CFire(GetObject(TI_FireStore, 0), BunkerBusterFireDesc, 0);
  5945. }
  5946. }
  5947.  
  5948. void PxBunkerBuster::Message(CObject* sender, EMType Type, int MSize, CMessageData* MData)
  5949. {
  5950. // Drawing operations are done here
  5951. if(Type == M_DRAWQUEUE)
  5952. {
  5953. if(Dead) return;
  5954.  
  5955. if(Sinking)
  5956. {
  5957. SetColorMod(RGB(90, 90, 240), 6);
  5958. }
  5959.  
  5960. CQuad q;
  5961. q.blend = 0;
  5962. for(int k=0 ; k<4 ; k+=1) q.v[k].color = RGB(255,255,255);
  5963.  
  5964. //AddSprite(10, PosX, PosY, 0, Sprite, AnimCycle);
  5965. if(Drilling)
  5966. {
  5967. //AddSpriteEx(10.01, PosX, PosY, SpriteDigging, AnimCycle, Rotation, 1.0);
  5968. FillSpriteQuad(&q, SpriteDigging, 0, 0);
  5969. TransformQuad(&q, Rotation, 1.0, 1.0, PosX, PosY);
  5970. AddSpriteQ(10.01, &q, SpriteDigging, AnimCycle, 0);
  5971. }
  5972. else
  5973. {
  5974. //AddSpriteEx(10.01, PosX, PosY, SpriteIdle, AnimCycle, Rotation, 1.0);
  5975. FillSpriteQuad(&q, SpriteIdle, 0, 0);
  5976. TransformQuad(&q, Rotation, 1.0, 1.0, PosX, PosY);
  5977. AddSpriteQ(10.01, &q, SpriteIdle, AnimCycle, 0);
  5978. }
  5979.  
  5980. if(Sinking)
  5981. {
  5982. ClearColorMod();
  5983. }
  5984. else if(SpriteGlow > 0)
  5985. {
  5986. FillSpriteQuad(&q, SpriteGlow, 0, 0);
  5987. TransformQuad(&q, Rotation, 1.0, 1.0, PosX, PosY);
  5988. q.blend = 1;
  5989. for(int i=0 ; i<4 ; i+=1) q.v[i].color = RGB(255,70,0);
  5990. AddSpriteQ(10, &q, SpriteGlow, 0, 64);
  5991. }
  5992.  
  5993. return;
  5994. }
  5995.  
  5996. super;
  5997.  
  5998. // This is done every frame
  5999. if(Type == M_FRAME)
  6000. {
  6001. if(Dead)
  6002. {
  6003. if(ExplosionNum >= NumExplosions)
  6004. {
  6005. Free(true);
  6006. return;
  6007. }
  6008.  
  6009. if(ExplosionTimer <= 0)
  6010. {
  6011. float dist = ExplosionDistance * ExplosionNum;
  6012. DoExplosion(PosX + DirY * dist, PosY - DirX * dist, ExplosionBlast, ExplosionDamage, 0, 0);
  6013. if(ExplosionNum > 0)
  6014. {
  6015. DoExplosion(PosX - DirY * dist, PosY + DirX * dist, ExplosionBlast, ExplosionDamage, 0, 0);
  6016. }
  6017.  
  6018. ExplosionTimer = ExplosionDeltaTime;
  6019. ExplosionNum = ExplosionNum + 1;
  6020. }
  6021. ExplosionTimer = ExplosionTimer - 1;
  6022. }
  6023.  
  6024. if(Sinking == false)
  6025. {
  6026. UpdateRotation();
  6027.  
  6028. // Animation
  6029. AnimCycle = AnimCycle + AnimSpeed;
  6030. if(AnimCycle > AnimCycleDuration) AnimCycle = AnimCycle - AnimCycleDuration;
  6031.  
  6032. BunkerBusterMagnetResult->Reset();
  6033. BunkerBusterMagnetResult->CalculateGlobalMagneticForce(PosX, PosY, 0.4);
  6034.  
  6035. if(BunkerBusterMagnetResult->IsNull == false && BunkerBusterMagnetResult->ForceX == 0.0)
  6036. {
  6037. BunkerBusterMagnetResult->ForceX = 0.01;
  6038. }
  6039.  
  6040. if(Drilling)
  6041. {
  6042. ColGroup = ColGroupDigging;
  6043. float force = sqrt(
  6044. BunkerBusterMagnetResult->ForceX * BunkerBusterMagnetResult->ForceX +
  6045. BunkerBusterMagnetResult->ForceY * BunkerBusterMagnetResult->ForceY
  6046. );
  6047.  
  6048. if(force > MaxMagnetForce)
  6049. {
  6050. force = MaxMagnetForce / force;
  6051. BunkerBusterMagnetResult->ForceX = BunkerBusterMagnetResult->ForceX * force;
  6052. BunkerBusterMagnetResult->ForceY = BunkerBusterMagnetResult->ForceY * force;
  6053. }
  6054.  
  6055. SetDirection(
  6056. 10 * DirX + DiggingMagnetFactor * BunkerBusterMagnetResult->ForceX,
  6057. 10 * DirY + DiggingMagnetFactor * BunkerBusterMagnetResult->ForceY
  6058. );
  6059.  
  6060. //if(DrillSoundTimer <= 0)
  6061. //{
  6062. // PlayLocalSound(84, 0, 1.0, 1.0, &Snd);
  6063. // DrillSoundTimer = 40;
  6064. //}
  6065. //
  6066. //DrillSoundTimer = DrillSoundTimer - 1;
  6067.  
  6068. // Change the speed of the buster every random interval
  6069. if(ChangeDrillSpeedTimer <= 0)
  6070. {
  6071. DrillSpeed = RandomFloat(DrillMinSpeed, DrillMaxSpeed);
  6072. ChangeDrillSpeedTimer = RandomInt(5, 15);
  6073. }
  6074.  
  6075. ChangeDrillSpeedTimer = ChangeDrillSpeedTimer - 1;
  6076.  
  6077. // If we're a super bunker buster, spread fire around
  6078. if(BusterType > 0)
  6079. {
  6080. if(DrillFireTimer <= 0)
  6081. {
  6082. BunkerBusterFireDesc->Count = 1;
  6083. BunkerBusterFireDesc->X = PosX;
  6084. BunkerBusterFireDesc->Y = PosY;
  6085. BunkerBusterFireDesc->SpX = RandomFloat(-2.0, 2.0);
  6086. BunkerBusterFireDesc->SpY = -4;
  6087.  
  6088. new CFire(GetObject(TI_FireStore, 0), BunkerBusterFireDesc, 0);
  6089.  
  6090. DrillFireTimer = RandomInt(DrillFireMinDelta, DrillFireMinDelta);
  6091. }
  6092.  
  6093. DrillFireTimer = DrillFireTimer - 1;
  6094. }
  6095.  
  6096. // Using the same mask as the Pneumatic Drill (mask 2)
  6097. SpX = DirX * DrillSpeed;
  6098. SpY = DirY * DrillSpeed;
  6099.  
  6100. int h_offset1 = RandomInt(6, 11);
  6101. int h_offset2 = RandomInt(5, 10);
  6102.  
  6103. //GG->land->ApplyMask(2, PosX + OffsetX, PosY);
  6104.  
  6105. GG->land->ApplyMask(1, PosX, PosY);
  6106. GG->land->ApplyMask(13, PosX + DirY * h_offset1, PosY - DirX * h_offset1);
  6107. GG->land->ApplyMask(13, PosX - DirY * h_offset2, PosY + DirX * h_offset2);
  6108.  
  6109. float dx = PosX - LastPosX;
  6110. float dy = PosY - LastPosY;
  6111. float distance = sqrt(dx*dx + dy*dy);
  6112.  
  6113. DrillFuelAmount -= distance;
  6114. //DrillFuelAmount -= DrillSpeed;
  6115.  
  6116. LastPosX = PosX;
  6117. LastPosY = PosY;
  6118.  
  6119. // Enough drilling, blow up now!
  6120. if(DrillFuelAmount <= 0.0)
  6121. {
  6122. Explode();
  6123. return;
  6124. }
  6125.  
  6126. // If there is no more land to drill, go back to falling mode
  6127. if(FindInMask(this, ColMask, PosX + 10.0*DirX, PosY + 10.0*DirY, 2) == NullObj)
  6128. {
  6129. // Give it a little push if it's not drilling directly downwards
  6130. SpX += 2 * (1.0 - DirY) * DirX * DrillSpeed;
  6131. SpY += 2 * (1.0 - DirY) * DirY * DrillSpeed;
  6132.  
  6133. StopDigging();
  6134. }
  6135. }
  6136. else
  6137. {
  6138. ColGroup = ColGroupDefault;
  6139. if(BunkerBusterMagnetResult->IsNull == false)
  6140. {
  6141. SpX += BunkerBusterMagnetResult->ForceX;
  6142. SpY += BunkerBusterMagnetResult->ForceY;
  6143. }
  6144. SetDirection(SpX, SpY);
  6145. }
  6146.  
  6147. // Smoke particles
  6148. if(ExhaustType == 0)
  6149. {
  6150. local p = new PxParticle(131, PosX - 14 * DirX, PosY - 14 * DirY);
  6151. p->SetLifeTime(30);
  6152. p->SetRandomVelocity(0.2, 0.5);
  6153. p->SetAirResistance(0.5);
  6154. p->SetStartAlpha(255);
  6155. p->SetEndAlpha(255);
  6156. p->SetStartColor(255,255,255);
  6157. p->SetEndColor(255,255,255);
  6158. }
  6159. else
  6160. {
  6161. if(BusterType == 0)
  6162. {
  6163. local p = new PxParticle(131, PosX + 14 * DirY - 12 * DirX, PosY - 14 * DirX - 12 * DirY);
  6164. p->SetLifeTime(30);
  6165. p->SetRandomVelocity(0.5, 0.8);
  6166. p->SetAirResistance(0.5);
  6167. p->SetStartAlpha(140);
  6168. p->SetEndAlpha(140);
  6169. p->SetStartSize(0.5, 0.5);
  6170. p->SetEndSize(0.5, 0.5);
  6171. p->SetStartColor(200,200,200);
  6172. p->SetEndColor(50,50,50);
  6173. }
  6174. else
  6175. {
  6176. local p = new PxParticle(130, PosX + 14 * DirY - 10 * DirX, PosY - 12 * DirX - 10 * DirY);
  6177. p->SetLifeTime(30);
  6178. p->SetBlendMode(1);
  6179. p->SetRandomVelocity(0.5, 0.8);
  6180. p->SetAirResistance(0.5);
  6181. p->SetStartAlpha(255);
  6182. p->SetEndAlpha(255);
  6183. p->SetStartSize(0.5, 0.5);
  6184. p->SetEndSize(0.5, 0.5);
  6185. p->SetColor(150,150,150);
  6186.  
  6187. p = new PxParticle(130, PosX - 14 * DirY - 10 * DirX, PosY + 12 * DirX - 10 * DirY);
  6188. p->SetLifeTime(30);
  6189. p->SetBlendMode(1);
  6190. p->SetRandomVelocity(0.5, 0.8);
  6191. p->SetAirResistance(0.5);
  6192. p->SetStartAlpha(255);
  6193. p->SetEndAlpha(255);
  6194. p->SetStartSize(0.5, 0.5);
  6195. p->SetEndSize(0.5, 0.5);
  6196. p->SetColor(150,150,150);
  6197. }
  6198. }
  6199. }
  6200. }
  6201. }
  6202.  
  6203. ///////////////////////////////////////////////////
  6204. // CWorm overrides
  6205.  
  6206. override void CWorm::FireFinal(CWeapon* Weap, CShootDesc* Desc)
  6207. {
  6208. if(Weap->CheckName("Bunker Buster"))
  6209. {
  6210. BunkerBusterParams->NumBombs = 1;
  6211. BunkerBusterParams->BombDistance = 64;
  6212. BunkerBusterParams->BombSpX = 0;
  6213. BunkerBusterParams->BombSpY = 0;
  6214. new PxBunkerBusterStrike(GetObject(25, 0), Desc, BunkerBusterParams, 0);
  6215. }
  6216. else if(Weap->CheckName("Super Bunker Buster"))
  6217. {
  6218. BunkerBusterParams->NumBombs = 1;
  6219. BunkerBusterParams->BombDistance = 64;
  6220. BunkerBusterParams->BombSpX = 0;
  6221. BunkerBusterParams->BombSpY = 0;
  6222. new PxBunkerBusterStrike(GetObject(25, 0), Desc, BunkerBusterParams, 1);
  6223. }
  6224. else
  6225. {
  6226. super;
  6227. }
  6228. }
  6229.  
  6230. override void CWorm::Message(CObject* sender, EMType Type, int MSize, CMessageData* MData)
  6231. {
  6232. if(Type == M_SPACE)
  6233. {
  6234. for(local i = 1; i < Env->Objs.Count; i+=1)
  6235. {
  6236. local obj = Env->Objs.Objs[i];
  6237.  
  6238. if(obj == NullObj) continue;
  6239. if(obj is PxBunkerBuster)
  6240. {
  6241. local bb = PxBunkerBuster(obj);
  6242. if(bb->Team == WormTeam)
  6243. {
  6244. bb->Explode();
  6245. return;
  6246. }
  6247. }
  6248. }
  6249. }
  6250.  
  6251. super;
  6252. }
  6253. PXS : Library Code :
  6254. require utils, pxparticles, wpsounds;
  6255.  
  6256. #WEAPON_FAN
  6257.  
  6258. CSprite* fanBodySprite;
  6259. CSprite* fanBladeSprite;
  6260. CSprite* fanBladeIdleSprite;
  6261. CSprite* fanGrateSprite;
  6262. CSprite* fanArrowSprite;
  6263.  
  6264. CColMask* MASK_FAN;
  6265. CColMask* MASK_FANBLADE_DMG;
  6266.  
  6267. int WEAPONINDEX_FAN;
  6268.  
  6269. //CLogFile *fanLog;
  6270.  
  6271. PxWindManager : CObject;
  6272. PxFan : CMine;
  6273.  
  6274. PxWindManager *WIND_M;
  6275.  
  6276. void fan::FirstFrame()
  6277. {
  6278. MASK_FAN = new CColMask(6, 12, MakeRectMask(6, 12));
  6279. MASK_FANBLADE_DMG = new CColMask(12, 28, MakeRectMask(12, 28));
  6280. WIND_M = new PxWindManager();
  6281. //fanLog = new CLogFile("fan_log.txt");
  6282.  
  6283. WEAPONINDEX_FAN = -1;
  6284. }
  6285.  
  6286. // Loading resources
  6287. void fan::InitGraphic()
  6288. {
  6289. CFile *f;
  6290.  
  6291. f = GetAttachment("fan_body.png"); fanBodySprite = LoadSprite(f, 1, 0);
  6292. f = GetAttachment("fan_blade.png"); fanBladeSprite = LoadSprite(f, 4, 0);
  6293. f = GetAttachment("fan_blade_idle.png"); fanBladeIdleSprite = LoadSprite(f, 1, 0);
  6294. f = GetAttachment("fan_grate.png"); fanGrateSprite = LoadSprite(f, 1, 0);
  6295. f = GetAttachment("fan_arrow.png"); fanArrowSprite = LoadSprite(f, 1, 0);
  6296. }
  6297.  
  6298. ///////////////////////////////////////////////////
  6299. // PxWindManager class
  6300.  
  6301. PxWindManager::PxWindManager()
  6302. {
  6303. super(Root, GS);
  6304.  
  6305. InitialWind = 0.0; // The wind at the beginning of the turn
  6306. ShouldRecalcWind = false; // Should we recalculate the total wind from every active fan?
  6307. }
  6308.  
  6309. void PxWindManager::InitWind()
  6310. {
  6311. InitialWind = GS->env->Wind;
  6312. }
  6313.  
  6314. void PxWindManager::RecalculateWind()
  6315. {
  6316. ShouldRecalcWind = false;
  6317. float wind = InitialWind;
  6318.  
  6319. for(local i = 1; i < Env->Objs.Count; i+=1)
  6320. {
  6321. local obj = Env->Objs.Objs[i];
  6322.  
  6323. if(obj == NullObj) continue;
  6324. if(obj is PxFan)
  6325. {
  6326. local obj_fan = PxFan(obj);
  6327. wind += obj_fan->GetWindForce();
  6328. }
  6329. }
  6330.  
  6331. if(wind > 0.34) wind = 0.34;
  6332. if(wind < -0.34) wind = -0.34;
  6333.  
  6334. GS->env->Wind = wind;
  6335.  
  6336. CMessageData msg;
  6337. msg.fparams[0] = wind;
  6338. Root->Message(Root, M_UPDATEWIND, 1032, &msg);
  6339. }
  6340.  
  6341. void PxWindManager::UpdateWind()
  6342. {
  6343. ShouldRecalcWind = true;
  6344. }
  6345.  
  6346. void PxWindManager::Message(CObject* sender, EMType Type, int MSize, CMessageData* MData)
  6347. {
  6348. if(Type == M_FRAME)
  6349. {
  6350. if(ShouldRecalcWind)
  6351. {
  6352. RecalculateWind();
  6353. }
  6354. }
  6355.  
  6356. if(Type == M_DRAWQUEUE)
  6357. {
  6358. return;
  6359. }
  6360.  
  6361. super;
  6362. }
  6363.  
  6364. ///////////////////////////////////////////////////
  6365. // PxFan class
  6366.  
  6367. PxFan::PxFan(CObject* Parent, CShootDesc* Desc, int force, int mode, int side)
  6368. {
  6369. // Health parameters
  6370. if(mode == 0)
  6371. MaxHealth = 55;
  6372. else
  6373. MaxHealth = 40;
  6374.  
  6375. Health = MaxHealth;
  6376. ExplosionDamage = 25;
  6377. ExplosionBlast = 50;
  6378.  
  6379. DamagePerBladeHit = 14;
  6380. DamageReductionPerHit = 4; // 14+10+6+2+1+1+1...
  6381. DamageTakenPerBladeHit = 3;
  6382. BladeHitForce = 5.0;
  6383. BladeCooldown = 5;
  6384.  
  6385. // Physics parameters
  6386. BounceMultiplierX = 0.0;
  6387. BounceMultiplierY = 1.0;
  6388.  
  6389. // INTERNAL PARAMETERS
  6390. FanMode = mode;
  6391. FanForce = force;
  6392. TurretScale = 0.6;
  6393.  
  6394. // Sprites
  6395. SpriteBody = fanBodySprite->Index;
  6396. SpriteBlade = fanBladeSprite->Index;
  6397. SpriteBladeIdle = fanBladeIdleSprite->Index;
  6398. SpriteGrate = fanGrateSprite->Index;
  6399. SpriteArrow = fanArrowSprite->Index;
  6400.  
  6401. // Private
  6402. AnimCycle = 0.0;
  6403.  
  6404. // Arrow animation
  6405. NumArrows = 0;
  6406. Arrows = new int[6];
  6407. for(local i=0 ; i<6 ; i+=1) Arrows[i] = 0;
  6408. NextArrow = 0;
  6409.  
  6410. ArrowSpeed = 2 + FanForce * 3;
  6411. ArrowPeriod = 40 / FanForce;
  6412. ArrowDistance = 6 + FanForce * 12;
  6413. ArrowScale = 1.0 + FanForce * 0.1;
  6414.  
  6415. AnimSpeed = 0.0;
  6416. MaxAnimSpeed = 0.06 + FanForce * 0.025;
  6417. TargetAnimSpeed = MaxAnimSpeed;
  6418. AnimAccel = 0.006;
  6419.  
  6420. NextBladeCooldown = 30;
  6421.  
  6422. BaseOffsetX = 0;
  6423. BaseOffsetY = -1;
  6424. BladeOffsetX = 10;
  6425. BladeOffsetY = -14;
  6426. GrateOffsetX = 10;
  6427. GrateOffsetY = -14;
  6428.  
  6429. Planted = false;
  6430. Removed = false;
  6431.  
  6432. TurnsRemaining = 7 - FanForce;
  6433. DestroyOnExpire = false;
  6434.  
  6435. //if(Desc->SpX < 0)
  6436. if(side < 0)
  6437. {
  6438. BaseSide = -1;
  6439. }
  6440. else
  6441. {
  6442. BaseSide = 1;
  6443. }
  6444.  
  6445. NextRecalcZPlane = 0;
  6446. ZPlane = 10.0;
  6447.  
  6448. OwnerTeam = Desc->Team;
  6449.  
  6450. BladePosX = PosX;
  6451. BladePosY = PosY;
  6452.  
  6453. CMineParams MParams;
  6454. zero(&MParams);
  6455.  
  6456. MParams.Prefuse = 0;
  6457. MParams.Flags = 0;
  6458. MParams.Bias = 0;
  6459. MParams.Radius = 0;
  6460. MParams.Fuse = 71;
  6461. MParams.Damage = 48;
  6462. MParams.BlastPower = 100;
  6463.  
  6464. SetLayerOverride(LAYER_OILDRUM);
  6465. SetMaskIndexOverride(3);
  6466.  
  6467. super(Parent, &MParams, Desc, false, 0);
  6468. ClType = EObjectClass(74);
  6469.  
  6470. //Layer = LAYER_OILDRUM;
  6471. //ColGroup = CMASK_DEFAULT_COLLIDEABLE;
  6472.  
  6473. ColMask = MASK_FAN;
  6474.  
  6475. WIND_M->UpdateWind();
  6476. }
  6477.  
  6478. bool PxFan::IsActive()
  6479. {
  6480. return (Removed == false) && (TurnsRemaining > 0);
  6481. }
  6482.  
  6483. void PxFan::Recharge()
  6484. {
  6485. if(Removed) return;
  6486.  
  6487. if(TurnsRemaining <= 0)
  6488. {
  6489. NextArrow = 0;
  6490. }
  6491.  
  6492. TurnsRemaining = 7 - FanForce;
  6493.  
  6494. WIND_M->UpdateWind();
  6495. }
  6496.  
  6497. void PxFan::OnTurnBegin(int Team)
  6498. {
  6499. if(TurnsRemaining>0)
  6500. {
  6501. if(Team == OwnerTeam) TurnsRemaining = TurnsRemaining - 1;
  6502. }
  6503. }
  6504.  
  6505. float PxFan::GetWindForce()
  6506. {
  6507. if(Removed || (IsActive() == false)) return 0.0;
  6508.  
  6509. return 0.07 * FanForce * BaseSide;
  6510. }
  6511.  
  6512. void PxFan::UpdateBladePosition()
  6513. {
  6514. if(BaseSide < 0)
  6515. BladePosX = PosX + BaseOffsetX - TurretScale*BladeOffsetX;
  6516. else
  6517. BladePosX = PosX + BaseOffsetX + TurretScale*BladeOffsetX;
  6518.  
  6519. BladePosY = PosY + BaseOffsetY + TurretScale*BladeOffsetY;
  6520. }
  6521.  
  6522. void PxFan::Collide(CGObject* Obj, int type)
  6523. {
  6524. if(Obj->ClType == OC_Landscape && Planted == false)
  6525. {
  6526. SpX = 0;
  6527. SpY = 0;
  6528. Planted = true;
  6529.  
  6530. return;
  6531. }
  6532.  
  6533. SpX = SpX * BounceMultiplierX;
  6534. SpY = SpY * BounceMultiplierY;
  6535.  
  6536. super;
  6537. }
  6538.  
  6539. // Applies blast damage
  6540. // x, y : origin of the explosion
  6541. // dmg : maximum damage the explosion should do
  6542. void PxFan::TakeExplosionDamage(fixed x, fixed y, int dmg)
  6543. {
  6544. if(dmg == 0) return;
  6545.  
  6546. float fdmg = dmg;
  6547. float dx = PosX - x;
  6548. float dy = PosY - y;
  6549.  
  6550. float distsqr = dx*dx + dy*dy;
  6551. float fdmgsqr = fdmg*fdmg*4.0;
  6552.  
  6553. fdmg = (1.0 - distsqr/fdmgsqr) * fdmg;
  6554. dmg = fdmg;
  6555.  
  6556. if(dmg > 0) TakeDamage(0, dmg);
  6557. }
  6558.  
  6559. // Applies direct damage (without any further calculation)
  6560. // type should be always 0 (10 is for percentage-based damage and is reserved to the Battle Axe)
  6561. void PxFan::TakeDamage(int type, int dmg)
  6562. {
  6563. PrintMessage(type);
  6564. if(type == 10)
  6565. {
  6566. fixed fdmg = dmg;
  6567. fdmg = Health * fdmg / 100.0;
  6568. dmg = fdmg;
  6569. }
  6570.  
  6571. Health -= dmg;
  6572. }
  6573.  
  6574. // Called when the object is destroyed
  6575. void PxFan::Explode()
  6576. {
  6577. if(Removed) return;
  6578.  
  6579. DoExplosion(PosX,PosY-20, ExplosionBlast, ExplosionDamage, 0, 0);
  6580. SpeedDivider = 1000;
  6581. SpX = 0.0;
  6582. SpY = 0.0;
  6583. GravityFactor = 0.0;
  6584. IsMaterial = false;
  6585. WIND_M->UpdateWind();
  6586. }
  6587.  
  6588. void PxFan::PushArrow()
  6589. {
  6590. if(NumArrows<6)
  6591. {
  6592. Arrows[NumArrows] = 0;
  6593. NumArrows = NumArrows + 1;
  6594. }
  6595. }
  6596.  
  6597. void PxFan::PopArrow()
  6598. {
  6599. if(NumArrows>0)
  6600. {
  6601. NumArrows = NumArrows - 1;
  6602. for(int i = 0; i < NumArrows; i+=1)
  6603. {
  6604. Arrows[i] = Arrows[i+1];
  6605. }
  6606. }
  6607. }
  6608.  
  6609. // Renders the object
  6610. void PxFan::Draw()
  6611. {
  6612. int baseX = PosX + BaseOffsetX;
  6613. int baseY = PosY + BaseOffsetY;
  6614.  
  6615. // Body
  6616. if(BaseSide < 0)
  6617. {
  6618. AddSpriteEx(ZPlane+0.03, baseX, baseY, 262144 + SpriteBody, 0, 0, TurretScale);
  6619. }
  6620. else
  6621. {
  6622. AddSpriteEx(ZPlane+0.03, baseX, baseY, SpriteBody, 0, 0, TurretScale);
  6623. }
  6624.  
  6625. // Blades
  6626. float r;
  6627. float g;
  6628. float b;
  6629.  
  6630. int TeamColor;
  6631.  
  6632. if (OwnerTeam < 1)
  6633. {
  6634. TeamColor = 0;
  6635. }
  6636. else
  6637. {
  6638. TeamColor = GetTeamColor(OwnerTeam) + 1;
  6639. }
  6640.  
  6641. if (TeamColor == 1)
  6642. {
  6643. r = 0.55;
  6644. g = 0.15;
  6645. b = 0.15;
  6646. }
  6647. else if (TeamColor == 2)
  6648. {
  6649. r = 0.15;
  6650. g = 0.15;
  6651. b = 0.55;
  6652. }
  6653. else if (TeamColor == 3)
  6654. {
  6655. r = 0.15;
  6656. g = 0.55;
  6657. b = 0.15;
  6658. }
  6659. else if (TeamColor == 4)
  6660. {
  6661. r = 0.50;
  6662. g = 0.50;
  6663. b = 0.15;
  6664. }
  6665. else if (TeamColor == 5)
  6666. {
  6667. r = 0.50;
  6668. g = 0.15;
  6669. b = 0.50;
  6670. }
  6671. else if (TeamColor == 6)
  6672. {
  6673. r = 0.15;
  6674. g = 0.50;
  6675. b = 0.50;
  6676. }
  6677. else
  6678. {
  6679. r = 0.4;
  6680. g = 0.4;
  6681. b = 0.4;
  6682. }
  6683.  
  6684. if(Sinking)
  6685. {
  6686. r = r * (90.0 / 255.0);
  6687. g = g * (90.0 / 255.0);
  6688. b = b * (240.0 / 255.0);
  6689. ClearColorMod();
  6690. }
  6691.  
  6692. SetColorMod(RGB(r * 255.0, g * 255.0, b * 255.0), 6);
  6693.  
  6694. float turretX = 0;
  6695. float turretY = baseY+TurretScale*BladeOffsetY;
  6696.  
  6697. local bladespr = SpriteBlade;
  6698. if(AnimSpeed <= 0.0) bladespr = SpriteBladeIdle;
  6699.  
  6700. local bladescale = TurretScale;
  6701. if(FanMode > 0) bladescale = bladescale * 1.25;
  6702.  
  6703. if(BaseSide < 0)
  6704. {
  6705. turretX = baseX-TurretScale*BladeOffsetX;
  6706. AddSpriteEx(ZPlane+0.02, turretX, turretY, 262144 + bladespr, AnimCycle, 0, bladescale);
  6707. }
  6708. else
  6709. {
  6710. turretX = baseX+TurretScale*BladeOffsetX;
  6711. AddSpriteEx(ZPlane+0.02, turretX, turretY, bladespr, AnimCycle, 0, bladescale);
  6712. }
  6713.  
  6714. ClearColorMod();
  6715.  
  6716. // Arrows
  6717. if(NumArrows>0)
  6718. {
  6719. CQuad q;
  6720.  
  6721. local scale = TurretScale * ArrowScale;
  6722.  
  6723. for(local i = 0; i < NumArrows; i+=1)
  6724. {
  6725. float dist = Arrows[i] * 0.1;
  6726. float alpha = 255.0 * (-4 * dist * (dist - ArrowDistance)) / (ArrowDistance * ArrowDistance);
  6727.  
  6728. FillSpriteQuad(&q, SpriteArrow, 0, 0);
  6729. if(BaseSide < 0)
  6730. {
  6731. TransformQuad(&q, 0, -scale, scale, turretX + BaseSide * dist, turretY);
  6732. }
  6733. else
  6734. {
  6735. TransformQuad(&q, 0, scale, scale, turretX + BaseSide * dist, turretY);
  6736. }
  6737.  
  6738. for(int k=0 ; k<4 ; k+=1) q.v[k].color = ARGB(alpha,255,200,40);
  6739.  
  6740. AddSpriteQ(ZPlane+0.01, &q, SpriteArrow, 0, 64);
  6741. }
  6742. }
  6743.  
  6744. // Grate
  6745. if(FanMode == 0)
  6746. {
  6747. if(BaseSide < 0)
  6748. {
  6749. AddSpriteEx(ZPlane, baseX-TurretScale*GrateOffsetX, baseY+TurretScale*GrateOffsetY, 262144 + SpriteGrate, 0, 0, TurretScale);
  6750. }
  6751. else
  6752. {
  6753. AddSpriteEx(ZPlane, baseX+TurretScale*GrateOffsetX, baseY+TurretScale*GrateOffsetY, SpriteGrate, 0, 0, TurretScale);
  6754. }
  6755. }
  6756. }
  6757.  
  6758. void PxFan::DoAnimation()
  6759. {
  6760. if(Removed) return;
  6761.  
  6762. // Animating arrows
  6763. if(NumArrows>0)
  6764. {
  6765. for(local i = 0; i < NumArrows; i+=1)
  6766. {
  6767. Arrows[i] += ArrowSpeed;
  6768. }
  6769. if(Arrows[0] >= (ArrowDistance*10)) PopArrow();
  6770. }
  6771.  
  6772. if(IsActive())
  6773. {
  6774. if(TargetAnimSpeed <= 0.0)
  6775. {
  6776. TargetAnimSpeed = MaxAnimSpeed;
  6777. }
  6778.  
  6779. if(NextArrow <= 0)
  6780. {
  6781. PushArrow();
  6782. NextArrow = ArrowPeriod;
  6783. }
  6784. else
  6785. {
  6786. NextArrow = NextArrow - 1;
  6787. }
  6788. }
  6789. else
  6790. {
  6791. if(TargetAnimSpeed > 0.0)
  6792. {
  6793. TargetAnimSpeed = 0.0;
  6794. }
  6795. }
  6796.  
  6797. // Spinning blades
  6798.  
  6799. if(AnimSpeed > (TargetAnimSpeed + AnimAccel))
  6800. {
  6801. AnimSpeed -= AnimAccel;
  6802. }
  6803. else if(AnimSpeed < (TargetAnimSpeed - AnimAccel))
  6804. {
  6805. AnimSpeed += AnimAccel;
  6806. }
  6807. else
  6808. {
  6809. AnimSpeed = TargetAnimSpeed;
  6810. }
  6811.  
  6812. AnimCycle = AnimCycle + AnimSpeed;
  6813. if(AnimCycle >= 1.0) AnimCycle -= 1.0;
  6814. }
  6815.  
  6816. void PxFan::CheckBladeCollision()
  6817. {
  6818. if(FanMode == 0) return;
  6819. if(IsActive() == false) return;
  6820.  
  6821. if(NextBladeCooldown > 0)
  6822. {
  6823. NextBladeCooldown -= 1;
  6824. return;
  6825. }
  6826.  
  6827. CGObject *obj;
  6828.  
  6829. for(i = 0; i < Env->Objs.Count; i += 1)
  6830. {
  6831. obj = CGObject(Env->Objs.Objs[i]);
  6832. if(obj == this) continue;
  6833. if(obj == NullObj) continue;
  6834.  
  6835. if(MASK_FANBLADE_DMG->Check(BladePosX+5*BaseSide+6, BladePosY+14, obj->ColMask, obj->PosX, obj->PosY))
  6836. {
  6837. float damage = 0;
  6838. bool hit = false;
  6839.  
  6840. if(obj->ClType == OC_Worm)
  6841. {
  6842. local worm = CWorm(obj);
  6843. // Reduce damage taken from consecutive hits to prevent worms from taking too much damage when stuck between a wall and a fan
  6844. damage = DamagePerBladeHit - worm->FanDamageReducer;
  6845. if(damage < 1)
  6846. damage = 1;
  6847. else
  6848. worm->FanDamageReducer += DamageReductionPerHit;
  6849.  
  6850. hit = true;
  6851. }
  6852. else if(obj->ClType == OC_Missile)
  6853. {
  6854. hit = true;
  6855. }
  6856. else if(obj->ClType == OC_Mine)
  6857. {
  6858. damage = DamagePerBladeHit;
  6859. hit = true;
  6860. }
  6861. else if(obj is CMagnet)
  6862. {
  6863. damage = DamagePerBladeHit;
  6864. hit = true;
  6865. }
  6866. else if(obj->ClType == OC_OilDrum)
  6867. {
  6868. damage = 100;
  6869. hit = true;
  6870. }
  6871. else if(obj->ClType == OC_Crate)
  6872. {
  6873. damage = 100;
  6874. hit = true;
  6875. }
  6876.  
  6877. if(hit)
  6878. {
  6879. float ang = RandomFloat(-1.57079, 1.57079);
  6880. if(BaseSide < 0) ang += 3.14159;
  6881.  
  6882. float ForceX = cos(ang) * BladeHitForce;
  6883. float ForceY = -sin(ang) * BladeHitForce;
  6884.  
  6885. if(damage > 0)
  6886. {
  6887. CMessageData msg;
  6888. msg.params[0] = 0;
  6889. msg.fparams[1] = PosX;
  6890. msg.fparams[2] = PosY;
  6891. msg.fparams[3] = ForceX;
  6892. msg.fparams[4] = ForceY;
  6893. msg.params[5] = damage;
  6894. msg.params[6] = 0;
  6895.  
  6896. obj->Message(this, M_GUNEXP, 1032, &msg);
  6897. }
  6898. else
  6899. {
  6900. obj->SpX += ForceX;
  6901. obj->SpY += ForceY;
  6902. }
  6903.  
  6904. local p = new PxParticle(81, BladePosX, BladePosY);
  6905. p->SetLifeTime(15);
  6906. p->SetVelocity(0,0);
  6907. p->SetStartAlpha(255);
  6908. p->SetEndAlpha(255);
  6909.  
  6910. PlayLocalSound(85, 5, 1.0, 1.0);
  6911.  
  6912. TakeDamage(1, DamageTakenPerBladeHit);
  6913.  
  6914. NextBladeCooldown = BladeCooldown;
  6915. }
  6916. }
  6917. }
  6918. }
  6919.  
  6920. void PxFan::Message(CObject* sender, EMType Type, int MSize, CMessageData* MData)
  6921. {
  6922. // Drawing operations are done here
  6923. if(Type == M_DRAWQUEUE)
  6924. {
  6925. //if(Removed) return;
  6926.  
  6927. if(Sinking) SetColorMod(RGB(90, 90, 240), 6);
  6928.  
  6929. Draw();
  6930.  
  6931. if(Sinking) ClearColorMod();
  6932.  
  6933. // Recalculate Z plane periodically to make sure magnets are drawn properly when overlapping each other
  6934. if(NextRecalcZPlane <= 0)
  6935. {
  6936. local matches = 0;
  6937.  
  6938. for(local i = 1; i < Env->Objs.Count; i+=1)
  6939. {
  6940. local obj = Env->Objs.Objs[i];
  6941.  
  6942. if(obj == NullObj) continue;
  6943. if(obj == this) continue;
  6944. if(obj is PxFan)
  6945. {
  6946. local fanobj = PxFan(obj);
  6947.  
  6948. float dX = fanobj->PosX - PosX;
  6949. float dY = fanobj->PosY - PosY;
  6950. float r2 = dX*dX + dY*dY;
  6951.  
  6952. if(r2 < 900.0)
  6953. {
  6954. if(fanobj->ZPlane == ZPlane)
  6955. {
  6956. fanobj->ZPlane = fanobj->ZPlane + 0.1;
  6957. }
  6958. matches = matches + 1;
  6959. }
  6960. }
  6961. }
  6962.  
  6963. if(matches == 0) ZPlane = 10;
  6964.  
  6965. NextRecalcZPlane = 200;
  6966. }
  6967. else
  6968. {
  6969. NextRecalcZPlane = NextRecalcZPlane - 1;
  6970. }
  6971.  
  6972. return;
  6973. }
  6974.  
  6975. // Damage handling
  6976. if(Removed==false)
  6977. {
  6978. if(Type == M_EXPLOSION)
  6979. {
  6980. TakeExplosionDamage(MData->fparams[1], MData->fparams[2], MData->params[4]);
  6981. }
  6982. if(Type == M_GUNEXP)
  6983. {
  6984. TakeDamage(MData->params[0], MData->params[5]);
  6985. }
  6986. }
  6987.  
  6988. super;
  6989.  
  6990. // This is done every frame (derp)
  6991. if(Type == M_FRAME)
  6992. {
  6993. UpdateBladePosition();
  6994. DoAnimation();
  6995.  
  6996. if(Removed)
  6997. {
  6998. //if(NumArrows <= 0) Free(true);
  6999. Free(true);
  7000. return;
  7001. }
  7002. else
  7003. {
  7004. if(Sinking)
  7005. {
  7006. if(IsActive())
  7007. {
  7008. TurnsRemaining = 0;
  7009. WIND_M->UpdateWind();
  7010. }
  7011. }
  7012.  
  7013. if(IsActive() && (FanMode > 0))
  7014. {
  7015. CheckBladeCollision();
  7016. }
  7017.  
  7018. if(Health <= 0)
  7019. {
  7020. Explode();
  7021. Removed = true;
  7022. }
  7023. }
  7024. }
  7025. }
  7026.  
  7027. ///////////////////////////////////////////////////
  7028. // CTurnGame overrides
  7029.  
  7030. override void CTurnGame::SetCurrentTeam(int Team)
  7031. {
  7032. super;
  7033.  
  7034. // Call OnTurnBegin on all fans
  7035. for(local i = 1; i < Env->Objs.Count; i+=1)
  7036. {
  7037. local obj = Env->Objs.Objs[i];
  7038.  
  7039. if(obj == NullObj) continue;
  7040. if(obj->ClType == OC_Worm)
  7041. {
  7042. // Reset damage reducer for all worms
  7043. CWorm *w = CWorm(obj);
  7044. w->FanDamageReducer = 0;
  7045. }
  7046. else if(obj is PxFan)
  7047. {
  7048. PxFan *fanobj = PxFan(obj);
  7049. fanobj->OnTurnBegin(Team);
  7050. }
  7051. }
  7052.  
  7053. // Resetting wind
  7054. WIND_M->InitWind();
  7055. WIND_M->UpdateWind();
  7056.  
  7057. // Undoing permanent fan delays set up after placing a safe fan
  7058. if(WEAPONINDEX_FAN >= 0)
  7059. {
  7060. local team = GetTeamColor(Team);
  7061. GS->Info.Stores[team].Delay[WEAPONINDEX_FAN] = 0;
  7062. }
  7063. }
  7064.  
  7065. ///////////////////////////////////////////////////
  7066. // CWorm overrides
  7067.  
  7068. override CWorm::CWorm(CObject* Parent, int aTeam, int aIndex, CWormParams* params)
  7069. {
  7070. super;
  7071. FanForce = 3;
  7072. FanMode = 0;
  7073. FanDamageReducer = 0;
  7074. }
  7075.  
  7076. override void CWorm::FireFinal(CWeapon* Weap, CShootDesc* Desc)
  7077. {
  7078. if(Weap->CheckName("Fan"))
  7079. {
  7080. local ang = (1 - FireAngle) * 3.14159;
  7081. if (TurnSide < 0)
  7082. {
  7083. ang = 6.28318 - ang;
  7084. }
  7085.  
  7086. CShootDesc SDesc;
  7087. zero(&SDesc);
  7088.  
  7089. local BaseForce = 0.3;
  7090.  
  7091. SDesc.Team = WormTeam;
  7092. SDesc.X = PosX;
  7093. SDesc.Y = PosY;
  7094. SDesc.SpX = SpX * 0.5 + TurnSide * BaseForce;
  7095. SDesc.SpY = SpY * 0.5 - 0.15;
  7096.  
  7097. new PxFan(GetObject(25, 0), &SDesc, FanForce, FanMode, TurnSide);
  7098.  
  7099. //PrintMessage(GS->Info.Stores[WormTeam-1].Count[index]);
  7100. if(FanMode == 0)
  7101. {
  7102. // Give the weapon a 1 turn delay so that you can't drop more than one fan in the same turn
  7103. local index = Weap->GetWeaponIndex()+2;
  7104. WEAPONINDEX_FAN = index;
  7105.  
  7106. local team = GetTeamColor(WormTeam);
  7107. GS->Info.Stores[team].Delay[index] = -1;
  7108. }
  7109. }
  7110. else
  7111. {
  7112. super;
  7113. }
  7114. }
  7115.  
  7116. void ShowFanMessage(int mode, int force)
  7117. {
  7118. if(mode)
  7119. {
  7120. ShowMessage(MakeNumberString("Fan, Force ", force, ", UNSAFE Mode"));
  7121. }
  7122. else
  7123. {
  7124. ShowMessage(MakeNumberString("Fan, Force ", force, ", SAFE Mode"));
  7125. }
  7126. }
  7127.  
  7128. override void CWorm::Message(CObject* sender, EMType Type, int MSize, CMessageData* MData)
  7129. {
  7130. if(Type == M_FRAME)
  7131. {
  7132. if (CurWeapon->CheckName("Fan"))
  7133. {
  7134. local Team = CTeam(GetObject(21, WormTeam));
  7135. Team->AllowSelectBounce = true;
  7136. Team->AllowSelectDelay = true;
  7137.  
  7138. if(FanMode == 0)
  7139. {
  7140. // Placing a fan in safe mode does not end turn
  7141. CurWeapon->EndsTurn = false;
  7142. }
  7143. else
  7144. {
  7145. // Placing a fan in unsafe mode ends the current turn because it can potentially deal damage
  7146. CurWeapon->EndsTurn = true;
  7147. }
  7148. }
  7149. }
  7150. else if (Type == M_SETBOUNCE)
  7151. {
  7152. if (CurWeapon->CheckName("Fan"))
  7153. {
  7154. if(MData->GetParameter(1) != WormNumber) return;
  7155. local mode = MData->GetParameter(2);
  7156. FanMode = mode;
  7157. ShowFanMessage(FanMode, FanForce);
  7158.  
  7159. return;
  7160. }
  7161. }
  7162. else if(Type == M_SETDELAY)
  7163. {
  7164. if (CurWeapon->CheckName("Fan"))
  7165. {
  7166. if(MData->GetParameter(1) != WormNumber) return;
  7167. local force = MData->GetParameter(2)+1;
  7168. FanForce = force;
  7169. ShowFanMessage(FanMode, FanForce);
  7170. return;
  7171. }
  7172. }
  7173.  
  7174. super;
  7175. }
  7176. PXS : Library Code :
  7177. require utils;
  7178.  
  7179. //#GLIDER_DEBUG
  7180. //#GLIDER_NOANGLECONSTRAINT
  7181. #WEAPON_GLIDER
  7182.  
  7183. //////////////////////////
  7184. // Global variables
  7185.  
  7186. float GliderGravityFactor;
  7187. float GliderWindFactor;
  7188. float GliderFriction;
  7189. float GliderMaxAngularVelocity;
  7190. float GliderMaxTurningSpeed;
  7191. float GliderAnimSpeed;
  7192. float GliderRotationLerp;
  7193. float GliderMoveAcceleration;
  7194.  
  7195. CSprite* wormGliderSprite;
  7196. CSprite* wormGliderBakSprite;
  7197.  
  7198. //////////////////////////
  7199. // Global initializations
  7200. void paratest::FirstFrame()
  7201. {
  7202. // Tweaks
  7203. GliderGravityFactor = 0.75;
  7204. GliderWindFactor = 3.0;
  7205. GliderFriction = 0.25;
  7206. GliderMaxAngularVelocity = 0.06;
  7207. GliderMaxTurningSpeed = 20.0;
  7208. GliderAnimSpeed = 0.04;
  7209. GliderRotationLerp = 0.03;
  7210. GliderMoveAcceleration = 0.02;
  7211. }
  7212.  
  7213. void paratest::InitGraphic()
  7214. {
  7215. CFile *f;
  7216. f = GetAttachment("wgldlnk.png"); wormGliderSprite = LoadSprite(f, 10, 0);
  7217. f = GetAttachment("wgldbak.png"); wormGliderBakSprite = LoadSprite(f, 6, 24);
  7218. }
  7219.  
  7220. //////////////////////////
  7221. // CWormGlider
  7222.  
  7223. CWormGlider::CWormGlider(CWorm *owner)
  7224. {
  7225. GliderAnimCycle = 0.0;
  7226. GliderAng = 0.0;
  7227. GliderTargetAng = 0.0;
  7228. ParaSpX = 0.0;
  7229. ParaSpY = 0.0;
  7230.  
  7231. Deployed = false;
  7232. Enabled = false;
  7233.  
  7234. Owner = owner;
  7235. PRegister(&Owner);
  7236.  
  7237. // Angle system used for the Hang-Glider
  7238. // -pi/2
  7239. // -
  7240. //
  7241. // 0 <-----|
  7242. //
  7243. // +
  7244. // +pi/2
  7245. //
  7246. // positive angle = facing down
  7247. // negative angle = facing up
  7248. }
  7249.  
  7250. void CWormGlider::OnStartGliding()
  7251. {
  7252. GliderAng = 0.0;
  7253. GliderTargetAng = 0.0;
  7254. GliderAnimCycle = 0.0;
  7255. }
  7256.  
  7257. void CWormGlider::OnStopGliding()
  7258. {
  7259. GliderAng = 0.0;
  7260. GliderTargetAng = 0.0;
  7261. GliderAnimCycle = 0.0;
  7262. }
  7263.  
  7264. void CWormGlider::Think()
  7265. {
  7266. // Owner was deleted, don't do anything
  7267. if(Owner == NullObj)
  7268. {
  7269. PUnregister(&Owner);
  7270. return;
  7271. }
  7272.  
  7273. // Which kind of parachute is currently used?
  7274. if(Owner->ObjState != WS_PARACHUTE)
  7275. {
  7276. if(Owner->CurWeapon->CheckName("Hang-Glider"))
  7277. {
  7278. Enabled = true;
  7279. }
  7280. else if(Owner->CurWeapon->CheckName("Parachute"))
  7281. {
  7282. Enabled = false;
  7283. }
  7284. }
  7285.  
  7286. if(Owner->ObjState == WS_PARACHUTE)
  7287. {
  7288. if(Enabled)
  7289. {
  7290. // Worm just entered parachute state while having the Hang-Glider equipped, start the physics overrides
  7291. if(Deployed == false)
  7292. {
  7293. Deployed = true;
  7294. OnStartGliding();
  7295. }
  7296. // Invisible animation (prevents the worm from being drawn using the default method)
  7297. Owner->Anim->Reset();
  7298. Owner->Anim->SetAnimEx(136, 0.0);
  7299. }
  7300. else
  7301. {
  7302. // Using regular Parachute, don't do anything
  7303. return;
  7304. }
  7305. }
  7306. else
  7307. {
  7308. // Worm left parachute state, stop the physics overrides
  7309. if(Deployed)
  7310. {
  7311. Deployed = false;
  7312. OnStopGliding();
  7313. }
  7314.  
  7315. // Always keep track of the worm's current velocity (so it is transmitted to the glider when it becomes deployed)
  7316. ParaSpX = Owner->SpX;
  7317. ParaSpY = Owner->SpY;
  7318.  
  7319. return;
  7320. }
  7321.  
  7322. ////////////////////////////////////
  7323. // Main physics calculations
  7324.  
  7325. // Calculating up and forward relative vectors
  7326. float ang;
  7327. if(Owner->TurnSide < 0)
  7328. {
  7329. ang = GliderAng;
  7330. }
  7331. else
  7332. {
  7333. ang = 3.141593 - GliderAng;
  7334. }
  7335.  
  7336. float ForwardX = -cos(ang);
  7337. float ForwardY = sin(ang);
  7338.  
  7339. float UpX;
  7340. float UpY;
  7341. if(Owner->TurnSide < 0)
  7342. {
  7343. UpX = -ForwardY;
  7344. UpY = ForwardX;
  7345. }
  7346. else
  7347. {
  7348. UpX = ForwardY;
  7349. UpY = -ForwardX;
  7350. }
  7351.  
  7352. // Applying gravity
  7353. ParaSpY = ParaSpY + GS->env->Gravity * GliderGravityFactor;
  7354.  
  7355. // Applying wind
  7356. float WindVel = UpX * GS->env->Wind * GliderWindFactor;
  7357. ParaSpX = ParaSpX + WindVel * UpX;
  7358. ParaSpY = ParaSpY + WindVel * UpY;
  7359.  
  7360. // Applying air resistance
  7361. float UpVel = ParaSpX * UpX + ParaSpY * UpY;
  7362. ParaSpX = ParaSpX - UpX * UpVel * GliderFriction;
  7363. ParaSpY = ParaSpY - UpY * UpVel * GliderFriction;
  7364.  
  7365. // Don't go backwards
  7366. //if(ParaSpX * Owner->TurnSide < 0)
  7367. //{
  7368. // ParaSpX = 0;
  7369. //}
  7370.  
  7371. // Calculating new glider angle based on current speed
  7372. if(Owner->TurnSide < 0)
  7373. {
  7374. ang = atan2(ParaSpY, -ParaSpX);
  7375. }
  7376. else
  7377. {
  7378. ang = atan2(ParaSpY, ParaSpX);
  7379. }
  7380.  
  7381. // Normalize
  7382. ang = NormalizeAngle(ang);
  7383.  
  7384. // Clamp to approx. [-80° ; 80°] (don't fly straight down when nose-diving)
  7385. if(#GLIDER_NOANGLECONSTRAINT) { }
  7386. else
  7387. {
  7388. if(ang > 1.5) ang = 1.5;
  7389. if(ang < -1.5) ang = -1.5;
  7390. }
  7391.  
  7392. GliderTargetAng = ang;
  7393.  
  7394. // Approach the target angle
  7395. GliderAng = LerpAngle(GliderRotationLerp, GliderAng, GliderTargetAng);
  7396.  
  7397. if(#GLIDER_DEBUG)
  7398. {
  7399. // DEBUG1 : GliderAng
  7400. Debug1X = Owner->PosX + 40*ForwardX;
  7401. Debug1Y = Owner->PosY + 40*ForwardY;
  7402.  
  7403. // DEBUG2 : GliderTargetAng
  7404. if(Owner->TurnSide < 0)
  7405. {
  7406. ang = GliderTargetAng;
  7407. }
  7408. else
  7409. {
  7410. ang = 3.141593 - GliderTargetAng;
  7411. }
  7412.  
  7413. ForwardX = -cos(ang);
  7414. ForwardY = sin(ang);
  7415. Debug2X = Owner->PosX + 40*ForwardX;
  7416. Debug2Y = Owner->PosY + 40*ForwardY;
  7417.  
  7418. // END DEBUG
  7419. }
  7420.  
  7421. // Animation
  7422. GliderAnimCycle = GliderAnimCycle + GliderAnimSpeed;
  7423. if(GliderAnimCycle >= 1.0) GliderAnimCycle = 1.0;
  7424.  
  7425. // Going to hit an obstacle, stop gliding
  7426. int hitX;
  7427. int hitY;
  7428. if(TraceMask(Owner, Owner->ColMask, Owner->PosX, Owner->PosY, Owner->PosX + 1.1 * ParaSpX, Owner->PosY + 1.1 * ParaSpY, 4332670, &hitX, &hitY) != NullObj)
  7429. {
  7430. Owner->SetState(WS_AFTERROPE);
  7431. }
  7432.  
  7433. // Update the worm's velocity
  7434. Owner->SpX = ParaSpX;
  7435. Owner->SpY = ParaSpY;
  7436. }
  7437.  
  7438. void CWormGlider::Render()
  7439. {
  7440. if(Deployed)
  7441. {
  7442. if(Owner->TurnSide < 0)
  7443. {
  7444. Owner->AddSpriteEx(6, Owner->PosX, Owner->PosY, wormGliderSprite->Index, GliderAnimCycle, -GliderAng, 1.0);
  7445. }
  7446. else
  7447. {
  7448. Owner->AddSpriteEx(6, Owner->PosX, Owner->PosY, wormGliderSprite->Index + 262144, GliderAnimCycle, GliderAng, 1.0);
  7449. }
  7450.  
  7451. if(#GLIDER_DEBUG)
  7452. {
  7453. Owner->AddSpriteEx(7, Debug1X, Debug1Y, 2, 0, 0, 1);
  7454. Owner->AddSpriteEx(7.1, Debug2X, Debug2Y, 3, 0, 0, 1);
  7455. }
  7456. }
  7457. }
  7458.  
  7459. void CWormGlider::Move(EMType Type)
  7460. {
  7461. if(Type == M_PUP)
  7462. {
  7463. // Rotate up
  7464. float vel = sqrt(ParaSpX*ParaSpX + ParaSpY*ParaSpY) / GliderMaxTurningSpeed;
  7465. if(vel > 1.0) vel = 1.0;
  7466.  
  7467. GliderAng -= GliderMaxAngularVelocity * vel;
  7468.  
  7469. if(#GLIDER_NOANGLECONSTRAINT) { }
  7470. else if(GliderAng < -1.5)
  7471. {
  7472. GliderAng = -1.5;
  7473. }
  7474. }
  7475. else if(Type == M_PDOWN)
  7476. {
  7477. // Rotate down
  7478. float vel = sqrt(ParaSpX*ParaSpX + ParaSpY*ParaSpY) / GliderMaxTurningSpeed;
  7479. if(vel < 0.5) vel = 0.5;
  7480. if(vel > 1.0) vel = 1.0;
  7481.  
  7482. GliderAng += GliderMaxAngularVelocity * vel;
  7483.  
  7484. if(#GLIDER_NOANGLECONSTRAINT) { }
  7485. else
  7486. if(GliderAng > 1.5)
  7487. {
  7488. GliderAng = 1.5;
  7489. }
  7490. }
  7491.  
  7492. if(Type == M_PLEFT)
  7493. {
  7494. // Left acceleration
  7495. ParaSpX -= GliderMoveAcceleration;
  7496. }
  7497. else if(Type == M_PRIGHT)
  7498. {
  7499. // Right acceleration
  7500. ParaSpX += GliderMoveAcceleration;
  7501. }
  7502. }
  7503.  
  7504. ///////////////////////////
  7505. // CWorm overrides
  7506.  
  7507. override CWorm::CWorm(CObject* Parent, int aTeam, int aIndex, CWormParams* params)
  7508. {
  7509. super;
  7510. Glider = new CWormGlider(this);
  7511. }
  7512.  
  7513. override void CWorm::Message(CObject* sender, EMType Type, int MSize, CMessageData* MData)
  7514. {
  7515. if(Type == M_FRAME)
  7516. {
  7517. Glider->Think();
  7518. }
  7519.  
  7520. if(Type == M_DRAWQUEUE)
  7521. {
  7522. if(Glider->Deployed)
  7523. {
  7524. Glider->Render();
  7525. //return;
  7526. }
  7527. }
  7528.  
  7529. if(Type == M_PUP || Type == M_PDOWN || Type == M_PLEFT || Type == M_PRIGHT)
  7530. {
  7531. if(Glider->Deployed)
  7532. {
  7533. Glider->Move(Type);
  7534. }
  7535. }
  7536.  
  7537. super;
  7538. }
  7539.  
  7540. ///////////////////////////////////////////////////
  7541. // CSpriteAnim overrides
  7542.  
  7543. override void CSpriteAnim::SetAnimEx(int sindex, fixed frame)
  7544. {
  7545. // Make sure the game has actually started (otherwise GetCurrentWorm would crash the game due to Root not existing)
  7546. if(GS->Tick >= 1)
  7547. {
  7548. // If we belong to the current worm
  7549. CWorm *w = GetCurrentWorm();
  7550. if(w != NullObj && w->Anim == this)
  7551. {
  7552. if(sindex == 289 && w->Glider->Enabled) // Glider landing animation
  7553. {
  7554. super(wormGliderBakSprite->Index, frame);
  7555. return;
  7556. }
  7557. }
  7558. }
  7559.  
  7560. super;
  7561. }
  7562. PXS : Library Code :
  7563. CQuad __BQ;
  7564. int __BN;
  7565. fixed __BZ;
  7566. fixed __BF;
  7567. int __BT;
  7568. int __BB;
  7569. CObject *__BO;
  7570.  
  7571. CTexBeamPoint::CTexBeamPoint()
  7572. {
  7573. x = 0.0;
  7574. y = 0.0;
  7575. dx = 0.0;
  7576. dy = 0.0;
  7577. texcoord = 0.0;
  7578. color = 0;
  7579. }
  7580.  
  7581. void CTexBeamPoint::Copy(CTexBeamPoint *dest)
  7582. {
  7583. dest->x = x;
  7584. dest->y = y;
  7585. dest->dx = dx;
  7586. dest->dy = dy;
  7587. dest->texcoord = texcoord;
  7588. dest->color = color;
  7589. }
  7590.  
  7591. void CTexBeamPoint::RenderBeamSection(CTexBeamPoint *target)
  7592. {
  7593. __BQ.blend = __BB;
  7594. __BQ.tex = __BT;
  7595.  
  7596. __BQ.v[0].x = x + dx;
  7597. __BQ.v[0].y = y + dy;
  7598. __BQ.v[0].z = __BZ;
  7599. __BQ.v[0].tx = texcoord;
  7600. __BQ.v[0].ty = 0.0;
  7601. __BQ.v[0].color = color;
  7602.  
  7603. __BQ.v[3].x = x - dx;
  7604. __BQ.v[3].y = y - dy;
  7605. __BQ.v[3].z = __BZ;
  7606. __BQ.v[3].tx = texcoord;
  7607. __BQ.v[3].ty = 1.0;
  7608. __BQ.v[3].color = color;
  7609.  
  7610. __BQ.v[1].x = target->x + target->dx;
  7611. __BQ.v[1].y = target->y + target->dy;
  7612. __BQ.v[1].z = __BZ;
  7613. __BQ.v[1].tx = target->texcoord;
  7614. __BQ.v[1].ty = 0.0;
  7615. __BQ.v[1].color = target->color;
  7616.  
  7617. __BQ.v[2].x = target->x - target->dx;
  7618. __BQ.v[2].y = target->y - target->dy;
  7619. __BQ.v[2].z = __BZ;
  7620. __BQ.v[2].tx = target->texcoord;
  7621. __BQ.v[2].ty = 1.0;
  7622. __BQ.v[2].color = target->color;
  7623.  
  7624. __BO->AddSpriteQ(__BZ, &__BQ, __BT, __BF, 64);
  7625. }
  7626.  
  7627. CTexBeamPoint *__BP0;
  7628. CTexBeamPoint *__BP1;
  7629. CTexBeamPoint *__BP2;
  7630. float __BW0;
  7631.  
  7632. void texbeam::InitGraphic()
  7633. {
  7634. __BP0 = new CTexBeamPoint();
  7635. __BP1 = new CTexBeamPoint();
  7636. __BP2 = new CTexBeamPoint();
  7637. }
  7638.  
  7639. void StartTexturedBeam(CObject *parent, fixed z, int tex, fixed frame, int blendmode)
  7640. {
  7641. __BO = parent;
  7642. __BN = 0;
  7643. __BZ = z;
  7644. __BT = tex;
  7645. __BF = frame;
  7646. __BB = blendmode;
  7647. }
  7648.  
  7649. void TexturedBeamPoint(float x, float y, float width, float texcoord, int color)
  7650. {
  7651. __BP0->x = x;
  7652. __BP0->y = y;
  7653. __BP0->texcoord = texcoord;
  7654. __BP0->color = color;
  7655.  
  7656. if(__BN > 0)
  7657. {
  7658. float dx = __BP0->x - __BP1->x;
  7659. float dy = __BP0->y - __BP1->y;
  7660. float d = sqrt(dx*dx+dy*dy);
  7661.  
  7662. // todo: exception handling for two successive beam points at the exact same position. (d=0)
  7663. __BP0->dx = -width * dy / d;
  7664. __BP0->dy = width * dx / d;
  7665.  
  7666. if(__BN == 1)
  7667. {
  7668. __BP1->dx = -__BW0 * dy / d;
  7669. __BP1->dy = __BW0 * dx / d;
  7670. }
  7671. else
  7672. {
  7673. __BP1->dx = (__BP0->dx + __BP2->dx) / 2.0;
  7674. __BP1->dy = (__BP0->dy + __BP2->dy) / 2.0;
  7675.  
  7676. __BP2->RenderBeamSection(__BP1);
  7677. }
  7678. }
  7679.  
  7680. __BN += 1;
  7681. __BP1->Copy(__BP2);
  7682. __BP0->Copy(__BP1);
  7683. __BW0 = width;
  7684. }
  7685.  
  7686. void EndTexturedBeam()
  7687. {
  7688. if(__BN > 0)
  7689. {
  7690. __BP2->RenderBeamSection(__BP1);
  7691. }
  7692. }
  7693.  
  7694. PXS : Library Code :
  7695. require utils, pxparticles, pxtexbeam;
  7696.  
  7697. /////////////////////////////////////////
  7698. // Uses custom message type 1000
  7699. // Sent to objects when hit by lightning
  7700. // params[0] : Lightning type (0 : lightning strike, 1 : tazer)
  7701. // params[1] : Owner team
  7702.  
  7703. CSprite* lightningBeamSprite;
  7704. CSprite* lightningGlowSprite;
  7705.  
  7706. CSoundFile* lightningStartSound;
  7707. CSoundFile* lightningHitSound;
  7708.  
  7709. CColMask* LIGHTNING_HITMASK;
  7710.  
  7711. int LightningR;
  7712. int LightningG;
  7713. int LightningB;
  7714.  
  7715. // Main beam : 17 divisions
  7716. // Sub-beams : 6 * 9 divisions
  7717. // = 71
  7718.  
  7719. //float NoiseTable[71];
  7720.  
  7721. // Main beam : 9 divisions
  7722. // Sub-beams : 6 * 9 divisions
  7723. // = 63
  7724.  
  7725. float NoiseTable[63];
  7726.  
  7727. // Generate this table randomly to decide which point of the main beam will have a sub beam attached to it
  7728. //bool AttachSubBeam[17];
  7729.  
  7730. bool AttachSubBeam[9];
  7731.  
  7732. PxDeadWormManager : CObject;
  7733.  
  7734. PxDeadWormManager *DW_M;
  7735.  
  7736. void lightningstrike::FirstFrame()
  7737. {
  7738. CFile *f;
  7739.  
  7740. f = GetAttachment("lightningthund.wav"); lightningStartSound = new CSoundFile(f);
  7741. f = GetAttachment("lightninghit.wav"); lightningHitSound = new CSoundFile(f);
  7742.  
  7743. LIGHTNING_HITMASK = new CColMask(12, 12, MakeCircleMask(12));
  7744. DW_M = new PxDeadWormManager();
  7745.  
  7746. //LightningR = 160;
  7747. //LightningG = 220;
  7748. //LightningB = 255;
  7749.  
  7750. LightningR = 120;
  7751. LightningG = 140;
  7752. LightningB = 255;
  7753. }
  7754.  
  7755. void lightningstrike::InitGraphic()
  7756. {
  7757. CFile *f;
  7758.  
  7759. f = GetAttachment("lightning_beam.png"); lightningBeamSprite = LoadSprite(f, 1, 0);
  7760. f = GetAttachment("lightning_glow.png"); lightningGlowSprite = LoadSprite(f, 1, 0);
  7761. }
  7762.  
  7763. ///////////////////////////////////////////////////
  7764. // PxDeadWorm (used to resurrect worms from graves)
  7765.  
  7766. PxDeadWorm : CObject
  7767.  
  7768. PxDeadWormManager::PxDeadWormManager()
  7769. {
  7770. super(Root, GS);
  7771. }
  7772.  
  7773. PxDeadWorm* PxDeadWormManager::DeadWormFromGrave(CGObject *grave)
  7774. {
  7775. PxDeadWorm *deadworm;
  7776.  
  7777. for(int i=0 ; i<Childs.Count ; i+=1)
  7778. {
  7779. deadworm = PxDeadWorm(Childs.Objs[i]);
  7780. if(deadworm == PxDeadWorm(NullObj)) continue;
  7781.  
  7782. if(deadworm->GraveObj == grave)
  7783. {
  7784. return deadworm;
  7785. }
  7786. }
  7787.  
  7788. return PxDeadWorm(NullObj);
  7789. }
  7790.  
  7791. PxDeadWorm::PxDeadWorm(CWorm *worm, CGObject *grave)
  7792. {
  7793. super(DW_M, GS);
  7794.  
  7795. GraveObj = grave;
  7796. PRegister(&GraveObj);
  7797.  
  7798. WormNumber = worm->WormNumber;
  7799. WormTeam = worm->WormTeam;
  7800. WormName = worm->GetName();
  7801.  
  7802. ResurrectedWorm = CWorm(NullObj);
  7803.  
  7804. RemoveMe = false;
  7805. }
  7806.  
  7807. void PxDeadWorm::Resurrect(int health)
  7808. {
  7809. if(RemoveMe) return;
  7810. if(GraveObj == CGObject(NullObj)) return;
  7811.  
  7812. ResurrectedWorm = RessurectWormEx(WormNumber, WormTeam, 0, 0, WormName, health);
  7813. ResurrectedWorm->PosX = GraveObj->PosX;
  7814. ResurrectedWorm->PosY = GraveObj->PosY-5;
  7815.  
  7816. ResurrectedWorm->ResurrectedByLightning = true;
  7817.  
  7818. GraveObj->Free(true);
  7819. PUnregister(&GraveObj);
  7820.  
  7821. RemoveMe = true;
  7822. }
  7823.  
  7824. void PxDeadWorm::Message(CObject* sender, EMType Type, int MSize, CMessageData* MData)
  7825. {
  7826. if(Type == M_FRAME)
  7827. {
  7828. if(RemoveMe)
  7829. {
  7830. if(ResurrectedWorm != CWorm(NullObj))
  7831. {
  7832. ResurrectedWorm->ResurrectedByLightning = false;
  7833. }
  7834. Free(true);
  7835. return;
  7836. }
  7837.  
  7838. if(GraveObj == CGObject(NullObj))
  7839. {
  7840. PUnregister(&GraveObj);
  7841. RemoveMe = true;
  7842. return;
  7843. }
  7844. }
  7845.  
  7846. if(Type == M_DRAWQUEUE)
  7847. {
  7848. return;
  7849. }
  7850.  
  7851. super;
  7852. }
  7853.  
  7854. ///////////////////////////////////////////////////
  7855. // PxLightningStrike
  7856.  
  7857. PxLightningStrike : CObject;
  7858.  
  7859. PxLightningStrike::PxLightningStrike(CObject* Parent, CShootDesc* Desc)
  7860. {
  7861. super(Parent, GS);
  7862. ClType = OC_AirStrike;
  7863.  
  7864. // Lightning parameters
  7865. LightningPitch = 30.0;
  7866. LightningMaxDistance = 300.0;
  7867. LightningMinY = -270;
  7868.  
  7869. // Calculate the lightning strike's starting position (where the cloud will appear)
  7870. // and ending position (where the lightning will strike)
  7871.  
  7872. float ang = (LightningPitch * 3.141593) / 180.0;
  7873. DirX = sin(ang);
  7874. DirY = cos(ang);
  7875.  
  7876. if(Desc->SpX < 0) DirX = -DirX;
  7877.  
  7878. // Perform a projection on y = LightningMinY (maximum height at which the lightning cloud can appear)
  7879. float y = LightningMinY;
  7880. float x = Desc->AddX - (Desc->AddY - y) * (DirX / DirY);
  7881.  
  7882. StartX = int(x);
  7883. StartY = int(y);
  7884.  
  7885. LightningHitLand = true;
  7886.  
  7887. // Trace down and get the exact strike position
  7888. int hitX;
  7889. int hitY;
  7890.  
  7891. int tracemask = CMASK_TERRAIN
  7892. | CMASK_WORM_ON_TERRAIN
  7893. | CMASK_WORM_USING_WEAPON
  7894. | CMASK_WORM_IN_MIDAIR
  7895. | CMASK_WORM_ON_ROPE
  7896. | CMASK_WORM_FROZEN
  7897. | CMASK_GASCANISTER
  7898. | CMASK_MINE
  7899. | CMASK_CRATE
  7900. | CMASK_DONORCARD
  7901. | CMASK_GRAVESTONE
  7902. | CMASK_OTHERWEAPON
  7903. | CMASK_OILDRUM;
  7904.  
  7905. if(TraceLine(this, StartX, StartY, StartX + 10000 * DirX, StartY + 10000 * DirY, tracemask, &hitX, &hitY) == NullObj)
  7906. {
  7907. // Didn't hit anything, just spawn the cloud high in the sky and make it strike some arbitrary point
  7908. x = StartX + LightningMaxDistance * DirX;
  7909. y = StartY + LightningMaxDistance * DirY;
  7910. hitX = x;
  7911. hitY = y;
  7912.  
  7913. LightningHitLand = false;
  7914. }
  7915. else
  7916. {
  7917. if(hitY - LightningMaxDistance * DirY > StartY)
  7918. {
  7919. // Hit something but it's too far away from the cloud
  7920. // Move the cloud down accordingly to the hit position
  7921. x = hitX - LightningMaxDistance * DirX;
  7922. y = hitY - LightningMaxDistance * DirY;
  7923. StartX = x;
  7924. StartY = y;
  7925. }
  7926. }
  7927.  
  7928. EndX = hitX;
  7929. EndY = hitY;
  7930.  
  7931. // Must be a multiple of 2 + 1, because we're generating fractal noise
  7932.  
  7933. // this should have been used to allocate the noise table but due to an issue with EAX,
  7934. // the noise table has been declared as a global variable (see line 15)
  7935. //NoiseDivs = (1 << 4) + 1; // 17
  7936. NoiseDivs = (1 << 3) + 1; // 9
  7937. SubNoiseDivs = (1 << 3) + 1; // 9
  7938. MaxSubBeams = (NoiseDivs * 2) / 3;
  7939.  
  7940. GenerateNoise();
  7941.  
  7942. // Timer stuff
  7943. CloudGenerateTimer = 0;
  7944. LightningHitDelay = 150;
  7945. LightningTime = 16;
  7946. PostLightningTime = 60;
  7947.  
  7948. // Internal states
  7949. Dead = false;
  7950. IsFirstFrame = true;
  7951. OwnerTeam = Desc->Team;
  7952. GroundGlowSize = 0.5;
  7953. }
  7954.  
  7955. // Calculates fractal noise from NoiseTable[offset] to NoiseTable[offset+divs-1]
  7956. void PxLightningStrike::CalcNoise(int offset, int divs, float scale, float start, float end)
  7957. {
  7958. int i;
  7959. int k = divs;
  7960. int l = k >> 1;
  7961.  
  7962. for(i=0 ; i<divs ; i+=1) NoiseTable[offset+i] = 0.0;
  7963. NoiseTable[offset] = start;
  7964. NoiseTable[offset+divs-1] = end;
  7965.  
  7966. while(l > 0)
  7967. {
  7968. for(i=l ; i<divs ; i+=k)
  7969. {
  7970. NoiseTable[offset+i] = (NoiseTable[offset+i-l] + NoiseTable[offset+i+l]) * 0.5 + RandomFloat(-scale, scale);
  7971. }
  7972. k = l;
  7973. l = k >> 1;
  7974. }
  7975. }
  7976.  
  7977. // Fills NoiseTable with fractal noise (1 main beam + 6 secondary beams), and generates the secondary beam attachment table
  7978. void PxLightningStrike::GenerateNoise()
  7979. {
  7980. int i;
  7981.  
  7982. CalcNoise(0, NoiseDivs, 1.0, 0.0, 0.0);
  7983.  
  7984. for(i=0 ; i<NoiseDivs ; i+=1) AttachSubBeam[i] = false;
  7985. for(i=0 ; i<MaxSubBeams ; i+=1) AttachSubBeam[RandomInt(1,16)] = true;
  7986.  
  7987. for(i=0 ; i<MaxSubBeams ; i+=1)
  7988. {
  7989. float offset = RandomFloat(2.0,6.0);
  7990. if(RandomInt(0,1) == 0) offset = -offset;
  7991.  
  7992. CalcNoise(NoiseDivs + SubNoiseDivs * i, SubNoiseDivs, 0.5, 0.0, offset);
  7993. }
  7994.  
  7995. GroundGlowSize = RandomFloat(0.5,0.8);
  7996. }
  7997.  
  7998. // Renders one lightning beam using data previously generated by GenerateNoise
  7999. void PxLightningStrike::RenderBeam(int offset, int divs, float width, float endwidth, float scale, float x1, float y1, float x2, float y2, float glowalpha)
  8000. {
  8001. float fraction;
  8002. float x;
  8003. float y;
  8004. float d = divs - 1;
  8005.  
  8006. int i;
  8007. float j;
  8008.  
  8009. float dx = x2-x1;
  8010. float dy = y2-y1;
  8011. float dd = sqrt(dx*dx+dy*dy);
  8012.  
  8013. dx = dx / dd;
  8014. dy = dy / dd;
  8015.  
  8016. StartTexturedBeam(this, 11, lightningBeamSprite->Index, 0.0, 1);
  8017.  
  8018. CQuad q;
  8019.  
  8020. for(i=0 ; i<divs ; i+=1)
  8021. {
  8022. j = i;
  8023. fraction = j / d;
  8024. x = Lerp(fraction, x1, x2) + scale * dy * NoiseTable[offset+i];
  8025. y = Lerp(fraction, y1, y2) - scale * dx * NoiseTable[offset+i];
  8026.  
  8027. float w = Lerp(fraction, width, endwidth);
  8028. float r = LightningR * glowalpha * (1.0 - fraction);
  8029. float g = LightningG * glowalpha * (1.0 - fraction);
  8030. float b = LightningB * glowalpha * (1.0 - fraction);
  8031.  
  8032. TexturedBeamPoint(x, y, w, fraction, RGB(LightningR, LightningG, LightningB));
  8033.  
  8034. FillSpriteQuad(&q, lightningGlowSprite->Index, 0, 0);
  8035. TransformQuad(&q, 0, 0.5, 0.5, x, y);
  8036. q.blend = 1;
  8037. for(int k=0 ; k<4 ; k+=1) q.v[k].color = RGB(r,g,b);
  8038. AddSpriteQ(9.9, &q, lightningGlowSprite->Index, 0, 64);
  8039. }
  8040.  
  8041. EndTexturedBeam();
  8042. }
  8043.  
  8044. // Renders the main lightning beam and its secondary beams
  8045. void PxLightningStrike::RenderLightning()
  8046. {
  8047. if(LightningHitDelay >= 8) return;
  8048.  
  8049. int divs = NoiseDivs;
  8050. float endx = EndX;
  8051. float endy = EndY;
  8052.  
  8053. if(LightningHitDelay > 0)
  8054. {
  8055. float fr = (8.0 - LightningHitDelay) / 8.0;
  8056. float fdivs = NoiseDivs * fr;
  8057. divs = fdivs;
  8058.  
  8059. endx = Lerp(fr, StartX, EndX);
  8060. endy = Lerp(fr, StartY, EndY);
  8061. }
  8062.  
  8063. RenderBeam(0, divs, 35.0, 3.0, 15.0, StartX, StartY, endx, endy, 1.0);
  8064.  
  8065. float fraction;
  8066. float x;
  8067. float y;
  8068. float d = divs - 1;
  8069.  
  8070. int i;
  8071. float j;
  8072.  
  8073. int subBeam = 0;
  8074.  
  8075. for(i=0 ; i<divs ; i+=1)
  8076. {
  8077. if(AttachSubBeam[i])
  8078. {
  8079. j = i;
  8080. fraction = j / d;
  8081. x = Lerp(fraction, StartX, endx) + 10.0 * DirY * NoiseTable[i];
  8082. y = Lerp(fraction, StartY, endy) - 10.0 * DirX * NoiseTable[i];
  8083.  
  8084. RenderBeam(NoiseDivs + SubNoiseDivs * subBeam, SubNoiseDivs, Lerp(fraction, 10.0, 1.0), 0.1, 15.0 * (1.0 - fraction), x, y,
  8085. x + DirX * 100.0 * (1.0 - fraction), y + DirY * 100.0 * (1.0 - fraction), 0.5 * (1.0 - fraction));
  8086.  
  8087. subBeam = subBeam + 1;
  8088. }
  8089. }
  8090.  
  8091. CQuad q;
  8092.  
  8093. FillSpriteQuad(&q, lightningGlowSprite->Index, 0, 0);
  8094. TransformQuad(&q, 0, 1.8, 1.8, StartX+10*DirX, StartY+10*DirY);
  8095. q.blend = 1;
  8096. for(i=0 ; i<4 ; i+=1) q.v[i].color = RGB(LightningR,LightningG,LightningB);
  8097. AddSpriteQ(9.9, &q, lightningGlowSprite->Index, 0, 64);
  8098.  
  8099. if(LightningHitDelay <= 0 && LightningHitLand)
  8100. {
  8101. FillSpriteQuad(&q, lightningGlowSprite->Index, 0, 0);
  8102. TransformQuad(&q, 0, GroundGlowSize, GroundGlowSize, EndX, EndY);
  8103. q.blend = 1;
  8104. for(i=0 ; i<4 ; i+=1) q.v[i].color = RGB(LightningR,LightningG,LightningB);
  8105. AddSpriteQ(9.9, &q, lightningGlowSprite->Index, 0, 64);
  8106. }
  8107. }
  8108.  
  8109. // Applies the lightning strike effect to a particular object
  8110. void PxLightningStrike::LightningHit(CGObject *obj)
  8111. {
  8112. if(#WEAPON_MAGNET)
  8113. {
  8114. if(obj is CMagnet)
  8115. {
  8116. // Recharge magnets
  8117. local mag = CMagnet(obj);
  8118. mag->Recharge();
  8119. return;
  8120. }
  8121. }
  8122.  
  8123. if(#WEAPON_BOWLINGBALL)
  8124. {
  8125. if(obj is CBowlingBall)
  8126. {
  8127. // Overcharge bowling balls
  8128. local ball = CBowlingBall(obj);
  8129. ball->Zap(0);
  8130. return;
  8131. }
  8132. }
  8133.  
  8134. if(#WEAPON_FAN)
  8135. {
  8136. if(obj is PxFan)
  8137. {
  8138. // Recharge magnets
  8139. local fanobj = PxFan(obj);
  8140. fanobj->Recharge();
  8141. return;
  8142. }
  8143. }
  8144.  
  8145. if(#WEAPON_KSENTRY)
  8146. {
  8147. if(obj is PxSentryGun)
  8148. {
  8149. // Changes sentry teams
  8150. local sentry = PxSentryGun(obj);
  8151. sentry->OwnerTeam = OwnerTeam;
  8152. sentry->TurretActive = false;
  8153. return;
  8154. }
  8155. }
  8156.  
  8157. if(obj->ClType == OC_Mine)
  8158. {
  8159. // Trigger mines
  8160. local mine = CMine(obj);
  8161.  
  8162. // If the mine is not a special mine, can be triggered, and has not been triggered yet
  8163. if(mine->Radius > 0 && mine->Active == 0 && mine->Prefuse <= 0)
  8164. {
  8165. // If the mine has a random timer
  8166. if(mine->Fuse < 0)
  8167. {
  8168. // Give it a random fuse time (between 1 and 5)
  8169. mine->Fuse = RandomInt(1000, 5000);
  8170. }
  8171.  
  8172. // Trigger the mine
  8173. mine->Active = 1;
  8174. mine->nPulses = mine->Fuse / 250;
  8175. }
  8176. }
  8177. else if(obj->ClType == OC_OilDrum || obj->ClType == OC_Crate)
  8178. {
  8179. // Blow up oil drums and crates
  8180. CMessageData msg;
  8181. msg.params[0] = 0;
  8182. msg.fparams[1] = EndX;
  8183. msg.fparams[2] = EndY;
  8184. msg.fparams[3] = 0.0;
  8185. msg.fparams[4] = 0.0;
  8186. msg.params[5] = 100;
  8187. msg.params[6] = 0;
  8188.  
  8189. obj->Message(this, M_GUNEXP, 1032, &msg);
  8190. }
  8191. else if(obj->ClType == OC_Worm)
  8192. {
  8193. // Heal worms
  8194. local worm = CWorm(obj);
  8195.  
  8196. if(worm->ResurrectedByLightning == false)
  8197. {
  8198. int health = GS->Info.GetWormHealth(worm->WormTeam, worm->WormNumber);
  8199. GS->Info.SetWormHealth(worm->WormTeam, worm->WormNumber, health + 25);
  8200. }
  8201. }
  8202. else if(obj->ClType == OC_Cross)
  8203. {
  8204. // Resurrect worms from their grave
  8205. local deadworm = DW_M->DeadWormFromGrave(obj);
  8206.  
  8207. if(deadworm != PxDeadWorm(NullObj))
  8208. {
  8209. deadworm->Resurrect(10);
  8210. }
  8211. else
  8212. {
  8213. ShowMessage("Grave has no bound worm, could not resurrect!");
  8214. }
  8215. }
  8216.  
  8217. // Allows any object to define its own custom behaviour
  8218. //CMessageData msg;
  8219. //msg.params[0] = 0;
  8220. //msg.params[1] = OwnerTeam;
  8221. //obj->Message(this, EMType(1000), 1032, &msg);
  8222. }
  8223.  
  8224. // Performs a mask test and applies the lightning strike effect to all detected objects
  8225. void PxLightningStrike::DoLightningStrike()
  8226. {
  8227. CGObject *obj;
  8228.  
  8229. for(int i = 0; i < Env->Objs.Count; i += 1)
  8230. {
  8231. obj = CGObject(Env->Objs.Objs[i]);
  8232. if(obj == NullObj) continue;
  8233.  
  8234. if(LIGHTNING_HITMASK->Check(EndX, EndY, obj->ColMask, obj->PosX, obj->PosY))
  8235. {
  8236. LightningHit(obj);
  8237. }
  8238. }
  8239. }
  8240.  
  8241. void PxLightningStrike::Message(CObject* sender, EMType Type, int MSize, CMessageData* MData)
  8242. {
  8243. if(Type == M_FRAME)
  8244. {
  8245. PxParticle *p;
  8246.  
  8247. if(Dead)
  8248. {
  8249. Free(true);
  8250. return;
  8251. }
  8252.  
  8253. if(IsFirstFrame)
  8254. {
  8255. lightningStartSound->Play(1.0, 0.0, false);
  8256. IsFirstFrame = false;
  8257. }
  8258.  
  8259. if(LightningTime > 0)
  8260. {
  8261. if(LightningHitDelay <= 0)
  8262. {
  8263. GenerateNoise();
  8264.  
  8265. if(LightningHitLand)
  8266. {
  8267. p = new PxParticle(lightningGlowSprite->Index, EndX, EndY);
  8268. p->SetBlendMode(1);
  8269. p->SetLifeTime(50);
  8270. p->SetRandomVelocity(1.0, 3.0);
  8271. p->SetAirResistance(0.0);
  8272. p->GravityFactor(1.0);
  8273. p->SetAlpha(255);
  8274. p->SetColor(LightningR, LightningG, LightningB);
  8275. p->SetStartSize(0.1, 0.1);
  8276. p->SetEndSize(0.01, 0.01);
  8277. }
  8278.  
  8279. LightningTime = LightningTime - 1;
  8280. if(LightningHitLand && LightningTime <= 0)
  8281. {
  8282. DoLightningStrike();
  8283. }
  8284. }
  8285. else
  8286. {
  8287. LightningHitDelay = LightningHitDelay - 1;
  8288. if(LightningHitDelay == 0)
  8289. {
  8290. lightningHitSound->Play(1.0, 0.0, false);
  8291. }
  8292. }
  8293. }
  8294. else
  8295. {
  8296. PostLightningTime = PostLightningTime - 1;
  8297. if(PostLightningTime <= 0)
  8298. {
  8299. Dead = true;
  8300. }
  8301. }
  8302.  
  8303. if(CloudGenerateTimer <= 0)
  8304. {
  8305. float xvel;
  8306. float yvel;
  8307.  
  8308. // Core clouds
  8309. if(LightningTime > 0)
  8310. {
  8311. p = new PxParticle(618, StartX, StartY);
  8312. p->SetAnimSpeed(0.02);
  8313. p->SetLifeTime(100);
  8314.  
  8315. xvel = RandomFloat(-1.0, 1.0);
  8316. yvel = 1.0 - (xvel * xvel);
  8317.  
  8318. p->SetVelocity(16.0 * xvel, RandomFloat(-8.0, 1.0) * yvel);
  8319. p->SetAirResistance(0.3);
  8320. p->SetStartAlpha(0);
  8321. p->SetEndAlpha(255);
  8322. p->SetStartSize(1.2, 1.2);
  8323. p->SetEndSize(0.6, 0.6);
  8324. p->SetStartColor(45,40,60);
  8325. p->SetEndColor(45,40,60);
  8326. }
  8327.  
  8328. // Surrounding clouds
  8329. p = new PxParticle(618, StartX, StartY);
  8330. p->SetAnimSpeed(0.02);
  8331. p->SetLifeTime(140);
  8332.  
  8333. xvel = RandomFloat(-1.0, 1.0);
  8334. yvel = 1.0 - (xvel * xvel);
  8335.  
  8336. p->SetVelocity(16.0 * xvel, RandomFloat(-8.0, 1.0) * yvel);
  8337. p->SetAirResistance(0.15);
  8338. p->SetStartAlpha(0);
  8339. p->SetEndAlpha(255);
  8340. p->SetStartSize(1.0, 1.0);
  8341. p->SetEndSize(0.01, 0.01);
  8342. p->SetStartColor(45,40,60);
  8343. p->SetEndColor(45,40,60);
  8344.  
  8345. CloudGenerateTimer = 2;
  8346. }
  8347. CloudGenerateTimer = CloudGenerateTimer - 1;
  8348. }
  8349.  
  8350. if(Type == M_DRAWQUEUE)
  8351. {
  8352. if(LightningTime <= 0) return;
  8353.  
  8354. //AddSprite(10, StartX, StartY, 0, 2, 0.0);
  8355. //AddSprite(10, EndX, EndY, 0, 2, 0.0);
  8356. RenderLightning();
  8357. return;
  8358. }
  8359.  
  8360. super;
  8361. }
  8362.  
  8363. ///////////////////////////////////////////////////
  8364. // CWorm overrides
  8365.  
  8366. override CWorm::CWorm(CObject* Parent, int aTeam, int aIndex, CWormParams* params)
  8367. {
  8368. super;
  8369. ResurrectedByLightning = false;
  8370. }
  8371.  
  8372. override void CWorm::FireFinal(CWeapon* Weap, CShootDesc* Desc)
  8373. {
  8374. if(Weap->CheckName("Lightning Strike"))
  8375. {
  8376. new PxLightningStrike(GetObject(25, 0), Desc);
  8377. }
  8378. else
  8379. {
  8380. super;
  8381. }
  8382. }
  8383.  
  8384. override void CWorm::Free(bool freeMem)
  8385. {
  8386. CGObject *obj;
  8387.  
  8388. for(int i = 0; i < Env->Objs.Count; i += 1)
  8389. {
  8390. obj = CGObject(Env->Objs.Objs[i]);
  8391. if(obj == NullObj) continue;
  8392.  
  8393. if(obj->ClType == OC_Cross)
  8394. {
  8395. if(obj->PosX == PosX && obj->PosY == PosY)
  8396. {
  8397. new PxDeadWorm(this, obj);
  8398. break;
  8399. }
  8400. }
  8401. }
  8402.  
  8403. super;
  8404. }
  8405. PXS : Library Code :
  8406. require utils, pxparticles;
  8407.  
  8408. PxBulletDesc::PxBulletDesc()
  8409. {
  8410. Damage = 10;
  8411. Push = 2;
  8412. Count = 1;
  8413. Spread = 0.0;
  8414. Flags = 4332670;
  8415. Team = 0;
  8416. }
  8417.  
  8418. void FireBullets(CObject *parent, CShootDesc *sdesc, PxBulletDesc *bdesc)
  8419. {
  8420. float ang = atan2(sdesc->SpY, sdesc->SpX);
  8421. float radiusSqr = bdesc->Damage * bdesc->Damage;
  8422. float spread = bdesc->Spread;
  8423.  
  8424. int hitX;
  8425. int hitY;
  8426. CGObject *hitObject;
  8427. int holeSize = bdesc->Damage;
  8428.  
  8429. if(holeSize < 5) holeSize = 5;
  8430.  
  8431. for(int i=0 ; i < bdesc->Count ; i+=1)
  8432. {
  8433. float a;
  8434. if(spread == 0.0) a = ang;
  8435. else a = ang + spread * RandomFloat(-1.0, 1.0);
  8436.  
  8437. float dirX = cos(a);
  8438. float dirY = sin(a);
  8439.  
  8440. float endX = sdesc->X + dirX * 10000.0;
  8441. float endY = sdesc->Y + dirY * 10000.0;
  8442. hitObject = TraceLine(parent, sdesc->X, sdesc->Y, endX, endY, bdesc->Flags, &hitX, &hitY);
  8443.  
  8444. if(hitObject != NullObj)
  8445. {
  8446. GG->land->MakeHole(holeSize, hitX, hitY);
  8447.  
  8448. // Hit effect
  8449. PxParticle *p;
  8450.  
  8451. if(hitObject->ClType == OC_Worm)
  8452. {
  8453. p = new PxParticle(118, hitX, hitY);
  8454. p->SetVelocity(0, 1);
  8455. }
  8456. else
  8457. {
  8458. p = new PxParticle(116, hitX, hitY);
  8459. p->SetVelocity(0, 0);
  8460. }
  8461. p->SetLifeTime(30);
  8462. p->GravityFactor(0);
  8463. p->SetAlpha(255);
  8464. p->SetSize(1, 1);
  8465. p->SetColor(255,255,255);
  8466.  
  8467. for(int j=0 ; j<5 ; j+=1)
  8468. {
  8469. p = new PxParticle(131, hitX, hitY);
  8470. p->SetLifeTime(50);
  8471. p->SetRandomVelocity(2.0, 3.5);
  8472. p->GravityFactor(-3);
  8473. p->SetAirResistance(0.2);
  8474. p->SetAlpha(255);
  8475. p->SetSize(0.5, 0.5);
  8476. p->SetColor(255,255,255);
  8477. p->SetMotionRandomness(1.0);
  8478. }
  8479.  
  8480. // Custom damage falloff
  8481. CMessageData msg;
  8482.  
  8483. for(i = 0; i < Env->Objs.Count; i += 1)
  8484. {
  8485. obj = CGObject(Env->Objs.Objs[i]);
  8486. if(obj == NullObj) continue;
  8487. if(obj->ClType == OC_Landscape) continue;
  8488.  
  8489. float dx = obj->PosX - hitX;
  8490. float dy = obj->PosY - hitY;
  8491. float dsqr = dx*dx+dy*dy;
  8492.  
  8493. if(obj == hitObject || dsqr <= radiusSqr)
  8494. {
  8495. float fraction;
  8496.  
  8497. if(obj == hitObject)
  8498. {
  8499. fraction = 1.0;
  8500. }
  8501. else
  8502. {
  8503. fraction = 1.0 - dsqr / (3*radiusSqr);
  8504. if(fraction > 1.0) fraction = 1.0;
  8505. }
  8506.  
  8507. float dmg = fraction * bdesc->Damage;
  8508. float force = fraction * bdesc->Push;
  8509.  
  8510. if(dmg > 0)
  8511. {
  8512. float fX;
  8513. float fY;
  8514.  
  8515. if(dsqr == 0)
  8516. {
  8517. fX = dirX;
  8518. fY = dirY;
  8519. }
  8520. else
  8521. {
  8522. float d = sqrt(dsqr);
  8523. fX = dx/d;
  8524. fY = dy/d;
  8525. }
  8526.  
  8527. msg.params[0] = 3;
  8528. msg.fparams[1] = hitX;
  8529. msg.fparams[2] = hitY;
  8530. msg.fparams[3] = force * fX;
  8531. msg.fparams[4] = force * fY;
  8532. msg.params[5] = dmg;
  8533. msg.params[6] = bdesc->Team;
  8534. obj->Message(parent, M_GUNEXP, 1032, &msg);
  8535. }
  8536. }
  8537. }
  8538. }
  8539. }
  8540. }
  8541.  
  8542. PXS : Library Code :
  8543. require utils, pxparticles, pxbullet, wpsounds;
  8544.  
  8545. CSprite* sentryBaseSprite;
  8546. CSprite* sentryBodySprite;
  8547. CSprite* sentryBarrelSprite;
  8548. CSprite* sentryBarrelSprite2;
  8549. CSprite* sentryMuzzleSprite;
  8550.  
  8551. CSoundFile* sentryPlaceSound;
  8552. CSoundFile* sentryRotateSound;
  8553. CSoundFile* sentryRotateStartSound;
  8554. CSoundFile* sentryRotateEndSound;
  8555. CSoundFile* sentryShootSound;
  8556. CSoundFile* sentryShootEndSound;
  8557. CSoundFile* sentryAlertSound;
  8558.  
  8559. PxBulletDesc* SentryBulletDesc;
  8560.  
  8561. #WEAPON_KSENTRY
  8562.  
  8563. CColMask* MASK_SENTRYGUN;
  8564.  
  8565. void sentrygun::FirstFrame()
  8566. {
  8567. MASK_SENTRYGUN = new CColMask(6, 12, MakeRectMask(6, 12));
  8568.  
  8569. CFile *f;
  8570.  
  8571. f = GetAttachment("sentryplace.wav"); sentryPlaceSound = new CSoundFile(f);
  8572. f = GetAttachment("sentryservoloop.wav"); sentryRotateSound = new CSoundFile(f);
  8573. f = GetAttachment("sentryservostart.wav"); sentryRotateStartSound = new CSoundFile(f);
  8574. f = GetAttachment("sentryservoend.wav"); sentryRotateEndSound = new CSoundFile(f);
  8575. f = GetAttachment("sentryfireloop.wav"); sentryShootSound = new CSoundFile(f);
  8576. f = GetAttachment("sentryfireend.wav"); sentryShootEndSound = new CSoundFile(f);
  8577. f = GetAttachment("sentrybeeps2.wav"); sentryAlertSound = new CSoundFile(f);
  8578.  
  8579. SentryBulletDesc = new PxBulletDesc;
  8580. }
  8581.  
  8582. // Loading resources
  8583. void sentrygun::InitGraphic()
  8584. {
  8585. CFile *f;
  8586.  
  8587. f = GetAttachment("sentry_base.png"); sentryBaseSprite = LoadSprite(f, 1, 0);
  8588. f = GetAttachment("sentry_body.png"); sentryBodySprite = LoadSprite(f, 1, 0);
  8589. f = GetAttachment("sentry_gun.png"); sentryBarrelSprite = LoadSprite(f, 1, 0);
  8590. f = GetAttachment("sentry_gun_firing.png"); sentryBarrelSprite2 = LoadSprite(f, 2, 0);
  8591. f = GetAttachment("sentry_muzzle.png"); sentryMuzzleSprite = LoadSprite(f, 1, 0);
  8592. }
  8593.  
  8594. ///////////////////////////////////////////////////
  8595. // PxSentryGun class
  8596.  
  8597. PxSentryGun : CMine;
  8598.  
  8599. PxSentryGun::PxSentryGun(CObject* Parent, CShootDesc* Desc)
  8600. {
  8601. // Maximum distance between a worm and the sentry for it to be detected
  8602. SensorRadius = 360.0;
  8603. //SensorLoseRadius = 500.0;
  8604.  
  8605. // Gun parameters
  8606. GunAmmunition = 20;
  8607. GunDamage = 2;
  8608. GunPush = 1;
  8609. GunSpread = 0.05;
  8610. GunFramesPerShot = 6;
  8611.  
  8612. // Turret parameters
  8613. TurretRotationSpeedIdle = 0.5;
  8614. TurretRotationSpeedActive = 1.5;
  8615. TurretIdleSweepAngle = 10.0;
  8616. TurretOffsetX = 0;
  8617. TurretOffsetY = -15;
  8618.  
  8619. // Health parameters
  8620. MaxHealth = 35;
  8621. Health = MaxHealth;
  8622. ExplosionDamage = 50;
  8623. ExplosionBlast = 100;
  8624.  
  8625. // Physics parameters
  8626. //DumpingA = -1.0;
  8627. //DumpingB = -1.0;
  8628. //DumpingC = -1.0;
  8629. BounceMultiplierX = 0.0;
  8630. BounceMultiplierY = 1.0;
  8631.  
  8632. // Number of frames to wait after activating before being able to fire
  8633. DelayBeforeFiring = 60;
  8634.  
  8635. // INTERNAL PARAMETERS
  8636.  
  8637. TurretScale = 0.8;
  8638.  
  8639. // Sprites
  8640. SpriteBase = sentryBaseSprite->Index;
  8641. SpriteBody = sentryBodySprite->Index;
  8642. SpriteBarrel = sentryBarrelSprite->Index;
  8643. SpriteBarrel2 = sentryBarrelSprite2->Index;
  8644. SpriteMuzzle = sentryMuzzleSprite->Index;
  8645. AnimSpeed = 0.2;
  8646.  
  8647. // Private
  8648. StunTurnsRemaining = 0;
  8649. SensorRadiusSqr = 0.0;
  8650.  
  8651. AnimCycle = 0.0;
  8652.  
  8653. BaseOffsetX = 0;
  8654. BaseOffsetY = 2;
  8655. BarrelOffsetX = 17;
  8656. BarrelOffsetY = 0;
  8657. MuzzleOffsetX = 14;
  8658. MuzzleOffsetY = 0;
  8659.  
  8660. SweepDir = 1;
  8661.  
  8662. Ammo = GunAmmunition;
  8663. TurretActive = true;
  8664. Target = NullObj;
  8665. ShootTimer = 0;
  8666. ActivateTimer = 0;
  8667. SentryBeepTimer = 0;
  8668.  
  8669. SentryBeepMinDelay = 60;
  8670.  
  8671. Planted = false;
  8672. Removed = false;
  8673. Firing = false;
  8674. LongRotation = false;
  8675.  
  8676. LostTarget = false;
  8677. LastTargetX = 0.0;
  8678. LastTargetY = 0.0;
  8679.  
  8680. // 180
  8681. // |
  8682. // 270 - + - 90
  8683. // |
  8684. // 0
  8685.  
  8686. if(Desc->SpX < 0)
  8687. {
  8688. BaseSide = -1;
  8689. }
  8690. else
  8691. {
  8692. BaseSide = 1;
  8693. }
  8694. TurretSide = BaseSide;
  8695. IdleTargetAngle = 180.0 - 90.0 * TurretSide;
  8696. DisabledTargetAngle = IdleTargetAngle - 45.0 * TurretSide;
  8697. TurretAngle = IdleTargetAngle;
  8698. TargetAngle = IdleTargetAngle;
  8699. RotationSpeed = TurretRotationSpeedIdle;
  8700.  
  8701. NextRecalcZPlane = 0;
  8702. ZPlane = 10.0;
  8703.  
  8704. OwnerTeam = Desc->Team;
  8705.  
  8706. CMineParams MParams;
  8707. zero(&MParams);
  8708.  
  8709. MParams.Prefuse = 0;
  8710. MParams.Flags = 0;
  8711. MParams.Bias = 0;
  8712. MParams.Radius = 0;
  8713. MParams.Fuse = 70;
  8714. MParams.Damage = 48;
  8715. MParams.BlastPower = 100;
  8716.  
  8717. SetLayerOverride(LAYER_OILDRUM);
  8718. SetMaskIndexOverride(3);
  8719.  
  8720. super(Parent, &MParams, Desc, false, 0);
  8721. ClType = EObjectClass(73);
  8722.  
  8723. //Layer = LAYER_OILDRUM;
  8724. //ColGroup = CMASK_DEFAULT_COLLIDEABLE;
  8725.  
  8726. ShootSoundObj = CSound(NullObj);
  8727. RotateSoundObj = CSound(NullObj);
  8728. RotateStartSoundObj = CSound(NullObj);
  8729.  
  8730. //ColMask = MASK_SENTRYGUN;
  8731. }
  8732.  
  8733. // Placeholder for CMagnetMissile
  8734. void PxSentryGun::Collide(CGObject* Obj, int type)
  8735. {
  8736. if(Obj->ClType == OC_Landscape && Planted == false)
  8737. {
  8738. SpX = 0;
  8739. SpY = 0;
  8740. Planted = true;
  8741.  
  8742. sentryPlaceSound->Play(1.0, 0.0, false);
  8743.  
  8744. return;
  8745. }
  8746.  
  8747. SpX = SpX * BounceMultiplierX;
  8748. SpY = SpY * BounceMultiplierY;
  8749.  
  8750. super;
  8751. }
  8752.  
  8753. void PxSentryGun::Stun(int turns)
  8754. {
  8755. StunTurnsRemaining = turns;
  8756. if(turns > 0) TurretActive = false;
  8757. }
  8758.  
  8759. // Applies blast damage
  8760. // x, y : origin of the explosion
  8761. // dmg : maximum damage the explosion should do
  8762. void PxSentryGun::TakeExplosionDamage(fixed x, fixed y, int dmg)
  8763. {
  8764. if(dmg == 0) return;
  8765.  
  8766. float fdmg = dmg;
  8767. float dx = PosX - x;
  8768. float dy = PosY - y;
  8769.  
  8770. float distsqr = dx*dx + dy*dy;
  8771. float fdmgsqr = fdmg*fdmg*4.0;
  8772.  
  8773. fdmg = (1.0 - distsqr/fdmgsqr) * fdmg;
  8774. dmg = fdmg;
  8775.  
  8776. if(dmg > 0) TakeDamage(0, dmg);
  8777. }
  8778.  
  8779. // Applies direct damage (without any further calculation)
  8780. // type should be always 0 (10 is for percentage-based damage and is reserved to the Battle Axe)
  8781. void PxSentryGun::TakeDamage(int type, int dmg)
  8782. {
  8783. if(type == 10)
  8784. {
  8785. fixed fdmg = dmg;
  8786. fdmg = Health * fdmg / 100.0;
  8787. dmg = fdmg;
  8788. }
  8789.  
  8790. Health -= dmg;
  8791.  
  8792. TurretActive = false;
  8793. }
  8794.  
  8795. void PxSentryGun::StartFiring()
  8796. {
  8797. if(Firing) return;
  8798.  
  8799. Firing = true;
  8800. ShootTimer = 0;
  8801.  
  8802. ShootSoundObj = sentryShootSound->Play(1.0, 0.0, true);
  8803. }
  8804.  
  8805. void PxSentryGun::StopFiring()
  8806. {
  8807. if(Firing == false) return;
  8808.  
  8809. Firing = false;
  8810.  
  8811. if(ShootSoundObj != CSound(NullObj))
  8812. {
  8813. ShootSoundObj->Stop();
  8814. ShootSoundObj = CSound(NullObj);
  8815. }
  8816. sentryShootEndSound->Play(1.0, 0.0, false);
  8817. }
  8818.  
  8819. void PxSentryGun::StartRotatingSound()
  8820. {
  8821. if(LongRotation) return;
  8822.  
  8823. LongRotation = true;
  8824.  
  8825. RotateStartSoundObj = sentryRotateStartSound->Play(0.95, 0.0, false);
  8826. //RotateSoundObj = sentryRotateSound->Play(1.0, 0.0, true);
  8827. }
  8828.  
  8829. void PxSentryGun::StopRotatingSound()
  8830. {
  8831. if(LongRotation == false) return;
  8832.  
  8833. LongRotation = false;
  8834.  
  8835. if(RotateStartSoundObj != CSound(NullObj))
  8836. {
  8837. RotateStartSoundObj->Stop();
  8838. RotateStartSoundObj = CSound(NullObj);
  8839. }
  8840. if(RotateSoundObj != CSound(NullObj))
  8841. {
  8842. RotateSoundObj->Stop();
  8843. RotateSoundObj = CSound(NullObj);
  8844. }
  8845. sentryRotateEndSound->Play(0.95, 0.0, false);
  8846. }
  8847.  
  8848. // Called when the object is destroyed
  8849. void PxSentryGun::Explode()
  8850. {
  8851. if(Removed) return;
  8852.  
  8853. DoExplosion(PosX,PosY-20, ExplosionBlast, ExplosionDamage, 0, 0);
  8854.  
  8855. SpeedDivider = 1000;
  8856. SpX = 0.0;
  8857. SpY = 0.0;
  8858. GravityFactor = 0.0;
  8859. IsMaterial = false;
  8860. Stopped = 1;
  8861.  
  8862. if(ShootSoundObj != CSound(NullObj))
  8863. {
  8864. ShootSoundObj->Stop();
  8865. ShootSoundObj = CSound(NullObj);
  8866. }
  8867. if(RotateStartSoundObj != CSound(NullObj))
  8868. {
  8869. RotateStartSoundObj->Stop();
  8870. RotateStartSoundObj = CSound(NullObj);
  8871. }
  8872. if(RotateSoundObj != CSound(NullObj))
  8873. {
  8874. RotateSoundObj->Stop();
  8875. RotateSoundObj = CSound(NullObj);
  8876. }
  8877. }
  8878.  
  8879. // Renders the object
  8880. void PxSentryGun::Draw()
  8881. {
  8882. int baseX = PosX + BaseOffsetX;
  8883. int baseY = PosY + BaseOffsetY;
  8884.  
  8885. // Base
  8886. if(BaseSide < 0)
  8887. {
  8888. AddSpriteEx(ZPlane+0.03, baseX, baseY, 262144 + SpriteBase, 0, 0, TurretScale);
  8889. }
  8890. else
  8891. {
  8892. AddSpriteEx(ZPlane+0.03, baseX, baseY, SpriteBase, 0, 0, TurretScale);
  8893. }
  8894.  
  8895. // Body
  8896. float ang = (90 - TurretAngle) * 3.141593 / 180.0;
  8897.  
  8898. float r;
  8899. float g;
  8900. float b;
  8901.  
  8902. int TeamColor;
  8903.  
  8904. if (OwnerTeam < 1)
  8905. {
  8906. TeamColor = 0;
  8907. }
  8908. else
  8909. {
  8910. TeamColor = GetTeamColor(OwnerTeam) + 1;
  8911. }
  8912.  
  8913. if (TeamColor == 1)
  8914. {
  8915. r = 0.65;
  8916. g = 0.15;
  8917. b = 0.15;
  8918. }
  8919. else if (TeamColor == 2)
  8920. {
  8921. r = 0.15;
  8922. g = 0.15;
  8923. b = 0.65;
  8924. }
  8925. else if (TeamColor == 3)
  8926. {
  8927. r = 0.15;
  8928. g = 0.65;
  8929. b = 0.15;
  8930. }
  8931. else if (TeamColor == 4)
  8932. {
  8933. r = 0.55;
  8934. g = 0.55;
  8935. b = 0.15;
  8936. }
  8937. else if (TeamColor == 5)
  8938. {
  8939. r = 0.55;
  8940. g = 0.15;
  8941. b = 0.55;
  8942. }
  8943. else if (TeamColor == 6)
  8944. {
  8945. r = 0.15;
  8946. g = 0.55;
  8947. b = 0.55;
  8948. }
  8949. else
  8950. {
  8951. r = 0.5;
  8952. g = 0.5;
  8953. b = 0.5;
  8954. }
  8955.  
  8956. if(Sinking)
  8957. {
  8958. r = r * (90.0 / 255.0);
  8959. g = g * (90.0 / 255.0);
  8960. b = b * (240.0 / 255.0);
  8961. ClearColorMod();
  8962. }
  8963.  
  8964. SetColorMod(RGB(r * 255.0, g * 255.0, b * 255.0), 6);
  8965.  
  8966. if(TurretSide < 0)
  8967. AddSpriteEx(ZPlane, baseX+TurretScale*TurretOffsetX, baseY+TurretScale*TurretOffsetY, SpriteBody, 0, ang, TurretScale);
  8968. else
  8969. AddSpriteEx(ZPlane, baseX+TurretScale*TurretOffsetX, baseY+TurretScale*TurretOffsetY, 262144 + SpriteBody, 0, ang+3.141593, TurretScale);
  8970.  
  8971. ClearColorMod();
  8972.  
  8973. if(Sinking)
  8974. {
  8975. SetColorMod(RGB(90, 90, 240), 6);
  8976. }
  8977.  
  8978. // Barrels
  8979. float realBarrelOffsetX = BarrelOffsetX;
  8980. if(Firing)
  8981. {
  8982. realBarrelOffsetX = realBarrelOffsetX + 2.0 * sin(0.5 * GS->Tick);
  8983. }
  8984.  
  8985. float barrelX = baseX + TurretScale*(TurretOffsetX + cos(ang)*realBarrelOffsetX - sin(ang)*BarrelOffsetY);
  8986. float barrelY = baseY + TurretScale*(TurretOffsetY + sin(ang)*realBarrelOffsetX - cos(ang)*BarrelOffsetY);
  8987.  
  8988. if(Firing)
  8989. {
  8990. AddSpriteEx(ZPlane+0.02, barrelX, barrelY, SpriteBarrel2, AnimCycle, ang, TurretScale);
  8991.  
  8992. if(AnimCycle < 0.5)
  8993. {
  8994. barrelX += TurretScale * (cos(ang)*MuzzleOffsetX - sin(ang)*MuzzleOffsetY);
  8995. barrelY += TurretScale * (sin(ang)*MuzzleOffsetX - cos(ang)*MuzzleOffsetY);
  8996.  
  8997. //AddSpriteEx(ZPlane+0.01, barrelX, barrelY, SpriteMuzzle, 0, ang, 1);
  8998.  
  8999. CQuad q;
  9000. FillSpriteQuad(&q, SpriteMuzzle, 0, 0);
  9001. TransformQuad(&q, ang, TurretScale, TurretScale, barrelX, barrelY);
  9002. q.blend = 1;
  9003. for(int i=0 ; i<4 ; i+=1) q.v[i].color = RGB(255,255,255);
  9004. AddSpriteQ(ZPlane+0.01, &q, SpriteMuzzle, 0, 64);
  9005. }
  9006. }
  9007. else
  9008. {
  9009. AddSpriteEx(ZPlane+0.02, barrelX, barrelY, SpriteBarrel, 0, ang, TurretScale);
  9010. }
  9011. }
  9012.  
  9013. bool PxSentryGun::IsTargetVisible(CGObject *target)
  9014. {
  9015. int hitX;
  9016. int hitY;
  9017. if(TraceLine(this, PosX + BaseOffsetX + TurretScale*TurretOffsetX, PosY + BaseOffsetY + TurretScale*TurretOffsetY,
  9018. target->PosX, target->PosY, 2, &hitX, &hitY) == NullObj)
  9019. return true;
  9020. else
  9021. return false;
  9022. }
  9023.  
  9024. void PxSentryGun::TurretThink()
  9025. {
  9026. int turretX = PosX + BaseOffsetX + TurretScale*TurretOffsetX;
  9027. int turretY = PosY + BaseOffsetY + TurretScale*TurretOffsetY;
  9028. int hitX;
  9029. int hitY;
  9030.  
  9031. if(TurretActive)
  9032. {
  9033. // Looking for targets
  9034. if(Target == NullObj)
  9035. {
  9036. if(SensorRadiusSqr == 0.0)
  9037. SensorRadiusSqr = SensorRadius * SensorRadius;
  9038.  
  9039. float best_distance;
  9040.  
  9041. for(int i = 1; i < Env->Objs.Count; i+=1)
  9042. {
  9043. local obj = CGObject(Env->Objs.Objs[i]);
  9044.  
  9045. if(obj == NullObj) continue;
  9046.  
  9047. // if it's a worm...
  9048. if(obj->ClType == OC_Worm)
  9049. {
  9050. CWorm *worm = CWorm(obj);
  9051. // if it's not friendly...
  9052. if(OwnerTeam < 1 || GetTeamColor(worm->WormTeam) != GetTeamColor(OwnerTeam))
  9053. {
  9054. // if it's moving...
  9055. if(obj->ObjState == WS_WALKING || obj->SpX != 0 || obj->SpY != 0)
  9056. {
  9057. float dx = obj->PosX - turretX;
  9058. float dy = obj->PosY - turretY;
  9059. float d = dx*dx + dy*dy;
  9060.  
  9061. // if it's inside the sentry's detection radius...
  9062. if(d <= SensorRadiusSqr)
  9063. {
  9064. // if it's visible...
  9065.  
  9066. if(IsTargetVisible(obj))
  9067. {
  9068. // -> potential target
  9069. if(Target == NullObj || d < best_distance)
  9070. {
  9071. // in the end, only the closest potential target will be selected
  9072. Target = obj;
  9073. best_distance = d;
  9074. }
  9075. }
  9076. }
  9077. }
  9078. }
  9079. }
  9080. }
  9081.  
  9082. if(Target != NullObj)
  9083. {
  9084. // Got a target, make a beeping sound
  9085. //PlayLocalSound(88, 5, 2.0, 1.0, &Snd);
  9086. if(SentryBeepTimer <= 0)
  9087. {
  9088. sentryAlertSound->Play(1.0, 0.0, false);
  9089. SentryBeepTimer = SentryBeepMinDelay;
  9090. }
  9091.  
  9092. ActivateTimer = DelayBeforeFiring;
  9093. }
  9094. }
  9095.  
  9096. if(Target == NullObj)
  9097. {
  9098. // Idle
  9099. TargetAngle = IdleTargetAngle + SweepDir * TurretIdleSweepAngle;
  9100. LostTarget = false;
  9101. RotationSpeed = TurretRotationSpeedIdle;
  9102. }
  9103. else
  9104. {
  9105. // Tracking (TODO)
  9106. if(IsTargetVisible(Target))
  9107. {
  9108. LostTarget = false;
  9109. TargetAngle = (atan2(Target->PosX - turretX, Target->PosY - turretY) * 180.0) / 3.141593;
  9110. }
  9111. else
  9112. {
  9113. if(LostTarget == false)
  9114. {
  9115. LastTargetX = Target->PosX;
  9116. LastTargetY = Target->PosY;
  9117. StopFiring();
  9118. }
  9119. LostTarget = true;
  9120. TargetAngle = (atan2(LastTargetX - turretX, LastTargetY - turretY) * 180.0) / 3.141593;
  9121. }
  9122. if(TargetAngle < 0.0) TargetAngle += 360.0;
  9123. if(TargetAngle > 360.0) TargetAngle -= 360.0;
  9124. RotationSpeed = TurretRotationSpeedActive;
  9125. }
  9126. }
  9127. else
  9128. {
  9129. // Disabled
  9130. TargetAngle = DisabledTargetAngle;
  9131. Target = NullObj;
  9132. StopFiring();
  9133. RotationSpeed = TurretRotationSpeedIdle;
  9134. }
  9135.  
  9136. // Rotate the turret towards the target angle
  9137. float speed = TargetAngle - TurretAngle;
  9138.  
  9139. if(RotateStartSoundObj != CSound(NullObj) && RotateStartSoundObj->isAlive() == false)
  9140. {
  9141. RotateStartSoundObj->Stop();
  9142. RotateStartSoundObj = CSound(NullObj);
  9143.  
  9144. RotateSoundObj = sentryRotateSound->Play(0.95, 0.0, true);
  9145. }
  9146.  
  9147. if(TurretActive && Target != NullObj)
  9148. {
  9149. if(speed >= 2*RotationSpeed || speed <= -2*RotationSpeed)
  9150. {
  9151. StartRotatingSound();
  9152. }
  9153. else
  9154. {
  9155. StopRotatingSound();
  9156. }
  9157. }
  9158. else
  9159. {
  9160. StopRotatingSound();
  9161. }
  9162.  
  9163. if(ActivateTimer > 0) ActivateTimer = ActivateTimer - 1;
  9164. if(SentryBeepTimer > 0) SentryBeepTimer = SentryBeepTimer - 1;
  9165.  
  9166. if(speed >= RotationSpeed)
  9167. {
  9168. TurretAngle += RotationSpeed;
  9169. StopFiring();
  9170. }
  9171. else if(speed <= -RotationSpeed)
  9172. {
  9173. TurretAngle -= RotationSpeed;
  9174. StopFiring();
  9175. }
  9176. else
  9177. {
  9178. TurretAngle = TargetAngle;
  9179.  
  9180. if(TurretActive)
  9181. {
  9182. if(Target == NullObj)
  9183. {
  9184. // If the target angle has been reached while the turret is idle, reverse the sweep direction
  9185. // so it looks like the sentry is scanning the area
  9186. SweepDir = -SweepDir;
  9187. }
  9188. else
  9189. {
  9190. if(LostTarget)
  9191. {
  9192. Target = NullObj;
  9193. }
  9194. else
  9195. {
  9196. if(ActivateTimer <= 0) StartFiring();
  9197. }
  9198. // Got focus on the target, is it visible?
  9199. //if(IsTargetVisible(obj))
  9200. //{
  9201. //StartFiring();
  9202. //}
  9203. //else
  9204. //{
  9205. // StopFiring();
  9206. //}
  9207. }
  9208. }
  9209. }
  9210.  
  9211. // Turret rotated over itself, change the sentry's idle target angle so the turret faces the other way when it goes back to idle
  9212. if((180 - TurretAngle) * TurretSide < 0)
  9213. {
  9214. TurretSide = -TurretSide;
  9215. IdleTargetAngle = 180.0 - 90.0 * TurretSide;
  9216. DisabledTargetAngle = IdleTargetAngle - 45.0 * TurretSide;
  9217. }
  9218.  
  9219. // Firing
  9220. if(Firing)
  9221. {
  9222. AnimCycle = AnimCycle + AnimSpeed;
  9223. if(AnimCycle >= 1.0) AnimCycle -= 1.0;
  9224.  
  9225. if(ShootTimer <= 0)
  9226. {
  9227. float ang = (90 - TurretAngle) * 3.141593 / 180.0;
  9228.  
  9229. CShootDesc SDesc;
  9230. zero(&SDesc);
  9231.  
  9232. SDesc.Team = 0;
  9233. SDesc.X = turretX;
  9234. SDesc.Y = turretY;
  9235.  
  9236. SDesc.SpX = cos(ang);
  9237. SDesc.SpY = sin(ang);
  9238.  
  9239. SentryBulletDesc->Damage = GunDamage;
  9240. SentryBulletDesc->Push = GunPush;
  9241. SentryBulletDesc->Count = 1;
  9242.  
  9243. if(RandomInt(1, 5) == 1)
  9244. SentryBulletDesc->Spread = 0.0; // 20% probability to fire a bullet at pin-point accuracy
  9245. else
  9246. SentryBulletDesc->Spread = GunSpread;
  9247.  
  9248. FireBullets(this, &SDesc, SentryBulletDesc);
  9249.  
  9250. // Shell ejection
  9251. PxParticle *p = new PxParticle(115, turretX, turretY);
  9252. p->SetAnimSpeed(0.1);
  9253. p->SetLifeTime(100);
  9254.  
  9255. float eject_ang = ang - TurretSide * 1.570797 + RandomFloat(-0.3, 0.3);
  9256. float eject_vel = RandomFloat(2.0, 3.0);
  9257.  
  9258. p->SetVelocity(eject_vel * cos(eject_ang), eject_vel * sin(eject_ang));
  9259. p->SetAirResistance(0.0);
  9260. p->GravityFactor(1.0);
  9261. p->SetAlpha(255);
  9262. p->SetSize(1.0, 1.0);
  9263.  
  9264. //PlayLocalSound(78, 5, 1.0, 1.0, &Snd);
  9265.  
  9266. ShootTimer = GunFramesPerShot;
  9267. Ammo = Ammo - 1;
  9268. if(Ammo <= 0)
  9269. {
  9270. StopFiring();
  9271. TurretActive = false;
  9272. }
  9273. }
  9274. ShootTimer = ShootTimer - 1;
  9275. }
  9276. }
  9277.  
  9278. // Called when a new turn begins
  9279. void PxSentryGun::OnTurnBegin(int Team)
  9280. {
  9281. // Reload the turret and activate it
  9282. Target = NullObj;
  9283.  
  9284. if(StunTurnsRemaining > 0)
  9285. {
  9286. if(Team == OwnerTeam) StunTurnsRemaining = StunTurnsRemaining - 1;
  9287. }
  9288. else
  9289. {
  9290. TurretActive = true;
  9291. Ammo = GunAmmunition;
  9292. }
  9293. }
  9294.  
  9295. void PxSentryGun::Message(CObject* sender, EMType Type, int MSize, CMessageData* MData)
  9296. {
  9297. // Drawing operations are done here
  9298. if(Type == M_DRAWQUEUE)
  9299. {
  9300. if(Removed) return;
  9301.  
  9302. if(Sinking) SetColorMod(RGB(90, 90, 240), 6);
  9303.  
  9304. Draw();
  9305.  
  9306. if(Sinking) ClearColorMod();
  9307.  
  9308. // Recalculate Z plane periodically to make sure magnets are drawn properly when overlapping each other
  9309. if(NextRecalcZPlane <= 0)
  9310. {
  9311. local matches = 0;
  9312.  
  9313. for(local i = 1; i < Env->Objs.Count; i+=1)
  9314. {
  9315. local obj = Env->Objs.Objs[i];
  9316.  
  9317. if(obj == NullObj) continue;
  9318. if(obj == this) continue;
  9319. if(obj is PxSentryGun)
  9320. {
  9321. local sentry = PxSentryGun(obj);
  9322.  
  9323. float dX = sentry->PosX - PosX;
  9324. float dY = sentry->PosY - PosY;
  9325. float r2 = dX*dX + dY*dY;
  9326.  
  9327. if(r2 < 900.0)
  9328. {
  9329. if(sentry->ZPlane == ZPlane)
  9330. {
  9331. sentry->ZPlane = sentry->ZPlane + 0.1;
  9332. }
  9333. matches = matches + 1;
  9334. }
  9335. }
  9336. }
  9337.  
  9338. if(matches == 0) ZPlane = 10;
  9339.  
  9340. NextRecalcZPlane = 200;
  9341. }
  9342. else
  9343. {
  9344. NextRecalcZPlane = NextRecalcZPlane - 1;
  9345. }
  9346.  
  9347. return;
  9348. }
  9349.  
  9350. // Damage handling
  9351. if(Removed==false)
  9352. {
  9353. if(Type == M_EXPLOSION)
  9354. {
  9355. TakeExplosionDamage(MData->fparams[1], MData->fparams[2], MData->params[4]);
  9356. }
  9357. else if(Type == M_GUNEXP)
  9358. {
  9359. TakeDamage(MData->params[0], MData->params[5]);
  9360. }
  9361. }
  9362.  
  9363. super;
  9364.  
  9365. // This is done every frame (derp)
  9366. if(Type == M_FRAME)
  9367. {
  9368. if(Removed)
  9369. {
  9370. Free(true);
  9371. return;
  9372. }
  9373. else
  9374. {
  9375. if(Sinking)
  9376. {
  9377. TurretActive = false;
  9378. }
  9379.  
  9380. TurretThink();
  9381.  
  9382. if(Health <= 0)
  9383. {
  9384. Explode();
  9385. Removed = true;
  9386. }
  9387. }
  9388. }
  9389. }
  9390.  
  9391. ///////////////////////////////////////////////////
  9392. // CTurnGame overrides
  9393.  
  9394. override void CTurnGame::SetCurrentTeam(int Team)
  9395. {
  9396. super;
  9397.  
  9398. for(local i = 1; i < Env->Objs.Count; i+=1)
  9399. {
  9400. local obj = Env->Objs.Objs[i];
  9401.  
  9402. if(obj == NullObj) continue;
  9403. if(obj is PxSentryGun)
  9404. {
  9405. PxSentryGun *sentry = PxSentryGun(obj);
  9406. sentry->OnTurnBegin(Team);
  9407. }
  9408. }
  9409. }
  9410.  
  9411. ///////////////////////////////////////////////////
  9412. // CWorm overrides
  9413.  
  9414. override void CWorm::FireFinal(CWeapon* Weap, CShootDesc* Desc)
  9415. {
  9416. if(Weap->CheckName("Sentry Gun"))
  9417. {
  9418. local ang = (1 - FireAngle) * 3.14159;
  9419. if (TurnSide < 0)
  9420. {
  9421. ang = 6.28318 - ang;
  9422. }
  9423.  
  9424. CShootDesc SDesc;
  9425. zero(&SDesc);
  9426.  
  9427. local BaseForce = 0.3;
  9428.  
  9429. SDesc.Team = WormTeam;
  9430. SDesc.X = PosX;
  9431. SDesc.Y = PosY;
  9432. SDesc.SpX = SpX * 0.5 + TurnSide * BaseForce;
  9433. SDesc.SpY = SpY * 0.5 - 0.15;
  9434.  
  9435. new PxSentryGun(GetObject(25, 0), &SDesc);
  9436. }
  9437. else
  9438. {
  9439. super;
  9440. }
  9441. }
  9442. PXS : Library Code :
  9443. require utils, pxparticles, pxtexbeam, wpsounds;
  9444.  
  9445. //////////////////////////
  9446. // Global variables
  9447.  
  9448. float TazerSegmentLength;
  9449. int TazerNumSegments;
  9450. int TazerLifeTime;
  9451. int TazerLifeTimeAfterHit;
  9452. int TazerStartDie;
  9453. float TazerSearchRadius;
  9454. float TazerSearchRadiusSqr;
  9455. float TazerNoiseScale;
  9456. int TazerWormDamage;
  9457. int TazerObjectDamage;
  9458. bool TazerCanFire;
  9459.  
  9460. // Most of those variables should be members of CTazerShot, but since PX has so many memory leaks, better have static tables
  9461. // Since there will be only one worm using a tazer at once, that shouldn't be a problem
  9462. int TazerNumPoints;
  9463. int TazerQueueHead;
  9464. int TazerQueueTail;
  9465. float TazerPointsX[128];
  9466. float TazerPointsY[128];
  9467. float TazerNoise[128];
  9468.  
  9469. CGObject* TazerIgnoreList[64];
  9470. int TazerIgnoreNum;
  9471.  
  9472. CTraceRes *TazerTrace;
  9473.  
  9474. CSprite* laserSprite;
  9475.  
  9476. CSprite* tazer_lightningBeamSprite;
  9477. CSprite* tazer_lightningGlowSprite;
  9478.  
  9479. CSprite* wormTazedSprite1;
  9480. CSprite* wormTazedSprite2;
  9481.  
  9482. CSoundFile* tazerLoopSound;
  9483. CSoundFile* tazerHitSound;
  9484.  
  9485. #WEAPON_TAZER
  9486.  
  9487. //CLogFile *tazerLog;
  9488.  
  9489. ///////////////////////////////////////////////////
  9490. // Initialization
  9491.  
  9492. void tazer::FirstFrame()
  9493. {
  9494. CFile *f;
  9495. f = GetAttachment("sentryservoloop.wav"); tazerLoopSound = new CSoundFile(f);
  9496. f = GetAttachment("sentryservoloop.wav"); tazerHitSound = new CSoundFile(f);
  9497.  
  9498. TazerSegmentLength = 10.0; // The length of each segment of the arc
  9499. TazerNumSegments = 33; // Maximum number of segments in the arc, must be a power of 2 plus 1
  9500.  
  9501. TazerLifeTime = 16; // How far the arc can progress
  9502. TazerLifeTimeAfterHit = 20; // Same, but after the initial hit (for making chains slightly easier)
  9503. TazerStartDie = 6; // The arc starts to fade out when its life reaches this value
  9504.  
  9505. TazerNoiseScale = 10.0;
  9506. TazerWormDamage = 24;
  9507. TazerObjectDamage = 12;
  9508.  
  9509. TazerSearchRadius = TazerSegmentLength * TazerLifeTimeAfterHit;
  9510. TazerSearchRadiusSqr = TazerSearchRadius * TazerSearchRadius;
  9511.  
  9512. TazerNumPoints = 0;
  9513. TazerTrace = new CTraceRes;
  9514. TazerObjectsZappedNum = 0;
  9515.  
  9516. TazerCanFire = true;
  9517.  
  9518. //tazerLog = new CLogFile("tazer_log.txt");
  9519. }
  9520.  
  9521. void tazer::InitGraphic()
  9522. {
  9523. CFile *f;
  9524. f = GetAttachment("worm_tazed1.png"); wormTazedSprite1 = LoadSprite(f, 4, 0);
  9525. f = GetAttachment("worm_tazed2.png"); wormTazedSprite2 = LoadSprite(f, 4, 0);
  9526. f = GetAttachment("lightning_beam.png"); tazer_lightningBeamSprite = LoadSprite(f, 1, 0);
  9527. f = GetAttachment("lightning_glow.png"); tazer_lightningGlowSprite = LoadSprite(f, 1, 0);
  9528. }
  9529.  
  9530. ///////////////////////////////////////////////////
  9531. // CTazerDamage
  9532.  
  9533. CTazerDamage : CObject;
  9534.  
  9535. CTazerDamage::CTazerDamage(CObject *parent, CGObject *target, int side)
  9536. {
  9537. super(parent, GS);
  9538.  
  9539. Target = target;
  9540. DamageSide = side;
  9541.  
  9542. if(Target->ClType == OC_Worm)
  9543. {
  9544. CWorm *w = CWorm(Target);
  9545. w->Taze();
  9546. }
  9547.  
  9548. NextDie = 24;
  9549.  
  9550. GlowSize = 10.0;
  9551. Removed = false;
  9552. Dead = false;
  9553.  
  9554. PosX = target->PosX;
  9555. PosY = target->PosY;
  9556.  
  9557. PRegister(&Target);
  9558.  
  9559. tazerHitSound->Play(1.0, 0.0, false);
  9560. }
  9561.  
  9562. void CTazerDamage::Zap(CGObject* obj)
  9563. {
  9564. if(obj->ClType == OC_Mine)
  9565. {
  9566. // Trigger mines
  9567. CMine *mine = CMine(obj);
  9568.  
  9569. // If the mine is not a special mine, can be triggered, and has not been triggered yet
  9570. if(mine->Radius > 0 && mine->Active == 0 && mine->Prefuse <= 0)
  9571. {
  9572. // Almost instant explosion
  9573. mine->Fuse = 400;
  9574.  
  9575. // Trigger the mine
  9576. mine->Active = 1;
  9577. mine->nPulses = 2;
  9578. }
  9579. }
  9580. else
  9581. {
  9582. CMessageData msg;
  9583. msg.params[0] = 0;
  9584. msg.fparams[1] = obj->PosX;
  9585. msg.fparams[2] = obj->PosY;
  9586. msg.fparams[3] = 1.2 * DamageSide;
  9587. msg.fparams[4] = -4.0;
  9588.  
  9589. if(obj->ClType == OC_Worm)
  9590. {
  9591. CWorm *w = CWorm(Target);
  9592. w->UnTaze();
  9593. msg.params[5] = TazerWormDamage;
  9594. }
  9595. else
  9596. {
  9597. msg.params[5] = TazerObjectDamage;
  9598. }
  9599.  
  9600. msg.params[6] = 0;
  9601.  
  9602. if(#WEAPON_MAGNET)
  9603. {
  9604. if(obj is CMagnet)
  9605. {
  9606. // Instantly destroy magnets
  9607. CMagnet *mag = CMagnet(obj);
  9608. mag->Health = 1;
  9609. mag->Message(this, M_GUNEXP, 1032, &msg);
  9610. return;
  9611. }
  9612. }
  9613.  
  9614. if(#WEAPON_FAN)
  9615. {
  9616. if(obj is PxFan)
  9617. {
  9618. // Instantly destroy fans
  9619. local fanobj = PxFan(obj);
  9620. fanobj->Health = 1;
  9621. fanobj->TakeDamage(TazerObjectDamage, 0);
  9622. fanobj->Message(this, M_GUNEXP, 1032, &msg);
  9623. return;
  9624. }
  9625. }
  9626.  
  9627. if(#WEAPON_BOWLINGBALL)
  9628. {
  9629. if(obj is CBowlingBall)
  9630. {
  9631. // Send bowling balls flying
  9632. CBowlingBall *ball = CBowlingBall(obj);
  9633. ball->Zap(1);
  9634. return;
  9635. }
  9636. }
  9637.  
  9638. if(#WEAPON_KSENTRY)
  9639. {
  9640. if(obj is PxSentryGun)
  9641. {
  9642. // Stun sentries
  9643. PxSentryGun *sentry = PxSentryGun(obj);
  9644. sentry->Stun(2);
  9645. sentry->Message(this, M_GUNEXP, 1032, &msg);
  9646. return;
  9647. }
  9648. }
  9649.  
  9650. obj->Message(this, M_GUNEXP, 1032, &msg);
  9651. }
  9652. }
  9653.  
  9654. void CTazerDamage::Message(CObject* sender, EMType Type, int MSize, CMessageData* MData)
  9655. {
  9656. if(Type == M_FRAME)
  9657. {
  9658. if(Removed) return;
  9659.  
  9660. if((NextDie <= 0) || (Target == CGObject(NullObj)))
  9661. {
  9662. if(Target != CGObject(NullObj))
  9663. {
  9664. Zap(Target);
  9665. }
  9666.  
  9667. PUnregister(&Target);
  9668. Removed = true;
  9669. Free(true);
  9670. return;
  9671. }
  9672. NextDie = NextDie - 1;
  9673.  
  9674. GlowSize = RandomFloat(0.4, 0.7);
  9675.  
  9676. PosX = Target->PosX;
  9677. PosY = Target->PosY;
  9678.  
  9679. PxParticle *p = new PxParticle(tazer_lightningGlowSprite->Index, PosX, PosY);
  9680. p->SetBlendMode(1);
  9681. p->SetLifeTime(50);
  9682. p->SetRandomVelocity(1.0, 3.0);
  9683. p->SetAirResistance(0.0);
  9684. p->GravityFactor(1.0);
  9685. p->SetAlpha(255);
  9686. p->SetColor(255,200,0);
  9687. p->SetStartSize(0.1, 0.1);
  9688. p->SetEndSize(0.01, 0.01);
  9689. }
  9690. if(Type == M_DRAWQUEUE)
  9691. {
  9692. if(Removed) return;
  9693.  
  9694. CQuad q;
  9695. FillSpriteQuad(&q, tazer_lightningGlowSprite->Index, 0, 0);
  9696. TransformQuad(&q, 0, GlowSize, GlowSize, PosX, PosY);
  9697. q.blend = 1;
  9698. for(i=0 ; i<4 ; i+=1) q.v[i].color = RGB(80,100,255);
  9699. AddSpriteQ(9.9, &q, tazer_lightningGlowSprite->Index, 0, 64);
  9700. }
  9701.  
  9702. super;
  9703. }
  9704.  
  9705. ///////////////////////////////////////////////////
  9706. // CTazerShot
  9707.  
  9708. CTazerShot : CObject;
  9709.  
  9710. CTazerShot::CTazerShot(CObject *parent, CWorm *owner)
  9711. {
  9712. super(parent, GS);
  9713. ClType = OC_AirStrike;
  9714.  
  9715. ClearIgnoreList();
  9716. AddToIgnoreList(owner);
  9717.  
  9718. float ang = (1 - owner->FireAngle) * 3.14159;
  9719. if(owner->TurnSide < 0)
  9720. {
  9721. ang = 6.28318 - ang;
  9722. }
  9723.  
  9724. LifeTime = TazerLifeTime;
  9725.  
  9726. Removed = false;
  9727. Dead = false;
  9728.  
  9729. DieFraction = 0.0;
  9730. DieRate = 0.05;
  9731.  
  9732. DirX = sin(ang);
  9733. DirY = -cos(ang);
  9734. PosX = owner->PosX + 4 * DirX;
  9735. PosY = owner->PosY + 4 * DirY;
  9736.  
  9737. LastX = owner->PosX;
  9738. LastY = owner->PosY;
  9739.  
  9740. NextProgress = 0;
  9741. StopProgress = false;
  9742.  
  9743. NumRemoveOnNextLink = 0;
  9744.  
  9745. ClearPoints();
  9746. AddPoint(PosX, PosY);
  9747.  
  9748. SoundObj = tazerLoopSound->Play(1.0, 0.0, false);
  9749. }
  9750.  
  9751. void CTazerShot::ClearPoints()
  9752. {
  9753. TazerNumPoints = 0;
  9754. TazerQueueHead = 0;
  9755. TazerQueueTail = 0;
  9756. }
  9757.  
  9758. float CTazerShot::PointX(int i)
  9759. {
  9760. i = (TazerQueueHead+i) % 64;
  9761. return TazerPointsX[i];
  9762. }
  9763.  
  9764. float CTazerShot::PointY(int i)
  9765. {
  9766. i = (TazerQueueHead+i) % 64;
  9767. return TazerPointsY[i];
  9768. }
  9769.  
  9770. void CTazerShot::AddPoint(float x, float y)
  9771. {
  9772. TazerPointsX[TazerQueueTail] = x;
  9773. TazerPointsY[TazerQueueTail] = y;
  9774. TazerQueueTail = (TazerQueueTail+1) % 64;
  9775. TazerNumPoints += 1;
  9776. }
  9777.  
  9778. void CTazerShot::RemovePoint()
  9779. {
  9780. TazerQueueHead = (TazerQueueHead+1) % 64;
  9781. TazerNumPoints -= 1;
  9782. }
  9783.  
  9784. void CTazerShot::ClearIgnoreList()
  9785. {
  9786. TazerIgnoreNum = 0;
  9787. }
  9788.  
  9789. bool CTazerShot::AddToIgnoreList(CGObject *obj)
  9790. {
  9791. if(TazerIgnoreNum == 63) return false;
  9792.  
  9793. TazerIgnoreList[TazerIgnoreNum] = obj;
  9794. TazerIgnoreNum += 1;
  9795.  
  9796. return true;
  9797. }
  9798.  
  9799. bool CTazerShot::IsValidTarget(CGObject *obj)
  9800. {
  9801. bool ok = false;
  9802.  
  9803. ///////////////////////////////
  9804.  
  9805. if(obj->ClType == OC_Worm) ok = true;
  9806. if(obj->ClType == OC_Mine) ok = true;
  9807. if(obj->ClType == OC_OilDrum) ok = true;
  9808. if(obj->ClType == OC_Crate) ok = true;
  9809.  
  9810. if(#WEAPON_MAGNET)
  9811. {
  9812. if(obj is CMagnet) ok = true;
  9813. }
  9814.  
  9815. if(#WEAPON_BOWLINGBALL)
  9816. {
  9817. if(obj is CBowlingBall) ok = true;
  9818. }
  9819.  
  9820. if(#WEAPON_FAN)
  9821. {
  9822. if(obj is PxFan) ok = true;
  9823. }
  9824.  
  9825. if(obj is PxSentryGun) ok = true;
  9826.  
  9827. ///////////////////////////////
  9828.  
  9829. if(ok)
  9830. {
  9831. for(int i=0 ; i<TazerIgnoreNum ; i += 1)
  9832. {
  9833. if(TazerIgnoreList[i] == obj) return false;
  9834. }
  9835. return true;
  9836. }
  9837.  
  9838. return false;
  9839. }
  9840.  
  9841. CGObject *CTazerShot::FindTarget()
  9842. {
  9843. float best_distance;
  9844. CGObject *target = NullObj;
  9845.  
  9846. for(int i = 1; i < Env->Objs.Count; i+=1)
  9847. {
  9848. local obj = CGObject(Env->Objs.Objs[i]);
  9849. if(obj == NullObj) continue;
  9850.  
  9851. if(IsValidTarget(obj))
  9852. {
  9853. float dx = obj->PosX - PosX;
  9854. float dy = obj->PosY - PosY;
  9855. float d = dx*dx + dy*dy;
  9856.  
  9857. if(d <= TazerSearchRadiusSqr)
  9858. {
  9859. if(target == NullObj || d < best_distance)
  9860. {
  9861. target = obj;
  9862. best_distance = d;
  9863. }
  9864. }
  9865. }
  9866. }
  9867.  
  9868. return target;
  9869. }
  9870.  
  9871. void CTazerShot::GenerateNoise(float scale, float start, float end)
  9872. {
  9873. int i;
  9874. int k = TazerNumSegments;
  9875. int l = k >> 1;
  9876.  
  9877. for(i=0 ; i<TazerNumSegments ; i+=1) TazerNoise[i] = 0.0;
  9878. TazerNoise[0] = start;
  9879. TazerNoise[TazerNumSegments-1] = end;
  9880.  
  9881. while(l > 0)
  9882. {
  9883. for(i=l ; i<TazerNumSegments ; i+=k)
  9884. {
  9885. TazerNoise[i] = (TazerNoise[i-l] + TazerNoise[i+l]) * 0.5 + RandomFloat(-scale, scale);
  9886. }
  9887. k = l;
  9888. l = k >> 1;
  9889. }
  9890. }
  9891.  
  9892. void CTazerShot::Message(CObject* sender, EMType Type, int MSize, CMessageData* MData)
  9893. {
  9894. if(Type == M_FRAME)
  9895. {
  9896. if(Removed) return;
  9897.  
  9898. GenerateNoise(1.0, 0.0, 0.0);
  9899.  
  9900. if(NextProgress == 0)
  9901. {
  9902. //NextProgress = RandomInt(0,2);
  9903. NextProgress = 0; // don't slow the progress down, maybe it looks better that way?
  9904. }
  9905. else
  9906. {
  9907. NextProgress = NextProgress - 1;
  9908. return;
  9909. }
  9910.  
  9911. if(TazerNumPoints >= TazerNumSegments || NumRemoveOnNextLink > 0)
  9912. {
  9913. RemovePoint();
  9914. NumRemoveOnNextLink = NumRemoveOnNextLink - 1;
  9915. }
  9916.  
  9917. if(LifeTime == 0)
  9918. {
  9919. if(SoundObj != CSound(NullObj))
  9920. {
  9921. SoundObj->Stop();
  9922. SoundObj = CSound(NullObj);
  9923. }
  9924.  
  9925. Removed = true;
  9926. Free(true);
  9927. return;
  9928. }
  9929. else
  9930. LifeTime = LifeTime - 1;
  9931.  
  9932. bool snapToTarget = false;
  9933. CGObject *target = NullObj;
  9934.  
  9935. if(LifeTime <= TazerStartDie)
  9936. {
  9937. // The electrical arc is dying, fade it out
  9938. RemovePoint();
  9939. RemovePoint();
  9940. NumRemoveOnNextLink = NumRemoveOnNextLink - 2;
  9941.  
  9942. float f = TazerStartDie;
  9943. f = LifeTime / f;
  9944. DieFraction = 1.0 - f;
  9945. }
  9946. else
  9947. DieFraction = 0.0;
  9948.  
  9949. if(StopProgress) return;
  9950.  
  9951. target = FindTarget();
  9952. if(target != NullObj)
  9953. {
  9954. // Curve towards targets
  9955. float tx = target->PosX - PosX;
  9956. float ty = target->PosY - PosY;
  9957. float td = sqrt(tx*tx + ty*ty);
  9958. tx = tx/td;
  9959. ty = ty/td;
  9960.  
  9961. float l = sqrt(TazerSegmentLength / td);
  9962.  
  9963. // Near enough?
  9964. if(l >= 0.9)
  9965. {
  9966. // Snap to the target
  9967. l = 1.0;
  9968. snapToTarget = true;
  9969.  
  9970. // Add the target to the ignore list so we don't zap it again and again
  9971. AddToIgnoreList(target);
  9972.  
  9973. CGObject *newtarget = FindTarget();
  9974. if(newtarget != CGObject(NullObj))
  9975. {
  9976. // Reset the life time of the electrical arc
  9977. LifeTime = TazerLifeTimeAfterHit;
  9978. }
  9979. else
  9980. StopProgress = true;
  9981.  
  9982. // Make it pause a bit
  9983. //NextProgress = RandomInt(2,4);
  9984. NextProgress = 14; // longer pause
  9985.  
  9986. // The number of points to remove from the arc the next time it links with something
  9987. // Kinda hard to explain but it's basically for removing excess points from the arc to make it look like
  9988. // it's linking the currently hit objects with the previously hit one.
  9989. NumRemoveOnNextLink = TazerNumPoints;
  9990.  
  9991. // Bam, damage
  9992. if(tx < 0)
  9993. new CTazerDamage(GetObject(25, 0), target, -1);
  9994. else
  9995. new CTazerDamage(GetObject(25, 0), target, 1);
  9996. }
  9997.  
  9998. DirX = DirX + (tx - DirX) * l;
  9999. DirY = DirY + (ty - DirY) * l;
  10000.  
  10001. td = sqrt(DirX*DirX + DirY*DirY);
  10002. DirX = DirX/td;
  10003. DirY = DirY/td;
  10004. }
  10005. else
  10006. {
  10007. // No target, take a random direction
  10008. DirX = DirX + RandomFloat(-1.0, 1.0);
  10009. DirY = DirY + RandomFloat(-1.0, 1.0);
  10010.  
  10011. float td = sqrt(DirX*DirX + DirY*DirY);
  10012. if(td == 0)
  10013. {
  10014. DirX = 0;
  10015. DirY = 1;
  10016. }
  10017. else
  10018. {
  10019. DirX = DirX/td;
  10020. DirY = DirY/td;
  10021. }
  10022. }
  10023.  
  10024. if(snapToTarget == false)
  10025. {
  10026. // Avoid terrain
  10027. float endx = PosX + DirX * TazerSegmentLength * 2;
  10028. float endy = PosY + DirY * TazerSegmentLength * 2;
  10029. TraceLineEx(this, PosX, PosY, endx, endy, CMASK_TERRAIN, TazerTrace);
  10030.  
  10031. if(TazerTrace->StartsSolid)
  10032. {
  10033. TraceLineEx(this, LastX, LastY, endx, endy, CMASK_TERRAIN, TazerTrace);
  10034. if(TazerTrace->StartsSolid)
  10035. {
  10036. Dead = true;
  10037. return;
  10038. }
  10039. }
  10040.  
  10041. if(TazerTrace->Hit)
  10042. {
  10043. if(true)
  10044. {
  10045. // So we just hit some terrain, what are we supposed to do now?
  10046.  
  10047. // Temporary vars, we'll use them for calculations later
  10048. float tx;
  10049. float ty;
  10050. float dx;
  10051. float dy;
  10052. float newPosX;
  10053. float newPosY;
  10054.  
  10055. // Move away from the terrain to make sure we aren't too close to it
  10056. newPosX = TazerTrace->HitX + TazerTrace->NormalX * TazerSegmentLength;
  10057. newPosY = TazerTrace->HitY + TazerTrace->NormalY * TazerSegmentLength;
  10058.  
  10059. // Let's try to follow the shape of the terrain and see if we're getting anywhere
  10060. dx = TazerTrace->TangentX;
  10061. dy = TazerTrace->TangentY;
  10062.  
  10063. // New direction doesn't matter if we don't have a target, heh
  10064. if(target != NullObj)
  10065. {
  10066. // Now we can either follow the terrain in one direction or the other
  10067. // See which direction brings us closer to the target
  10068.  
  10069. // Case 1: Projected new position if we follow the tangent's direction
  10070. float x1 = newPosX + dx * 2 * TazerSegmentLength;
  10071. float y1 = newPosY + dy * 2 * TazerSegmentLength;
  10072.  
  10073. // Case 2: Projected new position if we follow the opposite direction
  10074. float x2 = newPosX - dx * 2 * TazerSegmentLength;
  10075. float y2 = newPosY - dy * 2 * TazerSegmentLength;
  10076.  
  10077. // Distance to target when using case 1
  10078. tx = target->PosX - x1;
  10079. ty = target->PosY - y1;
  10080. float d1 = tx*tx+ty*ty;
  10081.  
  10082. // Distance to target when using case 2
  10083. tx = target->PosX - x2;
  10084. ty = target->PosY - y2;
  10085. float d2 = tx*tx+ty*ty;
  10086.  
  10087. if(d2 < d1)
  10088. {
  10089. // Case 2 brings us closer to the target, use the opposite tangent then
  10090. dx = -dx;
  10091. dy = -dy;
  10092. x1 = x2;
  10093. y1 = y2;
  10094. }
  10095. }
  10096.  
  10097. // Calculate the final movement direction vector
  10098. newPosX += dx * TazerSegmentLength;
  10099. newPosY += dy * TazerSegmentLength;
  10100. DirX = newPosX - PosX;
  10101. DirY = newPosY - PosY;
  10102. float td = sqrt(DirX*DirX + DirY*DirY);
  10103. DirX = DirX / td;
  10104. DirY = DirY / td;
  10105. }
  10106. else
  10107. {
  10108. // OLD ALGORITHM
  10109.  
  10110. float tx = TazerTrace->HitX - PosX;
  10111. float ty = TazerTrace->HitY - PosY;
  10112. float l = 1 - (sqrt(tx*tx+ty*ty) / (TazerSegmentLength * 2));
  10113.  
  10114. tx = TazerTrace->HitX + TazerTrace->NormalX * TazerSegmentLength;
  10115. ty = TazerTrace->HitY + TazerTrace->NormalY * TazerSegmentLength;
  10116.  
  10117. DirX = tx - PosX;
  10118. DirY = ty - PosY;
  10119. float td = sqrt(DirX*DirX + DirY*DirY);
  10120. DirX = DirX/td;
  10121. DirY = DirY/td;
  10122.  
  10123. if(target != NullObj)
  10124. {
  10125. float x1 = PosX + DirX * TazerSegmentLength;
  10126. float y1 = PosY + DirY * TazerSegmentLength;
  10127. float x2 = PosX - DirX * TazerSegmentLength;
  10128. float y2 = PosY - DirY * TazerSegmentLength;
  10129.  
  10130. tx = target->PosX - x1;
  10131. ty = target->PosY - y1;
  10132. float d1 = tx*tx+ty*ty;
  10133.  
  10134. tx = target->PosX - x2;
  10135. ty = target->PosY - y2;
  10136. float d2 = tx*tx+ty*ty;
  10137.  
  10138. if(d2 < d1)
  10139. {
  10140. DirX = -DirX;
  10141. DirY = -DirY;
  10142. x1 = x2;
  10143. y1 = y2;
  10144. }
  10145.  
  10146. int hitx;
  10147. int hity;
  10148.  
  10149. if(TraceLine(this, PosX, PosY, x1, y1, CMASK_TERRAIN, &hitx, &hity) != NullObj)
  10150. {
  10151. DirX = -DirX;
  10152. DirY = -DirY;
  10153. }
  10154. }
  10155. }
  10156. }
  10157. }
  10158.  
  10159. LastX = PosX;
  10160. LastY = PosY;
  10161.  
  10162. if(snapToTarget)
  10163. {
  10164. PosX = target->PosX;
  10165. PosY = target->PosY;
  10166. }
  10167. else
  10168. {
  10169. PosX += DirX * TazerSegmentLength;
  10170. PosY += DirY * TazerSegmentLength;
  10171. }
  10172.  
  10173. AddPoint(PosX, PosY);
  10174. }
  10175. if(Type == M_DRAWQUEUE)
  10176. {
  10177. if(Removed) return;
  10178.  
  10179. if(TazerNumPoints >= 2)
  10180. {
  10181. StartTexturedBeam(this, 10, tazer_lightningBeamSprite->Index, 0.0, 1);
  10182.  
  10183. CQuad q;
  10184. int num = (TazerNumPoints - 1);
  10185.  
  10186. for(int i=0 ; i<=num ; i += 1)
  10187. {
  10188. float t = num;
  10189. t = i / t;
  10190. float x = PointX(i);
  10191. float y = PointY(i);
  10192.  
  10193. if(i > 0 && i < num)
  10194. {
  10195. float dx = y - PointY(i-1);
  10196. float dy = PointX(i-1) - x;
  10197. float d = sqrt(dx*dx+dy*dy);
  10198.  
  10199. dx = dx / d;
  10200. dy = dy / d;
  10201.  
  10202. x = x + TazerNoiseScale * TazerNoise[i-1] * dx;
  10203. y = y + TazerNoiseScale * TazerNoise[i-1] * dy;
  10204. }
  10205.  
  10206. // Dome curve thing where f(0)=f(1)=0 and f(0.5)=1
  10207. // basically that means that the beam will be thicker in the middle and thinner at the extremities
  10208. float f = (4.0 * t * (1.0-t) + 0.1);
  10209. if(f > 1.0) f = 1.0;
  10210. float f2 = f * (1.0 - DieFraction);
  10211.  
  10212. float s;
  10213. float r;
  10214. float g;
  10215. float b;
  10216.  
  10217. r = 80.0 * f2;
  10218. g = 100.0 * f2;
  10219. b = 255.0 * f2;
  10220.  
  10221. TexturedBeamPoint(x, y, f * 9.0, t, RGB(r,g,b));
  10222.  
  10223. FillSpriteQuad(&q, tazer_lightningGlowSprite->Index, 0, 0);
  10224.  
  10225. if(i==num-1)
  10226. {
  10227. // Make the tip of the arc glow stronger
  10228. TransformQuad(&q, 0, 0.9, 0.9, x, y);
  10229. }
  10230. else
  10231. {
  10232. TransformQuad(&q, 0, 0.3, 0.3, x, y);
  10233. }
  10234.  
  10235. q.blend = 1;
  10236. for(int k=0 ; k<4 ; k+=1) q.v[k].color = RGB(r,g,b);
  10237. AddSpriteQ(9.9, &q, tazer_lightningGlowSprite->Index, 0, 64);
  10238. }
  10239.  
  10240. EndTexturedBeam();
  10241. }
  10242. }
  10243.  
  10244. super;
  10245. }
  10246.  
  10247. override void CTurnGame::SetCurrentTeam(int Team)
  10248. {
  10249. super;
  10250. TazerCanFire = true;
  10251. }
  10252.  
  10253. ///////////////////////////
  10254. // CWorm overrides
  10255.  
  10256. override CWorm::CWorm(CObject* Parent, int aTeam, int aIndex, CWormParams* params)
  10257. {
  10258. super;
  10259. Tazed = false;
  10260. TazedPosX = PosX;
  10261. TazedPosY = PosY;
  10262. TazedAnim = 0;
  10263. TazedAnimCycle = 0.0;
  10264. TazedAnimAngle = float(0.0);
  10265. }
  10266.  
  10267. void CWorm::Taze()
  10268. {
  10269. Tazed = true;
  10270. TazedPosX = PosX;
  10271. TazedPosY = PosY;
  10272.  
  10273. if(RandomInt(0,1) == 0)
  10274. {
  10275. TazedAnim = wormTazedSprite1->Index;
  10276. }
  10277. else
  10278. {
  10279. TazedAnim = wormTazedSprite2->Index;
  10280. }
  10281.  
  10282. TazedAnimCycle = 0.0;
  10283. TazedAnimAngle = 3.141593 + RandomFloat(-0.2, 0.2);
  10284. //TazedAnimAngle = 0.0;
  10285.  
  10286. SetState(WS_IDLE);
  10287. SpeedDivider = 1000;
  10288. }
  10289.  
  10290. void CWorm::UnTaze()
  10291. {
  10292. Tazed = false;
  10293. SpeedDivider = 1;
  10294. }
  10295.  
  10296. override void CWorm::Message(CObject* sender, EMType Type, int MSize, CMessageData* MData)
  10297. {
  10298. if(Type == M_FRAME)
  10299. {
  10300. if(Tazed)
  10301. {
  10302. // Makes the worm invisible
  10303. Anim->Reset();
  10304. Anim->SetAnimEx(136, 0.0);
  10305. TazedAnimCycle = TazedAnimCycle + 0.1;
  10306. if(TazedAnimCycle >= 1.0) TazedAnimCycle -= 1.0;
  10307.  
  10308. if(int(TazedPosX) != int(PosX) || int(TazedPosY) != int(PosY))
  10309. {
  10310. UnTaze();
  10311. }
  10312. }
  10313. }
  10314.  
  10315. if(Type == M_DRAWQUEUE)
  10316. {
  10317. if(Tazed)
  10318. {
  10319. if(TurnSide < 0)
  10320. {
  10321. AddSpriteEx(8, PosX, PosY, TazedAnim + 262144, TazedAnimCycle, TazedAnimAngle, 1.0);
  10322. }
  10323. else
  10324. {
  10325. AddSpriteEx(8, PosX, PosY, TazedAnim, TazedAnimCycle, TazedAnimAngle, 1.0);
  10326. }
  10327. }
  10328. }
  10329.  
  10330. super;
  10331. }
  10332.  
  10333. override void CWorm::FireFinal(CWeapon* Weap, CShootDesc* Desc)
  10334. {
  10335. if(Weap->CheckName("Tazer"))
  10336. {
  10337. if(TazerCanFire)
  10338. {
  10339. new CTazerShot(GetObject(25, 0), this);
  10340. TazerCanFire = false;
  10341. }
  10342. }
  10343. else
  10344. {
  10345. super;
  10346. }
  10347. }
  10348. PXS : Compiling..
  10349. PXS : Compiled
  10350. PXS : N Classes : 30
  10351. PXS : processing script class MissileIndex
  10352. PXS : instance size : 4
  10353. PXS : processing script class RandomsGens
  10354. PXS : processing script class WormsRelated
  10355. PXS : processing script class Maths
  10356. PXS : processing script class sync_script
  10357. PXS : instance size : 4
  10358. PXS : processing script class tracers
  10359. PXS : instance size : 4
  10360. PXS : processing script class all_utils
  10361. PXS : processing script class px_enums
  10362. PXS : instance size : 4
  10363. PXS : processing script class layer_override
  10364. PXS : instance size : 4
  10365. PXS : processing script class ldetector_script
  10366. PXS : instance size : 4
  10367. PXS : processing script class antiglitch_s
  10368. PXS : instance size : 4
  10369. PXS : processing script class darkness_script
  10370. PXS : instance size : 4
  10371. PXS : processing script class friendlymines
  10372. PXS : processing script class nades
  10373. PXS : processing script class turretbase
  10374. PXS : instance size : 4
  10375. PXS : processing script class mineturret
  10376. PXS : instance size : 4
  10377. PXS : processing script class arrowturret
  10378. PXS : instance size : 4
  10379. PXS : processing script class particle
  10380. PXS : instance size : 4
  10381. PXS : processing script class airstrikebase
  10382. PXS : processing script class bowlingball
  10383. PXS : instance size : 4
  10384. PXS : processing script class bbstrike
  10385. PXS : instance size : 4
  10386. PXS : processing script class magnet
  10387. PXS : instance size : 4
  10388. PXS : processing script class bunkerbuster
  10389. PXS : instance size : 4
  10390. PXS : processing script class fan
  10391. PXS : instance size : 4
  10392. PXS : processing script class paratest
  10393. PXS : instance size : 4
  10394. PXS : processing script class texbeam
  10395. PXS : instance size : 4
  10396. PXS : processing script class lightningstrike
  10397. PXS : instance size : 4
  10398. PXS : processing script class bullet
  10399. PXS : processing script class sentrygun
  10400. PXS : instance size : 4
  10401. PXS : processing script class tazer
  10402. PXS : instance size : 8
  10403. PXS : Linking group 2..
  10404. PXS : Processing overrides
  10405. PXS : Making overrides
  10406. PXS : Making overidde of FireFinal@PCCWeapon@PCCShootDesc@
  10407. PXS : by ^FireFinal@PCCWeapon@PCCShootDesc@
  10408. PXS : VFT 005E8490, class : CWorm
  10409. PXS : work3
  10410. PXS : Making overidde of CMissile@PCCObject@PCCWeaponLaunch@PCCShootDesc@
  10411. PXS : by ^CMissile@PCCObject@PCCWeaponLaunch@PCCShootDesc@
  10412. PXS : VFT 005E8388, class : CMissile
  10413. PXS : work3
  10414. PXS : Detected derived from CMissile to WindNade
  10415. PXS : Detected derived from CMissile to GravityNade
  10416. PXS : Making overidde of Message@PCCObject@eEMType@iPCCMessageData@
  10417. PXS : by ^Message@PCCObject@eEMType@iPCCMessageData@
  10418. PXS : VFT 005EDD14, class : CTurnGame
  10419. PXS : work3
  10420. PXS : Making overidde of CMine@PCCObject@PCCMineParams@PCCShootDesc@Bi
  10421. PXS : by ^CMine@PCCObject@PCCMineParams@PCCShootDesc@Bi
  10422. PXS : VFT 005E8338, class : CMine
  10423. PXS : work3
  10424. PXS : Detected derived from CMine to StickyMine
  10425. PXS : Detected derived from CMine to CBowlingBall
  10426. PXS : Detected derived from CMine to CMagnet
  10427. PXS : Detected derived from CMine to CMagnetMissile
  10428. PXS : Detected derived from CMine to PxBunkerBuster
  10429. PXS : Detected derived from CMine to PxFan
  10430. PXS : Detected derived from CMine to PxSentryGun
  10431. PXS : Making overidde of Message@PCCObject@eEMType@iPCCMessageData@
  10432. PXS : by ^Message@PCCObject@eEMType@iPCCMessageData@
  10433. PXS : VFT 005E8338, class : CMine
  10434. PXS : work3
  10435. PXS : Detected derived from CMine to StickyMine
  10436. PXS : Detected derived from CMine to CBowlingBall
  10437. PXS : Detected derived from CMine to CMagnet
  10438. PXS : Detected derived from CMine to CMagnetMissile
  10439. PXS : Detected derived from CMine to PxBunkerBuster
  10440. PXS : Detected derived from CMine to PxFan
  10441. PXS : Detected derived from CMine to PxSentryGun
  10442. PXS : Making overidde of SetCurrentTeam@i
  10443. PXS : by ^SetCurrentTeam@i
  10444. PXS : VFT 005EDD14, class : CTurnGame
  10445. PXS : work3
  10446. PXS : Making overidde of ^Message@PCCObject@eEMType@iPCCMessageData@
  10447. PXS : by ^^Message@PCCObject@eEMType@iPCCMessageData@
  10448. PXS : VFT 005EDD14, class : CTurnGame
  10449. PXS : work3
  10450. PXS : Making overidde of Free@B
  10451. PXS : by ^Free@B
  10452. PXS : VFT 005EDD14, class : CTurnGame
  10453. PXS : work3
  10454. PXS : Making overidde of CGObject@PCCObject@ii
  10455. PXS : by ^CGObject@PCCObject@ii
  10456. PXS : VFT 005E8140, class : CGObject
  10457. PXS : work3
  10458. PXS : Detected derived from CGObject to CCrate
  10459. PXS : Detected derived from CGObject to CMine
  10460. PXS : Detected derived from CGObject to CWorm
  10461. PXS : Detected derived from CGObject to COilDrum
  10462. PXS : Detected derived from CGObject to CArrow
  10463. PXS : Detected derived from CGObject to CMissile
  10464. PXS : Detected derived from CGObject to CTouchSensor
  10465. PXS : Detected derived from CGObject to StickyMine
  10466. PXS : Detected derived from CGObject to MovingOilDrum
  10467. PXS : Detected derived from CGObject to WindNade
  10468. PXS : Detected derived from CGObject to GravityNade
  10469. PXS : Detected derived from CGObject to CTurretBase
  10470. PXS : Detected derived from CGObject to CMineTurret
  10471. PXS : Detected derived from CGObject to CArrowTurret
  10472. PXS : Detected derived from CGObject to CBowlingBall
  10473. PXS : Detected derived from CGObject to CMagnet
  10474. PXS : Detected derived from CGObject to CMagnetMissile
  10475. PXS : Detected derived from CGObject to PxBunkerBuster
  10476. PXS : Detected derived from CGObject to PxFan
  10477. PXS : Detected derived from CGObject to PxSentryGun
  10478. PXS : Making overidde of CheckCollisionEx@PCCGObject@FFPCCColMask@i
  10479. PXS : by ^CheckCollisionEx@PCCGObject@FFPCCColMask@i
  10480. PXS : VFT 005E80E0, class : CEnv
  10481. PXS : work3
  10482. PXS : Making overidde of ^FireFinal@PCCWeapon@PCCShootDesc@
  10483. PXS : by ^^FireFinal@PCCWeapon@PCCShootDesc@
  10484. PXS : VFT 005E8490, class : CWorm
  10485. PXS : work3
  10486. PXS : Making overidde of SetState@eEObjState@
  10487. PXS : by ^SetState@eEObjState@
  10488. PXS : VFT 005E8490, class : CWorm
  10489. PXS : work3
  10490. PXS : Making overidde of ^^Message@PCCObject@eEMType@iPCCMessageData@
  10491. PXS : by ^^^Message@PCCObject@eEMType@iPCCMessageData@
  10492. PXS : VFT 005EDD14, class : CTurnGame
  10493. PXS : work3
  10494. PXS : Making overidde of RenderLabels@
  10495. PXS : by ^RenderLabels@
  10496. PXS : VFT 005E8490, class : CWorm
  10497. PXS : work3
  10498. PXS : Making overidde of RenderCrosshair@
  10499. PXS : by ^RenderCrosshair@
  10500. PXS : VFT 005E8490, class : CWorm
  10501. PXS : work3
  10502. PXS : Making overidde of AddSprite@FFFiiF
  10503. PXS : by ^AddSprite@FFFiiF
  10504. PXS : VFT 00000000, class : CDDQueue
  10505. PXS : work3
  10506. PXS : Making overidde of ForceFocus@FF
  10507. PXS : by ^ForceFocus@FF
  10508. PXS : VFT 005EDD30, class : CObject
  10509. PXS : work3
  10510. PXS : Detected derived from CObject to CTurnGame
  10511. PXS : Detected derived from CObject to CGObject
  10512. PXS : Detected derived from CObject to CCrate
  10513. PXS : Detected derived from CObject to CMine
  10514. PXS : Detected derived from CObject to CWorm
  10515. PXS : Detected derived from CObject to COilDrum
  10516. PXS : Detected derived from CObject to CFire
  10517. PXS : Detected derived from CObject to CGas
  10518. PXS : Detected derived from CObject to CArrow
  10519. PXS : Detected derived from CObject to CTeam
  10520. PXS : Detected derived from CObject to CFilter
  10521. PXS : Detected derived from CObject to CMissile
  10522. PXS : Detected derived from CObject to CTouchSensorParent
  10523. PXS : Detected derived from CObject to CTouchSensor
  10524. PXS : Detected derived from CObject to StickyMine
  10525. PXS : Detected derived from CObject to MovingOilDrum
  10526. PXS : Detected derived from CObject to WindNade
  10527. PXS : Detected derived from CObject to GravityNade
  10528. PXS : Detected derived from CObject to CTurretBase
  10529. PXS : Detected derived from CObject to CMineTurret
  10530. PXS : Detected derived from CObject to CArrowTurret
  10531. PXS : Detected derived from CObject to PxParticleManager
  10532. PXS : Detected derived from CObject to PxParticle
  10533. PXS : Detected derived from CObject to PxAirstrike
  10534. PXS : Detected derived from CObject to CBowlingBall
  10535. PXS : Detected derived from CObject to PxBowlingBallStrike
  10536. PXS : Detected derived from CObject to CMagnet
  10537. PXS : Detected derived from CObject to CMagnetMissile
  10538. PXS : Detected derived from CObject to PxBunkerBusterStrike
  10539. PXS : Detected derived from CObject to PxBunkerBuster
  10540. PXS : Detected derived from CObject to PxWindManager
  10541. PXS : Detected derived from CObject to PxFan
  10542. PXS : Detected derived from CObject to PxDeadWormManager
  10543. PXS : Detected derived from CObject to PxDeadWorm
  10544. PXS : Detected derived from CObject to PxLightningStrike
  10545. PXS : Detected derived from CObject to PxSentryGun
  10546. PXS : Detected derived from CObject to CTazerDamage
  10547. PXS : Detected derived from CObject to CTazerShot
  10548. PXS : Making overidde of LookAtMe@FFi
  10549. PXS : by ^LookAtMe@FFi
  10550. PXS : VFT 005E8140, class : CGObject
  10551. PXS : work3
  10552. PXS : Detected derived from CGObject to CCrate
  10553. PXS : Detected derived from CGObject to CMine
  10554. PXS : Detected derived from CGObject to CWorm
  10555. PXS : Detected derived from CGObject to COilDrum
  10556. PXS : Detected derived from CGObject to CArrow
  10557. PXS : Detected derived from CGObject to CMissile
  10558. PXS : Detected derived from CGObject to CTouchSensor
  10559. PXS : Detected derived from CGObject to StickyMine
  10560. PXS : Detected derived from CGObject to MovingOilDrum
  10561. PXS : Detected derived from CGObject to WindNade
  10562. PXS : Detected derived from CGObject to GravityNade
  10563. PXS : Detected derived from CGObject to CTurretBase
  10564. PXS : Detected derived from CGObject to CMineTurret
  10565. PXS : Detected derived from CGObject to CArrowTurret
  10566. PXS : Detected derived from CGObject to CBowlingBall
  10567. PXS : Detected derived from CGObject to CMagnet
  10568. PXS : Detected derived from CGObject to CMagnetMissile
  10569. PXS : Detected derived from CGObject to PxBunkerBuster
  10570. PXS : Detected derived from CGObject to PxFan
  10571. PXS : Detected derived from CGObject to PxSentryGun
  10572. PXS : Making overidde of ^^^Message@PCCObject@eEMType@iPCCMessageData@
  10573. PXS : by ^^^^Message@PCCObject@eEMType@iPCCMessageData@
  10574. PXS : VFT 005EDD14, class : CTurnGame
  10575. PXS : work3
  10576. PXS : Making overidde of ^CMine@PCCObject@PCCMineParams@PCCShootDesc@Bi
  10577. PXS : by ^^CMine@PCCObject@PCCMineParams@PCCShootDesc@Bi
  10578. PXS : VFT 005E8338, class : CMine
  10579. PXS : work3
  10580. PXS : Detected derived from CMine to StickyMine
  10581. PXS : Detected derived from CMine to CBowlingBall
  10582. PXS : Detected derived from CMine to CMagnet
  10583. PXS : Detected derived from CMine to CMagnetMissile
  10584. PXS : Detected derived from CMine to PxBunkerBuster
  10585. PXS : Detected derived from CMine to PxFan
  10586. PXS : Detected derived from CMine to PxSentryGun
  10587. PXS : Making overidde of ^Message@PCCObject@eEMType@iPCCMessageData@
  10588. PXS : by ^^Message@PCCObject@eEMType@iPCCMessageData@
  10589. PXS : VFT 005E8338, class : CMine
  10590. PXS : work3
  10591. PXS : Detected derived from CMine to StickyMine
  10592. PXS : Detected derived from CMine to CBowlingBall
  10593. PXS : Detected derived from CMine to CMagnet
  10594. PXS : Detected derived from CMine to CMagnetMissile
  10595. PXS : Detected derived from CMine to PxBunkerBuster
  10596. PXS : Detected derived from CMine to PxFan
  10597. PXS : Detected derived from CMine to PxSentryGun
  10598. PXS : Making overidde of Render@
  10599. PXS : by ^Render@
  10600. PXS : VFT 005E8338, class : CMine
  10601. PXS : work3
  10602. PXS : Detected derived from CMine to StickyMine
  10603. PXS : Detected derived from CMine to CBowlingBall
  10604. PXS : Detected derived from CMine to CMagnet
  10605. PXS : Detected derived from CMine to CMagnetMissile
  10606. PXS : Detected derived from CMine to PxBunkerBuster
  10607. PXS : Detected derived from CMine to PxFan
  10608. PXS : Detected derived from CMine to PxSentryGun
  10609. PXS : Making overidde of OnSink@
  10610. PXS : by ^OnSink@
  10611. PXS : VFT 005E8490, class : CWorm
  10612. PXS : work3
  10613. PXS : Making overidde of CWorm@PCCObject@iiPCCWormParams@
  10614. PXS : by ^CWorm@PCCObject@iiPCCWormParams@
  10615. PXS : VFT 005E8490, class : CWorm
  10616. PXS : work3
  10617. PXS : Making overidde of ^^FireFinal@PCCWeapon@PCCShootDesc@
  10618. PXS : by ^^^FireFinal@PCCWeapon@PCCShootDesc@
  10619. PXS : VFT 005E8490, class : CWorm
  10620. PXS : work3
  10621. PXS : Making overidde of ExplodeAt@FF
  10622. PXS : by ^ExplodeAt@FF
  10623. PXS : VFT 005E8388, class : CMissile
  10624. PXS : work3
  10625. PXS : Detected derived from CMissile to WindNade
  10626. PXS : Detected derived from CMissile to GravityNade
  10627. PXS : Making overidde of ^^^FireFinal@PCCWeapon@PCCShootDesc@
  10628. PXS : by ^^^^FireFinal@PCCWeapon@PCCShootDesc@
  10629. PXS : VFT 005E8490, class : CWorm
  10630. PXS : work3
  10631. PXS : Making overidde of ApplyBitmap@iiiiPCCBitmap@PCCBitmap@ii
  10632. PXS : by ^ApplyBitmap@iiiiPCCBitmap@PCCBitmap@ii
  10633. PXS : VFT 00608BB8, class : CLandscape
  10634. PXS : work3
  10635. PXS : Making overidde of CArrow@PCCObject@PiPCCShootDesc@
  10636. PXS : by ^CArrow@PCCObject@PiPCCShootDesc@
  10637. PXS : VFT 005E80E8, class : CArrow
  10638. PXS : work3
  10639. PXS : Making overidde of Message@PCCObject@eEMType@iPCCMessageData@
  10640. PXS : by ^Message@PCCObject@eEMType@iPCCMessageData@
  10641. PXS : VFT 005E80E8, class : CArrow
  10642. PXS : work3
  10643. PXS : Making overidde of ^^^^FireFinal@PCCWeapon@PCCShootDesc@
  10644. PXS : by ^^^^^FireFinal@PCCWeapon@PCCShootDesc@
  10645. PXS : VFT 005E8490, class : CWorm
  10646. PXS : work3
  10647. PXS : Making overidde of ^CWorm@PCCObject@iiPCCWormParams@
  10648. PXS : by ^^CWorm@PCCObject@iiPCCWormParams@
  10649. PXS : VFT 005E8490, class : CWorm
  10650. PXS : work3
  10651. PXS : Making overidde of Message@PCCObject@eEMType@iPCCMessageData@
  10652. PXS : by ^Message@PCCObject@eEMType@iPCCMessageData@
  10653. PXS : VFT 005E8490, class : CWorm
  10654. PXS : work3
  10655. PXS : Making overidde of ^^^^^FireFinal@PCCWeapon@PCCShootDesc@
  10656. PXS : by ^^^^^^FireFinal@PCCWeapon@PCCShootDesc@
  10657. PXS : VFT 005E8490, class : CWorm
  10658. PXS : work3
  10659. PXS : Making overidde of ^^^^^^FireFinal@PCCWeapon@PCCShootDesc@
  10660. PXS : by ^^^^^^^FireFinal@PCCWeapon@PCCShootDesc@
  10661. PXS : VFT 005E8490, class : CWorm
  10662. PXS : work3
  10663. PXS : Making overidde of ^SetCurrentTeam@i
  10664. PXS : by ^^SetCurrentTeam@i
  10665. PXS : VFT 005EDD14, class : CTurnGame
  10666. PXS : work3
  10667. PXS : Making overidde of ^^CWorm@PCCObject@iiPCCWormParams@
  10668. PXS : by ^^^CWorm@PCCObject@iiPCCWormParams@
  10669. PXS : VFT 005E8490, class : CWorm
  10670. PXS : work3
  10671. PXS : Making overidde of ^^^^^^^FireFinal@PCCWeapon@PCCShootDesc@
  10672. PXS : by ^^^^^^^^FireFinal@PCCWeapon@PCCShootDesc@
  10673. PXS : VFT 005E8490, class : CWorm
  10674. PXS : work3
  10675. PXS : Making overidde of ^Message@PCCObject@eEMType@iPCCMessageData@
  10676. PXS : by ^^Message@PCCObject@eEMType@iPCCMessageData@
  10677. PXS : VFT 005E8490, class : CWorm
  10678. PXS : work3
  10679. PXS : Making overidde of SetAnimEx@iF
  10680. PXS : by ^SetAnimEx@iF
  10681. PXS : VFT 005E8038, class : CSpriteAnim
  10682. PXS : work3
  10683. PXS : Making overidde of ^^^^^^^^FireFinal@PCCWeapon@PCCShootDesc@
  10684. PXS : by ^^^^^^^^^FireFinal@PCCWeapon@PCCShootDesc@
  10685. PXS : VFT 005E8490, class : CWorm
  10686. PXS : work3
  10687. PXS : Making overidde of ^^Message@PCCObject@eEMType@iPCCMessageData@
  10688. PXS : by ^^^Message@PCCObject@eEMType@iPCCMessageData@
  10689. PXS : VFT 005E8490, class : CWorm
  10690. PXS : work3
  10691. PXS : Making overidde of ^^SetCurrentTeam@i
  10692. PXS : by ^^^SetCurrentTeam@i
  10693. PXS : VFT 005EDD14, class : CTurnGame
  10694. PXS : work3
  10695. PXS : Making overidde of ^^^CWorm@PCCObject@iiPCCWormParams@
  10696. PXS : by ^^^^CWorm@PCCObject@iiPCCWormParams@
  10697. PXS : VFT 005E8490, class : CWorm
  10698. PXS : work3
  10699. PXS : Making overidde of ^^^^^^^^^FireFinal@PCCWeapon@PCCShootDesc@
  10700. PXS : by ^^^^^^^^^^FireFinal@PCCWeapon@PCCShootDesc@
  10701. PXS : VFT 005E8490, class : CWorm
  10702. PXS : work3
  10703. PXS : Making overidde of ^^^Message@PCCObject@eEMType@iPCCMessageData@
  10704. PXS : by ^^^^Message@PCCObject@eEMType@iPCCMessageData@
  10705. PXS : VFT 005E8490, class : CWorm
  10706. PXS : work3
  10707. PXS : Making overidde of ^^^^CWorm@PCCObject@iiPCCWormParams@
  10708. PXS : by ^^^^^CWorm@PCCObject@iiPCCWormParams@
  10709. PXS : VFT 005E8490, class : CWorm
  10710. PXS : work3
  10711. PXS : Making overidde of ^^^^Message@PCCObject@eEMType@iPCCMessageData@
  10712. PXS : by ^^^^^Message@PCCObject@eEMType@iPCCMessageData@
  10713. PXS : VFT 005E8490, class : CWorm
  10714. PXS : work3
  10715. PXS : Making overidde of ^SetAnimEx@iF
  10716. PXS : by ^^SetAnimEx@iF
  10717. PXS : VFT 005E8038, class : CSpriteAnim
  10718. PXS : work3
  10719. PXS : Making overidde of ^^^^^CWorm@PCCObject@iiPCCWormParams@
  10720. PXS : by ^^^^^^CWorm@PCCObject@iiPCCWormParams@
  10721. PXS : VFT 005E8490, class : CWorm
  10722. PXS : work3
  10723. PXS : Making overidde of ^^^^^^^^^^FireFinal@PCCWeapon@PCCShootDesc@
  10724. PXS : by ^^^^^^^^^^^FireFinal@PCCWeapon@PCCShootDesc@
  10725. PXS : VFT 005E8490, class : CWorm
  10726. PXS : work3
  10727. PXS : Making overidde of Free@B
  10728. PXS : by ^Free@B
  10729. PXS : VFT 005E8490, class : CWorm
  10730. PXS : work3
  10731. PXS : Making overidde of ^^^SetCurrentTeam@i
  10732. PXS : by ^^^^SetCurrentTeam@i
  10733. PXS : VFT 005EDD14, class : CTurnGame
  10734. PXS : work3
  10735. PXS : Making overidde of ^^^^^^^^^^^FireFinal@PCCWeapon@PCCShootDesc@
  10736. PXS : by ^^^^^^^^^^^^FireFinal@PCCWeapon@PCCShootDesc@
  10737. PXS : VFT 005E8490, class : CWorm
  10738. PXS : work3
  10739. PXS : Making overidde of ^^^^SetCurrentTeam@i
  10740. PXS : by ^^^^^SetCurrentTeam@i
  10741. PXS : VFT 005EDD14, class : CTurnGame
  10742. PXS : work3
  10743. PXS : Making overidde of ^^^^^^CWorm@PCCObject@iiPCCWormParams@
  10744. PXS : by ^^^^^^^CWorm@PCCObject@iiPCCWormParams@
  10745. PXS : VFT 005E8490, class : CWorm
  10746. PXS : work3
  10747. PXS : Making overidde of ^^^^^Message@PCCObject@eEMType@iPCCMessageData@
  10748. PXS : by ^^^^^^Message@PCCObject@eEMType@iPCCMessageData@
  10749. PXS : VFT 005E8490, class : CWorm
  10750. PXS : work3
  10751. PXS : Making overidde of ^^^^^^^^^^^^FireFinal@PCCWeapon@PCCShootDesc@
  10752. PXS : by ^^^^^^^^^^^^^FireFinal@PCCWeapon@PCCShootDesc@
  10753. PXS : VFT 005E8490, class : CWorm
  10754. PXS : work3
  10755. PXS : Making overidde of Message@PCCObject@eEMType@iPCCMessageData@
  10756. PXS : by Message@PCCObject@eEMType@iPCCMessageData@
  10757. PXS : VFT 08D60040, class : CTouchSensor
  10758. PXS : work3
  10759. PXS : Making overidde of Reflect@PCCGObject@i
  10760. PXS : by Reflect@PCCGObject@i
  10761. PXS : VFT 08D60040, class : CTouchSensor
  10762. PXS : work3
  10763. PXS : Making overidde of ^^Message@PCCObject@eEMType@iPCCMessageData@
  10764. PXS : by Message@PCCObject@eEMType@iPCCMessageData@
  10765. PXS : VFT 08D60098, class : StickyMine
  10766. PXS : work3
  10767. PXS : Making overidde of Collide@PCCGObject@i
  10768. PXS : by Collide@PCCGObject@i
  10769. PXS : VFT 08D60098, class : StickyMine
  10770. PXS : work3
  10771. PXS : Making overidde of Message@PCCObject@eEMType@iPCCMessageData@
  10772. PXS : by Message@PCCObject@eEMType@iPCCMessageData@
  10773. PXS : VFT 08D600E0, class : MovingOilDrum
  10774. PXS : work3
  10775. PXS : Making overidde of Message@PCCObject@eEMType@iPCCMessageData@
  10776. PXS : by Message@PCCObject@eEMType@iPCCMessageData@
  10777. PXS : VFT 08D601C0, class : CTurretBase
  10778. PXS : Detected derived from CTurretBase to CMineTurret
  10779. PXS : Detected derived from CTurretBase to CArrowTurret
  10780. PXS : Making overidde of Message@PCCObject@eEMType@iPCCMessageData@
  10781. PXS : by Message@PCCObject@eEMType@iPCCMessageData@
  10782. PXS : VFT 08D602A0, class : PxParticleManager
  10783. PXS : work3
  10784. PXS : Making overidde of Message@PCCObject@eEMType@iPCCMessageData@
  10785. PXS : by Message@PCCObject@eEMType@iPCCMessageData@
  10786. PXS : VFT 08D602C0, class : PxParticle
  10787. PXS : Making overidde of Message@PCCObject@eEMType@iPCCMessageData@
  10788. PXS : by Message@PCCObject@eEMType@iPCCMessageData@
  10789. PXS : VFT 08D602E0, class : PxAirstrike
  10790. PXS : Detected derived from PxAirstrike to PxBowlingBallStrike
  10791. PXS : Detected derived from PxAirstrike to PxBunkerBusterStrike
  10792. PXS : Making overidde of Free@B
  10793. PXS : by Free@B
  10794. PXS : VFT 08D60300, class : CBowlingBall
  10795. PXS : work3
  10796. PXS : Making overidde of ^^Message@PCCObject@eEMType@iPCCMessageData@
  10797. PXS : by Message@PCCObject@eEMType@iPCCMessageData@
  10798. PXS : VFT 08D60300, class : CBowlingBall
  10799. PXS : Making overidde of Collide@PCCGObject@i
  10800. PXS : by Collide@PCCGObject@i
  10801. PXS : VFT 08D60300, class : CBowlingBall
  10802. PXS : Making overidde of ^Render@
  10803. PXS : by Render@
  10804. PXS : VFT 08D60300, class : CBowlingBall
  10805. PXS : work3
  10806. PXS : Making overidde of ^^Message@PCCObject@eEMType@iPCCMessageData@
  10807. PXS : by Message@PCCObject@eEMType@iPCCMessageData@
  10808. PXS : VFT 08D60370, class : CMagnet
  10809. PXS : Detected derived from CMagnet to CMagnetMissile
  10810. PXS : Making overidde of Collide@PCCGObject@i
  10811. PXS : by Collide@PCCGObject@i
  10812. PXS : VFT 08D60370, class : CMagnet
  10813. PXS : Detected derived from CMagnet to CMagnetMissile
  10814. PXS : Making overidde of ^^Message@PCCObject@eEMType@iPCCMessageData@
  10815. PXS : by Message@PCCObject@eEMType@iPCCMessageData@
  10816. PXS : VFT 08D60420, class : PxBunkerBuster
  10817. PXS : Making overidde of DoExplosion@FFiiii
  10818. PXS : by DoExplosion@FFiiii
  10819. PXS : VFT 08D60420, class : PxBunkerBuster
  10820. PXS : work3
  10821. PXS : Making overidde of Collide@PCCGObject@i
  10822. PXS : by Collide@PCCGObject@i
  10823. PXS : VFT 08D60420, class : PxBunkerBuster
  10824. PXS : Making overidde of Message@PCCObject@eEMType@iPCCMessageData@
  10825. PXS : by Message@PCCObject@eEMType@iPCCMessageData@
  10826. PXS : VFT 08D60468, class : PxWindManager
  10827. PXS : Making overidde of ^^Message@PCCObject@eEMType@iPCCMessageData@
  10828. PXS : by Message@PCCObject@eEMType@iPCCMessageData@
  10829. PXS : VFT 08D60488, class : PxFan
  10830. PXS : Making overidde of Collide@PCCGObject@i
  10831. PXS : by Collide@PCCGObject@i
  10832. PXS : VFT 08D60488, class : PxFan
  10833. PXS : Making overidde of Message@PCCObject@eEMType@iPCCMessageData@
  10834. PXS : by Message@PCCObject@eEMType@iPCCMessageData@
  10835. PXS : VFT 08D60500, class : PxDeadWorm
  10836. PXS : Making overidde of Message@PCCObject@eEMType@iPCCMessageData@
  10837. PXS : by Message@PCCObject@eEMType@iPCCMessageData@
  10838. PXS : VFT 08D6051C, class : PxLightningStrike
  10839. PXS : Making overidde of ^^Message@PCCObject@eEMType@iPCCMessageData@
  10840. PXS : by Message@PCCObject@eEMType@iPCCMessageData@
  10841. PXS : VFT 08D60540, class : PxSentryGun
  10842. PXS : Making overidde of Collide@PCCGObject@i
  10843. PXS : by Collide@PCCGObject@i
  10844. PXS : VFT 08D60540, class : PxSentryGun
  10845. PXS : Making overidde of Message@PCCObject@eEMType@iPCCMessageData@
  10846. PXS : by Message@PCCObject@eEMType@iPCCMessageData@
  10847. PXS : VFT 08D6058C, class : CTazerDamage
  10848. PXS : Making overidde of Message@PCCObject@eEMType@iPCCMessageData@
  10849. PXS : by Message@PCCObject@eEMType@iPCCMessageData@
  10850. PXS : VFT 08D605A8, class : CTazerShot
  10851. PXS : Making overidde of ShootAtEnemy@
  10852. PXS : by ShootAtEnemy@
  10853. PXS : VFT 08D6020C, class : CMineTurret
  10854. PXS : work3
  10855. PXS : Making overidde of AimToEnemy@
  10856. PXS : by AimToEnemy@
  10857. PXS : VFT 08D60258, class : CArrowTurret
  10858. PXS : work3
  10859. PXS : Making overidde of ShootAtEnemy@
  10860. PXS : by ShootAtEnemy@
  10861. PXS : VFT 08D60258, class : CArrowTurret
  10862. PXS : Making overidde of DropBomb@
  10863. PXS : by DropBomb@
  10864. PXS : VFT 08D6034C, class : PxBowlingBallStrike
  10865. PXS : work3
  10866. PXS : Making overidde of RenderPlane@
  10867. PXS : by RenderPlane@
  10868. PXS : VFT 08D6034C, class : PxBowlingBallStrike
  10869. PXS : work3
  10870. PXS : Making overidde of Collide@PCCGObject@i
  10871. PXS : by Collide@PCCGObject@i
  10872. PXS : VFT 08D603B8, class : CMagnetMissile
  10873. PXS : work3
  10874. PXS : Making overidde of Message@PCCObject@eEMType@iPCCMessageData@
  10875. PXS : by Message@PCCObject@eEMType@iPCCMessageData@
  10876. PXS : VFT 08D603B8, class : CMagnetMissile
  10877. PXS : work3
  10878. PXS : Making overidde of DropBomb@
  10879. PXS : by DropBomb@
  10880. PXS : VFT 08D60404, class : PxBunkerBusterStrike
  10881. PXS : Making overidde of RenderPlane@
  10882. PXS : by RenderPlane@
  10883. PXS : VFT 08D60404, class : PxBunkerBusterStrike
  10884. PXS : Linking..
  10885. PXS : Updating class sizes..
  10886. PXS : Compiled from 07930004
  10887. PXS : Code size - 129,91 KB (12,991%)
  10888. PXS : Variables size - 11,69 KB (1,169%)
  10889. PXS : HKLIBEX extra memory size - 9,13 KB (0,713%)
  10890. PXS : Linked
  10891. PXS : ESS has been initialized
  10892. Loading hi\bazooka.img
  10893. Loading hi\bazooka.img
  10894. Loading hi\hmissile.img
  10895. Loading hi\mortar.img
  10896. Loading hi\pigeon.img
  10897. Loading hi\launch.img
  10898. Loading hi\grenade.img
  10899. Loading hi\cluster.img
  10900. Loading hi\banana.img
  10901. Loading hi\axe.img
  10902. Loading hi\quake.img
  10903. Loading hi\shotgun.img
  10904. Loading hi\handgun.img
  10905. Loading hi\uzi.img
  10906. Loading hi\minigun.img
  10907. Loading hi\longbow.img
  10908. Loading hi\firepnch.img
  10909. Loading hi\dragball.img
  10910. Loading hi\kamikaze.img
  10911. Loading hi\suicide.img
  10912. Loading hi\prod.img
  10913. Loading hi\dynamite.img
  10914. Loading hi\mine.img
  10915. Loading hi\sheep.img
  10916. Loading hi\sprsheep.img
  10917. Loading hi\aqua.img
  10918. Loading hi\mole.img
  10919. Loading hi\airstrke.img
  10920. Loading hi\firestrk.img
  10921. Loading hi\postal.img
  10922. Loading hi\minestrk.img
  10923. Loading hi\molestrk.img
  10924. Loading hi\blwtorch.img
  10925. Loading hi\drill.img
  10926. Loading hi\girder.img
  10927. Loading hi\baseball.img
  10928. Loading hi\girders.img
  10929. Loading hi\rope.img
  10930. Loading hi\bungee.img
  10931. Loading hi\parachut.img
  10932. Loading hi\teleport.img
  10933. Loading hi\scales.img
  10934. Loading hi\sbanana.img
  10935. Loading hi\hgrenade.img
  10936. Loading hi\thrower.img
  10937. Loading hi\tamborin.img
  10938. Loading hi\mbbomb.img
  10939. Loading hi\petrolbm.img
  10940. Loading hi\skunk.img
  10941. Loading hi\mingvase.img
  10942. Loading hi\shpstrke.img
  10943. Loading hi\carpet.img
  10944. Loading hi\cow.img
  10945. Loading hi\oldwoman.img
  10946. Loading hi\donkey.img
  10947. Loading hi\nuke.img
  10948. Loading hi\armagedn.img
  10949. Loading hi\skipgo.img
  10950. Loading hi\surender.img
  10951. Loading hi\select.img
  10952. Loading hi\freeze.img
  10953. Loading hi\bullet.img
  10954. Loading hi\jetpack.img
  10955. Loading hi\gravity.img
  10956. Loading hi\speed.img
  10957. Loading hi\laser.img
  10958. Loading hi\invisibl.img
  10959. Loading hi\damagex2.img
  10960. Loading hi\cratespy.img
  10961. Loading hi\cratespy.img
  10962. Loading hi\cratespy.img
  10963. Loading hi\bazooka.img
  10964. Weapon from lib
  10965. Loading ico_magmissile.png
  10966. Loading done
  10967. Loading hi\hmissile.img
  10968. Loading hi\mortar.img
  10969. Loading hi\pigeon.img
  10970. Loading hi\launch.img
  10971. Weapon from lib
  10972. Loading gravitynade.png
  10973. Loading done
  10974. Weapon from lib
  10975. Loading WindyNade.png
  10976. Loading done
  10977. Weapon from lib
  10978. Loading oildrum.png
  10979. Loading done
  10980. Weapon from lib
  10981. Loading ic_telenade.png
  10982. Loading done
  10983. Weapon from lib
  10984. Loading stickymine.png
  10985. Loading done
  10986. Weapon from lib
  10987. Loading ico_tazer.png
  10988. Loading done
  10989. Loading hi\handgun.img
  10990. Loading hi\uzi.img
  10991. Loading hi\minigun.img
  10992. Loading hi\longbow.img
  10993. Loading hi\firepnch.img
  10994. Loading hi\dragball.img
  10995. Loading hi\kamikaze.img
  10996. Loading hi\suicide.img
  10997. Loading hi\prod.img
  10998. Weapon from lib
  10999. Loading ico_bowling.png
  11000. Loading done
  11001. Weapon from lib
  11002. Loading ico_sentrygun.png
  11003. Loading done
  11004. Weapon from lib
  11005. Loading ico_magnet.png
  11006. Loading done
  11007. Weapon from lib
  11008. Loading ico_fan.png
  11009. Loading done
  11010. Loading hi\aqua.img
  11011. Loading hi\mole.img
  11012. Weapon from lib
  11013. Loading ico_bunkerbuster.png
  11014. Loading done
  11015. Weapon from lib
  11016. Loading ico_superbunkerbuster.png
  11017. Loading done
  11018. Weapon from lib
  11019. Loading ico_bbstrike.png
  11020. Loading done
  11021. Loading hi\minestrk.img
  11022. Loading hi\molestrk.img
  11023. Loading hi\blwtorch.img
  11024. Loading hi\drill.img
  11025. Loading hi\girder.img
  11026. Loading hi\baseball.img
  11027. Loading hi\girders.img
  11028. Loading hi\rope.img
  11029. Loading hi\bungee.img
  11030. Loading hi\parachut.img
  11031. Loading hi\teleport.img
  11032. Weapon from lib
  11033. Loading ico_glider.png
  11034. Loading done
  11035. Loading hi\sbanana.img
  11036. Loading hi\hgrenade.img
  11037. Loading hi\thrower.img
  11038. Loading hi\tamborin.img
  11039. Loading hi\mbbomb.img
  11040. Weapon from lib
  11041. Loading img_mineturret.png
  11042. Loading done
  11043. Weapon from lib
  11044. Loading img_balturret.png
  11045. Loading done
  11046. Weapon from lib
  11047. Loading ico_lightningstrike.png
  11048. Loading done
  11049. Loading hi\shpstrke.img
  11050. Loading hi\carpet.img
  11051. Loading hi\cow.img
  11052. Loading hi\oldwoman.img
  11053. Loading hi\donkey.img
  11054. Loading hi\nuke.img
  11055. Loading hi\armagedn.img
  11056. Loading hi\skipgo.img
  11057. Loading hi\surender.img
  11058. Loading hi\select.img
  11059. Loading hi\freeze.img
  11060. Loading hi\bullet.img
  11061. Loading hi\jetpack.img
  11062. Loading hi\gravity.img
  11063. Loading hi\speed.img
  11064. Loading hi\laser.img
  11065. Loading hi\invisibl.img
  11066. Loading hi\damagex2.img
  11067. Loading hi\cratespy.img
  11068. Loading hi\cratespy.img
  11069. Loading hi\cratespy.img
  11070. Loading done 4 all
  11071. SchemeMan initialized successfully!
  11072. Loaded
  11073. Done
  11074. PXS : calling method Init@
  11075. Calling method Init@ of class sync_script
  11076. WANEWOP allocated : 24
  11077. WANEWOP allocated : 8
  11078. WANEWOP allocated : 1024
  11079. WANEWOP allocated : 8
  11080. WANEWOP allocated : 1024
  11081. WANEWOP allocated : 8
  11082. WANEWOP allocated : 1024
  11083. WANEWOP allocated : 8
  11084. WANEWOP allocated : 1024
  11085. Runtime : Symbol initialized : CKeySync 0x03FB4E60
  11086. Calling method Init@ of class ldetector_script
  11087. WANEWOP allocated : 64
  11088. Runtime : Symbol initialized : CTouchSensorParent 0x0407B498
  11089. Calling method Init@ of class antiglitch_s
  11090. WANEWOP allocated : 24
  11091. Runtime : Symbol initialized : CAntiGlitch 0x03FA2418
  11092. Calling method Init@ of class darkness_script
  11093. WANEWOP allocated : 52
  11094. WANEWOP allocated : 8
  11095. WANEWOP allocated : 32768
  11096. Runtime : Symbol initialized : CDarknessControl 0x09DBAA58
  11097. Constructing render
  11098. Destructing DD
  11099. Intitiazlizing D3D wrapper..
  11100. Calling PX3D routines..
  11101. PX3D.dll : Fael to init d3D due to FAEL TO CREATE pD3DDevice! - D3DERR_INVALIDCALL!
  11102. D3D initialized successfully!
  11103. PX3D render initialization..
  11104. Done constructing render!
  11105. Runtime : CKeySync Generated : 0 pointers
  11106. Runtime : CTouchSensorParent Generated : 4 pointers
  11107. Runtime : CAntiGlitch Generated : 1 pointers
  11108. Runtime : CDarknessControl Generated : 0 pointers
  11109. Loading font 1
  11110. Loading font 2
  11111. Loading font 3
  11112. Loading font 4
  11113. Loading font 5
  11114. Loading font 6
  11115. Loading font 7
  11116. Loading font 8
  11117. Loading font 9
  11118. Loading font 10
  11119. Loading font 11
  11120. Loading font 12
  11121. Loading font 13
  11122. Loading font 14
  11123. Loading font 15
  11124. Loading font 16
  11125. Loading font 17
  11126. Loading font 18
  11127. Loading font 19
  11128. Loading font 20
  11129. Loading font 21
  11130. Loading font 22
  11131. Loading font 23
  11132. Loading font 24
  11133. Loading font 25
  11134. Loading font 26
  11135. Loading font 27
  11136. Loading font 28
  11137. Processing sprite 1,03FF00C0,1
  11138. NFrames : 25
  11139. Done
  11140. Have an erroR!
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement