Downloads containing deathcircle.mut

Downloads
Name Author Game Mode Rating
TSF with JJ2+ Only: Death CircleFeatured Download SmokeNC Mutator 9 Download file

File preview

  1.  
  2. /* Death Circle mutator for LRS, written by Smoke[NC] and VioletCLM DM april 2023 */
  3. /* VERSION 1.0 */
  4.  
  5. /* CONFIG VARIABLES */
  6. /* Speed of moving the center of the circle */
  7. const float cSpeed = 1;
  8. /* Minimum radius that the circle reaches after defaultCompletionTime */
  9. const float rMin = 300;
  10. /* Time it takes to reach minimum radius, in seconds */
  11. const float defaultCompletionTime = 120;
  12.  
  13. const uint8 ChromaKeyIndex = 25;
  14. int LayerZ;
  15.  
  16. void onLevelLoad()
  17. {
  18.         auto layers = jjLayerOrderGet();
  19.         LayerZ = 4 - layers.findByRef(jjLayers[4]) + 1;
  20.         jjLAYER storm(1,1);
  21.         storm.spriteMode = SPRITE::CHROMAKEY;
  22.         storm.spriteParam = ChromaKeyIndex;
  23.         storm.textureSurface = SURFACE::FULLSCREEN;
  24.         storm.xSpeed = storm.ySpeed = 1.1;
  25.         jjPIXELMAP stormImage(TEXTURE::DESOLATION);
  26.         array<uint8> recolor(256);
  27.         for (uint i = 0; i < 32; ++i)
  28.                 recolor[176 + i] = ChromaKeyIndex + uint8(i / 5.2);
  29.         stormImage.recolor(recolor).makeTexture(storm);
  30.         storm.textureStyle = TEXTURE::WAVE;
  31.         storm.tileWidth = storm.tileHeight = true;
  32.         layers.insertAt(0, storm);
  33.         jjLayerOrderSet(layers);
  34.        
  35.         //mess with these numbers and see what looks good
  36.         storm.wave.amplitudeX = 0.125;
  37.         storm.wave.wavelengthX = 127;
  38.         storm.wave.amplitudeY = 0.25;
  39.         storm.wave.wavelengthY = 255;
  40.         storm.wave.waveSpeed = 3;
  41. }
  42.        
  43. float max(float x, float y)
  44. {
  45.         return x > y? x : y;
  46. }
  47.  
  48. class Point
  49. {
  50.         float x;
  51.         float y;
  52. }
  53.  
  54. class DeathCircle
  55. {
  56.         float r; /* Radius */
  57.         Point c; /* Center */
  58.     float rSpeed;
  59.         float rOrig;
  60.  
  61.         /* Death circle will always move to center of mass of the players */
  62.         Point CalcCenterOfMass()
  63.         {
  64.                 Point cNew;
  65.                 cNew.x = 0;
  66.                 cNew.y = 0;
  67.                
  68.                 int numPlayersInGame = 0;
  69.                 for(int iP = 0; iP < 32; iP++)
  70.                 {
  71.                         if(jjPlayers[iP].isInGame && !jjPlayers[iP].isZombie)
  72.                         {
  73.                                 numPlayersInGame++;
  74.                                 cNew.x += jjPlayers[iP].xPos;
  75.                                 cNew.y += jjPlayers[iP].yPos;
  76.                         }
  77.                 }
  78.                
  79.                 if(numPlayersInGame != 0)
  80.                 {
  81.                         cNew.x /= numPlayersInGame;
  82.                         cNew.y /= numPlayersInGame;
  83.                 }
  84.  
  85.                 return cNew;
  86.         }
  87.        
  88.         void UpdateSpeed(float completionTime)
  89.         {
  90.                 if(completionTime > 0)
  91.                 {
  92.                         rSpeed = (r - rMin) / (completionTime * 70);
  93.                 }
  94.                 else /* Special effect, expand the circle!*/
  95.                 {
  96.                         rSpeed = (rOrig - rMin) / (completionTime * 70);
  97.                 }
  98.         }
  99.        
  100.         DeathCircle()
  101.         {      
  102.                 r = 32 * sqrt(jjLayerWidth[4] * jjLayerWidth[4] + jjLayerHeight[4] * jjLayerHeight[4]) / 2 ;
  103.                 rOrig = r;
  104.                
  105.                 UpdateSpeed(defaultCompletionTime);
  106.                
  107.                 c.x = 32 * jjLayerWidth[4] / 2;
  108.                 c.y = 32 * jjLayerHeight[4] / 2;
  109.         }
  110.        
  111.         bool GoTo(float objx1, float objy1, float & out objx, float & out objy, float Startx, float Starty, float Endx, float Endy, float Speed, float Behind)
  112.         {
  113.             float angle = atan2((Endx - Startx), (Endy - Starty));
  114.             objx1 += sin(angle) * Speed;
  115.             objy1 += cos(angle) * Speed;
  116.             objx = objx1;
  117.             objy = objy1;
  118.         if (((Endx + Behind * sin(angle) - objx1) * (Endx + Behind * sin(angle) - objx1)
  119.                 + (Endy + Behind * cos(angle) - objy1) * (Endy + Behind * cos(angle) - objy1))
  120.                 < (Speed * 1.1 + 3) * (Speed * 1.1 + 3))
  121.         return true; //arrived to destination
  122.         else return false; //not arrived to destination
  123.     }
  124.  
  125.         void UpdateCircle()
  126.         {
  127.             Point cNew = CalcCenterOfMass();
  128.  
  129.                 Point cMaybeNew;
  130.                 bool arrived = GoTo(c.x, c.y, cMaybeNew.x, cMaybeNew.y, c.x, c.y, cNew.x, cNew.y, cSpeed, 0);
  131.                 /* To avoid circle jitter */
  132.                 if(!arrived)
  133.                 {
  134.                         c = cMaybeNew;
  135.                 }
  136.                 r = max(rMin, r - rSpeed);
  137.         }
  138.  
  139.         bool OutsideCircle(float x, float y)
  140.         {
  141.                 return (x - c.x) * (x - c.x) + (y - c.y) * (y - c.y) > r * r;
  142.         }
  143. }
  144.        
  145. DeathCircle deathCircle;
  146.  
  147. void onPlayer(jjPLAYER@ player)
  148. {
  149.     /* DRAW DEATH CIRCLE*/
  150.        
  151.         int height = jjResolutionHeight + 5;
  152.         int width = jjResolutionWidth + 5;
  153.         float r = deathCircle.r;
  154.         Point c = deathCircle.c;
  155.        
  156.         /* Draw circle using horizontal rectangles,
  157.         we draw 600 horizontal rectangles instead of drawing 600 * 800 pixels,
  158.         which is much faster! */
  159.         for(int iY = 0; iY < height; iY++)
  160.         {
  161.                 float recWidth;
  162.                 float y = player.cameraY + iY;
  163.                 float x0 = 0, x1 = 0;
  164.                 bool drawRec0, drawRec1;
  165.                
  166.                 /* Circle equation:
  167.                    (x-xC)^2 + (y-yC)^2 = r^2;
  168.                    Attempt to solve for x0,x1:
  169.                    x0,1 = xC +- sqrt(r^2 - (y-yC)^2) */
  170.                    
  171.                 float dRYSq = r * r - (y - c.y) * (y - c.y);
  172.                
  173.                 /* If this horizontal line is outside the circle, fill the entire width */
  174.                 if(dRYSq < 0)
  175.                 {
  176.                         x0 = player.cameraX + width;
  177.                         drawRec0 = true;
  178.                         drawRec1 = false;
  179.                 }
  180.                 else /*This horizontal line intersects the circle in 2 points */
  181.                 {
  182.                         float dRY = sqrt(dRYSq);
  183.                         x0 = c.x - dRY;
  184.                         x1 = c.x + dRY;
  185.                        
  186.                         drawRec0 = true;
  187.                         drawRec1 = true;
  188.                 }
  189.                
  190.                 /* Draw the rectangles:
  191.                    Left-Camera-Edge|---------------x0                      x1-----------------|Right-Camera-Edge */
  192.                 if(drawRec0)
  193.                 {
  194.                         if(deathCircle.OutsideCircle(player.cameraX + jjResolutionWidth / 2, player.cameraY + jjResolutionHeight / 2))
  195.                         jjDrawRectangle(player.cameraX, y, int(x0 - player.cameraX), 1, ChromaKeyIndex, SPRITE::TRANSLUCENT, 0, -10);
  196.                         else
  197.                         jjDrawRectangle(player.cameraX, y, int(x0 - player.cameraX), 1, ChromaKeyIndex, SPRITE::SINGLECOLOR, ChromaKeyIndex, LayerZ);
  198.                 }
  199.                
  200.                 if(drawRec1)
  201.                 {
  202.                         if(deathCircle.OutsideCircle(player.cameraX + jjResolutionWidth / 2, player.cameraY + jjResolutionHeight / 2))
  203.                         jjDrawRectangle(x1, y, int(player.cameraX + width - x1), 1, ChromaKeyIndex, SPRITE::TRANSLUCENT, 0 , -10);
  204.                         else
  205.                         jjDrawRectangle(x1, y, int(player.cameraX + width - x1), 1, ChromaKeyIndex, SPRITE::SINGLECOLOR, ChromaKeyIndex, LayerZ);
  206.                 }
  207.         }
  208.        
  209.        
  210.         /*HURT IF OUTSIDE CIRCLE*/
  211.        
  212.         if(deathCircle.OutsideCircle(player.xPos, player.yPos) && (jjGameState == GAME::STARTED || jjGameState == GAME::OVERTIME))
  213.         {
  214.                 player.hurt();
  215.         }
  216. }
  217.  
  218. enum packetCmd
  219. {      
  220.         COMMAND_NONE,
  221.         COMMAND_CLIENT_REQUEST_UPDATE_FROM_SERVER,
  222.         COMMAND_PLAYER_WANTS_BROADCAST
  223. }
  224.  
  225. void PopCircleStats(jjSTREAM &in packet)
  226. {
  227.         packet.pop(deathCircle.c.y);
  228.         packet.pop(deathCircle.c.x);
  229.         packet.pop(deathCircle.r);
  230.         packet.pop(deathCircle.rSpeed);
  231. }
  232.  
  233. void PushCircleStats(jjSTREAM &inout packet)
  234. {
  235.         packet.push(deathCircle.c.y);
  236.         packet.push(deathCircle.c.x);
  237.         packet.push(deathCircle.r);
  238.         packet.push(deathCircle.rSpeed);
  239. }
  240.  
  241. void BroadcastCircleStats()
  242. {
  243.         jjSTREAM packet;
  244.         if(jjIsServer)
  245.         {
  246.                 packet.push(COMMAND_NONE);
  247.         }
  248.         else
  249.         {
  250.                 packet.push(COMMAND_PLAYER_WANTS_BROADCAST);
  251.         }
  252.         PushCircleStats(packet);
  253.         jjSendPacket(packet);
  254. }
  255.  
  256. void ClientRequestCircleStats()
  257. {
  258.         jjSTREAM packet;
  259.         packet.push(COMMAND_CLIENT_REQUEST_UPDATE_FROM_SERVER);
  260.         jjSendPacket(packet);
  261. }
  262.  
  263. void onReceive(jjSTREAM &in packet, int clientID)
  264.  {
  265.         int cmd;
  266.         packet.pop(cmd);
  267.         switch (cmd)
  268.         {
  269.                 case COMMAND_CLIENT_REQUEST_UPDATE_FROM_SERVER:
  270.                         if (jjIsServer)
  271.                         {
  272.                                 BroadcastCircleStats();
  273.                         }
  274.                         break;
  275.                 case COMMAND_PLAYER_WANTS_BROADCAST:
  276.                         if (jjIsServer)
  277.                         {
  278.                                 PopCircleStats(packet);
  279.                                 BroadcastCircleStats();
  280.                         }
  281.                         break;
  282.                 case COMMAND_NONE:
  283.                         if (!jjIsServer)
  284.                         {
  285.                                 PopCircleStats(packet);
  286.                         }
  287.                         break;
  288.                 default:
  289.                         jjAlert("Error in packet command!");
  290.                         break;
  291.         }
  292. }
  293.  
  294. bool onLocalChat(string &in stringReceived, CHAT::Type chatType)
  295. {
  296.         array<string> results;
  297.        
  298.         if (jjRegexIsValid(stringReceived) && (jjIsAdmin || jjIsServer))
  299.         {
  300.                 if (jjRegexMatch(stringReceived, "!deathcircle\\s+(.+)", results, true))
  301.                 {
  302.                         float circleCompletionTime = parseFloat(results[1]);
  303.                         if(circleCompletionTime != 0.f)
  304.                         {
  305.                                 jjAlert("DeathCircle timelimit has been set to " + circleCompletionTime + " minutes", true);
  306.                                 deathCircle.UpdateSpeed(circleCompletionTime * 60);
  307.                                 BroadcastCircleStats();
  308.                                 return true;
  309.                         }
  310.                 }
  311.         }
  312.  
  313.         return false;
  314. }
  315.  
  316. void onLevelBegin()
  317. {
  318.         jjAlert("ADMINS: type !deathcircle <time_m> to change DeathCircle timelimit for this match, default is 2");
  319.         deathCircle = DeathCircle();
  320.         if(!jjIsServer)
  321.         {
  322.                 ClientRequestCircleStats();
  323.         }
  324. }
  325.  
  326. void onMain()
  327. {
  328.         if(jjGameState == GAME::STARTED || jjGameState == GAME::OVERTIME)
  329.         {
  330.                 deathCircle.UpdateCircle();
  331.         }
  332. }
  333.