Taking more damage than I program?

QueenTeaYT

Veteran
Veteran
Joined
Nov 8, 2019
Messages
45
Reaction score
11
First Language
English
Primarily Uses
RMVXA
I made an enemy sprite with these contents:

@>Change HP: Entire Party, -1
@>Show Animation: Player, [Slash Physical]
Autonomous Movement
Type: Approach
Speed: 4: Normal
Freq: 5: Hightest
Priority
Same as Characters
Trigger
Event Touch
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!!
 

gstv87

Veteran
Veteran
Joined
Oct 20, 2015
Messages
2,154
Reaction score
1,123
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:

QueenTeaYT

Veteran
Veteran
Joined
Nov 8, 2019
Messages
45
Reaction score
11
First Language
English
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.
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. :)
 

QueenTeaYT

Veteran
Veteran
Joined
Nov 8, 2019
Messages
45
Reaction score
11
First Language
English
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?
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.
 

gstv87

Veteran
Veteran
Joined
Oct 20, 2015
Messages
2,154
Reaction score
1,123
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.
 

QueenTeaYT

Veteran
Veteran
Joined
Nov 8, 2019
Messages
45
Reaction score
11
First Language
English
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.
Ooh I understand now! Thanks for explaining again! c:
 

Shaz

Veteran
Veteran
Joined
Mar 2, 2012
Messages
39,429
Reaction score
12,953
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.
 

QueenTeaYT

Veteran
Veteran
Joined
Nov 8, 2019
Messages
45
Reaction score
11
First Language
English
Primarily Uses
RMVXA
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.
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!
 

gstv87

Veteran
Veteran
Joined
Oct 20, 2015
Messages
2,154
Reaction score
1,123
First Language
Spanish
Primarily Uses
RMVXA
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.
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.
 

QueenTeaYT

Veteran
Veteran
Joined
Nov 8, 2019
Messages
45
Reaction score
11
First Language
English
Primarily Uses
RMVXA
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.
Using "wait" before giving damage works! :D Now the player only takes 1 damage at a time. Thank you so much!
 

Heirukichi

Veteran
Veteran
Joined
Sep 24, 2015
Messages
1,397
Reaction score
587
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:

QueenTeaYT

Veteran
Veteran
Joined
Nov 8, 2019
Messages
45
Reaction score
11
First Language
English
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.
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?"
 

Shaz

Veteran
Veteran
Joined
Mar 2, 2012
Messages
39,429
Reaction score
12,953
First Language
English
Primarily Uses
RMMV
You can't have an event set to Event Touch and Action Button at the same time
 

Heirukichi

Veteran
Veteran
Joined
Sep 24, 2015
Messages
1,397
Reaction score
587
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.
 

QueenTeaYT

Veteran
Veteran
Joined
Nov 8, 2019
Messages
45
Reaction score
11
First Language
English
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.
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
 

Users Who Are Viewing This Thread (Users: 0, Guests: 1)

Latest Threads

Latest Posts

Latest Profile Posts

Anyone here managed to never burn out on programming? My current limit is 3 months(6-8 hours per day, 7 days per week, 50 hour programming week on average), and then I just have to take a break, sometimes lasting few days(with at most 2 hours on programming per day). I've been always like this so far, so I admire those who can always be so passionate on programming :)
This is starting to become a momochi collection y'all!
Meet Swefo The candy Eater!

Hide your candy... I or I sweefe sweefefooo~~~
Automatic level scaling without an option to turn it off can be a very bad choice for a game. The worst I've ever seen was in Nightmare of Druaga, where if a power outage made your system turn off, the game detects it as an attempted cheat and overwrites your save while taking away your best gear, leaving you unable to progress at the late stages of the game, and unable to recover.
Problem with sequels: Heroes getting rid of all their items and forgets all of their skills within the span of a year without explanation. :kaomad3:
I can see the end of my prologue. Perfect time to decide to pull everything over into MZ, right? Right?!

Forum statistics

Threads
99,652
Messages
967,699
Members
131,329
Latest member
GenAlFateh
Top