BImage tilesImg, characterImg, bgImg, logoImg, panelImg, smalldudeImg; String levels[], bhlevels[], bhpractice[]; Level level; boolean onMenu = true; boolean gameover = false; void setup() { size(320,200); framerate(20); tilesImg = loadImage("tiles.gif"); characterImg = loadImage("character.gif"); bgImg = loadImage("bg.gif"); logoImg = loadImage("logo.gif"); panelImg = loadImage("panel.gif"); smalldudeImg = loadImage("smalldude.gif"); smalldudeImg.alpha(loadImage("smalldudea.gif")); levels = bhlevels = loadStrings("bhlevels.txt"); bhpractice = loadStrings("bhpractice.txt"); credits = loadStrings("credits.txt"); hint (DISABLE_TEXT_SMOOTH); textFont( loadFont("acknowledge.vlw"), 16); loadLevel(-1); if (online()) viewsize(getSize().width, getSize().height); } public int viewwidth,viewheight; protected boolean viewstretching = false; public void viewsize(int width, int height) { this.viewwidth = width; this.viewheight = height; viewstretching = this.width != width || this.height != height; update(); } public void paint(Graphics g1) { g.mis.newPixels(pixels, g.cm, 0, width); if (g != null) { if (viewstretching) g1.drawImage(g.image, 0, 0, viewwidth, viewheight, null); else g1.drawImage(g.image, 0, 0, null); } } int score = 0, moves = 0, time = 0, lastTime = 0, totalmoves = 0, totaltime = 0; void reset() { score = 0; onMenu = true; levels = bhlevels; loadLevel(-1); demoPosition=0; logoy=0; logody=0; totalmoves = 0; totaltime = 0; creditPosition = 0; gameover = false; } void loadLevel(int di) { if (di<0) leveli=0; else leveli += di; int i=leveli*2; i++; if (i+1>=levels.length) { gameover = true; leveli--; return; } level = new Level(levels[i], levels[i+1]); if (di!=0) { moves = 0; time = 30; lastTime = millis(); } } float logoy=0,logody=0; int demoStep = 0; int demoPosition = 0; int creditPosition = 0; void mouseDragged() { creditPosition += viewstretching ? ((pmouseY-mouseY)*height/viewheight) : pmouseY-mouseY; } int leveli = 0; boolean onHelp = false; void shadowText(String s, int x, int y) { fill(255); text(s,x+1,y+1); fill(0); text(s,x,y); } String credits[]; void loop() { if (onMenu && demoStep--<=0) { demoStep = 5; switch (levels[0].charAt(demoPosition++)) { case 'N': level.input(UP); break; case 'S': level.input(DOWN); break; case 'W': level.input(LEFT); break; case 'E': level.input(RIGHT); break; } if (level.foundExit) loadLevel(+1); if (demoPosition>=levels[0].length()) { demoPosition = 0; loadLevel(-1); } } if (!level.foundExit && !gameover) { if (millis()-lastTime>1000) { lastTime = millis(); if (time>0) time--; totaltime++; } } level.update(); push(); translate(20,20); level.draw(); pop(); if (onMenu || onHelp) { fill(255,255,255,80); noStroke(); rect(20,20,200,160); } for (int x=0;x<12;x++) { image(bgImg,x*20,0); image(bgImg,x*20,180); } for (int y=0;y<10;y++) { image(bgImg,0,y*20); image(bgImg,220,y*20); } stroke(0); noFill(); rect(19,19,201,161); rect(0,0,239,199); if (onMenu) { if (!mousePressed) creditPosition++; final int spacing = 12; textMode(ALIGN_CENTER); for (int i=0; i=20 && y<180) { int fade = y<=40 ? (y-20)*255/20 : (y>=160 ? (180-y)*255/20 : 255); fill(255,fade); final int x = 120; text(credits[i],x+1,y+1); text(credits[i],x+2,y+2); fill(0,fade); text(credits[i],x,y); } } if (creditPosition>=160*2+spacing*credits.length) creditPosition = 0; logody+=0.6; logoy+=logody; if (logoy>=150) { logoy=150; logody *= -0.5; } image (logoImg, 20, logoy-120); } if (onHelp) { fill(255,255,255,200); noStroke(); rect(20,20,200,160); textMode(ALIGN_LEFT); String help[] = { "Blockhead v1.0 Help", "", "The objective of Blockhead is", "to reach the goal in the fewest", "number of moves possible.", "", "Left/Right - Move character", "Up/Down - Lift/drop boxes", "Shift+Arrow - Scroll", "R - Restart the current level", "Q - End the game", "", "Press any key to return." }; int y=30; for (int i=0; i0) shadowText(help[i],25,y); y+=12; } } image(panelImg, 240, 0); if (!onMenu) { textMode(ALIGN_CENTER); fill(0); text(level.name,121,194); fill(255); text(level.name,120,193); fill(0); textMode(ALIGN_LEFT); text("Level:", 245, 60); text("Score:", 245, 80); text("Par:", 245, 100); text("Moves:", 245,120); text("Time Bonus:", 245, 140); textMode(ALIGN_RIGHT); text(""+(leveli+1), 316, 70); text(""+score, 316, 90); text(""+level.par, 316, 110); text(""+moves, 316, 130); text(""+time, 316, 150); } if (onMenu && !onHelp) { textMode(ALIGN_CENTER); fill(0); text("Press any key to start",121,194); fill(255); text("Press any key to start",120,193); } fill(0); textMode(ALIGN_LEFT); text(onMenu ? "P: Practice" : "R: Restart", 244, 172); text("H: Help", 244, 182); image(smalldudeImg, 200, 130); } /* void mousePressed() { if (onMenu) { onMenu = false; loadLevel(-1); } } */ boolean shiftDown = false; public void keyPressed(KeyEvent e) { super.keyPressed(e); int code = e.getKeyCode(); shiftDown=e.isShiftDown(); if (onHelp) { onHelp = false; } else if (code==KeyEvent.VK_H) { onHelp = true; } else if (onMenu) { levels = code==KeyEvent.VK_P ? bhpractice : bhlevels; onMenu = false; loadLevel(-1); } else level.input(code); } public void keyReleased(KeyEvent e) { super.keyReleased(e); shiftDown=e.isShiftDown(); } final static byte EMPTY = 0; final static byte EMPTY2 = 1; final static byte WALL = 2; final static byte DECAL = 3; final static byte WATER = 4; final static byte WATERTOP = 5; final static byte ITEM = 6; final static byte EXIT = 6; final static byte BOX = 7; final static byte BOX2 = 8; final static byte CLOCK = 9; final static byte PLAYER = 10; class Level { String name; int par = 0; int tileset = 0; int width, height; byte tiles[] = new byte[99*99]; byte items[] = new byte[99*99]; int viewx=0, viewy=0; Level(String info, String data) { tileset = info.charAt(0)-'0'; par = (info.charAt(1)-'0')*100+ (info.charAt(2)-'0')*10+ (info.charAt(3)-'0'); name = info.substring(4); int i = 0; int x = 0; int y = 0; while (iwidth) width = x; x=0; y++; height++; continue; case 'S': playerx=x; playery=y; x++; continue; case ' ': fill = EMPTY; break; case '.': fill = DECAL; break; case '#': fill = WALL; break; case 'W': fill = WATER; break; case 'w': fill = WATERTOP; break; case 'B': fill = BOX; break; case 'C': fill = CLOCK; break; case 'F': fill = EXIT; setView(x,y); break; } if (isNum(a)) { String count = ""+a; i++; if (isNum(b)) { count+=b; i++; } try { int length = Integer.parseInt(count,10); while (length-->0) { if (fill>=ITEM) setItem(x++,y,fill); else setTile(x++,y,fill); } } catch (Exception e) {} } else { if (fill>=ITEM) setItem(x++,y,fill); else setTile(x++,y,fill); } } while (!isObstacle(playerx,playery+1)) { checkPlayer(); playery++; } } void setView(int x, int y) { viewx=x-5; viewy=y-4; if (viewx<0) viewx=0; if (viewx>width-10) viewx=width-10; if (viewy<0) viewy=0; if (viewy>height-8) viewy=height-8; } void slideView(int x, int y) { int vx = viewx+5; int vy = viewy+4; if (xvx) vx++; if (yvy) vy++; setView(vx,vy); } void setTile(int x, int y, byte type) { tiles[x+y*99] = type; } byte getTile(int x, int y) { if (x<0||y<0||x>=width||y>=height) return WALL; return tiles[x+y*99]; } void setItem(int x, int y, byte type) { items[x+y*99] = type; } byte getItem(int x, int y) { if (x<0||y<0||x>=width||y>=height) return 0; return items[x+y*99]; } boolean isNum(char c) { return c>='0' && c<='9'; } boolean isObstacle(int x, int y) { return getTile(x,y)==WALL || getItem(x,y)==BOX || getItem(x,y)==BOX2; } boolean isBlockObstacle(int x, int y) { return isObstacle(x,y) || getTile(x,y)==WATER; } boolean canPickup(int x, int y) { return (getItem(x,y)==BOX || getItem(x,y)==BOX2) && !isObstacle(x,y-1); } boolean facingRight = true; boolean holdingBox = false; int step = 0; int playerx = 0, playery = 0; boolean box2 = false; boolean foundExit = false; void update() { if (step>0) step--; if (score2=1) score2+=diff; else score2++; } if (!shiftDown) slideView(playerx,playery); } void input(int key) { if (gameover) { reset(); } if (key==KeyEvent.VK_Q) gameover = true; if (foundExit) { if (key==KeyEvent.VK_ENTER || key==KeyEvent.VK_SPACE) loadLevel(+1); return; } int x; if (shiftDown) { switch (key) { case UP: slideView(viewx+5,viewy+3); break; case DOWN: slideView(viewx+5,viewy+5); break; case LEFT: slideView(viewx+4,viewy+4); break; case RIGHT: slideView(viewx+6,viewy+4); break; } return; } switch (key) { case UP: if (holdingBox) break; x = playerx + (facingRight?1:-1); if (canPickup(x,playery) && !isObstacle(playerx,playery-1)) { box2 = getItem(x,playery)==BOX; setItem(x,playery,EMPTY); holdingBox = true; moves++; } break; case DOWN: if (!holdingBox) break; x = playerx + (facingRight?1:-1); if (!isObstacle(x,playery-1)) { int y = isObstacle(x,playery) ? playery-1 : playery; if (isObstacle(x,playery)) box2 = !box2; while (!isBlockObstacle(x,y+1)) y++; if (y 0 ? -3 : 3; if (!isObstacle(playerx-1,playery) && (!holdingBox || !isObstacle(playerx-1,playery-1))) { playerx--; moves++; } else if (!facingRight && !isObstacle(playerx,playery-1) && !isObstacle(playerx-1,playery-1) && (!holdingBox || (!isObstacle(playerx-1,playery-2)&&!isObstacle(playerx,playery-2)))) { playerx--; playery--; moves++; } facingRight = false; break; case RIGHT: step= step > 0 ? -3 : 3; if (!isObstacle(playerx+1,playery) && (!holdingBox || !isObstacle(playerx+1,playery-1))) { playerx++; moves++; } else if (facingRight && !isObstacle(playerx,playery-1) && !isObstacle(playerx+1,playery-1) && (!holdingBox || (!isObstacle(playerx+1,playery-2)&&!isObstacle(playerx,playery-2)))) { playerx++; playery--; moves++; } facingRight = true; break; case KeyEvent.VK_R: loadLevel(0); break; case KeyEvent.VK_N: loadLevel(+1); score = 0; totalmoves += 1000; totaltime += 1000; break; } while (!isObstacle(playerx,playery+1)) { checkPlayer(); playery++; } checkPlayer(); } int score2 = 0; void checkPlayer() { if (getItem(playerx,playery)==EXIT && !foundExit) { foundExit = true; score += max(0,par - moves) + time; totalmoves+=moves; } if (getItem(playerx,playery)==CLOCK) { setItem(playerx,playery,EMPTY); time+=15; } } void drawTile(int x, int y, int tile) { image(tilesImg, 20*x, 20*y, 20, 20, tile*20, tileset*20, (tile+1)*20, (tileset+1)*20); } void drawCharacter(int x, int y, int tile) { image(characterImg, 20*x, 20*y, 20, 20, tile*20, tileset*20, (tile+1)*20, (tileset+1)*20); } void draw() { push(); translate(-viewx*20,-viewy*20); for (int y=viewy; y0) frame++; if (!foundExit && holdingBox) { drawTile(playerx,playery-1,box2?BOX2:BOX); frame+=2; } drawCharacter(playerx,playery, frame); } pop(); if (foundExit || gameover) { fill(255,255,255,180); noStroke(); rect(0,0,200,160); image(logoImg, 0,0); textMode(ALIGN_CENTER); shadowText(gameover ? "Game Over!" : "Level Complete!", 100, 95); shadowText("Press Enter to continue...", 100,153); textMode(ALIGN_LEFT); shadowText(gameover ? "Final Score:" : "Score:", 40, 112); shadowText(gameover ? "Total Moves:" : "Move Bonus:", 40, 122); shadowText(gameover ? "Total Time:" : "Time Bonus:", 40, 132); textMode(ALIGN_RIGHT); shadowText(""+score2, 160, 112); shadowText(""+(gameover ? totalmoves : max(0,par-moves)), 160, 122); shadowText(""+(gameover ? totaltime : time), 160, 132); } } }