ref: b492d42e2545b8c414c917f7544bdd4b92e406e8
parent: 5e0dae801ca8b4d79a1fa08667b42f5457005e73
author: Jacob Moody <moody@posixcafe.org>
date: Fri May 19 22:39:14 EDT 2023
colo support, large refactor for colo support I dont love the View function pointer stuff. its whatever
--- /dev/null
+++ b/colo.c
@@ -1,0 +1,155 @@
+#include <u.h>
+#include <libc.h>
+#include <mp.h>
+#include <libsec.h>
+#include "colodat.h"
+#include "gen3dat.h"
+#include "pse.h"
+
+#define GET2(p) (u16int)(p)[1] | (u16int)(p)[0]<<8
+#define GET4(p) (u32int)(p)[3] | (u32int)(p)[2]<<8 | (u32int)(p)[1]<<16 | (u32int)(p)[0]<<24
+
+static void
+dodecrypt(uchar *dst, uchar *src)
+{
+ uchar d1[SHA1dlen];
+ uchar d2[SHA1dlen];
+ uchar *s, *e, *dot;
+ int i;
+
+ memcpy(d2, src + Slotszcolo - SHA1dlen, SHA1dlen);
+ for(i = 0; i < SHA1dlen; i++)
+ d2[i] = ~d2[i];
+
+ s = src + 0x18;
+ dst += 0x18;
+ e = src + Slotszcolo - (2*SHA1dlen);
+ while(s < e){
+ dot = s + SHA1dlen;
+ if(dot > e)
+ dot = e;
+ sha1(s, dot - s, d1, nil);
+ for(i = 0; i < dot - s; i++)
+ *dst++ = s[i] ^ d2[i];
+ memmove(d2, d1, dot - s);
+ s = dot;
+ }
+}
+
+void
+getcolo(int fd, Colo *dst)
+{
+ uchar buf[0x6000];
+ int i;
+ uchar *dd;
+ u32int max = 0;
+
+ if(readn(fd, dst->gcihdr, sizeof dst->gcihdr) != sizeof dst->gcihdr)
+ sysfatal("read: %r");
+ if(readn(fd, buf, sizeof buf) != sizeof buf)
+ sysfatal("read: %r");
+ for(i = 0; i < nelem(dst->slots); i++)
+ if(readn(fd, dst->slots[i], sizeof dst->slots[i]) != sizeof dst->slots[i])
+ sysfatal("read: %r");
+ for(i = 0; i < nelem(dst->index); i++){
+ dst->index[i] = GET4(&dst->slots[i][4]);
+ if(dst->index[i] > max)
+ dst->active = dst->slots[i];
+ }
+ dodecrypt(dst->decrypted, dst->active);
+ gettrainercolo(&dst->tr, dst->decrypted+0x78);
+ dst->money = GET4(dst->decrypted+0xAFC);
+ dst->coupons = GET4(dst->decrypted+0xB00);
+ dd = dst->decrypted + 0x00B90;
+ for(i = 0; i < 30*3; i++){
+ getpokemoncolo(dst->pc+i, dd + ((i/30 + 1) * 0x14));
+ dd += 312;
+ }
+}
+
+#pragma varargck type "L" uchar*
+
+/* colo strings are UTF16 but the game predates surrogate pairs */
+static int
+colostrfmt(Fmt *f)
+{
+ uchar *p;
+ Rune r;
+ int n;
+
+ p = va_arg(f->args, uchar*);
+ for(n = 0;; p +=2){
+ r = GET2(p);
+ if(r == 0)
+ break;
+ n += fmtprint(f, "%C", r);
+ }
+ return n;
+}
+
+static void
+vinit(void)
+{
+ fmtinstall('L', colostrfmt);
+}
+
+extern int gen3speciestab[];
+extern char *dexfiletab[];
+extern char *movenametab[];
+
+static int
+vdex(void *v)
+{
+ Pokemoncolo *p;
+
+ p = v;
+ if(p->species == 0)
+ return -1;
+ return gen3speciestab[p->species]-1;
+}
+
+static int
+vhdr(char *dst, char *e, void *v, int box)
+{
+ Colo *s;
+
+ s = v;
+ dst = seprint(dst, e, "Name: %L ID: %d Secret ID: %d\n", s->tr.name, s->tr.id, s->tr.secretid);
+ dst = seprint(dst, e, "Game: Colosseum Money: %ud Coupons: %ud\n", s->money, s->coupons);
+ seprint(dst, e, "Box %d: %L\n", box+1, s->decrypted + 0x00B90 + box*0x24a4);
+ return 0;
+}
+
+static int
+vbody(char *dst, char *e, void *v)
+{
+ Pokemoncolo *p;
+
+ p = v;
+ dst = seprint(dst, e, "Name: %L\n", p->name);
+ dst = seprint(dst, e, "OT Name: %L OT ID: %ud OT Secret ID: %d\n", p->otname, p->otid, p->otsecretid);
+ dst = seprint(dst, e, "National Dex: %d\n", gen3speciestab[p->species]-1);
+ dst = seprint(dst, e, "Exp: %d\n", p->exp);
+ dst = seprint(dst, e, "Move 1: %s Move 2: %s\n", movenametab[p->moves[0].id], movenametab[p->moves[1].id]);
+ dst = seprint(dst, e, "Move 3: %s Move 4: %s\n", movenametab[p->moves[2].id], movenametab[p->moves[3].id]);
+ dst = seprint(dst, e, "[EV] HP: %d Atk: %d Def: %d SpA: %d SpD: %d Spe: %d\n", p->ev.hp, p->ev.atk, p->ev.def, p->ev.spa, p->ev.spd, p->ev.spe);
+ seprint(dst, e, "[IV] HP: %d Atk: %d Def: %d SpA: %d SpD: %d Spe: %d\n", p->iv.hp, p->iv.atk, p->iv.def, p->iv.spa, p->iv.spd, p->iv.spe);
+ return 0;
+}
+
+static void*
+vbox(int box, int i, void *v)
+{
+ Colo *c;
+
+ c = v;
+ return c->pc + box*30 + i;
+}
+
+View vcolo = {
+ vinit,
+ vhdr,
+ vdex,
+ vbody,
+ vbox,
+};
--- /dev/null
+++ b/colodat.c
@@ -1,0 +1,303 @@
+#include <u.h>
+#include <libc.h>
+#include "colodat.h"
+
+#define GET2(p) (u16int)(p)[1] | (u16int)(p)[0]<<8
+#define PUT2(p, u) (p)[0] = (u)>>8, (p)[1] = (u)
+#define GET3(p) (u32int)(p)[2] | (u32int)(p)[1]<<8 | (u32int)(p)[0]<<16
+#define PUT3(p, u) (p)[0] = (u)>>16, (p)[1] = (u)>>8, (p)[2] = (u)
+#define GET4(p) (u32int)(p)[3] | (u32int)(p)[2]<<8 | (u32int)(p)[1]<<16 | (u32int)(p)[0]<<24
+#define PUT4(p, u) (p)[0] = (u)>>24, (p)[1] = (u)>>16, (p)[2] = (u)>>8, (p)[3] = (u)
+#define GET5(p) (u64int)(p)[4] | (u64int)(p)[3]<<8 | (u64int)(p)[2]<<16 | (u64int)(p)[1]<<24 | (u64int)(p)[0]<<32
+#define PUT5(p, u) (p)[0] = (u)>>32, (p)[1] = (u)>>24, (p)[2] = (u)>>16, (p)[3] = (u)>>8, (p)[4] = (u)
+#define GET6(p) (u64int)(p)[5] | (u64int)(p)[4]<<8 | (u64int)(p)[3]<<16 | (u64int)(p)[2]<<24 | (u64int)(p)[1]<<32 | (u64int)(p)[0]<<40
+#define PUT6(p, u) (p)[0] = (u)>>40, (p)[1] = (u)>>32, (p)[2] = (u)>>24, (p)[3] = (u)>>16, (p)[4] = (u)>>8, (p)[5] = (u)
+#define GET7(p) (u64int)(p)[6] | (u64int)(p)[5]<<8 | (u64int)(p)[4]<<16 | (u64int)(p)[3]<<24 | (u64int)(p)[2]<<32 | (u64int)(p)[1]<<40 | (u64int)(p)[0]<<48
+#define PUT7(p, u) (p)[0] = (u)>>48, (p)[1] = (u)>>40, (p)[2] = (u)>>32, (p)[3] = (u)>>24, (p)[4] = (u)>>16, (p)[5] = (u)>>8, (p)[6] = (u)
+#define GET8(p) (u64int)(p)[7] | (u64int)(p)[6]<<8 | (u64int)(p)[5]<<16 | (u64int)(p)[4]<<24 | (u64int)(p)[3]<<32 | (u64int)(p)[2]<<40 | (u64int)(p)[1]<<48 | (u64int)(p)[0]<<56
+#define PUT8(p, u) (p)[0] = (u)>>56, (p)[1] = (u)>>48, (p)[2] = (u)>>40, (p)[3] = (u)>>32, (p)[4] = (u)>>24, (p)[5] = (u)>>16, (p)[6] = (u)>>8, (p)[7] = (u)
+
+long
+getmovecolo(Movecolo *ret, uchar *data)
+{
+ long n;
+
+ n = 0;
+ ret->id = GET2(data+n);
+ n += 2;
+ ret->pp = data[n];
+ n += 1;
+ ret->up = data[n];
+ n += 1;
+ return n;
+}
+
+long
+putmovecolo(uchar *dst, Movecolo *src)
+{
+ long n;
+
+ n = 0;
+ PUT2(dst+n, src->id);
+ n += 2;
+ dst[n] = src->pp;
+ n += 1;
+ dst[n] = src->up;
+ n += 1;
+ return n;
+}
+
+long
+getstatcolo(Statcolo *ret, uchar *data)
+{
+ long n;
+
+ n = 0;
+ ret->hp = GET2(data+n);
+ n += 2;
+ ret->atk = GET2(data+n);
+ n += 2;
+ ret->def = GET2(data+n);
+ n += 2;
+ ret->spa = GET2(data+n);
+ n += 2;
+ ret->spd = GET2(data+n);
+ n += 2;
+ ret->spe = GET2(data+n);
+ n += 2;
+ return n;
+}
+
+long
+putstatcolo(uchar *dst, Statcolo *src)
+{
+ long n;
+
+ n = 0;
+ PUT2(dst+n, src->hp);
+ n += 2;
+ PUT2(dst+n, src->atk);
+ n += 2;
+ PUT2(dst+n, src->def);
+ n += 2;
+ PUT2(dst+n, src->spa);
+ n += 2;
+ PUT2(dst+n, src->spd);
+ n += 2;
+ PUT2(dst+n, src->spe);
+ n += 2;
+ return n;
+}
+
+long
+getpokemoncolo(Pokemoncolo *ret, uchar *data)
+{
+ long n;
+
+ n = 0;
+ ret->species = GET2(data+n);
+ n += 2;
+ ret->pad0 = GET2(data+n);
+ n += 2;
+ ret->pid = GET4(data+n);
+ n += 4;
+ ret->version = data[n];
+ n += 1;
+ ret->curregion = data[n];
+ n += 1;
+ ret->oriregion = data[n];
+ n += 1;
+ ret->lang = data[n];
+ n += 1;
+ ret->metloc = GET2(data+n);
+ n += 2;
+ ret->metlvl = data[n];
+ n += 1;
+ ret->ball = data[n];
+ n += 1;
+ ret->otgender = data[n];
+ n += 1;
+ memcpy(ret->pad3, data+n, 3);
+ n += 3;
+ ret->otid = GET2(data+n);
+ n += 2;
+ ret->otsecretid = GET2(data+n);
+ n += 2;
+ memcpy(ret->otname, data+n, 22);
+ n += 22;
+ memcpy(ret->name, data+n, 22);
+ n += 22;
+ memcpy(ret->namecopy, data+n, 22);
+ n += 22;
+ ret->pad1 = GET2(data+n);
+ n += 2;
+ ret->exp = GET4(data+n);
+ n += 4;
+ ret->statlvl = data[n];
+ n += 1;
+ memcpy(ret->battle, data+n, 23);
+ n += 23;
+ n += getmovecolo(&ret->moves[0], data+n);
+ n += getmovecolo(&ret->moves[1], data+n);
+ n += getmovecolo(&ret->moves[2], data+n);
+ n += getmovecolo(&ret->moves[3], data+n);
+ ret->item = GET2(data+n);
+ n += 2;
+ memcpy(ret->derived, data+n, 14);
+ n += 14;
+ n += getstatcolo(&ret->ev, data+n);
+ n += getstatcolo(&ret->iv, data+n);
+ ret->friendship = GET2(data+n);
+ n += 2;
+ memcpy(ret->contest, data+n, 11);
+ n += 11;
+ memcpy(ret->ribbon, data+n, 13);
+ n += 13;
+ ret->pkrs = data[n];
+ n += 1;
+ ret->isegg = data[n];
+ n += 1;
+ ret->ability = data[n];
+ n += 1;
+ ret->valid = data[n];
+ n += 1;
+ memcpy(ret->pad2, data+n, 9);
+ n += 9;
+ ret->slot = data[n];
+ n += 1;
+ ret->shadowid = GET2(data+n);
+ n += 2;
+ ret->pad4 = GET2(data+n);
+ n += 2;
+ ret->purification = GET4(data+n);
+ n += 4;
+ memcpy(ret->extra, data+n, 88);
+ n += 88;
+ return n;
+}
+
+long
+putpokemoncolo(uchar *dst, Pokemoncolo *src)
+{
+ long n;
+
+ n = 0;
+ PUT2(dst+n, src->species);
+ n += 2;
+ PUT2(dst+n, src->pad0);
+ n += 2;
+ PUT4(dst+n, src->pid);
+ n += 4;
+ dst[n] = src->version;
+ n += 1;
+ dst[n] = src->curregion;
+ n += 1;
+ dst[n] = src->oriregion;
+ n += 1;
+ dst[n] = src->lang;
+ n += 1;
+ PUT2(dst+n, src->metloc);
+ n += 2;
+ dst[n] = src->metlvl;
+ n += 1;
+ dst[n] = src->ball;
+ n += 1;
+ dst[n] = src->otgender;
+ n += 1;
+ memcpy(dst+n, src->pad3, 3);
+ n += 3;
+ PUT2(dst+n, src->otid);
+ n += 2;
+ PUT2(dst+n, src->otsecretid);
+ n += 2;
+ memcpy(dst+n, src->otname, 22);
+ n += 22;
+ memcpy(dst+n, src->name, 22);
+ n += 22;
+ memcpy(dst+n, src->namecopy, 22);
+ n += 22;
+ PUT2(dst+n, src->pad1);
+ n += 2;
+ PUT4(dst+n, src->exp);
+ n += 4;
+ dst[n] = src->statlvl;
+ n += 1;
+ memcpy(dst+n, src->battle, 23);
+ n += 23;
+ n += putmovecolo(dst+n, &src->moves[0]);
+ n += putmovecolo(dst+n, &src->moves[1]);
+ n += putmovecolo(dst+n, &src->moves[2]);
+ n += putmovecolo(dst+n, &src->moves[3]);
+ PUT2(dst+n, src->item);
+ n += 2;
+ memcpy(dst+n, src->derived, 14);
+ n += 14;
+ n += putstatcolo(dst+n, &src->ev);
+ n += putstatcolo(dst+n, &src->iv);
+ PUT2(dst+n, src->friendship);
+ n += 2;
+ memcpy(dst+n, src->contest, 11);
+ n += 11;
+ memcpy(dst+n, src->ribbon, 13);
+ n += 13;
+ dst[n] = src->pkrs;
+ n += 1;
+ dst[n] = src->isegg;
+ n += 1;
+ dst[n] = src->ability;
+ n += 1;
+ dst[n] = src->valid;
+ n += 1;
+ memcpy(dst+n, src->pad2, 9);
+ n += 9;
+ dst[n] = src->slot;
+ n += 1;
+ PUT2(dst+n, src->shadowid);
+ n += 2;
+ PUT2(dst+n, src->pad4);
+ n += 2;
+ PUT4(dst+n, src->purification);
+ n += 4;
+ memcpy(dst+n, src->extra, 88);
+ n += 88;
+ return n;
+}
+
+long
+gettrainercolo(Trainercolo *ret, uchar *data)
+{
+ long n;
+
+ n = 0;
+ memcpy(ret->name, data+n, 20);
+ n += 20;
+ memcpy(ret->namecopy, data+n, 20);
+ n += 20;
+ ret->pad0 = GET4(data+n);
+ n += 4;
+ ret->id = GET2(data+n);
+ n += 2;
+ ret->secretid = GET2(data+n);
+ n += 2;
+ return n;
+}
+
+long
+puttrainercolo(uchar *dst, Trainercolo *src)
+{
+ long n;
+
+ n = 0;
+ memcpy(dst+n, src->name, 20);
+ n += 20;
+ memcpy(dst+n, src->namecopy, 20);
+ n += 20;
+ PUT4(dst+n, src->pad0);
+ n += 4;
+ PUT2(dst+n, src->id);
+ n += 2;
+ PUT2(dst+n, src->secretid);
+ n += 2;
+ return n;
+}
+
--- /dev/null
+++ b/colodat.h
@@ -1,0 +1,70 @@
+typedef struct Movecolo Movecolo;
+typedef struct Statcolo Statcolo;
+typedef struct Pokemoncolo Pokemoncolo;
+typedef struct Slotcolo Slotcolo;
+typedef struct Trainercolo Trainercolo;
+
+struct Movecolo {
+ u16int id;
+ uchar pp;
+ uchar up;
+};
+
+struct Statcolo {
+ u16int hp;
+ u16int atk;
+ u16int def;
+ u16int spa;
+ u16int spd;
+ u16int spe;
+};
+
+struct Pokemoncolo {
+ u16int species;
+ u16int pad0;
+ u32int pid;
+ uchar version;
+ uchar curregion;
+ uchar oriregion;
+ uchar lang;
+ u16int metloc;
+ uchar metlvl;
+ uchar ball;
+ uchar otgender;
+ uchar pad3[3];
+ u16int otid;
+ u16int otsecretid;
+ uchar otname[22];
+ uchar name[22];
+ uchar namecopy[22];
+ u16int pad1;
+ u32int exp;
+ uchar statlvl;
+ uchar battle[23];
+ Movecolo moves[4];
+ u16int item;
+ uchar derived[14];
+ Statcolo ev;
+ Statcolo iv;
+ u16int friendship;
+ uchar contest[11];
+ uchar ribbon[13];
+ uchar pkrs;
+ uchar isegg;
+ uchar ability;
+ uchar valid;
+ uchar pad2[9];
+ uchar slot;
+ u16int shadowid;
+ u16int pad4;
+ u32int purification;
+ uchar extra[88];
+};
+
+struct Trainercolo {
+ uchar name[20];
+ uchar namecopy[20];
+ u32int pad0;
+ u16int id;
+ u16int secretid;
+};
--- a/dex.c
+++ b/dex.c
@@ -1,5 +1,15 @@
#include <u.h>
#include <libc.h>
+#include "colodat.h"
+#include "gen3dat.h"
+#include "pse.h"
+
+char *gnametab[] = {
+ [GRS] "Ruby/Sapphire",
+ [GFRLG] "Fire Red/Leaf Green",
+ [GEM] "Emerald",
+ [GCOLO] "Colosseum",
+};
char *dexfiletab[] = {
[0] "bulbasaur",
--- a/fs.c
+++ b/fs.c
@@ -4,7 +4,8 @@
#include <thread.h>
#include <9p.h>
#include "gen3dat.h"
-#include "gen3.h"
+#include "colodat.h"
+#include "pse.h"
Gen3 gen3;
--- a/gen3.c
+++ b/gen3.c
@@ -1,12 +1,24 @@
#include <u.h>
#include <libc.h>
#include "gen3dat.h"
-#include "gen3.h"
+#include "colodat.h"
+#include "pse.h"
-char *gen3gnametab[] = {
- [GRS] "Ruby/Sapphire",
- [GFRLG] "Fire Red/Leaf Green",
- [GEM] "Emerald",
+enum{
+ STrainer,
+ SInvent,
+ SState,
+ SMisc,
+ SRiv,
+ SPCA,
+ SPCB,
+ SPCC,
+ SPCD,
+ SPCE,
+ SPCF,
+ SPCG,
+ SPCH,
+ SPCI,
};
int poketab[24][4] = {
@@ -96,12 +108,24 @@
long n;
uchar buf[32];
+ n = f->prec;
p = va_arg(f->args, uchar*);
- n = va_arg(f->args, long);
gen3pkstr(buf, p, n);
return fmtprint(f, "%s", (char*)buf);
}
+typedef struct Gen3iv Gen3iv;
+struct Gen3iv {
+ uchar hp;
+ uchar atk;
+ uchar def;
+ uchar spe;
+ uchar spatk;
+ uchar spdef;
+ uchar egg;
+ uchar ability;
+};
+
void
getgen3iv(Gen3iv *dst, u32int src)
{
@@ -189,10 +213,77 @@
}
extern int gen3speciestab[];
+extern char *dexfiletab[];
+extern char *movenametab[];
-int
-getgen3dex(u16int species)
+static int
+vdex3(void *v)
{
+ Pokedat pd;
+ Pokemon *p;
- return gen3speciestab[species]-1;
+ p = v;
+ if(p->otid == 0)
+ return -1;
+ decryptpokemon(&pd, v);
+ return gen3speciestab[pd.g.species]-1;
}
+
+#pragma varargck type "L" uchar*
+
+static void
+vinit3(void)
+{
+ fmtinstall('L', gen3strfmt);
+}
+
+static int
+vhdr3(char *dst, char *e, void *v, int box)
+{
+ Gen3 *s;
+
+ s = v;
+ dst = seprint(dst, e, "Name: %.*L ID: %d Secret ID: %d\n", sizeof s->tr.name, s->tr.name, s->tr.id, s->tr.secretid);
+ dst = seprint(dst, e, "Game: %s Time Played: %dhr %dmin\n", gnametab[s->type], s->tr.hours, s->tr.min);
+ seprint(dst, e, "Box %d: %.*L\n", box+1, sizeof s->pc.name[box].n, s->pc.name[box].n);
+ return 0;
+}
+
+static int
+vbody3(char *dst, char *e, void *v)
+{
+ Pokemon *p;
+ Pokedat pd;
+ Gen3iv iv;
+
+ p = v;
+ decryptpokemon(&pd, p);
+ dst = seprint(dst, e, "Name: %.*L\n", sizeof p->name, p->name);
+ dst = seprint(dst, e, "OT Name: %.*L OT ID: %ud OT Secret ID: %d\n", sizeof p->otname, p->otname, p->otid, p->otsecretid);
+ dst = seprint(dst, e, "National Dex: %d\n", gen3speciestab[pd.g.species]-1);
+ dst = seprint(dst, e, "Shiny: %d\n", gen3shiny(p));
+ dst = seprint(dst, e, "Exp: %d\n", pd.g.exp);
+ dst = seprint(dst, e, "Move 1: %s Move 2: %s\n", movenametab[pd.a.move1], movenametab[pd.a.move2]);
+ dst = seprint(dst, e, "Move 3: %s Move 4: %s\n", movenametab[pd.a.move3], movenametab[pd.a.move4]);
+ dst = seprint(dst, e, "[EV] HP: %d Atk: %d Def: %d SpA: %d SpD: %d Spe: %d\n", pd.e.hp, pd.e.atk, pd.e.def, pd.e.spatk, pd.e.spdef, pd.e.spd);
+ getgen3iv(&iv, pd.m.iv);
+ seprint(dst, e, "[IV] HP: %d Atk: %d Def: %d SpA: %d SpD: %d Spe: %d\n", iv.hp, iv.atk, iv.def, iv.spatk, iv.spdef, iv.spe);
+ return 0;
+}
+
+static void*
+vboxpk3(int box, int i, void *v)
+{
+ Gen3 *s;
+
+ s = v;
+ return s->pc.box + box*30 + i;
+}
+
+View vgen3 = {
+ vinit3,
+ vhdr3,
+ vdex3,
+ vbody3,
+ vboxpk3,
+};
--- a/gen3.h
+++ /dev/null
@@ -1,63 +1,0 @@
-enum{
- /* Sections */
- STrainer,
- SInvent,
- SState,
- SMisc,
- SRiv,
- SPCA,
- SPCB,
- SPCC,
- SPCD,
- SPCE,
- SPCF,
- SPCG,
- SPCH,
- SPCI,
-
- /* Game Type */
- GRS,
- GFRLG,
- GEM,
-};
-
-extern char* gen3gnametab[];
-
-long getsection(Section*,uchar*);
-long gettrainer(Trainer*,uchar*);
-long getinvent(Invent*,uchar*);
-long getpokedat(Pokedat*,uchar*);
-long getpc(PC*,uchar*);
-
-typedef struct Gen3 Gen3;
-struct Gen3{
- int type;
- Section bank1[14];
- Section bank2[14];
- Section *active;
- Trainer tr;
- Invent inv;
- PC pc;
-
- uchar pcbuf[3968*8 + 2000];
-};
-
-typedef struct Gen3iv Gen3iv;
-struct Gen3iv {
- uchar hp;
- uchar atk;
- uchar def;
- uchar spe;
- uchar spatk;
- uchar spdef;
- uchar egg;
- uchar ability;
-};
-
-void gen3pkstr(uchar *d, uchar *s, int n);
-int gen3strfmt(Fmt*);
-void getgen3(int fd, Gen3 *save);
-void decryptpokemon(Pokedat *dst, Pokemon *src);
-void getgen3iv(Gen3iv *dst, u32int src);
-int getgen3dex(u16int species);
-int gen3shiny(Pokemon*);
--- a/mkfile
+++ b/mkfile
@@ -6,12 +6,14 @@
view\
HFILES=\
- gen3.h\
+ colodat.h\
gen3dat.h\
OFILES=\
+ colo.$O\
gen3.$O\
gen3dat.$O\
+ colodat.$O\
dex.$O\
</sys/src/cmd/mkmany
@@ -18,6 +20,9 @@
gen3dat.c: gen3dat.h
dfc -l $prereq > $target
+
+colodat.c: colodat.h
+ dfc -b $prereq > $target
pokesprite:
git/clone https://github.com/msikma/pokesprite.git
--- /dev/null
+++ b/pse.h
@@ -1,0 +1,81 @@
+enum {
+ Slotszcolo = 0x1E000,
+};
+
+typedef struct Colo Colo;
+struct Colo {
+ uchar slots[3][Slotszcolo];
+ u32int index[3];
+ uchar gcihdr[0x40];
+ uchar decrypted[Slotszcolo];
+
+ uchar *active;
+ Pokemoncolo pc[30*3];
+ Trainercolo tr;
+ u32int money;
+ u32int coupons;
+};
+
+long getpokemoncolo(Pokemoncolo*,uchar*);
+long gettrainercolo(Trainercolo*,uchar*);
+void getcolo(int fd, Colo *dst);
+
+enum{
+ /* Game Data Type */
+ GNONE,
+ GG3,
+ GCOLO,
+
+ /* Gen3 Cart Type */
+ GRS,
+ GFRLG,
+ GEM,
+};
+
+extern char* gnametab[];
+
+long getsection(Section*,uchar*);
+long gettrainer(Trainer*,uchar*);
+long getinvent(Invent*,uchar*);
+long getpokedat(Pokedat*,uchar*);
+long getpc(PC*,uchar*);
+
+typedef struct Gen3 Gen3;
+struct Gen3 {
+ int type;
+ Section bank1[14];
+ Section bank2[14];
+ Section *active;
+ Trainer tr;
+ Invent inv;
+ PC pc;
+
+ uchar pcbuf[3968*8 + 2000];
+};
+
+void gen3pkstr(uchar *d, uchar *p, int n);
+void getgen3(int fd, Gen3 *save);
+void decryptpokemon(Pokedat *dst, Pokemon *src);
+int gen3shiny(Pokemon*);
+
+typedef struct View View;
+struct View {
+ void (*init)(void);
+ int (*hdr)(char *dst, char *e, void *v, int box);
+ int (*dex)(void *v);
+ int (*body)(char *dst, char *e, void *v);
+ void* (*box)(int box, int i, void *v);
+};
+
+extern View vgen3;
+extern View vcolo;
+
+typedef struct Save Save;
+struct Save {
+ View *view;
+ int type;
+ union {
+ Gen3 gen3;
+ Colo colo;
+ };
+};
--- a/view.c
+++ b/view.c
@@ -7,12 +7,13 @@
#include <keyboard.h>
#include <ctype.h>
#include "gen3dat.h"
-#include "gen3.h"
+#include "colodat.h"
+#include "pse.h"
-Gen3 gen3;
+Save save;
int currentbox = 0;
-Pokemon *currentpk = nil;
+void *currentpk = nil;
Point spwd;
Image *background, *light;
@@ -24,65 +25,74 @@
static void
chbox(int x)
{
+ int max;
+
+ switch(save.type){
+ default:
+ case GG3:
+ max = 13;
+ break;
+ case GCOLO:
+ max = 2;
+ break;
+ }
currentbox += x;
if(currentbox < 0)
+ currentbox = max;
+ else if(currentbox > max)
currentbox = 0;
- else if(currentbox > 13)
- currentbox = 13;
}
static int
-screenprint(Point p, char *format, ...)
+screenprint(Point p, char *s)
{
- char buf[256];
- va_list v;
+ char *y, *dot;
+ Point op;
- va_start(v, format);
- vsnprint(buf, sizeof buf, format, v);
- va_end(v);
- string(screen, p, display->black, ZP, display->defaultfont, buf);
- return display->defaultfont->height;
+ op = p;
+ for(y = s; (dot = strchr(y, '\n')) != nil; y = dot+1){
+ *dot = 0;
+ string(screen, p, display->black, ZP, display->defaultfont, y);
+ p.y += display->defaultfont->height;
+ }
+ return p.y - op.y;
}
static void
redraw(void)
{
- char buf[32];
char path[128];
+ char buf[512];
Image *image;
Rectangle r, r2;
- Point p;
- Pokedat pd;
- Gen3iv iv;
int i;
int fd;
+ int dex;
+ void *p;
draw(screen, screen->r, background, nil, ZP);
r = screen->r;
r2 = r;
spwd = Pt(68*2, 56*2);
+ save.view->hdr(buf, buf + sizeof buf, &save.gen3, currentbox);
+ r.min.y += screenprint(r.min, buf);
- r.min.y += screenprint(r.min, "Name: %G ID: %d Secret ID: %d", gen3.tr.name, sizeof gen3.tr.name, gen3.tr.id, gen3.tr.secretid);
- r.min.y += screenprint(r.min, "Game: %s Time Played: %dhr %dmin", gen3gnametab[gen3.type], gen3.tr.hours, gen3.tr.min);
- r.min.y += screenprint(r.min, "Box %d: %G", currentbox+1, gen3.pc.name[currentbox].n, sizeof gen3.pc.name[currentbox].n);
-
if(currentpk == nil)
- currentpk = gen3.pc.box;
+ currentpk = save.view->box(0, 0, &save.gen3);
for(i = 0; i < 30; i++){
r2.min.x = r.min.x + (i%6) * spwd.x;
r2.min.y = r.min.y + (i/6) * spwd.y;
r2.max.x = r2.min.x + spwd.x;
r2.max.y = r2.min.y + spwd.y;
- if(gen3.pc.box + currentbox*30 + i == currentpk)
+ p = save.view->box(currentbox, i, &save.gen3);
+ if(p == currentpk)
draw(screen, r2, light, nil, ZP);
- if(gen3.pc.box[currentbox*30 + i].otid == 0)
+ dex = save.view->dex(p);
+ if(dex > 411 || dex == -1)
continue;
- decryptpokemon(&pd, gen3.pc.box + currentbox*30 + i);
- if(pd.g.species > 411 || getgen3dex(pd.g.species) == -1)
- continue;
- snprint(path, sizeof path, "/sys/games/lib/pokesprite/regular/%s.png", dexfiletab[getgen3dex(pd.g.species)]);
+ snprint(path, sizeof path, "/sys/games/lib/pokesprite/regular/%s.png", dexfiletab[dex]);
- image = spritecache[pd.g.species-1];
+ image = spritecache[dex];
if(image == nil){
fd = open(path, OREAD);
if(fd < 0){
@@ -95,23 +105,13 @@
continue;
}
draw(screen, r2, image, nil, ZP);
- spritecache[pd.g.species-1] = image;
+ spritecache[dex] = image;
}
- decryptpokemon(&pd, currentpk);
r = screen->r;
r.min.x += 6*spwd.x;
-
- r.min.y += screenprint(r.min, "Name: %G", currentpk->name, sizeof currentpk->name);
- r.min.y += screenprint(r.min, "OT Name: %G OT ID: %ud OT Secret ID: %d", currentpk->otname, sizeof currentpk->otname, currentpk->otid, currentpk->otsecretid);
- r.min.y += screenprint(r.min, "National Dex: %d", getgen3dex(pd.g.species));
- r.min.y += screenprint(r.min, "Shiny: %d", gen3shiny(currentpk));
- r.min.y += screenprint(r.min, "Exp: %d", pd.g.exp);
- r.min.y += screenprint(r.min, "Move 1: %s Move 2: %s", movenametab[pd.a.move1], movenametab[pd.a.move2]);
- r.min.y += screenprint(r.min, "Move 3: %s Move 4: %s", movenametab[pd.a.move3], movenametab[pd.a.move4]);
- r.min.y += screenprint(r.min, "[EV] HP: %d Atk: %d Def: %d SpA: %d SpD: %d Spe: %d", pd.e.hp, pd.e.atk, pd.e.def, pd.e.spatk, pd.e.spdef, pd.e.spd);
- getgen3iv(&iv, pd.m.iv);
- r.min.y += screenprint(r.min, "[IV] HP: %d Atk: %d Def: %d SpA: %d SpD: %d Spe: %d", iv.hp, iv.atk, iv.def, iv.spatk, iv.spdef, iv.spe);
+ save.view->body(buf, buf + sizeof buf, currentpk);
+ r.min.y += screenprint(r.min, buf);
flushimage(display, 1);
}
@@ -134,6 +134,7 @@
p.y -= screen->r.min.y;
p.x -= screen->r.min.x;
+ /* FIXME */
p.y -= display->defaultfont->height*3;
p.x /= spwd.x;
@@ -140,7 +141,7 @@
p.y /= spwd.y;
if(p.x + (p.y*6) > 30)
return 0;
- currentpk = gen3.pc.box +currentbox*30 + (p.x + (p.y*6));
+ currentpk = save.view->box(currentbox, (p.x + (p.y*6)), &save.gen3);
return 1;
}
@@ -154,7 +155,7 @@
void
usage(void)
{
- fprint(2, "usage: %s game.sav\n", argv0);
+ fprint(2, "usage: %s [-3c] file\n", argv0);
threadexitsall("usage");
}
@@ -175,11 +176,20 @@
{nil, nil, CHANEND},
};
+ save.type = GNONE;
ARGBEGIN{
+ case '3':
+ save.view = &vgen3;
+ save.type = GG3;
+ break;
+ case 'c':
+ save.view = &vcolo;
+ save.type = GCOLO;
+ break;
default:
usage();
}ARGEND;
- if(argc < 1)
+ if(argc < 1 || save.type == GNONE)
usage();
fd = open(argv[0], OREAD);
@@ -186,8 +196,15 @@
if(fd < 0)
sysfatal("open: %r");
- fmtinstall('G', gen3strfmt);
- getgen3(fd, &gen3);
+ save.view->init();
+ switch(save.type){
+ case GG3:
+ getgen3(fd, &save.gen3);
+ break;
+ case GCOLO:
+ getcolo(fd, &save.colo);
+ break;
+ }
if(initdraw(nil, nil, "pse") < 0)
sysfatal("initdraw: %r");