ID:2260285
 
(See the best response by Kaiochao.)
I was wondering if I was going in the right direction in terms of making Hotkeys. I wanted it so that once you select an ability and it's placed on a skill how'd I would be able to use a button linked to the hotkey to use the skill. I looked across the forum and I keep seeing "Datums" being used and if so then I guess it's time I learned about Datums. My alternative was to use procs so that if you'd pressed the button and if(istype(O,/obj/Skill/Fireball)) then it would call the Fireball verb. This would be used for virtually every skill and I was wondering if that is alright.
Nothing about that is alright. The fact that there is a specific verb for every single technique sounds like a headache and a half already.
Best response
Technically, objs are a subclass of datums, so you can do the same thing with a obj that one could suggest you do with a datum: call a proc. However, it should not be a verb specific to each object, it should be a proc defined under the parent type, /obj/Skill, and overridden under the /obj/Skill/Fireball type to do fireball-specific things:
obj/Skill
proc
// Called when a skill-user uses this skill.
// Does nothing by default.
Use(mob/user)

// This is the /obj/Skill/Fireball definition.
Fireball

// Override the Use proc
// to do Fireball things when used.
Use(mob/user)
user << "You are now a ball of fire, congrats."

That's how skills should be defined, IMO: the actions should be defined on the object, not the mob. Splitting behavior into separate types like this is what Object-Oriented Programming is all about.

As for actually using these in a hotbar, I usually go with this: a verb that takes a number from 1 to 10 (the number keys above the letters, except 0 is 10), uses that number as the index of a list of Skills to pull from, and call Use on the Skill at that index in the list.
// In whatever your player type is
mob/player
var
list
// A list of length 10, for 10 slots.
// To set the 5th slot to Fireball, do:
// hotbar[5] = new/obj/Skill/Fireball
hotbar = new(10)

verb

// A verb that takes a number from 1 to 10.
use_hotbar(i as num)
if(i in 1 to 10)

// Get the i'th skill
var obj/Skill/skill = hotbar[i]

// If this skill exists (if there is a skill there)
if(skill)

// Use this skill.
skill.Use(src)

With a verb like this, you can set up the necessary macros to call it with the command:
use-hotbar 5
(change the 5 to whichever number)

You can also use the Any macro for this, to reduce the number of macros you have to create (1 instead of 10).
I knew if I was vague enough with my answer the real pros would come along. :p
Seven months ago.
In response to Kaiochao
I did as you said and kept the notes to constantly look back on.

// In whatever your player type is
mob
var
skill
list
// A list of length 10, for 10 slots.
// To set the 5th slot to Fireball, do:
// hotbar[5] = new/obj/Skill/Fireball
hotbar = new(10)
verb

// A verb that takes a number from 1 to 10.
use_hotbar(i as num)
if(i in 1 to 10)

// Get the i'th skill
var obj/Skill/Fire = hotbar[1]
hotbar[1] = new/obj/Skill/Fire

// If this skill exists (if there is a skill there)
if(Fire)
// Use this skill.
Fire:Use(src)


For the actual skill itself

obj
Skill
Fire
proc
// Called when a skill-user uses this skill.
// Does nothing by default.
Use(mob/user)
user<<"Nothing happened"
// This is the /obj/Skill/Fireball definition.
Fire

// Override the Use proc
// to do Fireball things when used.
Use(mob/user)
user << "You are now a ball of fire, congrats."
It works as I both press the hotkey and use the verb and input the number. Though I get the "Nothing Happened" and do not understand how to make it override. Lastly, would I put every skill I have in this one string "obj/Skill" and then use things like "Fire/Fireball". I'm asking because I use different code files to separate abilities and everything having to do with said ability is in 1.
In response to Great_Sage
Your code completely misses the point of my code, actually. It's very different from what I wrote. I'll try presenting it a different way.

This is a skill. It's not a fireball skill, it's just the basic code for a "skill" that can be "used" by a skill user. It's just a proc definition under the /obj/Skill type. You can put this code in a file by itself, if you want.
obj/Skill
proc
Use(mob/user)


This is the fireball skill. It's a skill, so it inherits from /obj/Skill. It overrides the Use() proc to do whatever the fireball skill should do. This can also be in its own file, if you want.
obj/Skill/Fire
Use(mob/user)
user << "Fireball!"


Now for the code that lets mobs use skills. This can all go in its own file. It's completely separate from the Fireball.

This is what gives players a hotbar to store skills in. It's a simple variable declaration under the /mob type.
mob
var
list
hotbar = new(10)

hotbar is a list, so you could use it the same as any other list. For hotbars specifically, you won't be adding to or removing from it, you'll only be getting and setting elements by index.

This lets you use a skill at a certain index of the hotbar.
mob
verb
use_hotbar(index as num)
// Create a new variable called "skill" that has the type "/obj/Skill"
// and set it to hotbar[index], which is the element in the list
// [hotbar] at the index [index].
var obj/Skill/skill = hotbar[index]

// If the skill exists, then use it.
if(skill)
skill.Use(src)

Additional skills will inherit from /obj/Skill and override Use() to do their own things:
obj/Skill/whatever
Use(mob/user)
// do whatever

You can set any index of the hotbar (from 1 to 10) to any skill. It's all very abstract; nothing in this mob code is specific to Fireballs in particular.

Here's an example of setting slot 1 to the Fireball skill from above:
mob
// When a player logs in,
Login()
..()
// Set slot 1 of the hotbar to a new instance of /obj/Skill/Fireball.
hotbar[1] = new/obj/Skill/Fireball
Thanks, I feel like a complete idiot, but the second one felt much more clearer. I was wondering if adding an icon to the skill is the way to make it so that the skill is shown when in a slot. Then I'd use overlays+='Fire.dmi' for the skill slot, Correct?
Also last question, as far as people gaining the skills to put in the slots. Would I have to make a list called "skills" and once they gain a skill I'd add it to the list. They'd click on the slot and then click on the name of the skill, then use an if("") to determine the name and if it matches with Fireball it would assign it to said slot.
In response to Great_Sage
If you give the skill an icon (and probably a layer higher than the slot, or FLOAT_LAYER), you could just add the skill itself to the overlays of the slot.

In general, I try to be... general in my code. If you want all skills to appear over the slot, then you should write code in terms of any skill, not just one specific skill. It's better to write one piece of code that can adapt to many potential situations, rather than repeating similar code with slight adjustments for every situation that comes up.
In response to Great_Sage
I would have actual instances of /obj/Skill in a list of skills. You shouldn't need any specific checks. With an input(), you can choose from a list of skill objs, and use the return value of the input() as the value to put in the slot:
// The "as null | anything" adds a "Cancel" button to the popup. 
var obj/Skill/chosen_skill = input(player, "What skill?", "Hotbar") as null | anything in usr.skills
player.SetHotbar(slot, chosen_skill)

And you would want this proc in your player type, to avoid repetition:
mob
proc
SetHotbar(index, obj/Skill/skill)
// If the slot already has a skill, clear it.
if(hotbar[index])
// do whatever to clear this slot

hotbar[index] = skill

// If there is a new skill, show it on the slot
if(skill)
// do whatever to show the skill on the slot
In response to Great_Sage
As an example, this is the way you seem to be thinking about code:
proc
// Add one to x.
add_one(x)
// We need to be able to add one to 0, so here's that case.
if(x == 0)
return 1

// Eventually we found out that we need to add one to 1 too:
else if(x == 1)
return 2

// and so on

And this is how you should be thinking about code:
proc
// Add one to any number x.
add_one(x)
// This one line handles all possible x's.
return x + 1
Hello, I know I am being annoying but I need a bit more help. I can not figure how to "add" the skill.

    proc
SetHotbar(index, obj/Skill/skill)
if(hotbar[index])
src.hotbar[index] = null
hotbar[index] = skill

if(skill)



    Skill_Slot
Skill_Slot1
icon = 'Skill_Slot.dmi'
New(client/c)
screen_loc="8,3"
c.screen+=src
DblClick()
var obj/Skill/chosen_skill = input(usr, "Select a skill?", "Skill Slot") as null | anything in usr.skills
usr.SetHotbar(src, chosen_skill)
You don't need 10 different skill slot types. You're being too specific again. Here's how to generalize it, by passing the slot number as an argument to the cosntructor:
/* 
You could create these slots and add them to the screen like this:

// don't do it like this
new/Skill_Slot/Skill_Slot1(client)
new/Skill_Slot/Skill_Slot2(client)
new/Skill_Slot/Skill_Slot3(client)
// etc.

Or you could just do it simply with a loop:

for(var/slot_number = 1 to 10)
new/Skill_Slot(client, slot_number)

With this:
*/

Skill_Slot
var
slot_number

New(client/c, slot_number)
..()
c.screen += src

// Set the slot's variable to value given in the arguments.
src.slot_number = slot_number

// Example of how you might derive the screen_loc from the slot_number.
// As slot_number increases, the x value increases.
screen_loc = "[8 + slot_number],3"

DblClick()
// I like to break long lines down like this for readability.
// It doesn't change anything.
var obj/Skill/chosen_skill = input(usr,
"Select a skill?", "Skill Slot"
) as null | anything in usr.skills

// The SetHotbar() proc that I wrote earlier takes a number as the first argument.
// The number is the slot's number. It goes from 1 to 10.
usr.SetHotbar(slot_number, chosen_skill)
In response to Kaiochao
I have a question about this, is overiding a better choice in efficiency, or is there no particular demerit associated with separate procedures? This is the method I used and I'm just curious about any particular disadvantages it may present, for reflection's sake.

obj
skillcard
fireball
skillcall="Fireball"
cooldown=5

mob
proc
SkillUse(obj/skill)
if(call(src,skill.skillcall)())
return skill.cooldown
else
return 0


In response to Cheesy pants
Overriding is definitely more efficient than call()().

call()() also exposes your code to errors not caught until runtime, because the compiler can't check that the procs exist at compile-time.
Thanks for the info