Thanks ;) by the way im sure you can add the .dll into the program when building it. Some people choose to leave them out because it makes the program bigger i believe. I've heard of "external dependencies" when building source code so im sure you can choose to have it built into the program or make it so you can get the .dll seperately. Not sure how Codelite + wxFormBuilder works though.
I also think it would be useful if you still gave the number of the formation. So on Disc 1, the Beatrix battle is file0, so having it say "0: Beatrix" would be a help.Okay, I'll add that.
I'm quiet sure there is a simple way to remove the dll dependancies (it should be an option passed to the compiler) ; my attempts to do it just didn't work :(
05 D6 1E 0E 7F 02 EE 00 05 79 01 29 24 7D 10
27 1E 2A 7F 02 08 00 05 D6 1F 7D 01 00 2C 7F
10 27 = 10000.1 byte Unknown
1 byte NbGroups
1 byte NbEnemyTypes
1 byte NbAttacks
2 bytes Battle Flags
2 bytes Unknown
1 byte Group Frequency
1 byte Nb Enemies
2 bytes Engaging camera ID
2 bytes AP
2 bytes Unknown
[
1 byte Enemy ID
1 byte Targetable Flag
2 bytes Unknown
2 bytes Position X
2 bytes Position Z
2 bytes Position Y
2 bytes Facing Angle
] (x4)
4 bytes Status immunity
4 bytes Status evasion/auto-status
4 bytes Status initial cast
2 bytes HP
2 bytes MP
2 bytes Gils
2 bytes Exp
4 bytes Drop Item
4 bytes Steal Item
1 byte Unknown
1 byte Collision size (it tells how large some effects must be, such as scan)
2 bytes Aiming position, as you said (though I don't know more how it should be interpreted)
2 bytes Model ID (thx Zande for this and the followings)
2 bytes Animation ID 1
2 bytes Animation ID 2
2 bytes Animation ID 3
2 bytes Animation ID 4
2 bytes Animation ID 5
2 bytes Animation ID 6
4 bytes Unknown
2 bytes Attack Power
1 byte Speed
1 byte Strength
1 byte Magic
1 byte Spirit
4 bytes Unknown
1 byte Elemental guard
1 byte Elemental absorb
1 byte Elemental half
1 byte Elemental weak
1 byte Level
1 byte Class
1 byte Unknown
1 byte Physical defence
1 byte Physical evade
1 byte Magic defence
1 byte Magic evade
1 byte Blue magic
2 bytes Unknown
2 bytes Cursor position (not the one you mentioned but pretty much the same thing if I remember well)
2 bytes AKAO death ID (sound when he dies)
2 bytes Cursor position (the one you mentioned)
16 bytes Unknown
2 bytes Shadow Gap Y (didn't investigate it...)
7 bytes Unknown
1 byte Drop card
10 bytes Unknown
1 byte Unknown
2 bytes Model ID (though it seems unused ; the real model ID is in the 0x11 chunk file with the attack animations)
1 byte Unknown (often 1F or 5F)
1 byte Effect
1 byte Power
1 byte Element
1 byte Accuracy
1 byte Flags ("use reflect", "is magic" and I don't know the others, unfortunatly :/)
1 byte Status
1 byte MP cost
5 bytes Unknown
And finally, 4 bytes end the whole thing, but I don't know what it might be.D40D 7D0200 20 D809 7D0000 18 27 7F
is translated into :( Var_D40D == 2 ) && ( Var_D809 < 0 )
20 is the == operation, 18 is the < operation and 27 is the && operation and 7D announce a short numerical value. So it is read like that :D40D 7D0200 20 -> ( Var_D40D == 2 )
D809 7D0000 18 -> ( Var_D809 < 0 )
27 -> ( Var_D40D == 2 ) && ( Var_D809 < 0 )
The result is put on the stack (for a following conditional jump, for instance).16 bytes Unknown
2 bytes Shadow Gap Y (didn't investigate it...)
7 bytes Unknown
1 byte Card drop (00 to 63, FF is none)
9 bytes Unknown
[end of Goblin]
09 09 09 09 09 01 f9 00 ff 02 ff ee 01 00 f6 f9
fc 00 17 00 b6 00 b4 00 01 00 00 00 00 00 01 00
00 00 00 00 [36 bytes]
[Fang] 04 e0 00 44 00 00 00 00 00 00 00 00
44 00 aa 00 5a 00 17 00 ff f4 f0 ff ec f0 ed f9
70 03 97 00 c9 06 c9 06 c1 06 cd 0d bd 06 bd 06
00 00 00 00 02 00 08 00 13 08 08 0a 10 00 00 00
00 00 00 01 01 02 64 0a 02 0a 03 00 09 00 13 00
82 00 03 00
0d 0d 0d 0d 0d 01 fa 00 fd 00 fd f7
fc fc f6 f9 f9 00 83 00 ee 00 44 01 22 01 00 00
58 00 01 00 00 00 00 [35 bytes]
[attack data] 00 00 00 fe 1f 08 08 00 64
2c 00 00 80 00 00 00 00 12 00 fe 1f 40 08 01 00
...............................................
The only explanation is the attack data is wrong. It has one less byte near the start, and one more at the end. Because it says there should be four bytes before the "usually 1F byte", so I assume there should only be three.Check the first post : that's C++.
2 bytes TextAmount
2 bytes Unknown/Unused
[
2 bytes TextOffset (from the first text offset position)
1 byte Some Flag?
1 byte Some Flag?
] x TextAmount OR TextAmount x 2
Remaining Texts
Sometimes, the datas are doubled. It might be when the 2nd flag is 0 that the current and the previous texts are linked but I don't really know... For what I saw, dialogs and field texts are doubled while battle texts are not. When texts are doubled, it seems the 2nd offset is the one used...When you have problems like that, you can always google the dll. I added it to the zip file nonetheless.Thanks Work very well, but when I Overwrite binari file the program crash and alsot the text are limited, but there is a method to edit freely, I say in the matter of adding many characteres as you want?
I may add an import feature for texts but that's not my priority at all.
Sorry for the missing dll.
EDIT : there were more than 1 missing dll... I'm re-uploading the thing.
EDIT 2 : Done.
I can't reproduce the "overwrite save datas" bug. Does it happen even if you only edit a spell's power? Or is it related to text?
Did it re-scanned the file? The .hwf should be updated. If that's the problem, just delete the .hwf file and let the program redo one.
Saves and PPF exportation work properly,
Thanks. To answer you, it might be possible, but I think Zidane_2 (him again !) made a program to see the world map already. I don't remember how it worked (if you could export the models or only see it) but I may try to add this feature in the future.
@ Kikoutei : You mean they are not in the spell section list? :OTheir names and attacks are not in the same place, believe me. Just like "Rebirth Flame" and "Phoenix". "Phoenix" is shown in the Summon list, while "Rebirth Flame" is shown in the attack/skill message box. Yes, some Eidolon attacks are located somewhere else, I found them using a hex editor.
I have them... They are named "Atomos", "Carbuncle" (4 of them, including Ruby-light) and "Fenrir".
Or maybe you speak about the animations or about the effects? Eidolons' effects are quiet weird and you can't change the "ores powerup" effect on them, I guess.
Thanks :lol: It will save me some time indeed.
@ Bosola : I'm not sure to fully understand you. First, models are not the only thing Hades Workshop can edit. Second, I don't know how the FF7 tools you're refering to are coded, but I tried to make the binary saves (the "Save Mod" feature, if that's indeed what you're talking about) looking alike the binary data in the FFIX disc : this way, a program reading a FFIX disc should have little problem reading my files.
WorldGridW= 24
WorldGridH= 20
V1=2
(seek > 0x1000)
-> function loadSetka2(fil,1,1,13)
tmp1= 0x1000
ffs%=524548
point%=18432
dffs%= 8
mesh[0]= 24
mesh[1]= 4028
mesh[2]= 8216
mesh[3]= 12140
seek > 0x1018
numvert= 118
numTri= 189
VertPointer= 0x3C
TriPointer= 0x3EC
(seek > 0x103C)
//reading 118 vertices
Code:
# 0x103c
v 8.000000 62.466797 58.000000
v 7.675781 63.165039 58.481445
v 7.675781 62.676758 58.481445
v 8.000000 62.890625 58.916016
v 8.000000 63.378906 58.916016
v 2.000000 63.316406 59.892578
v 0.715820 0.000000 59.000000
v 2.000000 0.000000 60.039063
v 2.551758 63.316406 57.777344
v 1.797852 0.000000 57.000000
v 2.117188 0.000000 57.613281
v 4.000000 0.000000 60.146484
v 3.208008 63.316406 59.295898
v 3.338867 0.000000 59.663086
v 7.000000 63.488281 59.101563
v 8.000000 0.000000 59.062500
v 2.865234 63.316406 60.000000
v 3.012695 0.000000 60.146484
v 0.947266 63.316406 59.000000
v 0.819336 0.000000 57.951172
v 1.671875 63.316406 57.990234
v 1.050781 63.316406 58.163086
v 6.000000 63.679688 59.577148
v 7.000000 0.000000 59.248047
v 2.000000 63.316406 59.000000
v 8.000000 61.965820 56.255859
v 7.617188 61.685547 56.000000
v 7.617188 61.553711 56.250000
v 7.284180 61.770508 56.809570
v 8.000000 62.458008 56.656250
v 7.258789 61.783203 56.333008
v 8.000000 62.241211 56.562500
v 2.000000 0.000000 62.000000
v 1.000000 0.000000 63.000000
v 2.000000 0.000000 63.000000
v 1.000000 0.000000 61.000000
v 1.000000 0.000000 62.000000
v 1.000000 0.000000 0.000000
v 2.000000 0.000000 0.000000
v 3.000000 0.000000 62.000000
v 3.000000 0.000000 63.000000
v 3.000000 0.000000 61.000000
v 3.000000 0.000000 0.000000
v 4.000000 0.000000 62.000000
v 4.000000 0.000000 63.000000
v 4.000000 0.000000 0.000000
v 6.000000 0.000000 62.000000
v 5.000000 0.000000 63.000000
v 6.000000 0.000000 63.000000
v 5.000000 0.000000 61.250000
v 5.000000 0.000000 62.000000
v 5.000000 0.000000 0.000000
v 6.000000 0.000000 0.000000
v 7.000000 0.000000 62.000000
v 7.000000 0.000000 63.000000
v 7.000000 0.000000 61.000000
v 7.000000 0.000000 0.000000
v 8.000000 0.000000 63.000000
v 8.000000 0.000000 61.916992
v 8.000000 0.000000 60.903320
v 7.000000 0.000000 60.000000
v 8.000000 0.000000 0.000000
v 0.000000 0.000000 63.000000
v 0.000000 0.000000 62.000000
v 3.715820 0.000000 60.707031
v 0.786133 0.000000 60.000000
v 0.000000 0.000000 61.000000
v 0.000000 0.000000 59.000000
v 1.135742 0.000000 57.000000
v 0.000000 0.000000 56.000000
v 0.000000 0.000000 57.000000
v 0.000000 0.000000 0.000000
v 8.000000 62.955078 58.000000
v 8.000000 62.492188 58.493164
v 2.333984 0.000000 56.000000
v 2.000000 63.316406 57.000000
v 2.480469 63.006836 56.000000
v 1.671875 0.000000 57.778320
v 4.000000 63.316406 60.000000
v 5.000000 0.000000 60.460938
v 5.000000 63.535156 60.314453
v 6.000000 0.000000 59.723633
v 3.000000 63.006836 56.000000
v 3.000000 63.188477 57.000000
v 4.000000 63.087891 56.000000
v 4.000000 62.835938 57.000000
v 4.000000 62.998047 58.000000
v 7.082031 63.344727 58.075195
v 5.000000 63.368164 59.000000
v 4.000000 63.083008 59.000000
v 4.838867 63.087891 56.000000
v 6.000000 63.423828 59.000000
v 8.000000 62.901367 57.071289
v 6.946289 61.757813 56.954102
v 6.447266 60.680664 56.508789
v 6.657227 60.787109 56.254883
v 6.775391 60.762695 56.000000
v 6.270508 60.709961 56.729492
v 5.901367 60.823242 57.098633
v 6.763672 61.841797 57.445313
v 5.419922 61.757813 56.500000
v 4.810547 62.090820 57.190430
v 5.555664 61.580078 57.444336
v 6.222656 62.095703 57.960938
v 6.397461 61.182617 56.000000
v 5.547852 61.500977 56.000000
v 5.000000 62.343750 58.000000
v 7.310547 61.329102 56.000000
v 7.833984 61.919922 56.000000
v 8.000000 62.081055 56.000000
v 8.000000 62.449219 56.775391
v 0.000000 0.000000 58.000000
v 6.000000 0.000000 60.000000
v 8.000000 0.000000 59.847656
v 2.000000 0.000000 60.871094
v 1.513672 0.000000 56.000000
v 6.000000 0.000000 61.000000
v 0.000000 0.000000 60.000000
...being able to create extensive overhauls of FF9
An unhadled exception occurred. Press "Abort" to terminate the program, "Retry" to exit the program normally and "Ignore" to try to continue.It appears every time I go to the Enemies section. :(
'姫','我','隊','来','船','誘','拐','父','様','思','居','芝','観','演','虫','室',
'客', 'Υ','_','俺','愛','貴','度','奏','語','婚','刃','足','恋','話','仕','連',
'達','結','役','嫌','親','聞','掛','仲','言','主','太','乗','飛','続','望','宵',
'友','声','待','席','議','会','込','訳','申','引','醜','隙','驚','皆','苦','兄',
'張','頑','悟','良','奴','落','貸','到','団','戻','遅','娘','容','始','困','負',
'勝','存','納','年','座','玉','為','観','考','関','機','痛','壊','塞','赦','余',
'露','礼','悲','弟','済','刺','静','烈','憎','希','和','笑','千','丸','斯','母',
'原','覧','裂','公','盛','評','集','揮','響','美','番','情','急','舞','台','細',
'練','習','念','計','違','願','恩','配','漫','毎','朝','穴','幕','軽','頼','鳥',
'君','顏','参','安','丈','夫','熱','勘','弁','明','説','籍','祝','建','怪','男',
'捕','低','鐘','総','豪','少','逢','緒','帰','央','貢','仇','庫','温','泣','潮',
'早','準','完','供','胆','例','功','哀','彼','広','界','拒','輝','七','貝','似',
'仮','倉', non, non, non, non, non, non, non, non, non, non, non, non, non, non,
non, non, non, non, non, non, non, non, non, non, non, non, non, non, non, non,
non, non, non, non, non, non, non, non, non, non, non, non, non, non, non, non,
non, non, non, non, non, non, non, non, non, non, non, non, non, non, non, non
sauce (http://i829.photobucket.com/albums/zz212/JBedford128/kanji.png)need add\edit this menu (add characters from charmap like in image)
(http://immage.biz/images/2014/05/21/b4pG8TsSW.jpg)
and add save/load gliph positions in manadge texture menu
I was wondering about the intended rank for 1,700 pts in Tetra Master. It currently reads "Would you like to discard this card?" as we all know. The 2nd best rank is "Master".
Now, if you read the "Strategy Guide" key item, it is signed by "Grand Master I", and I think this is the title that would have been earned by the player if there wasn't the glitch. Simply "Grand Master" would be my guess as I don't think they would have specified the count, or maybe "Grand Master IX", who knows !
フライヤ
「ブルメシア王、ごぶさたしております
ブルメシア王
「おお、フライヤ、よくぞ来てくれた
ブルメシア王
「クレイラ大祭司と共に歓迎するぞ
クレイラ大祭司
「フライヤ殿
クレイラ大祭司
「この度のこと、もはや、ブルメシアだけの問題では無くなってきました
フライヤ
「承知いたしております
フライヤ
「ですが……
フライヤ
「私の力ではなんともならぬやもしれませぬ
ブルメシア王
「フライヤ……、あの時のことを言っておるのだな?
ブルメシア王
「あの時のことは、あやまる
ブルメシア王
「どうか、許してくれぬか?
ブルメシア王
「いや!許せぬのは分かっておる
ブルメシア王
「だが、いまは、わずかとなったブルメシアの国民の命がかかっておるのだ
Freya
It has been some time, Your Majesty.
King of Burmecia
Ah, Freya, well met.
The High Priest and I welcome you.
High Priest of Cleyra
My Lady.
It would appear that this predicament no longer concerns Burmecia alone.
Freya
I understand, Your Holiness.
And yet...
I fear my strength alone may not suffice.
King
Freya...I know what troubles you.
I must apologize for earlier.
Can you ever forgive me?
No! Of course you cannot.
But the fate of the people of Burmecia now hangs by but a thread.
The game script handles scripted events, enemy AIs and other related stuffs.
The script is presented with a kind of C-like syntax. There are several differences though.
[General]
The language accepts only one instruction per line.
Lines are not terminated by any punctuation character.
For flow control statements, the braces are mandatory.
You can't use braces out of a flow control statement.
There is no such thing as real values. Everything is done using integers (sometimes signed).
Once you have modified a function's script, you must parse it to check eventual errors.
[Flow Control]
The different keywords for controlling the script's flow are described here.
if : usual If/Then statement with an optional Else. The syntax is
if ( CONDITION ) {
CODE
}
or
if ( CONDITION ) {
CODE_A
} else {
CODE_B
}
Note that the opening braces must be on the same line as the keywords "if" and "else".
ifnot : opposite control of if. It works similarly though. The syntax is
ifnot ( CONDITION ) {
CODE
}
while : usual While statement. You can use the keyword "break" to leave the control but there is no such thing as a "continue" instruction. The syntax is
while ( CONDITION ) {
CODE
}
do/while : usual Do/While statement. You can also use the keyword "break" to leave the control. The syntax is
do {
CODE
} while ( CONDITION )
switch : a Switch statement with consecutive cases only. The first case's value is specified in the control, as well as the maximal amount of cases. The syntax is
switch NB ( VALUE ) from FIRST {
case +INC:
CODE_A
case +INC ; +INC:
CODE_B
default:
CODE_C
}
where
NB is the maximal amount of cases,
VALUE is the control expression,
FIRST is the "+0" case,
INC are numbers strictly lower than NB.
Note that, like in C, you have to use the keyword "break" if you want only one branch to be run and that the "default" case is optional.
The semicolon allows to make several values lead to the same code branch.
switchex : a more usual Switch statement. The exact amount of cases (default case excluded) must be provided in the control. The syntax is
switchex NB ( VALUE ) {
case X:
CODE_A
case Y ; Z:
CODE_B
default:
CODE_C
}
NB being the amount of cases and X, Y and Z representing numbers. The keywords "break", "default" and the semicolon have the same purpose than for the "switch" statement.
loop : rerun the whole function. It works as an alternative to a last "RETURN" instruction and can only be used out of any other control block.
[Variables]
You can not declare variables. There is a limited amount of them, some being globals shared accross different field scripts, some being locals initialized to 0 when the script code is loaded.
For what I know,
- local variables are the ones named "VAR_A" "VAR_B" followed by 2 numbers. The second number works as an array operator,
- usual globals variables are the ones named "VAR_D",
- global variables that are saved in a memory card save are the ones named "VAR_C",
- "MV" and "SV" variables are special globals that are also shared by the game's mechanics (such as the battle code or the deplacement code).
- There are also Getters to retrieve values from the other game's mechanics that can't be directly modified (such as the player's gils amount).
In order to manipulate variables, you must use the instruction "SET" followed by a series of operations over the variables. Some of those operations are still unknown.
Besides the usual operations, you have "^" that marks the binary XOR operation and "#" that is an unary operator counting the amount of active bits.
The brackets are more of a structure's field accesser than a real array operator. They will be displayed differently in a next version.
Note that the minus operator can't be read as an unary operator yet. Only positive integers can be used in variable manipulation codes.
WARNING : at the moment, the operation priorities are not respected. By default, the operations will be executed from right to left. It is advised to write all the parentheses.
Variable manipulation codes can also be used in most of instructions's arguments.
[32] : Enable back presence flag
[33] : Disable presence flag
[35] : max HP
[36] : current HP
[37] : max MP
[38] : current MP
[39] : max ATB
[40] : current ATB (Only player characters maybe)
[41] : level
[42] : status immune (Heat - Gradual Petrify)
[43] : status immune (Petrify - Protect)
[44] : auto status (Heat - Gradual Petrify)
[45] : auto status (Petrify - Protect)
[46] : current status (Heat - Gradual Petrify)
[47] : current status (Petrify - Protect)
[48] : elemental immune
[49] : elemental absorb
[50] : elemental half
[51] : elemental weakness
[54] : shadow flag?
[55] : model size
[59] : Disable model flag
[60] : Enable back model flag
[65] : line position (not to confuse with "row position" ; that's the ordering of the fighters from 0 to 3)
[73] : magic power
[74] : defence
[75] : evade
[76] : magic defence
[77] : magic evade
[78] : marthym order flag (change its value to cast Marthym !)
You can totally modify them in battle script (the game does that for turning Ozma's darkness absorbtion into a weakness, for instance).switchex 14 ( VAR_B9_239 ) {
case 206:
some_code_A...
FIELD( 206 )
some_code_B...
case 200:
same_code_B...
The code B is redundant in the first case because the "FIELD" opcode should be handled like a "RETURN"...I didn't even see that dialog was still in the script ! It's not in my Hidden Dialogs patch ^^"
I'll look into it. It might be related to the window's flag UI argument in the "WINDOW" or "DIALOG"s opcodes.
Tirlititi is it possible to replace "Change" into any other command list instead?
here's what i tried, but nothing worked...
also the only reason i linked the "itoikenza" command list, is because it won't let me add moves otherwise...
(https://dl.dropboxusercontent.com/u/50488782/models/itoikenzaFF9Change.PNG)
if ( VARL_GenBool_2439 == 1 ) {
WindowSyncEx( 13, 1, 128, 364 )
}
if ( VARL_GenBool_2438 == 1 ) {
WindowSyncEx( 13, 1, 128, 365 )
}
if ( VARL_GenBool_2437 == 1 ) {
WindowSyncEx( 13, 1, 128, 366 )
}
The variables VARL_GenBool_243x seems to not be used anywhere else. The easiest way to unlock a line of dialog is to delete the "if" statement around it (the line containing the "if" and the closing braces). case 12:
WindowSync( 6, 128, 118 )
set VAR_GlobInt16_28 = 17
EnableHeadFocus( 2 )
set VAR_GlobUInt8_31 = 96
RunSharedScript( 7 )
break
This function and the "SteinerB_2" one are responding each other using the variable "VAR_GlobInt16_28" which tells the current state of the dialog. Here, the variable is said to jump from the value 12 to the value 17, skiping a part of the dialog. Just replace the 17 by 13 and it will be fine. if ( VARL_GenUInt8_484 == 0 ) {
set VAR_GlobUInt16_30 |= 2
}
if ( VARL_GenUInt8_484 == 2 ) {
set VAR_GlobUInt16_30 |= 8
}
if ( VARL_GenUInt8_483 == 0 ) {
set VAR_GlobUInt16_30 |= 1
}
if ( VARL_GenUInt8_483 == 2 ) {
set VAR_GlobUInt16_30 |= 4
}
if ( VARL_GenBool_3857 == 0 ) {
set VAR_GlobUInt16_30 = 0
}
You need to add these lines in the list of "if" statement (before the last one, that's better) : if ( VARL_GenBool_3856 == 0 ) {
set VAR_GlobUInt16_30 |= 16
}
The variable "VARL_GenBool_3856" is a flag that is set to 1 once the ATE has been seen, and 16 is a bit-flag corresponding to the 5th ATE, the hidden one. PreloadField( 5, 1363 )
set VAR_GlobInt16_21 = 1363
if ( VAR_GlobUInt8_17 == 255 ) {
set Op66(( GetData_12 - 160 ), ( GetData_13 - 112 ))
}
0xA9( 250 )
FadeFilter( 6, 24, VAR_GlobUInt8_17, 255, 255, 255 )
Wait( 25 )
if ( VAR_GlobBool_167 == 1 ) {
RunSoundCode( 265, 65535 )
set VAR_GlobBool_167 = 0
}
if ( VAR_GlobBool_162 == 0 ) {
if ( VAR_GenUInt8_13 < 9 ) {
set VAR_GenUInt8_13 = 3
}
RunSoundCode1( 20864, 2297, 0 )
}
if ( VAR_GlobBool_163 == 0 ) {
}
set General_FieldEntrance = 2
Field( 1363 )
break
You must set the field to 1364 (Lindblum Airship Dock) instead of 1363 (Lindblum Hallway). Modify it in both the "PreloadField" and the "Field" opcodes. You also need to set the variable "General_FieldEntrance" to value 1, so Zidane appears at the right place of the Docks. if ( #( SV_FunctionEnemy[HP] <$ 10000 ) ) {
// Wait until Kuja no longer attacks
while ( IsAttacking != 0 ) {
Wait( 1 )
}
// A check of "The battle has started"
if ( GetBattleState != 4 ) {
return
}
// Freeze the ATB and hide it.
RunBattleCode( 32, 0 )
while ( GetBattleState != 1 ) {
Wait( 1 )
}
// Cast Ultima (the speech is included in it)
set #( SV_Target = SV_PlayerTeam )
AttackSpecial( 5 )
while ( !( VAR_GenUInt8_199 & 16 ) ) {
Wait( 1 )
}
RunBattleCode( 40, 1 )
set VAR_GenUInt8_199 &= 65519
Wait( 1 )
while ( !( VAR_GenUInt8_199 & 16 ) ) {
Wait( 1 )
}
// Fade filter and ends the fight
FadeFilter( 0, 1, 0, 255, 255, 255 )
set VAR_GenUInt8_199 &= 65519
while ( IsAttacking != 0 ) {
Wait( 1 )
}
set SV_FunctionEnemy[DEFEATED_ON] =$ 1
RunBattleCode( 33, 5 )
return
}
set SV_FunctionEnemy[HP] =$ FirstOf(SV_FunctionEnemy[MAX_HP])
"FirstOf" converts a list [value1, value2, value3, value4] into value1.set SV_FunctionEnemy[HP] =$ 65535
Function func_Trance_Kuja_Loop
if ( !VAR_LocUInt8_0 ) {
set VAR_LocUInt8_0 = 1
while ( !( GetBattleLoadState & 8 ) ) {
Wait( 1 )
set VAR_GenUInt8_206 = GetRandom
}
set SV_FunctionEnemy[SHADOW] =$ 0
while ( GetBattleState != 1 ) {
Wait( 1 )
set VAR_GenUInt8_206 = GetRandom
}
RunBattleCode( 35, 0 )
while ( GetBattleState != 4 ) {
Wait( 1 )
}
}
if ( #( SV_FunctionEnemy[HP] <$ 10000 ) ) {
if ( VAR_LocUInt8_60 < 5 ) {
set VAR_LocUInt8_60++
set SV_FunctionEnemy[HP] =$ FirstOf(SV_FunctionEnemy[MAX_HP])
} else {
while ( IsAttacking != 0 ) {
Wait( 1 )
}
if ( GetBattleState != 4 ) {
return
}
RunBattleCode( 32, 0 )
while ( GetBattleState != 1 ) {
Wait( 1 )
}
set #( SV_Target = SV_PlayerTeam )
AttackSpecial( 5 )
while ( !( VAR_GenUInt8_199 & 16 ) ) {
Wait( 1 )
}
RunBattleCode( 40, 1 )
set VAR_GenUInt8_199 &= 65519
Wait( 1 )
while ( !( VAR_GenUInt8_199 & 16 ) ) {
Wait( 1 )
}
FadeFilter( 0, 1, 0, 255, 255, 255 )
set VAR_GenUInt8_199 &= 65519
while ( IsAttacking != 0 ) {
Wait( 1 )
}
set SV_FunctionEnemy[DEFEATED_ON] =$ 1
RunBattleCode( 33, 5 )
return
}
}
Wait( 1 )
loop
Thanks :)
Updated to 0.27 :
- Field backgrounds can be viewed and exported (not edited yet),
- You can modify the amount of enemies inside battles ; be sure to change it both in the main panel and in the battle script,
- Added a window telling you how much some file reading processes are progressing (this is quiet useful when you load fields or battle scenes, since they are long to read),
- fixed bugs (tokenize code for japanese, some script bugs, some UI bugs...).
About field background, they are not 100% well displayed. Some tilesets (think of those as layers) are a mess and I don't know how to handle them ^^" Those tilesets are mainly about the "Places names" that are displayed when you first enter a new place but there are also some effects of light. There are also few tilesets that are behind ones they should be ahead of.
You can export them as .tiff (Gimp can read them at least). The filesize is hugely non-optimized.
You can see background's animations too.
I guess I'll keep making bug-fixes updates while I'm studying the top-level file format. I need to make the remaining (menu) texts available and I can't do it without this step (plus it should unlock the card's panel also).
However, the main problem with that is the image size (that's why you can't make the other textures larger than what they currently are). If there is space to add some lines in fields' scripts, increasing a background's size (including upscaling them) would hit the limit extremely fast.
The viewer window needs rework ^^ As you said, most backgrounds don't fit inside. The pathing and few other stuff should also be displayed in this window so I let it the way it is until I decide its final form. Same as the Script editor that definitely needs improvements.
SET VAR_B7_20 = 7
SET VAR_A11_1 = 794688L
SET VAR_A11_4 = 29060
SET VAR_A11_7 = 1280
SET VAR_A11_10 = 24576
VAR_B7_20 -> Number of different regular attacks if ( VAR_B7_19 == 7 ) {
SET VAR_B7_19 = 8
}
http://speedy.sh/PYtGD/FF9-Damage-Formulas.xls
WAIT(1)
loop
If there is a RETURN instead, it won't loop anyway so it may be why it didn't work.@ gledson : I would have advise you to do exactly what you did....
There is no need to remove the battles from the preloading list, though, and it is the thing that most likely made the bug.
In order to take no risk : simply remove the line RANDOM_BATTLE (remove it, don't change it to "NOTHING" though if that was the problem, then I made a terrible mistake ^^"), parse and save and that should be all about it.
Save states should work fine for a script edition like this. The changes will be effective as soon as you (re)enter the field. However, when changing the preloading files, I think the field needs not to have been preloaded first, so the save state must be at least 2 fields away from the modified field (for the entrance of the Gargan Roo, the save state should be in Tot's tower stairs, for example).
Also, keep in mind that there may be the "RANDOM_BATTLE" opcode somewhere else than in the main function. For instance, the random battles of the fire room in the Desert Palace are activated only once all the fires have been lightened up. So there is a conditionnal execution of "RANDOM_BATTLE" in the main function but there is also another one in another function running when the last fire is lightened.
@ Kefka : that's a pitty for the counters :/
I would have thought it should work at least in the looping function. Did you check if it was actually looping? The function should end with those two lines :Code: [Select]WAIT(1)
If there is a RETURN instead, it won't loop anyway so it may be why it didn't work.
loop
About the statuses : no, I don't plan to go that far in the battle mechanics. I wish I could, but the figures controlling these kind of things are really spread over the file and it will be too difficult for me to draw the big picture of the battle mechanics.
However, I've progressed in the spell animation editing feature ; without giving false hope (this feature was full of them for my concern), there might be a way to stop the ATB progression during spell animations, making the combo regen+booster lighter. That also needs checks.
RANDOM_BATTLE( 0, 306, 306, 310, 310 )
@ Kefka : You got it right, but you also need to add the battles in the preloading datas. There is a bug that should be corrected in the next version for preloading datas, but you can try now nonetheless.
Add those battles to the preloading datas, add the "RANDOM_BATTLE" opcode inside the script and test : it will crash in-game if the bug occured and should work fine if not ^^
The corresponding battle scene for the battles must be preloaded as well but I think I made it automatic (if you add a battle, the battle scene is added too if it weren't there).
Note that the 1st argument of "RANDOM_BATTLE" has unknown effect. It might be about the frequency of random encounters.
I find it kinda lame that in most battles there's only 1-2 enemies, and the maximum of 4 is hardly ever used.That's certainly due to the limited PlayStation VRAM space for enemy textures during battle.
the battle is usually automatically won when the boss reach 10000 HP, for instance.What do you mean by that? Is it maybe that healing an enemy for above 65535 (HP overflow) automatically kills it or something?
Most bosses don't die by their HP being reduced to 0. Instead, if HP < 10000 trigger death script. This is why Ozma has 55535 HP -- he actually has 65535 but he dies when going below 10000 so he effectively only has 55535. You can't scan so you wouldn't know either way. If the boss's HP did reach 0 the battle just wouldn't end/would hang, which isn't a problem since bosses are immune to instant death attacks and other damage doesn't exceed 9999.WTF?! That's so bizarre... :-o
Most bosses don't die by their HP being reduced to 0. Instead, if HP < 10000 trigger death script. This is why Ozma has 55535 HP -- he actually has 65535 but he dies when going below 10000 so he effectively only has 55535. You can't scan so you wouldn't know either way. If the boss's HP did reach 0 the battle just wouldn't end/would hang, which isn't a problem since bosses are immune to instant death attacks and other damage doesn't exceed 9999.
WTF?! That's so bizarre... :-o
Any idea on why they did that? :?
^this
That's really strange indeed. I didn't even see Maliris's final attack code. I thought it was also using the "under 10000 HP" way.
So they indeed made 2 different systems for handling the end of the boss battles...
You can't use the "perform special death if HP is 0" system with HW for now. I'll look into it but if that works as I think it does, it shouldn't be too hard to enable.
However, you can already give more HP to enemies using the script : when an enemy goes under 10 000 HP, heal him.
See this post for a detailled way to go : http://forums.qhimm.com/index.php?topic=14315.msg224426#msg224426
Program updated : I fixed those 2 bugs and added a way to add/remove functions in scripts. You can right-click on the function list for that.
When you add a new function, you're asked 2 numbers, the entry type and the function type. The entry type shouldn't be changed (it says if the script is attached to an object, to a region or to nothing). The function type can be any number but :
1) some numbers means the function is special and it will be run at some points (for AI script, this is what the previous posts in this page was about) ; the "looping function" number can be seen as a secondary "main function" as it is run when the script is initialised.
2) there will be unknown results if you use the same number for 2 different functions of the same entry. The normal version used the types 10 and followings for regular functions that can be called somewhere else in the script.
Since we are in weird things that comes from nowhere and can make battles bug, I just ran into one. When you add an enemy to a battle group, you sometimes also need (in addition to editing the script and increasing the enemy amount in the group) to uncheck then check back the "Targetable" flag. Some enemies that you'd add are invisible and bug if you don't do it.
1) I tried to use the "death" function with an enemy (I don't remember which one) but it didn't work. I didn't investigate much more though, and you can use the usual way "+10000 HP and run the death script in the looping function". Maybe there is some flag or thing to know for using that type.
2) Function types are not limited to IA scripts : they are also used for field scripts. The 3 examples you gave are of that kind : they are used for NPC dialogs or interactions (I'm not sure about the type 18 though ; it is used by Puck running on Vivi but also for a bunch of other functions not particulary special).
I think the Black Waltz 1 also uses a death function for his last dialog.
As a side note, the "counter enemy" type is not really what I thought it was. I need to check things but it seems to be running anytime a spell takes effect (be it casted by the enemy or the party). It also triggers on counter-attacks or returned spells, unlike the "counter party" type.
// Those lines are always in the counter functions already
if ( ( GetAttackCommandId == 25 ) && ( GetAttackId == 103 ) ) {
return
}
// Those lines need to be added, replacing the numbers by the spells IDs
// of the spells with several damage points in their animation
if ( ( GetAttackId == 100 ) || ( GetAttackId == 101 ) ) {
return
}
// Disc 1
Yan
Friendly Yan
Armstrong
Ghost
Gizamaluke
Grimlocks (both of them)
Jabberwock
Mimic
Cactuar
Lamia
Sand Scorpion
Bomb (counter fire spells only)
Black Waltz 2 (counter the elemental Black magics only)
// Disc 2
Soldier
Zuu
Sand Golem
Tantarian (put the script after HP update)
Zorn & Thorn
Sand Scorpion (more of them)
Soulcage (counter fire spells only)
Stroper
Zemzelett
// Disc 3
Amdusias
Shell Dragon (only the random encounters)
Epitaph (magic disbled for these battles)
Grimlocks (more of them)
Drakan
Ring Leader
Tonberry (put the script after HP update)
Mover (optionnal : they don't crash the game but don't pass from 2 of them to 1 of them)
// Disc 4
Ash
Kraken (when he's on crystal shape only ; he already has a "counter once" system as a boss)
Trance Kuja
Very Interesting, speaking of which, what is it about the Enemy Attack effect that seems to make it so random? The damage seems to vary from doing 40 damage to over 1000.
*Edit: After looking at the formula, it seems the Random Mod is only divided by 4 for Enemy Attack rather than 8 for party skills. They tried a little too hard to make this game random, jeez.
EDIT : The right formula for "Enemy Attack" is
Damage = (Power - Defence) * Random[Strength, Strength + (Level + Strength) / 4]
It's exactly the same as "Attack 8" actually, judging from my tests... There shouldn't be more variance in one or in the other.
Note that the "Attack" statistic of the enemy is not used... I begin to think this field as nothing to do with an attack statistic.
No probl. As said, there are lots of details like these.
1) Not for now. The accuracy formulas are hardcoded in the spell's effect (except for Vivi's Meteor and Comet which are linked to the spell slot).
2) The only difference I would see for Matra Magic and Roulette is the accuracy formula. Roulette always succeed while Matra Magic can miss.
They both don't use the Status field so I use Maelstrom if I ever want a similar effect adding a status.
3) I checked it and it does that :
- Doubles the stat of the user,
- Divide by 2 the stat of the target.
4) I think the programers kind of copy-pasted the spells and changed what needed to be changed, leaving unused fields (such as the power for those "Bad Status" spells) unmodified. I've noticed that the power is usually the same as another spell in the enemy's spell list.
I've figured the Death effect difference quiet recently : if the target is under Zombie, it totally heals him instead of applying the status effect (whatever this status is). The effect Death is the only one to do that (Lv5 Death, for instance, kill the zombies like the others).
There may be a similar thing for Mini but I recall having checked that a long time ago and it seems that "Bad Status" also removes Mini if the target is already under Mini and if that's the status of the spell.
SET VAR_B15_1 = ( 65535L - Op2B(SV_FunctionEnemy[HP]) )
SET VAR_B15_3 = ( ( ( 65535L - VAR_B15_1 ) / 3 ) + VAR_B15_1 )
SET SV_FunctionEnemy[MAX_HP] =$ 65535L
SET SV_FunctionEnemy[HP] =$ 65535L
It is set to 65535 and "VAR_B15_1" keeps memory of the initial HP gave to him. When Gizamaluke's HP gets under "VAR_B15_1", he does his death stuff.// Actual Max HP
SV_FunctionEnemy[MAX_HP] -> 65535
SV_FunctionEnemy[HP] -> 65535
// Death threshold
VAR_B15_1 -> 55535
// Multi-Water threshold
VAR_B15_3 -> 55535 + 10000 / 3 = 58868
can u add an option for ap after battle on monsters?
@ Kefka : I don't know how to solve this problem. It needs investigations but there's a chance that it won't be possible to add supporting abilities without messing with the regular characters' ability learning progress.
@ resinate : You can add Beatrix at disc 3 by editing the game script. You need to add Beatrix with a "PartyAdd" opcode or a "PARTY_RESERVE" opcode. You should change the ones that are already present (in the Hilda Gard 3 scenes, for instance).
PARTY_RESERVE( 4095 ) // Adjust this argument if you want fewer people
PARTY_BATTLE_DATA( 8, 1, 255, 22, 15 ) // Beatrix
PARTY_BATTLE_DATA( 9, 1, 255, 21, 8 ) // Cinna
PARTY_BATTLE_DATA( 10, 1, 255, 21, 10 ) // Marcus
PARTY_BATTLE_DATA( 11, 1, 255, 21, 12 ) // Blank
NAME( 8, 75 ) // Rename Beatrix (shouldn't be important)
NAME( 9, 72 ) // Rename Cinna (or else he's called "Quina")
NAME( 10, 73 ) // Rename Marcus (or else he's called "Eiko")
NAME( 11, 74 ) // Rename Blank (or else he's called "Amarant")
You'd need to add that kind of script anywhere the party is somehow modified to make it persistant ; or use a similar script to revert the changes if you want Quina, Eiko or Amarant back in the team.- Added a "Tetra Master" panel. You can modify the name and the random range for the statistics of cards (not pictures yet). You can also modify the card decks used by the NPC. The naming rules for decks are the following :
-- For decks used by NPC in Treno Stadium, Memoria or by the Fat Chocobo, the name of the NPC is used,
-- For the others, the name of the town where you can first meet a NPC playing that deck (provided you don't change the script for that) is used,
-- If decks are used by NPC of several towns, a dot dot dot is added.
Thanks to Froggy25 who totally cracked the Tetra Master deep mechanics btw.
Also added the "Link enemies" flag in the groups submenu : it is, by default, used exclusively by the Sand Golem, Movers and Kraken to make several targeting parts for 1 enemy. When enabling that flag, the scripts for all the linked enemies but 1 must be deleted and the remaining one will handle all the attacks and counter-attacks (See Kraken's AI script (https://dl.dropboxusercontent.com/u/98687557/Resources/KrakenScript.txt) for an example).
SET VAR_B15_0[MAX_HP] =$ 65535L
SET VAR_B15_2[MAX_HP] =$ ( 65535L - ( Op2B(SV_FunctionEnemy[HP]) / 2 ) )
SET VAR_B15_4[MAX_HP] =$ 65535L
SET VAR_B15_0[HP] =$ 65535L
SET VAR_B15_2[HP] =$ Op2B(VAR_B15_2[MAX_HP])
SET VAR_B15_4[HP] =$ 65535L
And insert those instead : SET VAR_B15_0[MODEL_OFF] =$ 60
SET VAR_B15_2[MODEL_OFF] =$ 51
SET VAR_B15_4[MODEL_OFF] =$ 15
You'll see their purpose if you don't do it ;) SET VAR_B15_0[STAND_ANIMATION] =$ 1
SET VAR_B15_2[STAND_ANIMATION] =$ 1
SET VAR_B15_4[STAND_ANIMATION] =$ 1
Set it back to 0 to remove the formation. }
0x27( 127 )
SET VAR_B9_220 = 600
SET VAR_B9_222 = 1700
SET VAR_B5_226 = VAR_C5_7175
SET VAR_B9_224 = 236
TEXT_VARIABLE( 0, 236 )
RUN_SCRIPT_SYNC( 2, 250, 12 )
if ( 1 ) {
SET VAR_C5_7175 = VAR_B5_226
}
Received µ!
With µ corresponding to the text opcode "[VAR_ITEM]". That "SetTextVariable" is used in the script to tell which item's name should be written in place of that µ. Note: For the Steam version, text opcodes are written more explicitely. if ( ( GetItemCount(VAR_GenInt16_224) < 99 ) && ( VAR_GenInt16_224 < 512 ) ) {
RunSoundCode3( 53248, 108, 0, -128, 125 )
set VAR_GenUInt8_226 = 1
SetTextVariable( 0, VAR_GenInt16_224 )
AddItem( VAR_GenInt16_224, 1 )
WindowSync( "Received [VAR_ITEM]!" )
} ....
Since you updated the variable "VAR_GenInt16_224" well, it all works fine as intended : check if the right item is not owned 99 times already, display the right item's name and add the right item to the inventory. if ( ( ( GetItemCount(238) < 99 ) && 1 ) || ( 0 && ( GetCardAmount < 100 ) ) ) {
Wait( 2 )
if ( VARL_GenBool_7243 == 0 ) {
RunSoundCode3( 53248, 108, 0, -128, 125 )
set VARL_GenBool_7243 = 1
SetTextVariable( 0, 238 )
if ( 1 ) {
AddItem( 238, 1 )
WindowSync( "Received [VAR_ITEM]!" )
} else {
if ( 1 ) {
AddItem( 238, 1 )
WindowSync( "Received [VAR_ITEM] Card!" )
} else {
AddGil( 16776454 )
set VAR_GenInt16_224 = 64774
SetTextVariable( 0, VAR_GenInt16_224 )
WindowSync( "Received [VAR_NUM] Gil!" )
}
}
}
Here, you have to modify the number 238 into whatever item you want 3 times :If that's too much of a work, you can send me you .hws file (or even one that contains only the corrupted "Stats" modifications) and I should be able to fix it pretty easily by hand.I'm overly busy these few days, but it'd most likely be done by the end of the week.
local [type] [name] [Default Name]
// example
local uint8 foo VAR_LocUInt8_10
Function Zidane_12
TimedTurn( Angle(VAR_GenInt16_220, VAR_GenInt16_222), 16 )
WaitTurn( )
if ( VAR_GenUInt8_226 == 0 ) {
if ( VAR_GenInt16_224 == 29999 ) {
WindowSync( 7, 0, 6 )
} else {
if ( VAR_GenInt16_224 >= 1000 ) {
RunSoundCode3( 53248, 108, 0, -128, 125 )
set VAR_GenInt16_228 = ( VAR_GenInt16_224 - 1000 )
if ( ( VAR_GenInt16_228 + GetGil ) > 9999999L ) {
set VAR_GenInt16_228 = ( 9999999L - GetGil )
}
AddGil( VAR_GenInt16_228 )
SetTextVariable( 0, VAR_GenInt16_228 )
WindowSync( 7, 0, 6 )
set VAR_GenUInt8_226 = 1
} else {
if ( ( GetItemCount(VAR_GenInt16_224) < 99 ) && ( VAR_GenInt16_224 < 512 ) ) {
RunSoundCode3( 53248, 108, 0, -128, 125 )
set VAR_GenUInt8_226 = 1
SetTextVariable( 0, VAR_GenInt16_224 )
AddItem( VAR_GenInt16_224, 1 )
WindowSync( 7, 0, 4 )
} else {
if ( ( VAR_GenInt16_224 >= 512 ) && ( GetCardAmount < 100 ) ) {
RunSoundCode3( 53248, 108, 0, -128, 125 )
set VAR_GenUInt8_226 = 1
SetTextVariable( 0, VAR_GenInt16_224 )
AddItem( VAR_GenInt16_224, 1 )
WindowSync( 7, 0, 5 )
} else {
SetTextVariable( 0, VAR_GenInt16_224 )
if ( VAR_GenInt16_224 < 512 ) {
WindowSync( 7, 0, 8 )
} else {
WindowSync( 7, 0, 9 )
}
}
}
}
}
}
return
Then you can declare these :global int16 TreasurePositionX VAR_GenInt16_220
global int16 TreasurePositionY VAR_GenInt16_222
global int16 TreasureItem VAR_GenInt16_224
global uint8 TreasureTaken VAR_GenInt16_226
Parse, close and reopen and find this instead :Function Zidane_12
TimedTurn( Angle(TreasurePositionX, TreasurePositionY), 16 )
WaitTurn( )
if ( VAR_GenUInt8_226 == 0 ) {
if ( TreasureItem == 29999 ) {
WindowSync( 7, 0, 6 )
} else {
if ( TreasureItem >= 1000 ) {
RunSoundCode3( 53248, 108, 0, -128, 125 )
set VAR_GenInt16_228 = ( TreasureItem - 1000 )
if ( ( VAR_GenInt16_228 + GetGil ) > 9999999L ) {
set VAR_GenInt16_228 = ( 9999999L - GetGil )
}
AddGil( VAR_GenInt16_228 )
SetTextVariable( 0, VAR_GenInt16_228 )
WindowSync( 7, 0, 6 )
set VAR_GenUInt8_226 = 1
} else {
if ( ( GetItemCount(TreasureItem) < 99 ) && ( TreasureItem < 512 ) ) {
RunSoundCode3( 53248, 108, 0, -128, 125 )
set VAR_GenUInt8_226 = 1
SetTextVariable( 0, TreasureItem )
AddItem( TreasureItem, 1 )
WindowSync( 7, 0, 4 )
} else {
if ( ( TreasureItem >= 512 ) && ( GetCardAmount < 100 ) ) {
RunSoundCode3( 53248, 108, 0, -128, 125 )
set VAR_GenUInt8_226 = 1
SetTextVariable( 0, TreasureItem )
AddItem( TreasureItem, 1 )
WindowSync( 7, 0, 5 )
} else {
SetTextVariable( 0, TreasureItem )
if ( TreasureItem < 512 ) {
WindowSync( 7, 0, 8 )
} else {
WindowSync( 7, 0, 9 )
}
}
}
}
}
}
return
Fixed, thx for warning Kefka.
Here is also a temporary link (https://dl.dropboxusercontent.com/u/98687557/Resources/wxmsw30u_gl_gcc471TDM.dll) for the .dll only.
if (#(SV_PlayerTeam[MODEL_TYPE] ==$ 2)) {
// Vivi is in the team
}
if (#((SV_PlayerTeam[MODEL_TYPE] ==$ 10) | (SV_PlayerTeam[MODEL_TYPE] ==$ 11))) {
// Eiko is in the team
}
The list for model types is this one (I don't think I've included it in the help yet, I should do it) :Zidane 0 or 1
Vivi 2
Dagger 3, 4, 5 or 6
Steiner 7 or 8
Quina 9
Eiko 10 or 11
Freya 12
Amarant 13
Cinna 14
Marcus 15
Blank 16 or 17
Beatrix 18
Is there a way for an enemy to check if a specific character is in your current party? Because I've been playing with the thought of making Trance-Kuja use Reflect only if either Eiko or Vivi (or both) are in the current party, since they are the only two characters that have reflectable spells. Reflect doesn't bother any of the other six party members, so if Kuja uses it if neither of the two is in your party, he is essentially just wasting a turn.The AI also uses it to circumvent auto-Reflect, by casting offensive spells on its own Reflect.
It would be this :Code: [Select]if (#(SV_PlayerTeam[MODEL_TYPE] ==$ 2)) {
The list for model types is this one (I don't think I've included it in the help yet, I should do it) :
// Vivi is in the team
}
if (#((SV_PlayerTeam[MODEL_TYPE] ==$ 10) | (SV_PlayerTeam[MODEL_TYPE] ==$ 11))) {
// Eiko is in the team
}Code: [Select]Zidane 0 or 1
Vivi 2
Dagger 3, 4, 5 or 6
Steiner 7 or 8
Quina 9
Eiko 10 or 11
Freya 12
Amarant 13
Cinna 14
Marcus 15
Blank 16 or 17
Beatrix 18
That's strange you got a crash though. What was your try?
The AI also uses it to circumvent auto-Reflect, by casting offensive spells on its own Reflect.
There is a quirk with this subroutine: if the reflected spell doesn't find any valid target, it will reflect the spell on the caster (https://youtu.be/fCJUhIG1ESw?t=1m40s).
case +2:
if (#(SV_PlayerTeam[MODEL_TYPE] ==$ 2)) {
set #( SV_Target = SV_PlayerTeam )
} else {
set #( SV_Target = 0 )
}
break
if ( !initflag ) {
set initflag = 1
while ( !( GetBattleLoadState & 16 ) ) {
Wait( 1 )
set VAR_GenUInt8_206 = GetRandom
}
// you can do it with a boolean like this :
set myreflectflag = (#(SV_PlayerTeam[MODEL_TYPE] ==$ 2))
// or, more like what devs usually did :
if (#(SV_PlayerTeam[MODEL_TYPE] ==$ 2)) {
set myreflecttarget = SV_FunctionEnemy
} else {
set myreflecttarget = 0
}
while ( GetBattleState != 4 ) {
Wait( 1 )
}
}
Then, in the ATB function (or Counter function if you want to use Reflect as a counter), you use "myreflecttarget" as your target when casting Reflect, or check the "myreflectflag". set VAR_B13_21 = 0
SetPartyReserve( VAR_B13_21 )
set VAR_B10_8 = ( VAR_B10_10 = ( VAR_B10_12 = ( VAR_B10_14 = 0 ) ) )
set VAR_B10_8 = 0
while ( VAR_B10_8 <= 11 ) {
if ( IsInParty(VAR_B10_8) ) {
set VAR_B10_10 |= ( 1 << VAR_B10_8 )
}
set VAR_B10_8++
}
if ( 1 ) {
set VAR_B10_12 |= 1
}
if ( 1 ) {
set VAR_B10_12 |= 4
}
if ( 1 ) {
set VAR_B10_12 |= 2
}
if ( 1 ) {
set VAR_B10_12 |= 64
}
set VAR_B10_14 = ( VAR_B10_10 ^ VAR_B10_12 )
set VAR_B10_8 = 0
while ( VAR_B10_8 <= 11 ) {
if ( ( VAR_B10_14 >> VAR_B10_8 ) & 1 ) {
RemoveParty( VAR_B10_8 )
}
set VAR_B10_8++
}
if ( IsInParty(0) == 0 ) {
set VAR_A6_147 = PartyAdd(0)
}
if ( IsInParty(2) == 0 ) {
set VAR_A6_147 = PartyAdd(2)
}
if ( IsInParty(1) == 0 ) {
set VAR_A6_147 = PartyAdd(1)
}
if ( IsInParty(6) == 0 ) {
set VAR_A6_147 = PartyAdd(6)
}
set VAR_D5_303 = 0
set VAR_B10_8 = ( VAR_B10_10 = ( VAR_B10_12 = ( VAR_B10_14 = 99 ) ) )
if ( 1 ) {
set VAR_D5_303++
set VAR_B10_8 = 0
}
if ( 1 ) {
set VAR_D5_303++
set VAR_B10_10 = 2
}
if ( 1 ) {
set VAR_D5_303++
set VAR_B10_12 = 1
}
if ( 1 ) {
set VAR_D5_303++
set VAR_B10_14 = 6
}
set VAR_A6_148 = ( VAR_A6_149 = ( VAR_A6_150 = ( VAR_A6_151 = 0 ) ) )
if ( VAR_B10_8 != 99 ) {
if ( GetHP(VAR_B10_8) == 0 ) {
set VAR_A6_148 = 1
}
}
if ( VAR_B10_10 != 99 ) {
if ( GetHP(VAR_B10_10) == 0 ) {
set VAR_A6_149 = 1
}
}
if ( VAR_B10_12 != 99 ) {
if ( GetHP(VAR_B10_12) == 0 ) {
set VAR_A6_150 = 1
}
}
if ( VAR_B10_14 != 99 ) {
if ( GetHP(VAR_B10_14) == 0 ) {
set VAR_A6_151 = 1
}
}
if ( ( ( ( VAR_A6_148 + VAR_A6_149 ) + VAR_A6_150 ) + VAR_A6_151 ) == VAR_D5_303 ) {
if ( ( VAR_B10_8 != 99 ) && ( VAR_A6_148 == 1 ) ) {
SetHP( VAR_B10_8, 1 )
}
if ( ( VAR_B10_10 != 99 ) && ( VAR_A6_149 == 1 ) ) {
SetHP( VAR_B10_10, 1 )
}
if ( ( VAR_B10_12 != 99 ) && ( VAR_A6_150 == 1 ) ) {
SetHP( VAR_B10_12, 1 )
}
if ( ( VAR_B10_14 != 99 ) && ( VAR_A6_151 == 1 ) ) {
SetHP( VAR_B10_14, 1 )
}
}
SetStatus( 0, 127 )
SetStatus( 1, 127 )
SetStatus( 3, 127 )
SetStatus( 2, 127 )
SetStatus( 4, 127 )
SetStatus( 5, 127 )
SetStatus( 7, 127 )
SetStatus( 6, 127 )
SetStatus( 8, 127 )
if ( IsInParty(5) ) {
set Setting_OptionalQuina = 1
} else {
set Setting_OptionalQuina = 0
}
if ( ( ( VAR_B13_19 >> 0 ) & 1 ) == 0 ) {
SetCharacterData( 0, 1, 255, 9, 0 )
set VAR_B13_19 |= 1
}
if ( ( ( VAR_B13_19 >> 1 ) & 1 ) == 0 ) {
SetCharacterData( 1, 1, 255, 5, 1 )
set VAR_B13_19 |= 2
}
if ( ( ( VAR_B13_19 >> 2 ) & 1 ) == 0 ) {
SetCharacterData( 2, 1, 255, 6, 2 )
set VAR_B13_19 |= 4
}
if ( ( ( VAR_B13_19 >> 6 ) & 1 ) == 0 ) {
SetCharacterData( 6, 1, 6, 6, 6 )
set VAR_B13_19 |= 64
SetRow( 6, 0 )
}
Function Main_Loop
if ( Global_FieldEntrance == 65535 ) {
set VAR_B13_21 = 103
SetPartyReserve( VAR_B13_21 )
if ( IsInParty(5) ) {
RemoveParty( 5 )
set VAR_D5_303 = 0
set VAR_B1_60 = ( VAR_B1_61 = ( VAR_B1_62 = ( VAR_B1_63 = ( VAR_B10_8 = ( VAR_B10_10 = ( VAR_B10_12 = ( VAR_B10_14 = 65535 ) ) ) ) ) ) )
set VAR_B10_14 = 0
while ( VAR_B10_14 <= 11 ) {
if ( IsInParty(VAR_B10_14) ) {
Function Main_Loop
if ( Global_FieldEntrance == 65535 ) {
set VAR_B13_21 = 64
SetPartyReserve( VAR_B13_21 )
if ( IsInParty(5) ) {
RemoveParty( 5 )
set VAR_D5_303 = 0
set VAR_B1_60 = ( VAR_B1_61 = ( VAR_B1_62 = ( VAR_B1_63 = ( VAR_B10_8 = ( VAR_B10_10 = ( VAR_B10_12 = ( VAR_B10_14 = 65535 ) ) ) ) ) ) )
set VAR_B10_14 = 0
while ( VAR_B10_14 <= 11 ) {
if ( IsInParty(VAR_B10_14) ) {
set VAR_B13_21 = 199
SetPartyReserve( VAR_B13_21 )
set VAR_B10_8 = ( VAR_B10_10 = ( VAR_B10_12 = ( VAR_B10_14 = 0 ) ) )
set VAR_B10_8 = 0
while ( VAR_B10_8 <= 11 ) {
if ( IsInParty(VAR_B10_8) ) {
set VAR_B10_10 |= ( 1 << VAR_B10_8 )
}
set VAR_B10_8++
}
if ( 1 ) {
set VAR_B10_12 |= 1
}
if ( 1 ) {
set VAR_B10_12 |= 4
}
if ( 1 ) {
set VAR_B10_12 |= 2
}
if ( 1 ) {
set VAR_B10_12 |= 64
}
set VAR_B10_14 = ( VAR_B10_10 ^ VAR_B10_12 )
set VAR_B10_8 = 0
while ( VAR_B10_8 <= 11 ) {
if ( ( VAR_B10_14 >> VAR_B10_8 ) & 1 ) {
RemoveParty( VAR_B10_8 )
}
set VAR_B10_8++
}
if ( IsInParty(0) == 0 ) {
set VAR_A6_147 = PartyAdd(0)
}
if ( IsInParty(2) == 0 ) {
set VAR_A6_147 = PartyAdd(2)
}
if ( IsInParty(1) == 0 ) {
set VAR_A6_147 = PartyAdd(1)
}
if ( IsInParty(6) == 0 ) {
set VAR_A6_147 = PartyAdd(6)
}
set VAR_D5_303 = 0
set VAR_B10_8 = ( VAR_B10_10 = ( VAR_B10_12 = ( VAR_B10_14 = 99 ) ) )
if ( 1 ) {
set VAR_D5_303++
set VAR_B10_8 = 0
}
if ( 1 ) {
set VAR_D5_303++
set VAR_B10_10 = 2
}
if ( 1 ) {
set VAR_D5_303++
set VAR_B10_12 = 1
}
if ( 1 ) {
set VAR_D5_303++
set VAR_B10_14 = 6
}
set VAR_A6_148 = ( VAR_A6_149 = ( VAR_A6_150 = ( VAR_A6_151 = 0 ) ) )
if ( VAR_B10_8 != 99 ) {
if ( GetHP(VAR_B10_8) == 0 ) {
set VAR_A6_148 = 1
}
}
if ( VAR_B10_10 != 99 ) {
if ( GetHP(VAR_B10_10) == 0 ) {
set VAR_A6_149 = 1
}
}
if ( VAR_B10_12 != 99 ) {
if ( GetHP(VAR_B10_12) == 0 ) {
set VAR_A6_150 = 1
}
}
if ( VAR_B10_14 != 99 ) {
if ( GetHP(VAR_B10_14) == 0 ) {
set VAR_A6_151 = 1
}
}
if ( ( ( ( VAR_A6_148 + VAR_A6_149 ) + VAR_A6_150 ) + VAR_A6_151 ) == VAR_D5_303 ) {
if ( ( VAR_B10_8 != 99 ) && ( VAR_A6_148 == 1 ) ) {
SetHP( VAR_B10_8, 1 )
}
if ( ( VAR_B10_10 != 99 ) && ( VAR_A6_149 == 1 ) ) {
SetHP( VAR_B10_10, 1 )
}
if ( ( VAR_B10_12 != 99 ) && ( VAR_A6_150 == 1 ) ) {
SetHP( VAR_B10_12, 1 )
}
if ( ( VAR_B10_14 != 99 ) && ( VAR_A6_151 == 1 ) ) {
SetHP( VAR_B10_14, 1 )
}
}
set VAR_B13_21 = 128
SetPartyReserve( VAR_B13_21 )
set VAR_B10_8 = ( VAR_B10_10 = ( VAR_B10_12 = ( VAR_B10_14 = 0 ) ) )
set VAR_B10_8 = 0
while ( VAR_B10_8 <= 11 ) {
if ( IsInParty(VAR_B10_8) ) {
set VAR_B10_10 |= ( 1 << VAR_B10_8 )
}
set VAR_B10_8++
}
if ( 1 ) {
set VAR_B10_12 |= 1
}
if ( 1 ) {
set VAR_B10_12 |= 4
}
if ( 1 ) {
set VAR_B10_12 |= 2
}
if ( 1 ) {
set VAR_B10_12 |= 64
}
set VAR_B10_14 = ( VAR_B10_10 ^ VAR_B10_12 )
set VAR_B10_8 = 0
while ( VAR_B10_8 <= 11 ) {
if ( ( VAR_B10_14 >> VAR_B10_8 ) & 1 ) {
RemoveParty( VAR_B10_8 )
}
set VAR_B10_8++
}
if ( ( ( VAR_B13_19 >> 0 ) & 1 ) == 0 ) {
SetCharacterData( 0, 1, 255, 9, 0 )
set VAR_B13_19 |= 1
}
if ( ( ( VAR_B13_19 >> 2 ) & 1 ) == 0 ) {
SetCharacterData( 2, 1, 255, 6, 2 )
set VAR_B13_19 |= 4
}
if ( ( ( VAR_B13_19 >> 1 ) & 1 ) == 0 ) {
SetCharacterData( 1, 1, 255, 5, 1 )
set VAR_B13_19 |= 2
}
if ( ( ( VAR_B13_19 >> 6 ) & 1 ) == 0 ) {
SetCharacterData( 6, 1, 255, 6, 6 )
set VAR_B13_19 |= 64
}
if ( ( ( VAR_B13_19 >> 7 ) & 1 ) == 0 ) {
SetCharacterData( 7, 1, 7, 5, 7 )
set VAR_B13_19 |= 128
SetRow( 7, 1 )
}
if ( IsInParty(0) == 0 ) {
set VAR_A6_147 = PartyAdd(0)
}
if ( IsInParty(2) == 0 ) {
set VAR_A6_147 = PartyAdd(2)
}
if ( IsInParty(1) == 0 ) {
set VAR_A6_147 = PartyAdd(1)
}
if ( IsInParty(6) == 0 ) {
set VAR_A6_147 = PartyAdd(6)
}
set VAR_D5_303 = 0
set VAR_B10_8 = ( VAR_B10_10 = ( VAR_B10_12 = ( VAR_B10_14 = 99 ) ) )
if ( 1 ) {
set VAR_D5_303++
set VAR_B10_8 = 0
}
if ( 1 ) {
set VAR_D5_303++
set VAR_B10_10 = 2
}
if ( 1 ) {
set VAR_D5_303++
set VAR_B10_12 = 1
}
if ( 1 ) {
set VAR_D5_303++
set VAR_B10_14 = 6
}
set VAR_A6_148 = ( VAR_A6_149 = ( VAR_A6_150 = ( VAR_A6_151 = 0 ) ) )
if ( VAR_B10_8 != 99 ) {
if ( GetHP(VAR_B10_8) == 0 ) {
set VAR_A6_148 = 1
}
}
if ( VAR_B10_10 != 99 ) {
if ( GetHP(VAR_B10_10) == 0 ) {
set VAR_A6_149 = 1
}
}
if ( VAR_B10_12 != 99 ) {
if ( GetHP(VAR_B10_12) == 0 ) {
set VAR_A6_150 = 1
}
}
if ( VAR_B10_14 != 99 ) {
if ( GetHP(VAR_B10_14) == 0 ) {
set VAR_A6_151 = 1
}
}
if ( ( ( ( VAR_A6_148 + VAR_A6_149 ) + VAR_A6_150 ) + VAR_A6_151 ) == VAR_D5_303 ) {
if ( ( VAR_B10_8 != 99 ) && ( VAR_A6_148 == 1 ) ) {
SetHP( VAR_B10_8, 1 )
}
if ( ( VAR_B10_10 != 99 ) && ( VAR_A6_149 == 1 ) ) {
SetHP( VAR_B10_10, 1 )
}
if ( ( VAR_B10_12 != 99 ) && ( VAR_A6_150 == 1 ) ) {
SetHP( VAR_B10_12, 1 )
}
if ( ( VAR_B10_14 != 99 ) && ( VAR_A6_151 == 1 ) ) {
SetHP( VAR_B10_14, 1 )
}
}
Charmap[RussianPirateRGR]=0123456789+-=*% АBСDEFGНIJКLМNOPQRSТUVWXYZ(!?“:.аbсdеfдhijкlтпорqrstиvwxyz),/+~&БДЖЗИЙЛУÍÌГПФШЩЬЭЯЮÜбвжзмнцйíìглшщэчыùюüЦяфьЫЧ'”_}{∴∵♪→∈×♦§<>←∋↑△□∞♥?????????????«»↓―°★♂♀☺?„‘#※;¡¿
Charmap[RussianPirateRGR]=0123456789+-=*% АBСDEFGНIJКLМNOPQRSТUVWXYZ(!?“:.аbсdеfдhijкlтпорqrstиvwxyz),/+~&БДЖЗИЙЛУÍÌГПФШЩЬЭЯЮÜбвжзмнцйíìглшщэчыùюüЦяфьЫЧ'”_}{∴∵♪→∈×♦§<>←∋↑△□∞♥?????????????«»↓―°★♂♀☺?„‘#※;¡¿
# Hades Workshop configuration file
# Comment lines begin with #
[Preferences]
Charmap=Latin
OpcodeCharacter=µ
MenuColor=0
TextPreview=2
[Text]
Charmap[Latin]=0123456789+-=*% ABCDEFGHIJKLMNOPQRSTUVWXYZ(!?“:.abcdefghijklmnopqrstuvwxyz),/+~&ÁÀÂÄÉÈÊËÍÌÎÏÓÒÔÖÚÙÛÜáàâäéèêëíìîïóòôöúùûüÇÑçñŒß'”_}{∴∵♪→∈×♦§<>←∋↑△□∞♥?????????????«»↓―°★♂♀☺?„‘#※;¡¿
Charmap[Latin][A]=?
Charmap[Latin][B]=?
Charmap[RussianPirateRGR]=0123456789+-=*% АBСDEFGНIJКLМNOPQRSТUVWXYZ(!?“:.аbсdеfдhijкlтпорqrstиvwxyz),/+~&БДЖЗИЙЛУÍÌГПФШЩЬЭЯЮÜбвжзмнцйíìглшщэчыùюüЦяфьЫЧ'”_}{∴∵♪→∈×♦§<>←∋↑△□∞♥?????????????«»↓―°★♂♀☺?„‘#※;¡¿
Charmap[Japanese]=0123456789+-=*% ABCDEFGHIJKLMNOPQRSTUVWXYZ(!?゛:。abcdefghijklmnopqrstuvwxyz)、/・〜&「」…、。ーあいうえおぁぃぅぇぉかきくけこがぎぐげごさしすせそざじずぜぞたちつてとだぢづでどなにぬねのはひふへほばびぶべぼまみむめもぱぴぷぺぽやゆよゃゅょっらりるれろわをんアイウエオァィゥェォカキクケコガギグゲゴサシスセソザジズゼゾタチツテトダヂヅデドナニヌネノハヒフヘホバビブベボマミムメモパピプペポヤユヨャュョッラリルレロワヲンヴ
Charmap[Japanese][A]=『』'城魔南場艇劇村道山洞窟宮砂街黒樹火幹法士森装用地備族下沼古氷輪術体祠性帽鉄属子門使武器石駅剣車馬畑号撃敵腕与専攻定薬全回白指効拳設動金雷師源町果単一数竜大技手黄宝変風鏡剤珠盗板得防頂目更北毒態状中死水見発暗無消列力気避取入精皮秘豆賊氏聖服生天炎切復在現味御加追人率色事赤複返費前闇冷投減桃針線神当路橋角髭月羽爪枯心瑚胸光鎧衣内郷司祭本妖後珊忍憩呪斬女吸方蘇孔理波青上値能収黙化沈倍自調乱半喚相迷眠召混先惑分実必制通験瀕改逃経反治万空原導利止隠固牙象鯨星右育持長鍵形面解意極者教触戒区熱満統免許射貫知熟警日緑
Charmap[Japanese][B]=替要決刀告宣運画江庭園部夢食着三付根束飽興帯転柔尾草奮円頭巾髪野菜銀左棒八閃Ⅱ兜猫飾嘯雑鳴息突章絞狂華六咲命桜海裁獄放魚魂夜戦所最闘個選獣種険冒初作幻確義奥移並誰絶物不受了的弱点終字常猛買名覚同々異未処文削除編成元屋造店鍛冶売書※択認箇具操否位置視世行出即土守殺身今何脱恐睡時好代高湿谷押諸岬漠岸脈盆平島瀬霧去東西陸浅忘外側閉夕川辺近浜血絵対重可向系正期記憶進階段退各合小遠距離速別表示間枚類以補助騎港王国裏徐
#more stuff below...
3 - Is it possible to disable equipment stat boosts so the stat growth is fixed to its minimum value?
Yes, that can be done right in the item section of Hades Workshop. Each weapon or armor has a Stat Set that can be modified to your liking.
2 - The first time you meet a new char, his level will be higher than 1 unless you're on level 1. This makes it impossible to max mag stones for that char if you level up. Is there a way to disable this check and simply have the character begin at level 1?
@itoikenza : There's unfortunatly no way to replace Beatrix inside the menus and battles and not on the field, besides doing what I described several times (replace Beatrix by a normal character at the beginning of the field's "main" function and replace her back in the party at the end of that same function).
I plan to make HW compatible with the Steam version (actually, if everything goes well, the space limitation should be removed, enabling a bunch of cool stuff), but I can't tell before I see it ^^"
Too bad about Beatrix, Tirlititi, thanks for considering making steam ver. compatible.
Remember this?!
(https://dl.dropboxusercontent.com/u/50488782/models/itoikenzaFF9Change.PNG)
How about that editing "Change" into any other movelist, or even a custom one called "Killer"
Remember this?!Is this type of Modding works?Spoiler: show
How about that editing "Change" into any other movelist, or even a custom one called "Killer"
Yeah, there is possibility. You should Edit Field scripts where characters fist time join your party.
Also I took Eiko at lv1 when Markus was lv 22
Scroll up all messages and you will find what Scripts you should edit to obtain Eiko and Amarant at minimal levels.
case +0:
MoveCamera( 160, 112, 1, 8 )
Wait( 45 )
MoveCamera( 256, 224, 30, 8 )
Wait( 15 )
RunScript( 2, 15, 12 )
Wait( 10 )
RunScript( 2, 18, 12 )
Wait( 10 )
RunScriptSync( 2, 16, 12 )
WindowSyncEx( 16, 3, 128, 137 )
WindowSyncEx( 15, 1, 128, 138 )
WindowSyncEx( 18, 2, 128, 139 )
WindowSyncEx( 18, 2, 128, 140 )
WindowSyncEx( 18, 2, 128, 141 )
WindowSyncEx( 15, 1, 128, 142 )
WindowSyncEx( 18, 2, 128, 143 )
0xBD( 9, 2798 )
Music1( 25089, 65535, 50 )
Model2( 40960, 12, 128, 1 )
Wait( 15 )
WindowAsyncEx( 15, 1, 128, 144 )
Wait( 45 )
set VAR_B13_21 = 2059
SetPartyReserve( VAR_B13_21 )
RemoveParty( 0 )
RemoveParty( 1 )
RemoveParty( 2 )
RemoveParty( 3 )
RemoveParty( 4 )
RemoveParty( 5 )
RemoveParty( 9 )
RemoveParty( 6 )
RemoveParty( 10 )
RemoveParty( 7 )
RemoveParty( 11 )
RemoveParty( 8 )
set VAR_A6_147 = PartyAdd(11)
set VAR_A6_147 = PartyAdd(0)
set VAR_A6_147 = PartyAdd(1)
set VAR_A6_147 = PartyAdd(3)
if ( IsInParty(5) ) {
set Setting_OptionalQuina = 1
} else {
set Setting_OptionalQuina = 0
}
if ( ( ( VAR_B13_19 >> 14 ) & 1 ) == 0 ) {
SetCharacterData( 11, 1, 14, 21, 12 )
set VAR_B13_19 |= 16384
SetRow( 11, 1 )
}
SetHP( 11, 9999 )
SetMP( 11, 999 )
SetStatus( 11, 127 )
if ( ( ( VAR_B13_19 >> 0 ) & 1 ) == 0 ) {
SetCharacterData( 0, 1, 255, 9, 0 )
set VAR_B13_19 |= 1
}
if ( ( ( VAR_B13_19 >> 3 ) & 1 ) == 0 ) {
SetCharacterData( 3, 1, 255, 5, 3 )
set VAR_B13_19 |= 8
}
if ( ( ( VAR_B13_19 >> 1 ) & 1 ) == 0 ) {
SetCharacterData( 1, 1, 255, 5, 1 )
set VAR_B13_19 |= 2
}
SetName( 11, 96 )
set Setting_OptionalQuina = 0
set Setting_DaggerDepresses = 0
set Setting_MPx4 = 1
Battle( 1, 303 )
break
to case +0:
MoveCamera( 160, 112, 1, 8 )
Wait( 45 )
MoveCamera( 256, 224, 30, 8 )
Wait( 15 )
RunScript( 2, 15, 12 )
Wait( 10 )
RunScript( 2, 18, 12 )
Wait( 10 )
RunScriptSync( 2, 16, 12 )
WindowSyncEx( 16, 3, 128, 137 )
WindowSyncEx( 15, 1, 128, 138 )
WindowSyncEx( 18, 2, 128, 139 )
WindowSyncEx( 18, 2, 128, 140 )
WindowSyncEx( 18, 2, 128, 141 )
WindowSyncEx( 15, 1, 128, 142 )
WindowSyncEx( 18, 2, 128, 143 )
0xBD( 9, 2798 )
Music1( 25089, 65535, 50 )
Model2( 40960, 12, 128, 1 )
Wait( 15 )
WindowAsyncEx( 15, 1, 128, 144 )
Wait( 45 )
set VAR_B13_21 = 2048
SetPartyReserve( VAR_B13_21 )
RemoveParty( 0 )
RemoveParty( 1 )
RemoveParty( 2 )
RemoveParty( 3 )
RemoveParty( 4 )
RemoveParty( 5 )
RemoveParty( 9 )
RemoveParty( 6 )
RemoveParty( 10 )
RemoveParty( 7 )
RemoveParty( 11 )
RemoveParty( 8 )
if ( IsInParty(5) ) {
set Setting_OptionalQuina = 1
} else {
set Setting_OptionalQuina = 0
}
if ( ( ( VAR_B13_19 >> 14 ) & 1 ) == 0 ) {
SetCharacterData( 11, 1, 14, 21, 12 )
set VAR_B13_19 |= 16384
SetRow( 11, 1 )
}
SetHP( 11, 9999 )
SetMP( 11, 999 )
SetStatus( 11, 127 )
if ( ( ( VAR_B13_19 >> 0 ) & 1 ) == 0 ) {
SetCharacterData( 0, 1, 255, 9, 0 )
set VAR_B13_19 |= 1
}
if ( ( ( VAR_B13_19 >> 3 ) & 1 ) == 0 ) {
SetCharacterData( 3, 1, 255, 5, 3 )
set VAR_B13_19 |= 8
}
if ( ( ( VAR_B13_19 >> 1 ) & 1 ) == 0 ) {
SetCharacterData( 1, 1, 255, 5, 1 )
set VAR_B13_19 |= 2
}
set VAR_A6_147 = PartyAdd(11)
set VAR_A6_147 = PartyAdd(0)
set VAR_A6_147 = PartyAdd(1)
set VAR_A6_147 = PartyAdd(3)
SetName( 11, 96 )
set Setting_OptionalQuina = 0
set Setting_DaggerDepresses = 0
set Setting_MPx4 = 1
Battle( 1, 303 )
break
if ( GetTimerTime > 3 ) {
if ( !VAR_B6_56 ) {
set VAR_B13_21 = 17
SetPartyReserve( VAR_B13_21 )
set VAR_B10_8 = ( VAR_B10_10 = ( VAR_B10_12 = ( VAR_B10_14 = 0 ) ) )
set VAR_B10_8 = 0
while ( VAR_B10_8 <= 11 ) {
if ( IsInParty(VAR_B10_8) ) {
set VAR_B10_10 |= ( 1 << VAR_B10_8 )
}
to if ( GetTimerTime > 3 ) {
if ( !VAR_B6_56 ) {
set VAR_B13_21 = 16
SetPartyReserve( VAR_B13_21 )
set VAR_B10_8 = ( VAR_B10_10 = ( VAR_B10_12 = ( VAR_B10_14 = 0 ) ) )
set VAR_B10_8 = 0
while ( VAR_B10_8 <= 11 ) {
if ( IsInParty(VAR_B10_8) ) {
set VAR_B10_10 |= ( 1 << VAR_B10_8 )
}
0xA9( -6 )
FadeFilter( 6, 24, VAR_B6_17, 255, 255, 255 )
Wait( 25 )
set VAR_B13_21 = 39
SetPartyReserve( VAR_B13_21 )
set VAR_B10_8 = ( VAR_B10_10 = ( VAR_B10_12 = ( VAR_B10_14 = 0 ) ) )
set VAR_B10_8 = 0
while ( VAR_B10_8 <= 11 ) {
if ( IsInParty(VAR_B10_8) ) {
set VAR_B10_10 |= ( 1 << VAR_B10_8 )
}
to }
0xA9( -6 )
FadeFilter( 6, 24, VAR_B6_17, 255, 255, 255 )
Wait( 25 )
set VAR_B13_21 = 32
SetPartyReserve( VAR_B13_21 )
set VAR_B10_8 = ( VAR_B10_10 = ( VAR_B10_12 = ( VAR_B10_14 = 0 ) ) )
set VAR_B10_8 = 0
while ( VAR_B10_8 <= 11 ) {
if ( IsInParty(VAR_B10_8) ) {
set VAR_B10_10 |= ( 1 << VAR_B10_8 )
}
}
0xA9( -6 )
FadeFilter( 6, 24, VAR_B6_17, 255, 255, 255 )
Wait( 25 )
set VAR_B13_21 = 51
SetPartyReserve( VAR_B13_21 )
set VAR_B10_8 = ( VAR_B10_10 = ( VAR_B10_12 = ( VAR_B10_14 = 0 ) ) )
set VAR_B10_8 = 0
while ( VAR_B10_8 <= 11 ) {
if ( IsInParty(VAR_B10_8) ) {
set VAR_B10_10 |= ( 1 << VAR_B10_8 )
}
to }
0xA9( -6 )
FadeFilter( 6, 24, VAR_B6_17, 255, 255, 255 )
Wait( 25 )
set VAR_B13_21 = 32
SetPartyReserve( VAR_B13_21 )
set VAR_B10_8 = ( VAR_B10_10 = ( VAR_B10_12 = ( VAR_B10_14 = 0 ) ) )
set VAR_B10_8 = 0
while ( VAR_B10_8 <= 11 ) {
if ( IsInParty(VAR_B10_8) ) {
set VAR_B10_10 |= ( 1 << VAR_B10_8 )
}
LearnAbility( 2, 49 )
LearnAbility( 2, 51 )
LearnAbility( 2, 55 )
LearnAbility( 2, 58 )
LearnAbility( 2, 62 )
As I understood this code made for learning eidolons.Tirlititi, do you think it is possible to make Hades Workshop comparable with Android version of FFIX?
Tirlititi thank you for reply.
Final Fantasy IX realised on Android today.
Congratulations folk.
Tirlititi, do you think it is possible to make Hades Workshop comparable with Android version of FFIX?
}
switch 2 ( GetDialogChoice ) from 0 {
case +0:
RunScript( 6, 12, 17 )
RunScript( 6, 2, 18 )
if ( Global_ScenarioCounter < 5690 ) {
RunScriptSync( 6, 12, 19 )
set VAR_B13_21 = 51
SetPartyReserve( VAR_B13_21 )
set VAR_B10_8 = ( VAR_B10_10 = ( VAR_B10_12 = ( VAR_B10_14 = 0 ) ) )
set VAR_B10_8 = 0
while ( VAR_B10_8 <= 11 ) {
if ( IsInParty(VAR_B10_8) ) {
set VAR_B10_10 |= ( 1 << VAR_B10_8 )
}
to }
switch 2 ( GetDialogChoice ) from 0 {
case +0:
RunScript( 6, 12, 17 )
RunScript( 6, 2, 18 )
if ( Global_ScenarioCounter < 5690 ) {
RunScriptSync( 6, 12, 19 )
set VAR_B13_21 = 32
SetPartyReserve( VAR_B13_21 )
set VAR_B10_8 = ( VAR_B10_10 = ( VAR_B10_12 = ( VAR_B10_14 = 0 ) ) )
set VAR_B10_8 = 0
while ( VAR_B10_8 <= 11 ) {
if ( IsInParty(VAR_B10_8) ) {
set VAR_B10_10 |= ( 1 << VAR_B10_8 )
}
} else {
RunScriptSync( 6, 12, 20 )
set VAR_B13_21 = 39
SetPartyReserve( VAR_B13_21 )
set VAR_B10_8 = ( VAR_B10_10 = ( VAR_B10_12 = ( VAR_B10_14 = 0 ) ) )
set VAR_B10_8 = 0
while ( VAR_B10_8 <= 11 ) {
if ( IsInParty(VAR_B10_8) ) {
set VAR_B10_10 |= ( 1 << VAR_B10_8 )
}
to } else {
RunScriptSync( 6, 12, 20 )
set VAR_B13_21 = 32
SetPartyReserve( VAR_B13_21 )
set VAR_B10_8 = ( VAR_B10_10 = ( VAR_B10_12 = ( VAR_B10_14 = 0 ) ) )
set VAR_B10_8 = 0
while ( VAR_B10_8 <= 11 ) {
if ( IsInParty(VAR_B10_8) ) {
set VAR_B10_10 |= ( 1 << VAR_B10_8 )
}
Tirlititi, I added code to configuration, "RussianPirateRGR" appeared at Alphabet. I chose it. But bin file doesn't open as FF9 bin file. Could you check it yourself?Сконвертируй .bin в .iso например UltraISO. Поидее я так делал. ну или образ тем же UltraISO открой, и достать от туда FF9.img и уже его открывать в программе.
I have a question, if I will edit Spell animation, would it affect to enemies spell animations too or just foe parties spell animation?
#HW filetype TEXT
For UI texts, it must be this instead :#HW filetype UITEXT
After that, you need to specify to which text block corresponds your file using a line like this one :#HW fileid [ID]
replacing [ID] by the number corresponding to the text block in the following list :0 : Generic UI
1 : Debug Room
2 : Prima Vista
3 : Alexandria Castle (1)
4 : Evil Forest
7 : Cleyra Trunk
8 : Ice Cavern
18 : Red Rose
22 : Lindblum Castle (Disc 2)
23 : Mist Gates
30 : Terra
31 : Mountain Path
32 : Conde Petie
33 : Alexandria (Disc 1)
37 : Black Mage Village (Disc 2/3)
38 : Mognet Central
40 : Ruined Prima Vista
42 : Quan's Dwelling
44 : Cleyra
47 : Dali
50 : Dali Underground
51 : Gizamaluke Grotto
52 : Bran Bal
53 : Observatory Mountain
63 : Cargo Ship
70 : Treno (Disc 2)
71 : Qu's Marsh
74 : South Gate
77 : Burmecia
88 : Alexandria Castle (3)
89 : Alexander
90 : Alexandria (Early Disc 3)
91 : Alexandria By Night
121 : Shrines
124 : Oeilvert
134 : Pinnacle Rocks
166 : Daguerreo
186 : Hilda Garde III
187 : Ending
189 : Invincible
223 : Treno & Supersoft
276 : Lindblum (Disc 1)
289 : Alexandria Castle (2)
290 : Stormless Cleyra
344 : Pandemonium
358 : Madain Sari (Disc 2/3)
359 : Gargan Roo
360 : Madain Sari (Disc 4)
361 : Fossil Roo
484 : Mount Gulug
485 : Occupied Lindblum
525 : Occupied Lindblum Castle
595 : Lindblum (Disc 3/4)
694 : Memoria
738 : Iifa Tree Roots
739 : Ipsen Castle
740 : Desert Palace
741 : Treno (Disc 3/4)
754 : Ruined Alexandria Castle
908 : Esto Gaza
943 : Lindblum Castle (Disc 3/4)
944 : Iifa Tree
945 : Chocobo Places
946 : Ruined Alexandria
1073 : Black Mage Village (Disc 4)
Then, before each text, you need to write a line :#HW newtext [POS]
replacing [POS] by the text's position in the text block.Update to v0.32 :
- Added a Mod Manager tool ; it allows to define which datas should be overwritten when you save (using any of the 3 save methods). Its main purpose is to allow you to create a Mod file (.hws) from an already modded version of the game : just check all the features that differ from the original game.
Hidden Dialogs : Texts (Cleyra) and Field scripts.
God Save the Queen : Items and Shops.
Vir's mods : Items, Stats, Texts (for some typo mistakes), Spells (Thunder Slash), Enemies (only the Pandemonium trio and Tantarian for the forced exp, I think).
Unleashed : Spells, Stats, Items, Shops and Enemies. Maybe also Commands and Supporting Abilities (I don't remember that being changed).
Alternate Fantasy : All those plus World Maps, a few Fields and Spell Animations.
ATB Speedup : not something modifiable in HW. Compatible with everything else.
Сконвертируй .bin в .iso например UltraISO. Поидее я так делал. ну или образ тем же UltraISO открой, и достать от туда FF9.img и уже его открывать в программе.
Кудос, хоть была плохая реализация, но зато переведено более живо. Я думал от туда шрифт от RGR вставить и текст переконвертировать под RGR формат таблицы, Но если заниматься, то в шрифте от RGR я тогда парочку косяков с тенью находил, и хотя бы упорядочить их.
Самая большая проблема пока что это импорт\экспорт надеюсь Tirlititi все таки сделает.
хотя по мне самая важная вещь это увеличить количество букв под текст в PSX образе, к тому же я думаю версия steam далеко не всем понравиться. (мне например не понравились upscaled задники, еще со звуком не известно что будет)
Update to v0.32 :
- Added Russian RGR charmap in the .conf file. Hades Workshop can't scan the translated version directly though
Function Theater_Ship_Miniature_SpeakBTN
set VAR_GlobBool_158 = 0
if ( VAR_GlobBool_159 == 1 ) {
DisableMove( )
if ( VAR_GlobBool_144 == 0 ) {
DisableMenu( )
} else {
Wait( 1 )
}
}
0x27( 127 )
HideObject( 255, 0 )
SetTextVariable( 0, 326 )
AddItem( 326, 1 )
WindowSync( 7, 0, 61 )
set VAR_GlobBool_158 = 1
if ( VAR_GlobBool_159 == 1 ) {
if ( VAR_GlobBool_156 == 0 ) {
EnableMove( )
0x27( 255 )
if ( VAR_GlobBool_144 == 0 ) {
EnableMenu( )
}
}
}
TerminateEntry( 255 )
return
5 ) Change the "326" figures to your item ID ; 326 is the ID of the first unused Key item so you may use that slot to create your Mini-Prima Vista as well, if ( VARL_GenBool_2419 == 1 ) {
InitObject( 3, 0 )
}
into these : if ( ( VARL_GenBool_2419 == 1 ) && ( GetItemCount(326) == 0 ) ) {
InitObject( 3, 0 )
}
7 ) There's no 7th step,Yes tiff doesn't seem to have any layers when you open it up in phtoshop. Might be a problem in the future if you'll ever make it possible for people to reimport pictures. But I doubt anyone will ever do that, you can't make the backgrounds higher resolution anyway. I'm trying to recreate the pre rendered effect in another engine and I thought I'd use one of the backgrounds from ff9, if I could export a character model from the game and it's animations too. I could basically recreate a scene exactly as it is from ff9. It's not a big deal, but if you want it to work you could maybe make it work somehow. ;)
Vivi (8)
Dagger_Bis (76)
Zidane (98)
Dagger (185)
Freya (192)
Beatrix (204)
Quina (273)
Eiko (443)
Amarant (509)
Steiner (5489)
I don't think you can use battle models ; there seems to be a problem when using them. // Vivi
SetModel( 8, 61 )
SetStandAnimation( 148 )
SetWalkAnimation( 571 )
SetRunAnimation( 419 )
SetLeftAnimation( 917 )
SetRightAnimation( 918 )
SetObjectLogicalSize( 20, 30, 44 )
SetAnimationStandSpeed( 14, 16, 18, 20 )
SetHeadAngle( 65, 57 )
// Dagger Bis
SetModel( 76, 91 )
SetStandAnimation( 2089 )
SetWalkAnimation( 2086 )
SetRunAnimation( 2091 )
SetLeftAnimation( 2088 )
SetRightAnimation( 2084 )
SetObjectLogicalSize( 20, 26, 42 )
SetAnimationStandSpeed( 14, 16, 18, 20 )
SetHeadAngle( 89, 4 )
// Zidane
SetModel( 98, 93 )
SetStandAnimation( 200 )
SetWalkAnimation( 25 )
SetRunAnimation( 38 )
SetLeftAnimation( 40 )
SetRightAnimation( 41 )
SetObjectLogicalSize( 20, 24, 40 )
SetAnimationStandSpeed( 14, 16, 18, 20 )
SetHeadAngle( 97, 61 )
// Dagger
SetModel( 185, 91 )
SetStandAnimation( 2089 )
SetWalkAnimation( 2086 )
SetRunAnimation( 2091 )
SetLeftAnimation( 2088 )
SetRightAnimation( 2084 )
SetObjectLogicalSize( 20, 26, 42 )
SetAnimationStandSpeed( 14, 16, 18, 20 )
SetHeadAngle( 89, 4 )
// Freya
SetModel( 192, 94 )
SetStandAnimation( 2556 )
SetWalkAnimation( 2553 )
SetRunAnimation( 2558 )
SetLeftAnimation( 2555 )
SetRightAnimation( 2551 )
SetObjectLogicalSize( 26, 34, 48 )
SetAnimationStandSpeed( 14, 16, 18, 20 )
SetHeadAngle( 105, 53 )
// Beatrix
SetModel( 204, 100 )
SetStandAnimation( 2978 )
SetWalkAnimation( 2975 )
SetRunAnimation( 2981 )
SetLeftAnimation( 2980 )
SetRightAnimation( 2974 )
SetObjectLogicalSize( 20, 20, 30 )
SetAnimationStandSpeed( 14, 16, 18, 20 )
SetHeadAngle( 104, 48 )
// Quina
SetModel( 273, 92 )
SetStandAnimation( 3228 )
SetWalkAnimation( 3237 )
SetRunAnimation( 3230 )
SetLeftAnimation( 3235 )
SetRightAnimation( 3227 )
SetObjectLogicalSize( 40, 48, 60 )
SetAnimationStandSpeed( 14, 16, 18, 20 )
SetHeadAngle( 65, 45 )
// Eiko
SetModel( 443, 63 )
SetStandAnimation( 7503 )
SetWalkAnimation( 7518 )
SetRunAnimation( 7506 )
SetLeftAnimation( 7516 )
SetRightAnimation( 7514 )
SetObjectLogicalSize( 20, 24, 38 )
SetAnimationStandSpeed( 14, 16, 18, 20 )
SetHeadAngle( 65, 5 )
// Amarant
SetModel( 509, 122 )
SetStandAnimation( 8307 )
SetWalkAnimation( 8316 )
SetRunAnimation( 8312 )
SetLeftAnimation( 8310 )
SetRightAnimation( 8314 )
SetObjectLogicalSize( 30, 35, 50 )
SetAnimationStandSpeed( 14, 16, 18, 20 )
SetHeadAngle( 65, 0 )
// Steiner
SetModel( 5489, 104 )
SetStandAnimation( 2001 )
SetWalkAnimation( 1996 )
SetRunAnimation( 2005 )
SetLeftAnimation( 1986 )
SetRightAnimation( 2010 )
SetObjectLogicalSize( 30, 35, 50 )
SetAnimationStandSpeed( 14, 16, 18, 20 )
SetHeadAngle( 97, 32 )
You can unfortunatly only use those 5 animations each time. The other character animations are field-dependant.$2 = $29[51] & 0xFF
nothing
$2 = $2 | 0x1
$29[51] = $2 & 0xFF
$4 = $17[8]
nothing
$3 = $4[5] & 0xFF
nothing
$2 = $3 << 1
$2 = $2 + $3
$2 = $2 << 3
$2 = $2 + $3
$3 = $4[7] & 0xFF
$2 = $2 << 2
jump 0xB4CC0
$3 = $3 + $2
// What lies at 0xB4CC0 :
jump 0xB7918
$29[54] = $3 & 0xFFFF
The $ things are placeholder for variables (RAM registries actually). There are 31 of them, most of which that have special purposes.$2 = $29[51] & 0xFF
nothing
$2 = $2 | 0x1
$29[51] = $2 & 0xFF
These lines are adding the bitflag 0x1 to $29[51]. That "$29[51]" is a special data that will be used latter by the "jump 0xB7918" call. Note that a lot of spell effects (all I think) end with a "jump 0xB7918" call : it resolves the effect by applying the damage, the statuses, checking if the target should die or change state, run the "hit" animations, etc...$4 = $17[8]
nothing
$3 = $4[5] & 0xFF
nothing
are used to retrieve the spell's power. "$17[8]" is the casted spell's data offset and the 5th data is the spell power (its written in 8 bits, just like the "$29[51]" flags, hence the 0xFF). Now the variable $3 holds the spell power.$2 = $3 << 1
$2 = $2 + $3
$2 = $2 << 3
$2 = $2 + $3
$2 = $2 << 2
You can translate them by "$2 = (($3 * 2 + $3) * 8 + $3) * 4" or, shortly, by "$2 = $3 * 100". Since the raw multiplications are slow operations (or were at the time), the devs prefered to use shifts and sums instead.$3 = $4[7] & 0xFF
$3 = $3 + $2
$29[54] = $3 & 0xFFFF
The spell's accuracy is stored into $3, then added to $2 and stored into "$29[54]", which is the memory place where you need to store the damage number before the "0xB7918" call. Note that the line following a jump call is always executed before the jump actually occurs (there's a delay of one instruction).@ Satoh : I've a list of all the cluster datas and I can easily check the objects' ID. That way I know which model IDs are field-dependant and which are not. For naming them, I looked at the game's script and listed them when I could identify them (there are still a lot of unnamed model IDs btw). I don't think they have any label indeed.It is strange that they would use the same index to refer to each model every time, when they are in different places in each field's data. It seems like there must be a master list somewhere that tells the game why [192] is Freya and [74] is Erin...
Well then, since SE decided to keep the release of the Steam version for later, here is the v0.33 :
- Added a MIPS editing feature. MIPS is the coding language shared by all the PSX games. It's the deepest level of game modifications and shouldn't be used carefree. More infos below.
- You can now add and remove several things, so you don't need to recycle another item to create a new one :
--- Add/Remove texts in text blocks and battles,
--- Add/Remove enemy groups,
--- Add/Remove enemy spells.
- Completed the list of spell effects, though I only know the effect of "Defless" among the new ones : it unconditionally divides both defences by 2.
It is strange that they would use the same index to refer to each model every time, when they are in different places in each field's data. It seems like there must be a master list somewhere that tells the game why [192] is Freya and [74] is Erin...Not necessarily. It may be some ID chosen by Square's compiler. It was decided which index refers to which model at the game's compilation time and the "master list" doesn't exist anymore.
Also, there seems to be a problem with adding new preloads to a field in some cases. For example, adding a preload to the list in Lindblum Shopping Area, breaks the model loading in Lindblum Church Area. Adding two causes the game to break altogether with an error of [unknown opcode 0x3F]Arf, that's a problem of Hades Workshop then, not of the game's preloading datas.
if ( !General_TonberryCounter ) {
set General_TonberryCounter = 1
}
When a Tonberry dies : if ( General_TonberryCounter < 254 ) {
set General_TonberryCounter += 2
}
0xB771C: $2 = 32776 << 16
0xB7720: $4 = $2 + 44784
0xB7724: $3 = $4[192] & 0xFF
0xB7728: $2 = $17[8]
0xB772C: $2 = $2[5] & 0xFF
0xB7730: $LO = $2 * $3
0xB7734: $2 = $LO
0xB7738: jump 0xB7748
0xB773C: if ($2 < 10000) $1 = 1 else $1 = 0
0xB7740: jump 0xB7918 // Offset of "Apply Effect"
0xB7744: $29[54] = $2 & 0xFFFF
0xB7748: if ($1 != $0), jump 0xB7754
0xB774C: $1 = $29[51] & 0xFF
0xB7750: $2 = $0 + 9999
0xB7754: $1 = $1 | 0x1
0xB7758: jump 0xB7740
0xB775C: $29[51] = $1 & 0xFFFF
On the left part, it looks like this :lui 2 32776
addiu 4 2 44784
lbu 3 4 192
lw 2 17 8
lbu 2 2 5
multu 2 3
mflo 2
j 187858
sltiu 2 10000 1
j 187974
sh 29 54 2
bne 1 0 2
lbu 1 29 51
addiu 2 0 9999
ori 1 1 1
j 187856
sh 29 51 1
I've let the lines "jump 0xB7918" and "$29[54] = $2 & 0xFFFF" untouched because they are used by other spell effects, such as Frog Drop. Because of that, the code fits dead on the allowed space of Grudge's spell effect.The counter for Tonberries is not the same as the counter for dragons or steals. You can see the counter increase in Tonberries' AI.
At battle initialization :Code: [Select]if ( !General_TonberryCounter ) {
When a Tonberry dies :
set General_TonberryCounter = 1
}Code: [Select]if ( General_TonberryCounter < 254 ) {
set General_TonberryCounter += 2
}
Function Main_Init
switch 5 ( GetBattleGroupId ) from 0 {
case +0:
InitObject( 1, 128 )
break
case +1:
InitObject( 1, 128 )
InitObject( 1, 129 )
break
case +2:
InitObject( 1, 128 )
InitObject( 2, 129 )
break
case +3:
InitObject( 2, 128 )
break
case +4:
InitObject( 2, 128 )
InitObject( 2, 129 )
break
}
return
About the text offsets, I just tried the disc 1 and 3 of the german version and it worked perfectly :/
I'm afraid your discs 2-4 are not really vanilla games. I don't think that can happen, but tell me if you verify the fact that it was non-modified and it still doesn't work.
uzoko1, Fraggoso you should place HadesWorkshop_ProgressVersion.exe in Hades Workshop 33b version folder, there wxmsw30u_core_gcc471TDM.dll file located and other dlls, and program will run.
Tirlititi, I tried open bins in assets folder, but program creashes every time when I am trying open any file named p0data. Perhaps I am doing something wrong. What file can open HadesWorkshop_ProgressVersion?
HadesWorkshop 33B version where is that at??? Sorry if I am being blind.
Needless to say you can't have a practical use for this versionIt seems it was needed in the end...
Tirlititi have you given up on the mod too...? You haven't been on in a while...
I hope he's still working on it. I'm waiting the steam version of HW sooo much.
RemoveItem( 236, 7 )
RemoveItem( 237, 2 )
RemoveItem( 238, 2 )
RemoveItem( 240, 2 )
RemoveItem( 247, 2 )
RemoveItem( 249, 1 )
RemoveItem( 253, 1 )
AddItem( .... )
Put them in the main function of the first Prima Vista's Cargo Room, it's fine (out of any "if" block).[...] you can link Dagger's eidolons (trance and normal) and the 2 Beatrix Seikens (dunno why there is 2 of them) [...]
Function ManA_Init
set VAR_B10_0 = 58
set VAR_B10_4 = 65163
set VAR_B10_6 = 192
set VAR_B10_2 = 65518
SetModel( 111, 100 )
CreateObject( VAR_B10_0, VAR_B10_4 )
TurnInstant( VAR_B10_6 )
SetStandAnimation( 555 )
SetWalkAnimation( 599 )
SetRunAnimation( 598 )
SetLeftAnimation( 597 )
SetRightAnimation( 601 )
SetObjectLogicalSize( 20, 20, 30 )
SetAnimationStandSpeed( 14, 16, 18, 20 )
SetHeadAngle( 64, 1 )
EnableHeadFocus( 0 )
SetObjectLogicalSize( 1, 40, 150 )
return
The first numbers are the object's initial position (the coordinates X, Y, the facing angle and then the Z coordinate respectively). For the "SetModel" code, a list of known model IDs is available ; note that the model gives its name to the entry, so the model 111 is "ManA".Function ManA_SpeakBTN
ifnot ( IsMovementEnabled ) {
return
}
set VAR_A6_158 = 0
if ( VAR_A6_159 == 1 ) {
DisableMove( )
if ( VAR_A6_144 == 0 ) {
DisableMenu( )
} else {
Wait( 1 )
}
}
0x27( 127 )
TurnTowardObject( 250, 32 )
WaitTurn( )
WindowSync( 0, 128, 199 )
set VAR_A6_158 = 1
if ( VAR_A6_159 == 1 ) {
if ( VAR_A6_156 == 0 ) {
EnableMove( )
0x27( 255 )
if ( VAR_A6_144 == 0 ) {
EnableMenu( )
}
}
}
return
If the player is in a cutscene, we don't want him to be able to speak with the NPC that he's facing, thus the "IsMovementEnabled" check. The following 10 lines are standard for everytime the game removes the control from the player, and the last ones are their counterpart to give it back. The "TurnTowardObject( 250, 32 )" forces the NPC to face the player's character, and the "WindowSync" displays a bubble of dialog.Wait(1)
loop
Which means that the function is executed every frame. There's a Range function that runs when the player's character comes in range of the NPC but don't necessarily speaks to him.InitObject( 252, 0 )
InitObject( 253, 0 )
InitObject( 254, 0 )
They can then be refered using the same special entry IDs for cutscenes and such. An example of use can be found in the script of the field "Oeilvert/Planetarium". In the function "Zidane_17" of this field, there's the cutscene when Zidane reads terran letters and the present characters are amazed. The different calls of "RunScriptAsync( ..., 252, ... )" are used to handle the reactions of the 2nd party member, whoever he is, at the different points of the cutscene.Function Beatrix_Init
set VAR_B10_0 = 364
set VAR_B10_4 = 63977
set VAR_B10_6 = 252
set VAR_B10_2 = 65456
SetModel( 204, 100 )
CreateObject( VAR_B10_0, VAR_B10_4 )
TurnInstant( VAR_B10_6 )
SetStandAnimation( 2978 )
SetWalkAnimation( 2975 )
SetRunAnimation( 2981 )
SetLeftAnimation( 2980 )
SetRightAnimation( 2974 )
SetObjectLogicalSize( 20, 20, 30 )
SetHeadAngle( 104, 48 )
return
Replace the first numbers by coordinates (or you can remove those 4 lines and put the coordinates inside the "CreateObject" and "TurnInstant" lines).if (( VAR_B6_24 == 100 ) && (World_CurrentTransport==0) && ((MV_WorldPositionX12 - POS_X) <= 30000L) && ((POS_X - MV_WorldPositionX12) <= 30000L) && ((MV_WorldPositionY12 - POS_Y) <= 30000L) && ((POS_Y - MV_WorldPositionY12) <= 30000L)) {
set VAR_B6_39 = PLACE_ID
RunScriptAsync( 6, 1, 11 )
}
where (POS_X, POS_Y) is the place's position (that's the hard thing to get) and PLACE_ID is the corresponding ID in the following table:After that, replace your modified binary file (which is still opened in HW) by the original game file...I don't have HW in front of me now, can you elaborate via a video or gif? Or more details? I just simply go to File then Open? Then it'll open vanilla right next to modified?
hey Tirlititi, can u make a beta version, can u set the Max hp above 65k, i think steam version can bypass this limit. i found this when using a tent on a boss it heals above 9999
also tool crashes when u load up steam version and click on stats tab.
@ Fraggoso : You can already export the backgrounds, you can't import them back. It won't be ready for the next release but maybe for the one after that (or if someone else does that ; the project is on GitHub !).
But since you can export them already, someone can start reworking them. I didn't see anyone doing that yet.
Also, Aelrobis seems to be making some work about it currently (Export/Import). I don't know whether he'll be able to change the resolution or how his solution will be conflicting with HW though.
hey is there any reasons for,the steam version freezes when i click on the stats tab?
LearnAbility( 8, 149 )
LearnAbility( 8, 150 )
LearnAbility( 8, 151 )
LearnAbility( 8, 152 )
LearnAbility( 8, 2 )
LearnAbility( 8, 5 )
LearnAbility( 8, 6 )
LearnAbility( 8, 10 )
LearnAbility( 8, 14 )
LearnAbility( 8, 16 )
LearnAbility( 8, 19 )
LearnAbility( 8, 24 )
Then parse and confirm.Hi everone, version 0.35 is now available :
- You can now poorly modify the IL script code (more details below),
- In the same panel, the feature called "Macro" allows to do pre-generated IL script modifications. For now, only two are availables :
--- Unlock Ability Learning for Beatrix : allows Beatrix to learn abilities like a regular character and to use supporting abilities (more below),
--- Disable Cheats : remove the booster features of the Steam version. The speedup is still available but it also speeds up timed game phases, like Hot & Cold or the 30 minutes Alexandria event.
- Fixed the export/import text batching,
- Fixed several bugs in scripts edition (when I say "script" alone, I mean the field/World and enemy AI scripts).
Two notes about IL scripts :
1) It is an assembly-type script, so it will be very very hard to decipher (plus, as said, the way HW displays it is not the best...). I can't imagine someone doing proper things if he doesn't have the source/decompiled C# code to compare with.
2) The list of IL instructions can be found here for instance :
https://en.wikipedia.org/wiki/List_of_CIL_instructions
IL and CIL are synonymous.
One of the most useful IL type to look at and modify must be "btl_calc" : every methods of this type are useful. It contains the same battle mechanics as the available MIPS code in the PSX version : damage calculations, status adding, special spell requirements... I modified a bit a version of the these methods to make it a bit more convenient (I changed the names of those "CalcSub" methods). You can find it here :
https://dl.dropboxusercontent.com/u/98687557/Resources/BtlCalc.cs
About IL Macros, they modify one or several methods ; if you modify those methods yourself aside of that, the related macro will not be available anymore. I'm planning on adding options for them also, so you can decide if you want to disable all the cheats or just some of them for instance. One of their point is also that they will be updated and the bugs (if any) will be fixed without for you to change everything if a bug is found for a macro.
About the "Unlock Ability Learning for Beatrix", you need to do two things so that it works : apply the macro and give to Beatrix AP requirements to her abilities (and optionnally supporting skills). She then will be like a normal character, which also means that her abilities won't be available from the start. You can make her learn her standard abilities by adding this code inside the field scripts when you recruit her for the first time :
In "A. Castle/Queen's Chamber" (the 3rd one when the fields are not sorted alphabetically ; there are functions with "Queen_Brahne" and "Bandersnatch" in the list on the left),
In the function "Beatrix_Loop", go at the very bottom of the function, there is a line "Battle( 0, 916 )" which is the battle against Bandersnatch.
Add these lines right before that battle :Code: [Select]LearnAbility( 8, 149 )
Then parse and confirm.
LearnAbility( 8, 150 )
LearnAbility( 8, 151 )
LearnAbility( 8, 152 )
LearnAbility( 8, 2 )
LearnAbility( 8, 5 )
LearnAbility( 8, 6 )
LearnAbility( 8, 10 )
LearnAbility( 8, 14 )
LearnAbility( 8, 16 )
LearnAbility( 8, 19 )
LearnAbility( 8, 24 )
Also, I checked and you can use this macro for the same purpose on Marcus, Blank and Cinna (if you give them abilities to learn). Their ability AP progression will even be conserved if you save/load the game, but, judging from the source code (maybe gjoerulv can confirm that, or someone tests it), they will be saved on the ability AP slots of the corresponding regular character : If Marcus learn abilities in disc 2, Eiko will have abilities learned as soon as you recruit her.
The script opcodes "LearnAbility" and "UnlearnAbility" should do the trick for that.
Beatrix has not this kind of problem since she doesn't share her character slot with someone else. Her ability learning progression is saved properly.
About the "Stats" panel bug now...
I wasn't able to reproduce it, but I think I know where it comes from : you somehow don't have the same Assembly-CSharp.dll as me.
You may try to reinstall FFIX to fix that problem (don't forget to copy your saves and such). I will need to fix it anyway because I don't want HW to be dependant on having the exact same files as the normal ones. I spent quiet some time trying to fix that already, though...
If one of you three who have the bug can check something for me :
- Check that you can go to the "CIL code" panel and that if you apply the CIL macro "Unlock Ability Learning for Beatrix", there's no bug (the tool doesn't crash, can save the Steam mod and the works will run fine (check up to the Main Menu screen)).
- However, if you apply the other macro "Disable Cheats", then check that it won't work (either HW crashes when you save the Steam mod, either the game crashes when you launch it afterward).
If both checks goes how I think, then I know why the stats panel bugs.
About field backgrounds, I've tried to adjust the alpha channel (despite it was adjusted according to the standard picture format, which is called DXT5 btw). I think it's a bit better now but it's still far from clean. I couldn't find why it's not the same as the in-game pictures, but that may be related to how they draw it. Each tile is actually, unlike for the PSX version, used for UV mapping and the background is rendered as a 3D model composed of planes one behind the others.
I think the next release will be a bug-fix for this stat panel thing. I will try to add a few more macros as well : if you have ideas, toss them at me !
Hold everything ! A new problem has just popped.
It seems that if you modify something in the "Items/Key Items" panels and export the mod to Steam, then the battle won't start properly in-game (either a black screen either you can see enemies with very few luminosity).
The saving/loading of .hws files seems to work fine still. Nothing's lost as long as you use that saving method.
Fixing that asap.
1. I just downloaded the latest version, 0.35, and whenever I choose to open a bin file, I get a message that hadesworkshop.exe has stopped working and it closes. I am on Windows 10 x64.
2. Is it possible to replace the in-game world map used for navigation using Hades Workshop? I mean the map that is shown when you press the [back] (xbox controller) button on the overworld areas.
The in-game map is horrendous. I can barely navigate with it because it is such low quality.
SetPartyReserve( 4095 ) // Adjust this argument if you want fewer people
SetCharacterData( 8, 1, 255, 22, 15 ) // Beatrix
SetCharacterData( 9, 1, 255, 21, 8 ) // Cinna
SetCharacterData( 10, 1, 255, 21, 10 ) // Marcus
SetCharacterData( 11, 1, 255, 21, 12 ) // Blank
SetName( 8, 75 ) // Rename Beatrix (shouldn't be important)
SetName( 9, 72 ) // Rename Cinna (or else he's called "Quina")
SetName( 10, 73 ) // Rename Marcus (or else he's called "Eiko")
SetName( 11, 74 ) // Rename Blank (or else he's called "Amarant")
You'd need to add that kind of script anywhere the party is somehow modified to make it persistant ; or use a similar script to revert the changes if you want Quina, Eiko or Amarant back in the team.Function Beatrix_Init
SetModel( 204, 100 )
CreateObject( 0, 0 )
TurnInstant( 0 )
SetStandAnimation( 8566 )
SetStandAnimation( 2978 )
SetWalkAnimation( 2975 )
SetRunAnimation( 2981 )
SetLeftAnimation( 2980 )
SetRightAnimation( 2974 )
SetJumpAnimation( 8566, 4, 23 )
SetObjectLogicalSize( 20, 20, 30 )
SetAnimationStandSpeed( 14, 16, 18, 20 )
SetHeadAngle( 104, 48 )
return
Function Cinna_Init
SetModel( 107, 87 )
CreateObject( 0, 0 )
TurnInstant( 0 )
SetStandAnimation( 9889 )
SetStandAnimation( 470 )
SetWalkAnimation( 761 )
SetRunAnimation( 105 )
SetLeftAnimation( 104 )
SetRightAnimation( 107 )
SetJumpAnimation( 9889, 5, 22 )
SetObjectLogicalSize( 20, 20, 30 )
SetAnimationStandSpeed( 14, 16, 18, 20 )
SetHeadAngle( 96, 61 )
return
Function MarcusA_Init
SetModel( 109, 100 )
CreateObject( 0, 0 )
TurnInstant( 0 )
SetStandAnimation( 12011 )
SetStandAnimation( 474 )
SetWalkAnimation( 367 )
SetRunAnimation( 365 )
SetLeftAnimation( 368 )
SetRightAnimation( 364 )
SetJumpAnimation( 12011, 9, 24 )
SetObjectLogicalSize( 20, 20, 30 )
SetAnimationStandSpeed( 14, 16, 18, 20 )
SetHeadAngle( 96, 61 )
return
Function Blank_Init
SetModel( 5467, 87 )
CreateObject( 0, 0 )
TurnInstant( 0 )
SetStandAnimation( 5041 )
SetStandAnimation( 462 )
SetWalkAnimation( 5225 )
SetRunAnimation( 5222 )
SetLeftAnimation( 5223 )
SetRightAnimation( 5224 )
SetJumpAnimation( 5041, 9, 25 )
SetObjectLogicalSize( 20, 20, 30 )
SetAnimationStandSpeed( 14, 16, 18, 20 )
SetHeadAngle( 96, 61 )
return
Function Main_Init
InitObject( 1, 128 )
InitObject( 2, 129 )
InitObject( 2, 130 )
return
Function Abomination_Init
return
Function Abomination_ATB
if ( GetRandom % 3 ) {
set SV_Target = RandomInTeam(SV_PlayerTeam)
Attack( 4 )
return
}
set SV_Target = SV_PlayerTeam
Attack( 5 )
return
AddItem( 236, 10 ) // Give 10 potions to the player
You remove the default starting items with these lines :RemoveItem( 236, 7 )
RemoveItem( 237, 2 )
RemoveItem( 238, 2 )
RemoveItem( 240, 2 )
RemoveItem( 247, 2 )
RemoveItem( 249, 1 )
RemoveItem( 253, 1 )
I think you can put these lines in the "Main_Init" function as it should run once at the start (I don't think it runs again after the Masked Man fight, but it should be checked).Function OldManOrSomething_SpeakBTN
// Keep the first few lines : a player can talk to a NPC only if he has the control
ifnot ( IsMovementEnabled ) {
return
}
set VAR_GlobBool_158 = 0
if ( VAR_GlobBool_159 == 1 ) {
DisableMove( )
if ( VAR_GlobBool_144 == 0 ) {
DisableMenu( )
} else {
Wait( 1 )
}
}
0x27( 127 )
WaitTurn( )
// Keep the following 3 lines if you want the NPC to face Zidane when he talks
set VAR_GlobUInt8_16 = GetEntryAngle(255)
TurnTowardObject( 250, 32 )
WaitTurn( )
// The following are the animation of the NPC while he talks
SetStandAnimation( XXX )
RunAnimation( XXX )
WindowSync( 0, 128, XXX ) // This line must be changed : choose your custom dialog here
// For dialogs with different choices, use "GetDialogChoice" to know the one chosen
if ( GetDialogChoice == 0 ) { // 0 is the first choice. Let's say the dialog is "Do you want to restart your stats? Yes/No"
if ( GetGil < 100 ) {
WindowSync( 0, 128, XXX ) // Not enough money
} else {
WindowSync( 0, 128, XXX ) // Which character?...
if ( GetDialogChoice < 8 ) { // Let's say the ninth choice is a "Cancel" choice
SetPartyReserve( 0 ) // Explained below
SetCharacterData( GetDialogChoice, 1, 255, 255, 255 ) // By using 255, you don't change the value
RemoveGil( 100 )
RunSoundCode3( 53248, 1045, 0, -128, 125 ) // Optional : play a sound. This one is the "buy something" sound
SetPartyReserve( 255 )
}
}
}
// Go back to a standard animation and turn back to its previous facing angle
WaitAnimation( )
SetStandAnimation( XXX )
RunAnimation( XXX )
set VAR_GlobBool_158 = 1
if ( VAR_GlobBool_159 == 1 ) {
if ( VAR_GlobBool_156 == 0 ) {
EnableMove( )
0x27( 255 )
if ( VAR_GlobBool_144 == 0 ) {
EnableMenu( )
}
}
}
TimedTurn( VAR_GlobUInt8_16, 16 )
WaitTurn( )
return
set VAR_B7_9 &= 127
set VAR_B7_10 = ( 71 | ( VAR_C6_372 << 4 ) )
if ( VAR_B3_1 >= 0 ) {
set VAR_B7_10 |= 8
}
while ( VAR_B7_9 < 128 ) {
RunSoundCode3( 53248, 1362, 0, -128, 125 )
EnableDialogChoices( VAR_B7_10, VAR_B7_9 )
WindowAsync( 2, 8, 3 )
Replace the line "set VAR_B7_10 = ( 71 | ( VAR_C6_372 << 4 ) )" by "set VAR_B7_10 = ( 103 | ( VAR_C6_372 << 4 ) )" to enable the debug choice. You can also replace it by "set VAR_B7_10 = 127" to enable all the choices (since the mogshop will be invalid, trying to use it in-game will bug though).Hi Aidolu ! Welcome back :D
Unfortunatly, while it is surely possible to do it, I don't know how... The MIPS code could certainly access to the AP and exp of the characters (in battle - it wouldn't be usable in menu anyway -), but it would require the expertise of a good person who does RAM analysis to find which sequences to use to retrieve these values.
There's a list of known fields in the MIPS help that you can access in the spell effect codes. There are HP, stats, trance gauge, level and activate supporting abilities, among others, but there's no exp nor AP (and I think it's not in the same structure so you wouldn't find them even by trying every possible figures).
In order to increase the level, that's this sequence :
lbu: $1 = $19[122] & 0xFF
addiu: $1 = $1 + 1
sb: $19[122] = $1 & 0xFF
However, I would bet that it would have only a twisted effect to directly change the level value :
1) Max HP/MP will most likely increase, but not the other stats (strength...),
2) The exp doesn't change so it will need more time to level up once again after that,
3) It may even be possible that the level gets reverted back to normal at the end of the battle. In this case, the only noticeable difference will be the effectiveness of spells like Lvl 5 death or so...
Sorry, I kind of deserted the PSX version for the Steam version now... Well, when something can be done for both, I do it (copy/paste the spells of enemies, for instance), but MIPS is just too related to the PSX version to get improved.
A reason why those filtering does happen is probably that a few parts of the backgrounds are in fact 3D objects and the games filtering (bilinear or trilinear) does affect these objects.
Nope, FFIX doesn't use any kind of 3D realtime models. Some 2D alpha effects like smoke is used but they not part of the static backgrounds and thus can't be filtered.
Hi Meru, are you creating all layers from scratch?Not sure what do you mean by "from scratch". You mean layer edges? Sometimes yes, sometimes no, but this doesn't matter. BTW the problem can be seen on some of your older screenshots of synthesist too.
The engine is really nitpicking on the Layers. Slight variations done to the background layers opposed to all other layers can yield very bad results like gray/black seams and/or the dot's you're mentioning.
Not sure what do you mean by "from scratch". You mean layer edges? Sometimes yes, sometimes no, but this doesn't matter. BTW the problem can be seen on some of your older screenshots of synthesist too.
Edit: of course for the final product all the layers must be redone. Leaving them as is and simply swapping backgrounds just makes things different kind of ugly from what it used to be with default backgrounds.
The dots are there because this is how HW creates textures. The problem is that these dots are outside of the range that must be shown on screen. I think that instead of trying to fix the engine, it is better mimic the way Silicon created textures. I dunno what the engine does there, nor I want to know, but these dots (and probably grid as well) look like a product of averaging with nearest pixels, like bilinear or better resampling or fxaa-style antialiasing (unlikely in this case since I think it works in screen-space only). When it happens that the nearest pixel is a black dot - sometimes we can see it on screen, when it happens to be imperfectly mirrored edge pixel - we see grid. The grid is very hard to spot if you deal with 64x64 tiles but quite easy with default ones.
Fraggoso
Heh, I was too focused on the problem we were discussing ^^
The templates you are talking about I am using of course, but only for now. They will have to be redone by hand at some point. Maybe with vector masks (https://i.imgur.com/zeeepfQ.png) maybe something else, not sure yet.
Speaking of layers, I am curious about different thing. For each of the moving objects in PSX version, HW creates only a single layer. This includes everything: doors, flags, water, clocks... how they were animated then? PSX engine was distorting and moving the layers in various ways? But for example that fan from a picture I posted above (that is on the disabled layers). You can not create all these layers by moving or distorting the fan on PSX layer.
Edit: in addition to that. It is known that all the moving objects and most of the scenes even were originally created in 3D by various artists. So instead of distorting a layer they should have made a few "shots", the same way we see in PC version? So does the HW output for PSX really complete?
I mean that in PC version animation is done by swapping layers at a right time. But in PSX, textures contain only a single layer, so there is nothing to swap. There are 2 possible outcomes. Whatever PSX engine generates extra frames on-the-fly based on that single layer, or HW's texture output is not complete.
Are you sure?I see. Now that you say it. It turns out to get a complete output I must check all the checkboxes 1st for that particular animation. Never bothered with that >__<
If I use HW to rip the psx tiles they're animated and are only tiles, so I suppose those are layers themself. But of course, I'm no technican. :/
I see. Now that you say it. It turns out to get a complete output I must check all the checkboxes 1st for that particular animation. Never bothered with that >__<
Open FFIX PSX -> Environment -> fields -> open synthesyst's "Manage" dialog and close it, switch to weapon shop (or possibly any field) then back to synthesyst -> crash.These exact steps crash it 100% of times.
@Fraggoso: yeah, i'll do some test to see if it can be modified easily. I'll probably need a FMV as well, not MBG (they may use a different FPS parameter). You're sure you can replace the FMV with .mp4 files? The normal format is .ogg for FF9 FMV.
@Meru: Yeah, all those tiny defects suck, but I gave up trying to fix them with hand-made twisted solutions. They'll surely go away once we change the engine to non-tiled backgrounds.
I'll think about making a .tmp file and rename it only if the process was successful (no error thrown).
ldarg.1
ldc.i4.s 10
div
add
ldloc.2
ldfld 0x4000885 // FF9LEVEL_BONUS::dex
ldc.i4.5
shr
add
Go to CIL Code, then search for "ff9level" in the list on the left, then "FF9Level_GetDex", then Edit Code.
Spot the following lines near the bottom of the code and remove them:Code: [Select]ldarg.1
ldc.i4.s 10
div
add
ldloc.2
ldfld 0x4000885 // FF9LEVEL_BONUS::dex
ldc.i4.5
shr
add
Then do the same for the "FF9Level_GetStr", "GetMgc" and "GetWpr". The codes are pretty similar and you always have to delete the lines between that "ldarg.1" and the second "add" below it.
With that, characters will keep their default stats whatever their level. Their max HP/MP still increase a bit ; see the "Party" -> "Stats" panel for that.
ldloc.2
ldfld 0x4000885 // FF9LEVEL_BONUS::dex
ldc.i4.5
shr
add
Why the heck the exclamation bubble got shifted?Icons are centered on a character. Be it one or two. So making one invisible does not remove the shift. One must hack the engine to take care of that =(
Well I don't mind the both bubbles to be honest, but as long as there maybe a solution on the horizon that's always welcome.
ldc.i4.2 // Replace this 2 by a 1
call 0x600091F // EIcon::PollFIcon
ldc.i4.1
stloc.0
That's near the middle of the method.ldc.i4.1
call 0x600091F // EIcon::PollFIcon
ldc.i4.1
stloc.0
ldc.i4.0
ret
Function Main_Init
set VAR_GlobBool_159 = 0
set VAR_GlobUInt8_17 = 255
set VAR_GenBool_191 = 0
if ( VAR_GenBool_184 == 1 ) {
set General_FieldEntrance = 10000
}
set VAR_GenBool_184 = 0
set VAR_GenInt16_9 = 65535
if ( VAR_GenUInt8_13 == 9 ) {
} else {
if ( ( VAR_GenUInt8_13 == 2 ) && ( VAR_GenInt16_9 < 0 ) ) {
set VAR_GenUInt8_13 = 9
} else {
if ( VAR_GenInt16_9 < 0 ) {
set VAR_GenUInt8_13 = 0
} else {
set VAR_GenUInt8_13 = 1
}
}
}
set VAR_GenInt16_11 = 65535
if ( VAR_GenUInt8_14 == 9 ) {
} else {
if ( ( VAR_GenUInt8_14 == 2 ) && ( VAR_GenInt16_11 < 0 ) ) {
set VAR_GenUInt8_14 = 9
} else {
if ( VAR_GenInt16_11 < 0 ) {
set VAR_GenUInt8_14 = 0
} else {
set VAR_GenUInt8_14 = 1
}
}
}
SetControlDirection( -10, 0 )
SetRandomBattleFrequency( 150 )
SetRandomBattles( 1, 915, 915, 915, 915 )
InitCode( 1, 0 )
InitCode( 2, 0 )
SetDialogProgression( 0 )
if ( General_ScenarioCounter < 8500 ) {
if ( General_ScenarioCounter <= 7060 ) {
set VAR_GlobInt16_30 = 308
}
if ( General_ScenarioCounter >= 7100 ) {
set VAR_GlobInt16_30 = 5
}
if ( General_ScenarioCounter >= 8000 ) {
set VAR_GlobInt16_30 = 305
}
if ( General_ScenarioCounter >= 8200 ) {
set VAR_GlobInt16_30 = 306
}
switchex 4 ( VAR_GlobInt16_30 ) {
case 308:
set VAR_GlobUInt8_24 = 1
InitObject( 14, 0 )
InitObject( 31, 0 )
InitObject( 13, 0 )
MoveCamera( 166, 190, 1, 8 )
break
case 5:
set VAR_GlobUInt8_24 = 0
InitObject( 25, 0 )
InitRegion( 17, 0 )
InitRegion( 18, 0 )
InitRegion( 19, 0 )
InitCode( 24, 0 )
break
case 305:
set VAR_GlobUInt8_24 = 10
InitObject( 27, 0 )
InitObject( 33, 0 )
InitObject( 28, 0 )
InitObject( 4, 0 )
InitObject( 5, 0 )
InitObject( 6, 0 )
InitObject( 7, 0 )
InitObject( 8, 0 )
InitObject( 9, 0 )
InitObject( 10, 0 )
InitObject( 11, 0 )
MoveCamera( 180, 180, 1, 8 )
ShowTile( 14, 0 )
ShowTile( 24, 0 )
break
case 306:
set VAR_GlobUInt8_24 = 24
InitObject( 27, 0 )
ShowTile( 14, 0 )
ShowTile( 24, 0 )
InitRegion( 22, 0 )
InitRegion( 23, 0 )
InitRegion( 21, 0 )
InitCode( 24, 0 )
SetFieldCamera( 1 )
SetControlDirection( -6, 0 )
RunSPSCode( 0, 130, -1, 0, 0 )
RunSPSCode( 1, 130, -1, 0, 0 )
RunSPSCode( 2, 130, -1, 0, 0 )
RunSPSCode( 3, 130, -1, 0, 0 )
RunSPSCode( 4, 130, -1, 0, 0 )
RunSPSCode( 5, 130, -1, 0, 0 )
RunSPSCode( 6, 130, -1, 0, 0 )
RunSPSCode( 7, 130, -1, 0, 0 )
RunSoundCode( 1792, 124 )
while ( SyncSounds != 0 ) {
Wait( 1 )
}
RunSoundCode1( 16903, 124, 31 )
RunSoundCode1( 16897, 124, 0 )
set VAR_GenUInt8_8 = 25
RunSoundCode2( 34305, 0, 180, VAR_GenUInt8_8 )
set VAR_GlobBool_167 = 0
break
}
} else {
if ( General_ScenarioCounter < 8600 ) {
set VAR_GlobUInt8_24 = 100
set General_FieldEntrance = 309
InitObject( 25, 0 )
InitObject( 15, 0 )
InitObject( 26, 0 )
InitObject( 29, 0 )
InitObject( 32, 0 )
InitObject( 16, 0 )
MoveCamera( 320, 224, 1, 8 )
RunSoundCode( 0, 98 )
while ( SyncSounds != 0 ) {
Wait( 1 )
}
set VAR_GenUInt8_8 = 125
RunSoundCode1( 16897, 98, VAR_GenUInt8_8 )
set VAR_GlobBool_167 = 0
} else {
set VAR_GlobUInt8_24 = 0
InitObject( 25, 0 )
RunSoundCode( 0, 98 )
while ( SyncSounds != 0 ) {
Wait( 1 )
}
set VAR_GenUInt8_8 = 125
RunSoundCode1( 16897, 98, VAR_GenUInt8_8 )
set VAR_GlobBool_167 = 0
}
InitRegion( 20, 0 )
InitRegion( 18, 0 )
InitRegion( 19, 0 )
InitCode( 24, 0 )
}
if ( General_ScenarioCounter >= 8000 ) {
ShowTile( 14, 0 )
ShowTile( 24, 0 )
}
if ( VAR_GlobBool_158 == 0 ) {
0x27( 127 )
} else {
0x27( 255 )
}
Wait( 2 )
Wait( 2 )
if ( VAR_GenUInt8_13 == 9 ) {
SetTextVariable( 2, 0 )
WindowAsync( 6, 0, 56 )
RaiseWindows( )
WaitWindow( 6 )
set VAR_GenUInt8_13 = 0
}
if ( VAR_GenUInt8_14 == 9 ) {
SetTextVariable( 2, 1 )
WindowAsync( 6, 0, 56 )
RaiseWindows( )
WaitWindow( 6 )
set VAR_GenUInt8_14 = 0
}
set VAR_GlobBool_159 = 1
if ( VAR_GlobBool_158 == 1 ) {
set VAR_GlobBool_158 = 1
if ( VAR_GlobBool_159 == 1 ) {
if ( VAR_GlobBool_156 == 0 ) {
EnableMove( )
0x27( 255 )
if ( VAR_GlobBool_144 == 0 ) {
EnableMenu( )
}
}
}
}
if ( VAR_GlobUInt8_17 == 255 ) {
set Op66(( GetData_12 - 160 ), ( GetData_13 - 112 ))
}
0xA9( 250 )
FadeFilter( 7, 16, VAR_GlobUInt8_17, 0, 0, 0 )
return
[/CODE}
Okay, if you're certain I asked you this question the first time, PLEASE link me where I said that, cause I can't find it.If that makes you happier...
But I know of a fact I did not ask such before; just lying so you don't have to help me with your tool?
Oh Jesus here we go again huh?
I just gave you a nice advice. If you don't care that's you problem.
If that makes you happier...
http://steamcommunity.com/app/377840/discussions/0/353915953249510749/?ctp=20#c133258593400587717
You're lucky though, I found the file where you can determine which music plays for which battle a few days ago. It's the files "BtlEncountBgmMetaData.txt" and "WldBtlEncountBgmMetaData.txt" that are in the resources.assets.
For each field, there's a list of the ID of the battles that are used in this field and the ID of the music that plays for it. If a battle is not preset, the music doesn't change. I didn't test anything though, just guesses.
And yes, I'm not at home and I have less time than usual for FF9 related things.
I worked on a partial model converter. With the next release, you will be able to export the models as .obj (Wavefront) format.
public static int FF9Level_GetCap(int slot_id, int lv, bool lvup) {
PLAYER pLAYER = FF9StateSystem.Common.FF9.player[slot_id];
FF9LEVEL_BONUS bonus = pLAYER.bonus;
FF9LEVEL_BASE fF9LEVEL_BASE = ff9level._FF9Level_Base[ff9play.FF9Play_GetCharID((int)pLAYER.info.menu_type)];
if (lvup) {
int num = (pLAYER.cur.capa != 0) ? 0 : 5;
int num2 = 0;
FF9LEVEL_BONUS expr_53 = bonus;
expr_53.cap += (ushort)(num + num2);
}
int num3 = (int)fF9LEVEL_BASE.cap + lv * 4 / 10 + (bonus.cap >> 5);
if (num3 > 99) {
num3 = 99;
}
return num3;
}
In term of CIL Code, the main operation ("int num3 = ...") is those lines:ldloc.3 // fF9LEVEL_BASE
ldfld 0x4000890 // FF9LEVEL_BASE::cap
ldarg.1 // lv
ldc.i4.4 // Multiply by 4
mul
ldc.i4.s 10 // Divide by 10
div
add
ldloc.2 // bonus
ldfld 0x400088B // FF9LEVEL_BONUS::cap
ldc.i4.5 // Right-shift by 5 ( = Divide by 32)
shr
add
stloc.0
I have no idea of where the font used is defined.
I'll ask Albeoris.Yes, do that. Now that I think of it, I think that Memoria can already change the text font.
Function Zidane_Reinit
RunSoundCode( 4616, 914 )
RunSoundCode( 4616, 923 )
RunModelCode( 16, 25, 4, 914 )
RunModelCode( 17, 25, 4, 923 )
RunModelCode( 18, 25, 4, 1 )
RunSoundCode( 4616, 914 )
RunSoundCode( 4616, 923 )
RunModelCode( 16, 25, 13, 914 )
RunModelCode( 17, 25, 13, 923 )
RunModelCode( 18, 25, 13, 1 )
RunSoundCode( 4616, 914 )
RunSoundCode( 4616, 923 )
RunModelCode( 16, 38, 0, 914 )
RunModelCode( 17, 38, 0, 923 )
RunModelCode( 18, 38, 0, 1 )
RunSoundCode( 4616, 914 )
RunSoundCode( 4616, 923 )
RunModelCode( 16, 38, 8, 914 )
RunModelCode( 17, 38, 8, 923 )
RunModelCode( 18, 38, 8, 1 )
return
However, the sound IDs change from field to field (as the footstep sound changes). Check out the "Zidane_Init" function to get those.@livegood118: The Assembly-CSharp.dll is important for Vir's mod. I'll take a look at it.
However, you'd only need to import 1 file, not 4.
at HonoBehaviorSystem.Update () [0x00000] in <filename unknown>:0
(Filename: Line: -1)
InvalidProgramException: Invalid IL code in EndingMain:HonoUpdate (): IL_009c: stfld 0x0400179d