float queen_x, queen_y, devan_x, devan_y; int queen_id = -1; int devan_id = -1; void onLevelLoad(){ if(jjObjectPresets[OBJECT::DEVILDEVAN].behavior == BEHAVIOR::DEVILDEVAN){ jjObjectPresets[OBJECT::DEVILDEVAN].behavior = function(obj) { obj.behavior = DevanRewrite(); }; } jjObjectPresets[OBJECT::ROBOT].behavior = function(obj) { obj.behavior = RobotRewrite(); }; jjObjectPresets[OBJECT::BILSY].behavior = function(obj) { obj.behavior = BilsyRewrite(); }; jjObjectPresets[OBJECT::TUFBOSS].behavior = function(obj) { obj.behavior = TufbossRewrite(); }; jjObjectPresets[OBJECT::BLASTERBULLET].behavior = function(obj) { obj.behavior = BulletRewrite(); }; jjObjectPresets[OBJECT::SEEKERBULLET].behavior = function(obj) { obj.behavior = SeekerRewrite(); }; jjObjectPresets[OBJECT::SEEKERBULLETPU].behavior = function(obj) { obj.behavior = SeekerRewrite(); }; jjObjectPresets[OBJECT::BAT].behavior = function(obj) { obj.behavior = BatRewrite(); }; jjObjectPresets[OBJECT::BAT].scriptedCollisions = true; jjObjectPresets[OBJECT::BAT].playerHandling = HANDLING::SPECIAL; } const array ButtstompSounds = {SOUND::COMMON_SPLAT1, SOUND::COMMON_SPLAT2, SOUND::COMMON_SPLAT3, SOUND::COMMON_SPLAT4}; class BatRewrite : jjBEHAVIORINTERFACE { bool deleted = false; int delay = -1; int count = 0; void onBehave(jjOBJ@ obj) { if(!deleted){ obj.behave(BEHAVIOR::BAT, true); obj.scriptedCollisions = true; obj.playerHandling = HANDLING::SPECIAL; if(delay == -1){ if(jjEventGet(int(obj.xOrg/32), int(obj.yOrg/32)) == OBJECT::GENERATOR){ delay = jjParameterGet(int(obj.xPos/32), int(obj.yPos/32), 8, 8); //jjAlert("delay: "+delay); if(delay == 0) delay = 5; } } }else{ if(jjGameTicks%70 == 0){ count++; if(count >= delay){ //jjAlert("recreate bat", false); obj.xPos = obj.xOrg; obj.yPos = obj.yOrg; obj.state = STATE::START; deleted = false; count = 0; } } } } bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ player, int force) { //As described in the signs in-level, this is a nearly 100% faithful recreation of standard enemy collision code. if(!deleted){ if (bullet !is null) { //recreation of HANDLING::HURTBYBULLET with HANDLING::ENEMY if (obj.causesRicochet) { if ((bullet.var[6] & 6) == 0) //not fire-based, not a laser beam bullet.ricochet(); else if ((bullet.var[6] & 4) == 0) //not a laser beam bullet.delete(); } else if ((bullet.var[6] & 16) == 0) //not a fireball bullet.state = STATE::EXPLODE; if (obj.freeze > 0 && force < 3) force = 3; obj.energy -= force; obj.justHit = 5; //flash white for 5 ticks--jjOBJ::justHit is automatically deincremented by the JJ2 engine, so individual behavior functions don't need to worry about doing that. if (obj.energy <= 0) { //killed obj.energy = 0; obj.state = STATE::FADEOUT; deleted = true; if (obj.freeze > 0) obj.unfreeze(0); else if ((bullet.var[6] & 2) == 0) //not fire-based obj.particlePixelExplosion(0); else { jjSample(obj.xPos, obj.yPos, SOUND::COMMON_BURN); if ((bullet.var[6] & 4) != 0) //laser beam obj.particlePixelExplosion(72); //gray else obj.particlePixelExplosion(((bullet.var[6] & 8) != 0) ? 32 : 40); //powered-up (blue) or not (orange) } if (player !is null) { obj.grantPickup(player, (uint(bullet.curAnim) == jjAnimSets[ANIM::AMMO].firstAnim + 17) ? 5 : 10); //givePlayerPointsForObject(player, obj); } } else obj.freeze = 0; } else { //recreation of HANDLING::ENEMY; player guaranteed to be non-null if (force != 0) { //attacking via special attack, e.g. buttstomp obj.energy -= 4; //constant amount of damage for special attacks if (obj.energy <= 0) { //killed obj.energy = 0; //givePlayerPointsForObject(player, obj); obj.state = STATE::FADEOUT; deleted = true; } else { //only wounded obj.justHit = 5; } if (obj.freeze > 0) { obj.unfreeze(1); } else { if (obj.energy == 0) obj.particlePixelExplosion(2); jjSample(obj.xPos, obj.yPos, ButtstompSounds[jjRandom() % ButtstompSounds.length]); } if (force > 0) { //buttstomp or sugar rush player.buttstomp = 50; //landing player.ySpeed = player.ySpeed / -2 - 8; player.yAcc = 0; player.extendInvincibility(-70); } else if (force == -101) { //running into frozen enemy player.xAcc = 0; player.xSpeed /= -2; player.ySpeed = -6; player.extendInvincibility(-10); } } else { //not attacking player.hurt(); } } } return true; } } array kill(4,0); void onMain(){ for(int i=0; i (p.xPos*p.xPos + p.yPos*p.yPos)){ min = p.xPos*p.xPos + p.yPos*p.yPos; poz = p.playerID; } } return poz; } void cDEVILDEVAN(jjOBJ@ obj) { switch (obj.state) { case STATE::FLY: if (obj.counter == 0) { obj.curAnim = jjAnimSets[ANIM::DEVILDEVAN].firstAnim + 5; obj.frameID = 0; obj.var[5] = findNearestLocalPlayer(); if (obj.var[5] < 0) obj.var[5] = 0; if (obj.xPos >= jjPlayers[obj.var[5]].xPos) { obj.var[4] = 40; obj.direction = -1; } else { obj.var[4] = -40; obj.direction = 1; } obj.var[3] = -4 * int(jjRandom()&15);//RandFac(15); } obj.counter++; if (obj.counter % 5 == 0) { obj.frameID++; if (obj.frameID == 1){ //PlaySample(obj.xPos, obj.yPos, sDEVILDEVAN_FLAP, 200, 0); } if (uint(obj.frameID) >= jjAnimations[obj.curAnim].frameCount){ obj.frameID = 0; } } if (obj.counter >= 128) { obj.state = STATE::ATTACK; obj.curAnim = jjAnimSets[ANIM::DEVILDEVAN].firstAnim; obj.frameID = 0; obj.counter = 0; } else { int xDist = int((jjPlayers[obj.var[5]].xPos + obj.var[4] - obj.xPos) / (129 - obj.counter)); if (xDist < -3) xDist = -3; else if (xDist > 3) xDist = 3; int yDist = int((obj.var[3] + jjPlayers[obj.var[5]].yPos - obj.yPos) / (129 - obj.counter)); if (yDist < -2) yDist = -2; else if (yDist > 2) yDist = 2; obj.xSpeed = (obj.xSpeed + 3 * xDist) / 4; obj.ySpeed = (obj.ySpeed + 3 * yDist) / 4; obj.xPos += obj.xSpeed; obj.yPos += obj.ySpeed; if (obj.xPos < jjPlayers[obj.var[5]].xPos - 20) obj.direction = 1; else if (obj.xPos > jjPlayers[obj.var[5]].xPos + 20) obj.direction = -1; } obj.curFrame = jjAnimations[obj.curAnim].firstFrame + obj.frameID; break; } SPRITE::Mode sprite_mode = obj.freeze == 0 ? SPRITE::NORMAL : SPRITE::FROZEN; jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, sprite_mode); }