Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - quantumpencil

Pages: [1] 2
1
No problem, any time =)

Make some cool 4x cut animations for sephiroth =D

2
Hi, I've been largely absent from the ff7 modding scene for a few years due to work obligations but I recently started working on some old projects again.

I've been editing some animations for one of my projects and have hit a bit of a roadblock, at current moment I'm adding new animations to the SAAA skeleton specifically the ones that are missing and I've had a lot of success, using some resources online specifically the wiki.ffrtt and the work of borde and L Spiro. At current moment I'm working on animation #6 the 'death' animation that the SAAA skeleton is missing. It works in game and functions exactly as I want it to apart from one thing. For some reason the weapon is not where it should be and I cannot open the animation in Kimera, I assume this is because weapon animation data is stored in a separate file or a separate place in the **DA file, i've been looking online but can't find any information on the topic and I thought that maybe somebody more experienced would have an idea of where I should look.

Thanks in advance.

EDIT
So i've found something strange, editing the value at offset 40(decimal) in the **AA file seems to effect which animations have a weapon in them, for instance in my case I have added animations 6, 10, 16, 17, 18, 22 & 34 to the SADA file. Changing the value to 01 removes the weapon from all but animation 0 and 1, but when I do this I am able to edit these animations in Kimera without causing a runtime error. If however I keep it at the default value these animations are unable to be edited.
Basically I'm just curious if the weapon animation data is inside the **AA file(Though i doubt it due to it's length).

1: Yes, that's because weapons actually have their own animations, for player model characters they are offset by 0x34 within the **da files (and this is, unfortunately, how the battle engines finds them). If you want the weapon to animate, then you will need to repack a corresponding weapon animation at index 0x6 + 0x34.

2: That dword is the number of weapon models, it need to always be 0x10 for player models in the vanilla game or weapons with model ID's greater than that will fail to allocate properly, since the code that loads them checks that the weapon model ID (gotten from the low byte of a field in the kernel.bin for the equipped weapon) is less than that value before allocating and initializing the polygon file and bone for the weapon

3
Not true. Lots of scientific simulation and maths code is still written in Fortran. And safety-critical embedded systems are often written in Ada - I have a friend who was writing new Ada code for satellite systems as recently as three years ago.

Yeah, maybe, but it is also almost impossible for 99% of human beings to write large applications in C that are totally secure, unless you've got some kind of cybernetic implants in your brain. For instance - quick q, what's wrong with this snippet?

That second null check won't do what you think it will, at least at first glance.

Of course, fiendishness like this is exactly why I think C is rewarding to learn. But actually using it is a different story!

This is a very common C gotcha (attempting to dereference podhd via &(podhd->line6) is undefined behavior if podhd is NULL. The check for NULL belongs before the attempt at dereferencing podhd and really any C programmer will know that. There's nothing wrong with the "second check" except that it's misplaced, and most good compiler's (gcc, for example) will optimize it away as the attempt to dereference podhd in the previous line will let the compiler know (mistakenly) that podhd cannot be NULL.

Simple solution, check for NULL before you dereference pointers. These sorts of things are more of a hassle when you're learning than later on when you've developed good habits w.r.t NULL handling (responsible for about 90% of C's "gotchas"). Being able to propogate constraints like this and letting the compiler (or instructing it with __builtin_unreachable) optimize away unnecessary works/checks is another factor that contributes to the performance advantage well written C code enjoys over most other compiled languages.

While I may have exaggerated about C/C++ being the only choice in those domains, it definitely has by far the largest marketshare. Ada isn't used outside U.S defense/aviation as far as a I know (and as much of a chore as the language is to work with, the extremely rigid typing and so many extra security checks -- totally makes sense for "mission critical" software so I'm glad it's preferred in those spaces. The amount of work to get a similar level of reliability out of C would definitely not be worth it, but that's not C's niche and that's fine -- just as the vast majority of problems in the domain above are not so 'critical" as to warrant the 5x development  time that results from trying to use the Ada ecosystem and deal with inane number of error checks it mandates. For that fast majority of speed critical applications, C is faster, much faster to develop in/easier to work with, portable, and "secure enough" provided your team is experienced enough to avoid the most common pitfalls.

Fortran is still around in some legacy code (and numpy/scipy) but mostly seems to be a legacy code language still adored by academics (and hence scipy/numpy, and other scientific computing libs are often written in it). I don't have any personal experience with the language, having only briefly encountered in in undergrad in the context of simulating physical systems in physics class before I realized I wasn't very good at physics. It's not as fast as C/C++ and those sorts of numerical modelling tasks are HPC, so I really don't understand why it's the preferred language for physicists in particular... but it is =p. Maybe someone with more physics experience (I never got past QM I) could offer more insight there.

4
The only reason Delphi died (although it hasn't) is because of poor decision making by Borland in their hay-day, coupled with the fact they were competing with the might of Microsoft (who also ship the libraries and even freeware compilers) meaning many gravitated towards C over Delphi.  Also, I hear, MS bought out loads of Borland's team.

As a language, Pascal is superior imho.  It was, after all, made to create good programming practices:

https://en.wikipedia.org/wiki/Pascal_(programming_language)

And came after C.

I think C is a terrible language and this becomes more apparent when you see mediocre code that will then not compile properly on another compiler. 

If you want to create a portable, self sustained program that will work almost universally when you ship the source to another person, then Delphi - or any other high level language - is the way to go.  I don't need to mess about with memory management, crazy syntax, and other annoyances.

Of course, no-one is going to agree on this - but I'll dance the day that C dies.  ;D ;D ;D

The trouble we've been having with Aali's source would never ever have happened with Delphi - the language simply doesn't allow for it.



The trouble with Aali's source is just due to it being a large project with no sensible build system, and no management for its dependencies, it has nothing to do with the C language specifically. Also the reason that similar C code may not compile on different compilers is directly related to other strengths of the language and it's very wide adoption, namely:

1: Unlike other languages, there are actually different compilers as no single organization "owns" C and it's useful enough in a wide range of domains to warrant compilers optimized for specific types of problems. Also competition leads to innovation and both gcc and MSVC are incredibly good compilers by pretty much any measure, capable of extremely sophisticated optimizations.

2: It does not have the additional overhead of an interpreter or a runtime virtual machine (like JVM or BEAM) so the machine code runs without any other layers of virtualization.

It's also actually the most portable language that doesn't require some immense amount of overhead, and there are many domains it is *exclusively* suited for.

Pascal (and probably Delphi too), for example --  is way less portable than C or C++, getting it to work on anything other than windows would be a nightmare. People program toasters in C, robots, and a large maority of embedded systems. As the easiest and most portable non-interpreted or runtime VM based language, C enjoys many advantages in a great number of circumstances. Those advantages have tradeoffs of course, but so does the convenience and hand-holding of C's competitors.

You may not like it --  but C and C++ (especially C) are the de facto languages of systems programming, embedded systems, games programming, drivers, vms, compilers, interpreters and any performance sensitive task for a very, VERY good reason.

I hate to say it, but you're gonna be waiting a long time if you're hoping for it do die =p. It's been forty years and nothing has really threatened it's position in any of the above domains.

Also Pascal (I don't know about Delphi's history specifically) lost to C because of the rise of Linux, crappy portability, poor (and late) advanced OOP extensions, and being too verbose (ok, the last one is just my opinion). No language with a single proprietary 'creator" which doesn't open source it's compiler is ever going to keep up with a language like C/C++, which has huge communities improving gcc/domain optimized toolchains and contributing to new new language versions to this day. So Microsoft may have played a role, but there was definitely more than that to the story

5
I don't think it's a good language for any user.  It baffles me why it's so popular.  Not to mention all the different compilers with their different quirks.  The language doesn't promote good efficient coding.  It's an annoyance. 

To this day, people keep repeating the lie that it's faster than other languages.  It just isn't.  They all end up as assembly and all modern languages have optimization.  The differences you will see at that level are not perceptible.

https://aplawrence.com/Unixart/C_is_for_Crap.html
https://www.radford.edu/ibarland/Manifestoes/whyC++isBad-printable.shtml


This is not true. It's strange to say that a language is faster than another language; obviously you could write horrible C-code that constantly cache missed, inefficiently allocated/de-allocated memory many times, is chock full of copies, etc. However C does not force you to rely on higher level "safety" features present in most other compiled language which means it does allow you to write much faster code than in most other languages. There's a reason why it remains the only choice for real-time (deterministic) programming tasks, or embedded systems programming. It's also lean and contains a small but useful set of core language features that are fundamental to computer science as a discipline -- unlike C++ -_-. Also this difference is absolutely perceptible, usually can be as much as 1-2 orders of magnitude over similarly well written code in a more restrictive language.

That's not really why it's good for a beginner, it'll be a while before you're worried about structure your data and iteration loops in a way that allows the most efficient pre-caching, or aggressively pre-allocate to avoid mallocs, etc. Getting the most of the freedom C offers requires substantial maturity as a developer and it requires you to structure your code in a specific way. If you don't have that, then sure, some other compiled language might get close to C's performance -- but everything you depend on is written in C, including many interpreters/compilers/drivers, and this is the case because in the hands of someone who understands programming at a low level it is STILL the best choice available. It's also the best choice available for editing compiled executable files,  as it will let you get very close to the metal and won't get in your way with annoying unsafe blocks or restrictions on casting like other language which are attempting to 1-up C (Rust, for example -- and have failed) do.

C is good for a beginner because in order to be able to use it all, it requires you learn common transferable skills and  develop a deeper understanding of core programming craft/CS concepts, which is a huge part of being a competent software engineer. There's no chance you'll spend much time working in C and not quickly develop an understanding of memory management, calling conventions, all steps of the compilation process (linking in particular), encoding schemes, etc.

Better tools are useful, but one should not be reliant upon them. This is why it's crucial that every engineer, at some point in their career, invest in learning C well if they want to expand behind writing CRUD app code and really begin to understand not just "x web framework" but computer science more broadly.

The other thing I will say that hasn't already been said: Learn a text editor well (Emacs/vim) and learn bash.

6
Thank you ergo_joe =). I've not been visiting the forums regularly since I joined the discord, but this is helpful.

I'm relocating all the kernel data right now, then I'm going to come back and do the same thing with the model data. Should be able to add new animations, items, weapons, armors, and materia within just a couple of months =)

7
Hardest part is going to be figuring out the animation structure and mapping it, I think. Kimara must already know this so its source code should help, but I need to figure out what chunk of **da data is getting copied/indexed by FF7. If the process is dynamic or based on metadata in the other model files, then we might be able to just extend Kimera to create new animations instead of having to malloc new memory specifically for a given animation -- and the game will just load them and convert

This would really be preferable, because the game dynamically loads/indexes model animations in battle based on the models present. From what I've seen so far, I think it can load a dynamic number of animations per model based on the **da file structures (which I don't understand yet).

Once they're loaded with a new index, we're done =p.

8
Don't try to take the easy way (because there isn't one). Realize that being a programming/CS are huge fields with a lot to learn, and prepare yourself for a multi-year journey.

I would suggest learning at least three languages, in the following order:
  • one classical systems language(C)
  • one functional language (Elixir/Erlang would be my bias cause <3 OTP and BEAM)
  • one scripting language (Python, probably).
  • If you want to learn specifically for modding, learn x86 after C

I would suggest C first, as it's the classical programming language and a lot of other popular programming languages are modeled on it. You can get close enough to the ASM to write code in C calling fist size structs in compiled executables, etc so it's by far the most useful languages for modding compiled code. C++ is also woefully complex for a beginner, I've worked in it for like 10 years and probably know 25% of the language spec cause it keeps getting more bloated.

Also take at least one systems programming course and one algorithms/data structures course, or familiarize yourself with the relevant material. Graph-traversals, dynamic programming, greedy/random algorithms, hashing and complexity analysis are tools you want in your toolbox for general purpose engineering. Systems programming will help you understand how code actually executes on your system, the various levels of virtualization involved, and is basically what you need to be able to mod a compiled executable.

I recommend this mostly to expose yourself to different paradigms and ways of thinking about code. Don't waste time on specific frameworks at first, this or that web-hotness is always changing and once you have a strong conceptual understanding of the foundations of programming picking up a new "framework" takes a few weeks of reading a codebase written in it + documentation.

To this end, remember to READ code, especially at first. Then try to use patterns you encounter in your own projects. You won't become better if you just write code, because -- well, you don't know how to write it. Gotta imitate before you innovate =p.

For getting started, I suggest you consider enrolling in Harvard's CS50 course: https://www.edx.org/course/cs50s-introduction-computer-science-harvardx-cs50x. It's free, and the first course in the series is taught in C and will do a good job familiarizing you with what I consider to be "the basics."

9
Would definitely be cool. I'm going to go ahead and try this in the coming weeks, my first test-case will by my float status effect for my upcoming tactical elements mod.

Ideally I'll be able to play the characters idle animations but transpose them up by a certain amount by adding a new animation per character of them "floating" up and "floating" down which is essentially the same thing the OP asked for but I'm not gonna do a bunch of work on the animation aspect (Animation will literally just be them moving straight up in idle).

If I get that working I will of course post and update and share my findings, any of these ideas are possible at that point.

10
Yes, I could probably do that.

You'll need more than one animation though. I would suggest the following at a minimum:

1: Take the animation where Cid changes into the back row as a base (03). Edit that animation in Kimera to look like a "jump" animation and make sure that he jumps really high off screen when it is used.
2: Take the animation where Cid changes into the front row as a base (04). Edit that animation to start up in the sky and "jump" back down to the ground.

That's all you need in theory. We can use a script like the change/row script with the opcodes that change/return model location(don't remember which ones, but they're in my disassembly) to have Cid jump off screen. Then we can flag him as not able to be targeted, and set a jump bit somewhere in his AI battle data. Whenever that bit is set, his just need to write a main-script that enqueues a battle command which uses Throw animation to have him rain down some lances on people by setting the data we want prior to the execution of the command. We can run the return to ground script after a certain number of C or V-Timer ticks (I'm doing this for burn already)

I wouldn't know how to create an entirely new command (I could replace one you don't care about and rename it "jump" on the menu) -- that might be possible too but I haven't looked into doing something like that yet.

11
Of course it's possible, this is just a program, and we can inject an arbitrary amount of Turing complete code into it so in theory it's possible =p.

I think it's practical as well. I recently hacked the game using DLL-injection to run a new animation script under specific conditions for my burn effect. (Simplest possible script, E8 EC FE =p)

There's really only two steps beyond that needed to do what you're talking about:

1: Someone needs to reverse engineer the structure of the animations themselves in the **da files so that a new "animation" can be created.
2: Someone needs to figure out how the game "looks up" a given animation that appears in an animation script (Where the **da files get loaded and where the pointers to the correct indexes get stored) which is just a matter of doing some more reversing work on the function that runs the animation scripts.

Then you just need to malloc a new struct to holding the custom animation you want (the *da clone data) and rewrite the opcode handler (The animation script doesn't actually think of low indexes as opcodes, so the "byte" of the specific model animation) to look up that index at your memory address instead of where it usually goes.

Depending on generated x86 that could either be super easy (If the opcode/handler for animations is a different function, you can just replace/redirect the function, which is the easiest way) or more difficult (might have to patch the raw ASM to make space for a call to a new function that does what you want).

12
EDITED to reflect solved problems.

Ok, I have found out how the relevant offsetting/handling of magic actually works. It is handled by the routine at 0x4281B1, corresponding to animation script opcode 0xE8. This explains why only matching command indexes AND model scripts can summon effects. There is a switch 31 in here, and based on the command ID, it fetches the final copy of the (relative animation ID)  and looks up an index in a table; This is an index to another big table of subroutines associated with various "animation" effects. (Mostly, Magic also has a few subs at random places handled by a secondary switch). These subs get passed to 0x4284A7 which actually executes the animations (and hits opengl libraries)

This is possibly the least modular way I can imagine this being implemented. It would still be possible to execute an Enemy Skill or something with a magic animation, but it requires some ugliness. Only way I can think of is to wrap this function and then prior to calling the original, change the Command ID and the Animation Indexes to whatever you want based on their copied values; i.e, if the it's command 0x0D (ES) with Effect ID (0x04), Instead go to the magic case with ID 0x1B and you got Fire. I'll work on a wrapper like this, but this is the actual code (I stepped through the animation frame by frame) so it's gonna work =). Not as elegant as I'd hoped though.

This also means getting burn to display will be a little tricky, as this function doesn't have a "case" for command index 23 at all, meaning I do not think that index can ever display additional effects Even if the particular model animation allows it (I know this, from testing, but now I know the reason). If this function is still called for out of range indexes then that's not too bad, but if it's not it might be annoying.

Moreover, I have found out how the game actually gets "which" script to run. This was hard to reverse as runAnimationScript is constantly running asynchronously for various actors, but basically the block that sets the ptr is at 41FBBB and it's said by taking the commandID (1D) for magic and offsetting from a ptr which is set per actor when a game,the ptr is at 0x8FE2AC, and is different every battle. For command indexes less than 2E, this is the final say on the script being run. This script is iterated over at 0x41FD66, opcode by opcode  and the calls underneath it touch openGL.


UPDATE:Burn effect is now fully functional for both player and enemy characters, and animated =).

13
Thanks ergonomy_joe! Definitely helpful, I think I mis-reversed the struct initially, +1 is the current opcode, not a ptr to the script -- that had me going down some wild goose-chases. This should help reversing the individual opcodes =)

Ok, some more progress tonight. This is as much of the path as I have figured out between "Command" and "Animation Run"

1:MainActionRoutine calls command specific loading functions which set the MainBattleStructures animation related fields.

2:The function which inflicts damage for most commands calls another function at 0x5DBD40, where it calls a "copy" anim data function at 0x5CAB7C.

3: The function at 0x5CAB7C just copies the animation related data and calls another function at 0x5C7DEA with with the AnimData as args.

4: The function at 0x5C7DEA copies this data into two different arrays of maximum size 0x40(EDIT: 0x40 and 0x80, actually), both of which have element sizes of 0xC: These two arrays are located 0x9AAD70 and 0x9ACB98, and the indexes (maintained separately) at which these structs are enqueued are held at 0x9AEA9C and 0x9AEAA0, and incremented after each copy.

5: The data in these structs is consumed 0x42CBF9, which seems to copy data from a specific "enqueued" animation block into ANOTHER array of structs of size 0x20, which starts at 0xBFB710(CommandID ends up here) and a giant array with elements of size 0x1AEC (haven't found the start of this one yet, but the "Animation Effect ID" form kernel.bin or scene.bin ends up here) The values in these structs are directly referenced by The function ergo_joe linked which runs all the scripts

Some copyceptron right there

Surprisingly, Even though I've traced the animation index and command indexes this far (which is pretty close to the end) I still haven't come across the relative offset math used to fetch actual additional effects. Nor have a found where the game actually says "If the command index is 0x02, run the 'magic cast' animation script -- which is the paydirt.

14
C is a lovely elegant language with a small set of tools that are unrivaled for close to the metal programming, I don't understand how someone could dislike C =p.

C++ is a bloated monstrosity with such a large language specification and every new programming paradigm that comes into existence quickly thrown on top -_-. I've worked on a few C++ codebases and they shared almost nothing in terms of design patterns, they were such distinct  language subjects they almost felt they were written in different languages.

If you want an IDE for C I suggest CLion.

15
UPDATE: The stated goals here have been achieved. I have a burn effect, displaying the "fire" animation on every tick, working for both enemies and player characters =). Thanks ergo_joe for the help,  looking forward to announcing/sharing some things with all of you soon =D

Starting a new thread for this specific issue. I've successfully gotten a fire-elemental burn effect working, which ticks alongside poison (but is inflicted/removed differently) by hooking into the poison callback and poison data setter that's run in the games main action routine(0x435D81) during the big switch statement on the command that loads data and calculates damage.

I would like to have these ticks display a fire attack. the main current action struct of size 0x260h has fields 0x24 (which is set from ability data to the effect ID toplay) and 0x14 (which the wiki says is the base index for calculating absolute animation indexes from relative ones). Unfortunately setting thes to 0x01B and 0x00 by replacing the poison-preparation function(0x5C9FC0)  respectively does not cause poison (issued via command (0x023) to play the fire animation.

So there are two current goals:

1: This whole mess about relative animation indexes is inconvenient for modding, as it would be great to be able to reuse all animations in any context; So I am going to work on replacing this behavior with a simpler absolute animation index system, so that any command type can use any animation.

2: I want to get the new burn effect to display the Fire 1 animation on tick (Which is probably more difficult than 1, as I recall certain player ability "scripts" call additional affect animations -- and poisons 0x23 command likely has no animation scripts associated -- so it's possible a very simple script which does nothing but display the animation effect itself at the target location will need to be created, if there is no "idle/no actor animation and then display an effect at target location" ability-effect using script currently in the game.)

EDIT 2 - GOOD PROGRESS: Did a bunch of reversing tonight. The scripts in question are actually loaded from the model files, and accessed by a routine which switches on the opcodes in the scripts which lives at 0x41FBA4. This function seems to be holding the a pointer to the script in ebp-14h, which it's setting based on some kind of other switch statement, but I don't quite understand what this is doing currently.

Now I have a much clearer idea of what I'm looking for, if anyone wants to help reverse/knows this. Basically this function gets a pointer to an animation script and runs it. These scripts are loaded up from model files. When the an action is popped of the battle queue and its main action routine is called, there must be a way in which the information about that attack reaches this function for the execution of the animation.

We don't need to fully disassembly 0x41FBA4 right now (it would take a while) to get a ton of power here; If we can just trace how we get from "setting a bunch of fields in the BattleDataContext Ptr" to "Ptr to correct action script is parsed by 0x41FBA4, we can interject code into the process and instead pass a ptr to a custom animation script under-the right conditions (which we can just hold in RAM somwhere).

This would be sufficient for injecting and creating more or less arbitrary in battle animation effects -- we'll just need to figure out a model script which corresponds to magic, and play around with the op-codes until we get it to "only" display an added effect (replace the 1B with 00 and try to shorten the length it's played). Then when-ever the command index is 0x23, run that script =)

16
Update: I've finished reversing most of the EventList and BattleActionQueue enqueue/pop logic (thanks ergonomy_joe =)), and while I still haven't totally figured out how the game is managing "time" --  which is the last piece to get dots working, I have thus far successfully:

Created a new mechanic for cloud where he has a chance to use double cut or combo an attack with death-blow (like added cut if the added cut were deathblow) after every physical attack, without materia (the first done by re-writing the attack index prior to the main command handling routine, and the second done by generating an event corresponding to "Deathblow on the current target" of priority 0 immediately after a "attack" from an actor identified as Cloud is issued.

Found the data that needs to be edited with to enable a class mod (There's a giant struct of player character data that holds enabled commands. By modifying it in BattleMain (after it is populated), you can pretty much give commands to characters by default without materia, i.e Yuffie can be given innate skills.  Similarly, you can disable access to certain commands, magic, summons or E-Skills in battle). Proved by giving Yuffie innate steal and no access to Deathblow, even if the materia is equipped. 

Replaced Sense with Provoke (Could probably do this without replacing Sense too, but it'd be harder): Enemies record the "provoker" mask in their unused AIVariables data block. If the provoke bit is set, then before any action, change the target mask to that AI stored value. If Sense is used, don't call the damage from the pointer table, but instead just set the bit associated with provoke  in the target, and store the actor mask in the targets AI block.

Once I figure out how the  game does all this clock magic, DoT affects will be next =D

17
Ok, so I got some time look into this. calling the sub (enqueue action?) called within the poison routine with the same arguments called there can be used to, unsurprisingly, re-create the poison effect in random situations.

enqueue_event(attacker_id, 3, 23, 0, 0) are pushed onto the stack prior to the call. The parameters are (as far as I'm able to tell):

attacker_id, some kind of queue priority, command index (poison has index 23h, which is capable of dealing damage, but I'm not sure where the data for these indexes are) attack index, and another 0 (I don't know what this one is for yet)

I have major need for this mechanic, as it is a much better way to implement, for instance, an overheated status (create an attack that does massive fire damage and enqueue it when the physical formula is used by an overheated actor).

So does anyone know what the last argument in the enqueue function is, and...
does anyone know how where the game is looking for the action attack metadata of poison (i.e, the fact that it uses formula 3, it's poison elemental, etc).

Thanks again guys =)


18
Alright, so it looks like referencing the unused variables at the end of those actor battlevariable blocks (the 68h array) in memory and applying extra damage modifiers based on their bit-state accomplishes the true elemental interaction modifiers I wanted. Current action elements are 0x44 in the "battle context struct" (the one with the large gap in between that has current ability data) and so that plus appropriate left/write shifts (which I stuck into the routine at 0x5DB593, which already handles elemental weakness/strength multiplication based on a different intermediate "current element interactions" variable set a previous sub (somewhere in 0x5DB593, though I haven't figured out exactly where) was successful.

Now I'm interested in the duration of  various expiring status effects and how the game handles that. I tried to do this through some truly ridiculous AI script (I used an invisible actor as a clock and kept localvars for every actor, and then checked the 'clock' actor every pre-action script, expiring the status after so many 'ticks' had passed.

Now that I've got routine replacement as an option, I'd prefer to see if these various effects could be made to expire the same way poison currently expires. I should be able to just malloc a new array of length 10 and the required size at runtime and use it as a place to hold any data needed (per actor) to handle the expiration. I'd like to see how the game currently expires its timed statuses, but I haven't had any luck finding the routines that manage/increment the clock or expire status effects (I think as long as I know where the game stores the in game clock, it should be possible to implement this logic). Anyone know where any of these (especially timed status effect expiration) live in the exe?

19
Thanks for the help guys. I'm gonna see about resizing the 68h actor array/relocating it somewhere else in memory. As many size-locked references to this struct as there are in the codebase, I think it may end up being simpler to just make a new array and get the AI engine to write new status data (I'm using battle variable 4310 as a new status mask in my mod) or locate exactly where that byte is being accessed by the AI scripts and have the engine access it from there (I suspect that might actually be the end of this actor struct array).  Either way hopefully once I get it figured out I can add an AddNewStatus() function utility to the dll injector.

@NFITC1 or anyone else who knows, you said the battle local_var correspondence correspond to battle vars 4000-42E0; It looks to me like these structs *are* what the scripting engine accesses/modifies when an AI script writes to actor data (They seem to be updated as expected by AI scripts when I've run them in debug mode and watched the structs), but I want to make sure there is no rawer form that is copied into this struct somewhere.  (As it seems 4300 - 433F, which  I've used extensively in my mod, are actually included in this struct as well, that's probably not the case).

Also wow,  that additional effects method is as almost as intimidating in C as the x86 version =p.

20
PM'd you  about IDA-Sync =)

I'm confused:

1: Are you saying the total struct has size 0x260h or that each actor has a struct of size 0x260h? Also, as I often express myself poorly, a clarification: I'm not talking about the struct pointed to by the battle pointer in my last post (I was in the first post tho), I think that is a different struct (and that one is 260h, I think) but a separate array that is sometimes used to access target/actor data that isn't retreived from the battle pointer. Example here:

From Magic Hit formula (Intel syntax):
mov     edx, BattleContextPtr
mov     eax, [edx+208h]
imul    eax, 68h
xor     ecx, ecx
mov     cl, byte_9AB0E5[eax]

This is only getting the "target id" (an integer) from the battle context_ptr and then referencing an array of contiguous structs starting somewhere around 9AB0E5 (but that's not the real start, that's the "level" of the first actor) and then getting the level of the target by offsetting 0x9AB0E5 by target_id*68h

That is in fact a contiguous array of structs of size 68h right?

21
Fantastic! So that method corresponds to the "effects" that can be assigned to an ability (Multiple Hits, Fills allied limit guages, etc)? Or do you mean additional effects more broadly.

As for the data structure referenced for calculation, I've noticed that there also appears to be a separate array of actor data structs of size 68h stored around 0x9AB070 (I think it starts here, not sure because instead of offsetting from the beginning of the struct, things are offset from the particular thing being fetched in the first actors struct), which seems to have some stats that aren't accessible from what I'm calling the "context" pointer. Target Level, Actor Status Masks, etc are often gotten by taking target ID from the context ptr and doing 68*target ID byte offset math to fetch the relevant actor data.

Now these structs are only 0x68h in size as opposed to the AI script accessible actor blocks of 0x3ff (masked addresses of 4000 - 43ff) so they clearly aren't the AI accessible actor blocks, but they also seem to be affected by changes made to the AI blocks. Do you/anyone else happen to know where information from the AI script accessible actor blocks gets gathered up into these smaller engine accessible blocks?

Depending on how that consolidation happens, I think it may be possible to implement *actual* new status effects within the engine with a nice C API. If the unused actor data (4300 - 433f) is not already being saved (via an object copy) to these blocks, they can be resized (by just relocating the data at runtime) to include new masks for new status effects, that can then be handled by damage calc, or elemental modifer routines, and possibly display visual effects =p

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ASIDE: NFTC1 btw if you want to sync IDA files (In case you have a lot of stuff labeled in it), I've got a plugin for exporting/importing the IDA db to json format for version control purposes. I'm planning to host this json file on github for modders along side this routine replacement toolkit so it's easy for any information about the .exe currently known to be accessed by anyone.

UPDATE: I've successfully replaced the physical damage routine with a routine which always deals 1 damage, and the game runs fine with it. I'd like to have some #includes (read: big structs) for all known data structures used in battle so they can be referenced in C++ in a human readable way and not as offsets. As long as the function signatures match (well, the argument counts match) so that the stack is not corrupted, we can in theory replace any function without needing to do rewrites on the exe, or worry about space constraints.

In particular, I think it will be very easy to add new formulas, once I get passed the data protection issues, we can relocate the function ptr table somewhere else in VRAM with more space and then register new formulas by function_ptr.  I'll try this next while waiting for more info on data.

22
I've been going through the exe battle routines and have a few questions/observations

1: The routine at 0x5D173F chooses the damage formula to call from a pointer table located at 0x8FF1F8. This same routine calls a sub 0x5DC880 which is quite daunting, but appears to be being passed a "0" and a "1" via the stack (as is standard with cdecl calls like this) and is called both before and after the damage formula pulled from the ability data in this routine is called via function pointer. Interestingly enough I can't see where this argument is used within the sub at 0x5dC880. Due to it's size I'm not totally sure what this sub does,  does but it seems to have some roll in preparing the battle context object pointed to in all damage formulas. Anyone made any substantial progress understanding this big guy?

2: The large data structure which is referenced throughout damage calculation and formula selection (and is pointed to by the pointer at 0x99CE0C) seems to contain a lot of information from my inspection, it contains at the very least attacker/target stats, ability data, and some attack flags like whether or not something crit. Has this data structure pointed to by 0x99CE0C been mapped by anyone in the modding community? I've got myself a little loader/dll injector for redirecting routines, but in order to make the redirected routines (and hopefully expose a C api for redirecting exe routines at runtime) I need a better understanding of this data structure -- it looks rather amorphous, I don't see evidence of a clear ability data struct or anything like that at the offsets which seem to correspond to ability flags (like context_ptr+ 48h, which is definitely ability power, or context_ptr + 6Ch which appears to some flags, one of which is "auto-critical")"

Thank you for your help =)


23
Yep, it sets its physical immune flag based on the performed actions action index (turns it off for 3, which is limit) which tells me that global variables like 2120, 2050, etc are set prior to pre-turn scripts.

My issue is that in order to half/double (or otherwise scale) damage taken based on the element of the previous action, I actually need to double or half the attackers level instead of the targets, diamond mutates his own flags.

So I need some way to get the index of the actor who used the attack during pre-turn which is being executed, if that was the case I could just do:

Pre-Turn
If self.soaked_bit_on{
    If 2120 bitAnd 8192 { ## was bolt attack  check
         If not already halved (will store this var in my global clock actor so its the same for all actors, and keep multiple actors from messing with it){
               temp = self.previous_attacker.level
               self.previous_attacker.level = temp/2           
         }     
    }
}

I can then unset the already_halved far and re-assign the attackers correct level in the counter script to achieve the desired effect.


EDIT: Actually, that will cause damage to be doubled for all targets if even one target is soaked, in the event that an attack hits more than one target =(

Is there a pointer table in the exe to the various formulas with actor/target stats in specific registers/fixed addresses for the jump, so that one could find an empty block and create a wrapper around base damage calculation which still performed the calculation according to the pointer, but did something like...

If target level = 255, bit-shift right the base_damage
if target level = 254, bit-shift left the base_damage.


EDIT: I've disassembled the exe, and with help from NFTC1, found the relevant routine. I have successful redirected the function in the exe to a (non functioning) custom function at run-time, so The damage formulas reference a context pointer for most stats/checks, so they have more or less global access to battle state making this much easier. I'm now confident I can implement this as described above with a bit more work tracing the formula calls to make sure my custom functions are referencing the arguments correctly.

 

24
I'm preparing to release a tactical element mod which adds 16 new status effects (mostly elemental) and elemental interactions via (somewhat lengthy and involved) AI scripts.

I've got a hidden actor working as a clock for timing/executing elemental effects (like proper burn/bleed statuses) and via using the 2120 global previous element mask and bitwise operations, this should work both when elemental materia is used to add an element to a weapon strike, or its a normal spell/summon.

Most everything is working, except one piece -- I need to be able to dynamically set an actors elemental weaknesses/resistances (double/half) within the AI script to accomplish my initial vision for this (or otherwise, and likely much more laboriously, boost/reduce damage based on element) Looping through all the bytes it seems proud clod/wall market do not recognize which addresses hold these masks, though they do exist for null/absorb elements. I was wondering if anyone had already figured out if any of the currently unlabeled actor data bytes are half/weak masks.


Example of what I am trying to accomplish:

Use water attack on enemy x, enemy gains the soaked status, which has the following interactions:
next lighting attack does double damage and has a 100% chance to paralyze (provided target is not floating),
next wind attack deals double damage and inflicts the chilled status,
next ice attack instantly freezes the target solid (so they can be shattered),
fire does 1/2 damage and removes the status.


All of this is currently working except for 1/2 fire damage and the multipliers on the lightning/wind effects.


EDIT:

I'm also trying to see if I can do this via stat manipulation

It looks like lowering the level of the target in the pre-target script doesn't affect damage (It's not a factor in damage formulas... too bad not every formula scales like conformer =p), though lowering/raising the level of the attacker prior to damage calculation would scale perfectly. Since I want this to work for both player characters and enemies I can't  lower the level prior to an action in the main script; Is it currently known when the actor values which track previous physical/magical attacker are set? If these can be accurately referenced in pre-action setup script then I could modify the attacker's level conditional on the element of their last attack (in 2120), and then zero out previous/current attacker masks at the end of the counter scripts.

So, tldr; can counter:preTurn scripts access the "2060.41E0" (I think that's it) to get the bit-mask of the user of the attack which is targeting the current actor, but that has not yet executed.

I'll try and check this when I'm back on my desktop which has FFVII set-up to run, hopefully that's the case =p. That would be even better, as it would stack with normal weakness/resistances


25
Chocobos, eh ?
10 bucks it will be replaced by motorcycle.

Agreed, and that is a horrifying, horrifying thought.

Pages: [1] 2