Show Posts

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

Messages - Tirlititi

Pages: 1 [2] 3 4 ... 25
Misc. Tools / Re: [FFX] Skill editor - Ronso (v0.3.1.0)
« on: 2019-06-01 19:48:10 »
The fact that it can be done doesn't mean that it would be easy. It can be way harder to do it for FFX because, indeed, of different data structures.

However, Husbjörn said that he plans to do something similar if he has time:
I have some new ideas for a more in-depth kind of editor actually (as well as have managed to figure out a working way to alter enemy data of the Steam version at load time), just not the time needed to realize it. Hopefully one day...
To me, that looks the closest you can get to a game patcher that actually uses RAM modifications (and it would be goddamn useful). It's not the same kind of tools normally.

Please, let your respect for the modder take the shape of patience :)

That seems correct.

1) You're using the Steam version, right? It doesn't work easily on the PSX version (though it should work if the animations are the standard ones).
2) Check that you added this function to the correct entry: it should be the 7th entry after Zidane's entry (for instance, if Zidane is the entry 11, Blank should be the entry 18). In particular, this "Blank_Init" function should be displayed below Zidane's functions.
3) In the "Edit Entries" window, check that Blank/Amarant's entry is properly set to a "model entry (2)". They are sometimes defaulted to "255" when they are not used.

What did you put in Blank's Init function?
It should look like the example I gave here for Beatrix (you need to change the position, the model ID and its animation IDs and add the "DefinePlayerCharacter" line).

@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.

That's because the .hws is in the separate download.
For the latest release, I separated the mod itself and its source files, to avoid confusion when installing it.

Yes, it is necessary to use dnSpy (or mod the source code using Memoria, but that's C# all the same).

When I write about editing C# code (or CIL code), I write about classes and method with the format "class::method". That means that you need to find the class in the list shown by dnSpy and then find the method inside that class. Namely, the classes of interest here are "btl_init" and "BattlePlayerCharacter".

@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.

There is no hard-coded polygon limit so I guess the problem doesn't come from there. There is no reason for the engine to discard big models if they are valid.

@ToraCarol: Yes, that's the main point of my previous message.

Here is how it works. It's pretty simple:
1) In the class "btl_init", the array "model_id" contains the list of the player character's models:
Code: [Select]
Zidane (2 of them),
Dagger (4 of them),
Steiner (2 of them),
Eiko (2 of them),
Blank (2 of them),
Zidane Trance (that's the 20th, at index 19 and there are 2 of them just like the regular),
Vivi Trance,
up to Amarant Trance.
Which makes a list of size 19 (regular) + 14 (trance) = 33 models.
These are different model names but I think that they mostly use the same mesh files and the different names are meant to link to different animations (but I'm not sure, that's what I remember about). Anyway, the duplicates are because of the different fighting stances when using, for example, thief daggers or thief swords. Dagger also has her long/short hair versions.
About Steiner, I think the difference has to do with a flag that can be activated in the "Battle" and "BattleEx" script codes, but it's a dummied feature and never actually used.

2) The methods "BattlePlayerCharacter::CreateTranceModel" and "btl_init::SetBattleModel" setup the models at the start of the battle. They create both a regular and a trance model/skin for those who have it and hide the trance version. The condition is simply "if ((int)(serialNumber + 19) < btl_init.model_id.Length) // add a trance version" for both methods.
Note that there is a duplicate of the regular model list, "BattlePlayerCharacter::PlayerModelFileName" for some impractical reason. The lists used are thus:
- "BattlePlayerCharacter::PlayerModelFileName" for the regular model and "btl_init::model_id" for its skin (geotexanim),
- "btl_init::model_id" for the trance model and its skin.

3) When creating a trance model, the animations are entirely taken from the regular model so you don't need to care about it (but the trance model has to have exactly the same bone hierarchy as the regular one). I suppose that there is no problem in taking the same "geotexanim" as the regular one or even don't use geotexanim at all (I don't really see a texture animation on battle models, except the trance glowing but that's handled automatically elsewhere).

4) In HW's "Party -> Stats" panel, there's some setting to do in order to have a proper trance command.

5) Characters have a trance gauge if they are not setup with category "temporary character" in the script code initializing them ("SetCharacterData"). Also, trance gauge is disabled early game and for Dagger when she's depressed.

6) Also, another array must be extended for Beatrix. In the method "btl_stat::SetStatusVfx", which mostly takes care of glowing effects (and floating/confused but we don't care there), you can find an array like that
Code: [Select]
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:
Code: [Select]
new byte[] { 255, 160, 128 }
In conclusion
In order to add a properly working trance to Blank, Cinna, Marcus or Beatrix, you need to do 3 things:
• In HW, setup a trance command for the character (define it in the panel "Party -> Commands" and give it to the character "Party -> Stats"; remind that Beatrix has 2 ability sets),
• In HW, remove the "Temporary Character" category of the character(s) you want to give trance to. It's in the "Environment -> Fields" scripts, when the characters join the team, there are lines "SetCharacterData" to tweak a bit. For instance, Beatrix's character data is initialized twice:
-- in the script "A. Castle/Queen’s Chamber" (one of them anyway, there are several ones... the good one has "Bandersnatch" functions in its script), whithin the function "Beatrix_Loop", there's a line "SetCharacterData( 8, 1, 11, 22, 14 )" near 4/5 of the function.
-- in the script "Alexandria/Square" (the one at night), whithin the function "Steiner_Init", there's a line "SetCharacterData( 8, 1, 13, 22, 15 )". In both cases, the change should be replacing the argument "22" by a "6" to remove the "Temporary Character" category.
• In dnSpy, append 5 lines to "btl_init::model_id" by giving trance models.
-- Either use the exact same models as the regulars (ie. append "GEO_MAIN_B0_013", "GEO_MAIN_B0_014", "GEO_MAIN_B0_015", "GEO_MAIN_B0_016" and "GEO_MAIN_B0_017" to the list): the only difference will be the glowing,
-- Or use another existing model and the same bone hierarchy (the correspondances between "model name" and "model numerical ID" is in the dictionary "FF9BattleDB::GEO"),
-- Or find a way to import a workable new model with the right bone hierarchy and register it in both "FF9BattleDB::GEO" and "btl_init::model_id". I have been unsuccessful to import a workable model, as the files added to the archives require a lot of registering and linkage and I apparently miss some (I don't remember if I successfully imported a new texture with the Unity Assets Viewer...).
• Still in dnSpy, append 1 entry to the local array that can be found around the middle of "btl_stat::SetStatusVfx".

No sorry, I don't know how Ze PilOt did for the music. It may be only music files in the archives or it may use features of Memoria (which is not compatible with Hades Workshop most of the time).

@eugene9: I warned you it wouldn't work for most animation swaps... Since the animation is not fitted to the model, no animation is played.

@ToraCarol: It's also the same "IsMovementEnabled" check. Since you don't have the control during the transition, the script stops.
I would say, the best is to add this line in the field transition script ("RegionX_Range" most of the time):
Code: [Select]
set VAR_GlobBool_247 = 1And in the following loop:
Code: [Select]
if ((IsMovementEnabled == 0) && VAR_GlobBool_247) {
    InitWalk(  )
    Walk( GetFieldExitX, GetFieldExitY )
"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).

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.

This message describes how to install AF with Moguri's mod.

@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.

@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).

About a character following another one, you should look at the script of Beatrix in Alexandria and inspire yourself from that.
The important code is this loop:
Code: [Select]
        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(  )

About the victory pose, it's the script code 0xDB (I just learnt that).
"0xDB(0, 1)" enables the victory pose of Zidane.
"0xDB(0, 0)" disables the victory pose of Zidane.

I have to reinstall things to test for separating the slots of Eiko and Marcus. Too bad it's not working for you, TheHobgoblin, you seemed to do things pretty well.

About the menu's UI size, you can try to edit the C# source code of the menu and use something like that:
Code: [Select]
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 the item limit in shops, I'm not sure of what is wrong... That might have been broken because of a Steam update a long time ago?
Anyway, you can change the sold items in shops by modifying the C# code (using dnSpy). It's the field "FF9/ff9buy::_FF9Buy_Data" (it consists of a list of item IDs either of maximum size 32 or ended by the null item 255).

About the Android version, there are a lot of things in common, provided that you can unpack the .obb archives (I don't remember how to do that). For instance, the "sharedassets" archives (yes, that's archives inside other archives... I don't chose the rules) is in the folder "assets\bin\Data" and the engine's source code is in "assets\bin\Data\Managed\Assembly-CSharp.dll".
There should also be "a0dataXXX.bin" equivalents of the Steam's "p0dataXXX.bin" somewhere... This prefix is "i" for iOS and I don't know if the PS4 and Switch versions have different formats.
The class "AssetManagerUtil" shows how different versions are handled. I don't think that the difference between the platforms are so big, but they may be non-trivial.
In any case, it would require some (a lot?) of work to mod the other versions, both for updating HW and for converting the non-PC games to suitable files.

About the list of abilities, all the characters have exactly the same number of (learnable spells + supporting abilities).
The only way to add more spells (= active abilities) without changing a lot of the game's engine is to remove supporting abilities to counter-balance. It's in the "Party -> Stats" panel.

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 and make sure that the option "Automatically Convert 3D Models -> Import Meshes/Materials" is disabled.

About the eyes animations (both for the characters and for the last battle's structure), it's a bugging feature of the Steam port. I don't know what happened but they apparently rewrote this part of the source code and it's not doing the same as the PSX version. I've no idea of how to fix it. There may also be a problem when the textures are upscaled, as Incinerator says (I've not done any test about that).

About the World Map bug, it's a bug of Hades Workshop, explained here. Sorry about that. The good thing is that it is fairly easy to fix (your mod files are not corrupted or anything).

Sorry answering so late.
Thanks a lot for answering each other.

Hello and thanks Euron-Crows-Eye,

You can switch from vanilla to Alternate Fantasy back and forth with little to no problem. The only things that can happen is that you learned in AF an ability that was not meant to be available in the normal game, or find an piece of equipment or things like that. Also, if you have Beatrix in your team in AF, you keep her when you switch back to the normal game which is fine in most situations but may freeze a couple of cutscenes (same problem when you hack her in the team with Gameshark/CheatEngine).
This message describes how to install AF with Moguri's mod. It is a bit tedious and the Assembly-CSharp.dll is indeed the trouble-maker. I may update my tool Hades Workshop to be able to directly export mods compatible with the Memoria tool but I don't promise anything as I am on a long break about modding.

Completely unrelated / Re: Article 13 Passed
« on: 2019-03-27 23:03:19 »
You cannot reproach DLPB for not accepting the rules of the democracy and then reply to me that too much democracy would be bad because of how poorly educated the people are. That's a logical flaw ;)

Btw, why would you want to use the expression "for the greater good" that could make you pass for a Harry Potter villain?

Completely unrelated / Re: Article 13 Passed
« on: 2019-03-27 21:47:31 »
And if you have a better idea than free, open vote and secret ballot paired with seperation of power... :)
Let's say... free, open vote and secret ballot on law proposals (instead of being forced to give this power to chosen representatives).
What about it? :)

@ToraCarol: I told you to disable the line "InitRegion( 8, 0 )" from the "Main_Init" function because I thought you wanted to make a cutscene (not a playable sequence). Put that line out of the "if" block if you want the region to work even with Blank.
Note that you'll get back to have Zidane as soon as you leave that field. In order to keep Blank along the fields, you need to edit the following fields as well.

Making a cutscene/playable sequence is not easy at all in any case. Make sure you understand the changes I suggest and if you don't, ask why I suggested them. It may be a slow learning process but you'll eventually understand scripts and know what to do.

@TheHobgoblin: All your problems come from the fact that the Steam version is basically a port of the old PSX version to more modern machines. The source code of the PSX version has been turned to a C# code with only the strict minimal changes required (how they handle images, 3D models, menus...). The basis of the code's structures (and a lot of the game's raw data) is a copy of how things worked on the PSX version.

So, the things you want to do are possible but not with Hades Workshop. I think that Memoria's "enable all characters" option doesn't allow to have both Marcus and Eiko in the team at the same time. The list of characters you printed is accurate and that's what needs to be changed if you want no restriction.

Also, I warn you that editing the game's UI (the way the menus look) is something on which we had only partial results. I'm not sure of what could be the resulting display of the "Choose your party's characters" menu after all the changes.

You need to edit the game's source code. You may do it with the devs' version of Memoria but also with a generic tool that is called dnSpy (if you work on dnSpy after doing the changes in HW, you can use both as I did for Alternate Fantasy).

In dnSpy, open the DLL of the game "Assembly-CSharp.dll". You'll see the list of classes (a structure of data) and their methods (an operation related to that class). If you know C# programing, it will be much easier (it's C# both for Memoria and dnSpy) but a few things can be done quite simply.

1) The total number of spells in the commands' sub-menus.
This is can be modified in the class "rdata" (in dnSpy, that's in the folder "{} -").
You should already see a bit how command datas are initialized in that class. That's exactly the part of the source code that is modified by HW when you edit some commands or stats (except there you'll mostly deal with numbers).

The error "You cannot add spells to the list anymore" refers to the value of "_FF9FAbil_ComAbil". Find where it is defined and "right-click -> edit the method/class" to change it.

It works like this: "_FF9FAbil_ComAbil" is the list of all the spells that are inside a command menu (side note: the terminology between HW and the C# code can differ as I've started developping HW for the PSX version without any access to the source code ; the "spells" of HW are called "Abil" or "Active Abilities" in the C# code). On a non-modded file, it starts with Dagger's Summons (49 is Shiva, 51 is Ifrit...) and continues with Dagger's White Magics (1, 2, 3...).
Simply add a few entries at the end of the list with the spell IDs you want to give.

A bit above that, you have the initialization of "_FF9FAbil_ComData". It's all the commands in the same order as what is displayed in HW.
Dagger's White Magic, for instance, is initialized like this:
Code: [Select]
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).
The third number, if I recall correctly, is a code for the help dialog's width and height. I think it is also ignored (the bubble size should be auto-computed on the fly).
The 4th number is the type of command. Here it is a command containing several spells (1).
The 5th number is the number of spells inside that command.
The last number is the starting point of the commands in the "_FF9FAbil_ComAbil" list. Here it starts at the 8th spells (the 1, 2, 3... from before).

If you want to use the spells that you added at the end of the list, put 192 as that last number.

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.

You can use the Unity Assets Viewer and open the archives p0data61, p0data62 or p0data63: it's the archives containing the sounds and musics.
Right-click on the sound/music you want to replace and export it. It should convert it to a readable OGG file. Replace that file (where it was exported) by another OGG file and then, in the UAV, right-click on the sound/music and import it back.

You should be able to add a new music/sound, but it requires more work: listing it in a soundmetadata.txt (in the archive resources.assets) and making the source code use it (using dnSpy to modify the Assembly-CSharp.dll).

@Zara9: I can't help you; I don't know what you are doing (and so what you are doing wrong).
There is a .hws example in the description I linked in my last message. Have you tried it?

Adding an enemy in a battle requires a bunch of things. Have you done everything I wrote in that message?

@resinate: No, it's not accessible from the PSX version. Only the Steam version allows to modify its source code.

@ToraCarol: The missing death sounds is just a single file to import in the "resources.assets". You can get it there for instance. It can be imported either in your "resources.assets" before doing your stuff with HW or after generating the modded files, it doesn't matter.
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.

Apparently, the water effect is handled by the different functions "Code1_Loop", "CodeN_11" and "CodeN_12" (with N ranging through 2, 3 and 4). They are SPS effects.
The problem is that they are specifically made for Zidane (ObjectUID_10). You can change every instance of "ObjectUID_10" to "ObjectUID_250" in these functions: it will refer to the party's character (so Zidane most of the time and Blank in your modifications). It would be more difficult to have two characters in the water at the same time apparently.

@resinate: Dagger also has 2 serial numbers but they are not handled differently than the others.
The variables "VAR_GenUInt16_19" have nothing to do with it. You can easily remove the "if" line so this variable doesn't appear anymore.
This lol FF9Play_Change is part of the game's source code. dnSpy is a tool that can omg access to this code and change it.

Your last post is incomprehensible. Please make some effort.

@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.

I've double-checked what the "update level" option does and it can't be used to level down the characters...
Code: [Select]
if (update_lv) {
int num = ff9play.FF9Play_GetAvgLevel(slot_no);
int lv;
if ( == 10 || == 11)
lv = num;
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.

In the Steam version, you can use the tool dnSpy (or even HW's CIL code modding for this) to edit the code above and remove that "take the max" line. It's in the class "ff9play" and its method "FF9Play_Change".

@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.
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, ... )".

Pages: 1 [2] 3 4 ... 25