FF like ATB battle system

Started by Sephiroth, Mon 13/04/2009 19:22:12

Previous topic - Next topic

Sephiroth

Hello AGS World,

I'm new to ags and would like to says thanks for this great game making software, instinctive ide, nice c++ like syntax allowing almost everything to be done (exept passing custom struct as an argument?).
I've spent a few days trying to get a ff like atb battle system up and now its almost all good.

What's implemented:

- 1vs1 fights (for now)
- Testing gui (basic stuff for display and actions)
- Keep track and display HP/MP/XP/LV etc
- Physical attacks (handling physical_def)
- Crit/Miss chance (using)
- Magic casting (Using a magics table)
- Looting  (Using a loots table)
- Level up (upgrading stats and full heal)


The code for this battle engine is not that complicated and i will gladly help anyone or give explainations, i will also give a link to the demo source code once i have all options implemented and a "user-friendly" clean code :p 

Right now i'd need some help for advanced stuff like xp progression, here is what i have running when the fight ends and xp is given:

*RESOLVED

Happy coding.

The link:
Use spacebar for actions/skip button and escape to cancel submenus.
Using spacebar on the closed door will start a random encounter.

http://www.elistra-systems.fr/Compiled.rar for demo only

First screenie :D

OneDollar

Depends how complicated you want your experience curve to be. A very simple answer is...

RoundDown((1 - (([Current Player Level] - 1)/[Max Player Level])) * Base Monster Exp)

So if your player has a maximum of 40 levels, is currently at level 3 and defeated an enemy of 10 exp, they'd get RoundDown((1-((3-1)/40))*10) = RoundDown(0.95 x 10) = 9 Experience.

Basically I'm expressing the player's current level as a negative percentage of the total level (i.e. 100% is level 1), then multiplying that by a base experience value for the enemy (i.e. the most experience you'll ever get out of them). I'm subtracting 1 from the player's level so that they always get 100% of the base experience when they're level 1, though this means that when they're level 40 they'll get 2.5% of the experience base rather than the implied 0%, whether this is a problem or not is up to you. I suggest you stick the function into Excel and plot some graphs of experience against player level and see if you think it'll work.

Also its your choice to round up, down or to the nearest number, and you might want to put a conditional in to make sure the player always gets at least one experience point.

Sephiroth

Thanks for the quick answer OneDollar, it looks like you are applying a kind of % and it made me think of one way,
If i have:

Level up happens every 1000xp and max xp is 100 000 at lv100 :
Code: ags


current_lv  = current_xp / 1000;  
gained_xp = enemy_xp - ( (current_lv * enemy_xp) / max_lv);



This way the xp you gain is a percentage of the enemy base xp, lv30 will get -30% of the enemy's base xp, lv 8 will get -8%.
So if i have for example:

Code: ags


enemy_xp = 500;
current_lv = 25;  // max is 100 but it works fo any number

gained_xp = 500 - ( (25*500) / 100) );
gained_xp = 500 - 125;
gained_xp = 375;



Maybe you were thinking about the same thing but i didnt get it sorry i'm so bad at maths and i'm french so it's even harder to get everything you told me...
Do you think it is appropriate? I just want it to look like xp gain is decreasing as you level up to avoid farming the same mob over and over and get the same xp whatever your lv is, thanks again.

Trent R

#3
What you should could do is search GameFAQs for a 'Game mechanics' guide for your favorite RPGs. These will tell you the formulas that are used for stat increase, attack damage, gaining experience, and so on and so forth.



~Trent
To give back to the AGS community, I can get you free, full versions of commercial software. Recently, Paint Shop Pro X, and eXPert PDF Pro 6. Please PM me for details.


Current Project: The Wanderer
On Hold: Hero of the Rune

Sephiroth

Well i just did, thanks, it helped me to find some clues but my goal is to have simple formulas and stats upgrade yet not too obvious to the player, i think i'm gonna use some tricks.

Dont misunderstand me i'm not a genius when it comes to maths but i'm quite good as a coder so i'll do it the tricky way not because i dont give a damn about your advice, heh, but because i'm so close to the end i dont want to rewrite everything from scratch to implement a complex engine that will take ages to understand. And because i need to release a working demo soon so the others can start working on puzzles.

All the battle engine works and i just have this part left, i will update the first post with the source and demo as soon as it's available if anyone wants to have a look it will of course be the battle system of our upcoming FF fan game (rpg) but you'll probably hear about that later, we have done a lot but not enough to post in the GIP forum yet ;)

OneDollar

Quote from: Sephiroth on Mon 13/04/2009 21:33:39
Code: ags

current_lv  = current_xp / 1000;  

I presume this line means set current_lv to current_xp / 1000 rather than current_lv is current_xp / 1000? Otherwise your level will change even when you get 1 experience point. You need to do some rounding or checking, something like
Code: ags

while (current_xp <= 1000) {
  current_xp -= 1000;
  current_lv ++;
}


Anyway, the rest of your code works out pretty similar to mine, except remember you'll be generating decimal values so you'll have to round the experience one way or the other.

If you've got Excel I made a spreadsheet comparing the two while checking my formula...here

Sephiroth

This is intresting, it looks like the reason why my graph is so regular is the lack of rounding, and actually the formula is executed on decimal values as you said but the raw display of the stats on the gui is actually rounded:

String.Format("XP : %d", current_xp);

:o I totally forgot the decimals would be added to xp and saved with SetGlobalInt() regardless of the displayed values. You're right i should use RoundDown(formula), this way i'll prevent the decimal influencing the xp curve and offer a decent progression to the players.

Thanks for your time and help!

Pumaman

You don't need any rounding code, assuming that current_lv is an int then it will be rounded down automatically.

Sephiroth

#8
Ok i see, but the formula uses a float var to store the result, on the other side i'm keeping track of the variables via SetGlobalInt that will propbably truncate the value when changing its cast as if it worked like  SetGlobalInt(id, (int)float_var); is that right?

Pumaman

Why are you using SetGlobalInt? It's obsolete and pretty unfriendly and confusing to use; create an int variable using the Global Variables pane instead.

But yes, if current_lv is a float then you will need to round it (though FloatToInt will do this for you anyway).

Sephiroth

Damn.. i didn't even notice the global variable pane, it's been a week since i discovered AGS Editor and i thought this was the only way to use globals, thanks for the tips.

I was also wondering, this will be my last question sorry... if i declare an array of anything for example Character Charz[10]; the bounds will actually be 0-9 and trying to use index 10 will give an access violation at runtime. I guess the interpreter applies the -1 to get the exact number of spots you specified including id 0.

-Sephi

Trent R

Extremely watered-down version: Most all programming languages initialize starting with 0, but you still end up with 10, right? You just have to just get used to it. Also, remember that 0 is often different from null.


~Trent
To give back to the AGS community, I can get you free, full versions of commercial software. Recently, Paint Shop Pro X, and eXPert PDF Pro 6. Please PM me for details.


Current Project: The Wanderer
On Hold: Hero of the Rune

OneDollar

Quote from: Sephiroth on Thu 16/04/2009 04:43:33
if i declare an array of anything for example Character Charz[10]; the bounds will actually be 0-9 and trying to use index 10 will give an access violation at runtime.

It's slightly confusing, but basically when you define the array you specify how many 'slots' to use, in this case 10, but the first slot is actually called slot 0. So you define an array of size 10 which contains indexes of 0 to 9.

Khris

Once you get used to it, you'll find it's more convenient though.
E.g. pixels on the screen start at 0,0; and using a one-dimensional array two emulate a two-dimensional one is easier, too.

Sephiroth

Maybe i expect a similar syntax and compiling than with cpp, if i say Character Charz[10]; i ll have 11 slots including 0 but i get why the author chose to simplify the arrays indexing.

What i don't really get is, I don't know if this is limited or i don't have the right syntax but i can't use a custom "struct" as member variable it returns an error:

Code: ags

struct CMagics
{
 int id;
 int mp_cost;
 (...)
};

struct CBattle
{
 CMagics Magics[10];
 import static function LoadMagics();
};


"Member variable cannot be struct" or
"Cannot declare pointer to non-managed type"

Instead i have to declare CMagics magics[10] as a global in the .asc file to use it, maybe i have to declare the CMagic struct in another ash?

Khris

Unfortunately, what you're trying to do isn't supported yet, correct.
Struct members can't be structs themselves.

Sephiroth

Heh this is where i become nit-picky, i can actually use what the compiler calls "managed type" in a struct. for example i can use Character *c1; and use its inherited variables so maybe there's a way to declare my custom struct as a managed type maybe like: _managed_type struct Foo{ }; or maybe not but i must say i kinda missed this feat.
Thx for all the explainations.

-Sephi

Trent R

Structs within structs, and pointers to structs have been requested many times, and will be coming eventually. As of right now, you can only declare pointers and struct members of managed types, ie. predefined AGS types (characters, objects, hotspots, items, etc). This is because of how AGS handles garbage, and there have been ideas on how to implement the suggestions above.


~Trent
To give back to the AGS community, I can get you free, full versions of commercial software. Recently, Paint Shop Pro X, and eXPert PDF Pro 6. Please PM me for details.


Current Project: The Wanderer
On Hold: Hero of the Rune

Pumaman

Quote from: Sephiroth on Thu 16/04/2009 14:30:49
Maybe i expect a similar syntax and compiling than with cpp, if i say Character Charz[10]; i ll have 11 slots including 0 but i get why the author chose to simplify the arrays indexing.

AGS is the same as C++, if you declare an array [10] in C++ you also get slots 0..9.
The difference is that since C++ doesn't perform any bounds checking you can access element[10], or element[11], even element[99] if you like and you probably won't get any errors but will be corrupting memory.

Quote
What i don't really get is, I don't know if this is limited or i don't have the right syntax but i can't use a custom "struct" as member variable it returns an error:

As Khris and Trent have said, this is not yet supported. It's a feature that has been requested but due to the fact that most people who use AGS aren't advanced enough at scripting to need it, it's actually a fairly low-priority "advanced" feature request.

Sephiroth

Pumaman: I'm so dumb, and i feel ashamed now. I always considered arrays index the way i described, but the worst is that i always use (max-1) inside for loops without knowing why ( i checked my old codes in the panic :p ), at least i'm a bit less stupid...

I also understand why it's not high priority to implement those feats, and there's no problem getting things done without it so there's no rush i guess. But it would be nice so please add one more vote if it has any value, regards.

SMF spam blocked by CleanTalk