Modding SF4 for PC (No DLC Unlocks!)

I’ve been following this thread lately, poking around in hex workshop and randomly adjusting values to make fun shit happen as a little project, and I found this.
at 0098C490 in RYU.cmn.emz (LP hadoken) I found a value that seems to do something to the amount of fireballs he shoots out. It works on all fireballs I think, I did it to HP fireball but forgot the location (and I’m in no way experienced with using a hex editor or at reading hex in general)
It’s originally B401, but if you change it to, say 0602, you get 3 fireballs in a row like in this vid i uploaded:
[media=youtube]3he5vQ2ySHw[/media]

If you change it to something lower, shit that can crash the game happens ,like a stream of 6 fireballs.
Funny.
I’m nowhere near where you guys are, but I’d like to find out how to fuck around with knockback and juggles so I can get something VS-like. I already got basic LP-MP-HP/LK-MK-HK working for Sagat.

i think that b401 might be a pointer to a later section of the move but i’m not sure… trying to copy and paste the 518 (206 hex) bytes down from the start into the 436 (1b4 hex) but keeping the b401 just causes him no longer to throw fireballs but just to do the animation and then scream but i’m pretty sure i’m just copy and pasting far too much stuff. also i might be off by one.

wait are you saying you got chain combos to work in a manner that doesn’t let things chain combo to themselves? how

110D788 on Gouken is the animation for his dizzy, replacing it with some characters from elsewhere changed it and made him huge. I also changed the place the opponent fall at for his forward throw but I’m not sure where I did it.

Well, I didn’t get proper chain combos working, no, the moves can still combo into themselves easily.

Gouken has way to many moves
I’ve figured out where the animations for Sagats normals are

It doesn’t seem to be in the same order as the move proprieties table
Not sure i’m at the start of the moves ether, I just replaced 100 characters at these locations and saw what moves changed
addresses in dec
2662020 5 mp
2742480 hp both close and far
2781352 lk both close and far
2882493 close mk
2936344 far mk
2979992 hk on hit, only changes the animation after the hk hits
3038143 f+hk, ie hsk
3204572 2 mk
3297696 8 lp
3367160 8 mp

there is probably a pointer table that points to all of these as well as pointing to names of anims

we need to figure out why dhalsim’s super can juggle the first hit post stun
http://www.capcom-unity.com/doopliss/blog/2009/12/26/new_combo_video:_what_just_happened

Sakura’s Ultra can also do that. I’m pretty sure I saw it in this combo vid:

[media=youtube]NadAipFN6_A[/media]

her ultra functions like a throw (opponent plays preset animation HARURANMAN_DMG) when she gets full ultra so its probably different

she does HARURANMAN_HIT… i dunno

Wow thats a quality video
it looks a lot like the old El Fuerte’s otg thing. He can also do that s.lk after the throw causes dizzy but it knocks them down rather then stands them up like here [media=youtube]wFsY45do1rg#t=1m23s[/media]. Realy have no idea.
It makes sense for Ken, Sakura, or Seth to be able to do it.

no ideas on why dhalsim’s super can do this? Honestly, i’m slightly confused at what’s making it be able to juggle in the first place the juggle potential part on all the hits is 01000101 if i’m looking at this right

i’m stumped

maybe just the first few frames of stun state are jugglable and fireball to super cancel w/ dhalsim is the only thing fast enough?

like how on MvC2 the first frame of spinout state can be grabbed by Rogue’s (blockable) grab super allowing the 999+ hit ruby / psylocke / rogue combo in [media=youtube]eZXSUZywhx0[/media]

frame data says it’s three frames for his super. Ryu’s super is quicker so you would expect him to be able to do it but he can’t. It could have to do with the yoga fire creating a free juggle setup, should probly test this with gouken.
edit couldn’t get it to work with gouken even with a meaty fb so the super hit at about the same time

Might have something to do with the state it puts the opponent in (burning). But this would imply that Ken’s DP should also be able to do it. It’s probably a combination of things.

Im sorry but what are the normal steps used to save a CMN? I did everything else but im just stuck at this part.

roses ultra acts weird…
if i let someone be able to juggle into it and then make the last hit put back into standing hitstun or crumple… they play the animation for the thing and it works right except the JUGGLE COUNTER STAYS FOR THE STANDING / CRUMPLE STATES. WTF?

[media=youtube]xLTx6da75hw[/media]
copy and pasting air fireball from akuma onto her j lk lets me do this… i had to change the byte that controls which fireball comes out of the fireball producing move

That’s what happens with Rufas’s super or Bison’s ultra if you interrupt them. Probly should see what ex tandem and I think kens ex srk does to reset the juggle counter

[media=youtube]oivAv5zOGoA[/media]
is this cheap enough yet

two more perl scripts for use
the first one you provide a filename for input, and a number (that you can get with the script I provided a page or two back), and it retrieves that move data at that location and spits it out into a file like NAME.dat. like if you call it on GKI.cmn.emz w/ number 156 then it spits out AIR_TATSUMAKI_L.dat in the same directory.

the second script takes 3 arguments, the first is the original file, the index, and a .dat that contains a move. it then takes the original file and creates a new file with the name the original file but with a 2 at the end, this file has the move at the index replaced by the one from the .dat file and all the pointer tables are updated accordingly and correctly.
this is how i copy and pasted akuma’s dive kick (92MK) and dhalsim’s teleport (AIR_TELEPO_A) to c viper like in the video in my above post


#/usr/bin/perl -w
use strict;
use warnings;
if(defined($ARGV[1])) {
	print "ok good
";
} else {
	print "not enough params
";
	exit 0;
}
print "----------------------------------------------------------------------
";
open(IN,$ARGV[0]);
binmode(IN);

# debugging mainly
sub printadd {
	my $a = shift;
	return $a . " - " . sprintf("%x",$a);
}

# loc, amount, buffer
sub sread {
	# bad programming here but whatev
	seek(IN, $_[0], 0) or die "seek:$!";
	read(IN, $_[2], $_[1]);
}

# endian stuff
sub convert {
	return unpack("V", shift);
}

# (start, end). returns array.
sub slurptable {
	my ($s, $e) = (shift,shift);
	my $buffer = "";
	my @out;
	my $i = 0;
	
	while($s < $e) {
		sread($s, 4, $buffer);
		$buffer = convert($buffer);
		if($buffer != 0) {
			$out[$i] = $buffer;
			$i++;
		}
		$s += 4;
	}
	return @out;
}

my $buffer = "";
my $pointer = 0;

sread(0x48, 4, $buffer);

my $bac = convert($buffer);
print printadd($bac) . " - header BAC
";

sread($bac, 256, $buffer);

#print $buffer . "
";

$bac += rindex($buffer, "#BAC");
print printadd($bac) . " - actual BAC
"; # 779040

# get animation table
sread($bac + 12, 4, $buffer);
$pointer = convert($buffer);
my $addanimation = $pointer+$bac;
print printadd($bac + 12) . " - pointer to animation table
    contents - " . printadd($pointer) . " or " .  printadd($addanimation) . "
";

# get end of animation table
sread($bac + 16, 4, $buffer);
$pointer = convert($buffer);
my $addname = $pointer+$bac;
print printadd($bac + 16) . " - pointer to name table
    contents - " . printadd($pointer) . " or " .  printadd($addname) . "
";

# get hit table start (so know end of name table)
sread($bac + 20, 4, $buffer);
$pointer = convert($buffer);
my $addhit = $pointer+$bac;
print printadd($bac + 20) . " - pointer to hit table
    contents - " . printadd($pointer) . " or " .  printadd($addhit) . "
";

my @animtable = slurptable($addanimation, $addname);
my @nametable = slurptable($addname, $addhit);

# not slurping the hit table for now except for the first value.
# get hit table start (so know end of name table)
sread($addhit, 4, $buffer);
$pointer = convert($buffer);
my $firsthit = $pointer+$bac;
print printadd($addhit) . " - hit table first value
    contents - " . printadd($pointer) . " or " .  printadd($firsthit) . "
";

print "------------------------------------
";
print "length of animtable -  " . scalar(@animtable) . "
";
print "length of nametable -  " . scalar(@nametable) . "
";

my $length = scalar(@nametable);
push(@nametable, $firsthit - $bac);
my @names = ();

for(my $i = 0; $i < $length; $i++)
{
	sread($nametable[$i]+$bac, $nametable[$i+1]-$nametable[$i], $buffer);
	$buffer =~ s/\x00+$//;
	push @names, $buffer;
	$buffer = $i . ". " . $buffer;
	$buffer .= " "x(30-length($buffer));
	print $buffer . printadd($animtable[$i] + $bac) . "
";
}

print printadd($nametable[199]) . "
";
# cleanup

my $target = $ARGV[1];
print "getting " . $target . ". " . $names[$target] . ": " . printadd($animtable[$target] + $bac) . " and ends at " . printadd($animtable[$target+1] + $bac) . "
";

open(OUT, ">".$names[$target] . ".dat");
binmode(OUT);

sread($animtable[$target]+$bac, $animtable[$target+1]-$animtable[$target], $buffer);
print OUT $buffer;

close(OUT);
close(IN);



#/usr/bin/perl -w
use strict;
use warnings;
if(defined($ARGV[2])) {
	print "ok good
";
} else {
	print "not enough params
";
	exit 0;
}
print "----------------------------------------------------------------------
";
open(IN,$ARGV[0])  or die "$!";
binmode(IN);

# debugging mainly
sub printadd {
	my $a = shift;
	return $a . " - " . sprintf("%x",$a);
}

# loc, amount, buffer
sub sread {
	# bad programming here but whatev
	seek(IN, $_[0], 0) or die "seek:$!";
	read(IN, $_[2], $_[1]);
}

# endian stuff
sub convert {
	return unpack("V", shift);
}

# (start, end). returns array.
sub slurptable {
	my ($s, $e) = (shift,shift);
	my $buffer = "";
	my @out;
	my $i = 0;
	
	while($s < $e) {
		sread($s, 4, $buffer);
		$buffer = convert($buffer);
		if($buffer != 0) {
			$out[$i] = $buffer;
			$i++;
		}
		$s += 4;
	}
	return @out;
}

# (start, end). returns array.
sub slurptablewithzeros {
	my ($s, $e) = (shift,shift);
	my $buffer = "";
	my @out;
	my $i = 0;
	
	while($s < $e) {
		sread($s, 4, $buffer);
		$buffer = convert($buffer);
		$out[$i] = $buffer;
		$i++;
		$s += 4;
	}
	return @out;
}

# give array returns big fat table with incremented
sub addtable {
	my ($s, $e, $dsize) = (shift,shift, shift);
	my @in = slurptablewithzeros($s,$e);
	my $out = "";
	foreach(@in)
	{
		if($_ != 0) {
			$out .= pack("V", $_ - $dsize)
		} else {
			$out .= pack("V", $_)
		}
	}
	return $out;
}

my $buffer = "";
my $pointer = 0;

sread(0x48, 4, $buffer);

my $bac = convert($buffer);
print printadd($bac) . " - header BAC
";

sread($bac, 256, $buffer);

#print $buffer . "
";

$bac += rindex($buffer, "#BAC");
print printadd($bac) . " - actual BAC
"; # 779040

# get animation table
sread($bac + 12, 4, $buffer);
$pointer = convert($buffer);
my $addanimation = $pointer+$bac;
print printadd($bac + 12) . " - pointer to animation table
    contents - " . printadd($pointer) . " or " .  printadd($addanimation) . "
";

# get end of animation table
sread($bac + 16, 4, $buffer);
$pointer = convert($buffer);
my $addname = $pointer+$bac;
print printadd($bac + 16) . " - pointer to name table
    contents - " . printadd($pointer) . " or " .  printadd($addname) . "
";

# get hit table start (so know end of name table)
sread($bac + 20, 4, $buffer);
$pointer = convert($buffer);
my $addhit = $pointer+$bac;
print printadd($bac + 20) . " - pointer to hit table
    contents - " . printadd($pointer) . " or " .  printadd($addhit) . "
";

my @animtable = slurptable($addanimation, $addname);
my @nametable = slurptable($addname, $addhit);
my @animtablez = slurptablewithzeros($addanimation, $addname);
my @nametablez = slurptablewithzeros($addname, $addhit);

# not slurping the hit table for now except for the first value.
# get hit table start (so know end of name table)
sread($addhit, 4, $buffer);
$pointer = convert($buffer);
my $firsthit = $pointer+$bac;
print printadd($addhit) . " - hit table first value
    contents - " . printadd($pointer) . " or " .  printadd($firsthit) . "
";

print "------------------------------------
";
print "length of animtable -  " . scalar(@animtable) . "
";
print "length of nametable -  " . scalar(@nametable) . "
";

my $length = scalar(@nametable);
push(@nametable, $firsthit - $bac);
my @names = ();

for(my $i = 0; $i < $length; $i++)
{
	sread($nametable[$i]+$bac, $nametable[$i+1]-$nametable[$i], $buffer);
	$buffer =~ s/\x00+$//;
	push @names, $buffer;
	$buffer = $i . ". " . $buffer;
	$buffer .= " "x(30-length($buffer));
	print $buffer . printadd($animtable[$i] + $bac) . "
";
}

print printadd($nametable[199]) . "
";
# cleanup

my $target = $ARGV[1];
my $oldsize = $animtable[$target+1]-$animtable[$target];
my $newsize = -s $ARGV[2];
my $dsize = $oldsize - $newsize;
print "old size: $oldsize 
";
print "new size: $newsize 
";
print "size diff: $dsize 
";
print "going for " . $target . ". " . $names[$target] . ": " . printadd($animtable[$target] + $bac) . " and ends at " . printadd($animtable[$target+1] + $bac) . "
";
print "aka " . printadd($animtable[$target]) . "
";

open(NEWM, $ARGV[2])  or die "$!";
binmode(NEWM);


open(OUT, ">" . $ARGV[0] . "2") or die "$!";
binmode(OUT);
print "writing EMB before
";
sread(0, 0x4C, $buffer);
print OUT $buffer;
print "getting EMB after 
";
print OUT addtable(0x4C, 0x74, $dsize);
print "getting ALL THE WAY TO BAC 
";
sread(0x74, $addanimation - 0x74, $buffer);
print OUT $buffer;
print "getting animtable 
";
my $truetarget = 0;
my $temp = "";
foreach(@animtablez) {
	if($_ == $animtable[$target] or $truetarget)
	{
		#print "truetarget! $animtable[$target]
";
		$truetarget = 1;
		if($_ != 0 and $_ != $animtable[$target]) {
			$temp .= pack("V", $_ - $dsize)
		} else {
			$temp .= pack("V", $_)
		}
	} else {
		$temp .= pack("V", $_)
	}
}
print OUT $temp;

print "getting next tables 
";
print OUT addtable($addname, $animtable[0]+$bac, $dsize);

sread($animtable[0]+$bac,  $animtable[$target] - $animtable[0], $buffer);
print OUT $buffer;

print "getting new anim 
";
read(NEWM, $buffer, $newsize);
print OUT $buffer;

my $insize = -s $ARGV[0];
print "getting data till EOF at $insize 
";
sread($animtable[$target+1] + $bac,  $insize - ($animtable[$target+1] + $bac), $buffer);
print OUT $buffer;
close(OUT);
close(NEWM);


some match videos
[media=youtube]l1VnMCMSZtI[/media]
[media=youtube]PpGYJ3feaLQ[/media]
[media=youtube]I8tMStQT_0M[/media]