ID:1904850
 
(See the best response by Ter13.)
Ok firstly i apologize if i'm posting quite a lot on here but I'm really getting into BYOND code and are super excited to be able to actually make something I can imagine using OO design, even if i'm not that good at it.

I've run into a problem juggling variables in my combat system, which its burning a hole in my brain.

I was wondering if any of you guys could give me some advice on how to handle something like this?

let me explain it a little, ill try to keep it short and simple (if i can);

1. Combat is based on "Effective Stats" which are calculated by "Base Stats" + "Boosted Stats"

2.You gain an obj/ability which is controlled by the hud and when used equips an obj/item on your character, what this item does is call a proc that works differently based on that item name, which changes on player choice and they cant change it while boosted.

3. Depending on what that item name is your "Boosted Stats" will be different.

3. You can spend points while boosted to upgrade your "Base Stats", here is where the issue starts.


The issue i'm having is that way I made it handle the variables, when the proc first runs it takes at that time the "Base Stats" and calculates what to add to the "Boosted Stats" however, you can change your "Base Stats" while you are still boosted and when it goes to remove the "Boosted Stats" It can remove way too much.

stat changes are calculated by doing the opposite of what the boost does which is;

usr.BoostedStats += usr.BaseStats * 2 //This is boosting the stats

usr.BoostedStats -= usr.BaseStats * 2 //This is what deboosting the stats


If the base stats have changed, when you go to deboost the value will be different from when you boosted. Making it cut away at another boost you have on or shave away all of the "Boosted Stats" value.

Not sure if i'm thinking about it too much, but the only soloution I could come up with is to make a ton a new tmp variables. Which I want to try and avoid.

How would any of you handle something like this?

Thanks in advance! (Sorry for the wall of text :(, i tried to shorten it. I really did!)
Well it's really all a numbers game, right?

Really I'm opposed to stats in general because I feel like they create stale gameplay. You're just looking for the things with the highest numbers. If you balance around base skills/effects I feel like it creates a nice environment.

As for your question itself, I personally never add stats like that. If you want to to stick to that, you should find a way to always add/subtract the same amount. Always add by the base stat

So if something added 10% of your damage and you had 100 damage

100 + 0.1 * 100 = 110
(or if you prefer, 11/10 * 100 = 110)

But wait, you leveled up and got 20 damage. Now you have to refresh your stats to make sure they're added properly

RefreshStat()

Now your stats are:
120 + 0.1 * 120 = 132
(120 * 11/10 = 132)

Okay, your buff ran out. Run the reciprocal of 11/10 on it (or 10/11)

132 * 10/11 = 120

All you need is to understand fractions. Boom.

EDIT: May want to make sure you utilize floor/ceil functions so you always get integers. I think there's a snippet which forces integer functions.
I also think that just "Stats" makes a stale game, which is why that the difference between low/high amounts isnt that much and it only takes up a small section of the game.

I used stats so that people could build their characters differently and try out different things. Having small amounts of bonus damage here and there. And the math geeks love it!

Unfortunately my issue isn't about fractions its about the proc that changes boosted stats being called when base has a different value.

Example
BaseAttack = 10
BoostedAttack = 0
EffectiveAttack = 0

Boost()
BoostedAttack = BaseAttack*20/10
EffectiveAttack = BaseAttack + BoostAttack

Result;

BaseAttack = 10
BoostedAttack = 20
EffectiveAttack = 30


Now say a player upgrades their attack stat so now its like this;

BaseAttack = 20
BoostedAttack = 20
EffectiveAttack = 30


So when the proc calls to undo the boost this happens.

BaseAttack = 20
BoostedAttack = 20
EffectiveAttack = 30

DeBoost()
BoostedAttack = BaseAttack*10/20
EffectiveAttack = BaseAttack + BoostAttack

Result;

BaseAttack = 20
BoostedAttack = 10
EffectiveAttack = 30


It doesn't reset back to 0 and I cant just get it to do BoostedAttack = 0 incase there are other buffs running at the same time.

I could probably fix this with a bunch of tmp/vars but if was wondering if there was a different way to do this without that.
Or you could just refresh all the stat changes (like I noted above) and subtract the correct value.
Best response
My advice would be to store the amount that the boost added.

boost
var
str_multiplier = 1
def_multiplier = 1
spd_multiplier = 1
str_mod = 0
def_mod = 0
spd_mod = 0
proc
Enable(mob/m)
if(str_multiplier!=1)
str_mod = m.str
m.str *= str_multiplier
str_mod = m.str - str_mod
if(def_multiplier!=1)
def_mod = m.def
m.def *= def_multiplier
def_mod = m.def - def_mod
if(spd_multiplier!=1)
spd_mod = m.spd
m.spd *= spd_multiplier
spd_mod = m.spd - spd_mod

Disable(mob/m)
m.str -= str_mod
m.def -= def_mod
m.spd -= spd_mod
str_mod = 0
def_mod = 0
spd_mod = 0

Update(mob/m)
Disable(m)
Enable(m)


That should solve the issue of taking away the wrong amount of stats. If you want the boost to be updated when the player changes their stats, just disable the boost, then enable it again.
Okay just had an epiphany!

Both Ter and Lugia gave me an idea!

Instead of this proc changing the BoostedStat, I could have another proc called BoostedCalc() run when the stat window is active!

BoostedCalc() Would add the multipliers and Base Stats together. The multipliers will now be set by another proc aka the old Boost()

That would mean that BoostedStats would update if Base ever changed and it could remove the correct amount.

But I was wondering if this has a huge impact at all, not sure how often the Stat() window updates.

Does Stat() update every time a value changes or on a tick?

And would it working out 4 different stats effective and boosted values have that much of an impact?
Stat() is called every tick if defined unless you sleep the current proc.
Calling a proc whenever you need to recalculate the stats is likely the best approach. You could simply call it whenever:

- A level gain impacts the base values
- A buff/debuff is applied
- A buff/debuff is removed (or times out)

All you'd have to do is keep track of the current effects that could influence your stats, which could be as simple as a list of intrinsic properties and going through your equipment.
Not sure if I should make another post on this question. Let me know and I will but.

What are the pros and cons for performance with dreamdaemon?

Is it better to use more memory with constant stat checks vs more lines of code which would use up more cpu and hard disk space?

Its probably such a small difference that it doesn't matter but my OCD would be satisfied.

I can imagine its almost always better to use more CPU/HD until the program starts to get really big.

EDIT: Also realized that memory is processed by the CPU, so its almost always better to have more code. Until it gets ridiculously massive.
Having more code doesn't really matter except when it comes to project maintenance. The less code you have, the better because it can make refactoring and bugfixing a lot easier.

Memory usage is something that I really don't worry about very much. If you hit memory limits, your approach needs reworking. IMO, you should only use as much memory as is necessary, but you can save a lot of CPU by jamming stuff into memory rather than recalculating it all the time.

CPU usage is going to be your biggest problem that you need to worry about. If you are doing polling updates every frame, there's probably a better way to deal with stuff.

As for "the best way", I think the best way is to get it working first, then worry about all the above stuff later.
I don't believe the "get it working, then fix it" approach. It's much easier to streamline code when the streamlining is part of the process, not an afterthought.
Using datums for stat would be a lot better, kinda like ter suggested, would be an easy way to keep track of whats boosting what and an easy way of taking boosts off one by one
Yeah, people are always giving me the "if I cache all this stuff doesn't memory usage go way up?" -- I always reply the same "no, not way up, but yes, it goes up, but you're gonna have a whole lot more memory to play with than CPU resources"
In response to DaGilbert
DaGilbert wrote:
Not sure if I should make another post on this question. Let me know and I will but.

What are the pros and cons for performance with dreamdaemon?

Is it better to use more memory with constant stat checks vs more lines of code which would use up more cpu and hard disk space?

Lines of code are a relatively meaningless stat; programmers have such different styles that it doesn't say much, and sometimes really elegant, fast code might take a lot more lines than something simple that performs poorly.

What you typically want to focus on is CPU usage. Anything to make the game faster within reason, you should do. Recalculating a stat only when something that could possibly affect it changes is a wise thing to do. Recalculating it constantly, usually not so much.

I can imagine its almost always better to use more CPU/HD until the program starts to get really big.

You're comparing apples and oranges. Memory and hard drive space are typically resources you trade off for performance. CPU usage tends to be higher for algorithms that use less memory, as a general rule. There's always a balance to be struck.

Usually the only time to worry about memory is if you're working with something that could scale very badly. For instance, BYOND does a lot to optimize the memory used by turfs, understanding that most turfs are uninteresting beyond their appearance vars, density, etc. With objs, mobs, and areas, of which it typically has fewer, it's more direct.