Wednesday, January 8, 2014

Generating Creatures 2 Egg files with Python

The Creatures 2 .egg file format is one of the few well documented aspects of the game series.

Why bother writing about it on a blog about investigating undocumented game aspects then ?
Well, the ability to generate .eeg files is a pretty simple skill that might prove an interesting addition for anybody writing Creatures tools.

The aim here is just to show how quick and easy it is
, and also to highlight some of the optional points.



Let's begin with the file structure, as found at the CDN.

Type        Meaning       Description
4 bytes     'eggf'        The eggfile header
1 byte      Gender        0=random, 1=male, 2=female
1 byte      Image         0..16 - Egg Image for Hatchery.
long        Reserved1     Unused field, must be present and Zero
long        Reserved2     Unused field, must be present and Zero
4 bytes     MumMoniker    The the mother's moniker.
4 bytes     DadMoniker    The father's moniker.Can be four \x00 bytes if not used.
long        DescriptionSize Length in bytes of the Egg description,0 if no description.
byte array    Description An arbitrary description text.If DescriptionSize is 0, then don't incorporate this field
long         MumGenSize   Size in bytes of the mother's Genetics file
byte array   MumGenetics  Mother Genetics file contents.

long         DadGenSize   Size in bytes of Father's Genetics file - don't add if no father is used
byte array    DadGenetics Father Genetics file contents - don't add if no father is used

</pre>


Pretty simple isn't it ?

The only thing to keep in mind is that :
  • an egg can either contain only one moniker, which means that you're merely packing a creature's gen file into an .egg file for easy deployment ( breed distribution for example ), and you will get the exact same Norn any single time the egg is hatched.
  • Or you can pack it with both a mum's and dad's genetic files, meaning that the moment the egg hatches, the resulting creature will be a random mix of mother and father's genes as if a natural egg had occurred.This is typically used on the eggs you begin the game with, or to provide diversity.

In the case you're making a one genome only egg, you just skip some of the mentioned fields from the description.

Alright let's get to it, here is how you would make a new egg file, containing a mix of the Grendel and the Ettin genome.We will be using python "struct" module as a way to be sure our values are codded with the expected length and format before writing it to a file.Put the following code inside a .py file, and drop it in your C2 genetics folder ( or change the paths accordingly ), then run it.



import struct

# Customise those values as needed :
MotherFile="ettn.gen"   # Mother genome file
FatherFile="gren.gen"   # Father genome file
OutputFile="pythonegg.egg"  # A name for the output Egg
Sex= 0                  # 0 = random, 1=Male, 2=Female
Image= 7                # Egg image to use (0-16)
Description="Python Test Egg"
# Don't change anything further down


MotherGenome=open(MotherFile,mode="rb").read()
FatherGenome=open(FatherFile,mode="rb").read()

Egg = "eggf"                        # Header
Egg = Egg + struct.pack("B",Sex)    # Sex..
Egg = Egg+struct.pack("B",Image)    # Image number
Egg = Egg+struct.pack("ll",0,0)     # Unused longs
Egg = Egg + MotherFile[:-4] +FatherFile[:-4] # Parent's monikers
Egg = Egg + struct.pack("l",len(Description))# Description length
Egg = Egg + Description # The actual description
Egg = Egg + struct.pack("l",len(MotherGenome)) # Mum genome length
Egg = Egg + MotherGenome # The contents of the Mum genome file
Egg = Egg + struct.pack("l",len(FatherGenome))
# Dad genome length
Egg = Egg + FatherGenome # The contents of the Dad genome file
OutputEgg = open (OutputFile, "wb")
EggFileContents=bytearray(Egg)
OutputEgg.write(EggFileContents)
OutputEgg.close()


This should produce  a "pythonegg.egg" file in the current directory.
Move the file to your "Eggs" folder inside the C2 main directory, and run the game and the hatchery applet.

This is how your new egg will look like if you keep the given script parameters.


Pick the newly generated egg ( the green/dark blue one if you didn't change it in the code ), and hatch it.
Voila! Enjoy your newly generated creature.

And this is precisely why grendels and ettins aren't supposed to breed naturally....

And what if we wanted to produce a "virgin birth" egg for distributing a genegineered  creature breed for example ?
Just omit the unneeded fields as follows :

import struct

MotherFile="ettn.gen"   # Mother genome file
OutputFile="1parent.egg"# A name for the output Egg
Sex= 0                  # 0 = random, 1=Male, 2=Female
Image= 7                # Egg image to use (0-16)
Description="1 genome Python test Egg"
# Don't change anything further down

MotherGenome=open(MotherFile,mode="rb").read()

Egg = "eggf"                        # Header
Egg = Egg + struct.pack("B",Sex)    # Sex..
Egg = Egg+struct.pack("B",Image)    # Image number
Egg = Egg+struct.pack("ll",0,0)     # Unused longs
Egg = Egg + MotherFile[:-4] +struct.pack("BBBB",0,0,0,0) # Parent's monikers
Egg = Egg + struct.pack("l",len(Description))
Egg = Egg + Description
Egg = Egg + struct.pack("l",len(MotherGenome))
Egg = Egg + MotherGenome

OutputEgg = open (OutputFile, "wb")
EggFileContents=bytearray(Egg)
OutputEgg.write(EggFileContents)
OutputEgg.close()



Soon enough there's a playground friend for our little monster (don't tell him I called him that, he's just..special)



That's all folks!
Generating egg files shouldn't be much more complicated in any programming language of your choice ( slightly longer if anything )

The ability to generate .egg files is not only useful for packaging and sharing your new breeds in a practical format, but it can also serve to revive the dead ( eurk! ) or to mate two long dead creature ( re-eurk !) whose offspring might be of interest to your genome experimentation but who never mated in game.

For this, all you need is to pick one or the two genomes you're interested in ( why not sort them out from a neat family tree ? ) and spawn the corresponding egg.

You can now revive a long dead Norn you liked, or artificially produce baby Norns "in-vitro" with a hand made tool.

Happy mad scientist-ing !

No comments:

Post a Comment