-
Notifications
You must be signed in to change notification settings - Fork 39
InfoTranslator: Draft randomUnits support #113
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,7 +26,7 @@ module.exports = function W3Buffer(buffer) { | |
| return String.fromCharCode(ch); | ||
| }).join(''); | ||
| }, | ||
| readChars: function(len) { | ||
| readChars: function(len, allowNull = false) { | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Likewise,
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In fact it was your commit fe0b16c 😄
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I know. As I said, this is based on v1.0.0, so I had to include it for completeness. Ultimately, gotta evaluate to what extent each implementation of random tables is accurate. It's a bit awkward that I didn't realize at first that you already had an implementation... Feel free to close and/or cherry-pick improvements. |
||
| let string = [], | ||
| numCharsToRead = len || 1; | ||
|
|
||
|
|
@@ -36,10 +36,21 @@ module.exports = function W3Buffer(buffer) { | |
| } | ||
|
|
||
| return string.map((ch) => { | ||
| if(ch === 0x0) return '0'; | ||
| if(!allowNull && ch === 0x0) return '0'; | ||
| return String.fromCharCode(ch); | ||
| }).join(''); | ||
| }, | ||
| readFourCCTwice: function() { | ||
| let value = 0; | ||
| let string = this.readChars(4, true); | ||
| for (let i = 0; i < string.length; i++) { | ||
| let c = string.charCodeAt(i); | ||
| if (c === 0) continue; | ||
| if (c < 0x30 || 0x39 < c) throw new Error(`Invalid numerical FourCC`); | ||
| value += (c - 0x30) * (1 << (8 * i)); | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is interesting - I haven't seen documentation on WC3's FourCC format, so am unfamiliar. Do you have any references or examples, perhaps ones where the prior WC3MapTranslator implementation fails and this one is correct?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Will gather this. Note that the previous "FourCC" implementation is correct per se. This is a different thing, which I named "FourCC twice" for lack of a better name.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, regarding FourCC, this is a close reference https://ubershmekel.github.io/fourcc-to-text/. The difference is that WC3 treats FourCC texts as case-insensitive in some contexts, such as tooltips files. I haven't fully researched the sensitiveness stuff, but it's not relevant for WC3MapTranslator. |
||
| } | ||
| return value; | ||
| }, | ||
| readByte: function() { | ||
| let byte = buffer[offset]; | ||
| offset += 1; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -88,14 +88,18 @@ const InfoTranslator = { | |
|
|
||
| // Misc. | ||
| // If globalWeather is not defined or is set to 'none', use 0 sentinel value, else add char[4] | ||
| if(!infoJson.globalWeather || infoJson.globalWeather.toLowerCase() === 'none') { | ||
| if(!infoJson.globalWeather || infoJson.globalWeather.toLowerCase() === 'none' || infoJson.globalWeather === '0000') { | ||
| outBuffer.addInt(0); | ||
| } | ||
| else { | ||
| outBuffer.addString(infoJson.globalWeather, false); // char[4] - lookup table | ||
| } | ||
| outBuffer.addString(infoJson.customSoundEnvironment || '', true); | ||
| outBuffer.addChar(infoJson.customLightEnv || 'L'); | ||
| if (infoJson.customLightEnv === '0') { | ||
| outBuffer.addByte(0); | ||
| } else { | ||
| outBuffer.addChar(infoJson.customLightEnv || 'L'); | ||
| } | ||
|
|
||
| // Custom water tinting | ||
| outBuffer.addByte(infoJson.water[0]); | ||
|
|
@@ -110,6 +114,7 @@ const InfoTranslator = { | |
| outBuffer.addInt(player.type); | ||
| outBuffer.addInt(player.race); | ||
| outBuffer.addInt(player.startingPos.fixed ? 1 : 0); | ||
| /* outBuffer.addInt(player.startingPos.fixed ? 1 : 2); */ | ||
| outBuffer.addString(player.name, true); | ||
| outBuffer.addFloat(player.startingPos.x); | ||
| outBuffer.addFloat(player.startingPos.y); | ||
|
|
@@ -129,10 +134,8 @@ const InfoTranslator = { | |
| if(force.flags.shareAdvUnitControl) forceFlags |= 0x0020; | ||
|
|
||
| outBuffer.addInt(forceFlags); | ||
| outBuffer.addByte(255); // force players - unsupported | ||
| outBuffer.addByte(255); // force players - unsupported | ||
| outBuffer.addByte(255); // force players - unsupported | ||
| outBuffer.addByte(255); // force players - unsupported | ||
|
|
||
| outBuffer.addInt(force.players === -1 ? (1 << 11) - 1 : force.players); | ||
| outBuffer.addString(force.name, true); | ||
| }); | ||
|
|
||
|
|
@@ -142,8 +145,21 @@ const InfoTranslator = { | |
| // Tech availability - unsupported | ||
| outBuffer.addInt(0); | ||
|
|
||
| // Unit table (random) - unsupported | ||
| outBuffer.addInt(0); | ||
| // Partial support: Unit table (random) | ||
| outBuffer.addInt(infoJson.randomUnits.length); | ||
| for (const randomUnitsGroup of infoJson.randomUnits) { | ||
| outBuffer.addInt(randomUnitsGroup.id); | ||
| outBuffer.addString(randomUnitsGroup.name, true); | ||
| outBuffer.addInt(randomUnitsGroup.subTables.length); | ||
| for (let i = 0; i < randomUnitsGroup.subTables.length; i++) outBuffer.addInt(0); // ???? | ||
| outBuffer.addInt(randomUnitsGroup.subTables.length); | ||
| for (let i = 0; i < randomUnitsGroup.subTables.length; i++) { | ||
| outBuffer.addFourCCTwice(randomUnitsGroup.subTables[i].variants.length); | ||
| for (let j = 0; j < randomUnitsGroup.subTables[i].variants.length; j++) { | ||
| outBuffer.addString(randomUnitsGroup.subTables[i].variants[j].object, false); | ||
| } | ||
| } | ||
| } | ||
|
Comment on lines
+148
to
+162
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like you're editing a
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah. After submitting this, I realized that v5.0.0 already supports random units tables. I was under the impression that v4.0.0 didn't and that v5.0.0 didn't either, which is why I originally thought this PR would be more useful 😅 , but I was wrong lol. Still, there are some details here such as UTF8 strings, which I do correctly, but the rest of my algorithm is actually iffy. |
||
|
|
||
| // Item table (random) - unsupported | ||
| outBuffer.addInt(0); | ||
|
|
@@ -154,7 +170,7 @@ const InfoTranslator = { | |
| }; | ||
| }, | ||
| warToJson: function(buffer) { | ||
| let result = { map: {}, loadingScreen: {}, prologue: {}, fog: {}, camera: {}, players: [], forces: [] }, | ||
| let result = { map: {}, loadingScreen: {}, prologue: {}, fog: {}, camera: {}, players: [], forces: [], randomUnits: [], randomItems: [] }, | ||
| b = new W3Buffer(buffer); | ||
|
|
||
| let fileVersion = b.readInt(), // File version | ||
|
|
@@ -278,51 +294,78 @@ const InfoTranslator = { | |
|
|
||
| // UNSUPPORTED: Struct: upgrade avail. | ||
| let numUpgrades = b.readInt(); | ||
| if (numUpgrades !== 0) throw new Error(`Custom upgrades unsupported`); | ||
| for(let i = 0; i < numUpgrades; i++) { | ||
| b.readInt(); // Player Flags (bit "x"=1 if this change applies for player "x") | ||
| b.readChars(4); // upgrade id (as in UpgradeData.slk) | ||
| b.readChars(4, true); // upgrade id (as in UpgradeData.slk) | ||
| b.readInt(); // Level of the upgrade for which the availability is changed (this is actually the level - 1, so 1 => 0) | ||
| b.readInt(); // Availability (0 = unavailable, 1 = available, 2 = researched) | ||
| } | ||
|
|
||
| // UNSUPPORTED: Struct: tech avail. | ||
| let numTech = b.readInt(); | ||
| if (numTech !== 0) throw new Error(`Custom tech tree unsupported`); | ||
| for(let i = 0; i < numTech; i++) { | ||
| b.readInt(); // Player Flags (bit "x"=1 if this change applies for player "x") | ||
| b.readChars(4); // tech id (this can be an item, unit or ability) | ||
| b.readChars(4, true); // tech id (this can be an item, unit or ability) | ||
| } | ||
|
|
||
| // UNSUPPORTED: Struct: random unit table | ||
| // PARTIAL SUPPORT: Struct: random unit table | ||
| let numUnitTable = b.readInt(); | ||
| let randomUnits = result.randomUnits; | ||
| for(let i = 0; i < numUnitTable; i++) { | ||
| b.readInt(); // Group number | ||
| b.readString(); // Group name | ||
| let randomUnitsGroup = { | ||
| id: b.readInt(), // Group number | ||
| name: b.readString(), // Group name | ||
| subTables: [], | ||
| }; | ||
| randomUnits.push(randomUnitsGroup); | ||
|
|
||
| let numPositions = b.readInt(); // Number "m" of positions | ||
| for (let n = 0; n < numPositions; n++) if (b.readInt() !== 0) throw new Error(`Invalid random units spec`); // ????? | ||
| let numPositions2 = b.readInt(); | ||
| if (numPositions !== numPositions2) throw new Error(`Invalid random units spec`); | ||
|
|
||
| for(let j = 0; j < numPositions; j++) { | ||
| b.readInt(); // unit table (=0), a building table (=1) or an item table (=2) | ||
| let thisTable = { | ||
| //type: b.readInt(), // unit table (=0), a building table (=1) or an item table (=2) | ||
| variants: [], | ||
| }; | ||
| randomUnitsGroup.subTables.push(thisTable); | ||
|
|
||
| let numLinesInTable = b.readInt(); | ||
| let numLinesInTable = b.readFourCCTwice(); | ||
| for(let k = 0; k < numLinesInTable; k++) { | ||
| b.readInt(); // Chance of the unit/item (percentage) | ||
| b.readChar(); // unit/item id's for this line specified | ||
| thisTable.variants.push({ | ||
| //chance: b.readInt(), // Chance of the unit/item (percentage) | ||
| object: b.readChars(4, true), // unit/item id's for this line specified | ||
| }); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // UNSUPPORTED: Struct: random item table | ||
| let numItemTable = b.readInt(); | ||
| if (numItemTable !== 0) throw new Error(`Custom random item table unsupported`); | ||
| let randomItems = result.randomItems; | ||
| for(let i = 0; i < numItemTable; i++) { | ||
| b.readInt(); // Table number | ||
| b.readString(); // Table name | ||
| let randomItemsGroup = { | ||
| id: b.readInt(), // Table number | ||
| name: b.readString(), // Table name | ||
| subTables: [], | ||
| }; | ||
| randomItems.push(randomItemsGroup); | ||
|
|
||
| let itemSetsCurrentTable = b.readInt(); // Number "m" of item sets on the current item table | ||
| for(let j = 0; j < itemSetsCurrentTable; j++) { | ||
| let thisTable = []; | ||
| randomItemsGroup.push(thisTable); | ||
|
|
||
| let itemsInItemSet = b.readInt(); // Number "i" of items on the current item set | ||
| for(let k = 0; k < itemsInItemSet; k++) { | ||
| b.readInt(); // Percentual chance | ||
| b.readChars(4); // Item id (as in ItemData.slk) | ||
| thisTable.push({ | ||
| chance: b.readInt(), // Percentual chance | ||
| object: b.readChars(4, true), // Item id (as in ItemData.slk) | ||
| }); | ||
| } | ||
|
|
||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
encoding an int can be done via
HexBuffer.addIntThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method is roughly supposed to store an integer as a decimal string, not as an int properly.