ID:775169
 
(See the best response by Deathguard.)
Life_Skill_Update()
for(var/item in Life_Skill_var["Level"])
if(Life_Skill_var["Level"][item] != Life_Skill_var["Previous_Level"][item])
Life_Skill_var["Previous_Level"][item] = Life_Skill_var["Level"][item]
winset(src, "Life_pane_2.[item]_Label", {"text = "[Life_Skill_var["Level"][item]] of [Max_Life_Level]""})
winset(src, "Life_pane_2.[item]_Level_Bar", {"value = [round(max((Life_Skill_var["Level"][item] / Max_Life_Level * 100),1),1)]"})

if(Life_Skill_var["EXP"][item] != Life_Skill_var["Previous_EXP"][item])
Life_Skill_var["Previous_EXP"][item] = Life_Skill_var["EXP"][item]
winset(src, "Life_pane_2.[item]_EXP_Bar", {"value = [round(max((Life_Skill_var["EXP"][item] / Life_Skill_var["Max_EXP"][item] * 100),1),1)]"})

Life_Skill_Level_Up()


Problem:
What I'm trying to do here is update skills in the bar as I train, and save the current variable to another variable and if the two does not equal, it'll update the bar.
When should I call this proc to level up the bar? I think about putting it in Stat() since it calls itself automatically. But if someone isn't training, it'll just be wasting up the space.
Is what I'm doing efficient (speed-wise)?
I don't see where an issue would be speed-wise unless you call it repeatedly and unnecessarily.
As far as when to use it, I would suggest calling it when they gain the experience. For example:
If you have it so that your experience goes up when you kill a monster, after you gain the experience from the kill run the proc.
I don't think it'd be too much of a problem checking it every second or so but it would be a bit of a waste. What Phits has said is probably best.

If you do stick it in Stat or some loop of some kind just stick a sleep(10) in there so at most it only updates every second.

Alternatively you could rethink your design a little bit. You could update your exp with a proc.
This code will update you EXP for one skill, level up that skill if appropriate and then update bars for that skill.
(I'm guessing that once exp>max_exp you gain a level for that item.)
Gain_EXP(var/gain, var/item)
var/EXP = Life_Skill_var["EXP"][item] + gain

if( EXP > Life_Skill_var["Max_EXP"] )
Life_Skill_var["Level"][item] += 1 //level up that skill
EXP -= Life_Skill_var["Max_EXP"] //reduce our EXP by the amount we just 'spent' levelling up

//Our level has changed so we need to update our level bar
winset(src, "Life_pane_2.[item]_Label", {"text = "[Life_Skill_var["Level"][item]] of [Max_Life_Level]""})
winset(src, "Life_pane_2.[item]_Level_Bar", {"value = [round(max((Life_Skill_var["Level"][item] / Max_Life_Level * 100),1),1)]"})

//update our EXP bar
winset(src, "Life_pane_2.[item]_EXP_Bar", {"value = [round(max((EXP / Life_Skill_var["Max_EXP"][item] * 100),1),1)]"})

Life_Skill_var["EXP"][item] = EXP //save our new EXP value.


Note, you'll need something similar to your old code to intitialise each of the bars say, when somebody Login() to their mob.

I really feel your main concern should be your use of lists though. Doesn't that get confusing?
Like I've said, I don't know how your game works so I'm guessing a lot but you could try:
- separate those lists into Level[item] = 42 EXP[item] = 3436368 etc.
- Have Max_Exp as a function calculated by level. e.g.
Max_EXP(var/item)
//every level requires an extra 1000EXP to level up than the previous level.
//Or if a difficulty curve would be preferable, use Level[item] ** 3 or something.
return ( Level[item] * 1000 )


best of luck
In response to Carnwennan
I don't like the design of have subtracting the amount we just spent for exp. That means if I gain 1 million exp, I will then be really high level depending on what the curve of Max_EXP is.

If you do stick it in Stat or some loop of some kind just stick a sleep(10) in there

If I do do that, the update will be delayed, I see a lot of games with that, and it's just a bad design for anything especially if you're doing things in 1/10th of a second.


Life_Skill_Gain( exp_gain, item)
Life_Skill_var["EXP"][item] += exp_gain
if(Life_Skill_var["EXP"][item] >= Life_Skill_var["Max_EXP"][item])
if(Life_Skill_var["Level"][item] < Max_Life_Level)
Life_Skill_var["Level"][item]++
Life_Skill_var["EXP"][item] = 0
Life_Skill_var["Max_EXP"][item] += Life_Skill_var["Level"][item] ** 2
usr << "Your [item] level is now [Life_Skill_var["Level"][item]]"
winset(src, "Life_pane_2.[item]_Label", {"text = "[Life_Skill_var["Level"][item]] of [Max_Life_Level]""})
winset(src, "Life_pane_2.[item]_Level_Bar", {"value = [round(max((Life_Skill_var["Level"][item] / Max_Life_Level * 100),1),1)]"})
else
Life_Skill_var["EXP"][item] = Life_Skill_var["Max_EXP"][item]
usr << "You have capped [item]."
winset(src, "Life_pane_2.[item]_EXP_Bar", {"value = [round(max((Life_Skill_var["EXP"][item] / Life_Skill_var["Max_EXP"][item] * 100),1),1)]"})


Phits wrote:
As far as when to use it, I would suggest calling it when they gain the experience.

I did take in your suggestion, it is unnecessary to call all of them every time.

Carnwennan wrote:
I really feel your main concern should be your use of lists though. Doesn't that get confusing?
Like I've said, I don't know how your game works so I'm guessing a lot but you could try:
- separate those lists into Level[item] = 42 EXP[item] = 3436368 etc.
- Have Max_Exp as a function calculated by level. e.g.

I rather have 1 variable list that associates with everything I got within the same category, rather than a few separate lists or many different variables.

var
Life_Skill_var[] = list(
"Level" = list("Blacksmithing" = 1,
"Cooking" = 1,
"Mining" = 1),
"EXP" = list("Blacksmithing" = 0,
"Cooking" = 0,
"Mining" = 0),
"Max_EXP" = list("Blacksmithing" = 100,
"Cooking" = 100,
"Mining" = 100)
)


Compared to few separate list:

var
Level = list("Blacksmithing" = 1,
"Cooking" = 1,
"Mining" = 1),

EXP[] = list("Blacksmithing" = 0,
"Cooking" = 0,
"Mining" = 0)

Max_EXP[] = list("Blacksmithing" = 100,
"Cooking" = 100,
"Mining" = 100)


Compared to many different variables.

var
Blacksmithing_Level = 1
Blacksmithing_EXP = 0
Blacksmithing_Max_EXP = 100
Cooking_Level = 1
Cooking_EXP = 0
Cooking_Max_EXP = 100
Mining_Level = 1
Mining_EXP = 0
Mining_Max_EXP = 100


I mean they have the same length of variables. But as the coder I want to be able to access all of the variables if necessary at any given time.

if difficulty curve would be preferable, use Level[item] ** 3 or something

Lol, I tried that, but find it to be really hard after a certain level. :P


Thank you both for the suggestions.
I think about putting it in Stat() since it calls itself automatically. But if someone isn't training, it'll just be wasting up the space.

Stat() is generally a bad idea; a given panel should only update if updating it will show new data, so basically whenever something changes that's shown in a panel, you should update that panel.

Rather than having "lists of lists" - which gets kind of resource intensive later when you're iterating over them to pull out information about a particular thing - I'd use a datum instead.

Essentially, a datum is just a custom object used to store data;

Crafting
var
name
maxexperience
experience
level


Then you make all the crafts an object, of the type 'Crafting.' This saves you having to define every variable and handle them individually.
If you're familiar with OO, 'Crafting' is your class and, say, 'Blacksmithing' is an object.
If you wanted, you could store these objects in a list still; But your list would just contain 'Blacksmithing,' 'Cooking,' 'Mining,' and so on, with their inherited variables.
You don't necessarily have to iterate over a list of lists to pull things out.

 List["name"]


If you define a datum, you would have to then make a var for it inside a proc/verb anyway.

var/Crafting/F 
F.LevelUp()


I rather save time and put it under a list. Maybe I just showed the example wrong. Those variables are supposedly under /mob.

mob/Player
var
list[]


To be honest, I'm not familiar with datum and I wouldn't attempt to do it without a proper understanding of it.
Best response
Think of a Datum as an atom with no map location and no associated in-game object. It's actually the parent type of atoms.

Your list would simply store;

var
CraftList = list(
Blacksmithing,
Cooking,
Mining)


Which are instances of Crafting, so you'd define them as such;

var/Crafting/Blacksmithing = new()

and enter them into your list;
SkillsList += Blacksmithing


So your list, once done, will contain Blacksmithing, Cooking, Mining and so on, each of which have their associated variables attached, inherited from Crafting.

So rather than getting "Blacksmithing" in "EXP" in "Life_Skill_var", you'd just get "Blacksmithing" in the players "SkillsList," and then do Blacksmithing.level.

In terms of processor time it's basically an insignificant difference, but in terms of memory and code elegance it's a much better solution.

There's an article on datums here, for reference.
They're really handy to know about; I think 'Use a datum' is one of the more common bits of advice I see thrown around on the forums.
The language is object-oriented, so play to its strengths! =]