/* @pjs crisp=true; preload="bar_bg.png, bar_fg.png, circle.png, coltan_goal_black.png, finger.png, intro_bg.png, mine_bg.png, mine_fg.png, mineral.png, slave_fearing.png, slave_idling.png, slave_working.png, slave_working0.png, slave_working1.png, slave_working2.png, slave_working3.png, slave_working4.png, slave_working5.png, slave_working6.png, slave_working7.png, slave_working_flipped.png, soldier_intimidate.png, soldier_stand.png, soldier_walk_down.png, soldier_walk_down0.png, soldier_walk_down1.png, soldier_walk_down2.png, soldier_walk_down3.png, soldier_walk_down4.png, soldier_walk_down5.png, soldier_walk_up.png, soldier_walk_up0.png, soldier_walk_up1.png, soldier_walk_up2.png, soldier_walk_up3.png, soldier_walk_up4.png, soldier_walk_up5.png, title.png"; */ /** This is a Web Standard version of PhoneStory
Processing code by DW dw@mondonerd.com
This software is licensed under GPL v.3
Graphical resources under Creative Commons BY-NC-SA 2011 **/ PImage introBg, title, bg, fg, barBg, barFg, barGoal; Animation[] animations = new Animation[9]; Soldier[] soldiers = new Soldier[2]; Slave[] slaves = new Slave[10]; Sprite[] minerals = new Sprite[3]; Sprite[] fingers = new Sprite[2]; Sprite circle; int[][] leftRow = new int[4][2]; int SOLDIER_STANDING = 0; int SOLDIER_WALK_UP = 1; int SOLDIER_WALK_DOWN = 2; int SOLDIER_INTIMIDATING = 3; int SLAVE_WORKING = 0; int SLAVE_IDLING = 1; int SLAVE_FEARING = 2; boolean intro = true; boolean showingScore = false; float lastIdle; float nextIdle = 3000; float counterGoalProduction = 0; float counterCurrentProduction = 0; float goalProductionStep = 0.02; int lastScore, highScore; boolean tutorialEnded = false; boolean tutorialExit = false; float circleFrameTimer; float scoreTimer; boolean circleShowing = false; PFont font; void setup() { size(160, 240); frameRate(20); font = loadFont("phonestoryfont.vlw"); textFont(font, 10); textMode(CENTER); bg = loadImage("mine_bg.png"); fg = loadImage("mine_fg.png"); barBg = loadImage("bar_bg.png"); barFg = loadImage("bar_fg.png"); barGoal = loadImage("coltan_goal_black.png"); introBg = loadImage("intro_bg.png"); title = loadImage("title.png"); animations[0] = new Animation("soldier_walk_down", 6); animations[1] = new Animation("soldier_walk_up", 6); animations[2] = new Animation("soldier_walk_down", 1); animations[3] = new Animation("slave_working", 8); animations[4] = new Animation("slave_idling.png", 30, 25); animations[5] = new Animation("soldier_intimidate.png", 34, 52); animations[6] = new Animation("mineral.png", 13, 8); animations[7] = new Animation("circle.png", 44, 44); animations[8] = new Animation("finger.png", 105, 107); soldiers[0] = new Soldier(); soldiers[0].setPosition(25, 70); soldiers[1] = new Soldier(); soldiers[1].setPosition(140, 100); soldiers[1].flipped = true; for (int i = 0; i < minerals.length; i++) { minerals[i] = new Sprite(); minerals[i].sprites = animations[6]; } minerals[0].setPosition(65, 76); minerals[1].setPosition(95, 136); minerals[2].setPosition(92, 215); setupSlaves(); setupTutorial(); initLevel(); } void setupTutorial() { fingers[0] = new Sprite(); fingers[1] = new Sprite(); fingers[0].setPosition(-40, 170); fingers[0].flipped = true; fingers[1].setPosition(200, 270); fingers[0].sprites = animations[8]; fingers[1].sprites = animations[8]; circle = new Sprite(); circle.setPosition(93, 92); circle.sprites = animations[7]; } void renderTutorial() { if (tutorialEnded) return; if (!tutorialExit) { if (fingers[0].position.x < -20) { fingers[0].position.x += 2; fingers[1].position.x -= 2; } else if (fingers[0].position.y < 270) { fingers[0].position.y += 2; fingers[1].position.y -= 2; } else { tutorialExit = true; } } else { if (fingers[0].position.x > -60) { fingers[0].position.x -= 4; fingers[1].position.x += 4; } else { tutorialEnded = true; } } fingers[0].render(); fingers[1].render(); if (millis() - circleFrameTimer > 500) { circleShowing = !circleShowing; circleFrameTimer = millis(); } if (circleShowing) circle.render(); } void setupSlaves() { for (int i = 0; i < slaves.length; i++) { slaves[i] = new Slave(); if (i > 4) { slaves[i].flipped = true; } else { slaves[i].flipped = false; } } slaves[0].setPosition(122 / 2 -15, 122 / 2 -25); slaves[1].setPosition(130 / 2 -15, 208 / 2 -25); slaves[2].setPosition(118 / 2 -15, 286 / 2 -25); slaves[3].setPosition(120 / 2 -15, 362 / 2 -25); slaves[4].setPosition(118 / 2 -15, 432 / 2 -25); slaves[5].setPosition(210 / 2 -15, 96 / 2 -25); slaves[6].setPosition(190 / 2 -15, 162 / 2 -25); slaves[7].setPosition(198 / 2 -15, 240 / 2 -25); slaves[8].setPosition(192 / 2 -15, 330 / 2 -25); slaves[9].setPosition(202 / 2 -15, 400 / 2 -25); slaves[6].setState(SLAVE_IDLING); } void initLevel() { counterGoalProduction = 0; counterCurrentProduction = 0; } void winLevel() { showingScore = true; lastScore = int(counterCurrentProduction - counterGoalProduction); if (highScore < lastScore) highScore = lastScore; setupSlaves(); scoreTimer = millis(); initLevel(); } void gameOver() { intro = true; setupSlaves(); initLevel(); } void updateScore() { if (counterCurrentProduction < 0) counterCurrentProduction = 0; counterGoalProduction += goalProductionStep * slaves.length; if (counterGoalProduction >= 100) if (counterCurrentProduction < 100) gameOver(); else winLevel(); } void draw() { if (intro) { background(introBg); image(title, width * .5 - title.width * .5, height * .5 - title.height * .5); return; } else if (showingScore) { background(introBg); text("YOUR SCORE", 30, height * .3); text(lastScore, 30, height * .4); text("YOUR HIGHSCORE", 30, height * .6); text(highScore, 30, height * .7); return; } updateScore(); background(bg); soldiers[0].update(); soldiers[1].update(); boolean soldierRightAggressive = (soldiers[1].state == SOLDIER_INTIMIDATING); boolean soldierLeftAggressive = (soldiers[0].state == SOLDIER_INTIMIDATING); int offSet = int(random(0, slaves.length - 1)); for (int i = offSet; i < slaves.length; i++) { if (slaves[i].state != SLAVE_IDLING && millis() - lastIdle > nextIdle) { slaves[i].state = SLAVE_IDLING; nextIdle = random(1000, 5000); lastIdle = millis(); } } for (int i = 0; i < minerals.length; i++) { minerals[i].render(); } for (int i = 0; i < slaves.length; i++) { slaves[i].update(); if (slaves[i].state == SLAVE_IDLING) { if (i > 4) { if (soldierRightAggressive && abs(soldiers[1].position.y -25 - slaves[i].position.y) < 20) { slaves[i].state = SLAVE_WORKING; } } else { if (soldierLeftAggressive && abs(soldiers[0].position.y -25 - slaves[i].position.y) < 20) { slaves[i].state = SLAVE_WORKING; } } } slaves[i].update(); slaves[i].render(); } soldiers[0].render(); soldiers[1].render(); image(fg, 0, 0); renderScore(); renderTutorial(); } void renderScore() { image(barBg, 29, 230); if (counterCurrentProduction < 100 && counterCurrentProduction > 0) image(barFg, 30, 231, counterCurrentProduction, 2); else if (counterCurrentProduction >= 100) image(barFg, 30, 231, 100, 2); image(barGoal, 30 + counterGoalProduction - barGoal.width / 2, 231); } void mousePressed() { if (intro) { intro = false; return; } else if (showingScore && millis() - scoreTimer > 2000) { showingScore = false; } int selectedSlave = -1; float minimumDistance = 30; for (int i = 0; i < slaves.length; i++) { float currentDistanceFromMouse = dist(slaves[i].position.x + 12, slaves[i].position.y + 25, mouseX, mouseY); if (currentDistanceFromMouse < minimumDistance) { minimumDistance = currentDistanceFromMouse; selectedSlave = i; } } if (selectedSlave < 0) return; if (mouseX < width * .5) soldiers[0].setTargetPosition(slaves[selectedSlave].position.x + 12, slaves[selectedSlave].position.y + 25); else soldiers[1].setTargetPosition(slaves[selectedSlave].position.x + 12, slaves[selectedSlave].position.y + 25); } class Animation { PImage[] images; int imageCount; String imagePrefix; Animation(String _imagePrefix, int count) { imagePrefix = _imagePrefix; imageCount = count; images = new PImage[imageCount]; for (int i = 0; i < imageCount; i++) { // Use nf() to number format 'i' into four digits String filename = imagePrefix + i + ".png"; images[i] = loadImage(filename); } } Animation(String imageURI, int frameWidth, int frameHeight) { PImage tempImage = loadImage(imageURI); imageCount = tempImage.width / frameWidth; images = new PImage[imageCount]; for (int i = 0; i < imageCount; i++) { images[i] = createImage(frameWidth, frameHeight, ARGB); images[i].copy(tempImage, frameWidth * i, 0, frameWidth, frameHeight, 0, 0, frameWidth, frameHeight); } } void display(float xpos, float ypos, int currentFrame) { currentFrame %= imageCount; image(images[currentFrame], xpos, ypos); } void display(float xpos, float ypos, boolean flipped, int currentFrame) { currentFrame %= imageCount; if (!flipped) { image(images[currentFrame], xpos, ypos); } else { pushMatrix(); translate(xpos, ypos); scale(-1, 1); image(images[currentFrame], -images[currentFrame].width, 0); popMatrix(); } } int getWidth() { return images[0].width; } int getHeight() { return images[0].height; } } class Slave extends Sprite { void update() { if (state == SLAVE_WORKING) { counterCurrentProduction += .02; } if (state == SLAVE_IDLING) { counterCurrentProduction -= .03; } } void setState(int newState) { state = newState; } void render() { currentFrame++; int currentX = int(position.x); int currentY = int(position.y); if (state == SLAVE_WORKING) { animations[3].display(currentX, currentY, flipped, currentFrame); } if (state == SLAVE_IDLING) { animations[4].display(currentX, currentY, flipped, currentFrame); } } } class Soldier extends Sprite { float intimidatingTimer; void render() { currentFrame++; int currentX = int(position.x) - (animations[0].getWidth() / 2); int currentY = int(position.y) - animations[0].getHeight(); if (state == SOLDIER_WALK_UP) animations[0].display(currentX, currentY, flipped, currentFrame); else if (state == SOLDIER_WALK_DOWN) animations[1].display(currentX, currentY, flipped, currentFrame); else if (state == SOLDIER_STANDING) animations[2].display(currentX, currentY, flipped, currentFrame); else if (state == SOLDIER_INTIMIDATING) animations[5].display(currentX, currentY, flipped, currentFrame); } void update() { if (state == SOLDIER_INTIMIDATING && millis() - intimidatingTimer > 2000) { state = SOLDIER_STANDING; } float distanceFromTarget = abs(position.y - positionTarget.y); if (distanceFromTarget > 5) { position.y += (positionTarget.y - position.y) * easying; if (position.y < positionTarget.y) { state = SOLDIER_WALK_UP; } else { state = SOLDIER_WALK_DOWN; } } else if (state == SOLDIER_WALK_DOWN || state == SOLDIER_WALK_UP) { state = SOLDIER_INTIMIDATING; intimidatingTimer = millis(); } } } class Sprite { int state = 0; boolean flipped = false; PVector position = new PVector(); PVector positionTarget = new PVector(); float easying = .1; int currentFrame; Animation sprites; Sprite() { } void render() { if (sprites == null) return; int currentX = int(position.x) - (sprites.getWidth() / 2); int currentY = int(position.y) - sprites.getHeight(); sprites.display(currentX, currentY, flipped, currentFrame); } void setPosition(float x, float y) { position.x = x; position.y = y; positionTarget.x = x; positionTarget.y = y; } void setTargetPosition(float x, float y) { positionTarget.x = x; positionTarget.y = y; } }