SFxT GAMEPLAY Modding Thread


#1

No talking about cosmetics here, just talking about actually modifying the gameplay, ala SF4Remix, Kouryu, etc. The other thread is dead because people suck, don’t ruin this one by even mentioning textures or models in here.

Ono will not be updated to support SFxT, and it wont really be updated that much at all anymore. The future is…PandoraPy. Here is how it works.

One of the main issues I had developing Ono is that GUI programming is hard, and I don’t want to do it. This may sound weird to you, but thats basically 100% of the issues with Ono. So, I was wondering, how could I make this easier to use for the people using it!

XML.! PandoraPy takes BCM and BAC files (so far) from SFxT (AE2012 support coming soon) and converts them to and from XML. It supports 360/PS3/PC files, and can convert between endianess of those files. While it will eventually support other filetypes, the goal is to work on modifying gameplay first.

Here is an example of what pre-alpha BCM output for PandoraPy looks like now.

The annoying thing is all of the Unknown values. I haven’t ported over all the labels from Ono, but I am working on it.


#2

In this case, I’ll make GUI tool with specialized editors.


Ultra Street Fighter 4 PC Custom Skin Thread
#3

Never stop modding man! We need you!


#4

Instead of editing one char at one time, I really hope there is an batch edit option.

Change every char’s control standard or AI behavior in no time would be a good thing.


#5

The XML output should be easier to manipulate than with a GUI, really. You’ll be able to find-and-replace, copy/paste from one character to another, etc. all with the text editor of your choice.


#6

Sounds good. I want to see if I can make these games more like sf2, and while ono is nice, it is still pretty hard, ha


#7

Its not out yet. I am still working on it, and I still need feedback from people about what I am doing.
XML is definetly the way to go for something like this, but theres a few things that are gonna be a bit tricky.


#8

Its been 24 hours, and looky what I have done!
Here is a link to the output so far for RYU.
http://www.sendspace.com/file/xbh60a (Hiteffect Table is missing but who cares ATM)

Let me give an example of how this works.
BCM.xml contains Charges, InputMotions, Moves, and CancelLists. Let me give an example of the latter 3 since RYU doesn’t have charge moves.



<InputMotion Name="HADO" Offset="0x1df0L">
<SUPEREASY>
<InputMotionEntry Offset="0x1e04L" Type="NORMAL" Buffer="0xc" Input="FORWARD" InputFlags="STRICT_DIRECTION" Flags1="0x1000" Flags2="0x2" Mash="0x0"/>
</SUPEREASY>
<EASY>
<InputMotionEntry Offset="0x1f08L" Type="NORMAL" Buffer="0xc" Input="DOWN" InputFlags="STRICT_DIRECTION" Flags1="0x0" Flags2="0x0" Mash="0x0"/>
<InputMotionEntry Offset="0x1f18L" Type="NORMAL" Buffer="0xc" Input="FORWARD" InputFlags="LENIENT_DIRECTION" Flags1="0x0" Flags2="0x0" Mash="0x0"/>
</EASY>
<NORMAL>
<InputMotionEntry Offset="0x200cL" Type="NORMAL" Buffer="0xc" Input="DOWN" InputFlags="STRICT_DIRECTION" Flags1="0x0" Flags2="0x0" Mash="0x0"/>
<InputMotionEntry Offset="0x201cL" Type="NORMAL" Buffer="0xc" Input="DOWN FORWARD" InputFlags="STRICT_DIRECTION" Flags1="0x0" Flags2="0x0" Mash="0x0"/>
<InputMotionEntry Offset="0x202cL" Type="NORMAL" Buffer="0xc" Input="FORWARD" InputFlags="STRICT_DIRECTION" Flags1="0x0" Flags2="0x0" Mash="0x0"/>
</NORMAL>
<STRICT>
<InputMotionEntry Offset="0x2110L" Type="NORMAL" Buffer="0x4" Input="DOWN" InputFlags="STRICT_DIRECTION" Flags1="0x0" Flags2="0x0" Mash="0x0"/>
<InputMotionEntry Offset="0x2120L" Type="NORMAL" Buffer="0x4" Input="DOWN FORWARD" InputFlags="STRICT_DIRECTION" Flags1="0x0" Flags2="0x0" Mash="0x0"/>
<InputMotionEntry Offset="0x2130L" Type="NORMAL" Buffer="0x4" Input="FORWARD" InputFlags="STRICT_DIRECTION" Flags1="0x0" Flags2="0x0" Mash="0x0"/>
</STRICT>
</InputMotion>

You can see the inputs for very easy gem, easy gem, normal, and strict gem, and the info associated with them.

Now lets look at a Move. This is hadoken. Most characters have their chargeable move labeled SC in their file, so dont get confused.



<Move Name="SC_L" Offset="0x44f0L" Input="LP" InputFlags="ALL_BUTTONS +ON_PRESS +ON_RELEASE" PositionRestriction="NONE" _Unk3="0x0" _Unk4="0x0" _Unk5="0x0" PositionRestrictionDistance="0.0" Restriction="0x1" _Unk8="0x830" _Unk9="0x0" Meter Req="0x0" Meter Loss="-0xf" InputMotion="HADO" Script="0x172" _Unk14="0x21" _Unk15="-0x1" _Unk16="0x0" _Unk17="-0x1" AI Min Distance="3.5" AI Max Distance="10.0" _Unk20="1.39999997616" _Unk21="0x4" _Unk22="0x0" _Unk23="0x0" _Unk24="-0x1" _Unk25="-0x1" _Unk26="0x0" _Unk27="0x0" _Unk28="0x1" _Unk29="0x3" AIFar="0x5" AIVeryFar="0xa"/>


Yeah, a lot of unknowns, some of these are known, but my first priority is getting this working, not labeled, since its hard to test things if you can’t edit.

And last, but not least, lets look at a CancelList



<CancelList Name="GROUND" Offset="0x4db0L">
<CancelData Move="AI_COMBO_0" Offset="0x4f30L" _Unk0="0x2" _Unk1="0x2" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0xa" _Unk6="0x0" _Unk7="0x0"/>
<CancelData Move="5LP" Offset="0x4f38L" _Unk0="0x14" _Unk1="0x0" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0x0" _Unk6="0x19" _Unk7="0xf"/>
<CancelData Move="5LPF" Offset="0x4f40L" _Unk0="0x14" _Unk1="0x0" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0x0" _Unk6="0x14" _Unk7="0xa"/>
<CancelData Move="5LK" Offset="0x4f48L" _Unk0="0x0" _Unk1="0x14" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0x0" _Unk6="0x14" _Unk7="0xa"/>
<CancelData Move="5LKF" Offset="0x4f50L" _Unk0="0x0" _Unk1="0x0" _Unk2="0xf" _Unk3="0x0" _Unk4="0x0" _Unk5="0x0" _Unk6="0x0" _Unk7="0x5"/>
<CancelData Move="5MP" Offset="0x4f58L" _Unk0="0xf" _Unk1="0xf" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0x0" _Unk6="0xf" _Unk7="0x0"/>
<CancelData Move="5MPF" Offset="0x4f60L" _Unk0="0x14" _Unk1="0x0" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0x14" _Unk6="0xf" _Unk7="0x0"/>
<CancelData Move="5MK" Offset="0x4f68L" _Unk0="0xc" _Unk1="0x14" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0x0" _Unk6="0xa" _Unk7="0x0"/>
<CancelData Move="5MKF" Offset="0x4f70L" _Unk0="0x14" _Unk1="0x14" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0x14" _Unk6="0xf" _Unk7="0x0"/>
<CancelData Move="5HP" Offset="0x4f78L" _Unk0="0xc" _Unk1="0xc" _Unk2="0xa" _Unk3="0x0" _Unk4="0x0" _Unk5="0x14" _Unk6="0x0" _Unk7="0x0"/>
<CancelData Move="5HPF" Offset="0x4f80L" _Unk0="0xf" _Unk1="0x0" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0xf" _Unk6="0xf" _Unk7="0xf"/>
<CancelData Move="5HK" Offset="0x4f88L" _Unk0="0x14" _Unk1="0xa" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0xa" _Unk6="0x2" _Unk7="0x0"/>
<CancelData Move="5HKF" Offset="0x4f90L" _Unk0="0x0" _Unk1="0x0" _Unk2="0xa" _Unk3="0x0" _Unk4="0x0" _Unk5="0x0" _Unk6="0x0" _Unk7="0x0"/>
<CancelData Move="2LP" Offset="0x4f98L" _Unk0="0xf" _Unk1="0xa" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0xf" _Unk6="0x14" _Unk7="0x0"/>
<CancelData Move="2LK" Offset="0x4fa0L" _Unk0="0x19" _Unk1="0xf" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0x23" _Unk6="0x1e" _Unk7="0x0"/>
<CancelData Move="2MP" Offset="0x4fa8L" _Unk0="0x14" _Unk1="0xf" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0x19" _Unk6="0xf" _Unk7="0x0"/>
<CancelData Move="2MK" Offset="0x4fb0L" _Unk0="0x28" _Unk1="0x19" _Unk2="0x5" _Unk3="0x0" _Unk4="0x0" _Unk5="0x19" _Unk6="0x19" _Unk7="0xa"/>
<CancelData Move="2HP" Offset="0x4fb8L" _Unk0="0x0" _Unk1="0x0" _Unk2="0xa" _Unk3="0x0" _Unk4="0x0" _Unk5="0x0" _Unk6="0x0" _Unk7="0x0"/>
<CancelData Move="2HK" Offset="0x4fc0L" _Unk0="0x14" _Unk1="0x0" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0x1" _Unk6="0x1" _Unk7="0x0"/>
<CancelData Move="6MP" Offset="0x4fc8L" _Unk0="0x5" _Unk1="0x19" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0x0" _Unk6="0x14" _Unk7="0x0"/>
<CancelData Move="6HP" Offset="0x4fd0L" _Unk0="0x5" _Unk1="0x5" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0x5" _Unk6="0x2" _Unk7="0x0"/>
<CancelData Move="SC_L" Offset="0x4fd8L" _Unk0="0x5" _Unk1="0x5" _Unk2="0x0" _Unk3="0x2" _Unk4="0x0" _Unk5="0xf" _Unk6="0xf" _Unk7="0x0"/>
<CancelData Move="SC_M" Offset="0x4fe0L" _Unk0="0x5" _Unk1="0x5" _Unk2="0x0" _Unk3="0x2" _Unk4="0x0" _Unk5="0xf" _Unk6="0xf" _Unk7="0x0"/>
<CancelData Move="SC_H" Offset="0x4fe8L" _Unk0="0x5" _Unk1="0x5" _Unk2="0x0" _Unk3="0x2" _Unk4="0x0" _Unk5="0xf" _Unk6="0xf" _Unk7="0x0"/>
<CancelData Move="SC_EX" Offset="0x4ff0L" _Unk0="0x2" _Unk1="0x2" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0x14" _Unk6="0x5" _Unk7="0x0"/>
<CancelData Move="TATSUMAKI_L" Offset="0x4ff8L" _Unk0="0xa" _Unk1="0x0" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0x14" _Unk6="0x0" _Unk7="0x0"/>
<CancelData Move="TATSUMAKI_M" Offset="0x5000L" _Unk0="0xa" _Unk1="0x0" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0xa" _Unk6="0x0" _Unk7="0x0"/>
<CancelData Move="TATSUMAKI_H" Offset="0x5008L" _Unk0="0xa" _Unk1="0x0" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0xa" _Unk6="0x0" _Unk7="0x0"/>
<CancelData Move="TATSUMAKI_EX" Offset="0x5010L" _Unk0="0xa" _Unk1="0x0" _Unk2="0x5" _Unk3="0x0" _Unk4="0x0" _Unk5="0x19" _Unk6="0x5" _Unk7="0xa"/>
<CancelData Move="SYORYU_L" Offset="0x5018L" _Unk0="0x5" _Unk1="0x5" _Unk2="0x1e" _Unk3="0x0" _Unk4="0x0" _Unk5="0x14" _Unk6="0x0" _Unk7="0x14"/>
<CancelData Move="SYORYU_M" Offset="0x5020L" _Unk0="0x0" _Unk1="0x0" _Unk2="0x19" _Unk3="0x0" _Unk4="0x0" _Unk5="0xa" _Unk6="0x0" _Unk7="0x5"/>
<CancelData Move="SYORYU_H" Offset="0x5028L" _Unk0="0x2" _Unk1="0x1" _Unk2="0xf" _Unk3="0x0" _Unk4="0x0" _Unk5="0x14" _Unk6="0x0" _Unk7="0x5"/>
<CancelData Move="SYORYU_EX" Offset="0x5030L" _Unk0="0xa" _Unk1="0x5" _Unk2="0xf" _Unk3="0x0" _Unk4="0x0" _Unk5="0x14" _Unk6="0x0" _Unk7="0x19"/>
<CancelData Move="SOKUTOU_L" Offset="0x5038L" _Unk0="0x2" _Unk1="0x0" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0xa" _Unk6="0x0" _Unk7="0x0"/>
<CancelData Move="SOKUTOU_M" Offset="0x5040L" _Unk0="0x2" _Unk1="0x0" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0xa" _Unk6="0x0" _Unk7="0x0"/>
<CancelData Move="SOKUTOU_H" Offset="0x5048L" _Unk0="0x2" _Unk1="0x0" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0xa" _Unk6="0x0" _Unk7="0x0"/>
<CancelData Move="SOKUTOU_EX" Offset="0x5050L" _Unk0="0xa" _Unk1="0x0" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0x14" _Unk6="0x0" _Unk7="0x0"/>
<CancelData Move="SC_SA" Offset="0x5058L" _Unk0="0x2" _Unk1="0x2" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0x14" _Unk6="0x5" _Unk7="0x0"/>
<CancelData Move="THROW_N" Offset="0x5060L" _Unk0="0xf" _Unk1="0x1e" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0x0" _Unk6="0x1e" _Unk7="0x0"/>
<CancelData Move="THROW_F" Offset="0x5068L" _Unk0="0x1e" _Unk1="0xf" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0x0" _Unk6="0x1e" _Unk7="0x0"/>
<CancelData Move="THROW_B" Offset="0x5070L" _Unk0="0x2" _Unk1="0x2" _Unk2="0x0" _Unk3="0xf" _Unk4="0x0" _Unk5="0x5" _Unk6="0x0" _Unk7="0x0"/>
<CancelData Move="CHANGE" Offset="0x5078L" _Unk0="0x5" _Unk1="0x5" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0x5" _Unk6="0x5" _Unk7="0x0"/>
<CancelData Move="CROSS_ASSAULT" Offset="0x5080L" _Unk0="0xa" _Unk1="0xa" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0x0" _Unk6="0x0" _Unk7="0x0"/>
<CancelData Move="CROSS_ARTS" Offset="0x5088L" _Unk0="0x1" _Unk1="0x0" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0x0" _Unk6="0x0" _Unk7="0x0"/>
<CancelData Move="PANDORA" Offset="0x5090L" _Unk0="0x0" _Unk1="0x3" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0x0" _Unk6="0x0" _Unk7="0x14"/>
<CancelData Move="LAUNCH" Offset="0x5098L" _Unk0="0x0" _Unk1="0x0" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0x0" _Unk6="0x0" _Unk7="0x0"/>
<CancelData Move="APPEAL" Offset="0x50a0L" _Unk0="0x2" _Unk1="0x0" _Unk2="0x0" _Unk3="0x0" _Unk4="0x0" _Unk5="0x0" _Unk6="0x0" _Unk7="0x0"/>
</CancelList>


This is just a list of moves that you can do in the STAND state, and…the unknowns might be AI weights for what to chain into what…not really sure. Anyways this is just an example of how this format is gonna look when its done.

Someone may want to write a GUI tool for editing certain parts of the file, this should be easy since there are good APIs for editing XML files. Let my tool go from BCM/BAC<->XML, and let your tool just touch the XML!
Edit: Just realized I left the Offsets in there. The offset thing just shows the original offset that part of the file had in the original file. Its useful for me since I am hex editing to test things. When its done they wont be in the files at all.


#9

It will support both, I state that clearly :confused:


#10

SFxT Project: C.

Calling it.


#11

Keep up this good work ! :wink:


#12

**Update: **The tool now reads all characters BAC/BCM for console and PC and produces the same output. It doesn’t rebuild files yet, but it prints out the offset of each element in the XML, allowing me to check and make sure all bytes are accounted for. So far it looks PERFECT. I have found a lot of things that I didn’t quite understand before in the files, such as hitsparks (The game uses a list per hiteffect) and on-hit commands (think SFX and camera shit like when you hit with launcher)

http://www.sendspace.com/file/hinxxr - Dump of all characters so far.


#13

You cant yet. However, you can use the offsets in the xml file entries to mess around until the tool is done.


#14

Pretty great. Using the offsets I’ve already started hacking away at Ryu, and it totally works.

I’m not very hex literate: the values for speed multipliers is stored in 4 bytes. How do I turn that into a number/float, mathematically I mean, not in a hex editor. How do get numbers from hex values when it isn’t just like, an integer 0-63 or whatever.


#15

http://www.tfinley.net/notes/cps104/floating.html


#16

You can use the Windows Calculator to convert hexadecimal values to decimal, or integers as you call it.


#17

Due to life hitting me in the face, its taking me longer to get rebuilding working. As a result, I am gonna upload current XML dumps and make a little website where you can browse the XML. Editing the files by using the offsets in the XML is completely legit for messing around, and perhaps you guys can help me find unknown values and things that arent labeled right yet!

First SFxT, then AE.
It will replace Ono completly


#18

A heads up, which you may have already picked up:

Some characters can walk forward and backward in multiple stances, but it appears that the way you’re dumping the files, I suspect that, since they have identical names (FORWARD, BACKWARD, etc.) they overwrote each other in the folder. For example, Steve has FORWARD for his normal backwards and forwards, but the file dump you used only has his FORWARD value for peakaboo stance.

Also, some general observations based on browsing the xml files. These are just intuitions based on hacking AE as well. None of this has been tested, because I don’t really know how using merely hex offset editing:

  • You’ll notice that with most characters, there are no scripts for being hit, falling down, etc. In AE, each of these was defined in the character file. I suspect the way it works, is if a basic script type isn’t defined, it actually uses a default script stored somewhere. The reason is because some characters DO have these things defined, but only if their versions of the script have unique aspects. For example, Marduk can do a few special attacks while knocked down - sure enough Marduk has versions of the knocked down script defined, with a CANCEL list defined for his ability to cancel the knockdown state into the special attack. Ogre is the same - he can, instead of waking up normally, go straight into his teleport-ground pound thing.

The real interesting implication, if this is true, is that we CAN overwrite these values simply by providing an appropriately indexed script.

  • SF4 used a system that was partially scrapped during development, where hurtboxes were mapped directly onto character models. Now, for most characters, they used a minor hack to basically ignore this system: they would make the character’s auto-generated limb hurtboxes invincible, and then manually add the “real” hurtboxes in what Ono! calls the hurtbox field. In SFxT, I suspect they abandoned this limb-modeling system entirely for hurtboxes.

This is also a guess, but I suspect they handle invincibility a little differently. In SF4, to make an attack invincible, you needed to give a scripted instruction to make the auto-generated hurtboxes invincible. In SFxT, there are none, so what they do is simply not generate hurtboxes on frames that are supposed to be invincible. If you want to add more or less invincibility, just alter the start and end ticks of the hurtboxes


#19

Nice catch!
I actually didn’t understand why that part of the files was so different compared to the AE ones, and forgot about that possibility! I will redump the files with stances having their own folder!

In fact, there is a CMN.bac that holds the data for all of the common states! You are absolutely right, and ill add CMN to the next batch of dumps!

This is also correct. However, I haven’t figured out how some moves are projectile invincible yet. Ill have to figure that out soon.

I started out focusing on RYU’s file, but I am going to need a more interesting target to use for testing, as there are so many things that don’t apply to RYU that many characters have.


#20

Some of the dumped data doesn’t seem to match up with the actual game. I’m specifically confused about Juri’s Fuhajin release, which I believe should correspond to HUJIN_L, HUJIN_M, and HUJIN_H in the hiteffects data. The actual damage they do is 40, 50, and 60, respectively, but the dumped data says they should do 80, 50, and 50. Also, for all 3 versions, the POSTBOUND_HIT effect is HIT, but in-game, it causes a normal knockdown, which should be marked as BLOW.