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
ldarg.1
ldind.ref
ldarg.1
ldind.ref
ldfld 0x40008AB // FF9PLAY_SKILL::max_hp
ldarg.1
ldind.ref
ldfld 0x40008AB // FF9PLAY_SKILL::max_hp
ldc.i4.s 10
div
add
conv.u2
stfld 0x40008AB // FF9PLAY_SKILL::max_hp
There is a similar code 4 times in a row, for HP+10%/20% and then for MP+10%/20%.ldc.i4.s 10
div
// Replace it by:
ldc.i4.s 80
mul
ldc.i4.s 100
div
This changes it into +80%Function Zorn_CounterEx
if ( GetAttacker == SV_FunctionEnemy ) {
if ( GetAttackId == 7 ) {
set SV_FunctionEnemy[PREVENT_ATTACK] =$ 1
}
return
}
if ( GetAttacker == thorn ) {
if ( ( GetAttackId == 13 ) || ( GetAttackId == 14 ) ) {
set zorn[PREVENT_ATTACK] =$ 1
set thorn[PREVENT_ATTACK] =$ 1
set SV_FunctionEnemy[ATB] =$ 0
set zornpoweron = 3 // HERE: setup the number of attacks required to cancel the spell
}
return
}
if ( #( SV_FunctionEnemy[HP] <$ hp ) ) {
set hp = FirstOf(SV_FunctionEnemy[HP])
if ( ( GetAttackCommandId == 18 ) || ( ( GetAttackCommandId == 27 ) && ( GetAttackId == 122 ) ) ) {
return
}
} else {
set hp = FirstOf(SV_FunctionEnemy[HP])
return
}
if ( zornpoweron ) {
set zornpoweron-- // HERE: decrease the counter instead of directly set it to 0
if ( zornpoweron==0 ) {
BattleDialog( 24 )
}
}
set SV_FunctionEnemy[STAND_ANIMATION] =$ 0
set SV_FunctionEnemy[PREVENT_ATTACK] =$ 1
return
And in the counter: case +2:
if ( zornpoweron ) {
set zornpoweron--
if ( zornpoweron==0 ) {
BattleDialog( 24 )
set SV_FunctionEnemy[STAND_ANIMATION] =$ 0
set SV_FunctionEnemy[PREVENT_ATTACK] =$ 1
}
} else {
set SV_FunctionEnemy[STAND_ANIMATION] =$ 0
set SV_FunctionEnemy[PREVENT_ATTACK] =$ 1
}
return
case +3:
if ( zornpoweron ) {
set zornpoweron--
if ( zornpoweron==0 ) {
BattleDialog( 24 )
set SV_FunctionEnemy[STAND_ANIMATION] =$ 0
set SV_FunctionEnemy[PREVENT_ATTACK] =$ 1
}
} else {
set SV_FunctionEnemy[STAND_ANIMATION] =$ 0
set SV_FunctionEnemy[PREVENT_ATTACK] =$ 1
}
if ( ( !zornpoweron ) && ( !thornpoweron ) ) {
set #( SV_Target = thorn )
Attack( 6 )
set waitingpowerthorn = 1
}
UInt8 -> contains a value between 0 and 255
UInt16 -> contains a value between 0 and 65535
UInt24 -> contains a value between 0 and 16777215
Int8 -> contains a value between -128 and 127
Int16 -> contains a value between -32768 and 32767
Int24 -> contains a value between -8388608 and 8388607
Bool -> contains 0 or 1
The more the max value is, the more the variable takes of memory in the RAM. The following infos are important when you declare variables or use new variables in the script:Thanks for the quick reply, it starts to make more sense now. So "GetRandom & 3" is basically like "GetRandom & 1" and "GetRandom & 2" in succession, resulting in 75% chance total (two 50% chances).
And for example, "GetRandom & 7" would then be like "GetRandom & 1" plus "GetRandom & 2" plus "GetRandom & 4", resulting in 3 x 50% chances = 87,5% final chance, right?
I'm gonna read that wikipedia page thoroughly sometime, I guess it'll be really helpful to non-programmers like me.
Function -> Attack and AttackSpecial
Function -> RunBattleCode
Function -> BattleDialog
Variable -> SV_EnemyTeam, SV_PlayerTeam, SV_FunctionEnemy and SV_Target
Variable -> GetAttacker, GetTarget, IsAttacking, GetAttackId, GetAttackElement, etc...
Variable -> GetBattleState
Var Code -> RandomInTeam
Var Code -> [DATA_ACCESS]
Hi elberuss,
You're not the first one to tell me that, but that's very strange... I have no problem at all changing enemy stats.
Are you sure you replace the files p0data2.bin and p0data7.bin after saving Steam Mod? And you replace the game's files by them?
Which enemies do you try to modify?
if ( (#( SV_FunctionEnemy[HP] <=$ 10000 )) && ( VAR_LocUInt8_60 <= 5 ) ) {
set VAR_LocUInt8_60++
set SV_FunctionEnemy[HP] =$ FirstOf(SV_FunctionEnemy[MAX_HP])
}
Sorry, the operator's parser is totally dumb (it has no concern for the operation's priorities). It will be fixed eventually but until then, you'll need to write a lot of parentheses.
}
if ( ( ( VAR_GenUInt16_19 >> 0 ) & 1 ) == 0 ) {
SetCharacterData( 0, 1, 255, 9, 0 )
set VAR_GenUInt16_19 |= 1
}
if ( ( ( VAR_GenUInt16_19 >> 2 ) & 1 ) == 0 ) {
SetCharacterData( 2, 1, 255, 6, 2 )
set VAR_GenUInt16_19 |= 4
}
if ( ( ( VAR_GenUInt16_19 >> 1 ) & 1 ) == 0 ) {
SetCharacterData( 1, 1, 255, 5, 1 )
set VAR_GenUInt16_19 |= 2
}
if ( ( ( VAR_GenUInt16_19 >> 6 ) & 1 ) == 0 ) {
SetCharacterData( 6, 1, 255, 6, 6 )
set VAR_GenUInt16_19 |= 64
}
if ( ( ( VAR_GenUInt16_19 >> 7 ) & 1 ) == 0 ) {
SetCharacterData( 7, 1, 7, 5, 7 )
set VAR_GenUInt16_19 |= 128
SetRow( 7, 1 )
}
It's much better to wait for a Memoria-HW compatibility than re-inventing the wheel twice.
Meh I just want vanilla FFIX
•No chat icons
•Increased encounter rate
•Disabled cheats
•Sound frequency fix
•Change font
•Sound fixes to certain sounds
•Disable autosaves
•Resize the battle UI
I wish I wouldn't have to wait for these replies from your master programmers.
>>>For just the sounds fix, replace files p0data62.bin + p0data63.bin. Just don't use the original p0data61.bin file with this, it won't make any sense.
Yeah your mod is more about enhancing the look and feel of the game, turn it into something new and fresh.is that what he thinks?
// "flag 1" states that the spell will modify the HP (of "ct" = caster, here). Setting both flags 1 and 2 can be used for healing
v.ct_flags |= 1;
// The damage is based on caster's max hp. The operation ">> 3" is equivalent to "/ 8"
v.ct_hp = (short)(v.caster.max.hp >> 3);
But you can't write C# scripts with HW (that's where the Memoria tool is more convenient), so you need to use a CIL code counterpart:ldarg.0
dup
ldfld 0x40007F6 // CALC_VAR::ct_flags
ldc.i4.1
or
conv.u1
stfld 0x40007F6 // CALC_VAR::ct_flags
ldarg.0
ldarg.0
ldfld 0x40007EC // CALC_VAR::caster
ldfld 0x4000229 // BTL_DATA::max
ldfld 0x4000809 // POINTS::hp
ldc.i4.3
shr
conv.i2
stfld 0x40007F8 // CALC_VAR::ct_hp
"ldarg.0" is the object of type CALC_VAR that contains all the information about the damage calculation. It was called "v" in the C# above.ldarg.0
ldfld 0x40007F0 // CALC_VAR::at_pow
ldarg.0
ldfld 0x40007F1 // CALC_VAR::df_pow
If the 0x..... numbers are different, you need to update your game beforehand (in Steam, "FF9 -> properties -> Verify the integrity of local game file").if (v.caster.bi.slot_no == 3) {
// Do you stuff
}
In CIL:IL_POS0: ldarg.0
IL_POS1: ldfld 0x40007EC // CALC_VAR::caster
IL_POS2: ldfld 0x400022D // BTL_DATA::bi
IL_POS3: ldfld 0x4000272 // BTL_INFO::slot_no
IL_POS4: ldc.i4.3
IL_POS5: bne.un IL_POSEND
// Do your stuff
IL_POSEND: // After the "if" block
ldarg.0
ldfld 0x40007EC // CALC_VAR::caster
ldfld 0x400022D // BTL_DATA::bi
ldfld 0x4000272 // BTL_INFO::slot_no
ldc.i4.3
bne.un IL_003E
ldarg.0
dup
ldfld 0x40007F6 // CALC_VAR::ct_flags
ldc.i4.1
or
conv.u1
stfld 0x40007F6 // CALC_VAR::ct_flags
ldarg.0
ldarg.0
ldfld 0x40007EC // CALC_VAR::caster
ldfld 0x4000229 // BTL_DATA::max
ldfld 0x4000809 // POINTS::hp
ldc.i4.3
shr
conv.i2
stfld 0x40007F8 // CALC_VAR::ct_hp
ldarg.0
ldfld 0x40007F0 // CALC_VAR::at_pow
ldarg.0
ldfld 0x40007F1 // CALC_VAR::df_pow
sub
dup
stloc.1
ldc.i4.0
bgt IL_0055
ldc.i4.1
stloc.1
ldarg.0
dup
ldfld 0x40007F7 // CALC_VAR::tg_flags
ldc.i4.1
or
conv.u1
stfld 0x40007F7 // CALC_VAR::tg_flags
ldarg.0
ldfld 0x40007F3 // CALC_VAR::at_num
ldc.i4.1
bge IL_0077
ldarg.0
ldc.i4.1
stfld 0x40007F3 // CALC_VAR::at_num
ldloc.1
ldarg.0
ldfld 0x40007F3 // CALC_VAR::at_num
mul
stloc.0
ldarg.0
ldfld 0x40007EE // CALC_VAR::cmd
ldfld 0x400028B // CMD_DATA::info
ldfld 0x4000293 // SELECT_INFO::short_summon
brfalse IL_009B
ldloc.0
ldc.i4.2
mul
ldc.i4.3
div
stloc.0
ldloc.0
ldc.i4 9999
ble IL_00AC
ldc.i4 9999
stloc.0
ldarg.0
ldfld 0x40007F5 // CALC_VAR::flags
ldc.i4.8
and
brfalse IL_00C8
ldarg.0
dup
ldfld 0x40007F7 // CALC_VAR::tg_flags
ldc.i4.2
or
conv.u1
stfld 0x40007F7 // CALC_VAR::tg_flags
ldarg.0
ldloc.0
conv.i2
stfld 0x40007F9 // CALC_VAR::tg_hp
ret
(If you copy-paste it, verify that the "IL_POS" numbers are correct: the program tends to update them automatically and not always the right way.)Lein, as it was already said, you can't expect everyone to have the same priorities as you. Besides, modding is something that requires time.
I told you that increasing the encounter rate back to normal means understanding what was changed in the Steam version. Those figures that you increased in the fields' scripts are exactly the same between Steam and PSX: if you want to have an encounter rate consistent and balanced as in PSX, that's not what needs to be fixed. If you want a quick and dirty fix, then you're done.
And yes, keeping repeating a few bullets is not going to make those go faster.
No comment about the trendy "autist" insult... That is a very dumb one.
set #( SV_Target = SV_FunctionEnemy ) // i set the target
AttackSpecial( 3 ) // atack
while ( IsAttacking != 0 ) {
Wait( 1 )
}
RunBattleCode( 35, 0 ) // continue battle
while ( GetBattleState != 4 ) {
Wait( 1 )
}
@sutebenukun: Hey, glad to see you enjoy it and want to personalize it :)
Unfortunatly, it is not convenient to modify the spell effects, and you can't go very far. It's in the CIL Code, more precisely the class "btl_calc".
Hades Workshop's CIL Code is quite buggy: it sometimes crashes if the edited methods are too big. It seems that you can't edit the main method related to spell effects ("CalcMain") without crash. You can however edit the sub-methods and put the HP cost in them.
For instance, the spell effect "Physical Strike" use the sub-method "CalcSub_203", which setups the damage for its target. What you can do is adding a script there that removes HP to the caster only if the caster is Steiner.
The C# script for removing HP to the caster is something like this:Code: [Select]// "flag 1" states that the spell will modify the HP (of "ct" = caster, here). Setting both flags 1 and 2 can be used for healing
But you can't write C# scripts with HW (that's where the Memoria tool is more convenient), so you need to use a CIL code counterpart:
v.ct_flags |= 1;
// The damage is based on caster's max hp. The operation ">> 3" is equivalent to "/ 8"
v.ct_hp = (short)(v.caster.max.hp >> 3);Code: [Select]ldarg.0
"ldarg.0" is the object of type CALC_VAR that contains all the information about the damage calculation. It was called "v" in the C# above.
dup
ldfld 0x40007F6 // CALC_VAR::ct_flags
ldc.i4.1
or
conv.u1
stfld 0x40007F6 // CALC_VAR::ct_flags
ldarg.0
ldarg.0
ldfld 0x40007EC // CALC_VAR::caster
ldfld 0x4000229 // BTL_DATA::max
ldfld 0x4000809 // POINTS::hp
ldc.i4.3
shr
conv.i2
stfld 0x40007F8 // CALC_VAR::ct_hp
Now, if I am telling you about C# code, it's because it is much more easy to read (even though it's still a programing language), and you can see here the whole class of "btl_calc" in C#:
https://www.dropbox.com/s/2k2mkezqx0loe4i/Source_BtlCalc.cs?dl=0
I added a few comments and renamed the methods "CalcSub" with less opaque names there.
The CIL script above can be used to remove HP to the caster in one of those "CalcSub" method. Verify that the hexadecimal IDs are the same with your game, which should be the case if it's up-to-date. For instance, the non-edited method "CalcSub_203" should start like this:Code: [Select]ldarg.0
If the 0x..... numbers are different, you need to update your game beforehand (in Steam, "FF9 -> properties -> Verify the integrity of local game file").
ldfld 0x40007F0 // CALC_VAR::at_pow
ldarg.0
ldfld 0x40007F1 // CALC_VAR::df_pow
Now, we need to add the information that only Steiner's attack should remove HP to him (he's not the only one to cast spells using that "CalcSub_203" method). You can do it like that:Code: [Select]if (v.caster.bi.slot_no == 3) {
In CIL:
// Do you stuff
}Code: [Select]IL_POS0: ldarg.0
IL_POS1: ldfld 0x40007EC // CALC_VAR::caster
IL_POS2: ldfld 0x400022D // BTL_DATA::bi
IL_POS3: ldfld 0x4000272 // BTL_INFO::slot_no
IL_POS4: ldc.i4.3
IL_POS5: bne.un IL_POSEND
// Do your stuff
IL_POSEND: // After the "if" block
If we put that together at the start of the method "CalcSub_203", we end up with a method like this:Code: [Select]ldarg.0
(If you copy-paste it, verify that the "IL_POS" numbers are correct: the program tends to update them automatically and not always the right way.)
ldfld 0x40007EC // CALC_VAR::caster
ldfld 0x400022D // BTL_DATA::bi
ldfld 0x4000272 // BTL_INFO::slot_no
ldc.i4.3
bne.un IL_003E
ldarg.0
dup
ldfld 0x40007F6 // CALC_VAR::ct_flags
ldc.i4.1
or
conv.u1
stfld 0x40007F6 // CALC_VAR::ct_flags
ldarg.0
ldarg.0
ldfld 0x40007EC // CALC_VAR::caster
ldfld 0x4000229 // BTL_DATA::max
ldfld 0x4000809 // POINTS::hp
ldc.i4.3
shr
conv.i2
stfld 0x40007F8 // CALC_VAR::ct_hp
ldarg.0
ldfld 0x40007F0 // CALC_VAR::at_pow
ldarg.0
ldfld 0x40007F1 // CALC_VAR::df_pow
sub
dup
stloc.1
ldc.i4.0
bgt IL_0055
ldc.i4.1
stloc.1
ldarg.0
dup
ldfld 0x40007F7 // CALC_VAR::tg_flags
ldc.i4.1
or
conv.u1
stfld 0x40007F7 // CALC_VAR::tg_flags
ldarg.0
ldfld 0x40007F3 // CALC_VAR::at_num
ldc.i4.1
bge IL_0077
ldarg.0
ldc.i4.1
stfld 0x40007F3 // CALC_VAR::at_num
ldloc.1
ldarg.0
ldfld 0x40007F3 // CALC_VAR::at_num
mul
stloc.0
ldarg.0
ldfld 0x40007EE // CALC_VAR::cmd
ldfld 0x400028B // CMD_DATA::info
ldfld 0x4000293 // SELECT_INFO::short_summon
brfalse IL_009B
ldloc.0
ldc.i4.2
mul
ldc.i4.3
div
stloc.0
ldloc.0
ldc.i4 9999
ble IL_00AC
ldc.i4 9999
stloc.0
ldarg.0
ldfld 0x40007F5 // CALC_VAR::flags
ldc.i4.8
and
brfalse IL_00C8
ldarg.0
dup
ldfld 0x40007F7 // CALC_VAR::tg_flags
ldc.i4.2
or
conv.u1
stfld 0x40007F7 // CALC_VAR::tg_flags
ldarg.0
ldloc.0
conv.i2
stfld 0x40007F9 // CALC_VAR::tg_hp
ret
I tested and it worked wonder for me.
Now you need to do the same thing for other "CalcSub" methods so that it doesn't apply only to damaging spells.
Modifying the engine is the most tedious feature of HW, sorry. I hope it helped you though ^^"
@dclem and Lein: Maybe you can just stop arguing? You both said that you were over with the other and kept posting just to have the final word... that's ridiculous.
Lein, as it was already said, you can't expect everyone to have the same priorities as you. Besides, modding is something that requires time.
I told you that increasing the encounter rate back to normal means understanding what was changed in the Steam version. Those figures that you increased in the fields' scripts are exactly the same between Steam and PSX: if you want to have an encounter rate consistent and balanced as in PSX, that's not what needs to be fixed. If you want a quick and dirty fix, then you're done.
And yes, keeping repeating a few bullets is not going to make those go faster.
No comment about the trendy "autist" insult... That is a very dumb one.
Function Sagnar_Loop
if ( !VAR_LocUInt8_30 ) {
set VAR_LocUInt8_30 = 1
while ( !( GetBattleLoadState & 8 ) ) {
Wait( 1 )
set VAR_GenUInt8_206 = GetRandom
}
set VAR_LocUInt16_33 = FirstOf(SV_FunctionEnemy[HP])
set SV_FunctionEnemy[MODEL_SIZE] =$ 6144
while ( !( GetBattleLoadState & 16 ) ) {
Wait( 1 )
set VAR_GenUInt8_206 = GetRandom
}
set #( VAR_GlobUInt16_24 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 0 ) )
set #( VAR_GlobUInt16_24 |= ( SV_PlayerTeam[MODEL_TYPE] ==$ 1 ) )
set #( VAR_GlobUInt16_26 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 2 ) )
set #( VAR_GlobUInt16_28 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 3 ) )
set #( VAR_GlobUInt16_28 |= ( SV_PlayerTeam[MODEL_TYPE] ==$ 4 ) )
set #( VAR_GlobUInt16_28 |= ( SV_PlayerTeam[MODEL_TYPE] ==$ 5 ) )
set #( VAR_GlobUInt16_28 |= ( SV_PlayerTeam[MODEL_TYPE] ==$ 6 ) )
set #( VAR_GlobUInt16_30 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 7 ) )
set #( VAR_GlobUInt16_30 |= ( SV_PlayerTeam[MODEL_TYPE] ==$ 8 ) )
set #( VAR_GlobUInt16_32 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 9 ) )
set #( VAR_GlobUInt16_34 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 10 ) )
set #( VAR_GlobUInt16_34 |= ( SV_PlayerTeam[MODEL_TYPE] ==$ 11 ) )
set #( VAR_GlobUInt16_36 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 12 ) )
set #( VAR_GlobUInt16_38 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 13 ) )
set #( VAR_GlobUInt16_40 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 15 ) )
set #( VAR_GlobUInt16_42 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 16 ) )
set #( VAR_GlobUInt16_42 |= ( SV_PlayerTeam[MODEL_TYPE] ==$ 17 ) )
set #( VAR_GlobUInt16_44 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 18 ) )
while ( GetBattleState != 4 ) {
Wait( 1 )
}
}
if ( #( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 4355) & VAR_GlobUInt16_24 ) ) {
set VARL_GenBool_2655 = 0
} else {
set VARL_GenBool_2655 = 1
}
if ( #( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 4355) & VAR_GlobUInt16_36 ) ) {
set VARL_GenBool_2648 = 0
} else {
set VARL_GenBool_2648 = 1
}
if ( #( SV_FunctionEnemy[HP] <=$ 10650 ) ) {
BattleDialog( 6 )
}
if ( #( SV_FunctionEnemy[HP] <=$ 10000 ) ) {
set SV_FunctionEnemy[HP] =$ 0
return
}
Wait( 1 )
loop
@sutebenukun: You access to the CIL Code using Hades Workshop, there's a panel "CIL Code", the list of classes (including "btl_calc") is on the left and the classes' methods ("CalcMain", "CalcSub_203", etc...) appear next to it once you selected a class.
You may also see the C# and CIL code using programs like JetBrains dotPeck, but it can only display it, not modify it. I don't know any free tool that allows to inject CIL code in a dll.
Oh?
Either it's a bug, either you don't have the latest version of the tool. I hope it's the latter ^^
You can see the version in the "About" window (F1). If it's not v0.37c, get the newest version in the opening post of the thread.
If it is v0.37c, then I guess it's a bug. Maybe try to open only the Steam version? (You have to select the FF9_Launcher.exe.)
Hum...
I couldn't successfully add a trance to Beatrix ; you need at least two things for that:
1) Making this character a permanent party member, that is removing the flag "temporary character" in the "SetCharacterData" call (in fields scripts),
2) Add a trance model to the list of character models, in the CIL "btl_init::..ctor" method.
With that, however, the trance gauge appears and fills correctly, but the game freezes once it's fully filled. So there has to be something else that I didn't spot :/
Also, the "temporary character" flag determines whether the game will use the temporary character or the permanent counterpart (Marcus/Eiko for instance). So for adding trance to Marcus, Blank or Cina, it would also require something else (maybe changing the condition (1) for the trance bar to appear).
Reading your talk I thought of a mod that might be worth doing in the future, imagine replacing all the silly characters that are over the top, for example Eiko and Quina with characters that are a bit more mature. Maybe the summoner in the ruined village could be garnet's older sister, or maybe an old granny. Quina could be replaced by some character that isn't so fat, maybe some muscular wild man.
The modeling and animation wouldn't be difficult to do, what might be difficult is to remake entire cutscenes, thinking specifically of the love letter event in Alexandria. Just throwing this out there, because if Final Fantasy is suffering from anything it's silly characters.
Hum...
I couldn't successfully add a trance to Beatrix ; you need at least two things for that:
1) Making this character a permanent party member, that is removing the flag "temporary character" in the "SetCharacterData" call (in fields scripts),
2) Add a trance model to the list of character models, in the CIL "btl_init::..ctor" method.
With that, however, the trance gauge appears and fills correctly, but the game freezes once it's fully filled. So there has to be something else that I didn't spot :/
Also, the "temporary character" flag determines whether the game will use the temporary character or the permanent counterpart (Marcus/Eiko for instance). So for adding trance to Marcus, Blank or Cina, it would also require something else (maybe changing the condition (1) for the trance bar to appear).
Interesting. I was wondering about adding trance to "guest" characters. I bet there's an animation call that it's missing when you activate trance and that's why it freezes, just a hunch. I haven't looked at this games data too hard yet.
Would it be possible to switch the character the temporary characters are tied to? I like Eiko, but I also want to use Marcus. Can I place him over someone else instead? Better yet, can we add character slots? I know Beatrix is a special case and seems to actually have her own slot, so I'm sure it would be complicated.
Has anyone tried to swap assets such as Zidane with his Pluto Knight gear, or Garnet with her dress or whitemage hood?
Lastly, is there something I can use to preview .fbx models?
Enemies on the world map is used from battle spots; but Tirltiti said it was buggy, (and it's not fixed in this current version, it doesn't work if you change it).
In the field, battle 'spawns' are handled in the SetRandomBattleFrequency~set enemies battles for that field. 1-4.
Problem signature:
Problem Event Name: APPCRASH
Application Name: HadesWorkshop.exe
Application Version: 0.0.0.0
Application Timestamp: 58ee662c
Fault Module Name: HadesWorkshop.exe
Fault Module Version: 0.0.0.0
Fault Module Timestamp: 58ee662c
Exception Code: c00000fd
Exception Offset: 029ccb53
OS Version: 6.3.9600.2.0.0.256.49
Locale ID: 1033
Additional Information 1: e860
Additional Information 2: e86090bc8c91ffd3c86d18fa8cdf1f70
Additional Information 3: de7f
Additional Information 4: de7f9705878d75421aa697c1b4f19d18
You need to open the launcher not the bin files.
struct FieldWalkmeshDataStruct : public ChunkChild {
public:
uint32_t magic_walkmesh;
int16_t unknown1;
int16_t offset_x2;
int16_t offset_z2;
int16_t offset_y2;
int16_t offset_x;
int16_t offset_z;
int16_t offset_y;
int16_t offset_x3;
int16_t offset_z3;
int16_t offset_y3;
int16_t unknown4;
int16_t unknown5;
int16_t unknown6;
int16_t unknown7;
int16_t unknown8;
int16_t unknown9;
int16_t active_walkpath;
int16_t active_triangle;
uint16_t triangle_amount;
uint16_t triangle_offset;
uint16_t edge_amount;
uint16_t edge_offset;
uint16_t animation_amount;
uint16_t animation_offset;
uint16_t walkpath_amount;
uint16_t walkpath_offset;
uint16_t normal_amount;
uint16_t normal_offset;
uint16_t vertex_amount;
uint16_t vertex_offset;
// As many as "triangle_amount"
uint8_t* triangle_unk1;
uint8_t* triangle_stepsound;
uint16_t* triangle_unk2;
uint16_t* triangle_walkpath;
uint16_t* triangle_normal;
uint16_t* triangle_unk4;
uint16_t* triangle_unk5;
uint16_t* triangle_vertex1;
uint16_t* triangle_vertex2;
uint16_t* triangle_vertex3;
uint16_t* triangle_edge1;
uint16_t* triangle_edge2;
uint16_t* triangle_edge3;
uint16_t* triangle_adjacenttriangle1;
uint16_t* triangle_adjacenttriangle2;
uint16_t* triangle_adjacenttriangle3;
int16_t* triangle_centerx;
int16_t* triangle_centerz;
int16_t* triangle_centery;
uint16_t* triangle_unk9;
uint16_t* triangle_unk10;
// As many as "edge_amount"
uint16_t* edge_flag;
int16_t* edge_clone;
// As many as "animation_amount"
uint16_t* animation_flag;
uint16_t* animation_frameamount;
int16_t* animation_framerate;
uint16_t* animation_counter;
int32_t* animation_currentframe;
uint32_t* animation_frameoffset;
// As many as "walkpath_amount"
uint16_t* walkpath_unk1;
uint16_t* walkpath_unk2;
int16_t* walkpath_minx;
int16_t* walkpath_minz;
int16_t* walkpath_miny;
int16_t* walkpath_offsetx;
int16_t* walkpath_offsetz;
int16_t* walkpath_offsety;
int16_t* walkpath_unkx3;
int16_t* walkpath_unkz3;
int16_t* walkpath_unky3;
int16_t* walkpath_unkx4;
int16_t* walkpath_unkz4;
int16_t* walkpath_unky4;
uint16_t* walkpath_triangleamount;
uint16_t* walkpath_trianglelistoffset;
uint32_t** walkpath_trianglelist;
// As many as "normal_amount"
int32_t* normal_x;
int32_t* normal_z;
int32_t* normal_y;
int32_t* normal_overz;
// As many as "vertex_amount"
int16_t* vertex_x;
int16_t* vertex_z;
int16_t* vertex_y;
}
Walkmesh contains a few informations about "how the objects behave" on each triangles. For instance, there is a data about which kind of step sound should be used when walking on it, or whether it is in the shade or not.
Also, each triangle has specified neighborood to let the characters moving from one triangle to another. Most of the time, that can be computed automatically from the mesh (if there is a common edge or not), but you may want to not make some connections, or on the contrary add connection between distant triangles to make kind of teleporters (though that could be better done by script).
Hiya!I believe its possible given the other changes and mods that have been done using this program, but there is no readme's at the moment to explain things.
I have a question. I've been using your Alternate Fantasy mod and I'm very happy with it! The only thing is after beating the game once (with Beatrix of course lol) I decided to make Beatrix and Steiner much more different from each other. Specifically I gave Beatrix access to Quadraslash and took away Stock Break from her and made Shock and Climhazzard skills exclusive to her (I also gave her an "ultimate skill" that's locked behind getting the Excalibur II which I made her ultimate weapon to make up for the fact she doesn't get a Trance).
Now that I solidified Beatrix as a Holy Knight/ Paladin I decided to make Steiner the very opposite of that; a Dark Knight. I've changed a lot of his skills to reflect his new status as a dark knight (with a couple as homage to FFT) but was wondering if it were possible with Hades Workshop to create unique damage/effect formulas?
For example, I'd like to have Steiner required to sacrifice some of his hp with most of his skills, including the non-damaging ones. Is this possible to do?
set Setting_OptionalQuina = 1
set Setting_DaggerDepresses = 1
0xDB( 2, 0 )
0xDB( 7, 0 )
set Setting_MPx4 = 0
SetHP( 0, 9999 )
SetHP( 1, 9999 )
SetHP( 3, 9999 )
SetHP( 2, 9999 )
SetHP( 4, 9999 )
SetHP( 5, 9999 )
SetHP( 7, 9999 )
SetHP( 6, 9999 )
SetHP( 8, 9999 )
SetMP( 0, 999 )
SetMP( 1, 999 )
SetMP( 3, 999 )
SetMP( 2, 999 )
SetMP( 4, 999 )
SetMP( 5, 999 )
SetMP( 7, 999 )
SetMP( 6, 999 )
SetMP( 8, 999 )
Replace that "set Setting_DaggerDepresses = 1" by "set Setting_DaggerDepresses = 0", then click on "Parse" and then confirm.I have ff9 for pc, and I think it's not a steam version.You don't know what version you have? Where did you get it?
if ( 27789 & ( 1 << questionid ) ) {
set endbattlestep = 6
} else {
set endbattlestep = 4
}
"endbattlestep = 4" makes the Ragtime Mouse cast its "Correct" reaction while "endbattlestep = 6" is the wrong answer.if ( questionnumber == 16 ) {
set endbattlestep = 6
} ....
If it's the 16th time that you see the Ragtime Mouse, attacking any of "True" of "False" will be a wrong answer. So what you have is normal: you must do something else to answer the riddle. It's a kind of Epimenides paradox.if ( (successrate >= 80) && (successrate < 100) ) {
....
set true[DEFEATED_ON] =$ 1
} else {
....
set ragtime_mouse[DEFEATED_ON] =$ 1
}
So you're getting the drop of the enemy "True", which is a dark matter in my mod until you change it. The Ragtime Mouse drops a dark matter + Exp + Gil.
192, Freya, Stand = 2556, Walk = 2553, Run = 2558, Left = 2555, Right = 2551, Jump = 12871, Stand = 6484, 12866, Stand = 12870, 6480, Jump = 12864, Jump = 12872, Stand = 805, 837, 807, 439, END...
0 : Select
3 : Start
4 : Up
5 : Right
6 : Down
7 : Left
8 : L2
9 : R2
10 : L1
11 : R1
12 : Triangle
13 : Circle
14 : Cross
15 : Square
16 : Cancel
17 : Confirm
19 : Moogle
20 : L1 Ex
21 : R1 Ex
22 : L2 Ex
23 : R2 Ex
24 : Menu
25 : Select Ex
Use the power of 2 for the number in the script.while (1) {
if (IsButton(16)) {
AddItem( 1, 1 ) // Add 1 Dagger everytime the player presses "Up"
}
if (IsButtonDown(16)) {
AddGil( 1 ) // Add 1 gil every frame as long as the button "Up" is pressed
}
Wait(1)
}
In practice, maybe they disabled the check of "IsButton" on the arrows for some reason. They use "IsButtonDown" for sure for special windows such as the Treno Action bidding (for selecting the amount of gil you want to bid).
SetStandAnimation( JUMP_ANIM )
SetStandAnimation( STAND_ANIM )
SetJumpAnimation( JUMP_ANIM )
This will force the jump animation to load up in the RAM so it can be used.About the ID, I'll do things like that if I think about it.I see! That is helpful advice, thank you for sharing. I'll have to try that.
About the jump animation, they are very special: the script code "SetJumpAnimation" is the only one that doesn't check if the animation is loaded in the RAM. In case that the animation was not loaded, it bugs instead of loading it. You can use things like:Code: [Select]SetStandAnimation( JUMP_ANIM )
This will force the jump animation to load up in the RAM so it can be used.
SetStandAnimation( STAND_ANIM )
SetJumpAnimation( JUMP_ANIM )
Hi there !
I'm working on a Final Fantasy IX modding tool called Hades Workshop. It is aiming to allow to edit most of Final Fantasy IX's content. Quite a big project and I don't know if I will ever decide when it's finished ;D
//============== THE TOOL =================//
The features so far :
- Can open Final Fantasy IX PSX files, in .bin format and in any language version,
- Now works with the Steam version,
- Read and edit datas about :
--- Spells the party can cast,
--- Supporting abilities the party can use,
--- Commands the party has,
--- Default stats of the party members,
--- Items' features,
--- Items sold in shops,
--- Statistics, attacks and AI of enemies,
--- Tetra Master cards,
--- Text, dialogs and charmap,
--- Game's script,
--- MIPS script and CIL script,
--- Model exporting (Battle Scenes only for PSX, more for Steam),
--- Backgrounds (view only in PSX, view/replace in Steam),
--- Steam resources exporter/importer,
--- Spell animation sequencing.
- Works under Windows only (you may recompile the source code I redistribute or use wine under linux).
It may be a good idea to have a look at the help (F2).
Also, I recommend to the new Steam users to go easy with this tool. Several features are easy to get familiar with, but due to the power of this program and the complexity of FF9, there are subtilities and traps to avoid.
You should read this post (http://forums.qhimm.com/index.php?topic=14315.msg242844#msg242844) to get to know some of them.
Important : Hades Workshop doesn't work if Albeoris's Memoria tool was used. The other tool called Memoria (seriously Albeoris...) by gjoerulv works just fine.
Credits :
I made the program, obviously, but I got helped a lot by your wiki (http://wiki.qhimm.com/view/FF9 (http://wiki.qhimm.com/view/FF9)) for cluster datas format and by http://finalfantasy.wikia.com/ (http://finalfantasy.wikia.com/) occasionally.
Other than that, LandonRay and Zande made quiet an useful work in data finding, Zidane_2 wrote most of the other tools about FFIX before me.
The background image has been drawn by Maxa'. You can check his Deviant-Art page here (http://maxa-art.deviantart.com/).
Please tell me if you get any suggestion/bug report/feedback to share ^^
Here are the download links :
HADES WORKSHOP (https://www.hiveworkshop.com/attachments/hadesworkshop-zip.274037/)
Github project (https://github.com/Tirlititi/Hades-Workshop)
The older versions can be found here (https://www.dropbox.com/sh/f8edyp5ua4a7kc7/AACuhcb46gQq4x4IMGmgRgl1a?dl=0)
Thank you for your attention :)
//=============== THE MODS =================//
Here are Final Fantasy IX mods made using Hades Workshop. I won't speak of LandonRay's mod because it is not related to it, but it's also worth a look ^^
Difficulty Tweak (http://forums.qhimm.com/index.php?topic=17546.0) : Made by Iamthehorker, this mod increases the MP cost of the abilities and make the battles tougher. The gameplay itself is preserved, so it really is an increase of difficulty for an augmented playthrough. If you think that the boss battles end too quickly or if you never saw the use of the ethers/elixirs, this mod is a way to go. It also allows Steiner to equip the Save of the Queen in the end-game.
Final Fantasy Formula IX (http://www.insanedifficulty.com/board/index.php?/topic/4194-final-fantasy-formula-ixfffix) : A mod made by Aidolu with completly different spells and commands. I particulary like how commands have been re-invested to make spells like Songs or Cooking moves. The new spells are mostly taken from other Final Fantasy with few changes sometimes because of the limitation of my program or of FFIX battle mechanics.
Save The Queen (http://www.romhacking.net/hacks/1984/) : A mod made by ThisGuyAreSick2. It allows Steiner to use the allmighty Save The Queen. It also changes the way you synthesize it (it's made in the Black Mage Village in disc 4).
FF9.2.2 (http://forums.qhimm.com/index.php?topic=15217.0) : A mod made by Vir to improve the Perfect Stats challenge balancing. It removes the forced exp battle so a true lvl 1 game can be made. It also fixes the Thunder Slash glitch. Vir also made a Fixed Stats Mod (http://forums.qhimm.com/index.php?topic=16703.0) which removes the primary stat variations from games to games and have a normalized stat progression.
Alternate Fantasy (http://forums.qhimm.com/index.php?topic=16324) : My own mod. It modifies a bit of everything in the game but mostly change the abilities and the gameplay in battles.
Also, you can find here (https://www.dropbox.com/sh/ac7sr4q3z2cx9vp/AACQDfqXPvn8c3ylXeGUrBKEa?dl=0) the different tiny mods I made over the years.
//============== HELP AND TIPS =================//
This topic is now more than 30 pages long. Different people asked for help at different points and I always tried to give a complete answer. You can thus find details in this topic about subtilities of the game, or how a feature of HW works, or how to do some precise thing. Since I don't want everyone to read the whole topic thoroughly, here are links to answers to these kind of questions.
Side effects of Initial/Auto-statuses (http://forums.qhimm.com/index.php?topic=14315.msg205428#msg205428)
A list of spells specially handled by the engine (http://forums.qhimm.com/index.php?topic=14315.msg248444#msg248444)
Bypass the enemies' Max HP limit (http://forums.qhimm.com/index.php?topic=14315.msg224426#msg224426)
Checking if a character is in the team in-battle (http://forums.qhimm.com/index.php?topic=14315.msg236103#msg236103)
Enabling an enemy attack depending on the party stats (http://forums.qhimm.com/index.php?topic=14315.msg236276#msg236276)
Make Zorn & Thorn battle more difficult (http://forums.qhimm.com/index.php?topic=14315.msg250236#msg250236)
About the random encounter rate (https://www.gamefaqs.com/boards/197338-final-fantasy-ix/75389893)
Removing Dagger's depression effect in-battle (http://forums.qhimm.com/index.php?topic=14315.msg251907#msg251907)
About Ragtime Mouse quizz and reward script (http://forums.qhimm.com/index.php?topic=14315.msg251926#msg251926)
Unlocking manually a few of the "Hidden Scenes" (http://forums.qhimm.com/index.php?topic=14315.msg222961#msg222961)
Skipping the script that makes Dagger unlearn her summons (http://forums.qhimm.com/index.php?topic=14315.msg237588#msg237588)
Make Mini-Theater Ship obtainable as a key item (http://forums.qhimm.com/index.php?topic=14315.msg238833#msg238833)
Removing Excalibur II time condition manually (http://forums.qhimm.com/index.php?topic=14315.msg248637#msg248637)
Making temporary characters available in the party menu (1) (http://forums.qhimm.com/index.php?topic=14315.msg245063#msg245063)
Making temporary characters available in the party menu (2) (http://steamcommunity.com/app/377840/discussions/0/353915953249510749/?ctp=8#c1457328927844133175)
Changing properly the content of a chest (http://forums.qhimm.com/index.php?topic=14315.msg233384#msg233384)
Ensure that characters enter the party at level 1 (http://forums.qhimm.com/index.php?topic=14315.msg237581#msg237581)
How to use "GetRandom" to generate a random number in a range (http://forums.qhimm.com/index.php?topic=14315.msg250290#msg250290)
List of animation IDs and who use them (http://forums.qhimm.com/index.php?topic=14315.msg253853#msg253853)
Declaring local and global variables in scripts (http://forums.qhimm.com/index.php?topic=14315.msg234516#msg234516)
Typical NPC dialog script (http://forums.qhimm.com/index.php?topic=14315.msg247568#msg247568)
Add NPC and PC on the field (http://forums.qhimm.com/index.php?topic=14315.msg242890#msg242890)
Manually extracting a Beatrix mod out of Alternate Fantasy (http://steamcommunity.com/app/377840/discussions/0/353915953249510749/?ctp=2#c276237094325785813)
How to mix some of the standard mods (http://forums.qhimm.com/index.php?topic=14315.msg237980#msg237980)
A word about background and walkmeshes (http://forums.qhimm.com/index.php?topic=14315.msg239117#msg239117)
HW format for text file batching (http://forums.qhimm.com/index.php?topic=14315.msg237956#msg237956)
Helping with the development of HW (http://forums.qhimm.com/index.php?topic=14315.msg248197#msg248197)
Bug when making a multi-hit spell animation (PSX) (http://forums.qhimm.com/index.php?topic=14315.msg230211#msg230211)
Adding custom text font (PSX) (http://forums.qhimm.com/index.php?topic=14315.msg213039#msg213039)
Using Memory card saves after modding (PSX) (http://forums.qhimm.com/index.php?topic=14315.msg212984#msg212984)
Fixing "The Collector" Tetra Master bug (PSX) (http://forums.qhimm.com/index.php?topic=14315.msg214553#msg214553)
Change the initial items + hex-hack to give supporting abilities to Beatrix (PSX) (http://forums.qhimm.com/index.php?topic=14315.msg241840#msg241840)
MIPS editing + controlling someone else than Zidane in fields for PSX (http://forums.qhimm.com/index.php?topic=14315.msg239490#msg239490)
Grudge's MIPS spell formula (PSX) (http://forums.qhimm.com/index.php?topic=14315.msg239660#msg239660)
Using the Background Editor (Steam) (http://forums.qhimm.com/index.php?topic=14315.msg247956#msg247956)
Properly adding a new enemy to a battle (Steam) (http://forums.qhimm.com/index.php?topic=14315.msg245485#msg245485)
Removing (some of) the bubbles appearing when you get close to NPC on Steam (http://forums.qhimm.com/index.php?topic=14315.msg248727#msg248727)
Removing the stat growth of characters (Steam) (http://forums.qhimm.com/index.php?topic=14315.msg248318#msg248318)
Modding Magic Stone growth of characters (Steam) (http://forums.qhimm.com/index.php?topic=14315.msg249629#msg249629)
Modding spell effect: explanation (Steam) (http://forums.qhimm.com/index.php?topic=14315.msg250810#msg250810)
Modding Supporting Abilities: HP/MP +X% (Steam) (http://forums.qhimm.com/index.php?topic=14315.msg249962#msg249962)
Modding Supporting Abilities: Auto-status and Immunes (Steam) (http://steamcommunity.com/groups/ff-modding/discussions/13/350533172684330089/#c2119355556487352609)
Skipping the last two cinematics of the game (Steam) (http://steamcommunity.com/groups/ff-modding/discussions/13/350533172684330089/?ctp=2#c1488861734096802623)
//================ BONUS =================//
Simplified Game Scripts
Here are some scripts of systems or mini-games that are of some interest if you wish to know how the game works in-depth.
FFIX Code Folder (https://www.dropbox.com/sh/8ce6b73316gkx0x/AAA2-z3GCFZf3-Ed-6htDRmCa?dl=0)
Hidden dialogs
Here are some few interesting secret dialogs, never used in the game.
I've also made a patch to enable some of them in-game :
Hidden Dialogs (PSX) (http://www.romhacking.net/hacks/2112/)
Hidden Dialogs (PC) (https://www.dropbox.com/s/ejifo5amf4kkcyc/PC_HiddenScenes.zip?dl=1)
And a video (https://www.youtube.com/watch?v=paxguJo6AqA) showing the patch's content.
Don't hesitate to tell me if you find more unused dialogs : I'll add them to the list ^^
Alexandria [Over the roofs...] :
Puck “So, Vivi... Is this your first time in Alexandria?”
Vivi “Uh... Um... Yeah. I bought my ticket from a moogle wearing a hat...”
Puck “Bad luck! If I ever find that moogle, I'll hurt him plenty!”
Vivi “Uh... Thanks...”
Puck “Alright! Just a little farther 'til we can see the stage!”
Ruined Prima Vista [Steiner's bitterness] :
[1/3]
Steiner “Those bastards... If they plan to demand a ransom, they're wasting their time. I'll see to it that they receive nothing!”
[2/3]
Steiner “Wretched thieves... I'll see them all hanged!”
[3/3]
Steiner “Those bastards... They will never get away with this!”
Observatory Mountain [Good and Evil with Grampa Morrid] :
Steiner “Alexandria, off course! Burmecia started the war, and we lost our king as a result.”
Morrid “Many wars were fought before the Lindblum Airship Revolution.”
Morrid “Alexandria intiated some of the wars against Burmecia. Now, can you tell me who was right or wrong?”
Steiner “I-I am not talking about the past! I am talking about the future!”
Morrid “What will you do if Alexandria starts a war?”
Steiner “When will the cargo ship arrive!?”
Gizamaluke's Grotto [Entering Burmecia] :
Burmecian Soldier “This is the Gizamaluke's Grotto. It is Burmecia's border.”
Burmecian Soldier “No one is allowed inside without the king's permission.”
Cleyra [Meeting with the King and the High Priest] translated from japanese by luksy :
Freya “It has been some time, Your Majesty.”
King of Burmecia “Ah, Freya, well met.”
King of Burmecia “The High Priest and I welcome you.”
High Priest of Cleyra “My Lady.”
High Priest of Cleyra “It would appear that this predicament no longer concerns Burmecia alone.”
Freya “I understand, Your Holiness.”
Freya “And yet...”
Freya “I fear my strength alone may not suffice.”
King “Freya...I know what troubles you.”
King “I must apologize for earlier.”
King “Can you ever forgive me?”
King “No! off course you cannot.”
King “But the fate of the people of Burmecia now hangs by but a thread.”
Occupied Lindblum Castle [Reaching Cid] :
Don't get caught by the enemy!
Jump out when she looks away!
Man “The regent is waiting for you at the Base Level.”
Man “The enemy is busy loading supplies. Go down on the lift, now!”
Man “Once you get on the lift, my comrades will take care of the rest.”
Zidane “So, I just take the lift to the Base Level without getting caught?”
Yeah...
Zidane “Piece o' cake! Leave everything to me.”
Huh?
Is anybody there...?
A tail?
Meeow!
Oh, it's only a cat...
Zidane (Wow, that was a close one.)
Man “(You idiot!)”
Man “Whatever you do, don't get caught!”
Man “What's wrong? The regent is waiting at the Base Level.”
Man “Go now, or you'll get caught!”
Zidane “I gotta run while she's looking away.”
Occupied Lindblum Castle [The Ancient World Map] :
Regent Cid “That is a national treasure of Lindblum!”
Regent Cid “It was passed down through my ancestors, since the days of the first regent.”
Regent Cid “It was probably made before our continent was covered in the Mist...”
Regent Cid “That is an ancient map of the entire world!”
Alexandria [Balloon Mini-game] translated from french by me :
Girl “You want to play with us?”
Girl “You've got some time to gather balloons and give them to the boys behind us!”
Girl “You get more time depending on the color of the balloon that you bring.”
Green → 5 more seconds
Yellow → 10 more seconds
Blue → 15 more seconds
Red → 30 more seconds
Girl “All the three of us have a balloon and we are somewhere on the square.”
Girl “Well... Start!”
Boy “X more seconds! You have Y points!”
Final [The 2 worlds' fusion] :
The Iifa Tree could not be stopped...
Gaia and Terra's fusion
caused global chaos,
destroying many cities and
taking many lives...
Yes it does. However, for the PSX version, not all the battles are present in all the discs. So if you opened disc 1 you only have the bosses of disc 1. Same for the other discs with a few exceptions (Gizamaluke is present on all the discs because the Grotto fields are still there as well).
Also, no need to quote a whole message of 215 lines (yeah, I checked that) for a 3 lines long reply. That's like subcontracting your speech, somehow :p
Yes it does. However, for the PSX version, not all the battles are present in all the discs. So if you opened disc 1 you only have the bosses of disc 1. Same for the other discs with a few exceptions (Gizamaluke is present on all the discs because the Grotto fields are still there as well).
Also, no need to quote a whole message of 215 lines (yeah, I checked that) for a 3 lines long reply. That's like subcontracting your speech, somehow :p
No, that's not really possible. These numbers are divided by 2 for the minimal randomized stat. I didn't add a limit for fun.
The Magic Stone progression is defined in the CIL Code, so it's a bit tedious to change. It's the method "ff9level::FF9Level_GetCap" :Code: [Select]public static int FF9Level_GetCap(int slot_id, int lv, bool lvup) {
In term of CIL Code, the main operation ("int num3 = ...") is those lines:
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;
}Code: [Select]ldloc.3 // fF9LEVEL_BASE
ldfld 0x4000890 // FF9LEVEL_BASE::cap
ldarg.1 // lv
[b]ldc.i4.4 // Multiply by 4[/b]
mul
[b]ldc.i4.s 10 // Divide by 10[/b]
div
add
[b]ldloc.2 // bonus[/b]
ldfld 0x400088B // FF9LEVEL_BONUS::cap
[b]ldc.i4.5 // Right-shift by 5 ( = Divide by 32)[/b]
shr
add
stloc.0
I have no idea of where the font used is defined.
int num3 = (int)fF9LEVEL_BASE.cap + lv * 4 / 10 + (bonus.cap >> 5);
"fF9LEVEL_BASE.cap" is the base number at lvl 1 that you can set in the "Party->Stats" panel.ldc.i4.4 -> Change it to ldc.i4.s 9 for instance
ldc.i4.s 10 -> Change it to ldc.i4.s 2 for instance
With these figures, you would get +4.5 Magic Stone every level (so +4 Magic Stone on odd levels and +5 on even levels).
Another thing I am considering: Is there a way to change the steal rates and to edit the AP required to learn skills and abilities?
ldarg.1
ldc.i4.s 10
div
add
ldloc.2
ldfld 0x4000885 // FF9LEVEL_BONUS::dex
ldc.i4.5
shr
add
ldarg.1
ldc.i4.s 5
mult
ldc.i4.s 13
div
add
ldloc.2
ldfld 0x4000885 // FF9LEVEL_BONUS::dex
ldc.i4.s 44
div
add
ldfld 0x40008AD // FF9PLAY_SKILL::Base
ldloc.0
ldelem.u1
ldloc.s 6
ldloc.0
ldelem.u1
ble IL_0328
ldarg.1
ldind.ref
ldfld 0x40008AD // FF9PLAY_SKILL::Base
Just replace the line "ble IL_0328" by "br IL_0328" and it should remove the limit totally.thanx you ^^
Is work.
Is possible change stats regular items arms and all armor stats, attack, defence, evade, magic defence, magic evade to steam and change formula effet ?
Thanx you verry much ...
.
I am not sure that increasing the max values is safe. If the HP of a character is beyond 9999, it will display a bit strangely but work just fine. However, there might be more troublesome bugs.
ldarg.0
ldfld 0x400022A // BTL_DATA::elem
ldfld 0x400080F // ELEMENT::wpr
sub
It's the four lines under a "ldc.i4.s 60". The Regen frequency formula is indeed "Frames to wait = (60 - wpr) << 2", which is, in a more standard writing, "(60 - Spirit) * 4". Removing these four lines will remove the spirit part so you will always regen with the same frequency (the overall duration is something else and will still increase though). You may change the number in "ldc.i4.s 60" to adjust it if you think it's too slow (or too fast).ldloc.1
conv.r4
ldloc.0
ldfld 0x40038A0 // SoundProfile::Pitch
mul
stloc.2
ldloc.0
ldloc.2
stfld 0x40038A0 // SoundProfile::Pitch
Remove the last 3 lines (ldloc.0, ldloc.2, stfld).Saving Instructions
You have to backup your files yourself. The program asks for the "FF9_Launcher.exe" file when opening the game, and then for a folder where you want to save your modded files. In any case, never choose the folder in which the selected "FF9_Launcher.exe" lies, either create a new folder either save it in a folder containing another "FF9_Launcher.exe".
The files created this way are intended to replace the files in the sub-folders of your "FINAL FANTASY IX" folder.
Here are the 2 safest possible choices :
1) Start by creating a backup of your "FINAL FANTASY IX" folder. When you use HW, only open the backup files and choose the non-backup "FINAL FANTASY IX" folder when you save (it's important that you keep that default name). As that's the game launched by Steam, you'll have your game directly modded.
2) Start by creating a backup of your "FINAL FANTASY IX" folder and use that backup for HW, but create a new folder somewhere else for the saving. To apply the mod, you need to replace manually the files in the "FINAL FANTASY IX" folder by the modded ones.
In any case, a 3rd backup is not a bad idea, unless you don't mind downloading the game again in case of problems.
1) The text still can't be imported properly from PSX to Steam, and it concerns all the texts, not only the ones in the "Texts" panel.
If there is one thing that HW does less well for Steam than for PSX, it's editing and managing the texts... I have been working on multi-language support lately but I will need more time to work on the Steam text opcodes (that's what makes it troublesome).
The best solution for now would be to use file batching for dialogs, I guess, but for the rest, you'll have to copy/paste and write the Steam opcodes yourself (you can have 2 windows/panels of HW opened: one of PSX and the other for Steam).
2) Yes, the encounter rate is definitely lower in the Steam version, but the difference is indeed not in the field script. It is unclear to me what makes this difference... I've said what I saw and what I think of it here (comparing the Steam engine's code with the description of SoftReset of the PSX engine's code, it would really look like they are the same):
https://www.gamefaqs.com/boards/197338-final-fantasy-ix/75389893
I've just googled around and it seems no one knows the reason for the indeed much lower encounter rate of the steam version. Damn, that's an even bigger bummer to my plans. So the only option is to manually go through each field and increase the encounter rate to somehow restore the battle frequency of the original PSX game (more or less)? That'll be quite tedious, but I guess there's no way around it if I don't want to remain constantly underleveled.
if (sMoveKey && !IsNearlyZero(DistanceFromLastFramePos)) {
. . sEncountTimer += DistanceFromLastFramePos * FieldWorldMapFactor;
. . if (!Cheat.IsNoEncounter && usercontrol != 0 && sEncountTimer > 960) {
. . . . sEncountTimer = 0f;
. . . . sEncountBase += encratio;
. . . . if (random8() < sEncountBase/8) {
. . . . . . sEncountBase = 0;
. . . . . . TriggerRandomBattle();
. . . . }
. . }
}
ldc.i4.0
beq.s IL_00A8
ldc.i4.1
br.s IL_00A9
ldc.i4.0
ret
@ste459: Controlling the ATB that accurately is not possible with Hades Workshop. It is possible with Albeoris's Memoria but you'd need to recode part of the engine for that.
However it is indeed possible to increase the Regen frequency, with both HW and Memoria. In HW, you go to CIL Code, search for the method "btl_stat -> SetOprStatusCount" and remove that part of the code:
Code: [Select]
ldarg.0
ldfld 0x400022A // BTL_DATA::elem
ldfld 0x400080F // ELEMENT::wpr
sub
It's the four lines under a "ldc.i4.s 60". The Regen frequency formula is indeed "Frames to wait = (60 - wpr) << 2", which is, in a more standard writing, "(60 - Spirit) * 4". Removing these four lines will remove the spirit part so you will always regen with the same frequency (the overall duration is something else and will still increase though). You may change the number in "ldc.i4.s 60" to adjust it if you think it's too slow (or too fast).
@Incinerator: I was bugged by the task of giving a precise answer but replying to ste459 gave me one : if you use regen on a character with 60 spirit or more, the formula above goes to negative which can either mean regen will never trigger or it will trigger every single frame (having a quick look at the code, I would incline to the latter).
ldarg.0 // This is the 1st argument passed to the method, of type BTL_DATA ; it contains a character's (or enemy's) battle infos
ldfld 0x400022B // BTL_DATA::elem ; contains the statistics
ldfld 0x4000811 // ELEMENT::wpr ; spirit
ldc.i4.2 // Put the number "2" on the stack for later left shift
shl // LeftShift( spirit, 2 )
conv.u2 // Just a conversion to unsigned short integer
stloc.1 // Store the result in a variable (used later)
AttackSpecial( 9 ) // Death Animation
while ( IsAttacking != 0 ) {
Wait( 1 )
}
set SV_FunctionEnemy[DEFEATED_ON] =$ 1 // This line is here by default and is also needed
// Put the line here
return
“And hast thou done the model importer?
Come to my arms, my beamish boy!
O frabjous day! Callooh! Callay!”
He chortled in his joy.
Field ID (to use in the Field script): 1805
Event files name (file containing its Field script): EVT_ALEX3_AC_SEAT_N
Background files name (background files to add in the archive p0data11): FBG_N02_ALXC_MAP038_AC_AST_0
Since you won't be able to edit that field's script in HW, you'd need to use another field as a temporary container, do all the changes you want on that field, export its files - event files (ie. script) from p0data7, and background files (ie. .bgs, .bgi and atlas texture from p0data1X) - and add them back with adjusted names (since there's already a script file, you only need to replace it, not add).- In most cases, when you add an asset, you must check the "Bundle Info" option and add a path to your asset (something like "assets/custom_resources/my_image.png"). For making the game use your asset directly, you must refer to that path in the game's engine code,
// Enemy Basilisk
5458, 379, "ANH_MON_B3_011_B", "Unexisting B"
// Enemy LizardMan
5459, 390, "ANH_MON_B3_019_B", "Unexisting B"
// Enemy Carve Spider
5460, 376, "ANH_MON_B3_021_015", "UnexistingA"
5460, 360, "ANH_MON_B3_021_040", "UnexistingB 1"
5460, 366, "ANH_MON_B3_021_041", "UnexistingB 2"
5460, 354, "ANH_MON_B3_021_042", "UnexistingB 3"
// Enemy Clipper
150, 8693, "ANH_MON_B3_039_P", "Unexisting P"
// Enemy Blazer Beetle
84, 9257, "ANH_MON_B3_042_B", "Unexisting B"
// Enemy Cactuar
244, 9239, "ANH_MON_B3_061_B", "Unexisting B"
244, 9900, "ANH_MON_B3_061_TEST", "Unexisting Test"
// Enemy Valia Pira
354, 9340, "ANH_MON_B3_130_B", "Unexisting B"
354, 13578, "ANH_MON_B3_130_ILLUST","Unexisting Illust"
354, 8833, "ANH_MON_B3_130_P", "Unexisting P"
354, 13581, "ANH_MON_B3_130_TEST", "Unexisting Test"
// Enemy Vivi
558, 12302, "ANH_MON_B3_151_001", "UnexistingA"
558, 12306, "ANH_MON_B3_151_005", "UnexistingB"
558, 9675, "ANH_MON_B3_151_B", "Unexisting B"
558, 9677, "ANH_MON_B3_151_P", "Unexisting P"
// Enemy Dagger
671, 9957, "ANH_MON_B3_169_002", "Unexisting"
// Enemy Freya
297, 10317, "ANH_MON_B3_174_B", "Unexisting B"
297, 10319, "ANH_MON_B3_174_P", "Unexisting P"
// Enemy Gigan Toad B
663, 8374, "ANH_MON_B3_197_034", "Unexisting"
// Battle Steiner B
655, 6744, "ANH_MAIN_B0_018_000", "Unexisting 000"
655, 6746, "ANH_MAIN_B0_018_001", "Unexisting 001"
655, 6747, "ANH_MAIN_B0_018_002", "Unexisting 002"
655, 6750, "ANH_MAIN_B0_018_010", "Unexisting 010"
655, 6752, "ANH_MAIN_B0_018_011", "Unexisting 011"
655, 6753, "ANH_MAIN_B0_018_020", "Unexisting 020"
655, 6755, "ANH_MAIN_B0_018_021", "Unexisting 021"
655, 6758, "ANH_MAIN_B0_018_022", "Unexisting 022"
655, 6759, "ANH_MAIN_B0_018_023", "Unexisting 023"
655, 6761, "ANH_MAIN_B0_018_032", "Unexisting 032"
655, 6763, "ANH_MAIN_B0_018_033", "Unexisting 033"
655, 6766, "ANH_MAIN_B0_018_040", "Unexisting 040"
655, 6768, "ANH_MAIN_B0_018_050", "Unexisting 050"
655, 6769, "ANH_MAIN_B0_018_100", "Unexisting 100"
655, 6771, "ANH_MAIN_B0_018_101", "Unexisting 101"
655, 6774, "ANH_MAIN_B0_018_102", "Unexisting 102"
655, 6776, "ANH_MAIN_B0_018_103", "Unexisting 103"
655, 6777, "ANH_MAIN_B0_018_104", "Unexisting 104"
655, 6779, "ANH_MAIN_B0_018_105", "Unexisting 105"
655, 6782, "ANH_MAIN_B0_018_200", "Unexisting 200"
655, 6784, "ANH_MAIN_B0_018_201", "Unexisting 201"
655, 6785, "ANH_MAIN_B0_018_202", "Unexisting 202"
655, 6787, "ANH_MAIN_B0_018_210", "Unexisting 210"
655, 6789, "ANH_MAIN_B0_018_220", "Unexisting 220"
655, 6791, "ANH_MAIN_B0_018_300", "Unexisting 300"
655, 6794, "ANH_MAIN_B0_018_310", "Unexisting 310"
655, 6795, "ANH_MAIN_B0_018_400", "Unexisting 400"
655, 6797, "ANH_MAIN_B0_018_401", "Unexisting 401"
655, 6799, "ANH_MAIN_B0_018_402", "Unexisting 402"
655, 6802, "ANH_MAIN_B0_018_410", "Unexisting 410"
655, 6803, "ANH_MAIN_B0_018_420", "Unexisting 420"
655, 6805, "ANH_MAIN_B0_018_430", "Unexisting 430"
655, 6807, "ANH_MAIN_B0_018_500", "Unexisting 500"
655, 6809, "ANH_MAIN_B0_018_501", "Unexisting 501"
655, 6812, "ANH_MAIN_B0_018_600", "Unexisting 600"
// Unexisting Battle model 002
568, 12511, "ANH_MAIN_B2_003_ALL", "Unexisting All"
// Unexisting Battle model Cam
649, 14461, "ANH_MAIN_B2_CAM_011_1ST", "Unexisting 1st"
649, 14460, "ANH_MAIN_B2_CAM_011_2ND", "Unexisting 2nd"
649, 14463, "ANH_MAIN_B2_CAM_011_DOWN", "Unexisting Down"
649, 14458, "ANH_MAIN_B2_CAM_011_END", "Unexisting End"
649, 14451, "ANH_MAIN_B2_CAM_011_JUMP", "Unexisting Jump"
649, 14454, "ANH_MAIN_B2_CAM_011_OPENING", "Unexisting Opening"
649, 14455, "ANH_MAIN_B2_CAM_011_RUN", "Unexisting Run"
649, 14462, "ANM_MAIN_B2_CAM_011_1ST", "Unexisting 1st"
649, 14459, "ANM_MAIN_B2_CAM_011_2ND", "Unexisting 2nd"
649, 14464, "ANM_MAIN_B2_CAM_011_DOWN", "Unexisting Down"
649, 14457, "ANM_MAIN_B2_CAM_011_END", "Unexisting End"
649, 14452, "ANM_MAIN_B2_CAM_011_JUMP", "Unexisting Jump"
649, 14453, "ANM_MAIN_B2_CAM_011_OPENING", "Unexisting Opening"
649, 14456, "ANM_MAIN_B2_CAM_011_RUN", "Unexisting Run"
// Unexisting Battle model 001
29, 838, "ANM_MAIN_B2_001", "Unexisting 001"
// Gargant
306, 4650, "ANH_ACC_F1_GRG_B", "Unexisting B"
306, 6132, "ANH_ACC_F1_GRG_RUN_1F", "Unexisting Run_1f"
// Zidane
98, 179, "ANH_MAIN_F0_ZDN_JUMP1", "Unexisting Jump1"
// King Leo
5501, 1135, "ANH_SUB_F1_BAK_ANXIETY_3", "Unexisting Anxiety_3"
5501, 9435, "ANH_SUB_F1_BAK_B", "Unexisting B"
5501, 9154, "ANH_SUB_F1_BAK_P", "Unexisting P"
// Puck
121, 2195, "ANH_NPC_F0_RTC_SK_ANGRY", "Unexisting Sk_Angry"
121, 2192, "ANH_NPC_F0_RTC_SK_CRUSH", "Unexisting Sk_Crush"
121, 2183, "ANH_NPC_F0_RTC_SK_GET_LD", "Unexisting Sk_Get_Ld"
121, 2193, "ANH_NPC_F0_RTC_SK_GO_UP1_LD", "Unexisting Sk_Go_Up1_Ld"
121, 2194, "ANH_NPC_F0_RTC_SK_GO_UP2_LD", "Unexisting Sk_Go_Up2_Ld"
121, 2187, "ANH_NPC_F0_RTC_SK_HURRY_UP_LD","Unexisting Sk_Hurry_Up_Ld"
121, 2177, "ANH_NPC_F0_RTC_SK_IDLE", "Unexisting Sk_Idle"
121, 2184, "ANH_NPC_F0_RTC_SK_IDL_LD", "Unexisting Sk_Idl_Ld"
121, 2188, "ANH_NPC_F0_RTC_SK_LIFT_LD", "Unexisting Sk_Lift_Ld"
121, 2191, "ANH_NPC_F0_RTC_SK_PUT_LD", "Unexisting Sk_Put_Ld"
121, 2181, "ANH_NPC_F0_RTC_SK_ROGER", "Unexisting Sk_Roger"
121, 2186, "ANH_NPC_F0_RTC_SK_RUN", "Unexisting Sk_Run"
121, 2190, "ANH_NPC_F0_RTC_SK_RUN_LD", "Unexisting Sk_Run_Ld"
121, 2182, "ANH_NPC_F0_RTC_SK_TURN_", "Unexisting Sk_Turn_"
121, 2179, "ANH_NPC_F0_RTC_SK_TURN_L_LD", "Unexisting Sk_Turn_L_Ld"
121, 2185, "ANH_NPC_F0_RTC_SK_TURN_R", "Unexisting Sk_Turn_R"
121, 2180, "ANH_NPC_F0_RTC_SK_TURN_R_LD", "Unexisting Sk_Turn_R_Ld"
121, 2196, "ANH_NPC_F0_RTC_SK_WALK", "Unexisting Sk_Walk"
121, 2189, "ANH_NPC_F0_RTC_SK_WALK_LD", "Unexisting Sk_Walk_Ld"
121, 2178, "ANH_NPC_F0_RTC_SK_WHICH_LD", "Unexisting Sk_Which_Ld"
The first number is the MODEL_ID, the second number is the ANIM_ID, the "ANH_" string is the internal animation name and the last string is the description as you find it in the field script.{ [NEW_ANIM_ID], [NEW_ANIM_STRING_ID] },
{ [NEW_MODEL_ID], "GEO_[MODEL_SHORT_STRING_ID]" },
{ 6000, "GEO_MAIN_F0_RED_DOG" },
{ 20000, "ANH_MAIN_F0_RED_DOG_TALK" },
{ 20001, "ANH_MAIN_F0_RED_DOG_RUN" },
etc...
; FBX 7.4.0 project file
; ----------------------------------------------------
FBXHeaderExtension: {
FBXHeaderVersion: 1003
FBXVersion: 7400
CreationTimeStamp: {
Version: 1000
Year: 2018
Month: 2
Day: 4
Hour: 10
Minute: 43
Second: 44
Millisecond: 584
}
Creator: "FBX SDK/FBX Plugins version 2018.1.1"
SceneInfo: "SceneInfo::GlobalInfo", "UserData" {
Type: "UserData"
Version: 100
MetaData: {
Version: 100
Title: ""
Subject: ""
Author: ""
Keywords: ""
Revision: ""
Comment: ""
}
Properties70: {
P: "DocumentUrl", "KString", "Url", "", "C:\Users\Dwight\Desktop\ZACH\98.fbx"
P: "SrcDocumentUrl", "KString", "Url", "", "C:\Users\Dwight\Desktop\ZACH\98.fbx"
P: "Original", "Compound", "", ""
P: "Original|ApplicationVendor", "KString", "", "", ""
P: "Original|ApplicationName", "KString", "", "", ""
P: "Original|ApplicationVersion", "KString", "", "", ""
P: "Original|DateTime_GMT", "DateTime", "", "", ""
P: "Original|FileName", "KString", "", "", ""
P: "LastSaved", "Compound", "", ""
P: "LastSaved|ApplicationVendor", "KString", "", "", ""
P: "LastSaved|ApplicationName", "KString", "", "", ""
P: "LastSaved|ApplicationVersion", "KString", "", "", ""
P: "LastSaved|DateTime_GMT", "DateTime", "", "", ""
}
}
}
GlobalSettings: {
Version: 1000
Properties70: {
P: "UpAxis", "int", "Integer", "",1
P: "UpAxisSign", "int", "Integer", "",1
P: "FrontAxis", "int", "Integer", "",2
P: "FrontAxisSign", "int", "Integer", "",1
P: "CoordAxis", "int", "Integer", "",0
P: "CoordAxisSign", "int", "Integer", "",1
P: "OriginalUpAxis", "int", "Integer", "",-1
P: "OriginalUpAxisSign", "int", "Integer", "",1
P: "UnitScaleFactor", "double", "Number", "",1
P: "OriginalUnitScaleFactor", "double", "Number", "",1
P: "AmbientColor", "ColorRGB", "Color", "",0,0,0
P: "DefaultCamera", "KString", "", "", "Producer Perspective"
P: "TimeMode", "enum", "", "",0
P: "TimeProtocol", "enum", "", "",2
P: "SnapOnFrameMode", "enum", "", "",0
P: "TimeSpanStart", "KTime", "Time", "",0
P: "TimeSpanStop", "KTime", "Time", "",46186158000
P: "CustomFrameRate", "double", "Number", "",-1
P: "TimeMarker", "Compound", "", ""
P: "CurrentTimeMarker", "int", "Integer", "",-1
}
}
; Documents Description
;------------------------------------------------------------------
Documents: {
Count: 1
Document: 127362160, "My Scene", "Scene" {
Properties70: {
P: "SourceObject", "object", "", ""
P: "ActiveAnimStackName", "KString", "", "", ""
}
RootNode: 0
}
}
; Document References
;------------------------------------------------------------------
References: {
}
; Object definitions
;------------------------------------------------------------------
assets/resources/models/2/98/98_2.png
ID: 7FFD1E8B51DB44F3
assets/resources/models/2/98/98_3.png
ID 7FFD1E8B51DB44F4
assets/resources/models/2/98/98_4.png
ID 7FFD1E8B51DB44F5
assets/resources/models/2/98/98_5.png
ID 7FFD1E8B51DB44F6
assets/resources/models/2/98/98_6.png
ID 7FFD1E8B51DB44F7
assets/resources/models/2/98/98_7.png
ID 7FFD1E8B51DB44F8
assets/resources/models/2/98/98_8.png
ID 7FFD1E8B51DB44F9
assets/resources/models/2/98/98_9.png
ID 7FFD1E8B51DB44FA
assets/resources/models/2/98/98_10.png
ID 7FFD1E8B51DB44FB
assets/resources/models/2/98/98_11.png
ID 7FFD1E8B51DB44FC
assets/resources/models/2/98/98_12.png
ID 7FFD1E8B51DB44FD
assets/resources/models/2/98/98_13.png
ID 7FFD1E8B51DB44FE
assets/resources/models/2/98/98_14.png
ID 7FFD1E8B51DB44FF
assets/resources/models/2/98/98_15.png
ID 7FFD1E8B51DB4500
assets/resources/models/2/98/98_16.png
ID 7FFD1E8B51DB4501
assets/resources/models/2/98/98_17.png
ID 7FFD1E8B51DB4502
assets/resources/models/2/98/98_18.png
ID 7FFD1E8B51DB4503
assets/resources/models/2/98/98_19.png
ID 7FFD1E8B51DB4504
assets/resources/models/2/98/98_20.png
ID 7FFD1E8B51DB4505
assets/resources/models/2/98/98_21.png
ID 7FFD1E8B51DB4506
assets/resources/models/2/98/98_22.png
ID 7FFD1E8B51DB4507
assets/resources/models/2/98/98_23.png
ID 7FFD1E8B51DB4508
assets/resources/models/2/98/98_24.png
ID 7FFD1E8B51DB4509
assets/resources/models/2/98/98_25.png
ID 7FFD1E8B51DB450A
assets/resources/models/2/98/98_26.png
ID 7FFD1E8B51DB450B
}
GeometryVersion: 124
LayerElementNormal: 0 {
Version: 102
Name: ""
MappingInformationType: "ByPolygonVertex"
ReferenceInformationType: "Direct"
Normals: *39258 {
However it is indeed possible to increase the Regen frequency, with both HW and Memoria. In HW, you go to CIL Code, search for the method "btl_stat -> SetOprStatusCount" and remove that part of the code:Code: [Select]ldarg.0
It's the four lines under a "ldc.i4.s 60". The Regen frequency formula is indeed "Frames to wait = (60 - wpr) << 2", which is, in a more standard writing, "(60 - Spirit) * 4". Removing these four lines will remove the spirit part so you will always regen with the same frequency (the overall duration is something else and will still increase though). You may change the number in "ldc.i4.s 60" to adjust it if you think it's too slow (or too fast).
ldfld 0x400022A // BTL_DATA::elem
ldfld 0x400080F // ELEMENT::wpr
sub
ldc.i4.3
newarr 0x2000062 // ENEMY_TYPE
...
ldc.i4.s 18
newarr 0x2000050 // AA_DATA
You may then ignore the warning that popups when adding too many enemy types or attacks in a battle.rename the texture dependancies in the FBX model to something else. The bug occurs when the model importer automatically catches the texture (more precisely, when another file as the same internal name as the texture, such as a material).
So you have to make sure that the program asks you what are the textures linked to the model.
So you have to make sure that the program asks you what are the textures linked to the model.
Wait( 1 )
Menu( 0, 0 )
Menu( 4, 0 )
set VAR_GenInt24_64 = GetEntryPosX(255)
set VAR_GenInt16_67 = GetEntryPosZ(255)
set VAR_GenInt24_69 = GetEntryPosY(255)
set VAR_GenUInt8_72 = GetEntryAngle(255)
set VAR_GenBool_184 = 1
Menu( 4, 0 )
set VAR_GenBool_184 = 0
And then something like this in the character's "Init" function:if ( General_FieldEntrance==10000 ) {
MoveInstantXZY( VAR_GenInt24_64, VAR_GenInt16_67, VAR_GenInt24_69 )
TurnInstant( VAR_GenUInt8_72 )
}
I think that the lines "if ( VAR_GenBool_184 == 1 ) { set General_FieldEntrance = 10000 }" are present in all the Fields of the game so you don't have to care about adding them.
ldarg.1
ldstr 0x7003CA77 // "_B0_"
callvirt 0xA0001A7 // bool System.String::Contains( string )
brtrue IL_0098
Replace them by these:call 0xA0000BB // !0 PersistenSingleton`1<class EventEngine>::get_Instance()
ldfld 0x40019E6 // EventEngine::gMode
ldc.i4.2
beq IL_0098
It may have an inconvenient bug though: sometimes models will be messed up in the first screen you see after launching the game. Going to the menu -> Title Screen -> Continue, it will be fixed back, but it is annoying.@Trostboot: I will fix that bug for the PSX version for the next release, but you can use an older version of HW in which there is not this bug. The version 0.37c (https://www.dropbox.com/sh/f8edyp5ua4a7kc7/AACuhcb46gQq4x4IMGmgRgl1a?dl=0) doesn't seem to have that bug. Also, most recent features are for the Steam version mainly so you don't miss a lot. Sorry about that.
You're supposed to select the corresponding Texture2D file.
That is, however, very weird that your texture is named "98.fbx"...
Thanks usb :)
Yeah, I thought that they fixed that bug, but apparently not. It doesn't concern only Italian but also French and Spanish. The bug lies in the CIL method "BattleHUD::SetBattleCommandTitle" but it's a bit tricky to fix it there with HW.
What you can do though is bypass the bug: go to the "Interface" panel, select the "Battle Spell Naming" field and add 13 entries to it (right-click -> Add), then write the proper full names ("Colpo Fire" etc...). Finally, go to the "Party -> Spells" panel and change the casting names of the magic swords spells to the entries that you just added.
It's a bit dirty as a fix, but it works. You should also translate the names in the "Interface" panel if you want it to work for all the languages (I think the game would crash in non-italian language otherwise).
For info, you can have up to 62 custom spell names in that interface field.
change the casting names of the magic swords spells to the entries that you just addedunder spells panel there are only the basic magic and not the magic swords (they are under special). if i change the vivi magic when Vivi cast Fire magic it will be shown as Colpo Fire but the magic sword is still wrong
About the "Spells" panel: yes, the Magic Swords are in there as well, but they are spread around. Most of them are next to Dagger's summons and Flare/Doomsday are at the end of the list.
About the "Localization" field, yes I noticed that. As strange as it appears, it's not a bug from HW but that's how the latest Steam version texts are (they were correctly set in the previous Steam versions). Don't bother.
call 0x6000F5D // FF9StateSystem::get_Battle
ldfld 0x4002267 // BattleState::FF9Battle
ldfld 0x4002230 // FF9StateBattleSystem::btl_list
ldfld 0x4000226 // BTL_DATA::next
ldfld 0x400022A // BTL_DATA::cur
ldfld 0x4000809 // POINTS::hp
call 0x6000F5D // FF9StateSystem::get_Battle
ldfld 0x4002267 // BattleState::FF9Battle
ldfld 0x4002230 // FF9StateBattleSystem::btl_list
ldfld 0x4000226 // BTL_DATA::next
ldfld 0x4000229 // BTL_DATA::max
ldfld 0x4000809 // POINTS::hp
ldc.i4.4
div
add
call 0x6000F5D // FF9StateSystem::get_Battle
ldfld 0x4002267 // BattleState::FF9Battle
ldfld 0x4002230 // FF9StateBattleSystem::btl_list
ldfld 0x4000226 // BTL_DATA::next
ldfld 0x400022A // BTL_DATA::cur
stfld 0x4000809 // POINTS::hp
This only restores 25% of max HP of the 1st character only (and doesn't even check if it goes over the max HP limit)...for (BTL_DATA next = FF9StateSystem.Battle.FF9Battle.btl_list.next; next != null; next = next.next)
if (next.bi.player != 0 && next.cur.hp>0)
next.cur.hp = min(next.cur.hp + next.max.hp / 4, next.max.hp);
Much simpler indeed ^^'Function Enemy_ATB
if (turn_counter == 0) {
// Turn 1
if (GetRandom % 2) {
set SV_Target = RandomInTeam( SV_PlayerTeam )
Attack( Poison ) // It is not "Poison" that should be in the real thing but the attack ID instead
} else {
// You may avoid Silencing someone who's already silenced using this kind of lines
set SV_Target = RandomInTeam( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 265) & NotMatching(SV_PlayerTeam[STATUS_CURRENT_B], 64) )
if (SV_Target == 0) { // Everyone is either dead or silenced already...
set SV_Target = RandomInTeam( SV_PlayerTeam )
}
Attack( Silence )
}
}
if ((turn_counter == 1) || (turn_counter == 3)) {
// Turn 2 and 4
set SV_Target = RandomInTeam( SV_PlayerTeam )
Attack( Physical Attack )
}
if (turn_counter == 2) {
// Turn 3
set rnd_num = GetRandom % 100
if (rnd_num < 50) {
set SV_Target = RandomInTeam( SV_PlayerTeam )
Attack( Flare )
} else {
if (rnd_num < 90) {
set SV_Target = RandomInTeam( SV_PlayerTeam )
Attack( Stop )
} else {
set SV_Target = SV_PlayerTeam | SV_EnemyTeam
Attack( Doomsday )
}
}
}
set turn_counter = ((turn_counter + 1) % 4)
return
And declare the local variables "turn_counter" and "rnd_num" in the local variable panel:local uint8 turn_counter
local uint8 rnd_num
@aidolu12: Yes, it's extremely difficult to do CIL changes by only looking at the CIL code. It's way better to look at the C# code to at least understand how the engine works before guessing how you can tweak it (it requires reading C# but that's always better than CIL).
You can see the C# code in Memoria's Github (https://github.com/Albeoris/Memoria/tree/492a4786d4f3061bff98b36b390a62c26b191cf1/Assembly-CSharp) page, or using a tool like dnSpy or dotPeek.
For your particular question, it's not particulary easy in CIL, but you might change the method "BattleHUD::GoToBattleResult" and add this kind of lines:Code: [Select]call 0x6000F5D // FF9StateSystem::get_Battle
This only restores 25% of max HP of the 1st character only (and doesn't even check if it goes over the max HP limit)...
ldfld 0x4002267 // BattleState::FF9Battle
ldfld 0x4002230 // FF9StateBattleSystem::btl_list
ldfld 0x4000226 // BTL_DATA::next
ldfld 0x400022A // BTL_DATA::cur
ldfld 0x4000809 // POINTS::hp
call 0x6000F5D // FF9StateSystem::get_Battle
ldfld 0x4002267 // BattleState::FF9Battle
ldfld 0x4002230 // FF9StateBattleSystem::btl_list
ldfld 0x4000226 // BTL_DATA::next
ldfld 0x4000229 // BTL_DATA::max
ldfld 0x4000809 // POINTS::hp
ldc.i4.4
div
add
call 0x6000F5D // FF9StateSystem::get_Battle
ldfld 0x4002267 // BattleState::FF9Battle
ldfld 0x4002230 // FF9StateBattleSystem::btl_list
ldfld 0x4000226 // BTL_DATA::next
ldfld 0x400022A // BTL_DATA::cur
stfld 0x4000809 // POINTS::hp
Best is to use Memoria for that and add these lines instead, since you can surely use local variables when replacing C# code:Code: [Select]for (BTL_DATA next = FF9StateSystem.Battle.FF9Battle.btl_list.next; next != null; next = next.next)
Much simpler indeed ^^'
if (next.bi.player != 0 && next.cur.hp>0)
next.cur.hp = min(next.cur.hp + next.max.hp / 4, next.max.hp);
@Gordo98: What you want to do is not related to AI but to the battle system, so CIL code or C# again :/
And increasing the duration of status effects is not possible with HW, as explained here (http://forums.qhimm.com/index.php?topic=14315.msg255569#msg255569). The best you can do is to change the tick for poison/venom/regen.
SetPartyReserve( 0 )
SetCharacterData( character_id, 1, 255, 255, 255 ) // By using 255 in the other arguments, you don't change the value
SetPartyReserve( 255 ) // May be different if you don't want the 8 regular characters to be available
Hello everyone, being a fan of Final Fantasy 9 especially, I hoped to see its output on PC and the possibility of being able to create it in HD, to redo it in 3D the ideal would be to get the walkmesh, as well as the coordinates camera and each environment to be able to work on it, I am completely null on the mod of FF IX so I wondered if someone had a complete pack to provide me so that I can take care of it? I had already done previously on FF 7 for those who know me :) But FF7 never interest me as much as the 9 and I would like to spend my time on the environment of the 9 which attracts me more and give the opportunity someone to do something :)
I could see new walkmeshes would provide possibility to import new backgrounds in assets; but whole 3D . In that case, the backgrounds would be kicked, and instead add 3D environments (maps) in the assets. No need for a walkmesh then, in such case. You see?
(Still dunno about the Vivi Cure bug).
I don't think its really possible to just switch everything out with 3d meshes,
Oh it's possible; being a Unity game after all.
Ah, I mean more as in, 'I don't think its a realistic goal', its possible, but the amount of extra things that'd need writing and editing is a bit much, plus actual 3D environments, if its still a static camera, would end up looking worse due to aliasing I'd imagine.
oh, but a real goal it is; determine is key. Minus the static camera; I always saw me eventually making ffix:tza with 3d & environments gambits (not a fan of backgrounds + fixed cameras; seems like an old method) with this engine still. T pointed where UI handled, it was extra work, but was determined to get gambits working here; at least I got somewhere! The button. I don't see it as completely impossible, more doable with determination. If Tirlititi confirms it's 100% impossible to do 3d environments; well, there's always back to walkmeshes for new backgrounds.
a huge amount of work,
So, I'm working on something else right now and I can't test about these bugs you mentioned, Incinerator, but I'll eventually take a look at them.
About 3D environment, it would be possible to change the engine to make it possible ; I don't even think that would be such a huge amount of work (the environment is already mostly 3D, engine-wise).
It would be way more difficult to recreate the scenes themselves in 3D, and I don't think they would look as great as prerendered backgrounds (not to mention that a lot of things are working visually because of static backgrounds: look at Alexandria's bell tower, its size from outside and its camera for inside).
Yeah, and recreate texture sets to match the environments from the prerendered backgrounds. Proper UV's.
I was forced to recreate in the environments in 3D anyways for ffix: tza the fmvs, considering it has different characters; look at the CGI, those as close to visual 3D of the environments in FF9 as one would get, without always seeing static positions. So, best start is to observe those, get a ball rolling and build off that.
It seems like it might be worth setting up a new topic then, instead of filling this one with our discussion.
I've had a look around, but I can't find any 3D or art related things for ffix: tza, do you happen to have anything online I can view at all?
I'm curious how close you got to the FF9 environments,
as I'm doing things myself recently, and thinking about eventually trying to get a few other people onboard if possible.
Creating textures to match the visuals shouldn't be difficult, most of the time, but its a given that anything we make is probably going to differ a little bit,
Battle (1, 938)
set VAR_[unused] variable = 1
Field( 16000 )
Variables of type "General" (Var_Gen...) are the ones saved in saved games. It doesn't matter whether it's an auto-save or a moogle save.
Function Blank_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
4) Last, for now.. there's a way to edit the portraits of the characters from menu etc? ( http://abload.de/img/retroarch-0424-150004neswt.png )
Easy. In sharedassets.assets (open with the Unity Viewer) Extract file FaceAtlas; rename to .png. When finished, must remove the '.png' extension to be imported back in. Portraits must be on the same scale, or will not fit.
if (IsInParty(0)) { // If Zidane is in the party
InitObject( 10, 0 ) // Init the 3D object and functions corresponding to Zidane
}
if (IsInParty(1)) { // If Vivi is in the party
InitObject( 11, 0 ) // Init the 3D object and functions corresponding to Vivi
}
// etc...
Except for that feature, NPCs and PCs are handled the same way.public static Font defaultFont = Font.CreateDynamicFontFromOSFont( "Arial" , 16 );
"Arial" is the font name and "16" is the font size (you can change them to your convenience).@ToraCarol: Albeoris's Memoria tool is able to change the text font of the game easily, but it's incompatible with HW right now.
But apparently, the tool dnSpy allows to edit the Assembly-CSharp.dll by changing the C# code, which is just as great. You can change the font by replacing the declaration of the variable "defaultFont", in the "EncryptFontManager" class, by this:Code: [Select]public static Font defaultFont = Font.CreateDynamicFontFromOSFont( "Arial" , 16 );
"Arial" is the font name and "16" is the font size (you can change them to your convenience).
Here's a list of fonts you can use.
ldfld 0x40008AD // FF9PLAY_SKILL::Base
ldloc.0
ldelem.u1
ldloc.s 6
ldloc.0
ldelem.u1
ble IL_0328
ldarg.1
ldind.ref
ldfld 0x40008AD // FF9PLAY_SKILL::Base
Just replace the line "ble IL_0328" by "br IL_0328" and it should remove the limit totally.ldfld 0x40009E2 // FF9PLAY_SKILL::Base
ldloc.0
ldelem.u1
ldloc.s 6
ldloc.0
ldelem.u1
ble IL_0328
ldarg.1
ldind.ref
ldfld 0x40009E2 // FF9PLAY_SKILL::Base
@Tedrainbow: Maybe you import the atlas file in a RGB format (Alpha channel, ie. transparency is not imported). In the Unity Assets Viewer's image options, you can choose the "RGBA" compression method to be sure to import the image without compression and with its transparency. If I remember correctly, the DXT5 compression method can use about 4 shades of transparency.
MIPS is the assembly language of the PSX. It doesn't exist anymore in the Steam version and is replaced by CIL code.
It is possible to move other characters than Zidane (actually, you just need to use the script code "DefinePlayerCharacter()" in another entry than Zidane's entry) but you'd need to script all the animations that come with that. Zidane can have an interaction with a lot of stuff through the game and sometimes has specific animations for these interactions that other characters just don't have.
This has nothing to do with MIPS but with Field scripts, by the way.
Ah-ha! So that's it! Thanks a bunch Tirlititi I give a try! And thank you for all the informations, I really didn't know; maybe I can give a shot just for Memoria and Crystal World, there are not alot of interactions requiered, except for "Jump", I guess.. :)
Let me know a thing.. what about if I want to add Lanì as a bonus character in the team (you know, you talk to her in Madain Sari and she decide to join your party) I don't mind to add her in cutscenes, just a playable characters in battles and stuff! ;D
Currently not possible as of right now, no character party data for Lani; but here’s a broader thought to get the ball rolling!:
1. Find a current character to replace (you’ll use as Lani) (Be it maybe: Blank/Marcus/Cinna
(Battle model only)
2. Design a portrait for Lani.
3. Model swap her model with said character (when it becomes workable).
4. Init the character from the script accordingly.
Best way to go about seeeing Lani as a bonus character; I have a similar set up with Nyx Ulric.
Hey thank you! This sound a good Idea! I can try swapping with Beatrix, maybe... but, how do I do exactly? Could you give me a little example with screenshots (you know I really don't want to mess something x''3) Can be the risk that can swaps of default for the entire game? (I mean, for Example, when Beatrix fight with Steiner, In that case I still have Beatrix or I'll total swap her with Lanì?)
That’s why I suggested: Blank, Cinna or Marcus. Yes if you model swap Beatrix it will affect scenes with Beatrix as a whole; except the battles against her, as that uses a different model. But to remain on the sure side, select between the tantalus troupe.
The model importer is in Hades workshop’s unity assets viewer. Explore archive p0data4.bin and locate Lani, export first, find said character to be replaced main model internal file name. Rename Lani’s file accordingly. But model swapping characters/importing new doesn’t work yet. It does not crash hades workshop, but it does crash in game.
Pardon, I must also note: replace any characters, be it even Blank/Cinna/Marcus, requires script editing elsewhere, otherwise, you may encounter unwanted entries during the game. Lani fighting on the theater stage and many more like scenarios to be thought out prior to. Unless such really is desired and in that case: go for it! By all means!
But model swapping characters/importing new doesn’t work yet. It does not crash hades workshop, but it does crash in game.
The model importer is in Hades workshop’s unity assets viewer. Explore archive p0data4.bin and locate Lani, export first, find said character to be replaced main model internal file name.
UPDATE:
Sorry to bother again, you guys but I have a little big problem...so, I'm trying to add Blank in the Scene of Ipsen Castle, and the first part works well, for the second I have a little problem.. I haven't added him yet in the field ( I need to know how it works, because it's not related to the party in this case) so the last variable I did is "Blank_16" (he speaks to Zidane, after Steiner) so I terminated the enter in the Main_25
Perhaps showing the script functions you have for Blank_16, hard to tell what's up or down, without it.
And what exactly did you terminate in function Main_25? Which doesn't sound right either way.
Hah, yup... sorry
That's it. Those are the only things I edited on this field.. maybe I was wrong with something... :-[
if ( VARL_GenBool_7173 ) {
InitObject( 13, 0 ) // Beatrix Initiate
InitObject( 1, 0 ) // Blank Initiate
}
Function Main_25
TerminateEntry( 6 )
TerminateEntry( 8 )
TerminateEntry( 7 )
TerminateEntry( 11 )
TerminateEntry( 9 )
TerminateEntry( 10 )
TerminateEntry( 12 )
if ( VARL_GenBool_7173 ) {
TerminateEntry( 13 ) // Terminate Entry_Beatrix
TerminateEntry( 1 ) // Terminate Entry_Blank
}
return
Tirititi- It is possible add one new NPC which learn add bonus Attack, Defense, Evade, Magic Defense or Magic Evade for equals 10,000 Gils?
It is possible ?
Thanx so much..
Alright, I just looked at script: Main_25 in field: Ipsen's Castle/Entrance. I ask, do you have Beatrix in this scene as well? I see a TerminateEntry(13) on your screenshot there.
Also in function: Main_Init/case: 10560, I see there isn't an InitObject( 6, 0 ) (which ought to be Vivi's Init), that maybe an area of issue there, must test. I'm assuming: InitObject( 1, 0 ) is Entry_Blank...
My initial guess from here would be to add Blank to the scene much as Beatrix is added to this scene in Alternate Fantasy; a variable. You might be able to get around adding his entry right below hers.
Example:
In case: 10560 of function: Main_InitCode: [Select]if ( VARL_GenBool_7173 ) {
InitObject( 13, 0 ) // Beatrix Initiate
InitObject( 1, 0 ) // Blank Initiate
}
Main_25 function:Code: [Select]Function Main_25
TerminateEntry( 6 )
TerminateEntry( 8 )
TerminateEntry( 7 )
TerminateEntry( 11 )
TerminateEntry( 9 )
TerminateEntry( 10 )
TerminateEntry( 12 )
if ( VARL_GenBool_7173 ) {
TerminateEntry( 13 ) // Terminate Entry_Beatrix
TerminateEntry( 1 ) // Terminate Entry_Blank
}
return
If you don't want Beatrix in this scene, remove her functions from said above.
Thank you Incinerator, when I'm home I give a try!
Thank you Incinerator, when I'm home I give a try!
About the model swap, to distinguish the battle model from the other I have to open it with a 3d program, or else?
And the animations? I can try to looking for all the animations, but you know is there's a particular way to show the preview? Maybe the same program for open models?
You know I don't want to go wrong with something when I'll try to swap Lani and Cinna :P
UPDATE: Mmh, maybe I figured how to distinguish the battle model, in the Field there's "Set Model" and the number, so the other one is the battle model..right?
Mhmh..nope, nothing changed.. :oops:
ps: InitObject (13 0) is Amarant, Vivi is InitObject (7,0) in my case.
Model swapping and/or importing doesn't work yet with the model tool.
Try starting from a clean slate, and then test the function.
I know for sure that the problem is something with blank.. but I really don't get what.. :-\ I'll try for a third time..
Thank you anyway, again.
I'd see where'd you come from there; I too had problems with Blank and this particular field. So, I ended up using an emergency function to save it all.
I simply did not put Blank in..
missing piece to the puzzle?
WindowSync( 0, 128, DialogID )
if ( GetDialogChoice==0 ) { // "Amarant..." is chosen
SetPartyReserve( 255 )
SetCharacterData( 7, 0, 255, 5, 7 )
} else if ( GetDialogChoice==1 ) { // "Blank ofc!" is chosen
SetPartyReserve( 1215 )
SetCharacterData( 11, 0, 255, 21, 12 )
}
I know Tirlititi mentioned a way to choose between Blank and Amarant without replacing
where i put this?Code: [Select]WindowSync( 0, 128, DialogID )
if ( GetDialogChoice==0 ) { // "Amarant..." is chosen
SetPartyReserve( 255 )
SetCharacterData( 7, 0, 255, 5, 7 )
} else if ( GetDialogChoice==1 ) { // "Blank ofc!" is chosen
SetPartyReserve( 1215 )
SetCharacterData( 11, 0, 255, 21, 12 )
}
Everytime i try to put this it says "unexpected line {" or something like this.. so where i need to put it exactly??? Between WHICH lines??? Thank you if you'll help :)
DisableMove( )
DisableMenu( )
WindowSync( 1, 128, 0 ) \\ dialog text with choice (set in Texts panel - example below)
if ( GetDialogChoice == 0 ) {
SetPartyReserve( 2143 )
SetCharacterData( 11, 0, 14, 21, 13 )
SetName( 11, 0 ) \\ Or Amarant's name will set over Blank's...
WindowSync( 1, 128, 1 ) \\ A text "Blank has joined the party!" or something similar.
set VARL_GenBool_8012 = 1
FadeFilter( 6, 16, VAR_GlobUInt8_17, 255, 255, 255 )
EnableMove( )
EnableMenu( )
Wait( 16 )
FadeFilter( 7, 16, VAR_GlobUInt8_17, 0, 0, 0 )
} else {
SetPartyReserve( 255 )
SetCharacterData( 7, 0, 7, 5, 7 )
Menu( 1, 7 ) \\ Set name back to Amarant etc.
WindowSync( 1, 128, 2 ) \\ A text "Amarant rejoins the party!" or similar.
FadeFilter( 6, 16, VAR_GlobUInt8_17, 255, 255, 255 )
EnableMove( )
EnableMenu( )
Wait( 16 )
FadeFilter( 7, 16, VAR_GlobUInt8_17, 0, 0, 0 )
}
if ( GetDialogChoice == 0 ) {
FadeFilter( 7, 16, VAR_GlobUInt8_17, 0, 0, 0 )
} else {
TimedTurn( VAR_GlobUInt8_16, 16 )
WaitTurn( )
EnableMove( )
0x27( 255 )
EnableMenu( )
}
return
[STRT=140,4][PCHC=2,1][IMME]NPC
"Who'll you replace?"
[CHOO][MOVE=18,0]Blank with Amarant
[MOVE=18,0]Amarant with Blank
it uses "TimedTurn( VAR_GlobUInt8_16, 16 )" without showing how "VAR_GlobUInt8_16" is setup.
I don't say it's wrong, I say it's incomplete. You didn't show the first lines of the function.
if ( ( GetRandom % 100 ) < 1 ) {
InitObject( X, 0 )
}
Where "X" is the entry of the chest. With this, the chest will appear with only 1/100 chances each time the player enters the field.The cameras of the fields are a bit weirdly stored and, last time I tried, I couldn't have them properly readed.
uint16 tileset_size // I don't remember if it's the whole file or only tiles
uint16 depth_shift // ???
uint16 tileanim_count
uint16 tileset_count
uint16 light_count
uint16 camera_count
uint32 tileanim_offset // Offsets are absolute with respect to the .bgs file
uint32 tileset_offset
uint32 light_offset
uint32 camera_offset
int16 origin_y // The Y coordinate is called Z in the game's source code ; it's the depth
int16 current_y // All these coordinates don't seem to be used anyway
int16 origin_x
int16 origin_z
int16 current_x
int16 current_z
int16 min_x
int16 max_x
int16 min_y
int16 max_y
int16 screen_x
int16 screen_y
...
// At camera_offset:
uint16 distance // "proj" in the source code
int16[9] matrix_3x3
int32 offset_x
int32 offset_z
int32 offset_y
int16 center_offset_x
int16 center_offset_y
int16 offset_width
int16 offset_height
int16 min_x // "vrpMinX" in the source code
int16 max_x
int16 min_y
int16 max_y
int32 depth
The main problem for me is the 3x3 matrix: I don't know to which OpenGL matrix it corresponds. I got bad views when I tried to do what seemed logical to me considering how the source code uses everything.
Note that the PSX cameras for the battle scenes are in the .raw17 (of archive p0data2) together with the enemy attack sequencing (and some datas related, like animation lists). But maybe they are ignored for the Steam version and they use other cameras somewhere else.
It seems weird to me that models would need some special setting to have a correct light.
0xA9( 250 )
FadeFilter( 7, 16, VAR_GlobUInt8_17, 0, 0, 0 )
SetDialogProgression( 0 )
WindowAsync( 0, 16, 493 )
Wait( 12 )
while ( !GetDialogProgression ) {
Wait( 1 )
}
while ( !IsButton(655360L) ) {
Wait( 1 )
}
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 )
CloseWindow( 0 )
WindowAsync( 0, 16, 494 )
RaiseWindows( )
WaitWindow( 0 )
TerminateEntry( 2 )
RunScript( 2, 14, 13 )
if ( VAR_GlobUInt8_17 == 255 ) {
set Op66(( GetData_12 - 160 ), ( GetData_13 - 112 ))
}
----------------------------------->HERE ENDS BLANK CODE AND STARTS THE AMARANT ONE
0xA9( 250 )
FadeFilter( 7, 16, VAR_GlobUInt8_17, 0, 0, 0 )
SetDialogProgression( 0 )
WindowAsync( 0, 16, 224 )
Wait( 12 )
while ( !GetDialogProgression ) {
Wait( 1 )
}
while ( !IsButton(655360L) ) {
Wait( 1 )
}
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 )
CloseWindow( 0 )
WindowAsync( 0, 16, 225 )
RaiseWindows( )
WaitWindow( 0 )
TerminateEntry( 14 )
RunScript( 2, 9, 14 )
if ( VAR_GlobUInt8_17 == 255 ) {
set Op66(( GetData_12 - 160 ), ( GetData_13 - 112 ))
}
I don't remember messing with the camera when I added Beatrix to this battle and it works fine.
I messed with the battle, but not with the camera.
I have seen several people doing that fight without bug, so I guess it's your version that glitches. The second Abadon uses the same functions as the first (even if it has a different attack pattern).
I didn't touched that script at all, nothing about the "Enemies" category..
Ha! So that's it.. I imagined so I've tried to check Yesterday..but I didn't know how to do exactly, can you give me a hint?
This script had to have been edited for Blank to appear in this battle.
I say this because, with Blank already in the party, during this event, the only battle he would be initiated automatically in be the first one against the Amdusias. (Amarant switch to Blank)
The second battle against the Abadon (Steiner Quina Zidane) Unless the script as been edited to add Blank to this battle, he wouldn't be there.
@Incinerator
So why, in my case, Blank is in the battle scene anyway? I mean the actual problem is the camera that cut out Steiner, and then Zidane.. but you say it may be also because of the Enemy script?
As I said I didn't edited at all the Enemy script.. I added Blank just in the Main Script.. on the Fields! :| So yeah, before the start of the battle with Abadon ^^''Had a feeling. Knew you did something like that.
change a function of the AI script? If so, what are those changes?
Hey all, is there anything new in the realm of adding the bonus party members as their own slots rather than shared slots with other party members?
hi , read your explanation in your post on steam about how to extract beatrix out of your mod , but i didn't understand exactly how we will get her once we accomplish the method II , i mean: she will just appear and stay in the party selection screen ? she will substitute a character in battle ?
Alright, so he may not have changed the Enemy script so far, yet it be an AI script Blank causing a glitch with the battle camera when Zidane comes in.
@Tetraspore: No, adding the three Tantalus members to the party is still relying on shared slots.
It is in the realm of possible to add slots to them, because it's in the engine source code (that can be modded using Albeoris's Memoria or other C# DLL editing tools like dnSpy). It however requires a big amount of work and it would be hard to deal with the interface (in the party selection menu and for the shop portraits).
The game is designed with 9 character slots ; a lot of datas and static numbers are relying on that, not to mention that the Field scripts are, as for them, expecting to have 8 team characters at some points (same problem with Beatrix).
I am not interested myself in adding Blank, Marcus or Cinna to the team of permanent characters, because I don't see the point both gameplay-wise and story-wise. But if I ever get into it, I'll let you know.
@ploppo: You're welcome :)
As ToraCarol said, you'll have the ability to recruit her. That means you must go to Alexandria's castle after getting the airship where you can meet her and let her come in the team. Then she'll appear in the party selection menu just like any other playable character.
@ToraCarol: no, sorry... As said, HW has little to no control over the cameras. I really don't know why the camera is scrambled for you and not for me (I mean, when you add Blank in your mod versus when I add Beatrix in mine).
I will release a new version of HW pretty soon (surely this week-end). I have investigated an "auto-translation" feature for translating texts automatically and, while I saw that it was possible, it would have delayed too much the next version (that has important bug fixes among other things).
So there will be an auto-translate in the future, but not in the upcoming version.
Good afternoon everyone. I am a complete newb when it comes to this stuff. I downloaded HW and was messing around with some text for items and abilities, etc. Just to learn how to use this and test it out. But I cannot figure out how to actually apply my changes to my Steam version of FF9. I cannot seem to find a basic tutorial of how to use HW. Can anyone help me out? Forgive me if this is not the right place to ask. Feel free to redirect me if necessary. Thanks!
Good afternoon everyone. I am a complete newb when it comes to this stuff. I downloaded HW and was messing around with some text for items and abilities, etc. Just to learn how to use this and test it out. But I cannot figure out how to actually apply my changes to my Steam version of FF9. I cannot seem to find a basic tutorial of how to use HW. Can anyone help me out? Forgive me if this is not the right place to ask. Feel free to redirect me if necessary. Thanks!
I don't know either... You have weird problems seriously ^^'
Please show your codes in which you add Blank in the battle. I also need to see the "SetCharacterData" line that you use for setting up Blank.
Function Main_Init
InitObject( 1, 128 )
while ( !( GetBattleLoadState & 16 ) ) {
Wait( 1 )
set VAR_GenUInt8_206 = GetRandom
}
set #( VAR_GlobUInt16_24 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 0 ) )
set #( VAR_GlobUInt16_24 |= ( SV_PlayerTeam[MODEL_TYPE] ==$ 1 ) )
set #( VAR_GlobUInt16_26 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 2 ) )
set #( VAR_GlobUInt16_28 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 3 ) )
set #( VAR_GlobUInt16_28 |= ( SV_PlayerTeam[MODEL_TYPE] ==$ 4 ) )
set #( VAR_GlobUInt16_28 |= ( SV_PlayerTeam[MODEL_TYPE] ==$ 5 ) )
set #( VAR_GlobUInt16_28 |= ( SV_PlayerTeam[MODEL_TYPE] ==$ 6 ) )
set #( VAR_GlobUInt16_30 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 7 ) )
set #( VAR_GlobUInt16_30 |= ( SV_PlayerTeam[MODEL_TYPE] ==$ 8 ) )
set #( VAR_GlobUInt16_32 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 9 ) )
set #( VAR_GlobUInt16_34 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 10 ) )
set #( VAR_GlobUInt16_34 |= ( SV_PlayerTeam[MODEL_TYPE] ==$ 11 ) )
set #( VAR_GlobUInt16_36 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 12 ) )
set #( VAR_GlobUInt16_38 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 13 ) )
set #( VAR_GlobUInt16_40 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 15 ) )
set #( VAR_GlobUInt16_42 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 16 ) )
set #( VAR_GlobUInt16_42 |= ( SV_PlayerTeam[MODEL_TYPE] ==$ 17 ) )
set #( VAR_GlobUInt16_44 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 18 ) )
if ( #VAR_GlobUInt16_28 ) {
set VAR_GlobUInt8_46++
set VAR_GlobUInt16_28[MODEL_OFF] =$ 65535L
set VAR_GlobUInt16_28[SHADOW] =$ 0
set VAR_GlobUInt16_42[MODEL_OFF] =$ 65535L
set VAR_GlobUInt16_42[SHADOW] =$ 0
}
while ( GetBattleState != 1 ) {
if ( #VAR_GlobUInt16_42 ) {
set VAR_GlobUInt16_42[PRESENCE_OFF] =$ 1
}
Wait( 1 )
}
if ( #VAR_GlobUInt16_28 ) {
set VAR_GlobUInt16_28[PRESENCE_OFF] =$ 1
}
Wait( 1 )
RunBattleCode( 35, 0 )
while ( GetBattleState != 4 ) {
Wait( 1 )
}
return
Function Main_Loop
if ( VAR_GlobUInt8_47 && ( !VAR_LocUInt8_0 ) ) {
set VAR_LocUInt8_0++
while ( IsAttacking != 0 ) {
Wait( 1 )
}
if ( GetBattleState != 4 ) {
return
}
RunBattleCode( 32, 0 )
while ( GetBattleState != 1 ) {
Wait( 1 )
}
set VAR_GlobUInt8_52 = 255
set VAR_GlobUInt8_48++
while ( !VAR_GlobUInt8_49 ) {
Wait( 1 )
}
set VAR_GlobUInt16_28[PRESENCE_ON] =$ 1
set VAR_GlobUInt16_42[PRESENCE_ON] =$ 1
set VAR_GlobUInt8_50++
while ( !VAR_GlobUInt8_51 ) {
Wait( 1 )
}
Wait( 5 )
set VAR_GlobUInt16_28[MODEL_ON] =$ 65535L
set VAR_GlobUInt16_28[SHADOW] =$ 1
set VAR_GlobUInt16_42[MODEL_ON] =$ 65535L
set VAR_GlobUInt16_42[SHADOW] =$ 1
Wait( 40 )
RunBattleCode( 36, 9 )
BattleDialog( 11 )
Wait( 45 )
if ( #( SV_PlayerTeam & VAR_GlobUInt16_28 ) ) {
if ( !( ( #Matching(VAR_GlobUInt16_28[STATUS_AUTO_A], 2097152L) ) && ( !( #Matching(VAR_GlobUInt16_42[STATUS_AUTO_A], 2097152L) ) ) ) ) {
RunBattleCode( 36, 10 )
} else {
RunBattleCode( 36, 11 )
}
}
BattleDialog( 12 )
Wait( 60 )
RunBattleCode( 35, 0 )
while ( GetBattleState != 4 ) {
Wait( 1 )
}
}
Wait( 1 )
loop
CureStatus( 0, 127 )
CureStatus( 1, 127 )
CureStatus( 3, 127 )
CureStatus( 2, 127 )
CureStatus( 4, 127 )
CureStatus( 5, 127 )
CureStatus( 7, 127 )
CureStatus( 6, 127 )
CureStatus( 8, 127 )
--------------- HERE I STARTED
SetCharacterData( 11, 1, 14, 21, 7 )
SetName( 11, 92 )
set Setting_PartyReserve = 1215
SetPartyReserve( Setting_PartyReserve )
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_GlobBool_147 = AddParty(2)
set VAR_GlobBool_147 = AddParty(0)
set VAR_GlobBool_147 = AddParty(11)
set VAR_GlobBool_147 = AddParty(65535)
set VARL_GenUInt8_303 = 0
set VAR_GlobInt16_8 = ( VAR_GlobInt16_10 = ( VAR_GlobInt16_12 = ( VAR_GlobInt16_14 = 99 ) ) )
if ( 1 ) {
set VARL_GenUInt8_303++
set VAR_GlobInt16_8 = 2
}
if ( 1 ) {
set VARL_GenUInt8_303++
set VAR_GlobInt16_10 = 0
}
if ( 1 ) {
set VARL_GenUInt8_303++
set VAR_GlobInt16_12 = 11
}
if ( 0 ) {
set VARL_GenUInt8_303++
set VAR_GlobInt16_14 = 65535
----------------- HERE I FINISHED
}
set VAR_GlobBool_148 = ( VAR_GlobBool_149 = ( VAR_GlobBool_150 = ( VAR_GlobBool_151 = 0 ) ) )
if ( VAR_GlobInt16_8 != 99 ) {
if ( GetHP(VAR_GlobInt16_8) == 0 ) {
set VAR_GlobBool_148 = 1
}
}
if ( VAR_GlobInt16_10 != 99 ) {
if ( GetHP(VAR_GlobInt16_10) == 0 ) {
set VAR_GlobBool_149 = 1
}
}
if ( VAR_GlobInt16_12 != 99 ) {
if ( GetHP(VAR_GlobInt16_12) == 0 ) {
set VAR_GlobBool_150 = 1
}
}
if ( VAR_GlobInt16_14 != 99 ) {
if ( GetHP(VAR_GlobInt16_14) == 0 ) {
set VAR_GlobBool_151 = 1
}
}
if ( ( ( ( VAR_GlobBool_148 + VAR_GlobBool_149 ) + VAR_GlobBool_150 ) + VAR_GlobBool_151 ) == VARL_GenUInt8_303 ) {
if ( ( VAR_GlobInt16_8 != 99 ) && ( VAR_GlobBool_148 == 1 ) ) {
SetHP( VAR_GlobInt16_8, 1 )
}
if ( ( VAR_GlobInt16_10 != 99 ) && ( VAR_GlobBool_149 == 1 ) ) {
SetHP( VAR_GlobInt16_10, 1 )
}
if ( ( VAR_GlobInt16_12 != 99 ) && ( VAR_GlobBool_150 == 1 ) ) {
SetHP( VAR_GlobInt16_12, 1 )
}
if ( ( VAR_GlobInt16_14 != 99 ) && ( VAR_GlobBool_151 == 1 ) ) {
SetHP( VAR_GlobInt16_14, 1 )
}
}
CureStatus( 0, 127 )
CureStatus( 1, 127 )
CureStatus( 3, 127 )
CureStatus( 2, 127 )
CureStatus( 4, 127 )
CureStatus( 5, 127 )
CureStatus( 7, 127 )
CureStatus( 6, 127 )
CureStatus( 8, 127 )
if ( IsInParty(5) ) {
set Setting_OptionalQuina = 1
} else {
set Setting_OptionalQuina = 0
}
if ( ( ( Setting_PartyInitialized >> 0 ) & 1 ) == 0 ) {
SetCharacterData( 0, 1, 255, 9, 0 )
set Setting_PartyInitialized |= 1
}
if ( ( ( Setting_PartyInitialized >> 2 ) & 1 ) == 0 ) {
SetCharacterData( 2, 1, 255, 6, 2 )
set Setting_PartyInitialized |= 4
}
For model swapping, I'm working on it but I don't guarantee anything for the next release.
I want to add damage to the Break attacks Steiner has. So, it does damage like a regular attack, and also performs the Break (Power, Armor, etc.) Is there any way to do that?
case 33:
case 34:
case 35:
case 36:
btl_calc.CalcSub_101(cALC_VAR);
btl_calc.CalcSub_114(cALC_VAR);
if (btl_calc.CalcSub_121(cALC_VAR))
{
if (prog_no == 33)
{
DEF_PARAMS expr_F0B = target.defence;
expr_F0B.p_def /= 2;
}
else if (prog_no == 34)
{
target.elem.str = target.elem.str * 3 / 4;
}
else if (prog_no == 35)
{
DEF_PARAMS expr_F54 = target.defence;
expr_F54.m_def /= 2;
}
else if (prog_no == 36)
{
target.elem.mgc = target.elem.mgc * 3 / 4;
}
}
break;
The "CalcSub" lines are quite abstruse. case 33:
case 34:
case 35:
case 36:
btl_calc.CalcSub_101(cALC_VAR); // Accuracy for the break effect
btl_calc.CalcSub_114(cALC_VAR); // Shell hit rate malus for the break effect
if (((int)v.hit_rate > Comn.random16() % 100) && ((int)v.ev <= Comn.random16() % 100)) // conditionally lower stat
{
if (prog_no == 33)
{
DEF_PARAMS expr_F0B = target.defence;
expr_F0B.p_def /= 2;
}
else if (prog_no == 34)
{
target.elem.str = target.elem.str * 3 / 4;
}
else if (prog_no == 35)
{
DEF_PARAMS expr_F54 = target.defence;
expr_F54.m_def /= 2;
}
else if (prog_no == 36)
{
target.elem.mgc = target.elem.mgc * 3 / 4;
}
}
// Unconditionally damage the target:
btl_calc.CalcSub_13A(cALC_VAR); // Setup base damage like a physical strike
btl_calc.CalcSub_141(cALC_VAR); // Apply caster bonuses of Bersek/Trance and malus of Mini
btl_calc.CalcSub_143(cALC_VAR); // Apply target bonuses of Sleep/Mini and maluses of Defend/Protect
btl_calc.CalcSub_159(cALC_VAR); // Apply equipment elemental boosts of the spell element
btl_calc.CalcSub_203(cALC_VAR); // Setup the damage... Everything else is handled by "CalcResult"
break;
It's a kind of mix between "Break" spells and "Physical Strike" spells. while ( GetBattleState != 1 ) {
if ( #VAR_GlobUInt16_42 ) {
set VAR_GlobUInt16_42[PRESENCE_OFF] =$ 1
}
Wait( 1 )
}
Use these instead: while ( GetBattleState != 1 ) {
Wait( 1 )
}
if ( #VAR_GlobUInt16_42 ) {
set VAR_GlobUInt16_42[PRESENCE_OFF] =$ 1
}
Also, you should import the .hws file "LocalVariableSettings": in the AI scripts, it gives names to the local variables and make it much more readable (you'll see "dagger" and "blank" instead of "VAR_GlobUInt16_28" and "VAR_GlobUInt16_42" for example).@Tirlititi were the game store and assign the music to play during the random battles ? i like to substitute the usual battle them with the ost " you are not alone " :D
"2924": { // field ID
"138" // Enemy ID : "35", // Music to Play
@Incinerator but wait a minute : what option i have to look in hades workshop to do that ?
Also, I tweaked the way that 3D models are imported, especially when custom model hierarchy are used, but I couldn't make everything work unfortunatly :/
I saw that replacing the 3D models of main characters is quite complicated (even swapping models) but it is possible: it needs to really make it perfect to have the good animations (so, let's say you use Quina's model instead of Zidane's, you'd need to rename the animations of Quina to fit the names of the animations of Zidane, not to mention to import everything properly with the right path names)... I'm not sure if I can make the process easier because it seems very dependant to what the engine expects... and when there is a dummy animation together with the model in the p0data4 archive, it has to be imported as well (for some reason, it's important to have this dummy animation when it's there by default).
Accessory, enemy and NPC models are much easier to change than models of the main characters (for battles, there's an additional problem since normal battle models and trance battle models share their animations).
I will now work on Alternate Fantasy for a while. I'll make an international version first, but then I'll also work on the mod ; I'm planning to only work sparsely on HW while doing that.
Also, I have once again changed a lot of things related to .hws file format (for script and text datas) ; I have done tests to check if that goes without bugs and didn't find any, but everything is possible. So I advise you to have copies of you .hws files (anyway, these files are so low-sized that I advise to have backups of them in any case).
The AnimationClip '' used by the Animation component '443(Clone)' must be marked as Legacy.
zidane is using ultima ? :-o
@Tirlititi so i am the only one with this problem in the battle spot section ? the first 4 lines appear , but the other group of four lines doesn't appearDoesn't happen with me...
I believe he said with Ultima, it's something about the battle not being able to continue after using it as a regular spell.
Of all the enemy spells this one can be used. Even some of the [Enemy-Death] animation can work as spells given it added damage figure points.
One hopes for HW to edit spell animations more deeply.
Doesn't happen with me...
I will now work on Alternate Fantasy for a while. I'll make an international version first
It's stored resources.assets :: BtlEncountBgmMetaData.txt
It's arranged as:Code: [Select]"2924": { // field ID
"138" // Enemy ID : "35", // Music to Play
Though for You're not Alone event in particular, the function is ran from the script, with "RunSoundCode( 0, 0 )"; played throughout the scene. The three battles are not present in BtlEncountBgmMetaData.txt, to prevet the changing of music during battle encounter.
It is in the Main_Loop function of field: Pand./Mind Control IIRC.
Change it from the script; change it from p0data61.bin
@ToraCarol:
1) I don't know :/
The "set VAR_GlobUInt16_42[MODEL_OFF] =$ 65535L" line should be the one that hides the weapon if I am not mistaken. I'll look in the engine if there are special instances where it's not good enough.
2) You can select one of the "Seiken" command and link it to the other "Seiken" command because they share the same abilities anyway ; that frees 4 slots that you can distribute somewhere else. You can do the same with Dagger's summons (normal & trance commands).
3) I gave the answer to that: musics are stored in the p0data61 archive and you can swap/replace them at will. You only need to have your music in .ogg format (and define looping points if you want it to loop in-game ; it is a feature of .ogg files).
i need some more instructions :\ , i found the p0data61 in the unity assets section , and i found the song i want to replace and the one to make the substitution , but from there i can't see how i can switch those osts , also , in the main_loop section of pand\ming control i didn't found " RunSoundCode( 0, 0 ) " , but only " RunSoundCode( 16897, 48 ) " and some other numbers , but probably i wasn't clear enough , my objective is to have the ost " you are not alone " , during the random battles , not the opposite :D
it's possible to give to Blank a Trance comand too? Or is something kinda hard?
if (mesh == 65535 && btl.bi.player == 0) ...
I think that it should be "!= 0" instead: it was meant to take care of weapons only if the character is a team member and not the opposite.if ( #VAR_GlobUInt16_28 ) {
set VAR_GlobUInt8_46++
set VAR_GlobUInt16_28[MODEL_OFF] =$ 65535L
set VAR_GlobUInt16_28[SHADOW] =$ 0
set VAR_GlobUInt16_28[PRESENCE_OFF] =$ 1
set VAR_GlobUInt16_42[MODEL_OFF] =$ 65535L
set VAR_GlobUInt16_42[SHADOW] =$ 0
set VAR_GlobUInt16_42[PRESENCE_OFF] =$ 1
}
Unless I'm mistaken, it should not crash the game 8)
@ToraCarol: I think that you didn't get it. Once you have linked Seiken abilities and Summon abilities, it frees space for other commands. Once you have done that, you can add up to 12 spells in another command without being told that there's no space.
About Blank's sword... It's strange but I got it!
So actually, "set character[MODEL_OFF] =$ 65535L" hides weapons only for the enemies (it might be that they have weapons meshes but I don't think so, so it's useless) and not for the party characters.
"set character[PRESENCE_OFF] =$ 1" hides weapons (as well as other stuff ; the character doesn't seem to even exist when its presence is off) but it is called a bit later, just before the ATB appears and the battle starts.
Conclusion: Dagger's weapon also appears mid-air before the battle starts. I just checked it on a youtube video and, indeed, there is a very small window during which you can clearly see her weapon...
So, I think that it's another bug of the Steam version. In the "btl_mot::HideMesh" and "btl_mot::ShowMesh", there is a "if" line that is wrong:Code: [Select]if (mesh == 65535 && btl.bi.player == 0) ...
I think that it should be "!= 0" instead: it was meant to take care of weapons only if the character is a team member and not the opposite.
You may fix the bug in this particular battle by adding another PRESENCE_OFF line together with the shadow/model hiding (still keep the PRESENCE_OFF lines that are below):Code: [Select]if ( #VAR_GlobUInt16_28 ) {
Unless I'm mistaken, it should not crash the game 8)
set VAR_GlobUInt8_46++
set VAR_GlobUInt16_28[MODEL_OFF] =$ 65535L
set VAR_GlobUInt16_28[SHADOW] =$ 0
set VAR_GlobUInt16_28[PRESENCE_OFF] =$ 1
set VAR_GlobUInt16_42[MODEL_OFF] =$ 65535L
set VAR_GlobUInt16_42[SHADOW] =$ 0
set VAR_GlobUInt16_42[PRESENCE_OFF] =$ 1
}
About giving trance to someone else, I'll make a few tests but it may be possible to actually do it now with dnSpy/Albeoris's Memoria. Of course, unless you import another model, the trance appearance will be roughly the same as the normal state.
I don't guarantee anything though ^^'
You may fix the bug in this particular battle by adding another PRESENCE_OFF line together with the shadow/model hiding (still keep the PRESENCE_OFF lines that are below):Code: [Select]if ( #VAR_GlobUInt16_28 ) {
set VAR_GlobUInt8_46++
set VAR_GlobUInt16_28[MODEL_OFF] =$ 65535L
set VAR_GlobUInt16_28[SHADOW] =$ 0
set VAR_GlobUInt16_28[PRESENCE_OFF] =$ 1
set VAR_GlobUInt16_42[MODEL_OFF] =$ 65535L
set VAR_GlobUInt16_42[SHADOW] =$ 0
set VAR_GlobUInt16_42[PRESENCE_OFF] =$ 1
}
i want to become immune to the "snort"
i placed tantarian and ozma in the isle were normally we can find the yan , and now , every time i fight with tantarian or ozma , there isn't any music , so what's the procedure to solve this problem ?
Don't believe that possible (with basic editing?)
Snort removes a target from battle; don't think there's an innate way to be immune to that.
If I hear correctly, you placed Tantarian and Ozma fightable on the world map where Yans are originally found (on vile island??)
If so, and anytime you move/add an enemy to a new field to battle; for the encounter music to play, you must edit the BtlEncountBgmMetaData.txt for fields and/or WldEncountBgmMetaData.txt for world map enemies.
i placed them in vile island XD
That's what I thought, so yes, you must edit: WldEncountBgmMetaData.txt
Add the enemies' ID to the list.
ok but what exactly i must do to accomplish that ? i must open the unity engine assets with hades workshop , then how i proceed ? were can i find the enemy id ? and how can i change the music that is played when i face zon and tron ?
"9000": { // world loc. ID
"138" // Enemy ID : "35", // Music to Play (35 is boss battle theme)
Yes like Tirlititi said, use Unity assets viewer, open archive resources.assets, navigate and find WldEncountBgmMetaData.txt extract it.
You can see enemy id in HW by checking "Show Enemy IDs"; in WldEncountBgmMetaData.txt, you identify which BGM to play by placing it's ID with the syntax.
ex:Code: [Select]"9000": { // world loc. ID
"138" // Enemy ID : "35", // Music to Play (35 is boss battle theme)
For Zorn and Thorn, edit the BtlEncountBgmMetaData.txt and do the same.
@Incinerator sorry if i am taking so much time to understand but i have problems to find what you told me to find , in the archivie the options are : streaming assets , levels , shared assets , what's the option i must select ? and once i select it , what file i must chose ?
resources
so it must be : resources assets -> resources , right ? but i still don't find those two files , maybe i don't find them because they have a different name after the patch :O
They have the same name and are in resources.assets. Sort names alphabetically to aid in search the list.
@Incinerator ok , i am noticing something strange in those txt files : there is always the "0" as ost to play , and the ost number 0 is the main theme of the game , the other number used is the 61 , what's the meaning of this ? according to this values there are only two osts used , but this isn't really possible :\
BGM ID - 0 is the battle theme not title BGM.
Not sure what you're viewing, I can't check it right now; show what you're seeing.
”57”: “35”,
“211:”35”
1. Songmetadata is not related to this.
2. The ID of battle theme main is 0.
3. Bgm ID 61 is fairy battle theme.
4. Only place:Code: [Select]”57”: “35”,
“211:”35”
syntax in wldencountbgmmetadata.txt~all loc., (9000, 9001, etc.)
And lastly, this file is not changed from any patch you may have missed before. It still reads the same.
ok , but i also need to place them under every list for every "9000, 9001..."? , and equally important , in what position exactly i have to place them ? because the list under every world id is pretty long and i need to know if i can place those two captions one under the other one even if between and after those captions there are enemies id that doesn't match with the numeric order
I don’t know atm, which ID spot is vile island, so I’d put in every list, just to be sure/safe.
yup , but i also need to know were , i mean , is ok to place in a random spot between a line and another one , or i must chose a specific position ? i don't know if this can influence the result
Place it anywhere within the syntax.
i was thinking about the incompatibility between hades workshop and the engine editor memoria , maybe a solution can be this : if , and only if memoria put the spells data in a different place , but always in the same different place , it would be sufficient to find the new collocation , and set hades workshop to look in the zone were the spells data are placed , but i am not an hacker , i just tried to give a good suggestion XD
Memoria uses a different Assembly Csharp than the vanilla for starters; with Memoria methods embedded into it, be one of the reasons it’s incompatible. It edits the csharp. The closets one’s gonna get for now is to manually edit Assembly CSharp with a C# decompiler/compiler. (dnspy, Visual studio etc.)
i am sure that trilititi and the creator of memoria can fix this if they collaborate , not now , but probably once they create the final version of their program :Ddon't think there'll technically be a final version for the program. between bug fixes, and features added; declaring final version could mean a possible stop growth in modding compatibility.
don't think they technically be a final version for the program. between bug fixes, and features added; declaring final version could mean a possible stop growth in modding compatibility.
that'll be quite the wait then otherwise, as that will be completely up to them. In the meantime thought, manually C# is the route if you use HW and what Memoria similar features.
They both have their own program, doing their own thing. All respect I have for the both of them in their work & programs.
I tried again, to check and try that "Lani swap". So, to test i tried to replace everything I found in p04data, so theBattleCinna is replaced now with everything of Enemy Lani. I know for sure that something is wrong but..the funny thing is that..NOTHING happens in the game I mean, it's like I didn't touched it! It really may be?
@Incinerator so now i assigned doomsday to freya , the problem is that the animation become bugged when freya perform it , is there a way to solve that with hades workshop ? i noticed that there are some options used to edit the spell animation but i prefer to have some istructions before try something
I tried again, to check and try that "Lani swap". So, to test i tried to replace everything I found in p04data, so theBattleCinna is replaced now with everything of Enemy Lani. I know for sure that something is wrong but..the funny thing is that..NOTHING happens in the game I mean, it's like I didn't touched it! It really may be?
If we’re hearing correctly, you did a successful model swap? Show screenshot if possible, Enemy_Lani replaced as BattleCinna as you speak.
No, no..unfortunately it isn't like this! ::) The fact "NOTHING happens" it means that nothing happens for real.. I mean that there is still Cinna, even if I imported Meshes, Gameobjects etc and replaced and added the missing texture and material..
@Incinerator but you are mentioning a comment in this discussion , or you are referring to the discussion in the steam forum ?
@Incinerator
you think it will be ok if i insert the text for ozma in this way ?
},
"9012": {
"5": "0",
"7": "0",
"8": "0",
"11": "0",
"25": "0",
"26": "0",
"42": "0",
"46": "0",
"48": "0",
"49": "0",
"50": "0",
"54": "0",
”57”: “35”,
“211:”35”
even after that attempt i still don't hear anything during the battle with ozma , i don't get it , i double checked the "61" ost , and it correspond with the one for the friendly monster, so what is my mistake ?
That’s exactly how it’s to be entered.
Likely because you didn’t put the ozma’s ID in all field loc. IDs, like I said before.
that's the strange thing , i did it , i placed those lines under all the (9000, 9001...), let's suppose that i didn't missed any map id , what else could be the cause, maybe the fact that since it is a boss i need some other setting to make that ost run ? ???
No, I’d check your entires again. It most certainly works, I’ve did it; tested it.
this is really strange , i tried to change the music that play when you fight the yan ( 784 ) under all the map id , still not a single change , it may depend on the fact that i changed the main battle ost ? and i really think i need your assistance with team viewer :\ , if i really didn't nothing wrong , then i think that i must baypass some sort of block , you think it is possible ?
Are you sure moved the edited resources.assets file from x86 folder to x64?
don't tell me that the changes to the sound file goes directly to the resources file of the x86 folder ?? :O
Exactly. That’s how it is with me. Even if I check Folder x64 in HW Unity Assets Viewer, it still only edits in Folder x86. Still.
No I don't. You can see music IDs in HW version 37c.
Under the Info Panel, should say something like: Music of IDXXX
p0data61
As I said before, Music BGM ID 61 is Friendly Monsters encounter; songmetadata IDs are different and unrelated to default music bgms.
@Tirlititi as you noticed , the "jump" ability of freya take several time to be active once she perform the jump, what i must modify to make sure that she attack instantly right after the jump ?
@Trilititi i will try to substitute amarant with blank , but i want to be sure that i can do that without have to touch the dialogues , i read from your guide that amarant and blank share almost every data that the game need in order to metabolize this swap , but if i can i would prefer to not touch the dialogues for now
thanks , now i want to first of all try with the swapping point in the invinicible , the strange thing is that all i found for "party" in the field invinicble/bridge ( first one )
Party( 4, 1 )
SetPartyReserve( 4095 ) // Adjust this argument if you want fewer people
SetCharacterData( 11, 1, 255, 21, 12 ) // Blank
UpdatePartyUI( )
} else {
Party( 0, 1 )
UpdatePartyUI( )
}
if ( IsInParty(5) ) {
set Setting_OptionalQuina = 1
This is good place to have such occasion.
I would test adding it after Party( 4, 1 )Code: [Select]Party( 4, 1 )
SetPartyReserve( 4095 ) // Adjust this argument if you want fewer people
SetCharacterData( 11, 1, 255, 21, 12 ) // Blank
UpdatePartyUI( )
} else {
Party( 0, 1 )
UpdatePartyUI( )
}
if ( IsInParty(5) ) {
set Setting_OptionalQuina = 1
Party( 4, 1 )
SetPartyReserve( 2431) // Adjust this argument if you want fewer people
SetCharacterData( 11, 1, 255, 21, 12 ) // Blank
SetCharacterData( 8, 1, 255, 19, 14 ) // Beatrix
UpdatePartyUI( )
} else {
Party( 0, 1 )
UpdatePartyUI( )
}
if ( IsInParty(5) ) {
set Setting_OptionalQuina = 1
btl_stat.AlterStatus(regist, 1073741824u);
regist.cmd[3].cmd_no = cmd.cmd_no;
regist.cmd[3].tar_id = ((cmd.cmd_no != 3) ? btl_util.GetStatusBtlID(1u, 0u) : cmd.tar_id);
cmd.tar_id = regist.btl_id;
return true;
And add a few lines before that return: btl_stat.AlterStatus(regist, 1073741824u);
regist.cmd[3].cmd_no = cmd.cmd_no;
regist.cmd[3].tar_id = ((cmd.cmd_no != 3) ? btl_util.GetStatusBtlID(1u, 0u) : cmd.tar_id);
cmd.tar_id = regist.btl_id;
btl.cmd[1].info.priority = 1;
if (btl.cmd[3].cmd_no == 3) {
btl_cmd.SetCounter(btl, 10u, 185, btl.cmd[3].tar_id);
} else {
btl_cmd.SetCounter(btl, 11u, 186, btl.cmd[3].tar_id);
}
return true;
I've not tested it but it should work (and she should perform the attack without any delay).RunBattleCode( 36, 0 ) // Change "0" to other numbers to try different cameras
Which string and which tutorial? What I did for Alternate Fantasy is a lot like what is described there (http://forums.qhimm.com/index.php?topic=14315.msg242890#msg242890).
For the Ipsen Curse, it's only a flag in the battles: you see that all the enemies of the Ipsen castle have this "Ipsen Curse" flag enabled.
It's a bit different for the Oeilvert Curse because that one also has an effect out of battles (you can't use magics). For this curse, there's the flag in the battles but also a general variable that is changed in the "Entrance" field of Oeilvert (I don't remember if it's turned off in the field where Ark is or if it's in one of the Desert Palace fields). The general variable is "Setting_MagicOff": as long as it's 1, magic is disabled in the player's menu.
Which string and which tutorial? What I did for Alternate Fantasy is a lot like what is described there (http://forums.qhimm.com/index.php?topic=14315.msg242890#msg242890).
For the Ipsen Curse, it's only a flag in the battles: you see that all the enemies of the Ipsen castle have this "Ipsen Curse" flag enabled.
It's a bit different for the Oeilvert Curse because that one also has an effect out of battles (you can't use magics). For this curse, there's the flag in the battles but also a general variable that is changed in the "Entrance" field of Oeilvert (I don't remember if it's turned off in the field where Ark is or if it's in one of the Desert Palace fields). The general variable is "Setting_MagicOff": as long as it's 1, magic is disabled in the player's menu.
Which string and which tutorial? What I did for Alternate Fantasy is a lot like what is described there (http://forums.qhimm.com/index.php?topic=14315.msg242890#msg242890).
For the Ipsen Curse, it's only a flag in the battles: you see that all the enemies of the Ipsen castle have this "Ipsen Curse" flag enabled.
It's a bit different for the Oeilvert Curse because that one also has an effect out of battles (you can't use magics). For this curse, there's the flag in the battles but also a general variable that is changed in the "Entrance" field of Oeilvert (I don't remember if it's turned off in the field where Ark is or if it's in one of the Desert Palace fields). The general variable is "Setting_MagicOff": as long as it's 1, magic is disabled in the player's menu.
case 19:
btl_calc.CalcSub_13A(cALC_VAR);
btl_calc.CalcSub_141(cALC_VAR);
btl_calc.CalcSub_143(cALC_VAR);
btl_calc.CalcSub_159(cALC_VAR);
if (btl_calc.CalcSub_152(cALC_VAR))
{
btl_calc.CalcSub_15E(cALC_VAR);
btl_calc.CalcSub_203(cALC_VAR);
btl_calc.CalcSub_270(cALC_VAR);
}
break;
You should put the line before the "CalcSub_20X" ("DoSetDamage_..." in the readable version).
Model importer update: still can't swap weapons. Tried swapping Javelin GameObject with Kain's Lance GameObject, to no avail.
@ToraCarol: About the animation at Ipsen Castle, I can't say anything without the script code that you use.
I still don't know how to handle cameras... You can try random things like using the following kind of lines after Blank joins the fight:Code: [Select]RunBattleCode( 36, 0 ) // Change "0" to other numbers to try different cameras
Sorry for late answers but that's a lot of things to read.
hey Tirlititi when modding field scripts where do they save on pc? in csharp or one of the data files?
Function Main_Loop
0xA9( 250 )
FadeFilter( 1, 64, VAR_GlobUInt8_17, 0, 0, 0 )
set Field_MusicVolume = 0
RunSoundCode2( 34305, 0, 128, Field_MusicVolume )
set VAR_GlobBool_167 = 0
if ( 1 ) {
set VAR_GlobBool_167 = 1
}
Wait( 64 )
RunSoundCode( 1792, 71 )
while ( SyncSounds != 0 ) {
Wait( 1 )
}
set VAR_GlobBool_167 = 0
RunSoundCode( 1792, 71 )
while ( SyncSounds != 0 ) {
Wait( 1 )
}
RunSoundCode1( 16903, 71, 1 )
RunSoundCode1( 16897, 71, 0 )
set Field_MusicVolume = 125
RunSoundCode2( 34305, 0, 128, Field_MusicVolume )
set VAR_GlobBool_167 = 0
RunScriptSync( 2, 7, 19 )
FadeFilter( 2, 15, VAR_GlobUInt8_17, 128, 128, 128 )
Wait( 15 )
WindowAsync( 1, 16, 273 )
RaiseWindows( )
WaitWindow( 1 )
if ( VAR_GlobUInt8_17 == 255 ) {
set Op66(( GetData_12 - 160 ), ( GetData_13 - 112 ))
}
0xA9( 250 )
FadeFilter( 7, 15, VAR_GlobUInt8_17, 0, 0, 0 )
Wait( 15 )
WindowSyncEx( 7, 0, 128, 274 )
MoveCamera( 180, 180, -100, 8 )
RunScriptAsync( 2, 7, 20 )
FadeFilter( 2, 15, VAR_GlobUInt8_17, 128, 128, 128 )
Wait( 15 )
WindowAsync( 1, 16, 275 )
RaiseWindows( )
WaitWindow( 1 )
WindowAsync( 1, 16, 276 )
RaiseWindows( )
WaitWindow( 1 )
WindowAsync( 1, 16, 277 )
RaiseWindows( )
WaitWindow( 1 )
WindowAsync( 1, 16, 278 )
RaiseWindows( )
WaitWindow( 1 )
WindowAsync( 1, 16, 279 )
RaiseWindows( )
WaitWindow( 1 )
WindowAsync( 1, 16, 280 )
RaiseWindows( )
WaitWindow( 1 )
WindowAsync( 1, 16, 281 )
RaiseWindows( )
WaitWindow( 1 )
if ( VAR_GlobUInt8_17 == 255 ) {
set Op66(( GetData_12 - 160 ), ( GetData_13 - 112 ))
}
0xA9( 250 )
FadeFilter( 7, 15, VAR_GlobUInt8_17, 0, 0, 0 )
Wait( 15 )
RunScriptSync( 2, 7, 21 )
FadeFilter( 2, 15, VAR_GlobUInt8_17, 128, 128, 128 )
Wait( 15 )
WindowAsync( 1, 16, 285 )
RaiseWindows( )
WaitWindow( 1 )
WindowAsync( 1, 16, 286 )
RaiseWindows( )
WaitWindow( 1 )
WindowAsync( 1, 16, 287 )
RaiseWindows( )
WaitWindow( 1 )
if ( VAR_GlobUInt8_17 == 255 ) {
set Op66(( GetData_12 - 160 ), ( GetData_13 - 112 ))
}
0xA9( 250 )
FadeFilter( 7, 15, VAR_GlobUInt8_17, 0, 0, 0 )
Wait( 15 )
WindowSyncEx( 7, 0, 128, 288 )
FadeFilter( 2, 15, VAR_GlobUInt8_17, 128, 128, 128 )
Wait( 15 )
WindowAsync( 1, 16, 289 )
RaiseWindows( )
WaitWindow( 1 )
WindowAsync( 1, 16, 290 )
RaiseWindows( )
WaitWindow( 1 )
WindowAsync( 1, 16, 291 )
RaiseWindows( )
WaitWindow( 1 )
if ( VAR_GlobUInt8_17 == 255 ) {
set Op66(( GetData_12 - 160 ), ( GetData_13 - 112 ))
}
0xA9( 250 )
FadeFilter( 7, 15, VAR_GlobUInt8_17, 0, 0, 0 )
Wait( 15 )
WindowSyncEx( 7, 0, 128, 292 )
WindowSyncEx( 7, 0, 128, 293 )
FadeFilter( 2, 15, VAR_GlobUInt8_17, 128, 128, 128 )
Wait( 15 )
WindowAsync( 1, 16, 294 )
RaiseWindows( )
WaitWindow( 1 )
WindowAsync( 1, 16, 295 )
RaiseWindows( )
WaitWindow( 1 )
WindowAsync( 1, 16, 296 )
RaiseWindows( )
WaitWindow( 1 )
WindowAsync( 1, 16, 297 )
RaiseWindows( )
WaitWindow( 1 )
WindowAsync( 1, 16, 298 )
RaiseWindows( )
WaitWindow( 1 )
if ( VAR_GlobUInt8_17 == 255 ) {
set Op66(( GetData_12 - 160 ), ( GetData_13 - 112 ))
}
0xA9( 250 )
FadeFilter( 7, 15, VAR_GlobUInt8_17, 0, 0, 0 )
Wait( 15 )
WindowSyncEx( 7, 0, 128, 299 )
WindowSyncEx( 7, 0, 128, 300 )
WindowSyncEx( 7, 0, 128, 301 )
RunScriptSync( 2, 7, 22 )
WindowSyncEx( 7, 0, 128, 302 )
WindowSyncEx( 7, 0, 128, 306 )
WindowSyncEx( 7, 0, 128, 303 )
WindowSyncEx( 7, 0, 128, 304 )
RunScriptSync( 2, 7, 23 )
WindowSyncEx( 7, 0, 128, 305 )
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 )
SetHP( 0, 1 )
SetHP( 6, 1 )
SetHP( 3, 1 )
SetHP( 1, 1 )
SetHP( 4, 1 )
SetHP( 5, 1 )
SetHP( 7, 1 )
SetHP( 2, 1 )
SetHP( 11, 1 )
SetPartyReserve( 1279 )
SetCharacterData( 11, 0, 255, 21, 12 )
SetName( 11, 74 )
if ( 1 ) {
Party( 4, 0 )
UpdatePartyUI( )
} else {
Party( 0, 0 )
UpdatePartyUI( )
}
if ( IsInParty(5) ) {
set Setting_OptionalQuina = 1
}
RunScriptAsync( 6, 7, 24 )
RunScriptAsync( 6, 8, 24 )
RunScriptAsync( 6, 10, 24 )
RunScriptAsync( 6, 14, 24 )
RunScriptAsync( 6, 12, 24 )
RunScriptAsync( 6, 9, 24 )
RunScriptAsync( 6, 13, 24 )
RunScriptAsync( 6, 11, 24 )
if ( GetEntryUniqueID(251) == GetEntryUniqueID(6) ) {
set VAR_GlobUInt8_46 = 0
if ( GetEntryUniqueID(252) == GetEntryUniqueID(12) ) {
set VAR_GlobUInt8_47 = 2
if ( GetEntryUniqueID(254) == GetEntryUniqueID(7) ) {
set VAR_GlobUInt8_48 = 3
set VAR_GlobUInt8_49 = 1
set VAR_GlobUInt8_42 = 4
set VAR_GlobUInt8_43 = 5
set VAR_GlobUInt8_44 = 6
set VAR_GlobUInt8_45 = 11
} else {
if ( GetEntryUniqueID(254) == GetEntryUniqueID(10) ) {
set VAR_GlobUInt8_49 = 4
set VAR_GlobUInt8_43 = 5
set VAR_GlobUInt8_44 = 6
set VAR_GlobUInt8_45 = 11
if ( GetEntryUniqueID(253) == GetEntryUniqueID(9) ) {
set VAR_GlobUInt8_48 = 3
set VAR_GlobUInt8_42 = 1
} else {
if ( GetEntryUniqueID(253) == GetEntryUniqueID(7) ) {
set VAR_GlobUInt8_42 = 3
set VAR_GlobUInt8_48 = 1
}
}
} else {
if ( GetEntryUniqueID(254) == GetEntryUniqueID(11) ) {
set VAR_GlobUInt8_49 = 5
set VAR_GlobUInt8_44 = 6
set VAR_GlobUInt8_45 = 11
if ( GetEntryUniqueID(253) == GetEntryUniqueID(9) ) {
set VAR_GlobUInt8_48 = 3
set VAR_GlobUInt8_42 = 1
set VAR_GlobUInt8_43 = 4
} else {
if ( GetEntryUniqueID(253) == GetEntryUniqueID(7) ) {
set VAR_GlobUInt8_48 = 1
set VAR_GlobUInt8_42 = 3
set VAR_GlobUInt8_43 = 4
} else {
if ( GetEntryUniqueID(253) == GetEntryUniqueID(10) ) {
set VAR_GlobUInt8_48 = 4
set VAR_GlobUInt8_42 = 3
set VAR_GlobUInt8_43 = 1
}
}
}
} else {
if ( GetEntryUniqueID(254) == GetEntryUniqueID(13) ) {
set VAR_GlobUInt8_49 = 6
set VAR_GlobUInt8_45 = 11
if ( GetEntryUniqueID(253) != GetEntryUniqueID(11) ) {
set VAR_GlobUInt8_44 = 5
if ( GetEntryUniqueID(253) != GetEntryUniqueID(10) ) {
set VAR_GlobUInt8_43 = 4
if ( GetEntryUniqueID(253) == GetEntryUniqueID(9) ) {
set VAR_GlobUInt8_42 = 1
set VAR_GlobUInt8_48 = 3
} else {
if ( GetEntryUniqueID(253) == GetEntryUniqueID(7) ) {
set VAR_GlobUInt8_48 = 1
set VAR_GlobUInt8_42 = 3
}
}
} else {
set VAR_GlobUInt8_48 = 4
set VAR_GlobUInt8_42 = 3
set VAR_GlobUInt8_43 = 1
}
} else {
set VAR_GlobUInt8_48 = 5
set VAR_GlobUInt8_42 = 3
set VAR_GlobUInt8_43 = 1
set VAR_GlobUInt8_44 = 4
}
} else {
if ( GetEntryUniqueID(254) == GetEntryUniqueID(8) ) {
set VAR_GlobUInt8_49 = 11
if ( GetEntryUniqueID(253) != GetEntryUniqueID(13) ) {
set VAR_GlobUInt8_45 = 6
if ( GetEntryUniqueID(253) == GetEntryUniqueID(9) ) {
set VAR_GlobUInt8_48 = 3
set VAR_GlobUInt8_42 = 1
set VAR_GlobUInt8_43 = 4
set VAR_GlobUInt8_44 = 5
} else {
if ( GetEntryUniqueID(253) == GetEntryUniqueID(7) ) {
set VAR_GlobUInt8_42 = 3
set VAR_GlobUInt8_48 = 1
set VAR_GlobUInt8_43 = 4
set VAR_GlobUInt8_44 = 5
} else {
if ( GetEntryUniqueID(253) == GetEntryUniqueID(10) ) {
set VAR_GlobUInt8_42 = 3
set VAR_GlobUInt8_43 = 1
set VAR_GlobUInt8_48 = 4
set VAR_GlobUInt8_44 = 5
} else {
if ( GetEntryUniqueID(253) == GetEntryUniqueID(11) ) {
set VAR_GlobUInt8_42 = 3
set VAR_GlobUInt8_43 = 1
set VAR_GlobUInt8_44 = 4
set VAR_GlobUInt8_48 = 5
}
}
}
}
} else {
set VAR_GlobUInt8_48 = 6
set VAR_GlobUInt8_42 = 3
set VAR_GlobUInt8_43 = 1
set VAR_GlobUInt8_44 = 4
set VAR_GlobUInt8_45 = 5
}
}
}
}
}
}
} else {
if ( GetEntryUniqueID(252) == GetEntryUniqueID(9) ) {
set VAR_GlobUInt8_47 = 3
set VAR_GlobUInt8_42 = 2
if ( GetEntryUniqueID(253) == GetEntryUniqueID(7) ) {
set VAR_GlobUInt8_48 = 1
if ( GetEntryUniqueID(254) == GetEntryUniqueID(10) ) {
set VAR_GlobUInt8_49 = 4
set VAR_GlobUInt8_43 = 5
set VAR_GlobUInt8_44 = 6
set VAR_GlobUInt8_45 = 11
} else {
if ( GetEntryUniqueID(254) == GetEntryUniqueID(11) ) {
set VAR_GlobUInt8_49 = 5
set VAR_GlobUInt8_43 = 4
set VAR_GlobUInt8_44 = 6
set VAR_GlobUInt8_45 = 11
} else {
if ( GetEntryUniqueID(254) == GetEntryUniqueID(13) ) {
set VAR_GlobUInt8_49 = 6
set VAR_GlobUInt8_43 = 4
set VAR_GlobUInt8_44 = 5
set VAR_GlobUInt8_45 = 11
} else {
if ( GetEntryUniqueID(254) == GetEntryUniqueID(8) ) {
set VAR_GlobUInt8_49 = 11
set VAR_GlobUInt8_43 = 4
set VAR_GlobUInt8_44 = 5
set VAR_GlobUInt8_45 = 6
}
}
}
}
} else {
if ( GetEntryUniqueID(253) == GetEntryUniqueID(10) ) {
set VAR_GlobUInt8_48 = 4
set VAR_GlobUInt8_43 = 1
RunScriptSync( 2, 6, 25 )
} else {
if ( GetEntryUniqueID(253) == GetEntryUniqueID(11) ) {
set VAR_GlobUInt8_48 = 5
set VAR_GlobUInt8_43 = 1
set VAR_GlobUInt8_44 = 4
RunScriptSync( 2, 6, 26 )
} else {
if ( GetEntryUniqueID(253) == GetEntryUniqueID(13) ) {
set VAR_GlobUInt8_48 = 6
set VAR_GlobUInt8_49 = 11
set VAR_GlobUInt8_43 = 1
set VAR_GlobUInt8_44 = 4
set VAR_GlobUInt8_45 = 5
}
}
}
}
} else {
if ( GetEntryUniqueID(252) == GetEntryUniqueID(7) ) {
set VAR_GlobUInt8_47 = 1
set VAR_GlobUInt8_42 = 2
set VAR_GlobUInt8_43 = 3
if ( GetEntryUniqueID(253) == GetEntryUniqueID(10) ) {
set VAR_GlobUInt8_48 = 4
RunScriptSync( 2, 6, 25 )
} else {
if ( GetEntryUniqueID(253) == GetEntryUniqueID(11) ) {
set VAR_GlobUInt8_48 = 5
set VAR_GlobUInt8_44 = 4
RunScriptSync( 2, 6, 26 )
} else {
if ( GetEntryUniqueID(253) == GetEntryUniqueID(13) ) {
set VAR_GlobUInt8_48 = 6
set VAR_GlobUInt8_49 = 11
set VAR_GlobUInt8_44 = 4
set VAR_GlobUInt8_45 = 5
}
}
}
} else {
if ( GetEntryUniqueID(252) == GetEntryUniqueID(10) ) {
set VAR_GlobUInt8_47 = 4
set VAR_GlobUInt8_42 = 2
set VAR_GlobUInt8_43 = 3
set VAR_GlobUInt8_44 = 1
if ( GetEntryUniqueID(253) == GetEntryUniqueID(11) ) {
set VAR_GlobUInt8_48 = 5
RunScriptSync( 2, 6, 26 )
} else {
if ( GetEntryUniqueID(253) == GetEntryUniqueID(13) ) {
set VAR_GlobUInt8_48 = 6
set VAR_GlobUInt8_49 = 11
set VAR_GlobUInt8_45 = 5
}
}
} else {
if ( GetEntryUniqueID(252) == GetEntryUniqueID(11) ) {
set VAR_GlobUInt8_42 = 2
set VAR_GlobUInt8_43 = 3
set VAR_GlobUInt8_44 = 1
set VAR_GlobUInt8_45 = 4
set VAR_GlobUInt8_47 = 5
set VAR_GlobUInt8_48 = 6
set VAR_GlobUInt8_49 = 11
}
}
}
}
}
} else {
if ( GetEntryUniqueID(251) == GetEntryUniqueID(12) ) {
set VAR_GlobUInt8_46 = 2
set VAR_GlobUInt8_42 = 0
if ( GetEntryUniqueID(252) == GetEntryUniqueID(9) ) {
set VAR_GlobUInt8_47 = 3
if ( GetEntryUniqueID(253) == GetEntryUniqueID(7) ) {
set VAR_GlobUInt8_48 = 1
if ( GetEntryUniqueID(254) == GetEntryUniqueID(10) ) {
set VAR_GlobUInt8_49 = 4
set VAR_GlobUInt8_43 = 5
set VAR_GlobUInt8_44 = 6
set VAR_GlobUInt8_45 = 11
} else {
if ( GetEntryUniqueID(254) == GetEntryUniqueID(11) ) {
set VAR_GlobUInt8_49 = 5
set VAR_GlobUInt8_43 = 4
set VAR_GlobUInt8_44 = 6
set VAR_GlobUInt8_45 = 11
} else {
if ( GetEntryUniqueID(254) == GetEntryUniqueID(13) ) {
set VAR_GlobUInt8_49 = 6
set VAR_GlobUInt8_43 = 4
set VAR_GlobUInt8_44 = 5
set VAR_GlobUInt8_45 = 11
} else {
set VAR_GlobUInt8_49 = 11
set VAR_GlobUInt8_43 = 4
set VAR_GlobUInt8_44 = 5
set VAR_GlobUInt8_45 = 6
}
}
}
} else {
if ( GetEntryUniqueID(253) == GetEntryUniqueID(10) ) {
set VAR_GlobUInt8_48 = 4
set VAR_GlobUInt8_43 = 1
RunScriptSync( 2, 6, 25 )
} else {
if ( GetEntryUniqueID(253) == GetEntryUniqueID(11) ) {
set VAR_GlobUInt8_48 = 5
set VAR_GlobUInt8_43 = 1
set VAR_GlobUInt8_44 = 4
RunScriptSync( 2, 6, 26 )
} else {
if ( GetEntryUniqueID(253) == GetEntryUniqueID(13) ) {
set VAR_GlobUInt8_48 = 6
set VAR_GlobUInt8_49 = 11
set VAR_GlobUInt8_43 = 1
set VAR_GlobUInt8_44 = 4
set VAR_GlobUInt8_45 = 5
}
}
}
}
} else {
if ( GetEntryUniqueID(252) == GetEntryUniqueID(7) ) {
set VAR_GlobUInt8_47 = 1
set VAR_GlobUInt8_43 = 3
if ( GetEntryUniqueID(253) == GetEntryUniqueID(10) ) {
set VAR_GlobUInt8_48 = 4
RunScriptSync( 2, 6, 25 )
} else {
if ( GetEntryUniqueID(253) == GetEntryUniqueID(11) ) {
set VAR_GlobUInt8_48 = 5
set VAR_GlobUInt8_44 = 4
RunScriptSync( 2, 6, 26 )
} else {
if ( GetEntryUniqueID(253) == GetEntryUniqueID(13) ) {
set VAR_GlobUInt8_48 = 6
set VAR_GlobUInt8_49 = 11
set VAR_GlobUInt8_44 = 4
set VAR_GlobUInt8_45 = 5
}
}
}
} else {
set VAR_GlobUInt8_43 = 3
set VAR_GlobUInt8_44 = 1
if ( GetEntryUniqueID(253) == GetEntryUniqueID(11) ) {
set VAR_GlobUInt8_47 = 4
set VAR_GlobUInt8_48 = 5
RunScriptSync( 2, 6, 26 )
} else {
if ( GetEntryUniqueID(253) == GetEntryUniqueID(13) ) {
set VAR_GlobUInt8_48 = 6
set VAR_GlobUInt8_49 = 11
if ( GetEntryUniqueID(252) == GetEntryUniqueID(10) ) {
set VAR_GlobUInt8_47 = 4
set VAR_GlobUInt8_45 = 5
} else {
if ( GetEntryUniqueID(252) == GetEntryUniqueID(11) ) {
set VAR_GlobUInt8_47 = 5
set VAR_GlobUInt8_45 = 4
}
}
}
}
}
}
} else {
if ( GetEntryUniqueID(251) == GetEntryUniqueID(9) ) {
set VAR_GlobUInt8_46 = 3
set VAR_GlobUInt8_42 = 0
set VAR_GlobUInt8_43 = 2
if ( GetEntryUniqueID(252) == GetEntryUniqueID(7) ) {
set VAR_GlobUInt8_47 = 1
if ( GetEntryUniqueID(254) == GetEntryUniqueID(11) ) {
set VAR_GlobUInt8_48 = 4
set VAR_GlobUInt8_49 = 5
set VAR_GlobUInt8_44 = 6
set VAR_GlobUInt8_45 = 11
} else {
if ( GetEntryUniqueID(254) == GetEntryUniqueID(13) ) {
set VAR_GlobUInt8_49 = 6
set VAR_GlobUInt8_45 = 11
if ( GetEntryUniqueID(253) == GetEntryUniqueID(10) ) {
set VAR_GlobUInt8_48 = 4
set VAR_GlobUInt8_44 = 5
} else {
if ( GetEntryUniqueID(253) == GetEntryUniqueID(11) ) {
set VAR_GlobUInt8_48 = 5
set VAR_GlobUInt8_44 = 4
}
}
} else {
if ( GetEntryUniqueID(254) == GetEntryUniqueID(8) ) {
set VAR_GlobUInt8_49 = 11
if ( GetEntryUniqueID(253) == GetEntryUniqueID(10) ) {
set VAR_GlobUInt8_48 = 4
set VAR_GlobUInt8_44 = 5
set VAR_GlobUInt8_45 = 6
} else {
if ( GetEntryUniqueID(253) == GetEntryUniqueID(11) ) {
set VAR_GlobUInt8_48 = 5
set VAR_GlobUInt8_44 = 4
set VAR_GlobUInt8_45 = 6
} else {
if ( GetEntryUniqueID(253) == GetEntryUniqueID(13) ) {
set VAR_GlobUInt8_44 = 4
set VAR_GlobUInt8_45 = 5
set VAR_GlobUInt8_48 = 6
}
}
}
}
}
}
} else {
if ( GetEntryUniqueID(252) == GetEntryUniqueID(10) ) {
set VAR_GlobUInt8_47 = 4
set VAR_GlobUInt8_44 = 1
if ( IsInParty(5) == 0 ) {
set VAR_GlobUInt8_45 = 5
set VAR_GlobUInt8_48 = 6
set VAR_GlobUInt8_49 = 11
} else {
if ( IsInParty(11) == 0 ) {
set VAR_GlobUInt8_45 = 6
set VAR_GlobUInt8_48 = 5
set VAR_GlobUInt8_49 = 11
} else {
if ( IsInParty(2) == 0 ) {
set VAR_GlobUInt8_48 = 5
set VAR_GlobUInt8_49 = 6
set VAR_GlobUInt8_45 = 11
}
}
}
} else {
if ( GetEntryUniqueID(252) == GetEntryUniqueID(11) ) {
set VAR_GlobUInt8_47 = 5
set VAR_GlobUInt8_48 = 6
set VAR_GlobUInt8_49 = 11
set VAR_GlobUInt8_44 = 1
set VAR_GlobUInt8_45 = 4
}
}
}
} else {
if ( GetEntryUniqueID(251) == GetEntryUniqueID(7) ) {
set VAR_GlobUInt8_46 = 1
set VAR_GlobUInt8_42 = 0
set VAR_GlobUInt8_43 = 2
set VAR_GlobUInt8_44 = 3
if ( IsInParty(4) != 1 ) {
set VAR_GlobUInt8_45 = 4
set VAR_GlobUInt8_47 = 5
set VAR_GlobUInt8_48 = 6
set VAR_GlobUInt8_49 = 11
} else {
if ( IsInParty(5) != 1 ) {
set VAR_GlobUInt8_47 = 4
set VAR_GlobUInt8_45 = 5
set VAR_GlobUInt8_48 = 6
set VAR_GlobUInt8_49 = 11
} else {
if ( IsInParty(11) != 1 ) {
set VAR_GlobUInt8_47 = 4
set VAR_GlobUInt8_48 = 5
set VAR_GlobUInt8_45 = 6
set VAR_GlobUInt8_49 = 11
} else {
if ( IsInParty(2) != 1 ) {
set VAR_GlobUInt8_47 = 4
set VAR_GlobUInt8_48 = 5
set VAR_GlobUInt8_49 = 6
set VAR_GlobUInt8_45 = 11
}
}
}
}
} else {
if ( GetEntryUniqueID(251) == GetEntryUniqueID(10) ) {
set VAR_GlobUInt8_46 = 4
set VAR_GlobUInt8_47 = 5
set VAR_GlobUInt8_48 = 6
set VAR_GlobUInt8_49 = 11
set VAR_GlobUInt8_42 = 0
set VAR_GlobUInt8_43 = 2
set VAR_GlobUInt8_44 = 3
set VAR_GlobUInt8_45 = 1
}
}
}
}
}
switch 8 ( VAR_GlobUInt8_42 ) from 0 {
case +0:
set VAR_GlobUInt8_51 = GetEntryUniqueID(7)
break
case +1:
set VAR_GlobUInt8_51 = GetEntryUniqueID(8)
break
case +2:
set VAR_GlobUInt8_51 = GetEntryUniqueID(13)
break
case +3:
set VAR_GlobUInt8_51 = GetEntryUniqueID(10)
break
case +4:
set VAR_GlobUInt8_51 = GetEntryUniqueID(11)
break
case +5:
set VAR_GlobUInt8_51 = GetEntryUniqueID(12)
break
case +6:
set VAR_GlobUInt8_51 = GetEntryUniqueID(14)
break
case +7:
set VAR_GlobUInt8_51 = GetEntryUniqueID(9)
break
}
switch 8 ( VAR_GlobUInt8_43 ) from 0 {
case +0:
set VAR_GlobUInt8_52 = GetEntryUniqueID(7)
break
case +1:
set VAR_GlobUInt8_52 = GetEntryUniqueID(8)
break
case +2:
set VAR_GlobUInt8_52 = GetEntryUniqueID(13)
break
case +3:
set VAR_GlobUInt8_52 = GetEntryUniqueID(10)
break
case +4:
set VAR_GlobUInt8_52 = GetEntryUniqueID(11)
break
case +5:
set VAR_GlobUInt8_52 = GetEntryUniqueID(12)
break
case +6:
set VAR_GlobUInt8_52 = GetEntryUniqueID(14)
break
case +7:
set VAR_GlobUInt8_52 = GetEntryUniqueID(9)
break
}
switch 8 ( VAR_GlobUInt8_44 ) from 0 {
case +0:
set VAR_GlobUInt8_53 = GetEntryUniqueID(7)
break
case +1:
set VAR_GlobUInt8_53 = GetEntryUniqueID(8)
break
case +2:
set VAR_GlobUInt8_53 = GetEntryUniqueID(13)
break
case +3:
set VAR_GlobUInt8_53 = GetEntryUniqueID(10)
break
case +4:
set VAR_GlobUInt8_53 = GetEntryUniqueID(11)
break
case +5:
set VAR_GlobUInt8_53 = GetEntryUniqueID(12)
break
case +6:
set VAR_GlobUInt8_53 = GetEntryUniqueID(14)
break
case +7:
set VAR_GlobUInt8_53 = GetEntryUniqueID(9)
break
}
switch 8 ( VAR_GlobUInt8_45 ) from 0 {
case +0:
set VAR_GlobUInt8_54 = GetEntryUniqueID(7)
break
case +1:
set VAR_GlobUInt8_54 = GetEntryUniqueID(8)
break
case +2:
set VAR_GlobUInt8_54 = GetEntryUniqueID(13)
break
case +3:
set VAR_GlobUInt8_54 = GetEntryUniqueID(10)
break
case +4:
set VAR_GlobUInt8_54 = GetEntryUniqueID(11)
break
case +5:
set VAR_GlobUInt8_54 = GetEntryUniqueID(12)
break
case +6:
set VAR_GlobUInt8_54 = GetEntryUniqueID(14)
break
case +7:
set VAR_GlobUInt8_54 = GetEntryUniqueID(9)
break
}
ReleaseCamera( 1, 8 )
Wait( 1 )
set VAR_GlobUInt8_41 = 0
RunScriptSync( 2, 7, 27 )
if ( VAR_GlobUInt8_17 == 255 ) {
set Op66(( GetData_12 - 160 ), ( GetData_13 - 112 ))
}
0xA9( 250 )
FadeFilter( 7, 16, VAR_GlobUInt8_17, 0, 0, 0 )
DisableMenu( )
Wait( 24 )
if ( IsInParty(0) & IsInParty(2) ) {
if ( ( IsInParty(1) & ( IsInParty(3) != 1 ) ) && ( IsInParty(6) == 1 ) ) {
set VAR_GlobUInt8_24 = VAR_GlobUInt8_43
set VAR_GlobUInt8_25 = VAR_GlobUInt8_49
RunScriptAsync( 6, 7, 24 )
RunScriptAsync( 6, 8, 24 )
RunScriptAsync( 6, 10, 24 )
RunScriptAsync( 6, 1, 24 )
RunScriptAsync( 6, 12, 24 )
RunScriptAsync( 6, 9, 24 )
RunScriptAsync( 6, 13, 24 )
RunScriptAsync( 6, 11, 24 )
RunScriptAsync( 6, 5, 14 )
while ( VAR_GlobUInt8_41 < 1 ) {
Wait( 1 )
}
RunScriptSync( 2, VAR_GlobUInt8_52, 28 )
RunScriptAsync( 6, 5, 15 )
while ( VAR_GlobUInt8_41 < 2 ) {
Wait( 1 )
}
RunScriptSync( 2, 254, 29 )
RunScriptSync( 2, 6, 30 )
while ( VAR_GlobUInt8_40 < 8 ) {
Wait( 1 )
}
Wait( 1 )
set VAR_GlobUInt8_40 = 0
Wait( 1 )
RunScriptAsync( 6, 5, 17 )
while ( VAR_GlobUInt8_41 < 3 ) {
Wait( 1 )
}
if ( ( VAR_GlobUInt8_43 != 0 ) && ( ( VAR_GlobUInt8_49 != 0 ) == 1 ) ) {
RunScript( 2, 7, 31 )
} else {
set VARL_GlobBool_407 = 1
}
if ( ( VAR_GlobUInt8_43 != 1 ) && ( ( VAR_GlobUInt8_49 != 1 ) == 1 ) ) {
RunScript( 2, 8, 31 )
} else {
set VARL_GlobBool_404 = 1
}
if ( ( VAR_GlobUInt8_43 != 2 ) && ( ( VAR_GlobUInt8_49 != 2 ) == 1 ) ) {
RunScript( 2, 13, 31 )
} else {
set VARL_GlobBool_406 = 1
}
if ( ( VAR_GlobUInt8_43 != 3 ) && ( ( VAR_GlobUInt8_49 != 3 ) == 1 ) ) {
RunScript( 2, 10, 31 )
} else {
set VARL_GlobBool_405 = 1
}
if ( ( VAR_GlobUInt8_43 != 4 ) && ( ( VAR_GlobUInt8_49 != 4 ) == 1 ) ) {
RunScript( 2, 11, 31 )
} else {
set VARL_GlobBool_403 = 1
}
if ( ( VAR_GlobUInt8_43 != 5 ) && ( ( VAR_GlobUInt8_49 != 5 ) == 1 ) ) {
RunScript( 2, 12, 31 )
} else {
set VARL_GlobBool_402 = 1
}
if ( ( VAR_GlobUInt8_43 != 6 ) && ( ( VAR_GlobUInt8_49 != 6 ) == 1 ) ) {
RunScript( 2, 1, 31 )
} else {
set VARL_GlobBool_401 = 1
}
if ( ( VAR_GlobUInt8_43 != 7 ) && ( ( VAR_GlobUInt8_49 != 7 ) == 1 ) ) {
RunScript( 2, 9, 31 )
} else {
set VARL_GlobBool_400 = 1
}
while ( VAR_GlobUInt8_40 < 6 ) {
Wait( 1 )
}
Wait( 1 )
set VAR_GlobUInt8_41 = 0
set VAR_GlobUInt8_40 = 0
Wait( 1 )
set VAR_GlobUInt8_24 = VAR_GlobUInt8_45
set VAR_GlobUInt8_25 = VAR_GlobUInt8_47
RunScriptAsync( 6, 7, 24 )
RunScriptAsync( 6, 8, 24 )
RunScriptAsync( 6, 10, 24 )
RunScriptAsync( 6, 1, 24 )
RunScriptAsync( 6, 12, 24 )
RunScriptAsync( 6, 9, 24 )
RunScriptAsync( 6, 13, 24 )
RunScriptAsync( 6, 11, 24 )
RunScriptAsync( 6, 5, 14 )
while ( VAR_GlobUInt8_41 < 1 ) {
Wait( 1 )
}
RunScriptSync( 2, VAR_GlobUInt8_54, 28 )
RunScriptAsync( 6, 5, 15 )
while ( VAR_GlobUInt8_41 < 2 ) {
Wait( 1 )
}
RunScriptSync( 2, 252, 29 )
RunScriptSync( 2, 6, 30 )
while ( VAR_GlobUInt8_40 < 6 ) {
Wait( 1 )
}
Wait( 1 )
set VAR_GlobUInt8_40 = 0
Wait( 1 )
RunScriptAsync( 6, 5, 17 )
while ( VAR_GlobUInt8_41 < 3 ) {
Wait( 1 )
}
if ( ( VAR_GlobUInt8_45 != 0 ) && ( ( VAR_GlobUInt8_47 != 0 ) == 1 ) ) {
if ( VARL_GlobBool_407 != 1 ) {
RunScript( 2, 7, 31 )
}
} else {
set VARL_GlobBool_407 = 1
}
if ( ( VAR_GlobUInt8_45 != 1 ) && ( ( VAR_GlobUInt8_47 != 1 ) == 1 ) ) {
if ( VARL_GlobBool_404 != 1 ) {
RunScript( 2, 8, 31 )
}
} else {
set VARL_GlobBool_404 = 1
}
if ( ( VAR_GlobUInt8_45 != 2 ) && ( ( VAR_GlobUInt8_47 != 2 ) == 1 ) ) {
if ( VARL_GlobBool_406 != 1 ) {
RunScript( 2, 13, 31 )
}
} else {
set VARL_GlobBool_406 = 1
}
if ( ( VAR_GlobUInt8_45 != 3 ) && ( ( VAR_GlobUInt8_47 != 3 ) == 1 ) ) {
if ( VARL_GlobBool_405 != 1 ) {
RunScript( 2, 10, 31 )
}
} else {
set VARL_GlobBool_405 = 1
}
if ( ( VAR_GlobUInt8_45 != 4 ) && ( ( VAR_GlobUInt8_47 != 4 ) == 1 ) ) {
if ( VARL_GlobBool_403 != 1 ) {
RunScript( 2, 11, 31 )
}
} else {
set VARL_GlobBool_403 = 1
}
if ( ( VAR_GlobUInt8_45 != 5 ) && ( ( VAR_GlobUInt8_47 != 5 ) == 1 ) ) {
if ( VARL_GlobBool_402 != 1 ) {
RunScript( 2, 12, 31 )
}
} else {
set VARL_GlobBool_402 = 1
}
if ( ( VAR_GlobUInt8_45 != 6 ) && ( ( VAR_GlobUInt8_47 != 6 ) == 1 ) ) {
if ( VARL_GlobBool_401 != 1 ) {
RunScript( 2, 1, 31 )
}
} else {
set VARL_GlobBool_401 = 1
}
if ( ( VAR_GlobUInt8_45 != 7 ) && ( ( VAR_GlobUInt8_47 != 7 ) == 1 ) ) {
if ( VARL_GlobBool_400 != 1 ) {
RunScript( 2, 9, 31 )
}
} else {
set VARL_GlobBool_400 = 1
}
while ( VAR_GlobUInt8_40 < 4 ) {
Wait( 1 )
}
Wait( 1 )
set VAR_GlobUInt8_40 = 0
Wait( 1 )
set VAR_GlobUInt8_41 = 0
set VAR_GlobUInt8_24 = VAR_GlobUInt8_42
set VAR_GlobUInt8_25 = VAR_GlobUInt8_48
RunScriptAsync( 6, 7, 24 )
RunScriptAsync( 6, 8, 24 )
RunScriptAsync( 6, 10, 24 )
RunScriptAsync( 6, 1, 24 )
RunScriptAsync( 6, 12, 24 )
RunScriptAsync( 6, 9, 24 )
RunScriptAsync( 6, 13, 24 )
RunScriptAsync( 6, 11, 24 )
RunScriptAsync( 6, 5, 14 )
while ( VAR_GlobUInt8_41 < 1 ) {
Wait( 1 )
}
RunScriptSync( 2, VAR_GlobUInt8_51, 28 )
RunScriptAsync( 6, 5, 15 )
while ( VAR_GlobUInt8_41 < 2 ) {
Wait( 1 )
}
RunScriptSync( 2, 253, 29 )
RunScriptSync( 2, 6, 30 )
while ( VAR_GlobUInt8_40 < 4 ) {
Wait( 1 )
}
Wait( 1 )
set VAR_GlobUInt8_40 = 0
Wait( 1 )
RunScriptAsync( 6, 5, 17 )
while ( VAR_GlobUInt8_41 < 3 ) {
Wait( 1 )
}
if ( ( VAR_GlobUInt8_42 != 0 ) && ( ( VAR_GlobUInt8_48 != 0 ) == 1 ) ) {
if ( VARL_GlobBool_407 != 1 ) {
RunScript( 2, 7, 31 )
}
} else {
set VARL_GlobBool_407 = 1
}
if ( ( VAR_GlobUInt8_42 != 1 ) && ( ( VAR_GlobUInt8_48 != 1 ) == 1 ) ) {
if ( VARL_GlobBool_404 != 1 ) {
RunScript( 2, 8, 31 )
}
} else {
set VARL_GlobBool_404 = 1
}
if ( ( VAR_GlobUInt8_42 != 2 ) && ( ( VAR_GlobUInt8_48 != 2 ) == 1 ) ) {
if ( VARL_GlobBool_406 != 1 ) {
RunScript( 2, 13, 31 )
}
} else {
set VARL_GlobBool_406 = 1
}
if ( ( VAR_GlobUInt8_42 != 3 ) && ( ( VAR_GlobUInt8_48 != 3 ) == 1 ) ) {
if ( VARL_GlobBool_405 != 1 ) {
RunScript( 2, 10, 31 )
}
} else {
set VARL_GlobBool_405 = 1
}
if ( ( VAR_GlobUInt8_42 != 4 ) && ( ( VAR_GlobUInt8_48 != 4 ) == 1 ) ) {
if ( VARL_GlobBool_403 != 1 ) {
RunScript( 2, 11, 31 )
}
} else {
set VARL_GlobBool_403 = 1
}
if ( ( VAR_GlobUInt8_42 != 5 ) && ( ( VAR_GlobUInt8_48 != 5 ) == 1 ) ) {
if ( VARL_GlobBool_402 != 1 ) {
RunScript( 2, 12, 31 )
}
} else {
set VARL_GlobBool_402 = 1
}
if ( ( VAR_GlobUInt8_42 != 6 ) && ( ( VAR_GlobUInt8_48 != 6 ) == 1 ) ) {
if ( VARL_GlobBool_401 != 1 ) {
RunScript( 2, 14, 31 )
}
} else {
set VARL_GlobBool_401 = 1
}
if ( ( VAR_GlobUInt8_42 != 7 ) && ( ( VAR_GlobUInt8_48 != 7 ) == 1 ) ) {
if ( VARL_GlobBool_400 != 1 ) {
RunScript( 2, 9, 31 )
}
} else {
set VARL_GlobBool_400 = 1
}
while ( VAR_GlobUInt8_40 < 2 ) {
Wait( 1 )
}
Wait( 1 )
set VAR_GlobUInt8_40 = 0
set VAR_GlobUInt8_41 = 0
Wait( 1 )
set VAR_GlobUInt8_24 = VAR_GlobUInt8_44
set VAR_GlobUInt8_25 = VAR_GlobUInt8_46
RunScriptAsync( 6, 7, 24 )
RunScriptAsync( 6, 8, 24 )
RunScriptAsync( 6, 10, 24 )
RunScriptAsync( 6, 1, 24 )
RunScriptAsync( 6, 12, 24 )
RunScriptAsync( 6, 9, 24 )
RunScriptAsync( 6, 13, 24 )
RunScriptAsync( 6, 11, 24 )
RunScriptAsync( 6, 5, 14 )
while ( VAR_GlobUInt8_41 < 1 ) {
Wait( 1 )
}
RunScriptSync( 2, VAR_GlobUInt8_53, 28 )
RunScriptAsync( 6, 5, 15 )
while ( VAR_GlobUInt8_41 < 2 ) {
Wait( 1 )
}
RunScriptSync( 2, 251, 29 )
RunScriptSync( 2, 6, 30 )
while ( VAR_GlobUInt8_40 < 2 ) {
Wait( 1 )
}
Wait( 1 )
set VAR_GlobUInt8_40 = 0
Wait( 1 )
} else {
set VAR_GlobUInt8_24 = VAR_GlobUInt8_44
set VAR_GlobUInt8_25 = VAR_GlobUInt8_48
RunScriptAsync( 6, 7, 24 )
RunScriptAsync( 6, 8, 24 )
RunScriptAsync( 6, 10, 24 )
RunScriptAsync( 6, 1, 24 )
RunScriptAsync( 6, 12, 24 )
RunScriptAsync( 6, 9, 24 )
RunScriptAsync( 6, 13, 24 )
RunScriptAsync( 6, 11, 24 )
RunScriptAsync( 6, 5, 14 )
while ( VAR_GlobUInt8_41 < 1 ) {
Wait( 1 )
}
RunScriptSync( 2, VAR_GlobUInt8_53, 28 )
RunScriptAsync( 6, 5, 15 )
while ( VAR_GlobUInt8_41 < 2 ) {
Wait( 1 )
}
RunScriptSync( 2, 253, 29 )
RunScriptSync( 2, 6, 30 )
while ( VAR_GlobUInt8_40 < 8 ) {
Wait( 1 )
}
Wait( 1 )
set VAR_GlobUInt8_40 = 0
Wait( 1 )
RunScriptAsync( 6, 5, 17 )
while ( VAR_GlobUInt8_41 < 3 ) {
Wait( 1 )
}
if ( ( VAR_GlobUInt8_44 != 0 ) && ( ( VAR_GlobUInt8_48 != 0 ) == 1 ) ) {
RunScript( 2, 7, 31 )
} else {
set VARL_GlobBool_407 = 1
}
if ( ( VAR_GlobUInt8_44 != 1 ) && ( ( VAR_GlobUInt8_48 != 1 ) == 1 ) ) {
RunScript( 2, 8, 31 )
} else {
set VARL_GlobBool_404 = 1
}
if ( ( VAR_GlobUInt8_44 != 2 ) && ( ( VAR_GlobUInt8_48 != 2 ) == 1 ) ) {
RunScript( 2, 13, 31 )
} else {
set VARL_GlobBool_406 = 1
}
if ( ( VAR_GlobUInt8_44 != 3 ) && ( ( VAR_GlobUInt8_48 != 3 ) == 1 ) ) {
RunScript( 2, 10, 31 )
} else {
set VARL_GlobBool_405 = 1
}
if ( ( VAR_GlobUInt8_44 != 4 ) && ( ( VAR_GlobUInt8_48 != 4 ) == 1 ) ) {
RunScript( 2, 11, 31 )
} else {
set VARL_GlobBool_403 = 1
}
if ( ( VAR_GlobUInt8_44 != 5 ) && ( ( VAR_GlobUInt8_48 != 5 ) == 1 ) ) {
RunScript( 2, 12, 31 )
} else {
set VARL_GlobBool_402 = 1
}
if ( ( VAR_GlobUInt8_44 != 6 ) && ( ( VAR_GlobUInt8_48 != 6 ) == 1 ) ) {
RunScript( 2, 14, 31 )
} else {
set VARL_GlobBool_401 = 1
}
if ( ( VAR_GlobUInt8_44 != 7 ) && ( ( VAR_GlobUInt8_48 != 7 ) == 1 ) ) {
RunScript( 2, 9, 31 )
} else {
set VARL_GlobBool_400 = 1
}
while ( VAR_GlobUInt8_40 < 6 ) {
Wait( 1 )
}
Wait( 1 )
set VAR_GlobUInt8_41 = 0
set VAR_GlobUInt8_40 = 0
Wait( 1 )
set VAR_GlobUInt8_24 = VAR_GlobUInt8_45
set VAR_GlobUInt8_25 = VAR_GlobUInt8_49
RunScriptAsync( 6, 7, 24 )
RunScriptAsync( 6, 8, 24 )
RunScriptAsync( 6, 10, 24 )
RunScriptAsync( 6, 1, 24 )
RunScriptAsync( 6, 12, 24 )
RunScriptAsync( 6, 9, 24 )
RunScriptAsync( 6, 13, 24 )
RunScriptAsync( 6, 11, 24 )
RunScriptAsync( 6, 5, 14 )
while ( VAR_GlobUInt8_41 < 1 ) {
Wait( 1 )
}
RunScriptSync( 2, VAR_GlobUInt8_54, 28 )
RunScriptAsync( 6, 5, 15 )
while ( VAR_GlobUInt8_41 < 2 ) {
Wait( 1 )
}
RunScriptSync( 2, 254, 29 )
RunScriptSync( 2, 6, 30 )
while ( VAR_GlobUInt8_40 < 6 ) {
Wait( 1 )
}
Wait( 1 )
set VAR_GlobUInt8_40 = 0
Wait( 1 )
RunScriptAsync( 6, 5, 17 )
while ( VAR_GlobUInt8_41 < 3 ) {
Wait( 1 )
}
if ( ( VAR_GlobUInt8_45 != 0 ) && ( ( VAR_GlobUInt8_49 != 0 ) == 1 ) ) {
if ( VARL_GlobBool_407 != 1 ) {
RunScript( 2, 7, 31 )
}
} else {
set VARL_GlobBool_407 = 1
}
if ( ( VAR_GlobUInt8_45 != 1 ) && ( ( VAR_GlobUInt8_49 != 1 ) == 1 ) ) {
if ( VARL_GlobBool_404 != 1 ) {
RunScript( 2, 8, 31 )
}
} else {
set VARL_GlobBool_404 = 1
}
if ( ( VAR_GlobUInt8_45 != 2 ) && ( ( VAR_GlobUInt8_49 != 2 ) == 1 ) ) {
if ( VARL_GlobBool_406 != 1 ) {
RunScript( 2, 13, 31 )
}
} else {
set VARL_GlobBool_406 = 1
}
if ( ( VAR_GlobUInt8_45 != 3 ) && ( ( VAR_GlobUInt8_49 != 3 ) == 1 ) ) {
if ( VARL_GlobBool_405 != 1 ) {
RunScript( 2, 10, 31 )
}
} else {
set VARL_GlobBool_405 = 1
}
if ( ( VAR_GlobUInt8_45 != 4 ) && ( ( VAR_GlobUInt8_49 != 4 ) == 1 ) ) {
if ( VARL_GlobBool_403 != 1 ) {
RunScript( 2, 11, 31 )
}
} else {
set VARL_GlobBool_403 = 1
}
if ( ( VAR_GlobUInt8_45 != 5 ) && ( ( VAR_GlobUInt8_49 != 5 ) == 1 ) ) {
if ( VARL_GlobBool_402 != 1 ) {
RunScript( 2, 12, 31 )
}
} else {
set VARL_GlobBool_402 = 1
}
if ( ( VAR_GlobUInt8_45 != 6 ) && ( ( VAR_GlobUInt8_49 != 6 ) == 1 ) ) {
if ( VARL_GlobBool_401 != 1 ) {
RunScript( 2, 14, 31 )
}
} else {
set VARL_GlobBool_401 = 1
}
if ( ( VAR_GlobUInt8_45 != 7 ) && ( ( VAR_GlobUInt8_49 != 7 ) == 1 ) ) {
if ( VARL_GlobBool_400 != 1 ) {
RunScript( 2, 9, 31 )
}
} else {
set VARL_GlobBool_400 = 1
}
while ( VAR_GlobUInt8_40 < 4 ) {
Wait( 1 )
}
Wait( 1 )
set VAR_GlobUInt8_40 = 0
Wait( 1 )
set VAR_GlobUInt8_41 = 0
set VAR_GlobUInt8_24 = VAR_GlobUInt8_43
set VAR_GlobUInt8_25 = VAR_GlobUInt8_47
RunScriptAsync( 6, 7, 24 )
RunScriptAsync( 6, 8, 24 )
RunScriptAsync( 6, 10, 24 )
RunScriptAsync( 6, 1, 24 )
RunScriptAsync( 6, 12, 24 )
RunScriptAsync( 6, 9, 24 )
RunScriptAsync( 6, 13, 24 )
RunScriptAsync( 6, 11, 24 )
RunScriptAsync( 6, 5, 14 )
while ( VAR_GlobUInt8_41 < 1 ) {
Wait( 1 )
}
RunScriptSync( 2, VAR_GlobUInt8_52, 28 )
&
}
if ( ( VAR_GlobUInt8_43 != 2 ) && ( ( VAR_GlobUInt8_47 != 2 ) == 1 ) ) {
if ( VARL_GlobBool_406 != 1 ) {
RunScript( 2, 13, 31 )
}
} else {
set VARL_GlobBool_406 = 1
}
if ( ( VAR_GlobUInt8_43 != 3 ) && ( ( VAR_GlobUInt8_47 != 3 ) == 1 ) ) {
if ( VARL_GlobBool_405 != 1 ) {
RunScript( 2, 10, 31 )
}
} else {
set VARL_GlobBool_405 = 1
}
if ( ( VAR_GlobUInt8_43 != 4 ) && ( ( VAR_GlobUInt8_47 != 4 ) == 1 ) ) {
if ( VARL_GlobBool_403 != 1 ) {
RunScript( 2, 11, 31 )
}
} else {
set VARL_GlobBool_403 = 1
}
if ( ( VAR_GlobUInt8_43 != 5 ) && ( ( VAR_GlobUInt8_47 != 5 ) == 1 ) ) {
if ( VARL_GlobBool_402 != 1 ) {
RunScript( 2, 12, 31 )
}
} else {
set VARL_GlobBool_402 = 1
}
if ( ( VAR_GlobUInt8_43 != 6 ) && ( ( VAR_GlobUInt8_47 != 6 ) == 1 ) ) {
if ( VARL_GlobBool_401 != 1 ) {
RunScript( 2, 1, 31 )
}
} else {
set VARL_GlobBool_401 = 1
}
if ( ( VAR_GlobUInt8_43 != 7 ) && ( ( VAR_GlobUInt8_47 != 7 ) == 1 ) ) {
if ( VARL_GlobBool_400 != 1 ) {
RunScript( 2, 9, 31 )
}
} else {
set VARL_GlobBool_400 = 1
}
while ( VAR_GlobUInt8_40 < 2 ) {
Wait( 1 )
}
Wait( 1 )
set VAR_GlobUInt8_40 = 0
set VAR_GlobUInt8_41 = 0
Wait( 1 )
set VAR_GlobUInt8_24 = VAR_GlobUInt8_42
set VAR_GlobUInt8_25 = VAR_GlobUInt8_46
RunScriptAsync( 6, 7, 24 )
RunScriptAsync( 6, 8, 24 )
RunScriptAsync( 6, 10, 24 )
RunScriptAsync( 6, 1, 24 )
RunScriptAsync( 6, 12, 24 )
RunScriptAsync( 6, 9, 24 )
RunScriptAsync( 6, 13, 24 )
RunScriptAsync( 6, 11, 24 )
RunScriptAsync( 6, 5, 14 )
while ( VAR_GlobUInt8_41 < 1 ) {
Wait( 1 )
}
RunScriptSync( 2, VAR_GlobUInt8_51, 28 )
RunScriptAsync( 6, 5, 15 )
while ( VAR_GlobUInt8_41 < 2 ) {
Wait( 1 )
}
RunScriptSync( 2, 251, 29 )
RunScriptSync( 2, 6, 30 )
while ( VAR_GlobUInt8_40 < 2 ) {
Wait( 1 )
}
Wait( 1 )
set VAR_GlobUInt8_40 = 0
Wait( 1 )
}
} else {
if ( IsInParty(0) ) {
set VAR_GlobUInt8_24 = VAR_GlobUInt8_44
set VAR_GlobUInt8_25 = VAR_GlobUInt8_49
RunScriptAsync( 6, 7, 24 )
RunScriptAsync( 6, 8, 24 )
RunScriptAsync( 6, 10, 24 )
RunScriptAsync( 6, 1, 24 )
RunScriptAsync( 6, 12, 24 )
RunScriptAsync( 6, 9, 24 )
RunScriptAsync( 6, 13, 24 )
RunScriptAsync( 6, 11, 24 )
RunScriptAsync( 6, 5, 14 )
while ( VAR_GlobUInt8_41 < 1 ) {
Wait( 1 )
}
RunScriptSync( 2, VAR_GlobUInt8_53, 28 )
RunScriptAsync( 6, 5, 15 )
while ( VAR_GlobUInt8_41 < 2 ) {
Wait( 1 )
}
RunScriptSync( 2, 254, 29 )
RunScriptSync( 2, 6, 30 )
while ( VAR_GlobUInt8_40 < 8 ) {
Wait( 1 )
}
Wait( 1 )
set VAR_GlobUInt8_40 = 0
Wait( 1 )
RunScriptAsync( 6, 5, 17 )
while ( VAR_GlobUInt8_41 < 3 ) {
Wait( 1 )
}
if ( ( VAR_GlobUInt8_44 != 0 ) && ( ( VAR_GlobUInt8_49 != 0 ) == 1 ) ) {
RunScript( 2, 7, 31 )
} else {
set VARL_GlobBool_407 = 1
}
if ( ( VAR_GlobUInt8_44 != 1 ) && ( ( VAR_GlobUInt8_49 != 1 ) == 1 ) ) {
RunScript( 2, 8, 31 )
} else {
set VARL_GlobBool_404 = 1
}
if ( ( VAR_GlobUInt8_44 != 2 ) && ( ( VAR_GlobUInt8_49 != 2 ) == 1 ) ) {
RunScript( 2, 13, 31 )
} else {
set VARL_GlobBool_406 = 1
}
if ( ( VAR_GlobUInt8_44 != 3 ) && ( ( VAR_GlobUInt8_49 != 3 ) == 1 ) ) {
RunScript( 2, 10, 31 )
} else {
set VARL_GlobBool_405 = 1
}
if ( ( VAR_GlobUInt8_44 != 4 ) && ( ( VAR_GlobUInt8_49 != 4 ) == 1 ) ) {
RunScript( 2, 11, 31 )
} else {
set VARL_GlobBool_403 = 1
}
if ( ( VAR_GlobUInt8_44 != 5 ) && ( ( VAR_GlobUInt8_49 != 5 ) == 1 ) ) {
RunScript( 2, 12, 31 )
} else {
set VARL_GlobBool_402 = 1
}
if ( ( VAR_GlobUInt8_44 != 6 ) && ( ( VAR_GlobUInt8_49 != 6 ) == 1 ) ) {
RunScript( 2, 14, 31 )
} else {
set VARL_GlobBool_401 = 1
}
if ( ( VAR_GlobUInt8_44 != 7 ) && ( ( VAR_GlobUInt8_49 != 7 ) == 1 ) ) {
RunScript( 2, 9, 31 )
} else {
set VARL_GlobBool_400 = 1
}
while ( VAR_GlobUInt8_40 < 6 ) {
Wait( 1 )
}
Wait( 1 )
set VAR_GlobUInt8_41 = 0
set VAR_GlobUInt8_40 = 0
Wait( 1 )
set VAR_GlobUInt8_24 = VAR_GlobUInt8_42
set VAR_GlobUInt8_25 = VAR_GlobUInt8_48
RunScriptAsync( 6, 7, 24 )
RunScriptAsync( 6, 8, 24 )
RunScriptAsync( 6, 10, 24 )
RunScriptAsync( 6, 1, 24 )
RunScriptAsync( 6, 12, 24 )
RunScriptAsync( 6, 9, 24 )
RunScriptAsync( 6, 13, 24 )
RunScriptAsync( 6, 11, 24 )
RunScriptAsync( 6, 5, 14 )
while ( VAR_GlobUInt8_41 < 1 ) {
Wait( 1 )
}
RunScriptSync( 2, VAR_GlobUInt8_51, 28 )
RunScriptAsync( 6, 5, 15 )
while ( VAR_GlobUInt8_41 < 2 ) {
Wait( 1 )
}
RunScriptSync( 2, 253, 29 )
RunScriptSync( 2, 6, 30 )
while ( VAR_GlobUInt8_40 < 6 ) {
Wait( 1 )
}
Wait( 1 )
set VAR_GlobUInt8_40 = 0
Wait( 1 )
RunScriptAsync( 6, 5, 17 )
while ( VAR_GlobUInt8_41 < 3 ) {
Wait( 1 )
}
if ( ( VAR_GlobUInt8_42 != 0 ) && ( ( VAR_GlobUInt8_48 != 0 ) == 1 ) ) {
if ( VARL_GlobBool_407 != 1 ) {
RunScript( 2, 7, 31 )
}
} else {
set VARL_GlobBool_407 = 1
}
if ( ( VAR_GlobUInt8_42 != 1 ) && ( ( VAR_GlobUInt8_48 != 1 ) == 1 ) ) {
if ( VARL_GlobBool_404 != 1 ) {
RunScript( 2, 8, 31 )
}
} else {
set VARL_GlobBool_404 = 1
}
if ( ( VAR_GlobUInt8_42 != 2 ) && ( ( VAR_GlobUInt8_48 != 2 ) == 1 ) ) {
if ( VARL_GlobBool_406 != 1 ) {
RunScript( 2, 13, 31 )
}
} else {
set VARL_GlobBool_406 = 1
}
if ( ( VAR_GlobUInt8_42 != 3 ) && ( ( VAR_GlobUInt8_48 != 3 ) == 1 ) ) {
if ( VARL_GlobBool_405 != 1 ) {
RunScript( 2, 10, 31 )
}
} else {
set VARL_GlobBool_405 = 1
}
if ( ( VAR_GlobUInt8_42 != 4 ) && ( ( VAR_GlobUInt8_48 != 4 ) == 1 ) ) {
if ( VARL_GlobBool_403 != 1 ) {
RunScript( 2, 11, 31 )
}
} else {
set VARL_GlobBool_403 = 1
}
if ( ( VAR_GlobUInt8_42 != 5 ) && ( ( VAR_GlobUInt8_48 != 5 ) == 1 ) ) {
if ( VARL_GlobBool_402 != 1 ) {
RunScript( 2, 12, 31 )
}
} else {
set VARL_GlobBool_402 = 1
}
if ( ( VAR_GlobUInt8_42 != 6 ) && ( ( VAR_GlobUInt8_48 != 6 ) == 1 ) ) {
if ( VARL_GlobBool_401 != 1 ) {
RunScript( 2, 14, 31 )
}
} else {
set VARL_GlobBool_401 = 1
}
if ( ( VAR_GlobUInt8_42 != 7 ) && ( ( VAR_GlobUInt8_48 != 7 ) == 1 ) ) {
if ( VARL_GlobBool_400 != 1 ) {
RunScript( 2, 9, 31 )
}
} else {
set VARL_GlobBool_400 = 1
}
while ( VAR_GlobUInt8_40 < 4 ) {
Wait( 1 )
}
Wait( 1 )
set VAR_GlobUInt8_40 = 0
Wait( 1 )
set VAR_GlobUInt8_41 = 0
set VAR_GlobUInt8_24 = VAR_GlobUInt8_43
set VAR_GlobUInt8_25 = VAR_GlobUInt8_47
RunScriptAsync( 6, 7, 24 )
RunScriptAsync( 6, 8, 24 )
RunScriptAsync( 6, 10, 24 )
RunScriptAsync( 6, 1, 24 )
RunScriptAsync( 6, 12, 24 )
RunScriptAsync( 6, 9, 24 )
RunScriptAsync( 6, 13, 24 )
RunScriptAsync( 6, 11, 24 )
RunScriptAsync( 6, 5, 14 )
while ( VAR_GlobUInt8_41 < 1 ) {
Wait( 1 )
}
RunScriptSync( 2, VAR_GlobUInt8_52, 28 )
RunScriptAsync( 6, 5, 15 )
while ( VAR_GlobUInt8_41 < 2 ) {
Wait( 1 )
}
RunScriptSync( 2, 252, 29 )
RunScriptSync( 2, 6, 30 )
while ( VAR_GlobUInt8_40 < 4 ) {
Wait( 1 )
}
Wait( 1 )
set VAR_GlobUInt8_40 = 0
Wait( 1 )
RunScriptAsync( 6, 5, 17 )
while ( VAR_GlobUInt8_41 < 3 ) {
Wait( 1 )
}
if ( ( VAR_GlobUInt8_43 != 0 ) && ( ( VAR_GlobUInt8_47 != 0 ) == 1 ) ) {
if ( VARL_GlobBool_407 != 1 ) {
RunScript( 2, 7, 31 )
}
} else {
set VARL_GlobBool_407 = 1
}
if ( ( VAR_GlobUInt8_43 != 1 ) && ( ( VAR_GlobUInt8_47 != 1 ) == 1 ) ) {
if ( VARL_GlobBool_404 != 1 ) {
RunScript( 2, 8, 31 )
}
} else {
set VARL_GlobBool_404 = 1
}
if ( ( VAR_GlobUInt8_43 != 2 ) && ( ( VAR_GlobUInt8_47 != 2 ) == 1 ) ) {
if ( VARL_GlobBool_406 != 1 ) {
RunScript( 2, 13, 31 )
}
} else {
set VARL_GlobBool_406 = 1
}
if ( ( VAR_GlobUInt8_43 != 3 ) && ( ( VAR_GlobUInt8_47 != 3 ) == 1 ) ) {
if ( VARL_GlobBool_405 != 1 ) {
RunScript( 2, 10, 31 )
}
} else {
set VARL_GlobBool_405 = 1
}
if ( ( VAR_GlobUInt8_43 != 4 ) && ( ( VAR_GlobUInt8_47 != 4 ) == 1 ) ) {
if ( VARL_GlobBool_403 != 1 ) {
RunScript( 2, 11, 31 )
}
} else {
set VARL_GlobBool_403 = 1
}
if ( ( VAR_GlobUInt8_43 != 5 ) && ( ( VAR_GlobUInt8_47 != 5 ) == 1 ) ) {
if ( VARL_GlobBool_402 != 1 ) {
RunScript( 2, 12, 31 )
}
} else {
set VARL_GlobBool_402 = 1
}
if ( ( VAR_GlobUInt8_43 != 6 ) && ( ( VAR_GlobUInt8_47 != 6 ) == 1 ) ) {
if ( VARL_GlobBool_401 != 1 ) {
RunScript( 2, 1, 31 )
}
} else {
set VARL_GlobBool_401 = 1
}
if ( ( VAR_GlobUInt8_43 != 7 ) && ( ( VAR_GlobUInt8_47 != 7 ) == 1 ) ) {
if ( VARL_GlobBool_400 != 1 ) {
RunScript( 2, 9, 31 )
}
} else {
set VARL_GlobBool_400 = 1
}
while ( VAR_GlobUInt8_40 < 2 ) {
Wait( 1 )
}
Wait( 1 )
set VAR_GlobUInt8_40 = 0
set VAR_GlobUInt8_41 = 0
Wait( 1 )
set VAR_GlobUInt8_24 = VAR_GlobUInt8_45
set VAR_GlobUInt8_25 = VAR_GlobUInt8_46
RunScriptAsync( 6, 7, 24 )
RunScriptAsync( 6, 8, 24 )
RunScriptAsync( 6, 10, 24 )
RunScriptAsync( 6, 1, 24 )
RunScriptAsync( 6, 12, 24 )
RunScriptAsync( 6, 9, 24 )
RunScriptAsync( 6, 13, 24 )
RunScriptAsync( 6, 11, 24 )
RunScriptAsync( 6, 5, 14 )
while ( VAR_GlobUInt8_41 < 1 ) {
Wait( 1 )
}
RunScriptSync( 2, VAR_GlobUInt8_54, 28 )
RunScriptAsync( 6, 5, 15 )
while ( VAR_GlobUInt8_41 < 2 ) {
Wait( 1 )
}
RunScriptSync( 2, 251, 29 )
RunScriptSync( 2, 6, 30 )
while ( VAR_GlobUInt8_40 < 2 ) {
Wait( 1 )
}
Wait( 1 )
set VAR_GlobUInt8_40 = 0
Wait( 1 )
} else {
set VAR_GlobUInt8_24 = VAR_GlobUInt8_45
set VAR_GlobUInt8_25 = VAR_GlobUInt8_48
RunScriptAsync( 6, 7, 24 )
RunScriptAsync( 6, 8, 24 )
RunScriptAsync( 6, 10, 24 )
RunScriptAsync( 6, 1, 24 )
RunScriptAsync( 6, 12, 24 )
RunScriptAsync( 6, 9, 24 )
RunScriptAsync( 6, 13, 24 )
RunScriptAsync( 6, 11, 24 )
RunScriptAsync( 6, 5, 14 )
while ( VAR_GlobUInt8_41 < 1 ) {
Wait( 1 )
}
RunScriptSync( 2, VAR_GlobUInt8_54, 28 )
RunScriptAsync( 6, 5, 15 )
while ( VAR_GlobUInt8_41 < 2 ) {
Wait( 1 )
}
RunScriptSync( 2, 253, 29 )
RunScriptSync( 2, 6, 30 )
while ( VAR_GlobUInt8_40 < 8 ) {
Wait( 1 )
}
Wait( 1 )
set VAR_GlobUInt8_40 = 0
Wait( 1 )
RunScriptAsync( 6, 5, 17 )
while ( VAR_GlobUInt8_41 < 3 ) {
Wait( 1 )
}
if ( ( VAR_GlobUInt8_45 != 0 ) && ( ( VAR_GlobUInt8_48 != 0 ) == 1 ) ) {
RunScript( 2, 7, 31 )
} else {
set VARL_GlobBool_407 = 1
}
if ( ( VAR_GlobUInt8_45 != 1 ) && ( ( VAR_GlobUInt8_48 != 1 ) == 1 ) ) {
RunScript( 2, 8, 31 )
} else {
set VARL_GlobBool_404 = 1
}
if ( ( VAR_GlobUInt8_45 != 2 ) && ( ( VAR_GlobUInt8_48 != 2 ) == 1 ) ) {
RunScript( 2, 13, 31 )
} else {
set VARL_GlobBool_406 = 1
}
if ( ( VAR_GlobUInt8_45 != 3 ) && ( ( VAR_GlobUInt8_48 != 3 ) == 1 ) ) {
RunScript( 2, 10, 31 )
} else {
set VARL_GlobBool_405 = 1
}
if ( ( VAR_GlobUInt8_45 != 4 ) && ( ( VAR_GlobUInt8_48 != 4 ) == 1 ) ) {
RunScript( 2, 11, 31 )
} else {
set VARL_GlobBool_403 = 1
}
if ( ( VAR_GlobUInt8_45 != 5 ) && ( ( VAR_GlobUInt8_48 != 5 ) == 1 ) ) {
RunScript( 2, 12, 31 )
} else {
set VARL_GlobBool_402 = 1
}
if ( ( VAR_GlobUInt8_45 != 6 ) && ( ( VAR_GlobUInt8_48 != 6 ) == 1 ) ) {
RunScript( 2, 1, 31 )
} else {
set VARL_GlobBool_401 = 1
}
if ( ( VAR_GlobUInt8_45 != 7 ) && ( ( VAR_GlobUInt8_48 != 7 ) == 1 ) ) {
RunScript( 2, 9, 31 )
} else {
set VARL_GlobBool_400 = 1
}
while ( VAR_GlobUInt8_40 < 6 ) {
Wait( 1 )
}
Wait( 1 )
set VAR_GlobUInt8_41 = 0
set VAR_GlobUInt8_40 = 0
Wait( 1 )
set VAR_GlobUInt8_24 = VAR_GlobUInt8_43
set VAR_GlobUInt8_25 = VAR_GlobUInt8_47
RunScriptAsync( 6, 7, 24 )
RunScriptAsync( 6, 8, 24 )
RunScriptAsync( 6, 10, 24 )
RunScriptAsync( 6, 1, 24 )
RunScriptAsync( 6, 12, 24 )
RunScriptAsync( 6, 9, 24 )
RunScriptAsync( 6, 13, 24 )
RunScriptAsync( 6, 11, 24 )
RunScriptAsync( 6, 5, 14 )
while ( VAR_GlobUInt8_41 < 1 ) {
Wait( 1 )
}
RunScriptSync( 2, VAR_GlobUInt8_52, 28 )
RunScriptAsync( 6, 5, 15 )
while ( VAR_GlobUInt8_41 < 2 ) {
Wait( 1 )
}
RunScriptSync( 2, 252, 29 )
RunScriptSync( 2, 6, 30 )
while ( VAR_GlobUInt8_40 < 6 ) {
Wait( 1 )
}
Wait( 1 )
set VAR_GlobUInt8_40 = 0
Wait( 1 )
RunScriptAsync( 6, 5, 17 )
while ( VAR_GlobUInt8_41 < 3 ) {
Wait( 1 )
}
if ( ( VAR_GlobUInt8_43 != 0 ) && ( ( VAR_GlobUInt8_47 != 0 ) == 1 ) ) {
if ( VARL_GlobBool_407 != 1 ) {
RunScript( 2, 7, 31 )
}
} else {
set VARL_GlobBool_407 = 1
}
if ( ( VAR_GlobUInt8_43 != 1 ) && ( ( VAR_GlobUInt8_47 != 1 ) == 1 ) ) {
if ( VARL_GlobBool_404 != 1 ) {
RunScript( 2, 8, 31 )
}
} else {
set VARL_GlobBool_404 = 1
}
if ( ( VAR_GlobUInt8_43 != 2 ) && ( ( VAR_GlobUInt8_47 != 2 ) == 1 ) ) {
if ( VARL_GlobBool_406 != 1 ) {
RunScript( 2, 13, 31 )
}
} else {
set VARL_GlobBool_406 = 1
}
if ( ( VAR_GlobUInt8_43 != 3 ) && ( ( VAR_GlobUInt8_47 != 3 ) == 1 ) ) {
if ( VARL_GlobBool_405 != 1 ) {
RunScript( 2, 10, 31 )
}
} else {
set VARL_GlobBool_405 = 1
}
if ( ( VAR_GlobUInt8_43 != 4 ) && ( ( VAR_GlobUInt8_47 != 4 ) == 1 ) ) {
if ( VARL_GlobBool_403 != 1 ) {
RunScript( 2, 11, 31 )
}
} else {
set VARL_GlobBool_403 = 1
}
if ( ( VAR_GlobUInt8_43 != 5 ) && ( ( VAR_GlobUInt8_47 != 5 ) == 1 ) ) {
if ( VARL_GlobBool_402 != 1 ) {
RunScript( 2, 12, 31 )
}
} else {
set VARL_GlobBool_402 = 1
}
if ( ( VAR_GlobUInt8_43 != 6 ) && ( ( VAR_GlobUInt8_47 != 6 ) == 1 ) ) {
if ( VARL_GlobBool_401 != 1 ) {
RunScript( 2, 1, 31 )
}
} else {
set VARL_GlobBool_401 = 1
}
if ( ( VAR_GlobUInt8_43 != 7 ) && ( ( VAR_GlobUInt8_47 != 7 ) == 1 ) ) {
if ( VARL_GlobBool_400 != 1 ) {
RunScript( 2, 9, 31 )
}
} else {
set VARL_GlobBool_400 = 1
}
while ( VAR_GlobUInt8_40 < 4 ) {
Wait( 1 )
}
Wait( 1 )
set VAR_GlobUInt8_40 = 0
Wait( 1 )
set VAR_GlobUInt8_41 = 0
set VAR_GlobUInt8_24 = VAR_GlobUInt8_44
set VAR_GlobUInt8_25 = VAR_GlobUInt8_46
RunScriptAsync( 6, 7, 24 )
RunScriptAsync( 6, 8, 24 )
RunScriptAsync( 6, 10, 24 )
RunScriptAsync( 6, 1, 24 )
RunScriptAsync( 6, 12, 24 )
RunScriptAsync( 6, 9, 24 )
RunScriptAsync( 6, 13, 24 )
RunScriptAsync( 6, 11, 24 )
RunScriptAsync( 6, 5, 14 )
while ( VAR_GlobUInt8_41 < 1 ) {
Wait( 1 )
}
RunScriptSync( 2, VAR_GlobUInt8_53, 28 )
RunScriptAsync( 6, 5, 15 )
while ( VAR_GlobUInt8_41 < 2 ) {
Wait( 1 )
}
RunScriptSync( 2, 251, 29 )
RunScriptSync( 2, 6, 30 )
while ( VAR_GlobUInt8_40 < 4 ) {
Wait( 1 )
}
Wait( 1 )
set VAR_GlobUInt8_40 = 0
Wait( 1 )
RunScriptAsync( 6, 5, 17 )
while ( VAR_GlobUInt8_41 < 3 ) {
Wait( 1 )
}
if ( ( VAR_GlobUInt8_44 != 0 ) && ( ( VAR_GlobUInt8_46 != 0 ) == 1 ) ) {
if ( VARL_GlobBool_407 != 1 ) {
RunScript( 2, 7, 31 )
}
} else {
set VARL_GlobBool_407 = 1
}
if ( ( VAR_GlobUInt8_44 != 1 ) && ( ( VAR_GlobUInt8_46 != 1 ) == 1 ) ) {
if ( VARL_GlobBool_404 != 1 ) {
RunScript( 2, 8, 31 )
}
} else {
set VARL_GlobBool_404 = 1
}
if ( ( VAR_GlobUInt8_44 != 2 ) && ( ( VAR_GlobUInt8_46 != 2 ) == 1 ) ) {
if ( VARL_GlobBool_406 != 1 ) {
RunScript( 2, 13, 31 )
}
} else {
set VARL_GlobBool_406 = 1
}
if ( ( VAR_GlobUInt8_44 != 3 ) && ( ( VAR_GlobUInt8_46 != 3 ) == 1 ) ) {
if ( VARL_GlobBool_405 != 1 ) {
RunScript( 2, 10, 31 )
}
} else {
set VARL_GlobBool_405 = 1
}
if ( ( VAR_GlobUInt8_44 != 4 ) && ( ( VAR_GlobUInt8_46 != 4 ) == 1 ) ) {
if ( VARL_GlobBool_403 != 1 ) {
RunScript( 2, 11, 31 )
}
} else {
set VARL_GlobBool_403 = 1
}
if ( ( VAR_GlobUInt8_44 != 5 ) && ( ( VAR_GlobUInt8_46 != 5 ) == 1 ) ) {
if ( VARL_GlobBool_402 != 1 ) {
RunScript( 2, 12, 31 )
}
} else {
set VARL_GlobBool_402 = 1
}
if ( ( VAR_GlobUInt8_44 != 6 ) && ( ( VAR_GlobUInt8_46 != 6 ) == 1 ) ) {
if ( VARL_GlobBool_401 != 1 ) {
RunScript( 2, 1, 31 )
}
} else {
set VARL_GlobBool_401 = 1
}
if ( ( VAR_GlobUInt8_44 != 7 ) && ( ( VAR_GlobUInt8_46 != 7 ) == 1 ) ) {
if ( VARL_GlobBool_400 != 1 ) {
RunScript( 2, 9, 31 )
}
} else {
set VARL_GlobBool_400 = 1
}
while ( VAR_GlobUInt8_40 < 2 ) {
Wait( 1 )
}
Wait( 1 )
set VAR_GlobUInt8_40 = 0
set VAR_GlobUInt8_41 = 0
Wait( 1 )
set VAR_GlobUInt8_24 = VAR_GlobUInt8_42
set VAR_GlobUInt8_25 = VAR_GlobUInt8_49
RunScriptAsync( 6, 7, 24 )
RunScriptAsync( 6, 8, 24 )
RunScriptAsync( 6, 10, 24 )
RunScriptAsync( 6, 1, 24 )
RunScriptAsync( 6, 12, 24 )
RunScriptAsync( 6, 9, 24 )
RunScriptAsync( 6, 13, 24 )
RunScriptAsync( 6, 11, 24 )
RunScriptAsync( 6, 5, 14 )
while ( VAR_GlobUInt8_41 < 1 ) {
Wait( 1 )
}
RunScriptSync( 2, VAR_GlobUInt8_51, 28 )
RunScriptAsync( 6, 5, 15 )
while ( VAR_GlobUInt8_41 < 2 ) {
Wait( 1 )
}
RunScriptSync( 2, 254, 29 )
RunScriptSync( 2, 6, 30 )
while ( VAR_GlobUInt8_40 < 2 ) {
Wait( 1 )
}
Wait( 1 )
set VAR_GlobUInt8_40 = 0
Wait( 1 )
}
}
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 )
RunScriptSync( 6, 5, 18 )
ReturnEntryFunctions( 7 )
ReturnEntryFunctions( 13 )
ReturnEntryFunctions( 10 )
ReturnEntryFunctions( 8 )
ReturnEntryFunctions( 11 )
ReturnEntryFunctions( 12 )
ReturnEntryFunctions( 1 )
ReturnEntryFunctions( 9 )
MoveCamera( 180, 240, 1, 8 )
Wait( 1 )
SetHP( 0, 9999 )
SetHP( 1, 9999 )
SetHP( 3, 9999 )
SetHP( 2, 9999 )
SetHP( 4, 9999 )
SetHP( 5, 9999 )
SetHP( 11, 9999 )
SetHP( 6, 9999 )
SetHP( 8, 9999 )
SetMP( 0, 999 )
SetMP( 1, 999 )
SetMP( 3, 999 )
SetMP( 2, 999 )
SetMP( 4, 999 )
SetMP( 5, 999 )
SetMP( 7, 999 )
SetMP( 6, 999 )
SetMP( 8, 999 )
CureStatus( 0, 127 )
CureStatus( 1, 127 )
CureStatus( 3, 127 )
CureStatus( 2, 127 )
CureStatus( 4, 127 )
CureStatus( 5, 127 )
CureStatus( 7, 127 )
CureStatus( 6, 127 )
CureStatus( 8, 127 )
Menu( 0, 0 )
Wait( 3 )
if ( VAR_GlobUInt8_17 == 255 ) {
set Op66(( GetData_12 - 160 ), ( GetData_13 - 112 ))
}
0xA9( 250 )
FadeFilter( 7, 16, VAR_GlobUInt8_17, 0, 0, 0 )
Wait( 2 )
RunScript( 2, 251, 32 )
RunScript( 2, 252, 32 )
RunScript( 2, 253, 32 )
RunScript( 2, 254, 32 )
while ( VAR_GlobUInt8_40 < 4 ) {
Wait( 1 )
}
RunSoundCode( 2566, 2 )
MoveCamera( 180, 120, 120, 8 )
Wait( 120 )
RunSoundCode2( 38401, 65535, 48, 0 )
RunSoundCode3( 54145, 2100, 0, 24, 0 )
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, 2100, 0 )
}
if ( VAR_GlobBool_163 == 0 ) {
}
set General_FieldEntrance = 0
Battle( 1, 938 )
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, 2100, 0 )
}
if ( VAR_GlobBool_163 == 0 ) {
}
set General_FieldEntrance = 0
Field( 2929 )
return
CureStatus( 0, 127 )
CureStatus( 1, 127 )
CureStatus( 3, 127 )
CureStatus( 2, 127 )
CureStatus( 4, 127 )
CureStatus( 5, 127 )
CureStatus( 7, 127 )
CureStatus( 6, 127 )
CureStatus( 8, 127 )
break
}
}
if ( 0 ) {
set Setting_OptionalQuina = 0
}
set Setting_PartyReserve = 1083
SetPartyReserve( Setting_PartyReserve )
if ( ( ( Setting_PartyInitialized >> 0 ) & 1 ) == 0 ) {
SetCharacterData( 0, 1, 255, 9, 0 )
set Setting_PartyInitialized |= 1
}
if ( ( ( Setting_PartyInitialized >> 1 ) & 1 ) == 0 ) {
SetCharacterData( 1, 1, 255, 5, 1 )
set Setting_PartyInitialized |= 2
}
if ( ( ( Setting_PartyInitialized >> 2 ) & 1 ) == 0 ) {
SetCharacterData( 2, 1, 255, 6, 2 )
set Setting_PartyInitialized |= 4
}
if ( ( ( Setting_PartyInitialized >> 3 ) & 1 ) == 0 ) {
SetCharacterData( 3, 1, 255, 5, 3 )
set Setting_PartyInitialized |= 8
}
if ( ( ( Setting_PartyInitialized >> 4 ) & 1 ) == 0 ) {
SetCharacterData( 4, 1, 255, 6, 4 )
set Setting_PartyInitialized |= 16
}
if ( ( ( Setting_PartyInitialized >> 5 ) & 1 ) == 0 ) {
SetCharacterData( 5, 1, 255, 5, 5 )
set Setting_PartyInitialized |= 32
}
if ( ( ( Setting_PartyInitialized >> 6 ) & 1 ) == 0 ) {
SetCharacterData( 6, 1, 255, 6, 6 )
set Setting_PartyInitialized |= 64
}
if ( ( ( Setting_PartyInitialized >> 7 ) & 1 ) == 0 ) {
SetCharacterData( 7, 0, 255, 5, 7 )
set Setting_PartyInitialized |= 128
}
SetName( 11, 30 )
SetCharacterData( 11, 1, 10, 21, 12 )
SetPartyReserve( 1083 )
set Setting_OptionalQuina = 1
set Setting_DaggerDepresses = 0
set Setting_MPx4 = 0
if ( 1 ) {
Party( 4, 1 )
UpdatePartyUI( )
} else {
Party( 0, 1 )
UpdatePartyUI( )
}
if ( IsInParty(5) ) {
set Setting_OptionalQuina = 1
}
if (IsInParty(6)) {
RemoveParty(6)
}
if (Status.checkCurStat(regist, 16384u) && cur_cmd.cmd_no != 3 && cur_cmd.cmd_no != 12) // The status "16384" is trance ; The commands 3 and 12 are "Jump"
{
byte b = (byte)((300 - (int)regist.level) / (int)regist.elem.wpr * 10); // That's the amount by which the trance is depleted
if (cur_cmd.cmd_no == 21 || cur_cmd.cmd_no == 23)
{
b /= 2; // For Double-Casts, it's halfed
}
if (FF9StateSystem.Settings.IsTranceFull)
{
b = 0; // Cheat mode
}
if (regist.trance > b)
{
BTL_DATA expr_1B0 = regist;
expr_1B0.trance -= b;
}
else if (!FF9StateSystem.Battle.isDebug)
{
btl_stat.RemoveStatus(regist, 16384u);
}
if (cur_cmd.cmd_no == 18 && btlsys.phantom_no != 0) // This registers the command for Dagger's Eidolon: it will recast the spell afterwards
{
btlsys.cmd_status |= 4;
btlsys.phantom_cnt = btl_cmd.setPhantomCount(regist);
}
}
I didn't really understand what you wanted to do, but there's a high probability that it's there.
Wasn’t till now:
Still no options to resize the UI menu for battles without using Memoria?
I also tried to change font with DnSpy... but it gives me the following error, may I did something wrong?
[img width=640 height=305]https://i.imgur.com/0tLMM2n.jpg[/
Last UPDATE:
Is there a way to cut the tutorial before the very first battle and the "Warning security" stuff before the Squaresoft logo? And where can I find the Texture2D of the Launcher?
I used to get that error a lot. Delete that mscorlib.dll (right panel) and recompile.
There isn’t a texture for the Launcher in any of the archives. That requires a different approach to change. Fact is, you can actually use the launcher from Memoria change the image launcher and use that compatible throughout. I use the launcher from Memoria to change the image. Changing the launcher image in Memoria wont affect your CSharp either.
Wasn’t till now:
Here (https://tri3fecta.com/ff9-battle-ui-fix/)
for your case, use this as your Csharp base.
Omg, thank you dude! Everything is perfect! ;D
Thank you, but I was thinking about something more like the PS1 version, something like this https://steamcommunity.com/groups/ff-modding/discussions/13/1290690926876650747/
The problem is that I don't know it I can apply it without mess everything (plus there's the problem about the link you sent me that if I copy and paste the AssemblyCSharp I will replace mine with all the work I made , right? )
case 96:
target.trance = byte.MaxValue;
btl_stat.AlterStatus(target, 16384u);
break;
9) Replace that case by this: case 96:
if (Status.checkCurStat(target, 16384u)) {
target.trance = 0;
btl_stat.RemoveStatus(target, 16384u);
} else {
target.trance = byte.MaxValue;
btl_stat.AlterStatus(target, 16384u);
}
break;
11) Compile. Apparently, dnSpy whines about implicit type-casting... So it will be a bit tedious, but for all the errors you get (double-click to go to the related line), add a type cast like this for example:Default: target.elem.str = target.elem.str * 3 / 4;
Replace with: target.elem.str = (byte)(target.elem.str * 3 / 4);
I've put "byte" in the parenthesis for this one because the error says "Cannot convert to 'byte'". You need to write "short" instead when the error is about converting to short. After each line replaced, you can press "Compile" to verify that the error line disappears.I'm not sure about the music format, but OGG seemed to be a quite popular format to me.
Audacity says that it can import and export files in the OGG format.
Don't forget that the file extension is only informative. In FF9 assets, they really didn't care about using correct file formats specifications, so it's not because the files have an extension ".mesh", ".txt" or ".png" that they really are Mesh, text or PNG files (for the later, the tool explicitely converts the assets to PNG but that's not what they are inside the archive).
Rename the sound files to ".ogg" if Audacity doesn't recognize them automatically.
@Tirlititi @Incinerator i tried the procedure you explained with audacity but the import still fail , what could be the cause ? maybe the problem is the audio file itself , i downloaded that file trough this site : https://www.onlinevideoconverter.com/it/video-converter
@Incinerator ok , now it works , i imported a song found on youtube, initially it didn't work because the extension of the music file was hidden by a default setting of windows 10 , in any case , now i need some help to solve another problem : the game doesn't run the song endlessly like it should , it play that only once , so where the game handle the "loop" function ? and what i must write in order to create the loop ?
How do you mod it? Is it HW that gives you a bugged CSharp? If so, did you mod the CSharp beforehand with dnSpy?
so maybe the problem can the the size of the loop , i don't know , what do you think ? :\
If you modified your CSharp with dnSpy and it's now not working, it can be pretty much anything...
We can't help you if you don't post the code that is bugged.
UPDATE: Guys I guess is solved, I noticed the problem when I tried to import it again with Dnspy, and I saw that every archive (like FF9, UI and stuff) are gone! So i decided to come back with a "Virgin" CSharp an put everything again, now I edit again the font ;)
UPDATE2: Aaaaand, i did it! I made anyway a backup, in case I will find other problems!
Did you set the Ability learning correctly? The first ability must have a non-zero AP requirement (if I remember correctly, that's the only thing to set up).
The method enabling it is "ff9abil::FF9Abil_HasAp". You can check that method to know why it doesn't apply for him.
About giving trance to someone else, I'll make a few tests but it may be possible to actually do it now with dnSpy/Albeoris's Memoria. Of course, unless you import another model, the trance appearance will be roughly the same as the normal state.
I don't guarantee anything though ^^'
Guys I want to disable the menu button when I'm using Cid Frog... it's possible?
You know I noticed this myself. The menu is enabled whilst controlling as Cid_Frog before the red light green light mini game.
Wasn’t like that in psx as far as I know.
Never the matter a simple fix.
- There is a special check in the engine's source code that prevents the effect of "DisableMenu" in that field at that point, which is likely to be a mistake.
Is model importing still broken? or am I doing things wrong?
I've tried importing proper versions of ASCII FBX & Binary FBX, but they either crash the game, or fail to load the scene.
Yes, it's still broken. I don't know what program you use for creating your FBX files, but you *should* be able to import accessory models.
The character models are a mess... I don't know what fails and why and I gave it up, at least temporarily.
Also, I didn't test replacing only the animations in the latest version, but it was working pretty nicely last time... so you may also do that if I'm not mistaken.
The character models are a mess... I don't know what fails and why and I gave it up, at least temporarily.
Also, I didn't test replacing only the animations in the latest version, but it was working pretty nicely last time... so you may also do that if I'm not mistaken.
Ah, I mainly use Blender. Thanks for the replies, looking forward to it being fixed no matter how long it takes.
if (ff9abil.FF9Abil_GetEnableSA((int)pLAYER.info.slot_no, 235))
{
battleEndValue.value += this.defaultExp >> 1;
}
And for AP: if (ff9abil.FF9Abil_GetEnableSA((int)pLAYER.info.slot_no, 236))
{
battleEndValue2.value = this.defaultAp << 1;
}
If you're not familiar with the shift operators, you can simply consider that "+= this.defaultExp >> 1" adds half of the default experience to the total, and "this.defaultAp << 1" is twice the number of AP (it's like a division or a multiplication by 2).And for AP:Code: [Select]if (ff9abil.FF9Abil_GetEnableSA((int)pLAYER.info.slot_no, 236))
If you're not familiar with the shift operators, you can simply consider that "+= this.defaultExp >> 1" adds half of the default experience to the total, and "this.defaultAp << 1" is twice the number of AP (it's like a division or a multiplication by 2).
{
battleEndValue2.value = this.defaultAp << 1;
}
You can replace those formulae by something else, like "battleEndValue.value = this.defaultExp * 3;" for getting three times the exp with Level Up.
ushort curap = FF9StateSystem.EventState.gEventGlobal[1500+2*pLAYER.info.slot_no] | ((ushort)FF9StateSystem.EventState.gEventGlobal[1500+2*pLAYER.info.slot_no+1] << 8);
curap += ap;
FF9StateSystem.EventState.gEventGlobal[1500+2*pLAYER.info.slot_no] = curap & 0xFF;
FF9StateSystem.EventState.gEventGlobal[1500+2*pLAYER.info.slot_no+1] = curap >> 8;
With this, the general variables "VARL_GenUInt16_1500" will hold the AP storage number (65535 max) of Zidane, "VARL_GenUInt16_1502" will contain the one's of Vivi, etc... I've chosen 1500 randomly ; I think that this general variable is not used but it might be.Yes, well, it's more in the "BattleResultUI::AddAp" method that you'd want to do that.
In that method, there's a loop over the equipments, then a loop over the ability slot of each piece of equipment, and the increase of these abilities' AP.
You can replace the whole loop by:Code: [Select]ushort curap = FF9StateSystem.EventState.gEventGlobal[1500+2*pLAYER.info.slot_no] | ((ushort)FF9StateSystem.EventState.gEventGlobal[1500+2*pLAYER.info.slot_no+1] << 8);
With this, the general variables "VARL_GenUInt16_1500" will hold the AP storage number (65535 max) of Zidane, "VARL_GenUInt16_1502" will contain the one's of Vivi, etc... I've chosen 1500 randomly ; I think that this general variable is not used but it might be.
curap += ap;
FF9StateSystem.EventState.gEventGlobal[1500+2*pLAYER.info.slot_no] = curap & 0xFF;
FF9StateSystem.EventState.gEventGlobal[1500+2*pLAYER.info.slot_no+1] = curap >> 8;
But then you need some system to allow players to spend these "ap_store" into abilities. And that's a completly different story, quite harder.
What you can do with that is to make this system with the field scripts: for instance, you can add the option to spend AP in the moogles' menu. If you don't want it, you have to wait until we know how to add a full menu with GameObjects and such. That surely won't be soon.
What were you trying to import? Accessory, Character?
the game's source code espects some 3D models to have very special hierarchy or bone names or whatever. It is not clear to me what are these special requirements, in addition to the bugs that probably exist in the model conversion.
I think I found a bug in Hades Workshop, but I'm not sure, it could be some weird glitch in my game files. I noticed that whenever I edit the status effect on the spell Silence, it also modifies the status effect on Doom. Likewise Earth Shake seems to be paired with Slow and Dragon's Crest is paired with Annoy. Any time I change the status effect for one of them, the other also changes. There may be others as well, those are just the ones I verified.
Any ideas/fixes?
My only speculation be you changed status effcts from the “Edit Status” sub menu instead drop down, Seems odd from this angle, but I’m not near my pc to see.
No, I don't plan on making any other CIL macro.
{
"ID of Field": {
"ID of Battle in the Field": "ID of Battle Music",
...
},
...
}
Battles have the music ID "0" (for normal encounters), "35" (for bosses) and "111" (for Hunter's Chance). Some battles are not registered in these files, when they don't stop the music played in the field (the "Don't Stop Music" battle flag is also checked for them in the "Enemy" panel).
Battles have the music ID "0" (for normal encounters), "35" (for bosses) and "111" (for Hunter's Chance). Some battles are not registered in these files, when they don't stop the music played in the field (the "Don't Stop Music" battle flag is also checked for them in the "Enemy" panel).
SetRandomBattleFrequency( 60 )Now I get proper random encounters in that field, but the music doesn't change to the battle theme. Instead, the normal field music keeps playing. Is there any sort of SoundCode that I have to add somewhere in the field script for that?
SetRandomBattles( 2, 859, 849, 854, 854 )
No: as you can see from the format of the "BtlEncountBGMMetaData.txt", the battle musics are not linked by "1 Battle -> 1 Music" but rather by "1 Field + 1 Battle -> 1 Music". So you need to add a line for your new battle (or, more precisely, to your new use of a battle inside a field) inside this .txt file.
No sound code needs to be added in the field script.
Hi tirlititi, I've done a bit of playtesting in the last few days, but it seems the desired changes to the battle theme won't take effect. Here's what I did:
I've exported the BtlEncountBGMMetaData.txt, opened it with a text editor and made the required changes, and then I imported it again using the "import selection" function in Hades Workshop. I've done this with both resource.assets files (the x64 and the x86) to be sure. However, I still don't get any music changes in my new random battles. Both resource.assets files are updated according to the fiel change date. Is there anything else I'm missing?
Also, I've encountered another problem: When adding random battles to a new field, after such a battle the field music doesn't resume and I can't move my character anymore. I've noticed that all fields that naturally have random battles also have a main_reinit function in their scripts, while fields without random battles don't. So I'm guessing I need to write a main_reinit function for the fields that I've added random encounters to, right? I'm just unsure what exactly I need to put there, as these scripts seem to differ from field to field. From what I see it's something similar to each respective field's main_init function, but before I resort to (potentially fruitless) trial and error I was hoping that you could give me some general tips as to what I can copy/paste from the main_init script.
Function Main_Reinit
set VAR_GlobBool_159 = 0
RunScriptAsync( 0, 250, 13 )
if ( VAR_GlobBool_155 == 1 ) {
ATE( 1 )
}
ShowTile( 11, 0 )
ShowTile( 12, 0 )
if ( VAR_GlobBool_158 == 0 ) {
0x27( 127 )
} else {
0x27( 255 )
}
Wait( 2 )
ShowTile( 9, 0 )
RunTileAnimation( 0, 0 )
SetTileAnimationFlags( 0, 16 )
SetTileAnimationSpeed( 0, 64 )
RunSPSCode( 10, 130, 195, 0, 0 )
RunSPSCode( 10, 145, 6000, 0, 0 )
RunSPSCode( 10, 155, 255, 0, 0 )
RunSPSCode( 10, 160, 16, 0, 0 )
RunSPSCode( 10, 170, 0, 0, 0 )
RunSPSCode( 10, 156, 1, 0, 0 )
RunSPSCode( 10, 131, 1, 0, 0 )
SetCameraFollowHeight( 500 )
if ( VARL_GenBool_2926 ) {
ShowTile( 9, 1 )
}
if ( VAR_GlobUInt8_24 ) {
RunScriptAsync( 2, 15, 14 )
}
if ( VAR_GlobUInt8_25 ) {
RunScriptAsync( 2, 18, 14 )
}
Wait( 2 )
if ( VAR_GenUInt8_13 == 9 ) {
SetTextVariable( 2, 0 )
WindowAsync( 6, 0, 65 )
RaiseWindows( )
WaitWindow( 6 )
set VAR_GenUInt8_13 = 0
}
if ( VAR_GenUInt8_14 == 9 ) {
SetTextVariable( 2, 1 )
WindowAsync( 6, 0, 65 )
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
if ( VARL_GenBool_7962 == 0 ) {
DisableMove( )
DisableMenu( )
RunSoundCode( 265, 0 )
Wait( 10 )
0xA9( 250 )
FadeFilter( 4, 24, VAR_GlobUInt8_17, 255, 255, 255 )
Wait( 25 )
RunSoundCode3( 53248, 3096, 0, -128, 125 )
Wait( 30 )
0xA9( 250 )
FadeFilter( 5, 16, VAR_GlobUInt8_17, 0, 0, 0 )
Wait( 70 )
RunSoundCode( 0, 73 )
WindowSync( 1, 128, 400 )
WindowSyncEx( 22, 1, 128, 401 )
Wait( 10 )
0xA9( 250 )
FadeFilter( 4, 24, VAR_GlobUInt8_17, 255, 255, 255 )
Wait( 25 )
RunSoundCode3( 53248, 3096, 0, -128, 125 )
Wait( 30 )
0xA9( 250 )
FadeFilter( 5, 16, VAR_GlobUInt8_17, 0, 0, 0 )
Wait( 10 )
WindowSyncEx( 22, 1, 128, 402 )
WindowSync( 1, 128, 403 )
WindowSyncEx( 22, 1, 128, 404 )
WindowSync( 1, 128, 405 )
FadeFilter( 2, 24, 0, 64, 64, 64 )
RaiseWindows( )
WindowSync( 1, 16, 406 )
WindowSync( 1, 16, 407 )
WindowSync( 1, 16, 408 )
WindowSync( 1, 16, 409 )
set VARL_GenBool_7962 = 1
}
DisableMove( )
DisableMenu( )
RunSoundCode( 0, 73 )
WindowSync( 1, 16, 410 )
switch 5 ( GetDialogChoice ) from 0 {
case +0:
RunSoundCode( 0, 0 )
DisableMenu( )
DisableMove( )
Wait( 20 )
Battle( 1, 896 )
RunSoundCode( 0, 111 )
DisableMenu( )
DisableMove( )
Wait( 20 )
RunSoundCode( 0, 111 )
DisableMenu( )
DisableMove( )
Wait( 20 )
Battle( 1, 899 )
RunSoundCode( 0, 111 )
DisableMenu( )
DisableMove( )
Wait( 20 )
RunSoundCode( 0, 111 )
DisableMenu( )
DisableMove( )
Wait( 20 )
Battle( 1, 897 )
RunSoundCode( 0, 111 )
DisableMenu( )
DisableMove( )
Wait( 20 )
RunSoundCode( 0, 111 )
DisableMenu( )
DisableMove( )
Wait( 20 )
Battle( 1, 210 )
RunSoundCode( 0, 111 )
DisableMenu( )
DisableMove( )
Wait( 20 )
RunSoundCode( 0, 111 )
DisableMenu( )
DisableMove( )
Wait( 20 )
Battle( 1, 211 )
RunSoundCode( 0, 111 )
DisableMenu( )
DisableMove( )
Wait( 20 )
RunSoundCode( 0, 111 )
DisableMenu( )
DisableMove( )
Wait( 20 )
Battle( 1, 57 )
RunSoundCode( 0, 111 )
DisableMenu( )
DisableMove( )
Wait( 20 )
RunSoundCode( 0, 111 )
DisableMenu( )
DisableMove( )
Wait( 20 )
Battle( 1, 82 )
RunSoundCode( 0, 111 )
DisableMenu( )
DisableMove( )
Wait( 20 )
RunSoundCode( 0, 111 )
DisableMenu( )
DisableMove( )
Wait( 20 )
Battle( 1, 231 )
RunSoundCode( 0, 111 )
DisableMenu( )
DisableMove( )
Wait( 20 )
RunSoundCode( 0, 111 )
DisableMenu( )
DisableMove( )
Wait( 20 )
Battle( 1, 280 )
RunSoundCode( 0, 111 )
DisableMenu( )
DisableMove( )
Wait( 20 )
RunSoundCode( 0, 111 )
DisableMenu( )
DisableMove( )
Wait( 20 )
Battle( 1, 763 )
RunSoundCode( 0, 111 )
DisableMenu( )
DisableMove( )
Wait( 20 )
0xA9( 250 )
FadeFilter( 4, 24, VAR_GlobUInt8_17, 255, 255, 255 )
Wait( 25 )
RunSoundCode3( 53248, 3096, 0, -128, 125 )
Wait( 30 )
0xA9( 250 )
FadeFilter( 5, 16, VAR_GlobUInt8_17, 0, 0, 0 )
Wait( 30 )
RunSoundCode( 0, 5 )
FadeFilter( 2, 24, 0, 64, 64, 64 )
RaiseWindows( )
WindowSync( 1, 16, 411 )
0xA9( 250 )
FadeFilter( 4, 24, VAR_GlobUInt8_17, 255, 255, 255 )
Wait( 25 )
RunSoundCode3( 53248, 3096, 0, -128, 125 )
Wait( 30 )
0xA9( 250 )
FadeFilter( 5, 16, VAR_GlobUInt8_17, 0, 0, 0 )
Wait( 30 )
FadeFilter( 2, 24, 0, 64, 64, 64 )
RaiseWindows( )
WindowSync( 1, 16, 412 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 15 )
AddItem( 15, 13 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 25 )
AddItem( 25, 1 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 39 )
AddItem( 39, 1 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 49 )
AddItem( 49, 13 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 44 )
AddItem( 44, 13 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 56 )
AddItem( 56, 1 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 61 )
AddItem( 61, 1 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 63 )
AddItem( 63, 1 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 67 )
AddItem( 67, 1 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 78 )
AddItem( 78, 13 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 83 )
AddItem( 83, 1 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 84 )
AddItem( 84, 1 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 87 )
AddItem( 87, 50 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 96 )
AddItem( 96, 13 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 97 )
AddItem( 97, 13 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 131 )
AddItem( 131, 6 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 147 )
AddItem( 147, 7 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 163 )
AddItem( 163, 4 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 164 )
AddItem( 164, 13 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 167 )
AddItem( 167, 13 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 175 )
AddItem( 175, 13 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 176 )
AddItem( 176, 8 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 191 )
AddItem( 191, 13 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 195 )
AddItem( 195, 13 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 197 )
AddItem( 197, 13 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 209 )
AddItem( 209, 13 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 222 )
AddItem( 222, 13 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 198 )
AddItem( 198, 8 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 225 )
AddItem( 225, 50 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 226 )
AddItem( 226, 50 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 227 )
AddItem( 227, 50 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 228 )
AddItem( 228, 50 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 229 )
AddItem( 229, 50 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 230 )
AddItem( 230, 50 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 231 )
AddItem( 231, 50 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 232 )
AddItem( 232, 50 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 233 )
AddItem( 233, 50 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 234 )
AddItem( 234, 50 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 238 )
AddItem( 238, 50 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 235 )
AddItem( 235, 50 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 241 )
AddItem( 241, 50 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 242 )
AddItem( 242, 50 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 243 )
AddItem( 243, 50 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 247 )
AddItem( 247, 50 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 248 )
AddItem( 248, 50 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 249 )
AddItem( 249, 50 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 250 )
AddItem( 250, 13 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 253 )
AddItem( 253, 50 )
WindowSync( 7, 0, 68 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
SetTextVariable( 0, 254 )
AddItem( 254, 50 )
WindowSync( 7, 0, 68 )
WindowSync( 1, 16, 413 )
WindowSync( 1, 16, 414 )
set VARL_GenBool_7963 = 1
FadeFilter( 6, 16, VAR_GlobUInt8_17, 255, 255, 255 )
EnableMove( )
RunSoundCode( 0, 73 )
EnableMenu( )
Wait( 16 )
FadeFilter( 7, 16, VAR_GlobUInt8_17, 0, 0, 0 )
TerminateEntry( 255 )
break
case +1:
DisableMenu( )
DisableMove( )
Menu( 0, 0 )
EnableMove( )
EnableMenu( )
break
case +2:
DisableMenu( )
DisableMove( )
Party( 4, 0 )
UpdatePartyUI( )
EnableMove( )
EnableMenu( )
break
case +3:
DisableMenu( )
DisableMove( )
SetHP( 0, 9999 )
SetMP( 0, 999 )
CureStatus( 0, 255 )
SetHP( 1, 9999 )
SetMP( 1, 999 )
CureStatus( 1, 255 )
SetHP( 2, 9999 )
SetMP( 2, 999 )
CureStatus( 2, 255 )
SetHP( 3, 9999 )
SetMP( 3, 999 )
CureStatus( 3, 255 )
SetHP( 4, 9999 )
SetMP( 4, 999 )
CureStatus( 4, 255 )
SetHP( 5, 9999 )
SetMP( 5, 999 )
CureStatus( 5, 255 )
SetHP( 6, 9999 )
SetMP( 6, 999 )
CureStatus( 6, 255 )
SetHP( 7, 9999 )
SetMP( 7, 999 )
CureStatus( 7, 255 )
SetHP( 8, 9999 )
SetMP( 8, 999 )
CureStatus( 8, 255 )
SetHP( 9, 9999 )
SetMP( 9, 999 )
CureStatus( 9, 255 )
SetHP( 10, 9999 )
SetMP( 10, 999 )
CureStatus( 10, 255 )
SetHP( 11, 9999 )
SetMP( 11, 999 )
CureStatus( 11, 255 )
RunSoundCode3( 53248, 534, 0, -128, 125 )
FadeFilter( 2, 24, 0, 64, 64, 64 )
RaiseWindows( )
WindowSync( 1, 16, 80 )
EnableMove( )
EnableMenu( )
break
case +4:
EnableMove( )
EnableMenu( )
Wait( 16 )
FadeFilter( 7, 16, VAR_GlobUInt8_17, 0, 0, 0 )
if ( GetDialogChoice == 0 ) {
FadeFilter( 7, 16, VAR_GlobUInt8_17, 0, 0, 0 )
} else {
EnableMove( )
0x27( 255 )
EnableMenu( )
}
}
return
@Kefka: Yes, it is possible with dnSpy again. In the "btl_calc::CalcMain", you need to put the line "btl_calc.CalcSub_15E(cALC_VAR);" a bit everywhere ^^'
Again, having a look at this file (https://www.dropbox.com/s/2k2mkezqx0loe4i/Source_BtlCalc.cs?dl=0) makes it easier to read the spell effects before editing the real thing (that has idiotic names and is harder to read).
For example, go to the "case 19" (Physical Strike effect) and change it to this:Code: [Select]case 19:
You should put the line before the "CalcSub_20X" ("DoSetDamage_..." in the readable version).
btl_calc.CalcSub_13A(cALC_VAR);
btl_calc.CalcSub_141(cALC_VAR);
btl_calc.CalcSub_143(cALC_VAR);
btl_calc.CalcSub_159(cALC_VAR);
if (btl_calc.CalcSub_152(cALC_VAR))
{
btl_calc.CalcSub_15E(cALC_VAR);
btl_calc.CalcSub_203(cALC_VAR);
btl_calc.CalcSub_270(cALC_VAR);
}
break;
byte x = (byte)5;
It's sometimes a bit more complicated, like "byte x = intvalue1 + intvalue2;" in which case you must also add parentheses around what needs to be converted:byte x = (byte)(intvalue1 + intvalue2);
What I personally do is that I create a .txt file in my mod's folder named after the class/method I edit and I put the code (and its modifications) in that file. This way, I only have to "Select All + Copy + Paste" when I change it (otherwise, I'd need to write these type conversions everytime because dnSpy doesn't register them after compilation).if (cALC_VAR.at_pow - cALC_VAR.df_pow > 0)
@Kefka: No problem. Well done going this far (you did most of the job).
For the errors, they are caused by dnSpy but they are not problematic: you just need to write the type conversion yourself when these errors pop. For instance, if the line "byte x = 5;" gives an error, change it to this:
Code: [Select]
byte x = (byte)5;
It's sometimes a bit more complicated, like "byte x = intvalue1 + intvalue2;" in which case you must also add parentheses around what needs to be converted:
Code: [Select]
byte x = (byte)(intvalue1 + intvalue2);
What I personally do is that I create a .txt file in my mod's folder named after the class/method I edit and I put the code (and its modifications) in that file. This way, I only have to "Select All + Copy + Paste" when I change it (otherwise, I'd need to write these type conversions everytime because dnSpy doesn't register them after compilation).
For the Darkside and Lancer effects, you need to add the line after the "at_pow" variable is set (it's usually in the "Setup..." call but sometimes it's directly in the "case" code) and before it is used (again, it's usually in the "DoSetDamage..." but sometimes it's directly in the "case" code). So for Lancer and Darskide, you need to add "btl_calc.CalcSub_15E(cALC_VAR);" before that one:
Code: [Select]
if (cALC_VAR.at_pow - cALC_VAR.df_pow > 0)
case 99: // Flare Star
btl_calc.SetupAccuracyMagic(cALC_VAR);
btl_calc.ApplyShellAccuracy(cALC_VAR);
btl_calc.ApplyMultiTargetAccuracyPenalty(cALC_VAR);
if (btl_calc.CheckRawAccuracyEvasionMiss(cALC_VAR))
{
CALC_VAR expr_29D6 = cALC_VAR;
expr_29D6.tg_flags |= this.CALC_FLAG_MISS;
cALC_VAR.tg_hp = (short)(target.level * cmd.aa.Ref.power);
}
break;
case 99: // Flare Star
cALC_VAR.tg_flags |= this.CALC_FLAG_MISS;
cALC_VAR.tg_hp = (short)(target.level * cmd.aa.Ref.power);
break;
Also, that's an error from my end: it shouldn't display "this.CALC_FLAG_MISS" but "this.CALC_TGFLAG_HP" instead, because that's not the "miss" flag that is turned on but the "deals damage to target" flag. I fixed it.PS: Since the last HW update, you can select "Unused XXX" in the list of spell effects. This allows you to code a completely new spell effect (deals damage to the target and heals caster's MP, to give a random example) without replacing any other. You just need to add a "case XXX" to this method in dnSpy.
if ( !VAR_LocUInt8_31 ) {
set VAR_LocUInt8_31 = 1
if ( GetRandom & 1 ) {
set #( SV_Target = SV_FunctionEnemy )
Attack( 8 )
return
}
}
switch 4 ( GetRandom % 4 ) from 0 {
case +0:
set #( SV_Target = RandomInTeam(SV_PlayerTeam) )
Attack( 3 )
break
case +1:
set #( SV_Target = RandomInTeam(SV_PlayerTeam) )
Attack( 4 )
break
case +2:
set #( SV_Target = RandomInTeam(SV_PlayerTeam) )
Attack( 5 )
break
case +3:
set #( SV_Target = RandomInTeam(SV_PlayerTeam) )
Attack( 6 )
break
}
return
SetTextVariable(0, FirstOf(SV_FunctionEnemy[ATB]))
BattleDialog( X )
Wait( 1 )
loop
...where the battle dialog X is a "[NUMB=0]" message. You should at least see if the loop function runs and if the enemy's ATB fills up.
ffix_img_extr.exe <C:\Users\PC\Desktop\Nouveau dossier> <C:\Users\SonyNintendo\Desktop\Nouveau dossier\Nouveau dossier>
ffix_img_extr.exe <C:\Users\PC\Desktop\Nouveau dossier> <C:\Users\SonyNintendo\Desktop\Nouveau dossier\Nouveau dossier/>
FF9_img_extractor.exe C:\Users\PC\Desktop\Nouveau dossier C:\Users\SonyNintendo\Desktop\Nouveau dossier\Nouveau dossier/
FF9_img_extractor.exe C:\Users\PC\Desktop\Nouveau dossier C:\Users\SonyNintendo\Desktop\Nouveau dossier\Nouveau dossier
ffix_img_extr.exe (<C:\Users\PC\Desktop\Nouveau dossier/to/ff9.im> <C:\Users\SonyNintendo\Desktop\Nouveau dossier\Nouveau dossier/to/extract>)
ffix_img_extr.exe C:\Users\PC\Desktop\Nouveau dossier/to/ff9.im> C:\Users\SonyNintendo\Desktop\Nouveau dossier\Nouveau dossier/to/extract>
ffix_img_extr.exe <C:\Users\PC\Desktop\Nouveau dossier/to/ff9.im> <C:\Users\SonyNintendo\Desktop\Nouveau dossier\Nouveau dossier/to/extract>
ffix_img_extr.exe "C:\Users\PC\Desktop\Nouveau dossier\ff9.img" "C:\Users\SonyNintendo\Desktop\Nouveau dossier"
If you don't have a ff9.img file but only a .bin, you need to use a tool (like CDmage) to extract the .img out of the .bin (Zidane_2's tools is always using the .img).
ffix_img_extr.exe <C:\Users\PC\Desktop\Nouveau dossier/to/ff9.im> <C:\Users\PC\Desktop\Nouveau dossier\Nouveau dossier/to/extract>
Normal Dir
0 Flag:0 Start Sector: fda9 End Sector: fe15
1 Flag:1 Start Sector: fe15 End Sector: fe82
2 Flag:2 Start Sector: fe82 End Sector: feee
3 Flag:3 Start Sector: feee End Sector: ff5a
4 Flag:4 Start Sector: ff5a End Sector: ffc6
5 Flag:5 Start Sector: ffc6 End Sector: 10030
6 Flag:6 Start Sector: 10030 End Sector: 1009b
7 Flag:7 Start Sector: 1009b End Sector: 10108
8 Flag:8 Start Sector: 10108 End Sector: 10176
9 Flag:9 Start Sector: 10176 End Sector: 101e2
10 Flag:a Start Sector: 101e2 End Sector: 1024e
11 Flag:b Start Sector: 1024e End Sector: 102bb
12 Flag:c Start Sector: 102bb End Sector: 10327
13 Flag:d Start Sector: 10327 End Sector: 10393
14 Flag:e Start Sector: 10393 End Sector: 103ff
15 Flag:f Start Sector: 103ff End Sector: 1046b
16 Flag:10 Start Sector: 1046b End Sector: 104d8
17 Flag:11 Start Sector: 104d8 End Sector: 10545
18 Flag:12 Start Sector: 10545 End Sector: 105b1
19 Flag:13 Start Sector: 105b1 End Sector: 1061e
20 Flag:14 Start Sector: 1061e End Sector: 1068a
21 Flag:15 Start Sector: 1068a End Sector: 106f7
22 Flag:16 Start Sector: 106f7 End Sector: 10765
23 Flag:17 Start Sector: 10765 End Sector: 107d2
24 Flag:18 Start Sector: 107d2 End Sector: 1083f
25 Flag:19 Start Sector: 1083f End Sector: 108ad
26 Flag:1a Start Sector: 108ad End Sector: 1091a
27 Flag:1b Start Sector: 1091a End Sector: 10989
28 Flag:1c Start Sector: 10989 End Sector: 109f7
29 Flag:1d Start Sector: 109f7 End Sector: 10a64
30 Flag:1e Start Sector: 10a64 End Sector: 10ad1
31 Flag:1f Start Sector: 10ad1 End Sector: 10b3e
32 Flag:20 Start Sector: 10b3e End Sector: 10bab
33 Flag:21 Start Sector: 10bab End Sector: 10c18
34 Flag:22 Start Sector: 10c18 End Sector: 10c85
35 Flag:23 Start Sector: 10c85 End Sector: 10cf1
36 Flag:24 Start Sector: 10cf1 End Sector: 10d5f
37 Flag:25 Start Sector: 10d5f End Sector: 10dce
38 Flag:26 Start Sector: 10dce End Sector: 10e3a
39 Flag:27 Start Sector: 10e3a End Sector: 10ea6
40 Flag:28 Start Sector: 10ea6 End Sector: 10f13
41 Flag:29 Start Sector: 10f13 End Sector: 10f80
42 Flag:2a Start Sector: 10f80 End Sector: 10fee
43 Flag:2b Start Sector: 10fee End Sector: 1105b
44 Flag:2c Start Sector: 1105b End Sector: 110c9
45 Flag:2d Start Sector: 110c9 End Sector: 11135
46 Flag:2e Start Sector: 11135 End Sector: 111a2
47 Flag:2f Start Sector: 111a2 End Sector: 1120e
48 Flag:30 Start Sector: 1120e End Sector: 1127b
49 Flag:31 Start Sector: 1127b End Sector: 112e8
50 Flag:32 Start Sector: 112e8 End Sector: 11356
51 Flag:33 Start Sector: 11356 End Sector: 113c3
52 Flag:34 Start Sector: 113c3 End Sector: 11430
53 Flag:35 Start Sector: 11430 End Sector: 1149d
54 Flag:36 Start Sector: 1149d End Sector: 1150a
55 Flag:37 Start Sector: 1150a End Sector: 11578
56 Flag:38 Start Sector: 11578 End Sector: 115e5
57 Flag:39 Start Sector: 115e5 End Sector: 11653
58 Flag:3a Start Sector: 11653 End Sector: 116bf
59 Flag:3b Start Sector: 116bf End Sector: 1172a
60 Flag:3c Start Sector: 1172a End Sector: 11796
61 Flag:3d Start Sector: 11796 End Sector: 11803
62 Flag:3e Start Sector: 11803 End Sector: 11870
@Kefka: So, you are definitely doing something wrong (or maybe there was a bug in a previous version of HW and I don't remember fixing it and you are still using that old version of HW).
In your .hws file, there was no script update at all. There was only an unconfigured "Abadon + Amdusias" battle and 4 unconfigured "Hecteyes + Ring Leader" battles. When I say "unconfigured", it means that there was no entry added for the new enemy and no change in the "Main_Init" function. The enemy's stats and attacks were properly copied to the new battle and the group was properly setup. However, there was no proper script for him and it lacked its battle animations for some reason.
So you need:
- To do the steps 6) and 7) described there (http://forums.qhimm.com/index.php?topic=14315.msg245485#msg245485). Maybe you did on your end but shared an old .hws because none of these steps were put in the file you provided (and it cannot just be a bug with the entry: even your "Main_Init" function was not modified).
- To add the animations required to cast spells. The Ring Leader only uses 3 animations: select him, click on "Edit Resources", then "Add Animation" x3 and change them to "Cast Init", "Cast Loop" and "Cast End". Alternatively, changing the enemy's model ID to something else and switching it back will reset the resources (and thus automatically add these 3 animations).
After this fix, it was all good on my end. However, the other battles were you added more enemies (you have battles with 4 Ring Leaders) are not working correctly because you didn't add any "InitObject" line in those battles' script either.
ffix_img_extr.exe "C:\Users\PC\Desktop\Nouveau dossier/to/ff9.im" "C:\Users\PC\Desktop\Nouveau dossier\Nouveau dossier/to/extract"
Directory1 : 21 files
???,SaveMenu,Battle,???,TetraMaster,
???,???,ChocoMenu,MenuComp+MenuEquip,MenuConfig,
CardMenu,ItemMenu,StatusMenu,MainMenu,NamingMenu,
TeamMenu,ShopMenu,???,???,???,BattleRewardMenu
Directory2 :
Generic Cluster Datas (charmaps, backgrounds...)
Directory3 :
Dialog & Text Cluster Datas
Directory4 :
World Map Cluster Datas
Directory5 :
Field Cluster Datas
Directory6 :
Enemy Cluster Datas
Directory7 :
Battle Scene Cluster Datas
Directory8 :
Enemy Model Cluster Datas
Directory9 :
Weapon Model Cluster Datas
Directory10 :
Music Cluster Datas
Directory11 :
Party Battle Model Cluster Datas
Directory12 :
Audio Cluster Datas
Directory13 :
Unknown
Directory14 :
Spell Animation Datas
Directory15 :
Dummy for directory ending
Function Steiner_Init
SetModel( 5489, 104 )
CreateObject( -222, -2015 )
TurnInstant( 152 )
SetStandAnimation( 2001 )
SetWalkAnimation( 1996 )
SetRunAnimation( 2005 )
SetLeftAnimation( 1986 )
SetRightAnimation( 2010 )
SetObjectLogicalSize( 30, 35, 50 )
SetAnimationStandSpeed( 14, 16, 18, 20 )
SetHeadAngle( 97, 32 )
EnableHeadFocus( 0 )
return
Function Freya_Init
SetModel( 192, 94 )
CreateObject( 186, -2179 )
TurnInstant( 160 )
SetStandAnimation( 2556 )
SetWalkAnimation( 2553 )
SetRunAnimation( 2558 )
SetLeftAnimation( 2555 )
SetRightAnimation( 2551 )
SetObjectLogicalSize( 26, 34, 48 )
SetAnimationStandSpeed( 14, 16, 18, 20 )
SetHeadAngle( 105, 53 )
SetPathing( 1 )
EnableHeadFocus( 0 )
return
if ( VARL_GenBool_8038 == 1 ) {
InitObject( 20, 0 )
}
if ( VARL_GenBool_8040 == 1 ) {
TerminateEntry( 20 )
}
if ( VARL_GenBool_8041 == 1 ) {
InitObject( 21, 0 )
}
if ( VARL_GenBool_8043 == 1 ) {
TerminateEntry( 21 )
}
return
if ( VARL_GenBool_8038 == 1 ) {
InitObject( 20, 0 )
}
if ( VARL_GenBool_8040 == 1 ) {
TerminateEntry( 20 )
}
if ( VARL_GenBool_8041 == 1 ) {
InitObject( 21, 0 )
}
if ( VARL_GenBool_8043 == 1 ) {
TerminateEntry( 21 )
}
return
[STRT=15,4][STNR]
"Someone named [68C0D8][HSHD]Viera[C8C8C8][HSHD] was attacked in
[68C0D8][HSHD]Burmecia[C8C8C8][HSHD], yet their belongings forfeit.
I would have them returned."
[STRT=140,4][PCHC=2,1][IMME][STNR]
"The creature was [68C0D8][HSHD]Lavos[C8C8C8][HSHD]. Will you slay it?"
[CHOO][MOVE=18,0]Accept
[MOVE=18,0]Decline
[STRT=140,4][PCHC=2,1][IMME][STNR]
"The creature was [68C0D8][HSHD]Lavos[C8C8C8][HSHD]. Will you slay it?"
[CHOO][MOVE=18,0]Accept
[MOVE=18,0]Decline
[ZDNE] "Set for Zidane"
[DGGR] "Set for Dagger"
[VIVI] "Set for Vivi"
{STNR] "Set for Steiner"
[FRYA] 'Set for Freya"
[QUIN] "Set for Quina"
[EIKO] "Set for Eiko"
[AMRT] "Set for Amarant"
[STRT=15,4][STNR]
"Someone named [68C0D8][HSHD]Viera[C8C8C8][HSHD] was attacked in
[68C0D8][HSHD]Burmecia[C8C8C8][HSHD], yet their belongings forfeit.
I would have them returned."
[STRT=140,4][PCHC=2,1][IMME][STNR]
"The creature was [68C0D8][HSHD]Lavos[C8C8C8][HSHD]. Will you slay it?"
[CHOO][MOVE=18,0]Accept
[MOVE=18,0]Decline
[STRT=15,5][STNR]
"I am glad to know there is
strength and honor even among
you. I will lend my arm in the hunt
of [68C0D8][HSHD]Lavos[C8C8C8][HSHD]."
[STRT=15,4][STNR]
"I shall await you in [68C0D8][HSHD]Burmecia[C8C8C8][HSHD] with
[68C0D8][HSHD][FRYA][C8C8C8][HSHD]. I do not think the creature
will have left."
[STRT=15,3]
[68C0D8][HSHD]Lavos[C8C8C8][HSHD][SPED=2]...[SPED=-1]
[C8B040][HSHD]The hunt begins![C8C8C8][HSHD]
[STRT=15,3][STNR]
"We are victorious. No more
shall that beast roam freely."
[STRT=15,6][FRYA]
"Thank you. I could not have
recovered past Viera's belongings
without your help. I was fortunate
to find such worthy aid. You have
my gratitude."
[STRT=15,5][FRYA]
"The world is a wonderful place,
filled with ideas as diverse as its
people. Such individuality was not
to be found on that steppe."
[STRT=15,2][STNR]
"I understand[SPED=2]...[SPED=-1]"
Function Steiner_SpeakBTN
DisableMove( ) \\ Disables player movement.
DisableMenu( ) \\ Disable player accessing menus.
if ( VARL_GenBool_8039 == 0 ) {
TurnTowardObject( 19, 32 ) \\Turns the model to an object.
WindowSync( 1, 128, 277 ) \\ Function for adding dialogue.
set VARL_GenBool_8039 = 1
}
DisableMove( )
DisableMenu( )
WindowSync( 1, 128, 278 )
if ( GetDialogChoice == 0 ) {
set VARL_GenBool_8040 = 1 \\ set the variable with value "1" (to keep Steiner removed after accepting the hunt & initiating the follow up scene in Burmecia).
WindowSync( 1, 128, 279 )
WindowSync( 1, 128, 280 )
FadeFilter( 6, 16, 0, 74, 74, 74 ) \\ Set a fade effect.
RaiseWindows( ) \\ Used for showing text on screen without a diagloue bubble.
WindowAsync( 1, 16, 281 )
RunSoundCode3( 53248, 1350, 0, -128, 125 ) \\ Run a sound effect.
Wait( 70 ) \\ Wait some time (calculated in frames)
RunSoundCode3( 53248, 789, 0, -128, 125 )
Wait( 40 )
CloseWindow( 1 )
FadeFilter( 6, 16, VAR_GlobUInt8_17, 255, 255, 255 )
EnableMove( )
EnableMenu( )
Wait( 16 )
FadeFilter( 7, 16, VAR_GlobUInt8_17, 0, 0, 0 )
TerminateEntry( 255 ) \\ Terimante the current function entry.
} else {
WindowSync( 1, 128, 295 ) \\ Steiner's text: "I understand..."
TurnTowardObject( 10, 32 )
EnableMove( )
EnableMenu( )
Wait( 16 )
}
if ( GetDialogChoice == 0 ) {
FadeFilter( 7, 16, VAR_GlobUInt8_17, 0, 0, 0 )
} else {
TimedTurn( VAR_GlobUInt8_16, 16 )
WaitTurn( )
EnableMove( )
0x27( 255 )
EnableMenu( )
}
return
Function Freya_SpeakBTN
DisableMove( )
DisableMenu( )
TurnTowardObject( 19, 32 )
WindowSync( 1, 128, 283 )
AddGil( 7000 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
WindowSync( 1, 128, 284 )
AddItem( 38, 1 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
WindowSync( 1, 128, 285 )
AddItem( 167, 1 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
WindowSync( 1, 128, 286 )
AddItem( 225, 15 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
WindowSync( 1, 128, 287 )
AddItem( 226, 7 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
WindowSync( 1, 128, 288 )
AddItem( 227, 4 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
WindowSync( 1, 128, 289 )
AddItem( 228, 2 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
WindowSync( 1, 128, 290 )
AddItem( 229, 1 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
WindowSync( 1, 128, 291 )
AddItem( 204, 1 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
WindowSync( 1, 128, 292 )
AddItem( 222, 2 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
WindowSync( 1, 128, 293 )
AddItem( 300, 1 )
RunSoundCode3( 53248, 3096, 0, -128, 125 )
WindowSync( 1, 128, 296 )
set VARL_GenBool_8043 = 1
WindowSync( 1, 128, 294 )
FadeFilter( 2, 12, 0, 255, 255, 255 )
EnableMove( )
EnableMenu( )
Wait( 16 )
FadeFilter( 2, 36, 0, 0, 0, 0 )
TerminateEntry( 255 )
return
if ( ( VARL_GenBool_8040 == 1 ) && ( IsInParty(3) && IsInParty(4) ) ) {
InitObject( 17, 0 )
InitObject( 18, 0 )
RunSoundCode( 0, 105 )
}
if ( VARL_GenBool_8042 == 1 ) {
TerminateEntry( 17 )
TerminateEntry( 18 )
}
if ( VARL_GenBool_8040 == 1 ) {
FadeFilter( 2, 24, 0, 2, 181, 225 )
}
if ( VARL_GenBool_8041 == 1 ) {
FadeFilter( 2, 24, 0, 0, 0, 0 )
RunSoundCode( 0, 68 )
}
if ( VARL_GenBool_8042 == 1 ) {
TerminateEntry( 17 )
TerminateEntry( 18 )
}
if ( VARL_GenBool_8040 == 1 ) {
FadeFilter( 2, 24, 0, 2, 181, 225 )
}
if ( VARL_GenBool_8041 == 1 ) {
FadeFilter( 2, 24, 0, 0, 0, 0 )
RunSoundCode( 0, 68 )
}
[STRT=15,2][STNR]
"Good. You are come."
[STRT=15,3][FRYA]
"[68C0D8][HSHD]Lavos[C8C8C8][HSHD] is a great creature
with massive scales. It will not be far. Come!"
[STRT=15,4][FRYA]
"We are victorious. I would reward
you for your courage. Visit me back
at Alexandria. I shall wait for you there."
Function Freya_SpeakBTN
DisableMove( )
DisableMenu( )
TurnTowardObject( 16, 32 )
WindowSyncEx( 18, 1, 128, 338 )
WindowSync( 1, 128, 339 )
EnableMove( )
EnableMenu( )
RunScriptSync( 2, 17, 30 )
RunScriptSync( 2, 18, 31 )
return
if ( ( VARL_GenBool_8040 == 1 ) && ( IsInParty(3) && IsInParty(4) ) ) {
InitObject( 16, 0 )
InitObject( 18, 0 )
}
if ( VARL_GenBool_8042 == 1 ) {
TerminateEntry( 16 )
TerminateEntry( 18 )
}
if ( VARL_GenBool_8040 == 1 ) {
FadeFilter( 2, 24, 0, 2, 181, 225 )
}
if ( VARL_GenBool_8041 == 1 ) {
FadeFilter( 2, 24, 0, 0, 0, 0 )
}
Function Freya_SpeakBTN
DisableMove( )
DisableMenu( )
WindowSync( 1, 128, 339 )
Wait( 20 )
RunSoundCode3( 53248, 789, 0, -128, 125 )
Wait( 40 )
RunSoundCode( 0, 77 ) \\ Run a BGM code.
Battle( 1, 210 ) \\ Start a battle. (Battle ID: 210)
DisableMove( )
DisableMenu( )
set VARL_GenBool_8041 = 1
set VARL_GenBool_8042 = 1
RunSoundCode( 256, 77 )
WindowSync( 1, 128, 340 )
FadeFilter( 2, 12, 0, 255, 255, 255 )
Wait( 16 )
EnableMove( )
EnableMenu( )
RunSoundCode( 0, 68 )
FadeFilter( 2, 36, 0, 0, 0, 0 )
TerminateEntry( 18 )
TerminateEntry( 255 )
return
Function Main_Reinit
set VAR_GlobBool_159 = 0
RunScriptAsync( 0, 250, 11 )
if ( VAR_GlobBool_155 == 1 ) {
ATE( 1 )
}
if ( VAR_GlobBool_158 == 0 ) {
0x27( 127 )
} else {
0x27( 255 )
}
Wait( 2 )
ShowTile( 5, 0 )
ShowTile( 6, 0 )
ShowTile( 7, 0 )
ShowTile( 8, 0 )
ShowTile( 9, 0 )
ShowTile( 10, 0 )
Wait( 2 )
if ( VAR_GenUInt8_13 == 9 ) {
SetTextVariable( 2, 0 )
WindowAsync( 6, 0, 62 )
RaiseWindows( )
WaitWindow( 6 )
set VAR_GenUInt8_13 = 0
}
if ( VAR_GenUInt8_14 == 9 ) {
SetTextVariable( 2, 1 )
WindowAsync( 6, 0, 62 )
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( )
}
}
}
}
set VAR_GlobUInt8_30 = 127
SetWeather( 24, 56 )
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
Function Freya_SpeakBTN
DisableMove( )
DisableMenu( )
TurnTowardObject( 19, 32 )
WindowSync( 1, 128, 283 )
AddGil( 7000 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
WindowSync( 1, 128, 284 )
AddItem( 38, 1 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
WindowSync( 1, 128, 285 )
AddItem( 167, 1 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
WindowSync( 1, 128, 286 )
AddItem( 225, 15 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
WindowSync( 1, 128, 287 )
AddItem( 226, 7 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
WindowSync( 1, 128, 288 )
AddItem( 227, 4 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
WindowSync( 1, 128, 289 )
AddItem( 228, 2 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
WindowSync( 1, 128, 290 )
AddItem( 229, 1 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
WindowSync( 1, 128, 291 )
AddItem( 204, 1 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
WindowSync( 1, 128, 292 )
AddItem( 222, 2 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
WindowSync( 1, 128, 293 )
AddItem( 300, 1 )
RunSoundCode3( 53248, 3096, 0, -128, 125 )
WindowSync( 1, 128, 296 )
set VARL_GenBool_8043 = 1
WindowSync( 1, 128, 294 )
FadeFilter( 2, 12, 0, 255, 255, 255 )
EnableMove( )
EnableMenu( )
Wait( 16 )
FadeFilter( 2, 36, 0, 0, 0, 0 )
TerminateEntry( 255 )
return
ffix_img_extr.exe "C:\Users\PC\Desktop\folder\FF9.IMG" "C:\Users\PC\Desktop\folder/folder1"
case 66:
{
CALC_VAR calc_VAR37 = calc_VAR;
calc_VAR37.tg_flags |= 1;
calc_VAR.df_pow = (short)target.defence.p_def;
if (ff.frog_no - calc_VAR.df_pow / 2 > 0)
{
if (calc_VAR.at_num < 1)
{
calc_VAR.at_num = 1;
}
int num22;
if (ff.frog_no != 0)
{
if ((num22 = (short)(caster.level * (ff.frog_no - calc_VAR.df_pow / 2))) > 9999)
{
num22 = 9999;
}
else
{
num22 = (short)(caster.level * (ff.frog_no - calc_VAR.df_pow / 2));
}
}
else
{
num22 = 1;
}
calc_VAR.tg_hp = (short)num22;
}
break;
}
case 67:
{
CALC_VAR calc_VAR38 = calc_VAR;
calc_VAR38.tg_flags |= 1;
calc_VAR.df_pow = (short)target.defence.p_def;
if (ff.steal_no - calc_VAR.df_pow > 0)
{
if (calc_VAR.at_num < 1)
{
calc_VAR.at_num = 1;
}
int num23;
if ((num23 = (ff.steal_no - calc_VAR.df_pow) * (short)caster.elem.dex / 2) > 9999)
{
num23 = 9999;
}
else
{
num23 = (short)((ff.steal_no - calc_VAR.df_pow) * (short)caster.elem.dex / 2);
}
calc_VAR.tg_hp = (short)num23;
}
break;
}
case 68:
{
CALC_VAR calc_VAR39 = calc_VAR;
calc_VAR39.tg_flags |= 1;
calc_VAR.df_pow = (short)target.defence.p_def;
if (ff.dragon_no - calc_VAR.df_pow > 0)
{
if (calc_VAR.at_num < 1)
{
calc_VAR.at_num = 1;
}
int num24;
if ((num24 = (ff.dragon_no - calc_VAR.df_pow) * ff.dragon_no) > 9999)
{
num24 = 9999;
}
else
{
num24 = (short)((ff.dragon_no - calc_VAR.df_pow) * ff.dragon_no);
}
calc_VAR.tg_hp = (short)num24;
}
break;
case 12:
if (FF9StateSystem.Battle.FF9Battle.add_status[(int)cALC_VAR.cmd.aa.AddNo]==2147483649u && btl_util.CheckEnemyCategory(target, CATEGORY_STONE))
{
if (btl_calc.CalcSub_12A(cALC_VAR)) // CheckPetrifyDeathMiss
{
btl_calc.SetEnforceHP0(target);
UIManager.Battle.SetBattleFollowMessage(25, new object[0]); // "Became too soft to live."
}
} else {
btl_calc.CalcSub_302(cALC_VAR); // DoRemoveSpellStatus
}
With this, spells that cure exactly the statuses Petrify and Gradual Petrify will also kill stone enemies. Esuna will not.if ((status & 4026466304u) != 0u)
{
short num6;
if ((status & 2601713664u) != 0u)
{
num6 = (short)(60 - btl.elem.wpr << 3);
}
else if ((status & 619446272u) != 0u)
{
num6 = (short)(btl.elem.wpr << 3);
}
else
{
num6 = (short)(60 - btl.elem.wpr << 2);
}
btl.stat.cnt.conti[(int)((UIntPtr)(num - 16u))] = (short)(status_data[(int)((UIntPtr)num)].conti_cnt * (ushort)num6);
}
That's the formulae to change for the duration. The first formula is for negative statuses, the second is for good ones and the last is the default (I think it's used for Berserk only). You can of course split the internal "if" blocks to have a formula specific to each status.set #( SV_Target = ... )
You can turn them to this to gain a little space:set SV_Target = ...
Other space optimisations depend on the code, that's why I ask what is the base enemy.
@Kefka: I don't know if you did it already, but you can add a "Stona-kill" like this:Code: [Select]case 12:
With this, spells that cure exactly the statuses Petrify and Gradual Petrify will also kill stone enemies. Esuna will not.
if (FF9StateSystem.Battle.FF9Battle.add_status[(int)cALC_VAR.cmd.aa.AddNo]==2147483649u && btl_util.CheckEnemyCategory(target, CATEGORY_STONE))
{
if (btl_calc.CalcSub_12A(cALC_VAR)) // CheckPetrifyDeathMiss
{
btl_calc.SetEnforceHP0(target);
UIManager.Battle.SetBattleFollowMessage(25, new object[0]); // "Became too soft to live."
}
} else {
btl_calc.CalcSub_302(cALC_VAR); // DoRemoveSpellStatus
}
For the duration of statuses, it's in the method "btl_stat::AlterStatus". Near the end of the method, you have this block:Code: [Select]if ((status & 4026466304u) != 0u)
That's the formulae to change for the duration. The first formula is for negative statuses, the second is for good ones and the last is the default (I think it's used for Berserk only). You can of course split the internal "if" blocks to have a formula specific to each status.
{
short num6;
if ((status & 2601713664u) != 0u)
{
num6 = (short)(60 - btl.elem.wpr << 3);
}
else if ((status & 619446272u) != 0u)
{
num6 = (short)(btl.elem.wpr << 3);
}
else
{
num6 = (short)(60 - btl.elem.wpr << 2);
}
btl.stat.cnt.conti[(int)((UIntPtr)(num - 16u))] = (short)(status_data[(int)((UIntPtr)num)].conti_cnt * (ushort)num6);
}
Congrats for modifying the damage formula of these other spells :)
btl.stat.cnt.conti[(int)((UIntPtr)(num - 16u))] = (short)(status_data[(int)((UIntPtr)num)].conti_cnt * (ushort)num6);
However, for the durations of the statuses, they are in 2 spots and it is not possible to edit either of them :/
- In "btl_stat::AlterStatus", a page before the end, there are 3 similar formulas "Duration = (60 - spirit) << 3" (for bad statuses and jump), "Duration = spirit << 3" for good ones and "Duration = spirit << 2" by default (it doesn't seem to be used). You can't edit this method because it's too big and CIL editing tends to bug with big methods.
- In FF9BattleDB (.ctor), there is the setup of "STAT_DATA", a class for status informations, including a multiplier used after the formulas I gave above. You can't modify the method because it's too big and anyway it is one of the few methods that are specially handled by HW and modified by other means.
I think that the loading of fields is bugged for the PSX version. If I recall correctly, it loads without crashing the fields of the japanese discs but completly scramble the field names.
I have no other solution than to try with older versions of HW and find one before that bug appeared, sorry.
maybe try to run the converter as administrator or with Windows XP compatibility? There should be these options somewhere if you right-click on it.
// A variable that is not used ; I think that you can take 60000 and the followings for booleans (it corresponds to 7500 for the other types of variable)
if ( !VARL_GenBool_XXX ) {
set VARL_GenBool_XXX = 1
// Do whatever you want as a one-time event
} else {
// Do whatever you want to be the default (in this case, going to field 256 normally)
}
You can see that there is already a code like this in the function "Region1_Range" because there's already a one-time cinematic playing when you go there for the first time. You can simply use it and change the destination field of the first case to 250 instead of 256, so you get there after the cinematic showing the Plant Brain. if ( ( General_ScenarioCounter == 2010 ) && ( !VARL_GenBool_2432 ) ) {
set VAR_GlobUInt8_30 = 1
InitObject( 10, 0 )
InitObject( 7, 0 )
InitCode( 6, 0 )
InitRegion( 8, 0 )
InitRegion( 9, 0 )
set VARL_GenBool_2432 = 1
} else {
set VAR_GlobUInt8_30 = 0
InitObject( 10, 0 )
InitRegion( 8, 0 )
InitRegion( 9, 0 )
}
Put a condition for initializing Zidane (and, while we are at it, the exiting regions): } else {
set VAR_GlobUInt8_30 = 0
if ( General_FieldEntrance != 10 ) {
InitObject( 10, 0 )
InitRegion( 8, 0 )
InitRegion( 9, 0 )
} else {
// Init the object corresponding to Blank, like "InitObject( 17, 0 )"
}
}
So you need to create a new entry that is linked to Blank's 3D model. You are very lucky there because I think that Blank is one of the few models that can be accessed in any field in the PSX version (you won't be able to use a lot of animations though). The Steam version is incredibly better for that, but it's still possible... SetModel( 5467, 87 )
CreateObject( POSITION_X, POSITION_Y )
TurnInstant( ANGLE )
SetStandAnimation( 462 )
SetWalkAnimation( 5225 )
SetRunAnimation( 5222 )
SetLeftAnimation( 5223 )
SetRightAnimation( 5224 )
SetObjectLogicalSize( 20, 20, 30 )
SetAnimationStandSpeed( 14, 16, 18, 20 )
SetHeadAngle( 96, 61 )
return
Then add a "Loop" function for him (add function of type "1") and code a cutscene there...set General_FieldEntrance = 27
Field( 256 )
Check this tutorial (http://forums.qhimm.com/index.php?topic=14315.msg260956#msg260956) for a detailed example of how you can do cutscenes. 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, 655, 0 )
}
if ( VAR_GlobBool_163 == 0 ) {
}
set VARL_GenBool_8000 = 0
set General_FieldEntrance = 27
Field( 250 )
}
return
} else {
set VAR_GlobUInt8_30 = 0
InitObject( 10, 0 )
InitRegion( 8, 0 )
InitRegion( 9, 0 )
}
if ( !VARL_GenBool_8000 ) {
InitObject( 17, 0 )
InitRegion( 8, 0 )
InitRegion( 9, 0 )
} else {
set VAR_GlobUInt8_30 = 0
if ( General_FieldEntrance != 10 ) {
InitObject( 10, 0 )
InitRegion( 8, 0 )
InitRegion( 9, 0 )
} else {
InitObject( 17, 0 )
}
}
// Instead of what you have
// } else {
// set VAR_GlobUInt8_30 = 0
// InitObject( 10, 0 )
// InitRegion( 8, 0 )
// InitRegion( 9, 0 )
// }
// if ( !VARL_GenBool_8000 ) {
// InitObject( 17, 0 )
// InitRegion( 8, 0 )
// InitRegion( 9, 0 )
// }
You may do things differently than I suggested, but with the little piece of changes that I suggested, you should already get to the entrance of the Evil Forest and have Blank showing up after the Plant Brain cinematic. if ( General_FieldEntrance != 10 ) {
you should already get to the entrance of the Evil Forest and have Blank showing up after the Plant Brain cinematic
RunScript( 2, 2, 15 )
Wait( 3 )
WindowSyncEx( 2, 0, 128, 86 )
RunScript( 2, 4, 14 ) <-- This script does not react
WindowSyncEx( 4, 0, 128, 276 )
set Setting_PartyReserve = 0
SetPartyReserve( Setting_PartyReserve )
SetCharacterData( 0, 1, 255, 255, 255 ) // Using 255 prevents unwanted changes
SetCharacterData( 1, 1, 255, 255, 255 )
SetCharacterData( 2, 1, 255, 255, 255 )
// etc... for each character
set Setting_PartyReserve = 255 // Use 511 instead if Beatrix should be available
SetPartyReserve( Setting_PartyReserve )
ps: And another quick question.. meanwhile I was waiting for the reply I just started to work on the other Fields, on the Blue Narciss I put the scripts from my Steam Project.. and everything is cool to HWS too, every entry is set right, and every script is at his place..Code: [Select]RunScript( 2, 2, 15 )
Wait( 3 )
WindowSyncEx( 2, 0, 128, 86 )
RunScript( 2, 4, 14 ) <-- This script does not react
WindowSyncEx( 4, 0, 128, 276 )
The function is a simple animation of Zidane, so is strange, because as I said everything, entry and functions are in their own place and on Steam works fine!
The script not reacting can be because Zidane is already moving, which cancels his animation to play? If he's walking and you use a "RunAnimation", I think that it doesn't work. You can also try to replace this line by a "RunAnimationEx( 4, ... )".
also what does the symbol mean? "|=" in set Setting_PartyInitialized |= 4
@resinate: No idea. Those characters don't have any special traitment :o
"VAR_GenUInt16_21" and "Setting_PartyReserve" are synonymous indeed ("Setting_PartyReserve" appeared in more recent versions of HW but you can still use "VAR_GenUInt16_21").
@ToraCarol: I answered that about it.
if (update_lv) {
int num = ff9play.FF9Play_GetAvgLevel(slot_no);
int lv;
if (pLAYER.info.serial_no == 10 || pLAYER.info.serial_no == 11)
lv = num;
else
lv = Mathf.Max((int)pLAYER.level, num);
ff9play.FF9Play_Build(slot_no, lv, null, false);
}
Except for the character serial number 10 and 11, which is indeed Eiko (she has 2 different serial numbers because she can wear two different kinds of weapons, flutes and rackets), the script is not allowed to reduce the level in any way.@ToraCarol: I don't know what could prevent the field to load (or the fading to happening). Have you properly setup Blank's init function?
Function Blank_Init
if ( ( General_FieldEntrance == 4 ) && ( VAR_GlobUInt8_30 == 1 ) ) {
set VAR_GlobInt16_0 = 64956
set VAR_GlobInt16_4 = 273
set VAR_GlobInt16_6 = 224
set VAR_GlobInt16_2 = 64967
}
SetModel( 5467, 87 )
CreateObject( VAR_GlobInt16_0, VAR_GlobInt16_4 )
TurnInstant( VAR_GlobInt16_6 )
SetStandAnimation( 462 )
SetWalkAnimation( 5225 )
SetRunAnimation( 5222 )
SetLeftAnimation( 5223 )
SetRightAnimation( 5224 )
SetObjectLogicalSize( 20, 20, 30 )
SetAnimationStandSpeed( 14, 16, 18, 20 )
SetHeadAngle( 96, 61 )
RunSoundCode( 4616, 919 )
RunSoundCode( 4616, 914 )
RunModelCode( 16, 25, 4, 919 )
RunModelCode( 17, 25, 4, 914 )
RunModelCode( 18, 25, 4, 1 )
RunSoundCode( 4616, 919 )
RunSoundCode( 4616, 914 )
RunModelCode( 16, 25, 13, 919 )
RunModelCode( 17, 25, 13, 914 )
RunModelCode( 18, 25, 13, 1 )
RunSoundCode( 4616, 919 )
RunSoundCode( 4616, 914 )
RunModelCode( 16, 38, 0, 919 )
RunModelCode( 17, 38, 0, 914 )
RunModelCode( 18, 38, 0, 1 )
RunSoundCode( 4616, 919 )
RunSoundCode( 4616, 914 )
RunModelCode( 16, 38, 8, 919 )
RunModelCode( 17, 38, 8, 914 )
RunModelCode( 18, 38, 8, 1 )
DefinePlayerCharacter( )
if ( VAR_GlobUInt8_30 != 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( )
}
}
}
}
return
Function Blank_Loop
DisableShadow( )
RunModelCode( 4, 1, -100, 0 )
Wait( 1 )
loop
SetControlDirection( 0, 0 )
InitCode( 1, 0 )
InitCode( 2, 0 )
InitCode( 3, 0 )
InitCode( 4, 0 )
if ( VARL_GenBool_2432 == 1 ) {
ShowTile( 5, 0 )
ShowTile( 6, 0 )
}
SetRandomBattleFrequency( 128 )
SetRandomBattles( 1, 67, 67, 67, 67 )
if ( ( General_ScenarioCounter == 2010 ) && ( !VARL_GenBool_2432 ) ) {
set VAR_GlobUInt8_30 = 1
InitObject( 10, 0 )
InitObject( 7, 0 )
InitCode( 6, 0 )
InitRegion( 8, 0 )
InitRegion( 9, 0 )
set VARL_GenBool_2432 = 1
} else {
set VAR_GlobUInt8_30 = 0
if ( General_FieldEntrance != 10 ) {
InitObject( 10, 0 )
InitRegion( 8, 0 )
InitRegion( 9, 0 )
} else {
InitObject( 17, 0 )
}
0xA9( 250 )
FadeFilter( 2, 1, VAR_GlobUInt8_17, 255, 255, 255 )
if ( ( ( ( SyncCinematic & 127 ) != 17 ) && ( ( SyncCinematic & 128 ) == 0 ) ) && ( VAR_GlobBool_146 == 1 ) ) {
while ( ( SyncCinematic & 127 ) != 1 ) {
Wait( 1 )
}
Wait( 1 )
}
set VAR_GlobBool_162 = 1
set VAR_GlobBool_163 = 1
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, 655, 0 )
}
if ( VAR_GlobBool_163 == 0 ) {
}
set General_FieldEntrance = 27
Field( 250 )
The script not reacting can be because Zidane is already moving, which cancels his animation to play? If he's walking and you use a "RunAnimation", I think that it doesn't work. You can also try to replace this line by a "RunAnimationEx( 4, ... )".
RunScript( 2, 2, 15 )
WindowSyncEx( 2, 0, 128, 86 )
Wait( 3 )
RunAnimationEx( 4, 3397 )
WindowSyncEx( 4, 0, 128, 276 )
WaitAnimationEx( 0 )
Wait( 3 )
@ToraCarol: In Blank's Init, remove the block "if ( ( General_FieldEntrance == 4 ) && ( VAR_GlobUInt8_30 == 1 ) ) {" and instead setup the position you want to give to Blank by selecting the line "CreateObject" and the helper "Field" on the left of the window (showing the field's walkmesh).
In Blank's loop, what is the "RunModelCode( 4, 1, -100, 0 )"? You should probably remove that line and the "DisableShadow" (unless you want to hide Blank's shadow for some reason).
In the swamp's function, you still have the line "set General_FieldEntrance = 27" while it should be "set General_FieldEntrance = 10".
Ah, and the animation is not working on PSX because you can't use all the animations there. Each field has the datas of some animations linked to it (the animations that the devs used for that field) and you can't access to the others.
On Steam, you can access any model and any animation at any time.
Thanks for the reply, as always ;)
Just want to ask...whats the best way to install the Dwight's "SFX & Missing Enemy Death Sounds Fix" to be compatible with my Mod? (When i copypaste the resoruce.assets, obviously, the game
looks kinda corrupted)
It's necessary to start from a clean project?
I don't remember if that mod also update the sounds with better ones. If that's the case, it is files like p0data61, 62 or 63 that are not modified by HW so it's perfectly compatible.
Tirlititi just want/need to ask you an interesting question.. What's the best way to add/replace sounds??? I have not seen a tutorial about it ;D
Great, thanks!
I've asked you about adding sound because i'm interested on adding voice to characters in battle for make something like "Opera Omnia" what do you think? It' too hard?
And tell me where I have to go exactly in DnSpy for making the source code?
ps: talking about sounds, is there a way to fix the reflex SFX (maybe adding another sound, instead of the sound of the magic is using..)
Be weary! Some sounds ignore the pitch and frequency set in Sdlib.dll! What you initially replace as say 44100hz can be played at frequency 22050hz in game! I still haven't understood this doing.
Sounds good to me!
On terms of difficult, well, way back when when I attempted to add assets for Voice line in FF9 TZA, I too had to add those assets with Unity Asset Viewer, and later work the source to make it use it. I didn't get successful with that attempt. IIRC, even when I added the assets in the p0data61-63.bin archives, updated soundeffectmetadata.txt and added the necessary functions in Assembly CSharp.dll, the audio still refused to play. I then settled with using some UNUSED sounds of the game for the voice lines. Just so one could still archive their ultimate goal whilst keeping everything else intact.
Great, thanks for the reply Incinerator! You know I've got this idea thanks to your FF9 TZA! I've seen you used the voices from FFXII so I said..WOW! Maybe I can give a shot :evil:
Can I ask you now two questions?
First of all..what are exactly the unused sounds? How can I recognize them?
And second...how did you put the sound to play exactly in the instant when, for example, a character die, or attack? I never tried something like this before :roll:
Ah, sorry, my bad !
I've misread the engine code ; I thought that "SetEnforceHP0" was executed everytime a fighter dies.
So, "SetEnforceHP0" is executed in most situations, except for the most frequent: when a character dies because of damage and that its death animation is not delayed or canceled for some reason (when you attack yourself, the character doesn't do its "Death" animation right there because it's already doing its "Attack" animations).
I would say to keep the code in "SetEnforceHP0" but also add it in another place: "btl_para::SetDamage".
At the end of the method, you have something like this:Code: [Select]btl.fig = (short)damage;
Add the lines in the first of alternatives:
if (dmg_mot != 0)
{
btl_mot.SetDamageMotion(btl);
}
else if (btl.cur.hp == 0)
{
btl_calc.SetEnforceHP0(btl);
}Code: [Select]btl.fig = (short)damage;
if (dmg_mot != 0)
{
btl_mot.SetDamageMotion(btl);
if (btl_util.getPlayerPtr(btl).info.serial_no == 0 || btl_util.getPlayerPtr(btl).info.serial_no == 1)
btl_util.SetBattleSfx(btl, ZIDANE_SOUND_ID, 127);
else if (btl_util.getPlayerPtr(btl).info.serial_no == 2)
btl_util.SetBattleSfx(btl, VIVI_SOUND_ID, 127);
// etc...
}
else if (btl.cur.hp == 0)
{
btl_calc.SetEnforceHP0(btl);
}
PS. : The way it compiled it in dnSpy is normal and perfectly fine. Even though it's not exactly the same C# code as you wrote, it is equivalent and leads to exactly the same CIL code.
Do this and now it should be finally ok:Code: [Select]btl.fig = (short)damage;
if (dmg_mot != 0)
{
btl_mot.SetDamageMotion(btl);
if ((btl.cur.hp == 0) && (btl.bi.player != 0) {
if (btl_util.getPlayerPtr(btl).info.serial_no == 0 || btl_util.getPlayerPtr(btl).info.serial_no == 1)
btl_util.SetBattleSfx(btl, ZIDANE_SOUND_ID, 127);
else if (btl_util.getPlayerPtr(btl).info.serial_no == 2)
btl_util.SetBattleSfx(btl, VIVI_SOUND_ID, 127);
// etc...
}
}
else if (btl.cur.hp == 0)
{
btl_calc.SetEnforceHP0(btl);
}
Really, I'm sorry, I got confused because there is not a single piece of code that is executed for sure when a character dies, and you have to add these lines in two different places (SetEnforceHP0 and SetDamage) that have different conditions to trigger.
I didn't do any more tests for the model importer. I've just decided to let the text auto-translation feature for the release after the next one because it'll take some time. I have a couple of things to fix for the text editing feature, then I go back to model exporter/importer to see what's wrong and then I release the next version of HW.
I really hope that the sound code works fine this time ^^'
Thanks alot Incinerator!I'll give a try right now!!! :-D
It's buggy,huh? So no way for adding sound on, for example, spells and victories? (the second one is interesting...because there is to consider a way to not play the sound of every character in the same time but only for the last one who "defeated")
UPDATE:
Uhm...where I have to work exactly? On CIL code? ???
And the sound ID is in the document "Soudeffectmetadata" right?
new rdata.FF9COMMAND(174, 458, 8301, 1, 16, 8UL),
The first two numbers can be ignored (it's a leftover of the text hexadecimal position from the PSX's version).2) Separating the slots of Eiko and Marcus (and Cinna/Quina and Blank/Amarant).
I'll edit this message and write the way to do it later...
Most of the things involved should be in the class "ff9play". The chararcters have several kinds of IDs and the one adding the problem is the "slot_id" or "slot_no". One has to add more "PLAYER_INFO" in the method "ff9play::FF9Play_New" and change all the conversion methods "ff9play::FF9Play_GetCharID2"... There are surely a bunch of other things to do and they need to be done smartly if one doesn't want to change all the field scripts related to Cinna/Blank/Marcus as temporary player characters...
Note: The field scripts are not part of the "Assembly-CSharp.dll" datas but are inside the archive "p0data7.bin" so you can still add HW modifications on top of dnSpy modifications.
If you try to open the modded "Assembly-CSharp.dll" with HW, it will surely crash though, as "rdata" is a key class for HW and it is assumed to have a very specific pattern (plus the total number of spells is hard-coded in HW's source).
Sorry for the late answer.
UPDATE:
Also I was wondering... how can I have a second character that follows the Main? I mean..like Beatrix and Steiner at Alexandria while they're fighting the "Mist Monsters"?
For example, at Burmecia I'd like to have Freya that follows Zidane in this case..is it possible?
Hello, people!
Is it possible to use this editor on Android, or maybe Switch ?
It could be a good thing using Unleashed or Alternate Fantasy (i don´t know which is better) on Android.
Thanks.
Hello, people!
I added several items to stores in the game, but while they appear listed in their respective stores in Hades, the items only appear up until the number of original items on that store. For instance: Lindblum weapon store sells 17 items during disc 1. I added several of them and they only appear until the number 17 on the list. All items after that do not show at all. I imagine this might be related to the number of items visible or listed, but I found no option on Hades to extend the list.
Anyone has any ideas?
Another thing: does anybody know how to make it so that the Beatrix fights have no time/turn limit, so that you can only end them by depleting her HP and triggering her final move?
Thanks in advance
Another thing: does anybody know how to make it so that the Beatrix fights have no time/turn limit, so that you can only end them by depleting her HP and triggering her final move?
if ( VAR_LocUInt8_32 < 10 ) {
set VAR_LocUInt8_32++
} else {
set VAR_LocUInt8_31 = 1
}
Guys, I want to add a new battle in the "You're not alone Event" but I don't know how to start a battle without switch to field-battle music..how can I solve? Thanks for the help
set Setting_PartyReserve = 255
SetPartyReserve( Setting_PartyReserve )
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_GlobBool_147 = AddParty(1)
set VAR_GlobBool_147 = AddParty(0)
set VAR_GlobBool_147 = AddParty(6)
set VAR_GlobBool_147 = AddParty(65535)
RunAnimationEx( 7, 910 )
Wait( 8 )
WindowSyncEx( 7, 0, 128, 249 )
Wait( 60 )
MoveCamera( 160, 172, 60, 0 )
Wait( 70 )
Battle( 0, 897 )
Wait( 30 )
RunScript( 2, 12, 28 )
Wait( 20 )
WindowSyncEx( 12, 0, 128, 250 )
RunScript( 2, 7, 28 )
RunScript( 2, 6, 29 )
MoveCamera( 160, 272, 100, 0 )
What a coincidence, I did exactly the same for my mod last year! I've added a Malboro battle in the first screen that you're gonna fight with Vivi and Eiko in the party (always found it kinda sad/wierd that those two were left out of this string of battles in the vanilla game).
But I don't know why, for some reason it keeps start the music battle... it's weird! :| I've also replaced the p0data2 and the AssemblyCSharp..so I really don't know! I've checked once, twice..I can check again..maybe I'm missing something but...
No, it's determined in a couple of .txt files of the "resources.assets" archive. The files are called "BtlEncountBGMMetaData.txt" (for battles on the field) and "WldBtlEncountBGMMetaData.txt" (for battles on the map).
The files present like this :Code: [Select]{
Battles have the music ID "0" (for normal encounters), "35" (for bosses) and "111" (for Hunter's Chance). Some battles are not registered in these files, when they don't stop the music played in the field (the "Don't Stop Music" battle flag is also checked for them in the "Enemy" panel).
"ID of Field": {
"ID of Battle in the Field": "ID of Battle Music",
...
},
...
}
Ah, I knew I forgot something! A few pages back I was asking tirlititi about changing the music used in certain battle formations, and this was his response:
Now what you have to do is open Hades Workshop, but instead of opening the FF9_Launcher the normal way, go to Tools -> Unity Assets Viewer, and open the Launcher there. Then go to Archive -> Shared Assets -> resources. Now scroll until you find the "BtlEncountBGMMetaData.txt" and export it (a text file will be generated in the HadesWorkshopAssets folder). Open this text file, the format is the one described by tirlititi. The list of field IDs is the same as in Hades Workshop when the fields are NOT sorted. In our case, Pandemonium laboratory is field ID 2705. There you will see that battle formation 896 is listed with a "0", which means normal battle theme. You'll have to delete the "896": "0" entry from this field, save, and then import this text file back into the Unity Assets Viewer by right-clicking the "BtlEncountBGMMetaData.txt" and chosing 'Import Selection'.
That should do the trick. Keep in mind that this will keep the field music playing at any time battle formation 896 is triggered, so maybe remove it as a random encounter from that location.
I have also another question if anyone can help.. there's somebody who knows in battle, how to make a model closing their eyes when KO and not look wierd/"creepy" like this?? Unfortunately this happens also when they're sleeping, faint etc etc on the normal field..but..why?Spoiler: show
UV texture errors from upscaled NPCs textures and the like of p0data4.bin!. High res textures damage texture animation + UV on some objects for unknown reasons; I have the same issue with my model's 4096x4096 textures. Have not yet found a fix for this yet!.
Function Freya_Loop
switchex 6 ( VAR_GlobUInt8_24 ) {
case 0:
EnableHeadFocus( 0 )
SetStandAnimation( 8385 )
Wait( 30 )
set VAR_GlobUInt8_26--
while ( VAR_GlobUInt8_26 > 0 ) {
set VAR_GlobBool_230 = 1
Wait( 1 )
}
while ( VAR_GlobBool_230 == 1 ) {
Wait( 1 )
}
set VAR_GlobBool_231 = 1
break
case 1:
RunAnimation( 8387 )
WaitAnimation( )
SetStandAnimation( 6484 )
WindowSync( 1, 128, 302 )
set VAR_GlobBool_231 = 1
break
case 5:
WindowSync( 1, 128, 307 )
set VAR_GlobBool_231 = 1
break
case 12:
RunAnimation( 6482 )
WaitAnimation( )
SetStandAnimation( 2556 )
set VAR_GlobUInt8_26--
while ( VAR_GlobUInt8_26 > 0 ) {
set VAR_GlobBool_230 = 1
Wait( 1 )
}
while ( VAR_GlobBool_230 == 1 ) {
Wait( 1 )
}
set VAR_GlobBool_231 = 1
break
case 13:
RunAnimation( 6489 )
SetStandAnimation( 6635 )
WindowAsync( 1, 128, 319 )
WindowSync( 1, 128, 320 )
WaitAnimation( )
RunAnimation( 6629 )
SetStandAnimation( 2556 )
set VAR_GlobBool_231 = 1
break
case 15:
WaitAnimation( )
SetObjectFlags( 7 )
SetPathing( 0 )
SetWalkSpeed( 45 )
TimedTurn( Angle(62969, 61115), 16 )
WaitTurn( )
InitWalk( )
Walk( -2567, -4421 )
SetDialogProgression( 0 )
set Field_MusicVolume = 0
RunSoundCode2( 34305, 0, 128, Field_MusicVolume )
set VAR_GlobBool_167 = 0
if ( 1 ) {
set VAR_GlobBool_167 = 1
}
RunSoundCode2( 38401, 65535, 128, 0 )
if ( VAR_GlobUInt8_17 == 255 ) {
set Op66(( GetData_12 - 160 ), ( GetData_13 - 112 ))
}
------I MODIFIED FROM HERE------
0xA9( 250 )
FadeFilter( 6, 64, 0, 255, 255, 255 )
Wait( 65 )
MoveInstantXZY( -1707, 0, -3264 )
TurnInstant( 56 )
Wait( 75 )
WindowAsync( 0, 16, 336 )
RaiseWindows( )
WaitWindow( 0 )
Wait( 25 )
0xA9( 250 )
WindowAsync( 0, 16, 337 )
RaiseWindows( )
WaitWindow( 0 )
Wait( 25 )
0xA9( 250 )
WindowAsync( 0, 16, 338 )
RaiseWindows( )
WaitWindow( 0 )
Wait( 35 )
set VAR_GlobBool_158 = 0
if ( VAR_GlobBool_159 == 1 ) {
DisableMove( )
if ( VAR_GlobBool_144 == 0 ) {
DisableMenu( )
} else {
Wait( 1 )
}
}
----------------TO HERE
0x27( 127 )
RunSoundCode1( 21761, 65535, 0 )
RunSoundCode( 8448, 65535 )
set VAR_GenInt24_64 = 246588L
set VAR_GenInt16_67 = 64746
set VAR_GenInt24_69 = 2147483647L
set World_PlayerAngle = 248
set General_FieldEntrance = 51
set VARL_GenBool_753 = 1
if ( General_ScenarioCounter >= 4600 ) {
set VARL_GenBool_754 = 1
}
if ( VAR_GenUInt8_13 < 9 ) {
set VAR_GenUInt8_13 = 3
}
RunSoundCode1( 20864, 1321, 0 )
if ( VAR_GenUInt8_14 < 9 ) {
set VAR_GenUInt8_14 = 3
}
RunSoundCode1( 20864, 1322, 0 )
set General_ScenarioCounter
set World_MusicVolume = 125
switchex 2 ( General_FieldEntrance ) {
case 65 ; 83:
set World_WhiteTransition = 1
break
default:
set World_WhiteTransition = 0
break
}
if ( General_ScenarioCounter < 5990 ) {
switch 67 ( General_FieldEntrance ) from 17 {
case +0 ; +6 ; +7 ; +9 ; +10 ; +11 ; +16 ; +17 ; +21 ; +24 ; +27 ; +29 ; +34 ; +46 ; +47 ; +49 ; +66:
WorldMap( 9000 )
break
case +18 ; +19 ; +25 ; +26 ; +28 ; +30 ; +31 ; +33:
WorldMap( 9011 )
break
case +1 ; +12 ; +13 ; +20:
WorldMap( 9010 )
break
case +50 ; +51 ; +52 ; +53 ; +54 ; +55 ; +56 ; +57 ; +58 ; +59 ; +60 ; +61:
WorldMap( 9002 )
break
case +35:
WorldMap( 9001 )
break
case +45:
set General_FieldEntrance = 0
WorldMap( 9009 )
break
}
} else {
if ( General_ScenarioCounter < 10400 ) {
if ( ( General_ScenarioCounter >= 9615 ) && ( General_ScenarioCounter <= 9790 ) ) {
switchex 4 ( General_FieldEntrance ) {
case 7 ; 10 ; 2 ; 83:
WorldMap( 9005 )
break
}
} else {
switch 84 ( General_FieldEntrance ) from 2 {
case +0 ; +2 ; +3 ; +4 ; +5 ; +7 ; +8 ; +11 ; +12 ; +13 ; +14 ; +15 ; +16 ; +17 ; +18 ; +19 ; +20 ; +21 ; +22 ; +23 ; +24 ; +25 ; +26 ; +27 ; +28 ; +29 ; +30 ; +31 ; +32 ; +33 ; +34 ; +35 ; +36 ; +37 ; +39 ; +40 ; +41 ; +42 ; +43 ; +44 ; +45 ; +46 ; +47 ; +48 ; +49 ; +54 ; +57 ; +61 ; +62 ; +77 ; +81:
WorldMap( 9003 )
break
case +51:
WorldMap( 9004 )
break
case +52:
WorldMap( 9005 )
break
case +53:
WorldMap( 9006 )
break
case +83:
WorldMap( 9012 )
break
case +60:
set General_FieldEntrance = 0
WorldMap( 9009 )
break
}
}
} else {
if ( General_ScenarioCounter < 11090 ) {
switch 85 ( General_FieldEntrance ) from 1 {
case +0 ; +1 ; +2 ; +4 ; +5 ; +6 ; +7 ; +9 ; +10 ; +11 ; +12 ; +13 ; +14 ; +15 ; +16 ; +17 ; +19 ; +20 ; +21 ; +22 ; +23 ; +24 ; +25 ; +26 ; +27 ; +28 ; +29 ; +30 ; +31 ; +32 ; +33 ; +34 ; +35 ; +36 ; +37 ; +38 ; +39 ; +40 ; +41 ; +42 ; +43 ; +44 ; +45 ; +46 ; +47 ; +49 ; +50 ; +56 ; +59 ; +62 ; +63 ; +64 ; +79 ; +81 ; +82:
WorldMap( 9007 )
break
case +84:
WorldMap( 9012 )
break
case +61:
set General_FieldEntrance = 0
WorldMap( 9009 )
break
}
} else {
switch 85 ( General_FieldEntrance ) from 1 {
case +0 ; +1 ; +4 ; +5 ; +6 ; +7 ; +9 ; +12 ; +13 ; +14 ; +15 ; +16 ; +17 ; +19 ; +20 ; +21 ; +22 ; +23 ; +24 ; +25 ; +26 ; +27 ; +28 ; +29 ; +30 ; +31 ; +32 ; +33 ; +34 ; +35 ; +36 ; +37 ; +38 ; +40 ; +41 ; +42 ; +43 ; +44 ; +45 ; +46 ; +47 ; +49 ; +50 ; +57 ; +60 ; +62 ; +63 ; +64 ; +80 ; +82:
WorldMap( 9008 )
break
case +84:
WorldMap( 9012 )
break
case +61:
set General_FieldEntrance = 0
WorldMap( 9009 )
break
}
}
}
}
set VAR_GlobBool_231 = 1
break
}
Wait( 1 )
loop
Guys sorry..I have another problem, and I hope someone of you can help me. Now I've added extra dialogs on Burmecia field, before Cleyra..but for some reason, when it goes on World Map it happens something like..that?Spoiler: show
So what happened? What's the problem?
while ( 1 ) {
if ( Distance(GetEntryPosX(250), GetEntryPosY(250)) > 640 ) { // Entry 250 is the player's character
while ( ( Distance(GetEntryPosX(250), GetEntryPosY(250)) > 500 ) && ( ( IsMovementEnabled == 1 ) || ( VAR_GlobUInt8_33 == 1 ) ) ) {
SetObjectFlags( 5 )
SetWalkSpeed( 45 )
if ( Distance(GetEntryPosX(250), GetEntryPosY(250)) > 1000 ) {
SetWalkSpeed( 60 )
}
InitWalk( )
MakeAnimationLoop( 1 )
Walk( GetEntryPosX(250), GetEntryPosY(250) )
}
if ( IsMovementEnabled == 0 ) {
Wait( 1 )
}
} else {
Wait( 10 )
if ( ( Distance(GetEntryPosX(250), GetEntryPosY(250)) > 640 ) && ( ( IsMovementEnabled == 1 ) || ( VAR_GlobUInt8_33 == 1 ) ) ) {
TurnTowardObject( 250, 32 )
WaitTurn( )
}
}
}
this.SubMenuPanel.transform.localScale = new Vector3(1.2f, 1.0f, 1.0f);
This would go in the method "MainMenuUI::Awake" (at the beginning, that's fine). I am not sure if it will work though, as UI modding is not something I know a lot about (and some informations are stored in GameObject and Transform files in the archives level1 and level2). Try to play with the figures here if you see that it has an effect.
About modifying the animations, you should try using the Unity Assets Viewer: it allows to export animated 3D models (most of them are in the archive p0data4). Unfortunatly, re-importing a modified 3D model bugs and is hardly working at all. However, for modifying the animations only, it should be working. Follow the tutorial there (http://forums.qhimm.com/index.php?topic=14315.msg255679#msg255679) and make sure that the option "Automatically Convert 3D Models -> Import Meshes/Materials" is disabled.
Thank YOU for all the replies Tirlititi! Tomorrow I check
@eugene9: Ah, I didn't understand exactly what you wanted.
I still don't really do. In most cases, you can't just "make someone uses someone else's animation". For instance, Zidane as a tail, not Steiner, so there's no way to use the animations of Zidane for someone who doesn't have a tail and vice versa... most of the time.
What you can try to do, using the Unity Assets Viewer:
1) In Hades Workshop, open "Tools -> Unity Assets Viewer", then "File -> Open -> FF9_Launcher.exe",
2) Then "Archive -> Streaming Assets -> p0data5" ; you should see a bunch of animation files appearing,
3) Select the animation you want to replace (you can sort the list by the "File Name" to have them grouped by models or by "Infos" to have them grouped by animation name), then "Right click -> Export Selection",
4) Select the animation by which you want to replace the previous one (let's call them A1 and A2: you want to replace A1 by A2) and "Right click -> Export Selection",
5) In the folder of FF9, there should now be a folder called "HadesWorkshopAssets" that contain the two files you just exported,
6) Copy A2 inside the folder of A1 and then rename it to replace it (give to A2 the name of A1),
7) Back in the Unity Assets Viewer, select A1 and "Right click -> Import Selection",
8) Done: the animation file has been replaced in the game's archive (if you have several copies of the game, the archive updated is the one corresponding to the "FF9_Launcher.exe" that you opened).
However, as I said, you will likely have bugs and non-working animations... But there might be a few animations that can be compatible with 3D models they were not meant for... if you're lucky.
You must not have the game's files opened in the main frame of Hades Workshop (the tool should have poped up a warning about that).
Close the main frame and the importation will get available.
@ToraCarol: You can put the "Freya follows Zidane" code in a new function with a high function code (let's say "Function Freya_20" if it doesn't exist already) and add the line "RunScriptAsync( 2, 255, 20 )" inside the "Freya_Init" function (replace 20 by your function code if needed).
This way, it won't mess with the "Freya_Loop" function. The condition "IsMovementEnabled" in the code I showed should be enough to disable that feature during cutscenes.
You may want to add a "return" line after the end of the "while ( 1 )" loop even though that shouldn't be problematic (I think I added a warning if there's no "return" or "loop" line when you parse).
set VAR_GlobBool_247 = 1
And in the following loop:if ((IsMovementEnabled == 0) && VAR_GlobBool_247) {
InitWalk( )
Walk( GetFieldExitX, GetFieldExitY )
return
}
"VAR_GlobBool_247" is the last bit of the last global variable and thus is the least often used. It is not used in any script of Burmecia but it is used at some other place (in those places, one can use "VAR_GlobBool_0" because the first 8 bytes are always used for the placing of the objects (VAR_GlobInt16_0, etc...) but then it needs to be re-initialized to 0 in the "Main_Init" script after the placing of all the objects).
Ooops! my bad!!! thank you for your help :). And what about changing Zidane's model for his trance model?
EDIT: I don't get animations working, everytime I try to swap characters' battle animation they remain in T pose.
Tirlititi has a mod for trance models defaults!.First things first. Thank you all for your help and instructions! I'm very glad to see how supportive this community is :). I know that mod, and I have used it. But the problem is that it sets all characters into their trance model, I only wnat it for Zidane. Evenmore, I don't know why, but when casting spells with that mod on, there is always a kind of shadow shilouette behind the spellcaster which looks quite weird.
https://www.dropbox.com/sh/ac7sr4q3z2cx9vp/AACQDfqXPvn8c3ylXeGUrBKEa?dl=0&preview=PC_AlwaysTranceMod.zip
it sets all characters on trance model but can be edited with the provided .hws!.
Tirlititi has a mod for trance models defaults!.
https://www.dropbox.com/sh/ac7sr4q3z2cx9vp/AACQDfqXPvn8c3ylXeGUrBKEa?dl=0&preview=PC_AlwaysTranceMod.zip
it sets all characters on trance model but can be edited with the provided .hws!.
Zidane (2 of them),
Vivi,
Dagger (4 of them),
Steiner (2 of them),
Quina,
Eiko (2 of them),
Freya,
Amarant,
Cinna,
Marcus,
Blank (2 of them),
Beatrix,
Zidane Trance (that's the 20th, at index 19 and there are 2 of them just like the regular),
Vivi Trance,
etc...
up to Amarant Trance.
Which makes a list of size 19 (regular) + 14 (trance) = 33 models.byte[][] array = new byte[][]
new byte[] { 255, 96, 96 },
// etc...
These are RGB color factors for the glowing effect of the trance. You must extend the array with one entry (of 3 bytes) corresponding to Beatrix's glowing effect when she turns to trance. The default color factor is 128, which means that "{ 128, 128, 128 }" will not display any glowing at all. Personally, I used the following in my mod:new byte[] { 255, 160, 128 }
@ToraCarol: Yes, that's the main point of my previous message.
@Incinerator: I don't think that splines are imported correctly!
Triangularize the mesh before importing it. I think splines are not supported because there is none in the non-modded game and I didn't know how to handle them. If someone is expert in Unity serialized 3D models, he could explain how to handle splines.
@ToraCarol: It's not really possible to do that because not all the characters have the correct animations (like opening a chest or climbing a ladder).
"InitObject( 251 )" works only if there are script functions for the character. For instance, if Eiko is the first character, then the script must have a "Eiko_Init" function attached to Eiko's entry for "InitObject( 251 )" to work.
You can see in the "Edit Entries" window that there is always an entry for the player characters. It's just that they usually don't have any function linked to them.
In order for the player to control a character, it's something different: you need to use "DefinePlayerCharacter()" in the entry that you want the player to take control of (usually, it's in the "Init" function but it can be in another function if, for instance, the control is not given as soon as the characters are placed).
You don't bother me; it's just that I stopped modding so I don't answer right away anymore.
Function Blank_Init
switchex 3 ( General_FieldEntrance ) {
case 150:
set VAR_GlobInt16_0 = 65390
set VAR_GlobInt16_4 = 62586
set VAR_GlobInt16_6 = 151
set VAR_GlobInt16_2 = 937
break
case 152:
set VAR_GlobInt16_0 = 117
set VAR_GlobInt16_4 = 3048
set VAR_GlobInt16_6 = 255
set VAR_GlobInt16_2 = 65349
break
case 10000:
set VAR_GlobInt16_0 = 64979
set VAR_GlobInt16_4 = 65407
set VAR_GlobInt16_6 = 64
set VAR_GlobInt16_2 = 65321
break
default:
set VAR_GlobInt16_0 = 65382
set VAR_GlobInt16_4 = 62643
set VAR_GlobInt16_6 = 0
set VAR_GlobInt16_2 = 937
}
SetModel( 5467, 87 )
CreateObject( VAR_GlobInt16_0, VAR_GlobInt16_4 )
TurnInstant( 80 )
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 )
MoveInstantXZY( GetEntryPosX(255), VAR_GlobInt16_2, GetEntryPosY(255) )
SetPathing( 1 )
DefinePlayerCharacter( )
EnableHeadFocus( 0 )
if ( General_FieldEntrance == 10000 ) {
SetObjectFlags( 14 )
SetObjectSize( 12, 0, 0, 0 )
}
return
What is the current script that you got?
There are two possibilities: either the loop enters a case where the script "returns" (which stops for good the script making her following Zidane) or you forget to set the safety variable back to its normal state (that's if the cutscene safety relies on a variable).
}
if ( ( IsMovementEnabled == 0 ) && ( General_ScenarioCounter <= 3820 ) ) {
Wait( 1 )
return
} else {
if ( ( IsMovementEnabled == 0 ) && VAR_GlobBool_247 ) {
InitWalk( )
Walk( GetFieldExitX, GetFieldExitY )
return
}
}
While we're in argument I also want to ask you..I've tried on South Gate to make Marcus jump on the bridge after Dagger jumps, but I don't know why for some reason the Object "Marcus" moves but not read the "jump" animation, plus takes a little to go back in it's normal state..if you know what I mean. What I did is simply copypaste the same codes of Dagger and use them for Marcus (setting his Jump animation..obviously) and also added the script on the Region...so what's wrong?
Thanks as always if you can help
UPDATE: I was wondering..is there a way, somehow, to emulate a "Change Disc"? Like a save menu, and then an image appears like to change the disc even if it's not? (You know, like Game Over)
Marcus's model might not have a jump animation as I don't think there is any point in the story that he jumps.
This sounds like the model moving, trying to execute an animation that doesn't exist, so instead doesn't do anything for the duration that the animation is meant to happen and then returning to the normal state.
@ToraCarol: There should not be any "return" line if the first "if" block that you show.
The problem with the jump animation is more likely to be the one described here (http://forums.qhimm.com/index.php?topic=14315.msg245063#msg245063). You need to use this jump animation before in the script to let the game load it (using "SetRightAnimation( 5041 )" just before "SetRightAnimation( 5224 )" is enough).
Emulating a "Change disc" screen requires modding the C# code and adding new assets (textures) to the game. I don't know if it can work, sorry.
You may more easily add a "Would you like to save?" screen, as it can simply be emulated with a dialog box... but I can understand that it's not what you want.
[...]Prison Cage; Garnet battle does this.
3) Last but not least, what about if I want to set in a "Trance Mode at start of the battle" other characters instead only Zidane, Steiner and Vivi? It's possible?
I know there is something that enables "Trance Mode" in the main enemy attacks, is it correct?
[...]
Function Main_Init
if ( IsBattleInitialized ) {
CloseAllWindows( )
Wait( 5 )
TerminateBattle( )
} else {
set SV_EnemyTeam[ATB] =$ FirstOf(SV_EnemyTeam[MAX_ATB])
set #( VAR_GlobUInt16_33 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 0 ) )
set #( VAR_GlobUInt16_33 |= ( SV_PlayerTeam[MODEL_TYPE] ==$ 1 ) )
}
return
The first check is to see if battle has ended already, that seems to be normal for most battles. Then at [else] there are some commands and one of them is setting the enemy's ATB to the MAX_ATB of the first enemy. Tirlititi will have to explain how the list assignments work because I don't fully understand them, but I know that's what's happening in that line anyway.set #( VAR_GlobUInt16_33 = RandomInTeam(SV_PlayerTeam) )
now, this variable is important for later, because in that fight ONLY Zidane is supposed to start with Trance, and the game needs to know which party slot he's in, in order to target him. (the battle also tracks all the other characters this way too so there is a variable for each specific character you might want to target)Function Prison_Cage_ATB
if ( !VAR_LocUInt8_3 ) {
set VAR_LocUInt8_3 = 1
set #( SV_Target = VAR_GlobUInt16_33 )
Attack( 8 )
return
}
return
VAR_LocUInt8_3 is for tracking the cutscene progression for Zidane and Steiner explaining what Trance is. To begin with, its not set, so the battle checks if it doesn't exist yet (it doesn't) and then it sets it to 1, sets the SV_Target variable to the VAR_GlobUInt16_33, which it previously set as the party slot for Zidane, so now the next attack to execute will hit Zidane. Finally, it executes Attack( 8 ) which in this battle is Transfer, which fills up a character's Trance meter completely, and then returns out of the [if] and then processes some other things I removed for brevity, and then returns again to allow the game to continue into the next cycle. set #( VAR_GlobUInt16_45 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 12 ) )
just like it did for Zidane in UInt16_33[MODEL_TYPE]
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
Hello guys, I'm sorry if I bother but I really hope anyone can help me with this oneSpoiler: show
As you can see in this image, there's a text window..with no text inside it! Why this happens? How to solve?
Looks like a script called text that doesn't exist!.
Thank you for the reply Incinerator..so how can I solve this missing? What did I or didn't I do? I've tried some things but looks like i really don't know how to come through this :(
I took Eiko on Lv1 editing Field scripts at Conde Petie Mountain Path in the function "Main_Loop" (Marcus' level was 21)
Function Main_Loop
if ( General_FieldEntrance == 65535 ) {
set Setting_PartyReserve = 103
SetPartyReserve( Setting_PartyReserve )
if ( IsInParty(5) ) {
RemoveParty( 5 )
set VARL_GenUInt8_303 = 0
set VAR_GenInt8_60 = ( VAR_GenInt8_61 = ( VAR_GenInt8_62 = ( VAR_GenInt8_63 = ( VAR_GlobInt16_8 = ( VAR_GlobInt16_10 = ( VAR_GlobInt16_12 = ( VAR_GlobInt16_14 = 65535 ) ) ) ) ) ) )
set VAR_GlobInt16_14 = 0
while ( VAR_GlobInt16_14 <= 11 ) {
if ( IsInParty(VAR_GlobInt16_14) ) {
I'm a such a turtle!
Is you text added in right text block for this field (iirc Text Panel -> Alexander)
Hold everything!
I found a bug when loading HWS files containing Spell Animations. It corrupts the saves done after that.
If you loaded HWS files containing Spell Animations and then saved HWS again with the version 0.41, you must do that, using the version 0.41b:
- Open the HWS with your latest changes (saved with v0.41) without the Spell Animations (it should crash anyway if you load them),
- Open a previous HWS with Spell Animations changes (saved with <= v040b) if you have a backup or do the Spell Animations changes again.
- Save as HWS; that's fine.
If you don't have a backup, you can also send me your (corrupted) HWS file and I will fix it.
Sorry for the troubles...
set VAR_LocInt8_29 = VAR_LocUInt8_28
while ( VAR_LocInt8_29 >= 0 ) {
switch 8 ( VAR_LocInt24_24 ) from 0 {
case +0:
set #( SV_Target = RandomInTeam(( ( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 257) & NotMatching(SV_PlayerTeam[STATUS_CURRENT_B], 64) ) & ( ~( Matching(SV_PlayerTeam[STATUS_CURRENT_B], 32) | Matching(SV_PlayerTeam[STATUS_AUTO_B], 32) ) ) )) )
break
if ( dummyindex == 1 )
if ( ( #NotMatching(SV_PlayerTeam[STATUS_CURRENT], PETRIFY | VENOM | DEATH | STOP | LOW_HP) < 4 ) && ( targetamount != 0 ) )
set SV_FunctionEnemy[PREVENT_ATTACK] = 1
elseif ( dummyindex == 2 )
Function Dummy_ATB
switch 3 ( VAR_LocUInt8_1 ) from 1 {
case +0:
if ( VAR_LocUInt8_8 ) {
set #( VAR_LocUInt16_4 = RandomInTeam(( ( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 257) & NotMatching(SV_PlayerTeam[STATUS_CURRENT_B], 64) ) & ( ~( Matching(SV_PlayerTeam[STATUS_CURRENT_B], 32) | Matching(SV_PlayerTeam[STATUS_AUTO_B], 32) ) ) )) )
} else {
set #( VAR_LocUInt16_4 = 1 )
}
set VAR_LocInt24_24 = ( VAR_LocInt24_21 & 7 )
set VAR_LocInt24_33 = GetRandom
set VAR_LocInt24_36 = 128
set VAR_LocInt8_29 = ( VAR_LocUInt8_28 - 1 )
while ( VAR_LocInt8_29 >= 0 ) {
if ( VAR_LocInt24_33 > VAR_LocInt24_36 ) {
break
}
set VAR_LocInt24_36 >>= 1
set VAR_LocInt8_29--
}
if ( VAR_LocInt8_29 == 65535 ) {
set VAR_LocInt8_29 = ( VAR_LocUInt8_28 - 1 )
}
if ( VAR_LocInt8_29 == ( VAR_LocUInt8_28 - 1 ) ) {
set VAR_LocInt24_21 = ( ( VAR_LocInt24_21 >> 3 ) & 2097151L )
set VAR_LocInt24_21 |= ( VAR_LocInt24_24 << ( VAR_LocInt8_29 * 3 ) )
} else {
if ( VAR_LocInt8_29 ) {
set VAR_LocInt24_30 = ( VAR_LocInt24_24 << ( VAR_LocInt8_29 * 3 ) )
set VAR_LocInt24_33 = ( ( 1 << ( ( VAR_LocInt8_29 + 1 ) * 3 ) ) - 1 )
set VAR_LocInt24_36 = ( ( VAR_LocInt24_33 & VAR_LocInt24_21 ) >> 3 )
set VAR_LocInt24_36 |= VAR_LocInt24_30
set VAR_LocInt24_33 ^= 16777215L
set VAR_LocInt24_21 &= VAR_LocInt24_33
set VAR_LocInt24_21 |= VAR_LocInt24_36
}
}
set VAR_LocInt8_29 = VAR_LocUInt8_28
while ( VAR_LocInt8_29 >= 0 ) {
switch 8 ( VAR_LocInt24_24 ) from 0 {
case +0:
set #( SV_Target = RandomInTeam(( ( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 257) & NotMatching(SV_PlayerTeam[STATUS_CURRENT_B], 64) ) & ( ~( Matching(SV_PlayerTeam[STATUS_CURRENT_B], 32) | Matching(SV_PlayerTeam[STATUS_AUTO_B], 32) ) ) )) )
break
case +1:
set #( SV_Target = RandomInTeam(( ( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 257) & NotMatching(SV_PlayerTeam[STATUS_CURRENT_B], 64) ) & ( ~( Matching(SV_PlayerTeam[STATUS_CURRENT_B], 32) | Matching(SV_PlayerTeam[STATUS_AUTO_B], 32) ) ) )) )
break
case +2:
set #( SV_Target = SV_PlayerTeam )
break
case +3:
set #( SV_Target = VAR_LocUInt16_4 )
break
case +4:
set #( SV_Target = VAR_LocUInt16_4 )
break
case +5:
set #( SV_Target = RandomInTeam(( ( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 257) & NotMatching(SV_PlayerTeam[STATUS_CURRENT_B], 64) ) & ( ~( Matching(SV_PlayerTeam[STATUS_CURRENT_B], 32) | Matching(SV_PlayerTeam[STATUS_AUTO_B], 32) ) ) )) )
break
case +6:
set #( SV_Target = RandomInTeam(( ( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 257) & NotMatching(SV_PlayerTeam[STATUS_CURRENT_B], 64) ) & ( ~( Matching(SV_PlayerTeam[STATUS_CURRENT_B], 32) | Matching(SV_PlayerTeam[STATUS_AUTO_B], 32) ) ) )) )
break
case +7:
set #( SV_Target = SV_FunctionEnemy )
}
if ( VAR_LocInt24_24 >= 4 ) {
set VAR_LocInt24_33 = ( ( VAR_LocInt24_18 >> ( ( VAR_LocInt24_24 - 4 ) * 6 ) ) & 63 )
} else {
set VAR_LocInt24_33 = ( ( VAR_LocInt24_15 >> ( VAR_LocInt24_24 * 6 ) ) & 63 )
}
set VAR_LocInt24_30 = ( #SV_Target )
set VAR_LocInt24_36 = FirstOf(SV_FunctionEnemy[MP])
if ( VAR_LocInt24_30 && ( VAR_LocInt24_33 <= VAR_LocInt24_36 ) ) {
break
}
if ( VAR_LocInt8_29 <= 0 ) {
break
}
set VAR_LocInt24_24 = ( VAR_LocInt24_21 & 7 )
set VAR_LocInt24_21 = ( ( VAR_LocInt24_21 >> 3 ) & 2097151L )
set VAR_LocInt24_21 |= ( VAR_LocInt24_24 << ( ( VAR_LocUInt8_28 - 1 ) * 3 ) )
set VAR_LocInt8_29--
}
if ( VAR_LocInt24_24 >= 4 ) {
set VAR_LocUInt8_27 = ( ( VAR_LocInt24_12 >> ( ( VAR_LocInt24_24 - 4 ) * 6 ) ) & 63 )
} else {
set VAR_LocUInt8_27 = ( ( VAR_LocInt24_9 >> ( VAR_LocInt24_24 * 6 ) ) & 63 )
}
if ( VAR_LocUInt8_27 == 9 ) {
set VAR_LocUInt8_8 = 1
}
break
case +1:
set VAR_LocInt24_24 = ( VAR_LocInt24_21 & 7 )
set VAR_LocInt24_33 = GetRandom
set VAR_LocInt24_36 = 128
set VAR_LocInt8_29 = ( VAR_LocUInt8_28 - 1 )
while ( VAR_LocInt8_29 >= 0 ) {
if ( VAR_LocInt24_33 > VAR_LocInt24_36 ) {
break
}
set VAR_LocInt24_36 >>= 1
set VAR_LocInt8_29--
}
if ( VAR_LocInt8_29 == 65535 ) {
set VAR_LocInt8_29 = ( VAR_LocUInt8_28 - 1 )
}
if ( VAR_LocInt8_29 == ( VAR_LocUInt8_28 - 1 ) ) {
set VAR_LocInt24_21 = ( ( VAR_LocInt24_21 >> 3 ) & 2097151L )
set VAR_LocInt24_21 |= ( VAR_LocInt24_24 << ( VAR_LocInt8_29 * 3 ) )
} else {
if ( VAR_LocInt8_29 ) {
set VAR_LocInt24_30 = ( VAR_LocInt24_24 << ( VAR_LocInt8_29 * 3 ) )
set VAR_LocInt24_33 = ( ( 1 << ( ( VAR_LocInt8_29 + 1 ) * 3 ) ) - 1 )
set VAR_LocInt24_36 = ( ( VAR_LocInt24_33 & VAR_LocInt24_21 ) >> 3 )
set VAR_LocInt24_36 |= VAR_LocInt24_30
set VAR_LocInt24_33 ^= 16777215L
set VAR_LocInt24_21 &= VAR_LocInt24_33
set VAR_LocInt24_21 |= VAR_LocInt24_36
}
}
set VAR_LocInt8_29 = VAR_LocUInt8_28
while ( VAR_LocInt8_29 >= 0 ) {
switch 8 ( VAR_LocInt24_24 ) from 0 {
case +0:
set #( SV_Target = SV_PlayerTeam )
break
case +1:
set #( SV_Target = SV_PlayerTeam )
break
case +2:
set #( SV_Target = SV_PlayerTeam )
break
case +3:
set #( SV_Target = SV_FunctionEnemy )
break
case +4:
set #( SV_Target = SV_FunctionEnemy )
break
case +5:
set #( SV_Target = SV_FunctionEnemy )
break
case +6:
set #( SV_Target = SV_FunctionEnemy )
break
case +7:
set #( SV_Target = SV_FunctionEnemy )
}
if ( VAR_LocInt24_24 >= 4 ) {
set VAR_LocInt24_33 = ( ( VAR_LocInt24_18 >> ( ( VAR_LocInt24_24 - 4 ) * 6 ) ) & 63 )
} else {
set VAR_LocInt24_33 = ( ( VAR_LocInt24_15 >> ( VAR_LocInt24_24 * 6 ) ) & 63 )
}
set VAR_LocInt24_30 = ( #SV_Target )
set VAR_LocInt24_36 = FirstOf(SV_FunctionEnemy[MP])
if ( VAR_LocInt24_30 && ( VAR_LocInt24_33 <= VAR_LocInt24_36 ) ) {
break
}
if ( VAR_LocInt8_29 <= 0 ) {
break
}
set VAR_LocInt24_24 = ( VAR_LocInt24_21 & 7 )
set VAR_LocInt24_21 = ( ( VAR_LocInt24_21 >> 3 ) & 2097151L )
set VAR_LocInt24_21 |= ( VAR_LocInt24_24 << ( ( VAR_LocUInt8_28 - 1 ) * 3 ) )
set VAR_LocInt8_29--
}
if ( VAR_LocInt24_24 >= 4 ) {
set VAR_LocUInt8_27 = ( ( VAR_LocInt24_12 >> ( ( VAR_LocInt24_24 - 4 ) * 6 ) ) & 63 )
} else {
set VAR_LocUInt8_27 = ( ( VAR_LocInt24_9 >> ( VAR_LocInt24_24 * 6 ) ) & 63 )
}
set #( VAR_LocUInt16_6 = RandomInTeam(( ( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 257) & NotMatching(SV_PlayerTeam[STATUS_CURRENT_B], 64) ) & ( ~( Matching(SV_PlayerTeam[STATUS_CURRENT_B], 32) | Matching(SV_PlayerTeam[STATUS_AUTO_B], 32) ) ) )) )
if ( !( #( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 4355) & VAR_LocUInt16_6 ) ) ) {
set #( SV_Target = 1 )
}
break
case +2:
set #( VAR_LocUInt16_2 = 0 )
if ( ( FirstOf(VAR_GlobUInt16_24[HP]) - 10000 ) < ( ( FirstOf(VAR_GlobUInt16_24[MAX_HP]) - 10000 ) >> 1 ) ) {
set #( VAR_LocUInt16_2 = VAR_GlobUInt16_24 )
} else {
set #( VAR_LocUInt16_2 = 1 )
}
set VAR_LocInt24_24 = ( VAR_LocInt24_21 & 7 )
set VAR_LocInt24_33 = GetRandom
set VAR_LocInt24_36 = 128
set VAR_LocInt8_29 = ( VAR_LocUInt8_28 - 1 )
while ( VAR_LocInt8_29 >= 0 ) {
if ( VAR_LocInt24_33 > VAR_LocInt24_36 ) {
break
}
set VAR_LocInt24_36 >>= 1
set VAR_LocInt8_29--
}
if ( VAR_LocInt8_29 == 65535 ) {
set VAR_LocInt8_29 = ( VAR_LocUInt8_28 - 1 )
}
if ( VAR_LocInt8_29 == ( VAR_LocUInt8_28 - 1 ) ) {
set VAR_LocInt24_21 = ( ( VAR_LocInt24_21 >> 3 ) & 2097151L )
set VAR_LocInt24_21 |= ( VAR_LocInt24_24 << ( VAR_LocInt8_29 * 3 ) )
} else {
if ( VAR_LocInt8_29 ) {
set VAR_LocInt24_30 = ( VAR_LocInt24_24 << ( VAR_LocInt8_29 * 3 ) )
set VAR_LocInt24_33 = ( ( 1 << ( ( VAR_LocInt8_29 + 1 ) * 3 ) ) - 1 )
set VAR_LocInt24_36 = ( ( VAR_LocInt24_33 & VAR_LocInt24_21 ) >> 3 )
set VAR_LocInt24_36 |= VAR_LocInt24_30
set VAR_LocInt24_33 ^= 16777215L
set VAR_LocInt24_21 &= VAR_LocInt24_33
set VAR_LocInt24_21 |= VAR_LocInt24_36
}
}
set VAR_LocInt8_29 = VAR_LocUInt8_28
while ( VAR_LocInt8_29 >= 0 ) {
switch 8 ( VAR_LocInt24_24 ) from 0 {
case +0:
set #( SV_Target = VAR_LocUInt16_2 )
break
case +1:
set #( SV_Target = RandomInTeam(( ( NotMatching(SV_EnemyTeam[STATUS_CURRENT_A], 257) & NotMatching(SV_EnemyTeam[STATUS_CURRENT_B], 64) ) & ( ~Matching(SV_EnemyTeam[STATUS_CURRENT_A], 4194304L) ) )) )
break
case +2:
set #( SV_Target = RandomInTeam(( ( NotMatching(SV_EnemyTeam[STATUS_CURRENT_A], 257) & NotMatching(SV_EnemyTeam[STATUS_CURRENT_B], 64) ) & ( ~Matching(SV_EnemyTeam[STATUS_CURRENT_A], 8388608L) ) )) )
break
case +3:
set #( SV_Target = SV_FunctionEnemy )
break
case +4:
set #( SV_Target = SV_FunctionEnemy )
break
case +5:
set #( SV_Target = SV_FunctionEnemy )
break
case +6:
set #( SV_Target = SV_FunctionEnemy )
break
case +7:
set #( SV_Target = SV_FunctionEnemy )
}
if ( VAR_LocInt24_24 >= 4 ) {
set VAR_LocInt24_33 = ( ( VAR_LocInt24_18 >> ( ( VAR_LocInt24_24 - 4 ) * 6 ) ) & 63 )
} else {
set VAR_LocInt24_33 = ( ( VAR_LocInt24_15 >> ( VAR_LocInt24_24 * 6 ) ) & 63 )
}
set VAR_LocInt24_30 = ( #SV_Target )
set VAR_LocInt24_36 = FirstOf(SV_FunctionEnemy[MP])
if ( VAR_LocInt24_30 && ( VAR_LocInt24_33 <= VAR_LocInt24_36 ) ) {
break
}
if ( VAR_LocInt8_29 <= 0 ) {
break
}
set VAR_LocInt24_24 = ( VAR_LocInt24_21 & 7 )
set VAR_LocInt24_21 = ( ( VAR_LocInt24_21 >> 3 ) & 2097151L )
set VAR_LocInt24_21 |= ( VAR_LocInt24_24 << ( ( VAR_LocUInt8_28 - 1 ) * 3 ) )
set VAR_LocInt8_29--
}
if ( VAR_LocInt24_24 >= 4 ) {
set VAR_LocUInt8_27 = ( ( VAR_LocInt24_12 >> ( ( VAR_LocInt24_24 - 4 ) * 6 ) ) & 63 )
} else {
set VAR_LocUInt8_27 = ( ( VAR_LocInt24_9 >> ( VAR_LocInt24_24 * 6 ) ) & 63 )
}
}
switch 9 ( VAR_LocUInt8_27 ) from 7 {
case +0:
if ( #( SV_FunctionEnemy[MP] <$ 46 ) ) {
set VAR_LocUInt8_27 = 16
}
break
case +1:
if ( #( SV_FunctionEnemy[MP] <$ 36 ) ) {
set VAR_LocUInt8_27 = 16
}
break
case +2:
if ( #( SV_FunctionEnemy[MP] <$ 40 ) ) {
set VAR_LocUInt8_27 = 16
}
break
case +3:
if ( #( SV_FunctionEnemy[MP] <$ 24 ) ) {
set VAR_LocUInt8_27 = 16
}
break
case +4:
if ( #( SV_FunctionEnemy[MP] <$ 24 ) ) {
set VAR_LocUInt8_27 = 16
}
break
case +5:
if ( #( SV_FunctionEnemy[MP] <$ 24 ) ) {
set VAR_LocUInt8_27 = 16
}
break
case +6:
if ( #( SV_FunctionEnemy[MP] <$ 20 ) ) {
set VAR_LocUInt8_27 = 16
}
break
case +7:
if ( #( SV_FunctionEnemy[MP] <$ 8 ) ) {
set VAR_LocUInt8_27 = 16
}
break
case +8:
if ( #( SV_FunctionEnemy[MP] <$ 8 ) ) {
set VAR_LocUInt8_27 = 16
}
break
}
if ( SV_Target == 0 ) {
set VAR_LocUInt8_27 = 16
}
switch 3 ( VAR_LocUInt8_1 ) from 1 {
case +0:
if ( ( #( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 4355) & ( ~Matching(SV_PlayerTeam[STATUS_CURRENT_A], 512) ) ) ) < 4 ) {
set #( SV_Target = 0 )
set VAR_LocUInt8_27 = 16
}
break
case +1:
if ( ( #( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 4355) & ( ~Matching(SV_PlayerTeam[STATUS_CURRENT_A], 512) ) ) ) < 3 ) {
set #( SV_Target = 0 )
set VAR_LocUInt8_27 = 16
}
break
case +2:
if ( ( #( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 4355) & ( ~Matching(SV_PlayerTeam[STATUS_CURRENT_A], 512) ) ) ) < 2 ) {
set #( SV_Target = 0 )
set VAR_LocUInt8_27 = 16
}
break
}
set VAR_LocUInt8_39 = ( #SV_Target )
Attack( VAR_LocUInt8_27 )
return
set #( reflecttargetcheck = RandomInTeam(( ( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 257) & NotMatching(SV_PlayerTeam[STATUS_CURRENT_B], 64) ) & ( ~( Matching(SV_PlayerTeam[STATUS_CURRENT_B], 32) | Matching(SV_PlayerTeam[STATUS_AUTO_B], 32) ) ) )) )
if ( !( #( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 4355) & reflecttargetcheck ) ) ) {
set #( SV_Target = 0 )}
set #( reflecttargetcheck = RandomInTeam(( ( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 257) & NotMatching(SV_PlayerTeam[STATUS_CURRENT_B], 64) ) )) )
if ( !( #( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 4355) & reflecttargetcheck ) ) ) {
set #( SV_Target = 1)}
set #( SV_Target = 1)
set #( SV_Target = 5)
SV_Target does not work like that.
"set SV_Target = 1" -> Only the 1st player's character is targeted (usually Zidane).
"set SV_Target = 2" -> Only the 2nd player's character is targeted.
"set SV_Target = 4" -> Only the 3rd player's character is targeted.
"set SV_Target = 8" -> Only the 4th player's character is targeted.
"set SV_Target = 16" -> Only the 1st enemy is targeted.
"set SV_Target = 32" -> Only the 2nd enemy is targeted.
"set SV_Target = 64" -> Only the 3rd enemy is targeted.
"set SV_Target = 128" -> Only the 4th enemy is targeted.
And then, you add numbers to have multiple targets. The whole player's party is thus targeted with "set SV_Target = 15" and not 5 (if you watch more carefully, you'll see that only two characters are affected when you use 5).
However, because the number of characters/enemies may vary, it is very unusual to use the numbers directly; oftentimes, "SV_PlayerTeam" or "SV_EnemyTeam" are used instead of "15" or "240" respectively. The "NotMatching" or "Matching" rules out characters not matching some conditions (the "32" means "Reflect": again, select that number and see how it converts to the "Status List B" which can be seen on the left of the window, inside the "Battle" panel). For single-targeted spells, a "RandomInTeam" is used.
The number used as an argument for the "Attack" corresponds to the attack in the attack list. Look at what's displayed on the right.
SV_Target does not work like that.
"set SV_Target = 1" -> Only the 1st player's character is targeted (usually Zidane).
"set SV_Target = 2" -> Only the 2nd player's character is targeted.
"set SV_Target = 4" -> Only the 3rd player's character is targeted.
"set SV_Target = 8" -> Only the 4th player's character is targeted.
"set SV_Target = 16" -> Only the 1st enemy is targeted.
"set SV_Target = 32" -> Only the 2nd enemy is targeted.
"set SV_Target = 64" -> Only the 3rd enemy is targeted.
"set SV_Target = 128" -> Only the 4th enemy is targeted.
And then, you add numbers to have multiple targets. The whole player's party is thus targeted with "set SV_Target = 15" and not 5 (if you watch more carefully, you'll see that only two characters are affected when you use 5).
However, because the number of characters/enemies may vary, it is very unusual to use the numbers directly; oftentimes, "SV_PlayerTeam" or "SV_EnemyTeam" are used instead of "15" or "240" respectively. The "NotMatching" or "Matching" rules out characters not matching some conditions (the "32" means "Reflect": again, select that number and see how it converts to the "Status List B" which can be seen on the left of the window, inside the "Battle" panel). For single-targeted spells, a "RandomInTeam" is used.
The number used as an argument for the "Attack" corresponds to the attack in the attack list. Look at what's displayed on the right.
if (ModelFactory.garnetShortHairTable.Contains(text))
{
ushort num = BitConverter.ToUInt16(FF9StateSystem.EventState.gEventGlobal, 0);
bool flag = num >= 10300;
if (flag)
{
// etc... Disable "long_hair" components
}
else
{
// etc... Disable "short_hair" components
}
}
Replace the "if (flag)" line by "if (flag && isBattle)". case EBin.event_code_binary.MODEL:
{
posObj.model = (ushort)this.getv2();
Obj expr_1EA4 = this.gExec;
expr_1EA4.flags |= 1;
posObj.eye = (short)(-4 * this.getv1());
if (this.gMode == 1)
{
string text = FF9BattleDB.GEO[(int)posObj.model];
posObj.go = ModelFactory.CreateModel(text, false);
GeoTexAnim.addTexAnim(posObj.go, text);
if (ModelFactory.garnetShortHairTable.Contains(text))
{
posObj.garnet = true;
ushort num7 = BitConverter.ToUInt16(FF9StateSystem.EventState.gEventGlobal, 0);
posObj.shortHair = (num7 >= 10300);
}
// etc...
Change the line "posObj.shortHair = (num7 >= 10300);" to "posObj.shortHair = false;".public void Perform()
{
if (!_v.Target.CanBeRevived())
return;
if (_v.Target.IsZombie)
{
_v.Context.Flags |= BattleCalcFlags.Miss; // Add this line
return; // Add this line
// if ((_v.Target.CurrentHp = (UInt16)(GameRandom.Next8() % 10)) == 0) // Remove this line
// _v.Target.Kill(); // Remove this line
}
else if (_v.Target.CheckIsPlayer())
{
if (_v.Target.IsUnderStatus(BattleStatus.Death))
_v.Target.CurrentHp = (UInt16)(1 + GameRandom.Next8() % 10);
_v.TargetCommand.TryRemoveItemStatuses();
}
}
if (Status.checkCurStat(target, 64u) || btl_util.CheckEnemyCategory(target, ENEMY.ENEMY_CATEGORY_UNDEAD))
{
calc_VAR.flags |= 1; // Add this line
// Remove the following lines, "if ((target.cur.hp = (ushort)(Comn.random8() % 10)) == 0)" and "SetEnforceHP0"
}
else if (btl_calc.CheckNotPlayerMiss(calc_VAR))
// etc... no change there
switch 3 ( Chocobo_ChocoColor ) from 1 {
case +0:
if ( Hot&ColdField == 1 ) {
set ChocographAvailableList |= 8 // 4th Chocograph (Yellow to Light Blue)
set ChocographLastAvailableFlag = 1
}
break
case +1:
if ( ( Hot&ColdField == 2 ) && ( Global_ScenarioCounter >= 9400 ) ) {
set ChocographAvailableList |= 2048 // 12th Chocograph (Light Blue to Red)
set ChocographLastAvailableFlag = 1
}
break
case +2:
if ( ( Hot&ColdField == 1 ) && ( Global_ScenarioCounter >= 9400 ) ) {
set ChocographAvailableList |= 8192 // 14th Chocograph (Red to Deep Blue)
set ChocographLastAvailableFlag = 1
}
break
default:
set ChocographLastAvailableFlag = 0
break
}
Without renamed variables (as it appears in Hades Workshop), it's this part: switch 3 ( Chocobo_ChocoColor ) from 1 {
case +0:
if ( Chocobo_CurrentField == 1 ) {
set VAR_GenInt24_172 |= 8
set VAR_LocUInt8_8 = 1
}
break
case +1:
if ( ( Chocobo_CurrentField == 2 ) && ( General_ScenarioCounter >= 9400 ) ) {
set VAR_GenInt24_172 |= 2048
set VAR_LocUInt8_8 = 1
}
break
case +2:
if ( ( Chocobo_CurrentField == 1 ) && ( General_ScenarioCounter >= 9400 ) ) {
set VAR_GenInt24_172 |= 8192
set VAR_LocUInt8_8 = 1
}
break
default:
set VAR_LocUInt8_8 = 0
break
}
So you see, you only need to increase the scenario counter lower bound for this special chocograph availability. Here are a few key scenario counter values (the first ones are named in the game's source code and I'm not always sure of the meaning, the last ones are values I searched myself in different field scripts):SC_COUNTER_ARMOR_BLANK_START = 1500
SC_COUNTER_ARMOR_BLANK_END = 1600
SC_COUNTER_WMTITLE_BUNMEI_ON = 2400
SC_COUNTER_SGATE_DESTROYED = 2990
SC_COUNTER_CLAY_DESTROYED = 4990
SC_COUNTER_LIND_DESTROYED = 5598
SC_COUNTER_FOG_END = 5990
SC_COUNTER_KUROMA_APPEAR = 6200
SC_COUNTER_DAGGER_AWAKE = 6875
SC_COUNTER_SGATE_RECOVER = 6990
SC_COUNTER_ALEX_DESTROYED = 8800
SC_COUNTER_SUNA_MAKYU_ON = 9450
SC_COUNTER_WMTITLE_NEW_ON = 9600
SC_COUNTER_SUNA_MAKYU_OFF = 9890
SC_COUNTER_CUT_HAIR = 10300
SC_COUNTER_GET_HILDA3 = 10400
SC_COUNTER_HOKORA_START = 10600
SC_COUNTER_HOKORA_END = 10700
SC_COUNTER_LAST_WORLD = 11090
Hilda Garde obtained = 10400
Ipsen Castle entered = 10500
Ipsen Castle done = 10600
Eiko+Dagger gone to Shrine = 10620
Amarant+Freya gone to Shrine = 10640
Steiner+Vivi gone to Shrine = 10660
Shrines done = 10700
Disc 4 = 11100
Update to v0.41c:
- Added script file batch importing: you can now write script functions with your favorite text editor and import it back when you're done,
- Fixed bugs with text and UI text batch importation; also, the text IDs now start from 0 instead of 1 in the exported batches (so they match with the text ID inside scripts),
- Added more unused/dummied datas (for enemies mainly) that can be recycled when modifying the game's source code; also added enemy attack targetting informations (they are mostly unused, except for deciding if Cover triggers if I'm not mistaken),
- Listed more script functions and general variables in the script editor,
- Fixed a bug with Qu's Marsh's dialogs (it was actually caused by a "mobile" version of the dialogs; I think it's unused),
- In the Randomizer, the Prison Cages' "Absorb" spell is not randomized anymore,
- Fixed another bug with spell animation sequencing.
I am retiring from FF9 modding (presumably definitively). I don't think that I'll update this tool any further. The code is on Github though and I'll still answer questions, so here you go.
this.SubMenuPanel.transform.localScale = new Vector3(1.2f, 1.0f, 1.0f);
So? Have you tried doing that?
But it can't be done for the PSX version. It's a modification of the game's engine, so it's for PC.
switchex 8 ( GetFrogAmount ) {
case 2 ; 5 ; 9 ; 15 ; 23 ; 33 ; 45 ; 99:
set VAR_GlobUInt8_64 = 2
break
default:
break
}
2) In the "Main_Loop", there's most of the cutscene's code, in particular the line "if ( GetFrogAmount == 99 ) {" triggering the battle.if ( ((GetRandom % 100) < 50) && ( FirstOf(SV_FunctionEnemy[MP]) >= 18 ) ) { // Example: 50% of chances to cast Life if there's a Zombie character and if the enemy has 18 MP or more
set SV_Target = Matching( SV_PlayerTeam[STATUS_CURRENT_A], 64 ) // All the Zombie characters
if ( #SV_Target ) { // Same as "if ( SV_Target ) {" or "if ( (#SV_Target) != 0 ) {"
set SV_Target = RandomInTeam(SV_Target) // Pick only one of them
Attack( ... ) // Cast Life
return
}
}
// etc... do something else if Life is not chosen for any reason
set AddParty(8)
"8" is an ID for Beatrix's character slot (0 is for Zidane, etc... Marcus shares Eiko's character slot).RemoveParty(0)
set Setting_PartyReserve = 511
SetPartyReserve(Setting_PartyReserve)
Note that it's a bit flag list (it works just like SV_Target (http://forums.qhimm.com/index.php?topic=14315.msg267122#msg267122) in battle scripts). Usually, this party reserve is set to 255 for all the eight normal characters, so adding 256 to that value adds Beatrix.if ( IsInParty(0) ) {
Party( 4, 1 ) // Form a party of 4 characters and lock Zidane inside
} else {
Party( 4, 0 ) // Form a party of 4 characters without locking any character inside
}
set SV_FunctionEnemy[DEFEATED_ON] =$ 1
You could also kill him for good with "set SV_FunctionEnemy[HP] =$ 0" but that would trigger other things like his death cry (I don't think he has one though), his death animation and fading... so that's a less good option.
new rdata.FF9COMMAND(89, 349, 8276, 1, 16, 192UL)
varshort = something + 16; // Error
varshort = (short)(something + 16); // Use this instead if the compiler complains: write the required converted type and wrap the computation inside parentheses
new rdata.FF9COMMAND(89, 349, 8276, 1, 16, 8UL)
Like in your guide, I changed the last number to 192. ChangeTimerTime( 1801 )
ShowTimer( 1 )
RunTimer( 1 )
1800 seconds = 30 x 60 seconds = 30 minutes. Just put any number you want there to change the initial time limit.music033 -> A Place to Call Home (internal ID: 58)
music078 -> A Song from Her Memory (internal ID: 106)
music083 -> Aboard the Hilda Garde (internal ID: 112)
music012 -> Aloha De Chocobo (internal ID: 24)
music005 -> Amarant's Theme (internal ID: 2)
music117 -> Another Nightmare (internal ID: 45)
music122 -> Assault of the Silver Dragons (internal ID: 147)
music102 -> Awaking Song (internal ID: 77)
music070 -> Bahamut is Summoned (internal ID: 98)
music006 -> Battle (internal ID: 0)
music071 -> Before the Altar (internal ID: 99)
music043 -> Beyond the Twilight (internal ID: 67)
music054 -> Black Mage Village (internal ID: 82)
music024 -> Boss Battle (internal ID: 35)
music059 -> Bran Bal, the Soulless Village (internal ID: 87)
music114 -> Broken Spell, Healed Hearts (internal ID: 146)
music044 -> Burmecia (internal ID: 68)
music077 -> Chamber of a Thousand Faces (internal ID: 105)
music097 -> Cid's Theme (internal ID: 133)
music049 -> Cleyra Settlement (internal ID: 80)
music064 -> Cleyra's Trunk (internal ID: 92)
music062 -> Conde Petie (internal ID: 90)
music037 -> Court Jesters (internal ID: 53)
music087 -> Crystal World (internal ID: 121)
music093 -> Daguerreo, the Hermit's Library (internal ID: 129)
music003 -> Danger in the Forest (internal ID: 4)
music057 -> Dark City Treno (internal ID: 85)
music098 -> Dark Messenger (internal ID: 134)
music067 -> Desert Palace (internal ID: 96)
music069 -> Devil's Ambition (internal ID: 97)
music030 -> Distant Memory (internal ID: 59)
music121 -> Doga and Une (internal ID: 148)
music050 -> Eidolon Wall (internal ID: 81)
music060 -> Eiko's Theme (internal ID: 88)
music113 -> Esto Gaza (internal ID: 144)
music055 -> Eternal Harvest (internal ID: 83)
music014 -> Eye to Eye (internal ID: 20)
music038 -> Faerie Battle (internal ID: 61)
music101 -> Final Battle (internal ID: 71)
music013 -> Find the Princess (internal ID: 27)
music053 -> Fleeting Life (internal ID: 76)
music116 -> Foolproof Love Letter Scheme (internal ID: 141)
music048 -> Fossil Roo (internal ID: 79)
music011 -> Freya's Theme (internal ID: 32)
music001 -> Game Over (internal ID: 6)
music063 -> Gargan Roo (internal ID: 91)
music010 -> Garnet's Theme (internal ID: 29)
music105 -> Girl of Madain Sari (internal ID: 139)
music118 -> Guardians (internal ID: 72)
music082 -> Hunter's Chance (internal ID: 111)
music111 -> I Want to be Your Canary (internal ID: 145)
music031 -> Ice Cavern (internal ID: 60)
music080 -> Iifa, the Ancient Tree of Life (internal ID: 109)
music112 -> Inseparable Hearts (internal ID: 142)
music075 -> Ipsen's Castle (internal ID: 103)
music115 -> Kiss of Betrayal (internal ID: 41)
music066 -> Kuja's Theme (internal ID: 95)
music088 -> Light of Destiny (internal ID: 124)
music047 -> Lindblum (internal ID: 74)
music058 -> Look Back, See the Frog! (internal ID: 86)
music092 -> Master of Time (internal ID: 118)
music084 -> Melodies of Life (internal ID: 113)
music096 -> Memoria (internal ID: 132)
music046 -> Moogle's Theme (internal ID: 73)
music081 -> Mount Gulug (internal ID: 110)
music061 -> Mourning in the Sky (internal ID: 89)
music025 -> Oeilvert (internal ID: 36)
music027 -> Out of the Frying Pan (internal ID: 49)
music026 -> Outlaws (internal ID: 44)
music045 -> Over the Hill (internal ID: 69)
music056 -> Pandemonium (internal ID: 84)
music106 -> Peaceful City (internal ID: 138)
music120 -> Prelude (internal ID: 156)
music041 -> Prima Vista Orchestra (internal ID: 65)
music089 -> Protecting My Devotion (internal ID: 125)
music032 -> Qu's Marsh (internal ID: 57)
music009 -> Quina's Theme (internal ID: 15)
music036 -> RUN! (internal ID: 52)
music090 -> Roses of May (internal ID: 116)
music052 -> Rufus' Welcoming Ceremony (internal ID: 75)
music094 -> Ruins of Madain Sari (internal ID: 130)
music079 -> South Gate (internal ID: 108)
music110 -> Star-Crossed Lovers (internal ID: 143)
music039 -> Steiner's Delusion (internal ID: 62)
music007 -> Steiner's Theme (internal ID: 10)
music017 -> Swords of Fury (internal ID: 18)
music095 -> Terra (internal ID: 131)
music042 -> Tetra Master (internal ID: 66)
music109 -> The Black Waltz (internal ID: 140)
music020 -> The Evil Within (internal ID: 30)
music108 -> The Extraction (internal ID: 7)
music016 -> The Fateful Hour (internal ID: 17)
music073 -> The Four Mirrors (internal ID: 101)
music018 -> The Meeting (internal ID: 12)
music091 -> The Wavering Blade (internal ID: 117)
music021 -> Thy Warmth (internal ID: 33)
music022 -> Tragic Love (internal ID: 25)
music072 -> Ukulele de Chocobo (internal ID: 100)
music029 -> Unforgettable Silhouette (internal ID: 50)
music004 -> Unforgettable Sorrow (internal ID: 1)
music051 -> Unrequited Love (internal ID: 70)
music015 -> Vamo Alla Flamenco (internal ID: 22)
music000 -> Victory Fanfare (internal ID: 5)
music002 -> Village of Dali (internal ID: 3)
music008 -> Vivi's Theme (internal ID: 9)
music068 -> Wicked Melody (internal ID: 94)
music028 -> You're Not Alone (internal ID: 48)
music085 -> Zidane and Dagger's Song (internal ID: 115)
music023 -> Zidane's Theme (internal ID: 34)
@Shinryu actually u can easily remove the time limit in getting the excalibur 2 using this tool so u dont need to rush your game. ;) go toTY
environment---->fields-->memoria gate to space and edit script:
if ( GetTime <= 43200L ) {
InitCode( 3, 0 )
remove the [ if ( GetTime <= 43200L ) { ]
and this one
if ( ( ( ( IsMovementEnabled == 1 ) && ( VARL_GenBool_7730 == 0 ) ) && ( VAR_GlobBool_145 == 0 ) ) && ( GetTime <= 43200L ) ) {
remove this line : && ( GetTime <= 43200L ) ) {
case 49:
RunAnimation( 10382 )
WaitAnimation( )
WaitAnimation( )
SetAnimationFlags( 2, 0 )
RunAnimation( 10388 )
WindowAsync( 2, 128, 212 )
WaitWindow( 2 )
set VAR_GlobInt16_47 = 50
SetAnimationFlags( 0, 0 )
RunAnimation( 10392 )
WaitAnimation( )
RunAnimation( 8197 )
WaitAnimation( )
SetAnimationFlags( 2, 0 )
RunAnimation( 8195 )
break
case 143:
RunSoundCode( 0, 134 )
RunAnimation( 1698 )
WindowSync( 7, 128, 336 )
Wait( 5 )
Battle( 1, 198 )
SetHP( 0, 9999 )
SetHP( 1, 9999 )
SetHP( 3, 9999 )
SetHP( 2, 9999 )
SetHP( 4, 9999 )
SetHP( 5, 9999 )
SetHP( 7, 9999 )
SetHP( 6, 9999 )
SetHP( 8, 9999 )
SetMP( 0, 999 )
SetMP( 1, 999 )
SetMP( 3, 999 )
SetMP( 2, 999 )
SetMP( 4, 999 )
SetMP( 5, 999 )
SetMP( 7, 999 )
SetMP( 6, 999 )
SetMP( 8, 999 )
CureStatus( 0, 127 )
CureStatus( 1, 127 )
CureStatus( 3, 127 )
CureStatus( 2, 127 )
CureStatus( 4, 127 )
CureStatus( 5, 127 )
CureStatus( 7, 127 )
CureStatus( 6, 127 )
CureStatus( 8, 127 )
Wait( 5 )
break
case 143:
RunSoundCode( 0, 134 )
RunAnimation( 5199 )
WindowSync( 7, 128, 336 )
Wait( 5 )
Battle( 1, 198 )
Wait( 5 )
break
@ToraCarol: Maybe it has something to do with the dialog itself? What text opcodes are you using?
Yes Clem Fandango, I've encountered such kind of crash before... and when I did, I tried to fix the problem ^^"
If you want to know where it comes from, the first thing is to try launching the game with all the files modded except p0data7.bin (which is the file containing the field scripts). If it doesn't crash with the base p0data7, that's a good point in favor of that Ash/Veteran change having triggered the problem. If it still crashes, then it was something else.
The field scripts are in p0data7 but if it crashes at the logo, then it's not really about the script itself but rather about how the files are packed inside the archive p0data7. I'm afraid you may have encountered a rare bug that happens only at specific settings (a file having a special position in the archive, replaced by an update with a special file size...). I'm not aware of such bug in the latest version of HW, but I expect it to work like that from experience...
Another possibility, that wouldn't make the issue comes from HW, is that you somehow replaced one of the game's files (p0data7 for instance) while HW was opened (and had loaded those game's files). If you do that, then HW will compile the Steam mod files wrongly and pack complete nonsense in the archives. The .hws would not be damaged in that scenario though.
I don't know why that's happening to you.
Your planned order of work looks fine if "Beatrix Mode Import" means that you import the AFBeatrixOnly_v5.0.hws on a clean non-modded game.
You should do this:
1) Import the Beatrix HWS file, do the modifications you want, save as HWS (the .hws will contain both Beatrix's changes and your own),
rather than that:
2) Do the modifications that you want, save as HWS (your modifications only), import the Beatrix HWS and then your modifications again.
Indeed, it is possible to import several HWS one after the other but the latest import will have priority for everything that is common to both mods. For instance, if you modify any of party's spells, all of them will be stored in the HWS file (not only the bit you've changed). You can see in the "Tools -> Mod Manager" how each section is splitted (for instance, if you modify an enemy's HP, all the other enemies are not stored in the HWS and even that enemy's AI script won't be).
Your planned order of work looks fine if "Beatrix Mode Import" means that you import the AFBeatrixOnly_v5.0.hws on a clean non-modded game.
@gledson999: The VWF is not in a standard format (you can see its format here (https://github.com/Tirlititi/Hades-Workshop/blob/master/Source/Charmaps.cpp)).
I don't have all my FF9 datas available for some time, but the file is a 0x0D chunk that is approximately at position 0x3cb048 (it depends on the disk and the language; 0x3cb048 is the disk 3 of the french version). For informations on chunks and cluster datas, you can check Qhimm's wiki.
I can do that but in 2 weeks only, once I return home.Thanks for you reply, i'll so i'll wait, Merry Christmas
anxietymafia: Not to my knowledge, no. You can try to find that icon in the "Environment -> Texts -> Generic UI" and edit the image to remove the icon (I don't remember for sure but I think that you can draw pixel by pixel in HW on these images).
Unknown, usually 0 (4 bytes)
Unknown short int (2 bytes)
Unknown short int (2 bytes)
Number of characters, short unsigned int (2 bytes)
Padding, usually 0 (2 bytes)
[
Img_x (1 byte)
Img_y (1 byte)
Img_width (1 byte)
Width (1 byte)
] (x Number of characters)
Also, you need to know that these font images are compressed in a 2:3 format, ie. 2 colors produce 3 pixels (a mean color is computed and the middle pixel in the x-axis is given that mean color). The coordinates reflect this compression: a width of 6 in the charmap file actually means a width of 9 pixels in the bitmap.
Function Lich_Loop
while ( GetBattleState != 1 ) {
Wait( 1 )
}
if ( VAR_GlobUInt8_24 == 0 ) {
Wait( 15 )
RunBattleCode( 36, 9 )
Wait( 10 )
BattleDialog( 12 )
Wait( 60 )
BattleDialog( 13 )
Wait( 75 )
}
RunBattleCode( 35, 0 )
while ( GetBattleState != 4 ) {
Wait( 1 )
}
if ( #( SV_FunctionEnemy[HP] <$ 10000 ) ) {
if ( VAR_LocUInt8_60 < 1 ) {
set VAR_LocUInt8_60++
set SV_FunctionEnemy[HP] =$ 40000
}
}
return
// ...
RunBattleCode( 35, 0 )
while ( GetBattleState != 4 ) {
Wait( 1 )
}
while ( 1 ) {
if ( #( SV_FunctionEnemy[HP] <$ 10000 ) ) {
if ( VAR_LocUInt8_60 < 1 ) {
set VAR_LocUInt8_60++
set SV_FunctionEnemy[HP] =$ 40000
}
}
Wait( 1 ) // If you forget that, the game will freeze
}
return
Damage = (Atk - Def) * (((Strength + OtherStat) / 2) + Rnd MOD (((Lvl + Str) / 8) + 1))
So it uses (Strength + OtherStat) / 2 for these special weapons instead of Strength for the normal weapons?The formulae displayed in HW are all wrong :/
case 48:
case 83:
btl_calc.CalcSub_13A(calc_VAR);
btl_calc.CalcSub_141(calc_VAR);
btl_calc.CalcSub_143(calc_VAR);
btl_calc.CalcSub_151(calc_VAR);
if ((caster.sa[0] & 2097152U) != 0U)
{
calc_VAR.at_num = (short)(calc_VAR.at_num * 3 >> 1);
}
if (prog_no == 48)
{
if (btl_calc.CalcSub_152(calc_VAR))
{
btl_calc.CalcSub_203(calc_VAR);
}
}
else
{
if (btl_calc.CalcSub_152(calc_VAR))
{
int num14;
if ((num14 = (int)(calc_VAR.at_pow - calc_VAR.df_pow)) <= 0)
{
num14 = 1;
}
CALC_VAR calc_VAR33 = calc_VAR;
calc_VAR33.tg_flags |= 1;
if (calc_VAR.at_num < 4)
{
calc_VAR.at_num = 4;
}
int num15 = (int)((long)(num14 * (int)calc_VAR.at_num) / (long)((ulong)btl_util.SumOfTarget(0U)));
if (num15 > 9999)
{
num15 = 9999;
}
if ((calc_VAR.flags & 8) != 0)
{
calc_VAR.tg_flags |= 2;
}
calc_VAR.tg_hp = (short)num15;
}
}
break;
btl_calc.ApplySpellElementBoost(calc_VAR);
if (btl_calc.ApplyWeapElement(calc_VAR))
{ [...] }
Dunno if elemental physical strikes exist, but doesn't this mean that the spell uses the element of the weapon for the sake of weaknesses/freeze/heat whatever and the element of the SPELL (not the weapon) for the sake of elm. boost alone?Yes exactly. Not sure if it's an oversight or anything, but that's indeed how it works.
// I think this was a working example for BattleUI
this.CommandPanel.GetComponent<UIWidget>().GetChild(0).GetComponent<UIWidget>().SetRect( X, Y, W, H );
// ... or lines like this
this.CommandPanel.transform.localPosition = new Vector3( X, Y, this.CommandPanel.transform.localPosition.z );
public class FixSpiritSkillNumberLabelPos : MonoBehaviour
{
void Start()
{
transform.localPosition = Vector2.right * 292;
}
void OnEnable()
{
transform.localPosition = Vector2.right * 292;
}
}
public class ParameterDetailCompareHUD
{
public ParameterDetailCompareHUD(GameObject go)
{
this.Self = go;
Int32 i = 0;
Int32 num = 0;
while (i < 10)
{
if (i != 4)
{
this.ParameterLabel[num] = go.GetChild(i).GetChild(1).GetComponent<UILabel>();
this.NewParameterLabel[num] = go.GetChild(i).GetChild(3).GetComponent<UILabel>();
this.ArrowSprite[num] = go.GetChild(i).GetChild(2).GetComponent<UISprite>();
this.ArrowTween[num] = go.GetChild(i).GetChild(2).GetComponent<TweenAlpha>();
num++;
}
i++;
}
//This is the added line of code
NewParameterLabel[3].gameObject.AddComponent<FixSpiritSkillNumberLabelPos>();
}
public GameObject Self;
[...]
}
public override bool OnKeyConfirm(GameObject go)
{
bool flag2 = base.OnKeyConfirm(go);
if (flag2)
{
bool flag3 = ButtonGroupState.ActiveGroup == EquipUI.SubMenuGroupButton;
if (flag3)
{
this.currentMenu = this.GetSubMenuFromGameObject(go);
switch (this.currentMenu)
{
case EquipUI.SubMenu.Equip:
case EquipUI.SubMenu.Off:
FF9Sfx.FF9SFX_Play(103);
ButtonGroupState.ActiveGroup = EquipUI.EquipmentGroupButton;
ButtonGroupState.SetSecondaryOnGroup(EquipUI.SubMenuGroupButton);
ButtonGroupState.HoldActiveStateOnGroup(EquipUI.SubMenuGroupButton);
this.DisplaySubMenuArrow(false);
this.DisplayEquiptmentInfo();
// Line added here
this.DisplayParameter();
break;
case EquipUI.SubMenu.Optimize:
[...]
It's not currently possible Xenogears, unfortunatly. That's indeed a problem with the widescreen mode: background pictures have a size adjusted to the screen mode used in the PSX version. These backgrounds have not been extended for the PC port (it would have been a huge work).
What might be done to fix some of these problems is to reduce the camera bounds. It can be done in HW for each field script 1 by 1 but it would be much better to do it with dnSpy/source code modding.
It wouldn't fix many fields, like Observatory Mountain's fields.
Hello everyone !
I am very curious how work modding with FFIX and that's why i decide to test HW !
However... i am big newbie with it :roll: (never use C# on my life lol but i can learn... i think)
For my first experience, i add BigDragon on Evil Forest first zone (light clearing).... yeah, pretty brutal.
I follow theses steps on "Properly adding a new enemy to a battle (Steam) (http://forums.qhimm.com/index.php?topic=14315.msg245485#msg245485)"
Dragon is present with Goblin and Fang, can attack Zidane but i have two issues :
- Dragon is called "Lame" (mean Knife in FR)
- All attacks from Dragon, Goblin and Fang display wrongly : sometimes there's is nothing (text box is empty), or None (EN)/Rien (FR) showed or EnnemyDummy for Dragon
(https://image.noelshack.com/minis/2020/15/2/1586279696-20200407191406-1.png) (https://www.noelshack.com/2020-15-2-1586279696-20200407191406-1.jpg)
As i said, i follow all steps from Tirlititi, use simply IA for Dragon (with 2/3 DragonClaw and 1/3 Thundaga), compare with other battles....
I didn't edit attacks and IA from Goblin and Fang and i copy all Dragon attacks from his original battle.
After few hours of testing... i am lost.
I am asking your help... i think i am dumb to find why it's broken ;DSpoiler: Main_Init showSpoiler: Dragon_Init showSpoiler: Dragon_ATB show
case 44:
{
ELEMENT elem2 = target.elem;
if ((elem2.mgc += target.elem.mgc / cmd.aa.Ref.power) > 99)
{
target.elem.mgc = 99;
}
break;
}
if ((elem2.mgc += target.elem.mgc / cmd.aa.Ref.power) > 99)
There's a "+=" operation there, which adds things but also return the value of "elem2.mgc" after it was updated for a comparison with "99".elem2.mgc += target.elem.mgc / cmd.aa.Ref.power;
if (elem2.mgc > 99)
(2) What should have most interest for you: the main method, "CalcMain", that contains the bone structure of spell effects, is written in the .cs files that are inside the folder "StreamingAssets\Scripts\Sources\Battle". The names of the files start with the same numbers as the "case" number inside the "Source_BtlCalc.cs" that I provided (for instance, the "case 9: // Magic Attack" is in the file "0009_MagicAttackScript.cs"; Albeoris and I didn't always use the same names but it shouldn't be to hard to go from one to the other).
Congrats if you've read and understood this far!
I guess that HW is not such a difficult tool to use, right? :p
For these other files, you don't need dnSpy a priori. Albeoris made it so you can simply change the scripts using a text editor but it comes with costs...
public void PenaltyBanishHitRate() // i don't understand why Banish, maybe Vanish instead ?
{
if (base.IsUnderStatus(BattleStatus.Vanish))
{
this._context.HitRate = 0;
}
if ((v.Command.Data.aa.Category & 8) != 0) // if attack is not magical ?
{
v.Target.RemoveStatus(BattleStatus.Confuse);
v.Target.RemoveStatus(BattleStatus.Sleep);
}
if ((v.Command.Data.aa.Category & 16) != 0) // if attack is not physical ?
{
v.Target.RemoveStatus(BattleStatus.Vanish);
}
public const BattleStatus ANIM_STOP_STATUS = BattleStatus.Venom | BattleStatus.Stop | BattleStatus.Freeze;
PenaltyBanishHitRateIndeed, there are a few "typos". There are a lot of mistakes like that in the Memoria's battle CS files but also in the normal source code sometimes. It indeed concerns Vanish there.
v.Command.Data.aa.Category & 1 -> "Reflectable"
v.Command.Data.aa.Category & 2 -> "Silence"
v.Command.Data.aa.Category & 4 -> "No M-Sword"
v.Command.Data.aa.Category & 8 -> "Is Physical"
v.Command.Data.aa.Category & 16 -> "Is Magical"
v.Command.Data.aa.Category & 32 -> "Short"
v.Command.Data.aa.Category & 64 -> "Hit Anim Off"
v.Command.Data.aa.Category & 128 -> "Returnable"
Flags are checked like that (it was the standard thing at the time). They use bitwise operators like "&" or "|" to manipulate flags and powers of 2 for the different flags.NoInput = 1107434753u,
CmdCancel = 134401u,
Immobilized = 33558529u,
FrozenAnimation = 1107300353u,
NoMagic = 318905609u,
CannotEscape = 1107431745u,
CannotTrance = 33575233u,
BattleEnd = 4353u,
NoReaction = 1107300609u,
- In the class btl_cmd, remove Venom from the disabling list in the methods "SetCounter" and "SetEnemyCommand[BySequence]".So, sorry for the late answers.
Flee is actually not a multi-target spell animation, but single-target. If you go in HW's panel "Environment -> Spell Animations -> Flee-Skill -> Edit Spell Sequencing", you can see that the damage point and effect point only apply to the 1st target. Change that to apply to all the targets and you'll be able to use a multi-target White Wind with that (I am not 100% sure of the effect on fleeing though; it might bug to trigger fleeing several time simultaneously but I don't think so).
No, you can't delete files added using UAV and actually... you shouldn't add files either as it bugs and somehow I was never able to make it so new files can be used by the game (it just doesn't find them).
Replacing existing files is okay. Sounds and images are converted back and forth to standard file formats (the raw files couldn't be opened with pretty much all the sound/image readers). 3D models and their animations can be exported to correct FBX files (you need to export the "GameObject" that corresponds to the model, not the "Mesh" entry that usually has the same name and you need to export the textures separatly; sometimes they are not refered automatically correctly in the exported FBX). However, you can barely replace 3D models as it would usually consist of creating new files that the game wouldn't recognize... Using custom 3D models would better be done by reading them out of any archive inside the DLL (last time I've checked, though, I didn't find C# methods for importing FBX models... maybe big libraries like UnityEditor.dll would be required for that).
Memoria adds a way to import new sounds through the class Memoria.SoundImporter. It requires the sound to be in .ogg format and I guess that you need to setup a "SoundProfile" yourself (setup an unused soundID and the proper SoundProfileType, etc). It must be possible and easier than importing a new 3D model in any case, but don't try to add it inside the archive, only in a sub-folder of the game (or Moguri mod's folder if it's inside "StreamingAssets").
02.05.2020 06:42:17 |M| [TextResourceExporter] Pass through {Configuration.Export.Text = 0}.
02.05.2020 06:42:17 |M| [GraphicResourceExporter] Pass through {Configuration.Export.Graphics = 0}.
02.05.2020 06:42:17 |M| [FieldSceneExporter] Pass through {Configuration.Export.Field = 0}.
02.05.2020 06:42:17 |M| [BattleSceneExporter] Pass through {Configuration.Export.Battle = 0}.
02.05.2020 06:42:17 |M| [ResourceExporter] Application will now quit. Please disable Configuration.Export.Enabled and restart the game.
02.05.2020 06:42:17 |M| [ResourceImporter] Pass through {Configuration.Import.Enabled = 0}.
02.05.2020 06:42:17 |M| [GameLoopManager] RaiseQuitEvent
Musics played in battles are indeed in these .txt files. They consist of a list of field IDs (or World Map IDs) and for each of them, a list of battle IDs encountered in these fields and the music linked to it. If the battle is not present, then the music is uninterrupted.
For my mod, I simply didn't change these files but I've put a line "Play Music" in the field scripts right before triggering some boss battles (something like "RunSoundCode( MusicID )" although I don't remember which "RunSoundCode" alternative should be used). That solution doesn't work with random encounters though.
// Token: 0x04001E7E RID: 7806
public const int SNG_MUSIC095 = 131;
// Token: 0x04001E7F RID: 7807
public const int SNG_MUSIC096 = 132;
// Token: 0x04001E80 RID: 7808
public const int SNG_MUSIC097 = 133;
// Token: 0x04001E81 RID: 7809
public const int SNG_MUSIC098 = 134;
// Token: 0x04001E82 RID: 7810
public const int SNG_MUSIC099 = 135;
// Token: 0x04001E83 RID: 7811
public const int SNG_MUSIC100 = 64;
// Token: 0x04001E84 RID: 7812
public const int SNG_MUSIC101 = 71;
// Token: 0x04001E85 RID: 7813
public const int SNG_MUSIC102 = 77;
03.05.2020 09:02:01 |W| [SoundLib] Music Id: 149 has Exception: System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
03.05.2020 09:02:01 |W| at System.Collections.Generic.Dictionary`2[System.Int32,System.String].get_Item (Int32 key) [0x00000] in <filename unknown>:0
03.05.2020 09:02:01 |W| at SoundMetaData.GetSoundProfile (Int32 soundIndex, SoundProfileType type) [0x00000] in <filename unknown>:0
03.05.2020 09:02:01 |W| at AllSoundDispatchPlayer.CreateSoundProfileIfNotExist (Int32 soundIndex, SoundProfileType type, .OnCreateFinish onFinishDelegate) [0x00000] in <filename unknown>:0
03.05.2020 09:02:01 |W| at AllSoundDispatchPlayer.FF9SOUND_SONG_PLAY (Int32 ObjNo, Int32 vol) [0x00000] in <filename unknown>:0
03.05.2020 09:02:01 |W| at FF9Snd.FF9AllSoundDispatch (Int32 ParmType, Int32 ObjNo, Int32 Arg1, Int32 Arg2, Int32 Arg3) [0x00000] in <filename unknown>:0
You need to use the Unity Assets Viewer for that.
Open the resources.assets archive, search for the file "BtlEncountBgmMetaData.txt", export it, modify it and then re-import it.
Inside that file, there's a list of field IDs (so the Queen's Chamber in which you fight Beatrix is 1223) and for each field, a list of battles that can trigger in that field with the music ID of the battle ran. If a battle is missing there, the ambiant music doesn't stop when entering a battle.
So just find the field (1223), the battle (73) and put the correct music ID for it (117, "The Wavering Blade").
Here's a list of music IDs. I don't think that you can actually see it in Hades Workshop (only in the UAV when you open the music archive p0data62).Code: [Select]34: Zidane's Theme
70: Unrequited Love
9: Vivi's Theme
82: Black Mage Village
76: Fleeting Life
10: Steiner's Theme
62: Steiner's Delusion
29: Garnet's Theme
113: Melodies of Life
69: Over the Hill
77: Awaking Song // A Song from Her Memory, probably sung in Dali
115: Zidane and Dagger's Song
106: A Song from Her Memory
59: Distant Memory
124: Light of Destiny
32: Freya's Theme
68: Burmecia
50: Unforgettable Silhouette
15: Quina's Theme
88: Eiko's Theme
139: Girl of Madain Sari
2: Amarant's Theme
116: Roses of May
117: The Wavering Blade
125: Protecting My Devotion
30: The Evil Within
53: Court Jesters
133: Cid's Theme
118: Master of Time
84: Pandemonium
95: Kuja's Theme
96: Desert Palace // Kuja's Theme, played during the exploration of the Desert Palace
97: Devil's Ambition
98: Bahamut is Summoned
94: Wicked Melody
134: Dark Messenger
73: Moogle's Theme
4: Danger in the Forest
60: Ice Cavern
3: Village of Dali
67: Beyond the Twilight
74: Lindblum
49: Out of the Frying Pan
57: Qu's Marsh
108: South Gate
85: Dark City Treno
92: Cleyra's Trunk
80: Cleyra Settlement
91: Gargan Roo
79: Fossil Roo
90: Conde Petie
99: Before the Altar
130: Ruins of Madain Sari
81: Eidolon Wall
109: Iifa, the Ancient Tree of Life
112: Aboard the Hilda Garde
144: Esto Gaza
110: Mount Gulug
129: Daguerreo, the Hermit's Library
87: Bran Bal, the Soulless Village
132: Memoria
121: Crystal World
24: Aloha De Chocobo
100: Ukulele de Chocobo
22: Vamo Alla Flamenco
58: A Place to Call Home
36: Oeilvert
105: Chamber of a Thousand Faces
103: Ipsen's Castle
101: The Four Mirrors
131: Terra
44: Outlaws
138: Peaceful City // Outlaws, when controlling Vivi early disc 3
18: Swords of Fury
27: Find the Princess
20: Eye to Eye
17: The Fateful Hour
33: Thy Warmth
25: Tragic Love
143: Star-Crossed Lovers
41: Kiss of Betrayal
145: I Want to be Your Canary
142: Inseparable Hearts
65: Prima Vista Orchestra
75: Rufus' Welcoming Ceremony
12: The Meeting
140: The Black Waltz
83: Eternal Harvest
7: The Extraction
141: Foolproof Love Letter Scheme
86: Look Back, See the Frog!
146: Broken Spell, Healed Hearts
72: Guardians
48: You're Not Alone
147: Assault of the Silver Dragons
1: Unforgettable Sorrow
89: Mourning in the Sky
45: Another Nightmare
52: RUN!
111: Hunter's Chance
66: Tetra Master
0: Battle
35: Boss Battle
61: Faerie Battle
71: Final Battle
5: Victory Fanfare
6: Game Over
156: Prelude
148: Doga and Une
Earth Guardian :
"2553": {
"2": "35"
},
Nova Dragon :
"2756": {
"931": "147"
},
Maliris:
"2904": {
"932": "147"
},
Tiamat:
"2908": {
"933": "147"
},
Kraken:
"2915": {
"934": "147"
},
Lich:
"2919": {
"935": "147"
},
"2754": {},
"2755": {},
"2756": {},
"2800": {},
"2801": {},
"2802": {},
"2754": {},
"2755": {},
"2756": {
"931": "147"
},
"2800": {},
"2801": {},
"2802": {},
Earth Guardian:
"2553": {},
I guess that the music stops for Nova Dragon because there is a script at the end of the cinematic to stop the music. itemListDetailHUD.Content.SetActive(true);
int num2 = this.PatchAbility(num); // Added line of code
itemListDetailHUD.NameLabel.text = FF9TextTool.ActionAbilityName(num2); // Change num to num2
int mp = this.GetMp(aaData);
bool flag2 = mp != 0;
if (flag2)
{
itemListDetailHUD.NumberLabel.text = mp.ToString();
}
else
{
itemListDetailHUD.NumberLabel.text = string.Empty;
}
bool flag3 = abilityState == BattleHUD.AbilityStatus.ABILSTAT_DISABLE;
if (flag3)
{
itemListDetailHUD.NameLabel.color = FF9TextTool.Gray;
itemListDetailHUD.NumberLabel.color = FF9TextTool.Gray;
ButtonGroupState.SetButtonAnimation(itemListDetailHUD.Self, false);
}
else
{
itemListDetailHUD.NameLabel.color = FF9TextTool.White;
itemListDetailHUD.NumberLabel.color = FF9TextTool.White;
ButtonGroupState.SetButtonAnimation(itemListDetailHUD.Self, true);
}
itemListDetailHUD.Button.Help.TextKey = string.Empty;
itemListDetailHUD.Button.Help.Text = FF9TextTool.ActionAbilityHelpDescription(num2); // Change num to num2
private void DisplayAADetail(Transform item, ListDataTypeBase data, int index, bool isInit)
{
[...]
int mp = this.GetMp(FF9StateSystem.Battle.FF9Battle.aa_data[abilityListData.Id]);
int num2 = this.PatchAbility(abilityListData.Id); // Add this line
itemListDetailHUD.NameLabel.text = FF9TextTool.ActionAbilityName(num2); // Change abilityListData.Id to num2
itemListDetailHUD.NumberLabel.text = ((mp != 0) ? mp.ToString() : string.Empty);
if (abilityListData.Type == AbilityUI.AbilityType.CantSpell)
{
itemListDetailHUD.NameLabel.color = FF9TextTool.Gray;
itemListDetailHUD.NumberLabel.color = FF9TextTool.Gray;
}
else if (abilityListData.Type == AbilityUI.AbilityType.Enable)
{
itemListDetailHUD.NameLabel.color = FF9TextTool.White;
itemListDetailHUD.NumberLabel.color = FF9TextTool.White;
}
itemListDetailHUD.Button.Help.Enable = true;
itemListDetailHUD.Button.Help.Text = FF9TextTool.ActionAbilityHelpDescription(num2); // Change abilityListData.Id to num2
}
}
//*************************************************
//Also copy paste the following anywhere within AbilityUI.cs
//*************************************************
private int PatchAbility(int id)
{
if (AbilityUI.AbilCarbuncle == id)
{
switch (FF9StateSystem.Common.FF9.party.member[this.currentPartyIndex].equip[4])
{
case 227:
id += 3;
break;
case 228:
id++;
break;
case 229:
id += 2;
break;
}
}
else
{
if (AbilityUI.AbilFenril == id)
{
byte b = FF9StateSystem.Common.FF9.party.member[this.currentPartyIndex].equip[4];
id += ((b != 222) ? 0 : 1);
}
}
return id;
}
private static int AbilFenril = 66;
private static int AbilCarbuncle = 68;
EDIT: One last things. Albeoris also added a "Spell rate" feature: apart from the method "Perform" that you can find in the battle scripts, you sometimes have a method "RateTarget" that returns a Single (number) and is added when the class derivates from "IEstimateBattleScript". This method is meant to somehow measure the usefulness of an ability in a given situation. I am not sure if that feature is working (maybe it is used when the player turns Auto-battle on?) though, and you can ignore it if you don't care.
[Battle]
SelectBestTarget = 1 ; 0 - Original, 1 - Estimate the best target via IEstimateBattleScript
ViviAutoAttack = 0 ; 0 - Default attack, 1 - One of the basic spells (Fire, Blizzard, Thunder) cost-free MP
{
"name": "Sounds01/BGM_/music123",
"soundIndex": "149",
"type": "Music"
}
{
"name": "Sounds01/BGM_/music121",
"soundIndex": "148",
"type": "Music"
},
{
"name": "Sounds01/BGM_/music122",
"soundIndex": "147",
"type": "Music"
}, <======= Don't forget the comma here !
{
"name": "Sounds01/BGM_/music123",
"soundIndex": "149",
"type": "Music"
}
]
}
DV, friends, if you notice any problem in the game engine (equipment is incorrectly displayed) or in the Memoria (music is not exported), do not hesitate to write about it:
https://github.com/Albeoris/Memoria/issues
Sounds03/SE50/se500228
Sounds03/SE50/se500229
Sounds03/SE50/se500230
It's the exact same sounds used for Thunder-Slash-2 and Thunder-Slash-3. I don't know if you have access to the spell effect IDs in HW (I think not) but they are listed there (https://github.com/Tirlititi/Hades-Workshop/blob/master/Source/Database_SpellAnimation.h).It's the exact same sounds used for Thunder-Slash-2 and Thunder-Slash-3. I don't know if you have access to the spell effect IDs in HW (I think not) but they are listed there (https://github.com/Tirlititi/Hades-Workshop/blob/master/Source/Database_SpellAnimation.h).
If I understood correctly, sounds in the meta-data are listed by their order of usage.
uint i = 1;
ushort u1 = i;
ushort u2 = i+1;
This will possibly be an error for both u1 and u2 because they don't have the proper byte length. The fix for that is to force the type-cast:uint i = 1;
ushort u1 = (ushort)i;
ushort u2 = (ushort)(i+1);
Since the problem repeats everytime you try to edit a method or a class (even if you already fixed it on a previous edit), I took the habit to copy-paste codes in my text editor and do the changes there, then copy-paste back the code in dnSpy and keep the code saved somewhere for subsequent modifications.Function Gigan_Toad_Loop
while ( !( GetBattleLoadState & 8 ) ) {
Wait( 1 )
set VAR_GenUInt8_206 = GetRandom
}
set SV_FunctionEnemy[MODEL_SIZE] =$ 6144
set SV_FunctionEnemy[STOP_ANIM] =$ 2
set SV_FunctionEnemy[PLAY_ANIM_ONCE] =$ 0
return
Function Plastique_Loop
while ( !( GetBattleLoadState & 8 ) ) {
Wait( 1 )
set VAR_GenUInt8_206 = GetRandom
}
set SV_FunctionEnemy[MODEL_SIZE] =$ 6144
return
set 16[MODEL_SIZE] =$ 6144
Use "16" for the first enemy, "32" for the 2nd, "64" for the 3rd and "128" for the 4th. It may be not the best way to do (if you have several Plastique in the fight, they share the loop function... there should be no problem having a line for each one of them). At least, you can see with that if the problem comes from "SV_FunctionEnemy" for some reason.
@DV:
1°) Yes, there should be no problem copy/pasting a Ghost in the list of enemies for that battle so you have two different Ghosts; the game doesn't care if they have the same models or such... Just maybe uncheck the option "Edit similar enemies" when you do that. Once your super-ghost is given a different level or name, though, you can enable back that option because it won't be considered similar to the other ghosts by HW anymore.
2°) You can't do that by default unfortunatly :/
It goes down to the functionalities implemented in btl_scrp (https://github.com/Albeoris/Memoria/blob/main/Assembly-CSharp/Global/btl_scrp.cs). You can see that you can access to the status properties ("GetCharacterData", cases 42-45) but can't modify them ("SetCharacterData", there's no cases 42-45). In AF's source files (https://www.hiveworkshop.com/attachments/alternatefantasy_v5-0_sources-zip.335459/), there are codes for improving that part though and, in particular, let scripts be able to do that, so you can mod the DLL to add (at least) that feature and then use it in your HW scripts. I am not sure how we will implement all the features I need for AF in a next version of Memoria but it can be safely assumed that for statuses it will be implemented like that (for the new features that were not present at all, such as modifying a spell's stat during the battle, I may make it optional or external...).
3°) The 3D models of their attacks' SFX? You can't. They are not in a format that could be recognized by any model ripping software :/
However, Tasior2's FF9 Reverse (http://forums.qhimm.com/index.php?topic=15957.msg258062#msg258062) tool was able to get a couple of very specific SFX models very well, but it's limited (IIRC, the "Correct answer" and "Wrong answer" SFX of the Ragtime Mouse were amongst the only ones to be read thanks to it).
@Clem Fandango: I don't know that bug.
Are you sure that this "loop" function is what makes Zidane big? If you remove it (or keep only "return"), then both the monster and Zidane get regular sized?
If yes, you can try to use something like this instead of "set SV_FunctionEnemy[MODEL_SIZE] =$ 6144":Code: [Select]set 16[MODEL_SIZE] =$ 6144
Use "16" for the first enemy, "32" for the 2nd, "64" for the 3rd and "128" for the 4th. It may be not the best way to do (if you have several Plastique in the fight, they share the loop function... there should be no problem having a line for each one of them). At least, you can see with that if the problem comes from "SV_FunctionEnemy" for some reason.
Also, double-check that your enemy groups have the correct number of enemies (and with proper enemy type) and that the "Main_Init" function creates them properly as well, with the correct IDs.
public static Int32 SeqExecCalc(SEQ_WORK pSeqWork, BTL_DATA pMe)
{
btlseq.BattleLog("SeqExecCalc");
CMD_DATA cmdPtr = pSeqWork.CmdPtr;
UInt16 tar_id = cmdPtr.tar_id;
for (BTL_DATA next = FF9StateSystem.Battle.FF9Battle.btl_list.next; next != null; next = next.next)
{
if ((next.btl_id & tar_id) != 0)
{
btl_cmd.ExecVfxCommand(next); // Effect point
btl2d.Btl2dReq(next); // Figure point
}
}
pSeqWork.CurPtr++;
return 1;
}
I didn't test it but that should be ok.
The "Run Spell Animation" and "SFX" codes should give the hand to a generic "Spell Animation" and thus show the numbers every time. However, for both of them, it's not possible to have two different generic "Spell Animations" running at the same time.
case +1:
if ( 1 ) {
SetCharacterData( 8, 0, 255, 5, 7 ) <-- this one I made to not make Beatrix temporary and let the passive ability on
WindowSync( 0, 128, 175 )
if ( GetDialogChoice == 0 ) {
SetPartyReserve( 4095 )
SetCharacterData( 7, 0, 255, 5, 7 )
Party( 4, 0 )
UpdatePartyUI( )
} else {
if ( GetDialogChoice == 1 ) {
SetPartyReserve( 4095 )
SetCharacterData( 11, 0, 255, 21, 7 ) <-- Blank (I could not remove the temporary flag like Marcus and Cinna because if I remove it turns back in Amarant, Eiko and Quina.. I don't know why)
SetName( 11, 74 )
}
WindowSync( 0, 128, 176 )
if ( GetDialogChoice == 0 ) {
SetPartyReserve( 4095 )
SetCharacterData( 6, 1, 255, 21, 6 )
Party( 4, 0 )
UpdatePartyUI( )
} else {
if ( GetDialogChoice == 1 ) {
SetPartyReserve( 4095 )
SetCharacterData( 10, 1, 255, 21, 0 ) <--Marcus
SetName( 10, 73 )
}
WindowSync( 0, 128, 177 )
if ( GetDialogChoice == 0 ) {
SetPartyReserve( 4095 )
SetCharacterData( 5, 0, 255, 5, 5 )
Party( 4, 0 )
UpdatePartyUI( )
} else {
if ( GetDialogChoice == 1 ) {
SetPartyReserve( 4095 )
SetCharacterData( 9, 0, 255, 21, 5 ) <--Cinna
SetName( 9, 72 )
Party( 4, 0 )
UpdatePartyUI( )
}
}
}
}
} else {
Party( 0, 0 )
UpdatePartyUI( )
}
if ( IsInParty(5) ) {
set Setting_OptionalQuina = 1
}
break
}
double factor = Math.Abs(Math.Round(Math.Log((double)(this._v.Caster.CurrentHp / this._v.Caster.MaximumHp)), 2));
this._v.NormalMagicParams();
this._v.Caster.PenaltyMini();
this._v.Target.PenaltyShellAttack();
this._v.PenaltyCommandDividedAttack();
this._v.CasterCommand.BonusElement();
if (this._v.CanAttackMagic())
{
this._v.TargetCommand.CalcHpDamage();
this._v.TargetCommand.TryAlterMagicStatuses();
this._v.Target.HpDamage = (short)factor;
}
short hpDamage = (short)Math.Min(9999, this._v.Context.PowerDifference * (int)this._v.Context.EnsureAttack * factor);
public void Perform()
{
int factor = (int)Math.Abs(Math.Floor(Math.Log((double)this._v.Caster.CurrentHp / (double)this._v.Caster.MaximumHp)));
this._v.NormalMagicParams();
this._v.Caster.PenaltyMini();
this._v.Target.PenaltyShellAttack();
this._v.PenaltyCommandDividedAttack();
this._v.CasterCommand.BonusElement();
if (this._v.CanAttackMagic())
{
this._v.TargetCommand.CalcHpDamage();
this._v.TargetCommand.TryAlterMagicStatuses();
short hpDamage = (short)Math.Min(9999, this._v.Context.PowerDifference * (int)this._v.Context.EnsureAttack * factor);
this._v.Target.HpDamage = hpDamage;
}
}
for (BTL_DATA next3 = ff9Battle.btl_list.next; next3 != null; next3 = next3.next)
{
if (btl_util.getSerialNumber(next3) - 10 <= 1)
{
if (Status.checkCurStat(next3, BattleStatus.Petrify | BattleStatus.Venom | BattleStatus.Zombie | BattleStatus.Stop))
{
break;
}
if (btl_cmd.CheckSpecificCommand(next3, BattleCommandId.SysLastPhoenix))
{
return;
}
if (ff9item.FF9Item_GetCount(249) > Comn.random8())
{
UIManager.Battle.FF9BMenu_EnableMenu(true);
btl_cmd.SetCommand(next3.cmd[0], BattleCommandId.SysLastPhoenix, 73U, btl_scrp.GetBattleID(0U), 1U);
return;
}
}
}
ff9Battle.btl_seq = 1;
UIManager.Battle.SetBattleFollowMessage(5, new object[0]);
Hi there, I downloaded Hades Workshop a few days ago and have been feverishly using it to modify my copy of FFIX. It's absolutely amazing, intuitive and easy-to-use so first and foremost, thanks for this amazing piece of software!
Most of it is fairly self-explanatory and I've changed most of the game to my liking but there's one thing I can't seem to get right: adding new spells and abilities to character's commands.
For example, I've altered Dagger's and Eiko's Wht Mag commands to use different spells, and moved some of Vivi's status spells (Sleep, Slow, etc) into their Wht Mag commands. I've also created some new spells (like the Aero spells and extended Water spells) and integrated them into Vivi's Blk Mag command. It all seems to work in theory, as I've added AP costs, added them properly to equipment and assigned animations and damage formulas. When playing the game, the spells show up fine in the menu. And then the problem: the spells are not present in battle when selecting the right command, and I don't know how to fix this.
I've noticed that when highlighting the new spells, their category of 'Wht Mag' or 'Blk Mag' doesn't display in the Abilities screen, so clearly the category isn't being linked to the commands, but I don't know how to fix this.
Also (sorry I'm hopeless at coding and such, so apologies for the rambling nature of this), how do you extend the capacity of a command list? Whenever I try to add more spells to a command, it says I can't add any more (I'm trying to add Watera Sword and Waterga Sword to Steiner's Swd Mag ability, and there's no more room!)
And in the same vein, how do I go about creating a new animation for Watera Sword and Waterga Sword? (since there's only one Water Sword animation).
Any help you could offer would be fantastic!
03.08.2020 10:04:18 |W| [SoundLib] FF9SOUND_SNDEFFECTRES_SUSPEND: slot: 0 is null!
03.08.2020 10:04:18 |W| [SoundLib] FF9SOUND_SNDEFFECTRES_SUSPEND: slot: 1 is null!
03.08.2020 10:04:18 |E| [SoundLib] File not found AT path: Sounds/Sounds01/BGM_/music123.akb
03.08.2020 10:04:19 |M| InitializeBattleText
03.08.2020 10:04:19 |M| [assetInterceptor] loading from directory [C:\Program Files\Moguri Mod\StreamingAssets\]
03.08.2020 10:04:20 |M| [assetInterceptor] loading from directory [C:\Program Files\Moguri Mod\StreamingAssets\]
03.08.2020 10:04:20 |M| [assetInterceptor] loading from directory [C:\Program Files\Moguri Mod\StreamingAssets\]
03.08.2020 10:04:24 |E| [SoundData] Sound not found: 372
03.08.2020 10:04:31 |M| [GameLoopManager] RaiseQuitEvent
03.08.2020 10:04:18 |E| [SoundLib] File not found AT path: Sounds/Sounds01/BGM_/music123.akb
if ( turncounter < 10 ) {
set turncounter++
} else {
set finishfightflag = 1
}
if ( finishfightflag && ( !( #Matching(SV_PlayerTeam[STATUS_CURRENT_B], 64) ) ) ) {
set climhazzardwaiting = 1
set #( SV_Target = SV_PlayerTeam )
Attack( 5 )
return
}
if ( !endflag ) {
if ( #( SV_FunctionEnemy[HP] <=$ 10000 ) ) {
set finishfightflag = 1
}
if ( finishfightflag ) {
set SV_FunctionEnemy[HP] =$ FirstOf(SV_FunctionEnemy[MAX_HP])
set SV_FunctionEnemy[ATB] =$ FirstOf(SV_FunctionEnemy[MAX_ATB])
if ( climhazzardwaiting ) {
if ( #Matching(SV_PlayerTeam[STATUS_CURRENT_B], 64) ) {
set climhazzardwaiting = 0
set SV_FunctionEnemy[PREVENT_ATTACK] =$ 1
} else {
if ( GetAttacker == SV_FunctionEnemy ) {
if ( GetTarget && ( #( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 257) & NotMatching(SV_PlayerTeam[STATUS_CURRENT_B], 64) ) ) ) {
set endflag = 1
Wait( 5 )
if ( GetBattleState != 4 ) {
return
}
RunBattleCode( 32, 0 )
while ( GetBattleState != 1 ) {
Wait( 1 )
}
set #( SV_Target = SV_FunctionEnemy )
AttackSpecial( 7 )
while ( IsAttacking != 0 ) {
Wait( 1 )
}
RunBattleCode( 33, 1 )
return
}
}
}
} else {
if ( !( #Matching(SV_PlayerTeam[STATUS_CURRENT_B], 64) ) ) {
set SV_FunctionEnemy[PREVENT_ATTACK] =$ 1
}
}
}
}
set #( zidane = ( SV_PlayerTeam[MODEL_TYPE] ==$ 0 ) )
set #( zidane |= ( SV_PlayerTeam[MODEL_TYPE] ==$ 1 ) )
set #( vivi = ( SV_PlayerTeam[MODEL_TYPE] ==$ 2 ) )
set #( dagger = ( SV_PlayerTeam[MODEL_TYPE] ==$ 3 ) )
set #( dagger |= ( SV_PlayerTeam[MODEL_TYPE] ==$ 4 ) )
set #( dagger |= ( SV_PlayerTeam[MODEL_TYPE] ==$ 5 ) )
set #( dagger |= ( SV_PlayerTeam[MODEL_TYPE] ==$ 6 ) )
set #( steiner = ( SV_PlayerTeam[MODEL_TYPE] ==$ 7 ) )
set #( steiner |= ( SV_PlayerTeam[MODEL_TYPE] ==$ 8 ) )
set #( quina = ( SV_PlayerTeam[MODEL_TYPE] ==$ 9 ) )
set #( eiko = ( SV_PlayerTeam[MODEL_TYPE] ==$ 10 ) )
set #( eiko |= ( SV_PlayerTeam[MODEL_TYPE] ==$ 11 ) )
set #( freya = ( SV_PlayerTeam[MODEL_TYPE] ==$ 12 ) )
set #( amarant = ( SV_PlayerTeam[MODEL_TYPE] ==$ 13 ) )
set #( marcus = ( SV_PlayerTeam[MODEL_TYPE] ==$ 15 ) )
set #( ciblagepola = ( SV_PlayerTeam[MODEL_TYPE] ==$ 16 ) )
set #( ciblagepola |= ( SV_PlayerTeam[MODEL_TYPE] ==$ 17 ) )
set #( beatrix = ( SV_PlayerTeam[MODEL_TYPE] ==$ 18 ) )
allocate 51
global uint16 zidane VAR_GlobUInt16_24
global uint16 vivi VAR_GlobUInt16_26
global uint16 dagger VAR_GlobUInt16_28
global uint16 steiner VAR_GlobUInt16_30
global uint16 quina VAR_GlobUInt16_32
global uint16 eiko VAR_GlobUInt16_34
global uint16 freya VAR_GlobUInt16_36
global uint16 amarant VAR_GlobUInt16_38
global uint16 marcus VAR_GlobUInt16_40
global uint16 ciblagepola VAR_GlobUInt16_42
global uint16 beatrix VAR_GlobUInt16_44
local uint8 tranceflag VAR_LocUInt8_46
if ( !tranceflag ) {
set tranceflag = 1
if ( #( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 4419) & CHARACTER ) ) { <=== Choose your CHARACTER (from variables)
set #( SV_Target = CHARACTER ) <=== Choose your CHARACTER (from variables)
Attack( 4 ) <===== Use Attack which call Trance !
return
}
}
[Import]
Enabled = 1
Path = %StreamingAssets%
Text = 1
Audio = 1
Graphics = 1
Field = 0
[System]
StreamingAssets=C:\Program Files\Moguri Mod\StreamingAssets
Enabled=1
#HW newfunction 1
Function Beatrix_Loop
if ( !VAR_LocUInt8_33 ) {
set VAR_LocUInt8_33 = 1
while ( GetBattleState != 1 ) {
Wait( 1 )
set VAR_GenUInt8_206 = GetRandom
}
RunBattleCode( 35, 0 ) // Enable ATB
while ( GetBattleState != 4 ) {
Wait( 1 )
}
}
if ( !VAR_LocUInt8_30 ) {
if ( VAR_LocUInt8_31 ) {
set SV_FunctionEnemy[HP] =$ FirstOf(SV_FunctionEnemy[MAX_HP])
set SV_FunctionEnemy[ATB] =$ FirstOf(SV_FunctionEnemy[MAX_ATB])
if ( VAR_LocUInt8_38 ) {
if ( #Matching(SV_PlayerTeam[STATUS_CURRENT_B], 64) ) {
set VAR_LocUInt8_38 = 0
set SV_FunctionEnemy[PREVENT_ATTACK] =$ 1
} else {
if ( GetAttacker == SV_FunctionEnemy ) {
if ( GetTarget && ( #( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 257) & NotMatching(SV_PlayerTeam[STATUS_CURRENT_B], 64) ) ) ) {
set VAR_LocUInt8_30 = 1
Wait( 5 )
if ( GetBattleState != 4 ) {
return
}
RunBattleCode( 32, 0 ) // Disable ATB
while ( GetBattleState != 1 ) {
Wait( 1 )
}
set #( SV_Target = SV_FunctionEnemy )
AttackSpecial( 7 ) // Talk
while ( IsAttacking != 0 ) {
Wait( 1 )
}
RunBattleCode( 33, 1 ) // End Battle
return
}
}
}
} else {
if ( !( #Matching(SV_PlayerTeam[STATUS_CURRENT_B], 64) ) ) {
set SV_FunctionEnemy[PREVENT_ATTACK] =$ 1
}
}
}
}
Wait( 1 )
set #( VAR_GlobUInt16_24 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 0 ) )
set #( VAR_GlobUInt16_24 |= ( SV_PlayerTeam[MODEL_TYPE] ==$ 1 ) )
set #( VAR_GlobUInt16_26 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 2 ) )
set #( VAR_GlobUInt16_28 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 3 ) )
set #( VAR_GlobUInt16_28 |= ( SV_PlayerTeam[MODEL_TYPE] ==$ 4 ) )
set #( VAR_GlobUInt16_28 |= ( SV_PlayerTeam[MODEL_TYPE] ==$ 5 ) )
set #( VAR_GlobUInt16_28 |= ( SV_PlayerTeam[MODEL_TYPE] ==$ 6 ) )
set #( VAR_GlobUInt16_30 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 7 ) )
set #( VAR_GlobUInt16_30 |= ( SV_PlayerTeam[MODEL_TYPE] ==$ 8 ) )
set #( VAR_GlobUInt16_32 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 9 ) )
set #( VAR_GlobUInt16_34 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 10 ) )
set #( VAR_GlobUInt16_34 |= ( SV_PlayerTeam[MODEL_TYPE] ==$ 11 ) )
set #( VAR_GlobUInt16_36 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 12 ) )
set #( VAR_GlobUInt16_38 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 13 ) )
set #( VAR_GlobUInt16_40 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 15 ) )
set #( VAR_GlobUInt16_42 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 16 ) )
loop
#HW newfunction 5
Function Beatrix_ATB
set #( VAR_LocUInt16_43 = RandomInTeam(SV_PlayerTeam) )
if ( !VAR_LocUInt8_46 ) {
set VAR_LocUInt8_46 = 1
if ( #( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 4419) & VAR_GlobUInt16_36 ) ) {
set #( SV_Target = VAR_GlobUInt16_36 )
Attack( 0 ) // Trance Full
return
}
}
if ( !VAR_LocUInt8_47 ) {
set VAR_LocUInt8_47 = 1
set #( VAR_LocUInt16_43 = ( RandomInTeam(SV_PlayerTeam) & ( ~VAR_GlobUInt16_36 ) ) )
}
set VAR_LocInt24_15 = ( VAR_LocInt24_12 & 7 )
set VAR_LocInt24_24 = GetRandom
set VAR_LocInt24_27 = 128
set VAR_LocInt8_20 = ( VAR_LocUInt8_19 - 1 )
while ( VAR_LocInt8_20 >= 0 ) {
if ( VAR_LocInt24_24 > VAR_LocInt24_27 ) {
break
}
set VAR_LocInt24_27 >>= 1
set VAR_LocInt8_20--
}
if ( VAR_LocInt8_20 == 65535 ) {
set VAR_LocInt8_20 = ( VAR_LocUInt8_19 - 1 )
}
if ( VAR_LocInt8_20 == ( VAR_LocUInt8_19 - 1 ) ) {
set VAR_LocInt24_12 = ( ( VAR_LocInt24_12 >> 3 ) & 2097151L )
set VAR_LocInt24_12 |= ( VAR_LocInt24_15 << ( VAR_LocInt8_20 * 3 ) )
} else {
if ( VAR_LocInt8_20 ) {
set VAR_LocInt24_21 = ( VAR_LocInt24_15 << ( VAR_LocInt8_20 * 3 ) )
set VAR_LocInt24_24 = ( ( 1 << ( ( VAR_LocInt8_20 + 1 ) * 3 ) ) - 1 )
set VAR_LocInt24_27 = ( ( VAR_LocInt24_24 & VAR_LocInt24_12 ) >> 3 )
set VAR_LocInt24_27 |= VAR_LocInt24_21
set VAR_LocInt24_24 ^= 16777215L
set VAR_LocInt24_12 &= VAR_LocInt24_24
set VAR_LocInt24_12 |= VAR_LocInt24_27
}
}
set VAR_LocInt8_20 = VAR_LocUInt8_19
while ( VAR_LocInt8_20 >= 0 ) {
switch 8 ( VAR_LocInt24_15 ) from 0 {
case +0:
set #( SV_Target = RandomInTeam(SV_PlayerTeam) )
break
case +1:
set #( SV_Target = RandomInTeam(SV_PlayerTeam) )
break
case +2:
set #( SV_Target = RandomInTeam(SV_PlayerTeam) )
break
case +3:
set #( SV_Target = RandomInTeam(SV_PlayerTeam) )
break
case +4:
set #( SV_Target = RandomInTeam(SV_PlayerTeam) )
break
case +5:
set #( SV_Target = RandomInTeam(SV_PlayerTeam) )
break
case +6:
set #( SV_Target = RandomInTeam(SV_PlayerTeam) )
break
case +7:
set #( SV_Target = RandomInTeam(SV_PlayerTeam) )
}
if ( VAR_LocInt24_15 >= 4 ) {
set VAR_LocInt24_24 = ( ( VAR_LocInt24_9 >> ( ( VAR_LocInt24_15 - 4 ) * 6 ) ) & 63 )
} else {
set VAR_LocInt24_24 = ( ( VAR_LocInt24_6 >> ( VAR_LocInt24_15 * 6 ) ) & 63 )
}
set VAR_LocInt24_21 = ( #SV_Target )
set VAR_LocInt24_27 = FirstOf(SV_FunctionEnemy[MP])
if ( VAR_LocInt24_21 && ( VAR_LocInt24_24 <= VAR_LocInt24_27 ) ) {
break
}
if ( VAR_LocInt8_20 <= 0 ) {
break
}
set VAR_LocInt24_15 = ( VAR_LocInt24_12 & 7 )
set VAR_LocInt24_12 = ( ( VAR_LocInt24_12 >> 3 ) & 2097151L )
set VAR_LocInt24_12 |= ( VAR_LocInt24_15 << ( ( VAR_LocUInt8_19 - 1 ) * 3 ) )
set VAR_LocInt8_20--
}
if ( VAR_LocInt24_15 >= 4 ) {
set VAR_LocUInt8_18 = ( ( VAR_LocInt24_3 >> ( ( VAR_LocInt24_15 - 4 ) * 6 ) ) & 63 )
} else {
set VAR_LocUInt8_18 = ( ( VAR_LocInt24_0 >> ( VAR_LocInt24_15 * 6 ) ) & 63 )
}
if ( ( FirstOf(SV_FunctionEnemy[HP]) - 10000 ) < ( ( FirstOf(SV_FunctionEnemy[MAX_HP]) - 10000 ) >> 1 ) ) {
set #( VAR_LocUInt16_39 = SV_FunctionEnemy )
} else {
set #( VAR_LocUInt16_39 = 0 )
}
if ( ( #VAR_LocUInt16_39 ) && ( !VAR_LocUInt8_41 ) ) {
set VAR_LocUInt8_41 = 1
set #( SV_Target = SV_FunctionEnemy )
Attack( 1 ) // Cura
return
}
Attack( VAR_LocUInt8_18 )
return
Hey again,
Is anyone able to help with this? I've done everything else that I want with the mod, but still struggling on these ones I listed before.
I've basically added Aero, Aera, Aeroga, Watera, Waterga, Watera Sword and Waterga Sword to the Spell list. I've done all the integration work like assigning descriptions, damage calculations, elements, attack types and animations on the Spells tab (using the blank Void abilities under the main chunk), and I've also updated the Commands tab to integrate the new spells into Dagger's, Vivi's and Eiko's spell set. I've then altered the Stats tab to assign each ability an AP amount and sorted them to reflect the same order in the Commands tab, as well as tweaking the Inventory to make sure the characters can actually learn their new spells. Obviously, I can't add the new spells to Steiner's Swd Mag command as there is no more room.
The game starts fine and has all the tweaks I've done and when leaving Evil Forest after the introduction, I go into the menu with Zidane, Dagger, Steiner and Vivi. Equipping the right weapons allows my new spells to be seen (Dagger can now learn Aero from her standard Rod) and it all looks fine in the menu. It has the right MP cost I assigned and it is a learnable skills as it has AP which accrue after battle.
But the only issue is that when we do get into a battle, Aero does not show up in the command list, there's only Cure and Protect (the other abilities on the Rod). When highlighting 'Aero' in Dagger's Abilities tab in the Menu, usually the ability will flag up as 'Wht Mag' or 'Summon' in the upper part of the screen, but Aero displays nothing. Which I assume means the game doesn't recognise the new spell as being part of her abilities, but I don't know where I assign this in Hades workshop.
This is the main issue I'm stumbling on as I'm planning to add a few more spells to Quina's Blu Mag as well and if they don't show up in their commands properly, obviously there's little point.
On the same vein though, how do you increase a command's spell capacity? Simply because I can't even add Steiner's abilities as there's no more room in his Swd Mag command, and therefore, no way to link it to Vivi's Watera and Waterga spell in the Special tab.
And sorry again for rambling, but how do you create new Swd Mag animations? For the new Aero and Water spells, I've simply reused single-target and multi-target animations from other abilities as I'm not wanting any too extravagant. For Watera Sword and Waterga Sword, I simply want the same Swd Mag animation (Steiner running up and striking the enemy), just ending with a different Water animation from the pre-done effects. But the Spell Animations tab looks a lot more complicated than the rest of the program and I'm hopeless when it comes to coding.
Can anyone offer a hand in the right direction for any of these issues? I'd be eternally grateful!
Thanks!
13.08.2020 11:45:30 |M| [AssetManager] Asset not found: FieldMaps/FBG_N38_SDPL_MAP640_SP_RRO_0/spt.tcb
13.08.2020 11:45:30 |M| [AssetManager] Embeded asset not found: EmbeddedAsset/GeoTexAnimIndex/GEO_ACC_F0_FLR.csv
13.08.2020 11:45:30 |M| [AssetManager] Asset not found: Models/GeoTexAnim/GEO_ACC_F0_FLR.tab
13.08.2020 11:45:30 |M| [AssetManager] Embeded asset not found: EmbeddedAsset/GeoTexAnimIndex/GEO_ACC_F0_FLR.csv
13.08.2020 11:45:30 |M| [AssetManager] Asset not found: Models/GeoTexAnim/GEO_ACC_F0_FLR.tab
13.08.2020 11:45:30 |M| [AssetManager] Embeded asset not found: EmbeddedAsset/GeoTexAnimIndex/GEO_ACC_F0_FLR.csv
13.08.2020 11:45:30 |M| [AssetManager] Asset not found: Models/GeoTexAnim/GEO_ACC_F0_FLR.tab
13.08.2020 11:45:30 |M| [AssetManager] Embeded asset not found: EmbeddedAsset/GeoTexAnimIndex/GEO_ACC_F0_FLR.csv
13.08.2020 11:45:30 |M| [AssetManager] Asset not found: Models/GeoTexAnim/GEO_ACC_F0_FLR.tab
13.08.2020 11:45:30 |M| [AssetManager] Embeded asset not found: EmbeddedAsset/GeoTexAnimIndex/GEO_ACC_F0_FLR.csv
13.08.2020 11:45:30 |M| [AssetManager] Asset not found: Models/GeoTexAnim/GEO_ACC_F0_FLR.tab
13.08.2020 11:45:30 |M| [AssetManager] Embeded asset not found: EmbeddedAsset/GeoTexAnimIndex/GEO_ACC_F0_FLR.csv
13.08.2020 11:45:30 |M| [AssetManager] Asset not found: Models/GeoTexAnim/GEO_ACC_F0_FLR.tab
13.08.2020 11:45:30 |M| [AssetManager] Embeded asset not found: EmbeddedAsset/GeoTexAnimIndex/GEO_ACC_F0_FLR.csv
13.08.2020 11:45:30 |M| [AssetManager] Asset not found: Models/GeoTexAnim/GEO_ACC_F0_FLR.tab
13.08.2020 11:45:30 |M| [AssetManager] Embeded asset not found: EmbeddedAsset/GeoTexAnimIndex/GEO_ACC_F0_FLR.csv
13.08.2020 11:45:30 |M| [AssetManager] Asset not found: Models/GeoTexAnim/GEO_ACC_F0_FLR.tab
The code execution cannot proceed because MSVCP140.dll was not found. Reinstalling the program may fix this problem.
Function Freya_100
if (CustomVar_FreyaRiding) {
MoveInstantXZY( GetEntryPosX( Choco's entry ), GetEntryPosZ( Choco's entry ), GetEntryPosY( Choco's entry ) )
TurnInstant( GetEntryAngle( Choco's entry ) + 60 ) // 60 is an example there, adjust it
// Optional: have Freya's animation depend on the situation
// I don't know what to use to replace "Is Choco Running": you may use "IsButtonDown( 16 | 32 | 64 | 128 )"
// or write the XZY pos of choco in custom variables and compare the old/new position each frame
if ( Is Choco Running ) {
SetStandAnimation( Riding_Move ) // Animation of Freya when Choco moves
} else {
SetStandAnimation( Riding_Normal ) // Animation of Freya when Choco doesn't move
}
}
Wait( 1 )
loop
HadesWorkshop.exe - Application Error
The application was unable to start correctly(0xc000007b). Click OK to close the application.
It *might* be because of a deprotection patch that is applied to your german version of the game (Paradox patch).Thanks for the reply.
One of these compresses datas and make them impossible to edit with HW, although it should warn you when opening the game instead of bugging like that.
In any case, it is very strange that "Open -> FF9_German_CD1.bin -> Do changes in HW -> Export as PPF -> Apply that PPF with PPF-O-MATIC on FF9_German_CD1.bin" would lead to an error "Bin/block check fails" or such... A small part of the binary file is copied in the PPF when generating it with HW and it's then compared to the file you want to patch with PPF-O-MATIC, so there shouldn't be any difference whatever you did in HW...
I have worked with the german version of the PSX game, but never did a HW update specifically for that version for what I remember...
Directory: C:\Users\pc\Downloads\HadesWorkshop
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 9/29/2020 1:27 AM msvcp140
-a---- 9/29/2020 6:22 AM 0 files.txt
-a---- 9/20/2020 3:21 PM 39609 HadesWorkshop.conf
-a---- 9/20/2020 3:21 PM 42273792 HadesWorkshop.exe
-a---- 9/20/2020 3:21 PM 6919640 libfbxsdk.dll
-a---- 9/20/2020 3:21 PM 294931 LocalVariableSettings_v1.hws
-a---- 9/29/2020 6:21 AM 590096 msvcp140.dll
-a---- 9/20/2020 3:21 PM 1526976 ucrtbased.dll
-a---- 9/20/2020 3:21 PM 2134528 wxbase31u_vc_custom.dll
-a---- 9/20/2020 3:21 PM 143360 wxbase31u_xml_vc_custom.dll
-a---- 9/20/2020 3:21 PM 1350144 wxmsw31u_adv_vc_custom.dll
-a---- 9/20/2020 3:21 PM 441344 wxmsw31u_aui_vc_custom.dll
-a---- 9/20/2020 3:21 PM 5010944 wxmsw31u_core_vc_custom.dll
-a---- 9/20/2020 3:21 PM 75776 wxmsw31u_gl_vc_custom.dll
-a---- 9/20/2020 3:21 PM 605696 wxmsw31u_html_vc_custom.dll
-a---- 9/20/2020 3:21 PM 1512448 wxmsw31u_richtext_vc_custom.dll
pc@laptop /cygdrive/c/Users/pc/Downloads/HadesWorkshop
$ sha256sum *
16b8f2cc0647648a86a86c2a62e5bbf226f23d94f50a6b7695f9904e977e7c64 *files.txt
466a8e172708a14f526c1da86395a4e9b50456211580065617835a7a553df078 *HadesWorkshop.conf
f0bdace03cd9adb7b1089e425603d7e6904272d138099d2c6e890eaf7dbc4ebc *HadesWorkshop.exe
2dae86a328f4852380ae5f8361badaac562d1c0c72e07d2c781950891d83eedc *libfbxsdk.dll
a81208bf8cf41b8299925855b403a314415bc309f9344b06a61ba1961b87cde7 *LocalVariableSettings_v1.hws
sha256sum: msvcp140: Is a directory
a2cb9cae4b86468ca44ba36320814a204ec8ad311df624b94e12c47e328e2726 *msvcp140.dll
c8fda4b882281f5a4d921416c1f565eddbdd552ef782a32380e0975fcc2696c1 *ucrtbased.dll
313f87259aa568811f2a63fac3e308b8f661dd623317ea655d027e67314443df *wxbase31u_vc_custom.dll
ad5a595cfb4043d3334420fd71adc89c262a0b1c87ec5660d825a3d29f3c2080 *wxbase31u_xml_vc_custom.dll
e44b11ad1de31c2e123bb04dd9d038ddc07b071df3f83cf9c4ee55c856dde3c7 *wxmsw31u_adv_vc_custom.dll
205c3ae91377b9b2c303f7faa947a4978b308c09711ac26a8c03a29cd54d2ac9 *wxmsw31u_aui_vc_custom.dll
7626628b10f75bc999dbc66190c0832cabf118ede7babc06e419ad3125e72a55 *wxmsw31u_core_vc_custom.dll
091e0c4c7a362d8bbe9d2828c38ddc9d49b260ad822aede7a94daffb67c1226b *wxmsw31u_gl_vc_custom.dll
6f566491714e46ad38c4a02b60ee584a20414475a75bd486dece521e0b8c52cf *wxmsw31u_html_vc_custom.dll
44174abf00f498b2ae83827206dd4d9a961efa6ed8d37b7e37ae34f9731e2926 *wxmsw31u_richtext_vc_custom.dll
Hello,
I would like to ask if there is a way to edit Ragtime Mouse's counter of right & wrong answers.
I've unknowingly kept going and saved after giving a wrong answer the first time I met it, so I'd like to avoid having to start the game from the beginning for this sole reason.
Thanks!
No nicolo.sesta, sorry. I don't look at the PSX version anymore and don't know where other MIPS codes are.
Yes, but not with Hades, because it's a matter of your savefile, not the game values.
Try with some Cheat Engine you can find online.
Function False_CounterEx
// ...
if ( 27789 & ( 1 << VAR_GlobUInt8_31 ) ) {
set VAR_GlobUInt8_32 = 4 // Correct answer
} else {
set VAR_GlobUInt8_32 = 6 // Wrong answer
}
"27789" is a bit flag, that is, its meaning appears when writing that number in base 2:About Ragtime's rights and wrongs, the answers are stored in the AI script, in the form of a bit flag:Code: [Select]Function False_CounterEx
"27789" is a bit flag, that is, its meaning appears when writing that number in base 2:
// ...
if ( 27789 & ( 1 << VAR_GlobUInt8_31 ) ) {
set VAR_GlobUInt8_32 = 4 // Correct answer
} else {
set VAR_GlobUInt8_32 = 6 // Wrong answer
}
27789 [base 10]
110110010001101 [base 2]
Thus the 1st, 3rd, 4th, 8th questions... (read the number in base 2 from right to left) must be answered False to be correctly answered. There's a symmetric code in "Function True_CounterEx".
set VAR_GlobUInt8_0 = Ragtime_QuizzSuccess >> 3
set VAR_GlobUInt8_0++
set Ragtime_QuizzSuccess = ( ( Ragtime_QuizzSuccess & 7 ) | ( VAR_GlobUInt8_0 << 3 ) )
In any field script, add these lines somewhere that is ran once (start of "Main_Init" function for instance):Code: [Select]set VAR_GlobUInt8_0 = Ragtime_QuizzSuccess >> 3
set VAR_GlobUInt8_0++
set Ragtime_QuizzSuccess = ( ( Ragtime_QuizzSuccess & 7 ) | ( VAR_GlobUInt8_0 << 3 ) )
Then parse the script, generate and install the mod, go in-game to the field that was modified, leave it and save (or save inside that field without leaving it), close the game, uninstall the mod and that should be it.
This will increase the number of questions you answered correctly without touching the list of questions you answered (right or wrong). If you enter the field more than once, you'll get more correct answers, potentially getting more correct answers than the total number of questions encountered (I guess it would display a score higher than 100% and still consider it as a 100%).
I am not sure if you can edit the save file using the Memoria Save Editor for that because it's a general variable involved, so better do it with HW.
set VAR_GlobUInt8_0 = Ragtime_QuizzSuccess >> 3
set VAR_GlobUInt8_0++
set Ragtime_QuizzSuccess = ( ( Ragtime_QuizzSuccess & 7 ) | ( VAR_GlobUInt8_0 << 3 ) )
SetTextVariable( 2, VAR_GlobUInt8_0 )
WindowSync( 6, 0, 68 )
This will display a message box in-game in addition to increasing the variable. You will see how many success you're at after the increase. If you don't see it, that means the script has not been modified for any of the reasons above.About custom supporting abilities, they can be modified in the Steam version but not with Hades Workshop (to be exact, it is very tedious and limited with Hades Workshop), because they are way too intertwined with the rest of the game's code. The modification of supporting ability effects is a feature of the Memoria Engine modifier, which is also installed automatically if you have the Moguri mod. Open the file "FINAL FANTASY IX\StreamingAssets\Data\Characters\Abilities\AbilityFeatures.txt (https://github.com/Albeoris/Memoria/blob/main/Memoria.Patcher/StreamingAssets/Data/Characters/Abilities/AbilityFeatures.txt)". Read the documentation, the examples and the way vanilla abilities are coded there to know how to modify things.
WindowSyncEx( 2, 0, 128, 357 ) // "Old Woman “Wow, I can’t believe it... Here’s your prize.”"
if ( 0 ) {
// ...
// Code for receiving gil, but unused since the reward is not gil
} else {
if ( ( ( GetItemCount(557) < 99 ) && 0 ) || ( 1 && ( GetCardAmount < 100 ) ) ) {
if ( VARL_GenBool_7347 == 0 ) {
RunSoundCode3( 53248, 108, 0, -128, 125 )
set VARL_GenBool_7347 = 1
SetTextVariable( 0, 557 ) // Tonberry
if ( 0 ) {
AddItem( 557, 1 ) // Code for receiving an item, unused
WindowSync( 7, 0, 56 )
} else {
if ( 1 ) {
AddItem( 557, 1 ) // Tonberry
WindowSync( 7, 0, 57 ) // " Received [Tonberry] Card! "
} else {
// Another unused code
}
}
}
} else {
SetTextVariable( 0, 557 ) // Tonberry
if ( 0 ) {
WindowSync( 7, 0, 60 ) // " Cannot carry another [Tonberry]. "
} else {
WindowSync( 7, 0, 61 ) // " Cannot hold more Cards. "
}
}
}
You need to change that "557" into something else everywhere it appears there.RunBattleCode( 37, 2901 )
Or at the end of the function "Vivi_Loop" of the field "Ending/AT":Field( 2901 )
You may also put the variable "General_ScenarioCounter" back to some early value, like "11100" (the line "set General_ScenarioCounter = 11100" should bring you back to the situation of the start of the disc 4, so you'll fight the bosses again).
Function Main_Init
set VAR_GlobBool_159 = 0
set VAR_GlobUInt8_17 = 255
set VAR_GenBool_191 = 0
if ( General_LoadedGame == 1 ) { set General_LoadedGame = 0
>SA 63 Soothing Petals
StatusInit AutoStatus Regen
Ability AsTarget WhenBattleScriptEnd
[code=Condition] HPDamage >= TargetHP && TargetHP >= TargetMaxHP / 50 && (EffectTargetFlags & 3) == 1
&& CasterIsPlayer != TargetIsPlayer
[code=TargetHP] 1 [/ code]
@FomaX:
1) There are 3 types of variable, "local" variables are local to an entry (they are shared between eg. "Blank_Init" and "Blank_Loop" but not between "Blank_Init" and "Marcus_Init"), "global" variables are local to a script (so all the functions of the same field or world map or battle share them), and "general" variables are shared by everything and are also saved in save files.
2) Somehow yes. The overall system is quite complicated but it's mainly coded in EventEngine.cs (https://github.com/Albeoris/Memoria/blob/main/Assembly-CSharp/Global/Event/Engine/EventEngine.DoEventCode.cs).
3) The problem is that doing so will change the format of save files, thus provoking compatibility issues. If I try to do that, I'll search for a way to have save compatibility backward and forward (= you can use non-Memoria saves after installing Memoria + you can use Memoria saves after deinstalling Memoria).
4) Since "General_LoadedGame" is a general variable, it can be set to 1 in another script or be 1 in the player's save. For this variable in particular, I think it is set everytime the player has a chance to save, like "set General_LoadedGame = 1 ... Menu( Save ) ... set General_LoadedGame = 0".
@ChikoLad: That's a tough one. Your code looks fine except that setting the target's HP to 1 will not prevent the damage to apply and thus still kill the character. You can either add a code "[ code = HPDamage ] 0 [ /code ]" or replace the setting of HP by a change of the damage "[ code = HPDamage ] TargetHP - 1 [ /code ]".
This system wouldn't prevent a "Death" spell or a tick from poison / venom (as they are not damaging through an ability cast). You could add a way to prevent "Death" but the poison / venom tick seems impossible to prevent this way... (although the Regen effect would make it hard to die from poison).
More importantly, I don't see any way to extend any of the two effects to all allies. You can't currently check if an ally has a SA equipped. I'll try to add that kind of features at some point.
No, I don't have a patreon and I don't plan on receiving donations for my work in modding. In my opinion, everyone should earn a revenue high enough to live a decent life and possibly work toward their passions. I see donations somehow as a wooden leg trying to compensate for the lack of institutional will toward the rewarding of passion works and securing a decent life for everyone.
Since I am not in need myself and can afford to not use that wooden leg, I prefer not to and hope for a more satisfying framework.
I don't know.Sure, thanks!
Do you want to share your .hws so I can check it?
Ok...But I read many people that changed it on this thread, how they did?
The world map "Places" and "Battle Spots" sub-panels bug.
Don't change anything in them. I need to fix that...
Thanks for warning, elberuss. I didn't think I would need to update this tool anymore. That adds to my todo-list.
It used to work correctly. I don't know why it doesn't work anymore. Maybe I changed something when moving to a format that is both compatible with the PSX and the PC versions of the game, maybe it's something else... I'll have to check.Thanks so much for your effort! really thaks! FFIX alwais was my liked game from my childhood and I love modding on it :)
On the same vibe, changing the script of "Opening-for-FMV" tends to create bugs, so that's also something to avoid with the current version.
First of all thank you for this amazing tool.
I am here to ask some help for a very little problem that has FF9 italian steam version: during a battle, when you choose to use magic sword ability (the Steiner+Vivi combo :)), the text that appears in the top of the screen with the ability name has the words swapped. Here an example:
You choose Firaga Sword (in italian is "Colpo Firaga" and in hades workshop is named perfectly), in the top screen appears as "Firaga Colpo" (maybe use english order with italian text?)
My question is: is it possible to fix with hades workshop or with some manual edit?
Thanks usb :)
Yeah, I thought that they fixed that bug, but apparently not. It doesn't concern only Italian but also French and Spanish. The bug lies in the CIL method "BattleHUD::SetBattleCommandTitle" but it's a bit tricky to fix it there with HW.
What you can do though is bypass the bug: go to the "Interface" panel, select the "Battle Spell Naming" field and add 13 entries to it (right-click -> Add), then write the proper full names ("Colpo Fire" etc...). Finally, go to the "Party -> Spells" panel and change the casting names of the magic swords spells to the entries that you just added.
It's a bit dirty as a fix, but it works. You should also translate the names in the "Interface" panel if you want it to work for all the languages (I think the game would crash in non-italian language otherwise).
For info, you can have up to 62 custom spell names in that interface field.
text = FF9TextTool.ActionAbilityName((int)pCmd.sub_no) + str + FF9TextTool.BattleCommandTitleText(0);
string locale = Localization.GetSymbol();
if (locale == "IT" || locale == "ES" || locale == "FR")
text = FF9TextTool.BattleCommandTitleText(0) + FF9TextTool.ActionAbilityName((int)pCmd.sub_no);
else
text = FF9TextTool.ActionAbilityName((int)pCmd.sub_no) + str + FF9TextTool.BattleCommandTitleText(0);
HW is quite sensible to mods, even those it generates itself. Other than that, there should be no problem. It used to scan correctly the japanese, US, UK, french, italian, german and spanish PSX images; I don't have copies of them anymore to thoroughly check but it still scans correctly at least the US version.
When it scans a game successfully, it generates a "Final Fantasy IX (Disc 1).hwf" file next to your PSX image that contains the results of the scan so you don't need to do that anymore next time.
So I guess you are trying to open a modded version of a PSX image. If you know which mod it is and you can remove it (eg. it's a .ppf with an "undo" feature), do that then open it with HW. In many cases, HW will then generate a .hwf that you can use even after re-applying the mod (close HW, re-apply the mod but keep the .hwf next to the game and with the same name, then re-open the PSX image with HW).
If you don't know what mod your game has, you'll have to get another version of the PSX image first, one that is not modded or only very slightly modded. If you're using the US version, I can share .hwf files as well; hopefully they'll work.
@akirat9: Here (https://www.dropbox.com/s/71uhlik7bv0q5jv/FF9%20HWF.zip?dl=1) they are.
@carl09876: About item/card steals/drops, mostly no. These are hardcoded in the battle code, which is MIPS in the PSX version and CIL/C# in the Steam version. I guess you can try changing the steal % of each item slot on the PSX version in the MIPS panel (with a bit of luck, these "256/64/16/1" pourcentages are written plainly in the code, so you'd just have to change these figures, even though it will change the rates for all the enemies). If you are on the Steam version, then you can change the code of the Steal script (https://github.com/Albeoris/Memoria/blob/main/Memoria.Scripts/Sources/Battle/0058_StealScript.cs#L56) for this kind of result (check out the documentations on how to use Memoria). It is actually not a bad idea to add fields to change these % chances; I'll see what I can do for the next version of Memoria.
When you add/remove an enemy to a group, make sure to change the script accordingly (Edit Script -> function Main_Init -> make sure that the "InitObject" lines match with the changes you made).
The corruption of .hws files happen when you try to modify the script of the field "Opening-for FMV" or when you change something in the panels "Environment -> World Maps -> Place Names" and "Environment -> World Maps -> Battle Spots". I am currently working on an update of HW that will fix that bug amongst other things.
@Trilititi helooo ??? fucking answer you dick , this bullshit about ignore people's messages must end once and for all
Function Region16_Range
if ( VAR_GlobBool_1 == 0 ) {
SetTextVariable( 0, 1 )
WindowAsync( 0, 4, 9 )
set VAR_GlobBool_1 = 1
}
return
Function Code1_Loop
if ( VAR_GlobBool_1 == 1 ) {
set VAR_GlobUInt8_1++
}
if ( VAR_GlobUInt8_1 == 59 ) {
set VAR_GlobBool_1 = 0
set VAR_GlobUInt8_1 = 0
}
Wait( 1 )
loop
[STRT=160,1][TAIL=LOC][IMME]press x to go to[WDTH=0,160,6,0,-1][TEXT=0,0][TIME=60]
if anyone know if there is a better way, im glad to read.Function World_Moogle_27
RunWorldCode( 35, 1 )
set VAR_LocUInt8_20 = GetData_199
set VAR_LocUInt8_19 = GetRandom
set VAR_LocUInt8_0 = ( 192 - ( VAR_LocUInt8_20 + VAR_LocUInt8_19 ) )
TurnInstant( Op60(ObjectUID_250) )
set VAR_LocUInt8_21 = 1
set VAR_LocUInt8_22 = 0
while ( VAR_LocUInt8_22 < 10 ) {
set VAR_LocInt24_1 = ( ( Cos(VAR_LocUInt8_0) * 2 ) + ( ( ( Cos(VAR_LocUInt8_0) * 4 ) - ( Cos(VAR_LocUInt8_0) * 2 ) ) / VAR_LocUInt8_21 ) )
set VAR_LocInt24_4 = ( ( Sin(VAR_LocUInt8_0) * 2 ) + ( ( ( Sin(VAR_LocUInt8_0) * 4 ) - ( Sin(VAR_LocUInt8_0) * 2 ) ) / VAR_LocUInt8_21 ) )
MoveInstantXZY( GetEntryPosX(250) + VAR_LocInt24_1, GetEntryPosZ(255), GetEntryPosY(250) + VAR_LocInt24_4 )
set VAR_LocUInt8_21 = ( VAR_LocUInt8_21 + 1 )
if ( VAR_LocUInt8_22 == 0 ) {
MoveInstantXZY( GetEntryPosX(250) + VAR_LocInt24_1, 2000, GetEntryPosY(250) + VAR_LocInt24_4 )
} else {
SetObjectFlags( 7 )
}
Wait( 1 )
set VAR_LocUInt8_22++
}
set VAR_LocInt24_1 = ( Cos(VAR_LocUInt8_0) * 2 )
set VAR_LocInt24_4 = ( Sin(VAR_LocUInt8_0) * 2 )
MoveInstantXZY( GetEntryPosX(250) + VAR_LocInt24_1, GetEntryPosZ(255), GetEntryPosY(250) + VAR_LocInt24_4 )
SetObjectFlags( 7 )
set VAR_LocInt24_7 = ( Cos(VAR_LocUInt8_0) / 3 )
set VAR_LocInt24_10 = ( Sin(VAR_LocUInt8_0) / 3 )
RunScriptAsync( 4, 4, 34 )
InitWalk( )
Walk( GetEntryPosX(250) + VAR_LocInt24_7, GetEntryPosY(250) + VAR_LocInt24_10 )
SetWalkSpeed( 60 )
RunScriptAsync( 4, 4, 35 )
TurnInstant( GetEntryAngle(7) - 64 )
RunAnimation( 6151 )
set VAR_LocInt24_13 = ( Cos(VAR_LocUInt8_0) / 8 )
set VAR_LocInt24_16 = ( Sin(VAR_LocUInt8_0) / 8 )
InitWalk( )
Walk( GetEntryPosX(250) + VAR_LocInt24_13, GetEntryPosY(250) + VAR_LocInt24_16 )
set VAR_LocInt8_25 = 0
while ( VAR_LocInt8_25 >= 0 ) {
RunWorldCode( 16, 6 )
RunWorldCode( 17, 126 )
RunWorldCode( 20, 0 )
WindowAsync( 5, 4, 42 )
do {
Wait( 1 )
} while ( !IsButton(196608L) )
CloseWindow( 5 )
if ( ( GetDialogChoice == 3 ) && IsButton(131072L) ) {
RunWorldCode( 16, 39 )
RunWorldCode( 17, 126 )
RunWorldCode( 20, 0 )
}
switch 4 ( GetDialogChoice ) from 0 {
case +0:
set VAR_LocUInt8_24 = 0
RunWorldCode( 16, 39 )
RunWorldCode( 17, 126 )
RunWorldCode( 20, 0 )
WindowAsync( 5, 4, 43 )
do {
Wait( 1 )
} while ( !IsButton(196608L) )
CloseWindow( 5 )
if ( ( GetDialogChoice == 1 ) && IsButton(131072L) ) {
RunWorldCode( 16, 39 )
RunWorldCode( 17, 126 )
RunWorldCode( 20, 0 )
}
switch 2 ( GetDialogChoice ) from 0 {
case +0:
RunWorldCode( 16, 5 )
RunWorldCode( 17, 126 )
RunWorldCode( 20, 0 )
WindowSync( 5, 4, 45 )
while ( GetData_200 ) {
Wait( 1 )
}
RunWorldCode( 39, 0 )
Menu( 4, 0 )
RunWorldCode( 40, 0 )
set VAR_LocUInt8_23 = 2
break
case +1:
set VAR_LocUInt8_23 = 1
break
}
break
case +1:
set VAR_LocUInt8_24 = 0
RunWorldCode( 16, 39 )
RunWorldCode( 17, 126 )
RunWorldCode( 20, 0 )
set VAR_GlobUInt8_42 = GetItemCount(253)
if ( !VAR_GlobUInt8_42 ) {
WindowSync( 5, 4, 46 )
} else {
SetTextVariable( 1, VAR_GlobUInt8_42 )
WindowAsync( 5, 4, 44 )
do {
Wait( 1 )
} while ( !IsButton(196608L) )
CloseWindow( 5 )
if ( ( GetDialogChoice == 1 ) && IsButton(131072L) ) {
RunWorldCode( 16, 39 )
RunWorldCode( 17, 126 )
RunWorldCode( 20, 0 )
}
switch 2 ( GetDialogChoice ) from 0 {
case +0:
RemoveItem( 253, 1 )
RunScriptAsync( 5, 4, 37 )
FadeFilter( 2, 24, 0, 255, 255, 255 )
Wait( 25 )
RunScriptAsync( 5, 7, 38 )
RunScriptAsync( 5, 250, 38 )
RunScriptSync( 5, 10, 40 )
FadeFilter( 3, 16, 0, 0, 0, 0 )
Wait( 40 )
FadeFilter( 2, 24, 0, 255, 255, 255 )
Wait( 25 )
RunScriptAsync( 5, 10, 41 )
RunScriptAsync( 5, 7, 39 )
RunScriptSync( 5, 250, 39 )
FadeFilter( 3, 16, 0, 0, 0, 0 )
Wait( 20 )
set VAR_LocUInt8_23 = 2
break
case +1:
set VAR_LocUInt8_23 = 1
break
}
}
break
case +2:
WindowAsync( 5, 4, 90 )
do {
Wait( 1 )
} while ( !IsButton(196608L) )
CloseWindow( 5 )
if ( ( GetDialogChoice == 1 ) && IsButton(131072L) ) {
RunWorldCode( 16, 39 )
RunWorldCode( 17, 126 )
RunWorldCode( 20, 0 )
}
//Dialog Option starts here
switch 2 ( GetDialogChoice ) from 0 {
case +0:
set VAR_LocInt24_2 = 0
set VAR_LocInt24_5 = 1
set VAR_LocInt24_6 = 0
SetTextVariable( 5, VAR_LocInt24_2 )
SetTextVariable( 6, VAR_LocInt24_5 )
SetTextVariable( 4, General_ScenarioCounter )
WindowAsync( 5, 4, 10 )
do {
if ( IsButton(16) ) {
if ( VAR_LocInt24_5 == 1000 ) {
set VAR_LocInt24_5 = 1000
}
if ( VAR_LocInt24_5 == 100 ) {
set VAR_LocInt24_5 = 1000
}
if ( VAR_LocInt24_5 == 10 ) {
set VAR_LocInt24_5 = 100
}
if ( VAR_LocInt24_5 == 1 ) {
set VAR_LocInt24_5 = 10
}
SetTextVariable( 6, VAR_LocInt24_5 )
}
if ( IsButton(64) ) {
if ( VAR_LocInt24_5 == 1 ) {
set VAR_LocInt24_5 = 1
}
if ( VAR_LocInt24_5 == 10 ) {
set VAR_LocInt24_5 = 1
}
if ( VAR_LocInt24_5 == 100 ) {
set VAR_LocInt24_5 = 10
}
if ( VAR_LocInt24_5 == 1000 ) {
set VAR_LocInt24_5 = 100
}
SetTextVariable( 6, VAR_LocInt24_5 )
}
if ( IsButton(128) ) {
set VAR_LocInt24_2 = ( VAR_LocInt24_2 - VAR_LocInt24_5 )
SetTextVariable( 5, VAR_LocInt24_2 )
}
if ( IsButton(32) ) {
set VAR_LocInt24_2 = ( VAR_LocInt24_2 + VAR_LocInt24_5 )
SetTextVariable( 5, VAR_LocInt24_2 )
}
if ( IsButton(8) ) {
set General_ScenarioCounter = VAR_LocInt24_2
}
Wait( 1 )
} while ( !IsButton(196608L) )
break
case +1:
set VAR_LocInt24_2 = 0
set VAR_LocInt24_5 = 1
set VAR_LocInt24_6 = 0
SetTextVariable( 5, VAR_LocInt24_2 )
SetTextVariable( 6, VAR_LocInt24_5 )
WindowAsync( 5, 4, 9 )
do {
if ( IsButton(16) ) {
if ( VAR_LocInt24_5 == 1000 ) {
set VAR_LocInt24_5 = 1000
}
if ( VAR_LocInt24_5 == 100 ) {
set VAR_LocInt24_5 = 1000
}
if ( VAR_LocInt24_5 == 10 ) {
set VAR_LocInt24_5 = 100
}
if ( VAR_LocInt24_5 == 1 ) {
set VAR_LocInt24_5 = 10
}
SetTextVariable( 6, VAR_LocInt24_5 )
}
if ( IsButton(64) ) {
if ( VAR_LocInt24_5 == 1 ) {
set VAR_LocInt24_5 = 1
}
if ( VAR_LocInt24_5 == 10 ) {
set VAR_LocInt24_5 = 1
}
if ( VAR_LocInt24_5 == 100 ) {
set VAR_LocInt24_5 = 10
}
if ( VAR_LocInt24_5 == 1000 ) {
set VAR_LocInt24_5 = 100
}
SetTextVariable( 6, VAR_LocInt24_5 )
}
if ( IsButton(128) ) {
set VAR_LocInt24_2 = ( VAR_LocInt24_2 - VAR_LocInt24_5 )
SetTextVariable( 5, VAR_LocInt24_2 )
}
if ( IsButton(32) ) {
set VAR_LocInt24_2 = ( VAR_LocInt24_2 + VAR_LocInt24_5 )
SetTextVariable( 5, VAR_LocInt24_2 )
}
if ( IsButton(8) ) {
Field( VAR_LocInt24_2 )
}
Wait( 1 )
} while ( !IsButton(196608L) )
break
}
break
case +3:
switch 2 ( VAR_LocUInt8_23 ) from 1 {
case +0:
WindowAsync( 5, 4, 47 )
break
case +1:
WindowAsync( 5, 4, 48 )
break
default:
if ( VAR_LocUInt8_24 < 8 ) {
WindowAsync( 5, 4, 50 )
} else {
if ( VAR_LocUInt8_24 == 8 ) {
WindowAsync( 5, 4, 51 )
} else {
if ( VAR_LocUInt8_24 == 12 ) {
WindowAsync( 5, 4, 52 )
} else {
if ( VAR_LocUInt8_24 >= 16 ) {
WindowAsync( 5, 4, 49 )
} else {
WindowAsync( 5, 4, 50 )
}
}
}
}
break
}
if ( ( !VAR_LocUInt8_23 ) && ( VAR_LocUInt8_24 < 32 ) ) {
set VAR_LocUInt8_24 = ( VAR_LocUInt8_24 + 1 )
}
RunScriptSync( 5, 7, 42 )
set VAR_LocInt8_25 = 65535
set VAR_LocUInt8_23 = 0
break
}
Wait( 1 )
}
return
[STRT=167,5][TAIL=DEFT][WDTH=0,61,64,0,64,1,-1][IMME][D06050][HSHD] [C8B040][HSHD]Set Field()
[68C0D8][HSHD]New=[NUMB=5], Increment=[NUMB=6]
[DBTN=START]: Overwrite[TIME=-1]
[STRT=167,5][TAIL=DEFT][WDTH=0,61,64,0,64,1,-1][IMME][D06050][HSHD] [C8B040][HSHD]Set Scenario Counter()
[68C0D8][HSHD]Old=[NUMB=4], New=[NUMB=5], Increment=[NUMB=6]
[DBTN=START]: Overwrite[TIME=-1]
[STRT=136,3][TAIL=UPC][PCHC=2,1][IMME]Debug?
[CHOO][MOVE=18,0]Scenario Counter
[MOVE=18,0]Field[TIME=-1]
Function YoungWomanB_SpeakBTN
ifnot ( IsMovementEnabled ) {
return
}
set VAR_GlobBool_158 = 0
if ( VAR_GlobBool_159 == 1 ) {
DisableMove( )
if ( VAR_GlobBool_144 == 0 ) {
DisableMenu( )
} else {
Wait( 1 )
}
}
SetTriangleFlagMask( 127 )
WaitTurn( )
set VAR_GlobUInt8_16 = GetEntryAngle(255)
TurnTowardObject( 250, 32 )
WaitTurn( )
WindowSync( 5, 2, 2 )
switch 1 ( GetDialogChoice ) from 0 {
case +0:
set VAR_GlobInt16_6 = 0
set VAR_GlobInt16_4 = 1
set VAR_GlobBool_21 = 0
SetTextVariable( 4, VAR_GlobBool_21 )
SetTextVariable( 5, VAR_GlobInt16_6 )
SetTextVariable( 6, VAR_GlobInt16_4 )
WindowAsync( 5, 4, 3 )
do {
if ( IsButton(16) ) {
if ( VAR_GlobInt16_4 == 1000 ) {
set VAR_GlobInt16_4 = 1000
}
if ( VAR_GlobInt16_4 == 100 ) {
set VAR_GlobInt16_4 = 1000
}
if ( VAR_GlobInt16_4 == 10 ) {
set VAR_GlobInt16_4 = 100
}
if ( VAR_GlobInt16_4 == 1 ) {
set VAR_GlobInt16_4 = 10
}
SetTextVariable( 6, VAR_GlobInt16_4 )
}
if ( IsButton(64) ) {
if ( VAR_GlobInt16_4 == 1 ) {
set VAR_GlobInt16_4 = 1
}
if ( VAR_GlobInt16_4 == 10 ) {
set VAR_GlobInt16_4 = 1
}
if ( VAR_GlobInt16_4 == 100 ) {
set VAR_GlobInt16_4 = 10
}
if ( VAR_GlobInt16_4 == 1000 ) {
set VAR_GlobInt16_4 = 100
}
SetTextVariable( 6, VAR_GlobInt16_4 )
}
if ( IsButton(128) ) {
set VAR_GlobInt16_6 = ( VAR_GlobInt16_6 - VAR_GlobInt16_4 )
SetTextVariable( 5, VAR_GlobInt16_6 )
}
if ( IsButton(32) ) {
set VAR_GlobInt16_6 = ( VAR_GlobInt16_6 + VAR_GlobInt16_4 )
SetTextVariable( 5, VAR_GlobInt16_6 )
}
if ( IsButton(8) ) {
if ( VAR_GlobBool_21 == 0 ) {
set VAR_GlobBool_21 = 1
SetTextVariable( 4, VAR_GlobBool_21 )
} else {
set VAR_GlobBool_20 = 0
SetTextVariable( 4, VAR_GlobBool_21 )
}
}
Wait( 1 )
} while ( ( !IsButton(196608L) ) )
break
default:
break
}
Wait( 5 )
if ( VAR_GlobBool_21 == 1 ) {
Battle( 0, VAR_GlobInt16_6 )
}
CloseAllWindows( )
0xA9( 250 )
set VAR_GlobBool_158 = 1
if ( VAR_GlobBool_159 == 1 ) {
if ( VAR_GlobBool_156 == 0 ) {
EnableMove( )
SetTriangleFlagMask( 255 )
if ( VAR_GlobBool_144 == 0 ) {
EnableMenu( )
}
}
}
TimedTurn( VAR_GlobUInt8_16, 16 )
WaitTurn( )
return
[STRT=100,3][IMME]What u wanna do?
[CHOO=2,1] Go Battle
Nothing
[STRT=200,4] [IMME]Increment: [NUMB=6] Destination: [NUMB=5]
startbattlebool: [NUMB=4] (0=no, 1=yes)
[JCBT=START] change startbattlebool
[JCBT=UP] [JCBT=DOWN]Increment[JCBT=LEFT] [JCBT=RIGHT]Destination
WeaponId == 74
MaxMP + MaxMP / 2
">SA GlobalLast
Permanent
etc...
and not:>SA
GlobalLast
Permanent
etc...
I used Memoria.Compiler.exe . Files have been updated ==> (D:\Final Fantasy IX\StreamingAssets\Scripts). But I haven't moved them anywhere. Copies of these files are nowhere to be found.
Good day to you!
It would be awesome to have more visual guides but I have such a long todo-list right now about this game that I don't feel like doing it myself at the moment.
Updating the "Memoria.script.dll" will not help toward "AbilityFeatures.txt". I can tell you however that "Memoria.script.dll" goes to "StreamingAssets/Scripts/Memoria.script.dll" by default and it can also be present in mod folders to take over that default one (for example, I have one for my own mod and thus it has the path "AlternateFantasy/StreamingAssets/Scripts/Memoria.script.dll").
Running Memoria.Patcher.exe should the be correct way to update Memoria.
There are surely problems because you have the game installed in the D: drive though, and not the C: drive. If you didn't install the game using Steam, then I don't know what happens. The normal installation path is "C:\Program Files (x86)\Steam\steamapps\common\FINAL FANTASY IX".
I'll check what it is but I don't remember having that issue. Maybe that's because you use GlobalLast instead of Global? Although I don't see why it would matter... I'm pretty sure that my implementation of MP+20% on Magus Hat doesn't have that problem.
I must have badly tested it because that was indeed a bug common to all of the HP+X% or MP+X% features.
Thanks for pointing that bug; I've fixed it for the next Memoria release.
// Player sequence of SFX Player_Attack_Garnet_LH_Racket
WaitAnimation: Char=Caster
PlayAnimation: Char=Caster ; Anim=MP_SET
StartThread: Condition=AreCasterAndTargetsEnemies ; Sync=True
Turn: Char=Caster ; BaseAngle=AllTargets ; Time=10
EndThread
StartThread: Condition=!AreCasterAndTargetsEnemies ; Sync=True
MoveToTarget: Char=Caster ; Target=AllTargets ; Offset=(0.0, 0.0, 1600) ; Time=0
Turn: Char=Caster ; BaseAngle=AllTargets ; Time=0
EndThread
StartThread: Condition=CasterWeaponId == 52 ; LoopCount=3 ; Chain ; Sync
LoadSFX: SFX=Player_Attack_Garnet_LH_Racket
Wait: Time=25
PlaySound: Sound=WeaponAttack
WaitSFXLoaded: SFX=Player_Attack_Garnet_LH_Racket
PlaySFX: SFX=Player_Attack_Garnet_LH_Racket
Wait: Time=7
EffectPoint: Char=AllTargets ; Type=Effect
StartThread: Condition=!IsAttackMiss
PlaySound: Sound=WeaponHit
EndThread
StartThread
Wait: Time=10
EffectPoint: Char=Everyone ; Type=Figure
EndThread
WaitAnimation: Char=Caster
PlayAnimation: Char=Caster ; Anim=MP_SET
EndThread
LoadSFX: SFX=Player_Attack_Garnet_LH_Racket
Wait: Time=25
PlaySound: Sound=WeaponAttack
WaitSFXLoaded: SFX=Player_Attack_Garnet_LH_Racket
PlaySFX: SFX=Player_Attack_Garnet_LH_Racket
Wait: Time=7
EffectPoint: Char=AllTargets ; Type=Effect
StartThread: Condition=!IsAttackMiss
PlaySound: Sound=WeaponHit
EndThread
Wait: Time=10
EffectPoint: Char=Everyone ; Type=Figure
StartThread: Condition=AreCasterAndTargetsEnemies ; Sync=True
Turn: Char=Caster ; BaseAngle=Default ; Time=4
EndThread
StartThread: Condition=!AreCasterAndTargetsEnemies ; Sync=True
MoveToPosition: Char=Caster ; AbsolutePosition=Default ; Time=0
Turn: Char=Caster ; BaseAngle=Default ; Time=0
EndThread
WaitTurn: Char=Caster
WaitSFXDone: SFX=Player_Attack_Garnet_LH_Racket
After a test, that seems to work fine. Maybe I'll do something similar for my own mod ^^MP_SET
then MP_RUN
then MP_RUN_TO_ATTACK
then MP_ATTACK
then MP_BACK
then MP_ATK_TO_NORMAL
It's only the ranged weapons that use only "MP_SET" as a complete attack animation loop.
set SV_Target = RandomInTeam(SV_PlayerTeam)
A line like that is party-wide:set SV_Target = SV_PlayerTeam
No, Gledson999. Hades Workshop cannot increase the file size of the PSX version, so using custom backgrounds can't be done and will most likely never be possible for the PSX version.I understood, I wanted to translate some city names in my translation, which are those names when we enter somewhere for the first time in some city/location, like Chocobo's Forest, Gizamaluke Grottos... and insert back using the same palette and the same size.
Function Moogle_Male_64
switch 3 ( Chocobo_CurrentField ) from 1 {
case +0:
SetTextVariable( 2, Chocobo_ForestHighScore )
SetTextVariable( 3, Chocobo_ForestGamePlayed )
break
case +1:
SetTextVariable( 2, Chocobo_LagoonHighScore )
SetTextVariable( 3, Chocobo_LagoonGamePlayed )
break
case +2:
SetTextVariable( 2, Chocobo_GardenHighScore )
SetTextVariable( 3, Chocobo_GardenGamePlayed )
}
SetTextVariable( 5, ( Chocobo_ForestGamePlayed + Chocobo_LagoonGamePlayed ) + Chocobo_GardenGamePlayed )
SetTextVariable( 4, Chocobo_HotColdPoints )
if ( Chocobo_Lv99 == 0 ) {
WindowSync( 7, 128, 240 )
} else {
WindowSync( 7, 128, 243 )
}
if ( GetDialogChoice == 0 ) {
set VAR_LocUInt16_9 = 0
set VAR_LocUInt8_2 = 8
EnableDialogChoices( 511, VAR_LocUInt8_2 )
WindowAsync( 6, 4, 246 )
while ( VAR_LocUInt16_9 < 1 ) {
set VAR_LocInt8_29 = 1
EnableDialogChoices( 511, VAR_LocUInt8_2 )
SetTextVariable( 4, Chocobo_HotColdPoints )
set VAR_LocInt8_30 = 0
while ( VAR_LocInt8_30 < 1 ) {
if ( IsButton(655360L) ) {
set VAR_LocInt8_30 = 1
}
Wait( 1 )
}
switch 9 ( GetDialogChoice ) from 0 {
case +0:
if ( ( Chocobo_HotColdPoints >= 10000 ) && ( GetItemCount(175) < 99 ) ) {
set Chocobo_HotColdPoints -= 10000
AddItem( 175, 1 )
set VAR_LocInt8_29 = 0
}
set VAR_LocUInt8_2 = 0
break
case +1:
if ( ( Chocobo_HotColdPoints >= 8500 ) && ( GetItemCount(209) < 99 ) ) {
set Chocobo_HotColdPoints -= 8500
AddItem( 209, 1 )
set VAR_LocInt8_29 = 0
}
set VAR_LocUInt8_2 = 1
break
case +2:
if ( ( Chocobo_HotColdPoints >= 3500 ) && ( GetItemCount(87) < 99 ) ) {
set Chocobo_HotColdPoints -= 3500
AddItem( 87, 1 )
set VAR_LocInt8_29 = 0
}
set VAR_LocUInt8_2 = 2
break
case +3:
if ( ( Chocobo_HotColdPoints >= 1800 ) && ( GetCardAmount < 100 ) ) {
set Chocobo_HotColdPoints -= 1800
AddItem( 599, 1 )
set VAR_LocInt8_29 = 0
}
set VAR_LocUInt8_2 = 3
break
case +4:
if ( ( Chocobo_HotColdPoints >= 450 ) && ( GetItemCount(238) < 99 ) ) {
set Chocobo_HotColdPoints -= 450
AddItem( 238, 1 )
set VAR_LocInt8_29 = 0
}
set VAR_LocUInt8_2 = 4
break
case +5:
if ( ( Chocobo_HotColdPoints >= 250 ) && ( GetItemCount(254) < 99 ) ) {
set Chocobo_HotColdPoints -= 250
AddItem( 254, 1 )
set VAR_LocInt8_29 = 0
}
set VAR_LocUInt8_2 = 5
break
case +6:
if ( ( Chocobo_HotColdPoints >= 150 ) && ( GetItemCount(249) < 99 ) ) {
set Chocobo_HotColdPoints -= 150
AddItem( 249, 1 )
set VAR_LocInt8_29 = 0
}
set VAR_LocUInt8_2 = 6
break
case +7:
if ( ( Chocobo_HotColdPoints >= 10 ) && ( GetItemCount(251) < 99 ) ) {
set Chocobo_HotColdPoints -= 10
AddItem( 251, 1 )
set VAR_LocInt8_29 = 0
}
set VAR_LocUInt8_2 = 7
break
default:
set VAR_LocUInt16_9 = 99
set VAR_LocInt8_29 = 99
CloseWindow( 7 )
break
}
switch 2 ( VAR_LocInt8_29 ) from 0 {
case +0:
Wait( 4 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
Wait( 4 )
break
case +1:
Wait( 4 )
RunSoundCode3( 53248, 102, 0, -128, 125 )
Wait( 4 )
break
}
}
RunSoundCode3( 53248, 103, 0, -128, 125 )
}
return
Function Moogle_Male_64
switch 3 ( Chocobo_CurrentField ) from 1 {
case +0:
SetTextVariable( 2, Chocobo_ForestHighScore )
SetTextVariable( 3, Chocobo_ForestGamePlayed )
break
case +1:
SetTextVariable( 2, Chocobo_LagoonHighScore )
SetTextVariable( 3, Chocobo_LagoonGamePlayed )
break
case +2:
SetTextVariable( 2, Chocobo_GardenHighScore )
SetTextVariable( 3, Chocobo_GardenGamePlayed )
}
SetTextVariable( 5, ( Chocobo_ForestGamePlayed + Chocobo_LagoonGamePlayed ) + Chocobo_GardenGamePlayed )
SetTextVariable( 4, Chocobo_HotColdPoints )
if ( Chocobo_Lv99 == 0 ) {
WindowSync( 7, 128, 240 )
} else {
WindowSync( 7, 128, 243 )
}
if ( GetDialogChoice == 0 ) {
set VAR_LocUInt16_9 = 0
set VAR_LocUInt8_2 = 8
EnableDialogChoices( 511, VAR_LocUInt8_2 )
WindowAsync( 6, 4, 246 )
while ( VAR_LocUInt16_9 < 1 ) {
set VAR_LocInt8_29 = 1
EnableDialogChoices( 511, VAR_LocUInt8_2 )
SetTextVariable( 4, Chocobo_HotColdPoints )
set VAR_LocInt8_30 = 0
while ( VAR_LocInt8_30 < 1 ) {
if ( IsButton(655360L) ) {
set VAR_LocInt8_30 = 1
}
Wait( 1 )
}
switch 9 ( GetDialogChoice ) from 0 {
case +0:
if ( ( Chocobo_HotColdPoints >= 60000 ) && ( GetItemCount(0) < 99 ) ) {
set Chocobo_HotColdPoints -= 60000
AddItem( 0, 1 )
set VAR_LocInt8_29 = 0
}
set VAR_LocUInt8_2 = 0
break
case +1:
if ( ( Chocobo_HotColdPoints >= 10000 ) && ( GetItemCount(175) < 99 ) ) {
set Chocobo_HotColdPoints -= 10000
AddItem( 175, 1 )
set VAR_LocInt8_29 = 0
}
set VAR_LocUInt8_2 = 1
break
case +2:
if ( ( Chocobo_HotColdPoints >= 8500 ) && ( GetItemCount(209) < 99 ) ) {
set Chocobo_HotColdPoints -= 8500
AddItem( 209, 1 )
set VAR_LocInt8_29 = 0
}
set VAR_LocUInt8_2 = 2
break
case +3:
if ( ( Chocobo_HotColdPoints >= 3500 ) && ( GetItemCount(87) < 99 ) ) {
set Chocobo_HotColdPoints -= 3500
AddItem( 87, 1 )
set VAR_LocInt8_29 = 0
}
set VAR_LocUInt8_2 = 3
break
case +4:
if ( ( Chocobo_HotColdPoints >= 1800 ) && ( GetCardAmount < 100 ) ) {
set Chocobo_HotColdPoints -= 1800
AddItem( 599, 1 )
set VAR_LocInt8_29 = 0
}
set VAR_LocUInt8_2 = 4
break
case +5:
if ( ( Chocobo_HotColdPoints >= 450 ) && ( GetItemCount(238) < 99 ) ) {
set Chocobo_HotColdPoints -= 450
AddItem( 238, 1 )
set VAR_LocInt8_29 = 0
}
set VAR_LocUInt8_2 = 5
break
case +6:
if ( ( Chocobo_HotColdPoints >= 250 ) && ( GetItemCount(254) < 99 ) ) {
set Chocobo_HotColdPoints -= 250
AddItem( 254, 1 )
set VAR_LocInt8_29 = 0
}
set VAR_LocUInt8_2 = 6
break
case +7:
if ( ( Chocobo_HotColdPoints >= 150 ) && ( GetItemCount(249) < 99 ) ) {
set Chocobo_HotColdPoints -= 150
AddItem( 249, 1 )
set VAR_LocInt8_29 = 0
}
set VAR_LocUInt8_2 = 7
break
case +8:
if ( ( Chocobo_HotColdPoints >= 10 ) && ( GetItemCount(251) < 99 ) ) {
set Chocobo_HotColdPoints -= 10
AddItem( 251, 1 )
set VAR_LocInt8_29 = 0
}
set VAR_LocUInt8_2 = 8
break
default:
set VAR_LocUInt16_9 = 99
set VAR_LocInt8_29 = 99
CloseWindow( 8 )
break
}
switch 2 ( VAR_LocInt8_29 ) from 0 {
case +0:
Wait( 4 )
RunSoundCode3( 53248, 108, 0, -128, 125 )
Wait( 4 )
break
case +1:
Wait( 4 )
RunSoundCode3( 53248, 102, 0, -128, 125 )
Wait( 4 )
break
}
}
RunSoundCode3( 53248, 103, 0, -128, 125 )
}
return
set Chocobo_HotColdPoints -= 60000L
That is because numbers higher than 32636 should be flagged as "long" numbers, otherwise they are stored as a 2-byte signed integer type.Replace "60000" by "60000L" in the code:Thank you, I corrected the item price issue here, as I also managed to put the value "set VAR_LocUInt8_2 = 9"Code: [Select]set Chocobo_HotColdPoints -= 60000L
That is because numbers higher than 32636 should be flagged as "long" numbers, otherwise they are stored as a 2-byte signed integer type.
Also, for the selectability problem, update the lines "EnableDialogChoices". You must both include the added choice to the available choice list (change "511" into "1023", or tick the next box in the script editor), and tell the game that the "default" choice has index 9 instead of 8 (change "set VAR_LocUInt8_2 = 8" into "set VAR_LocUInt8_2 = 9").
Also, when editing the text, there's an opcode that setups the choices ("FORMAT:Multichoice" in the PSX version): double-click to edit its parameter and do the same kind of changes there (number of choices => 10, "Cancel" choice => 9).I couldn't open the menu using the two clicks to edit the parameters, correct me if i'm wrong or i'm trying to click the wrong box
Ah, maybe you can't change "Format" opcodes for the PSX version of the game...If delete this Opcode, Only this two option are available
What happens if you delete that opcode? Careful, you won't be able to add it back, I think.
hey tiriltiti,
i'm trying to edit enemies panel on FF9 PSX (1.0 version) (pure vanilla/untouched) but when I try to rename an enemy, Hades Workshop crash instantly, even try to backspace one letter it instant crash.
Version 0.35b is up. All the changes apply only to the Steam version :
- Fixed the black screen bug in battles when you modified an item,
- Improved the reading/modding of Assembly-CSharp.dll,
- Added a "Break damage limit" macro, be careful that it will bug with certain bosses,
...->
The C# macros (and more generally the "CIL code" panel) don't work with the Memoria Engine mod.
I just added a "Break damage limit" option directly in Memoria though: it will be a new option of the next Memoria release.
Weapon ID == 64
Magic + 6
. SetCharacterData( 9, 1, 8, 21, 8 )
This line setup Cinna in particular by enabling his flag "Temporary character". Without that flag, he would use Quina's model and portrait and would have trance just like the other party members (he wouldn't have it against Masked Man because trance is still disabled for everyone at that point).For trance and whether it's Blank instead of Amarant or the other way around, it's the same thing in HW : it's the character's flag "Temporary party member". That's a flag that is used when settting up the characters before they join the party for the first time.
Example, in Prima Vista/Cargo Room's script, in the function "Baku_Masked_Loop", you have this line:Code: [Select]SetCharacterData( 9, 1, 8, 21, 8 )
This line setup Cinna in particular by enabling his flag "Temporary character". Without that flag, he would use Quina's model and portrait and would have trance just like the other party members (he wouldn't have it against Masked Man because trance is still disabled for everyone at that point).
I have no idea for gameshark codes.
case +6:
set SV_Target = SV_FunctionEnemy
break
... into something like that: case +6:
set SV_Target = SV_PlayerTeam
break
if ( GetFrogAmount == 99 ) {
orBattle( 1, 330 )
orswitchex 6 ( GetFrogAmount ) {
case 2:
set VAR_GlobUInt16_66 = 254
break
case 5:
set VAR_GlobUInt16_66 = 238
break
case 9:
set VAR_GlobUInt16_66 = 169
break
case 15:
set VAR_GlobUInt16_66 = 239
break
case 23:
set VAR_GlobUInt16_66 = 82
break
case 33:
set VAR_GlobUInt16_66 = 83
break
default:
set VAR_GlobUInt16_66 = 197
break
}
(all of these are close to each other)Expect 100%. It's not impossible that there are situations in which the conversion would be easier, but don't count on it.
You can however use Text Batching (export/import) that eases the process for the Text panel.
That's correct.
Yes, the "SetCharacterData" is almost a "one-time event" (actually not one time but 2 or 3 times depending on the character), ie. it is triggered once when the character is initialised and if the character was initialised with the "temporary" flag, that character will keep that flag for the rest of the game or until it gets re-initialised.
=> If you load a save in which the character was already initialised with this flag, it will keep this flag, no matter what change you did to the event scripts of "Prima Vista".
=> Also, the temporary characters are re-initialised a couple of time: Blank is re-initialised right before the Plant Brain battle (there's a line "SetCharacterData" for Blank a bit above the line that triggers the Plant Brain battle in its nest) / Marcus is re-initialised before the 2nd fight against Black Waltz 3 battle / Beatrix is initialised once in Queen's Chamber before fighting Bandersnatches and is re-initialised in Alexandria's marketplace during Bahamut's attack.
=> You are able remove that "temporary" flag even in your end-game saves if you add new "SetCharacterData" lines at places where there wasn't before. For example, you can add a "SetCharacterData" at the end of a "Main_Init" function of any place so that it removes the flag. Make sure that you use the equipement set "255", which is the value for "don't touch the equipment", otherwise you could lose/duplicate pieces of equipments.
Function Man_SpeakBTN
ifnot ( IsMovementEnabled ) {
return
}
set VAR_GlobBool_158 = 0
if ( VAR_GlobBool_159 == 1 ) {
DisableMove( )
if ( VAR_GlobBool_144 == 0 ) {
DisableMenu( )
} else {
Wait( 1 )
}
}
SetTriangleFlagMask( 127 )
WindowSync( 2, 128, XXX ) // Use whatever dialog line you want, like "Hello, here's a Beatrix for your party."
set Setting_PartyReserve = 511 // 511 is "all the usual party members + Beatrix
Party( 4, 1 ) // Open the party menu to allow the player to place Beatrix in
set VAR_GlobBool_158 = 1
if ( VAR_GlobBool_159 == 1 ) {
if ( VAR_GlobBool_156 == 0 ) {
EnableMove( )
SetTriangleFlagMask( 255 )
if ( VAR_GlobBool_144 == 0 ) {
EnableMenu( )
}
}
}
return
You can add things like "TurnTowardObject( 250, 32 ) / WaitTurn( )" to make add fanciness, but the main line is changing the "Setting_PartyReserve". Also, if you use this code before Beatrix joined your party the first time, you need a line like "SetCharacterData( 8, 1, 13, 22, 15 )" as well.SetCharacterData( 11, 1, 10, 21, 12 ) // Setup Blank
SetCharacterData( 7, 0, 7, 5, 7 ) // Setup Amarant instead
Hi. I wished I have this kind of almighty power ^^'I had to ask :) I know it won't run on original psx even if I managed to swap them but I'm hoping it's somehow possible when emulating in RetroArch for example.
No, it is not possible to increase the data size of the PSX version to my knowledge, so inserting the heavy FMVs of the PC version in the PSX disc image is out of reach, even before considering format discrepancies.
If you want to do the other way around, it might be possible with other tools.Why would I want to swap those high res movies? xD
Hi.
It's not easy to add a brand new NPC even with minimal interaction, but it is possible to add Beatrix in the party, even in the PSX version. Indeed it's impossible to have both Blank and Amarant simultaneously because they share a common slot. It'd also be problematic to switch between Blank and Amarant back and forth because it would lose some of Amarant's datas in the process.
Basically, you need to add this kind of function to a NPC in a field script. You can add a NPC that normally doesn't appear by adding an entry, but beware that 3D models are field-dependant on the PSX version and you can't have a NPC appearing in a field in which they would never appear otherwise.Code: [Select]Function Man_SpeakBTN
You can add things like "TurnTowardObject( 250, 32 ) / WaitTurn( )" to make add fanciness, but the main line is changing the "Setting_PartyReserve". Also, if you use this code before Beatrix joined your party the first time, you need a line like "SetCharacterData( 8, 1, 13, 22, 15 )" as well.
ifnot ( IsMovementEnabled ) {
return
}
set VAR_GlobBool_158 = 0
if ( VAR_GlobBool_159 == 1 ) {
DisableMove( )
if ( VAR_GlobBool_144 == 0 ) {
DisableMenu( )
} else {
Wait( 1 )
}
}
SetTriangleFlagMask( 127 )
WindowSync( 2, 128, XXX ) // Use whatever dialog line you want, like "Hello, here's a Beatrix for your party."
set Setting_PartyReserve = 511 // 511 is "all the usual party members + Beatrix
Party( 4, 1 ) // Open the party menu to allow the player to place Beatrix in
set VAR_GlobBool_158 = 1
if ( VAR_GlobBool_159 == 1 ) {
if ( VAR_GlobBool_156 == 0 ) {
EnableMove( )
SetTriangleFlagMask( 255 )
if ( VAR_GlobBool_144 == 0 ) {
EnableMenu( )
}
}
}
return
By the way, whether it's Blank or Amarant in your party depends on the flag "temporary character" in the corresponding "SetCharacterData" line that was last used on their shared slot.Code: [Select]SetCharacterData( 11, 1, 10, 21, 12 ) // Setup Blank
SetCharacterData( 7, 0, 7, 5, 7 ) // Setup Amarant instead
Hi paky-outsider,
Wouldn't it work to just replace all the occurences of "IsInParty(5)" by "IsInParty(9)", as you've started to do?
You can batch-export the field scripts and do some "search & replace" operation. Normally, you should even be able to batch-reimport the scripts easily then, even though I've not tested with the PSX version and it may bug if there are too many scripts.
The problem with making links to other fields in the PSX version is that it doesn't work well as the game needs to preload some datas. I wouldn't try to hijack the field exits like that in the PSX version.
Hey Tirlititi,
Fist off, thank you for the awesome update. I didn't even realize you were still working on it.
I had a question. I know you edited the game so that Quan's Dwelling scene couldn't be done until disc four, and I was wondering if I could do something similar. I wanted to edit the colored stone deposit shrine on the Conde Petie Mountain Path (1554: Mountain Path/Roots) so that you can't deposit the items on disc 2, only on disc 3. I was hoping to simply edit the message that pops up if you try to do it on disc two with something along the lines "looks like it's not working."
If this is too difficult, or not possible, it occurred to me that I can just hide one of the stones somewhere else in the world only available in disc three, and make the player come back later.
Function Zidane_48
TimedTurn( Angle(2000, 850), 32 )
WaitTurn( )
SetStandAnimation( 2605 ) // Crouch
RunAnimation( 2607 ) // Idle crouching
WaitAnimation( )
SetTextVariable( 0, 300 ) // "Red Stone"
WindowSync( 0, 0, 143 ) // "[Item] is set on the stone. Take it out Leave it alone"
if ( !GetDialogChoice ) {
Wait( 10 )
RunSoundCode3( 53248, 1340, 0, -128, 125 ) // Play Sound
Wait( 10 )
}
SetStandAnimation( 200 ) // Idle
RunAnimation( 2591 ) // Stand up
if ( !GetDialogChoice ) {
RunSoundCode3( 53248, 108, 0, -128, 125 ) // Play Sound
AddItem( 300, 1 ) // Add the Red Stone key item
SetTextVariable( 0, 300 ) // "Red Stone"
if ( 1 ) {
WindowSync( 7, 0, 58 ) // " Received [Item]! "
} else {
WindowSync( 7, 0, 59 ) // Unused - " Received [Item] Card! "
}
set VARL_GenBool_2864 = 1
}
WaitAnimation( )
return
So you see, by changing the ID "300" to something else, you can change the item given at these statues. It also shows how items are given to the player so you can do something similar later on on disk 3.Function ChestA_Init
SetModel( 75, 0 ) // The model of "ChestA"
CreateObject( [COORDINATES: Chest position on the field] )
TurnInstant( [ANGLE: Chest facing angle on the field] )
SetObjectLogicalSize( 1, 40, 45 )
SetStandAnimation( 7340 ) // Dummy Close
SetWalkAnimation( 7340 ) // Dummy Close
SetRunAnimation( 7340 ) // Dummy Close
SetObjectFlags( 5 )
SetHeadFocusMask( 2, 0 )
if ( [CONDITION: Chest content already picked up] ) {
SetStandAnimation( 7338 ) // Dummy Open
} else {
SetStandAnimation( 7339 ) // Dummy Close
}
SetObjectFlags( 49 )
EnableHeadFocus( 0 )
return
3) Add a line "InitObject" next to the others in the function "Main_Init" to actually create the chest object when entering the field.I think that's because you don't have the latest version of Memoria. Your installation sequence is the best but for some reason I think you didn't use the latest version (June 2023).
I. Getting Started
In field: Alexandria/Dock (Field ID: 2458), we need to firstly initiate some character that will pose as our scene starter (in this case, it will be Steiner):
1. In Hades Workshop, navigate to the Fields Tab and scroll down to Field Alexandria/Dock (Field ID: 2458)
1a. Select "Edit Entries"
1b. In the Entries Menu, scroll down and select "Steiner" and "Freya". *Because this field does not natively have Steiner or Freya initiated (par vanilla), we need to add them in manually)
1c. Select "Edit Script"
1d. In the Edit Script Window, under the "Functions" section, right-click and select "Add"
1e. In the Properties Menu, for "Entry" select "Steiner"
1f. For Entry Type, set the value "2". "2" means "object with model", standard for all 3D models initiated
1g. For "Function Type" set the value "0". "0" means "main function". Every 3d model has an _Init function, which is used to create the 3D model in scene
1h. Select "Parse", then "Ok".
@paky-outsider: No, they are mostly done for the PC version and even for the PC version that is modded with the Memoria Engine Mod.
These 3 points apply to the PSX version as well, but that's pretty much it.
- Fix "ObjectUID_" in scripts so they adapt if you add or remove entries.
- Add a copy/paste feature for texts. Only enemy, world map and field texts can use this feature.
- Add a couple of interface improvements (mainly some more IDs are displayed).
@g_west: These are handled by the field scripts (in "Environment -> Fields -> Edit Script" windows).
The functions that are relevant to this side-quest are mostly those:
1) Picking up the Red Stone: Field Mountain Path/Trail (1550), Function Zidane_48
2) Picking up the Blue Stone: Field Mountain Path/Trail (1551), Function Zidane_15
3) Picking up the Yellow Stone: Field Mountain Path/Roots (1555), Function Zidane_22
4) Picking up the Green Stone: Field Mountain Path/Roots (1557), Function Zidane_14
5) Placing all the stones: Field Mountain Path/Roots (1554), Function Zidane_16
The picking-up functions all look roughly the same. Something like that:Code: [Select]Function Zidane_48
So you see, by changing the ID "300" to something else, you can change the item given at these statues. It also shows how items are given to the player so you can do something similar later on on disk 3.
TimedTurn( Angle(2000, 850), 32 )
WaitTurn( )
SetStandAnimation( 2605 ) // Crouch
RunAnimation( 2607 ) // Idle crouching
WaitAnimation( )
SetTextVariable( 0, 300 ) // "Red Stone"
WindowSync( 0, 0, 143 ) // "[Item] is set on the stone. Take it out Leave it alone"
if ( !GetDialogChoice ) {
Wait( 10 )
RunSoundCode3( 53248, 1340, 0, -128, 125 ) // Play Sound
Wait( 10 )
}
SetStandAnimation( 200 ) // Idle
RunAnimation( 2591 ) // Stand up
if ( !GetDialogChoice ) {
RunSoundCode3( 53248, 108, 0, -128, 125 ) // Play Sound
AddItem( 300, 1 ) // Add the Red Stone key item
SetTextVariable( 0, 300 ) // "Red Stone"
if ( 1 ) {
WindowSync( 7, 0, 58 ) // " Received [Item]! "
} else {
WindowSync( 7, 0, 59 ) // Unused - " Received [Item] Card! "
}
set VARL_GenBool_2864 = 1
}
WaitAnimation( )
return
The function for placing the stones is a bit more complicated (in particular, it uses a variable "VARL_GenUInt8_358" with bitwise operations to keep track of which stones are already placed). It could be done to add another stone requirement (like a custom made "White Stone" or whatever) that would only be picked up in disk 3, but indeed the easiest is to change the reward in one of the pickup spot above + add the missing stone later on in disk 3.
In order to give the missing stone later on, check how to change a chest content (https://forums.qhimm.com/index.php?topic=14315.msg233384#msg233384) that I wrote a long time ago. Most of the time, you'll want to search for the "Chest" functions in field scripts or possibly the "Zidane_XX" functions when the items are placed on the floor and not inside a chest.
It is also possible to add a whole new chest, so you don't replace any other treasure. For that, you mostly need to:
1) Create a new entry in the "Edit Entries" window, of type "Object" (because it will be linked to a chest 3D object).
2) Add functions for that new entry, at least a "Init" (a function of type 0) and a "Range" (a function of type 2). Adding functions is done by right-clicking on the list of functions in the script window. These two functions should be like the functions for existing chests. The "Init" function for instance could look like that:Code: [Select]Function ChestA_Init
3) Add a line "InitObject" next to the others in the function "Main_Init" to actually create the chest object when entering the field.
SetModel( 75, 0 ) // The model of "ChestA"
CreateObject( [COORDINATES: Chest position on the field] )
TurnInstant( [ANGLE: Chest facing angle on the field] )
SetObjectLogicalSize( 1, 40, 45 )
SetStandAnimation( 7340 ) // Dummy Close
SetWalkAnimation( 7340 ) // Dummy Close
SetRunAnimation( 7340 ) // Dummy Close
SetObjectFlags( 5 )
SetHeadFocusMask( 2, 0 )
if ( [CONDITION: Chest content already picked up] ) {
SetStandAnimation( 7338 ) // Dummy Open
} else {
SetStandAnimation( 7339 ) // Dummy Close
}
SetObjectFlags( 49 )
EnableHeadFocus( 0 )
return
Sorry for the late answers.
// Player sequence of SFX Iai_Strike_2
// Used by Zidane (Windfall with a dagger)
WaitAnimation: Char=Caster
Message: Text=[CastName] ; Priority=1 ; Title=True ; Reflect=True
SetupReflect: Delay=SFXLoaded
LoadSFX: SFX=Iai_Strike_1 ; Reflect=True ; UseCamera=False
PlayAnimation: Char=Caster ; Anim=MP_SET
WaitAnimation: Char=Caster
MoveToTarget: Char=Caster ; Target=AllTargets ; Distance=670 ; UseCollisionRadius=True ; Anim=MP_RUN
Turn: Char=Caster ; BaseAngle=AllTargets ; Time=4
WaitMove: Char=Caster
MoveToTarget: Char=Caster ; Target=AllTargets ; Distance=400 ; UseCollisionRadius=True ; Anim=MP_RUN_TO_ATTACK
WaitMove: Char=Caster
StartThread
Wait: Time=4
WaitSFXLoaded: SFX=Iai_Strike_1
PlaySFX: SFX=Iai_Strike_1
WaitSFXDone: SFX=Iai_Strike_1
EndThread
PlayAnimation: Char=Caster ; Anim=MP_ATTACK
WaitAnimation: Char=Caster
MoveToTarget: Char=Caster ; Target=AllTargets ; Distance=-200 ; UseCollisionRadius=True ; Time=0
MoveToTarget: Char=Caster ; Target=AllTargets ; Distance=1100 ; UseCollisionRadius=True ; Anim=MP_STEP_BACK
WaitMove: Char=Caster
MoveToTarget: Char=Caster ; Target=AllTargets ; Distance=670 ; UseCollisionRadius=True ; Anim=MP_RUN
Turn: Char=Caster ; BaseAngle=AllTargets ; Time=4
WaitMove: Char=Caster
MoveToTarget: Char=Caster ; Target=AllTargets ; Distance=400 ; UseCollisionRadius=True ; Anim=MP_RUN_TO_ATTACK
WaitMove: Char=Caster
StartThread
Wait: Time=4
WaitSFXLoaded: SFX=Iai_Strike_1
PlaySFX: SFX=Iai_Strike_1
WaitSFXDone: SFX=Iai_Strike_1
EndThread
PlayAnimation: Char=Caster ; Anim=MP_ATTACK
WaitAnimation: Char=Caster
MoveToPosition: Char=Caster ; AbsolutePosition=Default ; Anim=MP_BACK
Turn: Char=Caster ; BaseAngle=Default ; Time=4
WaitMove: Caster
PlayAnimation: Char=Caster ; Anim=Idle
WaitTurn: Char=Caster
ActivateReflect
WaitReflect
By having this file saved as "{Mod Folder}/StreamingAssets/Data/SpecialEffects/ef030/Sequence.seq", the abilities that use the spell effect "Iai Strike 2" (that you can pick in Hades Workshop) will perform a double-hit with the Iai Strike effect./ Player sequence of SFX Iai_Strike_2
// Used by Zidane (Windfall with a dagger)
WaitAnimation: Char=Caster
Message: Text=[CastName] ; Priority=1 ; Title=True ; Reflect=True
SetupReflect: Delay=SFXLoaded
LoadSFX: SFX=Iai_Strike_1 ; Reflect=True ; UseCamera=False
PlayAnimation: Char=Caster ; Anim=MP_SET
WaitAnimation: Char=Caster
MoveToTarget: Char=Caster ; Target=FirstTarget ; Distance=670 ; UseCollisionRadius=True ; Anim=MP_RUN
Turn: Char=Caster ; BaseAngle=FirstTarget ; Time=4
WaitMove: Char=Caster
MoveToTarget: Char=Caster ; Target=FirstTarget ; Distance=400 ; UseCollisionRadius=True ; Anim=MP_RUN_TO_ATTACK
WaitMove: Char=Caster
StartThread
Wait: Time=4
WaitSFXLoaded: SFX=Iai_Strike_1
PlaySFX: SFX=Iai_Strike_1
WaitSFXDone: SFX=Iai_Strike_1
EndThread
PlayAnimation: Char=Caster ; Anim=MP_ATTACK
WaitAnimation: Char=Caster
MoveToTarget: Char=Caster ; Target=FirstTarget ; Distance=-200 ; UseCollisionRadius=True ; Time=0
MoveToTarget: Char=Caster ; Target=FirstTarget ; Distance=1100 ; UseCollisionRadius=True ; Anim=MP_STEP_BACK
WaitMove: Char=Caster
MoveToTarget: Char=Caster ; Target=SecondTarget ; Distance=670 ; UseCollisionRadius=True ; Anim=MP_RUN
Turn: Char=Caster ; BaseAngle=SecondTarget ; Time=4
WaitMove: Char=Caster
MoveToTarget: Char=Caster ; Target=SecondTarget ; Distance=400 ; UseCollisionRadius=True ; Anim=MP_RUN_TO_ATTACK
WaitMove: Char=Caster
StartThread
Wait: Time=4
WaitSFXLoaded: SFX=Iai_Strike_1
PlaySFX: SFX=Iai_Strike_1
WaitSFXDone: SFX=Iai_Strike_1
EndThread
PlayAnimation: Char=Caster ; Anim=MP_ATTACK
WaitAnimation: Char=Caster
MoveToTarget: Char=Caster ; Target=SecondTarget ; Distance=-200 ; UseCollisionRadius=True ; Time=0
MoveToTarget: Char=Caster ; Target=SecondTarget ; Distance=1100 ; UseCollisionRadius=True ; Anim=MP_STEP_BACK
WaitMove: Char=Caster
MoveToTarget: Char=Caster ; Target=ThirdTarget ; Distance=670 ; UseCollisionRadius=True ; Anim=MP_RUN
Turn: Char=Caster ; BaseAngle=ThirdTarget ; Time=4
WaitMove: Char=Caster
MoveToTarget: Char=Caster ; Target=ThirdTarget ; Distance=400 ; UseCollisionRadius=True ; Anim=MP_RUN_TO_ATTACK
WaitMove: Char=Caster
StartThread
Wait: Time=4
WaitSFXLoaded: SFX=Iai_Strike_1
PlaySFX: SFX=Iai_Strike_1
WaitSFXDone: SFX=Iai_Strike_1
EndThread
PlayAnimation: Char=Caster ; Anim=MP_ATTACK
WaitAnimation: Char=Caster
MoveToTarget: Char=Caster ; Target=ThirdTarget ; Distance=-200 ; UseCollisionRadius=True ; Time=0
MoveToTarget: Char=Caster ; Target=ThirdTarget ; Distance=1100 ; UseCollisionRadius=True ; Anim=MP_STEP_BACK
WaitMove: Char=Caster
MoveToTarget: Char=Caster ; Target=FourthTarget ; Distance=670 ; UseCollisionRadius=True ; Anim=MP_RUN
Turn: Char=Caster ; BaseAngle=FourthTarget ; Time=4
WaitMove: Char=Caster
MoveToTarget: Char=Caster ; Target=FourthTarget ; Distance=400 ; UseCollisionRadius=True ; Anim=MP_RUN_TO_ATTACK
WaitMove: Char=Caster
StartThread
Wait: Time=4
WaitSFXLoaded: SFX=Iai_Strike_1
PlaySFX: SFX=Iai_Strike_1
WaitSFXDone: SFX=Iai_Strike_1
EndThread
PlayAnimation: Char=Caster ; Anim=MP_ATTACK
WaitAnimation: Char=Caster
MoveToPosition: Char=Caster ; AbsolutePosition=Default ; Anim=MP_BACK
Turn: Char=Caster ; BaseAngle=Default ; Time=4
WaitMove: Caster
PlayAnimation: Char=Caster ; Anim=Idle
WaitTurn: Char=Caster
ActivateReflect
WaitReflect
StartThread: TargetLoop ; Chain ; Sync
LoadSFX: SFX=Iai_Strike_1 ; Target=AllTargets ; Reflect=True ; UseCamera=False
MoveToTarget: Char=Caster ; Target=AllTargets ; Distance=670 ; UseCollisionRadius=True ; Anim=MP_RUN
Turn: Char=Caster ; BaseAngle=AllTargets ; Time=4
WaitMove: Char=Caster
MoveToTarget: Char=Caster ; Target=AllTargets ; Distance=400 ; UseCollisionRadius=True ; Anim=MP_RUN_TO_ATTACK
WaitMove: Char=Caster
StartThread
Wait: Time=4
WaitSFXLoaded: SFX=Iai_Strike_1
PlaySFX: SFX=Iai_Strike_1
WaitSFXDone: SFX=Iai_Strike_1
EndThread
PlayAnimation: Char=Caster ; Anim=MP_ATTACK
WaitAnimation: Char=Caster
MoveToTarget: Char=Caster ; Target=AllTargets ; Distance=-200 ; UseCollisionRadius=True ; Time=0
MoveToTarget: Char=Caster ; Target=AllTargets ; Distance=1100 ; UseCollisionRadius=True ; Anim=MP_STEP_BACK
WaitMove: Char=Caster
EndThread
WaitAnimation: Char=Caster
Message: Text=[CastName] ; Priority=1 ; Title=True ; Reflect=True
SetupReflect: Delay=SFXLoaded
SetBackgroundIntensity: Intensity=0.5 ; Time=4 ; HoldDuration=50
Wait: Time=30
PlayAnimation: Char=Caster ; Anim=MP_WIN
WaitAnimation: Char=Caster
WaitTurn: Char=Caster
StartThread: TargetLoop ; Chain ; Sync
LoadSFX: SFX=Iai_Strike_1 ; Target=AllTargets ; Reflect=True ; UseCamera=False
MoveToTarget: Char=Caster ; Target=AllTargets ; Distance=670 ; UseCollisionRadius=True ; Anim=MP_RUN
Turn: Char=Caster ; BaseAngle=AllTargets ; Time=4
WaitMove: Char=Caster
MoveToTarget: Char=Caster ; Target=AllTargets ; Distance=400 ; UseCollisionRadius=True ; Anim=MP_RUN_TO_ATTACK
WaitMove: Char=Caster
StartThread
Wait: Time=4
WaitSFXLoaded: SFX=Iai_Strike_1
PlaySFX: SFX=Iai_Strike_1
WaitSFXDone: SFX=Iai_Strike_1
EndThread
PlayAnimation: Char=Caster ; Anim=MP_ATTACK
WaitAnimation: Char=Caster
MoveToTarget: Char=Caster ; Target=AllTargets ; Distance=-200 ; UseCollisionRadius=True ; Time=0
MoveToTarget: Char=Caster ; Target=AllTargets ; Distance=500 ; UseCollisionRadius=True ; Anim=MP_STEP_BACK
WaitMove: Char=Caster
EndThread
StartThread: TargetLoop ; Chain ; Sync
StartThread: Condition=TargetHP != 0 ; Sync
LoadSFX: SFX=Iai_Strike_1 ; Target=AllTargets ; Reflect=True ; UseCamera=False
MoveToTarget: Char=Caster ; Target=AllTargets ; Distance=670 ; UseCollisionRadius=True ; Anim=MP_RUN
Turn: Char=Caster ; BaseAngle=AllTargets ; Time=4
WaitMove: Char=Caster
MoveToTarget: Char=Caster ; Target=AllTargets ; Distance=400 ; UseCollisionRadius=True ; Anim=MP_RUN_TO_ATTACK
WaitMove: Char=Caster
StartThread
Wait: Time=4
WaitSFXLoaded: SFX=Iai_Strike_1
PlaySFX: SFX=Iai_Strike_1
WaitSFXDone: SFX=Iai_Strike_1
EndThread
PlayAnimation: Char=Caster ; Anim=MP_ATTACK
WaitAnimation: Char=Caster
MoveToTarget: Char=Caster ; Target=AllTargets ; Distance=-200 ; UseCollisionRadius=True ; Time=0
MoveToTarget: Char=Caster ; Target=AllTargets ; Distance=500 ; UseCollisionRadius=True ; Anim=MP_STEP_BACK
WaitMove: Char=Caster
EndThread
EndThread
SetBackgroundIntensity: Intensity=1 ; Time=8
MoveToPosition: Char=Caster ; AbsolutePosition=Default ; Anim=MP_BACK
Turn: Char=Caster ; BaseAngle=Default ; Time=4
WaitMove: Caster
PlayAnimation: Char=Caster ; Anim=Idle
WaitTurn: Char=Caster
ActivateReflect
WaitReflect
Hi Charlie_38.
There's no problem. Me and other people have done it without noticing any bug and there shouldn't be any. There would be issues if you tried to load a HWS that was created with HW v0.50b into the older version of HW v0.43, but the other way around is designed to work fine.