ID:2361551
 

Cooldown datum



Introduction
This tutorial will be explained in two parts. One explaining the functionality of the new beta version(v.512.1420) and one explaining the stable version(v.511.1385)

Example of the new 512 beta build list function
bread/proc/eat() world << "You eat some bread"
var/list/food = list("bread" = new/bread())
food["bread"].eat()



A cooldown acts as a datum which is stored for individual players. The way to store it is by adding it to a list, and save it as a string relative to the ability it functions for. In this example, we will use a fireball as an example. We will not store the cooldown to the ability itself, but to the user casting it. This is because we don't want every ability created to hold "unnecessary" information, as there would probably be hundreds of these objects created over time. An other reason is, the cooldown datum is easier to handle if it is a fixed data to each player, and not a cooldown that is created then deleted over and over again. We want to keep it simple.

This tutorial will also show you how Lummox's latest build improves the usage of datums inside lists, and how to properly apply the changes. However, the current stable build(v.511) will have a harder time doing what we want to achieve. Both versions will be explained.

Explanation of the code tree


/ability
parent_type = /obj
// obj holds all data for pixel movement and appearance, which is why we want to keep it an object.
// However, making it a child for /obj would make it less comprehensive as the project grows imo.
// example: /obj/ability = /parent/child
// And therefore i keep it simple by making it /ability

//This is also where you would want to add variables, such as damage, traveling speed and time etc.
fire/fb001 // short for fireball001
/cooldown
/mob/player
var/list/cooldown
//This holds all of our cooldowns.
It is important to know what is included in this tutorial. We are working with /mob, that is the player. We have /ability, a subclass of /obj. Then we have /cooldown, which is the cooldown itself.

We need to make sure /mob is able to cast /ability, and when cast it triggers /cooldown. Then unable to cast it while cooldown is triggered. That is the essence of the code.


/cooldown


 //For both v.512(Beta) and v.511(Stable)
cooldown
//First we need to set a few variables to our datum
var
name
// This acts as a name, in which it holds a name so we know which datum we are working with

time
// This holds the datums cooldown time, and to how long it will last.

triggered = FALSE
//Toggle explains the datum whether it is triggered or not. TRUE means it is ready to start a new cooldown

New(_name, _time)
src.name = _name
src.time = _time

proc/reset()
//Each cooldown needs a reset(), in where variables is reset
//time = originalTime
//This one is optional.

triggered = FALSE
/* the ability using this cooldown dstum calls for "triggered"
triggered needs to be set to FALSE, so the ability can be used.
*/


proc/trigger()
// This is how the cooldown works.
// We need to ensure the proc doesn't repeat itself. so lets make a condition
// (triggered is also used to inform a verb/ability() when it is allowed to cast a new object.
// If triggered is FALSE, it wont fulfill the statement of the proc, nor create a new object)
if(!triggered)
//Then flip the condition so it won't stack over itself
triggered = !triggered
//This is the sleep duration, before it can be cast again.
sleep(time)
//After it's off duration we need to set triggered to FALSE again
triggered = FALSE
proc/getToggle()
return triggered ? Triggered : 0


As cooldowns is just an example, this approach of code can be applied in so many different ways.

/ability


ability
parent_type = /obj
var
mob/owner
mob/target
damage
damageAmp
speed = 0
lag = 1
travel = 20 // Units to travel
New(mob/_owner, )
if(_owner)
loc = get_step(_owner,_owner.dir)
dir = _owner.dir
owner = _owner
else
throw EXCEPTION("[src]: /ability/New() : expecting mob as argument!")

Move()
travel-- // for every Move() iteration, we subtract from var/travel
if(!travel) del(src) //Once travel is depleted, we delete src(i.e the object)
return ..() // Else, return parent Move() (/obj/Move()) to continue the whole function of movement

Bump(atom/a)
if(ismob(a))
oview(10, src) << "[src.name] hit [a.name] for [damage]!"
del src // You can pass certain conditions to this statement, but for now lets keep it short.


The fireball object


ability/fire
fb002
icon = 'fireballs.dmi'
icon_state = "fb002"

name = "Huge fireball"

travel = 120
lag = 1
speed = 10

New()
..()


Bump(atom/a)
if(ismob(a))
var/mob/m = a //Typecast to mob
target = m

if(owner)
target.takeDamage(damage)
..(a)


/mob


mob
//This is how we apply our cooldowns.

//At first we need to declare a list, in which we want to contain all our cooldowns.
//By default, lets make it empty
var/list/cooldown = list()

//Then we could make a proc that adds property to our empty list.
//It would make more sense to add data to our list, rather wanting all mobs to hold unnecessary data.
proc
giveAbilityCooldown()
cooldown = list(\
"fb002" = new/cooldown("fb002", 100))
//We name the content relative to our ability, then create a new /cooldown
//You can look at the arguments in /cooldown/New() further up.

get_cooldown_trigger(argument)
var/cooldown/cd = cooldown && cooldown[argument]
return cd ? cd.triggered : 0


/mob/player


mob/player
verb
fb002()
// version 511
if(!get_cooldown_trigger("fb002"))
var/ability/fire/fb002/f = new(src)
walk(f, f.dir, world.tick_lag, f.speed)

// version 512
if(!cooldown["fb002"].getTrigger())
var/ability/fire/fb002/f = new(src)
walk(f, f.dir, world.tick_lag, f.speed)

cooldown["fb002"].trigger()



// All of this is required in v.511
// By lummox's latest work, you can bypass all sorts of overhead procs, by calling straight from the list containing the datum.




The few issues with this is when a player is saved. then it happens that cooldown/toggle is saved as TRUE, and the cooldowns will be locked. Therefore we have cooldown/reset() to turn toggle = FALSE
Our first step is create a datum that holds our cooldown property. The reason for this is because it is easier for us to structure a cooldown variable as an individual datum, rather then a bunch of random variables for mob. It is flexible and this datum can act as a cooldown for anything! Not just abilities, but weapon usages, items, potions and many other.

So we need to set our cooldown variables uppon creation of the datum. We do this through /cooldown/New()
cooldown
New(name, time)
All the variables related to how long it lasts is all located inside the /cooldown datum.

And to save a datum to a mob, we store it in a list and give it a list prefix, for example: Lets imagine we have a fireball we, as in the example, and our implimentation of this fireball we call it fb002. By giving the fireball a prefix, we can store the datum to the same prefix as a list property.

mob
var/list/cooldown = list(\
"fb002" = new/cooldown(name, time))


At this point, all you need to do is make sure the cooldown/toggle() is a demanded check for the fb002 verb, as shown in the example above.

At this time, what we need to do to access the datums functionality is access it straight from our cooldown[] list, inside a mob's scope
cooldown["fb002"].proc()
cooldown["fb002"].var
Sleeping to handle a cooldown is really not ideal. Check out cooldownlib for a less intrusive approach.


http://www.byond.com/developer/Ter13/CooldownLib

I like the effort tho.

Login to reply.