Downloads containing SEdec.j2as

Downloads
Name Author Game Mode Rating
JJ2+ Only: Anniversary Bash 25 Battle Jazz2Online Battle N/A Download file
TSF with JJ2+ Only: Anniversary Bash 20 Levels Jazz2Online Multiple N/A Download file
TSF with JJ2+ Only: Anniversary Bash 18 Levels Jazz2Online Multiple N/A Download file
JJ2+ Only: DecimationFeatured Download Seren Battle 8.5 Download file

File preview

  1. namespace palshift {
  2.         const array<uint8> ammoCount = {208, 232, 240, 216};
  3.         const uint8 asmdParticle = 221;
  4.         const uint8 barrel = 64;
  5.         const uint8 barrelDurability = 232;
  6.         const uint8 enemyHealth = 216;
  7.         const uint8 flak = 32;
  8.         const array<uint8> machineBadge = {249, 1, 241, 1, 249, 249, 9, 9, 17, 33};
  9.         const uint8 machineShard = 248;
  10.         const array<uint8> machineSpring = {0, 8, 248, 8, 0, 0, 16, 16, 0, 248};
  11.         const array<uint8> rocketShard = {200, 248};
  12.         const array<uint8> turret = {0, 248, 232, 248, 240, 240, 0, 0, 8, 24};
  13.         const uint8 turretDurability = 16;
  14. }
  15. namespace rabbit {
  16.         const int blinkingTime = 40;
  17. }
  18. namespace tileset {
  19.         const uint blackLine = 131;
  20.         const uint blackSquare = 114;
  21.         const uint empty = 0;
  22.         const uint healthBar = 230;
  23.         const uint ventShaft = 19;
  24.         const uint wall = 10;
  25.         const uint weaponLarge = 140;
  26.         const uint weaponSmall = 200;
  27.         const uint weaponSmallInactive = 205;
  28. }
  29. namespace trigger {
  30.         enum option {disableSD, friendlyFire, damageAmplifier}
  31. }
  32. namespace weapon {
  33.         const uint8 count = client::isCoopOrSP() ? 4 : 6;
  34.         const int dispersionPistolRegenerationTime = 80;
  35.         const int displayTime = 40;
  36.         const array<int> fireInterval = {0, 25, 5, 32, 70, 40, 1, 0, 0, 0};
  37.         const uint8 first = 1;
  38.         enum flags {maxDamage = 7, allowSD = 8}
  39.         const array<string> name = {"0", "Dispersion Pistol", "Machine Gun", "ASMD", "Rocket Launcher", "Flak Cannon", "Flamethrower", "7", "8", "9"};
  40.         const array<int> pickupMultiplier = {0, 1, 20, 4, 1, 1, 50, 0, 0, 0};
  41. }
  42. interface Itile {
  43.         void step();
  44. }
  45. class TlocalPlayer {
  46.         int dispersionPistolRegenerationTimer, fireIntervalTimer, weaponChangeTimer;
  47.         bool keyFirePrevious;
  48.         uint8 weaponLastShot, weaponPrevious;
  49.         TlocalPlayer() {
  50.                 dispersionPistolRegenerationTimer = fireIntervalTimer = weaponChangeTimer = 0;
  51.                 weaponPrevious = weaponLastShot = WEAPON::BLASTER;
  52.                 keyFirePrevious = false;
  53.         }
  54. }
  55. class Tsprite {
  56.         int x, y, direction;
  57.         uint frame;
  58.         SPRITE::Mode mode;
  59.         uint8 param;
  60.         void draw(jjCANVAS@ canvas) const {
  61.                 canvas.drawSpriteFromCurFrame(x, y, frame, direction, mode, param);
  62.         }
  63. }
  64. class TventShaft : Itile {
  65.         private int x, y;
  66.         private float xHigh, xLow, yHigh, yLow;
  67.         TventShaft(int X, int Y) {
  68.                 x = X * 32 + 12;
  69.                 y = Y * 32 + 12;
  70.                 xHigh = x + 328;
  71.                 yHigh = y + 248;
  72.                 xLow = x - 320;
  73.                 yLow = y - 240;
  74.         }
  75.         void step() {
  76.                 if (client::isIdleServer())
  77.                         return;
  78.                 if (jjGameTicks & 1 == 0) {
  79.                         const uint random = jjRandom();
  80.                         if (random & 1 == 0) {
  81.                                 for (int i = 0; i < jjLocalPlayerCount; i++) {
  82.                                         const jjPLAYER@ player = jjLocalPlayers[i];
  83.                                         if (player.cameraX < xHigh && player.cameraY <= yHigh && player.cameraX + jjSubscreenWidth > xLow && player.cameraY + jjSubscreenHeight > yLow) {
  84.                                                 jjPARTICLE@ part = jjAddParticle(PARTICLE::SMOKE);
  85.                                                 if (part !is null) {
  86.                                                         part.xPos = x + (random >> 1 & 7);
  87.                                                         part.yPos = y + (random >> 4 & 7);
  88.                                                         part.ySpeed = (random >> 7 & 3) / 4.f - 1.5f;
  89.                                                 }
  90.                                                 return;
  91.                                         }
  92.                                 }
  93.                         }
  94.                 }
  95.         }
  96. }
  97. bool onDrawAmmo(jjPLAYER@ player, jjCANVAS@ canvas) {
  98.         if (client::isIdleServer())
  99.                 return true;
  100.         if (jjSubscreenWidth >= 640 && jjSubscreenHeight >= 384) {
  101.                 draw::weaponIconBarVertical(canvas, jjSubscreenWidth - 88, jjSubscreenHeight / 2, player);
  102.         } else if (jjSubscreenWidth >= 640) {
  103.                 draw::weaponIconBarHorizontal(canvas, jjSubscreenWidth / 2, jjSubscreenHeight - 40, player);
  104.         } else if (jjSubscreenWidth >= 512 || jjSubscreenHeight >= 400) {
  105.                 uint8 weapon = player.currWeapon;
  106.                 draw::largeWeaponIcon(canvas, jjSubscreenWidth - 176, jjSubscreenHeight - 80, weapon - 1);
  107.                 draw::ammoCounter(canvas, jjSubscreenWidth - 176, jjSubscreenHeight - 24, player.ammo[weapon], jjWeapons[weapon].maximum, true);
  108.                 if (client::localPlayer[player.localPlayerID].weaponChangeTimer > 0)
  109.                         draw::weaponName(canvas, jjSubscreenWidth - 16, jjSubscreenHeight - 72, weapon);
  110.         } else {
  111.                 uint8 weapon = player.currWeapon;
  112.                 draw::smallWeaponIcon(canvas, jjSubscreenWidth - 88, jjSubscreenHeight - 40, weapon - 1, true);
  113.                 draw::ammoCounter(canvas, jjSubscreenWidth - 88, jjSubscreenHeight - 8, player.ammo[weapon], jjWeapons[weapon].maximum, true);
  114.         }
  115.         return true;
  116. }
  117. bool onDrawHealth(jjPLAYER@ player, jjCANVAS@ canvas) {
  118.         if (client::isIdleServer())
  119.                 return true;
  120.         if (jjSubscreenWidth >= 512 || jjSubscreenHeight >= 400) {
  121.                 draw::healthBar(canvas, 16, text::getScoreHUDHeight(jjGameMode), player.health, jjMaxHealth, player.blink > 0 && jjGameTicks >> 2 & 1 == 0);
  122.                 return true;
  123.         }
  124.         return false;
  125. }
  126. void onDrawLayer3(jjPLAYER@, jjCANVAS@ canvas) {
  127.         if (client::isIdleServer())
  128.                 return;
  129.         sprite::drawQueue(canvas, 2);
  130.         jjTileType[tileset::blackLine] = jjTileType[tileset::blackSquare] = 1;
  131. }
  132. void onDrawLayer4(jjPLAYER@, jjCANVAS@ canvas) {
  133.         if (client::isIdleServer())
  134.                 return;
  135.         if (!client::isCoopOrSP()) {
  136.                 for (int i = 0; i < jjObjectCount; i++) {
  137.                         jjOBJ@ obj = jjObjects[i];
  138.                         if (!obj.isActive || obj.eventID != OBJECT::GENERATOR)
  139.                                 continue;
  140.                         if (obj.direction == 0)
  141.                                 obj.direction = obj.var[3] != OBJECT::TNT && (obj.xPos / 32 % 2 > 1 ^^ obj.yPos / 32 % 2 > 1) ? -1 : 1;
  142.                         bool draw = obj.var[0] <= 0;
  143.                         if (!draw) {
  144.                                 jjOBJ@ item = jjObjects[obj.var[0]];
  145.                                 draw = !item.isActive || item.creatorType != CREATOR::LEVEL || item.creatorID != uint(obj.objectID);
  146.                         }
  147.                         if (draw)
  148.                                 canvas.drawSpriteFromCurFrame(int(obj.xPos), int(obj.yPos), jjObjectPresets[obj.var[3]].curFrame, obj.direction, SPRITE::SINGLECOLOR, 79);
  149.                 }
  150.         }
  151.         sprite::drawQueue(canvas, 3);
  152. }
  153. void onDrawLayer7(jjPLAYER@, jjCANVAS@) {
  154.         jjTileType[tileset::blackLine] = jjTileType[tileset::blackSquare] = 0;
  155. }
  156. bool onDrawLives(jjPLAYER@ player, jjCANVAS@ canvas) {
  157.         if (client::isIdleServer())
  158.                 return true;
  159.         if ((jjGameMode == GAME::COOP || jjGameMode == GAME::SP) && (jjSubscreenWidth >= 512 || jjSubscreenHeight >= 400)) {
  160.                 string text = formatInt(player.lives, "");
  161.                 canvas.drawString(43 - text::getSmallFontIntWidth(text) / 2, text::getScoreHUDHeight(jjGameMode) + 33, text);
  162.                 return true;
  163.         }
  164.         return false;
  165. }
  166. bool onDrawScore(jjPLAYER@, jjCANVAS@) {
  167.         return true;
  168. }
  169. void onLevelLoad() {
  170.         initialize::objectPresets();
  171.         initialize::weaponProfiles();
  172.         initialize::specialTiles();
  173.         initialize::palette();
  174.         jjTexturedBGTexture = TEXTURE::WTF;
  175.         if (client::isCoopOrSP()) {
  176.                 for (int i = 0; i < jjLayerHeight[4]; i++) {
  177.                         for (int j = 0; j < jjLayerWidth[4]; j++) {
  178.                                 if (jjParameterGet(j, i, -4, 2) == 3)
  179.                                         jjEventSet(j, i, 0);
  180.                         }
  181.                 }
  182.                 if (jjGameConnection == GAME::LOCAL) {
  183.                         jjChat("/flipmousewheel on");
  184.                         jjChat("/allowmouseaim on");
  185.                         if (jjLocalPlayerCount == 1)
  186.                                 jjChat("/mouseaim on");
  187.                         else
  188.                                 jjChat("/mouseaim off");
  189.                         int health = 6 - jjDifficulty;
  190.                         if (jjStartHealth != health || jjMaxHealth != health)
  191.                                 jjChat("/smhealth " + formatInt(health, ""));
  192.                 }
  193.         }
  194. }
  195. void onLevelReload() {
  196.         initialize::palette();
  197. }
  198. void onMain() {
  199.         for (int i = 0; i < 32; i++) {
  200.                 jjPLAYER@ player = jjPlayers[i];
  201.                 if (player.blink < -rabbit::blinkingTime)
  202.                         player.blink = -rabbit::blinkingTime;
  203.         }
  204.         for (uint i = 0; i < level::specialTile.length(); i++) {
  205.                 level::specialTile[i].step();
  206.         }
  207.         if ((jjIsServer || jjIsAdmin) && !client::admin) {
  208.                 jjAlert("/trigger " + formatInt(trigger::disableSD, "") + " " + (jjTriggers[trigger::disableSD] ? "off - enable" : "on - disable") + " Self-Destruction");
  209.                 jjAlert("/trigger " + formatInt(trigger::friendlyFire, "") + " " + (jjTriggers[trigger::friendlyFire] ? "off - disable" : "on - enable") + " Friendly Fire");
  210.                 jjAlert("/trigger " + formatInt(trigger::damageAmplifier, "") + " " + (jjTriggers[trigger::damageAmplifier] ? "off - disable" : "on - enable") + " Damage Amplifier");
  211.                 client::admin = true;
  212.         }
  213.         if (client::isCoopOrSP()) {
  214.                 for (int i = 0; i < 1024; i++) {
  215.                         jjPARTICLE@ part = jjParticles[i];
  216.                         if (part.type == PARTICLE::STRING) {
  217.                                 if (part.string.text == "1") {
  218.                                         part.xSpeed = 0;
  219.                                         part.ySpeed = -5;
  220.                                         part.string.text = "|+ HP";
  221.                                 }
  222.                                 if ((part.ySpeed = part.ySpeed * 16 / 17 + 0.125f) > 0) {
  223.                                         part.string.text = "";
  224.                                 }
  225.                         }
  226.                 }
  227.         }
  228.         if (client::isCoopOrSP() != client::startedAsCoopOrSP) {
  229.                 for (int i = 0; i < jjLocalPlayerCount; i++) {
  230.                         jjPLAYER@ player = jjLocalPlayers[i];
  231.                         for (int j = 1; j < 10; j++) {
  232.                                 player.ammo[j] = 0;
  233.                                 player.powerup[j] = false;
  234.                         }
  235.                 }
  236.                 client::startedAsCoopOrSP = !client::startedAsCoopOrSP;
  237.                 if (jjIsServer || jjGameConnection == GAME::LOCAL)
  238.                         jjChat("/r");
  239.         }
  240. }
  241. void onObjectHit(jjOBJ@ obj, jjOBJ@ other, jjPLAYER@ player, int) {
  242.         if (obj is null)
  243.                 return;
  244.         if (other !is null) {
  245.                 if (obj.eventID == OBJECT::TNT)
  246.                         collision::barrelExplode(obj, other);
  247.                 return;
  248.         }
  249.         if (player !is null) {
  250.                 switch (obj.eventID) {
  251.                         case OBJECT::BOUNCERAMMO3:
  252.                                 collision::ammoPickup(player, obj, WEAPON::BOUNCER);
  253.                                 break;
  254.                         case OBJECT::ICEAMMO3:
  255.                                 collision::ammoPickup(player, obj, WEAPON::ICE);
  256.                                 break;
  257.                         case OBJECT::SEEKERAMMO3:
  258.                                 collision::ammoPickup(player, obj, WEAPON::SEEKER);
  259.                                 break;
  260.                         case OBJECT::RFAMMO3:
  261.                                 collision::ammoPickup(player, obj, WEAPON::RF);
  262.                                 break;
  263.                         case OBJECT::TOASTERAMMO3:
  264.                                 collision::ammoPickup(player, obj, WEAPON::TOASTER);
  265.                                 break;
  266.                         case OBJECT::BLASTERBULLET:
  267.                         case OBJECT::BOUNCERBULLET:
  268.                         case OBJECT::ICEBULLET:
  269.                         case OBJECT::SEEKERBULLET:
  270.                         case OBJECT::RFBULLET:
  271.                         case OBJECT::TOASTERBULLET:
  272.                                 collision::projectile(player, obj);
  273.                                 break;
  274.                 }
  275.         }
  276. }
  277. void onPlayer(jjPLAYER@ player) {
  278.         sprite::clearQueues();
  279.         player.frozen = player.score = 0;
  280.         player.fastfire = weapon::fireInterval[player.currWeapon];
  281.         TlocalPlayer@ thisPlayer = client::localPlayer[player.localPlayerID];
  282.         if (--thisPlayer.dispersionPistolRegenerationTimer < 0) {
  283.                 if (player.ammo[WEAPON::BLASTER] < jjWeapons[WEAPON::BLASTER].maximum) {
  284.                         player.ammo[WEAPON::BLASTER] = player.ammo[WEAPON::BLASTER] + weapon::pickupMultiplier[WEAPON::BLASTER];
  285.                         thisPlayer.dispersionPistolRegenerationTimer = weapon::dispersionPistolRegenerationTime;
  286.                 } else {
  287.                         thisPlayer.dispersionPistolRegenerationTimer = 0;
  288.                 }
  289.         }
  290.         thisPlayer.weaponChangeTimer--;
  291.         if (player.currWeapon != thisPlayer.weaponPrevious) {
  292.                 thisPlayer.weaponChangeTimer = weapon::displayTime;
  293.                 thisPlayer.weaponPrevious = player.currWeapon;
  294.         }
  295.         thisPlayer.fireIntervalTimer++;
  296.         if (client::isCoopOrSP() && jjLocalPlayerCount == 1) {
  297.                 if (jjMouseX >= 0 && jjMouseX < jjResolutionWidth && jjMouseY >= 0 && jjMouseY < jjResolutionHeight)
  298.                         player.cameraFreeze(player.xPos + jjMouseX - jjSubscreenWidth, player.yPos + jjMouseY - jjSubscreenHeight, false, true);
  299.                 else
  300.                         player.cameraUnfreeze();
  301.         }
  302. }
  303. void onPlayerInput(jjPLAYER@ player) {
  304.         TlocalPlayer@ thisPlayer = client::localPlayer[player.localPlayerID];
  305.         if (!thisPlayer.keyFirePrevious && player.keyFire) {
  306.                 if (thisPlayer.fireIntervalTimer < player.fastfire)
  307.                         player.keyFire = false;
  308.                 else
  309.                         thisPlayer.fireIntervalTimer = 0;
  310.         }
  311.         thisPlayer.keyFirePrevious = player.keyFire;
  312. }
  313. namespace behavior {
  314.         void asmdBeam(jjOBJ@ obj) {
  315.                 switch (obj.state) {
  316.                         case STATE::START:
  317.                                 obj.var[5] = jjGameTicks;
  318.                                 break;
  319.                         case STATE::ACTION:
  320.                                 obj.state = STATE::EXPLODE;
  321.                                 break;
  322.                 }
  323.                 obj.behave(BEHAVIOR::BULLET, false);
  324.                 if (obj.state != STATE::EXPLODE) {
  325.                         obj.xPos = obj.xPos + obj.xSpeed / 2;
  326.                         obj.yPos = obj.yPos + obj.ySpeed / 2;
  327.                         if (obj.counter % 2 == 0) {
  328.                                 explosion::simpleExplosion(obj.xPos, obj.yPos, ANIM::AMMO, 71);
  329.                                 if (obj.counter % 10 == 0)
  330.                                         explosion::asmdRing(obj.xPos, obj.yPos, obj.xSpeed, obj.ySpeed, 30.f / obj.counter, 10.f / obj.counter);
  331.                         }
  332.                 } else if (obj.age++ == 0 && jjMaskedPixel(int(obj.xPos), int(obj.yPos))){
  333.                         explosion::asmdRing(obj.xPos, obj.yPos, obj.xSpeed, obj.ySpeed, 6, 2);
  334.                         explosion::harmfulExplosion(obj.xPos, obj.yPos, 32, 2, 50, obj.creatorType == CREATOR::PLAYER ? jjPlayers[obj.creatorID] : null);
  335.                 }
  336.         }
  337.         void barrel(jjOBJ@ obj) {
  338.                 switch (obj.state) {
  339.                         case STATE::START:
  340.                                 if (jjParameterGet(uint(obj.xOrg) >> 5, uint(obj.yOrg) >> 5, -4, 2) != 3 ^^ client::isCoopOrSP()) {
  341.                                         obj.delete();
  342.                                         return;
  343.                                 }
  344.                                 obj.putOnGround();
  345.                                 obj.state = STATE::IDLE;
  346.                         case STATE::IDLE:
  347.                                 sprite::add(obj.xPos, obj.yPos, obj.curFrame, 0, SPRITE::PALSHIFT, palshift::barrel);
  348.                                 for (int i = 1; i < jjObjectCount; i++) {
  349.                                         jjOBJ@ bull = jjObjects[i];
  350.                                         if (bull.isActive
  351.                                                 && bull.playerHandling == HANDLING::SPECIAL
  352.                                                 && bull.animSpeed > 0
  353.                                                 && bull.state != STATE::START
  354.                                                 && bull.state != STATE::EXPLODE
  355.                                                 && bull.xPos > obj.xPos - 11
  356.                                                 && bull.xPos < obj.xPos + 15
  357.                                                 && bull.yPos > obj.yPos - 19
  358.                                                 && bull.yPos < obj.yPos + 15)
  359.                                                         collision::barrel(obj, bull);
  360.                                 }
  361.                                 if (obj.energy < jjObjectPresets[obj.eventID].energy) {
  362.                                         string text = formatInt(obj.energy, "");
  363.                                         jjDrawString(obj.xPos - text::getSmallFontIntWidth(text) / 2, obj.yPos + 16, text, STRING::SMALL, STRING::PALSHIFT, palshift::barrelDurability);
  364.                                 }
  365.                                 break;
  366.                         case STATE::EXTRA:
  367.                                 {
  368.                                         uint16 creatorID = obj.special >= 0 ? obj.special : 0;
  369.                                         CREATOR::Type creatorType = obj.special >= 0 ? CREATOR::PLAYER : CREATOR::OBJECT;
  370.                                         int ID = jjAddObject(OBJECT::BULLET, obj.xPos, obj.yPos, creatorID, creatorType, behavior::delete);
  371.                                         if (ID != 0) {
  372.                                                 jjOBJ@ bull = jjObjects[ID];
  373.                                                 bull.curFrame = obj.curFrame;
  374.                                                 bull.freeze = 1;
  375.                                                 bull.playerHandling = HANDLING::PLAYERBULLET;
  376.                                                 bull.state = STATE::IDLE;
  377.                                         }
  378.                                 }
  379.                                 break;
  380.                         case STATE::ACTION:
  381.                                 if (obj.special >= 0 || client::isCoopOrSP() || uint(++obj.counter) > obj.counterEnd) {
  382.                                         explosion::barrelExplosion(obj.xPos, obj.yPos, obj.special >= 0 ? jjPlayers[obj.special] : null);
  383.                                         obj.delete();
  384.                                 }
  385.                                 break;
  386.                 }
  387.         }
  388.         void bullet(jjOBJ@ obj) {
  389.                 if (obj.state == STATE::ACTION)
  390.                         obj.state = STATE::EXPLODE;
  391.                 obj.behave(BEHAVIOR::BULLET, false);
  392.                 sprite::add(obj.xPos, obj.yPos, obj.curFrame, int(obj.xSpeed));
  393.         }
  394.         void delete(jjOBJ@ obj) {
  395.                 if (++obj.age > 3)
  396.                         obj.delete();
  397.         }
  398.         void destructScenery(jjOBJ@ obj) {
  399.                 if (obj.special == 0) {
  400.                         if (client::isCoopOrSP()) {
  401.                                 obj.behavior = BEHAVIOR::DESTRUCTSCENERY;
  402.                                 obj.behave();
  403.                                 if (obj.eventID == OBJECT::DESTRUCTSCENERYBOMB)
  404.                                         obj.delete();
  405.                                 return;
  406.                         }
  407.                         jjTileSet(4, uint(obj.xOrg) >> 5, uint(obj.yOrg) >> 5, obj.eventID == OBJECT::DESTRUCTSCENERY ? tileset::wall : tileset::empty);
  408.                         obj.delete();
  409.                 }
  410.         }
  411.         void enemy(jjOBJ@ obj) {
  412.                 if (jjParameterGet(uint(obj.xOrg) >> 5, uint(obj.yOrg) >> 5, 8, 1) == 0) {
  413.                         obj.behavior = turret;
  414.                         obj.doesHurt = 1;
  415.                         obj.energy = 50;
  416.                         obj.determineCurAnim(ANIM::SONCSHIP, 6);
  417.                 } else {
  418.                         obj.behavior = machine;
  419.                         obj.doesHurt = 0;
  420.                         obj.var[0] = obj.var[1] = 30;
  421.                         obj.determineCurAnim(ANIM::SONCSHIP, 2);
  422.                 }
  423.                 obj.determineCurFrame();
  424.                 obj.behave();
  425.         }
  426.         void explosion(jjOBJ@ obj) {
  427.                 obj.behave(BEHAVIOR::EXPLOSION, false);
  428.                 sprite::add(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::RESIZED, obj.age, 3);
  429.         }
  430.         void flak(jjOBJ@ obj) {
  431.                 switch (obj.state) {
  432.                         case STATE::START:
  433.                                 obj.var[5] = 0;
  434.                                 obj.determineCurAnim(ANIM::PICKUPS, 44 + (jjRandom() & 3));
  435.                                 obj.determineCurFrame();
  436.                                 obj.state = STATE::DELAYEDSTART;
  437.                                 break;
  438.                         case STATE::DELAYEDSTART:
  439.                                 if (obj.special > 0) {
  440.                                         if (obj.var[7] * obj.xSpeed > 0)
  441.                                                 obj.xSpeed = obj.xSpeed + float(obj.var[7]) / 0x10000;
  442.                                         const float angle = atan2(obj.ySpeed, obj.xSpeed);
  443.                                         const float speed = sqrt(obj.xSpeed * obj.xSpeed + obj.ySpeed * obj.ySpeed);
  444.                                         for (int i = -obj.special; i <= obj.special; i++) {
  445.                                                 int ID = jjAddObject(OBJECT::RFBULLET, obj.xPos, obj.yPos, obj.creatorID, obj.creatorType);
  446.                                                 if (ID != 0) {
  447.                                                         float newAngle = angle + i * 0.05f;
  448.                                                         float newSpeed = speed + (i * i & 18);
  449.                                                         jjOBJ@ bull = jjObjects[ID];
  450.                                                         bull.counterEnd = obj.counterEnd + (i * i & 5);
  451.                                                         bull.direction = obj.direction;
  452.                                                         bull.special = 0;
  453.                                                         bull.xAcc = -obj.xAcc * cos(newAngle);
  454.                                                         bull.xSpeed = newSpeed * cos(newAngle);
  455.                                                         bull.yAcc = obj.yAcc;
  456.                                                         bull.ySpeed = newSpeed * sin(newAngle);
  457.                                                 }
  458.                                         }
  459.                                         obj.delete();
  460.                                         return;
  461.                                 }
  462.                                 obj.state = STATE::FLY;
  463.                                 break;
  464.                         case STATE::ACTION:
  465.                                 obj.state = STATE::EXPLODE;
  466.                         case STATE::EXPLODE:
  467.                                 explosion::simpleExplosion(obj.xPos, obj.yPos, ANIM::PICKUPS, 4);
  468.                                 obj.delete();
  469.                                 return;
  470.                 }
  471.                 uint8 damage = jjObjectPresets[obj.eventID].doesHurt * (obj.counterEnd - obj.counter) / (obj.counterEnd * (obj.var[9] + 1)) + 1;
  472.                 if (damage > weapon::maxDamage)
  473.                         damage = weapon::maxDamage;
  474.                 obj.doesHurt = damage | obj.var[5];
  475.                 if (uint(++obj.counter) > obj.counterEnd)
  476.                         obj.state = STATE::EXPLODE;
  477.                 obj.xSpeed = obj.xSpeed + obj.xAcc;
  478.                 obj.ySpeed = obj.ySpeed + obj.yAcc;
  479.                 float x = obj.xPos;
  480.                 obj.xPos = obj.xPos + obj.xSpeed;
  481.                 if (obj.counter > 5)
  482.                         obj.var[5] = weapon::allowSD;
  483.                 if (jjMaskedPixel(int(obj.xPos), int(obj.yPos))) {
  484.                         if (jjRandom() & 3 == 0)
  485.                                 jjSample(obj.xPos, obj.yPos, SOUND::COMMON_CUP);
  486.                         obj.counter += 4;
  487.                         obj.var[9] = obj.var[9] + 1;
  488.                         obj.xPos = x;
  489.                         obj.xSpeed = -obj.xSpeed;
  490.                         obj.xAcc = -obj.xAcc;
  491.                 }
  492.                 float y = obj.yPos;
  493.                 obj.yPos = obj.yPos + obj.ySpeed;
  494.                 if (jjMaskedPixel(int(obj.xPos), int(obj.yPos))) {
  495.                         obj.counter += 4;
  496.                         obj.var[9] = obj.var[9] + 1;
  497.                         obj.yPos = y;
  498.                         obj.ySpeed = -obj.ySpeed;
  499.                 }
  500.                 if (jjGameTicks % 7 == 0) {
  501.                         obj.frameID++;
  502.                         obj.determineCurFrame();
  503.                 }
  504.                 sprite::add(obj.xPos, obj.yPos, obj.curFrame, int(obj.xSpeed), SPRITE::PALSHIFT, palshift::flak);
  505.         }
  506.         void flame(jjOBJ@ obj) {
  507.                 obj.xSpeed = obj.xSpeed + obj.xAcc;
  508.                 obj.ySpeed = obj.ySpeed + obj.yAcc;
  509.                 float xPrev = obj.xPos;
  510.                 float yPrev = obj.yPos;
  511.                 obj.xPos = obj.xPos + obj.xSpeed;
  512.                 obj.yPos = obj.yPos + obj.ySpeed;
  513.                 if (jjRandom() & 15 == 0) {
  514.                         jjPARTICLE@ part = jjAddParticle(PARTICLE::SMOKE);
  515.                         if (part !is null) {
  516.                                 part.xPos = obj.xPos;
  517.                                 part.yPos = obj.yPos;
  518.                         }
  519.                 }
  520.                 switch (obj.state) {
  521.                         case STATE::START:
  522.                                 if (jjGameTicks & 6 == 0)
  523.                                         jjSample(obj.xPos, obj.yPos, SOUND::BILSBOSS_FIRE);
  524.                                 obj.xSpeed = obj.xSpeed * 4 + float(obj.var[7]) / 0x20000;
  525.                                 obj.ySpeed = obj.ySpeed * 4;
  526.                                 obj.age = abs(obj.xSpeed) > abs(obj.ySpeed) ? 1 : 0;
  527.                                 obj.state = STATE::FIRE;
  528.                         case STATE::FIRE:
  529.                                 {
  530.                                         bool masked = jjMaskedPixel(int(obj.xPos), int(obj.yPos));
  531.                                         if (masked || (obj.age == 1 ? abs(obj.xSpeed) < 1 : abs(obj.ySpeed) < 1)) {
  532.                                                 obj.xAcc = obj.yAcc = 0;
  533.                                                 obj.doesHurt = (obj.doesHurt & weapon::maxDamage) / 2 | weapon::allowSD;
  534.                                                 if (masked) {
  535.                                                         obj.xPos = xPrev;
  536.                                                         obj.yPos = yPrev;
  537.                                                         obj.xSpeed = obj.ySpeed = 0;
  538.                                                 }
  539.                                                 obj.state = STATE::FALL;
  540.                                         }
  541.                                 }
  542.                                 break;
  543.                         case STATE::FALL:
  544.                                 if (obj.yAcc < 0.125f)
  545.                                         obj.yAcc = obj.yAcc + 0.005f;
  546.                                 if (jjMaskedPixel(int(obj.xPos), int(obj.yPos))) {
  547.                                         obj.xAcc = obj.xSpeed = obj.yAcc = obj.ySpeed = 0;
  548.                                         if (uint(++obj.counter) > obj.counterEnd)
  549.                                                 obj.state = STATE::EXPLODE;
  550.                                 }
  551.                                 break;
  552.                         case STATE::ACTION:
  553.                                 obj.state = STATE::EXPLODE;
  554.                         case STATE::EXPLODE:
  555.                                 explosion::simpleExplosion(obj.xPos, obj.yPos, ANIM::AMMO, 55);
  556.                                 obj.delete();
  557.                                 return;
  558.                 }
  559.                 if (jjGameTicks % 7 == 0) {
  560.                         obj.frameID++;
  561.                         obj.determineCurFrame();
  562.                 }
  563.                 sprite::add(obj.xPos, obj.yPos, obj.curFrame, int(obj.xSpeed));
  564.         }
  565.         void machine(jjOBJ@ obj) {
  566.                 const jjPLAYER@ nearestPlayer;
  567.                 float shortestDistanceSqr = 640 * 640;
  568.                 for (int i = 0; i < 32; i++) {
  569.                         const jjPLAYER@ player = jjPlayers[i];
  570.                         if (!player.isActive || player.health <= 0)
  571.                                 continue;
  572.                         float dx = player.xPos - obj.xPos;
  573.                         float dy = player.yPos - obj.yPos;
  574.                         float distanceSqr = dx * dx + 4 * dy * dy;
  575.                         if (distanceSqr < shortestDistanceSqr && level::isLineMaskFree(int(obj.xPos), int(obj.yPos), int(player.xPos), int(player.yPos))) {
  576.                                 @nearestPlayer = player;
  577.                                 shortestDistanceSqr = distanceSqr;
  578.                         }
  579.                 }
  580.                 int8 springFrame = 0;
  581.                 int yMod = 0;
  582.                 switch (obj.state) {
  583.                         case STATE::START:
  584.                                 obj.age = obj.var[0];
  585.                                 obj.counterEnd = 50 - jjDifficulty * 15;
  586.                                 obj.counter = obj.counterEnd / 2;
  587.                                 obj.direction = 1;
  588.                                 obj.special = jjParameterGet(uint(obj.xOrg) >> 5, uint(obj.yOrg) >> 5, 0, 8) % 10;
  589.                                 obj.var[4] = weapon::fireInterval[obj.special] * (4 - jjDifficulty);
  590.                                 obj.yAcc = 0.125f;
  591.                                 obj.yPos = obj.yPos - 25;
  592.                                 obj.state = STATE::IDLE;
  593.                         case STATE::IDLE:
  594.                                 if ((yMod = ((jjGameTicks >> 3) + obj.objectID) & 3) == 3)
  595.                                         yMod = 1;
  596.                                 if (obj.var[3] == 0 && nearestPlayer !is null) {
  597.                                         if (--obj.counter < 4)
  598.                                                 springFrame = 1;
  599.                                         if (obj.counter < 0) {
  600.                                                 obj.counter = 0;
  601.                                                 float xDistance = nearestPlayer.xPos - obj.xPos;
  602.                                                 if (xDistance * obj.direction >= 0) {
  603.                                                         obj.doesHurt = 0;
  604.                                                         obj.xSpeed = xDistance / 64;
  605.                                                         if (obj.xSpeed > 3)
  606.                                                                 obj.xSpeed = 3;
  607.                                                         else if (obj.xSpeed < -3)
  608.                                                                 obj.xSpeed = -3;
  609.                                                         obj.ySpeed = -5;
  610.                                                         jjSample(obj.xPos, obj.yPos + 40, SOUND::SPRING_SPRING1);
  611.                                                 } else {
  612.                                                         obj.doesHurt = 1;
  613.                                                         obj.xSpeed = 0;
  614.                                                         obj.ySpeed = -3;
  615.                                                         jjSample(obj.xPos, obj.yPos + 40, SOUND::SPRING_BOING_DOWN);
  616.                                                 }
  617.                                                 obj.state = STATE::JUMP;
  618.                                         }
  619.                                 }
  620.                                 break;
  621.                         case STATE::JUMP:
  622.                                 obj.xPos = obj.xPos + obj.xSpeed;
  623.                                 obj.yPos = obj.yPos + obj.ySpeed;
  624.                                 obj.ySpeed = obj.ySpeed + obj.yAcc;
  625.                                 if (obj.doesHurt > 0 && obj.ySpeed > 0 && nearestPlayer !is null && (nearestPlayer.xPos - obj.xPos) * obj.direction < 0) {
  626.                                         obj.direction = -obj.direction;
  627.                                         obj.doesHurt--;
  628.                                 }
  629.                                 if (++obj.counter < 12)
  630.                                         springFrame = (obj.counter >> 2) + 2;
  631.                                 if (jjMaskedVLine(int(obj.xPos) + obj.direction * 20, int(obj.yPos) - 12, 48)) {
  632.                                         obj.xSpeed = -obj.xSpeed;
  633.                                         obj.doesHurt++;
  634.                                 }
  635.                                 if (obj.ySpeed < 0 && jjMaskedHLine(int(obj.xPos) - 16, 32, int(obj.yPos) - 12))
  636.                                         obj.ySpeed = -obj.ySpeed / 2;
  637.                                 if (jjMaskedHLine(int(obj.xPos) - 16, 32, int(obj.yPos) + 42)) {
  638.                                         while (jjMaskedHLine(int(obj.xPos) - 16, 32, int(obj.yPos) + 41) && obj.yPos > 0) {
  639.                                                 obj.yPos = obj.yPos - 1;
  640.                                         }
  641.                                         explosion::machineStomp(obj.xPos, obj.yPos + 42);
  642.                                         obj.counter = obj.counterEnd;
  643.                                         obj.state = STATE::IDLE;
  644.                                 }
  645.                                 break;
  646.                         case STATE::EXPLODE:
  647.                                 for (int i = 0; i < 3; i++) {
  648.                                         if (obj.var[2] == 0)
  649.                                                 jjAddParticlePixelExplosion(obj.xPos - obj.direction * 9, obj.yPos + yMod - 7, obj.determineCurFrame(false), obj.direction, 1);
  650.                                         if (obj.var[3] == 0)
  651.                                                 jjAddParticlePixelExplosion(obj.xPos + obj.direction * 9, obj.yPos + yMod - 7, obj.determineCurFrame(false), obj.direction, 1);
  652.                                 }
  653.                                 explosion::machineExplosion(obj.xPos, obj.yPos);
  654.                                 obj.delete();
  655.                                 return;
  656.                 }
  657.                 if (obj.var[2] == 0
  658.                         && nearestPlayer !is null
  659.                         && (nearestPlayer.xPos - obj.xPos) * obj.direction >= 0
  660.                         && abs(nearestPlayer.yPos - obj.yPos) < 128
  661.                         && jjGameTicks % obj.var[4] == 0) {
  662.                                 int ID = jjAddObject(obj.special, obj.xPos + obj.direction * 35, obj.yPos + 13, obj.objectID);
  663.                                 if (obj.special > 3 && ID != 0) {
  664.                                         jjOBJ@ bull = jjObjects[ID];
  665.                                         bull.xPos = bull.xOrg;
  666.                                         bull.yPos = bull.yOrg;
  667.                                         bull.xSpeed = bull.xSpeed * obj.direction;
  668.                                         bull.xAcc = bull.xAcc * obj.direction;
  669.                                         bull.direction = obj.direction;
  670.                                 }
  671.                 }
  672.                 for (int i = 1; i < jjObjectCount; i++) {
  673.                         jjOBJ@ bull = jjObjects[i];
  674.                         if (bull.isActive
  675.                                 && bull.playerHandling == HANDLING::SPECIAL
  676.                                 && bull.animSpeed > 0
  677.                                 && bull.state != STATE::START
  678.                                 && bull.state != STATE::EXPLODE
  679.                                 && bull.xPos > obj.xPos - 30
  680.                                 && bull.xPos < obj.xPos + 30
  681.                                 && bull.yPos > obj.yPos - 30
  682.                                 && bull.yPos < obj.yPos + 30) {
  683.                                         float dx = bull.xPos - obj.xPos;
  684.                                         float dy = bull.yPos - obj.yPos;
  685.                                         if (dx * dx + dy * dy < 30 * 30)
  686.                                                 collision::machine(obj, bull);
  687.                                 }
  688.                 }
  689.                 obj.determineCurAnim(ANIM::SPRING, 4);
  690.                 obj.frameID = springFrame;
  691.                 sprite::add(obj.xPos, obj.yPos + 39, obj.determineCurFrame(false), 0, SPRITE::PALSHIFT, palshift::machineSpring[obj.special]);
  692.                 obj.determineCurAnim(ANIM::LIZARD, 2);
  693.                 obj.frameID = jjGameTicks >> 3 & 3;
  694.                 if (obj.var[2] == 0) {
  695.                         sprite::add(obj.xPos - obj.direction * 9, obj.yPos + yMod - 7, obj.determineCurFrame(false), obj.direction);
  696.                         if (obj.var[0] < obj.age) {
  697.                                 string text = formatInt(obj.var[0], "");
  698.                                 jjDrawString(obj.xPos - obj.direction * 20 - text::getSmallFontIntWidth(text) / 2, obj.yPos, text, STRING::SMALL, STRING::PALSHIFT, palshift::enemyHealth);
  699.                         }
  700.                 } else if (obj.var[2] == 1) {
  701.                         jjAddParticlePixelExplosion(obj.xPos - obj.direction * 9, obj.yPos + yMod - 7, obj.determineCurFrame(false), obj.direction, 0);
  702.                         obj.var[2] = 2;
  703.                 }
  704.                 obj.frameID = obj.frameID + 2 & 3;
  705.                 if (obj.var[3] == 0) {
  706.                         sprite::add(obj.xPos + obj.direction * 9, obj.yPos + yMod - 9, obj.determineCurFrame(false), obj.direction);
  707.                         if (obj.var[1] < obj.age) {
  708.                                 string text = formatInt(obj.var[1], "");
  709.                                 jjDrawString(obj.xPos + obj.direction * 20 - text::getSmallFontIntWidth(text) / 2, obj.yPos, text, STRING::SMALL, STRING::PALSHIFT, palshift::enemyHealth);
  710.                         }
  711.                 } else if (obj.var[3] == 1) {
  712.                         jjAddParticlePixelExplosion(obj.xPos + obj.direction * 9, obj.yPos + yMod - 7, obj.determineCurFrame(false), obj.direction, 0);
  713.                         obj.var[3] = 2;
  714.                 }
  715.                 sprite::add(obj.xPos, obj.yPos + yMod, obj.curFrame, obj.direction);
  716.                 obj.determineCurAnim(ANIM::AMMO, 8);
  717.                 obj.frameID = 4;
  718.                 sprite::add(obj.xPos - obj.direction * 9, obj.yPos + yMod + 11, obj.determineCurFrame(false), 0, SPRITE::PALSHIFT, palshift::machineBadge[obj.special]);
  719.         }
  720.         void pickup(jjOBJ@ obj) {
  721.                 switch (obj.state) {
  722.                         case STATE::START:
  723.                                 if (jjParameterGet(uint(obj.xOrg) >> 5, uint(obj.yOrg) >> 5, -4, 2) != 3 ^^ client::isCoopOrSP()) {
  724.                                         obj.delete();
  725.                                         return;
  726.                                 }
  727.                                 break;
  728.                         case STATE::ACTION:
  729.                                 jjSample(obj.xPos, obj.yPos, SOUND::COMMON_PICKUPW1);
  730.                                 explosion::simpleExplosion(obj.xPos, obj.yPos, ANIM::PICKUPS, 86);
  731.                                 obj.delete();
  732.                                 return;
  733.                         case STATE::FLOATFALL:
  734.                                 obj.state = STATE::FLOAT;
  735.                                 break;
  736.                 }
  737.                 obj.behave(BEHAVIOR::PICKUP, false);
  738.                 sprite::add(obj.xPos, obj.yPos + 4 * jjSin(((obj.objectID << 3) + jjGameTicks) << 4), obj.curFrame);
  739.         }
  740.         void rocket(jjOBJ@ obj) {
  741.                 switch (obj.state) {
  742.                         case STATE::START:
  743.                                 obj.state = STATE::ROCKETFLY;
  744.                                 break;
  745.                         case STATE::ACTION:
  746.                                 obj.state = STATE::EXPLODE;
  747.                         case STATE::EXPLODE:
  748.                                 explosion::rocketExplosion(obj.xPos, obj.yPos, obj.creatorType == CREATOR::PLAYER ? jjPlayers[obj.creatorID] : null);
  749.                                 obj.delete();
  750.                                 return;
  751.                 }
  752.                 obj.xSpeed = obj.xSpeed + obj.xAcc;
  753.                 obj.ySpeed = obj.ySpeed + obj.yAcc;
  754.                 obj.xPos = obj.xPos + obj.xSpeed;
  755.                 obj.yPos = obj.yPos + obj.ySpeed;
  756.                 if (jjMaskedPixel(int(obj.xPos), int(obj.yPos)))
  757.                         obj.state = STATE::EXPLODE;
  758.                 if (jjGameTicks % 7 == 0) {
  759.                         obj.frameID++;
  760.                         obj.determineCurFrame();
  761.                 }
  762.                 sprite::add(obj.xPos, obj.yPos, obj.curFrame, int(obj.xSpeed));
  763.         }
  764.         void savePoint(jjOBJ@ obj) {
  765.                 if (!client::isCoopOrSP()) {
  766.                         obj.delete();
  767.                         return;
  768.                 }
  769.                 obj.behave(BEHAVIOR::CHECKPOINT, false);
  770.                 sprite::add(obj.xPos, obj.yPos, obj.curFrame);
  771.         }
  772.         void shard(jjOBJ@ obj) {
  773.                 if (obj.age == 0)
  774.                         obj.age = (4 << (jjRandom() & 3)) - 1;
  775.                 obj.behave(BEHAVIOR::SHARD, false);
  776.                 obj.determineCurFrame();
  777.                 sprite::add(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::PALSHIFT, obj.special);
  778.                 uint random = jjRandom();
  779.                 if (random & obj.age == 0) {
  780.                         jjPARTICLE@ part = jjAddParticle(PARTICLE::FIRE);
  781.                         if (part !is null) {
  782.                                 part.xPos = obj.xPos;
  783.                                 part.yPos = obj.yPos;
  784.                         }
  785.                 }
  786.         }
  787.         void shortLivedParticle(jjOBJ@ obj) {
  788.                 if (--obj.counter < 0) {
  789.                         obj.delete();
  790.                         return;
  791.                 }
  792.                 obj.xSpeed = obj.xSpeed + obj.xAcc;
  793.                 obj.ySpeed = obj.ySpeed + obj.yAcc;
  794.                 obj.xPos = obj.xPos + obj.xSpeed;
  795.                 obj.yPos = obj.yPos + obj.ySpeed;
  796.                 if (jjGameTicks % 7 == 0 || obj.state == STATE::START) {
  797.                         obj.frameID++;
  798.                         obj.determineCurFrame();
  799.                 }
  800.                 sprite::add(obj.xPos, obj.yPos, obj.curFrame, 0, SPRITE::Mode(obj.special), obj.var[0]);
  801.         }
  802.         void spring(jjOBJ@ obj) {
  803.                 if (obj.state == STATE::START && jjParameterGet(uint(obj.xOrg) >> 5, uint(obj.yOrg) >> 5, -4, 2) == 3 && client::isCoopOrSP()) {
  804.                         obj.delete();
  805.                         return;
  806.                 }
  807.                 obj.behave(BEHAVIOR::SPRING, false);
  808.                 sprite::add(obj.xPos, obj.yPos, obj.curFrame);
  809.         }
  810.         void turret(jjOBJ@ obj) {
  811.                 switch (obj.state) {
  812.                         case STATE::START:
  813.                                 obj.age = obj.energy;
  814.                                 obj.direction = 64;
  815.                                 obj.special = jjParameterGet(uint(obj.xOrg) >> 5, uint(obj.yOrg) >> 5, 0, 8) % 10;
  816.                                 obj.yPos = obj.yPos - 8;
  817.                                 obj.state = STATE::DELAYEDSTART;
  818.                                 break;
  819.                         case STATE::EXPLODE:
  820.                                 obj.counter = 35;
  821.                                 obj.state = STATE::EXTRA;
  822.                         case STATE::EXTRA:
  823.                                 if (--obj.counter & 15 == 0)
  824.                                         explosion::turretExplosion(obj.xPos, obj.yPos);
  825.                                 if (obj.counter < 0)
  826.                                         obj.delete();
  827.                                 return;
  828.                 }
  829.                 obj.counter--;
  830.                 const jjPLAYER@ nearestPlayer;
  831.                 float xDistance = 0;
  832.                 float yDistance = 0;
  833.                 for (int i = 0; i < 32; i++) {
  834.                         const jjPLAYER@ player = jjPlayers[i];
  835.                         if (!player.isActive || player.health <= 0 || player.yPos <= obj.yPos)
  836.                                 continue;
  837.                         float dx = player.xPos - obj.xPos;
  838.                         float dy = player.yPos - obj.yPos;
  839.                         if ((nearestPlayer is null || dx * dx + dy * dy < xDistance * xDistance + yDistance * yDistance)
  840.                                 && level::isLineMaskFree(int(obj.xPos), int(obj.yPos), int(player.xPos), int(player.yPos))) {
  841.                                         @nearestPlayer = player;
  842.                                         xDistance = dx;
  843.                                         yDistance = dy;
  844.                         }
  845.                 }
  846.                 if (nearestPlayer !is null) {
  847.                         float angle = atan2(yDistance, xDistance);
  848.                         int convertedAngle = int(angle * 125 / 3.1415927f);
  849.                         if (obj.direction != convertedAngle) {
  850.                                 if (obj.state == STATE::DELAYEDSTART) {
  851.                                         obj.direction = convertedAngle;
  852.                                 } else {
  853.                                         if (obj.direction < convertedAngle)
  854.                                                 obj.direction++;
  855.                                         else
  856.                                                 obj.direction--;
  857.                                 }
  858.                                 if (obj.direction < 8)
  859.                                         obj.direction = 8;
  860.                                 else if (obj.direction >= 120)
  861.                                         obj.direction = 120;
  862.                                 obj.frameID = (125 - obj.direction) / 14 - 1;
  863.                                 if (obj.frameID < 0)
  864.                                         obj.frameID = 0;
  865.                                 else if (obj.frameID > 6)
  866.                                         obj.frameID = 6;
  867.                                 obj.determineCurFrame();
  868.                         }
  869.                         if (obj.counter <= 0) {
  870.                                 int convertedDirection = obj.direction * 512 / 125;
  871.                                 int8 direction = obj.direction;
  872.                                 obj.direction = 1;
  873.                                 int ID = jjAddObject(obj.special, obj.xPos + 20 * jjCos(convertedDirection), obj.yPos + 20 * jjSin(convertedDirection), obj.objectID);
  874.                                 obj.direction = direction;
  875.                                 if (ID != 0) {
  876.                                         jjOBJ@ bull = jjObjects[ID];
  877.                                         float speed = bull.xSpeed;
  878.                                         float acc = bull.xAcc;
  879.                                         bull.xPos = bull.xOrg;
  880.                                         bull.yPos = bull.yOrg;
  881.                                         bull.xSpeed = speed * jjCos(convertedDirection);
  882.                                         bull.ySpeed = speed * jjSin(convertedDirection);
  883.                                         bull.xAcc = acc * jjCos(convertedDirection);
  884.                                         bull.yAcc = acc * jjSin(convertedDirection);
  885.                                         bull.direction = bull.xSpeed >= 0 ? 1 : -1;
  886.                                 }
  887.                                 obj.counter = weapon::fireInterval[obj.special] << 3 >> jjDifficulty;
  888.                         }
  889.                 }
  890.                 if (obj.state == STATE::DELAYEDSTART)
  891.                         obj.state = STATE::ROTATE;
  892.                 for (int i = 1; i < jjObjectCount; i++) {
  893.                         jjOBJ@ bull = jjObjects[i];
  894.                         if (bull.isActive
  895.                                 && bull.playerHandling == HANDLING::SPECIAL
  896.                                 && bull.animSpeed > 0
  897.                                 && bull.state != STATE::START
  898.                                 && bull.state != STATE::EXPLODE
  899.                                 && bull.xPos > obj.xPos - 10
  900.                                 && bull.xPos < obj.xPos + 10
  901.                                 && bull.yPos > obj.yPos - 10
  902.                                 && bull.yPos < obj.yPos + 10)
  903.                                         collision::turret(obj, bull);
  904.                 }
  905.                 sprite::add(obj.xPos, obj.yPos, obj.curFrame, 0, SPRITE::PALSHIFT, palshift::turret[obj.special]);
  906.                 if (obj.energy < obj.age) {
  907.                         string text = formatInt(obj.energy, "");
  908.                         jjDrawString(obj.xPos - text::getSmallFontIntWidth(text) / 2, obj.yPos + 32, text, STRING::SMALL, STRING::PALSHIFT, palshift::turretDurability);
  909.                 }
  910.         }
  911. }
  912. namespace client {
  913.         bool admin = false;
  914.         int lastIdleServer = 0;
  915.         array<TlocalPlayer> localPlayer(jjLocalPlayerCount);
  916.         bool startedAsCoopOrSP = isCoopOrSP();
  917.         bool isCoopOrSP() {
  918.                 return jjGameMode == GAME::SP || jjGameMode == GAME::COOP;
  919.         }
  920.         bool isIdleServer() {
  921.                 return lastIdleServer == jjGameTicks || (jjIsServer && jjLocalPlayers[0].xPos == 0 && jjLocalPlayers[0].yPos == 0 && (lastIdleServer = jjGameTicks) != 0);
  922.         }
  923. }
  924. namespace collision {
  925.         void ammoPickup(jjPLAYER@ player, jjOBJ@ obj, WEAPON::Weapon type) {
  926.                 if (player.ammo[type] >= jjWeapons[type].maximum)
  927.                         return;
  928.                 if (player.ammo[type] == 0 && !player.keyFire && (uint8(type) > player.currWeapon || type == WEAPON::SEEKER))
  929.                         player.currWeapon = type;
  930.                 player.ammo[type] = player.ammo[type] + weapon::pickupMultiplier[type];
  931.                 if (player.ammo[type] > jjWeapons[type].maximum)
  932.                         player.ammo[type] = jjWeapons[type].maximum;
  933.                 if (client::isCoopOrSP()) {
  934.                         jjPARTICLE@ part = jjAddParticle(PARTICLE::STRING);
  935.                         if (part !is null) {
  936.                                 part.xPos = obj.xPos;
  937.                                 part.yPos = obj.yPos;
  938.                                 part.xSpeed = 0;
  939.                                 part.ySpeed = -5;
  940.                                 part.string.text = "||+ AMMO";
  941.                         }
  942.                 }
  943.                 obj.state = STATE::ACTION;
  944.         }
  945.         void barrel(jjOBJ@ obj, jjOBJ@ bull) {
  946.                 if (bull.creatorType == CREATOR::PLAYER)
  947.                         obj.special = bull.creatorID;
  948.                 if (obj.state == STATE::ACTION || obj.state == STATE::EXTRA)
  949.                         return;
  950.                 switch (bull.eventID) {
  951.                         case OBJECT::BLASTERBULLET:
  952.                                 jjSample(obj.xPos, obj.yPos, SOUND::AMMO_GUNJAZZ);
  953.                                 bull.state = STATE::EXPLODE;
  954.                                 break;
  955.                         case OBJECT::BOUNCERBULLET:
  956.                                 bull.direction = bull.xSpeed > 0 ? -1 : 1;
  957.                                 bull.ricochet();
  958.                                 bull.state = STATE::EXPLODE;
  959.                                 break;
  960.                         case OBJECT::ICEBULLET:
  961.                                 if (obj.var[5] == bull.var[5])
  962.                                         return;
  963.                                 obj.var[5] = bull.var[5];
  964.                                 break;
  965.                         case OBJECT::RFBULLET:
  966.                                 if (jjRandom() & 2 == 0)
  967.                                         jjSample(obj.xPos, obj.yPos, SOUND::COMMON_CUP);
  968.                                 bull.counter += 8;
  969.                                 bull.var[9] = bull.var[9] + 1;
  970.                                 if (!jjMaskedPixel(int(bull.xPos - bull.xSpeed), int(bull.yPos))) {
  971.                                         bull.xSpeed = -bull.xSpeed;
  972.                                 } else {
  973.                                         if (jjMaskedPixel(int(bull.xPos), int(bull.yPos - bull.ySpeed)))
  974.                                                 bull.xSpeed = -bull.xSpeed;
  975.                                         bull.ySpeed = -bull.ySpeed;
  976.                                 }
  977.                                 break;
  978.                         default:
  979.                                 bull.state = STATE::EXPLODE;
  980.                 }
  981.                 if (obj.energy > bull.animSpeed)
  982.                         obj.energy -= bull.animSpeed;
  983.                 else
  984.                         obj.state = STATE::EXTRA;
  985.         }
  986.         void barrelExplode(jjOBJ@ obj, jjOBJ@ bull) {
  987.                 obj.state = STATE::ACTION;
  988.                 bull.delete();
  989.         }
  990.         bool hurtPlayer(jjPLAYER@ player, jjPLAYER@ attacker, uint8 damage) {
  991.                 if (player.blink != 0 || player.health <= 0)
  992.                         return false;
  993.                 if (attacker !is null) {
  994.                         if (attacker.blink != 0)
  995.                                 return false;
  996.                         if (player is attacker) {
  997.                                 if (damage & weapon::allowSD == 0 || jjTriggers[trigger::disableSD])
  998.                                         return false;
  999.                         } else if (jjGameMode == GAME::CTF && player.teamRed == attacker.teamRed && !jjTriggers[trigger::friendlyFire]) {
  1000.                                 return false;
  1001.                         }
  1002.                 }
  1003.                 if (jjTriggers[trigger::damageAmplifier] && damage & weapon::maxDamage < weapon::maxDamage)
  1004.                         damage++;
  1005.                 if (player.hurt(damage & weapon::maxDamage, true, attacker)) {
  1006.                         player.blink = 60;
  1007.                         return true;
  1008.                 }
  1009.                 return false;
  1010.         }
  1011.         void machine(jjOBJ@ obj, jjOBJ@ bull) {
  1012.                 if (bull.yPos > obj.yPos - 12) {
  1013.                         if (bull.eventID == OBJECT::BOUNCERBULLET) {
  1014.                                 bull.direction = bull.xSpeed > 0 ? -1 : 1;
  1015.                                 bull.ricochet();
  1016.                         }
  1017.                 } else {
  1018.                         int index = (bull.xPos - obj.xPos) * obj.direction >= 0 ? 1 : 0;
  1019.                         if (obj.var[index + 2] != 0)
  1020.                                 return;
  1021.                         if ((obj.var[index] = obj.var[index] - bull.animSpeed) <= 0)
  1022.                                 obj.var[index + 2] = 1;
  1023.                 }
  1024.                 bull.state = STATE::EXPLODE;
  1025.         }
  1026.         void projectile(jjPLAYER@ player, jjOBJ@ bull) {
  1027.                 jjPLAYER@ creator;
  1028.                 if (bull.creatorType == CREATOR::PLAYER)
  1029.                         @creator = jjPlayers[bull.creatorID];
  1030.                 if (hurtPlayer(player, creator, bull.doesHurt))
  1031.                         bull.state = STATE::ACTION;
  1032.         }
  1033.         void turret(jjOBJ@ obj, jjOBJ@ bull) {
  1034.                 bull.state = STATE::EXPLODE;
  1035.                 if (obj.energy > bull.animSpeed)
  1036.                         obj.energy -= bull.animSpeed;
  1037.                 else
  1038.                         obj.state = STATE::EXPLODE;
  1039.         }
  1040. }
  1041. namespace draw {
  1042.         void ammoCounter(jjCANVAS@ canvas, int x, int y, int value, int max, bool active) {
  1043.                 int color = 0;
  1044.                 if (active) {
  1045.                         if (2 * value <= max) {
  1046.                                 if (4 * value <= max) {
  1047.                                         if (value <= 0)
  1048.                                                 color = 3;
  1049.                                         else
  1050.                                                 color = 2;
  1051.                                 } else {
  1052.                                         color = 1;
  1053.                                 }
  1054.                         }
  1055.                 }
  1056.                 STRING::Mode mode = active ? STRING::PALSHIFT : STRING::DARK;
  1057.                 string text = formatInt(value, "") + "/" + formatInt(max, "");
  1058.                 canvas.drawString(x, y, text, STRING::SMALL, mode, palshift::ammoCount[color]);
  1059.         }
  1060.         void healthBar(jjCANVAS@ canvas, int x, int y, int value, int max, bool red) {
  1061.                 const uint backgroundTile = tileset::healthBar + 12;
  1062.                 const int backgroundX = x + 32;
  1063.                 const uint insideTile = tileset::healthBar + 5;
  1064.                 const int insideX = x + 46;
  1065.                 const int insideY = y + 8;
  1066.                 const int length = 105 * value / max;
  1067.                 const bool low = value <= max / 2;
  1068.                 const TILE::Quadrant quadrantLeft = low ? TILE::BOTTOMLEFT : TILE::TOPLEFT;
  1069.                 const TILE::Quadrant quadrantRight = low ? TILE::BOTTOMRIGHT : TILE::TOPRIGHT;
  1070.                 if (value < max) {
  1071.                         for (int i = 0; i < 4; i++) {
  1072.                                 canvas.drawTile(backgroundX + i * 32, y, backgroundTile + i);
  1073.                         }
  1074.                 }
  1075.                 for (int i = 0; i < length; i++) {
  1076.                         uint random = jjRandom();
  1077.                         canvas.drawTile(insideX + i, insideY, insideTile + (random & 1), random & 2 != 0 ? quadrantLeft : quadrantRight);
  1078.                 }
  1079.                 if (value < max)
  1080.                         canvas.drawTile(insideX + length, insideY, insideTile + 11, jjRandom() & 1 != 0 ? quadrantLeft : quadrantRight);
  1081.                 if (length >= 9) {
  1082.                         canvas.drawTile(x + 48, y, insideTile + 4, quadrantLeft);
  1083.                         if (length >= 50) {
  1084.                                 canvas.drawTile(x + 80, y, insideTile + 4, quadrantRight);
  1085.                                 if (length >= 82)
  1086.                                         canvas.drawTile(x + 112, y, insideTile + 4, quadrantRight);
  1087.                         }
  1088.                 }
  1089.                 for (int i = 0; i < 5; i++) {
  1090.                         canvas.drawTile(x + i * 32, y, tileset::healthBar + i);
  1091.                 }
  1092.                 for (int i = 0; i < 2; i++) {
  1093.                         canvas.drawTile(x + i * 32, y + 32, tileset::healthBar + 10 + i);
  1094.                 }
  1095.                 if (!red) {
  1096.                         const uint heartTile = tileset::healthBar + (low ? 17 : 7);
  1097.                         for (int i = 0; i < 2; i++) {
  1098.                                 canvas.drawTile(x + i * 32, y + 16, heartTile + i);
  1099.                         }
  1100.                 }
  1101.         }
  1102.         void largeWeaponIcon(jjCANVAS@ canvas, int x, int y, uint8 type) {
  1103.                 uint modifier = tileset::weaponLarge + (type + (type & ~1)) * 5;
  1104.                 for (int i = 0; i < 2; i++) {
  1105.                         for (int j = 0; j < 5; j++) {
  1106.                                 canvas.drawTile(x + j * 32, y + i * 32, modifier + i * 10 + j);
  1107.                         }
  1108.                 }
  1109.         }
  1110.         void smallWeaponIcon(jjCANVAS@ canvas, int x, int y, uint8 type, bool active) {
  1111.                 uint modifier = (active ? tileset::weaponSmall : tileset::weaponSmallInactive) + type * 5;
  1112.                 if (type & 1 == 0) {
  1113.                         canvas.drawTile(x, y, modifier);
  1114.                         canvas.drawTile(x + 32, y, modifier + 1);
  1115.                         canvas.drawTile(x + 64, y, modifier + 2, TILE::TOPLEFT);
  1116.                         canvas.drawTile(x + 64, y + 16, modifier + 2, TILE::BOTTOMLEFT);
  1117.                 } else {
  1118.                         canvas.drawTile(x, y, modifier - 3, TILE::TOPRIGHT);
  1119.                         canvas.drawTile(x, y + 16, modifier - 3, TILE::BOTTOMRIGHT);
  1120.                         canvas.drawTile(x + 16, y, modifier - 2);
  1121.                         canvas.drawTile(x + 48, y, modifier - 1);
  1122.                 }
  1123.         }
  1124.         void weaponIconBarHorizontal(jjCANVAS@ canvas, int x, int y, const jjPLAYER@ player) {
  1125.                 const bool largeDisplay = client::localPlayer[player.localPlayerID].weaponChangeTimer > 0;
  1126.                 x -= weapon::count * 40 + (largeDisplay ? 40 : 0);
  1127.                 int x2 = x + (largeDisplay ? 80 : 0);
  1128.                 const uint8 currentWeaponID = player.currWeapon - weapon::first;
  1129.                 for (uint i = 0; i < weapon::count; i++) {
  1130.                         uint8 weapon = i + 1;
  1131.                         bool hasAmmoOrIsCurrent = player.ammo[weapon] > 0 || i == currentWeaponID;
  1132.                         if (i == currentWeaponID && largeDisplay) {
  1133.                                 largeWeaponIcon(canvas, x + i * 80, y - 32, i);
  1134.                                 ammoCounter(canvas, x + i * 80, y + 24, player.ammo[weapon], jjWeapons[weapon].maximum, true);
  1135.                                 weaponName(canvas, x + i * 80 + 160, y - 24, weapon);
  1136.                         } else {
  1137.                                 int xUsed = i < currentWeaponID ? x : x2;
  1138.                                 smallWeaponIcon(canvas, xUsed + i * 80, y - 16, i, hasAmmoOrIsCurrent);
  1139.                                 if (hasAmmoOrIsCurrent)
  1140.                                         ammoCounter(canvas, xUsed + i * 80, y + 16, player.ammo[weapon], jjWeapons[weapon].maximum, i == currentWeaponID);
  1141.                         }
  1142.                 }
  1143.         }
  1144.         void weaponIconBarVertical(jjCANVAS@ canvas, int x, int y, const jjPLAYER@ player) {
  1145.                 const bool largeDisplay = client::localPlayer[player.localPlayerID].weaponChangeTimer > 0;
  1146.                 y -= weapon::count * 24 + (largeDisplay ? 16 : 0);
  1147.                 const int x2 = x - 32;
  1148.                 const int y2 = y + (largeDisplay ? 32 : 0);
  1149.                 const uint8 currentWeaponID = player.currWeapon - weapon::first;
  1150.                 for (uint i = 0; i < weapon::count; i++) {
  1151.                         uint8 weapon = i + 1;
  1152.                         bool hasAmmoOrIsCurrent = player.ammo[weapon] > 0 || i == currentWeaponID;
  1153.                         if (i == currentWeaponID && largeDisplay) {
  1154.                                 largeWeaponIcon(canvas, x - 80, y + i * 48 + 8, i);
  1155.                                 ammoCounter(canvas, x - 80, y + i * 48 + 72, player.ammo[weapon], jjWeapons[weapon].maximum, true);
  1156.                                 weaponName(canvas, x + 80, y + i * 48 + 8, weapon);
  1157.                         } else {
  1158.                                 int yUsed = i < currentWeaponID ? y : y2;
  1159.                                 int xUsed = i != currentWeaponID ? x : x2;
  1160.                                 smallWeaponIcon(canvas, xUsed, yUsed + i * 48, i, hasAmmoOrIsCurrent);
  1161.                                 if (hasAmmoOrIsCurrent)
  1162.                                         ammoCounter(canvas, xUsed, yUsed + i * 48 + 32, player.ammo[weapon], jjWeapons[weapon].maximum, i == currentWeaponID);
  1163.                         }
  1164.                 }
  1165.         }
  1166.         void weaponName(jjCANVAS@ canvas, int x, int y, uint8 type) {
  1167.                 canvas.drawString(x - text::getSmallFontIntWidth(weapon::name[type]), y, weapon::name[type]);
  1168.         }
  1169. }
  1170. namespace explosion {
  1171.         void asmdRing(float x, float y, float xSpeed, float ySpeed, float semiMajor, float semiMinor) {
  1172.                 if (client::isIdleServer())
  1173.                         return;
  1174.                 const int shift = semiMajor > 2 ? 5 : 6;
  1175.                 const int count = 1 << (10 - shift);
  1176.                 const float multiplier = 6.2831853 / count;
  1177.                 const float hypot = sqrt(xSpeed * xSpeed + ySpeed * ySpeed);
  1178.                 const float axisSin = ySpeed / hypot;
  1179.                 const float axisCos = xSpeed / hypot;
  1180.                 const float majorSin = semiMajor * axisSin;
  1181.                 const float minorSin = semiMinor * axisSin;
  1182.                 const float majorCos = semiMajor * axisCos;
  1183.                 const float minorCos = semiMinor * axisCos;
  1184.                 for (int i = 0; i < count; i++) {
  1185.                         const int angle = i << shift;
  1186.                         const float angleSin = jjSin(angle);
  1187.                         const float angleCos = jjCos(angle);
  1188.                         const float xSpeedUlt = minorCos * angleCos - majorSin * angleSin;
  1189.                         const float ySpeedUlt = minorSin * angleCos + majorCos * angleSin;
  1190.                         particle(x, y, xSpeedUlt, ySpeedUlt, 0, 0, 35, ANIM::AMMO, 9, SPRITE::PALSHIFT, palshift::asmdParticle);
  1191.                 }
  1192.         }
  1193.         void barrelExplosion(float x, float y, jjPLAYER@ creator) {
  1194.                 harmfulExplosion(x, y, 128, 4, 80, creator);
  1195.                 if (client::isIdleServer())
  1196.                         return;
  1197.                 jjSample(x, y, SOUND::COMMON_GLASS2);
  1198.                 for (int i = 0; i < 20; i++) {
  1199.                         int ID = jjAddObject(OBJECT::SHARD, x, y);
  1200.                         if (ID != 0) {
  1201.                                 jjOBJ@ obj = jjObjects[ID];
  1202.                                 obj.behavior = behavior::shard;
  1203.                                 obj.special = palshift::barrel;
  1204.                                 uint random = jjRandom();
  1205.                                 int speed = 8 + (random >> 2 & 7);
  1206.                                 uint angle = random >> 5;
  1207.                                 obj.xSpeed = jjSin(angle) * speed;
  1208.                                 obj.ySpeed = jjCos(angle) * speed;
  1209.                                 obj.determineCurAnim(ANIM::PICKUPS, 6 + (random & 3));
  1210.                         }
  1211.                 }
  1212.                 simpleExplosion(x, y, ANIM::AMMO, 5, 128);
  1213.                 for (int i = 0; i < 3; i++) {
  1214.                         uint angle = jjRandom();
  1215.                         simpleExplosion(x + jjSin(angle) * 64, y + jjCos(angle) * 64, ANIM::AMMO, 3, 64);
  1216.                         angle >>= 10;
  1217.                         simpleExplosion(x + jjSin(angle) * 96, y + jjCos(angle) * 96, ANIM::AMMO, 3, 48);
  1218.                         angle >>= 10;
  1219.                         simpleExplosion(x + jjSin(angle) * 96, y + jjCos(angle) * 96, ANIM::AMMO, 3, 32);
  1220.                 }
  1221.                 uint16 creatorID = creator !is null ? creator.playerID : 0;
  1222.                 CREATOR::Type creatorType = creator !is null ? CREATOR::PLAYER : CREATOR::OBJECT;
  1223.                 for (int i = 0; i < 5; i++) {
  1224.                         int ID = jjAddObject(OBJECT::TOASTERBULLET, x, y, creatorID, creatorType);
  1225.                         if (ID != 0) {
  1226.                                 uint angle = (i - 2) << 6;
  1227.                                 jjOBJ@ obj = jjObjects[ID];
  1228.                                 obj.doesHurt = (obj.doesHurt & weapon::maxDamage) / 2 | weapon::allowSD;
  1229.                                 obj.state = STATE::FALL;
  1230.                                 obj.xAcc = obj.yAcc = 0;
  1231.                                 obj.xSpeed = jjSin(angle) * 2;
  1232.                                 obj.ySpeed = -jjCos(angle) * 2;
  1233.                         }
  1234.                 }
  1235.         }
  1236.         void harmfulExplosion(float x, float y, float radius, uint damage, int objectDamage, jjPLAYER@ creator = null) {
  1237.                 damage &= weapon::maxDamage;
  1238.                 for (int i = 0; i < jjLocalPlayerCount; i++) {
  1239.                         jjPLAYER@ player = jjLocalPlayers[i];
  1240.                         if (player.xPos < x - radius || player.xPos > x + radius || player.yPos < y - radius || player.yPos > y + radius)
  1241.                                 continue;
  1242.                         float dx = player.xPos - x;
  1243.                         float dy = player.yPos - y;
  1244.                         float distance = sqrt(dx * dx + dy * dy);
  1245.                         if (distance > radius)
  1246.                                 continue;
  1247.                         uint value = uint(damage * (radius - distance) / radius) + 1;
  1248.                         if (value > damage)
  1249.                                 value = damage;
  1250.                         collision::hurtPlayer(player, creator, value | weapon::allowSD);
  1251.                 }
  1252.                 for (int i = 0; i < jjObjectCount; i++) {
  1253.                         jjOBJ@ obj = jjObjects[i];
  1254.                         if (!obj.isActive || obj.xPos < x - radius || obj.xPos > x + radius || obj.yPos < y - radius || obj.yPos > y + radius)
  1255.                                 continue;
  1256.                         float dx = obj.xPos - x;
  1257.                         float dy = obj.yPos - y;
  1258.                         float distance = sqrt(dx * dx + dy * dy);
  1259.                         if (distance > radius)
  1260.                                 continue;
  1261.                         int value = int(objectDamage * (radius - distance) / radius) + 1;
  1262.                         switch (obj.eventID) {
  1263.                                 case OBJECT::TNT:
  1264.                                         if (value > objectDamage)
  1265.                                                 value = objectDamage;
  1266.                                         if (obj.energy > value)
  1267.                                                 obj.energy -= value;
  1268.                                         else
  1269.                                                 obj.state = STATE::EXTRA;
  1270.                                         if (creator !is null)
  1271.                                                 obj.special = creator.playerID;
  1272.                                         break;
  1273.                                 case OBJECT::DESTRUCTSCENERY:
  1274.                                         if (obj.state != STATE::DONE && value > 50)
  1275.                                                 obj.state = STATE::KILL;
  1276.                                         break;
  1277.                                 case OBJECT::FLOATLIZARD:
  1278.                                         if (obj.doesHurt == 1) {
  1279.                                                 if (obj.energy > value)
  1280.                                                         obj.energy -= value;
  1281.                                                 else
  1282.                                                         obj.state = STATE::EXPLODE;
  1283.                                         } else if (value > 50) {
  1284.                                                 obj.state = STATE::EXPLODE;
  1285.                                         }
  1286.                                         break;
  1287.                         }
  1288.                 }
  1289.         }
  1290.         void machineExplosion(float x, float y) {
  1291.                 harmfulExplosion(x, y, 160, 7, 200);
  1292.                 if (client::isIdleServer())
  1293.                         return;
  1294.                 jjSample(x, y, SOUND::COMMON_DAMPED1);
  1295.                 for (int i = 0; i < 40; i++) {
  1296.                         int ID = jjAddObject(OBJECT::SHARD, x, y);
  1297.                         if (ID != 0) {
  1298.                                 jjOBJ@ obj = jjObjects[ID];
  1299.                                 obj.behavior = behavior::shard;
  1300.                                 uint random = jjRandom();
  1301.                                 obj.special = palshift::machineShard;
  1302.                                 int speed = 7 + (random >> 2 & 7);
  1303.                                 uint angle = random >> 5;
  1304.                                 obj.xSpeed = jjSin(angle) * speed;
  1305.                                 obj.ySpeed = jjCos(angle) * speed;
  1306.                                 obj.determineCurAnim(ANIM::PICKUPS, 6 + (random & 3));
  1307.                         }
  1308.                 }
  1309.                 simpleExplosion(x, y, ANIM::AMMO, 5, 160);
  1310.                 for (int i = 0; i < 2; i++) {
  1311.                         uint angle = jjRandom();
  1312.                         simpleExplosion(x + jjSin(angle) * 64, y + jjCos(angle) * 64, ANIM::AMMO, 5, 96);
  1313.                         angle >>= 10;
  1314.                         simpleExplosion(x + jjSin(angle) * 96, y + jjCos(angle) * 96, ANIM::AMMO, 5, 96);
  1315.                         angle >>= 10;
  1316.                         simpleExplosion(x + jjSin(angle) * 128, y + jjCos(angle) * 128, ANIM::AMMO, 5, 96);
  1317.                 }
  1318.         }
  1319.         void machineStomp(float x, float y) {
  1320.                 harmfulExplosion(x, y, 32, 3, 100);
  1321.                 if (client::isIdleServer())
  1322.                         return;
  1323.                 jjSample(x, y, SOUND::COMMON_METALHIT);
  1324.                 uint random = jjRandom();
  1325.                 for (int i = 0; i < 3; i++) {
  1326.                         simpleExplosion(x + (i - 1) * 16, y + (random & 7), ANIM::AMMO, 72, 48);
  1327.                         random >>= 3;
  1328.                 }
  1329.         }
  1330.         void particle(float x, float y, float xSpeed, float ySpeed, float xAcc, float yAcc, int counter, ANIM::Set setID, uint8 animation, SPRITE::Mode mode = SPRITE::NORMAL, uint8 param = 0) {
  1331.                 if (client::isIdleServer())
  1332.                         return;
  1333.                 int ID = jjAddObject(OBJECT::EXPLOSION, x, y);
  1334.                 if (ID != 0) {
  1335.                         jjOBJ@ obj = jjObjects[ID];
  1336.                         obj.behavior = behavior::shortLivedParticle;
  1337.                         obj.xSpeed = xSpeed;
  1338.                         obj.ySpeed = ySpeed;
  1339.                         obj.xAcc = xAcc;
  1340.                         obj.yAcc = yAcc;
  1341.                         obj.counter = counter;
  1342.                         obj.determineCurAnim(setID, animation);
  1343.                         obj.special = mode;
  1344.                         obj.var[0] = param;
  1345.                 }
  1346.         }
  1347.         void rocketExplosion(float x, float y, jjPLAYER@ creator) {
  1348.                 harmfulExplosion(x, y, 160, 5, 120, creator);
  1349.                 if (client::isIdleServer())
  1350.                         return;
  1351.                 jjSample(x, y, SOUND::COMMON_DAMPED1);
  1352.                 for (int i = 0; i < 20; i++) {
  1353.                         int ID = jjAddObject(OBJECT::SHARD, x, y);
  1354.                         if (ID != 0) {
  1355.                                 jjOBJ@ obj = jjObjects[ID];
  1356.                                 obj.behavior = behavior::shard;
  1357.                                 uint random = jjRandom();
  1358.                                 obj.special = palshift::rocketShard[random >> 2 & 1];
  1359.                                 int speed = 7 + (random >> 3 & 3);
  1360.                                 uint angle = random >> 5;
  1361.                                 obj.xSpeed = jjSin(angle) * speed;
  1362.                                 obj.ySpeed = jjCos(angle) * speed;
  1363.                                 obj.determineCurAnim(ANIM::PICKUPS, 6 + (random & 3));
  1364.                         }
  1365.                 }
  1366.                 simpleExplosion(x, y, ANIM::AMMO, 5, 160);
  1367.                 for (int i = 0; i < 2; i++) {
  1368.                         uint angle = jjRandom();
  1369.                         simpleExplosion(x + jjSin(angle) * 64, y + jjCos(angle) * 64, ANIM::AMMO, 5, 96);
  1370.                         angle >>= 10;
  1371.                         simpleExplosion(x + jjSin(angle) * 96, y + jjCos(angle) * 96, ANIM::AMMO, 5, 64);
  1372.                         angle >>= 10;
  1373.                         simpleExplosion(x + jjSin(angle) * 128, y + jjCos(angle) * 128, ANIM::AMMO, 5, 48);
  1374.                 }
  1375.         }
  1376.         void simpleExplosion(float x, float y, ANIM::Set setID, uint8 animation, uint8 scale = 32) {
  1377.                 if (client::isIdleServer())
  1378.                         return;
  1379.                 int ID = jjAddObject(OBJECT::EXPLOSION, x, y);
  1380.                 if (ID != 0) {
  1381.                         jjOBJ@ obj = jjObjects[ID];
  1382.                         obj.determineCurAnim(setID, animation);
  1383.                         obj.age = scale;
  1384.                 }
  1385.         }
  1386.         void turretExplosion(float x, float y) {
  1387.                 if (client::isIdleServer())
  1388.                         return;
  1389.                 jjSample(x, y, SOUND::COMMON_GLASS2);
  1390.                 simpleExplosion(x, y, ANIM::AMMO, 5, 64);
  1391.                 for (int i = 0; i < 3; i++) {
  1392.                         uint angle = jjRandom();
  1393.                         simpleExplosion(x + jjSin(angle) * 32, y + jjCos(angle) * 32, ANIM::AMMO, 3);
  1394.                         angle >>= 10;
  1395.                         simpleExplosion(x + jjSin(angle) * 48, y + jjCos(angle) * 48, ANIM::AMMO, 3);
  1396.                         angle >>= 10;
  1397.                         simpleExplosion(x + jjSin(angle) * 48, y + jjCos(angle) * 48, ANIM::AMMO, 3);
  1398.                 }
  1399.         }
  1400. }
  1401. namespace initialize {
  1402.         void objectPresets() {
  1403.                 jjOBJ@ preset;
  1404.                 @preset = jjObjectPresets[OBJECT::BLASTERBULLET];
  1405.                 preset.animSpeed = 10;
  1406.                 preset.behavior = behavior::bullet;
  1407.                 preset.bulletHandling = HANDLING::IGNOREBULLET;
  1408.                 preset.counterEnd = 50;
  1409.                 preset.doesHurt = 2;
  1410.                 preset.freeze = 0;
  1411.                 preset.isFreezable = false;
  1412.                 preset.killAnim = preset.determineCurAnim(ANIM::AMMO, 82, false);
  1413.                 preset.lightType = LIGHT::POINT2;
  1414.                 preset.playerHandling = HANDLING::SPECIAL;
  1415.                 preset.scriptedCollisions = true;
  1416.                 preset.special = preset.determineCurAnim(ANIM::AMMO, 32, false);
  1417.                 preset.xAcc = preset.yAcc = preset.ySpeed = 0;
  1418.                 preset.xSpeed = 7;
  1419.                 preset.determineCurAnim(ANIM::AMMO, 30);
  1420.                 preset.determineCurFrame();
  1421.                 @preset = jjObjectPresets[OBJECT::BOUNCERBULLET];
  1422.                 preset.animSpeed = 6;
  1423.                 preset.behavior = behavior::bullet;
  1424.                 preset.bulletHandling = HANDLING::IGNOREBULLET;
  1425.                 preset.counterEnd = 100;
  1426.                 preset.doesHurt = 1;
  1427.                 preset.freeze = 0;
  1428.                 preset.isFreezable = false;
  1429.                 preset.killAnim = preset.determineCurAnim(ANIM::AMMO, 10, false);
  1430.                 preset.lightType = LIGHT::NONE;
  1431.                 preset.playerHandling = HANDLING::SPECIAL;
  1432.                 preset.scriptedCollisions = true;
  1433.                 preset.special = preset.determineCurAnim(ANIM::AMMO, 22, false);
  1434.                 preset.xAcc = preset.yAcc = preset.ySpeed = 0;
  1435.                 preset.xSpeed = 10;
  1436.                 preset.determineCurAnim(ANIM::AMMO, 20);
  1437.                 preset.determineCurFrame();
  1438.                 @preset = jjObjectPresets[OBJECT::ICEBULLET];
  1439.                 preset.animSpeed = 25;
  1440.                 preset.behavior = behavior::asmdBeam;
  1441.                 preset.bulletHandling = HANDLING::IGNOREBULLET;
  1442.                 preset.counterEnd = 40;
  1443.                 preset.doesHurt = 3;
  1444.                 preset.freeze = 0;
  1445.                 preset.isFreezable = false;
  1446.                 preset.killAnim = preset.determineCurAnim(ANIM::AMMO, 71, false);
  1447.                 preset.light = 4;
  1448.                 preset.lightType = LIGHT::RING2;
  1449.                 preset.playerHandling = HANDLING::SPECIAL;
  1450.                 preset.scriptedCollisions = true;
  1451.                 preset.special = preset.determineCurAnim(ANIM::AMMO, 65, false);
  1452.                 preset.xAcc = preset.yAcc = preset.ySpeed = 0;
  1453.                 preset.xSpeed = 10;
  1454.                 preset.determineCurAnim(ANIM::AMMO, 73);
  1455.                 preset.determineCurFrame();
  1456.                 @preset = jjObjectPresets[OBJECT::SEEKERBULLET];
  1457.                 preset.animSpeed = 1000;
  1458.                 preset.behavior = behavior::rocket;
  1459.                 preset.bulletHandling = HANDLING::IGNOREBULLET;
  1460.                 preset.doesHurt = 7;
  1461.                 preset.freeze = 0;
  1462.                 preset.isFreezable = false;
  1463.                 preset.lightType = LIGHT::NONE;
  1464.                 preset.playerHandling = HANDLING::SPECIAL;
  1465.                 preset.scriptedCollisions = true;
  1466.                 preset.xAcc = preset.yAcc = preset.ySpeed = 0;
  1467.                 preset.xSpeed = 10;
  1468.                 @preset = jjObjectPresets[OBJECT::RFBULLET];
  1469.                 preset.animSpeed = 10;
  1470.                 preset.behavior = behavior::flak;
  1471.                 preset.bulletHandling = HANDLING::IGNOREBULLET;
  1472.                 preset.counterEnd = 35;
  1473.                 preset.doesHurt = 6;
  1474.                 preset.freeze = 0;
  1475.                 preset.isFreezable = false;
  1476.                 preset.lightType = LIGHT::NONE;
  1477.                 preset.playerHandling = HANDLING::SPECIAL;
  1478.                 preset.scriptedCollisions = true;
  1479.                 preset.special = 3;
  1480.                 preset.xAcc = -0.1f;
  1481.                 preset.yAcc = 0.1f;
  1482.                 preset.xSpeed = 15;
  1483.                 preset.ySpeed = 0;
  1484.                 @preset = jjObjectPresets[OBJECT::TOASTERBULLET];
  1485.                 preset.animSpeed = 5;
  1486.                 preset.behavior = behavior::flame;
  1487.                 preset.bulletHandling = HANDLING::IGNOREBULLET;
  1488.                 preset.counterEnd = 40;
  1489.                 preset.doesHurt = 2;
  1490.                 preset.freeze = 0;
  1491.                 preset.isFreezable = false;
  1492.                 preset.lightType = LIGHT::NONE;
  1493.                 preset.playerHandling = HANDLING::SPECIAL;
  1494.                 preset.scriptedCollisions = true;
  1495.                 preset.xAcc = -0.2f;
  1496.                 preset.xSpeed = 3;
  1497.                 preset.yAcc = preset.ySpeed = 0;
  1498.                 preset.determineCurAnim(ANIM::AMMO, 13);
  1499.                 @preset = jjObjectPresets[OBJECT::TNT];
  1500.                 preset.behavior = behavior::barrel;
  1501.                 preset.bulletHandling = HANDLING::DETECTBULLET;
  1502.                 preset.counterEnd = 15;
  1503.                 preset.energy = 100;
  1504.                 preset.freeze = 0;
  1505.                 preset.isFreezable = false;
  1506.                 preset.lightType = LIGHT::NONE;
  1507.                 preset.playerHandling = HANDLING::SPECIAL;
  1508.                 preset.scriptedCollisions = true;
  1509.                 preset.special = -1;
  1510.                 preset.determineCurAnim(ANIM::PICKUPS, 3);
  1511.                 preset.determineCurFrame();
  1512.                 @preset = jjObjectPresets[OBJECT::BOUNCERAMMO3];
  1513.                 preset.behavior = behavior::pickup;
  1514.                 preset.scriptedCollisions = true;
  1515.                 preset.determineCurAnim(ANIM::HATTER, 1);
  1516.                 preset.determineCurFrame();
  1517.                 @preset = jjObjectPresets[OBJECT::ICEAMMO3];
  1518.                 preset.behavior = behavior::pickup;
  1519.                 preset.scriptedCollisions = true;
  1520.                 preset.determineCurAnim(ANIM::AMMO, 69);
  1521.                 preset.determineCurFrame();
  1522.                 @preset = jjObjectPresets[OBJECT::SEEKERAMMO3];
  1523.                 preset.behavior = behavior::pickup;
  1524.                 preset.scriptedCollisions = true;
  1525.                 preset.determineCurAnim(ANIM::SONCSHIP, 0);
  1526.                 preset.determineCurFrame();
  1527.                 @preset = jjObjectPresets[OBJECT::RFAMMO3];
  1528.                 preset.behavior = behavior::pickup;
  1529.                 preset.scriptedCollisions = true;
  1530.                 preset.determineCurAnim(ANIM::LIZARD, 1);
  1531.                 preset.determineCurFrame();
  1532.                 @preset = jjObjectPresets[OBJECT::TOASTERAMMO3];
  1533.                 preset.behavior = behavior::pickup;
  1534.                 preset.scriptedCollisions = true;
  1535.                 preset.determineCurAnim(ANIM::BILSBOSS, 3);
  1536.                 preset.determineCurFrame();
  1537.                 @preset = jjObjectPresets[OBJECT::CARROT];
  1538.                 preset.behavior = behavior::pickup;
  1539.                 preset.points = 1;
  1540.                 @preset = jjObjectPresets[OBJECT::EXPLOSION];
  1541.                 preset.behavior = behavior::explosion;
  1542.                 @preset = jjObjectPresets[OBJECT::COLLAPSESCENERY];
  1543.                 preset.behavior = behavior::destructScenery;
  1544.                 @preset = jjObjectPresets[OBJECT::DESTRUCTSCENERY];
  1545.                 preset.behavior = behavior::destructScenery;
  1546.                 preset.points = 0;
  1547.                 @preset = jjObjectPresets[OBJECT::DESTRUCTSCENERYBOMB];
  1548.                 preset.behavior = behavior::destructScenery;
  1549.                 preset.points = 0;
  1550.                 @preset = jjObjectPresets[OBJECT::STOMPSCENERY];
  1551.                 preset.behavior = behavior::destructScenery;
  1552.                 preset.points = 0;
  1553.                 @preset = jjObjectPresets[OBJECT::REDSPRING];
  1554.                 preset.behavior = behavior::spring;
  1555.                 @preset = jjObjectPresets[OBJECT::GREENSPRING];
  1556.                 preset.behavior = behavior::spring;
  1557.                 @preset = jjObjectPresets[OBJECT::BLUESPRING];
  1558.                 preset.behavior = behavior::spring;
  1559.                 @preset = jjObjectPresets[OBJECT::FLOATLIZARD];
  1560.                 preset.behavior = behavior::enemy;
  1561.                 preset.isFreezable = false;
  1562.                 preset.playerHandling = HANDLING::PARTICLE;
  1563.                 @preset = jjObjectPresets[OBJECT::CHECKPOINT];
  1564.                 preset.behavior = behavior::savePoint;
  1565.                 for (int i = 1; i < 256; i++) {
  1566.                         @preset = jjObjectPresets[i];
  1567.                         preset.deactivates = false;
  1568.                 }
  1569.         }
  1570.         void palette() {
  1571.                 jjPalette.fill(255, 255, 0, 104, 1);
  1572.                 jjPalette.fill(192, 192, 0, 117, 1);
  1573.                 jjPalette.gradient(200, 200, 0, 0, 0, 0, 123, 5);
  1574.                 jjPalette.gradient(255, 255, 0, 192, 0, 0, 144, 5);
  1575.                 jjPalette.gradient(192, 0, 0, 0, 0, 0, 148, 4);
  1576.                 jjPalette.gradient(128, 192, 192, 32, 48, 48);
  1577.                 jjPalette.apply();
  1578.         }
  1579.         void specialTiles() {
  1580.                 for (int i = 0; i < jjLayerHeight[4]; i++) {
  1581.                         for (int j = 0; j < jjLayerWidth[4]; j++) {
  1582.                                 switch (jjTileGet(4, j, i)) {
  1583.                                         case tileset::ventShaft:
  1584.                                                 level::specialTile.insertLast(TventShaft(j, i));
  1585.                                                 break;
  1586.                                 }
  1587.                         }
  1588.                 }
  1589.         }
  1590.         void weaponProfiles() {
  1591.                 jjWEAPON@ weapon;
  1592.                 @weapon = jjWeapons[WEAPON::BLASTER];
  1593.                 weapon.infinite = false;
  1594.                 weapon.maximum = 24;
  1595.                 weapon.multiplier = 1;
  1596.                 weapon.replenishes = true;
  1597.                 weapon.style = WEAPON::NORMAL;
  1598.                 @weapon = jjWeapons[WEAPON::BOUNCER];
  1599.                 weapon.infinite = false;
  1600.                 weapon.maximum = 120;
  1601.                 weapon.multiplier = 1;
  1602.                 weapon.replenishes = false;
  1603.                 weapon.style = WEAPON::NORMAL;
  1604.                 @weapon = jjWeapons[WEAPON::ICE];
  1605.                 weapon.infinite = false;
  1606.                 weapon.maximum = 40;
  1607.                 weapon.multiplier = 1;
  1608.                 weapon.replenishes = false;
  1609.                 weapon.style = WEAPON::NORMAL;
  1610.                 @weapon = jjWeapons[WEAPON::SEEKER];
  1611.                 weapon.infinite = false;
  1612.                 weapon.maximum = 4;
  1613.                 weapon.multiplier = 1;
  1614.                 weapon.replenishes = false;
  1615.                 weapon.style = WEAPON::NORMAL;
  1616.                 @weapon = jjWeapons[WEAPON::RF];
  1617.                 weapon.infinite = false;
  1618.                 weapon.maximum = client::isCoopOrSP() ? 0 : 16;
  1619.                 weapon.multiplier = 1;
  1620.                 weapon.replenishes = false;
  1621.                 weapon.style = WEAPON::NORMAL;
  1622.                 @weapon = jjWeapons[WEAPON::TOASTER];
  1623.                 weapon.infinite = false;
  1624.                 weapon.maximum = client::isCoopOrSP() ? 0 : 300;
  1625.                 weapon.multiplier = 1;
  1626.                 weapon.replenishes = false;
  1627.                 weapon.style = WEAPON::NORMAL;
  1628.                 @weapon = jjWeapons[WEAPON::TNT];
  1629.                 weapon.infinite = false;
  1630.                 weapon.maximum = 0;
  1631.                 @weapon = jjWeapons[WEAPON::GUN8];
  1632.                 weapon.infinite = false;
  1633.                 weapon.maximum = 0;
  1634.                 @weapon = jjWeapons[WEAPON::GUN9];
  1635.                 weapon.infinite = false;
  1636.                 weapon.maximum = 0;
  1637.         }
  1638. }
  1639. namespace level {
  1640.         array<Itile@> specialTile;
  1641.         bool isLineMaskFree(int xPos1, int yPos1, int xPos2, int yPos2) {
  1642.                 int xLength = xPos2 - xPos1;
  1643.                 int yLength = yPos2 - yPos1;
  1644.                 if (xLength == 0 && yLength == 0)
  1645.                         return !jjMaskedPixel(xPos1, yPos1);
  1646.                 int x, y;
  1647.                 if (abs(xLength) >= abs(yLength)) {
  1648.                         if (xPos1 < xPos2) {
  1649.                                 x = xPos1;
  1650.                                 y = yPos1;
  1651.                         } else {
  1652.                                 x = xPos2;
  1653.                                 y = yPos2;
  1654.                                 xLength = -xLength;
  1655.                                 yLength = -yLength;
  1656.                         }
  1657.                         for (int i = 0; i <= xLength; i++) {
  1658.                                 if (jjMaskedPixel(x + i, y + i * yLength / xLength))
  1659.                                         return false;
  1660.                         }
  1661.                 } else {
  1662.                         if (yPos1 < yPos2) {
  1663.                                 x = xPos1;
  1664.                                 y = yPos1;
  1665.                         } else {
  1666.                                 x = xPos2;
  1667.                                 y = yPos2;
  1668.                                 xLength = -xLength;
  1669.                                 yLength = -yLength;
  1670.                         }
  1671.                         for (int i = 0; i <= yLength; i++) {
  1672.                                 if (jjMaskedPixel(x + i * xLength / yLength, y + i))
  1673.                                         return false;
  1674.                         }
  1675.                 }
  1676.                 return true;
  1677.         }
  1678. }
  1679. namespace sprite {
  1680.         array<array<Tsprite>> spriteQueue(8);
  1681.         void add(float x, float y, uint frame, int direction = 0, SPRITE::Mode mode = SPRITE::NORMAL, uint8 param = 0, uint8 layer = 4) {
  1682.                 if (client::isIdleServer())
  1683.                         return;
  1684.                 Tsprite sprite;
  1685.                 sprite.x = int(floor(x));
  1686.                 sprite.y = int(floor(y));
  1687.                 sprite.frame = frame;
  1688.                 sprite.direction = direction;
  1689.                 sprite.mode = mode;
  1690.                 sprite.param = param;
  1691.                 spriteQueue[layer - 1].insertLast(sprite);
  1692.         }
  1693.         void clearQueues() {
  1694.                 for (uint i = 0; i < spriteQueue.length(); i++) {
  1695.                         spriteQueue[i].resize(0);
  1696.                 }
  1697.         }
  1698.         void drawQueue(jjCANVAS@ canvas, uint8 layer) {
  1699.                 for (uint i = 0; i < spriteQueue[layer].length(); i++) {
  1700.                         spriteQueue[layer][i].draw(canvas);
  1701.                 }
  1702.         }
  1703. }
  1704. namespace text {
  1705.         const array<int> smallFontCharacterWidth = {8, 6, 7, 15, 10, 12, 0, 4, 9, 9, 10, 13, 6, 10, 5, 11, 10, 8 /*actually 6*/, 11, 10, 11, 10, 9, 8, 9, 8, 6, 7, 9, 11, 9, 10, 14, 11, 11, 10, 12, 12, 9, 11, 9, 10, 11, 12, 10, 12, 12, 11, 10, 11, 12, 9, 11, 11, 9, 12, 10, 9, 11, 8, 11, 8, 13, 10, 6, 10, 9, 9, 9, 11, 9, 10, 10, 6, 9, 10, 6, 11, 10, 9, 10, 10, 10, 10, 9, 10, 9, 12, 9, 8, 9, 0, 0, 0, 0, 0};
  1706.         int getScoreHUDHeight(GAME::Mode mode) {
  1707.                 switch (jjGameMode) {
  1708.                         case GAME::BATTLE:
  1709.                         case GAME::TREASURE:
  1710.                                 return 36;
  1711.                         case GAME::CTF:
  1712.                                 switch (jjGameCustom) {
  1713.                                         case GAME::DOM:
  1714.                                         case GAME::JB:
  1715.                                         case GAME::TLRS:
  1716.                                                 return 80;
  1717.                                         default:
  1718.                                                 return 62;
  1719.                                 }
  1720.                         case GAME::RACE:
  1721.                                 return 62;
  1722.                         case GAME::COOP:
  1723.                         case GAME::SP:
  1724.                                 return 16;
  1725.                 }
  1726.                 return 0;
  1727.         }
  1728.         int getSmallFontIntWidth(string text) {
  1729.                 int width = 0;
  1730.                 for (uint i = 0; i < text.length(); i++) {
  1731.                         if(text[i] - 32 < smallFontCharacterWidth.length())
  1732.                                 width += smallFontCharacterWidth[text[i] - 32] + 1;
  1733.                         else
  1734.                                 width++;
  1735.                 }
  1736.                 return width;
  1737.         }
  1738. }
  1739.