1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
package Game;
/*
* Copyright 2009 Volker Oth
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @author Volker Oth
* Create and evaluate lemmings level codes
* Based on the documentation and Basic code of Herman Perk (LemGen)
*/
public class LevelCode {
// nibble 0 | nibble 1 | nibble 2 | nibble 3 | nibble 4 | nibble 5 | nibble 6
// ----------|----------|----------|-----------|----------|----------|---------
// 3 2 1 0| 3 2 1 0|3 2 1 0| 3 2 1 0| 3 2 1 0|3 2 1 0|3 2 1 0
// ----------|----------|----------|-----------|----------|----------|---------
// L0 %0 S0 0|S1 L1 0 %1|0 L2 %2 S2|S4 S3 %3 L3|%4 0 L4 S5|0 %5 S6 L5|0 L6 0 %6
/* magic: S*/
private final static int MMASK[] = { 1, 2, 4, 24, 32, 64, 0};
private final static int MSHIFTL[] = { 1, 2, 0, 0, 0, 0, 0};
private final static int MSHIFTR[] = { 0, 0, 2, 1, 5, 5, 0};
/* level: L */
private final static int LMASK[] = { 1, 2, 4, 8, 16, 32, 64};
private final static int LSHIFTL[] = { 3, 1, 0, 0, 0, 0, 0};
private final static int LSHIFTR[] = { 0, 0, 0, 3, 3, 5, 4};
/* percent: % */
private final static int PMASK[] = { 1, 2, 4, 8, 16, 32, 64};
private final static int PSHIFTL[] = { 2, 0, 0, 0, 0, 0, 0};
private final static int PSHIFTR[] = { 0, 1, 1, 2, 1, 3, 6};
private final static int MAX_LVL_NUM = 127;
/**
* Create a level code from the given parameters
* @param seed The seed string used as base for the level code
* @param lvl The level number (0..127)
* @param percent Percentage of levels saved in the level won to get this code
* @param magic A "magic" number with more or less unknown sense
* @param offset Used to get a higher code for the first level
* @return String containing level code
*/
public static String create(final String seed, int lvl, final int percent, final int magic, final int offset) {
if (lvl > MAX_LVL_NUM || percent > 127 || magic > 127 || seed==null || seed.length() != 10)
return null;
byte bi[] = seed.getBytes();
byte bo[] = new byte[bi.length];
// add offset and wrap around
int level = lvl + offset;
level %= (MAX_LVL_NUM+1);
// create first 7 bytes
int sum = 0;
for (int i=0; i<7; i++) {
bi[i] += (byte)(((magic & MMASK[i]) << MSHIFTL[i]) >>> MSHIFTR[i]);
bi[i] += (byte)(((level & LMASK[i]) << LSHIFTL[i]) >>> LSHIFTR[i]);
bi[i] += (byte)(((percent & PMASK[i]) << PSHIFTL[i]) >>> PSHIFTR[i]);
bo[(i + 8 - (level % 8)) % 7] = bi[i]; // rotate
sum += bi[i] & 0xff; // checksum
}
// create bytes 8th and 9th byte (level)
bo[7] = (byte)(bi[7] + (level & 0xf));
bo[8] = (byte)(bi[8] + ((level & 0xf0) >> 4));
sum += (bo[7] + bo[8]) & 0xff;
// create 10th byte (checksum)
bo[9] = (byte)(bi[9] + (sum & 0x0f));
return new String(bo);
}
/**
* Extract the level number from the level code and seed
* @param seed The seed string used as base for the level code
* @param code Code that contains the level number (amongst other things)
* @param offset Used to get a higher code for the first level
* @return Level number extracted from the level code (-1 in case of error)
*/
public static int getLevel(final String seed, final String code, final int offset) {
byte bs[] = seed.getBytes();
byte bi[] = code.getBytes();
byte bo[] = new byte[bi.length];
if (seed.length() != 10 || code.length() != 10)
return -1;
int level = ((bi[7]-bs[7]) & 0xf) + (((bi[8]-bs[8])& 0xf)<<4);
// unrotate
for (int j=0; j<7; j++)
bo[(j + 6 + (level % 8)) % 7] = bi[j];
//decode
int level_ = 0;
int percent = 0;
for (int i=0; i<7; i++) {
int nibble = (bo[i] - bs[i]) & 0xff; // reconstruct nibble stored
level_ += ((nibble << LSHIFTR[i]) >> LSHIFTL[i]) & LMASK[i];
percent += ((nibble << PSHIFTR[i]) >> PSHIFTL[i]) & PMASK[i];
}
if (level != level_ || percent > 100)
return -1;
level -= offset;
while (level < 0)
level += MAX_LVL_NUM;
return level;
}
}
|