/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
* Copyright 2008, 2010 Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
* This file is available and licensed under the following license:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * 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.
*
* * Neither the name of Oracle Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* 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
* OWNER 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.
*/
package dukeman;
import javafx.animation.*;
import javafx.scene.*;
import javafx.scene.image.*;
import javafx.scene.input.*;
import javafx.scene.paint.*;
import javafx.scene.text.*;
def BONUS_SCORE = [200, 400, 800, 1600];
def STATE_GET_READY = 1;
def STATE_PLAY = 2;
def STATE_GAME_OVER = 3;
public class Level {
public-init var level: LevelData;
def duke = Duke { }
def keyboardDirection = Direction { };
def enemies = [
Enemy {
type: Enemy.TYPE_0
},
Enemy {
type: Enemy.TYPE_1
},
Enemy {
type: Enemy.TYPE_2
},
Enemy {
type: Enemy.TYPE_3
},
];
def levelCaption = Text {
translateX: Config.SCREEN_WIDTH / 8
translateY: Config.GAME_FIELD_Y / 6
fill: Color.BLACK
font: Font {
name: "Bitstream Vera Sans Bold"
size: if (Config.IS_MOBILE) 12 else 20
}
textOrigin: TextOrigin.TOP
content: "Level {Main.mainFrame.state}"
}
def scoreCaption = Text {
translateX: bind levelCaption.translateX
translateY: Config.GAME_FIELD_Y / 6 + Config.GAME_FIELD_Y / 4
fill: bind levelCaption.fill
font: bind levelCaption.font
textOrigin: TextOrigin.TOP
content: "YOUR SCORE"
}
def scoreValue = Text {
translateX: Config.SCREEN_WIDTH * 2 / 3
translateY: bind scoreCaption.translateY
fill: bind levelCaption.fill
font: bind levelCaption.font
textOrigin: TextOrigin.TOP
}
def highScoreCaption = Text {
translateX: bind levelCaption.translateX
translateY: Config.GAME_FIELD_Y / 6 + Config.GAME_FIELD_Y / 2
fill: bind levelCaption.fill
font: bind levelCaption.font
textOrigin: TextOrigin.TOP
content: "HIGH SCORE"
}
def highScoreValue = Text {
translateX: bind scoreValue.translateX
translateY: bind highScoreCaption.translateY
fill: bind levelCaption.fill
font: bind levelCaption.font
textOrigin: TextOrigin.TOP
content: "{Main.mainFrame.highScore}"
}
def message: ImageView = ImageView {
translateX: bind Config.GAME_FIELD_X + (Config.GAME_FIELD_WIDTH -
message.image.width) / 2
translateY: bind Config.GAME_FIELD_Y +
(level.enemyHome.y + LevelData.ENEMY_HOME_HEIGHT) * Config.CELL_SIZE +
(Config.CELL_SIZE - message.image.height) / 2
}
var state: Integer = STATE_GET_READY;
var stateTime: Duration;
var animatedDots: Dot[];
var bonusIndex: Integer;
var bonuses: Bonus[];
var dotCount: Integer;
var lives: ImageView[];
def group = Group {
translateX: Config.GAME_FIELD_X
translateY: Config.GAME_FIELD_Y
};
public function start() {
def background = ImageView {
focusTraversable: true
image: Config.images[Config.IMAGE_BACKGROUND0 +
(level.levelNumber - 1) mod 3]
onKeyPressed: function( e: KeyEvent ):Void {
if (state == STATE_GAME_OVER) {
Main.mainFrame.state = 0;
} else if (state == STATE_PLAY) {
updateKeyboardDirection(e.code, true)
}
}
}
var content: Node[];
insert [
background,
levelCaption,
scoreCaption,
scoreValue,
highScoreCaption,
highScoreValue
] into content;
for (node in level.maze) {
node.translateX += Config.GAME_FIELD_X;
node.translateY += Config.GAME_FIELD_Y;
insert node into content;
}
for (node in level.dots) {
node.translateX += Config.GAME_FIELD_X;
node.translateY += Config.GAME_FIELD_Y;
insert node into content;
if (not node.small) {
insert node into animatedDots;
}
}
group.content = [
enemies,
duke
];
insert group into content;
insert message into content;
Main.mainFrame.scene.content = content;
dotCount = sizeof level.dots;
timeline.play();
background.requestFocus();
updateScore(0);
updateLives();
startGame();
}
public function stop() {
timeline.stop();
}
function startGame() {
duke.initialize(level);
keyboardDirection.offsetX = 0;
keyboardDirection.offsetY = 0;
for (enemy in enemies) {
enemy.initialize(level);
}
for (bonus in bonuses) {
delete bonus from bonuses;
delete bonus from group.content;
}
state = STATE_GET_READY;
stateTime = 3s;
message.image = Config.images[Config.IMAGE_GET_READY];
message.opacity = 1;
message.visible = true
}
function gameOver() {
state = STATE_GAME_OVER;
message.image = Config.images[Config.IMAGE_GAME_OVER];
message.opacity = 1;
message.visible = true;
if (Main.mainFrame.score > Main.mainFrame.highScore) {
Main.mainFrame.highScore = Main.mainFrame.score
}
}
function updateKeyboardDirection(code: KeyCode, pressed: Boolean) {
var offsetX: Integer;
var offsetY: Integer;
if (code == KeyCode.VK_UP) {
offsetY = -1;
} else if (code == KeyCode.VK_RIGHT) {
offsetX = 1;
} else if (code == KeyCode.VK_DOWN) {
offsetY = 1;
} else if (code == KeyCode.VK_LEFT) {
offsetX = -1;
} else {
return
}
if (pressed) {
keyboardDirection.offsetX = offsetX;
keyboardDirection.offsetY = offsetY;
} else {
if (offsetX != 0) {
keyboardDirection.offsetX = 0;
}
if (offsetY != 0) {
keyboardDirection.offsetY = 0;
}
}
}
function updateScore(inc: Integer) {
var oldScore = Main.mainFrame.score;
Main.mainFrame.score += inc;
scoreValue.content = "{Main.mainFrame.score}";
if (oldScore / 10000 != Main.mainFrame.score / 10000) {
Main.mainFrame.lifeCount++;
updateLives();
}
}
function updateLives() {
while (sizeof lives > Main.mainFrame.lifeCount) {
var life = lives[sizeof lives - 1];
delete life from lives;
delete life from Main.mainFrame.scene.content;
}
for (i in [sizeof lives..<java.lang.Math.min(Main.mainFrame.lifeCount, 9)]) {
var image = Config.images[Config.IMAGE_DUKE_LIVES];
var life = ImageView {
image: Config.images[Config.IMAGE_DUKE_LIVES]
translateX: Config.GAME_FIELD_X + image.width * i
translateY: Config.SCREEN_HEIGHT - Config.BOTTOM_AREA_HEIGHT +
(Config.BOTTOM_AREA_HEIGHT - image.height) / 2
}
insert life into lives;
insert life into Main.mainFrame.scene.content;
}
}
def timeline = Timeline {
repeatCount: Timeline.INDEFINITE
keyFrames : [
KeyFrame {
time: Config.ANIMATION_TIME
action: function () {
for (dot in animatedDots) {
dot.animate();
}
for (bonus in bonuses) {
if (not bonus.animate()) {
delete bonus from bonuses;
delete bonus from group.content;
}
}
if (state == STATE_GET_READY) {
stateTime -= Config.ANIMATION_TIME;
if (stateTime < 1s) {
message.opacity = stateTime.toMillis() / 1000;
}
if (stateTime < 0s) {
state = STATE_PLAY;
message.visible = false;
}
return;
}
if (state == STATE_GAME_OVER) {
return;
}
duke.move(level, keyboardDirection);
def index: Integer = (duke.translateX + Config.CELL_SIZE / 2 as Integer) / Config.CELL_SIZE +
(duke.translateY + Config.CELL_SIZE / 2 as Integer) / Config.CELL_SIZE * LevelData.WIDTH;
var node = level.levelData.elementAt(index) as Node;
if (node instanceof Dot) {
level.levelData.setElementAt(null, index);
if ((node as Dot).small) {
updateScore(10);
} else {
bonusIndex = 0;
updateScore(50);
for (enemy in enemies) {
enemy.setState(Enemy.STATE_SAFE);
}
}
node.visible = false;
delete node as Dot from animatedDots;
dotCount--;
if (dotCount == 0) {
Main.mainFrame.state++;
return;
}
}
for (enemy in enemies) {
enemy.move(level, duke);
if (duke.isIntersected(enemy)) {
if (enemy.state == Enemy.STATE_HUNTING) {
Main.mainFrame.lifeCount--;
if (Main.mainFrame.lifeCount < 0) {
gameOver();
} else {
updateLives();
startGame();
}
return
} else if (enemy.state == Enemy.STATE_SAFE) {
enemy.setState(Enemy.STATE_DEFEAT);
updateScore(BONUS_SCORE[bonusIndex]);
var bonus = Bonus {
type: Config.IMAGE_BONUS_200 + bonusIndex
translateX: enemy.translateX
translateY: enemy.translateY
}
insert bonus into bonuses;
insert bonus before group.content[0];
bonusIndex++
}
}
}
}
}
]
}
}