I’m learning Python, my first project was a tiny text-based game, now I remade it using Pygame. When I got to implementing combat I ran into this problem and failed to solve it on my own. What’s supposed to happen is the enemy goes idle for a turn, meaning a hard-hitting attack is incoming, and then after the player takes their turn the attack is delivered on the enemy’s second turn. And in most cases it behaves as it should. But if the player uses a defensive action (parry or counterspell) when the enemy is not preapring an attack then the idle part of the attack is skipped and it goes straight to instant damage.
Here’s the piece of the code that handles the player and the enemy’s turns:
if not player_turn:
if sblade.hp < sblade.hp_max*0.3:
if not action_generated:
action = random.randint(1, 2)
action_generated = True
if action == 1:
sblade.idle_index = 0
sblade.is_interrupting = False
sblade.is_preparing_attack = False
sblade.is_preparing_spell = False
sblade.is_idle = True
third_status_message = f"{sblade.name} looks scared and is taking a defensive posture."
sblade.is_parrying = True
player_turn = not player_turn
elif action == 2:
sblade.idle_index = 0
sblade.is_parrying = False
sblade.is_preparing_attack = False
sblade.is_preparing_spell = False
sblade.is_idle = True
third_status_message = f"{sblade.name} looks scared and is preparing a counterspell"
sblade.is_interrupting = True
player_turn = not player_turn
else:
if sblade.is_preparing_attack:
if not virtual_keypress:
# enemy uses the same attack functions as the player and they rely on variables being set to certain
# values by the player pressing Enter so there's a virtual keypress for the enemy
keys_locked = True
sblade.is_moving = True
sblade.is_moving_forward = True
virtual_keypress = True
channeled_attack(sblade, lavender, SBLADE_CHARGED_ATTACK2_LIST)
elif sblade.is_preparing_spell:
if not virtual_keypress:
keys_locked = True
sblade.is_moving = True
sblade.is_moving_forward = True
virtual_keypress = True
channeled_attack(sblade, lavender, SBLADE_CHARGED_SPELL2_LIST)
else:
if not action_generated:
action = random.randint(1, 4)
action_generated = True
if action == 1:
if not virtual_keypress:
keys_locked = True
sblade.is_parrying = False
sblade.is_interrupting = False
sblade.is_moving = True
sblade.is_moving_forward = True
virtual_keypress = True
attack(sblade, lavender, SBLADE_ATTACK_LIST)
elif action == 2:
if not virtual_keypress:
keys_locked = True
sblade.is_parrying = False
sblade.is_interrupting = False
sblade.is_casting = True
virtual_keypress = True
spell(sblade, lavender)
elif action == 3:
sblade.idle_index = 0
sblade.is_interrupting = False
sblade.is_parrying = False
sblade.is_preparing_attack = True
sblade.status_message = f"{sblade.name} is looking for an opening."
player_turn = not player_turn
elif action == 4:
sblade.idle_index = 0
sblade.is_parrying = False
sblade.is_interrupting = False
sblade.is_preparing_spell = True
sblade.status_message = f"{sblade.name} is looking focused."
player_turn = not player_turn
elif player_turn:
if not keys_locked:
arrow_movement(keys_pressed, arrow_rect)
if arrow_rect.y == pos1[1]:
if keys_pressed[pygame.K_RETURN] and not keys_locked:
main.confirm_sound.play()
keys_locked = True
lavender.is_parrying = False
lavender.is_interrupting = False
lavender.is_moving = True
lavender.is_moving_forward = True
attack(lavender, sblade, LAVENDER_ATTACK_LIST)
if arrow_rect.y == pos2[1]:
if keys_pressed[pygame.K_RETURN] and not keys_locked:
main.confirm_sound.play()
keys_locked = True
lavender.is_parrying = False
lavender.is_interrupting = False
lavender.is_casting = True
spell(lavender, sblade)
if arrow_rect.y == pos3[1]:
if keys_pressed[pygame.K_RETURN] and not keys_locked:
main.confirm_sound.play()
lavender.is_parrying = True
lavender.is_interrupting = False
lavender.status_message = "Lavender is preparing to parry."
action_generated = False
virtual_keypress = False
player_turn = not player_turn
if arrow_rect.y == pos4[1]:
if keys_pressed[pygame.K_RETURN] and not keys_locked:
main.confirm_sound.play()
lavender.is_interrupting = True
lavender.is_parrying = False
lavender.status_message = "Lavender is preparing to interrupt a spell."
action_generated = False
virtual_keypress = False
player_turn = not player_turn
The non-channelled attacks still happen when the player uses a defesive action so, since they’re in the same action pool as initiations of the channelled attacks, I’m guessing that the first half of a channelled attack still happens but then for some reason instead of passing the turn to the player it goes back to the beginning and the second half gets triggered. And if the player isn’t using a defesive action then it passes the turn as it should.
I don’t even see why it would be like that and so where to start with looking for a solution. Maybe I’m just too fatigued at this point becasue so far I’ve been figuring stuff and my own without asking anyone and while successful with everything except this one thing it also made the whole process take a veeeeryyyy long time. And I also got some brain lag and decided to make the player’s defesive actions set keys_locked to True even though it’s only ever a condition for allowing player input but for some reason it actually solved the problem which just confused me even more. Did I just go blind and can’t see how it makes a difference? But that’s not a valid solution, as to enable player input for subsequent turns the enemy’s actions that set up channelled attacks would need to set keys_locked back to False and when I made them do that channelled attacks went back to happenning instantly if the player uses a defensive action.
Nemoniah is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.