diff --git a/.gitignore b/.gitignore
index 287764c4..9c1d929d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,5 @@
*.code-workspace
config/database.json
config/email.json
+config/discord.json
+locale/*
diff --git a/IDEAS.md b/IDEAS.md
index 555d241a..5375c289 100644
--- a/IDEAS.md
+++ b/IDEAS.md
@@ -373,4 +373,9 @@ Obviously this would still be using slashes for commands still. The way this wor
* Take item from vehicle trunk (grab crate from vehicle)
* Place item on ground (crate)
* Take second beer from crate
- * Store second beer in trunk
\ No newline at end of file
+ * Store second beer in trunk
+---
+### Animation/emote, action, and message menu wheels
+So with new Steam Deck being available now, and all the other attempts to use mobile devices that either emulate or stream the older GTA PC games, I figure we'd need a way for players to interact with each other using them. Roleplay is usually a very chat-oriented gamemode, but I can probably make things easier with simple controls. Also customizable messages, animations, and actions for each menu/wheel slot
+The inventory system is already planned to use a hotbar/wheel but I don't have all the images for it yet
+---
\ No newline at end of file
diff --git a/TODO.md b/TODO.md
index d07c17b1..d08be4d1 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1,5 +1,23 @@
-* Finish auto-translate
-* Add /autotranslate to enable/disable automatic chat translations for all languages, or specific ones by short code (RU, ES, etc)
-* Finish working on the new job route system
+== TODO
+* Finish auto-translator
* Add ways to acquire drugs. Pot/coke plants, meth labs, etc
-* Finish setting up the persistent NPC system
\ No newline at end of file
+* Finish setting up the persistent NPC system
+* Add yes/no prompts for some important things like
+ * (Business owner) Setting item sell price below order price. Will result in losing money.
+ * Giving house, biz, or vehicle to clan. Clan leaders can revoke permissions and you may be screwed and not able to change it!
+ * Deleting character
+* Make game messages (big message, small message) into array of types
+ * Array of message types in shared
+ * Font, text, duration, etc arrays in client, indexed by type
+* Fix the item take/put system for items in vehicle trunks, other items, etc
+---
+== Planned Features
+* Named and scripted NPCs
+* Racing
+* Fishing
+* Stock Market
+* Mapped interiors for GTA 3
+* Drug growing/manufacturing
+---
+== Bug Fixes
+* Check natives for if player is console (getPlayerPosition, etc)
\ No newline at end of file
diff --git a/config/accents.json b/config/accents.json
index 2b5cb10f..63d53c11 100644
--- a/config/accents.json
+++ b/config/accents.json
@@ -22,5 +22,6 @@
"Estonian",
"Sicilian",
"Indian",
- "Rough"
+ "Rough",
+ "Swedish"
]
\ No newline at end of file
diff --git a/config/client/locale.json b/config/client/locale.json
new file mode 100644
index 00000000..62caa2db
--- /dev/null
+++ b/config/client/locale.json
@@ -0,0 +1,112 @@
+[
+ {
+ "id": 0,
+ "englishName": "English",
+ "stringsFile": "english.json",
+ "isoCode": "en",
+ "flagImageFile": "uk.png",
+ "countries": ["gb", "us", "au", "bz", "ca", "ie", "jm", "nz", "za", "tt"],
+ "requiresUnicode": false,
+ "contributor": "Vortrex"
+ },
+ {
+ "id": 1,
+ "englishName": "Russian",
+ "stringsFile": "russian.json",
+ "isoCode": "ru",
+ "flagImageFile": "ru.png",
+ "countries": ["ru", "ua"],
+ "requiresUnicode": false,
+ "contributor": "VNDTTS"
+ },
+ {
+ "id": 2,
+ "englishName": "Polish",
+ "stringsFile": "polish.json",
+ "isoCode": "pl",
+ "flagImageFile": "pl.png",
+ "countries": ["pl"],
+ "requiresUnicode": false,
+ "contributor": "Suprise444"
+ },
+ {
+ "id": 3,
+ "englishName": "Spanish",
+ "stringsFile": "spanish.json",
+ "isoCode": "es",
+ "flagImageFile": "es.png",
+ "countries": ["es", "ar", "bo", "cl", "co", "cr", "do", "ec", "sv", "gt", "hn", "mx", "ni", "pa", "py", "pe", "pr", "uy", "ve"],
+ "requiresUnicode": false,
+ "contributor": "PerikiyoXD"
+ },
+ {
+ "id": 4,
+ "englishName": "Chinese",
+ "stringsFile": "chinese.json",
+ "isoCode": "zh",
+ "flagImageFile": "cn.png",
+ "countries": ["cn", "hk", "sg", "tw"],
+ "requiresUnicode": true,
+ "contributor": "Renzuko_Ctone"
+ },
+ {
+ "id": 5,
+ "englishName": "Arabic",
+ "stringsFile": "arabic.json",
+ "isoCode": "ar",
+ "flagImageFile": "sa.png",
+ "countries": ["dz", "bh", "eg", "iq", "jo", "kw", "lb", "ly", "ma", "om", "qa", "sa", "sy", "tn", "ae", "ye"],
+ "requiresUnicode": true,
+ "contributor": "! KASIR"
+ },
+ {
+ "id": 6,
+ "englishName": "Slovak",
+ "stringsFile": "slovak.json",
+ "isoCode": "sk",
+ "flagImageFile": "sk.png",
+ "countries": ["sk"],
+ "requiresUnicode": false,
+ "contributor": "UAKLAUS"
+ },
+ {
+ "id": 7,
+ "englishName": "German",
+ "stringsFile": "german.json",
+ "isoCode": "de",
+ "flagImageFile": "de.png",
+ "countries": ["de", "at", "be", "ch", "li", "lu"],
+ "requiresUnicode": false,
+ "contributor": "Sladernimo"
+ },
+ {
+ "id": 8,
+ "englishName": "French",
+ "stringsFile": "french.json",
+ "isoCode": "fr",
+ "flagImageFile": "fr.png",
+ "countries": ["fr", "cd", "bj", "bf", "cd", "cg", "ga", "gn", "ml", "mc", "ne", "sn"],
+ "requiresUnicode": false,
+ "contributor": "Cocam"
+ },
+ {
+ "id": 9,
+ "englishName": "Japanese",
+ "stringsFile": "japanese.json",
+ "isoCode": "jp",
+ "flagImageFile": "jp.png",
+ "countries": ["jp"],
+ "requiresUnicode": true,
+ "contributor": "Cocam"
+ },
+ {
+ "id": 10,
+ "englishName": "Finnish",
+ "stringsFile": "finnish.json",
+ "isoCode": "fi",
+ "flagImageFile": "fi.png",
+ "countries": ["fi"],
+ "requiresUnicode": false,
+ "contributor": "SIMBA_MEOW"
+ }
+]
\ No newline at end of file
diff --git a/config/database.json b/config/database.json
deleted file mode 100644
index dd077d6d..00000000
--- a/config/database.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "host": "localhost",
- "user": "",
- "pass": "",
- "name": "",
- "port": 3306,
- "usePersistentConnection": true
-}
\ No newline at end of file
diff --git a/config/discord.json b/config/discord.json
new file mode 100644
index 00000000..3fe219f5
--- /dev/null
+++ b/config/discord.json
@@ -0,0 +1,13 @@
+{
+ "sendChat": false,
+ "sendEvents": false,
+ "sendConnectEvents": false,
+ "sendVehicleEvents": false,
+ "sendDeathEvents": false,
+ "sendAdmin": false,
+ "webhook": {
+ "enabled": false,
+ "webhookBaseURL": "http://127.0.0.1:8090/discord.php?message={0}&server={1}&type={2}&pass={3}",
+ "pass": "LWb7T3ZyCam7Nzen"
+ }
+}
\ No newline at end of file
diff --git a/config/email.json b/config/email.json
deleted file mode 100644
index 224bdb3d..00000000
--- a/config/email.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "enabled": "false",
- "smtp": {
- "host":"",
- "port":"",
- "username":"",
- "password":"",
- "from":"",
- "fromName":"",
- "useTLS":"true"
- },
- "bodyContent": {
- "confirmEmail": "Welcome to {SERVERNAME}!\nPlease confirm your email by using the command /verifyemail in-game.\n\nYour verification code is: {VERIFICATIONCODE}",
- "emailConfirmed": "Your email has been confirmed on {SERVERNAME}!\nYou may now use this email to reset your password, require two-factor authentication on login, receive offline notifications, and more!",
- "twoFactorAuthentication": "Please enter the following code to continue on {SERVERNAME} for {GAMENAME}: {2FACODE}",
- "accountAuthSuccessAlert": "You or someone else has successfully logged in to your account on {SERVERNAME} for {GAMENAME}.\n\nIP Address: {IPADDRESS}\nLocation: {LOCATION}\nTimestamp: {TIMESTAMP}\n\nIf you have two-factor authentication enabled (Using /2fa in-game), your account can't be accessed unless a correct 2FA code is entered.",
- "accountAuthFailAlert": "You or someone else has failed to login to your account on {SERVERNAME} for {GAMENAME}.\nIP Address: {IPADDRESS}\nLocation: {LOCATION}\nTimestamp: {TIMESTAMP}",
- "offlineMessageAlert": "You have received a private message on {SERVERNAME} for {GAMENAME}. \nYou are receiving this notification because you enabled email message notifications when you're not connected to the server.\nFrom: {FROMNAME}\nTimestamp: {TIMESTAMP}\nMessage: {MESSAGE}",
- "confirmPasswordReset": "You (or someone else) requested to reset your password on {SERVERNAME}!\nPlease confirm this request by entering the code below into the password reset window in-game.\n\nYour verification code is: {VERIFICATIONCODE}\n\n\nIf you did not request a password reset, then there's nothing to worry about since your password can only be reset with the code above.",
- "passwordChanged": "Your password on {SERVERNAME} has been changed successfully!"
- }
-}
\ No newline at end of file
diff --git a/config/locale.json b/config/locale.json
index 3eccf479..5a68a5de 100644
--- a/config/locale.json
+++ b/config/locale.json
@@ -1,10 +1,117 @@
{
"apiEmail": "example@example.com",
- "defaultLanguage": "en",
+ "defaultLanguageId": 0,
+ "translateURL": "http://api.mymemory.translated.net/get?de={3}&q={0}&langpair={1}|{2}",
"locales": [
- ["English", "english", "en"],
- ["Russian", "russian", "ru"],
- ["Polish", "polish", "pl"],
- ["Spanish", "spanish", "es"]
+ {
+ "id": 0,
+ "englishName": "English",
+ "stringsFile": "english.json",
+ "isoCode": "en",
+ "flagImageFile": "uk.png",
+ "countries": ["gb", "us", "au", "bz", "ca", "ie", "jm", "nz", "za", "tt"],
+ "requiresUnicode": false,
+ "contributor": "Vortrex"
+ },
+ {
+ "id": 1,
+ "englishName": "Russian",
+ "stringsFile": "russian.json",
+ "isoCode": "ru",
+ "flagImageFile": "ru.png",
+ "countries": ["ru", "ua"],
+ "requiresUnicode": false,
+ "contributor": "VNDTTS"
+ },
+ {
+ "id": 2,
+ "englishName": "Polish",
+ "stringsFile": "polish.json",
+ "isoCode": "pl",
+ "flagImageFile": "pl.png",
+ "countries": ["pl"],
+ "requiresUnicode": false,
+ "contributor": "Suprise444"
+ },
+ {
+ "id": 3,
+ "englishName": "Spanish",
+ "stringsFile": "spanish.json",
+ "isoCode": "es",
+ "flagImageFile": "es.png",
+ "countries": ["es", "ar", "bo", "cl", "co", "cr", "do", "ec", "sv", "gt", "hn", "mx", "ni", "pa", "py", "pe", "pr", "uy", "ve"],
+ "requiresUnicode": false,
+ "contributor": "PerikiyoXD"
+ },
+ {
+ "id": 4,
+ "englishName": "Chinese",
+ "stringsFile": "chinese.json",
+ "isoCode": "zh",
+ "flagImageFile": "cn.png",
+ "countries": ["cn", "hk", "sg", "tw"],
+ "requiresUnicode": true,
+ "contributor": "Renzuko_Ctone"
+ },
+ {
+ "id": 5,
+ "englishName": "Arabic",
+ "stringsFile": "arabic.json",
+ "isoCode": "ar",
+ "flagImageFile": "sa.png",
+ "countries": ["dz", "bh", "eg", "iq", "jo", "kw", "lb", "ly", "ma", "om", "qa", "sa", "sy", "tn", "ae", "ye"],
+ "requiresUnicode": true,
+ "contributor": "! KASIR"
+ },
+ {
+ "id": 6,
+ "englishName": "Slovak",
+ "stringsFile": "slovak.json",
+ "isoCode": "sk",
+ "flagImageFile": "sk.png",
+ "countries": ["sk"],
+ "requiresUnicode": false,
+ "contributor": "UAKLAUS"
+ },
+ {
+ "id": 7,
+ "englishName": "German",
+ "stringsFile": "german.json",
+ "isoCode": "de",
+ "flagImageFile": "de.png",
+ "countries": ["de", "at", "be", "ch", "li", "lu"],
+ "requiresUnicode": false,
+ "contributor": "Sladernimo"
+ },
+ {
+ "id": 8,
+ "englishName": "French",
+ "stringsFile": "french.json",
+ "isoCode": "fr",
+ "flagImageFile": "fr.png",
+ "countries": ["fr", "cd", "bj", "bf", "cd", "cg", "ga", "gn", "ml", "mc", "ne", "sn"],
+ "requiresUnicode": false,
+ "contributor": "Cocam"
+ },
+ {
+ "id": 9,
+ "englishName": "Japanese",
+ "stringsFile": "japanese.json",
+ "isoCode": "jp",
+ "flagImageFile": "jp.png",
+ "countries": ["jp"],
+ "requiresUnicode": true,
+ "contributor": "Cocam"
+ },
+ {
+ "id": 10,
+ "englishName": "Finnish",
+ "stringsFile": "finnish.json",
+ "isoCode": "fi",
+ "flagImageFile": "fi.png",
+ "countries": ["fi"],
+ "requiresUnicode": false,
+ "contributor": "SIMBA_MEOW"
+ }
]
}
\ No newline at end of file
diff --git a/documentation/gtac/client/gtaiv/Commands.xml b/documentation/gtac/client/gtaiv/Commands.xml
new file mode 100644
index 00000000..ca9a127e
--- /dev/null
+++ b/documentation/gtac/client/gtaiv/Commands.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/documentation/gtac/client/gtaiv/Defines.xml b/documentation/gtac/client/gtaiv/Defines.xml
new file mode 100644
index 00000000..24c48ded
--- /dev/null
+++ b/documentation/gtac/client/gtaiv/Defines.xml
@@ -0,0 +1,3542 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/documentation/gtac/client/gtaiv/Documentation.xml b/documentation/gtac/client/gtaiv/Documentation.xml
new file mode 100644
index 00000000..0cd15ac2
--- /dev/null
+++ b/documentation/gtac/client/gtaiv/Documentation.xml
@@ -0,0 +1,3159 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/documentation/gtac/client/gtaiv/EventTypes.xml b/documentation/gtac/client/gtaiv/EventTypes.xml
new file mode 100644
index 00000000..7f447490
--- /dev/null
+++ b/documentation/gtac/client/gtaiv/EventTypes.xml
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/documentation/gtac/server/Commands.xml b/documentation/gtac/server/Commands.xml
new file mode 100644
index 00000000..9d51e79b
--- /dev/null
+++ b/documentation/gtac/server/Commands.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/documentation/gtac/server/Defines.xml b/documentation/gtac/server/Defines.xml
new file mode 100644
index 00000000..f60fdcec
--- /dev/null
+++ b/documentation/gtac/server/Defines.xml
@@ -0,0 +1,1671 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/documentation/gtac/server/Documentation.xml b/documentation/gtac/server/Documentation.xml
new file mode 100644
index 00000000..7df381ed
--- /dev/null
+++ b/documentation/gtac/server/Documentation.xml
@@ -0,0 +1,439 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/documentation/gtac/server/EventTypes.xml b/documentation/gtac/server/EventTypes.xml
new file mode 100644
index 00000000..8de2c651
--- /dev/null
+++ b/documentation/gtac/server/EventTypes.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/documentation/mafiac/client/mafia1/Commands.xml b/documentation/mafiac/client/mafia1/Commands.xml
new file mode 100644
index 00000000..e255010a
--- /dev/null
+++ b/documentation/mafiac/client/mafia1/Commands.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/documentation/mafiac/client/mafia1/Defines.xml b/documentation/mafiac/client/mafia1/Defines.xml
new file mode 100644
index 00000000..4d559fa9
--- /dev/null
+++ b/documentation/mafiac/client/mafia1/Defines.xml
@@ -0,0 +1,577 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/documentation/mafiac/client/mafia1/Documentation.xml b/documentation/mafiac/client/mafia1/Documentation.xml
new file mode 100644
index 00000000..6a1303f5
--- /dev/null
+++ b/documentation/mafiac/client/mafia1/Documentation.xml
@@ -0,0 +1,459 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/documentation/mafiac/client/mafia1/EventTypes.xml b/documentation/mafiac/client/mafia1/EventTypes.xml
new file mode 100644
index 00000000..ea29b084
--- /dev/null
+++ b/documentation/mafiac/client/mafia1/EventTypes.xml
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/documentation/mafiac/server/Commands.xml b/documentation/mafiac/server/Commands.xml
new file mode 100644
index 00000000..a1be49df
--- /dev/null
+++ b/documentation/mafiac/server/Commands.xml
@@ -0,0 +1,399 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/documentation/mafiac/server/Defines.xml b/documentation/mafiac/server/Defines.xml
new file mode 100644
index 00000000..7ae0532e
--- /dev/null
+++ b/documentation/mafiac/server/Defines.xml
@@ -0,0 +1,545 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/documentation/mafiac/server/Documentation.xml b/documentation/mafiac/server/Documentation.xml
new file mode 100644
index 00000000..32fc0abb
--- /dev/null
+++ b/documentation/mafiac/server/Documentation.xml
@@ -0,0 +1,424 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/documentation/mafiac/server/EventTypes.xml b/documentation/mafiac/server/EventTypes.xml
new file mode 100644
index 00000000..17bcf503
--- /dev/null
+++ b/documentation/mafiac/server/EventTypes.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/files/images/asshat-logo.png b/files/images/asshat-logo.png
new file mode 100644
index 00000000..0ac65cb9
Binary files /dev/null and b/files/images/asshat-logo.png differ
diff --git a/files/images/flags/cn.png b/files/images/flags/cn.png
new file mode 100644
index 00000000..e3ca7a04
Binary files /dev/null and b/files/images/flags/cn.png differ
diff --git a/files/images/flags/de.png b/files/images/flags/de.png
new file mode 100644
index 00000000..06add737
Binary files /dev/null and b/files/images/flags/de.png differ
diff --git a/files/images/flags/es.png b/files/images/flags/es.png
new file mode 100644
index 00000000..e0daa0ec
Binary files /dev/null and b/files/images/flags/es.png differ
diff --git a/files/images/flags/fi.png b/files/images/flags/fi.png
new file mode 100644
index 00000000..f7eb60dd
Binary files /dev/null and b/files/images/flags/fi.png differ
diff --git a/files/images/flags/fr.png b/files/images/flags/fr.png
new file mode 100644
index 00000000..4d38f9e0
Binary files /dev/null and b/files/images/flags/fr.png differ
diff --git a/files/images/flags/jp.png b/files/images/flags/jp.png
new file mode 100644
index 00000000..f66f64af
Binary files /dev/null and b/files/images/flags/jp.png differ
diff --git a/files/images/flags/pl.png b/files/images/flags/pl.png
new file mode 100644
index 00000000..d54aaff9
Binary files /dev/null and b/files/images/flags/pl.png differ
diff --git a/files/images/flags/ru.png b/files/images/flags/ru.png
new file mode 100644
index 00000000..733119fb
Binary files /dev/null and b/files/images/flags/ru.png differ
diff --git a/files/images/flags/sa.png b/files/images/flags/sa.png
new file mode 100644
index 00000000..d255f3b1
Binary files /dev/null and b/files/images/flags/sa.png differ
diff --git a/files/images/flags/sk.png b/files/images/flags/sk.png
new file mode 100644
index 00000000..71e27304
Binary files /dev/null and b/files/images/flags/sk.png differ
diff --git a/files/images/flags/uk.png b/files/images/flags/uk.png
new file mode 100644
index 00000000..4912cbd2
Binary files /dev/null and b/files/images/flags/uk.png differ
diff --git a/gtac_roleplay.code-workspace b/gtac_roleplay.code-workspace
deleted file mode 100644
index 876a1499..00000000
--- a/gtac_roleplay.code-workspace
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "folders": [
- {
- "path": "."
- }
- ],
- "settings": {}
-}
\ No newline at end of file
diff --git a/locale/arabic.json b/locale/arabic.json
deleted file mode 100644
index bcba6e72..00000000
--- a/locale/arabic.json
+++ /dev/null
@@ -1,478 +0,0 @@
-{
- "TranslationProvidedBy": "Kasir",
- "LocaleEnglishName": "Arabic",
-
- "LocaleNativeName": "عربى",
- "LocaleOffer": ".الخادم متاح باللغة الإنجليزية.استخدم {1} لاستخدامه",
- "LocaleChanged1": "لغتك الآن على {1}",
- "LocaleChanged2": "سيعرض الخادم الآن الرسائل في {1}",
- "LocaleChangedNote": "هذا لا يغير الرسائل من اللاعبين الآخرين",
- "AccentsListHeader": "لهجآت",
- "HeaderHelpMainList": "فئة الدعم",
- "AccentNotFound": "اللكنة الحالية غير متوفرة",
- "AccentSet": "قمت بتعيين لهجتك على {1}",
- "InvalidAnimation": "هذه الرسوم المتحركة غير متوفرة",
- "AnimationCommandTip": "استخدم {1} لمشاهدة قائمة الرسوم المتحركة المتاحة",
- "InvalidAnimationDistance": "يجب المسافة تكون بين 0 و 3",
- "AnimationStopCommandTip": "استخدم {1} لإيقاف الرسوم المتحركة",
- "CantBanClient": "لا يمكنك حظر هذا الإعب",
- "PlayerAccountBanned": "تم حظر حساب {1}",
- "ClanNotFound": "لم يتم العثور على المجموعة",
- "ClanNameTaken": "توجد مجموعة بهذا الاسم بالفعل",
- "PlayerNotFound": "الاعب غير موجود",
- "ClanCantRemoveRanks": "لا يمكنك إزالة رتب المجموعة",
- "ClanCantAddRanks": "لأ يمكنك إضافة رتب",
- "ClanRankNotFound": "رتبة غير موجودهـ",
- "ClanCantChangeMemberTag": "ليس لديك الصلاحيات لتعديل على علامات رتب الاعضاء",
- "ClanPlayerNotInSameClan": "الاعب غير موجود بمجموعتك",
- "ClanCantChangeRankLevel": "ليس لديك صلاحيات لتغيير مستوى رتبة المجموعة",
- "ClanCantChangeRankTag": "لا يمكنك تغيير علامات رتب المجموعة",
- "NameNotRegistered": "اسمك غير مسجل! استخدم {1} لإنشاء حساب.",
- "AutomaticLoginIPToggle": "IP تم تفعيل {1} تسجيل الدخول التلقائي عن طربق",
- "CouldNotRegisterAccount": "حدثت مشكلة في إنشاء حسابك, يرجى التواصل بـ إلاداره.",
- "RandomTipsToggle": "النصائح العشوائية{1}",
- "ActionTipsToggle": "نصائح العمل{1}",
- "AutoSpawnLastCharToggle": "النشر التلقائي كأخر حرف تم استخدامه هو {1}",
- "AccountGUISettingToggle": "واجهة المستخدم الرسومية هي الآن {1}",
- "On": "تشغيل",
- "Off": "إيقاف",
- "Yes": "موافق",
- "No": "لا",
- "True": "صحيح",
- "False": "خطأ",
- "Locked": "مغلق",
- "Unlocked": "مفتوح",
- "PasswordNotGoodEnough": "كلمة المرور الجديدة يجب أن تفي بالمتطلبات!",
- "PasswordNeedsBase": " {1} يجب أن تحتوي كلمات المرور على الأقل",
- "PasswordNeedsCapitals": "{1}من الأحرف الكبيرة",
- "PasswordNeedsNumbers": "{1} أرقام",
- "PasswordNeedsSymbols": "{1} حروف او رموز",
- "PasswordsDontMatch": "كلمة المرور الجديدة وتأكيد كلمة المرور الجديدة ليسا متطابقين!!",
- "PasswordChanged": "تم بنجاح تغيير كلمة المرور!",
- "AutoLoggedInIP": "IP تم تسجيل دخولك تلقائيًا بواسطة!",
- "WelcomeBack": "مرحبًا بك مرة أخرى في {1} ، {2}! من فضلك {3} للمتابعة.",
- "WelcomeNewPlayer": "مرحبًا بك في {1} ، {2}! من فضلك {3} للعب.",
- "InvalidPlayer": "اللاعب غير موجود!",
- "InvalidBusiness": "لم يتم العثور على الأعمال!",
- "InvalidHouse": "البيت غير موجود!",
- "InvalidVehicle": "لم يتم ايجاد السيارة!",
- "InvalidClan": "لم يتم العثور على المجموعة!",
- "InvalidClanRank": "رتبة غير موجوده!",
- "InvalidJob": "لم يتم العثور على الوظيفة!",
- "InvalidItem": "العنصر غير موجود!",
- "InvalidItemType": "نوع العنصر غير موجود!",
- "InvalidRadioStation": "لم يتم العثور على محطة راديو!",
- "InvalidGate": "البوابة غير موجودة!",
- "EntersProperty": "يفتح الباب ويدخل {1}",
- "ExitsProperty": "يفتح الباب ويخرج من {1}",
- "EnterExitPropertyDoorLocked": "يحاول فتح الباب {1} ولكنه يفشل لأنه مغلق",
- "PropertyNoInterior": "هذا ليس له جزء داخلي {1}، ولكن لا يزال بإمكانك استخدام الأوامر على أيقونة الباب.",
- "NoBusinessWithItemType": "لا يوجد عمل مع هذا الخيار متاح",
- "HeaderKeyBinds": "مفتاح الروابط",
- "HeaderAccountHelp": "مساعدة الحساب",
- "HeaderVehicleHelp": "تعليمات السيارة",
- "HeaderVehicleDealershipHelp": "مساعدة بيع سيارات",
- "HeaderJobHelp": "تعليمات الوظيفة",
- "HeaderChatHelp": "تعليمات الدردشة",
- "HeaderServerRules": "قوانين سيرفر",
- "HeaderWebsiteInfo": "الموقع الرسمي",
- "HeaderDiscordInfo": "ديسكورد",
- "HeaderAnimationsList": "قائمة الرسوم المتحركة",
- "HeaderPayAndSprayHelp": "الدفع ,ورشٌ المساعده",
- "HeaderAmmunationHelp": "مساعدة الذخيرة",
- "HeaderVehicleTuneupHelp": "مساعدة تعديل السيارة",
- "HeaderBindableKeysHelp": "مفاتيح قابلة للربط",
- "HeaderSkinHelp": "مساعدة الملابس / الجلد",
- "HeaderBusinessHelp": "تعليمات الأعمال",
- "HeaderClanHelp": "تعليمات المجموعة",
- "HeaderPlayerVehiclesList": "مركبات المشغل ({1})",
- "HeaderPlayerBusinessesList": "أعمال اللاعب ({1})",
- "HeaderClansList": "قائمة المجموعة",
- "HeaderAdminsList": "قائمة الادمن",
- "HeaderBadgeInfo": "معلومات الشاره",
- "HeaderAccentsList": "قائمة اللغة",
- "HeaderPlayerInfo": "معلومات الاعب",
- "HeaderWealthandTaxHelp": "معلومات المال",
- "HeaderCommandInfo": "معلومات الإوامر ({1})",
- "HeaderRadioHelp": "تعليمات راديو",
- "HeaderRadioStationsList": "محطات الردايو",
- "HeaderKeyBindsList": "قائمة روابط المفاتيح",
- "RadioVolumeChanged": "{1} لقد {2} غيرت مستوى صوت البث اللاسلكى إلى٪",
- "VolumeLevelNotNumber": "يجب أن يكون مستوى الصوت رقمًا",
- "RadioStationLocationInvalid": "يجب أن تكون في سيارة أو منزل أو عمل أو لديك جهاز شخصي لتغيير المحطة!",
- "ActionBusinessRadioStationChange": "تغيير محطة راديو الأعمال إلى {1} ({2})",
- "ActionHouseRadioStationChange": "تغيير محطة راديو المنزل إلى {1} ({2})",
- "ActionVehicleRadioStationChange": "يغير محطة راديو السيارة إلى {1} ({2})",
- "ActionItemRadioStationChange": "يغير محطة {1} إلى {2} ({3})",
- "RandomVehicleCommandsDisabled": "هذه مركبة مرور عشوائية ولا يمكن استخدام الأوامر لها.",
- "HouseDoorLock": "البيت {1} {2}!",
- "BusinessDoorLock": "الأعمال {1} {2}!",
- "ServerGameModeRestarting": "يتم إعادة تشغيل وضع لعبة الخادم!",
- "HeaderSelfItemList": "المخزون الخاص بك",
- "HeaderPlayerItemList": "مخزون الاعب ({1})",
- "HeaderHouseItemList": "بيت الاعب",
- "HeaderBusinessFloorItemList": "جرد الأعمال (للبيع)",
- "HeaderBusinessStorageItemList": "جرد الأعمال (التخزين)",
- "HeaderItemItemList": "مخزون {1}",
- "ItemSlotNotNumber": "يجب أن تكون خانة العنصر رقمًا",
- "ItemSlotMustBeBetween": "The item slot must be between {1} and {2}!",
- "UseItemBugged": "العنصر الذي تحاول استخدامه به التنصت. تم إرسال تقرير خطأ إلى مطوري الخادم.",
- "PickupItemBugged": "العنصر الذي تحاول استلامه به التنصت. تم إرسال تقرير خطأ إلى مطوري الخادم.",
- "DropItemBugged": "تم التنصت على العنصر الذي تحاول إسقاطه. تم إرسال تقرير خطأ إلى مطوري الخادم.",
- "HandsBusy": "يديك مشغولتان",
- "CantUseItemInSkinChange": "لا يمكنك استخدام عنصر أثناء تخصيص مظهرك",
- "CantDropItemInSkinChange": "لا يمكنك إسقاط عنصر أثناء تخصيص مظهرك",
- "CantPickupItemInSkinChange": "لا يمكنك التقاط عنصر أثناء تخصيص مظهرك",
- "CantSwitchItemInSkinChange": "لا يمكنك تبديل عنصر أثناء تخصيص مظهرك",
- "CantGiveItemInSkinChange": "لا يمكنك إعطاء عنصر أثناء تخصيص مظهرك",
- "CantTakeItemInSkinChange": "لا يمكنك أن تأخذ عنصرًا أثناء تخصيص مظهرك",
- "ItemUnequippableNoAmmo": "لا تحتوي الفتحة {1} الموجودة في الفتحة {2} على ذخيرة ، ولا يمكن تجهيزها!",
- "NoSpaceSelfInventory": "ليس لديك أي مساحة إضافية في مخزونك",
- "Business": "الاعمال",
- "House": "البيت",
- "Clan": "المجموعة",
- "Vehicle": "السيارة",
- "Item": "الاغراض",
- "ItemType": "نوع العنصر",
- "Gate": "بوابة",
- "Door": "باب",
- "ClanRank": "رتبة المجموعة",
- "JobRank": "رتبة الوظيفة",
- "RadioStation": "المحطة الإذاعية",
- "Months": [
- "يناير",
- "فبراير",
- "مارس",
- "أبريل",
- "مايو",
- "يونيو",
- "يوليو",
- "أغسطس",
- "سبتمبر",
- "أكتوبر",
- "نوفمبر",
- "ديسمبر"
- ],
- "WeekDays": [
- "الأحد",
- "الإثنين",
- "الثلاثاء",
- "الاربعاء",
- "الخميس",
- "الجمعه",
- "السبت"
- ],
- "CardinalDirections": [
- "شمال",
- "الشمال الشرقي",
- "شرق",
- "الجنوب الشرقي",
- "جنوب",
- "جنوب غرب",
- "غرب",
- "الشمال الغربي"
- ],
- "NewPlayerReadyToPlay": [
- "لقد حصلت على بعض من المال. استخدم {1} للبحث عن أماكن لشراء العناصر.",
- "إذا كنت بحاجة إلى المال،الوظائف هي النقاط الصفراء على الخريطة.",
- "للحصول على سيارة ، قم بزيارة وكالة السيارات. يمكنك أيضًا استخدام سيارة مستأجرة بالقرب من السباون أو ركوب القطار",
- "تأكد من قراءة {1} واستخدم {2} للحصول على معلومات."
- ],
- "YourCurrentVehicleDeleted": "تم حذف السيارة التي كنت بداخلها.",
- "Distance": "مسافة",
- "Meters": "أمتار",
- "Feet": "قدم",
- "Kilometers": "كيلومترات",
- "Miles": "اميال",
- "MustBeVehicleDriver": "يجب أن تكون سائق السيارة!",
- "PlayerJoinedServer": "انضم إلى اللعبة من {1}!",
- "PlayerLeftServer": "غادر {1} اللعبة! ({1})",
- "DisconnectReasons": [
- "انقطع الإتصال",
- "انقطع الاتصال",
- "عميل غير مدعوم",
- "تحذير للعبة",
- "كلمة سر غير صحيحه",
- "قابل للتنفيذ غير معتمد",
- "انقطع الاتصال",
- "حظر",
- "فشل",
- "اسم غير صالح",
- "خطأ"
- ],
- "TakeItemFromHouse": "يأخذ {1} من المنزل",
- "TakeItemFromBusinessStorage": "يأخذ {1} من تخزين الشركة",
- "TakeItemFromBusiness": "يأخذ {1} من الأعمال",
- "TakeItemFromItem": "يأخذ {1} من {2}",
- "TakeItemFromVehicleTrunk": "يأخذ {1} من صندوق السيارة",
- "TakeItemFromVehicleDash": "يأخذ {1} من صندوق القفازات",
- "JobEquipmentInventoryKeyBindTip": "معدات العمل في مخزونك. اضغط على {1} لمشاهدتها.",
- "JobEquipmentInventoryCommandTip": "معدات العمل في مخزونك. استخدم {1} لمشاهدتها.",
- "AccountHelp": [
- "لا تشارك كلمة مرورك مع أي شخص آخر. لن يطالبك فريق عمل {1} بكلمة المرور مطلقًا",
- "استخدم {1} لتغيير كلمة المرور الخاصة بك ، و {2} إذا نسيتها",
- "بعض الإعدادات التي يمكنك استخدامها: {1}"
- ],
- "VehicleHelp": [
- "ستوفر مركباتك الشخصية أينما تتركها أنت أو أي شخص آخر!",
- "قم بزيارة المعرض لشراء مركبات جديدة (استخدم {1} لمزيد من المعلومات)",
- "Some commands: {1}",
- "قم بزيارة مرآب ميكانيكي لإصلاح وتلوين وضبط سيارتك! {1} للحصول على معلومات"
- ],
- "VehicleDealershipHelp": [
- "قم بزيارة تاجر سيارات لشراء مركبات جديدة. استخدم {1} للعثور على واحد.",
- "عند التاجر ، أدخل السيارة التي تريد شراءها ، وسيظهر لك السعر",
- "إذا كنت ترغب في شراء السيارة ، فاستخدم {1} وستحصل على مفاتيح لاختبار قيادتها حول ساحة الانتظار.",
- "ابتعد عن الوكالة مع السيارة الجديدة لتأكيد الشراء."
- ],
- "JobHelp": [
- "قم بزيارة مواقع العمل للحصول على وظيفة وكسب المال. ابحث عن علامات الصفراء على الخريطة",
- "في موقع العمل ، استخدم {1} للحصول على الوظيفة. استخدم {2} لإنهاء عملك",
- "استخدم {1} لبدء العمل. يمكنك أيضًا الحصول على وظيفة {2} و {3}",
- "يتم تأمين معظم مركبات العمل. استخدم {1} بالقرب من واحد للدخول إليه.",
- "عند دخول مركبة عمل ، ستظهر لك معلومات حول كيفية القيام بالمهمة."
- ],
- "ChatHelp": [
- "(IC)والشخصية(OOC)هناك نوعان رئيسيان من الدردشة: خارج الطابع الشخصي",
- "الخلط بين هذين النوعين ليس لعب الأدوار المناسب. راجع {1} للحصول على معلومات.",
- "بعض أوامر الدردشة: {1}",
- "يتوفر لبعضها أسماء أقصر ({1} للتحدث ، {2} للصراخ ، إلخ)"
- ],
- "ServerRulesHelp": [
- ".غير مسموح بها.انت لست سوبر مان(powergaming)الإجراءات غير الواقعية",
- "لا يسمح بأدوار إرهابية",
- "اتبع دائمًا التعليمات التي قدمها المشرفون والاداره",
- "لا تخلط الدردشات (metagaming). لا يمكنك استخدام المعلومات في IC التي تم استلامها OOC",
- "حافظ على اللغة الإنجليزية في الدردشات الرئيسية. إذا لم تكن جيدًا في اللغة الإنجليزية ، فاستخدم {1}"
- ],
- "AnimationHelp": [
- "تتيح لك الرسوم المتحركة تحسين لعب الأدوار من خلال الإجراءات المرئية",
- "استخدم {1} أو {2} مع اسم لاستخدام الرسم المتحرك.",
- "لمشاهدة قائمة الرسوم المتحركة ، استخدم {1}"
- ],
- "WeaponHelp": [
- "قم بزيارة متجر أسلحة لشراء أسلحة. استخدم {1} للعثور على واحد.",
- "شراء سلاح يتطلب رخصة سلاح.",
- "يتم إدارة تراخيص الأسلحة من قبل قسم الشرطة. قدم طلبًا للحصول على واحدة ",
- "يمكن أيضًا شراء الأسلحة بشكل غير قانوني من بعض الشركات وتجار الأسلحة والعصابات."
- ],
- "SkinHelp": [
- "في متجر الملابس ، استخدم {1} لشراء الملابس",
- "عندما يكون لديك عنصر من الملابس ، قم بتجهيزه واستخدامه مثل أي عنصر آخر لإظهار اختيار الجلد (حدد {1} لمعرفة كيفية استخدام العناصر)",
- "Some skins are restricted to jobs, clans, or for other reasons."
- ],
- "KeyBindHelp": [
- "يمكنك تعيين روابط المفاتيح الخاصة بك. استخدم {1} لرؤية المفاتيح التي تم ربطها.",
- "استخدم {1} لإضافة رابط مفتاح جديد و {2} لإزالة واحد.",
- "المفاتيح الافتراضية هي: {1} لمحرك السيارة و {2} للأضواء و {3} للقفل / فتح القفل",
- "اضغط على {1} لمشاهدة عناصرك و {2} لتجهيز عنصر أو {3} لإلغاء تجهيز الكل.",
- "اضغط على {1} لاستخدام العنصر الذي تمسكه ، أو اضغط على {2} لإسقاطه ، أو اضغط على {3} لالتقاط عنصر من الأرض."
- ],
- "BusinessHelp": [
- "استخدم {1} لشراء العناصر أو {2} لمشاهدة قائمة بما هو معروض للبيع في أي شركة",
- "تظهر الشركات بأسماء زرقاء فوق الرمز عند مدخلها.",
- "أوامر صاحب العمل: {1}",
- "ستظهر سيارة جديدة معروضة للبيع عندما تبتعد عن الوكيل."
- ],
- "ClanHelp": [
- "اطلب من الإدارة إنشاء تيم(القبيلة) (على غرار الفصائل / المجموعات / العائلات)",
- "يتمتع مالكو التيم(القبيلة) بالسيطرة الكاملة على افراد المجموعة بمجرد إنشائها",
- "أوامر القبيلة: {1}",
- "أوامر القبيلة: {1}"
- ],
- "RadioStationHelp": [
- "استخدم {1} لتعيين المحطة لمركبتك أو منزلك أو عملك",
- "استخدم {2} لمشاهدة قائمة المحطات",
- "يمكنك تغيير حجم تدفق الراديو باستخدام {1} مع 0-100 كنسبة مئوية"
- ],
- "WealthAndTaxHelp": [
- "ضرائبك في يوم الدفع هي {1} بالمائة من ثروتك المحسوبة.",
- "ثروتك المحسوبة هي مجموع إجمالي يعتمد على عدد المركبات والمنازل والشركات التي لديك.",
- "كل سيارة {1} ، كل منزل {2} ، وكل عمل {3}",
- "استخدم {1} لمعرفة ثروتك الحالية ، و {2} لمعرفة المبلغ الذي ستدفعه كضريبة في كل يوم دفع"
- ],
- "MustBeInAVehicle": "يجب أن تكون في مركبة!",
- "MustBeInOrNearVehicle": "أنت بحاجة إلى أن تكون في السيارة أو بالقرب منها!",
- "MustBeInVehicleFrontSeat": "يجب أن تكون في المقاعد الأمامية للسيارة!",
- "MustBeInVehicleDriverSeat": "يجب أن تكون السائق!",
- "DontHaveVehicleKey": "ليس لديك مفتاح لهذه السيارة!",
- "NoGateAccess": "لا يمكنك الوصول إلى هذه البوابة!",
- "GateBroken": "هذه البوابة مكسورة!",
- "GateHacked": "البوابة لا تستجيب!",
- "RadioJammed": "تسمع صوتًا ثابتًا فقط من الراديو.",
- "VehicleNotForSale": "هذه السيارة ليست للبيع!",
- "VehicleNotForRent": "هذه السيارة ليست للإيجار!",
- "BusinessNotForSale": "هذا العمل ليس للبيع!",
- "BusinessNotForRent": "هذا العمل ليس للإيجار!",
- "HouseNotForSale": "هذا المنزل ليس للبيع!",
- "HouseNotForRent": "هذا المنزل ليس للإيجار!",
- "DealershipPurchaseTestDrive": "قم بقيادة السيارة بعيدًا عن الوكالة لشرائها ، أو اخرج للإلغاء.",
- "DealershipPurchaseExitedVehicle": "لقد ألغيت شراء السيارة بالخروج من السيارة!",
- "VehiclePurchaseComplete": "هذه السيارة الآن لك!",
- "VehiclePurchaseNotEnoughMoney": "ليس لديك ما يكفي من المال لشراء هذه السيارة!",
- "HousePurchaseNotEnoughMoney": "ليس لديك ما يكفي من المال لشراء هذا المنزل!",
- "BusinessPurchaseNotEnoughMoney": "ليس لديك ما يكفي من المال لشراء هذا العمل!",
- "Locales": {
- "English": "انجلزي",
- "Russian": "روسي",
- "Spanish": "الإسبانية",
- "German": "الإلمانية",
- "Dutch": "الهولندية",
- "Polish": "البولندية"
- },
-
- "ADDED-21JAN2022": "DO NOT TRANSLATE. This string is just a comment to separate newly added translations.",
- "HeaderPlayerHousesList": "بيوت اللاعبين ({1})",
- "HeaderPlayerStaffFlagsList": "أعلام طاقم العمل ({1})",
- "HeaderStaffFlagsList": "أعلام الموظفين",
- "NonRPName": "اسم غير RP! اختر واحدة جديدة:",
- "InvalidStaffFlag": "لم يتم العثور على علم الموظفين!",
- "InvalidClanFlag": "علم القبيلة غير موجود!",
- "InvalidLocale": "اللغة غير موجودة!",
- "HeaderJobUniformList": "زي العمل ({1})",
- "HeaderJobEquipmentList": "معدات العمل ({1})",
- "InvalidJobUniform": "زي العمل غير موجود!",
- "InvalidJobEquipment": "لم يتم العثور على معدات العمل!",
- "HeaderVehiclesInRangeList": "مركبات داخل {1}",
- "NoVehiclesWithInRange": "لا توجد مركبات داخل {1}",
- "AmountNotNumber": "المبلغ يجب أن يكون رقما!",
- "NeedToBeWorking": "يجب أن تعمل! استخدم {1} في موقع العمل أو بالقرب من سيارات العمل.",
- "NeedToBeOnJobRoute": "عليك أن تفعل طريق عمل! استخدم {1} في مركبة عمل",
- "CurrentJobRouteDeleted": "تم حذف مسار العمل الذي كنت تعمل فيه بواسطة الإدمن",
- "CurrentJobRouteVehicleColoursChanged": "تم تغيير ألوان السيارة لمسار وظيفتك بواسطة الإدمن",
- "NotYourJob": "هذه ليست وظيفتك!",
- "JobPoints": "يمكنك الحصول على وظيفة من خلال الذهاب إلى النقاط الصفراء على الخريطة.",
- "QuitJobToTakeAnother": "إذا كنت تريد هذه الوظيفة ، فاستخدم {1} لإنهاء وظيفتك الحالية.",
- "NotAJobVehicle": "هذه ليست وسيلة عمل!",
- "NotYourJobVehicle": "هذه ليست مركبة عملك!",
- "JobRouteDisabled": "تم تعطيل مسار العمل الذي كنت تسلكه بواسطة أحد الإداريين",
- "HeaderPickupTypes": "أنواع الالتقاط",
- "HeaderBlipTypes": "أنواع أيقونات الخريطة",
- "InvalidGPSLocation": "لا توجد مواقع بهذا الاسم أو النوع",
- "HeaderBusinessList": "الأعمال",
- "VehicleForSale": "يمكن شراء {1} مقابل {2}! استخدم {3} إذا كنت ترغب في شرائه",
- "VehicleForRent": "هذا {1} قابل للتأجير لـ {2}! استخدم {3} إذا كنت تريد استئجاره",
-
- "ADDED-31JAN2022": "DO NOT TRANSLATE. This string is just a comment to separate newly added translations.",
- "LoginFailedInvalidPassword": "رمز مرور خاطئ! عدد المحاولات المتبقية: {1}",
- "LoginFailedNoPassword": "يجب عليك إدخال كلمة المرور! ! عدد المحاولات المتبقية: {1}",
- "RegistrationFailedNoPassword": "يجب عليك إدخال كلمة المرور!",
- "RegistrationFailedNoPasswordConfirm": "يجب عليك تأكيد كلمة المرور!",
- "RegistrationFailedNoEmail": "يجب إدخال البريد الإلكتروني!",
- "AccountNameAlreadyRegistered": "تم تسجيل اسمك بالفعل!",
- "AlreadyLoggedIn": "انت بالفعل بداخل!",
- "RegistrationFailedInvalidEmail": "هذا البريد الإلكتروني غير صالح!",
- "RegistrationFailedPasswordMismatch": "كلمات المرور غير متطابقة!",
- "RegistrationFailedCreateError": "تعذر إنشاء حسابك!",
- "RegistrationSuccess": "لقد تم إنشاء حسابك!",
- "RegistrationEmailVerifyReminder": "لا تنس التحقق من بريدك الإلكتروني! تم إرسال رمز التحقق لك.",
- "RegistrationCreateCharReminder": "للعب على الخادم ، ستحتاج إلى تكوين شخصية.",
- "NoCharactersGUIMessage": "ليس لديك أحرف. هل ترغب في صنع واحدة؟",
- "NoCharactersGUIWindowTitle": "لا أحرف",
- "NoCharactersChatMessage": "ليس لديك أحرف. استخدم {1} لإنشاء واحدة.",
- "NeedEmailFor2FA": "تحتاج إلى إضافة بريدك الإلكتروني إلى حسابك لاستخدام المصادقة ذات العاملين.",
- "NeedEmailVerifiedFor2FA": "تحتاج إلى التحقق من بريدك الإلكتروني لاستخدام المصادقة ذات العاملين.",
- "SetEmailHelpTip": "استخدم {1} لتعيين بريدك الإلكتروني.",
- "VerifyEmailHelpTip": "استخدم {1} للتحقق من بريدك الإلكتروني.",
-
- "ADDED-13FEB2022": "DO NOT TRANSLATE. This string is just a comment to separate newly added translations.",
- "NearbyRadio": "راديو قريب",
- "FromRadio": "من الراديو",
- "ToRadio": "في الراديو",
- "NeedToEnterPropertyCommand": "تحتاج إلى إدخال {1} أولاً! استخدم {2} للدخول والخروج",
- "NeedToEnterPropertyKeyPress": "تحتاج إلى إدخال {1} أولاً! اضغط على {2} للدخول والخروج",
- "InventoryFullCantCarry": "ليس لديك أي مساحة لحمل هذا (جرد كامل)!",
- "NotEnoughCashNeedAmountMore": "ليس لديك ما يكفي من المال! أنت بحاجة إلى {1} أكثر!",
- "AmountMustBeMoreThan": "يجب أن يكون المبلغ أكثر من {1}!",
- "WeaponBanned": "لا يسمح لك بشراء أو استخدام الأسلحة!",
- "TimeNotNumber": "يجب أن يكون الوقت رقمًا",
- "HeaderDefaultBusinessItemTypes": "قوالب عناصر الأعمال",
- "FixingStuck": "إصلاح موقعك والعالم الافتراضي ...",
- "CantUseCommandYet": "يجب أن تنتظر قبل أن تتمكن من استخدام هذا الأمر مرة أخرى!",
- "NotATester": "أنت لست مختبرا!",
- "AccessDenied": "تم الرفض",
- "InvalidSkin": "هذا الجلد غير صالح!",
- "HeaderInteriorTypes": "قائمة التصميمات الداخلية",
- "ViewInventoryKeyPressTip": "اضغط على {1} لرؤية العناصر الخاصة بك",
- "ViewInventoryCommandTip": "استخدم {1} لمشاهدة عناصرك",
- "GUIAccountSettingToggle": "لقد قمت بتحويل {1} GUI",
-
- "ADDED-23MAR2022": "DO NOT TRANSLATE. This string is just a comment to separate newly added translations",
- "CarCommandHelp": "You can buy a car by visiting a vehicle dealership. Use {1} for more information.",
- "SkinCommandHelp": "You can change your skin by visiting a clothes store. Use {1} for more info.",
- "BusinessVehiclesRespawned": "All business vehicles have been respawned by an admin!",
- "JobVehiclesRespawned": "All job vehicles have been respawned by an admin!",
- "PlayerVehiclesRespawned": "All player vehicles have been respawned by an admin!",
- "ClanVehiclesRespawned": "All clan vehicles have been respawned by an admin!",
- "PublicVehiclesRespawned": "All public have been respawned by an admin!",
- "EmptyVehiclesRespawned": "All empty vehicles have been respawned by an admin!",
- "AllVehiclesRespawned": "All vehicles have been respawned by an admin!",
- "AllVehiclesReloaded": "All vehicles have been reloaded by an admin!",
- "YourVehicleRespawned": "Your vehicle has been respawned",
- "PlayerIPBanned": "{1} has been IP banned!",
- "PlayerCharacterBanned": "{1} has been character banned!",
- "PlayerSubNetBanned": "{1} has been subnet banned!",
- "CantModifyBusiness": "You can't manage or modify this business",
- "CantModifyHouse": "You can't manage or modify this house",
- "ServerTimeSet": "{1} set the time to {2}",
- "ServerWeatherSet": "{1} set the weather to {2}",
- "ServerSnowSet": "{1} turned falling snow {2} and ground snow {3}",
- "AllJobsReloaded": "All server jobs have been reloaded by an admin",
- "ServerLogoSet": "{1} turned the server logo image {2}",
- "ServerGUISet": "{1} turned GUI for this server {2}",
- "ServerBusinessBlipsSet": "{1} turned all business blips {2}",
- "ServerHouseBlipsSet": "{1} turned all house blips {2}",
- "ServerJobBlipsSet": "{1} turned all job blips {2}",
- "ServerBusinessPickupsSet": "{1} turned all business pickups {2}",
- "ServerHousePickupsSet": "{1} turned all house pickups {2}",
- "ServerJobPickupsSet": "{1} turned on all job pickups {2}",
- "BusinessBuyItemsLabel": "Use {1} to purchase items",
- "PropertyEnterCommandLabel": "Use {1} to enter",
- "PropertyEnterKeyPressLabel": "Press {1} to enter",
- "PropertyForSaleLabel": "For sale: ${1}",
- "PropertyForRentLabel": "For rent: ${1} every payday",
- "RemainingTaxPaidInMoney": "You covered the remaining taxes with ${1} in cash.",
- "LostMoneyFromTaxes": "You lost money since your taxes are more than your paycheck!",
- "NextPaycheckRepossessionWarning": "If you don't have enough cash to cover taxes on next paycheck, you will lose stuff!",
- "NotEnoughMoneyForTax": "You don't have enough money to cover your taxes!",
- "AssetsRepossessedForTax": "You lost {1} vehicles, {2} houses, and {3} businesses because you couldn't pay taxes!",
- "Closed": "Closed",
- "Open": "Open",
- "VehicleDealershipLabel": "Enter a vehicle as driver to buy it",
- "TakeJobLabel": "Use {1} to work here",
- "StartWorkLabel": "Use {1} to start working",
- "JobEquipAndUniformLabel": "Use {1} and {2} for job stuff, or {3} to stop working",
- "NotYourJobLabel": "You already have a different job. Use {1} if you want this one",
- "JobLabel": "{1} Job",
- "PaydayBonusSet": "{1} set the payday bonus to ${2}",
- "AllHousesReloaded": "All houses have been reloaded by an admin",
- "AllRadioStationsReloaded": "All radio stations have been reloaded by an admin!",
- "PlayerKicked": "{1} has been kicked from the server",
- "AllBusinessesReloaded": "All businesses have been reloaded by an admin!",
- "UnableToDoThat": "You aren't able to do that",
- "SetVehicleClanConfirmMessage": "Are you sure you want to give this vehicle to your clan?",
- "SetVehicleClanConfirmTitle": "Warning!",
- "SetItemPriceBelowOrderPriceMessage": "Are you sure you want to set the item price below it's order price? You will lose ${1} every purchase!",
- "SetItemPriceBelowOrderPriceTitle": "Warning!",
- "MustOwnVehicle": "You don't own this vehicle!",
- "RandomTips": [
- "Look for yellow dots on your map for job locations",
- "You can set custom key binds. Use {1} for details",
- "Use {1} if you don't want to see tips and extra information",
- "You can edit your keybinds using {1} and {2}",
- "Press ℹ️ to see your inventory, and use number keys to select an item",
- "Use {1} at a business to purchase items",
- "Found a bug? Report it with {1}",
- "Have an idea or suggestion for the server? Let the devs know using {1}",
- "Want to buy a business? Use {1} at one for sale",
- "Want to buy a house? Use {1} at one for sale",
- "Want to buy a vehicle? Visit a dealership and enter one for info on how to buy it!",
- "Switch to any of your characters with {1}",
- "Use {1} to automatically login when connecting with the same IP",
- "Use {1} to turn on/off the lights in your house or business",
- "Use {1} to play an internet radio station in your car, house, or business",
- "Want to make a clan? Use {1} for details",
- "Legal weapons can be purchased at any ammunation"
- ],
- "PromptResponseTip": "Use {1} to accept or {2} to decline"
-}
diff --git a/locale/chinese.json b/locale/chinese.json
deleted file mode 100644
index 8619d09e..00000000
--- a/locale/chinese.json
+++ /dev/null
@@ -1,439 +0,0 @@
-{
- "TranslationProvidedBy": "Renzuka_Ctone",
- "LocaleEnglishName": "Simplified Chinese",
- "LocaleNativeName": "简体中文",
- "LocaleOffer": "本服务器有可用的中文翻译版本,使用 {1} 以启用。",
- "LocaleChanged1": "语言已设定为 {1}",
- "LocaleChanged2": "服务器现在将以 {1} 显示消息。",
- "LocaleChangedNote": "这将不会影响到来自其他玩家的消息",
- "AccentsListHeader": "口音",
- "HeaderHelpMainList": "帮助类别",
- "AccentNotFound": "口音不存在",
- "AccentSet": " 口音已设置为 {1}",
- "AnimationNotFound": "该动作不存在",
- "AnimationCommandTip": "使用 {1} 以查看可用动作列表",
- "AnimationInvalidDistance": "范围必须在 0 到 3 之间",
- "AnimationStopCommandTip": "使用 {1} 以停止当前动作",
- "CantBanClient": "你无法封禁该玩家",
- "PlayerAccountBanned": "{1} 的账号已被封禁",
- "ClanNotFound": "帮派不存在",
- "ClanNameTaken": "该帮派名称已被占用",
- "PlayerNotFound": "玩家不存在",
- "ClanCantRemoveRanks": "无法清除帮派等级",
- "ClanCantAddRanks": "无法增加帮派等级",
- "ClanRankNotFound": "帮派等级不存在",
- "ClanCantChangeMemberTag": "你无法更改帮派成员的标签",
- "ClanPlayerNotInSameClan": "该玩家并不属于你的帮派",
- "ClanCantChangeRankLevel": "你无法改变帮派等级",
- "ClanCantChangeRankTag": "你无法改变帮派标签",
- "NameNotRegistered": "你的游戏名尚未注册!使用 {1} 以创建一个新账户。",
- "AutomaticLoginIPToggle": "通过 IP 自动登录功能 现已 {1}",
- "CouldNotRegisterAccount": "在创建你的账户时遇到一些问题,请与管理员联系。",
- "RandomTipsToggle": "随机提示信息现已 {1}",
- "ActionTipsToggle": "操作帮助现已 {1}",
- "AutoSpawnLastCharToggle": "上次使用的角色 {1} 已自动复活。",
- "AccountGUISettingToggle": "GUI 现已 {1}",
- "On": "开启",
- "Off": "关闭",
- "Yes": "是",
- "No": "否",
- "True": "真",
- "False": "假",
- "Locked": "锁定",
- "Unlocked": "未锁定",
- "PasswordNotGoodEnough": "新密码必须符合要求!",
- "PasswordNeedsBase": "密码至少需要 {1}",
- "PasswordNeedsCapitals": "{1} 大写字母",
- "PasswordNeedsNumbers": "{1} 数字",
- "PasswordNeedsSymbols": "{1} 符号",
- "PasswordsDontMatch": "新密码和确认密码不一致!",
- "PasswordChanged": "已成功更改你的密码!",
- "AutoLoggedInIP": "已通过 IP 自动登录!",
- "WelcomeBack": "欢迎回到 {1}, {2}! 请 {3} 以继续。",
- "WelcomeNewPlayer": "欢迎来到 {1}, {2}! 请 {3} 以开始游戏。",
- "InvalidPlayer": "玩家不存在!",
- "InvalidBusiness": "企业不存在!",
- "InvalidHouse": "住宅不存在!",
- "InvalidVehicle": "载具不存在!",
- "InvalidClan": "帮派不存在!",
- "InvalidClanRank": "帮派等级不存在!",
- "InvalidJob": "职业不存在",
- "InvalidItem": "物品不存在!",
- "InvalidItemType": "物品种类不存在!",
- "InvalidRadioStation": "电台不存在!",
- "InvalidGate": "大门不存在!",
- "EntersProperty": "开门并进入 {1}",
- "ExitsProperty": "开门并退出 {1}",
- "EnterExitPropertyDoorLocked": "试图打开 {1} 之门,却发现已上锁。",
- "PropertyNoInterior": "{1} 暂无内部场景,但你仍可以在大门图标上使用相关指令。",
- "NoBusinessWithItemType": "暂无可用项目的企业",
- "HeaderKeyBinds": "快捷键设置",
- "HeaderAccountHelp": "账户帮助",
- "HeaderVehicleHelp": "载具帮助",
- "HeaderVehicleDealershipHelp": "汽车经销商帮助 ",
- "HeaderJobHelp": "职业帮助",
- "HeaderChatHelp": "聊天帮助",
- "HeaderServerRules": "服务器规则",
- "HeaderWebsiteInfo": "官网",
- "HeaderDiscordInfo": "Discord",
- "HeaderAnimationsList": "动作列表",
- "HeaderPayAndSprayHelp": "有偿喷漆帮助",
- "HeaderAmmunationHelp": "弹药帮助",
- "HeaderVehicleTuneupHelp": "载具改装帮助",
- "HeaderBindableKeysHelp": "可绑定的按键",
- "HeaderSkinHelp": "服装/皮肤帮助",
- "HeaderBusinessHelp": "企业帮助",
- "HeaderClanHelp": "帮派帮助",
- "HeaderPlayerVehiclesList": "玩家载具 ({1})",
- "HeaderPlayerBusinessesList": "玩家企业 ({1})",
- "HeaderClansList": "帮派列表",
- "HeaderAdminsList": "管理员列表",
- "HeaderBadgeInfo": "荣誉信息",
- "HeaderAccentsList": "口音列表",
- "HeaderPlayerInfo": "玩家信息 ({1})",
- "HeaderWealthandTaxHelp": "资产与税收帮助",
- "HeaderCommandInfo": "指令帮助 ({1})",
- "HeaderRadioHelp": "电台帮助",
- "HeaderRadioStationsList": "电台",
- "HeaderKeyBindsList": "按键绑定列表",
- "RadioVolumeChanged": "{1} 已将电台音量调整为 {2}%",
- "VolumeLevelNotNumber": "确保输入的音量大小为有效数值",
- "RadioStationLocationInvalid": "你必须在车辆、住宅或企业中,或拥有个人设备才能更改电台!",
- "ActionBusinessRadioStationChange": "企业电台已设置为 {1} ({2})",
- "ActionHouseRadioStationChange": "住宅电台已设置为 {1} ({2})",
- "ActionVehicleRadioStationChange": "载具电台已设置为 {1} ({2})",
- "ActionItemRadioStationChange": "{1} 的电台已设置为 {2} ({3})",
- "RandomVehicleCommandsDisabled": "这是一辆随机刷出的街车,无法对其使用指令。",
- "HouseDoorLock": "住宅 {1} {2}!",
- "BusinessDoorLock": "企业 {1} {2}!",
- "ServerGameModeRestarting": "游戏模式正在重启!",
- "HeaderSelfItemList": "你的库存",
- "HeaderPlayerItemList": "玩家库存 ({1})",
- "HeaderHouseItemList": "住宅库存",
- "HeaderBusinessFloorItemList": "企业库存 (供售)",
- "HeaderBusinessStorageItemList": "企业库存 (暂存)",
- "HeaderItemItemList": "{1} 的库存",
- "ItemSlotNotNumber": "物体槽位必须为整数",
- "ItemSlotMustBeBetween": "物体槽位应在 {1} 与 {2} 之间!",
- "UseItemBugged": "尝试操作的物品出现错误!错误报告已发送给服务器开发人员。",
- "PickupItemBugged": "尝试拾取的物品出现错误!错误报告已发送给服务器开发人员。",
- "DropItemBugged": "尝试丢弃的物品出现错误!错误报告已发送给服务器开发人员。",
- "HandsBusy": "操作繁忙",
- "CantUseItemInSkinChange": "自定义外观时无法使用该物品",
- "CantDropItemInSkinChange": "自定义外观时无法丢弃该物品",
- "CantPickupItemInSkinChange": "自定义外观时无法拾取物品",
- "CantSwitchItemInSkinChange": "自定义外观时无法切换物品",
- "CantGiveItemInSkinChange": "自定义外观时无法赠送物品",
- "CantTakeItemInSkinChange": "自定义外观时无法取出物品",
- "ItemUnequippableNoAmmo": "槽位 {2} 中 {1} 弹药耗尽,无法装备!",
- "NoSpaceSelfInventory": "库存已无更多空间",
- "Business": "企业",
- "House": "住宅",
- "Clan": "帮派",
- "Vehicle": "载具",
- "Item": "物品",
- "ItemType": "物品种类",
- "Gate": "大门",
- "Door": "门",
- "ClanRank": "帮派等级",
- "JobRank": "职业等级",
- "RadioStation": "电台",
- "Months": [
- "一月",
- "二月",
- "三月",
- "四月",
- "五月",
- "六月",
- "七月",
- "八月",
- "九月",
- "十月",
- "十一月",
- "十二月"
- ],
- "WeekDays": [
- "周日",
- "周一",
- "周二",
- "周三",
- "周四",
- "周五",
- "周六"
- ],
- "CardinalDirections": [
- "北",
- "东北",
- "东",
- "东南",
- "南",
- "西南",
- "西",
- "西北"
- ],
- "NewPlayerReadyToPlay": [
- "你得到了一些现金,使用 {1} 以找到买东西的地方。",
- "赚钱靠劳动,求职请前往雷达上的小黄点。",
- "买车可以到汽车经销店,你也可以在出生点附近租车或者直接乘火车。",
- "确保已阅读 {1},使用 {2} 以获取相关信息。"
- ],
- "YourCurrentVehicleDeleted": "你当前乘坐的车辆已被删除。",
- "Distance": "距离",
- "Meters": "米",
- "Feet": "英尺",
- "Kilometers": "公里",
- "Miles": "英里",
- "MustBeVehicleDriver": "你并不是主驾驶!",
- "PlayerJoinedServer": "{1} 加入游戏。来自:{1}",
- "PlayerLeftServer": "{1} 退出游戏! ({1})",
- "DisconnectReasons": [
- "失去连接",
- "断开连接",
- "不支持的客户端",
- "游戏错误",
- "密码错误",
- "不支持的游戏主程序",
- "断开连接",
- "已被封禁",
- "连接失败",
- "无效的游戏名",
- "客户端崩溃"
- ],
- "TakeItemFromHouse": "从住宅处拿到 {1}",
- "TakeItemFromBusinessStorage": "从企业仓库拿到 {1}",
- "TakeItemFromBusiness": "从企业处拿到 {1}",
- "TakeItemFromItem": "从 {2} 处拿到 {1}",
- "TakeItemFromVehicleTrunk": "从后备箱中取出 {1}",
- "TakeItemFromVehicleDash": "从杂物箱中取出 {1}",
- "JobEquipmentInventoryKeyBindTip": "工作设备在你的仓库里,按下 {1} 以查看。",
- "JobEquipmentInventoryCommandTip": "工作设备在你的仓库里,使用 {1} 以查看。",
- "AccountHelp": [
- "请不要将密码分享给任何人,且{1} 工作人员不会询问你的密码。",
- "使用 {1} 以更改密码,若遗忘密码请使用 {2} 。",
- "可用设定:{1}"
- ],
- "VehicleHelp": [
- "你的私人车辆将会在离开车辆时自动保存!",
- "前往汽车经销商购买新车 (使用 {1} 获取更多信息)",
- "相关指令:{1}",
- "去修理厂修理、喷漆和改装你的汽车! 使用 {1} 获取相关信息。"
- ],
- "VehicleDealershipHelp": [
- "前往汽车经销商购买新车,使用 {1} 可以找一家。",
- "在经销商处进入你希望购买的车辆,对应价格将会自动显示。",
- "确定车辆后使用 {1},即可开始试驾。",
- "驾驶车辆离开经销商以确认购买。"
- ],
- "JobHelp": [
- "地图上的黄点为求职处,你可以在那里找工作挣大钱。",
- "在求职处使用 {1} 以获得工作,不想干了就使用 {2} 跑路。",
- "使用 {1} 即开始工作,你也可以在 {2} 与 {3} 中获得工作。",
- "工作专用车一般都是锁着的,在其旁边使用 {1} 即可进入。",
- "进入专用车时,将向您显示有关如何执行工作的信息。"
- ],
- "ChatHelp": [
- "聊天方式主要有两种:本我意识 (OOC 即 out-of-character) 和 角色意识 (IC 即 in-character)",
- "在玩角色扮演的时候最好不要混用两种聊天方式,查看 {1} 以获取更多信息。",
- "聊天指令:{1}",
- "某些玩家有可用的更简短的名称 ({1} 用以正常交流, {2} 用以喊话等)"
- ],
- "ServerRulesHelp": [
- "不允许不切实际的行为 (powergaming),你拯救不了世界。",
- "不允许恐怖分子或恐怖主义式角色扮演。",
- "请始终遵循版主和管理员的指示。",
- "不建议混合式聊天 (metagaming), 你不能在IC中使用收到OOC的信息。",
- "请使用英语与其他玩家进行交流,不大擅长英语的话可以试试 {1}"
- ],
- "AnimationHelp": [
- "做出虚拟动作可以提升你角色扮演的游戏体验。",
- "使用 {1} 或 {2} + 动作名称 以做出一个动作。",
- "要查看动作列表,使用 {1}"
- ],
- "WeaponHelp": [
- "前往枪店购买武器,使用 {1} 可以找一家。",
- "购买武器是需要武器许可证的。",
- "而武器许可证由警察局管理,在那里申请就可以办到一张。",
- "武器也可以从一些企业、武器经销商和帮派那里非法购买。"
- ],
- "SkinHelp": [
- "在服装店里使用 {1} 即可买到衣服",
- "当你拥有可穿戴式物品时,像其它物品一样直接装备即可。(查看 {1} 以了解如何使用物品)",
- "某些服装将因工作、帮派或其它原因而受到限制。"
- ],
- "KeyBindHelp": [
- "你可以自定义快捷键,使用 {1} 以查看已绑定的按键。",
- "使用 {1} 以新增快捷键,{2} 以移除。",
- "默认按键如下: {1} 发动引擎,{2} 车灯开关,{3} 锁车/解锁",
- "按下 {1} 查看你的物品,{2} 装备选定物品,{3} 卸下所有物品",
- "按下 {1} 使用当前物品,{2} 丢弃当前物品,{3} 拾取地面物品"
- ],
- "BusinessHelp": [
- "使用 {1} 以购买物品,或者使用 {2} 以查看任意企业的待售物品列表。",
- "企业名称以蓝色字体显示在图标上方。",
- "企业主可用的指令:{1}",
- "一辆待售的新车会在你开车离开经销商(即确认购买)后出现。"
- ],
- "ClanHelp": [
- "请求管理员以创建一个属于你自己的帮派 (类似于派系/团体/家庭)",
- "帮派创建成功后,帮主将拥有其所有控制权。",
- "帮派指令:{1}",
- "更多帮派指令:{1}"
- ],
- "RadioStationHelp": [
- "使用 {1} 为你的车辆/住宅/企业设置电台",
- "使用 {2} 以查看电台列表",
- "你可以使用 {1} 来改变电台音量大小。(0-100%)"
- ],
- "WealthAndTaxHelp": [
- "发薪日那天需要缴税,而税款是你计算财富的 {1}%.",
- "计算财富是基于你所拥有的车辆、住宅和企业的总和。",
- "{1} 每辆车,{2} 每栋房,{3} 每个企业。",
- "使用 {1} 以查看你的当前财富,{2} 以查看发薪日当天你应当缴纳的税款。"
- ],
- "MustBeInAVehicle": "你必须先坐在一辆车上!",
- "MustBeInOrNearVehicle": "必须要有辆车在你旁边,或者你坐上那辆车!",
- "MustBeInVehicleFrontSeat": "你必须坐在车辆前排座椅上!",
- "MustBeInVehicleDriverSeat": "你必须是车辆主驾驶!",
- "DontHaveVehicleKey": "你并没有这车的钥匙!",
- "NoGateAccess": "你无法进入这个大门。",
- "GateBroken": "这门已是破烂不堪。",
- "GateHacked": "大门没什么反应。",
- "RadioJammed": "电台似是被干扰了。",
- "VehicleNotForSale": "本车不出售!",
- "VehicleNotForRent": "本车不出租!",
- "BusinessNotForSale": "本企业不出售!",
- "BusinessNotForRent": "本企业不出租!",
- "HouseNotForSale": "这房子不给卖!",
- "HouseNotForRent": "这房子不给租!",
- "DealershipPurchaseTestDrive": "将车辆驶离经销商处以确认购买,下车取消。",
- "DealershipPurchaseExitedVehicle": "已取消车辆购买。",
- "VehiclePurchaseComplete": "这辆车现在是你的了!不管它在哪里都会自动保存。",
- "VehiclePurchaseNotEnoughMoney": "你没有足够的钱买这辆车!",
- "HousePurchaseNotEnoughMoney": "你没有足够的钱买这所房子!",
- "BusinessPurchaseNotEnoughMoney": "你没有足够的钱来买这家企业!",
- "Locales": {
- "English": "英文",
- "Russian": "俄文",
- "Spanish": "西班牙文",
- "German": "德文",
- "Dutch": "荷兰文",
- "Polish": "波兰文",
- "Chinese": "中文"
- },
-
- "ADDED-21JAN2022": "DO NOT TRANSLATE. This string is just a comment to separate newly added translations.",
- "HeaderPlayerHousesList": "玩家住宅 ({1})",
- "HeaderPlayerStaffFlagsList": "玩家信号旗 ({1})",
- "HeaderStaffFlagsList": "信号旗",
- "NonRPName": "非角色扮演名称!请选择新的名称:",
- "InvalidStaffFlag": "信号旗帜不存在!",
- "InvalidClanFlag": "帮派旗帜不存在!",
- "InvalidLocale": "语言不存在!",
- "HeaderJobUniformList": "工作制服 ({1})",
- "HeaderJobEquipmentList": "工作设备 ({1})",
- "InvalidJobUniform": "工作制服不存在!",
- "InvalidJobEquipment": "工作设备不存在!",
- "HeaderVehiclesInRangeList": "{1} 内的车辆",
- "NoVehiclesWithInRange": "{1} 内无任何车辆。",
- "AmountNotNumber": "请输入有效数字!",
- "NeedToBeWorking": "你得去工作!在求职处或工作专用车旁使用 {1} 。",
- "NeedToBeOnJobRoute": "你需要进行一个工作路线!请在工作专用车内使用 {1} 。",
- "CurrentJobRouteDeleted": "管理员已删除你所在的工作路线",
- "CurrentJobRouteVehicleColoursChanged": "管理员已更改你的工作路线的车辆颜色",
- "NotYourJob": "这不是你的工作!",
- "JobPoints": "前往地图上的黄点找到工作。",
- "QuitJobToTakeAnother": "要是想干这行,先使用 {1} 离开当前工作。",
- "NotAJobVehicle": "这并不是辆工作专用车!",
- "NotYourJobVehicle": "这不是你工作用的车!",
- "JobRouteDisabled": "管理员已禁用你的工作路线",
- "HeaderPickupTypes": "拾取物类型",
- "HeaderBlipTypes": "地图图标类型",
- "InvalidGPSLocation": "没有具有该名称或类型的位置",
- "HeaderBusinessList": "企业",
- "VehicleForSale": "此 {1} 可被 {2} 购买到!购买请使用 {3}",
- "VehicleForRent": "此 {1} 可被 {2} 租用!租用请使用 {3}",
-
- "ADDED-31JAN2022": "DO NOT TRANSLATE. This string is just a comment to separate newly added translations.",
- "LoginFailedInvalidPassword": "密码错误!还有 {1} 次尝试机会。",
- "LoginFailedNoPassword": "密码不能为空!还有 {1} 次尝试机会。",
- "RegistrationFailedNoPassword": "密码不能为空!",
- "RegistrationFailedNoPasswordConfirm": "确认密码不能为空!",
- "RegistrationFailedNoEmail": "电子邮件不能为空!",
- "AccountNameAlreadyRegistered": "该游戏名已被注册。",
- "AlreadyLoggedIn": "您已登录过账号!",
- "RegistrationFailedInvalidEmail": "该电子邮件无效!",
- "RegistrationFailedPasswordMismatch": "密码不匹配!",
- "RegistrationFailedCreateError": "无法创建您的帐户!",
- "RegistrationSuccess": "账号创建成功!",
- "RegistrationEmailVerifyReminder": "验证码已发送至您的电子邮件,请前往进行验证。",
- "RegistrationCreateCharReminder": "在正式游玩之前,您需要创建一个角色。",
- "NoCharactersGUIMessage": "暂无角色。要创建一个吗?",
- "NoCharactersGUIWindowTitle": "无角色",
- "NoCharactersChatMessage": "暂无角色。使用 {1} 新建一个角色。",
- "NeedEmailFor2FA": "开启双重验证前,请先添加您的电子邮件。",
- "NeedEmailVerifiedFor2FA": "开启双重验证前,请先验证您的电子邮件。",
- "SetEmailHelpTip": "使用 {1} 以设置您的电子邮件。",
- "VerifyEmailHelpTip": "使用 {1} 以验证您的电子邮件。",
-
- "ADDED-13FEB2022": "DO NOT TRANSLATE. This string is just a comment to separate newly added translations.",
- "NearbyRadio": "附近电台",
- "FromRadio": "起始电台",
- "ToRadio": "终止电台",
- "NeedToEnterPropertyCommand": "你得先进入 {1} !使用 {2} 以进入或退出。",
- "NeedToEnterPropertyKeyPress": "你得先进入 {1} !使用 {2} 以进入或退出。",
- "InventoryFullCantCarry": "库存已满!",
- "NotEnoughCashNeedAmountMore": "没有足够现金!你需要多加 {1} !",
- "AmountMustBeMoreThan": "数额必须大于 {1}!",
- "WeaponBanned": "你已被禁止购买及使用武器!",
- "TimeNotNumber": "设定的时间非有效数值",
- "HeaderDefaultBusinessItemTypes": "企业项目模板",
- "FixingStuck": "修复你当前的位置和虚拟世界 ...",
- "CantUseCommandYet": "稍后才能再次使用该指令!",
- "NotATester": "非测试者",
- "AccessDenied": "拒绝访问",
- "InvalidSkin": "该皮肤无效!",
- "HeaderInteriorTypes": "内部场景列表",
- "ViewInventoryKeyPressTip": "按下 {1} 以查看你的全部物品",
- "ViewInventoryCommandTip": "使用 {1} 以查看你的全部物品",
- "GUIAccountSettingToggle": "已切换至 {1} GUI",
-
- "ADDED-23MAR2022": "DO NOT TRANSLATE. This string is just a comment to separate newly added translations",
- "CarCommandHelp": "前往汽车经销商购买新车,使用 {1} 以获取更多信息。",
- "SkinCommandHelp": "前往服装店购买新衣服,使用 {1} 以获取更多信息。",
- "BusinessVehiclesRespawned": "管理员已重置所有企业车辆!",
- "JobVehiclesRespawned": "管理员已重置所有工作车辆!",
- "PlayerVehiclesRespawned": "管理员已重置所有玩家车辆!",
- "ClanVehiclesRespawned": "管理员已重置所有帮派车辆!",
- "PublicVehiclesRespawned": "管理员已重置所有公众!",
- "EmptyVehiclesRespawned": "管理员已重置所有空闲车辆!",
- "AllVehiclesRespawned": "管理员已重置所有车辆!",
- "AllVehiclesReloaded": "管理员已重载所有车辆!",
- "YourVehicleRespawned": "你的车辆已重生!",
- "PlayerIPBanned": "{1} 被封禁 IP!",
- "PlayerCharacterBanned": "{1} 被封禁角色!",
- "PlayerSubNetBanned": "{1} 被封禁网段!",
- "CantModifyBusiness": "你无法操作或修改这个企业!",
- "CantModifyHouse": "你无法操作或修改此住宅!",
- "ServerTimeSet": "{1} 已将时间设定为 {2}",
- "ServerWeatherSet": "{1} 已将天气设定为 {2}",
- "ServerSnowSet": "{1} 已调整:落雪-{2},积雪-{3}",
- "AllJobsReloaded": "管理员已重置所有职业!",
- "ServerLogoSet": "{1} 已设定:服务器 LOGO 状态-{2}",
- "ServerGUISet": "{1} 已设定:服务器 GUI 状态-{2}",
- "ServerBusinessBlipsSet": "{1} 已设定:服务器企业图例显示状态-{2}",
- "ServerHouseBlipsSet": "{1} 已设定:服务器住宅图例显示状态-{2}",
- "ServerJobBlipsSet": "{1} 已设定:服务器职业图例显示状态-{2}",
- "ServerBusinessPickupsSet": "{1} 已设定:服务器企业拾取物状态-{2}",
- "ServerHousePickupsSet": "{1} 已设定:服务器住宅拾取物状态-{2}",
- "ServerJobPickupsSet": "{1} 已设定:服务器职业拾取物状态-{2}",
- "BusinessBuyItemsLabel": "使用 {1} 以购买物品",
- "PropertyEnterCommandLabel": "使用 {1} 以进入",
- "PropertyEnterKeyPressLabel": "按下 {1} 以进入",
- "PropertyForSaleLabel": "售价:${1}",
- "PropertyForRentLabel": "租价:每个发薪日需 ${1}",
- "RemainingTaxPaidInMoney": "你以 ${1} 现金支付了剩下的税款",
- "LostMoneyFromTaxes": "你应缴纳的税款超过了你的薪水!",
- "NextPaycheckRepossessionWarning": "若无足够的现金来支付下一份薪水的税款,你将失去一些资产!",
- "NotEnoughMoneyForTax": "没有足够的现金来支付税款",
- "AssetsRepossessedForTax": "因未缴纳税款,你已失去 {1} 辆车,{2} 处住宅,{3} 处企业!"
-}
diff --git a/locale/english.json b/locale/english.json
deleted file mode 100644
index db17cb30..00000000
--- a/locale/english.json
+++ /dev/null
@@ -1,395 +0,0 @@
-{
- "TranslationProvidedBy": "Vortrex",
- "LocaleEnglishName": "English",
- "LocaleNativeName": "English",
- "LocaleOffer": "This server is available in English. Use {1} to use it.",
- "LocaleChanged1": "Your language is now set to {1}",
- "LocaleChanged2": "The server will now display messages in {1}",
- "LocaleChangedNote": "This does not change messages from other players",
- "AccentsListHeader": "Accents",
- "HeaderHelpMainList": "Help Categories",
- "AccentNotFound": "Accent not found",
- "AccentSet": "You set your accent to {1}",
- "AnimationNotFound": "That animation doesn't exist",
- "AnimationCommandTip": "Use {1} to see a list of valid animations",
- "AnimationInvalidDistance": "The distance must be between 0 and 3",
- "AnimationStopCommandTip": "Use {1} to stop your animation",
- "CantBanClient": "You cannot ban this person",
- "PlayerAccountBanned": "{1} has been account banned",
- "ClanNotFound": "Clan not found",
- "ClanNameTaken": "A clan with that name already exists",
- "PlayerNotFound": "Player not found",
- "ClanCantRemoveRanks": "You can't remove clan ranks",
- "ClanCantAddRanks": "You can't add clan ranks",
- "ClanRankNotFound": "Clan rank not found",
- "ClanCantChangeMemberTag": "You can not change clan member's tags",
- "ClanPlayerNotInSameClan": "That player is not in your clan",
- "ClanCantChangeRankLevel": "You can not change clan rank's level",
- "ClanCantChangeRankTag": "You can not change clan rank's tags",
- "NameNotRegistered": "Your name is not registered! Use {1} to make an account.",
- "AutomaticLoginIPToggle": "Automatic login by IP is now {1}",
- "CouldNotRegisterAccount": "There was a problem creating your account. Please contact an admin.",
- "RandomTipsToggle": "Random tips are now {1}",
- "ActionTipsToggle": "Action tips are now {1}",
- "AutoSpawnLastCharToggle": "Automatic spawn as last used character is {1}",
- "AccountGUISettingToggle": "GUI is now {1}",
- "On": "On",
- "Off": "Off",
- "Yes": "Yes",
- "No": "No",
- "True": "True",
- "False": "False",
- "Locked": "Locked",
- "Unlocked": "Unlocked",
- "PasswordNotGoodEnough": "The new password must meet the requirements!",
- "PasswordNeedsBase": "Passwords must have at least {1}",
- "PasswordNeedsCapitals": "{1} capital letters",
- "PasswordNeedsNumbers": "{1} numbers",
- "PasswordNeedsSymbols": "{1} symbols",
- "PasswordsDontMatch": "The new password and confirm new password aren't the same!",
- "PasswordChanged": "Your password has been changed!",
- "AutoLoggedInIP": "You have been automatically logged in by IP!",
- "WelcomeBack": "Welcome back to {1}, {2}! Please {3} to continue.",
- "WelcomeNewPlayer": "Welcome to {1}, {2}! Please {3} to play.",
- "InvalidPlayer": "Player not found!",
- "InvalidBusiness": "Business not found!",
- "InvalidHouse": "House not found!",
- "InvalidVehicle": "Vehicle not found!",
- "InvalidClan": "Clan not found!",
- "InvalidClanRank": "Clan rank not found!",
- "InvalidJob": "Job not found!",
- "InvalidItem": "Item not found!",
- "InvalidItemType": "Item type not found!",
- "InvalidRadioStation": "Radio station not found!",
- "InvalidGate": "Gate not found!",
- "EntersProperty": "opens the door and enters the {1}",
- "ExitsProperty": "opens the door and exits the {1}",
- "EnterExitPropertyDoorLocked": "tries to open the {1} door but fails because it's locked",
- "PropertyNoInterior": "This {1} does not have an interior, but you can still use commands at the door icon.",
- "NoBusinessWithItemType": "There is no business with that item available",
- "HeaderKeyBinds": "Key Binds",
- "HeaderAccountHelp": "Account Help",
- "HeaderVehicleHelp": "Vehicle Help",
- "HeaderVehicleDealershipHelp": "Vehicle Dealership Help",
- "HeaderJobHelp": "Job Help",
- "HeaderChatHelp": "Chat Help",
- "HeaderServerRules": "Server Rules",
- "HeaderWebsiteInfo": "Website",
- "HeaderDiscordInfo": "Discord",
- "HeaderAnimationsList": "Animation List",
- "HeaderPayAndSprayHelp": "Pay and Spray Help",
- "HeaderAmmunationHelp": "Ammunation Help",
- "HeaderVehicleTuneupHelp": "Vehicle Tune Help",
- "HeaderBindableKeysHelp": "Bindable Keys",
- "HeaderSkinHelp": "Clothes/Skin Help",
- "HeaderBusinessHelp": "Business Help",
- "HeaderClanHelp": "Clan Help",
- "HeaderPlayerVehiclesList": "Player Vehicles ({1})",
- "HeaderPlayerBusinessesList": "Player Businesses ({1})",
- "HeaderClansList": "Clan List",
- "HeaderAdminsList": "Admin List",
- "HeaderBadgeInfo": "Badge Information",
- "HeaderAccentsList": "Accent List",
- "HeaderPlayerInfo": "Player Information ({1})",
- "HeaderWealthandTaxHelp": "Wealth and Tax Information",
- "HeaderCommandInfo": "Command Information ({1})",
- "HeaderRadioHelp": "Radio Help",
- "HeaderRadioStationsList": "Radio Stations",
- "HeaderKeyBindsList": "Key Binds List",
- "RadioVolumeChanged": "{1} You changed your streaming radio volume to {2}%",
- "VolumeLevelNotNumber": "The volume level must be a number",
- "RadioStationLocationInvalid": "You must be in a vehicle, house, or business or have a personal device to change the station!",
- "ActionBusinessRadioStationChange": "changes the business radio station to {1} ({2})",
- "ActionHouseRadioStationChange": "changes the house radio station to {1} ({2})",
- "ActionVehicleRadioStationChange": "changes the vehicle radio station to {1} ({2})",
- "ActionItemRadioStationChange": "changes the {1}'s station to {2} ({3})",
- "RandomVehicleCommandsDisabled": "This is a random traffic vehicle and commands can't be used for it.",
- "HouseDoorLock": "House {1} {2}!",
- "BusinessDoorLock": "Business {1} {2}!",
- "ServerGameModeRestarting": "The server game mode is restarting!",
- "HeaderSelfItemList": "Your Inventory",
- "HeaderPlayerItemList": "Player Inventory ({1})",
- "HeaderHouseItemList": "House Inventory",
- "HeaderBusinessFloorItemList": "Business Inventory (For Sale)",
- "HeaderBusinessStorageItemList": "Business Inventory (Storage)",
- "HeaderItemItemList": "{1}'s Inventory",
- "ItemSlotNotNumber": "The item slot must be a number",
- "ItemSlotMustBeBetween": "The item slot must be between {1} and {2}!",
- "UseItemBugged": "The item you're trying to use is bugged. A bug report has been sent to the server developers.",
- "PickupItemBugged": "The item you're trying to pickup is bugged. A bug report has been sent to the server developers.",
- "DropItemBugged": "The item you're trying to drop is bugged. A bug report has been sent to the server developers.",
- "HandsBusy": "Your hands are busy",
- "CantUseItemInSkinChange": "You can't use an item while customizing your appearance",
- "CantDropItemInSkinChange": "You can't drop an item while customizing your appearance",
- "CantPickupItemInSkinChange": "You can't pickup an item while customizing your appearance",
- "CantSwitchItemInSkinChange": "You can't switch an item while customizing your appearance",
- "CantGiveItemInSkinChange": "You can't give an item while customizing your appearance",
- "CantTakeItemInSkinChange": "You can't take an item while customizing your appearance",
- "ItemUnequippableNoAmmo": "The {1} in slot {2} has no ammo, and can't be equipped!",
- "NoSpaceSelfInventory": "You don't have any more space in your inventory",
- "Business": "business",
- "House": "house",
- "Clan": "clan",
- "Vehicle": "vehicle",
- "Item": "item",
- "ItemType": "item type",
- "Gate": "gate",
- "Door": "door",
- "ClanRank": "clan rank",
- "JobRank": "job rank",
- "RadioStation": "radio station",
- "Months": [
- "January",
- "February",
- "March",
- "April",
- "May",
- "June",
- "July",
- "August",
- "September",
- "October",
- "November",
- "December"
- ],
- "WeekDays": [
- "Sunday",
- "Monday",
- "Tuesday",
- "Wednesday",
- "Thursday",
- "Friday",
- "Saturday"
- ],
- "CardinalDirections": [
- "North",
- "Northeast",
- "East",
- "Southeast",
- "South",
- "Southwest",
- "West",
- "Northwest"
- ],
- "NewPlayerReadyToPlay": [
- "You have been given some cash. Use {1} to find places to buy items.",
- "If you need money, jobs are the yellow dots on the radar.",
- "For a car, visit the car dealership. You can also use a rental vehicle near spawn or take the train",
- "Be sure to read the {1} and use {2} for info."
- ],
- "YourCurrentVehicleDeleted": "The vehicle you were in was deleted.",
- "Distance": "Distance",
- "Meters": "Meters",
- "Feet": "Feet",
- "Kilometers": "Kilometers",
- "Miles": "Miles",
- "MustBeVehicleDriver": "You must be the driver of the vehicle!",
- "PlayerJoinedServer": "{1} has joined the game from {1}!",
- "PlayerLeftServer": "{1} has left the game! ({1})",
- "DisconnectReasons": [
- "Lost Connection",
- "Disconnected",
- "Unsupported Client",
- "Wrong Game",
- "Incorrect Password",
- "Unsupported Executable",
- "Disconnected",
- "Banned",
- "Failed",
- "Invalid Name",
- "Crashed"
- ],
- "TakeItemFromHouse": "takes a {1} from the house",
- "TakeItemFromBusinessStorage": "takes a {1} from the business storage",
- "TakeItemFromBusiness": "takes a {1} from the business",
- "TakeItemFromItem": "takes a {1} from the {2}",
- "TakeItemFromVehicleTrunk": "takes a {1} from the trunk",
- "TakeItemFromVehicleDash": "takes a {1} from the glove compartment",
- "JobEquipmentInventoryKeyBindTip": "The job equipment is in your inventory. Press {1} to see them.",
- "JobEquipmentInventoryCommandTip": "The job equipment is in your inventory. Use {1} to see them.",
- "AccountHelp": [
- "Do NOT share your password with anybody else. {1} staff will never ask you for your password",
- "Use {1} to change your password, and {2} if you forgot it",
- "Some settings you can use: {1}"
- ],
- "VehicleHelp": [
- "Your personal vehicles will save wherever you or somebody else leaves them!",
- "Visit dealerships to buy new vehicles (Use {1} for more information)",
- "Some commands: {1}",
- "Visit a mechanic garage to repair, colour, and tune up your car! {1} for info"
- ],
- "VehicleDealershipHelp": [
- "Visit a vehicle dealer to buy new vehicles. Use {1} to find one.",
- "At the dealer, enter a car you want to buy, and the price will be shown to you",
- "If you want to buy the vehicle, use {1} and you will be given keys to test drive it around the parking lot.",
- "Drive away from the dealership with the new vehicle to confirm the purchase."
- ],
- "JobHelp": [
- "Visit job locations to get a job and earn money. Look for yellow spots on the map",
- "At a job location, use {1} to get the job. Use {2} to quit your job",
- "Use {1} to begin working. You can also get a job {2} and {3}",
- "Most job vehicles are locked. Use {1} near one to enter it.",
- "When entering a job vehicle, information on how to do the job will be shown to you."
- ],
- "ChatHelp": [
- "There are two main types of chat: out-of-character (OOC) and in-character (IC)",
- "Mixing these two types is not proper roleplay. See {1} for info.",
- "Some chat commands: {1}",
- "Some have shorter names available ({1} to talk, {2} to shout, etc)"
- ],
- "ServerRulesHelp": [
- "Unrealistic actions (powergaming) are not allowed. You aren't superman.",
- "No terrorist or terrorism roleplay is allowed.",
- "Always follow instructions given by moderators and admins.",
- "Do not mix the chats (metagaming). You can't use info in IC that was received OOC",
- "Keep English in main chats. If you aren't good at English, use {1}"
- ],
- "AnimationHelp": [
- "Animations allow you to enhance roleplay with visual actions",
- "Use {1} or {2} with a name to use an animation.",
- "To see a list of animations, use {1}"
- ],
- "WeaponHelp": [
- "Visit an gun store to buy weapons. Use {1} to find one.",
- "Buying a weapon requires a weapon license.",
- "Weapon licenses are managed by the police department. Apply there to get one.",
- "Weapons can also be purchased illegally from some businesses, weapon dealers, and clans."
- ],
- "SkinHelp": [
- "At a clothing store, use {1} to purchase clothes",
- "When you have a clothing item, equip and use it like any other item to show the skin selection (check {1} to learn how to use items)",
- "Some skins are restricted to jobs, clans, or for other reasons."
- ],
- "KeyBindHelp": [
- "You can set your own key binds. Use {1} to see your binded keys.",
- "Use {1} to add a new keybind and {2} to remove one.",
- "Default keys are: {1} for vehicle engine, {1} for lights, and {3} for lock/unlock",
- "Press {1} to see your items and {2} to equip an item or {3} to unequip all.",
- "Press {1} to use the item you're holding, press {2} to drop it, or press {3} to pickup an item from the ground."
- ],
- "BusinessHelp": [
- "Use {1} to purchase items or {2} to see a list of what's for sale at any business",
- "Businesses are shown with blue names above the icon at their entrance.",
- "Business owner commands: {1}",
- "A new car for sale will appear when you drive away from the dealer."
- ],
- "ClanHelp": [
- "Ask an administrator to create a clan (Similar to factions/groups/families)",
- "Clan owners have full control over their clan once it's created",
- "Clan commands: {1}",
- "More clan commands: {1}"
- ],
- "RadioStationHelp": [
- "Use {1} to set the station for your vehicle, house, or business",
- "Use {2} to see a list of stations",
- "You can change your radio streaming volume using {1} with 0-100 as the percent"
- ],
- "WealthAndTaxHelp": [
- "Your taxes on payday are {1} percent of your calculated wealth.",
- "Your calculated wealth is a total sum based on how many vehicles, houses, and businesses you have.",
- "Each vehicle is {1}, each house is {2}, and each business is {3}",
- "Use {1} to see your current wealth, and {2} to see how much you'll pay in tax each payday"
- ],
- "MustBeInAVehicle": "You need to be in a vehicle!",
- "MustBeInOrNearVehicle": "You need to be in or near a vehicle!",
- "MustBeInVehicleFrontSeat": "You need to be in the vehicle front seats!",
- "MustBeInVehicleDriverSeat": "You need to be the driver!",
- "DontHaveVehicleKey": "You don't have a key for this vehicle!",
- "NoGateAccess": "You don't have access to this gate!",
- "GateBroken": "This gate is broken!",
- "GateHacked": "The gate does not respond!",
- "RadioJammed": "You hear only static from the radio.",
- "VehicleNotForSale": "This vehicle is not for sale!",
- "VehicleNotForRent": "This vehicle is not for rent!",
- "BusinessNotForSale": "This business is not for sale!",
- "BusinessNotForRent": "This business is not for rent!",
- "HouseNotForSale": "This house is not for sale!",
- "HouseNotForRent": "This house is not for rent!",
- "DealershipPurchaseTestDrive": "Drive the vehicle away from the dealership to buy it, or get out to cancel.",
- "DealershipPurchaseExitedVehicle": "You canceled the vehicle purchase by exiting the vehicle!",
- "VehiclePurchaseComplete": "This vehicle is now yours! It will save wherever you leave it.",
- "VehiclePurchaseNotEnoughMoney": "You don't have enough money to buy this vehicle!",
- "HousePurchaseNotEnoughMoney": "You don't have enough money to buy this house!",
- "BusinessPurchaseNotEnoughMoney": "You don't have enough money to buy this business!",
- "Locales": {
- "English": "English",
- "Russian": "Russian",
- "Spanish": "Spanish",
- "German": "German",
- "Dutch": "Dutch",
- "Polish": "Polish"
- },
-
- "ADDED-21JAN2022": "DO NOT TRANSLATE. This string is just a comment to separate newly added translations.",
- "HeaderPlayerHousesList": "Player Houses ({1})",
- "HeaderPlayerStaffFlagsList": "Player Staff Flags ({1})",
- "HeaderStaffFlagsList": "Staff Flags",
- "NonRPName": "Non-RP name! Choose a new one:",
- "InvalidStaffFlag": "Staff flag not found!",
- "InvalidClanFlag": "Clan flag not found!",
- "InvalidLocale": "Language not found!",
- "HeaderJobUniformList": "Job Uniforms ({1})",
- "HeaderJobEquipmentList": "Job Equipment ({1})",
- "InvalidJobUniform": "Job uniform not found!",
- "InvalidJobEquipment": "Job equipment not found!",
- "HeaderVehiclesInRangeList": "Vehicles within {1}",
- "NoVehiclesWithInRange": "There are no vehicles within {1}",
- "AmountNotNumber": "The amount must be a number!",
- "NeedToBeWorking": "You need to be working! Use {1} at a job location or near a job vehicle.",
- "NeedToBeOnJobRoute": "You need to be doing a job route! Use {1} in a job vehicle",
- "CurrentJobRouteDeleted": "The job route you were on has been deleted by an admin",
- "CurrentJobRouteVehicleColoursChanged": "Your job route's vehicle colours were changed by an admin",
- "NotYourJob": "This is not your job!",
- "JobPoints": "You can get a job by going the yellow points on the map.",
- "QuitJobToTakeAnother": "If you want this job, use {1} to quit your current job.",
- "NotAJobVehicle": "This is not a job vehicle!",
- "NotYourJobVehicle": "This is not your job's vehicle!",
- "JobRouteDisabled": "The job route you were on has been disabled by an admin",
- "HeaderPickupTypes": "Pickup Types",
- "HeaderBlipTypes": "Map Icon Types",
- "InvalidGPSLocation": "There are no locations with that name or type",
- "HeaderBusinessList": "Businesses",
- "VehicleForSale": "This {1} is buyable for {2}! Use {3} if you want to buy it",
- "VehicleForRent": "This {1} is rentable for {2}! Use {3} if you want to rent it",
-
- "ADDED-31JAN2022": "DO NOT TRANSLATE. This string is just a comment to separate newly added translations.",
- "LoginFailedInvalidPassword": "Invalid password! {1} attempts remaining",
- "LoginFailedNoPassword": "You must enter a password! ! {1} attempts remaining",
- "RegistrationFailedNoPassword": "You must enter a password!",
- "RegistrationFailedNoPasswordConfirm": "You must confirm the password!",
- "RegistrationFailedNoEmail": "You must enter an email!",
- "AccountNameAlreadyRegistered": "Your name is already registered!",
- "AlreadyLoggedIn": "You are already logged in!",
- "RegistrationFailedInvalidEmail": "That email is invalid!",
- "RegistrationFailedPasswordMismatch": "The passwords don't match!",
- "RegistrationFailedCreateError": "Your account couldn't be created!",
- "RegistrationSuccess": "Your account has been created!",
- "RegistrationEmailVerifyReminder": "Don't forget to verify your email! A verification code has been sent to you.",
- "RegistrationCreateCharReminder": "To play on the server, you will need to make a character.",
- "NoCharactersGUIMessage": "You have no characters. Would you like to make one?",
- "NoCharactersGUIWindowTitle": "No characters",
- "NoCharactersChatMessage": "You have no characters. Use {1} to make one.",
- "NeedEmailFor2FA": "You need to add your email to your account to use two-factor authentication.",
- "NeedEmailVerifiedFor2FA": "You need to verify your email to use two-factor authentication.",
- "SetEmailHelpTip": "Use {1} to set your email.",
- "VerifyEmailHelpTip": "Use {1} to verify your email.",
-
- "ADDED-13FEB2022": "DO NOT TRANSLATE. This string is just a comment to separate newly added translations.",
- "NearbyRadio": "Nearby radio",
- "FromRadio": "From radio",
- "ToRadio": "To radio",
- "NeedToEnterPropertyCommand": "You need to enter the {1} first! Use {2} to enter and exit",
- "NeedToEnterPropertyKeyPress": "You need to enter the {1} first! Press {2} to enter and exit",
- "InventoryFullCantCarry": "You don't have any space to carry this (full inventory)!",
- "NotEnoughCashNeedAmountMore": "You don't have enough money! You need {1} more!",
- "AmountMustBeMoreThan": "The amount must be more than {1}!",
- "WeaponBanned": "You are not allowed to buy or use weapons!",
- "TimeNotNumber": "The time must be a number",
- "HeaderDefaultBusinessItemTypes": "Business Item Templates",
- "FixingStuck": "Fixing your position and virtual world ...",
- "CantUseCommandYet": "You must wait before you can use this command again!",
- "NotATester": "You are not a tester!",
- "AccessDenied": "AccessDenied",
- "InvalidSkin": "That skin is invalid!",
- "HeaderInteriorTypes": "Interiors"
-}
diff --git a/locale/polish.json b/locale/polish.json
deleted file mode 100644
index 82bb663b..00000000
--- a/locale/polish.json
+++ /dev/null
@@ -1,395 +0,0 @@
-{
- "TranslationProvidedBy": "Suprise444",
- "LocaleEnglishName": "Polish",
- "LocaleNativeName": "Polski",
- "LocaleOffer": "Ten serwer jest dostępny w języku Polskim. Użyj {1} aby go użyć.",
- "LocaleChanged1": "Twój język jest ustawiony na {1}",
- "LocaleChanged2": "Serwer będzie teraz pokazywał wiadomości w języku {1}",
- "LocaleChangedNote": "To nie zmienia wiadomości od innych graczy",
- "AccentsListHeader": "Akcenty",
- "HeaderHelpMainList": "Pomoc - Kategorie",
- "AccentNotFound": "Akcent nie znaleziony",
- "AccentSet": "Ustawiłeś swój akcent na {1}",
- "AnimationNotFound": "Ta animcja nie istnieje",
- "AnimationCommandTip": "Użyj {1} aby zobaczyć listę działających animacji",
- "AnimationInvalidDistance": "Dystans musi być między 0 i 3",
- "AnimationStopCommandTip": "Użyj {1} aby zatrzymać swoją animacje",
- "CantBanClient": "Nie możesz zbanować tej osoby",
- "PlayerAccountBanned": "{1} został zbanowany",
- "ClanNotFound": "Nie znaleziono klanu",
- "ClanNameTaken": "Klan z taką nazwą już istnieje",
- "PlayerNotFound": "Nie znaleziono gracza",
- "ClanCantRemoveRanks": "Nie możesz usuwać rang klanu",
- "ClanCantAddRanks": "Nie możesz dodawać rang klanu",
- "ClanRankNotFound": "Nie znaleziono rangi klanu",
- "ClanCantChangeMemberTag": "Nie możesz zmienić tagu członka klanu",
- "ClanPlayerNotInSameClan": "Ten gracz nie jest w twoim klanie",
- "ClanCantChangeRankLevel": "Nie możesz zmienić poziomu rangi klanu",
- "ClanCantChangeRankTag": "Nie możesz zmienić tagu rangi klanu",
- "NameNotRegistered": "Twoja nazwa nie jest zarejestrowana! Użyj {1} aby stworzyć konto.",
- "AutomaticLoginIPToggle": "Automatyczny login przez IP jest teraz {1}",
- "CouldNotRegisterAccount": "Napotkano problem podczas tworzenia twojego konta. Proszę skontaktuj się z administratorem.",
- "RandomTipsToggle": "Losowe wskazówki są teraz {1}",
- "ActionTipsToggle": "Wskazówki akcji są teraz {1}",
- "AutoSpawnLastCharToggle": "Automatyczny spawn jako ostatnia postać jest teraz {1}",
- "AccountGUISettingToggle": "GUI jest teraz {1}",
- "On": "Włączony",
- "Off": "Wyłączony",
- "Yes": "Tak",
- "No": "Nie",
- "True": "Prawda",
- "False": "Fałsz",
- "Locked": "Zamknięty",
- "Unlocked": "Otwarty",
- "PasswordNotGoodEnough": "Nowe hasło musi spełniać wymagania!",
- "PasswordNeedsBase": "Hasło musi mieć przynajmniej {1}",
- "PasswordNeedsCapitals": "{1} dużych liter",
- "PasswordNeedsNumbers": "{1} numerów",
- "PasswordNeedsSymbols": "{1} symboli",
- "PasswordsDontMatch": "Hasła nie są takie same!",
- "PasswordChanged": "Twoje hasło zostało zmienione!",
- "AutoLoggedInIP": "Zostałeś automatycznie zalogowany przez IP!",
- "WelcomeBack": "Witaj ponownie w {1}, {2}! Użyj {3} aby kontynuować.",
- "WelcomeNewPlayer": "Witaj w {1}, {2}! Użyj {3} aby zagrać.",
- "InvalidPlayer": "Praca nie znaleziona!",
- "InvalidBusiness": "Biznes nie znaleziony!",
- "InvalidHouse": "Mieszkanie nie znalezione!",
- "InvalidVehicle": "Pojazd nie znaleziony!",
- "InvalidClan": "Klan nie znaleziony!",
- "InvalidClanRank": "Ranga klanu nie znaleziona!",
- "InvalidJob": "Gracz nie znaleziony!",
- "InvalidItem": "Przedmiot nie znaleziony!",
- "InvalidItemType": "Rodzaj przedmiot nie znaleziony!",
- "InvalidRadioStation": "Stacja radiowa nie znaleziona!",
- "InvalidGate": "Brama nie znaleziona!",
- "EntersProperty": "otwiera drzwi i wchodzi do {1}",
- "ExitsProperty": "otwiera drzwi i wychodzi z {1}",
- "EnterExitPropertyDoorLocked": "próbuje otworzyć {1} drzwi, ale nie udaje się, ponieważ są zamknięte",
- "PropertyNoInterior": "Ten {1} nie ma wnętrza, ale dalej możesz używaj komend przy ikonie drzwi.",
- "NoBusinessWithItemType": "Nie ma biznesu, który posiada ten przedmiot",
- "HeaderKeyBinds": "Przypisania klawiszy",
- "HeaderAccountHelp": "Pomoc - Konto",
- "HeaderVehicleHelp": "Pomoc - Pojazd",
- "HeaderVehicleDealershipHelp": "Pomoc - Dealer Samochodów",
- "HeaderJobHelp": "Pomoc - Praca",
- "HeaderChatHelp": "Pomoc - Czat",
- "HeaderServerRules": "Zasady serwera",
- "HeaderWebsiteInfo": "Strona",
- "HeaderDiscordInfo": "Discord",
- "HeaderAnimationsList": "Lista Animacji",
- "HeaderPayAndSprayHelp": "Pomoc - Pay and Spray",
- "HeaderAmmunationHelp": "Pomoc - Ammunation",
- "HeaderVehicleTuneupHelp": "Pomoc - Ulepszanie Aut",
- "HeaderBindableKeysHelp": "Przypisywalne klawisze",
- "HeaderSkinHelp": "Pomoc - Ubrania/Skóra",
- "HeaderBusinessHelp": "Pomoc - Biznes",
- "HeaderClanHelp": "Pomoc - Klan",
- "HeaderPlayerVehiclesList": "Pojazdy Gracza ({1})",
- "HeaderPlayerBusinessesList": "Biznesy Gracza ({1})",
- "HeaderClansList": "Lista Klanów",
- "HeaderAdminsList": "Lista Administracji",
- "HeaderBadgeInfo": "Informacje o Odznace",
- "HeaderAccentsList": "Lista Akcentów",
- "HeaderPlayerInfo": "Informacje o Graczu ({1})",
- "HeaderWealthandTaxHelp": "Informacje o Bogactwach i Podatkach",
- "HeaderCommandInfo": "Informacje o Komendzie ({1})",
- "HeaderRadioHelp": "Pomoc - Radio",
- "HeaderRadioStationsList": "Stacje Radiowe",
- "HeaderKeyBindsList": "Lista przypisań klawiszy",
- "RadioVolumeChanged": "{1} Zmieniłeś głośność swojego radia na {2}%",
- "VolumeLevelNotNumber": "Poziom głośności musi być liczbą",
- "RadioStationLocationInvalid": "Musisz być w aucie, domu, biznesie lub mieć osobite urządzenie by zmienić stacje radiową!",
- "ActionBusinessRadioStationChange": "zmienia biznesową stacje radiową na {1} ({2})",
- "ActionHouseRadioStationChange": "zmienia domową stacje radiową na {1} ({2})",
- "ActionVehicleRadioStationChange": "zmienia samochodową stacje radiową na {1} ({2})",
- "ActionItemRadioStationChange": "zmienia stacje {1} na {2} ({3})",
- "RandomVehicleCommandsDisabled": "To losowy pojazd uliczny i komendy nie mogą być na nim użyte.",
- "HouseDoorLock": "Mieszkanie {1} {2}!",
- "BusinessDoorLock": "Biznes {1} {2}!",
- "ServerGameModeRestarting": "Tryb gry serwera się restartuje!",
- "HeaderSelfItemList": "Twój ekwipunek",
- "HeaderPlayerItemList": "Ekwipunek gracza ({1})",
- "HeaderHouseItemList": "Ekwipunek mieszkania",
- "HeaderBusinessFloorItemList": "Ekwipunek Bizneus (Na sprzedaż)",
- "HeaderBusinessStorageItemList": "Ekwipunek Bizenus (Magazyn)",
- "HeaderItemItemList": "Ekwipunek {1}",
- "ItemSlotNotNumber": "Slot przedmiotu musi być liczbą",
- "ItemSlotMustBeBetween": "Slot itemu musi być liczbą między {1} i {2}!",
- "UseItemBugged": "Przedmiot, który próbujesz użyć jest popsuty. Zgłoszenie zostało wysłane do deweloperów serwera.",
- "PickupItemBugged": "Przedmiot, który próbujesz podnieść jest popsuty. Zgłoszenie zostało wysłane do deweloperów serwera.",
- "DropItemBugged": "Przedmiot, który próbujesz upuścić jest popsuty. Zgłoszenie zostało wysłane do deweloperów serwera.",
- "HandsBusy": "Twoje ręce są zajęte",
- "CantUseItemInSkinChange": "Nie możesz użyć przedmiotu podczas zmieniania swojego wizerunku",
- "CantDropItemInSkinChange": "Nie możesz upuścić przedmiotu podczas zmieniania swojego wizerunku",
- "CantPickupItemInSkinChange": "Nie możesz podnieść przedmiotu podczas zmieniania swojego wizerunku",
- "CantSwitchItemInSkinChange": "Nie możesz zmienić przedmiotu podczas zmieniania swojego wizerunku",
- "CantGiveItemInSkinChange": "Nie możesz dać przedmiotu podczas zmieniania swojego wizerunku",
- "CantTakeItemInSkinChange": "Nie możesz wziąć przedmiotu podczas zmieniania swojego wizerunku",
- "ItemUnequippableNoAmmo": "{1} w slocie {2} nie ma amunicji i nie może zostać użyty!",
- "NoSpaceSelfInventory": "Nie masz już miesca w ekwipunku",
- "Business": "biznes",
- "House": "mieszkanie",
- "Clan": "klan",
- "Vehicle": "pojazd",
- "Item": "przedmiot",
- "ItemType": "rodzaj przedmiotu",
- "Gate": "brama",
- "Door": "drzwi",
- "ClanRank": "ranga klanu",
- "JobRank": "praca rangi",
- "RadioStation": "stacja radiowa",
- "Months": [
- "Styczeń",
- "Luty",
- "Marzec",
- "Kwiecień",
- "Maj",
- "Czerwiec",
- "Lipiec",
- "Sierpień",
- "Wrzesień",
- "Październik",
- "Listopad",
- "Grudzień"
- ],
- "WeekDays": [
- "Niedziela",
- "Poniedziałek",
- "Wtorek",
- "Środa",
- "Czwartek",
- "Piątek",
- "Sobota"
- ],
- "CardinalDirections": [
- "Północ",
- "Północny wschód",
- "Wschód",
- "Południowy zachód",
- "Południe",
- "Południowy wschód",
- "Zachód",
- "Północny zachód"
- ],
- "NewPlayerReadyToPlay": [
- "Dostałeś trochę pieniędzy. Użyj {1} aby znaleść miejsca do kupowania przedmiotów.",
- "Jeżeli potrzebujesz pieniędzy, żółte kropki na mapie to miejsca pracy.",
- "Aby zdobyć auto musisz odwiedzić dealera samochodów. Możesz też wypożyczyć samochód przy spawnie lub użyć pociągu",
- "Pamiętaj aby przeczytać {1} i użyć {2} aby zdobyć więcej informacji."
- ],
- "YourCurrentVehicleDeleted": "Samochód w którym przebywałeś został usunięty.",
- "Distance": "Odległość",
- "Meters": "Metry",
- "Feet": "Stopy",
- "Kilometers": "Kilometry",
- "Miles": "Mile",
- "MustBeVehicleDriver": "Musisz być kierowcą tego pojazdu!",
- "PlayerJoinedServer": "{1} dołączył do gry z {1}!",
- "PlayerLeftServer": "{1} wyszedł z gry! ({1})",
- "DisconnectReasons": [
- "Utracenie Połączenia",
- "Odłączenie",
- "Niewspierana Wersja",
- "Nieprawidłowa Gra",
- "Błędne Hasło",
- "Niewspierany Plik Wykonalny",
- "Odłączenie",
- "Zbanowany",
- "Nie udane",
- "Nieprawidłowa Nazwa",
- "Crashed"
- ],
- "TakeItemFromHouse": "bierze {1} z mieszkania",
- "TakeItemFromBusinessStorage": "bierze {1} z magazynu biznesu",
- "TakeItemFromBusiness": "bierze {1} z biznesu",
- "TakeItemFromItem": "bierze {1} z {2}",
- "TakeItemFromVehicleTrunk": "bierze {1} z bagażnika",
- "TakeItemFromVehicleDash": "bierze {1} ze schowka",
- "JobEquipmentInventoryKeyBindTip": "Wyposażenie służbowe jest w twoim ekwipunku. Naciśnij {1} aby je zobaczyć.",
- "JobEquipmentInventoryCommandTip": "Wyposażenie służbowe jest w twoim ekwipunku. Użyj {1} aby je zobaczyć.",
- "AccountHelp": [
- "NIE PODAWAJ nikomu swojego hasła. {1} nigdy nie zapyta cię o twoje hasło",
- "Użyj {1} aby zmienić swoje hasło i {2} jeżeli je zapomniałeś",
- "Kilka ustawień które możesz użyć: {1}"
- ],
- "VehicleHelp": [
- "Twoje osobiste auta zapisują się za każdym razem jak ktoś wyjdzie z gry!",
- "Odwiedź dealera samochodów, aby zakupić pojazd (Użyj {1} po więcej informacji)",
- "Kilka komend: {1}",
- "Odwiedź warsztat mechanika aby naprawić, pokolorować i/lub ulepszyć swój pojazd! {1} po więcej informacji"
- ],
- "VehicleDealershipHelp": [
- "Odwiedź dealera samochodów, aby zakupić nowy pojazd. Użyj {1} aby jednego zlokalizować.",
- "Przy dealerze samochodów, wejdź do auta, które chcesz kupić i ukaże ci się jego cena.",
- "Jeśli chcesz kupić pojazd, użyj {1} i dostanie kluczyki by przetestować je na parkingu.",
- "Odjedź od dealera samochodów, aby potwierdzić zakup pojazdu."
- ],
- "JobHelp": [
- "Odwiedzaj miejsca pracy aby zarabiać pieniądze. Szkuaj zółtych punktów na mapie",
- "Przy miejscu pracy, użyj {1} aby zdobyć prace. Użyj {2} by opuścić swoją pracę",
- "Użyj {1} aby zacząć pracę. Możesz też dostać pracę {2} i {3}",
- "Większość pojazdów służbowych jest zamknięta. Użyj {1} obok niego aby do niego wsiąść.",
- "Przy wsiadaniu do pojazdu służbowego, dostaniesz informacje jak wykonać podjętą pracę."
- ],
- "ChatHelp": [
- "Są 2 główne rodzaje chatów: Poza postacią (OOC) i w postaci (IC)",
- "Mieszanie tych 2 rodzajów jest nieprawidłowym roleplay'em. Zobacz {1} po więcej informacji.",
- "Kilka komend na chacie: {1}",
- "Niektóre mają dostępne krótsze nazwy ({1} by rozmawiać, {2} by krzyczeć, itp.)"
- ],
- "ServerRulesHelp": [
- "Nierealistyczne akcje (powergaming) są niedozwolone. Nie jesteś superman'em.",
- "Roleplay na tle terrorystycznym jest niedozowolony.",
- "Zawszę słuchaj się administracji.",
- "Nie mieszaj czatów (metagaming). Nie możesz używać informacji w postaci, jeżeli uzyskałeś je poza nią.",
- "Używaj języka angielskiego na głównych chatach. Jeżeli nie jestes dobry z angielskiego, użyj {1}"
- ],
- "AnimationHelp": [
- "Animacje pozwalają ci bardziej wczuć się w swoją role.",
- "Używaj {1} lub {2} z nazwą by użyć animacji.",
- "By zobaczyć liste animacji, użyj {1}"
- ],
- "WeaponHelp": [
- "Odwiedź sklep z bronią, aby kupić nową broń. Użyj {1} by znaleźć taki sklep.",
- "Musisz posiadać licenje na broń, aby takową kupić.",
- "Licencje broni są wydawanie przez policję. Zaaplikuj się tam, aby taką zdobyć.",
- "Bronie mogą być też kupowane nielegalnie od niektórych bizensów, dealerów broni i klanów."
- ],
- "SkinHelp": [
- "W sklepie z ubraniami, użyj {1} aby kupić ubrania.",
- "Kiedy masz ubrania, wyposaż się w nie i użyj je jak każdy inny przedmiot by ukazać modyfikacje postaci (sprawdź {1} aby zobaczyć jak używać itemy)",
- "Niektóre skiny są dostępne tylko dla niektórych osób, klanów lub z innych powodów."
- ],
- "KeyBindHelp": [
- "Możesz zmienić przypisania klawiszy. Użyj {1} aby zobaczyć twoje przypisane klawisze.",
- "Użyj {1} aby dodać nowe przypisanie i {2} aby je usunąć.",
- "Domyślnymi przyciskami są: {1} aby uruchomić pojazd, {1} aby użyć świateł, and {3} aby otworzyć/zamknąć pojazd",
- "Naciśnij {1} aby zobaczyć swoje itemy i {2} aby wyposażyć się w jakiś przedmiot lub {3} aby go schować.",
- "Naciśnij {1} aby użyć przedmiot, który trzymasz, naciśnij {2} aby go upuścić lub naciśnij {3} aby podnieść jakiś przedmiot z ziemi."
- ],
- "BusinessHelp": [
- "Użyj {1} aby kupować przedmioty lub {2} aby zobaczyć listę co jest na sprzedaż w jakimkolwiek bizensie.",
- "Biznesy mają niebieskie nazwy nad ikoną przy ich wejściu.",
- "Komendy właściciela biznesu: {1}",
- "Nowe auto na sprzedaż pojawi się po odjechaniu od dealera samochodów."
- ],
- "ClanHelp": [
- "Zapytaj administratora o stworzenie klanu (Podobne do fakcji/grup/rodzin)",
- "Właściciele klanu mają pełną kontrole over nad ich klanem od momentu gdy jest stworzony",
- "Komendy klanu: {1}",
- "Więcej komend klanu: {1}"
- ],
- "RadioStationHelp": [
- "Użyj {1} by ustawić stację twojego auta, mieszkania lub biznesu",
- "Użyj {2} by zobaczyć listę stacji",
- "Możesz zmienić głośność swojego radia używając {1} i liczbą od 0 do 100 jako procenty"
- ],
- "WealthAndTaxHelp": [
- "Twoje podatki przy wypłacie są {1} procentami twojego przeliczonego bogactwa.",
- "Twoja przeliczone bogactwo jest obliczone wliczając twoje pojazdy, mieszkania i biznesy, które posiadasz.",
- "Każdy pojazd jest {1}, każde mieszkanie jest {2} i każdy biznes jest {3}",
- "Użyj {1} aby zobaczyć swoje bogactow i {2} zobaczyć ile będziesz musiał zapłacić przy następnej wypłacie"
- ],
- "MustBeInAVehicle": "Musisz być w pojeździe!",
- "MustBeInOrNearVehicle": "Musisz być w lub obok pojazdu!",
- "MustBeInVehicleFrontSeat": "Musisz być w przednim siedzeniu pojazdu!",
- "MustBeInVehicleDriverSeat": "Musisz być kierowcą pojazdu!",
- "DontHaveVehicleKey": "Nie masz klucza do tego pojazdu!",
- "NoGateAccess": "Nie masz dostępu do tej bramy!",
- "GateBroken": "Ta brama jest popsuta!",
- "GateHacked": "Ta brama nie odpowiada!",
- "RadioJammed": "Słysysz tylko szumy z radia.",
- "VehicleNotForSale": "To auto nie jest na sprzedaż!",
- "VehicleNotForRent": "Tego pojazdu nie można wypożyczyć!",
- "BusinessNotForSale": "Ten biznes nie jest na sprzedaż!",
- "BusinessNotForRent": "Tego biznesu nie można wypożyczyć!",
- "HouseNotForSale": "This house is not for sale!",
- "HouseNotForRent": "Tego biznesu nie można wypożyczyć!",
- "DealershipPurchaseTestDrive": "Odjedź pojazdem od dealera samochodów aby go kupić, lub wysiądź aby anulować zakup.",
- "DealershipPurchaseExitedVehicle": "Anulowałeś kupno pojazdu, ponieważ wysiadłeś z pojazdu!",
- "VehiclePurchaseComplete": "Ten pojazd jest teraz twój, zapiszę się nieważne gdzie jest.",
- "VehiclePurchaseNotEnoughMoney": "Nie masz wystarczająco dużo funduszy aby kupić to auto!",
- "HousePurchaseNotEnoughMoney": "Nie masz wystarczająco dużo funduszy aby kupić to mieszkanie!",
- "BusinessPurchaseNotEnoughMoney": "Nie masz wystarczająco dużo funduszy aby kupić ten biznes!",
- "Locales": {
- "English": "Angielski",
- "Russian": "Rosyjski",
- "Spanish": "Hiszpański",
- "German": "Niemiecki",
- "Dutch": "Holenderski",
- "Polish": "Polski"
- },
-
- "ADDED-21JAN2022": "DO NOT TRANSLATE. This string is just a comment to separate newly added translations.",
- "HeaderPlayerHousesList": "Mieszkania Gracza ({1})",
- "HeaderPlayerStaffFlagsList": "Flagi Administracji ({1})",
- "HeaderStaffFlagsList": "Flagi Administracji",
- "NonRPName": "Nieprawidłowa nazwa roleplay! Wybierz nową:",
- "InvalidStaffFlag": "Flaga administracji nie znaleziona!",
- "InvalidClanFlag": "Flaga klanu nie znaleziona!",
- "InvalidLocale": "Język nie znaleziony!",
- "HeaderJobUniformList": "Mundury robocze ({1})",
- "HeaderJobEquipmentList": "Wyposażenie robocze ({1})",
- "InvalidJobUniform": "Mundur roboczy nie znaleziony!",
- "InvalidJobEquipment": "Wyposażenie robocze nie znalezione!",
- "HeaderVehiclesInRangeList": "Pojazdy w {1}",
- "NoVehiclesWithInRange": "Nie ma pojazdów w {1}",
- "AmountNotNumber": "Ilość musi być liczbą!",
- "NeedToBeWorking": "Musisz być w pracy! Użyj {1} w punkcie pracy lub obok pojazdu służbowego.",
- "NeedToBeOnJobRoute": "Musisz być w trasie! Użyj {1} w pojeździe służbowym",
- "CurrentJobRouteDeleted": "Trasa służbowa, którą jechałeś została usunięta przez Administratora",
- "CurrentJobRouteVehicleColoursChanged": "Kolory pojazdów na twojej trasie zostały zmienione przez Administratora.",
- "NotYourJob": "To nie twoja praca!",
- "JobPoints": "Możesz zdobyć pracę udając się do żółtych punktów na mapie.",
- "QuitJobToTakeAnother": "Jeżeli chcesz tą prace, użyj {1} aby opuścić swoją dotychczasową pracę.",
- "NotAJobVehicle": "To nie jest pojazd służbowy!",
- "NotYourJobVehicle": "To nie jest twój pojazd służbowy!",
- "JobRouteDisabled": "Trasa służbowa, którą jechałeś została usunięta przed Administratora",
- "HeaderPickupTypes": "Rodzaję Pickup'ów",
- "HeaderBlipTypes": "Rodzaje Ikon Mapy",
- "InvalidGPSLocation": "Nie ma lokalizacji z taką nazwą lub rodzajem",
- "HeaderBusinessList": "Biznesy",
- "VehicleForSale": "Ten {1} jest do kupienia za {2}! Użyj {3} jeżeli chcesz go kupić",
- "VehicleForRent": "Ten {1} jest do wynajęcia za {2}! Użyj {3} jeżeli chcesz go wynająć",
-
- "ADDED-31JAN2022": "DO NOT TRANSLATE. This string is just a comment to separate newly added translations.",
- "LoginFailedInvalidPassword": "Nieprawidłowe hasło! Pozostało {1} prób",
- "LoginFailedNoPassword": "Musisz podać hasło! ! Pozostało {1} prób",
- "RegistrationFailedNoPassword": "Musisz podać hasło!",
- "RegistrationFailedNoPasswordConfirm": "Musisz potwierdzić hasło!",
- "RegistrationFailedNoEmail": "Musisz podać adres email!",
- "AccountNameAlreadyRegistered": "Twoja nazwa jest już zarejestrowana!",
- "AlreadyLoggedIn": "Jesteś już zalogowany!",
- "RegistrationFailedInvalidEmail": "Nieprawidłowy adres email!",
- "RegistrationFailedPasswordMismatch": "Hasła się nie zgadzają!",
- "RegistrationFailedCreateError": "Nie udało się stworzyć twojego konta!",
- "RegistrationSuccess": "Twoje konto zostało utworzone!",
- "RegistrationEmailVerifyReminder": "Nie zapomnij zweryfikować swojego adresu email! Kod werifikacyjny został wysłany na twój adres email.",
- "RegistrationCreateCharReminder": "Aby zagrać na serwerze, musisz stworzyć postać.",
- "NoCharactersGUIMessage": "Nie masz postaci. Czy chciałbyś ją stworzyć?",
- "NoCharactersGUIWindowTitle": "Brak postaci",
- "NoCharactersChatMessage": "Nie masz postaci. Użyj {1} aby ją stworzyć.",
- "NeedEmailFor2FA": "Musisz przypisać adres email do swojego konta, aby używać weryfikacji dwuetapowej.",
- "NeedEmailVerifiedFor2FA": "Musisz zweryfikować swój adres email, aby używać weryfikacji dwuetapowej",
- "SetEmailHelpTip": "Użyj {1} aby ustawić swój adres email.",
- "VerifyEmailHelpTip": "Użyj {1} aby zweryfikować swój adres email.",
-
- "ADDED-13FEB2022": "DO NOT TRANSLATE. This string is just a comment to separate newly added translations.",
- "NearbyRadio": "Pobliskie radio",
- "FromRadio": "Z radia",
- "ToRadio": "Do radia",
- "NeedToEnterPropertyCommand": "Musisz najpierw wejść do {1}! Użyj {2} aby wejść lub wyjść",
- "NeedToEnterPropertyKeyPress": "Musisz najpierw wejść do {1}! Naciśnij {2} aby wejść lub wyjść",
- "InventoryFullCantCarry": "Nie masz miejsca aby to podnieść (pełny ekwipunek)!",
- "NotEnoughCashNeedAmountMore": "Nie masz wystarczająco miejsca! Potrzebujesz jeszcze {1}!",
- "AmountMustBeMoreThan": "Wartość musi być większa od {1}!",
- "WeaponBanned": "Nie możesz używać ani kupować broni!",
- "TimeNotNumber": "Czas musi być numerem",
- "HeaderDefaultBusinessItemTypes": "Wzory przedmiotów biznesowych",
- "FixingStuck": "Naprawianie twojej pozycji i świata wirtualnego ...",
- "CantUseCommandYet": "Musisz poczekać zanim znowu użyjesz tej komendy!",
- "NotATester": "Nie jesteś testerem!",
- "AccessDenied": "OdmowaDostępu",
- "InvalidSkin": "Ta skórka jest nieprawidłowa!",
- "HeaderInteriorTypes": "Wnętrza"
-}
diff --git a/locale/russian.json b/locale/russian.json
deleted file mode 100644
index b9a0ade7..00000000
--- a/locale/russian.json
+++ /dev/null
@@ -1,394 +0,0 @@
-{
- "TranslationProvidedBy": "VNDTTS",
- "LocaleEnglishName": "Russian",
- "LocaleNativeName": "Русский",
- "LocaleOffer": "Этот сервер доступен на русском. Используйте {1} чтобы его использовать.",
- "LocaleChanged1": "Ваш язык был установлен на {1}",
- "LocaleChanged2": "Этот сервер теперь будет показывать сообщения в {1}",
- "LocaleChangedNote": "Это не влияет на сообщения других игроков",
- "AccentsListHeader": "Акценты",
- "HeaderHelpMainList": "Помощь Категории",
- "AccentNotFound": "Не удалось найти акцент",
- "AccentSet": "Вы установили свой акцент на {1}",
- "AnimationNotFound": "Такой анимации не существует",
- "AnimationCommandTip": "Используйте {1} чтобы просмотреть список доступных анимаций",
- "AnimationInvalidDistance": "Дистанция должна быть между 0 и 3",
- "AnimationStopCommandTip": "Используйте {1} чтобы остановить анимацию",
- "CantBanClient": "Вы не можете забанить этого игрока",
- "PlayerAccountBanned": "Аккаунт {1} был заблокирован ",
- "ClanNotFound": "Не удалось найти клан",
- "ClanNameTaken": "Клан с таким именем уже существует",
- "PlayerNotFound": "Не удалось найти игрока",
- "ClanCantRemoveRanks": "Вы не можете убрать ранги клана",
- "ClanCantAddRanks": "Вы не можете добавить новые ранги клана",
- "ClanRankNotFound": "Не удалось найти ранг клана",
- "ClanCantChangeMemberTag": "Вы не можете изменить теги членов клана",
- "ClanPlayerNotInSameClan": "Игрок не в вашем клане",
- "ClanCantChangeRankLevel": "Вы не можете изменить уровень ранга клана",
- "ClanCantChangeRankTag": "Вы не можете изменить теги ранга клана",
- "NameNotRegistered": "Ваше имя не зарегестрировано! Используйте {1} чтобы создать аккаунт.",
- "AutomaticLoginIPToggle": "Автоматический вход по IP теперь {1}",
- "CouldNotRegisterAccount": "Возникла проблема при создании аккаунта. Пожалуйста свяжитесь с администратором.",
- "RandomTipsToggle": "Случайные подсказки теперь {1}",
- "ActionTipsToggle": "Местные подсказки теперь {1}",
- "AutoSpawnLastCharToggle": "Автоматическое возрождение как последний выбраный персонаж теперь {1}",
- "AccountGUISettingToggle": "GUI теперь {1}",
- "On": "Включен",
- "Off": "Выключен",
- "Yes": "Да",
- "No": "Нет",
- "True": "Верно",
- "False": "Неверно",
- "Locked": "Закрыто",
- "Unlocked": "Открыто",
- "PasswordNotGoodEnough": "Новый пароль должен соответсвовать требованиям !",
- "PasswordNeedsBase": "Пароль должен местить не меншьше {1}",
- "PasswordNeedsCapitals": "{1} Заглавные буквы",
- "PasswordNeedsNumbers": "{1} цифры",
- "PasswordNeedsSymbols": "{1} символы",
- "PasswordsDontMatch": "Новый пароль и его подтверджение не совпадают!",
- "PasswordChanged": "Ваш пароль был изменен!",
- "AutoLoggedInIP": "Вы автоматически войшли по IP!",
- "WelcomeBack": "Добро пожаловать {1}, {2}! Используйте {3} чтобы продолжить.",
- "WelcomeNewPlayer": "Добро пожаловать в {1}, {2}! Используйте {3} чтобы начать играть.",
- "InvalidPlayer": "Не удалось найти игрока!",
- "InvalidBusiness": "Не удалось найти бизнес!",
- "InvalidHouse": "Не удалось найти дом!",
- "InvalidVehicle": "Не удалось найти транспорт!",
- "InvalidClan": "Не удалось найти клан!",
- "InvalidClanRank": "Не удалось найти ранг клана!",
- "InvalidJob": "Не удалось найти работу!",
- "InvalidItem": "Не удалось найти предмет!",
- "InvalidItemType": "Не удалось найти предмет!",
- "InvalidRadioStation": "Не удалось найти радиостанцию!",
- "InvalidGate": "Не удалось найти ворота!",
- "EntersProperty": "открывает дверь и входит в {1}",
- "ExitsProperty": "открывает дверь и покидает {1}",
- "EnterExitPropertyDoorLocked": "пытаеться открыть двери {1} но у него не выходить потому-что двери закрыты",
- "PropertyNoInterior": "У {1} нет доступного интерьера, но вы все еще можете использовать комманды стоя на значке возле входа.",
- "NoBusinessWithItemType": "Нет бизнесов в которых этот предмет доступен",
- "HeaderKeyBinds": "Привязки",
- "HeaderAccountHelp": "Помощь Аккаунт",
- "HeaderVehicleHelp": "Помощь Транспорт",
- "HeaderVehicleDealershipHelp": "Помощь Автосалон",
- "HeaderJobHelp": "Помощь Работа",
- "HeaderChatHelp": "Помощь Чат",
- "HeaderServerRules": "Правила Сервера",
- "HeaderWebsiteInfo": "Сайт",
- "HeaderDiscordInfo": "Discord",
- "HeaderAnimationsList": "Список Анимаций",
- "HeaderPayAndSprayHelp": "Помощь Pay 'n' Spray",
- "HeaderAmmunationHelp": "Помощь Аммунация",
- "HeaderVehicleTuneupHelp": "Помощь Тюнинг Автомобиля",
- "HeaderBindableKeysHelp": "Кнопки которые можно привязать",
- "HeaderSkinHelp": "Помощь Одежда/Облик",
- "HeaderBusinessHelp": "Помощь Бизнес",
- "HeaderClanHelp": "Помощь Клан",
- "HeaderPlayerVehiclesList": "Транспорт Игрока ({1})",
- "HeaderPlayerBusinessesList": "Бизнесы Игрока ({1})",
- "HeaderClansList": "Список кланов",
- "HeaderAdminsList": "Список администраторов",
- "HeaderBadgeInfo": "Информация значка",
- "HeaderAccentsList": "Список акцентов",
- "HeaderPlayerInfo": "Информация об игроке ({1})",
- "HeaderWealthandTaxHelp": "Информация о достатке и налогах",
- "HeaderCommandInfo": "Информация о команде ({1})",
- "HeaderRadioHelp": "Помощь Радио",
- "HeaderRadioStationsList": "Радиостанции",
- "HeaderKeyBindsList": "Список привязок",
- "RadioVolumeChanged": "{1} Вы сменили громкость звука на {2}%",
- "VolumeLevelNotNumber": "Уровень звука должен быть в цифрах",
- "RadioStationLocationInvalid": "Вы должны находится в транспорте, доме, или бизнесе или иметь устройство чтобы сменить радиостанцию!",
- "ActionBusinessRadioStationChange": "меняет радиостанцию бизнеса на {1} ({2})",
- "ActionHouseRadioStationChange": "меняет радиостанцию дома на {1} ({2})",
- "ActionVehicleRadioStationChange": "меняет радиостанцию транспорта на {1} ({2})",
- "ActionItemRadioStationChange": "переключает станцию {1} на станцию {2} ({3})",
- "RandomVehicleCommandsDisabled": "Это случайная машина трафика, команды на нее не работают.",
- "HouseDoorLock": "Дом {1} {2}!",
- "BusinessDoorLock": "Бизнес {1} {2}!",
- "ServerGameModeRestarting": "Режим игры сервера перезапускается!",
- "HeaderSelfItemList": "Ваш инвентарь",
- "HeaderPlayerItemList": "Инвентарь игрока ({1})",
- "HeaderHouseItemList": "Инвентарь дома",
- "HeaderBusinessFloorItemList": "Инвентарь бизнеса (Продажа)",
- "HeaderBusinessStorageItemList": "Инвертарь бизнеса (Хранилище)",
- "HeaderItemItemList": "Инвентарь {1}",
- "ItemSlotNotNumber": "Слот предмета должен быть цифрой",
- "ItemSlotMustBeBetween": "Слот этого предмета должен находиться между {1} и {2}!",
- "UseItemBugged": "Предмет который вы пытаетесь использовать забагован. Баг репорт был послан разработчикам сервера.",
- "PickupItemBugged": "Предмет который вы пытаетесь поднять забагован. Баг репорт был послан разработчикам сервера.",
- "DropItemBugged": "Предмет который вы пытаетесь выкинуть забагован. Баг репорт был послан разработчикам сервера.",
- "HandsBusy": "Ваши руки заняты",
- "CantUseItemInSkinChange": "Вы не можете использовать предметы когда вы меняете свой облик",
- "CantDropItemInSkinChange": "Вы не можете кидать предметы когда вы меняете свой облик",
- "CantPickupItemInSkinChange": "Вы не можете подбирать предметы когда вы меняете свой облик",
- "CantSwitchItemInSkinChange": "Вы не можете переключать предметы когда вы меняете свой облик",
- "CantGiveItemInSkinChange": "Вы не можете давать предметы когда вы меняете свой облик",
- "CantTakeItemInSkinChange": "Вы не можете брать предметы когда вы меняете свой облик",
- "ItemUnequippableNoAmmo": "{1} на слоте {2} не имеет патронов и не может быть экипирован!",
- "NoSpaceSelfInventory": "У вас не осталось места в инвентаре",
- "Business": "бизнес",
- "House": "дом",
- "Clan": "клан",
- "Vehicle": "транспорт",
- "Item": "предмет",
- "ItemType": "тип предмета",
- "Gate": "ворота",
- "Door": "двери",
- "ClanRank": "Ранг клана",
- "JobRank": "Ранг работы",
- "RadioStation": "радиостанция",
- "Months": [
- "Январь",
- "Февраль",
- "Март",
- "Апрель",
- "Май",
- "Июнь",
- "Июль",
- "Август",
- "Сентябрь",
- "Октябрь",
- "Ноябрь",
- "Декабрь"
- ],
- "WeekDays": [
- "Воскресенье",
- "Понедельник",
- "Вторник",
- "Среда",
- "Четверг",
- "Пятница",
- "Субота"
- ],
- "CardinalDirections": [
- "Север",
- "Северо-восток",
- "Восток",
- "Юго-восток",
- "Юг",
- "Юго-запад",
- "Запад",
- "Северо-запад"
- ],
- "NewPlayerReadyToPlay": [
- "Вам было надано немного денег. Используйте {1} чтобы найти места в которых можно купить предметы.",
- "Если вам нужны деньги, желтые точки это места работы на карте.",
- "Если вам нужен транспорт, посетите автосалон. Вы также можете использовать орендовочный транспорт возле начальной зоны или сесть на поезд",
- "Не забудьте ознакомиться с {1} и использовать {2} для информации."
- ],
- "YourCurrentVehicleDeleted": "Транспорт в котором вы находились было удалено.",
- "Distance": "Дистанция",
- "Meters": "Метров",
- "Feet": "Футов",
- "Kilometers": "Километры",
- "Miles": "Мили",
- "MustBeVehicleDriver": "Вы можете быть только водителем!",
- "PlayerJoinedServer": "{1} присоеденился к игре из {1}!",
- "PlayerLeftServer": "{1} покинул игру! ({1})",
- "DisconnectReasons": [
- "Потеряно соединение",
- "Отключен",
- "Неподерживаемый клинт",
- "Неправильная игра",
- "Неправильный пароль",
- "Неподдерживаемый Exe",
- "Disconnected",
- "Забанен",
- "Не удалось",
- "Не правильное имя",
- "Вылетел"
- ],
- "TakeItemFromHouse": "Берет {1} из дома",
- "TakeItemFromBusinessStorage": "Берет {1} из хранилища",
- "TakeItemFromBusiness": "Берет {1} из бизнеса",
- "TakeItemFromItem": "Достает {1} из {2}",
- "TakeItemFromVehicleTrunk": "Достает {1} из багажника",
- "TakeItemFromVehicleDash": "Достает {1} из бардачка",
- "JobEquipmentInventoryKeyBindTip": "Рабочее снаряжение у вас в инвентаре. Нажмите {1} чтобы его просмотреть.",
- "JobEquipmentInventoryCommandTip": "Рабочее снаряжение у вас в инвентаре. Используйте {1} чтобы его просмотреть.",
- "AccountHelp": [
- "Не предоставляйте свой пароль никому. {1} персонал никогда не будет спрашивать у вас пароль ",
- "Используйте {1} чтобы изменить ваш пароль, и {2} если вы его забыли",
- "Некоторые опции: {1}"
- ],
- "VehicleHelp": [
- "Ваш личный транспорт будет сохранен в любом месте где вы, или кто-либо другой его оставит!",
- "Посетите автосалон чтобы приобрести новый транспорт (Используйте {1} чтобы увидеть больше информации)",
- "Некоторые комманды: {1}",
- "Посетите гараж механика чтобы починить, изменить цвет, и затюнинговать ваш автомобиль! {1} для информации"
- ],
- "VehicleDealershipHelp": [
- "Посетите автосалон чтобы приобрести новый транспорт. Используйте {1} чтобы найти его.",
- "Ввойдите в транспорт который вы хотите приобрести, и цена на него будет вам показана",
- "Если хотите приобрести транспорт, используйте {1} и вам дадут ключи чтобы провести тест-драйв на парковке.",
- "Покиньте автосалон на вашем новом транспорте чтобы подвердить покупку."
- ],
- "JobHelp": [
- "Посетите места работы, получите работу и зарабатывайте деньги. Ищите желтые точки на карте",
- "На месте работы, используйте {1} чтобы получить работу. Используйте {2} чтобы оставить работу",
- "Используйте {1} чтобы начать работать. Вы также можете получить работу {2} и {3}",
- "Большинство рабочего транспорта изначально закрыто. Используйте {1} находясь возле него чтобы войти.",
- "Во время входа в рабочий транспорт, информация о том, как работать будет вам предоставлена."
- ],
- "ChatHelp": [
- "Существуют два основных типов чата: внутри персонажа и вне его",
- "Смешивать их не считается полноценной ролевой игрой. Просмотрите {1} для информации.",
- "Некоторые комманды чата: {1}",
- "Некоторые имеют укороченые версии ({1} чтобы говорить, {2} чтобы выкрикивать, и так далее)"
- ],
- "ServerRulesHelp": [
- "Нереалистичные действия запрещены. Вы не супермен.",
- "Ролевая игра за террориста и терроризм запрещены.",
- "Всегда следуйте соблюдайте инструкии даные модератором или администратором.",
- "Вам не позволяется использовать информацию полученую вне персонажа, персонажем ",
- "Пожалуйста придерживаетесь английского в главном чате, если вы плохо знаете английский, используйте {1}"
- ],
- "AnimationHelp": [
- "Анимации позволяют вам улучшить составляющую ролевой игры с помощью визуальных действий",
- "Используте {1} или {2} с названием тобы применить анимацию.",
- "Чтобы просмотреть список доступных анимаций, используйте {1}"
- ],
- "WeaponHelp": [
- "Посетите магазин оружия что-бы приобрести оружие. Используйте {1} чтобы найти.",
- "Оружие невозможно купить без лицензии.",
- "Лицензиями на оружие занимается отделение полиции. Обратитесь туда чтобы заполучить лицензию.",
- "Оружие также может быть приобретено нелегально от некоторых бизнесов, торговцев оружием, и кланов."
- ],
- "SkinHelp": [
- "В магазине одежды используйте {1} чтобы купить одежду",
- "Когда у вас есть предмет одежды, экипируйте его и используйте его как любой другой предмет чтобы просмотреть меню выбора облика персонажа (Просмотрите {1} чтобы научиться использовать предметы)",
- "Некоторые облики ограничены только для некоторых работ, кланов, или по каким-то другим причинам."
- ],
- "KeyBindHelp": [
- "Вы можете сами создавать ваши привязки на кнопки. Используйте {1} чтобы просмотреть ваши привязки.",
- "Используйте {1} чтобы добавить новую приязку или {2} чтобы убрать ее.",
- "Стандартные привязки: {1} для мотора, {1} для фар, и {3} для открытия/закрытия",
- "Используйте {1} чтобы просмотреть ваши предметы {2} чтобы экипировать предмет или {3} чтобы убрать.",
- "Используйте {1} чтобы использвать предмет который вы держите в руках, используйте {2} чтобы его выбростить, или используйте {3} чтобы подобрать предмет."
- ],
- "BusinessHelp": [
- "Используйте {1} чтобы покупать предметы или {2} чтобы просмотреть список того, что продаеться в любом бизнесе",
- "Бизнесы имеют их названия синим цветом над иконкой возле входа.",
- "Комманды владельца бизнеса: {1}",
- "Новый автомобиль появится после того как вы уедете из автосалона."
- ],
- "ClanHelp": [
- "Попросите администратора чтобы основать клан",
- "Владельцы клана имеют полный контроль над ихним кланом после его основания",
- "Комманды клана: {1}",
- "Больше комманд клана: {1}"
- ],
- "RadioStationHelp": [
- "Используйте {1} чтобы выбрать радиостанцию для вашего траспорта, дома, или бизнеса",
- "Используйте {2} чтобы просмотреть список радиостанций",
- "Вы можете изменить громкость радио используя {1} с 0-100 в качестве процентов"
- ],
- "WealthAndTaxHelp": [
- "Вы платите {1} процентов от вашего расчетного уровня достатка.",
- "Ваш расчетный уровень достатка зависит от того, сколько вам принадлежит транспорта, домов и бизнесов.",
- "Каждый транспорт это {1}, каждый дом это {2}, И каждый бизнес это {3}",
- "Используйте {1} чтобы просмотреть ваш текущий достаток, и {2} чтобы просмотреть сколько вы платите налогов с каждой зарплаты"
- ],
- "MustBeInAVehicle": "Вы должны быть внутри транспорта!",
- "MustBeInOrNearVehicle": "Вы должны быть возле транспорта!",
- "MustBeInVehicleFrontSeat": "Вы можете сидеть только спереди!",
- "MustBeInVehicleDriverSeat": "Вы можете быть только водителем!",
- "DontHaveVehicleKey": "У вас нет ключей к этому транспорту!",
- "NoGateAccess": "У вас нет доступа к воротам!",
- "GateBroken": "Эти ворота сломаны!",
- "GateHacked": "Ворота не отвечают!",
- "RadioJammed": "Из радио доносится лишь шум.",
- "VehicleNotForSale": "Этот транспорт не продается!",
- "VehicleNotForRent": "Этот транспорт не сдается в оренду! ",
- "BusinessNotForSale": "Этот бизнес не продается!",
- "BusinessNotForRent": "Этот бизнес не сдается в оренду!",
- "HouseNotForSale": "Этот дом не продаеться!",
- "HouseNotForRent": "Этот дом не сдаеться в оренду!",
- "DealershipPurchaseTestDrive": "Уедьте из автосалона чтобы подтвердить покупку транспорта, или выйдете из него чтобы отменить.",
- "DealershipPurchaseExitedVehicle": "Вы отменили покупку транспорта покинув его!",
- "VehiclePurchaseComplete": "Этот транспорт теперь принадлежит вам! Он останется там где вы его оставили.",
- "VehiclePurchaseNotEnoughMoney": "у вас недостаточно денег для покупки этого транспорта!",
- "HousePurchaseNotEnoughMoney": "У вас недостаточно денег для покупки этого дома!",
- "BusinessPurchaseNotEnoughMoney": "У вас недостаточно денег для покупки этого бизнеса!",
- "Locales": {
- "English": "Английский",
- "Russian": "Русский",
- "Spanish": "Испанский",
- "German": "Немецкий",
- "Dutch": "Нидерландский"
- },
-
- "ADDED-21JAN2022": "DO NOT TRANSLATE. This string is just a comment to separate newly added translations.",
- "HeaderPlayerHousesList": "Дома Игрока ({1})",
- "HeaderPlayerStaffFlagsList": "Флаги игрока персонала ({1})",
- "HeaderStaffFlagsList": "Флаги персонала",
- "NonRPName": "Ваше имя не подходит для ролевой игры! Выберете другое:",
- "InvalidStaffFlag": "Не удалось найти флаг персонала!",
- "InvalidClanFlag": "Не удалось найти флаг клана!",
- "InvalidLocale": "Не удалось найти язык!",
- "HeaderJobUniformList": "Рабочие униформы ({1})",
- "HeaderJobEquipmentList": "Рабочие снаряжение ({1})",
- "InvalidJobUniform": "Не удалось найти рабочую униформу!",
- "InvalidJobEquipment": "Не удалось найти рабочее снаряжение!",
- "HeaderVehiclesInRangeList": "Транспорт в пределах {1}",
- "NoVehiclesWithInRange": "Нет транспорта в пределах {1}",
- "AmountNotNumber": "Количество должно быть введено цифрой!",
- "NeedToBeWorking": "Вы должны быть на работе! Используйте {1} на месте работы или возле рабочего транспорта.",
- "NeedToBeOnJobRoute": "Вы должны быть на рабочем маршруте! Используйте {1} в рабочем транспорте",
- "CurrentJobRouteDeleted": "Рабочий маршрут на котором вы находились был удален администратором",
- "CurrentJobRouteVehicleColoursChanged": "Цвет транспорта на маршруте был изменен администратором",
- "NotYourJob": "Это работа пренадлежит не вам!",
- "JobPoints": "Вы можете устроиться на работу ориентируясь по желтым значкам на карте.",
- "QuitJobToTakeAnother": "Если хотите покинуть работу, ипользуйте {1}.",
- "NotAJobVehicle": "Это не рабочий транспорт!",
- "NotYourJobVehicle": "Этот транспорт пренадлежит не вашей работе!",
- "JobRouteDisabled": "Рабочий маршрут на котором вы были был удален администратором",
- "HeaderPickupTypes": "Типы подбираемых предметов",
- "HeaderBlipTypes": "Типы иконок карты",
- "InvalidGPSLocation": "Не существует локаций с таки именем или такого типа",
- "HeaderBusinessList": "Бизнесы",
- "VehicleForSale": "Этот {1} можно купить за {2}! Используйте {3} если хотите его купить",
- "VehicleForRent": "Этот {1} может быть орендован за {2}! Используйте {3} если хотите его орендовать",
-
- "ADDED-31JAN2022": "DO NOT TRANSLATE. This string is just a comment to separate newly added translations.",
- "LoginFailedInvalidPassword": "Неправельный пароль! Осталось {1} попыток",
- "LoginFailedNoPassword": "Вы должны ввести пароль! Осталось {1} попыток",
- "RegistrationFailedNoPassword": "Вы должны ввести пароль!",
- "RegistrationFailedNoPasswordConfirm": "Вы должны подтвердить пароль!",
- "RegistrationFailedNoEmail": "Вы должны ввести адрес электронной почты!",
- "AccountNameAlreadyRegistered": "Ваше имя уже зарегистрировано!",
- "AlreadyLoggedIn": "Вы уже вошли!",
- "RegistrationFailedInvalidEmail": "Такого адреса не существует!",
- "RegistrationFailedPasswordMismatch": "Пароли не совпадают!",
- "RegistrationFailedCreateError": "Не удалось создать аккаунт!",
- "RegistrationSuccess": "Ваш аккаунт был успешно создан!",
- "RegistrationEmailVerifyReminder": "Не забудьте подтвердить ваш электронный адрес, код подверждения был послан вам на электронную почту.",
- "RegistrationCreateCharReminder": "Чтобы играть на сервере, вам нужно будет создать персонажа.",
- "NoCharactersGUIMessage": "У вас нет персонажей. Не хотите создать?",
- "NoCharactersGUIWindowTitle": "Нет персонажей",
- "NoCharactersChatMessage": "У вас нет персонажей. Используйте {1} чтобы создать.",
- "NeedEmailFor2FA": "Вам нужно добавить ваш адрес электронной почты чтобы использовать двухфакторную аунтентификацию.",
- "NeedEmailVerifiedFor2FA": "Вам нужно подтвердить вашу электронную почту чтобы использовать двухфакторную аунтентификацию.",
- "SetEmailHelpTip": "Используйте {1} чтобы установить ваш адрес электронной почты.",
- "VerifyEmailHelpTip": "Используйте {1} чтобы подтвердить ваш адрес электронной почты.",
-
- "ADDED-13FEB2022": "DO NOT TRANSLATE. This string is just a comment to separate newly added translations.",
- "NearbyRadio": "Ближайшее радио",
- "FromRadio": "Из радио",
- "ToRadio": "В радио",
- "NeedToEnterPropertyCommand": "Вам нужно сначало ввести {1}! Используйте {2} чтобы выйти",
- "NeedToEnterPropertyKeyPress": "Вам нужно сначало ввести {1}! Используйте {2} чтобы выйти",
- "InventoryFullCantCarry": "У вас недостаточно места в инвентаре(Инвентарь заполнен)!",
- "NotEnoughCashNeedAmountMore": "У вас недостаточно денег! У вас не хватает {1}!",
- "AmountMustBeMoreThan": "Количество должно быть больше {1}!",
- "WeaponBanned": "Вам нельзя покупать оружие!",
- "TimeNotNumber": "Время должно быть назначено цифрой",
- "HeaderDefaultBusinessItemTypes": "Шаблоны предметов бизнеса",
- "FixingStuck": "Исправляет вашу текущую позицию и виртуальный мир ...",
- "CantUseCommandYet": "Подождите некоторое время перед тем как использовать комманду снова!",
- "NotATester": "Вы не тестировщик!",
- "AccessDenied": "Доступ запрещен",
- "InvalidSkin": "That skin is invalid!",
- "HeaderInteriorTypes": "Interiors"
-}
diff --git a/locale/slovak.json b/locale/slovak.json
deleted file mode 100644
index 907ae1ba..00000000
--- a/locale/slovak.json
+++ /dev/null
@@ -1,478 +0,0 @@
-{
- "TranslationProvidedBy": "ZaKlaus",
- "LocaleEnglishName": "Slovak",
-
- "LocaleNativeName": "Slovak",
- "LocaleOffer": "This server is available in Slovak. Use {1} to use it.",
- "LocaleChanged1": "Your language is now set to {1}",
- "LocaleChanged2": "The server will now display messages in {1}",
- "LocaleChangedNote": "This does not change messages from other players",
- "AccentsListHeader": "Accents",
- "HeaderHelpMainList": "Help Categories",
- "AccentNotFound": "Accent not found",
- "AccentSet": "You set your accent to {1}",
- "InvalidAnimation": "That animation doesn't exist",
- "AnimationCommandTip": "Use {1} to see a list of valid animations",
- "InvalidAnimationDistance": "The distance must be between 0 and 3",
- "AnimationStopCommandTip": "Use {1} to stop your animation",
- "CantBanClient": "You cannot ban this person",
- "PlayerAccountBanned": "{1} has been account banned",
- "ClanNotFound": "Clan not found",
- "ClanNameTaken": "A clan with that name already exists",
- "PlayerNotFound": "Player not found",
- "ClanCantRemoveRanks": "You can't remove clan ranks",
- "ClanCantAddRanks": "You can't add clan ranks",
- "ClanRankNotFound": "Clan rank not found",
- "ClanCantChangeMemberTag": "You can not change clan member's tags",
- "ClanPlayerNotInSameClan": "That player is not in your clan",
- "ClanCantChangeRankLevel": "You can not change clan rank's level",
- "ClanCantChangeRankTag": "You can not change clan rank's tags",
- "NameNotRegistered": "Your name is not registered! Use {1} to make an account.",
- "AutomaticLoginIPToggle": "Automatic login by IP is now {1}",
- "CouldNotRegisterAccount": "There was a problem creating your account. Please contact an admin.",
- "RandomTipsToggle": "Random tips are now {1}",
- "ActionTipsToggle": "Action tips are now {1}",
- "AutoSpawnLastCharToggle": "Automatic spawn as last used character is {1}",
- "AccountGUISettingToggle": "GUI is now {1}",
- "On": "On",
- "Off": "Off",
- "Yes": "Yes",
- "No": "No",
- "True": "True",
- "False": "False",
- "Locked": "Locked",
- "Unlocked": "Unlocked",
- "PasswordNotGoodEnough": "The new password must meet the requirements!",
- "PasswordNeedsBase": "Passwords must have at least {1}",
- "PasswordNeedsCapitals": "{1} capital letters",
- "PasswordNeedsNumbers": "{1} numbers",
- "PasswordNeedsSymbols": "{1} symbols",
- "PasswordsDontMatch": "The new password and confirm new password aren't the same!",
- "PasswordChanged": "Your password has been changed!",
- "AutoLoggedInIP": "You have been automatically logged in by IP!",
- "WelcomeBack": "Welcome back to {1}, {2}! Please {3} to continue.",
- "WelcomeNewPlayer": "Welcome to {1}, {2}! Please {3} to play.",
- "InvalidPlayer": "Player not found!",
- "InvalidBusiness": "Business not found!",
- "InvalidHouse": "House not found!",
- "InvalidVehicle": "Vehicle not found!",
- "InvalidClan": "Clan not found!",
- "InvalidClanRank": "Clan rank not found!",
- "InvalidJob": "Job not found!",
- "InvalidItem": "Item not found!",
- "InvalidItemType": "Item type not found!",
- "InvalidRadioStation": "Radio station not found!",
- "InvalidGate": "Gate not found!",
- "EntersProperty": "opens the door and enters the {1}",
- "ExitsProperty": "opens the door and exits the {1}",
- "EnterExitPropertyDoorLocked": "tries to open the {1} door but fails because it's locked",
- "PropertyNoInterior": "This {1} does not have an interior, but you can still use commands at the door icon.",
- "NoBusinessWithItemType": "There is no business with that item available",
- "HeaderKeyBinds": "Key Binds",
- "HeaderAccountHelp": "Account Help",
- "HeaderVehicleHelp": "Vehicle Help",
- "HeaderVehicleDealershipHelp": "Vehicle Dealership Help",
- "HeaderJobHelp": "Job Help",
- "HeaderChatHelp": "Chat Help",
- "HeaderServerRules": "Server Rules",
- "HeaderWebsiteInfo": "Website",
- "HeaderDiscordInfo": "Discord",
- "HeaderAnimationsList": "Animation List",
- "HeaderPayAndSprayHelp": "Pay and Spray Help",
- "HeaderAmmunationHelp": "Ammunation Help",
- "HeaderVehicleTuneupHelp": "Vehicle Tune Help",
- "HeaderBindableKeysHelp": "Bindable Keys",
- "HeaderSkinHelp": "Clothes/Skin Help",
- "HeaderBusinessHelp": "Business Help",
- "HeaderClanHelp": "Clan Help",
- "HeaderPlayerVehiclesList": "Player Vehicles ({1})",
- "HeaderPlayerBusinessesList": "Player Businesses ({1})",
- "HeaderClansList": "Clan List",
- "HeaderAdminsList": "Admin List",
- "HeaderBadgeInfo": "Badge Information",
- "HeaderAccentsList": "Accent List",
- "HeaderPlayerInfo": "Player Information ({1})",
- "HeaderWealthandTaxHelp": "Wealth and Tax Information",
- "HeaderCommandInfo": "Command Information ({1})",
- "HeaderRadioHelp": "Radio Help",
- "HeaderRadioStationsList": "Radio Stations",
- "HeaderKeyBindsList": "Key Binds List",
- "RadioVolumeChanged": "{1} You changed your streaming radio volume to {2}%",
- "VolumeLevelNotNumber": "The volume level must be a number",
- "RadioStationLocationInvalid": "You must be in a vehicle, house, or business or have a personal device to change the station!",
- "ActionBusinessRadioStationChange": "changes the business radio station to {1} ({2})",
- "ActionHouseRadioStationChange": "changes the house radio station to {1} ({2})",
- "ActionVehicleRadioStationChange": "changes the vehicle radio station to {1} ({2})",
- "ActionItemRadioStationChange": "changes the {1}'s station to {2} ({3})",
- "RandomVehicleCommandsDisabled": "This is a random traffic vehicle and commands can't be used for it.",
- "HouseDoorLock": "House {1} {2}!",
- "BusinessDoorLock": "Business {1} {2}!",
- "ServerGameModeRestarting": "The server game mode is restarting!",
- "HeaderSelfItemList": "Your Inventory",
- "HeaderPlayerItemList": "Player Inventory ({1})",
- "HeaderHouseItemList": "House Inventory",
- "HeaderBusinessFloorItemList": "Business Inventory (For Sale)",
- "HeaderBusinessStorageItemList": "Business Inventory (Storage)",
- "HeaderItemItemList": "{1}'s Inventory",
- "ItemSlotNotNumber": "The item slot must be a number",
- "ItemSlotMustBeBetween": "The item slot must be between {1} and {2}!",
- "UseItemBugged": "The item you're trying to use is bugged. A bug report has been sent to the server developers.",
- "PickupItemBugged": "The item you're trying to pickup is bugged. A bug report has been sent to the server developers.",
- "DropItemBugged": "The item you're trying to drop is bugged. A bug report has been sent to the server developers.",
- "HandsBusy": "Your hands are busy",
- "CantUseItemInSkinChange": "You can't use an item while customizing your appearance",
- "CantDropItemInSkinChange": "You can't drop an item while customizing your appearance",
- "CantPickupItemInSkinChange": "You can't pickup an item while customizing your appearance",
- "CantSwitchItemInSkinChange": "You can't switch an item while customizing your appearance",
- "CantGiveItemInSkinChange": "You can't give an item while customizing your appearance",
- "CantTakeItemInSkinChange": "You can't take an item while customizing your appearance",
- "ItemUnequippableNoAmmo": "The {1} in slot {2} has no ammo, and can't be equipped!",
- "NoSpaceSelfInventory": "You don't have any more space in your inventory",
- "Business": "business",
- "House": "house",
- "Clan": "clan",
- "Vehicle": "vehicle",
- "Item": "item",
- "ItemType": "item type",
- "Gate": "gate",
- "Door": "door",
- "ClanRank": "clan rank",
- "JobRank": "job rank",
- "RadioStation": "radio station",
- "Months": [
- "January",
- "February",
- "March",
- "April",
- "May",
- "June",
- "July",
- "August",
- "September",
- "October",
- "November",
- "December"
- ],
- "WeekDays": [
- "Sunday",
- "Monday",
- "Tuesday",
- "Wednesday",
- "Thursday",
- "Friday",
- "Saturday"
- ],
- "CardinalDirections": [
- "North",
- "Northeast",
- "East",
- "Southeast",
- "South",
- "Southwest",
- "West",
- "Northwest"
- ],
- "NewPlayerReadyToPlay": [
- "You have been given some cash. Use {1} to find places to buy items.",
- "If you need money, jobs are the yellow dots on the radar.",
- "For a car, visit the car dealership. You can also use a rental vehicle near spawn or take the train",
- "Be sure to read the {1} and use {2} for info."
- ],
- "YourCurrentVehicleDeleted": "The vehicle you were in was deleted.",
- "Distance": "Distance",
- "Meters": "Meters",
- "Feet": "Feet",
- "Kilometers": "Kilometers",
- "Miles": "Miles",
- "MustBeVehicleDriver": "You must be the driver of the vehicle!",
- "PlayerJoinedServer": "{1} has joined the game from {1}!",
- "PlayerLeftServer": "{1} has left the game! ({1})",
- "DisconnectReasons": [
- "Lost Connection",
- "Disconnected",
- "Unsupported Client",
- "Wrong Game",
- "Incorrect Password",
- "Unsupported Executable",
- "Disconnected",
- "Banned",
- "Failed",
- "Invalid Name",
- "Crashed"
- ],
- "TakeItemFromHouse": "takes a {1} from the house",
- "TakeItemFromBusinessStorage": "takes a {1} from the business storage",
- "TakeItemFromBusiness": "takes a {1} from the business",
- "TakeItemFromItem": "takes a {1} from the {2}",
- "TakeItemFromVehicleTrunk": "takes a {1} from the trunk",
- "TakeItemFromVehicleDash": "takes a {1} from the glove compartment",
- "JobEquipmentInventoryKeyBindTip": "The job equipment is in your inventory. Press {1} to see them.",
- "JobEquipmentInventoryCommandTip": "The job equipment is in your inventory. Use {1} to see them.",
- "AccountHelp": [
- "Do NOT share your password with anybody else. {1} staff will never ask you for your password",
- "Use {1} to change your password, and {2} if you forgot it",
- "Some settings you can use: {1}"
- ],
- "VehicleHelp": [
- "Your personal vehicles will save wherever you or somebody else leaves them!",
- "Visit dealerships to buy new vehicles (Use {1} for more information)",
- "Some commands: {1}",
- "Visit a mechanic garage to repair, colour, and tune up your car! {1} for info"
- ],
- "VehicleDealershipHelp": [
- "Visit a vehicle dealer to buy new vehicles. Use {1} to find one.",
- "At the dealer, enter a car you want to buy, and the price will be shown to you",
- "If you want to buy the vehicle, use {1} and you will be given keys to test drive it around the parking lot.",
- "Drive away from the dealership with the new vehicle to confirm the purchase."
- ],
- "JobHelp": [
- "Visit job locations to get a job and earn money. Look for yellow spots on the map",
- "At a job location, use {1} to get the job. Use {2} to quit your job",
- "Use {1} to begin working. You can also get a job {2} and {3}",
- "Most job vehicles are locked. Use {1} near one to enter it.",
- "When entering a job vehicle, information on how to do the job will be shown to you."
- ],
- "ChatHelp": [
- "There are two main types of chat: out-of-character (OOC) and in-character (IC)",
- "Mixing these two types is not proper roleplay. See {1} for info.",
- "Some chat commands: {1}",
- "Some have shorter names available ({1} to talk, {2} to shout, etc)"
- ],
- "ServerRulesHelp": [
- "Unrealistic actions (powergaming) are not allowed. You aren't superman.",
- "No terrorist or terrorism roleplay is allowed.",
- "Always follow instructions given by moderators and admins.",
- "Do not mix the chats (metagaming). You can't use info in IC that was received OOC",
- "Keep English in main chats. If you aren't good at English, use {1}"
- ],
- "AnimationHelp": [
- "Animations allow you to enhance roleplay with visual actions",
- "Use {1} or {2} with a name to use an animation.",
- "To see a list of animations, use {1}"
- ],
- "WeaponHelp": [
- "Visit an gun store to buy weapons. Use {1} to find one.",
- "Buying a weapon requires a weapon license.",
- "Weapon licenses are managed by the police department. Apply there to get one.",
- "Weapons can also be purchased illegally from some businesses, weapon dealers, and clans."
- ],
- "SkinHelp": [
- "At a clothing store, use {1} to purchase clothes",
- "When you have a clothing item, equip and use it like any other item to show the skin selection (check {1} to learn how to use items)",
- "Some skins are restricted to jobs, clans, or for other reasons."
- ],
- "KeyBindHelp": [
- "You can set your own key binds. Use {1} to see your binded keys.",
- "Use {1} to add a new keybind and {2} to remove one.",
- "Default keys are: {1} for vehicle engine, {2} for lights, and {3} for lock/unlock",
- "Press {1} to see your items and {2} to equip an item or {3} to unequip all.",
- "Press {1} to use the item you're holding, press {2} to drop it, or press {3} to pickup an item from the ground."
- ],
- "BusinessHelp": [
- "Use {1} to purchase items or {2} to see a list of what's for sale at any business",
- "Businesses are shown with blue names above the icon at their entrance.",
- "Business owner commands: {1}",
- "A new car for sale will appear when you drive away from the dealer."
- ],
- "ClanHelp": [
- "Ask an administrator to create a clan (Similar to factions/groups/families)",
- "Clan owners have full control over their clan once it's created",
- "Clan commands: {1}",
- "More clan commands: {1}"
- ],
- "RadioStationHelp": [
- "Use {1} to set the station for your vehicle, house, or business",
- "Use {2} to see a list of stations",
- "You can change your radio streaming volume using {1} with 0-100 as the percent"
- ],
- "WealthAndTaxHelp": [
- "Your taxes on payday are {1} percent of your calculated wealth.",
- "Your calculated wealth is a total sum based on how many vehicles, houses, and businesses you have.",
- "Each vehicle is {1}, each house is {2}, and each business is {3}",
- "Use {1} to see your current wealth, and {2} to see how much you'll pay in tax each payday"
- ],
- "MustBeInAVehicle": "You need to be in a vehicle!",
- "MustBeInOrNearVehicle": "You need to be in or near a vehicle!",
- "MustBeInVehicleFrontSeat": "You need to be in the vehicle front seats!",
- "MustBeInVehicleDriverSeat": "You need to be the driver!",
- "DontHaveVehicleKey": "You don't have a key for this vehicle!",
- "NoGateAccess": "You don't have access to this gate!",
- "GateBroken": "This gate is broken!",
- "GateHacked": "The gate does not respond!",
- "RadioJammed": "You hear only static from the radio.",
- "VehicleNotForSale": "This vehicle is not for sale!",
- "VehicleNotForRent": "This vehicle is not for rent!",
- "BusinessNotForSale": "This business is not for sale!",
- "BusinessNotForRent": "This business is not for rent!",
- "HouseNotForSale": "This house is not for sale!",
- "HouseNotForRent": "This house is not for rent!",
- "DealershipPurchaseTestDrive": "Drive the vehicle away from the dealership to buy it, or get out to cancel.",
- "DealershipPurchaseExitedVehicle": "You canceled the vehicle purchase by exiting the vehicle!",
- "VehiclePurchaseComplete": "This vehicle is now yours! It will save wherever you leave it.",
- "VehiclePurchaseNotEnoughMoney": "You don't have enough money to buy this vehicle!",
- "HousePurchaseNotEnoughMoney": "You don't have enough money to buy this house!",
- "BusinessPurchaseNotEnoughMoney": "You don't have enough money to buy this business!",
- "Locales": {
- "English": "English",
- "Russian": "Russian",
- "Spanish": "Spanish",
- "German": "German",
- "Dutch": "Dutch",
- "Polish": "Polish"
- },
-
- "ADDED-21JAN2022": "DO NOT TRANSLATE. This string is just a comment to separate newly added translations.",
- "HeaderPlayerHousesList": "Player Houses ({1})",
- "HeaderPlayerStaffFlagsList": "Player Staff Flags ({1})",
- "HeaderStaffFlagsList": "Staff Flags",
- "NonRPName": "Non-RP name! Choose a new one:",
- "InvalidStaffFlag": "Staff flag not found!",
- "InvalidClanFlag": "Clan flag not found!",
- "InvalidLocale": "Language not found!",
- "HeaderJobUniformList": "Job Uniforms ({1})",
- "HeaderJobEquipmentList": "Job Equipment ({1})",
- "InvalidJobUniform": "Job uniform not found!",
- "InvalidJobEquipment": "Job equipment not found!",
- "HeaderVehiclesInRangeList": "Vehicles within {1}",
- "NoVehiclesWithInRange": "There are no vehicles within {1}",
- "AmountNotNumber": "The amount must be a number!",
- "NeedToBeWorking": "You need to be working! Use {1} at a job location or near a job vehicle.",
- "NeedToBeOnJobRoute": "You need to be doing a job route! Use {1} in a job vehicle",
- "CurrentJobRouteDeleted": "The job route you were on has been deleted by an admin",
- "CurrentJobRouteVehicleColoursChanged": "Your job route's vehicle colours were changed by an admin",
- "NotYourJob": "This is not your job!",
- "JobPoints": "You can get a job by going the yellow points on the map.",
- "QuitJobToTakeAnother": "If you want this job, use {1} to quit your current job.",
- "NotAJobVehicle": "This is not a job vehicle!",
- "NotYourJobVehicle": "This is not your job's vehicle!",
- "JobRouteDisabled": "The job route you were on has been disabled by an admin",
- "HeaderPickupTypes": "Pickup Types",
- "HeaderBlipTypes": "Map Icon Types",
- "InvalidGPSLocation": "There are no locations with that name or type",
- "HeaderBusinessList": "Businesses",
- "VehicleForSale": "This {1} is buyable for {2}! Use {3} if you want to buy it",
- "VehicleForRent": "This {1} is rentable for {2}! Use {3} if you want to rent it",
-
- "ADDED-31JAN2022": "DO NOT TRANSLATE. This string is just a comment to separate newly added translations.",
- "LoginFailedInvalidPassword": "Invalid password! {1} attempts remaining",
- "LoginFailedNoPassword": "You must enter a password! ! {1} attempts remaining",
- "RegistrationFailedNoPassword": "You must enter a password!",
- "RegistrationFailedNoPasswordConfirm": "You must confirm the password!",
- "RegistrationFailedNoEmail": "You must enter an email!",
- "AccountNameAlreadyRegistered": "Your name is already registered!",
- "AlreadyLoggedIn": "You are already logged in!",
- "RegistrationFailedInvalidEmail": "That email is invalid!",
- "RegistrationFailedPasswordMismatch": "The passwords don't match!",
- "RegistrationFailedCreateError": "Your account couldn't be created!",
- "RegistrationSuccess": "Your account has been created!",
- "RegistrationEmailVerifyReminder": "Don't forget to verify your email! A verification code has been sent to you.",
- "RegistrationCreateCharReminder": "To play on the server, you will need to make a character.",
- "NoCharactersGUIMessage": "You have no characters. Would you like to make one?",
- "NoCharactersGUIWindowTitle": "No characters",
- "NoCharactersChatMessage": "You have no characters. Use {1} to make one.",
- "NeedEmailFor2FA": "You need to add your email to your account to use two-factor authentication.",
- "NeedEmailVerifiedFor2FA": "You need to verify your email to use two-factor authentication.",
- "SetEmailHelpTip": "Use {1} to set your email.",
- "VerifyEmailHelpTip": "Use {1} to verify your email.",
-
- "ADDED-13FEB2022": "DO NOT TRANSLATE. This string is just a comment to separate newly added translations.",
- "NearbyRadio": "Nearby radio",
- "FromRadio": "From radio",
- "ToRadio": "To radio",
- "NeedToEnterPropertyCommand": "You need to enter the {1} first! Use {2} to enter and exit",
- "NeedToEnterPropertyKeyPress": "You need to enter the {1} first! Press {2} to enter and exit",
- "InventoryFullCantCarry": "You don't have any space to carry this (full inventory)!",
- "NotEnoughCashNeedAmountMore": "You don't have enough money! You need {1} more!",
- "AmountMustBeMoreThan": "The amount must be more than {1}!",
- "WeaponBanned": "You are not allowed to buy or use weapons!",
- "TimeNotNumber": "The time must be a number",
- "HeaderDefaultBusinessItemTypes": "Business Item Templates",
- "FixingStuck": "Fixing your position and virtual world ...",
- "CantUseCommandYet": "You must wait before you can use this command again!",
- "NotATester": "You are not a tester!",
- "AccessDenied": "AccessDenied",
- "InvalidSkin": "That skin is invalid!",
- "HeaderInteriorTypes": "Interiors List",
- "ViewInventoryKeyPressTip": "Press {1} to see your items",
- "ViewInventoryCommandTip": "Use {1} to see your items",
- "GUIAccountSettingToggle": "You have turned {1} GUI",
-
- "ADDED-23MAR2022": "DO NOT TRANSLATE. This string is just a comment to separate newly added translations",
- "CarCommandHelp": "You can buy a car by visiting a vehicle dealership. Use {1} for more information.",
- "SkinCommandHelp": "You can change your skin by visiting a clothes store. Use {1} for more info.",
- "BusinessVehiclesRespawned": "All business vehicles have been respawned by an admin!",
- "JobVehiclesRespawned": "All job vehicles have been respawned by an admin!",
- "PlayerVehiclesRespawned": "All player vehicles have been respawned by an admin!",
- "ClanVehiclesRespawned": "All clan vehicles have been respawned by an admin!",
- "PublicVehiclesRespawned": "All public have been respawned by an admin!",
- "EmptyVehiclesRespawned": "All empty vehicles have been respawned by an admin!",
- "AllVehiclesRespawned": "All vehicles have been respawned by an admin!",
- "AllVehiclesReloaded": "All vehicles have been reloaded by an admin!",
- "YourVehicleRespawned": "Your vehicle has been respawned!",
- "PlayerIPBanned": "{1} has been IP banned!",
- "PlayerCharacterBanned": "{1} has been character banned!",
- "PlayerSubNetBanned": "{1} has been subnet banned!",
- "CantModifyBusiness": "You can't manage or modify this business!",
- "CantModifyHouse": "You can't manage or modify this house!",
- "ServerTimeSet": "{1} set the time to {2}",
- "ServerWeatherSet": "{1} set the weather to {2}",
- "ServerSnowSet": "{1} turned falling snow {2} and ground snow {3}",
- "AllJobsReloaded": "All server jobs have been reloaded by an admin",
- "ServerLogoSet": "{1} turned the server logo image {2}",
- "ServerGUISet": "{1} turned GUI for this server {2}",
- "ServerBusinessBlipsSet": "{1} turned all business blips {2}",
- "ServerHouseBlipsSet": "{1} turned all house blips {2}",
- "ServerJobBlipsSet": "{1} turned all job blips {2}",
- "ServerBusinessPickupsSet": "{1} turned all business pickups {2}",
- "ServerHousePickupsSet": "{1} turned all house pickups {2}",
- "ServerJobPickupsSet": "{1} turned on all job pickups {2}",
- "BusinessBuyItemsLabel": "Use {1} to purchase items",
- "PropertyEnterCommandLabel": "Use {1} to enter",
- "PropertyEnterKeyPressLabel": "Press {1} to enter",
- "PropertyForSaleLabel": "For sale: ${1}",
- "PropertyForRentLabel": "For rent: ${1} every payday",
- "RemainingTaxPaidInMoney": "You covered the remaining taxes with ${1} in cash.",
- "LostMoneyFromTaxes": "You lost money since your taxes are more than your paycheck!",
- "NextPaycheckRepossessionWarning": "If you don't have enough cash to cover taxes on next paycheck, you will lose stuff!",
- "NotEnoughMoneyForTax": "You don't have enough money to cover your taxes!",
- "AssetsRepossessedForTax": "You lost {1} vehicles, {2} houses, and {3} businesses because you couldn't pay taxes!",
- "Closed": "Closed",
- "Open": "Open",
- "VehicleDealershipLabel": "Enter a vehicle as driver to buy it",
- "TakeJobLabel": "Use {1} to work here",
- "StartWorkLabel": "Use {1} to start working",
- "JobEquipAndUniformLabel": "Use {1} and {2} for job stuff, or {3} to stop working",
- "NotYourJobLabel": "You already have a different job. Use {1} if you want this one",
- "JobLabel": "{1} Job",
- "PaydayBonusSet": "{1} set the payday bonus to ${2}",
- "AllHousesReloaded": "All houses have been reloaded by an admin",
- "AllRadioStationsReloaded": "All radio stations have been reloaded by an admin!",
- "PlayerKicked": "{1} has been kicked from the server",
- "AllBusinessesReloaded": "All businesses have been reloaded by an admin!",
- "UnableToDoThat": "You aren't able to do that",
- "SetVehicleClanConfirmMessage": "Are you sure you want to give this vehicle to your clan?",
- "SetVehicleClanConfirmTitle": "Warning!",
- "SetItemPriceBelowOrderPriceMessage": "Are you sure you want to set the item price below it's order price? You will lose ${1} every purchase!",
- "SetItemPriceBelowOrderPriceTitle": "Warning!",
- "MustOwnVehicle": "You don't own this vehicle!",
- "RandomTips": [
- "Look for yellow dots on your map for job locations",
- "You can set custom key binds. Use {1} for details",
- "Use {1} if you don't want to see tips and extra information",
- "You can edit your keybinds using {1} and {2}",
- "Press ℹ️ to see your inventory, and use number keys to select an item",
- "Use {1} at a business to purchase items",
- "Found a bug? Report it with {1}",
- "Have an idea or suggestion for the server? Let the devs know using {1}",
- "Want to buy a business? Use /bizbuy at one for sale",
- "Want to buy a house? Use /housebuy at one for sale",
- "Want to buy a vehicle? Visit a dealership and enter one for info on how to buy it!",
- "Switch to any of your characters with {1}",
- "Use {1} to automatically login when connecting with the same IP",
- "Use {1} to turn on/off the lights in your house or business",
- "Use {1} to play an internet radio station in your car, house, or business",
- "Want to make a clan? Use {1} for details",
- "Legal weapons can be purchased at any ammunation"
- ],
- "PromptResponseTip": "Use {1} to accept or {2} to decline"
-}
\ No newline at end of file
diff --git a/locale/spanish.json b/locale/spanish.json
deleted file mode 100644
index 070a9811..00000000
--- a/locale/spanish.json
+++ /dev/null
@@ -1,399 +0,0 @@
-{
- "TranslationProvidedBy": "PerikiyoXD",
- "LocaleEnglishName": "Español",
- "LocaleNativeName": "Inglés",
- "LocaleOffer": "Este servidor se encuentra disponible en Español. Utilice {1} para usarlo",
- "LocaleChanged1": "El idioma se ha configurado a {1}",
- "LocaleChanged2": "El servidor mostrará los mensajes en {1}",
- "LocaleChangedNote": "Esto no cambia los mensajes de otros jugadores",
- "AccentsListHeader": "Acentos",
- "HelpListHeader": "Categorías de ayuda",
- "HelpSkinHeader": "Ayuda de personajes",
- "HelpVehicleHeader": "Ayuda de vehículos",
- "HelpBusinessHeader": "Ayuda de negocios",
- "HelpHouseHeader": "Ayuda de casas",
- "HelpRadioHeader": "Ayuda de radio",
- "HelpAnimationHeader": "Ayuda de animaciones",
- "AccentNotFound": "Acento no encontrado",
- "AccentSet": "Acento establecido como {1}",
- "AnimationNotFound": "Esa animación no existe",
- "AnimationCommandTip": "Usa {1} para ver la lista de animaciones",
- "AnimationInvalidDistance": "La distancia debe ser un numero entre el 0 y el 3",
- "AnimationStopCommandTip": "Usa {1} para detener la animación actual",
- "CantBanClient": "No se puede vetar a esta persona",
- "PlayerAccountBanned": "La cuenta de {1} ha sido vetada",
- "ClanNotFound": "Clan no encontrado",
- "ClanNameTaken": "Ya existe un clan con ese nombre",
- "PlayerNotFound": "Jugador no encontrado",
- "ClanCantRemoveRanks": "No puedes eliminar rangos del clan",
- "ClanCantAddRanks": "No puedes añadir rangos del clan",
- "ClanRankNotFound": "No se encontró el rango del clan indicado",
- "ClanCantChangeMemberTag": "No puedes cambiar las etiquetas del miembro del clan",
- "ClanPlayerNotInSameClan": "El jugador indicado no está en tu clan",
- "ClanCantChangeRankLevel": "No puedes cambiar el nivel del rango del clan",
- "ClanCantChangeRankTag": "No puedes cambiar la etiqueta del rango del clan",
- "NameNotRegistered": "¡Tu nombre no está registrado! Usa {1} para crear una cuenta",
- "AutomaticLoginIPToggle": "Se ha {1} el inicio de sesión automático por IP",
- "CouldNotRegisterAccount": "Hubo un problema al crear su cuenta. Por favor, póngase en contacto con un administrador",
- "RandomTipsToggle": "Se han {1} los Consejos aleatorios",
- "ActionTipsToggle": "Se han {1} los Consejos de acción",
- "AutoSpawnLastCharToggle": "Se ha {1} reaparecer con el ultimo personaje usado",
- "AccountGUISettingToggle": "Se ha {1} la Interfaz de Usuario",
- "On": "Encendido",
- "Off": "Apagado",
- "Yes": "Si",
- "No": "No",
- "True": "True",
- "False": "False",
- "Locked": "Locked",
- "Unlocked": "Unlocked",
- "PasswordNotGoodEnough": "La nueva contraseña debe cumplir los requisitos",
- "PasswordNeedsBase": "Las contraseñas deben tener al menos {1}",
- "PasswordNeedsCapitals": "{1} letras mayúsculas",
- "PasswordNeedsNumbers": "{1} números",
- "PasswordNeedsSymbols": "{1} símbolos",
- "PasswordsDontMatch": "La nueva contraseña y la confirmación de la nueva contraseña no son iguales.",
- "PasswordChanged": "Su contraseña ha sido cambiada",
- "AutoLoggedInIP": "Ha iniciado la sesion automáticamente por su IP",
- "WelcomeBack": "¡Bienvenidos de nuevo a {1}, {2}! Por favor, {3} para continuar",
- "WelcomeNewPlayer": "¡Bienvenido a {1}, {2}! Por favor, {3} para jugar",
- "InvalidPlayer": "Jugador no encontrado",
- "InvalidBusiness": "Negocio no encontrada",
- "InvalidHouse": "Casa no encontrada",
- "InvalidVehicle": "Vehículo no encontrado",
- "InvalidClan": "Clan no encontrado",
- "InvalidClanRank": "Rango del clan no encontrado",
- "InvalidJob": "Trabajo no encontrado",
- "InvalidItem": "Objeto no encontrado",
- "InvalidItemType": "Tipo de objeto no encontrado",
- "InvalidRadioStation": "Estación de radio no encontrada",
- "InvalidGate": "Puerta no encontrada",
- "EntersProperty": "abre la puerta y entra en el {1}",
- "ExitsProperty": "abre la puerta y sale del {1}",
- "EnterExitPropertyDoorLocked": "intenta abrir la puerta {1} pero no lo consigue porque está cerrada",
- "PropertyNoInterior": "Este {1} no tiene un interior, pero todavía puede utilizar los comandos en el icono de la puerta",
- "NoBusinessWithItemType": "No hay ningun negocio con ese objeto disponible",
- "HeaderKeyBinds": "Atajos de teclado",
- "HeaderAccountHelp": "Account Help",
- "HeaderVehicleHelp": "Vehicle Help",
- "HeaderVehicleDealerships": "Ayuda del Concesionario de Vehiculos",
- "HeaderJobHelp": "Ayuda del Trabajo",
- "HeaderChatHelp": "Ayuda del Chat",
- "HeaderServerRules": "Reglas del Servidor",
- "HeaderWebsiteInfo": "Sitio Web",
- "HeaderDiscordInfo": "Discord",
- "HeaderAnimationsList": "Lista de animaciones",
- "HeaderPayAndSprayHelp": "Ayuda de 'Pay and Spray'",
- "HeaderAmmunationHelp": "Ayuda de 'Ammunation'",
- "HeaderVehicleTuneupHelp": "Ayuda de Puesta a punto del vehículo",
- "HeaderBindableKeysHelp": "Atajos de teclado",
- "HeaderSkinHelp": "Ayuda de Ropa/Personaje",
- "HeaderBusinessHelp": "Ayuda del negocio",
- "HeaderClanHelp": "Ayuda del clan",
- "HeaderPlayerVehiclesList": "Vehiculos del jugador ({1})",
- "HeaderPlayerBusinessesList": "Negocios del jugador ({1})",
- "HeaderClansList": "Lista de clanes",
- "HeaderAdminsList": "Lista de administradores",
- "HeaderBadgeInfo": "Información de la placa",
- "HeaderAccentsList": "Lista de acentos",
- "HeaderPlayerInfo": "Información del jugador ({1})",
- "HeaderWealthandTaxHelp": "Información sobre el patrimonio y los impuestos",
- "HeaderCommandInfo": "Información de comando ({1})",
- "HeaderRadioHelp": "Ayuda para la radio",
- "HeaderRadioStationsList": "Emisoras de radio",
- "HeaderKeyBindsList": "Lista de atajos de teclado",
- "RadioVolumeChanged": "{1} Has cambiado el volumen de tu radio en directo a {2}%",
- "VolumeLevelNotNumber": "El volumen debe ser un número",
- "RadioStationLocationInvalid": "Debe estar en un vehículo, casa o negocio o tener un dispositivo personal para cambiar la emisora",
- "ActionBusinessRadioStationChange": "cambia la emisora de la radio del negocio a {1} ({2})",
- "ActionHouseRadioStationChange": "cambia la emisora de la radio de la casa a {1} ({2})",
- "ActionVehicleRadioStationChange": "cambia la emisora de la radio del vehículo a {1} ({2})",
- "ActionItemRadioStationChange": "cambia la estación de {1} a {2} ({3})",
- "RandomVehicleCommandsDisabled": "Este es un vehículo de tráfico aleatorio y los comandos no se pueden utilizar en él",
- "HouseDoorLock": "Casa {1} {2}!",
- "BusinessDoorLock": "Negocio {1} {2}!",
- "ServerGameModeRestarting": "El modo de juego del servidor se reinicia",
- "HeaderSelfItemList": "Su inventario",
- "HeaderPlayerItemList": "Inventario del jugador ({1})",
- "HeaderHouseItemList": "Inventario de la casa",
- "HeaderBusinessFloorItemList": "Inventario del negocio (En venta)",
- "HeaderBusinessStorageItemList": "Inventario del negocio (Almacén)",
- "HeaderItemItemList": "Inventario de {1}",
- "ItemSlotNotNumber": "La ranura del objeto debe ser un número",
- "ItemSlotMustBeBetween": "La ranura del objeto debe ser un número entre {1} y {2}!",
- "UseItemBugged": "El objeto que intentas utilizar tiene un error. Se ha enviado un informe de error a los desarrolladores del servidor",
- "PickupItemBugged": "El objeto que intentas recoger tiene un error. Se ha enviado un informe de error a los desarrolladores del servidor",
- "DropItemBugged": "El objeto que intentas soltar tiene un error. Se ha enviado un informe de error a los desarrolladores del servidor",
- "HandsBusy": "Tus manos están ocupadas",
- "CantUseItemInSkinChange": "No puedes usar un objeto mientras personalizas tu apariencia",
- "CantDropItemInSkinChange": "No puedes soltar un objeto mientras personalizas tu apariencia",
- "CantPickupItemInSkinChange": "No puedes recoger un objeto mientras personalizas tu apariencia",
- "CantSwitchItemInSkinChange": "No puedes cambiar de objeto mientras se personaliza la apariencia",
- "CantGiveItemInSkinChange": "No puedes dar un objeto mientras personalizas tu apariencia",
- "CantTakeItemInSkinChange": "No puedes coger un objeto mientras personalizas tu apariencia",
- "ItemUnequippableNoAmmo": "{1} (ranura {2}) no tiene munición y no puede equiparse",
- "NoSpaceSelfInventory": "No tienes más espacio en tu inventario",
- "Business": "negocio",
- "House": "casa",
- "Clan": "clan",
- "Vehicle": "vehiculo",
- "Item": "objeto",
- "ItemType": "tipo de objeto",
- "Gate": "portón",
- "Door": "puerta",
- "ClanRank": "rango del clan",
- "JobRank": "rango del trabajo",
- "RadioStation": "estación de radio",
- "Months": [
- "Enero",
- "Febrero",
- "Marzo",
- "Abril",
- "Mayo",
- "Junio",
- "Julio",
- "Agosto",
- "Septiembre",
- "Octubre",
- "Noviembre",
- "Diciembre"
- ],
- "WeekDays": [
- "Domingo",
- "Lunes",
- "Martes",
- "Miércoles",
- "Jueves",
- "Viernes",
- "Sábado"
- ],
- "CardinalDirections": [
- "Norte",
- "Noreste",
- "Este",
- "Sureste",
- "Sur",
- "Suroeste",
- "Oeste",
- "Noroeste"
- ],
- "NewPlayerReadyToPlay": [
- "Te han dado algo de dinero. Usa {1} para encontrar lugares donde comprar artículos",
- "Si necesitas dinero, los trabajos son los puntos amarillos del radar",
- "Para conseguir un coche, visita el concesionario de coches. También puedes utilizar un vehículo de alquiler cerca del punto de aparición o tomar el tren",
- "Asegúrese de leer el {1} y utilizar el {2} para obtener información"
- ],
- "YourCurrentVehicleDeleted": "El vehículo en el que estabas fue eliminado",
- "Distance": "Distancia",
- "Meters": "Metros",
- "Feet": "Pies",
- "Kilometers": "Kilómetros",
- "Miles": "Millas",
- "MustBeVehicleDriver": "¡Debes ser el conductor del vehículo!",
- "PlayerJoinedServer": "¡{1} se unió al juego desde {1}!",
- "PlayerLeftServer": "¡{1} ha abandonado el juego! ({1})",
- "DisconnectReasons": [
- "Conexión perdida",
- "Desconectado",
- "Cliente no admitido",
- "Juego incorrecto",
- "Contraseña incorrecta",
- "Ejecutable no admitidos",
- "Desconectado",
- "Vetado",
- "Fallido",
- "Nombre inválido",
- "Fallo del programa"
- ],
- "TakeItemFromHouse": "saca {1} de la casa",
- "TakeItemFromBusinessStorage": "saca {1} del almacén del negocio",
- "TakeItemFromBusiness": "saca {1} del negocio",
- "TakeItemFromItem": "saca {1} del {2}",
- "TakeItemFromVehicleTrunk": "saca {1} del maletero",
- "TakeItemFromVehicleDash": "saca {1} de la guantera",
- "JobEquipmentInventoryKeyBindTip": "El equipo de trabajo está en su inventario. Pulse {1} para verlas",
- "JobEquipmentInventoryCommandTip": "El equipo de trabajo está en su inventario. Utilice {1} para verlos",
- "AccountHelp": [
- "NO comparta su contraseña con nadie más. El personal de {1} nunca le pedirá su contraseña",
- "Utilice {1} para cambiar su contraseña, y {2} si la ha olvidado",
- "Algunos comandos: {1}"
- ],
- "VehicleHelp": [
- "Sus vehículos personales se guardarán donde usted u otra persona los deje",
- "Visite un concesionario para comprar vehículos nuevos. {1} para más información)",
- "Algunos comandos: {1}",
- "Visita un taller mecánico para reparar, colorear y poner a punto tu coche. {1} para más información"
- ],
- "VehicleDealershipHelp": [
- "Visite un concesionario para comprar vehículos nuevos. {1} para encontrar uno",
- "En el concesionario, introduce el coche que quieres comprar, y se te mostrará el precio",
- "Si quieres comprar el vehículo, utiliza {1} y te darán las llaves para que lo pruebes en el aparcamiento",
- "Salga del concesionario con el vehículo nuevo para confirmar la compra"
- ],
- "JobHelp": [
- "Visita los lugares de trabajo para conseguir un empleo y ganar dinero. Busca puntos amarillos en el mapa",
- "En un lugar de trabajo, usa {1} para conseguir el trabajo. Utiliza {2} para dejar el trabajo",
- "Usa {1} para empezar a trabajar. También puedes conseguir un trabajo {2} y {3}",
- "La mayoría de los vehículos de trabajo están cerrados. Usa {1} cerca de uno para entrar en él",
- "Al entrar en un vehículo de trabajo, se le mostrará información sobre cómo hacer el trabajo"
- ],
- "ChatHelp": [
- "Hay dos tipos principales de chat: fuera del personaje (OOC) y dentro del personaje (IC)",
- "Mezclar estos dos tipos no resulta en un juego de rol apropiado. Vea {1} para más información",
- "Algunos comandos del chat: {1}",
- "Algunos tienen nombres más cortos disponibles ({1} para hablar, {2} para gritar, etc)"
- ],
- "ServerRulesHelp": [
- "Las acciones irreales (powergaming) no están permitidas. No eres Superman",
- "No se permite ningún juego de rol terrorista o de terrorismo",
- "Siga siempre las instrucciones de los moderadores y administradores",
- "No mezcles los chats (metagaming). No puedes usar información en IC que fue recibida OOC",
- "Mantén el inglés en los chats principales. Si no se te da bien el inglés, utiliza {1}"
- ],
- "AnimationHelp": [
- "Las animaciones permiten mejorar el juego de rol con acciones visuales",
- "Utilice {1} o {2} con un nombre para utilizar una animación",
- "Para ver una lista de animaciones, utilice {1}"
- ],
- "WeaponHelp": [
- "Visita una armería para comprar armas. Usa {1} para encontrar una",
- "La compra de un arma requiere una licencia de armas",
- "Las licencias de armas son gestionadas por el departamento de policía. Solicítela allí para obtenerla",
- "Las armas también pueden comprarse ilegalmente en algunos negocios, vendedores de armas y clanes"
- ],
- "SkinHelp": [
- "En una tienda de ropa, usa {1} para comprar ropa",
- "Cuando tengas un objeto de ropa, equípalo y úsalo como cualquier otro objeto para mostrar la selección de personajes (revisa {1} para aprender a usar objetos)",
- "Algunas pieles están restringidas a trabajos, clanes o por otras razones"
- ],
- "KeyBindHelp": [
- "Puedes establecer tus propias combinaciones de teclas. Utilice {1} para ver sus teclas vinculadas",
- "Utilice {1} para añadir una nueva combinación de teclas y {2} para eliminar una",
- "Las teclas por defecto son: {1} para el motor del vehículo, {1} para las luces y {3} para el bloqueo/desbloqueo",
- "Pulsa {1} para ver tus objetos y {2} para equipar un objeto o {3} para desequipar todos",
- "Pulsa {1} para usar el objeto que tienes en la mano, pulsa {2} para dejarlo caer o pulsa {3} para recoger un objeto del suelo"
- ],
- "BusinessHelp": [
- "Utilice {1} para comprar artículos o {2} para ver una lista de lo que está a la venta en cualquier negocio",
- "Las empresas aparecen con nombres azules sobre el icono de su entrada",
- "Comandos del dueño del negocio: {1}",
- "Un coche nuevo en venta aparecerá cuando salgas del concesionario"
- ],
- "ClanHelp": [
- "Pedir a un administrador que cree un clan (similar a las facciones/grupos/familias)",
- "Los propietarios de clanes tienen pleno control sobre su clan una vez creado",
- "Comandos de clan: {1}",
- "Más comandos del clan: {1}"
- ],
- "RadioStationHelp": [
- "Utilice {1} para fijar la estación de su vehículo, casa o negocio",
- "Utilice {2} para ver una lista de estaciones",
- "Puedes cambiar el volumen de tu radio usando {1} con 0-100 como porcentaje"
- ],
- "WealthAndTaxHelp": [
- "Sus impuestos en el día de pago son el {1} por ciento de su riqueza calculada",
- "Su riqueza calculada es una suma total basada en cuántos vehículos, casas y negocios tiene",
- "Cada vehículo es {1}, cada casa es {2}, y cada negocio es {3}",
- "Utilice {1} para ver su patrimonio actual, y {2} para ver cuánto pagará de impuestos cada día de pago"
- ],
- "MustBeInAVehicle": "Necesitas estar en un vehículo",
- "MustBeInOrNearVehicle": "Tienes que estar dentro o cerca de un vehículo",
- "MustBeInVehicleFrontSeat": "Tienes que estar en los asientos delanteros del vehículo",
- "MustBeInVehicleDriverSeat": "Tienes que ser el conductor",
- "DontHaveVehicleKey": "No tiene una llave para este vehículo",
- "NoGateAccess": "No tienes acceso a esta puerta",
- "GateBroken": "Esta puerta está rota",
- "GateHacked": "La puerta no funciona",
- "RadioJammed": "Sólo se oye la estática de la radio",
- "VehicleNotForSale": "Este vehículo no está en venta",
- "VehicleNotForRent": "Este vehículo no se alquila",
- "BusinessNotForSale": "Este negocio no está en venta",
- "BusinessNotForRent": "Este negocio no se alquila",
- "HouseNotForSale": "Esta casa no está en venta",
- "HouseNotForRent": "Esta casa no está en alquiler",
- "DealershipPurchaseTestDrive": "Conduzca fuera del concesionario para comprar el vehículo, o salga del vehículo para cancelar",
- "DealershipPurchaseExitedVehicle": "Has cancelado la compra del vehículo al salir de él",
- "VehiclePurchaseComplete": "¡Este vehículo es ahora tuyo! Se guardará donde quiera que lo dejes",
- "VehiclePurchaseNotEnoughMoney": "No tienes suficiente dinero para comprar este vehículo",
- "HousePurchaseNotEnoughMoney": "No tienes suficiente dinero para comprar esta casa",
- "BusinessPurchaseNotEnoughMoney": "No tienes suficiente dinero para comprar este negocio",
- "Locales": {
- "English": "Inglés",
- "Russian": "Ruso",
- "Spanish": "Español",
- "German": "Alemán",
- "Dutch": "Holandés",
- "Polish": "Polaco"
- },
- "HeaderPlayerHousesList": "Casas del jugador ({1})",
- "HeaderPlayerStaffFlagsList": "Banderas administrativas del jugador ({1})",
- "HeaderStaffFlagsList": "Banderas administrativas",
- "NonRPName": "¡Nombre no RP! Elige uno nuevo:",
- "InvalidStaffFlag": "Bandera administrativa no encontrada",
- "InvalidClanFlag": "Bandera del clan no encontrada",
- "InvalidLocale": "Language not found!",
- "HeaderJobUniformList": "Job Uniforms ({1})",
- "HeaderJobEquipmentList": "Job Equipment ({1})",
- "InvalidJobUniform": "Job uniform not found!",
- "InvalidJobEquipment": "Job equipment not found!",
- "HeaderVehiclesInRangeList": "Vehicles within {1}",
- "NoVehiclesWithInRange": "There are no vehicles within {1}",
- "AmountNotNumber": "The amount must be a number!",
- "NeedToBeWorking": "You need to be working! Use {1} at a job location or near a job vehicle.",
- "NeedToBeOnJobRoute": "You need to be doing a job route! Use {1} in a job vehicle",
- "CurrentJobRouteDeleted": "The job route you were on has been deleted by an admin",
- "CurrentJobRouteVehicleColoursChanged": "Your job route's vehicle colours were changed by an admin",
- "NotYourJob": "This is not your job!",
- "JobPoints": "You can get a job by going the yellow points on the map.",
- "QuitJobToTakeAnother": "If you want this job, use {1} to quit your current job.",
- "NotAJobVehicle": "This is not a job vehicle!",
- "NotYourJobVehicle": "This is not your job's vehicle!",
- "JobRouteDisabled": "The job route you were on has been disabled by an admin",
- "HeaderPickupTypes": "Pickup Types",
- "HeaderBlipTypes": "Map Icon Types",
- "InvalidGPSLocation": "There are no locations with that name or type",
- "HeaderBusinessList": "Businesses",
- "VehicleForSale": "This {1} is buyable for {2}! Use {3} if you want to buy it",
- "VehicleForRent": "This {1} is rentable for {2}! Use {3} if you want to rent it",
-
- "ADDED-31JAN2022": "DO NOT TRANSLATE. This string is just a comment to separate newly added translations.",
- "LoginFailedInvalidPassword": "Invalid password! {1} attempts remaining",
- "LoginFailedNoPassword": "You must enter a password! ! {1} attempts remaining",
- "RegistrationFailedNoPassword": "You must enter a password!",
- "RegistrationFailedNoPasswordConfirm": "You must confirm the password!",
- "RegistrationFailedNoEmail": "You must enter an email!",
- "AccountNameAlreadyRegistered": "Your name is already registered!",
- "AlreadyLoggedIn": "You are already logged in!",
- "RegistrationFailedInvalidEmail": "That email is invalid!",
- "RegistrationFailedPasswordMismatch": "The passwords don't match!",
- "RegistrationFailedCreateError": "Your account couldn't be created!",
- "RegistrationSuccess": "Your account has been created!",
- "RegistrationEmailVerifyReminder": "Don't forget to verify your email! A verification code has been sent to you.",
- "RegistrationCreateCharReminder": "To play on the server, you will need to make a character.",
- "NoCharactersGUIMessage": "You have no characters. Would you like to make one?",
- "NoCharactersGUIWindowTitle": "No characters",
- "NoCharactersChatMessage": "You have no characters. Use {1} to make one.",
- "NeedEmailFor2FA": "You need to add your email to your account to use two-factor authentication.",
- "NeedEmailVerifiedFor2FA": "You need to verify your email to use two-factor authentication.",
- "SetEmailHelpTip": "Use {1} to set your email.",
- "VerifyEmailHelpTip": "Use {1} to verify your email.",
-
- "ADDED-13FEB2022": "DO NOT TRANSLATE. This string is just a comment to separate newly added translations.",
- "NearbyRadio": "Nearby radio",
- "FromRadio": "From radio",
- "ToRadio": "To radio",
- "NeedToEnterPropertyCommand": "You need to enter the {1} first! Use {2} to enter and exit",
- "NeedToEnterPropertyKeyPress": "You need to enter the {1} first! Press {2} to enter and exit",
- "InventoryFullCantCarry": "You don't have any space to carry this (full inventory)!",
- "NotEnoughCashNeedAmountMore": "You don't have enough money! You need {1} more!",
- "AmountMustBeMoreThan": "The amount must be more than {1}!",
- "WeaponBanned": "You are not allowed to buy or use weapons!",
- "TimeNotNumber": "The time must be a number",
- "HeaderDefaultBusinessItemTypes": "Business Item Templates",
- "FixingStuck": "Fixing your position and virtual world ...",
- "CantUseCommandYet": "You must wait before you can use this command again!",
- "NotATester": "You are not a tester!",
- "AccessDenied": "AccessDenied",
- "InvalidSkin": "That skin is invalid!",
- "HeaderInteriorTypes": "Interiors"
-}
diff --git a/meta.xml b/meta.xml
index dd4d6d07..55c0ae83 100644
--- a/meta.xml
+++ b/meta.xml
@@ -9,8 +9,8 @@
-
+
@@ -34,6 +34,7 @@
+
@@ -44,9 +45,11 @@
-
+
+
+
@@ -56,19 +59,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -94,7 +84,34 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -111,6 +128,7 @@
+
@@ -119,22 +137,27 @@
+
+
+
+
-
+
+
diff --git a/scripts/client/afk.js b/scripts/client/afk.js
index 95cbd995..b0ca14e5 100644
--- a/scripts/client/afk.js
+++ b/scripts/client/afk.js
@@ -7,6 +7,7 @@
// TYPE: Client (JavaScript)
// ===========================================================================
+// Init AFK script
function initAFKScript() {
logToConsole(LOG_DEBUG, "[VRR.AFK]: Initializing AFK script ...");
logToConsole(LOG_DEBUG, "[VRR.AFK]: AFK script initialized!");
@@ -14,14 +15,16 @@ function initAFKScript() {
// ===========================================================================
+// Process stuff when game loses focus
function processLostFocusAFK(event) {
sendServerNewAFKStatus(true);
}
// ===========================================================================
+// Process stuff when game gains focus
function processFocusAFK(event) {
- sendServerNewAFKStatus(false);
+ sendServerNewAFKStatus(false);
}
// ===========================================================================
\ No newline at end of file
diff --git a/scripts/client/animation.js b/scripts/client/animation.js
index 1c9a2d2c..f62db4f7 100644
--- a/scripts/client/animation.js
+++ b/scripts/client/animation.js
@@ -7,64 +7,127 @@
// TYPE: Client (JavaScript)
// ===========================================================================
-function makePedPlayAnimation(pedId, animGroup, animId, animType, animSpeed, loop, loopNoControl, freezeLastFrame, returnToOriginalPosition, freezePlayer) {
- logToConsole(LOG_DEBUG, `[VRR.Animation] Playing animation ${animGroup}/${animId} for ped ${pedId}`);
- if(getGame() < VRR_GAME_GTA_IV) {
- if(animType == VRR_ANIMTYPE_NORMAL || animType == VRR_ANIMTYPE_SURRENDER) {
- if(getGame() == VRR_GAME_GTA_VC || getGame() == VRR_GAME_GTA_SA) {
- getElementFromId(pedId).clearAnimations();
- } else {
- getElementFromId(pedId).clearObjective();
- }
- getElementFromId(pedId).addAnimation(animGroup, animId);
+function makePedPlayAnimation(pedId, animationSlot, positionOffset) {
+ let ped = getElementFromId(pedId);
- if(getElementFromId(pedId) == localPlayer && freezePlayer == true) {
+ if(ped == null) {
+ return false;
+ }
+
+ let animationData = getAnimationData(animationSlot);
+ logToConsole(LOG_DEBUG, `[VRR.Animation] Playing animation ${animationData[0]} for ped ${pedId}`);
+
+ let freezePlayer = false;
+ switch(animationData.moveType) {
+ case VRR_ANIMMOVE_FORWARD: {
+ setElementCollisionsEnabled(ped, false);
+ if(ped.isSyncer) {
+ setElementPosition(ped, getPosInFrontOfPos(getElementPosition(pedId), fixAngle(getElementHeading(pedId)), positionOffset));
+ }
+ freezePlayer = true;
+ break;
+ }
+
+ case VRR_ANIMMOVE_BACK: {
+ setElementCollisionsEnabled(pedId, false);
+ if(ped.isSyncer) {
+ setElementPosition(pedId, getPosBehindPos(getElementPosition(pedId), fixAngle(getElementHeading(pedId)), positionOffset));
+ }
+ freezePlayer = true;
+ break;
+ }
+
+ case VRR_ANIMMOVE_LEFT: {
+ setElementCollisionsEnabled(pedId, false);
+ if(ped.isSyncer) {
+ setElementPosition(pedId, getPosToLeftOfPos(getElementPosition(pedId), fixAngle(getElementHeading(pedId)), positionOffset));
+ }
+ freezePlayer = true;
+ break;
+ }
+
+ case VRR_ANIMMOVE_RIGHT: {
+ setElementCollisionsEnabled(pedId, false);
+ if(ped.isSyncer) {
+ setElementPosition(pedId, getPosToRightOfPos(getElementPosition(pedId), fixAngle(getElementHeading(pedId)), positionOffset));
+ }
+ freezePlayer = true;
+ break;
+ }
+
+ default: {
+ break;
+ }
+ }
+
+ if(getGame() < VRR_GAME_GTA_IV) {
+ if(animationData.animType == VRR_ANIMTYPE_NORMAL || animationData.animType == VRR_ANIMTYPE_SURRENDER) {
+ if(getGame() == VRR_GAME_GTA_VC || getGame() == VRR_GAME_GTA_SA) {
+ ped.clearAnimations();
+ } else {
+ ped.clearObjective();
+ }
+ ped.addAnimation(animationData.groupId, animationData.animId);
+
+ if(ped == localPlayer && freezePlayer == true) {
inAnimation = true;
setLocalPlayerControlState(false, false);
localPlayer.collisionsEnabled = false;
}
- } else if(animType == VRR_ANIMTYPE_BLEND) {
- getElementFromId(pedId).position = getElementFromId(pedId).position;
- getElementFromId(pedId).blendAnimation(animGroup, animId, animSpeed);
+ } else if(animationData.animType == VRR_ANIMTYPE_BLEND) {
+ ped.position = ped.position;
+ ped.blendAnimation(animationData.groupId, animationData.animId, animationData.animSpeed);
}
} else {
- natives.requestAnims(animGroup);
- natives.taskPlayAnimNonInterruptable(getElementFromId(pedId), animId, animGroup, animSpeed, loop, loopNoControl, freezeLastFrame, returnToOriginalPosition, -1);
+ natives.requestAnims(animationData.groupId);
+ natives.taskPlayAnimNonInterruptable(ped, animationData.groupId, animationData.animId, animationData.animSpeed, boolToInt(animationData.infiniteLoop), boolToInt(animationData.infiniteLoopNoMovement), boolToInt(animationData.dontReturnToStartCoords), boolToInt(animationData.freezeLastFrame), -1);
}
}
// ===========================================================================
-function forcePedAnimation(pedId, animGroup, animId, animType, animSpeed, loop, loopNoControl, freezeLastFrame, returnToOriginalPosition) {
- if(getGame() < VRR_GAME_GTA_IV) {
- forcedAnimation = [animGroup, animId];
- getElementFromId(pedId).position = getElementFromId(pedId).position;
- getElementFromId(pedId).addAnimation(animGroup, animId);
+function forcePedAnimation(pedId, animSlot) {
+ let ped = getElementFromId(pedId);
- if(getElementFromId(pedId) == localPlayer) {
+ if(ped == null) {
+ return false;
+ }
+
+ let animationData = getAnimationData(animSlot);
+
+ if(getGame() < VRR_GAME_GTA_IV) {
+ ped.position = ped.position;
+ ped.addAnimation(animationData.groupId, animationData.animId);
+
+ if(ped == localPlayer) {
inAnimation = true;
setLocalPlayerControlState(false, false);
localPlayer.collisionsEnabled = false;
}
+ } else {
+ natives.requestAnims(animationData.groupId);
+ natives.taskPlayAnimNonInterruptable(ped, animationData.groupId, animationData.animId, animationData.animSpeed, boolToInt(animationData.infiniteLoop), boolToInt(animationData.infiniteLoopNoMovement), boolToInt(animationData.dontReturnToStartCoords), boolToInt(animationData.freezeLastFrame), -1);
}
}
// ===========================================================================
function makePedStopAnimation(pedId) {
- if(getElementFromId(pedId) == null) {
+ let ped = getElementFromId(pedId);
+
+ if(ped == null) {
return false;
}
if(getGame() != VRR_GAME_GTA_IV) {
if(getGame() == VRR_GAME_GTA_VC || getGame() == VRR_GAME_GTA_SA) {
- getElementFromId(pedId).clearAnimations();
+ ped.clearAnimations();
} else {
- getElementFromId(pedId).clearObjective();
+ ped.clearObjective();
}
}
- if(getElementFromId(pedId) == localPlayer) {
+ if(ped == localPlayer) {
if(getGame() != VRR_GAME_GTA_IV) {
localPlayer.collisionsEnabled = true;
}
@@ -72,4 +135,14 @@ function makePedStopAnimation(pedId) {
}
}
+// ===========================================================================
+
+/**
+ * @param {number} animationSlot - The slot index of the animation
+ * @return {AnimationData} The animation's data (array)
+ */
+ function getAnimationData(animationSlot, gameId = getGame()) {
+ return getGameConfig().animations[gameId][animationSlot];
+}
+
// ===========================================================================
\ No newline at end of file
diff --git a/scripts/client/business.js b/scripts/client/business.js
index ab0fd547..2c07f0de 100644
--- a/scripts/client/business.js
+++ b/scripts/client/business.js
@@ -8,8 +8,9 @@
// ===========================================================================
class BusinessData {
- constructor(index, name, entrancePosition, blipModel, pickupModel, hasInterior, hasItems) {
- this.index = index;
+ constructor(businessId, name, entrancePosition, blipModel, pickupModel, hasInterior, hasItems) {
+ this.index = -1;
+ this.businessId = businessId;
this.name = name;
this.entrancePosition = entrancePosition;
this.blipModel = blipModel;
@@ -17,36 +18,103 @@ class BusinessData {
this.hasInterior = hasInterior;
this.hasItems = hasItems;
this.blipId = -1;
+ this.labelInfoType = 0;
}
}
// ===========================================================================
function receiveBusinessFromServer(businessId, name, entrancePosition, blipModel, pickupModel, hasInterior, hasItems) {
- if(getGame() == VRR_GAME_GTA_IV) {
+ logToConsole(LOG_DEBUG, `[VRR.Business] Received business ${businessId} (${name}) from server`);
+
+ if(!areServerElementsSupported()) {
if(getBusinessData(businessId) != false) {
+ let businessData = getBusinessData(businessId);
+ businessData.name = name;
+ businessData.entrancePosition = entrancePosition;
+ businessData.blipModel = blipModel;
+ businessData.pickupModel = pickupModel;
+ businessData.hasInterior = hasInterior;
+ businessData.hasItems = hasItems;
+
+ logToConsole(LOG_DEBUG, `[VRR.Business] Business ${businessId} already exists. Checking blip ...`);
if(blipModel == -1) {
- natives.removeBlipAndClearIndex(getBusinessData(businessId).blipId);
- businesses.splice(getBusinessData(businessId).index, 1);
+ if(businessData.blipId != -1) {
+ logToConsole(LOG_DEBUG, `[VRR.Business] Business ${businessId}'s blip has been removed by the server`);
+ if(getGame() == VRR_GAME_GTA_IV) {
+ natives.removeBlipAndClearIndex(getBusinessData(businessId).blipId);
+ } else {
+ destroyElement(getElementFromId(blipId));
+ }
+ businessData.blipId = -1;
+ //businesses.splice(businessData.index, 1);
+ //setAllBusinessDataIndexes();
+ } else {
+ logToConsole(LOG_DEBUG, `[VRR.Business] Business ${businessId}'s blip is unchanged`);
+ }
} else {
- natives.setBlipCoordinates(getBusinessData(businessId).blipId, getBusinessData(businessId).entrancePosition);
- natives.changeBlipSprite(getBusinessData(businessId).blipId, getBusinessData(businessId).blipModel);
- natives.changeBlipNameFromAscii(getBusinessData(businessId).blipId, `${name.substr(0, 24)}${(name.length > 24) ? " ...": ""}`);
- }
- } else {
- if(blipModel != -1) {
- let blipId = natives.addBlipForCoord(entrancePosition);
- if(blipId) {
- let tempBusinessData = new BusinessData(businessId, name, entrancePosition, blipModel, pickupModel, hasInterior, hasItems);
- tempBusinessData.blipId = blipId;
- natives.changeBlipSprite(blipId, blipModel);
- natives.setBlipMarkerLongDistance(blipId, true);
- natives.changeBlipNameFromAscii(blipId, `${name.substr(0, 24)}${(name.length > 24) ? " ...": ""}`);
- businesses.push(tempBusinessData);
+ if(businessData.blipId != -1) {
+ logToConsole(LOG_DEBUG, `[VRR.Business] Business ${businessId}'s blip has been changed by the server`);
+ if(getGame() == VRR_GAME_GTA_IV) {
+ natives.setBlipCoordinates(businessData.blipId, businessData.entrancePosition);
+ natives.changeBlipSprite(businessData.blipId, businessData.blipModel);
+ natives.setBlipMarkerLongDistance(businessData.blipId, false);
+ natives.setBlipAsShortRange(tempBusinessData.blipId, true);
+ natives.changeBlipNameFromAscii(businessData.blipId, `${businessData.name.substr(0, 24)}${(businessData.name.length > 24) ? " ...": ""}`);
+ }
+ } else {
+ let blipId = createGameBlip(tempBusinessData.blipModel, tempBusinessData.entrancePosition, tempBusinessData.name);
+ if(blipId != -1) {
+ tempBusinessData.blipId = blipId;
+ }
+ logToConsole(LOG_DEBUG, `[VRR.Business] Business ${businessId}'s blip has been added by the server (Model ${blipModel}, ID ${blipId})`);
}
}
+ } else {
+ logToConsole(LOG_DEBUG, `[VRR.Business] Business ${businessId} doesn't exist. Adding ...`);
+ let tempBusinessData = new BusinessData(businessId, name, entrancePosition, blipModel, pickupModel, hasInterior, hasItems);
+ if(blipModel != -1) {
+ let blipId = createGameBlip(tempBusinessData.blipModel, tempBusinessData.entrancePosition, tempBusinessData.name);
+ if(blipId != -1) {
+ tempBusinessData.blipId = blipId;
+ }
+ logToConsole(LOG_DEBUG, `[VRR.Business] Business ${businessId}'s blip has been added by the server (Model ${blipModel}, ID ${blipId})`);
+ } else {
+ logToConsole(LOG_DEBUG, `[VRR.Business] Business ${businessId} has no blip.`);
+ }
+ getServerData().businesses.push(tempBusinessData);
+ setAllBusinessDataIndexes();
}
}
}
+// ===========================================================================
+
+/**
+ * @param {number} businessId - The ID of the business (initially provided by server)
+ * @return {BusinessData} The business's data (class instance)
+ */
+function getBusinessData(businessId) {
+ //let tempBusinessData = businesses.find((b) => b.businessId == businessId);
+ //return (typeof tempBusinessData != "undefined") ? tempBusinessData[0] : false;
+
+ let businesses = getServerData().businesses;
+
+ for(let i in businesses) {
+ if(businesses[i].businessId == businessId) {
+ return businesses[i];
+ }
+ }
+
+ return false;
+}
+
+// ===========================================================================
+
+function setAllBusinessDataIndexes() {
+ for(let i in getServerData().businesses) {
+ getServerData().businesses[i].index = i;
+ }
+}
+
// ===========================================================================
\ No newline at end of file
diff --git a/scripts/client/chatbox.js b/scripts/client/chatbox.js
index 46cfd5ad..bc71ebf7 100644
--- a/scripts/client/chatbox.js
+++ b/scripts/client/chatbox.js
@@ -16,6 +16,9 @@ let maxChatBoxHistory = 500;
let scrollAmount = 1;
let maxChatBoxLines = 6;
+let chatAutoHideDelay = 0;
+let chatLastUse = 0;
+
let scrollUpKey = false;
let scrollDownKey = false;
@@ -46,13 +49,22 @@ function unBindChatBoxKeys() {
// ===========================================================================
function receiveChatBoxMessageFromServer(messageString, colour) {
+ logToConsole(LOG_DEBUG, `[VRR.ChatBox]: Received chatbox message from server: ${messageString}`);
+
+ // Just in case it's hidden by auto hide
+ //setChatWindowEnabled(true);
+
let colouredString = replaceColoursInMessage(messageString);
- if(bottomMessageIndex >= chatBoxHistory.length-1) {
+ logToConsole(LOG_DEBUG, `[VRR.ChatBox]: Changed colours in string: ${colouredString}`);
+
+ addToChatBoxHistory(colouredString, colour);
+ //if(bottomMessageIndex >= chatBoxHistory.length-1) {
message(colouredString, colour);
bottomMessageIndex = chatBoxHistory.length-1;
- }
- addToChatBoxHistory(colouredString, colour);
+ //}
+
+ chatLastUse = getCurrentUnixTimestamp();
}
// ===========================================================================
@@ -63,6 +75,12 @@ function setChatScrollLines(amount) {
// ===========================================================================
+function setChatAutoHideDelay(delay) {
+ chatAutoHideDelay = delay*1000;
+}
+
+// ===========================================================================
+
function addToChatBoxHistory(messageString, colour) {
chatBoxHistory.push([messageString, colour]);
}
@@ -104,6 +122,50 @@ function updateChatBox() {
message("", COLOUR_WHITE);
}
}
+ chatLastUse = getCurrentUnixTimestamp();
+}
+
+// ===========================================================================
+
+function processMouseWheelForChatBox(mouseId, deltaCoordinates, flipped) {
+ // There isn't a way to detect whether chat input is active, but mouse cursor is forced shown when typing so ¯\_(ツ)_/¯
+ if(!gui.cursorEnabled) {
+ return false;
+ }
+
+ if(!flipped) {
+ if(deltaCoordinates.y > 0) {
+ chatBoxScrollUp();
+ } else {
+ chatBoxScrollDown();
+ }
+ } else {
+ if(deltaCoordinates.y > 0) {
+ chatBoxScrollDown();
+ } else {
+ chatBoxScrollUp();
+ }
+ }
+}
+
+// ===========================================================================
+
+function checkChatAutoHide() {
+ return false;
+
+ // Make sure chat input isn't active
+ if(gui.cursorEnabled) {
+ return false;
+ }
+
+ // Don't process auto-hide if it's disabled
+ if(chatAutoHideDelay == 0) {
+ return false;
+ }
+
+ if(getCurrentUnixTimestamp()-chatLastUse >= chatAutoHideDelay) {
+ setChatWindowEnabled(false);
+ }
}
// ===========================================================================
\ No newline at end of file
diff --git a/scripts/client/event.js b/scripts/client/event.js
index 052c29cf..26c75abe 100644
--- a/scripts/client/event.js
+++ b/scripts/client/event.js
@@ -51,14 +51,17 @@ function addAllEventHandlers() {
addEventHandler("OnFocus", onFocus);
addEventHandler("OnCameraProcess", onCameraProcess);
+
+ addEventHandler("OnMouseWheel", onMouseWheel);
+
+ addEventHandler("OnEntityProcess", onEntityProcess);
}
// ===========================================================================
function onResourceStart(event, resource) {
sendResourceStartedSignalToServer();
- setUpInitialGame();
- garbageCollectorInterval = setInterval(collectAllGarbage, 1000*60);
+ //garbageCollectorInterval = setInterval(collectAllGarbage, 1000*60);
}
// ===========================================================================
@@ -95,7 +98,10 @@ function onProcess(event, deltaTime) {
processGameSpecifics();
processNearbyPickups();
processVehiclePurchasing();
- processVehicleFires();
+ processVehicleBurning();
+ //checkChatBoxAutoHide(); // Will be uncommented on 1.4.0 GTAC update
+ //processVehicleFires();
+
}
// ===========================================================================
@@ -145,9 +151,7 @@ function onElementStreamIn(event, element) {
function onLocalPlayerExitedVehicle(event, vehicle, seat) {
logToConsole(LOG_DEBUG, `[VRR.Event] Local player exited vehicle`);
- if(areServerElementsSupported()) {
- sendNetworkEventToServer("vrr.onPlayerExitVehicle", getVehicleForNetworkEvent(vehicle), seat);
- }
+ sendNetworkEventToServer("vrr.onPlayerExitVehicle", getVehicleForNetworkEvent(vehicle), seat);
if(inVehicleSeat) {
parkedVehiclePosition = false;
@@ -160,19 +164,15 @@ function onLocalPlayerExitedVehicle(event, vehicle, seat) {
function onLocalPlayerEnteredVehicle(event, vehicle, seat) {
logToConsole(LOG_DEBUG, `[VRR.Event] Local player entered vehicle`);
- if(areServerElementsSupported()) {
- sendNetworkEventToServer("vrr.onPlayerEnterVehicle", getVehicleForNetworkEvent(vehicle), seat);
+ sendNetworkEventToServer("vrr.onPlayerEnterVehicle", getVehicleForNetworkEvent(vehicle), seat);
- if(inVehicleSeat == 0) {
- if(inVehicle.owner != -1) {
- inVehicle.engine = false;
- if(!inVehicle.engine) {
- parkedVehiclePosition = inVehicle.position;
- parkedVehicleHeading = inVehicle.heading;
- }
- }
- }
- }
+ //if(inVehicleSeat == 0) {
+ //setVehicleEngine(vehicle, false);
+ //if(!inVehicle.engine) {
+ // parkedVehiclePosition = inVehicle.position;
+ // parkedVehicleHeading = inVehicle.heading;
+ //}
+ //}
}
// ===========================================================================
@@ -185,7 +185,7 @@ function onPedInflictDamage(event, damagedEntity, damagerEntity, weaponId, healt
if(damagedEntity.isType(ELEMENT_PLAYER)) {
if(damagedEntity == localPlayer) {
//if(!weaponDamageEnabled[damagerEntity.name]) {
- event.preventDefault();
+ preventDefaultEventAction(event);
sendNetworkEventToServer("vrr.weaponDamage", damagerEntity.name, weaponId, pedPiece, healthLoss);
//}
}
@@ -223,11 +223,31 @@ function onFocus(event) {
// ===========================================================================
function onLocalPlayerSwitchWeapon(oldWeapon, newWeapon) {
+
}
// ===========================================================================
function onCameraProcess(event) {
+
+}
+
+// ===========================================================================
+
+function onMouseWheel(event, mouseId, deltaCoordinates, flipped) {
+ processMouseWheelForChatBox(mouseId, deltaCoordinates, flipped);
+}
+
+// ===========================================================================
+
+function onEntityProcess(event, entity) {
+ if(!isSpawned) {
+ return false;
+ }
+
+ //if(entity.isType(ELEMENT_PED) && !entity.isType(ELEMENT_PLAYER)) {
+ // processNPCMovement(entity);
+ //}
}
// ===========================================================================
\ No newline at end of file
diff --git a/scripts/client/gps.js b/scripts/client/gps.js
new file mode 100644
index 00000000..ee6415e9
--- /dev/null
+++ b/scripts/client/gps.js
@@ -0,0 +1,65 @@
+// ===========================================================================
+// Vortrex's Roleplay Resource
+// https://github.com/VortrexFTW/gtac_roleplay
+// ===========================================================================
+// FILE: gps.js
+// DESC: Provides GPS functions and usage
+// TYPE: Client (JavaScript)
+// ===========================================================================
+
+let gpsBlip = null;
+let gpsBlipBlinkTimes = 0;
+let gpsBlipBlinkAmount = 0;
+let gpsBlipBlinkInterval = 500;
+let gpsBlipBlinkTimer = null;
+
+// ===========================================================================
+
+function showGPSLocation(position, colour) {
+ logToConsole(LOG_DEBUG, `[VRR.GPS] Showing gps location`);
+ if(getMultiplayerMod() == VRR_MPMOD_GTAC) {
+ if(getGame() == VRR_GAME_GTA_SA) {
+ // Server-side spheres don't show in GTA SA for some reason.
+ gpsSphere = game.createPickup(1318, position, 1);
+ } else {
+ gpsSphere = game.createSphere(position, 3);
+ gpsSphere.colour = colour;
+ }
+
+ if(gpsBlip != null) {
+ destroyElement(gpsBlip);
+ }
+
+ // Blinking is bugged if player hit the spot before it stops blinking.
+ blinkGPSBlip(10, position, colour);
+ gpsBlip = game.createBlip(position, 0, 2, colour);
+ }
+}
+
+// ===========================================================================
+
+function blinkGPSBlip(times, position, colour) {
+ gpsBlipBlinkTimes = times;
+ gpsBlipBlinkTimer = setInterval(function() {
+ if(gpsBlip != null) {
+ destroyElement(gpsBlip);
+ gpsBlip = null;
+ } else {
+ gpsBlip = game.createBlip(position, 0, 2, colour);
+ }
+
+ if(gpsBlipBlinkAmount >= gpsBlipBlinkTimes) {
+ if(gpsBlip != null) {
+ destroyElement(gpsBlip);
+ gpsBlip = null;
+ }
+
+ gpsBlipBlinkAmount = 0;
+ gpsBlipBlinkTimes = 0;
+ gpsBlip = game.createBlip(position, 0, 2, colour);
+ clearInterval(gpsBlipBlinkTimer);
+ }
+ }, gpsBlipBlinkInterval);
+}
+
+// ===========================================================================
\ No newline at end of file
diff --git a/scripts/client/gui.js b/scripts/client/gui.js
index 86bd4cf3..853dcb58 100644
--- a/scripts/client/gui.js
+++ b/scripts/client/gui.js
@@ -12,7 +12,7 @@ var app = {};
let mainFont = "Roboto"; // "Arial"
//let mainLogoPath = (typeof gta == "undefined") ? "files/images/mafiac-logo.png" : "files/images/gtac-logo.png";
-let mainLogoPath = "files/images/server-logo.png";
+let mainLogoPath = "files/images/asshat-logo.png";
let primaryColour = [200, 200, 200];
let secondaryColour = [16, 16, 16];
@@ -29,27 +29,6 @@ let textInputAlpha = 180;
let guiReady = false;
-let guiSubmitKey = false;
-let guiLeftKey = false;
-let guiRightKey = false;
-let guiUpKey = false;
-let guiDownKey = false;
-
-// ===========================================================================
-
-let placesOfOrigin = [
- "Liberty City",
- "Vice City",
- "Los Santos",
- "San Fierro",
- "Las Venturas",
- "San Andreas",
- "Blaine County",
- "Red County",
- "Bone County",
- "Other",
-];
-
// ===========================================================================
let characterData = [];
@@ -81,11 +60,19 @@ function initGUI() {
initListGUI();
initResetPasswordGUI();
initChangePasswordGUI();
+ initLocaleChooserGUI();
closeAllWindows();
guiReady = true;
logToConsole(LOG_DEBUG, `[VRR.GUI] All GUI created successfully!`);
+
+ loadLocaleConfig();
+ loadAllLocaleStrings();
+
+ resetGUIStrings();
+ resetLocaleChooserOptions();
+
sendNetworkEventToServer("vrr.guiReady", true);
};
@@ -102,9 +89,10 @@ function closeAllWindows() {
characterSelect.window.shown = false;
twoFactorAuth.window.shown = false;
listDialog.window.shown = false;
- resetPassword.window.shown = false;
+ passwordReset.window.shown = false;
passwordChange.window.shown = false;
-
+ localeChooser.window.shown = false;
+
mexui.setInput(false);
mexui.focusedControl = false;
@@ -113,6 +101,8 @@ function closeAllWindows() {
guiRightKey = false;
guiUpKey = false;
guiDownKey = false;
+
+ setChatWindowEnabled(true);
}
// ===========================================================================
@@ -158,7 +148,7 @@ function isAnyGUIActive() {
return true;
}
- if(resetPassword.window.shown == true) {
+ if(passwordReset.window.shown == true) {
return true;
}
@@ -166,104 +156,16 @@ function isAnyGUIActive() {
return true;
}
+ if(localeChooser.window.shown == true) {
+ return true;
+ }
+
return false;
}
// ===========================================================================
-addNetworkEventHandler("vrr.showCharacterSelect", function(firstName, lastName, cash, clan, lastPlayed, skinId) {
- logToConsole(LOG_DEBUG, `[VRR.GUI] Received request from server to show character selection window`);
- showCharacterSelectGUI(firstName, lastName, cash, clan, lastPlayed, skinId);
-});
-
-// ===========================================================================
-
-addNetworkEventHandler("vrr.switchCharacterSelect", function(firstName, lastName, cash, clan, lastPlayed, skinId) {
- logToConsole(LOG_DEBUG, `[VRR.GUI] Received request from server to update character selection window with new info`);
- switchCharacterSelectGUI(firstName, lastName, cash, clan, lastPlayed, skinId);
-});
-
-// ===========================================================================
-
-addNetworkEventHandler("vrr.showError", function(errorMessage, errorTitle) {
- logToConsole(LOG_DEBUG, `[VRR.GUI] Received request from server to show error window`);
- showError(errorMessage, errorTitle);
-});
-
-// ===========================================================================
-
-addNetworkEventHandler("vrr.showPrompt", function(promptMessage, promptTitle) {
- logToConsole(LOG_DEBUG, `[VRR.GUI] Received request from server to show prompt window`);
- showYesNoPromptGUI(promptMessage, promptTitle);
-});
-
-// ===========================================================================
-
-addNetworkEventHandler("vrr.showInfo", function(infoMessage) {
- logToConsole(LOG_DEBUG, `[VRR.GUI] Received request from server to show info dialog`);
- showInfo(infoMessage);
-});
-
-// ===========================================================================
-
-addNetworkEventHandler("vrr.loginSuccess", function() {
- logToConsole(LOG_DEBUG, `[VRR.GUI] Received signal of successful login from server`);
- loginSuccess();
-});
-
-// ===========================================================================
-
-addNetworkEventHandler("vrr.characterSelectSuccess", function() {
- logToConsole(LOG_DEBUG, `[VRR.GUI] Received signal of successful character selection from server`);
- characterSelectSuccess();
- setChatWindowEnabled(true);
-});
-
-// ===========================================================================
-
-addNetworkEventHandler("vrr.loginFailed", function(remainingAttempts) {
- logToConsole(LOG_DEBUG, `[VRR.GUI] Received signal of failed login from server`);
- loginFailed(remainingAttempts);
-});
-
-// ===========================================================================
-
-addNetworkEventHandler("vrr.registrationSuccess", function() {
- logToConsole(LOG_DEBUG, `[VRR.GUI] Received signal of successful registration from server`);
- registrationSuccess();
-});
-
-// ===========================================================================
-
-addNetworkEventHandler("vrr.registrationFailed", function(errorMessage) {
- logToConsole(LOG_DEBUG, `[VRR.GUI] Received signal of failed registration from server`);
- registrationFailed(errorMessage);
-});
-
-// ===========================================================================
-
-addNetworkEventHandler("vrr.newCharacterFailed", function(errorMessage) {
- logToConsole(LOG_DEBUG, `[VRR.GUI] Received signal of failed registration from server`);
- newCharacterFailed(errorMessage);
-});
-
-// ===========================================================================
-
-addNetworkEventHandler("vrr.changePassword", function() {
- logToConsole(LOG_DEBUG, `[VRR.GUI] Received signal to change password from server`);
- showChangePasswordGUI();
-});
-
-// ===========================================================================
-
-addNetworkEventHandler("vrr.showResetPasswordCodeInput", function() {
- logToConsole(LOG_DEBUG, `[VRR.GUI] Received signal to input reset password code from server`);
- resetPasswordCodeInputGUI();
-});
-
-// ===========================================================================
-
-addNetworkEventHandler("vrr.guiColour", function(red1, green1, blue1, red2, green2, blue2, red3, green3, blue3) {
+function setGUIColours(red1, green1, blue1, red2, green2, blue2, red3, green3, blue3) {
logToConsole(LOG_DEBUG, `[VRR.GUI] Received new GUI colours from server: ${red1}, ${green1}, ${blue1} / ${red2}, ${green2}, ${blue2} / ${red3}, ${green3}, ${blue3}`);
primaryColour = [red1, green1, blue1];
secondaryColour = [red2, green2, blue2];
@@ -271,50 +173,55 @@ addNetworkEventHandler("vrr.guiColour", function(red1, green1, blue1, red2, gree
focusedColour = [red1+focusedColourOffset, green1+focusedColourOffset, blue1+focusedColourOffset];
initGUI();
-});
-
-// ===========================================================================
-
-addNetworkEventHandler("vrr.guiInit", function() {
- logToConsole(LOG_DEBUG, `[VRR.GUI] Initializing MexUI app`);
- //initGUI();
- sendNetworkEventToServer("vrr.guiReady", true);
-});
+}
// ===========================================================================
function hideAllGUI() {
- closeAllWindows();
- setChatWindowEnabled(true);
+ closeAllWindows();
+ setChatWindowEnabled(true);
guiSubmitKey = false;
}
// ===========================================================================
function processGUIKeyPress(keyCode) {
+ logToConsole(LOG_DEBUG, `[VRR.GUI] Processing key press: ${keyCode}`);
+
if(!isAnyGUIActive()) {
+ logToConsole(LOG_DEBUG, `[VRR.GUI] GUI is not active. Cancelling keypress processing.`);
return false;
}
if(keyCode == SDLK_RETURN || keyCode == SDLK_RETURN2) {
+ logToConsole(LOG_DEBUG, `[VRR.GUI] Key press is submit (${guiSubmitKey})`);
if(guiSubmitKey != false) {
- guiSubmitKey();
+ logToConsole(LOG_DEBUG, `[VRR.GUI] Calling submit key function`);
+ guiSubmitKey.call();
}
} else if(keyCode == getKeyIdFromParams("left") || keyCode == getKeyIdFromParams("a")) {
+ logToConsole(LOG_DEBUG, `[VRR.GUI] Key press is left (${guiLeftKey})`);
if(guiLeftKey != false) {
- guiLeftKey();
+ logToConsole(LOG_DEBUG, `[VRR.GUI] Calling left key function`);
+ guiLeftKey.call();
}
} else if(keyCode == getKeyIdFromParams("right") || keyCode == getKeyIdFromParams("d")) {
+ logToConsole(LOG_DEBUG, `[VRR.GUI] Key press is right (${guiRightKey})`);
if(guiRightKey != false) {
- guiRightKey();
+ logToConsole(LOG_DEBUG, `[VRR.GUI] Calling right key function`);
+ guiRightKey.call();
}
} else if(keyCode == getKeyIdFromParams("down") || keyCode == getKeyIdFromParams("s")) {
+ logToConsole(LOG_DEBUG, `[VRR.GUI] Key press is down (${guiDownKey})`);
if(guiDownKey != false) {
- guiDownKey();
+ logToConsole(LOG_DEBUG, `[VRR.GUI] Calling down key function`);
+ guiDownKey.call();
}
} else if(keyCode == getKeyIdFromParams("up") || keyCode == getKeyIdFromParams("w")) {
+ logToConsole(LOG_DEBUG, `[VRR.GUI] Key press is up (${guiUpKey})`);
if(guiUpKey != false) {
- guiUpKey();
+ logToConsole(LOG_DEBUG, `[VRR.GUI] Calling up key function`);
+ guiUpKey.call();
}
}
}
@@ -328,3 +235,49 @@ function processToggleGUIKeyPress(keyCode) {
}
// ===========================================================================
+
+function resetGUIStrings() {
+ // Login GUI
+ login.messageLabel.text = getLocaleString("GUILoginWindowLabelEnterPassword");
+ login.passwordInput.placeholder = getLocaleString("GUILoginWindowPasswordPlaceholder");
+ login.loginButton.text = toUpperCase(getLocaleString("GUILoginWindowSubmitButton"));
+ login.forgotPasswordButton.text = toUpperCase(getLocaleString("GUILoginWindowResetPasswordButton"));
+ login.resetPasswordLabel.text = getLocaleString("GUILoginWindowForgotPasswordLabel");
+
+ // Register GUI
+ register.messageLabel.text = getLocaleString("GUIRegisterWindowLabelCreateAccount");
+ register.passwordInput.placeholder = getLocaleString("GUIRegisterWindowPasswordPlaceholder");
+ register.confirmPasswordInput.placeholder = getLocaleString("GUIRegisterWindowConfirmPasswordPlaceholder");
+ register.emailInput.placeholder = getLocaleString("GUIRegisterWindowEmailPlaceholder");
+ register.registerButton.text = toUpperCase(getLocaleString("GUIRegisterWindowSubmitButton"));
+
+ // Change Password GUI
+ passwordChange.window.title = toUpperCase(getLocaleString("GUIChangePasswordWindowTitle"));
+ passwordChange.messageLabel.text = getLocaleString("GUIChangePasswordPasswordLabel");
+ passwordChange.passwordInput.placeholder = getLocaleString("GUIChangePasswordPasswordPlaceholder");
+ passwordChange.confirmPasswordInput.placeholder = getLocaleString("GUIChangePasswordConfirmPasswordPlaceholder");
+ passwordChange.submitButton.text = toUpperCase(getLocaleString("GUIChangePasswordSubmitButton"));
+
+ // Reset Password GUI
+ passwordReset.messageLabel.text = toUpperCase(getLocaleString("GUIResetPasswordConfirmEmailLabel"));
+ passwordReset.emailInput.placeholder = getLocaleString("GUIResetPasswordEmailPlaceholder");
+ passwordReset.resetPasswordButton.text = toUpperCase(getLocaleString("GUIResetPasswordSubmitButton"));
+ passwordReset.backToLoginButton.text = toUpperCase(getLocaleString("GUIResetPasswordLoginButton"));
+ passwordReset.backToLoginLabel.text = getLocaleString("GUIResetPasswordRememberMessage");
+
+ // Character Selection GUI
+ characterSelect.window.title = toUpperCase(getLocaleString("GUICharacterSelectWindowTitle"));
+ characterSelect.cashText.text = getLocaleString("GUICharacterSelectMoneyLabel", "0");
+ characterSelect.clanText.text = getLocaleString("GUICharacterSelectClanLabel", "None");
+ characterSelect.lastPlayedText.text = getLocaleString("GUICharacterSelectLastPlayedLabel", "Never");
+ characterSelect.previousCharacterButton.text = toUpperCase(getLocaleString("GUIPreviousCharacterButton"));
+ characterSelect.nextCharacterButton.text = toUpperCase(getLocaleString("GUINextCharacterButton"));
+ characterSelect.selectCharacterButton.text = toUpperCase(getLocaleString("GUIPlayAsCharacterButton"));
+ characterSelect.newCharacterButton.text = toUpperCase(getLocaleString("GUINewCharacterButton"));
+
+ // Character Creation GUI
+ newCharacter.messageLabel.text = getLocaleString("GUINewCharacterMessageLabel");
+ newCharacter.firstNameInput.placeholder = getLocaleString("GUINewCharacterFirstNamePlaceholder");
+ newCharacter.lastNameInput.placeholder = getLocaleString("GUINewCharacterLastNamePlaceholder");
+ newCharacter.createCharacterButton.text = toUpperCase(getLocaleString("GUINewCharacterSubmitButton"));
+}
\ No newline at end of file
diff --git a/scripts/client/gui/changepass.js b/scripts/client/gui/changepass.js
index b95a4b22..39476dfd 100644
--- a/scripts/client/gui/changepass.js
+++ b/scripts/client/gui/changepass.js
@@ -38,6 +38,7 @@ function initChangePasswordGUI() {
});
passwordChange.window.titleBarIconSize = toVector2(0,0);
passwordChange.window.titleBarHeight = 0;
+ passwordChange.window.titleBarShown = false;
passwordChange.window.image(85, -10, 140, 140, mainLogoPath, {
focused: {
@@ -132,14 +133,17 @@ function checkChangePassword() {
// ===========================================================================
-function showChangePasswordGUI() {
+function showChangePasswordGUI(errorMessage) {
logToConsole(LOG_DEBUG, `[VRR.GUI] Showing change password window`);
closeAllWindows();
setChatWindowEnabled(false);
mexui.setInput(true);
passwordChange.window.shown = true;
+ passwordChange.messageLabel = errorMessage;
mexui.focusedControl = passwordChange.passwordInput;
guiSubmitKey = checkChangePassword;
+
+ showLocaleChooserGUI(new Vec2(getScreenWidth()/2-(localeChooser.window.size.x/2), passwordChange.window.position.y+passwordChange.window.size.y+20));
}
// ===========================================================================
diff --git a/scripts/client/gui/charselect.js b/scripts/client/gui/charselect.js
index fb9b25fb..434e3a91 100644
--- a/scripts/client/gui/charselect.js
+++ b/scripts/client/gui/charselect.js
@@ -24,23 +24,26 @@ let characterSelect = {
function initCharacterSelectGUI() {
logToConsole(LOG_DEBUG, `[VRR.GUI] Creating character select GUI ...`);
- characterSelect.window = mexui.window(game.width/2-215, game.height/2-83, 430, 190, 'Select Character', {
+ characterSelect.window = mexui.window(game.width/2-215, game.height/2-83, 430, 190, 'SELECT CHARACTER', {
main: {
backgroundColour: toColour(secondaryColour[0], secondaryColour[1], secondaryColour[2], windowAlpha),
},
title: {
- textSize: 12.0,
- textColour: toColour(0, 0, 0, 0),
+ textSize: 12.0,
+ textFont: mainFont,
+ textColour: toColour(0, 0, 0, 255),
backgroundColour: toColour(primaryColour[0], primaryColour[1], primaryColour[2], windowTitleAlpha),
},
icon: {
- textSize: 12.0,
- textColour: toColour(0, 0, 0, 0),
+ textSize: 10.0,
+ textFont: mainFont,
+ textColour: toColour(0, 0, 0, 255),
backgroundColour: toColour(primaryColour[0], primaryColour[1], primaryColour[2], windowTitleAlpha),
}
});
- characterSelect.window.titleBarIconSize = toVector2(0,0);
- characterSelect.window.titleBarHeight = 0;
+ characterSelect.window.titleBarIconSize = toVector2(0, 0);
+ characterSelect.window.titleBarIconShown = false;
+ characterSelect.window.titleBarHeight = 30;
characterSelect.nameText = characterSelect.window.text(5, 40, 200, 25, 'Lastname, Firstname', {
main: {
@@ -163,6 +166,12 @@ function showCharacterSelectGUI(firstName, lastName, cash, clan, lastPlayed, ski
characterSelect.lastPlayedText.text = `Last Played: ${lastPlayed}`;
characterSelect.skinImage = characterSelect.window.image(310, 32, 100, 90, "files/images/skins/none.png");
characterSelect.window.shown = true;
+
+ guiSubmitKey = selectThisCharacter;
+ guiLeftKey = selectPreviousCharacter;
+ guiRightKey = selectNextCharacter;
+
+ showLocaleChooserGUI(new Vec2(getScreenWidth()/2-(localeChooser.window.size.x/2), characterSelect.window.position.y+characterSelect.window.size.y+20));
}
// ===========================================================================
@@ -211,6 +220,7 @@ function switchCharacterSelectGUI(firstName, lastName, cash, clan, lastPlayed, s
characterSelect.skinImage = (getGame() == VRR_GAME_GTA_III) ? characterSelect.window.image(310, 32, 100, 90, `files/images/skins/gta3/${getSkinImage(skinId)}.png`) : characterSelect.window.image(310, 32, 100, 90, "files/images/skins/none.png");
characterSelect.window.shown = true;
+
guiSubmitKey = selectThisCharacter;
guiLeftKey = selectPreviousCharacter;
guiRightKey = selectNextCharacter;
diff --git a/scripts/client/gui/error.js b/scripts/client/gui/error.js
index 9ace4627..360afa9e 100644
--- a/scripts/client/gui/error.js
+++ b/scripts/client/gui/error.js
@@ -17,7 +17,7 @@ let errorDialog = {
function initErrorDialogGUI() {
logToConsole(LOG_DEBUG, `[VRR.GUI] Creating error GUI ...`);
- errorDialog.window = mexui.window(game.width/2-200, game.height/2-70, 500, 140, 'ERROR', {
+ errorDialog.window = mexui.window(getScreenWidth()/2-200, getScreenHeight()/2-70, 400, 140, 'ERROR', {
main: {
backgroundColour: toColour(secondaryColour[0], secondaryColour[1], secondaryColour[2], windowAlpha),
transitionTime: 500,
@@ -34,7 +34,7 @@ function initErrorDialogGUI() {
},
});
- errorDialog.messageLabel = errorDialog.window.text(15, 50, 470, 75, 'Error Message', {
+ errorDialog.messageLabel = errorDialog.window.text(15, 50, 370, 20, 'Error Message', {
main: {
textSize: 10.0,
textAlign: 0.5,
@@ -63,12 +63,14 @@ function initErrorDialogGUI() {
// ===========================================================================
-function showErrorGUI(errorMessage, errorTitle) {
+function showErrorGUI(errorMessage, errorTitle, buttonText) {
closeAllWindows();
logToConsole(LOG_DEBUG, `[VRR.GUI] Showing error window. Error: ${errorTitle} - ${errorMessage}`);
setChatWindowEnabled(false);
mexui.setInput(true);
errorDialog.messageLabel.text = errorMessage;
+ errorDialog.okayButton.text = buttonText;
+ errorDialog.window.title = errorTitle;
errorDialog.window.shown = true;
}
diff --git a/scripts/client/gui/info.js b/scripts/client/gui/info.js
index 7ecff81b..c6066df8 100644
--- a/scripts/client/gui/info.js
+++ b/scripts/client/gui/info.js
@@ -17,7 +17,7 @@ let infoDialog = {
function initInfoDialogGUI() {
logToConsole(LOG_DEBUG, `[VRR.GUI] Creating info dialog GUI ...`);
- infoDialog.window = mexui.window(game.width/2-200, game.height/2-70, 400, 140, 'Information', {
+ infoDialog.window = mexui.window(getScreenWidth()/2-200, getScreenHeight()/2-70, 400, 140, 'Information', {
main: {
backgroundColour: toColour(secondaryColour[0], secondaryColour[1], secondaryColour[2], windowAlpha),
},
@@ -70,11 +70,13 @@ function closeInfoDialog() {
// ===========================================================================
-function showInfo(infoMessage, infoTitle) {
+function showInfoGUI(infoMessage, infoTitle, buttonText) {
closeAllWindows();
logToConsole(LOG_DEBUG, `[VRR.GUI] Showing info dialog window. Info: ${infoTitle} - ${infoMessage}`);
mexui.setInput(true);
infoDialog.messageLabel.text = infoMessage;
+ infoDialog.okayButton.text = buttonText;
+ infoDialog.window.title = infoTitle;
infoDialog.window.shown = true;
}
diff --git a/scripts/client/gui/localechooser.js b/scripts/client/gui/localechooser.js
new file mode 100644
index 00000000..e0bdf063
--- /dev/null
+++ b/scripts/client/gui/localechooser.js
@@ -0,0 +1,116 @@
+// ===========================================================================
+// Vortrex's Roleplay Resource
+// https://github.com/VortrexFTW/gtac_roleplay
+// ===========================================================================
+// FILE: localechooser.js
+// DESC: Provides locale chooser GUI
+// TYPE: Client (JavaScript)
+// ===========================================================================
+
+let localeChooser = {
+ window: null,
+ flagImages: [],
+ activeRingImages: [],
+};
+
+let flagImageSize = toVector2(30, 30);
+let flagImageGap = toVector2(5, 5);
+
+// ===========================================================================
+
+function initLocaleChooserGUI() {
+ logToConsole(LOG_DEBUG, `[VRR.GUI] Creating locale chooser GUI ...`);
+ localeChooser.window = mexui.window(game.width/2-200, game.height-150, 60, 60, 'Choose a language', {
+ main: {
+ backgroundColour: toColour(secondaryColour[0], secondaryColour[1], secondaryColour[2], 0),
+ },
+ title: {
+ textSize: 11.0,
+ textColour: toColour(primaryTextColour[0], primaryTextColour[1], primaryTextColour[2], 255),
+ backgroundColour: toColour(primaryColour[0], primaryColour[1], primaryColour[2], windowTitleAlpha),
+ },
+ icon: {
+ textSize: 0.0,
+ textColour: toColour(0, 0, 0, 0),
+ backgroundColour: toColour(0, 0, 0, 0),
+ },
+ });
+ localeChooser.window.titleBarShown = false;
+
+ loadLocaleConfig();
+
+ logToConsole(LOG_DEBUG, `[VRR.GUI] Created locale chooser GUI`);
+}
+
+// ===========================================================================
+
+function closeLocaleChooserGUI() {
+ logToConsole(LOG_DEBUG, `[VRR.GUI] Closing locale chooser window`);
+ localeChooser.window.shown = false;
+ mexui.setInput(false);
+}
+
+// ===========================================================================
+
+function showLocaleChooserGUI(position = toVector2(0.0, 0.0)) {
+ if(position.x != 0.0 && position.y != 0.0) {
+ localeChooser.window.position = position;
+ } else {
+ localeChooser.window.position = toVector2((getScreenWidth()/2)-(localeChooser.window.size.x/2), getScreenHeight()-100);
+ }
+
+ //closeAllWindows();
+ logToConsole(LOG_DEBUG, `[VRR.GUI] Showing locale chooser window`);
+ mexui.setInput(true);
+ localeChooser.window.shown = true;
+}
+
+// ===========================================================================
+
+function toggleLocaleChooserGUI() {
+ if(localeChooser.window.shown) {
+ closeLocaleChooserGUI();
+ } else {
+ showLocaleChooserGUI();
+ }
+}
+
+// ===========================================================================
+
+function localeChooserSetLocale(localeId) {
+ logToConsole(LOG_DEBUG|LOG_WARN, `[VRR.GUI] Asking server to change locale to ${localeId}`);
+ sendLocaleSelectToServer(localeId);
+}
+
+// ===========================================================================
+
+function resetLocaleChooserOptions() {
+ logToConsole(LOG_DEBUG|LOG_WARN, `[VRR.GUI] Resetting locale chooser options`);
+
+ // let tempLocaleOptions = getServerData().localeOptions; // getAvailableLocaleOptions();
+ let tempLocaleOptions = getAvailableLocaleOptions();
+
+ localeChooser.window.size = toVector2((tempLocaleOptions.length*(flagImageSize.x+flagImageGap.x))+flagImageGap.x, flagImageSize.y+flagImageGap.y*2);
+ localeChooser.window.position = toVector2((getScreenWidth()/2)-(localeChooser.window.size.x/2), getScreenHeight()-100);
+
+ for(let i in localeChooser.flagImages) {
+ localeChooser.flagImages[i].remove();
+ }
+
+ for(let i in tempLocaleOptions) {
+ let imagePath = `files/images/flags/${tempLocaleOptions[i].flagImageFile}`;
+ localeChooser.flagImages[i] = localeChooser.window.image((i*(flagImageSize.x+flagImageGap.x))+flagImageGap.x, flagImageGap.y, flagImageSize.x, flagImageSize.y, imagePath, {
+ focused: {
+ borderColour: toColour(0, 0, 0, 0),
+ },
+ }, function() {
+ localeChooserSetLocale(tempLocaleOptions[i].id);
+ });
+
+ logToConsole(LOG_DEBUG|LOG_WARN, `[VRR.GUI] Created locale chooser option ${tempLocaleOptions[i].englishName} with image ${imagePath}`);
+
+ //localeChooser.activeRingImages.push(activeRingImage);
+ }
+}
+
+// ===========================================================================
\ No newline at end of file
diff --git a/scripts/client/gui/login.js b/scripts/client/gui/login.js
index 51b5fa03..e33ef2c2 100644
--- a/scripts/client/gui/login.js
+++ b/scripts/client/gui/login.js
@@ -11,7 +11,6 @@ let login = {
window: null,
logoImage: null,
messageLabel: null,
- passwordLabel: null,
passwordInput: null,
loginButton: null,
forgotPasswordButton: null,
@@ -20,9 +19,31 @@ let login = {
// ===========================================================================
+let loginHTML =
+`
+
+ Asshat Gaming Roleplay: Login
+
+
+
+
+`;
+
+// ===========================================================================
+
function initLoginGUI() {
logToConsole(LOG_DEBUG, `[VRR.GUI] Creating login GUI ...`);
- login.window = mexui.window(game.width/2-150, game.height/2-135, 300, 275, 'LOGIN', {
+ login.window = mexui.window(getScreenWidth()/2-150, getScreenHeight()/2-135, 300, 275, 'LOGIN', {
main: {
backgroundColour: toColour(secondaryColour[0], secondaryColour[1], secondaryColour[2], windowAlpha),
transitionTime: 500,
@@ -41,8 +62,9 @@ function initLoginGUI() {
});
login.window.titleBarIconSize = toVector2(0,0);
login.window.titleBarHeight = 0;
+ login.window.titleBarShown = false;
- login.logoImage = login.window.image(5, 20, 290, 100, mainLogoPath, {
+ login.logoImage = login.window.image(100, 20, 100, 100, mainLogoPath, {
focused: {
borderColour: toColour(0, 0, 0, 0),
},
@@ -96,7 +118,7 @@ function initLoginGUI() {
},
}, checkLogin);
- login.forgotPasswordButton = login.window.button(200, 240, 80, 15, 'RESET PASS', {
+ login.forgotPasswordButton = login.window.button(180, 240, 100, 15, 'RESET PASS', {
main: {
backgroundColour: toColour(primaryColour[0], primaryColour[1], primaryColour[2], buttonAlpha),
textColour: toColour(0, 0, 0, 255),
@@ -109,7 +131,7 @@ function initLoginGUI() {
},
}, switchToPasswordResetGUI);
- login.resetPasswordLabel = login.window.text(125, 240, 60, 15, 'Forgot your password?', {
+ login.resetPasswordLabel = login.window.text(110, 240, 60, 15, 'Forgot your password?', {
main: {
textSize: 8.0,
textAlign: 1.0,
@@ -134,6 +156,8 @@ function showLoginGUI() {
login.window.shown = true;
mexui.focusedControl = login.passwordInput;
guiSubmitKey = checkLogin;
+
+ showLocaleChooserGUI(new Vec2(getScreenWidth()/2-(localeChooser.window.size.x/2), login.window.position.y+login.window.size.y+20));
//showSmallGameMessage(`If you don't have a mouse cursor, press ${toUpperCase(getKeyNameFromId(disableGUIKey))} to disable GUI`, COLOUR_WHITE, 7500);
}
@@ -164,9 +188,10 @@ function loginSuccess() {
// ===========================================================================
function switchToPasswordResetGUI() {
- closeAllWindows();
- logToConsole(LOG_DEBUG, `[VRR.GUI] Showing password reset dialog window`);
- showResetPasswordGUI();
+ //closeAllWindows();
+ //logToConsole(LOG_DEBUG, `[VRR.GUI] Showing password reset dialog window`);
+ //showResetPasswordGUI();
+ sendNetworkEventToServer("vrr.checkResetPassword", "");
return false;
}
diff --git a/scripts/client/gui/newchar.js b/scripts/client/gui/newchar.js
index 51421096..5a13504a 100644
--- a/scripts/client/gui/newchar.js
+++ b/scripts/client/gui/newchar.js
@@ -9,11 +9,10 @@
let newCharacter = {
window: null,
+ messageLabel: null,
firstNameInput: null,
lastNameInput: null,
- skinDropDown: null,
- spawnAreaDropDown: null,
- createButton: null,
+ createCharacterButton: null,
mainLogoImage: null,
};
@@ -21,13 +20,14 @@ let newCharacter = {
function initNewCharacterGUI() {
logToConsole(LOG_DEBUG, `[VRR.GUI] Creating new character GUI ...`);
- newCharacter.window = mexui.window(game.width/2-130, game.height/2-115, 300, 230, 'New Character', {
+ newCharacter.window = mexui.window(getScreenWidth()/2-130, getScreenHeight()/2-115, 300, 230, 'NEW CHARACTER', {
main: {
backgroundColour: toColour(secondaryColour[0], secondaryColour[1], secondaryColour[2], windowAlpha),
transitionTime: 500,
},
title: {
- textSize: 0.0,
+ textSize: 12.0,
+ textFont: mainFont,
textColour: toColour(0, 0, 0, 0),
backgroundColour: toColour(primaryColour[0], primaryColour[1], primaryColour[2], windowTitleAlpha),
},
@@ -37,10 +37,12 @@ function initNewCharacterGUI() {
backgroundColour: toColour(primaryColour[0], primaryColour[1], primaryColour[2], windowTitleAlpha),
}
});
- newCharacter.window.titleBarIconSize = toVector2(0,0);
- newCharacter.window.titleBarHeight = 0;
+ newCharacter.window.titleBarIconSize = toVector2(0, 0);
+ newCharacter.window.titleBarIconShown = false;
+ newCharacter.window.titleBarShown = false;
+ newCharacter.window.titleBarHeight = 30;
- newCharacter.mainLogoImage = newCharacter.window.image(5, 20, 290, 80, mainLogoPath, {
+ newCharacter.mainLogoImage = newCharacter.window.image(80, 20, 80, 80, mainLogoPath, {
focused: {
borderColour: toColour(0, 0, 0, 0),
},
@@ -133,8 +135,6 @@ function newCharacterFailed(errorMessage) {
function checkNewCharacter() {
logToConsole(LOG_DEBUG, `[VRR.GUI] Checking new character with server ...`);
- let skinId = false;
-
if(newCharacter.firstNameInput.lines[0].length < 2) {
return false;
}
@@ -158,7 +158,9 @@ function showNewCharacterGUI() {
mexui.setInput(true);
newCharacter.window.shown = true;
mexui.focusedInput = newCharacter.firstNameInput;
- guiSubmitButton = checkNewCharacter;
+ guiSubmitKey = checkNewCharacter;
+
+ showLocaleChooserGUI(new Vec2(getScreenWidth()/2-(localeChooser.window.size.x/2), newCharacter.window.position.y+newCharacter.window.size.y+20));
}
// ===========================================================================
\ No newline at end of file
diff --git a/scripts/client/gui/register.js b/scripts/client/gui/register.js
index 1d1e0378..110e39e4 100644
--- a/scripts/client/gui/register.js
+++ b/scripts/client/gui/register.js
@@ -21,7 +21,7 @@ let register = {
function initRegisterGUI() {
logToConsole(LOG_DEBUG, `[VRR.GUI] Creating register GUI ...`);
- register.window = mexui.window(game.width/2-150, game.height/2-150, 300, 300, 'Register', {
+ register.window = mexui.window(getScreenWidth()/2-150, getScreenHeight()/2-150, 300, 300, 'Register', {
main: {
backgroundColour: toColour(secondaryColour[0], secondaryColour[1], secondaryColour[2], windowAlpha),
transitionTime: 500,
@@ -39,8 +39,9 @@ function initRegisterGUI() {
});
register.window.titleBarIconSize = toVector2(0,0);
register.window.titleBarHeight = 0;
+ register.window.titleBarShown = false;
- register.window.image(5, 20, 290, 80, mainLogoPath, {
+ register.window.image(100, 20, 100, 100, mainLogoPath, {
focused: {
borderColour: toColour(0, 0, 0, 0),
},
@@ -160,6 +161,9 @@ function showRegistrationGUI() {
register.window.shown = true;
mexui.focusedControl = register.passwordInput;
guiSubmitKey = checkRegistration;
+
+ showLocaleChooserGUI(new Vec2(getScreenWidth()/2-(localeChooser.window.size.x/2), register.window.position.y+register.window.size.y+20));
+
//showSmallGameMessage(`If you don't have a mouse cursor, press ${toUpperCase(getKeyNameFromId(disableGUIKey))} to disable GUI`, COLOUR_WHITE, 7500);
}
diff --git a/scripts/client/gui/resetpass.js b/scripts/client/gui/resetpass.js
index 433e0046..f81eafc4 100644
--- a/scripts/client/gui/resetpass.js
+++ b/scripts/client/gui/resetpass.js
@@ -7,11 +7,10 @@
// TYPE: Client (JavaScript)
// ===========================================================================
-let resetPassword = {
+let passwordReset = {
window: null,
logoImage: null,
messageLabel: null,
- emailLabel: null,
emailInput: null,
resetPasswordButton: null,
backToLoginButton: null,
@@ -22,7 +21,7 @@ let resetPassword = {
function initResetPasswordGUI() {
logToConsole(LOG_DEBUG, `[VRR.GUI] Creating password reset GUI ...`);
- resetPassword.window = mexui.window(game.width/2-150, game.height/2-130, 300, 260, 'RESET PASSWORD', {
+ passwordReset.window = mexui.window(getScreenWidth()/2-150, getScreenHeight()/2-135, 300, 275, 'RESET PASSWORD', {
main: {
backgroundColour: toColour(secondaryColour[0], secondaryColour[1], secondaryColour[2], windowAlpha),
transitionTime: 500,
@@ -39,16 +38,17 @@ function initResetPasswordGUI() {
borderColour: toColour(0, 0, 0, 0),
},
});
- resetPassword.window.titleBarIconSize = toVector2(0,0);
- resetPassword.window.titleBarHeight = 0;
+ passwordReset.window.titleBarIconSize = toVector2(0,0);
+ passwordReset.window.titleBarHeight = 0;
+ passwordReset.window.titleBarShown = false;
- resetPassword.logoImage = resetPassword.window.image(5, 20, 290, 80, mainLogoPath, {
+ passwordReset.logoImage = passwordReset.window.image(100, 20, 100, 100, mainLogoPath, {
focused: {
borderColour: toColour(0, 0, 0, 0),
},
});
- resetPassword.messageLabel = resetPassword.window.text(20, 135, 260, 20, 'Please confirm your email', {
+ passwordReset.messageLabel = passwordReset.window.text(20, 135, 260, 20, 'Please confirm your email', {
main: {
textSize: 10.0,
textAlign: 0.5,
@@ -60,7 +60,7 @@ function initResetPasswordGUI() {
},
});
- resetPassword.emailInput = resetPassword.window.textInput(20, 170, 260, 25, '', {
+ passwordReset.emailInput = passwordReset.window.textInput(20, 170, 260, 25, '', {
main: {
backgroundColour: toColour(0, 0, 0, 120),
borderColour: toColour(primaryColour[0], primaryColour[1], primaryColour[2], textInputAlpha),
@@ -80,9 +80,9 @@ function initResetPasswordGUI() {
borderColour: toColour(primaryColour[0], primaryColour[1], primaryColour[2], 255),
},
});
- resetPassword.emailInput.placeholder = "Email";
+ passwordReset.emailInput.placeholder = "Email";
- resetPassword.resetPasswordButton = resetPassword.window.button(20, 205, 260, 30, 'RESET PASSWORD', {
+ passwordReset.resetPasswordButton = passwordReset.window.button(180, 240, 100, 15, 'RESET PASSWORD', {
main: {
backgroundColour: toColour(primaryColour[0], primaryColour[1], primaryColour[2], buttonAlpha),
textColour: toColour(primaryTextColour[0], primaryTextColour[1], primaryTextColour[2], 255),
@@ -95,7 +95,7 @@ function initResetPasswordGUI() {
},
}, checkResetPassword);
- resetPassword.backToLoginButton = resetPassword.window.button(200, 240, 80, 15, 'LOGIN', {
+ passwordReset.backToLoginButton = passwordReset.window.button(200, 240, 80, 15, 'LOGIN', {
main: {
backgroundColour: toColour(primaryColour[0], primaryColour[1], primaryColour[2], buttonAlpha),
textColour: toColour(primaryTextColour[0], primaryTextColour[1], primaryTextColour[2], 255),
@@ -108,7 +108,7 @@ function initResetPasswordGUI() {
},
}, switchToLoginGUI);
- resetPassword.backToLoginLabel = resetPassword.window.text(125, 240, 60, 15, 'Remember your password?', {
+ passwordReset.backToLoginLabel = passwordReset.window.text(110, 240, 60, 15, 'Remember your password?', {
main: {
textSize: 8.0,
textAlign: 1.0,
@@ -130,9 +130,11 @@ function showResetPasswordGUI() {
logToConsole(LOG_DEBUG, `[VRR.GUI] Showing password reset window`);
setChatWindowEnabled(false);
mexui.setInput(true);
- resetPassword.window.shown = true;
- mexui.focusedControl = resetPassword.emailInput;
- guiSubmitButton = checkResetPassword;
+ passwordReset.window.shown = true;
+ mexui.focusedControl = passwordReset.emailInput;
+ guiSubmitKey = checkResetPassword;
+
+ showLocaleChooserGUI(new Vec2(getScreenWidth()/2-(localeChooser.window.size.x/2), passwordReset.window.position.y+passwordReset.window.size.y+20));
//showSmallGameMessage(`If you don't have a mouse cursor, press ${toUpperCase(getKeyNameFromId(disableGUIKey))} to disable GUI`, COLOUR_WHITE, 7500);
}
@@ -140,30 +142,46 @@ function showResetPasswordGUI() {
function checkResetPassword() {
logToConsole(LOG_DEBUG, `[VRR.GUI] Checking password reset with server ...`);
- sendNetworkEventToServer("vrr.checkResetPassword", resetPassword.emailInput.lines[0]);
+ sendNetworkEventToServer("vrr.checkResetPassword", passwordReset.emailInput.lines[0]);
}
// ===========================================================================
function resetPasswordFailed(errorMessage) {
logToConsole(LOG_DEBUG, `[VRR.GUI] Server reports password reset failed`);
- resetPassword.messageLabel.text = errorMessage;
- resetPassword.messageLabel.styles.main.textColour = toColour(180, 32, 32, 255);
- resetPassword.emailInput.text = "";
+ passwordReset.messageLabel.text = errorMessage;
+ passwordReset.messageLabel.styles.main.textColour = toColour(180, 32, 32, 255);
+ passwordReset.emailInput.text = "";
}
// ===========================================================================
function resetPasswordCodeInputGUI() {
- logToConsole(LOG_DEBUG, `[VRR.GUI] Server reports password reset was successful`);
-
- resetPassword.messageLabel.text = "Check your email for a verification code";
- resetPassword.messageLabel.styles.main.textColour = toColour(180, 32, 32, 255);
- resetPassword.emailInput.text = "";
- resetPassword.emailInput.placeholder = "Verification Code";
-
- guiSubmitButton = checkResetPassword;
+ logToConsole(LOG_DEBUG|LOG_WARN, `[VRR.GUI] Server reports password reset email confirmation was successful. Asking for code ...`);
closeAllWindows();
+
+ passwordReset.messageLabel.text = getLocaleString("GUIResetPasswordCodeInputLabel");
+ //passwordReset.messageLabel.styles.main.textColour = toColour(180, 32, 32, 255);
+ passwordReset.emailInput.text = "";
+ passwordReset.emailInput.placeholder = getLocaleString("GUIResetPasswordCodePlaceholder");
+
+ guiSubmitKey = checkResetPassword;
+ showResetPasswordGUI();
+}
+
+// ===========================================================================
+
+function resetPasswordEmailInputGUI() {
+ logToConsole(LOG_DEBUG|LOG_WARN, `[VRR.GUI] Server reports password reset request was approved. Asking for email ...`);
+ closeAllWindows();
+
+ passwordReset.messageLabel.text = getLocaleString("GUIResetPasswordConfirmEmailLabel");
+ //passwordReset.messageLabel.styles.main.textColour = toColour(180, 32, 32, 255);
+ passwordReset.emailInput.text = "";
+ passwordReset.emailInput.placeholder = getLocaleString("GUIResetPasswordEmailPlaceholder");
+
+ guiSubmitKey = checkResetPassword;
+ showResetPasswordGUI();
}
// ===========================================================================
diff --git a/scripts/client/gui/yesno.js b/scripts/client/gui/yesno.js
index 43746040..8ba392d4 100644
--- a/scripts/client/gui/yesno.js
+++ b/scripts/client/gui/yesno.js
@@ -18,71 +18,81 @@ let yesNoDialog = {
// ===========================================================================
function initYesNoDialogGUI() {
- logToConsole(LOG_DEBUG, `[VRR.GUI] Created prompt GUI ...`);
- yesNoDialog.window = mexui.window(game.width/2-200, game.height/2-70, 400, 140, 'Question', {
- main: {
- backgroundColour: toColour(secondaryColour[0], secondaryColour[1], secondaryColour[2], windowAlpha),
- transitionTime: 500,
- },
- title: {
- textSize: 11.0,
- textColour: toColour(primaryTextColour[0], primaryTextColour[1], primaryTextColour[2], 255),
- backgroundColour: toColour(primaryColour[0], primaryColour[1], primaryColour[2], windowTitleAlpha),
- },
- icon: {
- textSize: 0.0,
- textColour: toColour(0, 0, 0, 0),
- backgroundColour: toColour(0, 0, 0, 0),
- },
- });
+ logToConsole(LOG_DEBUG, `[VRR.GUI] Created prompt GUI ...`);
+ yesNoDialog.window = mexui.window(game.width/2-200, game.height/2-70, 400, 140, 'Question', {
+ main: {
+ backgroundColour: toColour(secondaryColour[0], secondaryColour[1], secondaryColour[2], windowAlpha),
+ transitionTime: 500,
+ },
+ title: {
+ textSize: 11.0,
+ textColour: toColour(primaryTextColour[0], primaryTextColour[1], primaryTextColour[2], 255),
+ backgroundColour: toColour(primaryColour[0], primaryColour[1], primaryColour[2], windowTitleAlpha),
+ },
+ icon: {
+ textSize: 0.0,
+ textColour: toColour(0, 0, 0, 0),
+ backgroundColour: toColour(0, 0, 0, 0),
+ },
+ });
- yesNoDialog.messageLabel = yesNoDialog.window.text(15, 50, 370, 20, 'Would you like to answer this question?', {
- main: {
- textSize: 10.0,
- textAlign: 0.5,
- textColour: toColour(255, 255, 255, 255),
- textFont: mainFont,
- },
- focused: {
- borderColour: toColour(0, 0, 0, 0),
- },
- });
+ yesNoDialog.messageLabel = yesNoDialog.window.text(15, 50, 370, 20, 'Would you like to answer this question?', {
+ main: {
+ textSize: 10.0,
+ textAlign: 0.5,
+ textColour: toColour(255, 255, 255, 255),
+ textFont: mainFont,
+ },
+ focused: {
+ borderColour: toColour(0, 0, 0, 0),
+ },
+ });
- yesNoDialog.yesButton = yesNoDialog.window.button(5, 100, 197, 25, 'YES', {
- main: {
- backgroundColour: toColour(primaryColour[0], primaryColour[1], primaryColour[2], buttonAlpha),
- textColour: toColour(primaryTextColour[0], primaryTextColour[1], primaryTextColour[2], 255),
- textSize: 10.0,
- textFont: mainFont,
- textAlign: 0.5,
- },
- focused: {
- borderColour: toColour(primaryColour[0], primaryColour[1], primaryColour[2], 255),
- },
- }, yesNoDialogAnswerYes);
+ yesNoDialog.yesButton = yesNoDialog.window.button(5, 105, 193, 30, 'YES', {
+ main: {
+ backgroundColour: toColour(primaryColour[0], primaryColour[1], primaryColour[2], buttonAlpha),
+ textColour: toColour(primaryTextColour[0], primaryTextColour[1], primaryTextColour[2], 255),
+ textSize: 10.0,
+ textFont: mainFont,
+ textAlign: 0.5,
+ },
+ focused: {
+ borderColour: toColour(primaryColour[0], primaryColour[1], primaryColour[2], 255),
+ },
+ }, yesNoDialogAnswerYes);
- yesNoDialog.noButton = yesNoDialog.window.button(202, 105, 197, 25, 'NO', {
- main: {
- backgroundColour: toColour(primaryColour[0], primaryColour[1], primaryColour[2], buttonAlpha),
- textColour: toColour(primaryTextColour[0], primaryTextColour[1], primaryTextColour[2], 255),
- textSize: 10.0,
- textFont: mainFont,
- textAlign: 0.5,
- },
- focused: {
- borderColour: toColour(primaryColour[0], primaryColour[1], primaryColour[2], 255),
- },
- }, yesNoDialogAnswerNo);
- logToConsole(LOG_DEBUG, `[VRR.GUI] Created prompt GUI`);
+ yesNoDialog.noButton = yesNoDialog.window.button(203, 105, 192, 30, 'NO', {
+ main: {
+ backgroundColour: toColour(primaryColour[0], primaryColour[1], primaryColour[2], buttonAlpha),
+ textColour: toColour(primaryTextColour[0], primaryTextColour[1], primaryTextColour[2], 255),
+ textSize: 10.0,
+ textFont: mainFont,
+ textAlign: 0.5,
+ },
+ focused: {
+ borderColour: toColour(primaryColour[0], primaryColour[1], primaryColour[2], 255),
+ },
+ }, yesNoDialogAnswerNo);
+ logToConsole(LOG_DEBUG, `[VRR.GUI] Created prompt GUI`);
}
// ===========================================================================
-function showYesNoPromptGUI(promptMessage, promptTitle) {
+function showYesNoPromptGUI(promptMessage, promptTitle, yesButtonText, noButtonText) {
closeAllWindows();
logToConsole(LOG_DEBUG, `[VRR.GUI] Showing prompt window. Prompt: ${promptTitle} - ${promptMessage}`);
mexui.setInput(true);
+
+ yesNoDialog.messageLabel.text = "";
+ yesNoDialog.yesButton.text = "";
+ yesNoDialog.noButton.text = "";
+ yesNoDialog.window.title = "";
+
yesNoDialog.messageLabel.text = promptMessage;
+ yesNoDialog.yesButton.text = yesButtonText;
+ yesNoDialog.noButton.text = noButtonText;
+ yesNoDialog.window.title = promptTitle;
+
yesNoDialog.window.shown = true;
}
diff --git a/scripts/client/house.js b/scripts/client/house.js
index ecdc5d9a..0eaa47e9 100644
--- a/scripts/client/house.js
+++ b/scripts/client/house.js
@@ -8,9 +8,10 @@
// ===========================================================================
class HouseData {
- constructor(houseId, entrancePosition, blipModel, pickupModel, hasInterior) {
+ constructor(houseId, description, entrancePosition, blipModel, pickupModel, hasInterior) {
this.index = -1;
this.houseId = houseId;
+ this.description = description;
this.entrancePosition = entrancePosition;
this.blipModel = blipModel;
this.pickupModel = pickupModel;
@@ -21,12 +22,13 @@ class HouseData {
// ===========================================================================
-function receiveHouseFromServer(houseId, entrancePosition, blipModel, pickupModel, hasInterior) {
+function receiveHouseFromServer(houseId, description, entrancePosition, blipModel, pickupModel, hasInterior) {
logToConsole(LOG_DEBUG, `[VRR.House] Received house ${houseId} (${name}) from server`);
- if(getGame() == VRR_GAME_GTA_IV) {
+ if(!areServerElementsSupported()) {
if(getHouseData(houseId) != false) {
let houseData = getHouseData(houseId);
+ houseData.description = description;
houseData.entrancePosition = entrancePosition;
houseData.blipModel = blipModel;
houseData.pickupModel = pickupModel;
@@ -65,7 +67,7 @@ function receiveHouseFromServer(houseId, entrancePosition, blipModel, pickupMode
}
} else {
logToConsole(LOG_DEBUG, `[VRR.House] House ${houseId} doesn't exist. Adding ...`);
- let tempHouseData = new HouseData(houseId, entrancePosition, blipModel, pickupModel, hasInterior);
+ let tempHouseData = new HouseData(houseId, description, entrancePosition, blipModel, pickupModel, hasInterior);
if(blipModel != -1) {
let blipId = createGameBlip(tempHouseData.blipModel, tempHouseData.entrancePosition, "House");
if(blipId != -1) {
diff --git a/scripts/client/item.js b/scripts/client/item.js
index a1735ae0..783426eb 100644
--- a/scripts/client/item.js
+++ b/scripts/client/item.js
@@ -23,40 +23,40 @@ function initItemScript() {
// ===========================================================================
function processItemActionRendering() {
- if(renderItemActionDelay) {
- if(itemActionDelayEnabled) {
- let finishTime = itemActionDelayStart+itemActionDelayDuration;
- if(sdl.ticks >= finishTime) {
- itemActionDelayEnabled = false;
- itemActionDelayDuration = 0;
- itemActionDelayStart = 0;
- tellServerItemActionDelayComplete();
- } else {
- let currentTick = sdl.ticks-itemActionDelayStart;
- let progressPercent = Math.ceil(currentTick*100/itemActionDelayDuration);
- let width = Math.ceil(getPercentage(itemActionDelaySize.x, progressPercent));
+ if(renderItemActionDelay) {
+ if(itemActionDelayEnabled) {
+ let finishTime = itemActionDelayStart+itemActionDelayDuration;
+ if(sdl.ticks >= finishTime) {
+ itemActionDelayEnabled = false;
+ itemActionDelayDuration = 0;
+ itemActionDelayStart = 0;
+ tellServerItemActionDelayComplete();
+ } else {
+ let currentTick = sdl.ticks-itemActionDelayStart;
+ let progressPercent = Math.ceil(currentTick*100/itemActionDelayDuration);
+ let width = Math.ceil(getPercentage(itemActionDelaySize.x, progressPercent));
- let backgroundColour = toColour(0, 0, 0, 255);
- graphics.drawRectangle(null, [itemActionDelayPosition.x-(itemActionDelaySize.x/2)-1, itemActionDelayPosition.y-(itemActionDelaySize.y/2)-1], [itemActionDelaySize.x+2, itemActionDelaySize.y+2], backgroundColour, backgroundColour, backgroundColour, backgroundColour);
- graphics.drawRectangle(null, [itemActionDelayPosition.x-(itemActionDelaySize.x/2), itemActionDelayPosition.y-(itemActionDelaySize.y/2)-2], [width, itemActionDelaySize.y], COLOUR_LIME, COLOUR_LIME, COLOUR_LIME, COLOUR_LIME);
- }
- }
- }
+ let backgroundColour = toColour(0, 0, 0, 255);
+ graphics.drawRectangle(null, [itemActionDelayPosition.x-(itemActionDelaySize.x/2)-1, itemActionDelayPosition.y-(itemActionDelaySize.y/2)-1], [itemActionDelaySize.x+2, itemActionDelaySize.y+2], backgroundColour, backgroundColour, backgroundColour, backgroundColour);
+ graphics.drawRectangle(null, [itemActionDelayPosition.x-(itemActionDelaySize.x/2), itemActionDelayPosition.y-(itemActionDelaySize.y/2)-2], [width, itemActionDelaySize.y], COLOUR_LIME, COLOUR_LIME, COLOUR_LIME, COLOUR_LIME);
+ }
+ }
+ }
}
// ===========================================================================
function updatePlayerHotBar(activeSlot, itemsArray) {
- logToConsole(LOG_DEBUG, `[VRR.Main] Updating hotbar`);
+ logToConsole(LOG_DEBUG, `[VRR.Main] Updating hotbar`);
}
// ===========================================================================
function showItemActionDelay(duration) {
- itemActionDelayDuration = duration;
- itemActionDelayStart = sdl.ticks;
- itemActionDelayEnabled = true;
- logToConsole(LOG_DEBUG, `Item action delay started. Duration: ${itemActionDelayDuration}, Start: ${itemActionDelayStart}, Rendering Enabled: ${renderItemActionDelay}`);
+ itemActionDelayDuration = duration;
+ itemActionDelayStart = sdl.ticks;
+ itemActionDelayEnabled = true;
+ logToConsole(LOG_DEBUG, `Item action delay started. Duration: ${itemActionDelayDuration}, Start: ${itemActionDelayStart}, Rendering Enabled: ${renderItemActionDelay}`);
}
// ===========================================================================
\ No newline at end of file
diff --git a/scripts/client/job.js b/scripts/client/job.js
index 5fe79d1d..407d94df 100644
--- a/scripts/client/job.js
+++ b/scripts/client/job.js
@@ -12,6 +12,26 @@ let localPlayerWorking = false;
let jobRouteLocationBlip = null;
let jobRouteLocationSphere = null;
+let jobBlipBlinkAmount = 0;
+let jobBlipBlinkTimes = 10;
+let jobBlipBlinkInterval = 500;
+let jobBlipBlinkTimer = null;
+
+// ===========================================================================
+
+class JobData {
+ constructor(jobId, jobLocationId, name, position, blipModel, pickupModel) {
+ this.index = -1;
+ this.jobId = jobId;
+ this.jobLocationId = jobLocationId;
+ this.name = name;
+ this.position = position;
+ this.blipModel = blipModel;
+ this.pickupModel = pickupModel;
+ this.blipId = -1;
+ }
+}
+
// ===========================================================================
function initJobScript() {
@@ -22,14 +42,14 @@ function initJobScript() {
// ===========================================================================
function setLocalPlayerJobType(tempJobType) {
- logToConsole(LOG_DEBUG, `[VRR.Main] Set local player job type to ${tempJobType}`);
+ logToConsole(LOG_DEBUG, `[VRR.Job] Set local player job type to ${tempJobType}`);
localPlayerJobType = tempJobType;
}
// ===========================================================================
function setLocalPlayerWorkingState(tempWorking) {
- logToConsole(LOG_DEBUG, `[VRR.Main] Setting working state to ${tempWorking}`);
+ logToConsole(LOG_DEBUG, `[VRR.Job] Setting working state to ${tempWorking}`);
localPlayerWorking = tempWorking;
}
@@ -38,7 +58,8 @@ function setLocalPlayerWorkingState(tempWorking) {
function showJobRouteLocation(position, colour) {
logToConsole(LOG_DEBUG, `[VRR.Job] Showing job route location`);
if(getMultiplayerMod() == VRR_MPMOD_GTAC) {
- if(game.game == VRR_GAME_GTA_SA) {
+ if(getGame() == VRR_GAME_GTA_SA) {
+ // Server-side spheres don't show in GTA SA for some reason.
jobRouteLocationSphere = game.createPickup(1318, position, 1);
} else {
jobRouteLocationSphere = game.createSphere(position, 3);
@@ -49,7 +70,9 @@ function showJobRouteLocation(position, colour) {
destroyElement(jobRouteLocationBlip);
}
+ // Blinking is bugged if player hit the spot before it stops blinking.
blinkJobRouteLocationBlip(10, position, colour);
+ jobRouteLocationBlip = game.createBlip(position, 0, 2, colour);
}
}
@@ -57,30 +80,48 @@ function showJobRouteLocation(position, colour) {
function enteredJobRouteSphere() {
logToConsole(LOG_DEBUG, `[VRR.Job] Entered job route sphere`);
+
+ clearInterval(jobBlipBlinkTimer);
+ jobBlipBlinkAmount = 0;
+ jobBlipBlinkTimes = 0;
+
+ if(jobRouteLocationBlip != null) {
+ destroyElement(jobRouteLocationBlip);
+ jobRouteLocationBlip = null;
+ }
+
+ if(jobRouteLocationSphere != null) {
+ destroyElement(jobRouteLocationSphere);
+ jobRouteLocationSphere = null;
+ }
+
tellServerPlayerArrivedAtJobRouteLocation();
- destroyElement(jobRouteLocationSphere);
- destroyElement(jobRouteLocationBlip);
- jobRouteLocationSphere = null;
- jobRouteLocationBlip = null;
}
// ===========================================================================
function blinkJobRouteLocationBlip(times, position, colour) {
- for(let i = 1 ; i <= times ; i++) {
- setTimeout(function() {
+ jobBlipBlinkTimes = times;
+ jobBlipBlinkTimer = setInterval(function() {
+ if(jobRouteLocationBlip != null) {
+ destroyElement(jobRouteLocationBlip);
+ jobRouteLocationBlip = null;
+ } else {
+ jobRouteLocationBlip = game.createBlip(position, 0, 2, colour);
+ }
+
+ if(jobBlipBlinkAmount >= jobBlipBlinkTimes) {
if(jobRouteLocationBlip != null) {
destroyElement(jobRouteLocationBlip);
jobRouteLocationBlip = null;
- } else {
- jobRouteLocationBlip = game.createBlip(position, 0, 2, colour);
}
- }, 500*i);
- }
- setTimeout(function() {
- jobRouteLocationBlip = game.createBlip(position, 0, 2, colour);
- }, 500*times+1);
+ jobBlipBlinkAmount = 0;
+ jobBlipBlinkTimes = 0;
+ jobRouteLocationBlip = game.createBlip(position, 0, 2, colour);
+ clearInterval(jobBlipBlinkTimer);
+ }
+ }, jobBlipBlinkInterval);
}
// ===========================================================================
@@ -92,4 +133,91 @@ function hideJobRouteLocation() {
jobRouteLocationBlip = null;
}
+// ===========================================================================
+
+function receiveJobFromServer(jobId, jobLocationId, name, position, blipModel, pickupModel) {
+ logToConsole(LOG_DEBUG, `[VRR.Job] Received job ${jobId} (${name}) from server`);
+
+ if(getGame() == VRR_GAME_GTA_IV) {
+ if(getJobData(jobId) != false) {
+ let jobData = getJobData(jobId);
+ jobData.jobLocationId = jobLocationId;
+ jobData.name = name;
+ jobData.position = position;
+ jobData.blipModel = blipModel;
+ jobData.pickupModel = pickupModel;
+
+ logToConsole(LOG_DEBUG, `[VRR.Job] Job ${jobId} already exists. Checking blip ...`);
+ if(blipModel == -1) {
+ if(jobData.blipId != -1) {
+ logToConsole(LOG_DEBUG, `[VRR.Job] Job ${jobId}'s blip has been removed by the server`);
+ if(getGame() == VRR_GAME_GTA_IV) {
+ natives.removeBlipAndClearIndex(getJobData(jobId).blipId);
+ } else {
+ destroyElement(getElementFromId(blipId));
+ }
+ jobData.blipId = -1;
+ } else {
+ logToConsole(LOG_DEBUG, `[VRR.Job] Job ${jobId}'s blip is unchanged`);
+ }
+ } else {
+ if(jobData.blipId != -1) {
+ logToConsole(LOG_DEBUG, `[VRR.Job] Job ${jobId}'s blip has been changed by the server`);
+ if(getGame() == VRR_GAME_GTA_IV) {
+ natives.setBlipCoordinates(jobData.blipId, jobData.position);
+ natives.changeBlipSprite(jobData.blipId, jobData.blipModel);
+ natives.setBlipMarkerLongDistance(jobData.blipId, false);
+ natives.setBlipAsShortRange(jobData.blipId, true);
+ natives.changeBlipNameFromAscii(jobData.blipId, `${jobData.name.substr(0, 24)}${(jobData.name.length > 24) ? " ...": ""}`);
+ }
+ } else {
+ let blipId = createGameBlip(jobData.blipModel, jobData.position, jobData.name);
+ if(blipId != -1) {
+ jobData.blipId = blipId;
+ }
+ logToConsole(LOG_DEBUG, `[VRR.Job] Job ${jobId}'s blip has been added by the server (Model ${blipModel}, ID ${blipId})`);
+ }
+ }
+ } else {
+ logToConsole(LOG_DEBUG, `[VRR.Job] Job ${jobId} doesn't exist. Adding ...`);
+ let tempJobData = new JobData(jobId, jobLocationId, name, position, blipModel, pickupModel);
+ if(blipModel != -1) {
+ let blipId = createGameBlip(blipModel, tempJobData.position, tempJobData.name);
+ if(blipId != -1) {
+ tempJobData.blipId = blipId;
+ }
+ logToConsole(LOG_DEBUG, `[VRR.Job] Job ${jobId}'s blip has been added by the server (Model ${blipModel}, ID ${blipId})`);
+ } else {
+ logToConsole(LOG_DEBUG, `[VRR.Job] Job ${jobId} has no blip.`);
+ }
+ getServerData().jobs.push(tempJobData);
+ setAllJobDataIndexes();
+ }
+ }
+}
+
+// ===========================================================================
+
+/**
+ * @param {number} job - The ID of the job (initially provided by server)
+ * @return {JobData} The job's data (class instance)
+ */
+ function getJobData(jobId) {
+ for(let i in getServerData().jobs) {
+ if(getServerData().jobs[i].jobId == jobId) {
+ return getServerData().jobs[i];
+ }
+ }
+
+ return false;
+}
+
+// ===========================================================================
+
+function setAllJobDataIndexes() {
+ for(let i in getServerData().jobs) {
+ jobs[i].index = i;
+ }
+}
+
// ===========================================================================
\ No newline at end of file
diff --git a/scripts/client/label.js b/scripts/client/label.js
index 50eca11b..10a0c211 100644
--- a/scripts/client/label.js
+++ b/scripts/client/label.js
@@ -78,9 +78,26 @@ function renderPropertyEntranceLabel(name, position, locked, isBusiness, price,
return false;
}
+ if(getGame() == VRR_GAME_GTA_IV) {
+ if(!natives.doesViewportExist(natives.getGameViewportId())) {
+ logToConsole(LOG_INFO, "[VRR.Label]: Game viewport does not exist!");
+ return false;
+ }
+
+ if(!natives.isViewportActive(natives.getGameViewportId())) {
+ logToConsole(LOG_INFO, "[VRR.Label]: Game viewport is not active!");
+ return false;
+ }
+ }
+
let tempPosition = position;
tempPosition.z = tempPosition.z + propertyLabelHeight;
- let screenPosition = getScreenFromWorldPosition(tempPosition);
+ let screenPosition = new Vec3(0.0, 0.0, 0.0);
+ if(getGame() == VRR_GAME_GTA_IV) {
+ screenPosition = natives.getViewportPositionOfCoord(tempPosition, natives.getGameViewportId());
+ } else {
+ screenPosition = getScreenFromWorldPosition(tempPosition);
+ }
if(screenPosition.x < 0 || screenPosition.x > game.width) {
return false;
@@ -88,7 +105,7 @@ function renderPropertyEntranceLabel(name, position, locked, isBusiness, price,
let text = "";
if(price > "0") {
- text = `For sale: $${price}`;
+ text = getLocaleString("PropertyForSaleLabel", price);
let size = propertyLabelLockedFont.measure(text, game.width, 0.0, 0.0, propertyLabelLockedFont.size, true, true);
propertyLabelLockedFont.render(text, [screenPosition.x-size[0]/2, screenPosition.y-size[1]/2], game.width, 0.0, 0.0, propertyLabelLockedFont.size, toColour(200, 200, 200, 255), false, true, false, true);
@@ -97,59 +114,64 @@ function renderPropertyEntranceLabel(name, position, locked, isBusiness, price,
text = "";
if(rentPrice != "0") {
- text = `For rent: $${rentPrice} every payday`;
+ text = getLocaleString("PropertyForRentLabel", rentPrice);
let size = propertyLabelLockedFont.measure(text, game.width, 0.0, 0.0, propertyLabelLockedFont.size, true, true);
propertyLabelLockedFont.render(text, [screenPosition.x-size[0]/2, screenPosition.y-size[1]/2], game.width, 0.0, 0.0, propertyLabelLockedFont.size, toColour(200, 200, 200, 255), false, true, false, true);
screenPosition.y -= propertyLabelPriceOffset;
}
-
if(isBusiness) {
- text = (locked) ? "CLOSED" : "OPEN";
+ text = (locked) ? toUpperCase(getLocaleString("Closed")) : toUpperCase(getLocaleString("Open"));
} else {
- text = (locked) ? "LOCKED" : "UNLOCKED";
+ text = (locked) ? toUpperCase(getLocaleString("Locked")) : toUpperCase(getLocaleString("Unlocked"));
}
if(!locked && labelInfoType != VRR_PROPLABEL_INFO_NONE) {
let infoText = "";
switch(labelInfoType) {
- case VRR_PROPLABEL_INFO_ENTER:
+ case VRR_PROPLABEL_INFO_ENTER: {
if(enterPropertyKey) {
- infoText = `Press ${toUpperCase(getKeyNameFromId(enterPropertyKey))} to enter`;
+ infoText = getLocaleString("PropertyEnterKeyPressLabel", toUpperCase(getKeyNameFromId(enterPropertyKey)));
} else {
- infoText = `Use /enter to enter`;
+ infoText = getLocaleString("PropertyEnterCommandLabel", "/enter");
}
break;
+ }
- case VRR_PROPLABEL_INFO_BUY:
- infoText = `Use /buy to purchase items`;
+ case VRR_PROPLABEL_INFO_BUY: {
+ infoText = getLocaleString("BusinessBuyItemsLabel", "/buy");
break;
+ }
- case VRR_PROPLABEL_INFO_BUYBIZ:
- infoText = `Use /buy to purchase items`;
+ case VRR_PROPLABEL_INFO_BUYBIZ: {
+ infoText = getLocaleString("BuyBusinessLabel", "/bizbuy");
break;
+ }
- //case VRR_PROPLABEL_INFO_RENTBIZ:
- // infoText = `Use /bizrent to buy this business`;
- // break;
-
- case VRR_PROPLABEL_INFO_BUYHOUSE:
- infoText = `Use /housebuy to buy this house`;
+ case VRR_PROPLABEL_INFO_BUYHOUSE: {
+ infoText = getLocaleString("BuyHouseLabel", "/housebuy");
break;
+ }
- case VRR_PROPLABEL_INFO_RENTHOUSE:
- infoText = `Use /houserent to rent this house`;
+ case VRR_PROPLABEL_INFO_RENTHOUSE: {
+ infoText = getLocaleString("RentHouseLabel", "/houserent");
break;
+ }
- case VRR_PROPLABEL_INFO_ENTERVEH:
- infoText = "Enter a vehicle in the parking lot to buy it";
+ case VRR_PROPLABEL_INFO_ENTERVEHICLE: {
+ infoText = getLocaleString("VehicleDealershipLabel");
break;
+ }
- case VRR_PROPLABEL_INFO_NONE:
- default:
- infoText = "";
+ default: {
+ if(enterPropertyKey) {
+ infoText = getLocaleString("PropertyEnterKeyPressLabel", toUpperCase(getKeyNameFromId(enterPropertyKey)));
+ } else {
+ infoText = getLocaleString("PropertyEnterCommandLabel", "/enter");
+ }
break;
+ }
}
if(getDistance(localPlayer.position, position) <= renderLabelDistance-2) {
let size = propertyLabelLockedFont.measure(infoText, game.width, 0.0, 0.0, propertyLabelLockedFont.size, true, true);
@@ -183,9 +205,26 @@ function renderPropertyExitLabel(position) {
return false;
}
+ if(getGame() == VRR_GAME_GTA_IV) {
+ if(!natives.doesViewportExist(natives.getGameViewportId())) {
+ logToConsole(LOG_INFO, "[VRR.Label]: Game viewport does not exist!");
+ return false;
+ }
+
+ if(!natives.isViewportActive(natives.getGameViewportId())) {
+ logToConsole(LOG_INFO, "[VRR.Label]: Game viewport is not active!");
+ return false;
+ }
+ }
+
let tempPosition = position;
tempPosition.z = tempPosition.z + propertyLabelHeight;
- let screenPosition = getScreenFromWorldPosition(tempPosition);
+ let screenPosition = new Vec3(0.0, 0.0, 0.0);
+ if(getGame() == VRR_GAME_GTA_IV) {
+ screenPosition = natives.getViewportPositionOfCoord(tempPosition, natives.getGameViewportId());
+ } else {
+ screenPosition = getScreenFromWorldPosition(tempPosition);
+ }
if(screenPosition.x < 0 || screenPosition.x > game.width) {
return false;
@@ -211,9 +250,26 @@ function renderJobLabel(name, position, jobType) {
return false;
}
+ if(getGame() == VRR_GAME_GTA_IV) {
+ if(!natives.doesViewportExist(natives.getGameViewportId())) {
+ logToConsole(LOG_INFO, "[VRR.Label]: Game viewport does not exist!");
+ return false;
+ }
+
+ if(!natives.isViewportActive(natives.getGameViewportId())) {
+ logToConsole(LOG_INFO, "[VRR.Label]: Game viewport is not active!");
+ return false;
+ }
+ }
+
let tempPosition = position;
tempPosition.z = tempPosition.z + propertyLabelHeight;
- let screenPosition = getScreenFromWorldPosition(tempPosition);
+ let screenPosition = new Vec3(0.0, 0.0, 0.0);
+ if(getGame() == VRR_GAME_GTA_IV) {
+ screenPosition = natives.getViewportPositionOfCoord(tempPosition, natives.getGameViewportId());
+ } else {
+ screenPosition = getScreenFromWorldPosition(tempPosition);
+ }
if(screenPosition.x < 0 || screenPosition.x > game.width) {
return false;
@@ -222,15 +278,15 @@ function renderJobLabel(name, position, jobType) {
let text = "";
if(jobType == localPlayerJobType) {
if(localPlayerWorking) {
- text = "Use /uniform and /equip for job stuff, or /stopwork to go off duty";
+ text = getLocaleString("JobEquipAndUniformLabel", "/equip", "/uniform", "/stopwork");
} else {
- text = "Use /startwork to go on duty";
+ text = getLocaleString("StartWorkLabel", "/startwork");
}
} else {
if(localPlayerJobType == 0) {
- text = "Use /takejob to work here";
+ text = getLocaleString("TakeJobLabel", "/takejob");
} else {
- text = "You already have a job. Use /quitjob if you want this one";
+ text = getLocaleString("NotYourJobLabel", "/quitjob");
}
}
@@ -239,7 +295,7 @@ function renderJobLabel(name, position, jobType) {
screenPosition.y -= 18;
- text = name + " Job";
+ text = getLocaleString("JobLabel", name);
size = jobNameLabelFont.measure(text, game.width, 0.0, 0.0, jobNameLabelFont.size, true, true);
jobNameLabelFont.render(text, [screenPosition.x-size[0]/2, screenPosition.y-size[1]/2], game.width, 0.0, 0.0, jobNameLabelFont.size, COLOUR_WHITE, false, true, false, true);
}
@@ -247,17 +303,34 @@ function renderJobLabel(name, position, jobType) {
// -------------------------------------------------------------------------
function processLabelRendering() {
- if(renderLabels && areWorldLabelsSupported()) {
- if(localPlayer != null) {
- if(!areServerElementsSupported()) {
- //for(let i in businesses) {
- // if(pickups[i].getData("vrr.label.type") != null) {
- // if(getDistance(localPlayer.position, pickups[i].position) <= renderLabelDistance) {
+ if(renderLabels) {
+ if(!areServerElementsSupported()) {
+ if(localPlayer != null) {
+ getServerData().businesses.forEach((business) => {
+ if(getDistance(localPlayer.position, business.entrancePosition) <= 75.0) {
+ natives.drawColouredCylinder(getPosBelowPos(business.entrancePosition, 1.0), 0.0, 0.0, 0, 153, 255, 255);
+ //renderPropertyEntranceLabel(business.name, business.entrancePosition, business.locked, true, makeLargeNumberReadable(business.price), makeLargeNumberReadable(business.rentPrice), business.labelInfoType);
+ }
+ });
- // natives.getScreenViewportId
- // natives.getGameViewportId
- // natives.getViewportPositionOfCoord
- } else {
+ getServerData().houses.forEach((house) => {
+ if(getDistance(localPlayer.position, house.entrancePosition) <= 75.0) {
+ natives.drawColouredCylinder(getPosBelowPos(house.entrancePosition, 1.0), 0.0, 0.0, 0, 200, 0, 255);
+ //renderPropertyEntranceLabel("House", house.entrancePosition, house.locked, true, makeLargeNumberReadable(house.price), makeLargeNumberReadable(house.rentPrice), 0);
+ }
+ });
+
+ getServerData().jobs.forEach((job) => {
+ if(getDistance(localPlayer.position, job.position) <= 75.0) {
+ natives.drawColouredCylinder(getPosBelowPos(job.position, 1.0), 0.0, 0.0, 255, 255, 0, 255);
+ //renderJobLabel(job.name, job.position, job.jobType);
+ }
+ });
+ }
+ }
+
+ if(areWorldLabelsSupported()) {
+ if(localPlayer != null) {
let pickups = getElementsByType(ELEMENT_PICKUP);
for(let i in pickups) {
if(pickups[i].getData("vrr.label.type") != null) {
@@ -279,21 +352,25 @@ function processLabelRendering() {
}
switch(pickups[i].getData("vrr.label.type")) {
- case VRR_LABEL_BUSINESS:
+ case VRR_LABEL_BUSINESS: {
renderPropertyEntranceLabel(pickups[i].getData("vrr.label.name"), pickups[i].position, pickups[i].getData("vrr.label.locked"), true, price, rentPrice, labelInfoType);
break;
+ }
- case VRR_LABEL_HOUSE:
- renderPropertyEntranceLabel("House", pickups[i].position, pickups[i].getData("vrr.label.locked"), false, price, rentPrice, labelInfoType);
+ case VRR_LABEL_HOUSE: {
+ renderPropertyEntranceLabel(pickups[i].getData("vrr.label.name"), pickups[i].position, pickups[i].getData("vrr.label.locked"), false, price, rentPrice, labelInfoType);
break;
+ }
- case VRR_LABEL_JOB:
+ case VRR_LABEL_JOB: {
renderJobLabel(pickups[i].getData("vrr.label.name"), pickups[i].position, pickups[i].getData("vrr.label.jobType"));
break;
+ }
- case VRR_LABEL_EXIT:
+ case VRR_LABEL_EXIT: {
renderPropertyExitLabel(pickups[i].position);
break;
+ }
}
}
}
diff --git a/scripts/client/locale.js b/scripts/client/locale.js
index 53eb182a..f8218340 100644
--- a/scripts/client/locale.js
+++ b/scripts/client/locale.js
@@ -8,11 +8,15 @@
// ===========================================================================
function getLocaleString(stringName, ...args) {
- if(typeof getServerData().localeStrings[stringName] == undefined) {
+ if(typeof getServerData().localeStrings[localLocaleId][stringName] == undefined) {
return "";
}
- let tempString = getServerData().localeStrings[stringName];
+ let tempString = getServerData().localeStrings[localLocaleId][stringName];
+
+ if(tempString == "" || tempString == null || tempString == undefined) {
+ return "";
+ }
for(let i = 1; i <= args.length; i++) {
tempString = tempString.replace(`{${i}}`, args[i-1]);
@@ -23,9 +27,36 @@ function getLocaleString(stringName, ...args) {
// ===========================================================================
-function receiveLocaleStringFromServer(stringName, stringValue) {
- logToConsole(LOG_INFO, `[VRR.Locale]: Received locale string "${stringName}" from server (${stringValue})`);
- getServerData().localeStrings[stringName] = stringValue;
+function getAvailableLocaleOptions() {
+ return getServerData().localeOptions.filter(localeOption => localeOption.requiresUnicode == false);
+}
+
+// ===========================================================================
+
+function loadLocaleConfig() {
+ let configFile = loadTextFile("config/client/locale.json");
+ getServerData().localeOptions = JSON.parse(configFile);
+}
+
+// ===========================================================================
+
+function loadAllLocaleStrings() {
+ let localeOptions = getServerData().localeOptions;
+ for(let i in localeOptions) {
+ logToConsole(LOG_INFO, `[VRR.Locale] Loading locale strings for ${localeOptions[i].englishName} (${i})`);
+ let localeFile = loadTextFile(`locale/${localeOptions[i].stringsFile}`);
+ let localeData = JSON.parse(localeFile);
+
+ getServerData().localeStrings[i] = localeData;
+ }
+}
+
+// ===========================================================================
+
+function setLocale(tempLocaleId) {
+ logToConsole(LOG_DEBUG, `[VRR.Locale] Setting locale to ${tempLocaleId} (${getServerData().localeOptions[tempLocaleId].englishName})`);
+ localLocaleId = tempLocaleId;
+ resetGUIStrings();
}
// ===========================================================================
\ No newline at end of file
diff --git a/scripts/client/main.js b/scripts/client/main.js
index 7e56d8ce..7afcd3db 100644
--- a/scripts/client/main.js
+++ b/scripts/client/main.js
@@ -7,6 +7,9 @@
// TYPE: Client (JavaScript)
// ===========================================================================
+let resourceReady = false;
+let resourceStarted = false;
+
let inSphere = false;
let inVehicle = false;
let inVehicleSeat = false;
@@ -27,7 +30,7 @@ let renderHotBar = true;
let renderItemActionDelay = true;
let renderInteriorLights = true;
-let logLevel = LOG_ERROR|LOG_WARN|LOG_INFO;
+let logLevel = LOG_INFO|LOG_DEBUG|LOG_VERBOSE;
let weaponDamageEnabled = {};
let weaponDamageEvent = {};
@@ -66,11 +69,24 @@ let vehiclePurchasePosition = null;
let forceWantedLevel = 0;
+let guiSubmitKey = false;
+let guiLeftKey = false;
+let guiRightKey = false;
+let guiUpKey = false;
+let guiDownKey = false;
+
// Pre-cache all allowed skins
let allowedSkins = getAllowedSkins(getGame());
-let businesses = {};
-let houses = {};
-let jobs = {};
+let localLocaleId = 0;
-// ===========================================================================
\ No newline at end of file
+let serverData = {
+ houses: [],
+ businesses: [],
+ localeStrings: [],
+ localeOptions: [],
+ vehicles: [],
+ jobs: [],
+};
+
+// ===========================================================================
diff --git a/scripts/client/messaging.js b/scripts/client/messaging.js
index 11c17b71..1bd288c3 100644
--- a/scripts/client/messaging.js
+++ b/scripts/client/messaging.js
@@ -7,7 +7,14 @@
// TYPE: Client (JavaScript)
// ===========================================================================
-let smallGameMessageFont = null;
+let bigGameMessageFonts = {};
+let bigGameMessageFontName = "";
+let bigGameMessageText = "";
+let bigGameMessageColour = COLOUR_WHITE;
+let bigGameMessageTimer = null;
+
+let smallGameMessageFonts = {};
+let smallGameMessageFontName = "";
let smallGameMessageText = "";
let smallGameMessageColour = COLOUR_WHITE;
let smallGameMessageTimer = null;
@@ -16,43 +23,50 @@ let smallGameMessageTimer = null;
function initMessagingScript() {
logToConsole(LOG_DEBUG, "[VRR.Messaging]: Initializing messaging script ...");
- smallGameMessageFont = loadSmallGameMessageFont();
+ smallGameMessageFonts = loadSmallGameMessageFonts();
+ bigGameMessageFonts = loadSmallGameMessageFonts();
logToConsole(LOG_DEBUG, "[VRR.Messaging]: Messaging script initialized!");
}
// ===========================================================================
-function loadSmallGameMessageFont() {
- let tempSmallGameMessageFont = null;
+function loadSmallGameMessageFonts() {
+ let tempSmallGameMessageFonts = {};
let fontStream = openFile("files/fonts/pricedown.ttf");
if(fontStream != null) {
- tempSmallGameMessageFont = lucasFont.createFont(fontStream, 20.0);
+ tempSmallGameMessageFonts["Pricedown"] = lucasFont.createFont(fontStream, 20.0);
fontStream.close();
}
- return tempSmallGameMessageFont;
+ tempSmallGameMessageFonts["Roboto"] = lucasFont.createDefaultFont(20.0, "Roboto");
+ tempSmallGameMessageFonts["RobotoLight"] = lucasFont.createDefaultFont(20.0, "Roboto", "Light");
+
+ return tempSmallGameMessageFonts;
}
// ===========================================================================
function loadBigGameMessageFont() {
- let tempBigGameMessageFont = null;
+ let tempBigGameMessageFonts = {};
let fontStream = openFile("files/fonts/pricedown.ttf");
if(fontStream != null) {
- tempBigGameMessageFont = lucasFont.createFont(fontStream, 28.0);
+ tempBigGameMessageFonts["Pricedown"] = lucasFont.createFont(fontStream, 28.0);
fontStream.close();
}
- return tempBigGameMessageFont;
+ tempBigGameMessageFonts["Roboto"] = lucasFont.createDefaultFont(28.0, "Roboto");
+ tempBigGameMessageFonts["RobotoLight"] = lucasFont.createDefaultFont(28.0, "Roboto", "Light");
+
+ return tempBigGameMessageFonts;
}
// ===========================================================================
function processSmallGameMessageRendering() {
if(renderSmallGameMessage) {
- if(smallGameMessageFont != null) {
- if(smallGameMessageFont != "") {
- smallGameMessageFont.render(smallGameMessageText, [0, game.height-90], game.width, 0.5, 0.0, smallGameMessageFont.size, smallGameMessageColour, true, true, false, true);
+ if(smallGameMessageText != "") {
+ if(smallGameMessageFonts[smallGameMessageFontName] != null) {
+ smallGameMessageFonts[smallGameMessageFontName].render(smallGameMessageText, [0, game.height-90], game.width, 0.5, 0.0, smallGameMessageFonts[smallGameMessageFontName].size, smallGameMessageColour, true, true, false, true);
}
}
}
@@ -60,12 +74,13 @@ function processSmallGameMessageRendering() {
// ===========================================================================
-function showSmallGameMessage(text, colour, duration) {
- logToConsole(LOG_DEBUG, `[VRR.Messaging] Showing small game message '${text}' for ${duration}ms`);
+function showSmallGameMessage(text, colour, duration, fontName) {
+ logToConsole(LOG_DEBUG, `[VRR.Messaging] Showing small game message '${text}' using font ${fontName} for ${duration}ms`);
if(smallGameMessageText != "") {
clearTimeout(smallGameMessageTimer);
}
+ smallGameMessageFontName = fontName;
smallGameMessageColour = colour;
smallGameMessageText = text;
@@ -73,6 +88,7 @@ function showSmallGameMessage(text, colour, duration) {
smallGameMessageText = "";
smallGameMessageColour = COLOUR_WHITE;
smallGameMessageTimer = null;
+ smallGameMessageFontName = "";
}, duration);
}
diff --git a/scripts/client/mousecam.js b/scripts/client/mousecam.js
index cd4bfd7b..08889376 100644
--- a/scripts/client/mousecam.js
+++ b/scripts/client/mousecam.js
@@ -20,7 +20,7 @@ function SetStandardControlsEnabled(bEnabled)
if (game.standardControls === undefined)
{
- console.warn("game.standardControls not implemented");
+ logToConsole(LOG_WARN, "game.standardControls not implemented");
return;
}
game.standardControls = bEnabled;
@@ -93,7 +93,7 @@ function GetMouseSensitivity()
{
if (game.getMouseSensitivity === undefined)
{
- //console.error("game.getMouseSensitivity not implemented");
+ //logToConsole(LOG_ERROR, "game.getMouseSensitivity not implemented");
return [0.0025,0.003];
}
let MouseSensitivity = game.getMouseSensitivity();
@@ -124,7 +124,7 @@ function ProcessLineOfSight(vecStartX, vecStartY, vecStartZ, vecEndX, vecEndY, v
{
if (game.processLineOfSight === undefined)
{
- console.warn("game.processLineOfSight not implemented");
+ logToConsole(LOG_WARN, "game.processLineOfSight not implemented");
return [null];
}
let Result = game.processLineOfSight([vecStartX, vecStartY, vecStartZ], [vecEndX, vecEndY, vecEndZ], bCheckBuildings, bCheckVehicles, bCheckPeds, bCheckObjects, bCheckDummies, bCheckSeeThroughStuff, bIgnoreSomeObjectsForCamera);
@@ -632,10 +632,10 @@ function update()
addEventHandler("OnCameraProcess", (event) =>
{
- if(mouseCameraEnabled) {
- update();
- event.preventDefault();
- }
+ if(mouseCameraEnabled) {
+ update();
+ event.preventDefault();
+ }
});
function toggleMouseCamera() {
diff --git a/scripts/client/nametag.js b/scripts/client/nametag.js
index 7009f884..699b9bc6 100644
--- a/scripts/client/nametag.js
+++ b/scripts/client/nametag.js
@@ -48,11 +48,11 @@ function updatePlayerNameTag(clientName, characterName, colour, paused, ping) {
playerPaused[clientName] = paused;
playerPing[clientName] = ping;
- if(game.game == VRR_GAME_GTA_IV) {
+ if(getGame() == VRR_GAME_GTA_IV) {
let client = getPlayerFromParams(clientName);
if(client != false) {
- if(client.player != null) {
- client.player.setNametag(characterName, colour);
+ if(getPlayerPed(client) != null) {
+ getPlayerPed(client).setNametag(characterName, colour);
}
}
}
@@ -74,14 +74,14 @@ function drawNametag(x, y, health, armour, text, ping, alpha, distance, colour,
alpha *= 0.75;
let width = nametagWidth;
health = Math.max(0.0, Math.min(1.0, health));
- armour = Math.max(0.0, Math.min(1.0, armour));
+ armour = Math.max(0.0, Math.min(1.0, armour));
- // Starts at bottom and works it's way up
- // -------------------------------------------
- // Health Bar
+ // Starts at bottom and works it's way up
+ // -------------------------------------------
+ // Health Bar
if(getMultiplayerMod() == VRR_MPMOD_GTAC) {
- if(game.game == VRR_GAME_GTA_III) {
+ if(getGame() == VRR_GAME_GTA_III) {
// Mickey Hamfists is ridiculously tall. Raise the nametag for him a bit
if(skin == 109) {
y -= 20;
@@ -104,7 +104,7 @@ function drawNametag(x, y, health, armour, text, ping, alpha, distance, colour,
graphics.drawRectangle(null, [hx+2, hy+2], [(width-4)*health, 10-6], colour, colour, colour, colour);
}
- // Armour Bar
+ // Armour Bar
if (armour > 0.0)
{
// Go up 10 pixels to draw the next part
@@ -119,16 +119,16 @@ function drawNametag(x, y, health, armour, text, ping, alpha, distance, colour,
y -= 20;
- // Nametag
+ // Nametag
if(nametagFont != null) {
let size = nametagFont.measure(text, game.width, 0.0, 0.0, nametagFont.size, false, false);
nametagFont.render(text, [x-size[0]/2, y-size[1]/2], game.width, 0.0, 0.0, nametagFont.size, colour, false, false, false, true);
}
- // Go up another 10 pixels for the next part
- y -= 20;
+ // Go up another 10 pixels for the next part
+ y -= 20;
- // AFK Status
+ // AFK Status
if(afkStatusFont != null) {
if(afk) {
let size = afkStatusFont.measure("PAUSED", game.width, 0.0, 0.0, afkStatusFont.size, false, false);
@@ -139,7 +139,7 @@ function drawNametag(x, y, health, armour, text, ping, alpha, distance, colour,
// ===========================================================================
-function updateNametags(element) {
+function updateNametag(element) {
if(!areWorldLabelsSupported()) {
return false;
}
@@ -147,10 +147,11 @@ function updateNametags(element) {
if(localPlayer != null) {
let playerPos = localPlayer.position;
let elementPos = element.position;
- let client = getClientFromPlayerElement(element);
elementPos[2] += 0.9;
+ //if(typeof element.getComponentPosition()) {
+
let screenPos = getScreenFromWorldPosition(elementPos);
if (screenPos[2] >= 0.0) {
let health = element.health/100.0;
@@ -173,27 +174,29 @@ function updateNametags(element) {
}
if(element.type == ELEMENT_PLAYER) {
- let name = element.name;
- let colour = COLOUR_WHITE;
+ let name = element.name;
+ let colour = COLOUR_WHITE;
let paused = false;
let ping = -1;
- if(typeof playerNames[element.name] != "undefined") {
- name = playerNames[element.name];
- }
+ if(element.isType(ELEMENT_PLAYER)) {
+ if(typeof playerNames[element.name] != "undefined") {
+ name = playerNames[element.name];
+ }
- if(typeof playerPaused[element.name] != "undefined") {
- paused = playerPaused[element.name];
- }
+ if(typeof playerPaused[element.name] != "undefined") {
+ paused = playerPaused[element.name];
+ }
- if(typeof playerColours[element.name] != "undefined") {
- colour = playerColours[element.name];
+ if(typeof playerColours[element.name] != "undefined") {
+ colour = playerColours[element.name];
+ }
+
+ if(typeof playerPing[element.name] != "undefined") {
+ ping = playerPing[element.name];
+ }
}
- if(typeof playerPing[element.name] != "undefined") {
- ping = playerPing[element.name];
- }
-
drawNametag(screenPos[0], screenPos[1], health, armour, name, ping, 1.0-distance/nametagDistance, distance, colour, paused, element.skin);
}
}
@@ -205,7 +208,7 @@ function updateNametags(element) {
function getClientFromPlayer(player) {
getClients().forEach(function(client) {
- if(client.player == player) {
+ if(getPlayerPed(client) == player) {
return client;
}
});
@@ -214,13 +217,13 @@ function getClientFromPlayer(player) {
// ===========================================================================
function processNameTagRendering(event) {
- //if(game.game >= GAME_GTA_IV) {
+ //if(getGame() >= GAME_GTA_IV) {
// return false;
//}
- getElementsByType(ELEMENT_PLAYER).forEach(function(player) {
- if(player != localPlayer) {
- updateNametags(player);
+ getElementsByType(ELEMENT_PED).forEach(function(ped) {
+ if(ped != localPlayer) {
+ updateNametag(ped);
}
});
}
@@ -231,4 +234,10 @@ function createColour(alpha, red, green, blue) {
return alpha << 24 | red << 16 | green << 8 | blue;
}
+// ===========================================================================
+
+function setNameTagDistance(distance) {
+ nametagDistance = distance;
+}
+
// ===========================================================================
\ No newline at end of file
diff --git a/scripts/client/native/connected.js b/scripts/client/native/connected.js
index f0b41426..1cea7b56 100644
--- a/scripts/client/native/connected.js
+++ b/scripts/client/native/connected.js
@@ -7,58 +7,89 @@
// TYPE: Server (JavaScript)
// ===========================================================================
+let disconnectReasons = [
+ "Lost Connection",
+ "Disconnected",
+ "Unsupported Client",
+ "Wrong Game",
+ "Incorrect Password",
+ "Unsupported Executable",
+ "Disconnected",
+ "Banned",
+ "Failed",
+ "Invalid Name",
+ "Crashed",
+ "Modified Game"
+];
+
+// ===========================================================================
+
function sendNetworkEventToPlayer(networkEvent, client, ...args) {
- triggerNetworkEvent.apply(null, networkEvent, client, args);
+ triggerNetworkEvent.apply(null, networkEvent, client, args);
}
// ===========================================================================
function getPlayerPosition() {
- return localPlayer.position;
+ return localPlayer.position;
}
// ===========================================================================
function setPlayerPosition(position) {
- localPlayer.position = position;
+ if(getGame() == VRR_GAME_GTA_IV) {
+ natives.setCharCoordinates(localPlayer, position);
+ } else {
+ localPlayer.position = position;
+ }
}
// ===========================================================================
-function getElementPosition(element) {
- return element.position;
+function getElementPosition(elementId) {
+ return getElementFromId(elementId).position;
}
// ===========================================================================
-function setElementPosition(element, position) {
- if(!element.isSyncer) {
- return false;
- }
-
- element.position = position;
+function getElementHeading(elementId) {
+ return getElementFromId(elementId).heading;
}
// ===========================================================================
-function deleteGameElement(element, position) {
- if(!element.isOwner) {
- return false;
- }
+function setElementPosition(elementId, position) {
+ if(getElementFromId(elementId) == null) {
+ return false;
+ }
- destroyGameElement(element);
+ if(!getElementFromId(elementId).isSyncer) {
+ return false;
+ }
+
+ getElementFromId(elementId).position = position;
+}
+
+// ===========================================================================
+
+function deleteGameElement(elementId, position) {
+ if(!getElementFromId(elementId).isOwner) {
+ return false;
+ }
+
+ destroyGameElement(getElementFromId(elementId));
}
// ===========================================================================
function createGameVehicle(modelIndex, position, heading) {
- return game.createVehicle(getGameConfig().vehicles[getGame()][modelIndex][0], position, heading);
+ return game.createVehicle(getGameConfig().vehicles[getGame()][modelIndex][0], position, heading);
}
// ===========================================================================
function addNetworkEventHandler(eventName, handlerFunction) {
- addNetworkHandler(eventName, handlerFunction);
+ addNetworkHandler(eventName, handlerFunction);
}
// ===========================================================================
@@ -101,7 +132,7 @@ function getClientsInRange(position, distance) {
// ===========================================================================
function getCiviliansInRange(position, distance) {
- return getElementsByType(ELEMENT_PED).filter(x => !x.isType(ELEMENT_PLAYER) && getElementPosition(x).position.distance(position) <= distance);
+ return getElementsByType(ELEMENT_PED).filter(x => !x.isType(ELEMENT_PLAYER) && x.position.distance(position) <= distance);
}
// ===========================================================================
@@ -113,7 +144,7 @@ function getPlayersInRange(position, distance) {
// ===========================================================================
function getElementsByTypeInRange(elementType, position, distance) {
- return getElementsByType(elementType).filter(x => getElementPosition(x).position.distance(position) <= distance);
+ return getElementsByType(elementType).filter(x => x.position.distance(position) <= distance);
}
// ===========================================================================
@@ -124,6 +155,12 @@ function getClosestCivilian(position) {
// ===========================================================================
+function getClosestPlayer(position) {
+ return getElementsByType(ELEMENT_PLAYER).reduce((i, j) => ((i.position.distance(position) <= j.position.distance(position)) ? i : j));
+}
+
+// ===========================================================================
+
function is2dPositionOnScreen(pos2d) {
return pos2d.x >= 0 && pos2d.y >= 0 && pos2d.x <= game.width && pos2d.y <= game.height;
}
@@ -143,6 +180,31 @@ function getVehiclesInRange(position, range) {
// ===========================================================================
+function createGameBlip(blipModel, position, name = "") {
+ if(getGame() == VRR_GAME_GTA_IV) {
+ let blipId = natives.addBlipForCoord(position);
+ if(blipId) {
+ natives.changeBlipSprite(blipId, blipModel);
+ natives.setBlipMarkerLongDistance(blipId, false);
+ natives.setBlipAsShortRange(blipId, true);
+ natives.changeBlipNameFromAscii(blipId, `${name.substr(0, 24)}${(name.length > 24) ? " ...": ""}`);
+ return blipId;
+ }
+ }
+
+ return -1;
+}
+
+// ===========================================================================
+
+function setEntityData(entity, dataName, dataValue, syncToClients = true) {
+ if(entity != null) {
+ return entity.setData(dataName, dataValue);
+ }
+}
+
+// ===========================================================================
+
function setVehicleEngine(vehicleId, state) {
getElementFromId(vehicleId).engine = state;
}
@@ -150,19 +212,7 @@ function setVehicleEngine(vehicleId, state) {
// ===========================================================================
function setVehicleLights(vehicleId, state) {
- if(getGame() != VRR_GAME_MAFIA_ONE) {
- if(!state) {
- getElementFromId(vehicleId).lightStatus = 2;
- } else {
- getElementFromId(vehicleId).lightStatus = 1;
- }
- } else {
- if(!state) {
- getElementFromId(vehicleId).lights = false;
- } else {
- getElementFromId(vehicleId).lights = true;
- }
- }
+ getElementFromId(vehicleId).lights = state;
}
// ===========================================================================
@@ -176,11 +226,7 @@ function repairVehicle(syncId) {
function syncVehicleProperties(vehicle) {
if(doesEntityDataExist(vehicle, "vrr.lights")) {
let lightStatus = getEntityData(vehicle, "vrr.lights");
- if(!lightStatus) {
- vehicle.lightStatus = 2;
- } else {
- vehicle.lightStatus = 1;
- }
+ vehicle.lights = lightStatus;
}
if(doesEntityDataExist(vehicle, "vrr.invincible")) {
@@ -244,6 +290,24 @@ function syncVehicleProperties(vehicle) {
// ===========================================================================
+function removeEntityData(entity, dataName) {
+ if(entity != null) {
+ return entity.removeData(dataName);
+ }
+ return null;
+}
+
+// ===========================================================================
+
+function doesEntityDataExist(entity, dataName) {
+ if(entity != null) {
+ return (entity.getData(dataName) != null);
+ }
+ return null;
+}
+
+// ===========================================================================
+
function syncCivilianProperties(civilian) {
if(getGame() == VRR_GAME_GTA_III) {
if(doesEntityDataExist(civilian, "vrr.scale")) {
@@ -336,6 +400,12 @@ function syncCivilianProperties(civilian) {
// ===========================================================================
+function preventDefaultEventAction(event) {
+ event.preventDefault();
+}
+
+// ===========================================================================
+
function syncPlayerProperties(player) {
if(getGame() == VRR_GAME_GTA_III) {
if(doesEntityDataExist(player, "vrr.scale")) {
@@ -461,6 +531,42 @@ function syncObjectProperties(object) {
// ===========================================================================
+function consolePrint(text) {
+ console.log(text);
+}
+
+// ===========================================================================
+
+function consoleWarn(text) {
+ console.warn(text);
+}
+
+// ===========================================================================
+
+function consoleError(text) {
+ console.error(text);
+}
+
+// ===========================================================================
+
+function getPlayerName(client) {
+ return client.name;
+}
+
+// ===========================================================================
+
+function getGame() {
+ return game.game;
+}
+
+// ===========================================================================
+
+function getPlayerId(client) {
+ return client.index;
+}
+
+// ===========================================================================
+
function syncElementProperties(element) {
if(doesEntityDataExist(element, "vrr.interior")) {
if(typeof element.interior != "undefined") {
@@ -490,4 +596,105 @@ function syncElementProperties(element) {
}
}
+// ===========================================================================
+
+function getPlayerPed(client) {
+ return client.player;
+}
+
+// ===========================================================================
+
+function getScreenWidth() {
+ return game.width;
+}
+
+// ===========================================================================
+
+function getScreenHeight() {
+ return game.height;
+}
+
+// ===========================================================================
+
+// ===========================================================================
+
+function openAllGarages() {
+ switch(getGame()) {
+ case VRR_GAME_GTA_III:
+ for(let i=0;i<=26;i++) {
+ openGarage(i);
+ game.NO_SPECIAL_CAMERA_FOR_THIS_GARAGE(i);
+ }
+ break;
+
+ case VRR_GAME_GTA_VC:
+ for(let i=0;i<=32;i++) {
+ openGarage(i);
+ game.NO_SPECIAL_CAMERA_FOR_THIS_GARAGE(i);
+ }
+ break;
+
+ case VRR_GAME_GTA_SA:
+ for(let i=0;i<=44;i++) {
+ openGarage(i);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+// ===========================================================================
+
+function closeAllGarages() {
+ switch(getGame()) {
+ case VRR_GAME_GTA_III:
+ for(let i=0;i<=26;i++) {
+ closeGarage(i);
+ game.NO_SPECIAL_CAMERA_FOR_THIS_GARAGE(i);
+ }
+ break;
+
+ case VRR_GAME_GTA_VC:
+ for(let i=0;i<=32;i++) {
+ closeGarage(i);
+ game.NO_SPECIAL_CAMERA_FOR_THIS_GARAGE(i);
+ }
+ break;
+
+ case VRR_GAME_GTA_SA:
+ for(let i=0;i<=44;i++) {
+ closeGarage(i);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+// ===========================================================================
+
+function setPedInvincible(ped, state) {
+ ped.invincible = state;
+}
+
+// ===========================================================================
+
+function setPedLookAt(ped, position) {
+ if(getGame() == VRR_GAME_GTA_SA) {
+ ped.lookAt(position, 10000);
+ return true;
+ } else {
+ setElementHeading(ped.id, getHeadingFromPosToPos(getElementPosition(ped.id), position));
+ }
+}
+
+// ===========================================================================
+
+function setElementHeading(elementId, heading) {
+ getElementFromId(elementId).heading = heading;
+}
+
// ===========================================================================
\ No newline at end of file
diff --git a/scripts/client/npc.js b/scripts/client/npc.js
new file mode 100644
index 00000000..5d823bf6
--- /dev/null
+++ b/scripts/client/npc.js
@@ -0,0 +1,19 @@
+// ===========================================================================
+// Vortrex's Roleplay Resource
+// https://github.com/VortrexFTW/gtac_roleplay
+// ===========================================================================
+// FILE: npc.js
+// DESC: Provides NPC functions and processing
+// TYPE: Client (JavaScript)
+// ===========================================================================
+
+function processNPCMovement(npc) {
+ //if(npc.isSyncer == true) {
+ if(getEntityData(npc, "vrr.lookAtClosestPlayer") == true) {
+ let closestPlayer = getClosestPlayer(getElementPosition(npc.id));
+ setPedLookAt(npc, getElementPosition(closestPlayer.id));
+ }
+ //}
+}
+
+// ===========================================================================
\ No newline at end of file
diff --git a/scripts/client/radio.js b/scripts/client/radio.js
index a9ea993d..7cb04ae5 100644
--- a/scripts/client/radio.js
+++ b/scripts/client/radio.js
@@ -40,7 +40,7 @@ function setStreamingRadioVolume(volume) {
// ===========================================================================
function playAudioFile(audioName, loop, volume) {
- playCustomAudio(audioName, volume/100, loop);
+ findResourceByName("connectedrp-extra").exports.playCustomAudio(audioName, volume/100, loop);
}
// ===========================================================================
\ No newline at end of file
diff --git a/scripts/client/scoreboard.js b/scripts/client/scoreboard.js
index 5007d78b..04dd9630 100644
--- a/scripts/client/scoreboard.js
+++ b/scripts/client/scoreboard.js
@@ -43,7 +43,7 @@ function processScoreBoardRendering() {
}
if(renderScoreBoard) {
- if(isKeyDown(SDLK_TAB)) {
+ if(isKeyDown(SDLK_TAB)) {
if(scoreBoardListFont != null && scoreBoardTitleFont != null) {
let scoreboardStart = (game.height/2)-(Math.floor(getClients().length/2)*20);
let titleSize = scoreBoardTitleFont.measure("PLAYERS", game.width, 0.0, 1.0, 10, false, false);
diff --git a/scripts/client/server.js b/scripts/client/server.js
index 0c13d4dc..41bf72d6 100644
--- a/scripts/client/server.js
+++ b/scripts/client/server.js
@@ -18,95 +18,137 @@ function initServerScript() {
function addAllNetworkHandlers() {
logToConsole(LOG_DEBUG, "[VRR.Server]: Adding network handlers ...");
+ // Chat history
+ addNetworkEventHandler("m", receiveChatBoxMessageFromServer); // Not prefixed with VRR to make it as small as possible
+ addNetworkEventHandler("vrr.chatScrollLines", setChatScrollLines);
+ addNetworkEventHandler("vrr.chatAutoHideDelay", setChatAutoHideDelay);
+
+ // Messaging (like textdraws and stuff)
addNetworkEventHandler("vrr.smallGameMessage", showSmallGameMessage);
+
+ // Job
+ addNetworkEventHandler("vrr.job", receiveJobFromServer);
addNetworkEventHandler("vrr.working", setLocalPlayerWorkingState);
addNetworkEventHandler("vrr.jobType", setLocalPlayerJobType);
- addNetworkEventHandler("vrr.passenger", enterVehicleAsPassenger);
+ addNetworkEventHandler("vrr.showJobRouteLocation", showJobRouteLocation);
+ addNetworkEventHandler("vrr.hideJobRouteLocation", hideJobRouteLocation);
+ // Local player states and values
+ addNetworkEventHandler("vrr.restoreCamera", restoreLocalCamera);
+ addNetworkEventHandler("vrr.cameraLookAt", setLocalCameraLookAt);
addNetworkEventHandler("vrr.freeze", setLocalPlayerFrozenState);
addNetworkEventHandler("vrr.control", setLocalPlayerControlState);
addNetworkEventHandler("vrr.fadeCamera", fadeLocalCamera);
addNetworkEventHandler("vrr.removeFromVehicle", removeLocalPlayerFromVehicle);
- addNetworkEventHandler("vrr.clearPeds", clearLocalPlayerOwnedPeds);
- addNetworkEventHandler("vrr.restoreCamera", restoreLocalCamera);
- addNetworkEventHandler("vrr.cameraLookAt", setLocalCameraLookAt);
- addNetworkEventHandler("vrr.logo", setServerLogoRenderState);
- addNetworkEventHandler("vrr.ambience", setCityAmbienceState);
- addNetworkEventHandler("vrr.runCode", runClientCode);
addNetworkEventHandler("vrr.clearWeapons", clearLocalPlayerWeapons);
addNetworkEventHandler("vrr.giveWeapon", giveLocalPlayerWeapon);
addNetworkEventHandler("vrr.position", setLocalPlayerPosition);
addNetworkEventHandler("vrr.heading", setLocalPlayerHeading);
addNetworkEventHandler("vrr.interior", setLocalPlayerInterior);
- addNetworkEventHandler("vrr.minuteDuration", setMinuteDuration);
- addNetworkEventHandler("vrr.showJobRouteLocation", showJobRouteLocation);
- addNetworkEventHandler("vrr.hideJobRouteLocation", hideJobRouteLocation);
- addNetworkEventHandler("vrr.snow", setSnowState);
- addNetworkEventHandler("vrr.health", setLocalPlayerHealth);
- addNetworkEventHandler("vrr.enterPropertyKey", setEnterPropertyKey);
- addNetworkEventHandler("vrr.skinSelect", toggleSkinSelect);
- addNetworkEventHandler("vrr.hotbar", updatePlayerHotBar);
- addNetworkEventHandler("vrr.pedSpeech", playPedSpeech);
- addNetworkEventHandler("vrr.clearPedState", clearLocalPedState);
- addNetworkEventHandler("vrr.drunkEffect", setLocalPlayerDrunkEffect);
- addNetworkEventHandler("vrr.showItemActionDelay", showItemActionDelay);
- addNetworkEventHandler("vrr.set2DRendering", setPlayer2DRendering);
- addNetworkEventHandler("vrr.mouseCursor", toggleMouseCursor);
- addNetworkEventHandler("vrr.mouseCamera", toggleMouseCamera);
- addNetworkEventHandler("vrr.mouseCameraForce", setMouseCameraState);
- addNetworkEventHandler("vrr.weaponDamageEnabled", setPlayerWeaponDamageEnabled);
- addNetworkEventHandler("vrr.weaponDamageEvent", setPlayerWeaponDamageEvent);
- addNetworkEventHandler("vrr.spawned", onServerSpawnedPlayer);
+ addNetworkEventHandler("vrr.spawned", onServerSpawnedLocalPlayer);
addNetworkEventHandler("vrr.money", setLocalPlayerCash);
addNetworkEventHandler("vrr.armour", setLocalPlayerArmour);
- addNetworkEventHandler("vrr.wantedLevel", forceLocalPlayerWantedLevel);
+ addNetworkEventHandler("vrr.localPlayerSkin", setLocalPlayerSkin);
+ addNetworkEventHandler("vrr.pedSpeak", makeLocalPlayerPedSpeak);
+ addNetworkEventHandler("vrr.infiniteRun", setLocalPlayerInfiniteRun);
+ addNetworkEventHandler("vrr.playerCop", setLocalPlayerAsCopState);
+ addNetworkEventHandler("vrr.health", setLocalPlayerHealth);
+ addNetworkEventHandler("vrr.wantedLevel", setLocalPlayerWantedLevel);
+ addNetworkEventHandler("vrr.playerPedId", sendLocalPlayerNetworkIdToServer);
+ addNetworkEventHandler("vrr.ped", setLocalPlayerPedPartsAndProps);
+ addNetworkEventHandler("vrr.spawn", serverRequestedLocalPlayerSpawn);
+ addNetworkEventHandler("vrr.clearPedState", clearLocalPedState);
+ addNetworkEventHandler("vrr.drunkEffect", setLocalPlayerDrunkEffect);
- addNetworkEventHandler("vrr.delKeyBind", unBindAccountKey);
- addNetworkEventHandler("vrr.addKeyBind", bindAccountKey);
- addNetworkEventHandler("vrr.clearKeyBinds", clearKeyBinds);
-
- addNetworkEventHandler("vrr.nametag", updatePlayerNameTag);
- addNetworkEventHandler("vrr.ping", updatePlayerPing);
-
- addNetworkEventHandler("vrr.m", receiveChatBoxMessageFromServer);
- addNetworkEventHandler("vrr.chatScrollLines", setChatScrollLines);
+ // Vehicle
+ addNetworkEventHandler("vrr.vehicle", receiveVehicleFromServer);
+ addNetworkEventHandler("vrr.veh.lights", setVehicleLights);
+ addNetworkEventHandler("vrr.veh.engine", setVehicleEngine);
+ addNetworkEventHandler("vrr.veh.repair", repairVehicle);
+ // Radio
addNetworkEventHandler("vrr.radioStream", playStreamingRadio);
addNetworkEventHandler("vrr.audioFileStream", playAudioFile);
addNetworkEventHandler("vrr.stopRadioStream", stopStreamingRadio);
addNetworkEventHandler("vrr.radioVolume", setStreamingRadioVolume);
- addNetworkEventHandler("vrr.veh.lights", setVehicleLights);
- addNetworkEventHandler("vrr.veh.engine", setVehicleEngine);
- addNetworkEventHandler("vrr.veh.repair", repairVehicle);
+ // Key Bindings
+ addNetworkEventHandler("vrr.delKeyBind", unBindAccountKey);
+ addNetworkEventHandler("vrr.addKeyBind", bindAccountKey);
+ addNetworkEventHandler("vrr.clearKeyBinds", clearKeyBinds);
- addNetworkEventHandler("vrr.pedAnim", makePedPlayAnimation);
- addNetworkEventHandler("vrr.pedStopAnim", makePedStopAnimation);
- addNetworkEventHandler("vrr.localPlayerSkin", setLocalPlayerSkin);
- addNetworkEventHandler("vrr.forcePedAnim", forcePedAnimation);
- addNetworkEventHandler("vrr.hideAllGUI", hideAllGUI);
- addNetworkEventHandler("vrr.clientInfo", serverRequestedClientInfo);
- addNetworkEventHandler("vrr.interiorLights", updateInteriorLightsState);
-
- addNetworkEventHandler("vrr.syncElement", forceSyncElementProperties);
- addNetworkEventHandler("vrr.elementPosition", setElementPosition);
- addNetworkEventHandler("vrr.elementCollisions", setElementCollisionsEnabled);
-
- addNetworkEventHandler("vrr.vehBuyState", setVehiclePurchaseState);
+ // Weapon Damage
+ addNetworkEventHandler("vrr.weaponDamageEnabled", setPlayerWeaponDamageEnabled);
+ addNetworkEventHandler("vrr.weaponDamageEvent", setPlayerWeaponDamageEvent);
+ // GUI
addNetworkEventHandler("vrr.showRegistration", showRegistrationGUI);
addNetworkEventHandler("vrr.showNewCharacter", showNewCharacterGUI);
addNetworkEventHandler("vrr.showLogin", showLoginGUI);
+ addNetworkEventHandler("vrr.2fa", showTwoFactorAuthGUI);
+ addNetworkEventHandler("vrr.showResetPasswordCodeInput", resetPasswordCodeInputGUI);
+ addNetworkEventHandler("vrr.showResetPasswordEmailInput", resetPasswordEmailInputGUI);
+ addNetworkEventHandler("vrr.showChangePassword", showChangePasswordGUI);
+ addNetworkEventHandler("vrr.showCharacterSelect", showCharacterSelectGUI);
+ addNetworkEventHandler("vrr.switchCharacterSelect", switchCharacterSelectGUI);
+ addNetworkEventHandler("vrr.showError", showErrorGUI);
+ addNetworkEventHandler("vrr.showInfo", showInfoGUI);
+ addNetworkEventHandler("vrr.showPrompt", showYesNoPromptGUI);
+ addNetworkEventHandler("vrr.loginSuccess", loginSuccess);
+ addNetworkEventHandler("vrr.characterSelectSuccess", characterSelectSuccess);
+ addNetworkEventHandler("vrr.loginFailed", loginFailed);
+ addNetworkEventHandler("vrr.registrationSuccess", registrationSuccess);
+ addNetworkEventHandler("vrr.registrationFailed", registrationFailed);
+ addNetworkEventHandler("vrr.newCharacterFailed", newCharacterFailed);
+ addNetworkEventHandler("vrr.changePassword", showChangePasswordGUI);
+ addNetworkEventHandler("vrr.showLocaleChooser", showLocaleChooserGUI);
+ addNetworkEventHandler("vrr.guiColour", setGUIColours);
- addNetworkEventHandler("vrr.logLevel", setLogLevel);
- addNetworkEventHandler("vrr.infiniteRun", setLocalPlayerInfiniteRun);
-
+ // Business
addNetworkEventHandler("vrr.business", receiveBusinessFromServer);
+
+ // House
addNetworkEventHandler("vrr.house", receiveHouseFromServer);
- addNetworkEventHandler("vrr.holdObject", makePedHoldObject);
+ // GPS
+ addNetworkEventHandler("vrr.showGPSBlip", showGPSLocation);
- addNetworkEventHandler("vrr.playerPedId", sendLocalPlayerNetworkIdToServer);
+ // Locale
+ addNetworkEventHandler("vrr.locale", setLocale);
+ addNetworkEventHandler("vrr.localeChooser", toggleLocaleChooserGUI);
+
+ // Misc
+ addNetworkEventHandler("vrr.mouseCursor", toggleMouseCursor);
+ addNetworkEventHandler("vrr.mouseCamera", toggleMouseCamera);
+ addNetworkEventHandler("vrr.clearPeds", clearLocalPlayerOwnedPeds);
+ addNetworkEventHandler("vrr.passenger", enterVehicleAsPassenger);
+ addNetworkEventHandler("vrr.logo", setServerLogoRenderState);
+ addNetworkEventHandler("vrr.ambience", setCityAmbienceState);
+ addNetworkEventHandler("vrr.runCode", runClientCode);
+ addNetworkEventHandler("vrr.minuteDuration", setMinuteDuration);
+ addNetworkEventHandler("vrr.snow", setSnowState);
+ addNetworkEventHandler("vrr.enterPropertyKey", setEnterPropertyKey);
+ addNetworkEventHandler("vrr.skinSelect", toggleSkinSelect);
+ addNetworkEventHandler("vrr.hotbar", updatePlayerHotBar);
+ addNetworkEventHandler("vrr.showItemActionDelay", showItemActionDelay);
+ addNetworkEventHandler("vrr.set2DRendering", set2DRendering);
+ addNetworkEventHandler("vrr.mouseCameraForce", setMouseCameraState);
+ addNetworkEventHandler("vrr.logLevel", setLogLevel);
+ addNetworkEventHandler("vrr.hideAllGUI", hideAllGUI);
+ addNetworkEventHandler("vrr.nametag", updatePlayerNameTag);
+ addNetworkEventHandler("vrr.nametagDistance", setNameTagDistance);
+ addNetworkEventHandler("vrr.ping", updatePlayerPing);
+ addNetworkEventHandler("vrr.anim", makePedPlayAnimation);
+ addNetworkEventHandler("vrr.stopAnim", makePedStopAnimation);
+ addNetworkEventHandler("vrr.forceAnim", forcePedAnimation);
+ addNetworkEventHandler("vrr.clientInfo", serverRequestedClientInfo);
+ addNetworkEventHandler("vrr.interiorLights", updateInteriorLightsState);
+ addNetworkEventHandler("vrr.cutsceneInterior", setCutsceneInterior);
+ addNetworkEventHandler("vrr.syncElement", forceSyncElementProperties);
+ addNetworkEventHandler("vrr.elementPosition", setElementPosition);
+ addNetworkEventHandler("vrr.elementCollisions", setElementCollisionsEnabled);
+ addNetworkEventHandler("vrr.vehBuyState", setVehiclePurchaseState);
+ addNetworkEventHandler("vrr.holdObject", makePedHoldObject);
}
// ===========================================================================
@@ -131,7 +173,7 @@ function sendResourceStoppedSignalToServer() {
// ===========================================================================
-function setPlayer2DRendering(hudState, labelState, smallGameMessageState, scoreboardState, hotBarState, itemActionDelayState) {
+function set2DRendering(hudState, labelState, smallGameMessageState, scoreboardState, hotBarState, itemActionDelayState) {
logToConsole(LOG_DEBUG, `[VRR.Main] Updating render states (HUD: ${hudState}, Labels: ${labelState}, Bottom Text: ${smallGameMessageState}, Scoreboard: ${scoreboardState}, HotBar: ${hotBarState}, Item Action Delay: ${itemActionDelayState})`);
renderHUD = hudState;
@@ -139,6 +181,8 @@ function setPlayer2DRendering(hudState, labelState, smallGameMessageState, score
natives.displayCash(hudState);
natives.displayAmmo(hudState);
natives.displayHud(hudState);
+ natives.displayRadar(hudState);
+ natives.displayAreaName(hudState);
} else {
if(typeof setHUDEnabled != "undefined") {
setHUDEnabled(hudState);
@@ -154,12 +198,26 @@ function setPlayer2DRendering(hudState, labelState, smallGameMessageState, score
// ===========================================================================
-function onServerSpawnedPlayer(state) {
+function onServerSpawnedLocalPlayer(state) {
logToConsole(LOG_DEBUG, `[VRR.Main] Setting spawned state to ${state}`);
isSpawned = state;
+ setUpInitialGame();
if(state) {
- setUpInitialGame();
- calledDeathEvent = false;
+ setTimeout(function() {
+ calledDeathEvent = false;
+ }, 1000);
+
+ getElementsByType(ELEMENT_PED).filter(ped => !ped.isType(ELEMENT_PLAYER)).forEach(ped => {
+ syncCivilianProperties(ped);
+ });
+
+ getElementsByType(ELEMENT_PLAYER).forEach(player => {
+ syncPlayerProperties(player);
+ });
+
+ getElementsByType(ELEMENT_VEHICLE).forEach(vehicle => {
+ syncVehicleProperties(vehicle);
+ });
}
}
@@ -233,20 +291,6 @@ function forceSyncElementProperties(elementId) {
// ===========================================================================
-function setElementPosition(elementId, position) {
- if(getElementFromId(elementId) == null) {
- return false;
- }
-
- if(!getElementFromId(elementId).isSyncer) {
- return false;
- }
-
- getElementFromId(elementId).position = position;
-}
-
-// ===========================================================================
-
function setElementCollisionsEnabled(elementId, state) {
if(getElementFromId(elementId) == null) {
return false;
@@ -257,18 +301,6 @@ function setElementCollisionsEnabled(elementId, state) {
// ===========================================================================
-function setLocalPlayerPedPartsAndProps(parts, props) {
- for(let i in parts) {
- localPlayer.changeBodyPart(parts[0], parts[1], parts[2]);
- }
-
- for(let i in props) {
- localPlayer.changeBodyProp(props[0], props[1]);
- }
-}
-
-// ===========================================================================
-
function setLocalPlayerArmour(armour) {
if(typeof localPlayer.armour != "undefined") {
localPlayer.armour = armour;
@@ -277,7 +309,7 @@ function setLocalPlayerArmour(armour) {
// ===========================================================================
-function forceLocalPlayerWantedLevel(wantedLevel) {
+function setLocalPlayerWantedLevel(wantedLevel) {
forceWantedLevel = toInteger(wantedLevel);
}
@@ -300,9 +332,9 @@ function setLocalPlayerInfiniteRun(state) {
// ===========================================================================
function setLocalPlayerSkin(skinId) {
+ logToConsole(LOG_INFO, `[VRR.Server] Setting locale player skin to ${skinId}`);
if(getGame() == VRR_GAME_GTA_IV) {
- //natives.changePlayerModel(natives.getPlayerId(), skinId);
- localPlayer.skin = allowedSkins[skinSelectorIndex][0];
+ natives.changePlayerModel(natives.getPlayerId(), skinId);
} else {
localPlayer.skin = skinId;
}
@@ -322,4 +354,63 @@ function sendLocalPlayerNetworkIdToServer() {
sendNetworkEventToServer("vrr.playerPedId", natives.getNetworkIdFromPed(localPlayer));
}
+// ===========================================================================
+
+function setCutsceneInterior(cutsceneName) {
+ if(getGame() == VRR_GAME_GTA_IV) {
+ if(cutsceneName == "") {
+ natives.clearCutscene();
+ } else {
+ if(natives.isInteriorScene()) {
+ natives.clearCutscene();
+ }
+ natives.initCutscene(cutsceneName);
+ }
+ }
+}
+
+// ===========================================================================
+
+function makeLocalPlayerPedSpeak(speechName) {
+ if(getGame() == VRR_GAME_GTA_IV) {
+ // if player is in vehicle, allow megaphone (if last arg is "1", it will cancel megaphone echo)
+ // Only speeches with _MEGAPHONE will have the bullhorn effect
+ // Afaik it only works on police voices anyway
+ if(localPlayer.vehicle != null) {
+ natives.sayAmbientSpeech(localPlayer, speechName, true, false, 0);
+ } else {
+ natives.sayAmbientSpeech(localPlayer, speechName, true, false, 1);
+ }
+ } else if(getGame() == VRR_GAME_GTA_III || getGame() == VRR_GAME_GTA_VC) {
+ // Don't have a way to get the ped ref ID and can't use ped in arg
+ //game.SET_CHAR_SAY(game.GET_PLAYER_ID(), int);
+ }
+}
+
+// ===========================================================================
+
+function setLocalPlayerAsCopState(state) {
+ if(getGame() == VRR_GAME_GTA_IV) {
+ natives.setPlayerAsCop(natives.getPlayerId(), state);
+ natives.setPoliceIgnorePlayer(natives.getPlayerId(), state);
+ }
+}
+
+// ===========================================================================
+
+function serverRequestedLocalPlayerSpawn(skinId, position) {
+ if(getGame() == VRR_GAME_GTA_IV) {
+ natives.createPlayer(skinId, position);
+ //if(isCustomCameraSupported()) {
+ // game.restoreCamera(true);
+ //}
+ }
+}
+
+// ===========================================================================
+
+function sendLocaleSelectToServer(localeId) {
+ sendNetworkEventToServer("vrr.localeSelect", localeId);
+}
+
// ===========================================================================
\ No newline at end of file
diff --git a/scripts/client/skin-select.js b/scripts/client/skin-select.js
index 905f8c21..bc0fd1e9 100644
--- a/scripts/client/skin-select.js
+++ b/scripts/client/skin-select.js
@@ -54,8 +54,14 @@ function processSkinSelectKeyPress(keyCode) {
logToConsole(LOG_DEBUG, `Switching to skin ${allowedSkins[skinSelectorIndex][1]} (Index: ${skinSelectorIndex}, Skin: ${allowedSkins[skinSelectorIndex][0]})`);
skinSelectMessageTextTop = allowedSkins[skinSelectorIndex][1];
if(getGame() == VRR_GAME_GTA_IV) {
- //natives.changePlayerModel(natives.getPlayerId(), allowedSkins[skinSelectorIndex][0]);
- localPlayer.skin = allowedSkins[skinSelectorIndex][0];
+ let skinId = allowedSkins[skinSelectorIndex][0];
+ if(natives.isModelInCdimage(skinId)) {
+ natives.requestModel(skinId);
+ natives.loadAllObjectsNow();
+ if(natives.hasModelLoaded(skinId)) {
+ natives.changePlayerModel(natives.getPlayerId(), skinId);
+ }
+ }
} else {
localPlayer.skin = allowedSkins[skinSelectorIndex][0];
}
@@ -68,8 +74,14 @@ function processSkinSelectKeyPress(keyCode) {
logToConsole(LOG_DEBUG, `Switching to skin ${allowedSkins[skinSelectorIndex][1]} (Index: ${skinSelectorIndex}, Skin: ${allowedSkins[skinSelectorIndex][0]})`);
skinSelectMessageTextTop = allowedSkins[skinSelectorIndex][1];
if(getGame() == VRR_GAME_GTA_IV) {
- //natives.changePlayerModel(natives.getPlayerId(), allowedSkins[skinSelectorIndex][0]);
- localPlayer.skin = allowedSkins[skinSelectorIndex][0];
+ let skinId = allowedSkins[skinSelectorIndex][0];
+ if(natives.isModelInCdimage(skinId)) {
+ natives.requestModel(skinId);
+ natives.loadAllObjectsNow();
+ if(natives.hasModelLoaded(skinId)) {
+ natives.changePlayerModel(natives.getPlayerId(), skinId);
+ }
+ }
} else {
localPlayer.skin = allowedSkins[skinSelectorIndex][0];
}
@@ -120,8 +132,14 @@ function toggleSkinSelect(state) {
}
if(getGame() == VRR_GAME_GTA_IV) {
- //natives.changePlayerModel(natives.getPlayerId(), allowedSkins[skinSelectorIndex][0]);
- localPlayer.skin = allowedSkins[skinSelectorIndex][0];
+ let skinId = allowedSkins[skinSelectorIndex][0];
+ if(natives.isModelInCdimage(skinId)) {
+ natives.requestModel(skinId);
+ natives.loadAllObjectsNow();
+ if(natives.hasModelLoaded(skinId)) {
+ natives.changePlayerModel(natives.getPlayerId(), skinId);
+ }
+ }
} else {
localPlayer.skin = allowedSkins[skinSelectorIndex][0];
}
diff --git a/scripts/client/startup.js b/scripts/client/startup.js
index 42b50cd5..ce4b5c04 100644
--- a/scripts/client/startup.js
+++ b/scripts/client/startup.js
@@ -26,23 +26,39 @@ function initClientScripts() {
function setUpInitialGame() {
if(getGame() == VRR_GAME_GTA_III) {
+ logToConsole(LOG_DEBUG|LOG_WARN, "Setting up initial game stuff for GTA III ...");
+
+ // Turn off unlimited sprint
game.SET_PLAYER_NEVER_GETS_TIRED(game.GET_PLAYER_ID(), 0);
+
+ // Set completed game progress
game.setGameStat(STAT_PROGRESSMADE, 9999);
game.setGameStat(STAT_TOTALPROGRESSINGAME, 9999);
- game.SET_CAR_DENSITY_MULTIPLIER(3.0);
- game.SET_PED_DENSITY_MULTIPLIER(3.0);
+
+ // Traffic and ped density
+ //game.SET_CAR_DENSITY_MULTIPLIER(3.0); // No visual effect. Needs tweaking and testing.
+ //game.SET_PED_DENSITY_MULTIPLIER(3.0); // No visual effect. Needs tweaking and testing.
+
+ // Disables taxi/vigilante/etc and other start mission triggers
game.onMission = true;
+
+ // Provided by mouse camera script (mousecam.js)
SetStandardControlsEnabled(true);
- return true;
- }
+ } else if(getGame() == VRR_GAME_GTA_VC) {
+ logToConsole(LOG_DEBUG|LOG_WARN, "Setting up initial game stuff for GTA Vice City ...");
- if(getGame() == VRR_GAME_GTA_VC) {
+ // Turn off unlimited sprint
game.SET_PLAYER_NEVER_GETS_TIRED(game.GET_PLAYER_ID(), 0);
- game.setGameStat(STAT_PROGRESSMADE, 9999);
- game.setGameStat(STAT_TOTALPROGRESSINGAME, 9999);
- game.SET_CAR_DENSITY_MULTIPLIER(3.0);
- game.SET_PED_DENSITY_MULTIPLIER(3.0);
+ // Set completed game progress
+ game.setGameStat(STAT_PROGRESSMADE, 99999);
+ game.setGameStat(STAT_TOTALPROGRESSINGAME, 99999);
+
+ // Traffic and ped density
+ //game.SET_CAR_DENSITY_MULTIPLIER(3.0); // No visual effect. Needs tweaking and testing.
+ //game.SET_PED_DENSITY_MULTIPLIER(3.0); // No visual effect. Needs tweaking and testing.
+
+ // Load all anim libs
game.REQUEST_ANIMATION("bikev");
game.REQUEST_ANIMATION("bikeh");
game.REQUEST_ANIMATION("biked");
@@ -65,13 +81,15 @@ function setUpInitialGame() {
game.REQUEST_ANIMATION("lance");
game.REQUEST_ANIMATION("skate");
- game.LOAD_ALL_MODELS_NOW();
+ //game.LOAD_ALL_MODELS_NOW();
+ // Disables taxi/vigilante/etc and other start mission triggers
game.onMission = true;
- SetStandardControlsEnabled(true);
- return true;
- }
- if(getGame() == VRR_GAME_GTA_SA) {
+ // Provided by mouse camera script (mousecam.js)
+ SetStandardControlsEnabled(true);
+ } else if(getGame() == VRR_GAME_GTA_SA) {
+ logToConsole(LOG_DEBUG|LOG_WARN, "Setting up initial game stuff for GTA San Andreas ...");
+ // Turn weapon skills down a bit
game.setGameStat(STAT_WEAPONTYPE_PISTOL_SKILL, 400);
game.setGameStat(STAT_WEAPONTYPE_PISTOL_SILENCED_SKILL, 400);
game.setGameStat(STAT_WEAPONTYPE_DESERT_EAGLE_SKILL, 400);
@@ -82,7 +100,11 @@ function setUpInitialGame() {
game.setGameStat(STAT_WEAPONTYPE_MP5_SKILL, 400);
game.setGameStat(STAT_WEAPONTYPE_AK47_SKILL, 400);
game.setGameStat(STAT_WEAPONTYPE_M4_SKILL, 400);
+
+ // Pro driving skill
game.setGameStat(STAT_DRIVING_SKILL, 9999);
+
+ // Only visual for CJ, but affects all peds fight speed, bicycle hop, etc
game.setGameStat(STAT_FAT, 9999);
game.setGameStat(STAT_ENERGY, 9999);
game.setGameStat(STAT_CYCLE_SKILL, 9999);
@@ -97,12 +119,12 @@ function setUpInitialGame() {
game.setGameStat(STAT_UNDERWATER_STAMINA, 9999);
game.setGameStat(STAT_BODY_MUSCLE, 9999);
+ // Disables default yellow cone at doors for entering places in singleplayer
game.setDefaultInteriors(false);
- game.onMission = true;
- return true;
- }
- if(getGame() == VRR_GAME_GTA_IV) {
+ // Disables taxi/vigilante/etc and other start mission triggers
+ game.onMission = true;
+ } else if(getGame() == VRR_GAME_GTA_IV) {
natives.allowEmergencyServices(false);
natives.setCreateRandomCops(true);
natives.setMaxWantedLevel(0);
@@ -115,22 +137,23 @@ function setUpInitialGame() {
natives.setSyncWeatherAndGameTime(false);
natives.usePlayerColourInsteadOfTeamColour(true);
natives.disablePauseMenu(true);
- natives.allowReactionAnims(localPlayer, true);
+ //natives.allowReactionAnims(localPlayer, false);
natives.allowGameToPauseForStreaming(false);
natives.allowStuntJumpsToTrigger(false);
natives.setPickupsFixCars(false);
+ natives.forceFullVoice(localPlayer);
// HUD and Display
- natives.displayCash(false);
- natives.displayAmmo(false);
- natives.displayHud(false);
- natives.displayRadar(false);
- natives.displayAreaName(false);
- natives.displayPlayerNames(false);
+ //natives.displayCash(false);
+ //natives.displayAmmo(false);
+ //natives.displayHud(false);
+ //natives.displayRadar(false);
+ //natives.displayAreaName(false);
+ natives.displayPlayerNames(true);
natives.setPoliceRadarBlips(false);
natives.removeTemporaryRadarBlipsForPickups();
natives.displayNonMinigameHelpMessages(false);
- natives.setDisplayPlayerNameAndIcon(natives.getPlayerId(), false);
+ natives.setDisplayPlayerNameAndIcon(natives.getPlayerId(), true);
// Item/Money Dropping
natives.setMoneyCarriedByAllNewPeds(0);
@@ -138,27 +161,34 @@ function setUpInitialGame() {
natives.setPlayersDropMoneyInNetworkGame(false);
// Population
- natives.dontSuppressAnyCarModels(5.0);
- natives.dontSuppressAnyPedModels(5.0);
- natives.forceGenerateParkedCarsTooCloseToOthers(5.0);
- natives.setParkedCarDensityMultiplier(5.0);
- natives.setRandomCarDensityMultiplier(5.0);
- natives.setPedDensityMultiplier(5.0);
- natives.setCarDensityMultiplier(5.0);
- natives.setScenarioPedDensityMultiplier(5.0, 5.0);
+ //natives.dontSuppressAnyCarModels(5.0);
+ //natives.dontSuppressAnyPedModels(5.0);
+ //natives.forceGenerateParkedCarsTooCloseToOthers(true);
+ //natives.setParkedCarDensityMultiplier(5.0);
+ //natives.setRandomCarDensityMultiplier(5.0);
+ //natives.setPedDensityMultiplier(5.0);
+ //natives.setCarDensityMultiplier(5.0);
+ //natives.setScenarioPedDensityMultiplier(5.0, 5.0);
natives.switchRandomTrains(true);
natives.switchRandomBoats(true);
natives.switchAmbientPlanes(true);
natives.switchMadDrivers(false);
- natives.requestAnims("DANCING");
- return true;
- }
+ // Singleplayer Cellphone
+ //natives.requestScript("spcellphone");
+ //natives.startNewScript("spcellphone", 0);
+ // Script "v-blockedscripts" blocks the mpcellphone scripts
+ natives.setMessagesWaiting(false); // Seems to have no effect
+ natives.setMobilePhoneRadioState(false);
- if(getGame() == VRR_GAME_MAFIA_ONE) {
+ // Animation libraries
+ natives.requestAnims("DANCING");
+
+ // Some last steps
+ //natives.loadAllObjectsNow();
+ } else if(getGame() == VRR_GAME_MAFIA_ONE) {
game.mapEnabled = false;
game.setTrafficEnabled(false);
- return true;
}
}
@@ -166,4 +196,4 @@ function setUpInitialGame() {
initClientScripts();
-// ===========================================================================
\ No newline at end of file
+// ===========================================================================
diff --git a/scripts/client/sync.js b/scripts/client/sync.js
index a39a7ebc..4c727cec 100644
--- a/scripts/client/sync.js
+++ b/scripts/client/sync.js
@@ -10,8 +10,13 @@
function processSync(event, deltaTime) {
if(localPlayer != null) {
if(!areServerElementsSupported()) {
- sendNetworkEventToServer("vrr.player.position", localPlayer.position);
- sendNetworkEventToServer("vrr.player.heading", localPlayer.heading);
+ sendNetworkEventToServer("vrr.plr.pos", (localPlayer.vehicle != null) ? localPlayer.vehicle.position : localPlayer.position);
+ sendNetworkEventToServer("vrr.plr.rot", (localPlayer.vehicle != null) ? localPlayer.vehicle.heading : localPlayer.heading);
+
+ //if(localPlayer.vehicle != null) {
+ // sendNetworkEventToServer("vrr.veh.pos", getVehicleForNetworkEvent(localPlayer.vehicle), localPlayer.vehicle.position);
+ // sendNetworkEventToServer("vrr.veh.rot", getVehicleForNetworkEvent(localPlayer.vehicle), localPlayer.vehicle.heading);
+ //}
}
if(localPlayer.health <= 0) {
@@ -22,12 +27,393 @@ function processSync(event, deltaTime) {
sendNetworkEventToServer("vrr.playerDeath");
}
}
+ }
- if(streamingRadioElement) {
- streamingRadio.position = getElementPosition(streamingRadioElement);
- //streamingRadio.volume = getStreamingRadioVolumeForPosition(streamingRadio.position);
+ if(localPlayer.health <= 0) {
+ if(!calledDeathEvent) {
+ logToConsole(LOG_DEBUG, `Local player died`);
+ localPlayer.clearWeapons();
+ calledDeathEvent = true;
+ sendNetworkEventToServer("vrr.playerDeath");
}
}
+
+ if(streamingRadioElement) {
+ streamingRadio.position = getElementPosition(streamingRadioElement.id);
+ //streamingRadio.volume = getStreamingRadioVolumeForPosition(streamingRadio.position);
+ }
+}
+
+// ===========================================================================
+
+function setVehicleEngine(vehicleId, state) {
+ getElementFromId(vehicleId).engine = state;
+}
+
+// ===========================================================================
+
+function setVehicleLights(vehicleId, state) {
+ if(getGame() != VRR_GAME_MAFIA_ONE) {
+ if(!state) {
+ getElementFromId(vehicleId).lightStatus = 2;
+ } else {
+ getElementFromId(vehicleId).lightStatus = 1;
+ }
+ } else if(getGame() == VRR_GAME_GTA_IV) {
+ if(!state) {
+ natives.forceCarLights(natives.getVehicleFromNetworkId(vehicleId, 0));
+ } else {
+ natives.forceCarLights(natives.getVehicleFromNetworkId(vehicleId, 1));
+ }
+ } else {
+ if(!state) {
+ getElementFromId(vehicleId).lights = false;
+ } else {
+ getElementFromId(vehicleId).lights = true;
+ }
+ }
+}
+
+// ===========================================================================
+
+function repairVehicle(syncId) {
+ getVehicleFromSyncId(syncId).fix();
+}
+
+// ===========================================================================
+
+function syncVehicleProperties(vehicle) {
+ if(!areServerElementsSupported()) {
+ return false;
+ }
+
+ if(doesEntityDataExist(vehicle, "vrr.lights")) {
+ let lightStatus = getEntityData(vehicle, "vrr.lights");
+ if(!lightStatus) {
+ vehicle.lightStatus = 2;
+ } else {
+ vehicle.lightStatus = 1;
+ }
+ }
+
+ if(doesEntityDataExist(vehicle, "vrr.invincible")) {
+ let invincible = getEntityData(vehicle, "vrr.invincible");
+ element.setProofs(invincible, invincible, invincible, invincible, invincible);
+ }
+
+ if(doesEntityDataExist(vehicle, "vrr.panelStatus")) {
+ let panelsStatus = getEntityData(vehicle, "vrr.panelStatus");
+ for(let i in panelsStatus) {
+ vehicle.setPanelStatus(i, panelsStatus[i]);
+ }
+ }
+
+ if(doesEntityDataExist(vehicle, "vrr.wheelStatus")) {
+ let wheelsStatus = getEntityData(vehicle, "vrr.wheelStatus");
+ for(let i in wheelsStatus) {
+ vehicle.setWheelStatus(i, wheelsStatus[i]);
+ }
+ }
+
+ if(doesEntityDataExist(vehicle, "vrr.lightStatus")) {
+ let lightStatus = getEntityData(vehicle, "vrr.lightStatus");
+ for(let i in lightStatus) {
+ vehicle.setLightStatus(i, lightStatus[i]);
+ }
+ }
+
+ if(doesEntityDataExist(vehicle, "vrr.suspensionHeight")) {
+ let suspensionHeight = getEntityData(vehicle, "vrr.suspensionHeight");
+ vehicle.setSuspensionHeight(suspensionHeight);
+ }
+
+ if(getGame() == VRR_GAME_GTA_SA) {
+ //let allUpgrades = getGameConfig().vehicleUpgrades[getGame()];
+ //for(let i in allUpgrades) {
+ // vehicle.removeUpgrade(i);
+ //}
+
+ if(doesEntityDataExist(vehicle, "vrr.upgrades")) {
+ let upgrades = getEntityData(vehicle, "vrr.upgrades");
+ for(let i in upgrades) {
+ if(upgrades[i] != 0) {
+ vehicle.addUpgrade(upgrades[i]);
+ }
+ }
+ }
+ }
+
+ if(getGame() == VRR_GAME_GTA_SA || getGame() == VRR_GAME_GTA_IV) {
+ if(doesEntityDataExist(vehicle, "vrr.livery")) {
+ let livery = getEntityData(vehicle, "vrr.livery");
+ if(getGame() == VRR_GAME_GTA_SA) {
+ vehicle.setPaintJob(livery);
+ } else if(getGame() == VRR_GAME_GTA_IV) {
+ vehicle.livery = livery;
+ }
+ }
+ }
+}
+
+// ===========================================================================
+
+function syncCivilianProperties(civilian) {
+ if(!areServerElementsSupported()) {
+ return false;
+ }
+
+ if(getGame() == VRR_GAME_GTA_III) {
+ if(doesEntityDataExist(civilian, "vrr.scale")) {
+ let scaleFactor = getEntityData(civilian, "vrr.scale");
+ let tempMatrix = civilian.matrix;
+ tempMatrix.setScale(toVector3(scaleFactor.x, scaleFactor.y, scaleFactor.z));
+ let tempPosition = civilian.position;
+ civilian.matrix = tempMatrix;
+ tempPosition.z += scaleFactor.z;
+ civilian.position = tempPosition;
+ }
+ }
+
+ if(getGame() == VRR_GAME_GTA_SA) {
+ if(doesEntityDataExist(civilian, "vrr.fightStyle")) {
+ let fightStyle = getEntityData(civilian, "vrr.fightStyle");
+ civilian.setFightStyle(fightStyle[0], fightStyle[1]);
+ }
+ }
+
+ if(getGame() == VRR_GAME_GTA_III) {
+ if(doesEntityDataExist(civilian, "vrr.walkStyle")) {
+ let walkStyle = getEntityData(civilian, "vrr.walkStyle");
+ civilian.walkStyle = walkStyle;
+ }
+ }
+
+ if(getGame() == VRR_GAME_GTA_IV) {
+ if(doesEntityDataExist(civilian, "vrr.bodyPropHair")) {
+ let bodyPropHair = getEntityData(civilian, "vrr.bodyPropHair");
+ civilian.changeBodyProp(0, bodyPropHair[0], bodyPropHair[1]);
+ }
+
+ if(doesEntityDataExist(civilian, "vrr.bodyPropHead")) {
+ let bodyPropHead = getEntityData(civilian, "vrr.bodyPropHead");
+ civilian.changeBodyProp(1, bodyPropHead[0], bodyPropHead[1]);
+ }
+
+ if(doesEntityDataExist(civilian, "vrr.bodyPropEyes")) {
+ let bodyPropEyes = getEntityData(civilian, "vrr.bodyPropEyes");
+ civilian.changeBodyProp(1, bodyPropEyes[0], bodyPropEyes[1]);
+ }
+
+ if(doesEntityDataExist(civilian, "vrr.bodyPropLeftHand")) {
+ let bodyPropLeftHand = getEntityData(civilian, "vrr.bodyPropLeftHand");
+ civilian.changeBodyProp(1, bodyPropLeftHand[0], bodyPropLeftHand[1]);
+ }
+
+ if(doesEntityDataExist(civilian, "vrr.bodyPropRightHand")) {
+ let bodyPropRightHand = getEntityData(civilian, "vrr.bodyPropRightHand");
+ civilian.changeBodyProp(1, bodyPropRightHand[0], bodyPropRightHand[1]);
+ }
+
+ if(doesEntityDataExist(civilian, "vrr.bodyPropLeftWrist")) {
+ let bodyPropLeftWrist = getEntityData(civilian, "vrr.bodyPropLeftWrist");
+ civilian.changeBodyProp(1, bodyPropLeftWrist[0], bodyPropLeftWrist[1]);
+ }
+
+ if(doesEntityDataExist(civilian, "vrr.bodyPropRightWrist")) {
+ let bodyPropRightWrist = getEntityData(civilian, "vrr.bodyPropRightWrist");
+ civilian.changeBodyProp(1, bodyPropRightWrist[0], bodyPropRightWrist[1]);
+ }
+
+ if(doesEntityDataExist(civilian, "vrr.bodyPropRightWrist")) {
+ let bodyPropRightWrist = getEntityData(civilian, "vrr.bodyPropRightWrist");
+ civilian.changeBodyProp(1, bodyPropRightWrist[0], bodyPropRightWrist[1]);
+ }
+
+ if(doesEntityDataExist(civilian, "vrr.bodyPropHip")) {
+ let bodyPropHip = getEntityData(civilian, "vrr.bodyPropHip");
+ civilian.changeBodyProp(1, bodyPropHip[0], bodyPropHip[1]);
+ }
+
+ if(doesEntityDataExist(civilian, "vrr.bodyPropLeftFoot")) {
+ let bodyPropLeftFoot = getEntityData(civilian, "vrr.bodyPropLeftFoot");
+ civilian.changeBodyProp(1, bodyPropLeftFoot[0], bodyPropLeftFoot[1]);
+ }
+
+ if(doesEntityDataExist(civilian, "vrr.bodyPropRightFoot")) {
+ let bodyPropRightFoot = getEntityData(civilian, "vrr.bodyPropRightFoot");
+ civilian.changeBodyProp(1, bodyPropRightFoot[0], bodyPropRightFoot[1]);
+ }
+ }
+
+ if(doesEntityDataExist(civilian, "vrr.anim")) {
+ let animationSlot = getEntityData(civilian, "vrr.anim");
+ let animationData = getAnimationData(animationSlot);
+ civilian.addAnimation(animationData.groupId, animationData.animId);
+ }
+}
+
+// ===========================================================================
+
+function syncPlayerProperties(player) {
+ if(!areServerElementsSupported()) {
+ return false;
+ }
+
+ if(getGame() == VRR_GAME_GTA_III) {
+ if(doesEntityDataExist(player, "vrr.scale")) {
+ let scaleFactor = getEntityData(player, "vrr.scale");
+ let tempMatrix = player.matrix;
+ tempMatrix.setScale(toVector3(scaleFactor.x, scaleFactor.y, scaleFactor.z));
+ let tempPosition = player.position;
+ player.matrix = tempMatrix;
+ tempPosition.z += scaleFactor.z;
+ player.position = tempPosition;
+ }
+ }
+
+ if(getGame() == VRR_GAME_GTA_SA) {
+ if(doesEntityDataExist(player, "vrr.fightStyle")) {
+ let fightStyle = getEntityData(player, "vrr.fightStyle");
+ player.setFightStyle(fightStyle[0], fightStyle[1]);
+ }
+ }
+
+ //if(getGame() == VRR_GAME_GTA_SA) {
+ // if(doesEntityDataExist(player, "vrr.walkStyle")) {
+ // let walkStyle = getEntityData(player, "vrr.walkStyle");
+ // player.walkStyle = walkStyle;
+ // }
+ //}
+
+ if(getGame() == VRR_GAME_GTA_IV) {
+ if(doesEntityDataExist(player, "vrr.bodyPartHair")) {
+ let bodyPartHead = getEntityData(player, "vrr.bodyPartHair");
+ player.changeBodyPart(0, bodyPartHead[0], bodyPartHair[1]);
+ }
+
+ if(doesEntityDataExist(player, "vrr.bodyPartHead")) {
+ let bodyPartHead = getEntityData(player, "vrr.bodyPartHead");
+ player.changeBodyPart(1, bodyPartHead[0], bodyPartHead[1]);
+ }
+
+ if(doesEntityDataExist(player, "vrr.bodyPartUpper")) {
+ let bodyPartUpper = getEntityData(player, "vrr.bodyPartUpper");
+ player.changeBodyPart(1, bodyPartUpper[0], bodyPartUpper[1]);
+ }
+
+ if(doesEntityDataExist(player, "vrr.bodyPartLower")) {
+ let bodyPartLower = getEntityData(player, "vrr.bodyPartLower");
+ player.changeBodyPart(1, bodyPartLower[0], bodyPartLower[1]);
+ }
+ }
+
+ if(getGame() == VRR_GAME_GTA_IV) {
+ if(doesEntityDataExist(player, "vrr.bodyPropHair")) {
+ let bodyPropHair = getEntityData(player, "vrr.bodyPropHair");
+ player.changeBodyProp(0, bodyPropHair[0], bodyPropHair[1]);
+ }
+
+ if(doesEntityDataExist(player, "vrr.bodyPropHead")) {
+ let bodyPropHead = getEntityData(player, "vrr.bodyPropHead");
+ player.changeBodyProp(1, bodyPropHead[0], bodyPropHead[1]);
+ }
+
+ if(doesEntityDataExist(player, "vrr.bodyPropEyes")) {
+ let bodyPropEyes = getEntityData(player, "vrr.bodyPropEyes");
+ player.changeBodyProp(1, bodyPropEyes[0], bodyPropEyes[1]);
+ }
+
+ if(doesEntityDataExist(player, "vrr.bodyPropLeftHand")) {
+ let bodyPropLeftHand = getEntityData(player, "vrr.bodyPropLeftHand");
+ player.changeBodyProp(1, bodyPropLeftHand[0], bodyPropLeftHand[1]);
+ }
+
+ if(doesEntityDataExist(player, "vrr.bodyPropRightHand")) {
+ let bodyPropRightHand = getEntityData(player, "vrr.bodyPropRightHand");
+ player.changeBodyProp(1, bodyPropRightHand[0], bodyPropRightHand[1]);
+ }
+
+ if(doesEntityDataExist(player, "vrr.bodyPropLeftWrist")) {
+ let bodyPropLeftWrist = getEntityData(player, "vrr.bodyPropLeftWrist");
+ player.changeBodyProp(1, bodyPropLeftWrist[0], bodyPropLeftWrist[1]);
+ }
+
+ if(doesEntityDataExist(player, "vrr.bodyPropRightWrist")) {
+ let bodyPropRightWrist = getEntityData(player, "vrr.bodyPropRightWrist");
+ player.changeBodyProp(1, bodyPropRightWrist[0], bodyPropRightWrist[1]);
+ }
+
+ if(doesEntityDataExist(player, "vrr.bodyPropRightWrist")) {
+ let bodyPropRightWrist = getEntityData(player, "vrr.bodyPropRightWrist");
+ player.changeBodyProp(1, bodyPropRightWrist[0], bodyPropRightWrist[1]);
+ }
+
+ if(doesEntityDataExist(player, "vrr.bodyPropHip")) {
+ let bodyPropHip = getEntityData(player, "vrr.bodyPropHip");
+ player.changeBodyProp(1, bodyPropHip[0], bodyPropHip[1]);
+ }
+
+ if(doesEntityDataExist(player, "vrr.bodyPropLeftFoot")) {
+ let bodyPropLeftFoot = getEntityData(player, "vrr.bodyPropLeftFoot");
+ player.changeBodyProp(1, bodyPropLeftFoot[0], bodyPropLeftFoot[1]);
+ }
+
+ if(doesEntityDataExist(player, "vrr.bodyPropRightFoot")) {
+ let bodyPropRightFoot = getEntityData(player, "vrr.bodyPropRightFoot");
+ player.changeBodyProp(1, bodyPropRightFoot[0], bodyPropRightFoot[1]);
+ }
+ }
+}
+
+// ===========================================================================
+
+function syncElementProperties(element) {
+ if(!areServerElementsSupported()) {
+ return false;
+ }
+
+ if(doesEntityDataExist(element, "vrr.interior")) {
+ if(typeof element.interior != "undefined") {
+ element.interior = getEntityData(element, "vrr.interior");
+ }
+ }
+
+ if(getGame() == VRR_GAME_MAFIA_ONE) {
+ switch(element.type) {
+ case ELEMENT_VEHICLE:
+ syncVehicleProperties(element);
+ break;
+
+ case ELEMENT_PED:
+ syncCivilianProperties(element);
+ break;
+
+ case ELEMENT_PLAYER:
+ syncPlayerProperties(element);
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ switch(element.type) {
+ case ELEMENT_VEHICLE:
+ syncVehicleProperties(element);
+ break;
+
+ case ELEMENT_PED:
+ syncCivilianProperties(element);
+ break;
+
+ case ELEMENT_PLAYER:
+ syncPlayerProperties(element);
+ break;
+
+ default:
+ break;
+ }
+ }
+
}
// ===========================================================================
@@ -38,4 +424,16 @@ function receiveHouseFromServer(houseId, entrancePosition, blipModel, pickupMode
}
}
+// ===========================================================================
+
+function setLocalPlayerPedPartsAndProps(parts, props) {
+ for(let i in parts) {
+ localPlayer.changeBodyPart(parts[i][0], parts[i][1], parts[i][2]);
+ }
+
+ for(let j in props) {
+ localPlayer.changeBodyProp(props[j][0], props[j][1]);
+ }
+}
+
// ===========================================================================
\ No newline at end of file
diff --git a/scripts/client/utilities.js b/scripts/client/utilities.js
index a731cd11..876df66a 100644
--- a/scripts/client/utilities.js
+++ b/scripts/client/utilities.js
@@ -7,173 +7,6 @@
// TYPE: Client (JavaScript)
// ===========================================================================
-let weaponSlots = [
- false,
- [
- 0,
- 1,
- 2,
- 3,
- 4,
- 5,
- 6,
- 7,
- 8,
- 9,
- 10,
- 11
- ],
- [
- 0,
- 0,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 2,
- 2,
- 2,
- 2,
- 2,
- 3,
- 3,
- 4,
- 4,
- 4,
- 5,
- 5,
- 5,
- 5,
- 6,
- 6,
- 8,
- 8,
- 7,
- 7,
- 7,
- 7,
- 9,
- -1,
- 9,
- ],
- [
- 0,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 8,
- 8,
- 8,
- -1,
- -1,
- -1,
- 2,
- 2,
- 2,
- 3,
- 3,
- 3,
- 4,
- 4,
- 5,
- 5,
- 4,
- 6,
- 6,
- 7,
- 7,
- 7,
- 7,
- 8,
- 12,
- 9,
- 9,
- 9,
- 9,
- 9,
- 11,
- 9,
- 9,
- 9,
- ],
-];
-
-function openAllGarages() {
- switch(game.game) {
- case VRR_GAME_GTA_III:
- for(let i=0;i<=26;i++) {
- openGarage(i);
- game.NO_SPECIAL_CAMERA_FOR_THIS_GARAGE(i);
- }
- break;
-
- case VRR_GAME_GTA_VC:
- for(let i=0;i<=32;i++) {
- openGarage(i);
- game.NO_SPECIAL_CAMERA_FOR_THIS_GARAGE(i);
- }
- break;
-
- case VRR_GAME_GTA_SA:
- for(let i=0;i<=44;i++) {
- openGarage(i);
- }
- break;
-
- default:
- break;
- }
-}
-
-// ===========================================================================
-
-function closeAllGarages() {
- switch(game.game) {
- case VRR_GAME_GTA_III:
- for(let i=0;i<=26;i++) {
- closeGarage(i);
- game.NO_SPECIAL_CAMERA_FOR_THIS_GARAGE(i);
- }
- break;
-
- case VRR_GAME_GTA_VC:
- for(let i=0;i<=32;i++) {
- closeGarage(i);
- game.NO_SPECIAL_CAMERA_FOR_THIS_GARAGE(i);
- }
- break;
-
- case VRR_GAME_GTA_SA:
- for(let i=0;i<=44;i++) {
- closeGarage(i);
- }
- break;
-
- default:
- break;
- }
-}
-
-// ===========================================================================
-
function setLocalPlayerFrozenState(state) {
logToConsole(LOG_DEBUG, `[VRR.Utilities] Setting frozen state to ${state}`);
gui.showCursor(state, !state);
@@ -185,12 +18,10 @@ function setLocalPlayerControlState(controlState, cursorState = false) {
logToConsole(LOG_DEBUG, `[VRR.Utilities] Setting control state to ${controlState} (Cursor: ${cursorState})`);
controlsEnabled = controlState;
if(getGame() == VRR_GAME_GTA_III || getGame() == VRR_GAME_GTA_VC) {
- game.SET_PLAYER_CONTROL(localClient.index, boolToInt(controlState));
- }
-
- if(getGame() != VRR_GAME_GTA_IV) {
- localPlayer.collisionsEnabled = controlState;
- localPlayer.invincible = true;
+ game.SET_PLAYER_CONTROL(game.GET_PLAYER_ID(), boolToInt(controlState));
+ } else if(getGame() != VRR_GAME_GTA_IV) {
+ setElementCollisionsEnabled(localPlayer, controlState);
+ setPedInvincible(localPlayer, true);
}
}
@@ -246,7 +77,7 @@ function setCityAmbienceState(state, clearElements = false) {
if(getMultiplayerMod() == VRR_MPMOD_GTAC) {
game.setGenerateCarsAroundCamera(state);
- if(game.game != VRR_GAME_GTA_SA) {
+ if(getGame() != VRR_GAME_GTA_SA) {
game.setCiviliansEnabled(state);
}
@@ -264,10 +95,16 @@ function runClientCode(code, returnTo) {
try {
returnValue = eval("(" + code + ")");
} catch(error) {
- sendNetworkEventToServer("vrr.runCodeFail", returnTo, code);
+ sendNetworkEventToServer("vrr.runCodeFail", returnTo, error.toString());
return false;
}
- sendNetworkEventToServer("vrr.runCodeSuccess", returnTo, code, returnValue);
+ let returnValueString = returnValue;
+ if(returnValue != null && returnValue != undefined) {
+ returnValueString = `${returnValue.toString()} (${typeof returnValue})`;
+ } else {
+ returnValueString = "null/undefined";
+ }
+ sendNetworkEventToServer("vrr.runCodeSuccess", returnTo, returnValueString);
}
// ===========================================================================
@@ -280,11 +117,13 @@ function enterVehicleAsPassenger() {
localPlayer.enterVehicle(tempVehicle, false);
}
} else {
- for(let i = 0 ; i <= natives.getMaximumNumberOfPassengers(tempVehicle); i++) {
- if(natives.isCarPassengerSeatFree(tempVehicle, i)) {
- natives.taskEnterCarAsPassenger(localPlayer, tempVehicle, i, 1);
- }
- }
+ // Disable for now. GTA IV has built-in passenger entry
+
+ //for(let i = 0 ; i <= natives.getMaximumNumberOfPassengers(tempVehicle); i++) {
+ // if(natives.isCarPassengerSeatFree(tempVehicle, i)) {
+ // natives.taskEnterCarAsPassenger(localPlayer, tempVehicle, i, 10000);
+ // }
+ //}
}
}
}
@@ -312,12 +151,14 @@ function giveLocalPlayerWeapon(weaponId, ammo, active) {
// ===========================================================================
-function clearLocalPlayerWeapons() {
+function clearLocalPlayerWeapons(clearData) {
logToConsole(LOG_DEBUG, `[VRR.Utilities] Clearing weapons`);
localPlayer.clearWeapons();
- forceWeapon = 0;
- forceWeaponAmmo = 0;
- forceWeaponClipAmmo = 0;
+ if(clearData == true) {
+ forceWeapon = 0;
+ forceWeaponAmmo = 0;
+ forceWeaponClipAmmo = 0;
+ }
}
// ===========================================================================
@@ -356,18 +197,23 @@ function setLocalPlayerInterior(interior) {
if(!isGTAIV()) {
localPlayer.interior = interior;
game.cameraInterior = interior;
- } else {
- let interiorId = natives.getInteriorAtCoords(localPlayer.position);
- natives.activateInterior(interiorId, true);
- }
+ } //else {
+ //if(getGameConfig().mainWorldInterior != interior) {
+ // let interiorId = natives.getInteriorAtCoords(localPlayer.position);
+ // natives.activateInterior(interiorId, true);
+ // natives.loadAllObjectsNow();
+ //}
+ //let interiorId = natives.getInteriorAtCoords(localPlayer.position);
+ //natives.activateInterior(interiorId, true);
+ //}
}
- //let vehicles = getElementsByType(ELEMENT_VEHICLE);
- //for(let i in vehicles) {
- // if(getEntityData(vehicles[i], "vrr.interior")) {
- // vehicles[i].interior = getEntityData(vehicles[i], "vrr.interior");
- // }
- //}
+ let vehicles = getElementsByType(ELEMENT_VEHICLE);
+ for(let i in vehicles) {
+ if(getEntityData(vehicles[i], "vrr.interior")) {
+ vehicles[i].interior = getEntityData(vehicles[i], "vrr.interior");
+ }
+ }
}
// ===========================================================================
@@ -389,12 +235,6 @@ function setLocalPlayerHealth(health) {
// ===========================================================================
-function isSnowEnabled() {
- return (typeof snowing != "undefined");
-}
-
-// ===========================================================================
-
function playPedSpeech(pedName, speechId) {
logToConsole(LOG_DEBUG, `[VRR.Utilities] Making ${pedName}'s ped talk (${speechId})`);
if(getMultiplayerMod() == VRR_MPMOD_GTAC) {
@@ -412,18 +252,14 @@ function clearLocalPedState() {
// ===========================================================================
function getWeaponSlot(weaponId) {
- if(getGame() == VRR_GAME_GTA_IV) {
- return false;
- }
-
- return weaponSlots[getGame()][weaponId];
+ return getGameConfig().weaponSlots[getGame()][weaponId];
}
// ===========================================================================
function setLocalPlayerDrunkEffect(amount, duration) {
if(getMultiplayerMod() == VRR_MPMOD_GTAC) {
- logToConsole(LOG_DEBUG, `[VRR.Utilities] Drunk effect set to ${amount} for ${duration}ms`);
+ logToConsole(LOG_DEBUG, `[VRR.Utilities] Drunk effect set to ${amount} for ${duration} ms`);
drunkEffectAmount = 0;
drunkEffectDurationTimer = setInterval(function() {
drunkEffectAmount = drunkEffectAmount;
@@ -568,24 +404,20 @@ function processWantedLevelReset() {
function processLocalPlayerVehicleControlState() {
if(areServerElementsSupported()) {
if(inVehicle && localPlayer.vehicle != null) {
- if(getEntityData(localPlayer.vehicle, "vrr.engine") == false) {
- localPlayer.vehicle.engine = false;
- }
+ if(doesEntityDataExist(localPlayer.vehicle, "vrr.engine")) {
+ if(getEntityData(localPlayer.vehicle, "vrr.engine") == false) {
+ localPlayer.vehicle.engine = false;
+ if(!localPlayer.vehicle.engine) {
+ if(typeof localPlayer.vehicle.velocity != "undefined") {
+ localPlayer.vehicle.velocity = toVector3(0.0, 0.0, 0.0);
+ localPlayer.vehicle.turnVelocity = toVector3(0.0, 0.0, 0.0);
+ }
- if(!localPlayer.vehicle.engine) {
- if(typeof localPlayer.vehicle.velocity != "undefined") {
- localPlayer.vehicle.velocity = toVector3(0.0, 0.0, 0.0);
- localPlayer.vehicle.turnVelocity = toVector3(0.0, 0.0, 0.0);
- }
-
- if(parkedVehiclePosition) {
- localPlayer.vehicle.position = parkedVehiclePosition;
- localPlayer.vehicle.heading = parkedVehicleHeading;
- }
- } else {
- if(parkedVehiclePosition) {
- parkedVehiclePosition = false;
- parkedVehicleHeading = false;
+ //if(parkedVehiclePosition) {
+ // localPlayer.vehicle.position = parkedVehiclePosition;
+ // localPlayer.vehicle.heading = parkedVehicleHeading;
+ //}
+ }
}
}
}
@@ -617,7 +449,7 @@ function processLocalPlayerSphereEntryExitHandling() {
// ===========================================================================
function processJobRouteSphere() {
- if(game.game == VRR_GAME_GTA_SA) {
+ if(getGame() == VRR_GAME_GTA_SA) {
let position = getLocalPlayerPosition();
if(jobRouteLocationSphere != null) {
if(getDistance(position, jobRouteLocationSphere.position) <= 2.0) {
@@ -639,10 +471,10 @@ function forceLocalPlayerEquippedWeaponItem() {
localPlayer.setWeaponAmmunition(getWeaponSlot(forceWeapon), forceWeaponAmmo);
}
} else {
- if(getGame() < VRR_GAME_GTA_IV) {
- forceWeaponClipAmmo = localPlayer.getWeaponClipAmmunition(getWeaponSlot(forceWeapon));
- forceWeaponAmmo = localPlayer.getWeaponAmmunition(getWeaponSlot(forceWeapon));
- }
+ //if(getGame() < VRR_GAME_GTA_IV) {
+ // forceWeaponClipAmmo = localPlayer.getWeaponClipAmmunition(getWeaponSlot(forceWeapon));
+ // forceWeaponAmmo = localPlayer.getWeaponAmmunition(getWeaponSlot(forceWeapon));
+ //}
}
} else {
if(localPlayer.weapon > 0) {
@@ -683,9 +515,11 @@ function processLocalPlayerVehicleEntryExitHandling() {
// ===========================================================================
-function getVehicleForNetworkEvent(vehicleArg) {
- // Soon this will also be used to get the IV vehicle via it's ID
- return vehicleArg;
+function getVehicleForNetworkEvent(vehicle) {
+ if(getGame() == VRR_GAME_GTA_IV) {
+ return natives.getNetworkIdFromVehicle(vehicle);
+ }
+ return vehicle.id;
}
// ===========================================================================
@@ -765,7 +599,7 @@ function processNearbyPickups() {
// ===========================================================================
function processGameSpecifics() {
- if(game.game < VRR_GAME_GTA_IV) {
+ if(getGame() < VRR_GAME_GTA_IV) {
game.clearMessages();
}
@@ -774,55 +608,8 @@ function processGameSpecifics() {
// ===========================================================================
-function processVehiclePurchasing() {
- if(vehiclePurchaseState == VRR_VEHBUYSTATE_TESTDRIVE) {
- if(inVehicle == false) {
- vehiclePurchaseState = VRR_VEHBUYSTATE_EXITVEH;
- sendNetworkEventToServer("vrr.vehBuyState", VRR_VEHBUYSTATE_EXITVEH);
- return false;
- } else {
- if(vehiclePurchasing == inVehicle) {
- if(getDistance(inVehicle.position, vehiclePurchasePosition) >= 25) {
- vehiclePurchaseState = VRR_VEHBUYSTATE_FARENOUGH;
- sendNetworkEventToServer("vrr.vehBuyState", VRR_VEHBUYSTATE_FARENOUGH);
- }
- } else {
- vehiclePurchaseState = VRR_VEHBUYSTATE_WRONGVEH;
- sendNetworkEventToServer("vrr.vehBuyState", VRR_VEHBUYSTATE_WRONGVEH);
- }
- }
- }
-}
-
-// ===========================================================================
-
-function setVehiclePurchaseState(state, vehicleId, position) {
- vehiclePurchaseState = state;
-
- if(vehicleId != null) {
- vehiclePurchasing = getElementFromId(vehicleId);
- } else {
- vehiclePurchasing = null;
- }
-
- vehiclePurchasePosition = position;
-}
-
-// ===========================================================================
-
-function processVehicleFires() {
- /*
- let vehicles = getElementsByType(ELEMENT_VEHICLE);
- for(let i in vehicles) {
- if(vehicles[i].isSyncer) {
- if(!doesEntityDataExist(vehicles[i], "vrr.fire")) {
- triggerNetworkEvent("vrr.vehFire", vehicles[i].id);
- } else {
- vehicles[i].health = 249;
- }
- }
- }
- */
+function getServerData() {
+ return serverData;
}
// ===========================================================================
\ No newline at end of file
diff --git a/scripts/client/vehicle.js b/scripts/client/vehicle.js
index 2b28e5a2..3011f195 100644
--- a/scripts/client/vehicle.js
+++ b/scripts/client/vehicle.js
@@ -7,11 +7,124 @@
// TYPE: Client (JavaScript)
// ===========================================================================
-function receiveVehicleFromServer(vehicleId, position, model, colour1, colour2, colour3 = 0, colour4 = 0) {
- logToConsole(LOG_DEBUG, `[VRR.Job] Received vehicle ${vehicleId} (${getVehicleNameFromModel(model, getGame())}) from server`);
+class VehicleData {
+ constructor(vehicleId, model, position, heading, colour1, colour2, colour3, colour4, locked, lights, engine, licensePlate) {
+ this.index = -1;
+ this.vehicleId = vehicleId;
+ this.model = model;
+ this.position = position;
+ this.heading = heading;
+ this.colour1 = colour1;
+ this.colour2 = colour2;
+ this.colour3 = colour3;
+ this.colour4 = colour4;
+ this.pickupModel = pickupModel;
+ this.locked = locked;
+ this.lights = lights;
+ this.engine = engine;
+ this.licensePlate = licensePlate;
+ this.ivNetworkId = -1;
+ }
+}
- if(getGame() == VRR_GAME_GTA_IV) {
+// ===========================================================================
+function receiveVehicleFromServer(vehicleId, position, model, colour1, colour2, colour3 = 0, colour4 = 0, locked = false, lights = false, engine = false, licensePlate = "") {
+ logToConsole(LOG_DEBUG, `[VRR.Vehicle] Received vehicle ${vehicleId} (${getVehicleNameFromModel(model, getGame())}) from server`);
+
+ if(getGame() != VRR_GAME_GTA_IV) {
+ return false;
+ }
+
+ if(getVehicleData(vehicleId) != false) {
+ let vehicleData = getVehicleData(vehicleId);
+ //vehicleData.position = position;
+ //vehicleData.heading = heading;
+ //vehicleData.model
+ vehicleData.colour1 = colour1;
+ vehicleData.colour2 = colour2;
+ vehicleData.colour3 = colour3;
+ vehicleData.colour4 = colour4;
+ vehicleData.engine = engine;
+ vehicleData.lights = lights;
+ vehicleData.locked = locked;
+ vehicleData.licensePlate = "";
+
+ let vehicle = natives.getVehicleFromNetworkId(vehicleId.ivNetworkId);
+ } else {
+ //logToConsole(LOG_DEBUG, `[VRR.Vehicle] Vehicle ${vehicleId} doesn't exist. Adding ...`);
+ //let tempVehicleData = new VehicleData(vehicleId, name, position, blipModel, pickupModel);
+
+ //vehicles.push(tempVehicleData);
+ //setAllJobDataIndexes();
+ }
+}
+
+// ===========================================================================
+
+function processVehiclePurchasing() {
+ if(vehiclePurchaseState == VRR_VEHBUYSTATE_TESTDRIVE) {
+ if(getLocalPlayerVehicle() == false) {
+ vehiclePurchaseState = VRR_VEHBUYSTATE_EXITVEH;
+ sendNetworkEventToServer("vrr.vehBuyState", VRR_VEHBUYSTATE_EXITVEH);
+ return false;
+ } else {
+ if(vehiclePurchasing == getLocalPlayerVehicle()) {
+ if(getDistance(getLocalPlayerVehicle().position, vehiclePurchasePosition) >= 25) {
+ vehiclePurchaseState = VRR_VEHBUYSTATE_FARENOUGH;
+ sendNetworkEventToServer("vrr.vehBuyState", VRR_VEHBUYSTATE_FARENOUGH);
+ }
+ } else {
+ vehiclePurchaseState = VRR_VEHBUYSTATE_WRONGVEH;
+ sendNetworkEventToServer("vrr.vehBuyState", VRR_VEHBUYSTATE_WRONGVEH);
+ }
+ }
+ }
+}
+
+// ===========================================================================
+
+function processVehicleBurning() {
+ getElementsByType(ELEMENT_VEHICLE).filter(vehicle => vehicle.isSyncer && vehicle.health < 250).forEach((vehicle) => {
+ vehicle.health = 250;
+ });
+}
+
+// ===========================================================================
+
+function setVehiclePurchaseState(state, vehicleId, position) {
+ vehiclePurchaseState = state;
+
+ if(vehicleId != null) {
+ vehiclePurchasing = getElementFromId(vehicleId);
+ } else {
+ vehiclePurchasing = null;
+ }
+
+ vehiclePurchasePosition = position;
+}
+
+// ===========================================================================
+
+/**
+ * @param {number} vehicleId - The ID of the job (initially provided by server)
+ * @return {VehicleData} The vehicle's data (class instance)
+ */
+ function getVehicleData(vehicleId) {
+ for(let i in getServerData().vehicles) {
+ if(getServerData().vehicles[i].vehicleId == vehicleId) {
+ return getServerData().vehicles[i];
+ }
+ }
+
+ return false;
+}
+
+// ===========================================================================
+
+function setAllVehicleDataIndexes() {
+ for(let i in getServerData().vehicles) {
+ getServerData().vehicles[i].index = i;
}
}
diff --git a/scripts/server/accent.js b/scripts/server/accent.js
index 41cea951..f5709db0 100644
--- a/scripts/server/accent.js
+++ b/scripts/server/accent.js
@@ -8,30 +8,30 @@
// ===========================================================================
function getPlayerAccentText(client) {
- return getPlayerCurrentSubAccount(client).accent;
+ return getPlayerCurrentSubAccount(client).accent;
}
// ===========================================================================
function setPlayerAccentText(client, text) {
- getPlayerCurrentSubAccount(client).accent = text;
+ getPlayerCurrentSubAccount(client).accent = text;
}
// ===========================================================================
function doesPlayerHaveAccent(client) {
- return (getPlayerCurrentSubAccount(client).accent != "");
+ return (getPlayerCurrentSubAccount(client).accent != "");
}
// ===========================================================================
function getPlayerAccentInlineOutput(client) {
- let outputText = "";
- if(doesPlayerHaveAccent(client)) {
- outputText = `[${getPlayerAccentText(client)}] `;
- }
+ let outputText = "";
+ if(doesPlayerHaveAccent(client)) {
+ outputText = `[${getPlayerAccentText(client)}] `;
+ }
- return outputText;
+ return outputText;
}
// ===========================================================================
@@ -63,7 +63,7 @@ function listAccentsCommand(command, params, client) {
let chunkedList = splitArrayIntoChunks(accentList, 8);
- messagePlayerInfo(client, makeChatBoxSectionHeader(getLocaleString(client, "AccentList")));
+ messagePlayerInfo(client, makeChatBoxSectionHeader(getLocaleString(client, "AccentsListHeader")));
for(let i in chunkedList) {
messagePlayerInfo(client, chunkedList[i].join(", "));
}
@@ -91,7 +91,7 @@ function getAccentFromParams(params) {
function reloadAccentConfigurationCommand(command, params, client) {
getGlobalConfig().accents = loadAccentConfig();
- messageAdmins(`${client.name} {MAINCOLOUR}has reloaded the accent list`);
+ messageAdmins(`{adminOrange}${getPlayerName(client)} {MAINCOLOUR}has reloaded the accent list`);
}
// ===========================================================================
@@ -111,7 +111,7 @@ function addAccentCommand(command, params, client) {
getGlobalConfig().accents.push(newAccentName);
saveAccentConfig();
- messageAdmins(`${client.name}{MAINCOLOUR} added a new accent: ${newAccentName}`);
+ messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} added a new accent: {ALTCOLOUR}${newAccentName}{MAINCOLOUR}`);
}
// ===========================================================================
@@ -131,7 +131,7 @@ function removeAccentCommand(command, params, client) {
getGlobalConfig().accents.push(newAccentName);
saveAccentConfig();
- messageAdmins(`${client.name}{MAINCOLOUR} added a new accent: ${newAccentName}`);
+ messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} removed an accent: {ALTCOLOUR}${newAccentName}{MAINCOLOUR}`);
}
// ===========================================================================
\ No newline at end of file
diff --git a/scripts/server/account.js b/scripts/server/account.js
index 87be5779..c3b9f551 100644
--- a/scripts/server/account.js
+++ b/scripts/server/account.js
@@ -92,15 +92,16 @@ function toggleAutoSelectLastCharacterCommand(command, params, client) {
// ===========================================================================
function toggleAccountGUICommand(command, params, client) {
+ // Remember, the flag is BACKWARD. Enabled = NO GUI!
let flagValue = getAccountSettingsFlagValue("NoGUI");
- if(!doesPlayerHaveGUIEnabled(client)) {
- getPlayerData(client).accountData.settings = removeBitFlag(getPlayerData(client).accountData.settings, flagValue);
- messagePlayerNormal(client, getLocaleString(client, "GUIAccountSettingToggle", `{softRed}${toUpperCase(getLocaleString(client, "Off"))}`));
- logToConsole(LOG_DEBUG, `[VRR.Account] ${getPlayerDisplayForConsole(client)} has toggled GUI for their account ON.`);
- } else {
+ if(doesPlayerHaveGUIEnabled(client)) {
getPlayerData(client).accountData.settings = addBitFlag(getPlayerData(client).accountData.settings, flagValue);
- messagePlayerNormal(client, getLocaleString(client, "GUIAccountSettingToggle", `{softGreen}${toUpperCase(getLocaleString(client, "On"))}`));
+ messagePlayerNormal(client, getLocaleString(client, "GUIAccountSettingToggle", `{softRed}${toUpperCase(getLocaleString(client, "Off"))}{MAINCOLOUR}`));
+ logToConsole(LOG_DEBUG, `[VRR.Account] ${getPlayerDisplayForConsole(client)} has toggled GUI for their account OFF.`);
+ } else {
+ getPlayerData(client).accountData.settings = removeBitFlag(getPlayerData(client).accountData.settings, flagValue);
+ messagePlayerNormal(client, getLocaleString(client, "GUIAccountSettingToggle", `{softGreen}${toUpperCase(getLocaleString(client, "On"))}{MAINCOLOUR}`));
logToConsole(LOG_DEBUG, `[VRR.Account] ${getPlayerDisplayForConsole(client)} has toggled GUI for their account ON.`);
}
@@ -111,7 +112,7 @@ function toggleAccountGUICommand(command, params, client) {
logToConsole(LOG_DEBUG, `[VRR.Account] ${getPlayerDisplayForConsole(client)} is being shown the login GUI`);
} else {
hideAllPlayerGUI(client);
- messagePlayerNormal(client, `👋 Welcome back to ${getServerName()}, ${getPlayerName(client)}! Please /login to continue.`, getColourByName("softGreen"));
+ messagePlayerNormal(client, getLocaleString(client, "WelcomeBack", getServerName(), getPlayerName(client), "{ALTCOLOUR}/login{MAINCOLOUR}"));
logToConsole(LOG_DEBUG, `[VRR.Account] ${getPlayerDisplayForConsole(client)} is being shown the login message (GUI disabled)`);
}
} else {
@@ -120,7 +121,7 @@ function toggleAccountGUICommand(command, params, client) {
logToConsole(LOG_DEBUG, `[VRR.Account] ${getPlayerDisplayForConsole(client)} is being shown the register GUI`);
} else {
hideAllPlayerGUI(client);
- messagePlayerNormal(client, `👋 Welcome to ${getServerName()}, ${getPlayerName(client)}! Please /register to continue.`, getColourByName("softGreen"));
+ messagePlayerNormal(client, getLocaleString(client, "WelcomeNewPlayer", getServerName(), getPlayerName(client), "{ALTCOLOUR}/register{MAINCOLOUR}"));
logToConsole(LOG_DEBUG, `[VRR.Account] ${getPlayerDisplayForConsole(client)} is being shown the register message (GUI disabled)`);
}
}
@@ -133,13 +134,13 @@ function toggleAccountGUICommand(command, params, client) {
function toggleAccountLoginAttemptNotificationsCommand(command, params, client) {
let flagValue = getAccountSettingsFlagValue("AuthAttemptAlert");
- if(hasBitFlag(getPlayerData(client).accountData.settings, flagValue)) {
+ if(doesPlayerHaveLoginAlertsEnabled(client)) {
getPlayerData(client).accountData.settings = removeBitFlag(getPlayerData(client).accountData.settings, flagValue);
- messagePlayerNormal(client, `⚙️ You will ${getBoolRedGreenInlineColour(true)}now {MAINCOLOUR}be notified by email when somebody tries to login to your account`);
+ messagePlayerNormal(client, `⚙️ You turned ${getBoolRedGreenInlineColour(false)}OFF{MAINCOLOUR} notification by email when somebody tries to login to your account`);
logToConsole(LOG_DEBUG, `[VRR.Account] ${getPlayerDisplayForConsole(client)} has toggled the login attempt email notifications OFF for their account`);
} else {
getPlayerData(client).accountData.settings = addBitFlag(getPlayerData(client).accountData.settings, flagValue);
- messagePlayerNormal(client, `⚙️ You will ${getBoolRedGreenInlineColour(false)}not {MAINCOLOUR}be notified by email when somebody tries to login to your account`);
+ messagePlayerNormal(client, `⚙️ You turned ${getBoolRedGreenInlineColour(true)}ON{MAINCOLOUR} notification by email when somebody tries to login to your account`);
logToConsole(LOG_DEBUG, `[VRR.Account] ${getPlayerDisplayForConsole(client)} has toggled the login attempt email notifications OFF for their account`);
}
@@ -153,14 +154,14 @@ function toggleAccountServerLogoCommand(command, params, client) {
if(!doesPlayerHaveLogoEnabled(client)) {
getPlayerData(client).accountData.settings = removeBitFlag(getPlayerData(client).accountData.settings, flagValue);
- messagePlayerNormal(client, `⚙️ You will ${getBoolRedGreenInlineColour(true)}now {MAINCOLOUR}be shown the server logo (if enabled on current server)`);
+ messagePlayerSuccess(client, getLocaleString(client, "AccountServerLogoSet", `${getBoolRedGreenInlineColour(true)}${getLocaleString(client, "On")}{MAINCOLOUR}`));
logToConsole(LOG_DEBUG, `[VRR.Account] ${getPlayerDisplayForConsole(client)} has toggled the server logo ON for their account`);
if(getServerConfig().showLogo) {
updatePlayerShowLogoState(client, true);
}
} else {
getPlayerData(client).accountData.settings = addBitFlag(getPlayerData(client).accountData.settings, flagValue);
- messagePlayerNormal(client, `⚙️ You will ${getBoolRedGreenInlineColour(false)}not {MAINCOLOUR}be shown the server logo.`);
+ messagePlayerSuccess(client, getLocaleString(client, "AccountServerLogoSet", `${getBoolRedGreenInlineColour(false)}${getLocaleString(client, "Off")}{MAINCOLOUR}`));
logToConsole(LOG_DEBUG, `[VRR.Account] ${getPlayerDisplayForConsole(client)} has toggled the server logo OFF for their account`);
updatePlayerShowLogoState(client, false);
}
@@ -189,11 +190,11 @@ function toggleAccountTwoFactorAuthCommand(command, params, client) {
if(!doesPlayerHaveTwoFactorAuthEnabled(client)) {
getPlayerData(client).accountData.settings = addBitFlag(getPlayerData(client).accountData.settings, flagValue);
- messagePlayerSuccess(client, `{MAINCOLOUR}You have turned ${getBoolRedGreenInlineColour(false)}ON {MAINCOLOUR} two factor authentication!{ALTCOLOUR}${addtoAuthenticatorCode}`);
+ messagePlayerSuccess(client, getLocaleString(client, "TwoFactorAuthSet", `${getBoolRedGreenInlineColour(true)}${getLocaleString(client, "On")}{MAINCOLOUR}`));
logToConsole(LOG_DEBUG, `[VRR.Account] ${getPlayerDisplayForConsole(client)} has toggled two-factor authentication ON for their account`);
} else {
getPlayerData(client).accountData.settings = removeBitFlag(getPlayerData(client).accountData.settings, flagValue);
- messagePlayerSuccess(client, `You have turned ${getBoolRedGreenInlineColour(false)}OFF {MAINCOLOUR}two-factor authentication for login.`);
+ messagePlayerSuccess(client, getLocaleString(client, "TwoFactorAuthSet", `${getBoolRedGreenInlineColour(false)}${toUpperCase(getLocaleString(client, "Off"))}{MAINCOLOUR}`));
logToConsole(LOG_DEBUG, `[VRR.Account] ${getPlayerDisplayForConsole(client)} has toggled two-factor authentication OFF for their account`);
}
return true;
@@ -203,7 +204,7 @@ function toggleAccountTwoFactorAuthCommand(command, params, client) {
function registerCommand(command, params, client) {
if(isPlayerRegistered(client)) {
- messagePlayerError(client, `Your name is already registered!`);
+ messagePlayerError(client, getLocaleString(client, "AccountNameAlreadyRegistered"));
return false;
}
@@ -235,8 +236,8 @@ function changeAccountPasswordCommand(command, params, client) {
}
if(!doesPasswordMeetRequirements(newPassword)) {
- messagePlayerError(client, `The new password must meet the requirements!`);
- messagePlayerInfo(client, `Passwords must have at least one capital letter, one lowercase letter, and one number!`);
+ messagePlayerError(client, getLocaleString(client, "PasswordNotGoodEnough"));
+ messagePlayerInfo(client, getLocaleString(client, "PasswordNeedsBase", `${getLocaleString(client, "PasswordNeedsCapitals", getGlobalConfig().passwordRequiredCapitals)}, ${getLocaleString(client, "PasswordNeedsSymbols", getGlobalConfig().passwordRequiredSymbols)}`));
return false;
}
@@ -253,12 +254,12 @@ function setAccountChatScrollLinesCommand(command, params, client) {
}
if(isNaN(params)) {
- messagePlayerError(client, `The line amount must be a number!`);
+ messagePlayerError(client, getLocaleString(client, "ChatScrollLinesNotNumber"));
return false;
}
if(toInteger(params) < 1 || toInteger(params) > 6) {
- messagePlayerError(client, `The line amount must be between 1 and 6!`);
+ messagePlayerError(client, getLocaleString(client, "ChatScrollLinesMustBeBetween", getGlobalConfig().minChatLines, getGlobalConfig().maxChatLines));
return false;
}
@@ -266,7 +267,27 @@ function setAccountChatScrollLinesCommand(command, params, client) {
getPlayerData(client).accountData.chatScrollLines = lines;
sendPlayerChatScrollLines(client, lines);
- messagePlayerSuccess(client, `Your chatbox will now scroll ${toInteger(lines)} lines at a time!`);
+ messagePlayerSuccess(client, getLocaleString(client, "ChatScrollLinesSet", lines));
+}
+
+// ===========================================================================
+
+function setAccountChatAutoHideDelayCommand(command, params, client) {
+ if(areParamsEmpty(params)) {
+ messagePlayerSyntax(client, getCommandSyntaxText(command));
+ return false;
+ }
+
+ if(isNaN(params)) {
+ messagePlayerError(client, `The delay time must be a number!`);
+ return false;
+ }
+
+ let delay = Math.ceil(toInteger(params));
+
+ getPlayerData(client).accountData.chatAutoHideDelay = delay;
+ sendPlayerChatAutoHideDelay(client, delay);
+ messagePlayerSuccess(client, `Your chatbox will now automatically hide after ${toInteger(delay)} seconds!`);
}
// ===========================================================================
@@ -280,7 +301,7 @@ function setAccountEmailCommand(command, params, client) {
let emailAddress = getParam(params, " ", 1);
if(!isValidEmailAddress(emailAddress)) {
- messagePlayerError(client, `The email '${emailAddress} is not valid!`);
+ messagePlayerError(client, getLocaleString(client, "RegistrationFailedInvalidEmail"));
return false;
}
@@ -290,7 +311,7 @@ function setAccountEmailCommand(command, params, client) {
//}
if(getPlayerData(client).accountData.emailAddress != "" && isAccountEmailVerified(getPlayerData(client).accountData)) {
- messagePlayerError(client, `You already set your email and verified it!`);
+ messagePlayerError(client, getLocaleString(client, "AccountEmailAlreadySetAndVerified"));
return false;
}
@@ -300,9 +321,9 @@ function setAccountEmailCommand(command, params, client) {
setAccountEmailVerificationCode(getPlayerData(client).accountData, emailVerificationCode);
sendEmailVerificationEmail(client, emailVerificationCode);
- messagePlayerSuccess(client, `Your email has been set!`);
- messagePlayerAlert(client, `Please verify your email to enable extra account security and recovery features.`);
- messagePlayerAlert(client, `A verification code and instructions have been sent to your email.`);
+ messagePlayerSuccess(client, getLocaleString(client, "EmailSet"));
+ messagePlayerAlert(client, getLocaleString(client, "RegistrationEmailVerifyReminder"));
+ messagePlayerAlert(client, getLocaleString(client, "EmailVerificationCodeSent"));
saveAccountToDatabase(getPlayerData(client).accountData);
}
@@ -322,7 +343,7 @@ function verifyAccountEmailCommand(command, params, client) {
}
if(module.hashing.sha512(verificationCode) != getPlayerData(client).accountData.emailVerificationCode) {
- messagePlayerError(client, `Invalid email verification code! A new one has been created and sent to your email.`);
+ messagePlayerError(client, getLocaleString(client, "InvalidEmailVerificationCode"));
let emailVerificationCode = generateEmailVerificationCode();
setAccountEmailVerificationCode(getPlayerData(client).accountData, emailVerificationCode);
sendEmailVerificationEmail(client, emailVerificationCode);
@@ -332,8 +353,8 @@ function verifyAccountEmailCommand(command, params, client) {
getPlayerData(client).accountData.flags.moderation = addBitFlag(getPlayerData(client).accountData.flags.moderation, getModerationFlagValue("EmailVerified"));
getPlayerData(client).accountData.emailVerificationCode = "";
- messagePlayerSuccess(client, `Your email has been verified!`);
- messagePlayerAlert(client, `You can now use your email for password resets, two-factor authentication, alerts, and more!`);
+ messagePlayerSuccess(client, getLocaleString(client, "EmailVerified"));
+ messagePlayerAlert(client, getLocaleString(client, "EmailVerifiedTip"));
saveAccountToDatabase(getPlayerData(client).accountData);
}
@@ -563,13 +584,14 @@ function loginSuccess(client) {
if(doesPlayerHaveStaffPermission(client, "Developer") || doesPlayerHaveStaffPermission(client, "ManageServer")) {
logToConsole(LOG_WARN, `[VRR.Account] ${getPlayerDisplayForConsole(client)} has needed permissions and is being given administrator access`);
- client.administrator = true;
+ setPlayerNativeAdminState(client, true);
}
if(doesServerHaveTesterOnlyEnabled()) {
if(!hasBitFlag(getPlayerData(client).accountData.flags.moderation, getModerationFlagValue("IsTester"))) {
setTimeout(function() {
- client.disconnect();
+ getPlayerData(client).customDisconnectReason = "Kicked - Not a tester";
+ disconnectPlayer(client);
}, 3500);
if(doesServerHaveGUIEnabled() && doesPlayerHaveGUIEnabled(client)) {
@@ -580,13 +602,13 @@ function loginSuccess(client) {
logToConsole(LOG_DEBUG, `[VRR.Account] ${getPlayerDisplayForConsole(client)} is being shown the "not a tester" error message (GUI disabled).`);
messagePlayerError(client, getLocaleString(client, "NotATester"));
return false;
- }
+ }
}
}
if(getPlayerData(client).subAccounts.length == 0) {
if(doesServerHaveGUIEnabled() && doesPlayerHaveGUIEnabled(client)) {
- showPlayerPromptGUI(client, getLocaleString(client, "NoCharactersGUIMessage"), getLocaleString(client, "NoCharactersGUIWindowTitle"));
+ showPlayerPrompt(client, getLocaleString(client, "NoCharactersGUIMessage"), getLocaleString(client, "NoCharactersGUIWindowTitle"), getLocaleString(client, "Yes"), getLocaleString(client, "No"));
getPlayerData(client).promptType = VRR_PROMPT_CREATEFIRSTCHAR;
logToConsole(LOG_DEBUG, `[VRR.Account] ${getPlayerDisplayForConsole(client)} is being shown the no characters prompt GUI`);
} else {
@@ -597,11 +619,20 @@ function loginSuccess(client) {
showCharacterSelectToClient(client);
}
- getPlayerData(client).accountData.ipAddress = client.ip;
-
+ getPlayerData(client).accountData.ipAddress = getPlayerIP(client);
sendPlayerChatScrollLines(client, getPlayerData(client).accountData.chatScrollLines);
- messagePlayerNormal(null, `👋 ${getPlayerName(client)} has joined the server`, getColourByName("softYellow"));
+ messageDiscordChatChannel(`👋 ${getPlayerName(client)} has joined the server`);
+
+ //let countryName = "Unknown";
+ //if(getCountryNameFromIP(getPlayerIP(client))) {
+ // countryName = getCountryNameFromIP(getPlayerIP(client));
+ //}
+
+ //let clients = getClients();
+ //for(let i in clients) {
+ // messagePlayerNormal(clients[i], getLocaleString(clients[i], "PlayerJoinedServer", `{ALTCOLOUR}${getPlayerName(client)}{MAINCOLOUR}`, `{ALTCOLOUR}${countryName}{MAINCOLOUR}`), getColourByName("softYellow"));
+ //}
}
// ===========================================================================
@@ -636,6 +667,7 @@ function saveAccountToDatabase(accountData) {
["acct_svr_staff_flags", accountData.flags.admin],
["acct_svr_mod_flags", accountData.flags.moderation],
["acct_svr_chat_scroll_lines", accountData.chatScrollLines],
+ ["acct_svr_chat_auto_hide_delay", accountData.chatAutoHideDelay],
];
let queryString1 = createDatabaseUpdateQuery("acct_main", data, `acct_id=${accountData.databaseId}`);
@@ -772,7 +804,7 @@ function createAccount(name, password, email = "") {
function checkLogin(client, password) {
getPlayerData(client).loginAttemptsRemaining = getPlayerData(client).loginAttemptsRemaining-1;
if(getPlayerData(client).loginAttemptsRemaining <= 0) {
- client.disconnect();
+ disconnectPlayer(client);
}
if(isPlayerLoggedIn(client)) {
@@ -808,8 +840,8 @@ function checkLogin(client, password) {
logToConsole(LOG_DEBUG, `[VRR.Account] ${getPlayerDisplayForConsole(client)} is being shown the login message (GUI disabled) with ${getPlayerData(client).loginAttemptsRemaining} login attempts remaining alert.`);
}
- if(isAccountEmailVerified(getPlayerData(client).accountData) && isAccountSettingFlagEnabled(getPlayerData(client).accountData, getAccountSettingsFlagValue("AuthAttemptAlert"))) {
- sendAccountLoginFailedNotification(getPlayerData(client).accountData.emailAddress, client.name, client.ip, getServerGame());
+ if(isAccountEmailVerified(getPlayerData(client).accountData) && !isAccountSettingFlagEnabled(getPlayerData(client).accountData, getAccountSettingsFlagValue("AuthAttemptAlert"))) {
+ sendAccountLoginFailedNotification(getPlayerData(client).accountData.emailAddress, getPlayerName(client), getPlayerIP(client), getGame());
}
return false;
}
@@ -824,17 +856,18 @@ function checkLogin(client, password) {
logToConsole(LOG_DEBUG, `[VRR.Account] ${getPlayerDisplayForConsole(client)} is being shown the login message (GUI disabled) with ${getPlayerData(client).loginAttemptsRemaining} login attempts remaining alert.`);
}
- if(isAccountEmailVerified(getPlayerData(client).accountData) && isAccountSettingFlagEnabled(getPlayerData(client).accountData, getAccountSettingsFlagValue("AuthAttemptAlert"))) {
- sendAccountLoginFailedNotification(getPlayerData(client).accountData.emailAddress, client.name, client.ip, getServerGame());
+ if(isAccountEmailVerified(getPlayerData(client).accountData) && !isAccountSettingFlagEnabled(getPlayerData(client).accountData, getAccountSettingsFlagValue("AuthAttemptAlert"))) {
+ sendAccountLoginFailedNotification(getPlayerData(client).accountData.emailAddress, getPlayerName(client), getPlayerIP(client), getGame());
}
return false;
}
- //if(doesPlayerHaveTwoFactorAuthEnabled(client)) {
- // getPlayerData(client).twoFactorAuthCode = toUpperCase(generateRandomString(6));
- // showPlayerTwoFactorAuthenticationGUI(client);
- // return true;
- //}
+ if(doesPlayerHaveTwoFactorAuthEnabled(client) && checkForSMTPModule() && getEmailConfig().enabled) {
+ getPlayerData(client).twoFactorAuthCode = toUpperCase(generateRandomString(6));
+ showPlayerTwoFactorAuthenticationGUI(client);
+ sendAccountTwoFactorAuthCode(getPlayerData(client).accountData.emailAddress, getPlayerName(client), getPlayerData(client).twoFactorAuthCode);
+ return true;
+ }
if(doesServerHaveGUIEnabled() && doesPlayerHaveGUIEnabled(client)) {
showPlayerLoginSuccessGUI(client);
@@ -842,8 +875,8 @@ function checkLogin(client, password) {
loginSuccess(client);
- if(isAccountEmailVerified(getPlayerData(client).accountData) && isAccountSettingFlagEnabled(getPlayerData(client).accountData, getAccountSettingsFlagValue("AuthAttemptAlert"))) {
- sendAccountLoginSuccessNotification(getPlayerData(client).accountData.emailAddress, client.name, client.ip, getServerGame());
+ if(isAccountEmailVerified(getPlayerData(client).accountData) && !isAccountSettingFlagEnabled(getPlayerData(client).accountData, getAccountSettingsFlagValue("AuthAttemptAlert"))) {
+ sendAccountLoginSuccessNotification(getPlayerData(client).accountData.emailAddress, getPlayerName(client), getPlayerIP(client), getGame());
}
}
@@ -915,13 +948,13 @@ function checkRegistration(client, password, confirmPassword = "", emailAddress
} else {
messagePlayerError(client, "Password doesn't meet requirements!");
}
- return false
+ return false;
}
if(doesServerHaveGUIEnabled() && doesPlayerHaveGUIEnabled(client)) {
if(!isValidEmailAddress(emailAddress)) {
showPlayerRegistrationFailedGUI(client, getLocaleString(client, "RegistrationFailedInvalidEmail"));
- return false
+ return false;
}
}
@@ -947,11 +980,11 @@ function checkRegistration(client, password, confirmPassword = "", emailAddress
setAccountEmailVerificationCode(getPlayerData(client).accountData, emailVerificationCode);
sendEmailVerificationEmail(client, emailVerificationCode);
logToConsole(LOG_WARN, `${getPlayerDisplayForConsole(client)} was sent a registration email verification code`);
- }
+ }
if(doesServerHaveTesterOnlyEnabled() && !isPlayerATester(client)) {
setTimeout(function() {
- client.disconnect();
+ disconnectPlayer(client);
}, 5000);
if(doesServerHaveGUIEnabled() && doesPlayerHaveGUIEnabled(client)) {
@@ -962,13 +995,13 @@ function checkRegistration(client, password, confirmPassword = "", emailAddress
logToConsole(LOG_DEBUG, `[VRR.Account] ${getPlayerDisplayForConsole(client)} is being shown the "not a tester" error message (GUI disabled).`);
messagePlayerError(client, getLocaleString(client, "NotATester"));
return false;
- }
+ }
} else {
messagePlayerAlert(client, getLocaleString(client, "RegistrationCreateCharReminder"));
if(doesServerHaveGUIEnabled() && doesPlayerHaveGUIEnabled(client)) {
showPlayerRegistrationSuccessGUI(client);
- showPlayerPromptGUI(client, getLocaleString(client, "NoCharactersMessage"), getLocaleString(client, "NoCharactersWindowTitle"), getLocaleString(client, "Yes"), getLocaleString(client, "No"));
+ showPlayerPrompt(client, getLocaleString(client, "NoCharactersMessage"), getLocaleString(client, "NoCharactersWindowTitle"), getLocaleString(client, "Yes"), getLocaleString(client, "No"));
getPlayerData(client).promptType = VRR_PROMPT_CREATEFIRSTCHAR;
} else {
messagePlayerAlert(client, getLocaleString(client, "NoCharactersChatMessage"), `{ALTCOLOUR}/newchar{MAINCOLOUR}`);
@@ -979,27 +1012,52 @@ function checkRegistration(client, password, confirmPassword = "", emailAddress
// ===========================================================================
function checkAccountResetPasswordRequest(client, inputText) {
- if(getPlayerData(client).passwordResetState == VRR_RESETPASS_STATE_NONE) {
- if(toLowerCase(getPlayerData(client).accountData.emailAddress) != toLowerCase(inputText)) {
- logToConsole(LOG_DEBUG|LOG_WARN, `${getPlayerDisplayForConsole(client)} failed to reset their password (email not correct)`);
- return false;
+ if(!checkForSMTPModule() || !getEmailConfig().enabled) {
+ return false;
+ }
+
+ switch(getPlayerData(client).passwordResetState) {
+ case VRR_RESETPASS_STATE_EMAILCONFIRM: {
+ if(toLowerCase(getPlayerData(client).accountData.emailAddress) != toLowerCase(inputText)) {
+ logToConsole(LOG_INFO|LOG_WARN, `${getPlayerDisplayForConsole(client)} failed to reset their password (email not correct)`);
+ showPlayerErrorGUI(client, getLocaleString(client, "GUIErrorResetPasswordFailedInvalidEmail"), getLocaleString(client, "GUIErrorTitle"), getLocaleString(client, "GUIOkButton"));
+ return false;
+ }
+
+ let passwordResetCode = toUpperCase(generateEmailVerificationCode());
+ getPlayerData(client).passwordResetState = VRR_RESETPASS_STATE_CODEINPUT;
+ getPlayerData(client).passwordResetCode = passwordResetCode;
+ showPlayerResetPasswordCodeInputGUI(client);
+ sendPasswordResetEmail(client, passwordResetCode);
+ logToConsole(LOG_INFO, `${getPlayerDisplayForConsole(client)} submitted successful email for password reset. Sending email and awaiting verification code input ...`);
+ break;
}
- let passwordResetCode = toUpperCase(generateEmailVerificationCode());
- getPlayerData(client).passwordResetState = VRR_RESETPASS_STATE_CODEINPUT;
- getPlayerData(client).passwordResetCode = passwordResetCode;
- sendPasswordResetEmail(client, passwordResetCode);
- showPlayerResetPasswordCodeInputGUI(client);
- logToConsole(LOG_DEBUG|LOG_WARN, `${getPlayerDisplayForConsole(client)} reset their password. Awaiting verification code input ...`);
- } else if(getPlayerData(client).passwordResetState == VRR_RESETPASS_STATE_CODEINPUT) {
- if(getPlayerData(client).passwordResetCode == toUpperCase(inputText)) {
- getPlayerData(client).passwordResetState = VRR_RESETPASS_STATE_SETPASS;
- showPlayerChangePasswordGUI(client);
- logToConsole(LOG_DEBUG, `${getPlayerDisplayForConsole(client)} entered the correct reset password verification code. Awaiting new password input ...`);
- } else {
- getPlayerData(client).passwordResetState = VRR_RESETPASS_STATE_NONE;
- client.disconnect();
- logToConsole(LOG_DEBUG|LOG_WARN, `${getPlayerDisplayForConsole(client)} failed to reset their password (verification code not correct)`);
+ case VRR_RESETPASS_STATE_CODEINPUT: {
+ if(inputText != "") {
+ if(getPlayerData(client).passwordResetCode == toUpperCase(inputText)) {
+ getPlayerData(client).passwordResetState = VRR_RESETPASS_STATE_SETPASS;
+ showPlayerChangePasswordGUI(client, getLocaleString(client));
+ logToConsole(LOG_INFO, `${getPlayerDisplayForConsole(client)} entered the correct reset password verification code. Awaiting new password input ...`);
+ } else {
+ getPlayerData(client).passwordResetState = VRR_RESETPASS_STATE_NONE;
+ getPlayerData(client).passwordResetAttemptsRemaining = getPlayerData(client).passwordResetAttemptsRemaining - 1;
+ logToConsole(LOG_INFO|LOG_WARN, `${getPlayerDisplayForConsole(client)} failed to reset their password (verification code not correct, ${getPlayerData(client).passwordResetAttemptsRemaining} attempts remaining)`);
+ if(getPlayerData(client).passwordResetAttemptsRemaining <= 0) {
+ logToConsole(LOG_INFO|LOG_WARN, `${getPlayerDisplayForConsole(client)} failed to reset their password (verification code not correct, no more attempts remaining, kicking ...)`);
+ disconnectPlayer(client);
+ return false;
+ }
+ }
+ }
+ break;
+ }
+
+ case VRR_RESETPASS_STATE_NONE: {
+ logToConsole(LOG_INFO, `${getPlayerDisplayForConsole(client)} requested a password reset. Awaiting email input ...`);
+ showPlayerResetPasswordEmailInputGUI(client);
+ getPlayerData(client).passwordResetState = VRR_RESETPASS_STATE_EMAILCONFIRM;
+ break;
}
}
@@ -1012,7 +1070,7 @@ function checkAccountChangePassword(client, newPassword, confirmNewPassword) {
if(!isPlayerLoggedIn(client)) {
if(getPlayerData(client).passwordResetState != VRR_RESETPASS_STATE_SETPASS) {
//getPlayerData(client).passwordResetState = VRR_RESETPASS_STATE_NONE;
- //client.disconnect();
+ //disconnectPlayer(client);
logToConsole(LOG_DEBUG|LOG_WARN, `${getPlayerDisplayForConsole(client)} failed to change their password (not logged in or not using reset password)`);
return false;
}
@@ -1063,7 +1121,7 @@ function isValidEmailAddress(emailAddress) {
// ===========================================================================
-function saveAllClientsToDatabase() {
+function saveAllPlayersToDatabase() {
logToConsole(LOG_DEBUG, "[VRR.Account]: Saving all clients to database ...");
getClients().forEach(function(client) {
savePlayerToDatabase(client);
@@ -1078,7 +1136,7 @@ function savePlayerToDatabase(client) {
return false;
}
- if(!getPlayerData(client).loggedIn) {
+ if(!isPlayerLoggedIn(client)) {
return false;
}
@@ -1088,8 +1146,8 @@ function savePlayerToDatabase(client) {
if(getPlayerData(client).currentSubAccount != -1) {
//let subAccountData = getPlayerCurrentSubAccount(client);
- if(client.player != null) {
- if(getPlayerData(client).returnToPosition != null) {
+ if(getPlayerPed(client) != null) {
+ if(getPlayerData(client).returnToPosition != null && getPlayerData(client).returnToType != VRR_RETURNTO_TYPE_ADMINGET) {
getPlayerCurrentSubAccount(client).spawnPosition = getPlayerData(client).returnToPosition;
getPlayerCurrentSubAccount(client).spawnHeading = getPlayerData(client).returnToHeading.z;
getPlayerCurrentSubAccount(client).interior = getPlayerData(client).returnToInterior;
@@ -1111,40 +1169,55 @@ function savePlayerToDatabase(client) {
// ===========================================================================
function initClient(client) {
+ logToConsole(LOG_DEBUG, `[VRR.Account] Initializing client ${getPlayerDisplayForConsole(client)} ...`);
+
if(isConsole(client)) {
+ logToConsole(LOG_DEBUG|LOG_ERROR, `[VRR.Account] Client initialization failed for ${getPlayerDisplayForConsole(client)}! (is console client)`);
return false;
}
- if(client.getData("vrr.isInitialized") != null || client.getData("vrr.isInitialized") == true) {
+ logToConsole(LOG_DEBUG, `[VRR.Account] Initializing client ${getPlayerDisplayForConsole(client)} ...`);
+
+ if(playerInitialized[client.index] == true) {
+ logToConsole(LOG_DEBUG|LOG_ERROR, `[VRR.Account] Client initialization failed for ${getPlayerDisplayForConsole(client)}! (already initialized)`);
return false;
}
- client.setData("vrr.isInitialized", true, false);
+ setEntityData(client, "vrr.isInitialized", true, false);
sendPlayerGUIColours(client);
+
+ logToConsole(LOG_DEBUG, `[VRR.Account] Initializing GUI for ${getPlayerDisplayForConsole(client)} ...`);
sendPlayerGUIInit(client);
updatePlayerSnowState(client);
+ logToConsole(LOG_DEBUG, `[VRR.Account] Showing connect camera to ${getPlayerDisplayForConsole(client)} ...`);
showConnectCameraToPlayer(client);
+
messageClient(`Please wait ...`, client, getColourByName("softGreen"));
+ logToConsole(LOG_DEBUG, `[VRR.Account] Waiting for 2.5 seconds to prevent race attack ...`);
setTimeout(function() {
if(client != null) {
-
clearChatBox(client);
+ logToConsole(LOG_DEBUG, `[VRR.Account] Loading account for ${getPlayerDisplayForConsole(client)}`);
let tempAccountData = loadAccountFromName(getPlayerName(client), true);
+
+ logToConsole(LOG_DEBUG, `[VRR.Account] Loading subaccounts for ${getPlayerDisplayForConsole(client)}`);
let tempSubAccounts = loadSubAccountsFromAccount(tempAccountData.databaseId);
- getServerData().clients[client.index] = new ClientData(client, tempAccountData, tempSubAccounts);
+ getServerData().clients[getPlayerId(client)] = new ClientData(client, tempAccountData, tempSubAccounts);
- getServerData().clients[client.index].sessionId = saveConnectionToDatabase(client);
- getServerData().clients[client.index].connectTime = getCurrentUnixTimestamp();
+ getServerData().clients[getPlayerId(client)].sessionId = saveConnectionToDatabase(client);
+ getServerData().clients[getPlayerId(client)].connectTime = getCurrentUnixTimestamp();
requestClientInfo(client);
if(tempAccountData != false) {
- if(isAccountAutoIPLoginEnabled(tempAccountData) && getPlayerData(client).accountData.ipAddress == client.ip) {
+ sendPlayerLocaleId(client, getPlayerData(client).accountData.locale);
+ if(isAccountAutoIPLoginEnabled(tempAccountData) && getPlayerData(client).accountData.ipAddress == getPlayerIP(client)) {
messagePlayerAlert(client, getLocaleString(client, "AutoLoggedInIP"));
loginSuccess(client);
+ playRadioStreamForPlayer(client, getServerIntroMusicURL(), true, getPlayerStreamingRadioVolume(client));
} else {
if(doesServerHaveGUIEnabled() && doesPlayerHaveGUIEnabled(client)) {
logToConsole(LOG_DEBUG, `[VRR.Account] ${getPlayerDisplayForConsole(client)} is being shown the login GUI.`);
@@ -1152,10 +1225,17 @@ function initClient(client) {
} else {
logToConsole(LOG_DEBUG, `[VRR.Account] ${getPlayerDisplayForConsole(client)} is being shown the login message (GUI disabled).`);
messagePlayerNormal(client, getLocaleString(client, "WelcomeBack", getServerName(), getPlayerName(client), "/login"),getColourByName("softGreen"));
+
+ //if(checkForGeoIPModule()) {
+ // let iso = module.geoip.getCountryISO(getPlayerIP(client));
+ // let localeId = getLocaleFromCountryISO(iso);
+ //}
+ //showGameMessage(client, getLocaleString(client, "LocaleOffer", `/lang ${getLocaleData(localeId)[2]}`), getColourByName("white"), 10000, "Roboto");
}
playRadioStreamForPlayer(client, getServerIntroMusicURL(), true, getPlayerStreamingRadioVolume(client));
}
} else {
+ sendPlayerLocaleId(client, 0);
if(doesServerHaveGUIEnabled() && doesPlayerHaveGUIEnabled(client)) {
logToConsole(LOG_DEBUG, `[VRR.Account] ${getPlayerDisplayForConsole(client)} is being shown the register GUI.`);
showPlayerRegistrationGUI(client);
@@ -1166,9 +1246,12 @@ function initClient(client) {
playRadioStreamForPlayer(client, getServerIntroMusicURL(), true, getPlayerStreamingRadioVolume(client));
}
- getServerData().clients[client.index].keyBinds = loadAccountKeybindsFromDatabase(getServerData().clients[client.index].accountData.databaseId);
+ getServerData().clients[getPlayerId(client)].keyBinds = loadAccountKeybindsFromDatabase(getServerData().clients[getPlayerId(client)].accountData.databaseId);
sendAccountKeyBindsToClient(client);
+
+
}
+
}, 2500);
}
@@ -1178,7 +1261,7 @@ function saveConnectionToDatabase(client) {
let dbConnection = connectToDatabase();
if(dbConnection) {
let safeName = escapeDatabaseString(dbConnection, getPlayerName(client));
- let dbQueryString = `INSERT INTO conn_main (conn_when_connect, conn_server, conn_script_version, conn_game_version, conn_client_version, conn_name, conn_ip) VALUES (NOW(), ${getServerConfig().databaseId}, '${scriptVersion}', '${client.gameVersion}', '0.0.0', '${safeName}', '${client.ip}')`;
+ let dbQueryString = `INSERT INTO conn_main (conn_when_connect, conn_server, conn_script_version, conn_game_version, conn_client_version, conn_name, conn_ip) VALUES (NOW(), ${getServerConfig().databaseId}, '${scriptVersion}', '${getPlayerGameVersion(client)}', '0.0.0', '${safeName}', '${getPlayerIP(client)}')`;
queryDatabase(dbConnection, dbQueryString);
return getDatabaseInsertId(dbConnection);
}
@@ -1365,14 +1448,14 @@ function isAccountEmailVerified(accountData) {
// ===========================================================================
-function isAccountTwoFactorAuthenticationVerified(accountData) {
- return hasBitFlag(accountData.flags.moderation, getModerationFlagValue("TwoFactorAuthVerified"));
+function doesPlayerHaveTwoFactorAuthEnabled(client) {
+ return hasBitFlag(getPlayerData(client).accountData.settings, getAccountSettingsFlagValue("TwoStepAuth"));
}
// ===========================================================================
-function doesPlayerHaveTwoFactorAuthEnabled(client) {
- return hasBitFlag(getPlayerData(client).accountData.flags.settings, getAccountSettingsFlagValue("TwoFactorAuth"));
+function doesPlayerHaveLoginAlertsEnabled(client) {
+ return hasBitFlag(getPlayerData(client).accountData.settings, getAccountSettingsFlagValue("AuthAttemptAlert"));
}
// ===========================================================================
@@ -1430,7 +1513,7 @@ function verifyAccountEmail(accountData, verificationCode) {
// ===========================================================================
-function sendAccountLoginFailedNotification(emailAddress, name, ip, game = getServerGame()) {
+function sendAccountLoginFailedNotification(emailAddress, name, ip, game = getGame()) {
let countryName = module.geoip.getCountryName(getGlobalConfig().geoIPCountryDatabaseFilePath, ip);
let subDivisionName = module.geoip.getSubdivisionName(getGlobalConfig().geoIPCityDatabaseFilePath, ip);
let cityName = module.geoip.getCityName(getGlobalConfig().geoIPCityDatabaseFilePath, ip);
@@ -1438,7 +1521,7 @@ function sendAccountLoginFailedNotification(emailAddress, name, ip, game = getSe
let emailBodyText = getEmailConfig().bodyContent.accountAuthFailAlert;
emailBodyText = emailBodyText.replace("{GAMENAME}", getGameName(game));
emailBodyText = emailBodyText.replace("{IPADDRESS}", ip);
- emailBodyText = emailBodyText.replace("{LOCATION}", `${cityName}, ${countryName}, ${countryName}`);
+ emailBodyText = emailBodyText.replace("{LOCATION}", `${cityName}, ${subDivisionName}, ${countryName}`);
emailBodyText = emailBodyText.replace("{SERVERNAME}", getServerName());
emailBodyText = emailBodyText.replace("{TIMESTAMP}", date.toLocaleString('en-US'));
@@ -1448,7 +1531,7 @@ function sendAccountLoginFailedNotification(emailAddress, name, ip, game = getSe
// ===========================================================================
-function sendAccountLoginSuccessNotification(emailAddress, name, ip, game = getServerGame()) {
+function sendAccountLoginSuccessNotification(emailAddress, name, ip, game = getGame()) {
let countryName = module.geoip.getCountryName(getGlobalConfig().geoIPCountryDatabaseFilePath, ip);
let subDivisionName = module.geoip.getSubdivisionName(getGlobalConfig().geoIPCityDatabaseFilePath, ip);
let cityName = module.geoip.getCityName(getGlobalConfig().geoIPCityDatabaseFilePath, ip);
@@ -1486,7 +1569,7 @@ function checkPlayerTwoFactorAuthentication(client, authCode) {
}
}
- client.disconnect();
+ disconnectPlayer(client);
return false;
}
@@ -1496,4 +1579,16 @@ function isPlayerATester(client) {
}
+// ===========================================================================
+
+function sendAccountTwoFactorAuthCode(emailAddress, name, twoFactorAuthCode) {
+ let emailBodyText = getEmailConfig().bodyContent.twoFactorAuthentication;
+ emailBodyText = emailBodyText.replace("{2FACODE}", twoFactorAuthCode);
+ emailBodyText = emailBodyText.replace("{GAMENAME}", getGameName(getGame()));
+ emailBodyText = emailBodyText.replace("{SERVERNAME}", getServerName());
+
+ sendEmail(emailAddress, name, `Login code for ${getServerName()}`, emailBodyText);
+ return true;
+}
+
// ===========================================================================
\ No newline at end of file
diff --git a/scripts/server/animation.js b/scripts/server/animation.js
index 4c18f00f..6d722ef9 100644
--- a/scripts/server/animation.js
+++ b/scripts/server/animation.js
@@ -20,17 +20,17 @@ function playPlayerAnimationCommand(command, params, client) {
return false;
}
-let animationSlot = getAnimationFromParams(getParam(params, " ", 1));
- let animationPositionOffset = 1;
+ let animationSlot = getAnimationFromParams(getParam(params, " ", 1));
+ let animationPositionOffset = 1;
if(!animationSlot) {
- messagePlayerError(client, getLocaleString(client, "AnimationNotFound"));
- messagePlayerInfo(client, getLocaleString(client, "AnimationHelpTip"), `{ALTCOLOUR}/animlist{MAINCOLOUR}`);
+ messagePlayerError(client, getLocaleString(client, "InvalidAnimation"));
+ messagePlayerInfo(client, getLocaleString(client, "AnimationCommandTip", `{ALTCOLOUR}/animlist{MAINCOLOUR}`));
return false;
}
if(toInteger(animationPositionOffset) < 0 || toInteger(animationPositionOffset) > 3) {
- messagePlayerError(client, getLocaleString(client, "AnimationInvalidDistance"));
+ messagePlayerError(client, getLocaleString(client, "InvalidAnimationDistance"));
return false;
}
@@ -39,7 +39,7 @@ let animationSlot = getAnimationFromParams(getParam(params, " ", 1));
}
if(isPlayerHandCuffed(client) || isPlayerTazed(client) || isPlayerInForcedAnimation(client)) {
- messagePlayerError(client, `You aren't able to do that`);
+ messagePlayerError(client, getLocaleString(client, "UnableToDoThat"));
return false;
}
@@ -51,26 +51,26 @@ let animationSlot = getAnimationFromParams(getParam(params, " ", 1));
function stopPlayerAnimationCommand(command, params, client) {
if(isPlayerHandCuffed(client) || isPlayerTazed(client) || isPlayerInForcedAnimation(client)) {
- messagePlayerError(client, `You aren't able to do that`);
+ messagePlayerError(client, getLocaleString(client, "UnableToDoThat"));
return false;
}
setPlayerPosition(client, getPlayerData(client).currentAnimationPositionReturnTo);
- makePedStopAnimation(getPlayerData(client).ped);
+ makePedStopAnimation(getPlayerPed(client));
getPlayerData(client).currentAnimation = -1;
getPlayerData(client).currentAnimationPositionOffset = false;
getPlayerData(client).currentAnimationPositionReturnTo = false;
- getPlayerData(client).animationStart = 0;
+ getPlayerData(client).animationStart = 0;
getPlayerData(client).animationForced = false;
- setPlayerMouseCameraState(client, false);
+ //setPlayerMouseCameraState(client, false);
}
// ===========================================================================
function showAnimationListCommand(command, params, client) {
- let animList = getGameConfig().animations[getServerGame()].map(function(x) { return x[0]; });
+ let animList = getGameConfig().animations[getGame()].map(function(x) { return x.name; });
let chunkedList = splitArrayIntoChunks(animList, 10);
@@ -87,8 +87,8 @@ function showAnimationListCommand(command, params, client) {
* @param {number} animationSlot - The slot index of the animation
* @return {Array} The animation's data (array)
*/
-function getAnimationData(animationSlot, gameId = getServerGame()) {
- return getGameConfig().animations[gameId][animationSlot];
+function getAnimationData(animationSlot, gameId = getGame()) {
+ return getGameConfig().animations[gameId][animationSlot];
}
// ===========================================================================
@@ -100,14 +100,14 @@ function isPlayerInForcedAnimation(client) {
// ===========================================================================
function makePlayerPlayAnimation(client, animationSlot, offsetPosition = 1) {
- getPlayerData(client).currentAnimation = animationSlot;
+ getPlayerData(client).currentAnimation = animationSlot;
getPlayerData(client).currentAnimationPositionOffset = offsetPosition;
getPlayerData(client).currentAnimationPositionReturnTo = getPlayerPosition(client);
- getPlayerData(client).animationStart = getCurrentUnixTimestamp();
+ getPlayerData(client).animationStart = getCurrentUnixTimestamp();
getPlayerData(client).animationForced = false;
- makePedPlayAnimation(getPlayerData(client).ped, animationSlot, offsetPosition);
-
+ makePedPlayAnimation(getPlayerPed(client), animationSlot, offsetPosition);
+ setEntityData(getPlayerPed(client), "vrr.anim", animationSlot, true);
//if(getAnimationData(animationSlot)[9] != VRR_ANIMMOVE_NONE) {
// if(getGame() < VRR_GAME_GTA_SA) {
// setPlayerMouseCameraState(client, true);
@@ -118,40 +118,41 @@ function makePlayerPlayAnimation(client, animationSlot, offsetPosition = 1) {
// ===========================================================================
function forcePlayerPlayAnimation(client, animationSlot, offsetPosition = 1) {
- getPlayerData(client).currentAnimation = animationSlot;
+ getPlayerData(client).currentAnimation = animationSlot;
getPlayerData(client).currentAnimationPositionOffset = offsetPosition;
getPlayerData(client).currentAnimationPositionReturnTo = getPlayerPosition(client);
- getPlayerData(client).animationStart = getCurrentUnixTimestamp();
+ getPlayerData(client).animationStart = getCurrentUnixTimestamp();
getPlayerData(client).animationForced = true;
setPlayerControlState(client, false);
- forcePedAnimation(getPlayerData(client).ped, animationSlot, offsetPosition);
+ forcePedAnimation(getPlayerPed(client), animationSlot, offsetPosition);
}
// ===========================================================================
function makePlayerStopAnimation(client) {
//setPlayerPosition(client, getPlayerData(client).currentAnimationPositionReturnTo);
- makePedStopAnimation(getPlayerData(client).ped);
+ makePedStopAnimation(getPlayerPed(client));
getPlayerData(client).currentAnimation = -1;
getPlayerData(client).currentAnimationPositionOffset = false;
getPlayerData(client).currentAnimationPositionReturnTo = false;
- getPlayerData(client).animationStart = 0;
+ getPlayerData(client).animationStart = 0;
getPlayerData(client).animationForced = false;
}
// ===========================================================================
function getAnimationFromParams(params) {
+ let animations = getGameConfig().animations[getGame()];
if(isNaN(params)) {
- for(let i in getGameConfig().animations[getServerGame()]) {
- if(toLowerCase(getGameConfig().animations[getServerGame()][i][0]).indexOf(toLowerCase(params)) != -1) {
+ for(let i in animations) {
+ if(toLowerCase(animations[i].name).indexOf(toLowerCase(params)) != -1) {
return i;
}
}
} else {
- if(typeof getGameConfig().animations[getServerGame()][params] != "undefined") {
+ if(typeof getGameConfig().animations[getGame()][params] != "undefined") {
return toInteger(params);
}
}
diff --git a/scripts/server/anticheat.js b/scripts/server/anticheat.js
index 38ff2b63..9cf7fafb 100644
--- a/scripts/server/anticheat.js
+++ b/scripts/server/anticheat.js
@@ -8,14 +8,14 @@
// ===========================================================================
function initAntiCheatScript() {
- logToConsole(LOG_DEBUG, "[VRR.AntiCheat]: Initializing anticheat script ...");
+ logToConsole(LOG_DEBUG, "[VRR.AntiCheat]: Initializing anticheat script ...");
logToConsole(LOG_DEBUG, "[VRR.AntiCheat]: Anticheat script initialized!");
}
// ===========================================================================
function clearPlayerStateToEnterExitProperty(client) {
- if(getPlayerData(client).pedState != VRR_PEDSTATE_READY) {
+ if(getPlayerData(client).pedState != VRR_PEDSTATE_READY) {
if(getPlayerData(client).pedState == VRR_PEDSTATE_ENTERINGVEHICLE) {
sendPlayerClearPedState(client);
getPlayerData(client).pedState = VRR_PEDSTATE_READY;
diff --git a/scripts/server/ban.js b/scripts/server/ban.js
index fc4db510..6f42cd31 100644
--- a/scripts/server/ban.js
+++ b/scripts/server/ban.js
@@ -7,8 +7,6 @@
// TYPE: Server (JavaScript)
// ===========================================================================
-// ===========================================================================
-
function initBanScript() {
logToConsole(LOG_INFO, "[VRR.Ban]: Initializing ban script ...");
logToConsole(LOG_INFO, "[VRR.Ban]: Ban script initialized!");
@@ -39,7 +37,7 @@ function accountBanCommand(command, params, client) {
logToConsole(LOG_WARN, `[VRR.Ban]: ${getPlayerDisplayForConsole(targetClient)} (${getPlayerData(targetClient).accountData.name}) account was banned by ${getPlayerDisplayForConsole(client)}. Reason: ${reason}`);
- messageAdminAction(`{ALTCOLOUR}${getPlayerData(targetClient).currentSubAccountData.name} {MAINCOLOUR}has been account banned.`);
+ announceAdminAction(`PlayerAccountBanned`, `{ALTCOLOUR}${getPlayerName(client)}{MAINCOLOUR}`);
banAccount(getPlayerData(targetClient).accountData.databaseId, getPlayerData(client).accountData.databaseId, reason);
disconnectPlayer(client);
}
@@ -69,7 +67,7 @@ function subAccountBanCommand(command, params, client, fromDiscord) {
logToConsole(LOG_WARN, `[VRR.Ban]: ${getPlayerDisplayForConsole(targetClient)} (${getPlayerData(targetClient).accountData.name})'s subaccount was banned by ${getPlayerDisplayForConsole(client)}. Reason: ${reason}`);
- messageAdminAction(`{ALTCOLOUR}${getPlayerData(targetClient).currentSubAccountData.name} {MAINCOLOUR}has been character banned.`);
+ announceAdminAction(`PlayerCharacterBanned`, `{ALTCOLOUR}${getPlayerName(client)}{MAINCOLOUR}`);
banSubAccount(getPlayerData(targetClient).currentSubAccountData.databaseId, getPlayerData(client).accountData.databaseId, reason);
disconnectPlayer(client);
@@ -98,11 +96,11 @@ function ipBanCommand(command, params, client, fromDiscord) {
return false;
}
- messageAdminAction(`{ALTCOLOUR}${getPlayerData(targetClient).currentSubAccountData.name} {MAINCOLOUR}has been IP banned.`);
- banIPAddress(targetClient.ip, getPlayerData(client).accountData.databaseId, reason);
+ announceAdminAction(`PlayerIPBanned`, `{ALTCOLOUR}${getPlayerName(targetClient)}{MAINCOLOUR}`);
+ banIPAddress(getPlayerIP(targetClient), getPlayerData(client).accountData.databaseId, reason);
- server.banIP(targetClient.ip);
- targetClient.disconnect();
+ serverBanIP(getPlayerIP(targetClient));
+ disconnectPlayer(targetClient);
}
// ===========================================================================
@@ -129,10 +127,10 @@ function subNetBanCommand(command, params, client, fromDiscord) {
return false;
}
- messageAdminAction(`{ALTCOLOUR}${getPlayerData(targetClient).currentSubAccountData.name} {MAINCOLOUR}has been subnet banned`);
- banSubNet(targetClient.ip, getSubNet(targetClient.ip, octetAmount), getPlayerData(client).accountData.databaseId, reason);
+ announceAdminAction(`PlayerSubNetBanned`, `{ALTCOLOUR}${getPlayerName(client)}{MAINCOLOUR}`);
+ banSubNet(getPlayerIP(targetClient), getSubNet(getPlayerIP(targetClient), octetAmount), getPlayerData(client).accountData.databaseId, reason);
- server.banIP(targetClient.ip);
+ serverBanIP(getPlayerIP(targetClient));
}
// ===========================================================================
@@ -254,13 +252,9 @@ function unbanSubNet(ipAddressStart, ipAddressEnd, adminAccountId) {
// ===========================================================================
function isAccountBanned(accountId) {
- let bans = getServerData().bans;
- for(let i in bans) {
- if(bans[i].type == VRR_BANTYPE_ACCOUNT) {
- if(bans[i].detail == accountId) {
- return true;
- }
- }
+ let bans = getServerData().bans.filter(ban => ban.type === VRR_BANTYPE_ACCOUNT && ban.detail === accountId);
+ if(bans.length > 0) {
+ return true;
}
return false;
@@ -269,13 +263,9 @@ function isAccountBanned(accountId) {
// ===========================================================================
function isSubAccountBanned(subAccountId) {
- let bans = getServerData().bans;
- for(let i in bans) {
- if(bans[i].type == VRR_BANTYPE_SUBACCOUNT) {
- if(bans[i].detail == subAccountId) {
- return true;
- }
- }
+ let bans = getServerData().bans.filter(ban => ban.type === VRR_BANTYPE_SUBACCOUNT && ban.detail === subAccountId);
+ if(bans.length > 0) {
+ return true;
}
return false;
@@ -284,13 +274,9 @@ function isSubAccountBanned(subAccountId) {
// ===========================================================================
function isIpAddressBanned(ipAddress) {
- let bans = getServerData().bans;
- for(let i in bans) {
- if(bans[i].type == VRR_BANTYPE_IPADDRESS) {
- if(bans[i].detail == ipAddress) {
- return true;
- }
- }
+ let bans = getServerData().bans.filter(ban => ban.type === VRR_BANTYPE_IPADDRESS && ban.detail === ipAddress);
+ if(bans.length > 0) {
+ return true;
}
return false;
diff --git a/scripts/server/bitflag.js b/scripts/server/bitflag.js
index b095c2e8..01085c73 100644
--- a/scripts/server/bitflag.js
+++ b/scripts/server/bitflag.js
@@ -7,8 +7,6 @@
// TYPE: Server (JavaScript)
// ===========================================================================
-// ===========================================================================
-
let serverBitFlags = {
staffFlags: {},
moderationFlags: {},
@@ -21,7 +19,6 @@ let serverBitFlags = {
npcTriggerTypeFlags: {},
npcTriggerConditionTypesFlags: {},
npcTriggerResponseTypeFlags: {},
- serverSettings: {}
};
// ===========================================================================
@@ -41,6 +38,8 @@ let serverBitFlagKeys = {
"ManageWorld",
"ManageAntiCheat",
"Developer",
+ "ManageNPCs",
+ "ManageRaces",
],
moderationFlagKeys: [
"None",
@@ -119,6 +118,8 @@ let serverBitFlagKeys = {
"NoRandomTips",
"NoActionTips",
],
+
+ // Not going to be used. Use trigger, condition, and response stuff in trigger.js
npcTriggerTypeKeys: [
"None",
"FarProximity", // Comes within a far distance of NPC
@@ -219,26 +220,6 @@ let serverBitFlagKeys = {
"ShowItemsAfterPurchase",
"BuyCommandAfterEnterBusiness",
],
- serverSettingsKeys: [
- "None",
- "GUI",
- "ServerLogo",
- "FallingSnow",
- "GroundSnow",
- "Anticheat",
- "CheckGameScripts",
- "GameScriptBlackList",
- "GameScriptWhiteList",
- "JobBlips",
- "JobPickups",
- "BusinessBlips",
- "BusinessPickups",
- "HouseBlips",
- "HousePickups",
- "DiscordBot",
- "RealTime",
- "Testing",
- ],
};
// ===========================================================================
@@ -255,47 +236,12 @@ function initBitFlagScript() {
serverBitFlags.npcTriggerTypes = createBitFlagTable(serverBitFlagKeys.npcTriggerTypeKeys);
serverBitFlags.npcTriggerConditionTypes = createBitFlagTable(serverBitFlagKeys.npcTriggerConditionTypeKeys);
serverBitFlags.npcTriggerResponseTypes = createBitFlagTable(serverBitFlagKeys.npcTriggerResponseTypeKeys);
- serverBitFlags.serverSettings = createBitFlagTable(serverBitFlagKeys.serverSettingsKeys);
logToConsole(LOG_INFO, "[VRR.BitFlag]: Bit flag script initialized successfully!");
return true;
}
// ===========================================================================
-function createBitFlagTable(keyNames) {
- let bitVal = 0;
- let bitTable = {};
- let incVal = 1;
-
- for(let i in keyNames) {
- let key = keyNames[i];
- bitTable[key] = bitVal;
- bitVal = 1 << incVal;
- incVal++;
- }
- return bitTable;
-}
-
-// ===========================================================================
-
-function hasBitFlag(allFlags, checkForFlag) {
- if(allFlags == 0) {
- return false;
- }
-
- if(allFlags == -1) {
- return true;
- }
-
- if((allFlags & checkForFlag) == checkForFlag) {
- return true;
- }
-
- return false;
-}
-
-// ===========================================================================
-
function doesPlayerHaveStaffPermission(client, requiredFlags) {
if(isConsole(client)) {
return true;
@@ -311,15 +257,15 @@ function doesPlayerHaveStaffPermission(client, requiredFlags) {
}
// -1 is automatic override (having -1 for staff flags is basically god mode admin level)
- if(staffFlags == getStaffFlagValue("All")) {
- return true;
- }
+ if(staffFlags == getStaffFlagValue("All")) {
+ return true;
+ }
- if(hasBitFlag(staffFlags, requiredFlags)) {
- return true;
- }
+ if(hasBitFlag(staffFlags, requiredFlags)) {
+ return true;
+ }
- return false;
+ return false;
}
// ===========================================================================
@@ -341,22 +287,22 @@ function doesPlayerHaveClanPermission(client, requiredFlags) {
clanFlags = getPlayerCurrentSubAccount(client).clanFlags | getClanRankFlags(getPlayerCurrentSubAccount(client).clanRank);
// -1 is automatic override (having -1 for staff flags is basically god mode admin level)
- if(clanFlags == getClanFlagValue("All")) {
- return true;
- }
+ if(clanFlags == getClanFlagValue("All")) {
+ return true;
+ }
- if(hasBitFlag(clanFlags, requiredFlags)) {
- return true;
- }
+ if(hasBitFlag(clanFlags, requiredFlags)) {
+ return true;
+ }
- return false;
+ return false;
}
// ===========================================================================
function getStaffFlagValue(flagName) {
- if(flagName == "All") {
- return -1;
+ if(flagName == "All") {
+ return -1;
}
if(typeof serverBitFlags.staffFlags[flagName] == "undefined") {
@@ -369,8 +315,8 @@ function getStaffFlagValue(flagName) {
// ===========================================================================
function getClanFlagValue(flagName) {
- if(flagName == "All") {
- return -1;
+ if(flagName == "All") {
+ return -1;
}
if(typeof getServerBitFlags().clanFlags[flagName] == "undefined") {
@@ -383,8 +329,8 @@ function getClanFlagValue(flagName) {
// ===========================================================================
function getAccountSettingsFlagValue(flagName) {
- if(flagName == "All") {
- return -1;
+ if(flagName == "All") {
+ return -1;
}
if(typeof serverBitFlags.accountSettingsFlags[flagName] == "undefined") {
@@ -397,8 +343,8 @@ function getAccountSettingsFlagValue(flagName) {
// ===========================================================================
function getModerationFlagValue(flagName) {
- if(flagName == "All") {
- return -1;
+ if(flagName == "All") {
+ return -1;
}
if(typeof serverBitFlags.moderationFlags[flagName] == "undefined") {
@@ -410,20 +356,6 @@ function getModerationFlagValue(flagName) {
// ===========================================================================
-function getServerSettingsFlagValue(flagName) {
- if(flagName == "All") {
- return -1;
- }
-
- if(typeof serverBitFlags.serverSettings[flagName] == "undefined") {
- return false;
- }
-
- return serverBitFlags.serverSettings[flagName];
-}
-
-// ===========================================================================
-
function givePlayerStaffFlag(client, flagName) {
if(!getStaffFlagValue(flagName)) {
return false;
@@ -447,18 +379,6 @@ function takePlayerStaffFlag(client, flagName) {
// ===========================================================================
-function addBitFlag(allFlags, flagValue) {
- return allFlags | flagValue;
-}
-
-// ===========================================================================
-
-function removeBitFlag(allFlags, flagValue) {
- return allFlags ^ flagValue;
-}
-
-// ===========================================================================
-
function takePlayerStaffFlag(client, flagName) {
if(!getStaffFlagValue(flagName)) {
return false;
@@ -487,20 +407,4 @@ function getServerBitFlagKeys() {
return serverBitFlagKeys;
}
-// ===========================================================================
-
-function createBitwiseTable(tableKeys) {
- let bitVal = 0;
- let bitTable = {};
- let incVal = 1;
-
- for(let i in tableKeys) {
- let key = tableKeys[i];
- bitTable[key] = bitVal;
- bitVal = 1 << incVal;
- incVal++;
- }
- return bitTable;
-}
-
// ===========================================================================
\ No newline at end of file
diff --git a/scripts/server/business.js b/scripts/server/business.js
index 9335ea09..29944f8a 100644
--- a/scripts/server/business.js
+++ b/scripts/server/business.js
@@ -9,16 +9,8 @@
function initBusinessScript() {
logToConsole(LOG_INFO, "[VRR.Business]: Initializing business script ...");
- getServerData().businesses = loadBusinessesFromDatabase();
-
- createAllBusinessPickups();
- createAllBusinessBlips();
-
- setAllBusinessIndexes();
- cacheAllBusinessItems();
-
logToConsole(LOG_INFO, "[VRR.Business]: Business script initialized successfully!");
return true;
}
@@ -57,10 +49,10 @@ function loadBusinessesFromDatabase() {
if(dbQuery.numRows > 0) {
while(dbAssoc = fetchQueryAssoc(dbQuery)) {
let tempBusinessData = new BusinessData(dbAssoc);
- tempBusinessData.locations = loadBusinessLocationsFromDatabase(tempBusinessData.databaseId);
+ //tempBusinessData.locations = loadBusinessLocationsFromDatabase(tempBusinessData.databaseId);
//tempBusinessData.gameScripts = loadBusinessGameScriptsFromDatabase(tempBusinessData.databaseId);
tempBusinesses.push(tempBusinessData);
- logToConsole(LOG_INFO, `[VRR.Business]: Business '${tempBusinessData.name}' (ID ${tempBusinessData.databaseId}) loaded from database successfully!`);
+ logToConsole(LOG_VERBOSE, `[VRR.Business]: Business '${tempBusinessData.name}' (ID ${tempBusinessData.databaseId}) loaded from database successfully!`);
}
}
freeDatabaseQuery(dbQuery);
@@ -138,24 +130,32 @@ function loadBusinessGameScriptsFromDatabase(businessId) {
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function createBusinessCommand(command, params, client) {
- let tempBusinessData = createBusiness(params, getPlayerPosition(client), toVector3(0.0, 0.0, 0.0), getGameConfig().pickupModels[getServerGame()].Business, getGameConfig().blipSprites[getServerGame()].Business, getPlayerInterior(client), getPlayerDimension(client));
- tempBusinessData.needsSaved = true;
- let businessId = getServerData().businesses.push(tempBusinessData);
- setAllBusinessIndexes();
+ createBusiness(params, getPlayerPosition(client), toVector3(0.0, 0.0, 0.0), getGameConfig().pickupModels[getGame()].Business, -1, getPlayerInterior(client), getPlayerDimension(client), getPlayerData(client).interiorCutscene);
- saveAllBusinessesToDatabase();
-
- createBusinessEntrancePickup(businessId-1);
- createBusinessExitPickup(businessId-1);
- createBusinessEntranceBlip(businessId-1);
- createBusinessExitBlip(businessId-1);
-
- messageAdmins(`{ALTCOLOUR}${getPlayerName(client)} {MAINCOLOUR}created business {businessBlue}${tempBusinessData.name}`);
+ messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} created business: {businessBlue}${params}`);
}
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function createBusinessLocationCommand(command, params, client) {
if(!isPlayerSpawned(client)) {
messagePlayerError(client, "You must be spawned to use this command!");
@@ -163,7 +163,7 @@ function createBusinessLocationCommand(command, params, client) {
}
let locationType = toString(getParam(params, " ", 1));
- let businessId = (isPlayerInAnyBusiness(getParam(params, " ", 2))) ? getPlayerBusiness(client) : getClosestBusinessEntrance(getPlayerPosition(client));
+ let businessId = getPlayerBusiness(client);
if(!areParamsEmpty(params)) {
businessId = getBusinessFromParams(params);
@@ -177,12 +177,12 @@ function createBusinessLocationCommand(command, params, client) {
let tempBusinessLocationData = createBusinessLocation(locationType, businessId);
getServerData().businesses[businessId].push(tempBusinessLocationData);
- messageAdmins(`{ALTCOLOUR}${getPlayerName(client)} {MAINCOLOUR}created location {businessBlue}${params} {MAINCOLOUR}for business {businessBlue}${tempBusinessData.name}`);
+ messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} created location {businessBlue}${params}{MAINCOLOUR} for business {businessBlue}${tempBusinessData.name}`);
}
// ===========================================================================
-function createBusiness(name, entrancePosition, exitPosition, entrancePickupModel = -1, entranceBlipModel = -1, entranceInteriorId = 0, entranceVirtualWorld = 0, exitInteriorId = -1, exitVirtualWorld = -1, exitPickupModel = -1, exitBlipModel = -1) {
+function createBusiness(name, entrancePosition, exitPosition, entrancePickupModel = -1, entranceBlipModel = -1, entranceInterior = 0, entranceDimension = 0, entranceCutscene = -1) {
let tempBusinessData = new BusinessData(false);
tempBusinessData.name = name;
@@ -190,21 +190,40 @@ function createBusiness(name, entrancePosition, exitPosition, entrancePickupMode
tempBusinessData.entranceRotation = 0.0;
tempBusinessData.entrancePickupModel = entrancePickupModel;
tempBusinessData.entranceBlipModel = entranceBlipModel;
- tempBusinessData.entranceInterior = entranceInteriorId;
- tempBusinessData.entranceDimension = entranceVirtualWorld;
+ tempBusinessData.entranceInterior = entranceInterior;
+ tempBusinessData.entranceDimension = entranceDimension;
+ tempBusinessData.entranceCutscene = entranceCutscene;
tempBusinessData.exitPosition = exitPosition;
tempBusinessData.exitRotation = 0.0;
- tempBusinessData.exitPickupModel = exitPickupModel;
- tempBusinessData.exitBlipModel = exitBlipModel;
- tempBusinessData.exitInterior = exitInteriorId;
- tempBusinessData.exitDimension = exitVirtualWorld;
+ tempBusinessData.exitPickupModel = 0;
+ tempBusinessData.exitBlipModel = -1;
+ tempBusinessData.exitInterior = 0;
+ tempBusinessData.exitDimension = 0;
+ tempBusinessData.exitCutscene = -1;
+
+ tempBusinessData.needsSaved = true;
+ let businessId = getServerData().businesses.push(tempBusinessData);
+ setBusinessDataIndexes();
+ saveAllBusinessesToDatabase();
+
+ createBusinessPickups(businessId-1);
+ createBusinessBlips(businessId-1);
return tempBusinessData;
}
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function deleteBusinessCommand(command, params, client) {
let businessId = getPlayerBusiness(client);
@@ -217,12 +236,21 @@ function deleteBusinessCommand(command, params, client) {
return false;
}
- messageAdmins(`{ALTCOLOUR}${getPlayerName(client)} {MAINCOLOUR}deleted business {businessBlue}${getBusinessData(businessId).name}`);
+ messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} deleted business {businessBlue}${getBusinessData(businessId).name}`);
deleteBusiness(businessId, getPlayerData(client).accountData.databaseId);
}
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function deleteBusinessLocationCommand(command, params, client) {
//let businessId = toInteger(getParam(params, " ", 2));
//deleteBusinessLocation(businessId);
@@ -231,6 +259,15 @@ function deleteBusinessLocationCommand(command, params, client) {
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function setBusinessNameCommand(command, params, client) {
let newBusinessName = toString(params);
@@ -242,7 +279,7 @@ function setBusinessNameCommand(command, params, client) {
}
if(!canPlayerManageBusiness(client, businessId)) {
- messagePlayerError(client, "You can't change the name of this business!");
+ messagePlayerError(client, getLocaleString(client, "CantModifyBusiness"));
return false;
}
@@ -250,11 +287,20 @@ function setBusinessNameCommand(command, params, client) {
getBusinessData(businessId).name = newBusinessName;
setEntityData(getBusinessData(businessId).entrancePickup, "vrr.label.name", getBusinessData(businessId).name, true);
getBusinessData(businessId).needsSaved = true;
- messageAdmins(`{ALTCOLOUR}${getPlayerName(client)} {MAINCOLOUR}renamed business {businessBlue}${oldBusinessName} {MAINCOLOUR}to {businessBlue}${newBusinessName}`);
+ messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} renamed business {businessBlue}${oldBusinessName}{MAINCOLOUR} to {businessBlue}${newBusinessName}`);
}
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function setBusinessOwnerCommand(command, params, client) {
if(areParamsEmpty(params)) {
messagePlayerSyntax(client, getCommandSyntaxText(command));
@@ -275,7 +321,7 @@ function setBusinessOwnerCommand(command, params, client) {
}
if(!canPlayerManageBusiness(client, businessId)) {
- messagePlayerError(client, "You can't change the owner of this business!");
+ messagePlayerError(client, getLocaleString(client, "CantModifyBusiness"));
return false;
}
@@ -288,6 +334,15 @@ function setBusinessOwnerCommand(command, params, client) {
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function setBusinessJobCommand(command, params, client) {
if(areParamsEmpty(params)) {
messagePlayerSyntax(client, getCommandSyntaxText(command));
@@ -308,7 +363,7 @@ function setBusinessJobCommand(command, params, client) {
}
if(!canPlayerManageBusiness(client, businessId)) {
- messagePlayerError(client, "You can't change the owner of this business!");
+ messagePlayerError(client, getLocaleString(client, "CantModifyBusiness"));
return false;
}
@@ -321,6 +376,15 @@ function setBusinessJobCommand(command, params, client) {
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function setBusinessClanCommand(command, params, client) {
let businessId = getPlayerBusiness(client);
@@ -336,20 +400,35 @@ function setBusinessClanCommand(command, params, client) {
return false;
}
- if(!canPlayerManageBusiness(client, businessId)) {
- messagePlayerError(client, "You can't give this business to a clan!");
+ if(getBusinessData(business).ownerType != VRR_VEHOWNER_PLAYER) {
+ messagePlayerError(client, getLocaleString(client, "MustOwnBusiness"));
return false;
}
- getBusinessData(businessId).ownerType = VRR_BIZOWNER_CLAN;
- getBusinessData(businessId).ownerId = getClanData(clanId).databaseId;
- getBusinessData(businessId).needsSaved = true;
+ if(getBusinessData(business).ownerId != getPlayerCurrentSubAccount(client).databaseId) {
+ messagePlayerError(client, getLocaleString(client, "MustOwnBusiness"));
+ return false;
+ }
- messagePlayerSuccess(client, `{MAINCOLOUR}You gave business {businessBlue}${getBusinessData(businessId).name} {MAINCOLOUR}to the {clanOrange}${getClanData(clanId).name} {MAINCOLOUR}clan!`);
+ showPlayerPrompt(client, getLocaleString(client, "SetBusinessClanConfirmMessage"), getLocaleString(client, "SetBusinessClanConfirmTitle"), getLocaleString(client, "Yes"), getLocaleString(client, "No"));
+ getPlayerData(client).promptType = VRR_PROMPT_BIZGIVETOCLAN;
+
+ //getBusinessData(businessId).ownerType = VRR_BIZOWNER_CLAN;
+ //getBusinessData(businessId).ownerId = getClanData(clanId).databaseId;
+ //getBusinessData(businessId).needsSaved = true;
}
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function setBusinessRankCommand(command, params, client) {
let businessId = getPlayerBusiness(client);
@@ -361,7 +440,7 @@ function setBusinessRankCommand(command, params, client) {
let rankId = params;
if(!canPlayerManageBusiness(client, businessId)) {
- messagePlayerError(client, "You can't change this business rank level!");
+ messagePlayerError(client, getLocaleString(client, "CantModifyBusiness"));
return false;
}
@@ -421,7 +500,7 @@ function setBusinessRankCommand(command, params, client) {
}
if(!canPlayerManageBusiness(client, businessId)) {
- messagePlayerError(client, "You can't change this business rank!");
+ messagePlayerError(client, getLocaleString(client, "CantModifyBusiness"));
return false;
}
@@ -438,6 +517,15 @@ function setBusinessRankCommand(command, params, client) {
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function setBusinessJobCommand(command, params, client) {
let businessId = getPlayerBusiness(client);
@@ -471,6 +559,15 @@ function setBusinessJobCommand(command, params, client) {
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function setBusinessPublicCommand(command, params, client) {
let businessId = getPlayerBusiness(client);
@@ -492,6 +589,15 @@ function setBusinessPublicCommand(command, params, client) {
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function removeBusinessOwnerCommand(command, params, client) {
let businessId = getPlayerBusiness(client);
@@ -506,35 +612,9 @@ function removeBusinessOwnerCommand(command, params, client) {
getBusinessData(businessId).ownerType = VRR_BIZOWNER_NONE;
getBusinessData(businessId).ownerId = -1;
-
getBusinessData(businessId).needsSaved = true;
- messagePlayerSuccess(client, `{MAINCOLOUR}You removed business {businessBlue}${getBusinessData(businessId).name} {MAINCOLOUR}owner`);
-}
-// ===========================================================================
-
-function lockUnlockBusinessCommand(command, params, client) {
- let businessId = getPlayerBusiness(client);
-
- if(!areParamsEmpty(params)) {
- businessId = getBusinessFromParams(params);
- }
-
- if(!getBusinessData(businessId)) {
- messagePlayerError(client, getLocaleString(client, "InvalidBusiness"));
- return false;
- }
-
- if(!canPlayerManageBusiness(client, businessId)) {
- messagePlayerError(client, "You can't change this business rank!");
- return false;
- }
-
- getBusinessData(businessId).locked = !getBusinessData(businessId).locked;
- setEntityData(getBusinessData(businessId).entrancePickup, "vrr.label.locked", getBusinessData(businessId).locked, true);
-
- getBusinessData(businessId).needsSaved = true;
- messagePlayerSuccess(client, `${getLockedUnlockedEmojiFromBool((getBusinessData(businessId).locked))} Business {businessBlue}${getBusinessData(businessId).name} {MAINCOLOUR}${getLockedUnlockedFromBool((getBusinessData(businessId).locked))}!`);
+ messagePlayerSuccess(client, `{MAINCOLOUR}You removed business {businessBlue}${getBusinessData(businessId).name}'s{MAINCOLOUR} owner`);
}
// ===========================================================================
@@ -570,6 +650,15 @@ function lockUnlockBusinessCommand(command, params, client) {
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function setBusinessEntranceFeeCommand(command, params, client) {
let entranceFee = toInteger(getParam(params, " ", 1)) || 0;
let businessId = getPlayerBusiness(client);
@@ -580,7 +669,7 @@ function setBusinessEntranceFeeCommand(command, params, client) {
}
if(!canPlayerManageBusiness(client, businessId)) {
- messagePlayerError(client, "You can't change the entrance fee for this business!");
+ messagePlayerError(client, getLocaleString(client, "CantModifyBusiness"));
return false;
}
@@ -591,6 +680,15 @@ function setBusinessEntranceFeeCommand(command, params, client) {
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function getBusinessInfoCommand(command, params, client) {
let businessId = getPlayerBusiness(client);
@@ -603,35 +701,78 @@ function getBusinessInfoCommand(command, params, client) {
return false;
}
+ let businessData = getBusinessData(businessId);
+
let ownerName = "Unknown";
- switch(getBusinessData(businessId).ownerType) {
+ switch(businessData.ownerType) {
case VRR_BIZOWNER_CLAN:
- ownerName = getClanData(getBusinessData(businessId).ownerId).name;
+ ownerName = getClanData(businessData.ownerId).name;
break;
case VRR_BIZOWNER_JOB:
- ownerName = getJobData(getBusinessData(businessId).ownerId).name;
+ ownerName = getJobData(businessData.ownerId).name;
break;
case VRR_BIZOWNER_PLAYER:
- let subAccountData = loadSubAccountFromId(getBusinessData(businessId).ownerId);
+ let subAccountData = loadSubAccountFromId(businessData.ownerId);
ownerName = `${subAccountData.firstName} ${subAccountData.lastName} [${subAccountData.databaseId}]`;
break;
- case VRR_BIZOWNER_NONE:
- ownerName = "None";
- break;
-
case VRR_BIZOWNER_PUBLIC:
ownerName = "Public";
break;
+
+ case VRR_BIZOWNER_NONE:
+ //submitBugReport(client, `[AUTOMATED REPORT] getBusinessInfoCommand() - Invalid ownerType for business ${businessId}/${getBusinessData(businessId).databaseId}`);
+ ownerName = "None";
+ break;
+
+ default:
+ submitBugReport(client, `[AUTOMATED REPORT] getBusinessInfoCommand() - Invalid ownerType ${businessData.ownerType} for business ${businessId}/${getBusinessData(businessId).databaseId}`);
+ ownerName = "None";
+ break;
}
- messagePlayerInfo(client, `🏢 {businessBlue}[Business Info] {MAINCOLOUR}Name: {ALTCOLOUR}${getBusinessData(businessId).name}, {MAINCOLOUR}Owner: {ALTCOLOUR}${ownerName} (${getBusinessOwnerTypeText(getBusinessData(businessId).ownerType)}), {MAINCOLOUR}Locked: {ALTCOLOUR}${getYesNoFromBool(intToBool(getBusinessData(businessId).locked))}, {MAINCOLOUR}ID: {ALTCOLOUR}${businessId}/${getBusinessData(businessId).databaseId}`);
+
+ let tempStats = [
+ [`Name`, `${businessData.name}`],
+ [`ID`, `${businessData.index}/${businessData.databaseId}`],
+ [`Owner`, `${ownerName} (${getBusinessOwnerTypeText(businessData.ownerType)})`],
+ [`Locked`, `${getLockedUnlockedFromBool(businessData.locked)}`],
+ [`BuyPrice`, `$${businessData.buyPrice}`],
+ //[`RentPrice`, `${businessData.rentPrice}`],
+ [`HasInterior`, `${getYesNoFromBool(businessData.hasInterior)}`],
+ [`CustomInterior`, `${getYesNoFromBool(businessData.customInterior)}`],
+ [`HasBuyableItems`, `${getYesNoFromBool(doesBusinessHaveAnyItemsToBuy(businessId))}`],
+ [`EntranceFee`, `$${businessData.entranceFee}`],
+ [`InteriorLights`, `${getOnOffFromBool(businessData.interiorLights)}`],
+ [`Balance`, `$${businessData.till}`],
+ [`RadioStation`, `${businessData.streamingRadioStation}`],
+ [`LabelHelpType`, `${businessData.labelHelpType}`],
+ ];
+
+ let stats = tempStats.map(stat => `{MAINCOLOUR}${stat[0]}: {ALTCOLOUR}${stat[1]}{MAINCOLOUR}`);
+
+ messagePlayerNormal(client, makeChatBoxSectionHeader(getLocaleString(client, "HeaderBusinessInfo", businessData.name)));
+ let chunkedList = splitArrayIntoChunks(stats, 6);
+ for(let i in chunkedList) {
+ messagePlayerInfo(client, chunkedList[i].join(", "));
+ }
+
+ //messagePlayerInfo(client, `🏢 {businessBlue}[Business Info] {MAINCOLOUR}Name: {ALTCOLOUR}${getBusinessData(businessId).name}, {MAINCOLOUR}Owner: {ALTCOLOUR}${ownerName} (${getBusinessOwnerTypeText(getBusinessData(businessId).ownerType)}), {MAINCOLOUR}Locked: {ALTCOLOUR}${getYesNoFromBool(intToBool(getBusinessData(businessId).locked))}, {MAINCOLOUR}ID: {ALTCOLOUR}${businessId}/${getBusinessData(businessId).databaseId}`);
}
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function getBusinessFloorItemsCommand(command, params, client) {
let businessId = getPlayerBusiness(client);
@@ -649,6 +790,15 @@ function getBusinessFloorItemsCommand(command, params, client) {
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function getBusinessStorageItemsCommand(command, params, client) {
let businessId = getPlayerBusiness(client);
@@ -666,6 +816,15 @@ function getBusinessStorageItemsCommand(command, params, client) {
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function setBusinessPickupCommand(command, params, client) {
let typeParam = getParam(params, " ", 1) || "business";
let businessId = getPlayerBusiness(client);
@@ -676,9 +835,9 @@ function setBusinessPickupCommand(command, params, client) {
}
if(isNaN(typeParam)) {
- if(isNull(getGameConfig().pickupModels[getServerGame()][typeParam])) {
+ if(isNull(getGameConfig().pickupModels[getGame()][typeParam])) {
messagePlayerError(client, "Invalid pickup type! Use a pickup type name or a model ID");
- let pickupTypes = Object.keys(getGameConfig().pickupModels[getServerGame()]);
+ let pickupTypes = Object.keys(getGameConfig().pickupModels[getGame()]);
let chunkedList = splitArrayIntoChunks(pickupTypes, 10);
messagePlayerNormal(client, makeChatBoxSectionHeader(getLocaleString(client, "HeaderPickupTypes")));
@@ -688,7 +847,7 @@ function setBusinessPickupCommand(command, params, client) {
return false;
}
- getBusinessData(businessId).entrancePickupModel = getGameConfig().pickupModels[getServerGame()][typeParam];
+ getBusinessData(businessId).entrancePickupModel = getGameConfig().pickupModels[getGame()][typeParam];
} else {
getBusinessData(businessId).entrancePickupModel = toInteger(typeParam);
}
@@ -697,11 +856,20 @@ function setBusinessPickupCommand(command, params, client) {
getBusinessData(businessId).needsSaved = true;
- messageAdmins(`{ALTCOLOUR}${getPlayerName(client)}{MAINCOLOUR} set business {businessBlue}${getBusinessData(businessId).name} {MAINCOLOUR}pickup display to {ALTCOLOUR}${typeParam}!`);
+ messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} set business {businessBlue}${getBusinessData(businessId).name}{MAINCOLOUR} pickup display to {ALTCOLOUR}${typeParam}!`);
}
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function setBusinessInteriorTypeCommand(command, params, client) {
let typeParam = getParam(params, " ", 1) || "business";
let businessId = getPlayerBusiness(client);
@@ -711,20 +879,27 @@ function setBusinessInteriorTypeCommand(command, params, client) {
return false;
}
+ if(typeof getGameConfig().interiors[getGame()] == "undefined") {
+ messagePlayerError(client, `There are no interiors available for this game!`);
+ return false;
+ }
+
if(isNaN(typeParam)) {
if(toLowerCase(typeParam) == "None") {
getBusinessData(businessId).exitPosition = toVector3(0.0, 0.0, 0.0);
getBusinessData(businessId).exitDimension = 0;
getBusinessData(businessId).exitInterior = -1;
getBusinessData(businessId).hasInterior = false;
+ getBusinessData(businessId).interiorCutscene = "";
getBusinessData(businessId).exitPickupModel = -1;
- messageAdmins(`{ALTCOLOUR}${getPlayerName(client)} {MAINCOLOUR}removed business {businessBlue}${getBusinessData(businessId).name}{MAINCOLOUR} interior`);
+ getBusinessData(businessId).customInterior = false;
+ messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} removed business {businessBlue}${getBusinessData(businessId).name}{MAINCOLOUR} interior`);
return false;
}
- if(isNull(getGameConfig().interiors[getServerGame()][typeParam])) {
+ if(isNull(getGameConfig().interiors[getGame()][typeParam])) {
messagePlayerError(client, "Invalid interior type! Use an interior type name");
- let interiorTypesList = Object.keys(getGameConfig().interiors[getServerGame()]);
+ let interiorTypesList = Object.keys(getGameConfig().interiors[getGame()]);
let chunkedList = splitArrayIntoChunks(interiorTypesList, 10);
messagePlayerNormal(client, makeChatBoxSectionHeader(getLocaleString(client, "HeaderInteriorTypes")));
@@ -734,11 +909,13 @@ function setBusinessInteriorTypeCommand(command, params, client) {
return false;
}
- getBusinessData(businessId).exitPosition = getGameConfig().interiors[getServerGame()][typeParam][0];
- getBusinessData(businessId).exitInterior = getGameConfig().interiors[getServerGame()][typeParam][1];
+ getBusinessData(businessId).exitPosition = getGameConfig().interiors[getGame()][typeParam][0];
+ getBusinessData(businessId).exitInterior = getGameConfig().interiors[getGame()][typeParam][1];
getBusinessData(businessId).exitDimension = getBusinessData(businessId).databaseId+getGlobalConfig().businessDimensionStart;
- getBusinessData(businessId).exitPickupModel = getGameConfig().pickupModels[getServerGame()].Exit;
+ getBusinessData(businessId).exitPickupModel = getGameConfig().pickupModels[getGame()].Exit;
getBusinessData(businessId).hasInterior = true;
+ getBusinessData(businessId).customInterior = getGameConfig().interiors[getGame()][typeParam][2];
+ getBusinessData(businessId).interiorCutscene = getGameConfig().interiors[getGame()][typeParam][3];
}
//deleteBusinessExitPickup(businessId);
@@ -750,11 +927,79 @@ function setBusinessInteriorTypeCommand(command, params, client) {
getBusinessData(businessId).needsSaved = true;
- messageAdmins(`{ALTCOLOUR}${getPlayerName(client)}{MAINCOLOUR} set business {businessBlue}${getBusinessData(businessId).name}{MAINCOLOUR} interior type to {ALTCOLOUR}${typeParam}`);
+ messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} set business {businessBlue}${getBusinessData(businessId).name}{MAINCOLOUR} interior type to {ALTCOLOUR}${typeParam}`);
}
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
+ function addBusinessPropertyTemplateEntities(command, params, client) {
+ let propertyTemplateParam = getParam(params, " ", 1) || "business";
+ let businessId = getPlayerBusiness(client);
+
+ if(!getBusinessData(businessId)) {
+ messagePlayerError(client, getLocaleString(client, "InvalidBusiness"));
+ return false;
+ }
+
+ if(typeof getGameConfig().interiors[getGame()] == "undefined") {
+ messagePlayerError(client, `There are no property templates available for this game!`);
+ return false;
+ }
+
+ if(isNaN(propertyTemplateParam)) {
+ if(isNull(getGameConfig().interiors[getGame()][typeParam])) {
+ messagePlayerError(client, "Invalid interior type! Use an interior type name");
+ let interiorTypesList = Object.keys(getGameConfig().properties[getGame()]);
+ let chunkedList = splitArrayIntoChunks(interiorTypesList, 10);
+
+ messagePlayerNormal(client, makeChatBoxSectionHeader(getLocaleString(client, "HeaderPropertyTemplateTypes")));
+ for(let i in chunkedList) {
+ messagePlayerInfo(client, chunkedList[i].join(", "));
+ }
+ return false;
+ }
+
+ getBusinessData(businessId).exitPosition = getGameConfig().interiors[getGame()][typeParam][0];
+ getBusinessData(businessId).exitInterior = getGameConfig().interiors[getGame()][typeParam][1];
+ getBusinessData(businessId).exitDimension = getBusinessData(businessId).databaseId+getGlobalConfig().businessDimensionStart;
+ getBusinessData(businessId).exitPickupModel = getGameConfig().pickupModels[getGame()].Exit;
+ getBusinessData(businessId).hasInterior = true;
+ getBusinessData(businessId).customInterior = getGameConfig().interiors[getGame()][typeParam][2];
+ getBusinessData(businessId).interiorCutscene = getGameConfig().interiors[getGame()][typeParam][3];
+ }
+
+ //deleteBusinessExitPickup(businessId);
+ //deleteBusinessExitBlip(businessId);
+ //createBusinessExitBlip(businessId);
+ //createBusinessExitPickup(businessId);
+
+ resetBusinessPickups(businessId);
+
+ getBusinessData(businessId).needsSaved = true;
+
+ messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} set business {businessBlue}${getBusinessData(businessId).name}{MAINCOLOUR} interior type to {ALTCOLOUR}${typeParam}`);
+}
+
+// ===========================================================================
+
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function setBusinessBlipCommand(command, params, client) {
let typeParam = getParam(params, " ", 1) || "business";
let businessId = getPlayerBusiness(client);
@@ -765,10 +1010,10 @@ function setBusinessBlipCommand(command, params, client) {
}
if(isNaN(typeParam)) {
- if(isNull(getGameConfig().blipSprites[getServerGame()][typeParam])) {
+ if(isNull(getGameConfig().blipSprites[getGame()][typeParam])) {
messagePlayerError(client, "Invalid business type! Use a business type name or a blip image ID");
- let blipTypes = Object.keys(getGameConfig().blipSprites[getServerGame()]);
+ let blipTypes = Object.keys(getGameConfig().blipSprites[getGame()]);
let chunkedList = splitArrayIntoChunks(blipTypes, 10);
messagePlayerNormal(client, makeChatBoxSectionHeader(getLocaleString(client, "HeaderBlipTypes")));
@@ -778,7 +1023,7 @@ function setBusinessBlipCommand(command, params, client) {
return false;
}
- getBusinessData(businessId).entranceBlipModel = getGameConfig().blipSprites[getServerGame()][typeParam];
+ getBusinessData(businessId).entranceBlipModel = getGameConfig().blipSprites[getGame()][typeParam];
} else {
getBusinessData(businessId).entranceBlipModel = toInteger(typeParam);
}
@@ -786,11 +1031,20 @@ function setBusinessBlipCommand(command, params, client) {
resetBusinessBlips(businessId);
getBusinessData(businessId).needsSaved = true;
- messageAdmins(`{ALTCOLOUR}${getPlayerName(client)} {MAINCOLOUR}set business {businessBlue}${getBusinessData(businessId).name}{MAINCOLOUR} blip display to {ALTCOLOUR}${typeParam}`);
+ messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} set business {businessBlue}${getBusinessData(businessId).name}{MAINCOLOUR} blip display to {ALTCOLOUR}${typeParam}`);
}
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function giveDefaultItemsToBusinessCommand(command, params, client) {
let typeParam = getParam(params, " ", 1) || "business";
let businessId = getPlayerBusiness(client);
@@ -805,9 +1059,9 @@ function giveDefaultItemsToBusinessCommand(command, params, client) {
return false;
}
- if(isNull(getGameConfig().defaultBusinessItems[getServerGame()][typeParam])) {
+ if(isNull(getGameConfig().defaultBusinessItems[getGame()][typeParam])) {
messagePlayerError(client, "Invalid business items type! Use a business items type name");
- let businessItemTypes = Object.keys(getGameConfig().defaultBusinessItems[getServerGame()]);
+ let businessItemTypes = Object.keys(getGameConfig().defaultBusinessItems[getGame()]);
let chunkedList = splitArrayIntoChunks(businessItemTypes, 10);
messagePlayerNormal(client, makeChatBoxSectionHeader(getLocaleString(client, "HeaderDefaultBusinessItemTypes")));
@@ -817,22 +1071,31 @@ function giveDefaultItemsToBusinessCommand(command, params, client) {
return false;
}
- for(let i in getGameConfig().defaultBusinessItems[getServerGame()][typeParam]) {
- let itemTypeId = getItemTypeFromParams(getGameConfig().defaultBusinessItems[getServerGame()][typeParam][i][0]);
+ for(let i in getGameConfig().defaultBusinessItems[getGame()][typeParam]) {
+ let itemTypeId = getItemTypeFromParams(getGameConfig().defaultBusinessItems[getGame()][typeParam][i][0]);
let itemTypeData = getItemTypeData(itemTypeId);
if(itemTypeData) {
- let newItemIndex = createItem(itemTypeId, itemTypeData.orderValue, VRR_ITEM_OWNER_BIZFLOOR, getBusinessData(businessId).databaseId, getGameConfig().defaultBusinessItems[getServerGame()][typeParam][i][1]);
- getItemData(newItemIndex).buyPrice = applyServerInflationMultiplier(itemTypeData.orderPrice)*getGameConfig().defaultBusinessItems[getServerGame()][typeParam][i][2];
+ let newItemIndex = createItem(itemTypeId, itemTypeData.orderValue, VRR_ITEM_OWNER_BIZFLOOR, getBusinessData(businessId).databaseId, getGameConfig().defaultBusinessItems[getGame()][typeParam][i][1]);
+ getItemData(newItemIndex).buyPrice = applyServerInflationMultiplier(itemTypeData.orderPrice)*getGameConfig().defaultBusinessItems[getGame()][typeParam][i][2];
}
}
cacheBusinessItems(businessId);
updateBusinessPickupLabelData(businessId);
- messageAdmins(`{ALTCOLOUR}${getPlayerName(client)} {MAINCOLOUR}gave business {businessBlue}${getBusinessData(businessId).name} {MAINCOLOUR}the default items for ${toLowerCase(typeParam)}`);
+ messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} gave business {businessBlue}${getBusinessData(businessId).name}{MAINCOLOUR} the default items for ${toLowerCase(typeParam)}`);
}
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function setBusinessEntranceLabelToDealershipCommand(command, params, client) {
let businessId = getPlayerBusiness(client);
@@ -843,11 +1106,20 @@ function setBusinessEntranceLabelToDealershipCommand(command, params, client) {
getBusinessData(businessId).labelHelpType == VRR_PROPLABEL_INFO_ENTERVEHICLE;
updateBusinessPickupLabelData(businessId);
- messageAdmins(`{ALTCOLOUR}${getPlayerName(client)} {MAINCOLOUR}set the business type of {businessBlue}${getBusinessData(businessId).name} {MAINCOLOUR}to dealership`);
+ messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} set the business type of {businessBlue}${getBusinessData(businessId).name}{MAINCOLOUR} to dealership`);
}
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function deleteBusinessFloorItemsCommand(command, params, client) {
let businessId = getPlayerBusiness(client);
@@ -863,11 +1135,20 @@ function deleteBusinessFloorItemsCommand(command, params, client) {
cacheBusinessItems(businessId);
- messageAdmins(`{ALTCOLOUR}${getPlayerName(client)} {MAINCOLOUR}deleted all on-sale items for business {businessBlue}${getBusinessData(businessId).name}`);
+ messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} deleted all on-sale items for business {businessBlue}${getBusinessData(businessId).name}`);
}
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function deleteBusinessStorageItemsCommand(command, params, client) {
let businessId = getPlayerBusiness(client);
@@ -883,11 +1164,20 @@ function deleteBusinessStorageItemsCommand(command, params, client) {
cacheBusinessItems(businessId);
- messageAdmins(`{ALTCOLOUR}${getPlayerName(client)} {MAINCOLOUR}deleted all stored items for business {businessBlue}${getBusinessData(businessId).name}`);
+ messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} deleted all stored items for business {businessBlue}${getBusinessData(businessId).name}`);
}
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function withdrawFromBusinessCommand(command, params, client) {
if(areParamsEmpty(params)) {
messagePlayerSyntax(client, getCommandSyntaxText(command));
@@ -903,7 +1193,7 @@ function withdrawFromBusinessCommand(command, params, client) {
}
if(!canPlayerManageBusiness(client, businessId)) {
- messagePlayerError(client, "You can't withdraw cash from this business!");
+ messagePlayerError(client, getLocaleString(client, "CantModifyBusiness"));
return false;
}
@@ -922,6 +1212,15 @@ function withdrawFromBusinessCommand(command, params, client) {
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function setBusinessBuyPriceCommand(command, params, client) {
if(areParamsEmpty(params)) {
messagePlayerSyntax(client, getCommandSyntaxText(command));
@@ -937,7 +1236,7 @@ function setBusinessBuyPriceCommand(command, params, client) {
}
if(!canPlayerManageBusiness(client, businessId)) {
- messagePlayerError(client, "You can't change the purchase price for this business!");
+ messagePlayerError(client, getLocaleString(client, "CantModifyBusiness"));
return false;
}
@@ -955,6 +1254,15 @@ function setBusinessBuyPriceCommand(command, params, client) {
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function depositIntoBusinessCommand(command, params, client) {
if(areParamsEmpty(params)) {
messagePlayerSyntax(client, getCommandSyntaxText(command));
@@ -990,6 +1298,15 @@ function depositIntoBusinessCommand(command, params, client) {
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function orderItemForBusinessCommand(command, params, client) {
if(areParamsEmpty(params)) {
messagePlayerSyntax(client, getCommandSyntaxText(command));
@@ -1023,7 +1340,7 @@ function orderItemForBusinessCommand(command, params, client) {
}
if(!canPlayerManageBusiness(client, businessId)) {
- messagePlayerError(client, "You can't order items for this business!");
+ messagePlayerError(client, getLocaleString(client, "CantModifyBusiness"));
return false;
}
@@ -1037,11 +1354,21 @@ function orderItemForBusinessCommand(command, params, client) {
getPlayerData(client).businessOrderCost = orderTotalCost;
getBusinessData(businessId).needsSaved = true;
- showPlayerPrompt(client, VRR_PROMPT_BIZORDER, `Ordering ${amount} ${getPluralForm(getItemTypeData(itemType).name)} (${getItemValueDisplay(itemType, value)}) at $${makeLargeNumberReadable(pricePerItem)} each will cost a total of $${makeLargeNumberReadable(orderTotalCost)}`, "Business Order Cost");
+ showPlayerPrompt(client, `Ordering ${amount} ${getPluralForm(getItemTypeData(itemType).name)} (${getItemValueDisplay(itemType, value)}) at $${makeLargeNumberReadable(pricePerItem)} each will cost a total of $${makeLargeNumberReadable(orderTotalCost)}`, "Business Order Cost");
+ getPlayerData(client).promptType = VRR_PROMPT_BIZORDER;
}
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function orderItemForBusiness(businessId, itemType, amount) {
if(getBusinessData(businessId).till < orderTotalCost) {
let neededAmount = orderTotalCost-getBusinessData(businessId).till;
@@ -1056,6 +1383,15 @@ function orderItemForBusiness(businessId, itemType, amount) {
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function viewBusinessTillAmountCommand(command, params, client) {
let businessId = getPlayerBusiness(client);
@@ -1069,15 +1405,24 @@ function viewBusinessTillAmountCommand(command, params, client) {
}
if(!canPlayerManageBusiness(client, businessId)) {
- messagePlayerError(client, "You can't see the till amount for this business!");
+ messagePlayerError(client, getLocaleString(client, "CantModifyBusiness"));
return false;
}
- messagePlayerSuccess(client, `Business {businessBlue}${getBusinessData(businessId).name} {MAINCOLOUR}till has {ALTCOLOUR}$${getBusinessData(businessId).till}`);
+ messagePlayerSuccess(client, `Business {businessBlue}${getBusinessData(businessId).name}{MAINCOLOUR} till has {ALTCOLOUR}$${getBusinessData(businessId).till}`);
}
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function buyBusinessCommand(command, params, client) {
let businessId = getPlayerBusiness(client);
@@ -1096,18 +1441,21 @@ function buyBusinessCommand(command, params, client) {
return false;
}
- getBusinessData(businessId).ownerType = VRR_BIZOWNER_PLAYER;
- getBusinessData(businessId).ownerId = getPlayerCurrentSubAccount(client).databaseId;
- getBusinessData(businessId).buyPrice = 0;
-
- updateBusinessPickupLabelData(businessId);
- getBusinessData(businessId).needsSaved = true;
-
- messagePlayerSuccess(client, `You are now the owner of {businessBlue}${getBusinessData(businessId).name}`);
+ showPlayerPrompt(client, getLocaleString(client, "BuyBusinessConfirmMessage"), getLocaleString(client, "BuyBusinessConfirmTitle"), getLocaleString(client, "Yes"), getLocaleString(client, "No"));
+ getPlayerData(client).promptType = VRR_PROMPT_BIZBUY;
}
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function moveBusinessEntranceCommand(command, params, client) {
let businessId = getPlayerBusiness(client);
@@ -1134,11 +1482,20 @@ function moveBusinessEntranceCommand(command, params, client) {
getBusinessData(businessId).needsSaved = true;
- messageAdmins(`{ALTCOLOUR}${getPlayerName(client)} {MAINCOLOUR}moved business {businessBlue}${getBusinessData(businessId).name} {MAINCOLOUR}entrance to their position`);
+ messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} moved business {businessBlue}${getBusinessData(businessId).name}{MAINCOLOUR} entrance to their position`);
}
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function moveBusinessExitCommand(command, params, client) {
let businessId = getPlayerBusiness(client);
@@ -1163,7 +1520,7 @@ function moveBusinessExitCommand(command, params, client) {
getBusinessData(businessId).needsSaved = true;
- messageAdmins(`{ALTCOLOUR}${getPlayerName(client)} {MAINCOLOUR}moved business {businessBlue}${getBusinessData(businessId).name} {MAINCOLOUR}exit to their position`);
+ messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} moved business {businessBlue}${getBusinessData(businessId).name}{MAINCOLOUR}exit to their position`);
}
// ===========================================================================
@@ -1178,6 +1535,14 @@ function getBusinessDataFromDatabaseId(databaseId) {
// ===========================================================================
+/**
+ * Gets the closest business entrance to a position
+ *
+ * @param {Vector3} position - The position to check
+ * @param {Number} dimension - The dimension to check
+ * @return {Number} The data index of the business
+ *
+ */
function getClosestBusinessEntrance(position, dimension) {
let closest = 0;
for(let i in getServerData().businesses) {
@@ -1192,6 +1557,14 @@ function getClosestBusinessEntrance(position, dimension) {
// ===========================================================================
+/**
+ * Gets the closest business exit to a position
+ *
+ * @param {Vector3} position - The position to check
+ * @param {Number} dimension - The dimension to check
+ * @return {Number} The data index of the business
+ *
+ */
function getClosestBusinessExit(position, dimension) {
let closest = 0;
for(let i in getServerData().businesses) {
@@ -1206,6 +1579,13 @@ function getClosestBusinessExit(position, dimension) {
// ===========================================================================
+/**
+ * Gets whether or not a client is in a business
+ *
+ * @param {Client} client - The client to check whether or not is in a business
+ * @return {Boolean} Whether or not the client is in a business
+ *
+ */
function isPlayerInAnyBusiness(client) {
for(let i in getServerData().businesses) {
if(getServerData().businesses[i].hasInterior && getServerData().businesses[i].exitDimension == getPlayerDimension(client)) {
@@ -1218,39 +1598,71 @@ function isPlayerInAnyBusiness(client) {
// ===========================================================================
+/**
+ * Gets the data index of the business a client is in
+ *
+ * @param {Client} client - The client to check whether or not is in a business
+ * @return {Number} The data index of the business
+ *
+ */
function getPlayerBusiness(client) {
- let closestEntrance = getClosestBusinessEntrance(getPlayerPosition(client), getPlayerDimension(client));
- if(getDistance(getPlayerPosition(client), getBusinessData(closestEntrance).entrancePosition) <= getGlobalConfig().enterPropertyDistance) {
- return getBusinessData(closestEntrance).index;
- }
+ if(getPlayerDimension(client) == getGameConfig().mainWorldDimension[getGame()]) {
+ let closestEntrance = getClosestBusinessEntrance(getPlayerPosition(client), getPlayerDimension(client));
+ if(getDistance(getPlayerPosition(client), getBusinessData(closestEntrance).entrancePosition) <= getGlobalConfig().enterPropertyDistance) {
+ return getBusinessData(closestEntrance).index;
+ }
+ } else {
+ let closestEntrance = getClosestBusinessEntrance(getPlayerPosition(client), getPlayerDimension(client));
+ if(getDistance(getPlayerPosition(client), getBusinessData(closestEntrance).entrancePosition) <= getGlobalConfig().enterPropertyDistance) {
+ return getBusinessData(closestEntrance).index;
+ }
- for(let i in getServerData().businesses) {
- if(getServerData().businesses[i].hasInterior && getServerData().businesses[i].exitDimension == getPlayerDimension(client)) {
- return i;
+ for(let i in getServerData().businesses) {
+ if(getServerData().businesses[i].hasInterior && getServerData().businesses[i].exitDimension == getPlayerDimension(client)) {
+ return i;
+ }
}
}
-
return -1;
}
// ===========================================================================
+/**
+ * Saves all server businesses to the database
+ *
+ * @return {Boolean} Whether or not the businesses were saved
+ *
+ */
function saveAllBusinessesToDatabase() {
+ if(getServerConfig().devServer) {
+ return false;
+ }
+
for(let i in getServerData().businesses) {
if(getServerData().businesses[i].needsSaved) {
saveBusinessToDatabase(i);
}
}
+
+ return true
}
// ===========================================================================
+/**
+ * Saves a server businesses to the database by data index
+ *
+ * @param {Number} businessId - The data index of the business to save
+ * @return {Boolean} Whether or not the business was saved
+ *
+ */
function saveBusinessToDatabase(businessId) {
let tempBusinessData = getServerData().businesses[businessId];
- if(!tempBusinessData.needsSaved) {
- return false;
- }
+ if(!tempBusinessData.needsSaved) {
+ return false;
+ }
logToConsole(LOG_DEBUG, `[VRR.Business]: Saving business '${tempBusinessData.name}' to database ...`);
let dbConnection = connectToDatabase();
@@ -1273,6 +1685,7 @@ function saveBusinessToDatabase(businessId) {
["biz_entrance_vw", tempBusinessData.entranceDimension],
["biz_entrance_pickup", tempBusinessData.entrancePickupModel],
["biz_entrance_blip", tempBusinessData.entranceBlipModel],
+ ["biz_entrance_cutscene", tempBusinessData.entranceCutscene],
["biz_exit_pos_x", tempBusinessData.exitPosition.x],
["biz_exit_pos_y", tempBusinessData.exitPosition.y],
["biz_exit_pos_z", tempBusinessData.exitPosition.z],
@@ -1281,10 +1694,14 @@ function saveBusinessToDatabase(businessId) {
["biz_exit_vw", tempBusinessData.exitDimension],
["biz_exit_pickup", tempBusinessData.exitPickupModel],
["biz_exit_blip", tempBusinessData.exitBlipModel],
+ ["biz_exit_cutscene", tempBusinessData.exitCutscene],
["biz_has_interior", boolToInt(tempBusinessData.hasInterior)],
["biz_interior_lights", boolToInt(tempBusinessData.interiorLights)],
["biz_label_help_type", tempBusinessData.labelHelpType],
["biz_radiostation", tempBusinessData.streamingRadioStation],
+ ["biz_custom_interior", boolToInt(tempBusinessData.customInterior)],
+ ["biz_buy_price", boolToInt(tempBusinessData.buyPrice)],
+ //["biz_rent_price", boolToInt(tempBusinessData.rentPrice)],
];
let dbQuery = null;
@@ -1310,6 +1727,12 @@ function saveBusinessToDatabase(businessId) {
// ===========================================================================
+/**
+ * Creates all server pickups for all businesses
+ *
+ * @return {Boolean} Whether or not the server pickups were created
+ *
+ */
function createAllBusinessPickups() {
if(!getServerConfig().createBusinessPickups) {
return false;
@@ -1320,10 +1743,18 @@ function createAllBusinessPickups() {
createBusinessExitPickup(i);
updateBusinessPickupLabelData(i);
}
+
+ return true;
}
// ===========================================================================
+/**
+ * Creates all server blips for all businesses
+ *
+ * @return {Boolean} Whether or not the server blips were created
+ *
+ */
function createAllBusinessBlips() {
if(!getServerConfig().createBusinessBlips) {
return false;
@@ -1337,35 +1768,193 @@ function createAllBusinessBlips() {
// ===========================================================================
-function createBusinessEntrancePickup(businessId) {
+/**
+ * Creates the entrance pickup for a business by data index
+ *
+ * @param {Number} businessId - The data index of the business to create the pickup for
+ * @return {Boolean} Whether or not the blip was created
+ *
+ */
+function createBusinessEntrancePickup(businessId) {
+ if(!areServerElementsSupported()) {
+ return false;
+ }
+
if(!getServerConfig().createBusinessPickups) {
return false;
}
- if(getBusinessData(businessId).entrancePickupModel != -1) {
- let pickupModelId = getGameConfig().pickupModels[getServerGame()].Business;
+ let businessData = getBusinessData(businessId);
- if(getServerData().businesses[businessId].entrancePickupModel != 0) {
- pickupModelId = getBusinessData(businessId).entrancePickupModel;
- }
+ //if(businessData.hasInterior) {
+ // return false;
+ //}
- logToConsole(LOG_VERBOSE, `[VRR.Job]: Creating entrance pickup for business ${getBusinessData(businessId).name} (model ${pickupModelId})`);
-
- if(areServerElementsSupported()) {
- getBusinessData(businessId).entrancePickup = createGamePickup(pickupModelId, getBusinessData(businessId).entrancePosition, getGameConfig().pickupTypes[getServerGame()].business);
- setElementOnAllDimensions(getBusinessData(businessId).entrancePickup, false);
- setElementDimension(getBusinessData(businessId).entrancePickup, getBusinessData(businessId).entranceDimension);
+ if(businessData.entrancePickupModel == -1) {
+ return false;
+ }
+
+ let pickupModelId = getGameConfig().pickupModels[getGame()].Business;
+
+ if(businessData.entrancePickupModel != 0) {
+ pickupModelId = businessData.entrancePickupModel;
+ }
+
+ logToConsole(LOG_VERBOSE, `[VRR.Job]: Creating entrance pickup for business ${businessData.name} (model ${pickupModelId})`);
+
+ if(areServerElementsSupported()) {
+ let entrancePickup = createGamePickup(pickupModelId, businessData.entrancePosition, getGameConfig().pickupTypes[getGame()].business);
+ if(entrancePickup != null) {
+ if(businessData.entranceDimension != -1) {
+ setElementDimension(entrancePickup, businessData.entranceDimension);
+ setElementOnAllDimensions(entrancePickup, false);
+ } else {
+ setElementOnAllDimensions(entrancePickup, true);
+ }
+
+ if(getGlobalConfig().businessPickupStreamInDistance == -1 || getGlobalConfig().businessPickupStreamOutDistance == -1) {
+ entrancePickup.netFlags.distanceStreaming = false;
+ } else {
+ setElementStreamInDistance(entrancePickup, getGlobalConfig().businessPickupStreamInDistance);
+ setElementStreamOutDistance(entrancePickup, getGlobalConfig().businessPickupStreamOutDistance);
+ }
+ setElementTransient(entrancePickup, false);
+ getBusinessData(businessId).entrancePickup = entrancePickup;
updateBusinessPickupLabelData(businessId);
- addToWorld(getBusinessData(businessId).entrancePickup);
- } else {
- sendBusinessEntranceToPlayer(null, businessId, getBusinessData(businessId), getBusinessData(businessId).entrancePosition, getBusinessData(businessId).entranceBlipModel, getBusinessData(businessId).entrancePickupModel, getBusinessData(businessId).hasInterior, false);
+ }
+ } else {
+ let pickupModelId = getGameConfig().pickupModels[getGame()].Business;
+
+ if(businessData.entrancePickupModel != 0) {
+ pickupModelId = businessData.entrancePickupModel;
+ }
+ sendBusinessToPlayer(null, businessId, businessData.name, businessData.entrancePosition, blipModelId, pickupModelId, businessData.hasInterior, doesBusinessHaveAnyItemsToBuy(businessId));
+ }
+
+ return false;
+}
+
+// ===========================================================================
+
+/**
+ * Creates the entrance pickup for a business by data index
+ *
+ * @param {Number} businessId - The data index of the business to create the entrance pickup for
+ * @return {Boolean} Whether or not the blip was created
+ *
+ */
+function createBusinessEntranceBlip(businessId) {
+ if(!getServerConfig().createBusinessBlips) {
+ return false;
+ }
+
+ let businessData = getBusinessData(businessId);
+
+ //if(businessData.hasInterior) {
+ // return false;
+ //}
+
+ if(businessData.entranceBlipModel == -1) {
+ return false;
+ }
+
+ let blipModelId = getGameConfig().blipSprites[getGame()].Business;
+
+ if(businessData.entranceBlipModel != 0) {
+ blipModelId = businessData.entranceBlipModel;
+ }
+
+ logToConsole(LOG_VERBOSE, `[VRR.Job]: Creating entrance blip for business ${businessData.name} (model ${blipModelId})`);
+
+ if(areServerElementsSupported()) {
+ let entranceBlip = createGameBlip(businessData.entrancePosition, blipModelId, 1, getColourByType("businessBlue"));
+ if(entranceBlip != null) {
+ if(businessData.entranceDimension != -1) {
+ setElementDimension(entranceBlip, businessData.entranceDimension);
+ setElementOnAllDimensions(entranceBlip, false);
+ } else {
+ setElementOnAllDimensions(entranceBlip, true);
+ }
+
+ if(getGlobalConfig().businessBlipStreamInDistance == -1 || getGlobalConfig().businessBlipStreamOutDistance == -1) {
+ entranceBlip.netFlags.distanceStreaming = false;
+ } else {
+ setElementStreamInDistance(entranceBlip, getGlobalConfig().businessBlipStreamInDistance);
+ setElementStreamOutDistance(entranceBlip, getGlobalConfig().businessBlipStreamOutDistance);
+ }
+ setElementTransient(entranceBlip, false);
+ businessData.entranceBlip = entranceBlip;
}
}
}
// ===========================================================================
-function createBusinessEntranceBlip(businessId) {
+/**
+ * Creates the exit pickup for a business by data index
+ *
+ * @param {Number} businessId - The data index of the business to create the exit pickup for
+ * @return {Boolean} Whether or not the pickup was created
+ *
+ */
+function createBusinessExitPickup(businessId) {
+ if(!areServerElementsSupported()) {
+ return false;
+ }
+
+ if(!getServerConfig().createBusinessPickups) {
+ return false;
+ }
+
+ let businessData = getBusinessData(businessId);
+
+ //if(!businessData.hasInterior) {
+ // return false;
+ //}
+
+ if(businessData.exitPickupModel == -1) {
+ return false;
+ }
+
+ let pickupModelId = getGameConfig().pickupModels[getGame()].Exit;
+
+ if(businessData.exitPickupModel != 0) {
+ pickupModelId = businessData.exitPickupModel;
+ }
+
+ logToConsole(LOG_VERBOSE, `[VRR.Job]: Creating exit pickup for business ${businessData.name} (model ${pickupModelId})`);
+
+ let exitPickup = createGamePickup(pickupModelId, businessData.exitPosition, getGameConfig().pickupTypes[getGame()].business);
+ if(exitPickup != null) {
+ if(businessData.exitDimension != -1) {
+ setElementDimension(exitPickup, businessData.exitDimension);
+ setElementOnAllDimensions(exitPickup, false);
+ } else {
+ setElementOnAllDimensions(exitPickup, true);
+ }
+
+ if(getGlobalConfig().businessPickupStreamInDistance == -1 || getGlobalConfig().businessPickupStreamOutDistance == -1) {
+ exitPickup.netFlags.distanceStreaming = false;
+ } else {
+ setElementStreamInDistance(exitPickup, getGlobalConfig().businessPickupStreamInDistance);
+ setElementStreamOutDistance(exitPickup, getGlobalConfig().businessPickupStreamOutDistance);
+ }
+ setElementTransient(exitPickup, false);
+ getBusinessData(businessId).exitPickup = exitPickup;
+ updateBusinessPickupLabelData(businessId);
+ }
+}
+
+// ===========================================================================
+
+/**
+ * Creates the exit blip for a business by data index
+ *
+ * @param {Number} businessId - The data index of the business to create the exit blip for
+ * @return {Boolean} Whether or not the blip was created
+ *
+ */
+function createBusinessExitBlip(businessId) {
if(!areServerElementsSupported()) {
return false;
}
@@ -1374,92 +1963,62 @@ function createBusinessEntranceBlip(businessId) {
return false;
}
- if(getBusinessData(businessId).entranceBlipModel != -1) {
- let blipModelId = getGameConfig().blipSprites[getServerGame()].Business;
+ let businessData = getBusinessData(businessId);
- if(getServerData().businesses[businessId].entranceBlipModel != 0) {
- blipModelId = getBusinessData(businessId).entranceBlipModel;
- }
+ //if(!businessData.hasInterior) {
+ // return false;
+ //}
- logToConsole(LOG_VERBOSE, `[VRR.Job]: Creating entrance blip for business ${getBusinessData(businessId).name} (model ${blipModelId})`);
-
- if(areServerElementsSupported()) {
- getBusinessData(businessId).entranceBlip = createGameBlip(getBusinessData(businessId).entrancePosition, blipModelId, 1, getColourByName("businessBlue"));
- setElementOnAllDimensions(getBusinessData(businessId).entranceBlip, false);
- setElementDimension(getBusinessData(businessId).entranceBlip, getBusinessData(businessId).entranceDimension);
- addToWorld(getBusinessData(businessId).entranceBlip);
+ if(businessData.exitBlipModel == -1) {
+ return false;
+ }
+
+ let blipModelId = getGameConfig().blipSprites[getGame()].Business;
+
+ if(businessData.exitBlipModel != 0) {
+ blipModelId = businessData.exitBlipModel;
+ }
+
+ logToConsole(LOG_VERBOSE, `[VRR.Job]: Creating exit blip for business ${businessData.name} (model ${blipModelId})`);
+
+ let exitBlip = createGameBlip(businessData.exitPosition, blipModelId, 1, getColourByName("businessBlue"));
+ if(exitBlip != null) {
+ if(businessData.exitDimension != -1) {
+ setElementDimension(exitBlip, businessData.exitDimension);
+ setElementOnAllDimensions(exitBlip, false);
} else {
- sendBusinessEntranceToPlayer(null, businessId, getBusinessData(businessId).name, getBusinessData(businessId).entrancePosition, blipModelId, getBusinessData(businessId).entrancePickupModel, getBusinessData(businessId).hasInterior, false);
- }
- }
-}
-
-// ===========================================================================
-
-function createBusinessExitPickup(businessId) {
- if(!getServerConfig().createBusinessPickups) {
- return false;
- }
-
- if(getBusinessData(businessId).hasInterior) {
- if(getBusinessData(businessId).exitPickupModel != -1) {
- let pickupModelId = getGameConfig().pickupModels[getServerGame()].Exit;
-
- if(getServerData().businesses[businessId].exitPickupModel != 0) {
- pickupModelId = getBusinessData(businessId).exitPickupModel;
- }
-
- logToConsole(LOG_VERBOSE, `[VRR.Job]: Creating exit pickup for business ${getBusinessData(businessId).name} (model ${pickupModelId})`);
-
- if(areServerElementsSupported()) {
- getBusinessData(businessId).exitPickup = createGamePickup(pickupModelId, getBusinessData(businessId).exitPosition, getGameConfig().pickupTypes[getServerGame()].business);
- setElementDimension(getBusinessData(businessId).exitPickup, getBusinessData(businessId).exitDimension);
- setElementOnAllDimensions(getBusinessData(businessId).exitPickup, false);
- updateBusinessPickupLabelData(businessId);
- addToWorld(getBusinessData(businessId).exitPickup);
- }
- }
- }
-}
-
-// ===========================================================================
-
-function createBusinessExitBlip(businessId) {
- if(!getServerConfig().createBusinessBlips) {
- return false;
- }
-
- if(getBusinessData(businessId).hasInterior) {
- if(getBusinessData(businessId).exitBlipModel != -1) {
- let blipModelId = getGameConfig().blipSprites[getServerGame()].Business;
-
- if(getServerData().businesses[businessId].exitBlipModel != 0) {
- blipModelId = getBusinessData(businessId).exitBlipModel;
- }
-
- if(areServerElementsSupported()) {
- logToConsole(LOG_VERBOSE, `[VRR.Job]: Creating exit blip for business ${getBusinessData(businessId).name} (model ${blipModelId})`);
-
- getBusinessData(businessId).exitBlip = createGameBlip(getBusinessData(businessId).exitPosition, blipModelId, 1, getColourByName("businessBlue"));
- setElementDimension(getBusinessData(businessId).exitBlip, getBusinessData(businessId).entranceDimension);
- setElementOnAllDimensions(getBusinessData(businessId).exitBlip, false);
- //getBusinessData(businessId).exitBlip.interior = getBusinessData(businessId).exitInterior;
- //setEntityData(getBusinessData(businessId).exitBlip, "vrr.owner.type", VRR_BLIP_BUSINESS_EXIT, false);
- //setEntityData(getBusinessData(businessId).exitBlip, "vrr.owner.id", businessId, false);
- addToWorld(getBusinessData(businessId).exitBlip);
- }
+ setElementOnAllDimensions(exitBlip, true);
}
+
+ if(getGlobalConfig().businessBlipStreamInDistance == -1 || getGlobalConfig().businessBlipStreamOutDistance == -1) {
+ exitBlip.netFlags.distanceStreaming = false;
+ } else {
+ setElementStreamInDistance(exitBlip, getGlobalConfig().businessBlipStreamInDistance);
+ setElementStreamOutDistance(exitBlip, getGlobalConfig().businessBlipStreamOutDistance);
+ }
+ setElementTransient(exitBlip, false);
+ businessData.exitBlip = exitBlip;
}
}
// ===========================================================================
+/**
+ * Deletes a business data and removes it from the database by data index
+ *
+ * @param {Number} businessId - The data index of the business to delete
+ * @return {Boolean} Whether or not the business was deleted
+ *
+ */
function deleteBusiness(businessId, deletedBy = 0) {
let tempBusinessData = getServerData().businesses[businessId];
let dbConnection = connectToDatabase();
let dbQuery = null;
+ deleteBusinessBlips(businessId);
+ deleteBusinessPickups(businessId);
+
if(dbConnection) {
dbQuery = queryDatabase(dbConnection, `DELETE FROM biz_main WHERE biz_id = ${tempBusinessData.databaseId}`);
if(dbQuery) {
@@ -1468,49 +2027,83 @@ function deleteBusiness(businessId, deletedBy = 0) {
disconnectFromDatabase(dbConnection);
}
- deleteBusinessBlips(businessId);
- deleteBusinessPickups(businessId);
-
removePlayersFromBusiness(businessId);
getServerData().businesses.splice(businessId, 1);
+
+ return true;
}
// ===========================================================================
+/**
+ * Forces all players to exit a business
+ *
+ * @param {Number} businessId - The data index of the business to force all players inside to exit from
+ * @return {Boolean} Whether or not the players were forced to exit
+ *
+ */
function removePlayersFromBusiness(businessId) {
getClients().forEach(function(client) {
if(doesBusinessHaveInterior(businessId)) {
- if(isPlayerInAnyBusiness(client)) {
- if(getPlayerBusiness(client) == businessId) {
- exitBusiness(client);
- }
+ if(getPlayerBusiness(client) == businessId) {
+ exitBusiness(client);
}
}
});
+
+ return true;
}
// ===========================================================================
-function removePlayerFromBusinesses(client) {
- if(isPlayerInAnyBusiness(client)) {
- exitBusiness(client);
- }
+/**
+ * Forces a player to exit a business
+ *
+ * @param {Client} client - The client to force to exit the business
+ * @return {Boolean} Whether or not the player was forced to exit
+ *
+ */
+function removePlayerFromBusiness(client) {
+ exitBusiness(client);
+ return false;
}
// ===========================================================================
+/**
+ * Handles a player exiting a business
+ *
+ * @param {Client} client - The client to force to exit the business
+ * @return {Boolean} Whether or not the player successfully exited the business
+ *
+ */
function exitBusiness(client) {
let businessId = getPlayerBusiness(client);
+
+ if(businessId == false) {
+ return false;
+ }
+
if(isPlayerSpawned(client)) {
setPlayerInterior(client, getServerData().businesses[businessId].entranceInterior);
setPlayerDimension(client, getServerData().businesses[businessId].entranceDimension);
setPlayerPosition(client, getServerData().businesses[businessId].entrancePosition);
+ return true;
}
+
+ return false;
}
// ===========================================================================
+/**
+ * Gets the name of the type of a business owner by type ID
+ *
+ * @param {Number} ownerType - The business owner type ID
+ * @return {String} Name of the business owner type
+ *
+ */
function getBusinessOwnerTypeText(ownerType) {
switch(ownerType) {
case VRR_BIZOWNER_CLAN:
@@ -1546,12 +2139,22 @@ function getBusinessData(businessId) {
// ===========================================================================
+/**
+ *
+ * @param {Number} businessId - The data index of the business
+ * @returns {Boolean} Whether or not the business has an interior
+ */
function doesBusinessHaveInterior(businessId) {
return getBusinessData(businessId).hasInterior;
}
// ===========================================================================
+/**
+ *
+ * @param {Number} businessId - The data index of the business
+ * @returns {Boolean} Whether or not the entrance pickup of the business was deleted
+ */
function deleteBusinessEntrancePickup(businessId) {
if(!areServerElementsSupported()) {
return false;
@@ -1561,11 +2164,20 @@ function deleteBusinessEntrancePickup(businessId) {
//removeFromWorld(getBusinessData(businessId).entrancePickup);
deleteGameElement(getBusinessData(businessId).entrancePickup);
getBusinessData(businessId).entrancePickup = null;
+
+ return true;
}
+
+ return false;
}
// ===========================================================================
+/**
+ *
+ * @param {Number} businessId - The data index of the business
+ * @returns {Boolean} Whether or not the exit pickup of the business was deleted
+ */
function deleteBusinessExitPickup(businessId) {
if(!areServerElementsSupported()) {
return false;
@@ -1580,6 +2192,11 @@ function deleteBusinessExitPickup(businessId) {
// ===========================================================================
+/**
+ *
+ * @param {Number} businessId - The data index of the business
+ * @returns {Boolean} Whether or not the entrance blip of the business was deleted
+ */
function deleteBusinessEntranceBlip(businessId) {
if(!areServerElementsSupported()) {
return false;
@@ -1594,6 +2211,11 @@ function deleteBusinessEntranceBlip(businessId) {
// ===========================================================================
+/**
+ *
+ * @param {Number} businessId - The data index of the business
+ * @returns {Boolean} Whether or not the exit blip of the business was deleted
+ */
function deleteBusinessExitBlip(businessId) {
if(!areServerElementsSupported()) {
return false;
@@ -1608,12 +2230,19 @@ function deleteBusinessExitBlip(businessId) {
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function reloadAllBusinessesCommand(command, params, client) {
let clients = getClients();
for(let i in clients) {
- if(isPlayerInAnyBusiness(clients[i])) {
- removePlayerFromBusinesses(clients[i]);
- }
+ removePlayerFromBusiness(clients[i]);
}
for(let i in getServerData().businesses) {
@@ -1628,32 +2257,28 @@ function reloadAllBusinessesCommand(command, params, client) {
getServerData().businesses = loadBusinessesFromDatabase();
createAllBusinessPickups();
createAllBusinessBlips();
- setAllBusinessIndexes();
+ setBusinessDataIndexes();
cacheAllBusinessItems();
- messageAdminAction(`All businesses have been reloaded by an admin!`);
+ announceAdminAction(`AllBusinessesReloaded`);
}
// ===========================================================================
-function setAllBusinessIndexes() {
+/**
+ * Sets the indexes of all businesses
+ *
+ * @returns {Boolean} Whether or not the exit blip of the business was deleted
+ */
+function setBusinessDataIndexes() {
for(let i in getServerData().businesses) {
getServerData().businesses[i].index = i;
-
- //for(let j in getServerData().businesses[i].locations) {
- // getServerData().businesses[i].locations[j].index = j;
- // getServerData().businesses[i].locations[j].businessIndex = i;
- //}
-
- //for(let j in getServerData().businesses[i].gameScripts) {
- // getServerData().businesses[i].gameScripts[j].index = j;
- // getServerData().businesses[i].gameScripts[j].businessIndex = i;
- //}
}
}
// ===========================================================================
+// Adds an item to a business inventory by item type, amount and buy price
function addToBusinessInventory(businessId, itemType, amount, buyPrice) {
let tempItemData = new ItemData(false);
tempItemData.amount = amount;
@@ -1672,6 +2297,15 @@ function addToBusinessInventory(businessId, itemType, amount, buyPrice) {
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function buyFromBusinessCommand(command, params, client) {
let businessId = getPlayerBusiness(client);
@@ -1763,16 +2397,25 @@ function buyFromBusinessCommand(command, params, client) {
//messagePlayerSuccess(client, `You bought ${amount} {ALTCOLOUR}${itemName} {MAINCOLOUR}for ${totalCost} ${priceEach}`);
meActionToNearbyPlayers(client, `buys a ${itemName}`);
- if(!doesPlayerHaveKeyBindsDisabled(client) && doesPlayerHaveKeyBindForCommand("inv")) {
+ if(doesPlayerHaveKeyBindsDisabled(client) && doesPlayerHaveKeyBindForCommand("inv")) {
let keyData = getPlayerKeyBindForCommand("inv");
- messagePlayerNewbieTip(client, getLocaleString(client, "ViewInventoryKeyPressTip"), `{ALTCOLOUR}${getKeyNameFromId(keyData.key)}{MAINCOLOUR}`);
+ messagePlayerNewbieTip(client, getLocaleString(client, "ViewInventoryKeyPressTip", `{ALTCOLOUR}${getKeyNameFromId(keyData.key)}{MAINCOLOUR}`));
} else {
- messagePlayerNewbieTip(client, getLocaleString(client, "ViewInventoryKeyPressTip"), `{ALTCOLOUR}/inv{MAINCOLOUR}`);
+ messagePlayerNewbieTip(client, getLocaleString(client, "ViewInventoryCommandTip", `{ALTCOLOUR}/inv{MAINCOLOUR}`));
}
}
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function setBusinessItemSellPriceCommand(command, params, client) {
let businessId = getBusinessFromParams(getParam(params, " ", 3)) || getPlayerBusiness(client);
@@ -1807,6 +2450,15 @@ function setBusinessItemSellPriceCommand(command, params, client) {
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function storeItemInBusinessStorageCommand(command, params, client) {
let businessId = getBusinessFromParams(getParam(params, " ", 3)) || getPlayerBusiness(client);
@@ -1842,6 +2494,15 @@ function storeItemInBusinessStorageCommand(command, params, client) {
// ===========================================================================
+/**
+ * This is a command handler function.
+ *
+ * @param {string} command - The command name used by the player
+ * @param {string} params - The parameters/args string used with the command by the player
+ * @param {Client} client - The client/player that used the command
+ * @return {bool} Whether or not the command was successful
+ *
+ */
function stockItemOnBusinessFloorCommand(command, params, client) {
let businessId = getPlayerBusiness(client);
@@ -1877,30 +2538,21 @@ function stockItemOnBusinessFloorCommand(command, params, client) {
// ===========================================================================
+// Gets the first free slot in a business's storage items
function getBusinessStorageFirstFreeItemSlot(businessId) {
- for(let i in getBusinessData(businessId).storageItemCache) {
- if(getBusinessData(businessId).storageItemCache[i] == -1) {
- return i;
- }
- }
-
- return -1;
+ return getBusinessData(businessId).storageItemCache.findIndex(item => item == -1);
}
// ===========================================================================
+// Gets the first free slot in a business's floor items
function getBusinessFloorFirstFreeItemSlot(businessId) {
- for(let i in getBusinessData(businessId).floorItemCache) {
- if(getBusinessData(businessId).floorItemCache[i] == -1) {
- return i;
- }
- }
-
- return -1;
+ return getBusinessData(businessId).floorItemCache.findIndex(item => item == -1);
}
// ===========================================================================
+// Caches all items for all businesses
function cacheAllBusinessItems() {
logToConsole(LOG_DEBUG, "[VRR.Business] Caching all business items ...");
for(let i in getServerData().businesses) {
@@ -1911,9 +2563,15 @@ function cacheAllBusinessItems() {
// ===========================================================================
+// Caches all items for a business by businessId
function cacheBusinessItems(businessId) {
- getBusinessData(businessId).floorItemCache.splice(0, getBusinessData(businessId).floorItemCache.length);
- getBusinessData(businessId).storageItemCache.splice(0, getBusinessData(businessId).storageItemCache.length);
+ clearArray(getBusinessData(businessId).floorItemCache);
+ clearArray(getBusinessData(businessId).storageItemCache);
+
+ //let businessData = getBusinessData(businessId);
+ //logToConsole(LOG_VERBOSE, `[VRR.Business] Caching business items for business ${businessId} (${businessData.name}) ...`);
+ //getBusinessData(businessId).floorItemCache = getServerData().items.filter(item => item.ownerType == VRR_ITEM_OWNER_BIZFLOOR && item.ownerId == businessData.databaseId).map(i => i.index);
+ //getBusinessData(businessId).storageItemCache = getServerData().items.filter(item => item.ownerType == VRR_ITEM_OWNER_BIZSTORAGE && item.ownerId == businessData.databaseId);
logToConsole(LOG_VERBOSE, `[VRR.Business] Caching business items for business ${businessId} (${getBusinessData(businessId).name}) ...`);
for(let i in getServerData().items) {
@@ -1923,23 +2581,20 @@ function cacheBusinessItems(businessId) {
getBusinessData(businessId).storageItemCache.push(i);
}
}
+
logToConsole(LOG_VERBOSE, `[VRR.Business] Successfully cached ${getBusinessData(businessId).floorItemCache.length} floor items and ${getBusinessData(businessId).storageItemCache} storage items for business ${businessId} (${getBusinessData(businessId).name})!`);
}
// ===========================================================================
+// Gets a business's data index from a business's databaseId
function getBusinessIdFromDatabaseId(databaseId) {
- for(let i in getServerData().businesses) {
- if(getBusinessData(i).databaseId == databaseId) {
- return i;
- }
- }
-
- return false;
+ return getServerData().businesses.findIndex(business => business.databaseId == databaseId);
}
// ===========================================================================
+// Updates all pickup data for a business by businessId
function updateBusinessPickupLabelData(businessId) {
if(!areServerElementsSupported()) {
return false;
@@ -1958,41 +2613,38 @@ function updateBusinessPickupLabelData(businessId) {
setEntityData(getBusinessData(businessId).entrancePickup, "vrr.label.name", getBusinessData(businessId).name, true);
setEntityData(getBusinessData(businessId).entrancePickup, "vrr.label.locked", getBusinessData(businessId).locked, true);
setEntityData(getBusinessData(businessId).entrancePickup, "vrr.label.help", VRR_PROPLABEL_INFO_NONE, true);
- if(getBusinessData(businessId).labelHelpType == VRR_PROPLABEL_INFO_ENTERVEHICLE) {
- setEntityData(getBusinessData(businessId).entrancePickup, "vrr.label.help", VRR_PROPLABEL_INFO_ENTERVEHICLE, true);
- } else if(getBusinessData(businessId).labelHelpType == VRR_PROPLABEL_INFO_ENTER) {
- setEntityData(getBusinessData(businessId).entrancePickup, "vrr.label.help", VRR_PROPLABEL_INFO_ENTER, true);
- } else if(getBusinessData(businessId).labelHelpType == VRR_PROPLABEL_INFO_REPAIR) {
- setEntityData(getBusinessData(businessId).entrancePickup, "vrr.label.help", VRR_PROPLABEL_INFO_REPAIR, true);
- } else {
- if(getBusinessData(businessId).buyPrice > 0) {
- setEntityData(getBusinessData(businessId).entrancePickup, "vrr.label.price", getBusinessData(businessId).buyPrice, true);
- setEntityData(getBusinessData(businessId).entrancePickup, "vrr.label.help", VRR_PROPLABEL_INFO_BUYBIZ, true);
- } else {
+
+ switch(getBusinessData(businessId).labelHelpType) {
+ case VRR_PROPLABEL_INFO_ENTERVEHICLE: {
+ setEntityData(getBusinessData(businessId).entrancePickup, "vrr.label.help", VRR_PROPLABEL_INFO_ENTERVEHICLE, true);
+ break;
+ }
+
+ case VRR_PROPLABEL_INFO_ENTER: {
+ setEntityData(getBusinessData(businessId).entrancePickup, "vrr.label.help", VRR_PROPLABEL_INFO_ENTER, true);
+ break;
+ }
+
+ case VRR_PROPLABEL_INFO_REPAIR: {
+ setEntityData(getBusinessData(businessId).entrancePickup, "vrr.label.help", VRR_PROPLABEL_INFO_REPAIR, true);
+ break;
+ }
+
+ default: {
if(getBusinessData(businessId).hasInterior) {
setEntityData(getBusinessData(businessId).entrancePickup, "vrr.label.help", VRR_PROPLABEL_INFO_ENTER, true);
} else {
if(doesBusinessHaveAnyItemsToBuy(businessId)) {
setEntityData(getBusinessData(businessId).entrancePickup, "vrr.label.help", VRR_PROPLABEL_INFO_BUY, true);
+ } else {
+ removeEntityData(getBusinessData(businessId).entrancePickup, "vrr.label.help");
}
}
+ break;
}
}
- if(getBusinessData(businessId).buyPrice > 0) {
- setEntityData(getBusinessData(businessId).entrancePickup, "vrr.label.price", getBusinessData(businessId).buyPrice, true);
- }
- }
-}
-
-// ===========================================================================
-
-function getBusinessIdFromDatabaseId(databaseId) {
- let businesses = getServerData().businesses;
- for(let i in businesses) {
- if(businesses[i].databaseId == databaseId) {
- return i;
- }
+ setEntityData(getBusinessData(businessId).entrancePickup, "vrr.label.price", getBusinessData(businessId).buyPrice, true);
}
}
@@ -2207,17 +2859,73 @@ function getBusinessFromParams(params) {
// ===========================================================================
function deleteAllBusinessBlips() {
- for(let i in getServerData().businesses) {
- deleteBusinessBlips(i);
- }
+ for(let i in getServerData().businesses) {
+ deleteBusinessBlips(i);
+ }
}
// ===========================================================================
function deleteAllBusinessPickups() {
- for(let i in getServerData().businesses) {
- deleteBusinessPickups(i);
- }
+ for(let i in getServerData().businesses) {
+ deleteBusinessPickups(i);
+ }
+}
+
+// ===========================================================================
+
+function getBusinessFromInteriorAndDimension(dimension, interior) {
+ let businesses = getServerData().businesses;
+ for(let i in businesses) {
+ if(businesses[i].exitInterior == interior && businesses[i].exitDimension == dimension) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+// ===========================================================================
+
+function getClosestBusinessWithBuyableItemOfUseType(position, useType) {
+ let availableBusinesses = getBusinessesWithBuyableItemOfUseType(useType);
+
+ let closestBusiness = 0;
+ for(let i in availableBusinesses) {
+ if(getDistance(position, getBusinessData(availableBusinesses[i]).entrancePosition) < getDistance(position, getBusinessData(availableBusinesses[closestBusiness]).entrancePosition)) {
+ closestBusiness = i;
+ }
+ }
+ return availableBusinesses[closestBusiness];
+}
+
+// ===========================================================================
+
+function getBusinessesWithBuyableItemOfUseType(useType) {
+ let businesses = getServerData().businesses;
+ for(let i in businesses) {
+ if(doesBusinessHaveBuyableItemOfUseType(i, useType)) {
+ availableBusinesses.push(i);
+ }
+ }
+
+ return availableBusinesses;
+}
+
+// ===========================================================================
+
+function doesBusinessHaveBuyableItemOfUseType(businessId, useType) {
+ let floorItems = getBusinessData(businessId).floorItemCache;
+ for(let i in floorItems) {
+ if(floorItems[i] != -1) {
+ if(getItemData(floorItems[i]) != false) {
+ if(getItemTypeData(getItemData(floorItems[i])).useType == useType) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
}
// ===========================================================================
\ No newline at end of file
diff --git a/scripts/server/business/bakery.js b/scripts/server/business/bakery.js
deleted file mode 100644
index 5a0d1e81..00000000
--- a/scripts/server/business/bakery.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// ===========================================================================
-// Vortrex's Roleplay Resource
-// https://github.com/VortrexFTW/gtac_roleplay
-// ===========================================================================
-// FILE: bakery.js
-// DESC: Provides bakery business functions and usage
-// TYPE: Business (JavaScript)
-// ===========================================================================
\ No newline at end of file
diff --git a/scripts/server/business/bar.js b/scripts/server/business/bar.js
deleted file mode 100644
index 24265882..00000000
--- a/scripts/server/business/bar.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// ===========================================================================
-// Vortrex's Roleplay Resource
-// https://github.com/VortrexFTW/gtac_roleplay
-// ===========================================================================
-// FILE: bar.js
-// DESC: Provides bar/pub business functions and usage
-// TYPE: Business (JavaScript)
-// ===========================================================================
\ No newline at end of file
diff --git a/scripts/server/business/burger.js b/scripts/server/business/burger.js
deleted file mode 100644
index 4de61d2b..00000000
--- a/scripts/server/business/burger.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// ===========================================================================
-// Vortrex's Roleplay Resource
-// https://github.com/VortrexFTW/gtac_roleplay
-// ===========================================================================
-// FILE: burger.js
-// DESC: Provides burger joint (McDonalds?) business functions and usage
-// TYPE: Business (JavaScript)
-// ===========================================================================
\ No newline at end of file
diff --git a/scripts/server/business/casino.js b/scripts/server/business/casino.js
deleted file mode 100644
index 7317cf7f..00000000
--- a/scripts/server/business/casino.js
+++ /dev/null
@@ -1,67 +0,0 @@
-// ===========================================================================
-// Vortrex's Roleplay Resource
-// https://github.com/VortrexFTW/gtac_roleplay
-// ===========================================================================
-// FILE: casino.js
-// DESC: Provides casino business functions and usage
-// TYPE: Business (JavaScript)
-// ===========================================================================
-
-let deckCards = [
- DeckCardData("deckCardSpadeAce", VRR_DECKCARD_SUIT_SPADE, 1),
- DeckCardData("deckCardSpade2", VRR_DECKCARD_SUIT_SPADE, 2),
- DeckCardData("deckCardSpade3", VRR_DECKCARD_SUIT_SPADE, 3),
- DeckCardData("deckCardSpade4", VRR_DECKCARD_SUIT_SPADE, 4),
- DeckCardData("deckCardSpade5", VRR_DECKCARD_SUIT_SPADE, 5),
- DeckCardData("deckCardSpade6", VRR_DECKCARD_SUIT_SPADE, 6),
- DeckCardData("deckCardSpade7", VRR_DECKCARD_SUIT_SPADE, 7),
- DeckCardData("deckCardSpade8", VRR_DECKCARD_SUIT_SPADE, 8),
- DeckCardData("deckCardSpade9", VRR_DECKCARD_SUIT_SPADE, 9),
- DeckCardData("deckCardSpade10", VRR_DECKCARD_SUIT_SPADE, 10),
- DeckCardData("deckCardSpadeJack", VRR_DECKCARD_SUIT_SPADE, 11),
- DeckCardData("deckCardSpadeQueen", VRR_DECKCARD_SUIT_SPADE, 12),
- DeckCardData("deckCardSpadeKing", VRR_DECKCARD_SUIT_SPADE, 13),
- DeckCardData("deckCardClubAce", VRR_DECKCARD_SUIT_CLUB, 1),
- DeckCardData("deckCardClub2", VRR_DECKCARD_SUIT_CLUB, 2),
- DeckCardData("deckCardClub3", VRR_DECKCARD_SUIT_CLUB, 3),
- DeckCardData("deckCardClub4", VRR_DECKCARD_SUIT_CLUB, 4),
- DeckCardData("deckCardClub5", VRR_DECKCARD_SUIT_CLUB, 5),
- DeckCardData("deckCardClub6", VRR_DECKCARD_SUIT_CLUB, 6),
- DeckCardData("deckCardClub7", VRR_DECKCARD_SUIT_CLUB, 7),
- DeckCardData("deckCardClub8", VRR_DECKCARD_SUIT_CLUB, 8),
- DeckCardData("deckCardClub9", VRR_DECKCARD_SUIT_CLUB, 9),
- DeckCardData("deckCardClub10", VRR_DECKCARD_SUIT_CLUB, 10),
- DeckCardData("deckCardClubJack", VRR_DECKCARD_SUIT_CLUB, 11),
- DeckCardData("deckCardClubQueen", VRR_DECKCARD_SUIT_CLUB, 12),
- DeckCardData("deckCardClubKing", VRR_DECKCARD_SUIT_CLUB, 13),
- DeckCardData("deckCardHeartAce", VRR_DECKCARD_SUIT_HEART, 1),
- DeckCardData("deckCardHeart2", VRR_DECKCARD_SUIT_HEART, 2),
- DeckCardData("deckCardHeart3", VRR_DECKCARD_SUIT_HEART, 3),
- DeckCardData("deckCardHeart4", VRR_DECKCARD_SUIT_HEART, 4),
- DeckCardData("deckCardHeart5", VRR_DECKCARD_SUIT_HEART, 5),
- DeckCardData("deckCardHeart6", VRR_DECKCARD_SUIT_HEART, 6),
- DeckCardData("deckCardHeart7", VRR_DECKCARD_SUIT_HEART, 7),
- DeckCardData("deckCardHeart8", VRR_DECKCARD_SUIT_HEART, 8),
- DeckCardData("deckCardHeart9", VRR_DECKCARD_SUIT_HEART, 9),
- DeckCardData("deckCardHeart10", VRR_DECKCARD_SUIT_HEART, 10),
- DeckCardData("deckCardHeartJack", VRR_DECKCARD_SUIT_HEART, 11),
- DeckCardData("deckCardHeartQueen", VRR_DECKCARD_SUIT_HEART, 12),
- DeckCardData("deckCardHeartKing", VRR_DECKCARD_SUIT_HEART, 13),
- DeckCardData("deckCardDiamondAce", VRR_DECKCARD_SUIT_DIAMOND, 1),
- DeckCardData("deckCardDiamond2", VRR_DECKCARD_SUIT_DIAMOND, 2),
- DeckCardData("deckCardDiamond3", VRR_DECKCARD_SUIT_DIAMOND, 3),
- DeckCardData("deckCardDiamond4", VRR_DECKCARD_SUIT_DIAMOND, 4),
- DeckCardData("deckCardDiamond5", VRR_DECKCARD_SUIT_DIAMOND, 5),
- DeckCardData("deckCardDiamond6", VRR_DECKCARD_SUIT_DIAMOND, 6),
- DeckCardData("deckCardDiamond7", VRR_DECKCARD_SUIT_DIAMOND, 7),
- DeckCardData("deckCardDiamond8", VRR_DECKCARD_SUIT_DIAMOND, 8),
- DeckCardData("deckCardDiamond9", VRR_DECKCARD_SUIT_DIAMOND, 9),
- DeckCardData( "deckCardDiamond10", VRR_DECKCARD_SUIT_DIAMOND, 10),
- DeckCardData("deckCardDiamondJack", VRR_DECKCARD_SUIT_DIAMOND, 11),
- DeckCardData("deckCardDiamondQueen", VRR_DECKCARD_SUIT_DIAMOND, 12),
- DeckCardData("deckCardDiamondKing", VRR_DECKCARD_SUIT_DIAMOND, 13),
-];
-
-let deckCardBacks = [
-
-]
\ No newline at end of file
diff --git a/scripts/server/business/clothing.js b/scripts/server/business/clothing.js
deleted file mode 100644
index 1a38adad..00000000
--- a/scripts/server/business/clothing.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// ===========================================================================
-// Vortrex's Roleplay Resource
-// https://github.com/VortrexFTW/gtac_roleplay
-// ===========================================================================
-// FILE: clothing.js
-// DESC: Provides clothing (skin) business functions and usage
-// TYPE: Business (JavaScript)
-// ===========================================================================
\ No newline at end of file
diff --git a/scripts/server/business/club.js b/scripts/server/business/club.js
deleted file mode 100644
index 80f083c4..00000000
--- a/scripts/server/business/club.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// ===========================================================================
-// Vortrex's Roleplay Resource
-// https://github.com/VortrexFTW/gtac_roleplay
-// ===========================================================================
-// FILE: club.js
-// DESC: Provides club/nightclub business functions and usage
-// TYPE: Business (JavaScript)
-// ===========================================================================
\ No newline at end of file
diff --git a/scripts/server/business/fuel.js b/scripts/server/business/fuel.js
deleted file mode 100644
index 217d82a4..00000000
--- a/scripts/server/business/fuel.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// ===========================================================================
-// Vortrex's Roleplay Resource
-// https://github.com/VortrexFTW/gtac_roleplay
-// ===========================================================================
-// FILE: fuel.js
-// DESC: Provides fuel/petrol business functions and usage
-// TYPE: Business (JavaScript)
-// ===========================================================================
\ No newline at end of file
diff --git a/scripts/server/business/mechanic.js b/scripts/server/business/mechanic.js
deleted file mode 100644
index 6eec8be0..00000000
--- a/scripts/server/business/mechanic.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// ===========================================================================
-// Vortrex's Roleplay Resource
-// https://github.com/VortrexFTW/gtac_roleplay
-// ===========================================================================
-// FILE: mechanic.js
-// DESC: Provides mechanic/vehicle repair business functions and usage
-// TYPE: Business (JavaScript)
-// ===========================================================================
\ No newline at end of file
diff --git a/scripts/server/business/pizza.js b/scripts/server/business/pizza.js
deleted file mode 100644
index d14bb7a0..00000000
--- a/scripts/server/business/pizza.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// ===========================================================================
-// Vortrex's Roleplay Resource
-// https://github.com/VortrexFTW/gtac_roleplay
-// ===========================================================================
-// FILE: pizza.js
-// DESC: Provides pizza restaurant business functions and usage
-// TYPE: Business (JavaScript)
-// ===========================================================================
\ No newline at end of file
diff --git a/scripts/server/business/restaurant.js b/scripts/server/business/restaurant.js
deleted file mode 100644
index 0491cfca..00000000
--- a/scripts/server/business/restaurant.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// ===========================================================================
-// Vortrex's Roleplay Resource
-// https://github.com/VortrexFTW/gtac_roleplay
-// ===========================================================================
-// FILE: restaurant.js
-// DESC: Provides generic restaurant business functions and usage
-// TYPE: Business (JavaScript)
-// ===========================================================================
\ No newline at end of file
diff --git a/scripts/server/business/vehicle.js b/scripts/server/business/vehicle.js
deleted file mode 100644
index b7990e73..00000000
--- a/scripts/server/business/vehicle.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// ===========================================================================
-// Vortrex's Roleplay Resource
-// https://github.com/VortrexFTW/gtac_roleplay
-// ===========================================================================
-// FILE: vehicle.js
-// DESC: Provides vehicle dealership business functions and usage
-// TYPE: Business (JavaScript)
-// ===========================================================================
\ No newline at end of file
diff --git a/scripts/server/business/weapon.js b/scripts/server/business/weapon.js
deleted file mode 100644
index e81fc514..00000000
--- a/scripts/server/business/weapon.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// ===========================================================================
-// Vortrex's Roleplay Resource
-// https://github.com/VortrexFTW/gtac_roleplay
-// ===========================================================================
-// FILE: weapon.js
-// DESC: Provides weapon (ammunations & illegal gunshops) business usage
-// TYPE: Business (JavaScript)
-// ===========================================================================
-
diff --git a/scripts/server/chat.js b/scripts/server/chat.js
index fbb63857..06a3f921 100644
--- a/scripts/server/chat.js
+++ b/scripts/server/chat.js
@@ -13,31 +13,39 @@ function initChatScript() {
return true;
}
+// ===========================================================================
+
function processPlayerChat(client, messageText) {
- if(!getPlayerData(client)) {
- messagePlayerError(client, "You need to login before you can chat!");
- return false;
- }
+ if(!isConsole(client)) {
+ if(!getPlayerData(client)) {
+ messagePlayerError(client, getLocaleString(client, "MustBeLoggedInAndSpawnedToChat"));
+ return false;
+ }
- if(!isPlayerLoggedIn(client)) {
- messagePlayerError(client, "You need to login before you can chat!");
- return false;
- }
+ if(!isPlayerLoggedIn(client)) {
+ messagePlayerError(client, getLocaleString(client, "MustBeLoggedInAndSpawnedToChat"));
+ return false;
+ }
- if(!isPlayerSpawned(client)) {
- messagePlayerError(client, "You need to spawn before you can chat!");
- return false;
- }
+ if(!isPlayerSpawned(client)) {
+ messagePlayerError(client, getLocaleString(client, "MustBeLoggedInAndSpawnedToChat"));
+ return false;
+ }
- if(isPlayerMuted(client)) {
- messagePlayerError(client, "You are muted and can't chat!");
- return false;
- }
+ if(isPlayerMuted(client)) {
+ messagePlayerError(client, getLocaleString(client, "MutedCantChat"));
+ return false;
+ }
- messageText = messageText.substring(0, 128);
+ messageText = messageText.substring(0, 128);
+ messagePlayerNormal(null, `💬 ${getCharacterFullName(client)}: {MAINCOLOUR}${messageText}`, getPlayerColour(client));
+ messageDiscordChatChannel(`💬 ${getCharacterFullName(client)}: ${messageText}`);
+ } else {
+ messagePlayerNormal(null, `🛡️ (ADMIN) - ${messageText}`);
+ }
- /*
- let clients = getClients();
+ /*
+ let clients = getClients();
for(let i in clients) {
let translatedText;
translatedText = await translateMessage(messageText, getPlayerData(client).locale, getPlayerData(clients[i]).locale);
@@ -45,9 +53,9 @@ function processPlayerChat(client, messageText) {
let original = (getPlayerData(client).locale == getPlayerData(clients[i]).locale) ? `` : ` {ALTCOLOUR}(${messageText})`;
messagePlayerNormal(clients[i], `💬 ${getCharacterFullName(client)}: [#FFFFFF]${translatedText}${original}`, clients[i], getColourByName("mediumGrey"));
}
- */
- messagePlayerNormal(null, `💬 ${getCharacterFullName(client)}: ${messageText}`);
- messageDiscordChatChannel(`💬 ${getCharacterFullName(client)}: ${messageText}`);
+ */
+
+ //messageDiscordChatChannel(`💬 ${getCharacterFullName(client)}: ${messageText}`);
}
// ===========================================================================
@@ -66,7 +74,7 @@ function meActionCommand(command, params, client) {
function doActionCommand(command, params, client) {
if(isPlayerMuted(client)) {
- messagePlayerError(client, "You are muted and can't chat!");
+ messagePlayerError(client, getLocaleString(client, "MutedCantChat"));
return false;
}
@@ -83,7 +91,7 @@ function doActionCommand(command, params, client) {
function shoutCommand(command, params, client) {
if(isPlayerMuted(client)) {
- messagePlayerError(client, "You are muted and can't chat!");
+ messagePlayerError(client, getLocaleString(client, "MutedCantChat"));
return false;
}
@@ -100,7 +108,7 @@ function shoutCommand(command, params, client) {
function megaphoneChatCommand(command, params, client) {
if(isPlayerMuted(client)) {
- messagePlayerError(client, "You are muted and can't chat!");
+ messagePlayerError(client, getLocaleString(client, "MutedCantChat"));
return false;
}
@@ -110,7 +118,7 @@ function megaphoneChatCommand(command, params, client) {
}
if(!canPlayerUseMegaphone(client)) {
- messagePlayerError(client, "You must have a megaphone item or be in an emergency vehicle!");
+ messagePlayerError(client, getLocaleString(client, "CantUseMegaphone"));
return false;
}
@@ -122,7 +130,7 @@ function megaphoneChatCommand(command, params, client) {
function talkCommand(command, params, client) {
if(isPlayerMuted(client)) {
- messagePlayerError(client, "You are muted and can't chat!");
+ messagePlayerError(client, getLocaleString(client, "MutedCantChat"));
return false;
}
@@ -139,7 +147,7 @@ function talkCommand(command, params, client) {
function whisperCommand(command, params, client) {
if(isPlayerMuted(client)) {
- messagePlayerError(client, "You are muted and can't chat!");
+ messagePlayerError(client, getLocaleString(client, "MutedCantChat"));
return false;
}
@@ -156,7 +164,7 @@ function whisperCommand(command, params, client) {
function adminChatCommand(command, params, client) {
if(isPlayerMuted(client)) {
- messagePlayerError(client, "You are muted and can't chat!");
+ messagePlayerError(client, getLocaleString(client, "MutedCantChat"));
return false;
}
@@ -165,14 +173,14 @@ function adminChatCommand(command, params, client) {
return false;
}
- messageAdmins(`{jobYellow}[Admin Chat] {ALTCOLOUR}${getPlayerName(client)} [#CCCCCC](${getPlayerStaffTitle(client)}){MAINCOLOUR}: ${params}`);
+ messageAdmins(`{jobYellow}[Admin Chat] {ALTCOLOUR}${getPlayerName(client)}: ${params}`);
}
// ===========================================================================
function clanChatCommand(command, params, client) {
if(isPlayerMuted(client)) {
- messagePlayerError(client, "You are muted and can't chat!");
+ messagePlayerError(client, getLocaleString(client, "MutedCantChat"));
return false;
}
diff --git a/scripts/server/clan.js b/scripts/server/clan.js
index 0155dd4d..5fa85af6 100644
--- a/scripts/server/clan.js
+++ b/scripts/server/clan.js
@@ -9,8 +9,6 @@
function initClanScript() {
logToConsole(LOG_INFO, "[VRR.Clan]: Initializing clans script ...");
- getServerData().clans = loadClansFromDatabase();
- setAllClanDataIndexes();
logToConsole(LOG_INFO, "[VRR.Clan]: Clan script initialized successfully!");
return true;
}
@@ -33,7 +31,7 @@ function loadClansFromDatabase() {
//tempClanData.members = loadClanMembersFromDatabase(tempClanData.databaseId);
tempClanData.ranks = loadClanRanksFromDatabase(tempClanData.databaseId);
tempClans.push(tempClanData);
- logToConsole(LOG_VERBOSE, `[VRR.Clan]: Clan '${tempClanData.name}' loaded from database successfully!`);
+ logToConsole(LOG_DEBUG, `[VRR.Clan]: Clan '${tempClanData.name}' loaded from database successfully!`);
}
}
freeDatabaseQuery(dbQuery);
@@ -114,7 +112,7 @@ function createClanRank(clanId, rankId, rankName) {
let rankIndex = getClanData(clanId).ranks.push(tempClanRankData);
setAllClanDataIndexes();
- saveAllClanRanksToDatabase(clanId);
+ saveClanRanksToDatabase(clanId);
return rankIndex;
}
@@ -144,7 +142,7 @@ function listClansCommand(command, params, client) {
let chunkedList = splitArrayIntoChunks(nameList, 5);
- messagePlayerInfo(client, `{clanOrange}== {jobYellow}Clans {clanOrange}====================================`);
+ messagePlayerInfo(client, makeChatBoxSectionHeader(getLocaleString(client, "HeaderClansList")));
for(let i in chunkedList) {
messagePlayerInfo(client, chunkedList[i].join(", "));
@@ -171,7 +169,7 @@ function listClanRanksCommand(command, params, client) {
let chunkedList = splitArrayIntoChunks(rankNameList, 5);
- messagePlayerInfo(client, `{clanOrange}== {jobYellow}Clan Ranks (${getClanData(clanId).name}) {clanOrange}=====================`);
+ messagePlayerInfo(client, makeChatBoxSectionHeader(getLocaleString(client, "HeaderClanRanksList")));
for(let i in chunkedList) {
messagePlayerInfo(client, chunkedList[i].join(", "));
@@ -193,7 +191,7 @@ function createClanCommand(command, params, client) {
// Create clan without owner. Can set owner with /clanowner afterward
createClan(params);
- messageAdmins(`{ALTCOLOUR}${getPlayerName(client)} {MAINCOLOUR}created clan {clanOrange}${params}`);
+ messageAdmins(`{adminOrange}${getPlayerName(client)}{MAINCOLOUR} created clan {clanOrange}${params}`);
}
// ===========================================================================
@@ -211,7 +209,7 @@ function deleteClanCommand(command, params, client) {
return false;
}
- messageAdmins(`{ALTCOLOUR}${getPlayerName(client)} {MAINCOLOUR}deleted clan {clanOrange}${getClanData(clanId).name}`);
+ messageAdmins(`{adminOrange}${getPlayerName(client)} {MAINCOLOUR}deleted clan {clanOrange}${getClanData(clanId).name}`);
deleteClan(clanId);
}
@@ -242,10 +240,13 @@ function setClanOwnerCommand(command, params, client) {
}
getClanData(clanId).owner = getPlayerCurrentSubAccount(targetClient).databaseId;
+ getClanData(clanId).needsSaved = true;
+
getPlayerCurrentSubAccount(targetClient).clan = getClanData(clanId).databaseId;
getPlayerCurrentSubAccount(targetClient).clanFlags = getClanFlagValue("All");
- messageAdmins(`{ALTCOLOUR}${getPlayerName(client)} {MAINCOLOUR}set clan {clanOrange}${getClanData(clanId).name} {MAINCOLOUR}owner to {ALTCOLOUR}${getCharacterFullName(targetClient)}`);
+ //messageAdmins(`{adminOrange}${getPlayerName(client)} {MAINCOLOUR}set clan {clanOrange}${getClanData(clanId).name} {MAINCOLOUR}owner to {ALTCOLOUR}${getCharacterFullName(targetClient)}`);
+ messagePlayerSuccess(client, `You changed the clan owner to {ALTCOLOUR}${getCharacterFullName(targetClient)}`);
}
// ===========================================================================
@@ -268,9 +269,11 @@ function setClanTagCommand(command, params, client) {
return false;
}
- getClanData(clanId).params = params;
+ getClanData(clanId).tag = params;
+ getClanData(clanId).needsSaved = true;
- messageAdmins(`{ALTCOLOUR}${getPlayerName(client)} {MAINCOLOUR}set clan {clanOrange}${getClanData(clanId).index} {MAINCOLOUR}tag to {ALTCOLOUR}${params}`);
+ //messageAdmins(`{adminOrange}${getPlayerName(client)} {MAINCOLOUR}set clan {clanOrange}${getClanData(clanId).index} {MAINCOLOUR}tag to {ALTCOLOUR}${params}`);
+ messagePlayerSuccess(client, `You changed the clan tag to {ALTCOLOUR}${params}`);
}
// ===========================================================================
@@ -294,8 +297,10 @@ function setClanNameCommand(command, params, client) {
}
getClanData(clanId).name = params;
+ getClanData(clanId).needsSaved = true;
- messageAdmins(`{ALTCOLOUR}${getPlayerName(client)} {MAINCOLOUR}set clan {clanOrange}${getClanData(clanId).index} {MAINCOLOUR}name to {ALTCOLOUR}${params}`);
+ //messageAdmins(`{adminOrange}${getPlayerName(client)} {MAINCOLOUR}set clan {clanOrange}${getClanData(clanId).index} {MAINCOLOUR}name to {ALTCOLOUR}${params}`);
+ messagePlayerSuccess(client, `You changed the clan name to {ALTCOLOUR}${params}`);
}
// ===========================================================================
@@ -356,8 +361,9 @@ function deleteClanRankCommand(command, params, client) {
}
removeClanRank(clanId, rankId);
+ getClanData(clanId).needsSaved = true;
- messagePlayerSuccess(client, `You removed the {ALTCOLOUR}${tempRankName} {MAINCOLOUR}rank`);
+ messagePlayerSuccess(client, `You removed the {ALTCOLOUR}${tempRankName}{MAINCOLOUR} rank`);
}
// ===========================================================================
@@ -399,7 +405,7 @@ function setClanMemberTagCommand(command, params, client) {
}
}
- getPlayerCurrentSubAccount(targetClient).ClanTag = getParam(params, " ", 2);
+ getPlayerCurrentSubAccount(targetClient).clanTag = getParam(params, " ", 2);
messagePlayerSuccess(client, `You set {ALTCOLOUR}${getCharacterFullName(targetClient)}'s {MAINCOLOUR}clan tag to {ALTCOLOUR}${getParam(params, " ", 2)}`);
messagePlayerAlert(client, `{ALTCOLOUR}${getCharacterFullName(targetClient)} {MAINCOLOUR}set your clan tag to {ALTCOLOUR}${getParam(params, " ", 2)}`);
@@ -433,7 +439,8 @@ function setClanRankTagCommand(command, params, client) {
}
}
- getServerData().clans[clanId].rankId[rankId].customTag = newTag;
+ getClanRankData(clanId, rankId).customTag = newTag;
+ getClanRankData(clanId, rankId).needsSaved = true;
}
// ===========================================================================
@@ -481,7 +488,8 @@ function setClanRankLevelCommand(command, params, client) {
return false;
}
- getServerData().clans[clanId].rankId[rankId].level = toInteger(newLevel);
+ getClanRankData(clanId, rankId).level = toInteger(newLevel);
+ getClanRankData(clanId, rankId).needsSaved = true;
}
// ===========================================================================
@@ -620,7 +628,8 @@ function addClanRankFlagCommand(command, params, client) {
let flagValue = getClanFlagValue(getParam(params, " ", 2));
- addBitFlag(getClanRankData(clanId, rankId).flags, flagValue);
+ getClanRankData(clanId, rankId).flags = addBitFlag(getClanRankData(clanId, rankId).flags, flagValue);
+ getClanRankData(clanId, rankId).needsSaved = true;
messagePlayerSuccess(client, `You added the {ALTCOLOUR}${getParam(params, " ", 2)} {MAINCOLOUR}clan flag to rank {ALTCOLOUR}${getClanRankData(clanId, rankId).name}`);
}
@@ -658,7 +667,8 @@ function removeClanRankFlagCommand(command, params, client) {
let flagValue = getClanFlagValue(getParam(params, " ", 2));
- removeBitFlag(getClanRankData(clanId, rankId).flags, flagValue);
+ getClanRankData(clanId, rankId).flags = removeBitFlag(getClanRankData(clanId, rankId).flags, flagValue);
+ getClanRankData(clanId, rankId).needsSaved = true;
messagePlayerSuccess(client, `You removed the {ALTCOLOUR}${getParam(params, " ", 2)} {MAINCOLOUR}clan flag from rank {ALTCOLOUR}${getClanRankData(clanId, rankId).name}`);
}
@@ -702,8 +712,7 @@ function showClanRankFlagsCommand(command, params, client) {
let chunkedList = splitArrayIntoChunks(flagList, 6);
- messagePlayerInfo(client, `{clanOrange}== {jobYellow}Clan Rank Flags (${getClanRankData(clanId, rankId).name}){clanOrange}===================`);
-
+ makeChatBoxSectionHeader(client, getLocaleString(client, "ClanRankFlags"), getClanRankData(clanId, rankId).name);
for(let i in chunkedList) {
messagePlayerInfo(client, chunkedList[i].join("{MAINCOLOUR}, "));
}
@@ -784,6 +793,7 @@ function setClanRankTitleCommand(command, params, client) {
let oldRankName = getClanRankData(clanId, rankId).name;
getClanRankData(clanId, rankId).name = getParam(params, " ", 2);
+ getClanRankData(clanId, rankId).needsSaved = true;
messagePlayerSuccess(client, `You changed the name of rank ${rankId} from {ALTCOLOUR}${oldRankName} {MAINCOLOUR}to {ALTCOLOUR}${params}`);
}
@@ -844,7 +854,7 @@ function setClanMemberRankCommand(command, params, client) {
let oldClanRank = getClanRankData(clanId, getPlayerClanRank(targetClient));
getPlayerCurrentSubAccount(targetClient).clanRank = getClanRankData(clanId, rankId).databaseId;
getPlayerCurrentSubAccount(targetClient).clanRankIndex = rankId;
- messagePlayerSuccess(client, `You changed {ALTCOLOUR}${getCharacterFullName(targetClient)}'s {MAINCOLOUR}rank from {ALTCOLOUR}${oldClanRank.name} {MAINCOLOUR}to {ALTCOLOUR}${getClanRankData(clanId, rankId).name}`);
+ messagePlayerSuccess(client, `You changed {ALTCOLOUR}${getCharacterFullName(targetClient)}'s{MAINCOLOUR} rank from {ALTCOLOUR}${oldClanRank.name}{MAINCOLOUR} to {ALTCOLOUR}${getClanRankData(clanId, rankId).name}`);
}
// ===========================================================================
@@ -870,7 +880,7 @@ function createClan(name) {
// ===========================================================================
function deleteClan(clanId) {
- saveClansToDatabase();
+ //saveAllClansToDatabase();
let dbConnection = connectToDatabase();
if(dbConnection) {
@@ -927,12 +937,20 @@ function doesClanIdExist(clanId) {
// ===========================================================================
function reloadAllClans() {
+ if(getServerConfig().devServer) {
+ return false;
+ }
+
getServerData().clans = loadClansFromDatabase();
}
// ===========================================================================
-function saveAllClanRanksToDatabase(clanId) {
+function saveClanRanksToDatabase(clanId) {
+ if(getServerConfig().devServer) {
+ return false;
+ }
+
let ranks = getServerData().clans[clanId].ranks;
for(let i in ranks) {
saveClanRankToDatabase(clanId, i);
@@ -948,9 +966,13 @@ function saveClanToDatabase(clanId) {
return false;
}
- if(!tempClanData.needsSaved) {
- return false;
- }
+ if(tempClanData.databaseId == -1) {
+ return false;
+ }
+
+ if(!tempClanData.needsSaved) {
+ return false;
+ }
let dbConnection = connectToDatabase();
if(dbConnection) {
@@ -982,7 +1004,7 @@ function saveClanToDatabase(clanId) {
disconnectFromDatabase(dbConnection);
}
- saveAllClanRanksToDatabase(clanId);
+ saveClanRanksToDatabase(clanId);
return true;
}
@@ -994,41 +1016,41 @@ function saveClanToDatabase(clanId) {
function saveClanRankToDatabase(clanId, rankId) {
let tempClanRankData = getClanRankData(clanId, rankId);
- if(!tempClanRankData.needsSaved) {
- return false;
- }
+ if(!tempClanRankData.needsSaved) {
+ return false;
+ }
let dbConnection = connectToDatabase();
if(dbConnection) {
- let safeName = escapeDatabaseString(dbConnection, tempClanRankData.name);
- let safeTag = escapeDatabaseString(dbConnection, tempClanRankData.customTag);
- //let safeTitle = escapeDatabaseString(dbConnection, tempClanRankData.name);
+ let safeName = escapeDatabaseString(dbConnection, tempClanRankData.name);
+ let safeTag = escapeDatabaseString(dbConnection, tempClanRankData.customTag);
+ //let safeTitle = escapeDatabaseString(dbConnection, tempClanRankData.name);
- let data = [
- ["clan_rank_name", safeName],
- ["clan_rank_clan", tempClanRankData.clan],
- ["clan_rank_custom_tag", safeTag],
- //["clan_rank_title", safeTitle],
- ["clan_rank_flags", tempClanRankData.flags],
- ["clan_rank_level", tempClanRankData.level],
- ["clan_rank_enabled", boolToInt(tempClanRankData.enabled)],
- ];
+ let data = [
+ ["clan_rank_name", safeName],
+ ["clan_rank_clan", tempClanRankData.clan],
+ ["clan_rank_custom_tag", safeTag],
+ //["clan_rank_title", safeTitle],
+ ["clan_rank_flags", tempClanRankData.flags],
+ ["clan_rank_level", tempClanRankData.level],
+ ["clan_rank_enabled", boolToInt(tempClanRankData.enabled)],
+ ];
- let dbQuery = null;
- if(tempClanRankData.databaseId == 0) {
- let queryString = createDatabaseInsertQuery("clan_rank", data);
- dbQuery = queryDatabase(dbConnection, queryString);
- getClanRankData(clanId, rankId).databaseId = getDatabaseInsertId(dbConnection);
- getClanRankData(clanId, rankId).needsSaved = false;
- } else {
- let queryString = createDatabaseUpdateQuery("clan_rank", data, `clan_rank_id=${tempClanRankData.databaseId} LIMIT 1`);
- dbQuery = queryDatabase(dbConnection, queryString);
- getClanRankData(clanId, rankId).needsSaved = false;
- }
+ let dbQuery = null;
+ if(tempClanRankData.databaseId == 0) {
+ let queryString = createDatabaseInsertQuery("clan_rank", data);
+ dbQuery = queryDatabase(dbConnection, queryString);
+ getClanRankData(clanId, rankId).databaseId = getDatabaseInsertId(dbConnection);
+ getClanRankData(clanId, rankId).needsSaved = false;
+ } else {
+ let queryString = createDatabaseUpdateQuery("clan_rank", data, `clan_rank_id=${tempClanRankData.databaseId} LIMIT 1`);
+ dbQuery = queryDatabase(dbConnection, queryString);
+ getClanRankData(clanId, rankId).needsSaved = false;
+ }
- freeDatabaseQuery(dbQuery);
- disconnectFromDatabase(dbConnection);
- return true;
+ freeDatabaseQuery(dbQuery);
+ disconnectFromDatabase(dbConnection);
+ return true;
}
return false;
@@ -1072,6 +1094,10 @@ function setClanRankTitle(clanId, rankId, title) {
// ===========================================================================
function saveAllClansToDatabase() {
+ if(getServerConfig().devServer) {
+ return false;
+ }
+
for(let i in getServerData().clans) {
saveClanToDatabase(i);
}
@@ -1134,6 +1160,11 @@ function getClanRankIdFromDatabaseId(clanId, databaseId) {
// ===========================================================================
+/**
+ * @param {number} clanId - The data index of the clan
+ * @param {number} clanRankId - The data index of the clan rank
+ * @return {ClanRankData} The clan rank's data (class instance)
+ */
function getClanRankData(clanId, rankId) {
return getServerData().clans[clanId].ranks[rankId];
}
@@ -1190,7 +1221,7 @@ function showClanFlagListCommand(command, params, client) {
return false;
}
-let rankId = getClanRankFromParams(clanId, getParam(params, " ", 1));
+ let rankId = getClanRankFromParams(clanId, getParam(params, " ", 1));
if(!getClanRankData(clanId, rankId)) {
messagePlayerError(client, getLocaleString(client, "ClanRankInvalid"));
@@ -1213,6 +1244,12 @@ let rankId = getClanRankFromParams(clanId, getParam(params, " ", 1));
}
*/
+// ===========================================================================
+
+/**
+ * @param {String} params - The params to search for
+ * @return {Number} The data index of a matching clan
+ */
function getClanFromParams(params) {
if(isNaN(params)) {
for(let i in getServerData().clans) {
@@ -1231,6 +1268,11 @@ function getClanFromParams(params) {
// ===========================================================================
+/**
+ * @param {Number} clanId - The clan ID to search ranks for
+ * @param {String} params - The params to search for
+ * @return {Number} The data index of a matching clan
+ */
function getClanRankFromParams(clanId, params) {
if(isNaN(params)) {
for(let i in getClanData(clanId).ranks) {
diff --git a/scripts/server/class.js b/scripts/server/class.js
index a4d92a13..aa8f7ea4 100644
--- a/scripts/server/class.js
+++ b/scripts/server/class.js
@@ -7,8 +7,6 @@
// TYPE: Server (JavaScript)
// ===========================================================================
-// ===========================================================================
-
function initClassScript() {
logToConsole(LOG_INFO, "[VRR.Class]: Initializing class script ...");
logToConsole(LOG_INFO, "[VRR.Class]: Class script initialized successfully!");
@@ -19,7 +17,7 @@ function initClassScript() {
/**
* @class Representing data for server configuration
*/
-class ServerData {
+class ServerConfigData {
constructor(dbAssoc = false) {
this.databaseId = 0;
this.needsSaved = false;
@@ -58,7 +56,8 @@ class ServerData {
this.showLogo = true;
this.inflationMultiplier = 1;
this.testerOnly = false;
- this.settings = 0;
+ this.devServer = false;
+ this.nameTagDistance = 50.0;
this.antiCheat = {
enabled: false,
@@ -87,12 +86,9 @@ class ServerData {
this.realTimeZone = 0;
this.discordConfig = {
- eventChannelWebHookURL: "",
- chatChannelWebHookURL: "",
- adminChannelWebHookURL: "",
sendEvents: true,
sendChat: true,
- sendAdminEvents: true,
+ sendAdmin: true,
};
if(dbAssoc) {
@@ -104,7 +100,6 @@ class ServerData {
bank: dbAssoc["svr_newchar_bank"],
skin: dbAssoc["svr_newchar_skin"],
},
- this.settings = toInteger(dbAssoc["svr_settings"]);
this.connectCameraPosition = toVector3(dbAssoc["svr_connectcam_pos_x"], dbAssoc["svr_connectcam_pos_y"], dbAssoc["svr_connectcam_pos_z"]);
this.connectCameraLookAt = toVector3(dbAssoc["svr_connectcam_lookat_x"], dbAssoc["svr_connectcam_lookat_y"], dbAssoc["svr_connectcam_lookat_z"]);
@@ -113,24 +108,42 @@ class ServerData {
this.minute = toInteger(dbAssoc["svr_start_time_min"]);
this.minuteDuration = toInteger(dbAssoc["svr_time_min_duration"]);
this.weather = toInteger(dbAssoc["svr_start_weather"]);
+ this.fallingSnow = intToBool(toInteger(dbAssoc["svr_snow_falling"]));
+ this.groundSnow = intToBool(toInteger(dbAssoc["svr_snow_ground"]));
+ this.useGUI = intToBool(toInteger(dbAssoc["svr_gui"]));
+ this.showLogo = intToBool(toInteger(dbAssoc["svr_logo"]));
+ this.createJobPickups = intToBool(toInteger(dbAssoc["svr_job_pickups"]));
+ this.createBusinessPickups = intToBool(toInteger(dbAssoc["svr_biz_pickups"]));
+ this.createHousePickups = intToBool(toInteger(dbAssoc["svr_house_pickups"]));
+ this.createJobBlips = intToBool(toInteger(dbAssoc["svr_job_blips"]));
+ this.createBusinessBlips = intToBool(toInteger(dbAssoc["svr_biz_blips"]));
+ this.createHouseBlips = intToBool(toInteger(dbAssoc["svr_house_blips"]));
this.guiColourPrimary = [toInteger(dbAssoc["svr_gui_col1_r"]), toInteger(dbAssoc["svr_gui_col1_g"]), toInteger(dbAssoc["svr_gui_col1_b"])];
this.guiColourSecondary = [toInteger(dbAssoc["svr_gui_col2_r"]), toInteger(dbAssoc["svr_gui_col2_g"]), toInteger(dbAssoc["svr_gui_col2_b"])];
this.guiTextColourPrimary = [toInteger(dbAssoc["svr_gui_textcol1_r"]), toInteger(dbAssoc["svr_gui_textcol1_g"]), toInteger(dbAssoc["svr_gui_textcol1_b"])];
//this.guiTextColourSecondary = [toInteger(dbAssoc["svr_gui_textcol2_r"]), toInteger(dbAssoc["svr_gui_textcol2_g"]), toInteger(dbAssoc["svr_gui_textcol2_b"])];
this.inflationMultiplier = toFloat(dbAssoc["svr_inflation_multiplier"]);
-
+ this.nameTagDistance = toFloat(dbAssoc["svr_nametag_distance"]);
this.discordBotToken = intToBool(dbAssoc["svr_discord_bot_token"]);
this.introMusicURL = dbAssoc["svr_intro_music"];
- this.realTimeZone = dbAssoc["svr_time_realtime_timezone"];
- this.discordConfig = {
- eventChannelWebHookURL: dbAssoc["svr_discord_event_webhook"],
- chatChannelWebHookURL: dbAssoc["svr_discord_chat_webhook"],
- adminChannelWebHookURL: dbAssoc["svr_discord_admin_webhook"],
- sendEvents: true,
- sendChat: true,
- sendAdminEvents: true,
+ //this.useRealTime = intToBool(toInteger(dbAssoc["svr_real_time_enabled"]));
+ //this.realTimeZone = dbAssoc["svr_real_time_timezone"];
+
+ this.discord = {
+ sendEvents: intToBool(dbAssoc["svr_discord_send_events"]),
+ sendChat: intToBool(dbAssoc["svr_discord_send_chat"]),
+ sendAdmin: intToBool(dbAssoc["svr_discord_send_admin"]),
};
+
+ this.economy = {
+ inflationMultiplier: toFloat(dbAssoc["svr_inflation_multiplier"]),
+ incomeTaxRate: toFloat(dbAssoc["svr_income_tax_rate"]),
+ passiveIncome: toFloat(dbAssoc["svr_passive_income"]),
+ }
+
+ this.devServer = intToBool(toInteger(server.getCVar("vrr_devserver")));
+ this.testerOnly = intToBool(toInteger(server.getCVar("vrr_testeronly")));
}
}
};
@@ -149,6 +162,7 @@ class ClientData {
this.connectTime = 0;
this.clientVersion = "0.0.0";
this.loginAttemptsRemaining = 3;
+ this.passwordResetAttemptsRemaining = 3;
this.afk = false;
this.jobRoute = -1;
@@ -240,7 +254,9 @@ class ClientData {
this.enteringVehicle = null;
- this.pedId = -1;
+ this.customDisconnectReason = "";
+
+ this.interiorCutscene = -1;
}
};
@@ -273,6 +289,7 @@ class AccountData {
this.twoFactorAuthVerificationCode = "";
this.chatScrollLines = 1;
+ this.chatAutoHideDelay = 0;
this.streamingRadioVolume = 20;
this.locale = 0;
@@ -302,6 +319,7 @@ class AccountData {
this.emailVerificationCode = dbAssoc["acct_code_verifyemail"];
this.twoFactorAuthVerificationCode = dbAssoc["acct_code_2fa"];
this.chatScrollLines = toInteger(dbAssoc["acct_svr_chat_scroll_lines"]);
+ this.chatAutoHideDelay = toInteger(dbAssoc["acct_svr_chat_auto_hide_delay"]);
this.streamingRadioVolume = toInteger(dbAssoc["acct_streaming_radio_volume"]);
this.locale = toInteger(dbAssoc["acct_locale"]);
}
@@ -526,6 +544,7 @@ class BusinessData {
this.entranceBlipModel = -1;
this.entrancePickup = null;
this.entranceBlip = null;
+ this.entranceCutscene = -1;
this.exitPosition = false;
this.exitRotation = 0.0;
@@ -535,6 +554,7 @@ class BusinessData {
this.exitBlipModel = -1;
this.exitPickup = null;
this.exitBlip = null;
+ this.exitCutscene = -1;
this.entranceFee = 0;
this.till = 0;
@@ -543,6 +563,10 @@ class BusinessData {
this.labelHelpType = VRR_PROPLABEL_INFO_NONE;
+ this.triggers = [];
+
+ this.customInterior = false;
+
if(dbAssoc) {
this.databaseId = toInteger(dbAssoc["biz_id"]);
this.name = toString(dbAssoc["biz_name"]);
@@ -559,6 +583,7 @@ class BusinessData {
this.entranceDimension = toInteger(dbAssoc["biz_entrance_vw"]);
this.entrancePickupModel = toInteger(dbAssoc["biz_entrance_pickup"]);
this.entranceBlipModel = toInteger(dbAssoc["biz_entrance_blip"]);
+ this.entranceCutscene = toInteger(dbAssoc["biz_entrance_cutscene"]);
this.exitPosition = toVector3(dbAssoc["biz_exit_pos_x"], dbAssoc["biz_exit_pos_y"], dbAssoc["biz_exit_pos_z"]);
this.exitRotation = toInteger(dbAssoc["biz_exit_rot_z"]);
@@ -566,12 +591,14 @@ class BusinessData {
this.exitDimension = toInteger(dbAssoc["biz_exit_vw"]);
this.exitPickupModel = toInteger(dbAssoc["biz_exit_pickup"]);
this.exitBlipModel = toInteger(dbAssoc["biz_exit_blip"]);
+ this.exitCutscene = toInteger(dbAssoc["biz_exit_cutscene"]);
this.entranceFee = toInteger(dbAssoc["biz_entrance_fee"]);
this.till = toInteger(dbAssoc["biz_till"]);
this.labelHelpType = toInteger(dbAssoc["biz_label_help_type"]);
this.streamingRadioStation = toInteger(dbAssoc["biz_radiostation"]);
+ this.customInterior = intToBool(toInteger(dbAssoc["biz_custom_interior"]));
}
};
};
@@ -672,6 +699,10 @@ class HouseData {
this.streamingRadioStation = -1;
+ this.triggers = [];
+
+ this.customInterior = false;
+
if(dbAssoc) {
this.databaseId = toInteger(dbAssoc["house_id"]);
this.description = toString(dbAssoc["house_description"]);
@@ -690,6 +721,7 @@ class HouseData {
this.entranceDimension = toInteger(dbAssoc["house_entrance_vw"]);
this.entrancePickupModel = toInteger(dbAssoc["house_entrance_pickup"]);
this.entranceBlipModel = toInteger(dbAssoc["house_entrance_blip"]);
+ this.entranceCutscene = toInteger(dbAssoc["house_entrance_cutscene"]);
this.exitPosition = toVector3(toFloat(dbAssoc["house_exit_pos_x"]), toFloat(dbAssoc["house_exit_pos_y"]), toFloat(dbAssoc["house_exit_pos_z"]));
this.exitRotation = toFloat(dbAssoc["house_exit_rot_z"]);
@@ -697,6 +729,9 @@ class HouseData {
this.exitDimension = toInteger(dbAssoc["house_exit_vw"]);
this.exitPickupModel = toInteger(dbAssoc["house_exit_pickup"]);
this.exitBlipModel = toInteger(dbAssoc["house_exit_blip"]);
+ this.exitCutscene = toInteger(dbAssoc["house_exit_cutscene"]);
+
+ this.customInterior = intToBool(toInteger(dbAssoc["house_custom_interior"]));
}
}
};
@@ -864,6 +899,11 @@ class VehicleData {
this.index = -1;
this.needsSaved = false;
+ // GTA IV
+ this.ivNetworkId = -1;
+ this.syncPosition = toVector3(0.0, 0.0, 0.0);
+ this.syncHeading = 0.0;
+
// Ownership
this.ownerType = VRR_VEHOWNER_NONE;
this.ownerId = 0;
@@ -888,21 +928,7 @@ class VehicleData {
this.colour4 = (vehicle) ? vehicle.colour4 : 1;
this.livery = 3;
- this.extras = [
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- ];
+ this.mods = [];
// Vehicle Attributes
this.locked = false;
@@ -925,12 +951,15 @@ class VehicleData {
this.needsSaved = false;
this.whoAdded = 0;
this.whenAdded = 0;
+ this.licensePlate = "";
this.interior = 0;
this.dimension = 0;
this.lastActiveTime = false;
+ this.triggers = [];
+
if(dbAssoc) {
// General Info
this.databaseId = toInteger(dbAssoc["veh_id"]);
@@ -959,23 +988,6 @@ class VehicleData {
this.colour4 = toInteger(dbAssoc["veh_col4"]);
this.livery = toInteger(dbAssoc["veh_livery"]);
- // Extras (components on SA, extras on IV+)
- this.extras = [
- toInteger(dbAssoc["veh_extra1"]),
- toInteger(dbAssoc["veh_extra2"]),
- toInteger(dbAssoc["veh_extra3"]),
- toInteger(dbAssoc["veh_extra4"]),
- toInteger(dbAssoc["veh_extra5"]),
- toInteger(dbAssoc["veh_extra6"]),
- toInteger(dbAssoc["veh_extra7"]),
- toInteger(dbAssoc["veh_extra8"]),
- toInteger(dbAssoc["veh_extra9"]),
- toInteger(dbAssoc["veh_extra10"]),
- toInteger(dbAssoc["veh_extra11"]),
- toInteger(dbAssoc["veh_extra12"]),
- toInteger(dbAssoc["veh_extra13"]),
- ];
-
// Vehicle Attributes
this.locked = intToBool(toInteger(dbAssoc["veh_locked"]));
this.engine = intToBool(toInteger(dbAssoc["veh_engine"]));
@@ -992,6 +1004,7 @@ class VehicleData {
this.needsSaved = false;
this.whoAdded = toInteger(dbAssoc["veh_who_added"]);
this.whenAdded = toInteger(dbAssoc["veh_when_added"]);
+ this.licensePlate = toInteger(dbAssoc["veh_license_plate"]);
this.interior = toInteger(dbAssoc["veh_int"]);
this.dimension = toInteger(dbAssoc["veh_vw"]);
@@ -1000,7 +1013,7 @@ class VehicleData {
};
/**
- * @class Representing a command's data. Loaded and saved in the database
+ * @class Representing a command's data.
*/
class CommandData {
enable() {
@@ -1015,7 +1028,7 @@ class CommandData {
this.enabled = !this.enabled;
}
- constructor(command, handlerFunction, syntaxString, requiredStaffFlags, requireLogin, allowOnDiscord, helpDescription) {
+ constructor(command, handlerFunction, syntaxString = "", requiredStaffFlags = 0, requireLogin = true, allowOnDiscord = false, helpDescription = "") {
this.command = command;
this.handlerFunction = handlerFunction;
this.syntaxString = syntaxString;
@@ -1225,14 +1238,12 @@ class JobLocationData {
this.routeCache = [];
if(dbAssoc) {
- this.databaseId = dbAssoc["job_loc_id"];
- this.jobId = dbAssoc["job_loc_job"];
- this.position = toVector3(dbAssoc["job_loc_pos_x"], dbAssoc["job_loc_pos_y"], dbAssoc["job_loc_pos_z"]);
- this.blip = false;
- this.pickup = false;
- this.enabled = dbAssoc["job_loc_enabled"];
- this.interior = dbAssoc["job_loc_int"];
- this.dimension = dbAssoc["job_loc_vw"];
+ this.databaseId = toInteger(dbAssoc["job_loc_id"]);
+ this.jobId = toInteger(dbAssoc["job_loc_job"]);
+ this.position = toVector3(toFloat(dbAssoc["job_loc_pos_x"]), toFloat(dbAssoc["job_loc_pos_y"]), toFloat(dbAssoc["job_loc_pos_z"]));
+ this.enabled = toInteger(dbAssoc["job_loc_enabled"]);
+ this.interior = toInteger(dbAssoc["job_loc_int"]);
+ this.dimension = toInteger(dbAssoc["job_loc_vw"]);
}
}
};
@@ -1299,49 +1310,6 @@ class KeyBindData {
}
};
-class BlackListedGameScriptData {
- constructor(dbAssoc = false) {
- this.databaseId = 0;
- this.enabled = false
- this.serverId = 0;
- this.scriptName = "";
- this.index = -1;
- this.needsSaved = false;
-
- if(dbAssoc) {
- this.databaseId = dbAssoc["ac_script_bl_id"];
- this.enabled = intToBool(dbAssoc["ac_script_bl_enabled"]);
- this.serverId = dbAssoc["ac_script_bl_server"];
- this.scriptName = dbAssoc["ac_script_bl_name"];
- }
- }
-};
-
-class WhiteListedGameScriptData {
- constructor(dbAssoc = false) {
- this.databaseId = 0;
- this.enabled = false
- this.serverId = 0;
- this.scriptName = "";
- this.index = -1;
- this.needsSaved = false;
-
- if(dbAssoc) {
- this.databaseId = dbAssoc["ac_script_wl_id"];
- this.enabled = intToBool(dbAssoc["ac_script_wl_enabled"]);
- this.serverId = dbAssoc["ac_script_wl_server"];
- this.scriptName = dbAssoc["ac_script_wl_name"];
- }
- }
-};
-
-class InteriorTemplateData {
- constructor(exitPosition, exitInterior) {
- this.exitPosition = exitPosition;
- this.exitInterior = exitInterior;
- }
-};
-
class RadioStationData {
constructor(dbAssoc = false) {
this.databaseId = 0;
@@ -1483,17 +1451,18 @@ class ItemTypeData {
}
}
};
+
class NPCData {
constructor(dbAssoc = false) {
this.databaseId = 0;
this.serverId = 0;
- this.firstName = "John";
- this.lastName = "Doe";
- this.middleName = "Q";
+ this.name = "NPC";
this.skin = 0;
this.cash = 0;
- this.spawnPosition = toVector3(0.0, 0.0, 0.0);
- this.spawnHeading = 0.0;
+ this.position = toVector3(0.0, 0.0, 0.0);
+ this.rotation = toVector3(0.0, 0.0, 0.0);
+ this.scale = toVector3(1.0, 1.0, 1.0);
+ this.heading = 0.0;
this.clan = 0;
this.isWorking = false;
this.jobUniform = this.skin;
@@ -1502,13 +1471,19 @@ class NPCData {
this.weapons = [];
this.interior = 0;
this.dimension = 0;
- this.pedScale = toVector3(1.0, 1.0, 1.0);
this.walkStyle = 0;
this.fightStyle = 0;
this.health = 100;
this.armour = 100;
- this.currentAction = VRR_NPCACTION_NONE;
+ this.currentAction = VRR_NPC_ACTION_NONE;
this.triggers = [];
+ this.typeFlags = 0;
+ this.heedThreats = false;
+ this.threats = 0;
+ this.invincible = false;
+ this.animationName = "";
+ this.ownerType = VRR_NPCOWNER_NONE;
+ this.ownerId = 0;
this.bodyParts = {
hair: [0,0],
@@ -1530,29 +1505,33 @@ class NPCData {
rightFoot: [0,0],
};
+ this.triggers = [];
+
if(dbAssoc) {
this.databaseId = toInteger(dbAssoc["npc_id"]);
this.serverId = toInteger(dbAssoc["npc_server"]);
- this.firstName = dbAssoc["npc_name_first"];
- this.lastName = dbAssoc["npc_name_last"];
- this.middleName = dbAssoc["npc_name_middle"] || "";
+ this.name = dbAssoc["npc_name"];
this.skin = toInteger(dbAssoc["npc_skin"]);
this.cash = toInteger(dbAssoc["npc_cash"]);
- this.spawnPosition = toVector3(toFloat(dbAssoc["npc_pos_x"]), toFloat(dbAssoc["npc_pos_y"]), toFloat(dbAssoc["npc_pos_z"]));
- this.spawnHeading = toFloat(dbAssoc["npc_angle"]);
+ this.position = toVector3(toFloat(dbAssoc["npc_pos_x"]), toFloat(dbAssoc["npc_pos_y"]), toFloat(dbAssoc["npc_pos_z"]));
+ this.rotation = toVector3(toFloat(dbAssoc["npc_rot_x"]), toFloat(dbAssoc["npc_rot_y"]), toFloat(dbAssoc["npc_rot_z"]));
+ this.scale = toVector3(toFloat(dbAssoc["npc_scale_x"]), toFloat(dbAssoc["npc_scale_y"]), toFloat(dbAssoc["npc_scale_z"]));
+ this.heading = toFloat(dbAssoc["npc_rot_z"]);
this.lastLogin = toInteger(dbAssoc["npc_when_lastlogin"]);
- this.clan = toInteger(dbAssoc["npc_clan"]);
- this.clanFlags = toInteger(dbAssoc["npc_clan_flags"]);
- this.clanRank = toInteger(dbAssoc["npc_clan_rank"]);
- this.clanTitle = toInteger(dbAssoc["npc_clan_title"]);
+ this.rank = toInteger(dbAssoc["npc_rank"]);
+ this.title = toInteger(dbAssoc["npc_title"]);
this.job = toInteger(dbAssoc["npc_job"]);
this.interior = toInteger(dbAssoc["npc_int"]);
this.dimension = toInteger(dbAssoc["npc_vw"]);
- this.pedScale = toVector3(toFloat(dbAssoc["npc_scale_x"]), toFloat(dbAssoc["npc_scale_y"]), toFloat(dbAssoc["npc_scale_z"]));
this.walkStyle = toInteger(dbAssoc["npc_walkstyle"]);
this.fightStyle = toInteger(dbAssoc["npc_fightstyle"]);
this.health = toInteger(dbAssoc["npc_health"]);
this.armour = toInteger(dbAssoc["npc_armour"]);
+ this.typeFlags = toInteger(dbAssoc["npc_type_flags"]);
+ this.heedThreats = intToBool(dbAssoc["npc_headthreats"]);
+ this.threats = toInteger(dbAssoc["npc_threats"]);
+ this.invincible = intToBool(dbAssoc["npc_invincible"]);
+ this.animationName = intToBool(dbAssoc["npc_animation"]);
this.bodyParts = {
hair: [toInteger(dbAssoc["npc_hd_part_hair_model"]) || 0, toInteger(dbAssoc["npc_hd_part_hair_texture"]) || 0],
@@ -1653,28 +1632,6 @@ class BanData {
}
}
-class DeckCardData {
- constructor(imageName, value) {
- this.imageName = imageName,
- this.value = value;
- }
-}
-
-class DeckCardGameData {
- constructor() {
- this.gameType = VRR_DECKCARD_GAME_NONE;
- this.playedCards = [];
- this.remainingCards = [];
- }
-}
-
-class DeckCardHandData {
- constructor() {
- this.cards = [];
- this.total = 0;
- }
-}
-
class JobRouteData {
constructor(dbAssoc = false) {
this.databaseId = 0;
@@ -1705,7 +1662,7 @@ class JobRouteData {
this.pay = toInteger(dbAssoc["job_route_pay"]);
this.startMessage = toString(dbAssoc["job_route_start_msg"]);
this.finishMessage = toString(dbAssoc["job_route_finish_msg"]);
- this.locationArriveMessage = toString(dbAssoc["job_route_loc_arrive_msg"]);
+ this.locationArriveMessage = toString(dbAssoc["job_route_loc_arrive_msg"]);
this.locationNextMessage = toString(dbAssoc["job_route_loc_next_msg"]);
this.vehicleColour1 = toInteger(dbAssoc["job_route_veh_colour1"]);
this.vehicleColour2 = toInteger(dbAssoc["job_route_veh_colour2"]);
@@ -1721,7 +1678,7 @@ class JobRouteLocationData {
this.routeId = 0;
this.enabled = false;
this.index = -1;
- this.jobIndex = -1;
+ this.jobIndex = -1;
this.routeIndex = -1;
this.needsSaved = false;
this.position = toVector3(0.0, 0.0, 0.0);
@@ -1738,4 +1695,27 @@ class JobRouteLocationData {
this.pay = toInteger(dbAssoc["job_route_loc_pay"]);
}
}
-};
\ No newline at end of file
+};
+
+class GateData {
+ constructor(dbAssoc = false) {
+ this.databaseId = 0;
+ this.name = "";
+ this.scriptName = "";
+ this.enabled = false;
+ this.position = toVector3(0.0, 0.0, 0.0);
+ this.locked = true;
+ this.ownerType = VRR_GATEOWNER_NONE;
+ this.ownerId = 0;
+
+ if(dbAssoc) {
+ this.databaseId = toInteger(dbAssoc["gate_id"]);
+ this.name = toString(dbAssoc["gate_name"]);
+ this.scriptName = toString(dbAssoc["gate_script_name"]);
+ this.enabled = intToBool(toInteger(dbAssoc["gate_enabled"]));
+ this.position = toVector3(toFloat(dbAssoc["gate_pos_x"]), toFloat(dbAssoc["gate_pos_y"]), toFloat(dbAssoc["gate_pos_z"]));
+ this.ownerType = toInteger(dbAssoc["gate_owner_type"]);
+ this.ownerId = toInteger(dbAssoc["gate_owner_id"]);
+ }
+ }
+}
\ No newline at end of file
diff --git a/scripts/server/client.js b/scripts/server/client.js
index 992fa56d..d776ea15 100644
--- a/scripts/server/client.js
+++ b/scripts/server/client.js
@@ -67,14 +67,17 @@ function addAllNetworkHandlers() {
addNetworkEventHandler("vrr.itemActionDelayComplete", playerItemActionDelayComplete);
addNetworkEventHandler("vrr.weaponDamage", playerDamagedByPlayer);
+ // Locale
+ addNetworkEventHandler("vrr.localeSelect", playerSelectedNewLocale);
+
// Misc
- addNetworkEventHandler("vrr.player.position", updatePositionInPlayerData);
- addNetworkEventHandler("vrr.player.heading", updateHeadingInPlayerData);
- addNetworkEventHandler("vrr.player.lookat", setPlayerHeadLookPosition);
+ addNetworkEventHandler("vrr.plr.pos", updatePositionInPlayerData);
+ addNetworkEventHandler("vrr.plr.rot", updateHeadingInPlayerData);
addNetworkEventHandler("vrr.skinSelected", playerFinishedSkinSelection);
addNetworkEventHandler("vrr.clientInfo", updateConnectionLogOnClientInfoReceive);
addNetworkEventHandler("vrr.vehBuyState", receiveVehiclePurchaseStateUpdateFromClient);
addNetworkEventHandler("vrr.playerPedId", receivePlayerPedNetworkId);
+ addNetworkEventHandler("vrr.playerCop", setPlayerAsCopState);
}
// ===========================================================================
@@ -98,15 +101,15 @@ function updateAllPlayerNameTags() {
function updatePlayerPing(client) {
//logToConsole(LOG_DEBUG, `[VRR.Client] Sending ${getPlayerDisplayForConsole(client)}'s ping to all players`);
- sendNetworkEventToPlayer("vrr.ping", null, getPlayerName(client), client.ping);
+ sendNetworkEventToPlayer("vrr.ping", null, getPlayerName(client), getPlayerPing(client));
}
// ===========================================================================
function playerClientReady(client) {
- setEntityData(client, "vrr.isReady", true, false);
- logToConsole(LOG_DEBUG, `${getPlayerDisplayForConsole(client)}'s client resources are downloaded and ready!`);
- if(client.getData("vrr.isStarted") == true) {
+ playerResourceReady[client.index] = true;
+ logToConsole(LOG_DEBUG, `[VRR.Client] ${getPlayerDisplayForConsole(client)}'s client resources are downloaded and ready! Started: ${getYesNoFromBool(playerResourceStarted[client.index])}`);
+ if(playerResourceStarted[client.index] == true) {
initClient(client);
}
}
@@ -114,16 +117,16 @@ function playerClientReady(client) {
// ===========================================================================
function playerGUIReady(client) {
- setEntityData(client, "vrr.guiReady", true, false);
- logToConsole(LOG_DEBUG, `${getPlayerDisplayForConsole(client)}'s client GUI is initialized and ready!`);
+ playerGUI[client.index] = true;
+ logToConsole(LOG_DEBUG, `[VRR.Client] ${getPlayerDisplayForConsole(client)}'s client GUI is initialized and ready!`);
}
// ===========================================================================
function playerClientStarted(client) {
- setEntityData(client, "vrr.isStarted", true, false);
- logToConsole(LOG_DEBUG, `${getPlayerDisplayForConsole(client)}'s client resources are started and running!`);
- if(client.getData("vrr.isReady") == true) {
+ playerResourceStarted[client.index] = true;
+ logToConsole(LOG_DEBUG, `[VRR.Client] ${getPlayerDisplayForConsole(client)}'s client resources are started and running! Ready: ${getYesNoFromBool(playerResourceReady[client.index])}`);
+ if(playerResourceReady[client.index] == true) {
initClient(client);
}
}
@@ -131,15 +134,15 @@ function playerClientStarted(client) {
// ===========================================================================
function playerClientStopped(client) {
- logToConsole(LOG_DEBUG, `${getPlayerDisplayForConsole(client)}'s client resources have stopped (possibly error?). Kicking them from the server ...`);
- client.disconnect();
+ logToConsole(LOG_DEBUG, `[VRR.Client] ${getPlayerDisplayForConsole(client)}'s client resources have stopped (possibly error?). Kicking them from the server ...`);
+ disconnectPlayer(client);
}
// ===========================================================================
-function showGameMessage(client, text, colour, duration) {
+function showGameMessage(client, text, colour, duration, fontName = "Pricedown") {
logToConsole(LOG_DEBUG, `[VRR.Client] Showing game message to ${getPlayerDisplayForConsole(client)} (${text}) for ${duration} milliseconds`);
- sendNetworkEventToPlayer("vrr.smallGameMessage", client, text, colour, duration);
+ sendNetworkEventToPlayer("vrr.smallGameMessage", client, text, colour, duration, fontName);
}
// ===========================================================================
@@ -210,13 +213,13 @@ function setPlayer2DRendering(client, hudState = false, labelState = false, smal
function syncPlayerProperties(client) {
logToConsole(LOG_DEBUG, `[VRR.Client] Sending signal to sync ${getPlayerDisplayForConsole(client)}'s player ped properties`);
- sendNetworkEventToPlayer("vrr.player.sync", null, client.player);
+ sendNetworkEventToPlayer("vrr.syncElement", null, getPlayerPed(client).id);
}
// ===========================================================================
function updatePlayerSnowState(client) {
- if(isSnowSupported(getServerGame())) {
+ if(isSnowSupported(getGame())) {
logToConsole(LOG_DEBUG, `[VRR.Client] Setting ${getPlayerDisplayForConsole(client)}'s snow state (Falling: ${toUpperCase(getOnOffFromBool(getServerConfig().fallingSnow))}, Ground: ${toUpperCase(getOnOffFromBool(getServerConfig().groundSnow))})`);
sendNetworkEventToPlayer("vrr.snow", client, getServerConfig().fallingSnow, getServerConfig().groundSnow);
}
@@ -269,13 +272,6 @@ function sendJobRouteLocationToPlayer(client, position, colour) {
// ===========================================================================
-function showPlayerChangePasswordGUI(client) {
- logToConsole(LOG_DEBUG, `[VRR.Client] Sending change password GUI signal to ${getPlayerDisplayForConsole(client)}`);
- sendNetworkEventToPlayer("vrr.changePassword", client);
-}
-
-// ===========================================================================
-
function showPlayerLoginSuccessGUI(client) {
logToConsole(LOG_DEBUG, `[VRR.Client] Sending login success GUI signal to ${getPlayerDisplayForConsole(client)}`);
sendNetworkEventToPlayer("vrr.loginSuccess", client);
@@ -341,18 +337,25 @@ function showPlayerNewCharacterGUI(client) {
function showPlayerChangePasswordGUI(client, errorMessage = "") {
logToConsole(LOG_DEBUG, `[VRR.Client] Sending show change password GUI signal to ${getPlayerDisplayForConsole(client)}`);
- sendNetworkEventToPlayer("vrr.showChangePassword", client);
+ sendNetworkEventToPlayer("vrr.showChangePassword", client, errorMessage);
}
// ===========================================================================
function showPlayerResetPasswordCodeInputGUI(client) {
- logToConsole(LOG_DEBUG, `[VRR.Client] Sending show reset password GUI signal to ${getPlayerDisplayForConsole(client)}`);
+ logToConsole(LOG_DEBUG, `[VRR.Client] Sending show reset password code input GUI signal to ${getPlayerDisplayForConsole(client)}`);
sendNetworkEventToPlayer("vrr.showResetPasswordCodeInput", client);
}
// ===========================================================================
+function showPlayerResetPasswordEmailInputGUI(client) {
+ logToConsole(LOG_DEBUG, `[VRR.Client] Sending show reset password email input GUI signal to ${getPlayerDisplayForConsole(client)}`);
+ sendNetworkEventToPlayer("vrr.showResetPasswordEmailInput", client);
+}
+
+// ===========================================================================
+
function showPlayerCharacterSelectGUI(client, firstName, lastName, cash, clan, lastPlayed, skin) {
logToConsole(LOG_DEBUG, `[VRR.Client] Sending character select GUI signal to ${getPlayerDisplayForConsole(client)}`);
sendNetworkEventToPlayer("vrr.showCharacterSelect", client, firstName, lastName, cash, clan, lastPlayed, skin);
@@ -381,8 +384,8 @@ function showPlayerCharacterSelectFailedGUI(client) {
// ===========================================================================
-function showPlayerPromptGUI(client, promptMessage, promptTitle, yesButtonText, noButtonText) {
- logToConsole(LOG_DEBUG, `[VRR.Client] Sending show prompt GUI signal to ${getPlayerDisplayForConsole(client)} (Title: ${promptTitle}, Message: ${promptMessage})`);
+function showPlayerPromptGUI(client, promptMessage, promptTitle, yesButtonText = "Yes", noButtonText = "No") {
+ logToConsole(LOG_DEBUG, `[VRR.Client] Sending show prompt GUI signal to ${getPlayerDisplayForConsole(client)} (Title: ${promptTitle}, Message: ${promptMessage}, YesButton: ${yesButtonText}, NoButton: ${noButtonText})`);
sendNetworkEventToPlayer("vrr.showPrompt", client, promptMessage, promptTitle, yesButtonText, noButtonText);
}
@@ -397,14 +400,14 @@ function showPlayerInfoGUI(client, infoMessage, infoTitle, buttonText = "OK") {
function showPlayerErrorGUI(client, errorMessage, errorTitle, buttonText = "OK") {
logToConsole(LOG_DEBUG, `[VRR.Client] Sending show error GUI signal to ${getPlayerDisplayForConsole(client)} (Title: ${errorTitle}, Message: ${errorMessage})`);
- sendNetworkEventToPlayer("vrr.showInfo", client, errorMessage, errorTitle, buttonText);
+ sendNetworkEventToPlayer("vrr.showError", client, errorMessage, errorTitle, buttonText);
}
// ===========================================================================
function sendRunCodeToClient(client, code, returnTo) {
logToConsole(LOG_DEBUG, `[VRR.Client] Sending runcode to ${getPlayerDisplayForConsole(client)} (returnTo: ${getPlayerDisplayForConsole(getClientFromIndex(returnTo))}, Code: ${code})`);
- sendNetworkEventToPlayer("vrr.runCode", client, code, returnTo);
+ sendNetworkEventToPlayer("vrr.runCode", client, code, getPlayerId(returnTo));
}
// ===========================================================================
@@ -500,9 +503,9 @@ function sendPlayerFrozenState(client, state) {
// ===========================================================================
-function clearPlayerWeapons(client) {
+function clearPlayerWeapons(client, clearData = true) {
logToConsole(LOG_DEBUG, `[VRR.Client] Sending signal to ${getPlayerDisplayForConsole(client)} to clear weapons`);
- sendNetworkEventToPlayer("vrr.clearWeapons", client);
+ sendNetworkEventToPlayer("vrr.clearWeapons", client, clearData);
}
// ===========================================================================
@@ -521,9 +524,9 @@ function sendPlayerRemoveFromVehicle(client) {
// ===========================================================================
-function sendChatBoxMessageToPlayer(client, message, colour) {
- sendNetworkEventToPlayer("vrr.m", client, message, colour)
- //messageClient(message, client, colour);
+function sendChatBoxMessageToPlayer(client, messageText, colour) {
+ //messageClient(messageText, client, colour);
+ sendNetworkEventToPlayer("m", client, messageText, colour);
}
// ===========================================================================
@@ -716,18 +719,30 @@ function updateHeadingInPlayerData(client, heading) {
// ===========================================================================
+function updatePositionInVehicleData(client, vehicle, position) {
+ getVehicleData(vehicle).syncPosition = position;
+}
+
+// ===========================================================================
+
+function updateHeadingInVehicleData(client, vehicle, heading) {
+ getVehicleData(vehicle).syncHeading = heading;
+}
+
+// ===========================================================================
+
function forcePlayerIntoSkinSelect(client) {
- if(getGameConfig().skinChangePosition[getServerGame()].length > 0) {
+ if(typeof getGameConfig().skinChangePosition[getGame()] != "undefined") {
getPlayerData(client).returnToPosition = getPlayerPosition(client);
getPlayerData(client).returnToHeading = getPlayerHeading(client);
getPlayerData(client).returnToInterior = getPlayerInterior(client);
getPlayerData(client).returnToDimension = getPlayerDimension(client);
getPlayerData(client).returnToType = VRR_RETURNTO_TYPE_SKINSELECT;
- setPlayerPosition(client, getGameConfig().skinChangePosition[getServerGame()][0]);
- setPlayerHeading(client, getGameConfig().skinChangePosition[getServerGame()][1]);
- setPlayerInterior(client, getGameConfig().skinChangePosition[getServerGame()][2]);
- setPlayerDimension(client, client.index+500);
+ setPlayerPosition(client, getGameConfig().skinChangePosition[getGame()][0]);
+ setPlayerHeading(client, getGameConfig().skinChangePosition[getGame()][1]);
+ setPlayerInterior(client, getGameConfig().skinChangePosition[getGame()][2]);
+ setPlayerDimension(client, getPlayerId(client)+500);
}
sendNetworkEventToPlayer("vrr.skinSelect", client, true);
@@ -742,14 +757,14 @@ function updatePlayerCash(client) {
// ===========================================================================
function sendAllPoliceStationBlips(client) {
- if(getGameConfig().blipSprites[getServerGame()].policeStation != -1) {
+ if(getGameConfig().blipSprites[getGame()].policeStation != -1) {
let tempBlips = [];
- for(let i in getServerData().policeStations[getServerGame()]) {
+ for(let i in getServerData().policeStations[getGame()]) {
tempBlips.push([
- getGameConfig().blipSprites[getServerGame()].policeStation,
- getServerData().policeStations[getServerGame()][i].position.x,
- getServerData().policeStations[getServerGame()][i].position.y,
- getServerData().policeStations[getServerGame()][i].position.z,
+ getGameConfig().blipSprites[getGame()].policeStation,
+ getServerData().policeStations[getGame()][i].position.x,
+ getServerData().policeStations[getGame()][i].position.y,
+ getServerData().policeStations[getGame()][i].position.z,
3,
getColourByName("policeBlue"),
]);
@@ -761,14 +776,14 @@ function sendAllPoliceStationBlips(client) {
// ===========================================================================
function sendAllFireStationBlips(client) {
- if(getGameConfig().blipSprites[getServerGame()].fireStation != -1) {
+ if(getGameConfig().blipSprites[getGame()].fireStation != -1) {
let tempBlips = [];
- for(let i in getServerData().fireStations[getServerGame()]) {
+ for(let i in getServerData().fireStations[getGame()]) {
tempBlips.push([
- getGameConfig().blipSprites[getServerGame()].fireStation,
- getServerData().fireStations[getServerGame()][i].position.x,
- getServerData().fireStations[getServerGame()][i].position.y,
- getServerData().fireStations[getServerGame()][i].position.z,
+ getGameConfig().blipSprites[getGame()].fireStation,
+ getServerData().fireStations[getGame()][i].position.x,
+ getServerData().fireStations[getGame()][i].position.y,
+ getServerData().fireStations[getGame()][i].position.z,
3,
getColourByName("firefighterRed"),
]);
@@ -780,14 +795,14 @@ function sendAllFireStationBlips(client) {
// ===========================================================================
function sendAllHospitalBlips(client) {
- if(getGameConfig().blipSprites[getServerGame()].hospital != -1) {
+ if(getGameConfig().blipSprites[getGame()].hospital != -1) {
let tempBlips = [];
- for(let i in getServerData().hospitals[getServerGame()]) {
+ for(let i in getServerData().hospitals[getGame()]) {
tempBlips.push([
- getGameConfig().blipSprites[getServerGame()].hospital,
- getServerData().hospitals[getServerGame()][i].position.x,
- getServerData().hospitals[getServerGame()][i].position.y,
- getServerData().hospitals[getServerGame()][i].position.z,
+ getGameConfig().blipSprites[getGame()].hospital,
+ getServerData().hospitals[getGame()][i].position.x,
+ getServerData().hospitals[getGame()][i].position.y,
+ getServerData().hospitals[getGame()][i].position.z,
3,
getColourByName("medicPink"),
]);
@@ -799,14 +814,14 @@ function sendAllHospitalBlips(client) {
// ===========================================================================
function sendAllAmmunationBlips(client) {
- if(getGameConfig().blipSprites[getServerGame()].ammunation != -1) {
+ if(getGameConfig().blipSprites[getGame()].ammunation != -1) {
let tempBlips = [];
- for(let i in getServerData().ammunations[getServerGame()]) {
+ for(let i in getServerData().ammunations[getGame()]) {
tempBlips.push([
- getGameConfig().blipSprites[getServerGame()].ammunation,
- getServerData().ammunations[getServerGame()][i].position.x,
- getServerData().ammunations[getServerGame()][i].position.y,
- getServerData().ammunations[getServerGame()][i].position.z,
+ getGameConfig().blipSprites[getGame()].ammunation,
+ getServerData().ammunations[getGame()][i].position.x,
+ getServerData().ammunations[getGame()][i].position.y,
+ getServerData().ammunations[getGame()][i].position.z,
3,
0
]);
@@ -818,14 +833,14 @@ function sendAllAmmunationBlips(client) {
// ===========================================================================
function sendAllPayAndSprayBlips(client) {
- if(getGameConfig().blipSprites[getServerGame()].payAndSpray != -1) {
+ if(getGameConfig().blipSprites[getGame()].payAndSpray != -1) {
let tempBlips = [];
- for(let i in getServerData().payAndSprays[getServerGame()]) {
+ for(let i in getServerData().payAndSprays[getGame()]) {
tempBlips.push([
- getGameConfig().blipSprites[getServerGame()].payAndSpray,
- getServerData().payAndSprays[getServerGame()][i].position.x,
- getServerData().payAndSprays[getServerGame()][i].position.y,
- getServerData().payAndSprays[getServerGame()][i].position.z,
+ getGameConfig().blipSprites[getGame()].payAndSpray,
+ getServerData().payAndSprays[getGame()][i].position.x,
+ getServerData().payAndSprays[getGame()][i].position.y,
+ getServerData().payAndSprays[getGame()][i].position.z,
3,
0
]);
@@ -837,14 +852,14 @@ function sendAllPayAndSprayBlips(client) {
// ===========================================================================
function sendAllFuelStationBlips(client) {
- if(getGameConfig().blipSprites[getServerGame()].fuelStation != -1) {
+ if(getGameConfig().blipSprites[getGame()].fuelStation != -1) {
let tempBlips = [];
- for(let i in getServerData().fuelStations[getServerGame()]) {
+ for(let i in getServerData().fuelStations[getGame()]) {
tempBlips.push([
- getGameConfig().blipSprites[getServerGame()].fuelStation,
- getServerData().fuelStations[getServerGame()][i].position.x,
- getServerData().fuelStations[getServerGame()][i].position.y,
- getServerData().fuelStations[getServerGame()][i].position.z,
+ getGameConfig().blipSprites[getGame()].fuelStation,
+ getServerData().fuelStations[getGame()][i].position.x,
+ getServerData().fuelStations[getGame()][i].position.y,
+ getServerData().fuelStations[getGame()][i].position.z,
3,
getColourByName("burntOrange"),
]);
@@ -856,10 +871,9 @@ function sendAllFuelStationBlips(client) {
// ===========================================================================
function sendPlayerSetHealth(client, health) {
- sendNetworkEventToPlayer("vrr.health", client, health);
+ sendNetworkEventToPlayer("vrr.health", client, toInteger(health));
}
-
// ===========================================================================
function sendPlayerSetArmour(client, armour) {
@@ -887,7 +901,7 @@ function playerFinishedSkinSelection(client, allowedSkinIndex) {
}
return false;
} else {
- getPlayerCurrentSubAccount(client).skin = getSkinIndexFromModel(allowedSkins[allowedSkinIndex][0]);
+ getPlayerCurrentSubAccount(client).skin = getSkinIndexFromModel(getServerData().allowedSkins[allowedSkinIndex][0]);
if(isPlayerWorking(client)) {
messagePlayerAlert(client, "Your new skin has been saved but won't be shown until you stop working.");
setPlayerSkin(client, getJobData(getPlayerCurrentSubAccount(client).job).uniforms[getPlayerData(client).jobUniform].skinId);
@@ -914,7 +928,7 @@ function playerFinishedSkinSelection(client, allowedSkinIndex) {
switchPlayerActiveHotBarSlot(client, -1);
cachePlayerHotBarItems(client);
- meActionToNearbyPlayers(client, `changes their skin to ${allowedSkins[allowedSkinIndex][1]}`);
+ meActionToNearbyPlayers(client, `changes their skin to ${getServerData().allowedSkins[allowedSkinIndex][1]}`);
}
}
@@ -926,6 +940,12 @@ function sendPlayerChatScrollLines(client, amount) {
// ===========================================================================
+function sendPlayerChatAutoHideDelay(client, delay) {
+ sendNetworkEventToPlayer("vrr.chatAutoHideDelay", client, delay);
+}
+
+// ===========================================================================
+
function playRadioStreamForPlayer(client, streamURL, loop = true, volume = 0, element = false) {
logToConsole(LOG_DEBUG, `[VRR.Client] Forcing ${getPlayerDisplayForConsole(client)} to stream ${streamURL}`);
sendNetworkEventToPlayer("vrr.radioStream", client, streamURL, loop, volume, element);
@@ -969,50 +989,22 @@ function sendPlayerEnterPropertyKey(client, key) {
// ===========================================================================
function makePedPlayAnimation(ped, animationSlot, positionOffset) {
- let animationData = getAnimationData(animationSlot);
- let freezePlayer = false;
- //if(animationData[9] != VRR_ANIMMOVE_NONE) {
- switch(animationData[9]) {
- case VRR_ANIMMOVE_FORWARD:
- setElementCollisionsEnabled(ped, false);
- setElementPosition(ped, getPosInFrontOfPos(getElementPosition(ped), fixAngle(getElementHeading(ped)), positionOffset));
- freezePlayer = true;
- break;
-
- case VRR_ANIMMOVE_BACK:
- setElementCollisionsEnabled(ped, false);
- setElementPosition(ped, getPosBehindPos(getElementPosition(ped), fixAngle(getElementHeading(ped)), positionOffset));
- freezePlayer = true;
- break;
-
- case VRR_ANIMMOVE_LEFT:
- setElementCollisionsEnabled(ped, false);
- setElementPosition(ped, getPosToLeftOfPos(getElementPosition(ped), fixAngle(getElementHeading(ped)), positionOffset));
- freezePlayer = true;
- break;
-
- case VRR_ANIMMOVE_RIGHT:
- setElementCollisionsEnabled(ped, false);
- setElementPosition(ped, getPosToRightOfPos(getElementPosition(ped), fixAngle(getElementHeading(ped)), positionOffset));
- freezePlayer = true;
- break;
- }
- //}
- sendNetworkEventToPlayer("vrr.pedAnim", null, ped.id, animationData[1], animationData[2], animationData[3], animationData[4], animationData[5], positionOffset, freezePlayer);
+ setEntityData(ped, "vrr.anim", animationSlot, true);
+ sendNetworkEventToPlayer("vrr.anim", null, getPedForNetworkEvent(ped), animationSlot, positionOffset);
}
// ===========================================================================
function makePedStopAnimation(ped) {
- sendNetworkEventToPlayer("vrr.pedStopAnim", null, ped.id);
+ removeEntityData(ped, "vrr.anim");
+ sendNetworkEventToPlayer("vrr.stopAnim", null, getPedForNetworkEvent(ped));
}
// ===========================================================================
-function forcePedAnimation(ped, animationSlot) {
- let animationData = getAnimationData(animationSlot);
-
- sendNetworkEventToPlayer("vrr.forcePedAnim", null, ped.id, animationData[1], animationData[2], animationData[3], animationData[4]);
+function forcePedAnimation(ped, animationSlot, positionOffset = 0) {
+ addEntityData(ped, "vrr.anim", animationSlot, true);
+ sendNetworkEventToPlayer("vrr.forceAnim", null, getPedForNetworkEvent(ped), animationSlot, positionOffset);
}
// ===========================================================================
@@ -1023,14 +1015,6 @@ function hideAllPlayerGUI(client) {
// ===========================================================================
-function setPlayerHeadLookPosition(client, position) {
- if(client.player != null) {
- setEntityData(client.player, "vrr.headLook", position, true);
- }
-}
-
-// ===========================================================================
-
function requestClientInfo(client) {
sendNetworkEventToPlayer("vrr.clientInfo", client);
}
@@ -1058,13 +1042,6 @@ function sendPlayerPedPartsAndProps(client) {
// ===========================================================================
-function forcePlayerWantedLevel(client, wantedLevel) {
- sendNetworkEventToPlayer("vrr.wantedLevel", client, wantedLevel);
- return true;
-}
-
-// ===========================================================================
-
function onPlayerNearPickup(client, pickupId) {
getPlayerData(client).currentPickup = getElementFromId(pickupId);
}
@@ -1093,7 +1070,7 @@ function setPlayerBuyingVehicleState(client, state, vehicleId, position) {
function receiveVehiclePurchaseStateUpdateFromClient(client, state) {
if(getGlobalConfig().useServerSideVehiclePurchaseCheck == false) {
- checkVehicleBuying(client);
+ checkVehiclePurchasing(client);
}
}
@@ -1111,48 +1088,76 @@ function setPlayerInfiniteRun(client, state) {
// ==========================================================================
-function sendBusinessEntranceToPlayer(client, businessId, name, entrancePosition, blipModel, pickupModel, hasInterior, hasItems) {
+function sendBusinessToPlayer(client, businessId, name, entrancePosition, blipModel, pickupModel, hasInterior, hasItems) {
sendNetworkEventToPlayer("vrr.business", client, businessId, name, entrancePosition, blipModel, pickupModel, hasInterior, hasItems);
}
// ==========================================================================
-function sendHouseEntranceToPlayer(client, houseId, entrancePosition, blipModel, pickupModel, hasInterior) {
- sendNetworkEventToPlayer("vrr.house", client, houseId, entrancePosition, blipModel, pickupModel, hasInterior);
+function sendHouseToPlayer(client, houseId, description, entrancePosition, blipModel, pickupModel, hasInterior) {
+ sendNetworkEventToPlayer("vrr.house", client, houseId, description, entrancePosition, blipModel, pickupModel, hasInterior);
}
// ==========================================================================
-function sendAllBusinessEntrancesToPlayer(client) {
+function sendJobToPlayer(client, jobId, jobLocationId, name, position) {
+ sendNetworkEventToPlayer("vrr.job", client, jobId, jobLocationId, name, position);
+}
+
+// ==========================================================================
+
+function sendVehicleToPlayer(client, vehicleId, model, position, heading, colour1, colour2, colour3, colour4) {
+ sendNetworkEventToPlayer("vrr.vehicle", client, vehicleId, model, position, heading, colour1, colour2, colour3, colour4);
+}
+
+// ==========================================================================
+
+function sendAllBusinessesToPlayer(client) {
let businesses = getServerData().businesses;
for(let i in businesses) {
- if(businesses[i].entranceBlipModel > 0) {
- sendBusinessEntranceToPlayer(client, businesses[i].index, businesses[i].name, businesses[i].entrancePosition, businesses[i].entranceBlipModel, businesses[i].entrancePickupModel, businesses[i].hasInterior, false);
- }
+ sendBusinessToPlayer(client, businesses[i].index, businesses[i].name, businesses[i].entrancePosition, businesses[i].entranceBlipModel, businesses[i].entrancePickupModel, businesses[i].hasInterior, false);
}
}
// ==========================================================================
-function sendAllHouseEntrancesToPlayer(client) {
+function sendAllHousesToPlayer(client) {
let houses = getServerData().houses;
for(let i in houses) {
- if(houses[i].entranceBlipModel > 0) {
- sendBusinessEntranceToPlayer(client, businesses[i].index, houses[i].entrancePosition, houses[i].entranceBlipModel, houses[i].entrancePickupModel, houses[i].hasInterior);
- }
+ sendHouseToPlayer(client, houses[i].index, houses[i].entrancePosition, houses[i].entranceBlipModel, houses[i].entrancePickupModel, houses[i].hasInterior);
+ }
+}
+
+// ==========================================================================
+
+function sendAllJobsToPlayer(client) {
+ let jobs = getServerData().jobs;
+ for(let i in jobs) {
+ for(let j in jobs[i].locations) {
+ sendJobToPlayer(client, jobs[i].index, jobs[i].locations[j].index, jobs[i].name, jobs[i].locations[j].position, jobs[i].blipModel);
+ }
+ }
+}
+
+// ==========================================================================
+
+function sendAllVehiclesToPlayer(client) {
+ let vehicles = getServerData().vehicles;
+ for(let i in vehicles) {
+ sendVehicleToPlayer(client, vehicles[i].index, vehicles[i].model, vehicles[i].syncPosition, vehicles[i].syncHeading, vehicles[i].colour1, vehicles[i].colour2, vehicles[i].colour3, vehicles[i].colour4);
}
}
// ==========================================================================
function makePlayerHoldObjectModel(client, modelIndex) {
- sendNetworkEventToPlayer("vrr.holdObject", client, getPlayerData(client).pedId, modelIndex);
+ sendNetworkEventToPlayer("vrr.holdObject", client, getPlayerData(client).ped, modelIndex);
}
// ==========================================================================
function receivePlayerPedNetworkId(client, pedId) {
- getPlayerData(client).pedId = pedId;
+ getPlayerData(client).ped = pedId;
}
// ==========================================================================
@@ -1161,4 +1166,60 @@ function requestPlayerPedNetworkId(client) {
sendNetworkEventToPlayer("vrr.playerPedId", client);
}
+// ==========================================================================
+
+function setPlayerInCutsceneInterior(client, cutsceneName) {
+ getPlayerData(client).interiorCutscene = cutsceneName;
+ sendNetworkEventToPlayer("vrr.cutsceneInterior", client, cutsceneName);
+}
+
+// ==========================================================================
+
+function makePlayerPedSpeak(client, pedSpeechName) {
+ sendNetworkEventToPlayer("vrr.pedSpeak", client, pedSpeechName);
+}
+
+// ==========================================================================
+
+function setPlayerAsCopState(client, state) {
+ sendNetworkEventToPlayer("vrr.playerCop", client, state);
+}
+
+// ==========================================================================
+
+function tellPlayerToSpawn(client, skinId, position) {
+ sendNetworkEventToPlayer("vrr.spawn", client, skinId, position);
+}
+
+// ==========================================================================
+
+function sendNameTagDistanceToClient(client, distance) {
+ sendNetworkEventToPlayer("vrr.nameTagDistance", client, distance);
+}
+
+// ==========================================================================
+
+function sendGPSBlipToPlayer(client, position, colour) {
+ sendNetworkEventToPlayer("vrr.showGPSBlip", client, position, colour);
+}
+
+// ==========================================================================
+
+function playerSelectedNewLocale(client, localeId) {
+ getPlayerData(client).locale = localeId;
+ sendPlayerLocaleId(client, localeId);
+}
+
+// ==========================================================================
+
+function sendPlayerLocaleId(client, localeId) {
+ sendNetworkEventToPlayer("vrr.locale", client, localeId);
+}
+
+// ==========================================================================
+
+function showLocaleChooserForPlayer(client) {
+ sendNetworkEventToPlayer("vrr.localeChooser", client);
+}
+
// ==========================================================================
\ No newline at end of file
diff --git a/scripts/server/command.js b/scripts/server/command.js
index 673c4fed..8c448de8 100644
--- a/scripts/server/command.js
+++ b/scripts/server/command.js
@@ -7,29 +7,8 @@
// TYPE: Server (JavaScript)
// ===========================================================================
-let serverCommands = [];
-
-// ===========================================================================
-
-let builtInCommands = [
- "refresh",
- "restart",
- "stop",
- "start",
- "reconnect",
- "setname",
- "connect",
- "disconnect",
- "say",
- "dumpdoc",
-];
-
-// ===========================================================================
-
function initCommandScript() {
logToConsole(LOG_INFO, "[VRR.Command]: Initializing commands script ...");
- serverCommands = loadCommands();
- //addAllCommandHandlers();
logToConsole(LOG_INFO, "[VRR.Command]: Initialized commands script!");
}
@@ -38,483 +17,590 @@ function initCommandScript() {
function loadCommands() {
let tempCommands = {
accent: [
- commandData("accent", setAccentCommand, "", getStaffFlagValue("None"), false, false, "Sets your character's accent"),
- commandData("accents", listAccentsCommand, "", getStaffFlagValue("None"), false, false, "Shows a list of all available accents"),
- commandData("accentlist", listAccentsCommand, "", getStaffFlagValue("None"), false, false, "Shows a list of all available accents"),
+ new CommandData("accent", setAccentCommand, "", getStaffFlagValue("None"), false, false, "Sets your character's accent"),
+ new CommandData("accents", listAccentsCommand, "", getStaffFlagValue("None"), false, false, "Shows a list of all available accents"),
+ new CommandData("accentlist", listAccentsCommand, "", getStaffFlagValue("None"), false, false, "Shows a list of all available accents"),
],
account: [
- commandData("login", loginCommand, "", getStaffFlagValue("None"), false, false, "Login to an account"),
- commandData("register", registerCommand, "", getStaffFlagValue("None"), false, false, "Creates an account"),
- commandData("changepass", changeAccountPasswordCommand, " ", getStaffFlagValue("None"), true, false, "Change an account password"),
- commandData("iplogin", toggleAutoLoginByIPCommand, "", getStaffFlagValue("None"), true, false, "Toggle whether to automatically login if you join with the same IP as your last join"),
- commandData("autolastchar", toggleAutoSelectLastCharacterCommand, "", getStaffFlagValue("None"), true, false, "Toggle whether to automatically spawn with the last character you played as"),
- commandData("gui", toggleAccountGUICommand, "", getStaffFlagValue("None"), false, false, "Toggle whether to use GUI. If GUI is disabled on the server, it won't show even if you have GUI enabled."),
- commandData("2fa", toggleAccountTwoFactorAuthCommand, "", getStaffFlagValue("None"), true, false, "Set up and use two-factor authentication."),
- commandData("setemail", setAccountEmailCommand, "", getStaffFlagValue("None"), true, false, "Sets your email. To reset your password, you must have a valid email set and verified."),
- commandData("verifyemail", verifyAccountEmailCommand, "", getStaffFlagValue("None"), true, false, "Confirms/verifies your email."),
- //commandData("setdiscord", setAccountDiscordCommand, "", getStaffFlagValue("None"), true, false, "Set up the integration for discord. Allows you to see info and use in-game commands on discord."),
- commandData("notips", toggleNoRandomTipsCommand, "", getStaffFlagValue("None"), true, false, "Turn on and off random tips"),
- commandData("loginalert", toggleAccountLoginAttemptNotificationsCommand, "", getStaffFlagValue("None"), true, false, "Turn on and off email notifications for attempts to login to your account"),
- commandData("scrolllines", setAccountChatScrollLinesCommand, "", getStaffFlagValue("None"), true, false, "Sets how many chatbox lines to scroll at a time when using pageup/pagedown"),
+ new CommandData("login", loginCommand, "", getStaffFlagValue("None"), false, false, "Login to an account"),
+ new CommandData("register", registerCommand, "", getStaffFlagValue("None"), false, false, "Creates an account"),
+ new CommandData("changepass", changeAccountPasswordCommand, " ", getStaffFlagValue("None"), true, false, "Change an account password"),
+ new CommandData("iplogin", toggleAutoLoginByIPCommand, "", getStaffFlagValue("None"), true, false, "Toggle whether to automatically login if you join with the same IP as your last join"),
+ new CommandData("gui", toggleAccountGUICommand, "", getStaffFlagValue("None"), false, false, "Toggle whether to use GUI. If GUI is disabled on the server, it won't show even if you have GUI enabled."),
+ new CommandData("2fa", toggleAccountTwoFactorAuthCommand, "", getStaffFlagValue("None"), true, false, "Set up and use two-factor authentication."),
+ new CommandData("setemail", setAccountEmailCommand, "", getStaffFlagValue("None"), true, false, "Sets your email. To reset your password, you must have a valid email set and verified."),
+ new CommandData("verifyemail", verifyAccountEmailCommand, "", getStaffFlagValue("None"), true, false, "Confirms/verifies your email."),
+ //new CommandData("setdiscord", setAccountDiscordCommand, "", getStaffFlagValue("None"), true, false, "Set up the integration for discord. Allows you to see info and use in-game commands on discord."),
+ new CommandData("notips", toggleNoRandomTipsCommand, "", getStaffFlagValue("None"), true, false, "Turn on and off random tips"),
+ new CommandData("loginalert", toggleAccountLoginAttemptNotificationsCommand, "", getStaffFlagValue("None"), true, false, "Turn on and off email notifications for attempts to login to your account"),
+ new CommandData("scrolllines", setAccountChatScrollLinesCommand, "", getStaffFlagValue("None"), true, false, "Sets how many chatbox lines to scroll at a time when using pageup/pagedown"),
+ new CommandData("chatautohide", setAccountChatAutoHideDelayCommand, "