Downloads containing xlmesrs.j2as

Downloads
Name Author Game Mode Rating
TSF with JJ2+ Only: ELEKTREK SPACE ROTATED... SmokeNC Battle N/A Download file

File preview

const bool MLLESetupSuccessful = MLLE::Setup(); ///@MLLE-Generated
#include "MLLE-Include-1.5.asc" ///@MLLE-Generated
#pragma require "xlmesrs.j2l" ///@MLLE-Generated


bool coinMsg = false;
void onLevelLoad() {

  jjPalette.fill(4, 0, 8, 176, 1, 1);
  loadAnims();
  loadAnims1();

  jjAnimations[jjAnimSets[ANIM::SONICPLAT]] = jjAnimations[jjAnimSets[ANIM::AMMO] + 8];
  jjObjectPresets[OBJECT::TNTAMMO3].scriptedCollisions = true;
  jjObjectPresets[OBJECT::TNTAMMO3].behavior = StillPickup();
  jjObjectPresets[OBJECT::CRAB].causesRicochet = true;
  // jjObjectPresets[OBJECT::PLASMASHIELDBULLET].causesRicochet = true;
  jjObjectPresets[OBJECT::PLASMASHIELDBULLET].playerHandling = HANDLING::SPECIAL;
  jjObjectPresets[OBJECT::PLASMASHIELDBULLET].bulletHandling = HANDLING::DESTROYBULLET;
  jjObjectPresets[OBJECT::PLASMASHIELDBULLET].scriptedCollisions = true;
  //  jjObjectPresets[OBJECT::PLASMASHIELDBULLETPU].causesRicochet = true;
  jjObjectPresets[OBJECT::ICEBULLET].behavior = jjObjectPresets[OBJECT::ICEBULLETPU].behavior = ElektrekShield();
  jjObjectPresets[OBJECT::ICEBULLET].freeze = jjObjectPresets[OBJECT::ICEBULLETPU].freeze = 0;
  jjObjectPresets[OBJECT::PLASMASHIELDBULLET].behavior = ElektrekShield1();

  //jjObjectPresets[OBJECT::ELECTROBULLETPU].xSpeed=0;
  jjObjectPresets[OBJECT::TNT].behavior = Zeus_Artillery();

  jjObjectPresets[OBJECT::PLASMASHIELDBULLET].counterEnd = 20;
  jjWeapons[WEAPON::ICE].style = WEAPON::CAPPED;
  //jjWeapons[WEAPON::ICE].spread = SPREAD::RFPU;
  //jjWeapons[WEAPON::GUN9].spread = SPREAD::RFPU;
  jjWeapons[WEAPON::TNT].maximum = 18;
  jjAnimations[jjAnimSets[ANIM::AMMO] + 29] = jjAnimations[jjAnimSets[ANIM::DEMON] + 0];

  jjANIMATION @ anim = jjAnimations[jjAnimSets[ANIM::AMMO] + 14];
  for (uint j = 0; j < anim.frameCount; j++) {
    jjANIMFRAME @ frame = jjAnimFrames[anim + j];
    jjPIXELMAP sprite(frame);
    for (uint x = 0; x < sprite.width; ++x) {
      for (uint y = 0; y < sprite.height; ++y) {
        if (sprite[x, y] >= 40 && sprite[x, y] <= 47) sprite[x, y] += 48;
      }
    }
    sprite.save(frame);
  }

  //jjWeapons[WEAPON::ICE].multiplier = 32;

  //jjObjectPresets[OBJECT::PLASMASHIELDBULLET].playerHandling = HANDLING::PLAYERBULLET;

  jjUseLayer8Speeds = true;
  jjTexturedBGStyle = TEXTURE::TUNNEL;
  jjTexturedBGTexture = TEXTURE::NORMAL;

  for (int i = 1; i < 255; i++) {
    if (jjObjectPresets[i].behavior == BEHAVIOR::PICKUP) {
      jjObjectPresets[i].behavior = CannotBeShotDown;
    }
  }
  jjObjectPresets[OBJECT::GOLDCOIN].behavior = Clone(1, 100, 1);
  jjObjectPresets[OBJECT::SILVERCOIN].behavior = clonePickup();
  jjObjectPresets[OBJECT::GOLDCOIN].xSpeed = 0;
  jjObjectPresets[OBJECT::GOLDCOIN].ySpeed = 0;
  jjObjectPresets[OBJECT::GOLDCOIN].scriptedCollisions = true;
  jjObjectPresets[OBJECT::SILVERCOIN].scriptedCollisions = true;

  jjWeapons[WEAPON::GUN8].spread = SPREAD::NORMAL;
  jjWeapons[WEAPON::GUN9].allowed = true;
  jjWeapons[WEAPON::GUN9].allowedPowerup = true;

  jjObjectPresets[OBJECT::CHIPS].scriptedCollisions = true;
  jjObjectPresets[OBJECT::CHIPS].behavior = SpreadShot();
  ReplacePlatform();

}
void onMain() {
  //jjTexturedBGFadePositionX = jjSin(jjGameTicks << 1) / 2 + .5;
  //jjTexturedBGFadePositionY = jjCos(jjGameTicks << 1) / 2 + .5;
  jjLayerYOffset[8] = jjSin(jjGameTicks) * 64;

  ReplacePlatform();

  if (jjGameTicks % 10 == 1) {
    jjSetFadeColors(128 + jjSin(jjGameTicks / 8) * 126, 128 + jjSin(jjGameTicks / 8 + 341) * 126, 128 + jjSin(jjGameTicks / 8 + 683) * 126);

  }

  for (int iP = 0; iP < 32; iP++) {
    if (jjPlayers[iP].isActive && jjPlayers[iP].score > 0) {
      jjPLAYER @p = jjPlayers[iP];

      if (p.score > 0 && jjGameTicks % 70 == 0) {
        p.score--;
        if (p.score == 0) {
          resetSpread();
        }
      } else if (p.score == spreadShotMaxTime) {
        for (uint i = 1; i <= 9; i++) {
          jjWeapons[i].spread = SPREAD::RFPU;
        }
      }
      if (p.score > 0) {
        jjTEXTAPPEARANCE normal(STRING::NORMAL);

        int x = int(p.cameraX);
        int y = int(p.cameraY);

        jjDrawSprite(x + jjResolutionWidth - 72, y + jjResolutionHeight - 270 - 32, ANIM::PICKUPS, 87, jjGameTicks >> 2, 0, SPRITE::NORMAL, 0, 1);
        jjDrawString(x + jjResolutionWidth - 55, y + jjResolutionHeight - 274 - 32, "" + p.score, STRING::MEDIUM, normal, 0, SPRITE::PALSHIFT, 0, 1);
      }
      if (p.health == 0) {
        p.score = 0;
        resetSpread();
      }
    }

  }
}

void onObjectHit(jjOBJ @ obj, jjOBJ @ bullet, jjPLAYER @ play, int force) {
  if (obj.eventID == OBJECT::TNTAMMO3) {

    play.ammo[WEAPON::TNT] = 20;
    play.currWeapon = WEAPON::TNT;

  }
  if (obj.eventID == OBJECT::PLASMASHIELDBULLET) {

    if (obj.creatorID != play.playerID) {
      if ((force == -1) || (force == 0))
        play.hurt(1, false, jjPlayers[obj.creatorID]);
      //else 
      //play.hurt(0, false, jjPlayers[obj.creatorID]);
    }
  }

  if (obj.eventID == OBJECT::SILVERCOIN) {
    //jjPrint("test");
    if (cloneM.active == false) {
      cloneM.active = true;
      cloneM.pID = p.playerID;
      cloneM.time = 0;
      //obj.scriptedCollisions = false;
      obj.behavior = BEHAVIOR::EXPLOSION2;
      //	obj.frameID = 0;
      sendClone(cloneM, 0, PtoS);
      //obj.delete();
    } else obj.behavior = BEHAVIOR::EXPLOSION2;
  }
}
uint8 animShield = 0;

void loadAnims() {
  jjANIMSET @ shieldAnimSet = jjAnimSets[ANIM::BAT];
  if (shieldAnimSet.firstAnim == 0) {
    const int firstShieldTileID = jjTileCount;
    const int shieldFrameCount = 2;
    jjTilesFromTileset("daysis691.j2t", 825, shieldFrameCount);
    shieldAnimSet.allocate(array < uint > = {
      shieldFrameCount
    });
    const int firstShieldFrameID = jjAnimations[shieldAnimSet.firstAnim].firstFrame;
    for (int shieldFrameID = 0; shieldFrameID < shieldFrameCount; ++shieldFrameID) {
      jjPIXELMAP shieldImage(firstShieldTileID + shieldFrameID);
      jjANIMFRAME @ shieldFrame = jjAnimFrames[firstShieldFrameID + shieldFrameID];
      shieldImage.save(shieldFrame);
      shieldFrame.hotSpotX = -16;
      shieldFrame.hotSpotY = -24;
    }
  }

}
void loadAnims1() {
  jjANIMSET @ shieldAnimSet = jjAnimSets[ANIM::DEMON];
  if (shieldAnimSet.firstAnim == 0) {
    const int firstShieldTileID = jjTileCount;
    const int shieldFrameCount = 1;
    jjTilesFromTileset("daysis691.j2t", 835, shieldFrameCount);
    shieldAnimSet.allocate(array < uint > = {
      shieldFrameCount
    });
    const int firstShieldFrameID = jjAnimations[shieldAnimSet.firstAnim].firstFrame;
    for (int shieldFrameID = 0; shieldFrameID < shieldFrameCount; ++shieldFrameID) {
      jjPIXELMAP shieldImage(firstShieldTileID + shieldFrameID);
      jjANIMFRAME @ shieldFrame = jjAnimFrames[firstShieldFrameID + shieldFrameID];
      shieldImage.save(shieldFrame);
      shieldFrame.hotSpotX = -16;
      shieldFrame.hotSpotY = -24;
    }
  }

}

int ii;
int kk;
class ElektrekShield: jjBEHAVIORINTERFACE {
  void onBehave(jjOBJ @ obj) {
    if (obj.state == STATE::START) {
      obj.state = STATE::EXPLODE;
    } else if (obj.state == STATE::EXPLODE) {
      for (int ii = 0; ii < 8; ii++) {
        int q = jjAddObject((obj.eventID == OBJECT::ICEBULLET) ? OBJECT::PLASMASHIELDBULLET : OBJECT::PLASMASHIELDBULLET, 1000, 1000, obj.creatorID, CREATOR::PLAYER);
        jjOBJ @ o = jjObjects[q];
        o.counterEnd = 20;
        o.creatorID = obj.creatorID;
        o.light = ii;
        o.lightType = LIGHT::NORMAL;

      }
      if (cloneM.pID == obj.creatorID && cloneM.active == true) {
        for (int ii = 0; ii < 8; ii++) {
          int q = jjAddObject((obj.eventID == OBJECT::ICEBULLET) ? OBJECT::PLASMASHIELDBULLET : OBJECT::PLASMASHIELDBULLET, 1000, 1000, obj.creatorID, CREATOR::PLAYER);
          jjOBJ @ o = jjObjects[q];
          o.counterEnd = 20;
          o.creatorID = obj.creatorID;
          o.light = ii;
          o.lightType = LIGHT::NORMAL;
          o.var[0] = eClone;

        }
      }
      obj.delete();
    }
  }
}


class ElektrekShield1: jjBEHAVIORINTERFACE {
  void onBehave(jjOBJ @ o) {
    int xPos, yPos;

    if (o.var[0] == eClone && cloneM.pID == o.creatorID && cloneM.active == true) {
      xPos = cloneM.xPos;
      yPos = cloneM.yPos;
    } else {
      xPos = jjPlayers[o.creatorID].xPos;
      yPos = jjPlayers[o.creatorID].yPos;
    }

    int r = 0;
    if (jjPlayers[o.creatorID].score > 0 /*spreadPID == o.creatorID*/ ) {
      r = 140;
    } else {
      r = 70;
    }
    uint z = (jjGameTicks / 7) % 2;
    o.determineCurAnim(ANIM::BAT, 14, true);
    //obj.frameID = 2;	
    //obj.determineCurFrame();
    //obj.draw();
    jjDrawRotatedSprite(o.xPos, o.yPos, ANIM::BAT, 0, z, 256 + (512 / 3.14) * atan2(-yPos + o.yPos, xPos - o.xPos));
    o.behavior == BEHAVIOR::BULLET;
    o.counterEnd = 20;
    switch (o.light) {
    case 0: {
      o.xPos = xPos + r * jjSin(-jjGameTicks * 20);
      o.yPos = yPos + r * jjCos(-jjGameTicks * 20);
      break;
    }
    case 1: {
      o.xPos = xPos + r * jjSin((-jjGameTicks - 32) * 20);
      o.yPos = yPos + r * jjCos((-jjGameTicks - 32) * 20);
      break;
    }
    case 2: {
      o.xPos = xPos + r * jjSin((-jjGameTicks - 32 - 32) * 20);
      o.yPos = yPos + r * jjCos((-jjGameTicks - 32 - 32) * 20);
      break;
    }
    case 3: {
      o.xPos = xPos + r * jjSin((-jjGameTicks - 32 - 32 - 32) * 20);
      o.yPos = yPos + r * jjCos((-jjGameTicks - 32 - 32 - 32) * 20);
      break;
    }
    case 4: {
      o.xPos = xPos + r * jjSin((-jjGameTicks - 32 - 32 - 32 - 32) * 20);
      o.yPos = yPos + r * jjCos((-jjGameTicks - 32 - 32 - 32 - 32) * 20);
      break;
    }
    case 5: {
      o.xPos = xPos + r * jjSin((-jjGameTicks - 32 - 32 - 32 - 32 - 32) * 20);
      o.yPos = yPos + r * jjCos((-jjGameTicks - 32 - 32 - 32 - 32 - 32) * 20);
      break;
    }
    case 6: {
      o.xPos = xPos + r * jjSin((-jjGameTicks - 32 - 32 - 32 - 32 - 32 - 32) * 20);
      o.yPos = yPos + r * jjCos((-jjGameTicks - 32 - 32 - 32 - 32 - 32 - 32) * 20);
      break;
    }
    case 7: {
      o.xPos = xPos + r * jjSin((-jjGameTicks - 32 - 32 - 32 - 32 - 32 - 32 - 32) * 20);
      o.yPos = yPos + r * jjCos((-jjGameTicks - 32 - 32 - 32 - 32 - 32 - 32 - 32) * 20);
      break;
    }
    }

    o.counter++;
    if (o.counter > 40)
      o.delete();
  }

}

class StillPickup: jjBEHAVIORINTERFACE {
  void onBehave(jjOBJ @ obj) {
    if (obj.xPos > 100 * 32)
      obj.direction = 1;
    if (obj.xPos < 100 * 32)
      obj.direction = -1;

    if (obj.state == STATE::FLOATFALL) obj.state = STATE::FLOAT;
    obj.behave(BEHAVIOR::PICKUP);
  }
}

void onPlayer(jjPLAYER @ p) {

  if (p.fly == FLIGHT::FLYCARROT && p.timerState == TIMER::STOPPED) p.timerStart(10 * 70);
  if (p.fly == FLIGHT::NONE) p.timerStop();
  if (p.timerState == TIMER::STARTED && p.timerTime <= 3 * 70 && p.timerTime > 0 && p.timerTime % 70 == 0) jjSamplePriority(SOUND::COMMON_NOCOIN);

  for (int i = 1; i < jjObjectCount; ++i) {
    switch (jjObjects[i].eventID) {

    case OBJECT::FLYCARROT:
      if (jjObjects[i].state == STATE::FLOATFALL) jjObjects[i].state = STATE::FLOAT;
      break;
    }
  }

  if (cloneM.active == true and p.playerID == cloneM.pID) {
    jjTEXTAPPEARANCE normal(STRING::NORMAL);
    int x = int(p.cameraX);
    int y = int(p.cameraY);
    jjDrawString(x + jjResolutionWidth - 55, y + jjResolutionHeight - 274, "" + cloneM.time / 70, STRING::MEDIUM, normal, 0, SPRITE::PALSHIFT, 0, 1);
    jjDrawSprite(x + jjResolutionWidth - 72, y + jjResolutionHeight - 270, ANIM::PICKUPS, 84, jjGameTicks >> 2, 0, SPRITE::SINGLECOLOR, 16 + (8 * (jjGameTicks / 10)) % (256 - 16));

  }

  angle += 12;

}

void onPlayerTimerEnd(jjPLAYER @ p) {
  p.fly = FLIGHT::NONE;
}

void onFunction9(jjPLAYER @ p) {
  if (p.testForCoins(1)) {
    p.shieldType = SHIELD::PLASMA;
    p.shieldTime = 20 * 70;
    jjSamplePriority(SOUND::COMMON_GLASS2);
    jjSamplePriority(SOUND::COMMON_SHIELD1);
  }
}

bool onDrawHealth(jjPLAYER @ p, jjCANVAS @ canvas) {
  if (p.shieldType != 0 && p.shieldTime > 0) {
    canvas.drawString(
      jjSubscreenWidth - 100,
      jjSubscreenHeight - 464,
      "||||||||Shield!",
      STRING::MEDIUM,
      STRING::NORMAL
    );

    return true;
  }
  return false;
}

bool onDrawPlayerTimer(jjPLAYER @ p, jjCANVAS @ canvas) {
  if (p.fly == FLIGHT::FLYCARROT) {
    canvas.drawString(
      jjSubscreenWidth - 55,
      jjSubscreenHeight - 284,
      "" + (p.timerTime + 70) / 70,
      STRING::LARGE,
      STRING::PALSHIFT,
      p.timerTime > 3 * 70 ?
      0 :
      jjGameTicks % 28 > 14 ?
      -40 :
      -24
    );

    canvas.drawSprite(
      jjSubscreenWidth - 72,
      jjSubscreenHeight - 270,
      ANIM::PICKUPS,
      40,
      0
    );
  }
  return true;
}

class Zeus_Artillery: jjBEHAVIORINTERFACE {
  float startX, startY;
  void onBehave(jjOBJ @ obj) {
    if (obj.state == STATE::START) {
	  if (obj.var[0] != eClone && cloneM.pID == obj.creatorID && cloneM.active == true)
	  {
	   jjOBJ @ bullet = jjObjects[obj.fireBullet(OBJECT::TNT)];
       bullet.creatorID = obj.creatorID;
       bullet.creatorType = CREATOR::PLAYER;
	   bullet.var[0] = eClone;
	  }
	  if(obj.var[0] == eClone)
	  {
	  	startX = cloneM.xPos;
        startY = cloneM.yPos;
	  }
	  else
	  {
	    startX = jjPlayers[obj.creatorID].xPos;
        startY = jjPlayers[obj.creatorID].yPos;
	  }
      obj.state = STATE::FLY;

      obj.xPos = startX;
      obj.yPos = 1;
      obj.playerHandling = HANDLING::SPECIAL;
      obj.animSpeed = 3;
      obj.ySpeed = 13;
    } else if (obj.state == STATE::EXPLODE) {
      for (int i = -50; i < 50; i++) {
        int w = jjAddObject(OBJECT::RFBULLET, obj.xPos + (jjRandom() % 200) - 100, obj.yPos + (jjRandom() % 200) - 100, obj.creatorID, CREATOR::PLAYER);
        jjOBJ @ o = jjObjects[w];
        o.playerHandling = HANDLING::SPECIAL;
        o.counterEnd = 1;
        o.animSpeed = 2;
        if (o.doesCollide(jjPlayers[p.playerID]) && p.playerID != o.creatorID && p.blink == 0)
          if ((p.team != jjPlayers[o.creatorID].team && jjGameMode == GAME::CTF) || jjGameMode == GAME::BATTLE || jjGameMode == GAME::RACE)
            if (jjGameState == GAME::STARTED)
              p.hurt(2, false, jjPlayers[o.creatorID]);
      }
      obj.behavior = BEHAVIOR::EXPLOSION2;
    } else {
      jjPARTICLE @ particle = jjAddParticle(PARTICLE::STAR);
      if (particle!is null) {
        particle.xPos = obj.xPos;
        particle.yPos = obj.yPos;
        particle.xSpeed = jjRandom() & 5;
        particle.ySpeed = jjRandom() & 5;
        particle.star.color = jjRandom() % 100;
        particle.star.size = jjRandom() % 50 + 1;
        particle.star.frame = jjRandom() % 2 - 1;
      }
      int tail = jjAddObject(OBJECT::SEEKERBULLET, obj.xPos, obj.yPos, obj.creatorID, CREATOR::PLAYER);
      jjObjects[tail].counterEnd = 0;
		
	  int curAnim = jjPlayers[obj.creatorID].score > 0? 1 : 0;
      obj.determineCurAnim(ANIM::BOLLPLAT, curAnim, true);
      obj.determineCurFrame(true);
      obj.killAnim = jjObjects[OBJECT::SEEKERBULLET].killAnim;
      obj.yPos += obj.ySpeed;
      obj.draw();
      if (obj.yPos >= startY) obj.state = STATE::EXPLODE;
    }
  }
}

void ReplacePlatform() {
  jjPIXELMAP platform(11, 146 * 32 + 10, 74, 118, 5);
  jjANIMFRAME @ frame = jjAnimFrames[jjAnimations[jjAnimSets[ANIM::BOLLPLAT].firstAnim].firstFrame];



  frame.hotSpotX = -frame.width / 2;
  frame.hotSpotY = -frame.height / 2;
      bool rc = platform.save(frame);
    jjANIMFRAME @ frame2 = jjAnimFrames[jjAnimations[jjAnimSets[ANIM::BOLLPLAT].firstAnim + 1].firstFrame];

    platform.resize(2*74, 2*118);

       rc = platform.save(frame2);

  frame2.hotSpotX = -frame2.width / 2;
  frame2.hotSpotY = -frame2.height / 2;
}

void onLevelBegin() {
  if (!jjIsServer) {
    jjSTREAM packet;
    packet.push(StoP);
    jjSendPacket(packet); //send a packet to request an update from the server
  }
}

void onReceive(jjSTREAM & in packet, int clientID) {
  int type = -1;
  packet.pop(type);
  //jjPrint("type is "+type);
  if (type == -1) jjPrint("error!");
  if (jjIsServer) {
    if (type == StoP)
      sendClone(cloneM, clientID);
    if (type == PtoS) {
      //jjPrint(" I am server!");
      packet.pop(cloneM.pID);
      packet.pop(cloneM.active);
      packet.pop(cloneM.time);
      //jjPrint(" player: "+ cloneM.pID+" active: "+ cloneM.active+" time: "+cloneM.time);

      sendClone(cloneM);
    }
  } else {
    packet.pop(cloneM.pID);
    packet.pop(cloneM.active);
    packet.pop(cloneM.time);
    //jjPrint("player recieving: ");
    //jjPrint(" player: "+ cloneM.pID+" active: "+ cloneM.active+" time: "+cloneM.time);
  }
}

array < bool > transition(2, false);
array < float > transitionTime(2, 0);
array < uint8 > paletteReds;
array < uint8 > paletteBlues;

enum packetType {
  PtoS,
  StoP
};
//need to add packet enum such as joining and updating midway

cloneManager cloneM(1, 0, false);

void sendClone(cloneManager & clone, int clientID = 0, int type = StoP) {
  jjSTREAM packet;
  packet.push(type);
  packet.push(clone.pID);
  packet.push(clone.active);
  packet.push(clone.time);
  jjSendPacket(packet, clientID);
}

enum bulletOwner {
  ePlayer,
  eClone
};

class Clone: jjBEHAVIORINTERFACE {
  int fireTimer = 70;
  int ownerID;
  float dist;
  int dir;
  float delta = 0;
  bool fireSwitch;
  int timer = 0;
  Clone(int owner, float d, float di) {
    dist = d;
    dir = di;
    ownerID = owner;
    fireSwitch = false;
  }

  void onBehave(jjOBJ @ obj) {
    //activity and server checks
    if (cloneM.active == false) {
      obj.xPos = obj.xOrg;
      obj.yPos = obj.yOrg;
    }

    if (cloneM.time <= 0 and cloneM.active == true) {

      cloneM.time = totCloneTime;
    }
    if (cloneM.time <= 0) return;
    cloneM.time--;
    if (cloneM.time == 0)
      cloneM.active = false;
    if ((cloneM.active == true and jjPlayers[cloneM.pID].isInGame == false) or jjPlayers[cloneM.pID].health <= 0) //need to add deaths
    {
      cloneM.active = false;
      cloneM.time = 0;
      if (!jjIsServer)
        sendClone(cloneM, 0, PtoS);
    }
    ownerID = cloneM.pID;
    ////jjprint("timer: "+cloneM.time);
    jjPLAYER @ owner = jjPlayers[ownerID];

    //movement
    obj.yPos = owner.yPos;
    if (owner.direction >= 0) {
      obj.xPos = obj.xPos - 6;
      if (owner.xPos - obj.xPos >= dist)
        obj.xPos = owner.xPos - dist;
      obj.direction = -1;
    }
    if (owner.direction < 0) {
      obj.xPos = obj.xPos + 6;
      if (-owner.xPos + obj.xPos >= dist)
        obj.xPos = owner.xPos + dist;
      obj.direction = 1;
    }
    if (delta * (obj.xPos - owner.xPos) < 0)
      obj.direction *= -1;
    delta = obj.xPos - owner.xPos;
    dir = obj.xPos - owner.direction;

    cloneM.xPos = obj.xPos;
    cloneM.yPos = obj.yPos;
    //fire
    if (owner.keyFire == true && fireSwitch == false && owner.currWeapon != WEAPON::TNT) {
      //jjprint("FIRE");
      fireSwitch = true;
      if (jjWeapons[owner.currWeapon].style == WEAPON::POPCORN)
        fireTimer = 4;
      else
        fireTimer = 35;
		
      OBJECT::Object currwep = wepToEvent(owner.currWeapon, owner.powerup[owner.currWeapon]);
      jjOBJ @ bullet = jjObjects[obj.fireBullet(currwep)];
      bullet.creatorID = ownerID;
      bullet.creatorType = CREATOR::PLAYER;

      if (owner.currWeapon == WEAPON::TOASTER) {
        bullet.xSpeed = 0.5 * bullet.xSpeed;
        bullet.xPos = bullet.xPos + 6.5 * owner.xSpeed;

      }
      if (owner.currWeapon == WEAPON::BOUNCER) {
        //bullet.xPos-=obj.direction*7;
        bullet.xPos = bullet.xPos + 4 * owner.xSpeed;
      }
      if (wepToEvent(owner.currWeapon, owner.powerup[owner.currWeapon]) == OBJECT::RFBULLET) {
        jjOBJ @ bullet2 = jjObjects[obj.fireBullet(currwep)];
        bullet2.creatorID = ownerID;
        bullet2.creatorType = CREATOR::PLAYER;
        bullet.ySpeed = 0.8 * abs(bullet.xSpeed);
        bullet2.ySpeed = -0.8 * abs(bullet.xSpeed);
      }
      if (wepToEvent(owner.currWeapon, owner.powerup[owner.currWeapon]) == OBJECT::RFBULLETPU) {
        jjOBJ @ bullet2 = jjObjects[obj.fireBullet(currwep)];
        bullet2.creatorID = ownerID;
        bullet2.creatorType = CREATOR::PLAYER;
        bullet.ySpeed = 0.8 * abs(bullet.xSpeed);
        bullet2.ySpeed = -0.8 * abs(bullet.xSpeed);
        jjOBJ @ bullet3 = jjObjects[obj.fireBullet(currwep)];
        bullet3.creatorID = ownerID;
        bullet3.creatorType = CREATOR::PLAYER;

      }

      if (jjLayers[4].maskedPixel(owner.xPos, owner.yPos + (57 - 36 + 20)) and owner.keyUp == true) {
        bullet.xSpeed = bullet.xAcc = 0;
        bullet.ySpeed = -4.5;
        bullet.yAcc = 0;

      }
    }
    if (owner.keyFire == false)
      fireSwitch = false;
    if (fireSwitch == true)
      fireTimer--;
    if (fireSwitch == true && fireTimer < 0)
      fireSwitch = false;

  }

  void onDraw(jjOBJ @ obj) {
    if (cloneM.active == false) return;
    jjPLAYER @ player = jjPlayers[ownerID];
    obj.curAnim = player.curAnim;
    obj.curFrame = player.curFrame;
    obj.frameID = player.frameID;
    obj.determineCurFrame();
    jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::SINGLECOLOR, 16 + (8 * (jjGameTicks / 10)) % (256 - 16));
  }

  bool onObjectHit(jjOBJ @ obj, jjOBJ @ bullet, jjPLAYER @ player, int force) {
    if (cloneM.active == false || cloneM.time <= 0) return true;
    if (bullet is null and(jjPlayers[ownerID]).isEnemy(player) and(jjGameState == GAME::STARTED or jjGameState == GAME::OVERTIME))
      player.hurt(1, false, jjPlayers[ownerID]);
    return true;
  }

}

class clonePickup: jjBEHAVIORINTERFACE {
  void onBehave(jjOBJ @ obj) {
    obj.light = 12;
    obj.lightType = LIGHT::BRIGHT;
    obj.scriptedCollisions = true;
    obj.behave(BEHAVIOR::PICKUP);
    if (obj.state == STATE::FLOATFALL) obj.state = STATE::FLOAT;

  }

  void onDraw(jjOBJ @ obj) {
    jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::SINGLECOLOR, 16 + (8 * (jjGameTicks / 10)) % (256 - 16));
  }

}

const int totCloneTime = 70 * (19);
class cloneManager {

  int pID;
  int time;
  bool active;
  float xPos;
  float yPos;
  cloneManager() {};
  cloneManager(int p, int t, bool b) {
    pID = p;
    time = t;
    active = b;
  }
}

const OBJECT::Object wepToEvent(int weapon, bool isPU) {
  switch (weapon) {
  case WEAPON::BLASTER:
    return isPU ? OBJECT::BLASTERBULLETPU : OBJECT::BLASTERBULLET;
  case WEAPON::BOUNCER:
    return isPU ? OBJECT::BOUNCERBULLETPU : OBJECT::BOUNCERBULLET;
  case WEAPON::ICE:
    return isPU ? OBJECT::ICEBULLETPU : OBJECT::ICEBULLET;
  case WEAPON::SEEKER:
    return isPU ? OBJECT::SEEKERBULLETPU : OBJECT::SEEKERBULLET;
  case WEAPON::RF:
    return isPU ? OBJECT::RFBULLETPU : OBJECT::RFBULLET;
  case WEAPON::TOASTER:
    return isPU ? OBJECT::TOASTERBULLETPU : OBJECT::TOASTERBULLET;
  case WEAPON::TNT:
    return OBJECT::TNT;
  case WEAPON::GUN8:
    return isPU ? OBJECT::FIREBALLBULLETPU : OBJECT::FIREBALLBULLET;
  case WEAPON::GUN9:
    return isPU ? OBJECT::ELECTROBULLETPU : OBJECT::ELECTROBULLET;
  default:
    return OBJECT::BLASTERBULLET;
  }
  return OBJECT::BLASTERBULLET;
}

int sgn(float x) {
  return (x < 0 ? -1 : 1);
}

int min(int a, int b) {
  return a < b ? a : b;
}

void CannotBeShotDown(jjOBJ @ obj) {
  obj.behave(BEHAVIOR::PICKUP);
  if (obj.state == STATE::FLOATFALL) obj.state = STATE::FLOAT;
}

uint16 angle = 0;
/*using p.score as spreadshot countdown*/
int spreadShotCountdown = 0;
const int spreadShotMaxTime = 20;
class SpreadShot: jjBEHAVIORINTERFACE {
  void onBehave(jjOBJ @ obj) {

    obj.behave(BEHAVIOR::PICKUP, false);
    obj.light = 12;
    obj.lightType = LIGHT::BRIGHT;
    obj.xPos = 16 + obj.xOrg + 0 * jjSin(-jjGameTicks * 5 + int(obj.xOrg) * 32 / 3);
    obj.yPos = 16 + obj.yOrg + 0 * jjCos(-jjGameTicks * 5 + int(obj.xOrg) * 32 / 3);
  }
  void onDraw(jjOBJ @ obj) {
    jjDrawRotatedSprite(obj.xPos, obj.yPos + 10, ANIM::AMMO, 37, jjGameTicks >> 2, angle, 1, 1, SPRITE::NORMAL, 0, 1);
    jjDrawRotatedSprite(obj.xPos, obj.yPos, ANIM::AMMO, 37, jjGameTicks >> 2, angle, 1, 1, SPRITE::NORMAL, 0, 1);
    jjDrawRotatedSprite(obj.xPos, obj.yPos - 10, ANIM::AMMO, 37, jjGameTicks >> 2, angle, 1, 1, SPRITE::NORMAL, 0, 1);
  }
  bool onObjectHit(jjOBJ @ obj, jjOBJ @ bullet, jjPLAYER @ p, int force) {
    obj.bulletHandling = HANDLING::IGNOREBULLET;
    obj.behavior = BEHAVIOR::EXPLOSION2;
    obj.scriptedCollisions = false;
    obj.frameID = 0;
    //if (p.isLocal) spreadShotCountdown = 15;
    p.score = spreadShotMaxTime;
    jjSamplePriority(SOUND::COMMON_PICKUP1);
    return true;
  }
}

void resetSpread() {
  jjWeapons[WEAPON::BLASTER].spread = SPREAD::NORMAL;
  jjWeapons[WEAPON::BOUNCER].spread = SPREAD::NORMAL;
  jjWeapons[WEAPON::ICE].spread = SPREAD::ICE;
  jjWeapons[WEAPON::SEEKER].spread = SPREAD::NORMAL;
  jjWeapons[WEAPON::RF].spread = SPREAD::RF;
  jjWeapons[WEAPON::TNT].spread = SPREAD::NORMAL;
  jjWeapons[WEAPON::TOASTER].spread = SPREAD::TOASTER;
  jjWeapons[WEAPON::GUN8].spread = SPREAD::NORMAL;
  jjWeapons[WEAPON::GUN9].spread = SPREAD::NORMAL;
}