7 my $SHOWMAP = "head"; # ascii, num, ppm
12 "verbose|v!" => \$SHOWWARN,
13 "map|m=s" => \$SHOWMAP,
14 "color|c" => \$SHOWCOL,
19 package Data::StarCraft::Map;
28 my ($fh, $size, $seek) = @_;
29 seek *$fh, $seek, 0 if $seek;
30 read(*$fh, my $in, $size) eq $size or return undef;
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";
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);
52 return 'v' . ord $self->{VER};
57 my ($x, $y) = unpack "vv", $self->{DIM};
65 return $_[0]->info->{x};
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
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
91 'a' => [384..415], # high basilica
92 'm' => [416..447], # mud
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)
105 '=' => [864..1055], # some edge (tmp)
108 'D' => [1728..1780], # edge water
109 '/' => [1760..1791], # dirt -> water (top left)
110 '\\' => [1792..1823], # dirt -> water (top right)
121 # 'x' => [4096..4351],
123 # 'x' => [4352..4607],
124 # ' ' => [4608..4863],
130 # ' ' => [5824..5887],
131 '=' => [5888..6143], # raised jungle -> jungle
132 # ' ' => [6144..6655],
134 '/' => [7168..7359], # basilica -> crushed rock
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)
148 # 'm' => [9216..9776], # mud <-> dirt
149 # 'r' => [5792..5875, 5888..5904], # raised jungle edge
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)
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],
196 # Longinus (by KuKulZa, modified MBCgame/iCCup)
200 # SIDE: 5,5,5,1,2,0,1,2,7,7,7,4
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
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
217 22608..22611, 22624..22627, 22640..22643,
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,
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,
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,
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,
256 # Longinus (by KuKulZa, modified MBCgame/iCCup)
257 9125, 9141, 9126, 9142, # D→~
259 9059,9075, 9189,9205, # D→~
261 19200,19201,19216,19217, # object on D
264 17632,17633,17648,17649, # H rotating thing
265 18208,18209, # H skull thing
266 18224,18225,18240,18241, # H statuey thing
269 23872,23873,23874,23875,23888,23889,23890,23891,23904,23905,23906,23907, # Q crater
270 23680,23681,23696,23697,23712,23713,
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,
279 19856,19857,20144,20145, # D skeleton
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],
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,
297 # Lost Temple (default?)
300 # SIDE: 5,5,5,5,0,2,1,0,7,7,7,4
304 8966,8982, 8962,8978, # H→~
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
318 4384,4400, 4352,4368, # X→H
321 18096,18097, 17968,17969, 18032,18033,18176,18177,
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
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,
333 4482,4498, 4834,4850, 4642,4658,
334 ], 'd' => [4498,4642],
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
346 5859,5875, 5858,5874, # top edge
348 'O' => # temple center ornament
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,
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,
361 'D' => # underwater cave
363 21440,21441,21442,21443, 21456,21457,21458,21459,
364 21472,21473,21474,21475, 21488,21489,21490,21491,
366 'W' => [21456, 21472,21473,21474,21475],
367 'o' => [21442,21443],
368 '~' => [21488,21489, 21490,21491],
370 23632,23633,23648,23649,23664,23665, 23584,23585,23600,23601,23616,23617, # statue things on Q
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
383 5825,5841, 5857,5873, # J→R→map edge
388 23456,23457,23458,23459, 23472,23473,23474,23475,
389 23488,23489,23490,23491, 23504,23505,23506,23507,
391 23824,23825,23826,23827, 23840,23841,23842,23843, 23856,23857,23858,23859,
394 # Plains to Hill (v2.00 by Sir.Lupin)
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
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,
407 17088,17089,17090,17091, 17104,17105,17106,17107,
408 17120,17121,17122,17123, 17136,17137,17138,17139,
411 # Python (v1.3 by Terrance, modified by Forgotten_/KeSPA)
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
419 24464,24465, 24448,24449
427 9154,9170,9027,9043,9157,9173, # H↔D
430 [19504,19505,19520,19521, 18720,18721,18736,18737], # rock things
433 [17488..17491,17504..17507,17520..17523,17536..17539],
434 'h' => [17490,17491,17507,17523,17536..17539],
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,
441 4672,4688,4704,4720, # D↔O
444 4641,4657,4578,4594, 4802,4818, # O→D
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,
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)
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],
471 20912,20913,20928,20929, 20896,20897, 20944,
472 19440,19441,19456,19457, 20945,20960,20961,
475 'h' => [17760,17761,17776,17777, 17600,17601],
477 'o' => [19472..19475, 19488..19491],
479 21728,21729, 21744,21745, 21760,21761,
480 21776,21777, 19536,19537, 19538,19539, 19552..19555,
483 'O' => [19232..19235, 19248..19251], 'j' => [19218,19219],
484 'O' => [19938,19939,19954,19955],
485 'h' => [17792,17793],
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,
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,
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,
508 8034,8050,7936,7952,8033,8049,7937,7953,
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],
527 'a' => [7939,7955], # #3 bottom right
528 'a' => [7968..7971], 'A' => [7984..7987],
530 'A' => [8257,8273, 8259,8275, 8162,8178],
534 # tau cross (v1.1 by Rose.Of.Dream/BW4eVeR)
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
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,
558 22231..22235, 22246..22253, 22260..22269,
559 22273..22285, 22289..22301, 22306..22312, 22324..22328,
561 '4' => [22246..22253, 22273..22285, 22306..22312],
563 22084..22086, 22096..22103, 22112..22121, 22128..22139,
564 22144..22156, 22165..22171, 22181..22199,
566 '4' => [22084..22086, 22112..22121, 22144..22156, 22181..22199],
567 'r' => [22342,22343],
569 # Nostalgia (WGT13, v1.3 by Rose.of.Dream)
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
581 while (my ($char, $matches) = splice @maptile, 0, 2) {
582 $tilechar{$_} = $char for @$matches;
584 while (my ($char, $matches) = splice @{$eratile{4}}, 0, 2) {
585 $tilechar{$_} = $char for @$matches;
588 my @mapunit = ( # character => width, height, ids
589 '$' => [2,1, 176..178], # minerals
590 '*' => [2,1, 188], # gas
591 '@' => [2,2, 214], # start pos
595 while (my ($char, $matches) = splice @mapunit, 0, 2) {
596 my @charinfo = ($char, splice @$matches, 0, 2);
597 $unitchar{$_} = \@charinfo for @$matches;
602 my $map = $self->tiles or return;
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;
612 $_ = defined $tilechar{$_} ? $tilechar{$_} : '?' for @$map;
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;
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;
648 my ($chr, $width, $height) = defined $unitchar{$_->{id}} ?
649 @{ $unitchar{delete $_->{id}} } : ('#', 1, 1);
651 $_->{width} = $width;
661 FF0000 0000FF 209070 88409C E87824 5C2C14 FFFFFF DCDC3C
662 0F930F FCFC8F EFCEBD 547CDC
664 12 => "pale green", "gray", "pale yellow", "cyan",
665 17 => "black", "neon blue",
666 21 => "lavender", "black",
671 for (unpack "C*", $self->{COLR}) {
672 push @players, $colormap[$_] || "? (#$_)";
679 return unpack "v", $self->{ERA};
684 my $map = Data::StarCraft::Map->new->open(\*STDIN);
686 if ($SHOWMAP ne "ppm") {
687 printf("%s size %dx%d, %d player\n",
689 $map->info->{x}, $map->info->{y},
690 scalar grep {$_->{id} == 214} $map->units,
695 if ($SHOWMAP eq "head") {
697 my @str = split /\0/, substr $map->{STR}, 2051;
699 s/([\001-\007])/sprintf '
\e[0;%dm', 30+ord($1)/eg
701 ) : s/[\001-\017]//g, print "* $_\n" for @str;
704 printf "%-4s %d\n", $_, defined $map->{$_} ? length $map->{$_} : 0
707 printf "%s: %s\n", $_, join ",", unpack "C*", $map->{$_}
708 for sort grep { defined $map->{$_} and length $map->{$_} < 32 }
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] || "?";
722 '~' => '0 0 3', # water
723 'W' => '3 3 7', # coast/water object
724 'D' => '8 7 5', # D shore
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
733 'R' => '3 9 3', # raised jungle
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
740 'R' => '2 5 2', # raised jungle
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
755 '7' => '3 3 1', # D>H
764 '$' => '0 13 15', # mineral patch
765 '*' => '4 15 8', # gas geyser
766 '@' => '14 4 3', # start location
767 '#' => '15 12 0', # unknown unit
769 ' ' => '15 15 15', # defined unencountered
770 '?' => '0 0 0', # undefined
771 '!' => '15 0 15', # marked
772 '-' => '0 15 0', # debug
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?)
792 'O' => '11 10 6', # object on lower ground
793 'l' => '4 3 2', # asphalt↔dirt
795 'h' => '8 7 5', # high dirt
796 'x' => '9 8 5', # high grass ↔ high dirt?
799 'r' => '9 9 9', # structure
817 # high sandy sunken pit
881 # 'b' => '5 4 3', # basilica
882 # 'p' => '3 3 2', # ?
883 # 'r' => '3 9 3', # sunken stuff
886 my %addmapcol = !$SHOWWARN ? () : (
891 #%mapcol = (%mapcol, %{$eramapcol[$map->era]}, %addmapcol);
892 %mapcol = (%mapcol, %{$eramapcol[4]}, %addmapcol);
904 if (defined $mapsep{$SHOWMAP}) {
905 my $MAPCHARSEP = $mapsep{$SHOWMAP};
907 my $tiles = $SHOWMAP eq "num" ? [ map sprintf('%5d', $_), @{$map->tiles} ]
908 : $map->tiles_parsed;
910 if ($SHOWMAP eq "ppm") {
911 printf "P3\n%d %d\n15\n", $map->info->{x}, $map->info->{y};
914 defined $mapcol{$_} or $uncolored{$_}++ for @$tiles, '?';
915 warn "no color for tile '$_'\n" for keys %uncolored;
917 $_ = $mapcol{$_} || $mapcol{'?'} || '0 0 0' for @$tiles;
920 my ($unit, $match, $color) = @_;
921 my $pos = $unit->{x} + $unit->{y} * $map->width;
924 $pos+$map->width, $pos-$map->width,
925 $pos+1+$map->width, $pos+1-$map->width,
927 $tiles->[$delta] =~ s/($match)/$1 + $color/e
928 unless $tiles->[$delta] eq $mapcol{$unit->{chr}};
931 for ($map->units_parsed) {
932 if ($_->{chr} eq '$') {
933 surround($_, qr/\d+$/, 7);
934 } elsif ($_->{chr} eq '*') {
935 surround($_, qr/\d+(?= \d+$)/, 3);
941 while (my @line = splice @$tiles, 0, $map->width) {
942 printf "%s\n", join $MAPCHARSEP, @line;