Advertisement
connyloathsome

pxlog

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