ID:2187919
 
(See the best response by Ter13.)
Code:
mob
proc
skillCall(i)
switch(i)
if(1)
skillUse(skillOne)
skillUse(i)
switch(i)
if("Skill One")
if("Skill Two")
// etc


Problem description:
You have 5 variables - skillOne, skillTwo, et cetera. These are defined when you pick a character. The reason I don't wish to use a verb for this is because I can not change the name at run-time, though feel free to let me know otherwise (or, if I can just use a verb and have a proc just append "On Cooldown" to the end of a name).

I am wondering if there is a better way of doing this.

Best response
Quick runthrough:

Skills - singleton datums stored in a global associative list (indexed by skill.id, a unique string)

Cooldowns - a list of cooldown ids and the world.time value of the end of the cooldown.

mob
var/tmp
list/hotbar = list() //a list of skill datums (saves as a list of strings)
list/cooldowns = list() //a list of cooldown_ids and time offsets
proc
hotkey(n) //call to use a skill in hotkey(n)
var/skill/s = hotbar[n]
if(s)
s.Use(src)

Write(savefile/F) //when written to a savefile
..()
//convert the hotbar list from /skill datums to strings (skill.id)
var/list/l = list(), skill/s, time = world.time
for(var/v in hotbar)
s = v
l += s ? s.id : null
F["hotbar"] << l

//convert the cooldown list from world.time format timestamps to offsets by subtracting the current time from them. Also don't save any cooldowns that are expired already.
l = list()
for(var/v in cooldowns)
if(cooldowns[v]>time)
l[v] = cooldowns[v]-time
F["cooldowns"] << l

Read(savefile/F) //when loaded from a savefile
..()
//convert the hotbar list from strings to objects from the global skills list
var/len = hotbar.len, sid
for(var/count in 1 to len)
if(sid = hotbar[count])
hotbar[count] = global.skills[sid]
//convert cooldowns back to offsets by adding the current world time to them
var/time = world.time
for(var/v in cooldowns)
cooldowns[v] += time


var
skill_manager/skill_manager = new() //creates this datum before the world initializes
list/skills = list()

skill_manager
New()
//create and store one of each skill before world startup
var/skill/s, sid
for(var/v in typesof(/skill))
s = v
if(sid = initial(s.id))
global.skills[sid] = new v() //store them by id for later lookup

skill
var
id
cooldown_id
cooldown_time = 0
global_cooldown = 0

mp_cost
sp_cost
proc
canUse(mob/user,free=0) //call to check if this skill can be used
var/time = world.time
if(global_cooldown&&user.cooldowns["global"]>time)
return 0
if(cooldown_time&&user.cooldowns[cooldown_id]>time)
return 0
if(!free&&(user.mp<mp_cost||user.sp<sp_cost))
return 0
return 1

Use(mob/user,forced=0,free=0) //call to use the skill
if(forced||canUse(user,free))
Used(user,free)

Used(mob/user,free=0)
var/time = world.time
user.cooldowns["global"] = time+global_cooldown
user.cooldowns[cooldown_id] = time+cooldown_time
if(!free)
user.mp -= mp_cost
user.sp -= sp_cost




Example usage:

Skill datums are polymorphic in nature:

skill/fireball
id = "fireball"
var
list/rank_missiles = list(/obj/fireball1,/obj/fireball2,/obj/fireball3,/obj/fireball4,/obj/fireball5)

Used(mob/user,free=0)
..()
var/rank = user.skills[id]
missile(rank_missiles[rank],user.target)
user.target.takeDamage(25*rank,user)
for(var/mob/m in obounds(user.target,8*rank))
if(user.isEnemy(m))
m.takeDamage(10*rank,user)


Expand on the skills polymorphically rather than just building all the behavior into the single skill datum.

A few notes here. The reason I'm modifying Read() and Write() is so that you can save cooldowns, as world.time starts from 0 every time the server starts. I'm also changing the hotbar list. The hotbar list stores /skill datums, but you don't want to save them, because they might change, or even be removed! Loading an invalid object prototype is a recipe for disaster.

Instead, we save the string id of the skill, and on next load, we convert it back into an object based on what skills are in the global list.

Pick through this at your own pace. It might seem complex, but it's actually all very simple.
In response to Ter13
Thanks for all your help!

One thing, though - how would I handle skill descriptions? I was going for something like this.

http://i.imgur.com/KnCbOzN.png

Simply displayed in a tab that shows whether they're on cooldown or not, and what they are called and do.
If you are using statpanels:

skill
var
name
desc

mob
Stat()
if(statpanel("skills"))
var/skill/s, cd, time = world.time
for(var/count in 1 to hotbar.len)
s = hotbar[count]
stat("[count]",s.name)
stat("",s.desc)
if(s.cooldown_time)
cd = (max(cooldowns[s.id],cooldowns["global"],time) - time) / 10
else
cd = (max(cooldowns["global"],time) - time) / 10
if(cd)
stat("cooldown:","[round(cd,0.1)]s")
else
stat("","ready!")
In response to Ter13
Well then, thanks for all your help!
In response to Ter13
I do have two last things to add, though.

I am getting a runtime error, first of all -

runtime error: Cannot read /skill/fireball (/skill/fireball).name
proc name: Stat (/mob/Stat)
source file: Variables.dm,21

        if(statpanel("Skills"))
var/skill/s
for(var/count in 1 to hotbar.len)
s = hotbar[count]
stat(s.name)
stat(s.desc)


When using the code you have presented.

Secondly, startup times seem to have exponentially increased; is there no way to avoid this for debugging?
I am getting a runtime error, first of all -

You are getting runtime errors because you are putting the wrong types of values in the hotbar list.

You need to fill the hotbar list with object references from the global.skills list, NOT prototypes.

Secondly, startup times seem to have exponentially increased

This code doesn't do a lot of heavy lifting. The runtime errors are probably causing the startup time to balloon. If you fix those, the issue will go away.

This shouldn't be increasing startup time by that much.
In response to Ter13
I looked a little bit more into it - not only will checking what the list contains with an output result in /list/, I will get a bad index runtime error when starting up - this is exactly using the code you have presented.

skillManager
New()
var/skill/s, sid
for(var/v in typesof(/skill))
s = v
if(sid = initial(s.id))
global.skills[sid] = new v()

var
skillManager/skillManager = new()
list/skills = list()

runtime error: bad index
proc name: New (/skillManager/New)
source file: Skills.dm,20
usr: null
src: /skillManager (/skillManager)
call stack:
/skillManager (/skillManager): New()
world: ()


Have I done something wrong, or did you? o-o.
http://www.byond.com/forum/?post=2187919#comment21683434

You did something wrong. The above link tells you exactly what's wrong. This gif shows the code working.

http://i.imgur.com/WrPDz18.gifv
In response to Ter13
I commented and then deleted it because I noticed that I was... entirely wrong. The video froze while you were typing and appeared to have ended, when you said that you needed to add the skills to the hotbar, apologies.

Thanks for the help!
Skills have to change every round, when players pick a new character - meaning that what you have proposed

That's not actually a problem at all. The reason the runtime errors occur is because my code assumes that there will always be objects in the hotkeys list. Because my example didn't require the need for hotswapping skills, I didn't need to make the assumption it would ever happen.

However, there is nothing in my approach that stops the objects in hotkeys from being changed at any time, so it will work for what you need.

What I showed will have to be adapted to your specific needs, though. This is just an example of data structures and design patterns. You have to make it work for your needs.

Nobody can give you 100% functional examples that work for every single need. The best they can do is get you 90% of the way there and you have to learn how and most importantly WHY what they did works and apply it yourself.
In response to Ter13
I noticed that after I restarted the video, as it had frozen :p.

I've changed a little bit of what you made (for example, to use clamping), but for the most part it is the same. I can't thank you enough for your help, and I'll probably have more questions soon.