Jump to content

Dune II editor with 1.07 support


Recommended Posts

I said a MISSION, as in the mission SCRIPT FILE. Why would that script change the mouse cursor pos at the start of the mission?



Starting a mission doesn't affect the actual position of the mouse cursor in the game (I tested that), and it overall doesn't seem very useful to me, if it changes from the moment the player moves his mouse.

Edited by Nyerguds
Link to comment
Share on other sites

Yes, in the original missions it selects the player's Construction Yard, and also prevents it's buildup animation from being played (you can observe in some DuneX missions with a pre-placed player's base that structures that are not selected play the buildup animation right at the start of the mission).

Link to comment
Share on other sites

next version will have a slightly modified layout, and will use multi-dimensional arrays for everything related to the main types list (units/structs/houses becomes [0,1,2]), which removes a ton of exceptions from the code and generally makes my life easier :D

Theoretically, this should make it easier to add even more types to the editor, but there's still one huge problem with that though... at this moment, to get the name of an item in the units/structures/houses list (eg. "Carryall", "Hi-Tech", "Ordos"), it actually has an array (1,1,0) which tells it which option from the options list for that type to use to get that string. So to get a unit name, it looks at option #1 for the units (=name reference) and uses the resulting string as name. The function used for this is exactly the same as the one used to draw the values in the second column of the options.

Basically, this means the name has to come from one of the unit's options, which means there's no support for types without a name reference tongue.png


Edited by Nyerguds
Link to comment
Share on other sites

Hey Nyerguds,

I was wondering if it would be possible to implement a feature in your editor where you can compare a given field value for all structures/units at the same time. I have attached a screenshot from a dinky BASIC program I wrote quite a while ago to give you an idea of what I mean. Basically, lets say you have an unknown field, rather than having to go through all the units/structures to see how the value changes, you can just display that one field for all structures/units on the screen at once. It makes it easier to see patterns etc.

Keep up the awesome work :)


Link to comment
Share on other sites

Hmm... that shouldn't be too hard... but I'll have to think about how to adapt the interface for it.

I could just make it as second column in the units list... showing the hex value of whatever's currently selected in list #3. I could make it a standard feature for hexadecimal mode, even.

Though this still doesn't show all values at the same time... after all, the full list is longer than the screen (except for houses)

I could also do it as basic popup box like the editing or help boxes. I'll have to make sure it's big enough though... I already got a smart abbreviation method to shorten any string to 4 chars (this is used for the prerequisites), so I can use that for this too...

Problem is that I have to choose for either one scrolling list, or hardcoding a multiple-columns view, which limits support for possibly much larger type lists added in the future.

Link to comment
Share on other sites

I tried getting your editor to work on linux, but when trying to run it, I get this:

Runtime error 218 at $0000000000401884






I don't know much about pascal at all (I only wanted to run the editor to better understand the source;p),

but I had to fix some warnings and errors to get it to build with fpc, so I'll attach the resulting patch

at least...

What I specifically wanted to figure out was the version detection:

    dunever:  array[0..4] of string[7] = ('DEMO','1.00','1.07-US','1.07-EU','1.07-HS');

    //place of the identification string (gamenamestr) in each version

    verAddress:array[0..4] of longint = (225278,229282,228274,229682,229586);

    // Correction to make file addresses out of exe references for each version

    refAddress:array[0..4] of fourbyte = (($32, $4D, $90, $F0),

                                          ($33, $2B, $81, $10),

                                          ($32, $EC, $85, $00),

                                          ($33, $44, $7F, $80),

                                          ($33, $3E, $7F, $E0));

I was thinking that refAddres found at the offset verAddres might be what identified the version,

but I couldn't make much sense to that..

Any hints? :)


Link to comment
Share on other sites

well, you have to make sure to understand that these rows of 8 bits (datatype 12-19 in my editor) are all read from one single byte... if you look at the getDataLen function in my code you see the length of each entry type in the list. The bits are done so only the last of the 8 options actually has size "1". The first 7 all have size 0, making the editor read these 8 options from that one same byte before continuing to the next.

So I guess that part is wrong in your structs there. These 8 options together are really only one byte each time. In your structs it are 8 bytes.

oh, never mind, I figured it out when I looked closer into the 4 byte data I actually found at those offsets. :)

"verAddress" is just the offset of the exe filename string (normally "dune2.exe", but can be modified) in each version. "refAddress" is unrelated to that; it's used to get the string address from a string reference in the editing data. "dunever" is just the string to show in the editor; it has no relation to the actual identification process.

As for getting it working in Linux, I use FreePascal (from the Dev-Pascal suite), which, unlike normal pascal, allows functions that return custom defined datatypes. All internal traffic in my editor uses these FourBytes. Though this was mostly done because I didn't know I could use bit shifting and AND/OR functions to easily get separate bytes from a larger 4-byte value. Heck, I still haven't figured out if there's an actual unsigned integer type in Pascal. Hence why I used bytes :P

Link to comment
Share on other sites

Ah... honestly, I don't have a clue how that works. There doesn't seem to be any indication of when the next actual byte in the struct starts, using that bit indication system... unless the format actually requires you to define all 8 bits.

Link to comment
Share on other sites

yeah, but notice the ':' at the end of the declarations, 'uint8_t foo:1' refers to the first bit, 'uint8_t foo:2' the second, etcetc. :)

That doesn't sound right. It's the bit count. So :2 is 2 bits. Layout is undefined by C++ (compiler depended).

Link to comment
Share on other sites

Try these, they work fine (here anyway)

struct sExeHouseData {

#pragma pack(1)

dword houseName;

word Weakness;

word LemonFactor;

word buildingDecay;

word color;

word PalaceUnitRecharge;

word FrigateTime;

word houseLetter;

word PalaceSpecial;

word missionWinMusic;

word missionLoseMusic;

word missionBriefMusic;

dword houseVoice;


struct sExeStructureData {

#pragma pack(1)

word idShort;

dword Name;

word idLong;

dword Picture;

word  buildOpts;

word  field_E;

word  HitPoints;

word  Sight;    

word  sidebarIconID;

word  Cost;

word  BuildTime;

word  Techlevel;

dword PreReqs;

byte  buildOrder;

byte CYUpgradesNeeded;

byte field_22;

byte field_23;

byte field_24;

byte field_25;

byte field_26;

byte field_27;

byte field_28;

byte field_29;

byte field_2A;

word structureID;

word weaponDamage;

word weaponDamageAdd;

byte Owner;

word RepairFacility;

word UnitsCanEnter;

word SpiceStorage;

word PowerUsage;

word FoundationSize;

word structureGfxID;

word field_3E;

word field_40;

word field_42;

word field_44;

word field_46;

word field_48;

word constructOpt1;

word constructOpt2;

word constructOpt3;

word constructOpt4;

word constructOpt5;

word constructOpt6;

word constructOpt7;

word constructOpt8;

word techUpgrade1;

word techUpgrade2;

word techUpgrade3;


struct sExeUnitData {

#pragma pack(1)

word stringID;        

dword Name;

word stringLongID;    

dword Picture;

word optsWocaTuro;    

word field_E;        

word HitPoints;      

word Sight;          

word sidebarIconID;  

word Cost;            

word buildTime;      

word TechLevel;      

dword PreReqs;        

byte field_20;        

byte UpgradesNeeded;  

word sidebarCommand1;

word sidebarCommand2;

word sidebarCommand3;

word sidebarCommand4;

byte field_2A;        

word field_2B;        

word field_2D;        

word Aggressivity;    

byte Owner;          

word indexMin;        

word indexMax;        

word optsFitW;        

byte field_38;        

byte field_39;        

word field_3A;        

word MovementType;    

word field_3E;        

word Speed;

word turningSpeed;

word UnitGfxID;

word turretGfxID;

word field_48;

word field_4A;

word deathAnim;

word weaponRateFire;

word weaponRange;

word weaponDamage;

word field_54;  

word weaponType;

word weaponSound;


// Stored internal File table

struct sExeFileData {

#pragma pack(1)

dword fileName;

word  field_4;

word  field_6;

word  field_8;

word  field_A;

word  field_C;

word  field_E;

byte  parentIndex;

byte  field_11;

byte  fileType;


// Unit 'Action' commands

struct sExeActionData {

#pragma pack(1)

byte field_0;

byte field_1;

dword Name;

byte field_6;

byte field_7;

byte sidebarMode;

byte field_9;

byte field_A;

byte field_B;


EDIT: Forgot to mention, the bitfields were most likely done using ENUMs, the IDA DB has them mapped out if u just wanna copy/paste (nothing fancy ever happens with the OptsWoca fields, etc) the data is never copied from the internal hardcoded structures... tests are done directly against them

Link to comment
Share on other sites

That doesn't sound right. It's the bit count. So :2 is 2 bits. Layout is undefined by C++ (compiler depended).

yeah, you're right, I'm mixing things, but doing like segra suggested as in Dune 2 will probably be my way to go anyways. :)

Link to comment
Share on other sites

nyerguds, I was talking about data structures, not buildings ;)

segra: cool, but how many entries for filedata & actiondata?

Also, do you have any example code making use of these structures?

Any updates on your emc code would also be welcome btw. :)


Link to comment
Share on other sites

action table is 14 entries

file table is 671 entries, terminated with a null entry

havnt worked with the action table yet so im not sure of what its for

filetable however is checked if opening of a file from the disk fails, it searches for "filename" in the table, reads the "parent index" field (which is the index of a pak file), and attempts to read "filename" from the pak

gonna do some decoding of those unit script functions again in a few days, so will see what can be done ;)

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Create New...