ID:450047
 
(See the best response by Kaiochao.)
As you can see below, this is quite the amount of code for just 15 skills...Is there a more efficient way of structuring this?


Code: MoveExp & MoveCooldown (cooldown and level checks)

    MoveCooldown(var/mob/player/Player, var/mob/player/MoveID)
switch(MoveID)
//--Martial Artist Moves
if(1) //High Kick
Player.MM1OC = 1
sleep(Player.Mmove1CD)
Player.MM1OC = 0
if(2) //Low Kick
Player.MM2OC = 1
sleep(Player.Mmove2CD)
Player.MM2OC = 0
if(3) //Air Blast
Player.MM3OC = 1
sleep(Player.Mmove3CD)
Player.MM3OC = 0
if(4) //Low to High Earth Shatter (sends 2 earth blasts 4 tiles)
Player.MM4OC = 1
sleep(Player.Mmove4CD)
Player.MM4OC = 0
if(5) //12 Hit Combo (sends out 6 projectiles that have a range of 2 tiles (also freezes the person who is gettin hit))
Player.MM5OC = 1
sleep(Player.Mmove5CD)
Player.MM5OC = 0
//--Samurai Moves
if(6) //Slash
Player.SM1OC = 1
sleep(Player.Smove1CD)
Player.SM1OC = 0
if(7) //Quick Draw
Player.SM2OC = 1
sleep(Player.Smove2CD)
Player.SM2OC = 0
if(8) //Power Slash (sends out a projectile with a range of 4 tiles)
Player.SM3OC = 1
sleep(Player.Smove3CD)
Player.SM3OC = 0
if(9) //
Player.SM4OC = 1
sleep(Player.Smove4CD)
Player.SM4OC = 0
if(10) //Wicked Speed Stab
Player.SM5OC = 1
sleep(Player.Smove5CD)
Player.SM5OC = 0
//--Archer Moves
if(11) //Shoot
Player.AM1OC = 1
sleep(Player.Amove1CD)
Player.AM1OC = 0
if(12) //Iron Arrow
Player.AM2OC = 1
sleep(Player.Amove2CD)
Player.AM2OC = 0
if(13) //Frozen Iron Arrow
Player.AM3OC = 1
sleep(Player.Amove3CD)
Player.AM3OC = 0
if(14) //Scorching Iron Arrow
Player.AM4OC = 1
sleep(Player.Amove4CD)
Player.AM4OC = 0
if(15) //Lightning Arrow
Player.AM5OC = 1
sleep(Player.Amove5CD)
Player.AM5OC = 0
MoveExp(var/mob/player/Player)
if(isnull(Player))
Player = src
switch(Player.MoveID)
//--Martial Artist Moves
if(1)
if(!(Player.MM1L >= Player.MMove1Cap))
Player.Mmove1exp++
if(2)
if(!(Player.MM2L >= Player.MMove2Cap))
Player.Mmove2exp++
if(3)
if(!(Player.MM3L >= Player.MMove3Cap))
Player.Mmove3exp++
if(4)
if(!(Player.MM4L >= Player.MMove4Cap))
Player.Mmove4exp++
if(5)
if(!(Player.MM5L >= Player.MMove5Cap))
Player.Mmove5exp++
//--Samurai Moves
if(6)
if(!(SM1L >= SMove1Cap))
Player.Smove1exp++
if(7)
if(!(Player.SM2L >= Player.SMove2Cap))
Player.Smove2exp++
if(8)
if(!(Player.SM3L >= Player.SMove3Cap))
Player.Smove3exp++
if(9)
if(!(Player.SM4L >= Player.SMove4Cap))
Player.Smove4exp++
if(10)
if(!(Player.SM5L >= Player.SMove5Cap))
Player.Smove5exp++
//--Archer Moves
if(11)
if(!(Player.AM1L >= Player.AMove1Cap))
Player.Amove1exp++
if(12)
if(!(Player.AM2L >= Player.AMove2Cap))
Player.Amove2exp++
if(13)
if(!(Player.AM3L >= Player.AMove3Cap))
Player.Amove3exp++
if(14)
if(!(Player.AM4L >= Player.AMove4Cap))
Player.Amove4exp++
if(15)
if(!(Player.AM5L >= Player.AMove5Cap))
Player.Amove5exp++
//--Martial Artist Moves
var/Mname = "NULL"
if(Player.Mmove1exp >= Player.Mmove1Mexp)
Player.Mmove1exp -= Player.Mmove1Mexp
Player.Mmove1Mexp += rand(10,20)
Player.MM1L++
Mname = "High Kick"
if(Player.Mmove2exp >= Player.Mmove2Mexp)
Player.Mmove2exp -= Player.Mmove2Mexp
Player.Mmove2Mexp += rand(10,20)
Player.MM2L++
Mname = "Low Kick"
if(Player.Mmove3exp >= Player.Mmove3Mexp)
Player.Mmove3exp -= Player.Mmove3Mexp
Player.Mmove3Mexp += rand(10,20)
Player.MM3L++
Mname = "Air Strike"
if(Player.Mmove4exp >= Player.Mmove4Mexp)
Player.Mmove4exp -= Player.Mmove4Mexp
Player.Mmove4Mexp += rand(10,20)
Player.MM4L++
Mname = "Low to High Earth Shatter"
if(Player.Mmove5exp >= Player.Mmove5Mexp)
Player.Mmove5exp -= Player.Mmove5Mexp
Player.Mmove5Mexp += rand(10,20)
Player.MM5L++
Mname = "12 Hit Combo"
//--Samurai Moves
if(Player.Smove1exp >= Player.Smove1Mexp)
Player.Smove1exp -= Player.Smove1Mexp
Player.Smove1Mexp += rand(10,20)
Player.SM1L++
Mname = "Slash"
if(Player.Smove2exp >= Player.Smove2Mexp)
Player.Smove2exp -= Player.Smove2Mexp
Player.Smove1Mexp += rand(10,20)
Player.SM2L++
Mname = "Quick Draw"
if(Player.Smove3exp >= Player.Smove3Mexp)
Player.Smove3exp -= Player.Smove3Mexp
Player.Smove1Mexp += rand(10,20)
Player.SM3L++
Mname = "Power Slash"
if(Player.Smove4exp >= Player.Smove4Mexp)
Player.Smove4exp -= Player.Smove4Mexp
Player.Smove1Mexp += rand(10,20)
Player.SM4L++
Mname = "Samurai Move 4"
if(Player.Smove5exp >= Player.Smove5Mexp)
Player.Smove5exp -= Player.Smove5Mexp
Player.Smove1Mexp += rand(10,20)
Player.SM5L++
Mname = "Wicked Speed Stab"
//--Archer Moves
if(Player.Amove1exp >= Player.Amove1Mexp)
Player.Amove1exp -= Player.Amove1Mexp
Player.Amove1Mexp += rand(10,20)
Player.AM1L++
Mname = "Shoot"
if(Player.Amove2exp >= Player.Amove2Mexp)
Player.Amove2exp -= Player.Amove2Mexp
Player.Amove2Mexp += rand(10,20)
Player.AM1L++
Mname = "Iron Arrow"
if(Player.Amove3exp >= Player.Amove3Mexp)
Player.Amove3exp -= Player.Amove3Mexp
Player.Amove3Mexp += rand(10,20)
Player.AM1L++
Mname = "Frozen Iron Arrow"
if(Player.Amove4exp >= Player.Amove4Mexp)
Player.Amove4exp -= Player.Amove4Mexp
Player.Amove4Mexp += rand(10,20)
Player.AM1L++
Mname = "Scorching Iron Arrow"
if(Player.Amove5exp >= Player.Amove5Mexp)
Player.Amove5exp -= Player.Amove5Mexp
Player.Amove5Mexp += rand(10,20)
Player.AM1L++
Mname = "Lightning Arrow"
if(Mname != "NULL")
Player << output("You've leveled up [Mname]!", "Main.MainOutput")


Note: it was a time consuming process to make this as I did it all at the same time - which is why I asked the question


EDIT: I've modified if(!(Player.MM3L >= Player.MMove3Cap)) for example, don't know what I was thinking when doing that lol
Datums... i suppose? o.O
In response to Ocean King
Best response
Yeah, datums would actually shorten it a lot in the long run. Off the top of my head...
Skill
var
mob/player/player // The player using this skill

name // The name of this skill

level = 1
level_cap = 50 // Level can't exceed this

experience = 0
max_experience = 100 // Level up when experience exceeds this

tmp/locked = FALSE // Skill can't be used when this is TRUE

cooldown = 10

// When the skill is created, it's given a player to attach to.
New(mob/player/player)
src.player = player

proc
// Normal behavior is to deny usage if locked
can_use()
return !locked

// This is to be overridden to make the player do something
// See the example below
use()
do_cooldown()

do_cooldown()
locked = TRUE
spawn(cooldown)
locked = FALSE

gain_experience(amount=1)
// Do nothing if the level is at the level cap (or higher)
if(level >= level_cap) return

// Gain experience
experience += amount

// Check for level-up
var pre_level = level
while(experience >= max_experience)
experience -= max_experience
max_experience += rand(10, 20)
level ++

// The skill has leveled up
if(level != pre_level)
player << "[name] is now level [level]!"
// If this was in the while() above, you'd be spammed
// when you leveled up more than once (it's possible if
// you somehow suddenly gain a crapload of exp)

Martial_Artist
High_Kick
name = "High Kick"
cooldown = 3

// The High Kick skill has a 50% chance of success.
use()
// Regardless of what happens, the skill requires cooldown.
..()

if(prob(50))
player.shout("High kick! Hiyah!")
return TRUE

else
player.emote("fails to perform a high kick, falling on the floor")

Low_Kick
name = "Low Kick"
cooldown = 2

// etc.

mob
var skills[0]
proc
// e.g. learn_skill(/Skill/Martial_Artist/Low_Kick)
learn_skill(path)

// Do nothing if the skill is already known
if(locate(path) in skills) return

// Create the skill and attach it to src (see Skill/New())
var Skill/skill = new path (src)
skills += skill

// Tell the player that they learned a new skill
src << "You learn the skill, \"[skill.name]!\""

// e.g.
// use_skill(/Skill/Martial_Artist/Low_Kick)
// or
// use_skill(locate(/Skill/Martial_Artist/Low_Kick) in skills)

use_skill(Skill/skill)
// You passed a type path to this proc instead of an instance
if(ispath(skill)) skill = locate(skill) in skills

// The skill is invalid or not known
if(!istype(skill) || !(skill in skills)) return

// Skills have a can_use() proc that tells the player if it
// can be used or not.
if(!skill.can_use()) return

// Attempt to perform the technique, and check its success.
// (TRUE is success)
if(skill.use())
skill.gain_experience()

Longer than I expected, but if you plan on having a lot of skills, your code may be just as easy to read as this for a skill's definition:
Skill/Martial_Artist
Blah
name = "Blah"
cooldown = 1
Bloop
name = "Bloop"
cooldown = 4
Blah
name = "Blah"
cooldown = 1
Bloop
name = "Bloop"
cooldown = 4
Blah
name = "Blah"
cooldown = 1
Bloop
name = "Bloop"
cooldown = 4
Blah
name = "Blah"
cooldown = 1
Bloop
name = "Bloop"
cooldown = 4
Blah
name = "Blah"
cooldown = 1
Bloop
name = "Bloop"
cooldown = 4

The real difference between using datums and using a big switch() or huge if/else chain is that the code I have to make the skills work is the same for all of them, rather than copy/pasted with a couple changed.