screp: parse player data
[perl/schtarr.git] / scmap
1 #!/usr/bin/perl
2 use strict;
3 use warnings;
4 use Data::Dumper;
5
6 my $SHOWWARN = 0;
7 my $SHOWMAP = "head"; # ascii, num, ppm
8 my $SHOWCOL = 0;
9
10 use Getopt::Long;
11 GetOptions(
12         "verbose|v!" => \$SHOWWARN,
13         "map|m=s" => \$SHOWMAP,
14         "color|c" => \$SHOWCOL,
15 );
16
17 {
18
19 package Data::StarCraft::Map;
20
21 sub new {
22         my ($class) = @_;
23         bless {}, $class;
24 }
25
26 sub _read {
27         my $self = shift;
28         my ($fh, $size, $seek) = @_;
29         seek *$fh, $seek, 0 if $seek;
30         read(*$fh, my $in, $size) eq $size or return undef;
31         return $in;
32 }
33
34 sub open {
35         my $self = shift;
36         my ($file) = @_;
37
38         while (not eof $file) {
39                 local $_ = $self->_read($file, 8)
40                         and my ($type, $size) = unpack "a4V", $_
41                         or die "Couldn't chunk header\n";
42                 $type =~ s/ +$//;
43 #printf STDERR "%s: %s\n", $type, $size;
44                 defined $self->{$type} and warn "duplicate map chunk $type\n";
45                 $self->{$type} = $self->_read($file, $size);
46         }
47         return $self;
48 }
49
50 sub version {
51         my $self = shift;
52         return 'v' . ord $self->{VER};
53 }
54
55 sub info {
56         my $self = shift;
57         my ($x, $y) = unpack "vv", $self->{DIM};
58         return {
59                 x => $x,
60                 y => $y,
61         };
62 }
63
64 sub width {
65         return $_[0]->info->{x};
66 }
67
68 sub tiles {
69         my $self = shift;
70         my @map = unpack 'v*', $self->{MTXM};
71         @map == $#map + 1 or warn(sprintf
72                 "couldn't parse map: only %d tiles\n", scalar @map
73         ), return;
74         return \@map;
75 }
76
77 my @maptile = (
78         '!' => [  0.. 31],
79         'd' => [ 32.. 62,  63],      # dirt (verified)
80         'h' => [ 64.. 94],           # high dirt
81         "~" => [ 96..117, 118..127], # water
82         'j' => [128..159],           # jungle/crushed rock
83         'o' => [160..186, 187..191], # rocky/shale (verified)
84         'R' => [192..223],           # raised jungle
85         'l' => [224..252, 253..255], # lava/ruins (verified)/flagstones?
86         'b' => [256..287],           # basilica?
87         'x' => [288..319],           # high jungle
88 #       'x' => [3745..3792],         # high jungle
89         'q' => [320..351],           # high ruins
90         ' ' => [352..383],
91         'a' => [384..415],           # high basilica
92         'm' => [416..447],           # mud
93         ' ' => [448..479],
94         ' ' => [480..511],
95
96         ' ' => [512..543],
97         ' ' => [544..575],
98         '/' => [576..607], # high dirt -> dirt (top left)
99         '/' => [608..639], # dirt -> high dirt
100         '\\' => [640..671], # high dirt -> dirt (top right)
101         '\\' => [672..703], # dirt -> high dirt (bottom left)
102         '\\' => [704..735], # high dirt -> dirt (bottom left)
103         '\\' => [736..767], # dirt -> high dirt (top right)
104         '/' => [768..863],
105         '=' => [864..1055], # some edge (tmp)
106         '=' => [1056..1183],
107         '=' => [1184..1727],
108         'D' => [1728..1780], # edge water
109         '/' => [1760..1791], # dirt -> water (top left)
110         '\\' => [1792..1823], # dirt -> water (top right)
111
112         'd' => [609..611],
113         'W' => [2048..2303],
114         '/' => [2304..2559],
115         'W' => [2560..2815],
116         'j' => [2816..3071],
117         'd' => [3072..3327],
118         'j' => [3328..3583],
119         'x' => [3648..3839],
120         'h' => [3840..4095],
121 #       'x' => [4096..4351],
122         'h' => [4096..4351],
123 #       'x' => [4352..4607],
124 #       ' ' => [4608..4863],
125         'l' => [4864..5311],
126         'q' => [5312..5503],
127         'x' => [5504..5631],
128         'q' => [5632..5759],
129         'j' => [5760..5823],
130 #       ' ' => [5824..5887],
131         '=' => [5888..6143], # raised jungle -> jungle
132 #       ' ' => [6144..6655],
133         '/' => [6656..7167],
134         '/' => [7168..7359], # basilica -> crushed rock
135         '/' => [7360..7551],
136         'i' => [7552..7807], # high temple
137 #       ' ' => [7808..8959],
138 #       '=' => [8960..9087],
139 #       'd' => [9088..9215],
140 #       ' ' => [9216..9727],
141 #       'm' => [9728..9983],
142 #       #    >= 9984 unencountered
143 #       ' ' => [19968..20480], # something here on twilight
144 #       ' ' => [20544..20736], # center thing on twilight
145 #       '~' => [20896..21023], # something in the water on twilight
146 #       'x' => [23104..23231], # something on twilight (on X or H)
147 #
148 #       'm' => [9216..9776], # mud <-> dirt
149 #       'r' => [5792..5875, 5888..5904], # raised jungle edge
150 #
151 #       'd' => [3042..3250], # dirt<->grass
152 #       'P' => [4608..4977], # dirt<->shale (verified) [also seems to be rocks on mud]
153 #       #'=' => [768..1731], # dirt<->lava ridge (verified)
154
155         'h' => [16389],
156         '1' => [16405, 16388],
157         '2' => [16421, 16404, 16387],
158         '3' => [16437, 16420, 16403, 16386],
159         '4' => [16453, 16436, 16419, 16402, 16385],
160         '5' => [              16435, 16418, 16401, 16384],
161         '6' => [                     16434, 16417, 16400],
162         '7' => [                            16433, 16416],
163         'd' => [16501,                             16432],
164         '7' => [16485, 16500],  # these ↕ aren't ramps in temple!!
165         '6' => [16469, 16484, 16499],
166         '5' => [16453, 16468, 16483, 16498],
167         '4' => [       16452, 16467, 16482, 16497],
168         '3' => [              16451, 16466, 16481, 16496],
169         '2' => [                     16450, 16465, 16480],
170         '1' => [                            16449, 16464],
171         'h' => [17248,                             16448],
172         '1' => [17264, 17249],
173         '1' => [17280, 17265, 17250],
174         '2' => [17296, 17281, 17266, 17251],
175         '3' => [17312, 17297, 17282, 17267, 17252],
176         '4' => [17328, 17313, 17298, 17283, 17268, 17253],
177         '5' => [       17329, 17314, 17299, 17284, 17269],
178         '6' => [              17330, 17315, 17300, 17285],
179         '7' => [                     17331, 17316, 17301],
180         '7' => [                            17332, 17317],
181         'd' => [17232,                             17333],
182         '7' => [17216, 17233],
183         '7' => [17200, 17217, 17234],
184         '6' => [17184, 17201, 17218, 17235],
185         '5' => [17168, 17185, 17202, 17219, 17236],
186         '4' => [17152, 17169, 17186, 17203, 17220, 17237],
187         '3' => [       17153, 17170, 17187, 17204, 17221],
188         '2' => [              17154, 17171, 17188, 17205],
189         '1' => [                     17155, 17172, 17189],
190         '1' => [                            17156, 17173],
191         'h' => [                                   17157],
192 );
193
194 my %eratile = (
195         4 => [
196                 # Longinus (by KuKulZa, modified MBCgame/iCCup)
197                 # SPRP: 6,0,1,0
198                 # TYPE: 82,65,87,66
199                 # VER: 205,0
200                 # SIDE: 5,5,5,1,2,0,1,2,7,7,7,4
201                 'd' => [
202                         19760..19761, 19792, 19793, 19680, 19681, 19712, 19713, 19664, 19665, 19728, 19729, # D→J
203                         19808,19809, 19776,19777, 19872,19873, 19920,19921,
204                         19744,19745, 19696,19697, 19632,19633, 19696,19697, 19952,19953,
205                         19568,19569, # below ridge
206                         3618,3634, 3586,3602, # D←J
207                         3601, # D→J(3585)
208                 ],
209                 'j' => [
210                         21968, 21969, 21984, 21985,
211                         21824,21825,21840,21841, 21856,21857,21872,21873, 21792,21793,
212                         21808,21809, 21888,21889,21904,21905,
213                         3616,3632,3584,3600,3616,3632, # J→D
214                         3585, # J→D(3601)
215                 ],
216                 'l' => [
217                         22608..22611, 22624..22627, 22640..22643,
218                 ],
219                 'o' => [
220                         24850, # besides ladder
221                         20832,20833,20848,20849, 20768,20769,20784,20785,
222                         20864,20865,20880,20881,
223                         20704,20705,20720,20721, # large rock
224                         4432,4433,4434,4448,4449,4464,4465,
225                         4545,4561,4577,4593, 4544,4560,4576,4592,
226                 ],
227                 'h' => [
228                         18000,18001, # H→X
229                         17952,17953, 17936,17937, 17920,17921, 17856,17857, 17888,17889, # H→X unsure
230                         17984,17985, 18160,18161, 18128,18129, 18048,18049,
231                         19648,19649,19616,19617, 18016,18017,
232                         17696,17697,17712,17713, # tree
233                         17872,17873,17904,17905, 18144,18145,
234                         18448,18449,18464,18465,18480,18481,
235                 ],
236                 'm' => [ # mud hole
237                         9219,9235,9539,9555,
238                         9218,9234,9795,9235,9811,9571,9587,
239                         9472,9488,9250,9266,9635,9651,9280,9296,
240                         9504,9520,9665,9681,9344,9360,9760,9776,9539,9555,
241                         9475,9491,9889,9905,9376,9392,9440,9456,9571,9587,
242                         9507,9523,9377,9393,
243
244                         9537,9553,
245                         9569,9585,9474,9490,9283,9299,9216,9232,9536,9552,
246                         9536,9552,9923,9939,9283,9299,9506,9522,9827,9843,9728,9744,9568,9584,
247                         9283,9299,9217,9233,9731,9747,9568,9584,9699,9715,9315,9331,9284,9300,9217,9233,9955,9971,
248                         9763,9779,9793,9809,9379,9395,9664,9680,9316,9332,9249,9265,9536,9552,
249                         9443,9459,9921,9937,9284,9300,9216,9232,9284,9300,9216,9232,9696,9712,9345,9361,9409,9425,9604,9620,9568,9584,
250                         9216,9232,9764,9780,9248,9264,9316,9332,9248,9264,9346,9362,9441,9457,9860,9876,9537,9553,
251                         9728,9744,9444,9460,9667,9683,9348,9364,9411,9427,9602,9618,9378,9394,9444,9460,9569,9585,
252                         9891,9907,9380,9396,9443,9459,9858,9874,9540,9556,
253                         9379,9395,9442,9458,9572,9588,
254                 ],
255                 '/' => [
256                         # Longinus (by KuKulZa, modified MBCgame/iCCup)
257                         9125, 9141, 9126, 9142, # D→~
258                         9120, 9136, # H→D
259                         9059,9075, 9189,9205, # D→~
260                         19824,19825, # D→~
261                         19200,19201,19216,19217, # object on D
262                 ],
263                 '/' => [
264                         17632,17633,17648,17649, # H rotating thing
265                         18208,18209, # H skull thing
266                         18224,18225,18240,18241, # H statuey thing
267                 ],
268                 'q' => [
269                         23872,23873,23874,23875,23888,23889,23890,23891,23904,23905,23906,23907, # Q crater
270                         23680,23681,23696,23697,23712,23713,
271                 ],
272                 'x' => [
273                         24336,24337,24352,24353, 24272,24273,24288,24289,
274                         24272,24273,24288,24289, 24368,24369,24384,24385,
275                         4353,4369, 4385,4401,4353,4369, 4386,4402, 4385,4401,
276                         4386,4402,4354,4370,4386,4402,
277                 ],
278                 '/' => [
279                         19856,19857,20144,20145, # D skeleton
280                 ],
281                 '/' => [21184], 'W' => [21185,21200,21201,21216,21217], # standing rock
282                 '/' => [21232], 'W' => [21233,21248,21249,21264,21265], # standing rock
283                 '7' => [25011, 25010], # M»H
284                 '7' => [24699, 25143], 6 => [24716], # M»H
285                 'W' => # island o' rocks
286                                [21120..21125, 21136..21141, 21152..21157, 21168..21173],
287                         '/' => [21121,21122,21136..21139,21152..21154],
288                         '~' => [21120,21124,21125,21141,21157,21171..21173],
289                 '/' => [
290                         # D→~ coast
291                         8997,9013,8963,8979, 8996,9012,8963,8979,8993,9009, 8997,9013,
292                         8998,9014, 8993,9009, 9187,9203, 9121,9137, 9131,9147, 8992,9008,
293                         9190,9206, 9062,9078, 8996,9012, 9090,9106,9194,9210,
294                         9061,9077,9029,9045,9184,9200,8998,9014, 9024,9040,8997,9013,
295                 ],
296
297                 # Lost Temple (default?)
298                 # SPRP: 4,0,5,0
299                 # VER: 59,0
300                 # SIDE: 5,5,5,5,0,2,1,0,7,7,7,4
301                 '/' => [
302                         9089,9105, # H←D
303                         9196,9212, # H←D→~
304                         8966,8982, 8962,8978, # H→~
305                         9088,9104, # D→D/~
306                         16832..16835,16848..16851,16864..16867,16880..16883, # H→D ridge (ramp elsewhere?)
307                         16384..16389, 16400..16405, 16416..16421, 16432..16437, # idem
308                         8961,8977,9155,9171, # H←D→~
309                         20160,20161,19984,19985,19986,19987,20000,20001,20002,20003, # D→H
310                         9124,9140, 9122,9138, 9002,9018, 8960,8976, 9168,9152, 8995,9011, # H→D→~
311                         9057,9073, # H→D→~ temple.6
312                         8968,8984, # D↔H
313                 ],
314                 'j' => [
315                         21952,21953,
316                 ],
317                 'x' => [
318                         4384,4400, 4352,4368, # X→H
319                 ],
320                 'h' => [
321                         18096,18097, 17968,17969, 18032,18033,18176,18177,
322                 ],
323                 'd' => [
324                         9347,9363,9953,9969,9473,9489,9251,9267,9633,9649,9505,9521,9410,9426,
325                         9347,9363, 19840,19841, 19888,19889, 20208,20209,20224,20225,
326                         20240,20241,20256,20257, 20272,20273,20288,20289, 19601,19600,
327                         20304,20305,20320,20321, # tree
328                 ],
329                 'o' => [
330                         4673,4689,4737,4753,4705,4721,4769,4785, # rocks on D
331                         4674,4690,4706,4722,4674,4690,4480,4496,4706,4722,4832,4848,4640,4656,
332                         4736,4752,4768,4784,
333                         4482,4498, 4834,4850, 4642,4658,
334                 ], 'd' => [4498,4642],
335                 'm' => [
336                         # M→D mud holes
337                         9281,9297,9313,9329, 9281,9297,9313,9329, 9538,9554,9570,9586,
338                         9282,9298,9282,9298,9220,9236,9476,9492,9314,9330,9729,9745,9412,9428,9476,9492,9314,9330,9538,9554,9476,9492,9252,9268,
339                         9508,9524,9668,9684,9600,9616,9508,9524,9666,9682,9601,9617,9570,9586,9508,9524,9408,9424,9700,9716,9632,9648,9698,9714,9282,9298,9314,9330,
340                         9312,9328, 9412,9428, 9636,9652, 9634,9650,
341                         9730,9746, 9761,9777,9762,9778, 9794,9810,
342                         9732,9748, # temple.5
343                         9603,9619, # temple.6
344                 ],
345                 'r' => [
346                         5859,5875, 5858,5874, # top edge
347                 ],
348                 'O' => # temple center ornament
349                         [
350                                 22320,22321,22336,22337,22352,22353,
351                                 22368,22369,22384,22385,22400,22401,
352                                 22464..22467,22480..22483,22496..22499,
353                                 22800,22801,22802,22803,22816,22817,22818,22819,22832,22833,22834,22835,
354                                 22752,22753,22754,22755,22768,22769,22770,22771,22784,22785,22786,22787,
355                         ],
356                         'l' => [ # cut out shapes
357                                 22464,22467,22496,22499, 22321,22353, 22368,22400,
358                                 22800,22802,22803,22832,22835, 22819,
359                                 22752,22753,22755,22787,22784, 22768,
360                         ],
361                 'D' => # underwater cave
362                         [
363                                 21440,21441,21442,21443, 21456,21457,21458,21459,
364                                 21472,21473,21474,21475, 21488,21489,21490,21491,
365                         ],
366                         'W' => [21456, 21472,21473,21474,21475],
367                         'o' => [21442,21443],
368                         '~' => [21488,21489, 21490,21491],
369                 'i' => [
370                         23632,23633,23648,23649,23664,23665, 23584,23585,23600,23601,23616,23617, # statue things on Q
371                 ],
372                 'D' => [1824..1839], 'W' => [1840..1855], # D→~ bright transition
373                 'D' => [1856..1871], 'd' => [1872..1887], # D→~ bleft ridge
374                 'W' => [1888..1903], 'D' => [1904..1919], # D→~ bleft transition
375                 '~' => [1920..1935], 'W' => [1936..1951], # w→~ bleft transition
376                 'd' => [1952..1967], 'D' => [1968..1983],
377                 'D' => [1984..1999], 'W' => [2000..2015],
378                 'W' => [2016..2031], '~' => [2032..2047],
379                 'D' => [8965,8981, 8964,8980, 9174,9158, 9010,8994], # H→D→~
380                 'd' => [19936,19937], # D→~
381                 '/' => [19905], 'd' => [19904], # H→D
382                 'r' => [
383                         5825,5841, 5857,5873, # J→R→map edge
384                         5826,5842, # J↔R
385                 ],
386                 'q' => [
387                         # gap
388                         23456,23457,23458,23459, 23472,23473,23474,23475,
389                         23488,23489,23490,23491, 23504,23505,23506,23507,
390                         # towery thing
391                         23824,23825,23826,23827, 23840,23841,23842,23843, 23856,23857,23858,23859,
392                 ],
393
394                 # Plains to Hill (v2.00 by Sir.Lupin)
395                 # VER: 59,0
396                 # SPRP: 1,0,2,0
397                 # SIDE: 5,5,5,5,0,2,1,0,7,7,7,4
398                 # FORC: 0,0,0,0,1,1,1,1,31,0,30,0,29,0,28,0,1,11,0,0
399                 '/' => [
400                         # H→D bottom left side (may be a ramp elsewhere)
401                         16768,16769,16770,16771, 16784,16785,16786,16787,
402                         16800,16801,16802,16803, 16816,16817,16818,16819,
403                         # idem bottom right side
404                         16960,16961,16962,16963, 16976,16977,16978,16979,
405                         16992,16993,16994,16995, 17008,17009,17010,17011,
406                         # idem
407                         17088,17089,17090,17091, 17104,17105,17106,17107,
408                         17120,17121,17122,17123, 17136,17137,17138,17139,
409                 ],
410
411                 # Python (v1.3 by Terrance, modified by Forgotten_/KeSPA)
412                 # ERA: 100,0
413                 # TYPE: 82,65,87,66
414                 # VER: 205,0
415                 # SPRP: 1,0,7,0
416                 # SIDE: 5,5,5,5,0,2,1,0,7,7,7,4
417                 # FORC: 0,0,0,0,1,1,1,1,2,0,4,0,5,0,6,0,1,14,15,15
418                 'x' => [
419                         24464,24465, 24448,24449
420                 ],
421                 'h' => [
422                         18064,18065,
423                 ],
424                 '/' => [
425                         9186,9202,
426                         18112,18113, # H→D
427                         9154,9170,9027,9043,9157,9173, # H↔D
428                 ],
429                 'O' =>
430                         [19504,19505,19520,19521, 18720,18721,18736,18737], # rock things
431                         'h' => [18737],
432                 'O' => # hole
433                         [17488..17491,17504..17507,17520..17523,17536..17539],
434                         'h' => [17490,17491,17507,17523,17536..17539],
435                 'o' => [
436                         4610, 4610,4626, 4481,4497,4513,4529, 4514,4530,
437                         4417,4608,4624,4418, 4512,4528, 4450,4466,
438                         4609,4625,4546,4562, 4833,4849, 4801,4817, 4800,4816,
439                 ],
440                 'd' => [
441                         4672,4688,4704,4720, # D↔O
442                         19584,19585,
443                         4416, # D→O
444                         4641,4657,4578,4594, 4802,4818, # O→D
445                 ],
446                 'm' => [
447                         9824,9840,9952,9968,9920,9936,9888,9904, 9796,9812,9924,9940,
448                         9697,9713, 9890,9906, 9922,9938, 9792,9808,9856,9872,9826,9842,
449                 ],
450                 'o' => [4738,4770], 'd' => [4754,4786],
451                 '/' => [18256,18257,18272,18273], 'h' => [18288,18289], # obelisk
452                 '/' => # sunken temple
453                         [21024..21029, 21040..21045, 21056..21061, 21072..21077, 21088..21093,21104..21109],
454                         '~' => [21024,21104,21109,21027,21059,21076,21072,21093,],
455                         'W' => [21029, 21060,21045,21073,21090,21106,21092,21107,21075,21108,21058, 21056,21088,21105,21077],
456                 'O' => # ruins similar to 22464
457                         [22512..22515, 22528..22531, 22544..22547],
458                         'l' => [22512,22515, 22544,22547],
459                 'Q' => [17664,17665,17680,17681], # rock thing
460                 'Q' => [17728,17729,17744,17745], # tree
461                 '/' => [17808,17824,17840], 'h' => [17809,17825,17841],
462                 '6' => [25025], # D»H ramp (between D and 17328 = level 4)
463
464 #},     2 => {
465                 # Twilight Star (default)
466                 # (all guessed from low res thumb)
467                 'h' => [17584,17585], # H→D
468                 'r' => [5827,5843, 5824,5840,5856,5872],
469                 'W' => [
470                         # water objects
471                         20912,20913,20928,20929, 20896,20897, 20944,
472                         19440,19441,19456,19457, 20945,20960,20961,
473                         20816,20817,
474                 ],
475                 'h' => [17760,17761,17776,17777, 17600,17601],
476                 'D' => [9093,9109],
477                 'o' => [19472..19475, 19488..19491],
478                 'o' => [
479                         21728,21729, 21744,21745, 21760,21761,
480                         21776,21777, 19536,19537, 19538,19539, 19552..19555,
481                 ],
482                 'j' => [3587,3603],
483                 'O' => [19232..19235, 19248..19251], 'j' => [19218,19219],
484                 'O' => [19938,19939,19954,19955],
485                 'h' => [17792,17793],
486                 'x' => [4356,4372],
487                 'O' => [ # exotic/shiny things and other objects
488                         18656,18657,18672,18673, 18496,18497,18512,18513,
489                         18560..18563, 18576..18579, 18592..18595,
490                         18528,18529,18544,18545, 18864,18865,
491                         18608..18611,18624..18627,18640..18643,
492                         18912..18915,18928..18931,18944..18947,
493                         18816..18819,18832..18835,18848..18851,
494                         18960..18963,18976..18979,18992..18995,
495                         19008..19011,19024..19027,
496                         19040..19043,19056..19059,
497                 ],
498                 'A' => [ # X→A
499                         7811,7827,7873,7889,7809,7825,7875,7891,
500                         8707,8723,8737,8753,7874,7890,7808,7824,7872,7888,7904,
501                         8003,8019,8160,8176,7810,7826,
502                 ],
503                 'a' => [ # A←X
504                         7843,7859,7905,7921,7841,7857,7907,7923,
505                         8705,8721,7971,7987,8065,8081,8738,8754,7840,7856,
506                         7920,7906,7922,7938,7954,7969,7985,8066,8082,8035,8051,
507                         7970,7986,8032,8048,
508                         8034,8050,7936,7952,8033,8049,7937,7953,
509                 ],
510                 'R' => [6177,6193],
511                 '/' => [18080,18081],
512                 'a' => [8032..8047], 'a' => [8048..8063], # #3 bottom left
513                 'A' => [7841..7843], 'a' => [7857..7859], # #2 top left
514                 'A' => [8000..8003], 'x' => [8016..8019], # #1 bottom right
515                 'A' => [8064..8067], 'a' => [8080..8083], # #2 bottom left
516                 'A' => [8224..8227], 'x' => [8240..8243], # #1 top right
517                 'A' => [8288..8291], 'x' => [8304..8307], # #1 bottom right
518                 'a' => [8355], 'A' => [8371], # #2 top right
519                 'a' => [8322], 'A' => [8338], # #2 top right
520                 'A' => [8512], 'x' => [8528], # #1 top right
521                 'x' => [7811], 'A' => [7827],
522                 'x' => [8096..8099], 'A' => [8112..8115],
523                 'x' => [8163], 'a' => [8179],
524                 'x' => [8192..8195], 'A' => [8208..8211],
525                 'x' => [8128..8131], 'A' => [8144..8147],
526                 'A' => [8258,8274],
527                 'a' => [7939,7955], # #3 bottom right
528                 'a' => [7968..7971], 'A' => [7984..7987],
529                 'A' => [8256,8272],
530                 'A' => [8257,8273, 8259,8275, 8162,8178],
531
532                 '!' => [],
533
534                 # tau cross (v1.1 by Rose.Of.Dream/BW4eVeR)
535                 # ERA: 6
536                 # FORC: 0,0,0,1,1,1,1,1,7,0,6,0,5,0,4,0,1,15,15,15
537                 # SIDE: 5,5,5,1,0,2,1,0,7,7,7,4
538                 # SPRP: 1,0,2,0
539                 # TYPE: 82,65,87,66
540                 # VER: 205
541                 '?' => [
542                         6176,6192, 20976,20977, 20592,20593, 21392,21393, 20800,20801,
543                         20608,20609, 20624,20625, 20640,20641, 20992,20993, 21008,21009,
544                         19922,19923,22070,22071, 19968..19971, 22230,
545                         22133,22137,22272,22157,22288,22313,
546                         20592,20593,21392,21393,20800,20801,20608,20609,20624,20625,20640,20641,20992,20993,21008,21009,19922,19923,
547                         22070,22071,19968,19969,19970,19971,22230,22272,22157,22288,22313,6147,6163,6178,6194,3589,3605,22147,22162,22163,22164,
548                         22180,22315,18400,18401,18336,18337,18192,18193,17730,17731,17826,17827,17746,17747,17842,17843,
549                         17762,17763,17794,17795,17778,17779,17810,17811,17616,17617,
550                         20688,20689,6145,6161,20736,20737,21408,21409,21410,21411,
551                         20752,20753,21424,21425,21426,21427,21376,21377,20656,20657,
552                         21312,21313,21314,21315,20672,20673,21328,21329,21330,21331,
553                         6146,6162,21344,21345,21346,21347,21360,21361,21362,21363,6144,
554                         6160,
555                 ],
556                 '2' => # bridges
557                         [
558                                 22231..22235, 22246..22253, 22260..22269,
559                                 22273..22285, 22289..22301, 22306..22312, 22324..22328,
560                         ],
561                         '4' => [22246..22253, 22273..22285, 22306..22312],
562                         '2' => [
563                                 22084..22086, 22096..22103, 22112..22121, 22128..22139,
564                                 22144..22156, 22165..22171, 22181..22199,
565                         ],
566                         '4' => [22084..22086, 22112..22121, 22144..22156, 22181..22199],
567                 'r' => [22342,22343],
568
569                 # Nostalgia (WGT13, v1.3 by Rose.of.Dream)
570                 # ERA: 0,0
571                 # FORC: 0,0,0,0,1,1,1,1,12,0,11,0,10,0,9,0,1,14,0,0
572                 # SIDE: 5,5,5,5,0,2,1,0,7,7,7,4
573                 # SPRP: 1,0,4,0
574                 # TYPE: 82,65,87,66
575                 # VER: 205
576                 '!' => [],
577         ], # jungle
578 );
579
580 our %tilechar;
581 while (my ($char, $matches) = splice @maptile, 0, 2) {
582         $tilechar{$_} = $char for @$matches;
583 }
584 while (my ($char, $matches) = splice @{$eratile{4}}, 0, 2) {
585         $tilechar{$_} = $char for @$matches;
586 }
587
588 my @mapunit = ( # character => width, height, ids
589         '$' => [2,1, 176..178], # minerals
590         '*' => [2,1, 188], # gas
591         '@' => [2,2, 214], # start pos
592 );
593
594 our %unitchar;
595 while (my ($char, $matches) = splice @mapunit, 0, 2) {
596         my @charinfo = ($char, splice @$matches, 0, 2);
597         $unitchar{$_} = \@charinfo for @$matches;
598 }
599
600 sub tiles_parsed {
601         my $self = shift;
602         my $map = $self->tiles or return;
603         if ($SHOWWARN) {
604                 use Tie::IxHash;
605                 tie my %unknown, 'Tie::IxHash';
606                 defined $tilechar{$map->[$_]} or warn(sprintf
607                         "unknown tile %d at (%d,%d)\n",
608                         $map->[$_], $_ % $self->width, $_ / $self->width
609                 ), $unknown{$map->[$_]} = $_ for 0 .. $#$map;
610                 warn sprintf "unknown: %s\n", join ",", keys %unknown if keys %unknown;
611         }
612         $_ = defined $tilechar{$_} ? $tilechar{$_} : '?' for @$map;
613         for ($self->units) {
614                 my ($chr, $width, $height) = defined $unitchar{$_->{id}} ?
615                         @{ $unitchar{$_->{id}} } : ('#', 1, 1);
616                 for my $x ($_->{x} .. $_->{x} + $width - 1) {
617                         for my $y ($_->{y} .. $_->{y} + $height - 1) {
618                                 $map->[$x + $y * $self->width] = $chr;
619                         }
620                 }
621         }
622         return $map;
623 }
624
625 sub units {
626         my $self = shift;
627         my @units;
628         for (my $i = 0; $i < length $self->{UNIT}; $i += 36) {
629                 # d1, d2, x*32, y*32, unitid, bytes1, playerid, bytes2, mineral, bytes3
630                 my @pack = unpack "v5x6Cx3vx14", substr $self->{UNIT}, $i, 36;
631                 push @units, {
632                         id => $pack[4],
633                         player => $pack[5],
634                         amount => $pack[6],
635                         x => $pack[2] >> 5,
636                         y => $pack[3] >> 5,
637 #                       d1 => $pack[0],
638 #                       d2 => $pack[1],
639                 };
640         }
641         return @units;
642 }
643
644 sub units_parsed {
645         my $self = shift;
646         my @units;
647         for ($self->units) {
648                 my ($chr, $width, $height) = defined $unitchar{$_->{id}} ?
649                         @{ $unitchar{delete $_->{id}} } : ('#', 1, 1);
650                 $_->{chr} = $chr;
651                 $_->{width} = $width;
652                 push @units, $_;
653         }
654         return @units;
655 }
656
657 sub colors {
658         my $self = shift;
659         my @colormap = (
660                 qw(
661                         FF0000 0000FF 209070 88409C E87824 5C2C14 FFFFFF DCDC3C
662                         0F930F FCFC8F EFCEBD 547CDC
663                 ),
664                 12 => "pale green", "gray", "pale yellow", "cyan",
665                 17 => "black", "neon blue",
666                 21 => "lavender", "black",
667                 30 => "sky blue",
668                 33 => "purple",
669         );
670         my @players;
671         for (unpack "C*", $self->{COLR}) {
672                 push @players, $colormap[$_] || "? (#$_)";
673         }
674         return \@players;
675 }
676
677 sub era {
678         my $self = shift;
679         return unpack "v", $self->{ERA};
680 }
681
682 }
683
684 my $map = Data::StarCraft::Map->new->open(\*STDIN);
685
686 if ($SHOWMAP ne "ppm") {
687         printf("%s size %dx%d, %d player\n",
688                 $map->version,
689                 $map->info->{x}, $map->info->{y},
690                 scalar grep {$_->{id} == 214} $map->units,
691         );
692         print "\n";
693 }
694
695 if ($SHOWMAP eq "head") {
696         if ($map->{STR}) {
697                 my @str = split /\0/, substr $map->{STR}, 2051;
698                 $SHOWCOL ? (
699                         s/([\001-\007])/sprintf '\e[0;%dm', 30+ord($1)/eg
700                         and $_ .= "\e[0;37m"
701                 ) : s/[\001-\017]//g, print "* $_\n" for @str;
702                 print "\n";
703         }
704         printf "%-4s %d\n", $_, defined $map->{$_} ? length $map->{$_} : 0
705                 for sort keys %$map;
706         print "\n";
707         printf "%s: %s\n", $_, join ",", unpack "C*", $map->{$_}
708                 for sort grep { defined $map->{$_} and length $map->{$_} < 32 }
709                         keys %$map;
710         print "\n";
711 }
712
713 sub world {
714         my $self = shift;
715         # ERA:          0        1     2 3 4      5 6 7
716         my @worlds = qw(badlands space 0 0 jungle 0 0 twilight);
717         return $worlds[$self->era] || "?";
718 }
719
720 my %mapcol = (
721         # jungle world
722         '~' => '0 0 3', # water
723         'W' => '3 3 7', # coast/water object
724         'D' => '8 7 5', # D shore
725
726         'j' => '2 3 0', # jungle
727         'd' => '3 3 0', # dirt
728         'm' => '3 3 1', # mud
729         'o' => '3 3 2', # rocky
730         'O' => '11 10 6', # object on lower ground
731         'l' => '4 4 2', # ruins
732
733         'R' => '3 9 3',   # raised jungle
734         'r' => '8 14 8',
735         'x' => '6 9 2',   # high jungle
736         'h' => '10 10 4', # high dirt
737         'q' => '12 11 0', # high ruins
738         'i' => '13 9 0', # temple
739
740         'R' => '2 5 2',   # raised jungle
741         'r' => '4 6 4',
742         'x' => '5 7 3',   # high jungle
743         'h' => '7 7 3', # high dirt
744         'q' => '8 8 5', # high ruins
745         'Q' => '15 15 8', # object on higher ground
746         'i' => '10 9 5', # temple
747         'b' => '5 4 3', # asphalt/basilica
748         'a' => '13 11 5', # high basilica
749         'A' => '13 12 10', # bas. sides
750
751         '/' => '15 15 11',
752         '\\' => '13 13 9',
753         '=' => '11 12 8',
754
755         '7' => '3 3 1', # D>H
756         '6' => '4 4 1',
757         '5' => '4 4 2',
758         '4' => '5 5 2',
759         '3' => '5 5 3',
760         '2' => '6 6 3',
761         '1' => '7 7 4',
762
763         # common
764         '$' => '0 13 15', # mineral patch
765         '*' => '4 15 8', # gas geyser
766         '@' => '14 4 3', # start location
767         '#' => '15 12 0', # unknown unit
768
769         ' ' => '15 15 15', # defined unencountered
770         '?' => '0 0 0',    # undefined
771         '!' => '15 0 15',  # marked
772         '-' => '0 15 0',   # debug
773 );
774 my @eramapcol = (
775         { # badlands (era 0)
776                 # d:   dirt
777                 # o?:  mud 
778                 # h:   high dirt
779                 # ~:   water
780                 # j:   grass
781                 # x/o: high grass
782                 # s:   structure
783                 # b:   asphalt
784                 # i?:  rocky ground
785
786                 'b' => '3 3 2', # asphalt
787                 'j' => '5 4 0', # grass
788                 'd' => '4 3 1', # dirt
789                 'q' => '4 3 2', # dirt ↔ asphalt
790                 'o' => '8 8 5', # high grass (also mud?)
791                 'm' => '3 2 14', # ?
792                 'O' => '11 10 6', # object on lower ground
793                 'l' => '4 3 2', # asphalt↔dirt
794
795                 'h' => '8 7 5', # high dirt
796                 'x' => '9 8 5', # high grass ↔ high dirt?
797
798                 '/' => '15 14 11',
799                 'r' => '9 9 9', # structure
800         },
801
802         { # space platform
803         },
804
805         { # desert
806                 #    tar
807                 #    dirt
808                 #    dried mud
809                 #    sand dunes
810                 #    rocky ground
811                 #    crags
812                 #    sandy sunken pit
813                 #    compound
814                 #    high dirt
815                 #    high sand dunes
816                 #    high crags
817                 #    high sandy sunken pit
818                 #    high compound
819         },
820
821         { # ice
822                 #    ice
823                 #    snow
824                 #    moguls
825                 #    dirt
826                 #    rocky snow
827                 #    grass
828                 #    water
829                 #    outpost
830                 #    high snow
831                 #    high dirt
832                 #    high grass
833                 #    high water
834                 #    high outpost
835         },
836
837         { # jungle (era 4)
838                 # ~: water
839                 # d: dirt
840                 # m: mud
841                 # j: jungle
842                 # o: rocky ground
843                 # l: ruins
844                 # r: raised jungle
845                 #    temple
846                 # h: high dirt
847                 # x: high jungle
848                 # q: high ruins
849                 #    high raised jungle
850                 # i: high temple
851         },
852
853         { # ash
854                 #    magma
855                 # d: dirt
856                 # l: lava
857                 # o: shale
858                 #    broken rock
859                 #    high dirt
860                 #    high lava
861                 #    high shale
862         },
863
864         { # installation
865         },
866
867         { # twilight (era 7)
868                 #    water
869                 #    dirt
870                 #    mud
871                 #    crushed rock
872                 #    crevices
873                 #    flagstones
874                 #    sunken ground
875                 #    basilica
876                 #    high dirt
877                 #    high crushed rock
878                 #    high flagstones
879                 #    high sunken ground
880                 #    high basilica
881 #               'b' => '5 4 3', # basilica
882 #               'p' => '3 3 2', # ?
883 #               'r' => '3 9 3', # sunken stuff
884         },
885 );
886 my %addmapcol = !$SHOWWARN ? () : (
887         '?' => '15 0 0',
888         'm' => '2 2 1',
889 );
890
891 #%mapcol = (%mapcol, %{$eramapcol[$map->era]}, %addmapcol);
892 %mapcol = (%mapcol, %{$eramapcol[4]}, %addmapcol);
893
894 #        MTXM TILE
895 # ?      ?    yes
896 # v205 = yes  no
897
898 my %mapsep = (
899         num => ',',
900         ppm => '  ',
901         ascii => '',
902 );
903
904 if (defined $mapsep{$SHOWMAP}) {
905         my $MAPCHARSEP = $mapsep{$SHOWMAP};
906
907         my $tiles = $SHOWMAP eq "num" ? [ map sprintf('%5d', $_), @{$map->tiles} ]
908                 : $map->tiles_parsed;
909
910         if ($SHOWMAP eq "ppm") {
911                 printf "P3\n%d %d\n15\n", $map->info->{x}, $map->info->{y};
912                 if ($SHOWWARN) {
913                         my %uncolored;
914                         defined $mapcol{$_} or $uncolored{$_}++ for @$tiles, '?';
915                         warn "no color for tile '$_'\n" for keys %uncolored;
916                 }
917                 $_ = $mapcol{$_} || $mapcol{'?'} || '0 0 0' for @$tiles;
918                 if (0){
919                         sub surround {
920                                 my ($unit, $match, $color) = @_;
921                                 my $pos = $unit->{x} + $unit->{y} * $map->width;
922                                 for my $delta (
923                                         $pos+1, $pos-1,
924                                         $pos+$map->width, $pos-$map->width,
925                                         $pos+1+$map->width, $pos+1-$map->width,
926                                 ) {
927                                         $tiles->[$delta] =~ s/($match)/$1 + $color/e
928                                                 unless $tiles->[$delta] eq $mapcol{$unit->{chr}};
929                                 }
930                         }
931                         for ($map->units_parsed) {
932                                 if ($_->{chr} eq '$') {
933                                         surround($_, qr/\d+$/, 7);
934                                 } elsif ($_->{chr} eq '*') {
935                                         surround($_, qr/\d+(?= \d+$)/, 3);
936                                 }
937                         }
938                 }
939         }
940
941         while (my @line = splice @$tiles, 0, $map->width) {
942                 printf "%s\n", join $MAPCHARSEP, @line;
943         }
944 }
945