[ChatUpdate-v3] Added SentChatMessage-History & Added Chat-Tab-Completion for Commands,Subcommands,Playernames & Added 2 new Start-Parameters (#482)

Added SentChatMessages-History (including navigation)
    Added Tab-Completion for Main-Commands
    Added Tab-Completion for Sub-Commands
    Added Tab-Completion for Player-Names [Now finally fixed and working correctly]
    Improved some english translations
    Improved a lot of german translations
    Fixed a few bugs and bad code regarding "default commands"
    Development started on a new chat command handling system (Not in use yet)
    Fixed some stuff previously noted/criticized by other developers in a previous the code review
    Added new Start-Parameter "--playername PLAYERNAME"
    Added new Start-Parameter "--randomplayername"
This commit is contained in:
iZePlayzYT 2023-11-05 05:05:34 +01:00 committed by GitHub
parent 8d4f657930
commit 23903cd5fc
18 changed files with 1679 additions and 189 deletions

View File

@ -4,24 +4,24 @@ DISCONNECTED = "@ disconnected"
LEFT_THIS_LEVEL = "@ left this level"
ENTERED_THIS_LEVEL = "@ entered this level"
ENTERED = "@ entered\n#"
SERVER_CLOSED = "\\#ffa0a0\\Disconnected:\\#dcdcdc\\ server closed"
SERVER_CLOSED = "\\#ffa0a0\\Disconnected:\\#dcdcdc\\ Server closed"
DISCORD_ERROR = "Discord threw an error.\nTo fix, try: \n1. Close the game.\n2. Restart Discord.\n3. Start the game."
DISCORD_DETECT = "\\#ffa0a0\\Error:\\#c8c8c8\\ Could not detect Discord.\n\\#a0a0a0\\Try closing the game, restarting Discord, and opening the game again."
DISCONNECT_FULL = "\\#ffa0a0\\Disconnected:\\#c8c8c8\\ The party is full."
DISCONNECT_KICK = "\\#ffa0a0\\Disconnected:\\#c8c8c8\\ The server kicked you."
DISCONNECT_BAN = "\\#ffa0a0\\Disconnected:\\#c8c8c8\\ The server banned you."
DISCONNECT_REJOIN = "\\#ffa0a0\\Disconnected:\\#c8c8c8\\ Rejoining..."
DISCONNECT_CLOSED = "\\#ffa0a0\\Disconnected:\\#c8c8c8\\ Host has closed the connection."
DISCONNECT_CLOSED = "\\#ffa0a0\\Disconnected:\\#c8c8c8\\ Host closed the connection."
DISCONNECT_BIG_MOD = "Server had too large of a mod.\nQuitting."
DIED = "@ died"
DEBUG_FLY = "@ entered the debug free fly state"
DEBUG_FLY = "@ entered debug free-fly mode"
IMPORT_MOD_SUCCESS = "\\#a0ffa0\\Imported mod\n\\#c8c8c8\\'@'"
IMPORT_DYNOS_SUCCESS = "\\#a0ffa0\\Imported DynOS pack\n\\#c8c8c8\\'@'"
IMPORT_FAIL = "\\#ffa0a0\\Failed to import\n\\#c8c8c8\\'@'"
IMPORT_FAIL_INGAME = "\\#ffa0a0\\Can not import while in-game"
COOPNET_CONNECTION_FAILED = "\\#ffa0a0\\Could not connect to CoopNet!"
COOPNET_DISCONNECTED = "\\#ffa0a0\\Lost connection to CoopNet!"
LOBBY_NOT_FOUND = "\\#ffa0a0\\The lobby no longer exists!"
LOBBY_NOT_FOUND = "\\#ffa0a0\\Error:\\#c8c8c8\\ Lobby no longer exists!"
LOBBY_JOIN_FULL = "\\#ffa0a0\\The lobby is full!"
LOBBY_JOIN_FAILED = "\\#ffa0a0\\Failed to join the lobby!"
LOBBY_PASSWORD_INCORRECT = "\\#ffa0a0\\Entered the wrong lobby password!"
@ -96,10 +96,10 @@ RUMBLE_STRENGTH = "Rumble Strength"
CHAT = "Chat"
PLAYERS = "Players"
D_UP = "D Up"
D_DOWN = "D Down"
D_LEFT = "D Left"
D_RIGHT = "D Right"
D_UP = "D-Up"
D_DOWN = "D-Down"
D_LEFT = "D-Left"
D_RIGHT = "D-Right"
X = "X"
Y = "Y"
CONSOLE = "Console"
@ -116,10 +116,10 @@ START = "Start"
L = "L"
R = "R"
Z = "Z"
C_UP = "C Up"
C_DOWN = "C Down"
C_LEFT = "C Left"
C_RIGHT = "C Right"
C_UP = "C-Up"
C_DOWN = "C-Down"
C_LEFT = "C-Left"
C_RIGHT = "C-Right"
[DISPLAY]
DISPLAY = "DISPLAY"
@ -146,7 +146,7 @@ DRAW_DISTANCE = "Draw Distance"
DYNOS_PACKS = "DynOS Packs"
ANTIALIASING = "Anti-aliasing"
OFF = "Off"
MUST_RESTART = "You must restart the game for some changes to take effect."
MUST_RESTART = "Restart the game to apply some changes."
[DYNOS]
DYNOS = "DYNOS"

View File

@ -1,58 +1,58 @@
[NOTIF]
CONNECTED = "@ hat sich mit dem server verbunden"
DISCONNECTED = "@ hat sich vom server getrennt"
LEFT_THIS_LEVEL = "@ hat diesen level verlassen"
ENTERED_THIS_LEVEL = "@ ist diesem level beigetreten"
ENTERED = "@ ist beigetreten bei\n#"
SERVER_CLOSED = "\\#ffa0a0\\Verbindung getrennt:\\#dcdcdc\\ Server wurde geschlossen"
DISCORD_ERROR = "Discord warf einen fehler.\nUm dies zu vermeiden, versuche: \n1. das Spiel zu schließen.\n2. Discord neuzustarten.\n3. das Spiel wieder zu starten."
DISCORD_DETECT = "\\#ffa0a0\\Fehlermeldung:\\#c8c8c8\\ Konnte Discord nicht finden.\n\\#a0a0a0\\Versuche das Spiel zu schließen, Discord neuzustarten, und dann das Spiel anschließlich wieder zu starten."
DISCONNECT_FULL = "\\#ffa0a0\\Verbindung getrennt:\\#c8c8c8\\ Die Gruppe ist vollzählig."
DISCONNECT_KICK = "\\#ffa0a0\\Verbindung getrennt:\\#c8c8c8\\ Du wurdest vom Server rausgeschmissen."
CONNECTED = "@ hat sich mit dem Server verbunden."
DISCONNECTED = "@ hat die Verbindung zum Server getrennt."
LEFT_THIS_LEVEL = "@ hat dieses Level verlassen."
ENTERED_THIS_LEVEL = "@ ist diesem Level beigetreten."
ENTERED = "@ ist beigetreten zu\n#"
SERVER_CLOSED = "\\#ffa0a0\\Verbindung getrennt:\\#dcdcdc\\ Server wurde geschlossen."
DISCORD_ERROR = "Discord hat einen Fehler verursacht.\nUm dies zu vermeiden, versuche: \n1. das Spiel zu schließen.\n2. Discord neu zu starten.\n3. das Spiel erneut zu starten."
DISCORD_DETECT = "\\#ffa0a0\\Fehlermeldung:\\#c8c8c8\\ Discord konnte nicht gefunden werden.\n\\#a0a0a0\\Versuche, das Spiel zu schließen, Discord neu zu starten und dann das Spiel anschließend wieder zu öffnen."
DISCONNECT_FULL = "\\#ffa0a0\\Verbindung getrennt:\\#c8c8c8\\ Die Gruppe ist voll."
DISCONNECT_KICK = "\\#ffa0a0\\Verbindung getrennt:\\#c8c8c8\\ Du wurdest vom Server geworfen."
DISCONNECT_BAN = "\\#ffa0a0\\Verbindung getrennt:\\#c8c8c8\\ Du wurdest vom Server gebannt."
DISCONNECT_REJOIN = "\\#ffa0a0\\Verbindung getrennt:\\#c8c8c8\\ Verbinde erneut..."
DISCONNECT_REJOIN = "\\#ffa0a0\\Verbindung getrennt:\\#c8c8c8\\ Erneut verbinden..."
DISCONNECT_CLOSED = "\\#ffa0a0\\Verbindung getrennt:\\#c8c8c8\\ Der Servereigentümer hat die Verbindung geschlossen."
DISCONNECT_BIG_MOD = "Der Server besaß eine modifikation, die zu Groß war.\nDie Verbindung wird geschlossen."
DIED = "@ starb"
DEBUG_FLY = "@ trat in den Debug-Free-Fly-Zustand ein"
IMPORT_MOD_SUCCESS = "\\#a0ffa0\\Importierter Mod\n\\#c8c8c8\\'@'"
IMPORT_DYNOS_SUCCESS = "\\#a0ffa0\\Importiertes DynOS-Paket\n\\#c8c8c8\\'@'"
IMPORT_FAIL = "\\#ffa0a0\\Fehler zum Importieren von\n\\#c8c8c8\\'@'"
IMPORT_FAIL_INGAME = "\\#ffa0a0\\Kann im Spiel nicht importieren"
COOPNET_CONNECTION_FAILED = "\\#ffa0a0\\Verbindung zu CoopNet gescheitert!"
DISCONNECT_BIG_MOD = "Der Server verwendet eine zu große Modifikation.\nDie Verbindung wird getrennt."
DIED = "@ ist gestorben."
DEBUG_FLY = "@ hat den Debug-Free-Fly-Modus aktiviert."
IMPORT_MOD_SUCCESS = "\\#a0ffa0\\Mod importiert\n\\#c8c8c8\\'@'"
IMPORT_DYNOS_SUCCESS = "\\#a0ffa0\\DynOS-Paket importiert\n\\#c8c8c8\\'@'"
IMPORT_FAIL = "\\#ffa0a0\\Import fehlgeschlagen für\n\\#c8c8c8\\'@'"
IMPORT_FAIL_INGAME = "\\#ffa0a0\\Kann nicht im Spiel importieren."
COOPNET_CONNECTION_FAILED = "\\#ffa0a0\\Verbindung zu CoopNet fehlgeschlagen!"
COOPNET_DISCONNECTED = "\\#ffa0a0\\Verbindung zu CoopNet verloren!"
LOBBY_NOT_FOUND = "\\#ffa0a0\\Diese Lobby existiert nicht mehr!"
LOBBY_JOIN_FULL = "\\#ffa0a0\\Diese Lobby ist vollzählig!"
LOBBY_JOIN_FAILED = "\\#ffa0a0\\Konnte nicht zum Lobby beitreten!"
LOBBY_PASSWORD_INCORRECT = "\\#ffa0a0\\Falsches Lobby Passwort!"
COOPNET_VERSION = "\\#ffa0a0\\Deine version ist nicht mehr Kompatibel mit CoopNet. Lade die neuste Version des Spiels herunter!"
PEER_FAILED = "\\#ffa0a0\\Konnte nicht mit dem Spieler '@' verbinden"
LOBBY_NOT_FOUND = "\\#ffa0a0\\Diese Lobby existiert nicht mehr."
LOBBY_JOIN_FULL = "\\#ffa0a0\\Diese Lobby ist voll."
LOBBY_JOIN_FAILED = "\\#ffa0a0\\Konnte der Lobby nicht beitreten!"
LOBBY_PASSWORD_INCORRECT = "\\#ffa0a0\\Falsches Lobby-Passwort!"
COOPNET_VERSION = "\\#ffa0a0\\Deine Version ist nicht kompatibel mit CoopNet. Bitte lade die neueste Version des Spiels herunter!"
PEER_FAILED = "\\#ffa0a0\\Konnte keine Verbindung zum Spieler '@' aufbauen."
UNKNOWN = "Unbekannt"
LOBBY_HOST = "Lobby veranstalter"
LOBBY_HOST = "Lobby-Hoster"
[CHAT]
KICKING = "'@' wird rausgeschmissen!"
KICKING = "'@' wird hinausgeworfen!"
BANNING = "'@' wird gebannt!"
SERVER_ONLY = "Nur der Server kann diesen Befehl verwenden."
SERVER_ONLY = "Nur der Server kann diesen Befehl ausführen."
PERM_BANNING = "'@' wird dauerhaft gebannt!"
ADD_MODERATOR = "'@' wird as Moderator hinzugefügt!"
ADD_MODERATOR = "'@' wird als Moderator hinzugefügt!"
PLAYERS = "Spieler"
NO_PERMS = "Du bist nicht berechtigt, diesen Befehl zu verwenden."
PLAYER_NOT_FOUND = "Konnte diesen Spieler nicht finden."
SELF_KICK = "Du kannst nicht dich selbst rausschmeißen."
SELF_BAN = "Du kannst nicht dich selbst bannen."
SELF_MOD = "Du kannst nicht dich selbst als Moderator hinzufügen."
KICK_CONFIRM = "Sind Sie sicher, dass Sie '@' vom Server rausschmeissen möchten?\nGeben Sie '\\#a0ffa0\\/bestätigung\\#fff982\\' ein, um rauszuschmeißen."
BAN_CONFIRM = "Sind Sie sicher, dass Sie '@' vom Server bannen möchten?\nGeben sie '\\#a0ffa0\\/bestätigung\\#fff982\\' ein, um zu bannen."
PERM_BAN_CONFIRM = "Sind Sie sicher, dass Sie '@' dauerhaft vom Server bannen möchten?\nGeben sie '\\#a0ffa0\\/bestätigung\\#fff982\\' ein, um zu bannen."
MOD_CONFIRM = "Sind Sie sicher, dass Sie '@' zu einem Moderator machen möchten?\nGeben sie '\\#a0ffa0\\/bestätigung\\#fff982\\' ein."
PLAYERS_DESC = "/players - Alle Spieler und ihre IDs aufzeigen"
KICK_DESC = "/kick [NAME|ID] - Diesen Spieler aus dem aktuellen Spiel rausschmeißen"
BAN_DESC = "/ban [NAME|ID] - Diesen Spieler aus dem aktuellen Spiel bannen"
PERM_BAN_DESC = "/permban [NAME|ID] - Diesen Spieler dauerhaft für alle Spiele bannen, die Sie veranstalten"
MOD_DESC = "/moderator [NAME|ID] - Erlaubt diesem Spieler befehle wie /kick, /ban, /permban für alle Spiele, die sie veranstalten, zu verwenden."
UNRECOGNIZED = "Unbekannter befehl."
MOD_GRANTED = "\\#fff982\\Du bist jetzt ein Moderator."
NO_PERMS = "Du hast keine Berechtigung, diesen Befehl auszuführen."
PLAYER_NOT_FOUND = "Spieler konnte nicht gefunden werden."
SELF_KICK = "Du kannst dich nicht selbst hinauswerfen."
SELF_BAN = "Du kannst dich nicht selbst bannen."
SELF_MOD = "Du kannst dich nicht selbst zum Moderator machen."
KICK_CONFIRM = "Bist du sicher, dass du '@' vom Server werfen möchtest?\nGib '\\#a0ffa0\\/bestätigen\\#fff982\\' ein, um fortzufahren."
BAN_CONFIRM = "Bist du sicher, dass du '@' vom Server bannen möchtest?\nGib '\\#a0ffa0\\/bestätigen\\#fff982\\' ein, um fortzufahren."
PERM_BAN_CONFIRM = "Bist du sicher, dass du '@' dauerhaft vom Server bannen möchtest?\nGib '\\#a0ffa0\\/bestätigen\\#fff982\\' ein, um fortzufahren."
MOD_CONFIRM = "Bist du sicher, dass du '@' zum Moderator ernennen möchtest?\nGib '\\#a0ffa0\\/bestätigen\\#fff982\\' ein."
PLAYERS_DESC = "/players - Zeige alle Spieler und ihre IDs."
KICK_DESC = "/kick [NAME|ID] - Einen Spieler aus dem aktuellen Spiel werfen."
BAN_DESC = "/ban [NAME|ID] - Einen Spieler aus dem aktuellen Spiel bannen."
PERM_BAN_DESC = "/permban [NAME|ID] - Einen Spieler dauerhaft für alle von dir gehosteten Spiele bannen."
MOD_DESC = "/moderator [NAME|ID] - Einem Spieler die Berechtigung für Befehle wie /kick, /ban, /permban in allen von dir gehosteten Spielen geben."
UNRECOGNIZED = "Unbekannter Befehl."
MOD_GRANTED = "\\#fff982\\Du bist jetzt Moderator."
[MENU]
BACK = "Zurück"
@ -63,43 +63,43 @@ YES = "Ja"
[CAMERA]
CAMERA = "KAMERA"
FREE_CAMERA = "Freie Kamera"
ANALOG_CAMERA = "Analog Kamera"
MOUSE_LOOK = "Maus-Sicht"
INVERT_X = "X umkehren"
INVERT_Y = "Y umkehren"
X_SENSITIVITY = "X Empfindlichkeit"
Y_SENSITIVITY = "Y Empfindlichkeit"
AGGRESSION = "Aggression"
PAN_LEVEL = "Pan-Level"
DECELERATION = "Verzögerung"
ANALOG_CAMERA = "Analoge Kamera"
MOUSE_LOOK = "Mausansicht"
INVERT_X = "X invertieren"
INVERT_Y = "Y invertieren"
X_SENSITIVITY = "X-Empfindlichkeit"
Y_SENSITIVITY = "Y-Empfindlichkeit"
AGGRESSION = "Aggressivität"
PAN_LEVEL = "Schwenk-Level"
DECELERATION = "Abbremsen"
[CHEATS]
CHEATS = "CHEATS"
MOON_JUMP = "Mond-Sprung"
GOD_MODE = "Gott Modus"
INFINITE_LIVES = "Unbegrenzte Leben"
SUPER_SPEED = "Supergeschwindigkeit"
RESPONSIVE_CONTROLS = "Reaktionsschnelle Steuerung"
MOON_JUMP = "Mondsprung"
GOD_MODE = "Gott-Modus"
INFINITE_LIVES = "Unendlich Leben"
SUPER_SPEED = "Übergeschwindigkeit"
RESPONSIVE_CONTROLS = "Reaktive Steuerung"
RAPID_FIRE = "Schnellfeuer (A)"
BLJ_ANYWHERE = "Überall Rückwertsweitspringen"
ALWAYS_TRIPLE_JUMP = "Immer Dreisprung"
BLJ_ANYWHERE = "Überall Rückwärts-Langsprung"
ALWAYS_TRIPLE_JUMP = "Ständiger Dreifachsprung"
[CONTROLS]
CONTROLS = "STEUERUNG"
N64_BINDS = "N64 Konfiguration"
EXTRA_BINDS = "Extra Konfiguration"
N64_BINDS = "N64-Einstellungen"
EXTRA_BINDS = "Zusätzliche Einstellungen"
BACKGROUND_GAMEPAD = "Hintergrund-Gamepad"
GAMEPAD = "Gamepad"
DEADZONE = "Deadzone"
RUMBLE_STRENGTH = "Rumble-Stärke"
DEADZONE = "Tote Zone"
RUMBLE_STRENGTH = "Vibration-Stärke"
CHAT = "Chat"
PLAYERS = "Spieler"
D_UP = "D Hoch"
D_DOWN = "D Unten"
D_LEFT = "D Links"
D_RIGHT = "D Rechts"
D_UP = "D-Hoch"
D_DOWN = "D-Unten"
D_LEFT = "D-Links"
D_RIGHT = "D-Rechts"
X = "X"
Y = "Y"
CONSOLE = "Konsole"
@ -116,133 +116,133 @@ START = "Start"
L = "L"
R = "R"
Z = "Z"
C_UP = "C Hoch"
C_DOWN = "C Unten"
C_LEFT = "C Links"
C_RIGHT = "C Rechts"
C_UP = "C-Hoch"
C_DOWN = "C-Unten"
C_LEFT = "C-Links"
C_RIGHT = "C-Rechts"
[DISPLAY]
DISPLAY = "DISPLAY"
DISPLAY = "ANZEIGE"
FULLSCREEN = "Vollbildmodus"
FORCE_4BY3 = "Gewalt 4:3"
FORCE_4BY3 = "Erzwinge 4:3"
PRELOAD_TEXTURES = "Texturen vorladen"
VSYNC = "VSync"
UNCAPPED_FRAMERATE = "Unbegrenzte Framerate"
FRAME_LIMIT = "Frame-Limit"
UNCAPPED_FRAMERATE = "Unbegrenzte Bildrate"
FRAME_LIMIT = "Bildrate-Limit"
FAST = "Schnell"
ACCURATE = "Genauigkeit"
ACCURATE = "Präzise"
INTERPOLATION = "Interpolation"
NEAREST = "Nah"
NEAREST = "Nächste"
LINEAR = "Linear"
TRIPOINT = "Tripoint"
FILTERING = "Filtering"
TRIPOINT = "Dreipunkt"
FILTERING = "Filterung"
D0P5X = "0.5x"
D1X = "1x"
D1P5X = "1.5x"
D3X = "3x"
D10X = "10x"
D100X = "100x"
DRAW_DISTANCE = "Sichtweite"
DYNOS_PACKS = "DynOS Packs"
ANTIALIASING = "Anti-aliasing"
DRAW_DISTANCE = "Zeichenentfernung"
DYNOS_PACKS = "DynOS-Pakete"
ANTIALIASING = "Kantenglättung"
OFF = "Aus"
MUST_RESTART = "Du musst das Spiel neu starten, damit einige Änderungen wirksam werden."
MUST_RESTART = "Um einige Änderungen zu übernehmen, muss das Spiel neugestartet werden."
[DYNOS]
DYNOS = "DYNOS"
[HOST_MESSAGE]
INFO_TITLE = "INFO"
WARN_DISCORD = "Lade Freunde ein, indem du auf Discord mit der rechten Maustaste auf ihren Namen klickst und auf\n'\\#d0d0ff\\Zum Spiel einladen\\#c8c8c8\\' klickst.\n\nDu kannst auch Kanäle von Servern einladen, indem du auf der \\#d0d0ff\\plus\\#c8c8c8\\Schaltfläche klickst neben der Stelle, an der Sie den Chat betreten.\n\nSpielaktivität \\#ffa0a0\\muss\\#c8c8c8\\ in Ihren\nDiscord-Benutzereinstellungen aktiviert sein.\n\nErscheinen sie offline, \\#ffa0a0\\wird es nicht möglich sein\\#c8c8c8\\ Einladungen zu senden."
WARN_DISCORD2 = "\\#ffa0a0\\Fehlermeldung:\\#c8c8c8\\ Konnte Discord nicht finden.\n\n\\#a0a0a0\\Versuche das Spiel zu schließen,\nDiscord neuzustarten,\nund das Spiel wieder zu öffnen."
WARN_SOCKET = "Für Direkte Verbindungen \\#ffa0a0\\musst du\\#c8c8c8\\ die Portweiterleitung in deinem Router Konfigurieren.\n\nPort weiterleiten '\\#d0d0ff\\%d\\#c8c8c8\\' für UDP."
HOST = "Veranstalten"
WARN_DISCORD = "Lade Freunde über Discord ein, indem du rechtsklick auf ihren Namen machst und '\\#d0d0ff\\Zum Spiel einladen\\#c8c8c8\\' auswählst. Kanäle können auch über das \\#d0d0ff\\Plus-Symbol\\#c8c8c8\\ eingeladen werden. Stelle sicher, dass die Spielaktivität in den Discord-Einstellungen aktiviert ist. Wenn du offline angezeigt wirst, kannst du keine Einladungen senden."
WARN_DISCORD2 = "\\#ffa0a0\\Fehlermeldung:\\#c8c8c8\\ Discord nicht gefunden. Versuche das Spiel zu schließen, Discord zu starten und dann das Spiel erneut zu öffnen."
WARN_SOCKET = "Für direkte Verbindungen \\#ffa0a0\\musst du\\#c8c8c8\\ die Portweiterleitung in deinem Router konfigurieren. Leite den Port '\\#d0d0ff\\%d\\#c8c8c8\\' für UDP weiter."
HOST = "Hosten"
[HOST_MODS]
ROMHACKS = "ROMHACKS"
ROMHACKS = "ROM-HACKS"
MODS = "MODS"
[HOST_SAVE]
SAVE_TITLE = "SPEICHERN"
ERASE_TITLE = "LÖSCHEN"
CONFIRM = "Möchtest du wirklich diesen save slot löschen?"
CONFIRM = "Möchtest du diesen Speicherplatz wirklich löschen?"
ERASE = "Löschen"
[HOST_SETTINGS]
SETTINGS = "EINSTELLUNGEN"
NONSOLID = "Nicht-Fest"
NONSOLID = "Nicht fest"
SOLID = "Fest"
FRIENDLY_FIRE = "Teambeschuss"
PLAYER_INTERACTION = "Spieler Interaktion"
PLAYER_INTERACTION = "Spielerinteraktion"
WEAK = "Schwach"
NORMAL = "Normal"
TOO_MUCH = "Zu viel"
KNOCKBACK_STRENGTH = "Rückstoß stärke"
LEAVE_LEVEL = "Level Verlassen"
TOO_MUCH = "Zu stark"
KNOCKBACK_STRENGTH = "Rückstoßstärke"
LEAVE_LEVEL = "Level verlassen"
STAY_IN_LEVEL = "Im Level bleiben"
NONSTOP = "Non-stop"
ON_STAR_COLLECTION = "Auf Stern-Sammlung"
SKIP_INTRO_CUTSCENE = "Zwischensequenz überspringen"
NONSTOP = "Durchgehend"
ON_STAR_COLLECTION = "Beim Stern sammeln"
SKIP_INTRO_CUTSCENE = "Intro überspringen"
SHARE_LIVES = "Leben teilen"
ENABLE_CHEATS = "Cheats aktivieren"
BUBBLE_ON_DEATH = "Beim Tod in eine Luftblase gehen"
AMOUNT_OF_PLAYERS = "Anzahl der Spieler"
BUBBLE_ON_DEATH = "Beim Tod in Blase"
AMOUNT_OF_PLAYERS = "Spieleranzahl"
[HOST]
SERVER_TITLE = "SERVER"
HOST_TITLE = "VERANSTALTEN"
HOST_TITLE = "HOSTEN"
DISCORD = "Discord"
DIRECT_CONNECTION = "Direkte Verbindung"
DIRECT_CONNECTION = "Direktverbindung"
COOPNET = "CoopNet"
NETWORK_SYSTEM = "Netzwerk-System"
NETWORK_SYSTEM = "Netzwerksystem"
PORT = "Port"
PASSWORD = "Passwort"
SAVE_SLOT = "Save Slot"
SAVE_SLOT = "Speicherplatz"
SETTINGS = "Einstellungen"
MODS = "Mods"
ROMHACKS = "Rom-Hacks"
APPLY = "Anwenden"
HOST = "Veranstalten"
APPLY = "Übernehmen"
HOST = "Hosten"
[JOIN_MESSAGE]
JOINING = "BEITRETEN"
[JOIN]
JOIN_TITLE = "BEITRETEN"
JOIN_DISCORD = "Um einen \\#d0d0ff\\Discord\\#c8c8c8\\ lobby beizutreten:\n\nLassen Sie das Spiel geöffnet und klicken Sie in der Einladung auf die Schaltfläche "Beitreten".\n\nWenn die Einladung sagt, dass das Spiel beendet ist, klicken Sie auf den Namen der Person, die die Einladung gesendet hat, um sie zu aktualisieren."
JOIN_SOCKET = "Gib für die \\#d0d0ff\\Direkte Verbindung\\#c8c8c8\\ IP und port an:"
JOIN_DISCORD = "Um einer \\#d0d0ff\\Discord\\#c8c8c8\\ Lobby beizutreten, halte das Spiel geöffnet und klicke in der Einladung auf 'Beitreten'. Wenn angezeigt wird, dass das Spiel beendet ist, klicke auf den Namen des Einladenden, um die Einladung zu aktualisieren."
JOIN_SOCKET = "Für die \\#d0d0ff\\Direktverbindung\\#c8c8c8\\ gib IP und Port ein:"
JOIN = "Beitreten"
PUBLIC_LOBBIES = "Öffentliche Lobbys"
PRIVATE_LOBBIES = "Private Lobbys"
DIRECT = "Direkte Verbindung"
DIRECT = "Direktverbindung"
[MAIN]
QUIT_TITLE = "VERLASSEN"
QUIT_CONFIRM = "Willst du den Spiel wirklich verlassen?"
HOST = "Veranstalten"
QUIT_TITLE = "BEENDEN"
QUIT_CONFIRM = "Möchtest du das Spiel wirklich beenden?"
HOST = "Hosten"
JOIN = "Beitreten"
OPTIONS = "Optionen"
QUIT = "Verlassen"
QUIT = "Beenden"
[MENU_OPTIONS]
MAIN_MENU = "HAUPTMENÜ"
LEVEL = "Level"
USE_STAGE_MUSIC = "Musik von Level verwenden"
USE_STAGE_MUSIC = "Stufenmusik verwenden"
RANDOM_STAGE = "Zufälliger Level"
PLAY_VANILLA_DEMOS = "Vanilla Demos spielen"
PLAY_VANILLA_DEMOS = "Original-Demos spielen"
[MISC]
DEBUG_TITLE = "DEBUG"
FIXED_COLLISIONS = "Feste Kollision"
FIXED_COLLISIONS = "Feste Kollisionen"
LUA_PROFILER = "Lua Profiler"
CTX_PROFILER = "Ctx Profiler"
DEBUG_PRINT = "Debug Druck"
DEBUG_INFO = "Debug Info"
DEBUG_PRINT = "Debug Ausgabe"
DEBUG_INFO = "Debug Infos"
DEBUG_ERRORS = "Debug Fehler"
MISC_TITLE = "SONSTIGES"
PAUSE_IN_SINGLEPLAYER = "Pause In Einzelspieler"
DISABLE_POPUPS = "Popups Deaktivieren"
MENU_OPTIONS = "Menü Optionen"
PAUSE_IN_SINGLEPLAYER = "Pause im Einzelspieler"
DISABLE_POPUPS = "Pop-ups deaktivieren"
MENU_OPTIONS = "Menüoptionen"
DEBUG = "Debug"
LANGUAGE = "Sprache"
@ -257,43 +257,43 @@ OPTIONS = "OPTIONEN"
PLAYER = "Spieler"
CAMERA = "Kamera"
CONTROLS = "Steuerung"
DISPLAY = "Display"
DISPLAY = "Anzeige"
SOUND = "Sound"
MISC = "Sonstiges"
[PAUSE]
QUIT_TITLE = "VERLASSEN"
QUIT_HOST = "Möchtest du wirklich mit der Veranstaltung aufhören?"
QUIT_CLIENT = "Möchtest du wirklich die Verbindung einstellen?"
QUIT_TITLE = "BEENDEN"
QUIT_HOST = "Möchtest du wirklich das Hosting beenden?"
QUIT_CLIENT = "Möchtest du wirklich die Verbindung trennen?"
PAUSE_TITLE = "PAUSE"
PLAYER = "Spieler"
DYNOS_PACKS = "DynOS Packs"
DYNOS_PACKS = "DynOS-Pakete"
OPTIONS = "Optionen"
CHEATS = "Cheats"
SERVER_SETTINGS = "Server Einstellungen"
RESUME = "Fortsetzen"
STOP_HOSTING = "Veranstaltung beenden"
SERVER_SETTINGS = "Servereinstellungen"
RESUME = "Zurück zum Spiel"
STOP_HOSTING = "Hosting beenden"
DISCONNECT = "Verbindung trennen"
[PLAYER]
PLAYER_TITLE = "PLAYER"
OVERALLS = "Ganzanzug"
SHIRT = "Shirt"
PLAYER_TITLE = "SPIELER"
OVERALLS = "Overall"
SHIRT = "Hemd"
GLOVES = "Handschuhe"
SHOES = "Schuhe"
HAIR = "Haare"
HAIR = "Haar"
SKIN = "Haut"
CAP = "Hut"
CAP = "Mütze"
PALETTE = "PALETTE"
PART = "Teil"
HEX_CODE = "Hex Code"
HEX_CODE = "Hex-Code"
RED = "Rot"
GREEN = "Grün"
BLUE = "Blau"
PLAYER = "Spieler"
NAME = "Name"
MODEL = "Modell"
PALETTE_PRESET = "Vorhandene Palette"
PALETTE_PRESET = "Palette-Vorlage"
EDIT_PALETTE = "Palette bearbeiten"
[PALETTE]
@ -303,48 +303,48 @@ WALUIGI = "Waluigi"
WARIO = "Wario"
CHUCKYA = "Wurfmufti"
GOOMBA = "Gumba"
CLOVER = "Kleeblatt"
CLOVER = "Klee"
COBALT = "Kobalt"
FURY = "Wut"
HOT_PINK = "Hell Pink"
FURY = "Zorn"
HOT_PINK = "Neonpink"
NICE_PINK = "Schönes Pink"
SEAFOAM = "Meerschaum"
LILAC = "Lilac"
SEAFOAM = "Meeresschaum"
LILAC = "Flieder"
COPPER = "Kupfer"
AZURE = "Azurblau"
BURGUNDY = "Burgund"
AZURE = "Azur"
BURGUNDY = "Burgunder"
MINT = "Minze"
EGGPLANT = "Aubergine"
ORANGE = "Orange"
ARCTIC = "Arktik"
FIRE_MARIO = "Feuer Mario"
FIRE_LUIGI = "Feuer Luigi"
FIRE_WALUIGI = "Feuer Waluigi"
FIRE_WARIO = "Feuer Wario"
BUSY_BEE = "Beschäftigte Biene"
ARCTIC = "Arktis"
FIRE_MARIO = "Feuer-Mario"
FIRE_LUIGI = "Feuer-Luigi"
FIRE_WALUIGI = "Feuer-Waluigi"
FIRE_WARIO = "Feuer-Wario"
BUSY_BEE = "Fleißige Biene"
FORTRESS = "Festung"
BATTLEMENTS = "Battlements"
BLUEBERRY_PIE = "Heidelbeerkuchen"
BATTLEMENTS = "Wehrmauer"
BLUEBERRY_PIE = "Blaubeerkuchen"
RASPBERRY = "Himbeere"
BUBBLEGUM = "Kaugummi"
ICE_MARIO = "Eis Mario"
ICE_LUIGI = "Eis Luigi"
ICE_MARIO = "Eis-Mario"
ICE_LUIGI = "Eis-Luigi"
TOAD = "Toad"
CUSTOM = "Selbstgemacht"
CUSTOM = "Benutzerdefiniert"
[PLAYER_LIST]
PLAYERS = "SPIELER"
NAME = "Name"
LOCATION = "Ort"
ACT = "act"
ACT = "Akt"
[SOUND]
SOUND = "SOUND"
MASTER_VOLUME = "Hauptlautstärke"
MUSIC_VOLUME = "Musik Lautstärke"
SFX_VOLUME = "Geräusch Lautstärke"
ENV_VOLUME = "Env Lautstärke"
FADEOUT = "Geräusche von der Ferne ausblenden"
MUSIC_VOLUME = "Musiklautstärke"
SFX_VOLUME = "Effektlautstärke"
ENV_VOLUME = "Umgebungslautstärke"
FADEOUT = "Ausblenden"
[LANGUAGE]
LANGUAGE = "SPRACHE"
@ -353,10 +353,10 @@ LANGUAGE = "SPRACHE"
PUBLIC_LOBBIES = "ÖFFENTLICHE\nLOBBIES"
PRIVATE_LOBBIES = "PRIVATE LOBBIES"
REFRESH = "Aktualisieren"
REFRESHING = "Wird Aktualisiert..."
ENTER_PASSWORD = "Gib das Passwort für das Lobby ein:"
REFRESHING = "Aktualisiere..."
ENTER_PASSWORD = "Gib das Passwort für die Lobby ein:"
SEARCH = "Suchen"
NONE_FOUND = "Es wurden keine Lobbys gefunden."
NONE_FOUND = "Keine Lobbys gefunden."
[LOADING_SCREEN]
LOADING = "Wird geladen"

768
mods/iZeSaveStates.lua Normal file
View File

@ -0,0 +1,768 @@
-- name: iZeSaveStates v2.1.4
-- description: Adds SaveStates to SM64EX-COOP!\n\n-Save up to 4 states at the same time by using the 4 D-Pad buttons\n-To load states, hold down L and press the corresponding D-Pad button\n-Each player gets their own 4 local savestate slots (Global SaveStates maybe in the future)\n\n-Use /autoload or /al to toggle AutoLoading the latest savestate upon death\n-Use /autoheal or /ah to toggle AutoHealing after loading savestates\n-Use /savestates, /savestate, or /ss to get infos about your local settings and slots
local autoload_enabled = false
local autoheal_enabled = false
local latest_savestate = nil
local wait_until_inited = nil
local ready_to_load = nil
local savestates = {}
savestates.gNetworkPlayers_currLevelNum = { nil, nil, nil, nil }
savestates.gNetworkPlayers_currActNum = { nil, nil, nil, nil }
savestates.gNetworkPlayers_currAreaIndex = { nil, nil, nil, nil }
savestates.action = { nil, nil, nil, nil }
savestates.actionArg = { nil, nil, nil, nil }
savestates.actionState = { nil, nil, nil, nil }
savestates.actionTimer = { nil, nil, nil, nil }
savestates.angleVel_x = { nil, nil, nil, nil }
savestates.angleVel_y = { nil, nil, nil, nil }
savestates.angleVel_z = { nil, nil, nil, nil }
savestates.animation_targetAnim = { nil, nil, nil, nil }
savestates.area_camera = { nil, nil, nil, nil }
savestates.area_flags = { nil, nil, nil, nil }
savestates.area_index = { nil, nil, nil, nil }
savestates.area_instantWarps = { nil, nil, nil, nil }
savestates.area_musicParam = { nil, nil, nil, nil }
savestates.area_musicParam2 = { nil, nil, nil, nil }
savestates.area_numRedCoins = { nil, nil, nil, nil }
savestates.area_numSecrets = { nil, nil, nil, nil }
savestates.area_objectSpawnInfos_activeAreaIndex = { nil, nil, nil, nil }
savestates.area_objectSpawnInfos_areaIndex = { nil, nil, nil, nil }
savestates.area_objectSpawnInfos_behaviorArg = { nil, nil, nil, nil }
savestates.area_objectSpawnInfos_startAngle_x = { nil, nil, nil, nil }
savestates.area_objectSpawnInfos_startAngle_y = { nil, nil, nil, nil }
savestates.area_objectSpawnInfos_startAngle_z = { nil, nil, nil, nil }
savestates.area_objectSpawnInfos_startPos_x = { nil, nil, nil, nil }
savestates.area_objectSpawnInfos_startPos_y = { nil, nil, nil, nil }
savestates.area_objectSpawnInfos_startPos_z = { nil, nil, nil, nil }
savestates.area_objectSpawnInfos_unk18_extraFlags = { nil, nil, nil, nil }
savestates.area_objectSpawnInfos_unk18_flags = { nil, nil, nil, nil }
savestates.area_paintingWarpNodes_destArea = { nil, nil, nil, nil }
savestates.area_paintingWarpNodes_destLevel = { nil, nil, nil, nil }
savestates.area_paintingWarpNodes_destNode = { nil, nil, nil, nil }
savestates.area_paintingWarpNodes_id = { nil, nil, nil, nil }
savestates.area_terrainType = { nil, nil, nil, nil }
savestates.area_warpNodes_next = { nil, nil, nil, nil }
savestates.area_warpNodes_node_destArea = { nil, nil, nil, nil }
savestates.area_warpNodes_node_destLevel = { nil, nil, nil, nil }
savestates.area_warpNodes_node_destNode = { nil, nil, nil, nil }
savestates.area_warpNodes_node_id = { nil, nil, nil, nil }
savestates.area_warpNodes_object = { nil, nil, nil, nil }
savestates.bounceSquishTimer = { nil, nil, nil, nil }
savestates.bubbleObj = { nil, nil, nil, nil }
savestates.cap = { nil, nil, nil, nil }
savestates.capTimer = { nil, nil, nil, nil }
savestates.ceil = { nil, nil, nil, nil }
savestates.ceilHeight = { nil, nil, nil, nil }
savestates.character = { nil, nil, nil, nil }
savestates.collidedObjInteractTypes = { nil, nil, nil, nil }
savestates.controller_buttonDown = { nil, nil, nil, nil }
savestates.controller_buttonPressed = { nil, nil, nil, nil }
savestates.controller_extStickX = { nil, nil, nil, nil }
savestates.controller_extStickY = { nil, nil, nil, nil }
savestates.controller_port = { nil, nil, nil, nil }
savestates.controller_rawStickX = { nil, nil, nil, nil }
savestates.controller_rawStickY = { nil, nil, nil, nil }
savestates.controller_stickMag = { nil, nil, nil, nil }
savestates.controller_stickX = { nil, nil, nil, nil }
savestates.controller_stickY = { nil, nil, nil, nil }
savestates.curAnimOffset = { nil, nil, nil, nil }
savestates.currentRoom = { nil, nil, nil, nil }
savestates.doubleJumpTimer = { nil, nil, nil, nil }
savestates.faceAngle_x = { nil, nil, nil, nil }
savestates.faceAngle_y = { nil, nil, nil, nil }
savestates.faceAngle_z = { nil, nil, nil, nil }
savestates.fadeWarpOpacity = { nil, nil, nil, nil }
savestates.flags = { nil, nil, nil, nil }
savestates.floor = { nil, nil, nil, nil }
savestates.floorAngle = { nil, nil, nil, nil }
savestates.floorHeight = { nil, nil, nil, nil }
savestates.forwardVel = { nil, nil, nil, nil }
savestates.framesSinceA = { nil, nil, nil, nil }
savestates.framesSinceB = { nil, nil, nil, nil }
savestates.freeze = { nil, nil, nil, nil }
savestates.healCounter = { nil, nil, nil, nil }
savestates.health = { nil, nil, nil, nil }
savestates.heldByObj = { nil, nil, nil, nil }
savestates.heldObj = { nil, nil, nil, nil }
savestates.hurtCounter = { nil, nil, nil, nil }
savestates.input = { nil, nil, nil, nil }
savestates.intendedMag = { nil, nil, nil, nil }
savestates.intendedYaw = { nil, nil, nil, nil }
savestates.interactObj = { nil, nil, nil, nil }
savestates.invincTimer = { nil, nil, nil, nil }
savestates.isSnoring = { nil, nil, nil, nil }
savestates.knockbackTimer = { nil, nil, nil, nil }
savestates.marioBodyState_action = { nil, nil, nil, nil }
savestates.marioBodyState_capState = { nil, nil, nil, nil }
savestates.marioBodyState_eyeState = { nil, nil, nil, nil }
savestates.marioBodyState_grabPos = { nil, nil, nil, nil }
savestates.marioBodyState_handState = { nil, nil, nil, nil }
savestates.marioBodyState_headAngle_x = { nil, nil, nil, nil }
savestates.marioBodyState_headAngle_y = { nil, nil, nil, nil }
savestates.marioBodyState_headAngle_z = { nil, nil, nil, nil }
savestates.marioBodyState_headPos_x = { nil, nil, nil, nil }
savestates.marioBodyState_headPos_y = { nil, nil, nil, nil }
savestates.marioBodyState_headPos_z = { nil, nil, nil, nil }
savestates.marioBodyState_heldObjLastPosition_x = { nil, nil, nil, nil }
savestates.marioBodyState_heldObjLastPosition_y = { nil, nil, nil, nil }
savestates.marioBodyState_heldObjLastPosition_z = { nil, nil, nil, nil }
savestates.marioBodyState_modelState = { nil, nil, nil, nil }
savestates.marioBodyState_punchState = { nil, nil, nil, nil }
savestates.marioBodyState_torsoAngle_x = { nil, nil, nil, nil }
savestates.marioBodyState_torsoAngle_y = { nil, nil, nil, nil }
savestates.marioBodyState_torsoAngle_z = { nil, nil, nil, nil }
savestates.marioBodyState_torsoPos_x = { nil, nil, nil, nil }
savestates.marioBodyState_torsoPos_y = { nil, nil, nil, nil }
savestates.marioBodyState_torsoPos_z = { nil, nil, nil, nil }
savestates.marioBodyState_wingFlutter = { nil, nil, nil, nil }
savestates.marioObj_activeFlags = { nil, nil, nil, nil }
savestates.marioObj_areaTimer = { nil, nil, nil, nil }
savestates.marioObj_areaTimerDuration = { nil, nil, nil, nil }
savestates.marioObj_areaTimerType = { nil, nil, nil, nil }
savestates.marioObj_bhvDelayTimer = { nil, nil, nil, nil }
savestates.marioObj_collidedObjInteractTypes = { nil, nil, nil, nil }
savestates.marioObj_collisionData = { nil, nil, nil, nil }
savestates.marioObj_ctx = { nil, nil, nil, nil }
savestates.marioObj_globalPlayerIndex = { nil, nil, nil, nil }
savestates.marioObj_header_gfx_activeAreaIndex = { nil, nil, nil, nil }
savestates.marioObj_header_gfx_areaIndex = { nil, nil, nil, nil }
savestates.marioObj_header_gfx_disableAutomaticShadowPos = { nil, nil, nil, nil }
savestates.marioObj_header_gfx_shadowInvisible = { nil, nil, nil, nil }
savestates.marioObj_header_gfx_skipInViewCheck = { nil, nil, nil, nil }
savestates.marioObj_heldByPlayerIndex = { nil, nil, nil, nil }
savestates.marioObj_hitboxDownOffset = { nil, nil, nil, nil }
savestates.marioObj_hitboxHeight = { nil, nil, nil, nil }
savestates.marioObj_hitboxRadius = { nil, nil, nil, nil }
savestates.marioObj_hookRender = { nil, nil, nil, nil }
savestates.marioObj_hurtboxHeight = { nil, nil, nil, nil }
savestates.marioObj_hurtboxRadius = { nil, nil, nil, nil }
savestates.marioObj_parentObj = { nil, nil, nil, nil }
savestates.marioObj_platform = { nil, nil, nil, nil }
savestates.marioObj_prevObj = { nil, nil, nil, nil }
savestates.marioObj_setHome = { nil, nil, nil, nil }
savestates.marioObj_unused1 = { nil, nil, nil, nil }
savestates.marioObj_usingObj = { nil, nil, nil, nil }
savestates.minimumBoneY = { nil, nil, nil, nil }
savestates.nonInstantWarpPos_x = { nil, nil, nil, nil }
savestates.nonInstantWarpPos_y = { nil, nil, nil, nil }
savestates.nonInstantWarpPos_z = { nil, nil, nil, nil }
savestates.numCoins = { nil, nil, nil, nil }
savestates.numKeys = { nil, nil, nil, nil }
savestates.numLives = { nil, nil, nil, nil }
savestates.numStars = { nil, nil, nil, nil }
savestates.particleFlags = { nil, nil, nil, nil }
savestates.peakHeight = { nil, nil, nil, nil }
savestates.pos_x = { nil, nil, nil, nil }
savestates.pos_y = { nil, nil, nil, nil }
savestates.pos_z = { nil, nil, nil, nil }
savestates.prevAction = { nil, nil, nil, nil }
savestates.prevNumStarsForDialog = { nil, nil, nil, nil }
savestates.quicksandDepth = { nil, nil, nil, nil }
savestates.riddenObj = { nil, nil, nil, nil }
savestates.slideVelX = { nil, nil, nil, nil }
savestates.slideVelZ = { nil, nil, nil, nil }
savestates.slideYaw = { nil, nil, nil, nil }
savestates.spawnInfo = { nil, nil, nil, nil }
savestates.specialTripleJump = { nil, nil, nil, nil }
savestates.splineKeyframe = { nil, nil, nil, nil }
savestates.splineKeyframeFraction = { nil, nil, nil, nil }
savestates.splineState = { nil, nil, nil, nil }
savestates.squishTimer = { nil, nil, nil, nil }
savestates.statusForCamera_action = { nil, nil, nil, nil }
savestates.statusForCamera_cameraEvent = { nil, nil, nil, nil }
savestates.statusForCamera_faceAngle_x = { nil, nil, nil, nil }
savestates.statusForCamera_faceAngle_y = { nil, nil, nil, nil }
savestates.statusForCamera_faceAngle_z = { nil, nil, nil, nil }
savestates.statusForCamera_headRotation_x = { nil, nil, nil, nil }
savestates.statusForCamera_headRotation_y = { nil, nil, nil, nil }
savestates.statusForCamera_headRotation_z = { nil, nil, nil, nil }
savestates.statusForCamera_pos_x = { nil, nil, nil, nil }
savestates.statusForCamera_pos_y = { nil, nil, nil, nil }
savestates.statusForCamera_pos_z = { nil, nil, nil, nil }
savestates.statusForCamera_unused = { nil, nil, nil, nil }
savestates.statusForCamera_usedObj = { nil, nil, nil, nil }
savestates.terrainSoundAddend = { nil, nil, nil, nil }
savestates.twirlYaw = { nil, nil, nil, nil }
savestates.unkB0 = { nil, nil, nil, nil }
savestates.unkC4 = { nil, nil, nil, nil }
savestates.usedObj = { nil, nil, nil, nil }
savestates.vel_x = { nil, nil, nil, nil }
savestates.vel_y = { nil, nil, nil, nil }
savestates.vel_z = { nil, nil, nil, nil }
savestates.wall = { nil, nil, nil, nil }
savestates.wallKickTimer = { nil, nil, nil, nil }
savestates.wallNormal_x = { nil, nil, nil, nil }
savestates.wallNormal_y = { nil, nil, nil, nil }
savestates.wallNormal_z = { nil, nil, nil, nil }
savestates.wasNetworkVisible = { nil, nil, nil, nil }
savestates.waterLevel = { nil, nil, nil, nil }
function on_join(m)
if m.playerIndex == 0 then
reset_all(m)
end
end
function on_leave(m)
if m.playerIndex == 0 then
reset_all(m)
end
end
function on_death(m)
if m.playerIndex == 0 then
if autoload_enabled == true then
if latest_savestate ~= nil and is_state_slot_not_empty(latest_savestate) then
local nCoins = m.numCoins
local nRedCoins = m.area.numRedCoins
local nSecrets = m.area.numSecrets
init_single_mario(m)
m.pos.x = 0
m.pos.y = 0
m.pos.z = 0
m.health = 0x880
m.numLives = m.numLives + 1
m.numCoins = nCoins
m.area.numRedCoins = nRedCoins
m.area.numSecrets = nSecrets
soft_reset_camera(m.area.camera)
djui_popup_create("\\#ff80ff\\[AutoLoad] Loading latest state...", 1)
load_state_slot(m, latest_savestate)
return false
else
latest_savestate = nil
play_sound(SOUND_GENERAL_FLAME_OUT, m.marioObj.header.gfx.cameraToObject)
djui_popup_create("\\#a0a0a0\\[AutoLoad] 404 latest state not found!", 1)
return true
end
else
return true
end
end
end
function on_level_init()
if wait_until_inited ~= nil then
ready_to_load = wait_until_inited
wait_until_inited = nil
end
end
function on_mario_update(m)
if m.playerIndex == 0 then
if ready_to_load ~= nil then
load_state_slot(m, ready_to_load)
else
if (m.controller.buttonDown & L_TRIG) == 0 then
if (m.controller.buttonPressed & L_JPAD) ~= 0 then
save_state_slot(m, 0, "\\#ff4040\\")
elseif (m.controller.buttonPressed & U_JPAD) ~= 0 then
save_state_slot(m, 1, "\\#40ff40\\")
elseif (m.controller.buttonPressed & R_JPAD) ~= 0 then
save_state_slot(m, 2, "\\#4040ff\\")
elseif (m.controller.buttonPressed & D_JPAD) ~= 0 then
save_state_slot(m, 3, "\\#ffff40\\")
end
else
if (m.controller.buttonPressed & L_JPAD) ~= 0 then
load_state_slot(m, 0)
elseif (m.controller.buttonPressed & U_JPAD) ~= 0 then
load_state_slot(m, 1)
elseif (m.controller.buttonPressed & R_JPAD) ~= 0 then
load_state_slot(m, 2)
elseif (m.controller.buttonPressed & D_JPAD) ~= 0 then
load_state_slot(m, 3)
end
end
end
end
end
function reset_all(m)
delete_state_slot(m,0)
delete_state_slot(m,1)
delete_state_slot(m,2)
delete_state_slot(m,3)
autoload_enabled = false
autoheal_enabled = false
latest_savestate = nil
end
function save_state_slot(m, slot, color)
savestates.gNetworkPlayers_currLevelNum[slot] = gNetworkPlayers[0].currLevelNum
savestates.gNetworkPlayers_currActNum[slot] = gNetworkPlayers[0].currActNum
savestates.gNetworkPlayers_currAreaIndex[slot] = gNetworkPlayers[0].currAreaIndex
savestates.action[slot] = ((m and m.action) and m.action or nil)
savestates.actionArg[slot] = ((m and m.actionArg) and m.actionArg or nil)
savestates.actionState[slot] = ((m and m.actionState) and m.actionState or nil)
savestates.actionTimer[slot] = ((m and m.actionTimer) and m.actionTimer or nil)
savestates.angleVel_x[slot] = ((m and m.angleVel and m.angleVel.x) and m.angleVel.x or nil)
savestates.angleVel_y[slot] = ((m and m.angleVel and m.angleVel.y) and m.angleVel.y or nil)
savestates.angleVel_z[slot] = ((m and m.angleVel and m.angleVel.z) and m.angleVel.z or nil)
savestates.animation_targetAnim[slot] = ((m and m.animation and m.animation.targetAnim) and m.animation.targetAnim or nil)
savestates.area_camera[slot] = ((m and m.area and m.area.camera) and m.area.camera or nil)
savestates.area_flags[slot] = ((m and m.area and m.area.flags) and m.area.flags or nil)
savestates.area_index[slot] = ((m and m.area and m.area.index) and m.area.index or nil)
savestates.area_instantWarps[slot] = ((m and m.area and m.area.instantWarps) and m.area.instantWarps or nil)
savestates.area_musicParam[slot] = ((m and m.area and m.area.musicParam) and m.area.musicParam or nil)
savestates.area_musicParam2[slot] = ((m and m.area and m.area.musicParam2) and m.area.musicParam2 or nil)
savestates.area_numRedCoins[slot] = ((m and m.area and m.area.numRedCoins) and m.area.numRedCoins or nil)
savestates.area_numSecrets[slot] = ((m and m.area and m.area.numSecrets) and m.area.numSecrets or nil)
savestates.area_objectSpawnInfos_activeAreaIndex[slot] = ((m and m.area and m.area.objectSpawnInfos and m.area.objectSpawnInfos.activeAreaIndex) and m.area.objectSpawnInfos.activeAreaIndex or nil)
savestates.area_objectSpawnInfos_areaIndex[slot] = ((m and m.area and m.area.objectSpawnInfos and m.area.objectSpawnInfos.areaIndex) and m.area.objectSpawnInfos.areaIndex or nil)
savestates.area_objectSpawnInfos_behaviorArg[slot] = ((m and m.area and m.area.objectSpawnInfos and m.area.objectSpawnInfos.behaviorArg) and m.area.objectSpawnInfos.behaviorArg or nil)
savestates.area_objectSpawnInfos_startAngle_x[slot] = ((m and m.area and m.area.objectSpawnInfos and m.area.objectSpawnInfos.startAngle and m.area.objectSpawnInfos.startAngle.x) and m.area.objectSpawnInfos.startAngle.x or nil)
savestates.area_objectSpawnInfos_startAngle_y[slot] = ((m and m.area and m.area.objectSpawnInfos and m.area.objectSpawnInfos.startAngle and m.area.objectSpawnInfos.startAngle.y) and m.area.objectSpawnInfos.startAngle.y or nil)
savestates.area_objectSpawnInfos_startAngle_z[slot] = ((m and m.area and m.area.objectSpawnInfos and m.area.objectSpawnInfos.startAngle and m.area.objectSpawnInfos.startAngle.z) and m.area.objectSpawnInfos.startAngle.z or nil)
savestates.area_objectSpawnInfos_startPos_x[slot] = ((m and m.area and m.area.objectSpawnInfos and m.area.objectSpawnInfos.startPos and m.area.objectSpawnInfos.startPos.x) and m.area.objectSpawnInfos.startPos.x or nil)
savestates.area_objectSpawnInfos_startPos_y[slot] = ((m and m.area and m.area.objectSpawnInfos and m.area.objectSpawnInfos.startPos and m.area.objectSpawnInfos.startPos.y) and m.area.objectSpawnInfos.startPos.y or nil)
savestates.area_objectSpawnInfos_startPos_z[slot] = ((m and m.area and m.area.objectSpawnInfos and m.area.objectSpawnInfos.startPos and m.area.objectSpawnInfos.startPos.z) and m.area.objectSpawnInfos.startPos.z or nil)
savestates.area_objectSpawnInfos_unk18_extraFlags[slot] = ((m and m.area and m.area.objectSpawnInfos and m.area.objectSpawnInfos.unk18 and m.area.objectSpawnInfos.unk18.extraFlags) and m.area.objectSpawnInfos.unk18.extraFlags or nil)
savestates.area_objectSpawnInfos_unk18_flags[slot] = ((m and m.area and m.area.objectSpawnInfos and m.area.objectSpawnInfos.unk18 and m.area.objectSpawnInfos.unk18.flags) and m.area.objectSpawnInfos.unk18.flags or nil)
savestates.area_paintingWarpNodes_destArea[slot] = ((m and m.area and m.area.paintingWarpNodes and m.area.paintingWarpNodes.destArea) and m.area.paintingWarpNodes.destArea or nil)
savestates.area_paintingWarpNodes_destLevel[slot] = ((m and m.area and m.area.paintingWarpNodes and m.area.paintingWarpNodes.destLevel) and m.area.paintingWarpNodes.destLevel or nil)
savestates.area_paintingWarpNodes_destNode[slot] = ((m and m.area and m.area.paintingWarpNodes and m.area.paintingWarpNodes.destNode) and m.area.paintingWarpNodes.destNode or nil)
savestates.area_paintingWarpNodes_id[slot] = ((m and m.area and m.area.paintingWarpNodes and m.area.paintingWarpNodes.id) and m.area.paintingWarpNodes.id or nil)
savestates.area_terrainType[slot] = ((m and m.area and m.area.terrainType) and m.area.terrainType or nil)
savestates.area_warpNodes_next[slot] = ((m and m.area and m.area.warpNodes and m.area.warpNodes.next) and m.area.warpNodes.next or nil)
savestates.area_warpNodes_node_destArea[slot] = ((m and m.area and m.area.warpNodes and m.area.warpNodes.node and m.area.warpNodes.node.destArea) and m.area.warpNodes.node.destArea or nil)
savestates.area_warpNodes_node_destLevel[slot] = ((m and m.area and m.area.warpNodes and m.area.warpNodes.node and m.area.warpNodes.node.destLevel) and m.area.warpNodes.node.destLevel or nil)
savestates.area_warpNodes_node_destNode[slot] = ((m and m.area and m.area.warpNodes and m.area.warpNodes.node and m.area.warpNodes.node.destNode) and m.area.warpNodes.node.destNode or nil)
savestates.area_warpNodes_node_id[slot] = ((m and m.area and m.area.warpNodes and m.area.warpNodes.node and m.area.warpNodes.node.id) and m.area.warpNodes.node.id or nil)
savestates.area_warpNodes_object[slot] = ((m and m.area and m.area.warpNodes and m.area.warpNodes.object) and m.area.warpNodes.object or nil)
savestates.bounceSquishTimer[slot] = ((m and m.bounceSquishTimer) and m.bounceSquishTimer or nil)
savestates.bubbleObj[slot] = ((m and m.bubbleObj) and m.bubbleObj or nil)
savestates.cap[slot] = ((m and m.cap) and m.cap or nil)
savestates.capTimer[slot] = ((m and m.capTimer) and m.capTimer or nil)
savestates.ceil[slot] = ((m and m.ceil) and m.ceil or nil)
savestates.ceilHeight[slot] = ((m and m.ceilHeight) and m.ceilHeight or nil)
savestates.character[slot] = ((m and m.character) and m.character or nil)
savestates.collidedObjInteractTypes[slot] = ((m and m.collidedObjInteractTypes) and m.collidedObjInteractTypes or nil)
savestates.controller_buttonDown[slot] = ((m and m.controller and m.controller.buttonDown) and m.controller.buttonDown or nil)
savestates.controller_buttonPressed[slot] = ((m and m.controller and m.controller.buttonPressed) and m.controller.buttonPressed or nil)
savestates.controller_extStickX[slot] = ((m and m.controller and m.controller.extStickX) and m.controller.extStickX or nil)
savestates.controller_extStickY[slot] = ((m and m.controller and m.controller.extStickY) and m.controller.extStickY or nil)
savestates.controller_port[slot] = ((m and m.controller and m.controller.port) and m.controller.port or nil)
savestates.controller_rawStickX[slot] = ((m and m.controller and m.controller.rawStickX) and m.controller.rawStickX or nil)
savestates.controller_rawStickY[slot] = ((m and m.controller and m.controller.rawStickY) and m.controller.rawStickY or nil)
savestates.controller_stickMag[slot] = ((m and m.controller and m.controller.stickMag) and m.controller.stickMag or nil)
savestates.controller_stickX[slot] = ((m and m.controller and m.controller.stickX) and m.controller.stickX or nil)
savestates.controller_stickY[slot] = ((m and m.controller and m.controller.stickY) and m.controller.stickY or nil)
savestates.curAnimOffset[slot] = ((m and m.curAnimOffset) and m.curAnimOffset or nil)
savestates.currentRoom[slot] = ((m and m.currentRoom) and m.currentRoom or nil)
savestates.doubleJumpTimer[slot] = ((m and m.doubleJumpTimer) and m.doubleJumpTimer or nil)
savestates.faceAngle_x[slot] = ((m and m.faceAngle and m.faceAngle.x) and m.faceAngle.x or nil)
savestates.faceAngle_y[slot] = ((m and m.faceAngle and m.faceAngle.y) and m.faceAngle.y or nil)
savestates.faceAngle_z[slot] = ((m and m.faceAngle and m.faceAngle.z) and m.faceAngle.z or nil)
savestates.fadeWarpOpacity[slot] = ((m and m.fadeWarpOpacity) and m.fadeWarpOpacity or nil)
savestates.flags[slot] = ((m and m.flags) and m.flags or nil)
savestates.floor[slot] = ((m and m.floor) and m.floor or nil)
savestates.floorAngle[slot] = ((m and m.floorAngle) and m.floorAngle or nil)
savestates.floorHeight[slot] = ((m and m.floorHeight) and m.floorHeight or nil)
savestates.forwardVel[slot] = ((m and m.forwardVel) and m.forwardVel or nil)
savestates.framesSinceA[slot] = ((m and m.framesSinceA) and m.framesSinceA or nil)
savestates.framesSinceB[slot] = ((m and m.framesSinceB) and m.framesSinceB or nil)
savestates.freeze[slot] = ((m and m.freeze) and m.freeze or nil)
savestates.healCounter[slot] = ((m and m.healCounter) and m.healCounter or nil)
savestates.health[slot] = ((m and m.health) and m.health or nil)
savestates.heldByObj[slot] = ((m and m.heldByObj) and m.heldByObj or nil)
savestates.heldObj[slot] = ((m and m.heldObj) and m.heldObj or nil)
savestates.hurtCounter[slot] = ((m and m.hurtCounter) and m.hurtCounter or nil)
savestates.input[slot] = ((m and m.input) and m.input or nil)
savestates.intendedMag[slot] = ((m and m.intendedMag) and m.intendedMag or nil)
savestates.intendedYaw[slot] = ((m and m.intendedYaw) and m.intendedYaw or nil)
savestates.interactObj[slot] = ((m and m.interactObj) and m.interactObj or nil)
savestates.invincTimer[slot] = ((m and m.invincTimer) and m.invincTimer or nil)
savestates.isSnoring[slot] = ((m and m.isSnoring) and m.isSnoring or nil)
savestates.knockbackTimer[slot] = ((m and m.knockbackTimer) and m.knockbackTimer or nil)
savestates.marioBodyState_action[slot] = ((m and m.marioBodyState and m.marioBodyState.action) and m.marioBodyState.action or nil)
savestates.marioBodyState_capState[slot] = ((m and m.marioBodyState and m.marioBodyState.capState) and m.marioBodyState.capState or nil)
savestates.marioBodyState_eyeState[slot] = ((m and m.marioBodyState and m.marioBodyState.eyeState) and m.marioBodyState.eyeState or nil)
savestates.marioBodyState_grabPos[slot] = ((m and m.marioBodyState and m.marioBodyState.grabPos) and m.marioBodyState.grabPos or nil)
savestates.marioBodyState_handState[slot] = ((m and m.marioBodyState and m.marioBodyState.handState) and m.marioBodyState.handState or nil)
savestates.marioBodyState_headAngle_x[slot] = ((m and m.marioBodyState and m.marioBodyState.headAngle and m.marioBodyState.headAngle.x) and m.marioBodyState.headAngle.x or nil)
savestates.marioBodyState_headAngle_y[slot] = ((m and m.marioBodyState and m.marioBodyState.headAngle and m.marioBodyState.headAngle.y) and m.marioBodyState.headAngle.y or nil)
savestates.marioBodyState_headAngle_z[slot] = ((m and m.marioBodyState and m.marioBodyState.headAngle and m.marioBodyState.headAngle.z) and m.marioBodyState.headAngle.z or nil)
savestates.marioBodyState_headPos_x[slot] = ((m and m.marioBodyState and m.marioBodyState.headPos and m.marioBodyState.headPos.x) and m.marioBodyState.headPos.x or nil)
savestates.marioBodyState_headPos_y[slot] = ((m and m.marioBodyState and m.marioBodyState.headPos and m.marioBodyState.headPos.y) and m.marioBodyState.headPos.y or nil)
savestates.marioBodyState_headPos_z[slot] = ((m and m.marioBodyState and m.marioBodyState.headPos and m.marioBodyState.headPos.z) and m.marioBodyState.headPos.z or nil)
savestates.marioBodyState_heldObjLastPosition_x[slot] = ((m and m.marioBodyState and m.marioBodyState.heldObjLastPosition and m.marioBodyState.heldObjLastPosition.x) and m.marioBodyState.heldObjLastPosition.x or nil)
savestates.marioBodyState_heldObjLastPosition_y[slot] = ((m and m.marioBodyState and m.marioBodyState.heldObjLastPosition and m.marioBodyState.heldObjLastPosition.y) and m.marioBodyState.heldObjLastPosition.y or nil)
savestates.marioBodyState_heldObjLastPosition_z[slot] = ((m and m.marioBodyState and m.marioBodyState.heldObjLastPosition and m.marioBodyState.heldObjLastPosition.z) and m.marioBodyState.heldObjLastPosition.z or nil)
savestates.marioBodyState_modelState[slot] = ((m and m.marioBodyState and m.marioBodyState.modelState) and m.marioBodyState.modelState or nil)
savestates.marioBodyState_punchState[slot] = ((m and m.marioBodyState and m.marioBodyState.punchState) and m.marioBodyState.punchState or nil)
savestates.marioBodyState_torsoAngle_x[slot] = ((m and m.marioBodyState and m.marioBodyState.torsoAngle and m.marioBodyState.torsoAngle.x) and m.marioBodyState.torsoAngle.x or nil)
savestates.marioBodyState_torsoAngle_y[slot] = ((m and m.marioBodyState and m.marioBodyState.torsoAngle and m.marioBodyState.torsoAngle.y) and m.marioBodyState.torsoAngle.y or nil)
savestates.marioBodyState_torsoAngle_z[slot] = ((m and m.marioBodyState and m.marioBodyState.torsoAngle and m.marioBodyState.torsoAngle.z) and m.marioBodyState.torsoAngle.z or nil)
savestates.marioBodyState_torsoPos_x[slot] = ((m and m.marioBodyState and m.marioBodyState.torsoPos and m.marioBodyState.torsoPos.x) and m.marioBodyState.torsoPos.x or nil)
savestates.marioBodyState_torsoPos_y[slot] = ((m and m.marioBodyState and m.marioBodyState.torsoPos and m.marioBodyState.torsoPos.y) and m.marioBodyState.torsoPos.y or nil)
savestates.marioBodyState_torsoPos_z[slot] = ((m and m.marioBodyState and m.marioBodyState.torsoPos and m.marioBodyState.torsoPos.z) and m.marioBodyState.torsoPos.z or nil)
savestates.marioBodyState_wingFlutter[slot] = ((m and m.marioBodyState and m.marioBodyState.wingFlutter) and m.marioBodyState.wingFlutter or nil)
savestates.marioObj_activeFlags[slot] = ((m and m.marioObj and m.marioObj.activeFlags) and m.marioObj.activeFlags or nil)
savestates.marioObj_areaTimer[slot] = ((m and m.marioObj and m.marioObj.areaTimer) and m.marioObj.areaTimer or nil)
savestates.marioObj_areaTimerDuration[slot] = ((m and m.marioObj and m.marioObj.areaTimerDuration) and m.marioObj.areaTimerDuration or nil)
savestates.marioObj_areaTimerType[slot] = ((m and m.marioObj and m.marioObj.areaTimerType) and m.marioObj.areaTimerType or nil)
savestates.marioObj_bhvDelayTimer[slot] = ((m and m.marioObj and m.marioObj.bhvDelayTimer) and m.marioObj.bhvDelayTimer or nil)
savestates.marioObj_collidedObjInteractTypes[slot] = ((m and m.marioObj and m.marioObj.collidedObjInteractTypes) and m.marioObj.collidedObjInteractTypes or nil)
savestates.marioObj_collisionData[slot] = ((m and m.marioObj and m.marioObj.collisionData) and m.marioObj.collisionData or nil)
savestates.marioObj_ctx[slot] = ((m and m.marioObj and m.marioObj.ctx) and m.marioObj.ctx or nil)
savestates.marioObj_globalPlayerIndex[slot] = ((m and m.marioObj and m.marioObj.globalPlayerIndex) and m.marioObj.globalPlayerIndex or nil)
savestates.marioObj_header_gfx_activeAreaIndex[slot] = ((m and m.marioObj and m.marioObj.header and m.marioObj.header.gfx and m.marioObj.header.gfx.activeAreaIndex) and m.marioObj.header.gfx.activeAreaIndex or nil)
savestates.marioObj_header_gfx_areaIndex[slot] = ((m and m.marioObj and m.marioObj.header and m.marioObj.header.gfx and m.marioObj.header.gfx.areaIndex) and m.marioObj.header.gfx.areaIndex or nil)
savestates.marioObj_header_gfx_disableAutomaticShadowPos[slot] = ((m and m.marioObj and m.marioObj.header and m.marioObj.header.gfx and m.marioObj.header.gfx.disableAutomaticShadowPos) and m.marioObj.header.gfx.disableAutomaticShadowPos or nil)
savestates.marioObj_header_gfx_shadowInvisible[slot] = ((m and m.marioObj and m.marioObj.header and m.marioObj.header.gfx and m.marioObj.header.gfx.shadowInvisible) and m.marioObj.header.gfx.shadowInvisible or nil)
savestates.marioObj_header_gfx_skipInViewCheck[slot] = ((m and m.marioObj and m.marioObj.header and m.marioObj.header.gfx and m.marioObj.header.gfx.skipInViewCheck) and m.marioObj.header.gfx.skipInViewCheck or nil)
savestates.marioObj_heldByPlayerIndex[slot] = ((m and m.marioObj and m.marioObj.heldByPlayerIndex) and m.marioObj.heldByPlayerIndex or nil)
savestates.marioObj_hitboxDownOffset[slot] = ((m and m.marioObj and m.marioObj.hitboxDownOffset) and m.marioObj.hitboxDownOffset or nil)
savestates.marioObj_hitboxHeight[slot] = ((m and m.marioObj and m.marioObj.hitboxHeight) and m.marioObj.hitboxHeight or nil)
savestates.marioObj_hitboxRadius[slot] = ((m and m.marioObj and m.marioObj.hitboxRadius) and m.marioObj.hitboxRadius or nil)
savestates.marioObj_hookRender[slot] = ((m and m.marioObj and m.marioObj.hookRender) and m.marioObj.hookRender or nil)
savestates.marioObj_hurtboxHeight[slot] = ((m and m.marioObj and m.marioObj.hurtboxHeight) and m.marioObj.hurtboxHeight or nil)
savestates.marioObj_hurtboxRadius[slot] = ((m and m.marioObj and m.marioObj.hurtboxRadius) and m.marioObj.hurtboxRadius or nil)
savestates.marioObj_parentObj[slot] = ((m and m.marioObj and m.marioObj.parentObj) and m.marioObj.parentObj or nil)
savestates.marioObj_platform[slot] = ((m and m.marioObj and m.marioObj.platform) and m.marioObj.platform or nil)
savestates.marioObj_prevObj[slot] = ((m and m.marioObj and m.marioObj.prevObj) and m.marioObj.prevObj or nil)
savestates.marioObj_setHome[slot] = ((m and m.marioObj and m.marioObj.setHome) and m.marioObj.setHome or nil)
savestates.marioObj_unused1[slot] = ((m and m.marioObj and m.marioObj.unused1) and m.marioObj.unused1 or nil)
savestates.marioObj_usingObj[slot] = ((m and m.marioObj and m.marioObj.usingObj) and m.marioObj.usingObj or nil)
savestates.minimumBoneY[slot] = ((m and m.minimumBoneY) and m.minimumBoneY or nil)
savestates.nonInstantWarpPos_x[slot] = ((m and m.nonInstantWarpPos and m.nonInstantWarpPos.x) and m.nonInstantWarpPos.x or nil)
savestates.nonInstantWarpPos_y[slot] = ((m and m.nonInstantWarpPos and m.nonInstantWarpPos.y) and m.nonInstantWarpPos.y or nil)
savestates.nonInstantWarpPos_z[slot] = ((m and m.nonInstantWarpPos and m.nonInstantWarpPos.z) and m.nonInstantWarpPos.z or nil)
savestates.numCoins[slot] = ((m and m.numCoins) and m.numCoins or nil)
savestates.numKeys[slot] = ((m and m.numKeys) and m.numKeys or nil)
savestates.numLives[slot] = ((m and m.numLives) and m.numLives or nil)
savestates.numStars[slot] = ((m and m.numStars) and m.numStars or nil)
savestates.particleFlags[slot] = ((m and m.particleFlags) and m.particleFlags or nil)
savestates.peakHeight[slot] = ((m and m.peakHeight) and m.peakHeight or nil)
savestates.pos_x[slot] = ((m and m.pos and m.pos.x) and m.pos.x or nil)
savestates.pos_y[slot] = ((m and m.pos and m.pos.y) and m.pos.y or nil)
savestates.pos_z[slot] = ((m and m.pos and m.pos.z) and m.pos.z or nil)
savestates.prevAction[slot] = ((m and m.prevAction) and m.prevAction or nil)
savestates.prevNumStarsForDialog[slot] = ((m and m.prevNumStarsForDialog) and m.prevNumStarsForDialog or nil)
savestates.quicksandDepth[slot] = ((m and m.quicksandDepth) and m.quicksandDepth or nil)
savestates.riddenObj[slot] = ((m and m.riddenObj) and m.riddenObj or nil)
savestates.slideVelX[slot] = ((m and m.slideVelX) and m.slideVelX or nil)
savestates.slideVelZ[slot] = ((m and m.slideVelZ) and m.slideVelZ or nil)
savestates.slideYaw[slot] = ((m and m.slideYaw) and m.slideYaw or nil)
savestates.spawnInfo[slot] = ((m and m.spawnInfo) and m.spawnInfo or nil)
savestates.specialTripleJump[slot] = ((m and m.specialTripleJump) and m.specialTripleJump or nil)
savestates.splineKeyframe[slot] = ((m and m.splineKeyframe) and m.splineKeyframe or nil)
savestates.splineKeyframeFraction[slot] = ((m and m.splineKeyframeFraction) and m.splineKeyframeFraction or nil)
savestates.splineState[slot] = ((m and m.splineState) and m.splineState or nil)
savestates.squishTimer[slot] = ((m and m.squishTimer) and m.squishTimer or nil)
savestates.statusForCamera_action[slot] = ((m and m.statusForCamera and m.statusForCamera.action) and m.statusForCamera.action or nil)
savestates.statusForCamera_cameraEvent[slot] = ((m and m.statusForCamera and m.statusForCamera.cameraEvent) and m.statusForCamera.cameraEvent or nil)
savestates.statusForCamera_faceAngle_x[slot] = ((m and m.statusForCamera and m.statusForCamera.faceAngle and m.statusForCamera.faceAngle.x) and m.statusForCamera.faceAngle.x or nil)
savestates.statusForCamera_faceAngle_y[slot] = ((m and m.statusForCamera and m.statusForCamera.faceAngle and m.statusForCamera.faceAngle.y) and m.statusForCamera.faceAngle.y or nil)
savestates.statusForCamera_faceAngle_z[slot] = ((m and m.statusForCamera and m.statusForCamera.faceAngle and m.statusForCamera.faceAngle.z) and m.statusForCamera.faceAngle.z or nil)
savestates.statusForCamera_headRotation_x[slot] = ((m and m.statusForCamera and m.statusForCamera.headRotation and m.statusForCamera.headRotation.x) and m.statusForCamera.headRotation.x or nil)
savestates.statusForCamera_headRotation_y[slot] = ((m and m.statusForCamera and m.statusForCamera.headRotation and m.statusForCamera.headRotation.y) and m.statusForCamera.headRotation.y or nil)
savestates.statusForCamera_headRotation_z[slot] = ((m and m.statusForCamera and m.statusForCamera.headRotation and m.statusForCamera.headRotation.z) and m.statusForCamera.headRotation.z or nil)
savestates.statusForCamera_pos_x[slot] = ((m and m.statusForCamera and m.statusForCamera.pos and m.statusForCamera.pos.x) and m.statusForCamera.pos.x or nil)
savestates.statusForCamera_pos_y[slot] = ((m and m.statusForCamera and m.statusForCamera.pos and m.statusForCamera.pos.y) and m.statusForCamera.pos.y or nil)
savestates.statusForCamera_pos_z[slot] = ((m and m.statusForCamera and m.statusForCamera.pos and m.statusForCamera.pos.z) and m.statusForCamera.pos.z or nil)
savestates.statusForCamera_unused[slot] = ((m and m.statusForCamera and m.statusForCamera.unused) and m.statusForCamera.unused or nil)
savestates.statusForCamera_usedObj[slot] = ((m and m.statusForCamera and m.statusForCamera.usedObj) and m.statusForCamera.usedObj or nil)
savestates.terrainSoundAddend[slot] = ((m and m.terrainSoundAddend) and m.terrainSoundAddend or nil)
savestates.twirlYaw[slot] = ((m and m.twirlYaw) and m.twirlYaw or nil)
savestates.unkB0[slot] = ((m and m.unkB0) and m.unkB0 or nil)
savestates.unkC4[slot] = ((m and m.unkC4) and m.unkC4 or nil)
savestates.usedObj[slot] = ((m and m.usedObj) and m.usedObj or nil)
savestates.vel_x[slot] = ((m and m.vel and m.vel.x) and m.vel.x or nil)
savestates.vel_y[slot] = ((m and m.vel and m.vel.y) and m.vel.y or nil)
savestates.vel_z[slot] = ((m and m.vel and m.vel.z) and m.vel.z or nil)
savestates.wall[slot] = ((m and m.wall) and m.wall or nil)
savestates.wallKickTimer[slot] = ((m and m.wallKickTimer) and m.wallKickTimer or nil)
savestates.wallNormal_x[slot] = ((m and m.wallNormal and m.wallNormal.x) and m.wallNormal.x or nil)
savestates.wallNormal_y[slot] = ((m and m.wallNormal and m.wallNormal.y) and m.wallNormal.y or nil)
savestates.wallNormal_z[slot] = ((m and m.wallNormal and m.wallNormal.z) and m.wallNormal.z or nil)
savestates.wasNetworkVisible[slot] = ((m and m.wasNetworkVisible) and m.wasNetworkVisible or nil)
savestates.waterLevel[slot] = ((m and m.waterLevel) and m.waterLevel or nil)
latest_savestate = slot
m.particleFlags = PARTICLE_SPARKLES
play_sound(SOUND_GENERAL_GRAND_STAR, m.marioObj.header.gfx.cameraToObject)
djui_popup_create(color .. "State saved to Slot " .. tostring(latest_savestate + 1) .. "!", 1)
return true
end
function load_state_slot(m, slot)
ready_to_load = nil
if (is_state_slot_not_empty(slot)) then
if (savestates.gNetworkPlayers_currLevelNum[slot] ~= gNetworkPlayers[0].currLevelNum or savestates.gNetworkPlayers_currAreaIndex[slot] ~= gNetworkPlayers[0].currAreaIndex or savestates.gNetworkPlayers_currActNum[slot] ~= gNetworkPlayers[0].currActNum) then
warp_to_level(savestates.gNetworkPlayers_currLevelNum[slot], savestates.gNetworkPlayers_currAreaIndex[slot], savestates.gNetworkPlayers_currActNum[slot])
wait_until_inited = slot
return false
else
if (m and m.action) then m.action = savestates.action[slot] end
if (m and m.actionArg) then m.actionArg = savestates.actionArg[slot] end
if (m and m.actionState) then m.actionState = savestates.actionState[slot] end
if (m and m.actionTimer) then m.actionTimer = savestates.actionTimer[slot] end
if (m and m.angleVel and m.angleVel.x) then m.angleVel.x = savestates.angleVel_x[slot] end
if (m and m.angleVel and m.angleVel.y) then m.angleVel.y = savestates.angleVel_y[slot] end
if (m and m.angleVel and m.angleVel.z) then m.angleVel.z = savestates.angleVel_z[slot] end
if (m and m.animation and m.animation.targetAnim) then m.animation.targetAnim = savestates.animation_targetAnim[slot] end
if (m and m.area and m.area.camera) then m.area.camera = savestates.area_camera[slot] end
if (m and m.area and m.area.flags) then m.area.flags = savestates.area_flags[slot] end
if (m and m.area and m.area.index) then m.area.index = savestates.area_index[slot] end
if (m and m.area and m.area.instantWarps) then m.area.instantWarps = savestates.area_instantWarps[slot] end
if (m and m.area and m.area.musicParam) then m.area.musicParam = savestates.area_musicParam[slot] end
if (m and m.area and m.area.musicParam2) then m.area.musicParam2 = savestates.area_musicParam2[slot] end
--if (m and m.area and m.area.numRedCoins) then m.area.numRedCoins = savestates.area_numRedCoins[slot] end
--if (m and m.area and m.area.numSecrets) then m.area.numSecrets = savestates.area_numSecrets[slot] end
if (m and m.area and m.area.objectSpawnInfos and m.area.objectSpawnInfos.activeAreaIndex) then m.area.objectSpawnInfos.activeAreaIndex = savestates.area_objectSpawnInfos_activeAreaIndex[slot] end
if (m and m.area and m.area.objectSpawnInfos and m.area.objectSpawnInfos.areaIndex) then m.area.objectSpawnInfos.areaIndex = savestates.area_objectSpawnInfos_areaIndex[slot] end
if (m and m.area and m.area.objectSpawnInfos and m.area.objectSpawnInfos.behaviorArg) then m.area.objectSpawnInfos.behaviorArg = savestates.area_objectSpawnInfos_behaviorArg[slot] end
if (m and m.area and m.area.objectSpawnInfos and m.area.objectSpawnInfos.startAngle and m.area.objectSpawnInfos.startAngle.x) then m.area.objectSpawnInfos.startAngle.x = savestates.area_objectSpawnInfos_startAngle_x[slot] end
if (m and m.area and m.area.objectSpawnInfos and m.area.objectSpawnInfos.startAngle and m.area.objectSpawnInfos.startAngle.y) then m.area.objectSpawnInfos.startAngle.y = savestates.area_objectSpawnInfos_startAngle_y[slot] end
if (m and m.area and m.area.objectSpawnInfos and m.area.objectSpawnInfos.startAngle and m.area.objectSpawnInfos.startAngle.z) then m.area.objectSpawnInfos.startAngle.z = savestates.area_objectSpawnInfos_startAngle_z[slot] end
if (m and m.area and m.area.objectSpawnInfos and m.area.objectSpawnInfos.startPos and m.area.objectSpawnInfos.startPos.x) then m.area.objectSpawnInfos.startPos.x = savestates.area_objectSpawnInfos_startPos_x[slot] end
if (m and m.area and m.area.objectSpawnInfos and m.area.objectSpawnInfos.startPos and m.area.objectSpawnInfos.startPos.y) then m.area.objectSpawnInfos.startPos.y = savestates.area_objectSpawnInfos_startPos_y[slot] end
if (m and m.area and m.area.objectSpawnInfos and m.area.objectSpawnInfos.startPos and m.area.objectSpawnInfos.startPos.z) then m.area.objectSpawnInfos.startPos.z = savestates.area_objectSpawnInfos_startPos_z[slot] end
if (m and m.area and m.area.objectSpawnInfos and m.area.objectSpawnInfos.unk18 and m.area.objectSpawnInfos.unk18.extraFlags) then m.area.objectSpawnInfos.unk18.extraFlags = savestates.area_objectSpawnInfos_unk18_extraFlags[slot] end
if (m and m.area and m.area.objectSpawnInfos and m.area.objectSpawnInfos.unk18 and m.area.objectSpawnInfos.unk18.flags) then m.area.objectSpawnInfos.unk18.flags = savestates.area_objectSpawnInfos_unk18_flags[slot] end
--if (m and m.area and m.area.paintingWarpNodes and m.area.paintingWarpNodes.destArea) then m.area.paintingWarpNodes.destArea = savestates.area_paintingWarpNodes_destArea[slot] end
--if (m and m.area and m.area.paintingWarpNodes and m.area.paintingWarpNodes.destLevel) then m.area.paintingWarpNodes.destLevel = savestates.area_paintingWarpNodes_destLevel[slot] end
--if (m and m.area and m.area.paintingWarpNodes and m.area.paintingWarpNodes.destNode) then m.area.paintingWarpNodes.destNode = savestates.area_paintingWarpNodes_destNode[slot] end
--if (m and m.area and m.area.paintingWarpNodes and m.area.paintingWarpNodes.id) then m.area.paintingWarpNodes.id = savestates.area_paintingWarpNodes_id[slot] end
if (m and m.area and m.area.terrainType) then m.area.terrainType = savestates.area_terrainType[slot] end
--if (m and m.area and m.area.warpNodes and m.area.warpNodes.next) then m.area.warpNodes.next = savestates.area_warpNodes_next[slot] end
--if (m and m.area and m.area.warpNodes and m.area.warpNodes.node and m.area.warpNodes.node.destArea) then m.area.warpNodes.node.destArea = savestates.area_warpNodes_node_destArea[slot] end
--if (m and m.area and m.area.warpNodes and m.area.warpNodes.node and m.area.warpNodes.node.destLevel) then m.area.warpNodes.node.destLevel = savestates.area_warpNodes_node_destLevel[slot] end
--if (m and m.area and m.area.warpNodes and m.area.warpNodes.node and m.area.warpNodes.node.destNode) then m.area.warpNodes.node.destNode = savestates.area_warpNodes_node_destNode[slot] end
--if (m and m.area and m.area.warpNodes and m.area.warpNodes.node and m.area.warpNodes.node.id) then m.area.warpNodes.node.id = savestates.area_warpNodes_node_id[slot] end
--if (m and m.area and m.area.warpNodes and m.area.warpNodes.object) then m.area.warpNodes.object = savestates.area_warpNodes_object[slot] end
if (m and m.bounceSquishTimer) then m.bounceSquishTimer = savestates.bounceSquishTimer[slot] end
if (m and m.bubbleObj) then m.bubbleObj = savestates.bubbleObj[slot] end
if (m and m.cap) then m.cap = savestates.cap[slot] end
if (m and m.capTimer) then m.capTimer = savestates.capTimer[slot] end
if (m and m.ceil) then m.ceil = savestates.ceil[slot] end
if (m and m.ceilHeight) then m.ceilHeight = savestates.ceilHeight[slot] end
if (m and m.character) then m.character = savestates.character[slot] end
if (m and m.collidedObjInteractTypes) then m.collidedObjInteractTypes = savestates.collidedObjInteractTypes[slot] end
--if (m and m.controller and m.controller.buttonDown) then m.controller.buttonDown = savestates.controller_buttonDown[slot] end
--if (m and m.controller and m.controller.buttonPressed) then m.controller.buttonPressed = savestates.controller_buttonPressed[slot] end
--if (m and m.controller and m.controller.extStickX) then m.controller.extStickX = savestates.controller_extStickX[slot] end
--if (m and m.controller and m.controller.extStickY) then m.controller.extStickY = savestates.controller_extStickY[slot] end
--if (m and m.controller and m.controller.port) then m.controller.port = savestates.controller_port[slot] end
--if (m and m.controller and m.controller.rawStickX) then m.controller.rawStickX = savestates.controller_rawStickX[slot] end
--if (m and m.controller and m.controller.rawStickY) then m.controller.rawStickY = savestates.controller_rawStickY[slot] end
--if (m and m.controller and m.controller.stickMag) then m.controller.stickMag = savestates.controller_stickMag[slot] end
--if (m and m.controller and m.controller.stickX) then m.controller.stickX = savestates.controller_stickX[slot] end
--if (m and m.controller and m.controller.stickY) then m.controller.stickY = savestates.controller_stickY[slot] end
if (m and m.curAnimOffset) then m.curAnimOffset = savestates.curAnimOffset[slot] end
if (m and m.currentRoom) then m.currentRoom = savestates.currentRoom[slot] end
if (m and m.doubleJumpTimer) then m.doubleJumpTimer = savestates.doubleJumpTimer[slot] end
if (m and m.faceAngle and m.faceAngle.x) then m.faceAngle.x = savestates.faceAngle_x[slot] end
if (m and m.faceAngle and m.faceAngle.y) then m.faceAngle.y = savestates.faceAngle_y[slot] end
if (m and m.faceAngle and m.faceAngle.z) then m.faceAngle.z = savestates.faceAngle_z[slot] end
if (m and m.fadeWarpOpacity) then m.fadeWarpOpacity = savestates.fadeWarpOpacity[slot] end
if (m and m.flags) then m.flags = savestates.flags[slot] end
if (m and m.floor) then m.floor = savestates.floor[slot] end
if (m and m.floorAngle) then m.floorAngle = savestates.floorAngle[slot] end
if (m and m.floorHeight) then m.floorHeight = savestates.floorHeight[slot] end
if (m and m.forwardVel) then m.forwardVel = savestates.forwardVel[slot] end
if (m and m.framesSinceA) then m.framesSinceA = savestates.framesSinceA[slot] end
if (m and m.framesSinceB) then m.framesSinceB = savestates.framesSinceB[slot] end
if (m and m.freeze) then m.freeze = savestates.freeze[slot] end
if (m and m.healCounter) then m.healCounter = savestates.healCounter[slot] end
if (m and m.health) then m.health = (autoheal_enabled and 0x880 or savestates.health[slot]) end
if (m and m.heldByObj) then m.heldByObj = savestates.heldByObj[slot] end
if (m and m.heldObj) then m.heldObj = savestates.heldObj[slot] end
if (m and m.hurtCounter) then m.hurtCounter = savestates.hurtCounter[slot] end
if (m and m.input) then m.input = savestates.input[slot] end
if (m and m.intendedMag) then m.intendedMag = savestates.intendedMag[slot] end
if (m and m.intendedYaw) then m.intendedYaw = savestates.intendedYaw[slot] end
if (m and m.interactObj) then m.interactObj = savestates.interactObj[slot] end
if (m and m.invincTimer) then m.invincTimer = savestates.invincTimer[slot] end
if (m and m.isSnoring) then m.isSnoring = savestates.isSnoring[slot] end
if (m and m.knockbackTimer) then m.knockbackTimer = savestates.knockbackTimer[slot] end
if (m and m.marioBodyState and m.marioBodyState.action) then m.marioBodyState.action = savestates.marioBodyState_action[slot] end
if (m and m.marioBodyState and m.marioBodyState.capState) then m.marioBodyState.capState = savestates.marioBodyState_capState[slot] end
if (m and m.marioBodyState and m.marioBodyState.eyeState) then m.marioBodyState.eyeState = savestates.marioBodyState_eyeState[slot] end
if (m and m.marioBodyState and m.marioBodyState.grabPos) then m.marioBodyState.grabPos = savestates.marioBodyState_grabPos[slot] end
if (m and m.marioBodyState and m.marioBodyState.handState) then m.marioBodyState.handState = savestates.marioBodyState_handState[slot] end
if (m and m.marioBodyState and m.marioBodyState.headAngle and m.marioBodyState.headAngle.x) then m.marioBodyState.headAngle.x = savestates.marioBodyState_headAngle_x[slot] end
if (m and m.marioBodyState and m.marioBodyState.headAngle and m.marioBodyState.headAngle.y) then m.marioBodyState.headAngle.y = savestates.marioBodyState_headAngle_y[slot] end
if (m and m.marioBodyState and m.marioBodyState.headAngle and m.marioBodyState.headAngle.z) then m.marioBodyState.headAngle.z = savestates.marioBodyState_headAngle_z[slot] end
if (m and m.marioBodyState and m.marioBodyState.headPos and m.marioBodyState.headPos.x) then m.marioBodyState.headPos.x = savestates.marioBodyState_headPos_x[slot] end
if (m and m.marioBodyState and m.marioBodyState.headPos and m.marioBodyState.headPos.y) then m.marioBodyState.headPos.y = savestates.marioBodyState_headPos_y[slot] end
if (m and m.marioBodyState and m.marioBodyState.headPos and m.marioBodyState.headPos.z) then m.marioBodyState.headPos.z = savestates.marioBodyState_headPos_z[slot] end
if (m and m.marioBodyState and m.marioBodyState.heldObjLastPosition and m.marioBodyState.heldObjLastPosition.x) then m.marioBodyState.heldObjLastPosition.x = savestates.marioBodyState_heldObjLastPosition_x[slot] end
if (m and m.marioBodyState and m.marioBodyState.heldObjLastPosition and m.marioBodyState.heldObjLastPosition.y) then m.marioBodyState.heldObjLastPosition.y = savestates.marioBodyState_heldObjLastPosition_y[slot] end
if (m and m.marioBodyState and m.marioBodyState.heldObjLastPosition and m.marioBodyState.heldObjLastPosition.z) then m.marioBodyState.heldObjLastPosition.z = savestates.marioBodyState_heldObjLastPosition_z[slot] end
if (m and m.marioBodyState and m.marioBodyState.modelState) then m.marioBodyState.modelState = savestates.marioBodyState_modelState[slot] end
if (m and m.marioBodyState and m.marioBodyState.punchState) then m.marioBodyState.punchState = savestates.marioBodyState_punchState[slot] end
if (m and m.marioBodyState and m.marioBodyState.torsoAngle and m.marioBodyState.torsoAngle.x) then m.marioBodyState.torsoAngle.x = savestates.marioBodyState_torsoAngle_x[slot] end
if (m and m.marioBodyState and m.marioBodyState.torsoAngle and m.marioBodyState.torsoAngle.y) then m.marioBodyState.torsoAngle.y = savestates.marioBodyState_torsoAngle_y[slot] end
if (m and m.marioBodyState and m.marioBodyState.torsoAngle and m.marioBodyState.torsoAngle.z) then m.marioBodyState.torsoAngle.z = savestates.marioBodyState_torsoAngle_z[slot] end
if (m and m.marioBodyState and m.marioBodyState.torsoPos and m.marioBodyState.torsoPos.x) then m.marioBodyState.torsoPos.x = savestates.marioBodyState_torsoPos_x[slot] end
if (m and m.marioBodyState and m.marioBodyState.torsoPos and m.marioBodyState.torsoPos.y) then m.marioBodyState.torsoPos.y = savestates.marioBodyState_torsoPos_y[slot] end
if (m and m.marioBodyState and m.marioBodyState.torsoPos and m.marioBodyState.torsoPos.z) then m.marioBodyState.torsoPos.z = savestates.marioBodyState_torsoPos_z[slot] end
if (m and m.marioBodyState and m.marioBodyState.wingFlutter) then m.marioBodyState.wingFlutter = savestates.marioBodyState_wingFlutter[slot] end
if (m and m.marioObj and m.marioObj.activeFlags) then m.marioObj.activeFlags = savestates.marioObj_activeFlags[slot] end
if (m and m.marioObj and m.marioObj.areaTimer) then m.marioObj.areaTimer = savestates.marioObj_areaTimer[slot] end
if (m and m.marioObj and m.marioObj.areaTimerDuration) then m.marioObj.areaTimerDuration = savestates.marioObj_areaTimerDuration[slot] end
if (m and m.marioObj and m.marioObj.areaTimerType) then m.marioObj.areaTimerType = savestates.marioObj_areaTimerType[slot] end
if (m and m.marioObj and m.marioObj.bhvDelayTimer) then m.marioObj.bhvDelayTimer = savestates.marioObj_bhvDelayTimer[slot] end
if (m and m.marioObj and m.marioObj.collidedObjInteractTypes) then m.marioObj.collidedObjInteractTypes = savestates.marioObj_collidedObjInteractTypes[slot] end
if (m and m.marioObj and m.marioObj.collisionData) then m.marioObj.collisionData = savestates.marioObj_collisionData[slot] end
if (m and m.marioObj and m.marioObj.ctx) then m.marioObj.ctx = savestates.marioObj_ctx[slot] end
if (m and m.marioObj and m.marioObj.globalPlayerIndex) then m.marioObj.globalPlayerIndex = savestates.marioObj_globalPlayerIndex[slot] end
if (m and m.marioObj and m.marioObj.header and m.marioObj.header.gfx and m.marioObj.header.gfx.activeAreaIndex) then m.marioObj.header.gfx.activeAreaIndex = savestates.marioObj_header_gfx_activeAreaIndex[slot] end
if (m and m.marioObj and m.marioObj.header and m.marioObj.header.gfx and m.marioObj.header.gfx.areaIndex) then m.marioObj.header.gfx.areaIndex = savestates.marioObj_header_gfx_areaIndex[slot] end
if (m and m.marioObj and m.marioObj.header and m.marioObj.header.gfx and m.marioObj.header.gfx.disableAutomaticShadowPos) then m.marioObj.header.gfx.disableAutomaticShadowPos = savestates.marioObj_header_gfx_disableAutomaticShadowPos[slot] end
if (m and m.marioObj and m.marioObj.header and m.marioObj.header.gfx and m.marioObj.header.gfx.shadowInvisible) then m.marioObj.header.gfx.shadowInvisible = savestates.marioObj_header_gfx_shadowInvisible[slot] end
if (m and m.marioObj and m.marioObj.header and m.marioObj.header.gfx and m.marioObj.header.gfx.skipInViewCheck) then m.marioObj.header.gfx.skipInViewCheck = savestates.marioObj_header_gfx_skipInViewCheck[slot] end
if (m and m.marioObj and m.marioObj.heldByPlayerIndex) then m.marioObj.heldByPlayerIndex = savestates.marioObj_heldByPlayerIndex[slot] end
if (m and m.marioObj and m.marioObj.hitboxDownOffset) then m.marioObj.hitboxDownOffset = savestates.marioObj_hitboxDownOffset[slot] end
if (m and m.marioObj and m.marioObj.hitboxHeight) then m.marioObj.hitboxHeight = savestates.marioObj_hitboxHeight[slot] end
if (m and m.marioObj and m.marioObj.hitboxRadius) then m.marioObj.hitboxRadius = savestates.marioObj_hitboxRadius[slot] end
if (m and m.marioObj and m.marioObj.hookRender) then m.marioObj.hookRender = savestates.marioObj_hookRender[slot] end
if (m and m.marioObj and m.marioObj.hurtboxHeight) then m.marioObj.hurtboxHeight = savestates.marioObj_hurtboxHeight[slot] end
if (m and m.marioObj and m.marioObj.hurtboxRadius) then m.marioObj.hurtboxRadius = savestates.marioObj_hurtboxRadius[slot] end
if (m and m.marioObj and m.marioObj.parentObj) then m.marioObj.parentObj = savestates.marioObj_parentObj[slot] end
if (m and m.marioObj and m.marioObj.platform) then m.marioObj.platform = savestates.marioObj_platform[slot] end
if (m and m.marioObj and m.marioObj.prevObj) then m.marioObj.prevObj = savestates.marioObj_prevObj[slot] end
if (m and m.marioObj and m.marioObj.setHome) then m.marioObj.setHome = savestates.marioObj_setHome[slot] end
if (m and m.marioObj and m.marioObj.unused1) then m.marioObj.unused1 = savestates.marioObj_unused1[slot] end
if (m and m.marioObj and m.marioObj.usingObj) then m.marioObj.usingObj = savestates.marioObj_usingObj[slot] end
if (m and m.minimumBoneY) then m.minimumBoneY = savestates.minimumBoneY[slot] end
if (m and m.nonInstantWarpPos and m.nonInstantWarpPos.x) then m.nonInstantWarpPos.x = savestates.nonInstantWarpPos_x[slot] end
if (m and m.nonInstantWarpPos and m.nonInstantWarpPos.y) then m.nonInstantWarpPos.y = savestates.nonInstantWarpPos_y[slot] end
if (m and m.nonInstantWarpPos and m.nonInstantWarpPos.z) then m.nonInstantWarpPos.z = savestates.nonInstantWarpPos_z[slot] end
--if (m and m.numCoins) then m.numCoins = savestates.numCoins[slot] end
--if (m and m.numKeys) then m.numKeys = savestates.numKeys[slot] end
if (m and m.numLives) then m.numLives = savestates.numLives[slot] end
--if (m and m.numStars) then m.numStars = savestates.numStars[slot] end
if (m and m.particleFlags) then m.particleFlags = savestates.particleFlags[slot] end
if (m and m.peakHeight) then m.peakHeight = savestates.peakHeight[slot] end
if (m and m.pos and m.pos.x) then m.pos.x = savestates.pos_x[slot] end
if (m and m.pos and m.pos.y) then m.pos.y = savestates.pos_y[slot] end
if (m and m.pos and m.pos.z) then m.pos.z = savestates.pos_z[slot] end
if (m and m.prevAction) then m.prevAction = savestates.prevAction[slot] end
if (m and m.prevNumStarsForDialog) then m.prevNumStarsForDialog = savestates.prevNumStarsForDialog[slot] end
if (m and m.quicksandDepth) then m.quicksandDepth = savestates.quicksandDepth[slot] end
if (m and m.riddenObj) then m.riddenObj = savestates.riddenObj[slot] end
if (m and m.slideVelX) then m.slideVelX = savestates.slideVelX[slot] end
if (m and m.slideVelZ) then m.slideVelZ = savestates.slideVelZ[slot] end
if (m and m.slideYaw) then m.slideYaw = savestates.slideYaw[slot] end
if (m and m.spawnInfo) then m.spawnInfo = savestates.spawnInfo[slot] end
if (m and m.specialTripleJump) then m.specialTripleJump = savestates.specialTripleJump[slot] end
if (m and m.splineKeyframe) then m.splineKeyframe = savestates.splineKeyframe[slot] end
if (m and m.splineKeyframeFraction) then m.splineKeyframeFraction = savestates.splineKeyframeFraction[slot] end
if (m and m.splineState) then m.splineState = savestates.splineState[slot] end
if (m and m.squishTimer) then m.squishTimer = savestates.squishTimer[slot] end
if (m and m.statusForCamera and m.statusForCamera.action) then m.statusForCamera.action = savestates.statusForCamera_action[slot] end
if (m and m.statusForCamera and m.statusForCamera.cameraEvent) then m.statusForCamera.cameraEvent = savestates.statusForCamera_cameraEvent[slot] end
if (m and m.statusForCamera and m.statusForCamera.faceAngle and m.statusForCamera.faceAngle.x) then m.statusForCamera.faceAngle.x = savestates.statusForCamera_faceAngle_x[slot] end
if (m and m.statusForCamera and m.statusForCamera.faceAngle and m.statusForCamera.faceAngle.y) then m.statusForCamera.faceAngle.y = savestates.statusForCamera_faceAngle_y[slot] end
if (m and m.statusForCamera and m.statusForCamera.faceAngle and m.statusForCamera.faceAngle.z) then m.statusForCamera.faceAngle.z = savestates.statusForCamera_faceAngle_z[slot] end
if (m and m.statusForCamera and m.statusForCamera.headRotation and m.statusForCamera.headRotation.x) then m.statusForCamera.headRotation.x = savestates.statusForCamera_headRotation_x[slot] end
if (m and m.statusForCamera and m.statusForCamera.headRotation and m.statusForCamera.headRotation.y) then m.statusForCamera.headRotation.y = savestates.statusForCamera_headRotation_y[slot] end
if (m and m.statusForCamera and m.statusForCamera.headRotation and m.statusForCamera.headRotation.z) then m.statusForCamera.headRotation.z = savestates.statusForCamera_headRotation_z[slot] end
if (m and m.statusForCamera and m.statusForCamera.pos and m.statusForCamera.pos.x) then m.statusForCamera.pos.x = savestates.statusForCamera_pos_x[slot] end
if (m and m.statusForCamera and m.statusForCamera.pos and m.statusForCamera.pos.y) then m.statusForCamera.pos.y = savestates.statusForCamera_pos_y[slot] end
if (m and m.statusForCamera and m.statusForCamera.pos and m.statusForCamera.pos.z) then m.statusForCamera.pos.z = savestates.statusForCamera_pos_z[slot] end
if (m and m.statusForCamera and m.statusForCamera.unused) then m.statusForCamera.unused = savestates.statusForCamera_unused[slot] end
if (m and m.statusForCamera and m.statusForCamera.usedObj) then m.statusForCamera.usedObj = savestates.statusForCamera_usedObj[slot] end
if (m and m.terrainSoundAddend) then m.terrainSoundAddend = savestates.terrainSoundAddend[slot] end
if (m and m.twirlYaw) then m.twirlYaw = savestates.twirlYaw[slot] end
if (m and m.unkB0) then m.unkB0 = savestates.unkB0[slot] end
if (m and m.unkC4) then m.unkC4 = savestates.unkC4[slot] end
if (m and m.usedObj) then m.usedObj = savestates.usedObj[slot] end
if (m and m.vel and m.vel.x) then m.vel.x = savestates.vel_x[slot] end
if (m and m.vel and m.vel.y) then m.vel.y = savestates.vel_y[slot] end
if (m and m.vel and m.vel.z) then m.vel.z = savestates.vel_z[slot] end
if (m and m.wall) then m.wall = savestates.wall[slot] end
if (m and m.wallKickTimer) then m.wallKickTimer = savestates.wallKickTimer[slot] end
if (m and m.wallNormal and m.wallNormal.x) then m.wallNormal.x = savestates.wallNormal_x[slot] end
if (m and m.wallNormal and m.wallNormal.y) then m.wallNormal.y = savestates.wallNormal_y[slot] end
if (m and m.wallNormal and m.wallNormal.z) then m.wallNormal.z = savestates.wallNormal_z[slot] end
if (m and m.wasNetworkVisible) then m.wasNetworkVisible = savestates.wasNetworkVisible[slot] end
if (m and m.waterLevel) then m.waterLevel = savestates.waterLevel[slot] end
latest_savestate = slot
m.particleFlags = PARTICLE_HORIZONTAL_STAR
play_sound(SOUND_GENERAL_GRAND_STAR_JUMP, m.marioObj.header.gfx.cameraToObject)
if slot == 0 then
djui_popup_create("\\#ffa0a0\\State loaded from Slot 1!",1)
elseif slot == 1 then
djui_popup_create("\\#a0ffa0\\State loaded from Slot 2!",1)
elseif slot == 2 then
djui_popup_create("\\#a0a0ff\\State loaded from Slot 3!",1)
elseif slot == 3 then
djui_popup_create("\\#ffffa0\\State loaded from Slot 4!",1)
end
return true
end
else
play_sound(SOUND_GENERAL_FLAME_OUT, m.marioObj.header.gfx.cameraToObject)
if slot == 0 then
djui_popup_create("\\#a0a0a0\\No State found in Slot 1!",1)
elseif slot == 1 then
djui_popup_create("\\#a0a0a0\\No State found in Slot 2!",1)
elseif slot == 2 then
djui_popup_create("\\#a0a0a0\\No State found in Slot 3!",1)
elseif slot == 3 then
djui_popup_create("\\#a0a0a0\\No State found in Slot 4!",1)
end
return false
end
end
function delete_state_slot(m, slot)
savestates.pos_x[slot] = nil
savestates.pos_y[slot] = nil
savestates.pos_z[slot] = nil
end
function is_state_slot_not_empty(slot)
return ((savestates.pos_x[slot] ~= nil and savestates.pos_y[slot] ~= nil and savestates.pos_z[slot] ~= nil) and true or false)
end
function on_cmd_autoload()
if (autoload_enabled == true) then
autoload_enabled = false
djui_chat_message_create("\\#ff8080\\AutoLoad latest savestate on death is now \\#ff0000\\DISABLED")
else
autoload_enabled = true
djui_chat_message_create("\\#80ff80\\AutoLoad latest savestate on death is now \\#00ff00\\ENABLED")
end
return true
end
function on_cmd_autoheal()
if (autoheal_enabled == true) then
autoheal_enabled = false
djui_chat_message_create("\\#ff8080\\AutoHeal after loading savestate is now \\#ff0000\\DISABLED")
else
autoheal_enabled = true
djui_chat_message_create("\\#80ff80\\AutoHeal after loading savestate is now \\#00ff00\\ENABLED")
end
return true
end
function on_cmd_savestate()
djui_chat_message_create("\\#40b0ff\\[\\#40ffff\\LOCAL SAVESTATE-MOD SLOTS AND SETTINGS INFOS\\#40b0ff\\]")
djui_chat_message_create("\\#b0b0b0\\AutoLoad\\#808080\\: " .. (autoload_enabled and "\\#80ff80\\ON" or "\\#ff8080\\OFF") .. " " .. (is_state_slot_not_empty(latest_savestate) and ("\\#ffff80\\(Latest: Slot " .. tostring(latest_savestate + 1) .. ")") or ("\\#ff8040\\(Latest: MissingNo)")) .. " " .. "\\#b0b0b0\\AutoHeal\\#808080\\: " .. (autoheal_enabled and "\\#80ff80\\ON" or "\\#ff8080\\OFF"))
djui_chat_message_create("\\#b0b0b0\\Save-Slot 1\\#808080\\: " .. (is_state_slot_not_empty(0) and "\\#80ff80\\SET" or "\\#ff8080\\EMPTY") .. " " .. "\\#b0b0b0\\Save-Slot 2\\#808080\\: " .. (is_state_slot_not_empty(1) and "\\#80ff80\\SET" or "\\#ff8080\\EMPTY"))
djui_chat_message_create("\\#b0b0b0\\Save-Slot 3\\#808080\\: " .. (is_state_slot_not_empty(2) and "\\#80ff80\\SET" or "\\#ff8080\\EMPTY") .. " " .. "\\#b0b0b0\\Save-Slot 4\\#808080\\: " .. (is_state_slot_not_empty(3) and "\\#80ff80\\SET" or "\\#ff8080\\EMPTY"))
return true
end
hook_event(HOOK_ON_PLAYER_CONNECTED, on_join)
hook_event(HOOK_ON_PLAYER_DISCONNECTED, on_leave)
hook_event(HOOK_ON_DEATH, on_death)
hook_event(HOOK_ON_LEVEL_INIT, on_level_init)
hook_event(HOOK_MARIO_UPDATE, on_mario_update)
hook_chat_command("autoload", "Automatically load the latest savestate on death!", on_cmd_autoload)
hook_chat_command("al", "Automatically load the latest savestate on death!", on_cmd_autoload)
hook_chat_command("autoheal", "Automatically heal mario after loading a savestates!", on_cmd_autoheal)
hook_chat_command("ah", "Automatically heal mario after loading a savestates!", on_cmd_autoheal)
hook_chat_command("savestate", "List infos about your local savestates and settings!", on_cmd_savestate)
hook_chat_command("savestates", "List infos about your local savestates and settings!", on_cmd_savestate)
hook_chat_command("ss", "List infos about your local savestates and settings!", on_cmd_savestate)

View File

@ -17,6 +17,11 @@ static bool str_starts_with(const char* pre, char* str) {
}
bool exec_dev_chat_command(char* command) {
if (strcmp("/warp", command) == 0) {
djui_chat_message_create("Missing parameters: [LEVEL] [AREA] [ACT]");
return true;
}
if (gNetworkSystem == &gNetworkSystemSocket && str_starts_with("/warp ", command)) {
static const struct { const char *name; s32 num; } sLevelNumByName[] = {
#undef STUB_LEVEL
@ -103,11 +108,21 @@ bool exec_dev_chat_command(char* command) {
return true;
}
if (strcmp("/lua", command) == 0) {
djui_chat_message_create("Missing parameter: [LUA]");
return true;
}
if (str_starts_with("/lua ", command)) {
smlua_exec_str(&command[5]);
return true;
}
if (strcmp("/luaf", command) == 0) {
djui_chat_message_create("Missing parameter: [FILENAME]");
return true;
}
if (str_starts_with("/luaf ", command)) {
smlua_exec_file(&command[6]);
return true;

View File

@ -0,0 +1 @@

View File

@ -0,0 +1,12 @@
#ifndef CHAT_COMMAND_H
#define CHAT_COMMAND_H
#include <stdbool.h>
#include "pc/djui/djui.h"
typedef struct ChatCommand {
char* commandName;
bool (*execute)(char* command);
void (*display)();
} ChatCommand;
#endif

View File

@ -0,0 +1,37 @@
#include "chat_command_manager.h"
#include <string.h>
#define MAX_COMMANDS 512
typedef struct {
const char* name;
bool (*execute)(char* args);
const char* description;
} CommandEntry;
static CommandEntry sCommands[MAX_COMMANDS];
static s32 sNumCommands = 0;
void register_chat_command(const char* commandName, bool (*execute)(char* args), const char* description) {
if (sNumCommands < MAX_COMMANDS) {
sCommands[sNumCommands].name = commandName;
sCommands[sNumCommands].execute = execute;
sCommands[sNumCommands].description = description;
sNumCommands++;
}
}
bool execute_chat_command(char* commandName, char* args) {
for (s32 i = 0; i < sNumCommands; i++) {
if (strcmp(sCommands[i].name, commandName) == 0) {
return sCommands[i].execute(args);
}
}
return false;
}
void display_all_chat_commands() {
for (s32 i = 0; i < sNumCommands; i++) {
djui_chat_message_create(sCommands[i].description);
}
}

View File

@ -0,0 +1,11 @@
#ifndef CHAT_COMMAND_MANAGER_H
#define CHAT_COMMAND_MANAGER_H
#include <stdbool.h>
#include "chat_command.h"
#include "pc/djui/djui.h"
void register_chat_command(const char* commandName, bool (*execute)(char* args), const char* description);
bool execute_chat_command(char* commandName, char* args);
void display_all_chat_commands();
#endif

View File

@ -119,6 +119,11 @@ bool exec_chat_command(char* command) {
return true;
}
if (strcmp("/kick", command) == 0) {
djui_chat_message_create(DLANG(CHAT, PLAYER_NOT_FOUND));
return true;
}
if (str_starts_with("/kick ", command)) {
if (gNetworkType != NT_SERVER && !npl->moderator) {
djui_chat_message_create(DLANG(CHAT, NO_PERMS));
@ -142,6 +147,11 @@ bool exec_chat_command(char* command) {
return true;
}
if (strcmp("/ban", command) == 0) {
djui_chat_message_create(DLANG(CHAT, PLAYER_NOT_FOUND));
return true;
}
if (str_starts_with("/ban ", command)) {
if (gNetworkType != NT_SERVER && !npl->moderator) {
djui_chat_message_create(DLANG(CHAT, NO_PERMS));
@ -165,6 +175,11 @@ bool exec_chat_command(char* command) {
return true;
}
if (strcmp("/permban", command) == 0) {
djui_chat_message_create(DLANG(CHAT, PLAYER_NOT_FOUND));
return true;
}
if (str_starts_with("/permban ", command)) {
if (gNetworkType != NT_SERVER && !npl->moderator) {
djui_chat_message_create(DLANG(CHAT, NO_PERMS));
@ -188,7 +203,12 @@ bool exec_chat_command(char* command) {
return true;
}
if (str_starts_with("/moderator ", command)) {
if (strcmp("/moderator", command) == 0) {
djui_chat_message_create(DLANG(CHAT, PLAYER_NOT_FOUND));
return true;
}
if (str_starts_with("/moderator ", command)) {
if (gNetworkType != NT_SERVER) {
djui_chat_message_create(DLANG(CHAT, SERVER_ONLY));
return true;

View File

@ -25,6 +25,8 @@ static void print_help(void) {
printf("%-20s\tStarts the game and creates a new server.\n", "--server PORT");
printf("%-20s\tStarts the game and joins an existing server.\n", "--client IP PORT");
printf("%-20s\tStarts the game using a poolsize of your choice.\n", "--poolsize POOLSIZE");
printf("%-20s\tStarts the game with a specific playername.\n", "--playername PLAYERNAME");
printf("%-20s\tStarts the game with a random playername.\n", "--randomplayername");
}
static inline int arg_string(const char *name, const char *value, char *target, int maxLength) {
@ -86,6 +88,12 @@ bool parse_cli_opts(int argc, char* argv[]) {
else if (strcmp(argv[i], "--savepath") == 0 && (i + 1) < argc)
arg_string("--savepath", argv[++i], gCLIOpts.SavePath, SYS_MAX_PATH);
else if (strcmp(argv[i], "--playername") == 0 && (i + 1) < argc)
arg_string("--playername", argv[++i], gCLIOpts.PlayerName, MAX_PLAYER_STRING);
else if (strcmp(argv[i], "--randomplayername") == 0)
gCLIOpts.RandomPlayerName = 1;
// Print help
else if (strcmp(argv[i], "--help") == 0) {
print_help();

View File

@ -2,6 +2,7 @@
#define _CLIOPTS_H
#include "platform.h"
#include "pc/configfile.h"
enum NetworkType {
NT_NONE,
@ -22,6 +23,8 @@ struct PCCLIOptions {
char ConfigFile[SYS_MAX_PATH];
char SavePath[SYS_MAX_PATH];
char GameDir[SYS_MAX_PATH];
char PlayerName[MAX_PLAYER_STRING];
unsigned int RandomPlayerName;
};
extern struct PCCLIOptions gCLIOpts;

View File

@ -1,4 +1,5 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pc/network/network.h"
#include "pc/lua/smlua_hooks.h"
@ -9,6 +10,90 @@ struct DjuiChatBox* gDjuiChatBox = NULL;
bool gDjuiChatBoxFocus = false;
static bool sDjuiChatBoxClearText = false;
#define MAX_HISTORY_SIZE 256
#define MAX_MSG_LENGTH 201
typedef struct {
s32 initialized;
s32 size;
char messages[MAX_HISTORY_SIZE][MAX_MSG_LENGTH];
s32 currentIndex;
char currentMessage[MAX_MSG_LENGTH];
} ArrayList;
ArrayList sentHistory;
static s32 sCommandsTabCompletionIndex = -1;
static char sCommandsTabCompletionOriginalText[MAX_MSG_LENGTH];
static s32 sPlayersTabCompletionIndex = -1;
static char sPlayersTabCompletionOriginalText[MAX_MSG_LENGTH];
void reset_tab_completion_commands(void) {
sCommandsTabCompletionIndex = -1;
snprintf(sCommandsTabCompletionOriginalText, MAX_MSG_LENGTH, "%s", "");
}
void reset_tab_completion_players(void) {
sPlayersTabCompletionIndex = -1;
snprintf(sPlayersTabCompletionOriginalText, MAX_MSG_LENGTH, "%s", "");
}
void reset_tab_completion_all(void) {
reset_tab_completion_commands();
reset_tab_completion_players();
}
void sent_history_init(ArrayList *arrayList) {
if (!arrayList->initialized) {
arrayList->size = 0;
arrayList->initialized = 1;
arrayList->currentIndex = -1;
snprintf(arrayList->currentMessage, MAX_MSG_LENGTH, "%s", "");
}
}
void sent_history_add_message(ArrayList *arrayList, const char *newMessage) {
if (arrayList->size == MAX_HISTORY_SIZE) {
for (s32 i = 1; i < MAX_HISTORY_SIZE; i++) {
snprintf(arrayList->messages[i-1], MAX_MSG_LENGTH, "%s", arrayList->messages[i]);
}
arrayList->size--;
}
snprintf(arrayList->messages[arrayList->size], MAX_MSG_LENGTH, "%s", newMessage);
arrayList->messages[arrayList->size][MAX_MSG_LENGTH - 1] = '\0';
arrayList->size++;
}
void sent_history_update_current_message(ArrayList *arrayList, const char *message) {
if (arrayList->currentIndex == -1) {
snprintf(arrayList->currentMessage, MAX_MSG_LENGTH, "%s", message);
}
}
void sent_history_navigate(ArrayList *arrayList, bool navigateUp) {
if (navigateUp) {
if (arrayList->currentIndex == -1) {
arrayList->currentIndex = arrayList->size - 1;
} else if (arrayList->currentIndex > 1) {
arrayList->currentIndex = arrayList->currentIndex - 1;
} else {
arrayList->currentIndex = 0;
}
} else {
if (arrayList->currentIndex == -1 || arrayList->currentIndex == arrayList->size - 1) {
arrayList->currentIndex = -1;
} else if (arrayList->currentIndex > -1) {
arrayList->currentIndex = arrayList->currentIndex + 1;
}
}
djui_inputbox_set_text(gDjuiChatBox->chatInput, arrayList->currentIndex == -1 ? arrayList->currentMessage : arrayList->messages[arrayList->currentIndex]);
djui_inputbox_move_cursor_to_end(gDjuiChatBox->chatInput);
}
void sent_history_reset_navigation(ArrayList *arrayList) {
snprintf(arrayList->currentMessage, MAX_MSG_LENGTH, "%s", "");
arrayList->currentIndex = -1;
}
bool djui_chat_box_render(struct DjuiBase* base) {
struct DjuiChatBox* chatBox = (struct DjuiChatBox*)base;
struct DjuiBase* ccBase = &chatBox->chatContainer->base;
@ -39,10 +124,14 @@ static void djui_chat_box_input_enter(struct DjuiInputbox* chatInput) {
djui_interactable_set_input_focus(NULL);
if (strlen(chatInput->buffer) != 0) {
sent_history_add_message(&sentHistory, chatInput->buffer);
if (chatInput->buffer[0] == '/') {
if (!exec_chat_command(chatInput->buffer)) {
djui_chat_message_create(DLANG(CHAT, UNRECOGNIZED));
if (strcmp(chatInput->buffer, "/help") == 0 || strcmp(chatInput->buffer, "/?") == 0) {
display_chat_commands();
} else if (!exec_chat_command(chatInput->buffer)) {
char extendedUnknownCommandMessage[MAX_MSG_LENGTH];
snprintf(extendedUnknownCommandMessage, sizeof(extendedUnknownCommandMessage), "%s (/help)", DLANG(CHAT, UNRECOGNIZED));
djui_chat_message_create(extendedUnknownCommandMessage);
}
} else {
djui_chat_message_create_from(gNetworkPlayerLocal->globalIndex, chatInput->buffer);
@ -62,7 +151,258 @@ static void djui_chat_box_input_escape(struct DjuiInputbox* chatInput) {
if (gDjuiChatBoxFocus) { djui_chat_box_toggle(); }
}
static char* get_main_command_from_input(const char* input) {
char* spacePos = strrchr(input, ' ');
if (spacePos == NULL) {
return NULL;
}
size_t len = spacePos - input;
char* command = (char*) malloc(len + 1);
snprintf(command, len + 1, "%s", input);
command[len] = '\0';
return command;
}
static bool complete_subcommand(const char* mainCommand, const char* subCommandPrefix) {
char** subcommands = smlua_get_chat_subcommands_list(mainCommand);
if (!subcommands || !subcommands[0]) {
return false;
}
s32 foundSubCommandsCount = 0;
for (s32 i = 0; subcommands[i] != NULL; i++) {
if (strncmp(subcommands[i], subCommandPrefix, strlen(subCommandPrefix)) == 0) {
foundSubCommandsCount++;
}
}
bool completionSuccess = false;
if (foundSubCommandsCount > 0) {
sCommandsTabCompletionIndex = (sCommandsTabCompletionIndex + 1) % foundSubCommandsCount;
s32 currentIndex = 0;
for (s32 i = 0; subcommands[i] != NULL; i++) {
if (strncmp(subcommands[i], subCommandPrefix, strlen(subCommandPrefix)) == 0) {
if (currentIndex == sCommandsTabCompletionIndex) {
char completion[MAX_MSG_LENGTH];
snprintf(completion, MAX_MSG_LENGTH, "/%s %s", mainCommand, subcommands[i]);
djui_inputbox_set_text(gDjuiChatBox->chatInput, completion);
djui_inputbox_move_cursor_to_end(gDjuiChatBox->chatInput);
completionSuccess = true;
break;
}
currentIndex++;
}
}
}
for (s32 i = 0; subcommands[i] != NULL; i++) {
free(subcommands[i]);
}
free(subcommands);
return completionSuccess;
}
typedef struct {
char word[MAX_MSG_LENGTH];
s32 index;
} CurrentWordInfo;
CurrentWordInfo get_current_word_info(char* buffer, s32 position) {
CurrentWordInfo info;
memset(info.word, 0, MAX_MSG_LENGTH);
info.index = -1;
s32 currentWordStart = position;
s32 currentWordEnd = position;
while (currentWordStart > 0 && buffer[currentWordStart - 1] != ' ') {
currentWordStart--;
}
while (buffer[currentWordEnd] != '\0' && buffer[currentWordEnd] != ' ') {
currentWordEnd++;
}
s32 wordLength = currentWordEnd - currentWordStart;
if (wordLength > MAX_MSG_LENGTH - 1) {
wordLength = MAX_MSG_LENGTH - 1;
}
snprintf(info.word, wordLength + 1, "%.*s", wordLength, &buffer[currentWordStart]);
s32 wordCount = 0;
for (s32 i = 0; i <= currentWordStart; i++) {
if (buffer[i] == ' ' || i == 0) {
wordCount++;
}
}
info.index = wordCount;
return info;
}
void djui_inputbox_replace_current_word(struct DjuiInputbox* inputbox, char* text) {
if (!inputbox || !text) { return; }
s32 currentWordStart = inputbox->selection[0];
s32 currentWordEnd = inputbox->selection[0];
while (currentWordStart > 0 && inputbox->buffer[currentWordStart - 1] != ' ') { currentWordStart--; }
while (inputbox->buffer[currentWordEnd] != '\0' && inputbox->buffer[currentWordEnd] != ' ') { currentWordEnd++; }
char newBuffer[MAX_MSG_LENGTH];
snprintf(newBuffer, MAX_MSG_LENGTH, "%.*s%s%s", currentWordStart, inputbox->buffer, text, &inputbox->buffer[currentWordEnd]);
djui_inputbox_set_text(inputbox, newBuffer);
djui_inputbox_move_cursor_to_position(inputbox, currentWordStart + strlen(text));
}
static bool complete_player_name(const char* namePrefix) {
char** playerNames = smlua_get_chat_player_list();
if (!playerNames || !playerNames[0]) {
if (playerNames) {
free(playerNames);
}
return false;
}
s32 foundNamesCount = 0;
for (s32 i = 0; playerNames[i] != NULL; i++) {
if (strncmp(playerNames[i], namePrefix, strlen(namePrefix)) == 0) {
foundNamesCount++;
}
}
bool completionSuccess = false;
if (foundNamesCount > 0) {
sPlayersTabCompletionIndex = (sPlayersTabCompletionIndex + 1) % foundNamesCount;
s32 currentIndex = 0;
for (s32 i = 0; playerNames[i] != NULL; i++) {
if (strncmp(playerNames[i], namePrefix, strlen(namePrefix)) == 0) {
if (currentIndex == sPlayersTabCompletionIndex) {
djui_inputbox_replace_current_word(gDjuiChatBox->chatInput, playerNames[i]);
completionSuccess = true;
break;
}
currentIndex++;
}
}
}
for (s32 i = 0; playerNames[i] != NULL; i++) {
free(playerNames[i]);
}
free(playerNames);
return completionSuccess;
}
static bool handle_tab_completion() {
bool alreadyTabCompleted = false;
if (gDjuiChatBox->chatInput->buffer[0] == '/') {
char* spacePosition = strrchr(sCommandsTabCompletionOriginalText, ' ');
if (spacePosition != NULL) {
char* mainCommand = get_main_command_from_input(sCommandsTabCompletionOriginalText);
if (mainCommand) {
if (!complete_subcommand(mainCommand + 1, spacePosition + 1)) {
reset_tab_completion_all();
} else {
alreadyTabCompleted = true;
}
free(mainCommand);
}
} else {
if (sCommandsTabCompletionIndex == -1) {
snprintf(sCommandsTabCompletionOriginalText, MAX_MSG_LENGTH, "%s", gDjuiChatBox->chatInput->buffer);
}
char* bufferWithoutSlash = sCommandsTabCompletionOriginalText + 1;
char** commands = smlua_get_chat_maincommands_list();
s32 foundCommandsCount = 0;
for (s32 i = 0; commands[i] != NULL; i++) {
if (strncmp(commands[i], bufferWithoutSlash, strlen(bufferWithoutSlash)) == 0) {
foundCommandsCount++;
}
}
if (foundCommandsCount > 0) {
sCommandsTabCompletionIndex = (sCommandsTabCompletionIndex + 1) % foundCommandsCount;
s32 currentIndex = 0;
for (s32 i = 0; commands[i] != NULL; i++) {
if (strncmp(commands[i], bufferWithoutSlash, strlen(bufferWithoutSlash)) == 0) {
if (currentIndex == sCommandsTabCompletionIndex) {
char completion[MAX_MSG_LENGTH];
snprintf(completion, MAX_MSG_LENGTH, "/%s", commands[i]);
djui_inputbox_set_text(gDjuiChatBox->chatInput, completion);
djui_inputbox_move_cursor_to_end(gDjuiChatBox->chatInput);
alreadyTabCompleted = true;
}
currentIndex++;
}
}
} else {
char* spacePositionB = strrchr(sCommandsTabCompletionOriginalText, ' ');
if (spacePositionB != NULL) {
char* mainCommandB = get_main_command_from_input(sCommandsTabCompletionOriginalText);
if (mainCommandB) {
if (!complete_subcommand(mainCommandB + 1, spacePositionB + 1)) {
reset_tab_completion_all();
} else {
alreadyTabCompleted = true;
}
free(mainCommandB);
}
}
}
for (s32 i = 0; commands[i] != NULL; i++) {
free(commands[i]);
}
free(commands);
}
}
if (!alreadyTabCompleted) {
if (gDjuiChatBox->chatInput->selection[0] != gDjuiChatBox->chatInput->selection[1]) {
alreadyTabCompleted = true;
}
}
if (!alreadyTabCompleted) {
CurrentWordInfo wordCurrent = get_current_word_info(gDjuiChatBox->chatInput->buffer, gDjuiChatBox->chatInput->selection[0]);
if (gDjuiChatBox->chatInput->buffer[0] == '/') {
if (wordCurrent.index == 1 && smlua_maincommand_exists(wordCurrent.word + 1)) {
alreadyTabCompleted = true;
} else if (wordCurrent.index == 2) {
CurrentWordInfo worldMainCommand = get_current_word_info(gDjuiChatBox->chatInput->buffer, 0);
if (smlua_maincommand_exists(worldMainCommand.word + 1) && smlua_subcommand_exists(worldMainCommand.word + 1, wordCurrent.word)) {
alreadyTabCompleted = true;
}
}
}
}
if (!alreadyTabCompleted) {
CurrentWordInfo wordInfo = get_current_word_info(gDjuiChatBox->chatInput->buffer, gDjuiChatBox->chatInput->selection[0]);
if (wordInfo.index != -1) {
if (sPlayersTabCompletionIndex == -1) {
snprintf(sPlayersTabCompletionOriginalText, MAX_MSG_LENGTH, "%s", wordInfo.word);
}
if (!complete_player_name(sPlayersTabCompletionOriginalText)) {
reset_tab_completion_players();
} else {
alreadyTabCompleted = true;
}
}
}
}
static bool djui_chat_box_input_on_key_down(struct DjuiBase* base, int scancode) {
sent_history_init(&sentHistory);
if (gDjuiChatBox == NULL) { return false; }
f32 yMax = gDjuiChatBox->chatContainer->base.elem.height - gDjuiChatBox->chatFlow->base.height.value;
@ -71,26 +411,68 @@ static bool djui_chat_box_input_on_key_down(struct DjuiBase* base, int scancode)
bool canScrollDown = (*yValue < 0);
f32 pageAmount = gDjuiChatBox->chatContainer->base.elem.height * 3.0f / 4.0f;
char previousText[MAX_MSG_LENGTH];
snprintf(previousText, MAX_MSG_LENGTH, "%s", gDjuiChatBox->chatInput->buffer);
switch (scancode) {
case SCANCODE_UP:
gDjuiChatBox->scrolling = true;
if (canScrollDown) { *yValue = fmin(*yValue + 15, 0); }
sent_history_update_current_message(&sentHistory, gDjuiChatBox->chatInput->buffer);
sent_history_navigate(&sentHistory, true);
if (strcmp(previousText, gDjuiChatBox->chatInput->buffer) != 0) {
reset_tab_completion_all();
}
return true;
case SCANCODE_DOWN:
gDjuiChatBox->scrolling = true;
if (canScrollUp) { *yValue = fmax(*yValue - 15, yMax); }
sent_history_update_current_message(&sentHistory, gDjuiChatBox->chatInput->buffer);
sent_history_navigate(&sentHistory, false);
if (strcmp(previousText, gDjuiChatBox->chatInput->buffer) != 0) {
reset_tab_completion_all();
}
return true;
case SCANCODE_PAGE_UP:
gDjuiChatBox->scrolling = true;
if (canScrollDown) { *yValue = fmin(*yValue + pageAmount, 0); }
if (canScrollDown) { *yValue = fmin(*yValue + 15, 0); }
return true;
case SCANCODE_PAGE_DOWN:
gDjuiChatBox->scrolling = true;
if (canScrollUp) { *yValue = fmax(*yValue - 15, yMax); }
return true;
case SCANCODE_POS1:
gDjuiChatBox->scrolling = true;
if (canScrollDown) { *yValue = fmin(*yValue + pageAmount, 0); }
return true;
case SCANCODE_END:
gDjuiChatBox->scrolling = true;
if (canScrollUp) { *yValue = fmax(*yValue - pageAmount, yMax); }
return true;
case SCANCODE_ENTER: djui_chat_box_input_enter(gDjuiChatBox->chatInput); return true;
case SCANCODE_ESCAPE: djui_chat_box_input_escape(gDjuiChatBox->chatInput); return true;
default: return djui_inputbox_on_key_down(base, scancode);
case SCANCODE_TAB:
handle_tab_completion();
return true;
case SCANCODE_ENTER:
reset_tab_completion_all();
sent_history_reset_navigation(&sentHistory);
djui_chat_box_input_enter(gDjuiChatBox->chatInput);
return true;
case SCANCODE_ESCAPE:
reset_tab_completion_all();
sent_history_reset_navigation(&sentHistory);
djui_chat_box_input_escape(gDjuiChatBox->chatInput);
return true;
default:
bool returnValueOnOtherKeyDown = djui_inputbox_on_key_down(base, scancode);
if (strcmp(previousText, gDjuiChatBox->chatInput->buffer) != 0) {
reset_tab_completion_all();
}
return returnValueOnOtherKeyDown;
}
}
static void djui_chat_box_input_on_text_input(struct DjuiBase *base, char* text) {
size_t expectedIndex = strlen(gDjuiChatBox->chatInput->buffer);
bool isTextDifferent = (expectedIndex >= MAX_MSG_LENGTH) || (gDjuiChatBox->chatInput->buffer[expectedIndex] != text[0]);
djui_inputbox_on_text_input(base, text);
if (isTextDifferent) {
reset_tab_completion_all();
}
}
@ -145,6 +527,7 @@ struct DjuiChatBox* djui_chat_box_create(void) {
djui_base_set_size(ciBase, 1.0f, 32);
djui_base_set_alignment(ciBase, DJUI_HALIGN_LEFT, DJUI_VALIGN_BOTTOM);
djui_interactable_hook_key(&chatInput->base, djui_chat_box_input_on_key_down, djui_inputbox_on_key_up);
djui_interactable_hook_text_input(&chatInput->base, djui_chat_box_input_on_text_input);
chatBox->chatInput = chatInput;
gDjuiChatBox = chatBox;

View File

@ -54,6 +54,20 @@ void djui_inputbox_select_all(struct DjuiInputbox* inputbox) {
inputbox->selection[0] = djui_unicode_len(inputbox->buffer);
}
void djui_inputbox_move_cursor_to_end(struct DjuiInputbox* inputbox) {
inputbox->selection[1] = djui_unicode_len(inputbox->buffer);
inputbox->selection[0] = djui_unicode_len(inputbox->buffer);
sCursorBlink = 0;
djui_inputbox_on_change(inputbox);
}
void djui_inputbox_move_cursor_to_position(struct DjuiInputbox* inputbox, u16 newCursorPosition) {
inputbox->selection[1] = newCursorPosition;
inputbox->selection[0] = newCursorPosition;
sCursorBlink = 0;
djui_inputbox_on_change(inputbox);
}
void djui_inputbox_hook_enter_press(struct DjuiInputbox* inputbox, void (*on_enter_press)(struct DjuiInputbox*)) {
inputbox->on_enter_press = on_enter_press;
}
@ -302,7 +316,7 @@ void djui_inputbox_on_focus_end(UNUSED struct DjuiBase* base) {
wm_api->stop_text_input();
}
static void djui_inputbox_on_text_input(struct DjuiBase *base, char* text) {
void djui_inputbox_on_text_input(struct DjuiBase *base, char* text) {
struct DjuiInputbox *inputbox = (struct DjuiInputbox *) base;
char* msg = inputbox->buffer;
int msgLen = strlen(msg);

View File

@ -18,9 +18,12 @@ void djui_inputbox_on_focus_end(UNUSED struct DjuiBase* base);
void djui_inputbox_set_text_color(struct DjuiInputbox* inputbox, u8 r, u8 g, u8 b, u8 a);
void djui_inputbox_set_text(struct DjuiInputbox* inputbox, char* text);
void djui_inputbox_select_all(struct DjuiInputbox* inputbox);
void djui_inputbox_move_cursor_to_end(struct DjuiInputbox* inputbox);
void djui_inputbox_move_cursor_to_position(struct DjuiInputbox* inputbox, u16 newCursorPosition);
void djui_inputbox_hook_enter_press(struct DjuiInputbox* inputbox, void (*on_enter_press)(struct DjuiInputbox*));
void djui_inputbox_hook_escape_press(struct DjuiInputbox* inputbox, void (*on_escape_press)(struct DjuiInputbox*));
bool djui_inputbox_on_key_down(struct DjuiBase* base, int scancode);
void djui_inputbox_on_key_up(struct DjuiBase* base, int scancode);
void djui_inputbox_on_text_input(struct DjuiBase *base, char* text);
struct DjuiInputbox* djui_inputbox_create(struct DjuiBase* parent, u16 bufferSize);

View File

@ -14,11 +14,16 @@
#define SCANCODE_RIGHT 333
#define SCANCODE_PAGE_DOWN 337
#define SCANCODE_PAGE_UP 329
#define SCANCODE_POS1 327
#define SCANCODE_END 335
#define SCANCODE_ENTER 28
#define SCANCODE_SPACE 57
#define SCANCODE_ESCAPE 1
#define SCANCODE_TAB 15
#define SCANCODE_LSHIFT 42
#define SCANCODE_RSHIFT 54
struct DjuiInteractable {
bool enabled;

View File

@ -1,3 +1,6 @@
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#include "smlua.h"
#include "sm64.h"
#include "behavior_commands.h"
@ -7,6 +10,10 @@
#include "pc/crash_handler.h"
#include "src/game/hud.h"
#include "pc/debug_context.h"
#include "pc/network/network.h"
#include "pc/network/network_player.h"
#include "pc/network/socket/socket.h"
#include "pc/chat_commands.h"
#include "pc/pc_main.h"
#if defined(DEVELOPMENT)
@ -1308,7 +1315,7 @@ struct LuaHookedChatCommand {
struct Mod* mod;
};
#define MAX_HOOKED_CHAT_COMMANDS 64
#define MAX_HOOKED_CHAT_COMMANDS 512
static struct LuaHookedChatCommand sHookedChatCommands[MAX_HOOKED_CHAT_COMMANDS] = { 0 };
static int sHookedChatCommandsCount = 0;
@ -1445,6 +1452,184 @@ void smlua_display_chat_commands(void) {
}
}
char* remove_color_codes(const char* str) {
char* result = strdup(str);
char* startColor;
while ((startColor = strstr(result, "\\#"))) {
char* endColor = strstr(startColor, "\\");
if (endColor) {
memmove(startColor, endColor + 1, strlen(endColor));
} else {
break;
}
}
return result;
}
bool is_valid_subcommand(const char* start, const char* end) {
for (const char* ptr = start; ptr < end; ptr++) {
if (isspace(*ptr) || *ptr == '\0') {
return false;
}
}
return true;
}
s32 sort_alphabetically(const void *a, const void *b) {
const char* strA = *(const char**)a;
const char* strB = *(const char**)b;
s32 cmpResult = strcasecmp(strA, strB);
if (cmpResult == 0) {
return strcmp(strA, strB);
}
return cmpResult;
}
char** smlua_get_chat_player_list(void) {
char* playerNames[MAX_PLAYERS] = { NULL };
s32 playerCount = 0;
for (s32 i = 0; i < MAX_PLAYERS; i++) {
struct NetworkPlayer* np = &gNetworkPlayers[i];
if (!np->connected) continue;
bool isDuplicate = false;
for (s32 j = 0; j < playerCount; j++) {
if (strcmp(playerNames[j], np->name) == 0) {
isDuplicate = true;
break;
}
}
if (!isDuplicate) {
playerNames[playerCount++] = np->name;
}
}
qsort(playerNames, playerCount, sizeof(char*), sort_alphabetically);
char** sortedPlayers = (char**) malloc((playerCount + 1) * sizeof(char*));
for (s32 i = 0; i < playerCount; i++) {
sortedPlayers[i] = strdup(playerNames[i]);
}
sortedPlayers[playerCount] = NULL;
return sortedPlayers;
}
char** smlua_get_chat_maincommands_list(void) {
#if defined(DEVELOPMENT)
char* additionalCmds[] = {"players", "kick", "ban", "permban", "moderator", "confirm", "help", "?", "warp", "lua", "luaf"};
s32 additionalCmdsCount = 11;
#else
char* additionalCmds[] = {"players", "kick", "ban", "permban", "moderator", "confirm", "help", "?"};
s32 additionalCmdsCount = 8;
#endif
char** commands = (char**) malloc((sHookedChatCommandsCount + additionalCmdsCount + 1) * sizeof(char*));
for (s32 i = 0; i < sHookedChatCommandsCount; i++) {
struct LuaHookedChatCommand* hook = &sHookedChatCommands[i];
commands[i] = strdup(hook->command);
}
for (s32 i = 0; i < additionalCmdsCount; i++) {
commands[sHookedChatCommandsCount + i] = strdup(additionalCmds[i]);
}
commands[sHookedChatCommandsCount + additionalCmdsCount] = NULL;
qsort(commands, sHookedChatCommandsCount + additionalCmdsCount, sizeof(char*), sort_alphabetically);
return commands;
}
char** smlua_get_chat_subcommands_list(const char* maincommand) {
for (s32 i = 0; i < sHookedChatCommandsCount; i++) {
struct LuaHookedChatCommand* hook = &sHookedChatCommands[i];
if (strcmp(hook->command, maincommand) == 0) {
char* noColorsDesc = remove_color_codes(hook->description);
char* startSubcommands = strstr(noColorsDesc, "[");
char* endSubcommands = strstr(noColorsDesc, "]");
if (startSubcommands && endSubcommands && is_valid_subcommand(startSubcommands + 1, endSubcommands)) {
*endSubcommands = '\0';
char* subcommandsStr = strdup(startSubcommands + 1);
s32 count = 1;
for (s32 j = 0; subcommandsStr[j]; j++) {
if (subcommandsStr[j] == '|') count++;
}
char** subcommands = (char**) malloc((count + 1) * sizeof(char*));
char* token = strtok(subcommandsStr, "|");
s32 index = 0;
while (token) {
subcommands[index++] = strdup(token);
token = strtok(NULL, "|");
}
subcommands[index] = NULL;
qsort(subcommands, count, sizeof(char*), sort_alphabetically);
free(noColorsDesc);
free(subcommandsStr);
return subcommands;
}
free(noColorsDesc);
}
}
return NULL;
}
bool smlua_maincommand_exists(const char* maincommand) {
char** commands = smlua_get_chat_maincommands_list();
bool result = false;
s32 i = 0;
while (commands[i] != NULL) {
if (strcmp(commands[i], maincommand) == 0) {
result = true;
break;
}
i++;
}
for (s32 j = 0; commands[j] != NULL; j++) {
free(commands[j]);
}
free(commands);
return result;
}
bool smlua_subcommand_exists(const char* maincommand, const char* subcommand) {
char** subcommands = smlua_get_chat_subcommands_list(maincommand);
if (subcommands == NULL) {
return false;
}
bool result = false;
s32 i = 0;
while (subcommands[i] != NULL) {
if (strcmp(subcommands[i], subcommand) == 0) {
result = true;
break;
}
i++;
}
for (s32 j = 0; subcommands[j] != NULL; j++) {
free(subcommands[j]);
}
free(subcommands);
return result;
}
//////////////////////////////
// hooked sync table change //

View File

@ -139,6 +139,11 @@ u32 smlua_get_action_interaction_type(struct MarioState* m);
bool smlua_call_chat_command_hook(char* command);
void smlua_display_chat_commands(void);
char** smlua_get_chat_player_list(void);
char** smlua_get_chat_maincommands_list(void);
char** smlua_get_chat_subcommands_list(const char* maincommand);
bool smlua_maincommand_exists(const char* maincommand);
bool smlua_subcommand_exists(const char* maincommand, const char* subcommand);
void smlua_clear_hooks(void);
void smlua_bind_hooks(void);

View File

@ -1,6 +1,8 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "sm64.h"
@ -291,6 +293,24 @@ void *main_game_init(void*) {
if (gCLIOpts.FullScreen == 1) { configWindow.fullscreen = true; }
else if (gCLIOpts.FullScreen == 2) { configWindow.fullscreen = false; }
if (gCLIOpts.RandomPlayerName == 1) {
struct timespec TS;
clock_gettime(CLOCK_MONOTONIC, &TS);
srand((unsigned int)(TS.tv_nsec ^ TS.tv_sec ^ getpid()));
char randomDigits[9];
for (int i = 0; i < 8; i++) {
randomDigits[i] = '0' + (rand() % 10);
}
randomDigits[8] = '\0';
snprintf(configPlayerName, MAX_PLAYER_STRING, "Player%s", randomDigits);
printf("\nRandom Playername (Start-Parameter): %s\n\n", configPlayerName);
} else if (gCLIOpts.PlayerName[0] != '\0') {
snprintf(configPlayerName, MAX_PLAYER_STRING, "%s", gCLIOpts.PlayerName);
printf("\nCustom Playername (Start-Parameter): %s\n\n", configPlayerName);
}
if (!gGfxInited) {
gfx_init(&WAPI, &RAPI, TITLE);
WAPI.set_keyboard_callbacks(keyboard_on_key_down, keyboard_on_key_up, keyboard_on_all_keys_up, keyboard_on_text_input);