Need help to decide which cooldown method is best

Please post any questions about developing your plugin here. Please use the search function before posting!
User avatar
Mahi
Senior Member
Posts: 236
Joined: Wed Aug 29, 2012 8:39 pm
Location: Finland

Need help to decide which cooldown method is best

Postby Mahi » Sun Sep 25, 2016 11:54 am

I'm back to working on my warcraft mod, and I want it to be as perfect as possible. I'm now going to make the final decision on how the cooldowns should be handled for the skills. I am not looking into performance or anything, all I want is a balance between readable/easy-to-understand (I want beginners to be able to copy/paste cooldowns too) and functionality.

Here are the options (sorry for it's a bit long):
Of course, something else can be suggested too! I've also been thinking of allowing the @cooldown to take either fail_messageor fail_callback, making it very versatile yet most of the time easy to use.

Any opinions?

Edit: I'm not sure how important a custom fail message even is. It could by default say "<skill_name> cooldown: <duration>" but then you could provide a custom fail_callbackif you need to. It would end up looking like this for static cooldowns:

Syntax: Select all

@cooldown(8)
Or this for lambda cooldowns:

Syntax: Select all

@cooldown(lambda self, **eargs: 11 - self.level)
Or even this to gain similarity to the old warcraft mod, one int for each level:

Syntax: Select all

@cooldown([10, 9, 8, 7])
It could even support all of these, deciding the functionality based on the type... But is this needed or is the first option just better?
User avatar
Ayuto
Project Leader
Posts: 2193
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Re: Need help to decide which cooldown method is best

Postby Ayuto » Sun Sep 25, 2016 1:04 pm

I would definitely use the first option. If you don't want to clutter the skill implementation, you could simply out-source it.

Syntax: Select all

@callback('player_attack')
def on_player_attack(self, attacker, victim, **eargs):
cooldown = self.cooldowns[self.on_player_attack] # replace with any key, as long as it's unique
if cooldown.remaining > 0:
fail_message.send(attacker.index, remaining=cooldown.remaining)
else:
# Call the actual implementation
self._burn_victim(victim)

def _burn_victim(self, victim):
victim.burn(duration=self.level)
cooldown = self.cooldowns[self.on_player_attack]
cooldown.remaining = 10 - self.level

But I think I would use a different approach:

Syntax: Select all

class Cooldown(object):
def __init__(self):
self.cooldown_time = 0

def set(self, seconds):
self.cooldown_time = time.time() + seconds

def is_active(self):
return self.remaining_cooldown > 0

@property
def remaining_time(self):
return self.cooldown_time - time.time()


# Base class for all skills
class Skill(object):
def __init__(self, owner):
self.owner = owner
self.cooldown = Cooldown()

def activate(self, *args, **kwargs):
# Or use the ABC module
raise NotImplementedError


# Burn skill. Since it's encapsulated from the player, you can easily re-use
# it in other heroes. Moreover, every skill instance has its own cooldown
# tracker, so you don't need a dictionary that keeps track of the cooldowns.
class Burn(Skill):
def activate(self, target):
if self.cooldown.is_active():
fail_message.send(self.owner.index, self.cooldown.remaining_time)
return

target.burn(duration=self.owner.level)
self.cooldown.set(10-self.owner.level)
User avatar
Mahi
Senior Member
Posts: 236
Joined: Wed Aug 29, 2012 8:39 pm
Location: Finland

Re: Need help to decide which cooldown method is best

Postby Mahi » Sun Sep 25, 2016 3:08 pm

I was thinking of similar Cooldown class as yours, but for my implentation each skill has its own dict, not one dict for all skills. This allows different methods of the skill to have different cooldowns. But most people seem to agree to use the first method, I guess that's it then :)
User avatar
Ayuto
Project Leader
Posts: 2193
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Re: Need help to decide which cooldown method is best

Postby Ayuto » Sun Sep 25, 2016 3:25 pm

Mahi wrote:This allows different methods of the skill to have different cooldowns.

Why can a skill have different cooldown? A skill can only be activated.
User avatar
Mahi
Senior Member
Posts: 236
Joined: Wed Aug 29, 2012 8:39 pm
Location: Finland

Re: Need help to decide which cooldown method is best

Postby Mahi » Sun Sep 25, 2016 4:16 pm

A skill can be activated via any event (including user "activating" it manually via console commands), so @callback('player_spawn') might have different cooldown than @callback('player_jump')
User avatar
Ayuto
Project Leader
Posts: 2193
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Re: Need help to decide which cooldown method is best

Postby Ayuto » Sun Sep 25, 2016 4:26 pm

That sounds a little bit odd to me. Why should the same skill have a different cooldown when it has been activated manually than activating it passively? I know you didn't create the thread to discuss that topic, but I'm curious.
User avatar
Mahi
Senior Member
Posts: 236
Joined: Wed Aug 29, 2012 8:39 pm
Location: Finland

Re: Need help to decide which cooldown method is best

Postby Mahi » Sun Sep 25, 2016 5:13 pm

Well, say for example, upon 'player_attack' (which activates automatically whenever you attack someone) you gather one "blood stack" with a maximum of one stack every 5 seconds (player_attack method needs 5 second cooldown), and then upon player_victim (which activates automatically whenever you are being attacked) you gather another blood stack with another cooldown. And then upon player_ultimate (manually activated via console command) you release all the blood stacks and get some special effect. Again, this needs a separate cooldown. All are in the "Blood Stack" skill.
User avatar
Ayuto
Project Leader
Posts: 2193
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Re: Need help to decide which cooldown method is best

Postby Ayuto » Sun Sep 25, 2016 5:42 pm

Ah, I see. But why do you use a dict for that and not simple attributes?

Syntax: Select all

# Somewhere in your __init__
self.activate_cooldown = Cooldown()
self.attack_cooldown = Cooldown()
self.victim_cooldown = Cooldown()
User avatar
Mahi
Senior Member
Posts: 236
Joined: Wed Aug 29, 2012 8:39 pm
Location: Finland

Re: Need help to decide which cooldown method is best

Postby Mahi » Sun Sep 25, 2016 6:08 pm

Would you rather override __init__() in a hundred subclasses and define separate cooldown manually for every method which happens to need them, or would you have self.cooldowns = defaultdict(Cooldown) in the base class and then never have to worry about initializing your cooldowns in the subclasses?
User avatar
Ayuto
Project Leader
Posts: 2193
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Re: Need help to decide which cooldown method is best

Postby Ayuto » Sun Sep 25, 2016 6:42 pm

When you are talking about readability: yes.

And a hundred subclasses is slightly exaggerated. :grin:
Moreover, a cooldown is probably not the only thing you want to initialize in your subclass. There are probably other attributes as well, so you still need to override __init__().
User avatar
Mahi
Senior Member
Posts: 236
Joined: Wed Aug 29, 2012 8:39 pm
Location: Finland

Re: Need help to decide which cooldown method is best

Postby Mahi » Sun Sep 25, 2016 7:09 pm

Ayuto wrote:When you are talking about readability: yes.
Indeed, and that means a lot since I value readability and easiness very high! I want these skills to be readable and copy/paste-able by beginners too so they can make their own skills with very little knowledge of Python.

Ayuto wrote:And a hundred subclasses is slightly exaggerated. :grin:
Oh boy, you clearly haven't played WCS in CS:Source! Largest WCS servers had hundreds of races, each with around 6 skills. I should've said thousands of subclasses! ;) (I'm not joking, there actually were thousands of skills in some servers)

Ayuto wrote:Moreover, a cooldown is probably not the only thing you want to initialize in your subclass. There are probably other attributes as well, so you still need to override __init__().
I can't argue on this, sometimes one must define a custom __init__() in the skills.
However, I have tried to minimize the need for this, and as a matter of fact, most skills which don't need to store anything during the rounds don't need to override __init__() at all! Like I said, I value the beginner-friendliness very high with this project.

Return to “Plugin Development Support”

Who is online

Users browsing this forum: No registered users and 27 guests