New account registration is temporarily disabled.

[RGSS3] [SOLVED] YANFLY COMMAND EQUIP & LUNA ENGINE WORKS

Posts

Pages: first 12 next last
Red_Nova
Sir Redd of Novus: He who made Prayer of the Faithless that one time, and that was pretty dang rad! :D
9192
Good news: I think I figured out how to get Yanfly's Command Equip to work with the Luna Engine. Bad news: it requires a defunct Window_EquipStatus, a pretty important component of the equip scene. Hopeful news: I think I may know what to do, but I have no clue how to go about doing it. Hence the topic.


First, here's the temporary solution: Go to YEA's Equip engine line 1109 and add:
return if $game_party.in_battle

Just below the line: @last_item = item. Now Yanfly's Command Equip should work during battle:


Don't mind the battle HUD. That's an issue that can come later if this can work.

Battle HUD aside, do you notice something odd? That's right: the price you pay is that you can't see the changes in parameters when you highlight the individual equips. They still occur, don't worry, but you can no longer see it.

Now comment that line out, because the rest of my process doesn't have that line in. I just mentioned it so anyone who's fine with not seeing parameter changes can now use the script.

The reason the line is added is because the game crashes is due to the very next line:
temp_actor = Marshal.load(Marshal.dump(@actor))


In battle, the Luna Engine adds extra classes/properties to actors that Marshal's dump method doesn't recognize (mostly sprite properties). These new classes have neither marshal_dump nor marshal_load(obj) methods defined, so the game crashes. Well, okay, that's easy enough to fix. Those new classes aren't necessary for the equip scene to function, so creating some blank functions just to keep the game from crashing should work. After doing this for all the classes that cause the game to crash, I've got this little piece of code:

class Sprite_Base
  def marshal_dump; end
  def marshal_load(obj);  end
end


class Sprite
  def marshal_dump; end
  def marshal_load(obj);  end
end

class Bitmap
  def marshal_dump;  end
    def marshal_load(obj);  end
end

class Window_BattleActor < Window_BattleStatus
  def marshal_dump; end
  def marshal_load(obj);  end
end

  
class Font
  def marshal_dump;  end
  def marshal_load(obj);  end
end

class Method
  def marshal_dump;  end
  end

class Viewport
  def marshal_dump;  end
end

I run the program and... the game still crashes. However, it's no longer because of a lack of Marshal dumps. Instead, I've got:



That. And here, unfortunately, is where I'm stuck. It appears that something's screwy with marshal_load(obj) now that it won't even recognize the info. I don't think I messed anything up too badly, but I could be very wrong.

Now, I'm aware that the Command Equip script is listed as incompatible with the Luna Engine, and I'm also aware that, even if I can figure this out, there's no promise that it'll make everything work right. However, I've gotten this far in getting it to work, I feel like it's not much more before it'll work as intended unless I royally screwed something up with my current adjustment.

If anyone sees something I don't, I'd really appreciate it.
Don't use marshal to deep copy an object, use this instead. Then replace
temp_actor = Marshal.load(Marshal.dump(@actor))

with
temp_actor = @actor.deep_copy

with the deep copy code from SO pasted somewhere in your game
Red_Nova
Sir Redd of Novus: He who made Prayer of the Faithless that one time, and that was pretty dang rad! :D
9192
Well, this solution prevents the game from crashing, so yay! Unfortunately, unless I mislabeled something, the deep_copy isn't actually making a copy of the actor. On the field equip menu, I see this:



The selected sword changes a few of the character's parameters. Both sets of stats, however, are the altered versions, not a before/after comparison. What's worse, this messes up the actor's equip slots. Newly equipped items get deleted (not just unequipped!), and the newly equipped weapon isn't taken out of my inventory.

EDIT: I tested it some more, and it seems the actor's equip slots are deleted even without changing equips. Just selecting it, looking through the available options, and hitting cancel causes deletion.

EDIT2: This exact same result can be replicated by replacing
temp_actor = @actor.deep_copy
with
temp_actor = @actor.clone

Without the need for SO's code, which tells me I'm doing something wrong. Just can't figure out what...
Damnit, that should be creating a deep copy! All the issues sounds like it didn't copy the object instances inside of the actor object. I admit I haven't tested SO's code in Ace so maybe I missed something. I'll give it a more indepth look tonight when I get home from work.
Red_Nova
Sir Redd of Novus: He who made Prayer of the Faithless that one time, and that was pretty dang rad! :D
9192
I'd appreciate that, thanks! I tried something myself, but I'm not sure if it's the best solution.

*Redacted because that was definitely a bad idea.*
Red_Nova
Sir Redd of Novus: He who made Prayer of the Faithless that one time, and that was pretty dang rad! :D
9192
Update on the situation: GRS, I tested your solution on the Luna Engine Base and a fresh new project. Both tests ended in the same result: a deep_copy of the actor was not created.

What's really puzzling me is that I looked online for deep_copy solutions in Ruby, and I'm greeted with either the same result as you posted or a recommendation to just use the clone function. Neither of which produce the right result.

This is making me think that the issue isn't so much an incompatibility issue as it is a possible issue with RGSS3. Does anyone know which functions/settings/whatever Enterbrain modified for VX Ace? That could go a long way to figuring out what's going on here. I'll keep trying different things in the meantime. GRS, any luck on your end?
I completely forgot about this the entire weekend, sorry!


I'm not sure what bits of ruby are missing in RGSS3 but I certainly wouldn't put it past EB to leave bits out (in RMMV one if the first things I found out is that isNan(obj) is missing in their ECMA engine because ???). One possible solution is to just make our own actor copy code since that's all that's needed in your situation. Something like
temp_actor = Actor.new(@actor)

that'll copy all the important bits. It'll have to be done by hand though. I do want to look more into SO's deep copy because that'll fix all kinds of script compatibility issues for whoever decided to put non-serializable data in a class that others assumed would remain serializable.
Red_Nova
Sir Redd of Novus: He who made Prayer of the Faithless that one time, and that was pretty dang rad! :D
9192
No worries!

Your solution was actually the one I tried earlier but redacted. Granted, it IS the closest we've gotten to a working solution. I tried the line you showed, but that caused the game to crash. The line that works is

temp_actor = Game_Actor.new(@actor.id)


And it works. It'll change the equipment and show the before/after comparison for you parameters. Almost. If there are any changes in stats from stat-up items, that will not be reflected in the before/after comparison. Unless the copy of the stats are what you meant when you say "done by hand"
Haha, I should've thought my snippet a bit more thoroughly. I meant make our own clone style method but only for actors that would copy the instance variables over (like the stat ups, current class, equipment, etc.). So more like, with your bit of code:
temp_actor = Game_Actor.new(@actor.id)
temp_actor.copy_from(@actor)


with
class Game_Actor < Game_Battler
  def copy_from(actor)
    # copy stuff like statups from the passed actor, read access may need to be given so that we can copy the appropriate stuff
    @statups = Marshal.load(Marshal.dump(actor.statups))
    @equipment = Marshal.load(Marshal.dump(actor.equipment))
    # etc..
  end
end

I don't have the Actor's internal structure available on-hand so I can't make my example more explicit. Array values should be deep copied and the Marshal load/dump will work in this case (since we're just doing the explicit data arrays and not the entire class with the luna landmines hidden in them)
Red_Nova
Sir Redd of Novus: He who made Prayer of the Faithless that one time, and that was pretty dang rad! :D
9192
If it's not one thing, it's another -_-

The property we're looking for here is this method
def param_plus(param_id)
    equips.compact.inject(super) {|r, item| r += item.params[param_id] }
  end


This collects all the different modifications to the stats, including item use. However, this include changes made from equipment too, so we can't just copy over this property in the copy_from method.

Even if we could, the copying of equipment is crashing the game.
@equips =  Marshal.load(Marshal.dump(actor.equips))


This line is causing the crash


I have no idea how this is happening.
They way it was deep copying turned out to be really... lacking. Numeric/True/False can't be cloned the way it was doing it (they are just set values that can't be copied) and how it was doing arrays wasn't doing a deep copy of them. I just expanded some use cases on classes and got this:
class Object
  def deep_clone
    return @deep_cloning_obj if @deep_cloning
    @deep_cloning_obj = clone
    @deep_cloning_obj.instance_variables.each do |var|
      print "Cloning #{var}\n"
      val = @deep_cloning_obj.instance_variable_get(var)
      begin
        @deep_cloning = true
        val = val.deep_clone
      rescue TypeError
        print "TypeError occured :( #{$!} \n"
        next
      ensure
        @deep_cloning = false
      end
      @deep_cloning_obj.instance_variable_set(var, val)
    end
    deep_cloning_obj = @deep_cloning_obj
    @deep_cloning_obj = nil
    deep_cloning_obj
  end
end

class Array
  def deep_clone
    return map { |x| x.deep_clone }
  end
end

class Numeric
  def deep_clone
    return self
  end
end

class FalseClass
  def deep_clone
    return self
  end
end

class TrueClass
  def deep_clone
    return self
  end
end

class NilClass
  def deep_clone
    return self
  end
end
It worked in a vanilla Ace project where I replaced the Marshal.load/dump line in Window_EquipItem and it looked to work fine... except that there's a three point mystery discrepancy in the temp_actor that I haven't found the cause of yet. Haven't found any other issues yet but it's a pretty light test so far (weapon and some stat up items).

e: Oops, meant there's a 3 point stat difference in defense even when nothing touches it. Varies a bit between the default actors too.
Red_Nova
Sir Redd of Novus: He who made Prayer of the Faithless that one time, and that was pretty dang rad! :D
9192
I'm looking at it myself. It looks like the stat changes from each individual piece of equipment isn't registering with the others. I tested it by creating a piece of armor that boosts all parameters by 1 and a weapon that makes no changes. When I highlight the weapon with the armor equipped, the stat parameters all drop down by 1.

EDIT: Here's what I mean:





No actual changes are made to the stats outside of the equipment's parameters. It just looks that way from the status window.
Ahh, that explains it. I was poking in the entirely wrong place. I'll look more into the gear itself then and see what horrible mistake I made.

e: Looks like... the deep_clone isn't working arrays of objects. Primitives are fine, so I'm overlooking something again!

e2: Or not. hmmmmmmmmm
Red_Nova
Sir Redd of Novus: He who made Prayer of the Faithless that one time, and that was pretty dang rad! :D
9192
Thanks man! I wish there was more I could do to help.
Found the sneaky bugger. The deep_clone was in fact too aggressive. It would clone the class reference of Game_BaseItems which would trip up its own code because it no longer had an idea what the RPG::BaseItem class associated with the Game_BaseItem was! Simply not cloning a class is sufficient to get the deep_clone to work.

Updated code:
class Object
  def deep_clone    
    return @deep_cloning_obj if @deep_cloning
    @deep_cloning_obj = clone
    @deep_cloning_obj.instance_variables.each do |var|
      val = @deep_cloning_obj.instance_variable_get(var)
      begin
        @deep_cloning = true
        if(val.is_a? Class)
          val = val
        else
          val = val.deep_clone
        end
      rescue TypeError
        next
      ensure
        @deep_cloning = false
      end
      @deep_cloning_obj.instance_variable_set(var, val)
    end
    deep_cloning_obj = @deep_cloning_obj
    @deep_cloning_obj = nil
    return deep_cloning_obj
  end
end

class Array
  def deep_clone
    return map { |x| x.deep_clone }
  end
end

class Numeric
  def deep_clone
    return self
  end
end

class FalseClass
  def deep_clone
    return self
  end
end

class TrueClass
  def deep_clone
    return self
  end
end

class NilClass
  def deep_clone
    return self
  end
end

No more missing 3 DEF in my two second test project! Let me know how it turns out on your end.
Red_Nova
Sir Redd of Novus: He who made Prayer of the Faithless that one time, and that was pretty dang rad! :D
9192
YES! IT WORKS! Thank you GRS! You're the best!
unity
You're magical to me.
12540
Hooray! :D Yeah, GRS is amazing ^_^
Glad to hear it works now! :)
Red_Nova
Sir Redd of Novus: He who made Prayer of the Faithless that one time, and that was pretty dang rad! :D
9192
... Almost.

Remember that battle HUD issue I passed off earlier as an easy fix? Turns out it's not quite that easy.

The command window was easy enough to hide during the equip scene, but the status window and character bust will not disappear until after the equip scene is over, which is weird. I tested this by removing the calls to show the HUDs after Scene_Equip is over.



The face and bust are there despite calling the methods to hide them. Now, when I exit Scene_Equip...



Yikes.

So there's a delayed reaction in the sprites being erased, and I have no idea why. They can't be covered up because the Z values for all the windows in Scene_Equip are already higher than the windows in Scene_Battle


EDIT: Update: I figured out how to get the character busts to work:
def show_battler_picture
    #$game_troop.screen.pictures[1].show("ActorSelection_" + BattleManager.actor.class_id.to_s, 0, 0, 90, 100.0, 100.0, 255, 0) 
    @leaf = Sprite.new
    @leaf.bitmap = Cache.picture("ActorSelection_" + BattleManager.actor.class_id.to_s)
  end

  def hide_battler_picture
    #$game_troop.screen.pictures[1].erase if $game_troop.screen.pictures[1]
    @leaf.bitmap.dispose
    @leaf.dispose
  end

Where the commented lines are what has been replaced. If I can figure out how to do the same thing with @status_window then it'll be perfect.
The quickest and dirtiest way would be to just move the window offscreen and inactive (iirc it's @status_window.active = false ?) so it doesn't respond to input. I don't remember how window cleanup works in Ace atm though and I can't check it 'till I get home from work at the end of the day.
Pages: first 12 next last