Author Topic: About RPG maker's internal bugs  (Read 5216 times)

Offline Wecoc

  • Transcended Spirit
  • ***
  • Posts: 108
  • LV: 44
  • Gender: Male
    • View Profile
    • Mundo Maker
About RPG maker's internal bugs
« on: August 16, 2014, 02:29:43 AM »
RPG maker are full of internal bugs. Some have a known solution and others not yet. That's why I decided to make some sort of a compilation of them and I tried also to fix some.
I will post some of them, you can do the same.

Here's a template

Code: [Select]
[size=18pt][b][u][Maker] Bug's name[/u][/b][/size]

[size=14pt][b]Description[/b][/size]

> Short description of the bug <

[size=14pt][b]Examples[/b][/size]

> Examples about the problem (optional) <

[size=14pt][b]Screenshots[/b][/size]

> Only if it's necessary to understand the bug <

[size=14pt][b]Solution[/b][/size]

> If there is not a solution specify it <



[XP] Interpreter Script Call Bug

Description

On Script Call from events, when the final eval is 'false' the game crashes.

Examples

Code: [Select]
a = false
Code: [Select]
$game_system.timer_working = false
There are some ways to avoid it but it's not a real solution for the bug

Code: [Select]
a = false
result = true
Code: [Select]
a = false ; true
Solution

There is an official bugfix for this internal bug; Interpreter Script Call Fix



[XP] Float Speed Bug

Description

If you change the speed of the player to a float, the map and the events do not scroll exactly overlapped.

Screenshots

(click to show/hide)

Solution

There is not a known solution for this bug.



[XP] F12 Stack Level Too Deep

Description

If you press F12 in-game the game has to stop and go to the Title Screen. But sometimes the game will crash with a 'stack level too deep' exception.

Solution

It's an alias problem. What you have to do is simple; look for all the 'alias' in your scripts, for example

Code: [Select]
alias nmode7_setup setup
and add 'unless $@' on the back.

Code: [Select]
alias nmode7_setup setup unless $@


[XP] The 'Remove and restore Sprite Battler' problem

Description

On battle, if you call a common event to remove an actor and later you call another common event (for example with an item) to get him again to the party (easy way to do an invocation system) its sprite reappears in the same place as before and it should not (I didn't found this bug and I don't understand exactly how it's supposed to work, sorry)

Solution

Quote from: Orochii
I found the problem. That is solved with one line of code in the right place...

Find this on Sprite_Battler:
Code: [Select]
#--------------------------------------------------------------------------
  # * Frame Update
  #--------------------------------------------------------------------------
  def update
    super
    # If battler is nil
    if @battler == nil
      self.bitmap = nil
      loop_animation(nil)
      return
    end

And replace that with this:
Code: [Select]
#--------------------------------------------------------------------------
  # * Frame Update
  #--------------------------------------------------------------------------
  def update
    super
    # If battler is nil
    if @battler == nil
      @battler_name = nil
      self.bitmap = nil
      loop_animation(nil)
      return
    end

This solves the problem. What happens is that the game deletes the image but not the variable that tells which image is loaded. So when you restore the same hero the script does not reload the image because it thinks the image was already loaded. I added @battler_name = nil so the variable is cleared too.

The new bugfix of 'Screen animation to multiple sprites' by LittleDrago fixes this one too.



[XP] The 'Teleport and Collision' weird problem

Description

You are in a map (Map1) which has an event that teleports you wherever in the Map2. In the same coordinates than the event but in Map2 there's another event with collision condition which does whatever. That second event should not be activated, but it is.

Solution

Put this above main:

Code: [Select]
class Game_Event
  alias transferring_fix_cet_auto check_event_trigger_auto unless $@
  def check_event_trigger_auto
    if @trigger == 2 and $game_temp.transition_processing
      return
    end
    transferring_fix_cet_auto
  end
end



[XP] Parallel process in the first map

Description

When you initialize a new game from the title things are loaded is that sequence:
1) Events with Parallel Process start working
2) Transition from Title Screen to the game (20 frames)
3) $game_map and all its things are loaded
4) Auto-start Events, map's music, etc. start working

The problem is, if you start a parallel process which uses something related to the map, $game_map was not loaded yet when it starts so the game crashes, and if you use an Auto-start to solve that, it starts when the transition was done so maybe it will look bad. Also if you use a script call with 'if $scene.is_a?(Scene_Map)' or you use a 'Wait x frames', to try to solve the problem.

Solution

I did an script for an engine of my game and by chance this fixes the problem, but the fix by LittleDrago is much more concise.
Put the script above main:

Code: [Select]
#==============================================================================
# ** Scene_Map
#------------------------------------------------------------------------------
#  This class performs map screen processing.
#==============================================================================

class Scene_Map
  #--------------------------------------------------------------------------
  # * Constant
  #--------------------------------------------------------------------------
  Nothing = Struct.new(:update,:dispose)
  #--------------------------------------------------------------------------
  # * Alias Listing
  #--------------------------------------------------------------------------
  $@ || alias_method(:main_parallel_process_fix, :main)
  #--------------------------------------------------------------------------
  # * Main Processing
  #--------------------------------------------------------------------------
  def main
    init_parallel_process_fix
    main_parallel_process_fix
  end
  #--------------------------------------------------------------------------
  # * init_parallel_process_fix
  #--------------------------------------------------------------------------
  def init_parallel_process_fix
    @spriteset = Nothing.new
    update_systems
    transfer_player                    if $game_temp.player_transferring
    return $scene = Scene_Gameover.new if $game_temp.gameover
    return $scene = Scene_Title.new    if $game_temp.to_title
  end
  #--------------------------------------------------------------------------
  # * update_systems
  #--------------------------------------------------------------------------
  def update_systems
    $game_map.update
    $game_system.map_interpreter.update
    $game_player.update
    $game_system.update
    $game_screen.update
  end
end



[XP] Screen animation to multiple sprites

Description

When a screen animation (position == 3) is shown to different sprites at the same time, it is displayed overlapping itself and it should be displayed just once.

Solution

Edit: New script by LiTTleDRAgo

Put the script above main:

Code: [Select]
#==============================================================================
# ** Sprite_Battler
#------------------------------------------------------------------------------
#  This sprite is used to display the battler.It observes the Game_Character
#  class and automatically changes sprite conditions.
#==============================================================================
class Sprite_Battler
  #--------------------------------------------------------------------------
  # * Alias Listing
  #--------------------------------------------------------------------------
  $@ || alias_method(:update_fix_animation, :update)
  $@ || alias_method(:animation_set_sprites_fix, :animation_set_sprites)
  #--------------------------------------------------------------------------
  # * Frame Update
  #--------------------------------------------------------------------------
  def update(*args)
    if @battler.nil?
      @battler_name = nil
    elsif @battler_visible && @battler.animation_id != 0
      @disable_animation = @battler.instance_variable_get(:@disable_animation)
    end
    update_fix_animation(*args)
  end
  #--------------------------------------------------------------------------
  # * Animation Set Sprites
  #--------------------------------------------------------------------------
  def animation_set_sprites(sp, *args)
    return sp[0..15].each {|s| s && s.visible = false } if @disable_animation
    animation_set_sprites_fix(sp, *args)
  end
end
#==============================================================================
# ** Scene_Battle
#------------------------------------------------------------------------------
#  This class performs battle screen processing.
#==============================================================================
class Scene_Battle
  #--------------------------------------------------------------------------
  # * Alias Listing
  #--------------------------------------------------------------------------
  $@ || alias_method(:update_phase4_step4_fix, :update_phase4_step4)
  #--------------------------------------------------------------------------
  # * Frame Update (main phase step 4 : animation for target)
  #--------------------------------------------------------------------------
  def update_phase4_step4(*args)
    if @animation2_id != 0
      @target_battlers.each_with_index do |s,i|
        s.instance_variable_set(:@disable_animation,false)
        if i > 0 && $data_animations[@animation2_id].position == 3
          s.instance_variable_set(:@disable_animation,true)
        end
      end
    end
    update_phase4_step4_fix(*args)
  end
end



[XP] Disabling skills State bug

Description

There's a type of states restriction which disables the usage of skills to the actor (usually used as the "silence" state). But it doesn't work in the menu because the variable restriction when disabling skills equals 1 and the Skills on menu is disabled when it equals >= 2 by default (so it's so easy, if you change that to >= 1 it will work well). But the problem is the next one: You can go to the Skills scene from an actor who has not the state and with Q / W change to another actor who has the state.

Solution

Put this LiTTleDRAgo's script above main:

Code: [Select]
#==============================================================================
# ** Scene_Menu
#------------------------------------------------------------------------------
#  This class performs menu screen processing.
#==============================================================================
class Scene_Menu
  #--------------------------------------------------------------------------
  # * Alias Listing
  #--------------------------------------------------------------------------
  $@ || alias_method(:update_status_fix, :update_status)
  #--------------------------------------------------------------------------
  # * Frame Update (when status window is active)
  #--------------------------------------------------------------------------
  def update_status(*args)
    if Input.trigger?(Input::C)
      case @command_window.index
      when 1  # skill
        restrict = $game_party.actors[@status_window.index].restriction >= 1
        return $game_system.se_play($data_system.buzzer_se) if restrict
        $game_system.se_play($data_system.decision_se)
        return $scene = Scene_Skill.new(@status_window.index)
      end
    end
    update_status_fix(*args)
  end
end

#==============================================================================
# ** Scene_Skill
#------------------------------------------------------------------------------
#  This class performs skill screen processing.
#==============================================================================
class Scene_Skill
  #--------------------------------------------------------------------------
  # * Alias Listing
  #--------------------------------------------------------------------------
  $@ || alias_method(:update_skill_fix, :update_skill)
  #--------------------------------------------------------------------------
  # * Frame Update (if skill window is active)
  #--------------------------------------------------------------------------
  def update_skill(*args)
    return update_skill_lr(1)  if Input.trigger?(Input::R)
    return update_skill_lr(-1) if Input.trigger?(Input::L)
    update_skill_fix(*args)
  end
  #--------------------------------------------------------------------------
  # * update_skill_lr
  #--------------------------------------------------------------------------
  def update_skill_lr(type = 1)
    return if $game_party.actors.size == 1
    actor = @actor_index
    loop do
      @actor_index = (@actor_index + type) % $game_party.actors.size
      break unless $game_party.actors[@actor_index].restriction >= 1
      break if @actor_index == actor
    end
    return $game_system.se_play($data_system.buzzer_se) if @actor_index == actor
    $game_system.se_play($data_system.cursor_se)
    $scene = Scene_Skill.new(@actor_index)
  end
end
« Last Edit: August 17, 2014, 06:03:44 PM by Wecoc »

Offline winkio

  • Epiq
  • Administrator
  • Guardian of Chaos
  • *****
  • Posts: 4505
  • LV: 199
  • Gender: Male
  • I am lying.
    • View Profile
Re: About RPG maker's internal bugs
« Reply #1 on: August 16, 2014, 09:07:17 AM »
Good topic I'm going to stick it.

Offline Zexion

  • Addicted to LoL
  • Chaos User
  • ******
  • Posts: 1500
  • LV: 69
  • Gender: Male
  • My anaconda don't...jk it does
    • View Profile
Re: About RPG maker's internal bugs
« Reply #2 on: August 16, 2014, 07:17:35 PM »
I didn't know about the float thing, I think it can apply to a script I made where the animations seem to be off center when scrolling. Thanks for this, though I'm not sure I understand the collision one.

Is it something like teleporting from the edge of a mapA to the edge of another mapB, and activating the teleport on the other mapB causing an annoying loop of teleports?
If so, then thanks again because I had no idea that was a bug o.o

Offline Wecoc

  • Transcended Spirit
  • ***
  • Posts: 108
  • LV: 44
  • Gender: Male
    • View Profile
    • Mundo Maker
Re: About RPG maker's internal bugs
« Reply #3 on: August 16, 2014, 11:35:33 PM »
You are in coordinates [7, 6] and start a teleportation to another map, on new coordinates [3, 3].

There's a collision event on the second map, on coordinates [7, 6]. That event technically was not touched because your coordinates in the second map were always [3, 3], but the event is activated. That's the bug.

With the script, while the player is teleporting collision events can't be activated.

Offline LiTTleDRAgo

  • Astral Trancist
  • *****
  • Posts: 811
  • LV: 510
  • Gender: Male
    • View Profile
    • ~
Re: About RPG maker's internal bugs
« Reply #4 on: August 17, 2014, 09:31:04 AM »
(click to show/hide)

これならどうだ?

(click to show/hide)

(click to show/hide)

(click to show/hide)
« Last Edit: March 18, 2017, 10:36:48 AM by LiTTleDRAgo »

Offline Wecoc

  • Transcended Spirit
  • ***
  • Posts: 108
  • LV: 44
  • Gender: Male
    • View Profile
    • Mundo Maker
Re: About RPG maker's internal bugs
« Reply #5 on: August 17, 2014, 03:35:10 PM »
Wow, your fixes are waaay better, I will change my post.

First I thought it would be possible to apply the effect only on the first sprite but it was not, because the flash effects... so I changed all the animation methods to work only with the first sprite (only in that case) but without losing those effects.
I didn't thought about your mecanism. And I see you fixed the @battler_name = nil bug on the same script!

Well, thank you.

------

C'mon, I'm sure there are thousands of bugs and we have eight on the list!

Offline G_G

  • Green Gmod Game_Guy AKA G4 AKA hyper-G AKA G-force
  • Global Moderator
  • Chaos Ultimate
  • ****
  • Posts: 6585
  • LV: 407
  • Gender: Male
    • View Profile
Re: About RPG maker's internal bugs
« Reply #6 on: August 17, 2014, 04:42:54 PM »
I've fixed the bug before, but I don't have the script anymore. How about this one?

Create a troop. Put three enemies in there, make one Hidden. When you kill the other two, the battle is considered over even though the hidden is still there and fully alive. Even with a battle events, you can't make him re-appear unless enemies still exist. Example: You have a giant slime. Kill him, and two smaller slimes appear. logically, you'd just put a giant slime and two small slimes in a troop and make the small ones hidden.
« Last Edit: August 17, 2014, 04:44:56 PM by gameus »

Offline LiTTleDRAgo

  • Astral Trancist
  • *****
  • Posts: 811
  • LV: 510
  • Gender: Male
    • View Profile
    • ~
Re: About RPG maker's internal bugs
« Reply #7 on: August 17, 2014, 05:49:33 PM »
(click to show/hide)

(click to show/hide)
« Last Edit: August 18, 2014, 08:24:18 AM by LiTTleDRAgo »

Offline Wecoc

  • Transcended Spirit
  • ***
  • Posts: 108
  • LV: 44
  • Gender: Male
    • View Profile
    • Mundo Maker
Re: About RPG maker's internal bugs
« Reply #8 on: August 17, 2014, 06:01:08 PM »
game_guy: I wonder if it was really a bug, but this solves the problem:

Code: [Select]
class Scene_Battle
  alias hidden_fix_phase4_step1 update_phase4_step1 unless $@
  def update_phase4_step1
    troop = $game_troop.enemies
    if troop.all? {|enemy| (enemy.hidden == true or enemy.hp0?)}
      troop.collect {|enemy| enemy.hidden = false}
    end
    hidden_fix_phase4_step1
  end
end

LiTTleDRAgo: Thank you again, you are contributing a lot.
« Last Edit: August 17, 2014, 06:06:23 PM by Wecoc »

Offline ForeverZer0

  • CP's Pedophile
  • Global Moderator
  • Guardian of Chaos
  • ****
  • Posts: 3248
  • LV: 294
  • Gender: Male
  • Remember you are unique, just like everyone else.
    • View Profile
Re: About RPG maker's internal bugs
« Reply #9 on: August 17, 2014, 06:31:23 PM »
I don't think it really is a bug, but it does make it more difficult to do as GG described.
As it currently is, it can act as a mechanism for enemies who "escape", therefore allowing the battle to end, but not rewarding experience, etc. It would be more intuitive to have a @hidden flag, and a separate @escaped flag.
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

Offline G_G

  • Green Gmod Game_Guy AKA G4 AKA hyper-G AKA G-force
  • Global Moderator
  • Chaos Ultimate
  • ****
  • Posts: 6585
  • LV: 407
  • Gender: Male
    • View Profile
Re: About RPG maker's internal bugs
« Reply #10 on: August 17, 2014, 06:52:27 PM »
It's not a bug I guess, but more of a design flaw.

Offline LiTTleDRAgo

  • Astral Trancist
  • *****
  • Posts: 811
  • LV: 510
  • Gender: Male
    • View Profile
    • ~
Re: About RPG maker's internal bugs
« Reply #11 on: August 17, 2014, 07:24:09 PM »
I don't think it really is a bug, but it does make it more difficult to do as GG described.
As it currently is, it can act as a mechanism for enemies who "escape", therefore allowing the battle to end, but not rewarding experience, etc. It would be more intuitive to have a @hidden flag, and a separate @escaped flag.

something like this?

(click to show/hide)

it will automatically unhide all unescaped enemies when all visible enemies is defeated

NB : Not properly tested

Offline Wecoc

  • Transcended Spirit
  • ***
  • Posts: 108
  • LV: 44
  • Gender: Male
    • View Profile
    • Mundo Maker
Re: About RPG maker's internal bugs
« Reply #12 on: August 17, 2014, 09:04:43 PM »
LiTTleDRAgo: Like a boss! I tested that for you, it works great.

I did the VX Version:

Code: [Select]
#==============================================================================
# ** Game_Enemy
#------------------------------------------------------------------------------
#  This class handles enemies. It's used within the Game_Troop class
#  ($game_troop).
#==============================================================================
class Game_Enemy
  #--------------------------------------------------------------------------
  # * Public Instance Variables
  #--------------------------------------------------------------------------
  attr_accessor :escaped                   # escaped flag
  #--------------------------------------------------------------------------
  # * Alias Listing
  #--------------------------------------------------------------------------
  $@ || alias_method(:escaped_flag_addition, :escape)
  #--------------------------------------------------------------------------
  # * Escape
  #--------------------------------------------------------------------------
  def escape(*args)
    @escaped = true
    escaped_flag_addition(*args)
  end
end

#==============================================================================
# ** Scene_Battle
#------------------------------------------------------------------------------
#  This class performs battle screen processing.
#==============================================================================
class Scene_Battle
  #--------------------------------------------------------------------------
  # * Alias Listing
  #--------------------------------------------------------------------------
  $@ || alias_method(:escaped_battle_event, :process_battle_event)
 
  def process_battle_event(*args)
    if (troop = $game_troop.members).all? {|e| (e.hidden or e.dead?)}
      troop.each {|enemy| enemy.escaped || enemy.hidden = false }
    end
    escaped_battle_event(*args)
  end
end

#==============================================================================
# ** Interpreter
#------------------------------------------------------------------------------
#  This interpreter runs event commands. This class is used within the
#  Game_System class and the Game_Event class.
#==============================================================================
class Game_Interpreter
  #--------------------------------------------------------------------------
  # * Alias Listing
  #--------------------------------------------------------------------------
  $@ || alias_method(:escaped_command_335, :command_335)
  #--------------------------------------------------------------------------
  # * Enemy Appearance
  #--------------------------------------------------------------------------
  def command_335(*args)
    enemy = $game_troop.members[@params[0]]
    enemy && enemy.escaped = false
    escaped_command_335(*args)
  end
end

(I don't know if Ace needs that fix, too)

Offline G_G

  • Green Gmod Game_Guy AKA G4 AKA hyper-G AKA G-force
  • Global Moderator
  • Chaos Ultimate
  • ****
  • Posts: 6585
  • LV: 407
  • Gender: Male
    • View Profile
Re: About RPG maker's internal bugs
« Reply #13 on: August 18, 2014, 04:45:17 AM »
I don't think it really is a bug, but it does make it more difficult to do as GG described.
As it currently is, it can act as a mechanism for enemies who "escape", therefore allowing the battle to end, but not rewarding experience, etc. It would be more intuitive to have a @hidden flag, and a separate @escaped flag.

something like this?

(click to show/hide)

it will automatically unhide all unescaped enemies when all visible enemies is defeated

NB : Not properly tested

Yes, that's actually quite perfect. Still would have been nice to been able to do a "When all enemies died" page condition inside the editor, though I suppose no one really thought of that over at Enterbrain.

Offline LiTTleDRAgo

  • Astral Trancist
  • *****
  • Posts: 811
  • LV: 510
  • Gender: Male
    • View Profile
    • ~
Re: About RPG maker's internal bugs
« Reply #14 on: August 18, 2014, 07:32:01 AM »
Yes, that's actually quite perfect. Still would have been nice to been able to do a "When all enemies died" page condition inside the editor, though I suppose no one really thought of that over at Enterbrain.

http://pastebin.com/1WP0KMRM (edited from here)

How to Use


Offline G_G

  • Green Gmod Game_Guy AKA G4 AKA hyper-G AKA G-force
  • Global Moderator
  • Chaos Ultimate
  • ****
  • Posts: 6585
  • LV: 407
  • Gender: Male
    • View Profile
Re: About RPG maker's internal bugs
« Reply #15 on: August 18, 2014, 07:58:14 AM »
xD Thanks Drago! I wasn't actually expecting you to do it. ;p

Offline LiTTleDRAgo

  • Astral Trancist
  • *****
  • Posts: 811
  • LV: 510
  • Gender: Male
    • View Profile
    • ~
Re: About RPG maker's internal bugs
« Reply #16 on: August 18, 2014, 08:19:46 AM »
I'm not sure if it's a bug or not

when player is unarmed (barefisted), atk will became 0 regardless the enemy and player level

Offline Wecoc

  • Transcended Spirit
  • ***
  • Posts: 108
  • LV: 44
  • Gender: Male
    • View Profile
    • Mundo Maker
Re: About RPG maker's internal bugs
« Reply #17 on: August 19, 2014, 12:11:26 AM »
I'm not sure if it's a bug or not

when player is unarmed (barefisted), atk will became 0 regardless the enemy and player level

This should work, it's probably the easiest way.

Code: [Select]
class Game_Actor < Game_Battler
 
  attr_accessor :basic_atk
  attr_accessor :basic_animation_id
 
  alias no_weapon_fix_ini initialize unless $@
  def initialize(*args)
    no_weapon_fix_ini(*args)
    @basic_atk = 100
    @basic_animation_id = 4
  end

  def base_atk
    weapon = $data_weapons[@weapon_id]
    return weapon != nil ? weapon.atk : @basic_atk
  end
 
  def animation2_id
    weapon = $data_weapons[@weapon_id]
    return weapon != nil ? weapon.animation2_id : @basic_animation_id
  end
end

Another option I use in my game is not allowing actors to have no weapon.

(click to show/hide)

Offline Heretic86

  • Astral Trancist
  • *****
  • Posts: 724
  • LV: 29
    • View Profile
Re: About RPG maker's internal bugs
« Reply #18 on: October 27, 2014, 11:57:28 PM »
XP's Float Bug does have a solution.

It is based on the @real_x and @real_y using whole numbers, not @move_speed.  The trouble comes from @move_speed being used to calculate @real_x and @real_y exponentially.  2 ** X in Ruby means "to the power of", or an Exponent.  It comes from this line of code in def update_move.

Code: [Select]
   # Convert map coordinates from map move speed into move distance
    distance = 2 ** @move_speed

Move Speed 1: 2 ** 1 = 1
Move Speed 2: 2 ** 2 = 4
Move Speed 3: 2 ** 2 = 9
Move Speed 4: 2 ** 2 = 16
Move Speed 5: 2 ** 2 = 25
Move Speed 6: 2 ** 2 = 36

When the resulting value in the right column in the above example is not a whole number, it is still used to adjust @real_x and @real_y values as floats instead of whole numbers.  Lets say we wanted a Move Speed of 3.5.  It seems to be half way between 3 and 4.  But 2 ** 3.5 = 12.25, which is not a whole number.  Instead, pick a real value (x or y * 128) between 9 and 16 and get its square root, due to the exponent.  Lets say 12.  The square root of 12 is 3.46410161513775457705489268 and change.  But that is WAY too much for an average person to put in for @move_speed = 3.5.  Same problem occurs with a Move Speed of 4.5.  The square root of 4.5 would be 2.12132034 and change.  Again, too much for Joe Average, and the math has to be 100 accurate.

The code solution for this would be to just round the value to the next whole number.

Change
Code: [Select]
distance = 2 ** @move_speed to
Code: [Select]
distance = (2 ** @move_speed).round
There is only 2 places where this code is used.  Game_Map and Game_Character.  Just CTRL+SHIFT+F for 2 **.

I discovered this while updating my Downhill Ice Deluxe [XP] script (not released at time of this post).
Current Scripts:
Heretic's Moving Platforms

Current Demos:
Collection of Art and 100% Compatible Scripts

(Script Demos are all still available in the Collection link above.  I lost some individual demos due to a server crash.)

Offline Wecoc

  • Transcended Spirit
  • ***
  • Posts: 108
  • LV: 44
  • Gender: Male
    • View Profile
    • Mundo Maker
Re: About RPG maker's internal bugs
« Reply #19 on: October 28, 2014, 01:53:57 AM »
This was basically my try on this, but rounding the value has an obvious collateral problem; you lose "movement resolution"; 3.1 = 3.2, 3.4 = 3.5 ...

Here an example; these charas are walking (Move up) in frequence 6, and their speed is 3.0, 3.2, 3.4, 3.5, 3.6, 3.8 and 4.0
You can see the difference between rounding the value or not.

(click to show/hide)

One possible fix for that would be to round only the player's distance, but the player would still have that lack of "movement resolution".

Someone said me rounding the distance also has some problems on camera if you are using a "smooth-movement" script, but sincerely I didn't check that.

The other possible way to fix this would be to work always with distances directly controlling it's integer instead of the speed as a float. Anyway, I don't like so much this idea...

The character I used on the first image: http://s9.postimg.org/7i2mp9hzv/character.png

==============================

Anyway, I think I already fixed this on my game some months ago, I didn't post it here because I'm not 100% sure but I'll tell what I found ;D
All this fixes try to fit the charas movement with the current screen movement, but the one which is delayed is the screen.

Once, on my game, I tried to display a bitmap layer or a picture over the map and scroll it via script call on parallel process to fit with the map (changing display_x and display_y). The result was laggy, and because of the 3.6 speed of the player, I had the same problem. It had nothing to do with character speed, so I decided to modificate the Game_Map converting to some sort of a smooth-movement script, but "not so smooth". The result is a map scroll practically identical as the default but the picture is displayed well and lag decreases. The annoying bug also disappears. The only problem is the new script is not perfect. For example, on diagonal movement the map is too slow now...

This is the script. I'm pretty sure correcting its bugs, we would fix the problem definitelly:

Code: [Select]
#==============================================================================
# ** Game_Map
#------------------------------------------------------------------------------
#  This class handles the map. It includes scrolling and passable determining
#  functions. Refer to "$game_map" for the instance of this class.
#==============================================================================

class Game_Map
  #--------------------------------------------------------------------------
  # * Public Instance Variables
  #--------------------------------------------------------------------------
  attr_accessor :tileset_name             # tileset file name
  attr_accessor :autotile_names           # autotile file name
  attr_accessor :panorama_name            # panorama file name
  attr_accessor :panorama_hue             # panorama hue
  attr_accessor :fog_name                 # fog file name
  attr_accessor :fog_hue                  # fog hue
  attr_accessor :fog_opacity              # fog opacity level
  attr_accessor :fog_blend_type           # fog blending method
  attr_accessor :fog_zoom                 # fog zoom rate
  attr_accessor :fog_sx                   # fog sx
  attr_accessor :fog_sy                   # fog sy
  attr_accessor :battleback_name          # battleback file name
  attr_accessor :display_x                # display x-coordinate * 128
  attr_accessor :display_y                # display y-coordinate * 128
  attr_accessor :need_refresh             # refresh request flag
  attr_reader   :passages                 # passage table
  attr_reader   :priorities               # prioroty table
  attr_reader   :terrain_tags             # terrain tag table
  attr_reader   :events                   # events
  attr_reader   :fog_ox                   # fog x-coordinate starting point
  attr_reader   :fog_oy                   # fog y-coordinate starting point
  attr_reader   :fog_tone                 # fog color tone
  #--------------------------------------------------------------------------
  # * Object Initialization
  #--------------------------------------------------------------------------
  def initialize
    @map_id = 0
    @display_x = 0
    @display_y = 0
  end
  #--------------------------------------------------------------------------
  # * Setup
  #     map_id : map ID
  #--------------------------------------------------------------------------
  def setup(map_id)
    # Put map ID in @map_id memory
    @map_id = map_id
    # Load map from file and set @map
    @map = load_data(sprintf("Data/Map%03d.rxdata", @map_id))
    # set tile set information in opening instance variables
    tileset = $data_tilesets[@map.tileset_id]
    @tileset_name = tileset.tileset_name
    @autotile_names = tileset.autotile_names
    @panorama_name = tileset.panorama_name
    @panorama_hue = tileset.panorama_hue
    @fog_name = tileset.fog_name
    @fog_hue = tileset.fog_hue
    @fog_opacity = tileset.fog_opacity
    @fog_blend_type = tileset.fog_blend_type
    @fog_zoom = tileset.fog_zoom
    @fog_sx = tileset.fog_sx
    @fog_sy = tileset.fog_sy
    @battleback_name = tileset.battleback_name
    @passages = tileset.passages
    @priorities = tileset.priorities
    @terrain_tags = tileset.terrain_tags
    # Initialize displayed coordinates
    @display_x = 0
    @display_y = 0
    @scroll_remain_x = 0
    @scroll_remain_y = 0
    @scroll_take_x = 0
    @scroll_take_y = 0
    # Clear refresh request flag
    @need_refresh = false
    # Set map event data
    @events = {}
    for i in @map.events.keys
      @events[i] = Game_Event.new(@map_id, @map.events[i])
    end
    # Set common event data
    @common_events = {}
    for i in 1...$data_common_events.size
      @common_events[i] = Game_CommonEvent.new(i)
    end
    # Initialize all fog information
    @fog_ox = 0
    @fog_oy = 0
    @fog_tone = Tone.new(0, 0, 0, 0)
    @fog_tone_target = Tone.new(0, 0, 0, 0)
    @fog_tone_duration = 0
    @fog_opacity_duration = 0
    @fog_opacity_target = 0
    # Initialize scroll information
    @scroll_direction = 2
    @scroll_rest = 0
    @scroll_speed = 4
  end
  #--------------------------------------------------------------------------
  # * Get Map ID
  #--------------------------------------------------------------------------
  def map_id
    return @map_id
  end
  #--------------------------------------------------------------------------
  # * Get Width
  #--------------------------------------------------------------------------
  def width
    return @map.width
  end
  #--------------------------------------------------------------------------
  # * Get Height
  #--------------------------------------------------------------------------
  def height
    return @map.height
  end
  #--------------------------------------------------------------------------
  # * Get Encounter List
  #--------------------------------------------------------------------------
  def encounter_list
    return @map.encounter_list
  end
  #--------------------------------------------------------------------------
  # * Get Encounter Steps
  #--------------------------------------------------------------------------
  def encounter_step
    return @map.encounter_step
  end
  #--------------------------------------------------------------------------
  # * Get Map Data
  #--------------------------------------------------------------------------
  def data
    return @map.data
  end
  #--------------------------------------------------------------------------
  # * Automatically Change Background Music and Backround Sound
  #--------------------------------------------------------------------------
  def autoplay
    if @map.autoplay_bgm
      $game_system.bgm_play(@map.bgm)
    end
    if @map.autoplay_bgs
      $game_system.bgs_play(@map.bgs)
    end
  end
  #--------------------------------------------------------------------------
  # * Refresh
  #--------------------------------------------------------------------------
  def refresh
    # If map ID is effective
    if @map_id > 0
      # Refresh all map events
      for event in @events.values
        event.refresh
      end
      # Refresh all common events
      for common_event in @common_events.values
        common_event.refresh
      end
    end
    # Clear refresh request flag
    @need_refresh = false
  end
  #--------------------------------------------------------------------------
  # * Scroll Down
  #     distance : scroll distance
  #--------------------------------------------------------------------------
  def scroll_down(distance)
    if distance > (self.height - 15) * 128 - @display_y - @scroll_remain_y
      distance = (self.height - 15) * 128 - @display_y - @scroll_remain_y
    end
    if scrolling?
      @scroll_take_y = 2 ** @scroll_speed
    else
      if distance.ceil % 4 == 0
        @scroll_take_y = distance.ceil
      elsif distance.ceil % 4 <= 2
        @scroll_take_y = distance.ceil - distance.ceil % 4
      else
        @scroll_take_y = distance.ceil + (4 - (distance.ceil % 4))
      end
    end
    @scroll_remain_y += distance
  end
  #--------------------------------------------------------------------------
  # * Scroll Left
  #     distance : scroll distance
  #--------------------------------------------------------------------------
  def scroll_left(distance)
    if distance > @display_x - @scroll_remain_x
      distance = @display_x - @scroll_remain_x
    end
    if scrolling?
      @scroll_take_x = 2 ** @scroll_speed
    else
      if distance.ceil % 4 == 0
        @scroll_take_x = distance.ceil
      elsif distance.ceil % 4 <= 2
        @scroll_take_x = distance.ceil - distance.ceil % 4
      else
        @scroll_take_x = distance.ceil + (4 - (distance.ceil % 4))
      end
    end
    @scroll_remain_x -= distance
  end
  #--------------------------------------------------------------------------
  # * Scroll Right
  #     distance : scroll distance
  #--------------------------------------------------------------------------
  def scroll_right(distance)
    if distance > (self.width - 15) * 128 - @display_x - @scroll_remain_x
      distance = (self.width - 15) * 128 - @display_x - @scroll_remain_x
    end
    if scrolling?
      @scroll_take_x = 2 ** @scroll_speed
    else
      if distance.ceil % 4 == 0
        @scroll_take_x = distance.ceil
      elsif distance.ceil % 4 <= 2
        @scroll_take_x = distance.ceil - distance.ceil % 4
      else
        @scroll_take_x = distance.ceil + (4 - (distance.ceil % 4))
      end
    end
    @scroll_remain_x += distance
  end
  #--------------------------------------------------------------------------
  # * Scroll Up
  #     distance : scroll distance
  #--------------------------------------------------------------------------
  def scroll_up(distance)
    if distance > @display_y - @scroll_remain_y
      distance = @display_y - @scroll_remain_y
    end
    if scrolling?
      @scroll_take_y = 2 ** @scroll_speed
    else
      if distance.ceil % 4 == 0
        @scroll_take_y = distance.ceil
      elsif distance.ceil % 4 <= 2
        @scroll_take_y = distance.ceil - distance.ceil % 4
      else
        @scroll_take_y = distance.ceil + (4 - (distance.ceil % 4))
      end
    end
    @scroll_remain_y -= distance
  end
  #--------------------------------------------------------------------------
  # * Determine Valid Coordinates
  #     x          : x-coordinate
  #     y          : y-coordinate
  #--------------------------------------------------------------------------
  def valid?(x, y)
    return (x >= 0 and x < width and y >= 0 and y < height)
  end
  #--------------------------------------------------------------------------
  # * Determine if Passable
  #     x          : x-coordinate
  #     y          : y-coordinate
  #     d          : direction (0,2,4,6,8,10)
  #                  *  0,10 = determine if all directions are impassable
  #     self_event : Self (If event is determined passable)
  #--------------------------------------------------------------------------
  def passable?(x, y, d, self_event = nil)
    # If coordinates given are outside of the map
    unless valid?(x, y)
      # impassable
      return false
    end
    # Change direction (0,2,4,6,8,10) to obstacle bit (0,1,2,4,8,0)
    bit = (1 << (d / 2 - 1)) & 0x0f
    # Loop in all events
    for event in events.values
      # If tiles other than self are consistent with coordinates
      if event.tile_id >= 0 and event != self_event and
         event.x == x and event.y == y and not event.through
        # If obstacle bit is set
        if @passages[event.tile_id] & bit != 0
          # impassable
          return false
        # If obstacle bit is set in all directions
        elsif @passages[event.tile_id] & 0x0f == 0x0f
          # impassable
          return false
        # If priorities other than that are 0
        elsif @priorities[event.tile_id] == 0
          # passable
          return true
        end
      end
    end
    # Loop searches in order from top of layer
    for i in [2, 1, 0]
      # Get tile ID
      tile_id = data[x, y, i]
      # Tile ID acquistion failure
      if tile_id == nil
        # impassable
        return false
      # If obstacle bit is set
      elsif @passages[tile_id] & bit != 0
        # impassable
        return false
      # If obstacle bit is set in all directions
      elsif @passages[tile_id] & 0x0f == 0x0f
        # impassable
        return false
      # If priorities other than that are 0
      elsif @priorities[tile_id] == 0
        # passable
        return true
      end
    end
    # passable
    return true
  end
  #--------------------------------------------------------------------------
  # * Determine Thicket
  #     x          : x-coordinate
  #     y          : y-coordinate
  #--------------------------------------------------------------------------
  def bush?(x, y)
    if @map_id != 0
      for i in [2, 1, 0]
        tile_id = data[x, y, i]
        if tile_id == nil
          return false
        elsif @passages[tile_id] & 0x40 == 0x40
          return true
        end
      end
    end
    return false
  end
  #--------------------------------------------------------------------------
  # * Determine Counter
  #     x          : x-coordinate
  #     y          : y-coordinate
  #--------------------------------------------------------------------------
  def counter?(x, y)
    if @map_id != 0
      for i in [2, 1, 0]
        tile_id = data[x, y, i]
        if tile_id == nil
          return false
        elsif @passages[tile_id] & 0x80 == 0x80
          return true
        end
      end
    end
    return false
  end
  #--------------------------------------------------------------------------
  # * Get Terrain Tag
  #     x          : x-coordinate
  #     y          : y-coordinate
  #--------------------------------------------------------------------------
  def terrain_tag(x, y)
    if @map_id != 0
      for i in [2, 1, 0]
        tile_id = data[x, y, i]
        if tile_id == nil
          return 0
        elsif @terrain_tags[tile_id] > 0
          return @terrain_tags[tile_id]
        end
      end
    end
    return 0
  end
  #--------------------------------------------------------------------------
  # * Get Designated Position Event ID
  #     x          : x-coordinate
  #     y          : y-coordinate
  #--------------------------------------------------------------------------
  def check_event(x, y)
    for event in $game_map.events.values
      if event.x == x and event.y == y
        return event.id
      end
    end
  end
  #--------------------------------------------------------------------------
  # * Start Scroll
  #     direction : scroll direction
  #     distance  : scroll distance
  #     speed     : scroll speed
  #--------------------------------------------------------------------------
  def start_scroll(direction, distance, speed)
    @scroll_direction = direction
    @scroll_speed     = speed
    @scroll_rest      = distance.ceil * 128
    case @scroll_direction
    when 2  # Down
      scroll_down(@scroll_rest)
    when 4  # Left
      scroll_left(@scroll_rest)
    when 6  # Right
      scroll_right(@scroll_rest)
    when 8  # Up
      scroll_up(@scroll_rest)
    end
  end
  #--------------------------------------------------------------------------
  # * Determine if Scrolling
  #--------------------------------------------------------------------------
  def scrolling?
    return @scroll_rest > 0
  end
  #--------------------------------------------------------------------------
  # * Start Changing Fog Color Tone
  #     tone     : color tone
  #     duration : time
  #--------------------------------------------------------------------------
  def start_fog_tone_change(tone, duration)
    @fog_tone_target = tone.clone
    @fog_tone_duration = duration
    if @fog_tone_duration == 0
      @fog_tone = @fog_tone_target.clone
    end
  end
  #--------------------------------------------------------------------------
  # * Start Changing Fog Opacity Level
  #     opacity  : opacity level
  #     duration : time
  #--------------------------------------------------------------------------
  def start_fog_opacity_change(opacity, duration)
    @fog_opacity_target = opacity * 1.0
    @fog_opacity_duration = duration
    if @fog_opacity_duration == 0
      @fog_opacity = @fog_opacity_target
    end
  end
  #--------------------------------------------------------------------------
  # * Frame Update
  #--------------------------------------------------------------------------
  def update
    # Refresh map if necessary
    if $game_map.need_refresh
      refresh
    end
    # If scrolling
    if @scroll_rest > 0
      @scroll_rest -= 2 ** @scroll_speed
    end
    if @scroll_remain_x > 0
      old_display_x = @display_x
      distance = [@scroll_take_x, 4].max
      unless @display_x + distance > (self.width - 15) * 128
        @display_x += distance
      end
      @scroll_remain_x += old_display_x - @display_x
      if @scroll_remain_x < 0
        @scroll_remain_x = 0
      end
    elsif @scroll_remain_x < 0
      old_display_x = @display_x
      distance = [@scroll_take_x, 4].max
      unless @display_x - distance < 0
        @display_x -= distance
      end
      @scroll_remain_x += old_display_x - @display_x
      if @scroll_remain_x > 0
        @scroll_remain_x = 0
      end
    end
    if @scroll_remain_y > 0
      old_display_y = @display_y
      distance = [@scroll_take_y, 4].max
      unless @display_y + distance > (self.height - 15) * 128
        @display_y += distance
      end
      @scroll_remain_y += old_display_y - @display_y
      if @scroll_remain_y < 0
        @scroll_remain_y = 0
      end
    elsif @scroll_remain_y < 0
      old_display_y = @display_y
      distance = [@scroll_take_y, 4].max
      unless @display_y - distance < 0
        @display_y -= distance
      end
      @scroll_remain_y += old_display_y - @display_y
      if @scroll_remain_y > 0
        @scroll_remain_y = 0
      end
    end
    # Update map event
    for event in @events.values
      event.update
    end
    # Update common event
    for common_event in @common_events.values
      common_event.update
    end
    # Manage fog scrolling
    @fog_ox -= @fog_sx / 8.0
    @fog_oy -= @fog_sy / 8.0
    # Manage change in fog color tone
    if @fog_tone_duration >= 1
      d = @fog_tone_duration
      target = @fog_tone_target
      @fog_tone.red = (@fog_tone.red * (d - 1) + target.red) / d
      @fog_tone.green = (@fog_tone.green * (d - 1) + target.green) / d
      @fog_tone.blue = (@fog_tone.blue * (d - 1) + target.blue) / d
      @fog_tone.gray = (@fog_tone.gray * (d - 1) + target.gray) / d
      @fog_tone_duration -= 1
    end
    # Manage change in fog opacity level
    if @fog_opacity_duration >= 1
      d = @fog_opacity_duration
      @fog_opacity = (@fog_opacity * (d - 1) + @fog_opacity_target) / d
      @fog_opacity_duration -= 1
    end
  end
end
« Last Edit: October 28, 2014, 02:24:26 AM by Wecoc »