ID:1723531
 
(See the best response by FKI.)
Code:
mob/var
list/abilities
list/cooldowns

ability
parent_type = /obj
proc
cooldown_timer(mob/caster)
var cd = cooldown - round((cooldown * (caster.apply_sub_stat_boost(caster.haste) / 100)))
cd = cd * 10 + world.time

if(!caster.cooldowns) caster.cooldowns = list()
if(!(src in caster.cooldowns))
caster.cooldowns.Add(src)
on_cooldown(caster, cd)


on_cooldown(mob/caster, cooling_duration)
set waitfor = 0

var/obj/T = new/obj/effects/timer(src)

T.icon_state = "[round((world.time / cooling_duration) * 28)]"
caster << "icon_state1: [T:icon_state]"

while(cooling_duration > world.time)

T.icon_state = "[round((world.time / cooling_duration) * 28)]"
caster << "icon_state2: [T.icon_state]" // I used this line to figure out the icon_state based on the previous line.

sleep(world.tick_lag * 10)

if(cooling_duration < world.time)
caster.cooldowns.Remove(src)
del(T)


Problem description: I have been attacking this for quite awhile now but I can't seem to figure out the problem. I have a timer.dmi file and I want it's icon_state to change depending the ability's cooldown duration. I can't seem to get the timer.dmi to appear on top of the ability and the icon_states begin from 15-27 out of 1-28.

Best response
var/obj/T = new/obj/effects/timer(src)


What it looks like you are doing is placing the timer object in src's (which is an ability) contents list, which doesn't seem like what you want to do at all. If the timer is intended to be an overlay of some sort, which I'm assuming it is, you'd have to use client.screen and place it where your ability GUI is, or use an image object. I think the latter is the better route, but either would suffice.
In response to FKI
Thank you for your response. Here is my second attempt.

mob/proc
add_cooldown_timer(var/ability/A , var/cooling_duration)
var/image/cooldown_timer/c = image(icon = '_cooldown_timer.dmi',icon_state = "[round((world.time / cooling_duration) * 28)]" , loc = A)
src << c

update_cooldown_timer(cooling_duration = cooling_duration)

update_cooldown_timer(var/cooling_duration)
while(world.time > cooling_duration)
src << "Entered and going"

for(var/image/x in client.images) if(x.icon == '_cooldown_timer.dmi') x.icon_state = "[round((world.time / cooling_duration) * 28)]"

sleep(world.tick_lag * 10)


To be honest I think I am doing the same thing I posted earlier just in a different way. The problems I have with this one, is the while loop does not begin. It doesn't return "Entered and going." Another problem this method might employ, is that it will change all the "timer icon_states" for every single ability whether they are cooling down or not.

-Regards
You could just keep a reference to the image under the ability and update it while it's alive; that for() loop is unnecessary.

If that loop isn't starting, then you need to check what's being inputted for cooling_duration, since through that variable is the only way it would exit.
In response to FKI
Thank you very much for your help I am almost got this figured out. Now my final problem is, the icon_states don't seem to go in order. I have 28 icon_states for the timer, but it starts of randomly. Ie. From state 15 and ends at either 27 or 28.
mob/proc
//Give the ability a cooldown
cooldown_timer(var/ability/A , cooldown_duration)

if(!cooldowns) cooldowns = list()

if(!(A in cooldowns))
cooldowns.Add(A)

var/image/cooldown_timer/c = image(icon = '_cooldown_timer.dmi', loc = A)
src << c

on_cooldown(A , cooldown_duration = cooldown_duration, timer = c)


//Activate cooldown timer and watch the cooldown go down
on_cooldown(var/ability/A , cooldown_duration, var/image/timer)
set waitfor = 0

while(cooldown_duration > world.time)
var/state = "[round((world.time / cooldown_duration) * 28)]"
timer.icon_state = "[state]"

src << "------"
src << "World.timer/Coodown_duration: [world.time]/[cooldown_duration]"
src << "icon_states: [timer.icon_state]"
src << "------"

sleep(world.tick_lag * 10)

if(cooldown_duration < world.time)
src << "Cooldown is done"
cooldowns.Remove(A)
del(timer)
if(!cooldowns) cooldowns = null
break


The problem is here: but I can't seem to get it to work.
var/state = "[round((world.time / cooldown_duration) * 28)]"

-Regards
I believe your formula should be:

round(cooldown_duration / total_cooldown) * 28


In response to FKI
Is "world.time" not okay to use? As soon as the user performs the skill, cooldown_duration is set as:

var cd = cooldown - round((cooldown * (caster.apply_sub_stat_boost(caster.haste) / 100)))
cd += round(world.time)
// caster.haste implies as a cooldown_reduction.
//It reduces the initial cooldown by a percentage.

caster.cooldown_timer(src, cooldown_duration = cd)
In response to Luchasi
Why would you round the actual time to an integer? The value of world.time is a multiple of world.tick_lag, which is often less than 1.
In addition to the above: why are you adding world.time to the cooldown?

I think this is being made more complicated than it really is. Here is my short version of exactly what you are doing:

ability
parent_type = /obj

var/tmp/cooldown = 0
var/tmp/image/cooldown_img

proc/can_activate(mob/caster)
. = TRUE
if(cooldown > world.time)
caster << "This skill is on cooldown ([round((cooldown - world.time) / 10)] seconds left)!"
return 0

proc/use(mob/caster)
if(!caster || !can_activate(user)) return

activate(caster)

proc/activate(mob/caster)
// ...

proc/do_cooldown(mob/caster, time)
if(!caster) return

cooldown = world.time + time
cooldown_img = new(icon = 'cooldown_timer.dmi', loc = src)
caster << cooldown_img

spawn()
while(cooldown > world.time)
var/state = "[round((cooldown - world.time) / cooldown) * 28]"
cooldown_img.icon_state = state

sleep(world.tick_lag * 10)

if(caster && caster.client)
caster.client.images -= cooldown_img

cooldown_img.loc = null
cooldown_img = null


I'm not sure why you were handling ability cooldowns on the caster, but I believe that to be the wrong approach (or sloppy if you will). Instead, I'd rather have the ability itself take care of its own business.

world.time is most certainly OK to use, and it's really convenient in situations like this where I'm sure most would use a counter variable. The issue was you were using it wrong, placing it where the ability's total cooldown should be.

Being that your timer is supposed to be based on the ability's time left and not how long the world has been running, it should be checking the gap between the total cooldown time and the time that has passed.

Edit: I noticed your original post looks more like my example than your re-write. Now I'm confused why you decided to move that behavior to the mob.
Hi there. Thank you for responding. I was handling the cooldown on the caster, because I following FA's example. The problem still persists. The icon_state is always 0.

ability
proc
//Check if ability can be used
cast(mob/caster , req_target)
if(req_target) return 1

if(src in caster.cooldowns) return 1

if(reiatsu_needed)
var cost = reiatsu_cost - round(reiatsu_cost * (caster.apply_sub_stat_boost(caster.reiatsu_cost_reduction) / 100))
if(caster.reiatsu.current < cost) return 1

else
caster.main_stat_change(caster.reiatsu, amt = cost)
ability_cooldown_timer(caster)
return 0

ability_cooldown_timer(mob/caster)
var cd = cooldown - round((cooldown * (caster.apply_sub_stat_boost(caster.haste) / 100)))
cd = (cd * 10) + world.time

if(!caster.cooldowns) caster.cooldowns = list()
if(!(src in caster.cooldowns))
caster.cooldowns.Add(src)
spawn()
while(cd > world.time)

caster << "<b><font color = red>[src.name]</b>: [world.time]/[cd]"
cooldown_img = new(icon = '_cooldown_timer.dmi', icon_state = "[1]" , loc = src)
caster << cooldown_img

var/state = "[round((cd - world.time) / cd) * 28]"
cooldown_img.icon_state = state
caster << "<b>Image Icon_state</b>: [cooldown_img.icon_state]"

sleep(world.tick_lag * 10)

if(caster && caster.client)
caster.client.images -= cooldown_img

cooldown_img.loc = null
cooldown_img = null

caster.cooldowns.Remove(src)
Racked my brain for over an hour trying to figure out the problem, but to no avail. I am royally confused at this point.

The formula works in theory when numbers are plugged in. However, in action, when it divides the elapsed time by the total time, it always comes out to 0. Yet, I can plug the numbers in and perform the calculations manually and get the desired outcome.

Maybe someone else can chime in and point out the mistake.
In response to FKI
Hahaha :3 Thanks a lot for trying. I will make sure to credit you for your hard work.
In response to Kaiochao
The only reason why I rounded was to get an icon_state. I am completely lost at this point and willing to take a different approach without world.time. With that being said, I've yet to figure out the solution to my problem and would like extensive assistance if possible.

-Regards
Bump
I would be pretty awesome if I could get this solved. Thanks in advance.
round() needs to go on the outside, no?

var/state = "[round(((cd - world.time) / cd) * 28)]"
In response to Mightymo
Thanks for responding. That was a good post! we are almost there. Now my new problem is that the icon_state remains at 0 with higher world.time. At this point I think I would like to avoid world.time in general. I just can't seem to get this to work.
Ah, I didn't read closely enough. You should be dividing by the cooldown in 1/10 seconds.
var storeCD = cd * 10
...
var/state = "[round(((cd - world.time) / storeCD) * 28)]"
In response to Mightymo
In my previous code, I have these lines:

var cd = cooldown - round((cooldown * (caster.apply_sub_stat_boost(caster.haste) / 100)))
cd = (cd * 10) + world.time


Isn't the same thing?
No, you need one that doesn't add world.time to it. This is separate from the one that you declared. This should be in between the two lines that you posted.
Page: 1 2