Lode Runner v2.30e, AI_VERSION=4

The major change is adding a backup and restore feature for "custom levels".
Cette révision appartient à :
simon_hung
2025-03-26 22:30:17 +08:00
Parent f1a67fb54a
révision 24a7cc1749
23 fichiers modifiés avec 2194 ajouts et 206 suppressions
+22 -19
Voir le fichier
@@ -1,4 +1,4 @@
<a target="_blank" href="http://loderunnerwebgame.com/LodeRunner/">Lode Runner - Total Recall</a>
Lode Runner - Total Recall
=======================================
## (超級運動員 - 全面回憶)
@@ -7,19 +7,19 @@ This program build with Javascript + [CreateJS](http://www.createjs.com).
### * 3 GAME Mode & 1 DEMO Mode
<table>
<tr>
<td><b>(1) Challenge Mode</b></td>
<td><b>1. Challenge Mode</b></td>
<td>Compete with other players.</td>
</tr>
<tr>
<td><b>(2) Training Mode</b></td>
<td><b>2. Training Mode</b></td>
<td>Player can select any levels</td>
</tr>
<tr>
<td><b>(3) Edit Mode</b></td>
<td><b>3. Edit Mode</b></td>
<td>Player can create custom levels</td>
</tr>
<tr>
<td><b>(4) Demo Mode</b></td>
<td><b>4. Demo Mode</b></td>
<td>Demo passed levels</td>
</tr>
@@ -28,45 +28,45 @@ This program build with Javascript + [CreateJS](http://www.createjs.com).
### * Include 5 Game Versions
<table>
<tr>
<td><b>(1) <a target="_blank" href="https://en.wikipedia.org/wiki/Lode_Runner">Classic Lode Runner</a></b></td>
<td><b>1. <a target="_blank" href="https://en.wikipedia.org/wiki/Lode_Runner">Classic Lode Runner</a></b></td>
<td>(150 Levels)</td>
<td>Difficulty: 3</td>
</tr>
<tr>
<td><b>(2) <a target="_blank" href="http://www.gb64.com/game.php?id=5906&d=42">Professional Lode Runner</a></b></td>
<td><b>2. <a target="_blank" href="http://www.gb64.com/game.php?id=5906&d=42">Professional Lode Runner</a></b></td>
<td>(150 Levels)</td>
<td>Difficulty: 4</td>
</tr>
<tr>
<td><b>(3) <a target="_blank" href="http://www.vizzed.com/play/revenge-of-lode-runner-appleii-online-apple-ii-6223-game">Revenge of Lode Runner</a></b></td>
<td><b>3. <a target="_blank" href="http://www.vizzed.com/play/revenge-of-lode-runner-appleii-online-apple-ii-6223-game">Revenge of Lode Runner</a></b></td>
<td>(17 Levels)</td>
<td>Difficulty: 4</td>
</tr>
<tr>
<td><b>(4) <a target="_blank" href="http://www.spoonbillsoftware.com.au/loderunner.htm">Lode Runner Fan Book</a></b></td>
<td><b>4. <a target="_blank" href="http://www.spoonbillsoftware.com.au/loderunner.htm">Lode Runner Fan Book</a></b></td>
<td>(66 Levels)</td>
<td>Difficulty: 5</td>
</tr>
<tr>
<td><b>(5) <a target="_blank" href="https://en.wikipedia.org/wiki/Championship_Lode_Runner">Championship Lode Runner</a></b></td>
<td><b>5. <a target="_blank" href="https://en.wikipedia.org/wiki/Championship_Lode_Runner">Championship Lode Runner</a></b></td>
<td>(51 Levels)</td>
<td>Difficulty: 5</td>
</tr>
</table>
### * Provide 2 Theme
### * Provide 2 Themes
<table>
<tr>
<td valign="middle">(1)</td>
<td valign="middle">1.</td>
<td valign="middle"><img src="image/apple2.png" height="23" width="20"></td>
<td><b>APPLE-II</b></td>
</tr>
<tr>
<td valign="middle">(2)</td>
<td valign="middle">2.</td>
<td valign="middle"><img src="image/commodore64.png" height="23" width="20"></td>
<td valign="middle"><b>Commodore 64</b></td>
</tr>
@@ -76,19 +76,22 @@ This program build with Javascript + [CreateJS](http://www.createjs.com).
<table>
<tr>
<td valign="middle">(1)</td>
<td valign="middle">1.</td>
<td valign="middle"><img src="image/repeatOn.png" height="24" width="24"></td>
<td valign="middle"><b>Repeat Actions On:</b> Like APPLE-II keyboard behavior</td>
</tr>
<tr>
<td valign="middle">(2)</td>
<td valign="middle">2.</td>
<td valign="middle"><img src="image/repeatOff.png" height="24" width="24"></td>
<td valign="middle"><b>Repeat Actions Off:</b> Like NES keyboard behavior</td>
</tr>
</table>
### * PLAY
<a target="_blank" href="https://loderunnerwebgame.com/game/">https://loderunnerwebgame.com/game/</a>
### * Play on a Local Machine
#### A simple web server is required to play LoderRunner on a local machine; follow these instructions for Windows:
1. Download and extract the source code into a directory.
2. If Python is installed, open a command prompt, navigate to the LodeRunner directory, and run "`python -m http.server 8080`" to start an HTTP server.
3. Alternatively, download `sswws.zip` from [here](https://github.com/faustinoaq/sswws/releases/tag/v0.1.0), extract it into the LodeRunner directory, and run "`sswws.exe -p 8080`" from the command prompt.
4. Open a web browser and go to "`http://127.0.0.1:8080/lodeRunner.html`".
##### <font color="red">Note:</font><font color="blue"> Changing the HTTP port will cause the browser to store "status" or "custom levels" data in a separate storage.</font>
------------------------------------
BIN
Voir le fichier
Fichier binaire non affiché.

Avant

Largeur:  |  Hauteur:  |  Taille: 191 B

Après

Largeur:  |  Hauteur:  |  Taille: 239 B

BIN
Voir le fichier
Fichier binaire non affiché.

Après

Largeur:  |  Hauteur:  |  Taille: 229 B

BIN
Voir le fichier
Fichier binaire non affiché.

Après

Largeur:  |  Hauteur:  |  Taille: 1.9 KiB

BIN
Voir le fichier
Fichier binaire non affiché.

Après

Largeur:  |  Hauteur:  |  Taille: 259 B

BIN
Voir le fichier
Fichier binaire non affiché.

Après

Largeur:  |  Hauteur:  |  Taille: 233 B

+8 -1
Voir le fichier
@@ -141,12 +141,19 @@ function changeColor(canvas, oldColor, newColor)
var data = imgData.data;
var bitChanged = 0;
// add a range compare for fix browser (Brave) color have bit different ?, 6/3/2021
var oldMin = [oldColor[0]-2, oldColor[1]-2, oldColor[2]-2];
var oldMax = [oldColor[0]+2, oldColor[1]+2, oldColor[2]+2];
for (var i = 0; i < data.length; i += 4) {
var red = data[i + 0];
var green = data[i + 1];
var blue = data[i + 2];
var alpha = data[i + 3];
if(oldColor[0] == red && oldColor[1] == green && oldColor[2] == blue) {
if(oldMin[0] <= red && red <= oldMax[0] &&
oldMin[1] <= green && green <= oldMax[1] &&
oldMin[2] <= blue && blue <= oldMax[2])
{
data[i+0] = newColor[0];
data[i+1] = newColor[1];
data[i+2] = newColor[2];
+14 -5
Voir le fichier
@@ -1,4 +1,4 @@
var VERSION = "2.21i";
var VERSION = "2.30e";
var AI_VERSION = 4;
var NO_OF_TILES_X = 28,
@@ -27,7 +27,7 @@ var KEYCODE_BKSPACE = 8, //backspace
KEYCODE_ESC = 27, //escape
KEYCODE_X = 88, //dig right
KEYCODE_Y = 89, //dig left (for German keyboards)
KEYCODE_Y = 89, //dig left (Y key to dig left, for German keyboards)
KEYCODE_Z = 90, //dig left
KEYCODE_LEFT = 37, //move left
@@ -75,10 +75,11 @@ var KEYCODE_0 = 48,
KEYCODE_8 = 56,
KEYCODE_9 = 57;
var SCORE_COMPLETE_LEVEL = 1500, SCORE_COUNTER = 15;
var SCORE_COMPLETE_LEVEL = 1500, SCORE_COUNTER = 15,
SCORE_GET_GOLD = 250,
SCORE_IN_HOLE = 75,
SCORE_GUARD_DEAD = 75;
SCORE_GUARD_DEAD = 75,
SCORE_WIN_PER_MAN = 42500;
var SCORE_VALUE_PER_POINT = 100; //for modern & edit mode
@@ -91,7 +92,8 @@ var GAME_START = 0, GAME_RUNNING = 1,
GAME_NEW_LEVEL = 6, GAME_RUNNER_DEAD = 7,
GAME_OVER_ANIMATION = 8, GAME_OVER = 9,
GAME_NEXT_LEVEL = 10, GAME_PREV_LEVEL = 11,
GAME_LOADING = 12, GAME_WIN = 13;
GAME_LOADING = 12, GAME_WIN_SCORE_COUNT = 13,
GAME_WIN = 14;
var ACT_UNKNOWN = -1, ACT_STOP = 0,
ACT_LEFT = 1, ACT_RIGHT = 2,
@@ -181,6 +183,8 @@ var STORAGE_TEST_LEVEL = "loderunner_testlevel";
var STORAGE_HISCORE_INFO = "loderunner_hiScore";
var STORAGE_LASTSCORE = "loderunner_lastScore";
var STORAGE_PLAYER_NAME = "loderunner_player";
var STORAGE_UID = "loderunner_uid";
@@ -189,3 +193,8 @@ var STORAGE_THEME_COLOR = "loderunner_color_";
var STORAGE_REPEAT_ACTION = "loderunner_actRepeat";
var STORAGE_GAMEPAD_MODE = "loderunner_gamepadMode";
//================================
// backup & restore file header
//================================
var LRWG_FILE_START_INFO = "LODE RUNNER WEB GAME.";
+6 -6
Voir le fichier
@@ -135,7 +135,7 @@ function setDemoData(jsonTxt)
playerDemoData[wDemoData[i].level-1] = wDemoData[i];
}
} else {
error(arguments.callee.name, "Wrong Demo Data: " + jsonTxt);
error("Wrong Demo Data: " + jsonTxt);
}
demoDataLoading = 0;
if(playMode == PLAY_MODERN && gameState == GAME_START ) demoIconObj.enable();
@@ -175,7 +175,7 @@ function getDemoInfo()
//demoData = playerDemoData[playData-1];
demoData = playerDemoData;
} else {
error(arguments.callee.name, "design error, value =" + playData );
error("design error, value =" + playData );
}
if(infoJSON == null) {
@@ -196,7 +196,7 @@ function setDemoInfo()
if (playData >= 1 && playData <= maxPlayId) {
setStorage(STORAGE_DEMO_INFO + playData, infoJSON);
} else {
error(arguments.callee.name, "design error, value =" + playData );
error("design error, value =" + playData );
}
}
@@ -217,7 +217,7 @@ function getNextDemoLevel()
function curDemoLevelIsVaild()
{
if(playData == PLAY_DATA_USERDEF) return 0;
return (typeof playerDemoData[curLevel-1] != "undefined");
return (playerDemoData.length >= curLevel && typeof playerDemoData[curLevel-1] != "undefined");
}
function updatePlayerDemoData(playData, demoDataInfo)
@@ -258,7 +258,7 @@ function respUpdatePlayerDemoData(jsonTxt)
playerDemoData[level-1].cId = respObj.cId;
}
} else {
error(arguments.callee.name, "Wrong resp Data: " + jsonTxt);
error("Wrong resp Data: " + jsonTxt);
}
}
@@ -471,7 +471,7 @@ function convertBornPos()
bornRecord = tmpRecord;
}
var curDemoData;
var curDemoData = { ai: AI_VERSION, time: 0 }; //bug fixed: when press CTRL-C without demo data
function dumpRecord()
{
var txtStr;
+115 -33
Voir le fichier
@@ -50,6 +50,8 @@ var editorTile =[], editorActiveTileId = -1;
var editorButton = [], editorButtonMouseOverId = -1;
var editInNarrowScreen = 0;
var editMapIsEmpty = 1;
function startEditMode()
{
playMode = PLAY_EDIT;
@@ -69,6 +71,7 @@ function startEditMode()
createBaseTile();
createEditMap();
checkEditMapEmpty(); // 2021/04
startEditTicker();
setButtonState();
initForPlay();
@@ -116,6 +119,7 @@ function canvasEditReSize()
canvas.style.left = (left>0?left:0) + "px";
canvas.style.top = (top>0?top:0) + "px";
canvas.style.position = "absolute";
canvas.style.cursor = "default";
tileWScale = BASE_TILE_X * tileScale;
tileHScale = BASE_TILE_Y * tileScale;
@@ -208,6 +212,7 @@ function clearEditMap()
tileObj.id = emptyTile.id;
}
}
editMapIsEmpty = 1;
}
function tile2Id(tileChar)
@@ -453,6 +458,7 @@ function drawNewButton()
} else {
disableTestButton();
}
setPasteIconState();
clearTestLevel();
testLevelInfo.fromPlayData = -1;
testLevelInfo.fromLevel = -1;
@@ -577,7 +583,7 @@ function drawLoadButton()
function loadButtonClick()
{
saveState();
if(!editMapIsEmpty()) {
if(!editMapIsEmpty) {
yesNoDialog(["Abort current editing ?"], yesBitmap, noBitmap, mainStage, tileScale, loadExistLevel);
} else {
loadExistLevel(1);
@@ -895,7 +901,7 @@ function delManCheck(id, x, y)
guardTile.id = emptyTile.id;
lastGuardList.splice(removeId,1);
} else {
error(arguments.callee.name, "design error !");
error("design error !");
}
break;
}
@@ -905,26 +911,35 @@ function delManCheck(id, x, y)
function editSelectMenuClose(levelDeleted, newLevel, state)
{
if(levelDeleted) {
setEditSelectMenu();
startEditMode();
/*
Bug fixed: If player delete some custom levels and restart the program immediate will cause
testLevel inconsistent, must del or shift testlevel immediate.
==> so move below statements into function delLevel(level).
switch(true) {
case (state > 0): //level changed
getTestLevel(testLevelInfo);
testLevelInfo.level = newLevel;
setTestLevel(testLevelInfo);
case (state > 0): //level number changed
//getTestLevel(testLevelInfo);
//testLevelInfo.level = newLevel;
//setTestLevel(testLevelInfo);
startEditMode();
break;
case (state < 0): //level deleted
clearTestLevel();
//clearTestLevel();
setEditSelectMenu();
startEditMode();
break;
case (state == 0 && newLevel == 0): //new level
if(testLevelInfo.modified == 1) {
testLevelInfo.level = editLevels+1;
setTestLevel(testLevelInfo);
}
case (state == 0 && newLevel == 0): //newLevel = 0 : meanings edit new level just need change level id
//if(testLevelInfo.modified == 1) {
// testLevelInfo.level = editLevels+1;
// setTestLevel(testLevelInfo);
//}
startEditMode();
break;
}
*/
}
}
@@ -949,14 +964,28 @@ function map2LevelData()
}
}
function editMapIsEmpty()
function checkEditMapEmpty()
{
editMapIsEmpty = 1;
mapCheckLoop:
for(var y = 0; y < NO_OF_TILES_Y; y++) {
for(var x = 0; x < NO_OF_TILES_X; x++) {
if(editMap[x][y].id != emptyTile.id) return 0;
if(editMap[x][y].id != emptyTile.id) {
editMapIsEmpty = 0;
break mapCheckLoop;
}
}
return 1;
}
setPasteIconState();
}
function setPasteIconState()
{
if (editMapIsEmpty && copyLevelMap != null && testLevelInfo.level <= MAX_EDIT_LEVEL)
pasteIconObj.enable();
else
pasteIconObj.disable();
}
function copyEditingMap()
@@ -977,7 +1006,7 @@ function copyEditingMap()
var editWarningText = null;
function editWarningMsg(hidden)
{
var x, y, width, height;
var width, height;
if(editWarningText == null)
editWarningText = new createjs.Text("Too many custom levels !",
@@ -985,9 +1014,9 @@ function editWarningMsg(hidden)
width = editWarningText.getBounds().width;
height = editWarningText.getBounds().height;
x = editWarningText.x = (NO_OF_TILES_X*(tileWScale+EDIT_PADDING) - width) / 2 | 0;
y = editWarningText.y = (NO_OF_TILES_Y*tileHScale - height) / 2 | 0;
editWarningText.shadow = new createjs.Shadow("white", 2, 2, 1);
editWarningText.x = ((NO_OF_TILES_X+2)*(tileWScale+EDIT_PADDING) - width) / 2 | 0;
editWarningText.y = (NO_OF_TILES_Y*tileHScale - height) / 2 | 0;
editWarningText.shadow = new createjs.Shadow("white", tileScale, 2*tileScale, 1);
if(hidden) {
mainStage.removeChild(editWarningText);
@@ -1005,20 +1034,15 @@ function editHandleKeyDown(event)
if (event.ctrlKey) {
switch(event.keyCode) {
case KEYCODE_C: //CTRL-C : copy current level
if (!editMapIsEmpty) {
copyLevelMap = copyEditingMap();
copyLevelPassed = (!testLevelInfo.modified && lastRunner) || testLevelInfo.pass;
setTimeout(function() { showTipsText("COPY MAP", 1500);}, 50);
}
break;
case KEYCODE_V: //CTRL-V : paste copy map
if(copyLevelMap != null) {
testLevelInfo.levelMap = copyLevelMap;
testLevelInfo.modified = 1;
testLevelInfo.pass = copyLevelPassed;
testLevelInfo.fromPlayData = testLevelInfo.fromLevel = -1;
setTestLevel(testLevelInfo);
startEditMode();
////setButtonState();
setTimeout(function() { showTipsText("PASTE MAP", 1500);}, 50);
if(copyLevelMap != null && editMapIsEmpty && testLevelInfo.level <= MAX_EDIT_LEVEL) {
editPasteMap();
}
break;
}
@@ -1026,6 +1050,19 @@ function editHandleKeyDown(event)
return true;
}
function editPasteMap()
{
testLevelInfo.levelMap = copyLevelMap;
testLevelInfo.modified = 1;
testLevelInfo.pass = copyLevelPassed;
testLevelInfo.fromPlayData = testLevelInfo.fromLevel = -1;
setTestLevel(testLevelInfo);
copyLevelMap = null; //clear copy map after paste
startEditMode();
////setButtonState();
setTimeout(function() { showTipsText("PASTE MAP", 1500);}, 50);
}
function checkTileMouseOver(x, y)
{
var curTile;
@@ -1049,6 +1086,7 @@ function selectTileMouseOver(tile)
border.graphics.clear();
border.graphics.beginFill("gold").drawRect(-editBorder, -editBorder, tileWScale+editBorder*2, tileHScale+editBorder*2).endFill();
canvas.style.cursor = "pointer";
//mouseOver = 1;
}
@@ -1059,6 +1097,7 @@ function selectTileMouseOut(tile)
border.graphics.clear();
border.graphics.beginFill(color).drawRect(-editBorder, -editBorder, tileWScale+editBorder*2, tileHScale+editBorder*2).endFill();
canvas.style.cursor = "default";
//mouseOver = 0;
}
@@ -1090,7 +1129,8 @@ function editorButtonMouseOver(button)
var backColor = button.getChildAt(1);
backColor.graphics.clear();
backColor.graphics.beginFill("#ffa").drawRect(0, 0, width, tileHScale).endFill();
if (button.alpha)
canvas.style.cursor = "pointer";
//mouseOver = 1;
}
@@ -1105,7 +1145,7 @@ function editorButtonMouseOut(button)
var backColor = button.getChildAt(1);
backColor.graphics.clear();
backColor.graphics.beginFill("#fff").drawRect(0, 0, width, tileHScale).endFill();
canvas.style.cursor = "default";
//mouseOver = 0;
}
@@ -1113,8 +1153,10 @@ function setButtonState()
{
if(testLevelInfo.level > MAX_EDIT_LEVEL) {
newButton.alpha = 0;
loadButton.alpha = 0;
testButton.alpha = 0;
saveButton.alpha = 0;
canvas.style.cursor = "default";
editWarningMsg(0);
return;
} else {
@@ -1141,9 +1183,7 @@ function editTick()
var x = (x < 0)?-1:(x|0);
var y = ((mainStage.mouseY-EDIT_PADDING) / (tileHScale+EDIT_PADDING) )| 0;
if(testLevelInfo.level > MAX_EDIT_LEVEL) {
return;
}
if(testLevelInfo.level <= MAX_EDIT_LEVEL) {
//debug(mainStage.mouseX,editStartX, x,y);
if(mouseInStage && x >= 0 && x < NO_OF_TILES_X && y >= 0 && y < NO_OF_TILES_Y) {
//edit area
@@ -1170,6 +1210,7 @@ function editTick()
addManCheck(actTile.id, x, y);
}
lastDown = {x:x, y:y};
checkEditMapEmpty();
if(testLevelInfo.pass || actTile.id == RUNNER_ID || testLevelInfo.modified == 0) {
testLevelInfo.modified = 1;
@@ -1183,5 +1224,46 @@ function editTick()
checkButtonMouseOver(mainStage.mouseX, mainStage.mouseY);
cursorTileObj.alpha = 0;
}
}
mainStage.update();
}
function levelMapIsEmpty(levelMap)
{
for(i =0; i < levelMap.length; i++) {
if (levelMap[i] != ' ') return 0;
}
return 1;
}
//========================================================
//
// Copy share level to test level or copy map for editig
//
//=========================================================
function copyShareLevelForEditing()
{
getTestLevel(testLevelInfo);
if(testLevelInfo.level <= MAX_EDIT_LEVEL && levelMapIsEmpty(testLevelInfo.levelMap)) {
//test map is empty, replace test map with share level map
testLevelInfo.levelMap = shareLevelData[0];
testLevelInfo.modified = 1;
testLevelInfo.pass = 1;
testLevelInfo.fromPlayData = testLevelInfo.fromLevel = -1;
setTestLevel(testLevelInfo);
} else {
if (shareLevelData[0] != testLevelInfo.levelMap) {
//(testMap != empty and testMap != shareMap) ==> keep shareLevel map to copyMap
copyLevelMap = shareLevelData[0];
copyLevelPassed = 1;
}
}
}
function editShareLevel()
{
editEdit(0, null);
}
+4 -4
Voir le fichier
@@ -463,7 +463,7 @@ function add2GuardShakeQueue(id, shape)
curGuard.curFrameTime = -1; //for init
shakingGuardList.push(id);
//error(arguments.callee.name, "push id =" + id + "(" + shakingGuardList + ")" );
//error("push id =" + id + "(" + shakingGuardList + ")" );
}
@@ -488,7 +488,7 @@ function processGuardShake()
var id = shakingGuardList[i];
shakingGuardList.splice(i, 1); //remove from list
//error(arguments.callee.name, "remove id =" + id + "(" + shakingGuardList + ")" );
//error("remove id =" + id + "(" + shakingGuardList + ")" );
climbOut(id); //climb out
continue;
}
@@ -504,11 +504,11 @@ function removeFromShake(id)
for(var i = 0; i < shakingGuardList.length;i++) {
if(shakingGuardList[i] == id) {
shakingGuardList.splice(i, 1); //remove from list
//error(arguments.callee.name, "remove id =" + id + "(" + shakingGuardList + ")" );
//error("remove id =" + id + "(" + shakingGuardList + ")" );
return;
}
}
error(arguments.callee.name, "design error id =" + id + "(" + shakingGuardList + ")" );
error("design error id =" + id + "(" + shakingGuardList + ")" );
}
//======================
+36 -3
Voir le fichier
@@ -79,6 +79,16 @@ function showScoreTable(_playData, _curScoreInfo, _callbackFun, _waitTime)
}
function setLastScoreInfo(scoreInfo)
{
if(typeof cId == "undefined") return;
scoreInfo.id = cId;
var infoJSON = JSON.stringify(scoreInfo);
setStorage(STORAGE_LASTSCORE+_playData, infoJSON);
}
function updateScoreInfo()
{
var addId = -1;
@@ -246,6 +256,7 @@ function showScoreTable(_playData, _curScoreInfo, _callbackFun, _waitTime)
//update name for score info
hiScoreInfo[recordId].n = nameString;
setHiScoreInfo();
setLastScoreInfo(hiScoreInfo[recordId]); //save last score
if(nameString != playerName && nameString != "???") { //set and save playerName
playerName = nameString;
@@ -348,8 +359,10 @@ function showScoreTable(_playData, _curScoreInfo, _callbackFun, _waitTime)
name[curPos] = nextChar(name[curPos], -1);
break;
case (code == KEYCODE_ENTER): //ENTER
if(name.length > 0) inputFinish(true); //async
else soundPlay("beep");
if(vaildPlayerName(name)) {
restoreKeyDownHandler(); //avoid type "ENTER" twice
inputFinish(true); //async
} else soundPlay("beep");
break;
default:
//debug(code);
@@ -421,6 +434,26 @@ function inputPlayerName(_stage, _callbackFun)
}
}
function vaildPlayerName(playerArray)
{
var len = playerArray.length;
//(1)skip tail space
for(var i = len-1; i >= 0; i--) {
if(playerArray[i] == " ") len--;
else break;
}
//(2) string length must > 1 and don't all same char
if(len <= 1) return 0; //too short
for(var i = 1; i < len; i++) {
if(playerArray[0] != playerArray[i]) return 1; //OK
}
return 0; //all same char
}
function inputString(_stage, _maxSize, _startX, _startY, _defaultString, _callbackFun)
{
@@ -542,7 +575,7 @@ function inputString(_stage, _maxSize, _startX, _startY, _defaultString, _callba
inputText[curPos] = nextChar(inputText[curPos], -1);
break;
case (code == KEYCODE_ENTER): //ENTER
if(inputText.length > 0) {
if(vaildPlayerName(inputText)) {
inputFinish();
return true;
} else soundPlay("beep");
+2 -1
Voir le fichier
@@ -18,7 +18,7 @@
* Source Code: https://github.com/SimonHung/LodeRunner_TotalRecall
* Web page: http://LodeRunnerWebGame.com
*
* by Simon Hung 06/20/2014, 11/23/2014, 06/29/2015, 09/28/2016
* by Simon Hung 06/20/2014, 11/23/2014, 06/29/2015, 09/28/2016, 03/26/2025
* ===================================================================================
-->
<meta http-equiv="Content-Type" content="text/html" charset="utf-8" />
@@ -63,6 +63,7 @@
<script type="text/javascript" src="lodeRunner.gamepad.js"></script>
<script type="text/javascript" src="lodeRunner.main.js"></script>
<script type="text/javascript" src="lodeRunner.win.js"></script>
<script type="text/javascript" src="lodeRunner.share.js"></script>
</head>
<body onload="init();">
<div class="canvas">
+134 -1
Voir le fichier
@@ -178,7 +178,9 @@ function selectIconClass( _screenX1, _screenY1, _scale, _bitmap)
enabled = 1;
disableMouseHandler();
enableMouseHandler();
document.body.appendChild(selectCanvas);
document.body.appendChild(selectCanvas); //overlay with selectCanvas, make zIndex up ?
selectIcon.set({alpha:1})
stage.enableMouseOver(60);
stage.update();
@@ -369,6 +371,9 @@ function demoIconClass( _screenX1, _screenY1, _scale, _bitmap)
enabled = 1;
disableMouseHandler();
enableMouseHandler();
document.body.appendChild(canvas); //overlay with pasteCanvas, make zIndex up ?
iconObj.set({alpha:1})
stage.enableMouseOver(60);
stage.update();
@@ -627,6 +632,8 @@ function soundIconClass( _screenX1, _screenY1, _scale, _soundOnBitmap, _soundOff
if((soundOff ^= 1)) { soundStop(soundDig); soundStop(soundFall); }
}
resumeAudioContext(); //2021/08/25
self.updateSoundImage();
mouseOut();
}
@@ -1240,6 +1247,132 @@ function themeColorIconUpdate()
themeColorObj.themeChange();
}
// For EDIT mode
function pasteIconClass( _screenX1, _screenY1, _scale, _bitmap)
{
var border = 4 * _scale;
var canvas, stage;
var iconObj, bgObj;
var saveStateObj;
var mouseOverHandler = null, mouseOutHandler = null, mouseClickHandler = null;
var bitmapX = _bitmap.getBounds().width * _scale;
var bitmapY = _bitmap.getBounds().height * _scale;
var self = this;
var enabled = 0;
init();
function init()
{
createCanvas();
createIconObj();
}
this.enable = function ()
{
if (enabled) return;
enabled = 1;
disableMouseHandler();
enableMouseHandler();
document.body.appendChild(canvas); //overlay with demoCanvas, make zIndex up ?
iconObj.set({alpha:1})
stage.enableMouseOver(60);
stage.update();
}
this.disable = function ()
{
if (!enabled) return;
disableMouseHandler();
iconObj.set({alpha:0});
stage.update();
enabled = 0;
stage.enableMouseOver(0);
}
function enableMouseHandler()
{
mouseOverHandler = iconObj.on("mouseover", mouseOver);
mouseOutHandler = iconObj.on("mouseout", mouseOut);
mouseClickHandler = iconObj.on("click", mouseClick);
}
function disableMouseHandler()
{
iconObj.removeEventListener("mouseover", mouseOverHandler);
iconObj.removeEventListener("mouseout", mouseOutHandler);
iconObj.removeEventListener("click", mouseClickHandler);
stage.cursor = "default";
stage.update();
}
function createCanvas()
{
canvas = document.createElement('canvas');
canvas.id = "paste_icon";
canvas.width = bitmapX+border*2;
canvas.height = bitmapY+border*2;
var left = (_screenX1 - canvas.width - screenBorder),
top = (canvas.height*2 + bitmapY*3/2)|0;
canvas.style.left = left + "px";
canvas.style.top = top + "px";
canvas.style.position = "absolute";
document.body.appendChild(canvas);
}
function createIconObj()
{
stage = new createjs.Stage(canvas);
iconObj = new createjs.Container();
//create mouseOver shape
bgObj = new createjs.Shape();
bgObj.graphics.beginFill(mouseOverBGColor)
.drawRect(0, 0, bitmapX+border*2, bitmapY+border*2).endFill();
bgObj.alpha = 0;
//change bitmap size
_bitmap.setTransform(border, border, _scale, _scale);
iconObj.addChild(bgObj);
iconObj.addChild(_bitmap);
iconObj.set({alpha:0})
stage.addChild(iconObj);
stage.update();
}
function mouseOver()
{
if(playMode != PLAY_EDIT) return;
stage.cursor = "pointer";
bgObj.alpha = 1;
stage.update();
}
function mouseOut()
{
stage.cursor = "default";
bgObj.alpha = 0;
stage.update();
}
function mouseClick()
{
if(playMode != PLAY_EDIT) return;
mouseOut();
editPasteMap();
}
}
//======================================
// BEGIN: Change Theme Screen real time
//======================================
+4 -4
Voir le fichier
@@ -126,7 +126,7 @@ function infoMenu(callbackFun, args)
if(infoMsg) infoObj.showInfo(infoMsg, callbackFun, args);
else {
if(callbackFun) callbackFun(args);
error(arguments.callee.name, "Error: playMode = " + playMode);
error("Error: playMode = " + playMode);
}
}
@@ -278,7 +278,7 @@ function infoMenuClass(_stage, _scale)
menuY += (infoObj[i].textHeight * 3/2|0);
break;
default:
error(arguments.callee.name, "Error: type don't support, type = " + infoList[i].type);
error("Error: type don't support, type = " + infoList[i].type);
continue;
}
if(maxTextWidth < infoObj[i].width) maxTextWidth = infoObj[i].width;
@@ -373,7 +373,7 @@ function infoMenuClass(_stage, _scale)
_stage.addChild(infoObj[i].textLink);
break;
default:
error(arguments.callee.name, "Error: type don't support, type = " + infoObj[i].type);
error("Error: type don't support, type = " + infoObj[i].type);
continue;
}
}
@@ -396,7 +396,7 @@ function infoMenuClass(_stage, _scale)
_stage.removeChild(infoObj[i].textLink);
break;
default:
error(arguments.callee.name, "Error: type don't support, type = " + infoObj[i].type);
error("Error: type don't support, type = " + infoObj[i].type);
continue;
}
}
+1
Voir le fichier
@@ -268,6 +268,7 @@ function pressKey(code)
menuIconDisable(1);
gamePause();
showScoreTable(playData, null, function() { menuIconEnable(); gameResume();});
return; //don't record this key code !
} else {
keyAction = ACT_UNKNOWN;
}
+6 -5
Voir le fichier
@@ -126,6 +126,7 @@ function canvasReSize()
canvas.style.left = (left>0?left:0) + "px";
canvas.style.top = (top>0?top:0) + "px";
canvas.style.position = "absolute";
canvas.style.cursor = "default";
tileW = BASE_TILE_X; //tileW and tileH for detection so don't change scale
tileH = BASE_TILE_Y;
@@ -505,7 +506,7 @@ function moveSprite2Top()
}
if(runner == null) {
error(arguments.callee.name, "Without runner ???");
error("Without runner ???");
} else {
//move runner to top (z index)
moveChild2Top(mainStage, runner.sprite);
@@ -1314,7 +1315,7 @@ function gameFinishCallback(selectMode)
break;
case 1: //menu selection
//incLevel(1);
activeSelectMenu(gameFinishActiveNew, gameFinishCloseIcon, null)
activeSelectMenu(gameFinishActiveNew, gameFinishCloseIcon);
break;
case 2: //new level
incLevel(1,0);
@@ -1379,13 +1380,13 @@ function mainTick(event)
}
break;
case PLAY_DEMO:
error(arguments.callee.name, "DEMO dead level=" + curLevel);
error("DEMO dead level=" + curLevel);
setTimeout(function() {incLevel(1,0); gameState = GAME_NEW_LEVEL; }, 500);
gameState = GAME_WAITING;
break;
case PLAY_DEMO_ONCE:
error(arguments.callee.name, "DEMO dead level=" + curLevel);
error("DEMO dead level=" + curLevel);
disableStageClickEvent();
document.onkeydown = handleKeyDown;
@@ -1453,7 +1454,7 @@ function mainTick(event)
gameState = GAME_WAITING;
break;
default:
error(arguments.callee.name, "design error, playMode =" + playMode);
error("design error, playMode =" + playMode);
break;
}
+1376 -44
Voir le fichier
Fichier diff supprimé car celui-ci est trop grand Voir la Diff
+26 -7
Voir le fichier
@@ -14,9 +14,9 @@ function assert(expression, msg)
console.assert(expression, msg);
}
function error(funName, string)
function error(string)
{
console.log("Error In " + funName + "( ): " + string);
console.log("Error In " + error.caller.name + "( ): " + string);
}
function getScreenSize()
@@ -49,8 +49,11 @@ function getScreenSize()
//===============================
function showTipsMsg(_tipsTxt, _stage, _scale, _tipsTxt1)
{
var TEXT_SIZE = 72* _scale;
var TEXT_COLOR = "#ff2020";
var TEXT_SIZE = 72 * _scale;
var TEXT1_SIZE = 66 * _scale;
var TEXT_COLOR = "#FF2020";
var TEXT1_COLOR = "#FF2020";
var tipsText = new createjs.Text(_tipsTxt, "bold " + TEXT_SIZE + "px Helvetica", TEXT_COLOR);
var screenX1 = _stage.canvas.width;
var screenY1 = _stage.canvas.height;
@@ -67,7 +70,7 @@ function showTipsMsg(_tipsTxt, _stage, _scale, _tipsTxt1)
if(_tipsTxt1 != null) {
// two tips
var tipsText1 = new createjs.Text(_tipsTxt1, "bold " + TEXT_SIZE + "px Helvetica", TEXT_COLOR);
var tipsText1 = new createjs.Text(_tipsTxt1, "bold " + TEXT1_SIZE + "px Helvetica", TEXT1_COLOR);
tipsText1.x = (screenX1) / 2 | 0;
tipsText1.y = screenY1/2 | 0;
@@ -172,14 +175,30 @@ function phpTimeZone()
//========================================
// get local time (YYYY-MM-DD HH:MM:SS)
//========================================
function getLocalTime()
function getLocalTime(d)
{
var d = new Date();
if (d == null) d = new Date();
return (("000"+d.getFullYear()).slice(-4)+ "-" +("0"+(d.getMonth() + 1)).slice(-2)+ "-" +("0"+d.getDate()).slice(-2)+ " " +
("0"+d.getHours()).slice(-2) + ":" + ("0"+d.getMinutes()).slice(-2) + ":" + ("0"+d.getSeconds()).slice(-2));
}
// ======================================================================
// return format : "2021-06-08 12:09:08 GMT+0800 (Taipei Standard Time)"
// ======================================================================
function getLocalTimeZone(d)
{
if (d == null) d = new Date();
var dString = d.toString(); // format: "Tue Jun 08 2021 12:09:08 GMT+0800 (台北標準時間)"
var dGMTOffset = dString.indexOf('GMT');
var dGMT = ""
if(dGMTOffset >= 0) dGMT = ' ' + dString.substr(dGMTOffset);
return getLocalTime(d) + dGMT;
}
//===============
// Random Object
//===============
+17 -1
Voir le fichier
@@ -21,6 +21,7 @@ var helpObj, helpBitmap, editHelpBitmap;
var mainMenuIconBitmap, mainMenuIconObj;
var selectIconBitmap, selectIconObj;
var demoIconBitmap, demoIconObj;
var pasteIconBitmap, pasteIconObj; // paste icon
var soundOnIconBitmap, soundOffIconBitmap, soundIconObj;
var helpIconBitmap, helpIconObj;
var infoObj, infoIconBitmap, infoIconObj;
@@ -28,6 +29,8 @@ var repeatActionOnIconBitmap, repeatActionOffIconBitmap, repeatActionIconObj;
var apple2IconBitmap, C64IconBitmap, themeIconObj, themeColorObj;
var checkBitmap;
var returnBitmap, select1Bitmap, nextBitmap;
var openFolderBitmap; // for restore custom levels
var nextMapBitmap, prevMapBitmap; // for restore custom levels
var yesBitmap, noBitmap;
var coverPageLoad;
var noCache = "?" + VERSION+ ".1051230";
@@ -200,11 +203,17 @@ function preloadResource()
{ src: "image/select1.png"+noCache, id: "select1" },
{ src: "image/next.png"+noCache, id: "next" },
{ src: "image/openFolder.png"+noCache, id: "openFolder" }, //05/17/2021
{ src: "image/nextMap.png"+noCache, id: "nextMap" }, //05/21/2021
{ src: "image/prevMap.png"+noCache, id: "prevMap" }, //05/21/2021
{ src: "image/yes.png"+noCache, id: "yes" },
{ src: "image/no.png"+noCache, id: "no" },
{ src: "image/demo.png"+noCache,id: "demo" },
{ src: "image/paste.png"+noCache,id: "paste" }, //04/23/2021
{ src: "image/soundOn.png"+noCache, id: "soundOn" },
{ src: "image/soundOff.png"+noCache, id: "soundOff" },
@@ -287,7 +296,7 @@ function preloadResource()
//Set percentTxt position
percentTxt.x = (canvas.width - percentTxt.getBounds().width) / 2 | 0;
percentTxt.y = (BASE_SCREEN_Y - COVER_PROGRESS_UNDER_Y) * tileScale;
percentTxt.y = (BASE_SCREEN_Y - COVER_PROGRESS_UNDER_Y) * tileScale + height/12; // move percent number Lower
mainStage.addChild(runnerSprite, progress, progressBorder, percentTxt);
@@ -384,6 +393,9 @@ function preloadResource()
demoIconBitmap = new createjs.Bitmap(preload.getResult("demo")); //04/18/2015
demoIconObj = new demoIconClass(screenX1, screenY1, tileScale, demoIconBitmap);
pasteIconBitmap = new createjs.Bitmap(preload.getResult("paste")); //04/23/2021
pasteIconObj = new pasteIconClass(screenX1, screenY1, tileScale, pasteIconBitmap);
soundOnIconBitmap = new createjs.Bitmap(preload.getResult("soundOn")); //04/18/2015
soundOffIconBitmap = new createjs.Bitmap(preload.getResult("soundOff"));
soundIconObj = new soundIconClass(screenX1, screenY1, tileScale, soundOnIconBitmap, soundOffIconBitmap);
@@ -410,6 +422,10 @@ function preloadResource()
select1Bitmap = new createjs.Bitmap(preload.getResult("select1"));
nextBitmap = new createjs.Bitmap(preload.getResult("next"));
openFolderBitmap = new createjs.Bitmap(preload.getResult("openFolder")); // for restore custom levels
nextMapBitmap = new createjs.Bitmap(preload.getResult("nextMap")); // for restore custom levels
prevMapBitmap = new createjs.Bitmap(preload.getResult("prevMap"));
yesBitmap = new createjs.Bitmap(preload.getResult("yes"));
noBitmap = new createjs.Bitmap(preload.getResult("no"));
+1 -1
Voir le fichier
@@ -686,7 +686,7 @@ function removeFillHoleObj(spriteObj)
return;
}
}
error(arguments.callee.name, "design error !");
error("design error !");
}
//=======================================
+340
Voir le fichier
@@ -0,0 +1,340 @@
//=================================================================================
// For share custom level to other players
// --------------------------------------------------------------------------------
// Version 1 url parameter format:
//
// ?shareLevel=[LEVEL DATA].[s]([v][m][t][r][creator][pading])
//
// [LEVEL DATA] : ZIP level data
// [s]: checksum ([v]..[pading])
// [v]: version = 1 [0]
// [m]: share mode (1:Fackbook, 2:twitter, 3:weibo, 4:link) [1]
// [t]: theme mode (1:apple2, 2:c64) [2]
// [r]: reserved 3 bytes [3..5]
// [creator]: creator name [6-]
// [pading]: pading "@" let length([v]+[m]+[t]+[creator]+[pading]) multiplier of 3
//=================================================================================
var SHARE_DATA_VERSION = 1;
var shareLevelData = [""];
var shareInfo = null; // { ver:1, mode:1-4 [m], theme:1-2 [t], creator: }
var shareFirstTime = 1;
function getQueryStringParameterValue(queryString, parameterName)
{
var ParameterValue = "";
var valueLength = 0
queryString = decodeURIComponent(queryString); //url decode
var beginIdxOfParameter = queryString.indexOf(parameterName + "=");
if (beginIdxOfParameter >= 0) {
var startIdx = beginIdxOfParameter + parameterName.length + 1; // skip "parameterName="
for (var endIdx=startIdx;
queryString.charAt(endIdx) !='&' && endIdx < queryString.length; endIdx++) valueLength++;
ParameterValue = queryString.substr(startIdx, valueLength);
}
return ParameterValue;
}
function getShareChecksum(strData)
{
var checksum = 0;
for(var i = 0; i < strData.length; i++) {
checksum += strData.charCodeAt(i);
}
return value2OutValue((checksum & 0x1F)+1); //1..32
}
function getShareVerInfo(encUrlVerData)
{
var verInfo = null;
var infoChecksum = encUrlVerData.charAt(0);
var urlVerData = atob(encUrlVerData.substr(1,)); //base64 decode
var strChecksum = getShareChecksum(urlVerData);
var version = urlVerData.charAt(0);
if(infoChecksum == strChecksum && (urlVerData.length % 3) == 0 && urlVerData.length >= 9 && version == '1') {
var shareMode = urlVerData.charCodeAt(1)-'0'.charCodeAt(0); //[m]
var theme = urlVerData.charCodeAt(2)-'0'.charCodeAt(0); //[t]
var creator = urlVerData.substr(6,); //[creator]
var creatorLength = creator.length;
// remove last '@' chars
while(creatorLength > 0) {
if (creator.charAt(creatorLength-1) == '@') creatorLength--;
else break;
}
if (creator.length != creatorLength)
creator = creator.substr(0, creatorLength);
if(shareMode > 0 && shareMode <= 4 && theme > 0 && theme <=2 && creatorLength > 0 && vaildPlayerName(creator)) {
verInfo = {};
verInfo.ver = 1;
verInfo.mode = shareMode;
verInfo.theme = theme;
verInfo.creator = creator;
}
}
if(!verInfo) error("wrong verInfo");
return verInfo;
}
function getShareUrlInfo()
{
if (!shareFirstTime) return;
shareFirstTime = 0;
var shareUrlData = getQueryStringParameterValue(location.search, "shareLevel");
if (shareUrlData) {
var dotPos = shareUrlData.indexOf(".");
if (dotPos > 0) {
var unzipLevel = unzipLevelMap(shareUrlData.substr(0, dotPos));
if(unzipLevel && shareUrlData.length > dotPos) {
shareInfo = getShareVerInfo(shareUrlData.substr(dotPos+1,));
}
if (shareInfo) {
shareLevelData[0] = unzipLevel;
copyShareLevelForEditing();
playMode = PLAY_MODERN;
playData = PLAY_DATA_SHARE;
/////////////////////////////////////////////////
sendShareLevel2Server(unzipLevel, shareInfo, null); //new or update share count
/////////////////////////////////////////////////
}
// remove "share.html"
var removeString = "/share.html";
var removeLength = removeString.length;
var newPathName = location.pathname;
if(newPathName.substr(-removeLength) == removeString)
newPathName = newPathName.substr(0, newPathName.length-removeLength+1);
//console.log(newPathName);
// change URL to normal path (adds an entry to the browser's session history stack)
history.pushState({}, "Lode Runner Web Game", newPathName);
}
}
}
function converLevel2ShareUrl(level, shareMode, creator)
{
var theme =(curTheme == THEME_APPLE2)?1:2;
var padingTimes = (3-creator.length%3) % 3;
var zipLevel = zipLevelMap(level);
var verInfo = `1${shareMode}${theme} ${creator}${'@'.repeat(padingTimes)}`;
var checksum = getShareChecksum(verInfo);
var leftSlash = location.pathname.lastIndexOf("/");
var pathName = leftSlash < 0 ? "/": location.pathname.substr(0,leftSlash+1);
var host = location.host;
//host = "loderunnerwebgame.com/game";
return location.protocol + "//" + host + pathName + "share.html?shareLevel=" + zipLevel + "." + checksum + encodeURIComponent(btoa(verInfo));
}
var zipIdToMap = [' ', '#', '@', 'H', '-', 'X', 'S', '$', '0', '&'];
var mapToZipId = {' ':0, '#':1, '@':2, 'H':3, '-': 4, 'X':5, 'S':6, '$':7, '0':8, '&':9 }
// value range [1..52] ==> A..Z + a..z
// (01-26) ==> 'A'-'Z' (0x41 - 0x5A)
// (27-52) ==> 'a'-'z' (0x61 - 0x7A)
function value2OutValue(value)
{
assert(value >= 1 && value <= 52 , "Error: value not in range 1..52");
if (value <= 26) {
var outValue = String.fromCharCode(value-1 + 'A'.charCodeAt(0)); //'A' ==> 1 , 'B' ==> 2 ...
} else {
var outValue = String.fromCharCode(value-27 + 'a'.charCodeAt(0)); //'a' ==> 27 , 'b' ==> 28 ...
}
return outValue;
}
function appendZipTile(tileType, tileCount)
{
var rcTile = '';
var outTile = String.fromCharCode(mapToZipId[tileType] + '0'.charCodeAt(0)); //0 ==> '0' , 1 ==> '1'
switch(tileCount) {
case 0:
error("design error, tileType = None");
break;
case 1:
rcTile = outTile;
break
case 2:
rcTile = outTile + outTile;
break;
default:
outCount = value2OutValue(tileCount);
rcTile = outCount + outTile
break;
}
return rcTile;
}
function zipLevelMap(level)
{
var zipLevel = "";
assert(level.length == (NO_OF_TILES_X * NO_OF_TILES_Y), "Error: zipShareLevel tiles != totalTiles");
var lastTile = ''; // begin with a fake tile
var tileCount = 0;
var checksum = 0; // checksum
for(var tileIdx = 0; tileIdx < level.length; tileIdx++) {
curTile = level.charAt(tileIdx);
checksum += mapToZipId[curTile]; //XOR
if (lastTile == curTile) {
tileCount += 1;
if (tileCount < 52) continue; // the maximun compress count = 52 (a-z + A-Z)
else curTile = ''; //fake tile
}
if (tileCount > 0) zipLevel += appendZipTile(lastTile, tileCount);
lastTile = curTile;
if (lastTile == '') tileCount = 0; // compress count > max compress count (append a fake tile)
else tileCount = 1;
}
if (tileCount > 0) zipLevel += appendZipTile(lastTile, tileCount);
zipLevel += value2OutValue((checksum & 0x1F)+1); // checksum 1..32
return zipLevel;
}
function unzipLevelMap(zipLevel)
{
var dupNum = 1;
var unzipLevel = '';
var checksum = 0;
var caseType = 1;
for (var curIdx = 0; curIdx < zipLevel.length && caseType > 0; curIdx++) {
curChar = zipLevel.charAt(curIdx);
switch (true) {
case curChar >= '0' && curChar <= '9': // tileType
caseType = 1;
tileIdx = curChar.charCodeAt(0) - '0'.charCodeAt(0);
unzipLevel += Array(dupNum+1).join(zipIdToMap[tileIdx]); // char * dupNum
checksum += (tileIdx * dupNum);
dupNum = 1
break;
case curChar >= 'A' && curChar <= 'Z': // dup number 1-26
if (dupNum > 1) {
caseType = -1; //error
error("Error: before A-Z still a dupNumber");
} else {
caseType = 2;
dupNum = curChar.charCodeAt(0) - 'A'.charCodeAt(0) + 1;
}
break;
case curChar >= 'a' && curChar <= 'z': // dup number 27-52
if (dupNum > 1) {
caseType = -1; //error
error("Error: before a-z still a dupNumber");
} else {
caseType = 2;
dupNum = curChar.charCodeAt(0) - 'a'.charCodeAt(0) + 27;
}
break;
default:
caseType = -1; //error
error("Error: wrong tileType = '" + curChar + "'");
break;
}
}
if (caseType < 0) return ''; // Error
checksum = (checksum & 0x1F) + 1; // 1..32
if(caseType != 2 || checksum != dupNum) {
error("Error: wrong checksum !");
return '';
} else if (unzipLevel.length != (NO_OF_TILES_X * NO_OF_TILES_Y)) {
error("Error: wrong tile size (" + unzipLevel.length + ") !");
return '';
}
return unzipLevel;
}
// ==============================================================================================
// Generate custom level backup data
//
// (1) HeaderInfo: "LODE RUNNER WEB GAME.2021-06-08 12:09:08 GMT+0800 (台北標準時間).player."
// (2) zipInfo: [v][l][s][c]
//
// [v]: version [0] ==> 1 or 2
// [l]: levels [1:2] ==> [01-FF]
// [s]: size [3:8] ==> [000000-FFFFFF]
// [c]: checksum [9:12] ==> [0000-FFFF]
// [r]: reserved [13:14] ==> "LR"
//
// (3) level map data:
// ------------------------------
// v1:
// +----- startLevelPos
// V
// \n tile * NO_OF_TILES_X
// \n tile * NO_OF_TILES_X
// ....
// \n tile * NO_OF_TILES_X
// \n checksum
// ------------------------------
// v2:
// \n zipLevelData
// \n zipLevelData
// .......
// \n zipLevelData
// \n
// ------------------------------
// ==============================================================================================
function backupCustomLevelData(date)
{
var curTimeInfo = getLocalTimeZone(date);
var headerInfo = LRWG_FILE_START_INFO + curTimeInfo + "." + playerName + ".";
var levelSize = ("0" + editLevels.toString(16)).slice(-2);
var fileSize = encodeURI(headerInfo).replace(/%../g,'.').length + 20; //20 : length of zipInfo
var zipLevelData = "";
var zipChecksum = 0;
/* version 1
var verInfo = '1';
for(var i = 0; i < editLevels; i++) {
var curLevel = editLevelData[i];
for(var startPos = 0; startPos < curLevel.length; startPos += NO_OF_TILES_X) {
zipLevelData += '\n' + curLevel.substr(startPos, NO_OF_TILES_X);
}
zipLevelData += '\n' + getShareChecksum(curLevel);
}
*/
var verInfo = '2';
for(var i = 0; i < editLevels; i++) {
zipLevelData += '\n' + zipLevelMap(editLevelData[i]); // \nzipLevel \nzipLevel.... \nzipLevel
}
zipLevelData += '\n'; // \nzipLevel \nzipLevel.... \nzipLevel \n
for(var i = 0; i < zipLevelData.length; i++) {
zipChecksum += zipLevelData.charCodeAt(i);
}
zipChecksum = ("000" + (zipChecksum & 0xFFFF).toString(16)).slice(-4);
fileSize = ("00000" + (fileSize + zipLevelData.length).toString(16)).slice(-6);
var zipInfo = btoa(verInfo + levelSize + fileSize + zipChecksum + "LR");
return headerInfo + zipInfo + zipLevelData;
}
+30 -19
Voir le fichier
@@ -63,7 +63,7 @@ function getClassicInfo()
// END for support base64 encode
//================================
} else {
error(arguments.callee.name, "design error, value =" + playData );
error("design error, value =" + playData );
playData = 1;
}
levelData = getPlayVerData(playData);
@@ -104,7 +104,7 @@ function setClassicInfo(passed)
if(playData >= 1 && playData <= maxPlayId) {
setStorage(STORAGE_CLASSIC_INFO+playData, infoJSON);
} else {
error(arguments.callee.name, "design error, value =" + playData );
error("design error, value =" + playData );
}
}
@@ -128,13 +128,13 @@ function getModernInfo()
levelData = editLevelData;
} else { //no any user created level !
playData = 1;
playData2MainMenuId();
playData2GameVersionMenuId();
infoJSON = getStorage(STORAGE_MODERN_INFO+1);
levelData = getPlayVerData(playData);
}
break;
default:
error(arguments.callee.name, "design error, value =" + playData );
error("design error, value =" + playData );
playData = 1;
break;
}
@@ -165,7 +165,7 @@ function setModernInfo()
setStorage(STORAGE_USER_INFO, infoJSON); //user created
break;
default:
error(arguments.callee.name, "design error, value =" + playData );
error("design error, value =" + playData );
break;
}
}
@@ -180,7 +180,7 @@ function clearModernInfo()
clearStorage(STORAGE_USER_INFO);
break;
default:
error(arguments.callee.name, "design error, value =" + playData );
error("design error, value =" + playData );
break;
}
}
@@ -199,7 +199,7 @@ function getModernScoreInfo()
levelSize = MAX_EDIT_LEVEL;
break;
default:
error(arguments.callee.name, "design error, value =" + playData );
error("design error, value =" + playData );
break;
}
@@ -225,7 +225,7 @@ function setModernScoreInfo()
setStorage(STORAGE_USER_SCORE_INFO, infoJSON);
break;
default:
error(arguments.callee.name, "design error, value =" + playData );
error("design error, value =" + playData );
break;
}
}
@@ -377,6 +377,17 @@ function getTestLevel(testInfo)
var init = testInfo.level<0?1:0;
var infoObj = JSON.parse(infoJSON);
//add statements for testInfo safer
if(!('level' in infoObj) || !('map' in infoObj) || !('pass' in infoObj) ||
infoObj.level < 0 || infoObj.level > editLevels+1 ||
infoObj.map.length != NO_OF_TILES_X * NO_OF_TILES_Y)
{
//wrong map data clear it
clearTestLevel();
initNewLevelInfo(testInfo);
return;
}
testInfo.level = infoObj.level;
testInfo.levelMap = infoObj.map;
testInfo.pass = infoObj.pass;
@@ -389,18 +400,19 @@ function getTestLevel(testInfo)
}
//BEGIN for debug ====================
var i = 0;
for(var y = 0; y < NO_OF_TILES_Y; y++) {
var string = ""
for(var x = 0; x < NO_OF_TILES_X; x++) {
string += testInfo.levelMap[i++];
}
//debug('"' + string + '"');
}
//var i = 0;
//for(var y = 0; y < NO_OF_TILES_Y; y++) {
// var string = ""
// for(var x = 0; x < NO_OF_TILES_X; x++) {
// string += testInfo.levelMap[i++];
// }
// //debug('"' + string + '"');
//}
//END for debug ====================
if(testInfo.level > editLevels) testInfo.modified = 1;
else {
if(testInfo.level > editLevels) {
testInfo.modified = 1;
} else {
if(compareWithExist(editLevelData[infoObj.level-1], testInfo.levelMap) == 0) {
if(init) {
//same as exist level, new level
@@ -411,7 +423,6 @@ function getTestLevel(testInfo)
testInfo.modified = 1;
}
}
}
}