Week 2

At the second week I have done:

  • Fixed formatting
  • Removed C++11 features(lambdas, auto, extended initializer lists)
  • Fixed unsigned vs signed comparison
  • Found and fixed bug in ScummVm’s hashmap
  • Added improved pause support
  • Added saving system (currently without metadata)

The most interesting was fixing the bug in Hashmap. At first,  I thought that this was problem with my code. Experimented with code and noticed that calling clear with true parameter causes this bug. So I looked at clear method implementation(Line 4):

 

And this part of HashMap constructor(Line 1):

Simple mistake, which was easily fixed

Pink Scripts Format

In Pink engine scripts are stored as serialized objects.

Let’s look at Wanderlust logo’s script

 

The execution starts from HandlerStartPage. The last Handler is unnecessary.

Firstly, Handler executes SideEffectExit, which sets next executors.

Then, Handler starts sequence.

The sequence consists of SequenceItems.

SequenceItem – sets action to actor.

SequenceItemLeader  – same as SequenceItem but action which it sets will be used as a mark of script ending. In this example, the script ends when the music ends.

SequenceItemDefaultAction – sets the action to the actor, but only if SequenceItem haven’t executed for that actor.

Also, sequence can consist of two or more subsequences.

The execution is the same, but we stop before next leader while the previous subsequence is playing.

Thanks Douglas for great tool Carbon

Week 1

At the first week I fixed bugs in Pink Panther engine.

 

Not much work was done because I have exams in university.

The games were crashing when decoding some sprites, but at first I thought that it was a problem with my code. I ran the game with Valgrind and found a method which wrote beyond the array. And it was ScummVm’s decoder method. It decoded BYTE_RUN chunk as standard FLC format.

https://github.com/scummvm/scummvm/pull/1190

Next, I fixed sprites which started to play with delay. The problem was in that I decode frames until startFrame, but didn’t take into account the next frame start time. So I added a method which decodes the frame, but didn’t add a frame delay.

https://github.com/whiterandrek/scummvm/commit/7fe6bb2963fe72f8aaaf0697aeb6c9da92aff722

Next week I plan to add the menu to call PDA from it and finish loop sprites which currently are played only forward.

Some gameplay from current version

Reverse Engineering Pink Classes

This post will be about the reversing serialized objects, located in ORB file.They are written in ORB using MFC library.

Firstly, I parsed class names. To do that, I have written simple program in C++.  Each class in Pink starts with letter ‘C’, so program just finds this letter, then reads name as MFC String and checks it for correctness.

I’ve got 48 for Peril and 45 for Pokus.

Secondly, I found out fields names. It was really easy.

When these games were created, developers had program creating the game files. This program wrote data to txt files, but not using MFC serialization, because the game engine has code for executing game from txt files. That’s why each class has virtual method, which writes attribute name and value. For example, CConditionVariable class:

Each class in Pink games can be reversed using this approach.

Pink Files Format

The Pink Panther games use only two data files.

These are ORB and BRO.

 

Structure of ORB file header

1
2
3
4
5
6
7
8
char name[4]; // ORB
uint16 minorVersion;
uint16 majorVersion;
uint32 timestamp;
uint32 tableOffset;
uint32 tableSize;

After header, we will look at the table. It is located at the end of ORB. It contains descriptions of objects. The names in this table are sorted, so the binary search is used for searching.

1
2
3
4
5
6
7
struct ObjectDescription {
    char name[16];
    uint32 objectsOffset;
    uint32 objectsCount;
    uint32 resourcesOffset;
    uint32 resourcesCount;
};

Let’s look at resources table. Each object description has offset to the resource descriptions table.

1
2
3
4
5
6
struct ResourceDescription {
    char name[16];
    uint32 offset;
    uint32 size;
    bool inBro;
};

The last field determines where the resource is located.

BRO file contains only resources and it is only used in Passport to Peril. In Hokus Pokus it is empty.

1
2
3
4
5
6
char name[4]; // BRO
uint16 minorVersion;
uint16 majorVersion;
uint32 timestamp;

The timestamps of BRO and ORB must be equal to each other.