Rework PvP Balance (#357)

* PvP Rework

This rearranges the damages of last PR. The underused attacks should still see some buffs.

* Adjust how punches apply invincibility

Also increase punch invincibility timer to 12

* EmeraldLoc's easy suggestions

* Rework punching pvp

Punching no longer reduces invincibility frames. Instead, punches can ignore knockback invincibility and the full punch punch kick combo can be done.

* Adjust numbers

Breakdances should not deal 3 damage

* Potential fix for more common tripping

"Trip" here refers to 1 damage kicks

* Add temporary invincibility to rollouts

This is a test to see how different pvp feels with this change. Suggestion by sausrelics.

* Fix invincibility

* Prevent low damage/low knockback kicks altogether

* Update ignored attack list

* Allow dives to be attacked by most actions

A lot of people don't want dives to be entirely invincible and some suggested to make dives be able to only pierce through jump kicks

* Slightly nerf kick knockback

Suggestion by emily

* Rework dive piercing

Instead of all actions being able to hit dives other than jumpkicks, now only slidekicks (and ground pounds) can hit dives.

* Mild kick knockback increase from nerf

* Change direct equality to checking flag

* Decrease dive and punch knockback

* Prevent trades against dives with slidekicks

* Revert "Prevent trades against dives with slidekicks"

This reverts commit 2a2c3266a7.

* Allow ground pounds to always hit a sliding player

* Add server setting to change pvp

* Add pvp settings to config

* Add selection to menu

* Fix issues + autogen

* Rewrite goto statement to not use goto
This commit is contained in:
Sunk 2024-11-25 05:48:40 -05:00 committed by GitHub
parent cb34d85c33
commit 947ce9f080
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 129 additions and 32 deletions

View file

@ -3675,6 +3675,15 @@ INT_SUBTYPE_STAR_DOOR = 0x00000020
--- @type integer --- @type integer
INT_SUBTYPE_TWIRL_BOUNCE = 0x00000080 INT_SUBTYPE_TWIRL_BOUNCE = 0x00000080
--- @type integer
PVP_ATTACK_KNOCKBACK_TIMER_DEFAULT = 10
--- @type integer
PVP_ATTACK_KNOCKBACK_TIMER_OVERRIDE = -5
--- @type integer
PVP_ATTACK_OVERRIDE_VANILLA_INVINCIBILITY = 0x0000FFFF
--- @class InteractionFlag --- @class InteractionFlag
--- @type InteractionFlag --- @type InteractionFlag
@ -5549,6 +5558,14 @@ PLAYER_INTERACTIONS_SOLID = 1
--- @type PlayerInteractions --- @type PlayerInteractions
PLAYER_INTERACTIONS_PVP = 2 PLAYER_INTERACTIONS_PVP = 2
--- @class PvpType
--- @type PvpType
PLAYER_PVP_CLASSIC = 0
--- @type PvpType
PLAYER_PVP_REVAMPED = 1
--- @type integer --- @type integer
MAX_DESCRIPTION_STRING = 20 MAX_DESCRIPTION_STRING = 20

View file

@ -2034,6 +2034,7 @@
--- @field public pauseAnywhere integer --- @field public pauseAnywhere integer
--- @field public playerInteractions PlayerInteractions --- @field public playerInteractions PlayerInteractions
--- @field public playerKnockbackStrength integer --- @field public playerKnockbackStrength integer
--- @field public pvpType PvpType
--- @field public skipIntro integer --- @field public skipIntro integer
--- @field public stayInLevelAfterStar integer --- @field public stayInLevelAfterStar integer

View file

@ -45,6 +45,7 @@
- [enum BouncyLevelBounds](#enum-BouncyLevelBounds) - [enum BouncyLevelBounds](#enum-BouncyLevelBounds)
- [enum NetworkSystemType](#enum-NetworkSystemType) - [enum NetworkSystemType](#enum-NetworkSystemType)
- [enum PlayerInteractions](#enum-PlayerInteractions) - [enum PlayerInteractions](#enum-PlayerInteractions)
- [enum PvpType](#enum-PvpType)
- [network_player.h](#network_playerh) - [network_player.h](#network_playerh)
- [enum NetworkPlayerType](#enum-NetworkPlayerType) - [enum NetworkPlayerType](#enum-NetworkPlayerType)
- [obj_behaviors.c](#obj_behaviorsc) - [obj_behaviors.c](#obj_behaviorsc)
@ -1295,6 +1296,9 @@
- INT_SUBTYPE_SIGN - INT_SUBTYPE_SIGN
- INT_SUBTYPE_STAR_DOOR - INT_SUBTYPE_STAR_DOOR
- INT_SUBTYPE_TWIRL_BOUNCE - INT_SUBTYPE_TWIRL_BOUNCE
- PVP_ATTACK_KNOCKBACK_TIMER_DEFAULT
- PVP_ATTACK_KNOCKBACK_TIMER_OVERRIDE
- PVP_ATTACK_OVERRIDE_VANILLA_INVINCIBILITY
### [enum InteractionFlag](#InteractionFlag) ### [enum InteractionFlag](#InteractionFlag)
| Identifier | Value | | Identifier | Value |
@ -2006,6 +2010,12 @@
| PLAYER_INTERACTIONS_SOLID | 1 | | PLAYER_INTERACTIONS_SOLID | 1 |
| PLAYER_INTERACTIONS_PVP | 2 | | PLAYER_INTERACTIONS_PVP | 2 |
### [enum PvpType](#PvpType)
| Identifier | Value |
| :--------- | :---- |
| PLAYER_PVP_CLASSIC | 0 |
| PLAYER_PVP_REVAMPED | 1 |
[:arrow_up_small:](#) [:arrow_up_small:](#)
<br /> <br />

View file

@ -2563,6 +2563,7 @@
| pauseAnywhere | `integer` | | | pauseAnywhere | `integer` | |
| playerInteractions | [enum PlayerInteractions](constants.md#enum-PlayerInteractions) | | | playerInteractions | [enum PlayerInteractions](constants.md#enum-PlayerInteractions) | |
| playerKnockbackStrength | `integer` | | | playerKnockbackStrength | `integer` | |
| pvpType | [enum PvpType](constants.md#enum-PvpType) | |
| skipIntro | `integer` | | | skipIntro | `integer` | |
| stayInLevelAfterStar | `integer` | | | stayInLevelAfterStar | `integer` | |

View file

@ -428,7 +428,7 @@ struct MarioState
/*????*/ u8 wasNetworkVisible; /*????*/ u8 wasNetworkVisible;
/*????*/ f32 minimumBoneY; /*????*/ f32 minimumBoneY;
/*????*/ f32 curAnimOffset; /*????*/ f32 curAnimOffset;
/*????*/ u8 knockbackTimer; /*????*/ s8 knockbackTimer;
/*????*/ u8 specialTripleJump; /*????*/ u8 specialTripleJump;
/*????*/ Vec3f wallNormal; /*????*/ Vec3f wallNormal;
/*????*/ u8 visibleToEnemies; /*????*/ u8 visibleToEnemies;

View file

@ -194,6 +194,9 @@ WEAK = "Weak"
NORMAL = "Normal" NORMAL = "Normal"
TOO_MUCH = "Too much" TOO_MUCH = "Too much"
KNOCKBACK_STRENGTH = "Knockback Strength" KNOCKBACK_STRENGTH = "Knockback Strength"
CLASSIC_PVP = "Classic"
REVAMPED_PVP = "Revamped"
PVP_MODE = "Player PvP Mode"
LEAVE_LEVEL = "Leave Level" LEAVE_LEVEL = "Leave Level"
STAY_IN_LEVEL = "Stay In Level" STAY_IN_LEVEL = "Stay In Level"
NONSTOP = "Non-Stop" NONSTOP = "Non-Stop"

View file

@ -159,7 +159,7 @@ u32 determine_interaction(struct MarioState *m, struct Object *o) {
if (interaction == 0 && action & ACT_FLAG_ATTACKING) { if (interaction == 0 && action & ACT_FLAG_ATTACKING) {
u32 flags = (MARIO_PUNCHING | MARIO_KICKING | MARIO_TRIPPING); u32 flags = (MARIO_PUNCHING | MARIO_KICKING | MARIO_TRIPPING);
if ((action == ACT_PUNCHING || action == ACT_MOVE_PUNCHING || action == ACT_JUMP_KICK) || if ((action == ACT_PUNCHING || action == ACT_MOVE_PUNCHING || action == ACT_JUMP_KICK) ||
(m->flags & flags && interaction & INT_LUA)) { ((m->flags & flags) && (interaction & INT_LUA))) {
s16 dYawToObject = mario_obj_angle_to_object(m, o) - m->faceAngle[1]; s16 dYawToObject = mario_obj_angle_to_object(m, o) - m->faceAngle[1];
if (m->flags & MARIO_PUNCHING) { if (m->flags & MARIO_PUNCHING) {
@ -668,16 +668,21 @@ u32 determine_knockback_action(struct MarioState *m, UNUSED s32 arg) {
// set knockback very high when dealing with player attacks // set knockback very high when dealing with player attacks
if (m->interactObj != NULL && (m->interactObj->oInteractType & INTERACT_PLAYER) && terrainIndex != 2) { if (m->interactObj != NULL && (m->interactObj->oInteractType & INTERACT_PLAYER) && terrainIndex != 2) {
f32 scaler = 1; f32 scaler = 1;
s8 hasBeenPunched = FALSE;
#define IF_REVAMPED_PVP(Is, IsNot) gServerSettings.pvpType == PLAYER_PVP_REVAMPED ? (Is) : (IsNot);
for (s32 i = 0; i < MAX_PLAYERS; i++) { for (s32 i = 0; i < MAX_PLAYERS; i++) {
struct MarioState* m2 = &gMarioStates[i]; struct MarioState* m2 = &gMarioStates[i];
if (!is_player_active(m2)) { continue; } if (!is_player_active(m2)) { continue; }
if (m2->marioObj == NULL) { continue; } if (m2->marioObj == NULL) { continue; }
if (m2->marioObj != m->interactObj) { continue; } if (m2->marioObj != m->interactObj) { continue; }
if (m2->action == ACT_JUMP_KICK) { scaler = 2.0f; } // Redundent check in case the kicking flag somehow gets missed
if (m2->action == ACT_DIVE) { scaler += fabs(m2->forwardVel * 0.01); } if (m2->action == ACT_JUMP_KICK || m2->flags & MARIO_KICKING) { scaler = IF_REVAMPED_PVP(1.85f, 2.0f); }
else if (m2->action == ACT_DIVE) { scaler = 1 + IF_REVAMPED_PVP(m2->forwardVel * 0.005f, 0); }
else if ((m2->flags & MARIO_PUNCHING)) { scaler = IF_REVAMPED_PVP(0.18f, 1.0f); hasBeenPunched = gServerSettings.pvpType == PLAYER_PVP_REVAMPED; }
if (m2->flags & MARIO_METAL_CAP) { scaler *= 1.25f; } if (m2->flags & MARIO_METAL_CAP) { scaler *= 1.25f; }
break; break;
} }
if (m->flags & MARIO_METAL_CAP) { if (m->flags & MARIO_METAL_CAP) {
scaler *= 0.5f; scaler *= 0.5f;
if (scaler < 1) { scaler = 1; } if (scaler < 1) { scaler = 1; }
@ -692,8 +697,8 @@ u32 determine_knockback_action(struct MarioState *m, UNUSED s32 arg) {
m->vel[2] = -mag * coss(m->interactObj->oFaceAngleYaw); m->vel[2] = -mag * coss(m->interactObj->oFaceAngleYaw);
m->slideVelX = m->vel[0]; m->slideVelX = m->vel[0];
m->slideVelZ = m->vel[2]; m->slideVelZ = m->vel[2];
m->knockbackTimer = 10; m->knockbackTimer = hasBeenPunched ? PVP_ATTACK_KNOCKBACK_TIMER_OVERRIDE : PVP_ATTACK_KNOCKBACK_TIMER_DEFAULT;
#undef IF_REVAMPED_PVP
m->faceAngle[1] = m->interactObj->oFaceAngleYaw + (sign == 1.0f ? 0 : 0x8000); m->faceAngle[1] = m->interactObj->oFaceAngleYaw + (sign == 1.0f ? 0 : 0x8000);
} }
@ -826,8 +831,7 @@ u32 take_damage_and_knock_back(struct MarioState *m, struct Object *o) {
} }
update_mario_sound_and_camera(m); update_mario_sound_and_camera(m);
return drop_and_set_mario_action(m, determine_knockback_action(m, o->oDamageOrCoinValue), return drop_and_set_mario_action(m, determine_knockback_action(m, o->oDamageOrCoinValue), damage);
damage);
} }
return FALSE; return FALSE;
@ -1319,11 +1323,16 @@ static u8 resolve_player_collision(struct MarioState* m, struct MarioState* m2)
} }
u8 determine_player_damage_value(u32 interaction) { u8 determine_player_damage_value(u32 interaction) {
if (interaction & INT_GROUND_POUND) { return 4; } if (gServerSettings.pvpType == PLAYER_PVP_REVAMPED) {
if (interaction & (INT_TWIRL | INT_PUNCH | INT_TRIP)) { return 3; } if (interaction & INT_GROUND_POUND) { return 3; }
if (interaction & INT_KICK) { return 2; } if (interaction & (INT_KICK | INT_SLIDE_KICK | INT_TRIP | INT_TWIRL)) { return 2; }
if (interaction & INT_SLIDE_KICK) { return 2; } return 1;
return 1; } else {
if (interaction & INT_GROUND_POUND_OR_TWIRL) { return 3; }
if (interaction & INT_KICK) { return 2; }
if (interaction & INT_ATTACK_SLIDE) { return 1; }
return 2;
}
} }
u8 player_is_sliding(struct MarioState* m) { u8 player_is_sliding(struct MarioState* m) {
@ -1354,14 +1363,25 @@ u8 passes_pvp_interaction_checks(struct MarioState* attacker, struct MarioState*
|| attacker->action == ACT_LONG_JUMP || attacker->action == ACT_SIDE_FLIP || attacker->action == ACT_LONG_JUMP || attacker->action == ACT_SIDE_FLIP
|| attacker->action == ACT_BACKFLIP || attacker->action == ACT_TRIPLE_JUMP || attacker->action == ACT_BACKFLIP || attacker->action == ACT_TRIPLE_JUMP
|| attacker->action == ACT_WALL_KICK_AIR || attacker->action == ACT_WATER_JUMP || attacker->action == ACT_WALL_KICK_AIR || attacker->action == ACT_WATER_JUMP
|| attacker->action == ACT_STEEP_JUMP || attacker->action == ACT_HOLD_JUMP); || attacker->action == ACT_STEEP_JUMP || attacker->action == ACT_HOLD_JUMP
|| attacker->action == ACT_FREEFALL || attacker->action == ACT_LEDGE_GRAB
|| attacker->action == ACT_FORWARD_ROLLOUT || attacker->action == ACT_BACKWARD_ROLLOUT);
u8 isVictimIntangible = (victim->action & ACT_FLAG_INTANGIBLE); u8 isVictimIntangible = (victim->action & ACT_FLAG_INTANGIBLE);
u8 isVictimGroundPounding = (victim->action == ACT_GROUND_POUND) && (victim->actionState != 0); u8 isVictimGroundPounding = (victim->action == ACT_GROUND_POUND) && (victim->actionState != 0);
if (victim->knockbackTimer > 0) { u8 isVictimInRolloutFlip = (victim->action == ACT_FORWARD_ROLLOUT || victim->action == ACT_BACKWARD_ROLLOUT) && (victim->actionState == 1);
if (victim->knockbackTimer != 0) {
return false; return false;
} }
return (!isInvulnerable && !isIgnoredAttack && !isAttackerInvulnerable && !isVictimIntangible && !isVictimGroundPounding); if (gServerSettings.pvpType == PLAYER_PVP_REVAMPED &&
(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;
} else if (attacker->flags & MARIO_TRIPPING) {
return false;
}
return (!isInvulnerable && !isIgnoredAttack && !isAttackerInvulnerable && !isVictimIntangible && !isVictimGroundPounding && !isVictimInRolloutFlip);
} }
u32 interact_player(struct MarioState* m, UNUSED u32 interactType, struct Object* o) { u32 interact_player(struct MarioState* m, UNUSED u32 interactType, struct Object* o) {
@ -1437,6 +1457,8 @@ u32 interact_player_pvp(struct MarioState* attacker, struct MarioState* victim)
// see if it was an attack // see if it was an attack
u32 interaction = determine_interaction(attacker, cVictim->marioObj); u32 interaction = determine_interaction(attacker, cVictim->marioObj);
// Specfically override jump kicks to prevent low damage and low knockback kicks
if (interaction & INT_HIT_FROM_BELOW && attacker->action == ACT_JUMP_KICK) { interaction = INT_KICK; }
if (!(interaction & INT_ANY_ATTACK) || (interaction & INT_HIT_FROM_ABOVE) || !passes_pvp_interaction_checks(attacker, cVictim)) { if (!(interaction & INT_ANY_ATTACK) || (interaction & INT_HIT_FROM_ABOVE) || !passes_pvp_interaction_checks(attacker, cVictim)) {
return FALSE; return FALSE;
} }
@ -1450,21 +1472,32 @@ u32 interact_player_pvp(struct MarioState* attacker, struct MarioState* victim)
} }
// determine if slide attack should be ignored // determine if slide attack should be ignored
// Ground pounds will always be able to hit
if ((interaction & INT_ATTACK_SLIDE) || player_is_sliding(cVictim)) { if ((interaction & INT_ATTACK_SLIDE) || player_is_sliding(cVictim)) {
// determine the difference in velocities // determine the difference in velocities
Vec3f velDiff; //Vec3f velDiff;
vec3f_dif(velDiff, attacker->vel, cVictim->vel); //vec3f_dif(velDiff, attacker->vel, cVictim->vel);
if (gServerSettings.pvpType == PLAYER_PVP_REVAMPED && attacker->action == ACT_GROUND_POUND) {
if (attacker->action == ACT_SLIDE_KICK_SLIDE || attacker->action == ACT_SLIDE_KICK) { // do nothing
// if the difference vectors are not different enough, do not attack
if (vec3f_length(attacker->vel) < 15) { return FALSE; }
} else { } else {
// if the difference vectors are not different enough, do not attack if (attacker->action == ACT_SLIDE_KICK_SLIDE || attacker->action == ACT_SLIDE_KICK) {
if (vec3f_length(attacker->vel) < 40) { return FALSE; } // if the difference vectors are not different enough, do not attack
} if (vec3f_length(attacker->vel) < 15) { return FALSE; }
} else {
// if the difference vectors are not different enough, do not attack
if (vec3f_length(attacker->vel) < 40) { return FALSE; }
}
// if the victim is going faster, do not attack // if the victim is going faster, do not attack
if (vec3f_length(cVictim->vel) > vec3f_length(attacker->vel)) { return FALSE; } // However if the victim is diving and the attacker is slidekicking, do not check speed
if (vec3f_length(cVictim->vel) > vec3f_length(attacker->vel)) {
if (gServerSettings.pvpType == PLAYER_PVP_REVAMPED && (attacker->action == ACT_SLIDE_KICK && cVictim->action == ACT_DIVE)) {
// do nothing, meaning don't exit
} else {
return FALSE;
}
}
}
} }
// determine if ground pound should be ignored // determine if ground pound should be ignored
@ -1493,7 +1526,9 @@ u32 interact_player_pvp(struct MarioState* attacker, struct MarioState* victim)
victim->invincTimer = max(victim->invincTimer, 3); victim->invincTimer = max(victim->invincTimer, 3);
take_damage_and_knock_back(victim, attacker->marioObj); take_damage_and_knock_back(victim, attacker->marioObj);
bounce_back_from_attack(attacker, interaction); if (gServerSettings.pvpType != PLAYER_PVP_REVAMPED || !(attacker->flags & MARIO_PUNCHING)) {
bounce_back_from_attack(attacker, interaction);
}
victim->interactObj = NULL; victim->interactObj = NULL;
smlua_call_event_hooks_mario_params(HOOK_ON_PVP_ATTACK, attacker, victim, interaction); smlua_call_event_hooks_mario_params(HOOK_ON_PVP_ATTACK, attacker, victim, interaction);

View file

@ -100,6 +100,10 @@ enum InteractionFlag {
#define ATTACK_FAST_ATTACK 5 #define ATTACK_FAST_ATTACK 5
#define ATTACK_FROM_BELOW 6 #define ATTACK_FROM_BELOW 6
#define PVP_ATTACK_KNOCKBACK_TIMER_DEFAULT 10
#define PVP_ATTACK_KNOCKBACK_TIMER_OVERRIDE -5
#define PVP_ATTACK_OVERRIDE_VANILLA_INVINCIBILITY 0x0000FFFF
#define INT_STATUS_ATTACK_MASK 0x000000FF #define INT_STATUS_ATTACK_MASK 0x000000FF
#define INT_STATUS_HOOT_GRABBED_BY_MARIO (1 << 0) /* 0x00000001 */ #define INT_STATUS_HOOT_GRABBED_BY_MARIO (1 << 0) /* 0x00000001 */

View file

@ -1970,6 +1970,8 @@ s32 execute_mario_action(UNUSED struct Object *o) {
if (gMarioState->knockbackTimer > 0) { if (gMarioState->knockbackTimer > 0) {
gMarioState->knockbackTimer--; gMarioState->knockbackTimer--;
} else if (gMarioState->knockbackTimer < 0) {
gMarioState->knockbackTimer++;
} }
// hide inactive players // hide inactive players

View file

@ -1160,8 +1160,10 @@ u32 common_air_knockback_step(struct MarioState *m, u32 landAction, u32 hardFall
if (m->interactObj == NULL || !(m->interactObj->oInteractType & INTERACT_PLAYER)) { if (m->interactObj == NULL || !(m->interactObj->oInteractType & INTERACT_PLAYER)) {
mario_set_forward_vel(m, speed); mario_set_forward_vel(m, speed);
} }
} else if (m->knockbackTimer < 0) {
// do nothing
} else { } else {
m->knockbackTimer = 10; m->knockbackTimer = PVP_ATTACK_KNOCKBACK_TIMER_DEFAULT;
} }
stepResult = perform_air_step(m, 0); stepResult = perform_air_step(m, 0);

View file

@ -1678,8 +1678,10 @@ s32 common_ground_knockback_action(struct MarioState *m, s32 animation, s32 arg2
m->forwardVel = -32.0f; m->forwardVel = -32.0f;
} }
} }
} else if (m->knockbackTimer < 0) {
// do nothing
} else { } else {
m->knockbackTimer = 10; m->knockbackTimer = PVP_ATTACK_KNOCKBACK_TIMER_DEFAULT;
} }
animFrame = set_character_animation(m, animation); animFrame = set_character_animation(m, animation);

View file

@ -170,6 +170,7 @@ bool configMenuDemos = false;
bool configDisablePopups = false; bool configDisablePopups = false;
char configLanguage[MAX_CONFIG_STRING] = ""; char configLanguage[MAX_CONFIG_STRING] = "";
bool configDynosLocalPlayerModelOnly = false; bool configDynosLocalPlayerModelOnly = false;
unsigned int configPvpMode = PLAYER_PVP_CLASSIC;
// CoopNet settings // CoopNet settings
char configCoopNetIp[MAX_CONFIG_STRING] = DEFAULT_COOPNET_IP; char configCoopNetIp[MAX_CONFIG_STRING] = DEFAULT_COOPNET_IP;
unsigned int configCoopNetPort = DEFAULT_COOPNET_PORT; unsigned int configCoopNetPort = DEFAULT_COOPNET_PORT;
@ -300,6 +301,7 @@ static const struct ConfigOption options[] = {
{.name = "coop_menu_level", .type = CONFIG_TYPE_UINT, .uintValue = &configMenuLevel}, {.name = "coop_menu_level", .type = CONFIG_TYPE_UINT, .uintValue = &configMenuLevel},
{.name = "coop_menu_sound", .type = CONFIG_TYPE_UINT, .uintValue = &configMenuSound}, {.name = "coop_menu_sound", .type = CONFIG_TYPE_UINT, .uintValue = &configMenuSound},
{.name = "coop_menu_random", .type = CONFIG_TYPE_BOOL, .boolValue = &configMenuRandom}, {.name = "coop_menu_random", .type = CONFIG_TYPE_BOOL, .boolValue = &configMenuRandom},
{.name = "player_pvp_mode", .type = CONFIG_TYPE_UINT, .uintValue = &configPvpMode},
// {.name = "coop_menu_demos", .type = CONFIG_TYPE_BOOL, .boolValue = &configMenuDemos}, // {.name = "coop_menu_demos", .type = CONFIG_TYPE_BOOL, .boolValue = &configMenuDemos},
{.name = "disable_popups", .type = CONFIG_TYPE_BOOL, .boolValue = &configDisablePopups}, {.name = "disable_popups", .type = CONFIG_TYPE_BOOL, .boolValue = &configDisablePopups},
{.name = "language", .type = CONFIG_TYPE_STRING, .stringValue = (char*)&configLanguage, .maxStringLength = MAX_CONFIG_STRING}, {.name = "language", .type = CONFIG_TYPE_STRING, .stringValue = (char*)&configLanguage, .maxStringLength = MAX_CONFIG_STRING},

View file

@ -123,6 +123,7 @@ extern bool configMenuDemos;
extern bool configDisablePopups; extern bool configDisablePopups;
extern char configLanguage[MAX_CONFIG_STRING]; extern char configLanguage[MAX_CONFIG_STRING];
extern bool configDynosLocalPlayerModelOnly; extern bool configDynosLocalPlayerModelOnly;
extern unsigned int configPvpMode;
// CoopNet settings // CoopNet settings
extern char configCoopNetIp[MAX_CONFIG_STRING]; extern char configCoopNetIp[MAX_CONFIG_STRING];
extern unsigned int configCoopNetPort; extern unsigned int configCoopNetPort;

View file

@ -55,6 +55,9 @@ void djui_panel_host_settings_create(struct DjuiBase* caller) {
char* kChoices[3] = { DLANG(HOST_SETTINGS, WEAK), DLANG(HOST_SETTINGS, NORMAL), DLANG(HOST_SETTINGS, TOO_MUCH) }; char* kChoices[3] = { DLANG(HOST_SETTINGS, WEAK), DLANG(HOST_SETTINGS, NORMAL), DLANG(HOST_SETTINGS, TOO_MUCH) };
djui_selectionbox_create(body, DLANG(HOST_SETTINGS, KNOCKBACK_STRENGTH), kChoices, 3, &sKnockbackIndex, djui_panel_host_settings_knockback_change); djui_selectionbox_create(body, DLANG(HOST_SETTINGS, KNOCKBACK_STRENGTH), kChoices, 3, &sKnockbackIndex, djui_panel_host_settings_knockback_change);
char* pChoices[2] = { DLANG(HOST_SETTINGS, CLASSIC_PVP), DLANG(HOST_SETTINGS, REVAMPED_PVP) };
djui_selectionbox_create(body, DLANG(HOST_SETTINGS, PVP_MODE), pChoices, 2, &configPvpMode, NULL);
char* lChoices[3] = { DLANG(HOST_SETTINGS, LEAVE_LEVEL), DLANG(HOST_SETTINGS, STAY_IN_LEVEL), DLANG(HOST_SETTINGS, NONSTOP) }; char* lChoices[3] = { DLANG(HOST_SETTINGS, LEAVE_LEVEL), DLANG(HOST_SETTINGS, STAY_IN_LEVEL), DLANG(HOST_SETTINGS, NONSTOP) };
djui_selectionbox_create(body, DLANG(HOST_SETTINGS, ON_STAR_COLLECTION), lChoices, 3, &configStayInLevelAfterStar, NULL); djui_selectionbox_create(body, DLANG(HOST_SETTINGS, ON_STAR_COLLECTION), lChoices, 3, &configStayInLevelAfterStar, NULL);

View file

@ -1156,7 +1156,7 @@ static struct LuaObjectField sMarioStateFields[LUA_MARIO_STATE_FIELD_COUNT] = {
{ "interactObj", LVT_COBJECT_P, offsetof(struct MarioState, interactObj), false, LOT_OBJECT }, { "interactObj", LVT_COBJECT_P, offsetof(struct MarioState, interactObj), false, LOT_OBJECT },
{ "invincTimer", LVT_S16, offsetof(struct MarioState, invincTimer), false, LOT_NONE }, { "invincTimer", LVT_S16, offsetof(struct MarioState, invincTimer), false, LOT_NONE },
{ "isSnoring", LVT_U8, offsetof(struct MarioState, isSnoring), false, LOT_NONE }, { "isSnoring", LVT_U8, offsetof(struct MarioState, isSnoring), false, LOT_NONE },
{ "knockbackTimer", LVT_U8, offsetof(struct MarioState, knockbackTimer), false, LOT_NONE }, { "knockbackTimer", LVT_S8, offsetof(struct MarioState, knockbackTimer), false, LOT_NONE },
{ "marioBodyState", LVT_COBJECT_P, offsetof(struct MarioState, marioBodyState), true, LOT_MARIOBODYSTATE }, { "marioBodyState", LVT_COBJECT_P, offsetof(struct MarioState, marioBodyState), true, LOT_MARIOBODYSTATE },
{ "marioObj", LVT_COBJECT_P, offsetof(struct MarioState, marioObj), true, LOT_OBJECT }, { "marioObj", LVT_COBJECT_P, offsetof(struct MarioState, marioObj), true, LOT_OBJECT },
{ "minimumBoneY", LVT_F32, offsetof(struct MarioState, minimumBoneY), false, LOT_NONE }, { "minimumBoneY", LVT_F32, offsetof(struct MarioState, minimumBoneY), false, LOT_NONE },
@ -2227,7 +2227,7 @@ static struct LuaObjectField sRayIntersectionInfoFields[LUA_RAY_INTERSECTION_INF
{ "surface", LVT_COBJECT_P, offsetof(struct RayIntersectionInfo, surface), false, LOT_SURFACE }, { "surface", LVT_COBJECT_P, offsetof(struct RayIntersectionInfo, surface), false, LOT_SURFACE },
}; };
#define LUA_SERVER_SETTINGS_FIELD_COUNT 12 #define LUA_SERVER_SETTINGS_FIELD_COUNT 13
static struct LuaObjectField sServerSettingsFields[LUA_SERVER_SETTINGS_FIELD_COUNT] = { static struct LuaObjectField sServerSettingsFields[LUA_SERVER_SETTINGS_FIELD_COUNT] = {
{ "bouncyLevelBounds", LVT_S32, offsetof(struct ServerSettings, bouncyLevelBounds), false, LOT_NONE }, { "bouncyLevelBounds", LVT_S32, offsetof(struct ServerSettings, bouncyLevelBounds), false, LOT_NONE },
{ "bubbleDeath", LVT_U8, offsetof(struct ServerSettings, bubbleDeath), false, LOT_NONE }, { "bubbleDeath", LVT_U8, offsetof(struct ServerSettings, bubbleDeath), false, LOT_NONE },
@ -2239,6 +2239,7 @@ static struct LuaObjectField sServerSettingsFields[LUA_SERVER_SETTINGS_FIELD_COU
{ "pauseAnywhere", LVT_U8, offsetof(struct ServerSettings, pauseAnywhere), false, LOT_NONE }, { "pauseAnywhere", LVT_U8, offsetof(struct ServerSettings, pauseAnywhere), false, LOT_NONE },
{ "playerInteractions", LVT_S32, offsetof(struct ServerSettings, playerInteractions), false, LOT_NONE }, { "playerInteractions", LVT_S32, offsetof(struct ServerSettings, playerInteractions), false, LOT_NONE },
{ "playerKnockbackStrength", LVT_U8, offsetof(struct ServerSettings, playerKnockbackStrength), false, LOT_NONE }, { "playerKnockbackStrength", LVT_U8, offsetof(struct ServerSettings, playerKnockbackStrength), false, LOT_NONE },
{ "pvpType", LVT_S32, offsetof(struct ServerSettings, pvpType), false, LOT_NONE },
{ "skipIntro", LVT_U8, offsetof(struct ServerSettings, skipIntro), false, LOT_NONE }, { "skipIntro", LVT_U8, offsetof(struct ServerSettings, skipIntro), false, LOT_NONE },
{ "stayInLevelAfterStar", LVT_U8, offsetof(struct ServerSettings, stayInLevelAfterStar), false, LOT_NONE }, { "stayInLevelAfterStar", LVT_U8, offsetof(struct ServerSettings, stayInLevelAfterStar), false, LOT_NONE },
}; };

View file

@ -1445,6 +1445,9 @@ char gSmluaConstants[] = ""
"ATTACK_GROUND_POUND_OR_TWIRL = 4\n" "ATTACK_GROUND_POUND_OR_TWIRL = 4\n"
"ATTACK_FAST_ATTACK = 5\n" "ATTACK_FAST_ATTACK = 5\n"
"ATTACK_FROM_BELOW = 6\n" "ATTACK_FROM_BELOW = 6\n"
"PVP_ATTACK_KNOCKBACK_TIMER_DEFAULT = 10\n"
"PVP_ATTACK_KNOCKBACK_TIMER_OVERRIDE = -5\n"
"PVP_ATTACK_OVERRIDE_VANILLA_INVINCIBILITY = 0x0000FFFF\n"
"INT_STATUS_ATTACK_MASK = 0x000000FF\n" "INT_STATUS_ATTACK_MASK = 0x000000FF\n"
"INT_STATUS_HOOT_GRABBED_BY_MARIO = (1 << 0)\n" "INT_STATUS_HOOT_GRABBED_BY_MARIO = (1 << 0)\n"
"INT_STATUS_MARIO_UNK1 = (1 << 1)\n" "INT_STATUS_MARIO_UNK1 = (1 << 1)\n"
@ -2035,6 +2038,8 @@ char gSmluaConstants[] = ""
"BOUNCY_LEVEL_BOUNDS_OFF = 0\n" "BOUNCY_LEVEL_BOUNDS_OFF = 0\n"
"BOUNCY_LEVEL_BOUNDS_ON = 1\n" "BOUNCY_LEVEL_BOUNDS_ON = 1\n"
"BOUNCY_LEVEL_BOUNDS_ON_CAP = 2\n" "BOUNCY_LEVEL_BOUNDS_ON_CAP = 2\n"
"PLAYER_PVP_CLASSIC = 0\n"
"PLAYER_PVP_REVAMPED = 1\n"
"UNKNOWN_LOCAL_INDEX = (-1)\n" "UNKNOWN_LOCAL_INDEX = (-1)\n"
"UNKNOWN_GLOBAL_INDEX = (-1)\n" "UNKNOWN_GLOBAL_INDEX = (-1)\n"
"UNKNOWN_NETWORK_INDEX = (-1)\n" "UNKNOWN_NETWORK_INDEX = (-1)\n"

View file

@ -84,6 +84,7 @@ struct ServerSettings gServerSettings = {
.nametags = TRUE, .nametags = TRUE,
.maxPlayers = MAX_PLAYERS, .maxPlayers = MAX_PLAYERS,
.pauseAnywhere = FALSE, .pauseAnywhere = FALSE,
.pvpType = PLAYER_PVP_CLASSIC,
}; };
struct NametagsSettings gNametagsSettings = { struct NametagsSettings gNametagsSettings = {
@ -130,6 +131,7 @@ bool network_init(enum NetworkType inNetworkType, bool reconnecting) {
gServerSettings.nametags = configNametags; gServerSettings.nametags = configNametags;
gServerSettings.maxPlayers = configAmountofPlayers; gServerSettings.maxPlayers = configAmountofPlayers;
gServerSettings.pauseAnywhere = configPauseAnywhere; gServerSettings.pauseAnywhere = configPauseAnywhere;
gServerSettings.pvpType = configPvpMode;
#if defined(RAPI_DUMMY) || defined(WAPI_DUMMY) #if defined(RAPI_DUMMY) || defined(WAPI_DUMMY)
gServerSettings.headlessServer = (inNetworkType == NT_SERVER); gServerSettings.headlessServer = (inNetworkType == NT_SERVER);
#else #else

View file

@ -69,9 +69,15 @@ enum BouncyLevelBounds {
BOUNCY_LEVEL_BOUNDS_ON_CAP, BOUNCY_LEVEL_BOUNDS_ON_CAP,
}; };
enum PvpType {
PLAYER_PVP_CLASSIC,
PLAYER_PVP_REVAMPED
};
struct ServerSettings { struct ServerSettings {
enum PlayerInteractions playerInteractions; enum PlayerInteractions playerInteractions;
enum BouncyLevelBounds bouncyLevelBounds; enum BouncyLevelBounds bouncyLevelBounds;
enum PvpType pvpType;
u8 playerKnockbackStrength; u8 playerKnockbackStrength;
u8 stayInLevelAfterStar; u8 stayInLevelAfterStar;
u8 skipIntro; u8 skipIntro;