diff --git a/include/types.h b/include/types.h index a39ec00be..aa5048ed7 100644 --- a/include/types.h +++ b/include/types.h @@ -427,7 +427,7 @@ struct MarioState /*????*/ u8 wasNetworkVisible; /*????*/ f32 minimumBoneY; /*????*/ f32 curAnimOffset; - /*????*/ u8 knockbackTimer; + /*????*/ s8 knockbackTimer; /*????*/ u8 specialTripleJump; /*????*/ Vec3f wallNormal; /*????*/ u8 visibleToEnemies; diff --git a/src/game/interaction.c b/src/game/interaction.c index b2d023175..c04f343be 100644 --- a/src/game/interaction.c +++ b/src/game/interaction.c @@ -672,9 +672,9 @@ u32 determine_knockback_action(struct MarioState *m, UNUSED s32 arg) { if (!is_player_active(m2)) { continue; } if (m2->marioObj == NULL) { continue; } if (m2->marioObj != m->interactObj) { continue; } - if (m2->action == ACT_JUMP_KICK) { scaler = 2.0f; } + if (m2->flags & MARIO_KICKING) { scaler = 2.0f; } else if (m2->action == ACT_DIVE) { scaler = 1 + fabs(m2->forwardVel * 0.01f); } - else if (m2->action == ACT_PUNCHING || m2->action == ACT_MOVE_PUNCHING) { hasBeenPunched = TRUE; } + else if ((m2->flags & MARIO_PUNCHING)) { scaler = 0.2; hasBeenPunched = TRUE; } if (m2->flags & MARIO_METAL_CAP) { scaler *= 1.25f; } break; } @@ -692,7 +692,7 @@ u32 determine_knockback_action(struct MarioState *m, UNUSED s32 arg) { m->vel[2] = -mag * coss(m->interactObj->oFaceAngleYaw); m->slideVelX = m->vel[0]; m->slideVelZ = m->vel[2]; - m->knockbackTimer = hasBeenPunched ? PVP_ATTACK_KNOCKBACK_TIMER_OVERRIDE : PVP_ATTACK_KNOCKBACK_TIMER_DEFAULT; + m->knockbackTimer = hasBeenPunched ? PVP_ATTACK_KNOCKBACK_TIMER_OVERRIDE + 1 : PVP_ATTACK_KNOCKBACK_TIMER_DEFAULT; m->faceAngle[1] = m->interactObj->oFaceAngleYaw + (sign == 1.0f ? 0 : 0x8000); } @@ -826,8 +826,7 @@ u32 take_damage_and_knock_back(struct MarioState *m, struct Object *o) { } update_mario_sound_and_camera(m); - u32 action = determine_knockback_action(m, o->oDamageOrCoinValue); - return drop_and_set_mario_action(m, action, (m->knockbackTimer == PVP_ATTACK_KNOCKBACK_TIMER_DEFAULT) ? damage : PVP_ATTACK_OVERRIDE_VANILLA_INVINCIBILITY); + return drop_and_set_mario_action(m, determine_knockback_action(m, o->oDamageOrCoinValue), damage); } return FALSE; @@ -1355,9 +1354,13 @@ u8 passes_pvp_interaction_checks(struct MarioState* attacker, struct MarioState* || attacker->action == ACT_STEEP_JUMP || attacker->action == ACT_HOLD_JUMP); u8 isVictimIntangible = (victim->action & ACT_FLAG_INTANGIBLE); u8 isVictimGroundPounding = (victim->action == ACT_GROUND_POUND) && (victim->actionState != 0); - if (victim->knockbackTimer > 0) { + if (victim->knockbackTimer != 0) { return false; } + if ((attacker->action == ACT_PUNCHING || attacker->action == ACT_MOVE_PUNCHING) && + (victim->action == ACT_SOFT_BACKWARD_GROUND_KB || victim->action == ACT_SOFT_FORWARD_GROUND_KB)) { + return true; + } return (!isInvulnerable && !isIgnoredAttack && !isAttackerInvulnerable && !isVictimIntangible && !isVictimGroundPounding); } @@ -1491,7 +1494,9 @@ u32 interact_player_pvp(struct MarioState* attacker, struct MarioState* victim) victim->invincTimer = max(victim->invincTimer, 3); take_damage_and_knock_back(victim, attacker->marioObj); - bounce_back_from_attack(attacker, interaction); + if (!(attacker->flags & MARIO_PUNCHING)) { + bounce_back_from_attack(attacker, interaction); + } victim->interactObj = NULL; smlua_call_event_hooks_mario_params(HOOK_ON_PVP_ATTACK, attacker, victim, interaction); diff --git a/src/game/interaction.h b/src/game/interaction.h index 2c70d63b5..74b2affb4 100644 --- a/src/game/interaction.h +++ b/src/game/interaction.h @@ -100,7 +100,7 @@ enum InteractionFlag { #define ATTACK_FROM_BELOW 6 #define PVP_ATTACK_KNOCKBACK_TIMER_DEFAULT 10 -#define PVP_ATTACK_KNOCKBACK_TIMER_OVERRIDE 9 +#define PVP_ATTACK_KNOCKBACK_TIMER_OVERRIDE -5 #define PVP_ATTACK_OVERRIDE_VANILLA_INVINCIBILITY 0x0000FFFF #define INT_STATUS_ATTACK_MASK 0x000000FF diff --git a/src/game/mario.c b/src/game/mario.c index 1b30893bd..06049177f 100644 --- a/src/game/mario.c +++ b/src/game/mario.c @@ -1970,6 +1970,8 @@ s32 execute_mario_action(UNUSED struct Object *o) { if (gMarioState->knockbackTimer > 0) { gMarioState->knockbackTimer--; + } else if (gMarioState->knockbackTimer < 0) { + gMarioState->knockbackTimer++; } // hide inactive players diff --git a/src/game/mario_actions_airborne.c b/src/game/mario_actions_airborne.c index 229784b2c..602727819 100644 --- a/src/game/mario_actions_airborne.c +++ b/src/game/mario_actions_airborne.c @@ -1160,6 +1160,8 @@ u32 common_air_knockback_step(struct MarioState *m, u32 landAction, u32 hardFall if (m->interactObj == NULL || !(m->interactObj->oInteractType & INTERACT_PLAYER)) { mario_set_forward_vel(m, speed); } + } else if (m->knockbackTimer < 0) { + // do nothing } else { m->knockbackTimer = PVP_ATTACK_KNOCKBACK_TIMER_DEFAULT; } diff --git a/src/game/mario_actions_moving.c b/src/game/mario_actions_moving.c index 129299914..c8add04f6 100644 --- a/src/game/mario_actions_moving.c +++ b/src/game/mario_actions_moving.c @@ -1678,6 +1678,8 @@ s32 common_ground_knockback_action(struct MarioState *m, s32 animation, s32 arg2 m->forwardVel = -32.0f; } } + } else if (m->knockbackTimer < 0) { + // do nothing } else { m->knockbackTimer = PVP_ATTACK_KNOCKBACK_TIMER_DEFAULT; } @@ -1701,9 +1703,7 @@ s32 common_ground_knockback_action(struct MarioState *m, s32 animation, s32 arg2 if (m->health < 0x100) { set_mario_action(m, ACT_STANDING_DEATH, 0); } else { - if (arg4 == PVP_ATTACK_OVERRIDE_VANILLA_INVINCIBILITY) { // Make being punched have reduced invincibility frames - m->invincTimer = 12; - } else if (arg4 > 0) { + if (arg4 > 0) { m->invincTimer = 30; } set_mario_action(m, ACT_IDLE, 0);