Bouncy Level Bounds server option

This commit is contained in:
Agent X 2023-11-13 08:27:20 -05:00
parent 8088736efc
commit b6d1a8a706
22 changed files with 183 additions and 71 deletions

View file

@ -198,6 +198,10 @@ SHARE_LIVES = "Sdílet životy"
ENABLE_CHEATS = "Zapnout cheaty"
BUBBLE_ON_DEATH = "Bublina při smrti"
NAMETAGS = "Nametags \\#ffff00\\(NOVÉ!)"
BOUNCY_BOUNDS_ON_CAP = "Zapnuto (Omezeno)"
BOUNCY_BOUNDS_ON = "Zapnuto"
BOUNCY_BOUNDS_OFF = "Vypnuto"
BOUNCY_LEVEL_BOUNDS = "Omezení odražejícího úrovně \\#ffff00\\(NOVÉ!)"
AMOUNT_OF_PLAYERS = "Počet hráčů"
[HOST]

View file

@ -198,6 +198,10 @@ SHARE_LIVES = "Levens delen"
ENABLE_CHEATS = "Cheats aan zetten"
BUBBLE_ON_DEATH = "Bubbelen op dood"
NAMETAGS = "Nametags \\#ffff00\\(NIEUW!)"
BOUNCY_BOUNDS_ON_CAP = "Aan (Begrensd)"
BOUNCY_BOUNDS_ON = "Aan"
BOUNCY_BOUNDS_OFF = "Uit"
BOUNCY_LEVEL_BOUNDS = "Springende Niveau Grenzen \\#ffff00\\(NIEUW!)"
AMOUNT_OF_PLAYERS = "Hoeveelheid spelers"
[HOST]

View file

@ -198,6 +198,10 @@ SHARE_LIVES = "Share lives"
ENABLE_CHEATS = "Enable cheats"
BUBBLE_ON_DEATH = "Bubble on death"
NAMETAGS = "Nametags \\#ffff00\\(NEW!)"
BOUNCY_BOUNDS_ON_CAP = "On (Capped)"
BOUNCY_BOUNDS_ON = "On"
BOUNCY_BOUNDS_OFF = "Off"
BOUNCY_LEVEL_BOUNDS = "Bouncy Level Bounds \\#ffff00\\(NEW!)"
AMOUNT_OF_PLAYERS = "Amount of players"
[HOST]

View file

@ -198,6 +198,10 @@ SHARE_LIVES = "Partage de vies"
ENABLE_CHEATS = "Activer le mode triche"
BUBBLE_ON_DEATH = "Bulles (mort)"
NAMETAGS = "Étiquettes de nom \\#ffff00\\(NEW!)"
BOUNCY_BOUNDS_ON_CAP = "Allumé (Limité)"
BOUNCY_BOUNDS_ON = "Allumé"
BOUNCY_BOUNDS_OFF = "Éteint"
BOUNCY_LEVEL_BOUNDS = "Limites de Niveau Rebondissant \\#ffff00\\(NOUVEAU !)"
AMOUNT_OF_PLAYERS = "Nombre de joueurs"
[HOST]

View file

@ -198,6 +198,10 @@ SHARE_LIVES = "Leben teilen"
ENABLE_CHEATS = "Cheats aktivieren"
BUBBLE_ON_DEATH = "Beim Tod in Blase"
NAMETAGS = "Nametags \\#ffff00\\(NEU!)"
BOUNCY_BOUNDS_ON_CAP = "An (Gedrosselt)"
BOUNCY_BOUNDS_ON = "An"
BOUNCY_BOUNDS_OFF = "Aus"
BOUNCY_LEVEL_BOUNDS = "Elastische Levelgrenzen \\#ffff00\\(NEU!)"
AMOUNT_OF_PLAYERS = "Spieleranzahl"
[HOST]

View file

@ -196,6 +196,10 @@ SHARE_LIVES = "Condividi le vite"
ENABLE_CHEATS = "Abilita i trucchi"
BUBBLE_ON_DEATH = "Bolla alla morte"
NAMETAGS = "Nametags \\#ffff00\\(NUOVO!)"
BOUNCY_BOUNDS_ON_CAP = "Acceso (Limitato)"
BOUNCY_BOUNDS_ON = "Acceso"
BOUNCY_BOUNDS_OFF = "Spento"
BOUNCY_LEVEL_BOUNDS = "Limiti Livello Rimbalzante \\#ffff00\\(NUOVO!)"
AMOUNT_OF_PLAYERS = "Numero di giocatori"
[HOST]

View file

@ -198,6 +198,10 @@ SHARE_LIVES = "Dividir vidas"
ENABLE_CHEATS = "Ativar cheats"
BUBBLE_ON_DEATH = "Bolha após a morte"
NAMETAGS = "Etiquetas de nome \\#ffff00\\(NOVO!)"
BOUNCY_BOUNDS_ON_CAP = "Ligado (Limitado)"
BOUNCY_BOUNDS_ON = "Ligado"
BOUNCY_BOUNDS_OFF = "Desligado"
BOUNCY_LEVEL_BOUNDS = "Limites de Nível Saltitante \\#ffff00\\(NOVO!)"
AMOUNT_OF_PLAYERS = "Quantidade de jogadores"
[HOST]

View file

@ -197,6 +197,10 @@ SHARE_LIVES = "Делитесь жизнями"
ENABLE_CHEATS = "Включить читы"
BUBBLE_ON_DEATH = "Пузырик при смерти"
NAMETAGS = "Этикетки \\#ffff00\\(НОВОЕ!)"
BOUNCY_BOUNDS_ON_CAP = "Вкл. (Ограничено)"
BOUNCY_BOUNDS_ON = "Вкл"
BOUNCY_BOUNDS_OFF = "Выкл"
BOUNCY_LEVEL_BOUNDS = "Пределы упругого уровня \\#ffff00\\(НОВОЕ!)"
AMOUNT_OF_PLAYERS = "Количество игроков"
[HOST]

View file

@ -198,6 +198,10 @@ SHARE_LIVES = "Compartir vidas"
ENABLE_CHEATS = "Habilitar trucos"
BUBBLE_ON_DEATH = "Burbuja al morir"
NAMETAGS = "Etiquetas de nombre \\#ffff00\\(NUEVO!)"
BOUNCY_BOUNDS_ON_CAP = "Encendido (Limitado)"
BOUNCY_BOUNDS_ON = "Encendido"
BOUNCY_BOUNDS_OFF = "Apagado"
BOUNCY_LEVEL_BOUNDS = "Límites de Nivel Rebote \\#ffff00\\(¡NUEVO!)"
AMOUNT_OF_PLAYERS = "Número de jugadores"
[HOST]

View file

@ -198,6 +198,10 @@ SHARE_LIVES = "Compartir vidas"
ENABLE_CHEATS = "Habilitar trucos"
BUBBLE_ON_DEATH = "Burbuja al morir"
NAMETAGS = "Etiquetas de nombre \\#ffff00\\ (NUEVO!)"
BOUNCY_BOUNDS_ON_CAP = "Encendido (Limitado)"
BOUNCY_BOUNDS_ON = "Encendido"
BOUNCY_BOUNDS_OFF = "Apagado"
BOUNCY_LEVEL_BOUNDS = "Límites de Nivel Rebote \\#ffff00\\(¡NUEVO!)"
AMOUNT_OF_PLAYERS = "Número de jugadores"
[HOST]

View file

@ -630,7 +630,7 @@ void render_hud(void) {
create_dl_ortho_matrix();
#endif
bool showHud = (configHUD && !gDjuiInMainMenu && !gOverrideHideHud);
bool showHud = (!gDjuiInMainMenu && !gOverrideHideHud);
if (gCurrentArea != NULL && gCurrentArea->camera != NULL && gCurrentArea->camera->mode == CAMERA_MODE_INSIDE_CANNON) {
render_hud_cannon_reticle();

View file

@ -415,9 +415,11 @@ u32 common_air_action_step(struct MarioState *m, u32 landAction, s32 animation,
set_character_animation(m, animation);
if (m->forwardVel > 16.0f) {
if (m->wall == NULL && gServerSettings.bouncyLevelBounds == BOUNCY_LEVEL_BOUNDS_OFF) {
queue_rumble_data_mario(m, 5, 40);
mario_bonk_reflection(m, FALSE);
m->faceAngle[1] += 0x8000;
}
if (m->wall != NULL) {
set_mario_action(m, ACT_AIR_HIT_WALL, 0);
@ -435,6 +437,7 @@ u32 common_air_action_step(struct MarioState *m, u32 landAction, s32 animation,
// wall collision, or by rising into the top of a wall such
// that the final quarter step detects a ledge, but you are
// not able to ledge grab it.
if (gServerSettings.bouncyLevelBounds == BOUNCY_LEVEL_BOUNDS_OFF) {
if (m->forwardVel >= 38.0f) {
set_mario_particle_flags(m, PARTICLE_VERTICAL_STAR, FALSE);
set_mario_action(m, ACT_BACKWARD_AIR_KB, 0);
@ -445,6 +448,7 @@ u32 common_air_action_step(struct MarioState *m, u32 landAction, s32 animation,
return set_mario_action(m, ACT_SOFT_BONK, 0);
}
}
}
} else {
mario_set_forward_vel(m, 0.0f);
}
@ -807,6 +811,8 @@ s32 act_dive(struct MarioState *m) {
break;
case AIR_STEP_HIT_WALL:
if (m->wall == NULL && gServerSettings.bouncyLevelBounds != BOUNCY_LEVEL_BOUNDS_OFF) { break; }
mario_bonk_reflection(m, TRUE);
m->faceAngle[0] = 0;
@ -1182,6 +1188,8 @@ u32 common_air_knockback_step(struct MarioState *m, u32 landAction, u32 hardFall
break;
case AIR_STEP_HIT_WALL:
if (m->wall == NULL && gServerSettings.bouncyLevelBounds != BOUNCY_LEVEL_BOUNDS_OFF) { break; }
set_character_animation(m, CHAR_ANIM_BACKWARD_AIR_KB);
mario_bonk_reflection(m, FALSE);
@ -1439,6 +1447,7 @@ s32 act_forward_rollout(struct MarioState *m) {
break;
case AIR_STEP_HIT_WALL:
if (m->wall == NULL && gServerSettings.bouncyLevelBounds != BOUNCY_LEVEL_BOUNDS_OFF) { break; }
mario_set_forward_vel(m, 0.0f);
break;
@ -1481,6 +1490,7 @@ s32 act_backward_rollout(struct MarioState *m) {
break;
case AIR_STEP_HIT_WALL:
if (m->wall == NULL && gServerSettings.bouncyLevelBounds != BOUNCY_LEVEL_BOUNDS_OFF) { break; }
mario_set_forward_vel(m, 0.0f);
break;
@ -1515,6 +1525,8 @@ s32 act_butt_slide_air(struct MarioState *m) {
break;
case AIR_STEP_HIT_WALL:
if (m->wall == NULL && gServerSettings.bouncyLevelBounds != BOUNCY_LEVEL_BOUNDS_OFF) { break; }
if (m->vel[1] > 0.0f) {
m->vel[1] = 0.0f;
}
@ -1555,6 +1567,8 @@ s32 act_hold_butt_slide_air(struct MarioState *m) {
break;
case AIR_STEP_HIT_WALL:
if (m->wall == NULL && gServerSettings.bouncyLevelBounds != BOUNCY_LEVEL_BOUNDS_OFF) { break; }
if (m->vel[1] > 0.0f) {
m->vel[1] = 0.0f;
}
@ -1689,6 +1703,8 @@ s32 act_slide_kick(struct MarioState *m) {
break;
case AIR_STEP_HIT_WALL:
if (m->wall == NULL && gServerSettings.bouncyLevelBounds != BOUNCY_LEVEL_BOUNDS_OFF) { break; }
if (m->vel[1] > 0.0f) {
m->vel[1] = 0.0f;
}
@ -1735,6 +1751,7 @@ s32 act_jump_kick(struct MarioState *m) {
break;
case AIR_STEP_HIT_WALL:
if (m->wall == NULL && gServerSettings.bouncyLevelBounds != BOUNCY_LEVEL_BOUNDS_OFF) { break; }
mario_set_forward_vel(m, 0.0f);
break;
}

View file

@ -1437,6 +1437,8 @@ void common_slide_action(struct MarioState *m, u32 endAction, u32 airAction, s32
case GROUND_STEP_HIT_WALL:
if (!mario_floor_is_slippery(m)) {
if (m->wall == NULL && gServerSettings.bouncyLevelBounds != BOUNCY_LEVEL_BOUNDS_OFF) { break; }
#ifdef VERSION_JP
set_mario_particle_flags(m, PARTICLE_VERTICAL_STAR, FALSE);
#else
@ -1562,9 +1564,12 @@ s32 act_slide_kick_slide(struct MarioState *m) {
break;
case GROUND_STEP_HIT_WALL:
if (m->wall == NULL && gServerSettings.bouncyLevelBounds != BOUNCY_LEVEL_BOUNDS_OFF) { break; }
mario_bonk_reflection(m, TRUE);
set_mario_particle_flags(m, PARTICLE_VERTICAL_STAR, FALSE);
set_mario_action(m, ACT_BACKWARD_GROUND_KB, 0);
break;
}

View file

@ -11,6 +11,8 @@
#include "pc/lua/smlua.h"
#include "game/hardcoded.h"
#define CLAMP(_val, _min, _max) MAX(MIN((_val), _max), _min)
static s16 sMovingSandSpeeds[] = { 12, 8, 4, 0 };
struct Surface gWaterSurfacePseudoFloor = {
@ -294,7 +296,10 @@ static s32 perform_ground_quarter_step(struct MarioState *m, Vec3f nextPos) {
mario_update_wall(m, &upperWcd);
if (floor == NULL) {
//HOOK_ON_COLLIDE_LEVEL_BOUNDS, coopdx
if (gServerSettings.bouncyLevelBounds != BOUNCY_LEVEL_BOUNDS_OFF) {
m->faceAngle[1] += 0x8000;
mario_set_forward_vel(m, gServerSettings.bouncyLevelBounds == BOUNCY_LEVEL_BOUNDS_ON_CAP ? CLAMP(1.5f * m->forwardVel, -500, 500) : 1.5f * m->forwardVel);
}
smlua_call_event_hooks_mario_param(HOOK_ON_COLLIDE_LEVEL_BOUNDS, m);
return GROUND_STEP_HIT_WALL_STOP_QSTEPS;
}
@ -470,7 +475,10 @@ s32 perform_air_quarter_step(struct MarioState *m, Vec3f intendedPos, u32 stepAr
}
m->pos[1] = nextPos[1];
//HOOK_ON_COLLIDE_LEVEL_BOUNDS, coopdx
if (gServerSettings.bouncyLevelBounds != BOUNCY_LEVEL_BOUNDS_OFF) {
m->faceAngle[1] += 0x8000;
mario_set_forward_vel(m, gServerSettings.bouncyLevelBounds == BOUNCY_LEVEL_BOUNDS_ON_CAP ? CLAMP(1.5f * m->forwardVel, -500, 500) : 1.5f * m->forwardVel);
}
smlua_call_event_hooks_mario_param(HOOK_ON_COLLIDE_LEVEL_BOUNDS, m);
return AIR_STEP_HIT_WALL;
}

View file

@ -114,11 +114,10 @@ bool configCameraInvertY = true;
bool configEnableCamera = false;
bool configCameraAnalog = false;
bool configCameraMouse = false;
// coop-specific
bool configSkipIntro = 0;
bool configBubbleDeath = true;
unsigned int configAmountofPlayers = 16;
bool configHUD = true;
// coop-specific
char configJoinIp[MAX_CONFIG_STRING] = "";
unsigned int configJoinPort = DEFAULT_PORT;
unsigned int configHostPort = DEFAULT_PORT;
@ -126,6 +125,8 @@ unsigned int configHostSaveSlot = 1;
unsigned int configPlayerInteraction = 1;
unsigned int configPlayerKnockbackStrength = 25;
unsigned int configStayInLevelAfterStar = 0;
bool configNametags = true;
unsigned int configBouncyLevelBounds = 0;
unsigned int configNetworkSystem = 0;
char configPlayerName[MAX_PLAYER_STRING] = "";
unsigned int configPlayerModel = 0;
@ -148,7 +149,6 @@ unsigned int configInterpolationMode = 1;
unsigned int configGamepadNumber = 0;
bool configBackgroundGamepad = 1;
bool configSingleplayerPause = 0;
bool configNametags = true;
bool configDebugPrint = 0;
bool configDebugInfo = 0;
bool configDebugError = 0;
@ -229,6 +229,8 @@ static const struct ConfigOption options[] = {
{.name = "coop_network_system", .type = CONFIG_TYPE_UINT , .uintValue = &configNetworkSystem},
{.name = "coop_player_interaction", .type = CONFIG_TYPE_UINT , .uintValue = &configPlayerInteraction},
{.name = "coop_player_knockback_strength", .type = CONFIG_TYPE_UINT , .uintValue = &configPlayerKnockbackStrength},
{.name = "coopdx_nametags", .type = CONFIG_TYPE_BOOL , .boolValue = &configNametags},
{.name = "coopdx_bouncy_bounds", .type = CONFIG_TYPE_UINT , .uintValue = &configBouncyLevelBounds},
{.name = "coop_player_model", .type = CONFIG_TYPE_UINT , .uintValue = &configPlayerModel},
{.name = "coop_player_name", .type = CONFIG_TYPE_STRING, .stringValue = (char*)&configPlayerName, .maxStringLength = MAX_PLAYER_STRING},
{.name = "coop_menu_level", .type = CONFIG_TYPE_UINT , .uintValue = &configMenuLevel},
@ -252,7 +254,6 @@ static const struct ConfigOption options[] = {
{.name = "coop_stay_in_level_after_star", .type = CONFIG_TYPE_UINT , .uintValue = &configStayInLevelAfterStar},
{.name = "coop_singleplayer_pause", .type = CONFIG_TYPE_BOOL , .boolValue = &configSingleplayerPause},
{.name = "coop_compatibility", .type = CONFIG_TYPE_BOOL, .boolValue = &configCoopCompatibility},
{.name = "coopdx_nametags", .type = CONFIG_TYPE_BOOL , .boolValue = &configNametags},
{.name = "disable_popups", .type = CONFIG_TYPE_BOOL , .boolValue = &configDisablePopups},
#if defined(DEVELOPMENT)
{.name = "lua_profiler", .type = CONFIG_TYPE_BOOL , .boolValue = &configLuaProfiler},

View file

@ -74,7 +74,6 @@ extern bool configCameraInvertY;
extern bool configEnableCamera;
extern bool configCameraMouse;
extern bool configCameraAnalog;
extern bool configHUD;
extern bool configSkipIntro;
extern bool configBubbleDeath;
extern unsigned int configAmountofPlayers;
@ -85,6 +84,8 @@ extern unsigned int configHostSaveSlot;
extern unsigned int configPlayerInteraction;
extern unsigned int configPlayerKnockbackStrength;
extern unsigned int configStayInLevelAfterStar;
extern bool configNametags;
extern unsigned int configBouncyLevelBounds;
extern unsigned int configNetworkSystem;
extern char configPlayerName[];
extern unsigned int configPlayerModel;
@ -105,7 +106,6 @@ extern bool configCtxProfiler;
extern bool configDisableDownloadedModels;
extern unsigned int configInterpolationMode;
extern bool configSingleplayerPause;
extern bool configNametags;
extern bool configDebugPrint;
extern bool configDebugInfo;
extern bool configDebugError;

View file

@ -61,7 +61,12 @@ void djui_panel_host_settings_create(struct DjuiBase* caller) {
djui_checkbox_create(body, DLANG(HOST_SETTINGS, SKIP_INTRO_CUTSCENE), &configSkipIntro, NULL);
djui_checkbox_create(body, DLANG(HOST_SETTINGS, BUBBLE_ON_DEATH), &configBubbleDeath, NULL);
if (!gCoopCompatibility) djui_checkbox_create(body, DLANG(HOST_SETTINGS, NAMETAGS), &configNametags, NULL);
struct DjuiCheckbox* checkbox = djui_checkbox_create(body, DLANG(HOST_SETTINGS, NAMETAGS), &configNametags, NULL);
djui_base_set_enabled(&checkbox->base, !gCoopCompatibility);
char* bChoices[3] = { DLANG(HOST_SETTINGS, BOUNCY_BOUNDS_OFF), DLANG(HOST_SETTINGS, BOUNCY_BOUNDS_ON), DLANG(HOST_SETTINGS, BOUNCY_BOUNDS_ON_CAP) };
struct DjuiSelectionbox* selectionbox = djui_selectionbox_create(body, DLANG(HOST_SETTINGS, BOUNCY_LEVEL_BOUNDS), bChoices, 3, &configBouncyLevelBounds, NULL);
djui_base_set_enabled(&selectionbox->base, !gCoopCompatibility);
struct DjuiRect* rect1 = djui_rect_container_create(body, 32);
{

View file

@ -19,7 +19,7 @@ issues sm64ex-coop development has.\n\
Coop Deluxe Team:\n\
Agent X: Creator\n\
AngelicMiracles: Co-Creator\n\
eros71: Testing And Fixing\n\
eros71: Tester & Developer\n\
FluffaMario: Model Designer\n\
\n\
Contributors:\n\

View file

@ -69,6 +69,7 @@ enum NetworkSystemType sNetworkReconnectType = NS_SOCKET;
struct ServerSettings gServerSettings = {
.playerInteractions = PLAYER_INTERACTIONS_SOLID,
.bouncyLevelBounds = BOUNCY_LEVEL_BOUNDS_OFF,
.playerKnockbackStrength = 25,
.skipIntro = FALSE,
.enableCheats = FALSE,
@ -114,6 +115,7 @@ bool network_init(enum NetworkType inNetworkType, bool reconnecting) {
// set server settings
gServerSettings.playerInteractions = configPlayerInteraction;
gServerSettings.bouncyLevelBounds = configBouncyLevelBounds;
gServerSettings.playerKnockbackStrength = configPlayerKnockbackStrength;
gServerSettings.stayInLevelAfterStar = configStayInLevelAfterStar;
gServerSettings.skipIntro = configSkipIntro;

View file

@ -63,8 +63,15 @@ enum PlayerInteractions {
PLAYER_INTERACTIONS_PVP,
};
enum BouncyLevelBounds {
BOUNCY_LEVEL_BOUNDS_OFF,
BOUNCY_LEVEL_BOUNDS_ON,
BOUNCY_LEVEL_BOUNDS_ON_CAP,
};
struct ServerSettings {
enum PlayerInteractions playerInteractions;
enum BouncyLevelBounds bouncyLevelBounds;
u8 playerKnockbackStrength;
u8 stayInLevelAfterStar;
u8 skipIntro;

View file

@ -112,6 +112,7 @@ void network_send_join(struct Packet* joinRequestPacket) {
packet_write(&p, &globalIndex, sizeof(u8));
packet_write(&p, &gCurrSaveFileNum, sizeof(s16));
packet_write(&p, &gServerSettings.playerInteractions, sizeof(u8));
if (!gCoopCompatibility) { packet_write(&p, &gServerSettings.bouncyLevelBounds, sizeof(u8)); }
packet_write(&p, &gServerSettings.playerKnockbackStrength, sizeof(u8));
packet_write(&p, &gServerSettings.stayInLevelAfterStar, sizeof(u8));
packet_write(&p, &gServerSettings.skipIntro, sizeof(u8));
@ -163,6 +164,7 @@ void network_receive_join(struct Packet* p) {
packet_read(p, &myGlobalIndex, sizeof(u8));
packet_read(p, &gCurrSaveFileNum, sizeof(s16));
packet_read(p, &gServerSettings.playerInteractions, sizeof(u8));
if (!gCoopCompatibility) { packet_read(p, &gServerSettings.bouncyLevelBounds, sizeof(u8)); }
packet_read(p, &gServerSettings.playerKnockbackStrength, sizeof(u8));
packet_read(p, &gServerSettings.stayInLevelAfterStar, sizeof(u8));
packet_read(p, &gServerSettings.skipIntro, sizeof(u8));

25
tools/append_lang_keys.py Normal file
View file

@ -0,0 +1,25 @@
import os
import sys
# I can't stand it anymore, editing like 9 different INI files and finding the right spot just to add 1 line and also translating them all at the same time too, I'm making a script for this!
def add_new_key(ini_path, section, search_key, new_key):
new_value = input(f"{new_key} for {os.path.basename(ini_path)}: ")
current_section = ""
out = []
with open(ini_path, "r", encoding="utf-8") as f:
lines = f.readlines()
for line in lines:
if line.startswith("["):
current_section = line.replace("[", "").replace("]", "").replace("\n", "")
elif line.startswith(search_key) and current_section == section:
line += f'{new_key} = "{new_value}"\n'
out.append(line)
with open(ini_path, "w", encoding="utf-8") as f:
f.writelines(out)
for file in os.listdir("./lang/"):
if file.endswith(".ini"):
add_new_key("./lang/" + file, sys.argv[1], sys.argv[2], sys.argv[3])