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

Light Weight - Battle Order - Script Plugin, Idea #246

Closed Roguedeus closed 9 years ago

Roguedeus commented 9 years ago

I am thinking of writing a plugin for Yanfly's FTB Battle Option that utilizes its AP model but maintains the speed/initiative of the default system, with a twist.

Like FTB, actors will be able to take multiple actions in a turn, dependent on the AP used in the action. But unlike FTB, each potential action point has its own initiative and actions that require multiple action points must WAIT until the total points needed reach their initiative order.

The catch, of course, is that the player will need a visual indicator so they are aware when their potential actions will fall within the order. I figure I could use Yami's - Order Gauge for this somehow.

Thoughts? Critiques? Potential issues?

Roguedeus commented 9 years ago

Out of curiosity. Would you know of a simple way to institute sub-commands?

Say the command window had some commands with arrows on the right, denoting its selection would open a new command window at the same location, but filled with a new list of commands. Canceling would simply, step back to the previous command list.

Believe me when I say I haven't the first clue how I would accomplish this. But I thought you might.

Roguedeus commented 9 years ago

Also... Confirmation Windows, in battle.

Hmmm... No idea how I might do this. But is it worth taking the time to learn?

I have Delay and Pass working as intended. All actions have AP cost formulas. Now all I need to complete the basic (non-expended) mechanic is to allow enemies to pass their turn if they can't afford the AP of any of their possible actions.

HimeWorks commented 9 years ago

You may be able to write a plugin to the command manager to support subcommands.

First, have commands hold an array of commands. Then update the scene to check whether the command has subcommands. If it does, refresh the actor command window with the new commands.

Upon returning, you would load the previous commands. On Jun 29, 2015 9:31 AM, "Roguedeus" notifications@github.com wrote:

Out of curiosity. Would you know of a simple way to institute sub-commands.

Say the command window had some commands with arrows on the right, denoting its selection would open a new command window at the same location, but filled with a new list of commands. Canceling would simply, step back to the previous command list.

Believe me when I say I haven't the first clue how I would accomplish this. But I thought you might.

— Reply to this email directly or view it on GitHub https://github.com/Hime-Works/Requests/issues/246#issuecomment-116637688 .

Roguedeus commented 9 years ago

I am so clueless when it comes to wordpress blogs... No idea how to make lists of posts for easy reference, and whatnot.

edit: Well, that was interesting. It seems that the customize page is the idiots version of the admin page. No wonder I couldn't figure anything out. Heh...

Roguedeus commented 9 years ago

Its a start... https://roguedeus.wordpress.com/ap-combat-system/

This is the first script that is easy enough to use, and worth the bang for the buck, to share. (Its what I would have hoped of others. So its the least I could do. Battle mechanics are a big deal.) I just wish Wordpress wasn't so damned idiot proof.

edit: Speaking of idiots... This one can't decide on a theme. :(

edit: Ok, got one... Good enough, considering its free. And I'm not up for learning to write my own.

Roguedeus commented 9 years ago

Revisiting the remnants of my state mechanic two months after I looked at it last is painful. Even more so because I know its good for what it does, so I don't want to mess to much with whats already done. I just wish I could remember why the hell I did some of them. ;p

I think its about time I revisit my old habits of putting notes on EEEEEEEEVERYTHING.

Roguedeus commented 9 years ago

I hate it when this happens...

There I was, riding this wave of creativity, features flying out my ass like rainbows out of Nyan Cat, when suddenly one of my most resent and inspiring feature grinds to a sudden halt... I can't decide if I want to make it dependent on your instanced items script.

And I can't think of a way to accomplish what I am looking for another way.

Granted, I have intended on using your instanced items in my build, but I had begun writing Armor version 2, with the intention of having NO dependencies.

Sure I can make the dependency optional. But then it completely trivializes the PRIMARY balancing factor regarding Passive Armor. (that's the armor that is always renewed each turn)

Which is armor piece failure. (some actions in battle will break pieces of armor)

The idea is that Armor requires some sort of upkeep, like health would in any normal since. You'd drink a potion to restore Health, and you'd consume a repair kit to restore failed pieces of armor. (or use a repair skill)

Thus if you run out of repairs, you're armor will very likely become useless in short order. It also encourages carrying more than one suit or armor to swap out on occasions, besides the typical min/max scenarios.

Without this feature, building a Passive Armor tank has to few counter balances, and will make 'Active' Armor alternatives comparatively punishing.

Ugh...

Roguedeus commented 9 years ago

it feels weird looking at your instanced items script... I can CLEARLY remember a time, not to long ago, it felt like I was looking at some strange system of hieroglyphics when I tried to make since of this thing.

Roguedeus commented 9 years ago

Quick question...

Ruby (as a language) interprets 100% its code at run time. So, when it first loads code that aliases a method it hasn't seen yet (before its included) it will error as it has no idea what that method is at that moment... But if that method is wrapped in a conditional, such as this...

  if $imported["YEA-ClassSystem"]
  alias :rd_armor_change_subclass :change_subclass
  def change_subclass(class_id)
    rd_armor_change_subclass(class_id)
    refresh_armor
  end
  end

It won't error.

Do you know why?!? I can only guess...

HimeWorks commented 9 years ago

My assumption is that it hasn't executed the code, so there aren't any issues. Prematurely aliasing methods may also be undesirable. On Jul 19, 2015 9:54 AM, "Roguedeus" notifications@github.com wrote:

Quick question...

Ruby (as a language) interprets 100% its code at run time. So, when it first loads code that aliases a method it hasn't seen yet (before its included) it will error as it has no idea what that method is at that moment... But if that method is wrapped in a conditional, such as this...

if $imported["YEA-ClassSystem"] alias :rd_armor_change_subclass :change_subclass def change_subclass(class_id) rd_armor_change_subclass(class_id) refresh_armor end end

It won't error.

Do you know why?!? I can only guess...

— Reply to this email directly or view it on GitHub https://github.com/Hime-Works/Requests/issues/246#issuecomment-122662892 .

Roguedeus commented 9 years ago

That was what I guessed. It suggests whats happening is that every single method that is ever called, is analyzed based on its current run time state.

Is it correct to then assume that a compiled language is so fast because it has already determined that all potential run time states are valid? Static types included.

Anyway... On an off note, I just did four hours of coding on my Armor script without a single play test, and when I finely ran it, I had nothing but a few syntax issues. It seems I am FINELY getting this coding thing... :)

Roguedeus commented 9 years ago

Just to be sure...

When an object is instantiated in Ruby it resides in memory as long as there is at least one reference to it.

Over the course of the game, such objects can easily be referenced by multiple instance variables or collections. Thus, to truly delete the instance, each reference must be tracked and removed. Otherwise, if the instance were to be allowed to be deleted outright, any remaining reference will become invalid and throw an exception (or crash).

Thus it is good practice, to periodically require any data classes or collections of references (like an array) to rebuild (or refresh) itself. Thus, discarding any unnecessary old references that are no longer valid.

Am I mistaken anything?

Roguedeus commented 9 years ago

I just had an issue where armor pieces I had created, were referenced by a master array and sorted into separate specific arrays.

Later, some of the armor was removed from a master array, but still appeared in the specific array.

I thought I had adequately ensured the specific array would have been missing the removed armor. But for some reason I had to completely destroy the specific array and recreate it, for it to work.

Perhaps I misunderstood the functionality of 'nil' objects. Or missed a flag... I just want to make sure I am not misunderstanding the way object references work.

HimeWorks commented 9 years ago

A nil (or null) object is just an explicit way to say that a reference points to nothing. Or something like that.

Here's an example class that holds a number

class Test
  attr_accessor :num

  def initialize(num)
    @num = num
  end
end

Now create some of these objects and toss them in a list

a = Test.new(1)
b = Test.new(2)
c = [a,b]

At this point, you can see that c is an array that holds two references. That is:

a and c[0] point to the same object (call it O1) b and c[1] point to the same object (call it O2)

To verify this is true, you can check the memory addresses of each reference, or you can simply modify one of the objects

p c[0]   # you will see a Test object with num 1
a.num = 5
p c[0]   # the Test object now has num 5

So what happens if you set a to nil? You are changing the object that a references to.

In the beginning, c[0] holds a reference to O1 After setting a to nil, c[0] still holds a reference to O1.

All you've done is change what the variable is referencing; you didn't change the value at that location. Contrast this with changing the object's number.

HimeWorks commented 9 years ago

Now given the information above, we can look at your question

Over the course of the game, such objects can easily be referenced by multiple instance variables or collections.

Yes. For example, let's say you had a sword in your inventory, and then you put the sword in a storage chest.

Thus, to truly delete the instance, each reference must be tracked and removed. Otherwise, if the instance were to be allowed to be deleted outright, any remaining reference will become invalid and throw an exception (or crash).

This depends on how you are deleting the instance.

RPG Maker uses arrays to represent a database, and all objects simply reference the database via ID's. So when you try to look up ID 5, and ID 5 has been set to nil, then it will probably crash if you were expecting a valid object.

If you replaced ID 5 with a different object, now you have an invalid reference because you are suddenly pointing to a different object.

This is not an issue if all instances were self-contained objects (eg: you store objects instead of ID's and move those around). You could then have the issue where multiple objects reference it, and then you need to keep track of all of them.

Thus it is good practice, to periodically require any data classes or collections of references (like an array) to rebuild (or refresh) itself. Thus, discarding any unnecessary old references that are no longer valid.

That sounds a bit questionable. Under what circumstance would you delete a reference, and then require anything that references it to refresh its entries?

Roguedeus commented 9 years ago

That sounds a bit questionable. Under what circumstance would you delete a reference, and then require anything that references it to refresh its entries?

A specific example would be that if I use your instance items script, every piece of armor that gets equipped is assigned its own set of armor 'pieces'. Thus a suit of Leather Armor may have 5 'Pieces' of armor, each (possibly) with its own unique details.

(I am simplifying this for the sake of explanation)

When an actor equips the suit, all of its pieces are referenced by the actors armor pool, which itself is selectively queried by data classes that represent each type of potential armor... In this case, there are currently only two types. Physical and Magical.

For the sake of speed, I am caching these queries inside each of the data classes, until some external activity flags them to be refreshed.

Potentially, there are three separate places where the same objects are referenced inside arrays. The two data classes should have been rebuilding their caches whenever equipment changed. This way, all I needed to do was remove the pieces from the actors pool. But it wasn't happening.

Its possible I missed something in my own code. But rather than flag the caches to be rebuilt, I started assigning 'nil' to them.

  def armor_pieces
    return @armor_pieces unless @armor_pieces.nil?
    @armor_pieces = []
    @battler.armor_groups.each {|group|
      @armor_pieces << group.pieces.select {|piece| piece.type == self.type}
    }
    @armor_pieces.flatten!
    return @armor_pieces
  end

Your explanation is pretty much what I thought. I am not sure why I found myself confused earlier, I was just locked into a certain mode and apparently couldn't determine if I was trying to do something incorrectly, or if I just didn't understand it adequately.

I appreciate your answer. :)

Roguedeus commented 9 years ago

This script has been a practice in inheritance, and object oriented programming... Getting me away from my more functional style I had adopted via learning to code originally (and quite terribly) with a C like scripting language with no ability to define classes, or use arrays!!

The price I have paid for refusing proper education. :p

Roguedeus commented 9 years ago

Here is an example of a test note tag... It kind of resembles XML. (Though I have never used it)

<armor>
  <piece>
    count:  rand(3)+a.level
    type: physical
    nature: passive
    value: 10
  </piece>
  <piece>
    count:  rand(2)+a.level
    type: physical
    nature: active
    value: 10
  </piece>
  <piece>
    count:  rand(2)+a.level
    type: magical
    nature: passive
    value: 10
  </piece>
  <piece>
    count:  rand(3)+a.level
    type: magical
    nature: active
    value: 10
  </piece>
</armor>
HimeWorks commented 9 years ago

Caching would be a good example where you want to refresh the cache periodically. Or at least, make sure that the reference is still valid.

I don't have much experience with caching so I don't know what would be a good way to implement it. If performance is not an issue, I would not bother with caching.

Roguedeus commented 9 years ago

I am guessing that if you program for a living... Professionally that is... You eventually learn to constrain yourself within the parameters of what is necessary for your output and not to add to many extras. Each part is something else to break, or bug out. ;)

Sadly, I can understand this, but I have yet to internalize it. lol... My armor script is becoming a monstrosity.

Roguedeus commented 9 years ago

Either I am writing the best script I have ever written, or my brain is softening.

The jury is out.

HimeWorks commented 9 years ago

I typically try to do as little as possible in one script.

Roguedeus commented 9 years ago

That is an art I have yet to master!

I think its due to my still limited ability to abstract ideas into separate groups of code.

Roguedeus commented 9 years ago

This is the first script I've written where most methods actually consider the input when determining their output, rather than simply being single use triggers. (Not sure what the correct terms are.)

Though I still have to digest the use of unexpected arguments. Or whatever its called when I see this... def method(*args)

Roguedeus commented 9 years ago

I don't think I have ever been so satisfied by writing a script. Let alone one this challenging. Yet, when I look at it, I am filled with a contentment that I have never experienced before. Almost like it used to feel when I was very young, and still into drawing art. I would sometimes make something that made me proud to have made it. As if I had crossed some barrier, bringing a conclusion to some sort of journey.

A journey I didn't even know I was on, and yet looking back, was unmistakable.

Or maybe I am just way to self congratulatory. ;)

HimeWorks commented 9 years ago

Well, it's good to feel satisfied with what you're doing, no matter how challenging. Does it work?

Roguedeus commented 9 years ago

Do you ever find yourself challenged by what you are attempting to do?

I can imagine that eventually coding becomes so easy that you really just see most things as a measure of how much time it will take to finish.

HimeWorks commented 9 years ago

There are a lot of scripts I've attempted that did not work out, or did not work out as well as I would like it to.

If you're doing the same type of problem, then it might get boring, but usually that isn't the case. For example, implementing different types of battle systems typically comes with their own types of challenges.

Roguedeus commented 9 years ago

Something I've noticed about coding that other forms of authorship lack, is the immediacy with which you can measure success or failure. It either works, or it doesn't.

There is a lot less subjectivity in this, than say for a story or song writer.

Also, most code is written to be used with other code. Which makes it necessary for the author to ensure the code doesn't get in the way of its neighbors and is still able to accomplish its goals. It encourages a 'big picture' sort of cooperation that rarely (if ever) exists in stories or music... Or much of any forms of art.

The closest thing I can think of is movies. (Theater, TV, etc..) But even then, most of what is made for movies, are single shot one and done sort of things that are again rarely (if ever) intended for constant use. It is consumed and discarded.

I am not sure what I am trying to say... I just know that I have an entirely new respect for professional programmers, and cringe at the thought of some of my older criticisms. I can see now, clearer than ever, why good programmers get paid so well. The difference between a well written program, and a shitty one, is orders of magnitude compared to the difference between a well written story or song, and a shitty one.

So much so that lately I have felt PAIN looking at some of my previous scripts!! But I am doing my best not to re-write them all.

Roguedeus commented 9 years ago

Why am I having such a hard time declaring a method as private?

private
def foo
  #stuff
end

It's treating everything under it as private... Do I need to place the method at the bottom of the class, or can I box it up?

edit: I can't seem to find a quick answer to this. Perhaps its to stupid a question... lol

HimeWorks commented 9 years ago

http://stackoverflow.com/questions/10724221/where-to-place-private-methods-in-ruby

Roguedeus commented 9 years ago

Thanks for pointing that out!

I googl'd but didn't directly search stackoverflow... /sigh

Roguedeus commented 9 years ago

I am losing my patience with this script (I want it to be done) and I'm beginning to feel the impulse to stop practicing the refinements I've been doing so far... But I am resisting.

The only way I will get better is to do the work. I will only be cheating myself if I don't! Alright, I hope I've convinced myself... :)

Roguedeus commented 9 years ago

The eternal dichotomy... Versatility Vs. Speed

Make the code more versatile, speed suffers. Make the code faster, versatility suffers.

I hate this...

Roguedeus commented 9 years ago

Is duplicating and altering a constant, inside an alias, the only way to add to it without overwriting a method that uses the constant?

Example Constant:

    POPUP_RULES ={
      "DEFAULT"  => [   2.00,   1.0, 16, true,  false, 255, 255, 255, DEFAULT],
      "CRITICAL" => [   2.50,   1.0, 18, true,  false, 255,  80,  80, DEFAULT], 
    }

I just want to add new rules to a hash... Without overwriting it.

HimeWorks commented 9 years ago

I don't understand what you are trying to do. Can you provide an example? If your constant references a hash you can just add to it. On Aug 2, 2015 2:27 PM, "Roguedeus" notifications@github.com wrote:

Is duplicating an altering a constant, inside an alias, the only way to add to it without overwriting a method that uses the constant?

Example Constant:

POPUP_RULES ={
  "DEFAULT"  => [   2.00,   1.0, 16, true,  false, 255, 255, 255, DEFAULT],
  "CRITICAL" => [   2.50,   1.0, 18, true,  false, 255,  80,  80, DEFAULT],
}

I just want to add new rules to a hash... Without overwriting it.

— Reply to this email directly or view it on GitHub https://github.com/Hime-Works/Requests/issues/246#issuecomment-127052258 .

Roguedeus commented 9 years ago

I must be misremembering something then...

I just want to add new rule arrays to the hash. I haven't tried it yet. For some reason I seem to remember trying to in the past and getting an error about not being able to change constant values or some such...

Roguedeus commented 9 years ago

GUI work is agonizing...

HimeWorks commented 9 years ago

Yes, GUI is pretty boring. I think we need a GUI framework.

For constants, you cannot change what it references (eg: from one object to another), but you are free to change the contents of whatever it points to.

Roguedeus commented 9 years ago

And I am using Yanflys core and battle system. I haven't tried to play with Luna, or even the default gauges so I couldn't compare.

Roguedeus commented 9 years ago

Am I doing something wrong here?

    puts("<Armor> Creating (#{@owner.name}) Action. item_id(#{@item_id})")
    puts("        Value_Form:#{@value_form}  = value(#{self.value(@user, @user)})")

  def value(a, b, e=self.owner, p=$game_party, t=$game_troop, v=$game_variables, s=$game_switches)
    return RDeus.cache_armor_action(@user, :value, @value_form).call(a,b,e,p,t,v,s)
  end  

WTF?!? gl_armorv2_issue_2e

How is a clearly NEGATIVE value being returned as positive, after evaluation? It doesn't happen in any other context that I have noticed... Or I am REALLY unobservant. (Or just having a bad day)

HimeWorks commented 9 years ago

Well, what does the function do?

Roguedeus commented 9 years ago

Its your lambda cache function.

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

Nevermind... /facepalm

Roguedeus commented 9 years ago

It was the @user variable... It should have been self

edit: It just so happens that the object it was actually returning was a positive 10... Go figure.

The eval was returning the wrong cache object. I really am beginning to lose my patience with this script... lol I am starting to over react as I used to in the past, before I knew better.