blog SyKoHPaTh

Guild Wars 1 Template Formula

So, using some resources scattered about the 'net, I was finally able to piece together how to convert a Guild Wars template code into their respective skills and attributes. The biggest issue I came across was on error checking, as well as not being able to find clear instructions on parts.

So essentially, this: OwpiMypMBg1cxcBAMBdmtIKAA magically turns into this: Code Sample:
  1. Template ID: OwpiMypMBg1cxcBAMBdmtIKAA
  2. Template Type: default
  3. Template Version: default
  4. Primary Profession: Assassin
  5. Secondary Profession: Dervish
  6. Attribute 1: Critical Strikes: 12
  7. Attribute 2: Scythe Mastery: 12
  8. Skill 1: Wounding Strike
  9. Skill 2: Eremite's Attack
  10. Skill 3: Mystic Sweep
  11. Skill 4: (blank)
  12. Skill 5: Dash
  13. Skill 6: Assassin's Remedy
  14. Skill 7: Way of the Master
  15. Skill 8: Resurrection Signet

You can try it here!

Now, onto how to reproduce this...

1) Convert the code from base64 into binary. I used PHP, and unfortunately, binary conversions of "large numbers", let alone 64-bit just simply does not work. It has to be broken down into segments, and each segment converted:
Code Sample:
  1. function base64bin($str){
  2. //converts base64 to binary
  3. $result = '';
  4. $str = base64_decode($str);
  5. $len = strlen($str);
  6. for ( $n = 0; $n < $len; $n ) {
  7. $result .= str_pad(decbin(ord($str[$n])), 8, '0', STR_PAD_LEFT);
  8. }
  9. return $result;
  10. }

2) Next, separate that really long binary number into sections of 6.
Code Sample:
  1. $sectionsArray = str_split($templateID, 6);

3) Each section has to be flipped. Since the sections are stored into an array, I figure passing by reference to "string-flip" each section was the most efficient route:
Code Sample:
  1. foreach($sectionsArray as &$value){
  2. $value = $this->flip($value);
  3. }

Code Sample:
  1. function flip(&$str){
  2. //flips a string "abcd" -> "dcba"
  3. return strrev($str);
  4. }

4) With each section flipped, need to "glue" everything back together.
Code Sample:
  1. $implodedBinary = implode('', $sectionsArray);

5) Easy so far, right? Yeah, here's the hard part. Now we have to "read" the string. I decided that as I "read" the string, I'd go ahead and do the lookup of each code. I basically did this with 2 arrays, one to hold the decimal value (binary -> decimal convert each part), and an associative array to hold the name of the category (key) and the looked up name of the decimal code (value). How it broke down:
Template type: 4 bits
Template version: 4 bits

Profession bitlength: 2 bits - result is y=(x*2 4)
Primary Profession: y bits
Secondary Profession: y bits

Number of Attributes: 4 bits - result determines how many times to 'loop' through the next part
Attribute bitlength: 4 bits - result is n=x 4

(start loop)
Attribute id: n bits
Attribute points: n bits
(end loop)

Skill bitlength: 4 bits - result is k=x 4

(start loop, 8 times, one for each skill slot)
Skill id: k bits
(end loop)

Trailing: x bits - unimportant, can safely ignore these

So that template code we started off with? By following each step, we'll end up with decimal values, which every step can be viewed through the above link.

guild wars