PDA

View Full Version : PHP & IV's



willaien
Mar 18th, 2011, 10:06 PM
I vaguely understand the bit shifting required to set IV's.

Here's the C# code I use for, say, setting ATTIV:


uint i = rawdata.GetUInt(0x38);
i &= 0xFFFFFC1F;
uint val = (uint)(value << 5);
i |= val;
rawdata.SetUInt(0x38, i);

However, when I port the code to PHP, it gets mangled on most of them. Apparently, PHP's typing is rather awkward and numbers default to a signed integer, and all math is signed integers for the most part.

Currently, I'm attempting to use GMP as seen below:

$newIV = $row['AttIV'];
$i = substr($q,0x38,8);
$i = gmp_and($i , 0xFFFFFC1F);
$val = gmp_mul($newIV,gmp_pow(2,5));
$i = gmp_or($i, $val);
$i = pack("V", $i);
$q = substr($q,0,0x38).$i.substr($q,0x3C);

For reference, $q is the loaded pokemon.

xfr
Mar 19th, 2011, 11:12 AM
$newIV = $row['AttIV'];
$i = unpack("V", substr($q,0x38,4));
$i &= 0xFFFFFC1F; // Clear Attack IV
$i |= ($newIV & 0x1F) << 5; // Set new attack IV
$q = substr($q,0,0x38).pack("V",$i).substr($q,0x3C);

You only need GMP for 64 bit arithetic on 32 bit systems, for instance the PRNG (but you can use bcmath for that, although it's slow)

willaien
Mar 19th, 2011, 01:24 PM
$newIV = $row['AttIV'];
$i = unpack("V", substr($q,0x38,4));
$i &= 0xFFFFFC1F; // Clear Attack IV
$i |= ($newIV & 0x1F) << 5; // Set new attack IV
$q = substr($q,0,0x38).pack("V",$i).substr($q,0x3C);

You only need GMP for 64 bit arithetic on 32 bit systems, for instance the PRNG (but you can use bcmath for that, although it's slow)

I still have the same problem, only SPDEF gets set, and HP is set at 1? Odd.

http://pastebin.com/wuk0471x

Here is a resulting file with the GTS portion snipped out, you can load it in pokesav to see. For reference, I'm *not* running a 64-bit OS.

http://dl.dropbox.com/u/17115146/result.bin

xfr
Mar 19th, 2011, 04:44 PM
There are two problems, lack of list(,) when unpacking and 32 bit overflow if the pokemon is nicknamed. You could temporarly unset the nickname flag by temporarly masking byte 0x3B with 0x7F and using your code, or proceed by 16-bit words, for instance for the HP IV use:

$newIV = $row['HPIV'];
list(,$i) = unpack("v", substr($q,0x38,2)); // HP, Attack, Def
$i &= 0xFFE0; // Clear HP IV
$i |= ($newIV & 0x1F) << 0; // Set new HP IV
$q = substr($q,0,0x38).pack("v",$i).substr($q,0x3A);
Of course for speed you'll need 0x39-0x3A, and for SA/SDef 0x3A-0x3B... for the other solution:


$n = ord($q[0x3B]);
$nicknamed = $n>>7;
$q[0x3B] = chr($n & 0x7F);
// ... Your pastebin code fixed with list(,) before unpacks
if($nicknamed) $q[0x3B]=chr(ord($q[0x3B]) | 0x80);

Third and best solution is use a 64 bit OS.

willaien
Mar 19th, 2011, 10:29 PM
Thanks for your help. I implemented the option of temporarily storing the nickname bit.