Skip to content

Commit

Permalink
- Start fall during crouch on shaking/falling tile
Browse files Browse the repository at this point in the history
- Fix grab and hang straight sound assignment
- Fix room switch during gate bump (crouch and jump up)
- Show second counter after level switch
- Support sneak up of guards
- Prevent guard turn and engarde, if not facing opponent
- Minimal adjust stab and hurt distance
- Fix start fight distance of guard
- Pixel glitches in palace sprites
- Bring Guard above Kid after stabbed
- Add index.html meta information (SEO)
- Describe how to play on Apple Watch
  • Loading branch information
oklemenz committed Jan 11, 2022
1 parent d0e7454 commit c0b5435
Show file tree
Hide file tree
Showing 12 changed files with 93 additions and 34 deletions.
11 changes: 9 additions & 2 deletions README.md
@@ -1,4 +1,4 @@
# Prince of Persia (JavaScript) - princejs.com
# Prince of Persia (JS) - princejs.com

Prince of Persia reimplementation written in HTML5 / JavaScript (MS-DOS version)

Expand All @@ -15,7 +15,7 @@ Prince of Persia reimplementation written in HTML5 / JavaScript (MS-DOS version)
## Play Mobile

- Browser: https://princejs.com
- Use Landscape Mode
- Use Landscape Mode
- Single Tab
- Disable Landscape Tab Bar in Browser Settings
- Add to Home Screen to start as Fullscreen App
Expand All @@ -34,6 +34,13 @@ Prince of Persia reimplementation written in HTML5 / JavaScript (MS-DOS version)
- _Up_: Block
- _Down_: Sheathe

## Play on Apple Watch

- Send mail or message to yourself with body: https://princejs.com
- On Apple Watch open Mail or Message app
- Click included link to open Browser
- Play using Touch Controls like on Mobile

## Play GitHub Version

- Browser: https://oklemenz.github.io/PrinceJS
Expand Down
Binary file modified assets/gfx/palace.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion assets/maps/level8.json
Expand Up @@ -2733,7 +2733,8 @@
"skill": 3,
"colors": 4,
"type": "guard",
"direction": -1
"direction": -1,
"sneak": true
}
],
"events": [
Expand Down
9 changes: 8 additions & 1 deletion converter/index.js
Expand Up @@ -131,7 +131,14 @@ function mergeLevel(level, existingLevel) {
}
}
for (let i = 0; i < level.guards.length; i++) {
mergeProperties(level.guards[i], existingLevel.guards[i], ["type", "active", "visible", "bias", "reverse"]);
mergeProperties(level.guards[i], existingLevel.guards[i], [
"type",
"active",
"visible",
"bias",
"reverse",
"sneak"
]);
}
}

Expand Down
4 changes: 4 additions & 0 deletions index.html
Expand Up @@ -3,6 +3,10 @@
<head>
<title>PrinceJS</title>
<meta charset="UTF-8" />
<meta
name="description"
content="Prince of Persia reimplementation written in HTML5 / JavaScript (MS-DOS version)"
/>
<meta
name="viewport"
content="width=device-width, height=device-height, initial-scale=1.0, maximum-scale=1.0, user-scalable=0.0, viewport-fit=cover"
Expand Down
32 changes: 13 additions & 19 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -27,7 +27,7 @@
"eslint": "^8.6.0",
"eslint-config": "^0.3.0",
"eslint-config-prettier": "^8.3.0",
"http-server": "^14.0.0",
"http-server": "^14.1.0",
"prettier": "^2.5.1",
"xml2json": "^0.12.0"
}
Expand Down
23 changes: 19 additions & 4 deletions src/Enemy.js
Expand Up @@ -21,6 +21,7 @@ PrinceJS.Enemy = function (game, level, location, direction, room, skill, color,
this.strikeTimer = 0;
this.lookBelow = false;
this.startFight = false;
this.sneakUp = false;

this.health = PrinceJS.Enemy.EXTRA_STRENGTH[skill] + PrinceJS.Enemy.STRENGTH[this.level.number];

Expand Down Expand Up @@ -88,9 +89,9 @@ PrinceJS.Enemy.prototype.updateBehaviour = function () {
if (!this.opponent.alive) {
return;
}
if (this.active && !this.startFight && this.opponentCloseRoom(this.opponent, this.room)) {
if (this.willStartFight()) {
PrinceJS.Utils.delayed(() => {
if (this.active && !this.startFight && this.opponentCloseRoom(this.opponent, this.room)) {
if (this.willStartFight()) {
this.startFight = true;
}
}, 500);
Expand Down Expand Up @@ -132,11 +133,21 @@ PrinceJS.Enemy.prototype.updateBehaviour = function () {
}
} else {
if (this.canReachOpponent(this.lookBelow) || this.canSeeOpponent(this.lookBelow)) {
this.engarde();
if (!this.sneakUp || this.facingOpponent()) {
this.engarde();
}
}
}
};

PrinceJS.Enemy.prototype.willStartFight = function () {
return (
this.active &&
!this.startFight &&
(this.opponentCloseRoom(this.opponent, this.room) || Math.abs(this.opponentDistance()) < 35)
);
};

PrinceJS.Enemy.prototype.enemyAdvance = function () {
if (!this.startFight) {
return;
Expand Down Expand Up @@ -256,7 +267,7 @@ PrinceJS.Enemy.prototype.oppInRangeArmed = function (distance) {
if (!this.opponentOnSameLevel()) {
return;
}
if (distance < 10 || distance >= 29) {
if (distance < 10 || distance >= 28) {
this.tryAdvance();
} else {
this.tryBlock();
Expand Down Expand Up @@ -363,6 +374,10 @@ PrinceJS.Enemy.prototype.setInactive = function () {
}
};

PrinceJS.Enemy.prototype.setSneakUp = function () {
this.sneakUp = true;
};

PrinceJS.Enemy.prototype.checkBarrier = function () {
if (!this.alive || this.charName === "shadow") {
return;
Expand Down
22 changes: 20 additions & 2 deletions src/Fighter.js
Expand Up @@ -236,7 +236,8 @@ PrinceJS.Fighter.prototype.checkFight = function () {
!this.facingOpponent() &&
this.x > 0 &&
this.opponent.x > 0 &&
Math.abs(this.x - this.opponent.x) >= 20
Math.abs(this.x - this.opponent.x) >= 20 &&
!this.opponent.sneaks()
) {
this.turn();
}
Expand Down Expand Up @@ -287,7 +288,7 @@ PrinceJS.Fighter.prototype.checkFight = function () {
if (this.frameID(154) || this.frameID(4)) {
let minHurtDistance = this.opponent.swordDrawn ? 12 : 8;
let maxHurtDistance = 29 + (this.opponent.baseCharName === "fatguard" ? 2 : 0);
if ((distance >= minHurtDistance || distance <= 0) && distance < maxHurtDistance) {
if ((distance >= minHurtDistance || distance <= 0) && distance <= maxHurtDistance) {
this.opponent.stabbed();
}
}
Expand Down Expand Up @@ -553,13 +554,26 @@ PrinceJS.Fighter.prototype.stabbed = function () {

if (this.health === 0) {
this.action = "stabkill";
this.bringAboveOpponent();
} else {
this.action = "stabbed";
}

this.showSplash();
};

PrinceJS.Fighter.prototype.bringAboveOpponent = function () {
if (!this.opponent) {
return;
}
let group = this.game.world;
let opponentIndex = group.getIndex(this.opponent);
if (opponentIndex >= 0 && group.getIndex(this) < opponentIndex) {
group.remove(this, false, true);
group.add(this, true, opponentIndex);
}
};

PrinceJS.Fighter.prototype.opponentNextRoom = function (opponent, room) {
return (
this.opponentInSameRoom(opponent, room) ||
Expand Down Expand Up @@ -1300,6 +1314,10 @@ PrinceJS.Fighter.prototype.moveL = function (extended = true) {
);
};

PrinceJS.Fighter.prototype.sneaks = function () {
return ["stand", "turn"].includes(this.action) || this.action.startsWith("step");
};

PrinceJS.Fighter.prototype.getCharBounds = function () {
let f = this.game.cache.getFrameData(this.charName).getFrameByName(this.charName + "-" + this.charFrame);
let x = PrinceJS.Utils.convertX(this.charX + this.charFdx * this.charFace);
Expand Down
3 changes: 3 additions & 0 deletions src/Game.js
Expand Up @@ -65,6 +65,9 @@ PrinceJS.Game.prototype = {
if (data.active === false) {
enemy.setInactive();
}
if (data.sneak === true) {
enemy.setSneakUp();
}
enemy.onInitLife.add((fighter) => {
this.ui.setOpponentLive(fighter);
}, this);
Expand Down
1 change: 1 addition & 0 deletions src/Interface.js
Expand Up @@ -202,6 +202,7 @@ PrinceJS.Interface.prototype = {
this.hideTextTimer = 25;
PrinceJS.Utils.delayed(() => {
if (!this.showTextType || this.showTextType === "level") {
this.hideText();
this.showRegularRemainingTime(true);
}
}, 2000);
Expand Down
17 changes: 13 additions & 4 deletions src/Kid.js
Expand Up @@ -87,7 +87,7 @@ PrinceJS.Kid.prototype.CMD_TAP = function (data) {
if (data.p1 === 1) {
this.game.sound.play("Footsteps");
} else if (data.p1 === 2) {
this.game.sound.play("BumpIntoWallHard");
this.game.sound.play("BumpIntoWallSoft");
}
};

Expand Down Expand Up @@ -226,6 +226,10 @@ PrinceJS.Kid.prototype.updateTimer = function () {
};

PrinceJS.Kid.prototype.updateBehaviour = function () {
if (this.x === 0 && this.y === 0) {
return;
}

if (!this.keyL() && this.faceL()) {
this.allowCrawl = this.allowAdvance = true;
}
Expand Down Expand Up @@ -473,7 +477,8 @@ PrinceJS.Kid.prototype.tryEngarde = function () {
this.dodgeChoppers();

this.level.recheckCurrentRoom();
if (this.opponent && this.opponent.alive && this.opponentDistance() <= 100) {
let engardeDistance = !this.opponent.facingOpponent() && this.opponent.sneakUp ? 35 : 100;
if (this.opponent && this.opponent.alive && this.opponentDistance() <= engardeDistance) {
return this.engarde();
}
return false;
Expand Down Expand Up @@ -557,6 +562,7 @@ PrinceJS.Kid.prototype.grab = function (x) {
this.stopFall();
this.updateBlockXY();
this.action = "hang";
this.game.sound.play("BumpIntoWallHard");
this.processCommand();

let tile = this.level.getTileAt(this.charBlockX, this.charBlockY - 1, this.room);
Expand Down Expand Up @@ -834,7 +840,10 @@ PrinceJS.Kid.prototype.checkFloor = function () {
if (["climbup", "climbdown"].includes(this.action) && ![PrinceJS.Level.TILE_LOOSE_BOARD].includes(tile.element)) {
return;
}
if (["stoop", "strike"].includes(this.action)) {
if (["stoop"].includes(this.action) && ![PrinceJS.Level.TILE_SPACE].includes(tile.element)) {
return;
}
if (["strike"].includes(this.action)) {
return;
}

Expand Down Expand Up @@ -914,7 +923,7 @@ PrinceJS.Kid.prototype.checkRoomChange = function () {
let footX = this.charX + this.charFdx * this.charFace;
let footBlockX = PrinceJS.Utils.convertXtoBlockX(footX);

if (footBlockX >= 9 && this.moveR(false)) {
if (footBlockX >= 9 && (this.moveR(false) || ["bump"].includes(this.action))) {
let cameraRoom = this.room;
if (footX > 142 || (this.swordDrawn && (footX > 130 || footX < 0))) {
// Camera check
Expand Down

0 comments on commit c0b5435

Please sign in to comment.