Modifications to prince.exe (hex editing)

Post Reply
htamas
Efendi
Efendi
Posts: 10
Joined: February 22nd, 2009, 7:49 pm

Modifications to prince.exe (hex editing)

Post by htamas »

This topic was originally available at http://popuw.com/forum/viewtopic.php?t=590. I tried to salvage posts from my locally saved files and the Internet Archive's Wayback Machine. If you have some additional material, please share it. Thanks.
htamas @ popuw.com (Thu Aug 17, 2006 8:17 pm) wrote: This post is in response to the vpalace.dat thread, but I think it's quite off-topic there, so I've started a new one.
programmer wrote: htamas, I see you have managed to change many aspects of game by editing the executable. Can you write more details for any of those?
As poirot already noted in this thread, all versions of prince.exe are packed using MS ExePack 4.06, therefore some of the modifications are only available if you unpack it. You can use the upackexe.exe tool in the lzexe distribution to achieve this.

There are three versions of prince.exe commonly available: 1.0, 1.3 and 1.4. You can use the packed (original) or unpacked versions. I'm trying to give the modifications as generally as possible, so that you can use them for any version, though it is not always feasible. To make the description shorter, I'll denote the versions as p0, p3, p4 and u0, u3, u4 in the logical way.

For the assembly snippets, I use the u0 version. I'll give a hexadecimal listing to search for, where the bytes to change are marked with bold. A byte written as .. is a wildcard, it matches any byte.

Time available and starting hit points:

Code: Select all

12e5:002f    c7 06 7e 4f 3c 00    mov word ptr [4f7e], 003c
12e5:0035    c7 06 82 4f cf 02    mov word ptr [4f82], 02cf
12e5:003b    c7 06 08 46 03 00    mov word ptr [4608], 0003
Search for: c7 06 .. .. 3c 00 c7 06 .. .. cf 02 c7 06 .. .. 03 00
(offsets are p0:0x04a1f, u0:0x060cf, p3:0x04e9f, u3:0x055df, p4:0x0495b, u4:0x05a8b)
and replace
3c 00 for the number of minutes (+1)
cf 02 for the number of ticks (1 second = 12 ticks)
03 00 for the number of hit points
These values use the format used in the save files. For example, the original settings of 60, 719 and 3 mean that you have 59 minutes 719 ticks (1 tick less than 60 minutes -> that is 60 minutes, since for 0 minutes 0 ticks you have 1 tick) and 3 hit points when the game starts.

Starting level:

Code: Select all

0e66:0503    c7 06 b8 42 01 00    mov word ptr [42b8], 0001
0e66:0509    b8 5e 29             mov ax, 295e
0e66:050c    1e                   push ds
0e66:050d    50                   push ax
0e66:050e    2b c0                sub ax, ax
0e66:0510    50                   push ax
Search for: c7 06 .. .. 01 00 b8 .. .. 1e 50 2b c0 50
(offsets are p0:0x00703, u0:0x01db3, p3:0x007d7, u3:0x00f17, p4:0x0079b, u4:0x018cb)
and replace 01 00 with the starting level
This is the level you start everytime you press Ctrl+R also. Since there are quite few levels, only the first byte is meaningful.

Maximal number of hit points:

Code: Select all

0e66:11ec    a1 f2 5f             mov ax, [5ff2]
0e66:11ef    40                   inc ax
0e66:11f0    3d 0a 00             cmp ax, 000a
0e66:11f3    7e 03                jle 11f8
0e66:11f5    b8 0a 00             mov ax, 000a
0e66:11f8    a3 f2 5f             mov [5ff2], ax
Search for: a1 .. .. 40 3d 0a 00 7e 03 b8 0a 00 a3 .. ..
(offsets are p0:0x013ec, u0:0x02a9c, p3:0x015a7, u3:0x01ce7, p4:0x0149e, u4:0x025ce)
and replace both occurences of 0a 00 with the maximal number of hit points that can be achieved
Warning: setting a value larger than 10 (0a 00) will cause the hit points display in the lower left corner of the screen to be overlapped by the remaining time messages, so it is discouraged. However, from the point of view of the game, its value is handled correctly.

Minimal and maximal level where you can save:

Code: Select all

0e66:05c4    83 3e 9e 0f 02       cmp word ptr [0f9e], 0002
0e66:05c9    7e d0                jle 059b
0e66:05cb    83 3e 9e 0f 0e       cmp word ptr [0f9e], 000e
0e66:05d0    7d c9                jnl 059b
Search for: 83 3e .. .. 02 7e .. 83 3e .. .. 0e 7d ..
(offsets are p0:0x007c4, u0:0x01e74, p3:0x008b0, u3:0x00ff0, p4:0x00874, u4:0x019a4)
and replace
02 with one less than the minimal level where it is allowed to save
0e with one more than the maximal level where it is allowed to save
In the original set, you can save from level 3 to level 13. Note that by changing the assembly code, you can achieve some other logic as well (e.g. you can only save on levels whose number is an odd number) as long as it fits the place.

Dungeon and palace levels:

Code: Select all

2934:02b2    00 00 00 00 01 01 01 00
2934:02ba    00 00 01 01 00 00 01 00
Search for: 74 00 00 00 00 00 01 01 01 00 00 00 01 01 00 00 01 00
(offsets are p0:0x1ace8, u0:0x1c840, p3:0x1b9ac, u3:0x1c5c4, p4:0x17d4a, u4:0x18f3a)
Each of the 16 bytes corresponds to a level (0=demo, ..., 12=shadow, 13=jaffar, 14=princess, 15=potions), where 00 means dungeon and 01 means palace. I've prepended two bytes before the search string, since otherwise it can be found two times in the unpacked versions.

Guard base hit points:

Code: Select all

2934:0eda    04 03 03 03 03 04 05 04
2934:0ee2    04 05 05 05 04 06 00 00
Search for: 04 03 03 03 03 04 05 04 04 05 05 05 04 06 00 00
(offsets are p0:0x1b8a8, u0:0x1d46a, p3:0x1c6c5, u3:0x1d35c, p4:0x18a97, u4:0x19d06)
For each level, a single byte stores the number of hit points a guard has by default. The level file can increment this for individual guards.

Guard types:

Code: Select all

2934:03d4    00 00 00 00 00 00 02 00
2934:03dc    00 00 00 00 01 00 00 00
2934:03e4    00 00 00 00 00 00 00 00
2934:03ec    04 00 03 00 ff ff ff ff
Search for: 00 00 00 00 00 00 02 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 04 00 03 00 ff ff ff ff
(offsets are u0:0x1c964, u3:0x1c702, u4:0x1905e; this is not available in packed versions in this way)
For each level, two bytes are stored. The possible values are:
0000 default guard, using guard.dat
0100 fat guard, using fat.dat
0200 skeleton, using skel.dat
0300 Jaffar, using vizier.dat
0400 shadow, using shadow.dat
ffff no guard, don't load resources
Note that this only affects the resource file that is loaded and therefore the bitmaps that are displayed. For example, if you change level 3 to use the Jaffar sprite, it will remain unkillable. Killing guards using the skeleton or shadow sprite or meeting a guard when no resource is loaded causes the game to crash, since it would need to load a nonexistent resource.

Changing palace levels to use the dungeon wall-drawing algorithm:

Code: Select all

1828:0993    8b 1e 9e 0f          mov bx, [0f9e]
1828:0997    38 a7 b2 02          cmp [bx+02b2], ah
1828:099b    74 07                je 09a4
change to:
1828:099b    eb 07                jmp 09a4

1828:26f3    8b 1e 9e 0f          mov bx, [0f9e]
1828:26f7    80 bf b2 02 01       cmp byte ptr [bx+02b2], 01
1828:26fc    1b c0                sbb ax, ax
1828:26fe    f7 d8                neg ax
1828:2700    89 46 fe             mov [bp-02], ax
change to:
1828:26fc    b8 01 00             mov ax, 0001
1828:26ff    90                   nop

1828:0e72    8b 1e 9e 0f          mov bx, [0f9e]
1828:0e76    80 bf b2 02 00       cmp byte ptr [bx+02b2], 00
1828:0e7b    74 07                je 0e84
change to:
1828:0e7b    eb 07                jmp 0e84
This requires multiple modifications:

Search for: 8b 1e .. .. 38 a7 .. .. 74 07
(offsets are p0:0x0a7b3, u0:0x0be63, p3:0x0ac5f, u3:0x0b39f, p4:0x0a71b, u4:0x0b84b)
and change 74 07 to eb 07

Search for: 8b 1e .. .. 80 bf .. .. 01 1b c0 f7 d8 89 46 fe
(offsets are p0:0x0c513, u0:0x0dbc3, p3:0x0ca07, u3:0x0d147, p4:0x0c4c3, u4:0x0d5f3)
and change 1b c0 f7 d8 to b8 01 00 90

Search for: 8b 1e .. .. 80 bf .. .. 00 74 07
(offsets are p0:0x0ac92, u0:0x0c342, p3:0x0b13e, u3:0x0b87e, p4:0x0abfa, u4:0x0bd2a)
and change 74 07 to eb 07

This will cause the dungeon WDA to be used for palace levels, though, the tiles and palettes will be taken from vpalace.dat. This also changes the way resources from vpalace.dat are interpreted, so that file must also be changed accordingly. For more details, see the vpalace.dat thread.

That's all that comes to my mind now. Feel free to expand this list.
programmer @ popuw.com (Thu Aug 17, 2006 8:41 pm) wrote: Thanks for the informations, I'm going to edit the prince.exe file now ;)
KingOfPersia @ popuw.com (Thu Aug 17, 2006 9:27 pm) wrote: Looks very interesting!

I will see if I can use this information for my new mod.

How do you discover this kind of things?

I discovered a lot of things about The levels.dat (after a lot of chashes)
and stopped with it when I found a level editor. But Prince.exe seems very more difficult.

I'm hoping you will discover more
programmer @ popuw.com (Thu Aug 17, 2006 9:36 pm) wrote: htamas, I have been watching your video... Have you modified the demo sequence (I mean the 00 level)? If yes, how?
And I think this topic should be marked as important.

[+]And another question - is it possible to remove the intro sequence or force application to quit after passing some level?
htamas @ popuw.com (Thu Aug 17, 2006 10:25 pm) wrote:
KingOfPersia wrote: How do you discover this kind of things?

I discovered a lot of things about The levels.dat (after a lot of chashes)
and stopped with it when I found a level editor. But Prince.exe seems very more difficult.
I was using Turbo Debugger, which, besides regular debugging, can be used for reverse engineering. It shows the disassembly of the program code (like the code snippets shown above) and allows you to set breakpoints or use single-stepping. Assembly language is equivalent to machine code (those hexadecimal number sequences), but it is easier for humans to read. Even if you know 16-bit assembly, reverse engineering can be quite a challenge, and it involves some guesswork. But it is fun as well. Theoretically you see everything the program does, but it is composed from so small instructions that it is hard to follow.
programmer wrote: htamas, I have been watching your video... Have you modified the demo sequence (I mean the 00 level)?
And I think this topic should be marked as important.
If you mean the level itself, it isn't modified, only the movements. I've used pr to copy level 0 to level 2 and then played it :). After that, I've placed it where the demo would normally come. Btw, didn't you want to post this to the other thread? ;)
programmer wrote: [+]And another question - is it possible to remove the intro sequence or force application to quit after passing some level?
It should be possible. It is already partly implemented, since when you start the game using e.g. "prince megahit 8" or "prince improved 8", the given level is loaded without the title sequence (if you start level 2, level 15 will be loaded). I'll try to find some offsets for these modifications too.
programmer @ popuw.com (Thu Aug 17, 2006 10:44 pm) wrote:
It should be possible. It is already partly implemented, since when you start the game using e.g. "prince megahit 8" or "prince improved 8", the given level is loaded without the title sequence (if you start level 2, level 15 will be loaded). I'll try to find some offsets for these modifications too.
Yes, but I were thinking about making a demonstration with, lets say 2 levels, that let players try the game. Starting on selected by me level isn't hard, as you said, the megahit/improved cheat code + batch file can be used, but I was thinkink about self-exiting game when those 2 levels will be passed.

[+] and the introduction sequence - I saw that it isn't modified but how to add the prince movement into game? (I succesfully replaced the intro and level2 files by PR but what next?) I never tried to change this, so, can you write exactly how to change it?
htamas @ popuw.com (Sat Aug 19, 2006 12:21 am) wrote:
programmer wrote: Yes, but I were thinking about making a demonstration with, lets say 2 levels, that let players try the game. Starting on selected by me level isn't hard, as you said, the megahit/improved cheat code + batch file can be used, but I was thinkink about self-exiting game when those 2 levels will be passed.
Ok, here are some more for you:

Skipping the title sequence and starting with a specific level:

Code: Select all

0e66:01af    74 36                je 01e7
0e66:01b1    c7 46 f8 0e 00       mov word ptr [bp-08], 000e
0e66:01b6    eb 03                jmp 01bb
0e66:01b8    ff 4e f8             dec word ptr [bp-08]
e066:01bb    83 7e f8 00          cmp word ptr [bp-08], 0000
0e66:01bf    7c 26                jl 01e7

0e66:01e1    8b 46 f8             mov ax, [bp-08]
0e66:01e4    a3 b8 42             mov [42b8], ax
This requires multiple modifications:

Search for: 74 36 c7 46 f8 0e 00 eb 03 ff 4e f8 83 7e f8 00 7c 26
(offsets are p0:0x003af, u0:0x01a5f, p3:0x00438, u3:0x00b78, p4:0x00422, u4:0x01552)
and replace 36 with 30 and 26 with 20

Search for: 8b 46 f8 a3 .. ..
(offsets are p0:0x003e1, u0:0x01a91, p3:0x0046a, u3:0x00baa, p4:0x00454, u4:0x01584)
and replace 8b 46 f8 with b8 xx 00 where xx is the level you would like to load instead of the title sequence

When starting prince, this level will load instantly. Note that pressing Ctrl+R will return to the level that was specified above, in the Starting level hack. If it is not level 1, you'd better set that one as well.

Exiting automatically after a given level:

Code: Select all

12e5:055e    9a 14 72 df 1a       call 1adf:7214
change to:
12e5:055e    9a d7 09 b5 10       call 10b5:09d7

10b5:09d7    55                   push bp
10b5:09d8    8b ec                mov bp, sp
10b5:09da    83 ec 44             sub sp, 0044
10b5:09dd    56                   push si
10b5:09de    c7 46 fa 00 00       mov word ptr [bp-06], 0000
10b5:09e3    c7 46 fc 0f 00       mov word ptr [bp-04], 000f
10b5:09e8    b8 01 00             mov ax, 0001
10b5:09eb    50                   push ax
change to:
10b5:09d7    83 3e 9e 0f xx       cmp word ptr [0f9e], 00xx
10b5:09dc    75 08                jne 09e6
10b5:09de    2b c0                sub ax, ax
10b5:09e0    50                   push ax
10b5:09e1    9a 7a 0c df 1a       call 1adf:0c7a
10b5:09e6    9a 14 72 df 1a       call 1adf:7214
10b5:09eb    cb                   retf
This is quite a complicated hack, since we needed to write some extra code that handles the quit condition. Therefore, we had to hijack a function call and overwrite another procedure. I've chosen the one where you finish and meet the princess, since this won't play anyway when you quit after finishing a level < 14.

Such a modification requires function pointers to be written in some places in the code, but they are different for each version. I've chosen to only modify the unpacked 1.0 version, since probably one version is enough for you. (Therefore, this hack won't work for other versions.)

At offset 0x4777, replace
55 8b ec 83 ec 44 56 c7 46 fa 00 00 c7 46 fc 0f 00 b8 01 00 50
with
83 3e 9e 0f xx 75 08 2b c0 50 9a 7a 0c df 1a 9a 14 72 df 1a cb
where xx is the level after which you would like to quit.

Also, at offset 0x65ff, replace 14 72 79 0c with d7 09 4f 02.

Reading your question, I assume that you would like to minimize the impact of the original story on your levels. You can also quit when time expires and you can disable the cutscenes.

Quitting when time expires: at offset 0x2261, replace 94 0c 4f 02 with 7a 0c df 1a
(note: you won't see the scene with the hourglass in the princess' room when the time expires)

The table of cutscenes is starting at offset 0x1d530. For each level, 4 bytes is used. Note that these are offset:segment values, so you might not just write anything there, but you may swap them or disable them by writing 00 00 00 00. (Note that for levels starting from 3, the princess is animated, while before that, Jaffar is animated, if applicable. It's quite strange, but you'll see if you try it. So you should avoid swapping one before 3 to one after 2.)
programmer wrote: [+] and the introduction sequence - I saw that it isn't modified but how to add the prince movement into game? (I succesfully replaced the intro and level2 files by PR but what next?) I never tried to change this, so, can you write exactly how to change it?
I don't know, but probably the beginning is using a hardcoded list of keypresses or actions (function calls), and at the end, the fight is using the same ai for the kid and for the guard (that is the only randomized part of the demo sequence).
ecco @ popuw.com (Sun Aug 20, 2006 6:07 pm) wrote: Is there anyway in changing the default background colour from black to something else in all that code?

This would mainly so one could choose a bg colour to match the overall colour scheme. In my vpalace for example which is quite a bright environment in relation to the dungeons I made, a thick black line running over the floor tiles kind of stands out. I've been fiddling with the palette colour this morning too, but no good.

Or even being able to make a repeating pattern for the background would be even more excellent. More or less like the snes version.

I've searched and found a few references to a brown or yellow background in The Great Escape, but I've just played it and nothings different. I've also read that a future editor for PoP2 might be able to edit backgrounds or something somewhere.

Thanks
poirot @ popuw.com (Sun Aug 20, 2006 6:26 pm) wrote: that's really good stuff, I'd like to code an editor or something for that ;)

Last edited by poirot on Mon Aug 21, 2006 1:02 am; edited 1 time in total
poirot @ popuw.com (Mon Aug 21, 2006 12:56 am) wrote: oh, btw, don't you want to write a technical document (like the format specifications of .dat files) with all this stuff including the code you've posted in the other threads? I could give you access to the cvs if you want.
htamas @ popuw.com (Mon Aug 21, 2006 7:26 am) wrote:
ecco wrote: Is there anyway in changing the default background colour from black to something else in all that code?
Yes, there is, but it changes the background colour everywhere. That is, on the loading screen, in the cutscenes, and also in the bottom row where your hit points are. Therefore, e.g. the same colour is used for dungeon and palace levels.

Note: As you probably know, the game uses a 256 colour vga (mcga) mode, but bitmaps are using 16 colour palettes. These are loaded in the main palette at offsets divisible by 16. I have identified the following palettes:
00: This contains the background colour (index 0) and the colour used when printing texts: loading, level %d, %d minutes remaining, press any key to continue, etc. (index 15). Palette values are hardcoded.
20: Only two nonzero colours are present (indexes 6 and 15) and they are used for the sword when it is held by someone, i.e. not on the floor. Loaded from prince.dat/prince/sword/fighting/sword.pal.
30: Used for the fire of torches and potion vases, maybe some other objects as well. Loaded from prince.dat/prince/main.pal.
50: This is the generic dungeon/palace palette, including everything except the walls. Loaded from vdungeon.dat/vdungeon/palette/dungeon.pal or vpalace.dat/vpalace/palettes/palace.pal.
60: This is the dungeon/palace wall palette. Loaded from vdungeon.dat/vdungeon/binary/other.pal (shouldn't it be vdungeon.dat/vdungeon/palettes/wall.pal?) or vpalace.dat/vpalace/palettes/wall.pal.
70: Used for the prince, his hit points and the mouse. Loaded from kid.dat/kid/kid.pal.
80: This palette is used for the guards. It is reloaded everytime you go to another room and changed to the palette for that guard. As there is at most one guard per room, this is not a problem. Loaded from different files depending on the guard type and colour.
90: Used in the throne room. In the introduction, it is used for the princess (to be checked).
a0: Used in the throne room. In the introduction, it is used for Jaffar. In the cutscene before level 4, it's used for the princess (to be checked).
b0: Used in the intro sequences. Probably corresponds to title.dat/title/main titles/text background.pal.
c0: Used in the intro sequences. Probably corresponds to title.dat/title/main titles/titles.pal.
d0: Palette of the throne room background. Loaded from pv.dat/pv/objects/room and clock.pal.
e0: Palette of the bed in the throne room. Loaded from pv.dat/pv/objects/room bed.pal.

Here, you need to modify the hardcoded palette.
Search for: 00 00 00 00 00 2a 00 2a 00 00 2a 2a 2a 00 00 2a 00 2a 2a 15 00 2a 2a 2a 15 15 15 15 15 3f 15 3f 15 15 3f 3f 3f 15 15 3f 15 3f 3f 3f 15 3f 3f 3f
(offsets are p0:0x1d141, u0:0x1f136, p3:0x1df5e, u3:0x1f02a, p4:0x1a335, u4:0x1b9de)
Each palette entry corresponds to a 3-byte rgb triplet. Each byte contains a value from 00 to 3f (0 to 63), that is, a valid vga palette entry. If you would like to change the background colour, modify the first three bytes. Changing the text colour requires editing of the three last.
ecco wrote: In my vpalace for example which is quite a bright environment in relation to the dungeons I made, a thick black line running over the floor tiles kind of stands out.
You can't modify the background colour of dungeon and palace levels separately, or at least, not using this way. It might be possible to change the palette index used when clearing the screen to an 5x or 6x one, so that it is loaded from the dungeon or palace palette, but I don't see an easy way of doing that now.
ecco wrote: Or even being able to make a repeating pattern for the background would be even more excellent. More or less like the snes version.
Well, it would be nice, but injecting a not-yet-existing procedure into binary code is definitely not an easy task. And it would require hijacking another resource, too. Using modifiers on background tiles and editing their bitmaps (vpalace.dat/vpalace/background/bricksxx.bmp) might help, but we'll need to change their size as they don't fit exactly. I don't know yet where the offset and size information for these sprites is stored, so it would require some extra research.
ecco wrote: I've also read that a future editor for PoP2 might be able to edit backgrounds or something somewhere.
Probably PV4. But PoP2, in this aspect, is entirely different. There, backgrounds are used in the original game as well, so the problem is reduced to that of a resource replacement (and of course, reverse-engineering their format first ;)).
poirot wrote: oh, btw, don't you want to write a technical document (like the format specifications of .dat files) with all this stuff including the code you've posted in the other threads? I could give you access to the cvs if you want.
I think it's more like a collection of random hacks than any sort of specification. Anyway, feel free to copy it and post it anywhere. If you have some idea about what format would be better suited for it, I can change it to that format, but at the moment, I think it's just right this way ;).
poirot wrote: that's really good stuff, I'd like to code an editor or something for that ;)
Yes, it would be cool to edit the settings in an xml or text file and run a program, which commits them to prince.exe. Since the list of offsets in my posts are already generated by a script, it would be no problem to convert it to the program's import format. The most compatible (but comparably slow) way would be to search for the given expression, including wildcards, check that it is the only occurence, and then replace certain bytes from the found location with ones generated from the edited values. Using an offset table is easier, but then it has to be created for each version and we'll have to identify them.
ecco @ popuw.com (Mon Aug 21, 2006 1:41 pm) wrote:
htamas wrote:
ecco wrote: Or even being able to make a repeating pattern for the background would be even more excellent. More or less like the snes version.
Well, it would be nice, but injecting a not-yet-existing procedure into binary code is definitely not an easy task. And it would require hijacking another resource, too. Using modifiers on background tiles and editing their bitmaps (vpalace.dat/vpalace/background/bricksxx.bmp) might help, but we'll need to change their size as they don't fit exactly. I don't know yet where the offset and size information for these sprites is stored, so it would require some extra research.

Actually this is something I already researched way back when I developed my high detail vdungeon02 graphics. I had replied here but realised I was off topic, so I've turned that into a new topic:

Making Custom Graphics

Thanks again for the info htamas. I'll try sometime to understand all that stuff and change some colours. :)

..
poirot @ popuw.com (Mon Aug 21, 2006 8:36 pm) wrote: great!
poirot @ popuw.com (Mon Aug 21, 2006 8:52 pm) wrote: I was thinking about the dungeon wall generating algorithm, I've coded it for FP, and understood how it works, but there is a seed that the game uses and I think it is saved inside the game. The seeds I extracted from the game (just looking on the images and not the code) are in http://cvs.lug.fi.uba.ar/cgi-bin/cvsweb ... freeprince

The algorithm is in the format specifications http://cvs.lug.fi.uba.ar/cgi-bin/cvsweb ... freeprince

I was thinking if it is possible to find the offsets of this seeds. There are four different types of 63 different wall blocks. Each block has modifiers like the position of the middle separator, etc. The four types are called SWS, WWS, SWW, WWW (where the middle W is the wall and the S is empty space).

I'd like to know if it is possible to find those offsets and see how and where they are saved in the game. They could be very interesting to edit ;)

I have also found offsets of all resources in the .exe, all animations, etc. So editing them could add new frames to animations, etc. I don't remember where they were, but I do remember it was near the end of the file. It's easy to find them because they where encoded as unsigned short int and they were all sequenced numbers. That could also be interesting to edit ;)
jora @ popuw.com (Mon Aug 21, 2006 9:37 pm) wrote: Hi
could someone help me changing the starting time?, I am new to hex editing
htamas @ popuw.com (Tue Aug 22, 2006 2:50 am) wrote:
jora wrote: Hi
could someone help me changing the starting time?, I am new to hex editing
I don't know where to start from, but perhaps it'll help.

All files, regardless of their file type, are stored as a sequence of bytes (integers from 0 to 255). They can be further decomposed to bits (0 or 1), but they are quite rarely used separately. While editors you generally use deal with these files according to their type (text, image, archive, etc.), this approach is limited to files using a specific set of formats, and for each type, you'll need a separate application. Hex editors, on the other hand, display and let you modify the data in its raw form. For regular files, it's kind of inconvenient compared to, say, an image manipulator, but where you have no other choice, hex editors come in handy. Editing executables for which you don't have the source or files using an unknown format typically fall in this category.

Hex editors typically divide your screen to three vertical fields. The first displays the offset, that is, how many bytes far are you from the beginning of the file. The second shows the bytes in base 16. For example, the character 'x', which is has an ascii code of 120 (decimal) is displayed as 78. The third field shows the character itself, in this case, 'x'.
Image
You can find the offset of a certain byte by adding the number at the beginning of the line (hexadecimal) to the one at the top of the column. Most, if not all, hex editors allow you to jump to a specific offset. When you need to apply the patch, you have to go to the given offset and modify the byte there to the one you see in the patch description.

If you don't have a hex editor yet, you can download e.g. hxd, frhed, hexplorer or xvi32. There are really lots of hex editors, the ones I provided links for are free ones.

In this case, you would like to modify the time to complete your mod. I'll show you the easy way - using the offsets I've given for the specific versions. You'll need to know the exact version you are using. For example, if you downloaded prince.zip from http://popuw.com/download.html, you are using the p0 version. Let's assume this in the examples. Make a backup of your prince.exe so that you can revert to it if you make something wrong.

Start your hex editor and open prince.exe. Scroll to the "Time available and starting hit points" section of my post. You see that "offsets are p0:0x04a1f, u0:0x060cf, p3:0x04e9f, u3:0x055df, p4:0x0495b, u4:0x05a8b". Since you are using the p0 version, the offset is 0x04a1f. Here, "0x" simply means hexadecimal. It depends on which hex editor you use that you'll need to write the "0x". Therefore, you'll either have to write "0x04a1f" or simply "4a1f" in the go to dialog.

The cursor should jump to a cell containing a byte "c7". If you continue to read from this cell to the right, continuing in the next line when you reach the end of the central field, you should see "c7 06 .. .. 3c 00 c7 06 .. .. cf 02 c7 06 .. .. 03 00" where the ".." means an arbitrary byte. If you see something different, then you are either using a wrong version or have missed something. If you see that, take a closer look to the bytes I've marked with bold. These are the ones to modify.

You would like to modify the starting time to 180 minutes. You need to subtract one tick, as noted in the instruction, so that you get 179 minutes 719 ticks. In the first two bytes, instead of 3c 00, you'll have to write the number of minutes +1. That is, 180. But you have to write it in hexadecimal. You can use the windows calculator (start -> run -> "calc") to convert decimal values to hexadecimal. You get b4. But you have two bytes for it, so you'll have to write b4 00. (This is because the so-called little-endian system that the x86 cpu uses writes the least significant byte at the beginning). Now do that conversion again for the number of ticks. 719 ticks convert to 2cf. Here, 02 is the most significant byte and cf is the least significant byte. Therefore, you'll have cf 02.

Now comes the modification itself. Go to the "3c 00" you have just found and overwrite it with "b4 00". Most hex editors will automatically overwrite it, but if yours inserts these bytes instead then you'll have to delete the original "3c 00". Now go to the "cf 02". In this case, you don't have to modify it, since the new value we've just calculated is the same. But if we'd have to, this would be the way to do it.

Save the file and try to launch it. It should start with "180 minutes left".
jora @ popuw.com (Tue Aug 22, 2006 1:36 pm) wrote: Thanks 8-)
david @ popuw.com (Tue Aug 22, 2006 4:54 pm) wrote: Modifying the number of hit points of the Prince on demo level:

Code: Select all


00004C25: C7 46 FE 04 00 mov [bp-02],0004
change to:
00004C25: C7 46 FE xx 00 mov [bp-02],00xx

00004C2A: 8B 46 FE          mov ax,[bp-02]
00004C2D: A3 98 4C         mov [+4C98],ax
00004C30: A3 F2 5F          mov [+5FF2],ax
Search for: C7 46 FE 04 00 8B 46 FE
(offsets are p0:0x4C25, p3:0x50AD, p4:0x4B69, u0:0x62D5, u3:0x57ED, u4:0x5C99)
and replace 04 with the number of hit points you want.
htamas @ popuw.com (Tue Aug 22, 2006 6:48 pm) wrote:
poirot wrote: I was thinking about the dungeon wall generating algorithm, I've coded it for FP, and understood how it works, but there is a seed that the game uses and I think it is saved inside the game. The seeds I extracted from the game (just looking on the images and not the code) are in http://cvs.lug.fi.uba.ar/cgi-bin/cvsweb ... freeprince

The algorithm is in the format specifications http://cvs.lug.fi.uba.ar/cgi-bin/cvsweb ... freeprince
I'm still looking for these, but meanwhile, I've found the order in which the sprites are placed. It's quite interesting, different from what I thought. :)

Image
poirot @ popuw.com (Wed Aug 23, 2006 8:11 am) wrote: great, it's the same order I use in freeprince ;) except for the wall separators, I don't draw them twice.

I've coded the program that reads the .xml and edits the .exe. Take a look at http://www.princed.com.ar/customexe.jsp I'm sure all you people will love it!

btw, There are only three hacks for the moment, blackchar will add more, it's just copy/paste from the information in this thread ;)

oh, forgot to say: works only for p0, but it has support for all the files, I only need the original.exe's (it would be great if anybody can send them to me)
oh, and about the source, I'll publish it, but for the moment feel free to ask for it.
jalal @ popuw.com (Wed Aug 23, 2006 8:21 am) wrote: Nice! And why don't you make it a tool...
poirot wrote: oh, forgot to say: works only for p0, but it has support for all the files, I only need the original.exe's (it would be great if anybody can send them to me)
Ok I will try to send it or publish it a.s.a.p.

Btw, I have a question, what's the difference between packed and unpacked version of prince.exe?

htamas: Is there a way not to reduce the "time left" to 15 minutes and to block in level 4 if we are playing normally (Shift-L) with no cheats...?
poirot @ popuw.com (Wed Aug 23, 2006 9:18 am) wrote: yes, I will make it a tool, but coding php is much faster, I've made it in two hours ;) and I think it will be very easy to use for people who don't want to download and install complicated programs. There is much still comming :)
htamas @ popuw.com (Wed Aug 23, 2006 5:52 pm) wrote:
poirot wrote: great, it's the same order I use in freeprince Wink except for the wall separators, I don't draw them twice.
I think they are drawn twice because they have to be drawn for the top 3 pixels of the screen as well if they are the base tiles of walls that are on the screen one above. And they don't draw the main wall tiles for them, so it's probably the easiest if they are drawn with the base tiles, not with the main tiles. However, they'll need to repeat the ones overlapped by the main tiles again. It's true that it is unnecessary to draw them twice if we are using some different logic.
poirot wrote: I've coded the program that reads the .xml and edits the .exe. Take a look at http://www.princed.com.ar/customexe.jsp I'm sure all you people will love it!
Yes, definitely. There seems to be a bug with the seconds in the time, the division/multiplication seems not to work.
jalal wrote: htamas: Is there a way not to reduce the "time left" to 15 minutes and to block in level 4 if we are playing normally (Shift-L) with no cheats...?
There probably is. I'll look after it, but I'll also have to track down some of the previous questions. ;)
jalal wrote: Btw, I have a question, what's the difference between packed and unpacked version of prince.exe?
Packed ones are the original, distributed versions. They are packed (compressed/encrypted) with ms exepack in such a way that when the program starts, it decompresses/decrypts some parts of it in memory. Unpacked versions can be generated from the packed versions using an unpacker, and there's no difference between the packed and unpacked versions from the POV of an user. But for hex editors, there is. Most of the code of prince.exe is unaffected by packing (some packers completely obfuscate code, but seemingly this one doesn't), so most of the hacks work with packed versions too.
poirot @ popuw.com (Wed Aug 23, 2006 6:17 pm) wrote: done, I've uploaded all the versions!
My p0 version differed :s but it seems to work. I have to test it.
poirot @ popuw.com (Wed Aug 23, 2006 6:21 pm) wrote:
htamas wrote:
There seems to be a bug with the seconds in the time, the division/multiplication seems not to work.
Indeed, it is in my todo list (to code a little form processor to transform the hex codes into a human readable input)

I've also added a field for help ;)
jalal @ popuw.com (Wed Aug 23, 2006 6:29 pm) wrote:
htamas wrote:
jalal wrote: Btw, I have a question, what's the difference between packed and unpacked version of prince.exe?
Packed ones are the original, distributed versions. They are packed (compressed/encrypted) with ms exepack in such a way that when the program starts, it decompresses/decrypts some parts of it in memory. Unpacked versions can be generated from the packed versions using an unpacker, and there's no difference between the packed and unpacked versions from the POV of an user. But for hex editors, there is. Most of the code of prince.exe is unaffected by packing (some packers completely obfuscate code, but seemingly this one doesn't), so most of the hacks work with packed versions too.
ah, ok. thanks for clearing this up :)
poirot @ popuw.com (Thu Aug 24, 2006 1:04 am) wrote: htamas, do you have a clue on where to look for the max level limitation? Adding levels to level.dat is very easy with PR, but it needs a lot of work in the .exe: move the dunveon/palace type array to a bigger address space at the end of the file; move the resource loading array, etc
poirot @ popuw.com (Thu Aug 24, 2006 1:17 am) wrote: For those who are interested all sources are GPL: http://www.princed.com.ar/gethack/ (it's not very much, coding was very fast, but it works)

I've added more hacks to the xml and support of combo boxes.
BlackChar @ popuw.com (Thu Aug 24, 2006 3:38 pm) wrote: Aww, poirot how did you add all those data so fast? I barely managed to add those in first message and even then it's full of typo errors. I guess XML won't be my friend for much longer :?.
And by the way, the generated files now don't work. Not even with default settings. You probably know that, but anyway... DosBox crashes after entering PRINCE command with this:

Code: Select all

Exit to error: CPU:GRP5:Illegal call 7
jora @ popuw.com (Thu Aug 24, 2006 7:40 pm) wrote: Is it possible to add levels to the game :?:
programmer @ popuw.com (Thu Aug 24, 2006 8:00 pm) wrote: Yes, it is, but it's very difficult and requires changing resources format. As poirot said, this won't be difficult, but adding new level support into .exe file may be a hard work.
poirot @ popuw.com (Thu Aug 24, 2006 9:20 pm) wrote:
BlackChar wrote: Aww, poirot how did you add all those data so fast? I barely managed to add those in first message and even then it's full of typo errors. I guess XML won't be my friend for much longer :?.
And by the way, the generated files now don't work. Not even with default settings. You probably know that, but anyway... DosBox crashes after entering PRINCE command with this:

Code: Select all

Exit to error: CPU:GRP5:Illegal call 7
I just did copy/paste from the thread and used vim.

Yes, the packed versions won't work because some settings aren't supported un packed exes, I'll code a javascript that disables the unsupported fields when you choose the base exe.
programmer @ popuw.com (Thu Aug 24, 2006 9:34 pm) wrote: poirot - you can add options that allow to change the cheat activation code (megahit/improved) and the text that is displayed when exiting the game. I know that it's easy to change, but adding this may be useful
jalal @ popuw.com (Thu Aug 24, 2006 9:40 pm) wrote:
programmer wrote: poirot - you can add options that allow to change the cheat activation code (megahit/improved) and the text that is displayed when exiting the game. I know that it's easy to change, but adding this may be useful
Or better, an option that translates the game to other languages. Like level, minutes left, game version, etc. So we avoid 'killing ourselves' by the use of a hex editor! :D
programmer @ popuw.com (Thu Aug 24, 2006 9:42 pm) wrote: Game version change may be useful too, but changing all the text in game? Why not, but... when using a hex editor, it is a bit more interesting, I think ;)
jalal @ popuw.com (Thu Aug 24, 2006 9:43 pm) wrote:
programmer wrote: Game version change may be useful too, but changing all the text in game? Why not, but... when using a hex editor, it is a bit more interesting, I think ;)
Yes you're right, like taking spaces from other words and so on ...
poirot @ popuw.com (Thu Aug 24, 2006 11:11 pm) wrote: the next improvement will be string support, but for the moment I'm working in the xml parsing to support multiple editions per hack.

Editing a string will have a problem: you can't add text that is bigger than the text in the original game, if you want a bigger text you have to rewrite the pointer and add the text at the end of the file. It will take some time to find the pointers to the text. But for the moment I think I can add an option for string editing limiting the strings to the original size.
htamas @ popuw.com (Fri Aug 25, 2006 7:47 pm) wrote: poirot: The levels where saving is allowed are shifted by one (due to difference between < and <= in the code). In princehack.xml, you'll need to change

Code: Select all

<read type="unsigned char" name="minimal level" default="2" minval="0" maxval="65535"/>
<check codes="7e .. 83 3e .. .."/>
<read type="unsigned char" name="maximal level" default="14" minval="0" maxval="65535"/>
to

Code: Select all

<read type="unsigned char" name="minimal level" default="3" minval="1" maxval="65535" readoperation="add(1);" writeoperation="subtract(1);"/>
<check codes="7e .. 83 3e .. .."/>
<read type="unsigned char" name="maximal level" default="13" minval="0" maxval="65534" readoperation="subtract(1);" writeoperation="add(1);"/>
and add the subtract option in parsecommands.php.
poirot @ popuw.com (Fri Aug 25, 2006 9:16 pm) wrote: it's fixed ;)

btw, can you rin the offset script to these values:

Code: Select all

strings prince.exe|while read a; do echo "looking for $a";echo -n "check ($a) ";echo $a|od -t x1|head -n 1|awk '{for (i=2;i<NF;i++) printf("%s ",$i);}';echo '00';done
(note the 00 to find only null terminated strings)

(if you can't there's no problem, I'll run it as soon as I get home ;) )

I'd like to add all of them to the xml (at least to be replaced with smallest or same-sized strings).
htamas @ popuw.com (Sat Aug 26, 2006 12:01 am) wrote:
poirot wrote: btw, can you rin the offset script to these values:

Code: Select all

strings prince.exe|while read a; do echo "looking for $a";echo -n "check ($a) ";echo $a|od -t x1|head -n 1|awk '{for (i=2;i<NF;i++) printf("%s ",$i);}';echo '00';done
Well, I can, but `strings prince.exe | wc -l` is 588 for me, that sounds bit too much (not for running the script but for the set of possible changes). I think there isn't more than about 50 that makes sense.
You can change:
- the loading message
- messages in the status bar (%d minutes remaining, game saved, etc.)
- message dialogs (drink potion matching..., insert disk, etc.)
- error messages (e.g. stack overflow)
The "hope you enjoyed it" message in cracked versions is originally a two-part error message. But for some reason, that error condition triggers on every exit. But it can lead to strange results as well, I've once received "Hope you enjoye- integer divide by 0".
You can also change the filenames the game uses, but you'll have to be cautious, since some of them occur more than once and have to refer to the same file; others occur both as a whole and put together from parts, e.g. "%s%s.DAT", "V", "PALACE".
It would be better to decide on the safe strings and run the offset script on them.
poirot @ popuw.com (Sat Aug 26, 2006 1:38 am) wrote: ok, yes, for the repeated strings, I was planning to use the duplicated attribute in the read option. I'll make a list of interesting offsets and post them into a file.
poirot @ popuw.com (Sat Aug 26, 2006 2:03 am) wrote: I've made this list: http://www.princed.com.ar/gethack/strings

For the problems with duplicated records that differs in the char case, I'll add two operations (uppercase and lowercase) in the xml to work in conjunction with the duplicated field. I still don't know how to handle in the xml advanced functions like string concatenations, etc.
poirot @ popuw.com (Tue Aug 29, 2006 5:54 am) wrote: for all who are interested, I've uploaded the latest version of the custom exe generator to http://www.princed.com.ar/cuspop.jsp

It has a script that makes the verification of the fields that are allowed to be modified in each version.

I will add the latest hacks asap

PS: more hacks are welcome ;)
poirot @ popuw.com (Tue Aug 29, 2006 7:03 am) wrote:
htamas wrote: At offset 0x4777, replace
55 8b ec 83 ec 44 56 c7 46 fa 00 00 c7 46 fc 0f 00 b8 01 00 50
with
83 3e 9e 0f xx 75 08 2b c0 50 9a 7a 0c df 1a 9a 14 72 df 1a cb
where xx is the level after which you would like to quit.

Also, at offset 0x65ff, replace 14 72 79 0c with d7 09 4f 02.

Reading your question, I assume that you would like to minimize the impact of the original story on your levels. You can also quit when time expires and you can disable the cutscenes.

Quitting when time expires: at offset 0x2261, replace 94 0c 4f 02 with 7a 0c df 1a
(note: you won't see the scene with the hourglass in the princess' room when the time expires)

The table of cutscenes is starting at offset 0x1d530. For each level, 4 bytes is used. Note that these are offset:segment values, so you might not just write anything there, but you may swap them or disable them by writing 00 00 00 00. (Note that for levels starting from 3, the princess is animated, while before that, Jaffar is animated, if applicable. It's quite strange, but you'll see if you try it. So you should avoid swapping one before 3 to one after 2.)
What version are those offsets for? do you have the offsets for the other versions (I'm interested especially in the cutscenes, because it is very difficult to find an hex string because it will differ on each version.
david @ popuw.com (Tue Aug 29, 2006 9:05 pm) wrote: How to change tile incompatibilities
Offsets: p0:0x1AC3F, u0:0x1C782, p3:0x1B8F3, u3:0x1C4F6, p4:0x17C95, u4:0x18E70
You'll find a table like this:

level
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | tile
00 00 00 00 01 01 01 00 00 00 01 00 00 00 01 00 | lattice (0x1A-0x1D)
00 01 00 01 00 00 00 01 01 00 00 00 01 00 00 00 | skeleton (0x15)
00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 | mirror (0x1D)
00 00 00 00 01 01 01 00 00 00 01 01 00 00 01 00 | tapestry patterns (0x07, 0x0C)
01 00 01 00 00 01 00 00 00 01 01 00 01 01 00 00 | big pillar (0x08-0x09)
01 00 00 01 01 01 01 01 01 01 01 01 00 00 00 00 | chomper (0x12)
01 01 01 01 01 01 01 01 01 01 01 01 01 00 00 00 | spike (0x02)
00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 00 | big window (0x17-0x18)

If a byte is 01, the tile can appear on the level, if 00 then it can't.

Note: in compressed versions, some parts of this table are compressed, so it's difficult to edit.
htamas
Efendi
Efendi
Posts: 10
Joined: February 22nd, 2009, 7:49 pm

Re: Modifications to prince.exe (hex editing)

Post by htamas »

htamas @ popuw.com (Tue Aug 29, 2006 11:11 pm) wrote:
poirot wrote: I was thinking about the dungeon wall generating algorithm, I've coded it for FP, and understood how it works, but there is a seed that the game uses and I think it is saved inside the game. The seeds I extracted from the game (just looking on the images and not the code) are in http://cvs.lug.fi.uba.ar/cgi-bin/cvsweb ... freeprince

The algorithm is in the format specifications http://cvs.lug.fi.uba.ar/cgi-bin/cvsweb ... freeprince

I was thinking if it is possible to find the offsets of this seeds. There are four different types of 63 different wall blocks. Each block has modifiers like the position of the middle separator, etc. The four types are called SWS, WWS, SWW, WWW (where the middle W is the wall and the S is empty space).

I'd like to know if it is possible to find those offsets and see how and where they are saved in the game. They could be very interesting to edit ;)
Finally, I've finished with reverse engineering the dungeon wall drawing algorithm. It's not at all that simple ;). The core of it is a PRNG (pseudorandom number generator) which is seeded with the sum of the room number and the tile number so that it will be deterministic. Note that there is a glitch in the PRNG routine that still allows undeterministic behaviour with a small probability.

(I'm providing the reversed code as c-style pseudocode, but I favour easy understanding opposed to formal precision, so it'll contain some non-existing c keywords and won't compile. Variable and function names from the original code are lost and I had to name them. They are quite often unmeaningful and perhaps they can even be misleading.)

First, here is how the PRNG works:

Code: Select all

global dword gl_prng_state = 0;

word random (word max) {
  if (gl_prng_state == 0) {
    gl_prng_state = get_pit_timer();
    // the PIT (Programmable Interval Timer) gives the number of ticks
    // since power on, where 1 second equals approximately 18.2 ticks
  }
  gl_prng_state = gl_prng_state * 214013 + 2531011;
  return (word)(gl_prng_state >> 16) % (max + 1);
}
Here you see that if the state changes to zero as a result of fetching a random number, the next time it will be randomized based on the current time. Since it has a "probability" of 1/2^32, we can just ignore this effect (I've added the quotes since gl_prng_state is set to a number between 1 (1+0) and 53 (24+29) and only a quite small amount of random numbers is fetched, so we could check whether this theoretical problem has any practical effect).

Now let's get on to how the screen is drawn. Screen output is buffered twice, therefore when the sprites are put out, still nothing is visible on screen. PoP1 has two sprite reference arrays, respectively called BackTable and ForeTable (names found from the error messages in the strings section ;)), which both can contain 200 entries. (There is a third table called MidTable, and perhaps some others, but they are irrelevant from the point of the wall drawing algorithm.) An entry is composed of 7 bytes, each having a separate meaning:

T[0] and T[1] determine the x coordinate of the top left corner of the sprite. The x coordinate is calculated as 8 * T[0] + T[1]. It is separated in 2 parts because a value from 0 to 319 can't fit into a single byte. To simplify talking about that, I'll refer to T[0] as the 8x coordinate and T[1] as the 1x coordinate.

T[2] is the y coordinate of the top left corner of the sprite. The origin is the top left corner of the screen as per vga specifications. (Note that PoP1 works with a number of different graphics adapters, and the wall drawing algorithm is slightly different on each. Just start prince.exe in dosbox with each of the -machine hercules, -machine cga, -machine tandy and -machine vga options and note the differences. Palace WDA is only available in vga mode. Corner marks are only available from tandy upwards and only in dungeon levels. Hercules has even random blocks missing. Not to mention that vga uses vdungeon/vpalace.dat, ega uses edungeon/epalace.dat and cga uses cdungeon/cpalace.dat. I don't know about the others. In the rest of this post, I'll concentrate on the vga adapter, perhaps with some side notes about the others.)

T[3] is unused and I haven't got any clues about its functionality

T[4] is the resource set to use, it is used to index an array of memory locations that will give us the array of resources in that resource set. It can apparently have the values 0, 1, 2, 5, 6 and 7, and perhaps some more. Resource set 0 contains the sword fighting animations, 1 contains the torch flame, the sword on the floor and the potions, 5 contains the guard resources and 7 contains the wall tiles. Others are either stored in some different format (2-colour bitmaps) or were unloaded at the moment I've checked. This value probably corresponds to the palette to use, chosen from the ones mentioned in one of my previous posts.
I've defined this symbolic constant to refer to the wall resource set:

Code: Select all

#define RSET_WALL              7
T[5] contains the number of the resource in that resource set. For the wall set, it can have the following values:

Code: Select all

#define RES_WALL_FACE_MAIN     1    (face stack main.bmp)
#define RES_WALL_FACE_TOP      2    (face stack top.bmp)
#define RES_WALL_CENTRE_BASE   3    (centre stack base.bmp)
#define RES_WALL_CENTRE_MAIN   4    (centre stack main.bmp)
#define RES_WALL_RIGHT_BASE    5    (right stack base.bmp)
#define RES_WALL_RIGHT_MAIN    6    (right stack main.bmp)
#define RES_WALL_SINGLE_BASE   7    (single stack base.bmp)
#define RES_WALL_SINGLE_MAIN   8    (single stack main.bmp)
#define RES_WALL_LEFT_BASE     9    (left stack base.bmp)
#define RES_WALL_LEFT_MAIN    10    (left stack main.bmp)
#define RES_WALL_DIVIDER1     11    (divider01.bmp, the broad divider)
#define RES_WALL_DIVIDER2     12    (divider02.bmp, the narrow divider)
#define RES_WALL_RNDBLOCK     13    (random block.bmp)
#define RES_WALL_MARK_TL      14    (mark01.bmp, top left mark)
#define RES_WALL_MARK_BL      15    (mark02.bmp, bottom left mark)
#define RES_WALL_MARK_TR      16    (mark03.bmp, top right mark)
#define RES_WALL_MARK_BR      17    (mark04.bmp, bottom right mark)
T[6] is the blitting mode that specifies how the sprite is put on the screen. The following values have a special meaning:

Code: Select all

#define BLIT_NO_TRANS          0
#define BLIT_OR                2
#define BLIT_XOR               3
#define BLIT_BLACK             9
#define BLIT_TRANS            16
BLIT_NO_TRANS means to copy the sprite to the screen as-is, withour transparency, meaning that colours of index 0 will become black. BLIT_TRANS copies with transparency, so a pixel value of 0 will be skipped and will keep the background pixel there. BLIT_OR applies the bitwise "or" operation and is used when painting the tapestry top tiles. BLIT_XOR similarly applies the bitwise "xor" operation. I'm unaware of any location where it is used. BLIT_BLACK will skip pixel values of 0 as if they were transparent and replaces all other colours to black. It is possible to use any other value for the blitting mode, it is interpreted similarly to BLIT_BLACK, but that number will be used as a palette index instead of black.

The add_sprite function has seven arguments which correspond to these:

Code: Select all

void add_sprite(word discarded, word blitting, word coord_y, word coord_x, word coord_8x, word resource, word set);
Besides the fact that the order of the arguments is changed, there is a significant change. The meaning of the coord_y argument is different, as it refers to the position where the bottom left corner of the image is to be placed. Coordinates are still measured from the top left corner of the screen.

Note that the concept of the add_sprite function is a simplification, as it is always called using a pointer to a function, and the function to which the pointer points is changed between two values. The add_sprite_to_backtable and add_sprite_to_foretable functions add the sprite to the end of the BackTable and ForeTable, respectively, and add_sprite refers to the appropriate one using the current value of the gl_sim global variable (sim stands for sprite insertion method ;)).

There is a second buffer, but that's a plain 320*200 byte array that maps to the screen pixels in a one-to-one way. It is used so that each frame can appear instantaneously. Probably the inversion potion affects the function that copies this buffer to the screen. Before that, when the contents of this buffer is generated, a function is called four times in succession to blit the contents of four resource arrays to the screen. Two of these are the BackTable and the ForeTable (afair, the first and the third, but it should be checked) and there are two others. The MidTable, drawn the second, should contain the kid and guard sprites, but this is again unchecked.

The interesting part of the wall drawing is done by the draw_wall_overlays function. It has two arguments, both are words (16-bit integers) but both can only take the 0 or 1 values. It seems that the two arguments are always equal, or at least always where I've checked. The function is called twice for each wall block, first using 0 as both arguments, then using 1 as both arguments. The first places some sprites into the BackTable while the second places some into the ForeTable. By the time the function is called, the base and main sprites are already in the tables, so this function won't place them there.

The constants used in this function are, in addition to the previously mentioned ones:

Code: Select all

#define GRAPHICS_CGA          1
#define GRAPHICS_HERCULES     2
#define GRAPHICS_EGA          3
#define GRAPHICS_TANDY        4
#define GRAPHICS_VGA          5
#define DESIGN_DUNGEON        0
#define DESIGN_PALACE         1
#define WALL_MODIFIER_SWS     0
#define WALL_MODIFIER_SWW     1
#define WALL_MODIFIER_WWS     2
#define WALL_MODIFIER_WWW     3
Here is the pseudocode for the function:

Code: Select all

void draw_wall_overlays (word arg1, word arg2) {
  // local variables
  dword saved_sim;
  word v2; word v3; word v4; word v5;
  word bg_modifier;
  dword saved_prng_state;
  word is_dungeon;
  // save the value for the sprite insertion method, so that it can be restored
  saved_sim = gl_sim;
  // set the sprite insertion method based on the arguments
  if (arg1 == 0) {
    gl_sim = add_sprite_to_backtable;
  } else {
    gl_sim = add_sprite_to_foretable;
  }
  // save the state of the pseudorandom number generator
  saved_prng_state = gl_prng_state;
  // set the new seed
  gl_prng_state = gl_room_number + gl_tile_number;
  random(1); // fetch a random number and discard it
  is_dungeon = (gl_level_design[gl_level_number] < DESIGN_PALACE);
  if ( (!is_dungeon) && (gl_graphics_mode == GRAPHICS_VGA) ) {
    // I haven't traced the palace WDA
    [...]
  } else {
    v3 = random(1);
    v5 = random(4);
    v2 = random(1);
    v4 = random(4);
    // store the background modifier for the current tile in a local variable
    // apparently, for walls, the modifier stores whether there are adjacent walls
    bg_modifier = gl_background_modifier;
    switch (bg_modifier) {
      case WALL_MODIFIER_WWW:
        if (arg2 != 0) {
          if (random(4) == 0) {
            add_sprite(0, BLIT_NO_TRANS, gl_tile_y - 42, 0, gl_tile_8x, RES_WALL_RNDBLOCK, RSET_WALL);
          }
          add_sprite(0, BLIT_TRANS, gl_tile_y - 21, v5, gl_tile_8x + 1, RES_WALL_DIVIDER1 + v3, RSET_WALL);
        }
        add_sprite(0, BLIT_TRANS, gl_tile_y, v4, gl_tile_8x, RES_WALL_DIVIDER1 + v2, RSET_WALL);
        if (arg2 != 0) {
          if (is_dungeon) {
            if (random(4) == 0) {
              draw_right_mark(v5, random(3));
            }
            if (random(4) == 0) {
              draw_left_mark(v4 - v2, v5 - v3, random(4));
            }
          }
        }
        break;
      case WALL_MODIFIER_SWS:
        if (is_dungeon) {
          if (arg2 != 0) {
            if (random(6) == 0) {
              draw_left_mark(v4 - v2, v5 - v3, random(1));
            }
          }
        }
        break;
      case WALL_MODIFIER_SWW:
        if (arg2 != 0) {
          if (random(4) == 0) {
            add_sprite(0, BLIT_NO_TRANS, gl_tile_y - 42, 0, gl_tile_8x, RES_WALL_RNDBLOCK, RSET_WALL);
          }
          add_sprite(0, BLIT_TRANS, gl_tile_y - 21, v5, gl_tile_8x, RES_WALL_DIVIDER1 + v3, RSET_WALL);
          if (is_dungeon) {
            if (random(4) == 0) {
              draw_right_mark(v5, random(3));
            }
            if (random(4) == 0) {
              draw_left_mark(v4 - v2, v5 - v3, random(3));
            }
          }
        }
        break;
      case WALL_MODIFIER_WWS:
        if (arg2 != 0) {
          add_sprite(0, BLIT_TRANS, gl_tile_y - 21, v5, gl_tile_8x + 1, RES_WALL_DIVIDER1 + v3, RSET_WALL);
        }
        add_sprite(0, BLIT_TRANS, gl_tile_y, v4, gl_tile_8x, RES_WALL_DIVIDER1 + v2, RSET_WALL);
        if (arg2 != 0) {
          if (is_dungeon) {
            if (random(4) == 0) {
              draw_right_mark(v5, random(1) + 2);
            }
            if (random(4) == 0) {
              draw_left_mark(v4 - v2, v5 - v3, random(4));
            }
          }
        }
        break;
    }
    gl_prng_state = saved_prng_state;
    gl_sim = saved_sim;
  }
There are two helper functions, draw_left_mark and draw_right_mark, called. Here is their pseudocode:

Code: Select all

void draw_left_mark (word arg1, word arg2, word arg3) {
  word lv1; word lv2;
  const word LPOS[5] = {58, 41, 37, 20, 16};
  lv1 = RES_WALL_MARK_TL;
  lv2 = 0;
  if (arg3 % 2) {
    lv1 = RES_WALL_MARK_BL;
  }
  if (arg3 > 3) {
    lv2 = arg1 + 6;
  } else if (arg3 > 1) {
    lv2 = arg2 + 6;
  }
  add_sprite(0, BLIT_TRANS, gl_tile_y - LPOS[arg3], lv2, gl_tile_8x + ((arg3 == 2)|(arg3 == 3))?1:0, lv1, RSET_WALL);
}

void draw_right_mark (word arg1, word arg2) {
  word rv;
  const word RPOS[4] = {52, 42, 31, 21};
  rv = RES_WALL_MARK_TR;
  if (arg2 % 2) {
    rv = RES_WALL_MARK_BR;
  }
  if (arg2 < 2) {
    arg1 = 24;
  } else {
    arg1 -= 3;
  }
  add_sprite(0, BLIT_TRANS, gl_tile_y - RPOS[arg2], arg1, gl_tile_8x + (arg2 > 1)?1:0, rv, RSET_WALL);
}
That should be enough to recreate the dungeon WDA so that it produces identical results to PoP1. If it would help with your testing, I can send you dumps of the BackTable and ForeTable for any room in any level. Note that these tables contain non-wall elements as well, but filtering with RSET_WALL almost reduces them to the interesting ones.
poirot wrote: great, it's the same order I use in freeprince Wink except for the wall separators, I don't draw them twice.
I've just noticed that in freeprince, the wall dividers aren't placed on the wall bases that are in the top 3 pixels of the screen (parts of walls on the screen above), though they should be placed there. Probably that's why.
jalal wrote: htamas: Is there a way not to reduce the "time left" to 15 minutes and to block in level 4 if we are playing normally (Shift-L) with no cheats...?
Yes, there is:

Changing the effect of Shift+L in non-cheat mode:

Code: Select all

0e66:0658    83 3e 9e 0f 03       cmp word ptr [0f9e], 0003
0e66:065d    7e 0a                jle 0669

0e66:0694    a1 9e 0f             mov ax, [0f9e]
0e66:0697    40                   inc ax
0e66:0698    a3 18 3d             mov [3d18], ax
0e66:069b    83 3e 9c 00 00       cmp word ptr [009c], 0000
0e66:06a0    75 13                jne 06b5
0e66:06a2    83 3e 7e 4f 0f       cmp word ptr [4f7e], 000f
0e66:06a7    7e 0c                jle 06b5
0e66:06a9    c7 06 7e 4f 0f 00    mov word ptr [4f7e], 000f
0e66:06af    c7 06 82 4f cf 02    mov word ptr [4f82], 02cf
0e66:06b5    9a 14 72 df 1a       call 1adf:7214
This is a multi-part hack.

Search for: 83 3e .. .. 03 7e .. 83 3e .. .. 00 75 .. e9 .. ..
(offsets are p0:0x00858, u0:0x01f08, p3:0x00951, u3:0x01091, p4:0x00915, u4:0x01a45)
and replace
03 with the number of the last level where skipping with Shift+L is allowed

Search for: a1 .. .. 40 a3 .. .. 83 3e .. .. 00 75 .. 83 3e .. .. 0f 7e .. c7 06 .. .. 0f 00 c7 06 .. .. cf 02
(offsets are p0:0x00894, u0:0x01f44, p3:0x00978, u3:0x010b8, p4:0x0093c, u4:0x01a6c)
and replace
0f with ## if you want your time to be reduced if you have more than ## minutes
0f 00 with the number of minutes and
cf 02 with the number of seconds of the reduced time
david wrote: How to change tile incompatibilities
Offsets: p0:0x1AC3F, u0:0x1C782, p3:0x1B8F3, u3:0x1C4F6, p4:0x17C95, u4:0x18E70
I really like this table, thanks. These are the resources to be loaded for the level. Back in the time when PoP1 was released, it took some time to read the resources into memory, so they wanted to spare the unnecessary ones. But that's great for modding. I suggest using checkboxes for these ;).
poirot wrote:
htamas wrote: At offset 0x4777, replace
55 8b ec 83 ec 44 56 c7 46 fa 00 00 c7 46 fc 0f 00 b8 01 00 50
with
83 3e 9e 0f xx 75 08 2b c0 50 9a 7a 0c df 1a 9a 14 72 df 1a cb
where xx is the level after which you would like to quit.

Also, at offset 0x65ff, replace 14 72 79 0c with d7 09 4f 02.

Reading your question, I assume that you would like to minimize the impact of the original story on your levels. You can also quit when time expires and you can disable the cutscenes.

Quitting when time expires: at offset 0x2261, replace 94 0c 4f 02 with 7a 0c df 1a
(note: you won't see the scene with the hourglass in the princess' room when the time expires)

The table of cutscenes is starting at offset 0x1d530. For each level, 4 bytes is used. Note that these are offset:segment values, so you might not just write anything there, but you may swap them or disable them by writing 00 00 00 00. (Note that for levels starting from 3, the princess is animated, while before that, Jaffar is animated, if applicable. It's quite strange, but you'll see if you try it. So you should avoid swapping one before 3 to one after 2.)
What version are those offsets for? do you have the offsets for the other versions (I'm interested especially in the cutscenes, because it is very difficult to find an hex string because it will differ on each version.
These are for the unpacked 1.0 version. I'll try to look after the other versions.

P.S.: I won't be at home between Thursday, 31 August and Saturday, 3 September, so I won't answer (neither ask) any questions then.
  • 89 messages have been lost
Eagle-Head Priest(97) @ popuw.com (Thu Jul 12, 2007 3:17 pm) wrote:
poirot wrote: I have improved a bit the custom pop generator at http://www.princed.org/cuspop.jsp.

- The xml cached information works faster.
- The hidden form information is now less than before making the download faster for slow connections.
- Coded the "string type support" and
- Added File renaming fields,
- Added pop translation fields.
- Fixed very important bug in the JavaScript validator.
- The JavaScript validator code is now smaller.
- Added the help attribute to folders in the xml.
- Improved the xml dtd specification to support strings and the new help attribute.
Now I can't even try to use it. Where I'm able to change the guards on each level, I can't choose, nor on where the resources (like having chompers, etc.) are. Why?
Eckolin2 @ popuw.com (Mon Jul 16, 2007 3:32 pm) wrote: Those modifications are not supported in the packed versions.

Question to the hex editors... When I come across a call like 0123:0009, does the code continue at 123*10 + 0009 = 1239h or do I need to add an offset like with the jumps?
poirot @ popuw.com (Mon Jul 16, 2007 4:16 pm) wrote:
Eckolin2 wrote: Question to the hex editors... When I come across a call like 0123:0009, does the code continue at 123*10 + 0009 = 1239h or do I need to add an offset like with the jumps?
In my case I use turbo debugger to see the assembler instructions but I also have a disassembled version of prince.exe in text format to see the jumps in absolute mode. After finding what I want to edit, to get the offset I use http://www.princed.org/cusasm.jsp with the pasted turbo debugger line (click show me an example to see the format) to get a list of all the offsets in each pop versions. The output is in this forum format and an XML to append it to cuspop.

Last edited by poirot on Sun Oct 07, 2007 3:51 am; edited 1 time in total
mk1994 @ popuw.com (Tue Aug 21, 2007 5:11 pm) wrote: I have a quick question: Is it possible, that you could edit the hit points like this:

At the start of level 1, you have a maximum of three hitpoints, but only one hitpoint filled.

Is this possible, impossible or just way too hard?
Eckolin2 @ popuw.com (Wed Aug 29, 2007 4:59 pm) wrote: That is possible and relatively easy.
mk1994 @ popuw.com (Wed Aug 29, 2007 6:12 pm) wrote:
Eckolin2 wrote: That is possible and relatively easy.
Really? What code do I have to edit?
Eckolin2 @ popuw.com (Wed Aug 29, 2007 9:12 pm) wrote: The code around

00006603 a1 f2 5f MOV AX, [5ff2]
00006606 a3 08 46 MOV [4608], AX

looks promising.

I think you could change

a1 f2 5f a3 08 46

into

c6 06 08 46 01 90

to have one hitpoint out of the max by default.

Unfortunately I currently work 9-10 hours a day and have no time for a full investigation. :(
mk1994 @ popuw.com (Wed Aug 29, 2007 9:27 pm) wrote:
Eckolin2 wrote: The code around

00006603 a1 f2 5f MOV AX, [5ff2]
00006606 a3 08 46 MOV [4608], AX

looks promising.

I think you could change

a1 f2 5f a3 08 46

into

c6 06 08 46 01 90

to have one hitpoint out of the max by default.

Unfortunately I currently work 9-10 hours a day and have no time for a full investigation. :(
Hopefully, this is for the first level, only!
Butcher @ popuw.com (Wed Aug 29, 2007 9:46 pm) wrote: Anyone here know how to uncrack the generated executables that CusPop does?

I'm asking about that because I will release my "Príncipe da Pérsia", the portuguese version soon and I would like to release the three executables (1.0/1.3/1.4) both cracked and uncracked.

And I needed to do some hex-editting here because CusPOP can't allow you change the texts from the Potion Level. You know. "Drink the..." ;)

And I did a new topic here asking about the font used in the 'game name.bmp' but I think the font is not available as I think Jordan Mechner drew the Pop title by hand.

Thanx.
mk1994 @ popuw.com (Wed Aug 29, 2007 10:18 pm) wrote: :arrowu: Use a hex-editor. A REAL one, I mean.
Butcher @ popuw.com (Wed Aug 29, 2007 11:01 pm) wrote: Well, mk1994, if you would like to see an awesome REAL hex-editor you could check the X-Ways WinHex. :twisted: 8-)

http://www.x-ways.net/

Or I don't know, Norton Disk Editor?

What I'm asking for is what I need to search and change in the executables to uncrack the games. Any clue? ;)
mk1994 @ popuw.com (Thu Aug 30, 2007 10:39 am) wrote: Well, I prefer Cygnus Hex-editor. Just jump to the very first page of this topic and you see some hex-editors.
Eckolin2 @ popuw.com (Fri Aug 31, 2007 5:48 pm) wrote: Just tried the hack. It gives you a max of 1 hp starting from level 2. :S Oh well.
david @ popuw.com (Fri Aug 31, 2007 6:29 pm) wrote: I think you should add this: Modifying the number of hit points of the Prince on demo level
to the Custom prince.exe generator.
I remember that someone asked for this.
poirot @ popuw.com (Fri Aug 31, 2007 10:16 pm) wrote: it had already been added under the "Section level specific events" cathegory; first item.
mk1994 @ popuw.com (Sat Sep 01, 2007 8:50 am) wrote:
poirot wrote: it had already been added under the "Section level specific events" cathegory; first item.
Where? I don't find it! Well, I KNOW, it is in CusPoP, but it isn't the first item.
poirot, I think, you have to update it!
programmer @ popuw.com (Sat Sep 01, 2007 7:30 pm) wrote: Read what poirot wrote.
He said that it is the first in that category, not at the entire site..
mk1994 @ popuw.com (Sun Sep 02, 2007 9:41 am) wrote: But the first item is the customation for the demo prince's hit points...! :?:
Eagle-Head Priest(97) @ popuw.com (Sun Sep 02, 2007 1:58 pm) wrote: I guess you need help?
programmer @ popuw.com (Sun Sep 02, 2007 6:36 pm) wrote:
But the first item is the customation for the demo prince's hit points...!
....

I think you should add this: Modifying the number of hit points of the Prince on demo level
to the Custom prince.exe generator.
I remember that someone asked for this.
it had already been added under the "Section level specific events" cathegory; first item.
Where? I don't find it! Well, I KNOW, it is in CusPoP, but it isn't the first item.
poirot, I think, you have to update it!
Read what poirot wrote.
He said that it is the first in that category, not at the entire site..
But the first item is the customation for the demo prince's hit points...!
poirot @ popuw.com (Fri Sep 07, 2007 2:38 am) wrote: mk1994: read first, ask later!
programmer: thanks!
Butcher @ popuw.com (Sat Sep 15, 2007 9:21 pm) wrote: Is there an way to disable the text when entering the potions level and disable the potions that are placed?
mk1994 @ popuw.com (Sun Sep 16, 2007 6:55 am) wrote:
Butcher wrote: Is there an way to disable the text when entering the potions level and disable the potions that are placed?
Jalal once made a MOD for the potions level, where it was not called: "Drink potion with the first letter of the blablabla word in the blablabla line of the blablabla page in the manual."
but: "Drink potion, labeled blablabla."
You should search through the forum to find this. But it could be on the unofficial website, too. I'm not sure. Or PM him.
david @ popuw.com (Wed Sep 19, 2007 6:50 pm) wrote:
mk1994 wrote: Jalal once made a MOD for the potions level, where it was not called: "Drink potion with the first letter of the blablabla word in the blablabla line of the blablabla page in the manual."
but: "Drink potion, labeled blablabla."
"Drink the potion labelled A."
It's here: http://www.popuw.com/forum/viewtopic.php?t=2111
poirot @ popuw.com (Thu Sep 20, 2007 3:39 pm) wrote: When I have the time, I'll try to add it to cuspop
poirot @ popuw.com (Sat Sep 22, 2007 7:41 pm) wrote:
mk1994 wrote:
poirot wrote: it had already been added under the "Section level specific events" cathegory; first item.
Where? I don't find it! Well, I KNOW, it is in CusPoP, but it isn't the first item.
poirot, I think, you have to update it!
I think you misunderstood what I've said. This answer was for David's post (see it above), and was exactly about the number of hit points in the demo level.

I don't know what you were expecting to find in CusPOP. What is it?
mk1994 @ popuw.com (Sat Sep 22, 2007 7:43 pm) wrote:
poirot wrote:
mk1994 wrote:
  • poirot wrote:
    it had already been added under the "Section level specific events" cathegory; first item.
Where? I don't find it! Well, I KNOW, it is in CusPoP, but it isn't the first item.
poirot, I think, you have to update it!
I think you misunderstood what I've said. This answer was for David's post (see it above), and was exactly about the number of hit points in the demo level.

I don't know what are you expecting to find in CusPOP. What is it?
Oh, that's all the reason! I thought, you updated it and made this kind of "being weakened at the beginning of a level"-thing.
You just made a riddle of it! And it was hard to solve!!! :x
poirot @ popuw.com (Sat Sep 22, 2007 7:47 pm) wrote: lol, I'll see what I can do about the "being weakened at the beginning of a level"-thing.
mk1994 @ popuw.com (Sat Sep 22, 2007 7:59 pm) wrote:
poirot wrote: lol, I'll see what I can do about the "being weakened at the beginning of a level"-thing.
Thank you!
  • further messages written after Nov 10, 2007 may have been lost
User avatar
mickey96
Beylerbey
Beylerbey
Posts: 70
Joined: November 29th, 2008, 2:19 pm
Location: Nairobi, Kenya
Contact:

Re: Modifications to prince.exe (hex editing)

Post by mickey96 »

I have those lost posts. It's rared and it is roughly 5mb.
Go here for the link: viewtopic.php?f=67&t=561&p=3125#p3125 :lol:

(I have also POP2 hacks but they may have been lost)
Refueled my car! Now I can keep going!
David
The Prince of Persia
The Prince of Persia
Posts: 2848
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Modifications to prince.exe (hex editing)

Post by David »

Force blind mode

Code: Select all

00004E42: C706C24C0000   mov [+4CC2],0000
search:
C7 06 C2 4C 00 00 (1.0)
C7 06 B2 4E 00 00 (1.3)
C7 06 86 4C 00 00 (1.4)

offsets:
p0: 0x4e42, u0: 0x64f2, p3: 0x52ca, u3: 0x5a0a, p4: 0x4d86, u4: 0x5eb6

change: 00 00 -> 01 00
David
The Prince of Persia
The Prince of Persia
Posts: 2848
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Modifications to prince.exe (hex editing)

Post by David »

Positions of the shadow

Code: Select all

F  X  Y  D  C  R  A
0F 51 76 00 00 01 00 00 | level 6
0F 37 37 00 FF 00 00 00 | level 5
0F 51 E8 00 00 00 00 00 | level 12

F=frame (will be overridden)
X=x coordinate
Y=y coordinate
D=direction (00=right, FF=left)
C=column (not really used)
R=row (used only for collision detection)
A=action
offsets:
u0: 0x1d47a, u3: 0x1d36c, u4: 0x19d16
Note: in the packed versions, the end of the last entry is compressed.
p0: 0x1b8b8, p3: 0x1c6d5, p4: 0x18aa7


Automatic moves

For each line: (of course, the 2-byte numbers are written in reverse byte order)
first 2 bytes: time (in ticks, I guess)
second 2 bytes: action, see below
actions:
0=release all keys
1=forward
2=backward
3=up
4=down
5=jump forward (forward+up)
6=press shift
7=release shift
FFFE=end?
FFFF=end

Shadow's moves on level 5:

Code: Select all

00 00 00 00
01 00 01 00
0E 00 00 00
12 00 06 00
1D 00 07 00
2D 00 02 00
31 00 01 00
FF 00 FE FF
offsets:
u0: 0x1d492, u3: 0x1d384, u4: 0x19d2e
Note: in the packed versions, the first action (first line, with the four zeroes) is compressed, so I'll give the address of the second action.
p0: 0x1db82, p3: 0x1c6ef, p4: 0x18ac1

Prince's moves on demo level:

Code: Select all

00 00 00 00
01 00 01 00
0D 00 00 00
1E 00 01 00
25 00 05 00
2F 00 00 00
30 00 01 00
41 00 00 00
49 00 02 00
4B 00 00 00
63 00 02 00
64 00 00 00
73 00 05 00
80 00 06 00
88 00 03 00
9D 00 07 00
9E 00 00 00
9F 00 01 00
AB 00 04 00
B1 00 00 00
B2 00 01 00
BC 00 00 00
C1 00 01 00
CD 00 00 00
E9 00 FF FF
offsets:
u0: 0x1d4b2, u3: 0x1d3a4, u4: 0x19d4e, p0: 0x1b8ee, p3: 0x1c70b, p4: 0x18add
Last edited by David on June 14th, 2020, 9:19 pm, edited 1 time in total.
Reason: Clarified the headings.
User avatar
Norbert
The Prince of Persia
The Prince of Persia
Posts: 5745
Joined: April 9th, 2009, 10:58 pm

Re: Modifications to prince.exe (hex editing)

Post by Norbert »

Nice. :)

Does 00 (release all keys) also includes a pause?
For 0.5 seconds?
David
The Prince of Persia
The Prince of Persia
Posts: 2848
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Modifications to prince.exe (hex editing)

Post by David »

I don't think so. Timing is controlled by the left column.
User avatar
Norbert
The Prince of Persia
The Prince of Persia
Posts: 5745
Joined: April 9th, 2009, 10:58 pm

Re: Modifications to prince.exe (hex editing)

Post by Norbert »

I've created a (GNU/Linux) shell script that can be used to test custom Prince of Persia 1 demo levels.
Might also be useful for other people, so I'm posting it on this forum.

Code: Select all

# demo.sh
#
# This shell script can be used to test
# custom Prince of Persia 1 demo levels.
#
# Relies on xdotool.
#
# Can be tested with:
# http://www.popot.org/custom_levels/software/DEMO.zip
# IMPORTANT: When you're using the above ZIP file, make
# sure the prince starts in the correct 'demo level'
# position by jumping up once and then turning right.

function usleep {
	sleep $(echo "scale = 10; $1"|bc)
}

FORWARD=Left
BACKWARD=Right
UP=Up
DOWN=Down
SHIFT=Shift_L
FPS=12

WINDOWID=`xdotool search --title "DOSBox"`
xdotool windowactivate $WINDOWID
sleep 1

usleep 1/$FPS                # 00 00 (000) to 01 00 (001)
xdotool keydown $FORWARD     # 01 00
usleep 12/$FPS               # 01 00 (001) to 0D 00 (013)
xdotool keyup $FORWARD       # 00 00
usleep 17/$FPS               # 0D 00 (013) to 1E 00 (030)
xdotool keydown $FORWARD     # 01 00
usleep 7/$FPS                # 1E 00 (030) to 25 00 (037)
xdotool keydown $FORWARD     # 05 00
xdotool keydown $UP          # (same)
usleep 10/$FPS               # 25 00 (037) to 2F 00 (047)
xdotool keyup $FORWARD       # 00 00
xdotool keyup $UP            # (same)
usleep 1/$FPS                # 2F 00 (047) to 30 00 (048)
xdotool keydown $FORWARD     # 01 00
usleep 17/$FPS               # 30 00 (048) to 41 00 (065)
xdotool keyup $FORWARD       # 00 00
usleep 8/$FPS                # 41 00 (065) to 49 00 (073)
xdotool keydown $BACKWARD    # 02 00
usleep 2/$FPS                # 49 00 (073) to 4B 00 (075)
xdotool keyup $BACKWARD      # 00 00
usleep 24/$FPS               # 4B 00 (075) to 63 00 (099)
xdotool keydown $FORWARD     # 02 00 (start $BACKWARD)
usleep 1/$FPS                # 63 00 (099) to 64 00 (100)
xdotool keyup $FORWARD       # 00 00 (end $BACKWARD)
usleep 15/$FPS               # 64 00 (100) to 73 00 (115)
xdotool keydown $FORWARD     # 05 00
xdotool keydown $UP          # (same)
usleep 13/$FPS               # 73 00 (115) to 80 00 (128)
xdotool keydown $SHIFT       # 06 00
usleep 8/$FPS                # 80 00 (128) to 88 00 (136)
xdotool keydown $UP          # 03 00
usleep 21/$FPS               # 88 00 (136) to 9D 00 (157)
xdotool keyup $SHIFT         # 07 00
usleep 1/$FPS                # 9D 00 (157) to 9E 00 (158)
xdotool keyup $UP            # 00 00
xdotool keyup $FORWARD       # (same)
usleep 1/$FPS                # 9E 00 (158) to 9F 00 (159)
xdotool keydown $FORWARD     # 01 00
usleep 12/$FPS               # 9F 00 (159) to AB 00 (171)
xdotool keydown $DOWN        # 04 00
usleep 6/$FPS                # AB 00 (171) to B1 00 (177)
xdotool keyup $FORWARD       # 00 00
xdotool keyup $DOWN          # (same)
usleep 1/$FPS                # B1 00 (177) to B2 00 (178)
xdotool keydown $FORWARD     # 01 00
usleep 10/$FPS               # B2 00 (178) to BC 00 (188)
xdotool keyup $FORWARD       # 00 00
usleep 5/$FPS                # BC 00 (188) to C1 00 (193)
xdotool keydown $FORWARD     # 01 00
usleep 12/$FPS               # C1 00 (193) to CD 00 (205)
xdotool keyup $FORWARD       # 00 00
usleep 28/$FPS               # CD 00 (205) to E9 00 (233)
echo "Ready!"                # FF FF
David
The Prince of Persia
The Prince of Persia
Posts: 2848
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Modifications to prince.exe (hex editing)

Post by David »

There is a way to start immediately on the demo level.
Hex-edit prince.sav so that offsets 4 and 5 contain 0xFF. After this, pressing Ctrl-L on the title screen will load the demo level.
This will play the hardcoded moves unless prince.exe was hacked to make the demo level playable.
User avatar
robert
Sultan
Sultan
Posts: 194
Joined: August 27th, 2011, 7:16 pm
Location: Argentina

Re: CusPop TODO list

Post by robert »

Nice compilation! ;)

I have a doubt, what's the difference between "packed" and "unpacked" that mentions in Cuspop?
Last edited by robert on May 19th, 2013, 7:21 pm, edited 2 times in total.
Image
This will be my face if you can't win any of my mods
User avatar
Norbert
The Prince of Persia
The Prince of Persia
Posts: 5745
Joined: April 9th, 2009, 10:58 pm

Re: CusPop TODO list

Post by Norbert »

robert wrote:Nice compilation! ;)

I have a doubt, what's the difference between "packed" and "unpacked" that mentions in Cuspop?
See:
- viewtopic.php?p=9268#p9268
- viewtopic.php?p=11235#p11235
- http://www.popot.org/other_useful_tools ... ack_unpack
User avatar
robert
Sultan
Sultan
Posts: 194
Joined: August 27th, 2011, 7:16 pm
Location: Argentina

Re: CusPop TODO list

Post by robert »

Norbert wrote:
robert wrote:Nice compilation! ;)

I have a doubt, what's the difference between "packed" and "unpacked" that mentions in Cuspop?
See:
- viewtopic.php?p=9268#p9268
- viewtopic.php?p=11235#p11235
- http://www.popot.org/other_useful_tools ... ack_unpack
Ok! Thanks!

Some ideas:

1) What about making possible to have more than one exit in one level? Because opening another exit door after opening the first makes the game act weird.

2) And making possible a room not to have a celling whenever there is no room above? If it's confusing what I'm saying (because of my english :? ), think about the level editor of snes version, if you select 254 above a room there will be no celling.

3) What if I want the rescue level (or prince level 14) to still have time running? Because some mods have the vizier in level 14... (and to see the text "LEVEL 14" below?)
Image
This will be my face if you can't win any of my mods
David
The Prince of Persia
The Prince of Persia
Posts: 2848
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: CusPop TODO list

Post by David »

robert wrote: 2) And making possible a room not to have a celling whenever there is no room above? If it's confusing what I'm saying (because of my english :? ), think about the level editor of snes version, if you select 254 above a room there will be no celling.
To remove the floors from the top of the room:

Code: Select all

seg008:03C1		    mov	    [bp+var_2],	14h
seg008:03C6		    cmp	    drawn_row, 2
seg008:03CB		    jnz	    loc_9FF2
seg008:03CD		    mov	    [bp+var_2],	1

Code: Select all

0000A1E1:iC746FE1400                     mov       [bp-02],0014
0000A1E6:i833E344302                     cmp (w)   [+4334],+02
0000A1EB:i7505                           jne       file:0000A1F2
0000A1ED:iC746FE0100                     mov       [bp-02],0001
search: 75 05 C7 46 FE 01 00 , replace 01 with 00

Note that this will affect only the drawing. (Just like Room 254 in SNES: the wall stays there, but you can't see it, and you usually can't reach it.)
If you want the top of the level to behave as an empty space, you will also need the following:

To make the top and left edges of the level behave as empty:

Code: Select all

seg006:004E		    mov	    curr_tile2,	14h ; wall

Code: Select all

00006EFE:iC606F94214                     mov       [+42F9],14
search: C6 06 F9 42 14 , replace 14 with 00
Note that this will also change the left edge of the level to empty, but only the behaviour, and not the drawing.
If you also want the left edge to be drawn as empty, you need this:

To remove the wall from the left of the room:

Code: Select all

seg008:0446		    add	    ax,	offset byte_1F9B9
seg008:0449		    push    ax
seg008:044A		    mov	    ax,	14h
...
seg008:04E1		    mov	    ax,	5951h
seg008:04E4		    push    ax
seg008:04E5		    mov	    ax,	14h

Code: Select all

0000A266:i05D94C                         add       ax,4CD9
0000A269:i50                             push      ax
0000A26A:iB81400                         mov       ax,0014
...
0000A301:iB85159                         mov       ax,5951
0000A304:i50                             push      ax
0000A305:iB81400                         mov       ax,0014
search: 05 D9 4C 50 B8 14 00 , replace 14 with 00
search: B8 51 59 50 B8 14 00 , replace 14 with 00
David
The Prince of Persia
The Prince of Persia
Posts: 2848
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: CusPop TODO list

Post by David »

robert wrote: 1) What about making possible to have more than one exit in one level? Because opening another exit door after opening the first makes the game act weird.
To disable entering a closed level door:

Code: Select all

seg005:04A2                 cmp     ax, drawn_room
seg005:04A6                 jz      loc_6295
seg005:04A8                 cmp     leveldoor_open?, 0
seg005:04AD                 jz      loc_6295

Code: Select all

00006482:i3B069E40                       cmp       ax,[+409E]
00006486:i740D                           je        file:00006495
00006488:i833E9C4000                     cmp (w)   [+409C],+00 ; <- should check the modifier instead
0000648D:i7406                           je        file:00006495
search: 3B 06 9E 40 74 0D 83 3E 9C 40 00 74 06
replace: 8B 36 88 5F 8A 00 3C 2A 7C 09 90 90 90

To stop the second level door from acting weird:

Code: Select all

seg007:064A                 inc     curr_modifier
seg007:064E                 cmp     curr_modifier, 2Bh ; '+'
seg007:0653                 jb      loc_8BE6
seg007:0655                 cmp     leveldoor_open?, 0
seg007:065A                 jz      loc_8BB3
seg007:065C                 cmp     leveldoor_open?, 2
seg007:0661                 jnz     loc_8BF4

Code: Select all

00008D9A:iFE062843                       inc       [+4328]
00008D9E:i803E28432B                     cmp       [+4328],2B
00008DA3:i7241                           jc        file:00008DE6
00008DA5:i833E9C4000                     cmp (w)   [+409C],+00
00008DAA:i7407                           je        file:00008DB3
00008DAC:i833E9C4002                     cmp (w)   [+409C],+02
00008DB1:i7541                           jne       file:00008DF4
search: 83 3E 9C 40 00 74 07 , change 74 to EB
User avatar
robert
Sultan
Sultan
Posts: 194
Joined: August 27th, 2011, 7:16 pm
Location: Argentina

Re: CusPop TODO list

Post by robert »

Great info! It should be added to cuspop
Image
This will be my face if you can't win any of my mods
Post Reply