Overview
Comment: | Initial commit with files included. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
b152314d288df3e91af70a58b36ae776 |
User & Date: | user on 2018-03-05 09:32:23 |
Other Links: | manifest | tags |
Context
2018-03-08
| ||
05:50 | A change in file format, and notes about a hybrid approach check-in: a4f844ac56 user: user tags: trunk | |
2018-03-05
| ||
09:32 | Initial commit with files included. check-in: b152314d28 user: user tags: trunk | |
09:03 | initial empty check-in check-in: 1f3a1f5ef3 user: user tags: trunk | |
Changes
Added LICENSE version [71ed6913b8].
> > > > | 1 2 3 4 | Free Hero Mesh is released to public domain. Puzzle sets may have their own copyright which might or might not differ from that of the Free Hero Mesh program itself. |
Added colorpalette version [96e46c5fe1].
> > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | C020FF 000000 222222 333333 444444 555555 666666 777777 888888 999999 AAAAAA BBBBBB CCCCCC DDDDDD EEEEEE FFFFFF 281400 412300 5F3200 842100 A05000 C35F14 E1731E FF8232 FF9141 FFA050 FFAF5F FFBE73 FFD282 FFE191 FFF0A0 321E1E 412220 5F2830 823040 A03A4C BE4658 E15464 FF6670 FF7F7B FF8E7F FF9F7F FFAF7F FFBF7F FFCF7F FFDF7F 280D0D 401515 602020 802A2A A03535 C04040 E04A4A FF5555 FF6764 FF6F64 FF7584 FF849D FF94B7 FF9FD1 FFAEEA 901400 A02000 B03000 C04000 D05000 E06000 F07000 FF8000 FF9000 FFA000 FFB000 FFC000 FFD000 FFE000 FFF000 280000 400000 600000 800000 A00000 C00000 E00000 FF0000 FF2828 FF4040 FF6060 FF8080 FFA0A0 FFC0C0 FFE0E0 280028 400040 600060 800080 A000A0 C000C0 E000E0 FF00FF FF28FF FF40FF FF60FF FF80FF FFA0FF FFC0FF FFE0FF 281428 402040 603060 804080 A050A0 C060C0 E070E0 FF7CFF FF8CFF FF9CFF FFACFF FFBCFF FFCCFF FFDCFF FFECFF 280050 350566 420A7C 4F0F92 5C14A8 6919BE 761ED4 8323EA 9028FF A040FF B060FF C080FF D0A0FF E0C0FF F0E0FF 000028 000040 000060 000080 0000A0 0000C0 0000E0 0000FF 0A28FF 284AFF 466AFF 678AFF 87AAFF A7CAFF C7EBFF 0F1E1E 142323 193232 1E4141 285050 325F5F 377373 418282 469191 50A0A0 5AAFAF 5FC3C3 69D2D2 73E1E1 78F0F0 002828 004040 006060 008080 00A0A0 00C0C0 00E0E0 00FFFF 28FFFF 40FFFF 60FFFF 80FFFF A0FFFF C0FFFF E0FFFF 002800 004000 006000 008000 00A000 00C000 00E000 00FF00 28FF28 40FF40 60FF60 80FF80 A0FFA0 C0FFC0 E0FFE0 002110 234123 325F32 418241 50A050 5FC35F 73E173 85FF7A 91FF6E A0FF5F B4FF50 C3FF41 D2FF32 E1FF23 F0FF0F 282800 404000 606000 808000 A0A000 C0C000 E0E000 FFFF00 FFFF28 FFFF40 FFFF60 FFFF80 FFFFA0 FFFFC0 FFFFE0 442100 00FF55 0055FF FF5500 55FF00 FF0055 5500FF CA8B25 F078F0 F0F078 FF7F00 DD6D01 7AFF00 111111 000000 0000AA 00AA00 00AAAA AA0000 AA00AA AAAA00 AAAAAA 555555 5555FF 55FF55 55FFFF FF5555 FF55FF FFFF55 FFFFFF |
Added fileform1.txt version [a949aa6944].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 | ** Hero Mesh File Format ** This describes the file format of the Windows version of Hero Mesh. (Free Hero Mesh uses a different file format described in a different file.) All numbers are small-endian and unsigned. WORD is 16-bits, and DWORD is 32-bits, and BYTE is 8-bits. === Header === At the beginning of the file is the following: Offset Type Description 0 WORD File version 2 CHAR(4) ASCII characters "MESH" 6 DWORD Puzzle set number 10 WORD Number of picture sizes 12 WORD(8) Picture sizes 28 WORD Number of words in picture allocation table File version is 15 for Hero Mesh version 1.1c, and is 16 for Hero Mesh version 2.0. Other versions (if any) are unknown. The rest of this document is applicable to file version 16 (differences, if any, are unknown; file version 15 does not seem to have any differences as far as I can tell). Puzzle set number is a number that can be read by the class codes but otherwise does nothing. It is used by the Hero Hearts puzzle sets to determine which puzzle set to link to after completing the last level. The picture sizes are all square; the numbers given are the width (which is equal to the height) of that picture size. For example, if it says 24 then the pictures are 24x24. After this comes the picture allocation table, which specifies which pictures are allocated. The first word of the allocation table is for the first sixteen pictures; the low bit is for the first picture, and the high bit is for the sixteenth picture. === Pictures === Picture data comes next. The encoding is like this C code: // nsizes = number of picture sizes (1 to 8; normally 3) // nalloc = number of words in picture allocation table // sizes[s] = width or height of picture size s (where s is 0 to 7) for(s=0;s<nsizes;s++) { for(i=0;i<nalloc;i++) { for(y=0;y<sizes[s];y++) { for(j=0;j<16;j++) { @< Read (sizes[s]) bytes from file into scanline y of size s of picture 16*i+j (one byte per pixel; zero = transparent) @> } } } } // Unallocated pictures are still read, even though they aren't used. (This may also be considered as one large picture per size; where the pictures are tile sets with sixteen tiles across.) Next comes the picture availability table, which controls which pictures are available for selection in the level editor. There are always 512 bytes, one byte per picture. The byte value is 1 if it is available or 0 if it is not available. === User Message Table === Next is the user message table. It starts with a WORD which is the number of user messages. User message numbers start with 20; messages 0 to 19 are the built-in messages. For each user message there is a BYTE giving the length of the message name, followed by the message name. (There seems to be always one extra message name at the end which is blank and is unused. The reason for this is currently unknown.) If the name is empty then that user message does not exist (it may have been deleted). The standard messages are as follows: 0 = INIT 1 = CREATE 2 = DESTROY 3 = BEGIN_TURN 4 = ARRIVED 5 = DEPARTED 6 = LASTIMAGE 7 = MOVED 8 = JUMPED 9 = KEY 10 = MOVING 11 = SUNK 12 = FLOATED 13 = PLAYERMOVING 14 = HIT 15 = HITBY 16 = DESTROYED 17 = CREATED 18 = POSTINIT 19 = END_TURN === Classes === After the user message table comes the classes. This starts with a WORD specifying the number of classes. Classes then follow. Each class consists of the following: * Name: A BYTE giving the length of the name, followed by the name. * ID number: A WORD giving the zero-based class ID number (class ID numbers are sometimes one-based, but here they are zero-based). * Description: One or three bytes for length, followed by the plain text (using CRLF for line endings). If length is less than 255 then it is one byte. Otherwise, the first byte is 255 and then a WORD follows which gives the length of the description. The description isn't null terminated. Any escapes in the description are interpreted at runtime; they are not stored with the control codes mentioned for special texts. * Attributes: See attribute table below. * Number of pictures (WORD) * List of pictures. Each is a WORD, and is a zero-based number of the picture from the picture area; after this, all further picture numbers in the file are zero-based indexing into this table. * Number of user variables (WORD) * User variable names; each is eight bytes long and is padded with nulls. (Variable names are actually limited to seven characters.) * Number of subroutine labels (WORD) * Label names; each is ten bytes long, and is a eight-byte null terminated string, with junk in the remaining bytes; the final two bytes are a word address into the sobroutine or message section. * Subroutine program codes * Number of message labels (WORD) (these aren't the message names; these are labels outside of the subroutine section). * Message label names; stored like the subroutine label names. * Message program codes Attribute Table 0 BYTE ??? 1 BYTE Flag 2 WORD Misc4 4 WORD Misc5 6 WORD Misc6 8 WORD Misc7 10 WORD Shovable 12 BYTE(5) Arrivals 17 BYTE(5) Departures 22 WORD Density 24 WORD Volume 26 WORD Strength 28 WORD Weight 30 WORD HardE 32 WORD HardN 34 WORD HardW 36 WORD HardS 38 WORD SharpE 40 WORD SharpN 42 WORD SharpW 44 WORD SharpS 46 WORD Height 48 WORD Climb 50 WORD Temperature 52 WORD Shape 54 WORD ??? 56 WORD ??? 58 WORD ??? 60 WORD ??? The flag byte has bit0 set for "receives keys" and has bit7 set for "is the player". Other flags (if any) are unknown, they appear to be unset. The arrivals and departures are stored each as five bytes, each byte for one row, with the first byte corresponding to the top row. In each byte, the rightmost column is the low bit; only the low 5-bits are used. (This is not the same as the representation used in class codes!) The last four attributes seem to have something to do with the program length, but it is unknown. However, it is not necessary to read these in order to figure out the program length (see below for details). === Program === Each class has program codes; this section describes how the program codes are encoded in the file. The first WORD of the subroutine section is the number of WORDs that make up the the subroutine section, including the count itself. After that one WORD header comes the instructions. Each message block in the message section then consists of the header and then the instructions. The header of each message block consists of two WORDs, the first being the message number, and the second being the length (in WORDs) of this message block, including the header. The program is terminated by a header with both WORDs zero. Program instructions are executed using a stack-based virtual machine. Each instruction is normally one WORD; see below section for the opcodes. === Program Opcodes === The first byte is opcode byte (the major code). The second byte is the minor code, the meaning depending on the opcode. In the descriptions below, if it says / and a number, it is how many taken from stack. If there is * then it pushes to stack, ! means end block, - means no effect on data stack. [1*] Local variables: 0=Class, 1=Temperature, 2=Shape, 4=Xloc, 5=Yloc, 6=LastDir, 7=CurImage, 8=Inertia, 9=Misc1, 10=Misc2, 11=Misc3, 12=Misc4, 13=Misc5, 14=Misc6, 15=Misc7, 16=Arrived, 17=Departed, 18=Arrivals, 19=Departures, 32=Busy, 33=Invisible, 34=UserSignal, 35=UserState, 36=KeyCleared, 37=IsPlayer, 38=Destroyed, 39=Stealthy, 40=VisualOnly, 48=Msg, 49=MsgFrom, 50=MsgArg1, 51=MsgArg2, 64=Density, 65=Volume, 66=Strength, 67=Weight, 68=Distance, 69=Height, 70=Climb, 72=HardE, 73=HardN, 74=HardW, 75=HardS, 76=SharpE, 77=SharpN, 78=SharpW, 79=SharpS, 80=ShapeE, 81=ShapeN, 82=ShapeW, 83=ShapeS, 84=Shovable [2*] Retrieve local variable from other object. Local variable numbers are the same as opcode 1. [3/1] Assignment to standard local variables of current object. [5*] User-defined local variable; the second byte is zero-based local variable number. [6/1] Assignment to user-defined variable; the second byte is the zero-based local variable number to write to. [7*] Short decimal constant; the second byte is the 8-bit value. [8*] Long decimal constant. The next two words are the small-endian 32-bit number that it represents. [9*] Short class constant; the second byte is a zero-based class number (the class number is one-based at runtime). [14*] Direction constant (0-7 for absolute, 8-15 for relative) [16/1*] Unary operator: 0=negative, 1=bitwise NOT, 2=logical NOT [17/2*] Binary operator: 0=multiply, 1=divide, 2=modulo [18/2*] Binary operator: 0=add, 1=subtract, 2=AND, 3=OR, 4=XOR [19/2*] Bit shift operator: 0=left, 1=right [20/2*] Comparison operator: 0=equal, 1=unequal, 2=less, 3=greater, 4=less or equal, 5=greater or equal [21/2*] Logical operator: 0=AND, 1=OR, 2=XOR (not short-circuiting) [32] ObjDir [34] ObjAbove [36] ObjBelow [38] 0=ObjTopAt, 1=ObjBottomAt, 2=VolumeAt, 3=HeightAt, 4=Delta [39*] Self [40] ObjClassAt [48*] Key [49*] Animation constant: 0=STOP, 1=ONCE, 2=LOOP, 8=OSC [50*] Keyboard constant: See section about key codes. [51*] Short hexadecimal constant; second byte is the 8-bit value. [52*] Long hexadecimal constant. Next two words are the small-endian 32-bit number that it represents. [53*] Global variable: 0=Level, 1=LevelCount, 2=AltImage, 3=ExplainDeath, 4=GlobalBool, 5=PuzzleSetNumber, 6=MoveNumber [54] XDir [56] YDir [58] 0=NewX, 1=NewY [59*] Bit constant 0-31; the second byte is the number 0-31, and at runtime it is replaced by the relevant 32-bit number. [60*] Sound constant (see section about user sounds) [61] 0=ClassCount/1* (I don't know what this does), 1=GetArray [68/1*] Move(Self, ...); minor code is 255 [69/2*] Move; minor code is 255 [80] SendMessage [82] Broadcast [84-] Move(Self, dir). The second byte is the direction to move. Unlike the normal Move() function, this one adds Strength to Inertia instead of setting Inertia equal to Strength (this seems to be a bug). [85/2] Move; minor code is 255 [88] Create [96] Comment. Has one WORD giving length of the comment text (including the null terminator), and then the plain text of the comment (with CRLF line endings), null terminated. [97] Popup setting. Second byte is 0 for PopupColor or 1 for PopupLoc. [98] Destroy [100] CallSub [101] Goto [102] Return. Second byte is 0 for implicit end of SUBS block, 1 for return from a subroutine, 2 for the end of a message block. [103] Return short constant. Second byte is return value. [104/1] Return [105/1] If. Second byte is zero for block-if or one for inline-if. The next word is the number of words to skip (including the count itself) if the condition is false. [106] Else [107/3] ImageSeq (seems to do nothing?) [108/3] ImageLoop (seems to do nothing?) [109] PopUp [110] JumpTo [112] Sound [114] Array operations. Second byte: 0 = definition of an array, 1 = SetArray, 2 = InitArray. [126] Animate [127] Link [128] GotoLevel [129-] 0=WinLevel, 1=LocateMe, 2=IgnoreKey, 3=PopupMisc, 4=UpdateScreen (I don't know what UpdateScreen means?) [130] FlushClass [131] FlushObj [132] SetInventory [133] DelInventory [134] ForEachObjAt [240] Trace === Levels === After all classes are the levels. Before the levels comes: * Number of levels (WORD) * Two null bytes (meaing unknown) Each level consists of: * Zero-based level number (WORD) * Level description length, including the null terminator (WORD) * Level description; a null-terminated special text * Border colours, outer to inner (BYTE(32)) * Background colour (BYTE) * Null byte (maybe the high byte of the background colour) * Number of objects (WORD) * Objects, in ordinary progressive television order; within each cell they go bottom to top. See information about object records below. * Number of level strings (WORD) * Level strings; each one WORD length (the length includes the null terminator), followed by the null-terminated special text. An object record is sixteen bytes long, and consists of: 0 WORD Class (zero-based) 2 WORD CurImage (zero-based) 4 BYTE LastDir (zero-based; 0=east, 1=northeast, etc) 5 BYTE Data types for Misc vars 6 WORD X coordinate (one-based) 8 WORD Y coordinate (one-based) 10 WORD Misc1 12 WORD Misc2 14 WORD Misc3 The data types are as follows: 0 = Number 1 = Class (one-based) 2 = Message 3 = String Data type for Misc1 is in bit1 and bit0, data type for Misc2 is in bit3 and bit2, data type for Misc3 is in bit5 and bit4. Bit7 and bit6 are always zero. The data type is used only in the editor and is irrelevant at run time. === Special Text === Level data may contain special text. This is text using the following control codes (escapes have already been interpreted): 1 = Black (\0) 2 = Blue (\1) 3 = Green (\2) 4 = Cyan (\3) 5 = Red (\4) 6 = Purple (\5) 7 = Yellow (\6) 8 = White (\7) 10 = Line break (\n) 11 = Left (\l) 12 = Center (\c) 14 = Picture (\i); followed by two WORDs: zero-based class and image 15 = Horizontal line (\b) 16 = Quiz button (\q); followed by one byte key code === Solutions === After the levels come the solutions. There is first one WORD which is the number of solutions, and then the solutions. Each solution consists of: * Zero-based level number (WORD) * Number of keys in solution (WORD) * User name (BYTE(9)); the user name is null terminated, although there may be junk after the null terminator. * Key codes; one byte each. === User Sounds === Finally, the user sounds come last. One WORD gives the number of user sounds. And then each sound consists of: * Sound ID number (zero-based) (WORD) * Name length (BYTE) * Name (not terminated; length is given instead) * Data length (WORD) * Data (a RIFF WAVE file) The built-in sounds are as follows: SPLASH POUR DOOR GLASS BANG UNHH UH_OH FROG THWIT KLINKK POWER KLECK CLICK SMALL_POP DINK TICK CHYEW CHEEP ANHH BRRRT BRRREEET BWEEP DRLRLRINK FFFFTT WAHOO YEEHAW OLDPHONE RATTLE BEEDEEP THMP_thmp BEDOINGNG HEARTBEAT LOCK TAHTASHH BOOOM VACUUM RATCHET2 DYUPE UNCORK BOUNCE JAYAYAYNG DEEP_POP RATCHET1 GLISSANT BUZZER FAROUT KEWEL WHACK STEAM HAWK === Key codes === 8 BACK 9 TAB 12 CENTER (number pad 5 when numlock is off) 13 ENTER 16 SHIFT 17 CTRL 19 BREAK 20 CAPSLOCK 32 SPACE 33 PGUP 34 PGDN 35 END 36 HOME 37 LEFT 38 UP 39 RIGHT 40 DOWN 48 0 (the top row zero) 57 9 (the top row nine; 1-8 are in between 0 and 9) 65 A 90 Z (letters B-Y are in between A and Z) 96 NUMPAD0 105 NUMPAD9 (number pad 1-8 are in between) 106 MULTIPLY (the number pad "*" key) 110 DECIMAL (the number pad "." key) 111 DIVIDE (the number pad "/" key) 120 F9 121 F10 122 F11 123 F12 144 NUMLOCK 145 SCRLOCK 186 SEMICOLON 187 EQUALS 188 COMMA 189 MINUS 190 PERIOD 191 SLASH 192 TILDE 219 OBRACKET 220 BACKSLASH 221 CBRACKET 222 QUOTE The number pad and main enter keys have the same key code. When num lock is off, the number pad keys have the same codes as the other arrow keys. The NUMPAD codes are only when numlock is on. |
Added mbtofhm.c version [2264eccb2d].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 | #if 0 gcc -s -O2 -o ./mbtofhm -Wno-unused-result mbtofhm.c exit #endif // This program is part of Free Hero Mesh and is public domain. #include <stdio.h> #include <stdlib.h> #include <string.h> #include "names.h" #define fatal(...) do{ fprintf(stderr,__VA_ARGS__); exit(1); }while(0) // Pictures static unsigned char*pict; static unsigned short*picalloc; static int npic; static unsigned short sizes[8]; static unsigned char*inpic; static unsigned char*outpic; static unsigned char*inpicstr; static unsigned char*inpicabovestr; static int outpiclen; static char picavail[512]; // Classes typedef struct { char*name; char*desc; unsigned char attr[62]; short npic; unsigned short pic[128]; short nvars; unsigned char*vars; short nsubslbl; unsigned char*subslbl; unsigned char*subscode; short nmsgslbl; unsigned char*msgslbl; unsigned short nmsgs; unsigned char**msgscode; } ClassInfo; static int nusermsg; static char**usermsg; static ClassInfo*class[512]; // Levels static int nlevels; static unsigned short*levelid; // Sounds static int nsounds; static char**sounds; static unsigned short*soundid; // Common static char*basename; static char*nam; static unsigned long haroffs; static void*alloc(unsigned int s) { void*o=malloc(s); if(s && !o) fatal("Allocation failed\n"); return o; } static void*my_realloc(void*p,unsigned int s) { void*o=realloc(p,s); if(s && !o) fatal("Reallocation failed\n"); return o; } #define Allocate(x,y) (x=alloc((y)*sizeof(*(x)))) #define Reallocate(x,y) (x=my_realloc((x),(y)*sizeof(*(x)))) static void hamarc_begin(FILE*fp) { fwrite(nam,1,strlen(nam)+1,fp); fwrite("\0\0\0",4,1,fp); haroffs=ftell(fp); } static void hamarc_end(FILE*fp) { unsigned long end=ftell(fp); fseek(fp,haroffs-4,SEEK_SET); fputc((end-haroffs)>>16,fp); fputc((end-haroffs)>>24,fp); fputc((end-haroffs)>>0,fp); fputc((end-haroffs)>>8,fp); fseek(fp,end,SEEK_SET); } static inline void read_header(void) { unsigned char buf[30]; int i,s; fread(buf,1,30,stdin); if(memcmp("MESH",buf+2,4)) fatal("Unrecognized file format\n"); for(i=0;i<buf[10];i++) sizes[i]=buf[i+i+12]|(buf[i+i+13]<<8); npic=buf[28]|(buf[29]<<8); Allocate(picalloc,npic); for(i=0;i<npic;i++) { fread(buf,1,2,stdin); picalloc[i]=buf[0]|(buf[1]<<8); } for(i=s=0;i<8;i++) s+=sizes[i]*sizes[i]; Allocate(pict,i=s*npic*16); fread(pict,1,i,stdin); for(i=s=0;i<8;i++) if(s<sizes[i]) s=sizes[i]; s*=s; Allocate(inpic,s); Allocate(outpic,s+256); Allocate(inpicstr,s+4); Allocate(inpicabovestr,s+4); } static void out_run(int ch,int am,int st,int le) { int n=am%85?:85; outpic[outpiclen++]=ch+n-1; if(le) memcpy(outpic+outpiclen,inpicstr+st,le<n?le:n); if(le) outpiclen+=le<n?le:n; if(ch) st+=n,le-=n; while(am-=n) { n=am>7225?7225:am; outpic[outpiclen++]=ch+n/85-1; if(le>0) memcpy(outpic+outpiclen,inpicstr+st,le<n?le:n); if(le>0) outpiclen+=le<n?le:n; if(ch) st+=n,le-=n; } } static int one_picture(int ps,int me) { int ms=ps*ps; int i=0; int w,x,y,z; int ca,homo,hetero; for(y=0;y<ps;y++) for(x=0;x<ps;x++) { if(me&1) x=ps-x-1; if(me&2) y=ps-y-1; inpicstr[i++]=inpic[me&4?x*ps+y:y*ps+x]; if(me&1) x=ps-x-1; if(me&2) y=ps-y-1; } for(i=0;i<ms;i++) inpicabovestr[i]=i<ps?0:inpicstr[i-ps]; inpicabovestr[i]=255; inpicstr[i++]=254; inpicabovestr[i]=253; inpicstr[i++]=252; outpiclen=i=0; while(i<ms) { ca=0; while(i+ca<ms && inpicstr[i+ca]==inpicabovestr[i+ca]) ca++; homo=1; while(i+homo<ms && inpicstr[i+homo]==inpicstr[i]) homo++; hetero=1; while(i+hetero<ms) { if(inpicstr[i+hetero]==inpicabovestr[i+hetero] && inpicstr[i+hetero+1]==inpicabovestr[i+hetero+1]) break; if(inpicstr[i+hetero]==inpicstr[i+hetero+1] && i+hetero==ms-1) break; if(inpicstr[i+hetero]==inpicstr[i+hetero+1] && inpicstr[i+hetero]==inpicstr[i+hetero+2]) break; hetero++; } if(ca>=homo && (ca>=hetero || homo>1)) { // Output a copy-above run out_run(170,ca,0,0); i+=ca; } else if(homo>1) { // Output a homogeneous run out_run(0,homo-1,i,1); i+=homo; } else { // Output a heterogeneous run if(hetero>85) hetero=85; out_run(85,hetero,i,hetero); i+=hetero; } if(outpiclen>=ms) return ms+1; } return outpiclen; } static inline void do_pictures(void) { FILE*fp; int i,j,k,s,t,x,y,z; char meth[8]; int siz[8]; sprintf(nam,"%s.xclass",basename); fp=fopen(nam,"w"); if(!fp) fatal("Cannot open file '%s' for writing\n",nam); for(i=0;i<npic;i++) { for(j=0;j<16;j++) { if(picalloc[i]&(1<<j)) { fwrite(nam,sprintf(nam,"%d.IMG",i*16+j)+1,1,fp); for(z=k=t=0;z<8;z++) { x=sizes[z]; if(!x) break; for(y=0;y<x;y++) memcpy(inpic+y*x,pict+k+(i*x+y)*x*16+j*x,x); meth[z]=15; siz[z]=x*x; for(y=0;y<8;y++) { s=one_picture(x,y); if(s<siz[z]) siz[z]=s,meth[z]=y; } t+=siz[z]; k+=x*x*16*npic; } if(z!=8) meth[z]=15; t+=z+1+(z>>1); fputc(t>>16,fp); fputc(t>>24,fp); fputc(t,fp); fputc(t>>8,fp); fputc((*meth<<4)|z,fp); for(z=0;z<8;z++) { if(!sizes[z]) break; fputc(sizes[z],fp); } for(z=1;z<8;z+=2) { if(!sizes[z]) break; fputc(meth[z]|(z==7?0xF0:meth[z+1]<<4),fp); } for(z=k=0;z<8;z++) { x=sizes[z]; if(!x) break; for(y=0;y<x;y++) memcpy(inpic+y*x,pict+k+(i*x+y)*x*16+j*x,x); if(meth[z]==15) fwrite(inpic,x,x,fp); else fwrite(outpic,1,one_picture(x,meth[z]),fp); k+=x*x*16*npic; } } } } fclose(fp); } static void unprefix_messages(const char*pre,int n) { int i,j; for(i=0;i<nusermsg;i++) { if(usermsg[i] && !strncmp(pre,usermsg[i],n)) { for(j=0;j<nusermsg;j++) if(j!=i && usermsg[j] && !strcmp(usermsg[i],usermsg[j])) goto skip; memmove(usermsg[i],usermsg[i]+n,strlen(usermsg[i])+1-n); } skip: ; } } static inline void do_user_messages(void) { int i,j; i=fgetc(stdin); nusermsg=i|(fgetc(stdin)<<8); Allocate(usermsg,nusermsg); for(i=0;i<nusermsg;i++) { j=fgetc(stdin); if(j) { Allocate(usermsg[i],j+1); fread(usermsg[i],1,j,stdin); usermsg[i][j]=0; } else { usermsg[i]=0; } } unprefix_messages("MSG_",4); unprefix_messages("USR_",4); unprefix_messages("WTP_",4); unprefix_messages("MSG_",4); } static void read_one_class(void) { unsigned char buf[4]; int i,j,k,id; char*name; i=fgetc(stdin); Allocate(name,i+1); fread(name,1,i,stdin); name[i]=0; id=fgetc(stdin); id|=fgetc(stdin)<<8; if(id>=512) fatal("Class number %d out of range\n",id); if(class[id]) fatal("Duplicate class number %d\n",id); Allocate(class[id],1); class[id]->name=name; i=fgetc(stdin); if(i==255) { i=fgetc(stdin); i|=fgetc(stdin)<<8; } fread(Allocate(class[id]->desc,i+1),1,i,stdin); class[id]->desc[i]=0; fread(class[id]->attr,1,62,stdin); j=fgetc(stdin); j|=fgetc(stdin)<<8; class[id]->npic=j; for(i=0;i<j;i++) { k=fgetc(stdin); k|=fgetc(stdin)<<8; if(i<128) class[id]->pic[i]=k; } if(j>128) class[id]->npic=128; j=fgetc(stdin); j|=fgetc(stdin)<<8; class[id]->nvars=j; fread(Allocate(class[id]->vars,j<<3),j,8,stdin); j=fgetc(stdin); j|=fgetc(stdin)<<8; class[id]->nsubslbl=j; fread(Allocate(class[id]->subslbl,10*j),j,10,stdin); fread(buf,1,2,stdin); k=buf[0]|(buf[1]<<8); Allocate(class[id]->subscode,k<<1); class[id]->subscode[0]=i; class[id]->subscode[1]=j; fread(class[id]->subscode+2,2,k-1,stdin); j=fgetc(stdin); j|=fgetc(stdin)<<8; class[id]->nmsgslbl=j; fread(Allocate(class[id]->msgslbl,10*j),j,10,stdin); class[id]->nmsgs=0; class[id]->msgscode=0; for(;;) { fread(buf,1,4,stdin); k=buf[2]|(buf[3]<<8); if(!k) break; i=class[id]->nmsgs++; Allocate(Reallocate(class[id]->msgscode,class[id]->nmsgs)[i],k<<1); memcpy(class[id]->msgscode[i],buf,4); fread(class[id]->msgscode[i]+4,k-2,2,stdin); } } static inline void do_classes(void) { int n; n=fgetc(stdin); n|=fgetc(stdin)<<8; while(n--) read_one_class(); } static inline void out_classes(void) { FILE*fp; ClassInfo*c; int i,j,n; sprintf(nam,"%s.class",basename); fp=fopen(nam,"w"); if(!fp) fatal("Cannot open file '%s' for writing\n",nam); fprintf(fp,"; Note: This file was automatically converted.\n; Remove this notice if you have corrected it.\n"); for(n=0;n<512;n++) if(c=class[n]) { fprintf(fp,"\n($%s\n Compatible",c->name); if(c->attr[1]&1) fprintf(fp," Input"); if(c->attr[1]&128) fprintf(fp," Player"); if(!strcmp(c->name,"Quiz")) fprintf(fp," Quiz"); fprintf(fp,"\n (Image"); for(j=i=0;i<c->npic;i++) { fprintf(fp," \"%d\"",c->pic[i]); if(picavail[c->pic[i]]) j++; } fprintf(fp,")\n"); if(!j) { fprintf(fp," (DefaultImage ())\n"); } else if(j!=c->npic) { fprintf(fp," (DefaultImage"); for(i=0;i<c->npic;i++) if(picavail[c->pic[i]]) fprintf(fp," %d",i); fprintf(fp,")\n"); } //TODO: Description if(c->attr[2] || c->attr[3]) fprintf(fp," (Misc4 0x%04X)\n",c->attr[2]|(c->attr[3]<<8)); if(c->attr[4] || c->attr[5]) fprintf(fp," (Misc5 0x%04X)\n",c->attr[4]|(c->attr[5]<<8)); if(c->attr[6] || c->attr[7]) fprintf(fp," (Misc6 0x%04X)\n",c->attr[6]|(c->attr[7]<<8)); if(c->attr[8] || c->attr[9]) fprintf(fp," (Misc7 0x%04X)\n",c->attr[8]|(c->attr[9]<<8)); if(c->attr[50] || c->attr[51]) fprintf(fp," (Temperature %d)\n",c->attr[50]|(c->attr[51]<<8)); if(c->attr[10]) { if(c->attr[10]==0x55) { fprintf(fp," Shovable\n"); } else { fprintf(fp," (Shovable"); if(c->attr[10]&0xAA) { // I don't know why, but sometimes this happens. fprintf(fp," 0x%02X",c->attr[10]); } else { if(c->attr[10]&0x01) fprintf(fp," E"); if(c->attr[10]&0x04) fprintf(fp," N"); if(c->attr[10]&0x10) fprintf(fp," W"); if(c->attr[10]&0x40) fprintf(fp," S"); } fprintf(fp,")\n"); } } if(!c->attr[12] && !c->attr[13] && !c->attr[15] && !c->attr[16] && !(c->attr[14]&~4)) { if(c->attr[14]) fprintf(fp," (Arrivals InPlace)\n"); } else { fprintf(fp," (Arrivals\n"); for(i=0;i<5;i++) { fprintf(fp," "); for(j=0;j<5;j++) fprintf(fp," %c",(c->attr[i+12]<<j)&16?'1':'0'); fputc('\n',fp); } fprintf(fp," )\n"); } if(!c->attr[17] && !c->attr[18] && !c->attr[20] && !c->attr[21] && !(c->attr[19]&~4)) { if(c->attr[19]) fprintf(fp," (Departures InPlace)\n"); } else { fprintf(fp," (Departures\n"); for(i=0;i<5;i++) { fprintf(fp," "); for(j=0;j<5;j++) fprintf(fp," %c",(c->attr[i+17]<<j)&16?'1':'0'); fputc('\n',fp); } fprintf(fp," )\n"); } if(c->attr[22] || c->attr[23]) fprintf(fp," (Density %d)\n",c->attr[22]|(c->attr[23]<<8)); if(c->attr[24] || c->attr[25]) fprintf(fp," (Volume %d)\n",c->attr[24]|(c->attr[25]<<8)); if(c->attr[26] || c->attr[27]) fprintf(fp," (Strength %d)\n",c->attr[26]|(c->attr[27]<<8)); if(c->attr[28] || c->attr[29]) fprintf(fp," (Weight %d)\n",c->attr[28]|(c->attr[29]<<8)); if(c->attr[46] || c->attr[47]) fprintf(fp," (Height %d)\n",c->attr[46]|(c->attr[47]<<8)); if(c->attr[48] || c->attr[49]) fprintf(fp," (Climb %d)\n",c->attr[48]|(c->attr[49]<<8)); //TODO: Shape if(memcmp(c->attr+30,"\0\0\0\0\0\0\0\0",8)) { if(memcmp(c->attr+30,c->attr+32,2) || memcmp(c->attr+30,c->attr+34,4)) { fprintf(fp," (Hard"); if(c->attr[30] || c->attr[31]) fprintf(fp," (E %d)",c->attr[30]|(c->attr[31]<<8)); if(c->attr[32] || c->attr[33]) fprintf(fp," (N %d)",c->attr[32]|(c->attr[33]<<8)); if(c->attr[34] || c->attr[35]) fprintf(fp," (W %d)",c->attr[34]|(c->attr[35]<<8)); if(c->attr[36] || c->attr[37]) fprintf(fp," (S %d)",c->attr[36]|(c->attr[37]<<8)); fprintf(fp,")\n"); } else { fprintf(fp," (Hard %d)\n",c->attr[30]|(c->attr[31]<<8)); } } if(memcmp(c->attr+38,"\0\0\0\0\0\0\0\0",8)) { if(memcmp(c->attr+38,c->attr+40,2) || memcmp(c->attr+38,c->attr+42,4)) { fprintf(fp," (Sharp"); if(c->attr[38] || c->attr[39]) fprintf(fp," (E %d)",c->attr[38]|(c->attr[39]<<8)); if(c->attr[40] || c->attr[41]) fprintf(fp," (N %d)",c->attr[40]|(c->attr[41]<<8)); if(c->attr[42] || c->attr[43]) fprintf(fp," (W %d)",c->attr[42]|(c->attr[43]<<8)); if(c->attr[44] || c->attr[45]) fprintf(fp," (S %d)",c->attr[44]|(c->attr[45]<<8)); fprintf(fp,")\n"); } else { fprintf(fp," (Sharp %d)\n",c->attr[38]|(c->attr[39]<<8)); } } //TODO: Class codes if(c->subscode[1] || c->subscode[0]>2) { fprintf(fp," (SUBS\n ; Not implemented yet!\n )\n"); } for(i=0;i<c->nmsgs;i++) { fprintf(fp," ("); j=c->msgscode[i][0]|(c->msgscode[i][1]<<8); if(j<20) fprintf(fp,"%s",standard_message_names[j]); else if(j-20<nusermsg && usermsg[j-20]) fprintf(fp,"#%s",usermsg[j-20]); else fprintf(fp,"#%d?",j); fprintf(fp,"\n ; Not implemented yet!\n )\n"); } fprintf(fp,")\n"); } fclose(fp); } static void one_level(FILE*fp,int ord) { unsigned char buf[16]; unsigned char mru[32]; int i,j,x,y,n,q; i=fgetc(stdin); i|=fgetc(stdin)<<8; levelid[ord]=i; sprintf(nam,"%d.LVL",i); hamarc_begin(fp); fputc(0,fp); fputc(0,fp); // Level version fputc(ord,fp); fputc(ord>>8,fp); // Level code fputc(29,fp); fputc(21,fp); // Width/height i=fgetc(stdin); i|=fgetc(stdin)<<8; // fputc(17,fp); // Select proportional font while(i--) { switch(j=fgetc(stdin)) { case 14: i-=4; j=fgetc(stdin); j|=fgetc(stdin)<<8; if(j>=512 || !class[j]) { fgetc(stdin); fgetc(stdin); break; } fputc(14,fp); fputs(class[j]->name,fp); j=fgetc(stdin); j|=fgetc(stdin)<<8; fprintf(fp,":%d\\",j); break; default: fputc(j,fp); } } fread(mru,1,32,stdin); // Skip border colours fread(buf,1,2,stdin); // Skip border colours mru[0x04]=mru[0x14]=255; n=fgetc(stdin); n|=fgetc(stdin)<<8; x=q=0; y=1; // Free Hero Mesh level format for objects: // * bit flags (or 0xFF for end): // bit7 = MRU (omit everything but position) // bit6 = Next position // bit5 = New X position // bit4 = New Y position // bit3 = Has MiscVars // bit2-bit0 = LastDir (should be RLE in case of MRU?) // * new X if applicable // * new Y if applicable // * class (one-based; add 0x8000 for image 0) (two bytes) // * image (one byte) // * data types (if has MiscVars): // bit7-bit6 = How many (0=has Misc2 and Misc3, not Misc1) // bit5-bit4 = Misc3 type // bit3-bit2 = Misc2 type // bit1-bit0 = Misc1 type // * misc data (variable size) while(n--) { fread(buf,1,16,stdin); ++*buf; if(!*buf) ++buf[1]; mru[0x06]=mru[0x16]=buf[6]; mru[0x08]=mru[0x18]=buf[8]; i=0; if(buf[6]==x+1) i|=0x40; else if(buf[6]!=x) i|=0x20; if(buf[8]!=y) i|=0x10; if(x==buf[6] && y==buf[8]) q+=16; else q=0; if(q<32 && !memcmp(mru+q,buf,16)) { i|=0x80; } else { i|=buf[4]&7; if(buf[5] || memcmp(buf+10,"\0\0\0\0\0\0",6)) i|=0x08; if(q<32) memcpy(mru+q,buf,16); } fputc(i,fp); x=buf[6]; y=buf[8]; if(i&0x20) fputc(x,fp); if(i&0x10) fputc(y,fp); if(i<0x80) { if(buf[2]) { fwrite(buf,1,3,fp); } else { fputc(*buf,fp); fputc(buf[1]|0x80,fp); } } if(i&0x08) { i=buf[5]&0x3F; if(buf[14] || buf[15]) i|=0xC0; else if(buf[12] || buf[13]) i|=0x80; else i|=0x40; if(i>=0xC0 && !buf[10] && !buf[11]) i&=0x3F; if(i&0xC0) { if((i&0x03)==0x02 && (buf[11] || buf[10]>20)) { j=buf[10]|(buf[11]<<8); fputc(j+236,fp); fputc((j+236)>>8,fp); } else { fwrite(buf+10,1,2,fp); } } if((i&0xC0)!=0x40) { if((i&0x0C)==0x08 && (buf[13] || buf[12]>20)) { j=buf[12]|(buf[13]<<8); fputc(j+236,fp); fputc((j+236)>>8,fp); } else { fwrite(buf+12,1,2,fp); } } if(!(0xC0&~i) || !(i&0xC0)) { if((i&0x03)==0x02 && (buf[15] || buf[14]>20)) { j=buf[14]|(buf[15]<<8); fputc(j+236,fp); fputc((j+236)>>8,fp); } else { fwrite(buf+14,1,2,fp); } } } } fputc(255,fp); // End of objects n=fgetc(stdin); n|=fgetc(stdin)<<8; while(n--) { i=fgetc(stdin); i|=fgetc(stdin)<<8; // fputc(17,fp); // Select proportional font while(i--) { switch(j=fgetc(stdin)) { case 14: i-=4; j=fgetc(stdin); j|=fgetc(stdin)<<8; if(j>=512 || !class[j]) { fgetc(stdin); fgetc(stdin); break; } fputc(14,fp); fputs(class[j]->name,fp); j=fgetc(stdin); j|=fgetc(stdin)<<8; fprintf(fp,":%d\\",j); break; default: fputc(j,fp); } } } hamarc_end(fp); } static inline void do_levels(void) { int i,n; FILE*fp; sprintf(nam,"%s.level",basename); n=fgetc(stdin); n|=fgetc(stdin)<<8; fgetc(stdin); fgetc(stdin); // Unknown meaning if(!n) return; nlevels=n; Allocate(levelid,nlevels); fp=fopen(nam,"w"); if(!fp) fatal("Cannot open file '%s' for writing\n",nam); strcpy(nam,"CLASS.DEF"); hamarc_begin(fp); for(i=0;i<512;i++) if(class[i]) { fputc(i+1,fp); fputc((i+1)>>8,fp); fwrite(class[i]->name,1,strlen(class[i]->name)+1,fp); } fputc(0,fp); fputc(0,fp); for(i=0;i<nusermsg;i++) if(usermsg[i]) { fputc(i,fp); fputc((i+256)>>8,fp); fwrite(usermsg[i],1,strlen(usermsg[i])+1,fp); } hamarc_end(fp); for(i=0;i<n;i++) one_level(fp,i); strcpy(nam,"LEVEL.IDX"); hamarc_begin(fp); for(i=0;i<n;i++) { fputc(levelid[i],fp); fputc(levelid[i]>>8,fp); } hamarc_end(fp); fclose(fp); } static void one_solution(FILE*fp) { char buf[9]; int i,n; i=fgetc(stdin); i|=fgetc(stdin)<<8; n=fgetc(stdin); n|=fgetc(stdin)<<8; sprintf(nam,"%d.SOL",i); hamarc_begin(fp); fputc(0,fp); fputc(0,fp); // Level version fread(buf,1,9,stdin); if(*buf) { fputc(1,fp); // bit0=has user name, bit1=has timestamp for(i=0;i<9;i++) { fputc(buf[i],fp); if(!buf[i]) break; } } else { fputc(0,fp); // has neither user name nor timestamp } while(n--) fputc(fgetc(stdin),fp); hamarc_end(fp); } static inline void do_solutions(void) { int n; FILE*fp; sprintf(nam,"%s.solution",basename); n=fgetc(stdin); n|=fgetc(stdin)<<8; if(!n) return; fp=fopen(nam,"w"); if(!fp) fatal("Cannot open file '%s' for writing\n",nam); while(n--) one_solution(fp); fclose(fp); } static inline void do_user_sounds(void) { int i,j,n; FILE*fp; n=fgetc(stdin); n|=fgetc(stdin)<<8; if(!n) return; nsounds=n; sprintf(nam,"%s.xclass",basename); fp=fopen(nam,"r+"); if(!fp) fatal("Cannot open file '%s' for reading/writing\n",nam); fseek(fp,0,SEEK_END); Allocate(sounds,n); Allocate(soundid,n); while(n--) { i=fgetc(stdin); i|=fgetc(stdin)<<8; j=fgetc(stdin); fread(nam,1,j,stdin); nam[j]=0; sounds[n]=strdup(nam); if(!sounds[n]) fatal("String duplication failed\n"); strcpy(nam+j,".WAV"); soundid[n]=i; hamarc_begin(fp); i=fgetc(stdin); i|=fgetc(stdin)<<8; while(i--) fputc(fgetc(stdin),fp); hamarc_end(fp); } fclose(fp); } int main(int argc,char**argv) { if(argc!=2) fatal("usage: %s basename < inputfile\n",argv[0]); basename=argv[1]; Allocate(nam,strlen(basename)+256); read_header(); do_pictures(); fread(picavail,1,512,stdin); do_user_messages(); do_classes(); do_levels(); if(nlevels) do_solutions(); do_user_sounds(); out_classes(); return 0; } |
Added names.h version [e0fea38138].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | // Auto-generated! Do not modify directly! #define MSG_INIT 0 #define MSG_CREATE 1 #define MSG_DESTROY 2 #define MSG_BEGIN_TURN 3 #define MSG_ARRIVED 4 #define MSG_DEPARTED 5 #define MSG_LASTIMAGE 6 #define MSG_MOVED 7 #define MSG_JUMPED 8 #define MSG_KEY 9 #define MSG_MOVING 10 #define MSG_SUNK 11 #define MSG_FLOATED 12 #define MSG_PLAYERMOVING 13 #define MSG_HIT 14 #define MSG_HITBY 15 #define MSG_DESTROYED 16 #define MSG_CREATED 17 #define MSG_POSTINIT 18 #define MSG_END_TURN 19 #define MSG_CLEANUP 20 static const char*const standard_message_names[]={ "INIT", "CREATE", "DESTROY", "BEGIN_TURN", "ARRIVED", "DEPARTED", "LASTIMAGE", "MOVED", "JUMPED", "KEY", "MOVING", "SUNK", "FLOATED", "PLAYERMOVING", "HIT", "HITBY", "DESTROYED", "CREATED", "POSTINIT", "END_TURN", "CLEANUP", }; #define SND_SPLASH 0 #define SND_POUR 1 #define SND_DOOR 2 #define SND_GLASS 3 #define SND_BANG 4 #define SND_UNHH 5 #define SND_UH_OH 6 #define SND_FROG 7 #define SND_THWIT 8 #define SND_KLINKK 9 #define SND_POWER 10 #define SND_KLECK 11 #define SND_CLICK 12 #define SND_SMALL_POP 13 #define SND_DINK 14 #define SND_TICK 15 #define SND_CHYEW 16 #define SND_CHEEP 17 #define SND_ANHH 18 #define SND_BRRRT 19 #define SND_BRRREEET 20 #define SND_BWEEP 21 #define SND_DRLRLRINK 22 #define SND_FFFFTT 23 #define SND_WAHOO 24 #define SND_YEEHAW 25 #define SND_OLDPHONE 26 #define SND_RATTLE 27 #define SND_BEEDEEP 28 #define SND_THMP_thmp 29 #define SND_BEDOINGNG 30 #define SND_HEARTBEAT 31 #define SND_LOCK 32 #define SND_TAHTASHH 33 #define SND_BOOOM 34 #define SND_VACUUM 35 #define SND_RATCHET2 36 #define SND_DYUPE 37 #define SND_UNCORK 38 #define SND_BOUNCE 39 #define SND_JAYAYAYNG 40 #define SND_DEEP_POP 41 #define SND_RATCHET1 42 #define SND_GLISSANT 43 #define SND_BUZZER 44 #define SND_FAROUT 45 #define SND_KEWEL 46 #define SND_WHACK 47 #define SND_STEAM 48 #define SND_HAWK 49 static const char*const standard_sound_names[]={ "SPLASH", "POUR", "DOOR", "GLASS", "BANG", "UNHH", "UH_OH", "FROG", "THWIT", "KLINKK", "POWER", "KLECK", "CLICK", "SMALL_POP", "DINK", "TICK", "CHYEW", "CHEEP", "ANHH", "BRRRT", "BRRREEET", "BWEEP", "DRLRLRINK", "FFFFTT", "WAHOO", "YEEHAW", "OLDPHONE", "RATTLE", "BEEDEEP", "THMP_thmp", "BEDOINGNG", "HEARTBEAT", "LOCK", "TAHTASHH", "BOOOM", "VACUUM", "RATCHET2", "DYUPE", "UNCORK", "BOUNCE", "JAYAYAYNG", "DEEP_POP", "RATCHET1", "GLISSANT", "BUZZER", "FAROUT", "KEWEL", "WHACK", "STEAM", "HAWK", }; |
Added names.js version [db084a2327].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | // Program to generate names.h file. // Public domain. "use strict"; const standard_message_names=` // Original 0 = INIT 1 = CREATE 2 = DESTROY 3 = BEGIN_TURN 4 = ARRIVED 5 = DEPARTED 6 = LASTIMAGE 7 = MOVED 8 = JUMPED 9 = KEY 10 = MOVING 11 = SUNK 12 = FLOATED 13 = PLAYERMOVING 14 = HIT 15 = HITBY 16 = DESTROYED 17 = CREATED 18 = POSTINIT 19 = END_TURN // New 20 = CLEANUP `.split("\n").map(x=>/^ *([0-9]+) = ([^ ]*) *$/.exec(x)).filter(x=>x); const standard_sound_names=[]; ` SPLASH POUR DOOR GLASS BANG UNHH UH_OH FROG THWIT KLINKK POWER KLECK CLICK SMALL_POP DINK TICK CHYEW CHEEP ANHH BRRRT BRRREEET BWEEP DRLRLRINK FFFFTT WAHOO YEEHAW OLDPHONE RATTLE BEEDEEP THMP_thmp BEDOINGNG HEARTBEAT LOCK TAHTASHH BOOOM VACUUM RATCHET2 DYUPE UNCORK BOUNCE JAYAYAYNG DEEP_POP RATCHET1 GLISSANT BUZZER FAROUT KEWEL WHACK STEAM HAWK `.replace(/[A-Za-z_0-9]+/g,x=>standard_sound_names.push(x)); console.log("// Auto-generated! Do not modify directly!"); standard_message_names.forEach(([a,b,c])=>console.log("#define MSG_"+c+" "+b)); console.log("static const char*const standard_message_names[]={"); standard_message_names.forEach(([a,b,c])=>console.log(" \""+c+"\",")); console.log("};"); standard_sound_names.forEach((x,y)=>console.log("#define SND_"+x+" "+y)); console.log("static const char*const standard_sound_names[]={"); standard_sound_names.forEach(x=>console.log(" \""+x+"\",")); console.log("};"); |
Added notes version [477e17bf7e].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | Some notes === File formats === Each puzzle set in Free Hero Mesh is stored as four files: *.xclass (Hamster archive) - Pictures and user sounds *.class (Text) - Class definitions (attributes and codes) *.level (Hamster archive) - Levels *.solution (Hamster archive) - Solutions to levels An idea is to use either Hamster archive or SQLite for the .level and .solution files. I decided to use Hamster archive, but here are some of the advantages and disadvantages of each approach: Advantages of using Hamster archive: * It is a simple file format. * You can use the "har" program to extract and alter lumps. * There will be less bugs because it is simpler than SQLite. Disadvantages of using Hamster archive: * It is necessary to rewrite the entire file when it changes. Advantages of using SQLite: * You can read parts of the file at a time. * You can alter records without having to rewrite everything. * SQL can now be used for user queries and user scripts. * You can use sqlite3 command shell to deal with the file. Disadvantages of using SQLite: * There will be extra overhead due to b-trees and other stuff. * It may be necessary to deal with untrusted database schemas (unsure). * Now SQLite must be included in this program. |
Added readpicture.c version [528626beff].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #if 0 gcc -s -O2 -o ./readpicture -Wno-unused-result readpicture.c exit #endif // This program is part of Free Hero Mesh and is public domain. #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { unsigned char x[8]; } Color; static unsigned char buf[32]; static int size,num,meth; static Color pal[256]; static unsigned char*pic; static inline void load_palette(void) { int i; FILE*fp=fopen("colorpalette","r"); if(!fp) exit(1); for(i=0;i<256;i++) { fscanf(fp,"%2hhx%2hhx%2hhx",pal[i].x+0,pal[i].x+2,pal[i].x+4); pal[i].x[1]=pal[i].x[0]; pal[i].x[3]=pal[i].x[2]; pal[i].x[5]=pal[i].x[4]; pal[i].x[7]=pal[i].x[6]=i?255:0; } fclose(fp); } static void load_picture(int id) { int c,n,t,x,y; unsigned char*p; meth=(id?buf[(*buf&15)+1+((id-1)>>1)]>>(id&1?0:4):*buf>>4)&15; size=buf[id+1]; pic=realloc(pic,size*size); if(!pic) { fprintf(stderr,"Allocation failed\n"); exit(1); } if(meth==15) { fread(pic,size,size,stdin); return; } p=pic; n=t=0; y=size*size; while(y--) { if(!n) { n=fgetc(stdin); if(n<85) { // Homogeneous run n++; x=fgetc(stdin); if(t==1 && x==c) n*=85; else n++; c=x; t=1; } else if(n<170) { // Heterogeneous run n-=84; t=2; } else { // Copy-above run n-=169; if(t==3) n*=85; t=3; } } n--; if(t==2) c=fgetc(stdin); if(t==3) c=p-pic>=size?p[-size]:0; *p++=c; } } static inline void out_picture(void) { int x,y; //fprintf(stderr,"%d\n",meth); if(meth==5 || meth==6) meth^=3; for(y=0;y<size;y++) for(x=0;x<size;x++) { if(meth&1) x=size-x-1; if(meth&2) y=size-y-1; fwrite(pal[pic[meth&4?x*size+y:y*size+x]].x,1,8,stdout); if(meth&1) x=size-x-1; if(meth&2) y=size-y-1; } } int main(int argc,char**argv) { int i; if(argc!=2) return 1; load_palette(); num=strtol(argv[1],0,0); *buf=fgetc(stdin); i=*buf&15; fread(buf+1,1,i+(i>>1),stdin); for(i=0;i<=num;i++) load_picture(i); fwrite("farbfeld",1,8,stdout); putchar(0); putchar(0); putchar(size>>8); putchar(size); putchar(0); putchar(0); putchar(size>>8); putchar(size); out_picture(); return 0; } |