Taking more damage than I program?

Discussion in 'RPG Maker VX Ace' started by QueenTeaYT, Dec 5, 2019.

  1. QueenTeaYT

    QueenTeaYT Veteran Veteran

    Messages:
    45
    Likes Received:
    11
    First Language:
    English
    Primarily Uses:
    RMVXA
    I made an enemy sprite with these contents:

    The player has 10 HP and the other party member has 10 HP as well.

    However, when I play in-game, the enemy sprite will touch the player and they will die in less than 10 hits! Sometimes it takes 2 hits, other times it's 4 or something. I allowed knockout, so is this the issue? If so, how can I go around that and make it wait until the player has 1 HP before causing knockout?

    Please help!!
     
    #1
  2. gstv87

    gstv87 Veteran Veteran

    Messages:
    1,823
    Likes Received:
    857
    First Language:
    Spanish
    Primarily Uses:
    RMVXA
    I can tell you just by looking at it, you're mixing terms that are used separately.
    but I'll try and eyeball it from what you explain, and submit you're probably running that -1 in parallel, and parallel processes happen WAY faster than you think.
    you see one hit, but the game would run at least at 60FPS, so 60 actual -1's are happening at the same time.

    just for the record tho: you're mixing terms.... Sprites (code objects) are one thing, *sprites* (generic graphical icons) are another, and "sprites" (mythic ghosts) are another.

    I think I know what you're going for, and that's not handled like that (or, *is*, depending on your battle system)
    are you using an action battle system like Zelda or similar?
     
    Last edited: Dec 5, 2019
    #2
    QueenTeaYT likes this.
  3. QueenTeaYT

    QueenTeaYT Veteran Veteran

    Messages:
    45
    Likes Received:
    11
    First Language:
    English
    Primarily Uses:
    RMVXA
    Yikes, so the parallel process was the issue... thanks for explaining why, too!

    Aaah so I should be saying Sprites? The enemy is in fact a "sprite," and I mean more than just the *sprite.* Either way, thanks for the help. :)
     
    #3
  4. QueenTeaYT

    QueenTeaYT Veteran Veteran

    Messages:
    45
    Likes Received:
    11
    First Language:
    English
    Primarily Uses:
    RMVXA
    Also, I'm not using any scripts changing the battle system, I just want to avoid going into a default battle and want an enemy that can move on the map itself.
     
    #4
  5. gstv87

    gstv87 Veteran Veteran

    Messages:
    1,823
    Likes Received:
    857
    First Language:
    Spanish
    Primarily Uses:
    RMVXA
    those are events, not sprites.
    they were called sprites generically in the days of the Commodore 64 :D
    that's where the term "sprite" (the code object) comes from: the image that represents the object.... but these are *event* objects, with the sprite on top, which is a *character* (*itself* a sprite), and the set of instructions within, which is an *interpreter* object.
     
    #5
    QueenTeaYT likes this.
  6. QueenTeaYT

    QueenTeaYT Veteran Veteran

    Messages:
    45
    Likes Received:
    11
    First Language:
    English
    Primarily Uses:
    RMVXA
    Ooh I understand now! Thanks for explaining again! c:
     
    #6
  7. Shaz

    Shaz Veteran Veteran

    Messages:
    37,970
    Likes Received:
    11,631
    Location:
    Australia
    First Language:
    English
    Primarily Uses:
    RMMV
    Did you get it working? If not, you could put a Wait in there at the end, so the event pauses after each hit.

    I don't see any parallel process, unless that's how you had it originally and you changed it in your first post.
     
    #7
    Heirukichi and QueenTeaYT like this.
  8. QueenTeaYT

    QueenTeaYT Veteran Veteran

    Messages:
    45
    Likes Received:
    11
    First Language:
    English
    Primarily Uses:
    RMVXA
    I'll try the wait idea, since there wasn't a parallel process in the damage intake like I thought there was. I'll let you know!
     
    #8
  9. gstv87

    gstv87 Veteran Veteran

    Messages:
    1,823
    Likes Received:
    857
    First Language:
    Spanish
    Primarily Uses:
    RMVXA
    not a wait, but maybe an exit event, or a self switch.
    the thing is, it's running too fast, at the moment of contact with the player.

    I don't remember if exiting the process would cause the event to reset it's touch validation, but the problem can be fixed or at least adjusted..... there are ways around it.
     
    #9
    QueenTeaYT likes this.
  10. QueenTeaYT

    QueenTeaYT Veteran Veteran

    Messages:
    45
    Likes Received:
    11
    First Language:
    English
    Primarily Uses:
    RMVXA
    Using "wait" before giving damage works! :D Now the player only takes 1 damage at a time. Thank you so much!
     
    #10
  11. Heirukichi

    Heirukichi Veteran Veteran

    Messages:
    1,303
    Likes Received:
    549
    Location:
    Italy
    First Language:
    Italian
    Primarily Uses:
    RMVXA
    @QueenTeaYT That's more or less the way to go. In case you are wondering why that happens: both player touch and event touch trigger whenever an action that would make the player and the event have the same coordinates is queued (respectively a player action or an event action), even if it cannot be executed because they collide. In this case, while the event chases the player, if the player stands on a tile and the event tries to step on the same tile, the event is triggered.

    Executing the event commands, however, only takes a single frame, but in the next frame (it does not actually happen each frame, but it is still very fast), when the event tries to chase the player once again, the same thing happens. This loop only stops when the player coordinates change and the event can move.

    To be completely honest, using "Wait" might still lead to nasty issues if not timed properly (the damage might be dealt twice: once when hitting the player, once again as soon as the player moves another step after the wait command ends). The way to time it properly to avoid the aforementioned issue is this:
    Code:
    pick_a_var = var_id_here # E.g. 12, do not use it in your game for anything else
    pick_a_switch = switch_id_here # Read below
    cd = set_a_cooldown_for_damage_here # E.g. 30
    unless $game_variables[pick_a_var].is_a?(Array)
      $game_variables[pick_a_var] = [-1, -1, 0]
    end # You can write this in a single line, but it might be too long.
    same_x = ($game_variables[pick_a_var][0] == $game_player.x)
    same_y = ($game_variables[pick_a_var][1] == $game_player.y)
    change_xy = !(same_x && same_y)
    cd_expired = ($game_variables[pick_a_var][2] == cd)
    if (change_xy || cd_expired)
      $game_variables[pick_a_var] = [$game_player.x, $game_player.y, 0]
      $game_switches[pick_a_switch] = true
      # Alternatively -> $game_self_switches[[$game_map.map_id, @event_id, pick_a_switch]] = true
      # If you are using a self switch, pick_a_switch can be 'A', 'B', 'C' or 'D',
      # it doesn't make any difference, as long as you use quotation marks.
    else
      $game_variables[pick_a_var][2] += 1
    end
    
    In your event you can then check for the said switch, if it is true, you deal damage, if it is false, you do nothing.

    This logic basically checks if you have already dealt damage to the player in that position and prevents your event from dealing damage once again until the player moves or until too many attempts to hurt the player fail (otherwise the player could just stay still in the same place forever and become invulnerable). The amount of failed attempts is up to you, it depends on how many times you want the player to be able to avoid damage while standing, I recommend using a high enough number like 30 or 60. Anyway, if the player moves, the event can deal damage once again.

    All this goes in a script call. It basically works in the same way as the Wait command that Shaz suggested, but prevents the nasty interaction that I mentioned above.

    EDIT
    You could even deal damage within the script call itself, without having to use a switch, but I think that this option should be good enough for you, and it also allows you to control damage easily without having to edit the script call later on.

    EDIT 2
    @Shaz the reason why I would refrain from using a wait command here is that, if not timed properly, it would also prevent the player from moving smoothly (this is not a parallel process after all).

    According to the amount of frames left for the player sprite to complete its movement, the event can wait less than that amount, the same as that amount or more than that amount.
    • Less
      The event deals damage, the player is still moving (thus on the same square) and the event triggers once again. This repeats until the movement is completed. After that you have two different situations:
      • The player can queue a new action (which means that the wait command expired)
        When this is the case, the event still runs once more together with the first frame of the player movement, then the wait command starts counting, but it is irrelevant since the player is already moving.
      • The player cannot queue a new action (which means that the wait command is still waiting)
        If this happens the player can only queue a new action once the wait command stops counting, which leads to the previous point.
    • Same
      The event deals damage, the player ends the movement, and can queue a new action immediately. This, however, is the same as the first point of the previous case, so it is still somewhat incorrect.
    • More
      The event deals damage, the player ends the movement, but no new action can be queued because the wait command is still ongoing. This is the same as the second point of the first case, which means that the player will have to wait before being able to move.
     
    Last edited: Dec 5, 2019
    #11
    QueenTeaYT likes this.
  12. QueenTeaYT

    QueenTeaYT Veteran Veteran

    Messages:
    45
    Likes Received:
    11
    First Language:
    English
    Primarily Uses:
    RMVXA
    Oh my gosh thank you for this in-depth explanation and for even providing a solution!! :wub You made it really easy to understand and I'm super excited I can do all this without a special script.

    In theory, could I do this kind of damage to the event as well? Meaning, could the player "action button" the event and deal damage until the event "dies?"
     
    #12
  13. Shaz

    Shaz Veteran Veteran

    Messages:
    37,970
    Likes Received:
    11,631
    Location:
    Australia
    First Language:
    English
    Primarily Uses:
    RMMV
    You can't have an event set to Event Touch and Action Button at the same time
     
    #13
    QueenTeaYT likes this.
  14. Heirukichi

    Heirukichi Veteran Veteran

    Messages:
    1,303
    Likes Received:
    549
    Location:
    Italy
    First Language:
    Italian
    Primarily Uses:
    RMVXA
    @QueenTeaYT I am glad to read that you found my explanation useful. Concerning the other matter, as Shaz already said, you cannot have an event that has two different kind of triggers. However, what you can do is using a parallel process event to check if the player is pressing the action button and facing one of those events at the same time. The script call is very simple:
    Code:
    var_id = your_var_id_here # This is used to store harmful events
    $game_variables[var_id] = [0, []] unless $game_variables[var_id].is_a?(Array)
    $game_variables[var_id][0] = $game_map.map_id
    # You can add as many event IDs as you want in the following line
    $game_variables[var_id][1].replace([eventID, anotherEventID, etc])
    if (Input.trigger?(:C))
      event_hit_id = 0
      hit = false
      round_x = $game_map.round_x_with_dir($game_player.x, $game_player.direction)
      round_y = $game_map.round_y_with_dir($game_player.y, $game_player.direction)
      $game_variables[var_id][1].each do |i|
        ev = $game_map.events[i]
        if ((ev.x == round_x) && (ev.y == round_y))
          hit = true
          event_hit_id = i
          break
        end
        $game_self_switches[[$game_map.map_id, @event_id, 'A']] = hit
        $game_variables[another_variable_id_goes_here] = event_hit_id if hit
      end
    end
    
    This goes under the assumption that you have no harmful event with the "Through" setting checked. You can then use the self switch containing the hit result and the variable containing the hit event ID to do anything you want in your event. It is pretty basic, but it should be a solid way to build a rudimentary action battle system without using scripts.

    I recommend initializing the variable containing their health in a similar way as I initialized the variable containing their ID, it is pretty efficient and also solid and does not lead to memory leaks. When an event health reaches 0, you can then use a self switch to remember that so that it has no effect the next time the player enters the map.

    IMPORTANT NOTE
    You could achieve the same thing using the built-in method to check if any event is located at the rounded coordinates you obtain, but doing that includes a linear check on each event in the map, even those that are not harmful. Using the code I provided is more efficient than doing that, even if it takes a few more lines of code.

    Let me know if it fits your script call box. It can be shortened or split in two if necessary.
     
    #14
    Shaz and QueenTeaYT like this.
  15. QueenTeaYT

    QueenTeaYT Veteran Veteran

    Messages:
    45
    Likes Received:
    11
    First Language:
    English
    Primarily Uses:
    RMVXA
    It is a bit info-packed, so I will spend some time using your advice to figure it all out. Thank you so much, I appreciate you going above and beyond my original question to help. :wub
     
    #15

Share This Page