shithub: pse

Download patch

ref: 01aa306241cded28cf14e20744138a7551a9ff4d
parent: 287fcaf8a0877fb0c2abaadc0ceeda6fe482cc3b
author: Jacob Moody <moody@posixcafe.org>
date: Mon May 15 16:41:42 EDT 2023

initial view implementation

--- /dev/null
+++ b/dex.c
@@ -1,0 +1,895 @@
+#include <u.h>
+#include <libc.h>
+
+char *dexfiletab[] = {
+	[0] "bulbasaur",
+	[1] "ivysaur",
+	[2] "venusaur",
+	[3] "charmander",
+	[4] "charmeleon",
+	[5] "charizard",
+	[6] "squirtle",
+	[7] "wartortle",
+	[8] "blastoise",
+	[9] "caterpie",
+	[10] "metapod",
+	[11] "butterfree",
+	[12] "weedle",
+	[13] "kakuna",
+	[14] "beedrill",
+	[15] "pidgey",
+	[16] "pidgeotto",
+	[17] "pidgeot",
+	[18] "rattata",
+	[19] "raticate",
+	[20] "spearow",
+	[21] "fearow",
+	[22] "ekans",
+	[23] "arbok",
+	[24] "pikachu",
+	[25] "raichu",
+	[26] "sandshrew",
+	[27] "sandslash",
+	[28] "nidoran-f",
+	[29] "nidorina",
+	[30] "nidoqueen",
+	[31] "nidoran-m",
+	[32] "nidorino",
+	[33] "nidoking",
+	[34] "clefairy",
+	[35] "clefable",
+	[36] "vulpix",
+	[37] "ninetales",
+	[38] "jigglypuff",
+	[39] "wigglytuff",
+	[40] "zubat",
+	[41] "golbat",
+	[42] "oddish",
+	[43] "gloom",
+	[44] "vileplume",
+	[45] "paras",
+	[46] "parasect",
+	[47] "venonat",
+	[48] "venomoth",
+	[49] "diglett",
+	[50] "dugtrio",
+	[51] "meowth",
+	[52] "persian",
+	[53] "psyduck",
+	[54] "golduck",
+	[55] "mankey",
+	[56] "primeape",
+	[57] "growlithe",
+	[58] "arcanine",
+	[59] "poliwag",
+	[60] "poliwhirl",
+	[61] "poliwrath",
+	[62] "abra",
+	[63] "kadabra",
+	[64] "alakazam",
+	[65] "machop",
+	[66] "machoke",
+	[67] "machamp",
+	[68] "bellsprout",
+	[69] "weepinbell",
+	[70] "victreebel",
+	[71] "tentacool",
+	[72] "tentacruel",
+	[73] "geodude",
+	[74] "graveler",
+	[75] "golem",
+	[76] "ponyta",
+	[77] "rapidash",
+	[78] "slowpoke",
+	[79] "slowbro",
+	[80] "magnemite",
+	[81] "magneton",
+	[82] "farfetchd",
+	[83] "doduo",
+	[84] "dodrio",
+	[85] "seel",
+	[86] "dewgong",
+	[87] "grimer",
+	[88] "muk",
+	[89] "shellder",
+	[90] "cloyster",
+	[91] "gastly",
+	[92] "haunter",
+	[93] "gengar",
+	[94] "onix",
+	[95] "drowzee",
+	[96] "hypno",
+	[97] "krabby",
+	[98] "kingler",
+	[99] "voltorb",
+	[100] "electrode",
+	[101] "exeggcute",
+	[102] "exeggutor",
+	[103] "cubone",
+	[104] "marowak",
+	[105] "hitmonlee",
+	[106] "hitmonchan",
+	[107] "lickitung",
+	[108] "koffing",
+	[109] "weezing",
+	[110] "rhyhorn",
+	[111] "rhydon",
+	[112] "chansey",
+	[113] "tangela",
+	[114] "kangaskhan",
+	[115] "horsea",
+	[116] "seadra",
+	[117] "goldeen",
+	[118] "seaking",
+	[119] "staryu",
+	[120] "starmie",
+	[121] "mr-mime",
+	[122] "scyther",
+	[123] "jynx",
+	[124] "electabuzz",
+	[125] "magmar",
+	[126] "pinsir",
+	[127] "tauros",
+	[128] "magikarp",
+	[129] "gyarados",
+	[130] "lapras",
+	[131] "ditto",
+	[132] "eevee",
+	[133] "vaporeon",
+	[134] "jolteon",
+	[135] "flareon",
+	[136] "porygon",
+	[137] "omanyte",
+	[138] "omastar",
+	[139] "kabuto",
+	[140] "kabutops",
+	[141] "aerodactyl",
+	[142] "snorlax",
+	[143] "articuno",
+	[144] "zapdos",
+	[145] "moltres",
+	[146] "dratini",
+	[147] "dragonair",
+	[148] "dragonite",
+	[149] "mewtwo",
+	[150] "mew",
+	[151] "chikorita",
+	[152] "bayleef",
+	[153] "meganium",
+	[154] "cyndaquil",
+	[155] "quilava",
+	[156] "typhlosion",
+	[157] "totodile",
+	[158] "croconaw",
+	[159] "feraligatr",
+	[160] "sentret",
+	[161] "furret",
+	[162] "hoothoot",
+	[163] "noctowl",
+	[164] "ledyba",
+	[165] "ledian",
+	[166] "spinarak",
+	[167] "ariados",
+	[168] "crobat",
+	[169] "chinchou",
+	[170] "lanturn",
+	[171] "pichu",
+	[172] "cleffa",
+	[173] "igglybuff",
+	[174] "togepi",
+	[175] "togetic",
+	[176] "natu",
+	[177] "xatu",
+	[178] "mareep",
+	[179] "flaaffy",
+	[180] "ampharos",
+	[181] "bellossom",
+	[182] "marill",
+	[183] "azumarill",
+	[184] "sudowoodo",
+	[185] "politoed",
+	[186] "hoppip",
+	[187] "skiploom",
+	[188] "jumpluff",
+	[189] "aipom",
+	[190] "sunkern",
+	[191] "sunflora",
+	[192] "yanma",
+	[193] "wooper",
+	[194] "quagsire",
+	[195] "espeon",
+	[196] "umbreon",
+	[197] "murkrow",
+	[198] "slowking",
+	[199] "misdreavus",
+	[200] "unown",
+	[201] "wobbuffet",
+	[202] "girafarig",
+	[203] "pineco",
+	[204] "forretress",
+	[205] "dunsparce",
+	[206] "gligar",
+	[207] "steelix",
+	[208] "snubbull",
+	[209] "granbull",
+	[210] "qwilfish",
+	[211] "scizor",
+	[212] "shuckle",
+	[213] "heracross",
+	[214] "sneasel",
+	[215] "teddiursa",
+	[216] "ursaring",
+	[217] "slugma",
+	[218] "magcargo",
+	[219] "swinub",
+	[220] "piloswine",
+	[221] "corsola",
+	[222] "remoraid",
+	[223] "octillery",
+	[224] "delibird",
+	[225] "mantine",
+	[226] "skarmory",
+	[227] "houndour",
+	[228] "houndoom",
+	[229] "kingdra",
+	[230] "phanpy",
+	[231] "donphan",
+	[232] "porygon2",
+	[233] "stantler",
+	[234] "smeargle",
+	[235] "tyrogue",
+	[236] "hitmontop",
+	[237] "smoochum",
+	[238] "elekid",
+	[239] "magby",
+	[240] "miltank",
+	[241] "blissey",
+	[242] "raikou",
+	[243] "entei",
+	[244] "suicune",
+	[245] "larvitar",
+	[246] "pupitar",
+	[247] "tyranitar",
+	[248] "lugia",
+	[249] "ho-oh",
+	[250] "celebi",
+	[251] "treecko",
+	[252] "grovyle",
+	[253] "sceptile",
+	[254] "torchic",
+	[255] "combusken",
+	[256] "blaziken",
+	[257] "mudkip",
+	[258] "marshtomp",
+	[259] "swampert",
+	[260] "poochyena",
+	[261] "mightyena",
+	[262] "zigzagoon",
+	[263] "linoone",
+	[264] "wurmple",
+	[265] "silcoon",
+	[266] "beautifly",
+	[267] "cascoon",
+	[268] "dustox",
+	[269] "lotad",
+	[270] "lombre",
+	[271] "ludicolo",
+	[272] "seedot",
+	[273] "nuzleaf",
+	[274] "shiftry",
+	[275] "taillow",
+	[276] "swellow",
+	[277] "wingull",
+	[278] "pelipper",
+	[279] "ralts",
+	[280] "kirlia",
+	[281] "gardevoir",
+	[282] "surskit",
+	[283] "masquerain",
+	[284] "shroomish",
+	[285] "breloom",
+	[286] "slakoth",
+	[287] "vigoroth",
+	[288] "slaking",
+	[289] "nincada",
+	[290] "ninjask",
+	[291] "shedinja",
+	[292] "whismur",
+	[293] "loudred",
+	[294] "exploud",
+	[295] "makuhita",
+	[296] "hariyama",
+	[297] "azurill",
+	[298] "nosepass",
+	[299] "skitty",
+	[300] "delcatty",
+	[301] "sableye",
+	[302] "mawile",
+	[303] "aron",
+	[304] "lairon",
+	[305] "aggron",
+	[306] "meditite",
+	[307] "medicham",
+	[308] "electrike",
+	[309] "manectric",
+	[310] "plusle",
+	[311] "minun",
+	[312] "volbeat",
+	[313] "illumise",
+	[314] "roselia",
+	[315] "gulpin",
+	[316] "swalot",
+	[317] "carvanha",
+	[318] "sharpedo",
+	[319] "wailmer",
+	[320] "wailord",
+	[321] "numel",
+	[322] "camerupt",
+	[323] "torkoal",
+	[324] "spoink",
+	[325] "grumpig",
+	[326] "spinda",
+	[327] "trapinch",
+	[328] "vibrava",
+	[329] "flygon",
+	[330] "cacnea",
+	[331] "cacturne",
+	[332] "swablu",
+	[333] "altaria",
+	[334] "zangoose",
+	[335] "seviper",
+	[336] "lunatone",
+	[337] "solrock",
+	[338] "barboach",
+	[339] "whiscash",
+	[340] "corphish",
+	[341] "crawdaunt",
+	[342] "baltoy",
+	[343] "claydol",
+	[344] "lileep",
+	[345] "cradily",
+	[346] "anorith",
+	[347] "armaldo",
+	[348] "feebas",
+	[349] "milotic",
+	[350] "castform",
+	[351] "kecleon",
+	[352] "shuppet",
+	[353] "banette",
+	[354] "duskull",
+	[355] "dusclops",
+	[356] "tropius",
+	[357] "chimecho",
+	[358] "absol",
+	[359] "wynaut",
+	[360] "snorunt",
+	[361] "glalie",
+	[362] "spheal",
+	[363] "sealeo",
+	[364] "walrein",
+	[365] "clamperl",
+	[366] "huntail",
+	[367] "gorebyss",
+	[368] "relicanth",
+	[369] "luvdisc",
+	[370] "bagon",
+	[371] "shelgon",
+	[372] "salamence",
+	[373] "beldum",
+	[374] "metang",
+	[375] "metagross",
+	[376] "regirock",
+	[377] "regice",
+	[378] "registeel",
+	[379] "latias",
+	[380] "latios",
+	[381] "kyogre",
+	[382] "groudon",
+	[383] "rayquaza",
+	[384] "jirachi",
+	[385] "deoxys",
+	[386] "turtwig",
+	[387] "grotle",
+	[388] "torterra",
+	[389] "chimchar",
+	[390] "monferno",
+	[391] "infernape",
+	[392] "piplup",
+	[393] "prinplup",
+	[394] "empoleon",
+	[395] "starly",
+	[396] "staravia",
+	[397] "staraptor",
+	[398] "bidoof",
+	[399] "bibarel",
+	[400] "kricketot",
+	[401] "kricketune",
+	[402] "shinx",
+	[403] "luxio",
+	[404] "luxray",
+	[405] "budew",
+	[406] "roserade",
+	[407] "cranidos",
+	[408] "rampardos",
+	[409] "shieldon",
+	[410] "bastiodon",
+	[411] "burmy",
+	[412] "wormadam",
+	[413] "mothim",
+	[414] "combee",
+	[415] "vespiquen",
+	[416] "pachirisu",
+	[417] "buizel",
+	[418] "floatzel",
+	[419] "cherubi",
+	[420] "cherrim",
+	[421] "shellos",
+	[422] "gastrodon",
+	[423] "ambipom",
+	[424] "drifloon",
+	[425] "drifblim",
+	[426] "buneary",
+	[427] "lopunny",
+	[428] "mismagius",
+	[429] "honchkrow",
+	[430] "glameow",
+	[431] "purugly",
+	[432] "chingling",
+	[433] "stunky",
+	[434] "skuntank",
+	[435] "bronzor",
+	[436] "bronzong",
+	[437] "bonsly",
+	[438] "mime-jr",
+	[439] "happiny",
+	[440] "chatot",
+	[441] "spiritomb",
+	[442] "gible",
+	[443] "gabite",
+	[444] "garchomp",
+	[445] "munchlax",
+	[446] "riolu",
+	[447] "lucario",
+	[448] "hippopotas",
+	[449] "hippowdon",
+	[450] "skorupi",
+	[451] "drapion",
+	[452] "croagunk",
+	[453] "toxicroak",
+	[454] "carnivine",
+	[455] "finneon",
+	[456] "lumineon",
+	[457] "mantyke",
+	[458] "snover",
+	[459] "abomasnow",
+	[460] "weavile",
+	[461] "magnezone",
+	[462] "lickilicky",
+	[463] "rhyperior",
+	[464] "tangrowth",
+	[465] "electivire",
+	[466] "magmortar",
+	[467] "togekiss",
+	[468] "yanmega",
+	[469] "leafeon",
+	[470] "glaceon",
+	[471] "gliscor",
+	[472] "mamoswine",
+	[473] "porygon-z",
+	[474] "gallade",
+	[475] "probopass",
+	[476] "dusknoir",
+	[477] "froslass",
+	[478] "rotom",
+	[479] "uxie",
+	[480] "mesprit",
+	[481] "azelf",
+	[482] "dialga",
+	[483] "palkia",
+	[484] "heatran",
+	[485] "regigigas",
+	[486] "giratina",
+	[487] "cresselia",
+	[488] "phione",
+	[489] "manaphy",
+	[490] "darkrai",
+	[491] "shaymin",
+	[492] "arceus",
+	[493] "victini",
+	[494] "snivy",
+	[495] "servine",
+	[496] "serperior",
+	[497] "tepig",
+	[498] "pignite",
+	[499] "emboar",
+	[500] "oshawott",
+	[501] "dewott",
+	[502] "samurott",
+	[503] "patrat",
+	[504] "watchog",
+	[505] "lillipup",
+	[506] "herdier",
+	[507] "stoutland",
+	[508] "purrloin",
+	[509] "liepard",
+	[510] "pansage",
+	[511] "simisage",
+	[512] "pansear",
+	[513] "simisear",
+	[514] "panpour",
+	[515] "simipour",
+	[516] "munna",
+	[517] "musharna",
+	[518] "pidove",
+	[519] "tranquill",
+	[520] "unfezant",
+	[521] "blitzle",
+	[522] "zebstrika",
+	[523] "roggenrola",
+	[524] "boldore",
+	[525] "gigalith",
+	[526] "woobat",
+	[527] "swoobat",
+	[528] "drilbur",
+	[529] "excadrill",
+	[530] "audino",
+	[531] "timburr",
+	[532] "gurdurr",
+	[533] "conkeldurr",
+	[534] "tympole",
+	[535] "palpitoad",
+	[536] "seismitoad",
+	[537] "throh",
+	[538] "sawk",
+	[539] "sewaddle",
+	[540] "swadloon",
+	[541] "leavanny",
+	[542] "venipede",
+	[543] "whirlipede",
+	[544] "scolipede",
+	[545] "cottonee",
+	[546] "whimsicott",
+	[547] "petilil",
+	[548] "lilligant",
+	[549] "basculin",
+	[550] "sandile",
+	[551] "krokorok",
+	[552] "krookodile",
+	[553] "darumaka",
+	[554] "darmanitan",
+	[555] "maractus",
+	[556] "dwebble",
+	[557] "crustle",
+	[558] "scraggy",
+	[559] "scrafty",
+	[560] "sigilyph",
+	[561] "yamask",
+	[562] "cofagrigus",
+	[563] "tirtouga",
+	[564] "carracosta",
+	[565] "archen",
+	[566] "archeops",
+	[567] "trubbish",
+	[568] "garbodor",
+	[569] "zorua",
+	[570] "zoroark",
+	[571] "minccino",
+	[572] "cinccino",
+	[573] "gothita",
+	[574] "gothorita",
+	[575] "gothitelle",
+	[576] "solosis",
+	[577] "duosion",
+	[578] "reuniclus",
+	[579] "ducklett",
+	[580] "swanna",
+	[581] "vanillite",
+	[582] "vanillish",
+	[583] "vanilluxe",
+	[584] "deerling",
+	[585] "sawsbuck",
+	[586] "emolga",
+	[587] "karrablast",
+	[588] "escavalier",
+	[589] "foongus",
+	[590] "amoonguss",
+	[591] "frillish",
+	[592] "jellicent",
+	[593] "alomomola",
+	[594] "joltik",
+	[595] "galvantula",
+	[596] "ferroseed",
+	[597] "ferrothorn",
+	[598] "klink",
+	[599] "klang",
+	[600] "klinklang",
+	[601] "tynamo",
+	[602] "eelektrik",
+	[603] "eelektross",
+	[604] "elgyem",
+	[605] "beheeyem",
+	[606] "litwick",
+	[607] "lampent",
+	[608] "chandelure",
+	[609] "axew",
+	[610] "fraxure",
+	[611] "haxorus",
+	[612] "cubchoo",
+	[613] "beartic",
+	[614] "cryogonal",
+	[615] "shelmet",
+	[616] "accelgor",
+	[617] "stunfisk",
+	[618] "mienfoo",
+	[619] "mienshao",
+	[620] "druddigon",
+	[621] "golett",
+	[622] "golurk",
+	[623] "pawniard",
+	[624] "bisharp",
+	[625] "bouffalant",
+	[626] "rufflet",
+	[627] "braviary",
+	[628] "vullaby",
+	[629] "mandibuzz",
+	[630] "heatmor",
+	[631] "durant",
+	[632] "deino",
+	[633] "zweilous",
+	[634] "hydreigon",
+	[635] "larvesta",
+	[636] "volcarona",
+	[637] "cobalion",
+	[638] "terrakion",
+	[639] "virizion",
+	[640] "tornadus",
+	[641] "thundurus",
+	[642] "reshiram",
+	[643] "zekrom",
+	[644] "landorus",
+	[645] "kyurem",
+	[646] "keldeo",
+	[647] "meloetta",
+	[648] "genesect",
+	[649] "chespin",
+	[650] "quilladin",
+	[651] "chesnaught",
+	[652] "fennekin",
+	[653] "braixen",
+	[654] "delphox",
+	[655] "froakie",
+	[656] "frogadier",
+	[657] "greninja",
+	[658] "bunnelby",
+	[659] "diggersby",
+	[660] "fletchling",
+	[661] "fletchinder",
+	[662] "talonflame",
+	[663] "scatterbug",
+	[664] "spewpa",
+	[665] "vivillon",
+	[666] "litleo",
+	[667] "pyroar",
+	[668] "flabebe",
+	[669] "floette",
+	[670] "florges",
+	[671] "skiddo",
+	[672] "gogoat",
+	[673] "pancham",
+	[674] "pangoro",
+	[675] "furfrou",
+	[676] "espurr",
+	[677] "meowstic",
+	[678] "honedge",
+	[679] "doublade",
+	[680] "aegislash",
+	[681] "spritzee",
+	[682] "aromatisse",
+	[683] "swirlix",
+	[684] "slurpuff",
+	[685] "inkay",
+	[686] "malamar",
+	[687] "binacle",
+	[688] "barbaracle",
+	[689] "skrelp",
+	[690] "dragalge",
+	[691] "clauncher",
+	[692] "clawitzer",
+	[693] "helioptile",
+	[694] "heliolisk",
+	[695] "tyrunt",
+	[696] "tyrantrum",
+	[697] "amaura",
+	[698] "aurorus",
+	[699] "sylveon",
+	[700] "hawlucha",
+	[701] "dedenne",
+	[702] "carbink",
+	[703] "goomy",
+	[704] "sliggoo",
+	[705] "goodra",
+	[706] "klefki",
+	[707] "phantump",
+	[708] "trevenant",
+	[709] "pumpkaboo",
+	[710] "gourgeist",
+	[711] "bergmite",
+	[712] "avalugg",
+	[713] "noibat",
+	[714] "noivern",
+	[715] "xerneas",
+	[716] "yveltal",
+	[717] "zygarde",
+	[718] "diancie",
+	[719] "hoopa",
+	[720] "volcanion",
+	[721] "rowlet",
+	[722] "dartrix",
+	[723] "decidueye",
+	[724] "litten",
+	[725] "torracat",
+	[726] "incineroar",
+	[727] "popplio",
+	[728] "brionne",
+	[729] "primarina",
+	[730] "pikipek",
+	[731] "trumbeak",
+	[732] "toucannon",
+	[733] "yungoos",
+	[734] "gumshoos",
+	[735] "grubbin",
+	[736] "charjabug",
+	[737] "vikavolt",
+	[738] "crabrawler",
+	[739] "crabominable",
+	[740] "oricorio",
+	[741] "cutiefly",
+	[742] "ribombee",
+	[743] "rockruff",
+	[744] "lycanroc",
+	[745] "wishiwashi",
+	[746] "mareanie",
+	[747] "toxapex",
+	[748] "mudbray",
+	[749] "mudsdale",
+	[750] "dewpider",
+	[751] "araquanid",
+	[752] "fomantis",
+	[753] "lurantis",
+	[754] "morelull",
+	[755] "shiinotic",
+	[756] "salandit",
+	[757] "salazzle",
+	[758] "stufful",
+	[759] "bewear",
+	[760] "bounsweet",
+	[761] "steenee",
+	[762] "tsareena",
+	[763] "comfey",
+	[764] "oranguru",
+	[765] "passimian",
+	[766] "wimpod",
+	[767] "golisopod",
+	[768] "sandygast",
+	[769] "palossand",
+	[770] "pyukumuku",
+	[771] "type-null",
+	[772] "silvally",
+	[773] "minior",
+	[774] "komala",
+	[775] "turtonator",
+	[776] "togedemaru",
+	[777] "mimikyu",
+	[778] "bruxish",
+	[779] "drampa",
+	[780] "dhelmise",
+	[781] "jangmo-o",
+	[782] "hakamo-o",
+	[783] "kommo-o",
+	[784] "tapu-koko",
+	[785] "tapu-lele",
+	[786] "tapu-bulu",
+	[787] "tapu-fini",
+	[788] "cosmog",
+	[789] "cosmoem",
+	[790] "solgaleo",
+	[791] "lunala",
+	[792] "nihilego",
+	[793] "buzzwole",
+	[794] "pheromosa",
+	[795] "xurkitree",
+	[796] "celesteela",
+	[797] "kartana",
+	[798] "guzzlord",
+	[799] "necrozma",
+	[800] "magearna",
+	[801] "marshadow",
+	[802] "poipole",
+	[803] "naganadel",
+	[804] "stakataka",
+	[805] "blacephalon",
+	[806] "zeraora",
+	[807] "meltan",
+	[808] "melmetal",
+	[809] "grookey",
+	[810] "thwackey",
+	[811] "rillaboom",
+	[812] "scorbunny",
+	[813] "raboot",
+	[814] "cinderace",
+	[815] "sobble",
+	[816] "drizzile",
+	[817] "inteleon",
+	[818] "skwovet",
+	[819] "greedent",
+	[820] "rookidee",
+	[821] "corvisquire",
+	[822] "corviknight",
+	[823] "blipbug",
+	[824] "dottler",
+	[825] "orbeetle",
+	[826] "nickit",
+	[827] "thievul",
+	[828] "gossifleur",
+	[829] "eldegoss",
+	[830] "wooloo",
+	[831] "dubwool",
+	[832] "chewtle",
+	[833] "drednaw",
+	[834] "yamper",
+	[835] "boltund",
+	[836] "rolycoly",
+	[837] "carkol",
+	[838] "coalossal",
+	[839] "applin",
+	[840] "flapple",
+	[841] "appletun",
+	[842] "silicobra",
+	[843] "sandaconda",
+	[844] "cramorant",
+	[845] "arrokuda",
+	[846] "barraskewda",
+	[847] "toxel",
+	[848] "toxtricity",
+	[849] "sizzlipede",
+	[850] "centiskorch",
+	[851] "clobbopus",
+	[852] "grapploct",
+	[853] "sinistea",
+	[854] "polteageist",
+	[855] "hatenna",
+	[856] "hattrem",
+	[857] "hatterene",
+	[858] "impidimp",
+	[859] "morgrem",
+	[860] "grimmsnarl",
+	[861] "obstagoon",
+	[862] "perrserker",
+	[863] "cursola",
+	[864] "sirfetch'd",
+	[865] "mr.-rime",
+	[866] "runerigus",
+	[867] "milcery",
+	[868] "alcremie",
+	[869] "falinks",
+	[870] "pincurchin",
+	[871] "snom",
+	[872] "frosmoth",
+	[873] "stonjourner",
+	[874] "eiscue",
+	[875] "indeedee",
+	[876] "morpeko",
+	[877] "cufant",
+	[878] "copperajah",
+	[879] "dracozolt",
+	[880] "arctozolt",
+	[881] "dracovish",
+	[882] "arctovish",
+	[883] "duraludon",
+	[884] "dreepy",
+	[885] "drakloak",
+	[886] "dragapult",
+	[887] "zacian",
+	[888] "zamazenta",
+	[889] "eternatus",
+};
--- /dev/null
+++ b/fs.c
@@ -1,0 +1,111 @@
+#include <u.h>
+#include <libc.h>
+#include <fcall.h>
+#include <thread.h>
+#include <9p.h>
+#include "gen3dat.h"
+#include "gen3.h"
+
+Gen3 gen3;
+
+enum { Qtrainer, Qpokemon };
+typedef struct Xfile Xfile;
+struct Xfile {
+	int type;
+	union {
+		Pokemon *p;
+		Invent *i;
+		Trainer *tr;
+	};
+};
+
+static void
+fsread(Req *r)
+{
+	Xfile *f;
+	char buf[8192];
+	uchar str[64];
+	Pokedat pd;
+	char *p, *e;
+
+	f = r->fid->file->aux;
+	p = buf;
+	e = buf + sizeof buf;
+
+	switch(f->type){
+	case Qtrainer:
+		gen3pkstr(str, f->tr->name, sizeof f->tr->name);
+		seprint(p, e, "%s\t%d\t%d\n", (char*)str, f->tr->id, f->tr->secretid);
+		break;
+	case Qpokemon:
+		decryptpokemon(&pd, f->p);
+		gen3pkstr(str, f->p->name, sizeof f->p->name);
+		seprint(p, e, "%s\t%d\n", (char*)str, pd.g.species);
+		break;
+	}
+	readstr(r, buf);
+	respond(r, nil);
+}
+
+Srv fs = {
+.read = fsread,
+};
+
+static void
+usage(void)
+{
+	fprint(2, "usage: %s [-s srv] [-m mtpt] file.sav\n", argv0);
+	exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+	int fd;
+	int j;
+	Xfile *xf;
+	File *box;
+	char *user;
+	char *mtpt, *srvname;
+
+	srvname = nil;
+	mtpt = "/mnt/pse";
+	ARGBEGIN{
+	case 's':
+		srvname = EARGF(usage());
+		break;
+	case 'm':
+		mtpt = EARGF(usage());
+		break;
+	default:
+		usage();
+	}ARGEND;
+	if(argc < 1)
+		usage();
+
+	fd = open(argv[0], OREAD);
+	if(fd < 0)
+		sysfatal("open: %r");
+
+	getgen3(fd, &gen3);
+
+	user = getenv("user");
+	fs.tree = alloctree(user, "sys", DMDIR|0555, nil);
+	box = createfile(fs.tree->root, "box", user, DMDIR|0555, nil);
+
+	xf = mallocz(sizeof *xf, 1);
+	xf->type = Qtrainer;
+	xf->tr = &gen3.tr;
+	createfile(fs.tree->root, "trainer", user, 0444, xf);
+
+	for(j = 0; j < 420; j++){
+		if(gen3.pc.box[j].personality == 0 && gen3.pc.box[j].otid == 0)
+			continue;
+		xf = mallocz(sizeof *xf, 1);
+		xf->type = Qpokemon;
+		xf->p = &gen3.pc.box[j];
+		createfile(box, smprint("%d", j), user, 0444, xf);
+	}
+	postmountsrv(&fs, srvname, mtpt, MREPL);
+	exits(nil);
+}
--- a/gen3.c
+++ b/gen3.c
@@ -1,8 +1,6 @@
 #include <u.h>
 #include <libc.h>
-#include <fcall.h>
-#include <thread.h>
-#include <9p.h>
+#include "gen3dat.h"
 #include "gen3.h"
 
 int poketab[24][4] = {
@@ -32,43 +30,6 @@
 	{24, 36, 12, 0},
 };
 
-enum{
-	STrainer,
-	SInvent,
-	SState,
-	SMisc,
-	SRiv,
-	SPCA,
-	SPCB,
-	SPCC,
-	SPCD,
-	SPCE,
-	SPCF,
-	SPCG,
-	SPCH,
-	SPCI,
-};
-
-typedef struct Save Save;
-struct Save{
-	Section bank1[14];
-	Section bank2[14];
-	Section *active;
-	Trainer tr;
-	Invent inv;
-	PC pc;
-};
-
-Save save;
-
-uchar pcbuf[3968*8 + 2000];
-
-long getsection(Section*,uchar*);
-long gettrainer(Trainer*,uchar*);
-long getinvent(Invent*,uchar*);
-long getpokedat(Pokedat*,uchar*);
-long getpc(PC*,uchar*);
-
 #define PUT4(p, u) (p)[3] = (u)>>24, (p)[2] = (u)>>16, (p)[1] = (u)>>8, (p)[0] = (u)
 
 static void
@@ -82,11 +43,10 @@
 		b[i] = b[i] ^ key[i%4];
 }
 
-static Pokedat
-decryptpokemon(Pokemon *src)
+void
+decryptpokemon(Pokedat *dst, Pokemon *src)
 {
 	uchar buf[12*4];
-	Pokedat ret;
 	int *t;
 
 	t = poketab[src->personality % nelem(poketab)];
@@ -95,17 +55,15 @@
 	memcpy(buf + t[2], src->data + 24, 12);
 	memcpy(buf + t[3], src->data + 36, 12);
 	cryptpokedat(buf, src->otid, src->personality);
-	assert(getpokedat(&ret, buf) == sizeof buf);
-	return ret;
+	assert(getpokedat(dst, buf) == sizeof buf);
 }
 
-static char*
-pkstr(uchar *p, uchar *e)
+void
+gen3pkstr(uchar *d, uchar *p, int n)
 {
-	char out[16];
-	char *d;
+	uchar *e;
 
-	for(d = out; p < e && *p != 0xFF; p++){
+	for(e = p+n; p<e && *p != 0xFF; p++){
 		if(*p >= 0xA1 && *p <= 0xAA)
 			*d++ = '0' + (*p - 0xA1);
 		else if(*p >= 0xBB && *p <= 0xD4)
@@ -114,138 +72,47 @@
 			*d++ = 'a' + (*p - 0xD5);
 	}
 	*d = 0;
-	return strdup(out);
 }
 
-enum { Qtrainer, Qpokemon };
-typedef struct Xfile Xfile;
-struct Xfile {
-	int type;
-	union {
-		Pokemon *p;
-		Invent *i;
-		Trainer *tr;
-	};
-};
-
-static void
-fsread(Req *r)
-{
-	Xfile *f;
-	char buf[8192];
-	Pokedat pd;
-	char *p, *e;
-
-	f = r->fid->file->aux;
-	p = buf;
-	e = buf + sizeof buf;
-
-	switch(f->type){
-	case Qtrainer:
-		seprint(p, e, "%s\t%d\t%d\n", pkstr(f->tr->name, f->tr->name + 7), f->tr->id, f->tr->secretid);
-		break;
-	case Qpokemon:
-		pd = decryptpokemon(f->p);
-		seprint(p, e, "%s\t%d\n", pkstr(f->p->name, f->p->name + 10), pd.g.species);
-		break;
-	}
-	readstr(r, buf);
-	respond(r, nil);
-}
-
-Srv fs = {
-.read = fsread,
-};
-
-static void
-usage(void)
-{
-	fprint(2, "usage: %s [-s srv] [-m mtpt] file.sav\n", argv0);
-	exits("usage");
-}
-
 void
-main(int argc, char **argv)
+getgen3(int fd, Gen3 *save)
 {
-	int fd;
 	int i, j;
 	uchar buf[8192];
-	Xfile *xf;
-	File *box;
-	char *user;
-	char *mtpt, *srvname;
 
-	srvname = nil;
-	mtpt = "/mnt/gen3";
-	ARGBEGIN{
-	case 's':
-		srvname = EARGF(usage());
-		break;
-	case 'm':
-		mtpt = EARGF(usage());
-		break;
-	default:
-		usage();
-	}ARGEND;
-	if(argc < 1)
-		usage();
-
-	fd = open(argv[0], OREAD);
-	if(fd < 0)
-		sysfatal("open: %r");
-
 	for(i = 0; i < 14; i++){
 		if(readn(fd, buf, 4096) != 4096)
 			sysfatal("unexpected eof");
-		getsection(save.bank1 + i, buf);
+		getsection(save->bank1 + i, buf);
 	}
-
 	seek(fd, 0xE000, 0);
 	for(i = 0; i < 14; i++){
 		if(readn(fd, buf, 4096) != 4096)
 			sysfatal("unexpected eof");
-		getsection(save.bank2 + i, buf);
+		getsection(save->bank2 + i, buf);
 	}
-	save.active = save.bank1[0].index > save.bank2[0].index ? save.bank1 : save.bank2;
+	save->active = save->bank1[0].index > save->bank2[0].index ? save->bank1 : save->bank2;
 
-	user = getenv("user");
-	fs.tree = alloctree(user, "sys", DMDIR|0555, nil);
-	box = createfile(fs.tree->root, "box", user, DMDIR|0555, nil);
-
 	for(i = 0; i < 14; i++){
-		switch(save.active[i].id){
+		switch(save->active[i].id){
 		case STrainer:
-			gettrainer(&save.tr, save.active[i].data);
-			xf = mallocz(sizeof *xf, 1);
-			xf->type = Qtrainer;
-			xf->tr = &save.tr;
-			createfile(fs.tree->root, "trainer", user, 0444, xf);
+			gettrainer(&save->tr, save->active[i].data);
 			break;
 		case SInvent:
-			getinvent(&save.inv, save.active[i].data + 0x34);
+			getinvent(&save->inv, save->active[i].data + 0x34);
 			break;
 		case SState: case SMisc: case SRiv:
 			break;
 		default:
-			j = save.active[i].id - SPCA;
+			j = save->active[i].id - SPCA;
 			if(j >= 0 && j < 8)
-				memcpy(pcbuf + j * 3968, save.active[i].data, 3968);
+				memcpy(save->pcbuf + j * 3968, save->active[i].data, 3968);
 			else if(j == 8)
-				memcpy(pcbuf + 8 * 3968, save.active[i].data, 2000);
+				memcpy(save->pcbuf + 8 * 3968, save->active[i].data, 2000);
 			else
 				sysfatal("invalid section");
 		}
 	}
 
-	getpc(&save.pc, pcbuf);
-	for(j = 0; j < 420; j++){
-		if(save.pc.box[j].personality == 0 && save.pc.box[j].otid == 0)
-			continue;
-		xf = mallocz(sizeof *xf, 1);
-		xf->type = Qpokemon;
-		xf->p = &save.pc.box[j];
-		createfile(box, smprint("%d", j), user, 0444, xf);
-	}
-	postmountsrv(&fs, srvname, mtpt, MREPL);
-	exits(nil);
+	getpc(&save->pc, save->pcbuf);
 }
--- a/gen3.h
+++ b/gen3.h
@@ -1,121 +1,45 @@
-typedef struct Section Section;
-typedef struct Trainer Trainer;
-typedef struct Pokemon Pokemon;
-typedef struct Invent Invent;
-typedef struct InventPokemon InventPokemon;
+enum{
+	/* Sections */
+	STrainer,
+	SInvent,
+	SState,
+	SMisc,
+	SRiv,
+	SPCA,
+	SPCB,
+	SPCC,
+	SPCD,
+	SPCE,
+	SPCF,
+	SPCG,
+	SPCH,
+	SPCI,
 
-typedef struct Blocka Blocka;
-typedef struct Blockg Blockg;
-typedef struct Blockm Blockm;
-typedef struct Blocke Blocke;
-typedef struct Pokedat Pokedat;
-
-typedef struct Boxname Boxname;
-typedef struct PC PC;
-
-struct Section {
-	uchar data[4084];
-	u16int id;
-	u16int chk;
-	u32int pad;
-	u32int index;
+	/* Game Type */
+	GRS,
+	GFRLG,
+	GEM,
 };
 
-struct Trainer {
-	uchar name[7];
-	uchar gender;
-	u16int pad0;
-	u16int id;
-	u16int secretid;
-	u16int hours;
-	uchar min;
-	uchar sec;
-	uchar frame;
-	uchar button;
-	uchar text;
-	uchar misc;
-	uchar pad1[150];
-	u32int gamecode;
-};
+long getsection(Section*,uchar*);
+long gettrainer(Trainer*,uchar*);
+long getinvent(Invent*,uchar*);
+long getpokedat(Pokedat*,uchar*);
+long getpc(PC*,uchar*);
 
-struct Blockg {
-	u16int species;
-	u16int item;
-	u32int exp;
-	uchar ppbonus;
-	uchar friendship;
-	u16int magic;
-};
+typedef struct Gen3 Gen3;
+struct Gen3{
+	int type;
+	Section bank1[14];
+	Section bank2[14];
+	Section *active;
+	Trainer tr;
+	Invent inv;
+	PC pc;
 
-struct Blocka {
-	u16int move1;
-	u16int move2;
-	u16int move3;
-	u16int move4;
-	uchar pp[4];
+	uchar pcbuf[3968*8 + 2000];
 };
 
-struct Blockm {
-	uchar pokerus;
-	uchar met;
-	u16int origins;
-	u32int iv;
-	u32int ribbions;
-};
-
-struct Blocke {
-	uchar hp;
-	uchar atk;
-	uchar def;
-	uchar spd;
-	uchar spatk;
-	uchar spdef;
-	uchar cool;
-	uchar beauty;
-	uchar cute;
-	uchar smart;
-	uchar tough;
-	uchar feel;
-};
-
-struct Pokedat {
-	Blockg g;
-	Blocka a;
-	Blockm m;
-	Blocke e;
-};
-
-struct Pokemon {
-	u32int personality;
-	u32int otid;
-	uchar name[10];
-	u16int lang;
-	uchar otname[7];
-	uchar marks;
-	u16int chk;
-	u16int magic;
-	uchar data[48];
-};
-
-struct InventPokemon {
-	Pokemon p;
-	uchar derived[20];
-};
-
-struct Invent {
-	u32int teamsz;
-	InventPokemon team[6];
-	u32int money;
-	u16int coins;
-};
-
-struct Boxname {
-	uchar n[9];
-};
-
-struct PC {
-	u32int current;
-	Pokemon box[420];
-	Boxname name[14];
-	uchar wallpaper[14];
-};
+void gen3pkstr(uchar *d, uchar *s, int n);
+void getgen3(int fd, Gen3 *save);
+void decryptpokemon(Pokedat *dst, Pokemon *src);
--- a/gen3dat.c
+++ b/gen3dat.c
@@ -1,6 +1,6 @@
 #include <u.h>
 #include <libc.h>
-#include "gen3.h"
+#include "gen3dat.h"
 
 #define GET2(p) (u16int)(p)[0] | (u16int)(p)[1]<<8
 #define PUT2(p, u) (p)[1] = (u)>>8, (p)[0] = (u)
--- /dev/null
+++ b/gen3dat.h
@@ -1,0 +1,121 @@
+typedef struct Section Section;
+typedef struct Trainer Trainer;
+typedef struct Pokemon Pokemon;
+typedef struct Invent Invent;
+typedef struct InventPokemon InventPokemon;
+
+typedef struct Blocka Blocka;
+typedef struct Blockg Blockg;
+typedef struct Blockm Blockm;
+typedef struct Blocke Blocke;
+typedef struct Pokedat Pokedat;
+
+typedef struct Boxname Boxname;
+typedef struct PC PC;
+
+struct Section {
+	uchar data[4084];
+	u16int id;
+	u16int chk;
+	u32int pad;
+	u32int index;
+};
+
+struct Trainer {
+	uchar name[7];
+	uchar gender;
+	u16int pad0;
+	u16int id;
+	u16int secretid;
+	u16int hours;
+	uchar min;
+	uchar sec;
+	uchar frame;
+	uchar button;
+	uchar text;
+	uchar misc;
+	uchar pad1[150];
+	u32int gamecode;
+};
+
+struct Blockg {
+	u16int species;
+	u16int item;
+	u32int exp;
+	uchar ppbonus;
+	uchar friendship;
+	u16int magic;
+};
+
+struct Blocka {
+	u16int move1;
+	u16int move2;
+	u16int move3;
+	u16int move4;
+	uchar pp[4];
+};
+
+struct Blockm {
+	uchar pokerus;
+	uchar met;
+	u16int origins;
+	u32int iv;
+	u32int ribbions;
+};
+
+struct Blocke {
+	uchar hp;
+	uchar atk;
+	uchar def;
+	uchar spd;
+	uchar spatk;
+	uchar spdef;
+	uchar cool;
+	uchar beauty;
+	uchar cute;
+	uchar smart;
+	uchar tough;
+	uchar feel;
+};
+
+struct Pokedat {
+	Blockg g;
+	Blocka a;
+	Blockm m;
+	Blocke e;
+};
+
+struct Pokemon {
+	u32int personality;
+	u32int otid;
+	uchar name[10];
+	u16int lang;
+	uchar otname[7];
+	uchar marks;
+	u16int chk;
+	u16int magic;
+	uchar data[48];
+};
+
+struct InventPokemon {
+	Pokemon p;
+	uchar derived[20];
+};
+
+struct Invent {
+	u32int teamsz;
+	InventPokemon team[6];
+	u32int money;
+	u16int coins;
+};
+
+struct Boxname {
+	uchar n[9];
+};
+
+struct PC {
+	u32int current;
+	Pokemon box[420];
+	Boxname name[14];
+	uchar wallpaper[14];
+};
--- a/mkfile
+++ b/mkfile
@@ -1,15 +1,35 @@
 </$objtype/mkfile
 
-BIN=$home/bin/$objtype
-TARG=pse
+BIN=$home/bin/$objtype/pse
+TARG=\
+	fs\
+	view\
+
 HFILES=\
 	gen3.h\
+	gen3dat.h\
 
 OFILES=\
 	gen3.$O\
 	gen3dat.$O\
+	dex.$O\
 
-</sys/src/cmd/mkone
+</sys/src/cmd/mkmany
 
-gen3dat.c: gen3.h
+gen3dat.c: gen3dat.h
 	dfc -l $prereq > $target
+
+pokesprite:
+	git/clone https://github.com/msikma/pokesprite.git
+
+installsprite:	pokesprite
+	mkdir -p sprite/regular
+	for(i in pokesprite/pokemon-gen7x/regular/*.png)
+		png -tc $i | resize -n '-x200%' '-y200%' > sprite/regular/^`{basename $i}
+	mkdir -p /sys/games/lib/pokesprite
+	clone sprite/* /sys/games/lib/pokesprite
+
+install:V:
+	mkdir -p $BIN
+	for(i in $TARG)
+		mk $MKFLAGS $i.install
--- /dev/null
+++ b/view.c
@@ -1,0 +1,245 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <thread.h>
+#include <mouse.h>
+#include <cursor.h>
+#include <keyboard.h>
+#include <ctype.h>
+#include "gen3dat.h"
+#include "gen3.h"
+
+Gen3 gen3;
+
+static void
+mklower(char *d, char *e, char *s)
+{
+	assert(d <= e-1);
+	for(; *s != 0 && d < e-1; s++){
+		if(!isascii(*s))
+			continue;
+		*d++ = tolower(*s);
+	}
+	*d = 0;
+}
+
+int currentbox = 0;
+Pokemon *currentpk = nil;
+Point spwd;
+Image *background, *light;
+
+extern char *dexfiletab[];
+
+static void
+chbox(int x)
+{
+	currentbox += x;
+	if(currentbox < 0)
+		currentbox = 0;
+	else if(currentbox > 13)
+		currentbox = 13;
+}
+
+static void
+redraw(void)
+{
+	char buf[32];
+	char path[128];
+	Image *image;
+	Rectangle r, r2;
+	Pokedat pd;
+	int i;
+	int fd;
+
+	draw(screen, screen->r, background, nil, ZP);
+	r = screen->r;
+	r2 = r;
+	spwd = Pt(68*2, 56*2);
+
+	gen3pkstr((uchar*)buf, gen3.tr.name, sizeof gen3.tr.name);
+	snprint(path, sizeof path, "Name: %s  ID: %d  Secret ID: %d", buf, gen3.tr.id, gen3.tr.secretid);
+	string(screen, r.min, display->black, ZP, display->defaultfont, path);
+	r.min.y += display->defaultfont->height;
+	snprint(path, sizeof path, "Time Played: %dhr %dmin", gen3.tr.hours, gen3.tr.min);
+	string(screen, r.min, display->black, ZP, display->defaultfont, path);
+	r.min.y += display->defaultfont->height;
+	gen3pkstr((uchar*)buf, gen3.pc.name[currentbox].n, sizeof gen3.pc.name[currentbox].n);
+	snprint(path, sizeof path, "Box %d: %s", currentbox+1, buf);
+	string(screen, r.min, display->black, ZP, display->defaultfont, path);
+	r.min.y += display->defaultfont->height;
+
+	if(currentpk == nil)
+		currentpk = gen3.pc.box;
+	for(i = 0; i < 30; i++){
+		if(gen3.pc.box[currentbox*30 + i].otid == 0)
+			continue;
+		decryptpokemon(&pd, gen3.pc.box + currentbox*30 + i);
+		if(pd.g.species > 251)
+			pd.g.species -= 0x19;
+		//fprint(2, "%d %s\n", pd.g.species, dexfiletab[pd.g.species]);
+		snprint(path, sizeof path, "/sys/games/lib/pokesprite/regular/%s.png", dexfiletab[pd.g.species-1]);
+		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)
+			draw(screen, r2, light, nil, ZP);
+
+		//fprint(2, "opening %s\n", path);
+		fd = open(path, OREAD);
+		if(fd < 0){
+			fprint(2, "could not open %s\n", path);
+			continue;
+		}
+		image = readimage(display, fd, 0);
+		close(fd);
+		if(image == nil)
+			continue;
+		draw(screen, r2, image, nil, ZP);
+		freeimage(image);
+	}
+
+	decryptpokemon(&pd, currentpk);
+	r = screen->r;
+	r.min.x += 6*spwd.x;
+
+	snprint(path, sizeof path, "Species: %d", pd.g.species);
+	string(screen, r.min, display->black, ZP, display->defaultfont, path);
+	r.min.y += display->defaultfont->height;
+	snprint(path, sizeof path, "Exp: %d", pd.g.exp);
+	string(screen, r.min, display->black, ZP, display->defaultfont, path);
+	r.min.y += display->defaultfont->height;
+	snprint(path, sizeof path, "Move 1: %d  Move 2: %d  Move 3: %d  Move 4: %d", pd.a.move1, pd.a.move2, pd.a.move3, pd.a.move4);
+	string(screen, r.min, display->black, ZP, display->defaultfont, path);
+	r.min.y += display->defaultfont->height;
+
+	snprint(path, sizeof path, "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);
+	string(screen, r.min, display->black, ZP, display->defaultfont, path);
+	r.min.y += display->defaultfont->height;
+
+	flushimage(display, 1);
+}
+
+static int
+click(Mouse *m)
+{
+	Point p;
+
+	if((m->buttons&(1<<3)) != 0){
+		chbox(-1);
+		return 1;
+	} else if((m->buttons&(1<<4)) != 0){
+		chbox(1);
+		return 1;
+	}
+	if((m->buttons&1) == 0)
+		return 0;
+	p = m->xy;
+
+	p.y -= screen->r.min.y;
+	p.x -= screen->r.min.x;
+
+	p.y -= display->defaultfont->height*3;
+
+	p.x /= spwd.x;
+	p.y /= spwd.y;
+	if(p.x + (p.y*6) > 30)
+		return 0;
+	currentpk = gen3.pc.box +currentbox*30 + (p.x + (p.y*6));
+	return 1;
+}
+
+enum{
+	Ckey,
+	Cmouse,
+	Cresize,
+	Numchan,
+};
+
+void
+usage(void)
+{
+	fprint(2, "usage: %s game.sav\n", argv0);
+	threadexitsall("usage");
+}
+
+mainstacksize = 8192*16;
+
+void
+threadmain(int argc, char **argv)
+{
+	Mousectl *mctl;
+	Keyboardctl *kctl;
+	Rune r;
+	Mouse m;
+	int fd;
+	Alt a[Numchan+1] = {
+		[Ckey] = {nil, &r, CHANRCV},
+		[Cmouse] = {nil, &m, CHANRCV },
+		[Cresize] = {nil, nil, CHANRCV},
+		{nil, nil, CHANEND},
+	};
+
+	ARGBEGIN{
+	default:
+		usage();
+	}ARGEND;
+	if(argc < 1)
+		usage();
+
+	fd = open(argv[0], OREAD);
+	if(fd < 0)
+		sysfatal("open: %r");
+
+	getgen3(fd, &gen3);
+
+	if(initdraw(nil, nil, "pse") < 0)
+		sysfatal("initdraw: %r");
+	if((kctl = initkeyboard(nil)) == nil)
+		sysfatal("initkeyboard: %r");
+	a[Ckey].c = kctl->c;
+	if((mctl = initmouse(nil, screen)) == nil)
+		sysfatal("initmouse: %r");
+	a[Cmouse].c = mctl->c;
+	a[Cresize].c = mctl->resizec;
+
+	light = allocimagemix(display, DMedblue, DWhite);
+	background = allocimagemix(display, DPaleyellow, DWhite);
+
+	redraw();
+	for(;;){
+		switch(alt(a)){
+		case -1:
+			goto end;
+		case Ckey:
+			switch (r) {
+			case 'w':
+				chbox(-1);
+				redraw();
+				break;
+			case 'e':
+				chbox(1);
+				redraw();
+				break;
+			case Kdel:
+			case 'q':
+				goto end;
+				break;
+			}
+			break;
+
+		case Cmouse:
+			if(click(&m))
+				redraw();
+			break;
+
+		case Cresize:
+			getwindow(display, Refnone);
+			redraw();
+			break;
+		}
+	}
+end:
+	threadexitsall(nil);
+}