├── src └── main │ ├── resources │ ├── font.gif │ ├── logo.gif │ ├── test.lvl │ ├── bgsheet.png │ ├── tiles.dat │ ├── title.gif │ ├── endscene.gif │ ├── itemsheet.png │ ├── mapsheet.png │ ├── snd │ │ ├── 1-up.wav │ │ ├── bump.wav │ │ ├── coin.wav │ │ ├── death.wav │ │ ├── exit.wav │ │ ├── jump.wav │ │ ├── kick.wav │ │ ├── pipe.wav │ │ ├── stomp.wav │ │ ├── cannon.wav │ │ ├── fireball.wav │ │ ├── message.wav │ │ ├── powerup.wav │ │ ├── sprout.wav │ │ ├── breakblock.wav │ │ ├── powerdown.wav │ │ └── stagestart.wav │ ├── worldmap.png │ ├── enemysheet.png │ ├── gameovergost.gif │ ├── mariosheet.png │ ├── mus │ │ ├── smb3map1.mid │ │ ├── smb3ovr1.mid │ │ ├── smb3undr.mid │ │ ├── smwovr1.mid │ │ ├── smwovr2.mid │ │ ├── smwtitle.mid │ │ └── smwfortress.mid │ ├── firemariosheet.png │ ├── particlesheet.png │ ├── racoonmariosheet.png │ └── smallmariosheet.png │ └── java │ └── com │ └── mojang │ ├── sonar │ ├── SoundListener.java │ ├── SoundSource.java │ ├── SoundProducer.java │ ├── StereoSoundProducer.java │ ├── sample │ │ ├── SonarSample.java │ │ ├── SamplePlayer.java │ │ └── SampleLoader.java │ ├── FixedSoundSource.java │ ├── FakeSoundEngine.java │ ├── mixer │ │ ├── Sound.java │ │ └── ListenerMixer.java │ └── SonarSoundEngine.java │ └── mario │ ├── sprites │ ├── SpriteContext.java │ ├── Particle.java │ ├── CoinAnim.java │ ├── Sparkle.java │ ├── FireFlower.java │ ├── FlowerEnemy.java │ ├── Sprite.java │ ├── BulletBill.java │ ├── Fireball.java │ ├── Mushroom.java │ ├── Shell.java │ ├── Enemy.java │ └── Mario.java │ ├── Scene.java │ ├── FrameLauncher.java │ ├── level │ ├── SpriteTemplate.java │ ├── ImprovedNoise.java │ ├── Level.java │ └── BgLevelGenerator.java │ ├── AppletLauncher.java │ ├── Recorder.java │ ├── Replayer.java │ ├── WinScene.java │ ├── LoseScene.java │ ├── TitleScene.java │ ├── BgRenderer.java │ ├── mapedit │ ├── TilePicker.java │ ├── LevelEditView.java │ └── LevelEditor.java │ ├── Scale2x.java │ ├── Art.java │ ├── LevelRenderer.java │ ├── MarioComponent.java │ └── LevelScene.java ├── .gitignore ├── README.markdown ├── pom.xml └── LICENSE.txt /src/main/resources/font.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/font.gif -------------------------------------------------------------------------------- /src/main/resources/logo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/logo.gif -------------------------------------------------------------------------------- /src/main/resources/test.lvl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/test.lvl -------------------------------------------------------------------------------- /src/main/resources/bgsheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/bgsheet.png -------------------------------------------------------------------------------- /src/main/resources/tiles.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/tiles.dat -------------------------------------------------------------------------------- /src/main/resources/title.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/title.gif -------------------------------------------------------------------------------- /src/main/resources/endscene.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/endscene.gif -------------------------------------------------------------------------------- /src/main/resources/itemsheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/itemsheet.png -------------------------------------------------------------------------------- /src/main/resources/mapsheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/mapsheet.png -------------------------------------------------------------------------------- /src/main/resources/snd/1-up.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/snd/1-up.wav -------------------------------------------------------------------------------- /src/main/resources/snd/bump.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/snd/bump.wav -------------------------------------------------------------------------------- /src/main/resources/snd/coin.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/snd/coin.wav -------------------------------------------------------------------------------- /src/main/resources/snd/death.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/snd/death.wav -------------------------------------------------------------------------------- /src/main/resources/snd/exit.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/snd/exit.wav -------------------------------------------------------------------------------- /src/main/resources/snd/jump.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/snd/jump.wav -------------------------------------------------------------------------------- /src/main/resources/snd/kick.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/snd/kick.wav -------------------------------------------------------------------------------- /src/main/resources/snd/pipe.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/snd/pipe.wav -------------------------------------------------------------------------------- /src/main/resources/snd/stomp.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/snd/stomp.wav -------------------------------------------------------------------------------- /src/main/resources/worldmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/worldmap.png -------------------------------------------------------------------------------- /src/main/resources/enemysheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/enemysheet.png -------------------------------------------------------------------------------- /src/main/resources/gameovergost.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/gameovergost.gif -------------------------------------------------------------------------------- /src/main/resources/mariosheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/mariosheet.png -------------------------------------------------------------------------------- /src/main/resources/mus/smb3map1.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/mus/smb3map1.mid -------------------------------------------------------------------------------- /src/main/resources/mus/smb3ovr1.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/mus/smb3ovr1.mid -------------------------------------------------------------------------------- /src/main/resources/mus/smb3undr.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/mus/smb3undr.mid -------------------------------------------------------------------------------- /src/main/resources/mus/smwovr1.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/mus/smwovr1.mid -------------------------------------------------------------------------------- /src/main/resources/mus/smwovr2.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/mus/smwovr2.mid -------------------------------------------------------------------------------- /src/main/resources/mus/smwtitle.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/mus/smwtitle.mid -------------------------------------------------------------------------------- /src/main/resources/snd/cannon.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/snd/cannon.wav -------------------------------------------------------------------------------- /src/main/resources/snd/fireball.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/snd/fireball.wav -------------------------------------------------------------------------------- /src/main/resources/snd/message.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/snd/message.wav -------------------------------------------------------------------------------- /src/main/resources/snd/powerup.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/snd/powerup.wav -------------------------------------------------------------------------------- /src/main/resources/snd/sprout.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/snd/sprout.wav -------------------------------------------------------------------------------- /src/main/resources/firemariosheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/firemariosheet.png -------------------------------------------------------------------------------- /src/main/resources/particlesheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/particlesheet.png -------------------------------------------------------------------------------- /src/main/resources/snd/breakblock.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/snd/breakblock.wav -------------------------------------------------------------------------------- /src/main/resources/snd/powerdown.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/snd/powerdown.wav -------------------------------------------------------------------------------- /src/main/resources/snd/stagestart.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/snd/stagestart.wav -------------------------------------------------------------------------------- /src/main/resources/mus/smwfortress.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/mus/smwfortress.mid -------------------------------------------------------------------------------- /src/main/resources/racoonmariosheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/racoonmariosheet.png -------------------------------------------------------------------------------- /src/main/resources/smallmariosheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflewis/Infinite-Mario-Bros/HEAD/src/main/resources/smallmariosheet.png -------------------------------------------------------------------------------- /src/main/java/com/mojang/sonar/SoundListener.java: -------------------------------------------------------------------------------- 1 | package com.mojang.sonar; 2 | 3 | public interface SoundListener extends SoundSource 4 | { 5 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | .DS_Store 3 | .git 4 | test/* 5 | work/* 6 | target/* 7 | .settings/* 8 | *~ 9 | .project 10 | .classpath 11 | _site 12 | index.markdown -------------------------------------------------------------------------------- /src/main/java/com/mojang/sonar/SoundSource.java: -------------------------------------------------------------------------------- 1 | package com.mojang.sonar; 2 | 3 | public interface SoundSource 4 | { 5 | public float getX(float alpha); 6 | public float getY(float alpha); 7 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/sprites/SpriteContext.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario.sprites; 2 | 3 | public interface SpriteContext 4 | { 5 | public void addSprite(Sprite sprite); 6 | public void removeSprite(Sprite sprite); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/mojang/sonar/SoundProducer.java: -------------------------------------------------------------------------------- 1 | package com.mojang.sonar; 2 | 3 | public interface SoundProducer 4 | { 5 | public float read(float[] buf, int readRate); 6 | public void skip(int samplesToSkip, int readRate); 7 | public boolean isLive(); 8 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/sonar/StereoSoundProducer.java: -------------------------------------------------------------------------------- 1 | package com.mojang.sonar; 2 | 3 | public interface StereoSoundProducer 4 | { 5 | public float read(float[] leftBuf, float[] rightBuf, int readRate); 6 | public void skip(int samplesToSkip, int readRate); 7 | } -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | Infinite Mario Bros. 2 | ====================== 3 | [Infinite Mario Bros](http://www.mojang.com/notch/mario/) source code has a bug in the timing, which prevents it working on Mac OS X, and maybe other platforms. This version uses the timing from the Mario AI competition, and is Mac-compatible. 4 | -------------------------------------------------------------------------------- /src/main/java/com/mojang/sonar/sample/SonarSample.java: -------------------------------------------------------------------------------- 1 | package com.mojang.sonar.sample; 2 | 3 | public class SonarSample 4 | { 5 | public final float[] buf; 6 | public final float rate; 7 | 8 | public SonarSample(float[] buf, float rate) 9 | { 10 | this.buf = buf; 11 | this.rate = rate; 12 | } 13 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/sonar/FixedSoundSource.java: -------------------------------------------------------------------------------- 1 | package com.mojang.sonar; 2 | 3 | /** 4 | * @author Administrator 5 | */ 6 | public class FixedSoundSource implements SoundSource 7 | { 8 | private float x; 9 | private float y; 10 | 11 | public FixedSoundSource(float x, float y) 12 | { 13 | this.x = x; 14 | this.y = y; 15 | } 16 | 17 | public FixedSoundSource(SoundSource soundSource) 18 | { 19 | this.x = soundSource.getX(1); 20 | this.y = soundSource.getY(1); 21 | } 22 | 23 | public float getX(float alpha) 24 | { 25 | return x; 26 | } 27 | 28 | public float getY(float alpha) 29 | { 30 | return y; 31 | } 32 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/sonar/FakeSoundEngine.java: -------------------------------------------------------------------------------- 1 | package com.mojang.sonar; 2 | 3 | import com.mojang.sonar.sample.*; 4 | 5 | 6 | public class FakeSoundEngine extends SonarSoundEngine 7 | { 8 | public void setListener(SoundListener soundListener) 9 | { 10 | } 11 | 12 | public void shutDown() 13 | { 14 | } 15 | 16 | public SonarSample loadSample(String resourceName) 17 | { 18 | return null; 19 | } 20 | 21 | public void play(SonarSample sample, SoundSource soundSource, float volume, float priority, float rate) 22 | { 23 | } 24 | 25 | public void clientTick(float alpha) 26 | { 27 | } 28 | 29 | public void tick() 30 | { 31 | } 32 | 33 | public void run() 34 | { 35 | } 36 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/Scene.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario; 2 | 3 | import java.awt.Graphics; 4 | 5 | import com.mojang.sonar.SonarSoundEngine; 6 | import com.mojang.sonar.SoundListener; 7 | 8 | 9 | public abstract class Scene implements SoundListener 10 | { 11 | public SonarSoundEngine sound; 12 | public static boolean[] keys = new boolean[16]; 13 | 14 | public void toggleKey(int key, boolean isPressed) 15 | { 16 | keys[key] = isPressed; 17 | } 18 | 19 | public final void setSound(SonarSoundEngine sound) 20 | { 21 | sound.setListener(this); 22 | this.sound = sound; 23 | } 24 | 25 | public abstract void init(); 26 | 27 | public abstract void tick(); 28 | 29 | public abstract void render(Graphics og, float alpha); 30 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/FrameLauncher.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario; 2 | 3 | import java.awt.*; 4 | import javax.swing.*; 5 | 6 | public class FrameLauncher 7 | { 8 | public static void main(String[] args) 9 | { 10 | MarioComponent mario = new MarioComponent(640, 480); 11 | JFrame frame = new JFrame("Infinite Mario Bros."); 12 | frame.setContentPane(mario); 13 | frame.pack(); 14 | frame.setResizable(false); 15 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 16 | 17 | Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); 18 | frame.setLocation((screenSize.width-frame.getWidth())/2, (screenSize.height-frame.getHeight())/2); 19 | 20 | frame.setVisible(true); 21 | 22 | mario.start(); 23 | // frame.addKeyListener(mario); 24 | // frame.addFocusListener(mario); 25 | } 26 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/sprites/Particle.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario.sprites; 2 | 3 | import com.mojang.mario.Art; 4 | 5 | public class Particle extends Sprite 6 | { 7 | public int life; 8 | 9 | public Particle(int x, int y, float xa, float ya) 10 | { 11 | this(x, y, xa, ya, (int)(Math.random()*2), 0); 12 | } 13 | 14 | public Particle(int x, int y, float xa, float ya, int xPic, int yPic) 15 | { 16 | sheet = Art.particles; 17 | this.x = x; 18 | this.y = y; 19 | this.xa = xa; 20 | this.ya = ya; 21 | this.xPic = xPic; 22 | this.yPic = yPic; 23 | this.xPicO = 4; 24 | this.yPicO = 4; 25 | 26 | wPic = 8; 27 | hPic = 8; 28 | life = 10; 29 | } 30 | 31 | public void move() 32 | { 33 | if (life--<0) Sprite.spriteContext.removeSprite(this); 34 | x+=xa; 35 | y+=ya; 36 | ya*=0.95f; 37 | ya+=3; 38 | } 39 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/level/SpriteTemplate.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario.level; 2 | 3 | import com.mojang.mario.LevelScene; 4 | import com.mojang.mario.sprites.*; 5 | 6 | public class SpriteTemplate 7 | { 8 | public int lastVisibleTick = -1; 9 | public Sprite sprite; 10 | public boolean isDead = false; 11 | private boolean winged; 12 | 13 | private int type; 14 | 15 | public SpriteTemplate(int type, boolean winged) 16 | { 17 | this.type = type; 18 | this.winged = winged; 19 | } 20 | 21 | public void spawn(LevelScene world, int x, int y, int dir) 22 | { 23 | if (isDead) return; 24 | 25 | if (type==Enemy.ENEMY_FLOWER) 26 | { 27 | sprite = new FlowerEnemy(world, x*16+15, y*16+24); 28 | } 29 | else 30 | { 31 | sprite = new Enemy(world, x*16+8, y*16+15, dir, type, winged); 32 | } 33 | sprite.spriteTemplate = this; 34 | world.addSprite(sprite); 35 | } 36 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/sprites/CoinAnim.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario.sprites; 2 | 3 | import com.mojang.mario.Art; 4 | 5 | 6 | public class CoinAnim extends Sprite 7 | { 8 | private int life = 10; 9 | 10 | public CoinAnim(int xTile, int yTile) 11 | { 12 | sheet = Art.level; 13 | wPic = hPic = 16; 14 | 15 | x = xTile * 16; 16 | y = yTile * 16 - 16; 17 | xa = 0; 18 | ya = -6f; 19 | xPic = 0; 20 | yPic = 2; 21 | } 22 | 23 | public void move() 24 | { 25 | if (life-- < 0) 26 | { 27 | Sprite.spriteContext.removeSprite(this); 28 | for (int xx = 0; xx < 2; xx++) 29 | for (int yy = 0; yy < 2; yy++) 30 | Sprite.spriteContext.addSprite(new Sparkle((int)x + xx * 8 + (int) (Math.random() * 8), (int)y + yy * 8 + (int) (Math.random() * 8), 0, 0, 0, 2, 5)); 31 | } 32 | 33 | xPic = life & 3; 34 | 35 | x += xa; 36 | y += ya; 37 | ya += 1; 38 | } 39 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/AppletLauncher.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario; 2 | 3 | import javax.swing.JApplet; 4 | 5 | 6 | public class AppletLauncher extends JApplet 7 | { 8 | private static final long serialVersionUID = -2238077255106243788L; 9 | 10 | private MarioComponent mario; 11 | private boolean started = false; 12 | 13 | public void init() 14 | { 15 | this.setSize(640, 480); 16 | } 17 | 18 | public void start() 19 | { 20 | if (!started) 21 | { 22 | started = true; 23 | mario = new MarioComponent(getWidth(), getHeight()); 24 | setContentPane(mario); 25 | setFocusable(false); 26 | mario.setFocusCycleRoot(true); 27 | 28 | mario.start(); 29 | // addKeyListener(mario); 30 | // addFocusListener(mario); 31 | } 32 | } 33 | 34 | public void stop() 35 | { 36 | if (started) 37 | { 38 | started = false; 39 | removeKeyListener(mario); 40 | mario.stop(); 41 | removeFocusListener(mario); 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/sprites/Sparkle.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario.sprites; 2 | 3 | import com.mojang.mario.Art; 4 | 5 | public class Sparkle extends Sprite 6 | { 7 | public int life; 8 | public int xPicStart; 9 | 10 | public Sparkle(int x, int y, float xa, float ya) 11 | { 12 | this(x, y, xa, ya, (int)(Math.random()*2), 0, 5); 13 | } 14 | 15 | public Sparkle(int x, int y, float xa, float ya, int xPic, int yPic, int timeSpan) 16 | { 17 | sheet = Art.particles; 18 | this.x = x; 19 | this.y = y; 20 | this.xa = xa; 21 | this.ya = ya; 22 | this.xPic = xPic; 23 | xPicStart = xPic; 24 | this.yPic = yPic; 25 | this.xPicO = 4; 26 | this.yPicO = 4; 27 | 28 | wPic = 8; 29 | hPic = 8; 30 | life = 10+(int)(Math.random()*timeSpan); 31 | } 32 | 33 | public void move() 34 | { 35 | if (life>10) 36 | xPic = 7; 37 | else 38 | xPic = xPicStart+(10-life)*4/10; 39 | 40 | if (life--<0) Sprite.spriteContext.removeSprite(this); 41 | 42 | x+=xa; 43 | y+=ya; 44 | } 45 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/sonar/sample/SamplePlayer.java: -------------------------------------------------------------------------------- 1 | package com.mojang.sonar.sample; 2 | 3 | import com.mojang.sonar.*; 4 | 5 | 6 | public class SamplePlayer implements SoundProducer 7 | { 8 | private SonarSample sample; 9 | private float pos = 0; 10 | public boolean alive = true; 11 | private float rate; 12 | 13 | public SamplePlayer(SonarSample sample, float rate) 14 | { 15 | this.rate = rate; 16 | this.sample = sample; 17 | } 18 | 19 | public float read(float[] buf, int readRate) 20 | { 21 | float step = (sample.rate*rate)/readRate; 22 | 23 | for (int i=0; i=sample.buf.length) 26 | { 27 | buf[i] = 0; 28 | alive = false; 29 | } 30 | else 31 | { 32 | buf[i]=sample.buf[(int)(pos)]; 33 | } 34 | pos+=step; 35 | } 36 | 37 | return 1; 38 | } 39 | 40 | public void skip(int samplesToSkip, int readRate) 41 | { 42 | float step = sample.rate/readRate; 43 | pos+=step*samplesToSkip; 44 | 45 | if (pos>=sample.buf.length) 46 | { 47 | alive = false; 48 | } 49 | } 50 | 51 | public boolean isLive() 52 | { 53 | return alive; 54 | } 55 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/Recorder.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario; 2 | 3 | import java.io.*; 4 | 5 | 6 | public class Recorder 7 | { 8 | private ByteArrayOutputStream baos = new ByteArrayOutputStream(); 9 | private DataOutputStream dos = new DataOutputStream(baos); 10 | 11 | private byte lastTick = 0; 12 | private int tickCount = 0; 13 | 14 | public void addLong(long val) 15 | { 16 | try 17 | { 18 | dos.writeLong(val); 19 | } 20 | catch (IOException e) 21 | { 22 | e.printStackTrace(); 23 | } 24 | } 25 | 26 | public void addTick(byte tick) 27 | { 28 | try 29 | { 30 | if (tick == lastTick) 31 | { 32 | tickCount++; 33 | } 34 | else 35 | { 36 | dos.writeInt(tickCount); 37 | dos.write(tick); 38 | lastTick = tick; 39 | tickCount = 1; 40 | } 41 | } 42 | catch (IOException e) 43 | { 44 | e.printStackTrace(); 45 | } 46 | } 47 | 48 | public byte[] getBytes() 49 | { 50 | try 51 | { 52 | dos.writeInt(tickCount); 53 | dos.write(-1); 54 | dos.close(); 55 | } 56 | catch (IOException e) 57 | { 58 | e.printStackTrace(); 59 | } 60 | return baos.toByteArray(); 61 | } 62 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/Replayer.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario; 2 | 3 | import java.io.*; 4 | 5 | 6 | public class Replayer 7 | { 8 | private ByteArrayInputStream bais; 9 | private DataInputStream dis; 10 | 11 | private byte tick = 0; 12 | private int tickCount = -99999999; 13 | 14 | public Replayer(byte[] bytes) 15 | { 16 | bais = new ByteArrayInputStream(bytes); 17 | dis = new DataInputStream(bais); 18 | } 19 | 20 | public long nextLong() 21 | { 22 | try 23 | { 24 | return dis.readLong(); 25 | } 26 | catch (IOException e) 27 | { 28 | e.printStackTrace(); 29 | return 0; 30 | } 31 | } 32 | 33 | public byte nextTick() 34 | { 35 | if (tickCount == -99999999) 36 | { 37 | try 38 | { 39 | tickCount = dis.readInt(); 40 | } 41 | catch (IOException e) 42 | { 43 | e.printStackTrace(); 44 | } 45 | } 46 | 47 | if (tickCount == 0) 48 | { 49 | try 50 | { 51 | tick = (byte) dis.read(); 52 | tickCount = dis.readInt(); 53 | } 54 | catch (IOException e) 55 | { 56 | } 57 | } 58 | 59 | if (tickCount>0) 60 | { 61 | tickCount--; 62 | } 63 | 64 | return tick; 65 | } 66 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/sprites/FireFlower.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario.sprites; 2 | 3 | import com.mojang.mario.Art; 4 | import com.mojang.mario.LevelScene; 5 | 6 | 7 | public class FireFlower extends Sprite 8 | { 9 | @SuppressWarnings("unused") 10 | private int width = 4; 11 | int height = 24; 12 | 13 | private LevelScene world; 14 | public int facing; 15 | 16 | public boolean avoidCliffs = false; 17 | private int life; 18 | 19 | public FireFlower(LevelScene world, int x, int y) 20 | { 21 | sheet = Art.items; 22 | 23 | this.x = x; 24 | this.y = y; 25 | this.world = world; 26 | xPicO = 8; 27 | yPicO = 15; 28 | 29 | xPic = 1; 30 | yPic = 0; 31 | height = 12; 32 | facing = 1; 33 | wPic = hPic = 16; 34 | life = 0; 35 | } 36 | 37 | public void collideCheck() 38 | { 39 | float xMarioD = world.mario.x - x; 40 | float yMarioD = world.mario.y - y; 41 | float w = 16; 42 | if (xMarioD > -w && xMarioD < w) 43 | { 44 | if (yMarioD > -height && yMarioD < world.mario.height) 45 | { 46 | world.mario.getFlower(); 47 | spriteContext.removeSprite(this); 48 | } 49 | } 50 | } 51 | 52 | public void move() 53 | { 54 | if (life<9) 55 | { 56 | layer = 0; 57 | y--; 58 | life++; 59 | return; 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | edu.ucsc.eis.mario 5 | Mario 6 | Infinite Mario Mac 7 | 1.0 8 | A Mac-compatible version of Infinite Mario. 9 | 10 | 11 | 12 | org.apache.maven.plugins 13 | maven-compiler-plugin 14 | 15 | 1.5 16 | 1.5 17 | 18 | 19 | 20 | maven-assembly-plugin 21 | 2.2-beta-5 22 | 23 | 24 | create-executable-jar 25 | package 26 | 27 | single 28 | 29 | 30 | 31 | 32 | jar-with-dependencies 33 | 34 | 35 | 36 | 37 | com.mojang.mario.FrameLauncher 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/WinScene.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario; 2 | 3 | import java.awt.Color; 4 | import java.awt.Graphics; 5 | 6 | import com.mojang.mario.sprites.Mario; 7 | 8 | public class WinScene extends Scene 9 | { 10 | private MarioComponent component; 11 | private int tick; 12 | private String scrollMessage = "Thank you for saving me, Mario!"; 13 | 14 | public WinScene(MarioComponent component) 15 | { 16 | this.component = component; 17 | } 18 | 19 | public void init() 20 | { 21 | } 22 | 23 | public void render(Graphics g, float alpha) 24 | { 25 | g.setColor(Color.decode("#8080a0")); 26 | g.fillRect(0, 0, 320, 240); 27 | g.drawImage(Art.endScene[tick/24%2][0], 160-48, 100-48, null); 28 | drawString(g, scrollMessage, 160-scrollMessage.length()*4, 160, 0); 29 | } 30 | 31 | private void drawString(Graphics g, String text, int x, int y, int c) 32 | { 33 | char[] ch = text.toCharArray(); 34 | for (int i = 0; i < ch.length; i++) 35 | { 36 | g.drawImage(Art.font[ch[i] - 32][c], x + i * 8, y, null); 37 | } 38 | } 39 | 40 | private boolean wasDown = true; 41 | public void tick() 42 | { 43 | tick++; 44 | if (!wasDown && keys[Mario.KEY_JUMP]) 45 | { 46 | component.toTitle(); 47 | } 48 | if (keys[Mario.KEY_JUMP]) 49 | { 50 | wasDown = false; 51 | } 52 | } 53 | 54 | public float getX(float alpha) 55 | { 56 | return 0; 57 | } 58 | 59 | public float getY(float alpha) 60 | { 61 | return 0; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/LoseScene.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario; 2 | 3 | import java.awt.Color; 4 | import java.awt.Graphics; 5 | 6 | import com.mojang.mario.sprites.Mario; 7 | 8 | public class LoseScene extends Scene 9 | { 10 | private MarioComponent component; 11 | private int tick; 12 | private String scrollMessage = "Game over!"; 13 | 14 | public LoseScene(MarioComponent component) 15 | { 16 | this.component = component; 17 | } 18 | 19 | public void init() 20 | { 21 | } 22 | 23 | public void render(Graphics g, float alpha) 24 | { 25 | g.setColor(Color.decode("#a07070")); 26 | g.fillRect(0, 0, 320, 240); 27 | int f = tick/3%10; 28 | if (f>=6) f = 10-f; 29 | g.drawImage(Art.gameOver[f][0], 160-48, 100-32, null); 30 | drawString(g, scrollMessage, 160-scrollMessage.length()*4, 160, 0); 31 | } 32 | 33 | private void drawString(Graphics g, String text, int x, int y, int c) 34 | { 35 | char[] ch = text.toCharArray(); 36 | for (int i = 0; i < ch.length; i++) 37 | { 38 | g.drawImage(Art.font[ch[i] - 32][c], x + i * 8, y, null); 39 | } 40 | } 41 | 42 | private boolean wasDown = true; 43 | public void tick() 44 | { 45 | tick++; 46 | if (!wasDown && keys[Mario.KEY_JUMP]) 47 | { 48 | component.toTitle(); 49 | } 50 | if (keys[Mario.KEY_JUMP]) 51 | { 52 | wasDown = false; 53 | } 54 | } 55 | 56 | public float getX(float alpha) 57 | { 58 | return 0; 59 | } 60 | 61 | public float getY(float alpha) 62 | { 63 | return 0; 64 | } 65 | } -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2009--2018 Chris Lewis (lines of code created by c@chris.to / chris@chris.to) 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | 13 | 14 | Copyright 2014 Markus Persson: 15 | 16 | The source code for Infinite Mario Bros is PUBLIC DOMAIN. Do with it what you want. 17 | The art resources for Infinite Mario Bros is OWNED BY NINTENDO, and is probably illegal to copy without permission. 18 | -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/TitleScene.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario; 2 | 3 | import java.awt.Graphics; 4 | import java.awt.GraphicsConfiguration; 5 | 6 | import com.mojang.mario.level.BgLevelGenerator; 7 | import com.mojang.mario.level.LevelGenerator; 8 | import com.mojang.mario.sprites.Mario; 9 | 10 | public class TitleScene extends Scene 11 | { 12 | private MarioComponent component; 13 | private int tick; 14 | private BgRenderer bgLayer0; 15 | private BgRenderer bgLayer1; 16 | 17 | public TitleScene(MarioComponent component, GraphicsConfiguration gc) 18 | { 19 | this.component = component; 20 | bgLayer0 = new BgRenderer(BgLevelGenerator.createLevel(2048, 15, false, LevelGenerator.TYPE_OVERGROUND), gc, 320, 240, 1); 21 | bgLayer1 = new BgRenderer(BgLevelGenerator.createLevel(2048, 15, true, LevelGenerator.TYPE_OVERGROUND), gc, 320, 240, 2); 22 | } 23 | 24 | public void init() 25 | { 26 | Art.startMusic(4); 27 | } 28 | 29 | public void render(Graphics g, float alpha) 30 | { 31 | bgLayer0.setCam(tick+160, 0); 32 | bgLayer1.setCam(tick+160, 0); 33 | bgLayer1.render(g, tick, alpha); 34 | bgLayer0.render(g, tick, alpha); 35 | // g.setColor(Color.decode("#8080a0")); 36 | // g.fillRect(0, 0, 320, 240); 37 | int yo = 16-Math.abs((int)(Math.sin((tick+alpha)/6.0)*8)); 38 | g.drawImage(Art.logo, 0, yo, null); 39 | g.drawImage(Art.titleScreen, 0, 120, null); 40 | } 41 | 42 | @SuppressWarnings("unused") 43 | private void drawString(Graphics g, String text, int x, int y, int c) 44 | { 45 | char[] ch = text.toCharArray(); 46 | for (int i = 0; i < ch.length; i++) 47 | { 48 | g.drawImage(Art.font[ch[i] - 32][c], x + i * 8, y, null); 49 | } 50 | } 51 | 52 | 53 | private boolean wasDown = true; 54 | public void tick() 55 | { 56 | tick++; 57 | if (!wasDown && keys[Mario.KEY_JUMP]) 58 | { 59 | component.startGame(); 60 | } 61 | if (keys[Mario.KEY_JUMP]) 62 | { 63 | wasDown = false; 64 | } 65 | } 66 | 67 | public float getX(float alpha) 68 | { 69 | return 0; 70 | } 71 | 72 | public float getY(float alpha) 73 | { 74 | return 0; 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/com/mojang/sonar/mixer/Sound.java: -------------------------------------------------------------------------------- 1 | package com.mojang.sonar.mixer; 2 | 3 | import com.mojang.sonar.*; 4 | 5 | 6 | public class Sound implements Comparable 7 | { 8 | private static final double l10 = Math.log(10); 9 | 10 | private SoundProducer producer; 11 | private SoundSource source; 12 | private float volume; 13 | private float priority; 14 | 15 | private float x, y, z; 16 | private float score = 0; 17 | 18 | public float pan; 19 | public float amplitude; 20 | 21 | public Sound(SoundProducer producer, SoundSource source, float volume, float priority) 22 | { 23 | this.producer = producer; 24 | this.source = source; 25 | this.volume = volume; 26 | this.priority = priority; 27 | } 28 | 29 | public void update(SoundListener listener, float alpha) 30 | { 31 | x = source.getX(alpha)-listener.getX(alpha); 32 | y = source.getY(alpha)-listener.getY(alpha); 33 | 34 | float distSqr = x*x+y*y+z*z; 35 | float dist = (float)Math.sqrt(distSqr); 36 | 37 | float REFERENCE_DISTANCE = 1; 38 | float ROLLOFF_FACTOR = 2; 39 | 40 | // float dB = (float)(volume + (20 * (Math.log(1.0 / distSqr) / l10))); 41 | float dB = (float)(volume - 20*Math.log(1 + ROLLOFF_FACTOR*(dist-REFERENCE_DISTANCE)/REFERENCE_DISTANCE )/ l10); 42 | dB = Math.min(dB, +6); 43 | // dB = Math.max(dB, MIN_GAIN); 44 | 45 | score = dB*priority; 46 | 47 | // double angle = WMath.atan2(y, x); 48 | 49 | float p = -x/320.0f; 50 | if (p<-1) p = -1; 51 | if (p>1) p = 1; 52 | float dd = distSqr/16; 53 | if (dd>1) dd = 1; 54 | pan =(p*dd); 55 | amplitude = volume*1f; 56 | } 57 | 58 | public void read(float[] buf, int readRate) 59 | { 60 | producer.read(buf, readRate); 61 | } 62 | 63 | public void skip(int samplesToSkip, int readRate) 64 | { 65 | producer.skip(samplesToSkip, readRate); 66 | } 67 | 68 | public boolean isLive() 69 | { 70 | return producer.isLive(); 71 | } 72 | 73 | public int compareTo(Object o) 74 | { 75 | Sound s = (Sound)o; 76 | if (s.score>score) return 1; 77 | if (s.score 0) 40 | { 41 | deadTime--; 42 | 43 | if (deadTime == 0) 44 | { 45 | deadTime = 1; 46 | for (int i = 0; i < 8; i++) 47 | { 48 | world.addSprite(new Sparkle((int) (x + Math.random() * 16 - 8) + 4, (int) (y - Math.random() * 8) + 4, (float) (Math.random() * 2 - 1), (float) Math.random() * -1, 0, 1, 5)); 49 | } 50 | spriteContext.removeSprite(this); 51 | } 52 | 53 | x += xa; 54 | y += ya; 55 | ya *= 0.95; 56 | ya += 1; 57 | 58 | return; 59 | } 60 | 61 | tick++; 62 | 63 | if (y>=yStart) 64 | { 65 | y = yStart; 66 | 67 | int xd = (int)(Math.abs(world.mario.x-x)); 68 | jumpTime++; 69 | if (jumpTime>40 && xd>24) 70 | { 71 | ya = -8; 72 | } 73 | else 74 | { 75 | ya = 0; 76 | } 77 | } 78 | else 79 | { 80 | jumpTime = 0; 81 | } 82 | 83 | y+=ya; 84 | ya*=0.9; 85 | ya+=0.1f; 86 | 87 | xPic = ((tick/2)&1)*2+((tick/6)&1); 88 | } 89 | 90 | /* public void render(Graphics og, float alpha) 91 | { 92 | if (!visible) return; 93 | 94 | int xPixel = (int)(xOld+(x-xOld)*alpha)-xPicO; 95 | int yPixel = (int)(yOld+(y-yOld)*alpha)-yPicO; 96 | 97 | int a = ((tick/3)&1)*2; 98 | // a += ((tick/8)&1); 99 | og.drawImage(sheet[a*2+0][6], xPixel-8, yPixel+8, 16, 32, null); 100 | og.drawImage(sheet[a*2+1][6], xPixel+8, yPixel+8, 16, 32, null); 101 | }*/ 102 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/sonar/mixer/ListenerMixer.java: -------------------------------------------------------------------------------- 1 | package com.mojang.sonar.mixer; 2 | 3 | import java.util.*; 4 | 5 | import com.mojang.sonar.*; 6 | 7 | public class ListenerMixer implements StereoSoundProducer 8 | { 9 | private List sounds = new ArrayList(); 10 | private float[] buf = new float[0]; 11 | private int maxChannels; 12 | private SoundListener soundListener; 13 | 14 | public ListenerMixer(int maxChannels) 15 | { 16 | this.maxChannels = maxChannels; 17 | } 18 | 19 | public void setSoundListener(SoundListener soundListener) 20 | { 21 | this.soundListener = soundListener; 22 | } 23 | 24 | public void addSoundProducer(SoundProducer producer, SoundSource soundSource, float volume, float priority) 25 | { 26 | sounds.add(new Sound(producer, soundSource, volume, priority)); 27 | } 28 | 29 | public void update(float alpha) 30 | { 31 | for (Iterator it = sounds.iterator(); it.hasNext();) 32 | { 33 | Sound sound = (Sound) it.next(); 34 | sound.update(soundListener, alpha); 35 | if (!sound.isLive()) 36 | { 37 | it.remove(); 38 | } 39 | } 40 | } 41 | 42 | public float read(float[] leftBuf, float[] rightBuf, int readRate) 43 | { 44 | if (buf.length != leftBuf.length) buf = new float[leftBuf.length]; 45 | 46 | if (sounds.size() > maxChannels) 47 | { 48 | Collections.sort(sounds); 49 | } 50 | 51 | Arrays.fill(leftBuf, 0); 52 | Arrays.fill(rightBuf, 0); 53 | float maxAmplitude = 0; 54 | for (int i = 0; i < sounds.size(); i++) 55 | { 56 | Sound sound = (Sound) sounds.get(i); 57 | if (i < maxChannels) 58 | { 59 | sound.read(buf, readRate); 60 | float rp = (sound.pan<0?1:1-sound.pan)*sound.amplitude; 61 | float lp = (sound.pan>0?1:1+sound.pan)*sound.amplitude; 62 | for (int j = 0; j < leftBuf.length; j++) 63 | { 64 | leftBuf[j] += buf[j]*lp; 65 | rightBuf[j] += buf[j]*rp; 66 | if (leftBuf[j]>maxAmplitude) maxAmplitude = leftBuf[j]; 67 | if (rightBuf[j]>maxAmplitude) maxAmplitude = rightBuf[j]; 68 | } 69 | } 70 | else 71 | { 72 | sound.skip(leftBuf.length, readRate); 73 | } 74 | } 75 | 76 | return maxAmplitude; 77 | } 78 | 79 | public void skip(int samplesToSkip, int readRate) 80 | { 81 | for (int i = 0; i < sounds.size(); i++) 82 | { 83 | Sound sound = (Sound) sounds.get(i); 84 | sound.skip(samplesToSkip, readRate); 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/sprites/Sprite.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario.sprites; 2 | 3 | import java.awt.Graphics; 4 | import java.awt.Image; 5 | 6 | import com.mojang.mario.level.SpriteTemplate; 7 | import com.mojang.sonar.SoundSource; 8 | 9 | public class Sprite implements SoundSource 10 | { 11 | public static SpriteContext spriteContext; 12 | 13 | public float xOld, yOld, x, y, xa, ya; 14 | 15 | public int xPic, yPic; 16 | public int wPic = 32; 17 | public int hPic = 32; 18 | public int xPicO, yPicO; 19 | public boolean xFlipPic = false; 20 | public boolean yFlipPic = false; 21 | public Image[][] sheet; 22 | public boolean visible = true; 23 | 24 | public int layer = 1; 25 | 26 | public SpriteTemplate spriteTemplate; 27 | 28 | public void move() 29 | { 30 | x+=xa; 31 | y+=ya; 32 | } 33 | 34 | public void render(Graphics og, float alpha) 35 | { 36 | if (!visible) return; 37 | 38 | int xPixel = (int)(xOld+(x-xOld)*alpha)-xPicO; 39 | int yPixel = (int)(yOld+(y-yOld)*alpha)-yPicO; 40 | 41 | og.drawImage(sheet[xPic][yPic], xPixel+(xFlipPic?wPic:0), yPixel+(yFlipPic?hPic:0), xFlipPic?-wPic:wPic, yFlipPic?-hPic:hPic, null); 42 | } 43 | 44 | /* private void blit(Graphics og, Image bitmap, int x0, int y0, int x1, int y1, int w, int h) 45 | { 46 | if (!xFlipPic) 47 | { 48 | if (!yFlipPic) 49 | { 50 | og.drawImage(bitmap, x0, y0, x0+w, y0+h, x1, y1, x1+w, y1+h, null); 51 | } 52 | else 53 | { 54 | og.drawImage(bitmap, x0, y0, x0+w, y0+h, x1, y1+h, x1+w, y1, null); 55 | } 56 | } 57 | else 58 | { 59 | if (!yFlipPic) 60 | { 61 | og.drawImage(bitmap, x0, y0, x0+w, y0+h, x1+w, y1, x1, y1+h, null); 62 | } 63 | else 64 | { 65 | og.drawImage(bitmap, x0, y0, x0+w, y0+h, x1+w, y1+h, x1, y1, null); 66 | } 67 | } 68 | }*/ 69 | 70 | public final void tick() 71 | { 72 | xOld = x; 73 | yOld = y; 74 | move(); 75 | } 76 | 77 | public final void tickNoMove() 78 | { 79 | xOld = x; 80 | yOld = y; 81 | } 82 | 83 | public float getX(float alpha) 84 | { 85 | return (xOld+(x-xOld)*alpha)-xPicO; 86 | } 87 | 88 | public float getY(float alpha) 89 | { 90 | return (yOld+(y-yOld)*alpha)-yPicO; 91 | } 92 | 93 | public void collideCheck() 94 | { 95 | } 96 | 97 | public void bumpCheck(int xTile, int yTile) 98 | { 99 | } 100 | 101 | public boolean shellCollideCheck(Shell shell) 102 | { 103 | return false; 104 | } 105 | 106 | public void release(Mario mario) 107 | { 108 | } 109 | 110 | public boolean fireballCollideCheck(Fireball fireball) 111 | { 112 | return false; 113 | } 114 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/BgRenderer.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario; 2 | 3 | import java.awt.*; 4 | import java.util.Random; 5 | import com.mojang.mario.level.*; 6 | 7 | 8 | public class BgRenderer 9 | { 10 | private int xCam; 11 | private int yCam; 12 | private Image image; 13 | private Graphics2D g; 14 | private static final Color transparent = new Color(0, 0, 0, 0); 15 | private Level level; 16 | 17 | private Random random = new Random(); 18 | public boolean renderBehaviors = false; 19 | 20 | private int width; 21 | private int height; 22 | private int distance; 23 | 24 | public BgRenderer(Level level, GraphicsConfiguration graphicsConfiguration, int width, int height, int distance) 25 | { 26 | this.distance = distance; 27 | this.width = width; 28 | this.height = height; 29 | 30 | this.level = level; 31 | image = graphicsConfiguration.createCompatibleImage(width, height, Transparency.BITMASK); 32 | g = (Graphics2D) image.getGraphics(); 33 | g.setComposite(AlphaComposite.Src); 34 | 35 | updateArea(0, 0, width, height); 36 | } 37 | 38 | public void setCam(int xCam, int yCam) 39 | { 40 | xCam /= distance; 41 | yCam /= distance; 42 | int xCamD = this.xCam - xCam; 43 | int yCamD = this.yCam - yCam; 44 | this.xCam = xCam; 45 | this.yCam = yCam; 46 | 47 | g.setComposite(AlphaComposite.Src); 48 | g.copyArea(0, 0, width, height, xCamD, yCamD); 49 | 50 | if (xCamD < 0) 51 | { 52 | if (xCamD < -width) xCamD = -width; 53 | updateArea(width + xCamD, 0, -xCamD, height); 54 | } 55 | else if (xCamD > 0) 56 | { 57 | if (xCamD > width) xCamD = width; 58 | updateArea(0, 0, xCamD, height); 59 | } 60 | 61 | if (yCamD < 0) 62 | { 63 | if (yCamD < -width) yCamD = -width; 64 | updateArea(0, height + yCamD, width, -yCamD); 65 | } 66 | else if (yCamD > 0) 67 | { 68 | if (yCamD > width) yCamD = width; 69 | updateArea(0, 0, width, yCamD); 70 | } 71 | } 72 | 73 | private void updateArea(int x0, int y0, int w, int h) 74 | { 75 | g.setBackground(transparent); 76 | g.clearRect(x0, y0, w, h); 77 | int xTileStart = (x0 + xCam) / 32; 78 | int yTileStart = (y0 + yCam) / 32; 79 | int xTileEnd = (x0 + xCam + w) / 32; 80 | int yTileEnd = (y0 + yCam + h) / 32; 81 | for (int x = xTileStart; x <= xTileEnd; x++) 82 | { 83 | for (int y = yTileStart; y <= yTileEnd; y++) 84 | { 85 | int b = level.getBlock(x, y) & 0xff; 86 | g.drawImage(Art.bg[b % 8][b / 8], (x << 5) - xCam, (y << 5) - yCam-16, null); 87 | } 88 | } 89 | } 90 | 91 | public void render(Graphics g, int tick, float alpha) 92 | { 93 | g.drawImage(image, 0, 0, null); 94 | } 95 | 96 | public void setLevel(Level level) 97 | { 98 | this.level = level; 99 | updateArea(0, 0, width, height); 100 | } 101 | 102 | public void setRandom(Random random) { 103 | this.random = random; 104 | } 105 | 106 | public Random getRandom() { 107 | return random; 108 | } 109 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/mapedit/TilePicker.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario.mapedit; 2 | 3 | import java.awt.Color; 4 | import java.awt.Dimension; 5 | import java.awt.Graphics; 6 | import java.awt.event.MouseEvent; 7 | import java.awt.event.MouseListener; 8 | import java.awt.event.MouseMotionListener; 9 | 10 | import javax.swing.*; 11 | import com.mojang.mario.*; 12 | 13 | 14 | public class TilePicker extends JComponent implements MouseListener, MouseMotionListener 15 | { 16 | private static final long serialVersionUID = -7696446733303717142L; 17 | 18 | private int xTile = -1; 19 | private int yTile = -1; 20 | 21 | public byte pickedTile; 22 | 23 | @SuppressWarnings("unused") 24 | private byte paint = 0; 25 | private LevelEditor tilePickChangedListener; 26 | 27 | public TilePicker() 28 | { 29 | Dimension size = new Dimension(256, 256); 30 | setPreferredSize(size); 31 | setMinimumSize(size); 32 | setMaximumSize(size); 33 | 34 | addMouseListener(this); 35 | addMouseMotionListener(this); 36 | } 37 | 38 | public void addNotify() 39 | { 40 | super.addNotify(); 41 | Art.init(getGraphicsConfiguration(), null); 42 | } 43 | 44 | public void paintComponent(Graphics g) 45 | { 46 | g.setColor(new Color(0x8090ff)); 47 | g.fillRect(0, 0, 256, 256); 48 | 49 | for (int x=0; x<16; x++) 50 | for (int y=0; y<16; y++) 51 | { 52 | g.drawImage(Art.level[x][y], (x << 4), (y << 4), null); 53 | } 54 | 55 | g.setColor(Color.WHITE); 56 | int xPickedTile = (pickedTile&0xff)%16; 57 | int yPickedTile = (pickedTile&0xff)/16; 58 | g.drawRect(xPickedTile * 16, yPickedTile * 16, 15, 15); 59 | 60 | g.setColor(Color.BLACK); 61 | g.drawRect(xTile * 16 - 1, yTile * 16 - 1, 17, 17); 62 | } 63 | 64 | public void mouseClicked(MouseEvent e) 65 | { 66 | } 67 | 68 | public void mouseEntered(MouseEvent e) 69 | { 70 | } 71 | 72 | public void mouseExited(MouseEvent e) 73 | { 74 | xTile = -1; 75 | yTile = -1; 76 | repaint(); 77 | } 78 | 79 | public void mousePressed(MouseEvent e) 80 | { 81 | xTile = e.getX() / 16; 82 | yTile = e.getY() / 16; 83 | 84 | setPickedTile((byte)(xTile+yTile*16)); 85 | repaint(); 86 | } 87 | 88 | public void mouseReleased(MouseEvent e) 89 | { 90 | } 91 | 92 | public void mouseDragged(MouseEvent e) 93 | { 94 | xTile = e.getX() / 16; 95 | yTile = e.getY() / 16; 96 | 97 | repaint(); 98 | } 99 | 100 | public void mouseMoved(MouseEvent e) 101 | { 102 | xTile = e.getX() / 16; 103 | yTile = e.getY() / 16; 104 | repaint(); 105 | } 106 | 107 | public void setPickedTile(byte block) 108 | { 109 | pickedTile = block; 110 | repaint(); 111 | if (tilePickChangedListener!=null) 112 | tilePickChangedListener.setPickedTile(pickedTile); 113 | } 114 | 115 | public void addTilePickChangedListener(LevelEditor editor) 116 | { 117 | this.tilePickChangedListener = editor; 118 | if (tilePickChangedListener!=null) 119 | tilePickChangedListener.setPickedTile(pickedTile); 120 | } 121 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/mapedit/LevelEditView.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario.mapedit; 2 | 3 | import java.awt.Color; 4 | import java.awt.Dimension; 5 | import java.awt.Graphics; 6 | import java.awt.event.MouseEvent; 7 | import java.awt.event.MouseListener; 8 | import java.awt.event.MouseMotionListener; 9 | 10 | import javax.swing.*; 11 | import com.mojang.mario.*; 12 | import com.mojang.mario.level.*; 13 | 14 | 15 | public class LevelEditView extends JComponent implements MouseListener, MouseMotionListener 16 | { 17 | private static final long serialVersionUID = -7696446733303717142L; 18 | 19 | private LevelRenderer levelRenderer; 20 | private Level level; 21 | 22 | private int xTile = -1; 23 | private int yTile = -1; 24 | private TilePicker tilePicker; 25 | 26 | public LevelEditView(TilePicker tilePicker) 27 | { 28 | this.tilePicker = tilePicker; 29 | level = new Level(256, 15); 30 | Dimension size = new Dimension(level.width * 16, level.height * 16); 31 | setPreferredSize(size); 32 | setMinimumSize(size); 33 | setMaximumSize(size); 34 | 35 | addMouseListener(this); 36 | addMouseMotionListener(this); 37 | } 38 | 39 | public void setLevel(Level level) 40 | { 41 | this.level = level; 42 | Dimension size = new Dimension(level.width * 16, level.height * 16); 43 | setPreferredSize(size); 44 | setMinimumSize(size); 45 | setMaximumSize(size); 46 | repaint(); 47 | levelRenderer.setLevel(level); 48 | } 49 | 50 | public Level getLevel() 51 | { 52 | return level; 53 | } 54 | 55 | public void addNotify() 56 | { 57 | super.addNotify(); 58 | Art.init(getGraphicsConfiguration(), null); 59 | levelRenderer = new LevelRenderer(level, getGraphicsConfiguration(), level.width * 16, level.height * 16); 60 | levelRenderer.renderBehaviors = true; 61 | } 62 | 63 | public void paintComponent(Graphics g) 64 | { 65 | g.setColor(new Color(0x8090ff)); 66 | g.fillRect(0, 0, level.width * 16, level.height * 16); 67 | levelRenderer.render(g, 0, 0); 68 | g.setColor(Color.BLACK); 69 | g.drawRect(xTile * 16 - 1, yTile * 16 - 1, 17, 17); 70 | } 71 | 72 | public void mouseClicked(MouseEvent e) 73 | { 74 | } 75 | 76 | public void mouseEntered(MouseEvent e) 77 | { 78 | } 79 | 80 | public void mouseExited(MouseEvent e) 81 | { 82 | xTile = -1; 83 | yTile = -1; 84 | repaint(); 85 | } 86 | 87 | public void mousePressed(MouseEvent e) 88 | { 89 | xTile = e.getX() / 16; 90 | yTile = e.getY() / 16; 91 | 92 | if (e.getButton() == 3) 93 | { 94 | tilePicker.setPickedTile(level.getBlock(xTile, yTile)); 95 | } 96 | else 97 | { 98 | level.setBlock(xTile, yTile, tilePicker.pickedTile); 99 | levelRenderer.repaint(xTile - 1, yTile - 1, 3, 3); 100 | 101 | repaint(); 102 | } 103 | } 104 | 105 | public void mouseReleased(MouseEvent e) 106 | { 107 | } 108 | 109 | public void mouseDragged(MouseEvent e) 110 | { 111 | xTile = e.getX() / 16; 112 | yTile = e.getY() / 16; 113 | 114 | level.setBlock(xTile, yTile, tilePicker.pickedTile); 115 | levelRenderer.repaint(xTile - 1, yTile - 1, 3, 3); 116 | 117 | repaint(); 118 | } 119 | 120 | public void mouseMoved(MouseEvent e) 121 | { 122 | xTile = e.getX() / 16; 123 | yTile = e.getY() / 16; 124 | repaint(); 125 | } 126 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/level/ImprovedNoise.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario.level; 2 | 3 | import java.util.*; 4 | 5 | public final class ImprovedNoise 6 | { 7 | public ImprovedNoise(long seed) 8 | { 9 | shuffle(seed); 10 | } 11 | 12 | public double noise(double x, double y, double z) 13 | { 14 | int X = (int) Math.floor(x) & 255, // FIND UNIT CUBE THAT 15 | Y = (int) Math.floor(y) & 255, // CONTAINS POINT. 16 | Z = (int) Math.floor(z) & 255; 17 | x -= Math.floor(x); // FIND RELATIVE X,Y,Z 18 | y -= Math.floor(y); // OF POINT IN CUBE. 19 | z -= Math.floor(z); 20 | double u = fade(x), // COMPUTE FADE CURVES 21 | v = fade(y), // FOR EACH OF X,Y,Z. 22 | w = fade(z); 23 | int A = p[X] + Y, AA = p[A] + Z, AB = p[A + 1] + Z, // HASH COORDINATES OF 24 | B = p[X + 1] + Y, BA = p[B] + Z, BB = p[B + 1] + Z; // THE 8 CUBE CORNERS, 25 | 26 | return lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, z), // AND ADD 27 | grad(p[BA], x - 1, y, z)), // BLENDED 28 | lerp(u, grad(p[AB], x, y - 1, z), // RESULTS 29 | grad(p[BB], x - 1, y - 1, z))),// FROM 8 30 | lerp(v, lerp(u, grad(p[AA + 1], x, y, z - 1), // CORNERS 31 | grad(p[BA + 1], x - 1, y, z - 1)), // OF CUBE 32 | lerp(u, grad(p[AB + 1], x, y - 1, z - 1), grad(p[BB + 1], x - 1, y - 1, z - 1)))); 33 | } 34 | 35 | double fade(double t) 36 | { 37 | return t * t * t * (t * (t * 6 - 15) + 10); 38 | } 39 | 40 | double lerp(double t, double a, double b) 41 | { 42 | return a + t * (b - a); 43 | } 44 | 45 | double grad(int hash, double x, double y, double z) 46 | { 47 | int h = hash & 15; // CONVERT LO 4 BITS OF HASH CODE 48 | double u = h < 8 ? x : y, // INTO 12 GRADIENT DIRECTIONS. 49 | v = h < 4 ? y : h == 12 || h == 14 ? x : z; 50 | return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v); 51 | } 52 | 53 | int p[] = new int[512];//, permutation[] = {151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180}; 54 | 55 | public double perlinNoise(double x, double y) 56 | { 57 | double n = 0; 58 | 59 | for (int i = 0; i < 8; i++) 60 | { 61 | double stepSize = 64.0 / ((1 << i)); 62 | n += noise(x / stepSize, y / stepSize, 128) * 1.0 / (1 << i); 63 | } 64 | 65 | return n; 66 | } 67 | 68 | public void shuffle(long seed) 69 | { 70 | Random random = new Random(seed); 71 | int permutation[] = new int[256]; 72 | for (int i=0; i<256; i++) 73 | { 74 | permutation[i] = i; 75 | } 76 | 77 | for (int i=0; i<256; i++) 78 | { 79 | int j = random.nextInt(256-i)+i; 80 | int tmp = permutation[i]; 81 | permutation[i] = permutation[j]; 82 | permutation[j] = tmp; 83 | p[i+256] = p[i] = permutation[i]; 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/sprites/BulletBill.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario.sprites; 2 | 3 | import com.mojang.mario.Art; 4 | import com.mojang.mario.LevelScene; 5 | 6 | 7 | public class BulletBill extends Sprite 8 | { 9 | @SuppressWarnings("unused") 10 | private int width = 4; 11 | int height = 24; 12 | 13 | private LevelScene world; 14 | public int facing; 15 | 16 | public boolean avoidCliffs = false; 17 | public int anim; 18 | 19 | public boolean dead = false; 20 | private int deadTime = 0; 21 | 22 | 23 | public BulletBill(LevelScene world, float x, float y, int dir) 24 | { 25 | sheet = Art.enemies; 26 | 27 | this.x = x; 28 | this.y = y; 29 | this.world = world; 30 | xPicO = 8; 31 | yPicO = 31; 32 | 33 | height = 12; 34 | facing = 0; 35 | wPic = 16; 36 | yPic = 5; 37 | 38 | xPic = 0; 39 | ya = -5; 40 | this.facing = dir; 41 | } 42 | 43 | public void collideCheck() 44 | { 45 | if (dead) return; 46 | 47 | float xMarioD = world.mario.x - x; 48 | float yMarioD = world.mario.y - y; 49 | float w = 16; 50 | if (xMarioD > -w && xMarioD < w) 51 | { 52 | if (yMarioD > -height && yMarioD < world.mario.height) 53 | { 54 | if (world.mario.ya > 0 && yMarioD <= 0 && (!world.mario.onGround || !world.mario.wasOnGround)) 55 | { 56 | world.mario.stomp(this); 57 | dead = true; 58 | 59 | xa = 0; 60 | ya = 1; 61 | deadTime = 100; 62 | } 63 | else 64 | { 65 | world.mario.getHurt(); 66 | } 67 | } 68 | } 69 | } 70 | 71 | public void move() 72 | { 73 | if (deadTime > 0) 74 | { 75 | deadTime--; 76 | 77 | if (deadTime == 0) 78 | { 79 | deadTime = 1; 80 | for (int i = 0; i < 8; i++) 81 | { 82 | world.addSprite(new Sparkle((int) (x + Math.random() * 16 - 8) + 4, (int) (y - Math.random() * 8) + 4, (float) (Math.random() * 2 - 1), (float) Math.random() * -1, 0, 1, 5)); 83 | } 84 | spriteContext.removeSprite(this); 85 | } 86 | 87 | x += xa; 88 | y += ya; 89 | ya *= 0.95; 90 | ya += 1; 91 | 92 | return; 93 | } 94 | 95 | float sideWaysSpeed = 4f; 96 | 97 | xa = facing * sideWaysSpeed; 98 | xFlipPic = facing == -1; 99 | move(xa, 0); 100 | } 101 | 102 | private boolean move(float xa, float ya) 103 | { 104 | x += xa; 105 | return true; 106 | } 107 | 108 | public boolean fireballCollideCheck(Fireball fireball) 109 | { 110 | if (deadTime != 0) return false; 111 | 112 | float xD = fireball.x - x; 113 | float yD = fireball.y - y; 114 | 115 | if (xD > -16 && xD < 16) 116 | { 117 | if (yD > -height && yD < fireball.height) 118 | { 119 | return true; 120 | } 121 | } 122 | return false; 123 | } 124 | 125 | public boolean shellCollideCheck(Shell shell) 126 | { 127 | if (deadTime != 0) return false; 128 | 129 | float xD = shell.x - x; 130 | float yD = shell.y - y; 131 | 132 | if (xD > -16 && xD < 16) 133 | { 134 | if (yD > -height && yD < shell.height) 135 | { 136 | world.sound.play(Art.samples[Art.SAMPLE_MARIO_KICK], this, 1, 1, 1); 137 | 138 | dead = true; 139 | 140 | xa = 0; 141 | ya = 1; 142 | deadTime = 100; 143 | 144 | return true; 145 | } 146 | } 147 | return false; 148 | } 149 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/sonar/sample/SampleLoader.java: -------------------------------------------------------------------------------- 1 | package com.mojang.sonar.sample; 2 | 3 | import java.io.*; 4 | import java.nio.ByteBuffer; 5 | import java.nio.ByteOrder; 6 | 7 | import javax.sound.sampled.*; 8 | 9 | public class SampleLoader 10 | { 11 | /** 12 | * Loads a sample from an url 13 | */ 14 | public static SonarSample loadSample(String resourceName) throws UnsupportedAudioFileException, IOException 15 | { 16 | // Hack to prevent "mark/reset not supported" on some systems 17 | byte[] d = rip(SampleLoader.class.getResourceAsStream(resourceName)); 18 | AudioInputStream ais = AudioSystem.getAudioInputStream(new ByteArrayInputStream(d)); 19 | return buildSample(rip(ais), ais.getFormat()); 20 | } 21 | 22 | /** 23 | * Rips the entire contents of an inputstream into a byte array 24 | */ 25 | private static byte[] rip(InputStream in) throws IOException 26 | { 27 | ByteArrayOutputStream bos = new ByteArrayOutputStream(); 28 | byte[] b = new byte[4096]; 29 | 30 | int read = 0; 31 | while ((read = in.read(b)) > 0) 32 | { 33 | bos.write(b, 0, read); 34 | } 35 | 36 | bos.close(); 37 | return bos.toByteArray(); 38 | } 39 | 40 | /** 41 | * Reorganizes audio sample data into the intenal sonar format 42 | */ 43 | private static SonarSample buildSample(byte[] b, AudioFormat af) throws UnsupportedAudioFileException 44 | { 45 | // Rip audioformat data 46 | int channels = af.getChannels(); 47 | int sampleSize = af.getSampleSizeInBits(); 48 | float rate = af.getFrameRate(); 49 | boolean signed = af.getEncoding() == AudioFormat.Encoding.PCM_SIGNED; 50 | 51 | // Sanity checking 52 | if (channels != 1) throw new UnsupportedAudioFileException("Only mono samples are supported"); 53 | if (!(sampleSize == 8 || sampleSize == 16 || sampleSize == 32)) throw new UnsupportedAudioFileException("Unsupported sample size"); 54 | if (!(af.getEncoding() == AudioFormat.Encoding.PCM_UNSIGNED || af.getEncoding() == AudioFormat.Encoding.PCM_SIGNED)) throw new UnsupportedAudioFileException("Unsupported encoding"); 55 | 56 | // Wrap the data into a bytebuffer, and set up the byte order 57 | ByteBuffer bb = ByteBuffer.wrap(b); 58 | bb.order(af.isBigEndian() ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN); 59 | 60 | int s = b.length / (sampleSize / 8); 61 | float[] buf = new float[s]; 62 | // Six different cases for reordering the data. Can this be improved without slowing it down? 63 | if (sampleSize == 8) 64 | { 65 | if (signed) 66 | { 67 | for (int i = 0; i < s; i++) 68 | buf[i] = bb.get() / (float)0x80; 69 | } 70 | else 71 | { 72 | for (int i = 0; i < s; i++) 73 | buf[i] = ((bb.get()&0xFF)-0x80) / (float)0x80; 74 | } 75 | } 76 | else if (sampleSize == 16) 77 | { 78 | if (signed) 79 | { 80 | for (int i = 0; i < s; i++) 81 | buf[i] = bb.getShort() / (float)0x8000; 82 | } 83 | else 84 | { 85 | for (int i = 0; i < s; i++) 86 | buf[i] = ((bb.getShort()&0xFFFF)-0x8000) / (float)0x8000; 87 | } 88 | } 89 | else if (sampleSize == 32) 90 | { 91 | if (signed) 92 | { 93 | for (int i = 0; i < s; i++) 94 | buf[i] = bb.getInt() / (float)0x80000000; 95 | } 96 | else 97 | { 98 | // Nasty.. check this. 99 | for (int i = 0; i < s; i++) 100 | buf[i] = ((bb.getInt()&0xFFFFFFFFl)-0x80000000l) / (float)0x80000000; 101 | } 102 | } 103 | 104 | // Return the completed sample 105 | return new SonarSample(buf, rate); 106 | } 107 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/sonar/SonarSoundEngine.java: -------------------------------------------------------------------------------- 1 | package com.mojang.sonar; 2 | 3 | import java.nio.ByteBuffer; 4 | import java.nio.ByteOrder; 5 | 6 | import javax.sound.sampled.*; 7 | 8 | import com.mojang.sonar.mixer.ListenerMixer; 9 | import com.mojang.sonar.sample.*; 10 | 11 | 12 | public class SonarSoundEngine implements Runnable 13 | { 14 | private SonarSample silentSample; 15 | private SourceDataLine sdl; 16 | private int rate = 44100; 17 | private ListenerMixer listenerMixer; 18 | private int bufferSize = rate / 100; // 10 ms 19 | private ByteBuffer soundBuffer = ByteBuffer.allocate(bufferSize * 4); 20 | private float[] leftBuf, rightBuf; 21 | @SuppressWarnings("unused") 22 | private float amplitude = 1; 23 | @SuppressWarnings("unused") 24 | private float targetAmplitude = 1; 25 | private boolean alive = true; 26 | 27 | protected SonarSoundEngine() 28 | { 29 | } 30 | 31 | public SonarSoundEngine(int maxChannels) throws LineUnavailableException 32 | { 33 | silentSample = new SonarSample(new float[] {0}, 44100); 34 | Mixer mixer = AudioSystem.getMixer(null); 35 | 36 | sdl = (SourceDataLine) mixer.getLine(new Line.Info(SourceDataLine.class)); 37 | sdl.open(new AudioFormat(rate, 16, 2, true, false), bufferSize * 2 * 2 * 2 * 2 * 2); 38 | soundBuffer.order(ByteOrder.LITTLE_ENDIAN); 39 | sdl.start(); 40 | 41 | try 42 | { 43 | /* FloatControl volumeControl = (FloatControl) sdl.getControl(FloatControl.Type.MASTER_GAIN); 44 | volumeControl.setValue(volumeControl.getMaximum());*/ 45 | } 46 | catch (IllegalArgumentException e) 47 | { 48 | System.out.println("Failed to set the sound volume"); 49 | } 50 | 51 | listenerMixer = new ListenerMixer(maxChannels); 52 | 53 | leftBuf = new float[bufferSize]; 54 | rightBuf = new float[bufferSize]; 55 | 56 | Thread thread = new Thread(this); 57 | thread.setDaemon(true); 58 | thread.setPriority(10); 59 | thread.start(); 60 | } 61 | 62 | public void setListener(SoundListener soundListener) 63 | { 64 | listenerMixer.setSoundListener(soundListener); 65 | } 66 | 67 | public void shutDown() 68 | { 69 | alive = false; 70 | } 71 | 72 | public SonarSample loadSample(String resourceName) 73 | { 74 | try 75 | { 76 | return SampleLoader.loadSample(resourceName); 77 | } 78 | catch (Exception e) 79 | { 80 | System.out.println("Failed to load sample " + resourceName + ". Using silent sample"); 81 | e.printStackTrace(); 82 | return silentSample; 83 | } 84 | } 85 | 86 | public void play(SonarSample sample, SoundSource soundSource, float volume, float priority, float rate) 87 | { 88 | synchronized (listenerMixer) 89 | { 90 | listenerMixer.addSoundProducer(new SamplePlayer((SonarSample) sample, rate), soundSource, volume, priority); 91 | } 92 | } 93 | 94 | public void clientTick(float alpha) 95 | { 96 | synchronized (listenerMixer) 97 | { 98 | listenerMixer.update(alpha); 99 | } 100 | } 101 | 102 | public void tick() 103 | { 104 | soundBuffer.clear(); 105 | 106 | // targetAmplitude = (targetAmplitude - 1) * 0.9f + 1; 107 | // targetAmplitude = (targetAmplitude - 1) * 0.9f + 1; 108 | synchronized (listenerMixer) 109 | { 110 | @SuppressWarnings("unused") 111 | float maxAmplitude = listenerMixer.read(leftBuf, rightBuf, rate); 112 | // if (maxAmplitude > targetAmplitude) targetAmplitude = maxAmplitude; 113 | } 114 | 115 | soundBuffer.clear(); 116 | float gain = 32000; 117 | for (int i = 0; i < bufferSize; i++) 118 | { 119 | // amplitude += (targetAmplitude - amplitude) / rate; 120 | // amplitude = 1; 121 | // float gain = 30000; 122 | int l = (int) (leftBuf[i] * gain); 123 | int r = (int) (rightBuf[i] * gain); 124 | if (l > 32767) l = 32767; 125 | if (r > 32767) r = 32767; 126 | if (l < -32767) l = -32767; 127 | if (r < -32767) r = -32767; 128 | soundBuffer.putShort((short)l); 129 | soundBuffer.putShort((short)r); 130 | } 131 | 132 | sdl.write(soundBuffer.array(), 0, bufferSize * 2 * 2); 133 | } 134 | 135 | public void run() 136 | { 137 | while (alive) 138 | { 139 | tick(); 140 | } 141 | } 142 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/Scale2x.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Scale2x.java 3 | * 4 | * Written by Markus Persson of Mojang Specifications for a super mario programming contest. 5 | * Implements the Scale2x algorithm described here: http://scale2x.sourceforge.net/algorithm.html 6 | * Works on any input image size, and uses a fancy border hack to prevent range checking. 7 | * It's fast enough for real time use on smaller images (320x240 and thereabouts) 8 | * 9 | * This code is public domain. Do whatever you want with it. 10 | */ 11 | package com.mojang.mario; 12 | 13 | import java.awt.Graphics; 14 | import java.awt.Image; 15 | import java.awt.image.BufferedImage; 16 | import java.awt.image.DataBufferInt; 17 | 18 | 19 | public class Scale2x 20 | { 21 | private int width; 22 | private int height; 23 | 24 | private BufferedImage sourceImage; 25 | private int[] sourcePixels; 26 | private Graphics sourceGraphics; 27 | 28 | private BufferedImage targetImage; 29 | private int[] targetPixels; 30 | 31 | /** 32 | * Creates a new Scale2x object. The new object will scale images of the specified size to images 33 | * that are twice as large.
34 | * 35 | * @param width The width of the images to be scaled 36 | * @param height The height of the images to be scaled 37 | */ 38 | public Scale2x(int width, int height) 39 | { 40 | this.width = width; 41 | this.height = height; 42 | 43 | // A border of one pixel in each direction, and one down, to avoid if statements in the scale loop 44 | sourceImage = new BufferedImage(width + 2, height + 3, BufferedImage.TYPE_INT_RGB); 45 | DataBufferInt sourceDataBuffer = (DataBufferInt) sourceImage.getRaster().getDataBuffer(); 46 | sourcePixels = sourceDataBuffer.getData(); 47 | sourceGraphics = sourceImage.getGraphics(); 48 | 49 | targetImage = new BufferedImage(width * 2, height * 2, BufferedImage.TYPE_INT_RGB); 50 | DataBufferInt targetDataBuffer = (DataBufferInt) targetImage.getRaster().getDataBuffer(); 51 | targetPixels = targetDataBuffer.getData(); 52 | } 53 | 54 | /** 55 | * Scales an image and returns a twice as large image.
56 | * This assumes the input image is of the dimensions specified in the Scale2x constructor.
57 | * The returned image is a reference to the internal scale target in this Scale2x, so it 58 | * will get changed if you call this method again, so don't hold on to it for too long.
59 | * In other words:
60 | * Image i0 = scale2x.scale(image0);
61 | * Image i1 = scale2x.scale(image1);
62 | * if (i0 == i1) System.exit(0); // Will always terminate

63 | * 64 | * @param img The image to be scaled 65 | * @returns A scaled image. If you want that image to survive the next call to this method, make a copy of it. 66 | */ 67 | @SuppressWarnings("unused") 68 | public Image scale(Image img) 69 | { 70 | // Offset the image by one pixel so there's a border around it. 71 | // This lets us avoid having to check that A-I are in range of the image before samping them 72 | sourceGraphics.drawImage(img, 1, 1, null); 73 | 74 | int line = width + 2; 75 | for (int y = 0; y < height; y++) 76 | { 77 | // Two lines of target pixel pointers 78 | int tp0 = y * width * 4 - 1; 79 | int tp1 = tp0 + width * 2; 80 | 81 | // Three lines of source pixel pointers 82 | int sp0 = (y) * line; 83 | int sp1 = (y + 1) * line; 84 | int sp2 = (y + 2) * line; 85 | 86 | // Fill the initial A-I values 87 | int A = sourcePixels[sp0]; 88 | int B = sourcePixels[++sp0]; 89 | int C = sourcePixels[++sp0]; 90 | int D = sourcePixels[sp1]; 91 | int E = sourcePixels[++sp1]; 92 | int F = sourcePixels[++sp1]; 93 | int G = sourcePixels[sp2]; 94 | int H = sourcePixels[++sp2]; 95 | int I = sourcePixels[++sp2]; 96 | 97 | for (int x = 0; x < width; x++) 98 | { 99 | if (B != H && D != F) 100 | { 101 | targetPixels[++tp0] = D == B ? D : E; 102 | targetPixels[++tp0] = B == F ? F : E; 103 | targetPixels[++tp1] = D == H ? D : E; 104 | targetPixels[++tp1] = H == F ? F : E; 105 | } 106 | else 107 | { 108 | targetPixels[++tp0] = E; 109 | targetPixels[++tp0] = E; 110 | targetPixels[++tp1] = E; 111 | targetPixels[++tp1] = E; 112 | } 113 | 114 | // Scroll A-I left 115 | A = B; 116 | B = C; 117 | D = E; 118 | E = F; 119 | G = H; 120 | H = I; 121 | 122 | // Resample rightmost edge 123 | C = sourcePixels[++sp0]; 124 | F = sourcePixels[++sp1]; 125 | I = sourcePixels[++sp2]; 126 | } 127 | } 128 | 129 | return targetImage; 130 | } 131 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/level/Level.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario.level; 2 | 3 | import java.io.*; 4 | 5 | 6 | public class Level 7 | { 8 | public static final String[] BIT_DESCRIPTIONS = {// 9 | "BLOCK UPPER", // 10 | "BLOCK ALL", // 11 | "BLOCK LOWER", // 12 | "SPECIAL", // 13 | "BUMPABLE", // 14 | "BREAKABLE", // 15 | "PICKUPABLE", // 16 | "ANIMATED",// 17 | }; 18 | 19 | public static byte[] TILE_BEHAVIORS = new byte[256]; 20 | 21 | public static final int BIT_BLOCK_UPPER = 1 << 0; 22 | public static final int BIT_BLOCK_ALL = 1 << 1; 23 | public static final int BIT_BLOCK_LOWER = 1 << 2; 24 | public static final int BIT_SPECIAL = 1 << 3; 25 | public static final int BIT_BUMPABLE = 1 << 4; 26 | public static final int BIT_BREAKABLE = 1 << 5; 27 | public static final int BIT_PICKUPABLE = 1 << 6; 28 | public static final int BIT_ANIMATED = 1 << 7; 29 | 30 | private static final int FILE_HEADER = 0x271c4178; 31 | public int width; 32 | public int height; 33 | 34 | public byte[][] map; 35 | public byte[][] data; 36 | 37 | public SpriteTemplate[][] spriteTemplates; 38 | 39 | public int xExit; 40 | public int yExit; 41 | 42 | public Level(int width, int height) 43 | { 44 | this.width = width; 45 | this.height = height; 46 | 47 | xExit = 10; 48 | yExit = 10; 49 | map = new byte[width][height]; 50 | data = new byte[width][height]; 51 | spriteTemplates = new SpriteTemplate[width][height]; 52 | } 53 | 54 | public static void loadBehaviors(DataInputStream dis) throws IOException 55 | { 56 | dis.readFully(Level.TILE_BEHAVIORS); 57 | } 58 | 59 | public static void saveBehaviors(DataOutputStream dos) throws IOException 60 | { 61 | dos.write(Level.TILE_BEHAVIORS); 62 | } 63 | 64 | public static Level load(DataInputStream dis) throws IOException 65 | { 66 | long header = dis.readLong(); 67 | if (header != Level.FILE_HEADER) throw new IOException("Bad level header"); 68 | @SuppressWarnings("unused") 69 | int version = dis.read() & 0xff; 70 | 71 | int width = dis.readShort() & 0xffff; 72 | int height = dis.readShort() & 0xffff; 73 | Level level = new Level(width, height); 74 | level.map = new byte[width][height]; 75 | level.data = new byte[width][height]; 76 | for (int i = 0; i < width; i++) 77 | { 78 | dis.readFully(level.map[i]); 79 | dis.readFully(level.data[i]); 80 | } 81 | return level; 82 | } 83 | 84 | public void save(DataOutputStream dos) throws IOException 85 | { 86 | dos.writeLong(Level.FILE_HEADER); 87 | dos.write((byte) 0); 88 | 89 | dos.writeShort((short) width); 90 | dos.writeShort((short) height); 91 | 92 | for (int i = 0; i < width; i++) 93 | { 94 | dos.write(map[i]); 95 | dos.write(data[i]); 96 | } 97 | } 98 | 99 | public void tick() 100 | { 101 | for (int x = 0; x < width; x++) 102 | { 103 | for (int y = 0; y < height; y++) 104 | { 105 | if (data[x][y] > 0) data[x][y]--; 106 | } 107 | } 108 | } 109 | 110 | public byte getBlockCapped(int x, int y) 111 | { 112 | if (x < 0) x = 0; 113 | if (y < 0) y = 0; 114 | if (x >= width) x = width - 1; 115 | if (y >= height) y = height - 1; 116 | return map[x][y]; 117 | } 118 | 119 | public byte getBlock(int x, int y) 120 | { 121 | if (x < 0) x = 0; 122 | if (y < 0) return 0; 123 | if (x >= width) x = width - 1; 124 | if (y >= height) y = height - 1; 125 | return map[x][y]; 126 | } 127 | 128 | public void setBlock(int x, int y, byte b) 129 | { 130 | if (x < 0) return; 131 | if (y < 0) return; 132 | if (x >= width) return; 133 | if (y >= height) return; 134 | map[x][y] = b; 135 | } 136 | 137 | public void setBlockData(int x, int y, byte b) 138 | { 139 | if (x < 0) return; 140 | if (y < 0) return; 141 | if (x >= width) return; 142 | if (y >= height) return; 143 | data[x][y] = b; 144 | } 145 | 146 | public boolean isBlocking(int x, int y, float xa, float ya) 147 | { 148 | byte block = getBlock(x, y); 149 | boolean blocking = ((TILE_BEHAVIORS[block & 0xff]) & BIT_BLOCK_ALL) > 0; 150 | blocking |= (ya > 0) && ((TILE_BEHAVIORS[block & 0xff]) & BIT_BLOCK_UPPER) > 0; 151 | blocking |= (ya < 0) && ((TILE_BEHAVIORS[block & 0xff]) & BIT_BLOCK_LOWER) > 0; 152 | 153 | return blocking; 154 | } 155 | 156 | public SpriteTemplate getSpriteTemplate(int x, int y) 157 | { 158 | if (x < 0) return null; 159 | if (y < 0) return null; 160 | if (x >= width) return null; 161 | if (y >= height) return null; 162 | return spriteTemplates[x][y]; 163 | } 164 | 165 | public void setSpriteTemplate(int x, int y, SpriteTemplate spriteTemplate) 166 | { 167 | if (x < 0) return; 168 | if (y < 0) return; 169 | if (x >= width) return; 170 | if (y >= height) return; 171 | spriteTemplates[x][y] = spriteTemplate; 172 | } 173 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/mapedit/LevelEditor.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario.mapedit; 2 | 3 | import java.awt.*; 4 | import java.awt.event.ActionEvent; 5 | import java.awt.event.ActionListener; 6 | import java.io.*; 7 | 8 | import javax.swing.*; 9 | import javax.swing.border.*; 10 | 11 | import com.mojang.mario.level.*; 12 | 13 | 14 | public class LevelEditor extends JFrame implements ActionListener 15 | { 16 | private static final long serialVersionUID = 7461321112832160393L; 17 | 18 | private JButton loadButton; 19 | private JButton saveButton; 20 | private JTextField nameField; 21 | private LevelEditView levelEditView; 22 | private TilePicker tilePicker; 23 | 24 | private JCheckBox[] bitmapCheckboxes = new JCheckBox[8]; 25 | 26 | public LevelEditor() 27 | { 28 | super("Map Edit"); 29 | 30 | try 31 | { 32 | Level.loadBehaviors(new DataInputStream(new FileInputStream("tiles.dat"))); 33 | } 34 | catch (Exception e) 35 | { 36 | e.printStackTrace(); 37 | JOptionPane.showMessageDialog(this, e.toString(), "Failed to load tile behaviors", JOptionPane.ERROR_MESSAGE); 38 | } 39 | 40 | Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); 41 | setSize(screenSize.width * 8 / 10, screenSize.height * 8 / 10); 42 | setLocation((screenSize.width - getWidth()) / 2, (screenSize.height - getHeight()) / 2); 43 | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 44 | 45 | tilePicker = new TilePicker(); 46 | JPanel tilePickerPanel = new JPanel(new BorderLayout()); 47 | tilePickerPanel.add(BorderLayout.WEST, tilePicker); 48 | tilePickerPanel.add(BorderLayout.CENTER, buildBitmapPanel()); 49 | tilePickerPanel.setBorder(new TitledBorder(new EtchedBorder(), "Tile picker")); 50 | 51 | JPanel lowerPanel = new JPanel(new BorderLayout()); 52 | lowerPanel.add(BorderLayout.WEST, tilePickerPanel); 53 | 54 | JPanel borderPanel = new JPanel(new BorderLayout()); 55 | levelEditView = new LevelEditView(tilePicker); 56 | borderPanel.add(BorderLayout.CENTER, new JScrollPane(levelEditView)); 57 | borderPanel.add(BorderLayout.SOUTH, lowerPanel); 58 | borderPanel.add(BorderLayout.NORTH, buildButtonPanel()); 59 | setContentPane(borderPanel); 60 | 61 | tilePicker.addTilePickChangedListener(this); 62 | } 63 | 64 | public JPanel buildBitmapPanel() 65 | { 66 | JPanel panel = new JPanel(new GridLayout(0, 1)); 67 | for (int i=0; i<8; i++) 68 | { 69 | bitmapCheckboxes[i] = new JCheckBox(Level.BIT_DESCRIPTIONS[i]); 70 | panel.add(bitmapCheckboxes[i]); 71 | if (Level.BIT_DESCRIPTIONS[i].startsWith("- ")) bitmapCheckboxes[i].setEnabled(false); 72 | 73 | final int id = i; 74 | bitmapCheckboxes[i].addActionListener(new ActionListener() 75 | { 76 | public void actionPerformed(ActionEvent arg0) 77 | { 78 | int bm = Level.TILE_BEHAVIORS[tilePicker.pickedTile&0xff]&0xff; 79 | bm&=255-(1<0); 143 | } 144 | } 145 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/sprites/Fireball.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario.sprites; 2 | 3 | import com.mojang.mario.Art; 4 | import com.mojang.mario.LevelScene; 5 | 6 | 7 | public class Fireball extends Sprite 8 | { 9 | private static float GROUND_INERTIA = 0.89f; 10 | private static float AIR_INERTIA = 0.89f; 11 | 12 | private float runTime; 13 | private boolean onGround = false; 14 | 15 | private int width = 4; 16 | int height = 24; 17 | 18 | private LevelScene world; 19 | public int facing; 20 | 21 | public boolean avoidCliffs = false; 22 | public int anim; 23 | 24 | public boolean dead = false; 25 | private int deadTime = 0; 26 | 27 | public Fireball(LevelScene world, float x, float y, int facing) 28 | { 29 | sheet = Art.particles; 30 | 31 | this.x = x; 32 | this.y = y; 33 | this.world = world; 34 | xPicO = 4; 35 | yPicO = 4; 36 | 37 | yPic = 3; 38 | height = 8; 39 | this.facing = facing; 40 | wPic = 8; 41 | hPic = 8; 42 | 43 | xPic = 4; 44 | ya = 4; 45 | } 46 | 47 | public void move() 48 | { 49 | if (deadTime > 0) 50 | { 51 | for (int i = 0; i < 8; i++) 52 | { 53 | world.addSprite(new Sparkle((int) (x + Math.random() * 8 - 4)+4, (int) (y + Math.random() * 8-4)+2, (float) Math.random() * 2 - 1-facing, (float) Math.random() *2 -1, 0, 1, 5)); 54 | } 55 | spriteContext.removeSprite(this); 56 | 57 | return; 58 | } 59 | 60 | if (facing != 0) anim++; 61 | 62 | float sideWaysSpeed = 8f; 63 | // float sideWaysSpeed = onGround ? 2.5f : 1.2f; 64 | 65 | if (xa > 2) 66 | { 67 | facing = 1; 68 | } 69 | if (xa < -2) 70 | { 71 | facing = -1; 72 | } 73 | 74 | xa = facing * sideWaysSpeed; 75 | 76 | world.checkFireballCollide(this); 77 | 78 | xFlipPic = facing == -1; 79 | 80 | runTime += (Math.abs(xa)) + 5; 81 | 82 | xPic = (anim) % 4; 83 | 84 | 85 | 86 | if (!move(xa, 0)) 87 | { 88 | die(); 89 | } 90 | 91 | onGround = false; 92 | move(0, ya); 93 | if (onGround) ya = -10; 94 | 95 | ya *= 0.95f; 96 | if (onGround) 97 | { 98 | xa *= GROUND_INERTIA; 99 | } 100 | else 101 | { 102 | xa *= AIR_INERTIA; 103 | } 104 | 105 | if (!onGround) 106 | { 107 | ya += 1.5; 108 | } 109 | } 110 | 111 | private boolean move(float xa, float ya) 112 | { 113 | while (xa > 8) 114 | { 115 | if (!move(8, 0)) return false; 116 | xa -= 8; 117 | } 118 | while (xa < -8) 119 | { 120 | if (!move(-8, 0)) return false; 121 | xa += 8; 122 | } 123 | while (ya > 8) 124 | { 125 | if (!move(0, 8)) return false; 126 | ya -= 8; 127 | } 128 | while (ya < -8) 129 | { 130 | if (!move(0, -8)) return false; 131 | ya += 8; 132 | } 133 | 134 | boolean collide = false; 135 | if (ya > 0) 136 | { 137 | if (isBlocking(x + xa - width, y + ya, xa, 0)) collide = true; 138 | else if (isBlocking(x + xa + width, y + ya, xa, 0)) collide = true; 139 | else if (isBlocking(x + xa - width, y + ya + 1, xa, ya)) collide = true; 140 | else if (isBlocking(x + xa + width, y + ya + 1, xa, ya)) collide = true; 141 | } 142 | if (ya < 0) 143 | { 144 | if (isBlocking(x + xa, y + ya - height, xa, ya)) collide = true; 145 | else if (collide || isBlocking(x + xa - width, y + ya - height, xa, ya)) collide = true; 146 | else if (collide || isBlocking(x + xa + width, y + ya - height, xa, ya)) collide = true; 147 | } 148 | if (xa > 0) 149 | { 150 | if (isBlocking(x + xa + width, y + ya - height, xa, ya)) collide = true; 151 | if (isBlocking(x + xa + width, y + ya - height / 2, xa, ya)) collide = true; 152 | if (isBlocking(x + xa + width, y + ya, xa, ya)) collide = true; 153 | 154 | if (avoidCliffs && onGround && !world.level.isBlocking((int) ((x + xa + width) / 16), (int) ((y) / 16 + 1), xa, 1)) collide = true; 155 | } 156 | if (xa < 0) 157 | { 158 | if (isBlocking(x + xa - width, y + ya - height, xa, ya)) collide = true; 159 | if (isBlocking(x + xa - width, y + ya - height / 2, xa, ya)) collide = true; 160 | if (isBlocking(x + xa - width, y + ya, xa, ya)) collide = true; 161 | 162 | if (avoidCliffs && onGround && !world.level.isBlocking((int) ((x + xa - width) / 16), (int) ((y) / 16 + 1), xa, 1)) collide = true; 163 | } 164 | 165 | if (collide) 166 | { 167 | if (xa < 0) 168 | { 169 | x = (int) ((x - width) / 16) * 16 + width; 170 | this.xa = 0; 171 | } 172 | if (xa > 0) 173 | { 174 | x = (int) ((x + width) / 16 + 1) * 16 - width - 1; 175 | this.xa = 0; 176 | } 177 | if (ya < 0) 178 | { 179 | y = (int) ((y - height) / 16) * 16 + height; 180 | this.ya = 0; 181 | } 182 | if (ya > 0) 183 | { 184 | y = (int) (y / 16 + 1) * 16 - 1; 185 | onGround = true; 186 | } 187 | return false; 188 | } 189 | else 190 | { 191 | x += xa; 192 | y += ya; 193 | return true; 194 | } 195 | } 196 | 197 | private boolean isBlocking(float _x, float _y, float xa, float ya) 198 | { 199 | int x = (int) (_x / 16); 200 | int y = (int) (_y / 16); 201 | if (x == (int) (this.x / 16) && y == (int) (this.y / 16)) return false; 202 | 203 | boolean blocking = world.level.isBlocking(x, y, xa, ya); 204 | 205 | @SuppressWarnings("unused") 206 | byte block = world.level.getBlock(x, y); 207 | 208 | return blocking; 209 | } 210 | 211 | public void die() 212 | { 213 | dead = true; 214 | 215 | xa = -facing * 2; 216 | ya = -5; 217 | deadTime = 100; 218 | } 219 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/sprites/Mushroom.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario.sprites; 2 | 3 | import com.mojang.mario.Art; 4 | import com.mojang.mario.LevelScene; 5 | 6 | 7 | public class Mushroom extends Sprite 8 | { 9 | private static float GROUND_INERTIA = 0.89f; 10 | private static float AIR_INERTIA = 0.89f; 11 | 12 | private float runTime; 13 | private boolean onGround = false; 14 | @SuppressWarnings("unused") 15 | private boolean mayJump = false; 16 | @SuppressWarnings("unused") 17 | private int jumpTime = 0; 18 | @SuppressWarnings("unused") 19 | private float xJumpSpeed; 20 | @SuppressWarnings("unused") 21 | private float yJumpSpeed; 22 | 23 | private int width = 4; 24 | int height = 24; 25 | 26 | private LevelScene world; 27 | public int facing; 28 | 29 | public boolean avoidCliffs = false; 30 | private int life; 31 | 32 | public Mushroom(LevelScene world, int x, int y) 33 | { 34 | sheet = Art.items; 35 | 36 | this.x = x; 37 | this.y = y; 38 | this.world = world; 39 | xPicO = 8; 40 | yPicO = 15; 41 | 42 | yPic = 0; 43 | height = 12; 44 | facing = 1; 45 | wPic = hPic = 16; 46 | life = 0; 47 | } 48 | 49 | public void collideCheck() 50 | { 51 | float xMarioD = world.mario.x - x; 52 | float yMarioD = world.mario.y - y; 53 | float w = 16; 54 | if (xMarioD > -w && xMarioD < w) 55 | { 56 | if (yMarioD > -height && yMarioD < world.mario.height) 57 | { 58 | world.mario.getMushroom(); 59 | spriteContext.removeSprite(this); 60 | } 61 | } 62 | } 63 | 64 | public void move() 65 | { 66 | if (life<9) 67 | { 68 | layer = 0; 69 | y--; 70 | life++; 71 | return; 72 | } 73 | float sideWaysSpeed = 1.75f; 74 | layer = 1; 75 | // float sideWaysSpeed = onGround ? 2.5f : 1.2f; 76 | 77 | if (xa > 2) 78 | { 79 | facing = 1; 80 | } 81 | if (xa < -2) 82 | { 83 | facing = -1; 84 | } 85 | 86 | xa = facing * sideWaysSpeed; 87 | 88 | mayJump = (onGround); 89 | 90 | xFlipPic = facing == -1; 91 | 92 | runTime += (Math.abs(xa)) + 5; 93 | 94 | 95 | 96 | if (!move(xa, 0)) facing = -facing; 97 | onGround = false; 98 | move(0, ya); 99 | 100 | ya *= 0.85f; 101 | if (onGround) 102 | { 103 | xa *= GROUND_INERTIA; 104 | } 105 | else 106 | { 107 | xa *= AIR_INERTIA; 108 | } 109 | 110 | if (!onGround) 111 | { 112 | ya += 2; 113 | } 114 | } 115 | 116 | private boolean move(float xa, float ya) 117 | { 118 | while (xa > 8) 119 | { 120 | if (!move(8, 0)) return false; 121 | xa -= 8; 122 | } 123 | while (xa < -8) 124 | { 125 | if (!move(-8, 0)) return false; 126 | xa += 8; 127 | } 128 | while (ya > 8) 129 | { 130 | if (!move(0, 8)) return false; 131 | ya -= 8; 132 | } 133 | while (ya < -8) 134 | { 135 | if (!move(0, -8)) return false; 136 | ya += 8; 137 | } 138 | 139 | boolean collide = false; 140 | if (ya > 0) 141 | { 142 | if (isBlocking(x + xa - width, y + ya, xa, 0)) collide = true; 143 | else if (isBlocking(x + xa + width, y + ya, xa, 0)) collide = true; 144 | else if (isBlocking(x + xa - width, y + ya + 1, xa, ya)) collide = true; 145 | else if (isBlocking(x + xa + width, y + ya + 1, xa, ya)) collide = true; 146 | } 147 | if (ya < 0) 148 | { 149 | if (isBlocking(x + xa, y + ya - height, xa, ya)) collide = true; 150 | else if (collide || isBlocking(x + xa - width, y + ya - height, xa, ya)) collide = true; 151 | else if (collide || isBlocking(x + xa + width, y + ya - height, xa, ya)) collide = true; 152 | } 153 | if (xa > 0) 154 | { 155 | if (isBlocking(x + xa + width, y + ya - height, xa, ya)) collide = true; 156 | if (isBlocking(x + xa + width, y + ya - height / 2, xa, ya)) collide = true; 157 | if (isBlocking(x + xa + width, y + ya, xa, ya)) collide = true; 158 | 159 | if (avoidCliffs && onGround && !world.level.isBlocking((int) ((x + xa + width) / 16), (int) ((y) / 16 + 1), xa, 1)) collide = true; 160 | } 161 | if (xa < 0) 162 | { 163 | if (isBlocking(x + xa - width, y + ya - height, xa, ya)) collide = true; 164 | if (isBlocking(x + xa - width, y + ya - height / 2, xa, ya)) collide = true; 165 | if (isBlocking(x + xa - width, y + ya, xa, ya)) collide = true; 166 | 167 | if (avoidCliffs && onGround && !world.level.isBlocking((int) ((x + xa - width) / 16), (int) ((y) / 16 + 1), xa, 1)) collide = true; 168 | } 169 | 170 | if (collide) 171 | { 172 | if (xa < 0) 173 | { 174 | x = (int) ((x - width) / 16) * 16 + width; 175 | this.xa = 0; 176 | } 177 | if (xa > 0) 178 | { 179 | x = (int) ((x + width) / 16 + 1) * 16 - width - 1; 180 | this.xa = 0; 181 | } 182 | if (ya < 0) 183 | { 184 | y = (int) ((y - height) / 16) * 16 + height; 185 | jumpTime = 0; 186 | this.ya = 0; 187 | } 188 | if (ya > 0) 189 | { 190 | y = (int) (y / 16 + 1) * 16 - 1; 191 | onGround = true; 192 | } 193 | return false; 194 | } 195 | else 196 | { 197 | x += xa; 198 | y += ya; 199 | return true; 200 | } 201 | } 202 | 203 | private boolean isBlocking(float _x, float _y, float xa, float ya) 204 | { 205 | int x = (int) (_x / 16); 206 | int y = (int) (_y / 16); 207 | if (x == (int) (this.x / 16) && y == (int) (this.y / 16)) return false; 208 | 209 | boolean blocking = world.level.isBlocking(x, y, xa, ya); 210 | 211 | @SuppressWarnings("unused") 212 | byte block = world.level.getBlock(x, y); 213 | 214 | return blocking; 215 | } 216 | 217 | public void bumpCheck(int xTile, int yTile) 218 | { 219 | if (x + width > xTile * 16 && x - width < xTile * 16 + 16 && yTile==(int)((y-1)/16)) 220 | { 221 | facing = -world.mario.facing; 222 | ya = -10; 223 | } 224 | } 225 | 226 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/Art.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario; 2 | 3 | import java.awt.AlphaComposite; 4 | import java.awt.Graphics2D; 5 | import java.awt.GraphicsConfiguration; 6 | import java.awt.Image; 7 | import java.awt.Transparency; 8 | import java.awt.image.BufferedImage; 9 | import java.io.IOException; 10 | 11 | import javax.imageio.ImageIO; 12 | import javax.sound.midi.MidiSystem; 13 | import javax.sound.midi.Sequence; 14 | import javax.sound.midi.Sequencer; 15 | 16 | import com.mojang.sonar.SonarSoundEngine; 17 | import com.mojang.sonar.sample.SonarSample; 18 | 19 | 20 | public class Art 21 | { 22 | public static final int SAMPLE_BREAK_BLOCK = 0; 23 | public static final int SAMPLE_GET_COIN = 1; 24 | public static final int SAMPLE_MARIO_JUMP = 2; 25 | public static final int SAMPLE_MARIO_STOMP = 3; 26 | public static final int SAMPLE_MARIO_KICK = 4; 27 | public static final int SAMPLE_MARIO_POWER_UP = 5; 28 | public static final int SAMPLE_MARIO_POWER_DOWN = 6; 29 | public static final int SAMPLE_MARIO_DEATH = 7; 30 | public static final int SAMPLE_ITEM_SPROUT = 8; 31 | public static final int SAMPLE_CANNON_FIRE = 9; 32 | public static final int SAMPLE_SHELL_BUMP = 10; 33 | public static final int SAMPLE_LEVEL_EXIT = 11; 34 | public static final int SAMPLE_MARIO_1UP = 12; 35 | public static final int SAMPLE_MARIO_FIREBALL = 13; 36 | 37 | public static Image[][] mario; 38 | public static Image[][] smallMario; 39 | public static Image[][] fireMario; 40 | public static Image[][] enemies; 41 | public static Image[][] items; 42 | public static Image[][] level; 43 | public static Image[][] particles; 44 | public static Image[][] font; 45 | public static Image[][] bg; 46 | public static Image[][] map; 47 | public static Image[][] endScene; 48 | public static Image[][] gameOver; 49 | public static Image logo; 50 | public static Image titleScreen; 51 | 52 | public static SonarSample[] samples = new SonarSample[100]; 53 | 54 | private static Sequence[] songs = new Sequence[10]; 55 | private static Sequencer sequencer; 56 | 57 | 58 | public static void init(GraphicsConfiguration gc, SonarSoundEngine sound) 59 | { 60 | try 61 | { 62 | mario = cutImage(gc, "/mariosheet.png", 32, 32); 63 | smallMario = cutImage(gc, "/smallmariosheet.png", 16, 16); 64 | fireMario = cutImage(gc, "/firemariosheet.png", 32, 32); 65 | enemies = cutImage(gc, "/enemysheet.png", 16, 32); 66 | items = cutImage(gc, "/itemsheet.png", 16, 16); 67 | level = cutImage(gc, "/mapsheet.png", 16, 16); 68 | map = cutImage(gc, "/worldmap.png", 16, 16); 69 | particles = cutImage(gc, "/particlesheet.png", 8, 8); 70 | bg = cutImage(gc, "/bgsheet.png", 32, 32); 71 | logo = getImage(gc, "/logo.gif"); 72 | titleScreen = getImage(gc, "/title.gif"); 73 | font = cutImage(gc, "/font.gif", 8, 8); 74 | endScene = cutImage(gc, "/endscene.gif", 96, 96); 75 | gameOver = cutImage(gc, "/gameovergost.gif", 96, 64); 76 | 77 | if (sound != null) 78 | { 79 | samples[SAMPLE_BREAK_BLOCK] = sound.loadSample("/snd/breakblock.wav"); 80 | samples[SAMPLE_GET_COIN] = sound.loadSample("/snd/coin.wav"); 81 | samples[SAMPLE_MARIO_JUMP] = sound.loadSample("/snd/jump.wav"); 82 | samples[SAMPLE_MARIO_STOMP] = sound.loadSample("/snd/stomp.wav"); 83 | samples[SAMPLE_MARIO_KICK] = sound.loadSample("/snd/kick.wav"); 84 | samples[SAMPLE_MARIO_POWER_UP] = sound.loadSample("/snd/powerup.wav"); 85 | samples[SAMPLE_MARIO_POWER_DOWN] = sound.loadSample("/snd/powerdown.wav"); 86 | samples[SAMPLE_MARIO_DEATH] = sound.loadSample("/snd/death.wav"); 87 | samples[SAMPLE_ITEM_SPROUT] = sound.loadSample("/snd/sprout.wav"); 88 | samples[SAMPLE_CANNON_FIRE] = sound.loadSample("/snd/cannon.wav"); 89 | samples[SAMPLE_SHELL_BUMP] = sound.loadSample("/snd/bump.wav"); 90 | samples[SAMPLE_LEVEL_EXIT] = sound.loadSample("/snd/exit.wav"); 91 | samples[SAMPLE_MARIO_1UP] = sound.loadSample("/snd/1-up.wav"); 92 | samples[SAMPLE_MARIO_FIREBALL] = sound.loadSample("/snd/fireball.wav"); 93 | } 94 | } 95 | catch (Exception e) 96 | { 97 | e.printStackTrace(); 98 | } 99 | 100 | try 101 | { 102 | sequencer = MidiSystem.getSequencer(); 103 | sequencer.open(); 104 | songs[0] = MidiSystem.getSequence(Art.class.getResourceAsStream("/mus/smb3map1.mid")); 105 | songs[1] = MidiSystem.getSequence(Art.class.getResourceAsStream("/mus/smwovr1.mid")); 106 | songs[2] = MidiSystem.getSequence(Art.class.getResourceAsStream("/mus/smb3undr.mid")); 107 | songs[3] = MidiSystem.getSequence(Art.class.getResourceAsStream("/mus/smwfortress.mid")); 108 | songs[4] = MidiSystem.getSequence(Art.class.getResourceAsStream("/mus/smwtitle.mid")); 109 | } 110 | catch (Exception e) 111 | { 112 | sequencer = null; 113 | e.printStackTrace(); 114 | } 115 | } 116 | 117 | private static Image getImage(GraphicsConfiguration gc, String imageName) throws IOException 118 | { 119 | BufferedImage source = ImageIO.read(Art.class.getResourceAsStream(imageName)); 120 | Image image = gc.createCompatibleImage(source.getWidth(), source.getHeight(), Transparency.BITMASK); 121 | Graphics2D g = (Graphics2D) image.getGraphics(); 122 | g.setComposite(AlphaComposite.Src); 123 | g.drawImage(source, 0, 0, null); 124 | g.dispose(); 125 | return image; 126 | } 127 | 128 | private static Image[][] cutImage(GraphicsConfiguration gc, String imageName, int xSize, int ySize) throws IOException 129 | { 130 | Image source = getImage(gc, imageName); 131 | Image[][] images = new Image[source.getWidth(null) / xSize][source.getHeight(null) / ySize]; 132 | for (int x = 0; x < source.getWidth(null) / xSize; x++) 133 | { 134 | for (int y = 0; y < source.getHeight(null) / ySize; y++) 135 | { 136 | Image image = gc.createCompatibleImage(xSize, ySize, Transparency.BITMASK); 137 | Graphics2D g = (Graphics2D) image.getGraphics(); 138 | g.setComposite(AlphaComposite.Src); 139 | g.drawImage(source, -x * xSize, -y * ySize, null); 140 | g.dispose(); 141 | images[x][y] = image; 142 | } 143 | } 144 | 145 | return images; 146 | } 147 | 148 | public static void startMusic(int song) 149 | { 150 | stopMusic(); 151 | if (sequencer != null) 152 | { 153 | try 154 | { 155 | sequencer.open(); 156 | sequencer.setSequence((Sequence)null); 157 | sequencer.setSequence(songs[song]); 158 | sequencer.setLoopCount(Sequencer.LOOP_CONTINUOUSLY); 159 | sequencer.start(); 160 | } 161 | catch (Exception e) 162 | { 163 | } 164 | } 165 | } 166 | 167 | public static void stopMusic() 168 | { 169 | if (sequencer != null) 170 | { 171 | try 172 | { 173 | sequencer.stop(); 174 | sequencer.close(); 175 | } 176 | catch (Exception e) 177 | { 178 | } 179 | } 180 | } 181 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/LevelRenderer.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario; 2 | 3 | import java.awt.*; 4 | import java.util.Random; 5 | import com.mojang.mario.level.*; 6 | 7 | 8 | public class LevelRenderer 9 | { 10 | private int xCam; 11 | private int yCam; 12 | private Image image; 13 | private Graphics2D g; 14 | private static final Color transparent = new Color(0, 0, 0, 0); 15 | private Level level; 16 | 17 | @SuppressWarnings("unused") 18 | private Random random = new Random(); 19 | public boolean renderBehaviors = false; 20 | 21 | int width; 22 | int height; 23 | 24 | public LevelRenderer(Level level, GraphicsConfiguration graphicsConfiguration, int width, int height) 25 | { 26 | this.width = width; 27 | this.height = height; 28 | 29 | this.level = level; 30 | image = graphicsConfiguration.createCompatibleImage(width, height, Transparency.BITMASK); 31 | g = (Graphics2D) image.getGraphics(); 32 | g.setComposite(AlphaComposite.Src); 33 | 34 | updateArea(0, 0, width, height); 35 | } 36 | 37 | public void setCam(int xCam, int yCam) 38 | { 39 | int xCamD = this.xCam - xCam; 40 | int yCamD = this.yCam - yCam; 41 | this.xCam = xCam; 42 | this.yCam = yCam; 43 | 44 | g.setComposite(AlphaComposite.Src); 45 | g.copyArea(0, 0, width, height, xCamD, yCamD); 46 | 47 | if (xCamD < 0) 48 | { 49 | if (xCamD < -width) xCamD = -width; 50 | updateArea(width + xCamD, 0, -xCamD, height); 51 | } 52 | else if (xCamD > 0) 53 | { 54 | if (xCamD > width) xCamD = width; 55 | updateArea(0, 0, xCamD, height); 56 | } 57 | 58 | if (yCamD < 0) 59 | { 60 | if (yCamD < -width) yCamD = -width; 61 | updateArea(0, height + yCamD, width, -yCamD); 62 | } 63 | else if (yCamD > 0) 64 | { 65 | if (yCamD > width) yCamD = width; 66 | updateArea(0, 0, width, yCamD); 67 | } 68 | } 69 | 70 | private void updateArea(int x0, int y0, int w, int h) 71 | { 72 | g.setBackground(transparent); 73 | g.clearRect(x0, y0, w, h); 74 | int xTileStart = (x0 + xCam) / 16; 75 | int yTileStart = (y0 + yCam) / 16; 76 | int xTileEnd = (x0 + xCam + w) / 16; 77 | int yTileEnd = (y0 + yCam + h) / 16; 78 | for (int x = xTileStart; x <= xTileEnd; x++) 79 | { 80 | for (int y = yTileStart; y <= yTileEnd; y++) 81 | { 82 | int b = level.getBlock(x, y) & 0xff; 83 | if (((Level.TILE_BEHAVIORS[b]) & Level.BIT_ANIMATED) == 0) 84 | { 85 | g.drawImage(Art.level[b % 16][b / 16], (x << 4) - xCam, (y << 4) - yCam, null); 86 | } 87 | } 88 | } 89 | } 90 | 91 | public void render(Graphics g, int tick, float alpha) 92 | { 93 | g.drawImage(image, 0, 0, null); 94 | 95 | for (int x = xCam / 16; x <= (xCam + width) / 16; x++) 96 | for (int y = yCam / 16; y <= (yCam + height) / 16; y++) 97 | { 98 | byte b = level.getBlock(x, y); 99 | 100 | if (((Level.TILE_BEHAVIORS[b & 0xff]) & Level.BIT_ANIMATED) > 0) 101 | { 102 | int animTime = (tick / 3) % 4; 103 | 104 | if ((b % 16) / 4 == 0 && b / 16 == 1) 105 | { 106 | animTime = (tick / 2 + (x + y) / 8) % 20; 107 | if (animTime > 3) animTime = 0; 108 | } 109 | if ((b % 16) / 4 == 3 && b / 16 == 0) 110 | { 111 | animTime = 2; 112 | } 113 | int yo = 0; 114 | if (x >= 0 && y >= 0 && x < level.width && y < level.height) yo = level.data[x][y]; 115 | if (yo > 0) yo = (int) (Math.sin((yo - alpha) / 4.0f * Math.PI) * 8); 116 | g.drawImage(Art.level[(b % 16) / 4 * 4 + animTime][b / 16], (x << 4) - xCam, (y << 4) - yCam - yo, null); 117 | } 118 | /* else if (b == Level.TILE_BONUS) 119 | { 120 | int animTime = (tick / 3) % 4; 121 | int yo = 0; 122 | if (x >= 0 && y >= 0 && x < level.width && y < level.height) yo = level.data[x][y]; 123 | if (yo > 0) yo = (int) (Math.sin((yo - alpha) / 4.0f * Math.PI) * 8); 124 | g.drawImage(Art.mapSprites[(4 + animTime)][0], (x << 4) - xCam, (y << 4) - yCam - yo, null); 125 | }*/ 126 | 127 | if (renderBehaviors) 128 | { 129 | if (((Level.TILE_BEHAVIORS[b & 0xff]) & Level.BIT_BLOCK_UPPER) > 0) 130 | { 131 | g.setColor(Color.RED); 132 | g.fillRect((x << 4) - xCam, (y << 4) - yCam, 16, 2); 133 | } 134 | if (((Level.TILE_BEHAVIORS[b & 0xff]) & Level.BIT_BLOCK_ALL) > 0) 135 | { 136 | g.setColor(Color.RED); 137 | g.fillRect((x << 4) - xCam, (y << 4) - yCam, 16, 2); 138 | g.fillRect((x << 4) - xCam, (y << 4) - yCam + 14, 16, 2); 139 | g.fillRect((x << 4) - xCam, (y << 4) - yCam, 2, 16); 140 | g.fillRect((x << 4) - xCam + 14, (y << 4) - yCam, 2, 16); 141 | } 142 | if (((Level.TILE_BEHAVIORS[b & 0xff]) & Level.BIT_BLOCK_LOWER) > 0) 143 | { 144 | g.setColor(Color.RED); 145 | g.fillRect((x << 4) - xCam, (y << 4) - yCam + 14, 16, 2); 146 | } 147 | if (((Level.TILE_BEHAVIORS[b & 0xff]) & Level.BIT_SPECIAL) > 0) 148 | { 149 | g.setColor(Color.PINK); 150 | g.fillRect((x << 4) - xCam + 2 + 4, (y << 4) - yCam + 2 + 4, 4, 4); 151 | } 152 | if (((Level.TILE_BEHAVIORS[b & 0xff]) & Level.BIT_BUMPABLE) > 0) 153 | { 154 | g.setColor(Color.BLUE); 155 | g.fillRect((x << 4) - xCam + 2, (y << 4) - yCam + 2, 4, 4); 156 | } 157 | if (((Level.TILE_BEHAVIORS[b & 0xff]) & Level.BIT_BREAKABLE) > 0) 158 | { 159 | g.setColor(Color.GREEN); 160 | g.fillRect((x << 4) - xCam + 2 + 4, (y << 4) - yCam + 2, 4, 4); 161 | } 162 | if (((Level.TILE_BEHAVIORS[b & 0xff]) & Level.BIT_PICKUPABLE) > 0) 163 | { 164 | g.setColor(Color.YELLOW); 165 | g.fillRect((x << 4) - xCam + 2, (y << 4) - yCam + 2 + 4, 4, 4); 166 | } 167 | if (((Level.TILE_BEHAVIORS[b & 0xff]) & Level.BIT_ANIMATED) > 0) 168 | { 169 | } 170 | } 171 | 172 | } 173 | } 174 | 175 | public void repaint(int x, int y, int w, int h) 176 | { 177 | updateArea(x * 16 - xCam, y * 16 - yCam, w * 16, h * 16); 178 | } 179 | 180 | public void setLevel(Level level) 181 | { 182 | this.level = level; 183 | updateArea(0, 0, width, height); 184 | } 185 | 186 | public void renderExit0(Graphics g, int tick, float alpha, boolean bar) 187 | { 188 | for (int y = level.yExit - 8; y < level.yExit; y++) 189 | { 190 | g.drawImage(Art.level[12][y == level.yExit - 8 ? 4 : 5], (level.xExit << 4) - xCam - 16, (y << 4) - yCam, null); 191 | } 192 | int yh = level.yExit * 16 - (int) ((Math.sin((tick + alpha) / 20) * 0.5 + 0.5) * 7 * 16) - 8; 193 | if (bar) 194 | { 195 | g.drawImage(Art.level[12][3], (level.xExit << 4) - xCam - 16, yh - yCam, null); 196 | g.drawImage(Art.level[13][3], (level.xExit << 4) - xCam, yh - yCam, null); 197 | } 198 | } 199 | 200 | 201 | public void renderExit1(Graphics g, int tick, float alpha) 202 | { 203 | for (int y = level.yExit - 8; y < level.yExit; y++) 204 | { 205 | g.drawImage(Art.level[13][y == level.yExit - 8 ? 4 : 5], (level.xExit << 4) - xCam + 16, (y << 4) - yCam, null); 206 | } 207 | } 208 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/level/BgLevelGenerator.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario.level; 2 | 3 | import java.util.Random; 4 | 5 | 6 | public class BgLevelGenerator 7 | { 8 | private static Random levelSeedRandom = new Random(); 9 | 10 | public static Level createLevel(int width, int height, boolean distant, int type) 11 | { 12 | BgLevelGenerator levelGenerator = new BgLevelGenerator(width, height, distant, type); 13 | return levelGenerator.createLevel(levelSeedRandom.nextLong()); 14 | } 15 | 16 | private int width; 17 | private int height; 18 | private boolean distant; 19 | private int type; 20 | 21 | private BgLevelGenerator(int width, int height, boolean distant, int type) 22 | { 23 | this.width = width; 24 | this.height = height; 25 | this.distant = distant; 26 | this.type = type; 27 | } 28 | 29 | private Level createLevel(long seed) 30 | { 31 | Level level = new Level(width, height); 32 | Random random = new Random(seed); 33 | 34 | switch (type) 35 | { 36 | case LevelGenerator.TYPE_OVERGROUND: 37 | { 38 | 39 | int range = distant ? 4 : 6; 40 | int offs = distant ? 2 : 1; 41 | int oh = random.nextInt(range) + offs; 42 | int h = random.nextInt(range) + offs; 43 | for (int x = 0; x < width; x++) 44 | { 45 | oh = h; 46 | while (oh == h) 47 | { 48 | h = random.nextInt(range) + offs; 49 | } 50 | for (int y = 0; y < height; y++) 51 | { 52 | int h0 = (oh < h) ? oh : h; 53 | int h1 = (oh < h) ? h : oh; 54 | if (y < h0) 55 | { 56 | if (distant) 57 | { 58 | int s = 2; 59 | if (y < 2) s = y; 60 | level.setBlock(x, y, (byte) (4 + s * 8)); 61 | } 62 | else 63 | { 64 | level.setBlock(x, y, (byte) 5); 65 | } 66 | } 67 | else if (y == h0) 68 | { 69 | int s = h0 == h ? 0 : 1; 70 | s += distant ? 2 : 0; 71 | level.setBlock(x, y, (byte) s); 72 | } 73 | else if (y == h1) 74 | { 75 | int s = h0 == h ? 0 : 1; 76 | s += distant ? 2 : 0; 77 | level.setBlock(x, y, (byte) (s + 16)); 78 | } 79 | else 80 | { 81 | int s = y > h1 ? 1 : 0; 82 | if (h0 == oh) s = 1 - s; 83 | s += distant ? 2 : 0; 84 | level.setBlock(x, y, (byte) (s + 8)); 85 | } 86 | } 87 | } 88 | break; 89 | } 90 | case LevelGenerator.TYPE_UNDERGROUND: 91 | { 92 | if (distant) 93 | { 94 | int tt = 0; 95 | for (int x = 0; x < width; x++) 96 | { 97 | if (random.nextDouble() < 0.75) tt = 1 - tt; 98 | for (int y = 0; y < height; y++) 99 | { 100 | int t = tt; 101 | int yy = y - 2; 102 | if (yy < 0 || yy > 4) 103 | { 104 | yy = 2; 105 | t = 0; 106 | } 107 | level.setBlock(x, y, (byte) (4 + t + (3 + yy) * 8)); 108 | } 109 | } 110 | } 111 | else 112 | { 113 | for (int x = 0; x < width; x++) 114 | { 115 | for (int y = 0; y < height; y++) 116 | { 117 | int t = x % 2; 118 | int yy = y-1; 119 | if (yy < 0 || yy > 7) 120 | { 121 | yy = 7; 122 | t = 0; 123 | } 124 | if (t == 0 && yy > 1 && yy < 5) 125 | { 126 | t = -1; 127 | yy = 0; 128 | } 129 | level.setBlock(x, y, (byte) (6 + t + (yy) * 8)); 130 | } 131 | } 132 | } 133 | break; 134 | } 135 | case LevelGenerator.TYPE_CASTLE: 136 | { 137 | if (distant) 138 | { 139 | for (int x = 0; x < width; x++) 140 | { 141 | for (int y = 0; y < height; y++) 142 | { 143 | int t = x % 2; 144 | int yy = y - 1; 145 | if (yy>2 && yy<5) 146 | { 147 | yy = 2; 148 | } 149 | else if (yy>=5) 150 | { 151 | yy-=2; 152 | } 153 | if (yy < 0) 154 | { 155 | t = 0; 156 | yy = 5; 157 | } 158 | else if (yy > 4) 159 | { 160 | t = 1; 161 | yy = 5; 162 | } 163 | else if (t<1 && yy==3) 164 | { 165 | t = 0; 166 | yy = 3; 167 | } 168 | else if (t<1 && yy>0 && yy<3) 169 | { 170 | t = 0; 171 | yy = 2; 172 | } 173 | level.setBlock(x, y, (byte) (1+t + (yy + 4) * 8)); 174 | } 175 | } 176 | } 177 | else 178 | { 179 | for (int x = 0; x < width; x++) 180 | { 181 | for (int y = 0; y < height; y++) 182 | { 183 | int t = x % 3; 184 | int yy = y - 1; 185 | if (yy>2 && yy<5) 186 | { 187 | yy = 2; 188 | } 189 | else if (yy>=5) 190 | { 191 | yy-=2; 192 | } 193 | if (yy < 0) 194 | { 195 | t = 1; 196 | yy = 5; 197 | } 198 | else if (yy > 4) 199 | { 200 | t = 2; 201 | yy = 5; 202 | } 203 | else if (t<2 && yy==4) 204 | { 205 | t = 2; 206 | yy = 4; 207 | } 208 | else if (t<2 && yy>0 && yy<4) 209 | { 210 | t = 4; 211 | yy = -3; 212 | } 213 | level.setBlock(x, y, (byte) (1 + t + (yy + 3) * 8)); 214 | } 215 | } 216 | } 217 | break; 218 | } 219 | } 220 | return level; 221 | } 222 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/MarioComponent.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario; 2 | 3 | import java.awt.*; 4 | import java.awt.event.FocusEvent; 5 | import java.awt.event.FocusListener; 6 | import java.awt.event.KeyEvent; 7 | import java.awt.event.KeyListener; 8 | import java.awt.image.*; 9 | import java.util.Random; 10 | 11 | import javax.sound.sampled.LineUnavailableException; 12 | import javax.swing.*; 13 | 14 | import com.mojang.mario.sprites.*; 15 | import com.mojang.sonar.FakeSoundEngine; 16 | import com.mojang.sonar.SonarSoundEngine; 17 | 18 | 19 | public class MarioComponent extends JComponent implements Runnable, KeyListener, FocusListener 20 | { 21 | private static final long serialVersionUID = 739318775993206607L; 22 | public static final int TICKS_PER_SECOND = 24; 23 | 24 | private boolean running = false; 25 | private int width, height; 26 | private GraphicsConfiguration graphicsConfiguration; 27 | private Scene scene; 28 | private SonarSoundEngine sound; 29 | @SuppressWarnings("unused") 30 | private boolean focused = false; 31 | private boolean useScale2x = false; 32 | private MapScene mapScene; 33 | int delay; 34 | 35 | private Scale2x scale2x = new Scale2x(320, 240); 36 | 37 | public MarioComponent(int width, int height) 38 | { 39 | this.setFocusable(true); 40 | this.setEnabled(true); 41 | this.width = width; 42 | this.height = height; 43 | 44 | Dimension size = new Dimension(width, height); 45 | setPreferredSize(size); 46 | setMinimumSize(size); 47 | setMaximumSize(size); 48 | 49 | try 50 | { 51 | sound = new SonarSoundEngine(64); 52 | } 53 | catch (LineUnavailableException e) 54 | { 55 | e.printStackTrace(); 56 | sound = new FakeSoundEngine(); 57 | } 58 | 59 | setFocusable(true); 60 | } 61 | 62 | private void toggleKey(int keyCode, boolean isPressed) 63 | { 64 | if (keyCode == KeyEvent.VK_LEFT) 65 | { 66 | scene.toggleKey(Mario.KEY_LEFT, isPressed); 67 | } 68 | if (keyCode == KeyEvent.VK_RIGHT) 69 | { 70 | scene.toggleKey(Mario.KEY_RIGHT, isPressed); 71 | } 72 | if (keyCode == KeyEvent.VK_DOWN) 73 | { 74 | scene.toggleKey(Mario.KEY_DOWN, isPressed); 75 | } 76 | if (keyCode == KeyEvent.VK_UP) 77 | { 78 | scene.toggleKey(Mario.KEY_UP, isPressed); 79 | } 80 | if (keyCode == KeyEvent.VK_A) 81 | { 82 | scene.toggleKey(Mario.KEY_SPEED, isPressed); 83 | } 84 | if (keyCode == KeyEvent.VK_S) 85 | { 86 | scene.toggleKey(Mario.KEY_JUMP, isPressed); 87 | } 88 | if (isPressed && keyCode == KeyEvent.VK_F1) 89 | { 90 | useScale2x = !useScale2x; 91 | } 92 | } 93 | 94 | public void paint(Graphics g) 95 | { 96 | } 97 | 98 | public void update(Graphics g) 99 | { 100 | } 101 | 102 | public void start() 103 | { 104 | if (!running) 105 | { 106 | running = true; 107 | new Thread(this, "Game Thread").start(); 108 | } 109 | } 110 | 111 | public void stop() 112 | { 113 | Art.stopMusic(); 114 | running = false; 115 | } 116 | 117 | public void run() 118 | { 119 | graphicsConfiguration = getGraphicsConfiguration(); 120 | 121 | // scene = new LevelScene(graphicsConfiguration); 122 | mapScene = new MapScene(graphicsConfiguration, this, new Random().nextLong()); 123 | scene = mapScene; 124 | scene.setSound(sound); 125 | 126 | Art.init(graphicsConfiguration, sound); 127 | 128 | VolatileImage image = createVolatileImage(320, 240); 129 | Graphics g = getGraphics(); 130 | Graphics og = image.getGraphics(); 131 | 132 | int renderedFrames = 0; 133 | 134 | double time = System.nanoTime() / 1000000000.0; 135 | double now = time; 136 | long tm = System.currentTimeMillis(); 137 | long lTick = tm; 138 | 139 | addKeyListener(this); 140 | addFocusListener(this); 141 | 142 | toTitle(); 143 | adjustFPS(); 144 | 145 | while (running) 146 | { 147 | // double lastTime = time; 148 | // time = System.nanoTime() / 1000000000.0; 149 | // double passedTime = time - lastTime; 150 | // 151 | // if (passedTime < 0) naiveTiming = false; // Stop relying on nanotime if it starts skipping around in time (ie running backwards at least once). This sometimes happens on dual core amds. 152 | // averagePassedTime = averagePassedTime * 0.9 + passedTime * 0.1; 153 | // 154 | // if (naiveTiming) 155 | // { 156 | // now = time; 157 | // } 158 | // else 159 | // { 160 | // now += averagePassedTime; 161 | // } 162 | // 163 | // int tick = (int) (now * TICKS_PER_SECOND); 164 | // if (lastTick == -1) lastTick = tick; 165 | 166 | scene.tick(); 167 | // lastTick++; 168 | // 169 | // if (lastTick % TICKS_PER_SECOND == 0) 170 | // { 171 | // fps = renderedFrames; 172 | // renderedFrames = 0; 173 | // } 174 | 175 | float alpha = (float) (System.currentTimeMillis() - lTick); 176 | sound.clientTick(alpha); 177 | 178 | @SuppressWarnings("unused") 179 | int x = (int) (Math.sin(now) * 16 + 160); 180 | @SuppressWarnings("unused") 181 | int y = (int) (Math.cos(now) * 16 + 120); 182 | 183 | //og.setColor(Color.WHITE); 184 | og.fillRect(0, 0, 320, 240); 185 | 186 | alpha = 0; 187 | scene.render(og, alpha); 188 | 189 | if (!this.hasFocus() && lTick/4%2==0) 190 | { 191 | String msg = "CLICK TO PLAY"; 192 | 193 | drawString(og, msg, 160 - msg.length() * 4 + 1, 110 + 1, 0); 194 | drawString(og, msg, 160 - msg.length() * 4, 110, 7); 195 | } 196 | og.setColor(Color.BLACK); 197 | /* drawString(og, "FPS: " + fps, 5, 5, 0); 198 | drawString(og, "FPS: " + fps, 4, 4, 7);*/ 199 | 200 | if (width != 320 || height != 240) 201 | { 202 | if (useScale2x) 203 | { 204 | g.drawImage(scale2x.scale(image), 0, 0, null); 205 | } 206 | else 207 | { 208 | g.drawImage(image, 0, 0, 640, 480, null); 209 | } 210 | } 211 | else 212 | { 213 | g.drawImage(image, 0, 0, null); 214 | } 215 | 216 | if (delay > 0) 217 | try { 218 | tm += delay; 219 | Thread.sleep(Math.max(0, tm - System.currentTimeMillis())); 220 | } catch (InterruptedException e) { 221 | break; 222 | } 223 | 224 | renderedFrames++; 225 | } 226 | 227 | Art.stopMusic(); 228 | } 229 | 230 | private void drawString(Graphics g, String text, int x, int y, int c) 231 | { 232 | char[] ch = text.toCharArray(); 233 | for (int i = 0; i < ch.length; i++) 234 | { 235 | g.drawImage(Art.font[ch[i] - 32][c], x + i * 8, y, null); 236 | } 237 | } 238 | 239 | public void keyPressed(KeyEvent arg0) 240 | { 241 | toggleKey(arg0.getKeyCode(), true); 242 | } 243 | 244 | public void keyReleased(KeyEvent arg0) 245 | { 246 | toggleKey(arg0.getKeyCode(), false); 247 | } 248 | 249 | public void startLevel(long seed, int difficulty, int type) 250 | { 251 | scene = new LevelScene(graphicsConfiguration, this, seed, difficulty, type); 252 | scene.setSound(sound); 253 | scene.init(); 254 | } 255 | 256 | public void levelFailed() 257 | { 258 | scene = mapScene; 259 | mapScene.startMusic(); 260 | Mario.lives--; 261 | if (Mario.lives == 0) 262 | { 263 | lose(); 264 | } 265 | } 266 | 267 | public void keyTyped(KeyEvent arg0) 268 | { 269 | } 270 | 271 | public void focusGained(FocusEvent arg0) 272 | { 273 | focused = true; 274 | } 275 | 276 | public void focusLost(FocusEvent arg0) 277 | { 278 | focused = false; 279 | } 280 | 281 | public void levelWon() 282 | { 283 | scene = mapScene; 284 | mapScene.startMusic(); 285 | mapScene.levelWon(); 286 | } 287 | 288 | public void win() 289 | { 290 | scene = new WinScene(this); 291 | scene.setSound(sound); 292 | scene.init(); 293 | } 294 | 295 | public void toTitle() 296 | { 297 | Mario.resetStatic(); 298 | scene = new TitleScene(this, graphicsConfiguration); 299 | scene.setSound(sound); 300 | scene.init(); 301 | } 302 | 303 | public void lose() 304 | { 305 | scene = new LoseScene(this); 306 | scene.setSound(sound); 307 | scene.init(); 308 | } 309 | 310 | public void startGame() 311 | { 312 | scene = mapScene; 313 | mapScene.startMusic(); 314 | mapScene.init(); 315 | } 316 | 317 | public void adjustFPS() { 318 | int fps = 24; 319 | delay = (fps > 0) ? (fps >= 100) ? 0 : (1000 / fps) : 100; 320 | // System.out.println("Delay: " + delay); 321 | } 322 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/sprites/Shell.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario.sprites; 2 | 3 | import com.mojang.mario.Art; 4 | import com.mojang.mario.LevelScene; 5 | 6 | 7 | public class Shell extends Sprite 8 | { 9 | private static float GROUND_INERTIA = 0.89f; 10 | private static float AIR_INERTIA = 0.89f; 11 | 12 | private float runTime; 13 | private boolean onGround = false; 14 | 15 | private int width = 4; 16 | int height = 24; 17 | 18 | private LevelScene world; 19 | public int facing; 20 | 21 | public boolean avoidCliffs = false; 22 | public int anim; 23 | 24 | public boolean dead = false; 25 | private int deadTime = 0; 26 | public boolean carried; 27 | 28 | 29 | public Shell(LevelScene world, float x, float y, int type) 30 | { 31 | sheet = Art.enemies; 32 | 33 | this.x = x; 34 | this.y = y; 35 | this.world = world; 36 | xPicO = 8; 37 | yPicO = 31; 38 | 39 | yPic = type; 40 | height = 12; 41 | facing = 0; 42 | wPic = 16; 43 | 44 | xPic = 4; 45 | ya = -5; 46 | } 47 | 48 | public boolean fireballCollideCheck(Fireball fireball) 49 | { 50 | if (deadTime != 0) return false; 51 | 52 | float xD = fireball.x - x; 53 | float yD = fireball.y - y; 54 | 55 | if (xD > -16 && xD < 16) 56 | { 57 | if (yD > -height && yD < fireball.height) 58 | { 59 | if (facing!=0) return true; 60 | 61 | world.sound.play(Art.samples[Art.SAMPLE_MARIO_KICK], this, 1, 1, 1); 62 | 63 | xa = fireball.facing * 2; 64 | ya = -5; 65 | if (spriteTemplate != null) spriteTemplate.isDead = true; 66 | deadTime = 100; 67 | hPic = -hPic; 68 | yPicO = -yPicO + 16; 69 | return true; 70 | } 71 | } 72 | return false; 73 | } 74 | 75 | public void collideCheck() 76 | { 77 | if (carried || dead || deadTime>0) return; 78 | 79 | float xMarioD = world.mario.x - x; 80 | float yMarioD = world.mario.y - y; 81 | float w = 16; 82 | if (xMarioD > -w && xMarioD < w) 83 | { 84 | if (yMarioD > -height && yMarioD < world.mario.height) 85 | { 86 | if (world.mario.ya > 0 && yMarioD <= 0 && (!world.mario.onGround || !world.mario.wasOnGround)) 87 | { 88 | world.mario.stomp(this); 89 | if (facing != 0) 90 | { 91 | xa = 0; 92 | facing = 0; 93 | } 94 | else 95 | { 96 | facing = world.mario.facing; 97 | } 98 | } 99 | else 100 | { 101 | if (facing != 0) 102 | { 103 | world.mario.getHurt(); 104 | } 105 | else 106 | { 107 | world.mario.kick(this); 108 | facing = world.mario.facing; 109 | } 110 | } 111 | } 112 | } 113 | } 114 | 115 | public void move() 116 | { 117 | if (carried) 118 | { 119 | world.checkShellCollide(this); 120 | return; 121 | } 122 | 123 | if (deadTime > 0) 124 | { 125 | deadTime--; 126 | 127 | if (deadTime == 0) 128 | { 129 | deadTime = 1; 130 | for (int i = 0; i < 8; i++) 131 | { 132 | world.addSprite(new Sparkle((int) (x + Math.random() * 16 - 8) + 4, (int) (y - Math.random() * 8) + 4, (float) (Math.random() * 2 - 1), (float) Math.random() * -1, 0, 1, 5)); 133 | } 134 | spriteContext.removeSprite(this); 135 | } 136 | 137 | x += xa; 138 | y += ya; 139 | ya *= 0.95; 140 | ya += 1; 141 | 142 | return; 143 | } 144 | 145 | if (facing != 0) anim++; 146 | 147 | float sideWaysSpeed = 11f; 148 | // float sideWaysSpeed = onGround ? 2.5f : 1.2f; 149 | 150 | if (xa > 2) 151 | { 152 | facing = 1; 153 | } 154 | if (xa < -2) 155 | { 156 | facing = -1; 157 | } 158 | 159 | xa = facing * sideWaysSpeed; 160 | 161 | if (facing != 0) 162 | { 163 | world.checkShellCollide(this); 164 | } 165 | 166 | xFlipPic = facing == -1; 167 | 168 | runTime += (Math.abs(xa)) + 5; 169 | 170 | xPic = (anim / 2) % 4 + 3; 171 | 172 | 173 | 174 | if (!move(xa, 0)) 175 | { 176 | world.sound.play(Art.samples[Art.SAMPLE_SHELL_BUMP], this, 1, 1, 1); 177 | 178 | facing = -facing; 179 | } 180 | onGround = false; 181 | move(0, ya); 182 | 183 | ya *= 0.85f; 184 | if (onGround) 185 | { 186 | xa *= GROUND_INERTIA; 187 | } 188 | else 189 | { 190 | xa *= AIR_INERTIA; 191 | } 192 | 193 | if (!onGround) 194 | { 195 | ya += 2; 196 | } 197 | } 198 | 199 | private boolean move(float xa, float ya) 200 | { 201 | while (xa > 8) 202 | { 203 | if (!move(8, 0)) return false; 204 | xa -= 8; 205 | } 206 | while (xa < -8) 207 | { 208 | if (!move(-8, 0)) return false; 209 | xa += 8; 210 | } 211 | while (ya > 8) 212 | { 213 | if (!move(0, 8)) return false; 214 | ya -= 8; 215 | } 216 | while (ya < -8) 217 | { 218 | if (!move(0, -8)) return false; 219 | ya += 8; 220 | } 221 | 222 | boolean collide = false; 223 | if (ya > 0) 224 | { 225 | if (isBlocking(x + xa - width, y + ya, xa, 0)) collide = true; 226 | else if (isBlocking(x + xa + width, y + ya, xa, 0)) collide = true; 227 | else if (isBlocking(x + xa - width, y + ya + 1, xa, ya)) collide = true; 228 | else if (isBlocking(x + xa + width, y + ya + 1, xa, ya)) collide = true; 229 | } 230 | if (ya < 0) 231 | { 232 | if (isBlocking(x + xa, y + ya - height, xa, ya)) collide = true; 233 | else if (collide || isBlocking(x + xa - width, y + ya - height, xa, ya)) collide = true; 234 | else if (collide || isBlocking(x + xa + width, y + ya - height, xa, ya)) collide = true; 235 | } 236 | if (xa > 0) 237 | { 238 | if (isBlocking(x + xa + width, y + ya - height, xa, ya)) collide = true; 239 | if (isBlocking(x + xa + width, y + ya - height / 2, xa, ya)) collide = true; 240 | if (isBlocking(x + xa + width, y + ya, xa, ya)) collide = true; 241 | 242 | if (avoidCliffs && onGround && !world.level.isBlocking((int) ((x + xa + width) / 16), (int) ((y) / 16 + 1), xa, 1)) collide = true; 243 | } 244 | if (xa < 0) 245 | { 246 | if (isBlocking(x + xa - width, y + ya - height, xa, ya)) collide = true; 247 | if (isBlocking(x + xa - width, y + ya - height / 2, xa, ya)) collide = true; 248 | if (isBlocking(x + xa - width, y + ya, xa, ya)) collide = true; 249 | 250 | if (avoidCliffs && onGround && !world.level.isBlocking((int) ((x + xa - width) / 16), (int) ((y) / 16 + 1), xa, 1)) collide = true; 251 | } 252 | 253 | if (collide) 254 | { 255 | if (xa < 0) 256 | { 257 | x = (int) ((x - width) / 16) * 16 + width; 258 | this.xa = 0; 259 | } 260 | if (xa > 0) 261 | { 262 | x = (int) ((x + width) / 16 + 1) * 16 - width - 1; 263 | this.xa = 0; 264 | } 265 | if (ya < 0) 266 | { 267 | y = (int) ((y - height) / 16) * 16 + height; 268 | this.ya = 0; 269 | } 270 | if (ya > 0) 271 | { 272 | y = (int) (y / 16 + 1) * 16 - 1; 273 | onGround = true; 274 | } 275 | return false; 276 | } 277 | else 278 | { 279 | x += xa; 280 | y += ya; 281 | return true; 282 | } 283 | } 284 | 285 | private boolean isBlocking(float _x, float _y, float xa, float ya) 286 | { 287 | int x = (int) (_x / 16); 288 | int y = (int) (_y / 16); 289 | if (x == (int) (this.x / 16) && y == (int) (this.y / 16)) return false; 290 | 291 | boolean blocking = world.level.isBlocking(x, y, xa, ya); 292 | 293 | @SuppressWarnings("unused") 294 | byte block = world.level.getBlock(x, y); 295 | 296 | if (blocking && ya == 0 && xa!=0) 297 | { 298 | world.bump(x, y, true); 299 | } 300 | 301 | return blocking; 302 | } 303 | 304 | public void bumpCheck(int xTile, int yTile) 305 | { 306 | if (x + width > xTile * 16 && x - width < xTile * 16 + 16 && yTile == (int) ((y - 1) / 16)) 307 | { 308 | facing = -world.mario.facing; 309 | ya = -10; 310 | } 311 | } 312 | 313 | public void die() 314 | { 315 | dead = true; 316 | 317 | carried = false; 318 | 319 | xa = -facing * 2; 320 | ya = -5; 321 | deadTime = 100; 322 | } 323 | 324 | public boolean shellCollideCheck(Shell shell) 325 | { 326 | if (deadTime != 0) return false; 327 | 328 | float xD = shell.x - x; 329 | float yD = shell.y - y; 330 | 331 | if (xD > -16 && xD < 16) 332 | { 333 | if (yD > -height && yD < shell.height) 334 | { 335 | world.sound.play(Art.samples[Art.SAMPLE_MARIO_KICK], this, 1, 1, 1); 336 | 337 | if (world.mario.carried == shell || world.mario.carried == this) 338 | { 339 | world.mario.carried = null; 340 | } 341 | 342 | die(); 343 | shell.die(); 344 | return true; 345 | } 346 | } 347 | return false; 348 | } 349 | 350 | 351 | public void release(Mario mario) 352 | { 353 | carried = false; 354 | facing = mario.facing; 355 | x += facing * 8; 356 | } 357 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/sprites/Enemy.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario.sprites; 2 | 3 | import java.awt.Graphics; 4 | 5 | import com.mojang.mario.Art; 6 | import com.mojang.mario.LevelScene; 7 | 8 | 9 | public class Enemy extends Sprite 10 | { 11 | public static final int ENEMY_RED_KOOPA = 0; 12 | public static final int ENEMY_GREEN_KOOPA = 1; 13 | public static final int ENEMY_GOOMBA = 2; 14 | public static final int ENEMY_SPIKY = 3; 15 | public static final int ENEMY_FLOWER = 4; 16 | 17 | private static float GROUND_INERTIA = 0.89f; 18 | private static float AIR_INERTIA = 0.89f; 19 | 20 | private float runTime; 21 | private boolean onGround = false; 22 | @SuppressWarnings("unused") 23 | private boolean mayJump = false; 24 | @SuppressWarnings("unused") 25 | private int jumpTime = 0; 26 | @SuppressWarnings("unused") 27 | private float xJumpSpeed; 28 | @SuppressWarnings("unused") 29 | private float yJumpSpeed; 30 | 31 | int width = 4; 32 | int height = 24; 33 | 34 | private LevelScene world; 35 | public int facing; 36 | public int deadTime = 0; 37 | public boolean flyDeath = false; 38 | 39 | public boolean avoidCliffs = true; 40 | private int type; 41 | 42 | public boolean winged = true; 43 | private int wingTime = 0; 44 | 45 | public boolean noFireballDeath; 46 | 47 | public Enemy(LevelScene world, int x, int y, int dir, int type, boolean winged) 48 | { 49 | this.type = type; 50 | sheet = Art.enemies; 51 | this.winged = winged; 52 | 53 | this.x = x; 54 | this.y = y; 55 | this.world = world; 56 | xPicO = 8; 57 | yPicO = 31; 58 | 59 | avoidCliffs = type == Enemy.ENEMY_RED_KOOPA; 60 | 61 | noFireballDeath = type == Enemy.ENEMY_SPIKY; 62 | 63 | yPic = type; 64 | if (yPic > 1) height = 12; 65 | facing = dir; 66 | if (facing == 0) facing = 1; 67 | this.wPic = 16; 68 | } 69 | 70 | public void collideCheck() 71 | { 72 | if (deadTime != 0) 73 | { 74 | return; 75 | } 76 | 77 | float xMarioD = world.mario.x - x; 78 | float yMarioD = world.mario.y - y; 79 | @SuppressWarnings("unused") 80 | float w = 16; 81 | if (xMarioD > -width*2-4 && xMarioD < width*2+4) 82 | { 83 | if (yMarioD > -height && yMarioD < world.mario.height) 84 | { 85 | if (type != Enemy.ENEMY_SPIKY && world.mario.ya > 0 && yMarioD <= 0 && (!world.mario.onGround || !world.mario.wasOnGround)) 86 | { 87 | world.mario.stomp(this); 88 | if (winged) 89 | { 90 | winged = false; 91 | ya = 0; 92 | } 93 | else 94 | { 95 | this.yPicO = 31 - (32 - 8); 96 | hPic = 8; 97 | if (spriteTemplate != null) spriteTemplate.isDead = true; 98 | deadTime = 10; 99 | winged = false; 100 | 101 | if (type == Enemy.ENEMY_RED_KOOPA) 102 | { 103 | spriteContext.addSprite(new Shell(world, x, y, 0)); 104 | } 105 | else if (type == Enemy.ENEMY_GREEN_KOOPA) 106 | { 107 | spriteContext.addSprite(new Shell(world, x, y, 1)); 108 | } 109 | } 110 | } 111 | else 112 | { 113 | world.mario.getHurt(); 114 | } 115 | } 116 | } 117 | } 118 | 119 | public void move() 120 | { 121 | wingTime++; 122 | if (deadTime > 0) 123 | { 124 | deadTime--; 125 | 126 | if (deadTime == 0) 127 | { 128 | deadTime = 1; 129 | for (int i = 0; i < 8; i++) 130 | { 131 | world.addSprite(new Sparkle((int) (x + Math.random() * 16 - 8) + 4, (int) (y - Math.random() * 8) + 4, (float) (Math.random() * 2 - 1), (float) Math.random() * -1, 0, 1, 5)); 132 | } 133 | spriteContext.removeSprite(this); 134 | } 135 | 136 | if (flyDeath) 137 | { 138 | x += xa; 139 | y += ya; 140 | ya *= 0.95; 141 | ya += 1; 142 | } 143 | return; 144 | } 145 | 146 | 147 | float sideWaysSpeed = 1.75f; 148 | // float sideWaysSpeed = onGround ? 2.5f : 1.2f; 149 | 150 | if (xa > 2) 151 | { 152 | facing = 1; 153 | } 154 | if (xa < -2) 155 | { 156 | facing = -1; 157 | } 158 | 159 | xa = facing * sideWaysSpeed; 160 | 161 | mayJump = (onGround); 162 | 163 | xFlipPic = facing == -1; 164 | 165 | runTime += (Math.abs(xa)) + 5; 166 | 167 | int runFrame = ((int) (runTime / 20)) % 2; 168 | 169 | if (!onGround) 170 | { 171 | runFrame = 1; 172 | } 173 | 174 | 175 | if (!move(xa, 0)) facing = -facing; 176 | onGround = false; 177 | move(0, ya); 178 | 179 | ya *= winged ? 0.95f : 0.85f; 180 | if (onGround) 181 | { 182 | xa *= GROUND_INERTIA; 183 | } 184 | else 185 | { 186 | xa *= AIR_INERTIA; 187 | } 188 | 189 | if (!onGround) 190 | { 191 | if (winged) 192 | { 193 | ya += 0.6f; 194 | } 195 | else 196 | { 197 | ya += 2; 198 | } 199 | } 200 | else if (winged) 201 | { 202 | ya = -10; 203 | } 204 | 205 | if (winged) runFrame = wingTime / 4 % 2; 206 | 207 | xPic = runFrame; 208 | } 209 | 210 | private boolean move(float xa, float ya) 211 | { 212 | while (xa > 8) 213 | { 214 | if (!move(8, 0)) return false; 215 | xa -= 8; 216 | } 217 | while (xa < -8) 218 | { 219 | if (!move(-8, 0)) return false; 220 | xa += 8; 221 | } 222 | while (ya > 8) 223 | { 224 | if (!move(0, 8)) return false; 225 | ya -= 8; 226 | } 227 | while (ya < -8) 228 | { 229 | if (!move(0, -8)) return false; 230 | ya += 8; 231 | } 232 | 233 | boolean collide = false; 234 | if (ya > 0) 235 | { 236 | if (isBlocking(x + xa - width, y + ya, xa, 0)) collide = true; 237 | else if (isBlocking(x + xa + width, y + ya, xa, 0)) collide = true; 238 | else if (isBlocking(x + xa - width, y + ya + 1, xa, ya)) collide = true; 239 | else if (isBlocking(x + xa + width, y + ya + 1, xa, ya)) collide = true; 240 | } 241 | if (ya < 0) 242 | { 243 | if (isBlocking(x + xa, y + ya - height, xa, ya)) collide = true; 244 | else if (collide || isBlocking(x + xa - width, y + ya - height, xa, ya)) collide = true; 245 | else if (collide || isBlocking(x + xa + width, y + ya - height, xa, ya)) collide = true; 246 | } 247 | if (xa > 0) 248 | { 249 | if (isBlocking(x + xa + width, y + ya - height, xa, ya)) collide = true; 250 | if (isBlocking(x + xa + width, y + ya - height / 2, xa, ya)) collide = true; 251 | if (isBlocking(x + xa + width, y + ya, xa, ya)) collide = true; 252 | 253 | if (avoidCliffs && onGround && !world.level.isBlocking((int) ((x + xa + width) / 16), (int) ((y) / 16 + 1), xa, 1)) collide = true; 254 | } 255 | if (xa < 0) 256 | { 257 | if (isBlocking(x + xa - width, y + ya - height, xa, ya)) collide = true; 258 | if (isBlocking(x + xa - width, y + ya - height / 2, xa, ya)) collide = true; 259 | if (isBlocking(x + xa - width, y + ya, xa, ya)) collide = true; 260 | 261 | if (avoidCliffs && onGround && !world.level.isBlocking((int) ((x + xa - width) / 16), (int) ((y) / 16 + 1), xa, 1)) collide = true; 262 | } 263 | 264 | if (collide) 265 | { 266 | if (xa < 0) 267 | { 268 | x = (int) ((x - width) / 16) * 16 + width; 269 | this.xa = 0; 270 | } 271 | if (xa > 0) 272 | { 273 | x = (int) ((x + width) / 16 + 1) * 16 - width - 1; 274 | this.xa = 0; 275 | } 276 | if (ya < 0) 277 | { 278 | y = (int) ((y - height) / 16) * 16 + height; 279 | jumpTime = 0; 280 | this.ya = 0; 281 | } 282 | if (ya > 0) 283 | { 284 | y = (int) (y / 16 + 1) * 16 - 1; 285 | onGround = true; 286 | } 287 | return false; 288 | } 289 | else 290 | { 291 | x += xa; 292 | y += ya; 293 | return true; 294 | } 295 | } 296 | 297 | private boolean isBlocking(float _x, float _y, float xa, float ya) 298 | { 299 | int x = (int) (_x / 16); 300 | int y = (int) (_y / 16); 301 | if (x == (int) (this.x / 16) && y == (int) (this.y / 16)) return false; 302 | 303 | boolean blocking = world.level.isBlocking(x, y, xa, ya); 304 | 305 | @SuppressWarnings("unused") 306 | byte block = world.level.getBlock(x, y); 307 | 308 | return blocking; 309 | } 310 | 311 | public boolean shellCollideCheck(Shell shell) 312 | { 313 | if (deadTime != 0) return false; 314 | 315 | float xD = shell.x - x; 316 | float yD = shell.y - y; 317 | 318 | if (xD > -16 && xD < 16) 319 | { 320 | if (yD > -height && yD < shell.height) 321 | { 322 | world.sound.play(Art.samples[Art.SAMPLE_MARIO_KICK], this, 1, 1, 1); 323 | 324 | xa = shell.facing * 2; 325 | ya = -5; 326 | flyDeath = true; 327 | if (spriteTemplate != null) spriteTemplate.isDead = true; 328 | deadTime = 100; 329 | winged = false; 330 | hPic = -hPic; 331 | yPicO = -yPicO + 16; 332 | return true; 333 | } 334 | } 335 | return false; 336 | } 337 | 338 | public boolean fireballCollideCheck(Fireball fireball) 339 | { 340 | if (deadTime != 0) return false; 341 | 342 | float xD = fireball.x - x; 343 | float yD = fireball.y - y; 344 | 345 | if (xD > -16 && xD < 16) 346 | { 347 | if (yD > -height && yD < fireball.height) 348 | { 349 | if (noFireballDeath) return true; 350 | 351 | world.sound.play(Art.samples[Art.SAMPLE_MARIO_KICK], this, 1, 1, 1); 352 | 353 | xa = fireball.facing * 2; 354 | ya = -5; 355 | flyDeath = true; 356 | if (spriteTemplate != null) spriteTemplate.isDead = true; 357 | deadTime = 100; 358 | winged = false; 359 | hPic = -hPic; 360 | yPicO = -yPicO + 16; 361 | return true; 362 | } 363 | } 364 | return false; 365 | } 366 | 367 | public void bumpCheck(int xTile, int yTile) 368 | { 369 | if (deadTime != 0) return; 370 | 371 | if (x + width > xTile * 16 && x - width < xTile * 16 + 16 && yTile == (int) ((y - 1) / 16)) 372 | { 373 | world.sound.play(Art.samples[Art.SAMPLE_MARIO_KICK], this, 1, 1, 1); 374 | 375 | xa = -world.mario.facing * 2; 376 | ya = -5; 377 | flyDeath = true; 378 | if (spriteTemplate != null) spriteTemplate.isDead = true; 379 | deadTime = 100; 380 | winged = false; 381 | hPic = -hPic; 382 | yPicO = -yPicO + 16; 383 | } 384 | } 385 | 386 | public void render(Graphics og, float alpha) 387 | { 388 | if (winged) 389 | { 390 | int xPixel = (int) (xOld + (x - xOld) * alpha) - xPicO; 391 | int yPixel = (int) (yOld + (y - yOld) * alpha) - yPicO; 392 | 393 | if (type == Enemy.ENEMY_GREEN_KOOPA || type == Enemy.ENEMY_RED_KOOPA) 394 | { 395 | } 396 | else 397 | { 398 | xFlipPic = !xFlipPic; 399 | og.drawImage(sheet[wingTime / 4 % 2][4], xPixel + (xFlipPic ? wPic : 0) + (xFlipPic ? 10 : -10), yPixel + (yFlipPic ? hPic : 0) - 8, xFlipPic ? -wPic : wPic, yFlipPic ? -hPic : hPic, null); 400 | xFlipPic = !xFlipPic; 401 | } 402 | } 403 | 404 | super.render(og, alpha); 405 | 406 | if (winged) 407 | { 408 | int xPixel = (int) (xOld + (x - xOld) * alpha) - xPicO; 409 | int yPixel = (int) (yOld + (y - yOld) * alpha) - yPicO; 410 | 411 | if (type == Enemy.ENEMY_GREEN_KOOPA || type == Enemy.ENEMY_RED_KOOPA) 412 | { 413 | og.drawImage(sheet[wingTime / 4 % 2][4], xPixel + (xFlipPic ? wPic : 0) + (xFlipPic ? 10 : -10), yPixel + (yFlipPic ? hPic : 0) - 10, xFlipPic ? -wPic : wPic, yFlipPic ? -hPic : hPic, null); 414 | } 415 | else 416 | { 417 | og.drawImage(sheet[wingTime / 4 % 2][4], xPixel + (xFlipPic ? wPic : 0) + (xFlipPic ? 10 : -10), yPixel + (yFlipPic ? hPic : 0) - 8, xFlipPic ? -wPic : wPic, yFlipPic ? -hPic : hPic, null); 418 | } 419 | } 420 | } 421 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/LevelScene.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario; 2 | 3 | import java.awt.Color; 4 | import java.awt.Graphics; 5 | import java.awt.GraphicsConfiguration; 6 | import java.awt.Image; 7 | import java.io.*; 8 | import java.text.DecimalFormat; 9 | import java.util.*; 10 | 11 | import com.mojang.mario.sprites.*; 12 | import com.mojang.sonar.FixedSoundSource; 13 | import com.mojang.mario.level.*; 14 | 15 | 16 | public class LevelScene extends Scene implements SpriteContext 17 | { 18 | private List sprites = new ArrayList(); 19 | private List spritesToAdd = new ArrayList(); 20 | private List spritesToRemove = new ArrayList(); 21 | 22 | public Level level; 23 | public Mario mario; 24 | public float xCam, yCam, xCamO, yCamO; 25 | public static Image tmpImage; 26 | private int tick; 27 | 28 | private LevelRenderer layer; 29 | private BgRenderer[] bgLayer = new BgRenderer[2]; 30 | 31 | private GraphicsConfiguration graphicsConfiguration; 32 | 33 | public boolean paused = false; 34 | public int startTime = 0; 35 | private int timeLeft; 36 | 37 | // private Recorder recorder = new Recorder(); 38 | // private Replayer replayer = null; 39 | 40 | private long levelSeed; 41 | private MarioComponent renderer; 42 | private int levelType; 43 | private int levelDifficulty; 44 | 45 | public LevelScene(GraphicsConfiguration graphicsConfiguration, MarioComponent renderer, long seed, int levelDifficulty, int type) 46 | { 47 | this.graphicsConfiguration = graphicsConfiguration; 48 | this.levelSeed = seed; 49 | this.renderer = renderer; 50 | this.levelDifficulty = levelDifficulty; 51 | this.levelType = type; 52 | } 53 | 54 | public void init() 55 | { 56 | try 57 | { 58 | Level.loadBehaviors(new DataInputStream(LevelScene.class.getResourceAsStream("/tiles.dat"))); 59 | } 60 | catch (IOException e) 61 | { 62 | e.printStackTrace(); 63 | System.exit(0); 64 | } 65 | /* if (replayer!=null) 66 | { 67 | level = LevelGenerator.createLevel(2048, 15, replayer.nextLong()); 68 | } 69 | else 70 | {*/ 71 | // level = LevelGenerator.createLevel(320, 15, levelSeed); 72 | level = LevelGenerator.createLevel(320, 15, levelSeed, levelDifficulty, levelType); 73 | // } 74 | 75 | /* if (recorder != null) 76 | { 77 | recorder.addLong(LevelGenerator.lastSeed); 78 | }*/ 79 | 80 | if (levelType==LevelGenerator.TYPE_OVERGROUND) 81 | Art.startMusic(1); 82 | else if (levelType==LevelGenerator.TYPE_UNDERGROUND) 83 | Art.startMusic(2); 84 | else if (levelType==LevelGenerator.TYPE_CASTLE) 85 | Art.startMusic(3); 86 | 87 | 88 | paused = false; 89 | Sprite.spriteContext = this; 90 | sprites.clear(); 91 | layer = new LevelRenderer(level, graphicsConfiguration, 320, 240); 92 | for (int i = 0; i < 2; i++) 93 | { 94 | int scrollSpeed = 4 >> i; 95 | int w = ((level.width * 16) - 320) / scrollSpeed + 320; 96 | int h = ((level.height * 16) - 240) / scrollSpeed + 240; 97 | Level bgLevel = BgLevelGenerator.createLevel(w / 32 + 1, h / 32 + 1, i == 0, levelType); 98 | bgLayer[i] = new BgRenderer(bgLevel, graphicsConfiguration, 320, 240, scrollSpeed); 99 | } 100 | mario = new Mario(this); 101 | sprites.add(mario); 102 | startTime = 1; 103 | 104 | timeLeft = 200*15; 105 | 106 | tick = 0; 107 | } 108 | 109 | public int fireballsOnScreen = 0; 110 | 111 | List shellsToCheck = new ArrayList(); 112 | 113 | public void checkShellCollide(Shell shell) 114 | { 115 | shellsToCheck.add(shell); 116 | } 117 | 118 | List fireballsToCheck = new ArrayList(); 119 | 120 | public void checkFireballCollide(Fireball fireball) 121 | { 122 | fireballsToCheck.add(fireball); 123 | } 124 | 125 | public void tick() 126 | { 127 | timeLeft--; 128 | if (timeLeft==0) 129 | { 130 | mario.die(); 131 | } 132 | xCamO = xCam; 133 | yCamO = yCam; 134 | 135 | if (startTime > 0) 136 | { 137 | startTime++; 138 | } 139 | 140 | float targetXCam = mario.x - 160; 141 | 142 | xCam = targetXCam; 143 | 144 | if (xCam < 0) xCam = 0; 145 | if (xCam > level.width * 16 - 320) xCam = level.width * 16 - 320; 146 | 147 | /* if (recorder != null) 148 | { 149 | recorder.addTick(mario.getKeyMask()); 150 | } 151 | 152 | if (replayer!=null) 153 | { 154 | mario.setKeys(replayer.nextTick()); 155 | }*/ 156 | 157 | fireballsOnScreen = 0; 158 | 159 | for (Sprite sprite : sprites) 160 | { 161 | if (sprite != mario) 162 | { 163 | float xd = sprite.x - xCam; 164 | float yd = sprite.y - yCam; 165 | if (xd < -64 || xd > 320 + 64 || yd < -64 || yd > 240 + 64) 166 | { 167 | removeSprite(sprite); 168 | } 169 | else 170 | { 171 | if (sprite instanceof Fireball) 172 | { 173 | fireballsOnScreen++; 174 | } 175 | } 176 | } 177 | } 178 | 179 | if (paused) 180 | { 181 | for (Sprite sprite : sprites) 182 | { 183 | if (sprite == mario) 184 | { 185 | sprite.tick(); 186 | } 187 | else 188 | { 189 | sprite.tickNoMove(); 190 | } 191 | } 192 | } 193 | else 194 | { 195 | tick++; 196 | level.tick(); 197 | 198 | boolean hasShotCannon = false; 199 | int xCannon = 0; 200 | 201 | for (int x = (int) xCam / 16 - 1; x <= (int) (xCam + layer.width) / 16 + 1; x++) 202 | for (int y = (int) yCam / 16 - 1; y <= (int) (yCam + layer.height) / 16 + 1; y++) 203 | { 204 | int dir = 0; 205 | 206 | if (x * 16 + 8 > mario.x + 16) dir = -1; 207 | if (x * 16 + 8 < mario.x - 16) dir = 1; 208 | 209 | SpriteTemplate st = level.getSpriteTemplate(x, y); 210 | 211 | if (st != null) 212 | { 213 | if (st.lastVisibleTick != tick - 1) 214 | { 215 | if (st.sprite == null || !sprites.contains(st.sprite)) 216 | { 217 | st.spawn(this, x, y, dir); 218 | } 219 | } 220 | 221 | st.lastVisibleTick = tick; 222 | } 223 | 224 | if (dir != 0) 225 | { 226 | byte b = level.getBlock(x, y); 227 | if (((Level.TILE_BEHAVIORS[b & 0xff]) & Level.BIT_ANIMATED) > 0) 228 | { 229 | if ((b % 16) / 4 == 3 && b / 16 == 0) 230 | { 231 | if ((tick - x * 2) % 100 == 0) 232 | { 233 | xCannon = x; 234 | for (int i = 0; i < 8; i++) 235 | { 236 | addSprite(new Sparkle(x * 16 + 8, y * 16 + (int) (Math.random() * 16), (float) Math.random() * dir, 0, 0, 1, 5)); 237 | } 238 | addSprite(new BulletBill(this, x * 16 + 8 + dir * 8, y * 16 + 15, dir)); 239 | hasShotCannon = true; 240 | } 241 | } 242 | } 243 | } 244 | } 245 | 246 | if (hasShotCannon) 247 | { 248 | sound.play(Art.samples[Art.SAMPLE_CANNON_FIRE], new FixedSoundSource(xCannon * 16, yCam + 120), 1, 1, 1); 249 | } 250 | 251 | for (Sprite sprite : sprites) 252 | { 253 | sprite.tick(); 254 | } 255 | 256 | for (Sprite sprite : sprites) 257 | { 258 | sprite.collideCheck(); 259 | } 260 | 261 | for (Shell shell : shellsToCheck) 262 | { 263 | for (Sprite sprite : sprites) 264 | { 265 | if (sprite != shell && !shell.dead) 266 | { 267 | if (sprite.shellCollideCheck(shell)) 268 | { 269 | if (mario.carried == shell && !shell.dead) 270 | { 271 | mario.carried = null; 272 | shell.die(); 273 | } 274 | } 275 | } 276 | } 277 | } 278 | shellsToCheck.clear(); 279 | 280 | for (Fireball fireball : fireballsToCheck) 281 | { 282 | for (Sprite sprite : sprites) 283 | { 284 | if (sprite != fireball && !fireball.dead) 285 | { 286 | if (sprite.fireballCollideCheck(fireball)) 287 | { 288 | fireball.die(); 289 | } 290 | } 291 | } 292 | } 293 | fireballsToCheck.clear(); 294 | } 295 | 296 | sprites.addAll(0, spritesToAdd); 297 | sprites.removeAll(spritesToRemove); 298 | spritesToAdd.clear(); 299 | spritesToRemove.clear(); 300 | } 301 | 302 | private DecimalFormat df = new DecimalFormat("00"); 303 | private DecimalFormat df2 = new DecimalFormat("000"); 304 | 305 | public void render(Graphics g, float alpha) 306 | { 307 | int xCam = (int) (mario.xOld + (mario.x - mario.xOld) * alpha) - 160; 308 | int yCam = (int) (mario.yOld + (mario.y - mario.yOld) * alpha) - 120; 309 | //int xCam = (int) (xCamO + (this.xCam - xCamO) * alpha); 310 | // int yCam = (int) (yCamO + (this.yCam - yCamO) * alpha); 311 | if (xCam < 0) xCam = 0; 312 | if (yCam < 0) yCam = 0; 313 | if (xCam > level.width * 16 - 320) xCam = level.width * 16 - 320; 314 | if (yCam > level.height * 16 - 240) yCam = level.height * 16 - 240; 315 | 316 | // g.drawImage(Art.background, 0, 0, null); 317 | 318 | for (int i = 0; i < 2; i++) 319 | { 320 | bgLayer[i].setCam(xCam, yCam); 321 | bgLayer[i].render(g, tick, alpha); 322 | } 323 | 324 | g.translate(-xCam, -yCam); 325 | for (Sprite sprite : sprites) 326 | { 327 | if (sprite.layer == 0) sprite.render(g, alpha); 328 | } 329 | g.translate(xCam, yCam); 330 | 331 | layer.setCam(xCam, yCam); 332 | layer.render(g, tick, paused?0:alpha); 333 | layer.renderExit0(g, tick, paused?0:alpha, mario.winTime==0); 334 | 335 | g.translate(-xCam, -yCam); 336 | for (Sprite sprite : sprites) 337 | { 338 | if (sprite.layer == 1) sprite.render(g, alpha); 339 | } 340 | g.translate(xCam, yCam); 341 | g.setColor(Color.BLACK); 342 | layer.renderExit1(g, tick, paused?0:alpha); 343 | 344 | drawStringDropShadow(g, "MARIO " + df.format(Mario.lives), 0, 0, 7); 345 | drawStringDropShadow(g, "00000000", 0, 1, 7); 346 | 347 | drawStringDropShadow(g, "COIN", 14, 0, 7); 348 | drawStringDropShadow(g, " "+df.format(Mario.coins), 14, 1, 7); 349 | 350 | drawStringDropShadow(g, "WORLD", 24, 0, 7); 351 | drawStringDropShadow(g, " "+Mario.levelString, 24, 1, 7); 352 | 353 | drawStringDropShadow(g, "TIME", 35, 0, 7); 354 | int time = (timeLeft+15-1)/15; 355 | if (time<0) time = 0; 356 | drawStringDropShadow(g, " "+df2.format(time), 35, 1, 7); 357 | 358 | 359 | if (startTime > 0) 360 | { 361 | float t = startTime + alpha - 2; 362 | t = t * t * 0.6f; 363 | renderBlackout(g, 160, 120, (int) (t)); 364 | } 365 | // mario.x>level.xExit*16 366 | if (mario.winTime > 0) 367 | { 368 | float t = mario.winTime + alpha; 369 | t = t * t * 0.2f; 370 | 371 | if (t > 900) 372 | { 373 | renderer.levelWon(); 374 | // replayer = new Replayer(recorder.getBytes()); 375 | // init(); 376 | } 377 | 378 | renderBlackout(g, (int) (mario.xDeathPos - xCam), (int) (mario.yDeathPos - yCam), (int) (320 - t)); 379 | } 380 | 381 | if (mario.deathTime > 0) 382 | { 383 | float t = mario.deathTime + alpha; 384 | t = t * t * 0.4f; 385 | 386 | if (t > 1800) 387 | { 388 | renderer.levelFailed(); 389 | // replayer = new Replayer(recorder.getBytes()); 390 | // init(); 391 | } 392 | 393 | renderBlackout(g, (int) (mario.xDeathPos - xCam), (int) (mario.yDeathPos - yCam), (int) (320 - t)); 394 | } 395 | } 396 | 397 | private void drawStringDropShadow(Graphics g, String text, int x, int y, int c) 398 | { 399 | drawString(g, text, x*8+5, y*8+5, 0); 400 | drawString(g, text, x*8+4, y*8+4, c); 401 | } 402 | 403 | private void drawString(Graphics g, String text, int x, int y, int c) 404 | { 405 | char[] ch = text.toCharArray(); 406 | for (int i = 0; i < ch.length; i++) 407 | { 408 | g.drawImage(Art.font[ch[i] - 32][c], x + i * 8, y, null); 409 | } 410 | } 411 | 412 | private void renderBlackout(Graphics g, int x, int y, int radius) 413 | { 414 | if (radius > 320) return; 415 | 416 | int[] xp = new int[20]; 417 | int[] yp = new int[20]; 418 | for (int i = 0; i < 16; i++) 419 | { 420 | xp[i] = x + (int) (Math.cos(i * Math.PI / 15) * radius); 421 | yp[i] = y + (int) (Math.sin(i * Math.PI / 15) * radius); 422 | } 423 | xp[16] = 320; 424 | yp[16] = y; 425 | xp[17] = 320; 426 | yp[17] = 240; 427 | xp[18] = 0; 428 | yp[18] = 240; 429 | xp[19] = 0; 430 | yp[19] = y; 431 | g.fillPolygon(xp, yp, xp.length); 432 | 433 | for (int i = 0; i < 16; i++) 434 | { 435 | xp[i] = x - (int) (Math.cos(i * Math.PI / 15) * radius); 436 | yp[i] = y - (int) (Math.sin(i * Math.PI / 15) * radius); 437 | } 438 | xp[16] = 320; 439 | yp[16] = y; 440 | xp[17] = 320; 441 | yp[17] = 0; 442 | xp[18] = 0; 443 | yp[18] = 0; 444 | xp[19] = 0; 445 | yp[19] = y; 446 | 447 | g.fillPolygon(xp, yp, xp.length); 448 | } 449 | 450 | 451 | public void addSprite(Sprite sprite) 452 | { 453 | spritesToAdd.add(sprite); 454 | sprite.tick(); 455 | } 456 | 457 | public void removeSprite(Sprite sprite) 458 | { 459 | spritesToRemove.add(sprite); 460 | } 461 | 462 | public float getX(float alpha) 463 | { 464 | int xCam = (int) (mario.xOld + (mario.x - mario.xOld) * alpha) - 160; 465 | // int yCam = (int) (mario.yOld + (mario.y - mario.yOld) * alpha) - 120; 466 | //int xCam = (int) (xCamO + (this.xCam - xCamO) * alpha); 467 | // int yCam = (int) (yCamO + (this.yCam - yCamO) * alpha); 468 | if (xCam < 0) xCam = 0; 469 | // if (yCam < 0) yCam = 0; 470 | // if (yCam > 0) yCam = 0; 471 | return xCam + 160; 472 | } 473 | 474 | public float getY(float alpha) 475 | { 476 | return 0; 477 | } 478 | 479 | public void bump(int x, int y, boolean canBreakBricks) 480 | { 481 | byte block = level.getBlock(x, y); 482 | 483 | if ((Level.TILE_BEHAVIORS[block & 0xff] & Level.BIT_BUMPABLE) > 0) 484 | { 485 | bumpInto(x, y - 1); 486 | level.setBlock(x, y, (byte) 4); 487 | level.setBlockData(x, y, (byte) 4); 488 | 489 | if (((Level.TILE_BEHAVIORS[block & 0xff]) & Level.BIT_SPECIAL) > 0) 490 | { 491 | sound.play(Art.samples[Art.SAMPLE_ITEM_SPROUT], new FixedSoundSource(x * 16 + 8, y * 16 + 8), 1, 1, 1); 492 | if (!Mario.large) 493 | { 494 | addSprite(new Mushroom(this, x * 16 + 8, y * 16 + 8)); 495 | } 496 | else 497 | { 498 | addSprite(new FireFlower(this, x * 16 + 8, y * 16 + 8)); 499 | } 500 | } 501 | else 502 | { 503 | Mario.getCoin(); 504 | sound.play(Art.samples[Art.SAMPLE_GET_COIN], new FixedSoundSource(x * 16 + 8, y * 16 + 8), 1, 1, 1); 505 | addSprite(new CoinAnim(x, y)); 506 | } 507 | } 508 | 509 | if ((Level.TILE_BEHAVIORS[block & 0xff] & Level.BIT_BREAKABLE) > 0) 510 | { 511 | bumpInto(x, y - 1); 512 | if (canBreakBricks) 513 | { 514 | sound.play(Art.samples[Art.SAMPLE_BREAK_BLOCK], new FixedSoundSource(x * 16 + 8, y * 16 + 8), 1, 1, 1); 515 | level.setBlock(x, y, (byte) 0); 516 | for (int xx = 0; xx < 2; xx++) 517 | for (int yy = 0; yy < 2; yy++) 518 | addSprite(new Particle(x * 16 + xx * 8 + 4, y * 16 + yy * 8 + 4, (xx * 2 - 1) * 4, (yy * 2 - 1) * 4 - 8)); 519 | } 520 | else 521 | { 522 | level.setBlockData(x, y, (byte) 4); 523 | } 524 | } 525 | } 526 | 527 | public void bumpInto(int x, int y) 528 | { 529 | byte block = level.getBlock(x, y); 530 | if (((Level.TILE_BEHAVIORS[block & 0xff]) & Level.BIT_PICKUPABLE) > 0) 531 | { 532 | Mario.getCoin(); 533 | sound.play(Art.samples[Art.SAMPLE_GET_COIN], new FixedSoundSource(x * 16 + 8, y * 16 + 8), 1, 1, 1); 534 | level.setBlock(x, y, (byte) 0); 535 | addSprite(new CoinAnim(x, y + 1)); 536 | } 537 | 538 | for (Sprite sprite : sprites) 539 | { 540 | sprite.bumpCheck(x, y); 541 | } 542 | } 543 | } -------------------------------------------------------------------------------- /src/main/java/com/mojang/mario/sprites/Mario.java: -------------------------------------------------------------------------------- 1 | package com.mojang.mario.sprites; 2 | 3 | 4 | import com.mojang.mario.Art; 5 | import com.mojang.mario.Scene; 6 | import com.mojang.mario.level.*; 7 | import com.mojang.mario.LevelScene; 8 | import com.mojang.sonar.FixedSoundSource; 9 | 10 | 11 | public class Mario extends Sprite 12 | { 13 | public static boolean large = false; 14 | public static boolean fire = false; 15 | public static int coins = 0; 16 | public static int lives = 3; 17 | public static String levelString = "none"; 18 | 19 | public static void resetStatic() 20 | { 21 | large = false; 22 | fire = false; 23 | coins = 0; 24 | lives = 3; 25 | levelString = "none"; 26 | } 27 | 28 | public static final int KEY_LEFT = 0; 29 | public static final int KEY_RIGHT = 1; 30 | public static final int KEY_DOWN = 2; 31 | public static final int KEY_UP = 3; 32 | public static final int KEY_JUMP = 4; 33 | public static final int KEY_SPEED = 5; 34 | 35 | private static float GROUND_INERTIA = 0.89f; 36 | private static float AIR_INERTIA = 0.89f; 37 | 38 | public boolean[] keys; 39 | private float runTime; 40 | boolean wasOnGround = false; 41 | boolean onGround = false; 42 | private boolean mayJump = false; 43 | private boolean ducking = false; 44 | private boolean sliding = false; 45 | private int jumpTime = 0; 46 | private float xJumpSpeed; 47 | private float yJumpSpeed; 48 | private boolean canShoot = false; 49 | 50 | int width = 4; 51 | int height = 24; 52 | 53 | private LevelScene world; 54 | public int facing; 55 | private int powerUpTime = 0; 56 | 57 | public int xDeathPos, yDeathPos; 58 | 59 | public int deathTime = 0; 60 | public int winTime = 0; 61 | private int invulnerableTime = 0; 62 | 63 | public Sprite carried = null; 64 | private static Mario instance; 65 | 66 | public Mario(LevelScene world) 67 | { 68 | Mario.instance = this; 69 | this.world = world; 70 | keys = Scene.keys; 71 | x = 32; 72 | y = 0; 73 | 74 | facing = 1; 75 | setLarge(Mario.large, Mario.fire); 76 | } 77 | 78 | private boolean lastLarge; 79 | private boolean lastFire; 80 | private boolean newLarge; 81 | private boolean newFire; 82 | 83 | private void blink(boolean on) 84 | { 85 | Mario.large = on?newLarge:lastLarge; 86 | Mario.fire = on?newFire:lastFire; 87 | 88 | if (large) 89 | { 90 | sheet = Art.mario; 91 | if (fire) 92 | sheet = Art.fireMario; 93 | 94 | xPicO = 16; 95 | yPicO = 31; 96 | wPic = hPic = 32; 97 | } 98 | else 99 | { 100 | sheet = Art.smallMario; 101 | 102 | xPicO = 8; 103 | yPicO = 15; 104 | wPic = hPic = 16; 105 | } 106 | 107 | calcPic(); 108 | } 109 | 110 | void setLarge(boolean large, boolean fire) 111 | { 112 | if (fire) large = true; 113 | if (!large) fire = false; 114 | 115 | lastLarge = Mario.large; 116 | lastFire = Mario.fire; 117 | 118 | Mario.large = large; 119 | Mario.fire = fire; 120 | 121 | newLarge = Mario.large; 122 | newFire = Mario.fire; 123 | 124 | blink(true); 125 | } 126 | 127 | public void move() 128 | { 129 | if (winTime > 0) 130 | { 131 | winTime++; 132 | 133 | xa = 0; 134 | ya = 0; 135 | return; 136 | } 137 | 138 | if (deathTime > 0) 139 | { 140 | deathTime++; 141 | if (deathTime < 11) 142 | { 143 | xa = 0; 144 | ya = 0; 145 | } 146 | else if (deathTime == 11) 147 | { 148 | ya = -15; 149 | } 150 | else 151 | { 152 | ya += 2; 153 | } 154 | x += xa; 155 | y += ya; 156 | return; 157 | } 158 | 159 | if (powerUpTime != 0) 160 | { 161 | if (powerUpTime > 0) 162 | { 163 | powerUpTime--; 164 | blink(((powerUpTime / 3) & 1) == 0); 165 | } 166 | else 167 | { 168 | powerUpTime++; 169 | blink(((-powerUpTime / 3) & 1) == 0); 170 | } 171 | 172 | if (powerUpTime == 0) world.paused = false; 173 | 174 | calcPic(); 175 | return; 176 | } 177 | 178 | if (invulnerableTime > 0) invulnerableTime--; 179 | visible = ((invulnerableTime / 2) & 1) == 0; 180 | 181 | wasOnGround = onGround; 182 | float sideWaysSpeed = keys[KEY_SPEED] ? 1.2f : 0.6f; 183 | // float sideWaysSpeed = onGround ? 2.5f : 1.2f; 184 | 185 | if (onGround) 186 | { 187 | if (keys[KEY_DOWN] && large) 188 | { 189 | ducking = true; 190 | } 191 | else 192 | { 193 | ducking = false; 194 | } 195 | } 196 | 197 | if (xa > 2) 198 | { 199 | facing = 1; 200 | } 201 | if (xa < -2) 202 | { 203 | facing = -1; 204 | } 205 | 206 | if (keys[KEY_JUMP] || (jumpTime < 0 && !onGround && !sliding)) 207 | { 208 | if (jumpTime < 0) 209 | { 210 | xa = xJumpSpeed; 211 | ya = -jumpTime * yJumpSpeed; 212 | jumpTime++; 213 | } 214 | else if (onGround && mayJump) 215 | { 216 | world.sound.play(Art.samples[Art.SAMPLE_MARIO_JUMP], this, 1, 1, 1); 217 | xJumpSpeed = 0; 218 | yJumpSpeed = -1.9f; 219 | jumpTime = 7; 220 | ya = jumpTime * yJumpSpeed; 221 | onGround = false; 222 | sliding = false; 223 | } 224 | else if (sliding && mayJump) 225 | { 226 | world.sound.play(Art.samples[Art.SAMPLE_MARIO_JUMP], this, 1, 1, 1); 227 | xJumpSpeed = -facing * 6.0f; 228 | yJumpSpeed = -2.0f; 229 | jumpTime = -6; 230 | xa = xJumpSpeed; 231 | ya = -jumpTime * yJumpSpeed; 232 | onGround = false; 233 | sliding = false; 234 | facing = -facing; 235 | } 236 | else if (jumpTime > 0) 237 | { 238 | xa += xJumpSpeed; 239 | ya = jumpTime * yJumpSpeed; 240 | jumpTime--; 241 | } 242 | } 243 | else 244 | { 245 | jumpTime = 0; 246 | } 247 | 248 | if (keys[KEY_LEFT] && !ducking) 249 | { 250 | if (facing == 1) sliding = false; 251 | xa -= sideWaysSpeed; 252 | if (jumpTime >= 0) facing = -1; 253 | } 254 | 255 | if (keys[KEY_RIGHT] && !ducking) 256 | { 257 | if (facing == -1) sliding = false; 258 | xa += sideWaysSpeed; 259 | if (jumpTime >= 0) facing = 1; 260 | } 261 | 262 | if ((!keys[KEY_LEFT] && !keys[KEY_RIGHT]) || ducking || ya < 0 || onGround) 263 | { 264 | sliding = false; 265 | } 266 | 267 | if (keys[KEY_SPEED] && canShoot && Mario.fire && world.fireballsOnScreen<2) 268 | { 269 | world.sound.play(Art.samples[Art.SAMPLE_MARIO_FIREBALL], this, 1, 1, 1); 270 | world.addSprite(new Fireball(world, x+facing*6, y-20, facing)); 271 | } 272 | 273 | canShoot = !keys[KEY_SPEED]; 274 | 275 | mayJump = (onGround || sliding) && !keys[KEY_JUMP]; 276 | 277 | xFlipPic = facing == -1; 278 | 279 | runTime += (Math.abs(xa)) + 5; 280 | if (Math.abs(xa) < 0.5f) 281 | { 282 | runTime = 0; 283 | xa = 0; 284 | } 285 | 286 | calcPic(); 287 | 288 | if (sliding) 289 | { 290 | for (int i = 0; i < 1; i++) 291 | { 292 | world.addSprite(new Sparkle((int) (x + Math.random() * 4 - 2) + facing * 8, (int) (y + Math.random() * 4) - 24, (float) (Math.random() * 2 - 1), (float) Math.random() * 1, 0, 1, 5)); 293 | } 294 | ya *= 0.5f; 295 | } 296 | 297 | onGround = false; 298 | move(xa, 0); 299 | move(0, ya); 300 | 301 | if (y > world.level.height * 16 + 16) 302 | { 303 | die(); 304 | } 305 | 306 | if (x < 0) 307 | { 308 | x = 0; 309 | xa = 0; 310 | } 311 | 312 | if (x > world.level.xExit * 16) 313 | { 314 | win(); 315 | } 316 | 317 | if (x > world.level.width * 16) 318 | { 319 | x = world.level.width * 16; 320 | xa = 0; 321 | } 322 | 323 | ya *= 0.85f; 324 | if (onGround) 325 | { 326 | xa *= GROUND_INERTIA; 327 | } 328 | else 329 | { 330 | xa *= AIR_INERTIA; 331 | } 332 | 333 | if (!onGround) 334 | { 335 | ya += 3; 336 | } 337 | 338 | if (carried != null) 339 | { 340 | carried.x = x + facing * 8; 341 | carried.y = y - 2; 342 | if (!keys[KEY_SPEED]) 343 | { 344 | carried.release(this); 345 | carried = null; 346 | } 347 | } 348 | } 349 | 350 | private void calcPic() 351 | { 352 | int runFrame = 0; 353 | 354 | if (large) 355 | { 356 | runFrame = ((int) (runTime / 20)) % 4; 357 | if (runFrame == 3) runFrame = 1; 358 | if (carried == null && Math.abs(xa) > 10) runFrame += 3; 359 | if (carried != null) runFrame += 10; 360 | if (!onGround) 361 | { 362 | if (carried != null) runFrame = 12; 363 | else if (Math.abs(xa) > 10) runFrame = 7; 364 | else runFrame = 6; 365 | } 366 | } 367 | else 368 | { 369 | runFrame = ((int) (runTime / 20)) % 2; 370 | if (carried == null && Math.abs(xa) > 10) runFrame += 2; 371 | if (carried != null) runFrame += 8; 372 | if (!onGround) 373 | { 374 | if (carried != null) runFrame = 9; 375 | else if (Math.abs(xa) > 10) runFrame = 5; 376 | else runFrame = 4; 377 | } 378 | } 379 | 380 | if (onGround && ((facing == -1 && xa > 0) || (facing == 1 && xa < 0))) 381 | { 382 | if (xa > 1 || xa < -1) runFrame = large ? 9 : 7; 383 | 384 | if (xa > 3 || xa < -3) 385 | { 386 | for (int i = 0; i < 3; i++) 387 | { 388 | world.addSprite(new Sparkle((int) (x + Math.random() * 8 - 4), (int) (y + Math.random() * 4), (float) (Math.random() * 2 - 1), (float) Math.random() * -1, 0, 1, 5)); 389 | } 390 | } 391 | } 392 | 393 | if (large) 394 | { 395 | if (ducking) runFrame = 14; 396 | height = ducking ? 12 : 24; 397 | } 398 | else 399 | { 400 | height = 12; 401 | } 402 | 403 | xPic = runFrame; 404 | } 405 | 406 | private boolean move(float xa, float ya) 407 | { 408 | while (xa > 8) 409 | { 410 | if (!move(8, 0)) return false; 411 | xa -= 8; 412 | } 413 | while (xa < -8) 414 | { 415 | if (!move(-8, 0)) return false; 416 | xa += 8; 417 | } 418 | while (ya > 8) 419 | { 420 | if (!move(0, 8)) return false; 421 | ya -= 8; 422 | } 423 | while (ya < -8) 424 | { 425 | if (!move(0, -8)) return false; 426 | ya += 8; 427 | } 428 | 429 | boolean collide = false; 430 | if (ya > 0) 431 | { 432 | if (isBlocking(x + xa - width, y + ya, xa, 0)) collide = true; 433 | else if (isBlocking(x + xa + width, y + ya, xa, 0)) collide = true; 434 | else if (isBlocking(x + xa - width, y + ya + 1, xa, ya)) collide = true; 435 | else if (isBlocking(x + xa + width, y + ya + 1, xa, ya)) collide = true; 436 | } 437 | if (ya < 0) 438 | { 439 | if (isBlocking(x + xa, y + ya - height, xa, ya)) collide = true; 440 | else if (collide || isBlocking(x + xa - width, y + ya - height, xa, ya)) collide = true; 441 | else if (collide || isBlocking(x + xa + width, y + ya - height, xa, ya)) collide = true; 442 | } 443 | if (xa > 0) 444 | { 445 | sliding = true; 446 | if (isBlocking(x + xa + width, y + ya - height, xa, ya)) collide = true; 447 | else sliding = false; 448 | if (isBlocking(x + xa + width, y + ya - height / 2, xa, ya)) collide = true; 449 | else sliding = false; 450 | if (isBlocking(x + xa + width, y + ya, xa, ya)) collide = true; 451 | else sliding = false; 452 | } 453 | if (xa < 0) 454 | { 455 | sliding = true; 456 | if (isBlocking(x + xa - width, y + ya - height, xa, ya)) collide = true; 457 | else sliding = false; 458 | if (isBlocking(x + xa - width, y + ya - height / 2, xa, ya)) collide = true; 459 | else sliding = false; 460 | if (isBlocking(x + xa - width, y + ya, xa, ya)) collide = true; 461 | else sliding = false; 462 | } 463 | 464 | if (collide) 465 | { 466 | if (xa < 0) 467 | { 468 | x = (int) ((x - width) / 16) * 16 + width; 469 | this.xa = 0; 470 | } 471 | if (xa > 0) 472 | { 473 | x = (int) ((x + width) / 16 + 1) * 16 - width - 1; 474 | this.xa = 0; 475 | } 476 | if (ya < 0) 477 | { 478 | y = (int) ((y - height) / 16) * 16 + height; 479 | jumpTime = 0; 480 | this.ya = 0; 481 | } 482 | if (ya > 0) 483 | { 484 | y = (int) ((y - 1) / 16 + 1) * 16 - 1; 485 | onGround = true; 486 | } 487 | return false; 488 | } 489 | else 490 | { 491 | x += xa; 492 | y += ya; 493 | return true; 494 | } 495 | } 496 | 497 | private boolean isBlocking(float _x, float _y, float xa, float ya) 498 | { 499 | int x = (int) (_x / 16); 500 | int y = (int) (_y / 16); 501 | if (x == (int) (this.x / 16) && y == (int) (this.y / 16)) return false; 502 | 503 | boolean blocking = world.level.isBlocking(x, y, xa, ya); 504 | 505 | byte block = world.level.getBlock(x, y); 506 | 507 | if (((Level.TILE_BEHAVIORS[block & 0xff]) & Level.BIT_PICKUPABLE) > 0) 508 | { 509 | Mario.getCoin(); 510 | world.sound.play(Art.samples[Art.SAMPLE_GET_COIN], new FixedSoundSource(x * 16 + 8, y * 16 + 8), 1, 1, 1); 511 | world.level.setBlock(x, y, (byte) 0); 512 | for (int xx = 0; xx < 2; xx++) 513 | for (int yy = 0; yy < 2; yy++) 514 | world.addSprite(new Sparkle(x * 16 + xx * 8 + (int) (Math.random() * 8), y * 16 + yy * 8 + (int) (Math.random() * 8), 0, 0, 0, 2, 5)); 515 | } 516 | 517 | if (blocking && ya < 0) 518 | { 519 | world.bump(x, y, large); 520 | } 521 | 522 | return blocking; 523 | } 524 | 525 | public void stomp(Enemy enemy) 526 | { 527 | if (deathTime > 0 || world.paused) return; 528 | 529 | float targetY = enemy.y - enemy.height / 2; 530 | move(0, targetY - y); 531 | 532 | world.sound.play(Art.samples[Art.SAMPLE_MARIO_KICK], this, 1, 1, 1); 533 | xJumpSpeed = 0; 534 | yJumpSpeed = -1.9f; 535 | jumpTime = 8; 536 | ya = jumpTime * yJumpSpeed; 537 | onGround = false; 538 | sliding = false; 539 | invulnerableTime = 1; 540 | } 541 | 542 | public void stomp(Shell shell) 543 | { 544 | if (deathTime > 0 || world.paused) return; 545 | 546 | if (keys[KEY_SPEED] && shell.facing == 0) 547 | { 548 | carried = shell; 549 | shell.carried = true; 550 | } 551 | else 552 | { 553 | float targetY = shell.y - shell.height / 2; 554 | move(0, targetY - y); 555 | 556 | world.sound.play(Art.samples[Art.SAMPLE_MARIO_KICK], this, 1, 1, 1); 557 | xJumpSpeed = 0; 558 | yJumpSpeed = -1.9f; 559 | jumpTime = 8; 560 | ya = jumpTime * yJumpSpeed; 561 | onGround = false; 562 | sliding = false; 563 | invulnerableTime = 1; 564 | } 565 | } 566 | 567 | public void getHurt() 568 | { 569 | if (deathTime > 0 || world.paused) return; 570 | if (invulnerableTime > 0) return; 571 | 572 | if (large) 573 | { 574 | world.paused = true; 575 | powerUpTime = -3 * 6; 576 | world.sound.play(Art.samples[Art.SAMPLE_MARIO_POWER_DOWN], this, 1, 1, 1); 577 | if (fire) 578 | { 579 | world.mario.setLarge(true, false); 580 | } 581 | else 582 | { 583 | world.mario.setLarge(false, false); 584 | } 585 | invulnerableTime = 32; 586 | } 587 | else 588 | { 589 | die(); 590 | } 591 | } 592 | 593 | private void win() 594 | { 595 | xDeathPos = (int) x; 596 | yDeathPos = (int) y; 597 | world.paused = true; 598 | winTime = 1; 599 | Art.stopMusic(); 600 | world.sound.play(Art.samples[Art.SAMPLE_LEVEL_EXIT], this, 1, 1, 1); 601 | } 602 | 603 | public void die() 604 | { 605 | xDeathPos = (int) x; 606 | yDeathPos = (int) y; 607 | world.paused = true; 608 | deathTime = 1; 609 | Art.stopMusic(); 610 | world.sound.play(Art.samples[Art.SAMPLE_MARIO_DEATH], this, 1, 1, 1); 611 | } 612 | 613 | 614 | public void getFlower() 615 | { 616 | if (deathTime > 0 || world.paused) return; 617 | 618 | if (!fire) 619 | { 620 | world.paused = true; 621 | powerUpTime = 3 * 6; 622 | world.sound.play(Art.samples[Art.SAMPLE_MARIO_POWER_UP], this, 1, 1, 1); 623 | world.mario.setLarge(true, true); 624 | } 625 | else 626 | { 627 | Mario.getCoin(); 628 | world.sound.play(Art.samples[Art.SAMPLE_GET_COIN], this, 1, 1, 1); 629 | } 630 | } 631 | 632 | public void getMushroom() 633 | { 634 | if (deathTime > 0 || world.paused) return; 635 | 636 | if (!large) 637 | { 638 | world.paused = true; 639 | powerUpTime = 3 * 6; 640 | world.sound.play(Art.samples[Art.SAMPLE_MARIO_POWER_UP], this, 1, 1, 1); 641 | world.mario.setLarge(true, false); 642 | } 643 | else 644 | { 645 | Mario.getCoin(); 646 | world.sound.play(Art.samples[Art.SAMPLE_GET_COIN], this, 1, 1, 1); 647 | } 648 | } 649 | 650 | public void kick(Shell shell) 651 | { 652 | if (deathTime > 0 || world.paused) return; 653 | 654 | if (keys[KEY_SPEED]) 655 | { 656 | carried = shell; 657 | shell.carried = true; 658 | } 659 | else 660 | { 661 | world.sound.play(Art.samples[Art.SAMPLE_MARIO_KICK], this, 1, 1, 1); 662 | invulnerableTime = 1; 663 | } 664 | } 665 | 666 | public void stomp(BulletBill bill) 667 | { 668 | if (deathTime > 0 || world.paused) return; 669 | 670 | float targetY = bill.y - bill.height / 2; 671 | move(0, targetY - y); 672 | 673 | world.sound.play(Art.samples[Art.SAMPLE_MARIO_KICK], this, 1, 1, 1); 674 | xJumpSpeed = 0; 675 | yJumpSpeed = -1.9f; 676 | jumpTime = 8; 677 | ya = jumpTime * yJumpSpeed; 678 | onGround = false; 679 | sliding = false; 680 | invulnerableTime = 1; 681 | } 682 | 683 | public byte getKeyMask() 684 | { 685 | int mask = 0; 686 | for (int i = 0; i < 7; i++) 687 | { 688 | if (keys[i]) mask |= (1 << i); 689 | } 690 | return (byte) mask; 691 | } 692 | 693 | public void setKeys(byte mask) 694 | { 695 | for (int i = 0; i < 7; i++) 696 | { 697 | keys[i] = (mask & (1 << i)) > 0; 698 | } 699 | } 700 | 701 | public static void get1Up() 702 | { 703 | instance.world.sound.play(Art.samples[Art.SAMPLE_MARIO_1UP], instance, 1, 1, 1); 704 | lives++; 705 | if (lives==99) 706 | { 707 | lives = 99; 708 | } 709 | } 710 | 711 | public static void getCoin() 712 | { 713 | coins++; 714 | if (coins==100) 715 | { 716 | coins = 0; 717 | get1Up(); 718 | } 719 | } 720 | } --------------------------------------------------------------------------------