Packs and unpacks game resources for the old DOS game, The Adventures of Robin Hood, by Millenium.
RobinPacker is based on work by the ScummVM team to re-implement the Robin Hood engine.
RobinPacker lives at this address:
http://www.jestarjokin.net/apps/robinpacker
There is a live source code repository and issue tracker available on GitHub:
http://www.github.com/jestarjokin/robinpacker
- Make sure you have the Microsoft Visual C++ 2008 Runtime installed (and make sure it's not SP1!). If not, download and run the installer from Microsoft:
- Download the latest version of RobinPacker from here:
- Extract the files to a directory somewhere
- Run "robinpacker.exe"
- Install Python 2.7. Other versions of Python are not supported!
- Install the following Python packages (I suggest using PIP to do so):
- PyParsing >= 1.5.6
- PIL (Python Imaging Library) >= 1.1.6. Pillow should also work.
- Download the latest version of RobinPacker from here:
- Extract the files to a directory somewhere
- Run "robinpacker.py" from the command line (see the "Usage" section for more info)
To unpack all game files, pass the game directory as the first argument, and the output directory as the second argument.
robinpacker.py -u C:\Games\Robin C:\temp\unpacked
To re-pack the game files, do the following. Note that a "project.json" file must exist.
robinpacker.py -p C:\temp\unpacked C:\temp\repacked
To unpack rules files:
robinpacker.py -u ERULES.prg erules_out.json
To pack rules files:
robinpacker.py -p erules_out.json erules_packed.prg
To convert graphics files to PNG:
robinpacker.py -u AUTUMN.GFX autumn_out.gfx
To convert PNG files back to games graphics:
robinpacker.py -p autumn_out.png autumn_packed.gfx
Scripts are comprised of one or more rules. Each rule looks like the following:
rule "rule-name"
when
<conditionals>
then
<actions>
end
Conditionals are one or more function calls. Each call is separated by the keyword "and". You can negate each conditional by putting "not" at the start.
Actions are also function calls.
Here is an example rule.
rule "erules_out_gameScript_11-rule-01"
when
CurrentCharacterVar0Equals(0x00)
then
callScriptAndReturn(0x3A, characterIndex)
end
There is a special case for rules with no conditionals. Omit the "when" section, and instead of writing the keyword "then", write "always".
rule "rule-name"
always
<actions>
end
Refer to the section Function reference for a list of functions you can use in conditionals or actions.
Comments are written using the hash symbol, #
, and will apply to any text after the hash until the end of the line.
This is similar to comments used in the Python programming language.
# This rule is totally awesome
rule "erules_out_gameScript_11-rule-01"
when # when? WHEN? How about NOW!
CurrentCharacterVar0Equals(0x00) #and
#sub17782(0x2B)
then
callScriptAndReturn(0x3A, characterIndex)
end
- Support for ROBIN.MUS. There's definitely some standard MIDI data in there, but I'm not sure about the structure of the file.
- Separate the rules JSON into more files, maybe one for each logical section extracted.
- Better names for many of the functions in the rules scripts.
- Support for Rome: Pathway to Power (aka Rome: AD 92)
RobinPacker is available from:
https://github.com/jestarjokin/RobinPacker/
Issues/bugs/feature requests can be lodged there.
Feel free to e-mail the author, Laurence Dougal Myers, at jestarjokin@jestarjokin.net
IMMEDIATE_VALUE
This is just an immediate value. Like 43 or 0x23.
GET_VALUE
Possibly a reference, rather than an immediate value. Can be one of the following:
val(IMMEDIATE_VALUE)
getValue1(IMMEDIATE_VALUE)
_word10804
_currentCharacterVariables[6]
_word16F00_characterId
characterIndex
_selectedCharacterId
Values are limited to 16 bits.
POINT_VALUE
A 2-dimensional point, in the format (x, y). Also a few special values available.
(IMMEDIATE_VALUE, IMMEDIATE_VALUE)
(_rulesBuffer2_13[currentCharacter], _rulesBuffer2_14[currentCharacter])
(_vm->_rulesBuffer2_13[IMMEDIATE_VALUE], _vm->_rulesBuffer2_14[IMMEDIATE_VALUE])
_currentScriptCharacterPosition
(characterPositionTileX[IMMEDIATE_VALUE], characterPositionTileY[IMMEDIATE_VALUE])
(characterPositionTileX[_word16F00_characterId], characterPositionTileY[_word16F00_characterId])
(_array10999PosX[currentCharacter], _array109C1PosY[currentCharacter])
(_currentCharacterVariables[4], _currentCharacterVariables[5])
_vm->_rulesBuffer12Pos3[IMMEDIATE_VALUE]
(_characterPositionTileX[_currentCharacterVariables[6]], _characterPositionTileY[_currentCharacterVariables[6]])
_savedMousePosDivided
COMPARE_OPERATION
One of:
<
>
==
COMPUTE_OPERATION
One of:
-
+
*
/
%
=
STRING_REF
This is a reference to a string value.
The string value will appear in the script file; however, in the bytecode this gets translated to an index, to the "strings" array stored in the rules file.
This means strings in the script must exactly match a string in the strings array in the rules file. You cannot define new strings in the script alone.
checkCharacterGoalPos(POINT_VALUE)
comparePos(GET_VALUE, POINT_VALUE)
checkIsoMap3(IMMEDIATE_VALUE)
compareCharacterVariable(GET_VALUE, IMMEDIATE_VALUE, COMPARE_OPERATION, IMMEDIATE_VALUE)
CompareLastRandomValue(COMPARE_OPERATION, IMMEDIATE_VALUE)
getRandom(IMMEDIATE_VALUE)
for(IMMEDIATE_VALUE, IMMEDIATE_VALUE)
compCurrentSpeechId(STRING_REF)
checkSaveFlag()
compScriptForVal(COMPARE_OPERATION, IMMEDIATE_VALUE)
sub174D8(GET_VALUE, GET_VALUE)
CompareCharacterVariables(GET_VALUE, IMMEDIATE_VALUE, COMPARE_OPERATION, GET_VALUE, IMMEDIATE_VALUE)
compareCoords_1(IMMEDIATE_VALUE)
compareCoords_2(GET_VALUE, IMMEDIATE_VALUE)
CompareDistanceFromCharacterToPositionWith(POINT_VALUE, COMPARE_OPERATION, IMMEDIATE_VALUE)
compareRandomCharacterId(GET_VALUE, COMPARE_OPERATION, IMMEDIATE_VALUE)
IsCurrentCharacterIndex(GET_VALUE)
sub175C8(IMMEDIATE_VALUE, GET_VALUE)
sub17640(IMMEDIATE_VALUE, GET_VALUE)
sub176C4(IMMEDIATE_VALUE, GET_VALUE)
compWord10804(GET_VALUE)
sub17766(IMMEDIATE_VALUE)
sub17782(IMMEDIATE_VALUE)
CompareMapValueWith(POINT_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE, COMPARE_OPERATION)
IsCharacterValid(GET_VALUE)
compWord16EFE(IMMEDIATE_VALUE)
AreCurrentCharacterVar0AndVar1EqualsTo(IMMEDIATE_VALUE, IMMEDIATE_VALUE)
CurrentCharacterVar0Equals(IMMEDIATE_VALUE)
checkLastInterfaceHotspotIndexMenu13(IMMEDIATE_VALUE)
checkLastInterfaceHotspotIndexMenu2(IMMEDIATE_VALUE)
CompareNumberOfCharacterWithVar0Equals(IMMEDIATE_VALUE, COMPARE_OPERATION, IMMEDIATE_VALUE)
IsPositionInViewport(POINT_VALUE)
CompareGameVariables(GET_VALUE, GET_VALUE)
skipNextOpcode(IMMEDIATE_VALUE)
CurrentCharacterVar2Equals1()
sub178D2(GET_VALUE, IMMEDIATE_VALUE)
CharacterVariableAnd(GET_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE)
IsCurrentCharacterVar0LessEqualThan(IMMEDIATE_VALUE)
sub1790F(GET_VALUE)
CurrentCharacterVar1Equals(IMMEDIATE_VALUE)
isCurrentCharacterActive()
CurrentCharacterVar3Equals1()
sub1796E(GET_VALUE, IMMEDIATE_VALUE)
checkLastInterfaceHotspotIndex(IMMEDIATE_VALUE, IMMEDIATE_VALUE)
checkSelectedCharacter()
checkDelayedReactivation()
sub179C2(POINT_VALUE)
checkFunctionKeyPressed(IMMEDIATE_VALUE)
checkCodeEntered(IMMEDIATE_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE)
checkViewPortCharacterTarget(GET_VALUE)
setWord18821(GET_VALUE)
ChangeIsoMap(POINT_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE)
startSpeech(STRING_REF)
getComputedVariantSpeech(GET_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE, STRING_REF)
getRotatingVariantSpeech(STRING_REF, IMMEDIATE_VALUE)
startSpeechIfMute(STRING_REF)
getComputedVariantSpeechIfMute(GET_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE, STRING_REF)
startSpeechIfSilent(STRING_REF, IMMEDIATE_VALUE)
ComputeCharacterVariable(GET_VALUE, IMMEDIATE_VALUE, COMPUTE_OPERATION, IMMEDIATE_VALUE)
getRandom_type2(GET_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE)
setCharacterPosition(GET_VALUE, POINT_VALUE)
DisableCharacter(GET_VALUE)
saveAndQuit()
sub17B93(IMMEDIATE_VALUE)
startSpeech5()
resetByte1714E()
deleteSavegameAndQuit()
incScriptForVal()
sub17BA5(GET_VALUE, IMMEDIATE_VALUE, COMPUTE_OPERATION, GET_VALUE, IMMEDIATE_VALUE)
setByte18823(GET_VALUE, IMMEDIATE_VALUE)
callScript(IMMEDIATE_VALUE, GET_VALUE)
callScriptAndReturn(IMMEDIATE_VALUE, GET_VALUE)
setCurrentScriptCharacterPos(POINT_VALUE)
initScriptFor()
sub17AE1(IMMEDIATE_VALUE)
sub17AEE(IMMEDIATE_VALUE)
setWord10804(GET_VALUE)
sub17C0E()
sub17C55(GET_VALUE, GET_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE)
sub17C76(GET_VALUE)
setCurrentCharacter(GET_VALUE)
sub17C8B(IMMEDIATE_VALUE, IMMEDIATE_VALUE)
sub17CA2(IMMEDIATE_VALUE, IMMEDIATE_VALUE)
sub17CB9(IMMEDIATE_VALUE, GET_VALUE, IMMEDIATE_VALUE)
sub17CD1(IMMEDIATE_VALUE, IMMEDIATE_VALUE)
resetWord16EFE()
enableCurrentCharacterScript(IMMEDIATE_VALUE)
IncCurrentCharacterVar1()
sub17D23(IMMEDIATE_VALUE, POINT_VALUE)
sub17E6D(IMMEDIATE_VALUE)
changeCurrentCharacterSprite(IMMEDIATE_VALUE, IMMEDIATE_VALUE)
sub17E99(IMMEDIATE_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE)
sub17EC5(IMMEDIATE_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE)
setCharacterDirectionTowardsPos(POINT_VALUE)
turnCharacterTowardsAnother(GET_VALUE)
sub17F4F(GET_VALUE)
scrollAwayFromCharacter()
skipNextVal(IMMEDIATE_VALUE)
setCurrentCharacterVar6(GET_VALUE)
sub17FDD(IMMEDIATE_VALUE)
setCharacterScriptEnabled(GET_VALUE)
setCurrentCharacterVar2(IMMEDIATE_VALUE)
SetCurrentCharacterVar2ToZero()
setCharacterProperties(GET_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE)
sub1805D(GET_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE)
sub18074(IMMEDIATE_VALUE, IMMEDIATE_VALUE)
setCurrentCharacterDirection(IMMEDIATE_VALUE)
setInterfaceHotspot(IMMEDIATE_VALUE, IMMEDIATE_VALUE)
scrollViewPort(IMMEDIATE_VALUE)
setViewPortPos(POINT_VALUE)
setCurrentCharacterAltitude(IMMEDIATE_VALUE)
sub1817F(IMMEDIATE_VALUE, IMMEDIATE_VALUE)
sub181BB(IMMEDIATE_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE)
sub18213(IMMEDIATE_VALUE)
sub18252(GET_VALUE)
sub18260(GET_VALUE, POINT_VALUE)
CharacterVariableAddOrRemoveFlag(GET_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE)
PaletteFadeOut()
PaletteFadeIn()
loadAndDisplayCUBESx_GFX(IMMEDIATE_VALUE)
setCurrentCharacterVar3(IMMEDIATE_VALUE)
setArray122C1(IMMEDIATE_VALUE)
sub18367()
enableCharacterScript(GET_VALUE, IMMEDIATE_VALUE)
setRulesBuffer2Element(GET_VALUE, IMMEDIATE_VALUE)
setDebugFlag()
setByte14837()
waitForEvent()
disableInterfaceHotspot(IMMEDIATE_VALUE, IMMEDIATE_VALUE)
loadFileAerial()
startSpeechIfSoundOff(STRING_REF)
sub1844A(GET_VALUE, IMMEDIATE_VALUE)
displayNumericCharacterVariable(GET_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE)
displayVGAFile(STRING_REF)
startSpeechWithoutSpeaker(STRING_REF)
displayTitleScreen(IMMEDIATE_VALUE)
initGameAreaDisplay()
displayCharacterStatBar(GET_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE)
initSmallAnim(IMMEDIATE_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE)
setCharacterHeroismBar(GET_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE)
sub18690(GET_VALUE, POINT_VALUE)
setViewPortCharacterTarget(GET_VALUE)
sub186A1(GET_VALUE, IMMEDIATE_VALUE, IMMEDIATE_VALUE)
sub186E5_snd(GET_VALUE, IMMEDIATE_VALUE)
sub1870A_snd(POINT_VALUE, IMMEDIATE_VALUE)
sub18725_snd(GET_VALUE)
sub18733_snd(GET_VALUE)
sub1873F_snd(POINT_VALUE)
sub18746_snd(IMMEDIATE_VALUE)
sub1875D_snd()
setCharacterMapColor(GET_VALUE, IMMEDIATE_VALUE)
initGameAreaDisplay2()