Hime-Works / Requests

Bug reports and requests that may require longer discussions and is not suitable to leave on the blog
http://himeworks.com/
GNU General Public License v2.0
7 stars 9 forks source link

State Elements... #285

Closed Roguedeus closed 8 years ago

Roguedeus commented 8 years ago

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.

example_2 This would mean that each blind effect could be assigned a different element ID dependency. Or the same dependency, under different conditions... etc...

Roguedeus commented 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.

Roguedeus commented 8 years ago

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?

Roguedeus commented 8 years ago

I always get a flood of ideas when watching DotA2 matches. It's a curse.

Roguedeus commented 8 years ago

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.

Roguedeus commented 8 years ago

Any criticisms?

HimeWorks commented 8 years ago

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 .

Roguedeus commented 8 years ago

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?

HimeWorks commented 8 years ago

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 .

Roguedeus commented 8 years ago

Ah... Forgot about that.

Roguedeus commented 8 years ago

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.

Roguedeus commented 8 years ago

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

Roguedeus commented 8 years ago

So... I am not going to combine the State Elements with Aptitudes. Was my original point I failed to make. ;)

HimeWorks commented 8 years ago

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.

Roguedeus commented 8 years ago

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.

Roguedeus commented 8 years ago

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.

Roguedeus commented 8 years ago

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?

HimeWorks commented 8 years ago

I'm not sure. What are you thinking? Using external data files and just having the script load it in?

Roguedeus commented 8 years ago

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.

Roguedeus commented 8 years ago

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

Roguedeus commented 8 years ago

Also... I just noticed that excel 2010 has a pretty robust flowchart tool set. BOGGLE

excell_15_0819

Roguedeus commented 8 years ago

Does the script data hash appear over engineered?

HimeWorks commented 8 years ago

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.

Roguedeus commented 8 years ago

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.

HimeWorks commented 8 years ago

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.

Roguedeus commented 8 years ago

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. :)

Roguedeus commented 8 years ago

I just wasted half an hour, before I realized that Yanfly's Battle Engine replaced Scene_Battle.refresh_status with status_redraw_target...

Roguedeus commented 8 years ago

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

HimeWorks commented 8 years ago

Writing add-ons to existing scripts definitely saves a lot of time. Especially if it already designed with add-ons in mind.

Roguedeus commented 8 years ago

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

Roguedeus commented 8 years ago

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
Roguedeus commented 8 years ago

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
Roguedeus commented 8 years ago

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
Roguedeus commented 8 years ago

Question now is... Does the performance overhead warrant regular use of this?

Roguedeus commented 8 years ago

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...

Roguedeus commented 8 years ago

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.

Roguedeus commented 8 years ago

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>
Roguedeus commented 8 years ago

Ok... Now my head hurts.

I am confused.

edit: Would this effect global varaibles? Like p=$game_party??

Roguedeus commented 8 years ago

Due to this Armor Script, I am seriously re-evaluating the way I plan and write my future scripts.

Never Again... Never.

HimeWorks commented 8 years ago

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 .

Roguedeus commented 8 years ago

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

HimeWorks commented 8 years ago

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 .

Roguedeus commented 8 years ago

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.

Roguedeus commented 8 years ago

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?

Roguedeus commented 8 years ago

I figured it out... It wasn't the initialize causing the trouble.

Roguedeus commented 8 years ago

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?

Roguedeus commented 8 years ago

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.

Roguedeus commented 8 years ago

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.

Roguedeus commented 8 years ago

I apologize if I was a bit critical. A little of my frustration may have seeped in to my feedback.

HimeWorks commented 8 years ago

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.

Roguedeus commented 8 years ago

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.