Skip to content

Instantly share code, notes, and snippets.

@magical
Last active January 27, 2017 02:46
Show Gist options
  • Save magical/3330aa98aaffa0f7eb07b4b76adb3a47 to your computer and use it in GitHub Desktop.
Save magical/3330aa98aaffa0f7eb07b4b76adb3a47 to your computer and use it in GitHub Desktop.
Item Stats Structure
0x00 uint16 Purchase Price (in units of $10)
0x02 uint8 Held effect?
0x03 uint8 Effect argument
0x04 uint8 Natural Gift effect
0x05 uint8 Fling effect
0x06 uint8 Fling power
0x07 uint8 Natural Gift power
0x08 uint16 Bits 0-4: Natural Gift type (31=n/a)
Flags?
Bit 9 = Key Item
0x0A uint8 Use effect?
0x0B uint8 0 / 1 = Balls / 2 = Medicine /
3 = Poké Doll + Fluffy Tail + Poké Toy
0x0C uint8 0 / 1
0x0D uint8 0 / 1 / 2 / 3 = Battle items / 4 = Balls / 5 = Mail
0x0E uint8 1 = Usable by pokémon, consumed
0x0F uint8 Order in pocket
0x10 uint8 Status problems cured
1 = SLP / 2 = PSN / 4 = BRN / 8 = FRZ
16 = PAR / 32 = Confusion / 64 = Infatuation
128 = Guard Spec.
0x11 uint8 1 = Revive / 3 = Revive party / 5 = Level up /
8 = Evolution stone
0x11 bits 4..7 Attack boost
0x12 bits 0..3 Defense boost
0x12 bits 4..7 Special Attack boost
0x13 bits 0..3 Special Defense boost
0x13 bits 4..7 Speed boost
0x14 bits 0..3 Accuracy boost
0x14 bits 4..5 Critical Hit boost
0x14 bits 5..7 4 = PP Up / 8 = PP Max
0x15 uint8 1 = Ether / 2 = Elixer / 4 = Heal / 8 = HP Up
16 = Raises ATK / 32 = DEF / 64 = SPD / 128 = SPATK
0x16 uint8 1 = SPDEF / 2 = Wings / 4,8,16 = Friendship
0x17 int8 Effort gain (HP)
0x18 int8 Effort gain (Attack)
0x19 int8 Effort gain (Defense)
0x1A int8 Effort gain (Speed)
0x1B int8 Effort gain (Special Attack)
0x1C int8 Effort gain (Special Defense)
0x1D uint8 HP gain (0xFF = full, FE 50%, FD 25%)
0x1E uint8 PP gain
0x1F int8 Friendship gain
0x20 int8 Friendship gain
0x21 int8 Friendship gain
import struct
import base64
names = [line.strip() for line in open("rips/text/en/96")]
def icons():
code = open("../X/exefs/code.bin", 'rb')
code.seek(0x43db74)
while True:
index, = struct.unpack("<L", code.read(4))
yield index
iconcache = {}
f = open("rips/item-icons.html", 'w', encoding='utf-8')
f.write("<!doctype html>\n")
f.write("<title>X/Y Item Icons</title>\n")
f.write('<meta charset="utf-8">\n')
f.write('<style>\n')
f.write('body { -moz-column-width: 13em; }\n')
f.write('body { -webkit-column-width: 13em; }\n')
f.write('body { column-width: 13em; }\n')
f.write('img { vertical-align: middle; }\n')
f.write('</style>\n')
for name, icon in zip(names, icons()):
if icon not in iconcache:
data = open("rips/item_icons/{}.png".format(icon), 'rb').read()
iconcache[icon] = "data:image/png;base64," + base64.b64encode(data).decode()
f.write('<img src="{}" title="icon {}"> {}<br>\n'.format(iconcache[icon], icon, name))
f.close()
package main
import (
"encoding/binary"
"fmt"
"html/template"
"os"
"strconv"
"strings"
"xy/garc"
"xy/names"
)
type Item struct {
Index int
Name string
Icon int
ItemStats
}
// ItemStats is the item stat structure found at
// a/2/2/0 in Pokémon X and Y, and
// a/1/9/7 in Pokémon Omega Ruby and Alpha Sapphire.
type ItemStats struct {
PriceRaw uint16
Effect uint8
EffectArg uint8
NaturalGiftEffect uint8
FlingEffect uint8
FlingPower uint8
NaturalGiftPower uint8
FlagsRaw uint16
Unknown0A uint8
Unknown0B uint8
Unknown0C uint8
Unknown0D uint8
Unknown0E uint8
Order uint8
Status1 uint32
Status2 uint16
Status3 uint8
Effort [6]int8
HP uint8
PP uint8
Friendship [3]int8
}
func (m *Item) Price() uint { return uint(m.PriceRaw) * 10 }
func (m *Item) Status() uint64 { return uint64(m.Status1) | uint64(m.Status2)<<32 | uint64(m.Status3)<<48 }
func (m *Item) NaturalGiftType() int { return int(m.FlagsRaw & 31) }
func (m *Item) NaturalGiftTypeName() string { return names.Type(int(m.FlagsRaw & 31)) }
func (m *Item) Flags() uint16 { return m.FlagsRaw >> 5 }
// Flags:
// 2
// 3 berry / tm
// 4 key item
// 5 nothing
// 6 ball
// 7 battle item
// 8 restores HP or PP
// 9 restores status
func die(v ...interface{}) {
fmt.Fprintln(os.Stderr, v...)
os.Exit(1)
}
var t = template.Must(template.New("items").Funcs(funcs).Parse(tmpltext))
func main() {
filename := os.Args[1]
f, err := os.Open(filename)
if err != nil {
die(err)
}
defer f.Close()
files, err := garc.Files(f)
if err != nil {
die(err)
}
var iconmap []uint32
if len(os.Args) > 2 {
iconmap, err = readiconmap(os.Args[2], len(files))
if err != nil {
die(err)
}
}
var item Item
items := make([]Item, 0, len(files))
for i, file := range files {
err := binary.Read(file, binary.LittleEndian, &item.ItemStats)
if err != nil {
fmt.Fprintln(os.Stderr, err)
continue
}
item.Index = i
item.Name = names.Item(i)
if iconmap != nil {
item.Icon = int(iconmap[i])
} else {
item.Icon = -1
}
//item.Name = names[i]
items = append(items, item)
}
err = t.Execute(os.Stdout, items)
if err != nil {
die(err)
}
}
func readiconmap(filename string, n int) ([]uint32, error) {
filename, offstr := partition(filename, ":")
off, err := strconv.ParseInt(offstr, 0, 64)
if err != nil {
return nil, err
}
f, err := os.Open(filename)
if err != nil {
return nil, err
}
defer f.Close()
if _, err := f.Seek(off, 0); err != nil {
return nil, err
}
m := make([]uint32, n)
err = binary.Read(f, binary.LittleEndian, m)
return m, err
}
func partition(s string, sep string) (front, back string) {
i := strings.Index(s, sep)
if i >= 0 {
return s[:i], s[i+1:]
}
return s, ""
}
func flags(v interface{}, s string) string {
switch v := v.(type) {
case uint16:
return formatFlags(uint32(v), s)
}
return "error"
}
func formatFlags(u uint32, s string) string {
var b [64]byte
for i := 0; i < len(s); i++ {
if u & 1 == 0 {
b[i] = '-'
} else {
b[i] = s[i]
}
u = u >> 1
}
return string(b[:len(s)])
}
var funcs = template.FuncMap{
"flags": flags,
}
var tmpltext = `<!DOCTYPE html>
<meta charset="utf-8">
<title>OR/AS item struct</title>
<style type="text/css">
body { font-family: sans-serif; font-size: 16px; line-height: 1em; }
table { border-collapse: collapse; white-space: nowrap; }
tbody { border: 2px solid black; }
tbody td, tbody th { border: 1px solid black; }
td, th { padding: 0.3em; }
td { text-align: right; }
td.str { text-align: left; }
td.list { text-align: left; }
td.int { text-align: right; }
td.hex { font-family: monospace; }
td.icon { padding: 0; text-align: center; }
td img { vertical-align: middle; }
tr:hover { background: #DEE6F5; }
</style>
<table>
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Icon</th>
<th>Price</th>
<th>Effect</th>
<th>Arg</th>
<th>Ntl.Gift<br>effect</th>
<th>Fling<br>effect</th>
<th>Fling<br>power</th>
<th>Ntl.Gift<br>power</th>
<th>Ntl.Gift<br>type</th>
<th>Flags</th>
<th>0A</th>
<th>0B</th>
<th>0C</th>
<th>0D</th>
<th>0E</th>
<th>Order</th>
<th>Status</th>
<th>Effort</th>
<th>HP</th>
<th>PP</th>
<th>Friendship</th>
<th>Name</th>
<th>#</th>
</tr>
</thead>
<tbody>
{{range .}}
<tr>
<th>{{.Index}}</th>
<th class=str>{{.Name}}</th>
<td class=icon>{{if ne .Icon -1}}<img src="items/{{.Icon}}.png">{{end}}</td>
<td>{{.Price}}</td>
<td>{{.Effect}}</td>
<td>{{.EffectArg}}</td>
<td>{{.NaturalGiftEffect}}</td>
<td>{{.FlingEffect}}</td>
<td>{{.FlingPower}}</td>
<td>{{.NaturalGiftPower}}</td>
<td class=str>{{if ne .NaturalGiftType 31}}{{.NaturalGiftTypeName}}{{end}}</td>
<td class=hex>{{flags .Flags "012mk%bths%"}}</td>
<td class=hex>{{printf "%x" .Unknown0A}}</td>
<td>{{.Unknown0B}}</td>
<td>{{.Unknown0C}}</td>
<td>{{.Unknown0D}}</td>
<td>{{.Unknown0E}}</td>
<td>{{.Order}}</td>
<td class=hex>{{printf "%014x" .Status}}</td>
<td class=list>{{.Effort}}</td>
<td>{{.HP}}</td>
<td>{{.PP}}</td>
<td class=list>{{.Friendship}}</td>
<th class=str>{{.Name}}</th>
<th>{{.Index}}</th>
</tr>
{{end}}
</tbody>
</table>
`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment