Closed Roguedeus closed 8 years ago
As I understand it, the only way to make something like this sorta possible now, would be through Skill Links, making the conditions formula consider target element rates... etc... Possible, but very crude. Not to mention exceptionally difficult to consider when combining the quirks of Skill Links, including a separate use_item
call each time a link fires... etc...
A separate mechanic would be best IMO.
Perhaps, the element ID dependency could be optionally flagged as additional to success... Thus the action would first require normal success (HIT vs. Evade) based on attack type (magical or physical) and then, element based... (Application Rate vs. Defense Rate)?
Can it include your Element Attack Adjustments script?
I always get a flood of ideas when watching DotA2 matches. It's a curse.
Forgot to mention... A third dependency can be attack type. (magic or physical).
Hierarchy could be: 2a - Element ... 2b - Attack Type 1 - Default Effect
The attack type link would be implied by the UsableItem
's attack type, unless defined otherwise.
edit: Likewise, the element dependency would be implied the same way, unless defined otherwise.
So... Being Immune to Magical Ice, wont apply to Physical Ice... However, being Immune to ICE, applies to both magical and physical. Meanwhile, being Immune to Stun, applies to ALL possible sources.
Any criticisms?
When you are applying states, you have access to the target. You can just change how the calculation is done. On Aug 5, 2015 12:17 AM, "Roguedeus" notifications@github.com wrote:
Any criticisms?
— Reply to this email directly or view it on GitHub https://github.com/Hime-Works/Requests/issues/285#issuecomment-127840825 .
That was what I was referring to with performing the note tag checks via the usable item.
Can you see any reasonable existing alternative to this script? Or possible ways that it can be simplified?
It seems to be the most direct way to perform elemental checks when adding a state since the specific effect is all that matters.
You would need to determine what the attack element is if there are multiple. On Aug 5, 2015 12:36 AM, "Roguedeus" notifications@github.com wrote:
That was what I was referring to with performing the note tag checks via the usable item.
Can you see any reasonable existing alternative to this script? Or possible ways that it can be simplified?
— Reply to this email directly or view it on GitHub https://github.com/Hime-Works/Requests/issues/285#issuecomment-127842928 .
Ah... Forgot about that.
I may have a larger context with which to include this functionality... I am tentatively calling it, Aptitude Tags
. May find a better name soon.
It will include pretty much anything you want altered in a skill, based on tags. Using your Tag Manager.
Big mistake...
Two days ago I got really burned out on the armor script. I am guessing it was due to the fact that its taking so long to finish, primarily due to its ALL IN ONE nature. I could have built the core, and added on as I liked to, each smaller script having a resolution, rather than one big script, taking FOREVER to resolve.
From now on I think I need to make it a rule... I do my best to strip each idea into its simplest parts, and discover which parts are shared amongst all ideas. Work on that as the primary script, and FINISH IT. Then add each other part, one by one, making sure to FINISH one before moving to the next.
Hopefully, avoiding a monster script, that never seems to end. And hopefully with fewer mistakes.
/sigh
So... I am not going to combine the State Elements with Aptitudes. Was my original point I failed to make. ;)
If you haven't been writing your ideas down on paper or in notepad, that might be something to look at. Or get a whiteboard.
Then you can start throwing things at it and finding a common denominator.
I usually have a rough draft of features I am aiming to complete, but rarely 'plan' them... Then again, my scripts haven't been very complicated until recently, because I have not thought myself capable of accomplishing them.
It seems, as my competence grows, so to does my ambition. ;p
I am thinking I will begin using graph paper to block diagram my ideas and look for common activities. I have a FRACK-TON of paper from my 'pen and paper' days I have little use for now.
I would use online tools like Lucidchart...etc... but the brain to screen delay is a little much for my liking. I can scribble my thoughts much faster than I can build a flow chart piece by piece... by piece.
Change of subject...
I recently decided to plan on making a simple 'State - Linked Skill' script... It would use the state, as an origin of a linked skill, for any action that met the conditions. (such as tags, types, etc)
Example: A 'Flaming Strikes' state might add the 'Flame Strike' skill, on top of any Unarmed Attack performed by a Monk class or what not... (as an example) The condition being, that the action is an RPG::Skill
object with a specific wtype
ID... (maybe make it a formula)
I will need to add it in the context of my own State Mechanic, so if you like the idea feel free to make a plugin for your Skill Links.
edit: On second thought... I may just use feature objects in general. No reason to restrict the functionality to states alone. Perhaps a sword adds the same effect to all actions with a sword required to use it... etc.
I think I have decided that from now on, I am done using note-tags for anything more than a simple flag.
Its a detail only needed when the script is written to be shared and used by non-coders.
Its also added complexity I can do without, until (or if) I decide to share.
As a matter of fact, I think I will soon write a script to completely replace the need to use the toolset for the database... That way the only time I would need to interact with the tool is during mapping and eventing.
It is hard to quantify how much time is wasted via the clumsy database interface.
Unless there is already one written?
I'm not sure. What are you thinking? Using external data files and just having the script load it in?
Which do you think would be most 'use' friendly? (Like reducing potential mistakes, and not require potentially thousands of individual .txt files...)
Hashes are what I am currently using for my map setup script, and a few others.
I just setup a framework for module RDeus::Data.XXXX
hashes, complementing $data_XXXX
globals.
From now on, all my scripts will reference this data as default. Indexed by ID.
example:
def self.armor(script_sym, armor_id = 0)
armor_data = ARMORS[armor_id][script_sym]
return [] if script_sym == :armor_v2 && armor_data == :not_armor
return armor_data if armor_data.is_a?(Array)
armor_data = ARMORS[armor_data][script_sym] #Should be an ID...
return armor_data if armor_data.is_a?(Array)
return ARMORS[0][script_sym]
end
ARMORS = {
#=============================================================================
0 => {#Default Armor Object (for armor setup)
#---------------------------------------------------------------------------
:armor_v2 => [
#---------------------------------------------------------------------------
[ #Armor Group START ---------------
{ #Piece Start
:part => :piece,
:count => 1, #RDeus::Data::ARMORS[0][:armor_v2][0][0][:count]
:type => :magical,
:nature => :active,
:value => 5,
},#Piece End
],#Armor Group END -----------------
#---------------------------------------------------------------------------
],#armor_v2
#---------------------------------------------------------------------------
},#Default Armor Object
#=============================================================================
}
Of course, whatever is inside the scripts array is totally customizatable based on whatever the script needs and how I need to sample it. The example above is a simple armor piece used as a default for RPG::Armor
objects not flagged as :not_armor
Also... I just noticed that excel 2010 has a pretty robust flowchart tool set. BOGGLE
Does the script data hash appear over engineered?
Does the script data hash appear over engineered?
I think it is. Consider using a CSV file that allows people to edit in excel or something, and then all you have to do is read the CSV. Of course this depends on what kind of values you'll accept but you should be able to structure this in a way that's easier to edit.
I totally agree with using csv files for database objects. That would be a good solution for my earlier question.
However, I'm not sure if I agree with script data (like the armor script)... I spend so much time in a text editor these days that cut/paste is super easy for me. Especially when the text is formatted easily. Like the example.
Also, because the data is not database objects, it can potentially have a lot of nested and repeated data types... I can't think of an easy way to replicate that in a spreadsheet format. Not to mention the problem with entering long formulas in a cell.
Also, because the data is not database objects, it can potentially have a lot of nested and repeated data types
What do you mean? Do you have any examples that you are thinking of providing to users or yourself?
Not to mention the problem with entering long formulas in a cell.
That should not be an issue.
An example is the way my armor mechanic works... It looks for pieces, and adds them if they are in the note (or in this case, the hash) but otherwise uses a default data set unless told not to.
I can't imagine a good way to duplicate this in an all in one csv file. Not to mention that each of a number of armor groups can have none, or many, of each kind of armor piece, and other equips can simply reference other equipment ID's rather than repeat the same notes over and over.
edit: I forgot to mention that MOST number values can be formulas... another headache trying to keep formatted in a spreadsheet.
#=============================================================================
0 => {#Default Armor Object (for armor setup)
#---------------------------------------------------------------------------
:armor_v2 => [
#---------------------------------------------------------------------------
[ #Armor Group START ---------------
{ #Piece Start
:part => :piece,
:count => 1, #RDeus::Data::ARMORS[0][:armor_v2][0][0][:count]
:type => :magical,
:nature => :active,
:value => 5,
},#Piece End
],#Armor Group END -----------------
#---------------------------------------------------------------------------
],#armor_v2
#---------------------------------------------------------------------------
},#Default Armor Object
#=============================================================================
#=============================================================================
1 => { #Rotten Torso 1
#---------------------------------------------------------------------------
:armor_v2 => [
#---------------------------------------------------------------------------
[ #Armor Group START ---------------
{ #Piece Start
:part => :piece,
:count => 1,
:type => :magical,
:nature => :active,
:value => 10,
},#Piece End
{ #Piece Start
:part => :piece,
:count => 1,
:type => :physical,
:nature => :active,
:value => 5,
},#Piece End
{ #Piece Start
:part => :piece,
:count => 1,
:type => :physical,
:nature => :passive,
:value => 5,
},#Piece End
],#Armor Group END -----------------
#---------------------------------------------------------------------------
],#armor_v2
#---------------------------------------------------------------------------
},#Rotten Torso 1
#=============================================================================
#=============================================================================
2 => { #Rotten Torso 2
#---------------------------------------------------------------------------
:armor_v2 => [
#---------------------------------------------------------------------------
[ #Armor Group START ---------------
{ #Piece Start
:part => :piece,
:count => 1,
:type => :physical,
:nature => :active,
:value => 5,
},#Piece End
{ #Piece Start
:part => :piece,
:count => 1,
:type => :physical,
:nature => :passive,
:value => 5,
},#Piece End
],#Armor Group END -----------------
#---------------------------------------------------------------------------
[ #Armor Group START ---------------
{ #Option Start
:part => :option,
:type => :physical,
:pierce_rate => "0.95",
:breach_rate => "0.90",
},#Option End
],#Armor Group END -----------------
#---------------------------------------------------------------------------
],#armor_v2
#---------------------------------------------------------------------------
},#Rotten Torso 2
#=============================================================================
#=============================================================================
3 => { #Rotten Torso 3
#---------------------------------------------------------------------------
:armor_v2 => 2,
#---------------------------------------------------------------------------
},#Rotten Torso 1
#=============================================================================
When you consider I am trying to find a one stop shop for all data related to a single object ID, I simply can't think of an easier way than a Hash like the one above.
Each script will have its own key symbol, to access its data. If the single file gets to large, I can always just push new indexes into the hash from subsequent files. Or change the data mid game for whatever reason...
As for the long formula issue... I was referring to the difficulty of keeping things formatted and easy to read, in a large excel spreadsheet. Since such files tend to list item ID's up/down and data left/right, such cells can consume half the visible space. Forcing constant scrolling. Consuming time, much like using the default database UI. Sorta defeating the purpose of migrating the data manipulation the the spread sheet in the first place. :)
I just wasted half an hour, before I realized that Yanfly's Battle Engine replaced Scene_Battle.refresh_status
with status_redraw_target
...
From now on I think I need to make it a rule... I do my best to strip each idea into its simplest parts, and discover which parts are shared amongst all ideas. Work on that as the primary script, and FINISH IT. Then add each other part, one by one, making sure to FINISH one before moving to the>next.
Hopefully, avoiding a monster script, that never seems to end. And hopefully with fewer mistakes.
/sigh
Rule Number 2... Look to adapt existing scripts before full on adding new features to new ones...
/facepalm
Writing add-ons to existing scripts definitely saves a lot of time. Especially if it already designed with add-ons in mind.
I got feeling so smart that I went and added a feature to my Armor script that likely duplicates things I could have done with less complexity, had I just written a few plugins. Of course, on the flip side, I might be able to no longer use those scripts now that I have this alternative... /shrug
Reflection is as simple as an evaluation in ruby right?
Like how you did it in your Instance Items script.
class BaseItem
# List of all attributes that are shared instance variable
_instance_attr = [:name, :params, :price, :features, :note, :icon_index,
:description]
#---------------------------------------------------------------------------
# Define methods for all shared variables
#---------------------------------------------------------------------------
_instance_refresh = "def refresh"
_instance_attr.each do |ivar|
_instance_refresh << ";refresh_#{ivar}"
eval(
"def refresh_#{ivar}
var = InstanceManager.get_template(self).#{ivar}
@#{ivar} = make_#{ivar}(InstanceManager.make_full_copy(var))
end
def make_#{ivar}(#{ivar})
#{ivar}
end
"
)
end
_instance_refresh << ";end"
eval(_instance_refresh)
end
Such that this code:
def set_advanced_condition(_variable, value = 'true')
self.instance_variable_set("@#{_variable}".to_sym, "lambda {|r,a,e,p,t,v,s| #{value} }")
eval(
"def #{_variable}(r=@result, a=@result.battler, e=@owner, p=$game_party, t=$game_troop, v=$game_variables, s=$game_switches)
return true unless @#{_variable}
return RDeus.cache_armor_action(self, :#{_variable}, @#{_variable}).call(r,a,e,p,t,v,s)
end
"
)
@has_advanced_condition = true
end
Given that _variable
= on_result_eval
Would result in this method:
def on_result_eval(r=@result, a=@result.battler, e=@owner, p=$game_party, t=$game_troop, v=$game_variables, s=$game_switches)
return true unless @on_result_eval #might not be the defined condition.
return RDeus.cache_armor_action(self, :on_result_eval, @on_result_eval).call(r,a,e,p,t,v,s)
end
Ok... I was right. ;)
That is some seriously powerful shit.
module RDeus
#-----------------------------------------------------------------------------
#
#-----------------------------------------------------------------------------
def self.cache_armor_action(object, method_symb, lambda)
@cache_armor_action ||= {}
@cache_armor_action[object] ||= {}
return @cache_armor_action[object][method_symb] ||= eval(lambda)
end
end
class Test
attr_reader :on_hit
attr_reader :has_simple_condition
attr_reader :has_advanced_condition
attr_accessor :test_value
def initialize
@test_value = 9394
end
def set_simple_condition(symbol, value)
var = self.instance_variable_set(symbol, value)
# puts(var)
@has_simple_condition = true
end
# def set_advanced_condition(symbol, value)
# self.instance_variable_set(symbol, "lambda {|x| #{value} }")
# @has_advanced_condition = true
# end
# def on_result_eval(x=self)
# return true unless @on_result_eval #might not be the defined condition.
# return RDeus.cache_armor_action(self, :on_result_eval, @on_result_eval).call(x)
# end
def set_advanced_condition(_variable, value)
self.instance_variable_set("@#{_variable}".to_sym, "lambda {|x| #{value} }")
eval(
"def #{_variable}(x=self)
return true unless @#{_variable}
return RDeus.cache_armor_action(self, :#{_variable}, @#{_variable}).call(x)
end
"
)
@has_advanced_condition = true
end
end
test = Test.new
test.set_simple_condition(:@on_hit, true)
puts(test.on_hit) if test.has_simple_condition #true
test.set_advanced_condition(:on_result_eval, "x.test_value > 10000")
puts(test.on_result_eval) if test.has_advanced_condition #false
test.test_value = 93941
puts(test.on_result_eval) if test.has_advanced_condition #true
Question now is... Does the performance overhead warrant regular use of this?
Is there any other way to do this?
def set_advanced_condition(_variable, value = 'false')
self.instance_variable_set("@#{_variable}".to_sym, "lambda {|r,a,e,p,t,v,s| #{value} }")
eval(
"def #{_variable}(r=@result, a=@result.battler, e=@owner, p=$game_party, t=$game_troop, v=$game_variables, s=$game_switches)
return true unless @#{_variable}
return RDeus.cache_armor_action(self, :#{_variable}, @#{_variable}).call(r,a,e,p,t,v,s)
end
"
)
@has_advanced_condition = true
end
Just to be sure that I am not using a blunt tool here. It is a bit tricky to use when you consider that it is trying to read into every single thing you type. ;)
It works great btw...
Here is the current functional reflective advanced conditions...
def set_advanced_condition(_variable, value = 'false')
self.instance_variable_set("@#{_variable}".to_sym, "lambda {|r,a,e,p,t,v,s| #{value} }")
@advanced_conditions << "#{_variable}".to_sym
eval(
"def #{_variable}(r=@result, a=@result.battler, e=@owner, p=$game_party, t=$game_troop, v=$game_variables, s=$game_switches)
return true unless @#{_variable}
return RDeus.cache_armor_action(self, :#{_variable}, @#{_variable}).call(r,a,e,p,t,v,s)
end
"
)
@has_advanced_condition = true
end
#-----------------------------------------------------------------------------
def advanced_conditions
return true unless @has_advanced_condition
return false unless @result && @result.battler && @owner #Referenced in all Adv.Conditions
# return false unless self.on_result_eval
@advanced_conditions.each {|condition|
return false unless self.method(condition).call
}
return true
end
Now... If I wrap my noggin around more advanced nested regular expressions... Maybe I can figure out a way to no longer defined every potential note tag verbatim. A prefix of some kind would be great.
Playing with cached lambdas can be tricky... I dunno how it works, but it seems to take a snapshot of all related objects instance variables, at the moment its first cached. If that variable is nil, it stays nil, even if its assigned later.
Essentially the only time a method that calls a cached lambda should be used, is at the single moment its ever to be used, and no other. Otherwise you run the risk of related objects data states not being accurate upon future recall of the cached lambda.
Am I mistaken?
edit
example:
This actions result is clearly the subjects result at the moment the action is executed, or the eval condition would have been false (r
is referencing said result), and the action wouldn't have even fired.
But the action fired, and value errors as if result was nil
, until I removed a call of the method, shortly after the action objects creation, BEFORE subject result is defined.
I'm guessing r
returned the result, as it was cached after assignment, but e.result
was still nil, having been cached prior to assignment.
<armor>
<action>
<reflective>
result_eval: r.critical
type: magical
value: e.result.hp_damage
</action>
</armor>
Ok... Now my head hurts.
I am confused.
edit:
Would this effect global varaibles? Like p=$game_party
??
Due to this Armor Script, I am seriously re-evaluating the way I plan and write my future scripts.
Never Again... Never.
I would avoid premature optimization On Aug 26, 2015 5:43 PM, "Roguedeus" notifications@github.com wrote:
Due to this Armor Script, I am seriously re-evaluating the way I plan and write my future scripts.
Never Again... Never.
— Reply to this email directly or view it on GitHub https://github.com/Hime-Works/Requests/issues/285#issuecomment-135178984 .
I have half a mind to scrap it all and start over... using this leviathan as reference on what NOT TO DO.
But its difficult.
Lets see here... I've put at LEAST 120 Hrs into this thing... All I'd have to show for it, is experience. ;(
It works. As it exists, I could use it and do my best to overlook its rough edges. But something tells me, there are going to be problems in the future.
The code (heavily noted) and the use notes and options total more than 4500 lines. This is, without any doubt, the most complex thing I have ever written. AND IT WORKS.
Seems like a shame to just push it aside... lol
Sometimes it is better to start over. Other times you might try to see if you can clean it up.
Depends on how much effort you're willing to spend. On Aug 26, 2015 6:13 PM, "Roguedeus" notifications@github.com wrote:
I have half a mind to scrap it all and start over... using this leviathan as reference on what NOT TO DO.
But its difficult.
Lets see here... I've put at LEAST 120 Hrs into this thing... All I'd have to show for it, is experience. ;(
It works. As it exists, I could use it and do my best to overlook its rough edges. But something tells me, there is going to be problems in the future.
The code (heavily noted) and the use notes and options total more than 4500 lines. This is, without any doubt, the most complex thing I have ever written. AND IT WORKS.
Seems like a shame to just push it aside... lol
— Reply to this email directly or view it on GitHub https://github.com/Hime-Works/Requests/issues/285#issuecomment-135192570 .
I do recognize that a good half of the time its taken to finish this, was simply figuring out how to structure what I wanted, on the fly.
Trial and error like.
If I re-start, it will likely take a fraction of the time to get back to this point.
Time to analyze this and see what I can determine.
In Yanfly's HP Gauge script the Enemy_HP_Gauge_Viewport < Viewport
initialize method calls super(rect)
which is a hidden class.
#--------------------------------------------------------------------------
# initialize
#--------------------------------------------------------------------------
def initialize(battler, sprite, type)
@battler = battler
@base_sprite = sprite
@type = type
dw = YEA::BATTLE::ENEMY_GAUGE_WIDTH
dw += 2 if @type == :back
@start_width = dw
dh = YEA::BATTLE::ENEMY_GAUGE_HEIGHT
dh += 2 if @type == :back
rect = Rect.new(0, 0, dw, dh)
@current_hp = @battler.hp
@current_mhp = @battler.mhp
@target_gauge_width = target_gauge_width
@gauge_rate = 1.0
setup_original_hide_gauge
super(rect)
self.z = 125
create_gauge_sprites
self.visible = false
update_position
end
Shouldn't a derived class like Enemy_PA_Guage_Viewport < Enemy_HP_Gauge_Viewport
simply be able to call super(battler, sprite, type)
without issues?
I figured it out... It wasn't the initialize causing the trouble.
Do you think regular caching of frequently collected objects (such as feature objects) would make a great impact on performance?
Can you think of a way to measure possible improvements in game?
Ok, I know I'm not crazy now. Sometimes your use instructions are cryptic as hell. ;)
I still can't follow the directions you wrote on how to use your Feature Manger to create my own features. I am instead, doing my best to simply follow your code examples and guess my way through it.
lol
I really think more people would use this if they knew how to.
After an hour, I am about to give up. ;)
Every time I thought I was getting it, something confused me. And since the instructions in the script are completely different than those on the blog page, and huge chunks of the two examples you list, take for granted the user knows why you don't assign a code
value, or why you re-assign a data_id
after using it as a parameter? Or that all arguments passed in the note tag are collected in an array... etc...
I am still confused as to why the Add Param
example script defines this method
def add_feature_add_param(code, data_id, args)
data_id = FeatureManager::Param_Table[args[0].downcase]
add_feature(code, data_id, args[1])
end
Without any use for code
anywhere in the script. I assume its the symbol in the features_with_id
call...
def sum_add_param_features(param_id)
@eval_add_feature = true
sum = features_with_id(:add_param, param_id).inject(0) {|r, ft| r += eval_add_param_feature(ft.value, self)}
@eval_add_feature = false
return sum
end
And I am totally clueless why you are using the @eval_add_feature
flag. If I had to guess, its to prevent recursion? But I can't see where that would happen.
And I I am at a total loss as to how you are distinguishing between a normal value and something to evaluate. Is it evaluating every single value?
It would go a long way to note the code, step by step and reference it in the instructions. Like a paint by numbers in text.
I'll do it, if I was certain I wasn't incorrect.
I apologize if I was a bit critical. A little of my frustration may have seeped in to my feedback.
Do you think regular caching of frequently collected objects (such as feature objects) would make a great impact on performance?
Can you think of a way to measure possible improvements in game?
I'm sure caching would improve performance, given that features are collected very frequently. I don't know how one would do that reliably though.
If you want to measure performance you could probably run some sort of benchmarker on your code.
Without any use for code anywhere in the script. I assume its the symbol in the features_with_id call...
Ya, I think code
is kind of redundant here. I just kept it there in case someone wanted to change it for whatever reason, but code
is supplied when you register
the feature.
And I am totally clueless why you are using the @eval_add_feature flag. If I had to guess, its to prevent recursion? But I can't see where that would happen.
Try taking it out and see what happens. I think I added it because your formula might reference another parameter, and that parameter might reference this one.
And I I am at a total loss as to how you are distinguishing between a normal value and something to evaluate. Is it evaluating every single value?
Yes.
I really think more people would use this if they knew how to.
Maybe... I only did it as a test. I ended up not using it very much.
How would a benchmark work for an rpgmaker build? Or are you referring to creating a test scenario?
At the moment all I can manage is an FPS counter in the corner of the screen, as a blunt indicator.
...
I have gone and written a script I am calling 'Update'. Since I am not familiar with coding lingo I am not sure how to describe it, rather than that its a Hash of flags that can be reset when an update is needed, and set when its done, so that frequently created collections don't get rebuilt unless something in their collection has most likely changed.
The core does feature_objects
. Two plugins do all_features
and state
. But I intend to use it in all my scripts that create frequently rebuilt collections.
...
I'll revisit the feature manager and see if tackling it first thing after I wake up helps me digest it. The tireder I am the harder it is for me to stay focused.
We have Element Damage... And
UsableItem
Effects, like add state, etc... But nothing combined.What if, a stun wasn't just a stun, but an ICE stun? All rates are effected first by element resistance, and then by effect resistance. Thus a target 50% resistance to ICE, and 50% Resistance to Stun, has a 25% total resistance against ICE Stun.
This is just a simple example. But it would make certain effects able to be applied much more liberally, when something Immune to an element, is by extension also immune to all that elements linked effects.
Meanwhile, an EARTH Stun, will work fine... etc.
Elements are purely cosmetic. It would be linked to element ID's and thus can be easily extended.
Now... How would the easiest way to implement it be?
If the effect is a state, the note tag could be on that state... But then, it would require every state of every element to be individually defined. What if the link were made on the
UsableItem
?Thus, only one state is needed, and can be applied under different circumstances. Kind of like conditional effects.
This would mean that each blind effect could be assigned a different element ID dependency. Or the same dependency, under different conditions... etc...