Text to .CHT?

General area for talk about ZSNES. The best place to ask for related questions as well as troubleshooting.

Moderator: ZSNES Mods

DrGhastly

Text to .CHT?

Post by DrGhastly »

There are tons of programs that "extract" the codes from .cht files and save them as plain text, but how about vice versa? Something that would, allow for easily copying a GG code found online into the clipboard and pasting it into the program, which, in turn would convert it to a .cht file?

I actually found one such program... or rather one that claims to work that way. Unfortunately, it doesn't really work at all - when I try to paste a code into it, it immediately crashes with "Runtime error 521"... So, I'm looking for something that really works (a *program*, mind you, not a "perl script"... (?) :) )

(Better yet, just change the .cht format for future releases of ZSNES, so that it's a pure, easily editable, user friendly text file... :P)
Bacon
Hazed
Posts: 61
Joined: Thu Sep 23, 2004 4:10 am
Location: Canada

Re: Text to .CHT?

Post by Bacon »

DrGhastly wrote: (Better yet, just change the .cht format for future releases of ZSNES, so that it's a pure, easily editable, user friendly text file... :P)
I highly doubt this will happen, fyi
Noxious Ninja
Dark Wind
Posts: 1271
Joined: Thu Jul 29, 2004 8:58 pm
Location: Texas
Contact:

Post by Noxious Ninja »

There are "tons" of programs? I've only heard of mine and jdratlif's. What other ones are there?

Anyway, it shouldn't be too hard. Once I'm a bit more comfortable with Qt I'll try and whip something up.
Bacon wrote:
DrGhastly wrote: (Better yet, just change the .cht format for future releases of ZSNES, so that it's a pure, easily editable, user friendly text file... :P)
I highly doubt this will happen, fyi
It could very well happen.
[u][url=http://bash.org/?577451]#577451[/url][/u]
Nach
ZSNES Developer
ZSNES Developer
Posts: 3904
Joined: Tue Jul 27, 2004 10:54 pm
Location: Solar powered park bench
Contact:

Post by Nach »

It is very easy to turn text into a cheat file, simply use a hex editor.
May 9 2007 - NSRT 3.4, now with lots of hashing and even more accurate information! Go download it.
_____________
Insane Coding
emcee
Rookie
Posts: 17
Joined: Sun Oct 23, 2005 11:09 pm

I'll make one.

Post by emcee »

I know this is an old post but I came here looking for the specs for zsnes cht files, but couldn't find it. However if someone to gives me the specs or a link them, I'll write a program to do this right now.

P.S. And yes it will be a perl script, but also a "real program" with a GUI and everything.
Aerdan
Winter Knight
Posts: 467
Joined: Mon Aug 16, 2004 10:16 pm
Contact:

Post by Aerdan »

Read the sources to a .cht to text application.
emcee
Rookie
Posts: 17
Joined: Sun Oct 23, 2005 11:09 pm

Just did that

Post by emcee »

Aerdan wrote:Read the sources to a .cht to text application.
Actually I just did that and I was coming back to say I figured it out. What was harder was figuring out the specs for decoding game genie codes, but I got that now too, so I guess I'll see what I can throw together.
Aerdan
Winter Knight
Posts: 467
Joined: Mon Aug 16, 2004 10:16 pm
Contact:

Post by Aerdan »

Please be aware that ZSNES doesn't know/mind/care whether a given code is or isn't a GG code [there's no magic bit that tells it OMG THATS A GG CODE].
emcee
Rookie
Posts: 17
Joined: Sun Oct 23, 2005 11:09 pm

Post by emcee »

Aerdan wrote:Please be aware that ZSNES doesn't know/mind/care whether a given code is or isn't a GG code [there's no magic bit that tells it OMG THATS A GG CODE].
It seems that regardless of what type of code you give zsnes it stores it in the cht file as an address and value, so to create a cht code from a gg code it first has to be decoded into a hex address and value. Something I thought I figured out, but now I'm not sure. I got past the substitution cipher, but now I'm supposed to do a transposition cipher, but even if I did figure out how to get them in the right order, some character aren't even the same.
emcee
Rookie
Posts: 17
Joined: Sun Oct 23, 2005 11:09 pm

Ok, now I got it

Post by emcee »

Ok, I think I got this whole gg to hex business figured out.
PHoNyMiKe
Retrosexual
Posts: 1011
Joined: Wed Jul 28, 2004 2:09 am
Location: Rapture

Post by PHoNyMiKe »

Noxious Ninja wrote:There are "tons" of programs? I've only heard of mine and jdratlif's. What other ones are there?
I think I made a quick little one that would parse a text file and convert it to a .cht and vice versa. but I didn't think anyone had it. also I made a mirc script long time ago that showed the contents of a .cht file teeheehee.


actually bewm, a five year old script that will convert to and from with mirc script hahaha

Code: Select all

alias cht2txt {
  var %chtfile " $+ $$file="Choose a file" c:\*.cht $+ "
  var %byte 0
  var %line 0
  var %amount $calc($file(%chtfile).size / 28)
  echo -a $nopath(%chtfile) contains %amount code $+ $iif(%amount != 1,s)
  echo -a address cv pv tgl description
  :loop
  bread %chtfile %byte 28 &code
  var %address $base($bvar(&code,5),10,16) $+ $base($bvar(&code,4),10,16,2) $+ $base($bvar(&code,3),10,16,2) $base($bvar(&code,2),10,16,2) $base($bvar(&code,6),10,16,2)
  if ($bvar(&code,1) == 0) { var %status on  } | elseif ($bvar(&code,1) == 4) { var %status off } | else { var %status ??? }
  echo -a  %address %status $bvar(&code,9-28).text
  inc %line
  if (%line < %amount) { var %byte $calc(%byte + 28) | goto loop }
}

alias txt2cht {
  var %txtfile " $+ $$file="Choose a file" c:\*.txt $+ "
  var %chtfile " $+ $nofile(%txtfile) $+ $left($nopath(%txtfile),$calc($len($nopath(%txtfile)) -4)) $+ .cht $+ "
  var %line 2
  var %amount $lines(%txtfile)
  bset &binvar 7 254
  bset &binvar 8 252
  while (%line <= %amount) {
    var %currentline $read -l $+ %line %txtfile
    bset &binvar 1 $iif($gettok(%currentline,4,32) == off,04,00)
    bset &binvar 2 $base($gettok(%currentline,2,32),16,10)
    bset &binvar 3 $base($mid($gettok(%currentline,1,32),5,2),16,10)
    bset &binvar 4 $base($mid($gettok(%currentline,1,32),3,2),16,10)
    bset &binvar 5 $base($mid($gettok(%currentline,1,32),1,2),16,10)
    bset &binvar 6 $iif($bvar(&binvar,1) == 04,$base($gettok(%currentline,3,32),16,10),00)
    bset &binvar 9 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32
    if ($gettok(%currentline,5-,32) != $null) { bset -t &binvar 9 $gettok(%currentline,5-,32) }
    bwrite %chtfile $calc((%line -2) *28) 28 &binvar
    inc %line
  }
  echo -a $calc(%amount -1) code $+ $iif(%amount > 2,s) written from $nopath(%txtfile) to $nopath(%chtfile)
}
[url=http://www.alexchiu.com/affiliates/clickthru.cgi?id=phonymike]ultimate immortality[/url]
[url=http://www.sloganizer.net/en/][img]http://www.sloganizer.net/en/image,zsnes,white,purple.png[/img][/url]
Aerdan
Winter Knight
Posts: 467
Joined: Mon Aug 16, 2004 10:16 pm
Contact:

Post by Aerdan »

Descriptions have NULs from the end of the text to the end of the allowed space.
emcee
Rookie
Posts: 17
Joined: Sun Oct 23, 2005 11:09 pm

Ok, got it

Post by emcee »

Well, here it is.

Operation is fairly simple, when you first run it, type the directory you keep your snes roms in the box on at the upper left and hit the button, a list of the roms (well anything with a .smc, .swc, .fig or .zip extension) in that directory will appear below. When you select one the information in the rom's cht file (a file with the same path and name but .cht extension) will be loaded into the boxes to the right (if one exists, otherwise you will be creating one). You can then edit or add to the data in the boxes, then hit "save CHT file" to save the the changes (or create the file if it doesn't exist). When editing the codes, you need only the enter a PAR or a GG code, and it will fill the other in for you.

While testing it on various CHT files on the web, I realised many of them have 18 byte chunks per code rather than 28, I wasn't aware of these since the code I was reading to figure out the spec seems to only support 28. So for that reason the 18 byte code version won't work with this, but instead will only give you garbage. Any file created with this or ZSNES, however, should work.

As for the code, please excuse the mess:

Code: Select all

use Tk; #Load the Tk module
#load the last directory used \/
open(LD,'ld');
$rd=<LD>;
close(LD);
$b=chr(0); #Set $b to NULL
#Some hashes to make encoding and decoding gg codes easier \/
%bin=('D'=>'0000','6'=>'1000','F'=>'0001','B'=>'1001',
'4'=>'0010','C'=>'1010','7'=>'0011','8'=>'1011','0'=>'0100',
'A'=>'1100','9'=>'0101','2'=>'1101','1'=>'0110','3'=>'1110',
'5'=>'0111','E'=>'1111');
%bin2=('0'=>'1101','8'=>'0110','1'=>'1111','9'=>'1011',
'2'=>'0100','A'=>'1100','3'=>'0111','B'=>'1000','4'=>'0000',
'C'=>'1010','5'=>'1001','D'=>'0010','6'=>'0001','E'=>'0011'
,'7'=>'0101','F'=>'1110');
%hex=('0000'=>'0','0001'=>'1','0010'=>'2','0011'=>'3','
0100'=>'4','0101'=>'5',
'0110'=>'6','0111'=>'7','1000'=>'8','1001'=>'9','1010'=>'A',
'1011'=>'B','1100'=>'C','1101'=>'D','1110'=>'E','1111'=>'F');
%hex2=('0'=>'0000','1'=>'0001','2'=>'0010','3'=>'0011',
'4'=>'0100','5'=>'0101',
'6'=>'0110','7'=>'0111','8'=>'1000','9'=>'1001','A'=>'1010','
B'=>'1011','C'=>'1100','D'=>'1101','E'=>'1110','F'=>'1111');
#transposition cipher keys for gg codes \/
@pos=(8,9,10,11,16,17,18,19,14,15,0,1,2,3,20,21,22,23,4,5,6,7,12,13);
@pos2=(10,11,12,13,18,19,20,21,0,1,2,3,22,23,8,9,4,5,6,7,14,15,16,17);
#build the GUI \/
$mw=new MainWindow(-title=>'CHT Maker');
$chfr=$mw->Frame()->grid(-column=>0, -row=>0);
$cfr=$mw->Frame()->grid(-column=>1, -row=>0);
$dlab=$chfr->Label(-text=>'Rom directory:')->grid(-column=>0, -row=>0);
$dent=$chfr->Entry(-textvariable=>\$rd)->grid(-column=>1, -row=>0);
$dbut=$chfr->Button(-text=>'Load Roms', -command=>\&lrm)->grid(-column=>3, -row=>0);
$dlist=$chfr->Scrolled(Listbox, -width=>40, -height=>30, -scrollbars=>'se')->grid(-column=>0, -row=>1, -columnspan=>4);
&lrm if $rd; #this autoloads the last used directory into the listbox
#Bindings for the listbox, up and down set the active element, while mouse clicks set the anchor \/
$dlist->bind('<Up>'=>sub{&rdcht($dlist->get('active'))});
$dlist->bind('<Down>'=>sub{&rdcht($dlist->get('active'))});
$dlist->bind('<1>'=>sub{$dlist->focus();&rdcht($dlist->get('anchor'));});
#Loops for put the code entry boxes up \/
for($i=0;$i<5;$i++)
{
	$tlab[$i]=$cfr->Label(-text=>'Code'.($i+1).':')->grid(-column=>0, -row=>$i*5);
	$namelab[$i]=$cfr->Label(-text=>'Description: ')->grid(-column=>0, -row=>$i*5+1);
	$nameent[$i]=$cfr->Entry(-textvariable=>\$name[$i])->grid(-column=>1, -row=>$i*5+1);
	$gglab[$i]=$cfr->Label(-text=>'Game Genie Code: ')->grid(-column=>0, -row=>$i*5+2);
	$ggent[$i]=$cfr->Entry(-textvariable=>\$gg[$i])->grid(-column=>1, -row=>$i*5+2);
	$parlab[$i]=$cfr->Label(-text=>'Pro Action Replay Code: ')->grid(-column=>0, -row=>$i*5+3);
	$parent[$i]=$cfr->Entry(-textvariable=>\$par[$i])->grid(-column=>1, -row=>$i*5+3);
	$aclab[$i]=$cfr->Label(-text=>'Active: ')->grid(-column=>0, -row=>$i*5+4);
	$acchk[$i]=$cfr->Checkbutton(-variable=>\$act[$i])->grid(-column=>1, -row=>$i*5+4);
}
for($i=5;$i<10;$i++)
{
	$tlab[$i]=$cfr->Label(-text=>'Code'.($i+1).':')->grid(-column=>2, -row=>($i-5)*5);
	$namelab[$i]=$cfr->Label(-text=>'Description: ')->grid(-column=>2, -row=>($i-5)*5+1);
	$nameent[$i]=$cfr->Entry(-textvariable=>\$name[$i])->grid(-column=>3, -row=>($i-5)*5+1);
	$gglab[$i]=$cfr->Label(-text=>'Game Genie Code: ')->grid(-column=>2, -row=>($i-5)*5+2);
	$ggent[$i]=$cfr->Entry(-textvariable=>\$gg[$i])->grid(-column=>3, -row=>($i-5)*5+2);
	$parlab[$i]=$cfr->Label(-text=>'Pro Action Replay Code: ')->grid(-column=>2, -row=>($i-5)*5+3);
	$parent[$i]=$cfr->Entry(-textvariable=>\$par[$i])->grid(-column=>3, -row=>($i-5)*5+3);
	$aclab[$i]=$cfr->Label(-text=>'Active: ')->grid(-column=>2, -row=>($i-5)*5+4);
	$acchk[$i]=$cfr->Checkbutton(-variable=>\$act[$i])->grid(-column=>3, -row=>($i-5)*5+4);
}
$cbut=$mw->Button(-text=>'Save CHT file', -command=>\&go)->grid(-row=>1, -column=>1);
MainLoop;
sub go #subroutine that calls the gg codec subs then the sub that generates the CHT file
{
	$g=0;
	foreach(@gg)
	{
		if($_)
		{
			&decode($g++);
		}
		else
		{
			next unless $par[$g];
			&encode($g++);
		}
	}
	&mkcht;
}
sub decode #this decodes a gg code into par code (address and value)
{
	$a=0; #reset $a
	$d=$gg[$_[0]]; #I was originally using $_ here and in and the
#encode sub, but it caused all kinds of problems
	$d=uc($d); #make it all uppercase
	$d=~s/-//; #remove the hyphen
	$d=~s/(..)//; #take off the first to characters and put them in $1
	$v=$1; #$v is the value, unlike the rest of the code, it only uses the
#substitution cipher, and not the bitwise transposition
	$v=~tr/DF4709156BC8A23E/0123456789ABCDEF/; #this decodes 
#the value
	$d=~s/(.)/$bin{$1}/g; #convert to binart with substition cipher 
#already applied
	$new[$pos[$a++]]=$_ foreach(split //, $d); #this decodes the 
#transposition cipher, it uses the @pos array to put them in the right order
	$d=join '', @new; #turn @new into a string
	$d=~s/(....)/$hex{$1}/g; #convert back to hex
	$par[$_[0]]="$d$v"; #put the address and value together
}
sub mkcht #this generates the CHT file
{
	$chtfile=''; #reset $chtfile
	$once=0; #reset $once
	$g=0; #reset $g
	foreach(@par)
	{
		next unless $_; #this makes sure it only processes entries that 
#are filled in
		$cht=$act[$g]?chr(0):chr(4); #Conditional operator sets the 
#first byte to show whether the code is active
		foreach $h (reverse($_=~/(..)/g))
		{
			$cht.=chr(hex($h)); #The codes are stored basically like
#a par code in reverse
		}
		$gap=$once ? (chr(0).chr(0)) : (chr(hex('FE')).chr(hex('FC'))); #This sets the value of the bytes between the code and the title, these 
#bytes are different for the first code, I don't know why
		$cht.=chr(0).$gap.uc($name[$g++]); #put it together
		$cht=~/(.{0,28})/s; #chop any excess bytes
		$cht.=chr(0) x (28-length($cht)); #pad it as nessicary
		$chtfile.=$cht; #assignment operator add this code 
		$once=1; #ran this once
	}
	$_=$cur; 
	s/....$/\.cht/; #swap the extention .cht
	open(CHT,">$rd$_"); #open it for write
	binmode(CHT); #go to binmode, just in case to bytes form a new line code
	print CHT $chtfile; 
	close CHT;
}
sub rdcht #this parses a cht file
{
	$cur=$_[0];
	$_=$rd.$_[0]; #make the full path
	s/....$/\.cht/; #swap extensions
	open(CHT,$_); #open readonly
	#this loop resets the values in all the boxes \/
	for($i=0;$i<10;$i++)
	{
		$name[$i]='';
		$gg[$i]='';
		$par[$i]='';
		$act[$i]='';
	}
	binmode(CHT);
	$_=join '', <CHT>; #put the file contents in $_
	close(CHT);
	$g=0; #reset $g
	$chunk=(length()%28) ? 18: 28; #this is how I determine if it the 18
#byte 252 would match both, this will assume it 28 than (there isn't room
#for 14 codes anyway)
	$bn=$chunk==18?5:7; #set where to start reading the description
#from
	#this loop processes it one 18 or 28 byte chunk at a time
	foreach(/(.{$chunk})/gs)
	{
		s/(.)//; #take off first byte and put it in $1
		$act[$g]=!ord($1); #detimines if the code is active from first 
#byte
		/(.{4})/s; #next 4 bytes go in $1
		$code[$#code+1]=ord($_) foreach reverse(split //, $1); #get
#par code by reversing the string in $1
		$par[$g]=sprintf('%02X%02X%02X%02X', @code); #fill in par code
		/.{$bn}(.*)$b.*/s; #put description in $1 ($b is NULL)
		$name[$g]=$1; #fill in the entry
		&encode($g++); #encode to gg form
		@code=(); #reset @code
	}
}
sub encode #turn a par code into gg
{
	$a=0; #reset $a
	#Next several lines are like decoding, except substituing back \/
	$e=$par[$_[0]]; 
	$e=uc($e);
	$e=~s/://;
	$e=~s/(..)$//;
	$v=$1;
	$v=~tr/0123456789ABCDEF/DF4709156BC8A23E/;
	$e=~s/(.)/$hex2{$1}/g; #into binary, no substitution (this has to be
#done after the transposition)
	$new[$pos2[$a++]]=$_ foreach(split //, $e); #transposition, this 
#time putting things in the wrong order instead of right
	$e=join '', @new;
	$e=~s/(....)/$hex{$1}/g;
	$e=~tr/0123456789ABCDEF/DF4709156BC8A23E/; #now the 
#substitution
	$e="$v$e";
	$gg[$_[0]]=join '-', $e=~/(....)/g; #fill it in with the hyphen added
}
sub lrm #this loads the directory into the listbox
{
	$rd=~/(\/|\\)/; #this determines the direction of slash used
	$sdir=$1;
	$rd=~/(.)$/;
	$rd.=$sdir unless $1 eq $sdir; #add a trailing slash if there isn't one 
	opendir(DIR,$rd); #open the directory
	$dlist->delete('0','end'); #clear the list
	foreach(readdir(DIR))
	{
		$dlist->insert('end', $_) if /\.smc|\.fig|\.swc|\.zip/; #only put 
#things files that might be roms in the list
	}
	close(DIR);
	open(LD,'>ld');
	print LD $rd; #save the last directory used, to avoid retyping
	close(LD);
}
Last edited by emcee on Fri Oct 28, 2005 8:01 am, edited 5 times in total.
Ichinisan
Veteran
Posts: 603
Joined: Wed Jul 28, 2004 8:54 am

Post by Ichinisan »

When creating a code insertion tool, do remember that there are mirror and reflector codes for standard PAR cheats.
jhguitarfreak
New Member
Posts: 9
Joined: Tue Oct 25, 2005 11:52 am

Post by jhguitarfreak »

ok, i'm kinda new to the whole open source thing (i started with UQM), but can this be compiled in MS Visual Studio .NET 2003?

And is there certain libraries i need to get to compile this?



thanks ahead of time.
Aerdan
Winter Knight
Posts: 467
Joined: Mon Aug 16, 2004 10:16 pm
Contact:

Post by Aerdan »

It's a Perl script.

You need ActivePerl and the Tk module.

If you can't find ActivePerl through Google, I pity you.
jhguitarfreak
New Member
Posts: 9
Joined: Tue Oct 25, 2005 11:52 am

Post by jhguitarfreak »

Aerdan wrote:It's a Perl script.

You need ActivePerl and the Tk module.

If you can't find ActivePerl through Google, I pity you.
oh don't worry, i'll find it.

thanks

if i have any more questions i'll comeback.
jhguitarfreak
New Member
Posts: 9
Joined: Tue Oct 25, 2005 11:52 am

Post by jhguitarfreak »

i'm just gonna ask this stupid ass question knowing that i might be flamed...

*sigh*

is there a way to compile this into an exe file, or does activeperl run it as if it were an exe file?
Aerdan
Winter Knight
Posts: 467
Joined: Mon Aug 16, 2004 10:16 pm
Contact:

Post by Aerdan »

It's a script, sort of like a .bat file, except you need a Perl interpreter to run it.
emcee
Rookie
Posts: 17
Joined: Sun Oct 23, 2005 11:09 pm

Post by emcee »

jhguitarfreak wrote:i'm just gonna ask this stupid ass question knowing that i might be flamed...

*sigh*

is there a way to compile this into an exe file, or does activeperl run it as if it were an exe file?
It's real easy:

Step 1: Go here and download the package appropriate for your system (you'll probably want the Windows MSI) package. There's no need to download the Tk modules, it comes with standard Perl distributions.

Step 2: Run the install program, depending on your system you may need to upgrade your Microsoft Installer (you probably won't).

Step 3: Cut and paste the code into notepad, and save with a .pl extension make sure to pick 'all files' for the type, on older versions of Windows (9x, and probably ME) you'll also need to put the file name in quotes or it will add a .txt to end the anyway. (You may already know all this, but this is just in case you don't)

Step 4: Double click on the icon of the file you just saved.

There are a few benefits of this program over just using ZSNES, like cut and paste, and not needing to load a game to edit its cheats, but if you don't forsee any other use for Perl in the future, you may not want to even bother. I really just posted it for people who already had Perl installed its not really worth installing Perl specifically for. If you do try it, however, tell me what you think.
jhguitarfreak
New Member
Posts: 9
Joined: Tue Oct 25, 2005 11:52 am

Post by jhguitarfreak »

thanks for the help, i'll be testing it out in a little bit to see how it works, and sometimes i love going through all the trouble of learning something new. You never know when you might find something great in the process.
jhguitarfreak
New Member
Posts: 9
Joined: Tue Oct 25, 2005 11:52 am

Post by jhguitarfreak »

well i've been testing it on various games
which include FF3, Super Mario World, And Mortal Kombat
and i gotta say this is a nifty little program you got here.
the only pet peeve i have about it is it won't let me right click to paste in the boxes. so i basicall had my left hand sitting over the CTRL key while switching back and forth from text files and webpages while adding cheats.
but this is really cool, now i don't have to have a big printout of cheats to type in with every game i get.
SquareHead
Veteran
Posts: 970
Joined: Fri Jan 21, 2005 11:15 am
Location: Montana, United States

Post by SquareHead »

Or you could ... (not to disrespect the work at hand) go to Zophar's and download snes cheat files from their archives. They have a huge collection.
Aerdan
Winter Knight
Posts: 467
Joined: Mon Aug 16, 2004 10:16 pm
Contact:

Post by Aerdan »

Some of which are broken?
SquareHead
Veteran
Posts: 970
Joined: Fri Jan 21, 2005 11:15 am
Location: Montana, United States

Post by SquareHead »

Aerdan wrote:Some of which are broken?
Downloads or codes themselves?
Post Reply